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