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.rs288
1 files changed, 239 insertions, 49 deletions
diff --git a/crates/hir-ty/src/next_solver/infer/mod.rs b/crates/hir-ty/src/next_solver/infer/mod.rs
index 8e922abacb..443191423a 100644
--- a/crates/hir-ty/src/next_solver/infer/mod.rs
+++ b/crates/hir-ty/src/next_solver/infer/mod.rs
@@ -6,53 +6,48 @@ use std::ops::Range;
use std::sync::Arc;
pub use BoundRegionConversionTime::*;
-pub use at::DefineOpaqueTypes;
-use ena::undo_log::UndoLogs;
use ena::unify as ut;
use hir_def::GenericParamId;
-use intern::Symbol;
use opaque_types::{OpaqueHiddenType, OpaqueTypeStorage};
-use region_constraints::{
- GenericKind, RegionConstraintCollector, RegionConstraintStorage, UndoLog, VarInfos, VerifyBound,
-};
-pub use relate::StructurallyRelateAliases;
-pub use relate::combine::PredicateEmittingRelation;
-use rustc_hash::{FxHashMap, FxHashSet};
+use region_constraints::{RegionConstraintCollector, RegionConstraintStorage};
+use rustc_next_trait_solver::solve::SolverDelegateEvalExt;
use rustc_pattern_analysis::Captures;
-use rustc_type_ir::error::{ExpectedFound, TypeError};
-use rustc_type_ir::inherent::{
- Const as _, GenericArg as _, GenericArgs as _, IntoKind, ParamEnv as _, SliceLike, Term as _,
- Ty as _,
-};
use rustc_type_ir::{
- BoundVar, ClosureKind, ConstVid, FloatTy, FloatVarValue, FloatVid, GenericArgKind, InferConst,
- InferTy, IntTy, IntVarValue, IntVid, OutlivesPredicate, RegionVid, TyVid, UniverseIndex,
+ ClosureKind, ConstVid, FloatVarValue, FloatVid, GenericArgKind, InferConst, InferTy,
+ IntVarValue, IntVid, OutlivesPredicate, RegionVid, TermKind, TyVid, TypeFoldable, TypeFolder,
+ TypeSuperFoldable, TypeVisitableExt, UniverseIndex,
+ error::{ExpectedFound, TypeError},
+ inherent::{
+ Const as _, GenericArg as _, GenericArgs as _, IntoKind, SliceLike, Term as _, Ty as _,
+ },
};
-use rustc_type_ir::{TermKind, TypeVisitableExt};
-use rustc_type_ir::{TypeFoldable, TypeFolder, TypeSuperFoldable};
use snapshot::undo_log::InferCtxtUndoLogs;
use tracing::{debug, instrument};
use traits::{ObligationCause, PredicateObligations};
use type_variable::TypeVariableOrigin;
use unify_key::{ConstVariableOrigin, ConstVariableValue, ConstVidKey};
-use crate::next_solver::fold::BoundVarReplacerDelegate;
-use crate::next_solver::infer::opaque_types::table::OpaqueTypeStorageEntries;
-use crate::next_solver::{BoundConst, BoundRegion, BoundTy, BoundVarKind};
+use crate::next_solver::{
+ ArgOutlivesPredicate, BoundConst, BoundRegion, BoundTy, BoundVarKind, Goal, Predicate,
+ SolverContext,
+ fold::BoundVarReplacerDelegate,
+ infer::{at::ToTrace, select::EvaluationResult, traits::PredicateObligation},
+ obligation_ctxt::ObligationCtxt,
+};
-use super::generics::GenericParamDef;
use super::{
- AliasTerm, Binder, BoundRegionKind, CanonicalQueryInput, CanonicalVarValues, Const, ConstKind,
- DbInterner, ErrorGuaranteed, FxIndexMap, GenericArg, GenericArgs, OpaqueTypeKey, ParamEnv,
- PlaceholderRegion, PolyCoercePredicate, PolyExistentialProjection, PolyExistentialTraitRef,
- PolyFnSig, PolyRegionOutlivesPredicate, PolySubtypePredicate, Predicate, Region, SolverDefId,
- SubtypePredicate, Term, TraitPredicate, TraitRef, Ty, TyKind, TypingMode,
+ AliasTerm, Binder, CanonicalQueryInput, CanonicalVarValues, Const, ConstKind, DbInterner,
+ ErrorGuaranteed, GenericArg, GenericArgs, OpaqueTypeKey, ParamEnv, PolyCoercePredicate,
+ PolyExistentialProjection, PolyExistentialTraitRef, PolyFnSig, PolyRegionOutlivesPredicate,
+ PolySubtypePredicate, Region, SolverDefId, SubtypePredicate, Term, TraitRef, Ty, TyKind,
+ TypingMode,
};
pub mod at;
pub mod canonical;
mod context;
-mod opaque_types;
+pub mod opaque_types;
+mod outlives;
pub mod region_constraints;
pub mod relate;
pub mod resolve;
@@ -62,7 +57,7 @@ pub(crate) mod traits;
mod type_variable;
mod unify_key;
-/// `InferOk<'tcx, ()>` is used a lot. It may seem like a useless wrapper
+/// `InferOk<'db, ()>` is used a lot. It may seem like a useless wrapper
/// around `PredicateObligations`, but it has one important property:
/// because `InferOk` is marked with `#[must_use]`, if you have a method
/// `InferCtxt::f` that returns `InferResult<()>` and you call it with
@@ -77,8 +72,6 @@ pub struct InferOk<'db, T> {
}
pub type InferResult<'db, T> = Result<InferOk<'db, T>, TypeError<DbInterner<'db>>>;
-pub(crate) type FixupResult<T> = Result<T, FixupError>; // "fixup result"
-
pub(crate) type UnificationTable<'a, 'db, T> = ut::UnificationTable<
ut::InPlace<T, &'a mut ut::UnificationStorage<T>, &'a mut InferCtxtUndoLogs<'db>>,
>;
@@ -149,7 +142,14 @@ pub struct InferCtxtInner<'db> {
/// for each body-id in this map, which will process the
/// obligations within. This is expected to be done 'late enough'
/// that all type inference variables have been bound and so forth.
- pub(crate) region_obligations: Vec<RegionObligation<'db>>,
+ pub(crate) region_obligations: Vec<TypeOutlivesConstraint<'db>>,
+
+ /// The outlives bounds that we assume must hold about placeholders that
+ /// come from instantiating the binder of coroutine-witnesses. These bounds
+ /// are deduced from the well-formedness of the witness's types, and are
+ /// necessary because of the way we anonymize the regions in a coroutine,
+ /// which may cause types to no longer be considered well-formed.
+ region_assumptions: Vec<ArgOutlivesPredicate<'db>>,
/// Caches for opaque type inference.
pub(crate) opaque_type_storage: OpaqueTypeStorage<'db>,
@@ -166,12 +166,13 @@ impl<'db> InferCtxtInner<'db> {
float_unification_storage: Default::default(),
region_constraint_storage: Some(Default::default()),
region_obligations: vec![],
+ region_assumptions: Default::default(),
opaque_type_storage: Default::default(),
}
}
#[inline]
- pub fn region_obligations(&self) -> &[RegionObligation<'db>] {
+ pub fn region_obligations(&self) -> &[TypeOutlivesConstraint<'db>] {
&self.region_obligations
}
@@ -326,7 +327,7 @@ impl fmt::Display for FixupError {
/// See the `region_obligations` field for more information.
#[derive(Clone, Debug)]
-pub struct RegionObligation<'db> {
+pub struct TypeOutlivesConstraint<'db> {
pub sub_region: Region<'db>,
pub sup_type: Ty<'db>,
}
@@ -395,6 +396,162 @@ impl<'db> InferCtxt<'db> {
self.typing_mode
}
+ /// Evaluates whether the predicate can be satisfied (by any means)
+ /// in the given `ParamEnv`.
+ pub fn predicate_may_hold(&self, obligation: &PredicateObligation<'db>) -> bool {
+ self.evaluate_obligation(obligation).may_apply()
+ }
+
+ /// See the comment on [OpaqueTypesJank](crate::solve::OpaqueTypesJank)
+ /// for more details.
+ pub fn predicate_may_hold_opaque_types_jank(
+ &self,
+ obligation: &PredicateObligation<'db>,
+ ) -> bool {
+ <&SolverContext<'db>>::from(self).root_goal_may_hold_opaque_types_jank(Goal::new(
+ self.interner,
+ obligation.param_env,
+ obligation.predicate,
+ ))
+ }
+
+ pub(crate) fn insert_type_vars<T>(&self, ty: T) -> T
+ where
+ T: TypeFoldable<DbInterner<'db>>,
+ {
+ struct Folder<'a, 'db> {
+ infcx: &'a InferCtxt<'db>,
+ }
+ impl<'db> TypeFolder<DbInterner<'db>> for Folder<'_, 'db> {
+ fn cx(&self) -> DbInterner<'db> {
+ self.infcx.interner
+ }
+
+ fn fold_ty(&mut self, ty: Ty<'db>) -> Ty<'db> {
+ if !ty.references_error() {
+ return ty;
+ }
+
+ if ty.is_ty_error() { self.infcx.next_ty_var() } else { ty.super_fold_with(self) }
+ }
+
+ fn fold_const(&mut self, ct: Const<'db>) -> Const<'db> {
+ if !ct.references_error() {
+ return ct;
+ }
+
+ if ct.is_ct_error() {
+ self.infcx.next_const_var()
+ } 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 }
+ }
+ }
+
+ ty.fold_with(&mut Folder { infcx: self })
+ }
+
+ /// Evaluates whether the predicate can be satisfied in the given
+ /// `ParamEnv`, and returns `false` if not certain. However, this is
+ /// not entirely accurate if inference variables are involved.
+ ///
+ /// This version may conservatively fail when outlives obligations
+ /// are required. Therefore, this version should only be used for
+ /// optimizations or diagnostics and be treated as if it can always
+ /// return `false`.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// # #![allow(dead_code)]
+ /// trait Trait {}
+ ///
+ /// fn check<T: Trait>() {}
+ ///
+ /// fn foo<T: 'static>()
+ /// where
+ /// &'static T: Trait,
+ /// {
+ /// // Evaluating `&'?0 T: Trait` adds a `'?0: 'static` outlives obligation,
+ /// // which means that `predicate_must_hold_considering_regions` will return
+ /// // `false`.
+ /// check::<&'_ T>();
+ /// }
+ /// ```
+ #[expect(dead_code, reason = "this is used in rustc")]
+ fn predicate_must_hold_considering_regions(
+ &self,
+ obligation: &PredicateObligation<'db>,
+ ) -> bool {
+ self.evaluate_obligation(obligation).must_apply_considering_regions()
+ }
+
+ /// Evaluates whether the predicate can be satisfied in the given
+ /// `ParamEnv`, and returns `false` if not certain. However, this is
+ /// 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 {
+ self.evaluate_obligation(obligation).must_apply_modulo_regions()
+ }
+
+ /// Evaluate a given predicate, capturing overflow and propagating it back.
+ fn evaluate_obligation(&self, obligation: &PredicateObligation<'db>) -> EvaluationResult {
+ self.probe(|snapshot| {
+ let mut ocx = ObligationCtxt::new(self);
+ ocx.register_obligation(obligation.clone());
+ let mut result = EvaluationResult::EvaluatedToOk;
+ for error in ocx.evaluate_obligations_error_on_ambiguity() {
+ if error.is_true_error() {
+ return EvaluationResult::EvaluatedToErr;
+ } else {
+ result = result.max(EvaluationResult::EvaluatedToAmbig);
+ }
+ }
+ if self.opaque_types_added_in_snapshot(snapshot) {
+ result = result.max(EvaluationResult::EvaluatedToOkModuloOpaqueTypes);
+ } else if self.region_constraints_added_in_snapshot(snapshot) {
+ result = result.max(EvaluationResult::EvaluatedToOkModuloRegions);
+ }
+ result
+ })
+ }
+
+ pub fn can_eq<T: ToTrace<'db>>(&self, param_env: ParamEnv<'db>, a: T, b: T) -> bool {
+ self.probe(|_| {
+ let mut ocx = ObligationCtxt::new(self);
+ let Ok(()) = ocx.eq(&ObligationCause::dummy(), param_env, a, b) else {
+ return false;
+ };
+ ocx.try_evaluate_obligations().is_empty()
+ })
+ }
+
+ /// See the comment on [OpaqueTypesJank](crate::solve::OpaqueTypesJank)
+ /// for more details.
+ pub fn goal_may_hold_opaque_types_jank(&self, goal: Goal<'db, Predicate<'db>>) -> bool {
+ <&SolverContext<'db>>::from(self).root_goal_may_hold_opaque_types_jank(goal)
+ }
+
+ pub fn type_is_copy_modulo_regions(&self, param_env: ParamEnv<'db>, ty: Ty<'db>) -> bool {
+ let ty = self.resolve_vars_if_possible(ty);
+
+ let Some(copy_def_id) = self.interner.lang_items().Copy else {
+ return false;
+ };
+
+ // This can get called from typeck (by euv), and `moves_by_default`
+ // rightly refuses to work with inference variables, but
+ // moves_by_default has a cache, which we want to use in other
+ // cases.
+ traits::type_known_to_meet_bound_modulo_regions(self, param_env, ty, copy_def_id)
+ }
+
pub fn unresolved_variables(&self) -> Vec<Ty<'db>> {
let mut inner = self.inner.borrow_mut();
let mut vars: Vec<Ty<'db>> = inner
@@ -482,16 +639,16 @@ impl<'db> InferCtxt<'db> {
self.enter_forall(predicate, |SubtypePredicate { a_is_expected, a, b }| {
if a_is_expected {
- Ok(self.at(cause, param_env).sub(DefineOpaqueTypes::Yes, a, b))
+ Ok(self.at(cause, param_env).sub(a, b))
} else {
- Ok(self.at(cause, param_env).sup(DefineOpaqueTypes::Yes, b, a))
+ Ok(self.at(cause, param_env).sup(b, a))
}
})
}
pub fn region_outlives_predicate(
&self,
- cause: &traits::ObligationCause,
+ _cause: &traits::ObligationCause,
predicate: PolyRegionOutlivesPredicate<'db>,
) {
self.enter_forall(predicate, |OutlivesPredicate(r_a, r_b)| {
@@ -504,6 +661,14 @@ 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) -> Ty<'db> {
self.next_ty_var_with_origin(TypeVariableOrigin { param_def_id: None })
}
@@ -531,7 +696,7 @@ impl<'db> InferCtxt<'db> {
}
pub fn next_const_var(&self) -> Const<'db> {
- self.next_const_var_with_origin(ConstVariableOrigin { param_def_id: None })
+ self.next_const_var_with_origin(ConstVariableOrigin {})
}
pub fn next_const_vid(&self) -> ConstVid {
@@ -539,7 +704,7 @@ impl<'db> InferCtxt<'db> {
.borrow_mut()
.const_unification_table()
.new_key(ConstVariableValue::Unknown {
- origin: ConstVariableOrigin { param_def_id: None },
+ origin: ConstVariableOrigin {},
universe: self.universe(),
})
.vid
@@ -556,7 +721,7 @@ impl<'db> InferCtxt<'db> {
}
pub fn next_const_var_in_universe(&self, universe: UniverseIndex) -> Const<'db> {
- let origin = ConstVariableOrigin { param_def_id: None };
+ let origin = ConstVariableOrigin {};
let vid = self
.inner
.borrow_mut()
@@ -637,7 +802,7 @@ impl<'db> InferCtxt<'db> {
self.next_region_var_in_universe(universe)
}
- fn var_for_def(&self, id: GenericParamId, name: &Symbol) -> GenericArg<'db> {
+ fn var_for_def(&self, id: GenericParamId) -> GenericArg<'db> {
match id {
GenericParamId::LifetimeParamId(_) => {
// Create a region inference variable for the given
@@ -662,7 +827,7 @@ impl<'db> InferCtxt<'db> {
Ty::new_var(self.interner, ty_var_id).into()
}
GenericParamId::ConstParamId(_) => {
- let origin = ConstVariableOrigin { param_def_id: None };
+ let origin = ConstVariableOrigin {};
let const_var_id = self
.inner
.borrow_mut()
@@ -677,8 +842,17 @@ impl<'db> InferCtxt<'db> {
/// 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, |name, index, kind, _| {
- self.var_for_def(kind, name)
+ GenericArgs::for_item(self.interner, def_id, |_index, kind, _| self.var_for_def(kind))
+ }
+
+ /// Like `fresh_args_for_item()`, but first uses the args from `first`.
+ pub fn fill_rest_fresh_args(
+ &self,
+ 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)
})
}
@@ -709,6 +883,22 @@ impl<'db> InferCtxt<'db> {
self.inner.borrow_mut().opaque_type_storage.iter_opaque_types().collect()
}
+ pub fn has_opaques_with_sub_unified_hidden_type(&self, ty_vid: TyVid) -> bool {
+ let ty_sub_vid = self.sub_unification_table_root_var(ty_vid);
+ let inner = &mut *self.inner.borrow_mut();
+ let mut type_variables = inner.type_variable_storage.with_log(&mut inner.undo_log);
+ inner.opaque_type_storage.iter_opaque_types().any(|(_, hidden_ty)| {
+ if let TyKind::Infer(InferTy::TyVar(hidden_vid)) = hidden_ty.ty.kind() {
+ let opaque_sub_vid = type_variables.sub_unification_table_root_var(hidden_vid);
+ if opaque_sub_vid == ty_sub_vid {
+ return true;
+ }
+ }
+
+ false
+ })
+ }
+
#[inline(always)]
pub fn can_define_opaque_ty(&self, id: impl Into<SolverDefId>) -> bool {
match self.typing_mode_unchecked() {
@@ -716,8 +906,8 @@ impl<'db> InferCtxt<'db> {
defining_opaque_types_and_generators.contains(&id.into())
}
TypingMode::Coherence | TypingMode::PostAnalysis => false,
- TypingMode::Borrowck { defining_opaque_types } => unimplemented!(),
- TypingMode::PostBorrowckAnalysis { defined_opaque_types } => unimplemented!(),
+ TypingMode::Borrowck { defining_opaque_types: _ } => unimplemented!(),
+ TypingMode::PostBorrowckAnalysis { defined_opaque_types: _ } => unimplemented!(),
}
}
@@ -886,7 +1076,7 @@ impl<'db> InferCtxt<'db> {
// use [`InferCtxt::enter_forall`] instead.
pub fn instantiate_binder_with_fresh_vars<T>(
&self,
- lbrct: BoundRegionConversionTime,
+ _lbrct: BoundRegionConversionTime,
value: Binder<'db, T>,
) -> T
where
@@ -902,7 +1092,7 @@ impl<'db> InferCtxt<'db> {
for bound_var_kind in bound_vars {
let arg: GenericArg<'db> = match bound_var_kind {
BoundVarKind::Ty(_) => self.next_ty_var().into(),
- BoundVarKind::Region(br) => self.next_region_var().into(),
+ BoundVarKind::Region(_) => self.next_region_var().into(),
BoundVarKind::Const => self.next_const_var().into(),
};
args.push(arg);
@@ -958,7 +1148,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 + Captures<'db> + 'a {
// This hoists the borrow/release out of the loop body.
let inner = self.inner.try_borrow();