Migrate placeholder_error.rs

This commit is contained in:
Nikita Tomashevich 2022-09-11 00:45:38 +03:00
parent 8360a40a8a
commit 2118ff401f
No known key found for this signature in database
GPG key ID: B29791D4D878E345
3 changed files with 191 additions and 131 deletions

View file

@ -183,3 +183,31 @@ infer_explicit_lifetime_required_sugg = add explicit lifetime `{$named}` to {$id
[ident] the type of `{$simple_ident}` [ident] the type of `{$simple_ident}`
*[param_type] type *[param_type] type
} }
infer_actual_impl_expl_1 = {$leading_ellipsis ->
[true] ...
*[false] {""}
}{$kind ->
[signature] closure with signature `{$ty_or_sig}` must implement `{$trait_path}`
[passive] `{$trait_path}` would have to be implemented for the type `{$ty_or_sig}`
*[other] `{$ty_or_sig}` must implement `{$trait_path}`
}{$lt_kind ->
[two] , for any two lifetimes `'{$lifetime_1}` and `'{$lifetime_2}`...
[any] , for any lifetime `'{$lifetime_1}`...
[some] , for some specific lifetime `'{lifetime_1}`...
*[nothing] {""}
}
infer_actual_impl_expl_2 = {$kind_2 ->
[implements_trait] ...but it actually implements `{$trait_path_2}`
[implemented_for_ty] ...but `{$trait_path_2}` is actually implemented for the type `{$ty}`
*[ty_implements] ...but `{$ty}` actually implements `{$trait_path_2}`
}{$has_lifetime ->
[true] , for some specific lifetime `'{$lifetime}`
*[false] {""}
}
infer_trait_placeholder_mismatch = implementation of `{$trait_def_id}` is not general enough
.label_satisfy = doesn't satisfy where-clause
.label_where = due to a where-clause on `{$def_id}`...
.label_dup = implementation of `{$trait_def_id}` is not general enough

View file

@ -540,3 +540,44 @@ pub struct ExplicitLifetimeRequired<'a> {
#[skip_arg] #[skip_arg]
pub new_ty: Ty<'a>, pub new_ty: Ty<'a>,
} }
#[derive(SessionSubdiagnostic)]
pub enum ActualImplExplNotes {
// Field names have to be different across all variants
#[note(infer::actual_impl_expl_1)]
NoteOne {
leading_ellipsis: bool,
kind: &'static str,
ty_or_sig: String,
trait_path: String,
lt_kind: &'static str,
lifetime_1: usize,
lifetime_2: usize,
},
#[note(infer::actual_impl_expl_2)]
NoteTwo {
kind_2: &'static str,
trait_path_2: String,
has_lifetime: bool,
lifetime: usize,
ty: String,
},
}
#[derive(SessionDiagnostic)]
#[diag(infer::trait_placeholder_mismatch)]
pub struct TraitPlaceholderMismatch {
#[primary_span]
pub span: Span,
#[label(infer::label_satisfy)]
pub satisfy_span: Option<Span>,
#[label(infer::label_where)]
pub where_span: Option<Span>,
#[label(infer::label_dup)]
pub dup_span: Option<Span>,
pub def_id: String,
pub trait_def_id: String,
#[subdiagnostic]
pub actual_impl_expl_notes: Vec<ActualImplExplNotes>,
}

View file

