Skip to content

Commit af3343a

Browse files
committed
Migrate E0623
1 parent 3c72788 commit af3343a

File tree

4 files changed

+234
-121
lines changed

4 files changed

+234
-121
lines changed

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

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -104,9 +104,36 @@ infer_relate_object_bound = ...so that it can be closed over into an object
104104
infer_data_borrowed = ...so that the type `{$name}` is not borrowed for too long
105105
infer_reference_outlives_referent = ...so that the reference type `{$name}` does not outlive the data it points at
106106
infer_relate_param_bound = ...so that the type `{$name}` will meet its required lifetime bounds{$continues ->
107-
[true] ...
108-
*[false] {""}
107+
[true] ...
108+
*[false] {""}
109109
}
110110
infer_relate_param_bound_2 = ...that is required by this bound
111111
infer_relate_region_param_bound = ...so that the declared lifetime parameter bounds are satisfied
112112
infer_compare_impl_item_obligation = ...so that the definition in impl matches the definition from the trait
113+
114+
infer_nothing = {""}
115+
116+
infer_lifetime_mismatch = lifetime mismatch
117+
118+
infer_declared_different = this parameter and the return type are declared with different lifetimes...
119+
infer_data_returned = ...but data{$label_var1_exists ->
120+
[true] {" "}from `{$label_var1}`
121+
*[false] {""}
122+
} is returned here
123+
124+
infer_data_lifetime_flow = ...but data with one lifetime flows into the other here
125+
infer_declared_multiple = this type is declared with multiple lifetimes...
126+
infer_types_declared_different = these two types are declared with different lifetimes...
127+
infer_data_flows = ...but data{$label_var1_exists ->
128+
[true] -> {" "}from `{$label_var1}`
129+
*[false] -> {""}
130+
} flows{$label_var2_exists ->
131+
[true] -> {" "}into `{$label_var2}`
132+
*[false] -> {""}
133+
} here
134+
135+
infer_lifetime_param_suggestion = consider introducing a named lifetime parameter{$is_impl ->
136+
[true] {" "}and update trait if needed
137+
*[false] {""}
138+
}
139+
infer_lifetime_param_suggestion_elided = each elided lifetime in input position becomes a distinct lifetime

compiler/rustc_infer/src/errors.rs

Lines changed: 170 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,13 @@
1-
use rustc_errors::{fluent, AddSubdiagnostic, DiagnosticMessage, DiagnosticStyledString};
2-
use rustc_hir::FnRetTy;
1+
use hir::GenericParamKind;
2+
use rustc_errors::{
3+
fluent, AddSubdiagnostic, Applicability, DiagnosticMessage, DiagnosticStyledString,
4+
};
5+
use rustc_hir as hir;
6+
use rustc_hir::{FnRetTy, Ty};
37
use rustc_macros::SessionDiagnostic;
4-
use rustc_span::{BytePos, Span};
8+
use rustc_middle::ty::{Region, TyCtxt};
9+
use rustc_span::symbol::kw;
10+
use rustc_span::{symbol::Ident, BytePos, Span};
511

