summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_macros/src/lift.rs
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_macros/src/lift.rs')
-rw-r--r--compiler/rustc_macros/src/lift.rs52
1 files changed, 52 insertions, 0 deletions
diff --git a/compiler/rustc_macros/src/lift.rs b/compiler/rustc_macros/src/lift.rs
new file mode 100644
index 000000000..ad7ac7404
--- /dev/null
+++ b/compiler/rustc_macros/src/lift.rs
@@ -0,0 +1,52 @@
+use quote::quote;
+use syn::{self, parse_quote};
+
+pub fn lift_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::TokenStream {
+ s.add_bounds(synstructure::AddBounds::Generics);
+ s.bind_with(|_| synstructure::BindStyle::Move);
+
+ let tcx: syn::Lifetime = parse_quote!('tcx);
+ let newtcx: syn::GenericParam = parse_quote!('__lifted);
+
+ let lifted = {
+ let ast = s.ast();
+ let ident = &ast.ident;
+
+ // Replace `'tcx` lifetime by the `'__lifted` lifetime
+ let (_, generics, _) = ast.generics.split_for_impl();
+ let mut generics: syn::AngleBracketedGenericArguments = syn::parse_quote! { #generics };
+ for arg in generics.args.iter_mut() {
+ match arg {
+ syn::GenericArgument::Lifetime(l) if *l == tcx => {
+ *arg = parse_quote!('__lifted);
+ }
+ syn::GenericArgument::Type(t) => {
+ *arg = syn::parse_quote! { #t::Lifted };
+ }
+ _ => {}
+ }
+ }
+
+ quote! { #ident #generics }
+ };
+
+ let body = s.each_variant(|vi| {
+ let bindings = &vi.bindings();
+ vi.construct(|_, index| {
+ let bi = &bindings[index];
+ quote! { __tcx.lift(#bi)? }
+ })
+ });
+
+ s.add_impl_generic(newtcx);
+ s.bound_impl(
+ quote!(::rustc_middle::ty::Lift<'__lifted>),
+ quote! {
+ type Lifted = #lifted;
+
+ fn lift_to_tcx(self, __tcx: ::rustc_middle::ty::TyCtxt<'__lifted>) -> Option<#lifted> {
+ Some(match self { #body })
+ }
+ },
+ )
+}