Skip to content

Improve lifetime errors with implicit trait object lifetimes #66679

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Dec 1, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/librustc/ty/sty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ pub enum BoundRegion {
impl BoundRegion {
pub fn is_named(&self) -> bool {
match *self {
BoundRegion::BrNamed(..) => true,
BoundRegion::BrNamed(_, name) => name != kw::UnderscoreLifetime,
_ => false,
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,17 +78,7 @@ impl OutlivesSuggestionBuilder<'a> {
match name.source {
RegionNameSource::NamedEarlyBoundRegion(..)
| RegionNameSource::NamedFreeRegion(..)
| RegionNameSource::Static => {
// FIXME: This is a bit hacky. We should ideally have a semantic way for checking
// if the name is `'_`...
if name.name().with(|name| name != "'_") {
debug!("Region {:?} is suggestable", name);
true
} else {
debug!("Region {:?} is NOT suggestable", name);
false
}
}
| RegionNameSource::Static => true,

// Don't give suggestions for upvars, closure return types, or other unnamable
// regions.
Expand All @@ -98,7 +88,8 @@ impl OutlivesSuggestionBuilder<'a> {
| RegionNameSource::MatchedAdtAndSegment(..)
| RegionNameSource::AnonRegionFromUpvar(..)
| RegionNameSource::AnonRegionFromOutput(..)
| RegionNameSource::AnonRegionFromYieldTy(..) => {
| RegionNameSource::AnonRegionFromYieldTy(..)
| RegionNameSource::AnonRegionFromAsyncFn(..) => {
debug!("Region {:?} is NOT suggestable", name);
false
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,13 @@ use rustc::hir::def_id::DefId;
use rustc::infer::InferCtxt;
use rustc::mir::{Local, Body};
use rustc::ty::subst::{SubstsRef, GenericArgKind};
use rustc::ty::{self, RegionKind, RegionVid, Ty, TyCtxt};
use rustc::ty::{self, RegionVid, Ty, TyCtxt};
use rustc::ty::print::RegionHighlightMode;
use rustc_index::vec::IndexVec;
use rustc_errors::DiagnosticBuilder;
use syntax::symbol::kw;
use rustc_data_structures::fx::FxHashMap;
use syntax_pos::{Span, symbol::Symbol};
use syntax_pos::{Span, symbol::Symbol, DUMMY_SP};

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

/// Records region names that have been assigned before so that we can use the same ones in later
Expand Down Expand Up @@ -113,14 +116,11 @@ impl RegionName {
RegionNameSource::MatchedAdtAndSegment(..) |
RegionNameSource::AnonRegionFromUpvar(..) |
RegionNameSource::AnonRegionFromOutput(..) |
RegionNameSource::AnonRegionFromYieldTy(..) => false,
RegionNameSource::AnonRegionFromYieldTy(..) |
RegionNameSource::AnonRegionFromAsyncFn(..) => false,
}
}

crate fn name(&self) -> Symbol {
self.name
}

crate fn highlight_region_name(&self, diag: &mut DiagnosticBuilder<'_>) {
match &self.source {
RegionNameSource::NamedFreeRegion(span)
Expand All @@ -137,7 +137,8 @@ impl RegionName {
RegionNameSource::CannotMatchHirTy(span, type_name) => {
diag.span_label(*span, format!("has type `{}`", type_name));
}
RegionNameSource::MatchedHirTy(span) => {
RegionNameSource::MatchedHirTy(span) |
RegionNameSource::AnonRegionFromAsyncFn(span) => {
diag.span_label(
*span,
format!("let's call the lifetime of this reference `{}`", self),
Expand Down Expand Up @@ -270,7 +271,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
match error_region {
ty::ReEarlyBound(ebr) => {
if ebr.has_name() {
let span = self.get_named_span(tcx, error_region, ebr.name);
let span = tcx.hir().span_if_local(ebr.def_id).unwrap_or(DUMMY_SP);
Some(RegionName {
name: ebr.name,
source: RegionNameSource::NamedEarlyBoundRegion(span),
Expand All @@ -286,12 +287,30 @@ impl<'tcx> RegionInferenceContext<'tcx> {
}),

ty::ReFree(free_region) => match free_region.bound_region {
ty::BoundRegion::BrNamed(_, name) => {
let span = self.get_named_span(tcx, error_region, name);
Some(RegionName {
name,
source: RegionNameSource::NamedFreeRegion(span),
})
ty::BoundRegion::BrNamed(region_def_id, name) => {
// Get the span to point to, even if we don't use the name.
let span = tcx.hir().span_if_local(region_def_id).unwrap_or(DUMMY_SP);
debug!("bound region named: {:?}, is_named: {:?}",
name, free_region.bound_region.is_named());

if free_region.bound_region.is_named() {
// A named region that is actually named.
Some(RegionName {
name,
source: RegionNameSource::NamedFreeRegion(span),
})
} else {
// If we spuriously thought that the region is named, we should let the
// system generate a true name for error messages. Currently this can
// happen if we have an elided name in an async fn for example: the
// compiler will generate a region named `'_`, but reporting such a name is
// not actually useful, so we synthesize a name for it instead.
let name = renctx.synthesize_region_name();
Some(RegionName {
name,
source: RegionNameSource::AnonRegionFromAsyncFn(span),
})
}
}

ty::BoundRegion::BrEnv => {
Expand Down Expand Up @@ -350,40 +369,6 @@ impl<'tcx> RegionInferenceContext<'tcx> {
}
}

/// Gets a span of a named region to provide context for error messages that
/// mention that span, for example:
///
/// ```
/// |
/// | fn two_regions<'a, 'b, T>(cell: Cell<&'a ()>, t: T)
/// | -- -- lifetime `'b` defined here
/// | |
/// | lifetime `'a` defined here
/// |
/// | with_signature(cell, t, |cell, t| require(cell, t));
/// | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ argument requires that `'b` must
/// | outlive `'a`
/// ```
fn get_named_span(
&self,
tcx: TyCtxt<'tcx>,
error_region: &RegionKind,
name: Symbol,
) -> Span {
let scope = error_region.free_region_binding_scope(tcx);
let node = tcx.hir().as_local_hir_id(scope).unwrap_or(hir::DUMMY_HIR_ID);

let span = tcx.sess.source_map().def_span(tcx.hir().span(node));
if let Some(param) = tcx.hir()
.get_generics(scope)
.and_then(|generics| generics.get_named(name))
{
param.span
} else {
span
}
}

/// Finds an argument that contains `fr` and label it with a fully
/// elaborated type, returning something like `'1`. Result looks
/// like:
Expand Down
4 changes: 2 additions & 2 deletions src/test/ui/async-await/issues/issue-63388-1.nll.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,12 @@ error: lifetime may not live long enough
LL | async fn do_sth<'a>(
| -- lifetime `'a` defined here
LL | &'a self, foo: &dyn Foo
| - lifetime `'_` defined here
| - let's call the lifetime of this reference `'1`
LL | ) -> &dyn Foo
LL | / {
LL | | foo
LL | | }
| |_____^ function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'_`
| |_____^ function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'1`

error: aborting due to 2 previous errors

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@ error: lifetime may not live long enough
--> $DIR/arbitrary_self_types_pin_lifetime_impl_trait-async.rs:8:48
|
LL | async fn f(self: Pin<&Self>) -> impl Clone { self }
| - ^^^^^^^^ returning this value requires that `'_` must outlive `'static`
| - ^^^^^^^^ returning this value requires that `'1` must outlive `'static`
| |
| lifetime `'_` defined here
| let's call the lifetime of this reference `'1`
|
help: to allow this `impl Trait` to capture borrowed data with lifetime `'_`, add `'_` as a constraint
help: to allow this `impl Trait` to capture borrowed data with lifetime `'1`, add `'_` as a constraint
|
LL | async fn f(self: Pin<&Self>) -> impl Clone + '_ { self }
| ^^^^^^^^^^^^^^^
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,19 +10,19 @@ error: lifetime may not live long enough
--> $DIR/arbitrary_self_types_pin_lifetime_mismatch-async.rs:8:52
|
LL | async fn a(self: Pin<&Foo>, f: &Foo) -> &Foo { f }
| - ^ function was supposed to return data with lifetime `'_` but it is returning data with lifetime `'_`
| |
| lifetime `'_` defined here
| lifetime `'_` defined here
| - - ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
| | |
| | let's call the lifetime of this reference `'1`
| let's call the lifetime of this reference `'2`

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

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

error: aborting due to 5 previous errors
Expand Down
42 changes: 18 additions & 24 deletions src/test/ui/self/elision/lt-ref-self-async.nll.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,11 @@ error: lifetime may not live long enough
--> $DIR/lt-ref-self-async.rs:13:9
|
LL | async fn ref_self(&self, f: &u32) -> &u32 {
| -
| - - let's call the lifetime of this reference `'1`
| |
| lifetime `'_` defined here
| lifetime `'_` defined here
| let's call the lifetime of this reference `'2`
LL | f
| ^ function was supposed to return data with lifetime `'_` but it is returning data with lifetime `'_`
| ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`

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

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

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

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

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

error: aborting due to 12 previous errors

Expand Down
Loading