about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorCamille GILLOT <gillot.camille@gmail.com>2019-11-14 23:31:49 +0100
committerCamille GILLOT <gillot.camille@gmail.com>2019-11-18 08:41:28 +0100
commit2add2075dee5308e6cf4991aabe446c4ab313397 (patch)
treebdad69ffea3b816d385badaa8061ee8e733f2c5a /src
parentd8014582b843d8722795b06586ef9c2042094963 (diff)
downloadrust-2add2075dee5308e6cf4991aabe446c4ab313397.tar.gz
rust-2add2075dee5308e6cf4991aabe446c4ab313397.zip
Create derive proc-macro for Lift trait.
Diffstat (limited to 'src')
-rw-r--r--src/librustc_macros/src/lib.rs2
-rw-r--r--src/librustc_macros/src/lift.rs50
2 files changed, 52 insertions, 0 deletions
diff --git a/src/librustc_macros/src/lib.rs b/src/librustc_macros/src/lib.rs
index 351d60b9368..dce3820d284 100644
--- a/src/librustc_macros/src/lib.rs
+++ b/src/librustc_macros/src/lib.rs
@@ -10,6 +10,7 @@ use proc_macro::TokenStream;
 
 mod hash_stable;
 mod type_foldable;
+mod lift;
 mod query;
 mod symbols;
 
@@ -25,3 +26,4 @@ pub fn symbols(input: TokenStream) -> TokenStream {
 
 decl_derive!([HashStable, attributes(stable_hasher)] => hash_stable::hash_stable_derive);
 decl_derive!([TypeFoldable, attributes(type_foldable)] => type_foldable::type_foldable_derive);
+decl_derive!([Lift, attributes(lift)] => lift::lift_derive);
diff --git a/src/librustc_macros/src/lift.rs b/src/librustc_macros/src/lift.rs
new file mode 100644
index 00000000000..8a7734b147f
--- /dev/null
+++ b/src/librustc_macros/src/lift.rs
@@ -0,0 +1,50 @@
+use synstructure;
+use syn::{self, parse_quote};
+use proc_macro2;
+use quote::quote;
+
+pub fn lift_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::TokenStream {
+    s.add_bounds(synstructure::AddBounds::Generics);
+
+    let tcx: syn::Lifetime = parse_quote!('tcx);
+    let newtcx: syn::GenericParam = parse_quote!('__newtcx);
+
+    let lifted = {
+        let ast = s.ast();
+        let ident = &ast.ident;
+
+        // Replace `'tcx` lifetime by the `'__newtcx` 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!('__newtcx);
+                },
+                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::ty::Lift<'__newtcx>), quote!{
+        type Lifted = #lifted;
+
+        fn lift_to_tcx(&self, __tcx: ::rustc::ty::TyCtxt<'__newtcx>) -> Option<#lifted> {
+            Some(match *self { #body })
+        }
+    })
+}