rustc_resolve/late/
diagnostics.rs

1// ignore-tidy-filelength
2
3use std::borrow::Cow;
4use std::iter;
5use std::ops::Deref;
6
7use rustc_ast::ptr::P;
8use rustc_ast::visit::{FnCtxt, FnKind, LifetimeCtxt, Visitor, walk_ty};
9use rustc_ast::{
10    self as ast, AssocItemKind, DUMMY_NODE_ID, Expr, ExprKind, GenericParam, GenericParamKind,
11    Item, ItemKind, MethodCall, NodeId, Path, Ty, TyKind,
12};
13use rustc_ast_pretty::pprust::where_bound_predicate_to_string;
14use rustc_data_structures::fx::{FxHashSet, FxIndexSet};
15use rustc_errors::codes::*;
16use rustc_errors::{
17    Applicability, Diag, ErrorGuaranteed, MultiSpan, SuggestionStyle, pluralize,
18    struct_span_code_err,
19};
20use rustc_hir as hir;
21use rustc_hir::def::Namespace::{self, *};
22use rustc_hir::def::{self, CtorKind, CtorOf, DefKind};
23use rustc_hir::def_id::{CRATE_DEF_ID, DefId};
24use rustc_hir::{MissingLifetimeKind, PrimTy};
25use rustc_middle::ty;
26use rustc_session::{Session, lint};
27use rustc_span::edit_distance::find_best_match_for_name;
28use rustc_span::edition::Edition;
29use rustc_span::hygiene::MacroKind;
30use rustc_span::{DUMMY_SP, Ident, Span, Symbol, kw, sym};
31use thin_vec::ThinVec;
32use tracing::debug;
33
34use super::NoConstantGenericsReason;
35use crate::diagnostics::{ImportSuggestion, LabelSuggestion, TypoSuggestion};
36use crate::late::{
37    AliasPossibility, LateResolutionVisitor, LifetimeBinderKind, LifetimeRes, LifetimeRibKind,
38    LifetimeUseSet, RibKind,
39};
40use crate::ty::fast_reject::SimplifiedType;
41use crate::{
42    Module, ModuleKind, ModuleOrUniformRoot, PathResult, PathSource, Segment, errors,
43    path_names_to_string,
44};
45
46type Res = def::Res<ast::NodeId>;
47
48/// A field or associated item from self type suggested in case of resolution failure.
49enum AssocSuggestion {
50    Field(Span),
51    MethodWithSelf { called: bool },
52    AssocFn { called: bool },
53    AssocType,
54    AssocConst,
55}
56
57impl AssocSuggestion {
58    fn action(&self) -> &'static str {
59        match self {
60            AssocSuggestion::Field(_) => "use the available field",
61            AssocSuggestion::MethodWithSelf { called: true } => {
62                "call the method with the fully-qualified path"
63            }
64            AssocSuggestion::MethodWithSelf { called: false } => {
65                "refer to the method with the fully-qualified path"
66            }
67            AssocSuggestion::AssocFn { called: true } => "call the associated function",
68            AssocSuggestion::AssocFn { called: false } => "refer to the associated function",
69            AssocSuggestion::AssocConst => "use the associated `const`",
70            AssocSuggestion::AssocType => "use the associated type",
71        }
72    }
73}
74
75fn is_self_type(path: &[Segment], namespace: Namespace) -> bool {
76    namespace == TypeNS && path.len() == 1 && path[0].ident.name == kw::SelfUpper
77}
78
79fn is_self_value(path: &[Segment], namespace: Namespace) -> bool {
80    namespace == ValueNS && path.len() == 1 && path[0].ident.name == kw::SelfLower
81}
82
83/// Gets the stringified path for an enum from an `ImportSuggestion` for an enum variant.
84fn import_candidate_to_enum_paths(suggestion: &ImportSuggestion) -> (String, String) {
85    let variant_path = &suggestion.path;
86    let variant_path_string = path_names_to_string(variant_path);
87
88    let path_len = suggestion.path.segments.len();
89    let enum_path = ast::Path {
90        span: suggestion.path.span,
91        segments: suggestion.path.segments[0..path_len - 1].iter().cloned().collect(),
92        tokens: None,
93    };
94    let enum_path_string = path_names_to_string(&enum_path);
95
96    (variant_path_string, enum_path_string)
97}
98
99/// Description of an elided lifetime.
100#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug)]
101pub(super) struct MissingLifetime {
102    /// Used to overwrite the resolution with the suggestion, to avoid cascading errors.
103    pub id: NodeId,
104    /// As we cannot yet emit lints in this crate and have to buffer them instead,
105    /// we need to associate each lint with some `NodeId`,
106    /// however for some `MissingLifetime`s their `NodeId`s are "fake",
107    /// in a sense that they are temporary and not get preserved down the line,
108    /// which means that the lints for those nodes will not get emitted.
109    /// To combat this, we can try to use some other `NodeId`s as a fallback option.
110    pub id_for_lint: NodeId,
111    /// Where to suggest adding the lifetime.
112    pub span: Span,
113    /// How the lifetime was introduced, to have the correct space and comma.
114    pub kind: MissingLifetimeKind,
115    /// Number of elided lifetimes, used for elision in path.
116    pub count: usize,
117}
118
119/// Description of the lifetimes appearing in a function parameter.
120/// This is used to provide a literal explanation to the elision failure.
121#[derive(Clone, Debug)]
122pub(super) struct ElisionFnParameter {
123    /// The index of the argument in the original definition.
124    pub index: usize,
125    /// The name of the argument if it's a simple ident.
126    pub ident: Option<Ident>,
127    /// The number of lifetimes in the parameter.
128    pub lifetime_count: usize,
129    /// The span of the parameter.
130    pub span: Span,
131}
132
133/// Description of lifetimes that appear as candidates for elision.
134/// This is used to suggest introducing an explicit lifetime.
135#[derive(Debug)]
136pub(super) enum LifetimeElisionCandidate {
137    /// This is not a real lifetime.
138    Ignore,
139    /// There is a named lifetime, we won't suggest anything.
140    Named,
141    Missing(MissingLifetime),
142}
143
144/// Only used for diagnostics.
145#[derive(Debug)]
146struct BaseError {
147    msg: String,
148    fallback_label: String,
149    span: Span,
150    span_label: Option<(Span, &'static str)>,
151    could_be_expr: bool,
152    suggestion: Option<(Span, &'static str, String)>,
153    module: Option<DefId>,
154}
155
156#[derive(Debug)]
157enum TypoCandidate {
158    Typo(TypoSuggestion),
159    Shadowed(Res, Option<Span>),
160    None,
161}
162
163impl TypoCandidate {
164    fn to_opt_suggestion(self) -> Option<TypoSuggestion> {
165        match self {
166            TypoCandidate::Typo(sugg) => Some(sugg),
167            TypoCandidate::Shadowed(_, _) | TypoCandidate::None => None,
168        }
169    }
170}
171
172impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
173    fn make_base_error(
174        &mut self,
175        path: &[Segment],
176        span: Span,
177        source: PathSource<'_>,
178        res: Option<Res>,
179    ) -> BaseError {
180        // Make the base error.
181        let mut expected = source.descr_expected();
182        let path_str = Segment::names_to_string(path);
183        let item_str = path.last().unwrap().ident;
184        if let Some(res) = res {
185            BaseError {
186                msg: format!("expected {}, found {} `{}`", expected, res.descr(), path_str),
187                fallback_label: format!("not a {expected}"),
188                span,
189                span_label: match res {
190                    Res::Def(DefKind::TyParam, def_id) => {
191                        Some((self.r.def_span(def_id), "found this type parameter"))
192                    }
193                    _ => None,
194                },
195                could_be_expr: match res {
196                    Res::Def(DefKind::Fn, _) => {
197                        // Verify whether this is a fn call or an Fn used as a type.
198                        self.r
199                            .tcx
200                            .sess
201                            .source_map()
202                            .span_to_snippet(span)
203                            .is_ok_and(|snippet| snippet.ends_with(')'))
204                    }
205                    Res::Def(
206                        DefKind::Ctor(..) | DefKind::AssocFn | DefKind::Const | DefKind::AssocConst,
207                        _,
208                    )
209                    | Res::SelfCtor(_)
210                    | Res::PrimTy(_)
211                    | Res::Local(_) => true,
212                    _ => false,
213                },
214                suggestion: None,
215                module: None,
216            }
217        } else {
218            let mut span_label = None;
219            let item_ident = path.last().unwrap().ident;
220            let item_span = item_ident.span;
221            let (mod_prefix, mod_str, module, suggestion) = if path.len() == 1 {
222                debug!(?self.diag_metadata.current_impl_items);
223                debug!(?self.diag_metadata.current_function);
224                let suggestion = if self.current_trait_ref.is_none()
225                    && let Some((fn_kind, _)) = self.diag_metadata.current_function
226                    && let Some(FnCtxt::Assoc(_)) = fn_kind.ctxt()
227                    && let FnKind::Fn(_, _, _, ast::Fn { sig, .. }) = fn_kind
228                    && let Some(items) = self.diag_metadata.current_impl_items
229                    && let Some(item) = items.iter().find(|i| {
230                        i.ident.name == item_str.name
231                            // Don't suggest if the item is in Fn signature arguments (#112590).
232                            && !sig.span.contains(item_span)
233                    }) {
234                    let sp = item_span.shrink_to_lo();
235
236                    // Account for `Foo { field }` when suggesting `self.field` so we result on
237                    // `Foo { field: self.field }`.
238                    let field = match source {
239                        PathSource::Expr(Some(Expr { kind: ExprKind::Struct(expr), .. })) => {
240                            expr.fields.iter().find(|f| f.ident == item_ident)
241                        }
242                        _ => None,
243                    };
244                    let pre = if let Some(field) = field
245                        && field.is_shorthand
246                    {
247                        format!("{item_ident}: ")
248                    } else {
249                        String::new()
250                    };
251                    // Ensure we provide a structured suggestion for an assoc fn only for
252                    // expressions that are actually a fn call.
253                    let is_call = match field {
254                        Some(ast::ExprField { expr, .. }) => {
255                            matches!(expr.kind, ExprKind::Call(..))
256                        }
257                        _ => matches!(
258                            source,
259                            PathSource::Expr(Some(Expr { kind: ExprKind::Call(..), .. })),
260                        ),
261                    };
262
263                    match &item.kind {
264                        AssocItemKind::Fn(fn_)
265                            if (!sig.decl.has_self() || !is_call) && fn_.sig.decl.has_self() =>
266                        {
267                            // Ensure that we only suggest `self.` if `self` is available,
268                            // you can't call `fn foo(&self)` from `fn bar()` (#115992).
269                            // We also want to mention that the method exists.
270                            span_label = Some((
271                                item.ident.span,
272                                "a method by that name is available on `Self` here",
273                            ));
274                            None
275                        }
276                        AssocItemKind::Fn(fn_) if !fn_.sig.decl.has_self() && !is_call => {
277                            span_label = Some((
278                                item.ident.span,
279                                "an associated function by that name is available on `Self` here",
280                            ));
281                            None
282                        }
283                        AssocItemKind::Fn(fn_) if fn_.sig.decl.has_self() => {
284                            Some((sp, "consider using the method on `Self`", format!("{pre}self.")))
285                        }
286                        AssocItemKind::Fn(_) => Some((
287                            sp,
288                            "consider using the associated function on `Self`",
289                            format!("{pre}Self::"),
290                        )),
291                        AssocItemKind::Const(..) => Some((
292                            sp,
293                            "consider using the associated constant on `Self`",
294                            format!("{pre}Self::"),
295                        )),
296                        _ => None,
297                    }
298                } else {
299                    None
300                };
301                (String::new(), "this scope".to_string(), None, suggestion)
302            } else if path.len() == 2 && path[0].ident.name == kw::PathRoot {
303                if self.r.tcx.sess.edition() > Edition::Edition2015 {
304                    // In edition 2018 onwards, the `::foo` syntax may only pull from the extern prelude
305                    // which overrides all other expectations of item type
306                    expected = "crate";
307                    (String::new(), "the list of imported crates".to_string(), None, None)
308                } else {
309                    (
310                        String::new(),
311                        "the crate root".to_string(),
312                        Some(CRATE_DEF_ID.to_def_id()),
313                        None,
314                    )
315                }
316            } else if path.len() == 2 && path[0].ident.name == kw::Crate {
317                (String::new(), "the crate root".to_string(), Some(CRATE_DEF_ID.to_def_id()), None)
318            } else {
319                let mod_path = &path[..path.len() - 1];
320                let mod_res = self.resolve_path(mod_path, Some(TypeNS), None);
321                let mod_prefix = match mod_res {
322                    PathResult::Module(ModuleOrUniformRoot::Module(module)) => module.res(),
323                    _ => None,
324                };
325
326                let module_did = mod_prefix.as_ref().and_then(Res::mod_def_id);
327
328                let mod_prefix =
329                    mod_prefix.map_or_else(String::new, |res| (format!("{} ", res.descr())));
330
331                (mod_prefix, format!("`{}`", Segment::names_to_string(mod_path)), module_did, None)
332            };
333
334            let (fallback_label, suggestion) = if path_str == "async"
335                && expected.starts_with("struct")
336            {
337                ("`async` blocks are only allowed in Rust 2018 or later".to_string(), suggestion)
338            } else {
339                // check if we are in situation of typo like `True` instead of `true`.
340                let override_suggestion =
341                    if ["true", "false"].contains(&item_str.to_string().to_lowercase().as_str()) {
342                        let item_typo = item_str.to_string().to_lowercase();
343                        Some((item_span, "you may want to use a bool value instead", item_typo))
344                    // FIXME(vincenzopalazzo): make the check smarter,
345                    // and maybe expand with levenshtein distance checks
346                    } else if item_str.as_str() == "printf" {
347                        Some((
348                            item_span,
349                            "you may have meant to use the `print` macro",
350                            "print!".to_owned(),
351                        ))
352                    } else {
353                        suggestion
354                    };
355                (format!("not found in {mod_str}"), override_suggestion)
356            };
357
358            BaseError {
359                msg: format!("cannot find {expected} `{item_str}` in {mod_prefix}{mod_str}"),
360                fallback_label,
361                span: item_span,
362                span_label,
363                could_be_expr: false,
364                suggestion,
365                module,
366            }
367        }
368    }
369
370    /// Try to suggest for a module path that cannot be resolved.
371    /// Such as `fmt::Debug` where `fmt` is not resolved without importing,
372    /// here we search with `lookup_import_candidates` for a module named `fmt`
373    /// with `TypeNS` as namespace.
374    ///
375    /// We need a separate function here because we won't suggest for a path with single segment
376    /// and we won't change `SourcePath` api `is_expected` to match `Type` with `DefKind::Mod`
377    pub(crate) fn smart_resolve_partial_mod_path_errors(
378        &mut self,
379        prefix_path: &[Segment],
380        following_seg: Option<&Segment>,
381    ) -> Vec<ImportSuggestion> {
382        if let Some(segment) = prefix_path.last()
383            && let Some(following_seg) = following_seg
384        {
385            let candidates = self.r.lookup_import_candidates(
386                segment.ident,
387                Namespace::TypeNS,
388                &self.parent_scope,
389                &|res: Res| matches!(res, Res::Def(DefKind::Mod, _)),
390            );
391            // double check next seg is valid
392            candidates
393                .into_iter()
394                .filter(|candidate| {
395                    if let Some(def_id) = candidate.did
396                        && let Some(module) = self.r.get_module(def_id)
397                    {
398                        Some(def_id) != self.parent_scope.module.opt_def_id()
399                            && self
400                                .r
401                                .resolutions(module)
402                                .borrow()
403                                .iter()
404                                .any(|(key, _r)| key.ident.name == following_seg.ident.name)
405                    } else {
406                        false
407                    }
408                })
409                .collect::<Vec<_>>()
410        } else {
411            Vec::new()
412        }
413    }
414
415    /// Handles error reporting for `smart_resolve_path_fragment` function.
416    /// Creates base error and amends it with one short label and possibly some longer helps/notes.
417    pub(crate) fn smart_resolve_report_errors(
418        &mut self,
419        path: &[Segment],
420        following_seg: Option<&Segment>,
421        span: Span,
422        source: PathSource<'_>,
423        res: Option<Res>,
424    ) -> (Diag<'tcx>, Vec<ImportSuggestion>) {
425        debug!(?res, ?source);
426        let base_error = self.make_base_error(path, span, source, res);
427
428        let code = source.error_code(res.is_some());
429        let mut err = self.r.dcx().struct_span_err(base_error.span, base_error.msg.clone());
430        err.code(code);
431
432        self.detect_missing_binding_available_from_pattern(&mut err, path, following_seg);
433        self.suggest_at_operator_in_slice_pat_with_range(&mut err, path);
434        self.suggest_swapping_misplaced_self_ty_and_trait(&mut err, source, res, base_error.span);
435
436        if let Some((span, label)) = base_error.span_label {
437            err.span_label(span, label);
438        }
439
440        if let Some(ref sugg) = base_error.suggestion {
441            err.span_suggestion_verbose(sugg.0, sugg.1, &sugg.2, Applicability::MaybeIncorrect);
442        }
443
444        self.suggest_bare_struct_literal(&mut err);
445        self.suggest_changing_type_to_const_param(&mut err, res, source, span);
446        self.explain_functions_in_pattern(&mut err, res, source);
447
448        if self.suggest_pattern_match_with_let(&mut err, source, span) {
449            // Fallback label.
450            err.span_label(base_error.span, base_error.fallback_label);
451            return (err, Vec::new());
452        }
453
454        self.suggest_self_or_self_ref(&mut err, path, span);
455        self.detect_assoc_type_constraint_meant_as_path(&mut err, &base_error);
456        if self.suggest_self_ty(&mut err, source, path, span)
457            || self.suggest_self_value(&mut err, source, path, span)
458        {
459            return (err, Vec::new());
460        }
461
462        let (found, suggested_candidates, mut candidates) = self.try_lookup_name_relaxed(
463            &mut err,
464            source,
465            path,
466            following_seg,
467            span,
468            res,
469            &base_error,
470        );
471        if found {
472            return (err, candidates);
473        }
474
475        if self.suggest_shadowed(&mut err, source, path, following_seg, span) {
476            // if there is already a shadowed name, don'suggest candidates for importing
477            candidates.clear();
478        }
479
480        let mut fallback = self.suggest_trait_and_bounds(&mut err, source, res, span, &base_error);
481        fallback |= self.suggest_typo(
482            &mut err,
483            source,
484            path,
485            following_seg,
486            span,
487            &base_error,
488            suggested_candidates,
489        );
490
491        if fallback {
492            // Fallback label.
493            err.span_label(base_error.span, base_error.fallback_label);
494        }
495        self.err_code_special_cases(&mut err, source, path, span);
496
497        if let Some(module) = base_error.module {
498            self.r.find_cfg_stripped(&mut err, &path.last().unwrap().ident.name, module);
499        }
500
501        (err, candidates)
502    }
503
504    fn detect_assoc_type_constraint_meant_as_path(
505        &self,
506        err: &mut Diag<'_>,
507        base_error: &BaseError,
508    ) {
509        let Some(ty) = self.diag_metadata.current_type_path else {
510            return;
511        };
512        let TyKind::Path(_, path) = &ty.kind else {
513            return;
514        };
515        for segment in &path.segments {
516            let Some(params) = &segment.args else {
517                continue;
518            };
519            let ast::GenericArgs::AngleBracketed(ref params) = params.deref() else {
520                continue;
521            };
522            for param in &params.args {
523                let ast::AngleBracketedArg::Constraint(constraint) = param else {
524                    continue;
525                };
526                let ast::AssocItemConstraintKind::Bound { bounds } = &constraint.kind else {
527                    continue;
528                };
529                for bound in bounds {
530                    let ast::GenericBound::Trait(trait_ref) = bound else {
531                        continue;
532                    };
533                    if trait_ref.modifiers == ast::TraitBoundModifiers::NONE
534                        && base_error.span == trait_ref.span
535                    {
536                        err.span_suggestion_verbose(
537                            constraint.ident.span.between(trait_ref.span),
538                            "you might have meant to write a path instead of an associated type bound",
539                            "::",
540                            Applicability::MachineApplicable,
541                        );
542                    }
543                }
544            }
545        }
546    }
547
548    fn suggest_self_or_self_ref(&mut self, err: &mut Diag<'_>, path: &[Segment], span: Span) {
549        if !self.self_type_is_available() {
550            return;
551        }
552        let Some(path_last_segment) = path.last() else { return };
553        let item_str = path_last_segment.ident;
554        // Emit help message for fake-self from other languages (e.g., `this` in JavaScript).
555        if ["this", "my"].contains(&item_str.as_str()) {
556            err.span_suggestion_short(
557                span,
558                "you might have meant to use `self` here instead",
559                "self",
560                Applicability::MaybeIncorrect,
561            );
562            if !self.self_value_is_available(path[0].ident.span) {
563                if let Some((FnKind::Fn(_, _, _, ast::Fn { sig, .. }), fn_span)) =
564                    &self.diag_metadata.current_function
565                {
566                    let (span, sugg) = if let Some(param) = sig.decl.inputs.get(0) {
567                        (param.span.shrink_to_lo(), "&self, ")
568                    } else {
569                        (
570                            self.r
571                                .tcx
572                                .sess
573                                .source_map()
574                                .span_through_char(*fn_span, '(')
575                                .shrink_to_hi(),
576                            "&self",
577                        )
578                    };
579                    err.span_suggestion_verbose(
580                        span,
581                        "if you meant to use `self`, you are also missing a `self` receiver \
582                         argument",
583                        sugg,
584                        Applicability::MaybeIncorrect,
585                    );
586                }
587            }
588        }
589    }
590
591    fn try_lookup_name_relaxed(
592        &mut self,
593        err: &mut Diag<'_>,
594        source: PathSource<'_>,
595        path: &[Segment],
596        following_seg: Option<&Segment>,
597        span: Span,
598        res: Option<Res>,
599        base_error: &BaseError,
600    ) -> (bool, FxHashSet<String>, Vec<ImportSuggestion>) {
601        let span = match following_seg {
602            Some(_) if path[0].ident.span.eq_ctxt(path[path.len() - 1].ident.span) => {
603                // The path `span` that comes in includes any following segments, which we don't
604                // want to replace in the suggestions.
605                path[0].ident.span.to(path[path.len() - 1].ident.span)
606            }
607            _ => span,
608        };
609        let mut suggested_candidates = FxHashSet::default();
610        // Try to lookup name in more relaxed fashion for better error reporting.
611        let ident = path.last().unwrap().ident;
612        let is_expected = &|res| source.is_expected(res);
613        let ns = source.namespace();
614        let is_enum_variant = &|res| matches!(res, Res::Def(DefKind::Variant, _));
615        let path_str = Segment::names_to_string(path);
616        let ident_span = path.last().map_or(span, |ident| ident.ident.span);
617        let mut candidates = self
618            .r
619            .lookup_import_candidates(ident, ns, &self.parent_scope, is_expected)
620            .into_iter()
621            .filter(|ImportSuggestion { did, .. }| {
622                match (did, res.and_then(|res| res.opt_def_id())) {
623                    (Some(suggestion_did), Some(actual_did)) => *suggestion_did != actual_did,
624                    _ => true,
625                }
626            })
627            .collect::<Vec<_>>();
628        // Try to filter out intrinsics candidates, as long as we have
629        // some other candidates to suggest.
630        let intrinsic_candidates: Vec<_> = candidates
631            .extract_if(.., |sugg| {
632                let path = path_names_to_string(&sugg.path);
633                path.starts_with("core::intrinsics::") || path.starts_with("std::intrinsics::")
634            })
635            .collect();
636        if candidates.is_empty() {
637            // Put them back if we have no more candidates to suggest...
638            candidates = intrinsic_candidates;
639        }
640        let crate_def_id = CRATE_DEF_ID.to_def_id();
641        if candidates.is_empty() && is_expected(Res::Def(DefKind::Enum, crate_def_id)) {
642            let mut enum_candidates: Vec<_> = self
643                .r
644                .lookup_import_candidates(ident, ns, &self.parent_scope, is_enum_variant)
645                .into_iter()
646                .map(|suggestion| import_candidate_to_enum_paths(&suggestion))
647                .filter(|(_, enum_ty_path)| !enum_ty_path.starts_with("std::prelude::"))
648                .collect();
649            if !enum_candidates.is_empty() {
650                enum_candidates.sort();
651
652                // Contextualize for E0412 "cannot find type", but don't belabor the point
653                // (that it's a variant) for E0573 "expected type, found variant".
654                let preamble = if res.is_none() {
655                    let others = match enum_candidates.len() {
656                        1 => String::new(),
657                        2 => " and 1 other".to_owned(),
658                        n => format!(" and {n} others"),
659                    };
660                    format!("there is an enum variant `{}`{}; ", enum_candidates[0].0, others)
661                } else {
662                    String::new()
663                };
664                let msg = format!("{preamble}try using the variant's enum");
665
666                suggested_candidates.extend(
667                    enum_candidates
668                        .iter()
669                        .map(|(_variant_path, enum_ty_path)| enum_ty_path.clone()),
670                );
671                err.span_suggestions(
672                    span,
673                    msg,
674                    enum_candidates.into_iter().map(|(_variant_path, enum_ty_path)| enum_ty_path),
675                    Applicability::MachineApplicable,
676                );
677            }
678        }
679
680        // Try finding a suitable replacement.
681        let typo_sugg = self
682            .lookup_typo_candidate(path, following_seg, source.namespace(), is_expected)
683            .to_opt_suggestion()
684            .filter(|sugg| !suggested_candidates.contains(sugg.candidate.as_str()));
685        if let [segment] = path
686            && !matches!(source, PathSource::Delegation)
687            && self.self_type_is_available()
688        {
689            if let Some(candidate) =
690                self.lookup_assoc_candidate(ident, ns, is_expected, source.is_call())
691            {
692                let self_is_available = self.self_value_is_available(segment.ident.span);
693                // Account for `Foo { field }` when suggesting `self.field` so we result on
694                // `Foo { field: self.field }`.
695                let pre = match source {
696                    PathSource::Expr(Some(Expr { kind: ExprKind::Struct(expr), .. }))
697                        if expr
698                            .fields
699                            .iter()
700                            .any(|f| f.ident == segment.ident && f.is_shorthand) =>
701                    {
702                        format!("{path_str}: ")
703                    }
704                    _ => String::new(),
705                };
706                match candidate {
707                    AssocSuggestion::Field(field_span) => {
708                        if self_is_available {
709                            err.span_suggestion_verbose(
710                                span.shrink_to_lo(),
711                                "you might have meant to use the available field",
712                                format!("{pre}self."),
713                                Applicability::MachineApplicable,
714                            );
715                        } else {
716                            err.span_label(field_span, "a field by that name exists in `Self`");
717                        }
718                    }
719                    AssocSuggestion::MethodWithSelf { called } if self_is_available => {
720                        let msg = if called {
721                            "you might have meant to call the method"
722                        } else {
723                            "you might have meant to refer to the method"
724                        };
725                        err.span_suggestion_verbose(
726                            span.shrink_to_lo(),
727                            msg,
728                            "self.",
729                            Applicability::MachineApplicable,
730                        );
731                    }
732                    AssocSuggestion::MethodWithSelf { .. }
733                    | AssocSuggestion::AssocFn { .. }
734                    | AssocSuggestion::AssocConst
735                    | AssocSuggestion::AssocType => {
736                        err.span_suggestion_verbose(
737                            span.shrink_to_lo(),
738                            format!("you might have meant to {}", candidate.action()),
739                            "Self::",
740                            Applicability::MachineApplicable,
741                        );
742                    }
743                }
744                self.r.add_typo_suggestion(err, typo_sugg, ident_span);
745                return (true, suggested_candidates, candidates);
746            }
747
748            // If the first argument in call is `self` suggest calling a method.
749            if let Some((call_span, args_span)) = self.call_has_self_arg(source) {
750                let mut args_snippet = String::new();
751                if let Some(args_span) = args_span {
752                    if let Ok(snippet) = self.r.tcx.sess.source_map().span_to_snippet(args_span) {
753                        args_snippet = snippet;
754                    }
755                }
756
757                err.span_suggestion(
758                    call_span,
759                    format!("try calling `{ident}` as a method"),
760                    format!("self.{path_str}({args_snippet})"),
761                    Applicability::MachineApplicable,
762                );
763                return (true, suggested_candidates, candidates);
764            }
765        }
766
767        // Try context-dependent help if relaxed lookup didn't work.
768        if let Some(res) = res {
769            if self.smart_resolve_context_dependent_help(
770                err,
771                span,
772                source,
773                path,
774                res,
775                &path_str,
776                &base_error.fallback_label,
777            ) {
778                // We do this to avoid losing a secondary span when we override the main error span.
779                self.r.add_typo_suggestion(err, typo_sugg, ident_span);
780                return (true, suggested_candidates, candidates);
781            }
782        }
783
784        // Try to find in last block rib
785        if let Some(rib) = &self.last_block_rib
786            && let RibKind::Normal = rib.kind
787        {
788            for (ident, &res) in &rib.bindings {
789                if let Res::Local(_) = res
790                    && path.len() == 1
791                    && ident.span.eq_ctxt(path[0].ident.span)
792                    && ident.name == path[0].ident.name
793                {
794                    err.span_help(
795                        ident.span,
796                        format!("the binding `{path_str}` is available in a different scope in the same function"),
797                    );
798                    return (true, suggested_candidates, candidates);
799                }
800            }
801        }
802
803        if candidates.is_empty() {
804            candidates = self.smart_resolve_partial_mod_path_errors(path, following_seg);
805        }
806
807        (false, suggested_candidates, candidates)
808    }
809
810    fn suggest_trait_and_bounds(
811        &mut self,
812        err: &mut Diag<'_>,
813        source: PathSource<'_>,
814        res: Option<Res>,
815        span: Span,
816        base_error: &BaseError,
817    ) -> bool {
818        let is_macro =
819            base_error.span.from_expansion() && base_error.span.desugaring_kind().is_none();
820        let mut fallback = false;
821
822        if let (
823            PathSource::Trait(AliasPossibility::Maybe),
824            Some(Res::Def(DefKind::Struct | DefKind::Enum | DefKind::Union, _)),
825            false,
826        ) = (source, res, is_macro)
827        {
828            if let Some(bounds @ [first_bound, .., last_bound]) =
829                self.diag_metadata.current_trait_object
830            {
831                fallback = true;
832                let spans: Vec<Span> = bounds
833                    .iter()
834                    .map(|bound| bound.span())
835                    .filter(|&sp| sp != base_error.span)
836                    .collect();
837
838                let start_span = first_bound.span();
839                // `end_span` is the end of the poly trait ref (Foo + 'baz + Bar><)
840                let end_span = last_bound.span();
841                // `last_bound_span` is the last bound of the poly trait ref (Foo + >'baz< + Bar)
842                let last_bound_span = spans.last().cloned().unwrap();
843                let mut multi_span: MultiSpan = spans.clone().into();
844                for sp in spans {
845                    let msg = if sp == last_bound_span {
846                        format!(
847                            "...because of {these} bound{s}",
848                            these = pluralize!("this", bounds.len() - 1),
849                            s = pluralize!(bounds.len() - 1),
850                        )
851                    } else {
852                        String::new()
853                    };
854                    multi_span.push_span_label(sp, msg);
855                }
856                multi_span.push_span_label(base_error.span, "expected this type to be a trait...");
857                err.span_help(
858                    multi_span,
859                    "`+` is used to constrain a \"trait object\" type with lifetimes or \
860                        auto-traits; structs and enums can't be bound in that way",
861                );
862                if bounds.iter().all(|bound| match bound {
863                    ast::GenericBound::Outlives(_) | ast::GenericBound::Use(..) => true,
864                    ast::GenericBound::Trait(tr) => tr.span == base_error.span,
865                }) {
866                    let mut sugg = vec![];
867                    if base_error.span != start_span {
868                        sugg.push((start_span.until(base_error.span), String::new()));
869                    }
870                    if base_error.span != end_span {
871                        sugg.push((base_error.span.shrink_to_hi().to(end_span), String::new()));
872                    }
873
874                    err.multipart_suggestion(
875                        "if you meant to use a type and not a trait here, remove the bounds",
876                        sugg,
877                        Applicability::MaybeIncorrect,
878                    );
879                }
880            }
881        }
882
883        fallback |= self.restrict_assoc_type_in_where_clause(span, err);
884        fallback
885    }
886
887    fn suggest_typo(
888        &mut self,
889        err: &mut Diag<'_>,
890        source: PathSource<'_>,
891        path: &[Segment],
892        following_seg: Option<&Segment>,
893        span: Span,
894        base_error: &BaseError,
895        suggested_candidates: FxHashSet<String>,
896    ) -> bool {
897        let is_expected = &|res| source.is_expected(res);
898        let ident_span = path.last().map_or(span, |ident| ident.ident.span);
899        let typo_sugg =
900            self.lookup_typo_candidate(path, following_seg, source.namespace(), is_expected);
901        let mut fallback = false;
902        let typo_sugg = typo_sugg
903            .to_opt_suggestion()
904            .filter(|sugg| !suggested_candidates.contains(sugg.candidate.as_str()));
905        if !self.r.add_typo_suggestion(err, typo_sugg, ident_span) {
906            fallback = true;
907            match self.diag_metadata.current_let_binding {
908                Some((pat_sp, Some(ty_sp), None))
909                    if ty_sp.contains(base_error.span) && base_error.could_be_expr =>
910                {
911                    err.span_suggestion_short(
912                        pat_sp.between(ty_sp),
913                        "use `=` if you meant to assign",
914                        " = ",
915                        Applicability::MaybeIncorrect,
916                    );
917                }
918                _ => {}
919            }
920
921            // If the trait has a single item (which wasn't matched by the algorithm), suggest it
922            let suggestion = self.get_single_associated_item(path, &source, is_expected);
923            self.r.add_typo_suggestion(err, suggestion, ident_span);
924        }
925
926        if self.let_binding_suggestion(err, ident_span) {
927            fallback = false;
928        }
929
930        fallback
931    }
932
933    fn suggest_shadowed(
934        &mut self,
935        err: &mut Diag<'_>,
936        source: PathSource<'_>,
937        path: &[Segment],
938        following_seg: Option<&Segment>,
939        span: Span,
940    ) -> bool {
941        let is_expected = &|res| source.is_expected(res);
942        let typo_sugg =
943            self.lookup_typo_candidate(path, following_seg, source.namespace(), is_expected);
944        let is_in_same_file = &|sp1, sp2| {
945            let source_map = self.r.tcx.sess.source_map();
946            let file1 = source_map.span_to_filename(sp1);
947            let file2 = source_map.span_to_filename(sp2);
948            file1 == file2
949        };
950        // print 'you might have meant' if the candidate is (1) is a shadowed name with
951        // accessible definition and (2) either defined in the same crate as the typo
952        // (could be in a different file) or introduced in the same file as the typo
953        // (could belong to a different crate)
954        if let TypoCandidate::Shadowed(res, Some(sugg_span)) = typo_sugg
955            && res.opt_def_id().is_some_and(|id| id.is_local() || is_in_same_file(span, sugg_span))
956        {
957            err.span_label(
958                sugg_span,
959                format!("you might have meant to refer to this {}", res.descr()),
960            );
961            return true;
962        }
963        false
964    }
965
966    fn err_code_special_cases(
967        &mut self,
968        err: &mut Diag<'_>,
969        source: PathSource<'_>,
970        path: &[Segment],
971        span: Span,
972    ) {
973        if let Some(err_code) = err.code {
974            if err_code == E0425 {
975                for label_rib in &self.label_ribs {
976                    for (label_ident, node_id) in &label_rib.bindings {
977                        let ident = path.last().unwrap().ident;
978                        if format!("'{ident}") == label_ident.to_string() {
979                            err.span_label(label_ident.span, "a label with a similar name exists");
980                            if let PathSource::Expr(Some(Expr {
981                                kind: ExprKind::Break(None, Some(_)),
982                                ..
983                            })) = source
984                            {
985                                err.span_suggestion(
986                                    span,
987                                    "use the similarly named label",
988                                    label_ident.name,
989                                    Applicability::MaybeIncorrect,
990                                );
991                                // Do not lint against unused label when we suggest them.
992                                self.diag_metadata.unused_labels.remove(node_id);
993                            }
994                        }
995                    }
996                }
997            } else if err_code == E0412 {
998                if let Some(correct) = Self::likely_rust_type(path) {
999                    err.span_suggestion(
1000                        span,
1001                        "perhaps you intended to use this type",
1002                        correct,
1003                        Applicability::MaybeIncorrect,
1004                    );
1005                }
1006            }
1007        }
1008    }
1009
1010    /// Emit special messages for unresolved `Self` and `self`.
1011    fn suggest_self_ty(
1012        &mut self,
1013        err: &mut Diag<'_>,
1014        source: PathSource<'_>,
1015        path: &[Segment],
1016        span: Span,
1017    ) -> bool {
1018        if !is_self_type(path, source.namespace()) {
1019            return false;
1020        }
1021        err.code(E0411);
1022        err.span_label(span, "`Self` is only available in impls, traits, and type definitions");
1023        if let Some(item_kind) = self.diag_metadata.current_item {
1024            if !item_kind.ident.span.is_dummy() {
1025                err.span_label(
1026                    item_kind.ident.span,
1027                    format!(
1028                        "`Self` not allowed in {} {}",
1029                        item_kind.kind.article(),
1030                        item_kind.kind.descr()
1031                    ),
1032                );
1033            }
1034        }
1035        true
1036    }
1037
1038    fn suggest_self_value(
1039        &mut self,
1040        err: &mut Diag<'_>,
1041        source: PathSource<'_>,
1042        path: &[Segment],
1043        span: Span,
1044    ) -> bool {
1045        if !is_self_value(path, source.namespace()) {
1046            return false;
1047        }
1048
1049        debug!("smart_resolve_path_fragment: E0424, source={:?}", source);
1050        err.code(E0424);
1051        err.span_label(
1052            span,
1053            match source {
1054                PathSource::Pat => {
1055                    "`self` value is a keyword and may not be bound to variables or shadowed"
1056                }
1057                _ => "`self` value is a keyword only available in methods with a `self` parameter",
1058            },
1059        );
1060        let is_assoc_fn = self.self_type_is_available();
1061        let self_from_macro = "a `self` parameter, but a macro invocation can only \
1062                               access identifiers it receives from parameters";
1063        if let Some((fn_kind, span)) = &self.diag_metadata.current_function {
1064            // The current function has a `self` parameter, but we were unable to resolve
1065            // a reference to `self`. This can only happen if the `self` identifier we
1066            // are resolving came from a different hygiene context.
1067            if fn_kind.decl().inputs.get(0).is_some_and(|p| p.is_self()) {
1068                err.span_label(*span, format!("this function has {self_from_macro}"));
1069            } else {
1070                let doesnt = if is_assoc_fn {
1071                    let (span, sugg) = fn_kind
1072                        .decl()
1073                        .inputs
1074                        .get(0)
1075                        .map(|p| (p.span.shrink_to_lo(), "&self, "))
1076                        .unwrap_or_else(|| {
1077                            // Try to look for the "(" after the function name, if possible.
1078                            // This avoids placing the suggestion into the visibility specifier.
1079                            let span = fn_kind
1080                                .ident()
1081                                .map_or(*span, |ident| span.with_lo(ident.span.hi()));
1082                            (
1083                                self.r
1084                                    .tcx
1085                                    .sess
1086                                    .source_map()
1087                                    .span_through_char(span, '(')
1088                                    .shrink_to_hi(),
1089                                "&self",
1090                            )
1091                        });
1092                    err.span_suggestion_verbose(
1093                        span,
1094                        "add a `self` receiver parameter to make the associated `fn` a method",
1095                        sugg,
1096                        Applicability::MaybeIncorrect,
1097                    );
1098                    "doesn't"
1099                } else {
1100                    "can't"
1101                };
1102                if let Some(ident) = fn_kind.ident() {
1103                    err.span_label(
1104                        ident.span,
1105                        format!("this function {doesnt} have a `self` parameter"),
1106                    );
1107                }
1108            }
1109        } else if let Some(item_kind) = self.diag_metadata.current_item {
1110            if matches!(item_kind.kind, ItemKind::Delegation(..)) {
1111                err.span_label(item_kind.span, format!("delegation supports {self_from_macro}"));
1112            } else {
1113                err.span_label(
1114                    item_kind.ident.span,
1115                    format!(
1116                        "`self` not allowed in {} {}",
1117                        item_kind.kind.article(),
1118                        item_kind.kind.descr()
1119                    ),
1120                );
1121            }
1122        }
1123        true
1124    }
1125
1126    fn detect_missing_binding_available_from_pattern(
1127        &mut self,
1128        err: &mut Diag<'_>,
1129        path: &[Segment],
1130        following_seg: Option<&Segment>,
1131    ) {
1132        let [segment] = path else { return };
1133        let None = following_seg else { return };
1134        for rib in self.ribs[ValueNS].iter().rev() {
1135            for (def_id, spans) in &rib.patterns_with_skipped_bindings {
1136                if let DefKind::Struct | DefKind::Variant = self.r.tcx.def_kind(*def_id)
1137                    && let Some(fields) = self.r.field_idents(*def_id)
1138                {
1139                    for field in fields {
1140                        if field.name == segment.ident.name {
1141                            if spans.iter().all(|(_, had_error)| had_error.is_err()) {
1142                                // This resolution error will likely be fixed by fixing a
1143                                // syntax error in a pattern, so it is irrelevant to the user.
1144                                let multispan: MultiSpan =
1145                                    spans.iter().map(|(s, _)| *s).collect::<Vec<_>>().into();
1146                                err.span_note(
1147                                    multispan,
1148                                    "this pattern had a recovered parse error which likely lost \
1149                                     the expected fields",
1150                                );
1151                                err.downgrade_to_delayed_bug();
1152                            }
1153                            let ty = self.r.tcx.item_name(*def_id);
1154                            for (span, _) in spans {
1155                                err.span_label(
1156                                    *span,
1157                                    format!(
1158                                        "this pattern doesn't include `{field}`, which is \
1159                                         available in `{ty}`",
1160                                    ),
1161                                );
1162                            }
1163                        }
1164                    }
1165                }
1166            }
1167        }
1168    }
1169
1170    fn suggest_at_operator_in_slice_pat_with_range(
1171        &mut self,
1172        err: &mut Diag<'_>,
1173        path: &[Segment],
1174    ) {
1175        let Some(pat) = self.diag_metadata.current_pat else { return };
1176        let (bound, side, range) = match &pat.kind {
1177            ast::PatKind::Range(Some(bound), None, range) => (bound, Side::Start, range),
1178            ast::PatKind::Range(None, Some(bound), range) => (bound, Side::End, range),
1179            _ => return,
1180        };
1181        if let ExprKind::Path(None, range_path) = &bound.kind
1182            && let [segment] = &range_path.segments[..]
1183            && let [s] = path
1184            && segment.ident == s.ident
1185            && segment.ident.span.eq_ctxt(range.span)
1186        {
1187            // We've encountered `[first, rest..]` (#88404) or `[first, ..rest]` (#120591)
1188            // where the user might have meant `[first, rest @ ..]`.
1189            let (span, snippet) = match side {
1190                Side::Start => (segment.ident.span.between(range.span), " @ ".into()),
1191                Side::End => (range.span.to(segment.ident.span), format!("{} @ ..", segment.ident)),
1192            };
1193            err.subdiagnostic(errors::UnexpectedResUseAtOpInSlicePatWithRangeSugg {
1194                span,
1195                ident: segment.ident,
1196                snippet,
1197            });
1198        }
1199
1200        enum Side {
1201            Start,
1202            End,
1203        }
1204    }
1205
1206    fn suggest_swapping_misplaced_self_ty_and_trait(
1207        &mut self,
1208        err: &mut Diag<'_>,
1209        source: PathSource<'_>,
1210        res: Option<Res>,
1211        span: Span,
1212    ) {
1213        if let Some((trait_ref, self_ty)) =
1214            self.diag_metadata.currently_processing_impl_trait.clone()
1215            && let TyKind::Path(_, self_ty_path) = &self_ty.kind
1216            && let PathResult::Module(ModuleOrUniformRoot::Module(module)) =
1217                self.resolve_path(&Segment::from_path(self_ty_path), Some(TypeNS), None)
1218            && let ModuleKind::Def(DefKind::Trait, ..) = module.kind
1219            && trait_ref.path.span == span
1220            && let PathSource::Trait(_) = source
1221            && let Some(Res::Def(DefKind::Struct | DefKind::Enum | DefKind::Union, _)) = res
1222            && let Ok(self_ty_str) = self.r.tcx.sess.source_map().span_to_snippet(self_ty.span)
1223            && let Ok(trait_ref_str) =
1224                self.r.tcx.sess.source_map().span_to_snippet(trait_ref.path.span)
1225        {
1226            err.multipart_suggestion(
1227                    "`impl` items mention the trait being implemented first and the type it is being implemented for second",
1228                    vec![(trait_ref.path.span, self_ty_str), (self_ty.span, trait_ref_str)],
1229                    Applicability::MaybeIncorrect,
1230                );
1231        }
1232    }
1233
1234    fn suggest_bare_struct_literal(&mut self, err: &mut Diag<'_>) {
1235        if let Some(span) = self.diag_metadata.current_block_could_be_bare_struct_literal {
1236            err.multipart_suggestion(
1237                "you might have meant to write a `struct` literal",
1238                vec![
1239                    (span.shrink_to_lo(), "{ SomeStruct ".to_string()),
1240                    (span.shrink_to_hi(), "}".to_string()),
1241                ],
1242                Applicability::HasPlaceholders,
1243            );
1244        }
1245    }
1246
1247    fn explain_functions_in_pattern(
1248        &mut self,
1249        err: &mut Diag<'_>,
1250        res: Option<Res>,
1251        source: PathSource<'_>,
1252    ) {
1253        let PathSource::TupleStruct(_, _) = source else { return };
1254        let Some(Res::Def(DefKind::Fn, _)) = res else { return };
1255        err.primary_message("expected a pattern, found a function call");
1256        err.note("function calls are not allowed in patterns: <https://doc.rust-lang.org/book/ch19-00-patterns.html>");
1257    }
1258
1259    fn suggest_changing_type_to_const_param(
1260        &mut self,
1261        err: &mut Diag<'_>,
1262        res: Option<Res>,
1263        source: PathSource<'_>,
1264        span: Span,
1265    ) {
1266        let PathSource::Trait(_) = source else { return };
1267
1268        // We don't include `DefKind::Str` and `DefKind::AssocTy` as they can't be reached here anyway.
1269        let applicability = match res {
1270            Some(Res::PrimTy(PrimTy::Int(_) | PrimTy::Uint(_) | PrimTy::Bool | PrimTy::Char)) => {
1271                Applicability::MachineApplicable
1272            }
1273            // FIXME(const_generics): Add `DefKind::TyParam` and `SelfTyParam` once we support generic
1274            // const generics. Of course, `Struct` and `Enum` may contain ty params, too, but the
1275            // benefits of including them here outweighs the small number of false positives.
1276            Some(Res::Def(DefKind::Struct | DefKind::Enum, _))
1277                if self.r.tcx.features().adt_const_params() =>
1278            {
1279                Applicability::MaybeIncorrect
1280            }
1281            _ => return,
1282        };
1283
1284        let Some(item) = self.diag_metadata.current_item else { return };
1285        let Some(generics) = item.kind.generics() else { return };
1286
1287        let param = generics.params.iter().find_map(|param| {
1288            // Only consider type params with exactly one trait bound.
1289            if let [bound] = &*param.bounds
1290                && let ast::GenericBound::Trait(tref) = bound
1291                && tref.modifiers == ast::TraitBoundModifiers::NONE
1292                && tref.span == span
1293                && param.ident.span.eq_ctxt(span)
1294            {
1295                Some(param.ident.span)
1296            } else {
1297                None
1298            }
1299        });
1300
1301        if let Some(param) = param {
1302            err.subdiagnostic(errors::UnexpectedResChangeTyToConstParamSugg {
1303                span: param.shrink_to_lo(),
1304                applicability,
1305            });
1306        }
1307    }
1308
1309    fn suggest_pattern_match_with_let(
1310        &mut self,
1311        err: &mut Diag<'_>,
1312        source: PathSource<'_>,
1313        span: Span,
1314    ) -> bool {
1315        if let PathSource::Expr(_) = source
1316            && let Some(Expr { span: expr_span, kind: ExprKind::Assign(lhs, _, _), .. }) =
1317                self.diag_metadata.in_if_condition
1318        {
1319            // Icky heuristic so we don't suggest:
1320            // `if (i + 2) = 2` => `if let (i + 2) = 2` (approximately pattern)
1321            // `if 2 = i` => `if let 2 = i` (lhs needs to contain error span)
1322            if lhs.is_approximately_pattern() && lhs.span.contains(span) {
1323                err.span_suggestion_verbose(
1324                    expr_span.shrink_to_lo(),
1325                    "you might have meant to use pattern matching",
1326                    "let ",
1327                    Applicability::MaybeIncorrect,
1328                );
1329                return true;
1330            }
1331        }
1332        false
1333    }
1334
1335    fn get_single_associated_item(
1336        &mut self,
1337        path: &[Segment],
1338        source: &PathSource<'_>,
1339        filter_fn: &impl Fn(Res) -> bool,
1340    ) -> Option<TypoSuggestion> {
1341        if let crate::PathSource::TraitItem(_) = source {
1342            let mod_path = &path[..path.len() - 1];
1343            if let PathResult::Module(ModuleOrUniformRoot::Module(module)) =
1344                self.resolve_path(mod_path, None, None)
1345            {
1346                let resolutions = self.r.resolutions(module).borrow();
1347                let targets: Vec<_> =
1348                    resolutions
1349                        .iter()
1350                        .filter_map(|(key, resolution)| {
1351                            resolution.borrow().binding.map(|binding| binding.res()).and_then(
1352                                |res| if filter_fn(res) { Some((key, res)) } else { None },
1353                            )
1354                        })
1355                        .collect();
1356                if let [target] = targets.as_slice() {
1357                    return Some(TypoSuggestion::single_item_from_ident(target.0.ident, target.1));
1358                }
1359            }
1360        }
1361        None
1362    }
1363
1364    /// Given `where <T as Bar>::Baz: String`, suggest `where T: Bar<Baz = String>`.
1365    fn restrict_assoc_type_in_where_clause(&mut self, span: Span, err: &mut Diag<'_>) -> bool {
1366        // Detect that we are actually in a `where` predicate.
1367        let (bounded_ty, bounds, where_span) = if let Some(ast::WherePredicate {
1368            kind:
1369                ast::WherePredicateKind::BoundPredicate(ast::WhereBoundPredicate {
1370                    bounded_ty,
1371                    bound_generic_params,
1372                    bounds,
1373                }),
1374            span,
1375            ..
1376        }) = self.diag_metadata.current_where_predicate
1377        {
1378            if !bound_generic_params.is_empty() {
1379                return false;
1380            }
1381            (bounded_ty, bounds, span)
1382        } else {
1383            return false;
1384        };
1385
1386        // Confirm that the target is an associated type.
1387        let (ty, _, path) = if let ast::TyKind::Path(Some(qself), path) = &bounded_ty.kind {
1388            // use this to verify that ident is a type param.
1389            let Some(partial_res) = self.r.partial_res_map.get(&bounded_ty.id) else {
1390                return false;
1391            };
1392            if !matches!(
1393                partial_res.full_res(),
1394                Some(hir::def::Res::Def(hir::def::DefKind::AssocTy, _))
1395            ) {
1396                return false;
1397            }
1398            (&qself.ty, qself.position, path)
1399        } else {
1400            return false;
1401        };
1402
1403        let peeled_ty = ty.peel_refs();
1404        if let ast::TyKind::Path(None, type_param_path) = &peeled_ty.kind {
1405            // Confirm that the `SelfTy` is a type parameter.
1406            let Some(partial_res) = self.r.partial_res_map.get(&peeled_ty.id) else {
1407                return false;
1408            };
1409            if !matches!(
1410                partial_res.full_res(),
1411                Some(hir::def::Res::Def(hir::def::DefKind::TyParam, _))
1412            ) {
1413                return false;
1414            }
1415            if let (
1416                [ast::PathSegment { args: None, .. }],
1417                [ast::GenericBound::Trait(poly_trait_ref)],
1418            ) = (&type_param_path.segments[..], &bounds[..])
1419                && poly_trait_ref.modifiers == ast::TraitBoundModifiers::NONE
1420            {
1421                if let [ast::PathSegment { ident, args: None, .. }] =
1422                    &poly_trait_ref.trait_ref.path.segments[..]
1423                {
1424                    if ident.span == span {
1425                        let Some(new_where_bound_predicate) =
1426                            mk_where_bound_predicate(path, poly_trait_ref, ty)
1427                        else {
1428                            return false;
1429                        };
1430                        err.span_suggestion_verbose(
1431                            *where_span,
1432                            format!("constrain the associated type to `{ident}`"),
1433                            where_bound_predicate_to_string(&new_where_bound_predicate),
1434                            Applicability::MaybeIncorrect,
1435                        );
1436                    }
1437                    return true;
1438                }
1439            }
1440        }
1441        false
1442    }
1443
1444    /// Check if the source is call expression and the first argument is `self`. If true,
1445    /// return the span of whole call and the span for all arguments expect the first one (`self`).
1446    fn call_has_self_arg(&self, source: PathSource<'_>) -> Option<(Span, Option<Span>)> {
1447        let mut has_self_arg = None;
1448        if let PathSource::Expr(Some(parent)) = source
1449            && let ExprKind::Call(_, args) = &parent.kind
1450            && !args.is_empty()
1451        {
1452            let mut expr_kind = &args[0].kind;
1453            loop {
1454                match expr_kind {
1455                    ExprKind::Path(_, arg_name) if arg_name.segments.len() == 1 => {
1456                        if arg_name.segments[0].ident.name == kw::SelfLower {
1457                            let call_span = parent.span;
1458                            let tail_args_span = if args.len() > 1 {
1459                                Some(Span::new(
1460                                    args[1].span.lo(),
1461                                    args.last().unwrap().span.hi(),
1462                                    call_span.ctxt(),
1463                                    None,
1464                                ))
1465                            } else {
1466                                None
1467                            };
1468                            has_self_arg = Some((call_span, tail_args_span));
1469                        }
1470                        break;
1471                    }
1472                    ExprKind::AddrOf(_, _, expr) => expr_kind = &expr.kind,
1473                    _ => break,
1474                }
1475            }
1476        }
1477        has_self_arg
1478    }
1479
1480    fn followed_by_brace(&self, span: Span) -> (bool, Option<Span>) {
1481        // HACK(estebank): find a better way to figure out that this was a
1482        // parser issue where a struct literal is being used on an expression
1483        // where a brace being opened means a block is being started. Look
1484        // ahead for the next text to see if `span` is followed by a `{`.
1485        let sm = self.r.tcx.sess.source_map();
1486        if let Some(followed_brace_span) = sm.span_look_ahead(span, "{", Some(50)) {
1487            // In case this could be a struct literal that needs to be surrounded
1488            // by parentheses, find the appropriate span.
1489            let close_brace_span = sm.span_look_ahead(followed_brace_span, "}", Some(50));
1490            let closing_brace = close_brace_span.map(|sp| span.to(sp));
1491            (true, closing_brace)
1492        } else {
1493            (false, None)
1494        }
1495    }
1496
1497    /// Provides context-dependent help for errors reported by the `smart_resolve_path_fragment`
1498    /// function.
1499    /// Returns `true` if able to provide context-dependent help.
1500    fn smart_resolve_context_dependent_help(
1501        &mut self,
1502        err: &mut Diag<'_>,
1503        span: Span,
1504        source: PathSource<'_>,
1505        path: &[Segment],
1506        res: Res,
1507        path_str: &str,
1508        fallback_label: &str,
1509    ) -> bool {
1510        let ns = source.namespace();
1511        let is_expected = &|res| source.is_expected(res);
1512
1513        let path_sep = |this: &mut Self, err: &mut Diag<'_>, expr: &Expr, kind: DefKind| {
1514            const MESSAGE: &str = "use the path separator to refer to an item";
1515
1516            let (lhs_span, rhs_span) = match &expr.kind {
1517                ExprKind::Field(base, ident) => (base.span, ident.span),
1518                ExprKind::MethodCall(box MethodCall { receiver, span, .. }) => {
1519                    (receiver.span, *span)
1520                }
1521                _ => return false,
1522            };
1523
1524            if lhs_span.eq_ctxt(rhs_span) {
1525                err.span_suggestion_verbose(
1526                    lhs_span.between(rhs_span),
1527                    MESSAGE,
1528                    "::",
1529                    Applicability::MaybeIncorrect,
1530                );
1531                true
1532            } else if kind == DefKind::Struct
1533                && let Some(lhs_source_span) = lhs_span.find_ancestor_inside(expr.span)
1534                && let Ok(snippet) = this.r.tcx.sess.source_map().span_to_snippet(lhs_source_span)
1535            {
1536                // The LHS is a type that originates from a macro call.
1537                // We have to add angle brackets around it.
1538
1539                err.span_suggestion_verbose(
1540                    lhs_source_span.until(rhs_span),
1541                    MESSAGE,
1542                    format!("<{snippet}>::"),
1543                    Applicability::MaybeIncorrect,
1544                );
1545                true
1546            } else {
1547                // Either we were unable to obtain the source span / the snippet or
1548                // the LHS originates from a macro call and it is not a type and thus
1549                // there is no way to replace `.` with `::` and still somehow suggest
1550                // valid Rust code.
1551
1552                false
1553            }
1554        };
1555
1556        let find_span = |source: &PathSource<'_>, err: &mut Diag<'_>| {
1557            match source {
1558                PathSource::Expr(Some(Expr { span, kind: ExprKind::Call(_, _), .. }))
1559                | PathSource::TupleStruct(span, _) => {
1560                    // We want the main underline to cover the suggested code as well for
1561                    // cleaner output.
1562                    err.span(*span);
1563                    *span
1564                }
1565                _ => span,
1566            }
1567        };
1568
1569        let mut bad_struct_syntax_suggestion = |this: &mut Self, def_id: DefId| {
1570            let (followed_by_brace, closing_brace) = this.followed_by_brace(span);
1571
1572            match source {
1573                PathSource::Expr(Some(
1574                    parent @ Expr { kind: ExprKind::Field(..) | ExprKind::MethodCall(..), .. },
1575                )) if path_sep(this, err, parent, DefKind::Struct) => {}
1576                PathSource::Expr(
1577                    None
1578                    | Some(Expr {
1579                        kind:
1580                            ExprKind::Path(..)
1581                            | ExprKind::Binary(..)
1582                            | ExprKind::Unary(..)
1583                            | ExprKind::If(..)
1584                            | ExprKind::While(..)
1585                            | ExprKind::ForLoop { .. }
1586                            | ExprKind::Match(..),
1587                        ..
1588                    }),
1589                ) if followed_by_brace => {
1590                    if let Some(sp) = closing_brace {
1591                        err.span_label(span, fallback_label.to_string());
1592                        err.multipart_suggestion(
1593                            "surround the struct literal with parentheses",
1594                            vec![
1595                                (sp.shrink_to_lo(), "(".to_string()),
1596                                (sp.shrink_to_hi(), ")".to_string()),
1597                            ],
1598                            Applicability::MaybeIncorrect,
1599                        );
1600                    } else {
1601                        err.span_label(
1602                            span, // Note the parentheses surrounding the suggestion below
1603                            format!(
1604                                "you might want to surround a struct literal with parentheses: \
1605                                 `({path_str} {{ /* fields */ }})`?"
1606                            ),
1607                        );
1608                    }
1609                }
1610                PathSource::Expr(_) | PathSource::TupleStruct(..) | PathSource::Pat => {
1611                    let span = find_span(&source, err);
1612                    err.span_label(this.r.def_span(def_id), format!("`{path_str}` defined here"));
1613
1614                    let (tail, descr, applicability, old_fields) = match source {
1615                        PathSource::Pat => ("", "pattern", Applicability::MachineApplicable, None),
1616                        PathSource::TupleStruct(_, args) => (
1617                            "",
1618                            "pattern",
1619                            Applicability::MachineApplicable,
1620                            Some(
1621                                args.iter()
1622                                    .map(|a| this.r.tcx.sess.source_map().span_to_snippet(*a).ok())
1623                                    .collect::<Vec<Option<String>>>(),
1624                            ),
1625                        ),
1626                        _ => (": val", "literal", Applicability::HasPlaceholders, None),
1627                    };
1628
1629                    if !this.has_private_fields(def_id) {
1630                        // If the fields of the type are private, we shouldn't be suggesting using
1631                        // the struct literal syntax at all, as that will cause a subsequent error.
1632                        let fields = this.r.field_idents(def_id);
1633                        let has_fields = fields.as_ref().is_some_and(|f| !f.is_empty());
1634                        let (fields, applicability) = match fields {
1635                            Some(fields) => {
1636                                let fields = if let Some(old_fields) = old_fields {
1637                                    fields
1638                                        .iter()
1639                                        .enumerate()
1640                                        .map(|(idx, new)| (new, old_fields.get(idx)))
1641                                        .map(|(new, old)| {
1642                                            if let Some(Some(old)) = old
1643                                                && new.as_str() != old
1644                                            {
1645                                                format!("{new}: {old}")
1646                                            } else {
1647                                                new.to_string()
1648                                            }
1649                                        })
1650                                        .collect::<Vec<String>>()
1651                                } else {
1652                                    fields
1653                                        .iter()
1654                                        .map(|f| format!("{f}{tail}"))
1655                                        .collect::<Vec<String>>()
1656                                };
1657
1658                                (fields.join(", "), applicability)
1659                            }
1660                            None => ("/* fields */".to_string(), Applicability::HasPlaceholders),
1661                        };
1662                        let pad = if has_fields { " " } else { "" };
1663                        err.span_suggestion(
1664                            span,
1665                            format!("use struct {descr} syntax instead"),
1666                            format!("{path_str} {{{pad}{fields}{pad}}}"),
1667                            applicability,
1668                        );
1669                    }
1670                    if let PathSource::Expr(Some(Expr {
1671                        kind: ExprKind::Call(path, ref args),
1672                        span: call_span,
1673                        ..
1674                    })) = source
1675                    {
1676                        this.suggest_alternative_construction_methods(
1677                            def_id,
1678                            err,
1679                            path.span,
1680                            *call_span,
1681                            &args[..],
1682                        );
1683                    }
1684                }
1685                _ => {
1686                    err.span_label(span, fallback_label.to_string());
1687                }
1688            }
1689        };
1690
1691        match (res, source) {
1692            (
1693                Res::Def(DefKind::Macro(MacroKind::Bang), def_id),
1694                PathSource::Expr(Some(Expr {
1695                    kind: ExprKind::Index(..) | ExprKind::Call(..), ..
1696                }))
1697                | PathSource::Struct,
1698            ) => {
1699                // Don't suggest macro if it's unstable.
1700                let suggestable = def_id.is_local()
1701                    || self.r.tcx.lookup_stability(def_id).is_none_or(|s| s.is_stable());
1702
1703                err.span_label(span, fallback_label.to_string());
1704
1705                // Don't suggest `!` for a macro invocation if there are generic args
1706                if path
1707                    .last()
1708                    .is_some_and(|segment| !segment.has_generic_args && !segment.has_lifetime_args)
1709                    && suggestable
1710                {
1711                    err.span_suggestion_verbose(
1712                        span.shrink_to_hi(),
1713                        "use `!` to invoke the macro",
1714                        "!",
1715                        Applicability::MaybeIncorrect,
1716                    );
1717                }
1718
1719                if path_str == "try" && span.is_rust_2015() {
1720                    err.note("if you want the `try` keyword, you need Rust 2018 or later");
1721                }
1722            }
1723            (Res::Def(DefKind::Macro(MacroKind::Bang), _), _) => {
1724                err.span_label(span, fallback_label.to_string());
1725            }
1726            (Res::Def(DefKind::TyAlias, def_id), PathSource::Trait(_)) => {
1727                err.span_label(span, "type aliases cannot be used as traits");
1728                if self.r.tcx.sess.is_nightly_build() {
1729                    let msg = "you might have meant to use `#![feature(trait_alias)]` instead of a \
1730                               `type` alias";
1731                    let span = self.r.def_span(def_id);
1732                    if let Ok(snip) = self.r.tcx.sess.source_map().span_to_snippet(span) {
1733                        // The span contains a type alias so we should be able to
1734                        // replace `type` with `trait`.
1735                        let snip = snip.replacen("type", "trait", 1);
1736                        err.span_suggestion(span, msg, snip, Applicability::MaybeIncorrect);
1737                    } else {
1738                        err.span_help(span, msg);
1739                    }
1740                }
1741            }
1742            (
1743                Res::Def(kind @ (DefKind::Mod | DefKind::Trait), _),
1744                PathSource::Expr(Some(parent)),
1745            ) => {
1746                if !path_sep(self, err, parent, kind) {
1747                    return false;
1748                }
1749            }
1750            (
1751                Res::Def(DefKind::Enum, def_id),
1752                PathSource::TupleStruct(..) | PathSource::Expr(..),
1753            ) => {
1754                self.suggest_using_enum_variant(err, source, def_id, span);
1755            }
1756            (Res::Def(DefKind::Struct, def_id), source) if ns == ValueNS => {
1757                let struct_ctor = match def_id.as_local() {
1758                    Some(def_id) => self.r.struct_constructors.get(&def_id).cloned(),
1759                    None => {
1760                        let ctor = self.r.cstore().ctor_untracked(def_id);
1761                        ctor.map(|(ctor_kind, ctor_def_id)| {
1762                            let ctor_res =
1763                                Res::Def(DefKind::Ctor(CtorOf::Struct, ctor_kind), ctor_def_id);
1764                            let ctor_vis = self.r.tcx.visibility(ctor_def_id);
1765                            let field_visibilities = self
1766                                .r
1767                                .tcx
1768                                .associated_item_def_ids(def_id)
1769                                .iter()
1770                                .map(|field_id| self.r.tcx.visibility(field_id))
1771                                .collect();
1772                            (ctor_res, ctor_vis, field_visibilities)
1773                        })
1774                    }
1775                };
1776
1777                let (ctor_def, ctor_vis, fields) = if let Some(struct_ctor) = struct_ctor {
1778                    if let PathSource::Expr(Some(parent)) = source {
1779                        if let ExprKind::Field(..) | ExprKind::MethodCall(..) = parent.kind {
1780                            bad_struct_syntax_suggestion(self, def_id);
1781                            return true;
1782                        }
1783                    }
1784                    struct_ctor
1785                } else {
1786                    bad_struct_syntax_suggestion(self, def_id);
1787                    return true;
1788                };
1789
1790                let is_accessible = self.r.is_accessible_from(ctor_vis, self.parent_scope.module);
1791                if !is_expected(ctor_def) || is_accessible {
1792                    return true;
1793                }
1794
1795                let field_spans = match source {
1796                    // e.g. `if let Enum::TupleVariant(field1, field2) = _`
1797                    PathSource::TupleStruct(_, pattern_spans) => {
1798                        err.primary_message(
1799                            "cannot match against a tuple struct which contains private fields",
1800                        );
1801
1802                        // Use spans of the tuple struct pattern.
1803                        Some(Vec::from(pattern_spans))
1804                    }
1805                    // e.g. `let _ = Enum::TupleVariant(field1, field2);`
1806                    PathSource::Expr(Some(Expr {
1807                        kind: ExprKind::Call(path, ref args),
1808                        span: call_span,
1809                        ..
1810                    })) => {
1811                        err.primary_message(
1812                            "cannot initialize a tuple struct which contains private fields",
1813                        );
1814                        self.suggest_alternative_construction_methods(
1815                            def_id,
1816                            err,
1817                            path.span,
1818                            *call_span,
1819                            &args[..],
1820                        );
1821                        // Use spans of the tuple struct definition.
1822                        self.r
1823                            .field_idents(def_id)
1824                            .map(|fields| fields.iter().map(|f| f.span).collect::<Vec<_>>())
1825                    }
1826                    _ => None,
1827                };
1828
1829                if let Some(spans) =
1830                    field_spans.filter(|spans| spans.len() > 0 && fields.len() == spans.len())
1831                {
1832                    let non_visible_spans: Vec<Span> = iter::zip(&fields, &spans)
1833                        .filter(|(vis, _)| {
1834                            !self.r.is_accessible_from(**vis, self.parent_scope.module)
1835                        })
1836                        .map(|(_, span)| *span)
1837                        .collect();
1838
1839                    if non_visible_spans.len() > 0 {
1840                        if let Some(fields) = self.r.field_visibility_spans.get(&def_id) {
1841                            err.multipart_suggestion_verbose(
1842                                format!(
1843                                    "consider making the field{} publicly accessible",
1844                                    pluralize!(fields.len())
1845                                ),
1846                                fields.iter().map(|span| (*span, "pub ".to_string())).collect(),
1847                                Applicability::MaybeIncorrect,
1848                            );
1849                        }
1850
1851                        let mut m: MultiSpan = non_visible_spans.clone().into();
1852                        non_visible_spans
1853                            .into_iter()
1854                            .for_each(|s| m.push_span_label(s, "private field"));
1855                        err.span_note(m, "constructor is not visible here due to private fields");
1856                    }
1857
1858                    return true;
1859                }
1860
1861                err.span_label(span, "constructor is not visible here due to private fields");
1862            }
1863            (Res::Def(DefKind::Union | DefKind::Variant, def_id), _) if ns == ValueNS => {
1864                bad_struct_syntax_suggestion(self, def_id);
1865            }
1866            (Res::Def(DefKind::Ctor(_, CtorKind::Const), def_id), _) if ns == ValueNS => {
1867                match source {
1868                    PathSource::Expr(_) | PathSource::TupleStruct(..) | PathSource::Pat => {
1869                        let span = find_span(&source, err);
1870                        err.span_label(
1871                            self.r.def_span(def_id),
1872                            format!("`{path_str}` defined here"),
1873                        );
1874                        err.span_suggestion(
1875                            span,
1876                            "use this syntax instead",
1877                            path_str,
1878                            Applicability::MaybeIncorrect,
1879                        );
1880                    }
1881                    _ => return false,
1882                }
1883            }
1884            (Res::Def(DefKind::Ctor(_, CtorKind::Fn), ctor_def_id), _) if ns == ValueNS => {
1885                let def_id = self.r.tcx.parent(ctor_def_id);
1886                err.span_label(self.r.def_span(def_id), format!("`{path_str}` defined here"));
1887                let fields = self.r.field_idents(def_id).map_or_else(
1888                    || "/* fields */".to_string(),
1889                    |field_ids| vec!["_"; field_ids.len()].join(", "),
1890                );
1891                err.span_suggestion(
1892                    span,
1893                    "use the tuple variant pattern syntax instead",
1894                    format!("{path_str}({fields})"),
1895                    Applicability::HasPlaceholders,
1896                );
1897            }
1898            (Res::SelfTyParam { .. } | Res::SelfTyAlias { .. }, _) if ns == ValueNS => {
1899                err.span_label(span, fallback_label.to_string());
1900                err.note("can't use `Self` as a constructor, you must use the implemented struct");
1901            }
1902            (Res::Def(DefKind::TyAlias | DefKind::AssocTy, _), _) if ns == ValueNS => {
1903                err.note("can't use a type alias as a constructor");
1904            }
1905            _ => return false,
1906        }
1907        true
1908    }
1909
1910    fn suggest_alternative_construction_methods(
1911        &mut self,
1912        def_id: DefId,
1913        err: &mut Diag<'_>,
1914        path_span: Span,
1915        call_span: Span,
1916        args: &[P<Expr>],
1917    ) {
1918        if def_id.is_local() {
1919            // Doing analysis on local `DefId`s would cause infinite recursion.
1920            return;
1921        }
1922        // Look at all the associated functions without receivers in the type's
1923        // inherent impls to look for builders that return `Self`
1924        let mut items = self
1925            .r
1926            .tcx
1927            .inherent_impls(def_id)
1928            .iter()
1929            .flat_map(|i| self.r.tcx.associated_items(i).in_definition_order())
1930            // Only assoc fn with no receivers.
1931            .filter(|item| matches!(item.kind, ty::AssocKind::Fn) && !item.fn_has_self_parameter)
1932            .filter_map(|item| {
1933                // Only assoc fns that return `Self`
1934                let fn_sig = self.r.tcx.fn_sig(item.def_id).skip_binder();
1935                // Don't normalize the return type, because that can cause cycle errors.
1936                let ret_ty = fn_sig.output().skip_binder();
1937                let ty::Adt(def, _args) = ret_ty.kind() else {
1938                    return None;
1939                };
1940                let input_len = fn_sig.inputs().skip_binder().len();
1941                if def.did() != def_id {
1942                    return None;
1943                }
1944                let order = !item.name.as_str().starts_with("new");
1945                Some((order, item.name, input_len))
1946            })
1947            .collect::<Vec<_>>();
1948        items.sort_by_key(|(order, _, _)| *order);
1949        let suggestion = |name, args| {
1950            format!(
1951                "::{name}({})",
1952                std::iter::repeat("_").take(args).collect::<Vec<_>>().join(", ")
1953            )
1954        };
1955        match &items[..] {
1956            [] => {}
1957            [(_, name, len)] if *len == args.len() => {
1958                err.span_suggestion_verbose(
1959                    path_span.shrink_to_hi(),
1960                    format!("you might have meant to use the `{name}` associated function",),
1961                    format!("::{name}"),
1962                    Applicability::MaybeIncorrect,
1963                );
1964            }
1965            [(_, name, len)] => {
1966                err.span_suggestion_verbose(
1967                    path_span.shrink_to_hi().with_hi(call_span.hi()),
1968                    format!("you might have meant to use the `{name}` associated function",),
1969                    suggestion(name, *len),
1970                    Applicability::MaybeIncorrect,
1971                );
1972            }
1973            _ => {
1974                err.span_suggestions_with_style(
1975                    path_span.shrink_to_hi().with_hi(call_span.hi()),
1976                    "you might have meant to use an associated function to build this type",
1977                    items.iter().map(|(_, name, len)| suggestion(name, *len)),
1978                    Applicability::MaybeIncorrect,
1979                    SuggestionStyle::ShowAlways,
1980                );
1981            }
1982        }
1983        // We'd ideally use `type_implements_trait` but don't have access to
1984        // the trait solver here. We can't use `get_diagnostic_item` or
1985        // `all_traits` in resolve either. So instead we abuse the import
1986        // suggestion machinery to get `std::default::Default` and perform some
1987        // checks to confirm that we got *only* that trait. We then see if the
1988        // Adt we have has a direct implementation of `Default`. If so, we
1989        // provide a structured suggestion.
1990        let default_trait = self
1991            .r
1992            .lookup_import_candidates(
1993                Ident::with_dummy_span(sym::Default),
1994                Namespace::TypeNS,
1995                &self.parent_scope,
1996                &|res: Res| matches!(res, Res::Def(DefKind::Trait, _)),
1997            )
1998            .iter()
1999            .filter_map(|candidate| candidate.did)
2000            .find(|did| {
2001                self.r
2002                    .tcx
2003                    .get_attrs(*did, sym::rustc_diagnostic_item)
2004                    .any(|attr| attr.value_str() == Some(sym::Default))
2005            });
2006        let Some(default_trait) = default_trait else {
2007            return;
2008        };
2009        if self
2010            .r
2011            .extern_crate_map
2012            .iter()
2013            // FIXME: This doesn't include impls like `impl Default for String`.
2014            .flat_map(|(_, crate_)| self.r.tcx.implementations_of_trait((*crate_, default_trait)))
2015            .filter_map(|(_, simplified_self_ty)| *simplified_self_ty)
2016            .filter_map(|simplified_self_ty| match simplified_self_ty {
2017                SimplifiedType::Adt(did) => Some(did),
2018                _ => None,
2019            })
2020            .any(|did| did == def_id)
2021        {
2022            err.multipart_suggestion(
2023                "consider using the `Default` trait",
2024                vec![
2025                    (path_span.shrink_to_lo(), "<".to_string()),
2026                    (
2027                        path_span.shrink_to_hi().with_hi(call_span.hi()),
2028                        " as std::default::Default>::default()".to_string(),
2029                    ),
2030                ],
2031                Applicability::MaybeIncorrect,
2032            );
2033        }
2034    }
2035
2036    fn has_private_fields(&self, def_id: DefId) -> bool {
2037        let fields = match def_id.as_local() {
2038            Some(def_id) => self.r.struct_constructors.get(&def_id).cloned().map(|(_, _, f)| f),
2039            None => Some(
2040                self.r
2041                    .tcx
2042                    .associated_item_def_ids(def_id)
2043                    .iter()
2044                    .map(|field_id| self.r.tcx.visibility(field_id))
2045                    .collect(),
2046            ),
2047        };
2048
2049        fields.is_some_and(|fields| {
2050            fields.iter().any(|vis| !self.r.is_accessible_from(*vis, self.parent_scope.module))
2051        })
2052    }
2053
2054    /// Given the target `ident` and `kind`, search for the similarly named associated item
2055    /// in `self.current_trait_ref`.
2056    pub(crate) fn find_similarly_named_assoc_item(
2057        &mut self,
2058        ident: Symbol,
2059        kind: &AssocItemKind,
2060    ) -> Option<Symbol> {
2061        let (module, _) = self.current_trait_ref.as_ref()?;
2062        if ident == kw::Underscore {
2063            // We do nothing for `_`.
2064            return None;
2065        }
2066
2067        let resolutions = self.r.resolutions(*module);
2068        let targets = resolutions
2069            .borrow()
2070            .iter()
2071            .filter_map(|(key, res)| res.borrow().binding.map(|binding| (key, binding.res())))
2072            .filter(|(_, res)| match (kind, res) {
2073                (AssocItemKind::Const(..), Res::Def(DefKind::AssocConst, _)) => true,
2074                (AssocItemKind::Fn(_), Res::Def(DefKind::AssocFn, _)) => true,
2075                (AssocItemKind::Type(..), Res::Def(DefKind::AssocTy, _)) => true,
2076                (AssocItemKind::Delegation(_), Res::Def(DefKind::AssocFn, _)) => true,
2077                _ => false,
2078            })
2079            .map(|(key, _)| key.ident.name)
2080            .collect::<Vec<_>>();
2081
2082        find_best_match_for_name(&targets, ident, None)
2083    }
2084
2085    fn lookup_assoc_candidate<FilterFn>(
2086        &mut self,
2087        ident: Ident,
2088        ns: Namespace,
2089        filter_fn: FilterFn,
2090        called: bool,
2091    ) -> Option<AssocSuggestion>
2092    where
2093        FilterFn: Fn(Res) -> bool,
2094    {
2095        fn extract_node_id(t: &Ty) -> Option<NodeId> {
2096            match t.kind {
2097                TyKind::Path(None, _) => Some(t.id),
2098                TyKind::Ref(_, ref mut_ty) => extract_node_id(&mut_ty.ty),
2099                // This doesn't handle the remaining `Ty` variants as they are not
2100                // that commonly the self_type, it might be interesting to provide
2101                // support for those in future.
2102                _ => None,
2103            }
2104        }
2105        // Fields are generally expected in the same contexts as locals.
2106        if filter_fn(Res::Local(ast::DUMMY_NODE_ID)) {
2107            if let Some(node_id) =
2108                self.diag_metadata.current_self_type.as_ref().and_then(extract_node_id)
2109            {
2110                // Look for a field with the same name in the current self_type.
2111                if let Some(resolution) = self.r.partial_res_map.get(&node_id) {
2112                    if let Some(Res::Def(DefKind::Struct | DefKind::Union, did)) =
2113                        resolution.full_res()
2114                    {
2115                        if let Some(fields) = self.r.field_idents(did) {
2116                            if let Some(field) = fields.iter().find(|id| ident.name == id.name) {
2117                                return Some(AssocSuggestion::Field(field.span));
2118                            }
2119                        }
2120                    }
2121                }
2122            }
2123        }
2124
2125        if let Some(items) = self.diag_metadata.current_trait_assoc_items {
2126            for assoc_item in items {
2127                if assoc_item.ident == ident {
2128                    return Some(match &assoc_item.kind {
2129                        ast::AssocItemKind::Const(..) => AssocSuggestion::AssocConst,
2130                        ast::AssocItemKind::Fn(box ast::Fn { sig, .. }) if sig.decl.has_self() => {
2131                            AssocSuggestion::MethodWithSelf { called }
2132                        }
2133                        ast::AssocItemKind::Fn(..) => AssocSuggestion::AssocFn { called },
2134                        ast::AssocItemKind::Type(..) => AssocSuggestion::AssocType,
2135                        ast::AssocItemKind::Delegation(..)
2136                            if self
2137                                .r
2138                                .delegation_fn_sigs
2139                                .get(&self.r.local_def_id(assoc_item.id))
2140                                .is_some_and(|sig| sig.has_self) =>
2141                        {
2142                            AssocSuggestion::MethodWithSelf { called }
2143                        }
2144                        ast::AssocItemKind::Delegation(..) => AssocSuggestion::AssocFn { called },
2145                        ast::AssocItemKind::MacCall(_) | ast::AssocItemKind::DelegationMac(..) => {
2146                            continue;
2147                        }
2148                    });
2149                }
2150            }
2151        }
2152
2153        // Look for associated items in the current trait.
2154        if let Some((module, _)) = self.current_trait_ref {
2155            if let Ok(binding) = self.r.maybe_resolve_ident_in_module(
2156                ModuleOrUniformRoot::Module(module),
2157                ident,
2158                ns,
2159                &self.parent_scope,
2160                None,
2161            ) {
2162                let res = binding.res();
2163                if filter_fn(res) {
2164                    match res {
2165                        Res::Def(DefKind::Fn | DefKind::AssocFn, def_id) => {
2166                            let has_self = match def_id.as_local() {
2167                                Some(def_id) => self
2168                                    .r
2169                                    .delegation_fn_sigs
2170                                    .get(&def_id)
2171                                    .is_some_and(|sig| sig.has_self),
2172                                None => self
2173                                    .r
2174                                    .tcx
2175                                    .fn_arg_names(def_id)
2176                                    .first()
2177                                    .is_some_and(|ident| ident.name == kw::SelfLower),
2178                            };
2179                            if has_self {
2180                                return Some(AssocSuggestion::MethodWithSelf { called });
2181                            } else {
2182                                return Some(AssocSuggestion::AssocFn { called });
2183                            }
2184                        }
2185                        Res::Def(DefKind::AssocConst, _) => {
2186                            return Some(AssocSuggestion::AssocConst);
2187                        }
2188                        Res::Def(DefKind::AssocTy, _) => {
2189                            return Some(AssocSuggestion::AssocType);
2190                        }
2191                        _ => {}
2192                    }
2193                }
2194            }
2195        }
2196
2197        None
2198    }
2199
2200    fn lookup_typo_candidate(
2201        &mut self,
2202        path: &[Segment],
2203        following_seg: Option<&Segment>,
2204        ns: Namespace,
2205        filter_fn: &impl Fn(Res) -> bool,
2206    ) -> TypoCandidate {
2207        let mut names = Vec::new();
2208        if let [segment] = path {
2209            let mut ctxt = segment.ident.span.ctxt();
2210
2211            // Search in lexical scope.
2212            // Walk backwards up the ribs in scope and collect candidates.
2213            for rib in self.ribs[ns].iter().rev() {
2214                let rib_ctxt = if rib.kind.contains_params() {
2215                    ctxt.normalize_to_macros_2_0()
2216                } else {
2217                    ctxt.normalize_to_macro_rules()
2218                };
2219
2220                // Locals and type parameters
2221                for (ident, &res) in &rib.bindings {
2222                    if filter_fn(res) && ident.span.ctxt() == rib_ctxt {
2223                        names.push(TypoSuggestion::typo_from_ident(*ident, res));
2224                    }
2225                }
2226
2227                if let RibKind::MacroDefinition(def) = rib.kind
2228                    && def == self.r.macro_def(ctxt)
2229                {
2230                    // If an invocation of this macro created `ident`, give up on `ident`
2231                    // and switch to `ident`'s source from the macro definition.
2232                    ctxt.remove_mark();
2233                    continue;
2234                }
2235
2236                // Items in scope
2237                if let RibKind::Module(module) = rib.kind {
2238                    // Items from this module
2239                    self.r.add_module_candidates(module, &mut names, &filter_fn, Some(ctxt));
2240
2241                    if let ModuleKind::Block = module.kind {
2242                        // We can see through blocks
2243                    } else {
2244                        // Items from the prelude
2245                        if !module.no_implicit_prelude {
2246                            let extern_prelude = self.r.extern_prelude.clone();
2247                            names.extend(extern_prelude.iter().flat_map(|(ident, _)| {
2248                                self.r
2249                                    .crate_loader(|c| c.maybe_process_path_extern(ident.name))
2250                                    .and_then(|crate_id| {
2251                                        let crate_mod =
2252                                            Res::Def(DefKind::Mod, crate_id.as_def_id());
2253
2254                                        filter_fn(crate_mod).then(|| {
2255                                            TypoSuggestion::typo_from_ident(*ident, crate_mod)
2256                                        })
2257                                    })
2258                            }));
2259
2260                            if let Some(prelude) = self.r.prelude {
2261                                self.r.add_module_candidates(prelude, &mut names, &filter_fn, None);
2262                            }
2263                        }
2264                        break;
2265                    }
2266                }
2267            }
2268            // Add primitive types to the mix
2269            if filter_fn(Res::PrimTy(PrimTy::Bool)) {
2270                names.extend(PrimTy::ALL.iter().map(|prim_ty| {
2271                    TypoSuggestion::typo_from_name(prim_ty.name(), Res::PrimTy(*prim_ty))
2272                }))
2273            }
2274        } else {
2275            // Search in module.
2276            let mod_path = &path[..path.len() - 1];
2277            if let PathResult::Module(ModuleOrUniformRoot::Module(module)) =
2278                self.resolve_path(mod_path, Some(TypeNS), None)
2279            {
2280                self.r.add_module_candidates(module, &mut names, &filter_fn, None);
2281            }
2282        }
2283
2284        // if next_seg is present, let's filter everything that does not continue the path
2285        if let Some(following_seg) = following_seg {
2286            names.retain(|suggestion| match suggestion.res {
2287                Res::Def(DefKind::Struct | DefKind::Enum | DefKind::Union, _) => {
2288                    // FIXME: this is not totally accurate, but mostly works
2289                    suggestion.candidate != following_seg.ident.name
2290                }
2291                Res::Def(DefKind::Mod, def_id) => self.r.get_module(def_id).map_or_else(
2292                    || false,
2293                    |module| {
2294                        self.r
2295                            .resolutions(module)
2296                            .borrow()
2297                            .iter()
2298                            .any(|(key, _)| key.ident.name == following_seg.ident.name)
2299                    },
2300                ),
2301                _ => true,
2302            });
2303        }
2304        let name = path[path.len() - 1].ident.name;
2305        // Make sure error reporting is deterministic.
2306        names.sort_by(|a, b| a.candidate.as_str().cmp(b.candidate.as_str()));
2307
2308        match find_best_match_for_name(
2309            &names.iter().map(|suggestion| suggestion.candidate).collect::<Vec<Symbol>>(),
2310            name,
2311            None,
2312        ) {
2313            Some(found) => {
2314                let Some(sugg) = names.into_iter().find(|suggestion| suggestion.candidate == found)
2315                else {
2316                    return TypoCandidate::None;
2317                };
2318                if found == name {
2319                    TypoCandidate::Shadowed(sugg.res, sugg.span)
2320                } else {
2321                    TypoCandidate::Typo(sugg)
2322                }
2323            }
2324            _ => TypoCandidate::None,
2325        }
2326    }
2327
2328    // Returns the name of the Rust type approximately corresponding to
2329    // a type name in another programming language.
2330    fn likely_rust_type(path: &[Segment]) -> Option<Symbol> {
2331        let name = path[path.len() - 1].ident.as_str();
2332        // Common Java types
2333        Some(match name {
2334            "byte" => sym::u8, // In Java, bytes are signed, but in practice one almost always wants unsigned bytes.
2335            "short" => sym::i16,
2336            "Bool" => sym::bool,
2337            "Boolean" => sym::bool,
2338            "boolean" => sym::bool,
2339            "int" => sym::i32,
2340            "long" => sym::i64,
2341            "float" => sym::f32,
2342            "double" => sym::f64,
2343            _ => return None,
2344        })
2345    }
2346
2347    // try to give a suggestion for this pattern: `name = blah`, which is common in other languages
2348    // suggest `let name = blah` to introduce a new binding
2349    fn let_binding_suggestion(&mut self, err: &mut Diag<'_>, ident_span: Span) -> bool {
2350        if ident_span.from_expansion() {
2351            return false;
2352        }
2353
2354        // only suggest when the code is a assignment without prefix code
2355        if let Some(Expr { kind: ExprKind::Assign(lhs, ..), .. }) = self.diag_metadata.in_assignment
2356            && let ast::ExprKind::Path(None, ref path) = lhs.kind
2357            && self.r.tcx.sess.source_map().is_line_before_span_empty(ident_span)
2358        {
2359            let (span, text) = match path.segments.first() {
2360                Some(seg) if let Some(name) = seg.ident.as_str().strip_prefix("let") => {
2361                    // a special case for #117894
2362                    let name = name.strip_prefix('_').unwrap_or(name);
2363                    (ident_span, format!("let {name}"))
2364                }
2365                _ => (ident_span.shrink_to_lo(), "let ".to_string()),
2366            };
2367
2368            err.span_suggestion_verbose(
2369                span,
2370                "you might have meant to introduce a new binding",
2371                text,
2372                Applicability::MaybeIncorrect,
2373            );
2374            return true;
2375        }
2376
2377        // a special case for #133713
2378        // '=' maybe a typo of `:`, which is a type annotation instead of assignment
2379        if err.code == Some(E0423)
2380            && let Some((let_span, None, Some(val_span))) = self.diag_metadata.current_let_binding
2381            && val_span.contains(ident_span)
2382            && val_span.lo() == ident_span.lo()
2383        {
2384            err.span_suggestion_verbose(
2385                let_span.shrink_to_hi().to(val_span.shrink_to_lo()),
2386                "you might have meant to use `:` for type annotation",
2387                ": ",
2388                Applicability::MaybeIncorrect,
2389            );
2390            return true;
2391        }
2392        false
2393    }
2394
2395    fn find_module(&mut self, def_id: DefId) -> Option<(Module<'ra>, ImportSuggestion)> {
2396        let mut result = None;
2397        let mut seen_modules = FxHashSet::default();
2398        let root_did = self.r.graph_root.def_id();
2399        let mut worklist = vec![(
2400            self.r.graph_root,
2401            ThinVec::new(),
2402            root_did.is_local() || !self.r.tcx.is_doc_hidden(root_did),
2403        )];
2404
2405        while let Some((in_module, path_segments, doc_visible)) = worklist.pop() {
2406            // abort if the module is already found
2407            if result.is_some() {
2408                break;
2409            }
2410
2411            in_module.for_each_child(self.r, |r, ident, _, name_binding| {
2412                // abort if the module is already found or if name_binding is private external
2413                if result.is_some() || !name_binding.vis.is_visible_locally() {
2414                    return;
2415                }
2416                if let Some(module) = name_binding.module() {
2417                    // form the path
2418                    let mut path_segments = path_segments.clone();
2419                    path_segments.push(ast::PathSegment::from_ident(ident));
2420                    let module_def_id = module.def_id();
2421                    let doc_visible = doc_visible
2422                        && (module_def_id.is_local() || !r.tcx.is_doc_hidden(module_def_id));
2423                    if module_def_id == def_id {
2424                        let path =
2425                            Path { span: name_binding.span, segments: path_segments, tokens: None };
2426                        result = Some((
2427                            module,
2428                            ImportSuggestion {
2429                                did: Some(def_id),
2430                                descr: "module",
2431                                path,
2432                                accessible: true,
2433                                doc_visible,
2434                                note: None,
2435                                via_import: false,
2436                            },
2437                        ));
2438                    } else {
2439                        // add the module to the lookup
2440                        if seen_modules.insert(module_def_id) {
2441                            worklist.push((module, path_segments, doc_visible));
2442                        }
2443                    }
2444                }
2445            });
2446        }
2447
2448        result
2449    }
2450
2451    fn collect_enum_ctors(&mut self, def_id: DefId) -> Option<Vec<(Path, DefId, CtorKind)>> {
2452        self.find_module(def_id).map(|(enum_module, enum_import_suggestion)| {
2453            let mut variants = Vec::new();
2454            enum_module.for_each_child(self.r, |_, ident, _, name_binding| {
2455                if let Res::Def(DefKind::Ctor(CtorOf::Variant, kind), def_id) = name_binding.res() {
2456                    let mut segms = enum_import_suggestion.path.segments.clone();
2457                    segms.push(ast::PathSegment::from_ident(ident));
2458                    let path = Path { span: name_binding.span, segments: segms, tokens: None };
2459                    variants.push((path, def_id, kind));
2460                }
2461            });
2462            variants
2463        })
2464    }
2465
2466    /// Adds a suggestion for using an enum's variant when an enum is used instead.
2467    fn suggest_using_enum_variant(
2468        &mut self,
2469        err: &mut Diag<'_>,
2470        source: PathSource<'_>,
2471        def_id: DefId,
2472        span: Span,
2473    ) {
2474        let Some(variants) = self.collect_enum_ctors(def_id) else {
2475            err.note("you might have meant to use one of the enum's variants");
2476            return;
2477        };
2478
2479        let suggest_only_tuple_variants =
2480            matches!(source, PathSource::TupleStruct(..)) || source.is_call();
2481        if suggest_only_tuple_variants {
2482            // Suggest only tuple variants regardless of whether they have fields and do not
2483            // suggest path with added parentheses.
2484            let mut suggestable_variants = variants
2485                .iter()
2486                .filter(|(.., kind)| *kind == CtorKind::Fn)
2487                .map(|(variant, ..)| path_names_to_string(variant))
2488                .collect::<Vec<_>>();
2489            suggestable_variants.sort();
2490
2491            let non_suggestable_variant_count = variants.len() - suggestable_variants.len();
2492
2493            let source_msg = if source.is_call() {
2494                "to construct"
2495            } else if matches!(source, PathSource::TupleStruct(..)) {
2496                "to match against"
2497            } else {
2498                unreachable!()
2499            };
2500
2501            if !suggestable_variants.is_empty() {
2502                let msg = if non_suggestable_variant_count == 0 && suggestable_variants.len() == 1 {
2503                    format!("try {source_msg} the enum's variant")
2504                } else {
2505                    format!("try {source_msg} one of the enum's variants")
2506                };
2507
2508                err.span_suggestions(
2509                    span,
2510                    msg,
2511                    suggestable_variants,
2512                    Applicability::MaybeIncorrect,
2513                );
2514            }
2515
2516            // If the enum has no tuple variants..
2517            if non_suggestable_variant_count == variants.len() {
2518                err.help(format!("the enum has no tuple variants {source_msg}"));
2519            }
2520
2521            // If there are also non-tuple variants..
2522            if non_suggestable_variant_count == 1 {
2523                err.help(format!("you might have meant {source_msg} the enum's non-tuple variant"));
2524            } else if non_suggestable_variant_count >= 1 {
2525                err.help(format!(
2526                    "you might have meant {source_msg} one of the enum's non-tuple variants"
2527                ));
2528            }
2529        } else {
2530            let needs_placeholder = |ctor_def_id: DefId, kind: CtorKind| {
2531                let def_id = self.r.tcx.parent(ctor_def_id);
2532                match kind {
2533                    CtorKind::Const => false,
2534                    CtorKind::Fn => {
2535                        !self.r.field_idents(def_id).is_some_and(|field_ids| field_ids.is_empty())
2536                    }
2537                }
2538            };
2539
2540            let mut suggestable_variants = variants
2541                .iter()
2542                .filter(|(_, def_id, kind)| !needs_placeholder(*def_id, *kind))
2543                .map(|(variant, _, kind)| (path_names_to_string(variant), kind))
2544                .map(|(variant, kind)| match kind {
2545                    CtorKind::Const => variant,
2546                    CtorKind::Fn => format!("({variant}())"),
2547                })
2548                .collect::<Vec<_>>();
2549            suggestable_variants.sort();
2550            let no_suggestable_variant = suggestable_variants.is_empty();
2551
2552            if !no_suggestable_variant {
2553                let msg = if suggestable_variants.len() == 1 {
2554                    "you might have meant to use the following enum variant"
2555                } else {
2556                    "you might have meant to use one of the following enum variants"
2557                };
2558
2559                err.span_suggestions(
2560                    span,
2561                    msg,
2562                    suggestable_variants,
2563                    Applicability::MaybeIncorrect,
2564                );
2565            }
2566
2567            let mut suggestable_variants_with_placeholders = variants
2568                .iter()
2569                .filter(|(_, def_id, kind)| needs_placeholder(*def_id, *kind))
2570                .map(|(variant, _, kind)| (path_names_to_string(variant), kind))
2571                .filter_map(|(variant, kind)| match kind {
2572                    CtorKind::Fn => Some(format!("({variant}(/* fields */))")),
2573                    _ => None,
2574                })
2575                .collect::<Vec<_>>();
2576            suggestable_variants_with_placeholders.sort();
2577
2578            if !suggestable_variants_with_placeholders.is_empty() {
2579                let msg =
2580                    match (no_suggestable_variant, suggestable_variants_with_placeholders.len()) {
2581                        (true, 1) => "the following enum variant is available",
2582                        (true, _) => "the following enum variants are available",
2583                        (false, 1) => "alternatively, the following enum variant is available",
2584                        (false, _) => {
2585                            "alternatively, the following enum variants are also available"
2586                        }
2587                    };
2588
2589                err.span_suggestions(
2590                    span,
2591                    msg,
2592                    suggestable_variants_with_placeholders,
2593                    Applicability::HasPlaceholders,
2594                );
2595            }
2596        };
2597
2598        if def_id.is_local() {
2599            err.span_note(self.r.def_span(def_id), "the enum is defined here");
2600        }
2601    }
2602
2603    pub(crate) fn suggest_adding_generic_parameter(
2604        &self,
2605        path: &[Segment],
2606        source: PathSource<'_>,
2607    ) -> Option<(Span, &'static str, String, Applicability)> {
2608        let (ident, span) = match path {
2609            [segment]
2610                if !segment.has_generic_args
2611                    && segment.ident.name != kw::SelfUpper
2612                    && segment.ident.name != kw::Dyn =>
2613            {
2614                (segment.ident.to_string(), segment.ident.span)
2615            }
2616            _ => return None,
2617        };
2618        let mut iter = ident.chars().map(|c| c.is_uppercase());
2619        let single_uppercase_char =
2620            matches!(iter.next(), Some(true)) && matches!(iter.next(), None);
2621        if !self.diag_metadata.currently_processing_generic_args && !single_uppercase_char {
2622            return None;
2623        }
2624        match (self.diag_metadata.current_item, single_uppercase_char, self.diag_metadata.currently_processing_generic_args) {
2625            (Some(Item { kind: ItemKind::Fn(..), ident, .. }), _, _) if ident.name == sym::main => {
2626                // Ignore `fn main()` as we don't want to suggest `fn main<T>()`
2627            }
2628            (
2629                Some(Item {
2630                    kind:
2631                        kind @ ItemKind::Fn(..)
2632                        | kind @ ItemKind::Enum(..)
2633                        | kind @ ItemKind::Struct(..)
2634                        | kind @ ItemKind::Union(..),
2635                    ..
2636                }),
2637                true, _
2638            )
2639            // Without the 2nd `true`, we'd suggest `impl <T>` for `impl T` when a type `T` isn't found
2640            | (Some(Item { kind: kind @ ItemKind::Impl(..), .. }), true, true)
2641            | (Some(Item { kind, .. }), false, _) => {
2642                if let Some(generics) = kind.generics() {
2643                    if span.overlaps(generics.span) {
2644                        // Avoid the following:
2645                        // error[E0405]: cannot find trait `A` in this scope
2646                        //  --> $DIR/typo-suggestion-named-underscore.rs:CC:LL
2647                        //   |
2648                        // L | fn foo<T: A>(x: T) {} // Shouldn't suggest underscore
2649                        //   |           ^- help: you might be missing a type parameter: `, A`
2650                        //   |           |
2651                        //   |           not found in this scope
2652                        return None;
2653                    }
2654
2655                    let (msg, sugg) = match source {
2656                        PathSource::Type | PathSource::PreciseCapturingArg(TypeNS) => {
2657                            ("you might be missing a type parameter", ident)
2658                        }
2659                        PathSource::Expr(_) | PathSource::PreciseCapturingArg(ValueNS) => (
2660                            "you might be missing a const parameter",
2661                            format!("const {ident}: /* Type */"),
2662                        ),
2663                        _ => return None,
2664                    };
2665                    let (span, sugg) = if let [.., param] = &generics.params[..] {
2666                        let span = if let [.., bound] = &param.bounds[..] {
2667                            bound.span()
2668                        } else if let GenericParam {
2669                            kind: GenericParamKind::Const { ty, kw_span: _, default  }, ..
2670                        } = param {
2671                            default.as_ref().map(|def| def.value.span).unwrap_or(ty.span)
2672                        } else {
2673                            param.ident.span
2674                        };
2675                        (span, format!(", {sugg}"))
2676                    } else {
2677                        (generics.span, format!("<{sugg}>"))
2678                    };
2679                    // Do not suggest if this is coming from macro expansion.
2680                    if span.can_be_used_for_suggestions() {
2681                        return Some((
2682                            span.shrink_to_hi(),
2683                            msg,
2684                            sugg,
2685                            Applicability::MaybeIncorrect,
2686                        ));
2687                    }
2688                }
2689            }
2690            _ => {}
2691        }
2692        None
2693    }
2694
2695    /// Given the target `label`, search the `rib_index`th label rib for similarly named labels,
2696    /// optionally returning the closest match and whether it is reachable.
2697    pub(crate) fn suggestion_for_label_in_rib(
2698        &self,
2699        rib_index: usize,
2700        label: Ident,
2701    ) -> Option<LabelSuggestion> {
2702        // Are ribs from this `rib_index` within scope?
2703        let within_scope = self.is_label_valid_from_rib(rib_index);
2704
2705        let rib = &self.label_ribs[rib_index];
2706        let names = rib
2707            .bindings
2708            .iter()
2709            .filter(|(id, _)| id.span.eq_ctxt(label.span))
2710            .map(|(id, _)| id.name)
2711            .collect::<Vec<Symbol>>();
2712
2713        find_best_match_for_name(&names, label.name, None).map(|symbol| {
2714            // Upon finding a similar name, get the ident that it was from - the span
2715            // contained within helps make a useful diagnostic. In addition, determine
2716            // whether this candidate is within scope.
2717            let (ident, _) = rib.bindings.iter().find(|(ident, _)| ident.name == symbol).unwrap();
2718            (*ident, within_scope)
2719        })
2720    }
2721
2722    pub(crate) fn maybe_report_lifetime_uses(
2723        &mut self,
2724        generics_span: Span,
2725        params: &[ast::GenericParam],
2726    ) {
2727        for (param_index, param) in params.iter().enumerate() {
2728            let GenericParamKind::Lifetime = param.kind else { continue };
2729
2730            let def_id = self.r.local_def_id(param.id);
2731
2732            let use_set = self.lifetime_uses.remove(&def_id);
2733            debug!(
2734                "Use set for {:?}({:?} at {:?}) is {:?}",
2735                def_id, param.ident, param.ident.span, use_set
2736            );
2737
2738            let deletion_span = || {
2739                if params.len() == 1 {
2740                    // if sole lifetime, remove the entire `<>` brackets
2741                    Some(generics_span)
2742                } else if param_index == 0 {
2743                    // if removing within `<>` brackets, we also want to
2744                    // delete a leading or trailing comma as appropriate
2745                    match (
2746                        param.span().find_ancestor_inside(generics_span),
2747                        params[param_index + 1].span().find_ancestor_inside(generics_span),
2748                    ) {
2749                        (Some(param_span), Some(next_param_span)) => {
2750                            Some(param_span.to(next_param_span.shrink_to_lo()))
2751                        }
2752                        _ => None,
2753                    }
2754                } else {
2755                    // if removing within `<>` brackets, we also want to
2756                    // delete a leading or trailing comma as appropriate
2757                    match (
2758                        param.span().find_ancestor_inside(generics_span),
2759                        params[param_index - 1].span().find_ancestor_inside(generics_span),
2760                    ) {
2761                        (Some(param_span), Some(prev_param_span)) => {
2762                            Some(prev_param_span.shrink_to_hi().to(param_span))
2763                        }
2764                        _ => None,
2765                    }
2766                }
2767            };
2768            match use_set {
2769                Some(LifetimeUseSet::Many) => {}
2770                Some(LifetimeUseSet::One { use_span, use_ctxt }) => {
2771                    debug!(?param.ident, ?param.ident.span, ?use_span);
2772
2773                    let elidable = matches!(use_ctxt, LifetimeCtxt::Ref);
2774                    let deletion_span =
2775                        if param.bounds.is_empty() { deletion_span() } else { None };
2776
2777                    self.r.lint_buffer.buffer_lint(
2778                        lint::builtin::SINGLE_USE_LIFETIMES,
2779                        param.id,
2780                        param.ident.span,
2781                        lint::BuiltinLintDiag::SingleUseLifetime {
2782                            param_span: param.ident.span,
2783                            use_span: Some((use_span, elidable)),
2784                            deletion_span,
2785                            ident: param.ident,
2786                        },
2787                    );
2788                }
2789                None => {
2790                    debug!(?param.ident, ?param.ident.span);
2791                    let deletion_span = deletion_span();
2792
2793                    // if the lifetime originates from expanded code, we won't be able to remove it #104432
2794                    if deletion_span.is_some_and(|sp| !sp.in_derive_expansion()) {
2795                        self.r.lint_buffer.buffer_lint(
2796                            lint::builtin::UNUSED_LIFETIMES,
2797                            param.id,
2798                            param.ident.span,
2799                            lint::BuiltinLintDiag::SingleUseLifetime {
2800                                param_span: param.ident.span,
2801                                use_span: None,
2802                                deletion_span,
2803                                ident: param.ident,
2804                            },
2805                        );
2806                    }
2807                }
2808            }
2809        }
2810    }
2811
2812    pub(crate) fn emit_undeclared_lifetime_error(
2813        &self,
2814        lifetime_ref: &ast::Lifetime,
2815        outer_lifetime_ref: Option<Ident>,
2816    ) {
2817        debug_assert_ne!(lifetime_ref.ident.name, kw::UnderscoreLifetime);
2818        let mut err = if let Some(outer) = outer_lifetime_ref {
2819            struct_span_code_err!(
2820                self.r.dcx(),
2821                lifetime_ref.ident.span,
2822                E0401,
2823                "can't use generic parameters from outer item",
2824            )
2825            .with_span_label(lifetime_ref.ident.span, "use of generic parameter from outer item")
2826            .with_span_label(outer.span, "lifetime parameter from outer item")
2827        } else {
2828            struct_span_code_err!(
2829                self.r.dcx(),
2830                lifetime_ref.ident.span,
2831                E0261,
2832                "use of undeclared lifetime name `{}`",
2833                lifetime_ref.ident
2834            )
2835            .with_span_label(lifetime_ref.ident.span, "undeclared lifetime")
2836        };
2837        self.suggest_introducing_lifetime(
2838            &mut err,
2839            Some(lifetime_ref.ident.name.as_str()),
2840            |err, _, span, message, suggestion, span_suggs| {
2841                err.multipart_suggestion_with_style(
2842                    message,
2843                    std::iter::once((span, suggestion)).chain(span_suggs.clone()).collect(),
2844                    Applicability::MaybeIncorrect,
2845                    if span_suggs.is_empty() {
2846                        SuggestionStyle::ShowCode
2847                    } else {
2848                        SuggestionStyle::ShowAlways
2849                    },
2850                );
2851                true
2852            },
2853        );
2854        err.emit();
2855    }
2856
2857    fn suggest_introducing_lifetime(
2858        &self,
2859        err: &mut Diag<'_>,
2860        name: Option<&str>,
2861        suggest: impl Fn(
2862            &mut Diag<'_>,
2863            bool,
2864            Span,
2865            Cow<'static, str>,
2866            String,
2867            Vec<(Span, String)>,
2868        ) -> bool,
2869    ) {
2870        let mut suggest_note = true;
2871        for rib in self.lifetime_ribs.iter().rev() {
2872            let mut should_continue = true;
2873            match rib.kind {
2874                LifetimeRibKind::Generics { binder, span, kind } => {
2875                    // Avoid suggesting placing lifetime parameters on constant items unless the relevant
2876                    // feature is enabled. Suggest the parent item as a possible location if applicable.
2877                    if let LifetimeBinderKind::ConstItem = kind
2878                        && !self.r.tcx().features().generic_const_items()
2879                    {
2880                        continue;
2881                    }
2882
2883                    if !span.can_be_used_for_suggestions()
2884                        && suggest_note
2885                        && let Some(name) = name
2886                    {
2887                        suggest_note = false; // Avoid displaying the same help multiple times.
2888                        err.span_label(
2889                            span,
2890                            format!(
2891                                "lifetime `{name}` is missing in item created through this procedural macro",
2892                            ),
2893                        );
2894                        continue;
2895                    }
2896
2897                    let higher_ranked = matches!(
2898                        kind,
2899                        LifetimeBinderKind::BareFnType
2900                            | LifetimeBinderKind::PolyTrait
2901                            | LifetimeBinderKind::WhereBound
2902                    );
2903
2904                    let mut rm_inner_binders: FxIndexSet<Span> = Default::default();
2905                    let (span, sugg) = if span.is_empty() {
2906                        let mut binder_idents: FxIndexSet<Ident> = Default::default();
2907                        binder_idents.insert(Ident::from_str(name.unwrap_or("'a")));
2908
2909                        // We need to special case binders in the following situation:
2910                        // Change `T: for<'a> Trait<T> + 'b` to `for<'a, 'b> T: Trait<T> + 'b`
2911                        // T: for<'a> Trait<T> + 'b
2912                        //    ^^^^^^^  remove existing inner binder `for<'a>`
2913                        // for<'a, 'b> T: Trait<T> + 'b
2914                        // ^^^^^^^^^^^  suggest outer binder `for<'a, 'b>`
2915                        if let LifetimeBinderKind::WhereBound = kind
2916                            && let Some(predicate) = self.diag_metadata.current_where_predicate
2917                            && let ast::WherePredicateKind::BoundPredicate(
2918                                ast::WhereBoundPredicate { bounded_ty, bounds, .. },
2919                            ) = &predicate.kind
2920                            && bounded_ty.id == binder
2921                        {
2922                            for bound in bounds {
2923                                if let ast::GenericBound::Trait(poly_trait_ref) = bound
2924                                    && let span = poly_trait_ref
2925                                        .span
2926                                        .with_hi(poly_trait_ref.trait_ref.path.span.lo())
2927                                    && !span.is_empty()
2928                                {
2929                                    rm_inner_binders.insert(span);
2930                                    poly_trait_ref.bound_generic_params.iter().for_each(|v| {
2931                                        binder_idents.insert(v.ident);
2932                                    });
2933                                }
2934                            }
2935                        }
2936
2937                        let binders_sugg = binder_idents.into_iter().enumerate().fold(
2938                            "".to_string(),
2939                            |mut binders, (i, x)| {
2940                                if i != 0 {
2941                                    binders += ", ";
2942                                }
2943                                binders += x.as_str();
2944                                binders
2945                            },
2946                        );
2947                        let sugg = format!(
2948                            "{}<{}>{}",
2949                            if higher_ranked { "for" } else { "" },
2950                            binders_sugg,
2951                            if higher_ranked { " " } else { "" },
2952                        );
2953                        (span, sugg)
2954                    } else {
2955                        let span = self
2956                            .r
2957                            .tcx
2958                            .sess
2959                            .source_map()
2960                            .span_through_char(span, '<')
2961                            .shrink_to_hi();
2962                        let sugg = format!("{}, ", name.unwrap_or("'a"));
2963                        (span, sugg)
2964                    };
2965
2966                    if higher_ranked {
2967                        let message = Cow::from(format!(
2968                            "consider making the {} lifetime-generic with a new `{}` lifetime",
2969                            kind.descr(),
2970                            name.unwrap_or("'a"),
2971                        ));
2972                        should_continue = suggest(
2973                            err,
2974                            true,
2975                            span,
2976                            message,
2977                            sugg,
2978                            if !rm_inner_binders.is_empty() {
2979                                rm_inner_binders
2980                                    .into_iter()
2981                                    .map(|v| (v, "".to_string()))
2982                                    .collect::<Vec<_>>()
2983                            } else {
2984                                vec![]
2985                            },
2986                        );
2987                        err.note_once(
2988                            "for more information on higher-ranked polymorphism, visit \
2989                             https://doc.rust-lang.org/nomicon/hrtb.html",
2990                        );
2991                    } else if let Some(name) = name {
2992                        let message =
2993                            Cow::from(format!("consider introducing lifetime `{name}` here"));
2994                        should_continue = suggest(err, false, span, message, sugg, vec![]);
2995                    } else {
2996                        let message = Cow::from("consider introducing a named lifetime parameter");
2997                        should_continue = suggest(err, false, span, message, sugg, vec![]);
2998                    }
2999                }
3000                LifetimeRibKind::Item | LifetimeRibKind::ConstParamTy => break,
3001                _ => {}
3002            }
3003            if !should_continue {
3004                break;
3005            }
3006        }
3007    }
3008
3009    pub(crate) fn emit_non_static_lt_in_const_param_ty_error(&self, lifetime_ref: &ast::Lifetime) {
3010        self.r
3011            .dcx()
3012            .create_err(errors::ParamInTyOfConstParam {
3013                span: lifetime_ref.ident.span,
3014                name: lifetime_ref.ident.name,
3015                param_kind: Some(errors::ParamKindInTyOfConstParam::Lifetime),
3016            })
3017            .emit();
3018    }
3019
3020    /// Non-static lifetimes are prohibited in anonymous constants under `min_const_generics`.
3021    /// This function will emit an error if `generic_const_exprs` is not enabled, the body identified by
3022    /// `body_id` is an anonymous constant and `lifetime_ref` is non-static.
3023    pub(crate) fn emit_forbidden_non_static_lifetime_error(
3024        &self,
3025        cause: NoConstantGenericsReason,
3026        lifetime_ref: &ast::Lifetime,
3027    ) {
3028        match cause {
3029            NoConstantGenericsReason::IsEnumDiscriminant => {
3030                self.r
3031                    .dcx()
3032                    .create_err(errors::ParamInEnumDiscriminant {
3033                        span: lifetime_ref.ident.span,
3034                        name: lifetime_ref.ident.name,
3035                        param_kind: errors::ParamKindInEnumDiscriminant::Lifetime,
3036                    })
3037                    .emit();
3038            }
3039            NoConstantGenericsReason::NonTrivialConstArg => {
3040                assert!(!self.r.tcx.features().generic_const_exprs());
3041                self.r
3042                    .dcx()
3043                    .create_err(errors::ParamInNonTrivialAnonConst {
3044                        span: lifetime_ref.ident.span,
3045                        name: lifetime_ref.ident.name,
3046                        param_kind: errors::ParamKindInNonTrivialAnonConst::Lifetime,
3047                        help: self
3048                            .r
3049                            .tcx
3050                            .sess
3051                            .is_nightly_build()
3052                            .then_some(errors::ParamInNonTrivialAnonConstHelp),
3053                    })
3054                    .emit();
3055            }
3056        }
3057    }
3058
3059    pub(crate) fn report_missing_lifetime_specifiers(
3060        &mut self,
3061        lifetime_refs: Vec<MissingLifetime>,
3062        function_param_lifetimes: Option<(Vec<MissingLifetime>, Vec<ElisionFnParameter>)>,
3063    ) -> ErrorGuaranteed {
3064        let num_lifetimes: usize = lifetime_refs.iter().map(|lt| lt.count).sum();
3065        let spans: Vec<_> = lifetime_refs.iter().map(|lt| lt.span).collect();
3066
3067        let mut err = struct_span_code_err!(
3068            self.r.dcx(),
3069            spans,
3070            E0106,
3071            "missing lifetime specifier{}",
3072            pluralize!(num_lifetimes)
3073        );
3074        self.add_missing_lifetime_specifiers_label(
3075            &mut err,
3076            lifetime_refs,
3077            function_param_lifetimes,
3078        );
3079        err.emit()
3080    }
3081
3082    fn add_missing_lifetime_specifiers_label(
3083        &mut self,
3084        err: &mut Diag<'_>,
3085        lifetime_refs: Vec<MissingLifetime>,
3086        function_param_lifetimes: Option<(Vec<MissingLifetime>, Vec<ElisionFnParameter>)>,
3087    ) {
3088        for &lt in &lifetime_refs {
3089            err.span_label(
3090                lt.span,
3091                format!(
3092                    "expected {} lifetime parameter{}",
3093                    if lt.count == 1 { "named".to_string() } else { lt.count.to_string() },
3094                    pluralize!(lt.count),
3095                ),
3096            );
3097        }
3098
3099        let mut in_scope_lifetimes: Vec<_> = self
3100            .lifetime_ribs
3101            .iter()
3102            .rev()
3103            .take_while(|rib| {
3104                !matches!(rib.kind, LifetimeRibKind::Item | LifetimeRibKind::ConstParamTy)
3105            })
3106            .flat_map(|rib| rib.bindings.iter())
3107            .map(|(&ident, &res)| (ident, res))
3108            .filter(|(ident, _)| ident.name != kw::UnderscoreLifetime)
3109            .collect();
3110        debug!(?in_scope_lifetimes);
3111
3112        let mut maybe_static = false;
3113        debug!(?function_param_lifetimes);
3114        if let Some((param_lifetimes, params)) = &function_param_lifetimes {
3115            let elided_len = param_lifetimes.len();
3116            let num_params = params.len();
3117
3118            let mut m = String::new();
3119
3120            for (i, info) in params.iter().enumerate() {
3121                let ElisionFnParameter { ident, index, lifetime_count, span } = *info;
3122                debug_assert_ne!(lifetime_count, 0);
3123
3124                err.span_label(span, "");
3125
3126                if i != 0 {
3127                    if i + 1 < num_params {
3128                        m.push_str(", ");
3129                    } else if num_params == 2 {
3130                        m.push_str(" or ");
3131                    } else {
3132                        m.push_str(", or ");
3133                    }
3134                }
3135
3136                let help_name = if let Some(ident) = ident {
3137                    format!("`{ident}`")
3138                } else {
3139                    format!("argument {}", index + 1)
3140                };
3141
3142                if lifetime_count == 1 {
3143                    m.push_str(&help_name[..])
3144                } else {
3145                    m.push_str(&format!("one of {help_name}'s {lifetime_count} lifetimes")[..])
3146                }
3147            }
3148
3149            if num_params == 0 {
3150                err.help(
3151                    "this function's return type contains a borrowed value, but there is no value \
3152                     for it to be borrowed from",
3153                );
3154                if in_scope_lifetimes.is_empty() {
3155                    maybe_static = true;
3156                    in_scope_lifetimes = vec![(
3157                        Ident::with_dummy_span(kw::StaticLifetime),
3158                        (DUMMY_NODE_ID, LifetimeRes::Static { suppress_elision_warning: false }),
3159                    )];
3160                }
3161            } else if elided_len == 0 {
3162                err.help(
3163                    "this function's return type contains a borrowed value with an elided \
3164                     lifetime, but the lifetime cannot be derived from the arguments",
3165                );
3166                if in_scope_lifetimes.is_empty() {
3167                    maybe_static = true;
3168                    in_scope_lifetimes = vec![(
3169                        Ident::with_dummy_span(kw::StaticLifetime),
3170                        (DUMMY_NODE_ID, LifetimeRes::Static { suppress_elision_warning: false }),
3171                    )];
3172                }
3173            } else if num_params == 1 {
3174                err.help(format!(
3175                    "this function's return type contains a borrowed value, but the signature does \
3176                     not say which {m} it is borrowed from",
3177                ));
3178            } else {
3179                err.help(format!(
3180                    "this function's return type contains a borrowed value, but the signature does \
3181                     not say whether it is borrowed from {m}",
3182                ));
3183            }
3184        }
3185
3186        #[allow(rustc::symbol_intern_string_literal)]
3187        let existing_name = match &in_scope_lifetimes[..] {
3188            [] => Symbol::intern("'a"),
3189            [(existing, _)] => existing.name,
3190            _ => Symbol::intern("'lifetime"),
3191        };
3192
3193        let mut spans_suggs: Vec<_> = Vec::new();
3194        let build_sugg = |lt: MissingLifetime| match lt.kind {
3195            MissingLifetimeKind::Underscore => {
3196                debug_assert_eq!(lt.count, 1);
3197                (lt.span, existing_name.to_string())
3198            }
3199            MissingLifetimeKind::Ampersand => {
3200                debug_assert_eq!(lt.count, 1);
3201                (lt.span.shrink_to_hi(), format!("{existing_name} "))
3202            }
3203            MissingLifetimeKind::Comma => {
3204                let sugg: String = std::iter::repeat([existing_name.as_str(), ", "])
3205                    .take(lt.count)
3206                    .flatten()
3207                    .collect();
3208                (lt.span.shrink_to_hi(), sugg)
3209            }
3210            MissingLifetimeKind::Brackets => {
3211                let sugg: String = std::iter::once("<")
3212                    .chain(
3213                        std::iter::repeat(existing_name.as_str()).take(lt.count).intersperse(", "),
3214                    )
3215                    .chain([">"])
3216                    .collect();
3217                (lt.span.shrink_to_hi(), sugg)
3218            }
3219        };
3220        for &lt in &lifetime_refs {
3221            spans_suggs.push(build_sugg(lt));
3222        }
3223        debug!(?spans_suggs);
3224        match in_scope_lifetimes.len() {
3225            0 => {
3226                if let Some((param_lifetimes, _)) = function_param_lifetimes {
3227                    for lt in param_lifetimes {
3228                        spans_suggs.push(build_sugg(lt))
3229                    }
3230                }
3231                self.suggest_introducing_lifetime(
3232                    err,
3233                    None,
3234                    |err, higher_ranked, span, message, intro_sugg, _| {
3235                        err.multipart_suggestion_verbose(
3236                            message,
3237                            std::iter::once((span, intro_sugg))
3238                                .chain(spans_suggs.clone())
3239                                .collect(),
3240                            Applicability::MaybeIncorrect,
3241                        );
3242                        higher_ranked
3243                    },
3244                );
3245            }
3246            1 => {
3247                let post = if maybe_static {
3248                    let owned = if let [lt] = &lifetime_refs[..]
3249                        && lt.kind != MissingLifetimeKind::Ampersand
3250                    {
3251                        ", or if you will only have owned values"
3252                    } else {
3253                        ""
3254                    };
3255                    format!(
3256                        ", but this is uncommon unless you're returning a borrowed value from a \
3257                         `const` or a `static`{owned}",
3258                    )
3259                } else {
3260                    String::new()
3261                };
3262                err.multipart_suggestion_verbose(
3263                    format!("consider using the `{existing_name}` lifetime{post}"),
3264                    spans_suggs,
3265                    Applicability::MaybeIncorrect,
3266                );
3267                if maybe_static {
3268                    // FIXME: what follows are general suggestions, but we'd want to perform some
3269                    // minimal flow analysis to provide more accurate suggestions. For example, if
3270                    // we identified that the return expression references only one argument, we
3271                    // would suggest borrowing only that argument, and we'd skip the prior
3272                    // "use `'static`" suggestion entirely.
3273                    if let [lt] = &lifetime_refs[..]
3274                        && (lt.kind == MissingLifetimeKind::Ampersand
3275                            || lt.kind == MissingLifetimeKind::Underscore)
3276                    {
3277                        let pre = if lt.kind == MissingLifetimeKind::Ampersand
3278                            && let Some((kind, _span)) = self.diag_metadata.current_function
3279                            && let FnKind::Fn(_, _, _, ast::Fn { sig, .. }) = kind
3280                            && !sig.decl.inputs.is_empty()
3281                            && let sugg = sig
3282                                .decl
3283                                .inputs
3284                                .iter()
3285                                .filter_map(|param| {
3286                                    if param.ty.span.contains(lt.span) {
3287                                        // We don't want to suggest `fn elision(_: &fn() -> &i32)`
3288                                        // when we have `fn elision(_: fn() -> &i32)`
3289                                        None
3290                                    } else if let TyKind::CVarArgs = param.ty.kind {
3291                                        // Don't suggest `&...` for ffi fn with varargs
3292                                        None
3293                                    } else if let TyKind::ImplTrait(..) = &param.ty.kind {
3294                                        // We handle these in the next `else if` branch.
3295                                        None
3296                                    } else {
3297                                        Some((param.ty.span.shrink_to_lo(), "&".to_string()))
3298                                    }
3299                                })
3300                                .collect::<Vec<_>>()
3301                            && !sugg.is_empty()
3302                        {
3303                            let (the, s) = if sig.decl.inputs.len() == 1 {
3304                                ("the", "")
3305                            } else {
3306                                ("one of the", "s")
3307                            };
3308                            err.multipart_suggestion_verbose(
3309                                format!(
3310                                    "instead, you are more likely to want to change {the} \
3311                                     argument{s} to be borrowed...",
3312                                ),
3313                                sugg,
3314                                Applicability::MaybeIncorrect,
3315                            );
3316                            "...or alternatively, you might want"
3317                        } else if (lt.kind == MissingLifetimeKind::Ampersand
3318                            || lt.kind == MissingLifetimeKind::Underscore)
3319                            && let Some((kind, _span)) = self.diag_metadata.current_function
3320                            && let FnKind::Fn(_, _, _, ast::Fn { sig, .. }) = kind
3321                            && let ast::FnRetTy::Ty(ret_ty) = &sig.decl.output
3322                            && !sig.decl.inputs.is_empty()
3323                            && let arg_refs = sig
3324                                .decl
3325                                .inputs
3326                                .iter()
3327                                .filter_map(|param| match &param.ty.kind {
3328                                    TyKind::ImplTrait(_, bounds) => Some(bounds),
3329                                    _ => None,
3330                                })
3331                                .flat_map(|bounds| bounds.into_iter())
3332                                .collect::<Vec<_>>()
3333                            && !arg_refs.is_empty()
3334                        {
3335                            // We have a situation like
3336                            // fn g(mut x: impl Iterator<Item = &()>) -> Option<&()>
3337                            // So we look at every ref in the trait bound. If there's any, we
3338                            // suggest
3339                            // fn g<'a>(mut x: impl Iterator<Item = &'a ()>) -> Option<&'a ()>
3340                            let mut lt_finder =
3341                                LifetimeFinder { lifetime: lt.span, found: None, seen: vec![] };
3342                            for bound in arg_refs {
3343                                if let ast::GenericBound::Trait(trait_ref) = bound {
3344                                    lt_finder.visit_trait_ref(&trait_ref.trait_ref);
3345                                }
3346                            }
3347                            lt_finder.visit_ty(ret_ty);
3348                            let spans_suggs: Vec<_> = lt_finder
3349                                .seen
3350                                .iter()
3351                                .filter_map(|ty| match &ty.kind {
3352                                    TyKind::Ref(_, mut_ty) => {
3353                                        let span = ty.span.with_hi(mut_ty.ty.span.lo());
3354                                        Some((span, "&'a ".to_string()))
3355                                    }
3356                                    _ => None,
3357                                })
3358                                .collect();
3359                            self.suggest_introducing_lifetime(
3360                                err,
3361                                None,
3362                                |err, higher_ranked, span, message, intro_sugg, _| {
3363                                    err.multipart_suggestion_verbose(
3364                                        message,
3365                                        std::iter::once((span, intro_sugg))
3366                                            .chain(spans_suggs.clone())
3367                                            .collect(),
3368                                        Applicability::MaybeIncorrect,
3369                                    );
3370                                    higher_ranked
3371                                },
3372                            );
3373                            "alternatively, you might want"
3374                        } else {
3375                            "instead, you are more likely to want"
3376                        };
3377                        let mut owned_sugg = lt.kind == MissingLifetimeKind::Ampersand;
3378                        let mut sugg = vec![(lt.span, String::new())];
3379                        if let Some((kind, _span)) = self.diag_metadata.current_function
3380                            && let FnKind::Fn(_, _, _, ast::Fn { sig, .. }) = kind
3381                            && let ast::FnRetTy::Ty(ty) = &sig.decl.output
3382                        {
3383                            let mut lt_finder =
3384                                LifetimeFinder { lifetime: lt.span, found: None, seen: vec![] };
3385                            lt_finder.visit_ty(&ty);
3386
3387                            if let [Ty { span, kind: TyKind::Ref(_, mut_ty), .. }] =
3388                                &lt_finder.seen[..]
3389                            {
3390                                // We might have a situation like
3391                                // fn g(mut x: impl Iterator<Item = &'_ ()>) -> Option<&'_ ()>
3392                                // but `lt.span` only points at `'_`, so to suggest `-> Option<()>`
3393                                // we need to find a more accurate span to end up with
3394                                // fn g<'a>(mut x: impl Iterator<Item = &'_ ()>) -> Option<()>
3395                                sugg = vec![(span.with_hi(mut_ty.ty.span.lo()), String::new())];
3396                                owned_sugg = true;
3397                            }
3398                            if let Some(ty) = lt_finder.found {
3399                                if let TyKind::Path(None, path) = &ty.kind {
3400                                    // Check if the path being borrowed is likely to be owned.
3401                                    let path: Vec<_> = Segment::from_path(path);
3402                                    match self.resolve_path(&path, Some(TypeNS), None) {
3403                                        PathResult::Module(ModuleOrUniformRoot::Module(module)) => {
3404                                            match module.res() {
3405                                                Some(Res::PrimTy(PrimTy::Str)) => {
3406                                                    // Don't suggest `-> str`, suggest `-> String`.
3407                                                    sugg = vec![(
3408                                                        lt.span.with_hi(ty.span.hi()),
3409                                                        "String".to_string(),
3410                                                    )];
3411                                                }
3412                                                Some(Res::PrimTy(..)) => {}
3413                                                Some(Res::Def(
3414                                                    DefKind::Struct
3415                                                    | DefKind::Union
3416                                                    | DefKind::Enum
3417                                                    | DefKind::ForeignTy
3418                                                    | DefKind::AssocTy
3419                                                    | DefKind::OpaqueTy
3420                                                    | DefKind::TyParam,
3421                                                    _,
3422                                                )) => {}
3423                                                _ => {
3424                                                    // Do not suggest in all other cases.
3425                                                    owned_sugg = false;
3426                                                }
3427                                            }
3428                                        }
3429                                        PathResult::NonModule(res) => {
3430                                            match res.base_res() {
3431                                                Res::PrimTy(PrimTy::Str) => {
3432                                                    // Don't suggest `-> str`, suggest `-> String`.
3433                                                    sugg = vec![(
3434                                                        lt.span.with_hi(ty.span.hi()),
3435                                                        "String".to_string(),
3436                                                    )];
3437                                                }
3438                                                Res::PrimTy(..) => {}
3439                                                Res::Def(
3440                                                    DefKind::Struct
3441                                                    | DefKind::Union
3442                                                    | DefKind::Enum
3443                                                    | DefKind::ForeignTy
3444                                                    | DefKind::AssocTy
3445                                                    | DefKind::OpaqueTy
3446                                                    | DefKind::TyParam,
3447                                                    _,
3448                                                ) => {}
3449                                                _ => {
3450                                                    // Do not suggest in all other cases.
3451                                                    owned_sugg = false;
3452                                                }
3453                                            }
3454                                        }
3455                                        _ => {
3456                                            // Do not suggest in all other cases.
3457                                            owned_sugg = false;
3458                                        }
3459                                    }
3460                                }
3461                                if let TyKind::Slice(inner_ty) = &ty.kind {
3462                                    // Don't suggest `-> [T]`, suggest `-> Vec<T>`.
3463                                    sugg = vec![
3464                                        (lt.span.with_hi(inner_ty.span.lo()), "Vec<".to_string()),
3465                                        (ty.span.with_lo(inner_ty.span.hi()), ">".to_string()),
3466                                    ];
3467                                }
3468                            }
3469                        }
3470                        if owned_sugg {
3471                            err.multipart_suggestion_verbose(
3472                                format!("{pre} to return an owned value"),
3473                                sugg,
3474                                Applicability::MaybeIncorrect,
3475                            );
3476                        }
3477                    }
3478                }
3479
3480                // Record as using the suggested resolution.
3481                let (_, (_, res)) = in_scope_lifetimes[0];
3482                for &lt in &lifetime_refs {
3483                    self.r.lifetimes_res_map.insert(lt.id, res);
3484                }
3485            }
3486            _ => {
3487                let lifetime_spans: Vec<_> =
3488                    in_scope_lifetimes.iter().map(|(ident, _)| ident.span).collect();
3489                err.span_note(lifetime_spans, "these named lifetimes are available to use");
3490
3491                if spans_suggs.len() > 0 {
3492                    // This happens when we have `Foo<T>` where we point at the space before `T`,
3493                    // but this can be confusing so we give a suggestion with placeholders.
3494                    err.multipart_suggestion_verbose(
3495                        "consider using one of the available lifetimes here",
3496                        spans_suggs,
3497                        Applicability::HasPlaceholders,
3498                    );
3499                }
3500            }
3501        }
3502    }
3503}
3504
3505fn mk_where_bound_predicate(
3506    path: &Path,
3507    poly_trait_ref: &ast::PolyTraitRef,
3508    ty: &Ty,
3509) -> Option<ast::WhereBoundPredicate> {
3510    let modified_segments = {
3511        let mut segments = path.segments.clone();
3512        let [preceding @ .., second_last, last] = segments.as_mut_slice() else {
3513            return None;
3514        };
3515        let mut segments = ThinVec::from(preceding);
3516
3517        let added_constraint = ast::AngleBracketedArg::Constraint(ast::AssocItemConstraint {
3518            id: DUMMY_NODE_ID,
3519            ident: last.ident,
3520            gen_args: None,
3521            kind: ast::AssocItemConstraintKind::Equality {
3522                term: ast::Term::Ty(ast::ptr::P(ast::Ty {
3523                    kind: ast::TyKind::Path(None, poly_trait_ref.trait_ref.path.clone()),
3524                    id: DUMMY_NODE_ID,
3525                    span: DUMMY_SP,
3526                    tokens: None,
3527                })),
3528            },
3529            span: DUMMY_SP,
3530        });
3531
3532        match second_last.args.as_deref_mut() {
3533            Some(ast::GenericArgs::AngleBracketed(ast::AngleBracketedArgs { args, .. })) => {
3534                args.push(added_constraint);
3535            }
3536            Some(_) => return None,
3537            None => {
3538                second_last.args =
3539                    Some(ast::ptr::P(ast::GenericArgs::AngleBracketed(ast::AngleBracketedArgs {
3540                        args: ThinVec::from([added_constraint]),
3541                        span: DUMMY_SP,
3542                    })));
3543            }
3544        }
3545
3546        segments.push(second_last.clone());
3547        segments
3548    };
3549
3550    let new_where_bound_predicate = ast::WhereBoundPredicate {
3551        bound_generic_params: ThinVec::new(),
3552        bounded_ty: ast::ptr::P(ty.clone()),
3553        bounds: vec![ast::GenericBound::Trait(ast::PolyTraitRef {
3554            bound_generic_params: ThinVec::new(),
3555            modifiers: ast::TraitBoundModifiers::NONE,
3556            trait_ref: ast::TraitRef {
3557                path: ast::Path { segments: modified_segments, span: DUMMY_SP, tokens: None },
3558                ref_id: DUMMY_NODE_ID,
3559            },
3560            span: DUMMY_SP,
3561        })],
3562    };
3563
3564    Some(new_where_bound_predicate)
3565}
3566
3567/// Report lifetime/lifetime shadowing as an error.
3568pub(super) fn signal_lifetime_shadowing(sess: &Session, orig: Ident, shadower: Ident) {
3569    struct_span_code_err!(
3570        sess.dcx(),
3571        shadower.span,
3572        E0496,
3573        "lifetime name `{}` shadows a lifetime name that is already in scope",
3574        orig.name,
3575    )
3576    .with_span_label(orig.span, "first declared here")
3577    .with_span_label(shadower.span, format!("lifetime `{}` already in scope", orig.name))
3578    .emit();
3579}
3580
3581struct LifetimeFinder<'ast> {
3582    lifetime: Span,
3583    found: Option<&'ast Ty>,
3584    seen: Vec<&'ast Ty>,
3585}
3586
3587impl<'ast> Visitor<'ast> for LifetimeFinder<'ast> {
3588    fn visit_ty(&mut self, t: &'ast Ty) {
3589        if let TyKind::Ref(_, mut_ty) | TyKind::PinnedRef(_, mut_ty) = &t.kind {
3590            self.seen.push(t);
3591            if t.span.lo() == self.lifetime.lo() {
3592                self.found = Some(&mut_ty.ty);
3593            }
3594        }
3595        walk_ty(self, t)
3596    }
3597}
3598
3599/// Shadowing involving a label is only a warning for historical reasons.
3600//FIXME: make this a proper lint.
3601pub(super) fn signal_label_shadowing(sess: &Session, orig: Span, shadower: Ident) {
3602    let name = shadower.name;
3603    let shadower = shadower.span;
3604    sess.dcx()
3605        .struct_span_warn(
3606            shadower,
3607            format!("label name `{name}` shadows a label name that is already in scope"),
3608        )
3609        .with_span_label(orig, "first declared here")
3610        .with_span_label(shadower, format!("label `{name}` already in scope"))
3611        .emit();
3612}