Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Simplify shallow resolver to just fold ty/consts #123537

Merged
merged 1 commit into from
Apr 17, 2024
Merged
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
2 changes: 1 addition & 1 deletion compiler/rustc_borrowck/src/type_check/relate_tys.rs
Original file line number Diff line number Diff line change
Expand Up @@ -437,7 +437,7 @@ impl<'bccx, 'tcx> TypeRelation<'tcx> for NllTypeRelating<'_, 'bccx, 'tcx> {
a: ty::Const<'tcx>,
b: ty::Const<'tcx>,
) -> RelateResult<'tcx, ty::Const<'tcx>> {
let a = self.type_checker.infcx.shallow_resolve(a);
let a = self.type_checker.infcx.shallow_resolve_const(a);
assert!(!a.has_non_region_infer(), "unexpected inference var {:?}", a);
assert!(!b.has_non_region_infer(), "unexpected inference var {:?}", b);

Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_infer/src/infer/canonical/canonicalizer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -802,7 +802,7 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> {
const_var: ty::Const<'tcx>,
) -> ty::Const<'tcx> {
debug_assert!(
!self.infcx.is_some_and(|infcx| const_var != infcx.shallow_resolve(const_var))
!self.infcx.is_some_and(|infcx| const_var != infcx.shallow_resolve_const(const_var))
);
let var = self.canonical_var(info, const_var.into());
ty::Const::new_bound(self.tcx, self.binder_index, var, self.fold_ty(const_var.ty()))
Expand Down
166 changes: 70 additions & 96 deletions compiler/rustc_infer/src/infer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1253,19 +1253,76 @@ impl<'tcx> InferCtxt<'tcx> {
}
}

/// Resolve any type variables found in `value` -- but only one
/// level. So, if the variable `?X` is bound to some type
/// `Foo<?Y>`, then this would return `Foo<?Y>` (but `?Y` may
/// itself be bound to a type).
///
/// Useful when you only need to inspect the outermost level of
/// the type and don't care about nested types (or perhaps you
/// will be resolving them as well, e.g. in a loop).
pub fn shallow_resolve<T>(&self, value: T) -> T
where
T: TypeFoldable<TyCtxt<'tcx>>,
{
value.fold_with(&mut ShallowResolver { infcx: self })
pub fn shallow_resolve(&self, ty: Ty<'tcx>) -> Ty<'tcx> {
if let ty::Infer(v) = ty.kind() { self.fold_infer_ty(*v).unwrap_or(ty) } else { ty }
}

// This is separate from `shallow_resolve` to keep that method small and inlinable.
#[inline(never)]
fn fold_infer_ty(&self, v: InferTy) -> Option<Ty<'tcx>> {
match v {
ty::TyVar(v) => {
// Not entirely obvious: if `typ` is a type variable,
// it can be resolved to an int/float variable, which
// can then be recursively resolved, hence the
// recursion. Note though that we prevent type
// variables from unifying to other type variables
// directly (though they may be embedded
// structurally), and we prevent cycles in any case,
// so this recursion should always be of very limited
// depth.
//
// Note: if these two lines are combined into one we get
// dynamic borrow errors on `self.inner`.
let known = self.inner.borrow_mut().type_variables().probe(v).known();
known.map(|t| self.shallow_resolve(t))
}

ty::IntVar(v) => self
.inner
.borrow_mut()
.int_unification_table()
.probe_value(v)
.map(|v| v.to_type(self.tcx)),

ty::FloatVar(v) => self
.inner
.borrow_mut()
.float_unification_table()
.probe_value(v)
.map(|v| v.to_type(self.tcx)),

ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_) => None,
}
}

