about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_borrowck/src/handle_placeholders.rs4
-rw-r--r--compiler/rustc_borrowck/src/region_infer/mod.rs9
-rw-r--r--tests/ui/nll/member-constraints/non-root-universe-existential-1.rs29
-rw-r--r--tests/ui/nll/member-constraints/non-root-universe-existential-2.rs31
4 files changed, 72 insertions, 1 deletions
diff --git a/compiler/rustc_borrowck/src/handle_placeholders.rs b/compiler/rustc_borrowck/src/handle_placeholders.rs
index 34599ac55b8..1614c112ab5 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 b0c31ac9601..c76c5c17431 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 00000000000..39dbfebce10
--- /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<F: for<'a> 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 00000000000..c5ddde0d7d8
--- /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 simply 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<Type>);
+enum TypeTreeValueIter<'a, T> {
+    Once(T),
+    Ref(&'a ()),
+}
+
+impl<'a, T> Iterator for TypeTreeValueIter<'a, T> {
+    type Item = T;
+
+    fn next(&mut self) -> Option<Self::Item> {
+        loop {}
+    }
+}
+
+fn item<I: Iterator<Item: Iterator>>(x: I) -> <I::Item as Iterator>::Item {
+    loop {}
+}
+
+fn get_type_tree_values<'a>(ty: &'a Type) -> impl Iterator<Item = &'a Type> {
+    let _: &'a Type = item(std::iter::once(ty).map(get_type_tree_values));
+    TypeTreeValueIter::<'a, &'a Type>::Once(ty)
+}
+
+fn main() {}