summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_infer/src/infer/error_reporting/nice_region_error
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_infer/src/infer/error_reporting/nice_region_error')
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/nice_region_error/find_anon_type.rs4
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mod.rs2
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/nice_region_error/named_anon_conflict.rs43
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs323
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_relation.rs14
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs400
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs76
7 files changed, 416 insertions, 446 deletions
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 d8f540b74..39f4d5022 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
@@ -96,8 +96,8 @@ impl<'tcx> Visitor<'tcx> for FindNestedTypeVisitor<'tcx> {
}
}
- hir::TyKind::Rptr(ref lifetime, _) => {
- // the lifetime of the TyRptr
+ hir::TyKind::Ref(ref lifetime, _) => {
+ // the lifetime of the Ref
let hir_id = lifetime.hir_id;
match (self.tcx.named_region(hir_id), self.bound_region) {
// Find the index of the named region that was part of the
diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mod.rs
index 8a0e332f9..59fb74eb5 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mod.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mod.rs
@@ -9,7 +9,7 @@ mod different_lifetimes;
pub mod find_anon_type;
mod mismatched_static_lifetime;
mod named_anon_conflict;
-mod placeholder_error;
+pub(crate) mod placeholder_error;
mod placeholder_relation;
mod static_impl_trait;
mod trait_impl_difference;
diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/named_anon_conflict.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/named_anon_conflict.rs
index 3fe7c1598..4e13ec902 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/named_anon_conflict.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/named_anon_conflict.rs
@@ -1,8 +1,11 @@
//! Error Reporting for Anonymous Region Lifetime Errors
//! where one region is named and the other is anonymous.
-use crate::infer::error_reporting::nice_region_error::find_anon_type::find_anon_type;
use crate::infer::error_reporting::nice_region_error::NiceRegionError;
-use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, ErrorGuaranteed};
+use crate::{
+ errors::ExplicitLifetimeRequired,
+ infer::error_reporting::nice_region_error::find_anon_type::find_anon_type,
+};
+use rustc_errors::{DiagnosticBuilder, ErrorGuaranteed};
use rustc_middle::ty;
use rustc_span::symbol::kw;
@@ -86,31 +89,17 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
{
return None;
}
-
- let (error_var, span_label_var) = match param.pat.simple_ident() {
- Some(simple_ident) => (
- format!("the type of `{}`", simple_ident),
- format!("the type of `{}`", simple_ident),
- ),
- None => ("parameter type".to_owned(), "type".to_owned()),
+ let named = named.to_string();
+ let err = match param.pat.simple_ident() {
+ Some(simple_ident) => ExplicitLifetimeRequired::WithIdent {
+ span,
+ simple_ident,
+ named,
+ new_ty_span,
+ new_ty,
+ },
+ None => ExplicitLifetimeRequired::WithParamType { span, named, new_ty_span, new_ty },
};
-
- let mut diag = struct_span_err!(
- self.tcx().sess,
- span,
- E0621,
- "explicit lifetime required in {}",
- error_var
- );
-
- diag.span_label(span, format!("lifetime `{}` required", named));
- diag.span_suggestion(
- new_ty_span,
- &format!("add explicit lifetime `{}` to {}", named, span_label_var),
- new_ty,
- Applicability::Unspecified,
- );
-
- Some(diag)
+ Some(self.tcx().sess.parse_sess.create_err(err))
}
}
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 1f554c81e..99431567e 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
@@ -1,10 +1,14 @@
+use crate::errors::{
+ ActualImplExpectedKind, ActualImplExpectedLifetimeKind, ActualImplExplNotes,
+ TraitPlaceholderMismatch, TyOrSig,
+};
use crate::infer::error_reporting::nice_region_error::NiceRegionError;
use crate::infer::lexical_region_resolve::RegionResolutionError;
use crate::infer::ValuePairs;
use crate::infer::{SubregionOrigin, TypeTrace};
use crate::traits::{ObligationCause, ObligationCauseCode};
use rustc_data_structures::intern::Interned;
-use rustc_errors::{Diagnostic, DiagnosticBuilder, ErrorGuaranteed};
+use rustc_errors::{DiagnosticBuilder, ErrorGuaranteed, IntoDiagnosticArg};
use rustc_hir::def::Namespace;
use rustc_hir::def_id::DefId;
use rustc_middle::ty::error::ExpectedFound;
@@ -12,7 +16,43 @@ use rustc_middle::ty::print::{FmtPrinter, Print, RegionHighlightMode};
use rustc_middle::ty::subst::SubstsRef;
use rustc_middle::ty::{self, RePlaceholder, ReVar, Region, TyCtxt};
-use std::fmt::{self, Write};
+use std::fmt;
+
+// HACK(eddyb) maybe move this in a more central location.
+#[derive(Copy, Clone)]
+pub struct Highlighted<'tcx, T> {
+ tcx: TyCtxt<'tcx>,
+ highlight: RegionHighlightMode<'tcx>,
+ value: T,
+}
+
+impl<'tcx, T> IntoDiagnosticArg for Highlighted<'tcx, T>
+where
+ T: for<'a> Print<'tcx, FmtPrinter<'a, 'tcx>, Error = fmt::Error, Output = FmtPrinter<'a, 'tcx>>,
+{
+ fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue<'static> {
+ rustc_errors::DiagnosticArgValue::Str(self.to_string().into())
+ }
+}
+
+impl<'tcx, T> Highlighted<'tcx, T> {
+ fn map<U>(self, f: impl FnOnce(T) -> U) -> Highlighted<'tcx, U> {
+ Highlighted { tcx: self.tcx, highlight: self.highlight, value: f(self.value) }
+ }
+}
+
+impl<'tcx, T> fmt::Display for Highlighted<'tcx, T>
+where
+ T: for<'a> Print<'tcx, FmtPrinter<'a, 'tcx>, Error = fmt::Error, Output = FmtPrinter<'a, 'tcx>>,
+{
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ let mut printer = ty::print::FmtPrinter::new(self.tcx, Namespace::TypeNS);
+ printer.region_highlight_mode = self.highlight;
+
+ let s = self.value.print(printer)?.into_buffer();
+ f.write_str(&s)
+ }
+}
impl<'tcx> NiceRegionError<'_, 'tcx> {
/// When given a `ConcreteFailure` for a function with arguments containing a named region and
@@ -205,34 +245,27 @@ impl<'tcx> NiceRegionError<'_, 'tcx> {
actual_substs: SubstsRef<'tcx>,
) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
let span = cause.span();
- let msg = format!(
- "implementation of `{}` is not general enough",
- self.tcx().def_path_str(trait_def_id),
- );
- let mut err = self.tcx().sess.struct_span_err(span, &msg);
-
- 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),
- &format!("due to a where-clause on `{}`...", self.tcx().def_path_str(def_id)),
- );
- true
- } else {
- err.span_label(span, &msg);
- false
- };
- let expected_trait_ref = self.cx.resolve_vars_if_possible(ty::TraitRef {
- def_id: trait_def_id,
- substs: expected_substs,
- });
- let actual_trait_ref = self
+ let (leading_ellipsis, satisfy_span, where_span, dup_span, def_id) =
+ if let ObligationCauseCode::ItemObligation(def_id)
+ | ObligationCauseCode::ExprItemObligation(def_id, ..) = *cause.code()
+ {
+ (
+ true,
+ Some(span),
+ Some(self.tcx().def_span(def_id)),
+ None,
+ self.tcx().def_path_str(def_id),
+ )
+ } else {
+ (false, None, None, Some(span), String::new())
+ };
+
+ let expected_trait_ref = self
.cx
- .resolve_vars_if_possible(ty::TraitRef { def_id: trait_def_id, substs: actual_substs });
+ .resolve_vars_if_possible(self.cx.tcx.mk_trait_ref(trait_def_id, expected_substs));
+ let actual_trait_ref =
+ self.cx.resolve_vars_if_possible(self.cx.tcx.mk_trait_ref(trait_def_id, actual_substs));
// Search the expected and actual trait references to see (a)
// whether the sub/sup placeholders appear in them (sometimes
@@ -286,8 +319,7 @@ impl<'tcx> NiceRegionError<'_, 'tcx> {
?expected_self_ty_has_vid,
);
- self.explain_actual_impl_that_was_found(
- &mut err,
+ let actual_impl_expl_notes = self.explain_actual_impl_that_was_found(
sub_placeholder,
sup_placeholder,
has_sub,
@@ -301,7 +333,15 @@ impl<'tcx> NiceRegionError<'_, 'tcx> {
leading_ellipsis,
);
- err
+ self.tcx().sess.create_err(TraitPlaceholderMismatch {
+ span,
+ satisfy_span,
+ where_span,
+ dup_span,
+ def_id,
+ trait_def_id: self.tcx().def_path_str(trait_def_id),
+ actual_impl_expl_notes,
+ })
}
/// Add notes with details about the expected and actual trait refs, with attention to cases
@@ -311,7 +351,6 @@ impl<'tcx> NiceRegionError<'_, 'tcx> {
/// due to the number of combinations we have to deal with.
fn explain_actual_impl_that_was_found(
&self,
- err: &mut Diagnostic,
sub_placeholder: Option<Region<'tcx>>,
sup_placeholder: Option<Region<'tcx>>,
has_sub: Option<usize>,
@@ -323,39 +362,7 @@ impl<'tcx> NiceRegionError<'_, 'tcx> {
actual_has_vid: Option<usize>,
any_self_ty_has_vid: bool,
leading_ellipsis: bool,
- ) {
- // HACK(eddyb) maybe move this in a more central location.
- #[derive(Copy, Clone)]
- struct Highlighted<'tcx, T> {
- tcx: TyCtxt<'tcx>,
- highlight: RegionHighlightMode<'tcx>,
- value: T,
- }
-
- impl<'tcx, T> Highlighted<'tcx, T> {
- fn map<U>(self, f: impl FnOnce(T) -> U) -> Highlighted<'tcx, U> {
- Highlighted { tcx: self.tcx, highlight: self.highlight, value: f(self.value) }
- }
- }
-
- impl<'tcx, T> fmt::Display for Highlighted<'tcx, T>
- where
- T: for<'a> Print<
- 'tcx,
- FmtPrinter<'a, 'tcx>,
- Error = fmt::Error,
- Output = FmtPrinter<'a, 'tcx>,
- >,
- {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- let mut printer = ty::print::FmtPrinter::new(self.tcx, Namespace::TypeNS);
- printer.region_highlight_mode = self.highlight;
-
- let s = self.value.print(printer)?.into_buffer();
- f.write_str(&s)
- }
- }
-
+ ) -> Vec<ActualImplExplNotes<'tcx>> {
// The weird thing here with the `maybe_highlighting_region` calls and the
// the match inside is meant to be like this:
//
@@ -363,7 +370,7 @@ impl<'tcx> NiceRegionError<'_, 'tcx> {
// in the types are about to print
// - Meanwhile, the `maybe_highlighting_region` calls set up
// highlights so that, if they do appear, we will replace
- // them `'0` and whatever. (This replacement takes place
+ // them `'0` and whatever. (This replacement takes place
// inside the closure given to `maybe_highlighting_region`.)
//
// There is some duplication between the calls -- i.e., the
@@ -382,120 +389,110 @@ impl<'tcx> NiceRegionError<'_, 'tcx> {
let mut expected_trait_ref = highlight_trait_ref(expected_trait_ref);
expected_trait_ref.highlight.maybe_highlighting_region(sub_placeholder, has_sub);
expected_trait_ref.highlight.maybe_highlighting_region(sup_placeholder, has_sup);
- err.note(&{
- let passive_voice = match (has_sub, has_sup) {
- (Some(_), _) | (_, Some(_)) => any_self_ty_has_vid,
- (None, None) => {
- expected_trait_ref.highlight.maybe_highlighting_region(vid, expected_has_vid);
- match expected_has_vid {
- Some(_) => true,
- None => any_self_ty_has_vid,
- }
- }
- };
- let mut note = if same_self_type {
- let mut self_ty = expected_trait_ref.map(|tr| tr.self_ty());
- self_ty.highlight.maybe_highlighting_region(vid, actual_has_vid);
-
- if self_ty.value.is_closure()
- && self.tcx().is_fn_trait(expected_trait_ref.value.def_id)
- {
- let closure_sig = self_ty.map(|closure| {
- if let ty::Closure(_, substs) = closure.kind() {
- self.tcx().signature_unclosure(
- substs.as_closure().sig(),
- rustc_hir::Unsafety::Normal,
- )
- } else {
- bug!("type is not longer closure");
- }
- });
-
- format!(
- "{}closure with signature `{}` must implement `{}`",
- if leading_ellipsis { "..." } else { "" },
- closure_sig,
- expected_trait_ref.map(|tr| tr.print_only_trait_path()),
- )
- } else {
- format!(
- "{}`{}` must implement `{}`",
- if leading_ellipsis { "..." } else { "" },
- self_ty,
- expected_trait_ref.map(|tr| tr.print_only_trait_path()),
- )
+ let passive_voice = match (has_sub, has_sup) {
+ (Some(_), _) | (_, Some(_)) => any_self_ty_has_vid,
+ (None, None) => {
+ expected_trait_ref.highlight.maybe_highlighting_region(vid, expected_has_vid);
+ match expected_has_vid {
+ Some(_) => true,
+ None => any_self_ty_has_vid,
}
- } else if passive_voice {
- format!(
- "{}`{}` would have to be implemented for the type `{}`",
- if leading_ellipsis { "..." } else { "" },
+ }
+ };
+
+ let (kind, ty_or_sig, trait_path) = if same_self_type {
+ let mut self_ty = expected_trait_ref.map(|tr| tr.self_ty());
+ self_ty.highlight.maybe_highlighting_region(vid, actual_has_vid);
+
+ if self_ty.value.is_closure() && self.tcx().is_fn_trait(expected_trait_ref.value.def_id)
+ {
+ let closure_sig = self_ty.map(|closure| {
+ if let ty::Closure(_, substs) = closure.kind() {
+ self.tcx().signature_unclosure(
+ substs.as_closure().sig(),
+ rustc_hir::Unsafety::Normal,
+ )
+ } else {
+ bug!("type is not longer closure");
+ }
+ });
+ (
+ ActualImplExpectedKind::Signature,
+ TyOrSig::ClosureSig(closure_sig),
expected_trait_ref.map(|tr| tr.print_only_trait_path()),
- expected_trait_ref.map(|tr| tr.self_ty()),
)
} else {
- format!(
- "{}`{}` must implement `{}`",
- if leading_ellipsis { "..." } else { "" },
- expected_trait_ref.map(|tr| tr.self_ty()),
+ (
+ ActualImplExpectedKind::Other,
+ TyOrSig::Ty(self_ty),
expected_trait_ref.map(|tr| tr.print_only_trait_path()),
)
- };
+ }
+ } else if passive_voice {
+ (
+ ActualImplExpectedKind::Passive,
+ TyOrSig::Ty(expected_trait_ref.map(|tr| tr.self_ty())),
+ expected_trait_ref.map(|tr| tr.print_only_trait_path()),
+ )
+ } else {
+ (
+ ActualImplExpectedKind::Other,
+ TyOrSig::Ty(expected_trait_ref.map(|tr| tr.self_ty())),
+ expected_trait_ref.map(|tr| tr.print_only_trait_path()),
+ )
+ };
- match (has_sub, has_sup) {
- (Some(n1), Some(n2)) => {
- let _ = write!(
- note,
- ", for any two lifetimes `'{}` and `'{}`...",
- std::cmp::min(n1, n2),
- std::cmp::max(n1, n2),
- );
- }
- (Some(n), _) | (_, Some(n)) => {
- let _ = write!(note, ", for any lifetime `'{}`...", n,);
- }
- (None, None) => {
- if let Some(n) = expected_has_vid {
- let _ = write!(note, ", for some specific lifetime `'{}`...", n,);
- }
+ let (lt_kind, lifetime_1, lifetime_2) = match (has_sub, has_sup) {
+ (Some(n1), Some(n2)) => {
+ (ActualImplExpectedLifetimeKind::Two, std::cmp::min(n1, n2), std::cmp::max(n1, n2))
+ }
+ (Some(n), _) | (_, Some(n)) => (ActualImplExpectedLifetimeKind::Any, n, 0),
+ (None, None) => {
+ if let Some(n) = expected_has_vid {
+ (ActualImplExpectedLifetimeKind::Some, n, 0)
+ } else {
+ (ActualImplExpectedLifetimeKind::Nothing, 0, 0)
}
}
+ };
- note
- });
+ let note_1 = ActualImplExplNotes::new_expected(
+ kind,
+ lt_kind,
+ leading_ellipsis,
+ ty_or_sig,
+ trait_path,
+ lifetime_1,
+ lifetime_2,
+ );
let mut actual_trait_ref = highlight_trait_ref(actual_trait_ref);
actual_trait_ref.highlight.maybe_highlighting_region(vid, actual_has_vid);
- err.note(&{
- let passive_voice = match actual_has_vid {
- Some(_) => any_self_ty_has_vid,
- None => true,
- };
- let mut note = if same_self_type {
- format!(
- "...but it actually implements `{}`",
- actual_trait_ref.map(|tr| tr.print_only_trait_path()),
- )
- } else if passive_voice {
- format!(
- "...but `{}` is actually implemented for the type `{}`",
- actual_trait_ref.map(|tr| tr.print_only_trait_path()),
- actual_trait_ref.map(|tr| tr.self_ty()),
- )
- } else {
- format!(
- "...but `{}` actually implements `{}`",
- actual_trait_ref.map(|tr| tr.self_ty()),
- actual_trait_ref.map(|tr| tr.print_only_trait_path()),
- )
- };
+ let passive_voice = match actual_has_vid {
+ Some(_) => any_self_ty_has_vid,
+ None => true,
+ };
- if let Some(n) = actual_has_vid {
- let _ = write!(note, ", for some specific lifetime `'{}`", n);
+ let trait_path = actual_trait_ref.map(|tr| tr.print_only_trait_path());
+ let ty = actual_trait_ref.map(|tr| tr.self_ty()).to_string();
+ let has_lifetime = actual_has_vid.is_some();
+ let lifetime = actual_has_vid.unwrap_or_default();
+
+ let note_2 = if same_self_type {
+ ActualImplExplNotes::ButActuallyImplementsTrait { trait_path, has_lifetime, lifetime }
+ } else if passive_voice {
+ ActualImplExplNotes::ButActuallyImplementedForTy {
+ trait_path,
+ ty,
+ has_lifetime,
+ lifetime,
}
+ } else {
+ ActualImplExplNotes::ButActuallyTyImplements { trait_path, ty, has_lifetime, lifetime }
+ };
- note
- });
+ vec![note_1, note_2]
}
}
diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_relation.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_relation.rs
index c42240f21..9534bce54 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_relation.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_relation.rs
@@ -44,7 +44,7 @@ impl<'tcx> NiceRegionError<'_, 'tcx> {
);
}
(Some(sub_span), Some(sup_span), _, Some(sup_symbol)) => {
- err.span_note(sub_span, format!("the lifetime defined here..."));
+ err.span_note(sub_span, "the lifetime defined here...");
err.span_note(
sup_span,
format!("...must outlive the lifetime `{sup_symbol}` defined here"),
@@ -55,17 +55,11 @@ impl<'tcx> NiceRegionError<'_, 'tcx> {
sub_span,
format!("the lifetime `{sub_symbol}` defined here..."),
);
- err.span_note(
- sup_span,
- format!("...must outlive the lifetime defined here"),
- );
+ err.span_note(sup_span, "...must outlive the lifetime defined here");
}
(Some(sub_span), Some(sup_span), _, _) => {
- err.span_note(sub_span, format!("the lifetime defined here..."));
- err.span_note(
- sup_span,
- format!("...must outlive the lifetime defined here"),
- );
+ err.span_note(sub_span, "the lifetime defined here...");
+ err.span_note(sup_span, "...must outlive the lifetime defined here");
}
_ => {}
}
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 09f9aa3c8..49ad3ce50 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
@@ -1,20 +1,28 @@
//! Error Reporting for static impl Traits.
+use crate::errors::{
+ ButCallingIntroduces, ButNeedsToSatisfy, DynTraitConstraintSuggestion, MoreTargeted,
+ ReqIntroducedLocations,
+};
use crate::infer::error_reporting::nice_region_error::NiceRegionError;
use crate::infer::lexical_region_resolve::RegionResolutionError;
use crate::infer::{SubregionOrigin, TypeTrace};
use crate::traits::{ObligationCauseCode, UnifyReceiverContext};
use rustc_data_structures::fx::FxIndexSet;
-use rustc_errors::{struct_span_err, Applicability, Diagnostic, ErrorGuaranteed, MultiSpan};
+use rustc_errors::{AddToDiagnostic, Applicability, Diagnostic, ErrorGuaranteed, MultiSpan};
use rustc_hir::def_id::DefId;
use rustc_hir::intravisit::{walk_ty, Visitor};
-use rustc_hir::{self as hir, GenericBound, Item, ItemKind, Lifetime, LifetimeName, Node, TyKind};
+use rustc_hir::{
+ self as hir, GenericBound, GenericParamKind, Item, ItemKind, Lifetime, LifetimeName, Node,
+ TyKind,
+};
use rustc_middle::ty::{
self, AssocItemContainer, StaticLifetimeVisitor, Ty, TyCtxt, TypeSuperVisitable, TypeVisitor,
};
use rustc_span::symbol::Ident;
use rustc_span::Span;
+use rustc_span::def_id::LocalDefId;
use std::ops::ControlFlow;
impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
@@ -49,46 +57,32 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
}
let param = self.find_param_with_region(*sup_r, *sub_r)?;
- let lifetime = if sup_r.has_name() {
- format!("lifetime `{}`", sup_r)
- } else {
- "an anonymous lifetime `'_`".to_string()
+ let simple_ident = param.param.pat.simple_ident();
+
+ let (has_impl_path, impl_path) = match ctxt.assoc_item.container {
+ AssocItemContainer::TraitContainer => {
+ let id = ctxt.assoc_item.container_id(tcx);
+ (true, tcx.def_path_str(id))
+ }
+ AssocItemContainer::ImplContainer => (false, String::new()),
};
- let mut err = struct_span_err!(
- tcx.sess,
- cause.span,
- E0772,
- "{} has {} but calling `{}` introduces an implicit `'static` lifetime \
- requirement",
- param
- .param
- .pat
- .simple_ident()
- .map(|s| format!("`{}`", s))
- .unwrap_or_else(|| "`fn` parameter".to_string()),
- lifetime,
- ctxt.assoc_item.name,
- );
- err.span_label(param.param_ty_span, &format!("this data with {}...", lifetime));
- err.span_label(
- cause.span,
- &format!(
- "...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 => {
- let id = ctxt.assoc_item.container_id(tcx);
- format!("`impl` of `{}`", tcx.def_path_str(id))
- }
- AssocItemContainer::ImplContainer => "inherent `impl`".to_string(),
- },
- ),
- );
+
+ let mut err = self.tcx().sess.create_err(ButCallingIntroduces {
+ param_ty_span: param.param_ty_span,
+ cause_span: cause.span,
+ has_param_name: simple_ident.is_some(),
+ param_name: simple_ident.map(|x| x.to_string()).unwrap_or_default(),
+ has_lifetime: sup_r.has_name(),
+ lifetime: sup_r.to_string(),
+ assoc_item: ctxt.assoc_item.name,
+ has_impl_path,
+ impl_path,
+ });
if self.find_impl_on_dyn_trait(&mut err, param.param_ty, &ctxt) {
let reported = err.emit();
return Some(reported);
} else {
- err.cancel();
+ err.cancel()
}
}
return None;
@@ -104,25 +98,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
let sp = var_origin.span();
let return_sp = sub_origin.span();
let param = self.find_param_with_region(*sup_r, *sub_r)?;
- let (lifetime_name, lifetime) = if sup_r.has_name() {
- (sup_r.to_string(), format!("lifetime `{}`", sup_r))
- } else {
- ("'_".to_owned(), "an anonymous lifetime `'_`".to_string())
- };
- let param_name = param
- .param
- .pat
- .simple_ident()
- .map(|s| format!("`{}`", s))
- .unwrap_or_else(|| "`fn` parameter".to_string());
- let mut err = struct_span_err!(
- tcx.sess,
- sp,
- E0759,
- "{} has {} but it needs to satisfy a `'static` lifetime requirement",
- param_name,
- lifetime,
- );
+ let lifetime_name = if sup_r.has_name() { sup_r.to_string() } else { "'_".to_owned() };
let (mention_influencer, influencer_point) =
if sup_origin.span().overlaps(param.param_ty_span) {
@@ -141,7 +117,6 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
} else {
(!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);
@@ -155,31 +130,19 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
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);
+ let spans_empty = spans.is_empty();
+ let require_as_note = spans.iter().any(|sp| sp.overlaps(return_sp) || *sp > return_sp);
+ let bound = if let SubregionOrigin::RelateParamBound(_, _, Some(bound)) = sub_origin {
+ Some(*bound)
} 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);
- }
+ None
+ };
+
+ let mut subdiag = None;
- 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()
@@ -187,33 +150,50 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
let parent_id = tcx.hir().get_parent_item(*hir_id);
if let Some(fn_decl) = tcx.hir().fn_decl_by_hir_id(parent_id.into()) {
let mut span: MultiSpan = fn_decl.output.span().into();
+ let mut spans = Vec::new();
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");
- }
+ spans = v.0;
add_label = false;
}
}
- if add_label {
- span.push_span_label(
- fn_decl.output.span(),
- "requirement introduced by this return type",
- );
- }
- span.push_span_label(cause.span, "because of this returned expression");
- err.span_note(
+ let fn_decl_span = fn_decl.output.span();
+
+ subdiag = Some(ReqIntroducedLocations {
span,
- "`'static` lifetime requirement introduced by the return type",
- );
+ spans,
+ fn_decl_span,
+ cause_span: cause.span,
+ add_label,
+ });
}
}
}
+ let diag = ButNeedsToSatisfy {
+ sp,
+ influencer_point,
+ spans: spans.clone(),
+ // 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.
+ require_span_as_note: require_as_note.then_some(require_span),
+ // We don't need a note, it's already at the end, it can be shown as a `span_label`.
+ require_span_as_label: (!require_as_note).then_some(require_span),
+ req_introduces_loc: subdiag,
+
+ has_lifetime: sup_r.has_name(),
+ lifetime: sup_r.to_string(),
+ spans_empty,
+ bound,
+ };
+
+ let mut err = self.tcx().sess.create_err(diag);
+
let fn_returns = tcx.return_type_impl_or_dyn_traits(anon_reg_sup.def_id);
let mut override_error_code = None;
@@ -239,7 +219,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
let mut v = TraitObjectVisitor(FxIndexSet::default());
v.visit_ty(param.param_ty);
if let Some((ident, self_ty)) =
- self.get_impl_ident_and_self_ty_from_trait(item_def_id, &v.0)
+ NiceRegionError::get_impl_ident_and_self_ty_from_trait(tcx, item_def_id, &v.0)
&& self.suggest_constrain_dyn_trait_in_impl(&mut err, &v.0, ident, self_ty)
{
override_error_code = Some(ident.name);
@@ -247,12 +227,8 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
}
if let (Some(ident), true) = (override_error_code, fn_returns.is_empty()) {
// Provide a more targeted error code and description.
- err.code(rustc_errors::error_code!(E0772));
- err.set_primary_message(&format!(
- "{} has {} but calling `{}` introduces an implicit `'static` lifetime \
- requirement",
- param_name, lifetime, ident,
- ));
+ let retarget_subdiag = MoreTargeted { ident };
+ retarget_subdiag.add_to_diagnostic(&mut err);
}
let arg = match param.param.pat.simple_ident() {
@@ -268,6 +244,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
Some(arg),
captures,
Some((param.param_ty_span, param.param_ty.to_string())),
+ Some(anon_reg_sup.def_id),
);
let reported = err.emit();
@@ -283,6 +260,7 @@ pub fn suggest_new_region_bound(
arg: Option<String>,
captures: String,
param: Option<(Span, String)>,
+ scope_def_id: Option<LocalDefId>,
) {
debug!("try_report_static_impl_trait: fn_return={:?}", fn_returns);
// FIXME: account for the need of parens in `&(dyn Trait + '_)`
@@ -309,19 +287,12 @@ pub fn suggest_new_region_bound(
let did = item_id.owner_id.to_def_id();
let ty = tcx.mk_opaque(did, ty::InternalSubsts::identity_for_item(tcx, did));
- if let Some(span) = opaque
- .bounds
- .iter()
- .filter_map(|arg| match arg {
- GenericBound::Outlives(Lifetime {
- res: LifetimeName::Static,
- ident,
- ..
- }) => Some(ident.span),
- _ => None,
- })
- .next()
- {
+ if let Some(span) = opaque.bounds.iter().find_map(|arg| match arg {
+ GenericBound::Outlives(Lifetime {
+ res: LifetimeName::Static, ident, ..
+ }) => Some(ident.span),
+ _ => None,
+ }) {
if let Some(explicit_static) = &explicit_static {
err.span_suggestion_verbose(
span,
@@ -330,7 +301,7 @@ pub fn suggest_new_region_bound(
Applicability::MaybeIncorrect,
);
}
- if let Some((param_span, param_ty)) = param.clone() {
+ if let Some((param_span, ref param_ty)) = param {
err.span_suggestion_verbose(
param_span,
add_static_bound,
@@ -338,27 +309,78 @@ pub fn suggest_new_region_bound(
Applicability::MaybeIncorrect,
);
}
- } else if opaque
- .bounds
- .iter()
- .filter_map(|arg| match arg {
- GenericBound::Outlives(Lifetime { ident, .. })
- if ident.name.to_string() == lifetime_name =>
- {
- Some(ident.span)
- }
- _ => None,
- })
- .next()
- .is_some()
- {
+ } else if opaque.bounds.iter().any(|arg| match arg {
+ GenericBound::Outlives(Lifetime { ident, .. })
+ if ident.name.to_string() == lifetime_name =>
+ {
+ true
+ }
+ _ => false,
+ }) {
} else {
- err.span_suggestion_verbose(
- fn_return.span.shrink_to_hi(),
- &format!("{declare} `{ty}` {captures}, {explicit}",),
- &plus_lt,
- Applicability::MaybeIncorrect,
- );
+ // get a lifetime name of existing named lifetimes if any
+ let existing_lt_name = if let Some(id) = scope_def_id
+ && let Some(generics) = tcx.hir().get_generics(id)
+ && let named_lifetimes = generics
+ .params
+ .iter()
+ .filter(|p| matches!(p.kind, GenericParamKind::Lifetime { kind: hir::LifetimeParamKind::Explicit }))
+ .map(|p| { if let hir::ParamName::Plain(name) = p.name {Some(name.to_string())} else {None}})
+ .filter(|n| ! matches!(n, None))
+ .collect::<Vec<_>>()
+ && named_lifetimes.len() > 0 {
+ named_lifetimes[0].clone()
+ } else {
+ None
+ };
+ let name = if let Some(name) = &existing_lt_name {
+ format!("{}", name)
+ } else {
+ format!("'a")
+ };
+ // if there are more than one elided lifetimes in inputs, the explicit `'_` lifetime cannot be used.
+ // introducing a new lifetime `'a` or making use of one from existing named lifetimes if any
+ if let Some(id) = scope_def_id
+ && let Some(generics) = tcx.hir().get_generics(id)
+ && let mut spans_suggs = generics
+ .params
+ .iter()
+ .filter(|p| p.is_elided_lifetime())
+ .map(|p|
+ if p.span.hi() - p.span.lo() == rustc_span::BytePos(1) { // Ampersand (elided without '_)
+ (p.span.shrink_to_hi(),format!("{name} "))
+ } else { // Underscore (elided with '_)
+ (p.span, format!("{name}"))
+ }
+ )
+ .collect::<Vec<_>>()
+ && spans_suggs.len() > 1
+ {
+ let use_lt =
+ if existing_lt_name == None {
+ spans_suggs.push((generics.span.shrink_to_hi(), format!("<{name}>")));
+ format!("you can introduce a named lifetime parameter `{name}`")
+ } else {
+ // make use the existing named lifetime
+ format!("you can use the named lifetime parameter `{name}`")
+ };
+ spans_suggs
+ .push((fn_return.span.shrink_to_hi(), format!(" + {name} ")));
+ err.multipart_suggestion_verbose(
+ &format!(
+ "{declare} `{ty}` {captures}, {use_lt}",
+ ),
+ spans_suggs,
+ Applicability::MaybeIncorrect,
+ );
+ } else {
+ err.span_suggestion_verbose(
+ fn_return.span.shrink_to_hi(),
+ &format!("{declare} `{ty}` {captures}, {explicit}",),
+ &plus_lt,
+ Applicability::MaybeIncorrect,
+ );
+ }
}
}
TyKind::TraitObject(_, lt, _) => {
@@ -403,66 +425,54 @@ pub fn suggest_new_region_bound(
}
impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
- fn get_impl_ident_and_self_ty_from_trait(
- &self,
+ pub fn get_impl_ident_and_self_ty_from_trait(
+ tcx: TyCtxt<'tcx>,
def_id: DefId,
trait_objects: &FxIndexSet<DefId>,
) -> Option<(Ident, &'tcx hir::Ty<'tcx>)> {
- let tcx = self.tcx();
- match tcx.hir().get_if_local(def_id) {
- Some(Node::ImplItem(impl_item)) => {
- match tcx.hir().find_by_def_id(tcx.hir().get_parent_item(impl_item.hir_id()).def_id)
+ match tcx.hir().get_if_local(def_id)? {
+ Node::ImplItem(impl_item) => {
+ let impl_did = tcx.hir().get_parent_item(impl_item.hir_id());
+ if let hir::OwnerNode::Item(Item {
+ kind: ItemKind::Impl(hir::Impl { self_ty, .. }),
+ ..
+ }) = tcx.hir().owner(impl_did)
{
- Some(Node::Item(Item {
- kind: ItemKind::Impl(hir::Impl { self_ty, .. }),
- ..
- })) => Some((impl_item.ident, self_ty)),
- _ => None,
+ Some((impl_item.ident, self_ty))
+ } else {
+ None
}
}
- Some(Node::TraitItem(trait_item)) => {
- let trait_did = tcx.hir().get_parent_item(trait_item.hir_id());
- match tcx.hir().find_by_def_id(trait_did.def_id) {
- Some(Node::Item(Item { kind: ItemKind::Trait(..), .. })) => {
- // The method being called is defined in the `trait`, but the `'static`
- // obligation comes from the `impl`. Find that `impl` so that we can point
- // at it in the suggestion.
- let trait_did = trait_did.to_def_id();
- match tcx
- .hir()
- .trait_impls(trait_did)
- .iter()
- .filter_map(|&impl_did| {
- match tcx.hir().get_if_local(impl_did.to_def_id()) {
- Some(Node::Item(Item {
- kind: ItemKind::Impl(hir::Impl { self_ty, .. }),
- ..
- })) if trait_objects.iter().all(|did| {
- // FIXME: we should check `self_ty` against the receiver
- // type in the `UnifyReceiver` context, but for now, use
- // this imperfect proxy. This will fail if there are
- // multiple `impl`s for the same trait like
- // `impl Foo for Box<dyn Bar>` and `impl Foo for dyn Bar`.
- // In that case, only the first one will get suggestions.
- let mut traits = vec![];
- let mut hir_v = HirTraitObjectVisitor(&mut traits, *did);
- hir_v.visit_ty(self_ty);
- !traits.is_empty()
- }) =>
- {
- Some(self_ty)
- }
- _ => None,
- }
- })
- .next()
- {
- Some(self_ty) => Some((trait_item.ident, self_ty)),
- _ => None,
- }
+ Node::TraitItem(trait_item) => {
+ let trait_id = tcx.hir().get_parent_item(trait_item.hir_id());
+ debug_assert_eq!(tcx.def_kind(trait_id.def_id), hir::def::DefKind::Trait);
+ // The method being called is defined in the `trait`, but the `'static`
+ // obligation comes from the `impl`. Find that `impl` so that we can point
+ // at it in the suggestion.
+ let trait_did = trait_id.to_def_id();
+ tcx.hir().trait_impls(trait_did).iter().find_map(|&impl_did| {
+ if let Node::Item(Item {
+ kind: ItemKind::Impl(hir::Impl { self_ty, .. }),
+ ..
+ }) = tcx.hir().find_by_def_id(impl_did)?
+ && trait_objects.iter().all(|did| {
+ // FIXME: we should check `self_ty` against the receiver
+ // type in the `UnifyReceiver` context, but for now, use
+ // this imperfect proxy. This will fail if there are
+ // multiple `impl`s for the same trait like
+ // `impl Foo for Box<dyn Bar>` and `impl Foo for dyn Bar`.
+ // In that case, only the first one will get suggestions.
+ let mut traits = vec![];
+ let mut hir_v = HirTraitObjectVisitor(&mut traits, *did);
+ hir_v.visit_ty(self_ty);
+ !traits.is_empty()
+ })
+ {
+ Some((trait_item.ident, *self_ty))
+ } else {
+ None
}
- _ => None,
- }
+ })
}
_ => None,
}
@@ -493,7 +503,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
// Get the `Ident` of the method being called and the corresponding `impl` (to point at
// `Bar` in `impl Foo for dyn Bar {}` and the definition of the method being called).
- let Some((ident, self_ty)) = self.get_impl_ident_and_self_ty_from_trait(instance.def_id(), &v.0) else {
+ let Some((ident, self_ty)) = NiceRegionError::get_impl_ident_and_self_ty_from_trait(tcx, instance.def_id(), &v.0) else {
return false;
};
@@ -513,21 +523,9 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
let mut traits = vec![];
let mut hir_v = HirTraitObjectVisitor(&mut traits, *found_did);
hir_v.visit_ty(&self_ty);
- for span in &traits {
- let mut multi_span: MultiSpan = vec![*span].into();
- multi_span
- .push_span_label(*span, "this has an implicit `'static` lifetime requirement");
- multi_span.push_span_label(
- ident.span,
- "calling this method introduces the `impl`'s 'static` requirement",
- );
- err.span_note(multi_span, "the used `impl` has a `'static` requirement");
- err.span_suggestion_verbose(
- span.shrink_to_hi(),
- "consider relaxing the implicit `'static` requirement",
- " + '_",
- Applicability::MaybeIncorrect,
- );
+ for &span in &traits {
+ let subdiag = DynTraitConstraintSuggestion { span, ident };
+ subdiag.add_to_diagnostic(err);
suggested = true;
}
}
@@ -545,7 +543,7 @@ impl<'tcx> TypeVisitor<'tcx> for TraitObjectVisitor {
if let Some(def_id) = preds.principal_def_id() {
self.0.insert(def_id);
}
- ControlFlow::CONTINUE
+ ControlFlow::Continue(())
}
_ => t.super_visit_with(self),
}
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 5d536e982..40c0c806e 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
@@ -1,15 +1,17 @@
//! Error Reporting for `impl` items that do not match the obligations from their `trait`.
+use crate::errors::{ConsiderBorrowingParamHelp, RelationshipHelp, TraitImplDiff};
use crate::infer::error_reporting::nice_region_error::NiceRegionError;
use crate::infer::lexical_region_resolve::RegionResolutionError;
-use crate::infer::Subtype;
+use crate::infer::{Subtype, ValuePairs};
use crate::traits::ObligationCauseCode::CompareImplItemObligation;
-use rustc_errors::{ErrorGuaranteed, MultiSpan};
+use rustc_errors::ErrorGuaranteed;
use rustc_hir as hir;
use rustc_hir::def::Res;
use rustc_hir::def_id::DefId;
use rustc_hir::intravisit::Visitor;
use rustc_middle::hir::nested_filter;
+use rustc_middle::ty::error::ExpectedFound;
use rustc_middle::ty::print::RegionHighlightMode;
use rustc_middle::ty::{self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitor};
use rustc_span::Span;
@@ -22,22 +24,27 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
let error = self.error.as_ref()?;
debug!("try_report_impl_not_conforming_to_trait {:?}", error);
if let RegionResolutionError::SubSupConflict(
- _,
- var_origin,
- sub_origin,
- _sub,
- sup_origin,
- _sup,
- _,
- ) = error.clone()
+ _,
+ var_origin,
+ sub_origin,
+ _sub,
+ sup_origin,
+ _sup,
+ _,
+ ) = error.clone()
&& let (Subtype(sup_trace), Subtype(sub_trace)) = (&sup_origin, &sub_origin)
- && let sub_expected_found @ Some((sub_expected, sub_found)) = sub_trace.values.ty()
- && let sup_expected_found @ Some(_) = sup_trace.values.ty()
&& let CompareImplItemObligation { trait_item_def_id, .. } = sub_trace.cause.code()
- && sup_expected_found == sub_expected_found
+ && sub_trace.values == sup_trace.values
+ && let ValuePairs::Sigs(ExpectedFound { expected, found }) = sub_trace.values
{
- let guar =
- self.emit_err(var_origin.span(), sub_expected, sub_found, *trait_item_def_id);
+ // FIXME(compiler-errors): Don't like that this needs `Ty`s, but
+ // all of the region highlighting machinery only deals with those.
+ let guar = self.emit_err(
+ var_origin.span(),
+ self.cx.tcx.mk_fn_ptr(ty::Binder::dummy(expected)),
+ self.cx.tcx.mk_fn_ptr(ty::Binder::dummy(found)),
+ *trait_item_def_id,
+ );
return Some(guar);
}
None
@@ -51,10 +58,6 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
trait_def_id: DefId,
) -> ErrorGuaranteed {
let trait_sp = self.tcx().def_span(trait_def_id);
- let mut err = self
- .tcx()
- .sess
- .struct_span_err(sp, "`impl` item signature doesn't match `trait` item signature");
// Mark all unnamed regions in the type with a number.
// This diagnostic is called in response to lifetime errors, so be informative.
@@ -91,9 +94,6 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
let found =
self.cx.extract_inference_diagnostics_data(found.into(), Some(found_highlight)).name;
- err.span_label(sp, &format!("found `{}`", found));
- err.span_label(trait_sp, &format!("expected `{}`", expected));
-
// Get the span of all the used type parameters in the method.
let assoc_item = self.tcx().associated_item(trait_def_id);
let mut visitor = TypeParamSpanVisitor { tcx: self.tcx(), types: vec![] };
@@ -110,26 +110,18 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
}
_ => {}
}
- let mut type_param_span: MultiSpan = visitor.types.to_vec().into();
- for &span in &visitor.types {
- type_param_span
- .push_span_label(span, "consider borrowing this type parameter in the trait");
- }
- err.note(&format!("expected `{}`\n found `{}`", expected, found));
-
- err.span_help(
- type_param_span,
- "the lifetime requirements from the `impl` do not correspond to the requirements in \
- the `trait`",
- );
- if visitor.types.is_empty() {
- err.help(
- "verify the lifetime relationships in the `trait` and `impl` between the `self` \
- argument, the other inputs and its output",
- );
- }
- err.emit()
+ let diag = TraitImplDiff {
+ sp,
+ trait_sp,
+ note: (),
+ param_help: ConsiderBorrowingParamHelp { spans: visitor.types.to_vec() },
+ rel_help: visitor.types.is_empty().then_some(RelationshipHelp),
+ expected,
+ found,
+ };
+
+ self.tcx().sess.emit_err(diag)
}
}
@@ -147,7 +139,7 @@ impl<'tcx> Visitor<'tcx> for TypeParamSpanVisitor<'tcx> {
fn visit_ty(&mut self, arg: &'tcx hir::Ty<'tcx>) {
match arg.kind {
- hir::TyKind::Rptr(_, ref mut_ty) => {
+ hir::TyKind::Ref(_, ref mut_ty) => {
// We don't want to suggest looking into borrowing `&T` or `&Self`.
hir::intravisit::walk_ty(self, mut_ty.ty);
return;