Skip to content

Commit

Permalink
Merge #8285
Browse files Browse the repository at this point in the history
8285: Don't recheck obligations if we have learned nothing new r=matklad a=flodiebold

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).

Co-authored-by: Florian Diebold <flodiebold@gmail.com>
  • Loading branch information
bors[bot] and flodiebold committed Apr 2, 2021
2 parents a0b3eb7 + 0e8c450 commit 00ce7ae
Show file tree
Hide file tree
Showing 4 changed files with 26 additions and 8 deletions.
18 changes: 15 additions & 3 deletions crates/hir_ty/src/infer.rs
Expand Up @@ -210,6 +210,7 @@ struct InferenceContext<'a> {
table: unify::InferenceTable,
trait_env: Arc<TraitEnvironment>,
obligations: Vec<DomainGoal>,
last_obligations_check: Option<u32>,
result: InferenceResult,
/// The return type of the function being inferred, or the closure if we're
/// currently within one.
Expand Down Expand Up @@ -245,6 +246,7 @@ impl<'a> InferenceContext<'a> {
result: InferenceResult::default(),
table: unify::InferenceTable::new(),
obligations: Vec::default(),
last_obligations_check: None,
return_ty: TyKind::Unknown.intern(&Interner), // set in collect_fn_signature
trait_env: owner
.as_generic_def_id()
Expand Down Expand Up @@ -334,6 +336,11 @@ impl<'a> InferenceContext<'a> {
}

fn resolve_obligations_as_possible(&mut self) {
if self.last_obligations_check == Some(self.table.revision) {
// no change
return;
}
self.last_obligations_check = Some(self.table.revision);
let obligations = mem::replace(&mut self.obligations, Vec::new());
for obligation in obligations {
let in_env = InEnvironment::new(self.trait_env.env.clone(), obligation.clone());
Expand All @@ -360,6 +367,11 @@ impl<'a> InferenceContext<'a> {
}
}

fn push_obligation(&mut self, o: DomainGoal) {
self.obligations.push(o);
self.last_obligations_check = None;
}

fn unify(&mut self, ty1: &Ty, ty2: &Ty) -> bool {
self.table.unify(ty1, ty2)
}
Expand Down Expand Up @@ -408,8 +420,8 @@ impl<'a> InferenceContext<'a> {
}),
ty: ty.clone(),
};
self.obligations.push(trait_ref.cast(&Interner));
self.obligations.push(alias_eq.cast(&Interner));
self.push_obligation(trait_ref.cast(&Interner));
self.push_obligation(alias_eq.cast(&Interner));
self.resolve_ty_as_possible(ty)
}
None => self.err_ty(),
Expand All @@ -436,7 +448,7 @@ impl<'a> InferenceContext<'a> {
let var = self.table.new_type_var();
let alias_eq = AliasEq { alias: AliasTy::Projection(proj_ty), ty: var.clone() };
let obligation = alias_eq.cast(&Interner);
self.obligations.push(obligation);
self.push_obligation(obligation);
var
}

Expand Down
6 changes: 3 additions & 3 deletions crates/hir_ty/src/infer/expr.rs
Expand Up @@ -99,7 +99,7 @@ impl<'a> InferenceContext<'a> {
environment: trait_env,
});
if self.db.trait_solve(krate, goal.value).is_some() {
self.obligations.push(implements_fn_trait);
self.push_obligation(implements_fn_trait);
let output_proj_ty = crate::ProjectionTy {
associated_ty_id: to_assoc_type_id(output_assoc_type),
substitution: substs,
Expand Down Expand Up @@ -964,7 +964,7 @@ impl<'a> InferenceContext<'a> {
let (predicate, binders) =
predicate.clone().subst(parameters).into_value_and_skipped_binders();
always!(binders == 0); // quantified where clauses not yet handled
self.obligations.push(predicate.cast(&Interner));
self.push_obligation(predicate.cast(&Interner));
}
// add obligation for trait implementation, if this is a trait method
match def {
Expand All @@ -974,7 +974,7 @@ impl<'a> InferenceContext<'a> {
// construct a TraitRef
let substs =
parameters.prefix(generics(self.db.upcast(), trait_.into()).len());
self.obligations.push(
self.push_obligation(
TraitRef { trait_id: to_chalk_trait_id(trait_), substitution: substs }
.cast(&Interner),
);
Expand Down
2 changes: 1 addition & 1 deletion crates/hir_ty/src/infer/path.rs
Expand Up @@ -258,7 +258,7 @@ impl<'a> InferenceContext<'a> {
.push(ty.clone())
.fill(std::iter::repeat_with(|| self.table.new_type_var()))
.build();
self.obligations.push(
self.push_obligation(
TraitRef {
trait_id: to_chalk_trait_id(trait_),
substitution: trait_substs.clone(),
Expand Down
8 changes: 7 additions & 1 deletion crates/hir_ty/src/infer/unify.rs
Expand Up @@ -231,13 +231,15 @@ pub(crate) struct TypeVariableData {
pub(crate) struct InferenceTable {
pub(super) var_unification_table: InPlaceUnificationTable<TypeVarId>,
pub(super) type_variable_table: TypeVariableTable,
pub(super) revision: u32,
}

impl InferenceTable {
pub(crate) fn new() -> Self {
InferenceTable {
var_unification_table: InPlaceUnificationTable::new(),
type_variable_table: TypeVariableTable { inner: Vec::new() },
revision: 0,
}
}

Expand Down Expand Up @@ -360,7 +362,10 @@ impl InferenceTable {
== self.type_variable_table.is_diverging(*tv2) =>
{
// both type vars are unknown since we tried to resolve them
self.var_unification_table.union(tv1.to_inner(), tv2.to_inner());
if !self.var_unification_table.unioned(tv1.to_inner(), tv2.to_inner()) {
self.var_unification_table.union(tv1.to_inner(), tv2.to_inner());
self.revision += 1;
}
true
}

Expand Down Expand Up @@ -398,6 +403,7 @@ impl InferenceTable {
tv.to_inner(),
TypeVarValue::Known(other.clone().intern(&Interner)),
);
self.revision += 1;
true
}

Expand Down

0 comments on commit 00ce7ae

Please sign in to comment.