Skip to content

Commit dce79e4

Browse files
committed
Unify traversable derive macro implementations
1 parent d6fcafe commit dce79e4

File tree

4 files changed

+129
-112
lines changed

4 files changed

+129
-112
lines changed

compiler/rustc_macros/src/lib.rs

+3-4
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,7 @@ mod newtype;
2323
mod query;
2424
mod serialize;
2525
mod symbols;
26-
mod type_foldable;
27-
mod type_visitable;
26+
mod traversable;
2827

2928
#[proc_macro]
3029
pub fn current_rustc_version(input: TokenStream) -> TokenStream {
@@ -98,7 +97,7 @@ decl_derive!(
9897
/// and
9998
///
10099
/// `impl<'tcx> TypeFoldable<TyCtxt<'tcx>> for Bar<'tcx>`
101-
type_foldable::type_foldable_derive
100+
traversable::traversable_derive::<traversable::Foldable>
102101
);
103102
decl_derive!(
104103
[TypeVisitable, attributes(type_visitable)] =>
@@ -124,7 +123,7 @@ decl_derive!(
124123
/// and
125124
///
126125
/// `impl<'tcx> TypeVisitable<TyCtxt<'tcx>> for Bar<'tcx>`
127-
type_visitable::type_visitable_derive
126+
traversable::traversable_derive::<traversable::Visitable>
128127
);
129128
decl_derive!([Lift, attributes(lift)] => lift::lift_derive);
130129
decl_derive!(
+126
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
use proc_macro2::TokenStream;
2+
use quote::{quote, ToTokens};
3+
use syn::parse_quote;
4+
5+
pub struct Foldable;
6+
pub struct Visitable;
7+
8+
/// An abstraction over traversable traits.
9+
pub trait Traversable {
10+
/// The trait that this `Traversable` represents.
11+
fn traversable() -> TokenStream;
12+
13+
/// The `match` arms for a traversal of this type.
14+
fn arms(structure: &mut synstructure::Structure<'_>) -> TokenStream;
15+
16+
/// The body of an implementation given the match `arms`.
17+
fn impl_body(arms: impl ToTokens) -> TokenStream;
18+
}
19+
20+
impl Traversable for Foldable {
21+
fn traversable() -> TokenStream {
22+
quote! { ::rustc_middle::ty::fold::TypeFoldable<::rustc_middle::ty::TyCtxt<'tcx>> }
23+
}
24+
fn arms(structure: &mut synstructure::Structure<'_>) -> TokenStream {
25+
structure.each_variant(|vi| {
26+
let bindings = vi.bindings();
27+
vi.construct(|_, index| {
28+
let bind = &bindings[index];
29+
30+
let mut fixed = false;
31+
32+
// retain value of fields with #[type_foldable(identity)]
33+
bind.ast().attrs.iter().for_each(|x| {
34+
if !x.path().is_ident("type_foldable") {
35+
return;
36+
}
37+
let _ = x.parse_nested_meta(|nested| {
38+
if nested.path.is_ident("identity") {
39+
fixed = true;
40+
}
41+
Ok(())
42+
});
43+
});
44+
45+
if fixed {
46+
bind.to_token_stream()
47+
} else {
48+
quote! {
49+
::rustc_middle::ty::fold::TypeFoldable::try_fold_with(#bind, __folder)?
50+
}
51+
}
52+
})
53+
})
54+
}
55+
fn impl_body(arms: impl ToTokens) -> TokenStream {
56+
quote! {
57+
fn try_fold_with<__F: ::rustc_middle::ty::fold::FallibleTypeFolder<::rustc_middle::ty::TyCtxt<'tcx>>>(
58+
self,
59+
__folder: &mut __F
60+
) -> ::core::result::Result<Self, __F::Error> {
61+
::core::result::Result::Ok(match self { #arms })
62+
}
63+
}
64+
}
65+
}
66+
67+
impl Traversable for Visitable {
68+
fn traversable() -> TokenStream {
69+
quote! { ::rustc_middle::ty::visit::TypeVisitable<::rustc_middle::ty::TyCtxt<'tcx>> }
70+
}
71+
fn arms(structure: &mut synstructure::Structure<'_>) -> TokenStream {
72+
// ignore fields with #[type_visitable(ignore)]
73+
structure.filter(|bi| {
74+
let mut ignored = false;
75+
76+
bi.ast().attrs.iter().for_each(|attr| {
77+
if !attr.path().is_ident("type_visitable") {
78+
return;
79+
}
80+
let _ = attr.parse_nested_meta(|nested| {
81+
if nested.path.is_ident("ignore") {
82+
ignored = true;
83+
}
84+
Ok(())
85+
});
86+
});
87+
88+
!ignored
89+
});
90+
91+
structure.each(|bind| {
92+
quote! {
93+
::rustc_middle::ty::visit::TypeVisitable::visit_with(#bind, __visitor)?;
94+
}
95+
})
96+
}
97+
fn impl_body(arms: impl ToTokens) -> TokenStream {
98+
quote! {
99+
fn visit_with<__V: ::rustc_middle::ty::visit::TypeVisitor<::rustc_middle::ty::TyCtxt<'tcx>>>(
100+
&self,
101+
__visitor: &mut __V
102+
) -> ::std::ops::ControlFlow<__V::BreakTy> {
103+
match self { #arms }
104+
::std::ops::ControlFlow::Continue(())
105+
}
106+
}
107+
}
108+
}
109+
110+
pub fn traversable_derive<T: Traversable>(
111+
mut structure: synstructure::Structure<'_>,
112+
) -> TokenStream {
113+
if let syn::Data::Union(_) = structure.ast().data {
114+
panic!("cannot derive on union")
115+
}
116+
117+
structure.add_bounds(synstructure::AddBounds::Generics);
118+
structure.bind_with(|_| synstructure::BindStyle::Move);
119+
120+
if !structure.ast().generics.lifetimes().any(|lt| lt.lifetime.ident == "tcx") {
121+
structure.add_impl_generic(parse_quote! { 'tcx });
122+
}
123+
124+
let arms = T::arms(&mut structure);
125+
structure.bound_impl(T::traversable(), T::impl_body(arms))
126+
}

compiler/rustc_macros/src/type_foldable.rs

-56
This file was deleted.

compiler/rustc_macros/src/type_visitable.rs

-52
This file was deleted.

0 commit comments

Comments
 (0)