diff options
author | Florian Diebold <[email protected]> | 2021-04-01 20:45:44 +0100 |
---|---|---|
committer | Florian Diebold <[email protected]> | 2021-04-01 20:45:44 +0100 |
commit | 0e8c4503bf4754f4437d8bd45a110b9d0ec671e0 (patch) | |
tree | 0d09bc856ae7b8d5acc2dcc45226ea358dfa6412 /crates | |
parent | 25201b2dad7b4b0d41494e238ebf643ad7ad8cd6 (diff) |
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).
Diffstat (limited to 'crates')
-rw-r--r-- | crates/hir_ty/src/infer.rs | 18 | ||||
-rw-r--r-- | crates/hir_ty/src/infer/expr.rs | 6 | ||||
-rw-r--r-- | crates/hir_ty/src/infer/path.rs | 2 | ||||
-rw-r--r-- | crates/hir_ty/src/infer/unify.rs | 8 |
4 files changed, 26 insertions, 8 deletions
diff --git a/crates/hir_ty/src/infer.rs b/crates/hir_ty/src/infer.rs index e4407ff50..497a1beb7 100644 --- a/crates/hir_ty/src/infer.rs +++ b/crates/hir_ty/src/infer.rs | |||
@@ -210,6 +210,7 @@ struct InferenceContext<'a> { | |||
210 | table: unify::InferenceTable, | 210 | table: unify::InferenceTable, |
211 | trait_env: Arc<TraitEnvironment>, | 211 | trait_env: Arc<TraitEnvironment>, |
212 | obligations: Vec<DomainGoal>, | 212 | obligations: Vec<DomainGoal>, |
213 | last_obligations_check: Option<u32>, | ||
213 | result: InferenceResult, | 214 | result: InferenceResult, |
214 | /// The return type of the function being inferred, or the closure if we're | 215 | /// The return type of the function being inferred, or the closure if we're |
215 | /// currently within one. | 216 | /// currently within one. |
@@ -245,6 +246,7 @@ impl<'a> InferenceContext<'a> { | |||
245 | result: InferenceResult::default(), | 246 | result: InferenceResult::default(), |
246 | table: unify::InferenceTable::new(), | 247 | table: unify::InferenceTable::new(), |
247 | obligations: Vec::default(), | 248 | obligations: Vec::default(), |
249 | last_obligations_check: None, | ||
248 | return_ty: TyKind::Unknown.intern(&Interner), // set in collect_fn_signature | 250 | return_ty: TyKind::Unknown.intern(&Interner), // set in collect_fn_signature |
249 | trait_env: owner | 251 | trait_env: owner |
250 | .as_generic_def_id() | 252 | .as_generic_def_id() |
@@ -334,6 +336,11 @@ impl<'a> InferenceContext<'a> { | |||
334 | } | 336 | } |
335 | 337 | ||
336 | fn resolve_obligations_as_possible(&mut self) { | 338 | 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); | ||
337 | let obligations = mem::replace(&mut self.obligations, Vec::new()); | 344 | let obligations = mem::replace(&mut self.obligations, Vec::new()); |
338 | for obligation in obligations { | 345 | for obligation in obligations { |
339 | let in_env = InEnvironment::new(self.trait_env.env.clone(), obligation.clone()); | 346 | let in_env = InEnvironment::new(self.trait_env.env.clone(), obligation.clone()); |
@@ -360,6 +367,11 @@ impl<'a> InferenceContext<'a> { | |||
360 | } | 367 | } |
361 | } | 368 | } |
362 | 369 | ||
370 | fn push_obligation(&mut self, o: DomainGoal) { | ||
371 | self.obligations.push(o); | ||
372 | self.last_obligations_check = None; | ||
373 | } | ||
374 | |||
363 | fn unify(&mut self, ty1: &Ty, ty2: &Ty) -> bool { | 375 | fn unify(&mut self, ty1: &Ty, ty2: &Ty) -> bool { |
364 | self.table.unify(ty1, ty2) | 376 | self.table.unify(ty1, ty2) |
365 | } | 377 | } |
@@ -408,8 +420,8 @@ impl<'a> InferenceContext<'a> { | |||
408 | }), | 420 | }), |
409 | ty: ty.clone(), | 421 | ty: ty.clone(), |
410 | }; | 422 | }; |
411 | self.obligations.push(trait_ref.cast(&Interner)); | 423 | self.push_obligation(trait_ref.cast(&Interner)); |
412 | self.obligations.push(alias_eq.cast(&Interner)); | 424 | self.push_obligation(alias_eq.cast(&Interner)); |
413 | self.resolve_ty_as_possible(ty) | 425 | self.resolve_ty_as_possible(ty) |
414 | } | 426 | } |
415 | None => self.err_ty(), | 427 | None => self.err_ty(), |
@@ -436,7 +448,7 @@ impl<'a> InferenceContext<'a> { | |||
436 | let var = self.table.new_type_var(); | 448 | let var = self.table.new_type_var(); |
437 | let alias_eq = AliasEq { alias: AliasTy::Projection(proj_ty), ty: var.clone() }; | 449 | let alias_eq = AliasEq { alias: AliasTy::Projection(proj_ty), ty: var.clone() }; |
438 | let obligation = alias_eq.cast(&Interner); | 450 | let obligation = alias_eq.cast(&Interner); |
439 | self.obligations.push(obligation); | 451 | self.push_obligation(obligation); |
440 | var | 452 | var |
441 | } | 453 | } |
442 | 454 | ||
diff --git a/crates/hir_ty/src/infer/expr.rs b/crates/hir_ty/src/infer/expr.rs index 6279aa572..25ab3ea4c 100644 --- a/crates/hir_ty/src/infer/expr.rs +++ b/crates/hir_ty/src/infer/expr.rs | |||
@@ -99,7 +99,7 @@ impl<'a> InferenceContext<'a> { | |||
99 | environment: trait_env, | 99 | environment: trait_env, |
100 | }); | 100 | }); |
101 | if self.db.trait_solve(krate, goal.value).is_some() { | 101 | if self.db.trait_solve(krate, goal.value).is_some() { |
102 | self.obligations.push(implements_fn_trait); | 102 | self.push_obligation(implements_fn_trait); |
103 | let output_proj_ty = crate::ProjectionTy { | 103 | let output_proj_ty = crate::ProjectionTy { |
104 | associated_ty_id: to_assoc_type_id(output_assoc_type), | 104 | associated_ty_id: to_assoc_type_id(output_assoc_type), |
105 | substitution: substs, | 105 | substitution: substs, |
@@ -964,7 +964,7 @@ impl<'a> InferenceContext<'a> { | |||
964 | let (predicate, binders) = | 964 | let (predicate, binders) = |
965 | predicate.clone().subst(parameters).into_value_and_skipped_binders(); | 965 | predicate.clone().subst(parameters).into_value_and_skipped_binders(); |
966 | always!(binders == 0); // quantified where clauses not yet handled | 966 | always!(binders == 0); // quantified where clauses not yet handled |
967 | self.obligations.push(predicate.cast(&Interner)); | 967 | self.push_obligation(predicate.cast(&Interner)); |
968 | } | 968 | } |
969 | // add obligation for trait implementation, if this is a trait method | 969 | // add obligation for trait implementation, if this is a trait method |
970 | match def { | 970 | match def { |
@@ -974,7 +974,7 @@ impl<'a> InferenceContext<'a> { | |||
974 | // construct a TraitRef | 974 | // construct a TraitRef |
975 | let substs = | 975 | let substs = |
976 | parameters.prefix(generics(self.db.upcast(), trait_.into()).len()); | 976 | parameters.prefix(generics(self.db.upcast(), trait_.into()).len()); |
977 | self.obligations.push( | 977 | self.push_obligation( |
978 | TraitRef { trait_id: to_chalk_trait_id(trait_), substitution: substs } | 978 | TraitRef { trait_id: to_chalk_trait_id(trait_), substitution: substs } |
979 | .cast(&Interner), | 979 | .cast(&Interner), |
980 | ); | 980 | ); |
diff --git a/crates/hir_ty/src/infer/path.rs b/crates/hir_ty/src/infer/path.rs index cefa38509..717738789 100644 --- a/crates/hir_ty/src/infer/path.rs +++ b/crates/hir_ty/src/infer/path.rs | |||
@@ -258,7 +258,7 @@ impl<'a> InferenceContext<'a> { | |||
258 | .push(ty.clone()) | 258 | .push(ty.clone()) |
259 | .fill(std::iter::repeat_with(|| self.table.new_type_var())) | 259 | .fill(std::iter::repeat_with(|| self.table.new_type_var())) |
260 | .build(); | 260 | .build(); |
261 | self.obligations.push( | 261 | self.push_obligation( |
262 | TraitRef { | 262 | TraitRef { |
263 | trait_id: to_chalk_trait_id(trait_), | 263 | trait_id: to_chalk_trait_id(trait_), |
264 | substitution: trait_substs.clone(), | 264 | substitution: trait_substs.clone(), |
diff --git a/crates/hir_ty/src/infer/unify.rs b/crates/hir_ty/src/infer/unify.rs index 6e7b0f5a6..5ea4b7481 100644 --- a/crates/hir_ty/src/infer/unify.rs +++ b/crates/hir_ty/src/infer/unify.rs | |||
@@ -231,6 +231,7 @@ pub(crate) struct TypeVariableData { | |||
231 | pub(crate) struct InferenceTable { | 231 | pub(crate) struct InferenceTable { |
232 | pub(super) var_unification_table: InPlaceUnificationTable<TypeVarId>, | 232 | pub(super) var_unification_table: InPlaceUnificationTable<TypeVarId>, |
233 | pub(super) type_variable_table: TypeVariableTable, | 233 | pub(super) type_variable_table: TypeVariableTable, |
234 | pub(super) revision: u32, | ||
234 | } | 235 | } |
235 | 236 | ||
236 | impl InferenceTable { | 237 | impl InferenceTable { |
@@ -238,6 +239,7 @@ impl InferenceTable { | |||
238 | InferenceTable { | 239 | InferenceTable { |
239 | var_unification_table: InPlaceUnificationTable::new(), | 240 | var_unification_table: InPlaceUnificationTable::new(), |
240 | type_variable_table: TypeVariableTable { inner: Vec::new() }, | 241 | type_variable_table: TypeVariableTable { inner: Vec::new() }, |
242 | revision: 0, | ||
241 | } | 243 | } |
242 | } | 244 | } |
243 | 245 | ||
@@ -360,7 +362,10 @@ impl InferenceTable { | |||
360 | == self.type_variable_table.is_diverging(*tv2) => | 362 | == self.type_variable_table.is_diverging(*tv2) => |
361 | { | 363 | { |
362 | // both type vars are unknown since we tried to resolve them | 364 | // 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 | } | ||
364 | true | 369 | true |
365 | } | 370 | } |
366 | 371 | ||
@@ -398,6 +403,7 @@ impl InferenceTable { | |||
398 | tv.to_inner(), | 403 | tv.to_inner(), |
399 | TypeVarValue::Known(other.clone().intern(&Interner)), | 404 | TypeVarValue::Known(other.clone().intern(&Interner)), |
400 | ); | 405 | ); |
406 | self.revision += 1; | ||
401 | true | 407 | true |
402 | } | 408 | } |
403 | 409 | ||