pub fn shallow_resolve_const(&self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> {
match ct.kind() {
ty::ConstKind::Infer(infer_ct) => match infer_ct {
InferConst::Var(vid) => self
.inner
.borrow_mut()
.const_unification_table()
.probe_value(vid)
.known()
.unwrap_or(ct),
InferConst::EffectVar(vid) => self
.inner
.borrow_mut()
.effect_unification_table()
.probe_value(vid)
.known()
.unwrap_or(ct),
InferConst::Fresh(_) => ct,
},
ty::ConstKind::Param(_)
| ty::ConstKind::Bound(_, _)
| ty::ConstKind::Placeholder(_)
| ty::ConstKind::Unevaluated(_)
| ty::ConstKind::Value(_)
| ty::ConstKind::Error(_)
| ty::ConstKind::Expr(_) => ct,
}
}

pub fn root_var(&self, var: ty::TyVid) -> ty::TyVid {
Expand Down Expand Up @@ -1782,89 +1839,6 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for InferenceLiteralEraser<'tcx> {
}
}

struct ShallowResolver<'a, 'tcx> {
infcx: &'a InferCtxt<'tcx>,
}

impl<'a, 'tcx> TypeFolder<TyCtxt<'tcx>> for ShallowResolver<'a, 'tcx> {
fn interner(&self) -> TyCtxt<'tcx> {
self.infcx.tcx
}

/// If `ty` is a type variable of some kind, resolve it one level
/// (but do not resolve types found in the result). If `typ` is
/// not a type variable, just return it unmodified.
#[inline]
fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
if let ty::Infer(v) = ty.kind() { self.fold_infer_ty(*v).unwrap_or(ty) } else { ty }
}

fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> {
match ct.kind() {
ty::ConstKind::Infer(InferConst::Var(vid)) => self
.infcx
.inner
.borrow_mut()
.const_unification_table()
.probe_value(vid)
.known()
.unwrap_or(ct),
ty::ConstKind::Infer(InferConst::EffectVar(vid)) => self
.infcx
.inner
.borrow_mut()
.effect_unification_table()
.probe_value(vid)
.known()
.unwrap_or(ct),
_ => ct,
}
}
}

impl<'a, 'tcx> ShallowResolver<'a, 'tcx> {
// This is separate from `fold_ty` to keep that method small and inlinable.
#[inline(never)]
fn fold_infer_ty(&mut self, v: InferTy) -> Option<Ty<'tcx>> {
match v {
ty::TyVar(v) => {
// Not entirely obvious: if `typ` is a type variable,
// it can be resolved to an int/float variable, which
// can then be recursively resolved, hence the
// recursion. Note though that we prevent type
// variables from unifying to other type variables
// directly (though they may be embedded
// structurally), and we prevent cycles in any case,
// so this recursion should always be of very limited
// depth.
//
// Note: if these two lines are combined into one we get
// dynamic borrow errors on `self.inner`.
let known = self.infcx.inner.borrow_mut().type_variables().probe(v).known();
known.map(|t| self.fold_ty(t))
}

ty::IntVar(v) => self
.infcx
.inner
.borrow_mut()
.int_unification_table()
.probe_value(v)
.map(|v| v.to_type(self.infcx.tcx)),

ty::FloatVar(v) => self
.infcx
.inner
.borrow_mut()
.float_unification_table()
.probe_value(v)
.map(|v| v.to_type(self.infcx.tcx)),

ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_) => None,
}
}
}

