diff options
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 | |
