rustc_trait_selection/
errors.rs

1use rustc_ast::Path;
2use rustc_data_structures::fx::{FxHashSet, FxIndexSet};
3use rustc_errors::codes::*;
4use rustc_errors::{
5    Applicability, Diag, DiagCtxtHandle, DiagMessage, DiagStyledString, Diagnostic,
6    EmissionGuarantee, IntoDiagArg, Level, MultiSpan, Subdiagnostic,
7};
8use rustc_hir::def::DefKind;
9use rustc_hir::def_id::{DefId, LocalDefId};
10use rustc_hir::intravisit::{Visitor, VisitorExt, walk_ty};
11use rustc_hir::{self as hir, AmbigArg, FnRetTy, GenericParamKind, Node};
12use rustc_macros::{Diagnostic, Subdiagnostic};
13use rustc_middle::ty::print::{PrintTraitRefExt as _, TraitRefPrintOnlyTraitPath};
14use rustc_middle::ty::{self, Binder, ClosureKind, FnSig, GenericArg, Region, Ty, TyCtxt};
15use rustc_span::{BytePos, Ident, Span, Symbol, kw};
16
17use crate::error_reporting::infer::ObligationCauseAsDiagArg;
18use crate::error_reporting::infer::need_type_info::UnderspecifiedArgKind;
19use crate::error_reporting::infer::nice_region_error::placeholder_error::Highlighted;
20use crate::fluent_generated as fluent;
21
22pub mod note_and_explain;
23
24#[derive(Diagnostic)]
25#[diag(trait_selection_unable_to_construct_constant_value)]
26pub struct UnableToConstructConstantValue<'a> {
27    #[primary_span]
28    pub span: Span,
29    pub unevaluated: ty::UnevaluatedConst<'a>,
30}
31
32#[derive(Diagnostic)]
33pub enum InvalidOnClause {
34    #[diag(trait_selection_rustc_on_unimplemented_empty_on_clause, code = E0232)]
35    Empty {
36        #[primary_span]
37        #[label]
38        span: Span,
39    },
40    #[diag(trait_selection_rustc_on_unimplemented_expected_one_predicate_in_not, code = E0232)]
41    ExpectedOnePredInNot {
42        #[primary_span]
43        #[label]
44        span: Span,
45    },
46    #[diag(trait_selection_rustc_on_unimplemented_unsupported_literal_in_on, code = E0232)]
47    UnsupportedLiteral {
48        #[primary_span]
49        #[label]
50        span: Span,
51    },
52    #[diag(trait_selection_rustc_on_unimplemented_expected_identifier, code = E0232)]
53    ExpectedIdentifier {
54        #[primary_span]
55        #[label]
56        span: Span,
57        path: Path,
58    },
59    #[diag(trait_selection_rustc_on_unimplemented_invalid_predicate, code = E0232)]
60    InvalidPredicate {
61        #[primary_span]
62        #[label]
63        span: Span,
64        invalid_pred: Symbol,
65    },
66    #[diag(trait_selection_rustc_on_unimplemented_invalid_flag, code = E0232)]
67    InvalidFlag {
68        #[primary_span]
69        #[label]
70        span: Span,
71        invalid_flag: Symbol,
72    },
73    #[diag(trait_selection_rustc_on_unimplemented_invalid_name, code = E0232)]
74    InvalidName {
75        #[primary_span]
76        #[label]
77        span: Span,
78        invalid_name: Symbol,
79    },
80}
81
82#[derive(Diagnostic)]
83#[diag(trait_selection_rustc_on_unimplemented_missing_value, code = E0232)]
84#[note]
85pub struct NoValueInOnUnimplemented {
86    #[primary_span]
87    #[label]
88    pub span: Span,
89}
90
91pub struct NegativePositiveConflict<'tcx> {
92    pub impl_span: Span,
93    pub trait_desc: ty::TraitRef<'tcx>,
94    pub self_ty: Option<Ty<'tcx>>,
95    pub negative_impl_span: Result<Span, Symbol>,
96    pub positive_impl_span: Result<Span, Symbol>,
97}
98
99impl<G: EmissionGuarantee> Diagnostic<'_, G> for NegativePositiveConflict<'_> {
100    #[track_caller]
101    fn into_diag(self, dcx: DiagCtxtHandle<'_>, level: Level) -> Diag<'_, G> {
102        let mut diag = Diag::new(dcx, level, fluent::trait_selection_negative_positive_conflict);
103        diag.arg("trait_desc", self.trait_desc.print_only_trait_path().to_string());
104        diag.arg("self_desc", self.self_ty.map_or_else(|| "none".to_string(), |ty| ty.to_string()));
105        diag.span(self.impl_span);
106        diag.code(E0751);
107        match self.negative_impl_span {
108            Ok(span) => {
109                diag.span_label(span, fluent::trait_selection_negative_implementation_here);
110            }
111            Err(cname) => {
112                diag.note(fluent::trait_selection_negative_implementation_in_crate);
113                diag.arg("negative_impl_cname", cname.to_string());
114            }
115        }
116        match self.positive_impl_span {
117            Ok(span) => {
118                diag.span_label(span, fluent::trait_selection_positive_implementation_here);
119            }
120            Err(cname) => {
121                diag.note(fluent::trait_selection_positive_implementation_in_crate);
122                diag.arg("positive_impl_cname", cname.to_string());
123            }
124        }
125        diag
126    }
127}
128
129#[derive(Diagnostic)]
130#[diag(trait_selection_inherent_projection_normalization_overflow)]
131pub struct InherentProjectionNormalizationOverflow {
132    #[primary_span]
133    pub span: Span,
134    pub ty: String,
135}
136
137pub enum AdjustSignatureBorrow {
138    Borrow { to_borrow: Vec<(Span, String)> },
139    RemoveBorrow { remove_borrow: Vec<(Span, String)> },
140}
141
142impl Subdiagnostic for AdjustSignatureBorrow {
143    fn add_to_diag<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) {
144        match self {
145            AdjustSignatureBorrow::Borrow { to_borrow } => {
146                diag.arg("len", to_borrow.len());
147                diag.multipart_suggestion_verbose(
148                    fluent::trait_selection_adjust_signature_borrow,
149                    to_borrow,
150                    Applicability::MaybeIncorrect,
151                );
152            }
153            AdjustSignatureBorrow::RemoveBorrow { remove_borrow } => {
154                diag.arg("len", remove_borrow.len());
155                diag.multipart_suggestion_verbose(
156                    fluent::trait_selection_adjust_signature_remove_borrow,
157                    remove_borrow,
158                    Applicability::MaybeIncorrect,
159                );
160            }
161        }
162    }
163}
164
165#[derive(Diagnostic)]
166#[diag(trait_selection_closure_kind_mismatch, code = E0525)]
167pub struct ClosureKindMismatch {
168    #[primary_span]
169    #[label]
170    pub closure_span: Span,
171    pub expected: ClosureKind,
172    pub found: ClosureKind,
173    #[label(trait_selection_closure_kind_requirement)]
174    pub cause_span: Span,
175
176    pub trait_prefix: &'static str,
177
178    #[subdiagnostic]
179    pub fn_once_label: Option<ClosureFnOnceLabel>,
180
181    #[subdiagnostic]
182    pub fn_mut_label: Option<ClosureFnMutLabel>,
183}
184
185#[derive(Subdiagnostic)]
186#[label(trait_selection_closure_fn_once_label)]
187pub struct ClosureFnOnceLabel {
188    #[primary_span]
189    pub span: Span,
190    pub place: String,
191}
192
193#[derive(Subdiagnostic)]
194#[label(trait_selection_closure_fn_mut_label)]
195pub struct ClosureFnMutLabel {
196    #[primary_span]
197    pub span: Span,
198    pub place: String,
199}
200
201#[derive(Diagnostic)]
202#[diag(trait_selection_coro_closure_not_fn)]
203pub(crate) struct CoroClosureNotFn {
204    #[primary_span]
205    pub span: Span,
206    pub kind: &'static str,
207    pub coro_kind: String,
208}
209
210#[derive(Diagnostic)]
211#[diag(trait_selection_type_annotations_needed, code = E0282)]
212pub struct AnnotationRequired<'a> {
213    #[primary_span]
214    pub span: Span,
215    pub source_kind: &'static str,
216    pub source_name: &'a str,
217    #[label]
218    pub failure_span: Option<Span>,
219    #[subdiagnostic]
220    pub bad_label: Option<InferenceBadError<'a>>,
221    #[subdiagnostic]
222    pub infer_subdiags: Vec<SourceKindSubdiag<'a>>,
223    #[subdiagnostic]
224    pub multi_suggestions: Vec<SourceKindMultiSuggestion<'a>>,
225}
226
227// Copy of `AnnotationRequired` for E0283
228#[derive(Diagnostic)]
229#[diag(trait_selection_type_annotations_needed, code = E0283)]
230pub struct AmbiguousImpl<'a> {
231    #[primary_span]
232    pub span: Span,
233    pub source_kind: &'static str,
234    pub source_name: &'a str,
235    #[label]
236    pub failure_span: Option<Span>,
237    #[subdiagnostic]
238    pub bad_label: Option<InferenceBadError<'a>>,
239    #[subdiagnostic]
240    pub infer_subdiags: Vec<SourceKindSubdiag<'a>>,
241    #[subdiagnostic]
242    pub multi_suggestions: Vec<SourceKindMultiSuggestion<'a>>,
243}
244
245// Copy of `AnnotationRequired` for E0284
246#[derive(Diagnostic)]
247#[diag(trait_selection_type_annotations_needed, code = E0284)]
248pub struct AmbiguousReturn<'a> {
249    #[primary_span]
250    pub span: Span,
251    pub source_kind: &'static str,
252    pub source_name: &'a str,
253    #[label]
254    pub failure_span: Option<Span>,
255    #[subdiagnostic]
256    pub bad_label: Option<InferenceBadError<'a>>,
257    #[subdiagnostic]
258    pub infer_subdiags: Vec<SourceKindSubdiag<'a>>,
259    #[subdiagnostic]
260    pub multi_suggestions: Vec<SourceKindMultiSuggestion<'a>>,
261}
262
263// Used when a better one isn't available
264#[derive(Subdiagnostic)]
265#[label(trait_selection_label_bad)]
266pub struct InferenceBadError<'a> {
267    #[primary_span]
268    pub span: Span,
269    pub bad_kind: &'static str,
270    pub prefix_kind: UnderspecifiedArgKind,
271    pub has_parent: bool,
272    pub prefix: &'a str,
273    pub parent_prefix: &'a str,
274    pub parent_name: String,
275    pub name: String,
276}
277
278#[derive(Subdiagnostic)]
279pub enum SourceKindSubdiag<'a> {
280    #[suggestion(
281        trait_selection_source_kind_subdiag_let,
282        style = "verbose",
283        code = ": {type_name}",
284        applicability = "has-placeholders"
285    )]
286    LetLike {
287        #[primary_span]
288        span: Span,
289        name: String,
290        type_name: String,
291        kind: &'static str,
292        x_kind: &'static str,
293        prefix_kind: UnderspecifiedArgKind,
294        prefix: &'a str,
295        arg_name: String,
296    },
297    #[label(trait_selection_source_kind_subdiag_generic_label)]
298    GenericLabel {
299        #[primary_span]
300        span: Span,
301        is_type: bool,
302        param_name: String,
303        parent_exists: bool,
304        parent_prefix: String,
305        parent_name: String,
306    },
307    #[suggestion(
308        trait_selection_source_kind_subdiag_generic_suggestion,
309        style = "verbose",
310        code = "::<{args}>",
311        applicability = "has-placeholders"
312    )]
313    GenericSuggestion {
314        #[primary_span]
315        span: Span,
316        arg_count: usize,
317        args: String,
318    },
319}
320
321#[derive(Subdiagnostic)]
322pub enum SourceKindMultiSuggestion<'a> {
323    #[multipart_suggestion(
324        trait_selection_source_kind_fully_qualified,
325        style = "verbose",
326        applicability = "has-placeholders"
327    )]
328    FullyQualified {
329        #[suggestion_part(code = "{def_path}({adjustment}")]
330        span_lo: Span,
331        #[suggestion_part(code = "{successor_pos}")]
332        span_hi: Span,
333        def_path: String,
334        adjustment: &'a str,
335        successor_pos: &'a str,
336    },
337    #[multipart_suggestion(
338        trait_selection_source_kind_closure_return,
339        style = "verbose",
340        applicability = "has-placeholders"
341    )]
342    ClosureReturn {
343        #[suggestion_part(code = "{start_span_code}")]
344        start_span: Span,
345        start_span_code: String,
346        #[suggestion_part(code = " }}")]
347        end_span: Option<Span>,
348    },
349}
350
351impl<'a> SourceKindMultiSuggestion<'a> {
352    pub fn new_fully_qualified(
353        span: Span,
354        def_path: String,
355        adjustment: &'a str,
356        successor: (&'a str, BytePos),
357    ) -> Self {
358        Self::FullyQualified {
359            span_lo: span.shrink_to_lo(),
360            span_hi: span.shrink_to_hi().with_hi(successor.1),
361            def_path,
362            adjustment,
363            successor_pos: successor.0,
364        }
365    }
366
367    pub fn new_closure_return(
368        ty_info: String,
369        data: &'a FnRetTy<'a>,
370        should_wrap_expr: Option<Span>,
371    ) -> Self {
372        let arrow = match data {
373            FnRetTy::DefaultReturn(_) => " -> ",
374            _ => "",
375        };
376        let (start_span, start_span_code, end_span) = match should_wrap_expr {
377            Some(end_span) => (data.span(), format!("{arrow}{ty_info} {{"), Some(end_span)),
378            None => (data.span(), format!("{arrow}{ty_info}"), None),
379        };
380        Self::ClosureReturn { start_span, start_span_code, end_span }
381    }
382}
383
384pub enum RegionOriginNote<'a> {
385    Plain {
386        span: Span,
387        msg: DiagMessage,
388    },
389    WithName {
390        span: Span,
391        msg: DiagMessage,
392        name: &'a str,
393        continues: bool,
394    },
395    WithRequirement {
396        span: Span,
397        requirement: ObligationCauseAsDiagArg<'a>,
398        expected_found: Option<(DiagStyledString, DiagStyledString)>,
399    },
400}
401
402impl Subdiagnostic for RegionOriginNote<'_> {
403    fn add_to_diag<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) {
404        let mut label_or_note = |span, msg: DiagMessage| {
405            let sub_count = diag.children.iter().filter(|d| d.span.is_dummy()).count();
406            let expanded_sub_count = diag.children.iter().filter(|d| !d.span.is_dummy()).count();
407            let span_is_primary = diag.span.primary_spans().iter().all(|&sp| sp == span);
408            if span_is_primary && sub_count == 0 && expanded_sub_count == 0 {
409                diag.span_label(span, msg);
410            } else if span_is_primary && expanded_sub_count == 0 {
411                diag.note(msg);
412            } else {
413                diag.span_note(span, msg);
414            }
415        };
416        match self {
417            RegionOriginNote::Plain { span, msg } => {
418                label_or_note(span, msg);
419            }
420            RegionOriginNote::WithName { span, msg, name, continues } => {
421                label_or_note(span, msg);
422                diag.arg("name", name);
423                diag.arg("continues", continues);
424            }
425            RegionOriginNote::WithRequirement {
426                span,
427                requirement,
428                expected_found: Some((expected, found)),
429            } => {
430                label_or_note(span, fluent::trait_selection_subtype);
431                diag.arg("requirement", requirement);
432
433                diag.note_expected_found("", expected, "", found);
434            }
435            RegionOriginNote::WithRequirement { span, requirement, expected_found: None } => {
436                // FIXME: this really should be handled at some earlier stage. Our
437                // handling of region checking when type errors are present is
438                // *terrible*.
439                label_or_note(span, fluent::trait_selection_subtype_2);
440                diag.arg("requirement", requirement);
441            }
442        };
443    }
444}
445
446pub enum LifetimeMismatchLabels {
447    InRet {
448        param_span: Span,
449        ret_span: Span,
450        span: Span,
451        label_var1: Option<Ident>,
452    },
453    Normal {
454        hir_equal: bool,
455        ty_sup: Span,
456        ty_sub: Span,
457        span: Span,
458        sup: Option<Ident>,
459        sub: Option<Ident>,
460    },
461}
462
463impl Subdiagnostic for LifetimeMismatchLabels {
464    fn add_to_diag<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) {
465        match self {
466            LifetimeMismatchLabels::InRet { param_span, ret_span, span, label_var1 } => {
467                diag.span_label(param_span, fluent::trait_selection_declared_different);
468                diag.span_label(ret_span, fluent::trait_selection_nothing);
469                diag.span_label(span, fluent::trait_selection_data_returned);
470                diag.arg("label_var1_exists", label_var1.is_some());
471                diag.arg("label_var1", label_var1.map(|x| x.to_string()).unwrap_or_default());
472            }
473            LifetimeMismatchLabels::Normal {
474                hir_equal,
475                ty_sup,
476                ty_sub,
477                span,
478                sup: label_var1,
479                sub: label_var2,
480            } => {
481                if hir_equal {
482                    diag.span_label(ty_sup, fluent::trait_selection_declared_multiple);
483                    diag.span_label(ty_sub, fluent::trait_selection_nothing);
484                    diag.span_label(span, fluent::trait_selection_data_lifetime_flow);
485                } else {
486                    diag.span_label(ty_sup, fluent::trait_selection_types_declared_different);
487                    diag.span_label(ty_sub, fluent::trait_selection_nothing);
488                    diag.span_label(span, fluent::trait_selection_data_flows);
489                    diag.arg("label_var1_exists", label_var1.is_some());
490                    diag.arg("label_var1", label_var1.map(|x| x.to_string()).unwrap_or_default());
491                    diag.arg("label_var2_exists", label_var2.is_some());
492                    diag.arg("label_var2", label_var2.map(|x| x.to_string()).unwrap_or_default());
493                }
494            }
495        }
496    }
497}
498
499pub struct AddLifetimeParamsSuggestion<'a> {
500    pub tcx: TyCtxt<'a>,
501    pub generic_param_scope: LocalDefId,
502    pub sub: Region<'a>,
503    pub ty_sup: &'a hir::Ty<'a>,
504    pub ty_sub: &'a hir::Ty<'a>,
505    pub add_note: bool,
506}
507
508impl Subdiagnostic for AddLifetimeParamsSuggestion<'_> {
509    fn add_to_diag<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) {
510        let mut mk_suggestion = || {
511            let Some(anon_reg) = self.tcx.is_suitable_region(self.generic_param_scope, self.sub)
512            else {
513                return false;
514            };
515
516            let node = self.tcx.hir_node_by_def_id(anon_reg.scope);
517            let is_impl = matches!(&node, hir::Node::ImplItem(_));
518            let (generics, parent_generics) = match node {
519                hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn { generics, .. }, .. })
520                | hir::Node::TraitItem(hir::TraitItem { generics, .. })
521                | hir::Node::ImplItem(hir::ImplItem { generics, .. }) => (
522                    generics,
523                    match self.tcx.parent_hir_node(self.tcx.local_def_id_to_hir_id(anon_reg.scope))
524                    {
525                        hir::Node::Item(hir::Item {
526                            kind: hir::ItemKind::Trait(_, _, _, _, generics, ..),
527                            ..
528                        })
529                        | hir::Node::Item(hir::Item {
530                            kind: hir::ItemKind::Impl(hir::Impl { generics, .. }),
531                            ..
532                        }) => Some(generics),
533                        _ => None,
534                    },
535                ),
536                _ => return false,
537            };
538
539            let suggestion_param_name = generics
540                .params
541                .iter()
542                .filter(|p| matches!(p.kind, GenericParamKind::Lifetime { .. }))
543                .map(|p| p.name.ident().name)
544                .find(|i| *i != kw::UnderscoreLifetime);
545            let introduce_new = suggestion_param_name.is_none();
546
547            let mut default = "'a".to_string();
548            if let Some(parent_generics) = parent_generics {
549                let used: FxHashSet<_> = parent_generics
550                    .params
551                    .iter()
552                    .filter(|p| matches!(p.kind, GenericParamKind::Lifetime { .. }))
553                    .map(|p| p.name.ident().name)
554                    .filter(|i| *i != kw::UnderscoreLifetime)
555                    .map(|l| l.to_string())
556                    .collect();
557                if let Some(lt) =
558                    ('a'..='z').map(|it| format!("'{it}")).find(|it| !used.contains(it))
559                {
560                    // We want a lifetime that *isn't* present in the `trait` or `impl` that assoc
561                    // `fn` belongs to. We could suggest reusing one of their lifetimes, but it is
562                    // likely to be an over-constraining lifetime requirement, so we always add a
563                    // lifetime to the `fn`.
564                    default = lt;
565                }
566            }
567            let suggestion_param_name =
568                suggestion_param_name.map(|n| n.to_string()).unwrap_or_else(|| default);
569
570            struct ImplicitLifetimeFinder {
571                suggestions: Vec<(Span, String)>,
572                suggestion_param_name: String,
573            }
574
575            impl<'v> Visitor<'v> for ImplicitLifetimeFinder {
576                fn visit_ty(&mut self, ty: &'v hir::Ty<'v, AmbigArg>) {
577                    match ty.kind {
578                        hir::TyKind::Path(hir::QPath::Resolved(_, path)) => {
579                            for segment in path.segments {
580                                if let Some(args) = segment.args {
581                                    if args.args.iter().all(|arg| {
582                                        matches!(
583                                            arg,
584                                            hir::GenericArg::Lifetime(lifetime)
585                                                if lifetime.is_implicit()
586                                        )
587                                    }) {
588                                        self.suggestions.push((
589                                            segment.ident.span.shrink_to_hi(),
590                                            format!(
591                                                "<{}>",
592                                                args.args
593                                                    .iter()
594                                                    .map(|_| self.suggestion_param_name.clone())
595                                                    .collect::<Vec<_>>()
596                                                    .join(", ")
597                                            ),
598                                        ));
599                                    } else {
600                                        for arg in args.args {
601                                            if let hir::GenericArg::Lifetime(lifetime) = arg
602                                                && lifetime.is_anonymous()
603                                            {
604                                                self.suggestions.push(
605                                                    lifetime
606                                                        .suggestion(&self.suggestion_param_name),
607                                                );
608                                            }
609                                        }
610                                    }
611                                }
612                            }
613                        }
614                        hir::TyKind::Ref(lifetime, ..) if lifetime.is_anonymous() => {
615                            self.suggestions.push(lifetime.suggestion(&self.suggestion_param_name));
616                        }
617                        _ => {}
618                    }
619                    walk_ty(self, ty);
620                }
621            }
622            let mut visitor = ImplicitLifetimeFinder {
623                suggestions: vec![],
624                suggestion_param_name: suggestion_param_name.clone(),
625            };
626            if let Some(fn_decl) = node.fn_decl()
627                && let hir::FnRetTy::Return(ty) = fn_decl.output
628            {
629                visitor.visit_ty_unambig(ty);
630            }
631            if visitor.suggestions.is_empty() {
632                // Do not suggest constraining the `&self` param, but rather the return type.
633                // If that is wrong (because it is not sufficient), a follow up error will tell the
634                // user to fix it. This way we lower the chances of *over* constraining, but still
635                // get the cake of "correctly" constrained in two steps.
636                visitor.visit_ty_unambig(self.ty_sup);
637            }
638            visitor.visit_ty_unambig(self.ty_sub);
639            if visitor.suggestions.is_empty() {
640                return false;
641            }
642            if introduce_new {
643                let new_param_suggestion = if let Some(first) =
644                    generics.params.iter().find(|p| !p.name.ident().span.is_empty())
645                {
646                    (first.span.shrink_to_lo(), format!("{suggestion_param_name}, "))
647                } else {
648                    (generics.span, format!("<{suggestion_param_name}>"))
649                };
650
651                visitor.suggestions.push(new_param_suggestion);
652            }
653            diag.multipart_suggestion_verbose(
654                fluent::trait_selection_lifetime_param_suggestion,
655                visitor.suggestions,
656                Applicability::MaybeIncorrect,
657            );
658            diag.arg("is_impl", is_impl);
659            diag.arg("is_reuse", !introduce_new);
660
661            true
662        };
663        if mk_suggestion() && self.add_note {
664            diag.note(fluent::trait_selection_lifetime_param_suggestion_elided);
665        }
666    }
667}
668
669#[derive(Diagnostic)]
670#[diag(trait_selection_lifetime_mismatch, code = E0623)]
671pub struct LifetimeMismatch<'a> {
672    #[primary_span]
673    pub span: Span,
674    #[subdiagnostic]
675    pub labels: LifetimeMismatchLabels,
676    #[subdiagnostic]
677    pub suggestion: AddLifetimeParamsSuggestion<'a>,
678}
679
680pub struct IntroducesStaticBecauseUnmetLifetimeReq {
681    pub unmet_requirements: MultiSpan,
682    pub binding_span: Span,
683}
684
685impl Subdiagnostic for IntroducesStaticBecauseUnmetLifetimeReq {
686    fn add_to_diag<G: EmissionGuarantee>(mut self, diag: &mut Diag<'_, G>) {
687        self.unmet_requirements
688            .push_span_label(self.binding_span, fluent::trait_selection_msl_introduces_static);
689        diag.span_note(self.unmet_requirements, fluent::trait_selection_msl_unmet_req);
690    }
691}
692
693// FIXME(#100717): replace with a `Option<Span>` when subdiagnostic supports that
694#[derive(Subdiagnostic)]
695pub enum DoesNotOutliveStaticFromImpl {
696    #[note(trait_selection_does_not_outlive_static_from_impl)]
697    Spanned {
698        #[primary_span]
699        span: Span,
700    },
701    #[note(trait_selection_does_not_outlive_static_from_impl)]
702    Unspanned,
703}
704
705#[derive(Subdiagnostic)]
706pub enum ImplicitStaticLifetimeSubdiag {
707    #[note(trait_selection_implicit_static_lifetime_note)]
708    Note {
709        #[primary_span]
710        span: Span,
711    },
712    #[suggestion(
713        trait_selection_implicit_static_lifetime_suggestion,
714        style = "verbose",
715        code = " + '_",
716        applicability = "maybe-incorrect"
717    )]
718    Sugg {
719        #[primary_span]
720        span: Span,
721    },
722}
723
724#[derive(Diagnostic)]
725#[diag(trait_selection_mismatched_static_lifetime)]
726pub struct MismatchedStaticLifetime<'a> {
727    #[primary_span]
728    pub cause_span: Span,
729    #[subdiagnostic]
730    pub unmet_lifetime_reqs: IntroducesStaticBecauseUnmetLifetimeReq,
731    #[subdiagnostic]
732    pub expl: Option<note_and_explain::RegionExplanation<'a>>,
733    #[subdiagnostic]
734    pub does_not_outlive_static_from_impl: DoesNotOutliveStaticFromImpl,
735    #[subdiagnostic]
736    pub implicit_static_lifetimes: Vec<ImplicitStaticLifetimeSubdiag>,
737}
738
739#[derive(Diagnostic)]
740pub enum ExplicitLifetimeRequired<'a> {
741    #[diag(trait_selection_explicit_lifetime_required_with_ident, code = E0621)]
742    WithIdent {
743        #[primary_span]
744        #[label]
745        span: Span,
746        simple_ident: Ident,
747        named: String,
748        #[suggestion(
749            trait_selection_explicit_lifetime_required_sugg_with_ident,
750            code = "{new_ty}",
751            applicability = "unspecified",
752            style = "verbose"
753        )]
754        new_ty_span: Span,
755        #[skip_arg]
756        new_ty: Ty<'a>,
757    },
758    #[diag(trait_selection_explicit_lifetime_required_with_param_type, code = E0621)]
759    WithParamType {
760        #[primary_span]
761        #[label]
762        span: Span,
763        named: String,
764        #[suggestion(
765            trait_selection_explicit_lifetime_required_sugg_with_param_type,
766            code = "{new_ty}",
767            applicability = "unspecified",
768            style = "verbose"
769        )]
770        new_ty_span: Span,
771        #[skip_arg]
772        new_ty: Ty<'a>,
773    },
774}
775
776pub enum TyOrSig<'tcx> {
777    Ty(Highlighted<'tcx, Ty<'tcx>>),
778    ClosureSig(Highlighted<'tcx, Binder<'tcx, FnSig<'tcx>>>),
779}
780
781impl IntoDiagArg for TyOrSig<'_> {
782    fn into_diag_arg(self, path: &mut Option<std::path::PathBuf>) -> rustc_errors::DiagArgValue {
783        match self {
784            TyOrSig::Ty(ty) => ty.into_diag_arg(path),
785            TyOrSig::ClosureSig(sig) => sig.into_diag_arg(path),
786        }
787    }
788}
789
790#[derive(Subdiagnostic)]
791pub enum ActualImplExplNotes<'tcx> {
792    #[note(trait_selection_actual_impl_expl_expected_signature_two)]
793    ExpectedSignatureTwo {
794        leading_ellipsis: bool,
795        ty_or_sig: TyOrSig<'tcx>,
796        trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>,
797        lifetime_1: usize,
798        lifetime_2: usize,
799    },
800    #[note(trait_selection_actual_impl_expl_expected_signature_any)]
801    ExpectedSignatureAny {
802        leading_ellipsis: bool,
803        ty_or_sig: TyOrSig<'tcx>,
804        trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>,
805        lifetime_1: usize,
806    },
807    #[note(trait_selection_actual_impl_expl_expected_signature_some)]
808    ExpectedSignatureSome {
809        leading_ellipsis: bool,
810        ty_or_sig: TyOrSig<'tcx>,
811        trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>,
812        lifetime_1: usize,
813    },
814    #[note(trait_selection_actual_impl_expl_expected_signature_nothing)]
815    ExpectedSignatureNothing {
816        leading_ellipsis: bool,
817        ty_or_sig: TyOrSig<'tcx>,
818        trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>,
819    },
820    #[note(trait_selection_actual_impl_expl_expected_passive_two)]
821    ExpectedPassiveTwo {
822        leading_ellipsis: bool,
823        ty_or_sig: TyOrSig<'tcx>,
824        trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>,
825        lifetime_1: usize,
826        lifetime_2: usize,
827    },
828    #[note(trait_selection_actual_impl_expl_expected_passive_any)]
829    ExpectedPassiveAny {
830        leading_ellipsis: bool,
831        ty_or_sig: TyOrSig<'tcx>,
832        trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>,
833        lifetime_1: usize,
834    },
835    #[note(trait_selection_actual_impl_expl_expected_passive_some)]
836    ExpectedPassiveSome {
837        leading_ellipsis: bool,
838        ty_or_sig: TyOrSig<'tcx>,
839        trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>,
840        lifetime_1: usize,
841    },
842    #[note(trait_selection_actual_impl_expl_expected_passive_nothing)]
843    ExpectedPassiveNothing {
844        leading_ellipsis: bool,
845        ty_or_sig: TyOrSig<'tcx>,
846        trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>,
847    },
848    #[note(trait_selection_actual_impl_expl_expected_other_two)]
849    ExpectedOtherTwo {
850        leading_ellipsis: bool,
851        ty_or_sig: TyOrSig<'tcx>,
852        trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>,
853        lifetime_1: usize,
854        lifetime_2: usize,
855    },
856    #[note(trait_selection_actual_impl_expl_expected_other_any)]
857    ExpectedOtherAny {
858        leading_ellipsis: bool,
859        ty_or_sig: TyOrSig<'tcx>,
860        trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>,
861        lifetime_1: usize,
862    },
863    #[note(trait_selection_actual_impl_expl_expected_other_some)]
864    ExpectedOtherSome {
865        leading_ellipsis: bool,
866        ty_or_sig: TyOrSig<'tcx>,
867        trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>,
868        lifetime_1: usize,
869    },
870    #[note(trait_selection_actual_impl_expl_expected_other_nothing)]
871    ExpectedOtherNothing {
872        leading_ellipsis: bool,
873        ty_or_sig: TyOrSig<'tcx>,
874        trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>,
875    },
876    #[note(trait_selection_actual_impl_expl_but_actually_implements_trait)]
877    ButActuallyImplementsTrait {
878        trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>,
879        has_lifetime: bool,
880        lifetime: usize,
881    },
882    #[note(trait_selection_actual_impl_expl_but_actually_implemented_for_ty)]
883    ButActuallyImplementedForTy {
884        trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>,
885        has_lifetime: bool,
886        lifetime: usize,
887        ty: String,
888    },
889    #[note(trait_selection_actual_impl_expl_but_actually_ty_implements)]
890    ButActuallyTyImplements {
891        trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>,
892        has_lifetime: bool,
893        lifetime: usize,
894        ty: String,
895    },
896}
897
898pub enum ActualImplExpectedKind {
899    Signature,
900    Passive,
901    Other,
902}
903
904pub enum ActualImplExpectedLifetimeKind {
905    Two,
906    Any,
907    Some,
908    Nothing,
909}
910
911impl<'tcx> ActualImplExplNotes<'tcx> {
912    pub fn new_expected(
913        kind: ActualImplExpectedKind,
914        lt_kind: ActualImplExpectedLifetimeKind,
915        leading_ellipsis: bool,
916        ty_or_sig: TyOrSig<'tcx>,
917        trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>,
918        lifetime_1: usize,
919        lifetime_2: usize,
920    ) -> Self {
921        match (kind, lt_kind) {
922            (ActualImplExpectedKind::Signature, ActualImplExpectedLifetimeKind::Two) => {
923                Self::ExpectedSignatureTwo {
924                    leading_ellipsis,
925                    ty_or_sig,
926                    trait_path,
927                    lifetime_1,
928                    lifetime_2,
929                }
930            }
931            (ActualImplExpectedKind::Signature, ActualImplExpectedLifetimeKind::Any) => {
932                Self::ExpectedSignatureAny { leading_ellipsis, ty_or_sig, trait_path, lifetime_1 }
933            }
934            (ActualImplExpectedKind::Signature, ActualImplExpectedLifetimeKind::Some) => {
935                Self::ExpectedSignatureSome { leading_ellipsis, ty_or_sig, trait_path, lifetime_1 }
936            }
937            (ActualImplExpectedKind::Signature, ActualImplExpectedLifetimeKind::Nothing) => {
938                Self::ExpectedSignatureNothing { leading_ellipsis, ty_or_sig, trait_path }
939            }
940            (ActualImplExpectedKind::Passive, ActualImplExpectedLifetimeKind::Two) => {
941                Self::ExpectedPassiveTwo {
942                    leading_ellipsis,
943                    ty_or_sig,
944                    trait_path,
945                    lifetime_1,
946                    lifetime_2,
947                }
948            }
949            (ActualImplExpectedKind::Passive, ActualImplExpectedLifetimeKind::Any) => {
950                Self::ExpectedPassiveAny { leading_ellipsis, ty_or_sig, trait_path, lifetime_1 }
951            }
952            (ActualImplExpectedKind::Passive, ActualImplExpectedLifetimeKind::Some) => {
953                Self::ExpectedPassiveSome { leading_ellipsis, ty_or_sig, trait_path, lifetime_1 }
954            }
955            (ActualImplExpectedKind::Passive, ActualImplExpectedLifetimeKind::Nothing) => {
956                Self::ExpectedPassiveNothing { leading_ellipsis, ty_or_sig, trait_path }
957            }
958            (ActualImplExpectedKind::Other, ActualImplExpectedLifetimeKind::Two) => {
959                Self::ExpectedOtherTwo {
960                    leading_ellipsis,
961                    ty_or_sig,
962                    trait_path,
963                    lifetime_1,
964                    lifetime_2,
965                }
966            }
967            (ActualImplExpectedKind::Other, ActualImplExpectedLifetimeKind::Any) => {
968                Self::ExpectedOtherAny { leading_ellipsis, ty_or_sig, trait_path, lifetime_1 }
969            }
970            (ActualImplExpectedKind::Other, ActualImplExpectedLifetimeKind::Some) => {
971                Self::ExpectedOtherSome { leading_ellipsis, ty_or_sig, trait_path, lifetime_1 }
972            }
973            (ActualImplExpectedKind::Other, ActualImplExpectedLifetimeKind::Nothing) => {
974                Self::ExpectedOtherNothing { leading_ellipsis, ty_or_sig, trait_path }
975            }
976        }
977    }
978}
979
980#[derive(Diagnostic)]
981#[diag(trait_selection_trait_placeholder_mismatch)]
982pub struct TraitPlaceholderMismatch<'tcx> {
983    #[primary_span]
984    pub span: Span,
985    #[label(trait_selection_label_satisfy)]
986    pub satisfy_span: Option<Span>,
987    #[label(trait_selection_label_where)]
988    pub where_span: Option<Span>,
989    #[label(trait_selection_label_dup)]
990    pub dup_span: Option<Span>,
991    pub def_id: String,
992    pub trait_def_id: String,
993
994    #[subdiagnostic]
995    pub actual_impl_expl_notes: Vec<ActualImplExplNotes<'tcx>>,
996}
997
998pub struct ConsiderBorrowingParamHelp {
999    pub spans: Vec<Span>,
1000}
1001
1002impl Subdiagnostic for ConsiderBorrowingParamHelp {
1003    fn add_to_diag<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) {
1004        let mut type_param_span: MultiSpan = self.spans.clone().into();
1005        for &span in &self.spans {
1006            // Seems like we can't call f() here as Into<DiagMessage> is required
1007            type_param_span.push_span_label(span, fluent::trait_selection_tid_consider_borrowing);
1008        }
1009        let msg = diag.eagerly_translate(fluent::trait_selection_tid_param_help);
1010        diag.span_help(type_param_span, msg);
1011    }
1012}
1013
1014#[derive(Subdiagnostic)]
1015#[help(trait_selection_tid_rel_help)]
1016pub struct RelationshipHelp;
1017
1018#[derive(Diagnostic)]
1019#[diag(trait_selection_trait_impl_diff)]
1020pub struct TraitImplDiff {
1021    #[primary_span]
1022    #[label(trait_selection_found)]
1023    pub sp: Span,
1024    #[label(trait_selection_expected)]
1025    pub trait_sp: Span,
1026    #[note(trait_selection_expected_found)]
1027    pub note: (),
1028    #[subdiagnostic]
1029    pub param_help: ConsiderBorrowingParamHelp,
1030    #[subdiagnostic]
1031    // Seems like subdiagnostics are always pushed to the end, so this one
1032    // also has to be a subdiagnostic to maintain order.
1033    pub rel_help: Option<RelationshipHelp>,
1034    pub expected: String,
1035    pub found: String,
1036}
1037
1038pub struct DynTraitConstraintSuggestion {
1039    pub span: Span,
1040    pub ident: Ident,
1041}
1042
1043impl Subdiagnostic for DynTraitConstraintSuggestion {
1044    fn add_to_diag<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) {
1045        let mut multi_span: MultiSpan = vec![self.span].into();
1046        multi_span.push_span_label(self.span, fluent::trait_selection_dtcs_has_lifetime_req_label);
1047        multi_span
1048            .push_span_label(self.ident.span, fluent::trait_selection_dtcs_introduces_requirement);
1049        let msg = diag.eagerly_translate(fluent::trait_selection_dtcs_has_req_note);
1050        diag.span_note(multi_span, msg);
1051        let msg = diag.eagerly_translate(fluent::trait_selection_dtcs_suggestion);
1052        diag.span_suggestion_verbose(
1053            self.span.shrink_to_hi(),
1054            msg,
1055            " + '_",
1056            Applicability::MaybeIncorrect,
1057        );
1058    }
1059}
1060
1061#[derive(Diagnostic)]
1062#[diag(trait_selection_but_calling_introduces, code = E0772)]
1063pub struct ButCallingIntroduces {
1064    #[label(trait_selection_label1)]
1065    pub param_ty_span: Span,
1066    #[primary_span]
1067    #[label(trait_selection_label2)]
1068    pub cause_span: Span,
1069
1070    pub has_param_name: bool,
1071    pub param_name: String,
1072    pub has_lifetime: bool,
1073    pub lifetime: String,
1074    pub assoc_item: Symbol,
1075    pub has_impl_path: bool,
1076    pub impl_path: String,
1077}
1078
1079pub struct ReqIntroducedLocations {
1080    pub span: MultiSpan,
1081    pub spans: Vec<Span>,
1082    pub fn_decl_span: Span,
1083    pub cause_span: Span,
1084    pub add_label: bool,
1085}
1086
1087impl Subdiagnostic for ReqIntroducedLocations {
1088    fn add_to_diag<G: EmissionGuarantee>(mut self, diag: &mut Diag<'_, G>) {
1089        for sp in self.spans {
1090            self.span.push_span_label(sp, fluent::trait_selection_ril_introduced_here);
1091        }
1092
1093        if self.add_label {
1094            self.span.push_span_label(self.fn_decl_span, fluent::trait_selection_ril_introduced_by);
1095        }
1096        self.span.push_span_label(self.cause_span, fluent::trait_selection_ril_because_of);
1097        let msg = diag.eagerly_translate(fluent::trait_selection_ril_static_introduced_by);
1098        diag.span_note(self.span, msg);
1099    }
1100}
1101
1102#[derive(Diagnostic)]
1103#[diag(trait_selection_but_needs_to_satisfy, code = E0759)]
1104pub struct ButNeedsToSatisfy {
1105    #[primary_span]
1106    pub sp: Span,
1107    #[label(trait_selection_influencer)]
1108    pub influencer_point: Span,
1109    #[label(trait_selection_used_here)]
1110    pub spans: Vec<Span>,
1111    #[label(trait_selection_require)]
1112    pub require_span_as_label: Option<Span>,
1113    #[note(trait_selection_require)]
1114    pub require_span_as_note: Option<Span>,
1115    #[note(trait_selection_introduced_by_bound)]
1116    pub bound: Option<Span>,
1117
1118    pub has_param_name: bool,
1119    pub param_name: String,
1120    pub spans_empty: bool,
1121    pub has_lifetime: bool,
1122    pub lifetime: String,
1123}
1124
1125#[derive(Diagnostic)]
1126#[diag(trait_selection_outlives_content, code = E0312)]
1127pub struct OutlivesContent<'a> {
1128    #[primary_span]
1129    pub span: Span,
1130    #[subdiagnostic]
1131    pub notes: Vec<note_and_explain::RegionExplanation<'a>>,
1132}
1133
1134#[derive(Diagnostic)]
1135#[diag(trait_selection_outlives_bound, code = E0476)]
1136pub struct OutlivesBound<'a> {
1137    #[primary_span]
1138    pub span: Span,
1139    #[subdiagnostic]
1140    pub notes: Vec<note_and_explain::RegionExplanation<'a>>,
1141}
1142
1143#[derive(Diagnostic)]
1144#[diag(trait_selection_fulfill_req_lifetime, code = E0477)]
1145pub struct FulfillReqLifetime<'a> {
1146    #[primary_span]
1147    pub span: Span,
1148    pub ty: Ty<'a>,
1149    #[subdiagnostic]
1150    pub note: Option<note_and_explain::RegionExplanation<'a>>,
1151}
1152
1153#[derive(Diagnostic)]
1154#[diag(trait_selection_lf_bound_not_satisfied, code = E0478)]
1155pub struct LfBoundNotSatisfied<'a> {
1156    #[primary_span]
1157    pub span: Span,
1158    #[subdiagnostic]
1159    pub notes: Vec<note_and_explain::RegionExplanation<'a>>,
1160}
1161
1162#[derive(Diagnostic)]
1163#[diag(trait_selection_ref_longer_than_data, code = E0491)]
1164pub struct RefLongerThanData<'a> {
1165    #[primary_span]
1166    pub span: Span,
1167    pub ty: Ty<'a>,
1168    #[subdiagnostic]
1169    pub notes: Vec<note_and_explain::RegionExplanation<'a>>,
1170}
1171
1172#[derive(Subdiagnostic)]
1173pub enum WhereClauseSuggestions {
1174    #[suggestion(
1175        trait_selection_where_remove,
1176        code = "",
1177        applicability = "machine-applicable",
1178        style = "verbose"
1179    )]
1180    Remove {
1181        #[primary_span]
1182        span: Span,
1183    },
1184    #[suggestion(
1185        trait_selection_where_copy_predicates,
1186        code = "{space}where {trait_predicates}",
1187        applicability = "machine-applicable",
1188        style = "verbose"
1189    )]
1190    CopyPredicates {
1191        #[primary_span]
1192        span: Span,
1193        space: &'static str,
1194        trait_predicates: String,
1195    },
1196}
1197
1198#[derive(Subdiagnostic)]
1199pub enum SuggestRemoveSemiOrReturnBinding {
1200    #[multipart_suggestion(
1201        trait_selection_srs_remove_and_box,
1202        applicability = "machine-applicable"
1203    )]
1204    RemoveAndBox {
1205        #[suggestion_part(code = "Box::new(")]
1206        first_lo: Span,
1207        #[suggestion_part(code = ")")]
1208        first_hi: Span,
1209        #[suggestion_part(code = "Box::new(")]
1210        second_lo: Span,
1211        #[suggestion_part(code = ")")]
1212        second_hi: Span,
1213        #[suggestion_part(code = "")]
1214        sp: Span,
1215    },
1216    #[suggestion(
1217        trait_selection_srs_remove,
1218        style = "short",
1219        code = "",
1220        applicability = "machine-applicable"
1221    )]
1222    Remove {
1223        #[primary_span]
1224        sp: Span,
1225    },
1226    #[suggestion(
1227        trait_selection_srs_add,
1228        style = "verbose",
1229        code = "{code}",
1230        applicability = "maybe-incorrect"
1231    )]
1232    Add {
1233        #[primary_span]
1234        sp: Span,
1235        code: String,
1236        ident: Ident,
1237    },
1238    #[note(trait_selection_srs_add_one)]
1239    AddOne {
1240        #[primary_span]
1241        spans: MultiSpan,
1242    },
1243}
1244
1245#[derive(Subdiagnostic)]
1246pub enum ConsiderAddingAwait {
1247    #[help(trait_selection_await_both_futures)]
1248    BothFuturesHelp,
1249    #[multipart_suggestion(trait_selection_await_both_futures, applicability = "maybe-incorrect")]
1250    BothFuturesSugg {
1251        #[suggestion_part(code = ".await")]
1252        first: Span,
1253        #[suggestion_part(code = ".await")]
1254        second: Span,
1255    },
1256    #[suggestion(
1257        trait_selection_await_future,
1258        code = ".await",
1259        style = "verbose",
1260        applicability = "maybe-incorrect"
1261    )]
1262    FutureSugg {
1263        #[primary_span]
1264        span: Span,
1265    },
1266    #[note(trait_selection_await_note)]
1267    FutureSuggNote {
1268        #[primary_span]
1269        span: Span,
1270    },
1271    #[multipart_suggestion(
1272        trait_selection_await_future,
1273        style = "verbose",
1274        applicability = "maybe-incorrect"
1275    )]
1276    FutureSuggMultiple {
1277        #[suggestion_part(code = ".await")]
1278        spans: Vec<Span>,
1279    },
1280}
1281
1282#[derive(Diagnostic)]
1283pub enum PlaceholderRelationLfNotSatisfied {
1284    #[diag(trait_selection_lf_bound_not_satisfied)]
1285    HasBoth {
1286        #[primary_span]
1287        span: Span,
1288        #[note(trait_selection_prlf_defined_with_sub)]
1289        sub_span: Span,
1290        #[note(trait_selection_prlf_must_outlive_with_sup)]
1291        sup_span: Span,
1292        sub_symbol: Symbol,
1293        sup_symbol: Symbol,
1294        #[note(trait_selection_prlf_known_limitation)]
1295        note: (),
1296    },
1297    #[diag(trait_selection_lf_bound_not_satisfied)]
1298    HasSub {
1299        #[primary_span]
1300        span: Span,
1301        #[note(trait_selection_prlf_defined_with_sub)]
1302        sub_span: Span,
1303        #[note(trait_selection_prlf_must_outlive_without_sup)]
1304        sup_span: Span,
1305        sub_symbol: Symbol,
1306        #[note(trait_selection_prlf_known_limitation)]
1307        note: (),
1308    },
1309    #[diag(trait_selection_lf_bound_not_satisfied)]
1310    HasSup {
1311        #[primary_span]
1312        span: Span,
1313        #[note(trait_selection_prlf_defined_without_sub)]
1314        sub_span: Span,
1315        #[note(trait_selection_prlf_must_outlive_with_sup)]
1316        sup_span: Span,
1317        sup_symbol: Symbol,
1318        #[note(trait_selection_prlf_known_limitation)]
1319        note: (),
1320    },
1321    #[diag(trait_selection_lf_bound_not_satisfied)]
1322    HasNone {
1323        #[primary_span]
1324        span: Span,
1325        #[note(trait_selection_prlf_defined_without_sub)]
1326        sub_span: Span,
1327        #[note(trait_selection_prlf_must_outlive_without_sup)]
1328        sup_span: Span,
1329        #[note(trait_selection_prlf_known_limitation)]
1330        note: (),
1331    },
1332    #[diag(trait_selection_lf_bound_not_satisfied)]
1333    OnlyPrimarySpan {
1334        #[primary_span]
1335        span: Span,
1336        #[note(trait_selection_prlf_known_limitation)]
1337        note: (),
1338    },
1339}
1340
1341#[derive(Diagnostic)]
1342#[diag(trait_selection_opaque_captures_lifetime, code = E0700)]
1343pub struct OpaqueCapturesLifetime<'tcx> {
1344    #[primary_span]
1345    pub span: Span,
1346    #[label]
1347    pub opaque_ty_span: Span,
1348    pub opaque_ty: Ty<'tcx>,
1349}
1350
1351#[derive(Subdiagnostic)]
1352pub enum FunctionPointerSuggestion<'a> {
1353    #[suggestion(
1354        trait_selection_fps_use_ref,
1355        code = "&",
1356        style = "verbose",
1357        applicability = "maybe-incorrect"
1358    )]
1359    UseRef {
1360        #[primary_span]
1361        span: Span,
1362    },
1363    #[suggestion(
1364        trait_selection_fps_remove_ref,
1365        code = "{fn_name}",
1366        style = "verbose",
1367        applicability = "maybe-incorrect"
1368    )]
1369    RemoveRef {
1370        #[primary_span]
1371        span: Span,
1372        #[skip_arg]
1373        fn_name: String,
1374    },
1375    #[suggestion(
1376        trait_selection_fps_cast,
1377        code = "&({fn_name} as {sig})",
1378        style = "verbose",
1379        applicability = "maybe-incorrect"
1380    )]
1381    CastRef {
1382        #[primary_span]
1383        span: Span,
1384        #[skip_arg]
1385        fn_name: String,
1386        #[skip_arg]
1387        sig: Binder<'a, FnSig<'a>>,
1388    },
1389    #[suggestion(
1390        trait_selection_fps_cast,
1391        code = " as {sig}",
1392        style = "verbose",
1393        applicability = "maybe-incorrect"
1394    )]
1395    Cast {
1396        #[primary_span]
1397        span: Span,
1398        #[skip_arg]
1399        sig: Binder<'a, FnSig<'a>>,
1400    },
1401    #[suggestion(
1402        trait_selection_fps_cast_both,
1403        code = " as {found_sig}",
1404        style = "hidden",
1405        applicability = "maybe-incorrect"
1406    )]
1407    CastBoth {
1408        #[primary_span]
1409        span: Span,
1410        #[skip_arg]
1411        found_sig: Binder<'a, FnSig<'a>>,
1412        expected_sig: Binder<'a, FnSig<'a>>,
1413    },
1414    #[suggestion(
1415        trait_selection_fps_cast_both,
1416        code = "&({fn_name} as {found_sig})",
1417        style = "hidden",
1418        applicability = "maybe-incorrect"
1419    )]
1420    CastBothRef {
1421        #[primary_span]
1422        span: Span,
1423        #[skip_arg]
1424        fn_name: String,
1425        #[skip_arg]
1426        found_sig: Binder<'a, FnSig<'a>>,
1427        expected_sig: Binder<'a, FnSig<'a>>,
1428    },
1429}
1430
1431#[derive(Subdiagnostic)]
1432#[note(trait_selection_fps_items_are_distinct)]
1433pub struct FnItemsAreDistinct;
1434
1435#[derive(Subdiagnostic)]
1436#[note(trait_selection_fn_uniq_types)]
1437pub struct FnUniqTypes;
1438
1439#[derive(Subdiagnostic)]
1440#[help(trait_selection_fn_consider_casting)]
1441pub struct FnConsiderCasting {
1442    pub casting: String,
1443}
1444
1445#[derive(Subdiagnostic)]
1446#[help(trait_selection_fn_consider_casting_both)]
1447pub struct FnConsiderCastingBoth<'a> {
1448    pub sig: Binder<'a, FnSig<'a>>,
1449}
1450
1451#[derive(Subdiagnostic)]
1452pub enum SuggestAccessingField<'a> {
1453    #[suggestion(
1454        trait_selection_suggest_accessing_field,
1455        code = "{snippet}.{name}",
1456        applicability = "maybe-incorrect",
1457        style = "verbose"
1458    )]
1459    Safe {
1460        #[primary_span]
1461        span: Span,
1462        snippet: String,
1463        name: Symbol,
1464        ty: Ty<'a>,
1465    },
1466    #[suggestion(
1467        trait_selection_suggest_accessing_field,
1468        code = "unsafe {{ {snippet}.{name} }}",
1469        applicability = "maybe-incorrect",
1470        style = "verbose"
1471    )]
1472    Unsafe {
1473        #[primary_span]
1474        span: Span,
1475        snippet: String,
1476        name: Symbol,
1477        ty: Ty<'a>,
1478    },
1479}
1480
1481#[derive(Subdiagnostic)]
1482#[multipart_suggestion(trait_selection_stp_wrap_one, applicability = "maybe-incorrect")]
1483pub struct SuggestTuplePatternOne {
1484    pub variant: String,
1485    #[suggestion_part(code = "{variant}(")]
1486    pub span_low: Span,
1487    #[suggestion_part(code = ")")]
1488    pub span_high: Span,
1489}
1490
1491pub struct SuggestTuplePatternMany {
1492    pub path: String,
1493    pub cause_span: Span,
1494    pub compatible_variants: Vec<String>,
1495}
1496
1497impl Subdiagnostic for SuggestTuplePatternMany {
1498    fn add_to_diag<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) {
1499        diag.arg("path", self.path);
1500        let message = diag.eagerly_translate(fluent::trait_selection_stp_wrap_many);
1501        diag.multipart_suggestions(
1502            message,
1503            self.compatible_variants.into_iter().map(|variant| {
1504                vec![
1505                    (self.cause_span.shrink_to_lo(), format!("{variant}(")),
1506                    (self.cause_span.shrink_to_hi(), ")".to_string()),
1507                ]
1508            }),
1509            rustc_errors::Applicability::MaybeIncorrect,
1510        );
1511    }
1512}
1513
1514#[derive(Subdiagnostic)]
1515pub enum TypeErrorAdditionalDiags {
1516    #[suggestion(
1517        trait_selection_meant_byte_literal,
1518        code = "b'{code}'",
1519        applicability = "machine-applicable"
1520    )]
1521    MeantByteLiteral {
1522        #[primary_span]
1523        span: Span,
1524        code: String,
1525    },
1526    #[suggestion(
1527        trait_selection_meant_char_literal,
1528        code = "'{code}'",
1529        applicability = "machine-applicable"
1530    )]
1531    MeantCharLiteral {
1532        #[primary_span]
1533        span: Span,
1534        code: String,
1535    },
1536    #[multipart_suggestion(trait_selection_meant_str_literal, applicability = "machine-applicable")]
1537    MeantStrLiteral {
1538        #[suggestion_part(code = "\"")]
1539        start: Span,
1540        #[suggestion_part(code = "\"")]
1541        end: Span,
1542    },
1543    #[suggestion(
1544        trait_selection_consider_specifying_length,
1545        code = "{length}",
1546        applicability = "maybe-incorrect"
1547    )]
1548    ConsiderSpecifyingLength {
1549        #[primary_span]
1550        span: Span,
1551        length: u64,
1552    },
1553    #[note(trait_selection_try_cannot_convert)]
1554    TryCannotConvert { found: String, expected: String },
1555    #[suggestion(
1556        trait_selection_tuple_trailing_comma,
1557        code = ",",
1558        applicability = "machine-applicable"
1559    )]
1560    TupleOnlyComma {
1561        #[primary_span]
1562        span: Span,
1563    },
1564    #[multipart_suggestion(
1565        trait_selection_tuple_trailing_comma,
1566        applicability = "machine-applicable"
1567    )]
1568    TupleAlsoParentheses {
1569        #[suggestion_part(code = "(")]
1570        span_low: Span,
1571        #[suggestion_part(code = ",)")]
1572        span_high: Span,
1573    },
1574    #[suggestion(
1575        trait_selection_suggest_add_let_for_letchains,
1576        style = "verbose",
1577        applicability = "machine-applicable",
1578        code = "let "
1579    )]
1580    AddLetForLetChains {
1581        #[primary_span]
1582        span: Span,
1583    },
1584}
1585
1586#[derive(Diagnostic)]
1587pub enum ObligationCauseFailureCode {
1588    #[diag(trait_selection_oc_method_compat, code = E0308)]
1589    MethodCompat {
1590        #[primary_span]
1591        span: Span,
1592        #[subdiagnostic]
1593        subdiags: Vec<TypeErrorAdditionalDiags>,
1594    },
1595    #[diag(trait_selection_oc_type_compat, code = E0308)]
1596    TypeCompat {
1597        #[primary_span]
1598        span: Span,
1599        #[subdiagnostic]
1600        subdiags: Vec<TypeErrorAdditionalDiags>,
1601    },
1602    #[diag(trait_selection_oc_const_compat, code = E0308)]
1603    ConstCompat {
1604        #[primary_span]
1605        span: Span,
1606        #[subdiagnostic]
1607        subdiags: Vec<TypeErrorAdditionalDiags>,
1608    },
1609    #[diag(trait_selection_oc_try_compat, code = E0308)]
1610    TryCompat {
1611        #[primary_span]
1612        span: Span,
1613        #[subdiagnostic]
1614        subdiags: Vec<TypeErrorAdditionalDiags>,
1615    },
1616    #[diag(trait_selection_oc_match_compat, code = E0308)]
1617    MatchCompat {
1618        #[primary_span]
1619        span: Span,
1620        #[subdiagnostic]
1621        subdiags: Vec<TypeErrorAdditionalDiags>,
1622    },
1623    #[diag(trait_selection_oc_if_else_different, code = E0308)]
1624    IfElseDifferent {
1625        #[primary_span]
1626        span: Span,
1627        #[subdiagnostic]
1628        subdiags: Vec<TypeErrorAdditionalDiags>,
1629    },
1630    #[diag(trait_selection_oc_no_else, code = E0317)]
1631    NoElse {
1632        #[primary_span]
1633        span: Span,
1634    },
1635    #[diag(trait_selection_oc_no_diverge, code = E0308)]
1636    NoDiverge {
1637        #[primary_span]
1638        span: Span,
1639        #[subdiagnostic]
1640        subdiags: Vec<TypeErrorAdditionalDiags>,
1641    },
1642    #[diag(trait_selection_oc_fn_main_correct_type, code = E0580)]
1643    FnMainCorrectType {
1644        #[primary_span]
1645        span: Span,
1646    },
1647    #[diag(trait_selection_oc_fn_lang_correct_type, code = E0308)]
1648    FnLangCorrectType {
1649        #[primary_span]
1650        span: Span,
1651        #[subdiagnostic]
1652        subdiags: Vec<TypeErrorAdditionalDiags>,
1653        lang_item_name: Symbol,
1654    },
1655    #[diag(trait_selection_oc_intrinsic_correct_type, code = E0308)]
1656    IntrinsicCorrectType {
1657        #[primary_span]
1658        span: Span,
1659        #[subdiagnostic]
1660        subdiags: Vec<TypeErrorAdditionalDiags>,
1661    },
1662    #[diag(trait_selection_oc_method_correct_type, code = E0308)]
1663    MethodCorrectType {
1664        #[primary_span]
1665        span: Span,
1666        #[subdiagnostic]
1667        subdiags: Vec<TypeErrorAdditionalDiags>,
1668    },
1669    #[diag(trait_selection_oc_closure_selfref, code = E0644)]
1670    ClosureSelfref {
1671        #[primary_span]
1672        span: Span,
1673    },
1674    #[diag(trait_selection_oc_cant_coerce_force_inline, code = E0308)]
1675    CantCoerceForceInline {
1676        #[primary_span]
1677        span: Span,
1678        #[subdiagnostic]
1679        subdiags: Vec<TypeErrorAdditionalDiags>,
1680    },
1681    #[diag(trait_selection_oc_cant_coerce_intrinsic, code = E0308)]
1682    CantCoerceIntrinsic {
1683        #[primary_span]
1684        span: Span,
1685        #[subdiagnostic]
1686        subdiags: Vec<TypeErrorAdditionalDiags>,
1687    },
1688    #[diag(trait_selection_oc_generic, code = E0308)]
1689    Generic {
1690        #[primary_span]
1691        span: Span,
1692        #[subdiagnostic]
1693        subdiags: Vec<TypeErrorAdditionalDiags>,
1694    },
1695}
1696
1697#[derive(Subdiagnostic)]
1698pub enum AddPreciseCapturing {
1699    #[suggestion(
1700        trait_selection_precise_capturing_new,
1701        style = "verbose",
1702        code = " + use<{concatenated_bounds}>",
1703        applicability = "machine-applicable"
1704    )]
1705    New {
1706        #[primary_span]
1707        span: Span,
1708        new_lifetime: Symbol,
1709        concatenated_bounds: String,
1710    },
1711    #[suggestion(
1712        trait_selection_precise_capturing_existing,
1713        style = "verbose",
1714        code = "{pre}{new_lifetime}{post}",
1715        applicability = "machine-applicable"
1716    )]
1717    Existing {
1718        #[primary_span]
1719        span: Span,
1720        new_lifetime: Symbol,
1721        pre: &'static str,
1722        post: &'static str,
1723    },
1724}
1725
1726pub struct AddPreciseCapturingAndParams {
1727    pub suggs: Vec<(Span, String)>,
1728    pub new_lifetime: Symbol,
1729    pub apit_spans: Vec<Span>,
1730}
1731
1732impl Subdiagnostic for AddPreciseCapturingAndParams {
1733    fn add_to_diag<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) {
1734        diag.arg("new_lifetime", self.new_lifetime);
1735        diag.multipart_suggestion_verbose(
1736            fluent::trait_selection_precise_capturing_new_but_apit,
1737            self.suggs,
1738            Applicability::MaybeIncorrect,
1739        );
1740        diag.span_note(
1741            self.apit_spans,
1742            fluent::trait_selection_warn_removing_apit_params_for_undercapture,
1743        );
1744    }
1745}
1746
1747/// Given a set of captured `DefId` for an RPIT (opaque_def_id) and a given
1748/// function (fn_def_id), try to suggest adding `+ use<...>` to capture just
1749/// the specified parameters. If one of those parameters is an APIT, then try
1750/// to suggest turning it into a regular type parameter.
1751pub fn impl_trait_overcapture_suggestion<'tcx>(
1752    tcx: TyCtxt<'tcx>,
1753    opaque_def_id: LocalDefId,
1754    fn_def_id: LocalDefId,
1755    captured_args: FxIndexSet<DefId>,
1756) -> Option<AddPreciseCapturingForOvercapture> {
1757    let generics = tcx.generics_of(fn_def_id);
1758
1759    let mut captured_lifetimes = FxIndexSet::default();
1760    let mut captured_non_lifetimes = FxIndexSet::default();
1761    let mut synthetics = vec![];
1762
1763    for arg in captured_args {
1764        if tcx.def_kind(arg) == DefKind::LifetimeParam {
1765            captured_lifetimes.insert(tcx.item_name(arg));
1766        } else {
1767            let idx = generics.param_def_id_to_index(tcx, arg).expect("expected arg in scope");
1768            let param = generics.param_at(idx as usize, tcx);
1769            if param.kind.is_synthetic() {
1770                synthetics.push((tcx.def_span(arg), param.name));
1771            } else {
1772                captured_non_lifetimes.insert(tcx.item_name(arg));
1773            }
1774        }
1775    }
1776
1777    let mut next_fresh_param = || {
1778        ["T", "U", "V", "W", "X", "Y", "A", "B", "C"]
1779            .into_iter()
1780            .map(Symbol::intern)
1781            .chain((0..).map(|i| Symbol::intern(&format!("T{i}"))))
1782            .find(|s| captured_non_lifetimes.insert(*s))
1783            .unwrap()
1784    };
1785
1786    let mut suggs = vec![];
1787    let mut apit_spans = vec![];
1788
1789    if !synthetics.is_empty() {
1790        let mut new_params = String::new();
1791        for (i, (span, name)) in synthetics.into_iter().enumerate() {
1792            apit_spans.push(span);
1793
1794            let fresh_param = next_fresh_param();
1795
1796            // Suggest renaming.
1797            suggs.push((span, fresh_param.to_string()));
1798
1799            // Super jank. Turn `impl Trait` into `T: Trait`.
1800            //
1801            // This currently involves stripping the `impl` from the name of
1802            // the parameter, since APITs are always named after how they are
1803            // rendered in the AST. This sucks! But to recreate the bound list
1804            // from the APIT itself would be miserable, so we're stuck with
1805            // this for now!
1806            if i > 0 {
1807                new_params += ", ";
1808            }
1809            let name_as_bounds = name.as_str().trim_start_matches("impl").trim_start();
1810            new_params += fresh_param.as_str();
1811            new_params += ": ";
1812            new_params += name_as_bounds;
1813        }
1814
1815        let Some(generics) = tcx.hir_get_generics(fn_def_id) else {
1816            // This shouldn't happen, but don't ICE.
1817            return None;
1818        };
1819
1820        // Add generics or concatenate to the end of the list.
1821        suggs.push(if let Some(params_span) = generics.span_for_param_suggestion() {
1822            (params_span, format!(", {new_params}"))
1823        } else {
1824            (generics.span, format!("<{new_params}>"))
1825        });
1826    }
1827
1828    let concatenated_bounds = captured_lifetimes
1829        .into_iter()
1830        .chain(captured_non_lifetimes)
1831        .map(|sym| sym.to_string())
1832        .collect::<Vec<_>>()
1833        .join(", ");
1834
1835    let opaque_hir_id = tcx.local_def_id_to_hir_id(opaque_def_id);
1836    // FIXME: This is a bit too conservative, since it ignores parens already written in AST.
1837    let (lparen, rparen) = match tcx
1838        .hir_parent_iter(opaque_hir_id)
1839        .nth(1)
1840        .expect("expected ty to have a parent always")
1841        .1
1842    {
1843        Node::PathSegment(segment)
1844            if segment.args().paren_sugar_output().is_some_and(|ty| ty.hir_id == opaque_hir_id) =>
1845        {
1846            ("(", ")")
1847        }
1848        Node::Ty(ty) => match ty.kind {
1849            rustc_hir::TyKind::Ptr(_) | rustc_hir::TyKind::Ref(..) => ("(", ")"),
1850            // FIXME: RPITs are not allowed to be nested in `impl Fn() -> ...`,
1851            // but we eventually could support that, and that would necessitate
1852            // making this more sophisticated.
1853            _ => ("", ""),
1854        },
1855        _ => ("", ""),
1856    };
1857
1858    let rpit_span = tcx.def_span(opaque_def_id);
1859    if !lparen.is_empty() {
1860        suggs.push((rpit_span.shrink_to_lo(), lparen.to_string()));
1861    }
1862    suggs.push((rpit_span.shrink_to_hi(), format!(" + use<{concatenated_bounds}>{rparen}")));
1863
1864    Some(AddPreciseCapturingForOvercapture { suggs, apit_spans })
1865}
1866
1867pub struct AddPreciseCapturingForOvercapture {
1868    pub suggs: Vec<(Span, String)>,
1869    pub apit_spans: Vec<Span>,
1870}
1871
1872impl Subdiagnostic for AddPreciseCapturingForOvercapture {
1873    fn add_to_diag<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) {
1874        let applicability = if self.apit_spans.is_empty() {
1875            Applicability::MachineApplicable
1876        } else {
1877            // If there are APIT that are converted to regular parameters,
1878            // then this may make the API turbofishable in ways that were
1879            // not intended.
1880            Applicability::MaybeIncorrect
1881        };
1882        diag.multipart_suggestion_verbose(
1883            fluent::trait_selection_precise_capturing_overcaptures,
1884            self.suggs,
1885            applicability,
1886        );
1887        if !self.apit_spans.is_empty() {
1888            diag.span_note(
1889                self.apit_spans,
1890                fluent::trait_selection_warn_removing_apit_params_for_overcapture,
1891            );
1892        }
1893    }
1894}
1895
1896#[derive(Diagnostic)]
1897#[diag(trait_selection_opaque_type_non_generic_param, code = E0792)]
1898pub(crate) struct NonGenericOpaqueTypeParam<'a, 'tcx> {
1899    pub arg: GenericArg<'tcx>,
1900    pub kind: &'a str,
1901    #[primary_span]
1902    pub span: Span,
1903    #[label]
1904    pub param_span: Span,
1905}