cbindgen/bindgen/ir/
ty.rs

1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4
5use std::borrow::Cow;
6
7use syn::ext::IdentExt;
8
9use crate::bindgen::config::{Config, Language};
10use crate::bindgen::declarationtyperesolver::DeclarationTypeResolver;
11use crate::bindgen::dependencies::Dependencies;
12use crate::bindgen::ir::{GenericArgument, GenericParams, GenericPath, Path};
13use crate::bindgen::library::Library;
14use crate::bindgen::monomorph::Monomorphs;
15use crate::bindgen::utilities::IterHelpers;
16
17#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
18pub enum PrimitiveType {
19    Void,
20    Bool,
21    Char,
22    SChar,
23    UChar,
24    Char32,
25    Float,
26    Double,
27    VaList,
28    PtrDiffT,
29    Integer {
30        zeroable: bool,
31        signed: bool,
32        kind: IntKind,
33    },
34}
35
36#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
37pub enum IntKind {
38    Short,
39    Int,
40    Long,
41    LongLong,
42    SizeT,
43    Size,
44    B8,
45    B16,
46    B32,
47    B64,
48}
49
50impl PrimitiveType {
51    pub fn maybe(path: &str) -> Option<PrimitiveType> {
52        Some(match path {
53            "c_void" => PrimitiveType::Void,
54            "c_char" => PrimitiveType::Char,
55            "c_schar" => PrimitiveType::SChar,
56            "c_uchar" => PrimitiveType::UChar,
57            "c_float" => PrimitiveType::Float,
58            "c_double" => PrimitiveType::Double,
59            "ptrdiff_t" => PrimitiveType::PtrDiffT,
60            "VaList" => PrimitiveType::VaList,
61            "bool" => PrimitiveType::Bool,
62            "char" => PrimitiveType::Char32,
63
64            "f32" => PrimitiveType::Float,
65            "f64" => PrimitiveType::Double,
66
67            _ => return Self::maybe_integer(path),
68        })
69    }
70
71    // Converts well-known integral types to their respective `PrimitiveType`
72    fn maybe_integer(path: &str) -> Option<PrimitiveType> {
73        let (kind, signed) = match path {
74            "c_short" => (IntKind::Short, true),
75            "c_int" => (IntKind::Int, true),
76            "c_long" => (IntKind::Long, true),
77            "c_longlong" => (IntKind::LongLong, true),
78            "ssize_t" => (IntKind::SizeT, true),
79            "c_ushort" => (IntKind::Short, false),
80            "c_uint" => (IntKind::Int, false),
81            "c_ulong" => (IntKind::Long, false),
82            "c_ulonglong" => (IntKind::LongLong, false),
83            "size_t" => (IntKind::SizeT, false),
84            "RawFd" => (IntKind::Int, true),
85
86            "isize" | "intptr_t" => (IntKind::Size, true),
87            "usize" | "uintptr_t" => (IntKind::Size, false),
88
89            "u8" | "uint8_t" => (IntKind::B8, false),
90            "u16" | "uint16_t" => (IntKind::B16, false),
91            "u32" | "uint32_t" => (IntKind::B32, false),
92            "u64" | "uint64_t" => (IntKind::B64, false),
93            "i8" | "int8_t" => (IntKind::B8, true),
94            "i16" | "int16_t" => (IntKind::B16, true),
95            "i32" | "int32_t" => (IntKind::B32, true),
96            "i64" | "int64_t" => (IntKind::B64, true),
97
98            _ => return Self::maybe_nonzero_integer(path),
99        };
100        Some(PrimitiveType::Integer {
101            zeroable: true,
102            signed,
103            kind,
104        })
105    }
106
107    // Converts well-known typedefs for [`NonZero`] to their respective `PrimitiveType`.
108    //
109    // NOTE: This performs the type erasure directly, as if `NonZero<T>` had been specified, because
110    // it's actually more code to register an erased typedef instead.
111    fn maybe_nonzero_integer(path: &str) -> Option<PrimitiveType> {
112        let (kind, signed) = match path {
113            "NonZeroU8" => (IntKind::B8, false),
114            "NonZeroU16" => (IntKind::B16, false),
115            "NonZeroU32" => (IntKind::B32, false),
116            "NonZeroU64" => (IntKind::B64, false),
117            "NonZeroUSize" => (IntKind::Size, false),
118            "NonZeroI8" => (IntKind::B8, true),
119            "NonZeroI16" => (IntKind::B16, true),
120            "NonZeroI32" => (IntKind::B32, true),
121            "NonZeroI64" => (IntKind::B64, true),
122            "NonZeroISize" => (IntKind::Size, true),
123
124            _ => return None,
125        };
126        Some(PrimitiveType::Integer {
127            zeroable: false,
128            signed,
129            kind,
130        })
131    }
132
133    pub fn to_repr_rust(&self) -> &'static str {
134        match *self {
135            PrimitiveType::Bool => "bool",
136            PrimitiveType::Void => "c_void",
137            PrimitiveType::Char => "c_char",
138            PrimitiveType::SChar => "c_schar",
139            PrimitiveType::UChar => "c_uchar",
140            PrimitiveType::Char32 => "char",
141            PrimitiveType::Integer {
142                kind,
143                signed,
144                zeroable: _,
145            } => match (kind, signed) {
146                (IntKind::Short, true) => "c_short",
147                (IntKind::Short, false) => "c_ushort",
148                (IntKind::Int, true) => "c_int",
149                (IntKind::Int, false) => "c_uint",
150                (IntKind::Long, true) => "c_long",
151                (IntKind::Long, false) => "c_ulong",
152                (IntKind::LongLong, true) => "c_longlong",
153                (IntKind::LongLong, false) => "c_ulonglong",
154                (IntKind::SizeT, true) => "ssize_t",
155                (IntKind::SizeT, false) => "size_t",
156                (IntKind::Size, true) => "isize",
157                (IntKind::Size, false) => "usize",
158                (IntKind::B8, true) => "i8",
159                (IntKind::B8, false) => "u8",
160                (IntKind::B16, true) => "i16",
161                (IntKind::B16, false) => "u16",
162                (IntKind::B32, true) => "i32",
163                (IntKind::B32, false) => "u32",
164                (IntKind::B64, true) => "i64",
165                (IntKind::B64, false) => "u64",
166            },
167            PrimitiveType::Float => "f32",
168            PrimitiveType::Double => "f64",
169            PrimitiveType::PtrDiffT => "ptrdiff_t",
170            PrimitiveType::VaList => "va_list",
171        }
172    }
173
174    pub fn to_repr_c(&self, config: &Config) -> &'static str {
175        match *self {
176            PrimitiveType::Void => "void",
177            PrimitiveType::Bool => "bool",
178            PrimitiveType::Char => "char",
179            PrimitiveType::SChar => "signed char",
180            PrimitiveType::UChar => "unsigned char",
181            // NOTE: It'd be nice to use a char32_t, but:
182            //
183            //  * uchar.h is not present on mac (see #423).
184            //
185            //  * char32_t isn't required to be compatible with Rust's char, as
186            //    the C++ spec only requires it to be the same size as
187            //    uint_least32_t, which is _not_ guaranteed to be 4-bytes.
188            //
189            PrimitiveType::Char32 => "uint32_t",
190            PrimitiveType::Integer {
191                kind,
192                signed,
193                zeroable: _,
194            } => match (kind, signed) {
195                (IntKind::Short, true) => "short",
196                (IntKind::Short, false) => "unsigned short",
197                (IntKind::Int, true) => "int",
198                (IntKind::Int, false) => "unsigned int",
199                (IntKind::Long, true) => "long",
200                (IntKind::Long, false) => "unsigned long",
201                (IntKind::LongLong, true) => "long long",
202                (IntKind::LongLong, false) => "unsigned long long",
203                (IntKind::SizeT, true) => "ssize_t",
204                (IntKind::SizeT, false) => "size_t",
205                (IntKind::Size, true) if config.usize_is_size_t => "ptrdiff_t",
206                (IntKind::Size, false) if config.usize_is_size_t => "size_t",
207                (IntKind::Size, true) => "intptr_t",
208                (IntKind::Size, false) => "uintptr_t",
209                (IntKind::B8, true) => "int8_t",
210                (IntKind::B8, false) => "uint8_t",
211                (IntKind::B16, true) => "int16_t",
212                (IntKind::B16, false) => "uint16_t",
213                (IntKind::B32, true) => "int32_t",
214                (IntKind::B32, false) => "uint32_t",
215                (IntKind::B64, true) => "int64_t",
216                (IntKind::B64, false) => "uint64_t",
217            },
218            PrimitiveType::Float => "float",
219            PrimitiveType::Double => "double",
220            PrimitiveType::PtrDiffT => "ptrdiff_t",
221            PrimitiveType::VaList => "...",
222        }
223    }
224
225    fn can_cmp_order(&self) -> bool {
226        !matches!(*self, PrimitiveType::Bool)
227    }
228
229    fn can_cmp_eq(&self) -> bool {
230        true
231    }
232}
233
234/// Constant expressions.
235///
236/// Used for the `U` part of `[T; U]` and const generics. We support a very
237/// limited vocabulary here: only identifiers and literals.
238#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
239pub enum ConstExpr {
240    Name(String),
241    Value(String),
242}
243
244impl ConstExpr {
245    pub fn as_str(&self) -> &str {
246        match *self {
247            ConstExpr::Name(ref string) | ConstExpr::Value(ref string) => string,
248        }
249    }
250
251    pub fn rename_for_config(&mut self, config: &Config) {
252        if let ConstExpr::Name(ref mut name) = self {
253            config.export.rename(name);
254        }
255    }
256
257    pub fn load(expr: &syn::Expr) -> Result<Self, String> {
258        match *expr {
259            syn::Expr::Lit(syn::ExprLit { ref lit, .. }) => {
260                let val = match *lit {
261                    syn::Lit::Bool(syn::LitBool { value, .. }) => value.to_string(),
262                    syn::Lit::Int(ref len) => len.base10_digits().to_string(),
263                    syn::Lit::Byte(ref byte) => u8::to_string(&byte.value()),
264                    syn::Lit::Char(ref ch) => u32::to_string(&ch.value().into()),
265                    _ => return Err(format!("can't handle const expression {lit:?}")),
266                };
267                Ok(ConstExpr::Value(val))
268            }
269            syn::Expr::Path(ref path) => {
270                let generic_path = GenericPath::load(&path.path)?;
271                Ok(ConstExpr::Name(generic_path.export_name().to_owned()))
272            }
273            syn::Expr::Cast(ref cast) => Ok(ConstExpr::load(&cast.expr)?),
274            _ => Err(format!("can't handle const expression {expr:?}")),
275        }
276    }
277
278    pub fn specialize(&self, mappings: &[(&Path, &GenericArgument)]) -> ConstExpr {
279        match *self {
280            ConstExpr::Name(ref name) => {
281                let path = Path::new(name);
282                for &(param, value) in mappings {
283                    if path == *param {
284                        match *value {
285                            GenericArgument::Type(Type::Path(ref path))
286                                if path.is_single_identifier() =>
287                            {
288                                // This happens when the generic argument is a path.
289                                return ConstExpr::Name(path.name().to_string());
290                            }
291                            GenericArgument::Const(ref expr) => {
292                                return expr.clone();
293                            }
294                            _ => {
295                                // unsupported argument type - really should be an error
296                            }
297                        }
298                    }
299                }
300            }
301            ConstExpr::Value(_) => {}
302        }
303        self.clone()
304    }
305}
306
307#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
308pub enum Type {
309    Ptr {
310        ty: Box<Type>,
311        is_const: bool,
312        is_nullable: bool,
313        // FIXME: This is a bit of a hack, this is only to get us to codegen
314        // `T&` / `const T&`, but we should probably pass that down as an option
315        // to code generation or something.
316        is_ref: bool,
317    },
318    Path(GenericPath),
319    Primitive(PrimitiveType),
320    Array(Box<Type>, ConstExpr),
321    FuncPtr {
322        ret: Box<Type>,
323        args: Vec<(Option<String>, Type)>,
324        is_nullable: bool,
325        never_return: bool,
326    },
327}
328
329impl Type {
330    pub fn const_ref_to(ty: &Self) -> Self {
331        Type::Ptr {
332            ty: Box::new(ty.clone()),
333            is_const: true,
334            is_nullable: false,
335            is_ref: true,
336        }
337    }
338
339    pub fn load_from_output(output: &syn::ReturnType) -> Result<(Type, bool), String> {
340        let mut never_return = false;
341        let ty = match output {
342            syn::ReturnType::Default => Type::Primitive(PrimitiveType::Void),
343            syn::ReturnType::Type(_, ref ty) => {
344                if let syn::Type::Never(_) = ty.as_ref() {
345                    never_return = true;
346                    Type::Primitive(PrimitiveType::Void)
347                } else {
348                    Type::load(ty)?.unwrap_or(Type::Primitive(PrimitiveType::Void))
349                }
350            }
351        };
352        Ok((ty, never_return))
353    }
354
355    pub fn load(ty: &syn::Type) -> Result<Option<Type>, String> {
356        let converted = match *ty {
357            syn::Type::Reference(ref reference) => {
358                let converted = Type::load(&reference.elem)?;
359
360                let converted = match converted {
361                    Some(converted) => converted,
362                    None => Type::Primitive(PrimitiveType::Void),
363                };
364
365                // TODO(emilio): we could make these use is_ref: true.
366                let is_const = reference.mutability.is_none();
367                Type::Ptr {
368                    ty: Box::new(converted),
369                    is_const,
370                    is_nullable: false,
371                    is_ref: false,
372                }
373            }
374            syn::Type::Ptr(ref pointer) => {
375                let converted = Type::load(&pointer.elem)?;
376
377                let converted = match converted {
378                    Some(converted) => converted,
379                    None => Type::Primitive(PrimitiveType::Void),
380                };
381
382                let is_const = pointer.mutability.is_none();
383                Type::Ptr {
384                    ty: Box::new(converted),
385                    is_const,
386                    is_nullable: true,
387                    is_ref: false,
388                }
389            }
390            syn::Type::Path(ref path) => {
391                let generic_path = GenericPath::load(&path.path)?;
392
393                if generic_path.name() == "PhantomData" || generic_path.name() == "PhantomPinned" {
394                    return Ok(None);
395                }
396
397                if let Some(prim) = PrimitiveType::maybe(generic_path.name()) {
398                    if !generic_path.generics().is_empty() {
399                        return Err("Primitive has generics.".to_owned());
400                    }
401                    Type::Primitive(prim)
402                } else {
403                    Type::Path(generic_path)
404                }
405            }
406            syn::Type::Array(syn::TypeArray {
407                ref elem, ref len, ..
408            }) => {
409                let converted = Type::load(elem)?;
410
411                let converted = match converted {
412                    Some(converted) => converted,
413                    None => return Err("Cannot have an array of zero sized types.".to_owned()),
414                };
415
416                let len = ConstExpr::load(len)?;
417                Type::Array(Box::new(converted), len)
418            }
419            syn::Type::BareFn(ref function) => {
420                let mut wildcard_counter = 0;
421                let mut args = function.inputs.iter().try_skip_map(|x| {
422                    Type::load(&x.ty).map(|opt_ty| {
423                        opt_ty.map(|ty| {
424                            (
425                                x.name.as_ref().map(|(ref ident, _)| {
426                                    if ident == "_" {
427                                        wildcard_counter += 1;
428                                        if wildcard_counter == 1 {
429                                            "_".to_owned()
430                                        } else {
431                                            format!("_{}", wildcard_counter - 1)
432                                        }
433                                    } else {
434                                        ident.unraw().to_string()
435                                    }
436                                }),
437                                ty,
438                            )
439                        })
440                    })
441                })?;
442                if function.variadic.is_some() {
443                    args.push((None, Type::Primitive(super::PrimitiveType::VaList)))
444                }
445                let (ret, never_return) = Type::load_from_output(&function.output)?;
446                Type::FuncPtr {
447                    ret: Box::new(ret),
448                    args,
449                    is_nullable: false,
450                    never_return,
451                }
452            }
453            syn::Type::Tuple(ref tuple) => {
454                if tuple.elems.is_empty() {
455                    return Ok(None);
456                }
457                return Err("Tuples are not supported types.".to_owned());
458            }
459            syn::Type::Verbatim(ref tokens) if tokens.to_string() == "..." => {
460                Type::Primitive(PrimitiveType::VaList)
461            }
462            _ => return Err(format!("Unsupported type: {ty:?}")),
463        };
464
465        Ok(Some(converted))
466    }
467
468    pub fn is_ptr(&self) -> bool {
469        matches!(*self, Type::Ptr { .. } | Type::FuncPtr { .. })
470    }
471
472    pub fn is_primitive_or_ptr_primitive(&self) -> bool {
473        match *self {
474            Type::Primitive(..) => true,
475            Type::Ptr { ref ty, .. } => matches!(ty.as_ref(), Type::Primitive(..)),
476            _ => false,
477        }
478    }
479
480    pub fn make_zeroable(&self, new_zeroable: bool) -> Option<Self> {
481        match *self {
482            Type::Primitive(PrimitiveType::Integer {
483                zeroable: old_zeroable,
484                kind,
485                signed,
486            }) if old_zeroable != new_zeroable => Some(Type::Primitive(PrimitiveType::Integer {
487                kind,
488                signed,
489                zeroable: new_zeroable,
490            })),
491            _ => None,
492        }
493    }
494
495    pub fn make_nullable(&self) -> Option<Self> {
496        match *self {
497            Type::Ptr {
498                ref ty,
499                is_const,
500                is_ref,
501                is_nullable: false,
502            } => Some(Type::Ptr {
503                ty: ty.clone(),
504                is_const,
505                is_ref,
506                is_nullable: true,
507            }),
508            Type::FuncPtr {
509                ref ret,
510                ref args,
511                is_nullable: false,
512                never_return,
513            } => Some(Type::FuncPtr {
514                ret: ret.clone(),
515                args: args.clone(),
516                is_nullable: true,
517                never_return,
518            }),
519            _ => None,
520        }
521    }
522
523    fn simplified_type(&self, config: &Config) -> Option<Self> {
524        let path = match *self {
525            Type::Path(ref p) => p,
526            _ => return None,
527        };
528
529        if path.generics().is_empty() {
530            return None;
531        }
532
533        if path.generics().len() != 1 {
534            return None;
535        }
536
537        let unsimplified_generic = match path.generics()[0] {
538            GenericArgument::Type(ref ty) => ty,
539            GenericArgument::Const(_) => return None,
540        };
541
542        let generic = match unsimplified_generic.simplified_type(config) {
543            Some(generic) => Cow::Owned(generic),
544            None => Cow::Borrowed(unsimplified_generic),
545        };
546        match path.name() {
547            "Option" => generic
548                .make_nullable()
549                .or_else(|| generic.make_zeroable(true)),
550            "NonNull" => Some(Type::Ptr {
551                ty: Box::new(generic.into_owned()),
552                is_const: false,
553                is_nullable: false,
554                is_ref: false,
555            }),
556            "NonZero" => generic.make_zeroable(false),
557            "Box" if config.language != Language::Cxx => Some(Type::Ptr {
558                ty: Box::new(generic.into_owned()),
559                is_const: false,
560                is_nullable: false,
561                is_ref: false,
562            }),
563            "SyncUnsafeCell" | "UnsafeCell" | "Cell" => Some(generic.into_owned()),
564            "ManuallyDrop" | "MaybeUninit" | "Pin" if config.language != Language::Cxx => {
565                Some(generic.into_owned())
566            }
567            _ => None,
568        }
569    }
570
571    pub fn simplify_standard_types(&mut self, config: &Config) {
572        self.visit_types(|ty| ty.simplify_standard_types(config));
573        if let Some(ty) = self.simplified_type(config) {
574            *self = ty;
575        }
576    }
577
578    pub fn replace_self_with(&mut self, self_ty: &Path) {
579        if let Type::Path(ref mut generic_path) = *self {
580            generic_path.replace_self_with(self_ty);
581        }
582        self.visit_types(|ty| ty.replace_self_with(self_ty))
583    }
584
585    fn visit_types(&mut self, mut visitor: impl FnMut(&mut Type)) {
586        match *self {
587            Type::Array(ref mut ty, ..) | Type::Ptr { ref mut ty, .. } => visitor(ty),
588            Type::Path(ref mut path) => {
589                for generic in path.generics_mut() {
590                    match *generic {
591                        GenericArgument::Type(ref mut ty) => visitor(ty),
592                        GenericArgument::Const(_) => {}
593                    }
594                }
595            }
596            Type::Primitive(..) => {}
597            Type::FuncPtr {
598                ref mut ret,
599                ref mut args,
600                ..
601            } => {
602                visitor(ret);
603                for arg in args {
604                    visitor(&mut arg.1)
605                }
606            }
607        }
608    }
609
610    pub fn get_root_path(&self) -> Option<Path> {
611        let mut current = self;
612        loop {
613            match *current {
614                Type::Ptr { ref ty, .. } => current = ty,
615                Type::Path(ref generic) => {
616                    return Some(generic.path().clone());
617                }
618                Type::Primitive(..) => {
619                    return None;
620                }
621                Type::Array(..) => {
622                    return None;
623                }
624                Type::FuncPtr { .. } => {
625                    return None;
626                }
627            };
628        }
629    }
630
631    pub fn specialize(&self, mappings: &[(&Path, &GenericArgument)]) -> Type {
632        match *self {
633            Type::Ptr {
634                ref ty,
635                is_const,
636                is_nullable,
637                is_ref,
638            } => Type::Ptr {
639                ty: Box::new(ty.specialize(mappings)),
640                is_const,
641                is_nullable,
642                is_ref,
643            },
644            Type::Path(ref generic_path) => {
645                for &(param, value) in mappings {
646                    if generic_path.path() == param {
647                        if let GenericArgument::Type(ref ty) = *value {
648                            return ty.clone();
649                        }
650                    }
651                }
652
653                let specialized = GenericPath::new(
654                    generic_path.path().clone(),
655                    generic_path
656                        .generics()
657                        .iter()
658                        .map(|x| x.specialize(mappings))
659                        .collect(),
660                );
661                Type::Path(specialized)
662            }
663            Type::Primitive(ref primitive) => Type::Primitive(primitive.clone()),
664            Type::Array(ref ty, ref constant) => Type::Array(
665                Box::new(ty.specialize(mappings)),
666                constant.specialize(mappings),
667            ),
668            Type::FuncPtr {
669                ref ret,
670                ref args,
671                is_nullable,
672                never_return,
673            } => Type::FuncPtr {
674                ret: Box::new(ret.specialize(mappings)),
675                args: args
676                    .iter()
677                    .cloned()
678                    .map(|(name, ty)| (name, ty.specialize(mappings)))
679                    .collect(),
680                is_nullable,
681                never_return,
682            },
683        }
684    }
685
686    pub fn add_dependencies_ignoring_generics(
687        &self,
688        generic_params: &GenericParams,
689        library: &Library,
690        out: &mut Dependencies,
691    ) {
692        match *self {
693            Type::Ptr { ref ty, .. } => {
694                ty.add_dependencies_ignoring_generics(generic_params, library, out);
695            }
696            Type::Path(ref generic) => {
697                for generic_value in generic.generics() {
698                    if let GenericArgument::Type(ref ty) = *generic_value {
699                        ty.add_dependencies_ignoring_generics(generic_params, library, out);
700                    }
701                }
702                let path = generic.path();
703                if !generic_params.iter().any(|param| param.name() == path) {
704                    out.add(library, path);
705                }
706            }
707            Type::Primitive(_) => {}
708            Type::Array(ref ty, _) => {
709                ty.add_dependencies_ignoring_generics(generic_params, library, out);
710            }
711            Type::FuncPtr {
712                ref ret, ref args, ..
713            } => {
714                ret.add_dependencies_ignoring_generics(generic_params, library, out);
715                for (_, ref arg) in args {
716                    arg.add_dependencies_ignoring_generics(generic_params, library, out);
717                }
718            }
719        }
720    }
721
722    pub fn add_dependencies(&self, library: &Library, out: &mut Dependencies) {
723        self.add_dependencies_ignoring_generics(&GenericParams::default(), library, out)
724    }
725
726    pub fn add_monomorphs(&self, library: &Library, out: &mut Monomorphs) {
727        match *self {
728            Type::Ptr { ref ty, .. } => {
729                ty.add_monomorphs(library, out);
730            }
731            Type::Path(ref generic) => {
732                if generic.generics().is_empty() || out.contains(generic) {
733                    return;
734                }
735                let path = generic.path();
736                if let Some(items) = library.get_items(path) {
737                    for item in items {
738                        item.deref()
739                            .instantiate_monomorph(generic.generics(), library, out);
740                    }
741                }
742            }
743            Type::Primitive(_) => {}
744            Type::Array(ref ty, _) => {
745                ty.add_monomorphs(library, out);
746            }
747            Type::FuncPtr {
748                ref ret, ref args, ..
749            } => {
750                ret.add_monomorphs(library, out);
751                for (_, ref arg) in args {
752                    arg.add_monomorphs(library, out);
753                }
754            }
755        }
756    }
757
758    pub fn rename_for_config(&mut self, config: &Config, generic_params: &GenericParams) {
759        match *self {
760            Type::Ptr { ref mut ty, .. } => {
761                ty.rename_for_config(config, generic_params);
762            }
763            Type::Path(ref mut ty) => {
764                ty.rename_for_config(config, generic_params);
765            }
766            Type::Primitive(_) => {}
767            Type::Array(ref mut ty, ref mut len) => {
768                ty.rename_for_config(config, generic_params);
769                len.rename_for_config(config);
770            }
771            Type::FuncPtr {
772                ref mut ret,
773                ref mut args,
774                ..
775            } => {
776                ret.rename_for_config(config, generic_params);
777                for (_, arg) in args {
778                    arg.rename_for_config(config, generic_params);
779                }
780            }
781        }
782    }
783
784    pub fn resolve_declaration_types(&mut self, resolver: &DeclarationTypeResolver) {
785        match *self {
786            Type::Ptr { ref mut ty, .. } => {
787                ty.resolve_declaration_types(resolver);
788            }
789            Type::Path(ref mut generic_path) => {
790                generic_path.resolve_declaration_types(resolver);
791            }
792            Type::Primitive(_) => {}
793            Type::Array(ref mut ty, _) => {
794                ty.resolve_declaration_types(resolver);
795            }
796            Type::FuncPtr {
797                ref mut ret,
798                ref mut args,
799                ..
800            } => {
801                ret.resolve_declaration_types(resolver);
802                for (_, ref mut arg) in args {
803                    arg.resolve_declaration_types(resolver);
804                }
805            }
806        }
807    }
808
809    pub fn mangle_paths(&mut self, monomorphs: &Monomorphs) {
810        match *self {
811            Type::Ptr { ref mut ty, .. } => {
812                ty.mangle_paths(monomorphs);
813            }
814            Type::Path(ref mut generic_path) => {
815                if generic_path.generics().is_empty() {
816                    return;
817                }
818
819                if let Some(mangled_path) = monomorphs.mangle_path(generic_path) {
820                    *generic_path = GenericPath::new(mangled_path.clone(), vec![]);
821                } else {
822                    warn!(
823                        "Cannot find a mangling for generic path {generic_path:?}. This usually means that a \
824                         type referenced by this generic was incompatible or not found."
825                    );
826                }
827            }
828            Type::Primitive(_) => {}
829            Type::Array(ref mut ty, _) => {
830                ty.mangle_paths(monomorphs);
831            }
832            Type::FuncPtr {
833                ref mut ret,
834                ref mut args,
835                ..
836            } => {
837                ret.mangle_paths(monomorphs);
838                for (_, ref mut arg) in args {
839                    arg.mangle_paths(monomorphs);
840                }
841            }
842        }
843    }
844
845    pub fn can_cmp_order(&self) -> bool {
846        match *self {
847            // FIXME: Shouldn't this look at ty.can_cmp_order() as well?
848            Type::Ptr { is_ref, .. } => !is_ref,
849            Type::Path(..) => true,
850            Type::Primitive(ref p) => p.can_cmp_order(),
851            Type::Array(..) => false,
852            Type::FuncPtr { .. } => false,
853        }
854    }
855
856    pub fn can_cmp_eq(&self) -> bool {
857        match *self {
858            Type::Ptr { ref ty, is_ref, .. } => !is_ref || ty.can_cmp_eq(),
859            Type::Path(..) => true,
860            Type::Primitive(ref p) => p.can_cmp_eq(),
861            Type::Array(..) => false,
862            Type::FuncPtr { .. } => true,
863        }
864    }
865}