Skip to content

Commit c656ce7

Browse files
Don't arbitrarily choose one upper bound for hidden captured region
1 parent 60d1465 commit c656ce7

File tree

6 files changed

+68
-36
lines changed

6 files changed

+68
-36
lines changed

compiler/rustc_borrowck/src/region_infer/opaque_types.rs

+20-15
Original file line numberDiff line numberDiff line change
@@ -225,21 +225,26 @@ impl<'tcx> RegionInferenceContext<'tcx> {
225225

226226
// Find something that we can name
227227
let upper_bound = self.approx_universal_upper_bound(vid);
228-
let upper_bound = &self.definitions[upper_bound];
229-
match upper_bound.external_name {
230-
Some(reg) => reg,
231-
None => {
232-
// Nothing exact found, so we pick the first one that we find.
233-
let scc = self.constraint_sccs.scc(vid);
234-
for vid in self.rev_scc_graph.as_ref().unwrap().upper_bounds(scc) {
235-
match self.definitions[vid].external_name {
236-
None => {}
237-
Some(region) if region.is_static() => {}
238-
Some(region) => return region,
239-
}
240-
}
241-
region
242-
}
228+
if let Some(universal_region) = self.definitions[upper_bound].external_name {
229+
return universal_region;
230+
}
231+
232+
// Nothing exact found, so we pick a named upper bound, if there's only one.
233+
// If there's >1 universal region, then we probably are dealing w/ an intersection
234+
// region which cannot be mapped back to a universal.
235+
// FIXME: We could probably compute the LUB if there is one.
236+
let scc = self.constraint_sccs.scc(vid);
237+
let upper_bounds: Vec<_> = self
238+
.rev_scc_graph
239+
.as_ref()
240+
.unwrap()
241+
.upper_bounds(scc)
242+
.filter_map(|vid| self.definitions[vid].external_name)
243+
.filter(|r| !r.is_static())
244+
.collect();
245+
match &upper_bounds[..] {
246+
[universal_region] => *universal_region,
247+
_ => region,
243248
}
244249
}
245250
_ => region,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
#![feature(precise_capturing)]
2+
3+
use std::future::Future;
4+
use std::pin::Pin;
5+
6+
trait MyTrait {
7+
fn foo<'a, 'b>(&'a self, x: &'b i32) -> impl Future<Output = i32>;
8+
}
9+
10+
trait ErasedMyTrait {
11+
fn foo<'life0, 'life1, 'dynosaur>(&'life0 self, x: &'life1 i32)
12+
-> Pin<Box<dyn Future<Output = i32> + 'dynosaur>>
13+
where
14+
'life0: 'dynosaur,
15+
'life1: 'dynosaur;
16+
}
17+
18+
struct DynMyTrait<T: ErasedMyTrait> {
19+
ptr: T,
20+
}
21+
22+
impl<T: ErasedMyTrait> MyTrait for DynMyTrait<T> {
23+
fn foo<'a, 'b>(&'a self, x: &'b i32) -> impl Future<Output = i32> {
24+
self.ptr.foo(x)
25+
//~^ ERROR hidden type for `impl Future<Output = i32>` captures lifetime that does not appear in bounds
26+
}
27+
}
28+
29+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
error[E0700]: hidden type for `impl Future<Output = i32>` captures lifetime that does not appear in bounds
2+
--> $DIR/cannot-capture-intersection.rs:24:9
3+
|
4+
LL | fn foo<'a, 'b>(&'a self, x: &'b i32) -> impl Future<Output = i32> {
5+
| ------------------------- opaque type defined here
6+
LL | self.ptr.foo(x)
7+
| ^^^^^^^^^^^^^^^
8+
|
9+
= note: hidden type `Pin<Box<dyn Future<Output = i32>>>` captures lifetime `'_`
10+
11+
error: aborting due to 1 previous error
12+
13+
For more information about this error, try `rustc --explain E0700`.

tests/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unrelated.stderr

+2-7
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,12 @@ error[E0700]: hidden type for `impl Trait<'d, 'e>` captures lifetime that does n
22
--> $DIR/ordinary-bounds-unrelated.rs:28:33
33
|
44
LL | fn upper_bounds<'a, 'b, 'c, 'd, 'e>(a: Ordinary<'a>, b: Ordinary<'b>) -> impl Trait<'d, 'e>
5-
| -- ------------------ opaque type defined here
6-
| |
7-
| hidden type `Ordinary<'b>` captures the lifetime `'b` as defined here
5+
| ------------------ opaque type defined here
86
...
97
LL | if condition() { a } else { b }
108
| ^
119
|
12-
help: to declare that `impl Trait<'d, 'e>` captures `'b`, you can add an explicit `'b` lifetime bound
13-
|
14-
LL | fn upper_bounds<'a, 'b, 'c, 'd, 'e>(a: Ordinary<'a>, b: Ordinary<'b>) -> impl Trait<'d, 'e> + 'b
15-
| ++++
10+
= note: hidden type `Ordinary<'_>` captures lifetime `'_`
1611

1712
error: aborting due to 1 previous error
1813

tests/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unsuited.stderr

+2-7
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,12 @@ error[E0700]: hidden type for `impl Trait<'a, 'b>` captures lifetime that does n
22
--> $DIR/ordinary-bounds-unsuited.rs:31:33
33
|
44
LL | fn upper_bounds<'a, 'b>(a: Ordinary<'a>, b: Ordinary<'b>) -> impl Trait<'a, 'b>
5-
| -- ------------------ opaque type defined here
6-
| |
7-
| hidden type `Ordinary<'b>` captures the lifetime `'b` as defined here
5+
| ------------------ opaque type defined here
86
...
97
LL | if condition() { a } else { b }
108
| ^
119
|
12-
help: to declare that `impl Trait<'a, 'b>` captures `'b`, you can add an explicit `'b` lifetime bound
13-
|
14-
LL | fn upper_bounds<'a, 'b>(a: Ordinary<'a>, b: Ordinary<'b>) -> impl Trait<'a, 'b> + 'b
15-
| ++++
10+
= note: hidden type `Ordinary<'_>` captures lifetime `'_`
1611

1712
error: aborting due to 1 previous error
1813

tests/ui/suggestions/lifetimes/explicit-lifetime-suggestion-in-proper-span-issue-121267.stderr

+2-7
Original file line numberDiff line numberDiff line change
@@ -2,18 +2,13 @@ error[E0700]: hidden type for `impl Iterator<Item = i32>` captures lifetime that
22
--> $DIR/explicit-lifetime-suggestion-in-proper-span-issue-121267.rs:7:5
33
|
44
LL | fn bar(src: &crate::Foo) -> impl Iterator<Item = i32> {
5-
| ---------- ------------------------- opaque type defined here
6-
| |
7-
| 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
5+
| ------------------------- opaque type defined here
86
LL | / [0].into_iter()
97
LL | |
108
LL | | .filter_map(|_| foo(src))
119
| |_________________________________^
1210
|
13-
help: to declare that `impl Iterator<Item = i32>` captures `'_`, you can introduce a named lifetime parameter `'a`
14-
|
15-
LL | fn bar<'a>(src: &'a crate::Foo<'a>) -> impl Iterator<Item = i32> + 'a {
16-
| ++++ ++ ++++ ++++
11+
= 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 `'_`
1712

1813
error: aborting due to 1 previous error
1914

0 commit comments

Comments
 (0)