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, 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 {
513                    kind: hir::ItemKind::Fn { ref generics, .. },
514                    ..
515                })
516                | hir::Node::TraitItem(&hir::TraitItem { ref generics, .. })
517                | hir::Node::ImplItem(&hir::ImplItem { ref generics, .. }) => (
518                    generics,
519                    match self.tcx.parent_hir_node(self.tcx.local_def_id_to_hir_id(anon_reg.scope))
520                    {
521                        hir::Node::Item(hir::Item {
522                            kind: hir::ItemKind::Trait(_, _, ref generics, ..),
523                            ..
524                        })
525                        | hir::Node::Item(hir::Item {
526                            kind: hir::ItemKind::Impl(hir::Impl { ref generics, .. }),
527                            ..
528                        }) => Some(generics),
529                        _ => None,
530                    },
531                ),
532                _ => return false,
533            };
534
535            let suggestion_param_name = generics
536                .params
537                .iter()
538                .filter(|p| matches!(p.kind, GenericParamKind::Lifetime { .. }))
539                .map(|p| p.name.ident().name)
540                .find(|i| *i != kw::UnderscoreLifetime);
541            let introduce_new = suggestion_param_name.is_none();
542
543            let mut default = "'a".to_string();
544            if let Some(parent_generics) = parent_generics {
545                let used: FxHashSet<_> = parent_generics
546                    .params
547                    .iter()
548                    .filter(|p| matches!(p.kind, GenericParamKind::Lifetime { .. }))
549                    .map(|p| p.name.ident().name)
550                    .filter(|i| *i != kw::UnderscoreLifetime)
551                    .map(|l| l.to_string())
552                    .collect();
553                if let Some(lt) =
554                    ('a'..='z').map(|it| format!("'{it}")).find(|it| !used.contains(it))
555                {
556                    // We want a lifetime that *isn't* present in the `trait` or `impl` that assoc
557                    // `fn` belongs to. We could suggest reusing one of their lifetimes, but it is
558                    // likely to be an over-constraining lifetime requirement, so we always add a
559                    // lifetime to the `fn`.
560                    default = lt;
561                }
562            }
563            let suggestion_param_name =
564                suggestion_param_name.map(|n| n.to_string()).unwrap_or_else(|| default);
565
566            struct ImplicitLifetimeFinder {
567                suggestions: Vec<(Span, String)>,
568                suggestion_param_name: String,
569            }
570
571            impl<'v> Visitor<'v> for ImplicitLifetimeFinder {
572                fn visit_ty(&mut self, ty: &'v hir::Ty<'v, AmbigArg>) {
573                    let make_suggestion = |ident: Ident| {
574                        if ident.name == kw::Empty && ident.span.is_empty() {
575                            format!("{}, ", self.suggestion_param_name)
576                        } else if ident.name == kw::UnderscoreLifetime && ident.span.is_empty() {
577                            format!("{} ", self.suggestion_param_name)
578                        } else {
579                            self.suggestion_param_name.clone()
580                        }
581                    };
582                    match ty.kind {
583                        hir::TyKind::Path(hir::QPath::Resolved(_, path)) => {
584                            for segment in path.segments {
585                                if let Some(args) = segment.args {
586                                    if args.args.iter().all(|arg| {
587                                        matches!(
588                                            arg,
589                                            hir::GenericArg::Lifetime(lifetime)
590                                            if lifetime.ident.name == kw::Empty
591                                        )
592                                    }) {
593                                        self.suggestions.push((
594                                            segment.ident.span.shrink_to_hi(),
595                                            format!(
596                                                "<{}>",
597                                                args.args
598                                                    .iter()
599                                                    .map(|_| self.suggestion_param_name.clone())
600                                                    .collect::<Vec<_>>()
601                                                    .join(", ")
602                                            ),
603                                        ));
604                                    } else {
605                                        for arg in args.args {
606                                            if let hir::GenericArg::Lifetime(lifetime) = arg
607                                                && lifetime.is_anonymous()
608                                            {
609                                                self.suggestions.push((
610                                                    lifetime.ident.span,
611                                                    make_suggestion(lifetime.ident),
612                                                ));
613                                            }
614                                        }
615                                    }
616                                }
617                            }
618                        }
619                        hir::TyKind::Ref(lifetime, ..) if lifetime.is_anonymous() => {
620                            self.suggestions
621                                .push((lifetime.ident.span, make_suggestion(lifetime.ident)));
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) -> rustc_errors::DiagArgValue {
791        match self {
792            TyOrSig::Ty(ty) => ty.into_diag_arg(),
793            TyOrSig::ClosureSig(sig) => sig.into_diag_arg(),
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
1122pub struct MoreTargeted {
1123    pub ident: Symbol,
1124}
1125
1126impl Subdiagnostic for MoreTargeted {
1127    fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
1128        self,
1129        diag: &mut Diag<'_, G>,
1130        _f: &F,
1131    ) {
1132        diag.code(E0772);
1133        diag.primary_message(fluent::trait_selection_more_targeted);
1134        diag.arg("ident", self.ident);
1135    }
1136}
1137
1138#[derive(Diagnostic)]
1139#[diag(trait_selection_but_needs_to_satisfy, code = E0759)]
1140pub struct ButNeedsToSatisfy {
1141    #[primary_span]
1142    pub sp: Span,
1143    #[label(trait_selection_influencer)]
1144    pub influencer_point: Span,
1145    #[label(trait_selection_used_here)]
1146    pub spans: Vec<Span>,
1147    #[label(trait_selection_require)]
1148    pub require_span_as_label: Option<Span>,
1149    #[note(trait_selection_require)]
1150    pub require_span_as_note: Option<Span>,
1151    #[note(trait_selection_introduced_by_bound)]
1152    pub bound: Option<Span>,
1153
1154    #[subdiagnostic]
1155    pub req_introduces_loc: Option<ReqIntroducedLocations>,
1156
1157    pub has_param_name: bool,
1158    pub param_name: String,
1159    pub spans_empty: bool,
1160    pub has_lifetime: bool,
1161    pub lifetime: String,
1162}
1163
1164#[derive(Diagnostic)]
1165#[diag(trait_selection_outlives_content, code = E0312)]
1166pub struct OutlivesContent<'a> {
1167    #[primary_span]
1168    pub span: Span,
1169    #[subdiagnostic]
1170    pub notes: Vec<note_and_explain::RegionExplanation<'a>>,
1171}
1172
1173#[derive(Diagnostic)]
1174#[diag(trait_selection_outlives_bound, code = E0476)]
1175pub struct OutlivesBound<'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_fulfill_req_lifetime, code = E0477)]
1184pub struct FulfillReqLifetime<'a> {
1185    #[primary_span]
1186    pub span: Span,
1187    pub ty: Ty<'a>,
1188    #[subdiagnostic]
1189    pub note: Option<note_and_explain::RegionExplanation<'a>>,
1190}
1191
1192#[derive(Diagnostic)]
1193#[diag(trait_selection_lf_bound_not_satisfied, code = E0478)]
1194pub struct LfBoundNotSatisfied<'a> {
1195    #[primary_span]
1196    pub span: Span,
1197    #[subdiagnostic]
1198    pub notes: Vec<note_and_explain::RegionExplanation<'a>>,
1199}
1200
1201#[derive(Diagnostic)]
1202#[diag(trait_selection_ref_longer_than_data, code = E0491)]
1203pub struct RefLongerThanData<'a> {
1204    #[primary_span]
1205    pub span: Span,
1206    pub ty: Ty<'a>,
1207    #[subdiagnostic]
1208    pub notes: Vec<note_and_explain::RegionExplanation<'a>>,
1209}
1210
1211#[derive(Subdiagnostic)]
1212pub enum WhereClauseSuggestions {
1213    #[suggestion(
1214        trait_selection_where_remove,
1215        code = "",
1216        applicability = "machine-applicable",
1217        style = "verbose"
1218    )]
1219    Remove {
1220        #[primary_span]
1221        span: Span,
1222    },
1223    #[suggestion(
1224        trait_selection_where_copy_predicates,
1225        code = "{space}where {trait_predicates}",
1226        applicability = "machine-applicable",
1227        style = "verbose"
1228    )]
1229    CopyPredicates {
1230        #[primary_span]
1231        span: Span,
1232        space: &'static str,
1233        trait_predicates: String,
1234    },
1235}
1236
1237#[derive(Subdiagnostic)]
1238pub enum SuggestRemoveSemiOrReturnBinding {
1239    #[multipart_suggestion(
1240        trait_selection_srs_remove_and_box,
1241        applicability = "machine-applicable"
1242    )]
1243    RemoveAndBox {
1244        #[suggestion_part(code = "Box::new(")]
1245        first_lo: Span,
1246        #[suggestion_part(code = ")")]
1247        first_hi: Span,
1248        #[suggestion_part(code = "Box::new(")]
1249        second_lo: Span,
1250        #[suggestion_part(code = ")")]
1251        second_hi: Span,
1252        #[suggestion_part(code = "")]
1253        sp: Span,
1254    },
1255    #[suggestion(
1256        trait_selection_srs_remove,
1257        style = "short",
1258        code = "",
1259        applicability = "machine-applicable"
1260    )]
1261    Remove {
1262        #[primary_span]
1263        sp: Span,
1264    },
1265    #[suggestion(
1266        trait_selection_srs_add,
1267        style = "verbose",
1268        code = "{code}",
1269        applicability = "maybe-incorrect"
1270    )]
1271    Add {
1272        #[primary_span]
1273        sp: Span,
1274        code: String,
1275        ident: Ident,
1276    },
1277    #[note(trait_selection_srs_add_one)]
1278    AddOne {
1279        #[primary_span]
1280        spans: MultiSpan,
1281    },
1282}
1283
1284#[derive(Subdiagnostic)]
1285pub enum ConsiderAddingAwait {
1286    #[help(trait_selection_await_both_futures)]
1287    BothFuturesHelp,
1288    #[multipart_suggestion(trait_selection_await_both_futures, applicability = "maybe-incorrect")]
1289    BothFuturesSugg {
1290        #[suggestion_part(code = ".await")]
1291        first: Span,
1292        #[suggestion_part(code = ".await")]
1293        second: Span,
1294    },
1295    #[suggestion(
1296        trait_selection_await_future,
1297        code = ".await",
1298        style = "verbose",
1299        applicability = "maybe-incorrect"
1300    )]
1301    FutureSugg {
1302        #[primary_span]
1303        span: Span,
1304    },
1305    #[note(trait_selection_await_note)]
1306    FutureSuggNote {
1307        #[primary_span]
1308        span: Span,
1309    },
1310    #[multipart_suggestion(
1311        trait_selection_await_future,
1312        style = "verbose",
1313        applicability = "maybe-incorrect"
1314    )]
1315    FutureSuggMultiple {
1316        #[suggestion_part(code = ".await")]
1317        spans: Vec<Span>,
1318    },
1319}
1320
1321#[derive(Diagnostic)]
1322pub enum PlaceholderRelationLfNotSatisfied {
1323    #[diag(trait_selection_lf_bound_not_satisfied)]
1324    HasBoth {
1325        #[primary_span]
1326        span: Span,
1327        #[note(trait_selection_prlf_defined_with_sub)]
1328        sub_span: Span,
1329        #[note(trait_selection_prlf_must_outlive_with_sup)]
1330        sup_span: Span,
1331        sub_symbol: Symbol,
1332        sup_symbol: Symbol,
1333        #[note(trait_selection_prlf_known_limitation)]
1334        note: (),
1335    },
1336    #[diag(trait_selection_lf_bound_not_satisfied)]
1337    HasSub {
1338        #[primary_span]
1339        span: Span,
1340        #[note(trait_selection_prlf_defined_with_sub)]
1341        sub_span: Span,
1342        #[note(trait_selection_prlf_must_outlive_without_sup)]
1343        sup_span: Span,
1344        sub_symbol: Symbol,
1345        #[note(trait_selection_prlf_known_limitation)]
1346        note: (),
1347    },
1348    #[diag(trait_selection_lf_bound_not_satisfied)]
1349    HasSup {
1350        #[primary_span]
1351        span: Span,
1352        #[note(trait_selection_prlf_defined_without_sub)]
1353        sub_span: Span,
1354        #[note(trait_selection_prlf_must_outlive_with_sup)]
1355        sup_span: Span,
1356        sup_symbol: Symbol,
1357        #[note(trait_selection_prlf_known_limitation)]
1358        note: (),
1359    },
1360    #[diag(trait_selection_lf_bound_not_satisfied)]
1361    HasNone {
1362        #[primary_span]
1363        span: Span,
1364        #[note(trait_selection_prlf_defined_without_sub)]
1365        sub_span: Span,
1366        #[note(trait_selection_prlf_must_outlive_without_sup)]
1367        sup_span: Span,
1368        #[note(trait_selection_prlf_known_limitation)]
1369        note: (),
1370    },
1371    #[diag(trait_selection_lf_bound_not_satisfied)]
1372    OnlyPrimarySpan {
1373        #[primary_span]
1374        span: Span,
1375        #[note(trait_selection_prlf_known_limitation)]
1376        note: (),
1377    },
1378}
1379
1380#[derive(Diagnostic)]
1381#[diag(trait_selection_opaque_captures_lifetime, code = E0700)]
1382pub struct OpaqueCapturesLifetime<'tcx> {
1383    #[primary_span]
1384    pub span: Span,
1385    #[label]
1386    pub opaque_ty_span: Span,
1387    pub opaque_ty: Ty<'tcx>,
1388}
1389
1390#[derive(Subdiagnostic)]
1391pub enum FunctionPointerSuggestion<'a> {
1392    #[suggestion(
1393        trait_selection_fps_use_ref,
1394        code = "&",
1395        style = "verbose",
1396        applicability = "maybe-incorrect"
1397    )]
1398    UseRef {
1399        #[primary_span]
1400        span: Span,
1401    },
1402    #[suggestion(
1403        trait_selection_fps_remove_ref,
1404        code = "{fn_name}",
1405        style = "verbose",
1406        applicability = "maybe-incorrect"
1407    )]
1408    RemoveRef {
1409        #[primary_span]
1410        span: Span,
1411        #[skip_arg]
1412        fn_name: String,
1413    },
1414    #[suggestion(
1415        trait_selection_fps_cast,
1416        code = "&({fn_name} as {sig})",
1417        style = "verbose",
1418        applicability = "maybe-incorrect"
1419    )]
1420    CastRef {
1421        #[primary_span]
1422        span: Span,
1423        #[skip_arg]
1424        fn_name: String,
1425        #[skip_arg]
1426        sig: Binder<'a, FnSig<'a>>,
1427    },
1428    #[suggestion(
1429        trait_selection_fps_cast,
1430        code = " as {sig}",
1431        style = "verbose",
1432        applicability = "maybe-incorrect"
1433    )]
1434    Cast {
1435        #[primary_span]
1436        span: Span,
1437        #[skip_arg]
1438        sig: Binder<'a, FnSig<'a>>,
1439    },
1440    #[suggestion(
1441        trait_selection_fps_cast_both,
1442        code = " as {found_sig}",
1443        style = "hidden",
1444        applicability = "maybe-incorrect"
1445    )]
1446    CastBoth {
1447        #[primary_span]
1448        span: Span,
1449        #[skip_arg]
1450        found_sig: Binder<'a, FnSig<'a>>,
1451        expected_sig: Binder<'a, FnSig<'a>>,
1452    },
1453    #[suggestion(
1454        trait_selection_fps_cast_both,
1455        code = "&({fn_name} as {found_sig})",
1456        style = "hidden",
1457        applicability = "maybe-incorrect"
1458    )]
1459    CastBothRef {
1460        #[primary_span]
1461        span: Span,
1462        #[skip_arg]
1463        fn_name: String,
1464        #[skip_arg]
1465        found_sig: Binder<'a, FnSig<'a>>,
1466        expected_sig: Binder<'a, FnSig<'a>>,
1467    },
1468}
1469
1470#[derive(Subdiagnostic)]
1471#[note(trait_selection_fps_items_are_distinct)]
1472pub struct FnItemsAreDistinct;
1473
1474#[derive(Subdiagnostic)]
1475#[note(trait_selection_fn_uniq_types)]
1476pub struct FnUniqTypes;
1477
1478#[derive(Subdiagnostic)]
1479#[help(trait_selection_fn_consider_casting)]
1480pub struct FnConsiderCasting {
1481    pub casting: String,
1482}
1483
1484#[derive(Subdiagnostic)]
1485#[help(trait_selection_fn_consider_casting_both)]
1486pub struct FnConsiderCastingBoth<'a> {
1487    pub sig: Binder<'a, FnSig<'a>>,
1488}
1489
1490#[derive(Subdiagnostic)]
1491pub enum SuggestAccessingField<'a> {
1492    #[suggestion(
1493        trait_selection_suggest_accessing_field,
1494        code = "{snippet}.{name}",
1495        applicability = "maybe-incorrect"
1496    )]
1497    Safe {
1498        #[primary_span]
1499        span: Span,
1500        snippet: String,
1501        name: Symbol,
1502        ty: Ty<'a>,
1503    },
1504    #[suggestion(
1505        trait_selection_suggest_accessing_field,
1506        code = "unsafe {{ {snippet}.{name} }}",
1507        applicability = "maybe-incorrect"
1508    )]
1509    Unsafe {
1510        #[primary_span]
1511        span: Span,
1512        snippet: String,
1513        name: Symbol,
1514        ty: Ty<'a>,
1515    },
1516}
1517
1518#[derive(Subdiagnostic)]
1519#[multipart_suggestion(trait_selection_stp_wrap_one, applicability = "maybe-incorrect")]
1520pub struct SuggestTuplePatternOne {
1521    pub variant: String,
1522    #[suggestion_part(code = "{variant}(")]
1523    pub span_low: Span,
1524    #[suggestion_part(code = ")")]
1525    pub span_high: Span,
1526}
1527
1528pub struct SuggestTuplePatternMany {
1529    pub path: String,
1530    pub cause_span: Span,
1531    pub compatible_variants: Vec<String>,
1532}
1533
1534impl Subdiagnostic for SuggestTuplePatternMany {
1535    fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
1536        self,
1537        diag: &mut Diag<'_, G>,
1538        f: &F,
1539    ) {
1540        diag.arg("path", self.path);
1541        let message = f(diag, crate::fluent_generated::trait_selection_stp_wrap_many.into());
1542        diag.multipart_suggestions(
1543            message,
1544            self.compatible_variants.into_iter().map(|variant| {
1545                vec![
1546                    (self.cause_span.shrink_to_lo(), format!("{variant}(")),
1547                    (self.cause_span.shrink_to_hi(), ")".to_string()),
1548                ]
1549            }),
1550            rustc_errors::Applicability::MaybeIncorrect,
1551        );
1552    }
1553}
1554
1555#[derive(Subdiagnostic)]
1556pub enum TypeErrorAdditionalDiags {
1557    #[suggestion(
1558        trait_selection_meant_byte_literal,
1559        code = "b'{code}'",
1560        applicability = "machine-applicable"
1561    )]
1562    MeantByteLiteral {
1563        #[primary_span]
1564        span: Span,
1565        code: String,
1566    },
1567    #[suggestion(
1568        trait_selection_meant_char_literal,
1569        code = "'{code}'",
1570        applicability = "machine-applicable"
1571    )]
1572    MeantCharLiteral {
1573        #[primary_span]
1574        span: Span,
1575        code: String,
1576    },
1577    #[multipart_suggestion(trait_selection_meant_str_literal, applicability = "machine-applicable")]
1578    MeantStrLiteral {
1579        #[suggestion_part(code = "\"")]
1580        start: Span,
1581        #[suggestion_part(code = "\"")]
1582        end: Span,
1583    },
1584    #[suggestion(
1585        trait_selection_consider_specifying_length,
1586        code = "{length}",
1587        applicability = "maybe-incorrect"
1588    )]
1589    ConsiderSpecifyingLength {
1590        #[primary_span]
1591        span: Span,
1592        length: u64,
1593    },
1594    #[note(trait_selection_try_cannot_convert)]
1595    TryCannotConvert { found: String, expected: String },
1596    #[suggestion(
1597        trait_selection_tuple_trailing_comma,
1598        code = ",",
1599        applicability = "machine-applicable"
1600    )]
1601    TupleOnlyComma {
1602        #[primary_span]
1603        span: Span,
1604    },
1605    #[multipart_suggestion(
1606        trait_selection_tuple_trailing_comma,
1607        applicability = "machine-applicable"
1608    )]
1609    TupleAlsoParentheses {
1610        #[suggestion_part(code = "(")]
1611        span_low: Span,
1612        #[suggestion_part(code = ",)")]
1613        span_high: Span,
1614    },
1615    #[suggestion(
1616        trait_selection_suggest_add_let_for_letchains,
1617        style = "verbose",
1618        applicability = "machine-applicable",
1619        code = "let "
1620    )]
1621    AddLetForLetChains {
1622        #[primary_span]
1623        span: Span,
1624    },
1625}
1626
1627#[derive(Diagnostic)]
1628pub enum ObligationCauseFailureCode {
1629    #[diag(trait_selection_oc_method_compat, code = E0308)]
1630    MethodCompat {
1631        #[primary_span]
1632        span: Span,
1633        #[subdiagnostic]
1634        subdiags: Vec<TypeErrorAdditionalDiags>,
1635    },
1636    #[diag(trait_selection_oc_type_compat, code = E0308)]
1637    TypeCompat {
1638        #[primary_span]
1639        span: Span,
1640        #[subdiagnostic]
1641        subdiags: Vec<TypeErrorAdditionalDiags>,
1642    },
1643    #[diag(trait_selection_oc_const_compat, code = E0308)]
1644    ConstCompat {
1645        #[primary_span]
1646        span: Span,
1647        #[subdiagnostic]
1648        subdiags: Vec<TypeErrorAdditionalDiags>,
1649    },
1650    #[diag(trait_selection_oc_try_compat, code = E0308)]
1651    TryCompat {
1652        #[primary_span]
1653        span: Span,
1654        #[subdiagnostic]
1655        subdiags: Vec<TypeErrorAdditionalDiags>,
1656    },
1657    #[diag(trait_selection_oc_match_compat, code = E0308)]
1658    MatchCompat {
1659        #[primary_span]
1660        span: Span,
1661        #[subdiagnostic]
1662        subdiags: Vec<TypeErrorAdditionalDiags>,
1663    },
1664    #[diag(trait_selection_oc_if_else_different, code = E0308)]
1665    IfElseDifferent {
1666        #[primary_span]
1667        span: Span,
1668        #[subdiagnostic]
1669        subdiags: Vec<TypeErrorAdditionalDiags>,
1670    },
1671    #[diag(trait_selection_oc_no_else, code = E0317)]
1672    NoElse {
1673        #[primary_span]
1674        span: Span,
1675    },
1676    #[diag(trait_selection_oc_no_diverge, code = E0308)]
1677    NoDiverge {
1678        #[primary_span]
1679        span: Span,
1680        #[subdiagnostic]
1681        subdiags: Vec<TypeErrorAdditionalDiags>,
1682    },
1683    #[diag(trait_selection_oc_fn_main_correct_type, code = E0580)]
1684    FnMainCorrectType {
1685        #[primary_span]
1686        span: Span,
1687    },
1688    #[diag(trait_selection_oc_fn_lang_correct_type, code = E0308)]
1689    FnLangCorrectType {
1690        #[primary_span]
1691        span: Span,
1692        #[subdiagnostic]
1693        subdiags: Vec<TypeErrorAdditionalDiags>,
1694        lang_item_name: Symbol,
1695    },
1696    #[diag(trait_selection_oc_intrinsic_correct_type, code = E0308)]
1697    IntrinsicCorrectType {
1698        #[primary_span]
1699        span: Span,
1700        #[subdiagnostic]
1701        subdiags: Vec<TypeErrorAdditionalDiags>,
1702    },
1703    #[diag(trait_selection_oc_method_correct_type, code = E0308)]
1704    MethodCorrectType {
1705        #[primary_span]
1706        span: Span,
1707        #[subdiagnostic]
1708        subdiags: Vec<TypeErrorAdditionalDiags>,
1709    },
1710    #[diag(trait_selection_oc_closure_selfref, code = E0644)]
1711    ClosureSelfref {
1712        #[primary_span]
1713        span: Span,
1714    },
1715    #[diag(trait_selection_oc_cant_coerce_force_inline, code = E0308)]
1716    CantCoerceForceInline {
1717        #[primary_span]
1718        span: Span,
1719        #[subdiagnostic]
1720        subdiags: Vec<TypeErrorAdditionalDiags>,
1721    },
1722    #[diag(trait_selection_oc_cant_coerce_intrinsic, code = E0308)]
1723    CantCoerceIntrinsic {
1724        #[primary_span]
1725        span: Span,
1726        #[subdiagnostic]
1727        subdiags: Vec<TypeErrorAdditionalDiags>,
1728    },
1729    #[diag(trait_selection_oc_generic, code = E0308)]
1730    Generic {
1731        #[primary_span]
1732        span: Span,
1733        #[subdiagnostic]
1734        subdiags: Vec<TypeErrorAdditionalDiags>,
1735    },
1736}
1737
1738#[derive(Subdiagnostic)]
1739pub enum AddPreciseCapturing {
1740    #[suggestion(
1741        trait_selection_precise_capturing_new,
1742        style = "verbose",
1743        code = " + use<{concatenated_bounds}>",
1744        applicability = "machine-applicable"
1745    )]
1746    New {
1747        #[primary_span]
1748        span: Span,
1749        new_lifetime: Symbol,
1750        concatenated_bounds: String,
1751    },
1752    #[suggestion(
1753        trait_selection_precise_capturing_existing,
1754        style = "verbose",
1755        code = "{pre}{new_lifetime}{post}",
1756        applicability = "machine-applicable"
1757    )]
1758    Existing {
1759        #[primary_span]
1760        span: Span,
1761        new_lifetime: Symbol,
1762        pre: &'static str,
1763        post: &'static str,
1764    },
1765}
1766
1767pub struct AddPreciseCapturingAndParams {
1768    pub suggs: Vec<(Span, String)>,
1769    pub new_lifetime: Symbol,
1770    pub apit_spans: Vec<Span>,
1771}
1772
1773impl Subdiagnostic for AddPreciseCapturingAndParams {
1774    fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
1775        self,
1776        diag: &mut Diag<'_, G>,
1777        _f: &F,
1778    ) {
1779        diag.arg("new_lifetime", self.new_lifetime);
1780        diag.multipart_suggestion_verbose(
1781            fluent::trait_selection_precise_capturing_new_but_apit,
1782            self.suggs,
1783            Applicability::MaybeIncorrect,
1784        );
1785        diag.span_note(
1786            self.apit_spans,
1787            fluent::trait_selection_warn_removing_apit_params_for_undercapture,
1788        );
1789    }
1790}
1791
1792/// Given a set of captured `DefId` for an RPIT (opaque_def_id) and a given
1793/// function (fn_def_id), try to suggest adding `+ use<...>` to capture just
1794/// the specified parameters. If one of those parameters is an APIT, then try
1795/// to suggest turning it into a regular type parameter.
1796pub fn impl_trait_overcapture_suggestion<'tcx>(
1797    tcx: TyCtxt<'tcx>,
1798    opaque_def_id: LocalDefId,
1799    fn_def_id: LocalDefId,
1800    captured_args: FxIndexSet<DefId>,
1801) -> Option<AddPreciseCapturingForOvercapture> {
1802    let generics = tcx.generics_of(fn_def_id);
1803
1804    let mut captured_lifetimes = FxIndexSet::default();
1805    let mut captured_non_lifetimes = FxIndexSet::default();
1806    let mut synthetics = vec![];
1807
1808    for arg in captured_args {
1809        if tcx.def_kind(arg) == DefKind::LifetimeParam {
1810            captured_lifetimes.insert(tcx.item_name(arg));
1811        } else {
1812            let idx = generics.param_def_id_to_index(tcx, arg).expect("expected arg in scope");
1813            let param = generics.param_at(idx as usize, tcx);
1814            if param.kind.is_synthetic() {
1815                synthetics.push((tcx.def_span(arg), param.name));
1816            } else {
1817                captured_non_lifetimes.insert(tcx.item_name(arg));
1818            }
1819        }
1820    }
1821
1822    let mut next_fresh_param = || {
1823        ["T", "U", "V", "W", "X", "Y", "A", "B", "C"]
1824            .into_iter()
1825            .map(Symbol::intern)
1826            .chain((0..).map(|i| Symbol::intern(&format!("T{i}"))))
1827            .find(|s| captured_non_lifetimes.insert(*s))
1828            .unwrap()
1829    };
1830
1831    let mut suggs = vec![];
1832    let mut apit_spans = vec![];
1833
1834    if !synthetics.is_empty() {
1835        let mut new_params = String::new();
1836        for (i, (span, name)) in synthetics.into_iter().enumerate() {
1837            apit_spans.push(span);
1838
1839            let fresh_param = next_fresh_param();
1840
1841            // Suggest renaming.
1842            suggs.push((span, fresh_param.to_string()));
1843
1844            // Super jank. Turn `impl Trait` into `T: Trait`.
1845            //
1846            // This currently involves stripping the `impl` from the name of
1847            // the parameter, since APITs are always named after how they are
1848            // rendered in the AST. This sucks! But to recreate the bound list
1849            // from the APIT itself would be miserable, so we're stuck with
1850            // this for now!
1851            if i > 0 {
1852                new_params += ", ";
1853            }
1854            let name_as_bounds = name.as_str().trim_start_matches("impl").trim_start();
1855            new_params += fresh_param.as_str();
1856            new_params += ": ";
1857            new_params += name_as_bounds;
1858        }
1859
1860        let Some(generics) = tcx.hir_get_generics(fn_def_id) else {
1861            // This shouldn't happen, but don't ICE.
1862            return None;
1863        };
1864
1865        // Add generics or concatenate to the end of the list.
1866        suggs.push(if let Some(params_span) = generics.span_for_param_suggestion() {
1867            (params_span, format!(", {new_params}"))
1868        } else {
1869            (generics.span, format!("<{new_params}>"))
1870        });
1871    }
1872
1873    let concatenated_bounds = captured_lifetimes
1874        .into_iter()
1875        .chain(captured_non_lifetimes)
1876        .map(|sym| sym.to_string())
1877        .collect::<Vec<_>>()
1878        .join(", ");
1879
1880    let opaque_hir_id = tcx.local_def_id_to_hir_id(opaque_def_id);
1881    // FIXME: This is a bit too conservative, since it ignores parens already written in AST.
1882    let (lparen, rparen) = match tcx
1883        .hir()
1884        .parent_iter(opaque_hir_id)
1885        .nth(1)
1886        .expect("expected ty to have a parent always")
1887        .1
1888    {
1889        Node::PathSegment(segment)
1890            if segment.args().paren_sugar_output().is_some_and(|ty| ty.hir_id == opaque_hir_id) =>
1891        {
1892            ("(", ")")
1893        }
1894        Node::Ty(ty) => match ty.kind {
1895            rustc_hir::TyKind::Ptr(_) | rustc_hir::TyKind::Ref(..) => ("(", ")"),
1896            // FIXME: RPITs are not allowed to be nested in `impl Fn() -> ...`,
1897            // but we eventually could support that, and that would necessitate
1898            // making this more sophisticated.
1899            _ => ("", ""),
1900        },
1901        _ => ("", ""),
1902    };
1903
1904    let rpit_span = tcx.def_span(opaque_def_id);
1905    if !lparen.is_empty() {
1906        suggs.push((rpit_span.shrink_to_lo(), lparen.to_string()));
1907    }
1908    suggs.push((rpit_span.shrink_to_hi(), format!(" + use<{concatenated_bounds}>{rparen}")));
1909
1910    Some(AddPreciseCapturingForOvercapture { suggs, apit_spans })
1911}
1912
1913pub struct AddPreciseCapturingForOvercapture {
1914    pub suggs: Vec<(Span, String)>,
1915    pub apit_spans: Vec<Span>,
1916}
1917
1918impl Subdiagnostic for AddPreciseCapturingForOvercapture {
1919    fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
1920        self,
1921        diag: &mut Diag<'_, G>,
1922        _f: &F,
1923    ) {
1924        let applicability = if self.apit_spans.is_empty() {
1925            Applicability::MachineApplicable
1926        } else {
1927            // If there are APIT that are converted to regular parameters,
1928            // then this may make the API turbofishable in ways that were
1929            // not intended.
1930            Applicability::MaybeIncorrect
1931        };
1932        diag.multipart_suggestion_verbose(
1933            fluent::trait_selection_precise_capturing_overcaptures,
1934            self.suggs,
1935            applicability,
1936        );
1937        if !self.apit_spans.is_empty() {
1938            diag.span_note(
1939                self.apit_spans,
1940                fluent::trait_selection_warn_removing_apit_params_for_overcapture,
1941            );
1942        }
1943    }
1944}