Skip to content

Commit

Permalink
Rollup merge of rust-lang#89734 - estebank:issue-72312, r=nikomatsakis
Browse files Browse the repository at this point in the history
Point at capture points for non-`'static` reference crossing a `yield` point

```
error[E0759]: `self` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement
  --> $DIR/issue-72312.rs:10:24
   |
LL |     pub async fn start(&self) {
   |                        ^^^^^ this data with an anonymous lifetime `'_`...
...
LL |         require_static(async move {
   |         -------------- ...is required to live as long as `'static` here...
LL |             &self;
   |             ----- ...and is captured here
   |
note: `'static` lifetime requirement introduced by this trait bound
  --> $DIR/issue-72312.rs:2:22
   |
LL | fn require_static<T: 'static>(val: T) -> T {
   |                      ^^^^^^^

error: aborting due to previous error

For more information about this error, try `rustc --explain E0759`.
```

Fix rust-lang#72312.
  • Loading branch information
matthiaskrgr committed Dec 11, 2021
2 parents b6d96a1 + d2d9eb3 commit d9df1a8
Show file tree
Hide file tree
Showing 37 changed files with 466 additions and 133 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -368,6 +368,7 @@ fn try_extract_error_from_fulfill_cx<'tcx>(
error_region,
cause.clone(),
placeholder_region,
vec![],
),
),
(Some(error_region), _) => NiceRegionError::new(
Expand Down
3 changes: 2 additions & 1 deletion compiler/rustc_infer/src/infer/error_reporting/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -384,6 +384,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
sub_r,
sup_origin,
sup_r,
_,
) => {
if sub_r.is_placeholder() {
self.report_placeholder_failure(sub_origin, sub_r, sup_r).emit();
Expand Down Expand Up @@ -464,7 +465,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
errors.sort_by_key(|u| match *u {
RegionResolutionError::ConcreteFailure(ref sro, _, _) => sro.span(),
RegionResolutionError::GenericBoundFailure(ref sro, _, _) => sro.span(),
RegionResolutionError::SubSupConflict(_, ref rvo, _, _, _, _) => rvo.span(),
RegionResolutionError::SubSupConflict(_, ref rvo, _, _, _, _, _) => rvo.span(),
RegionResolutionError::UpperBoundUniverseConflict(_, ref rvo, _, _, _) => rvo.span(),
});
errors
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ impl<'cx, 'tcx> NiceRegionError<'cx, 'tcx> {
pub fn regions(&self) -> Option<(Span, ty::Region<'tcx>, ty::Region<'tcx>)> {
match (&self.error, self.regions) {
(Some(ConcreteFailure(origin, sub, sup)), None) => Some((origin.span(), sub, sup)),
(Some(SubSupConflict(_, _, origin, sub, _, sup)), None) => {
(Some(SubSupConflict(_, _, origin, sub, _, sup, _)), None) => {
Some((origin.span(), sub, sup))
}
(None, Some((span, sub, sup))) => Some((span, sub, sup)),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ impl NiceRegionError<'me, 'tcx> {
sub_placeholder @ ty::RePlaceholder(_),
_,
sup_placeholder @ ty::RePlaceholder(_),
_,
)) => self.try_report_trait_placeholder_mismatch(
Some(self.tcx().mk_region(ty::ReVar(*vid))),
cause,
Expand All @@ -49,6 +50,7 @@ impl NiceRegionError<'me, 'tcx> {
sub_placeholder @ ty::RePlaceholder(_),
_,
_,
_,
)) => self.try_report_trait_placeholder_mismatch(
Some(self.tcx().mk_region(ty::ReVar(*vid))),
cause,
Expand All @@ -64,6 +66,7 @@ impl NiceRegionError<'me, 'tcx> {
_,
_,
sup_placeholder @ ty::RePlaceholder(_),
_,
)) => self.try_report_trait_placeholder_mismatch(
Some(self.tcx().mk_region(ty::ReVar(*vid))),
cause,
Expand All @@ -79,6 +82,7 @@ impl NiceRegionError<'me, 'tcx> {
_,
SubregionOrigin::Subtype(box TypeTrace { cause, values }),
sup_placeholder @ ty::RePlaceholder(_),
_,
)) => self.try_report_trait_placeholder_mismatch(
Some(self.tcx().mk_region(ty::ReVar(*vid))),
cause,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ use rustc_hir::def_id::DefId;
use rustc_hir::intravisit::{walk_ty, ErasedMap, NestedVisitorMap, Visitor};
use rustc_hir::{self as hir, GenericBound, Item, ItemKind, Lifetime, LifetimeName, Node, TyKind};
use rustc_middle::ty::{
self, AssocItemContainer, RegionKind, Ty, TyCtxt, TypeFoldable, TypeVisitor,
self, AssocItemContainer, RegionKind, StaticLifetimeVisitor, Ty, TyCtxt, TypeFoldable,
TypeVisitor,
};
use rustc_span::symbol::Ident;
use rustc_span::{MultiSpan, Span};
Expand All @@ -23,16 +24,17 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
pub(super) fn try_report_static_impl_trait(&self) -> Option<ErrorReported> {
debug!("try_report_static_impl_trait(error={:?})", self.error);
let tcx = self.tcx();
let (var_origin, sub_origin, sub_r, sup_origin, sup_r) = match self.error.as_ref()? {
let (var_origin, sub_origin, sub_r, sup_origin, sup_r, spans) = match self.error.as_ref()? {
RegionResolutionError::SubSupConflict(
_,
var_origin,
sub_origin,
sub_r,
sup_origin,
sup_r,
spans,
) if **sub_r == RegionKind::ReStatic => {
(var_origin, sub_origin, sub_r, sup_origin, sup_r)
(var_origin, sub_origin, sub_r, sup_origin, sup_r, spans)
}
RegionResolutionError::ConcreteFailure(
SubregionOrigin::Subtype(box TypeTrace { cause, .. }),
Expand Down Expand Up @@ -74,7 +76,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
err.span_label(
cause.span,
&format!(
"...is captured and required to live as long as `'static` here \
"...is used and required to live as long as `'static` here \
because of an implicit lifetime bound on the {}",
match ctxt.assoc_item.container {
AssocItemContainer::TraitContainer(id) =>
Expand Down Expand Up @@ -123,56 +125,101 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
param_name,
lifetime,
);
err.span_label(param.param_ty_span, &format!("this data with {}...", lifetime));
debug!("try_report_static_impl_trait: param_info={:?}", param);

// We try to make the output have fewer overlapping spans if possible.
if (sp == sup_origin.span() || !return_sp.overlaps(sup_origin.span()))
&& sup_origin.span() != return_sp
{
// FIXME: account for `async fn` like in `async-await/issues/issue-62097.rs`

// Customize the spans and labels depending on their relative order so
// that split sentences flow correctly.
if sup_origin.span().overlaps(return_sp) && sp == sup_origin.span() {
// Avoid the following:
//
// error: cannot infer an appropriate lifetime
// --> $DIR/must_outlive_least_region_or_bound.rs:18:50
// |
// LL | fn foo(x: &i32) -> Box<dyn Debug> { Box::new(x) }
// | ---- ---------^-
let (mention_influencer, influencer_point) =
if sup_origin.span().overlaps(param.param_ty_span) {
// Account for `async fn` like in `async-await/issues/issue-62097.rs`.
// The desugaring of `async `fn`s causes `sup_origin` and `param` to point at the same
// place (but with different `ctxt`, hence `overlaps` instead of `==` above).
//
// and instead show:
// This avoids the following:
//
// error: cannot infer an appropriate lifetime
// --> $DIR/must_outlive_least_region_or_bound.rs:18:50
// |
// LL | fn foo(x: &i32) -> Box<dyn Debug> { Box::new(x) }
// | ---- ^
err.span_label(
sup_origin.span(),
"...is captured here, requiring it to live as long as `'static`",
);
// LL | pub async fn run_dummy_fn(&self) {
// | ^^^^^
// | |
// | this data with an anonymous lifetime `'_`...
// | ...is captured here...
(false, sup_origin.span())
} else {
err.span_label(sup_origin.span(), "...is captured here...");
if return_sp < sup_origin.span() {
err.span_note(
return_sp,
"...and is required to live as long as `'static` here",
(!sup_origin.span().overlaps(return_sp), param.param_ty_span)
};
err.span_label(influencer_point, &format!("this data with {}...", lifetime));

debug!("try_report_static_impl_trait: param_info={:?}", param);

let mut spans = spans.clone();

if mention_influencer {
spans.push(sup_origin.span());
}
// We dedup the spans *ignoring* expansion context.
spans.sort();
spans.dedup_by_key(|span| (span.lo(), span.hi()));

// We try to make the output have fewer overlapping spans if possible.
let require_msg = if spans.is_empty() {
"...is used and required to live as long as `'static` here"
} else {
"...and is required to live as long as `'static` here"
};
let require_span =
if sup_origin.span().overlaps(return_sp) { sup_origin.span() } else { return_sp };

for span in &spans {
err.span_label(*span, "...is used here...");
}

if spans.iter().any(|sp| sp.overlaps(return_sp) || *sp > return_sp) {
// If any of the "captured here" labels appears on the same line or after
// `require_span`, we put it on a note to ensure the text flows by appearing
// always at the end.
err.span_note(require_span, require_msg);
} else {
// We don't need a note, it's already at the end, it can be shown as a `span_label`.
err.span_label(require_span, require_msg);
}

if let SubregionOrigin::RelateParamBound(_, _, Some(bound)) = sub_origin {
err.span_note(*bound, "`'static` lifetime requirement introduced by this bound");
}
if let SubregionOrigin::Subtype(box TypeTrace { cause, .. }) = sub_origin {
if let ObligationCauseCode::ReturnValue(hir_id)
| ObligationCauseCode::BlockTailExpression(hir_id) = &cause.code
{
let parent_id = tcx.hir().get_parent_item(*hir_id);
if let Some(fn_decl) = tcx.hir().fn_decl_by_hir_id(parent_id) {
let mut span: MultiSpan = fn_decl.output.span().into();
let mut add_label = true;
if let hir::FnRetTy::Return(ty) = fn_decl.output {
let mut v = StaticLifetimeVisitor(vec![], tcx.hir());
v.visit_ty(ty);
if !v.0.is_empty() {
span = v.0.clone().into();
for sp in v.0 {
span.push_span_label(
sp,
"`'static` requirement introduced here".to_string(),
);
}
add_label = false;
}
}
if add_label {
span.push_span_label(
fn_decl.output.span(),
"requirement introduced by this return type".to_string(),
);
}
span.push_span_label(
cause.span,
"because of this returned expression".to_string(),
);
} else {
err.span_label(
return_sp,
"...and is required to live as long as `'static` here",
err.span_note(
span,
"`'static` lifetime requirement introduced by the return type",
);
}
}
} else {
err.span_label(
return_sp,
"...is captured and required to live as long as `'static` here",
);
}

let fn_returns = tcx.return_type_impl_or_dyn_traits(anon_reg_sup.def_id);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
_sub,
sup_origin,
_sup,
_,
) = error.clone()
{
if let (&Subtype(ref sup_trace), &Subtype(ref sub_trace)) = (&sup_origin, &sub_origin) {
Expand Down
30 changes: 29 additions & 1 deletion compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_middle::ty::{ReEarlyBound, ReEmpty, ReErased, ReFree, ReStatic};
use rustc_middle::ty::{ReLateBound, RePlaceholder, ReVar};
use rustc_middle::ty::{Region, RegionVid};
use rustc_span::Span;
use std::fmt;

/// This function performs lexical region resolution given a complete
Expand Down Expand Up @@ -96,6 +97,7 @@ pub enum RegionResolutionError<'tcx> {
Region<'tcx>,
SubregionOrigin<'tcx>,
Region<'tcx>,
Vec<Span>, // All the influences on a given value that didn't meet its constraints.
),

/// Indicates a `'b: 'a` constraint where `'a` is in a universe that
Expand Down Expand Up @@ -567,7 +569,30 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
// if this rule starts to create problems we'll
// have to revisit this portion of the code and
// think hard about it. =) -- nikomatsakis
self.collect_error_for_expanding_node(graph, &mut dup_vec, node_vid, errors);

// Obtain the spans for all the places that can
// influence the constraints on this value for
// richer diagnostics in `static_impl_trait`.
let influences: Vec<Span> = self
.data
.constraints
.iter()
.filter_map(|(constraint, origin)| match (constraint, origin) {
(
Constraint::VarSubVar(_, sup),
SubregionOrigin::DataBorrowed(_, sp),
) if sup == &node_vid => Some(*sp),
_ => None,
})
.collect();

self.collect_error_for_expanding_node(
graph,
&mut dup_vec,
node_vid,
errors,
influences,
);
}
}
}
Expand Down Expand Up @@ -621,6 +646,7 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
dup_vec: &mut IndexVec<RegionVid, Option<RegionVid>>,
node_idx: RegionVid,
errors: &mut Vec<RegionResolutionError<'tcx>>,
influences: Vec<Span>,
) {
// Errors in expanding nodes result from a lower-bound that is
// not contained by an upper-bound.
Expand Down Expand Up @@ -667,13 +693,15 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
sup: {:?}",
origin, node_idx, lower_bound.region, upper_bound.region
);

