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
8 changes: 1 addition & 7 deletions compiler/rustc_borrowck/src/type_check/relate_tys.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
use rustc_data_structures::fx::FxHashMap;
use rustc_errors::ErrorGuaranteed;
use rustc_hir::def_id::DefId;
use rustc_infer::infer::relate::{
PredicateEmittingRelation, Relate, RelateResult, StructurallyRelateAliases, TypeRelation,
};
use rustc_infer::infer::relate::{PredicateEmittingRelation, Relate, RelateResult, TypeRelation};
use rustc_infer::infer::{InferCtxt, NllRegionVariableOrigin};
use rustc_infer::traits::Obligation;
use rustc_infer::traits::solve::Goal;
Expand Down Expand Up @@ -552,10 +550,6 @@ impl<'b, 'tcx> PredicateEmittingRelation<InferCtxt<'tcx>> for NllTypeRelating<'_
self.locations.span(self.type_checker.body)
}

fn structurally_relate_aliases(&self) -> StructurallyRelateAliases {
StructurallyRelateAliases::No
}

fn param_env(&self) -> ty::ParamEnv<'tcx> {
self.type_checker.infcx.param_env
}
Expand Down
168 changes: 164 additions & 4 deletions compiler/rustc_infer/src/infer/context.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
//! Definition of `InferCtxtLike` from the librarified type layer.
use rustc_data_structures::sso::SsoHashMap;
use rustc_hir::def_id::DefId;
use rustc_middle::traits::ObligationCause;
use rustc_middle::ty::relate::RelateResult;
use rustc_middle::ty::relate::combine::PredicateEmittingRelation;
use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable};
use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span};
use rustc_type_ir::{TypeSuperFoldable, TypeVisitableExt};

use super::type_variable::TypeVariableValue;
use super::{
BoundRegionConversionTime, InferCtxt, OpaqueTypeStorageEntries, RegionVariableOrigin,
SubregionOrigin,
BoundRegionConversionTime, ConstVariableValue, InferCtxt, OpaqueTypeStorageEntries,
RegionVariableOrigin, SubregionOrigin,
};

