Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/hir-ty/src/infer/unify.rs')
| -rw-r--r-- | crates/hir-ty/src/infer/unify.rs | 74 |
1 files changed, 35 insertions, 39 deletions
diff --git a/crates/hir-ty/src/infer/unify.rs b/crates/hir-ty/src/infer/unify.rs index 1d0150d850..be7547f9ba 100644 --- a/crates/hir-ty/src/infer/unify.rs +++ b/crates/hir-ty/src/infer/unify.rs @@ -23,12 +23,9 @@ use crate::{ }; impl InferenceContext<'_> { - pub(super) fn canonicalize<T: TypeFoldable<Interner> + HasInterner<Interner = Interner>>( - &mut self, - t: T, - ) -> Canonicalized<T> + pub(super) fn canonicalize<T>(&mut self, t: T) -> Canonical<T> where - T: HasInterner<Interner = Interner>, + T: TypeFoldable<Interner> + HasInterner<Interner = Interner>, { self.table.canonicalize(t) } @@ -128,14 +125,14 @@ impl<T: HasInterner<Interner = Interner>> Canonicalized<T> { }), ); for (i, v) in solution.value.iter(Interner).enumerate() { - let var = self.free_vars[i].clone(); + let var = &self.free_vars[i]; if let Some(ty) = v.ty(Interner) { // eagerly replace projections in the type; we may be getting types // e.g. from where clauses where this hasn't happened yet let ty = ctx.normalize_associated_types_in(new_vars.apply(ty.clone(), Interner)); ctx.unify(var.assert_ty_ref(Interner), &ty); } else { - let _ = ctx.try_unify(&var, &new_vars.apply(v.clone(), Interner)); + let _ = ctx.try_unify(var, &new_vars.apply(v.clone(), Interner)); } } } @@ -243,7 +240,7 @@ pub(crate) struct InferenceTable<'a> { pub(crate) db: &'a dyn HirDatabase, pub(crate) trait_env: Arc<TraitEnvironment>, var_unification_table: ChalkInferenceTable, - type_variable_table: Vec<TypeVariableFlags>, + type_variable_table: SmallVec<[TypeVariableFlags; 16]>, pending_obligations: Vec<Canonicalized<InEnvironment<Goal>>>, /// Double buffer used in [`Self::resolve_obligations_as_possible`] to cut down on /// temporary allocations. @@ -252,8 +249,8 @@ pub(crate) struct InferenceTable<'a> { pub(crate) struct InferenceTableSnapshot { var_table_snapshot: chalk_solve::infer::InferenceSnapshot<Interner>, + type_variable_table: SmallVec<[TypeVariableFlags; 16]>, pending_obligations: Vec<Canonicalized<InEnvironment<Goal>>>, - type_variable_table_snapshot: Vec<TypeVariableFlags>, } impl<'a> InferenceTable<'a> { @@ -262,7 +259,7 @@ impl<'a> InferenceTable<'a> { db, trait_env, var_unification_table: ChalkInferenceTable::new(), - type_variable_table: Vec::new(), + type_variable_table: SmallVec::new(), pending_obligations: Vec::new(), resolve_obligations_buffer: Vec::new(), } @@ -292,14 +289,14 @@ impl<'a> InferenceTable<'a> { } fn fallback_value(&self, iv: InferenceVar, kind: TyVariableKind) -> Ty { + let is_diverging = self + .type_variable_table + .get(iv.index() as usize) + .map_or(false, |data| data.contains(TypeVariableFlags::DIVERGING)); + if is_diverging { + return TyKind::Never.intern(Interner); + } match kind { - _ if self - .type_variable_table - .get(iv.index() as usize) - .map_or(false, |data| data.contains(TypeVariableFlags::DIVERGING)) => - { - TyKind::Never - } TyVariableKind::General => TyKind::Error, TyVariableKind::Integer => TyKind::Scalar(Scalar::Int(IntTy::I32)), TyVariableKind::Float => TyKind::Scalar(Scalar::Float(FloatTy::F64)), @@ -307,12 +304,9 @@ impl<'a> InferenceTable<'a> { .intern(Interner) } - pub(crate) fn canonicalize<T: TypeFoldable<Interner> + HasInterner<Interner = Interner>>( - &mut self, - t: T, - ) -> Canonicalized<T> + pub(crate) fn canonicalize_with_free_vars<T>(&mut self, t: T) -> Canonicalized<T> where - T: HasInterner<Interner = Interner>, + T: TypeFoldable<Interner> + HasInterner<Interner = Interner>, { // try to resolve obligations before canonicalizing, since this might // result in new knowledge about variables @@ -326,6 +320,16 @@ impl<'a> InferenceTable<'a> { Canonicalized { value: result.quantified, free_vars } } + pub(crate) fn canonicalize<T>(&mut self, t: T) -> Canonical<T> + where + T: TypeFoldable<Interner> + HasInterner<Interner = Interner>, + { + // try to resolve obligations before canonicalizing, since this might + // result in new knowledge about variables + self.resolve_obligations_as_possible(); + self.var_unification_table.canonicalize(Interner, t).quantified + } + /// Recurses through the given type, normalizing associated types mentioned /// in it by replacing them by type variables and registering obligations to /// resolve later. This should be done once for every type we get from some @@ -541,7 +545,7 @@ impl<'a> InferenceTable<'a> { Err(_) => return false, }; result.goals.iter().all(|goal| { - let canonicalized = self.canonicalize(goal.clone()); + let canonicalized = self.canonicalize_with_free_vars(goal.clone()); self.try_resolve_obligation(&canonicalized).is_some() }) } @@ -575,19 +579,15 @@ impl<'a> InferenceTable<'a> { pub(crate) fn snapshot(&mut self) -> InferenceTableSnapshot { let var_table_snapshot = self.var_unification_table.snapshot(); - let type_variable_table_snapshot = self.type_variable_table.clone(); + let type_variable_table = self.type_variable_table.clone(); let pending_obligations = self.pending_obligations.clone(); - InferenceTableSnapshot { - var_table_snapshot, - pending_obligations, - type_variable_table_snapshot, - } + InferenceTableSnapshot { var_table_snapshot, pending_obligations, type_variable_table } } #[tracing::instrument(skip_all)] pub(crate) fn rollback_to(&mut self, snapshot: InferenceTableSnapshot) { self.var_unification_table.rollback_to(snapshot.var_table_snapshot); - self.type_variable_table = snapshot.type_variable_table_snapshot; + self.type_variable_table = snapshot.type_variable_table; self.pending_obligations = snapshot.pending_obligations; } @@ -606,7 +606,7 @@ impl<'a> InferenceTable<'a> { let in_env = InEnvironment::new(&self.trait_env.env, goal); let canonicalized = self.canonicalize(in_env); - self.db.trait_solve(self.trait_env.krate, self.trait_env.block, canonicalized.value) + self.db.trait_solve(self.trait_env.krate, self.trait_env.block, canonicalized) } pub(crate) fn register_obligation(&mut self, goal: Goal) { @@ -615,7 +615,7 @@ impl<'a> InferenceTable<'a> { } fn register_obligation_in_env(&mut self, goal: InEnvironment<Goal>) { - let canonicalized = self.canonicalize(goal); + let canonicalized = self.canonicalize_with_free_vars(goal); let solution = self.try_resolve_obligation(&canonicalized); if matches!(solution, Some(Solution::Ambig(_))) { self.pending_obligations.push(canonicalized); @@ -798,7 +798,7 @@ impl<'a> InferenceTable<'a> { let trait_data = self.db.trait_data(fn_once_trait); let output_assoc_type = trait_data.associated_type_by_name(&name![Output])?; - let mut arg_tys = vec![]; + let mut arg_tys = Vec::with_capacity(num_args); let arg_ty = TyBuilder::tuple(num_args) .fill(|it| { let arg = match it { @@ -828,11 +828,7 @@ impl<'a> InferenceTable<'a> { environment: trait_env.clone(), }; let canonical = self.canonicalize(obligation.clone()); - if self - .db - .trait_solve(krate, self.trait_env.block, canonical.value.cast(Interner)) - .is_some() - { + if self.db.trait_solve(krate, self.trait_env.block, canonical.cast(Interner)).is_some() { self.register_obligation(obligation.goal); let return_ty = self.normalize_projection_ty(projection); for fn_x in [FnTrait::Fn, FnTrait::FnMut, FnTrait::FnOnce] { @@ -845,7 +841,7 @@ impl<'a> InferenceTable<'a> { let canonical = self.canonicalize(obligation.clone()); if self .db - .trait_solve(krate, self.trait_env.block, canonical.value.cast(Interner)) + .trait_solve(krate, self.trait_env.block, canonical.cast(Interner)) .is_some() { return Some((fn_x, arg_tys, return_ty)); |