Skip to content

Commit d0b565d

Browse files
authored
Unrolled build for #157695
Rollup merge of #157695 - Jamesbarford:feat/extend-type-foldable-generic, r=lcnr Extend capabilities of `TypeFoldable_Generic` Split from #156538. - Lets `TypeFoldable_Generic` derive structural folding for types with extra generic parameters by adding the necessary `T: TypeFoldable<I>` bounds automatically - Means in #156538 we can remove the manual `TypeFoldable` implementation for `NormalizesTo` - Refactors shared traversal logic between `Lift_Generic` and `TypeFoldable_Generic` into a shared helper with a callback. r? @lcnr
2 parents 3bdd7f8 + 23e03d9 commit d0b565d

3 files changed

Lines changed: 93 additions & 20 deletions

File tree

Cargo.lock

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4892,6 +4892,7 @@ dependencies = [
48924892
name = "rustc_type_ir_macros"
48934893
version = "0.0.0"
48944894
dependencies = [
4895+
"indexmap",
48954896
"proc-macro2",
48964897
"quote",
48974898
"syn",

compiler/rustc_type_ir_macros/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ nightly = []
1111

1212
[dependencies]
1313
# tidy-alphabetical-start
14+
indexmap = "2.4.0"
1415
proc-macro2 = "1"
1516
quote = "1"
1617
syn = { version = "2.0.9", features = ["full", "visit-mut"] }

compiler/rustc_type_ir_macros/src/lib.rs

Lines changed: 91 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use indexmap::IndexSet;
12
use quote::{ToTokens, quote};
23
use syn::visit_mut::VisitMut;
34
use syn::{Attribute, parse_quote};
@@ -17,11 +18,24 @@ decl_derive!(
1718
[GenericTypeVisitable] => customizable_type_visitable_derive
1819
);
1920

20-
struct LiftedTy {
21+
struct TransformedTy {
2122
ty: syn::Type,
22-
generic_parameter_bounds: Vec<syn::Ident>,
23+
generic_parameter_bounds: IndexSet<syn::Ident>,
2324
}
2425

26+
enum TypeParameterPath {
27+
Interner,
28+
GenericParameter(syn::Ident),
29+
}
30+
31+
enum TypeParameterTransform {
32+
Continue,
33+
Stop,
34+
}
35+
36+
type TypeParameterVisitor =
37+
fn(TypeParameterPath, &mut syn::TypePath, &mut IndexSet<syn::Ident>) -> TypeParameterTransform;
38+
2539
fn has_ignore_attr(attrs: &[Attribute], name: &'static str, meta: &'static str) -> bool {
2640
let mut ignored = false;
2741
attrs.iter().for_each(|attr| {
@@ -91,6 +105,9 @@ fn type_foldable_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::Toke
91105

92106
s.add_where_predicate(parse_quote! { I: Interner });
93107
s.add_bounds(synstructure::AddBounds::Fields);
108+
let generic_parameters =
109+
s.ast().generics.type_params().map(|ty| ty.ident.clone()).collect::<Vec<_>>();
110+
let mut generic_parameter_bounds = IndexSet::new();
94111
s.bind_with(|_| synstructure::BindStyle::Move);
95112
let body_try_fold = s.each_variant(|vi| {
96113
let bindings = vi.bindings();
@@ -101,6 +118,12 @@ fn type_foldable_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::Toke
101118
if has_ignore_attr(&bind.ast().attrs, "type_foldable", "identity") {
102119
bind.to_token_stream()
103120
} else {
121+
for param in
122+
type_foldable_generic_parameters(bind.ast().ty.clone(), &generic_parameters)
123+
{
124+
generic_parameter_bounds.insert(param);
125+
}
126+
104127
quote! {
105128
::rustc_type_ir::TypeFoldable::try_fold_with(#bind, __folder)?
106129
}
@@ -129,6 +152,9 @@ fn type_foldable_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::Toke
129152
// to generate code for them.
130153
s.filter(|bi| !has_ignore_attr(&bi.ast().attrs, "type_foldable", "identity"));
131154
s.add_bounds(synstructure::AddBounds::Fields);
155+
for param in generic_parameter_bounds {
156+
s.add_where_predicate(parse_quote! { #param: ::rustc_type_ir::TypeFoldable<I> });
157+
}
132158
s.bound_impl(
133159
quote!(::rustc_type_ir::TypeFoldable<I>),
134160
quote! {
@@ -149,6 +175,19 @@ fn type_foldable_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::Toke
149175
)
150176
}
151177

178+
fn type_foldable_generic_parameters(
179+
ty: syn::Type,
180+
generic_parameters: &[syn::Ident],
181+
) -> IndexSet<syn::Ident> {
182+
transform_type_parameters(ty, generic_parameters, |path, _, generic_parameter_bounds| {
183+
if let TypeParameterPath::GenericParameter(param) = path {
184+
generic_parameter_bounds.insert(param);
185+
}
186+
TypeParameterTransform::Continue
187+
})
188+
.generic_parameter_bounds
189+
}
190+
152191
/// `Lift_Generic` is specialised for structs/enums parameterised by an interner
153192
/// `I: Interner`. It derives `Lift<J>` by rewriting interner associated types
154193
/// from `I::Assoc` to `J::Assoc`. The required associated type lift bounds are
@@ -251,40 +290,72 @@ fn is_type_phantom(ty: &syn::Type) -> bool {
251290
get_first_path_segment(ty).is_some_and(|segment| segment.ident == "PhantomData")
252291
}
253292

254-
fn lift(mut ty: syn::Type, generic_parameters: &[syn::Ident]) -> LiftedTy {
255-
struct ItoJ<'a> {
293+
fn lift(ty: syn::Type, generic_parameters: &[syn::Ident]) -> TransformedTy {
294+
transform_type_parameters(ty, generic_parameters, |path, ty, generic_parameter_bounds| {
295+
match path {
296+
TypeParameterPath::Interner => {
297+
*ty.path.segments.first_mut().unwrap() = parse_quote! { J };
298+
TypeParameterTransform::Continue
299+
}
300+
TypeParameterPath::GenericParameter(param) => {
301+
generic_parameter_bounds.insert(param.clone());
302+
*ty = parse_quote! { <#param as ::rustc_type_ir::lift::Lift<J>>::Lifted };
303+
TypeParameterTransform::Stop
304+
}
305+
}
306+
})
307+
}
308+
309+
fn transform_type_parameters(
310+
mut ty: syn::Type,
311+
generic_parameters: &[syn::Ident],
312+
visit: TypeParameterVisitor,
313+
) -> TransformedTy {
314+
struct TypeParameterTransformer<'a> {
256315
generic_parameters: &'a [syn::Ident],
257-
generic_parameter_bounds: Vec<syn::Ident>,
316+
generic_parameter_bounds: IndexSet<syn::Ident>,
317+
visit: TypeParameterVisitor,
258318
}
259319

260-
impl VisitMut for ItoJ<'_> {
320+
impl VisitMut for TypeParameterTransformer<'_> {
261321
fn visit_type_path_mut(&mut self, i: &mut syn::TypePath) {
262-
if i.qself.is_none() {
322+
let path = if i.qself.is_none() {
263323
let segments_len = i.path.segments.len();
264-
if let Some(first) = i.path.segments.first_mut() {
265-
// Turn paths from `I` into `J`
324+
i.path.segments.first().and_then(|first| {
266325
if first.ident == "I" {
267-
*first = parse_quote! { J };
326+
Some(TypeParameterPath::Interner)
268327
} else if segments_len == 1
269328
&& matches!(first.arguments, syn::PathArguments::None)
270-
&& self.generic_parameters.iter().any(|param| first.ident == *param)
329+
&& self.generic_parameters.contains(&first.ident)
271330
{
272-
let ident = first.ident.clone();
273-
if !self.generic_parameter_bounds.iter().any(|param| *param == ident) {
274-
self.generic_parameter_bounds.push(ident.clone());
275-
}
276-
277-
*i = parse_quote! { <#ident as ::rustc_type_ir::lift::Lift<J>>::Lifted };
278-
return;
331+
Some(TypeParameterPath::GenericParameter(first.ident.clone()))
332+
} else {
333+
None
279334
}
335+
})
336+
} else {
337+
None
338+
};
339+
340+
if let Some(path) = path {
341+
if let TypeParameterTransform::Stop =
342+
(self.visit)(path, i, &mut self.generic_parameter_bounds)
343+
{
344+
return;
280345
}
281346
}
347+
282348
syn::visit_mut::visit_type_path_mut(self, i);
283349
}
284350
}
285-
let mut visitor = ItoJ { generic_parameters, generic_parameter_bounds: Vec::new() };
351+
352+
let mut visitor = TypeParameterTransformer {
353+
generic_parameters,
354+
generic_parameter_bounds: IndexSet::new(),
355+
visit,
356+
};
286357
visitor.visit_type_mut(&mut ty);
287-
LiftedTy { ty, generic_parameter_bounds: visitor.generic_parameter_bounds }
358+
TransformedTy { ty, generic_parameter_bounds: visitor.generic_parameter_bounds }
288359
}
289360

290361
#[cfg(not(feature = "nightly"))]

0 commit comments

Comments
 (0)