Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 405e48f

Browse files
authoredJan 7, 2023
Rollup merge of #101936 - IntQuant:issue-100717-infer-4, r=compiler-errors
Migrating rustc_infer to session diagnostics (part 3) ``@rustbot`` label +A-translation r? rust-lang/diagnostics cc #100717 Seems like a part of static_impl_trait.rs emits suggestions in a loop, and note.rs needs to have two instances of the same subdiagnostic, so these will need to wait until we have eager translation/list support. Other than that, there is only error_reporting/mod.rs left to migrate.
2 parents b1691f6 + 0c50e1f commit 405e48f

File tree

7 files changed

+810
-326
lines changed

7 files changed

+810
-326
lines changed
 

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

Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,3 +172,142 @@ infer_msl_unmet_req = because this has an unmet lifetime requirement
172172
infer_msl_trait_note = this has an implicit `'static` lifetime requirement
173173
infer_msl_trait_sugg = consider relaxing the implicit `'static` requirement
174174
infer_suggest_add_let_for_letchains = consider adding `let`
175+
176+
infer_explicit_lifetime_required_with_ident = explicit lifetime required in the type of `{$simple_ident}`
177+
.label = lifetime `{$named}` required
178+
179+
infer_explicit_lifetime_required_with_param_type = explicit lifetime required in parameter type
180+
.label = lifetime `{$named}` required
181+
182+
infer_explicit_lifetime_required_sugg_with_ident = add explicit lifetime `{$named}` to the type of `{$simple_ident}`
183+
184+
infer_explicit_lifetime_required_sugg_with_param_type = add explicit lifetime `{$named}` to type
185+
186+
infer_actual_impl_expl_expected_signature_two = {$leading_ellipsis ->
187+
[true] ...
188+
*[false] {""}
189+
}closure with signature `{$ty_or_sig}` must implement `{$trait_path}`, for any two lifetimes `'{$lifetime_1}` and `'{$lifetime_2}`...
190+
infer_actual_impl_expl_expected_signature_any = {$leading_ellipsis ->
191+
[true] ...
192+
*[false] {""}
193+
}closure with signature `{$ty_or_sig}` must implement `{$trait_path}`, for any lifetime `'{$lifetime_1}`...
194+
infer_actual_impl_expl_expected_signature_some = {$leading_ellipsis ->
195+
[true] ...
196+
*[false] {""}
197+
}closure with signature `{$ty_or_sig}` must implement `{$trait_path}`, for some specific lifetime `'{lifetime_1}`...
198+
infer_actual_impl_expl_expected_signature_nothing = {$leading_ellipsis ->
199+
[true] ...
200+
*[false] {""}
201+
}closure with signature `{$ty_or_sig}` must implement `{$trait_path}`
202+
infer_actual_impl_expl_expected_passive_two = {$leading_ellipsis ->
203+
[true] ...
204+
*[false] {""}
205+
}`{$trait_path}` would have to be implemented for the type `{$ty_or_sig}`, for any two lifetimes `'{$lifetime_1}` and `'{$lifetime_2}`...
206+
infer_actual_impl_expl_expected_passive_any = {$leading_ellipsis ->
207+
[true] ...
208+
*[false] {""}
209+
}`{$trait_path}` would have to be implemented for the type `{$ty_or_sig}`, for any lifetime `'{$lifetime_1}`...
210+
infer_actual_impl_expl_expected_passive_some = {$leading_ellipsis ->
211+
[true] ...
212+
*[false] {""}
213+
}`{$trait_path}` would have to be implemented for the type `{$ty_or_sig}`, for some specific lifetime `'{lifetime_1}`...
214+
infer_actual_impl_expl_expected_passive_nothing = {$leading_ellipsis ->
215+
[true] ...
216+
*[false] {""}
217+
}`{$trait_path}` would have to be implemented for the type `{$ty_or_sig}`
218+
infer_actual_impl_expl_expected_other_two = {$leading_ellipsis ->
219+
[true] ...
220+
*[false] {""}
221+
}`{$ty_or_sig}` must implement `{$trait_path}`, for any two lifetimes `'{$lifetime_1}` and `'{$lifetime_2}`...
222+
infer_actual_impl_expl_expected_other_any = {$leading_ellipsis ->
223+
[true] ...
224+
*[false] {""}
225+
}`{$ty_or_sig}` must implement `{$trait_path}`, for any lifetime `'{$lifetime_1}`...
226+
infer_actual_impl_expl_expected_other_some = {$leading_ellipsis ->
227+
[true] ...
228+
*[false] {""}
229+
}`{$ty_or_sig}` must implement `{$trait_path}`, for some specific lifetime `'{lifetime_1}`...
230+
infer_actual_impl_expl_expected_other_nothing = {$leading_ellipsis ->
231+
[true] ...
232+
*[false] {""}
233+
}`{$ty_or_sig}` must implement `{$trait_path}`
234+
235+
infer_actual_impl_expl_but_actually_implements_trait = ...but it actually implements `{$trait_path}`{$has_lifetime ->
236+
[true] , for some specific lifetime `'{$lifetime}`
237+
*[false] {""}
238+
}
239+
infer_actual_impl_expl_but_actually_implemented_for_ty = ...but `{$trait_path}` is actually implemented for the type `{$ty}`{$has_lifetime ->
240+
[true] , for some specific lifetime `'{$lifetime}`
241+
*[false] {""}
242+
}
243+
infer_actual_impl_expl_but_actually_ty_implements = ...but `{$ty}` actually implements `{$trait_path}`{$has_lifetime ->
244+
[true] , for some specific lifetime `'{$lifetime}`
245+
*[false] {""}
246+
}
247+
248+
infer_trait_placeholder_mismatch = implementation of `{$trait_def_id}` is not general enough
249+
.label_satisfy = doesn't satisfy where-clause
250+
.label_where = due to a where-clause on `{$def_id}`...
251+
.label_dup = implementation of `{$trait_def_id}` is not general enough
252+
253+
infer_trait_impl_diff = `impl` item signature doesn't match `trait` item signature
254+
.found = found `{$found}`
255+
.expected = expected `{$expected}`
256+
.expected_found = expected `{$expected}`
257+
{" "}found `{$found}`
258+
259+
infer_tid_rel_help = verify the lifetime relationships in the `trait` and `impl` between the `self` argument, the other inputs and its output
260+
infer_tid_consider_borrowing = consider borrowing this type parameter in the trait
261+
infer_tid_param_help = the lifetime requirements from the `impl` do not correspond to the requirements in the `trait`
262+
263+
infer_dtcs_has_lifetime_req_label = this has an implicit `'static` lifetime requirement
264+
infer_dtcs_introduces_requirement = calling this method introduces the `impl`'s 'static` requirement
265+
infer_dtcs_has_req_note = the used `impl` has a `'static` requirement
266+
infer_dtcs_suggestion = consider relaxing the implicit `'static` requirement
267+
268+
infer_but_calling_introduces = {$has_param_name ->
269+
[true] `{$param_name}`
270+
*[false] `fn` parameter
271+
} has {$lifetime_kind ->
272+
[named] lifetime `{lifetime}`
273+
*[anon] an anonymous lifetime `'_`
274+
} but calling `{assoc_item}` introduces an implicit `'static` lifetime requirement
275+
.label1 = {$has_lifetime ->
276+
[named] lifetime `{lifetime}`
277+
*[anon] an anonymous lifetime `'_`
278+
}
279+
.label2 = ...is used and required to live as long as `'static` here because of an implicit lifetime bound on the {$has_impl_path ->
280+
[named] `impl` of `{$impl_path}`
281+
*[anon] inherent `impl`
282+
}
283+
284+
infer_but_needs_to_satisfy = {$has_param_name ->
285+
[true] `{$param_name}`
286+
*[false] `fn` parameter
287+
} has {$has_lifetime ->
288+
[named] lifetime `{lifetime}`
289+
*[anon] an anonymous lifetime `'_`
290+
} but it needs to satisfy a `'static` lifetime requirement
291+
.influencer = this data with {$has_lifetime ->
292+
[named] lifetime `{lifetime}`
293+
*[anon] an anonymous lifetime `'_`
294+
}...
295+
.require = {$spans_empty ->
296+
*[true] ...is used and required to live as long as `'static` here
297+
[false] ...and is required to live as long as `'static` here
298+
}
299+
.used_here = ...is used here...
300+
.introduced_by_bound = 'static` lifetime requirement introduced by this bound
301+
302+
infer_more_targeted = {$has_param_name ->
303+
[true] `{$param_name}`
304+
*[false] `fn` parameter
305+
} has {$has_lifetime ->
306+
[named] lifetime `{lifetime}`
307+
*[anon] an anonymous lifetime `'_`
308+
} but calling `{$ident}` introduces an implicit `'static` lifetime requirement
309+
310+
infer_ril_introduced_here = `'static` requirement introduced here
311+
infer_ril_introduced_by = requirement introduced by this return type
312+
infer_ril_because_of = because of this returned expression
313+
infer_ril_static_introduced_by = "`'static` lifetime requirement introduced by the return type

