Don't arbitrarily choose one upper bound for hidden captured region

This commit is contained in:
Michael Goulet 2024-08-06 15:43:28 -04:00
parent 60d146580c
commit c656ce7aeb
6 changed files with 68 additions and 36 deletions

View File

@ -225,21 +225,26 @@ impl<'tcx> RegionInferenceContext<'tcx> {
// Find something that we can name // Find something that we can name
let upper_bound = self.approx_universal_upper_bound(vid); let upper_bound = self.approx_universal_upper_bound(vid);
let upper_bound = &self.definitions[upper_bound]; if let Some(universal_region) = self.definitions[upper_bound].external_name {
match upper_bound.external_name { return universal_region;
Some(reg) => reg, }
None => {
// Nothing exact found, so we pick the first one that we find. // Nothing exact found, so we pick a named upper bound, if there's only one.
// If there's >1 universal region, then we probably are dealing w/ an intersection
// region which cannot be mapped back to a universal.
// FIXME: We could probably compute the LUB if there is one.
let scc = self.constraint_sccs.scc(vid); let scc = self.constraint_sccs.scc(vid);
for vid in self.rev_scc_graph.as_ref().unwrap().upper_bounds(scc) { let upper_bounds: Vec<_> = self
match self.definitions[vid].external_name { .rev_scc_graph
None => {} .as_ref()
Some(region) if region.is_static() => {} .unwrap()
Some(region) => return region, .upper_bounds(scc)
} .filter_map(|vid| self.definitions[vid].external_name)
} .filter(|r| !r.is_static())
region .collect();
} match &upper_bounds[..] {
[universal_region] => *universal_region,
_ => region,
} }
} }
_ => region, _ => region,

View File

@ -0,0 +1,29 @@
#![feature(precise_capturing)]
use std::future::Future;
use std::pin::Pin;
trait MyTrait {
fn foo<'a, 'b>(&'a self, x: &'b i32) -> impl Future<Output = i32>;
}
trait ErasedMyTrait {
fn foo<'life0, 'life1, 'dynosaur>(&'life0 self, x: &'life1 i32)
-> Pin<Box<dyn Future<Output = i32> + 'dynosaur>>
where
'life0: 'dynosaur,
'life1: 'dynosaur;
}
struct DynMyTrait<T: ErasedMyTrait> {
ptr: T,
}
impl<T: ErasedMyTrait> MyTrait for DynMyTrait<T> {
fn foo<'a, 'b>(&'a self, x: &'b i32) -> impl Future<Output = i32> {
self.ptr.foo(x)
//~^ ERROR hidden type for `impl Future<Output = i32>` captures lifetime that does not appear in bounds
}
}
fn main() {}

View File

@ -0,0 +1,13 @@
error[E0700]: hidden type for `impl Future<Output = i32>` captures lifetime that does not appear in bounds
--> $DIR/cannot-capture-intersection.rs:24:9
|
LL | fn foo<'a, 'b>(&'a self, x: &'b i32) -> impl Future<Output = i32> {
| ------------------------- opaque type defined here
LL | self.ptr.foo(x)
| ^^^^^^^^^^^^^^^
|
= note: hidden type `Pin<Box<dyn Future<Output = i32>>>` captures lifetime `'_`
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0700`.

View File

@ -2,17 +2,12 @@ error[E0700]: hidden type for `impl Trait<'d, 'e>` captures lifetime that does n
--> $DIR/ordinary-bounds-unrelated.rs:28:33 --> $DIR/ordinary-bounds-unrelated.rs:28:33
| |
LL | fn upper_bounds<'a, 'b, 'c, 'd, 'e>(a: Ordinary<'a>, b: Ordinary<'b>) -> impl Trait<'d, 'e> LL | fn upper_bounds<'a, 'b, 'c, 'd, 'e>(a: Ordinary<'a>, b: Ordinary<'b>) -> impl Trait<'d, 'e>
| -- ------------------ opaque type defined here | ------------------ opaque type defined here
| |
| hidden type `Ordinary<'b>` captures the lifetime `'b` as defined here
... ...
LL | if condition() { a } else { b } LL | if condition() { a } else { b }
| ^ | ^
| |
help: to declare that `impl Trait<'d, 'e>` captures `'b`, you can add an explicit `'b` lifetime bound = note: hidden type `Ordinary<'_>` captures lifetime `'_`
|
LL | fn upper_bounds<'a, 'b, 'c, 'd, 'e>(a: Ordinary<'a>, b: Ordinary<'b>) -> impl Trait<'d, 'e> + 'b
| ++++
error: aborting due to 1 previous error error: aborting due to 1 previous error

View File

@ -2,17 +2,12 @@ error[E0700]: hidden type for `impl Trait<'a, 'b>` captures lifetime that does n
--> $DIR/ordinary-bounds-unsuited.rs:31:33 --> $DIR/ordinary-bounds-unsuited.rs:31:33
| |
LL | fn upper_bounds<'a, 'b>(a: Ordinary<'a>, b: Ordinary<'b>) -> impl Trait<'a, 'b> LL | fn upper_bounds<'a, 'b>(a: Ordinary<'a>, b: Ordinary<'b>) -> impl Trait<'a, 'b>
| -- ------------------ opaque type defined here | ------------------ opaque type defined here
| |
| hidden type `Ordinary<'b>` captures the lifetime `'b` as defined here
... ...
LL | if condition() { a } else { b } LL | if condition() { a } else { b }
| ^ | ^
| |
help: to declare that `impl Trait<'a, 'b>` captures `'b`, you can add an explicit `'b` lifetime bound = note: hidden type `Ordinary<'_>` captures lifetime `'_`
|
LL | fn upper_bounds<'a, 'b>(a: Ordinary<'a>, b: Ordinary<'b>) -> impl Trait<'a, 'b> + 'b
| ++++
error: aborting due to 1 previous error error: aborting due to 1 previous error

View File

@ -2,18 +2,13 @@ error[E0700]: hidden type for `impl Iterator<Item = i32>` captures lifetime that
--> $DIR/explicit-lifetime-suggestion-in-proper-span-issue-121267.rs:7:5 --> $DIR/explicit-lifetime-suggestion-in-proper-span-issue-121267.rs:7:5
| |
LL | fn bar(src: &crate::Foo) -> impl Iterator<Item = i32> { LL | fn bar(src: &crate::Foo) -> impl Iterator<Item = i32> {
| ---------- ------------------------- opaque type defined here | ------------------------- opaque type defined here
| |
| hidden type `FilterMap<std::slice::Iter<'static, i32>, {closure@$DIR/explicit-lifetime-suggestion-in-proper-span-issue-121267.rs:9:21: 9:24}>` captures the anonymous lifetime defined here
LL | / [0].into_iter() LL | / [0].into_iter()
LL | | LL | |
LL | | .filter_map(|_| foo(src)) LL | | .filter_map(|_| foo(src))
| |_________________________________^ | |_________________________________^
| |
help: to declare that `impl Iterator<Item = i32>` captures `'_`, you can introduce a named lifetime parameter `'a` = note: hidden type `FilterMap<std::slice::Iter<'static, i32>, {closure@$DIR/explicit-lifetime-suggestion-in-proper-span-issue-121267.rs:9:21: 9:24}>` captures lifetime `'_`
|
LL | fn bar<'a>(src: &'a crate::Foo<'a>) -> impl Iterator<Item = i32> + 'a {
| ++++ ++ ++++ ++++
error: aborting due to 1 previous error error: aborting due to 1 previous error