impl<'tcx> TypeTrace<'tcx> {
pub fn span(&self) -> Span {
self.cause.span
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_infer/src/infer/relate/combine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -155,8 +155,8 @@ impl<'tcx> InferCtxt<'tcx> {
return Ok(a);
}

let a = self.shallow_resolve(a);
let b = self.shallow_resolve(b);
let a = self.shallow_resolve_const(a);
let b = self.shallow_resolve_const(b);

// We should never have to relate the `ty` field on `Const` as it is checked elsewhere that consts have the
// correct type for the generic param they are an argument for. However there have been a number of cases
Expand Down
14 changes: 6 additions & 8 deletions compiler/rustc_infer/src/infer/resolve.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,29 +12,27 @@ use rustc_middle::ty::{self, Const, InferConst, Ty, TyCtxt, TypeFoldable};
/// useful for printing messages etc but also required at various
/// points for correctness.
pub struct OpportunisticVarResolver<'a, 'tcx> {
// The shallow resolver is used to resolve inference variables at every
// level of the type.
shallow_resolver: crate::infer::ShallowResolver<'a, 'tcx>,
infcx: &'a InferCtxt<'tcx>,
}

impl<'a, 'tcx> OpportunisticVarResolver<'a, 'tcx> {
#[inline]
pub fn new(infcx: &'a InferCtxt<'tcx>) -> Self {
OpportunisticVarResolver { shallow_resolver: crate::infer::ShallowResolver { infcx } }
OpportunisticVarResolver { infcx }
}
}

impl<'a, 'tcx> TypeFolder<TyCtxt<'tcx>> for OpportunisticVarResolver<'a, 'tcx> {
fn interner(&self) -> TyCtxt<'tcx> {
TypeFolder::interner(&self.shallow_resolver)
self.infcx.tcx
}

#[inline]
fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
if !t.has_non_region_infer() {
t // micro-optimize -- if there is nothing in this type that this fold affects...
} else {
let t = self.shallow_resolver.fold_ty(t);
let t = self.infcx.shallow_resolve(t);
t.super_fold_with(self)
}
}
Expand All @@ -43,7 +41,7 @@ impl<'a, 'tcx> TypeFolder<TyCtxt<'tcx>> for OpportunisticVarResolver<'a, 'tcx> {
if !ct.has_non_region_infer() {
ct // micro-optimize -- if there is nothing in this const that this fold affects...
} else {
let ct = self.shallow_resolver.fold_const(ct);
let ct = self.infcx.shallow_resolve_const(ct);
ct.super_fold_with(self)
}
}
Expand Down Expand Up @@ -160,7 +158,7 @@ impl<'a, 'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for FullTypeResolver<'a, 'tcx> {
if !c.has_infer() {
Ok(c) // micro-optimize -- if there is nothing in this const that this fold affects...
} else {
let c = self.infcx.shallow_resolve(c);
let c = self.infcx.shallow_resolve_const(c);
match c.kind() {
ty::ConstKind::Infer(InferConst::Var(vid)) => {
return Err(FixupError::UnresolvedConst(vid));
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_trait_selection/src/solve/normalize.rs
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,7 @@ impl<'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for NormalizationFolder<'_, 'tcx> {
#[instrument(level = "debug", skip(self), ret)]
fn try_fold_const(&mut self, ct: ty::Const<'tcx>) -> Result<ty::Const<'tcx>, Self::Error> {
let infcx = self.at.infcx;
debug_assert_eq!(ct, infcx.shallow_resolve(ct));
debug_assert_eq!(ct, infcx.shallow_resolve_const(ct));
if !ct.has_aliases() {
return Ok(ct);
}
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_trait_selection/src/traits/coherence.rs
Original file line number Diff line number Diff line change
Expand Up @@ -501,7 +501,7 @@ fn plug_infer_with_placeholders<'tcx>(
}

fn visit_const(&mut self, ct: ty::Const<'tcx>) {
let ct = self.infcx.shallow_resolve(ct);
let ct = self.infcx.shallow_resolve_const(ct);
if ct.is_ct_infer() {
let Ok(InferOk { value: (), obligations }) =
self.infcx.at(&ObligationCause::dummy(), ty::ParamEnv::empty()).eq(
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_trait_selection/src/traits/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ fn pred_known_to_hold_modulo_regions<'tcx>(
let errors = ocx.select_all_or_error();
match errors.as_slice() {
// Only known to hold if we did no inference.
[] => infcx.shallow_resolve(goal) == goal,
[] => infcx.resolve_vars_if_possible(goal) == goal,

errors => {
debug!(?errors);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1165,8 +1165,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
return;
}

let self_ty = self.infcx.shallow_resolve(obligation.self_ty());
match self_ty.skip_binder().kind() {
let self_ty = self.infcx.shallow_resolve(obligation.self_ty().skip_binder());
match self_ty.kind() {
ty::Alias(..)
| ty::Dynamic(..)
| ty::Error(_)
Expand Down Expand Up @@ -1317,7 +1317,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
obligation: &PolyTraitObligation<'tcx>,
candidates: &mut SelectionCandidateSet<'tcx>,
) {
let self_ty = self.infcx.shallow_resolve(obligation.self_ty());
let self_ty = self.infcx.resolve_vars_if_possible(obligation.self_ty());

match self_ty.skip_binder().kind() {
ty::FnPtr(_) => candidates.vec.push(BuiltinCandidate { has_nested: false }),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -157,10 +157,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
) -> Result<Vec<PredicateObligation<'tcx>>, SelectionError<'tcx>> {
let tcx = self.tcx();

let trait_predicate = self.infcx.shallow_resolve(obligation.predicate);
let placeholder_trait_predicate =
self.infcx.enter_forall_and_leak_universe(trait_predicate).trait_ref;
let placeholder_self_ty = placeholder_trait_predicate.self_ty();
self.infcx.enter_forall_and_leak_universe(obligation.predicate).trait_ref;
let placeholder_self_ty = self.infcx.shallow_resolve(placeholder_trait_predicate.self_ty());
let candidate_predicate = self
.for_each_item_bound(
placeholder_self_ty,
Expand Down Expand Up @@ -422,7 +421,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
) -> Result<Vec<PredicateObligation<'tcx>>, SelectionError<'tcx>> {
debug!(?obligation, "confirm_auto_impl_candidate");

let self_ty = self.infcx.shallow_resolve(obligation.predicate.self_ty());
let self_ty = obligation.predicate.self_ty().map_bound(|ty| self.infcx.shallow_resolve(ty));
let types = self.constituent_types_for_ty(self_ty)?;
Ok(self.vtable_auto_impl(obligation, obligation.predicate.def_id(), types))
}
Expand Down Expand Up @@ -1378,7 +1377,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
let drop_trait = self.tcx().require_lang_item(LangItem::Drop, None);

let tcx = self.tcx();
let self_ty = self.infcx.shallow_resolve(obligation.self_ty());
let self_ty = obligation.self_ty().map_bound(|ty| self.infcx.shallow_resolve(ty));

let mut nested = vec![];
let cause = obligation.derived_cause(BuiltinDerivedObligation);
Expand Down
8 changes: 4 additions & 4 deletions compiler/rustc_trait_selection/src/traits/select/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -571,7 +571,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
)?;
// If the predicate has done any inference, then downgrade the
// result to ambiguous.
if this.infcx.shallow_resolve(goal) != goal {
if this.infcx.resolve_vars_if_possible(goal) != goal {
result = result.max(EvaluatedToAmbig);
}
Ok(result)
Expand Down Expand Up @@ -1774,9 +1774,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
// that means that we must have newly inferred something about the GAT.
// We should give up in that case.
if !generics.params.is_empty()
&& obligation.predicate.args[generics.parent_count..]
.iter()
.any(|&p| p.has_non_region_infer() && self.infcx.shallow_resolve(p) != p)
&& obligation.predicate.args[generics.parent_count..].iter().any(|&p| {
p.has_non_region_infer() && self.infcx.resolve_vars_if_possible(p) != p
})
{
ProjectionMatchesProjection::Ambiguous
} else {
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_trait_selection/src/traits/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -649,7 +649,7 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for PlaceholderReplacer<'_, 'tcx> {
}

fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> {
let ct = self.infcx.shallow_resolve(ct);
let ct = self.infcx.shallow_resolve_const(ct);
if let ty::ConstKind::Placeholder(p) = ct.kind() {
let replace_var = self.mapped_consts.get(&p);
match replace_var {
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_trait_selection/src/traits/wf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ pub fn obligations<'tcx>(
GenericArgKind::Const(ct) => {
match ct.kind() {
ty::ConstKind::Infer(_) => {
let resolved = infcx.shallow_resolve(ct);
let resolved = infcx.shallow_resolve_const(ct);
if resolved == ct {
// No progress.
return None;
Expand Down
Loading