612
use crate::infer::error_reporting::{
713
need_type_info::{GeneratorKindAsDiagArg, UnderspecifiedArgKind},
@@ -252,3 +258,164 @@ impl AddSubdiagnostic for RegionOriginNote<'_> {
252258
};
253259
}
254260
}
261+
262+
pub enum LifetimeMismatchLabels {
263+
InRet {
264+
param_span: Span,
265+
ret_span: Span,
266+
span: Span,
267+
label_var1: Option<Ident>,
268+
},
269+
Normal {
270+
hir_equal: bool,
271+
ty_sup: Span,
272+
ty_sub: Span,
273+
span: Span,
274+
label_var1: Option<Ident>,
275+
label_var2: Option<Ident>,
276+
},
277+
}
278+
279+
impl AddSubdiagnostic for LifetimeMismatchLabels {
280+
fn add_to_diagnostic(self, diag: &mut rustc_errors::Diagnostic) {
281+
match self {
282+
LifetimeMismatchLabels::InRet { param_span, ret_span, span, label_var1 } => {
283+
diag.span_label(param_span, fluent::infer::declared_different);
284+
diag.span_label(ret_span, fluent::infer::nothing);
285+
diag.span_label(span, fluent::infer::data_returned);
286+
diag.set_arg("label_var1_exists", label_var1.is_some());
287+
diag.set_arg("label_var1", label_var1.map(|x| x.to_string()).unwrap_or_default());
288+
}
289+
LifetimeMismatchLabels::Normal {
290+
hir_equal,
291+
ty_sup,
292+
ty_sub,
293+
span,
294+
label_var1,
295+
label_var2,
296+
} => {
297+
if hir_equal {
298+
diag.span_label(ty_sup, fluent::infer::declared_multiple);
299+
diag.span_label(ty_sub, fluent::infer::nothing);
300+
diag.span_label(span, fluent::infer::data_lifetime_flow);
301+
} else {
302+
diag.span_label(ty_sup, fluent::infer::types_declared_different);
303+
diag.span_label(ty_sub, fluent::infer::nothing);
304+
diag.span_label(span, fluent::infer::data_flows);
305+
diag.set_arg("label_var1_exists", label_var1.is_some());
306+
diag.set_arg(
307+
"label_var1",
308+
label_var1.map(|x| x.to_string()).unwrap_or_default(),
309+
);
310+
diag.set_arg("label_var2_exists", label_var2.is_some());
311+
diag.set_arg(
312+
"label_var2",
313+
label_var2.map(|x| x.to_string()).unwrap_or_default(),
314+
);
315+
}
316+
}
317+
}
318+
}
319+
}
320+
321+
pub struct AddLifetimeParamsSuggestion<'a> {
322+
pub tcx: TyCtxt<'a>,
323+
pub sub: Region<'a>,
324+
pub ty_sup: &'a Ty<'a>,
325+
pub ty_sub: &'a Ty<'a>,
326+
pub add_note: bool,
327+
}
328+
329+
impl AddSubdiagnostic for AddLifetimeParamsSuggestion<'_> {
330+
fn add_to_diagnostic(self, diag: &mut rustc_errors::Diagnostic) {
331+
let mut mk_suggestion = || {
332+
let (
333+
hir::Ty { kind: hir::TyKind::Rptr(lifetime_sub, _), .. },
334+
hir::Ty { kind: hir::TyKind::Rptr(lifetime_sup, _), .. },
335+
) = (self.ty_sub, self.ty_sup) else {
336+
return false;
337+
};
338+
339+
if !lifetime_sub.name.is_anonymous() || !lifetime_sup.name.is_anonymous() {
340+
return false;
341+
};
342+
343+
let Some(anon_reg) = self.tcx.is_suitable_region(self.sub) else {
344+
return false;
345+
};
346+
347+
let hir_id = self.tcx.hir().local_def_id_to_hir_id(anon_reg.def_id);
348+
349+
let node = self.tcx.hir().get(hir_id);
350+
let is_impl = matches!(&node, hir::Node::ImplItem(_));
351+
let generics = match node {
352+
hir::Node::Item(&hir::Item {
353+
kind: hir::ItemKind::Fn(_, ref generics, ..),
354+
..
355+
})
356+
| hir::Node::TraitItem(&hir::TraitItem { ref generics, .. })
357+
| hir::Node::ImplItem(&hir::ImplItem { ref generics, .. }) => generics,
358+
_ => return false,
359+
};
360+
361+
let suggestion_param_name = generics
362+
.params
363+
.iter()
364+
.filter(|p| matches!(p.kind, GenericParamKind::Lifetime { .. }))
365+
.map(|p| p.name.ident().name)
366+
.find(|i| *i != kw::UnderscoreLifetime);
367+
let introduce_new = suggestion_param_name.is_none();
368+
let suggestion_param_name =
369+
suggestion_param_name.map(|n| n.to_string()).unwrap_or_else(|| "'a".to_owned());
370+
371+
debug!(?lifetime_sup.span);
372+
debug!(?lifetime_sub.span);
373+
let make_suggestion = |span: rustc_span::Span| {
374+
if span.is_empty() {
375+
(span, format!("{}, ", suggestion_param_name))
376+
} else if let Ok("&") = self.tcx.sess.source_map().span_to_snippet(span).as_deref()
377+
{
378+
(span.shrink_to_hi(), format!("{} ", suggestion_param_name))
379+
} else {
380+
(span, suggestion_param_name.clone())
381+
}
382+
};
383+
let mut suggestions =
384+
vec![make_suggestion(lifetime_sub.span), make_suggestion(lifetime_sup.span)];
385+
386+
if introduce_new {
387+
let new_param_suggestion = if let Some(first) =
388+
generics.params.iter().find(|p| !p.name.ident().span.is_empty())
389+
{
390+
(first.span.shrink_to_lo(), format!("{}, ", suggestion_param_name))
391+
} else {
392+
(generics.span, format!("<{}>", suggestion_param_name))
393+
};
394+
395+
suggestions.push(new_param_suggestion);
396+
}
397+
398+
diag.multipart_suggestion(
399+
fluent::infer::lifetime_param_suggestion,
400+
suggestions,
401+
Applicability::MaybeIncorrect,
402+
);
403+
diag.set_arg("is_impl", is_impl);
404+
true
405+
};
406+
if mk_suggestion() && self.add_note {
407+
diag.note(fluent::infer::lifetime_param_suggestion_elided);
408+
}
409+
}
410+
}
411+
412+
#[derive(SessionDiagnostic)]
413+
#[diag(infer::lifetime_mismatch, code = "E0623")]
414+
pub struct LifetimeMismatch<'a> {
415+
#[primary_span]
416+
pub span: Span,
417+
#[subdiagnostic]
418+
pub labels: LifetimeMismatchLabels,
419+
#[subdiagnostic]
420+
pub suggestion: AddLifetimeParamsSuggestion<'a>,
421+
}

0 commit comments

Comments
 (0)