Skip to content

Commit 2118ff4

Browse files
committed
Migrate placeholder_error.rs
1 parent 8360a40 commit 2118ff4

File tree

3 files changed

+186
-126
lines changed

3 files changed

+186
-126
lines changed

compiler/rustc_error_messages/locales/en-US/infer.ftl

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,3 +183,31 @@ infer_explicit_lifetime_required_sugg = add explicit lifetime `{$named}` to {$id
183183
[ident] the type of `{$simple_ident}`
184184
*[param_type] type
185185
}
186+
187+
infer_actual_impl_expl_1 = {$leading_ellipsis ->
188+
[true] ...
189+
*[false] {""}
190+
}{$kind ->
191+
[signature] closure with signature `{$ty_or_sig}` must implement `{$trait_path}`
192+
[passive] `{$trait_path}` would have to be implemented for the type `{$ty_or_sig}`
193+
*[other] `{$ty_or_sig}` must implement `{$trait_path}`
194+
}{$lt_kind ->
195+
[two] , for any two lifetimes `'{$lifetime_1}` and `'{$lifetime_2}`...
196+
[any] , for any lifetime `'{$lifetime_1}`...
197+
[some] , for some specific lifetime `'{lifetime_1}`...
198+
*[nothing] {""}
199+
}
200+
201+
infer_actual_impl_expl_2 = {$kind_2 ->
202+
[implements_trait] ...but it actually implements `{$trait_path_2}`
203+
[implemented_for_ty] ...but `{$trait_path_2}` is actually implemented for the type `{$ty}`
204+
*[ty_implements] ...but `{$ty}` actually implements `{$trait_path_2}`
205+
}{$has_lifetime ->
206+
[true] , for some specific lifetime `'{$lifetime}`
207+
*[false] {""}
208+
}
209+
210+
infer_trait_placeholder_mismatch = implementation of `{$trait_def_id}` is not general enough
211+
.label_satisfy = doesn't satisfy where-clause
212+
.label_where = due to a where-clause on `{$def_id}`...
213+
.label_dup = implementation of `{$trait_def_id}` is not general enough

compiler/rustc_infer/src/errors/mod.rs

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -540,3 +540,44 @@ pub struct ExplicitLifetimeRequired<'a> {
540540
#[skip_arg]
541541
pub new_ty: Ty<'a>,
542542
}
543+
544+
#[derive(SessionSubdiagnostic)]
545+
pub enum ActualImplExplNotes {
546+
// Field names have to be different across all variants
547+
#[note(infer::actual_impl_expl_1)]
548+
NoteOne {
549+
leading_ellipsis: bool,
550+
kind: &'static str,
551+
ty_or_sig: String,
552+
trait_path: String,
553+
lt_kind: &'static str,
554+
lifetime_1: usize,
555+
lifetime_2: usize,
556+
},
557+
#[note(infer::actual_impl_expl_2)]
558+
NoteTwo {
559+
kind_2: &'static str,
560+
trait_path_2: String,
561+
has_lifetime: bool,
562+
lifetime: usize,
563+
ty: String,
564+
},
565+
}
566+
567+
#[derive(SessionDiagnostic)]
568+
#[diag(infer::trait_placeholder_mismatch)]
569+
pub struct TraitPlaceholderMismatch {
570+
#[primary_span]
571+
pub span: Span,
572+
#[label(infer::label_satisfy)]
573+
pub satisfy_span: Option<Span>,
574+
#[label(infer::label_where)]
575+
pub where_span: Option<Span>,
576+
#[label(infer::label_dup)]
577+
pub dup_span: Option<Span>,
578+
pub def_id: String,
579+
pub trait_def_id: String,
580+
581+
#[subdiagnostic]
582+
pub actual_impl_expl_notes: Vec<ActualImplExplNotes>,
583+
}

compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs

