From 287a6e94822f6e9712d6523c973ffc9e167323ac Mon Sep 17 00:00:00 2001 From: Chayim Refael Friedman Date: Wed, 10 Sep 2025 03:32:06 +0300 Subject: [PATCH] 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. --- crates/hir-ty/src/infer.rs | 50 +++- crates/hir-ty/src/infer/closure.rs | 10 +- crates/hir-ty/src/infer/expr.rs | 8 +- crates/hir-ty/src/infer/pat.rs | 4 +- crates/hir-ty/src/infer/path.rs | 17 +- crates/hir-ty/src/infer/unify.rs | 242 +++++++++--------- crates/hir-ty/src/method_resolution.rs | 21 +- crates/hir-ty/src/tests/macros.rs | 4 +- crates/hir-ty/src/tests/never_type.rs | 24 +- crates/hir-ty/src/tests/patterns.rs | 8 +- crates/hir-ty/src/tests/regression.rs | 12 +- .../hir-ty/src/tests/regression/new_solver.rs | 2 +- crates/hir-ty/src/tests/simple.rs | 2 +- crates/hir-ty/src/tests/traits.rs | 18 +- crates/hir/src/lib.rs | 9 +- 15 files changed, 234 insertions(+), 197 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(&mut self, ty: T) -> T + where + T: HasInterner + TypeFoldable + ChalkToNextSolver<'db, U>, + U: NextSolverToChalk<'db, T> + rustc_type_ir::TypeFoldable>, + { + 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(&mut self, ty: T) -> T + where + T: HasInterner + TypeFoldable + ChalkToNextSolver<'db, U>, + U: NextSolverToChalk<'db, T> + rustc_type_ir::TypeFoldable>, + { + 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(&mut self, ty: T) -> T + fn normalize_associated_types_in(&mut self, ty: T) -> T where - T: HasInterner + TypeFoldable, + T: HasInterner + TypeFoldable + ChalkToNextSolver<'db, U>, + U: NextSolverToChalk<'db, T> + rustc_type_ir::TypeFoldable>, { 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 { 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(&mut self, ty: T) -> T + pub(crate) fn normalize_associated_types_in(&mut self, ty: T) -> T where - T: HasInterner + TypeFoldable, + T: ChalkToNextSolver<'a, U>, + U: NextSolverToChalk<'a, T> + rustc_type_ir::TypeFoldable>, { - 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 }; + self.normalize_associated_types_in_ns(ty.to_nextsolver(self.interner)) + .to_chalk(self.interner) + } - 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, - ) + pub(crate) fn normalize_associated_types_in_ns(&mut self, ty: T) -> T + where + T: rustc_type_ir::TypeFoldable>, + { + 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(&mut self, t: T) -> T + pub(crate) fn resolve_completely(&mut self, t: T) -> T where - T: HasInterner + TypeFoldable, + T: HasInterner + TypeFoldable + ChalkToNextSolver<'a, U>, + U: NextSolverToChalk<'a, T> + rustc_type_ir::TypeFoldable>, { 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(&mut self, ty: T) -> T + where + T: HasInterner + TypeFoldable + ChalkToNextSolver<'a, U>, + U: NextSolverToChalk<'a, T> + rustc_type_ir::TypeFoldable>, + { + 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(&mut self, ty: T) -> T + where + T: HasInterner + TypeFoldable + ChalkToNextSolver<'a, U>, + U: NextSolverToChalk<'a, T> + rustc_type_ir::TypeFoldable>, + { + 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> 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 - 488..522 '{ ... }': as BoxedDsl>::Output + 488..522 '{ ... }': () 498..502 'self': SelectStatement 498..508 'self.order': O 498..515 'self.o...into()': dyn QueryFragment + '? @@ -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 + 174..181 '{ }': impl Iterator "#]], ); } 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 + 231..262 'Pin::n...usize)': CoroutineState 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:

::Pointer) { ); } -// 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(v: impl Trait) { } fn g<'a, T: 'a>(v: impl Trait = &'a T>) { let a = v.get::(); - //^ &'? T + //^ &'a T let a = v.get::<()>(); //^ = &'a T> as Trait>::Assoc<()> } fn h<'a>(v: impl Trait = &'a i32> + Trait = &'a i64>) { let a = v.get::(); - //^ &'? i32 + //^ &'a i32 let a = v.get::(); - //^ &'? i64 + //^ &'a i64 } fn i<'a>(v: impl Trait = &'a i32, Assoc = &'a i64>) { let a = v.get::(); - //^ &'? i32 + //^ &'a i32 let a = v.get::(); - //^ &'? i64 + //^ &'a i64 } "#, ); @@ -4259,8 +4257,8 @@ fn f<'a>(v: &dyn Trait = &'a i32>) { 127..128 'v': &'? (dyn Trait = &'a i32> + '?) 164..195 '{ ...f(); }': () 170..171 'v': &'? (dyn Trait = &'a i32> + '?) - 170..184 'v.get::()': = &'a i32> + '? as Trait>::Assoc - 170..192 'v.get:...eref()': {unknown} + 170..184 'v.get::()': {unknown} + 170..192 'v.get:...eref()': &'? {unknown} "#]], ); } @@ -4953,7 +4951,7 @@ where "#, expect![[r#" 84..86 'de': D - 135..138 '{ }': >::Error + 135..138 '{ }': >::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())); }