Avoid exponential behaviour when relating types

This commit is contained in:
Matthew Jasper 2020-02-02 11:54:11 +00:00
parent 13db6501c7
commit a606ffdb17
3 changed files with 42 additions and 2 deletions

View File

@ -125,7 +125,13 @@ impl TypeRelation<'tcx> for Equate<'combine, 'infcx, 'tcx> {
where
T: Relate<'tcx>,
{
self.fields.higher_ranked_sub(a, b, self.a_is_expected)?;
self.fields.higher_ranked_sub(b, a, self.a_is_expected)
if a.skip_binder().has_escaping_bound_vars() || b.skip_binder().has_escaping_bound_vars() {
self.fields.higher_ranked_sub(a, b, self.a_is_expected)?;
self.fields.higher_ranked_sub(b, a, self.a_is_expected)
} else {
// Fast path for the common case.
self.relate(a.skip_binder(), b.skip_binder())?;
return Ok(a.clone());
}
}
}

View File

@ -529,6 +529,10 @@ where
b = self.infcx.shallow_resolve(b);
}
if a == b {
return Ok(a);
}
match (&a.kind, &b.kind) {
(_, &ty::Infer(ty::TyVar(vid))) => {
if D::forbid_inference_vars() {
@ -638,6 +642,13 @@ where
debug!("binders({:?}: {:?}, ambient_variance={:?})", a, b, self.ambient_variance);
if !a.skip_binder().has_escaping_bound_vars() && !b.skip_binder().has_escaping_bound_vars()
{
// Fast path for the common case.
self.relate(a.skip_binder(), b.skip_binder())?;
return Ok(a.clone());
}
if self.ambient_covariance() {
// Covariance, so we want `for<..> A <: for<..> B` --
// therefore we compare any instantiation of A (i.e., A

View File

@ -0,0 +1,23 @@
// Check that this can be compiled in a reasonable time.
// build-pass
fn main() {
// 96 nested closures
let x = ();
|| || || || || || || ||
|| || || || || || || ||
|| || || || || || || ||
|| || || || || || || ||
|| || || || || || || ||
|| || || || || || || ||
|| || || || || || || ||
|| || || || || || || ||
|| || || || || || || ||
|| || || || || || || ||
|| || || || || || || ||
|| || || || || || || ||
[&(), &x];
}