summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_infer/src/infer/error_reporting/nice_region_error
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/nice_region_error/different_lifetimes.rs147
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/nice_region_error/find_anon_type.rs10
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mismatched_static_lifetime.rs54
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs5
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs6
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs15
6 files changed, 81 insertions, 156 deletions
diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/different_lifetimes.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/different_lifetimes.rs
index 9a2ab3e32..3a4320a9a 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/different_lifetimes.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/different_lifetimes.rs
@@ -1,6 +1,9 @@
//! Error Reporting for Anonymous Region Lifetime Errors
//! where both the regions are anonymous.
+use crate::errors::AddLifetimeParamsSuggestion;
+use crate::errors::LifetimeMismatch;
+use crate::errors::LifetimeMismatchLabels;
use crate::infer::error_reporting::nice_region_error::find_anon_type::find_anon_type;
use crate::infer::error_reporting::nice_region_error::util::AnonymousParamInfo;
use crate::infer::error_reporting::nice_region_error::NiceRegionError;
@@ -8,11 +11,10 @@ use crate::infer::lexical_region_resolve::RegionResolutionError;
use crate::infer::SubregionOrigin;
use crate::infer::TyCtxt;
-use rustc_errors::{struct_span_err, Applicability, Diagnostic, ErrorGuaranteed};
-use rustc_hir as hir;
-use rustc_hir::{GenericParamKind, Ty};
+use rustc_errors::AddSubdiagnostic;
+use rustc_errors::{Diagnostic, ErrorGuaranteed};
+use rustc_hir::Ty;
use rustc_middle::ty::Region;
-use rustc_span::symbol::kw;
impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
/// Print the error message for lifetime errors when both the concerned regions are anonymous.
@@ -98,137 +100,50 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
let sub_is_ret_type =
self.is_return_type_anon(scope_def_id_sub, bregion_sub, ty_fndecl_sub);
- let span_label_var1 = match anon_param_sup.pat.simple_ident() {
- Some(simple_ident) => format!(" from `{}`", simple_ident),
- None => String::new(),
- };
-
- let span_label_var2 = match anon_param_sub.pat.simple_ident() {
- Some(simple_ident) => format!(" into `{}`", simple_ident),
- None => String::new(),
- };
-
debug!(
"try_report_anon_anon_conflict: sub_is_ret_type={:?} sup_is_ret_type={:?}",
sub_is_ret_type, sup_is_ret_type
);
- let mut err = struct_span_err!(self.tcx().sess, span, E0623, "lifetime mismatch");
-
- match (sup_is_ret_type, sub_is_ret_type) {
+ let labels = match (sup_is_ret_type, sub_is_ret_type) {
(ret_capture @ Some(ret_span), _) | (_, ret_capture @ Some(ret_span)) => {
let param_span =
if sup_is_ret_type == ret_capture { ty_sub.span } else { ty_sup.span };
-
- err.span_label(
+ LifetimeMismatchLabels::InRet {
param_span,
- "this parameter and the return type are declared with different lifetimes...",
- );
- err.span_label(ret_span, "");
- err.span_label(span, format!("...but data{} is returned here", span_label_var1));
- }
-
- (None, None) => {
- if ty_sup.hir_id == ty_sub.hir_id {
- err.span_label(ty_sup.span, "this type is declared with multiple lifetimes...");
- err.span_label(ty_sub.span, "");
- err.span_label(span, "...but data with one lifetime flows into the other here");
- } else {
- err.span_label(
- ty_sup.span,
- "these two types are declared with different lifetimes...",
- );
- err.span_label(ty_sub.span, "");
- err.span_label(
- span,
- format!("...but data{} flows{} here", span_label_var1, span_label_var2),
- );
+ ret_span,
+ span,
+ label_var1: anon_param_sup.pat.simple_ident(),
}
}
- }
- if suggest_adding_lifetime_params(self.tcx(), sub, ty_sup, ty_sub, &mut err) {
- err.note("each elided lifetime in input position becomes a distinct lifetime");
- }
+ (None, None) => LifetimeMismatchLabels::Normal {
+ hir_equal: ty_sup.hir_id == ty_sub.hir_id,
+ ty_sup: ty_sup.span,
+ ty_sub: ty_sub.span,
+ span,
+ sup: anon_param_sup.pat.simple_ident(),
+ sub: anon_param_sub.pat.simple_ident(),
+ },
+ };
- let reported = err.emit();
+ let suggestion =
+ AddLifetimeParamsSuggestion { tcx: self.tcx(), sub, ty_sup, ty_sub, add_note: true };
+ let err = LifetimeMismatch { span, labels, suggestion };
+ let reported = self.tcx().sess.emit_err(err);
Some(reported)
}
}
+/// Currently only used in rustc_borrowck, probably should be
+/// removed in favour of public_errors::AddLifetimeParamsSuggestion
pub fn suggest_adding_lifetime_params<'tcx>(
tcx: TyCtxt<'tcx>,
sub: Region<'tcx>,
- ty_sup: &Ty<'_>,
- ty_sub: &Ty<'_>,
+ ty_sup: &'tcx Ty<'_>,
+ ty_sub: &'tcx Ty<'_>,
err: &mut Diagnostic,
-) -> bool {
- let (
- hir::Ty { kind: hir::TyKind::Rptr(lifetime_sub, _), .. },
- hir::Ty { kind: hir::TyKind::Rptr(lifetime_sup, _), .. },
- ) = (ty_sub, ty_sup) else {
- return false;
- };
-
- if !lifetime_sub.name.is_anonymous() || !lifetime_sup.name.is_anonymous() {
- return false;
- };
-
- let Some(anon_reg) = tcx.is_suitable_region(sub) else {
- return false;
- };
-
- let hir_id = tcx.hir().local_def_id_to_hir_id(anon_reg.def_id);
-
- let node = tcx.hir().get(hir_id);
- let is_impl = matches!(&node, hir::Node::ImplItem(_));
- let generics = match node {
- hir::Node::Item(&hir::Item { kind: hir::ItemKind::Fn(_, ref generics, ..), .. })
- | hir::Node::TraitItem(&hir::TraitItem { ref generics, .. })
- | hir::Node::ImplItem(&hir::ImplItem { ref generics, .. }) => generics,
- _ => return false,
- };
-
- let suggestion_param_name = generics
- .params
- .iter()
- .filter(|p| matches!(p.kind, GenericParamKind::Lifetime { .. }))
- .map(|p| p.name.ident().name)
- .find(|i| *i != kw::UnderscoreLifetime);
- let introduce_new = suggestion_param_name.is_none();
- let suggestion_param_name =
- suggestion_param_name.map(|n| n.to_string()).unwrap_or_else(|| "'a".to_owned());
-
- debug!(?lifetime_sup.span);
- debug!(?lifetime_sub.span);
- let make_suggestion = |span: rustc_span::Span| {
- if span.is_empty() {
- (span, format!("{}, ", suggestion_param_name))
- } else if let Ok("&") = tcx.sess.source_map().span_to_snippet(span).as_deref() {
- (span.shrink_to_hi(), format!("{} ", suggestion_param_name))
- } else {
- (span, suggestion_param_name.clone())
- }
- };
- let mut suggestions =
- vec![make_suggestion(lifetime_sub.span), make_suggestion(lifetime_sup.span)];
-
- if introduce_new {
- let new_param_suggestion =
- if let Some(first) = generics.params.iter().find(|p| !p.name.ident().span.is_empty()) {
- (first.span.shrink_to_lo(), format!("{}, ", suggestion_param_name))
- } else {
- (generics.span, format!("<{}>", suggestion_param_name))
- };
-
- suggestions.push(new_param_suggestion);
- }
-
- let mut sugg = String::from("consider introducing a named lifetime parameter");
- if is_impl {
- sugg.push_str(" and update trait if needed");
- }
- err.multipart_suggestion(sugg, suggestions, Applicability::MaybeIncorrect);
-
- true
+) {
+ let suggestion = AddLifetimeParamsSuggestion { tcx, sub, ty_sup, ty_sub, add_note: false };
+ suggestion.add_to_diagnostic(err);
}
diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/find_anon_type.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/find_anon_type.rs
index c1b201da6..d8f540b74 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/find_anon_type.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/find_anon_type.rs
@@ -91,7 +91,7 @@ impl<'tcx> Visitor<'tcx> for FindNestedTypeVisitor<'tcx> {
hir::TyKind::TraitObject(bounds, ..) => {
for bound in bounds {
self.current_index.shift_in(1);
- self.visit_poly_trait_ref(bound, hir::TraitBoundModifier::None);
+ self.visit_poly_trait_ref(bound);
self.current_index.shift_out(1);
}
}
@@ -103,7 +103,7 @@ impl<'tcx> Visitor<'tcx> for FindNestedTypeVisitor<'tcx> {
// Find the index of the named region that was part of the
// error. We will then search the function parameters for a bound
// region at the right depth with the same index
- (Some(rl::Region::EarlyBound(_, id)), ty::BrNamed(def_id, _)) => {
+ (Some(rl::Region::EarlyBound(id)), ty::BrNamed(def_id, _)) => {
debug!("EarlyBound id={:?} def_id={:?}", id, def_id);
if id == def_id {
self.found_type = Some(arg);
@@ -133,7 +133,7 @@ impl<'tcx> Visitor<'tcx> for FindNestedTypeVisitor<'tcx> {
Some(
rl::Region::Static
| rl::Region::Free(_, _)
- | rl::Region::EarlyBound(_, _)
+ | rl::Region::EarlyBound(_)
| rl::Region::LateBound(_, _, _),
)
| None,
@@ -188,7 +188,7 @@ impl<'tcx> Visitor<'tcx> for TyPathVisitor<'tcx> {
fn visit_lifetime(&mut self, lifetime: &hir::Lifetime) {
match (self.tcx.named_region(lifetime.hir_id), self.bound_region) {
// the lifetime of the TyPath!
- (Some(rl::Region::EarlyBound(_, id)), ty::BrNamed(def_id, _)) => {
+ (Some(rl::Region::EarlyBound(id)), ty::BrNamed(def_id, _)) => {
debug!("EarlyBound id={:?} def_id={:?}", id, def_id);
if id == def_id {
self.found_it = true;
@@ -209,7 +209,7 @@ impl<'tcx> Visitor<'tcx> for TyPathVisitor<'tcx> {
(
Some(
rl::Region::Static
- | rl::Region::EarlyBound(_, _)
+ | rl::Region::EarlyBound(_)
| rl::Region::LateBound(_, _, _)
| rl::Region::Free(_, _),
)
diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mismatched_static_lifetime.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mismatched_static_lifetime.rs
index 893ca3cf7..1410e2b63 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mismatched_static_lifetime.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mismatched_static_lifetime.rs
@@ -1,13 +1,14 @@
//! Error Reporting for when the lifetime for a type doesn't match the `impl` selected for a predicate
//! to hold.
+use crate::errors::{note_and_explain, IntroducesStaticBecauseUnmetLifetimeReq};
+use crate::errors::{ImplNote, MismatchedStaticLifetime, TraitSubdiag};
use crate::infer::error_reporting::nice_region_error::NiceRegionError;
-use crate::infer::error_reporting::note_and_explain_region;
use crate::infer::lexical_region_resolve::RegionResolutionError;
use crate::infer::{SubregionOrigin, TypeTrace};
use crate::traits::ObligationCauseCode;
use rustc_data_structures::fx::FxHashSet;
-use rustc_errors::{Applicability, ErrorGuaranteed, MultiSpan};
+use rustc_errors::{ErrorGuaranteed, MultiSpan};
use rustc_hir as hir;
use rustc_hir::intravisit::Visitor;
use rustc_middle::ty::TypeVisitor;
@@ -35,15 +36,27 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
let ObligationCauseCode::MatchImpl(parent, impl_def_id) = code else {
return None;
};
- let ObligationCauseCode::BindingObligation(_def_id, binding_span) = *parent.code() else {
+ let (ObligationCauseCode::BindingObligation(_, binding_span) | ObligationCauseCode::ExprBindingObligation(_, binding_span, ..))
+ = *parent.code() else {
return None;
};
- let mut err = self.tcx().sess.struct_span_err(cause.span, "incompatible lifetime on type");
+
// FIXME: we should point at the lifetime
- let mut multi_span: MultiSpan = vec![binding_span].into();
- multi_span.push_span_label(binding_span, "introduces a `'static` lifetime requirement");
- err.span_note(multi_span, "because this has an unmet lifetime requirement");
- note_and_explain_region(self.tcx(), &mut err, "", sup, "...", Some(binding_span));
+ let multi_span: MultiSpan = vec![binding_span].into();
+ let multispan_subdiag = IntroducesStaticBecauseUnmetLifetimeReq {
+ unmet_requirements: multi_span,
+ binding_span,
+ };
+
+ let expl = note_and_explain::RegionExplanation::new(
+ self.tcx(),
+ sup,
+ Some(binding_span),
+ note_and_explain::PrefixKind::Empty,
+ note_and_explain::SuffixKind::Continues,
+ );
+ let mut impl_span = None;
+ let mut trait_subdiags = Vec::new();
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.
@@ -72,31 +85,30 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
// there aren't trait objects or because none are implicit, then just
// write a single note on the impl itself.
- let impl_span = self.tcx().def_span(*impl_def_id);
- err.span_note(impl_span, "...does not necessarily outlive the static lifetime introduced by the compatible `impl`");
+ impl_span = Some(self.tcx().def_span(*impl_def_id));
} else {
// Otherwise, point at all implicit static lifetimes
- err.note("...does not necessarily outlive the static lifetime introduced by the compatible `impl`");
for span in &traits {
- err.span_note(*span, "this has an implicit `'static` lifetime requirement");
+ trait_subdiags.push(TraitSubdiag::Note { span: *span });
// It would be nice to put this immediately under the above note, but they get
// pushed to the end.
- err.span_suggestion_verbose(
- span.shrink_to_hi(),
- "consider relaxing the implicit `'static` requirement",
- " + '_",
- Applicability::MaybeIncorrect,
- );
+ trait_subdiags.push(TraitSubdiag::Sugg { span: span.shrink_to_hi() });
}
}
} else {
// Otherwise just point out the impl.
- let impl_span = self.tcx().def_span(*impl_def_id);
- err.span_note(impl_span, "...does not necessarily outlive the static lifetime introduced by the compatible `impl`");
+ impl_span = Some(self.tcx().def_span(*impl_def_id));
}
- let reported = err.emit();
+ let err = MismatchedStaticLifetime {
+ cause_span: cause.span,
+ unmet_lifetime_reqs: multispan_subdiag,
+ expl,
+ impl_note: ImplNote { impl_span },
+ trait_subdiags,
+ };
+ let reported = self.tcx().sess.emit_err(err);
Some(reported)
}
}
diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs
index 998699158..d4db07512 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs
@@ -211,7 +211,10 @@ impl<'tcx> NiceRegionError<'_, 'tcx> {
);
let mut err = self.tcx().sess.struct_span_err(span, &msg);
- let leading_ellipsis = if let ObligationCauseCode::ItemObligation(def_id) = *cause.code() {
+ let leading_ellipsis = if let ObligationCauseCode::ItemObligation(def_id)
+ | ObligationCauseCode::ExprItemObligation(def_id, ..) =
+ *cause.code()
+ {
err.span_label(span, "doesn't satisfy where-clause");
err.span_label(
self.tcx().def_span(def_id),
diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs
index 9886c572a..ae56bea6f 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs
@@ -232,7 +232,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
ObligationCauseCode::MatchImpl(parent, ..) => parent.code(),
_ => cause.code(),
}
- && let (&ObligationCauseCode::ItemObligation(item_def_id), None) = (code, override_error_code)
+ && let (&ObligationCauseCode::ItemObligation(item_def_id) | &ObligationCauseCode::ExprItemObligation(item_def_id, ..), None) = (code, override_error_code)
{
// Same case of `impl Foo for dyn Bar { fn qux(&self) {} }` introducing a `'static`
// lifetime as above, but called using a fully-qualified path to the method:
@@ -300,7 +300,7 @@ pub fn suggest_new_region_bound(
continue;
}
match fn_return.kind {
- TyKind::OpaqueDef(item_id, _) => {
+ TyKind::OpaqueDef(item_id, _, _) => {
let item = tcx.hir().item(item_id);
let ItemKind::OpaqueTy(opaque) = &item.kind else {
return;
@@ -544,7 +544,7 @@ pub struct TraitObjectVisitor(pub FxHashSet<DefId>);
impl<'tcx> TypeVisitor<'tcx> for TraitObjectVisitor {
fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
match t.kind() {
- ty::Dynamic(preds, re) if re.is_static() => {
+ ty::Dynamic(preds, re, _) if re.is_static() => {
if let Some(def_id) = preds.principal_def_id() {
self.0.insert(def_id);
}
diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs
index da465a764..a6a39d062 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs
@@ -154,16 +154,11 @@ impl<'tcx> Visitor<'tcx> for TypeParamSpanVisitor<'tcx> {
}
hir::TyKind::Path(hir::QPath::Resolved(None, path)) => match &path.segments {
[segment]
- if segment
- .res
- .map(|res| {
- matches!(
- res,
- Res::SelfTy { trait_: _, alias_to: _ }
- | Res::Def(hir::def::DefKind::TyParam, _)
- )
- })
- .unwrap_or(false) =>
+ if matches!(
+ segment.res,
+ Res::SelfTy { trait_: _, alias_to: _ }
+ | Res::Def(hir::def::DefKind::TyParam, _)
+ ) =>
{
self.types.push(path.span);
}