Skip to content
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

Give name if anonymous region appears in impl signature #98184

Merged
merged 1 commit into from
Jun 24, 2022
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
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,8 @@ impl OutlivesSuggestionBuilder {
| RegionNameSource::AnonRegionFromUpvar(..)
| RegionNameSource::AnonRegionFromOutput(..)
| RegionNameSource::AnonRegionFromYieldTy(..)
| RegionNameSource::AnonRegionFromAsyncFn(..) => {
| RegionNameSource::AnonRegionFromAsyncFn(..)
| RegionNameSource::AnonRegionFromImplSignature(..) => {
debug!("Region {:?} is NOT suggestable", name);
false
}
Expand Down
58 changes: 54 additions & 4 deletions compiler/rustc_borrowck/src/diagnostics/region_name.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use rustc_hir as hir;
use rustc_hir::def::{DefKind, Res};
use rustc_middle::ty::print::RegionHighlightMode;
use rustc_middle::ty::subst::{GenericArgKind, SubstsRef};
use rustc_middle::ty::{self, RegionVid, Ty};
use rustc_middle::ty::{self, DefIdTree, RegionVid, Ty};
use rustc_span::symbol::{kw, sym, Ident, Symbol};
use rustc_span::{Span, DUMMY_SP};

Expand Down Expand Up @@ -45,6 +45,8 @@ pub(crate) enum RegionNameSource {
AnonRegionFromYieldTy(Span, String),
/// An anonymous region from an async fn.
AnonRegionFromAsyncFn(Span),
/// An anonymous region from an impl self type or trait
AnonRegionFromImplSignature(Span, &'static str),
}

/// Describes what to highlight to explain to the user that we're giving an anonymous region a
Expand Down Expand Up @@ -75,7 +77,8 @@ impl RegionName {
| RegionNameSource::AnonRegionFromUpvar(..)
| RegionNameSource::AnonRegionFromOutput(..)
| RegionNameSource::AnonRegionFromYieldTy(..)
| RegionNameSource::AnonRegionFromAsyncFn(..) => false,
| RegionNameSource::AnonRegionFromAsyncFn(..)
| RegionNameSource::AnonRegionFromImplSignature(..) => false,
}
}

Expand All @@ -87,7 +90,8 @@ impl RegionName {
| RegionNameSource::SynthesizedFreeEnvRegion(span, _)
| RegionNameSource::AnonRegionFromUpvar(span, _)
| RegionNameSource::AnonRegionFromYieldTy(span, _)
| RegionNameSource::AnonRegionFromAsyncFn(span) => Some(span),
| RegionNameSource::AnonRegionFromAsyncFn(span)
| RegionNameSource::AnonRegionFromImplSignature(span, _) => Some(span),
RegionNameSource::AnonRegionFromArgument(ref highlight)
| RegionNameSource::AnonRegionFromOutput(ref highlight, _) => match *highlight {
RegionNameHighlight::MatchedHirTy(span)
Expand Down Expand Up @@ -166,6 +170,12 @@ impl RegionName {
RegionNameSource::AnonRegionFromYieldTy(span, type_name) => {
diag.span_label(*span, format!("yield type is {type_name}"));
}
RegionNameSource::AnonRegionFromImplSignature(span, location) => {
diag.span_label(
*span,
format!("lifetime `{self}` appears in the `impl`'s {location}"),
);
}
RegionNameSource::Static => {}
}
}
Expand Down Expand Up @@ -240,7 +250,8 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
.or_else(|| self.give_name_if_anonymous_region_appears_in_arguments(fr))
.or_else(|| self.give_name_if_anonymous_region_appears_in_upvars(fr))
.or_else(|| self.give_name_if_anonymous_region_appears_in_output(fr))
.or_else(|| self.give_name_if_anonymous_region_appears_in_yield_ty(fr));
.or_else(|| self.give_name_if_anonymous_region_appears_in_yield_ty(fr))
.or_else(|| self.give_name_if_anonymous_region_appears_in_impl_signature(fr));

if let Some(ref value) = value {
self.region_names.try_borrow_mut().unwrap().insert(fr, value.clone());
Expand Down Expand Up @@ -840,4 +851,43 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
source: RegionNameSource::AnonRegionFromYieldTy(yield_span, type_name),
})
}

fn give_name_if_anonymous_region_appears_in_impl_signature(
&self,
fr: RegionVid,
) -> Option<RegionName> {
let ty::ReEarlyBound(region) = *self.to_error_region(fr)? else {
return None;
};
if region.has_name() {
return None;
};

let tcx = self.infcx.tcx;
let body_parent_did = tcx.opt_parent(self.mir_def_id().to_def_id())?;
if tcx.parent(region.def_id) != body_parent_did
|| tcx.def_kind(body_parent_did) != DefKind::Impl
{
return None;
}

let mut found = false;
tcx.fold_regions(tcx.type_of(body_parent_did), &mut true, |r: ty::Region<'tcx>, _| {
if *r == ty::ReEarlyBound(region) {
found = true;
}
r
});

Some(RegionName {
name: self.synthesize_region_name(),
source: RegionNameSource::AnonRegionFromImplSignature(
tcx.def_span(region.def_id),
// FIXME(compiler-errors): Does this ever actually show up
// anywhere other than the self type? I couldn't create an
// example of a `'_` in the impl's trait being referenceable.
compiler-errors marked this conversation as resolved.
Show resolved Hide resolved
if found { "self type" } else { "header" },
),
})
}
}
25 changes: 25 additions & 0 deletions src/test/ui/nll/issue-98170.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
pub struct MyStruct<'a> {
field: &'a [u32],
}

