]> git.lizzy.rs Git - rust.git/commitdiff
Don't recheck obligations if we have learned nothing new
authorFlorian Diebold <flodiebold@gmail.com>
Thu, 1 Apr 2021 19:45:44 +0000 (21:45 +0200)
committerFlorian Diebold <flodiebold@gmail.com>
Thu, 1 Apr 2021 19:45:44 +0000 (21:45 +0200)
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).

crates/hir_ty/src/infer.rs
crates/hir_ty/src/infer/expr.rs
crates/hir_ty/src/infer/path.rs
crates/hir_ty/src/infer/unify.rs

index e4407ff5051db6e55277192557e291e8b455fbf5..497a1beb7dc795082555a253eb9aeb917c75186b 100644 (file)
@@ -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.
@@ -245,6 +246,7 @@ fn new(db: &'a dyn HirDatabase, owner: DefWithBodyId, resolver: Resolver) -> Sel
             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()
@@ -334,6 +336,11 @@ fn insert_type_vars(&mut self, ty: Ty) -> Ty {
     }
 
     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());
@@ -360,6 +367,11 @@ fn resolve_obligations_as_possible(&mut self) {
         }
     }
 
+    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)
     }
@@ -408,8 +420,8 @@ fn resolve_associated_type_with_params(
                     }),
                     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(),
@@ -436,7 +448,7 @@ fn normalize_projection_ty(&mut self, proj_ty: ProjectionTy) -> Ty {
         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
     }
 
index 6279aa572c565f8f0bb2c91bc01f0d33a5c15419..25ab3ea4c1a623242c216615527b5b7b3993e1ca 100644 (file)
@@ -99,7 +99,7 @@ fn callable_sig_from_fn_trait(&mut self, ty: &Ty, num_args: usize) -> Option<(Ve
             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,
@@ -964,7 +964,7 @@ fn register_obligations_for_call(&mut self, callable_ty: &Ty) {
                 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 {
@@ -974,7 +974,7 @@ fn register_obligations_for_call(&mut self, callable_ty: &Ty) {
                         // 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),
                         );
index cefa385094865db16c239d3257c1e821db7b751d..717738789b9612f5c54c5de95417a06e3524088b 100644 (file)
@@ -258,7 +258,7 @@ fn resolve_ty_assoc_item(
                             .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(),
index 6e7b0f5a63340053b0f25b51cb82ce524911e96f..5ea4b7481ecfe645eb9b38dd100b041cc8a64d33 100644 (file)
@@ -231,6 +231,7 @@ 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 {
@@ -238,6 +239,7 @@ pub(crate) fn new() -> Self {
         InferenceTable {
             var_unification_table: InPlaceUnificationTable::new(),
             type_variable_table: TypeVariableTable { inner: Vec::new() },
+            revision: 0,
         }
     }
 
@@ -360,7 +362,10 @@ pub(super) fn unify_inner_trivial(&mut self, ty1: &Ty, ty2: &Ty, depth: usize) -
                 == 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
             }
 
@@ -398,6 +403,7 @@ pub(super) fn unify_inner_trivial(&mut self, ty1: &Ty, ty2: &Ty, depth: usize) -
                     tv.to_inner(),
                     TypeVarValue::Known(other.clone().intern(&Interner)),
                 );
+                self.revision += 1;
                 true
             }