Provide more information for HRTB lifetime errors involving closures

This commit is contained in:
Esteban Küber 2020-12-01 00:10:13 -08:00
parent 704e47f78b
commit a8a974245e
18 changed files with 392 additions and 25 deletions

View file

@ -98,7 +98,7 @@ pub(super) fn note_and_explain_region(
// uh oh, hope no user ever sees THIS
ty::ReEmpty(ui) => (format!("the empty lifetime in universe {:?}", ui), None),
ty::RePlaceholder(_) => ("any other region".to_string(), None),
ty::RePlaceholder(_) => return,
// FIXME(#13998) RePlaceholder should probably print like
// ReFree rather than dumping Debug output on the user.
@ -1675,6 +1675,16 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
self.check_and_note_conflicting_crates(diag, terr);
self.tcx.note_and_explain_type_err(diag, terr, cause, span, body_owner_def_id.to_def_id());
if let Some(ValuePairs::PolyTraitRefs(exp_found)) = values {
if let ty::Closure(def_id, _) = exp_found.expected.skip_binder().self_ty().kind() {
if let Some(def_id) = def_id.as_local() {
let hir_id = self.tcx.hir().local_def_id_to_hir_id(def_id);
let span = self.tcx.hir().span(hir_id);
diag.span_note(span, "this closure does not fulfill the lifetime requirements");
}
}
}
// It reads better to have the error origin as the final
// thing.
self.note_error_origin(diag, cause, exp_found);

View file

@ -1,6 +1,7 @@
use crate::infer::error_reporting::{note_and_explain_region, ObligationCauseExt};
use crate::infer::{self, InferCtxt, SubregionOrigin};
use rustc_errors::{struct_span_err, DiagnosticBuilder};
use rustc_middle::traits::ObligationCauseCode;
use rustc_middle::ty::error::TypeError;
use rustc_middle::ty::{self, Region};
@ -107,14 +108,37 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
infer::Subtype(box trace) => {
let terr = TypeError::RegionsDoesNotOutlive(sup, sub);
let mut err = self.report_and_explain_type_error(trace, &terr);
note_and_explain_region(self.tcx, &mut err, "", sup, "...");
note_and_explain_region(
self.tcx,
&mut err,
"...does not necessarily outlive ",
sub,
"",
);
match (sub, sup) {
(ty::RePlaceholder(_), ty::RePlaceholder(_)) => {}
(ty::RePlaceholder(_), _) => {
note_and_explain_region(
self.tcx,
&mut err,
"",
sup,
" doesn't meet the lifetime requirements",
);
}
(_, ty::RePlaceholder(_)) => {
note_and_explain_region(
self.tcx,
&mut err,
"the required lifetime does not necessarily outlive ",
sub,
"",
);
}
_ => {
note_and_explain_region(self.tcx, &mut err, "", sup, "...");
note_and_explain_region(
self.tcx,
&mut err,
"...does not necessarily outlive ",
sub,
"",
);
}
}
err
}
infer::Reborrow(span) => {
@ -286,13 +310,31 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
sup: Region<'tcx>,
) -> DiagnosticBuilder<'tcx> {
// I can't think how to do better than this right now. -nikomatsakis
debug!(?placeholder_origin, ?sub, ?sup, "report_placeholder_failure");
match placeholder_origin {
infer::Subtype(box ref trace)
if matches!(
&trace.cause.code.peel_derives(),
ObligationCauseCode::BindingObligation(..)
) =>
{
// Hack to get around the borrow checker because trace.cause has an `Rc`.
if let ObligationCauseCode::BindingObligation(_, span) =
&trace.cause.code.peel_derives()
{
let span = *span;
let mut err = self.report_concrete_failure(placeholder_origin, sub, sup);
err.span_note(span, "the lifetime requirement is introduced here");
err
} else {
unreachable!()
}
}
infer::Subtype(box trace) => {
let terr = TypeError::RegionsPlaceholderMismatch;
self.report_and_explain_type_error(trace, &terr)
return self.report_and_explain_type_error(trace, &terr);
}
_ => self.report_concrete_failure(placeholder_origin, sub, sup),
_ => return self.report_concrete_failure(placeholder_origin, sub, sup),
}
}
}