From a39003660da2f444a518b8593d2aba66705bc9da Mon Sep 17 00:00:00 2001 From: Dnreikronos Date: Mon, 15 Jun 2026 11:59:10 -0300 Subject: [PATCH 1/3] resolve region inference vars when computing their max universe The `MaxUniverse` region visitor matched on `ReVar` terms and unwrapped `universe_of_lt`, which returns `None` for a variable that has already been unified with another region. Such resolved variables can reach the visitor while computing region assumptions under `-Zassumptions-on-binders`, causing an ICE. Resolve the variable first and inspect whatever it points at instead of assuming it is still an unresolved inference variable. --- .../rustc_type_ir/src/region_constraint.rs | 23 +++++++++++++--- .../resolved-region-var-max-universe.rs | 26 +++++++++++++++++++ .../resolved-region-var-max-universe.stderr | 14 ++++++++++ 3 files changed, 60 insertions(+), 3 deletions(-) create mode 100644 tests/ui/assumptions_on_binders/resolved-region-var-max-universe.rs create mode 100644 tests/ui/assumptions_on_binders/resolved-region-var-max-universe.stderr diff --git a/compiler/rustc_type_ir/src/region_constraint.rs b/compiler/rustc_type_ir/src/region_constraint.rs index 4b23bfd0f7765..6f13eedda4983 100644 --- a/compiler/rustc_type_ir/src/region_constraint.rs +++ b/compiler/rustc_type_ir/src/region_constraint.rs @@ -1013,6 +1013,10 @@ impl<'a, Infcx: InferCtxtLike, I: Interner> TypeVisitor match t.kind() { TyKind::Placeholder(p) => self.max_universe = self.max_universe.max(p.universe), TyKind::Infer(InferTy::TyVar(inf)) => { + // Unlike `visit_region`, we don't resolve the variable first: callers + // computing assumptions bail on any non-region inference variable + // before reaching here, so a type infer var is always unresolved and + // has a universe. let u = self.infcx.universe_of_ty(inf).unwrap(); debug!("var {inf:?} in universe {u:?}"); self.max_universe = self.max_universe.max(u); @@ -1025,6 +1029,8 @@ impl<'a, Infcx: InferCtxtLike, I: Interner> TypeVisitor match c.kind() { ConstKind::Placeholder(p) => self.max_universe = self.max_universe.max(p.universe), ConstKind::Infer(rustc_type_ir::InferConst::Var(inf)) => { + // See the comment in `visit_ty`: a const infer var is always + // unresolved here, so unlike a region it needs no resolving first. let u = self.infcx.universe_of_ct(inf).unwrap(); debug!("var {inf:?} in universe {u:?}"); self.max_universe = self.max_universe.max(u); @@ -1037,9 +1043,20 @@ impl<'a, Infcx: InferCtxtLike, I: Interner> TypeVisitor match r.kind() { RegionKind::RePlaceholder(p) => self.max_universe = self.max_universe.max(p.universe), RegionKind::ReVar(var) => { - let u = self.infcx.universe_of_lt(var).unwrap(); - debug!("var {var:?} in universe {u:?}"); - self.max_universe = self.max_universe.max(u); + // The variable may already have been unified with another region. + // `universe_of_lt` returns `None` for a resolved variable, so resolve + // it first and inspect whatever it points at. + match self.infcx.opportunistic_resolve_lt_var(var).kind() { + RegionKind::RePlaceholder(p) => { + self.max_universe = self.max_universe.max(p.universe) + } + RegionKind::ReVar(var) => { + let u = self.infcx.universe_of_lt(var).unwrap(); + debug!("var {var:?} in universe {u:?}"); + self.max_universe = self.max_universe.max(u); + } + _ => (), + } } _ => (), } diff --git a/tests/ui/assumptions_on_binders/resolved-region-var-max-universe.rs b/tests/ui/assumptions_on_binders/resolved-region-var-max-universe.rs new file mode 100644 index 0000000000000..f0286fb92453a --- /dev/null +++ b/tests/ui/assumptions_on_binders/resolved-region-var-max-universe.rs @@ -0,0 +1,26 @@ +//@ compile-flags: -Zassumptions-on-binders -Znext-solver=globally + +// Regression test for an ICE in the `MaxUniverse` region visitor. When computing +// the max universe of a region constraint, a `ReVar` term could already have been +// unified with another region. `universe_of_lt` returns `None` for such a resolved +// variable, so the visitor used to `unwrap()` `None` and panic. It now resolves the +// variable before inspecting its universe. + +#![feature(min_generic_const_args, inherent_associated_types, generic_const_items)] + +struct Parent<'a> { + a: &'a str, +} + +impl<'a> Parent<'a> { + type const CT: usize = 0; +} + +fn check/**/() +where + [(); Parent::CT::]:, + //~^ ERROR cannot find type `T` in this scope +{ +} + +fn main() {} diff --git a/tests/ui/assumptions_on_binders/resolved-region-var-max-universe.stderr b/tests/ui/assumptions_on_binders/resolved-region-var-max-universe.stderr new file mode 100644 index 0000000000000..6fa91876dd47b --- /dev/null +++ b/tests/ui/assumptions_on_binders/resolved-region-var-max-universe.stderr @@ -0,0 +1,14 @@ +error[E0425]: cannot find type `T` in this scope + --> $DIR/resolved-region-var-max-universe.rs:21:23 + | +LL | [(); Parent::CT::]:, + | ^ not found in this scope + | +help: you might be missing a type parameter + | +LL | fn check/**/() + | +++ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0425`. From 3bb0a1c892df204b9cdeca8aa394e7367680db9f Mon Sep 17 00:00:00 2001 From: Dnreikronos Date: Sat, 20 Jun 2026 15:54:57 -0300 Subject: [PATCH 2/3] Resolve vars before computing max universe --- compiler/rustc_type_ir/src/region_constraint.rs | 14 ++++---------- .../resolved-region-var-max-universe.rs | 8 +++++--- .../resolved-region-var-max-universe.stderr | 4 ++-- 3 files changed, 11 insertions(+), 15 deletions(-) diff --git a/compiler/rustc_type_ir/src/region_constraint.rs b/compiler/rustc_type_ir/src/region_constraint.rs index 6f13eedda4983..3bc0502b4f3cb 100644 --- a/compiler/rustc_type_ir/src/region_constraint.rs +++ b/compiler/rustc_type_ir/src/region_constraint.rs @@ -978,11 +978,14 @@ pub fn regions_outlived_by_placeholder( } /// The largest universe a variable or placeholder was from in `t` -pub fn max_universe, I: Interner, T: TypeVisitable>( +pub fn max_universe, I: Interner, T: TypeFoldable>( infcx: &Infcx, t: T, ) -> UniverseIndex { let mut visitor = MaxUniverse::new(infcx); + // `max_universe` is also used while rewriting constraints to lower universes, + // so do not rely on callers having already resolved non-region infer vars. + let t = infcx.resolve_vars_if_possible(t); t.visit_with(&mut visitor); visitor.max_universe() } @@ -1013,10 +1016,6 @@ impl<'a, Infcx: InferCtxtLike, I: Interner> TypeVisitor match t.kind() { TyKind::Placeholder(p) => self.max_universe = self.max_universe.max(p.universe), TyKind::Infer(InferTy::TyVar(inf)) => { - // Unlike `visit_region`, we don't resolve the variable first: callers - // computing assumptions bail on any non-region inference variable - // before reaching here, so a type infer var is always unresolved and - // has a universe. let u = self.infcx.universe_of_ty(inf).unwrap(); debug!("var {inf:?} in universe {u:?}"); self.max_universe = self.max_universe.max(u); @@ -1029,8 +1028,6 @@ impl<'a, Infcx: InferCtxtLike, I: Interner> TypeVisitor match c.kind() { ConstKind::Placeholder(p) => self.max_universe = self.max_universe.max(p.universe), ConstKind::Infer(rustc_type_ir::InferConst::Var(inf)) => { - // See the comment in `visit_ty`: a const infer var is always - // unresolved here, so unlike a region it needs no resolving first. let u = self.infcx.universe_of_ct(inf).unwrap(); debug!("var {inf:?} in universe {u:?}"); self.max_universe = self.max_universe.max(u); @@ -1043,9 +1040,6 @@ impl<'a, Infcx: InferCtxtLike, I: Interner> TypeVisitor match r.kind() { RegionKind::RePlaceholder(p) => self.max_universe = self.max_universe.max(p.universe), RegionKind::ReVar(var) => { - // The variable may already have been unified with another region. - // `universe_of_lt` returns `None` for a resolved variable, so resolve - // it first and inspect whatever it points at. match self.infcx.opportunistic_resolve_lt_var(var).kind() { RegionKind::RePlaceholder(p) => { self.max_universe = self.max_universe.max(p.universe) diff --git a/tests/ui/assumptions_on_binders/resolved-region-var-max-universe.rs b/tests/ui/assumptions_on_binders/resolved-region-var-max-universe.rs index f0286fb92453a..46c9aacdd93d9 100644 --- a/tests/ui/assumptions_on_binders/resolved-region-var-max-universe.rs +++ b/tests/ui/assumptions_on_binders/resolved-region-var-max-universe.rs @@ -3,8 +3,10 @@ // Regression test for an ICE in the `MaxUniverse` region visitor. When computing // the max universe of a region constraint, a `ReVar` term could already have been // unified with another region. `universe_of_lt` returns `None` for such a resolved -// variable, so the visitor used to `unwrap()` `None` and panic. It now resolves the -// variable before inspecting its universe. +// variable, so the visitor used to `unwrap()` `None` and panic. +// +// The missing `T` in `check` is intentional. It makes HIR ty lowering emit an +// error while still leaving behind the region constraint that used to ICE. #![feature(min_generic_const_args, inherent_associated_types, generic_const_items)] @@ -16,7 +18,7 @@ impl<'a> Parent<'a> { type const CT: usize = 0; } -fn check/**/() +fn check() where [(); Parent::CT::]:, //~^ ERROR cannot find type `T` in this scope diff --git a/tests/ui/assumptions_on_binders/resolved-region-var-max-universe.stderr b/tests/ui/assumptions_on_binders/resolved-region-var-max-universe.stderr index 6fa91876dd47b..e77a0994fc2db 100644 --- a/tests/ui/assumptions_on_binders/resolved-region-var-max-universe.stderr +++ b/tests/ui/assumptions_on_binders/resolved-region-var-max-universe.stderr @@ -1,12 +1,12 @@ error[E0425]: cannot find type `T` in this scope - --> $DIR/resolved-region-var-max-universe.rs:21:23 + --> $DIR/resolved-region-var-max-universe.rs:23:23 | LL | [(); Parent::CT::]:, | ^ not found in this scope | help: you might be missing a type parameter | -LL | fn check/**/() +LL | fn check() | +++ error: aborting due to 1 previous error From a44ab8d43042ffe67ab5e288a765f181d4474dc4 Mon Sep 17 00:00:00 2001 From: Dnreikronos Date: Sat, 20 Jun 2026 16:05:13 -0300 Subject: [PATCH 3/3] Format max universe visitor --- .../rustc_type_ir/src/region_constraint.rs | 22 +++++++++---------- 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/compiler/rustc_type_ir/src/region_constraint.rs b/compiler/rustc_type_ir/src/region_constraint.rs index 3bc0502b4f3cb..2ba2d40f3a540 100644 --- a/compiler/rustc_type_ir/src/region_constraint.rs +++ b/compiler/rustc_type_ir/src/region_constraint.rs @@ -1039,19 +1039,17 @@ impl<'a, Infcx: InferCtxtLike, I: Interner> TypeVisitor fn visit_region(&mut self, r: I::Region) { match r.kind() { RegionKind::RePlaceholder(p) => self.max_universe = self.max_universe.max(p.universe), - RegionKind::ReVar(var) => { - match self.infcx.opportunistic_resolve_lt_var(var).kind() { - RegionKind::RePlaceholder(p) => { - self.max_universe = self.max_universe.max(p.universe) - } - RegionKind::ReVar(var) => { - let u = self.infcx.universe_of_lt(var).unwrap(); - debug!("var {var:?} in universe {u:?}"); - self.max_universe = self.max_universe.max(u); - } - _ => (), + RegionKind::ReVar(var) => match self.infcx.opportunistic_resolve_lt_var(var).kind() { + RegionKind::RePlaceholder(p) => { + self.max_universe = self.max_universe.max(p.universe) } - } + RegionKind::ReVar(var) => { + let u = self.infcx.universe_of_lt(var).unwrap(); + debug!("var {var:?} in universe {u:?}"); + self.max_universe = self.max_universe.max(u); + } + _ => (), + }, _ => (), } }