summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_infer/src/infer/error_reporting/note.rs
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_infer/src/infer/error_reporting/note.rs')
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/note.rs195
1 files changed, 84 insertions, 111 deletions
diff --git a/compiler/rustc_infer/src/infer/error_reporting/note.rs b/compiler/rustc_infer/src/infer/error_reporting/note.rs
index d2dffa4a0..b18cbd404 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/note.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/note.rs
@@ -2,11 +2,14 @@ use crate::errors::RegionOriginNote;
use crate::infer::error_reporting::{note_and_explain_region, TypeErrCtxt};
use crate::infer::{self, SubregionOrigin};
use rustc_errors::{
- fluent, struct_span_err, AddToDiagnostic, Diagnostic, DiagnosticBuilder, ErrorGuaranteed,
+ fluent, struct_span_err, AddToDiagnostic, Applicability, Diagnostic, DiagnosticBuilder,
+ ErrorGuaranteed,
};
+use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_middle::traits::ObligationCauseCode;
use rustc_middle::ty::error::TypeError;
-use rustc_middle::ty::{self, Region};
+use rustc_middle::ty::{self, IsSuggestable, Region};
+use rustc_span::symbol::kw;
use super::ObligationCauseAsDiagArg;
@@ -22,29 +25,10 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
infer::Reborrow(span) => {
RegionOriginNote::Plain { span, msg: fluent::infer_reborrow }.add_to_diagnostic(err)
}
- infer::ReborrowUpvar(span, ref upvar_id) => {
- let var_name = self.tcx.hir().name(upvar_id.var_path.hir_id);
- RegionOriginNote::WithName {
- span,
- msg: fluent::infer_reborrow,
- name: &var_name.to_string(),
- continues: false,
- }
- .add_to_diagnostic(err);
- }
infer::RelateObjectBound(span) => {
RegionOriginNote::Plain { span, msg: fluent::infer_relate_object_bound }
.add_to_diagnostic(err);
}
- infer::DataBorrowed(ty, span) => {
- RegionOriginNote::WithName {
- span,
- msg: fluent::infer_data_borrowed,
- name: &self.ty_to_string(ty),
- continues: false,
- }
- .add_to_diagnostic(err);
- }
infer::ReferenceOutlivesReferent(ty, span) => {
RegionOriginNote::WithName {
span,
@@ -159,33 +143,6 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
);
err
}
- infer::ReborrowUpvar(span, ref upvar_id) => {
- let var_name = self.tcx.hir().name(upvar_id.var_path.hir_id);
- let mut err = struct_span_err!(
- self.tcx.sess,
- span,
- E0313,
- "lifetime of borrowed pointer outlives lifetime of captured variable `{}`...",
- var_name
- );
- note_and_explain_region(
- self.tcx,
- &mut err,
- "...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
- }
infer::RelateObjectBound(span) => {
let mut err = struct_span_err!(
self.tcx.sess,
@@ -261,32 +218,6 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
);
err
}
- infer::DataBorrowed(ty, span) => {
- let mut err = struct_span_err!(
- self.tcx.sess,
- span,
- E0490,
- "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,
- "",
- None,
- );
- note_and_explain_region(
- self.tcx,
- &mut err,
- "but the borrow lasts for ",
- sup,
- "",
- None,
- );
- err
- }
infer::ReferenceOutlivesReferent(ty, span) => {
let mut err = struct_span_err!(
self.tcx.sess,
@@ -313,55 +244,38 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
);
err
}
- infer::CompareImplItemObligation { span, impl_item_def_id, trait_item_def_id } => self
- .report_extra_impl_obligation(
+ infer::CompareImplItemObligation { span, impl_item_def_id, trait_item_def_id } => {
+ let mut err = self.report_extra_impl_obligation(
span,
impl_item_def_id,
trait_item_def_id,
&format!("`{}: {}`", sup, sub),
- ),
+ );
+ // We should only suggest rewriting the `where` clause if the predicate is within that `where` clause
+ if let Some(generics) = self.tcx.hir().get_generics(impl_item_def_id)
+ && generics.where_clause_span.contains(span)
+ {
+ self.suggest_copy_trait_method_bounds(
+ trait_item_def_id,
+ impl_item_def_id,
+ &mut err,
+ );
+ }
+ err
+ }
infer::CheckAssociatedTypeBounds { impl_item_def_id, trait_item_def_id, parent } => {
let mut err = self.report_concrete_failure(*parent, sub, sup);
-
let trait_item_span = self.tcx.def_span(trait_item_def_id);
let item_name = self.tcx.item_name(impl_item_def_id.to_def_id());
err.span_label(
trait_item_span,
format!("definition of `{}` from trait", item_name),
);
-
- let trait_predicates = self.tcx.explicit_predicates_of(trait_item_def_id);
- let impl_predicates = self.tcx.explicit_predicates_of(impl_item_def_id);
-
- let impl_predicates: rustc_data_structures::fx::FxHashSet<_> =
- impl_predicates.predicates.into_iter().map(|(pred, _)| pred).collect();
- let clauses: Vec<_> = trait_predicates
- .predicates
- .into_iter()
- .filter(|&(pred, _)| !impl_predicates.contains(pred))
- .map(|(pred, _)| format!("{}", pred))
- .collect();
-
- if !clauses.is_empty() {
- let generics = self.tcx.hir().get_generics(impl_item_def_id).unwrap();
- let where_clause_span = generics.tail_span_for_predicate_suggestion();
-
- let suggestion = format!(
- "{} {}",
- generics.add_where_or_trailing_comma(),
- clauses.join(", "),
- );
- err.span_suggestion(
- where_clause_span,
- &format!(
- "try copying {} from the trait",
- if clauses.len() > 1 { "these clauses" } else { "this clause" }
- ),
- suggestion,
- rustc_errors::Applicability::MaybeIncorrect,
- );
- }
-
+ self.suggest_copy_trait_method_bounds(
+ trait_item_def_id,
+ impl_item_def_id,
+ &mut err,
+ );
err
}
infer::AscribeUserTypeProvePredicate(span) => {
@@ -388,6 +302,65 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
}
}
+ pub fn suggest_copy_trait_method_bounds(
+ &self,
+ trait_item_def_id: DefId,
+ impl_item_def_id: LocalDefId,
+ err: &mut Diagnostic,
+ ) {
+ // FIXME(compiler-errors): Right now this is only being used for region
+ // predicate mismatches. Ideally, we'd use it for *all* predicate mismatches,
+ // but right now it's not really very smart when it comes to implicit `Sized`
+ // predicates and bounds on the trait itself.
+
+ let Some(impl_def_id) =
+ self.tcx.associated_item(impl_item_def_id).impl_container(self.tcx) else { return; };
+ let Some(trait_ref) = self
+ .tcx
+ .impl_trait_ref(impl_def_id)
+ else { return; };
+ let trait_substs = trait_ref
+ .subst_identity()
+ // Replace the explicit self type with `Self` for better suggestion rendering
+ .with_self_ty(self.tcx, self.tcx.mk_ty_param(0, kw::SelfUpper))
+ .substs;
+ let trait_item_substs =
+ ty::InternalSubsts::identity_for_item(self.tcx, impl_item_def_id.to_def_id())
+ .rebase_onto(self.tcx, impl_def_id, trait_substs);
+
+ let Ok(trait_predicates) = self
+ .tcx
+ .explicit_predicates_of(trait_item_def_id)
+ .instantiate_own(self.tcx, trait_item_substs)
+ .map(|(pred, _)| {
+ if pred.is_suggestable(self.tcx, false) {
+ Ok(pred.to_string())
+ } else {
+ Err(())
+ }
+ })
+ .collect::<Result<Vec<_>, ()>>() else { return; };
+
+ let Some(generics) = self.tcx.hir().get_generics(impl_item_def_id) else { return; };
+
+ if trait_predicates.is_empty() {
+ err.span_suggestion_verbose(
+ generics.where_clause_span,
+ "remove the `where` clause",
+ String::new(),
+ Applicability::MachineApplicable,
+ );
+ } else {
+ let space = if generics.where_clause_span.is_empty() { " " } else { "" };
+ err.span_suggestion_verbose(
+ generics.where_clause_span,
+ "copy the `where` clause predicates from the trait",
+ format!("{space}where {}", trait_predicates.join(", ")),
+ Applicability::MachineApplicable,
+ );
+ }
+ }
+
pub(super) fn report_placeholder_failure(
&self,
placeholder_origin: SubregionOrigin<'tcx>,