1 use quote::quote; 2 use syn::{self, parse_quote}; 3 lift_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::TokenStream4pub fn lift_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::TokenStream { 5 s.add_bounds(synstructure::AddBounds::Generics); 6 s.bind_with(|_| synstructure::BindStyle::Move); 7 8 let tcx: syn::Lifetime = parse_quote!('tcx); 9 let newtcx: syn::GenericParam = parse_quote!('__lifted); 10 11 let lifted = { 12 let ast = s.ast(); 13 let ident = &ast.ident; 14 15 // Replace `'tcx` lifetime by the `'__lifted` lifetime 16 let (_, generics, _) = ast.generics.split_for_impl(); 17 let mut generics: syn::AngleBracketedGenericArguments = syn::parse_quote! { #generics }; 18 for arg in generics.args.iter_mut() { 19 match arg { 20 syn::GenericArgument::Lifetime(l) if *l == tcx => { 21 *arg = parse_quote!('__lifted); 22 } 23 syn::GenericArgument::Type(t) => { 24 *arg = syn::parse_quote! { #t::Lifted }; 25 } 26 _ => {} 27 } 28 } 29 30 quote! { #ident #generics } 31 }; 32 33 let body = s.each_variant(|vi| { 34 let bindings = &vi.bindings(); 35 vi.construct(|_, index| { 36 let bi = &bindings[index]; 37 quote! { __tcx.lift(#bi)? } 38 }) 39 }); 40 41 s.add_impl_generic(newtcx); 42 s.bound_impl( 43 quote!(::rustc_middle::ty::Lift<'__lifted>), 44 quote! { 45 type Lifted = #lifted; 46 47 fn lift_to_tcx(self, __tcx: ::rustc_middle::ty::TyCtxt<'__lifted>) -> Option<#lifted> { 48 Some(match self { #body }) 49 } 50 }, 51 ) 52 } 53