|
11 | 11 |
|
12 | 12 | extern crate proc_macro;
|
13 | 13 |
|
| 14 | +use proc_macro2::Ident; |
| 15 | +use proc_macro2::Span; |
14 | 16 | use proc_macro2::TokenStream;
|
15 | 17 | use quote::quote;
|
16 | 18 | use syn::parse_macro_input;
|
17 | 19 | use syn::Error;
|
| 20 | +use syn::GenericParam; |
18 | 21 | use syn::ItemTraitAlias;
|
| 22 | +use syn::TypeParam; |
19 | 23 |
|
20 | 24 | /// Implement a trait alias using a subtrait and blanket definition.
|
21 | 25 | ///
|
@@ -66,9 +70,26 @@ fn gen_trait_alias(trait_alias: ItemTraitAlias) -> Result<TokenStream, Error> {
|
66 | 70 | let vis = trait_alias.vis;
|
67 | 71 | let ident = trait_alias.ident;
|
68 | 72 | let bounds = trait_alias.bounds;
|
| 73 | + let generics = trait_alias.generics; |
| 74 | + |
| 75 | + // Pick a unique name. Ideally this would use `Span::def_site`, but it isn't stable. |
| 76 | + let blanket_type_ident = Ident::new("_TraitAliasImplBlanketType", Span::mixed_site()); |
| 77 | + let mut blanket_type_param = TypeParam::from(blanket_type_ident.clone()); |
| 78 | + blanket_type_param.bounds = bounds.clone(); |
| 79 | + |
| 80 | + // Append the blanket type to the end of the generic params of our `impl` block. |
| 81 | + // We'll implement our alias over that blanket type. |
| 82 | + let mut generics_with_blanket_type = generics.clone(); |
| 83 | + generics_with_blanket_type |
| 84 | + .params |
| 85 | + .push(GenericParam::Type(blanket_type_param)); |
| 86 | + |
| 87 | + // declare all the bits needed by quote |
| 88 | + let (trait_generics, ty_generics, where_clause) = generics.split_for_impl(); |
| 89 | + let (impl_generics, _, _) = generics_with_blanket_type.split_for_impl(); |
69 | 90 |
|
70 | 91 | Ok(quote! {
|
71 |
| - #vis trait #ident : #bounds {} |
72 |
| - impl<T> #ident for T where T: #bounds {} |
| 92 | + #vis trait #ident #trait_generics : #bounds #where_clause {} |
| 93 | + impl #impl_generics #ident #ty_generics for #blanket_type_ident #where_clause {} |
73 | 94 | })
|
74 | 95 | }
|
0 commit comments