Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 10 additions & 13 deletions compiler/rustc_infer/src/infer/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -198,38 +198,35 @@ impl<'tcx> rustc_type_ir::InferCtxtLike for InferCtxt<'tcx> {
}

fn equate_ty_vids_raw(&self, a: ty::TyVid, b: ty::TyVid) {
self.inner.borrow_mut().type_variables().equate(a, b);
self.inner.borrow_mut().equate_ty_vids(a, b);
}

fn sub_unify_ty_vids_raw(&self, a: ty::TyVid, b: ty::TyVid) {
self.sub_unify_ty_vids_raw(a, b);
}

fn equate_int_vids_raw(&self, a: ty::IntVid, b: ty::IntVid) {
self.inner.borrow_mut().int_unification_table().union(a, b);
self.inner.borrow_mut().equate_int_vids(a, b);
}

fn equate_float_vids_raw(&self, a: ty::FloatVid, b: ty::FloatVid) {
self.inner.borrow_mut().float_unification_table().union(a, b);
self.inner.borrow_mut().equate_float_vids(a, b);
}

fn equate_const_vids_raw(&self, a: ty::ConstVid, b: ty::ConstVid) {
self.inner.borrow_mut().const_unification_table().union(a, b);
self.inner.borrow_mut().equate_const_vids(a, b);
}

fn instantiate_ty_var_raw(&self, vid: ty::TyVid, ty: Ty<'tcx>) {
let ty = lower_universe(self, self.try_resolve_ty_var(vid).unwrap_err(), ty);

self.inner.borrow_mut().type_variables().instantiate(vid, ty);
self.inner.borrow_mut().instantiate_ty_var(vid, ty);
}

fn instantiate_const_var_raw(&self, vid: ty::ConstVid, ct: ty::Const<'tcx>) {
let ct = lower_universe(self, self.try_resolve_const_var(vid).unwrap_err(), ct);

self.inner
.borrow_mut()
.const_unification_table()
.union_value(vid, ConstVariableValue::Known { value: ct });
self.inner.borrow_mut().instantiate_const_var(vid, ct);
}

fn instantiate_ty_var<R: PredicateEmittingRelation<Self>>(
Expand All @@ -250,11 +247,11 @@ impl<'tcx> rustc_type_ir::InferCtxtLike for InferCtxt<'tcx> {
}

fn instantiate_int_var_raw(&self, vid: ty::IntVid, value: ty::IntVarValue) {
self.inner.borrow_mut().int_unification_table().union_value(vid, value);
self.inner.borrow_mut().instantiate_int_var(vid, value);
}

fn instantiate_float_var_raw(&self, vid: ty::FloatVid, value: ty::FloatVarValue) {
self.inner.borrow_mut().float_unification_table().union_value(vid, value);
self.inner.borrow_mut().instantiate_float_var(vid, value);
}

fn instantiate_const_var<R: PredicateEmittingRelation<Self>>(
Expand Down Expand Up @@ -464,7 +461,7 @@ impl<'a, 'tcx> ty::TypeFolder<TyCtxt<'tcx>> for LowerUniverseFolder<'a, 'tcx> {
let origin = inner.type_variables().var_origin(vid);
let new_var_id =
inner.type_variables().new_var(self.for_universe, origin);
inner.type_variables().equate(vid, new_var_id);
inner.equate_ty_vids(vid, new_var_id);
Ty::new_var(self.cx(), new_var_id)
}
}
Expand Down Expand Up @@ -504,7 +501,7 @@ impl<'a, 'tcx> ty::TypeFolder<TyCtxt<'tcx>> for LowerUniverseFolder<'a, 'tcx> {
})
.vid;

self.infcx.inner.borrow_mut().const_unification_table().union(vid, new_var_id);
self.infcx.inner.borrow_mut().equate_const_vids(vid, new_var_id);

ty::Const::new_var(self.cx(), new_var_id)
}
Expand Down
93 changes: 90 additions & 3 deletions compiler/rustc_infer/src/infer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,11 @@ pub(crate) type UnificationTable<'a, 'tcx, T> = ut::UnificationTable<
pub struct InferCtxtInner<'tcx> {
undo_log: InferCtxtUndoLogs<'tcx>,

