Skip to content

Commit 0d6dcd0

Browse files
committed
Generalize infinite recursion avoidance logic
1 parent b105e2a commit 0d6dcd0

File tree

2 files changed

+39
-40
lines changed

2 files changed

+39
-40
lines changed

compiler/rustc_infer/src/infer/opaque_types.rs

+25-22
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ use crate::traits;
44
use hir::def::DefKind;
55
use hir::def_id::{DefId, LocalDefId};
66
use hir::{HirId, OpaqueTyOrigin};
7+
use rustc_data_structures::fx::FxHashSet;
78
use rustc_data_structures::sync::Lrc;
89
use rustc_data_structures::vec_map::VecMap;
910
use rustc_hir as hir;
@@ -16,7 +17,6 @@ use rustc_middle::ty::{
1617
};
1718
use rustc_middle::ty::{DefIdTree, GenericArgKind};
1819
use rustc_span::Span;
19-
use smallvec::SmallVec;
2020

2121
use std::ops::ControlFlow;
2222

@@ -673,29 +673,37 @@ pub fn may_define_opaque_type<'tcx>(
673673
struct Visitor<'tcx> {
674674
opaque_def_id: DefId,
675675
tcx: TyCtxt<'tcx>,
676-
ignore_nested: SmallVec<[DefId; 1]>,
676+
seen: FxHashSet<Ty<'tcx>>,
677677
param_env: ty::ParamEnv<'tcx>,
678678
}
679679
impl<'tcx> TypeVisitor<'tcx> for Visitor<'tcx> {
680680
type BreakTy = ();
681+
681682
#[instrument(skip(self), level = "trace", ret)]
682683
fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
684+
// Erase all lifetimes, they can't affect anything, but recursion
685+
// may cause late bound regions to differ, because the type visitor
686+
// can't erase them in `visit_binder`.
687+
let t = t.fold_with(&mut BottomUpFolder {
688+
tcx: self.tcx,
689+
ct_op: |c| c,
690+
ty_op: |t| t,
691+
lt_op: |_| self.tcx.lifetimes.re_erased,
692+
});
693+
if !self.seen.insert(t) {
694+
return ControlFlow::Continue(());
695+
}
683696
match t.kind() {
684697
ty::Alias(ty::Opaque, alias) => {
685698
if alias.def_id == self.opaque_def_id {
686699
return ControlFlow::Break(());
687700
}
688-
if !self.ignore_nested.contains(&alias.def_id) {
689-
// avoid infinite recursion since the opaque type shows
690-
// up in its own bounds.
691-
self.ignore_nested.push(alias.def_id);
692-
for (pred, _span) in self
693-
.tcx
694-
.bound_explicit_item_bounds(alias.def_id)
695-
.subst_iter_copied(self.tcx, alias.substs)
696-
{
697-
pred.visit_with(self)?;
698-
}
701+
for (pred, _span) in self
702+
.tcx
703+
.bound_explicit_item_bounds(alias.def_id)
704+
.subst_iter_copied(self.tcx, alias.substs)
705+
{
706+
pred.visit_with(self)?;
699707
}
700708
}
701709
ty::Alias(ty::Projection, _) => {
@@ -708,14 +716,9 @@ pub fn may_define_opaque_type<'tcx>(
708716
// Types that have opaque type fields must get walked manually, they
709717
// would not be seen by the type visitor otherwise.
710718
ty::Adt(adt_def, substs) => {
711-
if !self.ignore_nested.contains(&adt_def.did()) {
712-
// avoid infinite recursion since adts can recursively refer
713-
// to themselves
714-
self.ignore_nested.push(adt_def.did());
715-
for variant in adt_def.variants() {
716-
for field in &variant.fields {
717-
field.ty(self.tcx, substs).visit_with(self)?;
718-
}
719+
for variant in adt_def.variants() {
720+
for field in &variant.fields {
721+
field.ty(self.tcx, substs).visit_with(self)?;
719722
}
720723
}
721724
}
@@ -727,7 +730,7 @@ pub fn may_define_opaque_type<'tcx>(
727730
val.visit_with(&mut Visitor {
728731
opaque_def_id: opaque_def_id.to_def_id(),
729732
tcx,
730-
ignore_nested: SmallVec::new(),
733+
seen: Default::default(),
731734
param_env,
732735
})
733736
.is_break()

tests/ui/impl-trait/issues/issue-74282.stderr

+14-18
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
error[E0308]: mismatched types
2-
--> $DIR/issue-74282.rs:11:15
2+
--> $DIR/issue-74282.rs:7:15
33
|
4-
LL | type Closure = impl Fn() -> u64;
5-
| ---------------- the expected opaque type
4+
LL | type Closure = impl Fn() -> u64;
5+
| ---------------- the expected opaque type
66
...
77
LL | Anonymous(|| {
88
| _____---------_^
@@ -15,33 +15,29 @@ LL | | })
1515
| |_____^ expected closure, found a different closure
1616
|
1717
= note: expected opaque type `Closure`
18-
found closure `[closure@$DIR/issue-74282.rs:11:15: 11:17]`
18+
found closure `[closure@$DIR/issue-74282.rs:7:15: 7:17]`
1919
= note: no two closures, even if identical, have the same type
2020
= help: consider boxing your closure and/or using it as a trait object
2121
note: tuple struct defined here
22-
--> $DIR/issue-74282.rs:4:8
22+
--> $DIR/issue-74282.rs:5:12
2323
|
24-
LL | struct Anonymous(Closure);
25-
| ^^^^^^^^^
24+
LL | struct Anonymous(Closure);
25+
| ^^^^^^^^^
2626

2727
error[E0308]: mismatched types
28-
--> $DIR/issue-74282.rs:11:5
28+
--> $DIR/issue-74282.rs:7:5
2929
|
30+
LL | fn main() {
31+
| - expected `()` because of default return type
32+
...
3033
LL | / Anonymous(|| {
3134
LL | |
3235
LL | |
3336
LL | | 3
3437
LL | | })
35-
| |______^ expected `()`, found struct `Anonymous`
36-
|
37-
help: consider using a semicolon here
38-
|
39-
LL | });
40-
| +
41-
help: try adding a return type
42-
|
43-
LL | -> Anonymous where
44-
| ++++++++++++
38+
| | ^- help: consider using a semicolon here: `;`
39+
| |______|
40+
| expected `()`, found struct `Anonymous`
4541

4642
error: aborting due to 2 previous errors
4743

0 commit comments

Comments
 (0)