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.rs139
1 files changed, 100 insertions, 39 deletions
diff --git a/crates/hir-ty/src/infer/unify.rs b/crates/hir-ty/src/infer/unify.rs
index 8a8992cf37..60aa9b5a17 100644
--- a/crates/hir-ty/src/infer/unify.rs
+++ b/crates/hir-ty/src/infer/unify.rs
@@ -1,15 +1,15 @@
//! Unification and canonicalization logic.
-use std::{fmt, iter, mem};
+use std::{fmt, mem};
use chalk_ir::{
- cast::Cast, fold::TypeFoldable, interner::HasInterner, zip::Zip, CanonicalVarKind, FloatTy,
- IntTy, TyVariableKind, UniverseIndex,
+ CanonicalVarKind, FloatTy, IntTy, TyVariableKind, UniverseIndex, cast::Cast,
+ fold::TypeFoldable, interner::HasInterner, zip::Zip,
};
use chalk_solve::infer::ParameterEnaVariableExt;
use either::Either;
use ena::unify::UnifyKey;
-use hir_def::{lang_item::LangItem, AdtId};
+use hir_def::{AdtId, lang_item::LangItem};
use hir_expand::name::Name;
use intern::sym;
use rustc_hash::FxHashMap;
@@ -18,12 +18,12 @@ use triomphe::Arc;
use super::{InferOk, InferResult, InferenceContext, TypeError};
use crate::{
+ AliasEq, AliasTy, BoundVar, Canonical, Const, ConstValue, DebruijnIndex, DomainGoal,
+ GenericArg, GenericArgData, Goal, GoalData, Guidance, InEnvironment, InferenceVar, Interner,
+ Lifetime, OpaqueTyId, ParamKind, ProjectionTy, ProjectionTyExt, Scalar, Solution, Substitution,
+ TraitEnvironment, TraitRef, Ty, TyBuilder, TyExt, TyKind, VariableKind, WhereClause,
consteval::unknown_const, db::HirDatabase, fold_generic_args, fold_tys_and_consts,
- to_chalk_trait_id, traits::FnTrait, AliasEq, AliasTy, BoundVar, Canonical, Const, ConstValue,
- DebruijnIndex, DomainGoal, GenericArg, GenericArgData, Goal, GoalData, Guidance, InEnvironment,
- InferenceVar, Interner, Lifetime, OpaqueTyId, ParamKind, ProjectionTy, ProjectionTyExt, Scalar,
- Solution, Substitution, TraitEnvironment, TraitRef, Ty, TyBuilder, TyExt, TyKind, VariableKind,
- WhereClause,
+ to_chalk_trait_id, traits::FnTrait,
};
impl InferenceContext<'_> {
@@ -364,6 +364,64 @@ impl<'a> InferenceTable<'a> {
)
}
+ /// Works almost same as [`Self::normalize_associated_types_in`], but this also resolves shallow
+ /// the inference variables
+ pub(crate) fn eagerly_normalize_and_resolve_shallow_in<T>(&mut self, ty: T) -> T
+ where
+ T: HasInterner<Interner = Interner> + TypeFoldable<Interner>,
+ {
+ fn eagerly_resolve_ty<const N: usize>(
+ table: &mut InferenceTable<'_>,
+ ty: Ty,
+ mut tys: SmallVec<[Ty; N]>,
+ ) -> Ty {
+ if tys.contains(&ty) {
+ return ty;
+ }
+ tys.push(ty.clone());
+
+ match ty.kind(Interner) {
+ TyKind::Alias(AliasTy::Projection(proj_ty)) => {
+ let ty = table.normalize_projection_ty(proj_ty.clone());
+ eagerly_resolve_ty(table, ty, tys)
+ }
+ TyKind::InferenceVar(..) => {
+ let ty = table.resolve_ty_shallow(&ty);
+ eagerly_resolve_ty(table, ty, tys)
+ }
+ _ => ty,
+ }
+ }
+
+ fold_tys_and_consts(
+ ty,
+ |e, _| match e {
+ Either::Left(ty) => {
+ Either::Left(eagerly_resolve_ty::<8>(self, ty, SmallVec::new()))
+ }
+ Either::Right(c) => Either::Right(match &c.data(Interner).value {
+ chalk_ir::ConstValue::Concrete(cc) => match &cc.interned {
+ crate::ConstScalar::UnevaluatedConst(c_id, subst) => {
+ // FIXME: same as `normalize_associated_types_in`
+ if subst.len(Interner) == 0 {
+ if let Ok(eval) = self.db.const_eval(*c_id, subst.clone(), None) {
+ eval
+ } else {
+ unknown_const(c.data(Interner).ty.clone())
+ }
+ } else {
+ unknown_const(c.data(Interner).ty.clone())
+ }
+ }
+ _ => c,
+ },
+ _ => c,
+ }),
+ },
+ DebruijnIndex::INNERMOST,
+ )
+ }
+
pub(crate) fn normalize_projection_ty(&mut self, proj_ty: ProjectionTy) -> Ty {
let var = self.new_type_var();
let alias_eq = AliasEq { alias: AliasTy::Projection(proj_ty), ty: var.clone() };
@@ -386,7 +444,7 @@ impl<'a> InferenceTable<'a> {
}
fn extend_type_variable_table(&mut self, to_index: usize) {
let count = to_index - self.type_variable_table.len() + 1;
- self.type_variable_table.extend(iter::repeat(TypeVariableFlags::default()).take(count));
+ self.type_variable_table.extend(std::iter::repeat_n(TypeVariableFlags::default(), count));
}
fn new_var(&mut self, kind: TyVariableKind, diverging: bool) -> Ty {
@@ -795,13 +853,13 @@ impl<'a> InferenceTable<'a> {
num_args: usize,
) -> Option<(FnTrait, Vec<Ty>, Ty)> {
for (fn_trait_name, output_assoc_name, subtraits) in [
- (FnTrait::FnOnce, sym::Output.clone(), &[FnTrait::Fn, FnTrait::FnMut][..]),
- (FnTrait::AsyncFnMut, sym::CallRefFuture.clone(), &[FnTrait::AsyncFn]),
- (FnTrait::AsyncFnOnce, sym::CallOnceFuture.clone(), &[]),
+ (FnTrait::FnOnce, sym::Output, &[FnTrait::Fn, FnTrait::FnMut][..]),
+ (FnTrait::AsyncFnMut, sym::CallRefFuture, &[FnTrait::AsyncFn]),
+ (FnTrait::AsyncFnOnce, sym::CallOnceFuture, &[]),
] {
let krate = self.trait_env.krate;
let fn_trait = fn_trait_name.get_id(self.db, krate)?;
- let trait_data = self.db.trait_data(fn_trait);
+ let trait_data = self.db.trait_items(fn_trait);
let output_assoc_type =
trait_data.associated_type_by_name(&Name::new_symbol_root(output_assoc_name))?;
@@ -890,11 +948,7 @@ impl<'a> InferenceTable<'a> {
TyKind::Error => self.new_type_var(),
TyKind::InferenceVar(..) => {
let ty_resolved = self.resolve_ty_shallow(&ty);
- if ty_resolved.is_unknown() {
- self.new_type_var()
- } else {
- ty
- }
+ if ty_resolved.is_unknown() { self.new_type_var() } else { ty }
}
_ => ty,
}
@@ -922,15 +976,33 @@ impl<'a> InferenceTable<'a> {
/// Check if given type is `Sized` or not
pub(crate) fn is_sized(&mut self, ty: &Ty) -> bool {
+ fn short_circuit_trivial_tys(ty: &Ty) -> Option<bool> {
+ match ty.kind(Interner) {
+ TyKind::Scalar(..)
+ | TyKind::Ref(..)
+ | TyKind::Raw(..)
+ | TyKind::Never
+ | TyKind::FnDef(..)
+ | TyKind::Array(..)
+ | TyKind::Function(..) => Some(true),
+ TyKind::Slice(..) | TyKind::Str | TyKind::Dyn(..) => Some(false),
+ _ => None,
+ }
+ }
+
let mut ty = ty.clone();
+ ty = self.eagerly_normalize_and_resolve_shallow_in(ty);
+ if let Some(sized) = short_circuit_trivial_tys(&ty) {
+ return sized;
+ }
+
{
let mut structs = SmallVec::<[_; 8]>::new();
// Must use a loop here and not recursion because otherwise users will conduct completely
// artificial examples of structs that have themselves as the tail field and complain r-a crashes.
while let Some((AdtId::StructId(id), subst)) = ty.as_adt() {
- let struct_data = self.db.struct_data(id);
- if let Some((last_field, _)) = struct_data.variant_data.fields().iter().next_back()
- {
+ let struct_data = self.db.variant_fields(id.into());
+ if let Some((last_field, _)) = struct_data.fields().iter().next_back() {
let last_field_ty = self.db.field_types(id.into())[last_field]
.clone()
.substitute(Interner, subst);
@@ -942,26 +1014,16 @@ impl<'a> InferenceTable<'a> {
// Structs can have DST as its last field and such cases are not handled
// as unsized by the chalk, so we do this manually.
ty = last_field_ty;
+ ty = self.eagerly_normalize_and_resolve_shallow_in(ty);
+ if let Some(sized) = short_circuit_trivial_tys(&ty) {
+ return sized;
+ }
} else {
break;
};
}
}
- // Early return for some obvious types
- if matches!(
- ty.kind(Interner),
- TyKind::Scalar(..)
- | TyKind::Ref(..)
- | TyKind::Raw(..)
- | TyKind::Never
- | TyKind::FnDef(..)
- | TyKind::Array(..)
- | TyKind::Function(_)
- ) {
- return true;
- }
-
let Some(sized) = self
.db
.lang_item(self.trait_env.krate, LangItem::Sized)
@@ -1032,7 +1094,7 @@ mod resolve {
.assert_ty_ref(Interner)
.clone();
}
- let result = if let Some(known_ty) = self.table.var_unification_table.probe_var(var) {
+ if let Some(known_ty) = self.table.var_unification_table.probe_var(var) {
// known_ty may contain other variables that are known by now
self.var_stack.push(var);
let result = known_ty.fold_with(self, outer_binder);
@@ -1043,8 +1105,7 @@ mod resolve {
(self.fallback)(var, VariableKind::Ty(kind), default, outer_binder)
.assert_ty_ref(Interner)
.clone()
- };
- result
+ }
}
fn fold_inference_const(