From 6fb9b639176375612bb63d863f2ddf1cd1037d69 Mon Sep 17 00:00:00 2001 From: lcnr Date: Thu, 5 Jun 2025 12:01:20 +0200 Subject: [PATCH] apply_member_constraints: fix placeholder check --- .../rustc_borrowck/src/handle_placeholders.rs | 4 +++ .../rustc_borrowck/src/region_infer/mod.rs | 9 +++++- .../non-root-universe-existential-1.rs | 29 +++++++++++++++++ .../non-root-universe-existential-2.rs | 31 +++++++++++++++++++ 4 files changed, 72 insertions(+), 1 deletion(-) create mode 100644 tests/ui/nll/member-constraints/non-root-universe-existential-1.rs create mode 100644 tests/ui/nll/member-constraints/non-root-universe-existential-2.rs diff --git a/compiler/rustc_borrowck/src/handle_placeholders.rs b/compiler/rustc_borrowck/src/handle_placeholders.rs index aaaf2f45c869d..8893ba662ae67 100644 --- a/compiler/rustc_borrowck/src/handle_placeholders.rs +++ b/compiler/rustc_borrowck/src/handle_placeholders.rs @@ -103,6 +103,10 @@ impl RegionTracker { self.max_nameable_universe } + pub(crate) fn max_placeholder_universe_reached(self) -> UniverseIndex { + self.max_placeholder_universe_reached + } + fn merge_min_max_seen(&mut self, other: &Self) { self.max_placeholder_universe_reached = std::cmp::max( self.max_placeholder_universe_reached, diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs index 5f1b655c6b60d..2f1c1d7cd6109 100644 --- a/compiler/rustc_borrowck/src/region_infer/mod.rs +++ b/compiler/rustc_borrowck/src/region_infer/mod.rs @@ -713,7 +713,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { // If the member region lives in a higher universe, we currently choose // the most conservative option by leaving it unchanged. - if !self.max_nameable_universe(scc).is_root() { + if !self.max_placeholder_universe_reached(scc).is_root() { return; } @@ -1376,6 +1376,13 @@ impl<'tcx> RegionInferenceContext<'tcx> { self.scc_annotations[scc].max_nameable_universe() } + pub(crate) fn max_placeholder_universe_reached( + &self, + scc: ConstraintSccIndex, + ) -> UniverseIndex { + self.scc_annotations[scc].max_placeholder_universe_reached() + } + /// Checks the final value for the free region `fr` to see if it /// grew too large. In particular, examine what `end(X)` points /// wound up in `fr`'s final value; for each `end(X)` where `X != diff --git a/tests/ui/nll/member-constraints/non-root-universe-existential-1.rs b/tests/ui/nll/member-constraints/non-root-universe-existential-1.rs new file mode 100644 index 0000000000000..39dbfebce10aa --- /dev/null +++ b/tests/ui/nll/member-constraints/non-root-universe-existential-1.rs @@ -0,0 +1,29 @@ +//@ check-pass +//@ revisions: current next +//@ ignore-compare-mode-next-solver (explicit revisions) +//@[next] compile-flags: -Znext-solver + +trait Proj<'a> { + type Assoc; +} + +impl<'a, 'b, F: FnOnce() -> &'b ()> Proj<'a> for F { + type Assoc = (); +} + +fn is_proj Proj<'a>>(f: F) {} + +fn define<'a>() -> impl Sized + use<'a> { + // This defines the RPIT to `&'unconstrained_b ()`, an inference + // variable which is in a higher universe as gets created inside + // of the binder of `F: for<'a> Proj<'a>`. This previously caused + // us to not apply member constraints. + // + // This was unnecessary. It is totally acceptable for member regions + // to be able to name placeholders from higher universes, as long as + // they don't actually do so. + is_proj(define::<'a>); + &() +} + +fn main() {} diff --git a/tests/ui/nll/member-constraints/non-root-universe-existential-2.rs b/tests/ui/nll/member-constraints/non-root-universe-existential-2.rs new file mode 100644 index 0000000000000..8d637abad7d3b --- /dev/null +++ b/tests/ui/nll/member-constraints/non-root-universe-existential-2.rs @@ -0,0 +1,31 @@ +//@ check-pass + +// Unlike `non-root-universe-existential-1.rs` this previously +// compiled as it simnply didn't define the hidden type of +// `impl Iterator` when projecting through it. We will do so +// with the new solver. Further minimizing this is challenging. + +struct Type(Vec); +enum TypeTreeValueIter<'a, T> { + Once(T), + Ref(&'a ()), +} + +impl<'a, T> Iterator for TypeTreeValueIter<'a, T> { + type Item = T; + + fn next(&mut self) -> Option { + loop {} + } +} + +fn item>(x: I) -> ::Item { + loop {} +} + +fn get_type_tree_values<'a>(ty: &'a Type) -> impl Iterator { + let _: &'a Type = item(std::iter::once(ty).map(get_type_tree_values)); + TypeTreeValueIter::<'a, &'a Type>::Once(ty) +} + +fn main() {}