compiler/rustc_resolve/src/late/diagnostics.rs RUST 4,873 lines View on github.com → Search inside
File is large — showing lines 1–2,000 of 4,873.
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_attr_ir::diagnostic::{CustomDiagnostic, FormatArgs};15use rustc_attr_ir::find_attr;16use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet};17use rustc_data_structures::unord::UnordItems;18use rustc_errors::codes::*;19use rustc_errors::{20    Applicability, Diag, Diagnostic, ErrorGuaranteed, MultiSpan, SuggestionStyle, pluralize,21    struct_span_code_err,22};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};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, 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,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, 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((this, directive)) = self.r.on_unknown_data(module_def_id)562            {563                let args =564                    FormatArgs { unresolved: item_ident.to_string(), this: this.to_string(), .. };565                let CustomDiagnostic {566                    message,567                    label,568                    notes: custom_notes,569                    parent_label: _unreachable,570                } = directive.eval(None, &args);571                if let Some(message) = message {572                    notes.push(msg);573                    msg = message;574                }575                if let Some(label) = label {576                    fallback_label = label;577                    if let Some((_, span_label)) = span_label.take() {578                        notes.push(span_label.to_string());579                    }580                }581                notes.extend(custom_notes);582            }583584            BaseError {585                msg,586                fallback_label,587                span: item_span,588                span_label,589                could_be_expr,590                suggestion,591                module,592                notes,593            }594        }595    }596597    fn could_be_expr(&self, res: Res, span: Span) -> bool {598        match res {599            // Verify whether this is a fn call or an Fn used as a type.600            Res::Def(DefKind::Fn, _) => self601                .r602                .tcx603                .sess604                .source_map()605                .span_to_snippet(span)606                .is_ok_and(|snippet| snippet.ends_with(')')),607            Res::Def(608                DefKind::Ctor(..) | DefKind::AssocFn | DefKind::Const | DefKind::AssocConst,609                _,610            )611            | Res::SelfCtor(_)612            | Res::PrimTy(_)613            | Res::Local(_) => true,614            _ => false,615        }616    }617618    /// Try to suggest for a module path that cannot be resolved.619    /// Such as `fmt::Debug` where `fmt` is not resolved without importing,620    /// here we search with `lookup_import_candidates` for a module named `fmt`621    /// with `TypeNS` as namespace.622    ///623    /// We need a separate function here because we won't suggest for a path with single segment624    /// and we won't change `SourcePath` api `is_expected` to match `Type` with `DefKind::Mod`625    pub(crate) fn smart_resolve_partial_mod_path_errors(626        &mut self,627        prefix_path: &[Segment],628        following_seg: Option<&Segment>,629    ) -> Vec<ImportSuggestion> {630        if let Some(segment) = prefix_path.last()631            && let Some(following_seg) = following_seg632        {633            let candidates = self.r.lookup_import_candidates(634                segment.ident,635                Namespace::TypeNS,636                &self.parent_scope,637                &|res: Res| matches!(res, Res::Def(DefKind::Mod, _)),638            );639            // double check next seg is valid640            candidates641                .into_iter()642                .filter(|candidate| {643                    if let Some(def_id) = candidate.did644                        && let Some(module) = self.r.get_module(def_id)645                    {646                        Some(def_id) != self.parent_scope.module.opt_def_id()647                            && self648                                .r649                                .resolutions(module)650                                .iter()651                                .any(|(key, _r)| key.ident.name == following_seg.ident.name)652                    } else {653                        false654                    }655                })656                .collect::<Vec<_>>()657        } else {658            Vec::new()659        }660    }661662    /// Handles error reporting for `smart_resolve_path_fragment` function.663    /// Creates base error and amends it with one short label and possibly some longer helps/notes.664    #[tracing::instrument(skip(self), level = "debug")]665    pub(crate) fn smart_resolve_report_errors(666        &mut self,667        path: &[Segment],668        following_seg: Option<&Segment>,669        span: Span,670        mut source: PathSource<'_, 'ast, 'ra>,671        res: Option<Res>,672        qself: Option<&QSelf>,673    ) -> (Diag<'tcx>, Vec<ImportSuggestion>) {674        let cross_namespace_res = res.filter(|res| !res.matches_ns(source.namespace()));675        let could_be_expr = res.is_some_and(|res| self.could_be_expr(res, span));676        let base_error = self.make_base_error(677            path,678            span,679            source,680            if cross_namespace_res.is_some() { None } else { res },681            could_be_expr,682        );683684        let code = source.error_code(res.is_some());685        let mut err = self.r.dcx().struct_span_err(base_error.span, base_error.msg.clone());686        err.code(code);687688        if self.diag_metadata.currently_processing_generic_args689            && let PathSource::Type = source690            && let [segment] = path691            && !segment.has_generic_args692        {693            source = PathSource::TypeParam;694        }695696        if let Some(res) = cross_namespace_res {697            err.note(format!(698                "{} {} named `{}` exists in another namespace",699                res.article(),700                res.descr(),701                Segment::names_to_string(path),702            ));703        }704705        // Try to get the span of the identifier within the path's syntax context706        // (if that's different).707        if let Some(within_macro_span) =708            base_error.span.within_macro(span, self.r.tcx.sess.source_map())709        {710            err.span_label(within_macro_span, "due to this macro variable");711        }712713        self.detect_missing_binding_available_from_pattern(&mut err, path, following_seg);714        self.suggest_at_operator_in_slice_pat_with_range(&mut err, path);715        self.suggest_range_struct_destructuring(&mut err, path, source);716        self.suggest_swapping_misplaced_self_ty_and_trait(&mut err, source, res, base_error.span);717        self.detect_resolution_error_in_derive(&mut err, base_error.span);718719        if let Some((span, label)) = base_error.span_label {720            err.span_label(span, label);721        }722        for note in &base_error.notes {723            err.note(note.clone());724        }725726        if let Some((span, message, replacement)) = &base_error.suggestion {727            let ident = path.last().unwrap().ident;728            // An insertion adds a qualifier (`Self::CONST`), whereas a replacement729            // replaces the name itself (`True` -> `true`).730            let expression =731                if span.is_empty() { format!("{replacement}{ident}") } else { replacement.clone() };732            if !self.suggest_named_format_argument(733                &mut err,734                source,735                ident,736                &expression,737                Applicability::MaybeIncorrect,738            ) {739                err.span_suggestion_verbose(740                    *span,741                    *message,742                    replacement,743                    Applicability::MaybeIncorrect,744                );745            }746        }747748        self.suggest_changing_type_to_const_param(&mut err, res, source, path, following_seg, span);749        self.explain_functions_in_pattern(&mut err, res, source);750751        if self.suggest_pattern_match_with_let(&mut err, source, span) {752            // Fallback label.753            err.span_label(base_error.span, base_error.fallback_label);754            return (err, Vec::new());755        }756757        self.suggest_self_or_self_ref(&mut err, path, span);758        self.detect_assoc_type_constraint_meant_as_path(&mut err, &base_error);759        self.detect_rtn_with_fully_qualified_path(760            &mut err,761            path,762            following_seg,763            span,764            source,765            res,766            qself,767        );768        if self.suggest_self_ty(&mut err, source, path, span)769            || self.suggest_self_value(&mut err, source, path, span)770        {771            return (err, Vec::new());772        }773774        if let Some((did, item)) = self.lookup_doc_alias_name(path, source.namespace()) {775            let item_name = item.name;776            let suggestion_name = self.r.tcx.item_name(did);777            err.span_suggestion_verbose(778                item.span,779                format!(780                    "`{suggestion_name}` has a name defined in the doc alias attribute as \781                     `{item_name}`",782                ),783                suggestion_name,784                Applicability::MaybeIncorrect,785            );786787            return (err, Vec::new());788        };789790        let (found, suggested_candidates, mut candidates) = self.try_lookup_name_relaxed(791            &mut err,792            source,793            path,794            following_seg,795            span,796            res,797            &base_error,798        );799        if found {800            return (err, candidates);801        }802803        if self.suggest_shadowed(&mut err, source, path, following_seg, span) {804            // if there is already a shadowed name, don'suggest candidates for importing805            candidates.clear();806        }807808        let mut fallback = self.suggest_trait_and_bounds(&mut err, source, res, span, &base_error);809        fallback |= self.suggest_typo(810            &mut err,811            source,812            path,813            following_seg,814            span,815            &base_error,816            suggested_candidates,817        );818819        if fallback {820            // Fallback label.821            err.span_label(base_error.span, base_error.fallback_label);822        }823        self.err_code_special_cases(&mut err, source, path, span);824825        let module = base_error.module.unwrap_or_else(|| CRATE_DEF_ID.to_def_id());826        self.r.find_cfg_stripped(&mut err, &path.last().unwrap().ident.name, module);827828        (err, candidates)829    }830831    /// Captures only accept identifiers, so put the suggested expression in a named argument.832    fn suggest_named_format_argument(833        &self,834        err: &mut Diag<'_>,835        source: PathSource<'_, '_, '_>,836        ident: Ident,837        expression: &str,838        applicability: Applicability,839    ) -> bool {840        let PathSource::Expr(Some(Expr {841            kind: ExprKind::FormatArgs(args),842            span: format_span,843            ..844        })) = source845        else {846            return false;847        };848        let argument = format!("{ident} = {expression}");849        let insertion = args850            .arguments851            .explicit_args()852            .last()853            .map_or(args.span, |arg| arg.original_span)854            .shrink_to_hi();855        // A custom wrapper may not accept another named argument.856        let source_macro = format_span857            .source_callee()858            .and_then(|expn| expn.macro_def_id)859            // Local diagnostic items are not available before HIR lowering.860            .filter(|def_id| !def_id.is_local())861            .and_then(|def_id| self.r.tcx.get_diagnostic_name(def_id));862        if matches!(863            source_macro,864            Some(865                sym::format_macro866                    | sym::format_args_macro867                    | sym::print_macro868                    | sym::println_macro869                    | sym::eprint_macro870                    | sym::eprintln_macro871                    | sym::write_macro872                    | sym::writeln_macro873                    | sym::assert_macro874                    | sym::assert_eq_macro875                    | sym::assert_ne_macro876                    | sym::debug_assert_macro877                    | sym::debug_assert_eq_macro878                    | sym::debug_assert_ne_macro879                    | sym::core_panic_macro880                    | sym::std_panic_macro881                    | sym::unreachable_macro882                    | sym::todo_macro883                    | sym::unimplemented_macro884            )885        ) && !insertion.from_expansion()886            && !args.span.from_expansion()887        {888            err.span_suggestion_verbose(889                insertion,890                "you might have meant to add a named formatting argument",891                format!(", {argument}"),892                applicability,893            );894        } else {895            err.help(format!(896                "you might have meant to add a named formatting argument: `{argument}`"897            ));898        }899        true900    }901902    fn detect_rtn_with_fully_qualified_path(903        &self,904        err: &mut Diag<'_>,905        path: &[Segment],906        following_seg: Option<&Segment>,907        span: Span,908        source: PathSource<'_, '_, '_>,909        res: Option<Res>,910        qself: Option<&QSelf>,911    ) {912        if let Some(Res::Def(DefKind::AssocFn, _)) = res913            && let PathSource::TraitItem(TypeNS, _) = source914            && let None = following_seg915            && let Some(qself) = qself916            && let TyKind::Path(None, ty_path) = &qself.ty.kind917            && ty_path.segments.len() == 1918            && self.diag_metadata.current_where_predicate.is_some()919        {920            err.span_suggestion_verbose(921                span,922                "you might have meant to use the return type notation syntax",923                format!("{}::{}(..)", ty_path.segments[0].ident, path[path.len() - 1].ident),924                Applicability::MaybeIncorrect,925            );926        }927    }928929    fn detect_assoc_type_constraint_meant_as_path(930        &self,931        err: &mut Diag<'_>,932        base_error: &BaseError,933    ) {934        let Some(ty) = self.diag_metadata.current_type_path else {935            return;936        };937        let TyKind::Path(_, path) = &ty.kind else {938            return;939        };940        for segment in &path.segments {941            let Some(params) = &segment.args else {942                continue;943            };944            let ast::GenericArgs::AngleBracketed(params) = params.deref() else {945                continue;946            };947            for param in &params.args {948                let ast::AngleBracketedArg::Constraint(constraint) = param else {949                    continue;950                };951                let ast::AssocItemConstraintKind::Bound { bounds } = &constraint.kind else {952                    continue;953                };954                for bound in bounds {955                    let ast::GenericBound::Trait(trait_ref) = bound else {956                        continue;957                    };958                    if trait_ref.modifiers == ast::TraitBoundModifiers::NONE959                        && base_error.span == trait_ref.span960                    {961                        err.span_suggestion_verbose(962                            constraint.ident.span.between(trait_ref.span),963                            "you might have meant to write a path instead of an associated type bound",964                            "::",965                            Applicability::MachineApplicable,966                        );967                    }968                }969            }970        }971    }972973    fn suggest_self_or_self_ref(&mut self, err: &mut Diag<'_>, path: &[Segment], span: Span) {974        if !self.self_type_is_available() {975            return;976        }977        let Some(path_last_segment) = path.last() else { return };978        let item_str = path_last_segment.ident;979        // Emit help message for fake-self from other languages (e.g., `this` in JavaScript).980        if ["this", "my"].contains(&item_str.as_str()) {981            err.span_suggestion_short(982                span,983                "you might have meant to use `self` here instead",984                "self",985                Applicability::MaybeIncorrect,986            );987            if !self.self_value_is_available(path[0].ident.span) {988                if let Some((FnKind::Fn(_, _, ast::Fn { sig, .. }), fn_span)) =989                    &self.diag_metadata.current_function990                {991                    let (span, sugg) = if let Some(param) = sig.decl.inputs.get(0) {992                        (param.span.shrink_to_lo(), "&self, ")993                    } else {994                        (995                            self.r996                                .tcx997                                .sess998                                .source_map()999                                .span_through_char(*fn_span, '(')1000                                .shrink_to_hi(),1001                            "&self",1002                        )1003                    };1004                    err.span_suggestion_verbose(1005                        span,1006                        "if you meant to use `self`, you are also missing a `self` receiver \1007                         argument",1008                        sugg,1009                        Applicability::MaybeIncorrect,1010                    );1011                }1012            }1013        }1014    }10151016    fn try_lookup_name_relaxed(1017        &mut self,1018        err: &mut Diag<'_>,1019        source: PathSource<'_, '_, '_>,1020        path: &[Segment],1021        following_seg: Option<&Segment>,1022        span: Span,1023        res: Option<Res>,1024        base_error: &BaseError,1025    ) -> (bool, FxHashSet<String>, Vec<ImportSuggestion>) {1026        let span = match following_seg {1027            Some(_) if path[0].ident.span.eq_ctxt(path[path.len() - 1].ident.span) => {1028                // The path `span` that comes in includes any following segments, which we don't1029                // want to replace in the suggestions.1030                path[0].ident.span.to(path[path.len() - 1].ident.span)1031            }1032            _ => span,1033        };1034        let mut suggested_candidates = FxHashSet::default();1035        // Try to lookup name in more relaxed fashion for better error reporting.1036        let ident = path.last().unwrap().ident;1037        let is_expected = &|res| source.is_expected(res);1038        let ns = source.namespace();1039        let is_enum_variant = &|res| matches!(res, Res::Def(DefKind::Variant, _));1040        let path_str = Segment::names_to_string(path);1041        let ident_span = path.last().map_or(span, |ident| ident.ident.span);1042        let mut candidates = self1043            .r1044            .lookup_import_candidates(ident, ns, &self.parent_scope, is_expected)1045            .into_iter()1046            .filter(|ImportSuggestion { did, .. }| {1047                match (did, res.and_then(|res| res.opt_def_id())) {1048                    (Some(suggestion_did), Some(actual_did)) => *suggestion_did != actual_did,1049                    _ => true,1050                }1051            })1052            .collect::<Vec<_>>();1053        // Try to filter out intrinsics candidates, as long as we have1054        // some other candidates to suggest.1055        let intrinsic_candidates: Vec<_> = candidates1056            .extract_if(.., |sugg| {1057                let path = path_names_to_string(&sugg.path);1058                path.starts_with("core::intrinsics::") || path.starts_with("std::intrinsics::")1059            })1060            .collect();1061        if candidates.is_empty() {1062            // Put them back if we have no more candidates to suggest...1063            candidates = intrinsic_candidates;1064        }1065        let crate_def_id = CRATE_DEF_ID.to_def_id();1066        if candidates.is_empty() && is_expected(Res::Def(DefKind::Enum, crate_def_id)) {1067            let mut enum_candidates: Vec<_> = self1068                .r1069                .lookup_import_candidates(ident, ns, &self.parent_scope, is_enum_variant)1070                .into_iter()1071                .map(|suggestion| import_candidate_to_enum_paths(&suggestion))1072                .filter(|(_, enum_ty_path)| !enum_ty_path.starts_with("std::prelude::"))1073                .collect();1074            if !enum_candidates.is_empty() {1075                enum_candidates.sort();10761077                // Contextualize for E0425 "cannot find type", but don't belabor the point1078                // (that it's a variant) for E0573 "expected type, found variant".1079                let preamble = if res.is_none() {1080                    let others = match enum_candidates.len() {1081                        1 => String::new(),1082                        2 => " and 1 other".to_owned(),1083                        n => format!(" and {n} others"),1084                    };1085                    format!("there is an enum variant `{}`{}; ", enum_candidates[0].0, others)1086                } else {1087                    String::new()1088                };1089                let msg = format!("{preamble}try using the variant's enum");10901091                suggested_candidates.extend(1092                    enum_candidates1093                        .iter()1094                        .map(|(_variant_path, enum_ty_path)| enum_ty_path.clone()),1095                );1096                err.span_suggestions(1097                    span,1098                    msg,1099                    enum_candidates.into_iter().map(|(_variant_path, enum_ty_path)| enum_ty_path),1100                    Applicability::MachineApplicable,1101                );1102            }1103        }11041105        // Try finding a suitable replacement.1106        let typo_sugg = self1107            .lookup_typo_candidate(path, following_seg, source.namespace(), is_expected)1108            .to_opt_suggestion()1109            .filter(|sugg| !suggested_candidates.contains(sugg.candidate.as_str()));1110        if let [segment] = path1111            && !matches!(source, PathSource::Delegation)1112            && self.self_type_is_available()1113        {1114            if let Some((candidate, def_span)) =1115                self.lookup_assoc_candidate(ident, ns, is_expected, source.is_call())1116            {1117                let self_is_available = self.self_value_is_available(segment.ident.span);1118                // Account for `Foo { field }` when suggesting `self.field` so we result on1119                // `Foo { field: self.field }`.1120                let pre = match source {1121                    PathSource::Expr(Some(Expr { kind: ExprKind::Struct(expr), .. }))1122                        if expr1123                            .fields1124                            .iter()1125                            .any(|f| f.ident == segment.ident && f.is_shorthand) =>1126                    {1127                        format!("{path_str}: ")1128                    }1129                    _ => String::new(),1130                };1131                match candidate {1132                    AssocSuggestion::Field => {1133                        if self_is_available {1134                            if !self.suggest_named_format_argument(1135                                err,1136                                source,1137                                segment.ident,1138                                &format!("self.{}", segment.ident),1139                                Applicability::MaybeIncorrect,1140                            ) {1141                                err.span_suggestion_verbose(1142                                    span.shrink_to_lo(),1143                                    "you might have meant to use the available field",1144                                    format!("{pre}self."),1145                                    Applicability::MaybeIncorrect,1146                                );1147                            }1148                        } else {1149                            err.span_label(def_span, "a field by that name exists in `Self`");1150                        }1151                    }1152                    AssocSuggestion::MethodWithSelf { .. }1153                    | AssocSuggestion::AssocFn { .. }1154                    | AssocSuggestion::AssocType1155                        if matches!(1156                            source,1157                            PathSource::Expr(Some(Expr { kind: ExprKind::FormatArgs(_), .. }))1158                        ) =>1159                    {1160                        let kind = match candidate {1161                            AssocSuggestion::MethodWithSelf { .. } => "a method",1162                            AssocSuggestion::AssocFn { .. } => "an associated function",1163                            AssocSuggestion::AssocType => "an associated type",1164                            _ => unreachable!(),1165                        };1166                        err.span_label(1167                            def_span,1168                            format!("{kind} by that name is available on `Self` here"),1169                        );1170                    }1171                    AssocSuggestion::MethodWithSelf { called } if self_is_available => {1172                        let msg = if called {1173                            "you might have meant to call the method"1174                        } else {1175                            "you might have meant to refer to the method"1176                        };1177                        err.span_suggestion_verbose(1178                            span.shrink_to_lo(),1179                            msg,1180                            "self.",1181                            Applicability::MachineApplicable,1182                        );1183                    }1184                    AssocSuggestion::MethodWithSelf { .. }1185                    | AssocSuggestion::AssocFn { .. }1186                    | AssocSuggestion::AssocConst1187                    | AssocSuggestion::AssocType => {1188                        if !matches!(candidate, AssocSuggestion::AssocConst)1189                            || !self.suggest_named_format_argument(1190                                err,1191                                source,1192                                segment.ident,1193                                &format!("Self::{}", segment.ident),1194                                Applicability::MaybeIncorrect,1195                            )1196                        {1197                            err.span_suggestion_verbose(1198                                span.shrink_to_lo(),1199                                format!("you might have meant to {}", candidate.action()),1200                                "Self::",1201                                Applicability::MachineApplicable,1202                            );1203                        }1204                    }1205                }1206                self.r.add_typo_suggestion(err, typo_sugg, ident_span, None);1207                return (true, suggested_candidates, candidates);1208            }12091210            // If the first argument in call is `self` suggest calling a method.1211            if let Some((call_span, args_span)) = self.call_has_self_arg(source) {1212                let mut args_snippet = String::new();1213                if let Some(args_span) = args_span1214                    && let Ok(snippet) = self.r.tcx.sess.source_map().span_to_snippet(args_span)1215                {1216                    args_snippet = snippet;1217                }12181219                if let Some(Res::Def(DefKind::Struct, def_id)) = res {1220                    if let Some(ctor) = self.r.struct_ctor(def_id)1221                        && ctor.has_private_fields(self.parent_scope.module, self.r)1222                    {1223                        if matches!(1224                            ctor.res,1225                            Res::Def(DefKind::Ctor(CtorOf::Struct, CtorKind::Fn), _)1226                        ) {1227                            self.update_err_for_private_tuple_struct_fields(err, &source, def_id);1228                        }1229                        err.note("constructor is not visible here due to private fields");1230                    }1231                } else {1232                    err.span_suggestion_verbose(1233                        call_span,1234                        format!("try calling `{ident}` as a method"),1235                        format!("self.{path_str}({args_snippet})"),1236                        Applicability::MachineApplicable,1237                    );1238                }12391240                return (true, suggested_candidates, candidates);1241            }1242        }12431244        // Try context-dependent help if relaxed lookup didn't work.1245        if let Some(res) = res {1246            if self.smart_resolve_context_dependent_help(1247                err,1248                span,1249                source,1250                path,1251                res,1252                &path_str,1253                &base_error.fallback_label,1254            ) {1255                // We do this to avoid losing a secondary span when we override the main error span.1256                self.r.add_typo_suggestion(err, typo_sugg, ident_span, None);1257                return (true, suggested_candidates, candidates);1258            }1259        }12601261        // Try to find in last block rib1262        if let Some(rib) = &self.last_block_rib {1263            for (ident, &res) in &rib.bindings {1264                if let Res::Local(_) = res1265                    && path.len() == 11266                    && ident.span.eq_ctxt(path[0].ident.span)1267                    && ident.name == path[0].ident.name1268                {1269                    err.span_help(1270                        ident.span,1271                        format!("the binding `{path_str}` is available in a different scope in the same function"),1272                    );1273                    return (true, suggested_candidates, candidates);1274                }1275            }1276        }12771278        if candidates.is_empty() {1279            candidates = self.smart_resolve_partial_mod_path_errors(path, following_seg);1280        }12811282        (false, suggested_candidates, candidates)1283    }12841285    fn lookup_doc_alias_name(&mut self, path: &[Segment], ns: Namespace) -> Option<(DefId, Ident)> {1286        let find_doc_alias_name = |r: &mut Resolver<'ra, '_>, m: Module<'ra>, item_name: Symbol| {1287            for resolution in r.resolutions(m).values() {1288                let Some(did) =1289                    resolution.borrow(r).best_decl().and_then(|binding| binding.res().opt_def_id())1290                else {1291                    continue;1292                };1293                if did.is_local() {1294                    // We don't record the doc alias name in the local crate1295                    // because the people who write doc alias are usually not1296                    // confused by them.1297                    continue;1298                }1299                if let Some(d) = find_attr!(r.tcx, did, Doc(d) => d)1300                    && d.aliases.contains_key(&item_name)1301                {1302                    return Some(did);1303                }1304            }1305            None1306        };13071308        if path.len() == 1 {1309            for rib in self.ribs[ns].iter().rev() {1310                let item = path[0].ident;1311                if let RibKind::Module(module) | RibKind::Block(Some(module)) = rib.kind1312                    && let Some(did) = find_doc_alias_name(self.r, module.to_module(), item.name)1313                {1314                    return Some((did, item));1315                }1316            }1317        } else {1318            // Finds to the last resolved module item in the path1319            // and searches doc aliases within that module.1320            //1321            // Example: For the path `a::b::last_resolved::not_exist::c::d`,1322            // we will try to find any item has doc aliases named `not_exist`1323            // in `last_resolved` module.1324            //1325            // - Use `skip(1)` because the final segment must remain unresolved.1326            for (idx, seg) in path.iter().enumerate().rev().skip(1) {1327                let Some(id) = seg.id else {1328                    continue;1329                };1330                let Some(res) = self.r.partial_res_map.get(&id) else {1331                    continue;1332                };1333                if let Res::Def(DefKind::Mod, module) = res.expect_full_res()1334                    && let module = self.r.expect_module(module)1335                    && let item = path[idx + 1].ident1336                    && let Some(did) = find_doc_alias_name(self.r, module, item.name)1337                {1338                    return Some((did, item));1339                }1340                break;1341            }1342        }1343        None1344    }13451346    fn suggest_trait_and_bounds(1347        &self,1348        err: &mut Diag<'_>,1349        source: PathSource<'_, '_, '_>,1350        res: Option<Res>,1351        span: Span,1352        base_error: &BaseError,1353    ) -> bool {1354        let is_macro =1355            base_error.span.from_expansion() && base_error.span.desugaring_kind().is_none();1356        let mut fallback = false;13571358        if let (1359            PathSource::Trait(AliasPossibility::Maybe),1360            Some(Res::Def(DefKind::Struct | DefKind::Enum | DefKind::Union, _)),1361            false,1362        ) = (source, res, is_macro)1363            && let Some(bounds @ [first_bound, .., last_bound]) =1364                self.diag_metadata.current_trait_object1365        {1366            fallback = true;1367            let spans: Vec<Span> = bounds1368                .iter()1369                .map(|bound| bound.span())1370                .filter(|&sp| sp != base_error.span)1371                .collect();13721373            let start_span = first_bound.span();1374            // `end_span` is the end of the poly trait ref (Foo + 'baz + Bar><)1375            let end_span = last_bound.span();1376            // `last_bound_span` is the last bound of the poly trait ref (Foo + >'baz< + Bar)1377            let last_bound_span = spans.last().cloned().unwrap();1378            let mut multi_span: MultiSpan = spans.clone().into();1379            for sp in spans {1380                let msg = if sp == last_bound_span {1381                    format!(1382                        "...because of {these} bound{s}",1383                        these = pluralize!("this", bounds.len() - 1),1384                        s = pluralize!(bounds.len() - 1),1385                    )1386                } else {1387                    String::new()1388                };1389                multi_span.push_span_label(sp, msg);1390            }1391            multi_span.push_span_label(base_error.span, "expected this type to be a trait...");1392            err.span_help(1393                multi_span,1394                "`+` is used to constrain a \"trait object\" type with lifetimes or \1395                        auto-traits; structs and enums can't be bound in that way",1396            );1397            if bounds.iter().all(|bound| match bound {1398                ast::GenericBound::Outlives(_) | ast::GenericBound::Use(..) => true,1399                ast::GenericBound::Trait(tr) => tr.span == base_error.span,1400            }) {1401                let mut sugg = vec![];1402                if base_error.span != start_span {1403                    sugg.push((start_span.until(base_error.span), String::new()));1404                }1405                if base_error.span != end_span {1406                    sugg.push((base_error.span.shrink_to_hi().to(end_span), String::new()));1407                }14081409                err.multipart_suggestion(1410                    "if you meant to use a type and not a trait here, remove the bounds",1411                    sugg,1412                    Applicability::MaybeIncorrect,1413                );1414            }1415        }14161417        fallback |= self.restrict_assoc_type_in_where_clause(span, err);1418        fallback1419    }14201421    fn suggest_typo(1422        &mut self,1423        err: &mut Diag<'_>,1424        source: PathSource<'_, 'ast, 'ra>,1425        path: &[Segment],1426        following_seg: Option<&Segment>,1427        span: Span,1428        base_error: &BaseError,1429        suggested_candidates: FxHashSet<String>,1430    ) -> bool {1431        let is_expected = &|res| source.is_expected(res);1432        let ident_span = path.last().map_or(span, |ident| ident.ident.span);14331434        // Prefer suggestions based on associated types from in-scope bounds (e.g. `T::Item`)1435        // over purely edit-distance-based identifier suggestions.1436        // Otherwise suggestions could be verbose.1437        if self.suggest_assoc_type_from_bounds(err, source, path, ident_span) {1438            return false;1439        }14401441        // Preserve the field name for struct field shorthands to avoid suggesting invalid shorthands.1442        let mut prefix = None;1443        if let PathSource::Expr(Some(ast::Expr { kind: ExprKind::Struct(expr), .. })) = source1444            && let Some(ident) = path.last().map(|seg| seg.ident)1445            && expr.fields.iter().any(|f| f.ident == ident && f.is_shorthand)1446        {1447            prefix = Some(ident);1448        }14491450        let typo_sugg =1451            self.lookup_typo_candidate(path, following_seg, source.namespace(), is_expected);1452        let mut fallback = true;1453        let typo_sugg = typo_sugg1454            .to_opt_suggestion()1455            .filter(|sugg| !suggested_candidates.contains(sugg.candidate.as_str()));1456        self.r.add_typo_suggestion(err, typo_sugg, ident_span, prefix);14571458        match self.diag_metadata.current_let_binding {1459            Some((pat_sp, Some(ty_sp), None))1460                if ty_sp.contains(base_error.span) && base_error.could_be_expr =>1461            {1462                err.span_suggestion_verbose(1463                    pat_sp.between(ty_sp),1464                    "use `=` if you meant to assign",1465                    " = ",1466                    Applicability::MaybeIncorrect,1467                );1468            }1469            _ => {}1470        }14711472        // If the trait has a single item (which wasn't matched by the algorithm), suggest it1473        let suggestion = self.get_single_associated_item(path, &source, is_expected);1474        self.r.add_typo_suggestion(err, suggestion, ident_span, prefix);14751476        if self.let_binding_suggestion(err, ident_span) {1477            fallback = false;1478        }14791480        fallback1481    }14821483    fn suggest_shadowed(1484        &mut self,1485        err: &mut Diag<'_>,1486        source: PathSource<'_, '_, '_>,1487        path: &[Segment],1488        following_seg: Option<&Segment>,1489        span: Span,1490    ) -> bool {1491        let is_expected = &|res| source.is_expected(res);1492        let typo_sugg =1493            self.lookup_typo_candidate(path, following_seg, source.namespace(), is_expected);1494        let is_in_same_file = &|sp1, sp2| {1495            let source_map = self.r.tcx.sess.source_map();1496            let file1 = source_map.span_to_filename(sp1);1497            let file2 = source_map.span_to_filename(sp2);1498            file1 == file21499        };1500        // print 'you might have meant' if the candidate is (1) is a shadowed name with1501        // accessible definition and (2) either defined in the same crate as the typo1502        // (could be in a different file) or introduced in the same file as the typo1503        // (could belong to a different crate)1504        if let TypoCandidate::Shadowed(res, Some(sugg_span)) = typo_sugg1505            && res.opt_def_id().is_some_and(|id| id.is_local() || is_in_same_file(span, sugg_span))1506        {1507            err.span_label(1508                sugg_span,1509                format!("you might have meant to refer to this {}", res.descr()),1510            );1511            return true;1512        }1513        false1514    }15151516    fn err_code_special_cases(1517        &mut self,1518        err: &mut Diag<'_>,1519        source: PathSource<'_, '_, '_>,1520        path: &[Segment],1521        span: Span,1522    ) {1523        if let Some(err_code) = err.code {1524            if err_code == E0425 {1525                for label_rib in &self.label_ribs {1526                    for (label_ident, node_id) in &label_rib.bindings {1527                        let ident = path.last().unwrap().ident;1528                        if format!("'{ident}") == label_ident.to_string() {1529                            err.span_label(label_ident.span, "a label with a similar name exists");1530                            if let PathSource::Expr(Some(Expr {1531                                kind: ExprKind::Break(None, Some(_)),1532                                ..1533                            })) = source1534                            {1535                                err.span_suggestion_verbose(1536                                    span,1537                                    "use the similarly named label",1538                                    label_ident.name,1539                                    Applicability::MaybeIncorrect,1540                                );1541                                // Do not lint against unused label when we suggest them.1542                                self.diag_metadata.unused_labels.swap_remove(node_id);1543                            }1544                        }1545                    }1546                }15471548                self.suggest_ident_hidden_by_hygiene(err, path, span);1549                // cannot find type in this scope1550                if let Some(correct) = Self::likely_rust_type(path) {1551                    err.span_suggestion_verbose(1552                        span,1553                        format!("you might have intended to use the `{correct}` primitive type"),1554                        correct,1555                        Applicability::MaybeIncorrect,1556                    );1557                }1558            }1559        }1560    }15611562    fn suggest_ident_hidden_by_hygiene(&self, err: &mut Diag<'_>, path: &[Segment], span: Span) {1563        let [segment] = path else { return };15641565        let ident = segment.ident;1566        let callsite_span = span.source_callsite();1567        for rib in self.ribs[ValueNS].iter().rev() {1568            for (binding_ident, _) in &rib.bindings {1569                // Case 1: the identifier is defined in the same scope as the macro is called1570                if binding_ident.name == ident.name1571                    && !binding_ident.span.eq_ctxt(span)1572                    && !binding_ident.span.from_expansion()1573                    && binding_ident.span.lo() < callsite_span.lo()1574                {1575                    err.span_help(1576                        binding_ident.span,1577                        "an identifier with the same name exists, but is not accessible due to macro hygiene",1578                    );1579                    return;1580                }15811582                // Case 2: the identifier is defined in a macro call in the same scope1583                if binding_ident.name == ident.name1584                    && binding_ident.span.from_expansion()1585                    && binding_ident.span.source_callsite().eq_ctxt(callsite_span)1586                    && binding_ident.span.source_callsite().lo() < callsite_span.lo()1587                {1588                    err.span_help(1589                        binding_ident.span,1590                        "an identifier with the same name is defined here, but is not accessible due to macro hygiene",1591                    );1592                    return;1593                }1594            }1595        }1596    }15971598    /// Emit special messages for unresolved `Self` and `self`.1599    fn suggest_self_ty(1600        &self,1601        err: &mut Diag<'_>,1602        source: PathSource<'_, '_, '_>,1603        path: &[Segment],1604        span: Span,1605    ) -> bool {1606        if !is_self_type(path, source.namespace()) {1607            return false;1608        }1609        err.code(E0411);1610        err.span_label(span, "`Self` is only available in impls, traits, and type definitions");1611        if let Some(item) = self.diag_metadata.current_item1612            && let Some(ident) = item.kind.ident()1613        {1614            err.span_label(1615                ident.span,1616                format!("`Self` not allowed in {} {}", item.kind.article(), item.kind.descr()),1617            );1618        }1619        true1620    }16211622    fn suggest_self_value(1623        &mut self,1624        err: &mut Diag<'_>,1625        source: PathSource<'_, '_, '_>,1626        path: &[Segment],1627        span: Span,1628    ) -> bool {1629        if !is_self_value(path, source.namespace()) {1630            return false;1631        }16321633        debug!("smart_resolve_path_fragment: E0424, source={:?}", source);1634        err.code(E0424);1635        err.span_label(1636            span,1637            match source {1638                PathSource::Pat => {1639                    "`self` value is a keyword and may not be bound to variables or shadowed"1640                }1641                _ => "`self` value is a keyword only available in methods with a `self` parameter",1642            },1643        );16441645        // using `let self` is wrong even if we're not in an associated method or if we're in a macro expansion.1646        // So, we should return early if we're in a pattern, see issue #143134.1647        if matches!(source, PathSource::Pat) {1648            return true;1649        }16501651        let is_assoc_fn = self.self_type_is_available();1652        let self_from_macro = "a `self` parameter, but a macro invocation can only \1653                               access identifiers it receives from parameters";1654        if let Some((fn_kind, fn_span)) = &self.diag_metadata.current_function {1655            // The current function has a `self` parameter, but we were unable to resolve1656            // a reference to `self`. This can only happen if the `self` identifier we1657            // are resolving came from a different hygiene context or a variable binding.1658            // But variable binding error is returned early above.1659            if fn_kind.decl().inputs.get(0).is_some_and(|p| p.is_self()) {1660                err.span_label(*fn_span, format!("this function has {self_from_macro}"));1661            } else {1662                let doesnt = if is_assoc_fn {1663                    let (span, sugg) = fn_kind1664                        .decl()1665                        .inputs1666                        .get(0)1667                        .map(|p| (p.span.shrink_to_lo(), "&self, "))1668                        .unwrap_or_else(|| {1669                            // Try to look for the "(" after the function name, if possible.1670                            // This avoids placing the suggestion into the visibility specifier.1671                            let span = fn_kind1672                                .ident()1673                                .map_or(*fn_span, |ident| fn_span.with_lo(ident.span.hi()));1674                            (1675                                self.r1676                                    .tcx1677                                    .sess1678                                    .source_map()1679                                    .span_through_char(span, '(')1680                                    .shrink_to_hi(),1681                                "&self",1682                            )1683                        });1684                    err.span_suggestion_verbose(1685                        span,1686                        "add a `self` receiver parameter to make the associated `fn` a method",1687                        sugg,1688                        Applicability::MaybeIncorrect,1689                    );1690                    "doesn't"1691                } else {1692                    "can't"1693                };1694                if let Some(ident) = fn_kind.ident() {1695                    err.span_label(1696                        ident.span,1697                        format!("this function {doesnt} have a `self` parameter"),1698                    );1699                }1700            }1701        } else if let Some(item) = self.diag_metadata.current_item {1702            if matches!(item.kind, ItemKind::Delegation(..)) {1703                err.span_label(item.span, format!("delegation supports {self_from_macro}"));1704            } else {1705                let span = if let Some(ident) = item.kind.ident() { ident.span } else { item.span };1706                err.span_label(1707                    span,1708                    format!("`self` not allowed in {} {}", item.kind.article(), item.kind.descr()),1709                );1710            }1711        }1712        true1713    }17141715    fn detect_missing_binding_available_from_pattern(1716        &self,1717        err: &mut Diag<'_>,1718        path: &[Segment],1719        following_seg: Option<&Segment>,1720    ) {1721        let [segment] = path else { return };1722        let None = following_seg else { return };1723        for rib in self.ribs[ValueNS].iter().rev() {1724            let patterns_with_skipped_bindings =1725                self.r.tcx.with_stable_hashing_context(|mut hcx| {1726                    rib.patterns_with_skipped_bindings.to_sorted(&mut hcx, true)1727                });1728            for (def_id, spans) in patterns_with_skipped_bindings {1729                if let DefKind::Struct | DefKind::Variant = self.r.tcx.def_kind(*def_id)1730                    && let Some(fields) = self.r.field_idents(*def_id)1731                {1732                    for field in fields {1733                        if field.name == segment.ident.name {1734                            if spans.iter().all(|(.., had_error)| had_error.is_err()) {1735                                // This resolution error will likely be fixed by fixing a1736                                // syntax error in a pattern, so it is irrelevant to the user.1737                                let multispan: MultiSpan =1738                                    spans.iter().map(|(s, ..)| *s).collect::<Vec<_>>().into();1739                                err.span_note(1740                                    multispan,1741                                    "this pattern had a recovered parse error which likely lost \1742                                     the expected fields",1743                                );1744                                err.downgrade_to_delayed_bug();1745                            }1746                            let ty = self.r.tcx.item_name(*def_id);1747                            for (span, rest_span, _) in spans {1748                                err.span_label(1749                                    *span,1750                                    format!(1751                                        "this pattern doesn't include `{field}`, which is \1752                                         available in `{ty}`",1753                                    ),1754                                );1755                                if let Some(rest_span) = rest_span {1756                                    err.span_suggestion_verbose(1757                                        *rest_span,1758                                        format!("include `{field}` in the pattern"),1759                                        format!("{field}, .."),1760                                        Applicability::MaybeIncorrect,1761                                    );1762                                }1763                            }1764                        }1765                    }1766                }1767            }1768        }1769    }17701771    fn suggest_at_operator_in_slice_pat_with_range(&self, err: &mut Diag<'_>, path: &[Segment]) {1772        let Some(pat) = self.diag_metadata.current_pat else { return };1773        let (bound, side, range) = match &pat.kind {1774            ast::PatKind::Range(Some(bound), None, range) => (bound, Side::Start, range),1775            ast::PatKind::Range(None, Some(bound), range) => (bound, Side::End, range),1776            _ => return,1777        };1778        if let ExprKind::Path(None, range_path) = &bound.kind1779            && let [segment] = &range_path.segments[..]1780            && let [s] = path1781            && segment.ident == s.ident1782            && segment.ident.span.eq_ctxt(range.span)1783        {1784            // We've encountered `[first, rest..]` (#88404) or `[first, ..rest]` (#120591)1785            // where the user might have meant `[first, rest @ ..]`.1786            let (span, snippet) = match side {1787                Side::Start => (segment.ident.span.between(range.span), " @ ".into()),1788                Side::End => (range.span.to(segment.ident.span), format!("{} @ ..", segment.ident)),1789            };1790            err.subdiagnostic(diagnostics::UnexpectedResUseAtOpInSlicePatWithRangeSugg {1791                span,1792                ident: segment.ident,1793                snippet,1794            });1795        }17961797        enum Side {1798            Start,1799            End,1800        }1801    }18021803    fn suggest_range_struct_destructuring(1804        &mut self,1805        err: &mut Diag<'_>,1806        path: &[Segment],1807        source: PathSource<'_, '_, '_>,1808    ) {1809        if !matches!(source, PathSource::Pat | PathSource::TupleStruct(..) | PathSource::Expr(..)) {1810            return;1811        }18121813        let Some(pat) = self.diag_metadata.current_pat else { return };1814        let ast::PatKind::Range(start, end, end_kind) = &pat.kind else { return };18151816        let [segment] = path else { return };1817        let failing_span = segment.ident.span;18181819        let in_start = start.as_ref().is_some_and(|e| e.span.contains(failing_span));1820        let in_end = end.as_ref().is_some_and(|e| e.span.contains(failing_span));18211822        if !in_start && !in_end {1823            return;1824        }18251826        let start_snippet =1827            start.as_ref().and_then(|e| self.r.tcx.sess.source_map().span_to_snippet(e.span).ok());1828        let end_snippet =1829            end.as_ref().and_then(|e| self.r.tcx.sess.source_map().span_to_snippet(e.span).ok());18301831        let field = |name: &str, val: String| {1832            if val == name { val } else { format!("{name}: {val}") }1833        };18341835        let mut resolve_short_name = |short: Symbol, full: &str| -> String {1836            let ident = Ident::with_dummy_span(short);1837            let path = Segment::from_path(&Path::from_ident(ident));18381839            match self.resolve_path(&path, Some(TypeNS), None, PathSource::Type) {1840                PathResult::NonModule(..) => short.to_string(),1841                _ => full.to_string(),1842            }1843        };1844        // FIXME(new_range): Also account for new range types1845        let (struct_path, fields) = match (start_snippet, end_snippet, &end_kind.node) {1846            (Some(start), Some(end), ast::RangeEnd::Excluded) => (1847                resolve_short_name(sym::Range, "std::ops::Range"),1848                vec![field("start", start), field("end", end)],1849            ),1850            (Some(start), Some(end), ast::RangeEnd::Included(_)) => (1851                resolve_short_name(sym::RangeInclusive, "std::ops::RangeInclusive"),1852                vec![field("start", start), field("end", end)],1853            ),1854            (Some(start), None, _) => (1855                resolve_short_name(sym::RangeFrom, "std::ops::RangeFrom"),1856                vec![field("start", start)],1857            ),1858            (None, Some(end), ast::RangeEnd::Excluded) => {1859                (resolve_short_name(sym::RangeTo, "std::ops::RangeTo"), vec![field("end", end)])1860            }1861            (None, Some(end), ast::RangeEnd::Included(_)) => (1862                resolve_short_name(sym::RangeToInclusive, "std::ops::RangeToInclusive"),1863                vec![field("end", end)],1864            ),1865            _ => return,1866        };18671868        err.span_suggestion_verbose(1869            pat.span,1870            format!("if you meant to destructure a range use a struct pattern"),1871            format!("{} {{ {} }}", struct_path, fields.join(", ")),1872            Applicability::MaybeIncorrect,1873        );18741875        err.note(1876            "range patterns match against the start and end of a range; \1877             to bind the components, use a struct pattern",1878        );1879    }18801881    fn suggest_swapping_misplaced_self_ty_and_trait(1882        &mut self,1883        err: &mut Diag<'_>,1884        source: PathSource<'_, 'ast, 'ra>,1885        res: Option<Res>,1886        span: Span,1887    ) {1888        if let Some((trait_ref, self_ty)) = self.diag_metadata.currently_processing_impl_trait1889            && let TyKind::Path(_, self_ty_path) = &self_ty.kind1890            && let PathResult::Module(ModuleOrUniformRoot::Module(module)) =1891                self.resolve_path(&Segment::from_path(self_ty_path), Some(TypeNS), None, source)1892            && module.def_kind() == Some(DefKind::Trait)1893            && trait_ref.path.span == span1894            && let PathSource::Trait(_) = source1895            && let Some(Res::Def(DefKind::Struct | DefKind::Enum | DefKind::Union, _)) = res1896            && let Ok(self_ty_str) = self.r.tcx.sess.source_map().span_to_snippet(self_ty.span)1897            && let Ok(trait_ref_str) =1898                self.r.tcx.sess.source_map().span_to_snippet(trait_ref.path.span)1899        {1900            err.multipart_suggestion(1901                    "`impl` items mention the trait being implemented first and the type it is being implemented for second",1902                    vec![(trait_ref.path.span, self_ty_str), (self_ty.span, trait_ref_str)],1903                    Applicability::MaybeIncorrect,1904                );1905        }1906    }19071908    /// If the name resolution error occurs in an ident that has no span context, but the enclosing1909    /// item is within a derive macro, point at the derive, as the error can either be because of an1910    /// invalid derive macro *or* a non-existing item that will already have been reported through1911    /// the annotated item.1912    fn detect_resolution_error_in_derive(&self, err: &mut Diag<'_>, span: Span) {1913        if let Some(item) = self.diag_metadata.current_item1914            && !item.span.eq_ctxt(span)1915            && item.span.in_derive_expansion()1916        {1917            // `item` comes from a `#[derive()]`, but the error `span` doesn't, which means that the1918            // derive is referencing a name coming from the annotated item. If the item exists, then1919            // the derive macro itself is buggy. If the item exists, then an error will have already1920            // been emitted while evaluating the annotated item itself, but we can't silence this1921            // one because one *can* write a derive macro referencing a non-existing item that is1922            // part of the expansion, *not* from the user's code. Because of that, at least for now,1923            // we just add context to the current error.1924            err.span_label(item.span, "in this derive macro");1925        }1926    }19271928    fn explain_functions_in_pattern(1929        &self,1930        err: &mut Diag<'_>,1931        res: Option<Res>,1932        source: PathSource<'_, '_, '_>,1933    ) {1934        let PathSource::TupleStruct(_, _) = source else { return };1935        let Some(Res::Def(DefKind::Fn, _)) = res else { return };1936        err.primary_message("expected a pattern, found a function call");1937        err.note("function calls are not allowed in patterns: <https://doc.rust-lang.org/book/ch19-00-patterns.html>");1938    }19391940    fn suggest_changing_type_to_const_param(1941        &self,1942        err: &mut Diag<'_>,1943        res: Option<Res>,1944        source: PathSource<'_, '_, '_>,1945        path: &[Segment],1946        following_seg: Option<&Segment>,1947        span: Span,1948    ) {1949        if let PathSource::Expr(None) = source1950            && let Some(Res::Def(DefKind::TyParam, _)) = res1951            && following_seg.is_none()1952            && let [segment] = path1953        {1954            // We have something like1955            // impl<T, N> From<[T; N]> for VecWrapper<T> {1956            //     fn from(slice: [T; N]) -> Self {1957            //         VecWrapper(slice.to_vec())1958            //     }1959            // }1960            // where `N` is a type param but should likely have been a const param.1961            let Some(item) = self.diag_metadata.current_item else { return };1962            let Some(generics) = item.kind.generics() else { return };1963            let Some(span) = generics.params.iter().find_map(|param| {1964                // Only consider type params with no bounds.1965                if param.bounds.is_empty() && param.ident.name == segment.ident.name {1966                    Some(param.ident.span)1967                } else {1968                    None1969                }1970            }) else {1971                return;1972            };1973            err.subdiagnostic(diagnostics::UnexpectedResChangeTyParamToConstParamSugg {1974                before: span.shrink_to_lo(),1975                after: span.shrink_to_hi(),1976            });1977            return;1978        }1979        let PathSource::Trait(_) = source else { return };19801981        // We don't include `DefKind::Str` and `DefKind::AssocTy` as they can't be reached here anyway.1982        let applicability = match res {1983            Some(Res::PrimTy(PrimTy::Int(_) | PrimTy::Uint(_) | PrimTy::Bool | PrimTy::Char)) => {1984                Applicability::MachineApplicable1985            }1986            // FIXME(const_generics): Add `DefKind::TyParam` and `SelfTyParam` once we support generic1987            // const generics. Of course, `Struct` and `Enum` may contain ty params, too, but the1988            // benefits of including them here outweighs the small number of false positives.1989            Some(Res::Def(DefKind::Struct | DefKind::Enum, _))1990                if self.r.features.adt_const_params() || self.r.features.min_adt_const_params() =>1991            {1992                Applicability::MaybeIncorrect1993            }1994            _ => return,1995        };19961997        let Some(item) = self.diag_metadata.current_item else { return };1998        let Some(generics) = item.kind.generics() else { return };19992000        let param = generics.params.iter().find_map(|param| {

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.

Generated by searchcode.com · powered by code_get_file + code_get_findings