impl<'tcx> rustc_type_ir::InferCtxtLike for InferCtxt<'tcx> {
Expand Down Expand Up @@ -251,7 +254,30 @@ impl<'tcx> rustc_type_ir::InferCtxtLike for InferCtxt<'tcx> {
self.inner.borrow_mut().const_unification_table().union(a, b);
}

fn instantiate_ty_var_raw<R: PredicateEmittingRelation<Self>>(
fn instantiate_ty_var_raw(&self, vid: ty::TyVid, ty: Ty<'tcx>) {
let ty = ty.fold_with(&mut LowerUniverseFolder {
infcx: self,
for_universe: self.try_resolve_ty_var(vid).unwrap_err(),
cache: Default::default(),
});

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

fn instantiate_const_var_raw(&self, vid: ty::ConstVid, ct: ty::Const<'tcx>) {
let ct = ct.fold_with(&mut LowerUniverseFolder {
infcx: self,
for_universe: self.try_resolve_const_var(vid).unwrap_err(),
cache: Default::default(),
});

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

fn instantiate_ty_var<R: PredicateEmittingRelation<Self>>(
&self,
relation: &mut R,
target_is_expected: bool,
Expand All @@ -276,7 +302,7 @@ impl<'tcx> rustc_type_ir::InferCtxtLike for InferCtxt<'tcx> {
self.inner.borrow_mut().float_unification_table().union_value(vid, value);
}

fn instantiate_const_var_raw<R: PredicateEmittingRelation<Self>>(
fn instantiate_const_var<R: PredicateEmittingRelation<Self>>(
&self,
relation: &mut R,
target_is_expected: bool,
Expand Down Expand Up @@ -411,3 +437,137 @@ impl<'tcx> rustc_type_ir::InferCtxtLike for InferCtxt<'tcx> {
let _ = self.take_opaque_types();
}
}

/// Canonicalizing inputs puts all inference variables and placeholders
/// into the root universe.
///
/// This means when instantiating the query response we need to pull
/// down the universe of returned `var_values` to the universe of
/// the inference variable in `orig_values`.
///
/// This folder is similar to the `Generalizer`, except that it simply
/// structurally folds non-rigid aliases as these should have already
/// been generalized in the query so we shouldn't try to do it again.
struct LowerUniverseFolder<'a, 'tcx> {
infcx: &'a InferCtxt<'tcx>,
for_universe: ty::UniverseIndex,
cache: SsoHashMap<Ty<'tcx>, Ty<'tcx>>,
}
impl<'a, 'tcx> ty::TypeFolder<TyCtxt<'tcx>> for LowerUniverseFolder<'a, 'tcx> {
fn cx(&self) -> TyCtxt<'tcx> {
self.infcx.tcx
}

fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
if !(t.has_free_regions() || t.has_infer()) {
return t;
}

if let Some(&answer) = self.cache.get(&t) {
return answer;
}

let folded = match t.kind() {
ty::Infer(ty::TyVar(vid)) => {
let vid = self.infcx.root_var(*vid);
let probe = self.infcx.inner.borrow_mut().type_variables().probe(vid);
match probe {
TypeVariableValue::Known { value: u } => u.super_fold_with(self),
TypeVariableValue::Unknown { universe } => {
if self.for_universe.can_name(universe) {
t
} else {
let mut inner = self.infcx.inner.borrow_mut();
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);
Ty::new_var(self.cx(), new_var_id)
}
}
}
}
ty::Placeholder(p) => {
debug_assert!(
self.for_universe.can_name(p.universe),
"variable in universe {:?} can't name type in universe {:?}",
self.for_universe,
p.universe
);
Comment on lines +491 to +496

@lcnr lcnr Jul 17, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can you instead do a separate max_universe check after this folder has returned. Given that we have a fast path for

        if !(t.has_free_regions() || t.has_infer()) {
            return t;
        }

this is unreachable

View changes since the review

t
}
_ => t.super_fold_with(self),
};

self.cache.insert(t, folded);
folded
}

fn fold_const(&mut self, c: ty::Const<'tcx>) -> ty::Const<'tcx> {
if !(c.has_free_regions() || c.has_infer()) {
return c;
}

match c.kind() {
ty::ConstKind::Infer(ty::InferConst::Var(vid)) => {
let vid = self.infcx.root_const_var(vid);
let universe = self.infcx.try_resolve_const_var(vid).unwrap_err();
if self.for_universe.can_name(universe) {
c
} else {
let origin = self.infcx.const_var_origin(vid).unwrap();
let new_var_id = self
.infcx
.inner
.borrow_mut()
.const_unification_table()
.new_key(ConstVariableValue::Unknown {
origin,
universe: self.for_universe,
})
.vid;

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

ty::Const::new_var(self.cx(), new_var_id)
}
}
ty::ConstKind::Placeholder(p) => {
debug_assert!(
self.for_universe.can_name(p.universe),
"variable in universe {:?} can't name const in universe {:?}",
self.for_universe,
p.universe
);
c
}
_ => c.super_fold_with(self),
}
}

fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
match r.kind() {
ty::ReBound(..) | ty::ReErased => r,
_ => {
let r_universe = self.infcx.universe_of_region(r);
if self.for_universe.can_name(r_universe) {
r
} else {
// FIXME: unfortunately we lose the relating span here unless we take another
// argument.
let new_region = self.infcx.next_region_var_in_universe(
RegionVariableOrigin::Misc(DUMMY_SP),
self.for_universe,
);
self.infcx.equate_regions(
SubregionOrigin::RelateRegionParamBound(DUMMY_SP, None),
r,
new_region,
ty::VisibleForLeakCheck::Yes,
);
new_region
}
}
}
}
}
1 change: 0 additions & 1 deletion compiler/rustc_infer/src/infer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ pub use opaque_types::{OpaqueTypeStorage, OpaqueTypeStorageEntries, OpaqueTypeTa
use region_constraints::{
GenericKind, RegionConstraintCollector, RegionConstraintStorage, VarInfos, VerifyBound,
};
pub use relate::StructurallyRelateAliases;
pub use relate::combine::PredicateEmittingRelation;
use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
use rustc_data_structures::undo_log::{Rollback, UndoLogs};
Expand Down
80 changes: 36 additions & 44 deletions compiler/rustc_infer/src/infer/relate/generalize.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,7 @@ use rustc_middle::ty::{self, InferConst, Term, Ty, TyCtxt, TypeVisitableExt};
use rustc_span::Span;
use tracing::{debug, instrument, warn};

use super::{
PredicateEmittingRelation, Relate, RelateResult, StructurallyRelateAliases, TypeRelation,
};
use super::{PredicateEmittingRelation, Relate, RelateResult, TypeRelation};
use crate::infer::type_variable::TypeVariableValue;
use crate::infer::unify_key::ConstVariableValue;
use crate::infer::{InferCtxt, RegionVariableOrigin, relate};
Expand Down Expand Up @@ -142,13 +140,8 @@ impl<'tcx> InferCtxt<'tcx> {
//
// We then relate `generalized_term <: source_term`, adding constraints like `'x: '?2` and
// `?1 <: ?3`.
let Generalization { value_may_be_infer: generalized_term } = self.generalize(
relation.span(),
relation.structurally_relate_aliases(),
target_vid,
instantiation_variance,
source_term,
)?;
let Generalization { value_may_be_infer: generalized_term } =
self.generalize(relation.span(), target_vid, instantiation_variance, source_term)?;

// Constrain `b_vid` to the generalized type `generalized_term`.
self.union_var_term(target_vid, generalized_term);
Expand Down Expand Up @@ -304,13 +297,24 @@ impl<'tcx> InferCtxt<'tcx> {
if let Some(r) = r.ty_vid() {
self.inner.borrow_mut().type_variables().equate(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)
}
}
(TermVid::Const(l), ty::TermKind::Const(r)) => {
if let Some(r) = r.ct_vid() {
self.inner.borrow_mut().const_unification_table().union(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()
Expand All @@ -326,7 +330,6 @@ impl<'tcx> InferCtxt<'tcx> {
fn generalize(
&self,
span: Span,
structurally_relate_aliases: StructurallyRelateAliases,
target_vid: TermVid,
ambient_variance: ty::Variance,
source_term: Term<'tcx>,
Expand All @@ -345,7 +348,6 @@ impl<'tcx> InferCtxt<'tcx> {
let mut generalizer = Generalizer {
infcx: self,
span,
structurally_relate_aliases,
root_vid,
for_universe,
root_term: source_term,
Expand Down Expand Up @@ -377,10 +379,6 @@ struct Generalizer<'me, 'tcx> {

span: Span,

/// Whether aliases should be related structurally. If not, we have to
/// be careful when generalizing aliases.
structurally_relate_aliases: StructurallyRelateAliases,

/// The vid of the type variable that is in the process of being
/// instantiated. If we find this within the value we are folding,
/// that means we would have created a cyclic value.
Expand Down Expand Up @@ -634,12 +632,9 @@ impl<'tcx> TypeRelation<TyCtxt<'tcx>> for Generalizer<'_, 'tcx> {

// We only need to be careful with potentially normalizeable
// aliases here. See `generalize_alias_term` for more information.
ty::Alias(ty::IsRigid::No, data) => match self.structurally_relate_aliases {
StructurallyRelateAliases::No => {
self.generalize_alias_term(data.into()).map(|v| v.expect_type())
}
StructurallyRelateAliases::Yes => relate::structurally_relate_tys(self, t, t),
},
ty::Alias(ty::IsRigid::No, data) => {
self.generalize_alias_term(data.into()).map(|v| v.expect_type())
}

_ => relate::structurally_relate_tys(self, t, t),
}?;
Expand Down Expand Up @@ -748,33 +743,30 @@ impl<'tcx> TypeRelation<TyCtxt<'tcx>> for Generalizer<'_, 'tcx> {
// FIXME: Alias consts are also not rigid, so the current
// approach of always relating them structurally is incomplete.
//
// FIXME: replace the StructurallyRelateAliases::Yes branch with
// FIXME: replace the `else` branch with
// `structurally_relate_consts` once it is fully structural.
//
// We only need to be careful with potentially normalizeable
// aliases here. See `generalize_alias_term` for more information.
ty::ConstKind::Alias(ty::IsRigid::No, alias_const) => {
match self.structurally_relate_aliases {
// Hack: Fall back to old behavior if GCE is enabled (it used to just be the Yes
// path), as doing this new No path breaks some GCE things. I expect GCE to be
// ripped out soon so this shouldn't matter soon.
StructurallyRelateAliases::No if !tcx.features().generic_const_exprs() => {
self.generalize_alias_term(alias_const.into()).map(|v| v.expect_const())
}
_ => {
let ty::AliasConst { kind, args, .. } = alias_const;
let args = self.relate_with_variance(
ty::Invariant,
ty::VarianceDiagInfo::default(),
args,
args,
)?;
Ok(ty::Const::new_alias(
tcx,
ty::IsRigid::No,
ty::AliasConst::new(tcx, kind, args),
))
}
// Hack: Fall back to old behavior if GCE is enabled (it used to just be the Yes
// path), as doing this new No path breaks some GCE things. I expect GCE to be
// ripped out soon so this shouldn't matter soon.
if !tcx.features().generic_const_exprs() {
self.generalize_alias_term(alias_const.into()).map(|v| v.expect_const())
} else {
let ty::AliasConst { kind, args, .. } = alias_const;
let args = self.relate_with_variance(
ty::Invariant,
ty::VarianceDiagInfo::default(),
args,
args,
)?;
Ok(ty::Const::new_alias(
tcx,
ty::IsRigid::No,
ty::AliasConst::new(tcx, kind, args),
))
}
}
ty::ConstKind::Placeholder(placeholder) => {
Expand Down
5 changes: 0 additions & 5 deletions compiler/rustc_infer/src/infer/relate/lattice.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ use rustc_middle::ty::{self, Ty, TyCtxt, TyVar, TypeVisitableExt};
use rustc_span::Span;
use tracing::{debug, instrument};

use super::StructurallyRelateAliases;
use super::combine::PredicateEmittingRelation;
use crate::infer::{DefineOpaqueTypes, InferCtxt, SubregionOrigin, TypeTrace};
use crate::traits::{Obligation, PredicateObligations};
Expand Down Expand Up @@ -263,10 +262,6 @@ impl<'tcx> PredicateEmittingRelation<InferCtxt<'tcx>> for LatticeOp<'_, 'tcx> {
self.trace.span()
}

fn structurally_relate_aliases(&self) -> StructurallyRelateAliases {
StructurallyRelateAliases::No
}

fn param_env(&self) -> ty::ParamEnv<'tcx> {
self.param_env
}
Expand Down
Loading
Loading