rustc_macros/
type_foldable.rs1use quote::{ToTokens, quote};
2use syn::parse_quote;
3
4pub(super) fn type_foldable_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::TokenStream {
5 if let syn::Data::Union(_) = s.ast().data {
6 panic!("cannot derive on union")
7 }
8
9 if !s.ast().generics.lifetimes().any(|lt| lt.lifetime.ident == "tcx") {
10 s.add_impl_generic(parse_quote! { 'tcx });
11 }
12
13 s.add_bounds(synstructure::AddBounds::Generics);
14 s.bind_with(|_| synstructure::BindStyle::Move);
15 let try_body_fold = s.each_variant(|vi| {
16 let bindings = vi.bindings();
17 vi.construct(|_, index| {
18 let bind = &bindings[index];
19
20 if has_ignore_attr(&bind.ast().attrs, "type_foldable", "identity") {
22 bind.to_token_stream()
23 } else {
24 quote! {
25 ::rustc_middle::ty::TypeFoldable::try_fold_with(#bind, __folder)?
26 }
27 }
28 })
29 });
30
31 let body_fold = s.each_variant(|vi| {
32 let bindings = vi.bindings();
33 vi.construct(|_, index| {
34 let bind = &bindings[index];
35
36 if has_ignore_attr(&bind.ast().attrs, "type_foldable", "identity") {
38 bind.to_token_stream()
39 } else {
40 quote! {
41 ::rustc_middle::ty::TypeFoldable::fold_with(#bind, __folder)
42 }
43 }
44 })
45 });
46
47 s.bound_impl(
48 quote!(::rustc_middle::ty::TypeFoldable<::rustc_middle::ty::TyCtxt<'tcx>>),
49 quote! {
50 fn try_fold_with<__F: ::rustc_middle::ty::FallibleTypeFolder<::rustc_middle::ty::TyCtxt<'tcx>>>(
51 self,
52 __folder: &mut __F
53 ) -> Result<Self, __F::Error> {
54 Ok(match self { #try_body_fold })
55 }
56
57 fn fold_with<__F: ::rustc_middle::ty::TypeFolder<::rustc_middle::ty::TyCtxt<'tcx>>>(
58 self,
59 __folder: &mut __F
60 ) -> Self {
61 match self { #body_fold }
62 }
63 },
64 )
65}
66
67fn has_ignore_attr(attrs: &[syn::Attribute], name: &'static str, meta: &'static str) -> bool {
68 let mut ignored = false;
69 attrs.iter().for_each(|attr| {
70 if !attr.path().is_ident(name) {
71 return;
72 }
73 let _ = attr.parse_nested_meta(|nested| {
74 if nested.path.is_ident(meta) {
75 ignored = true;
76 }
77 Ok(())
78 });
79 });
80
81 ignored
82}