about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/opaque_types.rs2
-rw-r--r--compiler/rustc_borrowck/src/region_infer/mod.rs60
-rw-r--r--tests/ui/async-await/issue-74072-lifetime-name-annotations.stderr4
-rw-r--r--tests/ui/async-await/issue-76547.rs4
-rw-r--r--tests/ui/async-await/issue-76547.stderr34
-rw-r--r--tests/ui/async-await/multiple-lifetimes/ret-impl-trait-one.stderr2
-rw-r--r--tests/ui/impl-trait/wf-check-hidden-type.stderr2
-rw-r--r--tests/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.rs2
-rw-r--r--tests/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.stderr16
-rw-r--r--tests/ui/suggestions/lifetimes/trait-object-nested-in-impl-trait.stderr4
10 files changed, 71 insertions, 59 deletions
diff --git a/compiler/rustc_borrowck/src/diagnostics/opaque_types.rs b/compiler/rustc_borrowck/src/diagnostics/opaque_types.rs
index e16af988f69..f77f759035b 100644
--- a/compiler/rustc_borrowck/src/diagnostics/opaque_types.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/opaque_types.rs
@@ -244,7 +244,7 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for FindOpaqueRegion<'_, 'tcx> {
 
                 // Find a path between the borrow region and our opaque capture.
                 if let Some((path, _)) =
-                    self.regioncx.find_constraint_paths_between_regions(self.borrow_region, |r| {
+                    self.regioncx.find_constraint_path_between_regions(self.borrow_region, |r| {
                         r == opaque_region_vid
                     })
                 {
diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs
index d6d6b8a6bf2..3d95eb4663a 100644
--- a/compiler/rustc_borrowck/src/region_infer/mod.rs
+++ b/compiler/rustc_borrowck/src/region_infer/mod.rs
@@ -1405,19 +1405,40 @@ impl<'tcx> RegionInferenceContext<'tcx> {
     }
 
     /// Walks the graph of constraints (where `'a: 'b` is considered
-    /// an edge `'a -> 'b`) to find all paths from `from_region` to
-    /// `to_region`. The paths are accumulated into the vector
-    /// `results`. The paths are stored as a series of
-    /// `ConstraintIndex` values -- in other words, a list of *edges*.
+    /// an edge `'a -> 'b`) to find a path from `from_region` to
+    /// `to_region`.
     ///
     /// Returns: a series of constraints as well as the region `R`
     /// that passed the target test.
     #[instrument(skip(self, target_test), ret)]
-    pub(crate) fn find_constraint_paths_between_regions(
+    pub(crate) fn find_constraint_path_between_regions(
         &self,
         from_region: RegionVid,
         target_test: impl Fn(RegionVid) -> bool,
     ) -> Option<(Vec<OutlivesConstraint<'tcx>>, RegionVid)> {
+        self.find_constraint_path_between_regions_inner(true, from_region, &target_test).or_else(
+            || self.find_constraint_path_between_regions_inner(false, from_region, &target_test),
+        )
+    }
+
+    /// The constraints we get from equating the hidden type of each use of an opaque
+    /// with its final concrete type may end up getting preferred over other, potentially
+    /// longer constraint paths.
+    ///
+    /// Given that we compute the final concrete type by relying on this existing constraint
+    /// path, this can easily end up hiding the actual reason for why we require these regions
+    /// to be equal.
+    ///
+    /// To handle this, we first look at the path while ignoring these constraints and then
+    /// retry while considering them. This is not perfect, as the `from_region` may have already
+    /// been partially related to its argument region, so while we rely on a member constraint
+    /// to get a complete path, the most relevant step of that path already existed before then.
+    fn find_constraint_path_between_regions_inner(
+        &self,
+        ignore_opaque_type_constraints: bool,
+        from_region: RegionVid,
+        target_test: impl Fn(RegionVid) -> bool,
+    ) -> Option<(Vec<OutlivesConstraint<'tcx>>, RegionVid)> {
         let mut context = IndexVec::from_elem(Trace::NotVisited, &self.definitions);
         context[from_region] = Trace::StartRegion;
 
@@ -1431,7 +1452,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
 
         while let Some(r) = deque.pop_front() {
             debug!(
-                "find_constraint_paths_between_regions: from_region={:?} r={:?} value={}",
+                "find_constraint_path_between_regions: from_region={:?} r={:?} value={}",
                 from_region,
                 r,
                 self.region_value_str(r),
@@ -1503,9 +1524,16 @@ impl<'tcx> RegionInferenceContext<'tcx> {
                 let edges = self.constraint_graph.outgoing_edges_from_graph(r, &self.constraints);
                 // This loop can be hot.
                 for constraint in edges {
-                    if matches!(constraint.category, ConstraintCategory::IllegalUniverse) {
-                        debug!("Ignoring illegal universe constraint: {constraint:?}");
-                        continue;
+                    match constraint.category {
+                        ConstraintCategory::IllegalUniverse => {
+                            debug!("Ignoring illegal universe constraint: {constraint:?}");
+                            continue;
+                        }
+                        ConstraintCategory::OpaqueType if ignore_opaque_type_constraints => {
+                            debug!("Ignoring member constraint: {constraint:?}");
+                            continue;
+                        }
+                        _ => {}
                     }
                     debug_assert_eq!(constraint.sup, r);
                     handle_trace(constraint.sub, Trace::FromGraph(constraint));
@@ -1521,7 +1549,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
     pub(crate) fn find_sub_region_live_at(&self, fr1: RegionVid, location: Location) -> RegionVid {
         trace!(scc = ?self.constraint_sccs.scc(fr1));
         trace!(universe = ?self.max_nameable_universe(self.constraint_sccs.scc(fr1)));
-        self.find_constraint_paths_between_regions(fr1, |r| {
+        self.find_constraint_path_between_regions(fr1, |r| {
             // First look for some `r` such that `fr1: r` and `r` is live at `location`
             trace!(?r, liveness_constraints=?self.liveness_constraints.pretty_print_live_points(r));
             self.liveness_constraints.is_live_at(r, location)
@@ -1531,9 +1559,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
             // `fr1: r` and `r` is a placeholder from some universe
             // `fr1` cannot name. This would force `fr1` to be
             // `'static`.
-            self.find_constraint_paths_between_regions(fr1, |r| {
-                self.cannot_name_placeholder(fr1, r)
-            })
+            self.find_constraint_path_between_regions(fr1, |r| self.cannot_name_placeholder(fr1, r))
         })
         .or_else(|| {
             // If we fail to find THAT, it may be that `fr1` is a
@@ -1546,9 +1572,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
             // must be able to name the universe of R2, because R2 will
             // be at least `'empty(Universe(R2))`, and `R1` must be at
             // larger than that.
-            self.find_constraint_paths_between_regions(fr1, |r| {
-                self.cannot_name_placeholder(r, fr1)
-            })
+            self.find_constraint_path_between_regions(fr1, |r| self.cannot_name_placeholder(r, fr1))
         })
         .map(|(_path, r)| r)
         .unwrap()
@@ -1604,9 +1628,9 @@ impl<'tcx> RegionInferenceContext<'tcx> {
     ) -> (BlameConstraint<'tcx>, Vec<OutlivesConstraint<'tcx>>) {
         // Find all paths
         let (path, target_region) = self
-            .find_constraint_paths_between_regions(from_region, target_test)
+            .find_constraint_path_between_regions(from_region, target_test)
             .or_else(|| {
-                self.find_constraint_paths_between_regions(from_region, |r| {
+                self.find_constraint_path_between_regions(from_region, |r| {
                     self.cannot_name_placeholder(from_region, r)
                 })
             })
diff --git a/tests/ui/async-await/issue-74072-lifetime-name-annotations.stderr b/tests/ui/async-await/issue-74072-lifetime-name-annotations.stderr
index 96975f5ec72..e1f268116fc 100644
--- a/tests/ui/async-await/issue-74072-lifetime-name-annotations.stderr
+++ b/tests/ui/async-await/issue-74072-lifetime-name-annotations.stderr
@@ -53,7 +53,7 @@ LL | ||         let y = &*x;
 LL | ||         *x += 1;
 LL | ||         y
 LL | ||     })()
-   | ||______^_- opaque type requires that borrow lasts for `'1`
+   | ||______^_- argument requires that borrow lasts for `'1`
    | |_______|
    |         creates a temporary value which is freed while still in use
 LL |    }
@@ -102,7 +102,7 @@ LL | ||         let y = &*x;
 LL | ||         *x += 1;
 LL | ||         y
 LL | ||     })()
-   | ||______^_- opaque type requires that borrow lasts for `'1`
+   | ||______^_- argument requires that borrow lasts for `'1`
    | |_______|
    |         creates a temporary value which is freed while still in use
 LL |    }
diff --git a/tests/ui/async-await/issue-76547.rs b/tests/ui/async-await/issue-76547.rs
index 24decf9b5f7..30a39c89437 100644
--- a/tests/ui/async-await/issue-76547.rs
+++ b/tests/ui/async-await/issue-76547.rs
@@ -17,8 +17,8 @@ impl<'a> Future for ListFut<'a> {
 }
 
 async fn fut(bufs: &mut [&mut [u8]]) {
-    //~^ ERROR lifetime may not live long enough
     ListFut(bufs).await
+    //~^ ERROR lifetime may not live long enough
 }
 
 pub struct ListFut2<'a>(&'a mut [&'a mut [u8]]);
@@ -31,8 +31,8 @@ impl<'a> Future for ListFut2<'a> {
 }
 
 async fn fut2(bufs: &mut [&mut [u8]]) -> i32 {
-    //~^ ERROR lifetime may not live long enough
     ListFut2(bufs).await
+    //~^ ERROR lifetime may not live long enough
 }
 
 fn main() {}
diff --git a/tests/ui/async-await/issue-76547.stderr b/tests/ui/async-await/issue-76547.stderr
index 5131f054234..4d96cce824b 100644
--- a/tests/ui/async-await/issue-76547.stderr
+++ b/tests/ui/async-await/issue-76547.stderr
@@ -1,15 +1,12 @@
 error: lifetime may not live long enough
-  --> $DIR/issue-76547.rs:19:38
+  --> $DIR/issue-76547.rs:20:13
    |
-LL |   async fn fut(bufs: &mut [&mut [u8]]) {
-   |  ____________________-_____-___________^
-   | |                    |     |
-   | |                    |     let's call the lifetime of this reference `'2`
-   | |                    let's call the lifetime of this reference `'1`
-LL | |
-LL | |     ListFut(bufs).await
-LL | | }
-   | |_^ opaque type requires that `'1` must outlive `'2`
+LL | async fn fut(bufs: &mut [&mut [u8]]) {
+   |                    -     - let's call the lifetime of this reference `'2`
+   |                    |
+   |                    let's call the lifetime of this reference `'1`
+LL |     ListFut(bufs).await
+   |             ^^^^ this usage requires that `'1` must outlive `'2`
    |
 help: consider introducing a named lifetime parameter
    |
@@ -17,17 +14,14 @@ LL | async fn fut<'a>(bufs: &'a mut [&'a mut [u8]]) {
    |             ++++        ++       ++
 
 error: lifetime may not live long enough
-  --> $DIR/issue-76547.rs:33:46
+  --> $DIR/issue-76547.rs:34:14
    |
-LL |   async fn fut2(bufs: &mut [&mut [u8]]) -> i32 {
-   |  _____________________-_____-__________________^
-   | |                     |     |
-   | |                     |     let's call the lifetime of this reference `'2`
-   | |                     let's call the lifetime of this reference `'1`
-LL | |
-LL | |     ListFut2(bufs).await
-LL | | }
-   | |_^ opaque type requires that `'1` must outlive `'2`
+LL | async fn fut2(bufs: &mut [&mut [u8]]) -> i32 {
+   |                     -     - let's call the lifetime of this reference `'2`
+   |                     |
+   |                     let's call the lifetime of this reference `'1`
+LL |     ListFut2(bufs).await
+   |              ^^^^ this usage requires that `'1` must outlive `'2`
    |
 help: consider introducing a named lifetime parameter
    |
diff --git a/tests/ui/async-await/multiple-lifetimes/ret-impl-trait-one.stderr b/tests/ui/async-await/multiple-lifetimes/ret-impl-trait-one.stderr
index 8fea6bf9580..167b5ee4425 100644
--- a/tests/ui/async-await/multiple-lifetimes/ret-impl-trait-one.stderr
+++ b/tests/ui/async-await/multiple-lifetimes/ret-impl-trait-one.stderr
@@ -9,7 +9,7 @@ LL |   async fn async_ret_impl_trait3<'a, 'b>(a: &'a u8, b: &'b u8) -> impl Trai
 LL | |
 LL | |     (a, b)
 LL | | }
-   | |_^ opaque type requires that `'a` must outlive `'b`
+   | |_^ function was supposed to return data with lifetime `'b` but it is returning data with lifetime `'a`
    |
    = help: consider adding the following bound: `'a: 'b`
 
diff --git a/tests/ui/impl-trait/wf-check-hidden-type.stderr b/tests/ui/impl-trait/wf-check-hidden-type.stderr
index 0cbfc502720..86ba7aff54a 100644
--- a/tests/ui/impl-trait/wf-check-hidden-type.stderr
+++ b/tests/ui/impl-trait/wf-check-hidden-type.stderr
@@ -6,7 +6,7 @@ LL | fn boom<'a, 'b>() -> impl Extend<'a, 'b> {
    |         |
    |         lifetime `'a` defined here
 LL |     None::<&'_ &'_ ()>
-   |     ^^^^^^^^^^^^^^^^^^ opaque type requires that `'a` must outlive `'b`
+   |     ^^^^^^^^^^^^^^^^^^ function was supposed to return data with lifetime `'b` but it is returning data with lifetime `'a`
    |
    = help: consider adding the following bound: `'a: 'b`
 
diff --git a/tests/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.rs b/tests/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.rs
index 0f257a3cd24..eb9b376686a 100644
--- a/tests/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.rs
+++ b/tests/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.rs
@@ -18,7 +18,7 @@ mod bav {
     impl Bar for i32 {}
 
     fn use_it<'a>(val: Box<dyn ObjectTrait<Assoc = i32>>) -> impl OtherTrait<'a> {
-        val.use_self() //~ ERROR `val` does not live long enough
+        val.use_self() //~ ERROR cannot return value referencing function parameter `val`
     }
 }
 
diff --git a/tests/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.stderr b/tests/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.stderr
index 6f33b33580b..505765d2b41 100644
--- a/tests/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.stderr
+++ b/tests/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.stderr
@@ -1,17 +1,11 @@
-error[E0597]: `val` does not live long enough
+error[E0515]: cannot return value referencing function parameter `val`
   --> $DIR/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.rs:21:9
    |
-LL |     fn use_it<'a>(val: Box<dyn ObjectTrait<Assoc = i32>>) -> impl OtherTrait<'a> {
-   |               --  --- binding `val` declared here
-   |               |
-   |               lifetime `'a` defined here
 LL |         val.use_self()
-   |         ^^^-----------
+   |         ---^^^^^^^^^^^
    |         |
-   |         borrowed value does not live long enough
-   |         opaque type requires that `val` is borrowed for `'a`
-LL |     }
-   |     - `val` dropped here while still borrowed
+   |         returns a value referencing data owned by the current function
+   |         `val` is borrowed here
 
 error[E0515]: cannot return value referencing function parameter `val`
   --> $DIR/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.rs:43:9
@@ -76,5 +70,5 @@ LL |         val.use_self()
 
 error: aborting due to 6 previous errors
 
-Some errors have detailed explanations: E0515, E0521, E0597.
+Some errors have detailed explanations: E0515, E0521.
 For more information about an error, try `rustc --explain E0515`.
diff --git a/tests/ui/suggestions/lifetimes/trait-object-nested-in-impl-trait.stderr b/tests/ui/suggestions/lifetimes/trait-object-nested-in-impl-trait.stderr
index 62c591a0db6..c77ef79e7ed 100644
--- a/tests/ui/suggestions/lifetimes/trait-object-nested-in-impl-trait.stderr
+++ b/tests/ui/suggestions/lifetimes/trait-object-nested-in-impl-trait.stderr
@@ -8,7 +8,7 @@ LL | |
 LL | |             current: None,
 LL | |             remaining: self.0.iter(),
 LL | |         }
-   | |_________^ opaque type requires that `'1` must outlive `'static`
+   | |_________^ returning this value requires that `'1` must outlive `'static`
    |
 help: to declare that `impl Iterator<Item = Box<(dyn Foo + 'static)>>` captures data from argument `self`, you can add an explicit `'_` lifetime bound
    |
@@ -63,7 +63,7 @@ LL | |
 LL | |             current: None,
 LL | |             remaining: self.0.iter(),
 LL | |         }
-   | |_________^ opaque type requires that `'a` must outlive `'static`
+   | |_________^ returning this value requires that `'a` must outlive `'static`
    |
 help: to declare that `impl Iterator<Item = Box<(dyn Foo + 'static)>>` captures data from argument `self`, you can add an explicit `'a` lifetime bound
    |