rustc_macros/
type_foldable.rs
1use 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 s.underscore_const(true);
10
11 if !s.ast().generics.lifetimes().any(|lt| lt.lifetime.ident == "tcx") {
12 s.add_impl_generic(parse_quote! { 'tcx });
13 }
14
15 s.add_bounds(synstructure::AddBounds::Generics);
16 s.bind_with(|_| synstructure::BindStyle::Move);
17 let body_fold = s.each_variant(|vi| {
18 let bindings = vi.bindings();
19 vi.construct(|_, index| {
20 let bind = &bindings[index];
21
22 let mut fixed = false;
23
24 bind.ast().attrs.iter().for_each(|x| {
26 if !x.path().is_ident("type_foldable") {
27 return;
28 }
29 let _ = x.parse_nested_meta(|nested| {
30 if nested.path.is_ident("identity") {
31 fixed = true;
32 }
33 Ok(())
34 });
35 });
36
37 if fixed {
38 bind.to_token_stream()
39 } else {
40 quote! {
41 ::rustc_middle::ty::fold::TypeFoldable::try_fold_with(#bind, __folder)?
42 }
43 }
44 })
45 });
46
47 s.bound_impl(
48 quote!(::rustc_middle::ty::fold::TypeFoldable<::rustc_middle::ty::TyCtxt<'tcx>>),
49 quote! {
50 fn try_fold_with<__F: ::rustc_middle::ty::fold::FallibleTypeFolder<::rustc_middle::ty::TyCtxt<'tcx>>>(
51 self,
52 __folder: &mut __F
53 ) -> Result<Self, __F::Error> {
54 Ok(match self { #body_fold })
55 }
56 },
57 )
58}