From 2add2075dee5308e6cf4991aabe446c4ab313397 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Thu, 14 Nov 2019 23:31:49 +0100 Subject: [PATCH] Create derive proc-macro for Lift trait. --- src/librustc_macros/src/lib.rs | 2 ++ src/librustc_macros/src/lift.rs | 50 +++++++++++++++++++++++++++++++++ 2 files changed, 52 insertions(+) create mode 100644 src/librustc_macros/src/lift.rs 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 }) + } + }) +}