about summary refs log tree commit diff
diff options
context:
space:
mode:
authorAli MJ Al-Nasrawy <alimjalnasrawy@gmail.com>2023-07-11 14:24:08 +0000
committerOli Scherer <git-spam-no-reply9815368754983@oli-obk.de>2023-08-04 15:11:09 +0000
commitd55522aad87c5605d7edd5dd4b37926e8b446117 (patch)
tree9631a11dddc9276e5faaac41eacaf88a9a0267f4
parent4f7bb9890c0402cd145556ac1929d13d7524959e (diff)
downloadrust-d55522aad87c5605d7edd5dd4b37926e8b446117.tar.gz
rust-d55522aad87c5605d7edd5dd4b37926e8b446117.zip
don't ICE on higher ranked hidden types
-rw-r--r--compiler/rustc_borrowck/src/region_infer/mod.rs25
-rw-r--r--compiler/rustc_borrowck/src/region_infer/opaque_types.rs15
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/mod.rs9
-rw-r--r--tests/ui/impl-trait/nested-rpit-hrtb-2.rs9
-rw-r--r--tests/ui/impl-trait/nested-rpit-hrtb-2.stderr12
-rw-r--r--tests/ui/type-alias-impl-trait/nested-tait-hrtb.rs15
-rw-r--r--tests/ui/type-alias-impl-trait/nested-tait-hrtb.stderr35
7 files changed, 109 insertions, 11 deletions
diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs
index 30dfb2d919a..b8cd94e5422 100644
--- a/compiler/rustc_borrowck/src/region_infer/mod.rs
+++ b/compiler/rustc_borrowck/src/region_infer/mod.rs
@@ -784,13 +784,20 @@ impl<'tcx> RegionInferenceContext<'tcx> {
     /// is considered a *lower bound*. If possible, we will modify
     /// the constraint to set it equal to one of the option regions.
     /// If we make any changes, returns true, else false.
+    ///
+    /// This function only adds the member constraints to the region graph,
+    /// it does not check them. They are later checked in
+    /// `check_member_constraints` after the region graph has been computed.
     #[instrument(skip(self, member_constraint_index), level = "debug")]
     fn apply_member_constraint(
         &mut self,
         scc: ConstraintSccIndex,
         member_constraint_index: NllMemberConstraintIndex,
         choice_regions: &[ty::RegionVid],
-    ) -> bool {
+    ) {
+        // Lazily compute the reverse graph, we'll need it later.
+        self.compute_reverse_scc_graph();
+
         // Create a mutable vector of the options. We'll try to winnow
         // them down.
         let mut choice_regions: Vec<ty::RegionVid> = choice_regions.to_vec();
@@ -805,10 +812,11 @@ impl<'tcx> RegionInferenceContext<'tcx> {
             *c_r = self.scc_representatives[scc];
         }
 
-        // The 'member region' in a member constraint is part of the
-        // hidden type, which must be in the root universe. Therefore,
-        // it cannot have any placeholders in its value.
-        assert!(self.scc_universes[scc] == ty::UniverseIndex::ROOT);
+        // If the member region lives in a higher universe, we currently choose
+        // the most conservative option by leaving it unchanged.
+        if self.scc_universes[scc] != ty::UniverseIndex::ROOT {
+            return;
+        }
         debug_assert!(
             self.scc_values.placeholders_contained_in(scc).next().is_none(),
             "scc {:?} in a member constraint has placeholder value: {:?}",
@@ -832,7 +840,6 @@ impl<'tcx> RegionInferenceContext<'tcx> {
         // free region that must outlive the member region `R0` (`UB:
         // R0`). Therefore, we need only keep an option `O` if `UB: O`
         // for all UB.
-        self.compute_reverse_scc_graph();
         let universal_region_relations = &self.universal_region_relations;
         for ub in self.rev_scc_graph.as_ref().unwrap().upper_bounds(scc) {
             debug!(?ub);
@@ -867,7 +874,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
             }
         }) else {
             debug!("no unique minimum choice");
-            return false;
+            return;
         };
 
         let min_choice_scc = self.constraint_sccs.scc(min_choice);
@@ -878,10 +885,6 @@ impl<'tcx> RegionInferenceContext<'tcx> {
                 min_choice,
                 member_constraint_index,
             });
-
-            true
-        } else {
-            false
         }
     }
 
