Skip to content

Delay replacing escaping bound vars in FindParamInClause #142441

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

Merged
merged 5 commits into from
Jun 14, 2025
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 Cargo.lock
Original file line number Diff line number Diff line change
Expand Up @@ -4618,7 +4618,7 @@ dependencies = [
"derive-where",
"ena",
"indexmap",
"rustc-hash 1.1.0",
"rustc-hash 2.1.1",
"rustc_ast_ir",
"rustc_data_structures",
"rustc_index",
Expand Down
6 changes: 3 additions & 3 deletions compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ use rustc_hir::def::{DefKind, Res};
use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_middle::bug;
use rustc_middle::ty::{
self as ty, IsSuggestable, Ty, TyCtxt, TypeFoldable, TypeSuperVisitable, TypeVisitable,
TypeVisitableExt, TypeVisitor, Upcast,
self as ty, IsSuggestable, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt,
TypeVisitor, Upcast,
};
use rustc_span::{ErrorGuaranteed, Ident, Span, Symbol, kw, sym};
use rustc_trait_selection::traits;
Expand Down Expand Up @@ -927,7 +927,7 @@ struct GenericParamAndBoundVarCollector<'a, 'tcx> {
impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for GenericParamAndBoundVarCollector<'_, 'tcx> {
type Result = ControlFlow<ErrorGuaranteed>;

fn visit_binder<T: TypeFoldable<TyCtxt<'tcx>>>(
fn visit_binder<T: TypeVisitable<TyCtxt<'tcx>>>(
&mut self,
binder: &ty::Binder<'tcx, T>,
) -> Self::Result {
Expand Down
5 changes: 2 additions & 3 deletions compiler/rustc_lint/src/impl_trait_overcaptures.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,7 @@ use rustc_middle::ty::relate::{
Relate, RelateResult, TypeRelation, structurally_relate_consts, structurally_relate_tys,
};
use rustc_middle::ty::{
self, Ty, TyCtxt, TypeFoldable, TypeSuperVisitable, TypeVisitable, TypeVisitableExt,
TypeVisitor,
self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor,
};
use rustc_middle::{bug, span_bug};
use rustc_session::lint::FutureIncompatibilityReason;
Expand Down Expand Up @@ -210,7 +209,7 @@ where
VarFn: FnOnce() -> FxHashMap<DefId, ty::Variance>,
OutlivesFn: FnOnce() -> OutlivesEnvironment<'tcx>,
{
fn visit_binder<T: TypeFoldable<TyCtxt<'tcx>>>(&mut self, t: &ty::Binder<'tcx, T>) {
fn visit_binder<T: TypeVisitable<TyCtxt<'tcx>>>(&mut self, t: &ty::Binder<'tcx, T>) {
// When we get into a binder, we need to add its own bound vars to the scope.
let mut added = vec![];
for arg in t.bound_vars() {
Expand Down
4 changes: 4 additions & 0 deletions compiler/rustc_middle/src/ty/consts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,10 @@ impl<'tcx> rustc_type_ir::inherent::Const<TyCtxt<'tcx>> for Const<'tcx> {
Const::new_bound(tcx, debruijn, var)
}

fn new_placeholder(tcx: TyCtxt<'tcx>, placeholder: ty::PlaceholderConst) -> Self {
Const::new_placeholder(tcx, placeholder)
}

fn new_unevaluated(interner: TyCtxt<'tcx>, uv: ty::UnevaluatedConst<'tcx>) -> Self {
Const::new_unevaluated(interner, uv)
}
Expand Down
30 changes: 24 additions & 6 deletions compiler/rustc_middle/src/ty/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -933,7 +933,9 @@ impl Placeholder<BoundVar> {

pub type PlaceholderRegion = Placeholder<BoundRegion>;

impl rustc_type_ir::inherent::PlaceholderLike for PlaceholderRegion {
impl<'tcx> rustc_type_ir::inherent::PlaceholderLike<TyCtxt<'tcx>> for PlaceholderRegion {
type Bound = BoundRegion;

fn universe(self) -> UniverseIndex {
self.universe
}
Expand All @@ -946,14 +948,20 @@ impl rustc_type_ir::inherent::PlaceholderLike for PlaceholderRegion {
Placeholder { universe: ui, ..self }
}

fn new(ui: UniverseIndex, var: BoundVar) -> Self {
fn new(ui: UniverseIndex, bound: BoundRegion) -> Self {
Placeholder { universe: ui, bound }
}

fn new_anon(ui: UniverseIndex, var: BoundVar) -> Self {
Placeholder { universe: ui, bound: BoundRegion { var, kind: BoundRegionKind::Anon } }
}
}

pub type PlaceholderType = Placeholder<BoundTy>;

impl rustc_type_ir::inherent::PlaceholderLike for PlaceholderType {
impl<'tcx> rustc_type_ir::inherent::PlaceholderLike<TyCtxt<'tcx>> for PlaceholderType {
type Bound = BoundTy;

fn universe(self) -> UniverseIndex {
self.universe
}
Expand All @@ -966,7 +974,11 @@ impl rustc_type_ir::inherent::PlaceholderLike for PlaceholderType {
Placeholder { universe: ui, ..self }
}

fn new(ui: UniverseIndex, var: BoundVar) -> Self {
fn new(ui: UniverseIndex, bound: BoundTy) -> Self {
Placeholder { universe: ui, bound }
}

fn new_anon(ui: UniverseIndex, var: BoundVar) -> Self {
Placeholder { universe: ui, bound: BoundTy { var, kind: BoundTyKind::Anon } }
}
}
Expand All @@ -980,7 +992,9 @@ pub struct BoundConst<'tcx> {

pub type PlaceholderConst = Placeholder<BoundVar>;

impl rustc_type_ir::inherent::PlaceholderLike for PlaceholderConst {
impl<'tcx> rustc_type_ir::inherent::PlaceholderLike<TyCtxt<'tcx>> for PlaceholderConst {
type Bound = BoundVar;

fn universe(self) -> UniverseIndex {
self.universe
}
Expand All @@ -993,7 +1007,11 @@ impl rustc_type_ir::inherent::PlaceholderLike for PlaceholderConst {
Placeholder { universe: ui, ..self }
}

fn new(ui: UniverseIndex, var: BoundVar) -> Self {
fn new(ui: UniverseIndex, bound: BoundVar) -> Self {
Placeholder { universe: ui, bound }
}

fn new_anon(ui: UniverseIndex, var: BoundVar) -> Self {
Placeholder { universe: ui, bound: var }
}
}
Expand Down
4 changes: 4 additions & 0 deletions compiler/rustc_middle/src/ty/region.rs
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,10 @@ impl<'tcx> rustc_type_ir::inherent::Region<TyCtxt<'tcx>> for Region<'tcx> {
Region::new_bound(tcx, debruijn, ty::BoundRegion { var, kind: ty::BoundRegionKind::Anon })
}

fn new_placeholder(tcx: TyCtxt<'tcx>, placeholder: ty::PlaceholderRegion) -> Self {
Region::new_placeholder(tcx, placeholder)
}

fn new_static(tcx: TyCtxt<'tcx>) -> Self {
tcx.lifetimes.re_static
}
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_middle/src/ty/visit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ impl<'tcx> TyCtxt<'tcx> {
{
type Result = ControlFlow<()>;

fn visit_binder<T: TypeFoldable<TyCtxt<'tcx>>>(
fn visit_binder<T: TypeVisitable<TyCtxt<'tcx>>>(
&mut self,
t: &Binder<'tcx, T>,
) -> Self::Result {
Expand Down Expand Up @@ -168,7 +168,7 @@ impl LateBoundRegionsCollector {
}

impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for LateBoundRegionsCollector {
fn visit_binder<T: TypeFoldable<TyCtxt<'tcx>>>(&mut self, t: &Binder<'tcx, T>) {
fn visit_binder<T: TypeVisitable<TyCtxt<'tcx>>>(&mut self, t: &Binder<'tcx, T>) {
self.current_index.shift_in(1);
t.super_visit_with(self);
self.current_index.shift_out(1);
Expand Down
8 changes: 4 additions & 4 deletions compiler/rustc_next_trait_solver/src/canonicalizer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -435,13 +435,13 @@ impl<'a, D: SolverDelegate<Interner = I>, I: Interner> Canonicalizer<'a, D, I> {
},
ty::Placeholder(placeholder) => match self.canonicalize_mode {
CanonicalizeMode::Input { .. } => CanonicalVarKind::PlaceholderTy(
PlaceholderLike::new(placeholder.universe(), self.variables.len().into()),
PlaceholderLike::new_anon(placeholder.universe(), self.variables.len().into()),
),
CanonicalizeMode::Response { .. } => CanonicalVarKind::PlaceholderTy(placeholder),
},
ty::Param(_) => match self.canonicalize_mode {
CanonicalizeMode::Input { .. } => CanonicalVarKind::PlaceholderTy(
PlaceholderLike::new(ty::UniverseIndex::ROOT, self.variables.len().into()),
PlaceholderLike::new_anon(ty::UniverseIndex::ROOT, self.variables.len().into()),
),
CanonicalizeMode::Response { .. } => panic!("param ty in response: {t:?}"),
},
Expand Down Expand Up @@ -594,15 +594,15 @@ impl<D: SolverDelegate<Interner = I>, I: Interner> TypeFolder<I> for Canonicaliz
},
ty::ConstKind::Placeholder(placeholder) => match self.canonicalize_mode {
CanonicalizeMode::Input { .. } => CanonicalVarKind::PlaceholderConst(
PlaceholderLike::new(placeholder.universe(), self.variables.len().into()),
PlaceholderLike::new_anon(placeholder.universe(), self.variables.len().into()),
),
CanonicalizeMode::Response { .. } => {
CanonicalVarKind::PlaceholderConst(placeholder)
}
},
ty::ConstKind::Param(_) => match self.canonicalize_mode {
CanonicalizeMode::Input { .. } => CanonicalVarKind::PlaceholderConst(
PlaceholderLike::new(ty::UniverseIndex::ROOT, self.variables.len().into()),
PlaceholderLike::new_anon(ty::UniverseIndex::ROOT, self.variables.len().into()),
),
CanonicalizeMode::Response { .. } => panic!("param ty in response: {c:?}"),
},
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_next_trait_solver/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,6 @@
pub mod canonicalizer;
pub mod coherence;
pub mod delegate;
pub mod placeholder;
pub mod resolve;
pub mod solve;
158 changes: 158 additions & 0 deletions compiler/rustc_next_trait_solver/src/placeholder.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
use core::panic;

use rustc_type_ir::data_structures::IndexMap;
use rustc_type_ir::inherent::*;
use rustc_type_ir::{
self as ty, InferCtxtLike, Interner, TypeFoldable, TypeFolder, TypeSuperFoldable,
TypeVisitableExt,
};

pub struct BoundVarReplacer<'a, Infcx, I = <Infcx as InferCtxtLike>::Interner>
where
Infcx: InferCtxtLike<Interner = I>,
I: Interner,
{
infcx: &'a Infcx,
// These three maps track the bound variable that were replaced by placeholders. It might be
// nice to remove these since we already have the `kind` in the placeholder; we really just need
// the `var` (but we *could* bring that into scope if we were to track them as we pass them).
mapped_regions: IndexMap<I::PlaceholderRegion, I::BoundRegion>,
mapped_types: IndexMap<I::PlaceholderTy, I::BoundTy>,
mapped_consts: IndexMap<I::PlaceholderConst, I::BoundConst>,
// The current depth relative to *this* folding, *not* the entire normalization. In other words,
// the depth of binders we've passed here.
current_index: ty::DebruijnIndex,
// The `UniverseIndex` of the binding levels above us. These are optional, since we are lazy:
// we don't actually create a universe until we see a bound var we have to replace.
universe_indices: &'a mut Vec<Option<ty::UniverseIndex>>,
}

impl<'a, Infcx, I> BoundVarReplacer<'a, Infcx, I>
where
Infcx: InferCtxtLike<Interner = I>,
I: Interner,
{
/// Returns `Some` if we *were* able to replace bound vars. If there are any bound vars that
/// use a binding level above `universe_indices.len()`, we fail.
pub fn replace_bound_vars<T: TypeFoldable<I>>(
infcx: &'a Infcx,
universe_indices: &'a mut Vec<Option<ty::UniverseIndex>>,
value: T,
) -> (
T,
IndexMap<I::PlaceholderRegion, I::BoundRegion>,
IndexMap<I::PlaceholderTy, I::BoundTy>,
IndexMap<I::PlaceholderConst, I::BoundConst>,
) {
let mut replacer = BoundVarReplacer {
infcx,
mapped_regions: Default::default(),
mapped_types: Default::default(),
mapped_consts: Default::default(),
current_index: ty::INNERMOST,
universe_indices,
};

let value = value.fold_with(&mut replacer);

(value, replacer.mapped_regions, replacer.mapped_types, replacer.mapped_consts)
}

fn universe_for(&mut self, debruijn: ty::DebruijnIndex) -> ty::UniverseIndex {
let infcx = self.infcx;
let index =
self.universe_indices.len() + self.current_index.as_usize() - debruijn.as_usize() - 1;
let universe = self.universe_indices[index].unwrap_or_else(|| {
for i in self.universe_indices.iter_mut().take(index + 1) {
*i = i.or_else(|| Some(infcx.create_next_universe()))
}
self.universe_indices[index].unwrap()
});
universe
}
}

impl<Infcx, I> TypeFolder<I> for BoundVarReplacer<'_, Infcx, I>
where
Infcx: InferCtxtLike<Interner = I>,
I: Interner,
{
fn cx(&self) -> I {
self.infcx.cx()
}

fn fold_binder<T: TypeFoldable<I>>(&mut self, t: ty::Binder<I, T>) -> ty::Binder<I, T> {
self.current_index.shift_in(1);
let t = t.super_fold_with(self);
self.current_index.shift_out(1);
t
}

fn fold_region(&mut self, r: I::Region) -> I::Region {
match r.kind() {
ty::ReBound(debruijn, _)
if debruijn.as_usize()
>= self.current_index.as_usize() + self.universe_indices.len() =>
{
panic!(
"Bound vars {r:#?} outside of `self.universe_indices`: {:#?}",
self.universe_indices
);
}
ty::ReBound(debruijn, br) if debruijn >= self.current_index => {
let universe = self.universe_for(debruijn);
let p = PlaceholderLike::new(universe, br);
self.mapped_regions.insert(p, br);
Region::new_placeholder(self.cx(), p)
}
_ => r,
}
}

fn fold_ty(&mut self, t: I::Ty) -> I::Ty {
match t.kind() {
ty::Bound(debruijn, _)
if debruijn.as_usize() + 1
> self.current_index.as_usize() + self.universe_indices.len() =>
{
panic!(
"Bound vars {t:#?} outside of `self.universe_indices`: {:#?}",
self.universe_indices
);
}
ty::Bound(debruijn, bound_ty) if debruijn >= self.current_index => {
let universe = self.universe_for(debruijn);
let p = PlaceholderLike::new(universe, bound_ty);
self.mapped_types.insert(p, bound_ty);
Ty::new_placeholder(self.cx(), p)
}
_ if t.has_vars_bound_at_or_above(self.current_index) => t.super_fold_with(self),
_ => t,
}
}

fn fold_const(&mut self, ct: I::Const) -> I::Const {
match ct.kind() {
ty::ConstKind::Bound(debruijn, _)
if debruijn.as_usize() + 1
> self.current_index.as_usize() + self.universe_indices.len() =>
{
panic!(
"Bound vars {ct:#?} outside of `self.universe_indices`: {:#?}",
self.universe_indices
);
}
ty::ConstKind::Bound(debruijn, bound_const) if debruijn >= self.current_index => {
let universe = self.universe_for(debruijn);
let p = PlaceholderLike::new(universe, bound_const);
self.mapped_consts.insert(p, bound_const);
Const::new_placeholder(self.cx(), p)
}
_ => ct.super_fold_with(self),
}
}

fn fold_predicate(&mut self, p: I::Predicate) -> I::Predicate {
if p.has_vars_bound_at_or_above(self.current_index) { p.super_fold_with(self) } else { p }
}
}
Loading
Loading