‎compiler/rustc_infer/src/errors/mod.rs

Lines changed: 416 additions & 5 deletions
Large diffs are not rendered by default.

‎compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ mod different_lifetimes;
99
pub mod find_anon_type;
1010
mod mismatched_static_lifetime;
1111
mod named_anon_conflict;
12-
mod placeholder_error;
12+
pub(crate) mod placeholder_error;
1313
mod placeholder_relation;
1414
mod static_impl_trait;
1515
mod trait_impl_difference;

‎compiler/rustc_infer/src/infer/error_reporting/nice_region_error/named_anon_conflict.rs

Lines changed: 16 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
11
//! Error Reporting for Anonymous Region Lifetime Errors
22
//! where one region is named and the other is anonymous.
3-
use crate::infer::error_reporting::nice_region_error::find_anon_type::find_anon_type;
43
use crate::infer::error_reporting::nice_region_error::NiceRegionError;
5-
use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, ErrorGuaranteed};
4+
use crate::{
5+
errors::ExplicitLifetimeRequired,
6+
infer::error_reporting::nice_region_error::find_anon_type::find_anon_type,
7+
};
8+
use rustc_errors::{DiagnosticBuilder, ErrorGuaranteed};
69
use rustc_middle::ty;
710
use rustc_span::symbol::kw;
811

