Skip to content
140 changes: 60 additions & 80 deletions compiler/rustc_infer/src/infer/freshen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,45 +60,35 @@ impl<'a, 'tcx> TypeFreshener<'a, 'tcx> {
}
}

fn freshen_ty<F>(&mut self, input: Result<Ty<'tcx>, ty::InferTy>, mk_fresh: F) -> Ty<'tcx>
fn freshen_ty<F>(&mut self, input: ty::InferTy, mk_fresh: F) -> Ty<'tcx>
where
F: FnOnce(u32) -> Ty<'tcx>,
{
match input {
Ok(ty) => ty.fold_with(self),
Err(key) => match self.ty_freshen_map.entry(key) {
Entry::Occupied(entry) => *entry.get(),
Entry::Vacant(entry) => {
let index = self.ty_freshen_count;
self.ty_freshen_count += 1;
let t = mk_fresh(index);
entry.insert(t);
t
}
},
match self.ty_freshen_map.entry(input) {
Entry::Occupied(entry) => *entry.get(),
Entry::Vacant(entry) => {
let index = self.ty_freshen_count;
self.ty_freshen_count += 1;
let t = mk_fresh(index);
entry.insert(t);
t
}
}
}

fn freshen_const<F>(
&mut self,
input: Result<ty::Const<'tcx>, ty::InferConst>,
freshener: F,
) -> ty::Const<'tcx>
fn freshen_const<F>(&mut self, input: ty::InferConst, freshener: F) -> ty::Const<'tcx>
where
F: FnOnce(u32) -> ty::InferConst,
{
match input {
Ok(ct) => ct.fold_with(self),
Err(key) => match self.const_freshen_map.entry(key) {
Entry::Occupied(entry) => *entry.get(),
Entry::Vacant(entry) => {
let index = self.const_freshen_count;
self.const_freshen_count += 1;
let ct = ty::Const::new_infer(self.infcx.tcx, freshener(index));
entry.insert(ct);
ct
}
},
match self.const_freshen_map.entry(input) {
Entry::Occupied(entry) => *entry.get(),
Entry::Vacant(entry) => {
let index = self.const_freshen_count;
self.const_freshen_count += 1;
let ct = ty::Const::new_infer(self.infcx.tcx, freshener(index));
entry.insert(ct);
ct
}
}
}
}
Expand Down Expand Up @@ -130,7 +120,7 @@ impl<'a, 'tcx> TypeFolder<TyCtxt<'tcx>> for TypeFreshener<'a, 'tcx> {
t
} else {
match *t.kind() {
ty::Infer(v) => self.fold_infer_ty(v).unwrap_or(t),
ty::Infer(v) => self.fold_infer_ty(v),

// This code is hot enough that a non-debug assertion here makes a noticeable
// difference on benchmarks like `wg-grammar`.
Expand All @@ -146,27 +136,24 @@ impl<'a, 'tcx> TypeFolder<TyCtxt<'tcx>> for TypeFreshener<'a, 'tcx> {
match ct.kind() {
ty::ConstKind::Infer(ty::InferConst::Var(v)) => {
let mut inner = self.infcx.inner.borrow_mut();
let input =
inner.const_unification_table().probe_value(v).known().ok_or_else(|| {
ty::InferConst::Var(inner.const_unification_table().find(v).vid)
});
drop(inner);
self.freshen_const(input, ty::InferConst::Fresh)
}
ty::ConstKind::Infer(ty::InferConst::Fresh(i)) => {
if i >= self.const_freshen_count {
bug!(
"Encountered a freshend const with id {} \
but our counter is only at {}",
i,
self.const_freshen_count,
);
match inner.const_unification_table().probe_value(v).known() {
Some(const_) => {
drop(inner);
const_.fold_with(self)
}
None => {
let input =
ty::InferConst::Var(inner.const_unification_table().find(v).vid);
self.freshen_const(input, ty::InferConst::Fresh)
}
}
ct
}
ty::ConstKind::Infer(ty::InferConst::Fresh(_)) => {
bug!("trying to freshen already-freshened const {ct:?}");
}

ty::ConstKind::Bound(..) | ty::ConstKind::Placeholder(_) => {
bug!("unexpected const {:?}", ct)
bug!("unexpected const {ct:?}")
}

ty::ConstKind::Param(_)
Expand All @@ -181,56 +168,49 @@ impl<'a, 'tcx> TypeFolder<TyCtxt<'tcx>> for TypeFreshener<'a, 'tcx> {
impl<'a, 'tcx> TypeFreshener<'a, 'tcx> {
// This is separate from `fold_ty` to keep that method small and inlinable.
#[inline(never)]
fn fold_infer_ty(&mut self, v: ty::InferTy) -> Option<Ty<'tcx>> {
match v {
fn fold_infer_ty(&mut self, ty: ty::InferTy) -> Ty<'tcx> {
match ty {
ty::TyVar(v) => {
let mut inner = self.infcx.inner.borrow_mut();
let input = inner
.type_variables()
.probe(v)
.known()
.ok_or_else(|| ty::TyVar(inner.type_variables().root_var(v)));
drop(inner);
Some(self.freshen_ty(input, |n| Ty::new_fresh(self.infcx.tcx, n)))
match inner.type_variables().probe(v).known() {
Some(ty) => {
drop(inner);
ty.fold_with(self)
}
None => {
let input = ty::TyVar(inner.type_variables().root_var(v));
self.freshen_ty(input, |n| Ty::new_fresh(self.infcx.tcx, n))
}
}
}

ty::IntVar(v) => {
let mut inner = self.infcx.inner.borrow_mut();
let value = inner.int_unification_table().probe_value(v);
let input = match value {
ty::IntVarValue::IntType(ty) => Ok(Ty::new_int(self.infcx.tcx, ty)),
ty::IntVarValue::UintType(ty) => Ok(Ty::new_uint(self.infcx.tcx, ty)),
match value {
ty::IntVarValue::IntType(ty) => Ty::new_int(self.infcx.tcx, ty),
ty::IntVarValue::UintType(ty) => Ty::new_uint(self.infcx.tcx, ty),
ty::IntVarValue::Unknown => {
Err(ty::IntVar(inner.int_unification_table().find(v)))
let input = ty::IntVar(inner.int_unification_table().find(v));
self.freshen_ty(input, |n| Ty::new_fresh_int(self.infcx.tcx, n))
}
};
drop(inner);
Some(self.freshen_ty(input, |n| Ty::new_fresh_int(self.infcx.tcx, n)))
}
}

ty::FloatVar(v) => {
let mut inner = self.infcx.inner.borrow_mut();
let value = inner.float_unification_table().probe_value(v);
let input = match value {
ty::FloatVarValue::Known(ty) => Ok(Ty::new_float(self.infcx.tcx, ty)),
match value {
ty::FloatVarValue::Known(ty) => Ty::new_float(self.infcx.tcx, ty),
ty::FloatVarValue::Unknown => {
Err(ty::FloatVar(inner.float_unification_table().find(v)))
let input = ty::FloatVar(inner.float_unification_table().find(v));
self.freshen_ty(input, |n| Ty::new_fresh_float(self.infcx.tcx, n))
}
};
drop(inner);
Some(self.freshen_ty(input, |n| Ty::new_fresh_float(self.infcx.tcx, n)))
}
}

ty::FreshTy(ct) | ty::FreshIntTy(ct) | ty::FreshFloatTy(ct) => {
if ct >= self.ty_freshen_count {
bug!(
"Encountered a freshend type with id {} \
but our counter is only at {}",
ct,
self.ty_freshen_count
);
}
None
ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_) => {
bug!("trying to freshen already-freshened type {ty:?}");
}
}
}
Expand Down
8 changes: 0 additions & 8 deletions compiler/rustc_infer/src/infer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -637,10 +637,6 @@ impl<'tcx> InferCtxt<'tcx> {
self.typing_mode
}

pub fn freshen<T: TypeFoldable<TyCtxt<'tcx>>>(&self, t: T) -> T {
t.fold_with(&mut self.freshener())
}

/// Returns the origin of the type variable identified by `vid`.
///
/// No attempt is made to resolve `vid` to its root variable.
Expand All @@ -658,10 +654,6 @@ impl<'tcx> InferCtxt<'tcx> {
}
}

pub fn freshener<'b>(&'b self) -> TypeFreshener<'b, 'tcx> {
freshen::TypeFreshener::new(self)
}

pub fn unresolved_variables(&self) -> Vec<Ty<'tcx>> {
let mut inner = self.inner.borrow_mut();
let mut vars: Vec<Ty<'_>> = inner
Expand Down
3 changes: 2 additions & 1 deletion compiler/rustc_trait_selection/src/traits/auto_trait.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ use tracing::debug;

use super::*;
use crate::errors::UnableToConstructConstantValue;
use crate::infer::TypeFreshener;
use crate::infer::region_constraints::{ConstraintKind, RegionConstraintData};
use crate::regions::OutlivesEnvironmentBuildExt;
use crate::traits::project::ProjectAndUnifyResult;
Expand Down Expand Up @@ -817,6 +818,6 @@ impl<'tcx> AutoTraitFinder<'tcx> {
infcx: &InferCtxt<'tcx>,
p: ty::Predicate<'tcx>,
) -> ty::Predicate<'tcx> {
infcx.freshen(p)
p.fold_with(&mut TypeFreshener::new(infcx))
}
}
15 changes: 8 additions & 7 deletions compiler/rustc_trait_selection/src/traits/select/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
pub fn new(infcx: &'cx InferCtxt<'tcx>) -> SelectionContext<'cx, 'tcx> {
SelectionContext {
infcx,
freshener: infcx.freshener(),
freshener: TypeFreshener::new(infcx),
intercrate_ambiguity_causes: None,
query_mode: TraitQueryMode::Standard,
}
Expand Down Expand Up @@ -321,10 +321,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
self.check_recursion_limit(stack.obligation, stack.obligation)?;

// Check the cache. Note that we freshen the trait-ref
// separately rather than using `stack.fresh_trait_ref` --
// separately rather than using `stack.fresh_trait_pred` --
// this is because we want the unbound variables to be
// replaced with fresh types starting from index 0.
let cache_fresh_trait_pred = self.infcx.freshen(stack.obligation.predicate);
let cache_fresh_trait_pred =
stack.obligation.predicate.fold_with(&mut TypeFreshener::new(self.infcx));
debug!(?cache_fresh_trait_pred);
debug_assert!(!stack.obligation.predicate.has_escaping_bound_vars());

Expand Down Expand Up @@ -1135,7 +1136,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
/// `Option<Box<List<T>>>` is `Send` if `Box<List<T>>` is
/// `Send`.
///
/// Note that we do this comparison using the `fresh_trait_ref`
/// Note that we do this comparison using the `fresh_trait_pred`
/// fields. Because these have all been freshened using
/// `self.freshener`, we can be sure that (a) this will not
/// affect the inferencer state and (b) that if we see two
Expand Down Expand Up @@ -1219,7 +1220,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
if unbound_input_types
&& stack.iter().skip(1).any(|prev| {
stack.obligation.param_env == prev.obligation.param_env
&& self.match_fresh_trait_refs(stack.fresh_trait_pred, prev.fresh_trait_pred)
&& self.match_fresh_trait_preds(stack.fresh_trait_pred, prev.fresh_trait_pred)
})
{
debug!("evaluate_stack --> unbound argument, recursive --> giving up",);
Expand Down Expand Up @@ -2742,7 +2743,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
///////////////////////////////////////////////////////////////////////////
// Miscellany

fn match_fresh_trait_refs(
fn match_fresh_trait_preds(
&self,
previous: ty::PolyTraitPredicate<'tcx>,
current: ty::PolyTraitPredicate<'tcx>,
Expand Down Expand Up @@ -3031,7 +3032,7 @@ impl<'tcx> ProvisionalEvaluationCache<'tcx> {
}

/// Check the provisional cache for any result for
/// `fresh_trait_ref`. If there is a hit, then you must consider
/// `fresh_trait_pred`. If there is a hit, then you must consider
/// it an access to the stack slots at depth
/// `reached_depth` (from the returned value).
fn get_provisional(
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_type_ir/src/const_kind.rs
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ rustc_index::newtype_index! {
pub enum InferConst {
/// Infer the value of the const.
Var(ConstVid),
/// A fresh const variable. See `infer::freshen` for more details.
/// A fresh const variable. See `TypeFreshener` for more details.
Fresh(u32),
}

Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_type_ir/src/ty_kind.rs
Original file line number Diff line number Diff line change
Expand Up @@ -594,7 +594,7 @@ pub enum InferTy {

/// A [`FreshTy`][Self::FreshTy] is one that is generated as a replacement
/// for an unbound type variable. This is convenient for caching etc. See
/// `rustc_infer::infer::freshen` for more details.
/// `TypeFreshener` for more details.
///
/// Compare with [`TyVar`][Self::TyVar].
FreshTy(u32),
Expand Down
Loading
Loading