Merge pull request #20647 from ChayimFriedman2/ns-projections

fix: Fix normalization in the new solver
This commit is contained in:
Shoyu Vanilla (Flint) 2025-09-10 01:32:49 +00:00 committed by GitHub
commit 8b2671e0c4
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
16 changed files with 265 additions and 198 deletions

View file

@ -54,6 +54,8 @@ use rustc_hash::{FxHashMap, FxHashSet};
use stdx::{always, never}; use stdx::{always, never};
use triomphe::Arc; use triomphe::Arc;
use crate::next_solver::DbInterner;
use crate::next_solver::mapping::NextSolverToChalk;
use crate::{ use crate::{
AliasEq, AliasTy, Binders, ClosureId, Const, DomainGoal, GenericArg, ImplTraitId, ImplTraitIdx, AliasEq, AliasTy, Binders, ClosureId, Const, DomainGoal, GenericArg, ImplTraitId, ImplTraitIdx,
IncorrectGenericsLenKind, Interner, Lifetime, OpaqueTyId, ParamLoweringMode, IncorrectGenericsLenKind, Interner, Lifetime, OpaqueTyId, ParamLoweringMode,
@ -922,13 +924,15 @@ impl<'db> InferenceContext<'db> {
}); });
diagnostics.shrink_to_fit(); diagnostics.shrink_to_fit();
for (_, subst) in method_resolutions.values_mut() { 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 =
*has_errors || subst.type_parameters(Interner).any(|ty| ty.contains_unknown()); *has_errors || subst.type_parameters(Interner).any(|ty| ty.contains_unknown());
} }
method_resolutions.shrink_to_fit(); method_resolutions.shrink_to_fit();
for (_, subst) in assoc_resolutions.values_mut() { 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 =
*has_errors || subst.type_parameters(Interner).any(|ty| ty.contains_unknown()); *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 result.tuple_field_access_types = tuple_field_accesses_rev
.into_iter() .into_iter()
.enumerate() .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)| { .inspect(|(_, subst)| {
*has_errors = *has_errors =
*has_errors || subst.type_parameters(Interner).any(|ty| ty.contains_unknown()); *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 if let Some(self_param) = self.body.self_param
&& let Some(ty) = param_tys.next() && let Some(ty) = param_tys.next()
{ {
let ty = self.insert_type_vars(ty); let ty = self.process_user_written_ty(ty);
let ty = self.normalize_associated_types_in(ty);
self.write_binding_ty(self_param, ty); self.write_binding_ty(self_param, ty);
} }
let mut tait_candidates = FxHashSet::default(); let mut tait_candidates = FxHashSet::default();
for (ty, pat) in param_tys.zip(&*self.body.params) { for (ty, pat) in param_tys.zip(&*self.body.params) {
let ty = self.insert_type_vars(ty); let ty = self.process_user_written_ty(ty);
let ty = self.normalize_associated_types_in(ty);
self.infer_top_pat(*pat, &ty, None); self.infer_top_pat(*pat, &ty, None);
if ty if ty
@ -1073,7 +1080,7 @@ impl<'db> InferenceContext<'db> {
None => self.result.standard_types.unit.clone(), 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())); self.return_coercion = Some(CoerceMany::new(self.return_ty.clone()));
// Functions might be defining usage sites of TAITs. // Functions might be defining usage sites of TAITs.
@ -1415,8 +1422,7 @@ impl<'db> InferenceContext<'db> {
) -> Ty { ) -> Ty {
let ty = self let ty = self
.with_ty_lowering(store, type_source, lifetime_elision, |ctx| ctx.lower_ty(type_ref)); .with_ty_lowering(store, type_source, lifetime_elision, |ctx| ctx.lower_ty(type_ref));
let ty = self.insert_type_vars(ty); self.process_user_written_ty(ty)
self.normalize_associated_types_in(ty)
} }
fn make_body_ty(&mut self, type_ref: TypeRefId) -> Ty { fn make_body_ty(&mut self, type_ref: TypeRefId) -> Ty {
@ -1562,15 +1568,35 @@ impl<'db> InferenceContext<'db> {
ty 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 /// Recurses through the given type, normalizing associated types mentioned
/// in it by replacing them by type variables and registering obligations to /// 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 /// 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 /// 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 /// call). `make_ty` handles this already, but e.g. for field types we need
/// to do it as well. /// 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 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) self.table.normalize_associated_types_in(ty)
} }

View file

@ -53,7 +53,7 @@ pub(super) struct ClosureSignature {
pub(super) expected_sig: FnPointer, pub(super) expected_sig: FnPointer,
} }
impl InferenceContext<'_> { impl<'db> InferenceContext<'db> {
pub(super) fn infer_closure( pub(super) fn infer_closure(
&mut self, &mut self,
body: &ExprId, body: &ExprId,
@ -71,9 +71,13 @@ impl InferenceContext<'_> {
None => (None, None), 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); 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 sig_ty = TyKind::Function(bound_sig.clone()).intern(Interner);
let (id, ty, resume_yield_tys) = match closure_kind { let (id, ty, resume_yield_tys) = match closure_kind {

View file

@ -1419,7 +1419,7 @@ impl InferenceContext<'_> {
None => self.err_ty(), 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) { if self.is_builtin_binop(&lhs_ty, &rhs_ty, op) {
// use knowledge of built-in binary ops, which can sometimes help inference // use knowledge of built-in binary ops, which can sometimes help inference
@ -1630,8 +1630,7 @@ impl InferenceContext<'_> {
Some(match res { Some(match res {
Some((field_id, ty)) => { Some((field_id, ty)) => {
let adjustments = auto_deref_adjust_steps(&autoderef); let adjustments = auto_deref_adjust_steps(&autoderef);
let ty = self.insert_type_vars(ty); let ty = self.process_remote_user_written_ty(ty);
let ty = self.normalize_associated_types_in(ty);
(ty, field_id, adjustments, true) (ty, field_id, adjustments, true)
} }
@ -1641,8 +1640,7 @@ impl InferenceContext<'_> {
let ty = self.db.field_types(field_id.parent)[field_id.local_id] let ty = self.db.field_types(field_id.parent)[field_id.local_id]
.clone() .clone()
.substitute(Interner, &subst); .substitute(Interner, &subst);
let ty = self.insert_type_vars(ty); let ty = self.process_remote_user_written_ty(ty);
let ty = self.normalize_associated_types_in(ty);
(ty, Either::Left(field_id), adjustments, false) (ty, Either::Left(field_id), adjustments, false)
} }

View file

@ -88,7 +88,7 @@ impl InferenceContext<'_> {
Some(substs) => f.substitute(Interner, substs), Some(substs) => f.substitute(Interner, substs),
None => f.substitute(Interner, &Substitution::empty(Interner)), 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(), None => self.err_ty(),
} }
@ -152,7 +152,7 @@ impl InferenceContext<'_> {
Some(substs) => f.substitute(Interner, substs), Some(substs) => f.substitute(Interner, substs),
None => f.substitute(Interner, &Substitution::empty(Interner)), None => f.substitute(Interner, &Substitution::empty(Interner)),
}; };
self.normalize_associated_types_in(expected_ty) self.process_remote_user_written_ty(expected_ty)
} }
None => { None => {
self.push_diagnostic(InferenceDiagnostic::NoSuchField { self.push_diagnostic(InferenceDiagnostic::NoSuchField {

View file

@ -23,7 +23,7 @@ use crate::{
use super::{ExprOrPatId, InferenceContext, InferenceTyDiagnosticSource}; use super::{ExprOrPatId, InferenceContext, InferenceTyDiagnosticSource};
impl InferenceContext<'_> { impl<'db> InferenceContext<'db> {
pub(super) fn infer_path(&mut self, path: &Path, id: ExprOrPatId) -> Option<Ty> { 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)? { let (value_def, generic_def, substs) = match self.resolve_value_path(path, id)? {
ValuePathResolution::GenericDef(value_def, generic_def, substs) => { ValuePathResolution::GenericDef(value_def, generic_def, substs) => {
@ -31,13 +31,13 @@ impl InferenceContext<'_> {
} }
ValuePathResolution::NonGeneric(ty) => return Some(ty), ValuePathResolution::NonGeneric(ty) => return Some(ty),
}; };
let substs = self.insert_type_vars(substs); let substs =
let substs = self.normalize_associated_types_in(substs); self.process_remote_user_written_ty::<_, crate::next_solver::GenericArgs<'db>>(substs);
self.add_required_obligations_for_value_path(generic_def, &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.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) Some(ty)
} }
@ -173,14 +173,12 @@ impl InferenceContext<'_> {
let last = path.segments().last()?; let last = path.segments().last()?;
let (ty, orig_ns) = path_ctx.ty_ctx().lower_ty_ext(type_ref); 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.process_user_written_ty(ty);
let ty = self.table.normalize_associated_types_in(ty);
path_ctx.ignore_last_segment(); path_ctx.ignore_last_segment();
let (ty, _) = path_ctx.lower_ty_relative_path(ty, orig_ns, true); let (ty, _) = path_ctx.lower_ty_relative_path(ty, orig_ns, true);
drop_ctx(ctx, no_diagnostics); drop_ctx(ctx, no_diagnostics);
let ty = self.table.insert_type_vars(ty); let ty = self.table.process_user_written_ty(ty);
let ty = self.table.normalize_associated_types_in(ty);
self.resolve_ty_assoc_item(ty, last.name, id).map(|(it, substs)| (it, Some(substs)))? self.resolve_ty_assoc_item(ty, last.name, id).map(|(it, substs)| (it, Some(substs)))?
} else { } else {
let hygiene = self.body.expr_or_pat_path_hygiene(id); let hygiene = self.body.expr_or_pat_path_hygiene(id);
@ -223,8 +221,7 @@ impl InferenceContext<'_> {
return None; return None;
} }
let ty = self.insert_type_vars(ty); let ty = self.process_user_written_ty(ty);
let ty = self.normalize_associated_types_in(ty);
self.resolve_ty_assoc_item(ty, last_segment.name, id) self.resolve_ty_assoc_item(ty, last_segment.name, id)
} }

View file

@ -12,12 +12,14 @@ use hir_expand::name::Name;
use intern::sym; use intern::sym;
use rustc_hash::{FxHashMap, FxHashSet}; use rustc_hash::{FxHashMap, FxHashSet};
use rustc_next_trait_solver::solve::HasChanged; use rustc_next_trait_solver::solve::HasChanged;
use rustc_type_ir::inherent::IntoKind;
use rustc_type_ir::{ use rustc_type_ir::{
AliasRelationDirection, FloatVid, IntVid, TyVid, AliasRelationDirection, FloatVid, IntVid, TyVid,
inherent::{Span, Term as _}, inherent::{Span, Term as _},
relate::{Relate, solver_relating::RelateExt}, relate::{Relate, solver_relating::RelateExt},
solve::{Certainty, NoSolution}, solve::{Certainty, NoSolution},
}; };
use rustc_type_ir::{TypeSuperFoldable, TypeVisitableExt};
use smallvec::SmallVec; use smallvec::SmallVec;
use triomphe::Arc; use triomphe::Arc;
@ -31,11 +33,8 @@ use crate::{
db::HirDatabase, db::HirDatabase,
fold_generic_args, fold_tys_and_consts, fold_generic_args, fold_tys_and_consts,
next_solver::{ next_solver::{
self, Binder, DbInterner, ParamEnvAnd, Predicate, PredicateKind, SolverDefIds, Term, self, Binder, DbInterner, Predicate, PredicateKind, SolverDefIds, Term,
infer::{ infer::{DbInternerInferExt, InferCtxt, snapshot::CombinedSnapshot},
DbInternerInferExt, InferCtxt, canonical::canonicalizer::OriginalQueryValues,
snapshot::CombinedSnapshot,
},
mapping::{ChalkToNextSolver, InferenceVarExt, NextSolverToChalk}, mapping::{ChalkToNextSolver, InferenceVarExt, NextSolverToChalk},
}, },
to_chalk_trait_id, 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 /// 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 /// call). `make_ty` handles this already, but e.g. for field types we need
/// to do it as well. /// to do it as well.
#[tracing::instrument(skip(self), ret)] pub(crate) fn normalize_associated_types_in<T, U>(&mut self, ty: T) -> T
pub(crate) fn normalize_associated_types_in<T>(&mut self, ty: T) -> T
where 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( self.normalize_associated_types_in_ns(ty.to_nextsolver(self.interner))
ty, .to_chalk(self.interner)
|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) = { pub(crate) fn normalize_associated_types_in_ns<T>(&mut self, ty: T) -> T
let mut orig_values = OriginalQueryValues::default(); where
let result = T: rustc_type_ir::TypeFoldable<DbInterner<'a>>,
self.infer_ctxt.canonicalize_query(goal, &mut orig_values); {
(result.canonical, orig_values) let ty = self.resolve_vars_with_obligations(ty);
}; ty.fold_with(&mut Normalizer { table: self })
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,
)
} }
/// Works almost same as [`Self::normalize_associated_types_in`], but this also resolves shallow /// 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 { pub(crate) fn normalize_projection_ty(&mut self, proj_ty: ProjectionTy) -> Ty {
let var = self.new_type_var(); let ty = TyKind::Alias(chalk_ir::AliasTy::Projection(proj_ty))
let alias_eq = AliasEq { alias: AliasTy::Projection(proj_ty), ty: var.clone() }; .intern(Interner)
let obligation: Goal = alias_eq.cast(Interner); .to_nextsolver(self.interner);
self.register_obligation(obligation.to_nextsolver(self.interner)); self.normalize_alias_ty(ty).to_chalk(self.interner)
var }
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 { 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 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.resolve_with_fallback(t, &|_, _, d, _| d);
let t = self.normalize_associated_types_in(t); 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. /// 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 { pub(super) fn insert_const_vars_shallow(&mut self, c: Const) -> Const {
let data = c.data(Interner); 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()
}
}

View file

@ -22,10 +22,9 @@ use stdx::never;
use triomphe::Arc; use triomphe::Arc;
use crate::{ use crate::{
AdtId, AliasTy, Canonical, CanonicalVarKinds, DebruijnIndex, DynTyExt, ForeignDefId, AdtId, Canonical, CanonicalVarKinds, DebruijnIndex, DynTyExt, ForeignDefId, GenericArgData,
GenericArgData, Goal, InEnvironment, Interner, Mutability, Scalar, Substitution, Goal, InEnvironment, Interner, Mutability, Scalar, Substitution, TraitEnvironment, TraitRef,
TraitEnvironment, TraitRef, TraitRefExt, Ty, TyBuilder, TyExt, TyKind, TyVariableKind, TraitRefExt, Ty, TyBuilder, TyExt, TyKind, TyVariableKind, VariableKind, WhereClause,
VariableKind, WhereClause,
autoderef::{self, AutoderefKind}, autoderef::{self, AutoderefKind},
db::HirDatabase, db::HirDatabase,
from_chalk_trait_id, from_foreign_def_id, from_chalk_trait_id, from_foreign_def_id,
@ -106,8 +105,12 @@ impl TyFingerprint {
} }
} }
TyKind::AssociatedType(_, _) 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::OpaqueType(_, _)
| TyKind::Alias(AliasTy::Opaque(_))
| TyKind::FnDef(_, _) | TyKind::FnDef(_, _)
| TyKind::Closure(_, _) | TyKind::Closure(_, _)
| TyKind::Coroutine(..) | TyKind::Coroutine(..)
@ -115,8 +118,7 @@ impl TyFingerprint {
TyKind::Function(fn_ptr) => { TyKind::Function(fn_ptr) => {
TyFingerprint::Function(fn_ptr.substitution.0.len(Interner) as u32) TyFingerprint::Function(fn_ptr.substitution.0.len(Interner) as u32)
} }
TyKind::Alias(_) TyKind::Placeholder(_)
| TyKind::Placeholder(_)
| TyKind::BoundVar(_) | TyKind::BoundVar(_)
| TyKind::InferenceVar(_, _) | TyKind::InferenceVar(_, _)
| TyKind::Error => return None, | TyKind::Error => return None,
@ -908,7 +910,10 @@ fn find_matching_impl(
} }
table.register_obligation(goal.to_nextsolver(table.interner)); 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),
))
}) })
}) })
} }

