From 7ae0ad1e6274e614ec82fc84f317db09884b4beb Mon Sep 17 00:00:00 2001 From: Matt Corallo Date: Fri, 30 Apr 2021 18:35:58 +0000 Subject: [PATCH] Resolve generic params with default (eg `) as their default. --- c-bindings-gen/src/types.rs | 44 ++++++++++++++++++++++++++++++++----- 1 file changed, 39 insertions(+), 5 deletions(-) diff --git a/c-bindings-gen/src/types.rs b/c-bindings-gen/src/types.rs index 5767866..395441b 100644 --- a/c-bindings-gen/src/types.rs +++ b/c-bindings-gen/src/types.rs @@ -167,17 +167,18 @@ pub struct GenericTypes<'a, 'b> { self_ty: Option<(String, &'a syn::Path)>, parent: Option<&'b GenericTypes<'b, 'b>>, typed_generics: HashMap<&'a syn::Ident, (String, Option<&'a syn::Path>)>, + default_generics: HashMap<&'a syn::Ident, (&'a syn::Type, syn::Type)>, } impl<'a, 'p: 'a> GenericTypes<'a, 'p> { pub fn new(self_ty: Option<(String, &'a syn::Path)>) -> Self { - Self { self_ty, parent: None, typed_generics: HashMap::new(), } + Self { self_ty, parent: None, typed_generics: HashMap::new(), default_generics: HashMap::new(), } } /// push a new context onto the stack, allowing for a new set of generics to be learned which /// will override any lower contexts, but which will still fall back to resoltion via lower /// contexts. pub fn push_ctx<'c>(&'c self) -> GenericTypes<'a, 'c> { - GenericTypes { self_ty: None, parent: Some(self), typed_generics: HashMap::new(), } + GenericTypes { self_ty: None, parent: Some(self), typed_generics: HashMap::new(), default_generics: HashMap::new(), } } /// Learn the generics in generics in the current context, given a TypeResolver. @@ -208,6 +209,10 @@ impl<'a, 'p: 'a> GenericTypes<'a, 'p> { } else { return false; } } } + if let Some(default) = type_param.default.as_ref() { + assert!(type_param.bounds.is_empty()); + self.default_generics.insert(&type_param.ident, (default, parse_quote!(&#default))); + } }, _ => {}, } @@ -296,6 +301,7 @@ impl<'a, 'p: 'a> GenericTypes<'a, 'p> { None } } + /// Attempt to resolve a Path as a generic parameter and return the full path. as both a string /// and syn::Path. pub fn maybe_resolve_path<'b>(&'b self, path: &syn::Path) -> Option<(&'b String, &'a syn::Path)> { @@ -327,6 +333,34 @@ impl<'a, 'p: 'a> GenericTypes<'a, 'p> { } } +trait ResolveType<'a> { fn resolve_type(&'a self, ty: &'a syn::Type) -> &'a syn::Type; } +impl<'a, 'b, 'c: 'a + 'b> ResolveType<'c> for Option<&GenericTypes<'a, 'b>> { + fn resolve_type(&'c self, ty: &'c syn::Type) -> &'c syn::Type { + if let Some(us) = self { + match ty { + syn::Type::Path(p) => { + if let Some(ident) = p.path.get_ident() { + if let Some((ty, _)) = us.default_generics.get(ident) { + return ty; + } + } + }, + syn::Type::Reference(syn::TypeReference { elem, .. }) => { + if let syn::Type::Path(p) = &**elem { + if let Some(ident) = p.path.get_ident() { + if let Some((_, refty)) = us.default_generics.get(ident) { + return refty; + } + } + } + } + _ => {}, + } + } + ty + } +} + #[derive(Clone, PartialEq)] // The type of declaration and the object itself pub enum DeclType<'a> { @@ -1644,7 +1678,7 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> { LP: Fn(&str, bool, bool) -> Option, DL: Fn(&mut W, &DeclType, &str, bool, bool), SC: Fn(bool, Option<&str>) -> String> (&self, w: &mut W, t: &syn::Type, generics: Option<&GenericTypes>, is_ref: bool, is_mut: bool, ptr_for_ref: bool, tupleconv: &str, prefix: bool, sliceconv: SC, path_lookup: LP, decl_lookup: DL) { - match t { + match generics.resolve_type(t) { syn::Type::Reference(r) => { self.write_conversion_inline_intern(w, &*r.elem, generics, true, r.mutability.is_some(), ptr_for_ref, tupleconv, prefix, sliceconv, path_lookup, decl_lookup); @@ -1974,7 +2008,7 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> { } } } - match t { + match generics.resolve_type(t) { syn::Type::Reference(r) => { if let syn::Type::Slice(_) = &*r.elem { self.write_conversion_new_var_intern(w, ident, var, &*r.elem, generics, is_ref, ptr_for_ref, to_c, path_lookup, container_lookup, var_prefix, var_suffix) @@ -2418,7 +2452,7 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> { } } fn write_c_type_intern(&self, w: &mut W, t: &syn::Type, generics: Option<&GenericTypes>, is_ref: bool, is_mut: bool, ptr_for_ref: bool) -> bool { - match t { + match generics.resolve_type(t) { syn::Type::Path(p) => { if p.qself.is_some() { return false; -- 2.30.2