Skip to content

Commit

Permalink
Rollup merge of rust-lang#66679 - mark-i-m:fix-anon-lifetime-errors, …
Browse files Browse the repository at this point in the history
…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.
  • Loading branch information
Centril authored Dec 1, 2019
2 parents cb43d82 + 2a86b6c commit 99f9fa3
Show file tree
Hide file tree
Showing 10 changed files with 120 additions and 165 deletions.
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

0 comments on commit 99f9fa3

Please sign in to comment.