mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-09-28 12:54:58 +00:00
Merge #8285
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>
This commit is contained in:
commit
00ce7ae524
4 changed files with 26 additions and 8 deletions
|
@ -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 @@ 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()
|
||||
|
@ -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());
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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(),
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
@ -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 {
|
||||
|
@ -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),
|
||||
);
|
||||
|
|
|
@ -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(),
|
||||
|
|
|
@ -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 @@ impl InferenceTable {
|
|||
InferenceTable {
|
||||
var_unification_table: InPlaceUnificationTable::new(),
|
||||
type_variable_table: TypeVariableTable { inner: Vec::new() },
|
||||
revision: 0,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
@ -398,6 +403,7 @@ impl InferenceTable {
|
|||
tv.to_inner(),
|
||||
TypeVarValue::Known(other.clone().intern(&Interner)),
|
||||
);
|
||||
self.revision += 1;
|
||||
true
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue