From 0a5457a39234091fc2e73737bfc7af11d334bbfb Mon Sep 17 00:00:00 2001 From: Shoyu Vanilla Date: Mon, 22 Sep 2025 00:42:44 +0900 Subject: [PATCH] internal: Migrate more predicate things to next-solver --- crates/hir-ty/src/infer/unify.rs | 106 ++++++++++--------------- crates/hir-ty/src/lib.rs | 45 ++++++----- crates/hir-ty/src/lower_nextsolver.rs | 12 +++ crates/hir-ty/src/method_resolution.rs | 98 ++++++++--------------- crates/hir-ty/src/traits.rs | 6 +- 5 files changed, 118 insertions(+), 149 deletions(-) diff --git a/crates/hir-ty/src/infer/unify.rs b/crates/hir-ty/src/infer/unify.rs index 1687857ae1..cee95d3880 100644 --- a/crates/hir-ty/src/infer/unify.rs +++ b/crates/hir-ty/src/infer/unify.rs @@ -11,39 +11,35 @@ use hir_def::{AdtId, lang_item::LangItem}; use hir_expand::name::Name; use intern::sym; use rustc_hash::{FxHashMap, FxHashSet}; -use rustc_type_ir::inherent::Ty as _; use rustc_type_ir::{ - FloatVid, IntVid, TyVid, TypeVisitableExt, - inherent::{IntoKind, Span, Term as _}, + FloatVid, IntVid, TyVid, TypeVisitableExt, UpcastFrom, + inherent::{IntoKind, Span, Term as _, Ty as _}, relate::{Relate, solver_relating::RelateExt}, - solve::{Certainty, GoalSource, NoSolution}, + solve::{Certainty, GoalSource}, }; use smallvec::SmallVec; use triomphe::Arc; use super::{InferResult, InferenceContext, TypeError}; -use crate::next_solver::ErrorGuaranteed; use crate::{ AliasTy, BoundVar, Canonical, Const, ConstValue, DebruijnIndex, GenericArg, GenericArgData, - Goal, GoalData, InEnvironment, InferenceVar, Interner, Lifetime, OpaqueTyId, ParamKind, - ProjectionTy, Scalar, Substitution, TraitEnvironment, TraitRef, Ty, TyBuilder, TyExt, TyKind, - VariableKind, WhereClause, + InferenceVar, Interner, Lifetime, OpaqueTyId, ProjectionTy, Scalar, Substitution, + TraitEnvironment, Ty, TyExt, TyKind, VariableKind, consteval::unknown_const, db::HirDatabase, fold_generic_args, fold_tys_and_consts, - next_solver::infer::InferOk, next_solver::{ - self, ClauseKind, DbInterner, ParamEnv, Predicate, PredicateKind, SolverDefIds, Term, + self, ClauseKind, DbInterner, ErrorGuaranteed, ParamEnv, Predicate, PredicateKind, + SolverDefIds, Term, TraitRef, fulfill::FulfillmentCtxt, infer::{ - DbInternerInferExt, InferCtxt, + DbInternerInferExt, InferCtxt, InferOk, snapshot::CombinedSnapshot, traits::{Obligation, ObligationCause}, }, inspect::{InspectConfig, InspectGoal, ProofTreeVisitor}, mapping::{ChalkToNextSolver, NextSolverToChalk}, }, - to_chalk_trait_id, traits::{ FnTrait, NextTraitSolveResult, next_trait_solve_canonical_in_ctxt, next_trait_solve_in_ctxt, }, @@ -877,26 +873,15 @@ impl<'db> InferenceTable<'db> { /// whether a trait *might* be implemented before deciding to 'lock in' the /// choice (during e.g. method resolution or deref). #[tracing::instrument(level = "debug", skip(self))] - pub(crate) fn try_obligation(&mut self, goal: Goal) -> NextTraitSolveResult { - let in_env = InEnvironment::new(&self.trait_env.env, goal); - let canonicalized = self.canonicalize(in_env.to_nextsolver(self.interner)); + pub(crate) fn try_obligation(&mut self, predicate: Predicate<'db>) -> NextTraitSolveResult { + let goal = next_solver::Goal { param_env: self.param_env, predicate }; + let canonicalized = self.canonicalize(goal); next_trait_solve_canonical_in_ctxt(&self.infer_ctxt, canonicalized) } - #[tracing::instrument(level = "debug", skip(self))] - pub(crate) fn solve_obligation(&mut self, goal: Goal) -> Result { - let goal = InEnvironment::new(&self.trait_env.env, goal); - let goal = goal.to_nextsolver(self.interner); - let result = next_trait_solve_in_ctxt(&self.infer_ctxt, goal); - result.map(|m| m.1) - } - pub(crate) fn register_obligation(&mut self, predicate: Predicate<'db>) { - let goal = next_solver::Goal { - param_env: self.trait_env.env.to_nextsolver(self.interner), - predicate, - }; + let goal = next_solver::Goal { param_env: self.param_env, predicate }; self.register_obligation_in_env(goal) } @@ -984,7 +969,7 @@ impl<'db> InferenceTable<'db> { &mut self, ty: &Ty, num_args: usize, - ) -> Option<(FnTrait, Vec>, crate::next_solver::Ty<'db>)> { + ) -> Option<(FnTrait, Vec>, next_solver::Ty<'db>)> { for (fn_trait_name, output_assoc_name, subtraits) in [ (FnTrait::FnOnce, sym::Output, &[FnTrait::Fn, FnTrait::FnMut][..]), (FnTrait::AsyncFnMut, sym::CallRefFuture, &[FnTrait::AsyncFn]), @@ -997,42 +982,34 @@ impl<'db> InferenceTable<'db> { trait_data.associated_type_by_name(&Name::new_symbol_root(output_assoc_name))?; let mut arg_tys = Vec::with_capacity(num_args); - let arg_ty = TyBuilder::tuple(num_args) - .fill(|it| { - let arg = match it { - ParamKind::Type => self.new_type_var(), - ParamKind::Lifetime => unreachable!("Tuple with lifetime parameter"), - ParamKind::Const(_) => unreachable!("Tuple with const parameter"), - }; - arg_tys.push(arg.to_nextsolver(self.interner)); - arg.cast(Interner) + let arg_ty = next_solver::Ty::new_tup_from_iter( + self.interner, + std::iter::repeat_with(|| { + let ty = self.next_ty_var(); + arg_tys.push(ty); + ty }) - .build(); + .take(num_args), + ); + let args = [ty.to_nextsolver(self.interner), arg_ty]; + let trait_ref = crate::next_solver::TraitRef::new(self.interner, fn_trait.into(), args); - let b = TyBuilder::trait_ref(self.db, fn_trait); - if b.remaining() != 2 { - return None; - } - let mut trait_ref = b.push(ty.clone()).push(arg_ty).build(); + let projection = crate::next_solver::Ty::new_alias( + self.interner, + rustc_type_ir::AliasTyKind::Projection, + crate::next_solver::AliasTy::new(self.interner, output_assoc_type.into(), args), + ); - let projection = TyBuilder::assoc_type_projection( - self.db, - output_assoc_type, - Some(trait_ref.substitution.clone()), - ) - .fill_with_unknown() - .build(); - - let goal: Goal = trait_ref.clone().cast(Interner); - if !self.try_obligation(goal.clone()).no_solution() { - self.register_obligation(goal.to_nextsolver(self.interner)); - let return_ty = - self.normalize_projection_ty(projection).to_nextsolver(self.interner); + let pred = crate::next_solver::Predicate::upcast_from(trait_ref, self.interner); + if !self.try_obligation(pred).no_solution() { + self.register_obligation(pred); + let return_ty = self.normalize_alias_ty(projection); for &fn_x in subtraits { let fn_x_trait = fn_x.get_id(self.db, krate)?; - trait_ref.trait_id = to_chalk_trait_id(fn_x_trait); - let goal = trait_ref.clone().cast(Interner); - if !self.try_obligation(goal).no_solution() { + let trait_ref = + crate::next_solver::TraitRef::new(self.interner, fn_x_trait.into(), args); + let pred = crate::next_solver::Predicate::upcast_from(trait_ref, self.interner); + if !self.try_obligation(pred).no_solution() { return Some((fn_x, arg_tys, return_ty)); } } @@ -1171,12 +1148,11 @@ impl<'db> InferenceTable<'db> { let Some(sized) = LangItem::Sized.resolve_trait(self.db, self.trait_env.krate) else { return false; }; - let sized_pred = WhereClause::Implemented(TraitRef { - trait_id: to_chalk_trait_id(sized), - substitution: Substitution::from1(Interner, ty), - }); - let goal = GoalData::DomainGoal(chalk_ir::DomainGoal::Holds(sized_pred)).intern(Interner); - self.try_obligation(goal).certain() + let sized_pred = Predicate::upcast_from( + TraitRef::new(self.interner, sized.into(), [ty.to_nextsolver(self.interner)]), + self.interner, + ); + self.try_obligation(sized_pred).certain() } } diff --git a/crates/hir-ty/src/lib.rs b/crates/hir-ty/src/lib.rs index 451622ef74..2accf48843 100644 --- a/crates/hir-ty/src/lib.rs +++ b/crates/hir-ty/src/lib.rs @@ -93,7 +93,10 @@ use intern::{Symbol, sym}; use la_arena::{Arena, Idx}; use mir::{MirEvalError, VTableMap}; use rustc_hash::{FxBuildHasher, FxHashMap, FxHashSet}; -use rustc_type_ir::inherent::SliceLike; +use rustc_type_ir::{ + UpcastFrom, + inherent::{SliceLike, Ty as _}, +}; use syntax::ast::{ConstArg, make}; use traits::FnTrait; use triomphe::Arc; @@ -106,7 +109,7 @@ use crate::{ infer::unify::InferenceTable, next_solver::{ DbInterner, - mapping::{ChalkToNextSolver, convert_ty_for_result}, + mapping::{ChalkToNextSolver, NextSolverToChalk, convert_ty_for_result}, }, }; @@ -957,26 +960,32 @@ pub fn callable_sig_from_fn_trait( // Register two obligations: // - Self: FnOnce // - >::Output == ?ret_ty - let args_ty = table.new_type_var(); - let mut trait_ref = b.push(self_ty.clone()).push(args_ty.clone()).build(); - let projection = TyBuilder::assoc_type_projection( - db, - output_assoc_type, - Some(trait_ref.substitution.clone()), - ) - .build(); + let args_ty = table.next_ty_var(); + let args = [self_ty.to_nextsolver(table.interner), args_ty]; + let trait_ref = crate::next_solver::TraitRef::new(table.interner, fn_once_trait.into(), args); + let projection = crate::next_solver::Ty::new_alias( + table.interner, + rustc_type_ir::AliasTyKind::Projection, + crate::next_solver::AliasTy::new(table.interner, output_assoc_type.into(), args), + ); - let goal: Goal = trait_ref.clone().cast(Interner); - let pred = goal.to_nextsolver(table.interner); - if !table.try_obligation(goal).no_solution() { + let pred = crate::next_solver::Predicate::upcast_from(trait_ref, table.interner); + if !table.try_obligation(pred).no_solution() { table.register_obligation(pred); - let return_ty = table.normalize_projection_ty(projection); + let return_ty = table.normalize_alias_ty(projection); for fn_x in [FnTrait::Fn, FnTrait::FnMut, FnTrait::FnOnce] { let fn_x_trait = fn_x.get_id(db, krate)?; - trait_ref.trait_id = to_chalk_trait_id(fn_x_trait); - if !table.try_obligation(trait_ref.clone().cast(Interner)).no_solution() { - let ret_ty = table.resolve_completely(return_ty); - let args_ty = table.resolve_completely(args_ty); + let trait_ref = + crate::next_solver::TraitRef::new(table.interner, fn_x_trait.into(), args); + if !table + .try_obligation(crate::next_solver::Predicate::upcast_from( + trait_ref, + table.interner, + )) + .no_solution() + { + let ret_ty = table.resolve_completely(return_ty.to_chalk(table.interner)); + let args_ty = table.resolve_completely(args_ty.to_chalk(table.interner)); let params = args_ty .as_tuple()? .iter(Interner) diff --git a/crates/hir-ty/src/lower_nextsolver.rs b/crates/hir-ty/src/lower_nextsolver.rs index 0076446a95..6ecf8874c4 100644 --- a/crates/hir-ty/src/lower_nextsolver.rs +++ b/crates/hir-ty/src/lower_nextsolver.rs @@ -1355,6 +1355,18 @@ pub(crate) fn generic_predicates_for_param_cycle_result( #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct GenericPredicates<'db>(Option]>>); +impl<'db> GenericPredicates<'db> { + pub fn instantiate( + &self, + interner: DbInterner<'db>, + args: GenericArgs<'db>, + ) -> Option>> { + self.0 + .as_ref() + .map(|it| EarlyBinder::bind(it.iter().copied()).iter_instantiated(interner, args)) + } +} + impl<'db> ops::Deref for GenericPredicates<'db> { type Target = [Clause<'db>]; diff --git a/crates/hir-ty/src/method_resolution.rs b/crates/hir-ty/src/method_resolution.rs index 7fa3d31fe5..5cd4879a54 100644 --- a/crates/hir-ty/src/method_resolution.rs +++ b/crates/hir-ty/src/method_resolution.rs @@ -32,9 +32,12 @@ use crate::{ lang_items::is_box, next_solver::{ self, SolverDefId, - fulfill::FulfillmentCtxt, - infer::DefineOpaqueTypes, + infer::{ + DefineOpaqueTypes, + traits::{ObligationCause, PredicateObligation}, + }, mapping::{ChalkToNextSolver, NextSolverToChalk}, + obligation_ctxt::ObligationCtxt, }, primitive::{FloatTy, IntTy, UintTy}, to_chalk_trait_id, @@ -907,10 +910,11 @@ fn find_matching_impl( .into_iter() .map(|b| -> Goal { b.cast(Interner) }); for goal in wcs { - if table.try_obligation(goal.clone()).no_solution() { + let goal = goal.to_nextsolver(table.interner); + if table.try_obligation(goal).no_solution() { return None; } - table.register_obligation(goal.to_nextsolver(table.interner)); + table.register_obligation(goal); } Some(( impl_.impl_items(db), @@ -1395,7 +1399,7 @@ fn iterate_trait_method_candidates( let db = table.db; let canonical_self_ty = table.canonicalize(self_ty.clone().to_nextsolver(table.interner)); - let TraitEnvironment { krate, .. } = *table.trait_env; + let krate = table.trait_env.krate; 'traits: for &t in traits_in_scope { let data = db.trait_signature(t); @@ -1635,7 +1639,6 @@ pub(crate) fn resolve_indexing_op<'db>( let ty = table.instantiate_canonical_ns(ty); let deref_chain = autoderef_method_receiver(table, ty); for (ty, adj) in deref_chain { - //let goal = generic_implements_goal_ns(db, &table.trait_env, index_trait, &ty); let goal = generic_implements_goal_ns(table, index_trait, ty); if !next_trait_solve_canonical_in_ctxt(&table.infer_ctxt, goal).no_solution() { return Some(adj); @@ -1752,10 +1755,7 @@ fn is_valid_trait_method_candidate( }; let res = table .infer_ctxt - .at( - &next_solver::infer::traits::ObligationCause::dummy(), - table.trait_env.env.to_nextsolver(table.interner), - ) + .at(&next_solver::infer::traits::ObligationCause::dummy(), table.param_env) .relate( DefineOpaqueTypes::No, expected_receiver.to_nextsolver(table.interner), @@ -1767,12 +1767,10 @@ fn is_valid_trait_method_candidate( }; if !infer_ok.obligations.is_empty() { - let mut ctxt = FulfillmentCtxt::new(&table.infer_ctxt); - for pred in infer_ok.into_obligations() { - ctxt.register_predicate_obligation(&table.infer_ctxt, pred); - } + let mut ctxt = ObligationCtxt::new(&table.infer_ctxt); + ctxt.register_obligations(infer_ok.into_obligations()); // FIXME: Are we doing this correctly? Probably better to follow rustc more closely. - check_that!(ctxt.select_where_possible(&table.infer_ctxt).is_empty()); + check_that!(ctxt.select_where_possible().is_empty()); } check_that!(table.unify(receiver_ty, &expected_receiver)); @@ -1815,9 +1813,11 @@ fn is_valid_impl_fn_candidate( } table.run_in_snapshot(|table| { let _p = tracing::info_span!("subst_for_def").entered(); - let impl_subst = - TyBuilder::subst_for_def(db, impl_id, None).fill_with_inference_vars(table).build(); - let expect_self_ty = db.impl_self_ty(impl_id).substitute(Interner, &impl_subst); + let impl_subst = table.infer_ctxt.fresh_args_for_item(impl_id.into()); + let expect_self_ty = db + .impl_self_ty_ns(impl_id) + .instantiate(table.interner, &impl_subst) + .to_chalk(table.interner); check_that!(table.unify(&expect_self_ty, self_ty)); @@ -1825,9 +1825,8 @@ fn is_valid_impl_fn_candidate( let _p = tracing::info_span!("check_receiver_ty").entered(); check_that!(data.has_self_param()); - let fn_subst = TyBuilder::subst_for_def(db, fn_id, Some(impl_subst.clone())) - .fill_with_inference_vars(table) - .build(); + let fn_subst: crate::Substitution = + table.infer_ctxt.fresh_args_for_item(fn_id.into()).to_chalk(table.interner); let sig = db.callable_item_signature(fn_id.into()); let expected_receiver = @@ -1838,48 +1837,25 @@ fn is_valid_impl_fn_candidate( // We need to consider the bounds on the impl to distinguish functions of the same name // for a type. - let predicates = db.generic_predicates(impl_id.into()); - let goals = predicates.iter().map(|p| { - let (p, b) = p - .clone() - .substitute(Interner, &impl_subst) - // Skipping the inner binders is ok, as we don't handle quantified where - // clauses yet. - .into_value_and_skipped_binders(); - stdx::always!(b.len(Interner) == 0); + let predicates = db.generic_predicates_ns(impl_id.into()); + let Some(predicates) = predicates.instantiate(table.interner, impl_subst) else { + return IsValidCandidate::Yes; + }; - p.cast::(Interner) - }); + let mut ctxt = ObligationCtxt::new(&table.infer_ctxt); - for goal in goals.clone() { - match table.solve_obligation(goal) { - Ok(_) => {} - Err(_) => { - return IsValidCandidate::No; - } - } + ctxt.register_obligations(predicates.into_iter().map(|p| { + PredicateObligation::new(table.interner, ObligationCause::new(), table.param_env, p.0) + })); + + if ctxt.select_where_possible().is_empty() { + IsValidCandidate::Yes + } else { + IsValidCandidate::No } - - for goal in goals { - if table.try_obligation(goal).no_solution() { - return IsValidCandidate::No; - } - } - - IsValidCandidate::Yes }) } -pub fn implements_trait( - ty: &Canonical, - db: &dyn HirDatabase, - env: &TraitEnvironment, - trait_: TraitId, -) -> bool { - let goal = generic_implements_goal(db, env, trait_, ty); - !db.trait_solve(env.krate, env.block, goal.cast(Interner)).no_solution() -} - pub fn implements_trait_unique( ty: &Canonical, db: &dyn HirDatabase, @@ -1891,7 +1867,7 @@ pub fn implements_trait_unique( } /// This creates Substs for a trait with the given Self type and type variables -/// for all other parameters, to query Chalk with it. +/// for all other parameters, to query next solver with it. #[tracing::instrument(skip_all)] fn generic_implements_goal( db: &dyn HirDatabase, @@ -1934,11 +1910,7 @@ fn generic_implements_goal_ns<'db>( let trait_ref = rustc_type_ir::TraitRef::new_from_args(table.infer_ctxt.interner, trait_.into(), args) .with_replaced_self_ty(table.infer_ctxt.interner, self_ty); - let goal = next_solver::Goal::new( - table.infer_ctxt.interner, - table.trait_env.env.to_nextsolver(table.infer_ctxt.interner), - trait_ref, - ); + let goal = next_solver::Goal::new(table.infer_ctxt.interner, table.param_env, trait_ref); table.canonicalize(goal) } diff --git a/crates/hir-ty/src/traits.rs b/crates/hir-ty/src/traits.rs index 8095d702be..3ce78e83c1 100644 --- a/crates/hir-ty/src/traits.rs +++ b/crates/hir-ty/src/traits.rs @@ -1,4 +1,4 @@ -//! Trait solving using Chalk. +//! Trait solving using next trait solver. use core::fmt; use std::hash::Hash; @@ -128,7 +128,7 @@ fn identity_subst( chalk_ir::Canonical { binders, value: identity_subst } } -/// Solve a trait goal using Chalk. +/// Solve a trait goal using next trait solver. pub(crate) fn trait_solve_query( db: &dyn HirDatabase, krate: Crate, @@ -325,7 +325,7 @@ pub fn next_trait_solve_canonical_in_ctxt<'db>( } } -/// Solve a trait goal using Chalk. +/// Solve a trait goal using next trait solver. pub fn next_trait_solve_in_ctxt<'db, 'a>( infer_ctxt: &'a InferCtxt<'db>, goal: crate::next_solver::Goal<'db, crate::next_solver::Predicate<'db>>,