Support Self in generics in some cases (eg Result<Self, E> in an impl block)
authorMatt Corallo <git@bluematt.me>
Sun, 18 Apr 2021 20:23:50 +0000 (20:23 +0000)
committerMatt Corallo <git@bluematt.me>
Thu, 29 Apr 2021 18:59:50 +0000 (18:59 +0000)
c-bindings-gen/src/blocks.rs
c-bindings-gen/src/main.rs
c-bindings-gen/src/types.rs

index 28323498336c750d97abe45e899d282a3042265a..88172722efbda088aef61443fba43e2af6515e07 100644 (file)
@@ -648,7 +648,7 @@ pub fn write_method_call_params<W: std::io::Write>(w: &mut W, sig: &syn::Signatu
 /// Prints concrete generic parameters for a struct/trait/function, including the less-than and
 /// greater-than symbols, if any generic parameters are defined.
 pub fn maybe_write_generics<W: std::io::Write>(w: &mut W, generics: &syn::Generics, types: &TypeResolver, concrete_lifetimes: bool) {
-       let mut gen_types = GenericTypes::new();
+       let mut gen_types = GenericTypes::new(None);
        assert!(gen_types.learn_generics(generics, types));
        if !generics.params.is_empty() {
                write!(w, "<").unwrap();
index 75b537c7022c49b47bbd7ce43c650f4ec10da09a..faa51f5460163b759ada3d936855b7bca0ecbe16 100644 (file)
@@ -225,7 +225,7 @@ fn writeln_trait<'a, 'b, W: std::io::Write>(w: &mut W, t: &'a syn::ItemTrait, ty
        }
        writeln_docs(w, &t.attrs, "");
 
-       let mut gen_types = GenericTypes::new();
+       let mut gen_types = GenericTypes::new(None);
        assert!(gen_types.learn_generics(&t.generics, types));
        gen_types.learn_associated_types(&t, types);
 
@@ -579,7 +579,10 @@ fn writeln_struct<'a, 'b, W: std::io::Write>(w: &mut W, s: &'a syn::ItemStruct,
        writeln_opaque(w, &s.ident, struct_name, &s.generics, &s.attrs, types, extra_headers, cpp_headers);
 
        if let syn::Fields::Named(fields) = &s.fields {
-               let mut gen_types = GenericTypes::new();
+               let mut self_path_segs = syn::punctuated::Punctuated::new();
+               self_path_segs.push(s.ident.clone().into());
+               let self_path = syn::Path { leading_colon: None, segments: self_path_segs};
+               let mut gen_types = GenericTypes::new(Some((types.resolve_path(&self_path, None), &self_path)));
                assert!(gen_types.learn_generics(&s.generics, types));
 
                let mut all_fields_settable = true;
@@ -674,7 +677,7 @@ fn writeln_impl<W: std::io::Write>(w: &mut W, i: &syn::ItemImpl, types: &mut Typ
 
        if let syn::Type::Tuple(_) = &*i.self_ty {
                if types.understood_c_type(&*i.self_ty, None) {
-                       let mut gen_types = GenericTypes::new();
+                       let mut gen_types = GenericTypes::new(None);
                        if !gen_types.learn_generics(&i.generics, types) {
                                eprintln!("Not implementing anything for `impl (..)` due to not understood generics");
                                return;
@@ -701,7 +704,7 @@ fn writeln_impl<W: std::io::Write>(w: &mut W, i: &syn::ItemImpl, types: &mut Typ
                if p.qself.is_some() { unimplemented!(); }
                if let Some(ident) = single_ident_generic_path_to_ident(&p.path) {
                        if let Some(resolved_path) = types.maybe_resolve_non_ignored_ident(&ident) {
-                               let mut gen_types = GenericTypes::new();
+                               let mut gen_types = GenericTypes::new(Some((resolved_path.clone(), &p.path)));
                                if !gen_types.learn_generics(&i.generics, types) {
                                        eprintln!("Not implementing anything for impl {} due to not understood generics", ident);
                                        return;
@@ -1270,7 +1273,7 @@ fn writeln_fn<'a, 'b, W: std::io::Write>(w: &mut W, f: &'a syn::ItemFn, types: &
        }
        writeln_docs(w, &f.attrs, "");
 
-       let mut gen_types = GenericTypes::new();
+       let mut gen_types = GenericTypes::new(None);
        if !gen_types.learn_generics(&f.sig.generics, types) { return; }
 
        write!(w, "#[no_mangle]\npub extern \"C\" fn {}(", f.sig.ident).unwrap();
index 835e6c02323a92eff2d2df0f070b04b21e7ebadc..e4f37c659ac4c949a83f32d0e8680471167aa931 100644 (file)
@@ -164,19 +164,20 @@ pub fn is_enum_opaque(e: &syn::ItemEnum) -> bool {
 /// concrete C container struct, etc).
 #[must_use]
 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>)>,
 }
 impl<'a, 'p: 'a> GenericTypes<'a, 'p> {
-       pub fn new() -> Self {
-               Self { parent: None, typed_generics: HashMap::new(), }
+       pub fn new(self_ty: Option<(String, &'a syn::Path)>) -> Self {
+               Self { self_ty, parent: None, typed_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 { parent: Some(self), typed_generics: HashMap::new(), }
+               GenericTypes { self_ty: None, parent: Some(self), typed_generics: HashMap::new(), }
        }
 
        /// Learn the generics in generics in the current context, given a TypeResolver.
@@ -281,6 +282,11 @@ impl<'a, 'p: 'a> GenericTypes<'a, 'p> {
 
        /// Attempt to resolve an Ident as a generic parameter and return the full path.
        pub fn maybe_resolve_ident<'b>(&'b self, ident: &syn::Ident) -> Option<&'b String> {
+               if let Some(ty) = &self.self_ty {
+                       if format!("{}", ident) == "Self" {
+                               return Some(&ty.0);
+                       }
+               }
                if let Some(res) = self.typed_generics.get(ident).map(|(a, _)| a) {
                        return Some(res);
                }
@@ -294,6 +300,11 @@ impl<'a, 'p: 'a> GenericTypes<'a, 'p> {
        /// and syn::Path.
        pub fn maybe_resolve_path<'b>(&'b self, path: &syn::Path) -> Option<(&'b String, &'a syn::Path)> {
                if let Some(ident) = path.get_ident() {
+                       if let Some(ty) = &self.self_ty {
+                               if format!("{}", ident) == "Self" {
+                                       return Some((&ty.0, ty.1));
+                               }
+                       }
                        if let Some(res) = self.typed_generics.get(ident).map(|(a, b)| (a, b.unwrap())) {
                                return Some(res);
                        }