]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_infer/src/errors/mod.rs
Rollup merge of #103845 - camsteffen:data-structures-track-caller, r=compiler-errors
[rust.git] / compiler / rustc_infer / src / errors / mod.rs
1 use hir::GenericParamKind;
2 use rustc_errors::{
3     fluent, AddToDiagnostic, Applicability, Diagnostic, DiagnosticMessage, DiagnosticStyledString,
4     MultiSpan, SubdiagnosticMessage,
5 };
6 use rustc_hir as hir;
7 use rustc_hir::{FnRetTy, Ty};
8 use rustc_macros::{Diagnostic, Subdiagnostic};
9 use rustc_middle::ty::{Region, TyCtxt};
10 use rustc_span::symbol::kw;
11 use rustc_span::{symbol::Ident, BytePos, Span};
12
13 use crate::infer::error_reporting::{
14     need_type_info::{GeneratorKindAsDiagArg, UnderspecifiedArgKind},
15     ObligationCauseAsDiagArg,
16 };
17
18 pub mod note_and_explain;
19
20 #[derive(Diagnostic)]
21 #[diag(infer_opaque_hidden_type)]
22 pub struct OpaqueHiddenTypeDiag {
23     #[primary_span]
24     #[label]
25     pub span: Span,
26     #[note(opaque_type)]
27     pub opaque_type: Span,
28     #[note(hidden_type)]
29     pub hidden_type: Span,
30 }
31
32 #[derive(Diagnostic)]
33 #[diag(infer_type_annotations_needed, code = "E0282")]
34 pub struct AnnotationRequired<'a> {
35     #[primary_span]
36     pub span: Span,
37     pub source_kind: &'static str,
38     pub source_name: &'a str,
39     #[label]
40     pub failure_span: Option<Span>,
41     #[subdiagnostic]
42     pub bad_label: Option<InferenceBadError<'a>>,
43     #[subdiagnostic]
44     pub infer_subdiags: Vec<SourceKindSubdiag<'a>>,
45     #[subdiagnostic]
46     pub multi_suggestions: Vec<SourceKindMultiSuggestion<'a>>,
47 }
48
49 // Copy of `AnnotationRequired` for E0283
50 #[derive(Diagnostic)]
51 #[diag(infer_type_annotations_needed, code = "E0283")]
52 pub struct AmbigousImpl<'a> {
53     #[primary_span]
54     pub span: Span,
55     pub source_kind: &'static str,
56     pub source_name: &'a str,
57     #[label]
58     pub failure_span: Option<Span>,
59     #[subdiagnostic]
60     pub bad_label: Option<InferenceBadError<'a>>,
61     #[subdiagnostic]
62     pub infer_subdiags: Vec<SourceKindSubdiag<'a>>,
63     #[subdiagnostic]
64     pub multi_suggestions: Vec<SourceKindMultiSuggestion<'a>>,
65 }
66
67 // Copy of `AnnotationRequired` for E0284
68 #[derive(Diagnostic)]
69 #[diag(infer_type_annotations_needed, code = "E0284")]
70 pub struct AmbigousReturn<'a> {
71     #[primary_span]
72     pub span: Span,
73     pub source_kind: &'static str,
74     pub source_name: &'a str,
75     #[label]
76     pub failure_span: Option<Span>,
77     #[subdiagnostic]
78     pub bad_label: Option<InferenceBadError<'a>>,
79     #[subdiagnostic]
80     pub infer_subdiags: Vec<SourceKindSubdiag<'a>>,
81     #[subdiagnostic]
82     pub multi_suggestions: Vec<SourceKindMultiSuggestion<'a>>,
83 }
84
85 #[derive(Diagnostic)]
86 #[diag(infer_need_type_info_in_generator, code = "E0698")]
87 pub struct NeedTypeInfoInGenerator<'a> {
88     #[primary_span]
89     pub span: Span,
90     pub generator_kind: GeneratorKindAsDiagArg,
91     #[subdiagnostic]
92     pub bad_label: InferenceBadError<'a>,
93 }
94
95 // Used when a better one isn't available
96 #[derive(Subdiagnostic)]
97 #[label(infer_label_bad)]
98 pub struct InferenceBadError<'a> {
99     #[primary_span]
100     pub span: Span,
101     pub bad_kind: &'static str,
102     pub prefix_kind: UnderspecifiedArgKind,
103     pub has_parent: bool,
104     pub prefix: &'a str,
105     pub parent_prefix: &'a str,
106     pub parent_name: String,
107     pub name: String,
108 }
109
110 #[derive(Subdiagnostic)]
111 pub enum SourceKindSubdiag<'a> {
112     #[suggestion(
113         infer_source_kind_subdiag_let,
114         style = "verbose",
115         code = ": {type_name}",
116         applicability = "has-placeholders"
117     )]
118     LetLike {
119         #[primary_span]
120         span: Span,
121         name: String,
122         type_name: String,
123         kind: &'static str,
124         x_kind: &'static str,
125         prefix_kind: UnderspecifiedArgKind,
126         prefix: &'a str,
127         arg_name: String,
128     },
129     #[label(infer_source_kind_subdiag_generic_label)]
130     GenericLabel {
131         #[primary_span]
132         span: Span,
133         is_type: bool,
134         param_name: String,
135         parent_exists: bool,
136         parent_prefix: String,
137         parent_name: String,
138     },
139     #[suggestion(
140         infer_source_kind_subdiag_generic_suggestion,
141         style = "verbose",
142         code = "::<{args}>",
143         applicability = "has-placeholders"
144     )]
145     GenericSuggestion {
146         #[primary_span]
147         span: Span,
148         arg_count: usize,
149         args: String,
150     },
151 }
152
153 #[derive(Subdiagnostic)]
154 pub enum SourceKindMultiSuggestion<'a> {
155     #[multipart_suggestion(
156         infer_source_kind_fully_qualified,
157         style = "verbose",
158         applicability = "has-placeholders"
159     )]
160     FullyQualified {
161         #[suggestion_part(code = "{def_path}({adjustment}")]
162         span_lo: Span,
163         #[suggestion_part(code = "{successor_pos}")]
164         span_hi: Span,
165         def_path: String,
166         adjustment: &'a str,
167         successor_pos: &'a str,
168     },
169     #[multipart_suggestion(
170         infer_source_kind_closure_return,
171         style = "verbose",
172         applicability = "has-placeholders"
173     )]
174     ClosureReturn {
175         #[suggestion_part(code = "{start_span_code}")]
176         start_span: Span,
177         start_span_code: String,
178         #[suggestion_part(code = " }}")]
179         end_span: Option<Span>,
180     },
181 }
182
183 impl<'a> SourceKindMultiSuggestion<'a> {
184     pub fn new_fully_qualified(
185         span: Span,
186         def_path: String,
187         adjustment: &'a str,
188         successor: (&'a str, BytePos),
189     ) -> Self {
190         Self::FullyQualified {
191             span_lo: span.shrink_to_lo(),
192             span_hi: span.shrink_to_hi().with_hi(successor.1),
193             def_path,
194             adjustment,
195             successor_pos: successor.0,
196         }
197     }
198
199     pub fn new_closure_return(
200         ty_info: String,
201         data: &'a FnRetTy<'a>,
202         should_wrap_expr: Option<Span>,
203     ) -> Self {
204         let (arrow, post) = match data {
205             FnRetTy::DefaultReturn(_) => ("-> ", " "),
206             _ => ("", ""),
207         };
208         let (start_span, start_span_code, end_span) = match should_wrap_expr {
209             Some(end_span) => {
210                 (data.span(), format!("{}{}{}{{ ", arrow, ty_info, post), Some(end_span))
211             }
212             None => (data.span(), format!("{}{}{}", arrow, ty_info, post), None),
213         };
214         Self::ClosureReturn { start_span, start_span_code, end_span }
215     }
216 }
217
218 pub enum RegionOriginNote<'a> {
219     Plain {
220         span: Span,
221         msg: DiagnosticMessage,
222     },
223     WithName {
224         span: Span,
225         msg: DiagnosticMessage,
226         name: &'a str,
227         continues: bool,
228     },
229     WithRequirement {
230         span: Span,
231         requirement: ObligationCauseAsDiagArg<'a>,
232         expected_found: Option<(DiagnosticStyledString, DiagnosticStyledString)>,
233     },
234 }
235
236 impl AddToDiagnostic for RegionOriginNote<'_> {
237     fn add_to_diagnostic_with<F>(self, diag: &mut Diagnostic, _: F)
238     where
239         F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage,
240     {
241         let mut label_or_note = |span, msg: DiagnosticMessage| {
242             let sub_count = diag.children.iter().filter(|d| d.span.is_dummy()).count();
243             let expanded_sub_count = diag.children.iter().filter(|d| !d.span.is_dummy()).count();
244             let span_is_primary = diag.span.primary_spans().iter().all(|&sp| sp == span);
245             if span_is_primary && sub_count == 0 && expanded_sub_count == 0 {
246                 diag.span_label(span, msg);
247             } else if span_is_primary && expanded_sub_count == 0 {
248                 diag.note(msg);
249             } else {
250                 diag.span_note(span, msg);
251             }
252         };
253         match self {
254             RegionOriginNote::Plain { span, msg } => {
255                 label_or_note(span, msg);
256             }
257             RegionOriginNote::WithName { span, msg, name, continues } => {
258                 label_or_note(span, msg);
259                 diag.set_arg("name", name);
260                 diag.set_arg("continues", continues);
261             }
262             RegionOriginNote::WithRequirement {
263                 span,
264                 requirement,
265                 expected_found: Some((expected, found)),
266             } => {
267                 label_or_note(span, fluent::infer_subtype);
268                 diag.set_arg("requirement", requirement);
269
270                 diag.note_expected_found(&"", expected, &"", found);
271             }
272             RegionOriginNote::WithRequirement { span, requirement, expected_found: None } => {
273                 // FIXME: this really should be handled at some earlier stage. Our
274                 // handling of region checking when type errors are present is
275                 // *terrible*.
276                 label_or_note(span, fluent::infer_subtype_2);
277                 diag.set_arg("requirement", requirement);
278             }
279         };
280     }
281 }
282
283 pub enum LifetimeMismatchLabels {
284     InRet {
285         param_span: Span,
286         ret_span: Span,
287         span: Span,
288         label_var1: Option<Ident>,
289     },
290     Normal {
291         hir_equal: bool,
292         ty_sup: Span,
293         ty_sub: Span,
294         span: Span,
295         sup: Option<Ident>,
296         sub: Option<Ident>,
297     },
298 }
299
300 impl AddToDiagnostic for LifetimeMismatchLabels {
301     fn add_to_diagnostic_with<F>(self, diag: &mut Diagnostic, _: F)
302     where
303         F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage,
304     {
305         match self {
306             LifetimeMismatchLabels::InRet { param_span, ret_span, span, label_var1 } => {
307                 diag.span_label(param_span, fluent::infer_declared_different);
308                 diag.span_label(ret_span, fluent::infer_nothing);
309                 diag.span_label(span, fluent::infer_data_returned);
310                 diag.set_arg("label_var1_exists", label_var1.is_some());
311                 diag.set_arg("label_var1", label_var1.map(|x| x.to_string()).unwrap_or_default());
312             }
313             LifetimeMismatchLabels::Normal {
314                 hir_equal,
315                 ty_sup,
316                 ty_sub,
317                 span,
318                 sup: label_var1,
319                 sub: label_var2,
320             } => {
321                 if hir_equal {
322                     diag.span_label(ty_sup, fluent::infer_declared_multiple);
323                     diag.span_label(ty_sub, fluent::infer_nothing);
324                     diag.span_label(span, fluent::infer_data_lifetime_flow);
325                 } else {
326                     diag.span_label(ty_sup, fluent::infer_types_declared_different);
327                     diag.span_label(ty_sub, fluent::infer_nothing);
328                     diag.span_label(span, fluent::infer_data_flows);
329                     diag.set_arg("label_var1_exists", label_var1.is_some());
330                     diag.set_arg(
331                         "label_var1",
332                         label_var1.map(|x| x.to_string()).unwrap_or_default(),
333                     );
334                     diag.set_arg("label_var2_exists", label_var2.is_some());
335                     diag.set_arg(
336                         "label_var2",
337                         label_var2.map(|x| x.to_string()).unwrap_or_default(),
338                     );
339                 }
340             }
341         }
342     }
343 }
344
345 pub struct AddLifetimeParamsSuggestion<'a> {
346     pub tcx: TyCtxt<'a>,
347     pub sub: Region<'a>,
348     pub ty_sup: &'a Ty<'a>,
349     pub ty_sub: &'a Ty<'a>,
350     pub add_note: bool,
351 }
352
353 impl AddToDiagnostic for AddLifetimeParamsSuggestion<'_> {
354     fn add_to_diagnostic_with<F>(self, diag: &mut Diagnostic, _: F)
355     where
356         F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage,
357     {
358         let mut mk_suggestion = || {
359             let (
360                 hir::Ty { kind: hir::TyKind::Rptr(lifetime_sub, _), .. },
361                 hir::Ty { kind: hir::TyKind::Rptr(lifetime_sup, _), .. },
362             ) = (self.ty_sub, self.ty_sup) else {
363                 return false;
364             };
365
366             if !lifetime_sub.name.is_anonymous() || !lifetime_sup.name.is_anonymous() {
367                 return false;
368             };
369
370             let Some(anon_reg) = self.tcx.is_suitable_region(self.sub) else {
371                 return false;
372             };
373
374             let hir_id = self.tcx.hir().local_def_id_to_hir_id(anon_reg.def_id);
375
376             let node = self.tcx.hir().get(hir_id);
377             let is_impl = matches!(&node, hir::Node::ImplItem(_));
378             let generics = match node {
379                 hir::Node::Item(&hir::Item {
380                     kind: hir::ItemKind::Fn(_, ref generics, ..),
381                     ..
382                 })
383                 | hir::Node::TraitItem(&hir::TraitItem { ref generics, .. })
384                 | hir::Node::ImplItem(&hir::ImplItem { ref generics, .. }) => generics,
385                 _ => return false,
386             };
387
388             let suggestion_param_name = generics
389                 .params
390                 .iter()
391                 .filter(|p| matches!(p.kind, GenericParamKind::Lifetime { .. }))
392                 .map(|p| p.name.ident().name)
393                 .find(|i| *i != kw::UnderscoreLifetime);
394             let introduce_new = suggestion_param_name.is_none();
395             let suggestion_param_name =
396                 suggestion_param_name.map(|n| n.to_string()).unwrap_or_else(|| "'a".to_owned());
397
398             debug!(?lifetime_sup.span);
399             debug!(?lifetime_sub.span);
400             let make_suggestion = |span: rustc_span::Span| {
401                 if span.is_empty() {
402                     (span, format!("{}, ", suggestion_param_name))
403                 } else if let Ok("&") = self.tcx.sess.source_map().span_to_snippet(span).as_deref()
404                 {
405                     (span.shrink_to_hi(), format!("{} ", suggestion_param_name))
406                 } else {
407                     (span, suggestion_param_name.clone())
408                 }
409             };
410             let mut suggestions =
411                 vec![make_suggestion(lifetime_sub.span), make_suggestion(lifetime_sup.span)];
412
413             if introduce_new {
414                 let new_param_suggestion = if let Some(first) =
415                     generics.params.iter().find(|p| !p.name.ident().span.is_empty())
416                 {
417                     (first.span.shrink_to_lo(), format!("{}, ", suggestion_param_name))
418                 } else {
419                     (generics.span, format!("<{}>", suggestion_param_name))
420                 };
421
422                 suggestions.push(new_param_suggestion);
423             }
424
425             diag.multipart_suggestion(
426                 fluent::infer_lifetime_param_suggestion,
427                 suggestions,
428                 Applicability::MaybeIncorrect,
429             );
430             diag.set_arg("is_impl", is_impl);
431             true
432         };
433         if mk_suggestion() && self.add_note {
434             diag.note(fluent::infer_lifetime_param_suggestion_elided);
435         }
436     }
437 }
438
439 #[derive(Diagnostic)]
440 #[diag(infer_lifetime_mismatch, code = "E0623")]
441 pub struct LifetimeMismatch<'a> {
442     #[primary_span]
443     pub span: Span,
444     #[subdiagnostic]
445     pub labels: LifetimeMismatchLabels,
446     #[subdiagnostic]
447     pub suggestion: AddLifetimeParamsSuggestion<'a>,
448 }
449
450 pub struct IntroducesStaticBecauseUnmetLifetimeReq {
451     pub unmet_requirements: MultiSpan,
452     pub binding_span: Span,
453 }
454
455 impl AddToDiagnostic for IntroducesStaticBecauseUnmetLifetimeReq {
456     fn add_to_diagnostic_with<F>(mut self, diag: &mut Diagnostic, _: F)
457     where
458         F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage,
459     {
460         self.unmet_requirements
461             .push_span_label(self.binding_span, fluent::infer_msl_introduces_static);
462         diag.span_note(self.unmet_requirements, fluent::infer_msl_unmet_req);
463     }
464 }
465
466 // FIXME(#100717): replace with a `Option<Span>` when subdiagnostic supports that
467 #[derive(Subdiagnostic)]
468 pub enum DoesNotOutliveStaticFromImpl {
469     #[note(infer_does_not_outlive_static_from_impl)]
470     Spanned {
471         #[primary_span]
472         span: Span,
473     },
474     #[note(infer_does_not_outlive_static_from_impl)]
475     Unspanned,
476 }
477
478 #[derive(Subdiagnostic)]
479 pub enum ImplicitStaticLifetimeSubdiag {
480     #[note(infer_implicit_static_lifetime_note)]
481     Note {
482         #[primary_span]
483         span: Span,
484     },
485     #[suggestion(
486         infer_implicit_static_lifetime_suggestion,
487         style = "verbose",
488         code = " + '_",
489         applicability = "maybe-incorrect"
490     )]
491     Sugg {
492         #[primary_span]
493         span: Span,
494     },
495 }
496
497 #[derive(Diagnostic)]
498 #[diag(infer_mismatched_static_lifetime)]
499 pub struct MismatchedStaticLifetime<'a> {
500     #[primary_span]
501     pub cause_span: Span,
502     #[subdiagnostic]
503     pub unmet_lifetime_reqs: IntroducesStaticBecauseUnmetLifetimeReq,
504     #[subdiagnostic]
505     pub expl: Option<note_and_explain::RegionExplanation<'a>>,
506     #[subdiagnostic]
507     pub does_not_outlive_static_from_impl: DoesNotOutliveStaticFromImpl,
508     #[subdiagnostic(eager)]
509     pub implicit_static_lifetimes: Vec<ImplicitStaticLifetimeSubdiag>,
510 }