rustc_macros/
lift.rs

1use quote::quote;
2use syn::parse_quote;
3
4pub(super) 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(quote!(::rustc_middle::ty::Lift<::rustc_middle::ty::TyCtxt<'__lifted>>), quote! {
43        type Lifted = #lifted;
44
45        fn lift_to_interner(self, __tcx: ::rustc_middle::ty::TyCtxt<'__lifted>) -> Option<#lifted> {
46            Some(match self { #body })
47        }
48    })
49}