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