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        )]
764        new_ty_span: Span,
765        #[skip_arg]
766        new_ty: Ty<'a>,
767    },
768    #[diag(trait_selection_explicit_lifetime_required_with_param_type, code = E0621)]
769    WithParamType {
770        #[primary_span]
771        #[label]
772        span: Span,
773        named: String,
774        #[suggestion(
775            trait_selection_explicit_lifetime_required_sugg_with_param_type,
776            code = "{new_ty}",
777            applicability = "unspecified"
778        )]
779        new_ty_span: Span,
780        #[skip_arg]
781        new_ty: Ty<'a>,
782    },
783}
784
785pub enum TyOrSig<'tcx> {
786    Ty(Highlighted<'tcx, Ty<'tcx>>),
787    ClosureSig(Highlighted<'tcx, Binder<'tcx, FnSig<'tcx>>>),
788}
789
790impl IntoDiagArg for TyOrSig<'_> {
791    fn into_diag_arg(self, path: &mut Option<std::path::PathBuf>) -> rustc_errors::DiagArgValue {
792        match self {
793            TyOrSig::Ty(ty) => ty.into_diag_arg(path),
794            TyOrSig::ClosureSig(sig) => sig.into_diag_arg(path),
795        }
796    }
797}
798
799#[derive(Subdiagnostic)]
800pub enum ActualImplExplNotes<'tcx> {
801    #[note(trait_selection_actual_impl_expl_expected_signature_two)]
802    ExpectedSignatureTwo {
803        leading_ellipsis: bool,
804        ty_or_sig: TyOrSig<'tcx>,
805        trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>,
806        lifetime_1: usize,
807        lifetime_2: usize,
808    },
809    #[note(trait_selection_actual_impl_expl_expected_signature_any)]
810    ExpectedSignatureAny {
811        leading_ellipsis: bool,
812        ty_or_sig: TyOrSig<'tcx>,
813        trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>,
814        lifetime_1: usize,
815    },
816    #[note(trait_selection_actual_impl_expl_expected_signature_some)]
817    ExpectedSignatureSome {
818        leading_ellipsis: bool,
819        ty_or_sig: TyOrSig<'tcx>,
820        trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>,
821        lifetime_1: usize,
822    },
823    #[note(trait_selection_actual_impl_expl_expected_signature_nothing)]
824    ExpectedSignatureNothing {
825        leading_ellipsis: bool,
826        ty_or_sig: TyOrSig<'tcx>,
827        trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>,
828    },
829    #[note(trait_selection_actual_impl_expl_expected_passive_two)]
830    ExpectedPassiveTwo {
831        leading_ellipsis: bool,
832        ty_or_sig: TyOrSig<'tcx>,
833        trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>,
834        lifetime_1: usize,
835        lifetime_2: usize,
836    },
837    #[note(trait_selection_actual_impl_expl_expected_passive_any)]
838    ExpectedPassiveAny {
839        leading_ellipsis: bool,
840        ty_or_sig: TyOrSig<'tcx>,
841        trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>,
842        lifetime_1: usize,
843    },
844    #[note(trait_selection_actual_impl_expl_expected_passive_some)]
845    ExpectedPassiveSome {
846        leading_ellipsis: bool,
847        ty_or_sig: TyOrSig<'tcx>,
848        trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>,
849        lifetime_1: usize,
850    },
851    #[note(trait_selection_actual_impl_expl_expected_passive_nothing)]
852    ExpectedPassiveNothing {
853        leading_ellipsis: bool,
854        ty_or_sig: TyOrSig<'tcx>,
855        trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>,
856    },
857    #[note(trait_selection_actual_impl_expl_expected_other_two)]
858    ExpectedOtherTwo {
859        leading_ellipsis: bool,
860        ty_or_sig: TyOrSig<'tcx>,
861        trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>,
862        lifetime_1: usize,
863        lifetime_2: usize,
864    },
865    #[note(trait_selection_actual_impl_expl_expected_other_any)]
866    ExpectedOtherAny {
867        leading_ellipsis: bool,
868        ty_or_sig: TyOrSig<'tcx>,
869        trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>,
870        lifetime_1: usize,
871    },
872    #[note(trait_selection_actual_impl_expl_expected_other_some)]
873    ExpectedOtherSome {
874        leading_ellipsis: bool,
875        ty_or_sig: TyOrSig<'tcx>,
876        trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>,
877        lifetime_1: usize,
878    },
879    #[note(trait_selection_actual_impl_expl_expected_other_nothing)]
880    ExpectedOtherNothing {
881        leading_ellipsis: bool,
882        ty_or_sig: TyOrSig<'tcx>,
883        trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>,
884    },
885    #[note(trait_selection_actual_impl_expl_but_actually_implements_trait)]
886    ButActuallyImplementsTrait {
887        trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>,
888        has_lifetime: bool,
889        lifetime: usize,
890    },
891    #[note(trait_selection_actual_impl_expl_but_actually_implemented_for_ty)]
892    ButActuallyImplementedForTy {
893        trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>,
894        has_lifetime: bool,
895        lifetime: usize,
896        ty: String,
897    },
898    #[note(trait_selection_actual_impl_expl_but_actually_ty_implements)]
899    ButActuallyTyImplements {
900        trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>,
901        has_lifetime: bool,
902        lifetime: usize,
903        ty: String,
904    },
905}
906
907pub enum ActualImplExpectedKind {
908    Signature,
909    Passive,
910    Other,
911}
912
913pub enum ActualImplExpectedLifetimeKind {
914    Two,
915    Any,
916    Some,
917    Nothing,
918}
919
920impl<'tcx> ActualImplExplNotes<'tcx> {
921    pub fn new_expected(
922        kind: ActualImplExpectedKind,
923        lt_kind: ActualImplExpectedLifetimeKind,
924        leading_ellipsis: bool,
925        ty_or_sig: TyOrSig<'tcx>,
926        trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>,
927        lifetime_1: usize,
928        lifetime_2: usize,
929    ) -> Self {
930        match (kind, lt_kind) {
931            (ActualImplExpectedKind::Signature, ActualImplExpectedLifetimeKind::Two) => {
932                Self::ExpectedSignatureTwo {
933                    leading_ellipsis,
934                    ty_or_sig,
935                    trait_path,
936                    lifetime_1,
937                    lifetime_2,
938                }
939            }
940            (ActualImplExpectedKind::Signature, ActualImplExpectedLifetimeKind::Any) => {
941                Self::ExpectedSignatureAny { leading_ellipsis, ty_or_sig, trait_path, lifetime_1 }
942            }
943            (ActualImplExpectedKind::Signature, ActualImplExpectedLifetimeKind::Some) => {
944                Self::ExpectedSignatureSome { leading_ellipsis, ty_or_sig, trait_path, lifetime_1 }
945            }
946            (ActualImplExpectedKind::Signature, ActualImplExpectedLifetimeKind::Nothing) => {
947                Self::ExpectedSignatureNothing { leading_ellipsis, ty_or_sig, trait_path }
948            }
949            (ActualImplExpectedKind::Passive, ActualImplExpectedLifetimeKind::Two) => {
950                Self::ExpectedPassiveTwo {
951                    leading_ellipsis,
952                    ty_or_sig,
953                    trait_path,
954                    lifetime_1,
955                    lifetime_2,
956                }
957            }
958            (ActualImplExpectedKind::Passive, ActualImplExpectedLifetimeKind::Any) => {
959                Self::ExpectedPassiveAny { leading_ellipsis, ty_or_sig, trait_path, lifetime_1 }
960            }
961            (ActualImplExpectedKind::Passive, ActualImplExpectedLifetimeKind::Some) => {
962                Self::ExpectedPassiveSome { leading_ellipsis, ty_or_sig, trait_path, lifetime_1 }
963            }
964            (ActualImplExpectedKind::Passive, ActualImplExpectedLifetimeKind::Nothing) => {
965                Self::ExpectedPassiveNothing { leading_ellipsis, ty_or_sig, trait_path }
966            }
967            (ActualImplExpectedKind::Other, ActualImplExpectedLifetimeKind::Two) => {
968                Self::ExpectedOtherTwo {
969                    leading_ellipsis,
970                    ty_or_sig,
971                    trait_path,
972                    lifetime_1,
973                    lifetime_2,
974                }
975            }
976            (ActualImplExpectedKind::Other, ActualImplExpectedLifetimeKind::Any) => {
977                Self::ExpectedOtherAny { leading_ellipsis, ty_or_sig, trait_path, lifetime_1 }
978            }
979            (ActualImplExpectedKind::Other, ActualImplExpectedLifetimeKind::Some) => {
980                Self::ExpectedOtherSome { leading_ellipsis, ty_or_sig, trait_path, lifetime_1 }
981            }
982            (ActualImplExpectedKind::Other, ActualImplExpectedLifetimeKind::Nothing) => {
983                Self::ExpectedOtherNothing { leading_ellipsis, ty_or_sig, trait_path }
984            }
985        }
986    }
987}
988
989#[derive(Diagnostic)]
990#[diag(trait_selection_trait_placeholder_mismatch)]
991pub struct TraitPlaceholderMismatch<'tcx> {
992    #[primary_span]
993    pub span: Span,
994    #[label(trait_selection_label_satisfy)]
995    pub satisfy_span: Option<Span>,
996    #[label(trait_selection_label_where)]
997    pub where_span: Option<Span>,
998    #[label(trait_selection_label_dup)]
999    pub dup_span: Option<Span>,
1000    pub def_id: String,
1001    pub trait_def_id: String,
1002
1003    #[subdiagnostic]
1004    pub actual_impl_expl_notes: Vec<ActualImplExplNotes<'tcx>>,
1005}
1006
1007pub struct ConsiderBorrowingParamHelp {
1008    pub spans: Vec<Span>,
1009}
1010
1011impl Subdiagnostic for ConsiderBorrowingParamHelp {
1012    fn add_to_diag<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) {
1013        let mut type_param_span: MultiSpan = self.spans.clone().into();
1014        for &span in &self.spans {
1015            // Seems like we can't call f() here as Into<DiagMessage> is required
1016            type_param_span.push_span_label(span, fluent::trait_selection_tid_consider_borrowing);
1017        }
1018        let msg = diag.eagerly_translate(fluent::trait_selection_tid_param_help);
1019        diag.span_help(type_param_span, msg);
1020    }
1021}
1022
1023#[derive(Subdiagnostic)]
1024#[help(trait_selection_tid_rel_help)]
1025pub struct RelationshipHelp;
1026
1027#[derive(Diagnostic)]
1028#[diag(trait_selection_trait_impl_diff)]
1029pub struct TraitImplDiff {
1030    #[primary_span]
1031    #[label(trait_selection_found)]
1032    pub sp: Span,
1033    #[label(trait_selection_expected)]
1034    pub trait_sp: Span,
1035    #[note(trait_selection_expected_found)]
1036    pub note: (),
1037    #[subdiagnostic]
1038    pub param_help: ConsiderBorrowingParamHelp,
1039    #[subdiagnostic]
1040    // Seems like subdiagnostics are always pushed to the end, so this one
1041    // also has to be a subdiagnostic to maintain order.
1042    pub rel_help: Option<RelationshipHelp>,
1043    pub expected: String,
1044    pub found: String,
1045}
1046
1047pub struct DynTraitConstraintSuggestion {
1048    pub span: Span,
1049    pub ident: Ident,
1050}
1051
1052impl Subdiagnostic for DynTraitConstraintSuggestion {
1053    fn add_to_diag<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) {
1054        let mut multi_span: MultiSpan = vec![self.span].into();
1055        multi_span.push_span_label(self.span, fluent::trait_selection_dtcs_has_lifetime_req_label);
1056        multi_span
1057            .push_span_label(self.ident.span, fluent::trait_selection_dtcs_introduces_requirement);
1058        let msg = diag.eagerly_translate(fluent::trait_selection_dtcs_has_req_note);
1059        diag.span_note(multi_span, msg);
1060        let msg = diag.eagerly_translate(fluent::trait_selection_dtcs_suggestion);
1061        diag.span_suggestion_verbose(
1062            self.span.shrink_to_hi(),
1063            msg,
1064            " + '_",
1065            Applicability::MaybeIncorrect,
1066        );
1067    }
1068}
1069
1070#[derive(Diagnostic)]
1071#[diag(trait_selection_but_calling_introduces, code = E0772)]
1072pub struct ButCallingIntroduces {
1073    #[label(trait_selection_label1)]
1074    pub param_ty_span: Span,
1075    #[primary_span]
1076    #[label(trait_selection_label2)]
1077    pub cause_span: Span,
1078
1079    pub has_param_name: bool,
1080    pub param_name: String,
1081    pub has_lifetime: bool,
1082    pub lifetime: String,
1083    pub assoc_item: Symbol,
1084    pub has_impl_path: bool,
1085    pub impl_path: String,
1086}
1087
1088pub struct ReqIntroducedLocations {
1089    pub span: MultiSpan,
1090    pub spans: Vec<Span>,
1091    pub fn_decl_span: Span,
1092    pub cause_span: Span,
1093    pub add_label: bool,
1094}
1095
1096impl Subdiagnostic for ReqIntroducedLocations {
1097    fn add_to_diag<G: EmissionGuarantee>(mut self, diag: &mut Diag<'_, G>) {
1098        for sp in self.spans {
1099            self.span.push_span_label(sp, fluent::trait_selection_ril_introduced_here);
1100        }
1101
1102        if self.add_label {
1103            self.span.push_span_label(self.fn_decl_span, fluent::trait_selection_ril_introduced_by);
1104        }
1105        self.span.push_span_label(self.cause_span, fluent::trait_selection_ril_because_of);
1106        let msg = diag.eagerly_translate(fluent::trait_selection_ril_static_introduced_by);
1107        diag.span_note(self.span, msg);
1108    }
1109}
1110
1111#[derive(Diagnostic)]
1112#[diag(trait_selection_but_needs_to_satisfy, code = E0759)]
1113pub struct ButNeedsToSatisfy {
1114    #[primary_span]
1115    pub sp: Span,
1116    #[label(trait_selection_influencer)]
1117    pub influencer_point: Span,
1118    #[label(trait_selection_used_here)]
1119    pub spans: Vec<Span>,
1120    #[label(trait_selection_require)]
1121    pub require_span_as_label: Option<Span>,
1122    #[note(trait_selection_require)]
1123    pub require_span_as_note: Option<Span>,
1124    #[note(trait_selection_introduced_by_bound)]
1125    pub bound: Option<Span>,
1126
1127    pub has_param_name: bool,
1128    pub param_name: String,
1129    pub spans_empty: bool,
1130    pub has_lifetime: bool,
1131    pub lifetime: String,
1132}
1133
1134#[derive(Diagnostic)]
1135#[diag(trait_selection_outlives_content, code = E0312)]
1136pub struct OutlivesContent<'a> {
1137    #[primary_span]
1138    pub span: Span,
1139    #[subdiagnostic]
1140    pub notes: Vec<note_and_explain::RegionExplanation<'a>>,
1141}
1142
1143#[derive(Diagnostic)]
1144#[diag(trait_selection_outlives_bound, code = E0476)]
1145pub struct OutlivesBound<'a> {
1146    #[primary_span]
1147    pub span: Span,
1148    #[subdiagnostic]
1149    pub notes: Vec<note_and_explain::RegionExplanation<'a>>,
1150}
1151
1152#[derive(Diagnostic)]
1153#[diag(trait_selection_fulfill_req_lifetime, code = E0477)]
1154pub struct FulfillReqLifetime<'a> {
1155    #[primary_span]
1156    pub span: Span,
1157    pub ty: Ty<'a>,
1158    #[subdiagnostic]
1159    pub note: Option<note_and_explain::RegionExplanation<'a>>,
1160}
1161
1162#[derive(Diagnostic)]
1163#[diag(trait_selection_lf_bound_not_satisfied, code = E0478)]
1164pub struct LfBoundNotSatisfied<'a> {
1165    #[primary_span]
1166    pub span: Span,
1167    #[subdiagnostic]
1168    pub notes: Vec<note_and_explain::RegionExplanation<'a>>,
1169}
1170
1171#[derive(Diagnostic)]
1172#[diag(trait_selection_ref_longer_than_data, code = E0491)]
1173pub struct RefLongerThanData<'a> {
1174    #[primary_span]
1175    pub span: Span,
1176    pub ty: Ty<'a>,
1177    #[subdiagnostic]
1178    pub notes: Vec<note_and_explain::RegionExplanation<'a>>,
1179}
1180
1181#[derive(Subdiagnostic)]
1182pub enum WhereClauseSuggestions {
1183    #[suggestion(
1184        trait_selection_where_remove,
1185        code = "",
1186        applicability = "machine-applicable",
1187        style = "verbose"
1188    )]
1189    Remove {
1190        #[primary_span]
1191        span: Span,
1192    },
1193    #[suggestion(
1194        trait_selection_where_copy_predicates,
1195        code = "{space}where {trait_predicates}",
1196        applicability = "machine-applicable",
1197        style = "verbose"
1198    )]
1199    CopyPredicates {
1200        #[primary_span]
1201        span: Span,
1202        space: &'static str,
1203        trait_predicates: String,
1204    },
1205}
1206
1207#[derive(Subdiagnostic)]
1208pub enum SuggestRemoveSemiOrReturnBinding {
1209    #[multipart_suggestion(
1210        trait_selection_srs_remove_and_box,
1211        applicability = "machine-applicable"
1212    )]
1213    RemoveAndBox {
1214        #[suggestion_part(code = "Box::new(")]
1215        first_lo: Span,
1216        #[suggestion_part(code = ")")]
1217        first_hi: Span,
1218        #[suggestion_part(code = "Box::new(")]
1219        second_lo: Span,
1220        #[suggestion_part(code = ")")]
1221        second_hi: Span,
1222        #[suggestion_part(code = "")]
1223        sp: Span,
1224    },
1225    #[suggestion(
1226        trait_selection_srs_remove,
1227        style = "short",
1228        code = "",
1229        applicability = "machine-applicable"
1230    )]
1231    Remove {
1232        #[primary_span]
1233        sp: Span,
1234    },
1235    #[suggestion(
1236        trait_selection_srs_add,
1237        style = "verbose",
1238        code = "{code}",
1239        applicability = "maybe-incorrect"
1240    )]
1241    Add {
1242        #[primary_span]
1243        sp: Span,
1244        code: String,
1245        ident: Ident,
1246    },
1247    #[note(trait_selection_srs_add_one)]
1248    AddOne {
1249        #[primary_span]
1250        spans: MultiSpan,
1251    },
1252}
1253
1254#[derive(Subdiagnostic)]
1255pub enum ConsiderAddingAwait {
1256    #[help(trait_selection_await_both_futures)]
1257    BothFuturesHelp,
1258    #[multipart_suggestion(trait_selection_await_both_futures, applicability = "maybe-incorrect")]
1259    BothFuturesSugg {
1260        #[suggestion_part(code = ".await")]
1261        first: Span,
1262        #[suggestion_part(code = ".await")]
1263        second: Span,
1264    },
1265    #[suggestion(
1266        trait_selection_await_future,
1267        code = ".await",
1268        style = "verbose",
1269        applicability = "maybe-incorrect"
1270    )]
1271    FutureSugg {
1272        #[primary_span]
1273        span: Span,
1274    },
1275    #[note(trait_selection_await_note)]
1276    FutureSuggNote {
1277        #[primary_span]
1278        span: Span,
1279    },
1280    #[multipart_suggestion(
1281        trait_selection_await_future,
1282        style = "verbose",
1283        applicability = "maybe-incorrect"
1284    )]
1285    FutureSuggMultiple {
1286        #[suggestion_part(code = ".await")]
1287        spans: Vec<Span>,
1288    },
1289}
1290
1291#[derive(Diagnostic)]
1292pub enum PlaceholderRelationLfNotSatisfied {
1293    #[diag(trait_selection_lf_bound_not_satisfied)]
1294    HasBoth {
1295        #[primary_span]
1296        span: Span,
1297        #[note(trait_selection_prlf_defined_with_sub)]
1298        sub_span: Span,
1299        #[note(trait_selection_prlf_must_outlive_with_sup)]
1300        sup_span: Span,
1301        sub_symbol: Symbol,
1302        sup_symbol: Symbol,
1303        #[note(trait_selection_prlf_known_limitation)]
1304        note: (),
1305    },
1306    #[diag(trait_selection_lf_bound_not_satisfied)]
1307    HasSub {
1308        #[primary_span]
1309        span: Span,
1310        #[note(trait_selection_prlf_defined_with_sub)]
1311        sub_span: Span,
1312        #[note(trait_selection_prlf_must_outlive_without_sup)]
1313        sup_span: Span,
1314        sub_symbol: Symbol,
1315        #[note(trait_selection_prlf_known_limitation)]
1316        note: (),
1317    },
1318    #[diag(trait_selection_lf_bound_not_satisfied)]
1319    HasSup {
1320        #[primary_span]
1321        span: Span,
1322        #[note(trait_selection_prlf_defined_without_sub)]
1323        sub_span: Span,
1324        #[note(trait_selection_prlf_must_outlive_with_sup)]
1325        sup_span: Span,
1326        sup_symbol: Symbol,
1327        #[note(trait_selection_prlf_known_limitation)]
1328        note: (),
1329    },
1330    #[diag(trait_selection_lf_bound_not_satisfied)]
1331    HasNone {
1332        #[primary_span]
1333        span: Span,
1334        #[note(trait_selection_prlf_defined_without_sub)]
1335        sub_span: Span,
1336        #[note(trait_selection_prlf_must_outlive_without_sup)]
1337        sup_span: Span,
1338        #[note(trait_selection_prlf_known_limitation)]
1339        note: (),
1340    },
1341    #[diag(trait_selection_lf_bound_not_satisfied)]
1342    OnlyPrimarySpan {
1343        #[primary_span]
1344        span: Span,
1345        #[note(trait_selection_prlf_known_limitation)]
1346        note: (),
1347    },
1348}
1349
1350#[derive(Diagnostic)]
1351#[diag(trait_selection_opaque_captures_lifetime, code = E0700)]
1352pub struct OpaqueCapturesLifetime<'tcx> {
1353    #[primary_span]
1354    pub span: Span,
1355    #[label]
1356    pub opaque_ty_span: Span,
1357    pub opaque_ty: Ty<'tcx>,
1358}
1359
1360#[derive(Subdiagnostic)]
1361pub enum FunctionPointerSuggestion<'a> {
1362    #[suggestion(
1363        trait_selection_fps_use_ref,
1364        code = "&",
1365        style = "verbose",
1366        applicability = "maybe-incorrect"
1367    )]
1368    UseRef {
1369        #[primary_span]
1370        span: Span,
1371    },
1372    #[suggestion(
1373        trait_selection_fps_remove_ref,
1374        code = "{fn_name}",
1375        style = "verbose",
1376        applicability = "maybe-incorrect"
1377    )]
1378    RemoveRef {
1379        #[primary_span]
1380        span: Span,
1381        #[skip_arg]
1382        fn_name: String,
1383    },
1384    #[suggestion(
1385        trait_selection_fps_cast,
1386        code = "&({fn_name} as {sig})",
1387        style = "verbose",
1388        applicability = "maybe-incorrect"
1389    )]
1390    CastRef {
1391        #[primary_span]
1392        span: Span,
1393        #[skip_arg]
1394        fn_name: String,
1395        #[skip_arg]
1396        sig: Binder<'a, FnSig<'a>>,
1397    },
1398    #[suggestion(
1399        trait_selection_fps_cast,
1400        code = " as {sig}",
1401        style = "verbose",
1402        applicability = "maybe-incorrect"
1403    )]
1404    Cast {
1405        #[primary_span]
1406        span: Span,
1407        #[skip_arg]
1408        sig: Binder<'a, FnSig<'a>>,
1409    },
1410    #[suggestion(
1411        trait_selection_fps_cast_both,
1412        code = " as {found_sig}",
1413        style = "hidden",
1414        applicability = "maybe-incorrect"
1415    )]
1416    CastBoth {
1417        #[primary_span]
1418        span: Span,
1419        #[skip_arg]
1420        found_sig: Binder<'a, FnSig<'a>>,
1421        expected_sig: Binder<'a, FnSig<'a>>,
1422    },
1423    #[suggestion(
1424        trait_selection_fps_cast_both,
1425        code = "&({fn_name} as {found_sig})",
1426        style = "hidden",
1427        applicability = "maybe-incorrect"
1428    )]
1429    CastBothRef {
1430        #[primary_span]
1431        span: Span,
1432        #[skip_arg]
1433        fn_name: String,
1434        #[skip_arg]
1435        found_sig: Binder<'a, FnSig<'a>>,
1436        expected_sig: Binder<'a, FnSig<'a>>,
1437    },
1438}
1439
1440#[derive(Subdiagnostic)]
1441#[note(trait_selection_fps_items_are_distinct)]
1442pub struct FnItemsAreDistinct;
1443
1444#[derive(Subdiagnostic)]
1445#[note(trait_selection_fn_uniq_types)]
1446pub struct FnUniqTypes;
1447
1448#[derive(Subdiagnostic)]
1449#[help(trait_selection_fn_consider_casting)]
1450pub struct FnConsiderCasting {
1451    pub casting: String,
1452}
1453
1454#[derive(Subdiagnostic)]
1455#[help(trait_selection_fn_consider_casting_both)]
1456pub struct FnConsiderCastingBoth<'a> {
1457    pub sig: Binder<'a, FnSig<'a>>,
1458}
1459
1460#[derive(Subdiagnostic)]
1461pub enum SuggestAccessingField<'a> {
1462    #[suggestion(
1463        trait_selection_suggest_accessing_field,
1464        code = "{snippet}.{name}",
1465        applicability = "maybe-incorrect"
1466    )]
1467    Safe {
1468        #[primary_span]
1469        span: Span,
1470        snippet: String,
1471        name: Symbol,
1472        ty: Ty<'a>,
1473    },
1474    #[suggestion(
1475        trait_selection_suggest_accessing_field,
1476        code = "unsafe {{ {snippet}.{name} }}",
1477        applicability = "maybe-incorrect"
1478    )]
1479    Unsafe {
1480        #[primary_span]
1481        span: Span,
1482        snippet: String,
1483        name: Symbol,
1484        ty: Ty<'a>,
1485    },
1486}
1487
1488#[derive(Subdiagnostic)]
1489#[multipart_suggestion(trait_selection_stp_wrap_one, applicability = "maybe-incorrect")]
1490pub struct SuggestTuplePatternOne {
1491    pub variant: String,
1492    #[suggestion_part(code = "{variant}(")]
1493    pub span_low: Span,
1494    #[suggestion_part(code = ")")]
1495    pub span_high: Span,
1496}
1497
1498pub struct SuggestTuplePatternMany {
1499    pub path: String,
1500    pub cause_span: Span,
1501    pub compatible_variants: Vec<String>,
1502}
1503
1504impl Subdiagnostic for SuggestTuplePatternMany {
1505    fn add_to_diag<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) {
1506        diag.arg("path", self.path);
1507        let message = diag.eagerly_translate(fluent::trait_selection_stp_wrap_many);
1508        diag.multipart_suggestions(
1509            message,
1510            self.compatible_variants.into_iter().map(|variant| {
1511                vec![
1512                    (self.cause_span.shrink_to_lo(), format!("{variant}(")),
1513                    (self.cause_span.shrink_to_hi(), ")".to_string()),
1514                ]
1515            }),
1516            rustc_errors::Applicability::MaybeIncorrect,
1517        );
1518    }
1519}
1520
1521#[derive(Subdiagnostic)]
1522pub enum TypeErrorAdditionalDiags {
1523    #[suggestion(
1524        trait_selection_meant_byte_literal,
1525        code = "b'{code}'",
1526        applicability = "machine-applicable"
1527    )]
1528    MeantByteLiteral {
1529        #[primary_span]
1530        span: Span,
1531        code: String,
1532    },
1533    #[suggestion(
1534        trait_selection_meant_char_literal,
1535        code = "'{code}'",
1536        applicability = "machine-applicable"
1537    )]
1538    MeantCharLiteral {
1539        #[primary_span]
1540        span: Span,
1541        code: String,
1542    },
1543    #[multipart_suggestion(trait_selection_meant_str_literal, applicability = "machine-applicable")]
1544    MeantStrLiteral {
1545        #[suggestion_part(code = "\"")]
1546        start: Span,
1547        #[suggestion_part(code = "\"")]
1548        end: Span,
1549    },
1550    #[suggestion(
1551        trait_selection_consider_specifying_length,
1552        code = "{length}",
1553        applicability = "maybe-incorrect"
1554    )]
1555    ConsiderSpecifyingLength {
1556        #[primary_span]
1557        span: Span,
1558        length: u64,
1559    },
1560    #[note(trait_selection_try_cannot_convert)]
1561    TryCannotConvert { found: String, expected: String },
1562    #[suggestion(
1563        trait_selection_tuple_trailing_comma,
1564        code = ",",
1565        applicability = "machine-applicable"
1566    )]
1567    TupleOnlyComma {
1568        #[primary_span]
1569        span: Span,
1570    },
1571    #[multipart_suggestion(
1572        trait_selection_tuple_trailing_comma,
1573        applicability = "machine-applicable"
1574    )]
1575    TupleAlsoParentheses {
1576        #[suggestion_part(code = "(")]
1577        span_low: Span,
1578        #[suggestion_part(code = ",)")]
1579        span_high: Span,
1580    },
1581    #[suggestion(
1582        trait_selection_suggest_add_let_for_letchains,
1583        style = "verbose",
1584        applicability = "machine-applicable",
1585        code = "let "
1586    )]
1587    AddLetForLetChains {
1588        #[primary_span]
1589        span: Span,
1590    },
1591}
1592
1593#[derive(Diagnostic)]
1594pub enum ObligationCauseFailureCode {
1595    #[diag(trait_selection_oc_method_compat, code = E0308)]
1596    MethodCompat {
1597        #[primary_span]
1598        span: Span,
1599        #[subdiagnostic]
1600        subdiags: Vec<TypeErrorAdditionalDiags>,
1601    },
1602    #[diag(trait_selection_oc_type_compat, code = E0308)]
1603    TypeCompat {
1604        #[primary_span]
1605        span: Span,
1606        #[subdiagnostic]
1607        subdiags: Vec<TypeErrorAdditionalDiags>,
1608    },
1609    #[diag(trait_selection_oc_const_compat, code = E0308)]
1610    ConstCompat {
1611        #[primary_span]
1612        span: Span,
1613        #[subdiagnostic]
1614        subdiags: Vec<TypeErrorAdditionalDiags>,
1615    },
1616    #[diag(trait_selection_oc_try_compat, code = E0308)]
1617    TryCompat {
1618        #[primary_span]
1619        span: Span,
1620        #[subdiagnostic]
1621        subdiags: Vec<TypeErrorAdditionalDiags>,
1622    },
1623    #[diag(trait_selection_oc_match_compat, code = E0308)]
1624    MatchCompat {
1625        #[primary_span]
1626        span: Span,
1627        #[subdiagnostic]
1628        subdiags: Vec<TypeErrorAdditionalDiags>,
1629    },
1630    #[diag(trait_selection_oc_if_else_different, code = E0308)]
1631    IfElseDifferent {
1632        #[primary_span]
1633        span: Span,
1634        #[subdiagnostic]
1635        subdiags: Vec<TypeErrorAdditionalDiags>,
1636    },
1637    #[diag(trait_selection_oc_no_else, code = E0317)]
1638    NoElse {
1639        #[primary_span]
1640        span: Span,
1641    },
1642    #[diag(trait_selection_oc_no_diverge, code = E0308)]
1643    NoDiverge {
1644        #[primary_span]
1645        span: Span,
1646        #[subdiagnostic]
1647        subdiags: Vec<TypeErrorAdditionalDiags>,
1648    },
1649    #[diag(trait_selection_oc_fn_main_correct_type, code = E0580)]
1650    FnMainCorrectType {
1651        #[primary_span]
1652        span: Span,
1653    },
1654    #[diag(trait_selection_oc_fn_lang_correct_type, code = E0308)]
1655    FnLangCorrectType {
1656        #[primary_span]
1657        span: Span,
1658        #[subdiagnostic]
1659        subdiags: Vec<TypeErrorAdditionalDiags>,
1660        lang_item_name: Symbol,
1661    },
1662    #[diag(trait_selection_oc_intrinsic_correct_type, code = E0308)]
1663    IntrinsicCorrectType {
1664        #[primary_span]
1665        span: Span,
1666        #[subdiagnostic]
1667        subdiags: Vec<TypeErrorAdditionalDiags>,
1668    },
1669    #[diag(trait_selection_oc_method_correct_type, code = E0308)]
1670    MethodCorrectType {
1671        #[primary_span]
1672        span: Span,
1673        #[subdiagnostic]
1674        subdiags: Vec<TypeErrorAdditionalDiags>,
1675    },
1676    #[diag(trait_selection_oc_closure_selfref, code = E0644)]
1677    ClosureSelfref {
1678        #[primary_span]
1679        span: Span,
1680    },
1681    #[diag(trait_selection_oc_cant_coerce_force_inline, code = E0308)]
1682    CantCoerceForceInline {
1683        #[primary_span]
1684        span: Span,
1685        #[subdiagnostic]
1686        subdiags: Vec<TypeErrorAdditionalDiags>,
1687    },
1688    #[diag(trait_selection_oc_cant_coerce_intrinsic, code = E0308)]
1689    CantCoerceIntrinsic {
1690        #[primary_span]
1691        span: Span,
1692        #[subdiagnostic]
1693        subdiags: Vec<TypeErrorAdditionalDiags>,
1694    },
1695    #[diag(trait_selection_oc_generic, code = E0308)]
1696    Generic {
1697        #[primary_span]
1698        span: Span,
1699        #[subdiagnostic]
1700        subdiags: Vec<TypeErrorAdditionalDiags>,
1701    },
1702}
1703
1704#[derive(Subdiagnostic)]
1705pub enum AddPreciseCapturing {
1706    #[suggestion(
1707        trait_selection_precise_capturing_new,
1708        style = "verbose",
1709        code = " + use<{concatenated_bounds}>",
1710        applicability = "machine-applicable"
1711    )]
1712    New {
1713        #[primary_span]
1714        span: Span,
1715        new_lifetime: Symbol,
1716        concatenated_bounds: String,
1717    },
1718    #[suggestion(
1719        trait_selection_precise_capturing_existing,
1720        style = "verbose",
1721        code = "{pre}{new_lifetime}{post}",
1722        applicability = "machine-applicable"
1723    )]
1724    Existing {
1725        #[primary_span]
1726        span: Span,
1727        new_lifetime: Symbol,
1728        pre: &'static str,
1729        post: &'static str,
1730    },
1731}
1732
1733pub struct AddPreciseCapturingAndParams {
1734    pub suggs: Vec<(Span, String)>,
1735    pub new_lifetime: Symbol,
1736    pub apit_spans: Vec<Span>,
1737}
1738
1739impl Subdiagnostic for AddPreciseCapturingAndParams {
1740    fn add_to_diag<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) {
1741        diag.arg("new_lifetime", self.new_lifetime);
1742        diag.multipart_suggestion_verbose(
1743            fluent::trait_selection_precise_capturing_new_but_apit,
1744            self.suggs,
1745            Applicability::MaybeIncorrect,
1746        );
1747        diag.span_note(
1748            self.apit_spans,
1749            fluent::trait_selection_warn_removing_apit_params_for_undercapture,
1750        );
1751    }
1752}
1753
1754/// Given a set of captured `DefId` for an RPIT (opaque_def_id) and a given
1755/// function (fn_def_id), try to suggest adding `+ use<...>` to capture just
1756/// the specified parameters. If one of those parameters is an APIT, then try
1757/// to suggest turning it into a regular type parameter.
1758pub fn impl_trait_overcapture_suggestion<'tcx>(
1759    tcx: TyCtxt<'tcx>,
1760    opaque_def_id: LocalDefId,
1761    fn_def_id: LocalDefId,
1762    captured_args: FxIndexSet<DefId>,
1763) -> Option<AddPreciseCapturingForOvercapture> {
1764    let generics = tcx.generics_of(fn_def_id);
1765
1766    let mut captured_lifetimes = FxIndexSet::default();
1767    let mut captured_non_lifetimes = FxIndexSet::default();
1768    let mut synthetics = vec![];
1769
1770    for arg in captured_args {
1771        if tcx.def_kind(arg) == DefKind::LifetimeParam {
1772            captured_lifetimes.insert(tcx.item_name(arg));
1773        } else {
1774            let idx = generics.param_def_id_to_index(tcx, arg).expect("expected arg in scope");
1775            let param = generics.param_at(idx as usize, tcx);
1776            if param.kind.is_synthetic() {
1777                synthetics.push((tcx.def_span(arg), param.name));
1778            } else {
1779                captured_non_lifetimes.insert(tcx.item_name(arg));
1780            }
1781        }
1782    }
1783
1784    let mut next_fresh_param = || {
1785        ["T", "U", "V", "W", "X", "Y", "A", "B", "C"]
1786            .into_iter()
1787            .map(Symbol::intern)
1788            .chain((0..).map(|i| Symbol::intern(&format!("T{i}"))))
1789            .find(|s| captured_non_lifetimes.insert(*s))
1790            .unwrap()
1791    };
1792
1793    let mut suggs = vec![];
1794    let mut apit_spans = vec![];
1795
1796    if !synthetics.is_empty() {
1797        let mut new_params = String::new();
1798        for (i, (span, name)) in synthetics.into_iter().enumerate() {
1799            apit_spans.push(span);
1800
1801            let fresh_param = next_fresh_param();
1802
1803            // Suggest renaming.
1804            suggs.push((span, fresh_param.to_string()));
1805
1806            // Super jank. Turn `impl Trait` into `T: Trait`.
1807            //
1808            // This currently involves stripping the `impl` from the name of
1809            // the parameter, since APITs are always named after how they are
1810            // rendered in the AST. This sucks! But to recreate the bound list
1811            // from the APIT itself would be miserable, so we're stuck with
1812            // this for now!
1813            if i > 0 {
1814                new_params += ", ";
1815            }
1816            let name_as_bounds = name.as_str().trim_start_matches("impl").trim_start();
1817            new_params += fresh_param.as_str();
1818            new_params += ": ";
1819            new_params += name_as_bounds;
1820        }
1821
1822        let Some(generics) = tcx.hir_get_generics(fn_def_id) else {
1823            // This shouldn't happen, but don't ICE.
1824            return None;
1825        };
1826
1827        // Add generics or concatenate to the end of the list.
1828        suggs.push(if let Some(params_span) = generics.span_for_param_suggestion() {
1829            (params_span, format!(", {new_params}"))
1830        } else {
1831            (generics.span, format!("<{new_params}>"))
1832        });
1833    }
1834
1835    let concatenated_bounds = captured_lifetimes
1836        .into_iter()
1837        .chain(captured_non_lifetimes)
1838        .map(|sym| sym.to_string())
1839        .collect::<Vec<_>>()
1840        .join(", ");
1841
1842    let opaque_hir_id = tcx.local_def_id_to_hir_id(opaque_def_id);
1843    // FIXME: This is a bit too conservative, since it ignores parens already written in AST.
1844    let (lparen, rparen) = match tcx
1845        .hir_parent_iter(opaque_hir_id)
1846        .nth(1)
1847        .expect("expected ty to have a parent always")
1848        .1
1849    {
1850        Node::PathSegment(segment)
1851            if segment.args().paren_sugar_output().is_some_and(|ty| ty.hir_id == opaque_hir_id) =>
1852        {
1853            ("(", ")")
1854        }
1855        Node::Ty(ty) => match ty.kind {
1856            rustc_hir::TyKind::Ptr(_) | rustc_hir::TyKind::Ref(..) => ("(", ")"),
1857            // FIXME: RPITs are not allowed to be nested in `impl Fn() -> ...`,
1858            // but we eventually could support that, and that would necessitate
1859            // making this more sophisticated.
1860            _ => ("", ""),
1861        },
1862        _ => ("", ""),
1863    };
1864
1865    let rpit_span = tcx.def_span(opaque_def_id);
1866    if !lparen.is_empty() {
1867        suggs.push((rpit_span.shrink_to_lo(), lparen.to_string()));
1868    }
1869    suggs.push((rpit_span.shrink_to_hi(), format!(" + use<{concatenated_bounds}>{rparen}")));
1870
1871    Some(AddPreciseCapturingForOvercapture { suggs, apit_spans })
1872}
1873
1874pub struct AddPreciseCapturingForOvercapture {
1875    pub suggs: Vec<(Span, String)>,
1876    pub apit_spans: Vec<Span>,
1877}
1878
1879impl Subdiagnostic for AddPreciseCapturingForOvercapture {
1880    fn add_to_diag<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) {
1881        let applicability = if self.apit_spans.is_empty() {
1882            Applicability::MachineApplicable
1883        } else {
1884            // If there are APIT that are converted to regular parameters,
1885            // then this may make the API turbofishable in ways that were
1886            // not intended.
1887            Applicability::MaybeIncorrect
1888        };
1889        diag.multipart_suggestion_verbose(
1890            fluent::trait_selection_precise_capturing_overcaptures,
1891            self.suggs,
1892            applicability,
1893        );
1894        if !self.apit_spans.is_empty() {
1895            diag.span_note(
1896                self.apit_spans,
1897                fluent::trait_selection_warn_removing_apit_params_for_overcapture,
1898            );
1899        }
1900    }
1901}
1902
1903#[derive(Diagnostic)]
1904#[diag(trait_selection_opaque_type_non_generic_param, code = E0792)]
1905pub(crate) struct NonGenericOpaqueTypeParam<'a, 'tcx> {
1906    pub arg: GenericArg<'tcx>,
1907    pub kind: &'a str,
1908    #[primary_span]
1909    pub span: Span,
1910    #[label]
1911    pub param_span: Span,
1912}