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