@@ -86,31 +89,17 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
8689
{
8790
return None;
8891
}
89-
90-
let (error_var, span_label_var) = match param.pat.simple_ident() {
91-
Some(simple_ident) => (
92-
format!("the type of `{}`", simple_ident),
93-
format!("the type of `{}`", simple_ident),
94-
),
95-
None => ("parameter type".to_owned(), "type".to_owned()),
92+
let named = named.to_string();
93+
let err = match param.pat.simple_ident() {
94+
Some(simple_ident) => ExplicitLifetimeRequired::WithIdent {
95+
span,
96+
simple_ident,
97+
named,
98+
new_ty_span,
99+
new_ty,
100+
},
101+
None => ExplicitLifetimeRequired::WithParamType { span, named, new_ty_span, new_ty },
96102
};
97-
98-
let mut diag = struct_span_err!(
99-
self.tcx().sess,
100-
span,
101-
E0621,
102-
"explicit lifetime required in {}",
103-
error_var
104-
);
105-
106-
diag.span_label(span, format!("lifetime `{}` required", named));
107-
diag.span_suggestion(
108-
new_ty_span,
109-
&format!("add explicit lifetime `{}` to {}", named, span_label_var),
110-
new_ty,
111-
Applicability::Unspecified,
112-
);
113-
114-
Some(diag)
103+
Some(self.tcx().sess.parse_sess.create_err(err))
115104
}
116105
}

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

Lines changed: 155 additions & 156 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,58 @@
1+
use crate::errors::{
2+
ActualImplExpectedKind, ActualImplExpectedLifetimeKind, ActualImplExplNotes,
3+
TraitPlaceholderMismatch, TyOrSig,
4+
};
15
use crate::infer::error_reporting::nice_region_error::NiceRegionError;
26
use crate::infer::lexical_region_resolve::RegionResolutionError;
37
use crate::infer::ValuePairs;
48
use crate::infer::{SubregionOrigin, TypeTrace};
59
use crate::traits::{ObligationCause, ObligationCauseCode};
610
use rustc_data_structures::intern::Interned;
7-
use rustc_errors::{Diagnostic, DiagnosticBuilder, ErrorGuaranteed};
11+
use rustc_errors::{DiagnosticBuilder, ErrorGuaranteed, IntoDiagnosticArg};
812
use rustc_hir::def::Namespace;
913
use rustc_hir::def_id::DefId;
1014
use rustc_middle::ty::error::ExpectedFound;
1115
use rustc_middle::ty::print::{FmtPrinter, Print, RegionHighlightMode};
1216
use rustc_middle::ty::subst::SubstsRef;
1317
use rustc_middle::ty::{self, RePlaceholder, ReVar, Region, TyCtxt};
1418

15-
use std::fmt::{self, Write};
19+
use std::fmt;
20+
21+
// HACK(eddyb) maybe move this in a more central location.
22+
#[derive(Copy, Clone)]
23+
pub struct Highlighted<'tcx, T> {
24+
tcx: TyCtxt<'tcx>,
25+
highlight: RegionHighlightMode<'tcx>,
26+
value: T,
27+
}
28+
29+
impl<'tcx, T> IntoDiagnosticArg for Highlighted<'tcx, T>
30+
where
31+
T: for<'a> Print<'tcx, FmtPrinter<'a, 'tcx>, Error = fmt::Error, Output = FmtPrinter<'a, 'tcx>>,
32+
{
33+
fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue<'static> {
34+
rustc_errors::DiagnosticArgValue::Str(self.to_string().into())
35+
}
36+
}
37+
38+
impl<'tcx, T> Highlighted<'tcx, T> {
39+
fn map<U>(self, f: impl FnOnce(T) -> U) -> Highlighted<'tcx, U> {
40+
Highlighted { tcx: self.tcx, highlight: self.highlight, value: f(self.value) }
41+
}
42+
}
43+
44+
impl<'tcx, T> fmt::Display for Highlighted<'tcx, T>
45+
where
46+
T: for<'a> Print<'tcx, FmtPrinter<'a, 'tcx>, Error = fmt::Error, Output = FmtPrinter<'a, 'tcx>>,
47+
{
48+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
49+
let mut printer = ty::print::FmtPrinter::new(self.tcx, Namespace::TypeNS);
50+
printer.region_highlight_mode = self.highlight;
51+
52+
let s = self.value.print(printer)?.into_buffer();
53+
f.write_str(&s)
54+
}
55+
}
1656

