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