aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/lib.rs26
-rw-r--r--src/parse_attrs.rs29
-rw-r--r--tests/tests.rs15
-rw-r--r--ui-tests/src/bin/attr_dynamized_duplicate.rs6
-rw-r--r--ui-tests/src/bin/attr_dynamized_duplicate.stderr5
-rw-r--r--ui-tests/src/bin/attr_dynamized_no_such_supertrait.rs5
-rw-r--r--ui-tests/src/bin/attr_dynamized_no_such_supertrait.stderr5
7 files changed, 86 insertions, 5 deletions
diff --git a/src/lib.rs b/src/lib.rs
index f8fdde8..017a58b 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -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)]
+ | ^^^