Lines changed: 117 additions & 126 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,19 @@
1+
use crate::errors::{ActualImplExplNotes, TraitPlaceholderMismatch};
12
use crate::infer::error_reporting::nice_region_error::NiceRegionError;
23
use crate::infer::lexical_region_resolve::RegionResolutionError;
34
use crate::infer::ValuePairs;
45
use crate::infer::{SubregionOrigin, TypeTrace};
56
use crate::traits::{ObligationCause, ObligationCauseCode};
67
use rustc_data_structures::intern::Interned;
7-
use rustc_errors::{Diagnostic, DiagnosticBuilder, ErrorGuaranteed};
8+
use rustc_errors::{DiagnosticBuilder, ErrorGuaranteed};
89
use rustc_hir::def::Namespace;
910
use rustc_hir::def_id::DefId;
1011
use rustc_middle::ty::error::ExpectedFound;
1112
use rustc_middle::ty::print::{FmtPrinter, Print, RegionHighlightMode};
1213
use rustc_middle::ty::subst::SubstsRef;
1314
use rustc_middle::ty::{self, RePlaceholder, ReVar, Region, TyCtxt};
1415

15-
use std::fmt::{self, Write};
16+
use std::fmt;
1617

1718
impl<'tcx> NiceRegionError<'_, 'tcx> {
1819
/// When given a `ConcreteFailure` for a function with arguments containing a named region and
@@ -205,26 +206,21 @@ impl<'tcx> NiceRegionError<'_, 'tcx> {
205206
actual_substs: SubstsRef<'tcx>,
206207
) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
207208
let span = cause.span();
208-
let msg = format!(
209-
"implementation of `{}` is not general enough",
210-
self.tcx().def_path_str(trait_def_id),
211-
);
212-
let mut err = self.tcx().sess.struct_span_err(span, &msg);
213209

214-
let leading_ellipsis = if let ObligationCauseCode::ItemObligation(def_id)
215-
| ObligationCauseCode::ExprItemObligation(def_id, ..) =
216-
*cause.code()
217-
{
218-
err.span_label(span, "doesn't satisfy where-clause");
219-
err.span_label(
220-
self.tcx().def_span(def_id),
221-
&format!("due to a where-clause on `{}`...", self.tcx().def_path_str(def_id)),
222-
);
223-
true
224-
} else {
225-
err.span_label(span, &msg);
226-
false
227-
};
210+
let (leading_ellipsis, satisfy_span, where_span, dup_span, def_id) =
211+
if let ObligationCauseCode::ItemObligation(def_id)
212+
| ObligationCauseCode::ExprItemObligation(def_id, ..) = *cause.code()
213+
{
214+
(
215+
true,
216+
Some(span),
217+
Some(self.tcx().def_span(def_id)),
218+
None,
219+
self.tcx().def_path_str(def_id),
220+
)
221+
} else {
222+
(false, None, None, Some(span), String::new())
223+
};
228224

229225
let expected_trait_ref = self
230226
.cx
@@ -284,8 +280,7 @@ impl<'tcx> NiceRegionError<'_, 'tcx> {
284280
?expected_self_ty_has_vid,
285281
);
286282

287-
self.explain_actual_impl_that_was_found(
288-
&mut err,
283+
let actual_impl_expl_notes = self.explain_actual_impl_that_was_found(
289284
sub_placeholder,
290285
sup_placeholder,
291286
has_sub,
@@ -299,7 +294,17 @@ impl<'tcx> NiceRegionError<'_, 'tcx> {
299294
leading_ellipsis,
300295
);
301296

302-
err
297+
let diag = TraitPlaceholderMismatch {
298+
span,
299+
satisfy_span,
300+
where_span,
301+
dup_span,
302+
def_id,
303+
trait_def_id: self.tcx().def_path_str(trait_def_id),
304+
actual_impl_expl_notes,
305+
};
306+
307+
self.tcx().sess.create_err(diag)
303308
}
304309