1757
impl<'tcx> NiceRegionError<'_, 'tcx> {
1858
/// When given a `ConcreteFailure` for a function with arguments containing a named region and
@@ -205,26 +245,21 @@ impl<'tcx> NiceRegionError<'_, 'tcx> {
205245
actual_substs: SubstsRef<'tcx>,
206246
) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
207247
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);
213-
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-
};
248+
249+
let (leading_ellipsis, satisfy_span, where_span, dup_span, def_id) =
250+
if let ObligationCauseCode::ItemObligation(def_id)
251+
| ObligationCauseCode::ExprItemObligation(def_id, ..) = *cause.code()
252+
{
253+
(
254+
true,
255+
Some(span),
256+
Some(self.tcx().def_span(def_id)),
257+
None,
258+
self.tcx().def_path_str(def_id),
259+
)
260+
} else {
261+
(false, None, None, Some(span), String::new())
262+
};
228263

229264
let expected_trait_ref = self
230265
.cx
@@ -284,8 +319,7 @@ impl<'tcx> NiceRegionError<'_, 'tcx> {
284319
?expected_self_ty_has_vid,
285320
);
286321

287-
self.explain_actual_impl_that_was_found(
288-
&mut err,
322+
let actual_impl_expl_notes = self.explain_actual_impl_that_was_found(
289323
sub_placeholder,
290324
sup_placeholder,
291325
has_sub,
@@ -299,7 +333,15 @@ impl<'tcx> NiceRegionError<'_, 'tcx> {
299333
leading_ellipsis,
300334
);
301335

302-
err
336+
self.tcx().sess.create_err(TraitPlaceholderMismatch {
337+
span,
338+
satisfy_span,
339+
where_span,
340+
dup_span,
341+
def_id,
342+
trait_def_id: self.tcx().def_path_str(trait_def_id),
343+
actual_impl_expl_notes,
344+
})
303345
}
304346

