1
Fork 0

TypingMode 🤔

This commit is contained in:
lcnr 2024-10-18 00:28:43 +02:00
parent 2dece5bb62
commit f51ec110a7
75 changed files with 513 additions and 506 deletions

View file

@ -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 {

View file

@ -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

View file

@ -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)
}

View file

@ -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 {

View file

@ -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(())
}

View file

@ -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);