From 9e28e9c545ab86f314ed242922f3d83e69319e45 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Wed, 13 Nov 2019 20:47:41 +0100 Subject: [PATCH] Create TypeFoldable derive proc-macro. --- src/librustc_macros/src/lib.rs | 2 ++ src/librustc_macros/src/type_foldable.rs | 39 ++++++++++++++++++++++++ 2 files changed, 41 insertions(+) create mode 100644 src/librustc_macros/src/type_foldable.rs diff --git a/src/librustc_macros/src/lib.rs b/src/librustc_macros/src/lib.rs index 0540c95d3de..351d60b9368 100644 --- a/src/librustc_macros/src/lib.rs +++ b/src/librustc_macros/src/lib.rs @@ -9,6 +9,7 @@ use synstructure::decl_derive; use proc_macro::TokenStream; mod hash_stable; +mod type_foldable; mod query; mod symbols; @@ -23,3 +24,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); diff --git a/src/librustc_macros/src/type_foldable.rs b/src/librustc_macros/src/type_foldable.rs new file mode 100644 index 00000000000..e6057767b47 --- /dev/null +++ b/src/librustc_macros/src/type_foldable.rs @@ -0,0 +1,39 @@ +use synstructure; +use syn; +use quote::quote; + +pub fn type_foldable_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::TokenStream { + if let syn::Data::Union(_) = s.ast().data { + panic!("cannot derive on union") + } + + s.add_bounds(synstructure::AddBounds::Generics); + let body_fold = s.each_variant(|vi| { + let bindings = vi.bindings(); + vi.construct(|_, index| { + let bind = &bindings[index]; + quote!{ + ::rustc::ty::fold::TypeFoldable::fold_with(#bind, __folder) + } + }) + }); + let body_visit = s.fold(false, |acc, bind| { + quote!{ #acc || ::rustc::ty::fold::TypeFoldable::visit_with(#bind, __folder) } + }); + + s.bound_impl(quote!(::rustc::ty::fold::TypeFoldable<'tcx>), quote!{ + fn super_fold_with<__F: ::rustc::ty::fold::TypeFolder<'tcx>>( + &self, + __folder: &mut __F + ) -> Self { + match *self { #body_fold } + } + + fn super_visit_with<__F: ::rustc::ty::fold::TypeVisitor<'tcx>>( + &self, + __folder: &mut __F + ) -> bool { + match *self { #body_visit } + } + }) +}