Skip to content

Commit 147445a

Browse files
Merge pull request #43 from LukasKalbertodt/supertrait-bounds
Correctly work with supertrait bounds of the trait
2 parents c25b0e2 + 1144eb9 commit 147445a

File tree

5 files changed

+71
-2
lines changed

5 files changed

+71
-2
lines changed

src/gen.rs

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ pub(crate) fn gen_impls(
2828

2929
// One impl for each proxy type
3030
for proxy_type in proxy_types {
31-
let header = header(proxy_type, trait_def, &proxy_ty_param, &proxy_lt_param)?;
31+
let header = gen_header(proxy_type, trait_def, &proxy_ty_param, &proxy_lt_param)?;
3232
let items = gen_items(proxy_type, trait_def, &proxy_ty_param)?;
3333

3434
tokens.append_all(quote! {
@@ -41,7 +41,7 @@ pub(crate) fn gen_impls(
4141

4242
/// Generates the header of the impl of the given trait for the given proxy
4343
/// type.
44-
fn header(
44+
fn gen_header(
4545
proxy_type: &ProxyType,
4646
trait_def: &ItemTrait,
4747
proxy_ty_param: &Ident,
@@ -113,6 +113,24 @@ fn header(
113113
ProxyType::FnOnce => quote! { #proxy_ty_param },
114114
};
115115

116+
// If the trait has super traits, we need to add the super trait bound to
117+
// our self type. This can only be done in the where clause, so we need to
118+
// combine the existing where clauses with our new predicate in that case.
119+
let where_clause = if !trait_def.supertraits.is_empty() {
120+
let mut out = quote! { where };
121+
122+
if !trait_def.supertraits.is_empty() {
123+
let supertraits = &trait_def.supertraits;
124+
out.extend(quote! { #self_ty: #supertraits, });
125+
}
126+
if let Some(predicates) = where_clause.map(|c| &c.predicates) {
127+
out.extend(predicates.into_token_stream());
128+
}
129+
130+
out
131+
} else {
132+
where_clause.into_token_stream()
133+
};
116134

117135
// Combine everything
118136
Ok(quote! {
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
use auto_impl::auto_impl;
2+
3+
trait Supi {}
4+
5+
#[auto_impl(Box, &)]
6+
trait Foo: Supi {}
7+
8+
9+
struct Dog;
10+
impl Supi for Dog {}
11+
impl Foo for Dog {}
12+
13+
14+
fn requires_foo<T: Foo>(_: T) {}
15+
16+
fn main() {
17+
requires_foo(Dog); // should work
18+
requires_foo(Box::new(Dog)); // shouldn't, because `Box<Dog>: Supi` is not satisfied
19+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
use auto_impl::auto_impl;
2+
3+
trait Supi<'a, T> {
4+
fn supi(&self);
5+
}
6+
7+
#[auto_impl(Box, &)]
8+
trait Foo<T, U>: Supi<'static, U>
9+
where
10+
Self: Send
11+
{
12+
fn foo(&self) -> i32 {
13+
self.supi();
14+
3
15+
}
16+
17+
fn bar(&self);
18+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
use auto_impl::auto_impl;
2+
3+
trait Supi {}
4+
5+
#[auto_impl(Fn)]
6+
trait Foo: Supi {
7+
fn foo(&self, x: u32) -> String;
8+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
use auto_impl::auto_impl;
2+
3+
trait Supi {}
4+
5+
#[auto_impl(Box, &)]
6+
trait Foo: Supi {}

0 commit comments

Comments
 (0)