diff --git a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs
index 90bde88f792..68dddd65acb 100644
--- a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs
+++ b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs
@@ -185,6 +185,21 @@ impl<'tcx> RegionInferenceContext<'tcx> {
     {
         tcx.fold_regions(ty, |region, _| match *region {
             ty::ReVar(vid) => {
+                let scc = self.constraint_sccs.scc(vid);
+
+                // Special handling of higher-ranked regions.
+                if self.scc_universes[scc] != ty::UniverseIndex::ROOT {
+                    match self.scc_values.placeholders_contained_in(scc).enumerate().last() {
+                        // If the region contains a single placeholder then they're equal.
+                        Some((0, placeholder)) => {
+                            return ty::Region::new_placeholder(tcx, placeholder);
+                        }
+
+                        // Fallback: this will produce a cryptic error message.
+                        _ => return region,
+                    }
+                }
+
                 // Find something that we can name
                 let upper_bound = self.approx_universal_upper_bound(vid);
                 let upper_bound = &self.definitions[upper_bound];
diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
index 69e5bda975e..75cca973306 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
@@ -351,6 +351,15 @@ pub fn unexpected_hidden_region_diagnostic<'tcx>(
                 )
             }
         }
+        ty::RePlaceholder(_) => {
+            explain_free_region(
+                tcx,
+                &mut err,
+                &format!("hidden type `{}` captures ", hidden_ty),
+                hidden_region,
+                "",
+            );
+        }
         ty::ReError(_) => {
             err.delay_as_bug();
         }
diff --git a/tests/ui/impl-trait/nested-rpit-hrtb-2.rs b/tests/ui/impl-trait/nested-rpit-hrtb-2.rs
new file mode 100644
index 00000000000..4d72962157b
--- /dev/null
+++ b/tests/ui/impl-trait/nested-rpit-hrtb-2.rs
@@ -0,0 +1,9 @@
+// The nested impl Trait references a higher-ranked region
+
+trait Trait<'a> { type Assoc; }
+impl<'a> Trait<'a> for () { type Assoc = &'a str; }
+
+fn test() -> impl for<'a> Trait<'a, Assoc = impl Sized> {}
+//~^ ERROR captures lifetime that does not appear in bounds
+
+fn main() {}
diff --git a/tests/ui/impl-trait/nested-rpit-hrtb-2.stderr b/tests/ui/impl-trait/nested-rpit-hrtb-2.stderr
new file mode 100644
index 00000000000..71d1d45f48b
--- /dev/null
+++ b/tests/ui/impl-trait/nested-rpit-hrtb-2.stderr
@@ -0,0 +1,12 @@
+error[E0700]: hidden type for `impl Sized` captures lifetime that does not appear in bounds
+  --> $DIR/nested-rpit-hrtb-2.rs:6:57
+   |
+LL | fn test() -> impl for<'a> Trait<'a, Assoc = impl Sized> {}
+   |                       --                    ----------  ^^
+   |                       |                     |
+   |                       |                     opaque type defined here
+   |                       hidden type `&'a str` captures the lifetime `'a` as defined here
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0700`.
diff --git a/tests/ui/type-alias-impl-trait/nested-tait-hrtb.rs b/tests/ui/type-alias-impl-trait/nested-tait-hrtb.rs
new file mode 100644
index 00000000000..4a9631a7208
--- /dev/null
+++ b/tests/ui/type-alias-impl-trait/nested-tait-hrtb.rs
@@ -0,0 +1,15 @@
+#![feature(type_alias_impl_trait)]
+
+trait Trait<'a> { type Assoc; }
+impl<'a> Trait<'a> for () { type Assoc = &'a str; }
+
+type WithoutLt = impl Sized;
+fn without_lt() -> impl for<'a> Trait<'a, Assoc = WithoutLt> {}
+//~^ ERROR captures lifetime that does not appear in bounds
+
+type WithLt<'a> = impl Sized + 'a;
+//~^ ERROR concrete type differs from previous defining opaque type use
+fn with_lt() -> impl for<'a> Trait<'a, Assoc = WithLt<'a>> {}
+//~^ ERROR expected generic lifetime parameter, found `'a`
+
+fn main() {}
diff --git a/tests/ui/type-alias-impl-trait/nested-tait-hrtb.stderr b/tests/ui/type-alias-impl-trait/nested-tait-hrtb.stderr
new file mode 100644
index 00000000000..9a783a6d92a
--- /dev/null
+++ b/tests/ui/type-alias-impl-trait/nested-tait-hrtb.stderr
@@ -0,0 +1,35 @@
+error[E0700]: hidden type for `WithoutLt` captures lifetime that does not appear in bounds
+  --> $DIR/nested-tait-hrtb.rs:7:62
+   |
+LL | type WithoutLt = impl Sized;
+   |                  ---------- opaque type defined here
+LL | fn without_lt() -> impl for<'a> Trait<'a, Assoc = WithoutLt> {}
+   |                             --                               ^^
+   |                             |
+   |                             hidden type `&'a str` captures the lifetime `'a` as defined here
+
+error[E0792]: expected generic lifetime parameter, found `'a`
+  --> $DIR/nested-tait-hrtb.rs:12:60
+   |
+LL | type WithLt<'a> = impl Sized + 'a;
+   |             -- this generic parameter must be used with a generic lifetime parameter
+LL |
+LL | fn with_lt() -> impl for<'a> Trait<'a, Assoc = WithLt<'a>> {}
+   |                                                            ^^
+
+error: concrete type differs from previous defining opaque type use
+  --> $DIR/nested-tait-hrtb.rs:10:19
+   |
+LL | type WithLt<'a> = impl Sized + 'a;
+   |                   ^^^^^^^^^^^^^^^ expected `&'a str`, got `{type error}`
+   |
+note: previous use here
+  --> $DIR/nested-tait-hrtb.rs:12:17
+   |
+LL | fn with_lt() -> impl for<'a> Trait<'a, Assoc = WithLt<'a>> {}
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 3 previous errors
+
+Some errors have detailed explanations: E0700, E0792.
+For more information about an error, try `rustc --explain E0700`.