Skip to content

Commit

Permalink
Auto merge of rust-lang#87628 - estebank:unmet-explicit-lifetime-boun…
Browse files Browse the repository at this point in the history
…d, r=oli-obk

Point at unmet explicit lifetime obligation bound

r? `@oli-obk`

Split off of rust-lang#85799.
  • Loading branch information
bors committed Aug 2, 2021
2 parents e3b1c12 + e5d42af commit f63ab6c
Show file tree
Hide file tree
Showing 24 changed files with 238 additions and 55 deletions.
25 changes: 16 additions & 9 deletions compiler/rustc_infer/src/infer/error_reporting/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -89,16 +89,17 @@ pub(super) fn note_and_explain_region(
prefix: &str,
region: ty::Region<'tcx>,
suffix: &str,
alt_span: Option<Span>,
) {
let (description, span) = match *region {
ty::ReEarlyBound(_) | ty::ReFree(_) | ty::ReStatic => {
msg_span_from_free_region(tcx, region)
msg_span_from_free_region(tcx, region, alt_span)
}

ty::ReEmpty(ty::UniverseIndex::ROOT) => ("the empty lifetime".to_owned(), None),
ty::ReEmpty(ty::UniverseIndex::ROOT) => ("the empty lifetime".to_owned(), alt_span),

// uh oh, hope no user ever sees THIS
ty::ReEmpty(ui) => (format!("the empty lifetime in universe {:?}", ui), None),
ty::ReEmpty(ui) => (format!("the empty lifetime in universe {:?}", ui), alt_span),

ty::RePlaceholder(_) => return,

Expand All @@ -108,7 +109,7 @@ pub(super) fn note_and_explain_region(
// We shouldn't really be having unification failures with ReVar
// and ReLateBound though.
ty::ReVar(_) | ty::ReLateBound(..) | ty::ReErased => {
(format!("lifetime {:?}", region), None)
(format!("lifetime {:?}", region), alt_span)
}
};

Expand All @@ -122,22 +123,23 @@ pub(super) fn note_and_explain_free_region(
region: ty::Region<'tcx>,
suffix: &str,
) {
let (description, span) = msg_span_from_free_region(tcx, region);
let (description, span) = msg_span_from_free_region(tcx, region, None);

emit_msg_span(err, prefix, description, span, suffix);
}

fn msg_span_from_free_region(
tcx: TyCtxt<'tcx>,
region: ty::Region<'tcx>,
alt_span: Option<Span>,
) -> (String, Option<Span>) {
match *region {
ty::ReEarlyBound(_) | ty::ReFree(_) => {
msg_span_from_early_bound_and_free_regions(tcx, region)
}
ty::ReStatic => ("the static lifetime".to_owned(), None),
ty::ReEmpty(ty::UniverseIndex::ROOT) => ("an empty lifetime".to_owned(), None),
ty::ReEmpty(ui) => (format!("an empty lifetime in universe {:?}", ui), None),
ty::ReStatic => ("the static lifetime".to_owned(), alt_span),
ty::ReEmpty(ty::UniverseIndex::ROOT) => ("an empty lifetime".to_owned(), alt_span),
ty::ReEmpty(ui) => (format!("an empty lifetime in universe {:?}", ui), alt_span),
_ => bug!("{:?}", region),
}
}
Expand Down Expand Up @@ -319,6 +321,7 @@ pub fn unexpected_hidden_region_diagnostic(
&format!("hidden type `{}` captures ", hidden_ty),
hidden_region,
"",
None,
);
}
}
Expand Down Expand Up @@ -2303,8 +2306,9 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
&format!("{} must be valid for ", labeled_user_string),
sub,
"...",
None,
);
if let Some(infer::RelateParamBound(_, t)) = origin {
if let Some(infer::RelateParamBound(_, t, _)) = origin {
let return_impl_trait = self
.in_progress_typeck_results
.map(|typeck_results| typeck_results.borrow().hir_owner)
Expand Down Expand Up @@ -2350,6 +2354,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
"first, the lifetime cannot outlive ",
sup_region,
"...",
None,
);

debug!("report_sub_sup_conflict: var_origin={:?}", var_origin);
Expand All @@ -2376,6 +2381,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
"...but the lifetime must also be valid for ",
sub_region,
"...",
None,
);
err.span_note(
sup_trace.cause.span,
Expand All @@ -2397,6 +2403,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
"but, the lifetime must be valid for ",
sub_region,
"...",
None,
);

