From 840d23def8783e48f760bad9a61881317eee11cb Mon Sep 17 00:00:00 2001 From: Adwin White Date: Fri, 3 Jul 2026 18:42:30 +0800 Subject: [PATCH 1/3] new relating for response --- compiler/rustc_infer/src/infer/context.rs | 168 ++++++++++++++- .../src/canonical/mod.rs | 203 +++++++++++++++++- compiler/rustc_type_ir/src/infer_ctxt.rs | 10 +- compiler/rustc_type_ir/src/relate/combine.rs | 4 +- .../src/relate/solver_relating.rs | 4 +- 5 files changed, 375 insertions(+), 14 deletions(-) diff --git a/compiler/rustc_infer/src/infer/context.rs b/compiler/rustc_infer/src/infer/context.rs index d1a56d5ab073c..adba31f35aba6 100644 --- a/compiler/rustc_infer/src/infer/context.rs +++ b/compiler/rustc_infer/src/infer/context.rs @@ -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> { @@ -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>( + 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>( &self, relation: &mut R, target_is_expected: bool, @@ -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>( + fn instantiate_const_var>( &self, relation: &mut R, target_is_expected: bool, @@ -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>>, +} +impl<'a, 'tcx> ty::TypeFolder> 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 + ); + 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 + } + } + } + } +} diff --git a/compiler/rustc_next_trait_solver/src/canonical/mod.rs b/compiler/rustc_next_trait_solver/src/canonical/mod.rs index b2f6ac78040b6..dc419136d150f 100644 --- a/compiler/rustc_next_trait_solver/src/canonical/mod.rs +++ b/compiler/rustc_next_trait_solver/src/canonical/mod.rs @@ -14,7 +14,10 @@ use std::iter; use canonicalizer::Canonicalizer; use rustc_index::IndexVec; use rustc_type_ir::inherent::*; -use rustc_type_ir::relate::solver_relating::RelateExt; +use rustc_type_ir::relate::{ + self, Relate, RelateResult, StructurallyRelateAliases, TypeRelation, + VarianceDiagInfo, relate_args_invariantly, +}; use rustc_type_ir::{ self as ty, Canonical, CanonicalVarKind, CanonicalVarValues, InferCtxtLike, Interner, TypeFoldable, TypingMode, TypingModeEqWrapper, @@ -246,6 +249,199 @@ where }) } +/// Enforce that `a` is equal to `b`. +/// +/// In normal type relating, we don't structurally relate non-rigid aliases +/// as they can be normalized to any type. So we emit projection obligations to +/// defer the checks. E.g. in `infcx.eq` or `infcx.relate`. +/// But when unifying query response with original vars, we want to directly +/// set the original vars to values in response. +/// +/// Therefore this type relation is created to **always** structurally relate +/// aliases, or more specifically, structurally eq everything. +struct ResponseRelating<'infcx, Infcx, I: Interner> { + infcx: &'infcx Infcx, + span: I::Span, +} + +impl<'infcx, Infcx, I> ResponseRelating<'infcx, Infcx, I> +where + Infcx: InferCtxtLike, + I: Interner, +{ + fn new(infcx: &'infcx Infcx, span: I::Span) -> Self { + ResponseRelating { infcx, span } + } +} + +impl TypeRelation for ResponseRelating<'_, Infcx, I> +where + Infcx: InferCtxtLike, + I: Interner, +{ + fn cx(&self) -> I { + self.infcx.cx() + } + + fn relate_ty_args( + &mut self, + a_ty: I::Ty, + _b_ty: I::Ty, + _def_id: I::DefId, + a_args: I::GenericArgs, + b_args: I::GenericArgs, + _: impl FnOnce(I::GenericArgs) -> I::Ty, + ) -> RelateResult { + relate_args_invariantly(self, a_args, b_args)?; + Ok(a_ty) + } + fn relate_with_variance>( + &mut self, + _variance: ty::Variance, + _info: VarianceDiagInfo, + a: T, + b: T, + ) -> RelateResult { + self.relate(a, b) + } + + #[instrument(skip(self), level = "trace")] + fn tys(&mut self, a: I::Ty, b: I::Ty) -> RelateResult { + if a == b { + return Ok(a); + } + + let infcx = self.infcx; + let a = infcx.shallow_resolve(a); + let b = infcx.shallow_resolve(b); + + match (a.kind(), b.kind()) { + (ty::Infer(ty::TyVar(a_id)), ty::Infer(ty::TyVar(b_id))) => { + infcx.equate_ty_vids_raw(a_id, b_id); + } + + (ty::Infer(ty::TyVar(a_vid)), _) => { + infcx.instantiate_ty_var_raw(a_vid, b); + } + + (_, ty::Infer(ty::TyVar(b_vid))) => { + infcx.instantiate_ty_var_raw(b_vid, a); + } + + (ty::Error(e), _) | (_, ty::Error(e)) => { + infcx.set_tainted_by_errors(e); + return Ok(Ty::new_error(infcx.cx(), e)); + } + + // FIXME: Share the arms below with `super_combine_tys`. + // We can't use `super_combine_tys` here because we want to support + // values with escaping bound vars so that we can avoid + // instantiating binders when relating them. + // + // Relate integral variables to other types + (ty::Infer(ty::IntVar(a_id)), ty::Infer(ty::IntVar(b_id))) => { + infcx.equate_int_vids_raw(a_id, b_id); + } + (ty::Infer(ty::IntVar(v_id)), ty::Int(v)) => { + infcx.instantiate_int_var_raw(v_id, ty::IntVarValue::IntType(v)); + } + (ty::Int(v), ty::Infer(ty::IntVar(v_id))) => { + infcx.instantiate_int_var_raw(v_id, ty::IntVarValue::IntType(v)); + } + (ty::Infer(ty::IntVar(v_id)), ty::Uint(v)) => { + infcx.instantiate_int_var_raw(v_id, ty::IntVarValue::UintType(v)); + } + (ty::Uint(v), ty::Infer(ty::IntVar(v_id))) => { + infcx.instantiate_int_var_raw(v_id, ty::IntVarValue::UintType(v)); + } + + // Relate floating-point variables to other types + (ty::Infer(ty::FloatVar(a_id)), ty::Infer(ty::FloatVar(b_id))) => { + infcx.equate_float_vids_raw(a_id, b_id); + } + (ty::Infer(ty::FloatVar(v_id)), ty::Float(v)) => { + infcx.instantiate_float_var_raw(v_id, ty::FloatVarValue::Known(v)); + } + (ty::Float(v), ty::Infer(ty::FloatVar(v_id))) => { + infcx.instantiate_float_var_raw(v_id, ty::FloatVarValue::Known(v)); + } + + (_, ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_))) + | (ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)), _) => { + panic!("We do not expect to encounter `Fresh` variables in the new solver") + } + + _ => { + relate::structurally_relate_tys(self, a, b)?; + } + } + + Ok(a) + } + + #[instrument(skip(self), level = "trace")] + fn regions(&mut self, a: I::Region, b: I::Region) -> RelateResult { + self.infcx.equate_regions(a, b, VisibleForLeakCheck::Yes, self.span); + + Ok(a) + } + + #[instrument(skip(self), level = "trace")] + fn consts(&mut self, a: I::Const, b: I::Const) -> RelateResult { + if a == b { + return Ok(a); + } + + let infcx = self.infcx; + // FIXME: make this a debug_assert. + // Currently proof tree evaluation can unify infer vars in original + // vars while not resolving them. + // See `tests/ui/traits/next-solver/transmute-from-async-closure.rs` + let a = infcx.shallow_resolve_const(a); + debug_assert_eq!(b, infcx.shallow_resolve_const(b)); + match (a.kind(), b.kind()) { + ( + ty::ConstKind::Infer(ty::InferConst::Var(a_vid)), + ty::ConstKind::Infer(ty::InferConst::Var(b_vid)), + ) => { + infcx.equate_const_vids_raw(a_vid, b_vid); + } + + (ty::ConstKind::Infer(ty::InferConst::Var(a_vid)), _) => { + infcx.instantiate_const_var_raw(a_vid, b); + } + + (_, ty::ConstKind::Infer(ty::InferConst::Var(b_vid))) => { + infcx.instantiate_const_var_raw(b_vid, a); + } + + _ => { + relate::structurally_relate_consts(self, a, b)?; + } + } + + Ok(a) + } + + fn binders( + &mut self, + a: ty::Binder, + b: ty::Binder, + ) -> RelateResult> + where + T: Relate, + { + if a == b { + return Ok(a); + } + + debug_assert_eq!(a.bound_vars(), b.bound_vars()); + self.relate(a.skip_binder(), b.skip_binder())?; + + Ok(a) + } +} + /// Unify the `original_values` with the `var_values` returned by the canonical query.. /// /// This assumes that this unification will always succeed. This is the case when @@ -272,9 +468,8 @@ fn unify_query_var_values( assert_eq!(original_values.len(), var_values.len()); for (&orig, response) in iter::zip(original_values, var_values.var_values.iter()) { - let goals = - delegate.eq_structurally_relating_aliases(param_env, orig, response, span).unwrap(); - assert!(goals.is_empty()); + let mut must_eq = ResponseRelating::new(&**delegate, span); + must_eq.relate(orig, response).unwrap(); } } diff --git a/compiler/rustc_type_ir/src/infer_ctxt.rs b/compiler/rustc_type_ir/src/infer_ctxt.rs index 6a011e82dcbbf..03fedfc723186 100644 --- a/compiler/rustc_type_ir/src/infer_ctxt.rs +++ b/compiler/rustc_type_ir/src/infer_ctxt.rs @@ -427,7 +427,13 @@ pub trait InferCtxtLike: Sized { fn equate_float_vids_raw(&self, a: ty::FloatVid, b: ty::FloatVid); fn equate_const_vids_raw(&self, a: ty::ConstVid, b: ty::ConstVid); - fn instantiate_ty_var_raw>( + /// Use `instantiate_ty_var` instead unless you have reasons to skip + /// generalization. + fn instantiate_ty_var_raw(&self, vid: ty::TyVid, ty: ::Ty); + /// Use `instantiate_const_var` instead unless you have reasons to skip + /// generalization. + fn instantiate_const_var_raw(&self, vid: ty::ConstVid, ct: ::Const); + fn instantiate_ty_var>( &self, relation: &mut R, target_is_expected: bool, @@ -437,7 +443,7 @@ pub trait InferCtxtLike: Sized { ) -> RelateResult; fn instantiate_int_var_raw(&self, vid: ty::IntVid, value: ty::IntVarValue); fn instantiate_float_var_raw(&self, vid: ty::FloatVid, value: ty::FloatVarValue); - fn instantiate_const_var_raw>( + fn instantiate_const_var>( &self, relation: &mut R, target_is_expected: bool, diff --git a/compiler/rustc_type_ir/src/relate/combine.rs b/compiler/rustc_type_ir/src/relate/combine.rs index b292be195e103..26751ab71df5e 100644 --- a/compiler/rustc_type_ir/src/relate/combine.rs +++ b/compiler/rustc_type_ir/src/relate/combine.rs @@ -238,12 +238,12 @@ where } (ty::ConstKind::Infer(ty::InferConst::Var(vid)), _) => { - infcx.instantiate_const_var_raw(relation, true, vid, b)?; + infcx.instantiate_const_var(relation, true, vid, b)?; Ok(b) } (_, ty::ConstKind::Infer(ty::InferConst::Var(vid))) => { - infcx.instantiate_const_var_raw(relation, false, vid, a)?; + infcx.instantiate_const_var(relation, false, vid, a)?; Ok(a) } diff --git a/compiler/rustc_type_ir/src/relate/solver_relating.rs b/compiler/rustc_type_ir/src/relate/solver_relating.rs index a3ed4ac4b6e7f..2bc9e8c6cfa9c 100644 --- a/compiler/rustc_type_ir/src/relate/solver_relating.rs +++ b/compiler/rustc_type_ir/src/relate/solver_relating.rs @@ -230,10 +230,10 @@ where } (ty::Infer(ty::TyVar(a_vid)), _) => { - infcx.instantiate_ty_var_raw(self, true, a_vid, self.ambient_variance, b)?; + infcx.instantiate_ty_var(self, true, a_vid, self.ambient_variance, b)?; } (_, ty::Infer(ty::TyVar(b_vid))) => { - infcx.instantiate_ty_var_raw( + infcx.instantiate_ty_var( self, false, b_vid, From 6b4d1fdac7a542770580db5ccf95410380458aa4 Mon Sep 17 00:00:00 2001 From: Adwin White Date: Fri, 3 Jul 2026 20:24:01 +0800 Subject: [PATCH 2/3] remove `StructurallyRelateAliases` --- .../src/type_check/relate_tys.rs | 8 +-- compiler/rustc_infer/src/infer/mod.rs | 1 - .../src/infer/relate/generalize.rs | 69 +++++++------------ .../rustc_infer/src/infer/relate/lattice.rs | 5 -- .../src/infer/relate/type_relating.rs | 6 +- .../src/canonical/mod.rs | 32 ++++++++- compiler/rustc_type_ir/src/relate.rs | 12 ---- compiler/rustc_type_ir/src/relate/combine.rs | 14 +--- .../src/relate/solver_relating.rs | 42 +---------- 9 files changed, 61 insertions(+), 128 deletions(-) diff --git a/compiler/rustc_borrowck/src/type_check/relate_tys.rs b/compiler/rustc_borrowck/src/type_check/relate_tys.rs index c2b70e2ea5e42..d821ada3c2f57 100644 --- a/compiler/rustc_borrowck/src/type_check/relate_tys.rs +++ b/compiler/rustc_borrowck/src/type_check/relate_tys.rs @@ -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; @@ -552,10 +550,6 @@ impl<'b, 'tcx> PredicateEmittingRelation> 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 } diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index aa2fe2ee21dfa..8313cdd2c0ab3 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -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}; diff --git a/compiler/rustc_infer/src/infer/relate/generalize.rs b/compiler/rustc_infer/src/infer/relate/generalize.rs index 12c577d3a50e2..d6bac5a274e64 100644 --- a/compiler/rustc_infer/src/infer/relate/generalize.rs +++ b/compiler/rustc_infer/src/infer/relate/generalize.rs @@ -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}; @@ -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); @@ -326,7 +319,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>, @@ -345,7 +337,6 @@ impl<'tcx> InferCtxt<'tcx> { let mut generalizer = Generalizer { infcx: self, span, - structurally_relate_aliases, root_vid, for_universe, root_term: source_term, @@ -377,10 +368,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. @@ -634,12 +621,9 @@ impl<'tcx> TypeRelation> 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), }?; @@ -748,33 +732,30 @@ impl<'tcx> TypeRelation> 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) => { diff --git a/compiler/rustc_infer/src/infer/relate/lattice.rs b/compiler/rustc_infer/src/infer/relate/lattice.rs index 0ae7842a9d593..d8baaf01c87d3 100644 --- a/compiler/rustc_infer/src/infer/relate/lattice.rs +++ b/compiler/rustc_infer/src/infer/relate/lattice.rs @@ -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}; @@ -263,10 +262,6 @@ impl<'tcx> PredicateEmittingRelation> for LatticeOp<'_, 'tcx> { self.trace.span() } - fn structurally_relate_aliases(&self) -> StructurallyRelateAliases { - StructurallyRelateAliases::No - } - fn param_env(&self) -> ty::ParamEnv<'tcx> { self.param_env } diff --git a/compiler/rustc_infer/src/infer/relate/type_relating.rs b/compiler/rustc_infer/src/infer/relate/type_relating.rs index 2e3a50ac953e7..e9541592e4e03 100644 --- a/compiler/rustc_infer/src/infer/relate/type_relating.rs +++ b/compiler/rustc_infer/src/infer/relate/type_relating.rs @@ -7,7 +7,7 @@ use rustc_span::Span; use tracing::{debug, instrument}; use crate::infer::BoundRegionConversionTime::HigherRankedType; -use crate::infer::relate::{PredicateEmittingRelation, StructurallyRelateAliases}; +use crate::infer::relate::PredicateEmittingRelation; use crate::infer::{DefineOpaqueTypes, InferCtxt, SubregionOrigin, TypeTrace}; use crate::traits::{Obligation, PredicateObligations}; @@ -360,10 +360,6 @@ impl<'tcx> PredicateEmittingRelation> for TypeRelating<'_, 'tcx> self.param_env } - fn structurally_relate_aliases(&self) -> StructurallyRelateAliases { - StructurallyRelateAliases::No - } - fn register_predicates( &mut self, preds: impl IntoIterator, ty::Predicate<'tcx>>>, diff --git a/compiler/rustc_next_trait_solver/src/canonical/mod.rs b/compiler/rustc_next_trait_solver/src/canonical/mod.rs index dc419136d150f..5c9884558a614 100644 --- a/compiler/rustc_next_trait_solver/src/canonical/mod.rs +++ b/compiler/rustc_next_trait_solver/src/canonical/mod.rs @@ -15,8 +15,7 @@ use canonicalizer::Canonicalizer; use rustc_index::IndexVec; use rustc_type_ir::inherent::*; use rustc_type_ir::relate::{ - self, Relate, RelateResult, StructurallyRelateAliases, TypeRelation, - VarianceDiagInfo, relate_args_invariantly, + self, Relate, RelateResult, TypeRelation, VarianceDiagInfo, relate_args_invariantly, }; use rustc_type_ir::{ self as ty, Canonical, CanonicalVarKind, CanonicalVarValues, InferCtxtLike, Interner, @@ -442,6 +441,35 @@ where } } +impl PredicateEmittingRelation for ResponseRelating<'_, Infcx, I> +where + Infcx: InferCtxtLike, + I: Interner, +{ + fn span(&self) -> I::Span { + Span::dummy() + } + + fn param_env(&self) -> I::ParamEnv { + self.param_env + } + + fn register_predicates( + &mut self, + _obligations: impl IntoIterator>, + ) { + panic!("we shouldn't register any goal when unifying response with original values"); + } + + fn register_goals(&mut self, _obligations: impl IntoIterator>) { + panic!("we shouldn't register any goal when unifying response with original values"); + } + + fn ambient_variance(&self) -> ty::Variance { + ty::Variance::Invariant + } +} + /// Unify the `original_values` with the `var_values` returned by the canonical query.. /// /// This assumes that this unification will always succeed. This is the case when diff --git a/compiler/rustc_type_ir/src/relate.rs b/compiler/rustc_type_ir/src/relate.rs index b0a30773731eb..e015410b856f8 100644 --- a/compiler/rustc_type_ir/src/relate.rs +++ b/compiler/rustc_type_ir/src/relate.rs @@ -14,18 +14,6 @@ pub mod solver_relating; pub type RelateResult = Result>; -/// Whether aliases should be related structurally or not. Used -/// to adjust the behavior of generalization and combine. -/// -/// This should always be `No` unless in a few special-cases when -/// instantiating canonical responses and in the new solver. Each -/// such case should have a comment explaining why it is used. -#[derive(Debug, Copy, Clone)] -pub enum StructurallyRelateAliases { - Yes, - No, -} - /// Extra information about why we ended up with a particular variance. /// This is only used to add more information to error messages, and /// has no effect on soundness. While choosing the 'wrong' `VarianceDiagInfo` diff --git a/compiler/rustc_type_ir/src/relate/combine.rs b/compiler/rustc_type_ir/src/relate/combine.rs index 26751ab71df5e..9ac4cd2dddc81 100644 --- a/compiler/rustc_type_ir/src/relate/combine.rs +++ b/compiler/rustc_type_ir/src/relate/combine.rs @@ -3,8 +3,7 @@ use std::iter; use tracing::debug; use super::{ - ExpectedFound, RelateResult, StructurallyRelateAliases, TypeRelation, - structurally_relate_consts, structurally_relate_tys, + ExpectedFound, RelateResult, TypeRelation, structurally_relate_consts, structurally_relate_tys, }; use crate::error::TypeError; use crate::inherent::*; @@ -23,11 +22,6 @@ where fn param_env(&self) -> I::ParamEnv; - /// Whether aliases should be related structurally. This is pretty much - /// always `No` unless you're equating in some specific locations of the - /// new solver. See the comments in these use-cases for more details. - fn structurally_relate_aliases(&self) -> StructurallyRelateAliases; - /// Register obligations that must hold in order for this relation to hold fn register_goals(&mut self, obligations: impl IntoIterator>); @@ -115,8 +109,7 @@ where } (ty::Alias(ty::IsRigid::No, alias), _) | (_, ty::Alias(ty::IsRigid::No, alias)) - if infcx.next_trait_solver() - && let StructurallyRelateAliases::No = relation.structurally_relate_aliases() => + if infcx.next_trait_solver() => { // If both sides are aliases, arbitrarily do the LHS first let terms_are_inverted = !matches!(a.kind(), ty::Alias(ty::IsRigid::No, _)); @@ -249,8 +242,7 @@ where (ty::ConstKind::Alias(ty::IsRigid::No, alias), _) | (_, ty::ConstKind::Alias(ty::IsRigid::No, alias)) - if (infcx.cx().features().generic_const_exprs() || infcx.next_trait_solver()) - && let StructurallyRelateAliases::No = relation.structurally_relate_aliases() => + if (infcx.cx().features().generic_const_exprs() || infcx.next_trait_solver()) => { if infcx.next_trait_solver() { let other = if matches!(a.kind(), ty::ConstKind::Alias(..)) { b } else { a }; diff --git a/compiler/rustc_type_ir/src/relate/solver_relating.rs b/compiler/rustc_type_ir/src/relate/solver_relating.rs index 2bc9e8c6cfa9c..85ca047fb7043 100644 --- a/compiler/rustc_type_ir/src/relate/solver_relating.rs +++ b/compiler/rustc_type_ir/src/relate/solver_relating.rs @@ -19,17 +19,6 @@ pub trait RelateExt: InferCtxtLike { Vec::Predicate>>, TypeError, >; - - fn eq_structurally_relating_aliases>( - &self, - param_env: ::ParamEnv, - lhs: T, - rhs: T, - span: ::Span, - ) -> Result< - Vec::Predicate>>, - TypeError, - >; } impl RelateExt for Infcx { @@ -44,29 +33,7 @@ impl RelateExt for Infcx { Vec::Predicate>>, TypeError, > { - let mut relate = - SolverRelating::new(self, StructurallyRelateAliases::No, variance, param_env, span); - relate.relate(lhs, rhs)?; - Ok(relate.goals) - } - - fn eq_structurally_relating_aliases>( - &self, - param_env: ::ParamEnv, - lhs: T, - rhs: T, - span: ::Span, - ) -> Result< - Vec::Predicate>>, - TypeError, - > { - let mut relate = SolverRelating::new( - self, - StructurallyRelateAliases::Yes, - ty::Invariant, - param_env, - span, - ); + let mut relate = SolverRelating::new(self, variance, param_env, span); relate.relate(lhs, rhs)?; Ok(relate.goals) } @@ -76,7 +43,6 @@ impl RelateExt for Infcx { pub struct SolverRelating<'infcx, Infcx, I: Interner> { infcx: &'infcx Infcx, // Immutable fields. - structurally_relate_aliases: StructurallyRelateAliases, param_env: I::ParamEnv, span: I::Span, // Mutable fields. @@ -114,14 +80,12 @@ where { pub fn new( infcx: &'infcx Infcx, - structurally_relate_aliases: StructurallyRelateAliases, ambient_variance: ty::Variance, param_env: I::ParamEnv, span: I::Span, ) -> Self { SolverRelating { infcx, - structurally_relate_aliases, span, ambient_variance, param_env, @@ -366,10 +330,6 @@ where self.param_env } - fn structurally_relate_aliases(&self) -> StructurallyRelateAliases { - self.structurally_relate_aliases - } - fn register_predicates( &mut self, obligations: impl IntoIterator>, From 33d6455bbd0ca3aeda55444f1a87e69c07285cba Mon Sep 17 00:00:00 2001 From: Adwin White Date: Fri, 17 Jul 2026 11:54:01 +0800 Subject: [PATCH 3/3] add universe assert in instantiation --- .../src/infer/relate/generalize.rs | 11 ++++++ compiler/rustc_type_ir/src/universe.rs | 36 ++++++++++++++----- 2 files changed, 38 insertions(+), 9 deletions(-) diff --git a/compiler/rustc_infer/src/infer/relate/generalize.rs b/compiler/rustc_infer/src/infer/relate/generalize.rs index d6bac5a274e64..88d0c20b178fa 100644 --- a/compiler/rustc_infer/src/infer/relate/generalize.rs +++ b/compiler/rustc_infer/src/infer/relate/generalize.rs @@ -297,6 +297,12 @@ 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) } } @@ -304,6 +310,11 @@ impl<'tcx> InferCtxt<'tcx> { 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() diff --git a/compiler/rustc_type_ir/src/universe.rs b/compiler/rustc_type_ir/src/universe.rs index 9b0990d4d0ff0..86d23baae6a89 100644 --- a/compiler/rustc_type_ir/src/universe.rs +++ b/compiler/rustc_type_ir/src/universe.rs @@ -1,3 +1,4 @@ +use rustc_data_structures::fx::FxHashSet; use tracing::{debug, instrument}; use crate::inherent::*; @@ -49,11 +50,11 @@ fn max_universe_inner< infcx: &Infcx, t: T, ) -> UniverseIndex { - if !MaxUniverse::::needs_visit(&t) { + if !MaxUniverse::::needs_visit(&t) { return UniverseIndex::ROOT; } - let mut visitor = MaxUniverse::<_, VISIT_PLACEHOLDER, VISIT_INFER>::new(infcx); + let mut visitor = MaxUniverse::<_, _, VISIT_PLACEHOLDER, VISIT_INFER>::new(infcx); // FIXME: make this a debug_assert and let callers resolve vars if there's // perf win here. let t = infcx.resolve_vars_if_possible(t); @@ -61,17 +62,28 @@ fn max_universe_inner< visitor.max_universe() } -struct MaxUniverse<'a, Infcx: InferCtxtLike, const VISIT_PLACEHOLDER: bool, const VISIT_INFER: bool> -{ +struct MaxUniverse< + 'a, + Infcx: InferCtxtLike, + I: Interner, + const VISIT_PLACEHOLDER: bool, + const VISIT_INFER: bool, +> { max_universe: UniverseIndex, infcx: &'a Infcx, + cache: FxHashSet, } -impl<'a, Infcx: InferCtxtLike, const VISIT_PLACEHOLDER: bool, const VISIT_INFER: bool> - MaxUniverse<'a, Infcx, VISIT_PLACEHOLDER, VISIT_INFER> +impl< + 'a, + Infcx: InferCtxtLike, + I: Interner, + const VISIT_PLACEHOLDER: bool, + const VISIT_INFER: bool, +> MaxUniverse<'a, Infcx, I, VISIT_PLACEHOLDER, VISIT_INFER> { fn new(infcx: &'a Infcx) -> Self { - MaxUniverse { infcx, max_universe: UniverseIndex::ROOT } + MaxUniverse { infcx, max_universe: UniverseIndex::ROOT, cache: Default::default() } } fn max_universe(self) -> UniverseIndex { @@ -79,7 +91,7 @@ impl<'a, Infcx: InferCtxtLike, const VISIT_PLACEHOLDER: bool, const VISIT_INFER: } #[instrument(ret, level = "debug")] - fn needs_visit, I: Interner>(t: &T) -> bool { + fn needs_visit>(t: &T) -> bool { (VISIT_PLACEHOLDER && t.has_placeholders()) || (VISIT_INFER && t.has_infer()) } } @@ -90,7 +102,7 @@ impl< I: Interner, const VISIT_PLACEHOLDER: bool, const VISIT_INFER: bool, -> TypeVisitor for MaxUniverse<'a, Infcx, VISIT_PLACEHOLDER, VISIT_INFER> +> TypeVisitor for MaxUniverse<'a, Infcx, I, VISIT_PLACEHOLDER, VISIT_INFER> { type Result = (); @@ -99,6 +111,10 @@ impl< return; } + if self.cache.contains(&t) { + return; + } + match t.kind() { TyKind::Placeholder(p) if VISIT_PLACEHOLDER => { self.max_universe = self.max_universe.max(p.universe) @@ -110,6 +126,8 @@ impl< } _ => t.super_visit_with(self), } + + assert!(self.cache.insert(t), "we shouldn't visit {t:?} twice"); } fn visit_const(&mut self, c: I::Const) {