Skip to content

Commit 98728c2

Browse files
committed
Implement changes suggested by tmiasko and davidtwco
1 parent ee882b3 commit 98728c2

File tree

7 files changed

+42
-43
lines changed

7 files changed

+42
-43
lines changed

compiler/rustc_ty_utils/src/representability.rs

+42-43
Original file line numberDiff line numberDiff line change
@@ -25,20 +25,25 @@ pub enum Representability {
2525
pub fn ty_is_representable<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, sp: Span) -> Representability {
2626
debug!("is_type_representable: {:?}", ty);
2727
// To avoid a stack overflow when checking an enum variant or struct that
28-
// contains a different, structurally recursive type, maintain a stack
29-
// of seen types and check recursion for each of them (issues #3008, #3779).
28+
// contains a different, structurally recursive type, maintain a stack of
29+
// seen types and check recursion for each of them (issues #3008, #3779,
30+
// #74224, #84611). `shadow_seen` contains the full stack and `seen` only
31+
// the one for the current type (e.g. if we have structs A and B, B contains
32+
// a field of type A, and we're currently looking at B, then `seen` will be
33+
// cleared when recursing to check A, but `shadow_seen` won't, so that we
34+
// can catch cases of mutual recursion where A also contains B).
3035
let mut seen: Vec<Ty<'_>> = Vec::new();
31-
let mut shadow_seen: Vec<Ty<'_>> = Vec::new();
36+
let mut shadow_seen: Vec<&'tcx ty::AdtDef> = Vec::new();
3237
let mut representable_cache = FxHashMap::default();
33-
let mut f_res = false;
38+
let mut force_result = false;
3439
let r = is_type_structurally_recursive(
3540
tcx,
3641
sp,
3742
&mut seen,
3843
&mut shadow_seen,
3944
&mut representable_cache,
4045
ty,
41-
&mut f_res,
46+
&mut force_result,
4247
);
4348
debug!("is_type_representable: {:?} is {:?}", ty, r);
4449
r
@@ -58,10 +63,10 @@ fn are_inner_types_recursive<'tcx>(
5863
tcx: TyCtxt<'tcx>,
5964
sp: Span,
6065
seen: &mut Vec<Ty<'tcx>>,
61-
shadow_seen: &mut Vec<Ty<'tcx>>,
66+
shadow_seen: &mut Vec<&'tcx ty::AdtDef>,
6267
representable_cache: &mut FxHashMap<Ty<'tcx>, Representability>,
6368
ty: Ty<'tcx>,
64-
f_res: &mut bool,
69+
force_result: &mut bool,
6570
) -> Representability {
6671
debug!("are_inner_types_recursive({:?}, {:?}, {:?})", ty, seen, shadow_seen);
6772
match ty.kind() {
@@ -75,7 +80,7 @@ fn are_inner_types_recursive<'tcx>(
7580
shadow_seen,
7681
representable_cache,
7782
ty,
78-
f_res,
83+
force_result,
7984
)
8085
}))
8186
}
@@ -88,7 +93,7 @@ fn are_inner_types_recursive<'tcx>(
8893
shadow_seen,
8994
representable_cache,
9095
ty,
91-
f_res,
96+
force_result,
9297
),
9398
ty::Adt(def, substs) => {
9499
// Find non representable fields with their spans
@@ -125,22 +130,12 @@ fn are_inner_types_recursive<'tcx>(
125130
// case (shadow_seen.first() is the type we are originally
126131
// interested in, and if we ever encounter the same AdtDef again,
127132
// we know that it must be SelfRecursive) and "forcibly" returning
128-
// SelfRecursive (by setting f_res, which tells the calling
133+
// SelfRecursive (by setting force_result, which tells the calling
129134
// invocations of are_inner_types_representable to forward the
130135
// result without adjusting).
131-
if shadow_seen.len() > 1 && shadow_seen.len() > seen.len() {
132-
match shadow_seen.first().map(|ty| ty.kind()) {
133-
Some(ty::Adt(f_def, _)) => {
134-
if f_def == def {
135-
*f_res = true;
136-
result = Some(Representability::SelfRecursive(vec![span]));
137-
}
138-
}
139-
Some(_) => {
140-
bug!("shadow_seen stack contains non-ADT type: {:?}", ty);
141-
}
142-
None => unreachable!(),
143-
}
136+
if shadow_seen.len() > seen.len() && shadow_seen.first() == Some(def) {
137+
*force_result = true;
138+
result = Some(Representability::SelfRecursive(vec![span]));
144139
}
145140

146141
if result == None {
@@ -154,15 +149,11 @@ fn are_inner_types_recursive<'tcx>(
154149
// If we have encountered an ADT definition that we have not seen
155150
// before (no need to check them twice), recurse to see whether that
156151
// definition is SelfRecursive. If so, we must be ContainsRecursive.
157-
if shadow_seen.iter().len() > 1
158-
&& !shadow_seen.iter().take(shadow_seen.iter().len() - 1).any(|seen_ty| {
159-
match seen_ty.kind() {
160-
ty::Adt(seen_def, _) => seen_def == def,
161-
_ => {
162-
bug!("seen stack contains non-ADT type: {:?}", seen_ty);
163-
}
164-
}
165-
})
152+
if shadow_seen.len() > 1
153+
&& !shadow_seen
154+
.iter()
155+
.take(shadow_seen.len() - 1)
156+
.any(|seen_def| seen_def == def)
166157
{
167158
let adt_def_id = def.did;
168159
let raw_adt_ty = tcx.type_of(adt_def_id);
@@ -180,10 +171,10 @@ fn are_inner_types_recursive<'tcx>(
180171
shadow_seen,
181172
representable_cache,
182173
raw_adt_ty,
183-
f_res,
174+
force_result,
184175
) {
185176
Representability::SelfRecursive(_) => {
186-
if *f_res {
177+
if *force_result {
187178
Representability::SelfRecursive(vec![span])
188179
} else {
189180
Representability::ContainsRecursive
@@ -227,7 +218,7 @@ fn are_inner_types_recursive<'tcx>(
227218
shadow_seen,
228219
representable_cache,
229220
ty,
230-
f_res,
221+
force_result,
231222
) {
232223
Representability::SelfRecursive(_) => {
233224
Representability::SelfRecursive(vec![span])
@@ -263,10 +254,10 @@ fn is_type_structurally_recursive<'tcx>(
263254
tcx: TyCtxt<'tcx>,
264255
sp: Span,
265256
seen: &mut Vec<Ty<'tcx>>,
266-
shadow_seen: &mut Vec<Ty<'tcx>>,
257+
shadow_seen: &mut Vec<&'tcx ty::AdtDef>,
267258
representable_cache: &mut FxHashMap<Ty<'tcx>, Representability>,
268259
ty: Ty<'tcx>,
269-
f_res: &mut bool,
260+
force_result: &mut bool,
270261
) -> Representability {
271262
debug!("is_type_structurally_recursive: {:?} {:?}", ty, sp);
272263
if let Some(representability) = representable_cache.get(ty) {
@@ -284,7 +275,7 @@ fn is_type_structurally_recursive<'tcx>(
284275
shadow_seen,
285276
representable_cache,
286277
ty,
287-
f_res,
278+
force_result,
288279
);
289280

290281
representable_cache.insert(ty, representability.clone());
@@ -295,10 +286,10 @@ fn is_type_structurally_recursive_inner<'tcx>(
295286
tcx: TyCtxt<'tcx>,
296287
sp: Span,
297288
seen: &mut Vec<Ty<'tcx>>,
298-
shadow_seen: &mut Vec<Ty<'tcx>>,
289+
shadow_seen: &mut Vec<&'tcx ty::AdtDef>,
299290
representable_cache: &mut FxHashMap<Ty<'tcx>, Representability>,
300291
ty: Ty<'tcx>,
301-
f_res: &mut bool,
292+
force_result: &mut bool,
302293
) -> Representability {
303294
match ty.kind() {
304295
ty::Adt(def, _) => {
@@ -346,23 +337,31 @@ fn is_type_structurally_recursive_inner<'tcx>(
346337
// For structs and enums, track all previously seen types by pushing them
347338
// onto the 'seen' stack.
348339
seen.push(ty);
349-
shadow_seen.push(ty);
340+
shadow_seen.push(def);
350341
let out = are_inner_types_recursive(
351342
tcx,
352343
sp,
353344
seen,
354345
shadow_seen,
355346
representable_cache,
356347
ty,
357-
f_res,
348+
force_result,
358349
);
359350
shadow_seen.pop();
360351
seen.pop();
361352
out
362353
}
363354
_ => {
364355
// No need to push in other cases.
365-
are_inner_types_recursive(tcx, sp, seen, shadow_seen, representable_cache, ty, f_res)
356+
are_inner_types_recursive(
357+
tcx,
358+
sp,
359+
seen,
360+
shadow_seen,
361+
representable_cache,
362+
ty,
363+
force_result,
364+
)
366365
}
367366
}
368367
}

0 commit comments

Comments
 (0)