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