diff options
| -rw-r--r-- | src/lib.rs | 26 | ||||
| -rw-r--r-- | src/parse_attrs.rs | 29 | ||||
| -rw-r--r-- | tests/tests.rs | 15 | ||||
| -rw-r--r-- | ui-tests/src/bin/attr_dynamized_duplicate.rs | 6 | ||||
| -rw-r--r-- | ui-tests/src/bin/attr_dynamized_duplicate.stderr | 5 | ||||
| -rw-r--r-- | ui-tests/src/bin/attr_dynamized_no_such_supertrait.rs | 5 | ||||
| -rw-r--r-- | ui-tests/src/bin/attr_dynamized_no_such_supertrait.stderr | 5 | 
7 files changed, 86 insertions, 5 deletions
| @@ -83,6 +83,15 @@ pub fn dynamize(_attr: TokenStream, input: TokenStream) -> TokenStream {          Err(err) => return err.to_compile_error().into(),      }; +    for dyn_supertrait in &method_attrs.dynamized_supertraits { +        if !trait_bounds(&original_trait.supertraits).any(|t| t.path.is_ident(dyn_supertrait)) { +            return abort!( +                dyn_supertrait.span(), +                "this trait definition has no such supertrait" +            ); +        } +    } +      let mut type_converter = TypeConverter {          collections: method_attrs.collections,          assoc_type_conversions: HashMap::new(), @@ -185,11 +194,20 @@ pub fn dynamize(_attr: TokenStream, input: TokenStream) -> TokenStream {          supertraits: original_trait              .supertraits              .iter() -            .filter(|t| match t { -                TypeParamBound::Trait(t) => !t.path.is_ident("Sized"), -                TypeParamBound::Lifetime(_) => true, +            .filter_map(|t| { +                if let TypeParamBound::Trait(trait_bound) = t { +                    if let Some(ident) = trait_bound.path.get_ident() { +                        if ident == "Sized" { +                            return None; +                        } else if method_attrs.dynamized_supertraits.contains(ident) { +                            let mut bound = trait_bound.clone(); +                            bound.path.segments[0].ident = format_ident!("Dyn{}", ident); +                            return Some(TypeParamBound::Trait(bound)); +                        } +                    } +                } +                Some(t.clone())              }) -            .cloned()              .collect(),          brace_token: Brace::default(),          items: Vec::new(), diff --git a/src/parse_attrs.rs b/src/parse_attrs.rs index 03b5377..d9725ff 100644 --- a/src/parse_attrs.rs +++ b/src/parse_attrs.rs @@ -1,4 +1,4 @@ -use std::collections::HashMap; +use std::collections::{HashMap, HashSet};  use proc_macro2::{Group, TokenStream};  use quote::quote; @@ -33,6 +33,21 @@ pub struct TraitAttrs {      pub blanket_impl_attrs: Vec<TokenStream>,      pub dyn_trait_attrs: Vec<TokenStream>,      pub collections: HashMap<Ident, usize>, +    pub dynamized_supertraits: HashSet<Ident>, +} + +struct Dynamized { +    ident: Ident, +} + +impl Parse for Dynamized { +    fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> { +        let inner; +        parenthesized!(inner in input); +        Ok(Self { +            ident: inner.parse()?, +        }) +    }  }  impl TraitAttrs { @@ -84,6 +99,18 @@ impl TraitAttrs {                          ),                      ));                  } +            } else if attrs[i].path.is_ident("dynamized") { +                let attr = attrs.remove(i); +                let dynamized: Dynamized = syn::parse2(attr.tokens)?; +                let span = dynamized.ident.span(); + +                if !parsed.dynamized_supertraits.insert(dynamized.ident) { +                    // FUTURE: relax to warning once proc_macro::Diagnostic is stable +                    return Err(Error::new( +                        span, +                        format_args!("dynamized attribute is defined multiple times"), +                    )); +                }              } else {                  i += 1;              } diff --git a/tests/tests.rs b/tests/tests.rs index e3df519..b75c605 100644 --- a/tests/tests.rs +++ b/tests/tests.rs @@ -282,3 +282,18 @@ trait CustomCollection {      fn test(&self) -> MyCollection<Self::A, Self::A, Self::A>;  } + +#[dynamize::dynamize] +trait SomeTrait { +    type Y: Into<String>; + +    fn foo(&self) -> Self::Y; +} + +#[dynamize::dynamize] +#[dynamized(SomeTrait)] +trait OneTrait: SomeTrait { +    type X: Into<String>; + +    fn test(&self) -> Self::X; +} diff --git a/ui-tests/src/bin/attr_dynamized_duplicate.rs b/ui-tests/src/bin/attr_dynamized_duplicate.rs new file mode 100644 index 0000000..fbe0d11 --- /dev/null +++ b/ui-tests/src/bin/attr_dynamized_duplicate.rs @@ -0,0 +1,6 @@ +#[dynamize::dynamize] +#[dynamized(Foo)] +#[dynamized(Foo)] +trait Trait {} + +fn main() {} diff --git a/ui-tests/src/bin/attr_dynamized_duplicate.stderr b/ui-tests/src/bin/attr_dynamized_duplicate.stderr new file mode 100644 index 0000000..6ff67d1 --- /dev/null +++ b/ui-tests/src/bin/attr_dynamized_duplicate.stderr @@ -0,0 +1,5 @@ +error: dynamized attribute is defined multiple times + --> src/bin/attr_dynamized_duplicate.rs:3:13 +  | +3 | #[dynamized(Foo)] +  |             ^^^ diff --git a/ui-tests/src/bin/attr_dynamized_no_such_supertrait.rs b/ui-tests/src/bin/attr_dynamized_no_such_supertrait.rs new file mode 100644 index 0000000..5b298ea --- /dev/null +++ b/ui-tests/src/bin/attr_dynamized_no_such_supertrait.rs @@ -0,0 +1,5 @@ +#[dynamize::dynamize] +#[dynamized(Foo)] +trait Trait {} + +fn main() {} diff --git a/ui-tests/src/bin/attr_dynamized_no_such_supertrait.stderr b/ui-tests/src/bin/attr_dynamized_no_such_supertrait.stderr new file mode 100644 index 0000000..b7e4cf4 --- /dev/null +++ b/ui-tests/src/bin/attr_dynamized_no_such_supertrait.stderr @@ -0,0 +1,5 @@ +error: this trait definition has no such supertrait + --> src/bin/attr_dynamized_no_such_supertrait.rs:2:13 +  | +2 | #[dynamized(Foo)] +  |             ^^^ | 