@ -1,10 +1,11 @@
use crate::errors::{ActualImplExplNotes, TraitPlaceholderMismatch};
use crate::infer::error_reporting::nice_region_error::NiceRegionError; use crate::infer::error_reporting::nice_region_error::NiceRegionError;
use crate::infer::lexical_region_resolve::RegionResolutionError; use crate::infer::lexical_region_resolve::RegionResolutionError;
use crate::infer::ValuePairs; use crate::infer::ValuePairs;
use crate::infer::{SubregionOrigin, TypeTrace}; use crate::infer::{SubregionOrigin, TypeTrace};
use crate::traits::{ObligationCause, ObligationCauseCode}; use crate::traits::{ObligationCause, ObligationCauseCode};
use rustc_data_structures::intern::Interned; use rustc_data_structures::intern::Interned;
use rustc_errors::{Diagnostic, DiagnosticBuilder, ErrorGuaranteed}; use rustc_errors::{DiagnosticBuilder, ErrorGuaranteed};
use rustc_hir::def::Namespace; use rustc_hir::def::Namespace;
use rustc_hir::def_id::DefId; use rustc_hir::def_id::DefId;
use rustc_middle::ty::error::ExpectedFound; use rustc_middle::ty::error::ExpectedFound;
@ -12,7 +13,7 @@ use rustc_middle::ty::print::{FmtPrinter, Print, RegionHighlightMode};
use rustc_middle::ty::subst::SubstsRef; use rustc_middle::ty::subst::SubstsRef;
use rustc_middle::ty::{self, RePlaceholder, ReVar, Region, TyCtxt}; use rustc_middle::ty::{self, RePlaceholder, ReVar, Region, TyCtxt};
use std::fmt::{self, Write}; use std::fmt;
impl<'tcx> NiceRegionError<'_, 'tcx> { impl<'tcx> NiceRegionError<'_, 'tcx> {
/// When given a `ConcreteFailure` for a function with arguments containing a named region and /// When given a `ConcreteFailure` for a function with arguments containing a named region and
@ -205,26 +206,21 @@ impl<'tcx> NiceRegionError<'_, 'tcx> {
actual_substs: SubstsRef<'tcx>, actual_substs: SubstsRef<'tcx>,
) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
let span = cause.span(); 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) let (leading_ellipsis, satisfy_span, where_span, dup_span, def_id) =
| ObligationCauseCode::ExprItemObligation(def_id, ..) = if let ObligationCauseCode::ItemObligation(def_id)
*cause.code() | ObligationCauseCode::ExprItemObligation(def_id, ..) = *cause.code()
{ {
err.span_label(span, "doesn't satisfy where-clause"); (
err.span_label( true,
self.tcx().def_span(def_id), Some(span),
&format!("due to a where-clause on `{}`...", self.tcx().def_path_str(def_id)), Some(self.tcx().def_span(def_id)),
); None,
true self.tcx().def_path_str(def_id),
} else { )
err.span_label(span, &msg); } else {
false (false, None, None, Some(span), String::new())
}; };
let expected_trait_ref = self let expected_trait_ref = self
.cx .cx
@ -284,8 +280,7 @@ impl<'tcx> NiceRegionError<'_, 'tcx> {
?expected_self_ty_has_vid, ?expected_self_ty_has_vid,
); );
self.explain_actual_impl_that_was_found( let actual_impl_expl_notes = self.explain_actual_impl_that_was_found(
&mut err,
sub_placeholder, sub_placeholder,
sup_placeholder, sup_placeholder,
has_sub, has_sub,
@ -299,7 +294,17 @@ impl<'tcx> NiceRegionError<'_, 'tcx> {
leading_ellipsis, leading_ellipsis,
); );
err let diag = 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,
};
self.tcx().sess.create_err(diag)
} }
/// Add notes with details about the expected and actual trait refs, with attention to cases /// Add notes with details about the expected and actual trait refs, with attention to cases
@ -309,7 +314,6 @@ impl<'tcx> NiceRegionError<'_, 'tcx> {
/// due to the number of combinations we have to deal with. /// due to the number of combinations we have to deal with.
fn explain_actual_impl_that_was_found( fn explain_actual_impl_that_was_found(
&self, &self,
err: &mut Diagnostic,
sub_placeholder: Option<Region<'tcx>>, sub_placeholder: Option<Region<'tcx>>,
sup_placeholder: Option<Region<'tcx>>, sup_placeholder: Option<Region<'tcx>>,
has_sub: Option<usize>, has_sub: Option<usize>,
@ -321,7 +325,7 @@ impl<'tcx> NiceRegionError<'_, 'tcx> {
actual_has_vid: Option<usize>, actual_has_vid: Option<usize>,
any_self_ty_has_vid: bool, any_self_ty_has_vid: bool,
leading_ellipsis: bool, leading_ellipsis: bool,
) { ) -> Vec<ActualImplExplNotes> {
// HACK(eddyb) maybe move this in a more central location. // HACK(eddyb) maybe move this in a more central location.
#[derive(Copy, Clone)] #[derive(Copy, Clone)]
struct Highlighted<'tcx, T> { struct Highlighted<'tcx, T> {
@ -380,120 +384,107 @@ impl<'tcx> NiceRegionError<'_, 'tcx> {
let mut expected_trait_ref = highlight_trait_ref(expected_trait_ref); 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(sub_placeholder, has_sub);
expected_trait_ref.highlight.maybe_highlighting_region(sup_placeholder, has_sup); 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 passive_voice = match (has_sub, has_sup) {
let mut self_ty = expected_trait_ref.map(|tr| tr.self_ty()); (Some(_), _) | (_, Some(_)) => any_self_ty_has_vid,
self_ty.highlight.maybe_highlighting_region(vid, actual_has_vid); (None, None) => {
expected_trait_ref.highlight.maybe_highlighting_region(vid, expected_has_vid);
if self_ty.value.is_closure() match expected_has_vid {
&& self.tcx().is_fn_trait(expected_trait_ref.value.def_id) Some(_) => true,
{ None => any_self_ty_has_vid,
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()),
)
}
} else if passive_voice {
format!(
"{}`{}` would have to be implemented for the type `{}`",
if leading_ellipsis { "..." } else { "" },
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()),
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,);
}
} }
} }
};
note 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");
}
});
(
"signature",
closure_sig.to_string(),
expected_trait_ref.map(|tr| tr.print_only_trait_path()).to_string(),
)
} else {
(
"other",
self_ty.to_string(),
expected_trait_ref.map(|tr| tr.print_only_trait_path()).to_string(),
)
}
} else if passive_voice {
(
"passive",
expected_trait_ref.map(|tr| tr.self_ty()).to_string(),
expected_trait_ref.map(|tr| tr.print_only_trait_path()).to_string(),
)
} else {
(
"other",
expected_trait_ref.map(|tr| tr.self_ty()).to_string(),
expected_trait_ref.map(|tr| tr.print_only_trait_path()).to_string(),
)
};
let (lt_kind, lifetime_1, lifetime_2) = match (has_sub, has_sup) {
(Some(n1), Some(n2)) => ("two", std::cmp::min(n1, n2), std::cmp::max(n1, n2)),
(Some(n), _) | (_, Some(n)) => ("any", n, 0),
(None, None) => {
if let Some(n) = expected_has_vid {
("some", n, 0)
} else {
("nothing", 0, 0)
}
}
};
let note_1 = ActualImplExplNotes::NoteOne {
leading_ellipsis,
kind,
ty_or_sig,
trait_path,
lt_kind,
lifetime_1,
lifetime_2,
};
let mut actual_trait_ref = highlight_trait_ref(actual_trait_ref); let mut actual_trait_ref = highlight_trait_ref(actual_trait_ref);
actual_trait_ref.highlight.maybe_highlighting_region(vid, actual_has_vid); 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 { let passive_voice = match actual_has_vid {
format!( Some(_) => any_self_ty_has_vid,
"...but it actually implements `{}`", None => true,
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()),
)
};
if let Some(n) = actual_has_vid { let trait_path_2 = actual_trait_ref.map(|tr| tr.print_only_trait_path()).to_string();
let _ = write!(note, ", for some specific lifetime `'{}`", n); let ty = actual_trait_ref.map(|tr| tr.self_ty()).to_string();
} let kind_2 = if same_self_type {
"implements_trait"
} else if passive_voice {
"implemented_for_ty"
} else {
"ty_implements"
};
note let has_lifetime = actual_has_vid.is_some();
}); let lifetime = actual_has_vid.unwrap_or_default();
let note_2 =
ActualImplExplNotes::NoteTwo { kind_2, trait_path_2, ty, has_lifetime, lifetime };
vec![note_1, note_2]
} }
} }