Unnamed repository; edit this file 'description' to name the repository.
Properly handle normalization
Previously normalization was broken, which caused a lot of fake errors. This fix most type mismatches of the new solver, and it also reverts many test regressions. The downside is that now `chalk_ir::TyKind::AssociatedType`/`chalk_ir::TyKind::Alias` cannot be trusted anymore with their roles, namely: `AssociatedType` is always fully normalized and `Alias` only if it can possibly be normalized further. That seems okay as the new solver does not have this distinction at all (due to it being a lazy normalizer), so this will only hold for the migration time. This does mean we have to change some APIs, notably `hir::Type::walk()` and `TyFingerprint`, to treat `Alias` the same as `AssociatedType`. Another small thing this commit does is to isolate processing of user-written types (currently involving replacing error types and normalizing, but in the future validation will also be needed) to separate functions.
Chayim Refael Friedman 7 months ago
parent 0f1adf4 · commit 287a6e9
-rw-r--r--crates/hir-ty/src/infer.rs50
-rw-r--r--crates/hir-ty/src/infer/closure.rs10
-rw-r--r--crates/hir-ty/src/infer/expr.rs8
-rw-r--r--crates/hir-ty/src/infer/pat.rs4
-rw-r--r--crates/hir-ty/src/infer/path.rs17
-rw-r--r--crates/hir-ty/src/infer/unify.rs244
-rw-r--r--crates/hir-ty/src/method_resolution.rs21
-rw-r--r--crates/hir-ty/src/tests/macros.rs4
-rw-r--r--crates/hir-ty/src/tests/never_type.rs24
-rw-r--r--crates/hir-ty/src/tests/patterns.rs8
-rw-r--r--crates/hir-ty/src/tests/regression.rs12
-rw-r--r--crates/hir-ty/src/tests/regression/new_solver.rs2
-rw-r--r--crates/hir-ty/src/tests/simple.rs2
-rw-r--r--crates/hir-ty/src/tests/traits.rs18
-rw-r--r--crates/hir/src/lib.rs9
15 files changed, 235 insertions, 198 deletions
diff --git a/crates/hir-ty/src/infer.rs b/crates/hir-ty/src/infer.rs
index 265d1f8541..3d91a2558f 100644
--- a/crates/hir-ty/src/infer.rs
+++ b/crates/hir-ty/src/infer.rs
@@ -54,6 +54,8 @@ use rustc_hash::{FxHashMap, FxHashSet};
use stdx::{always, never};
use triomphe::Arc;
+use crate::next_solver::DbInterner;
+use crate::next_solver::mapping::NextSolverToChalk;
use crate::{
AliasEq, AliasTy, Binders, ClosureId, Const, DomainGoal, GenericArg, ImplTraitId, ImplTraitIdx,
IncorrectGenericsLenKind, Interner, Lifetime, OpaqueTyId, ParamLoweringMode,
@@ -922,13 +924,15 @@ impl<'db> InferenceContext<'db> {
});
diagnostics.shrink_to_fit();
for (_, subst) in method_resolutions.values_mut() {
- *subst = table.resolve_completely(subst.clone());
+ *subst =
+ table.resolve_completely::<_, crate::next_solver::GenericArgs<'db>>(subst.clone());
*has_errors =
*has_errors || subst.type_parameters(Interner).any(|ty| ty.contains_unknown());
}
method_resolutions.shrink_to_fit();
for (_, subst) in assoc_resolutions.values_mut() {
- *subst = table.resolve_completely(subst.clone());
+ *subst =
+ table.resolve_completely::<_, crate::next_solver::GenericArgs<'db>>(subst.clone());
*has_errors =
*has_errors || subst.type_parameters(Interner).any(|ty| ty.contains_unknown());
}
@@ -946,7 +950,12 @@ impl<'db> InferenceContext<'db> {
result.tuple_field_access_types = tuple_field_accesses_rev
.into_iter()
.enumerate()
- .map(|(idx, subst)| (TupleId(idx as u32), table.resolve_completely(subst)))
+ .map(|(idx, subst)| {
+ (
+ TupleId(idx as u32),
+ table.resolve_completely::<_, crate::next_solver::GenericArgs<'db>>(subst),
+ )
+ })
.inspect(|(_, subst)| {
*has_errors =
*has_errors || subst.type_parameters(Interner).any(|ty| ty.contains_unknown());
@@ -1015,14 +1024,12 @@ impl<'db> InferenceContext<'db> {
if let Some(self_param) = self.body.self_param
&& let Some(ty) = param_tys.next()
{
- let ty = self.insert_type_vars(ty);
- let ty = self.normalize_associated_types_in(ty);
+ let ty = self.process_user_written_ty(ty);
self.write_binding_ty(self_param, ty);
}
let mut tait_candidates = FxHashSet::default();
for (ty, pat) in param_tys.zip(&*self.body.params) {
- let ty = self.insert_type_vars(ty);
- let ty = self.normalize_associated_types_in(ty);
+ let ty = self.process_user_written_ty(ty);
self.infer_top_pat(*pat, &ty, None);
if ty
@@ -1073,7 +1080,7 @@ impl<'db> InferenceContext<'db> {
None => self.result.standard_types.unit.clone(),
};
- self.return_ty = self.normalize_associated_types_in(return_ty);
+ self.return_ty = self.process_user_written_ty(return_ty);
self.return_coercion = Some(CoerceMany::new(self.return_ty.clone()));
// Functions might be defining usage sites of TAITs.
@@ -1415,8 +1422,7 @@ impl<'db> InferenceContext<'db> {
) -> Ty {
let ty = self
.with_ty_lowering(store, type_source, lifetime_elision, |ctx| ctx.lower_ty(type_ref));
- let ty = self.insert_type_vars(ty);
- self.normalize_associated_types_in(ty)
+ self.process_user_written_ty(ty)
}
fn make_body_ty(&mut self, type_ref: TypeRefId) -> Ty {
@@ -1562,15 +1568,35 @@ impl<'db> InferenceContext<'db> {
ty
}
+ /// Whenever you lower a user-written type, you should call this.
+ fn process_user_written_ty<T, U>(&mut self, ty: T) -> T
+ where
+ T: HasInterner<Interner = Interner> + TypeFoldable<Interner> + ChalkToNextSolver<'db, U>,
+ U: NextSolverToChalk<'db, T> + rustc_type_ir::TypeFoldable<DbInterner<'db>>,
+ {
+ self.table.process_user_written_ty(ty)
+ }
+
+ /// The difference of this method from `process_user_written_ty()` is that this method doesn't register a well-formed obligation,
+ /// while `process_user_written_ty()` should (but doesn't currently).
+ fn process_remote_user_written_ty<T, U>(&mut self, ty: T) -> T
+ where
+ T: HasInterner<Interner = Interner> + TypeFoldable<Interner> + ChalkToNextSolver<'db, U>,
+ U: NextSolverToChalk<'db, T> + rustc_type_ir::TypeFoldable<DbInterner<'db>>,
+ {
+ self.table.process_remote_user_written_ty(ty)
+ }
+
/// 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
/// type annotation (e.g. from a let type annotation, field type or function
/// call). `make_ty` handles this already, but e.g. for field types we need
/// to do it as well.
- fn normalize_associated_types_in<T>(&mut self, ty: T) -> T
+ fn normalize_associated_types_in<T, U>(&mut self, ty: T) -> T
where
- T: HasInterner<Interner = Interner> + TypeFoldable<Interner>,
+ T: HasInterner<Interner = Interner> + TypeFoldable<Interner> + ChalkToNextSolver<'db, U>,
+ U: NextSolverToChalk<'db, T> + rustc_type_ir::TypeFoldable<DbInterner<'db>>,
{
self.table.normalize_associated_types_in(ty)
}
diff --git a/crates/hir-ty/src/infer/closure.rs b/crates/hir-ty/src/infer/closure.rs
index 5a69ad68b5..fd7e5a6a0e 100644
--- a/crates/hir-ty/src/infer/closure.rs
+++ b/crates/hir-ty/src/infer/closure.rs
@@ -53,7 +53,7 @@ pub(super) struct ClosureSignature {
pub(super) expected_sig: FnPointer,
}
-impl InferenceContext<'_> {
+impl<'db> InferenceContext<'db> {
pub(super) fn infer_closure(
&mut self,
body: &ExprId,
@@ -71,9 +71,13 @@ impl InferenceContext<'_> {
None => (None, None),
};
- let ClosureSignature { expected_sig: bound_sig, ret_ty: body_ret_ty } =
+ let ClosureSignature { expected_sig: mut bound_sig, ret_ty: body_ret_ty } =
self.sig_of_closure(body, ret_type, arg_types, closure_kind, expected_sig);
- let bound_sig = self.normalize_associated_types_in(bound_sig);
+ bound_sig.substitution.0 = self
+ .normalize_associated_types_in::<_, crate::next_solver::GenericArgs<'db>>(
+ bound_sig.substitution.0,
+ );
+ let bound_sig = bound_sig;
let sig_ty = TyKind::Function(bound_sig.clone()).intern(Interner);
let (id, ty, resume_yield_tys) = match closure_kind {
diff --git a/crates/hir-ty/src/infer/expr.rs b/crates/hir-ty/src/infer/expr.rs
index bfeb5bae85..0a58ea11bb 100644
--- a/crates/hir-ty/src/infer/expr.rs
+++ b/crates/hir-ty/src/infer/expr.rs
@@ -1419,7 +1419,7 @@ impl InferenceContext<'_> {
None => self.err_ty(),
};
- let ret_ty = self.normalize_associated_types_in(ret_ty);
+ let ret_ty = self.process_remote_user_written_ty(ret_ty);
if self.is_builtin_binop(&lhs_ty, &rhs_ty, op) {
// use knowledge of built-in binary ops, which can sometimes help inference
@@ -1630,8 +1630,7 @@ impl InferenceContext<'_> {
Some(match res {
Some((field_id, ty)) => {
let adjustments = auto_deref_adjust_steps(&autoderef);
- let ty = self.insert_type_vars(ty);
- let ty = self.normalize_associated_types_in(ty);
+ let ty = self.process_remote_user_written_ty(ty);
(ty, field_id, adjustments, true)
}
@@ -1641,8 +1640,7 @@ impl InferenceContext<'_> {
let ty = self.db.field_types(field_id.parent)[field_id.local_id]
.clone()
.substitute(Interner, &subst);
- let ty = self.insert_type_vars(ty);
- let ty = self.normalize_associated_types_in(ty);
+ let ty = self.process_remote_user_written_ty(ty);
(ty, Either::Left(field_id), adjustments, false)
}
diff --git a/crates/hir-ty/src/infer/pat.rs b/crates/hir-ty/src/infer/pat.rs
index 16489e3068..6781bc84d1 100644
--- a/crates/hir-ty/src/infer/pat.rs
+++ b/crates/hir-ty/src/infer/pat.rs
@@ -88,7 +88,7 @@ impl InferenceContext<'_> {
Some(substs) => f.substitute(Interner, substs),
None => f.substitute(Interner, &Substitution::empty(Interner)),
};
- self.normalize_associated_types_in(expected_ty)
+ self.process_remote_user_written_ty(expected_ty)
}
None => self.err_ty(),
}
@@ -152,7 +152,7 @@ impl InferenceContext<'_> {
Some(substs) => f.substitute(Interner, substs),
None => f.substitute(Interner, &Substitution::empty(Interner)),
};
- self.normalize_associated_types_in(expected_ty)
+ self.process_remote_user_written_ty(expected_ty)
}
None => {
self.push_diagnostic(InferenceDiagnostic::NoSuchField {
diff --git a/crates/hir-ty/src/infer/path.rs b/crates/hir-ty/src/infer/path.rs
index 1f62f9c4aa..80f7324e58 100644
--- a/crates/hir-ty/src/infer/path.rs
+++ b/crates/hir-ty/src/infer/path.rs
@@ -23,7 +23,7 @@ use crate::{
use super::{ExprOrPatId, InferenceContext, InferenceTyDiagnosticSource};
-impl InferenceContext<'_> {
+impl<'db> InferenceContext<'db> {
pub(super) fn infer_path(&mut self, path: &Path, id: ExprOrPatId) -> Option<Ty> {
let (value_def, generic_def, substs) = match self.resolve_value_path(path, id)? {
ValuePathResolution::GenericDef(value_def, generic_def, substs) => {
@@ -31,13 +31,13 @@ impl InferenceContext<'_> {
}
ValuePathResolution::NonGeneric(ty) => return Some(ty),
};
- let substs = self.insert_type_vars(substs);
- let substs = self.normalize_associated_types_in(substs);
+ let substs =
+ self.process_remote_user_written_ty::<_, crate::next_solver::GenericArgs<'db>>(substs);
self.add_required_obligations_for_value_path(generic_def, &substs);
let ty = self.db.value_ty(value_def)?.substitute(Interner, &substs);
- let ty = self.normalize_associated_types_in(ty);
+ let ty = self.process_remote_user_written_ty(ty);
Some(ty)
}
@@ -173,14 +173,12 @@ impl InferenceContext<'_> {
let last = path.segments().last()?;
let (ty, orig_ns) = path_ctx.ty_ctx().lower_ty_ext(type_ref);
- let ty = self.table.insert_type_vars(ty);
- let ty = self.table.normalize_associated_types_in(ty);
+ let ty = self.table.process_user_written_ty(ty);
path_ctx.ignore_last_segment();
let (ty, _) = path_ctx.lower_ty_relative_path(ty, orig_ns, true);
drop_ctx(ctx, no_diagnostics);
- let ty = self.table.insert_type_vars(ty);
- let ty = self.table.normalize_associated_types_in(ty);
+ let ty = self.table.process_user_written_ty(ty);
self.resolve_ty_assoc_item(ty, last.name, id).map(|(it, substs)| (it, Some(substs)))?
} else {
let hygiene = self.body.expr_or_pat_path_hygiene(id);
@@ -223,8 +221,7 @@ impl InferenceContext<'_> {
return None;
}
- let ty = self.insert_type_vars(ty);
- let ty = self.normalize_associated_types_in(ty);
+ let ty = self.process_user_written_ty(ty);
self.resolve_ty_assoc_item(ty, last_segment.name, id)
}
diff --git a/crates/hir-ty/src/infer/unify.rs b/crates/hir-ty/src/infer/unify.rs
index ec4b7ee85d..19b83d3c21 100644
--- a/crates/hir-ty/src/infer/unify.rs
+++ b/crates/hir-ty/src/infer/unify.rs
@@ -12,12 +12,14 @@ use hir_expand::name::Name;
use intern::sym;
use rustc_hash::{FxHashMap, FxHashSet};
use rustc_next_trait_solver::solve::HasChanged;
+use rustc_type_ir::inherent::IntoKind;
use rustc_type_ir::{
AliasRelationDirection, FloatVid, IntVid, TyVid,
inherent::{Span, Term as _},
relate::{Relate, solver_relating::RelateExt},
solve::{Certainty, NoSolution},
};
+use rustc_type_ir::{TypeSuperFoldable, TypeVisitableExt};
use smallvec::SmallVec;
use triomphe::Arc;
@@ -31,11 +33,8 @@ use crate::{
db::HirDatabase,
fold_generic_args, fold_tys_and_consts,
next_solver::{
- self, Binder, DbInterner, ParamEnvAnd, Predicate, PredicateKind, SolverDefIds, Term,
- infer::{
- DbInternerInferExt, InferCtxt, canonical::canonicalizer::OriginalQueryValues,
- snapshot::CombinedSnapshot,
- },
+ self, Binder, DbInterner, Predicate, PredicateKind, SolverDefIds, Term,
+ infer::{DbInternerInferExt, InferCtxt, snapshot::CombinedSnapshot},
mapping::{ChalkToNextSolver, InferenceVarExt, NextSolverToChalk},
},
to_chalk_trait_id,
@@ -305,116 +304,21 @@ impl<'a> InferenceTable<'a> {
/// type annotation (e.g. from a let type annotation, field type or function
/// call). `make_ty` handles this already, but e.g. for field types we need
/// to do it as well.
- #[tracing::instrument(skip(self), ret)]
- pub(crate) fn normalize_associated_types_in<T>(&mut self, ty: T) -> T
+ pub(crate) fn normalize_associated_types_in<T, U>(&mut self, ty: T) -> T
where
- T: HasInterner<Interner = Interner> + TypeFoldable<Interner>,
+ T: ChalkToNextSolver<'a, U>,
+ U: NextSolverToChalk<'a, T> + rustc_type_ir::TypeFoldable<DbInterner<'a>>,
{
- fold_tys_and_consts(
- ty,
- |e, _| match e {
- Either::Left(ty) => {
- let ty = self.resolve_ty_shallow(&ty);
- tracing::debug!(?ty);
- Either::Left(match ty.kind(Interner) {
- TyKind::Alias(AliasTy::Projection(proj_ty)) => {
- let ty = self.normalize_projection_ty(proj_ty.clone());
- self.resolve_ty_shallow(&ty)
- }
- TyKind::AssociatedType(id, subst) => {
- // return Either::Left(self.resolve_ty_shallow(&ty));
- if ty.data(Interner).flags.intersects(
- chalk_ir::TypeFlags::HAS_TY_INFER
- | chalk_ir::TypeFlags::HAS_CT_INFER,
- ) {
- return Either::Left(ty);
- }
- let var = self.new_type_var();
- let proj_ty = chalk_ir::ProjectionTy {
- associated_ty_id: *id,
- substitution: subst.clone(),
- };
- let normalize = chalk_ir::Normalize {
- alias: AliasTy::Projection(proj_ty),
- ty: var.clone(),
- };
- let goal = chalk_ir::Goal::new(
- Interner,
- chalk_ir::GoalData::DomainGoal(chalk_ir::DomainGoal::Normalize(
- normalize,
- )),
- );
- let in_env = InEnvironment::new(&self.trait_env.env, goal);
- let goal = in_env.to_nextsolver(self.interner);
- let goal =
- ParamEnvAnd { param_env: goal.param_env, value: goal.predicate };
-
- let (canonical_goal, orig_values) = {
- let mut orig_values = OriginalQueryValues::default();
- let result =
- self.infer_ctxt.canonicalize_query(goal, &mut orig_values);
- (result.canonical, orig_values)
- };
- let canonical_goal = rustc_type_ir::Canonical {
- max_universe: canonical_goal.max_universe,
- variables: canonical_goal.variables,
- value: crate::next_solver::Goal {
- param_env: canonical_goal.value.param_env,
- predicate: canonical_goal.value.value,
- },
- };
- let solution = next_trait_solve_canonical_in_ctxt(
- &self.infer_ctxt,
- canonical_goal,
- );
- if let NextTraitSolveResult::Certain(canonical_subst) = solution {
- let subst = self.instantiate_canonical(canonical_subst).subst;
- if subst.len(Interner) != orig_values.var_values.len() {
- ty
- } else {
- let target_ty = var.to_nextsolver(self.interner);
- subst
- .iter(Interner)
- .zip(orig_values.var_values.iter())
- .find_map(|(new, orig)| {
- if orig.ty() == Some(target_ty) {
- Some(new.assert_ty_ref(Interner).clone())
- } else {
- None
- }
- })
- .unwrap_or(ty)
- }
- } else {
- ty
- }
- }
- _ => ty,
- })
- }
- 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: Ideally here we should do everything that we do with type alias, i.e. adding a variable
- // and registering an obligation. But it needs chalk support, so we handle the most basic
- // case (a non associated const without generic parameters) manually.
- 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,
- )
+ self.normalize_associated_types_in_ns(ty.to_nextsolver(self.interner))
+ .to_chalk(self.interner)
+ }
+
+ pub(crate) fn normalize_associated_types_in_ns<T>(&mut self, ty: T) -> T
+ where
+ T: rustc_type_ir::TypeFoldable<DbInterner<'a>>,
+ {
+ let ty = self.resolve_vars_with_obligations(ty);
+ ty.fold_with(&mut Normalizer { table: self })
}
/// Works almost same as [`Self::normalize_associated_types_in`], but this also resolves shallow
@@ -476,11 +380,27 @@ impl<'a> InferenceTable<'a> {
}
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() };
- let obligation: Goal = alias_eq.cast(Interner);
- self.register_obligation(obligation.to_nextsolver(self.interner));
- var
+ let ty = TyKind::Alias(chalk_ir::AliasTy::Projection(proj_ty))
+ .intern(Interner)
+ .to_nextsolver(self.interner);
+ self.normalize_alias_ty(ty).to_chalk(self.interner)
+ }
+
+ pub(crate) fn normalize_alias_ty(
+ &mut self,
+ alias: crate::next_solver::Ty<'a>,
+ ) -> crate::next_solver::Ty<'a> {
+ let infer_term = self.infer_ctxt.next_ty_var();
+ let obligation = crate::next_solver::Predicate::new(
+ self.interner,
+ crate::next_solver::Binder::dummy(crate::next_solver::PredicateKind::AliasRelate(
+ alias.into(),
+ infer_term.into(),
+ rustc_type_ir::AliasRelationDirection::Equate,
+ )),
+ );
+ self.register_obligation(obligation);
+ self.resolve_vars_with_obligations(infer_term)
}
fn new_var(&mut self, kind: TyVariableKind, diverging: bool) -> Ty {
@@ -591,9 +511,10 @@ impl<'a> InferenceTable<'a> {
)
}
- pub(crate) fn resolve_completely<T>(&mut self, t: T) -> T
+ pub(crate) fn resolve_completely<T, U>(&mut self, t: T) -> T
where
- T: HasInterner<Interner = Interner> + TypeFoldable<Interner>,
+ T: HasInterner<Interner = Interner> + TypeFoldable<Interner> + ChalkToNextSolver<'a, U>,
+ U: NextSolverToChalk<'a, T> + rustc_type_ir::TypeFoldable<DbInterner<'a>>,
{
let t = self.resolve_with_fallback(t, &|_, _, d, _| d);
let t = self.normalize_associated_types_in(t);
@@ -1045,6 +966,30 @@ impl<'a> InferenceTable<'a> {
}
}
+ /// Whenever you lower a user-written type, you should call this.
+ pub(crate) fn process_user_written_ty<T, U>(&mut self, ty: T) -> T
+ where
+ T: HasInterner<Interner = Interner> + TypeFoldable<Interner> + ChalkToNextSolver<'a, U>,
+ U: NextSolverToChalk<'a, T> + rustc_type_ir::TypeFoldable<DbInterner<'a>>,
+ {
+ self.process_remote_user_written_ty(ty)
+ // FIXME: Register a well-formed obligation.
+ }
+
+ /// The difference of this method from `process_user_written_ty()` is that this method doesn't register a well-formed obligation,
+ /// while `process_user_written_ty()` should (but doesn't currently).
+ pub(crate) fn process_remote_user_written_ty<T, U>(&mut self, ty: T) -> T
+ where
+ T: HasInterner<Interner = Interner> + TypeFoldable<Interner> + ChalkToNextSolver<'a, U>,
+ U: NextSolverToChalk<'a, T> + rustc_type_ir::TypeFoldable<DbInterner<'a>>,
+ {
+ let ty = self.insert_type_vars(ty);
+ // See https://github.com/rust-lang/rust/blob/cdb45c87e2cd43495379f7e867e3cc15dcee9f93/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs#L487-L495:
+ // Even though the new solver only lazily normalizes usually, here we eagerly normalize so that not everything needs
+ // to normalize before inspecting the `TyKind`.
+ self.normalize_associated_types_in(ty)
+ }
+
/// Replaces ConstScalar::Unknown by a new type var, so we can maybe still infer it.
pub(super) fn insert_const_vars_shallow(&mut self, c: Const) -> Const {
let data = c.data(Interner);
@@ -1319,3 +1264,62 @@ mod resolve {
}
}
}
+
+/// This expects its input to be resolved.
+struct Normalizer<'a, 'b> {
+ table: &'a mut InferenceTable<'b>,
+}
+
+impl<'db> Normalizer<'_, 'db> {
+ fn normalize_alias_term(
+ &mut self,
+ alias_term: crate::next_solver::Term<'db>,
+ ) -> crate::next_solver::Term<'db> {
+ let infer_term = self.table.infer_ctxt.next_term_var_of_kind(alias_term);
+ let obligation = crate::next_solver::Predicate::new(
+ self.table.interner,
+ crate::next_solver::Binder::dummy(crate::next_solver::PredicateKind::AliasRelate(
+ alias_term,
+ infer_term,
+ rustc_type_ir::AliasRelationDirection::Equate,
+ )),
+ );
+ self.table.register_obligation(obligation);
+ let term = self.table.resolve_vars_with_obligations(infer_term);
+ // Now normalize the result, because maybe it contains more aliases.
+ match term {
+ Term::Ty(term) => term.super_fold_with(self).into(),
+ Term::Const(term) => term.super_fold_with(self).into(),
+ }
+ }
+}
+
+impl<'db> rustc_type_ir::TypeFolder<DbInterner<'db>> for Normalizer<'_, 'db> {
+ fn cx(&self) -> DbInterner<'db> {
+ self.table.interner
+ }
+
+ fn fold_ty(&mut self, ty: crate::next_solver::Ty<'db>) -> crate::next_solver::Ty<'db> {
+ if !ty.has_aliases() {
+ return ty;
+ }
+
+ let crate::next_solver::TyKind::Alias(..) = ty.kind() else {
+ return ty.super_fold_with(self);
+ };
+ // FIXME: Handle escaping bound vars by replacing them with placeholders (relevant to when we handle HRTB only).
+ self.normalize_alias_term(ty.into()).expect_type()
+ }
+
+ fn fold_const(&mut self, ct: crate::next_solver::Const<'db>) -> crate::next_solver::Const<'db> {
+ if !ct.has_aliases() {
+ return ct;
+ }
+
+ let crate::next_solver::ConstKind::Unevaluated(..) = ct.kind() else {
+ return ct.super_fold_with(self);
+ };
+ // FIXME: Handle escaping bound vars by replacing them with placeholders (relevant to when we handle HRTB only).
+ self.normalize_alias_term(ct.into()).expect_const()
+ }
+}
diff --git a/crates/hir-ty/src/method_resolution.rs b/crates/hir-ty/src/method_resolution.rs
index fa80567b1e..a234312173 100644
--- a/crates/hir-ty/src/method_resolution.rs
+++ b/crates/hir-ty/src/method_resolution.rs
@@ -22,10 +22,9 @@ use stdx::never;
use triomphe::Arc;
use crate::{
- AdtId, AliasTy, Canonical, CanonicalVarKinds, DebruijnIndex, DynTyExt, ForeignDefId,
- GenericArgData, Goal, InEnvironment, Interner, Mutability, Scalar, Substitution,
- TraitEnvironment, TraitRef, TraitRefExt, Ty, TyBuilder, TyExt, TyKind, TyVariableKind,
- VariableKind, WhereClause,
+ AdtId, Canonical, CanonicalVarKinds, DebruijnIndex, DynTyExt, ForeignDefId, GenericArgData,
+ Goal, InEnvironment, Interner, Mutability, Scalar, Substitution, TraitEnvironment, TraitRef,
+ TraitRefExt, Ty, TyBuilder, TyExt, TyKind, TyVariableKind, VariableKind, WhereClause,
autoderef::{self, AutoderefKind},
db::HirDatabase,
from_chalk_trait_id, from_foreign_def_id,
@@ -106,8 +105,12 @@ impl TyFingerprint {
}
}
TyKind::AssociatedType(_, _)
+ // FIXME(next-solver): Putting `Alias` here is *probably* incorrect, AFAIK it should return `None`. But this breaks
+ // flyimport, which uses an incorrect but fast method resolution algorithm. Therefore we put it here,
+ // because this function is only called by flyimport, and anyway we should get rid of `TyFingerprint`
+ // and switch to `rustc_type_ir`'s `SimplifiedType`.
+ | TyKind::Alias(_)
| TyKind::OpaqueType(_, _)
- | TyKind::Alias(AliasTy::Opaque(_))
| TyKind::FnDef(_, _)
| TyKind::Closure(_, _)
| TyKind::Coroutine(..)
@@ -115,8 +118,7 @@ impl TyFingerprint {
TyKind::Function(fn_ptr) => {
TyFingerprint::Function(fn_ptr.substitution.0.len(Interner) as u32)
}
- TyKind::Alias(_)
- | TyKind::Placeholder(_)
+ TyKind::Placeholder(_)
| TyKind::BoundVar(_)
| TyKind::InferenceVar(_, _)
| TyKind::Error => return None,
@@ -908,7 +910,10 @@ fn find_matching_impl(
}
table.register_obligation(goal.to_nextsolver(table.interner));
}
- Some((impl_.impl_items(db), table.resolve_completely(impl_substs)))
+ Some((
+ impl_.impl_items(db),
+ table.resolve_completely::<_, crate::next_solver::GenericArgs<'_>>(impl_substs),
+ ))
})
})
}
diff --git a/crates/hir-ty/src/tests/macros.rs b/crates/hir-ty/src/tests/macros.rs
index 6490554b22..5d088e40cd 100644
--- a/crates/hir-ty/src/tests/macros.rs
+++ b/crates/hir-ty/src/tests/macros.rs
@@ -202,7 +202,7 @@ fn expr_macro_def_expanded_in_various_places() {
100..119 'for _ ...!() {}': {unknown}
100..119 'for _ ...!() {}': &'? mut {unknown}
100..119 'for _ ...!() {}': fn next<{unknown}>(&'? mut {unknown}) -> Option<<{unknown} as Iterator>::Item>
- 100..119 'for _ ...!() {}': Option<<{unknown} as Iterator>::Item>
+ 100..119 'for _ ...!() {}': Option<{unknown}>
100..119 'for _ ...!() {}': ()
100..119 'for _ ...!() {}': ()
100..119 'for _ ...!() {}': ()
@@ -296,7 +296,7 @@ fn expr_macro_rules_expanded_in_various_places() {
114..133 'for _ ...!() {}': {unknown}
114..133 'for _ ...!() {}': &'? mut {unknown}
114..133 'for _ ...!() {}': fn next<{unknown}>(&'? mut {unknown}) -> Option<<{unknown} as Iterator>::Item>
- 114..133 'for _ ...!() {}': Option<<{unknown} as Iterator>::Item>
+ 114..133 'for _ ...!() {}': Option<{unknown}>
114..133 'for _ ...!() {}': ()
114..133 'for _ ...!() {}': ()
114..133 'for _ ...!() {}': ()
diff --git a/crates/hir-ty/src/tests/never_type.rs b/crates/hir-ty/src/tests/never_type.rs
index baca7f2318..6a9135622d 100644
--- a/crates/hir-ty/src/tests/never_type.rs
+++ b/crates/hir-ty/src/tests/never_type.rs
@@ -362,12 +362,12 @@ fn diverging_expression_3_break() {
140..141 'x': u32
149..175 '{ for ...; }; }': u32
151..172 'for a ...eak; }': fn into_iter<{unknown}>({unknown}) -> <{unknown} as IntoIterator>::IntoIter
- 151..172 'for a ...eak; }': <{unknown} as IntoIterator>::IntoIter
+ 151..172 'for a ...eak; }': {unknown}
151..172 'for a ...eak; }': !
- 151..172 'for a ...eak; }': <{unknown} as IntoIterator>::IntoIter
- 151..172 'for a ...eak; }': &'? mut <{unknown} as IntoIterator>::IntoIter
+ 151..172 'for a ...eak; }': {unknown}
+ 151..172 'for a ...eak; }': &'? mut {unknown}
151..172 'for a ...eak; }': fn next<{unknown}>(&'? mut {unknown}) -> Option<<{unknown} as Iterator>::Item>
- 151..172 'for a ...eak; }': Option<<{unknown} as Iterator>::Item>
+ 151..172 'for a ...eak; }': Option<{unknown}>
151..172 'for a ...eak; }': ()
151..172 'for a ...eak; }': ()
151..172 'for a ...eak; }': ()
@@ -379,12 +379,12 @@ fn diverging_expression_3_break() {
226..227 'x': u32
235..253 '{ for ... {}; }': u32
237..250 'for a in b {}': fn into_iter<{unknown}>({unknown}) -> <{unknown} as IntoIterator>::IntoIter
- 237..250 'for a in b {}': <{unknown} as IntoIterator>::IntoIter
+ 237..250 'for a in b {}': {unknown}
237..250 'for a in b {}': !
- 237..250 'for a in b {}': <{unknown} as IntoIterator>::IntoIter
- 237..250 'for a in b {}': &'? mut <{unknown} as IntoIterator>::IntoIter
+ 237..250 'for a in b {}': {unknown}
+ 237..250 'for a in b {}': &'? mut {unknown}
237..250 'for a in b {}': fn next<{unknown}>(&'? mut {unknown}) -> Option<<{unknown} as Iterator>::Item>
- 237..250 'for a in b {}': Option<<{unknown} as Iterator>::Item>
+ 237..250 'for a in b {}': Option<{unknown}>
237..250 'for a in b {}': ()
237..250 'for a in b {}': ()
237..250 'for a in b {}': ()
@@ -395,12 +395,12 @@ fn diverging_expression_3_break() {
304..305 'x': u32
313..340 '{ for ...; }; }': u32
315..337 'for a ...urn; }': fn into_iter<{unknown}>({unknown}) -> <{unknown} as IntoIterator>::IntoIter
- 315..337 'for a ...urn; }': <{unknown} as IntoIterator>::IntoIter
+ 315..337 'for a ...urn; }': {unknown}
315..337 'for a ...urn; }': !
- 315..337 'for a ...urn; }': <{unknown} as IntoIterator>::IntoIter
- 315..337 'for a ...urn; }': &'? mut <{unknown} as IntoIterator>::IntoIter
+ 315..337 'for a ...urn; }': {unknown}
+ 315..337 'for a ...urn; }': &'? mut {unknown}
315..337 'for a ...urn; }': fn next<{unknown}>(&'? mut {unknown}) -> Option<<{unknown} as Iterator>::Item>
- 315..337 'for a ...urn; }': Option<<{unknown} as Iterator>::Item>
+ 315..337 'for a ...urn; }': Option<{unknown}>
315..337 'for a ...urn; }': ()
315..337 'for a ...urn; }': ()
315..337 'for a ...urn; }': ()
diff --git a/crates/hir-ty/src/tests/patterns.rs b/crates/hir-ty/src/tests/patterns.rs
index 60a2641e1a..02cb037069 100644
--- a/crates/hir-ty/src/tests/patterns.rs
+++ b/crates/hir-ty/src/tests/patterns.rs
@@ -48,12 +48,12 @@ fn infer_pattern() {
83..84 '1': i32
86..93 '"hello"': &'static str
101..151 'for (e... }': fn into_iter<{unknown}>({unknown}) -> <{unknown} as IntoIterator>::IntoIter
- 101..151 'for (e... }': <{unknown} as IntoIterator>::IntoIter
+ 101..151 'for (e... }': {unknown}
101..151 'for (e... }': !
- 101..151 'for (e... }': <{unknown} as IntoIterator>::IntoIter
- 101..151 'for (e... }': &'? mut <{unknown} as IntoIterator>::IntoIter
+ 101..151 'for (e... }': {unknown}
+ 101..151 'for (e... }': &'? mut {unknown}
101..151 'for (e... }': fn next<{unknown}>(&'? mut {unknown}) -> Option<<{unknown} as Iterator>::Item>
- 101..151 'for (e... }': Option<<{unknown} as Iterator>::Item>
+ 101..151 'for (e... }': Option<({unknown}, {unknown})>
101..151 'for (e... }': ()
101..151 'for (e... }': ()
101..151 'for (e... }': ()
diff --git a/crates/hir-ty/src/tests/regression.rs b/crates/hir-ty/src/tests/regression.rs
index eacc4603ea..6a3f228621 100644
--- a/crates/hir-ty/src/tests/regression.rs
+++ b/crates/hir-ty/src/tests/regression.rs
@@ -268,12 +268,12 @@ fn infer_std_crash_5() {
expect![[r#"
26..322 '{ ... } }': ()
32..320 'for co... }': fn into_iter<{unknown}>({unknown}) -> <{unknown} as IntoIterator>::IntoIter
- 32..320 'for co... }': <{unknown} as IntoIterator>::IntoIter
+ 32..320 'for co... }': {unknown}
32..320 'for co... }': !
- 32..320 'for co... }': <{unknown} as IntoIterator>::IntoIter
- 32..320 'for co... }': &'? mut <{unknown} as IntoIterator>::IntoIter
+ 32..320 'for co... }': {unknown}
+ 32..320 'for co... }': &'? mut {unknown}
32..320 'for co... }': fn next<{unknown}>(&'? mut {unknown}) -> Option<<{unknown} as Iterator>::Item>
- 32..320 'for co... }': Option<<{unknown} as Iterator>::Item>
+ 32..320 'for co... }': Option<{unknown}>
32..320 'for co... }': ()
32..320 'for co... }': ()
32..320 'for co... }': ()
@@ -628,7 +628,7 @@ fn issue_4053_diesel_where_clauses() {
65..69 'self': Self
267..271 'self': Self
466..470 'self': SelectStatement<F, S, D, W, O, LOf, {unknown}, {unknown}>
- 488..522 '{ ... }': <SelectStatement<F, S, D, W, O, LOf, {unknown}, {unknown}> as BoxedDsl<DB>>::Output
+ 488..522 '{ ... }': ()
498..502 'self': SelectStatement<F, S, D, W, O, LOf, {unknown}, {unknown}>
498..508 'self.order': O
498..515 'self.o...into()': dyn QueryFragment<DB> + '?
@@ -1248,7 +1248,7 @@ fn test() {
16..66 'for _ ... }': {unknown}
16..66 'for _ ... }': &'? mut {unknown}
16..66 'for _ ... }': fn next<{unknown}>(&'? mut {unknown}) -> Option<<{unknown} as Iterator>::Item>
- 16..66 'for _ ... }': Option<<{unknown} as Iterator>::Item>
+ 16..66 'for _ ... }': Option<{unknown}>
16..66 'for _ ... }': ()
16..66 'for _ ... }': ()
16..66 'for _ ... }': ()
diff --git a/crates/hir-ty/src/tests/regression/new_solver.rs b/crates/hir-ty/src/tests/regression/new_solver.rs
index 471108d964..6d6c56696a 100644
--- a/crates/hir-ty/src/tests/regression/new_solver.rs
+++ b/crates/hir-ty/src/tests/regression/new_solver.rs
@@ -20,7 +20,7 @@ impl<'a> IntoIterator for &'a Grid {
"#,
expect![[r#"
150..154 'self': &'a Grid
- 174..181 '{ }': impl Iterator<Item = &'? ()>
+ 174..181 '{ }': impl Iterator<Item = &'a ()>
"#]],
);
}
diff --git a/crates/hir-ty/src/tests/simple.rs b/crates/hir-ty/src/tests/simple.rs
index e7357ed5aa..60ad0f49c6 100644
--- a/crates/hir-ty/src/tests/simple.rs
+++ b/crates/hir-ty/src/tests/simple.rs
@@ -2000,7 +2000,7 @@ fn test() {
225..360 'match ... }': ()
231..239 'Pin::new': fn new<&'? mut |usize| yields i64 -> &'static str>(&'? mut |usize| yields i64 -> &'static str) -> Pin<&'? mut |usize| yields i64 -> &'static str>
231..247 'Pin::n...mut g)': Pin<&'? mut |usize| yields i64 -> &'static str>
- 231..262 'Pin::n...usize)': CoroutineState<i64, &'? str>
+ 231..262 'Pin::n...usize)': CoroutineState<i64, &'static str>
240..246 '&mut g': &'? mut |usize| yields i64 -> &'static str
245..246 'g': |usize| yields i64 -> &'static str
255..261 '0usize': usize
diff --git a/crates/hir-ty/src/tests/traits.rs b/crates/hir-ty/src/tests/traits.rs
index 7a946f7ec7..22332fdc2b 100644
--- a/crates/hir-ty/src/tests/traits.rs
+++ b/crates/hir-ty/src/tests/traits.rs
@@ -4190,8 +4190,6 @@ fn g<P: PointerFamily>(p: <P as PointerFamily>::Pointer<i32>) {
);
}
-// FIXME(next-solver): Was `&'a T` but now getting error lifetime.
-// This might be fixed once we migrate into next-solver fully without chalk-ir in lowering.
#[test]
fn gats_with_impl_trait() {
// FIXME: the last function (`fn i()`) is not valid Rust as of this writing because you cannot
@@ -4215,21 +4213,21 @@ fn f<T>(v: impl Trait) {
}
fn g<'a, T: 'a>(v: impl Trait<Assoc<T> = &'a T>) {
let a = v.get::<T>();
- //^ &'? T
+ //^ &'a T
let a = v.get::<()>();
//^ <impl Trait<Assoc<T> = &'a T> as Trait>::Assoc<()>
}
fn h<'a>(v: impl Trait<Assoc<i32> = &'a i32> + Trait<Assoc<i64> = &'a i64>) {
let a = v.get::<i32>();
- //^ &'? i32
+ //^ &'a i32
let a = v.get::<i64>();
- //^ &'? i64
+ //^ &'a i64
}
fn i<'a>(v: impl Trait<Assoc<i32> = &'a i32, Assoc<i64> = &'a i64>) {
let a = v.get::<i32>();
- //^ &'? i32
+ //^ &'a i32
let a = v.get::<i64>();
- //^ &'? i64
+ //^ &'a i64
}
"#,
);
@@ -4259,8 +4257,8 @@ fn f<'a>(v: &dyn Trait<Assoc<i32> = &'a i32>) {
127..128 'v': &'? (dyn Trait<Assoc<i32> = &'a i32> + '?)
164..195 '{ ...f(); }': ()
170..171 'v': &'? (dyn Trait<Assoc<i32> = &'a i32> + '?)
- 170..184 'v.get::<i32>()': <dyn Trait<Assoc<i32> = &'a i32> + '? as Trait>::Assoc<i32>
- 170..192 'v.get:...eref()': {unknown}
+ 170..184 'v.get::<i32>()': {unknown}
+ 170..192 'v.get:...eref()': &'? {unknown}
"#]],
);
}
@@ -4953,7 +4951,7 @@ where
"#,
expect![[r#"
84..86 'de': D
- 135..138 '{ }': <D as Deserializer<'?>>::Error
+ 135..138 '{ }': <D as Deserializer<'de>>::Error
"#]],
);
}
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs
index 52ab808d22..888392b0ff 100644
--- a/crates/hir/src/lib.rs
+++ b/crates/hir/src/lib.rs
@@ -76,7 +76,7 @@ use hir_expand::{
};
use hir_ty::{
AliasTy, CallableSig, Canonical, CanonicalVarKinds, Cast, ClosureId, GenericArg,
- GenericArgData, Interner, ParamKind, QuantifiedWhereClause, Scalar, Substitution,
+ GenericArgData, Interner, ParamKind, ProjectionTy, QuantifiedWhereClause, Scalar, Substitution,
TraitEnvironment, TraitRefExt, Ty, TyBuilder, TyDefId, TyExt, TyKind, TyLoweringDiagnostic,
ValueTyDefId, WhereClause, all_super_traits, autoderef, check_orphan_rules,
consteval::{ConstExt, try_const_usize, unknown_const_as_generic},
@@ -4973,6 +4973,7 @@ impl<'db> Type<'db> {
| TyKind::Tuple(_, substitution)
| TyKind::OpaqueType(_, substitution)
| TyKind::AssociatedType(_, substitution)
+ | TyKind::Alias(AliasTy::Projection(ProjectionTy { substitution, .. }))
| TyKind::FnDef(_, substitution) => {
substitution.iter(Interner).filter_map(|x| x.ty(Interner)).any(|ty| go(db, ty))
}
@@ -5819,7 +5820,11 @@ impl<'db> Type<'db> {
cb(type_.derived(ty.clone()));
walk_substs(db, type_, substs, cb);
}
- TyKind::AssociatedType(_, substs) => {
+ TyKind::AssociatedType(_, substs)
+ | TyKind::Alias(AliasTy::Projection(hir_ty::ProjectionTy {
+ substitution: substs,
+ ..
+ })) => {
if ty.associated_type_parent_trait(db).is_some() {
cb(type_.derived(ty.clone()));
}