Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/hir-ty/src/next_solver/infer/mod.rs')
| -rw-r--r-- | crates/hir-ty/src/next_solver/infer/mod.rs | 282 |
1 files changed, 156 insertions, 126 deletions
diff --git a/crates/hir-ty/src/next_solver/infer/mod.rs b/crates/hir-ty/src/next_solver/infer/mod.rs index a6352c7899..839bdf17e7 100644 --- a/crates/hir-ty/src/next_solver/infer/mod.rs +++ b/crates/hir-ty/src/next_solver/infer/mod.rs @@ -7,12 +7,10 @@ use std::sync::Arc; pub use BoundRegionConversionTime::*; use ena::unify as ut; -use hir_def::GenericParamId; +use hir_def::{GenericParamId, TraitId}; use opaque_types::{OpaqueHiddenType, OpaqueTypeStorage}; use region_constraints::{RegionConstraintCollector, RegionConstraintStorage}; use rustc_next_trait_solver::solve::{GoalEvaluation, SolverDelegateEvalExt}; -use rustc_pattern_analysis::Captures; -use rustc_type_ir::solve::{NoSolution, inspect}; use rustc_type_ir::{ ClosureKind, ConstVid, FloatVarValue, FloatVid, GenericArgKind, InferConst, InferTy, IntVarValue, IntVid, OutlivesPredicate, RegionVid, TermKind, TyVid, TypeFoldable, TypeFolder, @@ -22,19 +20,25 @@ use rustc_type_ir::{ Const as _, GenericArg as _, GenericArgs as _, IntoKind, SliceLike, Term as _, Ty as _, }, }; +use rustc_type_ir::{ + Upcast, + solve::{NoSolution, inspect}, +}; use snapshot::undo_log::InferCtxtUndoLogs; use tracing::{debug, instrument}; use traits::{ObligationCause, PredicateObligations}; -use type_variable::TypeVariableOrigin; -use unify_key::{ConstVariableOrigin, ConstVariableValue, ConstVidKey}; +use unify_key::{ConstVariableValue, ConstVidKey}; pub use crate::next_solver::infer::traits::ObligationInspector; -use crate::next_solver::{ - ArgOutlivesPredicate, BoundConst, BoundRegion, BoundTy, BoundVariableKind, Goal, Predicate, - SolverContext, - fold::BoundVarReplacerDelegate, - infer::{at::ToTrace, select::EvaluationResult, traits::PredicateObligation}, - obligation_ctxt::ObligationCtxt, +use crate::{ + Span, + next_solver::{ + ArgOutlivesPredicate, BoundConst, BoundRegion, BoundTy, BoundVariableKind, Goal, Predicate, + SolverContext, + fold::BoundVarReplacerDelegate, + infer::{at::ToTrace, select::EvaluationResult, traits::PredicateObligation}, + obligation_ctxt::ObligationCtxt, + }, }; use super::{ @@ -48,6 +52,7 @@ use super::{ pub mod at; pub mod canonical; mod context; +pub mod errors; pub mod opaque_types; mod outlives; pub mod region_constraints; @@ -55,7 +60,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; @@ -361,13 +366,14 @@ impl<'db> InferCtxtBuilder<'db> { /// (in other words, `S(C) = V`). pub fn build_with_canonical<T>( mut self, + span: Span, input: &CanonicalQueryInput<'db, T>, ) -> (InferCtxt<'db>, T, CanonicalVarValues<'db>) where T: TypeFoldable<DbInterner<'db>>, { let infcx = self.build(input.typing_mode.0); - let (value, args) = infcx.instantiate_canonical(&input.canonical); + let (value, args) = infcx.instantiate_canonical(span, &input.canonical); (infcx, value, args) } @@ -396,7 +402,7 @@ impl<'db> InferOk<'db, ()> { impl<'db> InferCtxt<'db> { #[inline(always)] - pub fn typing_mode(&self) -> TypingMode<'db> { + pub fn typing_mode_raw(&self) -> TypingMode<'db> { self.typing_mode } @@ -441,7 +447,11 @@ impl<'db> InferCtxt<'db> { return ty; } - if ty.is_ty_error() { self.infcx.next_ty_var() } else { ty.super_fold_with(self) } + if ty.is_ty_error() { + self.infcx.next_ty_var(Span::Dummy) + } else { + ty.super_fold_with(self) + } } fn fold_const(&mut self, ct: Const<'db>) -> Const<'db> { @@ -450,14 +460,14 @@ impl<'db> InferCtxt<'db> { } if ct.is_ct_error() { - self.infcx.next_const_var() + self.infcx.next_const_var(Span::Dummy) } else { ct.super_fold_with(self) } } fn fold_region(&mut self, r: Region<'db>) -> Region<'db> { - if r.is_error() { self.infcx.next_region_var() } else { r } + if r.is_error() { self.infcx.next_region_var(Span::Dummy) } else { r } } } @@ -491,8 +501,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 { @@ -504,11 +513,59 @@ 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() } + /// Check whether a `ty` implements given trait(trait_def_id) without side-effects. + /// + /// The inputs are: + /// + /// - the def-id of the trait + /// - the type parameters of the trait, including the self-type + /// - the parameter environment + /// + /// Invokes `evaluate_obligation`, so in the event that evaluating + /// `Ty: Trait` causes overflow, EvaluatedToAmbigStackDependent will be returned. + /// + /// `type_implements_trait` is a convenience function for simple cases like + /// + /// ```ignore (illustrative) + /// let copy_trait = infcx.tcx.require_lang_item(LangItem::Copy, span); + /// let implements_copy = infcx.type_implements_trait(copy_trait, [ty], param_env) + /// .must_apply_modulo_regions(); + /// ``` + /// + /// In most cases you should instead create an [Obligation] and check whether + /// it holds via [`evaluate_obligation`] or one of its helper functions like + /// [`predicate_must_hold_modulo_regions`], because it properly handles higher ranked traits + /// and it is more convenient and safer when your `params` are inside a [`Binder`]. + /// + /// [Obligation]: traits::Obligation + /// [`evaluate_obligation`]: InferCtxt::evaluate_obligation + /// [`predicate_must_hold_modulo_regions`]: InferCtxt::predicate_must_hold_modulo_regions + /// [`Binder`]: rustc_type_ir::Binder + #[instrument(level = "debug", skip(self, params), ret)] + pub fn type_implements_trait( + &self, + trait_def_id: TraitId, + params: impl IntoIterator<Item: Into<GenericArg<'db>>>, + param_env: ParamEnv<'db>, + ) -> EvaluationResult { + let trait_ref = TraitRef::new(self.interner, trait_def_id.into(), params); + + let obligation = traits::Obligation { + cause: traits::ObligationCause::dummy(), + param_env, + recursion_depth: 0, + predicate: trait_ref.upcast(self.interner), + }; + self.evaluate_obligation(&obligation) + } + /// Evaluate a given predicate, capturing overflow and propagating it back. fn evaluate_obligation(&self, obligation: &PredicateObligation<'db>) -> EvaluationResult { self.probe(|snapshot| { @@ -561,6 +618,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); @@ -680,80 +744,49 @@ impl<'db> InferCtxt<'db> { self.inner.borrow_mut().type_variables().num_vars() } - pub fn next_var_for_param(&self, id: GenericParamId) -> GenericArg<'db> { - match id { - GenericParamId::TypeParamId(_) => self.next_ty_var().into(), - GenericParamId::ConstParamId(_) => self.next_const_var().into(), - GenericParamId::LifetimeParamId(_) => self.next_region_var().into(), - } + pub fn next_ty_var(&self, span: Span) -> Ty<'db> { + let vid = self.next_ty_vid(span); + Ty::new_var(self.interner, vid) } - pub fn next_ty_var(&self) -> Ty<'db> { - self.next_ty_var_with_origin(TypeVariableOrigin { param_def_id: None }) + pub fn next_ty_vid(&self, span: Span) -> TyVid { + self.next_ty_var_id_in_universe(self.universe(), span) } - pub fn next_ty_vid(&self) -> TyVid { - self.inner - .borrow_mut() - .type_variables() - .new_var(self.universe(), TypeVariableOrigin { param_def_id: None }) + pub fn next_ty_var_id_in_universe(&self, universe: UniverseIndex, span: Span) -> TyVid { + self.inner.borrow_mut().type_variables().new_var(universe, span) } - pub fn next_ty_var_with_origin(&self, origin: TypeVariableOrigin) -> Ty<'db> { - let vid = self.inner.borrow_mut().type_variables().new_var(self.universe(), origin); + pub fn next_ty_var_in_universe(&self, universe: UniverseIndex, span: Span) -> Ty<'db> { + let vid = self.next_ty_var_id_in_universe(universe, span); Ty::new_var(self.interner, vid) } - pub fn next_ty_var_id_in_universe(&self, universe: UniverseIndex) -> TyVid { - let origin = TypeVariableOrigin { param_def_id: None }; - self.inner.borrow_mut().type_variables().new_var(universe, origin) - } - - pub fn next_ty_var_in_universe(&self, universe: UniverseIndex) -> Ty<'db> { - let vid = self.next_ty_var_id_in_universe(universe); - Ty::new_var(self.interner, vid) + pub fn next_const_var(&self, span: Span) -> Const<'db> { + let vid = self.next_const_vid(span); + Const::new_var(self.interner, vid) } - pub fn next_const_var(&self) -> Const<'db> { - self.next_const_var_with_origin(ConstVariableOrigin {}) + pub fn next_const_vid(&self, span: Span) -> ConstVid { + self.next_const_vid_in_universe(self.universe(), span) } - pub fn next_const_vid(&self) -> ConstVid { + pub fn next_const_vid_in_universe(&self, universe: UniverseIndex, span: Span) -> ConstVid { self.inner .borrow_mut() .const_unification_table() - .new_key(ConstVariableValue::Unknown { - origin: ConstVariableOrigin {}, - universe: self.universe(), - }) + .new_key(ConstVariableValue::Unknown { span, universe }) .vid } - pub fn next_const_var_with_origin(&self, origin: ConstVariableOrigin) -> Const<'db> { - let vid = self - .inner - .borrow_mut() - .const_unification_table() - .new_key(ConstVariableValue::Unknown { origin, universe: self.universe() }) - .vid; - Const::new_var(self.interner, vid) - } - - pub fn next_const_var_in_universe(&self, universe: UniverseIndex) -> Const<'db> { - let origin = ConstVariableOrigin {}; - let vid = self - .inner - .borrow_mut() - .const_unification_table() - .new_key(ConstVariableValue::Unknown { origin, universe }) - .vid; + pub fn next_const_var_in_universe(&self, universe: UniverseIndex, span: Span) -> Const<'db> { + let vid = self.next_const_vid_in_universe(universe, span); Const::new_var(self.interner, vid) } pub fn next_int_var(&self) -> Ty<'db> { - let next_int_var_id = - self.inner.borrow_mut().int_unification_table().new_key(IntVarValue::Unknown); - Ty::new_int_var(self.interner, next_int_var_id) + let vid = self.next_int_vid(); + Ty::new_int_var(self.interner, vid) } pub fn next_int_vid(&self) -> IntVid { @@ -771,27 +804,27 @@ impl<'db> InferCtxt<'db> { /// Creates a fresh region variable with the next available index. /// The variable will be created in the maximum universe created /// thus far, allowing it to name any region created thus far. - pub fn next_region_var(&self) -> Region<'db> { - self.next_region_var_in_universe(self.universe()) + pub fn next_region_var(&self, span: Span) -> Region<'db> { + self.next_region_var_in_universe(self.universe(), span) } - pub fn next_region_vid(&self) -> RegionVid { - self.inner.borrow_mut().unwrap_region_constraints().new_region_var(self.universe()) + pub fn next_region_vid(&self, span: Span) -> RegionVid { + self.inner.borrow_mut().unwrap_region_constraints().new_region_var(self.universe(), span) } /// Creates a fresh region variable with the next available index /// in the given universe; typically, you can use /// `next_region_var` and just use the maximal universe. - pub fn next_region_var_in_universe(&self, universe: UniverseIndex) -> Region<'db> { + pub fn next_region_var_in_universe(&self, universe: UniverseIndex, span: Span) -> Region<'db> { let region_var = - self.inner.borrow_mut().unwrap_region_constraints().new_region_var(universe); + self.inner.borrow_mut().unwrap_region_constraints().new_region_var(universe, span); Region::new_var(self.interner, region_var) } - pub fn next_term_var_of_kind(&self, term: Term<'db>) -> Term<'db> { + pub fn next_term_var_of_kind(&self, term: Term<'db>, span: Span) -> Term<'db> { match term.kind() { - TermKind::Ty(_) => self.next_ty_var().into(), - TermKind::Const(_) => self.next_const_var().into(), + TermKind::Ty(_) => self.next_ty_var(span).into(), + TermKind::Const(_) => self.next_const_var(span).into(), } } @@ -809,24 +842,12 @@ impl<'db> InferCtxt<'db> { self.inner.borrow_mut().unwrap_region_constraints().num_region_vars() } - /// Just a convenient wrapper of `next_region_var` for using during NLL. - #[instrument(skip(self), level = "debug")] - pub fn next_nll_region_var(&self) -> Region<'db> { - self.next_region_var() - } - - /// Just a convenient wrapper of `next_region_var` for using during NLL. - #[instrument(skip(self), level = "debug")] - pub fn next_nll_region_var_in_universe(&self, universe: UniverseIndex) -> Region<'db> { - self.next_region_var_in_universe(universe) - } - - fn var_for_def(&self, id: GenericParamId) -> GenericArg<'db> { + pub fn var_for_def(&self, id: GenericParamId, span: Span) -> GenericArg<'db> { match id { GenericParamId::LifetimeParamId(_) => { // Create a region inference variable for the given // region parameter definition. - self.next_region_var().into() + self.next_region_var(span).into() } GenericParamId::TypeParamId(_) => { // Create a type inference variable for the given @@ -837,41 +858,27 @@ impl<'db> InferCtxt<'db> { // used in a path such as `Foo::<T, U>::new()` will // use an inference variable for `C` with `[T, U]` // as the generic parameters for the default, `(T, U)`. - let ty_var_id = self - .inner - .borrow_mut() - .type_variables() - .new_var(self.universe(), TypeVariableOrigin { param_def_id: None }); - - Ty::new_var(self.interner, ty_var_id).into() - } - GenericParamId::ConstParamId(_) => { - let origin = ConstVariableOrigin {}; - let const_var_id = self - .inner - .borrow_mut() - .const_unification_table() - .new_key(ConstVariableValue::Unknown { origin, universe: self.universe() }) - .vid; - Const::new_var(self.interner, const_var_id).into() + self.next_ty_var(span).into() } + GenericParamId::ConstParamId(_) => self.next_const_var(span).into(), } } /// Given a set of generics defined on a type or impl, returns the generic parameters mapping /// each type/region parameter to a fresh inference variable. - pub fn fresh_args_for_item(&self, def_id: SolverDefId) -> GenericArgs<'db> { - GenericArgs::for_item(self.interner, def_id, |_index, kind, _| self.var_for_def(kind)) + pub fn fresh_args_for_item(&self, span: Span, def_id: SolverDefId) -> GenericArgs<'db> { + GenericArgs::for_item(self.interner, def_id, |_index, kind, _| self.var_for_def(kind, span)) } /// Like `fresh_args_for_item()`, but first uses the args from `first`. pub fn fill_rest_fresh_args( &self, + span: Span, def_id: SolverDefId, first: impl IntoIterator<Item = GenericArg<'db>>, ) -> GenericArgs<'db> { GenericArgs::fill_rest(self.interner, def_id, first, |_index, kind, _| { - self.var_for_def(kind) + self.var_for_def(kind, span) }) } @@ -922,7 +929,7 @@ impl<'db> InferCtxt<'db> { #[inline(always)] pub fn can_define_opaque_ty(&self, id: impl Into<SolverDefId>) -> bool { - match self.typing_mode_unchecked() { + match self.typing_mode_raw().assert_not_erased() { TypingMode::Analysis { defining_opaque_types_and_generators } => { defining_opaque_types_and_generators.contains(&id.into()) } @@ -938,8 +945,8 @@ impl<'db> InferCtxt<'db> { use self::type_variable::TypeVariableValue; match self.inner.borrow_mut().type_variables().probe(vid) { - TypeVariableValue::Known { value } => Ok(value), - TypeVariableValue::Unknown { universe } => Err(universe), + TypeVariableValue::Known { value, .. } => Ok(value), + TypeVariableValue::Unknown { universe, .. } => Err(universe), } } @@ -1007,6 +1014,13 @@ impl<'db> InferCtxt<'db> { } } + pub fn shallow_resolve_term(&self, term: Term<'db>) -> Term<'db> { + match term.kind() { + TermKind::Ty(ty) => self.shallow_resolve(ty).into(), + TermKind::Const(ct) => self.shallow_resolve_const(ct).into(), + } + } + pub fn root_var(&self, var: TyVid) -> TyVid { self.inner.borrow_mut().type_variables().root_var(var) } @@ -1084,7 +1098,22 @@ impl<'db> InferCtxt<'db> { pub fn probe_const_var(&self, vid: ConstVid) -> Result<Const<'db>, UniverseIndex> { match self.inner.borrow_mut().const_unification_table().probe_value(vid) { ConstVariableValue::Known { value } => Ok(value), - ConstVariableValue::Unknown { origin: _, universe } => Err(universe), + ConstVariableValue::Unknown { span: _, universe } => Err(universe), + } + } + + /// Returns the span of the type variable identified by `vid`. + /// + /// No attempt is made to resolve `vid` to its root variable. + pub fn type_var_span(&self, vid: TyVid) -> Span { + self.inner.borrow_mut().type_variables().var_span(vid) + } + + /// Returns the span of the const variable identified by `vid` + pub fn const_var_span(&self, vid: ConstVid) -> Option<Span> { + match self.inner.borrow_mut().const_unification_table().probe_value(vid) { + ConstVariableValue::Known { .. } => None, + ConstVariableValue::Unknown { span, .. } => Some(span), } } @@ -1097,6 +1126,7 @@ impl<'db> InferCtxt<'db> { // use [`InferCtxt::enter_forall`] instead. pub fn instantiate_binder_with_fresh_vars<T>( &self, + span: Span, _lbrct: BoundRegionConversionTime, value: Binder<'db, T>, ) -> T @@ -1112,9 +1142,9 @@ impl<'db> InferCtxt<'db> { for bound_var_kind in bound_vars { let arg: GenericArg<'db> = match bound_var_kind { - BoundVariableKind::Ty(_) => self.next_ty_var().into(), - BoundVariableKind::Region(_) => self.next_region_var().into(), - BoundVariableKind::Const => self.next_const_var().into(), + BoundVariableKind::Ty(_) => self.next_ty_var(span).into(), + BoundVariableKind::Region(_) => self.next_region_var(span).into(), + BoundVariableKind::Const => self.next_const_var(span).into(), }; args.push(arg); } @@ -1169,7 +1199,7 @@ impl<'db> InferCtxt<'db> { #[inline] pub fn is_ty_infer_var_definitely_unchanged<'a>( &'a self, - ) -> impl Fn(TyOrConstInferVar) -> bool + Captures<'db> + 'a { + ) -> impl Fn(TyOrConstInferVar) -> bool + use<'a, 'db> { // This hoists the borrow/release out of the loop body. let inner = self.inner.try_borrow(); @@ -1321,7 +1351,7 @@ impl TyOrConstInferVar { impl<'db> TypeTrace<'db> { pub fn types(cause: &ObligationCause, a: Ty<'db>, b: Ty<'db>) -> TypeTrace<'db> { TypeTrace { - cause: cause.clone(), + cause: *cause, values: ValuePairs::Terms(ExpectedFound::new(a.into(), b.into())), } } @@ -1331,12 +1361,12 @@ impl<'db> TypeTrace<'db> { a: TraitRef<'db>, b: TraitRef<'db>, ) -> TypeTrace<'db> { - TypeTrace { cause: cause.clone(), values: ValuePairs::TraitRefs(ExpectedFound::new(a, b)) } + TypeTrace { cause: *cause, values: ValuePairs::TraitRefs(ExpectedFound::new(a, b)) } } pub fn consts(cause: &ObligationCause, a: Const<'db>, b: Const<'db>) -> TypeTrace<'db> { TypeTrace { - cause: cause.clone(), + cause: *cause, values: ValuePairs::Terms(ExpectedFound::new(a.into(), b.into())), } } |