rustc_trait_selection/
errors.rs

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