Skip to content

Commit 99f9fa3

Browse files
authored
Rollup merge of rust-lang#66679 - mark-i-m:fix-anon-lifetime-errors, r=matthewjasper
Improve lifetime errors with implicit trait object lifetimes r? @matthewjasper cc @estebank I still think the ideal solution would be to construct a `BrAnon`, but that seems like a more invasive change, and can be done later. This at least gets rid of the hack in `OutliveSuggestion` and is slightly more principled.
2 parents cb43d82 + 2a86b6c commit 99f9fa3

10 files changed

+120
-165
lines changed

src/librustc/ty/sty.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ pub enum BoundRegion {
6969
impl BoundRegion {
7070
pub fn is_named(&self) -> bool {
7171
match *self {
72-
BoundRegion::BrNamed(..) => true,
72+
BoundRegion::BrNamed(_, name) => name != kw::UnderscoreLifetime,
7373
_ => false,
7474
}
7575
}

src/librustc_mir/borrow_check/nll/region_infer/error_reporting/outlives_suggestion.rs

+3-12
Original file line numberDiff line numberDiff line change
@@ -78,17 +78,7 @@ impl OutlivesSuggestionBuilder<'a> {
7878
match name.source {
7979
RegionNameSource::NamedEarlyBoundRegion(..)
8080
| RegionNameSource::NamedFreeRegion(..)
81-
| RegionNameSource::Static => {
82-
// FIXME: This is a bit hacky. We should ideally have a semantic way for checking
83-
// if the name is `'_`...
84-
if name.name().with(|name| name != "'_") {
85-
debug!("Region {:?} is suggestable", name);
86-
true
87-
} else {
88-
debug!("Region {:?} is NOT suggestable", name);
89-
false
90-
}
91-
}
81+
| RegionNameSource::Static => true,
9282

9383
// Don't give suggestions for upvars, closure return types, or other unnamable
9484
// regions.
@@ -98,7 +88,8 @@ impl OutlivesSuggestionBuilder<'a> {
9888
| RegionNameSource::MatchedAdtAndSegment(..)
9989
| RegionNameSource::AnonRegionFromUpvar(..)
10090
| RegionNameSource::AnonRegionFromOutput(..)
101-
| RegionNameSource::AnonRegionFromYieldTy(..) => {
91+
| RegionNameSource::AnonRegionFromYieldTy(..)
92+
| RegionNameSource::AnonRegionFromAsyncFn(..) => {
10293
debug!("Region {:?} is NOT suggestable", name);
10394
false
10495
}

src/librustc_mir/borrow_check/nll/region_infer/error_reporting/region_name.rs

+34-49
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,13 @@ use rustc::hir::def_id::DefId;
1313
use rustc::infer::InferCtxt;
1414
use rustc::mir::{Local, Body};
1515
use rustc::ty::subst::{SubstsRef, GenericArgKind};
16-
use rustc::ty::{self, RegionKind, RegionVid, Ty, TyCtxt};
16+
use rustc::ty::{self, RegionVid, Ty, TyCtxt};
1717
use rustc::ty::print::RegionHighlightMode;
1818
use rustc_index::vec::IndexVec;
1919
use rustc_errors::DiagnosticBuilder;
2020
use syntax::symbol::kw;
2121
use rustc_data_structures::fx::FxHashMap;
22-
use syntax_pos::{Span, symbol::Symbol};
22+
use syntax_pos::{Span, symbol::Symbol, DUMMY_SP};
2323

2424
/// A name for a particular region used in emitting diagnostics. This name could be a generated
2525
/// name like `'1`, a name used by the user like `'a`, or a name like `'static`.
@@ -55,7 +55,10 @@ crate enum RegionNameSource {
5555
AnonRegionFromUpvar(Span, String),
5656
/// The region corresponding to the return type of a closure.
5757
AnonRegionFromOutput(Span, String, String),
58+
/// The region from a type yielded by a generator.
5859
AnonRegionFromYieldTy(Span, String),
60+
/// An anonymous region from an async fn.
61+
AnonRegionFromAsyncFn(Span),
5962
}
6063

6164
/// Records region names that have been assigned before so that we can use the same ones in later
@@ -113,14 +116,11 @@ impl RegionName {
113116
RegionNameSource::MatchedAdtAndSegment(..) |
114117
RegionNameSource::AnonRegionFromUpvar(..) |
115118
RegionNameSource::AnonRegionFromOutput(..) |
116-
RegionNameSource::AnonRegionFromYieldTy(..) => false,
119+
RegionNameSource::AnonRegionFromYieldTy(..) |
120+
RegionNameSource::AnonRegionFromAsyncFn(..) => false,
117121
}
118122
}
119123

120-
crate fn name(&self) -> Symbol {
121-
self.name
122-
}
123-
124124
crate fn highlight_region_name(&self, diag: &mut DiagnosticBuilder<'_>) {
125125
match &self.source {
126126
RegionNameSource::NamedFreeRegion(span)
@@ -137,7 +137,8 @@ impl RegionName {
137137
RegionNameSource::CannotMatchHirTy(span, type_name) => {
138138
diag.span_label(*span, format!("has type `{}`", type_name));
139139
}
140-
RegionNameSource::MatchedHirTy(span) => {
140+
RegionNameSource::MatchedHirTy(span) |
141+
RegionNameSource::AnonRegionFromAsyncFn(span) => {
141142
diag.span_label(
142143
*span,
143144
format!("let's call the lifetime of this reference `{}`", self),
@@ -270,7 +271,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
270271
match error_region {
271272
ty::ReEarlyBound(ebr) => {
272273
if ebr.has_name() {
273-
let span = self.get_named_span(tcx, error_region, ebr.name);
274+
let span = tcx.hir().span_if_local(ebr.def_id).unwrap_or(DUMMY_SP);
274275
Some(RegionName {
275276
name: ebr.name,
276277
source: RegionNameSource::NamedEarlyBoundRegion(span),
@@ -286,12 +287,30 @@ impl<'tcx> RegionInferenceContext<'tcx> {
286287
}),
287288

288289
ty::ReFree(free_region) => match free_region.bound_region {
289-
ty::BoundRegion::BrNamed(_, name) => {
290-
let span = self.get_named_span(tcx, error_region, name);
291-
Some(RegionName {
292-
name,
293-
source: RegionNameSource::NamedFreeRegion(span),
294-
})
290+
ty::BoundRegion::BrNamed(region_def_id, name) => {
291+
// Get the span to point to, even if we don't use the name.
292+
let span = tcx.hir().span_if_local(region_def_id).unwrap_or(DUMMY_SP);
293+
debug!("bound region named: {:?}, is_named: {:?}",
294+
name, free_region.bound_region.is_named());
295+
296+
if free_region.bound_region.is_named() {
297+
// A named region that is actually named.
298+
Some(RegionName {
299+
name,
300+
source: RegionNameSource::NamedFreeRegion(span),
301+
})
302+
} else {
303+
// If we spuriously thought that the region is named, we should let the
304+
// system generate a true name for error messages. Currently this can
305+
// happen if we have an elided name in an async fn for example: the
306+
// compiler will generate a region named `'_`, but reporting such a name is
307+
// not actually useful, so we synthesize a name for it instead.
308+
let name = renctx.synthesize_region_name();
309+
Some(RegionName {
310+
name,
311+
source: RegionNameSource::AnonRegionFromAsyncFn(span),
312+
})
313+
}
295314
}
296315

297316
ty::BoundRegion::BrEnv => {
@@ -350,40 +369,6 @@ impl<'tcx> RegionInferenceContext<'tcx> {
350369
}
351370
}
352371

353-
/// Gets a span of a named region to provide context for error messages that
354-
/// mention that span, for example:
355-
///
356-
/// ```
357-
/// |
358-
/// | fn two_regions<'a, 'b, T>(cell: Cell<&'a ()>, t: T)
359-
/// | -- -- lifetime `'b` defined here
360-
/// | |
361-
/// | lifetime `'a` defined here
362-
/// |
363-
/// | with_signature(cell, t, |cell, t| require(cell, t));
364-
/// | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ argument requires that `'b` must
365-
/// | outlive `'a`
366-
/// ```
367-
fn get_named_span(
368-
&self,
369-
tcx: TyCtxt<'tcx>,
370-
error_region: &RegionKind,
371-
name: Symbol,
372-
) -> Span {
373-
let scope = error_region.free_region_binding_scope(tcx);
374-
let node = tcx.hir().as_local_hir_id(scope).unwrap_or(hir::DUMMY_HIR_ID);
375-
376-
let span = tcx.sess.source_map().def_span(tcx.hir().span(node));
377-
if let Some(param) = tcx.hir()
378-
.get_generics(scope)
379-
.and_then(|generics| generics.get_named(name))
380-
{
381-
param.span
382-
} else {
383-
span
384-
}
385-
}
386-
387372
/// Finds an argument that contains `fr` and label it with a fully
388373
/// elaborated type, returning something like `'1`. Result looks
389374
/// like:

src/test/ui/async-await/issues/issue-63388-1.nll.stderr

+2-2
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,12 @@ error: lifetime may not live long enough
1212
LL | async fn do_sth<'a>(
1313
| -- lifetime `'a` defined here
1414
LL | &'a self, foo: &dyn Foo
15-
| - lifetime `'_` defined here
15+
| - let's call the lifetime of this reference `'1`
1616
LL | ) -> &dyn Foo
1717
LL | / {
1818
LL | | foo
1919
LL | | }
20-
| |_____^ function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'_`
20+
| |_____^ function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'1`
2121

2222
error: aborting due to 2 previous errors
2323

src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait-async.nll.stderr

+3-3
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,11 @@ error: lifetime may not live long enough
22
--> $DIR/arbitrary_self_types_pin_lifetime_impl_trait-async.rs:8:48
33
|
44
LL | async fn f(self: Pin<&Self>) -> impl Clone { self }
5-
| - ^^^^^^^^ returning this value requires that `'_` must outlive `'static`
5+
| - ^^^^^^^^ returning this value requires that `'1` must outlive `'static`
66
| |
7-
| lifetime `'_` defined here
7+
| let's call the lifetime of this reference `'1`
88
|
9-
help: to allow this `impl Trait` to capture borrowed data with lifetime `'_`, add `'_` as a constraint
9+
help: to allow this `impl Trait` to capture borrowed data with lifetime `'1`, add `'_` as a constraint
1010
|
1111
LL | async fn f(self: Pin<&Self>) -> impl Clone + '_ { self }
1212
| ^^^^^^^^^^^^^^^

src/test/ui/self/arbitrary_self_types_pin_lifetime_mismatch-async.nll.stderr

+11-10
Original file line numberDiff line numberDiff line change
@@ -10,19 +10,19 @@ error: lifetime may not live long enough
1010
--> $DIR/arbitrary_self_types_pin_lifetime_mismatch-async.rs:8:52
1111
|
1212
LL | async fn a(self: Pin<&Foo>, f: &Foo) -> &Foo { f }
13-
| - ^ function was supposed to return data with lifetime `'_` but it is returning data with lifetime `'_`
14-
| |
15-
| lifetime `'_` defined here
16-
| lifetime `'_` defined here
13+
| - - ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
14+
| | |
15+
| | let's call the lifetime of this reference `'1`
16+
| let's call the lifetime of this reference `'2`
1717

1818
error: lifetime may not live long enough
1919
--> $DIR/arbitrary_self_types_pin_lifetime_mismatch-async.rs:11:75
2020
|
2121
LL | async fn c(self: Pin<&Self>, f: &Foo, g: &Foo) -> (Pin<&Foo>, &Foo) { (self, f) }
22-
| - ^^^^^^^^^ function was supposed to return data with lifetime `'_` but it is returning data with lifetime `'_`
23-
| |
24-
| lifetime `'_` defined here
25-
| lifetime `'_` defined here
22+
| - - ^^^^^^^^^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
23+
| | |
24+
| | let's call the lifetime of this reference `'1`
25+
| let's call the lifetime of this reference `'2`
2626

2727
error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
2828
--> $DIR/arbitrary_self_types_pin_lifetime_mismatch-async.rs:17:58
@@ -36,8 +36,9 @@ error: lifetime may not live long enough
3636
--> $DIR/arbitrary_self_types_pin_lifetime_mismatch-async.rs:17:64
3737
|
3838
LL | async fn bar<'a>(self: Alias<&Self>, arg: &'a ()) -> &() { arg }
39-
| -- - lifetime `'_` defined here ^^^ function was supposed to return data with lifetime `'_` but it is returning data with lifetime `'a`
40-
| |
39+
| -- - ^^^ function was supposed to return data with lifetime `'1` but it is returning data with lifetime `'a`
40+
| | |
41+
| | let's call the lifetime of this reference `'1`
4142
| lifetime `'a` defined here
4243

4344
error: aborting due to 5 previous errors

src/test/ui/self/elision/lt-ref-self-async.nll.stderr

+18-24
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,11 @@ error: lifetime may not live long enough
1010
--> $DIR/lt-ref-self-async.rs:13:9
1111
|
1212
LL | async fn ref_self(&self, f: &u32) -> &u32 {
13-
| -
13+
| - - let's call the lifetime of this reference `'1`
1414
| |
15-
| lifetime `'_` defined here
16-
| lifetime `'_` defined here
15+
| let's call the lifetime of this reference `'2`
1716
LL | f
18-
| ^ function was supposed to return data with lifetime `'_` but it is returning data with lifetime `'_`
17+
| ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
1918

2019
error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
2120
--> $DIR/lt-ref-self-async.rs:18:48
@@ -29,12 +28,11 @@ error: lifetime may not live long enough
2928
--> $DIR/lt-ref-self-async.rs:19:9
3029
|
3130
LL | async fn ref_Self(self: &Self, f: &u32) -> &u32 {
32-
| -
31+
| - - let's call the lifetime of this reference `'1`
3332
| |
34-
| lifetime `'_` defined here
35-
| lifetime `'_` defined here
33+
| let's call the lifetime of this reference `'2`
3634
LL | f
37-
| ^ function was supposed to return data with lifetime `'_` but it is returning data with lifetime `'_`
35+
| ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
3836

3937
error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
4038
--> $DIR/lt-ref-self-async.rs:22:57
@@ -48,12 +46,11 @@ error: lifetime may not live long enough
4846
--> $DIR/lt-ref-self-async.rs:23:9
4947
|
5048
LL | async fn box_ref_Self(self: Box<&Self>, f: &u32) -> &u32 {
51-
| -
49+
| - - let's call the lifetime of this reference `'1`
5250
| |
53-
| lifetime `'_` defined here
54-
| lifetime `'_` defined here
51+
| let's call the lifetime of this reference `'2`
5552
LL | f
56-
| ^ function was supposed to return data with lifetime `'_` but it is returning data with lifetime `'_`
53+
| ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
5754

5855
error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
5956
--> $DIR/lt-ref-self-async.rs:26:57
@@ -67,12 +64,11 @@ error: lifetime may not live long enough
6764
--> $DIR/lt-ref-self-async.rs:27:9
6865
|
6966
LL | async fn pin_ref_Self(self: Pin<&Self>, f: &u32) -> &u32 {
70-
| -
67+
| - - let's call the lifetime of this reference `'1`
7168
| |
72-
| lifetime `'_` defined here
73-
| lifetime `'_` defined here
69+
| let's call the lifetime of this reference `'2`
7470
LL | f
75-
| ^ function was supposed to return data with lifetime `'_` but it is returning data with lifetime `'_`
71+
| ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
7672

7773
error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
7874
--> $DIR/lt-ref-self-async.rs:30:66
@@ -86,12 +82,11 @@ error: lifetime may not live long enough
8682
--> $DIR/lt-ref-self-async.rs:31:9
8783
|
8884
LL | async fn box_box_ref_Self(self: Box<Box<&Self>>, f: &u32) -> &u32 {
89-
| -
85+
| - - let's call the lifetime of this reference `'1`
9086
| |
91-
| lifetime `'_` defined here
92-
| lifetime `'_` defined here
87+
| let's call the lifetime of this reference `'2`
9388
LL | f
94-
| ^ function was supposed to return data with lifetime `'_` but it is returning data with lifetime `'_`
89+
| ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
9590

9691
error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
9792
--> $DIR/lt-ref-self-async.rs:34:62
@@ -105,12 +100,11 @@ error: lifetime may not live long enough
105100
--> $DIR/lt-ref-self-async.rs:35:9
106101
|
107102
LL | async fn box_pin_Self(self: Box<Pin<&Self>>, f: &u32) -> &u32 {
108-
| -
103+
| - - let's call the lifetime of this reference `'1`
109104
| |
110-
| lifetime `'_` defined here
111-
| lifetime `'_` defined here
105+
| let's call the lifetime of this reference `'2`
112106
LL | f
113-
| ^ function was supposed to return data with lifetime `'_` but it is returning data with lifetime `'_`
107+
| ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
114108

115109
error: aborting due to 12 previous errors
116110

0 commit comments

Comments
 (0)