305347
/// Add notes with details about the expected and actual trait refs, with attention to cases
@@ -309,7 +351,6 @@ impl<'tcx> NiceRegionError<'_, 'tcx> {
309351
/// due to the number of combinations we have to deal with.
310352
fn explain_actual_impl_that_was_found(
311353
&self,
312-
err: &mut Diagnostic,
313354
sub_placeholder: Option<Region<'tcx>>,
314355
sup_placeholder: Option<Region<'tcx>>,
315356
has_sub: Option<usize>,
@@ -321,39 +362,7 @@ impl<'tcx> NiceRegionError<'_, 'tcx> {
321362
actual_has_vid: Option<usize>,
322363
any_self_ty_has_vid: bool,
323364
leading_ellipsis: bool,
324-
) {
325-
// HACK(eddyb) maybe move this in a more central location.
326-
#[derive(Copy, Clone)]
327-
struct Highlighted<'tcx, T> {
328-
tcx: TyCtxt<'tcx>,
329-
highlight: RegionHighlightMode<'tcx>,
330-
value: T,
331-
}
332-
333-
impl<'tcx, T> Highlighted<'tcx, T> {
334-
fn map<U>(self, f: impl FnOnce(T) -> U) -> Highlighted<'tcx, U> {
335-
Highlighted { tcx: self.tcx, highlight: self.highlight, value: f(self.value) }
336-
}
337-
}
338-
339-
impl<'tcx, T> fmt::Display for Highlighted<'tcx, T>
340-
where
341-
T: for<'a> Print<
342-
'tcx,
343-
FmtPrinter<'a, 'tcx>,
344-
Error = fmt::Error,
345-
Output = FmtPrinter<'a, 'tcx>,
346-
>,
347-
{
348-
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
349-
let mut printer = ty::print::FmtPrinter::new(self.tcx, Namespace::TypeNS);
350-
printer.region_highlight_mode = self.highlight;
351-
352-
let s = self.value.print(printer)?.into_buffer();
353-
f.write_str(&s)
354-
}
355-
}
356-
365+
) -> Vec<ActualImplExplNotes<'tcx>> {
357366
// The weird thing here with the `maybe_highlighting_region` calls and the
358367
// the match inside is meant to be like this:
359368
//
@@ -380,120 +389,110 @@ impl<'tcx> NiceRegionError<'_, 'tcx> {
380389
let mut expected_trait_ref = highlight_trait_ref(expected_trait_ref);
381390
expected_trait_ref.highlight.maybe_highlighting_region(sub_placeholder, has_sub);
382391
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-
};
394392

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-
)
393+
let passive_voice = match (has_sub, has_sup) {
394+
(Some(_), _) | (_, Some(_)) => any_self_ty_has_vid,
395+
(None, None) => {
396+
expected_trait_ref.highlight.maybe_highlighting_region(vid, expected_has_vid);
397+
match expected_has_vid {
398+
Some(_) => true,
399+
None => any_self_ty_has_vid,
426400
}
427-
} else if passive_voice {
428-
format!(
429-
"{}`{}` would have to be implemented for the type `{}`",
430-
if leading_ellipsis { "..." } else { "" },
401+
}
402+
};
403+
404+
let (kind, ty_or_sig, trait_path) = if same_self_type {
405+
let mut self_ty = expected_trait_ref.map(|tr| tr.self_ty());
406+
self_ty.highlight.maybe_highlighting_region(vid, actual_has_vid);
407+
408+
if self_ty.value.is_closure() && self.tcx().is_fn_trait(expected_trait_ref.value.def_id)
409+
{
410+
let closure_sig = self_ty.map(|closure| {
411+
if let ty::Closure(_, substs) = closure.kind() {
412+
self.tcx().signature_unclosure(
413+
substs.as_closure().sig(),
414+
rustc_hir::Unsafety::Normal,
415+
)
416+
} else {
417+
bug!("type is not longer closure");
418+
}
419+
});
420+
(
421+
ActualImplExpectedKind::Signature,
422+
TyOrSig::ClosureSig(closure_sig),
431423
expected_trait_ref.map(|tr| tr.print_only_trait_path()),
432-
expected_trait_ref.map(|tr| tr.self_ty()),
433424
)
434425
} else {
435-
format!(
436-
"{}`{}` must implement `{}`",
437-
if leading_ellipsis { "..." } else { "" },
438-
expected_trait_ref.map(|tr| tr.self_ty()),
426+
(
427+
ActualImplExpectedKind::Other,
428+
TyOrSig::Ty(self_ty),
439429
expected_trait_ref.map(|tr| tr.print_only_trait_path()),
440430
)
441-
};
431+
}
432+
} else if passive_voice {
433+
(
434+
ActualImplExpectedKind::Passive,
435+
TyOrSig::Ty(expected_trait_ref.map(|tr| tr.self_ty())),
436+
expected_trait_ref.map(|tr| tr.print_only_trait_path()),
437+
)
438+
} else {
439+
(
440+
ActualImplExpectedKind::Other,
441+
TyOrSig::Ty(expected_trait_ref.map(|tr| tr.self_ty())),
442+
expected_trait_ref.map(|tr| tr.print_only_trait_path()),
443+
)
444+
};
442445

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-
}
446+
let (lt_kind, lifetime_1, lifetime_2) = match (has_sub, has_sup) {
447+
(Some(n1), Some(n2)) => {
448+
(ActualImplExpectedLifetimeKind::Two, std::cmp::min(n1, n2), std::cmp::max(n1, n2))
449+
}
450+
(Some(n), _) | (_, Some(n)) => (ActualImplExpectedLifetimeKind::Any, n, 0),
451+
(None, None) => {
452+
if let Some(n) = expected_has_vid {
453+
(ActualImplExpectedLifetimeKind::Some, n, 0)
454+
} else {
455+
(ActualImplExpectedLifetimeKind::Nothing, 0, 0)
459456
}
460457
}
458+
};
461459

462-
note
463-
});
460+
let note_1 = ActualImplExplNotes::new_expected(
461+
kind,
462+
lt_kind,
463+
leading_ellipsis,
464+
ty_or_sig,
465+
trait_path,
466+
lifetime_1,
467+
lifetime_2,
468+
);
464469

465470
let mut actual_trait_ref = highlight_trait_ref(actual_trait_ref);
466471
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-
};
472472

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-
};
473+
let passive_voice = match actual_has_vid {
474+
Some(_) => any_self_ty_has_vid,
475+
None => true,
476+
};
491477

492-
if let Some(n) = actual_has_vid {
493-
let _ = write!(note, ", for some specific lifetime `'{}`", n);
478+
let trait_path = actual_trait_ref.map(|tr| tr.print_only_trait_path());
479+
let ty = actual_trait_ref.map(|tr| tr.self_ty()).to_string();
480+
let has_lifetime = actual_has_vid.is_some();
481+
let lifetime = actual_has_vid.unwrap_or_default();
482+
483+
let note_2 = if same_self_type {
484+
ActualImplExplNotes::ButActuallyImplementsTrait { trait_path, has_lifetime, lifetime }
485+
} else if passive_voice {
486+
ActualImplExplNotes::ButActuallyImplementedForTy {
487+
trait_path,
488+
ty,
489+
has_lifetime,
490+
lifetime,
494491
}
492+
} else {
493+
ActualImplExplNotes::ButActuallyTyImplements { trait_path, ty, has_lifetime, lifetime }
494+
};
495495

496-
note
497-
});
496+
vec![note_1, note_2]
498497
}
499498
}

