1 use hir::GenericParamKind;
3 fluent, AddToDiagnostic, Applicability, Diagnostic, DiagnosticMessage, DiagnosticStyledString,
4 MultiSpan, SubdiagnosticMessage,
7 use rustc_hir::FnRetTy;
8 use rustc_macros::{Diagnostic, Subdiagnostic};
9 use rustc_middle::ty::{Region, Ty, TyCtxt};
10 use rustc_span::symbol::kw;
11 use rustc_span::Symbol;
12 use rustc_span::{symbol::Ident, BytePos, Span};
14 use crate::infer::error_reporting::{
15 need_type_info::{GeneratorKindAsDiagArg, UnderspecifiedArgKind},
16 ObligationCauseAsDiagArg,
19 pub mod note_and_explain;
22 #[diag(infer_opaque_hidden_type)]
23 pub struct OpaqueHiddenTypeDiag {
28 pub opaque_type: Span,
30 pub hidden_type: Span,
34 #[diag(infer_type_annotations_needed, code = "E0282")]
35 pub struct AnnotationRequired<'a> {
38 pub source_kind: &'static str,
39 pub source_name: &'a str,
41 pub failure_span: Option<Span>,
43 pub bad_label: Option<InferenceBadError<'a>>,
45 pub infer_subdiags: Vec<SourceKindSubdiag<'a>>,
47 pub multi_suggestions: Vec<SourceKindMultiSuggestion<'a>>,
50 // Copy of `AnnotationRequired` for E0283
52 #[diag(infer_type_annotations_needed, code = "E0283")]
53 pub struct AmbigousImpl<'a> {
56 pub source_kind: &'static str,
57 pub source_name: &'a str,
59 pub failure_span: Option<Span>,
61 pub bad_label: Option<InferenceBadError<'a>>,
63 pub infer_subdiags: Vec<SourceKindSubdiag<'a>>,
65 pub multi_suggestions: Vec<SourceKindMultiSuggestion<'a>>,
68 // Copy of `AnnotationRequired` for E0284
70 #[diag(infer_type_annotations_needed, code = "E0284")]
71 pub struct AmbigousReturn<'a> {
74 pub source_kind: &'static str,
75 pub source_name: &'a str,
77 pub failure_span: Option<Span>,
79 pub bad_label: Option<InferenceBadError<'a>>,
81 pub infer_subdiags: Vec<SourceKindSubdiag<'a>>,
83 pub multi_suggestions: Vec<SourceKindMultiSuggestion<'a>>,
87 #[diag(infer_need_type_info_in_generator, code = "E0698")]
88 pub struct NeedTypeInfoInGenerator<'a> {
91 pub generator_kind: GeneratorKindAsDiagArg,
93 pub bad_label: InferenceBadError<'a>,
96 // Used when a better one isn't available
97 #[derive(Subdiagnostic)]
98 #[label(infer_label_bad)]
99 pub struct InferenceBadError<'a> {
102 pub bad_kind: &'static str,
103 pub prefix_kind: UnderspecifiedArgKind,
104 pub has_parent: bool,
106 pub parent_prefix: &'a str,
107 pub parent_name: String,
111 #[derive(Subdiagnostic)]
112 pub enum SourceKindSubdiag<'a> {
114 infer_source_kind_subdiag_let,
116 code = ": {type_name}",
117 applicability = "has-placeholders"
125 x_kind: &'static str,
126 prefix_kind: UnderspecifiedArgKind,
130 #[label(infer_source_kind_subdiag_generic_label)]
137 parent_prefix: String,
141 infer_source_kind_subdiag_generic_suggestion,
144 applicability = "has-placeholders"
154 #[derive(Subdiagnostic)]
155 pub enum SourceKindMultiSuggestion<'a> {
156 #[multipart_suggestion(
157 infer_source_kind_fully_qualified,
159 applicability = "has-placeholders"
162 #[suggestion_part(code = "{def_path}({adjustment}")]
164 #[suggestion_part(code = "{successor_pos}")]
168 successor_pos: &'a str,
170 #[multipart_suggestion(
171 infer_source_kind_closure_return,
173 applicability = "has-placeholders"
176 #[suggestion_part(code = "{start_span_code}")]
178 start_span_code: String,
179 #[suggestion_part(code = " }}")]
180 end_span: Option<Span>,
184 #[derive(Subdiagnostic)]
186 infer_suggest_add_let_for_letchains,
188 applicability = "machine-applicable",
191 pub(crate) struct SuggAddLetForLetChains {
196 impl<'a> SourceKindMultiSuggestion<'a> {
197 pub fn new_fully_qualified(
201 successor: (&'a str, BytePos),
203 Self::FullyQualified {
204 span_lo: span.shrink_to_lo(),
205 span_hi: span.shrink_to_hi().with_hi(successor.1),
208 successor_pos: successor.0,
212 pub fn new_closure_return(
214 data: &'a FnRetTy<'a>,
215 should_wrap_expr: Option<Span>,
217 let (arrow, post) = match data {
218 FnRetTy::DefaultReturn(_) => ("-> ", " "),
221 let (start_span, start_span_code, end_span) = match should_wrap_expr {
223 (data.span(), format!("{}{}{}{{ ", arrow, ty_info, post), Some(end_span))
225 None => (data.span(), format!("{}{}{}", arrow, ty_info, post), None),
227 Self::ClosureReturn { start_span, start_span_code, end_span }
231 pub enum RegionOriginNote<'a> {
234 msg: DiagnosticMessage,
238 msg: DiagnosticMessage,
244 requirement: ObligationCauseAsDiagArg<'a>,
245 expected_found: Option<(DiagnosticStyledString, DiagnosticStyledString)>,
249 impl AddToDiagnostic for RegionOriginNote<'_> {
250 fn add_to_diagnostic_with<F>(self, diag: &mut Diagnostic, _: F)
252 F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage,
254 let mut label_or_note = |span, msg: DiagnosticMessage| {
255 let sub_count = diag.children.iter().filter(|d| d.span.is_dummy()).count();
256 let expanded_sub_count = diag.children.iter().filter(|d| !d.span.is_dummy()).count();
257 let span_is_primary = diag.span.primary_spans().iter().all(|&sp| sp == span);
258 if span_is_primary && sub_count == 0 && expanded_sub_count == 0 {
259 diag.span_label(span, msg);
260 } else if span_is_primary && expanded_sub_count == 0 {
263 diag.span_note(span, msg);
267 RegionOriginNote::Plain { span, msg } => {
268 label_or_note(span, msg);
270 RegionOriginNote::WithName { span, msg, name, continues } => {
271 label_or_note(span, msg);
272 diag.set_arg("name", name);
273 diag.set_arg("continues", continues);
275 RegionOriginNote::WithRequirement {
278 expected_found: Some((expected, found)),
280 label_or_note(span, fluent::infer_subtype);
281 diag.set_arg("requirement", requirement);
283 diag.note_expected_found(&"", expected, &"", found);
285 RegionOriginNote::WithRequirement { span, requirement, expected_found: None } => {
286 // FIXME: this really should be handled at some earlier stage. Our
287 // handling of region checking when type errors are present is
289 label_or_note(span, fluent::infer_subtype_2);
290 diag.set_arg("requirement", requirement);
296 pub enum LifetimeMismatchLabels {
301 label_var1: Option<Ident>,
313 impl AddToDiagnostic for LifetimeMismatchLabels {
314 fn add_to_diagnostic_with<F>(self, diag: &mut Diagnostic, _: F)
316 F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage,
319 LifetimeMismatchLabels::InRet { param_span, ret_span, span, label_var1 } => {
320 diag.span_label(param_span, fluent::infer_declared_different);
321 diag.span_label(ret_span, fluent::infer_nothing);
322 diag.span_label(span, fluent::infer_data_returned);
323 diag.set_arg("label_var1_exists", label_var1.is_some());
324 diag.set_arg("label_var1", label_var1.map(|x| x.to_string()).unwrap_or_default());
326 LifetimeMismatchLabels::Normal {
335 diag.span_label(ty_sup, fluent::infer_declared_multiple);
336 diag.span_label(ty_sub, fluent::infer_nothing);
337 diag.span_label(span, fluent::infer_data_lifetime_flow);
339 diag.span_label(ty_sup, fluent::infer_types_declared_different);
340 diag.span_label(ty_sub, fluent::infer_nothing);
341 diag.span_label(span, fluent::infer_data_flows);
342 diag.set_arg("label_var1_exists", label_var1.is_some());
345 label_var1.map(|x| x.to_string()).unwrap_or_default(),
347 diag.set_arg("label_var2_exists", label_var2.is_some());
350 label_var2.map(|x| x.to_string()).unwrap_or_default(),
358 pub struct AddLifetimeParamsSuggestion<'a> {
361 pub ty_sup: &'a hir::Ty<'a>,
362 pub ty_sub: &'a hir::Ty<'a>,
366 impl AddToDiagnostic for AddLifetimeParamsSuggestion<'_> {
367 fn add_to_diagnostic_with<F>(self, diag: &mut Diagnostic, _: F)
369 F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage,
371 let mut mk_suggestion = || {
373 hir::Ty { kind: hir::TyKind::Rptr(lifetime_sub, _), .. },
374 hir::Ty { kind: hir::TyKind::Rptr(lifetime_sup, _), .. },
375 ) = (self.ty_sub, self.ty_sup) else {
379 if !lifetime_sub.is_anonymous() || !lifetime_sup.is_anonymous() {
383 let Some(anon_reg) = self.tcx.is_suitable_region(self.sub) else {
387 let hir_id = self.tcx.hir().local_def_id_to_hir_id(anon_reg.def_id);
389 let node = self.tcx.hir().get(hir_id);
390 let is_impl = matches!(&node, hir::Node::ImplItem(_));
391 let generics = match node {
392 hir::Node::Item(&hir::Item {
393 kind: hir::ItemKind::Fn(_, ref generics, ..),
396 | hir::Node::TraitItem(&hir::TraitItem { ref generics, .. })
397 | hir::Node::ImplItem(&hir::ImplItem { ref generics, .. }) => generics,
401 let suggestion_param_name = generics
404 .filter(|p| matches!(p.kind, GenericParamKind::Lifetime { .. }))
405 .map(|p| p.name.ident().name)
406 .find(|i| *i != kw::UnderscoreLifetime);
407 let introduce_new = suggestion_param_name.is_none();
408 let suggestion_param_name =
409 suggestion_param_name.map(|n| n.to_string()).unwrap_or_else(|| "'a".to_owned());
411 debug!(?lifetime_sup.ident.span);
412 debug!(?lifetime_sub.ident.span);
413 let make_suggestion = |ident: Ident| {
414 let sugg = if ident.name == kw::Empty {
415 format!("{}, ", suggestion_param_name)
416 } else if ident.name == kw::UnderscoreLifetime && ident.span.is_empty() {
417 format!("{} ", suggestion_param_name)
419 suggestion_param_name.clone()
423 let mut suggestions =
424 vec![make_suggestion(lifetime_sub.ident), make_suggestion(lifetime_sup.ident)];
427 let new_param_suggestion = if let Some(first) =
428 generics.params.iter().find(|p| !p.name.ident().span.is_empty())
430 (first.span.shrink_to_lo(), format!("{}, ", suggestion_param_name))
432 (generics.span, format!("<{}>", suggestion_param_name))
435 suggestions.push(new_param_suggestion);
438 diag.multipart_suggestion(
439 fluent::infer_lifetime_param_suggestion,
441 Applicability::MaybeIncorrect,
443 diag.set_arg("is_impl", is_impl);
446 if mk_suggestion() && self.add_note {
447 diag.note(fluent::infer_lifetime_param_suggestion_elided);
452 #[derive(Diagnostic)]
453 #[diag(infer_lifetime_mismatch, code = "E0623")]
454 pub struct LifetimeMismatch<'a> {
458 pub labels: LifetimeMismatchLabels,
460 pub suggestion: AddLifetimeParamsSuggestion<'a>,
463 pub struct IntroducesStaticBecauseUnmetLifetimeReq {
464 pub unmet_requirements: MultiSpan,
465 pub binding_span: Span,
468 impl AddToDiagnostic for IntroducesStaticBecauseUnmetLifetimeReq {
469 fn add_to_diagnostic_with<F>(mut self, diag: &mut Diagnostic, _: F)
471 F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage,
473 self.unmet_requirements
474 .push_span_label(self.binding_span, fluent::infer_msl_introduces_static);
475 diag.span_note(self.unmet_requirements, fluent::infer_msl_unmet_req);
479 // FIXME(#100717): replace with a `Option<Span>` when subdiagnostic supports that
480 #[derive(Subdiagnostic)]
481 pub enum DoesNotOutliveStaticFromImpl {
482 #[note(infer_does_not_outlive_static_from_impl)]
487 #[note(infer_does_not_outlive_static_from_impl)]
491 #[derive(Subdiagnostic)]
492 pub enum ImplicitStaticLifetimeSubdiag {
493 #[note(infer_implicit_static_lifetime_note)]
499 infer_implicit_static_lifetime_suggestion,
502 applicability = "maybe-incorrect"
510 #[derive(Diagnostic)]
511 #[diag(infer_mismatched_static_lifetime)]
512 pub struct MismatchedStaticLifetime<'a> {
514 pub cause_span: Span,
516 pub unmet_lifetime_reqs: IntroducesStaticBecauseUnmetLifetimeReq,
518 pub expl: Option<note_and_explain::RegionExplanation<'a>>,
520 pub does_not_outlive_static_from_impl: DoesNotOutliveStaticFromImpl,
522 pub implicit_static_lifetimes: Vec<ImplicitStaticLifetimeSubdiag>,
525 #[derive(Diagnostic)]
526 pub enum ExplicitLifetimeRequired<'a> {
527 #[diag(infer_explicit_lifetime_required_with_ident, code = "E0621")]
535 infer_explicit_lifetime_required_sugg_with_ident,
537 applicability = "unspecified"
543 #[diag(infer_explicit_lifetime_required_with_param_type, code = "E0621")]
550 infer_explicit_lifetime_required_sugg_with_param_type,
552 applicability = "unspecified"
560 #[derive(Subdiagnostic)]
561 pub enum ActualImplExplNotes {
562 #[note(infer_actual_impl_expl_expected_signature_two)]
563 ExpectedSignatureTwo {
564 leading_ellipsis: bool,
570 #[note(infer_actual_impl_expl_expected_signature_any)]
571 ExpectedSignatureAny {
572 leading_ellipsis: bool,
577 #[note(infer_actual_impl_expl_expected_signature_some)]
578 ExpectedSignatureSome {
579 leading_ellipsis: bool,
584 #[note(infer_actual_impl_expl_expected_signature_nothing)]
585 ExpectedSignatureNothing { leading_ellipsis: bool, ty_or_sig: String, trait_path: String },
586 #[note(infer_actual_impl_expl_expected_passive_two)]
588 leading_ellipsis: bool,
594 #[note(infer_actual_impl_expl_expected_passive_any)]
596 leading_ellipsis: bool,
601 #[note(infer_actual_impl_expl_expected_passive_some)]
602 ExpectedPassiveSome {
603 leading_ellipsis: bool,
608 #[note(infer_actual_impl_expl_expected_passive_nothing)]
609 ExpectedPassiveNothing { leading_ellipsis: bool, ty_or_sig: String, trait_path: String },
610 #[note(infer_actual_impl_expl_expected_other_two)]
612 leading_ellipsis: bool,
618 #[note(infer_actual_impl_expl_expected_other_any)]
620 leading_ellipsis: bool,
625 #[note(infer_actual_impl_expl_expected_other_some)]
627 leading_ellipsis: bool,
632 #[note(infer_actual_impl_expl_expected_other_nothing)]
633 ExpectedOtherNothing { leading_ellipsis: bool, ty_or_sig: String, trait_path: String },
634 #[note(infer_actual_impl_expl_but_actually_implements_trait)]
635 ButActuallyImplementsTrait { trait_path: String, has_lifetime: bool, lifetime: usize },
636 #[note(infer_actual_impl_expl_but_actually_implemented_for_ty)]
637 ButActuallyImplementedForTy {
643 #[note(infer_actual_impl_expl_but_actually_ty_implements)]
644 ButActuallyTyImplements { trait_path: String, has_lifetime: bool, lifetime: usize, ty: String },
647 pub enum ActualImplExpectedKind {
653 pub enum ActualImplExpectedLifetimeKind {
660 impl ActualImplExplNotes {
662 kind: ActualImplExpectedKind,
663 lt_kind: ActualImplExpectedLifetimeKind,
664 leading_ellipsis: bool,
670 match (kind, lt_kind) {
671 (ActualImplExpectedKind::Signature, ActualImplExpectedLifetimeKind::Two) => {
672 Self::ExpectedSignatureTwo {
680 (ActualImplExpectedKind::Signature, ActualImplExpectedLifetimeKind::Any) => {
681 Self::ExpectedSignatureAny { leading_ellipsis, ty_or_sig, trait_path, lifetime_1 }
683 (ActualImplExpectedKind::Signature, ActualImplExpectedLifetimeKind::Some) => {
684 Self::ExpectedSignatureSome { leading_ellipsis, ty_or_sig, trait_path, lifetime_1 }
686 (ActualImplExpectedKind::Signature, ActualImplExpectedLifetimeKind::Nothing) => {
687 Self::ExpectedSignatureNothing { leading_ellipsis, ty_or_sig, trait_path }
689 (ActualImplExpectedKind::Passive, ActualImplExpectedLifetimeKind::Two) => {
690 Self::ExpectedPassiveTwo {
698 (ActualImplExpectedKind::Passive, ActualImplExpectedLifetimeKind::Any) => {
699 Self::ExpectedPassiveAny { leading_ellipsis, ty_or_sig, trait_path, lifetime_1 }
701 (ActualImplExpectedKind::Passive, ActualImplExpectedLifetimeKind::Some) => {
702 Self::ExpectedPassiveSome { leading_ellipsis, ty_or_sig, trait_path, lifetime_1 }
704 (ActualImplExpectedKind::Passive, ActualImplExpectedLifetimeKind::Nothing) => {
705 Self::ExpectedPassiveNothing { leading_ellipsis, ty_or_sig, trait_path }
707 (ActualImplExpectedKind::Other, ActualImplExpectedLifetimeKind::Two) => {
708 Self::ExpectedOtherTwo {
716 (ActualImplExpectedKind::Other, ActualImplExpectedLifetimeKind::Any) => {
717 Self::ExpectedOtherAny { leading_ellipsis, ty_or_sig, trait_path, lifetime_1 }
719 (ActualImplExpectedKind::Other, ActualImplExpectedLifetimeKind::Some) => {
720 Self::ExpectedOtherSome { leading_ellipsis, ty_or_sig, trait_path, lifetime_1 }
722 (ActualImplExpectedKind::Other, ActualImplExpectedLifetimeKind::Nothing) => {
723 Self::ExpectedOtherNothing { leading_ellipsis, ty_or_sig, trait_path }
729 #[derive(Diagnostic)]
730 #[diag(infer_trait_placeholder_mismatch)]
731 pub struct TraitPlaceholderMismatch {
734 #[label(label_satisfy)]
735 pub satisfy_span: Option<Span>,
736 #[label(label_where)]
737 pub where_span: Option<Span>,
739 pub dup_span: Option<Span>,
741 pub trait_def_id: String,
743 #[subdiagnostic(eager)]
744 pub actual_impl_expl_notes: Vec<ActualImplExplNotes>,
747 pub struct ConsiderBorrowingParamHelp {
748 pub spans: Vec<Span>,
751 impl AddToDiagnostic for ConsiderBorrowingParamHelp {
752 fn add_to_diagnostic_with<F>(self, diag: &mut Diagnostic, f: F)
754 F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage,
756 let mut type_param_span: MultiSpan = self.spans.clone().into();
757 for &span in &self.spans {
758 // Seems like we can't call f() here as Into<DiagnosticMessage> is required
759 type_param_span.push_span_label(span, fluent::infer_tid_consider_borrowing);
761 let msg = f(diag, fluent::infer_tid_param_help.into());
762 diag.span_help(type_param_span, msg);
766 #[derive(Subdiagnostic)]
767 #[help(infer_tid_rel_help)]
768 pub struct RelationshipHelp;
770 #[derive(Diagnostic)]
771 #[diag(infer_trait_impl_diff)]
772 pub struct TraitImplDiff {
778 #[note(expected_found)]
781 pub param_help: ConsiderBorrowingParamHelp,
783 // Seems like subdiagnostics are always pushed to the end, so this one
784 // also has to be a subdiagnostic to maintain order.
785 pub rel_help: Option<RelationshipHelp>,
786 pub expected: String,
790 pub struct DynTraitConstraintSuggestion {
795 impl AddToDiagnostic for DynTraitConstraintSuggestion {
796 fn add_to_diagnostic_with<F>(self, diag: &mut Diagnostic, f: F)
798 F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage,
800 let mut multi_span: MultiSpan = vec![self.span].into();
801 multi_span.push_span_label(self.span, fluent::infer_dtcs_has_lifetime_req_label);
802 multi_span.push_span_label(self.ident.span, fluent::infer_dtcs_introduces_requirement);
803 let msg = f(diag, fluent::infer_dtcs_has_req_note.into());
804 diag.span_note(multi_span, msg);
805 let msg = f(diag, fluent::infer_dtcs_suggestion.into());
806 diag.span_suggestion_verbose(
807 self.span.shrink_to_hi(),
810 Applicability::MaybeIncorrect,
815 #[derive(Diagnostic)]
816 #[diag(infer_but_calling_introduces, code = "E0772")]
817 pub struct ButCallingIntroduces {
819 pub param_ty_span: Span,
822 pub cause_span: Span,
824 pub has_param_name: bool,
825 pub param_name: String,
826 pub has_lifetime: bool,
827 pub lifetime: String,
828 pub assoc_item: Symbol,
829 pub has_impl_path: bool,
830 pub impl_path: String,
833 pub struct ReqIntroducedLocations {
835 pub spans: Vec<Span>,
836 pub fn_decl_span: Span,
837 pub cause_span: Span,
841 impl AddToDiagnostic for ReqIntroducedLocations {
842 fn add_to_diagnostic_with<F>(mut self, diag: &mut Diagnostic, f: F)
844 F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage,
846 for sp in self.spans {
847 self.span.push_span_label(sp, fluent::infer_ril_introduced_here);
851 self.span.push_span_label(self.fn_decl_span, fluent::infer_ril_introduced_by);
853 self.span.push_span_label(self.cause_span, fluent::infer_ril_because_of);
854 let msg = f(diag, fluent::infer_ril_static_introduced_by.into());
855 diag.span_note(self.span, msg);
859 pub struct MoreTargeted {
863 impl AddToDiagnostic for MoreTargeted {
864 fn add_to_diagnostic_with<F>(self, diag: &mut Diagnostic, _f: F)
866 F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage,
868 diag.code(rustc_errors::error_code!(E0772));
869 diag.set_primary_message(fluent::infer_more_targeted);
870 diag.set_arg("ident", self.ident);
874 #[derive(Diagnostic)]
875 #[diag(infer_but_needs_to_satisfy, code = "E0759")]
876 pub struct ButNeedsToSatisfy {
880 pub influencer_point: Span,
882 pub spans: Vec<Span>,
884 pub require_span_as_label: Option<Span>,
886 pub require_span_as_note: Option<Span>,
887 #[note(introduced_by_bound)]
888 pub bound: Option<Span>,
891 pub req_introduces_loc: Option<ReqIntroducedLocations>,
893 pub spans_empty: bool,
894 pub has_lifetime: bool,
895 pub lifetime: String,