diff options
Diffstat (limited to 'compiler/rustc_macros/src/type_foldable.rs')
-rw-r--r-- | compiler/rustc_macros/src/type_foldable.rs | 33 |
1 files changed, 27 insertions, 6 deletions
diff --git a/compiler/rustc_macros/src/type_foldable.rs b/compiler/rustc_macros/src/type_foldable.rs index 23e619221..388e254cd 100644 --- a/compiler/rustc_macros/src/type_foldable.rs +++ b/compiler/rustc_macros/src/type_foldable.rs @@ -1,5 +1,5 @@ -use quote::quote; -use syn::parse_quote; +use quote::{quote, ToTokens}; +use syn::{parse_quote, Attribute, Meta, NestedMeta}; pub fn type_foldable_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::TokenStream { if let syn::Data::Union(_) = s.ast().data { @@ -16,16 +16,37 @@ pub fn type_foldable_derive(mut s: synstructure::Structure<'_>) -> proc_macro2:: let bindings = vi.bindings(); vi.construct(|_, index| { let bind = &bindings[index]; - quote! { - ::rustc_middle::ty::fold::TypeFoldable::try_fold_with(#bind, __folder)? + + // retain value of fields with #[type_foldable(identity)] + let fixed = bind + .ast() + .attrs + .iter() + .map(Attribute::parse_meta) + .filter_map(Result::ok) + .flat_map(|attr| match attr { + Meta::List(list) if list.path.is_ident("type_foldable") => list.nested, + _ => Default::default(), + }) + .any(|nested| match nested { + NestedMeta::Meta(Meta::Path(path)) => path.is_ident("identity"), + _ => false, + }); + + if fixed { + bind.to_token_stream() + } else { + quote! { + ::rustc_middle::ty::fold::TypeFoldable::try_fold_with(#bind, __folder)? + } } }) }); s.bound_impl( - quote!(::rustc_middle::ty::fold::TypeFoldable<'tcx>), + quote!(::rustc_middle::ty::fold::TypeFoldable<::rustc_middle::ty::TyCtxt<'tcx>>), quote! { - fn try_fold_with<__F: ::rustc_middle::ty::fold::FallibleTypeFolder<'tcx>>( + fn try_fold_with<__F: ::rustc_middle::ty::fold::FallibleTypeFolder<::rustc_middle::ty::TyCtxt<'tcx>>>( self, __folder: &mut __F ) -> Result<Self, __F::Error> { |