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