305310
/// Add notes with details about the expected and actual trait refs, with attention to cases
@@ -309,7 +314,6 @@ impl<'tcx> NiceRegionError<'_, 'tcx> {
309314
/// due to the number of combinations we have to deal with.
310315
fn explain_actual_impl_that_was_found(
311316
&self,
312-
err: &mut Diagnostic,
313317
sub_placeholder: Option<Region<'tcx>>,
314318
sup_placeholder: Option<Region<'tcx>>,
315319
has_sub: Option<usize>,
@@ -321,7 +325,7 @@ impl<'tcx> NiceRegionError<'_, 'tcx> {
321325
actual_has_vid: Option<usize>,
322326
any_self_ty_has_vid: bool,
323327
leading_ellipsis: bool,
324-
) {
328+
) -> Vec<ActualImplExplNotes> {
325329
// HACK(eddyb) maybe move this in a more central location.
326330
#[derive(Copy, Clone)]
327331
struct Highlighted<'tcx, T> {
@@ -380,120 +384,107 @@ impl<'tcx> NiceRegionError<'_, 'tcx> {
380384
let mut expected_trait_ref = highlight_trait_ref(expected_trait_ref);
381385
expected_trait_ref.highlight.maybe_highlighting_region(sub_placeholder, has_sub);
382386
expected_trait_ref.highlight.maybe_highlighting_region(sup_placeholder, has_sup);
383-
err.note(&{
384-
let passive_voice = match (has_sub, has_sup) {
385-
(Some(_), _) | (_, Some(_)) => any_self_ty_has_vid,
386-
(None, None) => {
387-
expected_trait_ref.highlight.maybe_highlighting_region(vid, expected_has_vid);
388-
match expected_has_vid {
389-
Some(_) => true,
390-
None => any_self_ty_has_vid,
391-
}
392-
}
393-
};
394387

395-
let mut note = if same_self_type {
396-
let mut self_ty = expected_trait_ref.map(|tr| tr.self_ty());
397-
self_ty.highlight.maybe_highlighting_region(vid, actual_has_vid);
398-
399-
if self_ty.value.is_closure()
400-
&& self.tcx().is_fn_trait(expected_trait_ref.value.def_id)
401-
{
402-
let closure_sig = self_ty.map(|closure| {
403-
if let ty::Closure(_, substs) = closure.kind() {
404-
self.tcx().signature_unclosure(
405-
substs.as_closure().sig(),
406-
rustc_hir::Unsafety::Normal,
407-
)
408-
} else {
409-
bug!("type is not longer closure");
410-
}
411-
});
412-
413-
format!(
414-
"{}closure with signature `{}` must implement `{}`",
415-
if leading_ellipsis { "..." } else { "" },
416-
closure_sig,
417-
expected_trait_ref.map(|tr| tr.print_only_trait_path()),
418-
)
419-
} else {
420-
format!(
421-
"{}`{}` must implement `{}`",
422-
if leading_ellipsis { "..." } else { "" },
423-
self_ty,
424-
expected_trait_ref.map(|tr| tr.print_only_trait_path()),
425-
)
388+
let passive_voice = match (has_sub, has_sup) {
389+
(Some(_), _) | (_, Some(_)) => any_self_ty_has_vid,
390+
(None, None) => {
391+
expected_trait_ref.highlight.maybe_highlighting_region(vid, expected_has_vid);
392+
match expected_has_vid {
393+
Some(_) => true,
394+
None => any_self_ty_has_vid,
426395
}
427-
} else if passive_voice {
428-
format!(
429-
"{}`{}` would have to be implemented for the type `{}`",
430-
if leading_ellipsis { "..." } else { "" },
431-
expected_trait_ref.map(|tr| tr.print_only_trait_path()),
432-
expected_trait_ref.map(|tr| tr.self_ty()),
396+
}
397+
};
398+
399+
let (kind, ty_or_sig, trait_path) = if same_self_type {
400+
let mut self_ty = expected_trait_ref.map(|tr| tr.self_ty());
401+
self_ty.highlight.maybe_highlighting_region(vid, actual_has_vid);
402+
403+
if self_ty.value.is_closure()
404+
&& self.tcx().is_fn_trait(expected_trait_ref.value.def_id)
405+
{
406+
let closure_sig = self_ty.map(|closure| {
407+
if let ty::Closure(_, substs) = closure.kind() {
408+
self.tcx().signature_unclosure(
409+
substs.as_closure().sig(),
410+
rustc_hir::Unsafety::Normal,
411+
)
412+
} else {
413+
bug!("type is not longer closure");
414+
}
415+
});
416+
(
417+
"signature",
418+
closure_sig.to_string(),
419+
expected_trait_ref.map(|tr| tr.print_only_trait_path()).to_string(),
433420
)
434421
} else {
435-
format!(
436-
"{}`{}` must implement `{}`",
437-
if leading_ellipsis { "..." } else { "" },
438-
expected_trait_ref.map(|tr| tr.self_ty()),
439-
expected_trait_ref.map(|tr| tr.print_only_trait_path()),
422+
(
423+
"other",
424+
self_ty.to_string(),
425+
expected_trait_ref.map(|tr| tr.print_only_trait_path()).to_string(),
440426
)
441-
};
427+
}
428+
} else if passive_voice {
429+
(
430+
"passive",
431+
expected_trait_ref.map(|tr| tr.self_ty()).to_string(),
432+
expected_trait_ref.map(|tr| tr.print_only_trait_path()).to_string(),
433+
)
434+
} else {
435+
(
436+
"other",
437+
expected_trait_ref.map(|tr| tr.self_ty()).to_string(),
438+
expected_trait_ref.map(|tr| tr.print_only_trait_path()).to_string(),
439+
)
440+
};
442441

443-
match (has_sub, has_sup) {
444-
(Some(n1), Some(n2)) => {
445-
let _ = write!(
446-
note,
447-
", for any two lifetimes `'{}` and `'{}`...",
448-
std::cmp::min(n1, n2),
449-
std::cmp::max(n1, n2),
450-
);
451-
}
452-
(Some(n), _) | (_, Some(n)) => {
453-
let _ = write!(note, ", for any lifetime `'{}`...", n,);
454-
}
455-
(None, None) => {
456-
if let Some(n) = expected_has_vid {
457-
let _ = write!(note, ", for some specific lifetime `'{}`...", n,);
458-
}
442+
let (lt_kind, lifetime_1, lifetime_2) = match (has_sub, has_sup) {
443+
(Some(n1), Some(n2)) => ("two", std::cmp::min(n1, n2), std::cmp::max(n1, n2)),
444+
(Some(n), _) | (_, Some(n)) => ("any", n, 0),
445+
(None, None) => {
446+
if let Some(n) = expected_has_vid {
447+
("some", n, 0)
448+
} else {
449+
("nothing", 0, 0)
459450
}
460451
}
452+
};
461453

462-
note
463-
});
454+
let note_1 = ActualImplExplNotes::NoteOne {
455+
leading_ellipsis,
456+
kind,
457+
ty_or_sig,
458+
trait_path,
459+
lt_kind,
460+
lifetime_1,
461+
lifetime_2,
462+
};
464463

465464
let mut actual_trait_ref = highlight_trait_ref(actual_trait_ref);
466465
actual_trait_ref.highlight.maybe_highlighting_region(vid, actual_has_vid);
467-
err.note(&{
468-
let passive_voice = match actual_has_vid {
469-
Some(_) => any_self_ty_has_vid,
470-
None => true,
471-
};
472466

473-
let mut note = if same_self_type {
474-
format!(
475-
"...but it actually implements `{}`",
476-
actual_trait_ref.map(|tr| tr.print_only_trait_path()),
477-
)
478-
} else if passive_voice {
479-
format!(
480-
"...but `{}` is actually implemented for the type `{}`",
481-
actual_trait_ref.map(|tr| tr.print_only_trait_path()),
482-
actual_trait_ref.map(|tr| tr.self_ty()),
483-
)
484-
} else {
485-
format!(
486-
"...but `{}` actually implements `{}`",
487-
actual_trait_ref.map(|tr| tr.self_ty()),
488-
actual_trait_ref.map(|tr| tr.print_only_trait_path()),
489-
)
490-
};
467+
let passive_voice = match actual_has_vid {
468+
Some(_) => any_self_ty_has_vid,
469+
None => true,
470+
};
491471

492-
if let Some(n) = actual_has_vid {
493-
let _ = write!(note, ", for some specific lifetime `'{}`", n);
494-
}
472+
let trait_path_2 = actual_trait_ref.map(|tr| tr.print_only_trait_path()).to_string();
473+
let ty = actual_trait_ref.map(|tr| tr.self_ty()).to_string();
474+
let kind_2 = if same_self_type {
475+
"implements_trait"
476+
} else if passive_voice {
477+
"implemented_for_ty"
478+
} else {
479+
"ty_implements"
480+
};
495481

496-
note
497-
});
482+
let has_lifetime = actual_has_vid.is_some();
483+
let lifetime = actual_has_vid.unwrap_or_default();
484+
485+
let note_2 =
486+
ActualImplExplNotes::NoteTwo { kind_2, trait_path_2, ty, has_lifetime, lifetime };
487+
488+
vec![note_1, note_2]
498489
}
499490
}

0 commit comments

Comments
 (0)