1 use hir::GenericParamKind;
3 fluent, AddToDiagnostic, Applicability, Diagnostic, DiagnosticMessage, DiagnosticStyledString,
4 MultiSpan, SubdiagnosticMessage,
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};
13 use crate::infer::error_reporting::{
14 need_type_info::{GeneratorKindAsDiagArg, UnderspecifiedArgKind},
15 ObligationCauseAsDiagArg,
18 pub mod note_and_explain;
21 #[diag(infer_opaque_hidden_type)]
22 pub struct OpaqueHiddenTypeDiag {
27 pub opaque_type: Span,
29 pub hidden_type: Span,
33 #[diag(infer_type_annotations_needed, code = "E0282")]
34 pub struct AnnotationRequired<'a> {
37 pub source_kind: &'static str,
38 pub source_name: &'a str,
40 pub failure_span: Option<Span>,
42 pub bad_label: Option<InferenceBadError<'a>>,
44 pub infer_subdiags: Vec<SourceKindSubdiag<'a>>,
46 pub multi_suggestions: Vec<SourceKindMultiSuggestion<'a>>,
49 // Copy of `AnnotationRequired` for E0283
51 #[diag(infer_type_annotations_needed, code = "E0283")]
52 pub struct AmbigousImpl<'a> {
55 pub source_kind: &'static str,
56 pub source_name: &'a str,
58 pub failure_span: Option<Span>,
60 pub bad_label: Option<InferenceBadError<'a>>,
62 pub infer_subdiags: Vec<SourceKindSubdiag<'a>>,
64 pub multi_suggestions: Vec<SourceKindMultiSuggestion<'a>>,
67 // Copy of `AnnotationRequired` for E0284
69 #[diag(infer_type_annotations_needed, code = "E0284")]
70 pub struct AmbigousReturn<'a> {
73 pub source_kind: &'static str,
74 pub source_name: &'a str,
76 pub failure_span: Option<Span>,
78 pub bad_label: Option<InferenceBadError<'a>>,
80 pub infer_subdiags: Vec<SourceKindSubdiag<'a>>,
82 pub multi_suggestions: Vec<SourceKindMultiSuggestion<'a>>,
86 #[diag(infer_need_type_info_in_generator, code = "E0698")]
87 pub struct NeedTypeInfoInGenerator<'a> {
90 pub generator_kind: GeneratorKindAsDiagArg,
92 pub bad_label: InferenceBadError<'a>,
95 // Used when a better one isn't available
96 #[derive(Subdiagnostic)]
97 #[label(infer_label_bad)]
98 pub struct InferenceBadError<'a> {
101 pub bad_kind: &'static str,
102 pub prefix_kind: UnderspecifiedArgKind,
103 pub has_parent: bool,
105 pub parent_prefix: &'a str,
106 pub parent_name: String,
110 #[derive(Subdiagnostic)]
111 pub enum SourceKindSubdiag<'a> {
113 infer_source_kind_subdiag_let,
115 code = ": {type_name}",
116 applicability = "has-placeholders"
124 x_kind: &'static str,
125 prefix_kind: UnderspecifiedArgKind,
129 #[label(infer_source_kind_subdiag_generic_label)]
136 parent_prefix: String,
140 infer_source_kind_subdiag_generic_suggestion,
143 applicability = "has-placeholders"
153 #[derive(Subdiagnostic)]
154 pub enum SourceKindMultiSuggestion<'a> {
155 #[multipart_suggestion(
156 infer_source_kind_fully_qualified,
158 applicability = "has-placeholders"
161 #[suggestion_part(code = "{def_path}({adjustment}")]
163 #[suggestion_part(code = "{successor_pos}")]
167 successor_pos: &'a str,
169 #[multipart_suggestion(
170 infer_source_kind_closure_return,
172 applicability = "has-placeholders"
175 #[suggestion_part(code = "{start_span_code}")]
177 start_span_code: String,
178 #[suggestion_part(code = " }}")]
179 end_span: Option<Span>,
183 #[derive(Subdiagnostic)]
185 infer_suggest_add_let_for_letchains,
187 applicability = "machine-applicable",
190 pub(crate) struct SuggAddLetForLetChains {
195 impl<'a> SourceKindMultiSuggestion<'a> {
196 pub fn new_fully_qualified(
200 successor: (&'a str, BytePos),
202 Self::FullyQualified {
203 span_lo: span.shrink_to_lo(),
204 span_hi: span.shrink_to_hi().with_hi(successor.1),
207 successor_pos: successor.0,
211 pub fn new_closure_return(
213 data: &'a FnRetTy<'a>,
214 should_wrap_expr: Option<Span>,
216 let (arrow, post) = match data {
217 FnRetTy::DefaultReturn(_) => ("-> ", " "),
220 let (start_span, start_span_code, end_span) = match should_wrap_expr {
222 (data.span(), format!("{}{}{}{{ ", arrow, ty_info, post), Some(end_span))
224 None => (data.span(), format!("{}{}{}", arrow, ty_info, post), None),
226 Self::ClosureReturn { start_span, start_span_code, end_span }
230 pub enum RegionOriginNote<'a> {
233 msg: DiagnosticMessage,
237 msg: DiagnosticMessage,
243 requirement: ObligationCauseAsDiagArg<'a>,
244 expected_found: Option<(DiagnosticStyledString, DiagnosticStyledString)>,
248 impl AddToDiagnostic for RegionOriginNote<'_> {
249 fn add_to_diagnostic_with<F>(self, diag: &mut Diagnostic, _: F)
251 F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage,
253 let mut label_or_note = |span, msg: DiagnosticMessage| {
254 let sub_count = diag.children.iter().filter(|d| d.span.is_dummy()).count();
255 let expanded_sub_count = diag.children.iter().filter(|d| !d.span.is_dummy()).count();
256 let span_is_primary = diag.span.primary_spans().iter().all(|&sp| sp == span);
257 if span_is_primary && sub_count == 0 && expanded_sub_count == 0 {
258 diag.span_label(span, msg);
259 } else if span_is_primary && expanded_sub_count == 0 {
262 diag.span_note(span, msg);
266 RegionOriginNote::Plain { span, msg } => {
267 label_or_note(span, msg);
269 RegionOriginNote::WithName { span, msg, name, continues } => {
270 label_or_note(span, msg);
271 diag.set_arg("name", name);
272 diag.set_arg("continues", continues);
274 RegionOriginNote::WithRequirement {
277 expected_found: Some((expected, found)),
279 label_or_note(span, fluent::infer_subtype);
280 diag.set_arg("requirement", requirement);
282 diag.note_expected_found(&"", expected, &"", found);
284 RegionOriginNote::WithRequirement { span, requirement, expected_found: None } => {
285 // FIXME: this really should be handled at some earlier stage. Our
286 // handling of region checking when type errors are present is
288 label_or_note(span, fluent::infer_subtype_2);
289 diag.set_arg("requirement", requirement);
295 pub enum LifetimeMismatchLabels {
300 label_var1: Option<Ident>,
312 impl AddToDiagnostic for LifetimeMismatchLabels {
313 fn add_to_diagnostic_with<F>(self, diag: &mut Diagnostic, _: F)
315 F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage,
318 LifetimeMismatchLabels::InRet { param_span, ret_span, span, label_var1 } => {
319 diag.span_label(param_span, fluent::infer_declared_different);
320 diag.span_label(ret_span, fluent::infer_nothing);
321 diag.span_label(span, fluent::infer_data_returned);
322 diag.set_arg("label_var1_exists", label_var1.is_some());
323 diag.set_arg("label_var1", label_var1.map(|x| x.to_string()).unwrap_or_default());
325 LifetimeMismatchLabels::Normal {
334 diag.span_label(ty_sup, fluent::infer_declared_multiple);
335 diag.span_label(ty_sub, fluent::infer_nothing);
336 diag.span_label(span, fluent::infer_data_lifetime_flow);
338 diag.span_label(ty_sup, fluent::infer_types_declared_different);
339 diag.span_label(ty_sub, fluent::infer_nothing);
340 diag.span_label(span, fluent::infer_data_flows);
341 diag.set_arg("label_var1_exists", label_var1.is_some());
344 label_var1.map(|x| x.to_string()).unwrap_or_default(),
346 diag.set_arg("label_var2_exists", label_var2.is_some());
349 label_var2.map(|x| x.to_string()).unwrap_or_default(),
357 pub struct AddLifetimeParamsSuggestion<'a> {
360 pub ty_sup: &'a Ty<'a>,
361 pub ty_sub: &'a Ty<'a>,
365 impl AddToDiagnostic for AddLifetimeParamsSuggestion<'_> {
366 fn add_to_diagnostic_with<F>(self, diag: &mut Diagnostic, _: F)
368 F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage,
370 let mut mk_suggestion = || {
372 hir::Ty { kind: hir::TyKind::Ref(lifetime_sub, _), .. },
373 hir::Ty { kind: hir::TyKind::Ref(lifetime_sup, _), .. },
374 ) = (self.ty_sub, self.ty_sup) else {
378 if !lifetime_sub.is_anonymous() || !lifetime_sup.is_anonymous() {
382 let Some(anon_reg) = self.tcx.is_suitable_region(self.sub) else {
386 let hir_id = self.tcx.hir().local_def_id_to_hir_id(anon_reg.def_id);
388 let node = self.tcx.hir().get(hir_id);
389 let is_impl = matches!(&node, hir::Node::ImplItem(_));
390 let generics = match node {
391 hir::Node::Item(&hir::Item {
392 kind: hir::ItemKind::Fn(_, ref generics, ..),
395 | hir::Node::TraitItem(&hir::TraitItem { ref generics, .. })
396 | hir::Node::ImplItem(&hir::ImplItem { ref generics, .. }) => generics,
400 let suggestion_param_name = generics
403 .filter(|p| matches!(p.kind, GenericParamKind::Lifetime { .. }))
404 .map(|p| p.name.ident().name)
405 .find(|i| *i != kw::UnderscoreLifetime);
406 let introduce_new = suggestion_param_name.is_none();
407 let suggestion_param_name =
408 suggestion_param_name.map(|n| n.to_string()).unwrap_or_else(|| "'a".to_owned());
410 debug!(?lifetime_sup.ident.span);
411 debug!(?lifetime_sub.ident.span);
412 let make_suggestion = |ident: Ident| {
413 let sugg = if ident.name == kw::Empty {
414 format!("{}, ", suggestion_param_name)
415 } else if ident.name == kw::UnderscoreLifetime && ident.span.is_empty() {
416 format!("{} ", suggestion_param_name)
418 suggestion_param_name.clone()
422 let mut suggestions =
423 vec![make_suggestion(lifetime_sub.ident), make_suggestion(lifetime_sup.ident)];
426 let new_param_suggestion = if let Some(first) =
427 generics.params.iter().find(|p| !p.name.ident().span.is_empty())
429 (first.span.shrink_to_lo(), format!("{}, ", suggestion_param_name))
431 (generics.span, format!("<{}>", suggestion_param_name))
434 suggestions.push(new_param_suggestion);
437 diag.multipart_suggestion(
438 fluent::infer_lifetime_param_suggestion,
440 Applicability::MaybeIncorrect,
442 diag.set_arg("is_impl", is_impl);
445 if mk_suggestion() && self.add_note {
446 diag.note(fluent::infer_lifetime_param_suggestion_elided);
451 #[derive(Diagnostic)]
452 #[diag(infer_lifetime_mismatch, code = "E0623")]
453 pub struct LifetimeMismatch<'a> {
457 pub labels: LifetimeMismatchLabels,
459 pub suggestion: AddLifetimeParamsSuggestion<'a>,
462 pub struct IntroducesStaticBecauseUnmetLifetimeReq {
463 pub unmet_requirements: MultiSpan,
464 pub binding_span: Span,
467 impl AddToDiagnostic for IntroducesStaticBecauseUnmetLifetimeReq {
468 fn add_to_diagnostic_with<F>(mut self, diag: &mut Diagnostic, _: F)
470 F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage,
472 self.unmet_requirements
473 .push_span_label(self.binding_span, fluent::infer_msl_introduces_static);
474 diag.span_note(self.unmet_requirements, fluent::infer_msl_unmet_req);
478 // FIXME(#100717): replace with a `Option<Span>` when subdiagnostic supports that
479 #[derive(Subdiagnostic)]
480 pub enum DoesNotOutliveStaticFromImpl {
481 #[note(infer_does_not_outlive_static_from_impl)]
486 #[note(infer_does_not_outlive_static_from_impl)]
490 #[derive(Subdiagnostic)]
491 pub enum ImplicitStaticLifetimeSubdiag {
492 #[note(infer_implicit_static_lifetime_note)]
498 infer_implicit_static_lifetime_suggestion,
501 applicability = "maybe-incorrect"
509 #[derive(Diagnostic)]
510 #[diag(infer_mismatched_static_lifetime)]
511 pub struct MismatchedStaticLifetime<'a> {
513 pub cause_span: Span,
515 pub unmet_lifetime_reqs: IntroducesStaticBecauseUnmetLifetimeReq,
517 pub expl: Option<note_and_explain::RegionExplanation<'a>>,
519 pub does_not_outlive_static_from_impl: DoesNotOutliveStaticFromImpl,
521 pub implicit_static_lifetimes: Vec<ImplicitStaticLifetimeSubdiag>,