impl MyStruct<'_> {
pub fn new<'a>(field: &'a [u32]) -> MyStruct<'a> {
Self { field }
//~^ ERROR lifetime may not live long enough
//~| ERROR lifetime may not live long enough
}
}
compiler-errors marked this conversation as resolved.
Show resolved Hide resolved

trait Trait<'a> {
fn new(field: &'a [u32]) -> MyStruct<'a>;
}

impl<'a> Trait<'a> for MyStruct<'_> {
fn new(field: &'a [u32]) -> MyStruct<'a> {
Self { field }
//~^ ERROR lifetime may not live long enough
//~| ERROR lifetime may not live long enough
}
}

fn main() {}
44 changes: 44 additions & 0 deletions src/test/ui/nll/issue-98170.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
error: lifetime may not live long enough
--> $DIR/issue-98170.rs:7:9
|
LL | impl MyStruct<'_> {
| -- lifetime `'1` appears in the `impl`'s self type
LL | pub fn new<'a>(field: &'a [u32]) -> MyStruct<'a> {
| -- lifetime `'a` defined here
LL | Self { field }
| ^^^^^^^^^^^^^^ associated function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'1`

error: lifetime may not live long enough
--> $DIR/issue-98170.rs:7:16
|
LL | impl MyStruct<'_> {
| -- lifetime `'1` appears in the `impl`'s self type
LL | pub fn new<'a>(field: &'a [u32]) -> MyStruct<'a> {
| -- lifetime `'a` defined here
LL | Self { field }
| ^^^^^ this usage requires that `'a` must outlive `'1`

error: lifetime may not live long enough
--> $DIR/issue-98170.rs:19:9
|
LL | impl<'a> Trait<'a> for MyStruct<'_> {
| -- -- lifetime `'1` appears in the `impl`'s self type
| |
| lifetime `'a` defined here
LL | fn new(field: &'a [u32]) -> MyStruct<'a> {
LL | Self { field }
| ^^^^^^^^^^^^^^ associated function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'1`

error: lifetime may not live long enough
--> $DIR/issue-98170.rs:19:16
|
LL | impl<'a> Trait<'a> for MyStruct<'_> {
| -- -- lifetime `'1` appears in the `impl`'s self type
| |
| lifetime `'a` defined here
LL | fn new(field: &'a [u32]) -> MyStruct<'a> {
LL | Self { field }
| ^^^^^ this usage requires that `'a` must outlive `'1`

error: aborting due to 4 previous errors