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.rs282
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())),
}
}