Unnamed repository; edit this file 'description' to name the repository.
| -rw-r--r-- | crates/hir-ty/src/dyn_compatibility.rs | 14 | ||||
| -rw-r--r-- | crates/hir-ty/src/infer.rs | 2 | ||||
| -rw-r--r-- | crates/hir-ty/src/infer/cast.rs | 7 | ||||
| -rw-r--r-- | crates/hir-ty/src/infer/unify.rs | 141 | ||||
| -rw-r--r-- | crates/hir-ty/src/lib.rs | 115 | ||||
| -rw-r--r-- | crates/hir-ty/src/next_solver/infer/mod.rs | 18 | ||||
| -rw-r--r-- | crates/hir-ty/src/next_solver/infer/traits.rs | 8 | ||||
| -rw-r--r-- | crates/hir-ty/src/next_solver/ty.rs | 4 | ||||
| -rw-r--r-- | crates/hir-ty/src/traits.rs | 97 | ||||
| -rw-r--r-- | crates/hir/src/lib.rs | 18 |
10 files changed, 111 insertions, 313 deletions
diff --git a/crates/hir-ty/src/dyn_compatibility.rs b/crates/hir-ty/src/dyn_compatibility.rs index ee7527446a..0cf7f650f0 100644 --- a/crates/hir-ty/src/dyn_compatibility.rs +++ b/crates/hir-ty/src/dyn_compatibility.rs @@ -21,11 +21,14 @@ use crate::{ db::{HirDatabase, InternedOpaqueTyId}, lower::{GenericPredicates, associated_ty_item_bounds}, next_solver::{ - AliasTy, Binder, Clause, Clauses, DbInterner, EarlyBinder, GenericArgs, Goal, ParamEnv, - ParamTy, SolverDefId, TraitPredicate, TraitRef, Ty, TypingMode, infer::DbInternerInferExt, + AliasTy, Binder, Clause, Clauses, DbInterner, EarlyBinder, GenericArgs, ParamEnv, ParamTy, + SolverDefId, TraitPredicate, TraitRef, Ty, TypingMode, + infer::{ + DbInternerInferExt, + traits::{Obligation, ObligationCause}, + }, mk_param, }, - traits::next_trait_solve_in_ctxt, }; #[derive(Debug, Clone, PartialEq, Eq, Hash)] @@ -474,12 +477,11 @@ fn receiver_is_dispatchable<'db>( // Receiver: DispatchFromDyn<Receiver[Self => U]> let predicate = TraitRef::new(interner, dispatch_from_dyn_did.into(), [receiver_ty, unsized_receiver_ty]); - let goal = Goal::new(interner, param_env, predicate); + let obligation = Obligation::new(interner, ObligationCause::dummy(), param_env, predicate); let infcx = interner.infer_ctxt().build(TypingMode::non_body_analysis()); // the receiver is dispatchable iff the obligation holds - let res = next_trait_solve_in_ctxt(&infcx, goal); - res.map_or(false, |res| matches!(res.1, rustc_type_ir::solve::Certainty::Yes)) + infcx.predicate_must_hold_modulo_regions(&obligation) } fn receiver_for_self_ty<'db>( diff --git a/crates/hir-ty/src/infer.rs b/crates/hir-ty/src/infer.rs index 54f334b66d..9a6941f8a3 100644 --- a/crates/hir-ty/src/infer.rs +++ b/crates/hir-ty/src/infer.rs @@ -1240,7 +1240,7 @@ impl<'body, 'db> InferenceContext<'body, 'db> { db.trait_environment(ExpressionStoreOwnerId::VariantFields(variant_id)) } }; - let table = unify::InferenceTable::new(db, trait_env, resolver.krate(), Some(owner)); + let table = unify::InferenceTable::new(db, trait_env, resolver.krate(), owner); let types = crate::next_solver::default_types(db); InferenceContext { result: InferenceResult::new(types.types.error), diff --git a/crates/hir-ty/src/infer/cast.rs b/crates/hir-ty/src/infer/cast.rs index 09855766d8..d23a32d81b 100644 --- a/crates/hir-ty/src/infer/cast.rs +++ b/crates/hir-ty/src/infer/cast.rs @@ -147,7 +147,8 @@ impl<'db> CastCheck<'db> { return Ok(()); } - if !self.cast_ty.has_infer_types() && !ctx.table.is_sized(self.cast_ty) { + if !self.cast_ty.has_infer_types() && !ctx.table.type_is_sized_modulo_regions(self.cast_ty) + { return Err(InferenceDiagnostic::CastToUnsized { expr: self.expr, cast_ty: self.cast_ty.store(), @@ -199,7 +200,7 @@ impl<'db> CastCheck<'db> { // array-ptr-cast CastTy::Ptr(t, m) => { let t = ctx.table.try_structurally_resolve_type(t); - if !ctx.table.is_sized(t) { + if !ctx.table.type_is_sized_modulo_regions(t) { return Err(CastError::IllegalCast); } self.check_ref_cast(ctx, inner_ty, mutbl, t, m) @@ -520,7 +521,7 @@ fn pointer_kind<'db>( ) -> Result<Option<PointerKind<'db>>, ()> { let ty = ctx.table.try_structurally_resolve_type(ty); - if ctx.table.is_sized(ty) { + if ctx.table.type_is_sized_modulo_regions(ty) { return Ok(Some(PointerKind::Thin)); } diff --git a/crates/hir-ty/src/infer/unify.rs b/crates/hir-ty/src/infer/unify.rs index b0f916b8c0..1d6a87a157 100644 --- a/crates/hir-ty/src/infer/unify.rs +++ b/crates/hir-ty/src/infer/unify.rs @@ -3,10 +3,10 @@ use std::fmt; use base_db::Crate; -use hir_def::{AdtId, ExpressionStoreOwnerId, GenericParamId, TraitId}; +use hir_def::{ExpressionStoreOwnerId, GenericParamId, TraitId}; use rustc_hash::FxHashSet; use rustc_type_ir::{ - TyVid, TypeFoldable, TypeVisitableExt, UpcastFrom, + TyVid, TypeFoldable, TypeVisitableExt, inherent::{Const as _, GenericArg as _, IntoKind, Ty as _}, solve::Certainty, }; @@ -15,7 +15,7 @@ use smallvec::SmallVec; use crate::{ db::HirDatabase, next_solver::{ - Canonical, ClauseKind, Const, DbInterner, ErrorGuaranteed, GenericArg, GenericArgs, Goal, + Canonical, ClauseKind, Const, DbInterner, ErrorGuaranteed, GenericArg, GenericArgs, ParamEnv, Predicate, PredicateKind, Region, SolverDefId, Term, TraitRef, Ty, TyKind, TypingMode, fulfill::{FulfillmentCtxt, NextSolverError}, @@ -28,10 +28,7 @@ use crate::{ inspect::{InspectConfig, InspectGoal, ProofTreeVisitor}, obligation_ctxt::ObligationCtxt, }, - traits::{ - NextTraitSolveResult, ParamEnvAndCrate, next_trait_solve_canonical_in_ctxt, - next_trait_solve_in_ctxt, - }, + traits::ParamEnvAndCrate, }; struct NestedObligationsForSelfTy<'a, 'db> { @@ -145,14 +142,10 @@ impl<'db> InferenceTable<'db> { db: &'db dyn HirDatabase, trait_env: ParamEnv<'db>, krate: Crate, - owner: Option<ExpressionStoreOwnerId>, + owner: ExpressionStoreOwnerId, ) -> Self { let interner = DbInterner::new_with(db, krate); - let typing_mode = match owner { - Some(owner) => TypingMode::typeck_for_body(interner, owner.into()), - // IDE things wants to reveal opaque types. - None => TypingMode::PostAnalysis, - }; + let typing_mode = TypingMode::typeck_for_body(interner, owner.into()); let infer_ctxt = interner.infer_ctxt().build(typing_mode); InferenceTable { db, @@ -172,6 +165,10 @@ impl<'db> InferenceTable<'db> { self.infer_ctxt.type_is_copy_modulo_regions(self.param_env, ty) } + pub(crate) fn type_is_sized_modulo_regions(&self, ty: Ty<'db>) -> bool { + self.infer_ctxt.type_is_sized_modulo_regions(self.param_env, ty) + } + pub(crate) fn type_is_use_cloned_modulo_regions(&self, ty: Ty<'db>) -> bool { self.infer_ctxt.type_is_use_cloned_modulo_regions(self.param_env, ty) } @@ -253,23 +250,6 @@ impl<'db> InferenceTable<'db> { self.diverging_type_vars.insert(ty); } - pub(crate) fn canonicalize<T>(&mut self, t: T) -> rustc_type_ir::Canonical<DbInterner<'db>, T> - where - T: TypeFoldable<DbInterner<'db>>, - { - // try to resolve obligations before canonicalizing, since this might - // result in new knowledge about variables - self.select_obligations_where_possible(); - self.infer_ctxt.canonicalize_response(t) - } - - pub(crate) fn normalize_alias_ty(&mut self, alias: Ty<'db>) -> Ty<'db> { - self.infer_ctxt - .at(&ObligationCause::new(), self.param_env) - .structurally_normalize_ty(alias, &mut self.fulfillment_cx) - .unwrap_or(alias) - } - pub(crate) fn next_ty_var(&self) -> Ty<'db> { self.infer_ctxt.next_ty_var() } @@ -407,43 +387,6 @@ impl<'db> InferenceTable<'db> { result } - /// Checks an obligation without registering it. Useful mostly to check - /// 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, predicate: Predicate<'db>) -> NextTraitSolveResult { - let goal = Goal { param_env: self.param_env, predicate }; - let canonicalized = self.canonicalize(goal); - - next_trait_solve_canonical_in_ctxt(&self.infer_ctxt, canonicalized) - } - - pub(crate) fn register_obligation(&mut self, predicate: Predicate<'db>) { - let goal = Goal { param_env: self.param_env, predicate }; - self.register_obligation_in_env(goal) - } - - #[tracing::instrument(level = "debug", skip(self))] - fn register_obligation_in_env(&mut self, goal: Goal<'db, Predicate<'db>>) { - let result = next_trait_solve_in_ctxt(&self.infer_ctxt, goal); - tracing::debug!(?result); - match result { - Ok((_, Certainty::Yes)) => {} - Err(rustc_type_ir::solve::NoSolution) => {} - Ok((_, Certainty::Maybe { .. })) => { - self.fulfillment_cx.register_predicate_obligation( - &self.infer_ctxt, - Obligation::new( - self.interner(), - ObligationCause::new(), - goal.param_env, - goal.predicate, - ), - ); - } - } - } - pub(crate) fn register_bound(&mut self, ty: Ty<'db>, def_id: TraitId, cause: ObligationCause) { if !ty.references_non_lt_error() { let trait_ref = TraitRef::new(self.interner(), def_id.into(), [ty]); @@ -533,70 +476,6 @@ impl<'db> InferenceTable<'db> { pub(super) fn insert_const_vars_shallow(&mut self, c: Const<'db>) -> Const<'db> { if c.is_ct_error() { self.next_const_var() } else { c } } - - /// Check if given type is `Sized` or not - pub(crate) fn is_sized(&mut self, ty: Ty<'db>) -> bool { - fn short_circuit_trivial_tys(ty: Ty<'_>) -> Option<bool> { - match ty.kind() { - TyKind::Bool - | TyKind::Char - | TyKind::Int(_) - | TyKind::Uint(_) - | TyKind::Float(_) - | TyKind::Ref(..) - | TyKind::RawPtr(..) - | TyKind::Never - | TyKind::FnDef(..) - | TyKind::Array(..) - | TyKind::FnPtr(..) => Some(true), - TyKind::Slice(..) | TyKind::Str | TyKind::Dynamic(..) => Some(false), - _ => None, - } - } - - let mut ty = ty; - ty = self.try_structurally_resolve_type(ty); - if let Some(sized) = short_circuit_trivial_tys(ty) { - return sized; - } - - { - let mut structs = SmallVec::<[_; 8]>::new(); - // Must use a loop here and not recursion because otherwise users will conduct completely - // artificial examples of structs that have themselves as the tail field and complain r-a crashes. - while let Some((AdtId::StructId(id), subst)) = ty.as_adt() { - let struct_data = id.fields(self.db); - if let Some((last_field, _)) = struct_data.fields().iter().next_back() { - let last_field_ty = self.db.field_types(id.into())[last_field] - .get() - .instantiate(self.interner(), subst); - if structs.contains(&ty) { - // A struct recursively contains itself as a tail field somewhere. - return true; // Don't overload the users with too many errors. - } - structs.push(ty); - // Structs can have DST as its last field and such cases are not handled - // as unsized by the chalk, so we do this manually. - ty = last_field_ty; - ty = self.try_structurally_resolve_type(ty); - if let Some(sized) = short_circuit_trivial_tys(ty) { - return sized; - } - } else { - break; - }; - } - } - - let Some(sized) = self.interner().lang_items().Sized else { - return false; - }; - let sized_pred = Predicate::upcast_from( - TraitRef::new(self.interner(), sized.into(), [ty]), - self.interner(), - ); - self.try_obligation(sized_pred).certain() - } } impl fmt::Debug for InferenceTable<'_> { diff --git a/crates/hir-ty/src/lib.rs b/crates/hir-ty/src/lib.rs index c6c7856c8c..2973b970f3 100644 --- a/crates/hir-ty/src/lib.rs +++ b/crates/hir-ty/src/lib.rs @@ -71,7 +71,7 @@ use macros::GenericTypeVisitable; use mir::{MirEvalError, VTableMap}; use rustc_hash::{FxBuildHasher, FxHashMap, FxHashSet}; use rustc_type_ir::{ - BoundVarIndexKind, TypeSuperVisitable, TypeVisitableExt, UpcastFrom, + BoundVarIndexKind, TypeSuperVisitable, TypeVisitableExt, inherent::{IntoKind, Ty as _}, }; use syntax::ast::{ConstArg, make}; @@ -80,12 +80,17 @@ use traits::FnTrait; use crate::{ db::HirDatabase, display::{DisplayTarget, HirDisplay}, - infer::unify::InferenceTable, lower::SupertraitsInfo, next_solver::{ AliasTy, Binder, BoundConst, BoundRegion, BoundRegionKind, BoundTy, BoundTyKind, Canonical, - CanonicalVarKind, CanonicalVarKinds, ClauseKind, Const, ConstKind, DbInterner, FnSig, - GenericArgs, PolyFnSig, Predicate, Region, RegionKind, TraitRef, Ty, TyKind, Tys, abi, + CanonicalVarKind, CanonicalVarKinds, ClauseKind, Const, ConstKind, DbInterner, GenericArgs, + PolyFnSig, Region, RegionKind, TraitRef, Ty, TyKind, TypingMode, + abi::Safety, + infer::{ + DbInternerInferExt, + traits::{Obligation, ObligationCause}, + }, + obligation_ctxt::ObligationCtxt, }, }; @@ -525,68 +530,64 @@ pub fn associated_type_shorthand_candidates( /// To be used from `hir` only. pub fn callable_sig_from_fn_trait<'db>( self_ty: Ty<'db>, - trait_env: ParamEnvAndCrate<'db>, + param_env: ParamEnvAndCrate<'db>, db: &'db dyn HirDatabase, ) -> Option<(FnTrait, PolyFnSig<'db>)> { - let mut table = InferenceTable::new(db, trait_env.param_env, trait_env.krate, None); - let lang_items = table.interner().lang_items(); + let ParamEnvAndCrate { param_env, krate } = param_env; + let interner = DbInterner::new_with(db, krate); + let infcx = interner.infer_ctxt().build(TypingMode::PostAnalysis); + let lang_items = interner.lang_items(); + let cause = ObligationCause::dummy(); + + let impls_trait = |trait_: FnTrait| { + let mut ocx = ObligationCtxt::new(&infcx); + let tupled_args = infcx.next_ty_var(); + let args = GenericArgs::new_from_slice(&[self_ty.into(), tupled_args.into()]); + let trait_id = trait_.get_id(lang_items)?; + let trait_ref = TraitRef::new_from_args(interner, trait_id.into(), args); + let obligation = Obligation::new(interner, cause.clone(), param_env, trait_ref); + ocx.register_obligation(obligation); + if !ocx.try_evaluate_obligations().is_empty() { + return None; + } + let tupled_args = + infcx.resolve_vars_if_possible(tupled_args).replace_infer_with_error(interner); + if tupled_args.is_tuple() { Some(tupled_args) } else { None } + }; - let fn_once_trait = FnTrait::FnOnce.get_id(lang_items)?; + let (trait_, args) = 'find_trait: { + for trait_ in [FnTrait::Fn, FnTrait::FnMut, FnTrait::FnOnce] { + if let Some(args) = impls_trait(trait_) { + break 'find_trait (trait_, args); + } + } + return None; + }; + + let fn_once_trait = lang_items.FnOnce?; let output_assoc_type = fn_once_trait .trait_items(db) .associated_type_by_name(&Name::new_symbol_root(sym::Output))?; - - // Register two obligations: - // - Self: FnOnce<?args_ty> - // - <Self as FnOnce<?args_ty>>::Output == ?ret_ty - let args_ty = table.next_ty_var(); - let args = GenericArgs::new_from_slice(&[self_ty.into(), args_ty.into()]); - let trait_ref = TraitRef::new_from_args(table.interner(), fn_once_trait.into(), args); - let projection = Ty::new_alias( - table.interner(), - AliasTy::new_from_args( - table.interner(), + let output_projection = Ty::new_alias( + interner, + AliasTy::new( + interner, rustc_type_ir::Projection { def_id: output_assoc_type.into() }, - args, + [self_ty, args], ), ); - - let pred = Predicate::upcast_from(trait_ref, table.interner()); - if !table.try_obligation(pred).no_solution() { - table.register_obligation(pred); - 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(lang_items)?; - let trait_ref = TraitRef::new_from_args(table.interner(), fn_x_trait.into(), args); - if !table - .try_obligation(Predicate::upcast_from(trait_ref, table.interner())) - .no_solution() - { - let ret_ty = table.resolve_completely(return_ty); - let args_ty = table.resolve_completely(args_ty); - let TyKind::Tuple(params) = args_ty.kind() else { - return None; - }; - let inputs_and_output = Tys::new_from_iter( - table.interner(), - params.iter().chain(std::iter::once(ret_ty)), - ); - - return Some(( - fn_x, - Binder::dummy(FnSig { - inputs_and_output, - c_variadic: false, - safety: abi::Safety::Safe, - abi: FnAbi::RustCall, - }), - )); - } - } - unreachable!("It should at least implement FnOnce at this point"); - } else { - None - } + let mut ocx = ObligationCtxt::new(&infcx); + let ret = ocx.structurally_normalize_ty(&cause, param_env, output_projection).ok()?; + let ret = ret.replace_infer_with_error(interner); + + let sig = Binder::dummy(interner.mk_fn_sig( + args.tuple_fields(), + ret, + false, + Safety::Safe, + FnAbi::Rust, + )); + Some((trait_, sig)) } struct ParamCollector { diff --git a/crates/hir-ty/src/next_solver/infer/mod.rs b/crates/hir-ty/src/next_solver/infer/mod.rs index de21c5442b..1eacc295c9 100644 --- a/crates/hir-ty/src/next_solver/infer/mod.rs +++ b/crates/hir-ty/src/next_solver/infer/mod.rs @@ -58,7 +58,7 @@ pub mod relate; pub mod resolve; pub mod select; pub(crate) mod snapshot; -pub(crate) mod traits; +pub mod traits; mod type_variable; mod unify_key; @@ -494,8 +494,7 @@ impl<'db> InferCtxt<'db> { /// check::<&'_ T>(); /// } /// ``` - #[expect(dead_code, reason = "this is used in rustc")] - fn predicate_must_hold_considering_regions( + pub fn predicate_must_hold_considering_regions( &self, obligation: &PredicateObligation<'db>, ) -> bool { @@ -507,8 +506,10 @@ impl<'db> InferCtxt<'db> { /// not entirely accurate if inference variables are involved. /// /// This version ignores all outlives constraints. - #[expect(dead_code, reason = "this is used in rustc")] - fn predicate_must_hold_modulo_regions(&self, obligation: &PredicateObligation<'db>) -> bool { + pub fn predicate_must_hold_modulo_regions( + &self, + obligation: &PredicateObligation<'db>, + ) -> bool { self.evaluate_obligation(obligation).must_apply_modulo_regions() } @@ -610,6 +611,13 @@ impl<'db> InferCtxt<'db> { traits::type_known_to_meet_bound_modulo_regions(self, param_env, ty, copy_def_id) } + pub fn type_is_sized_modulo_regions(&self, param_env: ParamEnv<'db>, ty: Ty<'db>) -> bool { + let Some(sized_def_id) = self.interner.lang_items().Sized else { + return true; + }; + traits::type_known_to_meet_bound_modulo_regions(self, param_env, ty, sized_def_id) + } + pub fn type_is_use_cloned_modulo_regions(&self, param_env: ParamEnv<'db>, ty: Ty<'db>) -> bool { let ty = self.resolve_vars_if_possible(ty); diff --git a/crates/hir-ty/src/next_solver/infer/traits.rs b/crates/hir-ty/src/next_solver/infer/traits.rs index dde6234836..5b875d2960 100644 --- a/crates/hir-ty/src/next_solver/infer/traits.rs +++ b/crates/hir-ty/src/next_solver/infer/traits.rs @@ -185,12 +185,12 @@ impl<'db> PredicateObligation<'db> { impl<'db, O> Obligation<'db, O> { pub fn new( - tcx: DbInterner<'db>, + interner: DbInterner<'db>, cause: ObligationCause, param_env: ParamEnv<'db>, predicate: impl Upcast<DbInterner<'db>, O>, ) -> Obligation<'db, O> { - Self::with_depth(tcx, cause, 0, param_env, predicate) + Self::with_depth(interner, cause, 0, param_env, predicate) } /// We often create nested obligations without setting the correct depth. @@ -202,13 +202,13 @@ impl<'db, O> Obligation<'db, O> { } pub fn with_depth( - tcx: DbInterner<'db>, + interner: DbInterner<'db>, cause: ObligationCause, recursion_depth: usize, param_env: ParamEnv<'db>, predicate: impl Upcast<DbInterner<'db>, O>, ) -> Obligation<'db, O> { - let predicate = predicate.upcast(tcx); + let predicate = predicate.upcast(interner); Obligation { cause, param_env, recursion_depth, predicate } } diff --git a/crates/hir-ty/src/next_solver/ty.rs b/crates/hir-ty/src/next_solver/ty.rs index c953e79602..0fd02eb8ca 100644 --- a/crates/hir-ty/src/next_solver/ty.rs +++ b/crates/hir-ty/src/next_solver/ty.rs @@ -626,6 +626,10 @@ impl<'db> Ty<'db> { } } + pub fn is_tuple(self) -> bool { + matches!(self.kind(), TyKind::Tuple(_)) + } + pub fn as_tuple(self) -> Option<Tys<'db>> { match self.kind() { TyKind::Tuple(tys) => Some(tys), diff --git a/crates/hir-ty/src/traits.rs b/crates/hir-ty/src/traits.rs index 878696c721..0dc834ddcc 100644 --- a/crates/hir-ty/src/traits.rs +++ b/crates/hir-ty/src/traits.rs @@ -15,18 +15,15 @@ use hir_def::{ }; use hir_expand::name::Name; use intern::sym; -use rustc_next_trait_solver::solve::{HasChanged, SolverDelegateEvalExt}; use rustc_type_ir::{ TypingMode, - inherent::{AdtDef, BoundExistentialPredicates, IntoKind, Span as _}, - solve::Certainty, + inherent::{AdtDef, BoundExistentialPredicates, IntoKind}, }; use crate::{ db::HirDatabase, next_solver::{ - Canonical, DbInterner, GenericArgs, Goal, ParamEnv, Predicate, SolverContext, Span, - StoredClauses, Ty, TyKind, + DbInterner, GenericArgs, ParamEnv, StoredClauses, Ty, TyKind, infer::{ DbInternerInferExt, InferCtxt, traits::{Obligation, ObligationCause}, @@ -79,91 +76,6 @@ pub fn structurally_normalize_ty<'db>( ty.replace_infer_with_error(infcx.interner) } -#[derive(Clone, Debug, PartialEq)] -pub enum NextTraitSolveResult { - Certain, - Uncertain, - NoSolution, -} - -impl NextTraitSolveResult { - pub fn no_solution(&self) -> bool { - matches!(self, NextTraitSolveResult::NoSolution) - } - - pub fn certain(&self) -> bool { - matches!(self, NextTraitSolveResult::Certain) - } - - pub fn uncertain(&self) -> bool { - matches!(self, NextTraitSolveResult::Uncertain) - } -} - -pub fn next_trait_solve_canonical_in_ctxt<'db>( - infer_ctxt: &InferCtxt<'db>, - goal: Canonical<'db, Goal<'db, Predicate<'db>>>, -) -> NextTraitSolveResult { - infer_ctxt.probe(|_| { - let context = <&SolverContext<'db>>::from(infer_ctxt); - - tracing::info!(?goal); - - let (goal, var_values) = context.instantiate_canonical(&goal); - tracing::info!(?var_values); - - let res = context.evaluate_root_goal(goal, Span::dummy(), None); - - let obligation = Obligation { - cause: ObligationCause::dummy(), - param_env: goal.param_env, - recursion_depth: 0, - predicate: goal.predicate, - }; - infer_ctxt.inspect_evaluated_obligation(&obligation, &res, || { - Some(context.evaluate_root_goal_for_proof_tree(goal, Span::dummy()).1) - }); - - let res = res.map(|r| (r.has_changed, r.certainty)); - - tracing::debug!("solve_nextsolver({:?}) => {:?}", goal, res); - - match res { - Err(_) => NextTraitSolveResult::NoSolution, - Ok((_, Certainty::Yes)) => NextTraitSolveResult::Certain, - Ok((_, Certainty::Maybe { .. })) => NextTraitSolveResult::Uncertain, - } - }) -} - -/// Solve a trait goal using next trait solver. -pub fn next_trait_solve_in_ctxt<'db, 'a>( - infer_ctxt: &'a InferCtxt<'db>, - goal: Goal<'db, Predicate<'db>>, -) -> Result<(HasChanged, Certainty), rustc_type_ir::solve::NoSolution> { - tracing::info!(?goal); - - let context = <&SolverContext<'db>>::from(infer_ctxt); - - let res = context.evaluate_root_goal(goal, Span::dummy(), None); - - let obligation = Obligation { - cause: ObligationCause::dummy(), - param_env: goal.param_env, - recursion_depth: 0, - predicate: goal.predicate, - }; - infer_ctxt.inspect_evaluated_obligation(&obligation, &res, || { - Some(context.evaluate_root_goal_for_proof_tree(goal, Span::dummy()).1) - }); - - let res = res.map(|r| (r.has_changed, r.certainty)); - - tracing::debug!("solve_nextsolver({:?}) => {:?}", goal, res); - - res -} - #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, salsa::Update)] pub enum FnTrait { // Warning: Order is important. If something implements `x` it should also implement @@ -235,10 +147,9 @@ fn implements_trait_unique_impl<'db>( let args = create_args(&infcx); let trait_ref = rustc_type_ir::TraitRef::new_from_args(interner, trait_.into(), args); - let goal = Goal::new(interner, env.param_env, trait_ref); - let result = crate::traits::next_trait_solve_in_ctxt(&infcx, goal); - matches!(result, Ok((_, Certainty::Yes))) + let obligation = Obligation::new(interner, ObligationCause::dummy(), env.param_env, trait_ref); + infcx.predicate_must_hold_modulo_regions(&obligation) } pub fn is_inherent_impl_coherent(db: &dyn HirDatabase, def_map: &DefMap, impl_id: ImplId) -> bool { diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs index ecd11fb5d7..11598f2a10 100644 --- a/crates/hir/src/lib.rs +++ b/crates/hir/src/lib.rs @@ -6561,21 +6561,13 @@ impl<'db> TypeNs<'db> { ); let trait_ref = hir_ty::next_solver::TraitRef::new_from_args(infcx.interner, trait_.id.into(), args); - - let pred_kind = rustc_type_ir::Binder::dummy(rustc_type_ir::PredicateKind::Clause( - rustc_type_ir::ClauseKind::Trait(rustc_type_ir::TraitPredicate { - trait_ref, - polarity: rustc_type_ir::PredicatePolarity::Positive, - }), - )); - let predicate = hir_ty::next_solver::Predicate::new(infcx.interner, pred_kind); - let goal = hir_ty::next_solver::Goal::new( + let obligation = hir_ty::next_solver::infer::traits::Obligation::new( infcx.interner, - hir_ty::next_solver::ParamEnv::empty(), - predicate, + hir_ty::next_solver::infer::traits::ObligationCause::dummy(), + self.env.param_env, + trait_ref, ); - let res = hir_ty::traits::next_trait_solve_in_ctxt(&infcx, goal); - res.map_or(false, |res| matches!(res.1, rustc_type_ir::solve::Certainty::Yes)) + infcx.predicate_must_hold_modulo_regions(&obligation) } pub fn is_bool(&self) -> bool { |