Skip to content

Commit 0d34a87

Browse files
committed
Auto merge of #68772 - matthewjasper:relate-opt, r=davidtwco
Avoid exponential behaviour when relating types When equating bound types we check subtyping in both directions. Since closures are invariant in their substs, we end up comparing the two types an exponential number of times. If there are no bound variables this isn't needed. Closes #68061
2 parents a2e8030 + a606ffd commit 0d34a87

File tree

3 files changed

+42
-2
lines changed

3 files changed

+42
-2
lines changed

Diff for: src/librustc/infer/equate.rs

+8-2
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,13 @@ impl TypeRelation<'tcx> for Equate<'combine, 'infcx, 'tcx> {
125125
where
126126
T: Relate<'tcx>,
127127
{
128-
self.fields.higher_ranked_sub(a, b, self.a_is_expected)?;
129-
self.fields.higher_ranked_sub(b, a, self.a_is_expected)
128+
if a.skip_binder().has_escaping_bound_vars() || b.skip_binder().has_escaping_bound_vars() {
129+
self.fields.higher_ranked_sub(a, b, self.a_is_expected)?;
130+
self.fields.higher_ranked_sub(b, a, self.a_is_expected)
131+
} else {
132+
// Fast path for the common case.
133+
self.relate(a.skip_binder(), b.skip_binder())?;
134+
return Ok(a.clone());
135+
}
130136
}
131137
}

Diff for: src/librustc/infer/nll_relate/mod.rs

+11
Original file line numberDiff line numberDiff line change
@@ -529,6 +529,10 @@ where
529529
b = self.infcx.shallow_resolve(b);
530530
}
531531

532+
if a == b {
533+
return Ok(a);
534+
}
535+
532536
match (&a.kind, &b.kind) {
533537
(_, &ty::Infer(ty::TyVar(vid))) => {
534538
if D::forbid_inference_vars() {
@@ -638,6 +642,13 @@ where
638642

639643
debug!("binders({:?}: {:?}, ambient_variance={:?})", a, b, self.ambient_variance);
640644

645+
if !a.skip_binder().has_escaping_bound_vars() && !b.skip_binder().has_escaping_bound_vars()
646+
{
647+
// Fast path for the common case.
648+
self.relate(a.skip_binder(), b.skip_binder())?;
649+
return Ok(a.clone());
650+
}
651+
641652
if self.ambient_covariance() {
642653
// Covariance, so we want `for<..> A <: for<..> B` --
643654
// therefore we compare any instantiation of A (i.e., A

Diff for: src/test/ui/closures/deeply-nested_closures.rs

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
// Check that this can be compiled in a reasonable time.
2+
3+
// build-pass
4+
5+
fn main() {
6+
// 96 nested closures
7+
let x = ();
8+
|| || || || || || || ||
9+
|| || || || || || || ||
10+
|| || || || || || || ||
11+
|| || || || || || || ||
12+
13+
|| || || || || || || ||
14+
|| || || || || || || ||
15+
|| || || || || || || ||
16+
|| || || || || || || ||
17+
18+
|| || || || || || || ||
19+
|| || || || || || || ||
20+
|| || || || || || || ||
21+
|| || || || || || || ||
22+
[&(), &x];
23+
}

0 commit comments

Comments
 (0)