‎compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs

Lines changed: 70 additions & 110 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,15 @@
11
//! Error Reporting for static impl Traits.
22
3+
use crate::errors::{
4+
ButCallingIntroduces, ButNeedsToSatisfy, DynTraitConstraintSuggestion, MoreTargeted,
5+
ReqIntroducedLocations,
6+
};
37
use crate::infer::error_reporting::nice_region_error::NiceRegionError;
48
use crate::infer::lexical_region_resolve::RegionResolutionError;
59
use crate::infer::{SubregionOrigin, TypeTrace};
610
use crate::traits::{ObligationCauseCode, UnifyReceiverContext};
711
use rustc_data_structures::fx::FxIndexSet;
8-
use rustc_errors::{struct_span_err, Applicability, Diagnostic, ErrorGuaranteed, MultiSpan};
12+
use rustc_errors::{AddToDiagnostic, Applicability, Diagnostic, ErrorGuaranteed, MultiSpan};
913
use rustc_hir::def_id::DefId;
1014
use rustc_hir::intravisit::{walk_ty, Visitor};
1115
use rustc_hir::{
@@ -53,46 +57,32 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
5357
}
5458

5559
let param = self.find_param_with_region(*sup_r, *sub_r)?;
56-
let lifetime = if sup_r.has_name() {
57-
format!("lifetime `{}`", sup_r)
58-
} else {
59-
"an anonymous lifetime `'_`".to_string()
60+
let simple_ident = param.param.pat.simple_ident();
61+
62+
let (has_impl_path, impl_path) = match ctxt.assoc_item.container {
63+
AssocItemContainer::TraitContainer => {
64+
let id = ctxt.assoc_item.container_id(tcx);
65+
(true, tcx.def_path_str(id))
66+
}
67+
AssocItemContainer::ImplContainer => (false, String::new()),
6068
};
61-
let mut err = struct_span_err!(
62-
tcx.sess,
63-
cause.span,
64-
E0772,
65-
"{} has {} but calling `{}` introduces an implicit `'static` lifetime \
66-
requirement",
67-
param
68-
.param
69-
.pat
70-
.simple_ident()
71-
.map(|s| format!("`{}`", s))
72-
.unwrap_or_else(|| "`fn` parameter".to_string()),
73-
lifetime,
74-
ctxt.assoc_item.name,
75-
);
76-
err.span_label(param.param_ty_span, &format!("this data with {}...", lifetime));
77-
err.span_label(
78-
cause.span,
79-
&format!(
80-
"...is used and required to live as long as `'static` here \
81-
because of an implicit lifetime bound on the {}",
82-
match ctxt.assoc_item.container {
83-
AssocItemContainer::TraitContainer => {
84-
let id = ctxt.assoc_item.container_id(tcx);
85-
format!("`impl` of `{}`", tcx.def_path_str(id))
86-
}
87-
AssocItemContainer::ImplContainer => "inherent `impl`".to_string(),
88-
},
89-
),
90-
);
69+
70+
let mut err = self.tcx().sess.create_err(ButCallingIntroduces {
71+
param_ty_span: param.param_ty_span,
72+
cause_span: cause.span,
73+
has_param_name: simple_ident.is_some(),
74+
param_name: simple_ident.map(|x| x.to_string()).unwrap_or_default(),
75+
has_lifetime: sup_r.has_name(),
76+
lifetime: sup_r.to_string(),
77+
assoc_item: ctxt.assoc_item.name,
78+
has_impl_path,
79+
impl_path,
80+
});
9181
if self.find_impl_on_dyn_trait(&mut err, param.param_ty, &ctxt) {
9282
let reported = err.emit();
9383
return Some(reported);
9484
} else {
95-
err.cancel();
85+
err.cancel()
9686
}
9787
}
9888
return None;
@@ -108,25 +98,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
10898
let sp = var_origin.span();
10999
let return_sp = sub_origin.span();
110100
let param = self.find_param_with_region(*sup_r, *sub_r)?;
111-
let (lifetime_name, lifetime) = if sup_r.has_name() {
112-
(sup_r.to_string(), format!("lifetime `{}`", sup_r))
113-
} else {
114-
("'_".to_owned(), "an anonymous lifetime `'_`".to_string())
115-
};
116-
let param_name = param
117-
.param
118-
.pat
119-
.simple_ident()
120-
.map(|s| format!("`{}`", s))
121-
.unwrap_or_else(|| "`fn` parameter".to_string());
122-
let mut err = struct_span_err!(
123-
tcx.sess,
124-
sp,
125-
E0759,
126-
"{} has {} but it needs to satisfy a `'static` lifetime requirement",
127-
param_name,
128-
lifetime,
129-
);
101+
let lifetime_name = if sup_r.has_name() { sup_r.to_string() } else { "'_".to_owned() };
130102

