Hi all,
In procedural macro, I can't find how to add an additional lifetime to the set of lifetimes returned by syn::Generics::split_for_impl()
For example, if have this:
let (impl_generics, ty_generics, where_clause) = ast.generics.split_for_impl();
I don't know how to add another lifetime to impl_generics
variable:
impl 'a #impl_generics MyTrait for #struct_name #ty_generics #where_clause {
fn my_fn<R: std::io::Read>(&mut self, buffer: &mut R) -> Result<(), Error> {
#( #method_calls)*
Ok(())
}
}
doesn't work.
Any hint ?
Thanks a lot.
What I usually do is to create a second instance of Generics
where I add the new lifetime/type generics and bounds, then I split both and use the ty_generics
from the original one and the impl_generics
and where_clause
from the new one. It would be nice if there was a way that doesn't involve cloning though.
1 Like
Ok thanks, but how do you add another lifetime to the second impl_generics
?
Looks to me, peeking at the source code of ToTokens for ImplGenerics<'_>
that out-of-order lifetimes (e.g. lifetimes appearing later than consts/types) and missing <
>
tokens are properly supported and fixed up while printing. So it might simply work to (clone the Generics
, if you still need the unmodified original one, and then) use .push
on the params
field. Or maybe use .insert
at index 0 if you really want that new lifetime first.
If you don’t want to construct the datatype of the generic yourself, you could try generics.param.push(parse_quote!('a))
. I’m not a hygiene expert but one should probably also consider parse_quote_spanned!(Span::mixed_site() => 'a)
as an option… feel free to test which works better, especially if the struct already comes with another lifetime names 'a
.
Yes, works like that:
let mut gen_clone = ast.generics.clone();
let lt = Lifetime::new("'a", Span::call_site());
let ltp = LifetimeParam::new(lt);
gen_clone.params.push(GenericParam::from(ltp));
let (impl_generics2, _, _) = gen_clone.split_for_impl();
Thanks @steffahn & @SkiFire13 for your help !
Ah you already answered… I’ve included an edit to also consider Span::mixed_site()
for the new lifetime; which – as far as I understand from the docs – may help avoid any naming conflict with other pre-existing lifetimes also named 'a
that come from the user of your procedural macro. Feel free to test if it actually works like that
– also, even with hygiene, I’m not sure if it won’t generate confusing docs with the same lifetime re-appearing (feel free to answer that in case you test it), in which case a less common name than 'a
might be nicer
1 Like