errors.push(RegionResolutionError::SubSupConflict(
node_idx,
origin,
lower_bound.origin.clone(),
lower_bound.region,
upper_bound.origin.clone(),
upper_bound.region,
influences,
));
return;
}
Expand Down
36 changes: 2 additions & 34 deletions compiler/rustc_middle/src/ty/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1481,40 +1481,8 @@ impl<'tcx> TyCtxt<'tcx> {
scope_def_id: LocalDefId,
) -> Vec<&'tcx hir::Ty<'tcx>> {
let hir_id = self.hir().local_def_id_to_hir_id(scope_def_id);
let hir_output = match self.hir().get(hir_id) {
Node::Item(hir::Item {
kind:
ItemKind::Fn(
hir::FnSig {
decl: hir::FnDecl { output: hir::FnRetTy::Return(ty), .. },
..
},
..,
),
..
})
| Node::ImplItem(hir::ImplItem {
kind:
hir::ImplItemKind::Fn(
hir::FnSig {
decl: hir::FnDecl { output: hir::FnRetTy::Return(ty), .. },
..
},
_,
),
..
})
| Node::TraitItem(hir::TraitItem {
kind:
hir::TraitItemKind::Fn(
hir::FnSig {
decl: hir::FnDecl { output: hir::FnRetTy::Return(ty), .. },
..
},
_,
),
..
}) => ty,
let hir_output = match self.hir().fn_decl_by_hir_id(hir_id) {
Some(hir::FnDecl { output: hir::FnRetTy::Return(ty), .. }) => ty,
_ => return vec![],
};

Expand Down
Loading

0 comments on commit d9df1a8

Please sign in to comment.