self.note_region_origin(&mut err, &sub_origin);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
multi_span
.push_span_label(binding_span, "introduces a `'static` lifetime requirement".into());
err.span_note(multi_span, "because this has an unmet lifetime requirement");
note_and_explain_region(self.tcx(), &mut err, "", sup, "...");
note_and_explain_region(self.tcx(), &mut err, "", sup, "...", Some(binding_span));
if let Some(impl_node) = self.tcx().hir().get_if_local(*impl_def_id) {
// If an impl is local, then maybe this isn't what they want. Try to
// be as helpful as possible with implicit lifetimes.
Expand Down
82 changes: 69 additions & 13 deletions compiler/rustc_infer/src/infer/error_reporting/note.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,14 +74,18 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
),
);
}
infer::RelateParamBound(span, t) => {
infer::RelateParamBound(span, t, opt_span) => {
label_or_note(
span,
&format!(
"...so that the type `{}` will meet its required lifetime bounds",
self.ty_to_string(t)
"...so that the type `{}` will meet its required lifetime bounds{}",
self.ty_to_string(t),
if opt_span.is_some() { "..." } else { "" },
),
);
if let Some(span) = opt_span {
err.span_note(span, "...that is required by this bound");
}
}
infer::RelateRegionParamBound(span) => {
label_or_note(
Expand Down Expand Up @@ -117,6 +121,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
"",
sup,
" doesn't meet the lifetime requirements",
None,
);
}
(_, ty::RePlaceholder(_)) => {
Expand All @@ -126,16 +131,18 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
"the required lifetime does not necessarily outlive ",
sub,
"",
None,
);
}
_ => {
note_and_explain_region(self.tcx, &mut err, "", sup, "...");
note_and_explain_region(self.tcx, &mut err, "", sup, "...", None);
note_and_explain_region(
self.tcx,
&mut err,
"...does not necessarily outlive ",
sub,
"",
None,
);
}
}
Expand All @@ -154,13 +161,15 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
"...the reference is valid for ",
sub,
"...",
None,
);
note_and_explain_region(
self.tcx,
&mut err,
"...but the borrowed content is only valid for ",
sup,
"",
None,
);
err
}
Expand All @@ -179,13 +188,15 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
"...the borrowed pointer is valid for ",
sub,
"...",
None,
);
note_and_explain_region(
self.tcx,
&mut err,
&format!("...but `{}` is only valid for ", var_name),
sup,
"",
None,
);
err
}
Expand All @@ -197,17 +208,25 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
"lifetime of the source pointer does not outlive lifetime bound of the \
object type"
);
note_and_explain_region(self.tcx, &mut err, "object type is valid for ", sub, "");
note_and_explain_region(
self.tcx,
&mut err,
"object type is valid for ",
sub,
"",
None,
);
note_and_explain_region(
self.tcx,
&mut err,
"source pointer is only valid for ",
sup,
"",
None,
);
err
}
infer::RelateParamBound(span, ty) => {
infer::RelateParamBound(span, ty, opt_span) => {
let mut err = struct_span_err!(
self.tcx.sess,
span,
Expand All @@ -216,10 +235,22 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
self.ty_to_string(ty)
);
match *sub {
ty::ReStatic => {
note_and_explain_region(self.tcx, &mut err, "type must satisfy ", sub, "")
}
_ => note_and_explain_region(self.tcx, &mut err, "type must outlive ", sub, ""),
ty::ReStatic => note_and_explain_region(
self.tcx,
&mut err,
"type must satisfy ",
sub,
if opt_span.is_some() { " as required by this binding" } else { "" },
opt_span,
),
_ => note_and_explain_region(
self.tcx,
&mut err,
"type must outlive ",
sub,
if opt_span.is_some() { " as required by this binding" } else { "" },
opt_span,
),
}
err
}
Expand All @@ -232,13 +263,15 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
"lifetime parameter instantiated with ",
sup,
"",
None,
);
note_and_explain_region(
self.tcx,
&mut err,
"but lifetime parameter must outlive ",
sub,
"",
None,
);
err
}
Expand All @@ -255,6 +288,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
"the return value is only valid for ",
sup,
"",
None,
);
err
}
Expand All @@ -266,8 +300,22 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
"a value of type `{}` is borrowed for too long",
self.ty_to_string(ty)
);
note_and_explain_region(self.tcx, &mut err, "the type is valid for ", sub, "");
note_and_explain_region(self.tcx, &mut err, "but the borrow lasts for ", sup, "");
note_and_explain_region(
self.tcx,
&mut err,
"the type is valid for ",
sub,
"",
None,
);
note_and_explain_region(
self.tcx,
&mut err,
"but the borrow lasts for ",
sup,
"",
None,
);
err
}
infer::ReferenceOutlivesReferent(ty, span) => {
Expand All @@ -278,13 +326,21 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
"in type `{}`, reference has a longer lifetime than the data it references",
self.ty_to_string(ty)
);
note_and_explain_region(self.tcx, &mut err, "the pointer is valid for ", sub, "");
note_and_explain_region(
self.tcx,
&mut err,
"the pointer is valid for ",
sub,
"",
None,
);
note_and_explain_region(
self.tcx,
&mut err,
"but the referenced data is only valid for ",
sup,
"",
None,
);
err
}
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_infer/src/infer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -375,7 +375,7 @@ pub enum SubregionOrigin<'tcx> {

