compiler/rustc_resolve/src/late/diagnostics.rs RUST 4,651 lines View on github.com → Search inside
File is large — showing lines 1–2,000 of 4,651.
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::def::Namespace::{self, *};23use rustc_hir::def::{CtorKind, CtorOf, DefKind, MacroKinds};24use rustc_hir::def_id::{CRATE_DEF_ID, DefId};25use rustc_hir::{MissingLifetimeKind, PrimTy, find_attr};26use rustc_middle::ty;27use rustc_session::{Session, lint};28use rustc_span::edit_distance::{edit_distance, find_best_match_for_name};29use rustc_span::edition::Edition;30use rustc_span::{DUMMY_SP, DesugaringKind, Ident, Span, Symbol, kw, sym};31use thin_vec::{ThinVec, thin_vec};32use tracing::debug;3334use super::NoConstantGenericsReason;35use crate::diagnostics::impls::{ImportSuggestion, LabelSuggestion, TypoSuggestion};36use crate::late::{37    AliasPossibility, LateResolutionVisitor, LifetimeBinderKind, LifetimeRes, LifetimeRibKind,38    LifetimeUseSet, QSelf, RibKind,39};40use crate::ty::fast_reject::SimplifiedType;41use crate::{42    Finalize, Module, ModuleOrUniformRoot, ParentScope, PathResult, PathSource, Res, Resolver,43    ScopeSet, Segment, diagnostics, path_names_to_string,44};4546/// A field or associated item from self type suggested in case of resolution failure.47enum AssocSuggestion {48    Field(Span),49    MethodWithSelf { called: bool },50    AssocFn { called: bool },51    AssocType,52    AssocConst,53}5455impl AssocSuggestion {56    fn action(&self) -> &'static str {57        match self {58            AssocSuggestion::Field(_) => "use the available field",59            AssocSuggestion::MethodWithSelf { called: true } => {60                "call the method with the fully-qualified path"61            }62            AssocSuggestion::MethodWithSelf { called: false } => {63                "refer to the method with the fully-qualified path"64            }65            AssocSuggestion::AssocFn { called: true } => "call the associated function",66            AssocSuggestion::AssocFn { called: false } => "refer to the associated function",67            AssocSuggestion::AssocConst => "use the associated `const`",68            AssocSuggestion::AssocType => "use the associated type",69        }70    }71}7273fn is_self_type(path: &[Segment], namespace: Namespace) -> bool {74    namespace == TypeNS && path.len() == 1 && path[0].ident.name == kw::SelfUpper75}7677fn is_self_value(path: &[Segment], namespace: Namespace) -> bool {78    namespace == ValueNS && path.len() == 1 && path[0].ident.name == kw::SelfLower79}8081fn path_to_string_without_assoc_item_bindings(path: &Path) -> String {82    let mut path = path.clone();83    for segment in &mut path.segments {84        let mut remove_args = false;85        if let Some(args) = segment.args.as_deref_mut()86            && let ast::GenericArgs::AngleBracketed(angle_bracketed) = args87        {88            angle_bracketed.args.retain(|arg| matches!(arg, ast::AngleBracketedArg::Arg(_)));89            remove_args = angle_bracketed.args.is_empty();90        }91        if remove_args {92            segment.args = None;93        }94    }95    path_to_string(&path)96}9798/// Gets the stringified path for an enum from an `ImportSuggestion` for an enum variant.99fn import_candidate_to_enum_paths(suggestion: &ImportSuggestion) -> (String, String) {100    let variant_path = &suggestion.path;101    let variant_path_string = path_names_to_string(variant_path);102103    let path_len = suggestion.path.segments.len();104    let enum_path = ast::Path {105        span: suggestion.path.span,106        segments: suggestion.path.segments[0..path_len - 1].iter().cloned().collect(),107    };108    let enum_path_string = path_names_to_string(&enum_path);109110    (variant_path_string, enum_path_string)111}112113/// Description of an elided lifetime.114#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug)]115pub(super) struct MissingLifetime {116    /// Used to overwrite the resolution with the suggestion, to avoid cascading errors.117    pub id: NodeId,118    /// As we cannot yet emit lints in this crate and have to buffer them instead,119    /// we need to associate each lint with some `NodeId`,120    /// however for some `MissingLifetime`s their `NodeId`s are "fake",121    /// in a sense that they are temporary and not get preserved down the line,122    /// which means that the lints for those nodes will not get emitted.123    /// To combat this, we can try to use some other `NodeId`s as a fallback option.124    pub id_for_lint: NodeId,125    /// Where to suggest adding the lifetime.126    pub span: Span,127    /// How the lifetime was introduced, to have the correct space and comma.128    pub kind: MissingLifetimeKind,129    /// Number of elided lifetimes, used for elision in path.130    pub count: usize,131}132133/// Description of the lifetimes appearing in a function parameter.134/// This is used to provide a literal explanation to the elision failure.135#[derive(Debug)]136pub(super) struct ElisionFnParameter {137    /// The index of the argument in the original definition.138    pub index: usize,139    /// The name of the argument if it's a simple ident.140    pub ident: Option<Ident>,141    /// The number of lifetimes in the parameter.142    pub lifetime_count: usize,143    /// The span of the parameter.144    pub span: Span,145}146147/// Description of lifetimes that appear as candidates for elision.148/// This is used to suggest introducing an explicit lifetime.149#[derive(Clone, Copy, Debug)]150pub(super) enum LifetimeElisionCandidate {151    /// This is not a real lifetime, or it is a named lifetime, in which case we won't suggest anything.152    Ignore,153    Missing(MissingLifetime),154}155156/// Only used for diagnostics.157#[derive(Debug)]158struct BaseError {159    msg: String,160    fallback_label: String,161    span: Span,162    span_label: Option<(Span, &'static str)>,163    could_be_expr: bool,164    suggestion: Option<(Span, &'static str, String)>,165    module: Option<DefId>,166}167168#[derive(Debug)]169enum TypoCandidate {170    Typo(TypoSuggestion),171    Shadowed(Res, Option<Span>),172    None,173}174175impl TypoCandidate {176    fn to_opt_suggestion(self) -> Option<TypoSuggestion> {177        match self {178            TypoCandidate::Typo(sugg) => Some(sugg),179            TypoCandidate::Shadowed(_, _) | TypoCandidate::None => None,180        }181    }182}183184impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {185    fn trait_assoc_type_def_id_by_name(186        &mut self,187        trait_def_id: DefId,188        assoc_name: Symbol,189    ) -> Option<DefId> {190        let module = self.r.get_module(trait_def_id)?;191        self.r.resolutions(module).borrow().iter().find_map(|(key, resolution)| {192            if key.ident.name != assoc_name {193                return None;194            }195            let resolution = resolution.borrow();196            let binding = resolution.best_decl()?;197            match binding.res() {198                Res::Def(DefKind::AssocTy, def_id) => Some(def_id),199                _ => None,200            }201        })202    }203204    /// This does best-effort work to generate suggestions for associated types.205    fn suggest_assoc_type_from_bounds(206        &mut self,207        err: &mut Diag<'_>,208        source: PathSource<'_, 'ast, 'ra>,209        path: &[Segment],210        ident_span: Span,211    ) -> bool {212        // Filter out cases where we cannot emit meaningful suggestions.213        if source.namespace() != TypeNS {214            return false;215        }216        let [segment] = path else { return false };217        if segment.has_generic_args {218            return false;219        }220        if !ident_span.can_be_used_for_suggestions() {221            return false;222        }223        let assoc_name = segment.ident.name;224        if assoc_name == kw::Underscore {225            return false;226        }227228        // Map: type parameter name -> (trait def id -> (assoc type def id, trait paths as written)).229        // We keep a set of paths per trait so we can detect cases like230        // `T: Trait<i32> + Trait<u32>` where suggesting `T::Assoc` would be ambiguous.231        let mut matching_bounds: FxIndexMap<232            Symbol,233            FxIndexMap<DefId, (DefId, FxIndexSet<String>)>,234        > = FxIndexMap::default();235236        let mut record_bound = |this: &mut Self,237                                ty_param: Symbol,238                                poly_trait_ref: &ast::PolyTraitRef| {239            // Avoid generating suggestions we can't print in a well-formed way.240            if !poly_trait_ref.bound_generic_params.is_empty() {241                return;242            }243            if poly_trait_ref.modifiers != ast::TraitBoundModifiers::NONE {244                return;245            }246            let Some(trait_seg) = poly_trait_ref.trait_ref.path.segments.last() else {247                return;248            };249            let Some(partial_res) = this.r.partial_res_map.get(&trait_seg.id) else {250                return;251            };252            let Some(trait_def_id) = partial_res.full_res().and_then(|res| res.opt_def_id()) else {253                return;254            };255            let Some(assoc_type_def_id) =256                this.trait_assoc_type_def_id_by_name(trait_def_id, assoc_name)257            else {258                return;259            };260261            // Preserve `::` and generic args so we don't generate broken suggestions like262            // `<T as Foo>::Assoc` for bounds written as `T: ::Foo<'a>`, while stripping263            // associated-item bindings that are rejected in qualified paths.264            let trait_path =265                path_to_string_without_assoc_item_bindings(&poly_trait_ref.trait_ref.path);266            let trait_bounds = matching_bounds.entry(ty_param).or_default();267            let trait_bounds = trait_bounds268                .entry(trait_def_id)269                .or_insert_with(|| (assoc_type_def_id, FxIndexSet::default()));270            debug_assert_eq!(trait_bounds.0, assoc_type_def_id);271            trait_bounds.1.insert(trait_path);272        };273274        let mut record_from_generics = |this: &mut Self, generics: &ast::Generics| {275            for param in &generics.params {276                let ast::GenericParamKind::Type { .. } = param.kind else { continue };277                for bound in &param.bounds {278                    let ast::GenericBound::Trait(poly_trait_ref) = bound else { continue };279                    record_bound(this, param.ident.name, poly_trait_ref);280                }281            }282283            for predicate in &generics.where_clause.predicates {284                let ast::WherePredicateKind::BoundPredicate(where_bound) = &predicate.kind else {285                    continue;286                };287288                let ast::TyKind::Path(None, bounded_path) = &where_bound.bounded_ty.kind else {289                    continue;290                };291                let [ast::PathSegment { ident, args: None, .. }] = &bounded_path.segments[..]292                else {293                    continue;294                };295296                // Only suggest for bounds that are explicitly on an in-scope type parameter.297                let Some(partial_res) = this.r.partial_res_map.get(&where_bound.bounded_ty.id)298                else {299                    continue;300                };301                if !matches!(partial_res.full_res(), Some(Res::Def(DefKind::TyParam, _))) {302                    continue;303                }304305                for bound in &where_bound.bounds {306                    let ast::GenericBound::Trait(poly_trait_ref) = bound else { continue };307                    record_bound(this, ident.name, poly_trait_ref);308                }309            }310        };311312        if let Some(item) = self.diag_metadata.current_item313            && let Some(generics) = item.kind.generics()314        {315            record_from_generics(self, generics);316        }317318        if let Some(item) = self.diag_metadata.current_item319            && matches!(item.kind, ItemKind::Impl(..))320            && let Some(assoc) = self.diag_metadata.current_impl_item321        {322            let generics = match &assoc.kind {323                AssocItemKind::Const(ast::ConstItem { generics, .. })324                | AssocItemKind::Fn(ast::Fn { generics, .. })325                | AssocItemKind::Type(ast::TyAlias { generics, .. }) => Some(generics),326                AssocItemKind::Delegation(..)327                | AssocItemKind::MacCall(..)328                | AssocItemKind::DelegationMac(..) => None,329            };330            if let Some(generics) = generics {331                record_from_generics(self, generics);332            }333        }334335        let mut suggestions: FxIndexSet<String> = FxIndexSet::default();336        for (ty_param, traits) in matching_bounds {337            let ty_param = ty_param.to_ident_string();338            let trait_paths_len: usize = traits.values().map(|(_, paths)| paths.len()).sum();339            if traits.len() == 1 && trait_paths_len == 1 {340                let assoc_type_def_id = traits.values().next().unwrap().0;341                let assoc_segment = format!(342                    "{}{}",343                    assoc_name,344                    self.r.item_required_generic_args_suggestion(assoc_type_def_id)345                );346                suggestions.insert(format!("{ty_param}::{assoc_segment}"));347            } else {348                for (assoc_type_def_id, trait_paths) in traits.into_values() {349                    let assoc_segment = format!(350                        "{}{}",351                        assoc_name,352                        self.r.item_required_generic_args_suggestion(assoc_type_def_id)353                    );354                    for trait_path in trait_paths {355                        suggestions356                            .insert(format!("<{ty_param} as {trait_path}>::{assoc_segment}"));357                    }358                }359            }360        }361362        if suggestions.is_empty() {363            return false;364        }365366        let mut suggestions: Vec<String> = suggestions.into_iter().collect();367        suggestions.sort();368369        err.span_suggestions_with_style(370            ident_span,371            "you might have meant to use an associated type of the same name",372            suggestions,373            Applicability::MaybeIncorrect,374            SuggestionStyle::ShowAlways,375        );376377        true378    }379380    fn make_base_error(381        &mut self,382        path: &[Segment],383        span: Span,384        source: PathSource<'_, 'ast, 'ra>,385        res: Option<Res>,386    ) -> BaseError {387        // Make the base error.388        let mut expected = source.descr_expected();389        let path_str = Segment::names_to_string(path);390        let item_str = path.last().unwrap().ident;391392        if let Some(res) = res {393            BaseError {394                msg: format!("expected {}, found {} `{}`", expected, res.descr(), path_str),395                fallback_label: format!("not a {expected}"),396                span,397                span_label: match res {398                    Res::Def(DefKind::TyParam, def_id) => {399                        Some((self.r.def_span(def_id), "found this type parameter"))400                    }401                    _ => None,402                },403                could_be_expr: match res {404                    Res::Def(DefKind::Fn, _) => {405                        // Verify whether this is a fn call or an Fn used as a type.406                        self.r407                            .tcx408                            .sess409                            .source_map()410                            .span_to_snippet(span)411                            .is_ok_and(|snippet| snippet.ends_with(')'))412                    }413                    Res::Def(414                        DefKind::Ctor(..)415                        | DefKind::AssocFn416                        | DefKind::Const { .. }417                        | DefKind::AssocConst { .. },418                        _,419                    )420                    | Res::SelfCtor(_)421                    | Res::PrimTy(_)422                    | Res::Local(_) => true,423                    _ => false,424                },425                suggestion: None,426                module: None,427            }428        } else {429            let mut span_label = None;430            let item_ident = path.last().unwrap().ident;431            let item_span = item_ident.span;432            let (mod_prefix, mod_str, module, suggestion) = if path.len() == 1 {433                debug!(?self.diag_metadata.current_impl_items);434                debug!(?self.diag_metadata.current_function);435                let suggestion = if self.current_trait_ref.is_none()436                    && let Some((fn_kind, _)) = self.diag_metadata.current_function437                    && let Some(FnCtxt::Assoc(_)) = fn_kind.ctxt()438                    && let FnKind::Fn(_, _, ast::Fn { sig, .. }) = fn_kind439                    && let Some(items) = self.diag_metadata.current_impl_items440                    && let Some(item) = items.iter().find(|i| {441                        i.kind.ident().is_some_and(|ident| {442                            // Don't suggest if the item is in Fn signature arguments (#112590).443                            ident.name == item_str.name && !sig.span.contains(item_span)444                        })445                    }) {446                    let sp = item_span.shrink_to_lo();447448                    // Account for `Foo { field }` when suggesting `self.field` so we result on449                    // `Foo { field: self.field }`.450                    let field = match source {451                        PathSource::Expr(Some(Expr { kind: ExprKind::Struct(expr), .. })) => {452                            expr.fields.iter().find(|f| f.ident == item_ident)453                        }454                        _ => None,455                    };456                    let pre = if let Some(field) = field457                        && field.is_shorthand458                    {459                        format!("{item_ident}: ")460                    } else {461                        String::new()462                    };463                    // Ensure we provide a structured suggestion for an assoc fn only for464                    // expressions that are actually a fn call.465                    let is_call = match field {466                        Some(ast::ExprField { expr, .. }) => {467                            matches!(expr.kind, ExprKind::Call(..))468                        }469                        _ => matches!(470                            source,471                            PathSource::Expr(Some(Expr { kind: ExprKind::Call(..), .. })),472                        ),473                    };474475                    match &item.kind {476                        AssocItemKind::Fn(fn_)477                            if (!sig.decl.has_self() || !is_call) && fn_.sig.decl.has_self() =>478                        {479                            // Ensure that we only suggest `self.` if `self` is available,480                            // you can't call `fn foo(&self)` from `fn bar()` (#115992).481                            // We also want to mention that the method exists.482                            span_label = Some((483                                fn_.ident.span,484                                "a method by that name is available on `Self` here",485                            ));486                            None487                        }488                        AssocItemKind::Fn(fn_) if !fn_.sig.decl.has_self() && !is_call => {489                            span_label = Some((490                                fn_.ident.span,491                                "an associated function by that name is available on `Self` here",492                            ));493                            None494                        }495                        AssocItemKind::Fn(fn_) if fn_.sig.decl.has_self() => {496                            Some((sp, "consider using the method on `Self`", format!("{pre}self.")))497                        }498                        AssocItemKind::Fn(_) => Some((499                            sp,500                            "consider using the associated function on `Self`",501                            format!("{pre}Self::"),502                        )),503                        AssocItemKind::Const(..) => Some((504                            sp,505                            "consider using the associated constant on `Self`",506                            format!("{pre}Self::"),507                        )),508                        _ => None,509                    }510                } else {511                    None512                };513                (String::new(), "this scope".to_string(), None, suggestion)514            } else if path.len() == 2 && path[0].ident.name == kw::PathRoot {515                if self.r.tcx.sess.edition() > Edition::Edition2015 {516                    // In edition 2018 onwards, the `::foo` syntax may only pull from the extern prelude517                    // which overrides all other expectations of item type518                    expected = "crate";519                    (String::new(), "the list of imported crates".to_string(), None, None)520                } else {521                    (522                        String::new(),523                        "the crate root".to_string(),524                        Some(CRATE_DEF_ID.to_def_id()),525                        None,526                    )527                }528            } else if path.len() == 2 && path[0].ident.name == kw::Crate {529                (String::new(), "the crate root".to_string(), Some(CRATE_DEF_ID.to_def_id()), None)530            } else {531                let mod_path = &path[..path.len() - 1];532                let mod_res = self.resolve_path(mod_path, Some(TypeNS), None, source);533                let mod_prefix = match mod_res {534                    PathResult::Module(ModuleOrUniformRoot::Module(module)) => module.res(),535                    _ => None,536                };537538                let module_did = mod_prefix.as_ref().and_then(Res::mod_def_id);539540                let mod_prefix =541                    mod_prefix.map_or_else(String::new, |res| format!("{} ", res.descr()));542                (mod_prefix, format!("`{}`", Segment::names_to_string(mod_path)), module_did, None)543            };544545            let (fallback_label, suggestion) = if path_str == "async"546                && expected.starts_with("struct")547            {548                ("`async` blocks are only allowed in Rust 2018 or later".to_string(), suggestion)549            } else {550                // check if we are in situation of typo like `True` instead of `true`.551                let override_suggestion =552                    if ["true", "false"].contains(&item_str.to_string().to_lowercase().as_str()) {553                        let item_typo = item_str.to_string().to_lowercase();554                        Some((item_span, "you may want to use a bool value instead", item_typo))555                    // FIXME(vincenzopalazzo): make the check smarter,556                    // and maybe expand with levenshtein distance checks557                    } else if item_str.as_str() == "printf" {558                        Some((559                            item_span,560                            "you may have meant to use the `print` macro",561                            "print!".to_owned(),562                        ))563                    } else {564                        suggestion565                    };566                (format!("not found in {mod_str}"), override_suggestion)567            };568569            BaseError {570                msg: format!("cannot find {expected} `{item_str}` in {mod_prefix}{mod_str}"),571                fallback_label,572                span: item_span,573                span_label,574                could_be_expr: false,575                suggestion,576                module,577            }578        }579    }580581    /// Try to suggest for a module path that cannot be resolved.582    /// Such as `fmt::Debug` where `fmt` is not resolved without importing,583    /// here we search with `lookup_import_candidates` for a module named `fmt`584    /// with `TypeNS` as namespace.585    ///586    /// We need a separate function here because we won't suggest for a path with single segment587    /// and we won't change `SourcePath` api `is_expected` to match `Type` with `DefKind::Mod`588    pub(crate) fn smart_resolve_partial_mod_path_errors(589        &mut self,590        prefix_path: &[Segment],591        following_seg: Option<&Segment>,592    ) -> Vec<ImportSuggestion> {593        if let Some(segment) = prefix_path.last()594            && let Some(following_seg) = following_seg595        {596            let candidates = self.r.lookup_import_candidates(597                segment.ident,598                Namespace::TypeNS,599                &self.parent_scope,600                &|res: Res| matches!(res, Res::Def(DefKind::Mod, _)),601            );602            // double check next seg is valid603            candidates604                .into_iter()605                .filter(|candidate| {606                    if let Some(def_id) = candidate.did607                        && let Some(module) = self.r.get_module(def_id)608                    {609                        Some(def_id) != self.parent_scope.module.opt_def_id()610                            && self611                                .r612                                .resolutions(module)613                                .borrow()614                                .iter()615                                .any(|(key, _r)| key.ident.name == following_seg.ident.name)616                    } else {617                        false618                    }619                })620                .collect::<Vec<_>>()621        } else {622            Vec::new()623        }624    }625626    /// Handles error reporting for `smart_resolve_path_fragment` function.627    /// Creates base error and amends it with one short label and possibly some longer helps/notes.628    #[tracing::instrument(skip(self), level = "debug")]629    pub(crate) fn smart_resolve_report_errors(630        &mut self,631        path: &[Segment],632        following_seg: Option<&Segment>,633        span: Span,634        source: PathSource<'_, 'ast, 'ra>,635        res: Option<Res>,636        qself: Option<&QSelf>,637    ) -> (Diag<'tcx>, Vec<ImportSuggestion>) {638        debug!(?res, ?source);639        let base_error = self.make_base_error(path, span, source, res);640641        let code = source.error_code(res.is_some());642        let mut err = self.r.dcx().struct_span_err(base_error.span, base_error.msg.clone());643        err.code(code);644645        // Try to get the span of the identifier within the path's syntax context646        // (if that's different).647        if let Some(within_macro_span) =648            base_error.span.within_macro(span, self.r.tcx.sess.source_map())649        {650            err.span_label(within_macro_span, "due to this macro variable");651        }652653        self.detect_missing_binding_available_from_pattern(&mut err, path, following_seg);654        self.suggest_at_operator_in_slice_pat_with_range(&mut err, path);655        self.suggest_range_struct_destructuring(&mut err, path, source);656        self.suggest_swapping_misplaced_self_ty_and_trait(&mut err, source, res, base_error.span);657658        if let Some((span, label)) = base_error.span_label {659            err.span_label(span, label);660        }661662        if let Some(ref sugg) = base_error.suggestion {663            err.span_suggestion_verbose(sugg.0, sugg.1, &sugg.2, Applicability::MaybeIncorrect);664        }665666        self.suggest_changing_type_to_const_param(&mut err, res, source, path, following_seg, span);667        self.explain_functions_in_pattern(&mut err, res, source);668669        if self.suggest_pattern_match_with_let(&mut err, source, span) {670            // Fallback label.671            err.span_label(base_error.span, base_error.fallback_label);672            return (err, Vec::new());673        }674675        self.suggest_self_or_self_ref(&mut err, path, span);676        self.detect_assoc_type_constraint_meant_as_path(&mut err, &base_error);677        self.detect_rtn_with_fully_qualified_path(678            &mut err,679            path,680            following_seg,681            span,682            source,683            res,684            qself,685        );686        if self.suggest_self_ty(&mut err, source, path, span)687            || self.suggest_self_value(&mut err, source, path, span)688        {689            return (err, Vec::new());690        }691692        if let Some((did, item)) = self.lookup_doc_alias_name(path, source.namespace()) {693            let item_name = item.name;694            let suggestion_name = self.r.tcx.item_name(did);695            err.span_suggestion(696                item.span,697                format!("`{suggestion_name}` has a name defined in the doc alias attribute as `{item_name}`"),698                    suggestion_name,699                    Applicability::MaybeIncorrect700                );701702            return (err, Vec::new());703        };704705        let (found, suggested_candidates, mut candidates) = self.try_lookup_name_relaxed(706            &mut err,707            source,708            path,709            following_seg,710            span,711            res,712            &base_error,713        );714        if found {715            return (err, candidates);716        }717718        if self.suggest_shadowed(&mut err, source, path, following_seg, span) {719            // if there is already a shadowed name, don'suggest candidates for importing720            candidates.clear();721        }722723        let mut fallback = self.suggest_trait_and_bounds(&mut err, source, res, span, &base_error);724        fallback |= self.suggest_typo(725            &mut err,726            source,727            path,728            following_seg,729            span,730            &base_error,731            suggested_candidates,732        );733734        if fallback {735            // Fallback label.736            err.span_label(base_error.span, base_error.fallback_label);737        }738        self.err_code_special_cases(&mut err, source, path, span);739740        let module = base_error.module.unwrap_or_else(|| CRATE_DEF_ID.to_def_id());741        self.r.find_cfg_stripped(&mut err, &path.last().unwrap().ident.name, module);742743        (err, candidates)744    }745746    fn detect_rtn_with_fully_qualified_path(747        &self,748        err: &mut Diag<'_>,749        path: &[Segment],750        following_seg: Option<&Segment>,751        span: Span,752        source: PathSource<'_, '_, '_>,753        res: Option<Res>,754        qself: Option<&QSelf>,755    ) {756        if let Some(Res::Def(DefKind::AssocFn, _)) = res757            && let PathSource::TraitItem(TypeNS, _) = source758            && let None = following_seg759            && let Some(qself) = qself760            && let TyKind::Path(None, ty_path) = &qself.ty.kind761            && ty_path.segments.len() == 1762            && self.diag_metadata.current_where_predicate.is_some()763        {764            err.span_suggestion_verbose(765                span,766                "you might have meant to use the return type notation syntax",767                format!("{}::{}(..)", ty_path.segments[0].ident, path[path.len() - 1].ident),768                Applicability::MaybeIncorrect,769            );770        }771    }772773    fn detect_assoc_type_constraint_meant_as_path(774        &self,775        err: &mut Diag<'_>,776        base_error: &BaseError,777    ) {778        let Some(ty) = self.diag_metadata.current_type_path else {779            return;780        };781        let TyKind::Path(_, path) = &ty.kind else {782            return;783        };784        for segment in &path.segments {785            let Some(params) = &segment.args else {786                continue;787            };788            let ast::GenericArgs::AngleBracketed(params) = params.deref() else {789                continue;790            };791            for param in &params.args {792                let ast::AngleBracketedArg::Constraint(constraint) = param else {793                    continue;794                };795                let ast::AssocItemConstraintKind::Bound { bounds } = &constraint.kind else {796                    continue;797                };798                for bound in bounds {799                    let ast::GenericBound::Trait(trait_ref) = bound else {800                        continue;801                    };802                    if trait_ref.modifiers == ast::TraitBoundModifiers::NONE803                        && base_error.span == trait_ref.span804                    {805                        err.span_suggestion_verbose(806                            constraint.ident.span.between(trait_ref.span),807                            "you might have meant to write a path instead of an associated type bound",808                            "::",809                            Applicability::MachineApplicable,810                        );811                    }812                }813            }814        }815    }816817    fn suggest_self_or_self_ref(&mut self, err: &mut Diag<'_>, path: &[Segment], span: Span) {818        if !self.self_type_is_available() {819            return;820        }821        let Some(path_last_segment) = path.last() else { return };822        let item_str = path_last_segment.ident;823        // Emit help message for fake-self from other languages (e.g., `this` in JavaScript).824        if ["this", "my"].contains(&item_str.as_str()) {825            err.span_suggestion_short(826                span,827                "you might have meant to use `self` here instead",828                "self",829                Applicability::MaybeIncorrect,830            );831            if !self.self_value_is_available(path[0].ident.span) {832                if let Some((FnKind::Fn(_, _, ast::Fn { sig, .. }), fn_span)) =833                    &self.diag_metadata.current_function834                {835                    let (span, sugg) = if let Some(param) = sig.decl.inputs.get(0) {836                        (param.span.shrink_to_lo(), "&self, ")837                    } else {838                        (839                            self.r840                                .tcx841                                .sess842                                .source_map()843                                .span_through_char(*fn_span, '(')844                                .shrink_to_hi(),845                            "&self",846                        )847                    };848                    err.span_suggestion_verbose(849                        span,850                        "if you meant to use `self`, you are also missing a `self` receiver \851                         argument",852                        sugg,853                        Applicability::MaybeIncorrect,854                    );855                }856            }857        }858    }859860    fn try_lookup_name_relaxed(861        &mut self,862        err: &mut Diag<'_>,863        source: PathSource<'_, '_, '_>,864        path: &[Segment],865        following_seg: Option<&Segment>,866        span: Span,867        res: Option<Res>,868        base_error: &BaseError,869    ) -> (bool, FxHashSet<String>, Vec<ImportSuggestion>) {870        let span = match following_seg {871            Some(_) if path[0].ident.span.eq_ctxt(path[path.len() - 1].ident.span) => {872                // The path `span` that comes in includes any following segments, which we don't873                // want to replace in the suggestions.874                path[0].ident.span.to(path[path.len() - 1].ident.span)875            }876            _ => span,877        };878        let mut suggested_candidates = FxHashSet::default();879        // Try to lookup name in more relaxed fashion for better error reporting.880        let ident = path.last().unwrap().ident;881        let is_expected = &|res| source.is_expected(res);882        let ns = source.namespace();883        let is_enum_variant = &|res| matches!(res, Res::Def(DefKind::Variant, _));884        let path_str = Segment::names_to_string(path);885        let ident_span = path.last().map_or(span, |ident| ident.ident.span);886        let mut candidates = self887            .r888            .lookup_import_candidates(ident, ns, &self.parent_scope, is_expected)889            .into_iter()890            .filter(|ImportSuggestion { did, .. }| {891                match (did, res.and_then(|res| res.opt_def_id())) {892                    (Some(suggestion_did), Some(actual_did)) => *suggestion_did != actual_did,893                    _ => true,894                }895            })896            .collect::<Vec<_>>();897        // Try to filter out intrinsics candidates, as long as we have898        // some other candidates to suggest.899        let intrinsic_candidates: Vec<_> = candidates900            .extract_if(.., |sugg| {901                let path = path_names_to_string(&sugg.path);902                path.starts_with("core::intrinsics::") || path.starts_with("std::intrinsics::")903            })904            .collect();905        if candidates.is_empty() {906            // Put them back if we have no more candidates to suggest...907            candidates = intrinsic_candidates;908        }909        let crate_def_id = CRATE_DEF_ID.to_def_id();910        if candidates.is_empty() && is_expected(Res::Def(DefKind::Enum, crate_def_id)) {911            let mut enum_candidates: Vec<_> = self912                .r913                .lookup_import_candidates(ident, ns, &self.parent_scope, is_enum_variant)914                .into_iter()915                .map(|suggestion| import_candidate_to_enum_paths(&suggestion))916                .filter(|(_, enum_ty_path)| !enum_ty_path.starts_with("std::prelude::"))917                .collect();918            if !enum_candidates.is_empty() {919                enum_candidates.sort();920921                // Contextualize for E0425 "cannot find type", but don't belabor the point922                // (that it's a variant) for E0573 "expected type, found variant".923                let preamble = if res.is_none() {924                    let others = match enum_candidates.len() {925                        1 => String::new(),926                        2 => " and 1 other".to_owned(),927                        n => format!(" and {n} others"),928                    };929                    format!("there is an enum variant `{}`{}; ", enum_candidates[0].0, others)930                } else {931                    String::new()932                };933                let msg = format!("{preamble}try using the variant's enum");934935                suggested_candidates.extend(936                    enum_candidates937                        .iter()938                        .map(|(_variant_path, enum_ty_path)| enum_ty_path.clone()),939                );940                err.span_suggestions(941                    span,942                    msg,943                    enum_candidates.into_iter().map(|(_variant_path, enum_ty_path)| enum_ty_path),944                    Applicability::MachineApplicable,945                );946            }947        }948949        // Try finding a suitable replacement.950        let typo_sugg = self951            .lookup_typo_candidate(path, following_seg, source.namespace(), is_expected)952            .to_opt_suggestion()953            .filter(|sugg| !suggested_candidates.contains(sugg.candidate.as_str()));954        if let [segment] = path955            && !matches!(source, PathSource::Delegation)956            && self.self_type_is_available()957        {958            if let Some(candidate) =959                self.lookup_assoc_candidate(ident, ns, is_expected, source.is_call())960            {961                let self_is_available = self.self_value_is_available(segment.ident.span);962                // Account for `Foo { field }` when suggesting `self.field` so we result on963                // `Foo { field: self.field }`.964                let pre = match source {965                    PathSource::Expr(Some(Expr { kind: ExprKind::Struct(expr), .. }))966                        if expr967                            .fields968                            .iter()969                            .any(|f| f.ident == segment.ident && f.is_shorthand) =>970                    {971                        format!("{path_str}: ")972                    }973                    _ => String::new(),974                };975                match candidate {976                    AssocSuggestion::Field(field_span) => {977                        if self_is_available {978                            let source_map = self.r.tcx.sess.source_map();979                            let field_is_format_named_arg = matches!(980                                span.desugaring_kind(),981                                Some(DesugaringKind::FormatLiteral { .. })982                            ) && source_map983                                .span_to_source(span, |s, start, _| {984                                    Ok(s.get(start.saturating_sub(1)..start) == Some("{"))985                                })986                                .unwrap_or(false);987                            if field_is_format_named_arg {988                                err.help(989                                    format!("you might have meant to use the available field in a format string: `\"{{}}\", self.{}`", segment.ident.name),990                                );991                            } else {992                                err.span_suggestion_verbose(993                                    span.shrink_to_lo(),994                                    "you might have meant to use the available field",995                                    format!("{pre}self."),996                                    Applicability::MaybeIncorrect,997                                );998                            }999                        } else {1000                            err.span_label(field_span, "a field by that name exists in `Self`");1001                        }1002                    }1003                    AssocSuggestion::MethodWithSelf { called } if self_is_available => {1004                        let msg = if called {1005                            "you might have meant to call the method"1006                        } else {1007                            "you might have meant to refer to the method"1008                        };1009                        err.span_suggestion_verbose(1010                            span.shrink_to_lo(),1011                            msg,1012                            "self.",1013                            Applicability::MachineApplicable,1014                        );1015                    }1016                    AssocSuggestion::MethodWithSelf { .. }1017                    | AssocSuggestion::AssocFn { .. }1018                    | AssocSuggestion::AssocConst1019                    | AssocSuggestion::AssocType => {1020                        err.span_suggestion_verbose(1021                            span.shrink_to_lo(),1022                            format!("you might have meant to {}", candidate.action()),1023                            "Self::",1024                            Applicability::MachineApplicable,1025                        );1026                    }1027                }1028                self.r.add_typo_suggestion(err, typo_sugg, ident_span);1029                return (true, suggested_candidates, candidates);1030            }10311032            // If the first argument in call is `self` suggest calling a method.1033            if let Some((call_span, args_span)) = self.call_has_self_arg(source) {1034                let mut args_snippet = String::new();1035                if let Some(args_span) = args_span1036                    && let Ok(snippet) = self.r.tcx.sess.source_map().span_to_snippet(args_span)1037                {1038                    args_snippet = snippet;1039                }10401041                if let Some(Res::Def(DefKind::Struct, def_id)) = res {1042                    if let Some(ctor) = self.r.struct_ctor(def_id)1043                        && ctor.has_private_fields(self.parent_scope.module, self.r)1044                    {1045                        if matches!(1046                            ctor.res,1047                            Res::Def(DefKind::Ctor(CtorOf::Struct, CtorKind::Fn), _)1048                        ) {1049                            self.update_err_for_private_tuple_struct_fields(err, &source, def_id);1050                        }1051                        err.note("constructor is not visible here due to private fields");1052                    }1053                } else {1054                    err.span_suggestion(1055                        call_span,1056                        format!("try calling `{ident}` as a method"),1057                        format!("self.{path_str}({args_snippet})"),1058                        Applicability::MachineApplicable,1059                    );1060                }10611062                return (true, suggested_candidates, candidates);1063            }1064        }10651066        // Try context-dependent help if relaxed lookup didn't work.1067        if let Some(res) = res {1068            if self.smart_resolve_context_dependent_help(1069                err,1070                span,1071                source,1072                path,1073                res,1074                &path_str,1075                &base_error.fallback_label,1076            ) {1077                // We do this to avoid losing a secondary span when we override the main error span.1078                self.r.add_typo_suggestion(err, typo_sugg, ident_span);1079                return (true, suggested_candidates, candidates);1080            }1081        }10821083        // Try to find in last block rib1084        if let Some(rib) = &self.last_block_rib {1085            for (ident, &res) in &rib.bindings {1086                if let Res::Local(_) = res1087                    && path.len() == 11088                    && ident.span.eq_ctxt(path[0].ident.span)1089                    && ident.name == path[0].ident.name1090                {1091                    err.span_help(1092                        ident.span,1093                        format!("the binding `{path_str}` is available in a different scope in the same function"),1094                    );1095                    return (true, suggested_candidates, candidates);1096                }1097            }1098        }10991100        if candidates.is_empty() {1101            candidates = self.smart_resolve_partial_mod_path_errors(path, following_seg);1102        }11031104        (false, suggested_candidates, candidates)1105    }11061107    fn lookup_doc_alias_name(&mut self, path: &[Segment], ns: Namespace) -> Option<(DefId, Ident)> {1108        let find_doc_alias_name = |r: &mut Resolver<'ra, '_>, m: Module<'ra>, item_name: Symbol| {1109            for resolution in r.resolutions(m).borrow().values() {1110                let Some(did) =1111                    resolution.borrow().best_decl().and_then(|binding| binding.res().opt_def_id())1112                else {1113                    continue;1114                };1115                if did.is_local() {1116                    // We don't record the doc alias name in the local crate1117                    // because the people who write doc alias are usually not1118                    // confused by them.1119                    continue;1120                }1121                if let Some(d) = hir::find_attr!(r.tcx, did, Doc(d) => d)1122                    && d.aliases.contains_key(&item_name)1123                {1124                    return Some(did);1125                }1126            }1127            None1128        };11291130        if path.len() == 1 {1131            for rib in self.ribs[ns].iter().rev() {1132                let item = path[0].ident;1133                if let RibKind::Module(module) | RibKind::Block(Some(module)) = rib.kind1134                    && let Some(did) = find_doc_alias_name(self.r, module.to_module(), item.name)1135                {1136                    return Some((did, item));1137                }1138            }1139        } else {1140            // Finds to the last resolved module item in the path1141            // and searches doc aliases within that module.1142            //1143            // Example: For the path `a::b::last_resolved::not_exist::c::d`,1144            // we will try to find any item has doc aliases named `not_exist`1145            // in `last_resolved` module.1146            //1147            // - Use `skip(1)` because the final segment must remain unresolved.1148            for (idx, seg) in path.iter().enumerate().rev().skip(1) {1149                let Some(id) = seg.id else {1150                    continue;1151                };1152                let Some(res) = self.r.partial_res_map.get(&id) else {1153                    continue;1154                };1155                if let Res::Def(DefKind::Mod, module) = res.expect_full_res()1156                    && let module = self.r.expect_module(module)1157                    && let item = path[idx + 1].ident1158                    && let Some(did) = find_doc_alias_name(self.r, module, item.name)1159                {1160                    return Some((did, item));1161                }1162                break;1163            }1164        }1165        None1166    }11671168    fn suggest_trait_and_bounds(1169        &self,1170        err: &mut Diag<'_>,1171        source: PathSource<'_, '_, '_>,1172        res: Option<Res>,1173        span: Span,1174        base_error: &BaseError,1175    ) -> bool {1176        let is_macro =1177            base_error.span.from_expansion() && base_error.span.desugaring_kind().is_none();1178        let mut fallback = false;11791180        if let (1181            PathSource::Trait(AliasPossibility::Maybe),1182            Some(Res::Def(DefKind::Struct | DefKind::Enum | DefKind::Union, _)),1183            false,1184        ) = (source, res, is_macro)1185            && let Some(bounds @ [first_bound, .., last_bound]) =1186                self.diag_metadata.current_trait_object1187        {1188            fallback = true;1189            let spans: Vec<Span> = bounds1190                .iter()1191                .map(|bound| bound.span())1192                .filter(|&sp| sp != base_error.span)1193                .collect();11941195            let start_span = first_bound.span();1196            // `end_span` is the end of the poly trait ref (Foo + 'baz + Bar><)1197            let end_span = last_bound.span();1198            // `last_bound_span` is the last bound of the poly trait ref (Foo + >'baz< + Bar)1199            let last_bound_span = spans.last().cloned().unwrap();1200            let mut multi_span: MultiSpan = spans.clone().into();1201            for sp in spans {1202                let msg = if sp == last_bound_span {1203                    format!(1204                        "...because of {these} bound{s}",1205                        these = pluralize!("this", bounds.len() - 1),1206                        s = pluralize!(bounds.len() - 1),1207                    )1208                } else {1209                    String::new()1210                };1211                multi_span.push_span_label(sp, msg);1212            }1213            multi_span.push_span_label(base_error.span, "expected this type to be a trait...");1214            err.span_help(1215                multi_span,1216                "`+` is used to constrain a \"trait object\" type with lifetimes or \1217                        auto-traits; structs and enums can't be bound in that way",1218            );1219            if bounds.iter().all(|bound| match bound {1220                ast::GenericBound::Outlives(_) | ast::GenericBound::Use(..) => true,1221                ast::GenericBound::Trait(tr) => tr.span == base_error.span,1222            }) {1223                let mut sugg = vec![];1224                if base_error.span != start_span {1225                    sugg.push((start_span.until(base_error.span), String::new()));1226                }1227                if base_error.span != end_span {1228                    sugg.push((base_error.span.shrink_to_hi().to(end_span), String::new()));1229                }12301231                err.multipart_suggestion(1232                    "if you meant to use a type and not a trait here, remove the bounds",1233                    sugg,1234                    Applicability::MaybeIncorrect,1235                );1236            }1237        }12381239        fallback |= self.restrict_assoc_type_in_where_clause(span, err);1240        fallback1241    }12421243    fn suggest_typo(1244        &mut self,1245        err: &mut Diag<'_>,1246        source: PathSource<'_, 'ast, 'ra>,1247        path: &[Segment],1248        following_seg: Option<&Segment>,1249        span: Span,1250        base_error: &BaseError,1251        suggested_candidates: FxHashSet<String>,1252    ) -> bool {1253        let is_expected = &|res| source.is_expected(res);1254        let ident_span = path.last().map_or(span, |ident| ident.ident.span);12551256        // Prefer suggestions based on associated types from in-scope bounds (e.g. `T::Item`)1257        // over purely edit-distance-based identifier suggestions.1258        // Otherwise suggestions could be verbose.1259        if self.suggest_assoc_type_from_bounds(err, source, path, ident_span) {1260            return false;1261        }12621263        let typo_sugg =1264            self.lookup_typo_candidate(path, following_seg, source.namespace(), is_expected);1265        let mut fallback = false;1266        let typo_sugg = typo_sugg1267            .to_opt_suggestion()1268            .filter(|sugg| !suggested_candidates.contains(sugg.candidate.as_str()));1269        if !self.r.add_typo_suggestion(err, typo_sugg, ident_span) {1270            fallback = true;1271            match self.diag_metadata.current_let_binding {1272                Some((pat_sp, Some(ty_sp), None))1273                    if ty_sp.contains(base_error.span) && base_error.could_be_expr =>1274                {1275                    err.span_suggestion_verbose(1276                        pat_sp.between(ty_sp),1277                        "use `=` if you meant to assign",1278                        " = ",1279                        Applicability::MaybeIncorrect,1280                    );1281                }1282                _ => {}1283            }12841285            // If the trait has a single item (which wasn't matched by the algorithm), suggest it1286            let suggestion = self.get_single_associated_item(path, &source, is_expected);1287            self.r.add_typo_suggestion(err, suggestion, ident_span);1288        }12891290        if self.let_binding_suggestion(err, ident_span) {1291            fallback = false;1292        }12931294        fallback1295    }12961297    fn suggest_shadowed(1298        &mut self,1299        err: &mut Diag<'_>,1300        source: PathSource<'_, '_, '_>,1301        path: &[Segment],1302        following_seg: Option<&Segment>,1303        span: Span,1304    ) -> bool {1305        let is_expected = &|res| source.is_expected(res);1306        let typo_sugg =1307            self.lookup_typo_candidate(path, following_seg, source.namespace(), is_expected);1308        let is_in_same_file = &|sp1, sp2| {1309            let source_map = self.r.tcx.sess.source_map();1310            let file1 = source_map.span_to_filename(sp1);1311            let file2 = source_map.span_to_filename(sp2);1312            file1 == file21313        };1314        // print 'you might have meant' if the candidate is (1) is a shadowed name with1315        // accessible definition and (2) either defined in the same crate as the typo1316        // (could be in a different file) or introduced in the same file as the typo1317        // (could belong to a different crate)1318        if let TypoCandidate::Shadowed(res, Some(sugg_span)) = typo_sugg1319            && res.opt_def_id().is_some_and(|id| id.is_local() || is_in_same_file(span, sugg_span))1320        {1321            err.span_label(1322                sugg_span,1323                format!("you might have meant to refer to this {}", res.descr()),1324            );1325            return true;1326        }1327        false1328    }13291330    fn err_code_special_cases(1331        &mut self,1332        err: &mut Diag<'_>,1333        source: PathSource<'_, '_, '_>,1334        path: &[Segment],1335        span: Span,1336    ) {1337        if let Some(err_code) = err.code {1338            if err_code == E0425 {1339                for label_rib in &self.label_ribs {1340                    for (label_ident, node_id) in &label_rib.bindings {1341                        let ident = path.last().unwrap().ident;1342                        if format!("'{ident}") == label_ident.to_string() {1343                            err.span_label(label_ident.span, "a label with a similar name exists");1344                            if let PathSource::Expr(Some(Expr {1345                                kind: ExprKind::Break(None, Some(_)),1346                                ..1347                            })) = source1348                            {1349                                err.span_suggestion(1350                                    span,1351                                    "use the similarly named label",1352                                    label_ident.name,1353                                    Applicability::MaybeIncorrect,1354                                );1355                                // Do not lint against unused label when we suggest them.1356                                self.diag_metadata.unused_labels.swap_remove(node_id);1357                            }1358                        }1359                    }1360                }13611362                self.suggest_ident_hidden_by_hygiene(err, path, span);1363                // cannot find type in this scope1364                if let Some(correct) = Self::likely_rust_type(path) {1365                    err.span_suggestion(1366                        span,1367                        "perhaps you intended to use this type",1368                        correct,1369                        Applicability::MaybeIncorrect,1370                    );1371                }1372            }1373        }1374    }13751376    fn suggest_ident_hidden_by_hygiene(&self, err: &mut Diag<'_>, path: &[Segment], span: Span) {1377        let [segment] = path else { return };13781379        let ident = segment.ident;1380        let callsite_span = span.source_callsite();1381        for rib in self.ribs[ValueNS].iter().rev() {1382            for (binding_ident, _) in &rib.bindings {1383                // Case 1: the identifier is defined in the same scope as the macro is called1384                if binding_ident.name == ident.name1385                    && !binding_ident.span.eq_ctxt(span)1386                    && !binding_ident.span.from_expansion()1387                    && binding_ident.span.lo() < callsite_span.lo()1388                {1389                    err.span_help(1390                        binding_ident.span,1391                        "an identifier with the same name exists, but is not accessible due to macro hygiene",1392                    );1393                    return;1394                }13951396                // Case 2: the identifier is defined in a macro call in the same scope1397                if binding_ident.name == ident.name1398                    && binding_ident.span.from_expansion()1399                    && binding_ident.span.source_callsite().eq_ctxt(callsite_span)1400                    && binding_ident.span.source_callsite().lo() < callsite_span.lo()1401                {1402                    err.span_help(1403                        binding_ident.span,1404                        "an identifier with the same name is defined here, but is not accessible due to macro hygiene",1405                    );1406                    return;1407                }1408            }1409        }1410    }14111412    /// Emit special messages for unresolved `Self` and `self`.1413    fn suggest_self_ty(1414        &self,1415        err: &mut Diag<'_>,1416        source: PathSource<'_, '_, '_>,1417        path: &[Segment],1418        span: Span,1419    ) -> bool {1420        if !is_self_type(path, source.namespace()) {1421            return false;1422        }1423        err.code(E0411);1424        err.span_label(span, "`Self` is only available in impls, traits, and type definitions");1425        if let Some(item) = self.diag_metadata.current_item1426            && let Some(ident) = item.kind.ident()1427        {1428            err.span_label(1429                ident.span,1430                format!("`Self` not allowed in {} {}", item.kind.article(), item.kind.descr()),1431            );1432        }1433        true1434    }14351436    fn suggest_self_value(1437        &mut self,1438        err: &mut Diag<'_>,1439        source: PathSource<'_, '_, '_>,1440        path: &[Segment],1441        span: Span,1442    ) -> bool {1443        if !is_self_value(path, source.namespace()) {1444            return false;1445        }14461447        debug!("smart_resolve_path_fragment: E0424, source={:?}", source);1448        err.code(E0424);1449        err.span_label(1450            span,1451            match source {1452                PathSource::Pat => {1453                    "`self` value is a keyword and may not be bound to variables or shadowed"1454                }1455                _ => "`self` value is a keyword only available in methods with a `self` parameter",1456            },1457        );14581459        // using `let self` is wrong even if we're not in an associated method or if we're in a macro expansion.1460        // So, we should return early if we're in a pattern, see issue #143134.1461        if matches!(source, PathSource::Pat) {1462            return true;1463        }14641465        let is_assoc_fn = self.self_type_is_available();1466        let self_from_macro = "a `self` parameter, but a macro invocation can only \1467                               access identifiers it receives from parameters";1468        if let Some((fn_kind, fn_span)) = &self.diag_metadata.current_function {1469            // The current function has a `self` parameter, but we were unable to resolve1470            // a reference to `self`. This can only happen if the `self` identifier we1471            // are resolving came from a different hygiene context or a variable binding.1472            // But variable binding error is returned early above.1473            if fn_kind.decl().inputs.get(0).is_some_and(|p| p.is_self()) {1474                err.span_label(*fn_span, format!("this function has {self_from_macro}"));1475            } else {1476                let doesnt = if is_assoc_fn {1477                    let (span, sugg) = fn_kind1478                        .decl()1479                        .inputs1480                        .get(0)1481                        .map(|p| (p.span.shrink_to_lo(), "&self, "))1482                        .unwrap_or_else(|| {1483                            // Try to look for the "(" after the function name, if possible.1484                            // This avoids placing the suggestion into the visibility specifier.1485                            let span = fn_kind1486                                .ident()1487                                .map_or(*fn_span, |ident| fn_span.with_lo(ident.span.hi()));1488                            (1489                                self.r1490                                    .tcx1491                                    .sess1492                                    .source_map()1493                                    .span_through_char(span, '(')1494                                    .shrink_to_hi(),1495                                "&self",1496                            )1497                        });1498                    err.span_suggestion_verbose(1499                        span,1500                        "add a `self` receiver parameter to make the associated `fn` a method",1501                        sugg,1502                        Applicability::MaybeIncorrect,1503                    );1504                    "doesn't"1505                } else {1506                    "can't"1507                };1508                if let Some(ident) = fn_kind.ident() {1509                    err.span_label(1510                        ident.span,1511                        format!("this function {doesnt} have a `self` parameter"),1512                    );1513                }1514            }1515        } else if let Some(item) = self.diag_metadata.current_item {1516            if matches!(item.kind, ItemKind::Delegation(..)) {1517                err.span_label(item.span, format!("delegation supports {self_from_macro}"));1518            } else {1519                let span = if let Some(ident) = item.kind.ident() { ident.span } else { item.span };1520                err.span_label(1521                    span,1522                    format!("`self` not allowed in {} {}", item.kind.article(), item.kind.descr()),1523                );1524            }1525        }1526        true1527    }15281529    fn detect_missing_binding_available_from_pattern(1530        &self,1531        err: &mut Diag<'_>,1532        path: &[Segment],1533        following_seg: Option<&Segment>,1534    ) {1535        let [segment] = path else { return };1536        let None = following_seg else { return };1537        for rib in self.ribs[ValueNS].iter().rev() {1538            let patterns_with_skipped_bindings =1539                self.r.tcx.with_stable_hashing_context(|mut hcx| {1540                    rib.patterns_with_skipped_bindings.to_sorted(&mut hcx, true)1541                });1542            for (def_id, spans) in patterns_with_skipped_bindings {1543                if let DefKind::Struct | DefKind::Variant = self.r.tcx.def_kind(*def_id)1544                    && let Some(fields) = self.r.field_idents(*def_id)1545                {1546                    for field in fields {1547                        if field.name == segment.ident.name {1548                            if spans.iter().all(|(_, had_error)| had_error.is_err()) {1549                                // This resolution error will likely be fixed by fixing a1550                                // syntax error in a pattern, so it is irrelevant to the user.1551                                let multispan: MultiSpan =1552                                    spans.iter().map(|(s, _)| *s).collect::<Vec<_>>().into();1553                                err.span_note(1554                                    multispan,1555                                    "this pattern had a recovered parse error which likely lost \1556                                     the expected fields",1557                                );1558                                err.downgrade_to_delayed_bug();1559                            }1560                            let ty = self.r.tcx.item_name(*def_id);1561                            for (span, _) in spans {1562                                err.span_label(1563                                    *span,1564                                    format!(1565                                        "this pattern doesn't include `{field}`, which is \1566                                         available in `{ty}`",1567                                    ),1568                                );1569                            }1570                        }1571                    }1572                }1573            }1574        }1575    }15761577    fn suggest_at_operator_in_slice_pat_with_range(&self, err: &mut Diag<'_>, path: &[Segment]) {1578        let Some(pat) = self.diag_metadata.current_pat else { return };1579        let (bound, side, range) = match &pat.kind {1580            ast::PatKind::Range(Some(bound), None, range) => (bound, Side::Start, range),1581            ast::PatKind::Range(None, Some(bound), range) => (bound, Side::End, range),1582            _ => return,1583        };1584        if let ExprKind::Path(None, range_path) = &bound.kind1585            && let [segment] = &range_path.segments[..]1586            && let [s] = path1587            && segment.ident == s.ident1588            && segment.ident.span.eq_ctxt(range.span)1589        {1590            // We've encountered `[first, rest..]` (#88404) or `[first, ..rest]` (#120591)1591            // where the user might have meant `[first, rest @ ..]`.1592            let (span, snippet) = match side {1593                Side::Start => (segment.ident.span.between(range.span), " @ ".into()),1594                Side::End => (range.span.to(segment.ident.span), format!("{} @ ..", segment.ident)),1595            };1596            err.subdiagnostic(diagnostics::UnexpectedResUseAtOpInSlicePatWithRangeSugg {1597                span,1598                ident: segment.ident,1599                snippet,1600            });1601        }16021603        enum Side {1604            Start,1605            End,1606        }1607    }16081609    fn suggest_range_struct_destructuring(1610        &mut self,1611        err: &mut Diag<'_>,1612        path: &[Segment],1613        source: PathSource<'_, '_, '_>,1614    ) {1615        if !matches!(source, PathSource::Pat | PathSource::TupleStruct(..) | PathSource::Expr(..)) {1616            return;1617        }16181619        let Some(pat) = self.diag_metadata.current_pat else { return };1620        let ast::PatKind::Range(start, end, end_kind) = &pat.kind else { return };16211622        let [segment] = path else { return };1623        let failing_span = segment.ident.span;16241625        let in_start = start.as_ref().is_some_and(|e| e.span.contains(failing_span));1626        let in_end = end.as_ref().is_some_and(|e| e.span.contains(failing_span));16271628        if !in_start && !in_end {1629            return;1630        }16311632        let start_snippet =1633            start.as_ref().and_then(|e| self.r.tcx.sess.source_map().span_to_snippet(e.span).ok());1634        let end_snippet =1635            end.as_ref().and_then(|e| self.r.tcx.sess.source_map().span_to_snippet(e.span).ok());16361637        let field = |name: &str, val: String| {1638            if val == name { val } else { format!("{name}: {val}") }1639        };16401641        let mut resolve_short_name = |short: Symbol, full: &str| -> String {1642            let ident = Ident::with_dummy_span(short);1643            let path = Segment::from_path(&Path::from_ident(ident));16441645            match self.resolve_path(&path, Some(TypeNS), None, PathSource::Type) {1646                PathResult::NonModule(..) => short.to_string(),1647                _ => full.to_string(),1648            }1649        };1650        // FIXME(new_range): Also account for new range types1651        let (struct_path, fields) = match (start_snippet, end_snippet, &end_kind.node) {1652            (Some(start), Some(end), ast::RangeEnd::Excluded) => (1653                resolve_short_name(sym::Range, "std::ops::Range"),1654                vec![field("start", start), field("end", end)],1655            ),1656            (Some(start), Some(end), ast::RangeEnd::Included(_)) => (1657                resolve_short_name(sym::RangeInclusive, "std::ops::RangeInclusive"),1658                vec![field("start", start), field("end", end)],1659            ),1660            (Some(start), None, _) => (1661                resolve_short_name(sym::RangeFrom, "std::ops::RangeFrom"),1662                vec![field("start", start)],1663            ),1664            (None, Some(end), ast::RangeEnd::Excluded) => {1665                (resolve_short_name(sym::RangeTo, "std::ops::RangeTo"), vec![field("end", end)])1666            }1667            (None, Some(end), ast::RangeEnd::Included(_)) => (1668                resolve_short_name(sym::RangeToInclusive, "std::ops::RangeToInclusive"),1669                vec![field("end", end)],1670            ),1671            _ => return,1672        };16731674        err.span_suggestion_verbose(1675            pat.span,1676            format!("if you meant to destructure a range use a struct pattern"),1677            format!("{} {{ {} }}", struct_path, fields.join(", ")),1678            Applicability::MaybeIncorrect,1679        );16801681        err.note(1682            "range patterns match against the start and end of a range; \1683             to bind the components, use a struct pattern",1684        );1685    }16861687    fn suggest_swapping_misplaced_self_ty_and_trait(1688        &mut self,1689        err: &mut Diag<'_>,1690        source: PathSource<'_, 'ast, 'ra>,1691        res: Option<Res>,1692        span: Span,1693    ) {1694        if let Some((trait_ref, self_ty)) =1695            self.diag_metadata.currently_processing_impl_trait.clone()1696            && let TyKind::Path(_, self_ty_path) = &self_ty.kind1697            && let PathResult::Module(ModuleOrUniformRoot::Module(module)) =1698                self.resolve_path(&Segment::from_path(self_ty_path), Some(TypeNS), None, source)1699            && module.def_kind() == Some(DefKind::Trait)1700            && trait_ref.path.span == span1701            && let PathSource::Trait(_) = source1702            && let Some(Res::Def(DefKind::Struct | DefKind::Enum | DefKind::Union, _)) = res1703            && let Ok(self_ty_str) = self.r.tcx.sess.source_map().span_to_snippet(self_ty.span)1704            && let Ok(trait_ref_str) =1705                self.r.tcx.sess.source_map().span_to_snippet(trait_ref.path.span)1706        {1707            err.multipart_suggestion(1708                    "`impl` items mention the trait being implemented first and the type it is being implemented for second",1709                    vec![(trait_ref.path.span, self_ty_str), (self_ty.span, trait_ref_str)],1710                    Applicability::MaybeIncorrect,1711                );1712        }1713    }17141715    fn explain_functions_in_pattern(1716        &self,1717        err: &mut Diag<'_>,1718        res: Option<Res>,1719        source: PathSource<'_, '_, '_>,1720    ) {1721        let PathSource::TupleStruct(_, _) = source else { return };1722        let Some(Res::Def(DefKind::Fn, _)) = res else { return };1723        err.primary_message("expected a pattern, found a function call");1724        err.note("function calls are not allowed in patterns: <https://doc.rust-lang.org/book/ch19-00-patterns.html>");1725    }17261727    fn suggest_changing_type_to_const_param(1728        &self,1729        err: &mut Diag<'_>,1730        res: Option<Res>,1731        source: PathSource<'_, '_, '_>,1732        path: &[Segment],1733        following_seg: Option<&Segment>,1734        span: Span,1735    ) {1736        if let PathSource::Expr(None) = source1737            && let Some(Res::Def(DefKind::TyParam, _)) = res1738            && following_seg.is_none()1739            && let [segment] = path1740        {1741            // We have something like1742            // impl<T, N> From<[T; N]> for VecWrapper<T> {1743            //     fn from(slice: [T; N]) -> Self {1744            //         VecWrapper(slice.to_vec())1745            //     }1746            // }1747            // where `N` is a type param but should likely have been a const param.1748            let Some(item) = self.diag_metadata.current_item else { return };1749            let Some(generics) = item.kind.generics() else { return };1750            let Some(span) = generics.params.iter().find_map(|param| {1751                // Only consider type params with no bounds.1752                if param.bounds.is_empty() && param.ident.name == segment.ident.name {1753                    Some(param.ident.span)1754                } else {1755                    None1756                }1757            }) else {1758                return;1759            };1760            err.subdiagnostic(diagnostics::UnexpectedResChangeTyParamToConstParamSugg {1761                before: span.shrink_to_lo(),1762                after: span.shrink_to_hi(),1763            });1764            return;1765        }1766        let PathSource::Trait(_) = source else { return };17671768        // We don't include `DefKind::Str` and `DefKind::AssocTy` as they can't be reached here anyway.1769        let applicability = match res {1770            Some(Res::PrimTy(PrimTy::Int(_) | PrimTy::Uint(_) | PrimTy::Bool | PrimTy::Char)) => {1771                Applicability::MachineApplicable1772            }1773            // FIXME(const_generics): Add `DefKind::TyParam` and `SelfTyParam` once we support generic1774            // const generics. Of course, `Struct` and `Enum` may contain ty params, too, but the1775            // benefits of including them here outweighs the small number of false positives.1776            Some(Res::Def(DefKind::Struct | DefKind::Enum, _))1777                if self.r.features.adt_const_params() || self.r.features.min_adt_const_params() =>1778            {1779                Applicability::MaybeIncorrect1780            }1781            _ => return,1782        };17831784        let Some(item) = self.diag_metadata.current_item else { return };1785        let Some(generics) = item.kind.generics() else { return };17861787        let param = generics.params.iter().find_map(|param| {1788            // Only consider type params with exactly one trait bound.1789            if let [bound] = &*param.bounds1790                && let ast::GenericBound::Trait(tref) = bound1791                && tref.modifiers == ast::TraitBoundModifiers::NONE1792                && tref.span == span1793                && param.ident.span.eq_ctxt(span)1794            {1795                Some(param.ident.span)1796            } else {1797                None1798            }1799        });18001801        if let Some(param) = param {1802            err.subdiagnostic(diagnostics::UnexpectedResChangeTyToConstParamSugg {1803                span: param.shrink_to_lo(),1804                applicability,1805            });1806        }1807    }18081809    fn suggest_pattern_match_with_let(1810        &self,1811        err: &mut Diag<'_>,1812        source: PathSource<'_, '_, '_>,1813        span: Span,1814    ) -> bool {1815        if let PathSource::Expr(_) = source1816            && let Some(Expr { span: expr_span, kind: ExprKind::Assign(lhs, _, _), .. }) =1817                self.diag_metadata.in_if_condition1818        {1819            // Icky heuristic so we don't suggest:1820            // `if (i + 2) = 2` => `if let (i + 2) = 2` (approximately pattern)1821            // `if 2 = i` => `if let 2 = i` (lhs needs to contain error span)1822            if lhs.is_approximately_pattern() && lhs.span.contains(span) {1823                err.span_suggestion_verbose(1824                    expr_span.shrink_to_lo(),1825                    "you might have meant to use pattern matching",1826                    "let ",1827                    Applicability::MaybeIncorrect,1828                );1829                return true;1830            }1831        }1832        false1833    }18341835    fn get_single_associated_item(1836        &mut self,1837        path: &[Segment],1838        source: &PathSource<'_, 'ast, 'ra>,1839        filter_fn: &impl Fn(Res) -> bool,1840    ) -> Option<TypoSuggestion> {1841        if let crate::PathSource::TraitItem(_, _) = source {1842            let mod_path = &path[..path.len() - 1];1843            if let PathResult::Module(ModuleOrUniformRoot::Module(module)) =1844                self.resolve_path(mod_path, None, None, *source)1845            {1846                let targets: Vec<_> = self1847                    .r1848                    .resolutions(module)1849                    .borrow()1850                    .iter()1851                    .filter_map(|(key, resolution)| {1852                        let resolution = resolution.borrow();1853                        resolution.best_decl().map(|binding| binding.res()).and_then(|res| {1854                            if filter_fn(res) {1855                                Some((key.ident.name, resolution.orig_ident_span, res))1856                            } else {1857                                None1858                            }1859                        })1860                    })1861                    .collect();1862                if let &[(name, orig_ident_span, res)] = targets.as_slice() {1863                    return Some(TypoSuggestion::single_item(name, orig_ident_span, res));1864                }1865            }1866        }1867        None1868    }18691870    /// Given `where <T as Bar>::Baz: String`, suggest `where T: Bar<Baz = String>`.1871    fn restrict_assoc_type_in_where_clause(&self, span: Span, err: &mut Diag<'_>) -> bool {1872        // Detect that we are actually in a `where` predicate.1873        let Some(ast::WherePredicate {1874            kind:1875                ast::WherePredicateKind::BoundPredicate(ast::WhereBoundPredicate {1876                    bounded_ty,1877                    bound_generic_params,1878                    bounds,1879                }),1880            span: where_span,1881            ..1882        }) = self.diag_metadata.current_where_predicate1883        else {1884            return false;1885        };1886        if !bound_generic_params.is_empty() {1887            return false;1888        }18891890        // Confirm that the target is an associated type.1891        let ast::TyKind::Path(Some(qself), path) = &bounded_ty.kind else { return false };1892        // use this to verify that ident is a type param.1893        let Some(partial_res) = self.r.partial_res_map.get(&bounded_ty.id) else { return false };1894        if !matches!(partial_res.full_res(), Some(Res::Def(DefKind::AssocTy, _))) {1895            return false;1896        }18971898        let peeled_ty = qself.ty.peel_refs();1899        let ast::TyKind::Path(None, type_param_path) = &peeled_ty.kind else { return false };1900        // Confirm that the `SelfTy` is a type parameter.1901        let Some(partial_res) = self.r.partial_res_map.get(&peeled_ty.id) else {1902            return false;1903        };1904        if !matches!(partial_res.full_res(), Some(Res::Def(DefKind::TyParam, _))) {1905            return false;1906        }1907        let ([ast::PathSegment { args: None, .. }], [ast::GenericBound::Trait(poly_trait_ref)]) =1908            (&type_param_path.segments[..], &bounds[..])1909        else {1910            return false;1911        };1912        let [ast::PathSegment { ident, args: None, id }] =1913            &poly_trait_ref.trait_ref.path.segments[..]1914        else {1915            return false;1916        };1917        if poly_trait_ref.modifiers != ast::TraitBoundModifiers::NONE {1918            return false;1919        }1920        if ident.span == span {1921            let Some(partial_res) = self.r.partial_res_map.get(&id) else {1922                return false;1923            };1924            if !matches!(partial_res.full_res(), Some(Res::Def(..))) {1925                return false;1926            }19271928            let Some(new_where_bound_predicate) =1929                mk_where_bound_predicate(path, poly_trait_ref, &qself.ty)1930            else {1931                return false;1932            };1933            err.span_suggestion_verbose(1934                *where_span,1935                format!("constrain the associated type to `{ident}`"),1936                where_bound_predicate_to_string(&new_where_bound_predicate),1937                Applicability::MaybeIncorrect,1938            );1939        }1940        true1941    }19421943    /// Check if the source is call expression and the first argument is `self`. If true,1944    /// return the span of whole call and the span for all arguments expect the first one (`self`).1945    fn call_has_self_arg(&self, source: PathSource<'_, '_, '_>) -> Option<(Span, Option<Span>)> {1946        let mut has_self_arg = None;1947        if let PathSource::Expr(Some(parent)) = source1948            && let ExprKind::Call(_, args) = &parent.kind1949            && !args.is_empty()1950        {1951            let mut expr_kind = &args[0].kind;1952            loop {1953                match expr_kind {1954                    ExprKind::Path(_, arg_name) if arg_name.segments.len() == 1 => {1955                        if arg_name.segments[0].ident.name == kw::SelfLower {1956                            let call_span = parent.span;1957                            let tail_args_span = if args.len() > 1 {1958                                Some(Span::new(1959                                    args[1].span.lo(),1960                                    args.last().unwrap().span.hi(),1961                                    call_span.ctxt(),1962                                    None,1963                                ))1964                            } else {1965                                None1966                            };1967                            has_self_arg = Some((call_span, tail_args_span));1968                        }1969                        break;1970                    }1971                    ExprKind::AddrOf(_, _, expr) => expr_kind = &expr.kind,1972                    _ => break,1973                }1974            }1975        }1976        has_self_arg1977    }19781979    fn followed_by_brace(&self, span: Span) -> (bool, Option<Span>) {1980        // HACK(estebank): find a better way to figure out that this was a1981        // parser issue where a struct literal is being used on an expression1982        // where a brace being opened means a block is being started. Look1983        // ahead for the next text to see if `span` is followed by a `{`.1984        let sm = self.r.tcx.sess.source_map();1985        if let Some(open_brace_span) = sm.span_followed_by(span, "{") {1986            // In case this could be a struct literal that needs to be surrounded1987            // by parentheses, find the appropriate span.1988            let close_brace_span =1989                sm.span_to_next_source(open_brace_span).ok().and_then(|next_source| {1990                    // Find the matching `}` accounting for nested braces.1991                    let mut depth: u32 = 1;1992                    let offset = next_source.char_indices().find_map(|(i, c)| {1993                        match c {1994                            '{' => depth += 1,1995                            '}' if depth == 1 => return Some(i),1996                            '}' => depth -= 1,1997                            _ => {}1998                        }1999                        None2000                    })?;

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.