1
Fork 0

Recover most impl Trait and dyn Trait lifetime bound suggestions under NLL

This commit is contained in:
marmeladema 2022-04-24 16:44:09 +02:00
parent fedbe5dabc
commit e1b074a2a8
14 changed files with 244 additions and 148 deletions

View file

@ -1,17 +1,17 @@
//! Error reporting machinery for lifetime errors.
use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed};
use rustc_errors::{Diagnostic, DiagnosticBuilder, ErrorGuaranteed};
use rustc_infer::infer::{
error_reporting::nice_region_error::NiceRegionError,
error_reporting::unexpected_hidden_region_diagnostic, NllRegionVariableOrigin,
RelateParamBound,
error_reporting::nice_region_error::{self, find_param_with_region, NiceRegionError},
error_reporting::unexpected_hidden_region_diagnostic,
NllRegionVariableOrigin, RelateParamBound,
};
use rustc_middle::hir::place::PlaceBase;
use rustc_middle::mir::{ConstraintCategory, ReturnConstraint};
use rustc_middle::ty::subst::{InternalSubsts, Subst};
use rustc_middle::ty::subst::InternalSubsts;
use rustc_middle::ty::{self, RegionVid, Ty};
use rustc_span::symbol::{kw, sym};
use rustc_span::{BytePos, Span};
use rustc_span::symbol::sym;
use rustc_span::Span;
use crate::borrowck_errors;
@ -651,82 +651,47 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
fr_name: RegionName,
outlived_fr: RegionVid,
) {
if let (Some(f), Some(ty::ReStatic)) =
(self.to_error_region(fr), self.to_error_region(outlived_fr).as_deref())
if let (Some(f), Some(outlived_f)) =
(self.to_error_region(fr), self.to_error_region(outlived_fr))
{
if let Some(&ty::Opaque(did, substs)) = self
if *outlived_f != ty::ReStatic {
return;
}
let fn_returns = self
.infcx
.tcx
.is_suitable_region(f)
.map(|r| r.def_id)
.and_then(|id| self.infcx.tcx.return_type_impl_trait(id))
.map(|(ty, _)| ty.kind())
{
// Check whether or not the impl trait return type is intended to capture
// data with the static lifetime.
//
// eg. check for `impl Trait + 'static` instead of `impl Trait`.
let has_static_predicate = {
let bounds = self.infcx.tcx.explicit_item_bounds(did);
.map(|r| self.infcx.tcx.return_type_impl_or_dyn_traits(r.def_id))
.unwrap_or_default();
let mut found = false;
for (bound, _) in bounds {
if let ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(_, r)) =
bound.kind().skip_binder()
{
let r = r.subst(self.infcx.tcx, substs);
if r.is_static() {
found = true;
break;
} else {
// If there's already a lifetime bound, don't
// suggest anything.
return;
}
}
}
found
};
debug!(
"add_static_impl_trait_suggestion: has_static_predicate={:?}",
has_static_predicate
);
let static_str = kw::StaticLifetime;
// If there is a static predicate, then the only sensible suggestion is to replace
// fr with `'static`.
if has_static_predicate {
diag.help(&format!("consider replacing `{fr_name}` with `{static_str}`"));
} else {
// Otherwise, we should suggest adding a constraint on the return type.
let span = self.infcx.tcx.def_span(did);
if let Ok(snippet) = self.infcx.tcx.sess.source_map().span_to_snippet(span) {
let suggestable_fr_name = if fr_name.was_named() {
fr_name.to_string()
} else {
"'_".to_string()
};
let span = if snippet.ends_with(';') {
// `type X = impl Trait;`
span.with_hi(span.hi() - BytePos(1))
} else {
span
};
let suggestion = format!(" + {suggestable_fr_name}");
let span = span.shrink_to_hi();
diag.span_suggestion(
span,
&format!(
"to allow this `impl Trait` to capture borrowed data with lifetime \
`{fr_name}`, add `{suggestable_fr_name}` as a bound",
),
suggestion,
Applicability::MachineApplicable,
);
}
}
if fn_returns.is_empty() {
return;
}
let param = if let Some(param) = find_param_with_region(self.infcx.tcx, f, outlived_f) {
param
} else {
return;
};
let lifetime = if f.has_name() { fr_name.to_string() } else { "'_".to_string() };
let arg = match param.param.pat.simple_ident() {
Some(simple_ident) => format!("argument `{}`", simple_ident),
None => "the argument".to_string(),
};
let captures = format!("captures data from {}", arg);
return nice_region_error::suggest_new_region_bound(
self.infcx.tcx,
diag,
fn_returns,
lifetime,
Some(arg),
captures,
Some((param.param_ty_span, param.param_ty.to_string())),
);
}
}
}