Skip to content

Commit 0e8c450

Browse files
committed
Don't recheck obligations if we have learned nothing new
This is just the most trivial check: If no inference variables have been updated, and there are no new obligations, we can just skip trying to solve them again. We could be smarter about it, but this already helps quite a bit, and I don't want to touch this too much before we replace the inference table by Chalk's. Fixes #8263 (well, improves it quite a bit).
1 parent 25201b2 commit 0e8c450

File tree

4 files changed

+26
-8
lines changed

4 files changed

+26
-8
lines changed

crates/hir_ty/src/infer.rs

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,7 @@ struct InferenceContext<'a> {
210210
table: unify::InferenceTable,
211211
trait_env: Arc<TraitEnvironment>,
212212
obligations: Vec<DomainGoal>,
213+
last_obligations_check: Option<u32>,
213214
result: InferenceResult,
214215
/// The return type of the function being inferred, or the closure if we're
215216
/// currently within one.
@@ -245,6 +246,7 @@ impl<'a> InferenceContext<'a> {
245246
result: InferenceResult::default(),
246247
table: unify::InferenceTable::new(),
247248
obligations: Vec::default(),
249+
last_obligations_check: None,
248250
return_ty: TyKind::Unknown.intern(&Interner), // set in collect_fn_signature
249251
trait_env: owner
250252
.as_generic_def_id()
@@ -334,6 +336,11 @@ impl<'a> InferenceContext<'a> {
334336
}
335337

336338
fn resolve_obligations_as_possible(&mut self) {
339+
if self.last_obligations_check == Some(self.table.revision) {
340+
// no change
341+
return;
342+
}
343+
self.last_obligations_check = Some(self.table.revision);
337344
let obligations = mem::replace(&mut self.obligations, Vec::new());
338345
for obligation in obligations {
339346
let in_env = InEnvironment::new(self.trait_env.env.clone(), obligation.clone());
@@ -360,6 +367,11 @@ impl<'a> InferenceContext<'a> {
360367
}
361368
}
362369

370+
fn push_obligation(&mut self, o: DomainGoal) {
371+
self.obligations.push(o);
372+
self.last_obligations_check = None;
373+
}
374+
363375
fn unify(&mut self, ty1: &Ty, ty2: &Ty) -> bool {
364376
self.table.unify(ty1, ty2)
365377
}
@@ -408,8 +420,8 @@ impl<'a> InferenceContext<'a> {
408420
}),
409421
ty: ty.clone(),
410422
};
411-
self.obligations.push(trait_ref.cast(&Interner));
412-
self.obligations.push(alias_eq.cast(&Interner));
423+
self.push_obligation(trait_ref.cast(&Interner));
424+
self.push_obligation(alias_eq.cast(&Interner));
413425
self.resolve_ty_as_possible(ty)
414426
}
415427
None => self.err_ty(),
@@ -436,7 +448,7 @@ impl<'a> InferenceContext<'a> {
436448
let var = self.table.new_type_var();
437449
let alias_eq = AliasEq { alias: AliasTy::Projection(proj_ty), ty: var.clone() };
438450
let obligation = alias_eq.cast(&Interner);
439-
self.obligations.push(obligation);
451+
self.push_obligation(obligation);
440452
var
441453
}
442454

crates/hir_ty/src/infer/expr.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ impl<'a> InferenceContext<'a> {
9999
environment: trait_env,
100100
});
101101
if self.db.trait_solve(krate, goal.value).is_some() {
102-
self.obligations.push(implements_fn_trait);
102+
self.push_obligation(implements_fn_trait);
103103
let output_proj_ty = crate::ProjectionTy {
104104
associated_ty_id: to_assoc_type_id(output_assoc_type),
105105
substitution: substs,
@@ -964,7 +964,7 @@ impl<'a> InferenceContext<'a> {
964964
let (predicate, binders) =
965965
predicate.clone().subst(parameters).into_value_and_skipped_binders();
966966
always!(binders == 0); // quantified where clauses not yet handled
967-
self.obligations.push(predicate.cast(&Interner));
967+
self.push_obligation(predicate.cast(&Interner));
968968
}
969969
// add obligation for trait implementation, if this is a trait method
970970
match def {
@@ -974,7 +974,7 @@ impl<'a> InferenceContext<'a> {
974974
// construct a TraitRef
975975
let substs =
976976
parameters.prefix(generics(self.db.upcast(), trait_.into()).len());
977-
self.obligations.push(
977+
self.push_obligation(
978978
TraitRef { trait_id: to_chalk_trait_id(trait_), substitution: substs }
979979
.cast(&Interner),
980980
);

crates/hir_ty/src/infer/path.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -258,7 +258,7 @@ impl<'a> InferenceContext<'a> {
258258
.push(ty.clone())
259259
.fill(std::iter::repeat_with(|| self.table.new_type_var()))
260260
.build();
261-
self.obligations.push(
261+
self.push_obligation(
262262
TraitRef {
263263
trait_id: to_chalk_trait_id(trait_),
264264
substitution: trait_substs.clone(),

crates/hir_ty/src/infer/unify.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -231,13 +231,15 @@ pub(crate) struct TypeVariableData {
231231
pub(crate) struct InferenceTable {
232232
pub(super) var_unification_table: InPlaceUnificationTable<TypeVarId>,
233233
pub(super) type_variable_table: TypeVariableTable,
234+
pub(super) revision: u32,
234235
}
235236

236237
impl InferenceTable {
237238
pub(crate) fn new() -> Self {
238239
InferenceTable {
239240
var_unification_table: InPlaceUnificationTable::new(),
240241
type_variable_table: TypeVariableTable { inner: Vec::new() },
242+
revision: 0,
241243
}
242244
}
243245

@@ -360,7 +362,10 @@ impl InferenceTable {
360362
== self.type_variable_table.is_diverging(*tv2) =>
361363
{
362364
// both type vars are unknown since we tried to resolve them
363-
self.var_unification_table.union(tv1.to_inner(), tv2.to_inner());
365+
if !self.var_unification_table.unioned(tv1.to_inner(), tv2.to_inner()) {
366+
self.var_unification_table.union(tv1.to_inner(), tv2.to_inner());
367+
self.revision += 1;
368+
}
364369
true
365370
}
366371

@@ -398,6 +403,7 @@ impl InferenceTable {
398403
tv.to_inner(),
399404
TypeVarValue::Known(other.clone().intern(&Interner)),
400405
);
406+
self.revision += 1;
401407
true
402408
}
403409

0 commit comments

Comments
 (0)