TypingMode 🤔
This commit is contained in:
parent
2dece5bb62
commit
f51ec110a7
75 changed files with 513 additions and 506 deletions
|
@ -28,7 +28,7 @@
|
|||
use relate::lattice::{LatticeOp, LatticeOpKind};
|
||||
use rustc_middle::bug;
|
||||
use rustc_middle::ty::relate::solver_relating::RelateExt as NextSolverRelate;
|
||||
use rustc_middle::ty::{Const, ImplSubject};
|
||||
use rustc_middle::ty::{Const, ImplSubject, TypingMode};
|
||||
|
||||
use super::*;
|
||||
use crate::infer::relate::type_relating::TypeRelating;
|
||||
|
@ -67,16 +67,9 @@ impl<'tcx> InferCtxt<'tcx> {
|
|||
/// variables in the same state. This can be used to "branch off" many tests from the same
|
||||
/// common state.
|
||||
pub fn fork(&self) -> Self {
|
||||
self.fork_with_intercrate(self.intercrate)
|
||||
}
|
||||
|
||||
/// Forks the inference context, creating a new inference context with the same inference
|
||||
/// variables in the same state, except possibly changing the intercrate mode. This can be
|
||||
/// used to "branch off" many tests from the same common state. Used in negative coherence.
|
||||
pub fn fork_with_intercrate(&self, intercrate: bool) -> Self {
|
||||
Self {
|
||||
tcx: self.tcx,
|
||||
defining_opaque_types: self.defining_opaque_types,
|
||||
typing_mode: self.typing_mode,
|
||||
considering_regions: self.considering_regions,
|
||||
skip_leak_check: self.skip_leak_check,
|
||||
inner: self.inner.clone(),
|
||||
|
@ -87,11 +80,36 @@ impl<'tcx> InferCtxt<'tcx> {
|
|||
reported_signature_mismatch: self.reported_signature_mismatch.clone(),
|
||||
tainted_by_errors: self.tainted_by_errors.clone(),
|
||||
universe: self.universe.clone(),
|
||||
intercrate,
|
||||
next_trait_solver: self.next_trait_solver,
|
||||
obligation_inspector: self.obligation_inspector.clone(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Forks the inference context, creating a new inference context with the same inference
|
||||
/// variables in the same state, except possibly changing the intercrate mode. This can be
|
||||
/// used to "branch off" many tests from the same common state. Used in negative coherence.
|
||||
pub fn fork_with_typing_mode(&self, typing_mode: TypingMode<'tcx>) -> Self {
|
||||
// Unlike `fork`, this invalidates all cache entries as they may depend on the
|
||||
// typing mode.
|
||||
let forked = Self {
|
||||
tcx: self.tcx,
|
||||
typing_mode,
|
||||
considering_regions: self.considering_regions,
|
||||
skip_leak_check: self.skip_leak_check,
|
||||
inner: self.inner.clone(),
|
||||
lexical_region_resolutions: self.lexical_region_resolutions.clone(),
|
||||
selection_cache: Default::default(),
|
||||
evaluation_cache: Default::default(),
|
||||
reported_trait_errors: self.reported_trait_errors.clone(),
|
||||
reported_signature_mismatch: self.reported_signature_mismatch.clone(),
|
||||
tainted_by_errors: self.tainted_by_errors.clone(),
|
||||
universe: self.universe.clone(),
|
||||
next_trait_solver: self.next_trait_solver,
|
||||
obligation_inspector: self.obligation_inspector.clone(),
|
||||
};
|
||||
forked.inner.borrow_mut().projection_cache().clear();
|
||||
forked
|
||||
}
|
||||
}
|
||||
|
||||
pub trait ToTrace<'tcx>: Relate<TyCtxt<'tcx>> + Copy {
|
||||
|
|
|
@ -46,7 +46,7 @@ impl<'tcx> InferCtxt<'tcx> {
|
|||
V: TypeFoldable<TyCtxt<'tcx>>,
|
||||
{
|
||||
let (param_env, value) = value.into_parts();
|
||||
let param_env = self.tcx.canonical_param_env_cache.get_or_insert(
|
||||
let canonical_param_env = self.tcx.canonical_param_env_cache.get_or_insert(
|
||||
self.tcx,
|
||||
param_env,
|
||||
query_state,
|
||||
|
@ -64,7 +64,7 @@ impl<'tcx> InferCtxt<'tcx> {
|
|||
);
|
||||
|
||||
let canonical = Canonicalizer::canonicalize_with_base(
|
||||
param_env,
|
||||
canonical_param_env,
|
||||
value,
|
||||
Some(self),
|
||||
self.tcx,
|
||||
|
@ -72,7 +72,7 @@ impl<'tcx> InferCtxt<'tcx> {
|
|||
query_state,
|
||||
)
|
||||
.unchecked_map(|(param_env, value)| param_env.and(value));
|
||||
CanonicalQueryInput { canonical, defining_opaque_types: self.defining_opaque_types() }
|
||||
CanonicalQueryInput { canonical, typing_mode: self.typing_mode(param_env) }
|
||||
}
|
||||
|
||||
/// Canonicalizes a query *response* `V`. When we canonicalize a
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
///! Definition of `InferCtxtLike` from the librarified type layer.
|
||||
use rustc_hir::def_id::{DefId, LocalDefId};
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_middle::traits::ObligationCause;
|
||||
use rustc_middle::traits::solve::SolverMode;
|
||||
use rustc_middle::ty::fold::TypeFoldable;
|
||||
use rustc_middle::ty::relate::RelateResult;
|
||||
use rustc_middle::ty::relate::combine::PredicateEmittingRelation;
|
||||
|
@ -21,11 +20,11 @@ impl<'tcx> rustc_type_ir::InferCtxtLike for InferCtxt<'tcx> {
|
|||
self.next_trait_solver
|
||||
}
|
||||
|
||||
fn solver_mode(&self) -> ty::solve::SolverMode {
|
||||
match self.intercrate {
|
||||
true => SolverMode::Coherence,
|
||||
false => SolverMode::Normal,
|
||||
}
|
||||
fn typing_mode(
|
||||
&self,
|
||||
param_env_for_debug_assertion: ty::ParamEnv<'tcx>,
|
||||
) -> ty::TypingMode<'tcx> {
|
||||
self.typing_mode(param_env_for_debug_assertion)
|
||||
}
|
||||
|
||||
fn universe(&self) -> ty::UniverseIndex {
|
||||
|
@ -91,10 +90,6 @@ impl<'tcx> rustc_type_ir::InferCtxtLike for InferCtxt<'tcx> {
|
|||
self.inner.borrow_mut().unwrap_region_constraints().opportunistic_resolve_var(self.tcx, vid)
|
||||
}
|
||||
|
||||
fn defining_opaque_types(&self) -> &'tcx ty::List<LocalDefId> {
|
||||
self.defining_opaque_types()
|
||||
}
|
||||
|
||||
fn next_ty_infer(&self) -> Ty<'tcx> {
|
||||
self.next_ty_var(DUMMY_SP)
|
||||
}
|
||||
|
|
|
@ -38,11 +38,12 @@ use rustc_middle::ty::fold::{
|
|||
use rustc_middle::ty::visit::TypeVisitableExt;
|
||||
use rustc_middle::ty::{
|
||||
self, ConstVid, FloatVid, GenericArg, GenericArgKind, GenericArgs, GenericArgsRef,
|
||||
GenericParamDefKind, InferConst, IntVid, Ty, TyCtxt, TyVid,
|
||||
GenericParamDefKind, InferConst, IntVid, Ty, TyCtxt, TyVid, TypingMode,
|
||||
};
|
||||
use rustc_middle::{bug, span_bug};
|
||||
use rustc_span::Span;
|
||||
use rustc_span::symbol::Symbol;
|
||||
use rustc_type_ir::solve::Reveal;
|
||||
use snapshot::undo_log::InferCtxtUndoLogs;
|
||||
use tracing::{debug, instrument};
|
||||
use type_variable::TypeVariableOrigin;
|
||||
|
@ -243,8 +244,9 @@ impl<'tcx> InferCtxtInner<'tcx> {
|
|||
pub struct InferCtxt<'tcx> {
|
||||
pub tcx: TyCtxt<'tcx>,
|
||||
|
||||
/// The `DefIds` of the opaque types that may have their hidden types constrained.
|
||||
defining_opaque_types: &'tcx ty::List<LocalDefId>,
|
||||
/// The mode of this inference context, see the struct documentation
|
||||
/// for more details.
|
||||
typing_mode: TypingMode<'tcx>,
|
||||
|
||||
/// Whether this inference context should care about region obligations in
|
||||
/// the root universe. Most notably, this is used during hir typeck as region
|
||||
|
@ -296,26 +298,6 @@ pub struct InferCtxt<'tcx> {
|
|||
/// bound.
|
||||
universe: Cell<ty::UniverseIndex>,
|
||||
|
||||
/// During coherence we have to assume that other crates may add
|
||||
/// additional impls which we currently don't know about.
|
||||
///
|
||||
/// To deal with this evaluation, we should be conservative
|
||||
/// and consider the possibility of impls from outside this crate.
|
||||
/// This comes up primarily when resolving ambiguity. Imagine
|
||||
/// there is some trait reference `$0: Bar` where `$0` is an
|
||||
/// inference variable. If `intercrate` is true, then we can never
|
||||
/// say for sure that this reference is not implemented, even if
|
||||
/// there are *no impls at all for `Bar`*, because `$0` could be
|
||||
/// bound to some type that in a downstream crate that implements
|
||||
/// `Bar`.
|
||||
///
|
||||
/// Outside of coherence, we set this to false because we are only
|
||||
/// interested in types that the user could actually have written.
|
||||
/// In other words, we consider `$0: Bar` to be unimplemented if
|
||||
/// there is no type that the user could *actually name* that
|
||||
/// would satisfy it. This avoids crippling inference, basically.
|
||||
pub intercrate: bool,
|
||||
|
||||
next_trait_solver: bool,
|
||||
|
||||
pub obligation_inspector: Cell<Option<ObligationInspector<'tcx>>>,
|
||||
|
@ -529,11 +511,8 @@ pub struct RegionObligation<'tcx> {
|
|||
/// Used to configure inference contexts before their creation.
|
||||
pub struct InferCtxtBuilder<'tcx> {
|
||||
tcx: TyCtxt<'tcx>,
|
||||
defining_opaque_types: &'tcx ty::List<LocalDefId>,
|
||||
considering_regions: bool,
|
||||
skip_leak_check: bool,
|
||||
/// Whether we are in coherence mode.
|
||||
intercrate: bool,
|
||||
/// Whether we should use the new trait solver in the local inference context,
|
||||
/// which affects things like which solver is used in `predicate_may_hold`.
|
||||
next_trait_solver: bool,
|
||||
|
@ -544,37 +523,19 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
fn infer_ctxt(self) -> InferCtxtBuilder<'tcx> {
|
||||
InferCtxtBuilder {
|
||||
tcx: self,
|
||||
defining_opaque_types: ty::List::empty(),
|
||||
considering_regions: true,
|
||||
skip_leak_check: false,
|
||||
intercrate: false,
|
||||
next_trait_solver: self.next_trait_solver_globally(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> InferCtxtBuilder<'tcx> {
|
||||
/// Whenever the `InferCtxt` should be able to handle defining uses of opaque types,
|
||||
/// you need to call this function. Otherwise the opaque type will be treated opaquely.
|
||||
///
|
||||
/// It is only meant to be called in two places, for typeck
|
||||
/// (via `Inherited::build`) and for the inference context used
|
||||
/// in mir borrowck.
|
||||
pub fn with_opaque_type_inference(mut self, defining_anchor: LocalDefId) -> Self {
|
||||
self.defining_opaque_types = self.tcx.opaque_types_defined_by(defining_anchor);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_next_trait_solver(mut self, next_trait_solver: bool) -> Self {
|
||||
self.next_trait_solver = next_trait_solver;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn intercrate(mut self, intercrate: bool) -> Self {
|
||||
self.intercrate = intercrate;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn ignoring_regions(mut self) -> Self {
|
||||
self.considering_regions = false;
|
||||
self
|
||||
|
@ -600,24 +561,17 @@ impl<'tcx> InferCtxtBuilder<'tcx> {
|
|||
where
|
||||
T: TypeFoldable<TyCtxt<'tcx>>,
|
||||
{
|
||||
self.defining_opaque_types = input.defining_opaque_types;
|
||||
let infcx = self.build();
|
||||
let infcx = self.build(input.typing_mode);
|
||||
let (value, args) = infcx.instantiate_canonical(span, &input.canonical);
|
||||
(infcx, value, args)
|
||||
}
|
||||
|
||||
pub fn build(&mut self) -> InferCtxt<'tcx> {
|
||||
let InferCtxtBuilder {
|
||||
tcx,
|
||||
defining_opaque_types,
|
||||
considering_regions,
|
||||
skip_leak_check,
|
||||
intercrate,
|
||||
next_trait_solver,
|
||||
} = *self;
|
||||
pub fn build(&mut self, typing_mode: TypingMode<'tcx>) -> InferCtxt<'tcx> {
|
||||
let InferCtxtBuilder { tcx, considering_regions, skip_leak_check, next_trait_solver } =
|
||||
*self;
|
||||
InferCtxt {
|
||||
tcx,
|
||||
defining_opaque_types,
|
||||
typing_mode,
|
||||
considering_regions,
|
||||
skip_leak_check,
|
||||
inner: RefCell::new(InferCtxtInner::new()),
|
||||
|
@ -628,7 +582,6 @@ impl<'tcx> InferCtxtBuilder<'tcx> {
|
|||
reported_signature_mismatch: Default::default(),
|
||||
tainted_by_errors: Cell::new(None),
|
||||
universe: Cell::new(ty::UniverseIndex::ROOT),
|
||||
intercrate,
|
||||
next_trait_solver,
|
||||
obligation_inspector: Cell::new(None),
|
||||
}
|
||||
|
@ -659,14 +612,30 @@ impl<'tcx> InferCtxt<'tcx> {
|
|||
self.tcx.dcx().taintable_handle(&self.tainted_by_errors)
|
||||
}
|
||||
|
||||
pub fn defining_opaque_types(&self) -> &'tcx ty::List<LocalDefId> {
|
||||
self.defining_opaque_types
|
||||
}
|
||||
|
||||
pub fn next_trait_solver(&self) -> bool {
|
||||
self.next_trait_solver
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn typing_mode(
|
||||
&self,
|
||||
param_env_for_debug_assertion: ty::ParamEnv<'tcx>,
|
||||
) -> TypingMode<'tcx> {
|
||||
if cfg!(debug_assertions) {
|
||||
match (param_env_for_debug_assertion.reveal(), self.typing_mode) {
|
||||
(Reveal::All, TypingMode::PostAnalysis)
|
||||
| (Reveal::UserFacing, TypingMode::Coherence | TypingMode::Analysis { .. }) => {}
|
||||
(r, t) => unreachable!("TypingMode x Reveal mismatch: {r:?} {t:?}"),
|
||||
}
|
||||
}
|
||||
self.typing_mode
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn typing_mode_unchecked(&self) -> TypingMode<'tcx> {
|
||||
self.typing_mode
|
||||
}
|
||||
|
||||
pub fn freshen<T: TypeFoldable<TyCtxt<'tcx>>>(&self, t: T) -> T {
|
||||
t.fold_with(&mut self.freshener())
|
||||
}
|
||||
|
@ -1029,8 +998,12 @@ impl<'tcx> InferCtxt<'tcx> {
|
|||
|
||||
#[inline(always)]
|
||||
pub fn can_define_opaque_ty(&self, id: impl Into<DefId>) -> bool {
|
||||
let Some(id) = id.into().as_local() else { return false };
|
||||
self.defining_opaque_types.contains(&id)
|
||||
match self.typing_mode_unchecked() {
|
||||
TypingMode::Analysis { defining_opaque_types } => {
|
||||
id.into().as_local().is_some_and(|def_id| defining_opaque_types.contains(&def_id))
|
||||
}
|
||||
TypingMode::Coherence | TypingMode::PostAnalysis => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn ty_to_string(&self, t: Ty<'tcx>) -> String {
|
||||
|
|
|
@ -2,6 +2,7 @@ use hir::def_id::{DefId, LocalDefId};
|
|||
use rustc_data_structures::fx::FxIndexMap;
|
||||
use rustc_data_structures::sync::Lrc;
|
||||
use rustc_hir as hir;
|
||||
use rustc_middle::bug;
|
||||
use rustc_middle::traits::ObligationCause;
|
||||
use rustc_middle::traits::solve::Goal;
|
||||
use rustc_middle::ty::error::{ExpectedFound, TypeError};
|
||||
|
@ -100,7 +101,7 @@ impl<'tcx> InferCtxt<'tcx> {
|
|||
let process = |a: Ty<'tcx>, b: Ty<'tcx>| match *a.kind() {
|
||||
ty::Alias(ty::Opaque, ty::AliasTy { def_id, args, .. }) if def_id.is_local() => {
|
||||
let def_id = def_id.expect_local();
|
||||
if self.intercrate {
|
||||
if let ty::TypingMode::Coherence = self.typing_mode(param_env) {
|
||||
// See comment on `insert_hidden_type` for why this is sufficient in coherence
|
||||
return Some(self.register_hidden_type(
|
||||
OpaqueTypeKey { def_id, args },
|
||||
|
@ -519,28 +520,32 @@ impl<'tcx> InferCtxt<'tcx> {
|
|||
// value being folded. In simple cases like `-> impl Foo`,
|
||||
// these are the same span, but not in cases like `-> (impl
|
||||
// Foo, impl Bar)`.
|
||||
if self.intercrate {
|
||||
// During intercrate we do not define opaque types but instead always
|
||||
// force ambiguity unless the hidden type is known to not implement
|
||||
// our trait.
|
||||
goals.push(Goal::new(self.tcx, param_env, ty::PredicateKind::Ambiguous))
|
||||
} else {
|
||||
let prev = self
|
||||
.inner
|
||||
.borrow_mut()
|
||||
.opaque_types()
|
||||
.register(opaque_type_key, OpaqueHiddenType { ty: hidden_ty, span });
|
||||
if let Some(prev) = prev {
|
||||
goals.extend(
|
||||
self.at(&ObligationCause::dummy_with_span(span), param_env)
|
||||
.eq(DefineOpaqueTypes::Yes, prev, hidden_ty)?
|
||||
.obligations
|
||||
.into_iter()
|
||||
// FIXME: Shuttling between obligations and goals is awkward.
|
||||
.map(Goal::from),
|
||||
);
|
||||
match self.typing_mode(param_env) {
|
||||
ty::TypingMode::Coherence => {
|
||||
// During intercrate we do not define opaque types but instead always
|
||||
// force ambiguity unless the hidden type is known to not implement
|
||||
// our trait.
|
||||
goals.push(Goal::new(self.tcx, param_env, ty::PredicateKind::Ambiguous));
|
||||
}
|
||||
};
|
||||
ty::TypingMode::Analysis { .. } => {
|
||||
let prev = self
|
||||
.inner
|
||||
.borrow_mut()
|
||||
.opaque_types()
|
||||
.register(opaque_type_key, OpaqueHiddenType { ty: hidden_ty, span });
|
||||
if let Some(prev) = prev {
|
||||
goals.extend(
|
||||
self.at(&ObligationCause::dummy_with_span(span), param_env)
|
||||
.eq(DefineOpaqueTypes::Yes, prev, hidden_ty)?
|
||||
.obligations
|
||||
.into_iter()
|
||||
// FIXME: Shuttling between obligations and goals is awkward.
|
||||
.map(Goal::from),
|
||||
);
|
||||
}
|
||||
}
|
||||
ty::TypingMode::PostAnalysis => bug!("insert hidden type post-analysis"),
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@ use rustc_middle::ty::error::TypeError;
|
|||
use rustc_middle::ty::visit::MaxUniverse;
|
||||
use rustc_middle::ty::{
|
||||
self, AliasRelationDirection, InferConst, Term, Ty, TyCtxt, TypeVisitable, TypeVisitableExt,
|
||||
TypingMode,
|
||||
};
|
||||
use rustc_span::Span;
|
||||
use tracing::{debug, instrument, warn};
|
||||
|
@ -519,7 +520,10 @@ impl<'tcx> TypeRelation<TyCtxt<'tcx>> for Generalizer<'_, 'tcx> {
|
|||
//
|
||||
// cc trait-system-refactor-initiative#108
|
||||
if self.infcx.next_trait_solver()
|
||||
&& !self.infcx.intercrate
|
||||
&& !matches!(
|
||||
self.infcx.typing_mode_unchecked(),
|
||||
TypingMode::Coherence
|
||||
)
|
||||
&& self.in_alias
|
||||
{
|
||||
inner.type_variables().equate(vid, new_var_id);
|
||||
|
@ -650,7 +654,10 @@ impl<'tcx> TypeRelation<TyCtxt<'tcx>> for Generalizer<'_, 'tcx> {
|
|||
// See the comment for type inference variables
|
||||
// for more details.
|
||||
if self.infcx.next_trait_solver()
|
||||
&& !self.infcx.intercrate
|
||||
&& !matches!(
|
||||
self.infcx.typing_mode_unchecked(),
|
||||
TypingMode::Coherence
|
||||
)
|
||||
&& self.in_alias
|
||||
{
|
||||
variable_table.union(vid, new_var_id);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue