compiler/rustc_resolve/src/late/diagnostics.rs RUST 4,602 lines View on github.com → Search inside
File is large — showing lines 1–2,000 of 4,602.
1// ignore-tidy-filelength23use std::borrow::Cow;4use std::iter;5use std::ops::Deref;67use rustc_ast::visit::{FnCtxt, FnKind, LifetimeCtxt, Visitor, walk_ty};8use rustc_ast::{9    self as ast, AngleBracketedArg, AssocItemKind, DUMMY_NODE_ID, Expr, ExprKind, GenericArg,10    GenericArgs, GenericParam, GenericParamKind, Item, ItemKind, MethodCall, NodeId, Path,11    PathSegment, Ty, TyKind,12};13use rustc_ast_pretty::pprust::{path_to_string, where_bound_predicate_to_string};14use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet};15use rustc_errors::codes::*;16use rustc_errors::{17    Applicability, Diag, Diagnostic, 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::{CtorKind, CtorOf, DefKind, MacroKinds};23use rustc_hir::def_id::{CRATE_DEF_ID, DefId};24use rustc_hir::{MissingLifetimeKind, PrimTy, find_attr};25use rustc_middle::ty;26use rustc_session::{Session, lint};27use rustc_span::edit_distance::{edit_distance, find_best_match_for_name};28use rustc_span::edition::Edition;29use rustc_span::{DUMMY_SP, DesugaringKind, Ident, Span, Symbol, kw, sym};30use thin_vec::ThinVec;31use tracing::debug;3233use super::NoConstantGenericsReason;34use crate::diagnostics::{ImportSuggestion, LabelSuggestion, TypoSuggestion};35use crate::late::{36    AliasPossibility, LateResolutionVisitor, LifetimeBinderKind, LifetimeRes, LifetimeRibKind,37    LifetimeUseSet, QSelf, RibKind,38};39use crate::ty::fast_reject::SimplifiedType;40use crate::{41    Finalize, Module, ModuleKind, ModuleOrUniformRoot, ParentScope, PathResult, PathSource, Res,42    Resolver, ScopeSet, Segment, errors, path_names_to_string,43};4445/// A field or associated item from self type suggested in case of resolution failure.46enum AssocSuggestion {47    Field(Span),48    MethodWithSelf { called: bool },49    AssocFn { called: bool },50    AssocType,51    AssocConst,52}5354impl AssocSuggestion {55    fn action(&self) -> &'static str {56        match self {57            AssocSuggestion::Field(_) => "use the available field",58            AssocSuggestion::MethodWithSelf { called: true } => {59                "call the method with the fully-qualified path"60            }61            AssocSuggestion::MethodWithSelf { called: false } => {62                "refer to the method with the fully-qualified path"63            }64            AssocSuggestion::AssocFn { called: true } => "call the associated function",65            AssocSuggestion::AssocFn { called: false } => "refer to the associated function",66            AssocSuggestion::AssocConst => "use the associated `const`",67            AssocSuggestion::AssocType => "use the associated type",68        }69    }70}7172fn is_self_type(path: &[Segment], namespace: Namespace) -> bool {73    namespace == TypeNS && path.len() == 1 && path[0].ident.name == kw::SelfUpper74}7576fn is_self_value(path: &[Segment], namespace: Namespace) -> bool {77    namespace == ValueNS && path.len() == 1 && path[0].ident.name == kw::SelfLower78}7980fn path_to_string_without_assoc_item_bindings(path: &Path) -> String {81    let mut path = path.clone();82    for segment in &mut path.segments {83        let mut remove_args = false;84        if let Some(args) = segment.args.as_deref_mut()85            && let ast::GenericArgs::AngleBracketed(angle_bracketed) = args86        {87            angle_bracketed.args.retain(|arg| matches!(arg, ast::AngleBracketedArg::Arg(_)));88            remove_args = angle_bracketed.args.is_empty();89        }90        if remove_args {91            segment.args = None;92        }93    }94    path_to_string(&path)95}9697/// Gets the stringified path for an enum from an `ImportSuggestion` for an enum variant.98fn import_candidate_to_enum_paths(suggestion: &ImportSuggestion) -> (String, String) {99    let variant_path = &suggestion.path;100    let variant_path_string = path_names_to_string(variant_path);101102    let path_len = suggestion.path.segments.len();103    let enum_path = ast::Path {104        span: suggestion.path.span,105        segments: suggestion.path.segments[0..path_len - 1].iter().cloned().collect(),106        tokens: None,107    };108    let enum_path_string = path_names_to_string(&enum_path);109110    (variant_path_string, enum_path_string)111}112113/// Description of an elided lifetime.114#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug)]115pub(super) struct MissingLifetime {116    /// Used to overwrite the resolution with the suggestion, to avoid cascading errors.117    pub id: NodeId,118    /// As we cannot yet emit lints in this crate and have to buffer them instead,119    /// we need to associate each lint with some `NodeId`,120    /// however for some `MissingLifetime`s their `NodeId`s are "fake",121    /// in a sense that they are temporary and not get preserved down the line,122    /// which means that the lints for those nodes will not get emitted.123    /// To combat this, we can try to use some other `NodeId`s as a fallback option.124    pub id_for_lint: NodeId,125    /// Where to suggest adding the lifetime.126    pub span: Span,127    /// How the lifetime was introduced, to have the correct space and comma.128    pub kind: MissingLifetimeKind,129    /// Number of elided lifetimes, used for elision in path.130    pub count: usize,131}132133/// Description of the lifetimes appearing in a function parameter.134/// This is used to provide a literal explanation to the elision failure.135#[derive(Clone, Debug)]136pub(super) struct ElisionFnParameter {137    /// The index of the argument in the original definition.138    pub index: usize,139    /// The name of the argument if it's a simple ident.140    pub ident: Option<Ident>,141    /// The number of lifetimes in the parameter.142    pub lifetime_count: usize,143    /// The span of the parameter.144    pub span: Span,145}146147/// Description of lifetimes that appear as candidates for elision.148/// This is used to suggest introducing an explicit lifetime.149#[derive(Clone, Copy, Debug)]150pub(super) enum LifetimeElisionCandidate {151    /// This is not a real lifetime.152    Ignore,153    /// There is a named lifetime, we won't suggest anything.154    Named,155    Missing(MissingLifetime),156}157158/// Only used for diagnostics.159#[derive(Debug)]160struct BaseError {161    msg: String,162    fallback_label: String,163    span: Span,164    span_label: Option<(Span, &'static str)>,165    could_be_expr: bool,166    suggestion: Option<(Span, &'static str, String)>,167    module: Option<DefId>,168}169170#[derive(Debug)]171enum TypoCandidate {172    Typo(TypoSuggestion),173    Shadowed(Res, Option<Span>),174    None,175}176177impl TypoCandidate {178    fn to_opt_suggestion(self) -> Option<TypoSuggestion> {179        match self {180            TypoCandidate::Typo(sugg) => Some(sugg),181            TypoCandidate::Shadowed(_, _) | TypoCandidate::None => None,182        }183    }184}185186impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {187    fn trait_assoc_type_def_id_by_name(188        &mut self,189        trait_def_id: DefId,190        assoc_name: Symbol,191    ) -> Option<DefId> {192        let module = self.r.get_module(trait_def_id)?;193        self.r.resolutions(module).borrow().iter().find_map(|(key, resolution)| {194            if key.ident.name != assoc_name {195                return None;196            }197            let resolution = resolution.borrow();198            let binding = resolution.best_decl()?;199            match binding.res() {200                Res::Def(DefKind::AssocTy, def_id) => Some(def_id),201                _ => None,202            }203        })204    }205206    /// This does best-effort work to generate suggestions for associated types.207    fn suggest_assoc_type_from_bounds(208        &mut self,209        err: &mut Diag<'_>,210        source: PathSource<'_, 'ast, 'ra>,211        path: &[Segment],212        ident_span: Span,213    ) -> bool {214        // Filter out cases where we cannot emit meaningful suggestions.215        if source.namespace() != TypeNS {216            return false;217        }218        let [segment] = path else { return false };219        if segment.has_generic_args {220            return false;221        }222        if !ident_span.can_be_used_for_suggestions() {223            return false;224        }225        let assoc_name = segment.ident.name;226        if assoc_name == kw::Underscore {227            return false;228        }229230        // Map: type parameter name -> (trait def id -> (assoc type def id, trait paths as written)).231        // We keep a set of paths per trait so we can detect cases like232        // `T: Trait<i32> + Trait<u32>` where suggesting `T::Assoc` would be ambiguous.233        let mut matching_bounds: FxIndexMap<234            Symbol,235            FxIndexMap<DefId, (DefId, FxIndexSet<String>)>,236        > = FxIndexMap::default();237238        let mut record_bound = |this: &mut Self,239                                ty_param: Symbol,240                                poly_trait_ref: &ast::PolyTraitRef| {241            // Avoid generating suggestions we can't print in a well-formed way.242            if !poly_trait_ref.bound_generic_params.is_empty() {243                return;244            }245            if poly_trait_ref.modifiers != ast::TraitBoundModifiers::NONE {246                return;247            }248            let Some(trait_seg) = poly_trait_ref.trait_ref.path.segments.last() else {249                return;250            };251            let Some(partial_res) = this.r.partial_res_map.get(&trait_seg.id) else {252                return;253            };254            let Some(trait_def_id) = partial_res.full_res().and_then(|res| res.opt_def_id()) else {255                return;256            };257            let Some(assoc_type_def_id) =258                this.trait_assoc_type_def_id_by_name(trait_def_id, assoc_name)259            else {260                return;261            };262263            // Preserve `::` and generic args so we don't generate broken suggestions like264            // `<T as Foo>::Assoc` for bounds written as `T: ::Foo<'a>`, while stripping265            // associated-item bindings that are rejected in qualified paths.266            let trait_path =267                path_to_string_without_assoc_item_bindings(&poly_trait_ref.trait_ref.path);268            let trait_bounds = matching_bounds.entry(ty_param).or_default();269            let trait_bounds = trait_bounds270                .entry(trait_def_id)271                .or_insert_with(|| (assoc_type_def_id, FxIndexSet::default()));272            debug_assert_eq!(trait_bounds.0, assoc_type_def_id);273            trait_bounds.1.insert(trait_path);274        };275276        let mut record_from_generics = |this: &mut Self, generics: &ast::Generics| {277            for param in &generics.params {278                let ast::GenericParamKind::Type { .. } = param.kind else { continue };279                for bound in &param.bounds {280                    let ast::GenericBound::Trait(poly_trait_ref) = bound else { continue };281                    record_bound(this, param.ident.name, poly_trait_ref);282                }283            }284285            for predicate in &generics.where_clause.predicates {286                let ast::WherePredicateKind::BoundPredicate(where_bound) = &predicate.kind else {287                    continue;288                };289290                let ast::TyKind::Path(None, bounded_path) = &where_bound.bounded_ty.kind else {291                    continue;292                };293                let [ast::PathSegment { ident, args: None, .. }] = &bounded_path.segments[..]294                else {295                    continue;296                };297298                // Only suggest for bounds that are explicitly on an in-scope type parameter.299                let Some(partial_res) = this.r.partial_res_map.get(&where_bound.bounded_ty.id)300                else {301                    continue;302                };303                if !matches!(partial_res.full_res(), Some(Res::Def(DefKind::TyParam, _))) {304                    continue;305                }306307                for bound in &where_bound.bounds {308                    let ast::GenericBound::Trait(poly_trait_ref) = bound else { continue };309                    record_bound(this, ident.name, poly_trait_ref);310                }311            }312        };313314        if let Some(item) = self.diag_metadata.current_item315            && let Some(generics) = item.kind.generics()316        {317            record_from_generics(self, generics);318        }319320        if let Some(item) = self.diag_metadata.current_item321            && matches!(item.kind, ItemKind::Impl(..))322            && let Some(assoc) = self.diag_metadata.current_impl_item323        {324            let generics = match &assoc.kind {325                AssocItemKind::Const(box ast::ConstItem { generics, .. })326                | AssocItemKind::Fn(box ast::Fn { generics, .. })327                | AssocItemKind::Type(box ast::TyAlias { generics, .. }) => Some(generics),328                AssocItemKind::Delegation(..)329                | AssocItemKind::MacCall(..)330                | AssocItemKind::DelegationMac(..) => None,331            };332            if let Some(generics) = generics {333                record_from_generics(self, generics);334            }335        }336337        let mut suggestions: FxIndexSet<String> = FxIndexSet::default();338        for (ty_param, traits) in matching_bounds {339            let ty_param = ty_param.to_ident_string();340            let trait_paths_len: usize = traits.values().map(|(_, paths)| paths.len()).sum();341            if traits.len() == 1 && trait_paths_len == 1 {342                let assoc_type_def_id = traits.values().next().unwrap().0;343                let assoc_segment = format!(344                    "{}{}",345                    assoc_name,346                    self.r.item_required_generic_args_suggestion(assoc_type_def_id)347                );348                suggestions.insert(format!("{ty_param}::{assoc_segment}"));349            } else {350                for (assoc_type_def_id, trait_paths) in traits.into_values() {351                    let assoc_segment = format!(352                        "{}{}",353                        assoc_name,354                        self.r.item_required_generic_args_suggestion(assoc_type_def_id)355                    );356                    for trait_path in trait_paths {357                        suggestions358                            .insert(format!("<{ty_param} as {trait_path}>::{assoc_segment}"));359                    }360                }361            }362        }363364        if suggestions.is_empty() {365            return false;366        }367368        let mut suggestions: Vec<String> = suggestions.into_iter().collect();369        suggestions.sort();370371        err.span_suggestions_with_style(372            ident_span,373            "you might have meant to use an associated type of the same name",374            suggestions,375            Applicability::MaybeIncorrect,376            SuggestionStyle::ShowAlways,377        );378379        true380    }381382    fn make_base_error(383        &mut self,384        path: &[Segment],385        span: Span,386        source: PathSource<'_, 'ast, 'ra>,387        res: Option<Res>,388    ) -> BaseError {389        // Make the base error.390        let mut expected = source.descr_expected();391        let path_str = Segment::names_to_string(path);392        let item_str = path.last().unwrap().ident;393394        if let Some(res) = res {395            BaseError {396                msg: format!("expected {}, found {} `{}`", expected, res.descr(), path_str),397                fallback_label: format!("not a {expected}"),398                span,399                span_label: match res {400                    Res::Def(DefKind::TyParam, def_id) => {401                        Some((self.r.def_span(def_id), "found this type parameter"))402                    }403                    _ => None,404                },405                could_be_expr: match res {406                    Res::Def(DefKind::Fn, _) => {407                        // Verify whether this is a fn call or an Fn used as a type.408                        self.r409                            .tcx410                            .sess411                            .source_map()412                            .span_to_snippet(span)413                            .is_ok_and(|snippet| snippet.ends_with(')'))414                    }415                    Res::Def(416                        DefKind::Ctor(..)417                        | DefKind::AssocFn418                        | DefKind::Const { .. }419                        | DefKind::AssocConst { .. },420                        _,421                    )422                    | Res::SelfCtor(_)423                    | Res::PrimTy(_)424                    | Res::Local(_) => true,425                    _ => false,426                },427                suggestion: None,428                module: None,429            }430        } else {431            let mut span_label = None;432            let item_ident = path.last().unwrap().ident;433            let item_span = item_ident.span;434            let (mod_prefix, mod_str, module, suggestion) = if path.len() == 1 {435                debug!(?self.diag_metadata.current_impl_items);436                debug!(?self.diag_metadata.current_function);437                let suggestion = if self.current_trait_ref.is_none()438                    && let Some((fn_kind, _)) = self.diag_metadata.current_function439                    && let Some(FnCtxt::Assoc(_)) = fn_kind.ctxt()440                    && let FnKind::Fn(_, _, ast::Fn { sig, .. }) = fn_kind441                    && let Some(items) = self.diag_metadata.current_impl_items442                    && let Some(item) = items.iter().find(|i| {443                        i.kind.ident().is_some_and(|ident| {444                            // Don't suggest if the item is in Fn signature arguments (#112590).445                            ident.name == item_str.name && !sig.span.contains(item_span)446                        })447                    }) {448                    let sp = item_span.shrink_to_lo();449450                    // Account for `Foo { field }` when suggesting `self.field` so we result on451                    // `Foo { field: self.field }`.452                    let field = match source {453                        PathSource::Expr(Some(Expr { kind: ExprKind::Struct(expr), .. })) => {454                            expr.fields.iter().find(|f| f.ident == item_ident)455                        }456                        _ => None,457                    };458                    let pre = if let Some(field) = field459                        && field.is_shorthand460                    {461                        format!("{item_ident}: ")462                    } else {463                        String::new()464                    };465                    // Ensure we provide a structured suggestion for an assoc fn only for466                    // expressions that are actually a fn call.467                    let is_call = match field {468                        Some(ast::ExprField { expr, .. }) => {469                            matches!(expr.kind, ExprKind::Call(..))470                        }471                        _ => matches!(472                            source,473                            PathSource::Expr(Some(Expr { kind: ExprKind::Call(..), .. })),474                        ),475                    };476477                    match &item.kind {478                        AssocItemKind::Fn(fn_)479                            if (!sig.decl.has_self() || !is_call) && fn_.sig.decl.has_self() =>480                        {481                            // Ensure that we only suggest `self.` if `self` is available,482                            // you can't call `fn foo(&self)` from `fn bar()` (#115992).483                            // We also want to mention that the method exists.484                            span_label = Some((485                                fn_.ident.span,486                                "a method by that name is available on `Self` here",487                            ));488                            None489                        }490                        AssocItemKind::Fn(fn_) if !fn_.sig.decl.has_self() && !is_call => {491                            span_label = Some((492                                fn_.ident.span,493                                "an associated function by that name is available on `Self` here",494                            ));495                            None496                        }497                        AssocItemKind::Fn(fn_) if fn_.sig.decl.has_self() => {498                            Some((sp, "consider using the method on `Self`", format!("{pre}self.")))499                        }500                        AssocItemKind::Fn(_) => Some((501                            sp,502                            "consider using the associated function on `Self`",503                            format!("{pre}Self::"),504                        )),505                        AssocItemKind::Const(..) => Some((506                            sp,507                            "consider using the associated constant on `Self`",508                            format!("{pre}Self::"),509                        )),510                        _ => None,511                    }512                } else {513                    None514                };515                (String::new(), "this scope".to_string(), None, suggestion)516            } else if path.len() == 2 && path[0].ident.name == kw::PathRoot {517                if self.r.tcx.sess.edition() > Edition::Edition2015 {518                    // In edition 2018 onwards, the `::foo` syntax may only pull from the extern prelude519                    // which overrides all other expectations of item type520                    expected = "crate";521                    (String::new(), "the list of imported crates".to_string(), None, None)522                } else {523                    (524                        String::new(),525                        "the crate root".to_string(),526                        Some(CRATE_DEF_ID.to_def_id()),527                        None,528                    )529                }530            } else if path.len() == 2 && path[0].ident.name == kw::Crate {531                (String::new(), "the crate root".to_string(), Some(CRATE_DEF_ID.to_def_id()), None)532            } else {533                let mod_path = &path[..path.len() - 1];534                let mod_res = self.resolve_path(mod_path, Some(TypeNS), None, source);535                let mod_prefix = match mod_res {536                    PathResult::Module(ModuleOrUniformRoot::Module(module)) => module.res(),537                    _ => None,538                };539540                let module_did = mod_prefix.as_ref().and_then(Res::mod_def_id);541542                let mod_prefix =543                    mod_prefix.map_or_else(String::new, |res| format!("{} ", res.descr()));544                (mod_prefix, format!("`{}`", Segment::names_to_string(mod_path)), module_did, None)545            };546547            let (fallback_label, suggestion) = if path_str == "async"548                && expected.starts_with("struct")549            {550                ("`async` blocks are only allowed in Rust 2018 or later".to_string(), suggestion)551            } else {552                // check if we are in situation of typo like `True` instead of `true`.553                let override_suggestion =554                    if ["true", "false"].contains(&item_str.to_string().to_lowercase().as_str()) {555                        let item_typo = item_str.to_string().to_lowercase();556                        Some((item_span, "you may want to use a bool value instead", item_typo))557                    // FIXME(vincenzopalazzo): make the check smarter,558                    // and maybe expand with levenshtein distance checks559                    } else if item_str.as_str() == "printf" {560                        Some((561                            item_span,562                            "you may have meant to use the `print` macro",563                            "print!".to_owned(),564                        ))565                    } else {566                        suggestion567                    };568                (format!("not found in {mod_str}"), override_suggestion)569            };570571            BaseError {572                msg: format!("cannot find {expected} `{item_str}` in {mod_prefix}{mod_str}"),573                fallback_label,574                span: item_span,575                span_label,576                could_be_expr: false,577                suggestion,578                module,579            }580        }581    }582583    /// Try to suggest for a module path that cannot be resolved.584    /// Such as `fmt::Debug` where `fmt` is not resolved without importing,585    /// here we search with `lookup_import_candidates` for a module named `fmt`586    /// with `TypeNS` as namespace.587    ///588    /// We need a separate function here because we won't suggest for a path with single segment589    /// and we won't change `SourcePath` api `is_expected` to match `Type` with `DefKind::Mod`590    pub(crate) fn smart_resolve_partial_mod_path_errors(591        &mut self,592        prefix_path: &[Segment],593        following_seg: Option<&Segment>,594    ) -> Vec<ImportSuggestion> {595        if let Some(segment) = prefix_path.last()596            && let Some(following_seg) = following_seg597        {598            let candidates = self.r.lookup_import_candidates(599                segment.ident,600                Namespace::TypeNS,601                &self.parent_scope,602                &|res: Res| matches!(res, Res::Def(DefKind::Mod, _)),603            );604            // double check next seg is valid605            candidates606                .into_iter()607                .filter(|candidate| {608                    if let Some(def_id) = candidate.did609                        && let Some(module) = self.r.get_module(def_id)610                    {611                        Some(def_id) != self.parent_scope.module.opt_def_id()612                            && self613                                .r614                                .resolutions(module)615                                .borrow()616                                .iter()617                                .any(|(key, _r)| key.ident.name == following_seg.ident.name)618                    } else {619                        false620                    }621                })622                .collect::<Vec<_>>()623        } else {624            Vec::new()625        }626    }627628    /// Handles error reporting for `smart_resolve_path_fragment` function.629    /// Creates base error and amends it with one short label and possibly some longer helps/notes.630    #[tracing::instrument(skip(self), level = "debug")]631    pub(crate) fn smart_resolve_report_errors(632        &mut self,633        path: &[Segment],634        following_seg: Option<&Segment>,635        span: Span,636        source: PathSource<'_, 'ast, 'ra>,637        res: Option<Res>,638        qself: Option<&QSelf>,639    ) -> (Diag<'tcx>, Vec<ImportSuggestion>) {640        debug!(?res, ?source);641        let base_error = self.make_base_error(path, span, source, res);642643        let code = source.error_code(res.is_some());644        let mut err = self.r.dcx().struct_span_err(base_error.span, base_error.msg.clone());645        err.code(code);646647        // Try to get the span of the identifier within the path's syntax context648        // (if that's different).649        if let Some(within_macro_span) =650            base_error.span.within_macro(span, self.r.tcx.sess.source_map())651        {652            err.span_label(within_macro_span, "due to this macro variable");653        }654655        self.detect_missing_binding_available_from_pattern(&mut err, path, following_seg);656        self.suggest_at_operator_in_slice_pat_with_range(&mut err, path);657        self.suggest_range_struct_destructuring(&mut err, path, source);658        self.suggest_swapping_misplaced_self_ty_and_trait(&mut err, source, res, base_error.span);659660        if let Some((span, label)) = base_error.span_label {661            err.span_label(span, label);662        }663664        if let Some(ref sugg) = base_error.suggestion {665            err.span_suggestion_verbose(sugg.0, sugg.1, &sugg.2, Applicability::MaybeIncorrect);666        }667668        self.suggest_changing_type_to_const_param(&mut err, res, source, path, following_seg, span);669        self.explain_functions_in_pattern(&mut err, res, source);670671        if self.suggest_pattern_match_with_let(&mut err, source, span) {672            // Fallback label.673            err.span_label(base_error.span, base_error.fallback_label);674            return (err, Vec::new());675        }676677        self.suggest_self_or_self_ref(&mut err, path, span);678        self.detect_assoc_type_constraint_meant_as_path(&mut err, &base_error);679        self.detect_rtn_with_fully_qualified_path(680            &mut err,681            path,682            following_seg,683            span,684            source,685            res,686            qself,687        );688        if self.suggest_self_ty(&mut err, source, path, span)689            || self.suggest_self_value(&mut err, source, path, span)690        {691            return (err, Vec::new());692        }693694        if let Some((did, item)) = self.lookup_doc_alias_name(path, source.namespace()) {695            let item_name = item.name;696            let suggestion_name = self.r.tcx.item_name(did);697            err.span_suggestion(698                item.span,699                format!("`{suggestion_name}` has a name defined in the doc alias attribute as `{item_name}`"),700                    suggestion_name,701                    Applicability::MaybeIncorrect702                );703704            return (err, Vec::new());705        };706707        let (found, suggested_candidates, mut candidates) = self.try_lookup_name_relaxed(708            &mut err,709            source,710            path,711            following_seg,712            span,713            res,714            &base_error,715        );716        if found {717            return (err, candidates);718        }719720        if self.suggest_shadowed(&mut err, source, path, following_seg, span) {721            // if there is already a shadowed name, don'suggest candidates for importing722            candidates.clear();723        }724725        let mut fallback = self.suggest_trait_and_bounds(&mut err, source, res, span, &base_error);726        fallback |= self.suggest_typo(727            &mut err,728            source,729            path,730            following_seg,731            span,732            &base_error,733            suggested_candidates,734        );735736        if fallback {737            // Fallback label.738            err.span_label(base_error.span, base_error.fallback_label);739        }740        self.err_code_special_cases(&mut err, source, path, span);741742        let module = base_error.module.unwrap_or_else(|| CRATE_DEF_ID.to_def_id());743        self.r.find_cfg_stripped(&mut err, &path.last().unwrap().ident.name, module);744745        (err, candidates)746    }747748    fn detect_rtn_with_fully_qualified_path(749        &self,750        err: &mut Diag<'_>,751        path: &[Segment],752        following_seg: Option<&Segment>,753        span: Span,754        source: PathSource<'_, '_, '_>,755        res: Option<Res>,756        qself: Option<&QSelf>,757    ) {758        if let Some(Res::Def(DefKind::AssocFn, _)) = res759            && let PathSource::TraitItem(TypeNS, _) = source760            && let None = following_seg761            && let Some(qself) = qself762            && let TyKind::Path(None, ty_path) = &qself.ty.kind763            && ty_path.segments.len() == 1764            && self.diag_metadata.current_where_predicate.is_some()765        {766            err.span_suggestion_verbose(767                span,768                "you might have meant to use the return type notation syntax",769                format!("{}::{}(..)", ty_path.segments[0].ident, path[path.len() - 1].ident),770                Applicability::MaybeIncorrect,771            );772        }773    }774775    fn detect_assoc_type_constraint_meant_as_path(776        &self,777        err: &mut Diag<'_>,778        base_error: &BaseError,779    ) {780        let Some(ty) = self.diag_metadata.current_type_path else {781            return;782        };783        let TyKind::Path(_, path) = &ty.kind else {784            return;785        };786        for segment in &path.segments {787            let Some(params) = &segment.args else {788                continue;789            };790            let ast::GenericArgs::AngleBracketed(params) = params.deref() else {791                continue;792            };793            for param in &params.args {794                let ast::AngleBracketedArg::Constraint(constraint) = param else {795                    continue;796                };797                let ast::AssocItemConstraintKind::Bound { bounds } = &constraint.kind else {798                    continue;799                };800                for bound in bounds {801                    let ast::GenericBound::Trait(trait_ref) = bound else {802                        continue;803                    };804                    if trait_ref.modifiers == ast::TraitBoundModifiers::NONE805                        && base_error.span == trait_ref.span806                    {807                        err.span_suggestion_verbose(808                            constraint.ident.span.between(trait_ref.span),809                            "you might have meant to write a path instead of an associated type bound",810                            "::",811                            Applicability::MachineApplicable,812                        );813                    }814                }815            }816        }817    }818819    fn suggest_self_or_self_ref(&mut self, err: &mut Diag<'_>, path: &[Segment], span: Span) {820        if !self.self_type_is_available() {821            return;822        }823        let Some(path_last_segment) = path.last() else { return };824        let item_str = path_last_segment.ident;825        // Emit help message for fake-self from other languages (e.g., `this` in JavaScript).826        if ["this", "my"].contains(&item_str.as_str()) {827            err.span_suggestion_short(828                span,829                "you might have meant to use `self` here instead",830                "self",831                Applicability::MaybeIncorrect,832            );833            if !self.self_value_is_available(path[0].ident.span) {834                if let Some((FnKind::Fn(_, _, ast::Fn { sig, .. }), fn_span)) =835                    &self.diag_metadata.current_function836                {837                    let (span, sugg) = if let Some(param) = sig.decl.inputs.get(0) {838                        (param.span.shrink_to_lo(), "&self, ")839                    } else {840                        (841                            self.r842                                .tcx843                                .sess844                                .source_map()845                                .span_through_char(*fn_span, '(')846                                .shrink_to_hi(),847                            "&self",848                        )849                    };850                    err.span_suggestion_verbose(851                        span,852                        "if you meant to use `self`, you are also missing a `self` receiver \853                         argument",854                        sugg,855                        Applicability::MaybeIncorrect,856                    );857                }858            }859        }860    }861862    fn try_lookup_name_relaxed(863        &mut self,864        err: &mut Diag<'_>,865        source: PathSource<'_, '_, '_>,866        path: &[Segment],867        following_seg: Option<&Segment>,868        span: Span,869        res: Option<Res>,870        base_error: &BaseError,871    ) -> (bool, FxHashSet<String>, Vec<ImportSuggestion>) {872        let span = match following_seg {873            Some(_) if path[0].ident.span.eq_ctxt(path[path.len() - 1].ident.span) => {874                // The path `span` that comes in includes any following segments, which we don't875                // want to replace in the suggestions.876                path[0].ident.span.to(path[path.len() - 1].ident.span)877            }878            _ => span,879        };880        let mut suggested_candidates = FxHashSet::default();881        // Try to lookup name in more relaxed fashion for better error reporting.882        let ident = path.last().unwrap().ident;883        let is_expected = &|res| source.is_expected(res);884        let ns = source.namespace();885        let is_enum_variant = &|res| matches!(res, Res::Def(DefKind::Variant, _));886        let path_str = Segment::names_to_string(path);887        let ident_span = path.last().map_or(span, |ident| ident.ident.span);888        let mut candidates = self889            .r890            .lookup_import_candidates(ident, ns, &self.parent_scope, is_expected)891            .into_iter()892            .filter(|ImportSuggestion { did, .. }| {893                match (did, res.and_then(|res| res.opt_def_id())) {894                    (Some(suggestion_did), Some(actual_did)) => *suggestion_did != actual_did,895                    _ => true,896                }897            })898            .collect::<Vec<_>>();899        // Try to filter out intrinsics candidates, as long as we have900        // some other candidates to suggest.901        let intrinsic_candidates: Vec<_> = candidates902            .extract_if(.., |sugg| {903                let path = path_names_to_string(&sugg.path);904                path.starts_with("core::intrinsics::") || path.starts_with("std::intrinsics::")905            })906            .collect();907        if candidates.is_empty() {908            // Put them back if we have no more candidates to suggest...909            candidates = intrinsic_candidates;910        }911        let crate_def_id = CRATE_DEF_ID.to_def_id();912        if candidates.is_empty() && is_expected(Res::Def(DefKind::Enum, crate_def_id)) {913            let mut enum_candidates: Vec<_> = self914                .r915                .lookup_import_candidates(ident, ns, &self.parent_scope, is_enum_variant)916                .into_iter()917                .map(|suggestion| import_candidate_to_enum_paths(&suggestion))918                .filter(|(_, enum_ty_path)| !enum_ty_path.starts_with("std::prelude::"))919                .collect();920            if !enum_candidates.is_empty() {921                enum_candidates.sort();922923                // Contextualize for E0425 "cannot find type", but don't belabor the point924                // (that it's a variant) for E0573 "expected type, found variant".925                let preamble = if res.is_none() {926                    let others = match enum_candidates.len() {927                        1 => String::new(),928                        2 => " and 1 other".to_owned(),929                        n => format!(" and {n} others"),930                    };931                    format!("there is an enum variant `{}`{}; ", enum_candidates[0].0, others)932                } else {933                    String::new()934                };935                let msg = format!("{preamble}try using the variant's enum");936937                suggested_candidates.extend(938                    enum_candidates939                        .iter()940                        .map(|(_variant_path, enum_ty_path)| enum_ty_path.clone()),941                );942                err.span_suggestions(943                    span,944                    msg,945                    enum_candidates.into_iter().map(|(_variant_path, enum_ty_path)| enum_ty_path),946                    Applicability::MachineApplicable,947                );948            }949        }950951        // Try finding a suitable replacement.952        let typo_sugg = self953            .lookup_typo_candidate(path, following_seg, source.namespace(), is_expected)954            .to_opt_suggestion()955            .filter(|sugg| !suggested_candidates.contains(sugg.candidate.as_str()));956        if let [segment] = path957            && !matches!(source, PathSource::Delegation)958            && self.self_type_is_available()959        {960            if let Some(candidate) =961                self.lookup_assoc_candidate(ident, ns, is_expected, source.is_call())962            {963                let self_is_available = self.self_value_is_available(segment.ident.span);964                // Account for `Foo { field }` when suggesting `self.field` so we result on965                // `Foo { field: self.field }`.966                let pre = match source {967                    PathSource::Expr(Some(Expr { kind: ExprKind::Struct(expr), .. }))968                        if expr969                            .fields970                            .iter()971                            .any(|f| f.ident == segment.ident && f.is_shorthand) =>972                    {973                        format!("{path_str}: ")974                    }975                    _ => String::new(),976                };977                match candidate {978                    AssocSuggestion::Field(field_span) => {979                        if self_is_available {980                            let source_map = self.r.tcx.sess.source_map();981                            let field_is_format_named_arg = matches!(982                                span.desugaring_kind(),983                                Some(DesugaringKind::FormatLiteral { .. })984                            ) && source_map985                                .span_to_source(span, |s, start, _| {986                                    Ok(s.get(start.saturating_sub(1)..start) == Some("{"))987                                })988                                .unwrap_or(false);989                            if field_is_format_named_arg {990                                err.help(991                                    format!("you might have meant to use the available field in a format string: `\"{{}}\", self.{}`", segment.ident.name),992                                );993                            } else {994                                err.span_suggestion_verbose(995                                    span.shrink_to_lo(),996                                    "you might have meant to use the available field",997                                    format!("{pre}self."),998                                    Applicability::MaybeIncorrect,999                                );1000                            }1001                        } else {1002                            err.span_label(field_span, "a field by that name exists in `Self`");1003                        }1004                    }1005                    AssocSuggestion::MethodWithSelf { called } if self_is_available => {1006                        let msg = if called {1007                            "you might have meant to call the method"1008                        } else {1009                            "you might have meant to refer to the method"1010                        };1011                        err.span_suggestion_verbose(1012                            span.shrink_to_lo(),1013                            msg,1014                            "self.",1015                            Applicability::MachineApplicable,1016                        );1017                    }1018                    AssocSuggestion::MethodWithSelf { .. }1019                    | AssocSuggestion::AssocFn { .. }1020                    | AssocSuggestion::AssocConst1021                    | AssocSuggestion::AssocType => {1022                        err.span_suggestion_verbose(1023                            span.shrink_to_lo(),1024                            format!("you might have meant to {}", candidate.action()),1025                            "Self::",1026                            Applicability::MachineApplicable,1027                        );1028                    }1029                }1030                self.r.add_typo_suggestion(err, typo_sugg, ident_span);1031                return (true, suggested_candidates, candidates);1032            }10331034            // If the first argument in call is `self` suggest calling a method.1035            if let Some((call_span, args_span)) = self.call_has_self_arg(source) {1036                let mut args_snippet = String::new();1037                if let Some(args_span) = args_span1038                    && let Ok(snippet) = self.r.tcx.sess.source_map().span_to_snippet(args_span)1039                {1040                    args_snippet = snippet;1041                }10421043                if let Some(Res::Def(DefKind::Struct, def_id)) = res {1044                    if let Some(ctor) = self.r.struct_ctor(def_id)1045                        && ctor.has_private_fields(self.parent_scope.module, self.r)1046                    {1047                        if matches!(1048                            ctor.res,1049                            Res::Def(DefKind::Ctor(CtorOf::Struct, CtorKind::Fn), _)1050                        ) {1051                            self.update_err_for_private_tuple_struct_fields(err, &source, def_id);1052                        }1053                        err.note("constructor is not visible here due to private fields");1054                    }1055                } else {1056                    err.span_suggestion(1057                        call_span,1058                        format!("try calling `{ident}` as a method"),1059                        format!("self.{path_str}({args_snippet})"),1060                        Applicability::MachineApplicable,1061                    );1062                }10631064                return (true, suggested_candidates, candidates);1065            }1066        }10671068        // Try context-dependent help if relaxed lookup didn't work.1069        if let Some(res) = res {1070            if self.smart_resolve_context_dependent_help(1071                err,1072                span,1073                source,1074                path,1075                res,1076                &path_str,1077                &base_error.fallback_label,1078            ) {1079                // We do this to avoid losing a secondary span when we override the main error span.1080                self.r.add_typo_suggestion(err, typo_sugg, ident_span);1081                return (true, suggested_candidates, candidates);1082            }1083        }10841085        // Try to find in last block rib1086        if let Some(rib) = &self.last_block_rib {1087            for (ident, &res) in &rib.bindings {1088                if let Res::Local(_) = res1089                    && path.len() == 11090                    && ident.span.eq_ctxt(path[0].ident.span)1091                    && ident.name == path[0].ident.name1092                {1093                    err.span_help(1094                        ident.span,1095                        format!("the binding `{path_str}` is available in a different scope in the same function"),1096                    );1097                    return (true, suggested_candidates, candidates);1098                }1099            }1100        }11011102        if candidates.is_empty() {1103            candidates = self.smart_resolve_partial_mod_path_errors(path, following_seg);1104        }11051106        (false, suggested_candidates, candidates)1107    }11081109    fn lookup_doc_alias_name(&mut self, path: &[Segment], ns: Namespace) -> Option<(DefId, Ident)> {1110        let find_doc_alias_name = |r: &mut Resolver<'ra, '_>, m: Module<'ra>, item_name: Symbol| {1111            for resolution in r.resolutions(m).borrow().values() {1112                let Some(did) =1113                    resolution.borrow().best_decl().and_then(|binding| binding.res().opt_def_id())1114                else {1115                    continue;1116                };1117                if did.is_local() {1118                    // We don't record the doc alias name in the local crate1119                    // because the people who write doc alias are usually not1120                    // confused by them.1121                    continue;1122                }1123                if let Some(d) = hir::find_attr!(r.tcx, did, Doc(d) => d)1124                    && d.aliases.contains_key(&item_name)1125                {1126                    return Some(did);1127                }1128            }1129            None1130        };11311132        if path.len() == 1 {1133            for rib in self.ribs[ns].iter().rev() {1134                let item = path[0].ident;1135                if let RibKind::Module(module) | RibKind::Block(Some(module)) = rib.kind1136                    && let Some(did) = find_doc_alias_name(self.r, module.to_module(), item.name)1137                {1138                    return Some((did, item));1139                }1140            }1141        } else {1142            // Finds to the last resolved module item in the path1143            // and searches doc aliases within that module.1144            //1145            // Example: For the path `a::b::last_resolved::not_exist::c::d`,1146            // we will try to find any item has doc aliases named `not_exist`1147            // in `last_resolved` module.1148            //1149            // - Use `skip(1)` because the final segment must remain unresolved.1150            for (idx, seg) in path.iter().enumerate().rev().skip(1) {1151                let Some(id) = seg.id else {1152                    continue;1153                };1154                let Some(res) = self.r.partial_res_map.get(&id) else {1155                    continue;1156                };1157                if let Res::Def(DefKind::Mod, module) = res.expect_full_res()1158                    && let module = self.r.expect_module(module)1159                    && let item = path[idx + 1].ident1160                    && let Some(did) = find_doc_alias_name(self.r, module, item.name)1161                {1162                    return Some((did, item));1163                }1164                break;1165            }1166        }1167        None1168    }11691170    fn suggest_trait_and_bounds(1171        &self,1172        err: &mut Diag<'_>,1173        source: PathSource<'_, '_, '_>,1174        res: Option<Res>,1175        span: Span,1176        base_error: &BaseError,1177    ) -> bool {1178        let is_macro =1179            base_error.span.from_expansion() && base_error.span.desugaring_kind().is_none();1180        let mut fallback = false;11811182        if let (1183            PathSource::Trait(AliasPossibility::Maybe),1184            Some(Res::Def(DefKind::Struct | DefKind::Enum | DefKind::Union, _)),1185            false,1186        ) = (source, res, is_macro)1187            && let Some(bounds @ [first_bound, .., last_bound]) =1188                self.diag_metadata.current_trait_object1189        {1190            fallback = true;1191            let spans: Vec<Span> = bounds1192                .iter()1193                .map(|bound| bound.span())1194                .filter(|&sp| sp != base_error.span)1195                .collect();11961197            let start_span = first_bound.span();1198            // `end_span` is the end of the poly trait ref (Foo + 'baz + Bar><)1199            let end_span = last_bound.span();1200            // `last_bound_span` is the last bound of the poly trait ref (Foo + >'baz< + Bar)1201            let last_bound_span = spans.last().cloned().unwrap();1202            let mut multi_span: MultiSpan = spans.clone().into();1203            for sp in spans {1204                let msg = if sp == last_bound_span {1205                    format!(1206                        "...because of {these} bound{s}",1207                        these = pluralize!("this", bounds.len() - 1),1208                        s = pluralize!(bounds.len() - 1),1209                    )1210                } else {1211                    String::new()1212                };1213                multi_span.push_span_label(sp, msg);1214            }1215            multi_span.push_span_label(base_error.span, "expected this type to be a trait...");1216            err.span_help(1217                multi_span,1218                "`+` is used to constrain a \"trait object\" type with lifetimes or \1219                        auto-traits; structs and enums can't be bound in that way",1220            );1221            if bounds.iter().all(|bound| match bound {1222                ast::GenericBound::Outlives(_) | ast::GenericBound::Use(..) => true,1223                ast::GenericBound::Trait(tr) => tr.span == base_error.span,1224            }) {1225                let mut sugg = vec![];1226                if base_error.span != start_span {1227                    sugg.push((start_span.until(base_error.span), String::new()));1228                }1229                if base_error.span != end_span {1230                    sugg.push((base_error.span.shrink_to_hi().to(end_span), String::new()));1231                }12321233                err.multipart_suggestion(1234                    "if you meant to use a type and not a trait here, remove the bounds",1235                    sugg,1236                    Applicability::MaybeIncorrect,1237                );1238            }1239        }12401241        fallback |= self.restrict_assoc_type_in_where_clause(span, err);1242        fallback1243    }12441245    fn suggest_typo(1246        &mut self,1247        err: &mut Diag<'_>,1248        source: PathSource<'_, 'ast, 'ra>,1249        path: &[Segment],1250        following_seg: Option<&Segment>,1251        span: Span,1252        base_error: &BaseError,1253        suggested_candidates: FxHashSet<String>,1254    ) -> bool {1255        let is_expected = &|res| source.is_expected(res);1256        let ident_span = path.last().map_or(span, |ident| ident.ident.span);12571258        // Prefer suggestions based on associated types from in-scope bounds (e.g. `T::Item`)1259        // over purely edit-distance-based identifier suggestions.1260        // Otherwise suggestions could be verbose.1261        if self.suggest_assoc_type_from_bounds(err, source, path, ident_span) {1262            return false;1263        }12641265        let typo_sugg =1266            self.lookup_typo_candidate(path, following_seg, source.namespace(), is_expected);1267        let mut fallback = false;1268        let typo_sugg = typo_sugg1269            .to_opt_suggestion()1270            .filter(|sugg| !suggested_candidates.contains(sugg.candidate.as_str()));1271        if !self.r.add_typo_suggestion(err, typo_sugg, ident_span) {1272            fallback = true;1273            match self.diag_metadata.current_let_binding {1274                Some((pat_sp, Some(ty_sp), None))1275                    if ty_sp.contains(base_error.span) && base_error.could_be_expr =>1276                {1277                    err.span_suggestion_verbose(1278                        pat_sp.between(ty_sp),1279                        "use `=` if you meant to assign",1280                        " = ",1281                        Applicability::MaybeIncorrect,1282                    );1283                }1284                _ => {}1285            }12861287            // If the trait has a single item (which wasn't matched by the algorithm), suggest it1288            let suggestion = self.get_single_associated_item(path, &source, is_expected);1289            self.r.add_typo_suggestion(err, suggestion, ident_span);1290        }12911292        if self.let_binding_suggestion(err, ident_span) {1293            fallback = false;1294        }12951296        fallback1297    }12981299    fn suggest_shadowed(1300        &mut self,1301        err: &mut Diag<'_>,1302        source: PathSource<'_, '_, '_>,1303        path: &[Segment],1304        following_seg: Option<&Segment>,1305        span: Span,1306    ) -> bool {1307        let is_expected = &|res| source.is_expected(res);1308        let typo_sugg =1309            self.lookup_typo_candidate(path, following_seg, source.namespace(), is_expected);1310        let is_in_same_file = &|sp1, sp2| {1311            let source_map = self.r.tcx.sess.source_map();1312            let file1 = source_map.span_to_filename(sp1);1313            let file2 = source_map.span_to_filename(sp2);1314            file1 == file21315        };1316        // print 'you might have meant' if the candidate is (1) is a shadowed name with1317        // accessible definition and (2) either defined in the same crate as the typo1318        // (could be in a different file) or introduced in the same file as the typo1319        // (could belong to a different crate)1320        if let TypoCandidate::Shadowed(res, Some(sugg_span)) = typo_sugg1321            && res.opt_def_id().is_some_and(|id| id.is_local() || is_in_same_file(span, sugg_span))1322        {1323            err.span_label(1324                sugg_span,1325                format!("you might have meant to refer to this {}", res.descr()),1326            );1327            return true;1328        }1329        false1330    }13311332    fn err_code_special_cases(1333        &mut self,1334        err: &mut Diag<'_>,1335        source: PathSource<'_, '_, '_>,1336        path: &[Segment],1337        span: Span,1338    ) {1339        if let Some(err_code) = err.code {1340            if err_code == E0425 {1341                for label_rib in &self.label_ribs {1342                    for (label_ident, node_id) in &label_rib.bindings {1343                        let ident = path.last().unwrap().ident;1344                        if format!("'{ident}") == label_ident.to_string() {1345                            err.span_label(label_ident.span, "a label with a similar name exists");1346                            if let PathSource::Expr(Some(Expr {1347                                kind: ExprKind::Break(None, Some(_)),1348                                ..1349                            })) = source1350                            {1351                                err.span_suggestion(1352                                    span,1353                                    "use the similarly named label",1354                                    label_ident.name,1355                                    Applicability::MaybeIncorrect,1356                                );1357                                // Do not lint against unused label when we suggest them.1358                                self.diag_metadata.unused_labels.swap_remove(node_id);1359                            }1360                        }1361                    }1362                }13631364                self.suggest_ident_hidden_by_hygiene(err, path, span);1365                // cannot find type in this scope1366                if let Some(correct) = Self::likely_rust_type(path) {1367                    err.span_suggestion(1368                        span,1369                        "perhaps you intended to use this type",1370                        correct,1371                        Applicability::MaybeIncorrect,1372                    );1373                }1374            }1375        }1376    }13771378    fn suggest_ident_hidden_by_hygiene(&self, err: &mut Diag<'_>, path: &[Segment], span: Span) {1379        let [segment] = path else { return };13801381        let ident = segment.ident;1382        let callsite_span = span.source_callsite();1383        for rib in self.ribs[ValueNS].iter().rev() {1384            for (binding_ident, _) in &rib.bindings {1385                // Case 1: the identifier is defined in the same scope as the macro is called1386                if binding_ident.name == ident.name1387                    && !binding_ident.span.eq_ctxt(span)1388                    && !binding_ident.span.from_expansion()1389                    && binding_ident.span.lo() < callsite_span.lo()1390                {1391                    err.span_help(1392                        binding_ident.span,1393                        "an identifier with the same name exists, but is not accessible due to macro hygiene",1394                    );1395                    return;1396                }13971398                // Case 2: the identifier is defined in a macro call in the same scope1399                if binding_ident.name == ident.name1400                    && binding_ident.span.from_expansion()1401                    && binding_ident.span.source_callsite().eq_ctxt(callsite_span)1402                    && binding_ident.span.source_callsite().lo() < callsite_span.lo()1403                {1404                    err.span_help(1405                        binding_ident.span,1406                        "an identifier with the same name is defined here, but is not accessible due to macro hygiene",1407                    );1408                    return;1409                }1410            }1411        }1412    }14131414    /// Emit special messages for unresolved `Self` and `self`.1415    fn suggest_self_ty(1416        &self,1417        err: &mut Diag<'_>,1418        source: PathSource<'_, '_, '_>,1419        path: &[Segment],1420        span: Span,1421    ) -> bool {1422        if !is_self_type(path, source.namespace()) {1423            return false;1424        }1425        err.code(E0411);1426        err.span_label(span, "`Self` is only available in impls, traits, and type definitions");1427        if let Some(item) = self.diag_metadata.current_item1428            && let Some(ident) = item.kind.ident()1429        {1430            err.span_label(1431                ident.span,1432                format!("`Self` not allowed in {} {}", item.kind.article(), item.kind.descr()),1433            );1434        }1435        true1436    }14371438    fn suggest_self_value(1439        &mut self,1440        err: &mut Diag<'_>,1441        source: PathSource<'_, '_, '_>,1442        path: &[Segment],1443        span: Span,1444    ) -> bool {1445        if !is_self_value(path, source.namespace()) {1446            return false;1447        }14481449        debug!("smart_resolve_path_fragment: E0424, source={:?}", source);1450        err.code(E0424);1451        err.span_label(1452            span,1453            match source {1454                PathSource::Pat => {1455                    "`self` value is a keyword and may not be bound to variables or shadowed"1456                }1457                _ => "`self` value is a keyword only available in methods with a `self` parameter",1458            },1459        );14601461        // using `let self` is wrong even if we're not in an associated method or if we're in a macro expansion.1462        // So, we should return early if we're in a pattern, see issue #143134.1463        if matches!(source, PathSource::Pat) {1464            return true;1465        }14661467        let is_assoc_fn = self.self_type_is_available();1468        let self_from_macro = "a `self` parameter, but a macro invocation can only \1469                               access identifiers it receives from parameters";1470        if let Some((fn_kind, fn_span)) = &self.diag_metadata.current_function {1471            // The current function has a `self` parameter, but we were unable to resolve1472            // a reference to `self`. This can only happen if the `self` identifier we1473            // are resolving came from a different hygiene context or a variable binding.1474            // But variable binding error is returned early above.1475            if fn_kind.decl().inputs.get(0).is_some_and(|p| p.is_self()) {1476                err.span_label(*fn_span, format!("this function has {self_from_macro}"));1477            } else {1478                let doesnt = if is_assoc_fn {1479                    let (span, sugg) = fn_kind1480                        .decl()1481                        .inputs1482                        .get(0)1483                        .map(|p| (p.span.shrink_to_lo(), "&self, "))1484                        .unwrap_or_else(|| {1485                            // Try to look for the "(" after the function name, if possible.1486                            // This avoids placing the suggestion into the visibility specifier.1487                            let span = fn_kind1488                                .ident()1489                                .map_or(*fn_span, |ident| fn_span.with_lo(ident.span.hi()));1490                            (1491                                self.r1492                                    .tcx1493                                    .sess1494                                    .source_map()1495                                    .span_through_char(span, '(')1496                                    .shrink_to_hi(),1497                                "&self",1498                            )1499                        });1500                    err.span_suggestion_verbose(1501                        span,1502                        "add a `self` receiver parameter to make the associated `fn` a method",1503                        sugg,1504                        Applicability::MaybeIncorrect,1505                    );1506                    "doesn't"1507                } else {1508                    "can't"1509                };1510                if let Some(ident) = fn_kind.ident() {1511                    err.span_label(1512                        ident.span,1513                        format!("this function {doesnt} have a `self` parameter"),1514                    );1515                }1516            }1517        } else if let Some(item) = self.diag_metadata.current_item {1518            if matches!(item.kind, ItemKind::Delegation(..)) {1519                err.span_label(item.span, format!("delegation supports {self_from_macro}"));1520            } else {1521                let span = if let Some(ident) = item.kind.ident() { ident.span } else { item.span };1522                err.span_label(1523                    span,1524                    format!("`self` not allowed in {} {}", item.kind.article(), item.kind.descr()),1525                );1526            }1527        }1528        true1529    }15301531    fn detect_missing_binding_available_from_pattern(1532        &self,1533        err: &mut Diag<'_>,1534        path: &[Segment],1535        following_seg: Option<&Segment>,1536    ) {1537        let [segment] = path else { return };1538        let None = following_seg else { return };1539        for rib in self.ribs[ValueNS].iter().rev() {1540            let patterns_with_skipped_bindings =1541                self.r.tcx.with_stable_hashing_context(|mut hcx| {1542                    rib.patterns_with_skipped_bindings.to_sorted(&mut hcx, true)1543                });1544            for (def_id, spans) in patterns_with_skipped_bindings {1545                if let DefKind::Struct | DefKind::Variant = self.r.tcx.def_kind(*def_id)1546                    && let Some(fields) = self.r.field_idents(*def_id)1547                {1548                    for field in fields {1549                        if field.name == segment.ident.name {1550                            if spans.iter().all(|(_, had_error)| had_error.is_err()) {1551                                // This resolution error will likely be fixed by fixing a1552                                // syntax error in a pattern, so it is irrelevant to the user.1553                                let multispan: MultiSpan =1554                                    spans.iter().map(|(s, _)| *s).collect::<Vec<_>>().into();1555                                err.span_note(1556                                    multispan,1557                                    "this pattern had a recovered parse error which likely lost \1558                                     the expected fields",1559                                );1560                                err.downgrade_to_delayed_bug();1561                            }1562                            let ty = self.r.tcx.item_name(*def_id);1563                            for (span, _) in spans {1564                                err.span_label(1565                                    *span,1566                                    format!(1567                                        "this pattern doesn't include `{field}`, which is \1568                                         available in `{ty}`",1569                                    ),1570                                );1571                            }1572                        }1573                    }1574                }1575            }1576        }1577    }15781579    fn suggest_at_operator_in_slice_pat_with_range(&self, err: &mut Diag<'_>, path: &[Segment]) {1580        let Some(pat) = self.diag_metadata.current_pat else { return };1581        let (bound, side, range) = match &pat.kind {1582            ast::PatKind::Range(Some(bound), None, range) => (bound, Side::Start, range),1583            ast::PatKind::Range(None, Some(bound), range) => (bound, Side::End, range),1584            _ => return,1585        };1586        if let ExprKind::Path(None, range_path) = &bound.kind1587            && let [segment] = &range_path.segments[..]1588            && let [s] = path1589            && segment.ident == s.ident1590            && segment.ident.span.eq_ctxt(range.span)1591        {1592            // We've encountered `[first, rest..]` (#88404) or `[first, ..rest]` (#120591)1593            // where the user might have meant `[first, rest @ ..]`.1594            let (span, snippet) = match side {1595                Side::Start => (segment.ident.span.between(range.span), " @ ".into()),1596                Side::End => (range.span.to(segment.ident.span), format!("{} @ ..", segment.ident)),1597            };1598            err.subdiagnostic(errors::UnexpectedResUseAtOpInSlicePatWithRangeSugg {1599                span,1600                ident: segment.ident,1601                snippet,1602            });1603        }16041605        enum Side {1606            Start,1607            End,1608        }1609    }16101611    fn suggest_range_struct_destructuring(1612        &mut self,1613        err: &mut Diag<'_>,1614        path: &[Segment],1615        source: PathSource<'_, '_, '_>,1616    ) {1617        if !matches!(source, PathSource::Pat | PathSource::TupleStruct(..) | PathSource::Expr(..)) {1618            return;1619        }16201621        let Some(pat) = self.diag_metadata.current_pat else { return };1622        let ast::PatKind::Range(start, end, end_kind) = &pat.kind else { return };16231624        let [segment] = path else { return };1625        let failing_span = segment.ident.span;16261627        let in_start = start.as_ref().is_some_and(|e| e.span.contains(failing_span));1628        let in_end = end.as_ref().is_some_and(|e| e.span.contains(failing_span));16291630        if !in_start && !in_end {1631            return;1632        }16331634        let start_snippet =1635            start.as_ref().and_then(|e| self.r.tcx.sess.source_map().span_to_snippet(e.span).ok());1636        let end_snippet =1637            end.as_ref().and_then(|e| self.r.tcx.sess.source_map().span_to_snippet(e.span).ok());16381639        let field = |name: &str, val: String| {1640            if val == name { val } else { format!("{name}: {val}") }1641        };16421643        let mut resolve_short_name = |short: Symbol, full: &str| -> String {1644            let ident = Ident::with_dummy_span(short);1645            let path = Segment::from_path(&Path::from_ident(ident));16461647            match self.resolve_path(&path, Some(TypeNS), None, PathSource::Type) {1648                PathResult::NonModule(..) => short.to_string(),1649                _ => full.to_string(),1650            }1651        };1652        // FIXME(new_range): Also account for new range types1653        let (struct_path, fields) = match (start_snippet, end_snippet, &end_kind.node) {1654            (Some(start), Some(end), ast::RangeEnd::Excluded) => (1655                resolve_short_name(sym::Range, "std::ops::Range"),1656                vec![field("start", start), field("end", end)],1657            ),1658            (Some(start), Some(end), ast::RangeEnd::Included(_)) => (1659                resolve_short_name(sym::RangeInclusive, "std::ops::RangeInclusive"),1660                vec![field("start", start), field("end", end)],1661            ),1662            (Some(start), None, _) => (1663                resolve_short_name(sym::RangeFrom, "std::ops::RangeFrom"),1664                vec![field("start", start)],1665            ),1666            (None, Some(end), ast::RangeEnd::Excluded) => {1667                (resolve_short_name(sym::RangeTo, "std::ops::RangeTo"), vec![field("end", end)])1668            }1669            (None, Some(end), ast::RangeEnd::Included(_)) => (1670                resolve_short_name(sym::RangeToInclusive, "std::ops::RangeToInclusive"),1671                vec![field("end", end)],1672            ),1673            _ => return,1674        };16751676        err.span_suggestion_verbose(1677            pat.span,1678            format!("if you meant to destructure a range use a struct pattern"),1679            format!("{} {{ {} }}", struct_path, fields.join(", ")),1680            Applicability::MaybeIncorrect,1681        );16821683        err.note(1684            "range patterns match against the start and end of a range; \1685             to bind the components, use a struct pattern",1686        );1687    }16881689    fn suggest_swapping_misplaced_self_ty_and_trait(1690        &mut self,1691        err: &mut Diag<'_>,1692        source: PathSource<'_, 'ast, 'ra>,1693        res: Option<Res>,1694        span: Span,1695    ) {1696        if let Some((trait_ref, self_ty)) =1697            self.diag_metadata.currently_processing_impl_trait.clone()1698            && let TyKind::Path(_, self_ty_path) = &self_ty.kind1699            && let PathResult::Module(ModuleOrUniformRoot::Module(module)) =1700                self.resolve_path(&Segment::from_path(self_ty_path), Some(TypeNS), None, source)1701            && let ModuleKind::Def(DefKind::Trait, ..) = module.kind1702            && trait_ref.path.span == span1703            && let PathSource::Trait(_) = source1704            && let Some(Res::Def(DefKind::Struct | DefKind::Enum | DefKind::Union, _)) = res1705            && let Ok(self_ty_str) = self.r.tcx.sess.source_map().span_to_snippet(self_ty.span)1706            && let Ok(trait_ref_str) =1707                self.r.tcx.sess.source_map().span_to_snippet(trait_ref.path.span)1708        {1709            err.multipart_suggestion(1710                    "`impl` items mention the trait being implemented first and the type it is being implemented for second",1711                    vec![(trait_ref.path.span, self_ty_str), (self_ty.span, trait_ref_str)],1712                    Applicability::MaybeIncorrect,1713                );1714        }1715    }17161717    fn explain_functions_in_pattern(1718        &self,1719        err: &mut Diag<'_>,1720        res: Option<Res>,1721        source: PathSource<'_, '_, '_>,1722    ) {1723        let PathSource::TupleStruct(_, _) = source else { return };1724        let Some(Res::Def(DefKind::Fn, _)) = res else { return };1725        err.primary_message("expected a pattern, found a function call");1726        err.note("function calls are not allowed in patterns: <https://doc.rust-lang.org/book/ch19-00-patterns.html>");1727    }17281729    fn suggest_changing_type_to_const_param(1730        &self,1731        err: &mut Diag<'_>,1732        res: Option<Res>,1733        source: PathSource<'_, '_, '_>,1734        path: &[Segment],1735        following_seg: Option<&Segment>,1736        span: Span,1737    ) {1738        if let PathSource::Expr(None) = source1739            && let Some(Res::Def(DefKind::TyParam, _)) = res1740            && following_seg.is_none()1741            && let [segment] = path1742        {1743            // We have something like1744            // impl<T, N> From<[T; N]> for VecWrapper<T> {1745            //     fn from(slice: [T; N]) -> Self {1746            //         VecWrapper(slice.to_vec())1747            //     }1748            // }1749            // where `N` is a type param but should likely have been a const param.1750            let Some(item) = self.diag_metadata.current_item else { return };1751            let Some(generics) = item.kind.generics() else { return };1752            let Some(span) = generics.params.iter().find_map(|param| {1753                // Only consider type params with no bounds.1754                if param.bounds.is_empty() && param.ident.name == segment.ident.name {1755                    Some(param.ident.span)1756                } else {1757                    None1758                }1759            }) else {1760                return;1761            };1762            err.subdiagnostic(errors::UnexpectedResChangeTyParamToConstParamSugg {1763                before: span.shrink_to_lo(),1764                after: span.shrink_to_hi(),1765            });1766            return;1767        }1768        let PathSource::Trait(_) = source else { return };17691770        // We don't include `DefKind::Str` and `DefKind::AssocTy` as they can't be reached here anyway.1771        let applicability = match res {1772            Some(Res::PrimTy(PrimTy::Int(_) | PrimTy::Uint(_) | PrimTy::Bool | PrimTy::Char)) => {1773                Applicability::MachineApplicable1774            }1775            // FIXME(const_generics): Add `DefKind::TyParam` and `SelfTyParam` once we support generic1776            // const generics. Of course, `Struct` and `Enum` may contain ty params, too, but the1777            // benefits of including them here outweighs the small number of false positives.1778            Some(Res::Def(DefKind::Struct | DefKind::Enum, _))1779                if self.r.tcx.features().adt_const_params()1780                    || self.r.tcx.features().min_adt_const_params() =>1781            {1782                Applicability::MaybeIncorrect1783            }1784            _ => return,1785        };17861787        let Some(item) = self.diag_metadata.current_item else { return };1788        let Some(generics) = item.kind.generics() else { return };17891790        let param = generics.params.iter().find_map(|param| {1791            // Only consider type params with exactly one trait bound.1792            if let [bound] = &*param.bounds1793                && let ast::GenericBound::Trait(tref) = bound1794                && tref.modifiers == ast::TraitBoundModifiers::NONE1795                && tref.span == span1796                && param.ident.span.eq_ctxt(span)1797            {1798                Some(param.ident.span)1799            } else {1800                None1801            }1802        });18031804        if let Some(param) = param {1805            err.subdiagnostic(errors::UnexpectedResChangeTyToConstParamSugg {1806                span: param.shrink_to_lo(),1807                applicability,1808            });1809        }1810    }18111812    fn suggest_pattern_match_with_let(1813        &self,1814        err: &mut Diag<'_>,1815        source: PathSource<'_, '_, '_>,1816        span: Span,1817    ) -> bool {1818        if let PathSource::Expr(_) = source1819            && let Some(Expr { span: expr_span, kind: ExprKind::Assign(lhs, _, _), .. }) =1820                self.diag_metadata.in_if_condition1821        {1822            // Icky heuristic so we don't suggest:1823            // `if (i + 2) = 2` => `if let (i + 2) = 2` (approximately pattern)1824            // `if 2 = i` => `if let 2 = i` (lhs needs to contain error span)1825            if lhs.is_approximately_pattern() && lhs.span.contains(span) {1826                err.span_suggestion_verbose(1827                    expr_span.shrink_to_lo(),1828                    "you might have meant to use pattern matching",1829                    "let ",1830                    Applicability::MaybeIncorrect,1831                );1832                return true;1833            }1834        }1835        false1836    }18371838    fn get_single_associated_item(1839        &mut self,1840        path: &[Segment],1841        source: &PathSource<'_, 'ast, 'ra>,1842        filter_fn: &impl Fn(Res) -> bool,1843    ) -> Option<TypoSuggestion> {1844        if let crate::PathSource::TraitItem(_, _) = source {1845            let mod_path = &path[..path.len() - 1];1846            if let PathResult::Module(ModuleOrUniformRoot::Module(module)) =1847                self.resolve_path(mod_path, None, None, *source)1848            {1849                let targets: Vec<_> = self1850                    .r1851                    .resolutions(module)1852                    .borrow()1853                    .iter()1854                    .filter_map(|(key, resolution)| {1855                        let resolution = resolution.borrow();1856                        resolution.best_decl().map(|binding| binding.res()).and_then(|res| {1857                            if filter_fn(res) {1858                                Some((key.ident.name, resolution.orig_ident_span, res))1859                            } else {1860                                None1861                            }1862                        })1863                    })1864                    .collect();1865                if let &[(name, orig_ident_span, res)] = targets.as_slice() {1866                    return Some(TypoSuggestion::single_item(name, orig_ident_span, res));1867                }1868            }1869        }1870        None1871    }18721873    /// Given `where <T as Bar>::Baz: String`, suggest `where T: Bar<Baz = String>`.1874    fn restrict_assoc_type_in_where_clause(&self, span: Span, err: &mut Diag<'_>) -> bool {1875        // Detect that we are actually in a `where` predicate.1876        let Some(ast::WherePredicate {1877            kind:1878                ast::WherePredicateKind::BoundPredicate(ast::WhereBoundPredicate {1879                    bounded_ty,1880                    bound_generic_params,1881                    bounds,1882                }),1883            span: where_span,1884            ..1885        }) = self.diag_metadata.current_where_predicate1886        else {1887            return false;1888        };1889        if !bound_generic_params.is_empty() {1890            return false;1891        }18921893        // Confirm that the target is an associated type.1894        let ast::TyKind::Path(Some(qself), path) = &bounded_ty.kind else { return false };1895        // use this to verify that ident is a type param.1896        let Some(partial_res) = self.r.partial_res_map.get(&bounded_ty.id) else { return false };1897        if !matches!(partial_res.full_res(), Some(Res::Def(DefKind::AssocTy, _))) {1898            return false;1899        }19001901        let peeled_ty = qself.ty.peel_refs();1902        let ast::TyKind::Path(None, type_param_path) = &peeled_ty.kind else { return false };1903        // Confirm that the `SelfTy` is a type parameter.1904        let Some(partial_res) = self.r.partial_res_map.get(&peeled_ty.id) else {1905            return false;1906        };1907        if !matches!(partial_res.full_res(), Some(Res::Def(DefKind::TyParam, _))) {1908            return false;1909        }1910        let ([ast::PathSegment { args: None, .. }], [ast::GenericBound::Trait(poly_trait_ref)]) =1911            (&type_param_path.segments[..], &bounds[..])1912        else {1913            return false;1914        };1915        let [ast::PathSegment { ident, args: None, id }] =1916            &poly_trait_ref.trait_ref.path.segments[..]1917        else {1918            return false;1919        };1920        if poly_trait_ref.modifiers != ast::TraitBoundModifiers::NONE {1921            return false;1922        }1923        if ident.span == span {1924            let Some(partial_res) = self.r.partial_res_map.get(&id) else {1925                return false;1926            };1927            if !matches!(partial_res.full_res(), Some(Res::Def(..))) {1928                return false;1929            }19301931            let Some(new_where_bound_predicate) =1932                mk_where_bound_predicate(path, poly_trait_ref, &qself.ty)1933            else {1934                return false;1935            };1936            err.span_suggestion_verbose(1937                *where_span,1938                format!("constrain the associated type to `{ident}`"),1939                where_bound_predicate_to_string(&new_where_bound_predicate),1940                Applicability::MaybeIncorrect,1941            );1942        }1943        true1944    }19451946    /// Check if the source is call expression and the first argument is `self`. If true,1947    /// return the span of whole call and the span for all arguments expect the first one (`self`).1948    fn call_has_self_arg(&self, source: PathSource<'_, '_, '_>) -> Option<(Span, Option<Span>)> {1949        let mut has_self_arg = None;1950        if let PathSource::Expr(Some(parent)) = source1951            && let ExprKind::Call(_, args) = &parent.kind1952            && !args.is_empty()1953        {1954            let mut expr_kind = &args[0].kind;1955            loop {1956                match expr_kind {1957                    ExprKind::Path(_, arg_name) if arg_name.segments.len() == 1 => {1958                        if arg_name.segments[0].ident.name == kw::SelfLower {1959                            let call_span = parent.span;1960                            let tail_args_span = if args.len() > 1 {1961                                Some(Span::new(1962                                    args[1].span.lo(),1963                                    args.last().unwrap().span.hi(),1964                                    call_span.ctxt(),1965                                    None,1966                                ))1967                            } else {1968                                None1969                            };1970                            has_self_arg = Some((call_span, tail_args_span));1971                        }1972                        break;1973                    }1974                    ExprKind::AddrOf(_, _, expr) => expr_kind = &expr.kind,1975                    _ => break,1976                }1977            }1978        }1979        has_self_arg1980    }19811982    fn followed_by_brace(&self, span: Span) -> (bool, Option<Span>) {1983        // HACK(estebank): find a better way to figure out that this was a1984        // parser issue where a struct literal is being used on an expression1985        // where a brace being opened means a block is being started. Look1986        // ahead for the next text to see if `span` is followed by a `{`.1987        let sm = self.r.tcx.sess.source_map();1988        if let Some(open_brace_span) = sm.span_followed_by(span, "{") {1989            // In case this could be a struct literal that needs to be surrounded1990            // by parentheses, find the appropriate span.1991            let close_brace_span =1992                sm.span_to_next_source(open_brace_span).ok().and_then(|next_source| {1993                    // Find the matching `}` accounting for nested braces.1994                    let mut depth: u32 = 1;1995                    let offset = next_source.char_indices().find_map(|(i, c)| {1996                        match c {1997                            '{' => depth += 1,1998                            '}' if depth == 1 => return Some(i),1999                            '}' => depth -= 1,2000                            _ => {}

Findings

✓ No findings reported for this file.

Get this view in your editor

Same data, no extra tab — call code_get_file + code_get_findings over MCP from Claude/Cursor/Copilot.