/// Some type parameter was instantiated with the given type,
/// and that type must outlive some region.
RelateParamBound(Span, Ty<'tcx>),
RelateParamBound(Span, Ty<'tcx>, Option<Span>),

/// The given region parameter was instantiated with a region
/// that must outlive some other region.
Expand Down Expand Up @@ -1705,7 +1705,7 @@ impl<'tcx> SubregionOrigin<'tcx> {
match *self {
Subtype(ref a) => a.span(),
RelateObjectBound(a) => a,
RelateParamBound(a, _) => a,
RelateParamBound(a, ..) => a,
RelateRegionParamBound(a) => a,
Reborrow(a) => a,
ReborrowUpvar(a, _) => a,
Expand Down
11 changes: 9 additions & 2 deletions compiler/rustc_infer/src/infer/outlives/obligations.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ use crate::infer::outlives::verify::VerifyBoundCx;
use crate::infer::{
self, GenericKind, InferCtxt, RegionObligation, SubregionOrigin, UndoLog, VerifyBound,
};
use crate::traits::ObligationCause;
use crate::traits::{ObligationCause, ObligationCauseCode};
use rustc_middle::ty::outlives::Component;
use rustc_middle::ty::subst::GenericArgKind;
use rustc_middle::ty::{self, Region, Ty, TyCtxt, TypeFoldable};
Expand Down Expand Up @@ -99,7 +99,14 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
cause: &ObligationCause<'tcx>,
) {
let origin = SubregionOrigin::from_obligation_cause(cause, || {
infer::RelateParamBound(cause.span, sup_type)
infer::RelateParamBound(
cause.span,
sup_type,
match cause.code.peel_derives() {
ObligationCauseCode::BindingObligation(_, span) => Some(*span),
_ => None,
},
)
});

self.register_region_obligation(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
GenericArgKind::Type(t1) => {
// we don't actually use this for anything, but
// the `TypeOutlives` code needs an origin.
let origin = infer::RelateParamBound(DUMMY_SP, t1);
let origin = infer::RelateParamBound(DUMMY_SP, t1, None);

TypeOutlives::new(
&mut *self,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,13 @@ error[E0310]: the parameter type `U` may not live long enough
LL | struct Foo<U> {
| - help: consider adding an explicit lifetime bound...: `U: 'static`
LL | bar: Bar<U>
| ^^^^^^ ...so that the type `U` will meet its required lifetime bounds
| ^^^^^^ ...so that the type `U` will meet its required lifetime bounds...
|
note: ...that is required by this bound
--> $DIR/feature-gate-infer_static_outlives_requirements.rs:7:15
|
LL | struct Bar<T: 'static> {
| ^^^^^^^

error: aborting due to previous error

Expand Down
Loading

0 comments on commit f63ab6c

Please sign in to comment.