View file

@ -1358,7 +1358,10 @@ pub(crate) fn convert_ty_for_result<'db>(interner: DbInterner<'db>, ty: Ty<'db>)
}; };
let associated_ty_id = to_assoc_type_id(assoc_ty_id); let associated_ty_id = to_assoc_type_id(assoc_ty_id);
let substitution = convert_args_for_result(interner, alias_ty.args.as_slice()); let substitution = convert_args_for_result(interner, alias_ty.args.as_slice());
TyKind::AssociatedType(associated_ty_id, substitution) TyKind::Alias(crate::AliasTy::Projection(crate::ProjectionTy {
associated_ty_id,
substitution,
}))
} }
rustc_type_ir::AliasTyKind::Opaque => { rustc_type_ir::AliasTyKind::Opaque => {
let opaque_ty_id = match alias_ty.def_id { let opaque_ty_id = match alias_ty.def_id {

View file

@ -202,7 +202,7 @@ fn expr_macro_def_expanded_in_various_places() {
100..119 'for _ ...!() {}': {unknown} 100..119 'for _ ...!() {}': {unknown}
100..119 'for _ ...!() {}': &'? mut {unknown} 100..119 'for _ ...!() {}': &'? mut {unknown}
100..119 'for _ ...!() {}': fn next<{unknown}>(&'? mut {unknown}) -> Option<<{unknown} as Iterator>::Item> 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 _ ...!() {}': () 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 _ ...!() {}': {unknown}
114..133 'for _ ...!() {}': &'? mut {unknown} 114..133 'for _ ...!() {}': &'? mut {unknown}
114..133 'for _ ...!() {}': fn next<{unknown}>(&'? mut {unknown}) -> Option<<{unknown} as Iterator>::Item> 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 _ ...!() {}': () 114..133 'for _ ...!() {}': ()
114..133 'for _ ...!() {}': () 114..133 'for _ ...!() {}': ()

View file

@ -362,12 +362,12 @@ fn diverging_expression_3_break() {
140..141 'x': u32 140..141 'x': u32
149..175 '{ for ...; }; }': u32 149..175 '{ for ...; }; }': u32
151..172 'for a ...eak; }': fn into_iter<{unknown}>({unknown}) -> <{unknown} as IntoIterator>::IntoIter 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; }': !
151..172 'for a ...eak; }': <{unknown} as IntoIterator>::IntoIter 151..172 'for a ...eak; }': {unknown}
151..172 'for a ...eak; }': &'? mut <{unknown} as IntoIterator>::IntoIter 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; }': 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; }': () 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 226..227 'x': u32
235..253 '{ for ... {}; }': 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 {}': 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 {}': !
237..250 'for a in b {}': <{unknown} as IntoIterator>::IntoIter 237..250 'for a in b {}': {unknown}
237..250 'for a in b {}': &'? mut <{unknown} as IntoIterator>::IntoIter 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 {}': 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 {}': () 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 304..305 'x': u32
313..340 '{ for ...; }; }': u32 313..340 '{ for ...; }; }': u32
315..337 'for a ...urn; }': fn into_iter<{unknown}>({unknown}) -> <{unknown} as IntoIterator>::IntoIter 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; }': !
315..337 'for a ...urn; }': <{unknown} as IntoIterator>::IntoIter 315..337 'for a ...urn; }': {unknown}
315..337 'for a ...urn; }': &'? mut <{unknown} as IntoIterator>::IntoIter 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; }': 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; }': () 315..337 'for a ...urn; }': ()
315..337 'for a ...urn; }': () 315..337 'for a ...urn; }': ()

View file

@ -48,12 +48,12 @@ fn infer_pattern() {
83..84 '1': i32 83..84 '1': i32
86..93 '"hello"': &'static str 86..93 '"hello"': &'static str
101..151 'for (e... }': fn into_iter<{unknown}>({unknown}) -> <{unknown} as IntoIterator>::IntoIter 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... }': !
101..151 'for (e... }': <{unknown} as IntoIterator>::IntoIter 101..151 'for (e... }': {unknown}
101..151 'for (e... }': &'? mut <{unknown} as IntoIterator>::IntoIter 101..151 'for (e... }': &'? mut {unknown}
101..151 'for (e... }': fn next<{unknown}>(&'? mut {unknown}) -> Option<<{unknown} as Iterator>::Item> 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... }': () 101..151 'for (e... }': ()
101..151 'for (e... }': () 101..151 'for (e... }': ()

View file

@ -268,12 +268,12 @@ fn infer_std_crash_5() {
expect![[r#" expect![[r#"
26..322 '{ ... } }': () 26..322 '{ ... } }': ()
32..320 'for co... }': fn into_iter<{unknown}>({unknown}) -> <{unknown} as IntoIterator>::IntoIter 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... }': !
32..320 'for co... }': <{unknown} as IntoIterator>::IntoIter 32..320 'for co... }': {unknown}
32..320 'for co... }': &'? mut <{unknown} as IntoIterator>::IntoIter 32..320 'for co... }': &'? mut {unknown}
32..320 'for co... }': fn next<{unknown}>(&'? mut {unknown}) -> Option<<{unknown} as Iterator>::Item> 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... }': () 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 65..69 'self': Self
267..271 'self': Self 267..271 'self': Self
466..470 'self': SelectStatement<F, S, D, W, O, LOf, {unknown}, {unknown}> 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..502 'self': SelectStatement<F, S, D, W, O, LOf, {unknown}, {unknown}>
498..508 'self.order': O 498..508 'self.order': O
498..515 'self.o...into()': dyn QueryFragment<DB> + '? 498..515 'self.o...into()': dyn QueryFragment<DB> + '?
@ -1248,7 +1248,7 @@ fn test() {
16..66 'for _ ... }': {unknown} 16..66 'for _ ... }': {unknown}
16..66 'for _ ... }': &'? mut {unknown} 16..66 'for _ ... }': &'? mut {unknown}
16..66 'for _ ... }': fn next<{unknown}>(&'? mut {unknown}) -> Option<<{unknown} as Iterator>::Item> 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 _ ... }': () 16..66 'for _ ... }': ()
16..66 'for _ ... }': () 16..66 'for _ ... }': ()

View file

@ -20,7 +20,7 @@ impl<'a> IntoIterator for &'a Grid {
"#, "#,
expect![[r#" expect![[r#"
150..154 'self': &'a Grid 150..154 'self': &'a Grid
174..181 '{ }': impl Iterator<Item = &'? ()> 174..181 '{ }': impl Iterator<Item = &'a ()>
"#]], "#]],
); );
} }
@ -71,3 +71,30 @@ fn main() {
}"#, }"#,
); );
} }
#[test]
fn projection_is_not_associated_type() {
check_no_mismatches(
r#"
//- minicore: fn
trait Iterator {
type Item;
fn partition<F>(self, f: F)
where
F: FnMut(&Self::Item) -> bool,
{
}
}
struct Iter;
impl Iterator for Iter {
type Item = i32;
}
fn main() {
Iter.partition(|n| true);
}
"#,
);
}

View file

@ -2000,7 +2000,7 @@ fn test() {
225..360 'match ... }': () 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..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..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 240..246 '&mut g': &'? mut |usize| yields i64 -> &'static str
245..246 'g': |usize| yields i64 -> &'static str 245..246 'g': |usize| yields i64 -> &'static str
255..261 '0usize': usize 255..261 '0usize': usize

View file

@ -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] #[test]
fn gats_with_impl_trait() { fn gats_with_impl_trait() {
// FIXME: the last function (`fn i()`) is not valid Rust as of this writing because you cannot // 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>) { fn g<'a, T: 'a>(v: impl Trait<Assoc<T> = &'a T>) {
let a = v.get::<T>(); let a = v.get::<T>();
//^ &'? T //^ &'a T
let a = v.get::<()>(); let a = v.get::<()>();
//^ <impl Trait<Assoc<T> = &'a T> as Trait>::Assoc<()> //^ <impl Trait<Assoc<T> = &'a T> as Trait>::Assoc<()>
} }
fn h<'a>(v: impl Trait<Assoc<i32> = &'a i32> + Trait<Assoc<i64> = &'a i64>) { fn h<'a>(v: impl Trait<Assoc<i32> = &'a i32> + Trait<Assoc<i64> = &'a i64>) {
let a = v.get::<i32>(); let a = v.get::<i32>();
//^ &'? i32 //^ &'a i32
let a = v.get::<i64>(); let a = v.get::<i64>();
//^ &'? i64 //^ &'a i64
} }
fn i<'a>(v: impl Trait<Assoc<i32> = &'a i32, Assoc<i64> = &'a i64>) { fn i<'a>(v: impl Trait<Assoc<i32> = &'a i32, Assoc<i64> = &'a i64>) {
let a = v.get::<i32>(); let a = v.get::<i32>();
//^ &'? i32 //^ &'a i32
let a = v.get::<i64>(); 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> + '?) 127..128 'v': &'? (dyn Trait<Assoc<i32> = &'a i32> + '?)
164..195 '{ ...f(); }': () 164..195 '{ ...f(); }': ()
170..171 'v': &'? (dyn Trait<Assoc<i32> = &'a i32> + '?) 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..184 'v.get::<i32>()': {unknown}
170..192 'v.get:...eref()': {unknown} 170..192 'v.get:...eref()': &'? {unknown}
"#]], "#]],
); );
} }
@ -4953,7 +4951,7 @@ where
"#, "#,
expect![[r#" expect![[r#"
84..86 'de': D 84..86 'de': D
135..138 '{ }': <D as Deserializer<'?>>::Error 135..138 '{ }': <D as Deserializer<'de>>::Error
"#]], "#]],
); );
} }