131103
let (mention_influencer, influencer_point) =
132104
if sup_origin.span().overlaps(param.param_ty_span) {
@@ -145,7 +117,6 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
145117
} else {
146118
(!sup_origin.span().overlaps(return_sp), param.param_ty_span)
147119
};
148-
err.span_label(influencer_point, &format!("this data with {}...", lifetime));
149120

150121
debug!("try_report_static_impl_trait: param_info={:?}", param);
151122

@@ -159,65 +130,70 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
159130
spans.dedup_by_key(|span| (span.lo(), span.hi()));
160131

161132
// We try to make the output have fewer overlapping spans if possible.
162-
let require_msg = if spans.is_empty() {
163-
"...is used and required to live as long as `'static` here"
164-
} else {
165-
"...and is required to live as long as `'static` here"
166-
};
167133
let require_span =
168134
if sup_origin.span().overlaps(return_sp) { sup_origin.span() } else { return_sp };
169135

170-
for span in &spans {
171-
err.span_label(*span, "...is used here...");
172-
}
173-
174-
if spans.iter().any(|sp| sp.overlaps(return_sp) || *sp > return_sp) {
175-
// If any of the "captured here" labels appears on the same line or after
176-
// `require_span`, we put it on a note to ensure the text flows by appearing
177-
// always at the end.
178-
err.span_note(require_span, require_msg);
136+
let spans_empty = spans.is_empty();
137+
let require_as_note = spans.iter().any(|sp| sp.overlaps(return_sp) || *sp > return_sp);
138+
let bound = if let SubregionOrigin::RelateParamBound(_, _, Some(bound)) = sub_origin {
139+
Some(*bound)
179140
} else {
180-
// We don't need a note, it's already at the end, it can be shown as a `span_label`.
181-
err.span_label(require_span, require_msg);
182-
}
141+
None
142+
};
143+
144+
let mut subdiag = None;
183145

184-
if let SubregionOrigin::RelateParamBound(_, _, Some(bound)) = sub_origin {
185-
err.span_note(*bound, "`'static` lifetime requirement introduced by this bound");
186-
}
187146
if let SubregionOrigin::Subtype(box TypeTrace { cause, .. }) = sub_origin {
188147
if let ObligationCauseCode::ReturnValue(hir_id)
189148
| ObligationCauseCode::BlockTailExpression(hir_id) = cause.code()
190149
{
191150
let parent_id = tcx.hir().get_parent_item(*hir_id);
192151
if let Some(fn_decl) = tcx.hir().fn_decl_by_hir_id(parent_id.into()) {
193152
let mut span: MultiSpan = fn_decl.output.span().into();
153+
let mut spans = Vec::new();
194154
let mut add_label = true;
195155
if let hir::FnRetTy::Return(ty) = fn_decl.output {
196156
let mut v = StaticLifetimeVisitor(vec![], tcx.hir());
197157
v.visit_ty(ty);
198158
if !v.0.is_empty() {
199159
span = v.0.clone().into();
200-
for sp in v.0 {
201-
span.push_span_label(sp, "`'static` requirement introduced here");
202-
}
160+
spans = v.0;
203161
add_label = false;
204162
}
205163
}
206-
if add_label {
207-
span.push_span_label(
208-
fn_decl.output.span(),
209-
"requirement introduced by this return type",
210-
);
211-
}
212-
span.push_span_label(cause.span, "because of this returned expression");
213-
err.span_note(
164+
let fn_decl_span = fn_decl.output.span();
165+
166+
subdiag = Some(ReqIntroducedLocations {
214167
span,
215-
"`'static` lifetime requirement introduced by the return type",
216-
);
168+
spans,
169+
fn_decl_span,
170+
cause_span: cause.span,
171+
add_label,
172+
});
217173
}
218174
}
219175
}
220176

177+
let diag = ButNeedsToSatisfy {
178+
sp,
179+
influencer_point,
180+
spans: spans.clone(),
181+
// If any of the "captured here" labels appears on the same line or after
182+
// `require_span`, we put it on a note to ensure the text flows by appearing
183+
// always at the end.
184+
require_span_as_note: require_as_note.then_some(require_span),
185+
// We don't need a note, it's already at the end, it can be shown as a `span_label`.
186+
require_span_as_label: (!require_as_note).then_some(require_span),
187+
req_introduces_loc: subdiag,
188+
189+
has_lifetime: sup_r.has_name(),
190+
lifetime: sup_r.to_string(),
191+
spans_empty,
192+
bound,
193+
};
194+
195+
let mut err = self.tcx().sess.create_err(diag);
196+
221197
let fn_returns = tcx.return_type_impl_or_dyn_traits(anon_reg_sup.def_id);
222198

