rustc_trait_selection/
errors.rs

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