View file

@ -76,7 +76,7 @@ use hir_expand::{
}; };
use hir_ty::{ use hir_ty::{
AliasTy, CallableSig, Canonical, CanonicalVarKinds, Cast, ClosureId, GenericArg, 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, TraitEnvironment, TraitRefExt, Ty, TyBuilder, TyDefId, TyExt, TyKind, TyLoweringDiagnostic,
ValueTyDefId, WhereClause, all_super_traits, autoderef, check_orphan_rules, ValueTyDefId, WhereClause, all_super_traits, autoderef, check_orphan_rules,
consteval::{ConstExt, try_const_usize, unknown_const_as_generic}, consteval::{ConstExt, try_const_usize, unknown_const_as_generic},
@ -4973,6 +4973,7 @@ impl<'db> Type<'db> {
| TyKind::Tuple(_, substitution) | TyKind::Tuple(_, substitution)
| TyKind::OpaqueType(_, substitution) | TyKind::OpaqueType(_, substitution)
| TyKind::AssociatedType(_, substitution) | TyKind::AssociatedType(_, substitution)
| TyKind::Alias(AliasTy::Projection(ProjectionTy { substitution, .. }))
| TyKind::FnDef(_, substitution) => { | TyKind::FnDef(_, substitution) => {
substitution.iter(Interner).filter_map(|x| x.ty(Interner)).any(|ty| go(db, ty)) 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())); cb(type_.derived(ty.clone()));
walk_substs(db, type_, substs, cb); 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() { if ty.associated_type_parent_trait(db).is_some() {
cb(type_.derived(ty.clone())); cb(type_.derived(ty.clone()));
} }