223199
let mut override_error_code = None;
@@ -251,12 +227,8 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
251227
}
252228
if let (Some(ident), true) = (override_error_code, fn_returns.is_empty()) {
253229
// Provide a more targeted error code and description.
254-
err.code(rustc_errors::error_code!(E0772));
255-
err.set_primary_message(&format!(
256-
"{} has {} but calling `{}` introduces an implicit `'static` lifetime \
257-
requirement",
258-
param_name, lifetime, ident,
259-
));
230+
let retarget_subdiag = MoreTargeted { ident };
231+
retarget_subdiag.add_to_diagnostic(&mut err);
260232
}
261233

262234
let arg = match param.param.pat.simple_ident() {
@@ -551,21 +523,9 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
551523
let mut traits = vec![];
552524
let mut hir_v = HirTraitObjectVisitor(&mut traits, *found_did);
553525
hir_v.visit_ty(&self_ty);
554-
for span in &traits {
555-
let mut multi_span: MultiSpan = vec![*span].into();
556-
multi_span
557-
.push_span_label(*span, "this has an implicit `'static` lifetime requirement");
558-
multi_span.push_span_label(
559-
ident.span,
560-
"calling this method introduces the `impl`'s 'static` requirement",
561-
);
562-
err.span_note(multi_span, "the used `impl` has a `'static` requirement");
563-
err.span_suggestion_verbose(
564-
span.shrink_to_hi(),
565-
"consider relaxing the implicit `'static` requirement",
566-
" + '_",
567-
Applicability::MaybeIncorrect,
568-
);
526+
for &span in &traits {
527+
let subdiag = DynTraitConstraintSuggestion { span, ident };
528+
subdiag.add_to_diagnostic(err);
569529
suggested = true;
570530
}
571531
}

‎compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs

Lines changed: 13 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
//! Error Reporting for `impl` items that do not match the obligations from their `trait`.
22
3+
use crate::errors::{ConsiderBorrowingParamHelp, RelationshipHelp, TraitImplDiff};
34
use crate::infer::error_reporting::nice_region_error::NiceRegionError;
45
use crate::infer::lexical_region_resolve::RegionResolutionError;
56
use crate::infer::Subtype;
67
use crate::traits::ObligationCauseCode::CompareImplItemObligation;
7-
use rustc_errors::{ErrorGuaranteed, MultiSpan};
8+
use rustc_errors::ErrorGuaranteed;
89
use rustc_hir as hir;
910
use rustc_hir::def::Res;
1011
use rustc_hir::def_id::DefId;
@@ -51,10 +52,6 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
5152
trait_def_id: DefId,
5253
) -> ErrorGuaranteed {
5354
let trait_sp = self.tcx().def_span(trait_def_id);
54-
let mut err = self
55-
.tcx()
56-
.sess
57-
.struct_span_err(sp, "`impl` item signature doesn't match `trait` item signature");
5855

5956
// Mark all unnamed regions in the type with a number.
6057
// This diagnostic is called in response to lifetime errors, so be informative.
@@ -91,9 +88,6 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
9188
let found =
9289
self.cx.extract_inference_diagnostics_data(found.into(), Some(found_highlight)).name;
9390

94-
err.span_label(sp, &format!("found `{}`", found));
95-
err.span_label(trait_sp, &format!("expected `{}`", expected));
96-
9791
// Get the span of all the used type parameters in the method.
9892
let assoc_item = self.tcx().associated_item(trait_def_id);
9993
let mut visitor = TypeParamSpanVisitor { tcx: self.tcx(), types: vec![] };
@@ -110,26 +104,18 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
110104
}
111105
_ => {}
112106
}
113-
let mut type_param_span: MultiSpan = visitor.types.to_vec().into();
114-
for &span in &visitor.types {
115-
type_param_span
116-
.push_span_label(span, "consider borrowing this type parameter in the trait");
117-
}
118107

119-
err.note(&format!("expected `{}`\n found `{}`", expected, found));
120-
121-
err.span_help(
122-
type_param_span,
123-
"the lifetime requirements from the `impl` do not correspond to the requirements in \
124-
the `trait`",
125-
);
126-
if visitor.types.is_empty() {
127-
err.help(
128-
"verify the lifetime relationships in the `trait` and `impl` between the `self` \
129-
argument, the other inputs and its output",
130-
);
131-
}
132-
err.emit()
108+
let diag = TraitImplDiff {
109+
sp,
110+
trait_sp,
111+
note: (),
112+
param_help: ConsiderBorrowingParamHelp { spans: visitor.types.to_vec() },
113+
rel_help: visitor.types.is_empty().then_some(RelationshipHelp),
114+
expected,
115+
found,
116+
};
117+
118+
self.tcx().sess.emit_err(diag)
133119
}
134120
}
135121

0 commit comments

Comments
 (0)
Please sign in to comment.