/// Bumped whenever an inference change may let a stalled fulfillment goal
/// make progress. Snapshots save and restore the value, but individual bumps
/// are not undo-log entries.
stalled_goal_generation: Option<u64>,

/// Cache for projections.
///
/// This cache is snapshotted along with the infcx.
Expand Down Expand Up @@ -168,9 +173,10 @@ pub struct InferCtxtInner<'tcx> {
}

impl<'tcx> InferCtxtInner<'tcx> {
fn new() -> InferCtxtInner<'tcx> {
fn new(next_trait_solver: bool) -> InferCtxtInner<'tcx> {
InferCtxtInner {
undo_log: InferCtxtUndoLogs::default(),
stalled_goal_generation: next_trait_solver.then_some(0),

projection_cache: Default::default(),
type_variable_storage: Default::default(),
Expand Down Expand Up @@ -234,6 +240,79 @@ impl<'tcx> InferCtxtInner<'tcx> {
self.const_unification_storage.with_log(&mut self.undo_log)
}

#[inline]
pub(crate) fn start_snapshot(&mut self) -> snapshot::undo_log::Snapshot<'tcx> {
self.undo_log.start_snapshot(self.stalled_goal_generation)
}

#[inline]
fn stalled_goal_generation(&self) -> Option<u64> {
self.stalled_goal_generation
}

#[inline]
fn bump_stalled_goal_generation(&mut self) {
if let Some(generation) = &mut self.stalled_goal_generation {
*generation = generation.wrapping_add(1);
}
}

#[inline]
fn equate_ty_vids(&mut self, a: ty::TyVid, b: ty::TyVid) {
self.bump_stalled_goal_generation();
self.type_variables().equate(a, b);
}

#[inline]
fn sub_unify_ty_vids(&mut self, a: ty::TyVid, b: ty::TyVid) {
self.bump_stalled_goal_generation();
self.type_variables().sub_unify(a, b);
}

#[inline]
fn instantiate_ty_var(&mut self, vid: ty::TyVid, ty: Ty<'tcx>) {
self.bump_stalled_goal_generation();
self.type_variables().instantiate(vid, ty);
}

// These mutations can unblock stalled goals too, so route them through the
// same generation bump.
#[inline]
fn equate_int_vids(&mut self, a: ty::IntVid, b: ty::IntVid) {
self.bump_stalled_goal_generation();
self.int_unification_table().union(a, b);
}

#[inline]
fn equate_float_vids(&mut self, a: ty::FloatVid, b: ty::FloatVid) {
self.bump_stalled_goal_generation();
self.float_unification_table().union(a, b);
}

#[inline]
fn equate_const_vids(&mut self, a: ty::ConstVid, b: ty::ConstVid) {
self.bump_stalled_goal_generation();
self.const_unification_table().union(a, b);
}

#[inline]
fn instantiate_int_var(&mut self, vid: ty::IntVid, value: ty::IntVarValue) {
self.bump_stalled_goal_generation();
self.int_unification_table().union_value(vid, value);
}

#[inline]
fn instantiate_float_var(&mut self, vid: ty::FloatVid, value: ty::FloatVarValue) {
self.bump_stalled_goal_generation();
self.float_unification_table().union_value(vid, value);
}

#[inline]
fn instantiate_const_var(&mut self, vid: ty::ConstVid, value: ty::Const<'tcx>) {
self.bump_stalled_goal_generation();
self.const_unification_table().union_value(vid, ConstVariableValue::Known { value });
}

#[inline]
pub fn unwrap_region_constraints(&mut self) -> RegionConstraintCollector<'_, 'tcx> {
self.region_constraint_storage
Expand Down Expand Up @@ -681,7 +760,7 @@ impl<'tcx> InferCtxtBuilder<'tcx> {
considering_regions,
in_hir_typeck,
skip_leak_check,
inner: RefCell::new(InferCtxtInner::new()),
inner: RefCell::new(InferCtxtInner::new(next_trait_solver)),
lexical_region_resolutions: RefCell::new(None),
selection_cache: Default::default(),
evaluation_cache: Default::default(),
Expand Down Expand Up @@ -1352,7 +1431,7 @@ impl<'tcx> InferCtxt<'tcx> {
}

pub fn sub_unify_ty_vids_raw(&self, a: ty::TyVid, b: ty::TyVid) {
self.inner.borrow_mut().type_variables().sub_unify(a, b);
self.inner.borrow_mut().sub_unify_ty_vids(a, b);
}

pub fn sub_unification_table_root_var(&self, var: ty::TyVid) -> ty::TyVid {
Expand Down Expand Up @@ -1651,6 +1730,14 @@ impl<'tcx> InferCtxt<'tcx> {
self.typing_env(param_env).as_query_input(value)
}

#[inline]
pub fn stalled_goal_generation(&self) -> u64 {
self.inner
.borrow()
.stalled_goal_generation()
.expect("stalled-goal generation requires the next trait solver")
}

/// The returned function is used in a fast path. If it returns `true` the variable is
/// unchanged, `false` indicates that the status is unknown.
#[inline]
Expand Down
24 changes: 11 additions & 13 deletions compiler/rustc_infer/src/infer/relate/generalize.rs
Original file line number Diff line number Diff line change
Expand Up @@ -245,30 +245,27 @@ impl<'tcx> InferCtxt<'tcx> {
match (l, r.kind()) {
(TermVid::Ty(l), ty::TermKind::Ty(r)) => {
if let Some(r) = r.ty_vid() {
self.inner.borrow_mut().type_variables().equate(l, r)
self.inner.borrow_mut().equate_ty_vids(l, r)
} else {
// Ideally, we put this assert into `type_variables().instantiate()`.
// But we can't pass the infcx into it as the infcx is already
// mutably borrowed.
debug_assert!(
self.try_resolve_ty_var(l).unwrap_err().can_name(ty::max_universe(self, r))
);
self.inner.borrow_mut().type_variables().instantiate(l, r)
self.inner.borrow_mut().instantiate_ty_var(l, r)
}
}
(TermVid::Const(l), ty::TermKind::Const(r)) => {
if let Some(r) = r.ct_vid() {
self.inner.borrow_mut().const_unification_table().union(l, r)
self.inner.borrow_mut().equate_const_vids(l, r)
} else {
debug_assert!(
self.try_resolve_const_var(l)
.unwrap_err()
.can_name(ty::max_universe(self, r))
);
self.inner
.borrow_mut()
.const_unification_table()
.union_value(l, ConstVariableValue::Known { value: r })
self.inner.borrow_mut().instantiate_const_var(l, r)
}
}
_ => bug!("mismatched term kinds in generalize: {l:?}, {r:?}"),
Expand Down Expand Up @@ -531,7 +528,7 @@ impl<'tcx> TypeRelation<TyCtxt<'tcx>> for Generalizer<'_, 'tcx> {
// Record that `vid` and `new_var_id` have to be subtypes
// of each other. This is currently only used for diagnostics.
// To see why, see the docs in the `type_variables` module.
inner.type_variables().sub_unify(vid, new_var_id);
inner.sub_unify_ty_vids(vid, new_var_id);
// If we're in the new solver and create a new inference
// variable inside of an alias we eagerly constrain that
// inference variable to prevent unexpected ambiguity errors.
Expand All @@ -551,7 +548,7 @@ impl<'tcx> TypeRelation<TyCtxt<'tcx>> for Generalizer<'_, 'tcx> {
&& !self.infcx.typing_mode_raw().is_coherence()
&& self.in_alias
{
inner.type_variables().equate(vid, new_var_id);
inner.equate_ty_vids(vid, new_var_id);
}

debug!("replacing original vid={:?} with new={:?}", vid, new_var_id);
Expand Down Expand Up @@ -660,8 +657,8 @@ impl<'tcx> TypeRelation<TyCtxt<'tcx>> for Generalizer<'_, 'tcx> {
}

let mut inner = self.infcx.inner.borrow_mut();
let variable_table = &mut inner.const_unification_table();
match variable_table.probe_value(vid) {
let vid_value = inner.const_unification_table().probe_value(vid);
match vid_value {
ConstVariableValue::Known { value: u } => {
drop(inner);
self.relate(u, u)
Expand All @@ -670,7 +667,8 @@ impl<'tcx> TypeRelation<TyCtxt<'tcx>> for Generalizer<'_, 'tcx> {
if self.for_universe.can_name(universe) {
Ok(c)
} else {
let new_var_id = variable_table
let new_var_id = inner
.const_unification_table()
.new_key(ConstVariableValue::Unknown {
origin,
universe: self.for_universe,
Expand All @@ -683,7 +681,7 @@ impl<'tcx> TypeRelation<TyCtxt<'tcx>> for Generalizer<'_, 'tcx> {
&& !self.infcx.typing_mode_raw().is_coherence()
&& self.in_alias
{
variable_table.union(vid, new_var_id);
inner.equate_const_vids(vid, new_var_id);
}
Ok(ty::Const::new_var(tcx, new_var_id))
}
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_infer/src/infer/relate/type_relating.rs
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,7 @@ impl<'tcx> TypeRelation<TyCtxt<'tcx>> for TypeRelating<'_, 'tcx> {
));
}
ty::Invariant => {
infcx.inner.borrow_mut().type_variables().equate(a_id, b_id);
infcx.inner.borrow_mut().equate_ty_vids(a_id, b_id);
}
ty::Bivariant => {
unreachable!("Expected bivariance to be handled in relate_with_variance")
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_infer/src/infer/snapshot/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ impl<'tcx> InferCtxt<'tcx> {
let mut inner = self.inner.borrow_mut();

CombinedSnapshot {
undo_snapshot: inner.undo_log.start_snapshot(),
undo_snapshot: inner.start_snapshot(),
region_constraints_snapshot: inner.unwrap_region_constraints().start_snapshot(),
universe: self.universe(),
}
Expand Down
9 changes: 7 additions & 2 deletions compiler/rustc_infer/src/infer/snapshot/undo_log.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ use crate::traits;

pub struct Snapshot<'tcx> {
pub(crate) undo_len: usize,
stalled_goal_generation: Option<u64>,
_marker: PhantomData<&'tcx ()>,
}

Expand Down Expand Up @@ -158,6 +159,7 @@ impl<'tcx> InferCtxtInner<'tcx> {
}

self.type_variable_storage.finalize_rollback();
self.stalled_goal_generation = snapshot.stalled_goal_generation;

if self.undo_log.num_open_snapshots == 1 {
// After the root snapshot the undo log should be empty.
Expand All @@ -184,9 +186,12 @@ impl<'tcx> InferCtxtInner<'tcx> {
}

impl<'tcx> InferCtxtUndoLogs<'tcx> {
pub(crate) fn start_snapshot(&mut self) -> Snapshot<'tcx> {
pub(crate) fn start_snapshot(
&mut self,
stalled_goal_generation: Option<u64>,
) -> Snapshot<'tcx> {
self.num_open_snapshots += 1;
Snapshot { undo_len: self.logs.len(), _marker: PhantomData }
Snapshot { undo_len: self.logs.len(), stalled_goal_generation, _marker: PhantomData }
}

pub(crate) fn region_constraints_in_snapshot(
Expand Down
3 changes: 3 additions & 0 deletions compiler/rustc_infer/src/infer/type_variable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,7 @@ impl<'tcx> TypeVariableTable<'_, 'tcx> {
pub(crate) fn equate(&mut self, a: ty::TyVid, b: ty::TyVid) {
debug_assert!(self.probe(a).is_unknown());
debug_assert!(self.probe(b).is_unknown());

self.eq_relations().union(a, b);
self.sub_unification_table().union(a, b);
}
Expand All @@ -189,6 +190,7 @@ impl<'tcx> TypeVariableTable<'_, 'tcx> {
pub(crate) fn sub_unify(&mut self, a: ty::TyVid, b: ty::TyVid) {
debug_assert!(self.probe(a).is_unknown());
debug_assert!(self.probe(b).is_unknown());

self.sub_unification_table().union(a, b);
}

Expand All @@ -204,6 +206,7 @@ impl<'tcx> TypeVariableTable<'_, 'tcx> {
"instantiating type variable `{vid:?}` twice: new-value = {ty:?}, old-value={:?}",
self.eq_relations().probe_value(vid)
);

self.eq_relations().union_value(vid, TypeVariableValue::Known { value: ty });
}

Expand Down
Loading
Loading