compiler/rustc_resolve/src/late/diagnostics.rs RUST 4,709 lines View on github.com → Search inside
File is large — showing lines 1–2,000 of 4,709.
1// ignore-tidy-file-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_data_structures::unord::UnordItems;16use rustc_errors::codes::*;17use rustc_errors::{18    Applicability, Diag, Diagnostic, ErrorGuaranteed, MultiSpan, SuggestionStyle, pluralize,19    struct_span_code_err,20};21use rustc_hir as hir;22use rustc_hir::attrs::diagnostic::{CustomDiagnostic, FormatArgs};23use rustc_hir::def::Namespace::{self, *};24use rustc_hir::def::{CtorKind, CtorOf, DefKind, MacroKinds};25use rustc_hir::def_id::{CRATE_DEF_ID, DefId};26use rustc_hir::{MissingLifetimeKind, PrimTy, find_attr};27use rustc_lint_defs::builtin::{SINGLE_USE_LIFETIMES, UNUSED_LIFETIMES};28use rustc_middle::ty;29use rustc_session::Session;30use rustc_span::edit_distance::{edit_distance, find_best_match_for_name};31use rustc_span::edition::Edition;32use rustc_span::{DUMMY_SP, DesugaringKind, Ident, Span, Symbol, kw, sym};33use thin_vec::{ThinVec, thin_vec};34use tracing::debug;3536use super::NoConstantGenericsReason;37use crate::diagnostics::impls::{ImportSuggestion, LabelSuggestion, TypoSuggestion};38use crate::late::{39    AliasPossibility, LateResolutionVisitor, LifetimeBinderKind, LifetimeRes, LifetimeRibKind,40    LifetimeUseSet, QSelf, RibKind,41};42use crate::ty::fast_reject::SimplifiedType;43use crate::{44    Finalize, Module, ModuleOrUniformRoot, ParentScope, PathResult, PathSource, Res, Resolver,45    ScopeSet, Segment, diagnostics, path_names_to_string,46};4748/// 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}5657impl 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}7475fn is_self_type(path: &[Segment], namespace: Namespace) -> bool {76    namespace == TypeNS && path.len() == 1 && path[0].ident.name == kw::SelfUpper77}7879fn is_self_value(path: &[Segment], namespace: Namespace) -> bool {80    namespace == ValueNS && path.len() == 1 && path[0].ident.name == kw::SelfLower81}8283fn path_to_string_without_assoc_item_bindings(path: &Path) -> String {84    let mut path = path.clone();85    for segment in &mut path.segments {86        let mut remove_args = false;87        if let Some(args) = segment.args.as_deref_mut()88            && let ast::GenericArgs::AngleBracketed(angle_bracketed) = args89        {90            angle_bracketed.args.retain(|arg| matches!(arg, ast::AngleBracketedArg::Arg(_)));91            remove_args = angle_bracketed.args.is_empty();92        }93        if remove_args {94            segment.args = None;95        }96    }97    path_to_string(&path)98}99100/// Gets the stringified path for an enum from an `ImportSuggestion` for an enum variant.101fn import_candidate_to_enum_paths(suggestion: &ImportSuggestion) -> (String, String) {102    let variant_path = &suggestion.path;103    let variant_path_string = path_names_to_string(variant_path);104105    let path_len = suggestion.path.segments.len();106    let enum_path = ast::Path {107        span: suggestion.path.span,108        segments: suggestion.path.segments[0..path_len - 1].iter().cloned().collect(),109    };110    let enum_path_string = path_names_to_string(&enum_path);111112    (variant_path_string, enum_path_string)113}114115/// Description of an elided lifetime.116#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug)]117pub(super) struct MissingLifetime {118    /// Used to overwrite the resolution with the suggestion, to avoid cascading errors.119    pub id: NodeId,120    /// As we cannot yet emit lints in this crate and have to buffer them instead,121    /// we need to associate each lint with some `NodeId`,122    /// however for some `MissingLifetime`s their `NodeId`s are "fake",123    /// in a sense that they are temporary and not get preserved down the line,124    /// which means that the lints for those nodes will not get emitted.125    /// To combat this, we can try to use some other `NodeId`s as a fallback option.126    pub id_for_lint: NodeId,127    /// Where to suggest adding the lifetime.128    pub span: Span,129    /// How the lifetime was introduced, to have the correct space and comma.130    pub kind: MissingLifetimeKind,131    /// Number of elided lifetimes, used for elision in path.132    pub count: usize,133}134135/// Description of the lifetimes appearing in a function parameter.136/// This is used to provide a literal explanation to the elision failure.137#[derive(Debug)]138pub(super) struct ElisionFnParameter {139    /// The index of the argument in the original definition.140    pub index: usize,141    /// The name of the argument if it's a simple ident.142    pub ident: Option<Ident>,143    /// The number of lifetimes in the parameter.144    pub lifetime_count: usize,145    /// The span of the parameter.146    pub span: Span,147}148149/// Description of lifetimes that appear as candidates for elision.150/// This is used to suggest introducing an explicit lifetime.151#[derive(Clone, Copy, Debug)]152pub(super) enum LifetimeElisionCandidate {153    /// This is not a real lifetime, or it is a named lifetime, in which case we won't suggest anything.154    Ignore,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    notes: Vec<String>,169}170171#[derive(Debug)]172enum TypoCandidate {173    Typo(TypoSuggestion),174    Shadowed(Res, Option<Span>),175    None,176}177178impl TypoCandidate {179    fn to_opt_suggestion(self) -> Option<TypoSuggestion> {180        match self {181            TypoCandidate::Typo(sugg) => Some(sugg),182            TypoCandidate::Shadowed(_, _) | TypoCandidate::None => None,183        }184    }185}186187impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {188    fn trait_assoc_type_def_id_by_name(189        &mut self,190        trait_def_id: DefId,191        assoc_name: Symbol,192    ) -> Option<DefId> {193        let module = self.r.get_module(trait_def_id)?;194        self.r.resolutions(module).iter().find_map(|(key, resolution)| {195            if key.ident.name != assoc_name {196                return None;197            }198            let resolution = resolution.borrow(self.r);199            let binding = resolution.best_decl()?;200            match binding.res() {201                Res::Def(DefKind::AssocTy, def_id) => Some(def_id),202                _ => None,203            }204        })205    }206207    /// This does best-effort work to generate suggestions for associated types.208    fn suggest_assoc_type_from_bounds(209        &mut self,210        err: &mut Diag<'_>,211        source: PathSource<'_, 'ast, 'ra>,212        path: &[Segment],213        ident_span: Span,214    ) -> bool {215        // Filter out cases where we cannot emit meaningful suggestions.216        if source.namespace() != TypeNS {217            return false;218        }219        let [segment] = path else { return false };220        if segment.has_generic_args {221            return false;222        }223        if !ident_span.can_be_used_for_suggestions() {224            return false;225        }226        let assoc_name = segment.ident.name;227        if assoc_name == kw::Underscore {228            return false;229        }230231        // Map: type parameter name -> (trait def id -> (assoc type def id, trait paths as written)).232        // We keep a set of paths per trait so we can detect cases like233        // `T: Trait<i32> + Trait<u32>` where suggesting `T::Assoc` would be ambiguous.234        let mut matching_bounds: FxIndexMap<235            Symbol,236            FxIndexMap<DefId, (DefId, FxIndexSet<String>)>,237        > = FxIndexMap::default();238239        let mut record_bound = |this: &mut Self,240                                ty_param: Symbol,241                                poly_trait_ref: &ast::PolyTraitRef| {242            // Avoid generating suggestions we can't print in a well-formed way.243            if !poly_trait_ref.bound_generic_params.is_empty() {244                return;245            }246            if poly_trait_ref.modifiers != ast::TraitBoundModifiers::NONE {247                return;248            }249            let Some(trait_seg) = poly_trait_ref.trait_ref.path.segments.last() else {250                return;251            };252            let Some(partial_res) = this.r.partial_res_map.get(&trait_seg.id) else {253                return;254            };255            let Some(trait_def_id) = partial_res.full_res().and_then(|res| res.opt_def_id()) else {256                return;257            };258            let Some(assoc_type_def_id) =259                this.trait_assoc_type_def_id_by_name(trait_def_id, assoc_name)260            else {261                return;262            };263264            // Preserve `::` and generic args so we don't generate broken suggestions like265            // `<T as Foo>::Assoc` for bounds written as `T: ::Foo<'a>`, while stripping266            // associated-item bindings that are rejected in qualified paths.267            let trait_path =268                path_to_string_without_assoc_item_bindings(&poly_trait_ref.trait_ref.path);269            let trait_bounds = matching_bounds.entry(ty_param).or_default();270            let trait_bounds = trait_bounds271                .entry(trait_def_id)272                .or_insert_with(|| (assoc_type_def_id, FxIndexSet::default()));273            debug_assert_eq!(trait_bounds.0, assoc_type_def_id);274            trait_bounds.1.insert(trait_path);275        };276277        let mut record_from_generics = |this: &mut Self, generics: &ast::Generics| {278            for param in &generics.params {279                let ast::GenericParamKind::Type { .. } = param.kind else { continue };280                for bound in &param.bounds {281                    let ast::GenericBound::Trait(poly_trait_ref) = bound else { continue };282                    record_bound(this, param.ident.name, poly_trait_ref);283                }284            }285286            for predicate in &generics.where_clause.predicates {287                let ast::WherePredicateKind::BoundPredicate(where_bound) = &predicate.kind else {288                    continue;289                };290291                let ast::TyKind::Path(None, bounded_path) = &where_bound.bounded_ty.kind else {292                    continue;293                };294                let [ast::PathSegment { ident, args: None, .. }] = &bounded_path.segments[..]295                else {296                    continue;297                };298299                // Only suggest for bounds that are explicitly on an in-scope type parameter.300                let Some(partial_res) = this.r.partial_res_map.get(&where_bound.bounded_ty.id)301                else {302                    continue;303                };304                if !matches!(partial_res.full_res(), Some(Res::Def(DefKind::TyParam, _))) {305                    continue;306                }307308                for bound in &where_bound.bounds {309                    let ast::GenericBound::Trait(poly_trait_ref) = bound else { continue };310                    record_bound(this, ident.name, poly_trait_ref);311                }312            }313        };314315        if let Some(item) = self.diag_metadata.current_item316            && let Some(generics) = item.kind.generics()317        {318            record_from_generics(self, generics);319        }320321        if let Some(item) = self.diag_metadata.current_item322            && matches!(item.kind, ItemKind::Impl(..))323            && let Some(assoc) = self.diag_metadata.current_impl_item324        {325            let generics = match &assoc.kind {326                AssocItemKind::Const(ast::ConstItem { generics, .. })327                | AssocItemKind::Fn(ast::Fn { generics, .. })328                | AssocItemKind::Type(ast::TyAlias { generics, .. }) => Some(generics),329                AssocItemKind::Delegation(..)330                | AssocItemKind::MacCall(..)331                | AssocItemKind::DelegationMac(..) => None,332            };333            if let Some(generics) = generics {334                record_from_generics(self, generics);335            }336        }337338        let mut suggestions: FxIndexSet<String> = FxIndexSet::default();339        for (ty_param, traits) in matching_bounds {340            let ty_param = ty_param.to_ident_string();341            let trait_paths_len: usize = traits.values().map(|(_, paths)| paths.len()).sum();342            if traits.len() == 1 && trait_paths_len == 1 {343                let assoc_type_def_id = traits.values().next().unwrap().0;344                let assoc_segment = format!(345                    "{}{}",346                    assoc_name,347                    self.r.item_required_generic_args_suggestion(assoc_type_def_id)348                );349                suggestions.insert(format!("{ty_param}::{assoc_segment}"));350            } else {351                for (assoc_type_def_id, trait_paths) in traits.into_values() {352                    let assoc_segment = format!(353                        "{}{}",354                        assoc_name,355                        self.r.item_required_generic_args_suggestion(assoc_type_def_id)356                    );357                    for trait_path in trait_paths {358                        suggestions359                            .insert(format!("<{ty_param} as {trait_path}>::{assoc_segment}"));360                    }361                }362            }363        }364365        if suggestions.is_empty() {366            return false;367        }368369        let mut suggestions: Vec<String> = suggestions.into_iter().collect();370        suggestions.sort();371372        err.span_suggestions_with_style(373            ident_span,374            "you might have meant to use an associated type of the same name",375            suggestions,376            Applicability::MaybeIncorrect,377            SuggestionStyle::ShowAlways,378        );379380        true381    }382383    fn make_base_error(384        &mut self,385        path: &[Segment],386        span: Span,387        source: PathSource<'_, 'ast, 'ra>,388        res: Option<Res>,389        could_be_expr: bool,390    ) -> BaseError {391        // Make the base error.392        let mut expected = source.descr_expected();393        let path_str = Segment::names_to_string(path);394395        if let Some(res) = res {396            BaseError {397                msg: format!("expected {}, found {} `{}`", expected, res.descr(), path_str),398                fallback_label: format!("not a {expected}"),399                span,400                span_label: match res {401                    Res::Def(DefKind::TyParam, def_id) => {402                        Some((self.r.def_span(def_id), "found this type parameter"))403                    }404                    _ => None,405                },406                could_be_expr,407                suggestion: None,408                module: None,409                notes: Vec::new(),410            }411        } else {412            let mut span_label = None;413            let item_ident = path.last().unwrap().ident;414            let item_span = item_ident.span;415            let (tick, mod_prefix, mod_str, module, suggestion) = if path.len() == 1 {416                debug!(?self.diag_metadata.current_impl_items);417                debug!(?self.diag_metadata.current_function);418                let suggestion = if self.current_trait_ref.is_none()419                    && let Some((fn_kind, _)) = self.diag_metadata.current_function420                    && let Some(FnCtxt::Assoc(_)) = fn_kind.ctxt()421                    && let FnKind::Fn(_, _, ast::Fn { sig, .. }) = fn_kind422                    && let Some(items) = self.diag_metadata.current_impl_items423                    && let Some(item) = items.iter().find(|i| {424                        i.kind.ident().is_some_and(|ident| {425                            // Don't suggest if the item is in Fn signature arguments (#112590).426                            ident.name == item_ident.name && !sig.span.contains(item_span)427                        })428                    }) {429                    let sp = item_span.shrink_to_lo();430431                    // Account for `Foo { field }` when suggesting `self.field` so we result on432                    // `Foo { field: self.field }`.433                    let field = match source {434                        PathSource::Expr(Some(Expr { kind: ExprKind::Struct(expr), .. })) => {435                            expr.fields.iter().find(|f| f.ident == item_ident)436                        }437                        _ => None,438                    };439                    let pre = if let Some(field) = field440                        && field.is_shorthand441                    {442                        format!("{item_ident}: ")443                    } else {444                        String::new()445                    };446                    // Ensure we provide a structured suggestion for an assoc fn only for447                    // expressions that are actually a fn call.448                    let is_call = match field {449                        Some(ast::ExprField { expr, .. }) => {450                            matches!(expr.kind, ExprKind::Call(..))451                        }452                        _ => matches!(453                            source,454                            PathSource::Expr(Some(Expr { kind: ExprKind::Call(..), .. })),455                        ),456                    };457458                    match &item.kind {459                        AssocItemKind::Fn(fn_)460                            if (!sig.decl.has_self() || !is_call) && fn_.sig.decl.has_self() =>461                        {462                            // Ensure that we only suggest `self.` if `self` is available,463                            // you can't call `fn foo(&self)` from `fn bar()` (#115992).464                            // We also want to mention that the method exists.465                            span_label = Some((466                                fn_.ident.span,467                                "a method by that name is available on `Self` here",468                            ));469                            None470                        }471                        AssocItemKind::Fn(fn_) if !fn_.sig.decl.has_self() && !is_call => {472                            span_label = Some((473                                fn_.ident.span,474                                "an associated function by that name is available on `Self` here",475                            ));476                            None477                        }478                        AssocItemKind::Fn(fn_) if fn_.sig.decl.has_self() => {479                            Some((sp, "consider using the method on `Self`", format!("{pre}self.")))480                        }481                        AssocItemKind::Fn(_) => Some((482                            sp,483                            "consider using the associated function on `Self`",484                            format!("{pre}Self::"),485                        )),486                        AssocItemKind::Const(..) => Some((487                            sp,488                            "consider using the associated constant on `Self`",489                            format!("{pre}Self::"),490                        )),491                        _ => None,492                    }493                } else {494                    None495                };496                ("", String::new(), "this scope".to_string(), None, suggestion)497            } else if path.len() == 2 && path[0].ident.name == kw::PathRoot {498                if self.r.tcx.sess.edition() > Edition::Edition2015 {499                    // In edition 2018 onwards, the `::foo` syntax may only pull from the extern prelude500                    // which overrides all other expectations of item type501                    expected = "crate";502                    ("", String::new(), "the list of imported crates".to_string(), None, None)503                } else {504                    (505                        "",506                        String::new(),507                        "the crate root".to_string(),508                        Some(CRATE_DEF_ID.to_def_id()),509                        None,510                    )511                }512            } else if path.len() == 2 && path[0].ident.name == kw::Crate {513                (514                    "",515                    String::new(),516                    "the crate root".to_string(),517                    Some(CRATE_DEF_ID.to_def_id()),518                    None,519                )520            } else {521                let mod_path = &path[..path.len() - 1];522                let mod_res = self.resolve_path(mod_path, Some(TypeNS), None, source);523                let mod_prefix = match mod_res {524                    PathResult::Module(ModuleOrUniformRoot::Module(module)) => module.res(),525                    _ => None,526                };527528                let module_did = mod_prefix.as_ref().and_then(Res::mod_def_id);529530                let mod_prefix =531                    mod_prefix.map_or_else(String::new, |res| format!("{} ", res.descr()));532                ("`", mod_prefix, Segment::names_to_string(mod_path), module_did, None)533            };534535            let suggestion =536                if ["true", "false"].contains(&item_ident.to_string().to_lowercase().as_str()) {537                    // check if we are in situation of typo like `True` instead of `true`.538                    let item_typo = item_ident.to_string().to_lowercase();539                    Some((item_span, "you may want to use a bool value instead", item_typo))540                // FIXME(vincenzopalazzo): make the check smarter,541                // and maybe expand with levenshtein distance checks542                } else if item_ident.as_str() == "printf" {543                    Some((544                        item_span,545                        "you may have meant to use the `print` macro",546                        "print!".to_owned(),547                    ))548                } else {549                    suggestion550                };551            let mut msg = format!(552                "cannot find {expected} `{item_ident}` in {mod_prefix}{tick}{mod_str}{tick}"553            );554            let mut fallback_label = if path_str == "async" && expected.starts_with("struct") {555                "`async` blocks are only allowed in Rust 2018 or later".to_string()556            } else {557                format!("not found in {tick}{mod_str}{tick}")558            };559            let mut notes = Vec::new();560            if let Some(module_def_id) = module561                && let Some(directive) = self.r.on_unknown_data(module_def_id)562            {563                let args = FormatArgs { unresolved: item_ident.to_string(), this: mod_str, .. };564                let CustomDiagnostic {565                    message,566                    label,567                    notes: custom_notes,568                    parent_label: _unreachable,569                } = directive.eval(None, &args);570                if let Some(message) = message {571                    notes.push(msg);572                    msg = message;573                }574                if let Some(label) = label {575                    fallback_label = label;576                    if let Some((_, span_label)) = span_label.take() {577                        notes.push(span_label.to_string());578                    }579                }580                notes.extend(custom_notes);581            }582583            BaseError {584                msg,585                fallback_label,586                span: item_span,587                span_label,588                could_be_expr,589                suggestion,590                module,591                notes,592            }593        }594    }595596    fn could_be_expr(&self, res: Res, span: Span) -> bool {597        match res {598            // Verify whether this is a fn call or an Fn used as a type.599            Res::Def(DefKind::Fn, _) => self600                .r601                .tcx602                .sess603                .source_map()604                .span_to_snippet(span)605                .is_ok_and(|snippet| snippet.ends_with(')')),606            Res::Def(607                DefKind::Ctor(..)608                | DefKind::AssocFn609                | DefKind::Const { .. }610                | DefKind::AssocConst { .. },611                _,612            )613            | Res::SelfCtor(_)614            | Res::PrimTy(_)615            | Res::Local(_) => true,616            _ => false,617        }618    }619620    /// Try to suggest for a module path that cannot be resolved.621    /// Such as `fmt::Debug` where `fmt` is not resolved without importing,622    /// here we search with `lookup_import_candidates` for a module named `fmt`623    /// with `TypeNS` as namespace.624    ///625    /// We need a separate function here because we won't suggest for a path with single segment626    /// and we won't change `SourcePath` api `is_expected` to match `Type` with `DefKind::Mod`627    pub(crate) fn smart_resolve_partial_mod_path_errors(628        &mut self,629        prefix_path: &[Segment],630        following_seg: Option<&Segment>,631    ) -> Vec<ImportSuggestion> {632        if let Some(segment) = prefix_path.last()633            && let Some(following_seg) = following_seg634        {635            let candidates = self.r.lookup_import_candidates(636                segment.ident,637                Namespace::TypeNS,638                &self.parent_scope,639                &|res: Res| matches!(res, Res::Def(DefKind::Mod, _)),640            );641            // double check next seg is valid642            candidates643                .into_iter()644                .filter(|candidate| {645                    if let Some(def_id) = candidate.did646                        && let Some(module) = self.r.get_module(def_id)647                    {648                        Some(def_id) != self.parent_scope.module.opt_def_id()649                            && self650                                .r651                                .resolutions(module)652                                .iter()653                                .any(|(key, _r)| key.ident.name == following_seg.ident.name)654                    } else {655                        false656                    }657                })658                .collect::<Vec<_>>()659        } else {660            Vec::new()661        }662    }663664    /// Handles error reporting for `smart_resolve_path_fragment` function.665    /// Creates base error and amends it with one short label and possibly some longer helps/notes.666    #[tracing::instrument(skip(self), level = "debug")]667    pub(crate) fn smart_resolve_report_errors(668        &mut self,669        path: &[Segment],670        following_seg: Option<&Segment>,671        span: Span,672        source: PathSource<'_, 'ast, 'ra>,673        res: Option<Res>,674        qself: Option<&QSelf>,675    ) -> (Diag<'tcx>, Vec<ImportSuggestion>) {676        debug!(?res, ?source);677        let cross_namespace_res = res.filter(|res| !res.matches_ns(source.namespace()));678        let could_be_expr = res.is_some_and(|res| self.could_be_expr(res, span));679        let base_error = self.make_base_error(680            path,681            span,682            source,683            if cross_namespace_res.is_some() { None } else { res },684            could_be_expr,685        );686687        let code = source.error_code(res.is_some());688        let mut err = self.r.dcx().struct_span_err(base_error.span, base_error.msg.clone());689        err.code(code);690691        if let Some(res) = cross_namespace_res {692            err.note(format!(693                "{} {} named `{}` exists in another namespace",694                res.article(),695                res.descr(),696                Segment::names_to_string(path),697            ));698        }699700        // Try to get the span of the identifier within the path's syntax context701        // (if that's different).702        if let Some(within_macro_span) =703            base_error.span.within_macro(span, self.r.tcx.sess.source_map())704        {705            err.span_label(within_macro_span, "due to this macro variable");706        }707708        self.detect_missing_binding_available_from_pattern(&mut err, path, following_seg);709        self.suggest_at_operator_in_slice_pat_with_range(&mut err, path);710        self.suggest_range_struct_destructuring(&mut err, path, source);711        self.suggest_swapping_misplaced_self_ty_and_trait(&mut err, source, res, base_error.span);712713        if let Some((span, label)) = base_error.span_label {714            err.span_label(span, label);715        }716        for note in &base_error.notes {717            err.note(note.clone());718        }719720        if let Some(ref sugg) = base_error.suggestion {721            err.span_suggestion_verbose(sugg.0, sugg.1, &sugg.2, Applicability::MaybeIncorrect);722        }723724        self.suggest_changing_type_to_const_param(&mut err, res, source, path, following_seg, span);725        self.explain_functions_in_pattern(&mut err, res, source);726727        if self.suggest_pattern_match_with_let(&mut err, source, span) {728            // Fallback label.729            err.span_label(base_error.span, base_error.fallback_label);730            return (err, Vec::new());731        }732733        self.suggest_self_or_self_ref(&mut err, path, span);734        self.detect_assoc_type_constraint_meant_as_path(&mut err, &base_error);735        self.detect_rtn_with_fully_qualified_path(736            &mut err,737            path,738            following_seg,739            span,740            source,741            res,742            qself,743        );744        if self.suggest_self_ty(&mut err, source, path, span)745            || self.suggest_self_value(&mut err, source, path, span)746        {747            return (err, Vec::new());748        }749750        if let Some((did, item)) = self.lookup_doc_alias_name(path, source.namespace()) {751            let item_name = item.name;752            let suggestion_name = self.r.tcx.item_name(did);753            err.span_suggestion(754                item.span,755                format!("`{suggestion_name}` has a name defined in the doc alias attribute as `{item_name}`"),756                    suggestion_name,757                    Applicability::MaybeIncorrect758                );759760            return (err, Vec::new());761        };762763        let (found, suggested_candidates, mut candidates) = self.try_lookup_name_relaxed(764            &mut err,765            source,766            path,767            following_seg,768            span,769            res,770            &base_error,771        );772        if found {773            return (err, candidates);774        }775776        if self.suggest_shadowed(&mut err, source, path, following_seg, span) {777            // if there is already a shadowed name, don'suggest candidates for importing778            candidates.clear();779        }780781        let mut fallback = self.suggest_trait_and_bounds(&mut err, source, res, span, &base_error);782        fallback |= self.suggest_typo(783            &mut err,784            source,785            path,786            following_seg,787            span,788            &base_error,789            suggested_candidates,790        );791792        if fallback {793            // Fallback label.794            err.span_label(base_error.span, base_error.fallback_label);795        }796        self.err_code_special_cases(&mut err, source, path, span);797798        let module = base_error.module.unwrap_or_else(|| CRATE_DEF_ID.to_def_id());799        self.r.find_cfg_stripped(&mut err, &path.last().unwrap().ident.name, module);800801        (err, candidates)802    }803804    fn detect_rtn_with_fully_qualified_path(805        &self,806        err: &mut Diag<'_>,807        path: &[Segment],808        following_seg: Option<&Segment>,809        span: Span,810        source: PathSource<'_, '_, '_>,811        res: Option<Res>,812        qself: Option<&QSelf>,813    ) {814        if let Some(Res::Def(DefKind::AssocFn, _)) = res815            && let PathSource::TraitItem(TypeNS, _) = source816            && let None = following_seg817            && let Some(qself) = qself818            && let TyKind::Path(None, ty_path) = &qself.ty.kind819            && ty_path.segments.len() == 1820            && self.diag_metadata.current_where_predicate.is_some()821        {822            err.span_suggestion_verbose(823                span,824                "you might have meant to use the return type notation syntax",825                format!("{}::{}(..)", ty_path.segments[0].ident, path[path.len() - 1].ident),826                Applicability::MaybeIncorrect,827            );828        }829    }830831    fn detect_assoc_type_constraint_meant_as_path(832        &self,833        err: &mut Diag<'_>,834        base_error: &BaseError,835    ) {836        let Some(ty) = self.diag_metadata.current_type_path else {837            return;838        };839        let TyKind::Path(_, path) = &ty.kind else {840            return;841        };842        for segment in &path.segments {843            let Some(params) = &segment.args else {844                continue;845            };846            let ast::GenericArgs::AngleBracketed(params) = params.deref() else {847                continue;848            };849            for param in &params.args {850                let ast::AngleBracketedArg::Constraint(constraint) = param else {851                    continue;852                };853                let ast::AssocItemConstraintKind::Bound { bounds } = &constraint.kind else {854                    continue;855                };856                for bound in bounds {857                    let ast::GenericBound::Trait(trait_ref) = bound else {858                        continue;859                    };860                    if trait_ref.modifiers == ast::TraitBoundModifiers::NONE861                        && base_error.span == trait_ref.span862                    {863                        err.span_suggestion_verbose(864                            constraint.ident.span.between(trait_ref.span),865                            "you might have meant to write a path instead of an associated type bound",866                            "::",867                            Applicability::MachineApplicable,868                        );869                    }870                }871            }872        }873    }874875    fn suggest_self_or_self_ref(&mut self, err: &mut Diag<'_>, path: &[Segment], span: Span) {876        if !self.self_type_is_available() {877            return;878        }879        let Some(path_last_segment) = path.last() else { return };880        let item_str = path_last_segment.ident;881        // Emit help message for fake-self from other languages (e.g., `this` in JavaScript).882        if ["this", "my"].contains(&item_str.as_str()) {883            err.span_suggestion_short(884                span,885                "you might have meant to use `self` here instead",886                "self",887                Applicability::MaybeIncorrect,888            );889            if !self.self_value_is_available(path[0].ident.span) {890                if let Some((FnKind::Fn(_, _, ast::Fn { sig, .. }), fn_span)) =891                    &self.diag_metadata.current_function892                {893                    let (span, sugg) = if let Some(param) = sig.decl.inputs.get(0) {894                        (param.span.shrink_to_lo(), "&self, ")895                    } else {896                        (897                            self.r898                                .tcx899                                .sess900                                .source_map()901                                .span_through_char(*fn_span, '(')902                                .shrink_to_hi(),903                            "&self",904                        )905                    };906                    err.span_suggestion_verbose(907                        span,908                        "if you meant to use `self`, you are also missing a `self` receiver \909                         argument",910                        sugg,911                        Applicability::MaybeIncorrect,912                    );913                }914            }915        }916    }917918    fn try_lookup_name_relaxed(919        &mut self,920        err: &mut Diag<'_>,921        source: PathSource<'_, '_, '_>,922        path: &[Segment],923        following_seg: Option<&Segment>,924        span: Span,925        res: Option<Res>,926        base_error: &BaseError,927    ) -> (bool, FxHashSet<String>, Vec<ImportSuggestion>) {928        let span = match following_seg {929            Some(_) if path[0].ident.span.eq_ctxt(path[path.len() - 1].ident.span) => {930                // The path `span` that comes in includes any following segments, which we don't931                // want to replace in the suggestions.932                path[0].ident.span.to(path[path.len() - 1].ident.span)933            }934            _ => span,935        };936        let mut suggested_candidates = FxHashSet::default();937        // Try to lookup name in more relaxed fashion for better error reporting.938        let ident = path.last().unwrap().ident;939        let is_expected = &|res| source.is_expected(res);940        let ns = source.namespace();941        let is_enum_variant = &|res| matches!(res, Res::Def(DefKind::Variant, _));942        let path_str = Segment::names_to_string(path);943        let ident_span = path.last().map_or(span, |ident| ident.ident.span);944        let mut candidates = self945            .r946            .lookup_import_candidates(ident, ns, &self.parent_scope, is_expected)947            .into_iter()948            .filter(|ImportSuggestion { did, .. }| {949                match (did, res.and_then(|res| res.opt_def_id())) {950                    (Some(suggestion_did), Some(actual_did)) => *suggestion_did != actual_did,951                    _ => true,952                }953            })954            .collect::<Vec<_>>();955        // Try to filter out intrinsics candidates, as long as we have956        // some other candidates to suggest.957        let intrinsic_candidates: Vec<_> = candidates958            .extract_if(.., |sugg| {959                let path = path_names_to_string(&sugg.path);960                path.starts_with("core::intrinsics::") || path.starts_with("std::intrinsics::")961            })962            .collect();963        if candidates.is_empty() {964            // Put them back if we have no more candidates to suggest...965            candidates = intrinsic_candidates;966        }967        let crate_def_id = CRATE_DEF_ID.to_def_id();968        if candidates.is_empty() && is_expected(Res::Def(DefKind::Enum, crate_def_id)) {969            let mut enum_candidates: Vec<_> = self970                .r971                .lookup_import_candidates(ident, ns, &self.parent_scope, is_enum_variant)972                .into_iter()973                .map(|suggestion| import_candidate_to_enum_paths(&suggestion))974                .filter(|(_, enum_ty_path)| !enum_ty_path.starts_with("std::prelude::"))975                .collect();976            if !enum_candidates.is_empty() {977                enum_candidates.sort();978979                // Contextualize for E0425 "cannot find type", but don't belabor the point980                // (that it's a variant) for E0573 "expected type, found variant".981                let preamble = if res.is_none() {982                    let others = match enum_candidates.len() {983                        1 => String::new(),984                        2 => " and 1 other".to_owned(),985                        n => format!(" and {n} others"),986                    };987                    format!("there is an enum variant `{}`{}; ", enum_candidates[0].0, others)988                } else {989                    String::new()990                };991                let msg = format!("{preamble}try using the variant's enum");992993                suggested_candidates.extend(994                    enum_candidates995                        .iter()996                        .map(|(_variant_path, enum_ty_path)| enum_ty_path.clone()),997                );998                err.span_suggestions(999                    span,1000                    msg,1001                    enum_candidates.into_iter().map(|(_variant_path, enum_ty_path)| enum_ty_path),1002                    Applicability::MachineApplicable,1003                );1004            }1005        }10061007        // Try finding a suitable replacement.1008        let typo_sugg = self1009            .lookup_typo_candidate(path, following_seg, source.namespace(), is_expected)1010            .to_opt_suggestion()1011            .filter(|sugg| !suggested_candidates.contains(sugg.candidate.as_str()));1012        if let [segment] = path1013            && !matches!(source, PathSource::Delegation)1014            && self.self_type_is_available()1015        {1016            if let Some(candidate) =1017                self.lookup_assoc_candidate(ident, ns, is_expected, source.is_call())1018            {1019                let self_is_available = self.self_value_is_available(segment.ident.span);1020                // Account for `Foo { field }` when suggesting `self.field` so we result on1021                // `Foo { field: self.field }`.1022                let pre = match source {1023                    PathSource::Expr(Some(Expr { kind: ExprKind::Struct(expr), .. }))1024                        if expr1025                            .fields1026                            .iter()1027                            .any(|f| f.ident == segment.ident && f.is_shorthand) =>1028                    {1029                        format!("{path_str}: ")1030                    }1031                    _ => String::new(),1032                };1033                match candidate {1034                    AssocSuggestion::Field(field_span) => {1035                        if self_is_available {1036                            let source_map = self.r.tcx.sess.source_map();1037                            let field_is_format_named_arg = matches!(1038                                span.desugaring_kind(),1039                                Some(DesugaringKind::FormatLiteral { .. })1040                            ) && source_map1041                                .span_to_source(span, |s, start, _| {1042                                    Ok(s.get(start.saturating_sub(1)..start) == Some("{"))1043                                })1044                                .unwrap_or(false);1045                            if field_is_format_named_arg {1046                                err.help(1047                                    format!("you might have meant to use the available field in a format string: `\"{{}}\", self.{}`", segment.ident.name),1048                                );1049                            } else {1050                                err.span_suggestion_verbose(1051                                    span.shrink_to_lo(),1052                                    "you might have meant to use the available field",1053                                    format!("{pre}self."),1054                                    Applicability::MaybeIncorrect,1055                                );1056                            }1057                        } else {1058                            err.span_label(field_span, "a field by that name exists in `Self`");1059                        }1060                    }1061                    AssocSuggestion::MethodWithSelf { called } if self_is_available => {1062                        let msg = if called {1063                            "you might have meant to call the method"1064                        } else {1065                            "you might have meant to refer to the method"1066                        };1067                        err.span_suggestion_verbose(1068                            span.shrink_to_lo(),1069                            msg,1070                            "self.",1071                            Applicability::MachineApplicable,1072                        );1073                    }1074                    AssocSuggestion::MethodWithSelf { .. }1075                    | AssocSuggestion::AssocFn { .. }1076                    | AssocSuggestion::AssocConst1077                    | AssocSuggestion::AssocType => {1078                        err.span_suggestion_verbose(1079                            span.shrink_to_lo(),1080                            format!("you might have meant to {}", candidate.action()),1081                            "Self::",1082                            Applicability::MachineApplicable,1083                        );1084                    }1085                }1086                self.r.add_typo_suggestion(err, typo_sugg, ident_span);1087                return (true, suggested_candidates, candidates);1088            }10891090            // If the first argument in call is `self` suggest calling a method.1091            if let Some((call_span, args_span)) = self.call_has_self_arg(source) {1092                let mut args_snippet = String::new();1093                if let Some(args_span) = args_span1094                    && let Ok(snippet) = self.r.tcx.sess.source_map().span_to_snippet(args_span)1095                {1096                    args_snippet = snippet;1097                }10981099                if let Some(Res::Def(DefKind::Struct, def_id)) = res {1100                    if let Some(ctor) = self.r.struct_ctor(def_id)1101                        && ctor.has_private_fields(self.parent_scope.module, self.r)1102                    {1103                        if matches!(1104                            ctor.res,1105                            Res::Def(DefKind::Ctor(CtorOf::Struct, CtorKind::Fn), _)1106                        ) {1107                            self.update_err_for_private_tuple_struct_fields(err, &source, def_id);1108                        }1109                        err.note("constructor is not visible here due to private fields");1110                    }1111                } else {1112                    err.span_suggestion(1113                        call_span,1114                        format!("try calling `{ident}` as a method"),1115                        format!("self.{path_str}({args_snippet})"),1116                        Applicability::MachineApplicable,1117                    );1118                }11191120                return (true, suggested_candidates, candidates);1121            }1122        }11231124        // Try context-dependent help if relaxed lookup didn't work.1125        if let Some(res) = res {1126            if self.smart_resolve_context_dependent_help(1127                err,1128                span,1129                source,1130                path,1131                res,1132                &path_str,1133                &base_error.fallback_label,1134            ) {1135                // We do this to avoid losing a secondary span when we override the main error span.1136                self.r.add_typo_suggestion(err, typo_sugg, ident_span);1137                return (true, suggested_candidates, candidates);1138            }1139        }11401141        // Try to find in last block rib1142        if let Some(rib) = &self.last_block_rib {1143            for (ident, &res) in &rib.bindings {1144                if let Res::Local(_) = res1145                    && path.len() == 11146                    && ident.span.eq_ctxt(path[0].ident.span)1147                    && ident.name == path[0].ident.name1148                {1149                    err.span_help(1150                        ident.span,1151                        format!("the binding `{path_str}` is available in a different scope in the same function"),1152                    );1153                    return (true, suggested_candidates, candidates);1154                }1155            }1156        }11571158        if candidates.is_empty() {1159            candidates = self.smart_resolve_partial_mod_path_errors(path, following_seg);1160        }11611162        (false, suggested_candidates, candidates)1163    }11641165    fn lookup_doc_alias_name(&mut self, path: &[Segment], ns: Namespace) -> Option<(DefId, Ident)> {1166        let find_doc_alias_name = |r: &mut Resolver<'ra, '_>, m: Module<'ra>, item_name: Symbol| {1167            for resolution in r.resolutions(m).values() {1168                let Some(did) =1169                    resolution.borrow(r).best_decl().and_then(|binding| binding.res().opt_def_id())1170                else {1171                    continue;1172                };1173                if did.is_local() {1174                    // We don't record the doc alias name in the local crate1175                    // because the people who write doc alias are usually not1176                    // confused by them.1177                    continue;1178                }1179                if let Some(d) = hir::find_attr!(r.tcx, did, Doc(d) => d)1180                    && d.aliases.contains_key(&item_name)1181                {1182                    return Some(did);1183                }1184            }1185            None1186        };11871188        if path.len() == 1 {1189            for rib in self.ribs[ns].iter().rev() {1190                let item = path[0].ident;1191                if let RibKind::Module(module) | RibKind::Block(Some(module)) = rib.kind1192                    && let Some(did) = find_doc_alias_name(self.r, module.to_module(), item.name)1193                {1194                    return Some((did, item));1195                }1196            }1197        } else {1198            // Finds to the last resolved module item in the path1199            // and searches doc aliases within that module.1200            //1201            // Example: For the path `a::b::last_resolved::not_exist::c::d`,1202            // we will try to find any item has doc aliases named `not_exist`1203            // in `last_resolved` module.1204            //1205            // - Use `skip(1)` because the final segment must remain unresolved.1206            for (idx, seg) in path.iter().enumerate().rev().skip(1) {1207                let Some(id) = seg.id else {1208                    continue;1209                };1210                let Some(res) = self.r.partial_res_map.get(&id) else {1211                    continue;1212                };1213                if let Res::Def(DefKind::Mod, module) = res.expect_full_res()1214                    && let module = self.r.expect_module(module)1215                    && let item = path[idx + 1].ident1216                    && let Some(did) = find_doc_alias_name(self.r, module, item.name)1217                {1218                    return Some((did, item));1219                }1220                break;1221            }1222        }1223        None1224    }12251226    fn suggest_trait_and_bounds(1227        &self,1228        err: &mut Diag<'_>,1229        source: PathSource<'_, '_, '_>,1230        res: Option<Res>,1231        span: Span,1232        base_error: &BaseError,1233    ) -> bool {1234        let is_macro =1235            base_error.span.from_expansion() && base_error.span.desugaring_kind().is_none();1236        let mut fallback = false;12371238        if let (1239            PathSource::Trait(AliasPossibility::Maybe),1240            Some(Res::Def(DefKind::Struct | DefKind::Enum | DefKind::Union, _)),1241            false,1242        ) = (source, res, is_macro)1243            && let Some(bounds @ [first_bound, .., last_bound]) =1244                self.diag_metadata.current_trait_object1245        {1246            fallback = true;1247            let spans: Vec<Span> = bounds1248                .iter()1249                .map(|bound| bound.span())1250                .filter(|&sp| sp != base_error.span)1251                .collect();12521253            let start_span = first_bound.span();1254            // `end_span` is the end of the poly trait ref (Foo + 'baz + Bar><)1255            let end_span = last_bound.span();1256            // `last_bound_span` is the last bound of the poly trait ref (Foo + >'baz< + Bar)1257            let last_bound_span = spans.last().cloned().unwrap();1258            let mut multi_span: MultiSpan = spans.clone().into();1259            for sp in spans {1260                let msg = if sp == last_bound_span {1261                    format!(1262                        "...because of {these} bound{s}",1263                        these = pluralize!("this", bounds.len() - 1),1264                        s = pluralize!(bounds.len() - 1),1265                    )1266                } else {1267                    String::new()1268                };1269                multi_span.push_span_label(sp, msg);1270            }1271            multi_span.push_span_label(base_error.span, "expected this type to be a trait...");1272            err.span_help(1273                multi_span,1274                "`+` is used to constrain a \"trait object\" type with lifetimes or \1275                        auto-traits; structs and enums can't be bound in that way",1276            );1277            if bounds.iter().all(|bound| match bound {1278                ast::GenericBound::Outlives(_) | ast::GenericBound::Use(..) => true,1279                ast::GenericBound::Trait(tr) => tr.span == base_error.span,1280            }) {1281                let mut sugg = vec![];1282                if base_error.span != start_span {1283                    sugg.push((start_span.until(base_error.span), String::new()));1284                }1285                if base_error.span != end_span {1286                    sugg.push((base_error.span.shrink_to_hi().to(end_span), String::new()));1287                }12881289                err.multipart_suggestion(1290                    "if you meant to use a type and not a trait here, remove the bounds",1291                    sugg,1292                    Applicability::MaybeIncorrect,1293                );1294            }1295        }12961297        fallback |= self.restrict_assoc_type_in_where_clause(span, err);1298        fallback1299    }13001301    fn suggest_typo(1302        &mut self,1303        err: &mut Diag<'_>,1304        source: PathSource<'_, 'ast, 'ra>,1305        path: &[Segment],1306        following_seg: Option<&Segment>,1307        span: Span,1308        base_error: &BaseError,1309        suggested_candidates: FxHashSet<String>,1310    ) -> bool {1311        let is_expected = &|res| source.is_expected(res);1312        let ident_span = path.last().map_or(span, |ident| ident.ident.span);13131314        // Prefer suggestions based on associated types from in-scope bounds (e.g. `T::Item`)1315        // over purely edit-distance-based identifier suggestions.1316        // Otherwise suggestions could be verbose.1317        if self.suggest_assoc_type_from_bounds(err, source, path, ident_span) {1318            return false;1319        }13201321        let typo_sugg =1322            self.lookup_typo_candidate(path, following_seg, source.namespace(), is_expected);1323        let mut fallback = true;1324        let typo_sugg = typo_sugg1325            .to_opt_suggestion()1326            .filter(|sugg| !suggested_candidates.contains(sugg.candidate.as_str()));1327        self.r.add_typo_suggestion(err, typo_sugg, ident_span);13281329        match self.diag_metadata.current_let_binding {1330            Some((pat_sp, Some(ty_sp), None))1331                if ty_sp.contains(base_error.span) && base_error.could_be_expr =>1332            {1333                err.span_suggestion_verbose(1334                    pat_sp.between(ty_sp),1335                    "use `=` if you meant to assign",1336                    " = ",1337                    Applicability::MaybeIncorrect,1338                );1339            }1340            _ => {}1341        }13421343        // If the trait has a single item (which wasn't matched by the algorithm), suggest it1344        let suggestion = self.get_single_associated_item(path, &source, is_expected);1345        self.r.add_typo_suggestion(err, suggestion, ident_span);13461347        if self.let_binding_suggestion(err, ident_span) {1348            fallback = false;1349        }13501351        fallback1352    }13531354    fn suggest_shadowed(1355        &mut self,1356        err: &mut Diag<'_>,1357        source: PathSource<'_, '_, '_>,1358        path: &[Segment],1359        following_seg: Option<&Segment>,1360        span: Span,1361    ) -> bool {1362        let is_expected = &|res| source.is_expected(res);1363        let typo_sugg =1364            self.lookup_typo_candidate(path, following_seg, source.namespace(), is_expected);1365        let is_in_same_file = &|sp1, sp2| {1366            let source_map = self.r.tcx.sess.source_map();1367            let file1 = source_map.span_to_filename(sp1);1368            let file2 = source_map.span_to_filename(sp2);1369            file1 == file21370        };1371        // print 'you might have meant' if the candidate is (1) is a shadowed name with1372        // accessible definition and (2) either defined in the same crate as the typo1373        // (could be in a different file) or introduced in the same file as the typo1374        // (could belong to a different crate)1375        if let TypoCandidate::Shadowed(res, Some(sugg_span)) = typo_sugg1376            && res.opt_def_id().is_some_and(|id| id.is_local() || is_in_same_file(span, sugg_span))1377        {1378            err.span_label(1379                sugg_span,1380                format!("you might have meant to refer to this {}", res.descr()),1381            );1382            return true;1383        }1384        false1385    }13861387    fn err_code_special_cases(1388        &mut self,1389        err: &mut Diag<'_>,1390        source: PathSource<'_, '_, '_>,1391        path: &[Segment],1392        span: Span,1393    ) {1394        if let Some(err_code) = err.code {1395            if err_code == E0425 {1396                for label_rib in &self.label_ribs {1397                    for (label_ident, node_id) in &label_rib.bindings {1398                        let ident = path.last().unwrap().ident;1399                        if format!("'{ident}") == label_ident.to_string() {1400                            err.span_label(label_ident.span, "a label with a similar name exists");1401                            if let PathSource::Expr(Some(Expr {1402                                kind: ExprKind::Break(None, Some(_)),1403                                ..1404                            })) = source1405                            {1406                                err.span_suggestion(1407                                    span,1408                                    "use the similarly named label",1409                                    label_ident.name,1410                                    Applicability::MaybeIncorrect,1411                                );1412                                // Do not lint against unused label when we suggest them.1413                                self.diag_metadata.unused_labels.swap_remove(node_id);1414                            }1415                        }1416                    }1417                }14181419                self.suggest_ident_hidden_by_hygiene(err, path, span);1420                // cannot find type in this scope1421                if let Some(correct) = Self::likely_rust_type(path) {1422                    err.span_suggestion(1423                        span,1424                        "perhaps you intended to use this type",1425                        correct,1426                        Applicability::MaybeIncorrect,1427                    );1428                }1429            }1430        }1431    }14321433    fn suggest_ident_hidden_by_hygiene(&self, err: &mut Diag<'_>, path: &[Segment], span: Span) {1434        let [segment] = path else { return };14351436        let ident = segment.ident;1437        let callsite_span = span.source_callsite();1438        for rib in self.ribs[ValueNS].iter().rev() {1439            for (binding_ident, _) in &rib.bindings {1440                // Case 1: the identifier is defined in the same scope as the macro is called1441                if binding_ident.name == ident.name1442                    && !binding_ident.span.eq_ctxt(span)1443                    && !binding_ident.span.from_expansion()1444                    && binding_ident.span.lo() < callsite_span.lo()1445                {1446                    err.span_help(1447                        binding_ident.span,1448                        "an identifier with the same name exists, but is not accessible due to macro hygiene",1449                    );1450                    return;1451                }14521453                // Case 2: the identifier is defined in a macro call in the same scope1454                if binding_ident.name == ident.name1455                    && binding_ident.span.from_expansion()1456                    && binding_ident.span.source_callsite().eq_ctxt(callsite_span)1457                    && binding_ident.span.source_callsite().lo() < callsite_span.lo()1458                {1459                    err.span_help(1460                        binding_ident.span,1461                        "an identifier with the same name is defined here, but is not accessible due to macro hygiene",1462                    );1463                    return;1464                }1465            }1466        }1467    }14681469    /// Emit special messages for unresolved `Self` and `self`.1470    fn suggest_self_ty(1471        &self,1472        err: &mut Diag<'_>,1473        source: PathSource<'_, '_, '_>,1474        path: &[Segment],1475        span: Span,1476    ) -> bool {1477        if !is_self_type(path, source.namespace()) {1478            return false;1479        }1480        err.code(E0411);1481        err.span_label(span, "`Self` is only available in impls, traits, and type definitions");1482        if let Some(item) = self.diag_metadata.current_item1483            && let Some(ident) = item.kind.ident()1484        {1485            err.span_label(1486                ident.span,1487                format!("`Self` not allowed in {} {}", item.kind.article(), item.kind.descr()),1488            );1489        }1490        true1491    }14921493    fn suggest_self_value(1494        &mut self,1495        err: &mut Diag<'_>,1496        source: PathSource<'_, '_, '_>,1497        path: &[Segment],1498        span: Span,1499    ) -> bool {1500        if !is_self_value(path, source.namespace()) {1501            return false;1502        }15031504        debug!("smart_resolve_path_fragment: E0424, source={:?}", source);1505        err.code(E0424);1506        err.span_label(1507            span,1508            match source {1509                PathSource::Pat => {1510                    "`self` value is a keyword and may not be bound to variables or shadowed"1511                }1512                _ => "`self` value is a keyword only available in methods with a `self` parameter",1513            },1514        );15151516        // using `let self` is wrong even if we're not in an associated method or if we're in a macro expansion.1517        // So, we should return early if we're in a pattern, see issue #143134.1518        if matches!(source, PathSource::Pat) {1519            return true;1520        }15211522        let is_assoc_fn = self.self_type_is_available();1523        let self_from_macro = "a `self` parameter, but a macro invocation can only \1524                               access identifiers it receives from parameters";1525        if let Some((fn_kind, fn_span)) = &self.diag_metadata.current_function {1526            // The current function has a `self` parameter, but we were unable to resolve1527            // a reference to `self`. This can only happen if the `self` identifier we1528            // are resolving came from a different hygiene context or a variable binding.1529            // But variable binding error is returned early above.1530            if fn_kind.decl().inputs.get(0).is_some_and(|p| p.is_self()) {1531                err.span_label(*fn_span, format!("this function has {self_from_macro}"));1532            } else {1533                let doesnt = if is_assoc_fn {1534                    let (span, sugg) = fn_kind1535                        .decl()1536                        .inputs1537                        .get(0)1538                        .map(|p| (p.span.shrink_to_lo(), "&self, "))1539                        .unwrap_or_else(|| {1540                            // Try to look for the "(" after the function name, if possible.1541                            // This avoids placing the suggestion into the visibility specifier.1542                            let span = fn_kind1543                                .ident()1544                                .map_or(*fn_span, |ident| fn_span.with_lo(ident.span.hi()));1545                            (1546                                self.r1547                                    .tcx1548                                    .sess1549                                    .source_map()1550                                    .span_through_char(span, '(')1551                                    .shrink_to_hi(),1552                                "&self",1553                            )1554                        });1555                    err.span_suggestion_verbose(1556                        span,1557                        "add a `self` receiver parameter to make the associated `fn` a method",1558                        sugg,1559                        Applicability::MaybeIncorrect,1560                    );1561                    "doesn't"1562                } else {1563                    "can't"1564                };1565                if let Some(ident) = fn_kind.ident() {1566                    err.span_label(1567                        ident.span,1568                        format!("this function {doesnt} have a `self` parameter"),1569                    );1570                }1571            }1572        } else if let Some(item) = self.diag_metadata.current_item {1573            if matches!(item.kind, ItemKind::Delegation(..)) {1574                err.span_label(item.span, format!("delegation supports {self_from_macro}"));1575            } else {1576                let span = if let Some(ident) = item.kind.ident() { ident.span } else { item.span };1577                err.span_label(1578                    span,1579                    format!("`self` not allowed in {} {}", item.kind.article(), item.kind.descr()),1580                );1581            }1582        }1583        true1584    }15851586    fn detect_missing_binding_available_from_pattern(1587        &self,1588        err: &mut Diag<'_>,1589        path: &[Segment],1590        following_seg: Option<&Segment>,1591    ) {1592        let [segment] = path else { return };1593        let None = following_seg else { return };1594        for rib in self.ribs[ValueNS].iter().rev() {1595            let patterns_with_skipped_bindings =1596                self.r.tcx.with_stable_hashing_context(|mut hcx| {1597                    rib.patterns_with_skipped_bindings.to_sorted(&mut hcx, true)1598                });1599            for (def_id, spans) in patterns_with_skipped_bindings {1600                if let DefKind::Struct | DefKind::Variant = self.r.tcx.def_kind(*def_id)1601                    && let Some(fields) = self.r.field_idents(*def_id)1602                {1603                    for field in fields {1604                        if field.name == segment.ident.name {1605                            if spans.iter().all(|(_, had_error)| had_error.is_err()) {1606                                // This resolution error will likely be fixed by fixing a1607                                // syntax error in a pattern, so it is irrelevant to the user.1608                                let multispan: MultiSpan =1609                                    spans.iter().map(|(s, _)| *s).collect::<Vec<_>>().into();1610                                err.span_note(1611                                    multispan,1612                                    "this pattern had a recovered parse error which likely lost \1613                                     the expected fields",1614                                );1615                                err.downgrade_to_delayed_bug();1616                            }1617                            let ty = self.r.tcx.item_name(*def_id);1618                            for (span, _) in spans {1619                                err.span_label(1620                                    *span,1621                                    format!(1622                                        "this pattern doesn't include `{field}`, which is \1623                                         available in `{ty}`",1624                                    ),1625                                );1626                            }1627                        }1628                    }1629                }1630            }1631        }1632    }16331634    fn suggest_at_operator_in_slice_pat_with_range(&self, err: &mut Diag<'_>, path: &[Segment]) {1635        let Some(pat) = self.diag_metadata.current_pat else { return };1636        let (bound, side, range) = match &pat.kind {1637            ast::PatKind::Range(Some(bound), None, range) => (bound, Side::Start, range),1638            ast::PatKind::Range(None, Some(bound), range) => (bound, Side::End, range),1639            _ => return,1640        };1641        if let ExprKind::Path(None, range_path) = &bound.kind1642            && let [segment] = &range_path.segments[..]1643            && let [s] = path1644            && segment.ident == s.ident1645            && segment.ident.span.eq_ctxt(range.span)1646        {1647            // We've encountered `[first, rest..]` (#88404) or `[first, ..rest]` (#120591)1648            // where the user might have meant `[first, rest @ ..]`.1649            let (span, snippet) = match side {1650                Side::Start => (segment.ident.span.between(range.span), " @ ".into()),1651                Side::End => (range.span.to(segment.ident.span), format!("{} @ ..", segment.ident)),1652            };1653            err.subdiagnostic(diagnostics::UnexpectedResUseAtOpInSlicePatWithRangeSugg {1654                span,1655                ident: segment.ident,1656                snippet,1657            });1658        }16591660        enum Side {1661            Start,1662            End,1663        }1664    }16651666    fn suggest_range_struct_destructuring(1667        &mut self,1668        err: &mut Diag<'_>,1669        path: &[Segment],1670        source: PathSource<'_, '_, '_>,1671    ) {1672        if !matches!(source, PathSource::Pat | PathSource::TupleStruct(..) | PathSource::Expr(..)) {1673            return;1674        }16751676        let Some(pat) = self.diag_metadata.current_pat else { return };1677        let ast::PatKind::Range(start, end, end_kind) = &pat.kind else { return };16781679        let [segment] = path else { return };1680        let failing_span = segment.ident.span;16811682        let in_start = start.as_ref().is_some_and(|e| e.span.contains(failing_span));1683        let in_end = end.as_ref().is_some_and(|e| e.span.contains(failing_span));16841685        if !in_start && !in_end {1686            return;1687        }16881689        let start_snippet =1690            start.as_ref().and_then(|e| self.r.tcx.sess.source_map().span_to_snippet(e.span).ok());1691        let end_snippet =1692            end.as_ref().and_then(|e| self.r.tcx.sess.source_map().span_to_snippet(e.span).ok());16931694        let field = |name: &str, val: String| {1695            if val == name { val } else { format!("{name}: {val}") }1696        };16971698        let mut resolve_short_name = |short: Symbol, full: &str| -> String {1699            let ident = Ident::with_dummy_span(short);1700            let path = Segment::from_path(&Path::from_ident(ident));17011702            match self.resolve_path(&path, Some(TypeNS), None, PathSource::Type) {1703                PathResult::NonModule(..) => short.to_string(),1704                _ => full.to_string(),1705            }1706        };1707        // FIXME(new_range): Also account for new range types1708        let (struct_path, fields) = match (start_snippet, end_snippet, &end_kind.node) {1709            (Some(start), Some(end), ast::RangeEnd::Excluded) => (1710                resolve_short_name(sym::Range, "std::ops::Range"),1711                vec![field("start", start), field("end", end)],1712            ),1713            (Some(start), Some(end), ast::RangeEnd::Included(_)) => (1714                resolve_short_name(sym::RangeInclusive, "std::ops::RangeInclusive"),1715                vec![field("start", start), field("end", end)],1716            ),1717            (Some(start), None, _) => (1718                resolve_short_name(sym::RangeFrom, "std::ops::RangeFrom"),1719                vec![field("start", start)],1720            ),1721            (None, Some(end), ast::RangeEnd::Excluded) => {1722                (resolve_short_name(sym::RangeTo, "std::ops::RangeTo"), vec![field("end", end)])1723            }1724            (None, Some(end), ast::RangeEnd::Included(_)) => (1725                resolve_short_name(sym::RangeToInclusive, "std::ops::RangeToInclusive"),1726                vec![field("end", end)],1727            ),1728            _ => return,1729        };17301731        err.span_suggestion_verbose(1732            pat.span,1733            format!("if you meant to destructure a range use a struct pattern"),1734            format!("{} {{ {} }}", struct_path, fields.join(", ")),1735            Applicability::MaybeIncorrect,1736        );17371738        err.note(1739            "range patterns match against the start and end of a range; \1740             to bind the components, use a struct pattern",1741        );1742    }17431744    fn suggest_swapping_misplaced_self_ty_and_trait(1745        &mut self,1746        err: &mut Diag<'_>,1747        source: PathSource<'_, 'ast, 'ra>,1748        res: Option<Res>,1749        span: Span,1750    ) {1751        if let Some((trait_ref, self_ty)) =1752            self.diag_metadata.currently_processing_impl_trait.clone()1753            && let TyKind::Path(_, self_ty_path) = &self_ty.kind1754            && let PathResult::Module(ModuleOrUniformRoot::Module(module)) =1755                self.resolve_path(&Segment::from_path(self_ty_path), Some(TypeNS), None, source)1756            && module.def_kind() == Some(DefKind::Trait)1757            && trait_ref.path.span == span1758            && let PathSource::Trait(_) = source1759            && let Some(Res::Def(DefKind::Struct | DefKind::Enum | DefKind::Union, _)) = res1760            && let Ok(self_ty_str) = self.r.tcx.sess.source_map().span_to_snippet(self_ty.span)1761            && let Ok(trait_ref_str) =1762                self.r.tcx.sess.source_map().span_to_snippet(trait_ref.path.span)1763        {1764            err.multipart_suggestion(1765                    "`impl` items mention the trait being implemented first and the type it is being implemented for second",1766                    vec![(trait_ref.path.span, self_ty_str), (self_ty.span, trait_ref_str)],1767                    Applicability::MaybeIncorrect,1768                );1769        }1770    }17711772    fn explain_functions_in_pattern(1773        &self,1774        err: &mut Diag<'_>,1775        res: Option<Res>,1776        source: PathSource<'_, '_, '_>,1777    ) {1778        let PathSource::TupleStruct(_, _) = source else { return };1779        let Some(Res::Def(DefKind::Fn, _)) = res else { return };1780        err.primary_message("expected a pattern, found a function call");1781        err.note("function calls are not allowed in patterns: <https://doc.rust-lang.org/book/ch19-00-patterns.html>");1782    }17831784    fn suggest_changing_type_to_const_param(1785        &self,1786        err: &mut Diag<'_>,1787        res: Option<Res>,1788        source: PathSource<'_, '_, '_>,1789        path: &[Segment],1790        following_seg: Option<&Segment>,1791        span: Span,1792    ) {1793        if let PathSource::Expr(None) = source1794            && let Some(Res::Def(DefKind::TyParam, _)) = res1795            && following_seg.is_none()1796            && let [segment] = path1797        {1798            // We have something like1799            // impl<T, N> From<[T; N]> for VecWrapper<T> {1800            //     fn from(slice: [T; N]) -> Self {1801            //         VecWrapper(slice.to_vec())1802            //     }1803            // }1804            // where `N` is a type param but should likely have been a const param.1805            let Some(item) = self.diag_metadata.current_item else { return };1806            let Some(generics) = item.kind.generics() else { return };1807            let Some(span) = generics.params.iter().find_map(|param| {1808                // Only consider type params with no bounds.1809                if param.bounds.is_empty() && param.ident.name == segment.ident.name {1810                    Some(param.ident.span)1811                } else {1812                    None1813                }1814            }) else {1815                return;1816            };1817            err.subdiagnostic(diagnostics::UnexpectedResChangeTyParamToConstParamSugg {1818                before: span.shrink_to_lo(),1819                after: span.shrink_to_hi(),1820            });1821            return;1822        }1823        let PathSource::Trait(_) = source else { return };18241825        // We don't include `DefKind::Str` and `DefKind::AssocTy` as they can't be reached here anyway.1826        let applicability = match res {1827            Some(Res::PrimTy(PrimTy::Int(_) | PrimTy::Uint(_) | PrimTy::Bool | PrimTy::Char)) => {1828                Applicability::MachineApplicable1829            }1830            // FIXME(const_generics): Add `DefKind::TyParam` and `SelfTyParam` once we support generic1831            // const generics. Of course, `Struct` and `Enum` may contain ty params, too, but the1832            // benefits of including them here outweighs the small number of false positives.1833            Some(Res::Def(DefKind::Struct | DefKind::Enum, _))1834                if self.r.features.adt_const_params() || self.r.features.min_adt_const_params() =>1835            {1836                Applicability::MaybeIncorrect1837            }1838            _ => return,1839        };18401841        let Some(item) = self.diag_metadata.current_item else { return };1842        let Some(generics) = item.kind.generics() else { return };18431844        let param = generics.params.iter().find_map(|param| {1845            // Only consider type params with exactly one trait bound.1846            if let [bound] = &*param.bounds1847                && let ast::GenericBound::Trait(tref) = bound1848                && tref.modifiers == ast::TraitBoundModifiers::NONE1849                && tref.span == span1850                && param.ident.span.eq_ctxt(span)1851            {1852                Some(param.ident.span)1853            } else {1854                None1855            }1856        });18571858        if let Some(param) = param {1859            err.subdiagnostic(diagnostics::UnexpectedResChangeTyToConstParamSugg {1860                span: param.shrink_to_lo(),1861                applicability,1862            });1863        }1864    }18651866    fn suggest_pattern_match_with_let(1867        &self,1868        err: &mut Diag<'_>,1869        source: PathSource<'_, '_, '_>,1870        span: Span,1871    ) -> bool {1872        if let PathSource::Expr(_) = source1873            && let Some(Expr { span: expr_span, kind: ExprKind::Assign(lhs, _, _), .. }) =1874                self.diag_metadata.in_if_condition1875        {1876            // Icky heuristic so we don't suggest:1877            // `if (i + 2) = 2` => `if let (i + 2) = 2` (approximately pattern)1878            // `if 2 = i` => `if let 2 = i` (lhs needs to contain error span)1879            if lhs.is_approximately_pattern() && lhs.span.contains(span) {1880                err.span_suggestion_verbose(1881                    expr_span.shrink_to_lo(),1882                    "you might have meant to use pattern matching",1883                    "let ",1884                    Applicability::MaybeIncorrect,1885                );1886                return true;1887            }1888        }1889        false1890    }18911892    fn get_single_associated_item(1893        &mut self,1894        path: &[Segment],1895        source: &PathSource<'_, 'ast, 'ra>,1896        filter_fn: &impl Fn(Res) -> bool,1897    ) -> Option<TypoSuggestion> {1898        if let crate::PathSource::TraitItem(_, _) = source {1899            let mod_path = &path[..path.len() - 1];1900            if let PathResult::Module(ModuleOrUniformRoot::Module(module)) =1901                self.resolve_path(mod_path, None, None, *source)1902            {1903                let targets: Vec<_> = self1904                    .r1905                    .resolutions(module)1906                    .iter()1907                    .filter_map(|(key, resolution)| {1908                        let resolution = resolution.borrow(self.r);1909                        resolution.best_decl().map(|binding| binding.res()).and_then(|res| {1910                            if filter_fn(res) {1911                                Some((key.ident.name, resolution.orig_ident_span, res))1912                            } else {1913                                None1914                            }1915                        })1916                    })1917                    .collect();1918                if let &[(name, orig_ident_span, res)] = targets.as_slice() {1919                    return Some(TypoSuggestion::single_item(name, orig_ident_span, res));1920                }1921            }1922        }1923        None1924    }19251926    /// Given `where <T as Bar>::Baz: String`, suggest `where T: Bar<Baz = String>`.1927    fn restrict_assoc_type_in_where_clause(&self, span: Span, err: &mut Diag<'_>) -> bool {1928        // Detect that we are actually in a `where` predicate.1929        let Some(ast::WherePredicate {1930            kind:1931                ast::WherePredicateKind::BoundPredicate(ast::WhereBoundPredicate {1932                    bounded_ty,1933                    bound_generic_params,1934                    bounds,1935                }),1936            span: where_span,1937            ..1938        }) = self.diag_metadata.current_where_predicate1939        else {1940            return false;1941        };1942        if !bound_generic_params.is_empty() {1943            return false;1944        }19451946        // Confirm that the target is an associated type.1947        let ast::TyKind::Path(Some(qself), path) = &bounded_ty.kind else { return false };1948        // use this to verify that ident is a type param.1949        let Some(partial_res) = self.r.partial_res_map.get(&bounded_ty.id) else { return false };1950        if !matches!(partial_res.full_res(), Some(Res::Def(DefKind::AssocTy, _))) {1951            return false;1952        }19531954        let peeled_ty = qself.ty.peel_refs();1955        let ast::TyKind::Path(None, type_param_path) = &peeled_ty.kind else { return false };1956        // Confirm that the `SelfTy` is a type parameter.1957        let Some(partial_res) = self.r.partial_res_map.get(&peeled_ty.id) else {1958            return false;1959        };1960        if !matches!(partial_res.full_res(), Some(Res::Def(DefKind::TyParam, _))) {1961            return false;1962        }1963        let ([ast::PathSegment { args: None, .. }], [ast::GenericBound::Trait(poly_trait_ref)]) =1964            (&type_param_path.segments[..], &bounds[..])1965        else {1966            return false;1967        };1968        let [ast::PathSegment { ident, args: None, id }] =1969            &poly_trait_ref.trait_ref.path.segments[..]1970        else {1971            return false;1972        };1973        if poly_trait_ref.modifiers != ast::TraitBoundModifiers::NONE {1974            return false;1975        }1976        if ident.span == span {1977            let Some(partial_res) = self.r.partial_res_map.get(&id) else {1978                return false;1979            };1980            if !matches!(partial_res.full_res(), Some(Res::Def(..))) {1981                return false;1982            }19831984            let Some(new_where_bound_predicate) =1985                mk_where_bound_predicate(path, poly_trait_ref, &qself.ty)1986            else {1987                return false;1988            };1989            err.span_suggestion_verbose(1990                *where_span,1991                format!("constrain the associated type to `{ident}`"),1992                where_bound_predicate_to_string(&new_where_bound_predicate),1993                Applicability::MaybeIncorrect,1994            );1995        }1996        true1997    }19981999    /// Check if the source is call expression and the first argument is `self`. If true,2000    /// return the span of whole call and the span for all arguments expect the first one (`self`).

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.