rustc_resolve/
diagnostics.rs

1use rustc_ast::expand::StrippedCfgItem;
2use rustc_ast::ptr::P;
3use rustc_ast::visit::{self, Visitor};
4use rustc_ast::{
5    self as ast, CRATE_NODE_ID, Crate, ItemKind, MetaItemInner, MetaItemKind, ModKind, NodeId, Path,
6};
7use rustc_ast_pretty::pprust;
8use rustc_attr_data_structures::{self as attr, Stability};
9use rustc_data_structures::fx::{FxHashMap, FxHashSet};
10use rustc_data_structures::unord::{UnordMap, UnordSet};
11use rustc_errors::codes::*;
12use rustc_errors::{
13    Applicability, Diag, DiagCtxtHandle, ErrorGuaranteed, MultiSpan, SuggestionStyle,
14    report_ambiguity_error, struct_span_code_err,
15};
16use rustc_feature::BUILTIN_ATTRIBUTES;
17use rustc_hir::PrimTy;
18use rustc_hir::def::Namespace::{self, *};
19use rustc_hir::def::{self, CtorKind, CtorOf, DefKind, NonMacroAttrKind, PerNS};
20use rustc_hir::def_id::{CRATE_DEF_ID, DefId};
21use rustc_middle::bug;
22use rustc_middle::ty::TyCtxt;
23use rustc_session::Session;
24use rustc_session::lint::builtin::{
25    ABSOLUTE_PATHS_NOT_STARTING_WITH_CRATE, AMBIGUOUS_GLOB_IMPORTS,
26    MACRO_EXPANDED_MACRO_EXPORTS_ACCESSED_BY_ABSOLUTE_PATHS,
27};
28use rustc_session::lint::{AmbiguityErrorDiag, BuiltinLintDiag};
29use rustc_session::utils::was_invoked_from_cargo;
30use rustc_span::edit_distance::find_best_match_for_name;
31use rustc_span::edition::Edition;
32use rustc_span::hygiene::MacroKind;
33use rustc_span::source_map::SourceMap;
34use rustc_span::{BytePos, Ident, Span, Symbol, SyntaxContext, kw, sym};
35use thin_vec::{ThinVec, thin_vec};
36use tracing::{debug, instrument};
37
38use crate::errors::{
39    self, AddedMacroUse, ChangeImportBinding, ChangeImportBindingSuggestion, ConsiderAddingADerive,
40    ExplicitUnsafeTraits, MacroDefinedLater, MacroRulesNot, MacroSuggMovePosition,
41    MaybeMissingMacroRulesName,
42};
43use crate::imports::{Import, ImportKind};
44use crate::late::{PatternSource, Rib};
45use crate::{
46    AmbiguityError, AmbiguityErrorMisc, AmbiguityKind, BindingError, BindingKey, Finalize,
47    ForwardGenericParamBanReason, HasGenericParams, LexicalScopeBinding, MacroRulesScope, Module,
48    ModuleKind, ModuleOrUniformRoot, NameBinding, NameBindingKind, ParentScope, PathResult,
49    PrivacyError, ResolutionError, Resolver, Scope, ScopeSet, Segment, UseError, Used,
50    VisResolutionError, errors as errs, path_names_to_string,
51};
52
53type Res = def::Res<ast::NodeId>;
54
55/// A vector of spans and replacements, a message and applicability.
56pub(crate) type Suggestion = (Vec<(Span, String)>, String, Applicability);
57
58/// Potential candidate for an undeclared or out-of-scope label - contains the ident of a
59/// similarly named label and whether or not it is reachable.
60pub(crate) type LabelSuggestion = (Ident, bool);
61
62#[derive(Debug)]
63pub(crate) enum SuggestionTarget {
64    /// The target has a similar name as the name used by the programmer (probably a typo)
65    SimilarlyNamed,
66    /// The target is the only valid item that can be used in the corresponding context
67    SingleItem,
68}
69
70#[derive(Debug)]
71pub(crate) struct TypoSuggestion {
72    pub candidate: Symbol,
73    /// The source location where the name is defined; None if the name is not defined
74    /// in source e.g. primitives
75    pub span: Option<Span>,
76    pub res: Res,
77    pub target: SuggestionTarget,
78}
79
80impl TypoSuggestion {
81    pub(crate) fn typo_from_ident(ident: Ident, res: Res) -> TypoSuggestion {
82        Self {
83            candidate: ident.name,
84            span: Some(ident.span),
85            res,
86            target: SuggestionTarget::SimilarlyNamed,
87        }
88    }
89    pub(crate) fn typo_from_name(candidate: Symbol, res: Res) -> TypoSuggestion {
90        Self { candidate, span: None, res, target: SuggestionTarget::SimilarlyNamed }
91    }
92    pub(crate) fn single_item_from_ident(ident: Ident, res: Res) -> TypoSuggestion {
93        Self {
94            candidate: ident.name,
95            span: Some(ident.span),
96            res,
97            target: SuggestionTarget::SingleItem,
98        }
99    }
100}
101
102/// A free importable items suggested in case of resolution failure.
103#[derive(Debug, Clone)]
104pub(crate) struct ImportSuggestion {
105    pub did: Option<DefId>,
106    pub descr: &'static str,
107    pub path: Path,
108    pub accessible: bool,
109    // false if the path traverses a foreign `#[doc(hidden)]` item.
110    pub doc_visible: bool,
111    pub via_import: bool,
112    /// An extra note that should be issued if this item is suggested
113    pub note: Option<String>,
114    pub is_stable: bool,
115}
116
117/// Adjust the impl span so that just the `impl` keyword is taken by removing
118/// everything after `<` (`"impl<T> Iterator for A<T> {}" -> "impl"`) and
119/// everything after the first whitespace (`"impl Iterator for A" -> "impl"`).
120///
121/// *Attention*: the method used is very fragile since it essentially duplicates the work of the
122/// parser. If you need to use this function or something similar, please consider updating the
123/// `source_map` functions and this function to something more robust.
124fn reduce_impl_span_to_impl_keyword(sm: &SourceMap, impl_span: Span) -> Span {
125    let impl_span = sm.span_until_char(impl_span, '<');
126    sm.span_until_whitespace(impl_span)
127}
128
129impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
130    pub(crate) fn dcx(&self) -> DiagCtxtHandle<'tcx> {
131        self.tcx.dcx()
132    }
133
134    pub(crate) fn report_errors(&mut self, krate: &Crate) {
135        self.report_with_use_injections(krate);
136
137        for &(span_use, span_def) in &self.macro_expanded_macro_export_errors {
138            self.lint_buffer.buffer_lint(
139                MACRO_EXPANDED_MACRO_EXPORTS_ACCESSED_BY_ABSOLUTE_PATHS,
140                CRATE_NODE_ID,
141                span_use,
142                BuiltinLintDiag::MacroExpandedMacroExportsAccessedByAbsolutePaths(span_def),
143            );
144        }
145
146        for ambiguity_error in &self.ambiguity_errors {
147            let diag = self.ambiguity_diagnostics(ambiguity_error);
148            if ambiguity_error.warning {
149                let NameBindingKind::Import { import, .. } = ambiguity_error.b1.0.kind else {
150                    unreachable!()
151                };
152                self.lint_buffer.buffer_lint(
153                    AMBIGUOUS_GLOB_IMPORTS,
154                    import.root_id,
155                    ambiguity_error.ident.span,
156                    BuiltinLintDiag::AmbiguousGlobImports { diag },
157                );
158            } else {
159                let mut err = struct_span_code_err!(self.dcx(), diag.span, E0659, "{}", diag.msg);
160                report_ambiguity_error(&mut err, diag);
161                err.emit();
162            }
163        }
164
165        let mut reported_spans = FxHashSet::default();
166        for error in std::mem::take(&mut self.privacy_errors) {
167            if reported_spans.insert(error.dedup_span) {
168                self.report_privacy_error(&error);
169            }
170        }
171    }
172
173    fn report_with_use_injections(&mut self, krate: &Crate) {
174        for UseError { mut err, candidates, def_id, instead, suggestion, path, is_call } in
175            std::mem::take(&mut self.use_injections)
176        {
177            let (span, found_use) = if let Some(def_id) = def_id.as_local() {
178                UsePlacementFinder::check(krate, self.def_id_to_node_id(def_id))
179            } else {
180                (None, FoundUse::No)
181            };
182
183            if !candidates.is_empty() {
184                show_candidates(
185                    self.tcx,
186                    &mut err,
187                    span,
188                    &candidates,
189                    if instead { Instead::Yes } else { Instead::No },
190                    found_use,
191                    DiagMode::Normal,
192                    path,
193                    "",
194                );
195                err.emit();
196            } else if let Some((span, msg, sugg, appl)) = suggestion {
197                err.span_suggestion_verbose(span, msg, sugg, appl);
198                err.emit();
199            } else if let [segment] = path.as_slice()
200                && is_call
201            {
202                err.stash(segment.ident.span, rustc_errors::StashKey::CallIntoMethod);
203            } else {
204                err.emit();
205            }
206        }
207    }
208
209    pub(crate) fn report_conflict(
210        &mut self,
211        parent: Module<'_>,
212        ident: Ident,
213        ns: Namespace,
214        new_binding: NameBinding<'ra>,
215        old_binding: NameBinding<'ra>,
216    ) {
217        // Error on the second of two conflicting names
218        if old_binding.span.lo() > new_binding.span.lo() {
219            return self.report_conflict(parent, ident, ns, old_binding, new_binding);
220        }
221
222        let container = match parent.kind {
223            // Avoid using TyCtxt::def_kind_descr in the resolver, because it
224            // indirectly *calls* the resolver, and would cause a query cycle.
225            ModuleKind::Def(kind, _, _) => kind.descr(parent.def_id()),
226            ModuleKind::Block => "block",
227        };
228
229        let (name, span) =
230            (ident.name, self.tcx.sess.source_map().guess_head_span(new_binding.span));
231
232        if self.name_already_seen.get(&name) == Some(&span) {
233            return;
234        }
235
236        let old_kind = match (ns, old_binding.module()) {
237            (ValueNS, _) => "value",
238            (MacroNS, _) => "macro",
239            (TypeNS, _) if old_binding.is_extern_crate() => "extern crate",
240            (TypeNS, Some(module)) if module.is_normal() => "module",
241            (TypeNS, Some(module)) if module.is_trait() => "trait",
242            (TypeNS, _) => "type",
243        };
244
245        let code = match (old_binding.is_extern_crate(), new_binding.is_extern_crate()) {
246            (true, true) => E0259,
247            (true, _) | (_, true) => match new_binding.is_import() && old_binding.is_import() {
248                true => E0254,
249                false => E0260,
250            },
251            _ => match (old_binding.is_import_user_facing(), new_binding.is_import_user_facing()) {
252                (false, false) => E0428,
253                (true, true) => E0252,
254                _ => E0255,
255            },
256        };
257
258        let label = match new_binding.is_import_user_facing() {
259            true => errors::NameDefinedMultipleTimeLabel::Reimported { span },
260            false => errors::NameDefinedMultipleTimeLabel::Redefined { span },
261        };
262
263        let old_binding_label =
264            (!old_binding.span.is_dummy() && old_binding.span != span).then(|| {
265                let span = self.tcx.sess.source_map().guess_head_span(old_binding.span);
266                match old_binding.is_import_user_facing() {
267                    true => {
268                        errors::NameDefinedMultipleTimeOldBindingLabel::Import { span, old_kind }
269                    }
270                    false => errors::NameDefinedMultipleTimeOldBindingLabel::Definition {
271                        span,
272                        old_kind,
273                    },
274                }
275            });
276
277        let mut err = self
278            .dcx()
279            .create_err(errors::NameDefinedMultipleTime {
280                span,
281                name,
282                descr: ns.descr(),
283                container,
284                label,
285                old_binding_label,
286            })
287            .with_code(code);
288
289        // See https://github.com/rust-lang/rust/issues/32354
290        use NameBindingKind::Import;
291        let can_suggest = |binding: NameBinding<'_>, import: self::Import<'_>| {
292            !binding.span.is_dummy()
293                && !matches!(import.kind, ImportKind::MacroUse { .. } | ImportKind::MacroExport)
294        };
295        let import = match (&new_binding.kind, &old_binding.kind) {
296            // If there are two imports where one or both have attributes then prefer removing the
297            // import without attributes.
298            (Import { import: new, .. }, Import { import: old, .. })
299                if {
300                    (new.has_attributes || old.has_attributes)
301                        && can_suggest(old_binding, *old)
302                        && can_suggest(new_binding, *new)
303                } =>
304            {
305                if old.has_attributes {
306                    Some((*new, new_binding.span, true))
307                } else {
308                    Some((*old, old_binding.span, true))
309                }
310            }
311            // Otherwise prioritize the new binding.
312            (Import { import, .. }, other) if can_suggest(new_binding, *import) => {
313                Some((*import, new_binding.span, other.is_import()))
314            }
315            (other, Import { import, .. }) if can_suggest(old_binding, *import) => {
316                Some((*import, old_binding.span, other.is_import()))
317            }
318            _ => None,
319        };
320
321        // Check if the target of the use for both bindings is the same.
322        let duplicate = new_binding.res().opt_def_id() == old_binding.res().opt_def_id();
323        let has_dummy_span = new_binding.span.is_dummy() || old_binding.span.is_dummy();
324        let from_item =
325            self.extern_prelude.get(&ident).is_none_or(|entry| entry.introduced_by_item);
326        // Only suggest removing an import if both bindings are to the same def, if both spans
327        // aren't dummy spans. Further, if both bindings are imports, then the ident must have
328        // been introduced by an item.
329        let should_remove_import = duplicate
330            && !has_dummy_span
331            && ((new_binding.is_extern_crate() || old_binding.is_extern_crate()) || from_item);
332
333        match import {
334            Some((import, span, true)) if should_remove_import && import.is_nested() => {
335                self.add_suggestion_for_duplicate_nested_use(&mut err, import, span);
336            }
337            Some((import, _, true)) if should_remove_import && !import.is_glob() => {
338                // Simple case - remove the entire import. Due to the above match arm, this can
339                // only be a single use so just remove it entirely.
340                err.subdiagnostic(errors::ToolOnlyRemoveUnnecessaryImport {
341                    span: import.use_span_with_attributes,
342                });
343            }
344            Some((import, span, _)) => {
345                self.add_suggestion_for_rename_of_use(&mut err, name, import, span);
346            }
347            _ => {}
348        }
349
350        err.emit();
351        self.name_already_seen.insert(name, span);
352    }
353
354    /// This function adds a suggestion to change the binding name of a new import that conflicts
355    /// with an existing import.
356    ///
357    /// ```text,ignore (diagnostic)
358    /// help: you can use `as` to change the binding name of the import
359    ///    |
360    /// LL | use foo::bar as other_bar;
361    ///    |     ^^^^^^^^^^^^^^^^^^^^^
362    /// ```
363    fn add_suggestion_for_rename_of_use(
364        &self,
365        err: &mut Diag<'_>,
366        name: Symbol,
367        import: Import<'_>,
368        binding_span: Span,
369    ) {
370        let suggested_name = if name.as_str().chars().next().unwrap().is_uppercase() {
371            format!("Other{name}")
372        } else {
373            format!("other_{name}")
374        };
375
376        let mut suggestion = None;
377        let mut span = binding_span;
378        match import.kind {
379            ImportKind::Single { type_ns_only: true, .. } => {
380                suggestion = Some(format!("self as {suggested_name}"))
381            }
382            ImportKind::Single { source, .. } => {
383                if let Some(pos) = source.span.hi().0.checked_sub(binding_span.lo().0)
384                    && let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(binding_span)
385                    && pos as usize <= snippet.len()
386                {
387                    span = binding_span.with_lo(binding_span.lo() + BytePos(pos)).with_hi(
388                        binding_span.hi() - BytePos(if snippet.ends_with(';') { 1 } else { 0 }),
389                    );
390                    suggestion = Some(format!(" as {suggested_name}"));
391                }
392            }
393            ImportKind::ExternCrate { source, target, .. } => {
394                suggestion = Some(format!(
395                    "extern crate {} as {};",
396                    source.unwrap_or(target.name),
397                    suggested_name,
398                ))
399            }
400            _ => unreachable!(),
401        }
402
403        if let Some(suggestion) = suggestion {
404            err.subdiagnostic(ChangeImportBindingSuggestion { span, suggestion });
405        } else {
406            err.subdiagnostic(ChangeImportBinding { span });
407        }
408    }
409
410    /// This function adds a suggestion to remove an unnecessary binding from an import that is
411    /// nested. In the following example, this function will be invoked to remove the `a` binding
412    /// in the second use statement:
413    ///
414    /// ```ignore (diagnostic)
415    /// use issue_52891::a;
416    /// use issue_52891::{d, a, e};
417    /// ```
418    ///
419    /// The following suggestion will be added:
420    ///
421    /// ```ignore (diagnostic)
422    /// use issue_52891::{d, a, e};
423    ///                      ^-- help: remove unnecessary import
424    /// ```
425    ///
426    /// If the nested use contains only one import then the suggestion will remove the entire
427    /// line.
428    ///
429    /// It is expected that the provided import is nested - this isn't checked by the
430    /// function. If this invariant is not upheld, this function's behaviour will be unexpected
431    /// as characters expected by span manipulations won't be present.
432    fn add_suggestion_for_duplicate_nested_use(
433        &self,
434        err: &mut Diag<'_>,
435        import: Import<'_>,
436        binding_span: Span,
437    ) {
438        assert!(import.is_nested());
439
440        // Two examples will be used to illustrate the span manipulations we're doing:
441        //
442        // - Given `use issue_52891::{d, a, e};` where `a` is a duplicate then `binding_span` is
443        //   `a` and `import.use_span` is `issue_52891::{d, a, e};`.
444        // - Given `use issue_52891::{d, e, a};` where `a` is a duplicate then `binding_span` is
445        //   `a` and `import.use_span` is `issue_52891::{d, e, a};`.
446
447        let (found_closing_brace, span) =
448            find_span_of_binding_until_next_binding(self.tcx.sess, binding_span, import.use_span);
449
450        // If there was a closing brace then identify the span to remove any trailing commas from
451        // previous imports.
452        if found_closing_brace {
453            if let Some(span) = extend_span_to_previous_binding(self.tcx.sess, span) {
454                err.subdiagnostic(errors::ToolOnlyRemoveUnnecessaryImport { span });
455            } else {
456                // Remove the entire line if we cannot extend the span back, this indicates an
457                // `issue_52891::{self}` case.
458                err.subdiagnostic(errors::RemoveUnnecessaryImport {
459                    span: import.use_span_with_attributes,
460                });
461            }
462
463            return;
464        }
465
466        err.subdiagnostic(errors::RemoveUnnecessaryImport { span });
467    }
468
469    pub(crate) fn lint_if_path_starts_with_module(
470        &mut self,
471        finalize: Option<Finalize>,
472        path: &[Segment],
473        second_binding: Option<NameBinding<'_>>,
474    ) {
475        let Some(Finalize { node_id, root_span, .. }) = finalize else {
476            return;
477        };
478
479        let first_name = match path.get(0) {
480            // In the 2018 edition this lint is a hard error, so nothing to do
481            Some(seg) if seg.ident.span.is_rust_2015() && self.tcx.sess.is_rust_2015() => {
482                seg.ident.name
483            }
484            _ => return,
485        };
486
487        // We're only interested in `use` paths which should start with
488        // `{{root}}` currently.
489        if first_name != kw::PathRoot {
490            return;
491        }
492
493        match path.get(1) {
494            // If this import looks like `crate::...` it's already good
495            Some(Segment { ident, .. }) if ident.name == kw::Crate => return,
496            // Otherwise go below to see if it's an extern crate
497            Some(_) => {}
498            // If the path has length one (and it's `PathRoot` most likely)
499            // then we don't know whether we're gonna be importing a crate or an
500            // item in our crate. Defer this lint to elsewhere
501            None => return,
502        }
503
504        // If the first element of our path was actually resolved to an
505        // `ExternCrate` (also used for `crate::...`) then no need to issue a
506        // warning, this looks all good!
507        if let Some(binding) = second_binding
508            && let NameBindingKind::Import { import, .. } = binding.kind
509            // Careful: we still want to rewrite paths from renamed extern crates.
510            && let ImportKind::ExternCrate { source: None, .. } = import.kind
511        {
512            return;
513        }
514
515        let diag = BuiltinLintDiag::AbsPathWithModule(root_span);
516        self.lint_buffer.buffer_lint(
517            ABSOLUTE_PATHS_NOT_STARTING_WITH_CRATE,
518            node_id,
519            root_span,
520            diag,
521        );
522    }
523
524    pub(crate) fn add_module_candidates(
525        &mut self,
526        module: Module<'ra>,
527        names: &mut Vec<TypoSuggestion>,
528        filter_fn: &impl Fn(Res) -> bool,
529        ctxt: Option<SyntaxContext>,
530    ) {
531        module.for_each_child(self, |_this, ident, _ns, binding| {
532            let res = binding.res();
533            if filter_fn(res) && ctxt.is_none_or(|ctxt| ctxt == ident.span.ctxt()) {
534                names.push(TypoSuggestion::typo_from_ident(ident, res));
535            }
536        });
537    }
538
539    /// Combines an error with provided span and emits it.
540    ///
541    /// This takes the error provided, combines it with the span and any additional spans inside the
542    /// error and emits it.
543    pub(crate) fn report_error(
544        &mut self,
545        span: Span,
546        resolution_error: ResolutionError<'ra>,
547    ) -> ErrorGuaranteed {
548        self.into_struct_error(span, resolution_error).emit()
549    }
550
551    pub(crate) fn into_struct_error(
552        &mut self,
553        span: Span,
554        resolution_error: ResolutionError<'ra>,
555    ) -> Diag<'_> {
556        match resolution_error {
557            ResolutionError::GenericParamsFromOuterItem(
558                outer_res,
559                has_generic_params,
560                def_kind,
561            ) => {
562                use errs::GenericParamsFromOuterItemLabel as Label;
563                let static_or_const = match def_kind {
564                    DefKind::Static { .. } => {
565                        Some(errs::GenericParamsFromOuterItemStaticOrConst::Static)
566                    }
567                    DefKind::Const => Some(errs::GenericParamsFromOuterItemStaticOrConst::Const),
568                    _ => None,
569                };
570                let is_self =
571                    matches!(outer_res, Res::SelfTyParam { .. } | Res::SelfTyAlias { .. });
572                let mut err = errs::GenericParamsFromOuterItem {
573                    span,
574                    label: None,
575                    refer_to_type_directly: None,
576                    sugg: None,
577                    static_or_const,
578                    is_self,
579                };
580
581                let sm = self.tcx.sess.source_map();
582                let def_id = match outer_res {
583                    Res::SelfTyParam { .. } => {
584                        err.label = Some(Label::SelfTyParam(span));
585                        return self.dcx().create_err(err);
586                    }
587                    Res::SelfTyAlias { alias_to: def_id, .. } => {
588                        err.label = Some(Label::SelfTyAlias(reduce_impl_span_to_impl_keyword(
589                            sm,
590                            self.def_span(def_id),
591                        )));
592                        err.refer_to_type_directly = Some(span);
593                        return self.dcx().create_err(err);
594                    }
595                    Res::Def(DefKind::TyParam, def_id) => {
596                        err.label = Some(Label::TyParam(self.def_span(def_id)));
597                        def_id
598                    }
599                    Res::Def(DefKind::ConstParam, def_id) => {
600                        err.label = Some(Label::ConstParam(self.def_span(def_id)));
601                        def_id
602                    }
603                    _ => {
604                        bug!(
605                            "GenericParamsFromOuterItem should only be used with \
606                            Res::SelfTyParam, Res::SelfTyAlias, DefKind::TyParam or \
607                            DefKind::ConstParam"
608                        );
609                    }
610                };
611
612                if let HasGenericParams::Yes(span) = has_generic_params {
613                    let name = self.tcx.item_name(def_id);
614                    let (span, snippet) = if span.is_empty() {
615                        let snippet = format!("<{name}>");
616                        (span, snippet)
617                    } else {
618                        let span = sm.span_through_char(span, '<').shrink_to_hi();
619                        let snippet = format!("{name}, ");
620                        (span, snippet)
621                    };
622                    err.sugg = Some(errs::GenericParamsFromOuterItemSugg { span, snippet });
623                }
624
625                self.dcx().create_err(err)
626            }
627            ResolutionError::NameAlreadyUsedInParameterList(name, first_use_span) => self
628                .dcx()
629                .create_err(errs::NameAlreadyUsedInParameterList { span, first_use_span, name }),
630            ResolutionError::MethodNotMemberOfTrait(method, trait_, candidate) => {
631                self.dcx().create_err(errs::MethodNotMemberOfTrait {
632                    span,
633                    method,
634                    trait_,
635                    sub: candidate.map(|c| errs::AssociatedFnWithSimilarNameExists {
636                        span: method.span,
637                        candidate: c,
638                    }),
639                })
640            }
641            ResolutionError::TypeNotMemberOfTrait(type_, trait_, candidate) => {
642                self.dcx().create_err(errs::TypeNotMemberOfTrait {
643                    span,
644                    type_,
645                    trait_,
646                    sub: candidate.map(|c| errs::AssociatedTypeWithSimilarNameExists {
647                        span: type_.span,
648                        candidate: c,
649                    }),
650                })
651            }
652            ResolutionError::ConstNotMemberOfTrait(const_, trait_, candidate) => {
653                self.dcx().create_err(errs::ConstNotMemberOfTrait {
654                    span,
655                    const_,
656                    trait_,
657                    sub: candidate.map(|c| errs::AssociatedConstWithSimilarNameExists {
658                        span: const_.span,
659                        candidate: c,
660                    }),
661                })
662            }
663            ResolutionError::VariableNotBoundInPattern(binding_error, parent_scope) => {
664                let BindingError { name, target, origin, could_be_path } = binding_error;
665
666                let target_sp = target.iter().copied().collect::<Vec<_>>();
667                let origin_sp = origin.iter().copied().collect::<Vec<_>>();
668
669                let msp = MultiSpan::from_spans(target_sp.clone());
670                let mut err = self
671                    .dcx()
672                    .create_err(errors::VariableIsNotBoundInAllPatterns { multispan: msp, name });
673                for sp in target_sp {
674                    err.subdiagnostic(errors::PatternDoesntBindName { span: sp, name });
675                }
676                for sp in origin_sp {
677                    err.subdiagnostic(errors::VariableNotInAllPatterns { span: sp });
678                }
679                if could_be_path {
680                    let import_suggestions = self.lookup_import_candidates(
681                        name,
682                        Namespace::ValueNS,
683                        &parent_scope,
684                        &|res: Res| {
685                            matches!(
686                                res,
687                                Res::Def(
688                                    DefKind::Ctor(CtorOf::Variant, CtorKind::Const)
689                                        | DefKind::Ctor(CtorOf::Struct, CtorKind::Const)
690                                        | DefKind::Const
691                                        | DefKind::AssocConst,
692                                    _,
693                                )
694                            )
695                        },
696                    );
697
698                    if import_suggestions.is_empty() {
699                        let help_msg = format!(
700                            "if you meant to match on a variant or a `const` item, consider \
701                             making the path in the pattern qualified: `path::to::ModOrType::{name}`",
702                        );
703                        err.span_help(span, help_msg);
704                    }
705                    show_candidates(
706                        self.tcx,
707                        &mut err,
708                        Some(span),
709                        &import_suggestions,
710                        Instead::No,
711                        FoundUse::Yes,
712                        DiagMode::Pattern,
713                        vec![],
714                        "",
715                    );
716                }
717                err
718            }
719            ResolutionError::VariableBoundWithDifferentMode(variable_name, first_binding_span) => {
720                self.dcx().create_err(errs::VariableBoundWithDifferentMode {
721                    span,
722                    first_binding_span,
723                    variable_name,
724                })
725            }
726            ResolutionError::IdentifierBoundMoreThanOnceInParameterList(identifier) => self
727                .dcx()
728                .create_err(errs::IdentifierBoundMoreThanOnceInParameterList { span, identifier }),
729            ResolutionError::IdentifierBoundMoreThanOnceInSamePattern(identifier) => self
730                .dcx()
731                .create_err(errs::IdentifierBoundMoreThanOnceInSamePattern { span, identifier }),
732            ResolutionError::UndeclaredLabel { name, suggestion } => {
733                let ((sub_reachable, sub_reachable_suggestion), sub_unreachable) = match suggestion
734                {
735                    // A reachable label with a similar name exists.
736                    Some((ident, true)) => (
737                        (
738                            Some(errs::LabelWithSimilarNameReachable(ident.span)),
739                            Some(errs::TryUsingSimilarlyNamedLabel {
740                                span,
741                                ident_name: ident.name,
742                            }),
743                        ),
744                        None,
745                    ),
746                    // An unreachable label with a similar name exists.
747                    Some((ident, false)) => (
748                        (None, None),
749                        Some(errs::UnreachableLabelWithSimilarNameExists {
750                            ident_span: ident.span,
751                        }),
752                    ),
753                    // No similarly-named labels exist.
754                    None => ((None, None), None),
755                };
756                self.dcx().create_err(errs::UndeclaredLabel {
757                    span,
758                    name,
759                    sub_reachable,
760                    sub_reachable_suggestion,
761                    sub_unreachable,
762                })
763            }
764            ResolutionError::SelfImportsOnlyAllowedWithin { root, span_with_rename } => {
765                // None of the suggestions below would help with a case like `use self`.
766                let (suggestion, mpart_suggestion) = if root {
767                    (None, None)
768                } else {
769                    // use foo::bar::self        -> foo::bar
770                    // use foo::bar::self as abc -> foo::bar as abc
771                    let suggestion = errs::SelfImportsOnlyAllowedWithinSuggestion { span };
772
773                    // use foo::bar::self        -> foo::bar::{self}
774                    // use foo::bar::self as abc -> foo::bar::{self as abc}
775                    let mpart_suggestion = errs::SelfImportsOnlyAllowedWithinMultipartSuggestion {
776                        multipart_start: span_with_rename.shrink_to_lo(),
777                        multipart_end: span_with_rename.shrink_to_hi(),
778                    };
779                    (Some(suggestion), Some(mpart_suggestion))
780                };
781                self.dcx().create_err(errs::SelfImportsOnlyAllowedWithin {
782                    span,
783                    suggestion,
784                    mpart_suggestion,
785                })
786            }
787            ResolutionError::SelfImportCanOnlyAppearOnceInTheList => {
788                self.dcx().create_err(errs::SelfImportCanOnlyAppearOnceInTheList { span })
789            }
790            ResolutionError::SelfImportOnlyInImportListWithNonEmptyPrefix => {
791                self.dcx().create_err(errs::SelfImportOnlyInImportListWithNonEmptyPrefix { span })
792            }
793            ResolutionError::FailedToResolve { segment, label, suggestion, module } => {
794                let mut err =
795                    struct_span_code_err!(self.dcx(), span, E0433, "failed to resolve: {label}");
796                err.span_label(span, label);
797
798                if let Some((suggestions, msg, applicability)) = suggestion {
799                    if suggestions.is_empty() {
800                        err.help(msg);
801                        return err;
802                    }
803                    err.multipart_suggestion(msg, suggestions, applicability);
804                }
805                if let Some(ModuleOrUniformRoot::Module(module)) = module
806                    && let Some(module) = module.opt_def_id()
807                    && let Some(segment) = segment
808                {
809                    self.find_cfg_stripped(&mut err, &segment, module);
810                }
811
812                err
813            }
814            ResolutionError::CannotCaptureDynamicEnvironmentInFnItem => {
815                self.dcx().create_err(errs::CannotCaptureDynamicEnvironmentInFnItem { span })
816            }
817            ResolutionError::AttemptToUseNonConstantValueInConstant {
818                ident,
819                suggestion,
820                current,
821                type_span,
822            } => {
823                // let foo =...
824                //     ^^^ given this Span
825                // ------- get this Span to have an applicable suggestion
826
827                // edit:
828                // only do this if the const and usage of the non-constant value are on the same line
829                // the further the two are apart, the higher the chance of the suggestion being wrong
830
831                let sp = self
832                    .tcx
833                    .sess
834                    .source_map()
835                    .span_extend_to_prev_str(ident.span, current, true, false);
836
837                let ((with, with_label), without) = match sp {
838                    Some(sp) if !self.tcx.sess.source_map().is_multiline(sp) => {
839                        let sp = sp
840                            .with_lo(BytePos(sp.lo().0 - (current.len() as u32)))
841                            .until(ident.span);
842                        (
843                        (Some(errs::AttemptToUseNonConstantValueInConstantWithSuggestion {
844                                span: sp,
845                                suggestion,
846                                current,
847                                type_span,
848                            }), Some(errs::AttemptToUseNonConstantValueInConstantLabelWithSuggestion {span})),
849                            None,
850                        )
851                    }
852                    _ => (
853                        (None, None),
854                        Some(errs::AttemptToUseNonConstantValueInConstantWithoutSuggestion {
855                            ident_span: ident.span,
856                            suggestion,
857                        }),
858                    ),
859                };
860
861                self.dcx().create_err(errs::AttemptToUseNonConstantValueInConstant {
862                    span,
863                    with,
864                    with_label,
865                    without,
866                })
867            }
868            ResolutionError::BindingShadowsSomethingUnacceptable {
869                shadowing_binding,
870                name,
871                participle,
872                article,
873                shadowed_binding,
874                shadowed_binding_span,
875            } => self.dcx().create_err(errs::BindingShadowsSomethingUnacceptable {
876                span,
877                shadowing_binding,
878                shadowed_binding,
879                article,
880                sub_suggestion: match (shadowing_binding, shadowed_binding) {
881                    (
882                        PatternSource::Match,
883                        Res::Def(DefKind::Ctor(CtorOf::Variant | CtorOf::Struct, CtorKind::Fn), _),
884                    ) => Some(errs::BindingShadowsSomethingUnacceptableSuggestion { span, name }),
885                    _ => None,
886                },
887                shadowed_binding_span,
888                participle,
889                name,
890            }),
891            ResolutionError::ForwardDeclaredGenericParam(param, reason) => match reason {
892                ForwardGenericParamBanReason::Default => {
893                    self.dcx().create_err(errs::ForwardDeclaredGenericParam { param, span })
894                }
895                ForwardGenericParamBanReason::ConstParamTy => self
896                    .dcx()
897                    .create_err(errs::ForwardDeclaredGenericInConstParamTy { param, span }),
898            },
899            ResolutionError::ParamInTyOfConstParam { name } => {
900                self.dcx().create_err(errs::ParamInTyOfConstParam { span, name })
901            }
902            ResolutionError::ParamInNonTrivialAnonConst { name, param_kind: is_type } => {
903                self.dcx().create_err(errs::ParamInNonTrivialAnonConst {
904                    span,
905                    name,
906                    param_kind: is_type,
907                    help: self
908                        .tcx
909                        .sess
910                        .is_nightly_build()
911                        .then_some(errs::ParamInNonTrivialAnonConstHelp),
912                })
913            }
914            ResolutionError::ParamInEnumDiscriminant { name, param_kind: is_type } => self
915                .dcx()
916                .create_err(errs::ParamInEnumDiscriminant { span, name, param_kind: is_type }),
917            ResolutionError::ForwardDeclaredSelf(reason) => match reason {
918                ForwardGenericParamBanReason::Default => {
919                    self.dcx().create_err(errs::SelfInGenericParamDefault { span })
920                }
921                ForwardGenericParamBanReason::ConstParamTy => {
922                    self.dcx().create_err(errs::SelfInConstGenericTy { span })
923                }
924            },
925            ResolutionError::UnreachableLabel { name, definition_span, suggestion } => {
926                let ((sub_suggestion_label, sub_suggestion), sub_unreachable_label) =
927                    match suggestion {
928                        // A reachable label with a similar name exists.
929                        Some((ident, true)) => (
930                            (
931                                Some(errs::UnreachableLabelSubLabel { ident_span: ident.span }),
932                                Some(errs::UnreachableLabelSubSuggestion {
933                                    span,
934                                    // intentionally taking 'ident.name' instead of 'ident' itself, as this
935                                    // could be used in suggestion context
936                                    ident_name: ident.name,
937                                }),
938                            ),
939                            None,
940                        ),
941                        // An unreachable label with a similar name exists.
942                        Some((ident, false)) => (
943                            (None, None),
944                            Some(errs::UnreachableLabelSubLabelUnreachable {
945                                ident_span: ident.span,
946                            }),
947                        ),
948                        // No similarly-named labels exist.
949                        None => ((None, None), None),
950                    };
951                self.dcx().create_err(errs::UnreachableLabel {
952                    span,
953                    name,
954                    definition_span,
955                    sub_suggestion,
956                    sub_suggestion_label,
957                    sub_unreachable_label,
958                })
959            }
960            ResolutionError::TraitImplMismatch {
961                name,
962                kind,
963                code,
964                trait_item_span,
965                trait_path,
966            } => self
967                .dcx()
968                .create_err(errors::TraitImplMismatch {
969                    span,
970                    name,
971                    kind,
972                    trait_path,
973                    trait_item_span,
974                })
975                .with_code(code),
976            ResolutionError::TraitImplDuplicate { name, trait_item_span, old_span } => self
977                .dcx()
978                .create_err(errs::TraitImplDuplicate { span, name, trait_item_span, old_span }),
979            ResolutionError::InvalidAsmSym => self.dcx().create_err(errs::InvalidAsmSym { span }),
980            ResolutionError::LowercaseSelf => self.dcx().create_err(errs::LowercaseSelf { span }),
981            ResolutionError::BindingInNeverPattern => {
982                self.dcx().create_err(errs::BindingInNeverPattern { span })
983            }
984        }
985    }
986
987    pub(crate) fn report_vis_error(
988        &mut self,
989        vis_resolution_error: VisResolutionError<'_>,
990    ) -> ErrorGuaranteed {
991        match vis_resolution_error {
992            VisResolutionError::Relative2018(span, path) => {
993                self.dcx().create_err(errs::Relative2018 {
994                    span,
995                    path_span: path.span,
996                    // intentionally converting to String, as the text would also be used as
997                    // in suggestion context
998                    path_str: pprust::path_to_string(path),
999                })
1000            }
1001            VisResolutionError::AncestorOnly(span) => {
1002                self.dcx().create_err(errs::AncestorOnly(span))
1003            }
1004            VisResolutionError::FailedToResolve(span, label, suggestion) => self.into_struct_error(
1005                span,
1006                ResolutionError::FailedToResolve { segment: None, label, suggestion, module: None },
1007            ),
1008            VisResolutionError::ExpectedFound(span, path_str, res) => {
1009                self.dcx().create_err(errs::ExpectedModuleFound { span, res, path_str })
1010            }
1011            VisResolutionError::Indeterminate(span) => {
1012                self.dcx().create_err(errs::Indeterminate(span))
1013            }
1014            VisResolutionError::ModuleOnly(span) => self.dcx().create_err(errs::ModuleOnly(span)),
1015        }
1016        .emit()
1017    }
1018
1019    /// Lookup typo candidate in scope for a macro or import.
1020    fn early_lookup_typo_candidate(
1021        &mut self,
1022        scope_set: ScopeSet<'ra>,
1023        parent_scope: &ParentScope<'ra>,
1024        ident: Ident,
1025        filter_fn: &impl Fn(Res) -> bool,
1026    ) -> Option<TypoSuggestion> {
1027        let mut suggestions = Vec::new();
1028        let ctxt = ident.span.ctxt();
1029        self.visit_scopes(scope_set, parent_scope, ctxt, |this, scope, use_prelude, _| {
1030            match scope {
1031                Scope::DeriveHelpers(expn_id) => {
1032                    let res = Res::NonMacroAttr(NonMacroAttrKind::DeriveHelper);
1033                    if filter_fn(res) {
1034                        suggestions.extend(
1035                            this.helper_attrs
1036                                .get(&expn_id)
1037                                .into_iter()
1038                                .flatten()
1039                                .map(|(ident, _)| TypoSuggestion::typo_from_ident(*ident, res)),
1040                        );
1041                    }
1042                }
1043                Scope::DeriveHelpersCompat => {
1044                    let res = Res::NonMacroAttr(NonMacroAttrKind::DeriveHelperCompat);
1045                    if filter_fn(res) {
1046                        for derive in parent_scope.derives {
1047                            let parent_scope = &ParentScope { derives: &[], ..*parent_scope };
1048                            let Ok((Some(ext), _)) = this.resolve_macro_path(
1049                                derive,
1050                                Some(MacroKind::Derive),
1051                                parent_scope,
1052                                false,
1053                                false,
1054                                None,
1055                                None,
1056                            ) else {
1057                                continue;
1058                            };
1059                            suggestions.extend(
1060                                ext.helper_attrs
1061                                    .iter()
1062                                    .map(|name| TypoSuggestion::typo_from_name(*name, res)),
1063                            );
1064                        }
1065                    }
1066                }
1067                Scope::MacroRules(macro_rules_scope) => {
1068                    if let MacroRulesScope::Binding(macro_rules_binding) = macro_rules_scope.get() {
1069                        let res = macro_rules_binding.binding.res();
1070                        if filter_fn(res) {
1071                            suggestions.push(TypoSuggestion::typo_from_ident(
1072                                macro_rules_binding.ident,
1073                                res,
1074                            ))
1075                        }
1076                    }
1077                }
1078                Scope::CrateRoot => {
1079                    let root_ident = Ident::new(kw::PathRoot, ident.span);
1080                    let root_module = this.resolve_crate_root(root_ident);
1081                    this.add_module_candidates(root_module, &mut suggestions, filter_fn, None);
1082                }
1083                Scope::Module(module, _) => {
1084                    this.add_module_candidates(module, &mut suggestions, filter_fn, None);
1085                }
1086                Scope::MacroUsePrelude => {
1087                    suggestions.extend(this.macro_use_prelude.iter().filter_map(
1088                        |(name, binding)| {
1089                            let res = binding.res();
1090                            filter_fn(res).then_some(TypoSuggestion::typo_from_name(*name, res))
1091                        },
1092                    ));
1093                }
1094                Scope::BuiltinAttrs => {
1095                    let res = Res::NonMacroAttr(NonMacroAttrKind::Builtin(sym::dummy));
1096                    if filter_fn(res) {
1097                        suggestions.extend(
1098                            BUILTIN_ATTRIBUTES
1099                                .iter()
1100                                .map(|attr| TypoSuggestion::typo_from_name(attr.name, res)),
1101                        );
1102                    }
1103                }
1104                Scope::ExternPrelude => {
1105                    suggestions.extend(this.extern_prelude.iter().filter_map(|(ident, _)| {
1106                        let res = Res::Def(DefKind::Mod, CRATE_DEF_ID.to_def_id());
1107                        filter_fn(res).then_some(TypoSuggestion::typo_from_ident(*ident, res))
1108                    }));
1109                }
1110                Scope::ToolPrelude => {
1111                    let res = Res::NonMacroAttr(NonMacroAttrKind::Tool);
1112                    suggestions.extend(
1113                        this.registered_tools
1114                            .iter()
1115                            .map(|ident| TypoSuggestion::typo_from_ident(*ident, res)),
1116                    );
1117                }
1118                Scope::StdLibPrelude => {
1119                    if let Some(prelude) = this.prelude {
1120                        let mut tmp_suggestions = Vec::new();
1121                        this.add_module_candidates(prelude, &mut tmp_suggestions, filter_fn, None);
1122                        suggestions.extend(
1123                            tmp_suggestions
1124                                .into_iter()
1125                                .filter(|s| use_prelude.into() || this.is_builtin_macro(s.res)),
1126                        );
1127                    }
1128                }
1129                Scope::BuiltinTypes => {
1130                    suggestions.extend(PrimTy::ALL.iter().filter_map(|prim_ty| {
1131                        let res = Res::PrimTy(*prim_ty);
1132                        filter_fn(res)
1133                            .then_some(TypoSuggestion::typo_from_name(prim_ty.name(), res))
1134                    }))
1135                }
1136            }
1137
1138            None::<()>
1139        });
1140
1141        // Make sure error reporting is deterministic.
1142        suggestions.sort_by(|a, b| a.candidate.as_str().cmp(b.candidate.as_str()));
1143
1144        match find_best_match_for_name(
1145            &suggestions.iter().map(|suggestion| suggestion.candidate).collect::<Vec<Symbol>>(),
1146            ident.name,
1147            None,
1148        ) {
1149            Some(found) if found != ident.name => {
1150                suggestions.into_iter().find(|suggestion| suggestion.candidate == found)
1151            }
1152            _ => None,
1153        }
1154    }
1155
1156    fn lookup_import_candidates_from_module<FilterFn>(
1157        &mut self,
1158        lookup_ident: Ident,
1159        namespace: Namespace,
1160        parent_scope: &ParentScope<'ra>,
1161        start_module: Module<'ra>,
1162        crate_path: ThinVec<ast::PathSegment>,
1163        filter_fn: FilterFn,
1164    ) -> Vec<ImportSuggestion>
1165    where
1166        FilterFn: Fn(Res) -> bool,
1167    {
1168        let mut candidates = Vec::new();
1169        let mut seen_modules = FxHashSet::default();
1170        let start_did = start_module.def_id();
1171        let mut worklist = vec![(
1172            start_module,
1173            ThinVec::<ast::PathSegment>::new(),
1174            true,
1175            start_did.is_local() || !self.tcx.is_doc_hidden(start_did),
1176            true,
1177        )];
1178        let mut worklist_via_import = vec![];
1179
1180        while let Some((in_module, path_segments, accessible, doc_visible, is_stable)) =
1181            match worklist.pop() {
1182                None => worklist_via_import.pop(),
1183                Some(x) => Some(x),
1184            }
1185        {
1186            let in_module_is_extern = !in_module.def_id().is_local();
1187            in_module.for_each_child(self, |this, ident, ns, name_binding| {
1188                // Avoid non-importable candidates.
1189                if name_binding.is_assoc_item()
1190                    && !this.tcx.features().import_trait_associated_functions()
1191                {
1192                    return;
1193                }
1194
1195                if ident.name == kw::Underscore {
1196                    return;
1197                }
1198
1199                let child_accessible =
1200                    accessible && this.is_accessible_from(name_binding.vis, parent_scope.module);
1201
1202                // do not venture inside inaccessible items of other crates
1203                if in_module_is_extern && !child_accessible {
1204                    return;
1205                }
1206
1207                let via_import = name_binding.is_import() && !name_binding.is_extern_crate();
1208
1209                // There is an assumption elsewhere that paths of variants are in the enum's
1210                // declaration and not imported. With this assumption, the variant component is
1211                // chopped and the rest of the path is assumed to be the enum's own path. For
1212                // errors where a variant is used as the type instead of the enum, this causes
1213                // funny looking invalid suggestions, i.e `foo` instead of `foo::MyEnum`.
1214                if via_import && name_binding.is_possibly_imported_variant() {
1215                    return;
1216                }
1217
1218                // #90113: Do not count an inaccessible reexported item as a candidate.
1219                if let NameBindingKind::Import { binding, .. } = name_binding.kind
1220                    && this.is_accessible_from(binding.vis, parent_scope.module)
1221                    && !this.is_accessible_from(name_binding.vis, parent_scope.module)
1222                {
1223                    return;
1224                }
1225
1226                let res = name_binding.res();
1227                let did = match res {
1228                    Res::Def(DefKind::Ctor(..), did) => this.tcx.opt_parent(did),
1229                    _ => res.opt_def_id(),
1230                };
1231                let child_doc_visible = doc_visible
1232                    && did.is_none_or(|did| did.is_local() || !this.tcx.is_doc_hidden(did));
1233
1234                // collect results based on the filter function
1235                // avoid suggesting anything from the same module in which we are resolving
1236                // avoid suggesting anything with a hygienic name
1237                if ident.name == lookup_ident.name
1238                    && ns == namespace
1239                    && in_module != parent_scope.module
1240                    && !ident.span.normalize_to_macros_2_0().from_expansion()
1241                    && filter_fn(res)
1242                {
1243                    // create the path
1244                    let mut segms = if lookup_ident.span.at_least_rust_2018() {
1245                        // crate-local absolute paths start with `crate::` in edition 2018
1246                        // FIXME: may also be stabilized for Rust 2015 (Issues #45477, #44660)
1247                        crate_path.clone()
1248                    } else {
1249                        ThinVec::new()
1250                    };
1251                    segms.append(&mut path_segments.clone());
1252
1253                    segms.push(ast::PathSegment::from_ident(ident));
1254                    let path = Path { span: name_binding.span, segments: segms, tokens: None };
1255
1256                    if child_accessible
1257                        // Remove invisible match if exists
1258                        && let Some(idx) = candidates
1259                            .iter()
1260                            .position(|v: &ImportSuggestion| v.did == did && !v.accessible)
1261                    {
1262                        candidates.remove(idx);
1263                    }
1264
1265                    let is_stable = if is_stable
1266                        && let Some(did) = did
1267                        && this.is_stable(did, path.span)
1268                    {
1269                        true
1270                    } else {
1271                        false
1272                    };
1273
1274                    // Rreplace unstable suggestions if we meet a new stable one,
1275                    // and do nothing if any other situation. For example, if we
1276                    // meet `std::ops::Range` after `std::range::legacy::Range`,
1277                    // we will remove the latter and then insert the former.
1278                    if is_stable
1279                        && let Some(idx) = candidates
1280                            .iter()
1281                            .position(|v: &ImportSuggestion| v.did == did && !v.is_stable)
1282                    {
1283                        candidates.remove(idx);
1284                    }
1285
1286                    if candidates.iter().all(|v: &ImportSuggestion| v.did != did) {
1287                        // See if we're recommending TryFrom, TryInto, or FromIterator and add
1288                        // a note about editions
1289                        let note = if let Some(did) = did {
1290                            let requires_note = !did.is_local()
1291                                && this.tcx.get_attrs(did, sym::rustc_diagnostic_item).any(
1292                                    |attr| {
1293                                        [sym::TryInto, sym::TryFrom, sym::FromIterator]
1294                                            .map(|x| Some(x))
1295                                            .contains(&attr.value_str())
1296                                    },
1297                                );
1298
1299                            requires_note.then(|| {
1300                                format!(
1301                                    "'{}' is included in the prelude starting in Edition 2021",
1302                                    path_names_to_string(&path)
1303                                )
1304                            })
1305                        } else {
1306                            None
1307                        };
1308
1309                        candidates.push(ImportSuggestion {
1310                            did,
1311                            descr: res.descr(),
1312                            path,
1313                            accessible: child_accessible,
1314                            doc_visible: child_doc_visible,
1315                            note,
1316                            via_import,
1317                            is_stable,
1318                        });
1319                    }
1320                }
1321
1322                // collect submodules to explore
1323                if let Some(module) = name_binding.module() {
1324                    // form the path
1325                    let mut path_segments = path_segments.clone();
1326                    path_segments.push(ast::PathSegment::from_ident(ident));
1327
1328                    let alias_import = if let NameBindingKind::Import { import, .. } =
1329                        name_binding.kind
1330                        && let ImportKind::ExternCrate { source: Some(_), .. } = import.kind
1331                        && import.parent_scope.expansion == parent_scope.expansion
1332                    {
1333                        true
1334                    } else {
1335                        false
1336                    };
1337
1338                    let is_extern_crate_that_also_appears_in_prelude =
1339                        name_binding.is_extern_crate() && lookup_ident.span.at_least_rust_2018();
1340
1341                    if !is_extern_crate_that_also_appears_in_prelude || alias_import {
1342                        // add the module to the lookup
1343                        if seen_modules.insert(module.def_id()) {
1344                            if via_import { &mut worklist_via_import } else { &mut worklist }.push(
1345                                (
1346                                    module,
1347                                    path_segments,
1348                                    child_accessible,
1349                                    child_doc_visible,
1350                                    is_stable && this.is_stable(module.def_id(), name_binding.span),
1351                                ),
1352                            );
1353                        }
1354                    }
1355                }
1356            })
1357        }
1358
1359        candidates
1360    }
1361
1362    fn is_stable(&self, did: DefId, span: Span) -> bool {
1363        if did.is_local() {
1364            return true;
1365        }
1366
1367        match self.tcx.lookup_stability(did) {
1368            Some(Stability {
1369                level: attr::StabilityLevel::Unstable { implied_by, .. },
1370                feature,
1371                ..
1372            }) => {
1373                if span.allows_unstable(feature) {
1374                    true
1375                } else if self.tcx.features().enabled(feature) {
1376                    true
1377                } else if let Some(implied_by) = implied_by
1378                    && self.tcx.features().enabled(implied_by)
1379                {
1380                    true
1381                } else {
1382                    false
1383                }
1384            }
1385            Some(_) => true,
1386            None => false,
1387        }
1388    }
1389
1390    /// When name resolution fails, this method can be used to look up candidate
1391    /// entities with the expected name. It allows filtering them using the
1392    /// supplied predicate (which should be used to only accept the types of
1393    /// definitions expected, e.g., traits). The lookup spans across all crates.
1394    ///
1395    /// N.B., the method does not look into imports, but this is not a problem,
1396    /// since we report the definitions (thus, the de-aliased imports).
1397    pub(crate) fn lookup_import_candidates<FilterFn>(
1398        &mut self,
1399        lookup_ident: Ident,
1400        namespace: Namespace,
1401        parent_scope: &ParentScope<'ra>,
1402        filter_fn: FilterFn,
1403    ) -> Vec<ImportSuggestion>
1404    where
1405        FilterFn: Fn(Res) -> bool,
1406    {
1407        let crate_path = thin_vec![ast::PathSegment::from_ident(Ident::with_dummy_span(kw::Crate))];
1408        let mut suggestions = self.lookup_import_candidates_from_module(
1409            lookup_ident,
1410            namespace,
1411            parent_scope,
1412            self.graph_root,
1413            crate_path,
1414            &filter_fn,
1415        );
1416
1417        if lookup_ident.span.at_least_rust_2018() {
1418            for ident in self.extern_prelude.clone().into_keys() {
1419                if ident.span.from_expansion() {
1420                    // Idents are adjusted to the root context before being
1421                    // resolved in the extern prelude, so reporting this to the
1422                    // user is no help. This skips the injected
1423                    // `extern crate std` in the 2018 edition, which would
1424                    // otherwise cause duplicate suggestions.
1425                    continue;
1426                }
1427                let Some(crate_id) = self.crate_loader(|c| c.maybe_process_path_extern(ident.name))
1428                else {
1429                    continue;
1430                };
1431
1432                let crate_def_id = crate_id.as_def_id();
1433                let crate_root = self.expect_module(crate_def_id);
1434
1435                // Check if there's already an item in scope with the same name as the crate.
1436                // If so, we have to disambiguate the potential import suggestions by making
1437                // the paths *global* (i.e., by prefixing them with `::`).
1438                let needs_disambiguation =
1439                    self.resolutions(parent_scope.module).borrow().iter().any(
1440                        |(key, name_resolution)| {
1441                            if key.ns == TypeNS
1442                                && key.ident == ident
1443                                && let Some(binding) = name_resolution.borrow().binding
1444                            {
1445                                match binding.res() {
1446                                    // No disambiguation needed if the identically named item we
1447                                    // found in scope actually refers to the crate in question.
1448                                    Res::Def(_, def_id) => def_id != crate_def_id,
1449                                    Res::PrimTy(_) => true,
1450                                    _ => false,
1451                                }
1452                            } else {
1453                                false
1454                            }
1455                        },
1456                    );
1457                let mut crate_path = ThinVec::new();
1458                if needs_disambiguation {
1459                    crate_path.push(ast::PathSegment::path_root(rustc_span::DUMMY_SP));
1460                }
1461                crate_path.push(ast::PathSegment::from_ident(ident));
1462
1463                suggestions.extend(self.lookup_import_candidates_from_module(
1464                    lookup_ident,
1465                    namespace,
1466                    parent_scope,
1467                    crate_root,
1468                    crate_path,
1469                    &filter_fn,
1470                ));
1471            }
1472        }
1473
1474        suggestions
1475    }
1476
1477    pub(crate) fn unresolved_macro_suggestions(
1478        &mut self,
1479        err: &mut Diag<'_>,
1480        macro_kind: MacroKind,
1481        parent_scope: &ParentScope<'ra>,
1482        ident: Ident,
1483        krate: &Crate,
1484        sugg_span: Option<Span>,
1485    ) {
1486        // Bring imported but unused `derive` macros into `macro_map` so we ensure they can be used
1487        // for suggestions.
1488        self.visit_scopes(
1489            ScopeSet::Macro(MacroKind::Derive),
1490            &parent_scope,
1491            ident.span.ctxt(),
1492            |this, scope, _use_prelude, _ctxt| {
1493                let Scope::Module(m, _) = scope else {
1494                    return None;
1495                };
1496                for (_, resolution) in this.resolutions(m).borrow().iter() {
1497                    let Some(binding) = resolution.borrow().binding else {
1498                        continue;
1499                    };
1500                    let Res::Def(DefKind::Macro(MacroKind::Derive | MacroKind::Attr), def_id) =
1501                        binding.res()
1502                    else {
1503                        continue;
1504                    };
1505                    // By doing this all *imported* macros get added to the `macro_map` even if they
1506                    // are *unused*, which makes the later suggestions find them and work.
1507                    let _ = this.get_macro_by_def_id(def_id);
1508                }
1509                None::<()>
1510            },
1511        );
1512
1513        let is_expected = &|res: Res| res.macro_kind() == Some(macro_kind);
1514        let suggestion = self.early_lookup_typo_candidate(
1515            ScopeSet::Macro(macro_kind),
1516            parent_scope,
1517            ident,
1518            is_expected,
1519        );
1520        if !self.add_typo_suggestion(err, suggestion, ident.span) {
1521            self.detect_derive_attribute(err, ident, parent_scope, sugg_span);
1522        }
1523
1524        let import_suggestions =
1525            self.lookup_import_candidates(ident, Namespace::MacroNS, parent_scope, is_expected);
1526        let (span, found_use) = match parent_scope.module.nearest_parent_mod().as_local() {
1527            Some(def_id) => UsePlacementFinder::check(krate, self.def_id_to_node_id(def_id)),
1528            None => (None, FoundUse::No),
1529        };
1530        show_candidates(
1531            self.tcx,
1532            err,
1533            span,
1534            &import_suggestions,
1535            Instead::No,
1536            found_use,
1537            DiagMode::Normal,
1538            vec![],
1539            "",
1540        );
1541
1542        if macro_kind == MacroKind::Bang && ident.name == sym::macro_rules {
1543            let label_span = ident.span.shrink_to_hi();
1544            let mut spans = MultiSpan::from_span(label_span);
1545            spans.push_span_label(label_span, "put a macro name here");
1546            err.subdiagnostic(MaybeMissingMacroRulesName { spans });
1547            return;
1548        }
1549
1550        if macro_kind == MacroKind::Derive && (ident.name == sym::Send || ident.name == sym::Sync) {
1551            err.subdiagnostic(ExplicitUnsafeTraits { span: ident.span, ident });
1552            return;
1553        }
1554
1555        let unused_macro = self.unused_macros.iter().find_map(|(def_id, (_, unused_ident))| {
1556            if unused_ident.name == ident.name { Some((def_id, unused_ident)) } else { None }
1557        });
1558
1559        if let Some((def_id, unused_ident)) = unused_macro {
1560            let scope = self.local_macro_def_scopes[&def_id];
1561            let parent_nearest = parent_scope.module.nearest_parent_mod();
1562            if Some(parent_nearest) == scope.opt_def_id() {
1563                match macro_kind {
1564                    MacroKind::Bang => {
1565                        err.subdiagnostic(MacroDefinedLater { span: unused_ident.span });
1566                        err.subdiagnostic(MacroSuggMovePosition { span: ident.span, ident });
1567                    }
1568                    MacroKind::Attr => {
1569                        err.subdiagnostic(MacroRulesNot::Attr { span: unused_ident.span, ident });
1570                    }
1571                    MacroKind::Derive => {
1572                        err.subdiagnostic(MacroRulesNot::Derive { span: unused_ident.span, ident });
1573                    }
1574                }
1575
1576                return;
1577            }
1578        }
1579
1580        if self.macro_names.contains(&ident.normalize_to_macros_2_0()) {
1581            err.subdiagnostic(AddedMacroUse);
1582            return;
1583        }
1584
1585        if ident.name == kw::Default
1586            && let ModuleKind::Def(DefKind::Enum, def_id, _) = parent_scope.module.kind
1587        {
1588            let span = self.def_span(def_id);
1589            let source_map = self.tcx.sess.source_map();
1590            let head_span = source_map.guess_head_span(span);
1591            err.subdiagnostic(ConsiderAddingADerive {
1592                span: head_span.shrink_to_lo(),
1593                suggestion: "#[derive(Default)]\n".to_string(),
1594            });
1595        }
1596        for ns in [Namespace::MacroNS, Namespace::TypeNS, Namespace::ValueNS] {
1597            let Ok(binding) = self.early_resolve_ident_in_lexical_scope(
1598                ident,
1599                ScopeSet::All(ns),
1600                parent_scope,
1601                None,
1602                false,
1603                None,
1604                None,
1605            ) else {
1606                continue;
1607            };
1608
1609            let desc = match binding.res() {
1610                Res::Def(DefKind::Macro(MacroKind::Bang), _) => "a function-like macro".to_string(),
1611                Res::Def(DefKind::Macro(MacroKind::Attr), _) | Res::NonMacroAttr(..) => {
1612                    format!("an attribute: `#[{ident}]`")
1613                }
1614                Res::Def(DefKind::Macro(MacroKind::Derive), _) => {
1615                    format!("a derive macro: `#[derive({ident})]`")
1616                }
1617                Res::ToolMod => {
1618                    // Don't confuse the user with tool modules.
1619                    continue;
1620                }
1621                Res::Def(DefKind::Trait, _) if macro_kind == MacroKind::Derive => {
1622                    "only a trait, without a derive macro".to_string()
1623                }
1624                res => format!(
1625                    "{} {}, not {} {}",
1626                    res.article(),
1627                    res.descr(),
1628                    macro_kind.article(),
1629                    macro_kind.descr_expected(),
1630                ),
1631            };
1632            if let crate::NameBindingKind::Import { import, .. } = binding.kind
1633                && !import.span.is_dummy()
1634            {
1635                let note = errors::IdentImporterHereButItIsDesc {
1636                    span: import.span,
1637                    imported_ident: ident,
1638                    imported_ident_desc: &desc,
1639                };
1640                err.subdiagnostic(note);
1641                // Silence the 'unused import' warning we might get,
1642                // since this diagnostic already covers that import.
1643                self.record_use(ident, binding, Used::Other);
1644                return;
1645            }
1646            let note = errors::IdentInScopeButItIsDesc {
1647                imported_ident: ident,
1648                imported_ident_desc: &desc,
1649            };
1650            err.subdiagnostic(note);
1651            return;
1652        }
1653    }
1654
1655    /// Given an attribute macro that failed to be resolved, look for `derive` macros that could
1656    /// provide it, either as-is or with small typos.
1657    fn detect_derive_attribute(
1658        &self,
1659        err: &mut Diag<'_>,
1660        ident: Ident,
1661        parent_scope: &ParentScope<'ra>,
1662        sugg_span: Option<Span>,
1663    ) {
1664        // Find all of the `derive`s in scope and collect their corresponding declared
1665        // attributes.
1666        // FIXME: this only works if the crate that owns the macro that has the helper_attr
1667        // has already been imported.
1668        let mut derives = vec![];
1669        let mut all_attrs: UnordMap<Symbol, Vec<_>> = UnordMap::default();
1670        // We're collecting these in a hashmap, and handle ordering the output further down.
1671        #[allow(rustc::potential_query_instability)]
1672        for (def_id, data) in &self.macro_map {
1673            for helper_attr in &data.ext.helper_attrs {
1674                let item_name = self.tcx.item_name(*def_id);
1675                all_attrs.entry(*helper_attr).or_default().push(item_name);
1676                if helper_attr == &ident.name {
1677                    derives.push(item_name);
1678                }
1679            }
1680        }
1681        let kind = MacroKind::Derive.descr();
1682        if !derives.is_empty() {
1683            // We found an exact match for the missing attribute in a `derive` macro. Suggest it.
1684            let mut derives: Vec<String> = derives.into_iter().map(|d| d.to_string()).collect();
1685            derives.sort();
1686            derives.dedup();
1687            let msg = match &derives[..] {
1688                [derive] => format!(" `{derive}`"),
1689                [start @ .., last] => format!(
1690                    "s {} and `{last}`",
1691                    start.iter().map(|d| format!("`{d}`")).collect::<Vec<_>>().join(", ")
1692                ),
1693                [] => unreachable!("we checked for this to be non-empty 10 lines above!?"),
1694            };
1695            let msg = format!(
1696                "`{}` is an attribute that can be used by the {kind}{msg}, you might be \
1697                     missing a `derive` attribute",
1698                ident.name,
1699            );
1700            let sugg_span = if let ModuleKind::Def(DefKind::Enum, id, _) = parent_scope.module.kind
1701            {
1702                let span = self.def_span(id);
1703                if span.from_expansion() {
1704                    None
1705                } else {
1706                    // For enum variants sugg_span is empty but we can get the enum's Span.
1707                    Some(span.shrink_to_lo())
1708                }
1709            } else {
1710                // For items this `Span` will be populated, everything else it'll be None.
1711                sugg_span
1712            };
1713            match sugg_span {
1714                Some(span) => {
1715                    err.span_suggestion_verbose(
1716                        span,
1717                        msg,
1718                        format!("#[derive({})]\n", derives.join(", ")),
1719                        Applicability::MaybeIncorrect,
1720                    );
1721                }
1722                None => {
1723                    err.note(msg);
1724                }
1725            }
1726        } else {
1727            // We didn't find an exact match. Look for close matches. If any, suggest fixing typo.
1728            let all_attr_names = all_attrs.keys().map(|s| *s).into_sorted_stable_ord();
1729            if let Some(best_match) = find_best_match_for_name(&all_attr_names, ident.name, None)
1730                && let Some(macros) = all_attrs.get(&best_match)
1731            {
1732                let mut macros: Vec<String> = macros.into_iter().map(|d| d.to_string()).collect();
1733                macros.sort();
1734                macros.dedup();
1735                let msg = match &macros[..] {
1736                    [] => return,
1737                    [name] => format!(" `{name}` accepts"),
1738                    [start @ .., end] => format!(
1739                        "s {} and `{end}` accept",
1740                        start.iter().map(|m| format!("`{m}`")).collect::<Vec<_>>().join(", "),
1741                    ),
1742                };
1743                let msg = format!("the {kind}{msg} the similarly named `{best_match}` attribute");
1744                err.span_suggestion_verbose(
1745                    ident.span,
1746                    msg,
1747                    best_match,
1748                    Applicability::MaybeIncorrect,
1749                );
1750            }
1751        }
1752    }
1753
1754    pub(crate) fn add_typo_suggestion(
1755        &self,
1756        err: &mut Diag<'_>,
1757        suggestion: Option<TypoSuggestion>,
1758        span: Span,
1759    ) -> bool {
1760        let suggestion = match suggestion {
1761            None => return false,
1762            // We shouldn't suggest underscore.
1763            Some(suggestion) if suggestion.candidate == kw::Underscore => return false,
1764            Some(suggestion) => suggestion,
1765        };
1766
1767        let mut did_label_def_span = false;
1768
1769        if let Some(def_span) = suggestion.res.opt_def_id().map(|def_id| self.def_span(def_id)) {
1770            if span.overlaps(def_span) {
1771                // Don't suggest typo suggestion for itself like in the following:
1772                // error[E0423]: expected function, tuple struct or tuple variant, found struct `X`
1773                //   --> $DIR/issue-64792-bad-unicode-ctor.rs:3:14
1774                //    |
1775                // LL | struct X {}
1776                //    | ----------- `X` defined here
1777                // LL |
1778                // LL | const Y: X = X("ö");
1779                //    | -------------^^^^^^- similarly named constant `Y` defined here
1780                //    |
1781                // help: use struct literal syntax instead
1782                //    |
1783                // LL | const Y: X = X {};
1784                //    |              ^^^^
1785                // help: a constant with a similar name exists
1786                //    |
1787                // LL | const Y: X = Y("ö");
1788                //    |              ^
1789                return false;
1790            }
1791            let span = self.tcx.sess.source_map().guess_head_span(def_span);
1792            let candidate_descr = suggestion.res.descr();
1793            let candidate = suggestion.candidate;
1794            let label = match suggestion.target {
1795                SuggestionTarget::SimilarlyNamed => {
1796                    errors::DefinedHere::SimilarlyNamed { span, candidate_descr, candidate }
1797                }
1798                SuggestionTarget::SingleItem => {
1799                    errors::DefinedHere::SingleItem { span, candidate_descr, candidate }
1800                }
1801            };
1802            did_label_def_span = true;
1803            err.subdiagnostic(label);
1804        }
1805
1806        let (span, msg, sugg) = if let SuggestionTarget::SimilarlyNamed = suggestion.target
1807            && let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span)
1808            && let Some(span) = suggestion.span
1809            && let Some(candidate) = suggestion.candidate.as_str().strip_prefix('_')
1810            && snippet == candidate
1811        {
1812            let candidate = suggestion.candidate;
1813            // When the suggested binding change would be from `x` to `_x`, suggest changing the
1814            // original binding definition instead. (#60164)
1815            let msg = format!(
1816                "the leading underscore in `{candidate}` marks it as unused, consider renaming it to `{snippet}`"
1817            );
1818            if !did_label_def_span {
1819                err.span_label(span, format!("`{candidate}` defined here"));
1820            }
1821            (span, msg, snippet)
1822        } else {
1823            let msg = match suggestion.target {
1824                SuggestionTarget::SimilarlyNamed => format!(
1825                    "{} {} with a similar name exists",
1826                    suggestion.res.article(),
1827                    suggestion.res.descr()
1828                ),
1829                SuggestionTarget::SingleItem => {
1830                    format!("maybe you meant this {}", suggestion.res.descr())
1831                }
1832            };
1833            (span, msg, suggestion.candidate.to_ident_string())
1834        };
1835        err.span_suggestion(span, msg, sugg, Applicability::MaybeIncorrect);
1836        true
1837    }
1838
1839    fn binding_description(&self, b: NameBinding<'_>, ident: Ident, from_prelude: bool) -> String {
1840        let res = b.res();
1841        if b.span.is_dummy() || !self.tcx.sess.source_map().is_span_accessible(b.span) {
1842            // These already contain the "built-in" prefix or look bad with it.
1843            let add_built_in =
1844                !matches!(b.res(), Res::NonMacroAttr(..) | Res::PrimTy(..) | Res::ToolMod);
1845            let (built_in, from) = if from_prelude {
1846                ("", " from prelude")
1847            } else if b.is_extern_crate()
1848                && !b.is_import()
1849                && self.tcx.sess.opts.externs.get(ident.as_str()).is_some()
1850            {
1851                ("", " passed with `--extern`")
1852            } else if add_built_in {
1853                (" built-in", "")
1854            } else {
1855                ("", "")
1856            };
1857
1858            let a = if built_in.is_empty() { res.article() } else { "a" };
1859            format!("{a}{built_in} {thing}{from}", thing = res.descr())
1860        } else {
1861            let introduced = if b.is_import_user_facing() { "imported" } else { "defined" };
1862            format!("the {thing} {introduced} here", thing = res.descr())
1863        }
1864    }
1865
1866    fn ambiguity_diagnostics(&self, ambiguity_error: &AmbiguityError<'_>) -> AmbiguityErrorDiag {
1867        let AmbiguityError { kind, ident, b1, b2, misc1, misc2, .. } = *ambiguity_error;
1868        let (b1, b2, misc1, misc2, swapped) = if b2.span.is_dummy() && !b1.span.is_dummy() {
1869            // We have to print the span-less alternative first, otherwise formatting looks bad.
1870            (b2, b1, misc2, misc1, true)
1871        } else {
1872            (b1, b2, misc1, misc2, false)
1873        };
1874        let could_refer_to = |b: NameBinding<'_>, misc: AmbiguityErrorMisc, also: &str| {
1875            let what = self.binding_description(b, ident, misc == AmbiguityErrorMisc::FromPrelude);
1876            let note_msg = format!("`{ident}` could{also} refer to {what}");
1877
1878            let thing = b.res().descr();
1879            let mut help_msgs = Vec::new();
1880            if b.is_glob_import()
1881                && (kind == AmbiguityKind::GlobVsGlob
1882                    || kind == AmbiguityKind::GlobVsExpanded
1883                    || kind == AmbiguityKind::GlobVsOuter && swapped != also.is_empty())
1884            {
1885                help_msgs.push(format!(
1886                    "consider adding an explicit import of `{ident}` to disambiguate"
1887                ))
1888            }
1889            if b.is_extern_crate() && ident.span.at_least_rust_2018() {
1890                help_msgs.push(format!("use `::{ident}` to refer to this {thing} unambiguously"))
1891            }
1892            match misc {
1893                AmbiguityErrorMisc::SuggestCrate => help_msgs
1894                    .push(format!("use `crate::{ident}` to refer to this {thing} unambiguously")),
1895                AmbiguityErrorMisc::SuggestSelf => help_msgs
1896                    .push(format!("use `self::{ident}` to refer to this {thing} unambiguously")),
1897                AmbiguityErrorMisc::FromPrelude | AmbiguityErrorMisc::None => {}
1898            }
1899
1900            (
1901                b.span,
1902                note_msg,
1903                help_msgs
1904                    .iter()
1905                    .enumerate()
1906                    .map(|(i, help_msg)| {
1907                        let or = if i == 0 { "" } else { "or " };
1908                        format!("{or}{help_msg}")
1909                    })
1910                    .collect::<Vec<_>>(),
1911            )
1912        };
1913        let (b1_span, b1_note_msg, b1_help_msgs) = could_refer_to(b1, misc1, "");
1914        let (b2_span, b2_note_msg, b2_help_msgs) = could_refer_to(b2, misc2, " also");
1915
1916        AmbiguityErrorDiag {
1917            msg: format!("`{ident}` is ambiguous"),
1918            span: ident.span,
1919            label_span: ident.span,
1920            label_msg: "ambiguous name".to_string(),
1921            note_msg: format!("ambiguous because of {}", kind.descr()),
1922            b1_span,
1923            b1_note_msg,
1924            b1_help_msgs,
1925            b2_span,
1926            b2_note_msg,
1927            b2_help_msgs,
1928        }
1929    }
1930
1931    /// If the binding refers to a tuple struct constructor with fields,
1932    /// returns the span of its fields.
1933    fn ctor_fields_span(&self, binding: NameBinding<'_>) -> Option<Span> {
1934        let NameBindingKind::Res(Res::Def(
1935            DefKind::Ctor(CtorOf::Struct, CtorKind::Fn),
1936            ctor_def_id,
1937        )) = binding.kind
1938        else {
1939            return None;
1940        };
1941
1942        let def_id = self.tcx.parent(ctor_def_id);
1943        self.field_idents(def_id)?.iter().map(|&f| f.span).reduce(Span::to) // None for `struct Foo()`
1944    }
1945
1946    fn report_privacy_error(&mut self, privacy_error: &PrivacyError<'ra>) {
1947        let PrivacyError { ident, binding, outermost_res, parent_scope, single_nested, dedup_span } =
1948            *privacy_error;
1949
1950        let res = binding.res();
1951        let ctor_fields_span = self.ctor_fields_span(binding);
1952        let plain_descr = res.descr().to_string();
1953        let nonimport_descr =
1954            if ctor_fields_span.is_some() { plain_descr + " constructor" } else { plain_descr };
1955        let import_descr = nonimport_descr.clone() + " import";
1956        let get_descr =
1957            |b: NameBinding<'_>| if b.is_import() { &import_descr } else { &nonimport_descr };
1958
1959        // Print the primary message.
1960        let ident_descr = get_descr(binding);
1961        let mut err =
1962            self.dcx().create_err(errors::IsPrivate { span: ident.span, ident_descr, ident });
1963
1964        let mut not_publicly_reexported = false;
1965        if let Some((this_res, outer_ident)) = outermost_res {
1966            let import_suggestions = self.lookup_import_candidates(
1967                outer_ident,
1968                this_res.ns().unwrap_or(Namespace::TypeNS),
1969                &parent_scope,
1970                &|res: Res| res == this_res,
1971            );
1972            let point_to_def = !show_candidates(
1973                self.tcx,
1974                &mut err,
1975                Some(dedup_span.until(outer_ident.span.shrink_to_hi())),
1976                &import_suggestions,
1977                Instead::Yes,
1978                FoundUse::Yes,
1979                DiagMode::Import { append: single_nested, unresolved_import: false },
1980                vec![],
1981                "",
1982            );
1983            // If we suggest importing a public re-export, don't point at the definition.
1984            if point_to_def && ident.span != outer_ident.span {
1985                not_publicly_reexported = true;
1986                let label = errors::OuterIdentIsNotPubliclyReexported {
1987                    span: outer_ident.span,
1988                    outer_ident_descr: this_res.descr(),
1989                    outer_ident,
1990                };
1991                err.subdiagnostic(label);
1992            }
1993        }
1994
1995        let mut non_exhaustive = None;
1996        // If an ADT is foreign and marked as `non_exhaustive`, then that's
1997        // probably why we have the privacy error.
1998        // Otherwise, point out if the struct has any private fields.
1999        if let Some(def_id) = res.opt_def_id()
2000            && !def_id.is_local()
2001            && let Some(attr) = self.tcx.get_attr(def_id, sym::non_exhaustive)
2002        {
2003            non_exhaustive = Some(attr.span());
2004        } else if let Some(span) = ctor_fields_span {
2005            let label = errors::ConstructorPrivateIfAnyFieldPrivate { span };
2006            err.subdiagnostic(label);
2007            if let Res::Def(_, d) = res
2008                && let Some(fields) = self.field_visibility_spans.get(&d)
2009            {
2010                let spans = fields.iter().map(|span| *span).collect();
2011                let sugg =
2012                    errors::ConsiderMakingTheFieldPublic { spans, number_of_fields: fields.len() };
2013                err.subdiagnostic(sugg);
2014            }
2015        }
2016
2017        let mut sugg_paths = vec![];
2018        if let Some(mut def_id) = res.opt_def_id() {
2019            // We can't use `def_path_str` in resolve.
2020            let mut path = vec![def_id];
2021            while let Some(parent) = self.tcx.opt_parent(def_id) {
2022                def_id = parent;
2023                if !def_id.is_top_level_module() {
2024                    path.push(def_id);
2025                } else {
2026                    break;
2027                }
2028            }
2029            // We will only suggest importing directly if it is accessible through that path.
2030            let path_names: Option<Vec<String>> = path
2031                .iter()
2032                .rev()
2033                .map(|def_id| {
2034                    self.tcx.opt_item_name(*def_id).map(|n| {
2035                        if def_id.is_top_level_module() {
2036                            "crate".to_string()
2037                        } else {
2038                            n.to_string()
2039                        }
2040                    })
2041                })
2042                .collect();
2043            if let Some(def_id) = path.get(0)
2044                && let Some(path) = path_names
2045            {
2046                if let Some(def_id) = def_id.as_local() {
2047                    if self.effective_visibilities.is_directly_public(def_id) {
2048                        sugg_paths.push((path, false));
2049                    }
2050                } else if self.is_accessible_from(self.tcx.visibility(def_id), parent_scope.module)
2051                {
2052                    sugg_paths.push((path, false));
2053                }
2054            }
2055        }
2056
2057        // Print the whole import chain to make it easier to see what happens.
2058        let first_binding = binding;
2059        let mut next_binding = Some(binding);
2060        let mut next_ident = ident;
2061        let mut path = vec![];
2062        while let Some(binding) = next_binding {
2063            let name = next_ident;
2064            next_binding = match binding.kind {
2065                _ if res == Res::Err => None,
2066                NameBindingKind::Import { binding, import, .. } => match import.kind {
2067                    _ if binding.span.is_dummy() => None,
2068                    ImportKind::Single { source, .. } => {
2069                        next_ident = source;
2070                        Some(binding)
2071                    }
2072                    ImportKind::Glob { .. }
2073                    | ImportKind::MacroUse { .. }
2074                    | ImportKind::MacroExport => Some(binding),
2075                    ImportKind::ExternCrate { .. } => None,
2076                },
2077                _ => None,
2078            };
2079
2080            match binding.kind {
2081                NameBindingKind::Import { import, .. } => {
2082                    for segment in import.module_path.iter().skip(1) {
2083                        path.push(segment.ident.to_string());
2084                    }
2085                    sugg_paths.push((
2086                        path.iter()
2087                            .cloned()
2088                            .chain(vec![ident.to_string()].into_iter())
2089                            .collect::<Vec<_>>(),
2090                        true, // re-export
2091                    ));
2092                }
2093                NameBindingKind::Res(_) | NameBindingKind::Module(_) => {}
2094            }
2095            let first = binding == first_binding;
2096            let def_span = self.tcx.sess.source_map().guess_head_span(binding.span);
2097            let mut note_span = MultiSpan::from_span(def_span);
2098            if !first && binding.vis.is_public() {
2099                let desc = match binding.kind {
2100                    NameBindingKind::Import { .. } => "re-export",
2101                    _ => "directly",
2102                };
2103                note_span.push_span_label(def_span, format!("you could import this {desc}"));
2104            }
2105            // Final step in the import chain, point out if the ADT is `non_exhaustive`
2106            // which is probably why this privacy violation occurred.
2107            if next_binding.is_none()
2108                && let Some(span) = non_exhaustive
2109            {
2110                note_span.push_span_label(
2111                    span,
2112                    "cannot be constructed because it is `#[non_exhaustive]`",
2113                );
2114            }
2115            let note = errors::NoteAndRefersToTheItemDefinedHere {
2116                span: note_span,
2117                binding_descr: get_descr(binding),
2118                binding_name: name,
2119                first,
2120                dots: next_binding.is_some(),
2121            };
2122            err.subdiagnostic(note);
2123        }
2124        // We prioritize shorter paths, non-core imports and direct imports over the alternatives.
2125        sugg_paths.sort_by_key(|(p, reexport)| (p.len(), p[0] == "core", *reexport));
2126        for (sugg, reexport) in sugg_paths {
2127            if not_publicly_reexported {
2128                break;
2129            }
2130            if sugg.len() <= 1 {
2131                // A single path segment suggestion is wrong. This happens on circular imports.
2132                // `tests/ui/imports/issue-55884-2.rs`
2133                continue;
2134            }
2135            let path = sugg.join("::");
2136            let sugg = if reexport {
2137                errors::ImportIdent::ThroughReExport { span: dedup_span, ident, path }
2138            } else {
2139                errors::ImportIdent::Directly { span: dedup_span, ident, path }
2140            };
2141            err.subdiagnostic(sugg);
2142            break;
2143        }
2144
2145        err.emit();
2146    }
2147
2148    pub(crate) fn find_similarly_named_module_or_crate(
2149        &mut self,
2150        ident: Symbol,
2151        current_module: Module<'ra>,
2152    ) -> Option<Symbol> {
2153        let mut candidates = self
2154            .extern_prelude
2155            .keys()
2156            .map(|ident| ident.name)
2157            .chain(
2158                self.module_map
2159                    .iter()
2160                    .filter(|(_, module)| {
2161                        current_module.is_ancestor_of(**module) && current_module != **module
2162                    })
2163                    .flat_map(|(_, module)| module.kind.name()),
2164            )
2165            .filter(|c| !c.to_string().is_empty())
2166            .collect::<Vec<_>>();
2167        candidates.sort();
2168        candidates.dedup();
2169        find_best_match_for_name(&candidates, ident, None).filter(|sugg| *sugg != ident)
2170    }
2171
2172    pub(crate) fn report_path_resolution_error(
2173        &mut self,
2174        path: &[Segment],
2175        opt_ns: Option<Namespace>, // `None` indicates a module path in import
2176        parent_scope: &ParentScope<'ra>,
2177        ribs: Option<&PerNS<Vec<Rib<'ra>>>>,
2178        ignore_binding: Option<NameBinding<'ra>>,
2179        ignore_import: Option<Import<'ra>>,
2180        module: Option<ModuleOrUniformRoot<'ra>>,
2181        failed_segment_idx: usize,
2182        ident: Ident,
2183    ) -> (String, Option<Suggestion>) {
2184        let is_last = failed_segment_idx == path.len() - 1;
2185        let ns = if is_last { opt_ns.unwrap_or(TypeNS) } else { TypeNS };
2186        let module_res = match module {
2187            Some(ModuleOrUniformRoot::Module(module)) => module.res(),
2188            _ => None,
2189        };
2190        if module_res == self.graph_root.res() {
2191            let is_mod = |res| matches!(res, Res::Def(DefKind::Mod, _));
2192            let mut candidates = self.lookup_import_candidates(ident, TypeNS, parent_scope, is_mod);
2193            candidates
2194                .sort_by_cached_key(|c| (c.path.segments.len(), pprust::path_to_string(&c.path)));
2195            if let Some(candidate) = candidates.get(0) {
2196                let path = {
2197                    // remove the possible common prefix of the path
2198                    let len = candidate.path.segments.len();
2199                    let start_index = (0..=failed_segment_idx.min(len - 1))
2200                        .find(|&i| path[i].ident.name != candidate.path.segments[i].ident.name)
2201                        .unwrap_or_default();
2202                    let segments =
2203                        (start_index..len).map(|s| candidate.path.segments[s].clone()).collect();
2204                    Path { segments, span: Span::default(), tokens: None }
2205                };
2206                (
2207                    String::from("unresolved import"),
2208                    Some((
2209                        vec![(ident.span, pprust::path_to_string(&path))],
2210                        String::from("a similar path exists"),
2211                        Applicability::MaybeIncorrect,
2212                    )),
2213                )
2214            } else if ident.name == sym::core {
2215                (
2216                    format!("you might be missing crate `{ident}`"),
2217                    Some((
2218                        vec![(ident.span, "std".to_string())],
2219                        "try using `std` instead of `core`".to_string(),
2220                        Applicability::MaybeIncorrect,
2221                    )),
2222                )
2223            } else if ident.name == kw::Underscore {
2224                (format!("`_` is not a valid crate or module name"), None)
2225            } else if self.tcx.sess.is_rust_2015() {
2226                (
2227                    format!("use of unresolved module or unlinked crate `{ident}`"),
2228                    Some((
2229                        vec![(
2230                            self.current_crate_outer_attr_insert_span,
2231                            format!("extern crate {ident};\n"),
2232                        )],
2233                        if was_invoked_from_cargo() {
2234                            format!(
2235                                "if you wanted to use a crate named `{ident}`, use `cargo add {ident}` \
2236                             to add it to your `Cargo.toml` and import it in your code",
2237                            )
2238                        } else {
2239                            format!(
2240                                "you might be missing a crate named `{ident}`, add it to your \
2241                                 project and import it in your code",
2242                            )
2243                        },
2244                        Applicability::MaybeIncorrect,
2245                    )),
2246                )
2247            } else {
2248                (format!("could not find `{ident}` in the crate root"), None)
2249            }
2250        } else if failed_segment_idx > 0 {
2251            let parent = path[failed_segment_idx - 1].ident.name;
2252            let parent = match parent {
2253                // ::foo is mounted at the crate root for 2015, and is the extern
2254                // prelude for 2018+
2255                kw::PathRoot if self.tcx.sess.edition() > Edition::Edition2015 => {
2256                    "the list of imported crates".to_owned()
2257                }
2258                kw::PathRoot | kw::Crate => "the crate root".to_owned(),
2259                _ => format!("`{parent}`"),
2260            };
2261
2262            let mut msg = format!("could not find `{ident}` in {parent}");
2263            if ns == TypeNS || ns == ValueNS {
2264                let ns_to_try = if ns == TypeNS { ValueNS } else { TypeNS };
2265                let binding = if let Some(module) = module {
2266                    self.resolve_ident_in_module(
2267                        module,
2268                        ident,
2269                        ns_to_try,
2270                        parent_scope,
2271                        None,
2272                        ignore_binding,
2273                        ignore_import,
2274                    )
2275                    .ok()
2276                } else if let Some(ribs) = ribs
2277                    && let Some(TypeNS | ValueNS) = opt_ns
2278                {
2279                    assert!(ignore_import.is_none());
2280                    match self.resolve_ident_in_lexical_scope(
2281                        ident,
2282                        ns_to_try,
2283                        parent_scope,
2284                        None,
2285                        &ribs[ns_to_try],
2286                        ignore_binding,
2287                    ) {
2288                        // we found a locally-imported or available item/module
2289                        Some(LexicalScopeBinding::Item(binding)) => Some(binding),
2290                        _ => None,
2291                    }
2292                } else {
2293                    self.early_resolve_ident_in_lexical_scope(
2294                        ident,
2295                        ScopeSet::All(ns_to_try),
2296                        parent_scope,
2297                        None,
2298                        false,
2299                        ignore_binding,
2300                        ignore_import,
2301                    )
2302                    .ok()
2303                };
2304                if let Some(binding) = binding {
2305                    let mut found = |what| {
2306                        msg = format!(
2307                            "expected {}, found {} `{}` in {}",
2308                            ns.descr(),
2309                            what,
2310                            ident,
2311                            parent
2312                        )
2313                    };
2314                    if binding.module().is_some() {
2315                        found("module")
2316                    } else {
2317                        match binding.res() {
2318                            // Avoid using TyCtxt::def_kind_descr in the resolver, because it
2319                            // indirectly *calls* the resolver, and would cause a query cycle.
2320                            Res::Def(kind, id) => found(kind.descr(id)),
2321                            _ => found(ns_to_try.descr()),
2322                        }
2323                    }
2324                };
2325            }
2326            (msg, None)
2327        } else if ident.name == kw::SelfUpper {
2328            // As mentioned above, `opt_ns` being `None` indicates a module path in import.
2329            // We can use this to improve a confusing error for, e.g. `use Self::Variant` in an
2330            // impl
2331            if opt_ns.is_none() {
2332                ("`Self` cannot be used in imports".to_string(), None)
2333            } else {
2334                (
2335                    "`Self` is only available in impls, traits, and type definitions".to_string(),
2336                    None,
2337                )
2338            }
2339        } else if ident.name.as_str().chars().next().is_some_and(|c| c.is_ascii_uppercase()) {
2340            // Check whether the name refers to an item in the value namespace.
2341            let binding = if let Some(ribs) = ribs {
2342                assert!(ignore_import.is_none());
2343                self.resolve_ident_in_lexical_scope(
2344                    ident,
2345                    ValueNS,
2346                    parent_scope,
2347                    None,
2348                    &ribs[ValueNS],
2349                    ignore_binding,
2350                )
2351            } else {
2352                None
2353            };
2354            let match_span = match binding {
2355                // Name matches a local variable. For example:
2356                // ```
2357                // fn f() {
2358                //     let Foo: &str = "";
2359                //     println!("{}", Foo::Bar); // Name refers to local
2360                //                               // variable `Foo`.
2361                // }
2362                // ```
2363                Some(LexicalScopeBinding::Res(Res::Local(id))) => {
2364                    Some(*self.pat_span_map.get(&id).unwrap())
2365                }
2366                // Name matches item from a local name binding
2367                // created by `use` declaration. For example:
2368                // ```
2369                // pub Foo: &str = "";
2370                //
2371                // mod submod {
2372                //     use super::Foo;
2373                //     println!("{}", Foo::Bar); // Name refers to local
2374                //                               // binding `Foo`.
2375                // }
2376                // ```
2377                Some(LexicalScopeBinding::Item(name_binding)) => Some(name_binding.span),
2378                _ => None,
2379            };
2380            let suggestion = match_span.map(|span| {
2381                (
2382                    vec![(span, String::from(""))],
2383                    format!("`{ident}` is defined here, but is not a type"),
2384                    Applicability::MaybeIncorrect,
2385                )
2386            });
2387
2388            (format!("use of undeclared type `{ident}`"), suggestion)
2389        } else {
2390            let mut suggestion = None;
2391            if ident.name == sym::alloc {
2392                suggestion = Some((
2393                    vec![],
2394                    String::from("add `extern crate alloc` to use the `alloc` crate"),
2395                    Applicability::MaybeIncorrect,
2396                ))
2397            }
2398
2399            suggestion = suggestion.or_else(|| {
2400                self.find_similarly_named_module_or_crate(ident.name, parent_scope.module).map(
2401                    |sugg| {
2402                        (
2403                            vec![(ident.span, sugg.to_string())],
2404                            String::from("there is a crate or module with a similar name"),
2405                            Applicability::MaybeIncorrect,
2406                        )
2407                    },
2408                )
2409            });
2410            if let Ok(binding) = self.early_resolve_ident_in_lexical_scope(
2411                ident,
2412                ScopeSet::All(ValueNS),
2413                parent_scope,
2414                None,
2415                false,
2416                ignore_binding,
2417                ignore_import,
2418            ) {
2419                let descr = binding.res().descr();
2420                (format!("{descr} `{ident}` is not a crate or module"), suggestion)
2421            } else {
2422                let suggestion = if suggestion.is_some() {
2423                    suggestion
2424                } else if let Some(m) = self.undeclared_module_exists(ident) {
2425                    self.undeclared_module_suggest_declare(ident, m)
2426                } else if was_invoked_from_cargo() {
2427                    Some((
2428                        vec![],
2429                        format!(
2430                            "if you wanted to use a crate named `{ident}`, use `cargo add {ident}` \
2431                             to add it to your `Cargo.toml`",
2432                        ),
2433                        Applicability::MaybeIncorrect,
2434                    ))
2435                } else {
2436                    Some((
2437                        vec![],
2438                        format!("you might be missing a crate named `{ident}`",),
2439                        Applicability::MaybeIncorrect,
2440                    ))
2441                };
2442                (format!("use of unresolved module or unlinked crate `{ident}`"), suggestion)
2443            }
2444        }
2445    }
2446
2447    fn undeclared_module_suggest_declare(
2448        &mut self,
2449        ident: Ident,
2450        path: std::path::PathBuf,
2451    ) -> Option<(Vec<(Span, String)>, String, Applicability)> {
2452        Some((
2453            vec![(self.current_crate_outer_attr_insert_span, format!("mod {ident};\n"))],
2454            format!(
2455                "to make use of source file {}, use `mod {ident}` \
2456                 in this file to declare the module",
2457                path.display()
2458            ),
2459            Applicability::MaybeIncorrect,
2460        ))
2461    }
2462
2463    fn undeclared_module_exists(&mut self, ident: Ident) -> Option<std::path::PathBuf> {
2464        let map = self.tcx.sess.source_map();
2465
2466        let src = map.span_to_filename(ident.span).into_local_path()?;
2467        let i = ident.as_str();
2468        // FIXME: add case where non parent using undeclared module (hard?)
2469        let dir = src.parent()?;
2470        let src = src.file_stem()?.to_str()?;
2471        for file in [
2472            // …/x.rs
2473            dir.join(i).with_extension("rs"),
2474            // …/x/mod.rs
2475            dir.join(i).join("mod.rs"),
2476        ] {
2477            if file.exists() {
2478                return Some(file);
2479            }
2480        }
2481        if !matches!(src, "main" | "lib" | "mod") {
2482            for file in [
2483                // …/x/y.rs
2484                dir.join(src).join(i).with_extension("rs"),
2485                // …/x/y/mod.rs
2486                dir.join(src).join(i).join("mod.rs"),
2487            ] {
2488                if file.exists() {
2489                    return Some(file);
2490                }
2491            }
2492        }
2493        None
2494    }
2495
2496    /// Adds suggestions for a path that cannot be resolved.
2497    #[instrument(level = "debug", skip(self, parent_scope))]
2498    pub(crate) fn make_path_suggestion(
2499        &mut self,
2500        mut path: Vec<Segment>,
2501        parent_scope: &ParentScope<'ra>,
2502    ) -> Option<(Vec<Segment>, Option<String>)> {
2503        match path[..] {
2504            // `{{root}}::ident::...` on both editions.
2505            // On 2015 `{{root}}` is usually added implicitly.
2506            [first, second, ..]
2507                if first.ident.name == kw::PathRoot && !second.ident.is_path_segment_keyword() => {}
2508            // `ident::...` on 2018.
2509            [first, ..]
2510                if first.ident.span.at_least_rust_2018()
2511                    && !first.ident.is_path_segment_keyword() =>
2512            {
2513                // Insert a placeholder that's later replaced by `self`/`super`/etc.
2514                path.insert(0, Segment::from_ident(Ident::dummy()));
2515            }
2516            _ => return None,
2517        }
2518
2519        self.make_missing_self_suggestion(path.clone(), parent_scope)
2520            .or_else(|| self.make_missing_crate_suggestion(path.clone(), parent_scope))
2521            .or_else(|| self.make_missing_super_suggestion(path.clone(), parent_scope))
2522            .or_else(|| self.make_external_crate_suggestion(path, parent_scope))
2523    }
2524
2525    /// Suggest a missing `self::` if that resolves to an correct module.
2526    ///
2527    /// ```text
2528    ///    |
2529    /// LL | use foo::Bar;
2530    ///    |     ^^^ did you mean `self::foo`?
2531    /// ```
2532    #[instrument(level = "debug", skip(self, parent_scope))]
2533    fn make_missing_self_suggestion(
2534        &mut self,
2535        mut path: Vec<Segment>,
2536        parent_scope: &ParentScope<'ra>,
2537    ) -> Option<(Vec<Segment>, Option<String>)> {
2538        // Replace first ident with `self` and check if that is valid.
2539        path[0].ident.name = kw::SelfLower;
2540        let result = self.maybe_resolve_path(&path, None, parent_scope, None);
2541        debug!(?path, ?result);
2542        if let PathResult::Module(..) = result { Some((path, None)) } else { None }
2543    }
2544
2545    /// Suggests a missing `crate::` if that resolves to an correct module.
2546    ///
2547    /// ```text
2548    ///    |
2549    /// LL | use foo::Bar;
2550    ///    |     ^^^ did you mean `crate::foo`?
2551    /// ```
2552    #[instrument(level = "debug", skip(self, parent_scope))]
2553    fn make_missing_crate_suggestion(
2554        &mut self,
2555        mut path: Vec<Segment>,
2556        parent_scope: &ParentScope<'ra>,
2557    ) -> Option<(Vec<Segment>, Option<String>)> {
2558        // Replace first ident with `crate` and check if that is valid.
2559        path[0].ident.name = kw::Crate;
2560        let result = self.maybe_resolve_path(&path, None, parent_scope, None);
2561        debug!(?path, ?result);
2562        if let PathResult::Module(..) = result {
2563            Some((
2564                path,
2565                Some(
2566                    "`use` statements changed in Rust 2018; read more at \
2567                     <https://doc.rust-lang.org/edition-guide/rust-2018/module-system/path-\
2568                     clarity.html>"
2569                        .to_string(),
2570                ),
2571            ))
2572        } else {
2573            None
2574        }
2575    }
2576
2577    /// Suggests a missing `super::` if that resolves to an correct module.
2578    ///
2579    /// ```text
2580    ///    |
2581    /// LL | use foo::Bar;
2582    ///    |     ^^^ did you mean `super::foo`?
2583    /// ```
2584    #[instrument(level = "debug", skip(self, parent_scope))]
2585    fn make_missing_super_suggestion(
2586        &mut self,
2587        mut path: Vec<Segment>,
2588        parent_scope: &ParentScope<'ra>,
2589    ) -> Option<(Vec<Segment>, Option<String>)> {
2590        // Replace first ident with `crate` and check if that is valid.
2591        path[0].ident.name = kw::Super;
2592        let result = self.maybe_resolve_path(&path, None, parent_scope, None);
2593        debug!(?path, ?result);
2594        if let PathResult::Module(..) = result { Some((path, None)) } else { None }
2595    }
2596
2597    /// Suggests a missing external crate name if that resolves to an correct module.
2598    ///
2599    /// ```text
2600    ///    |
2601    /// LL | use foobar::Baz;
2602    ///    |     ^^^^^^ did you mean `baz::foobar`?
2603    /// ```
2604    ///
2605    /// Used when importing a submodule of an external crate but missing that crate's
2606    /// name as the first part of path.
2607    #[instrument(level = "debug", skip(self, parent_scope))]
2608    fn make_external_crate_suggestion(
2609        &mut self,
2610        mut path: Vec<Segment>,
2611        parent_scope: &ParentScope<'ra>,
2612    ) -> Option<(Vec<Segment>, Option<String>)> {
2613        if path[1].ident.span.is_rust_2015() {
2614            return None;
2615        }
2616
2617        // Sort extern crate names in *reverse* order to get
2618        // 1) some consistent ordering for emitted diagnostics, and
2619        // 2) `std` suggestions before `core` suggestions.
2620        let mut extern_crate_names =
2621            self.extern_prelude.keys().map(|ident| ident.name).collect::<Vec<_>>();
2622        extern_crate_names.sort_by(|a, b| b.as_str().cmp(a.as_str()));
2623
2624        for name in extern_crate_names.into_iter() {
2625            // Replace first ident with a crate name and check if that is valid.
2626            path[0].ident.name = name;
2627            let result = self.maybe_resolve_path(&path, None, parent_scope, None);
2628            debug!(?path, ?name, ?result);
2629            if let PathResult::Module(..) = result {
2630                return Some((path, None));
2631            }
2632        }
2633
2634        None
2635    }
2636
2637    /// Suggests importing a macro from the root of the crate rather than a module within
2638    /// the crate.
2639    ///
2640    /// ```text
2641    /// help: a macro with this name exists at the root of the crate
2642    ///    |
2643    /// LL | use issue_59764::makro;
2644    ///    |     ^^^^^^^^^^^^^^^^^^
2645    ///    |
2646    ///    = note: this could be because a macro annotated with `#[macro_export]` will be exported
2647    ///            at the root of the crate instead of the module where it is defined
2648    /// ```
2649    pub(crate) fn check_for_module_export_macro(
2650        &mut self,
2651        import: Import<'ra>,
2652        module: ModuleOrUniformRoot<'ra>,
2653        ident: Ident,
2654    ) -> Option<(Option<Suggestion>, Option<String>)> {
2655        let ModuleOrUniformRoot::Module(mut crate_module) = module else {
2656            return None;
2657        };
2658
2659        while let Some(parent) = crate_module.parent {
2660            crate_module = parent;
2661        }
2662
2663        if module == ModuleOrUniformRoot::Module(crate_module) {
2664            // Don't make a suggestion if the import was already from the root of the crate.
2665            return None;
2666        }
2667
2668        let resolutions = self.resolutions(crate_module).borrow();
2669        let binding_key = BindingKey::new(ident, MacroNS);
2670        let resolution = resolutions.get(&binding_key)?;
2671        let binding = resolution.borrow().binding()?;
2672        let Res::Def(DefKind::Macro(MacroKind::Bang), _) = binding.res() else {
2673            return None;
2674        };
2675        let module_name = crate_module.kind.name().unwrap_or(kw::Crate);
2676        let import_snippet = match import.kind {
2677            ImportKind::Single { source, target, .. } if source != target => {
2678                format!("{source} as {target}")
2679            }
2680            _ => format!("{ident}"),
2681        };
2682
2683        let mut corrections: Vec<(Span, String)> = Vec::new();
2684        if !import.is_nested() {
2685            // Assume this is the easy case of `use issue_59764::foo::makro;` and just remove
2686            // intermediate segments.
2687            corrections.push((import.span, format!("{module_name}::{import_snippet}")));
2688        } else {
2689            // Find the binding span (and any trailing commas and spaces).
2690            //   ie. `use a::b::{c, d, e};`
2691            //                      ^^^
2692            let (found_closing_brace, binding_span) = find_span_of_binding_until_next_binding(
2693                self.tcx.sess,
2694                import.span,
2695                import.use_span,
2696            );
2697            debug!(found_closing_brace, ?binding_span);
2698
2699            let mut removal_span = binding_span;
2700
2701            // If the binding span ended with a closing brace, as in the below example:
2702            //   ie. `use a::b::{c, d};`
2703            //                      ^
2704            // Then expand the span of characters to remove to include the previous
2705            // binding's trailing comma.
2706            //   ie. `use a::b::{c, d};`
2707            //                    ^^^
2708            if found_closing_brace
2709                && let Some(previous_span) =
2710                    extend_span_to_previous_binding(self.tcx.sess, binding_span)
2711            {
2712                debug!(?previous_span);
2713                removal_span = removal_span.with_lo(previous_span.lo());
2714            }
2715            debug!(?removal_span);
2716
2717            // Remove the `removal_span`.
2718            corrections.push((removal_span, "".to_string()));
2719
2720            // Find the span after the crate name and if it has nested imports immediately
2721            // after the crate name already.
2722            //   ie. `use a::b::{c, d};`
2723            //               ^^^^^^^^^
2724            //   or  `use a::{b, c, d}};`
2725            //               ^^^^^^^^^^^
2726            let (has_nested, after_crate_name) =
2727                find_span_immediately_after_crate_name(self.tcx.sess, import.use_span);
2728            debug!(has_nested, ?after_crate_name);
2729
2730            let source_map = self.tcx.sess.source_map();
2731
2732            // Make sure this is actually crate-relative.
2733            let is_definitely_crate = import
2734                .module_path
2735                .first()
2736                .is_some_and(|f| f.ident.name != kw::SelfLower && f.ident.name != kw::Super);
2737
2738            // Add the import to the start, with a `{` if required.
2739            let start_point = source_map.start_point(after_crate_name);
2740            if is_definitely_crate
2741                && let Ok(start_snippet) = source_map.span_to_snippet(start_point)
2742            {
2743                corrections.push((
2744                    start_point,
2745                    if has_nested {
2746                        // In this case, `start_snippet` must equal '{'.
2747                        format!("{start_snippet}{import_snippet}, ")
2748                    } else {
2749                        // In this case, add a `{`, then the moved import, then whatever
2750                        // was there before.
2751                        format!("{{{import_snippet}, {start_snippet}")
2752                    },
2753                ));
2754
2755                // Add a `};` to the end if nested, matching the `{` added at the start.
2756                if !has_nested {
2757                    corrections.push((source_map.end_point(after_crate_name), "};".to_string()));
2758                }
2759            } else {
2760                // If the root import is module-relative, add the import separately
2761                corrections.push((
2762                    import.use_span.shrink_to_lo(),
2763                    format!("use {module_name}::{import_snippet};\n"),
2764                ));
2765            }
2766        }
2767
2768        let suggestion = Some((
2769            corrections,
2770            String::from("a macro with this name exists at the root of the crate"),
2771            Applicability::MaybeIncorrect,
2772        ));
2773        Some((
2774            suggestion,
2775            Some(
2776                "this could be because a macro annotated with `#[macro_export]` will be exported \
2777            at the root of the crate instead of the module where it is defined"
2778                    .to_string(),
2779            ),
2780        ))
2781    }
2782
2783    /// Finds a cfg-ed out item inside `module` with the matching name.
2784    pub(crate) fn find_cfg_stripped(&self, err: &mut Diag<'_>, segment: &Symbol, module: DefId) {
2785        let local_items;
2786        let symbols = if module.is_local() {
2787            local_items = self
2788                .stripped_cfg_items
2789                .iter()
2790                .filter_map(|item| {
2791                    let parent_module = self.opt_local_def_id(item.parent_module)?.to_def_id();
2792                    Some(StrippedCfgItem {
2793                        parent_module,
2794                        ident: item.ident,
2795                        cfg: item.cfg.clone(),
2796                    })
2797                })
2798                .collect::<Vec<_>>();
2799            local_items.as_slice()
2800        } else {
2801            self.tcx.stripped_cfg_items(module.krate)
2802        };
2803
2804        for &StrippedCfgItem { parent_module, ident, ref cfg } in symbols {
2805            if ident.name != *segment {
2806                continue;
2807            }
2808
2809            fn comes_from_same_module_for_glob(
2810                r: &Resolver<'_, '_>,
2811                parent_module: DefId,
2812                module: DefId,
2813                visited: &mut FxHashMap<DefId, bool>,
2814            ) -> bool {
2815                if let Some(&cached) = visited.get(&parent_module) {
2816                    // this branch is prevent from being called recursively infinity,
2817                    // because there has some cycles in globs imports,
2818                    // see more spec case at `tests/ui/cfg/diagnostics-reexport-2.rs#reexport32`
2819                    return cached;
2820                }
2821                visited.insert(parent_module, false);
2822                let res = r.module_map.get(&parent_module).is_some_and(|m| {
2823                    for importer in m.glob_importers.borrow().iter() {
2824                        if let Some(next_parent_module) = importer.parent_scope.module.opt_def_id()
2825                        {
2826                            if next_parent_module == module
2827                                || comes_from_same_module_for_glob(
2828                                    r,
2829                                    next_parent_module,
2830                                    module,
2831                                    visited,
2832                                )
2833                            {
2834                                return true;
2835                            }
2836                        }
2837                    }
2838                    false
2839                });
2840                visited.insert(parent_module, res);
2841                res
2842            }
2843
2844            let comes_from_same_module = parent_module == module
2845                || comes_from_same_module_for_glob(
2846                    self,
2847                    parent_module,
2848                    module,
2849                    &mut Default::default(),
2850                );
2851            if !comes_from_same_module {
2852                continue;
2853            }
2854
2855            let note = errors::FoundItemConfigureOut { span: ident.span };
2856            err.subdiagnostic(note);
2857
2858            if let MetaItemKind::List(nested) = &cfg.kind
2859                && let MetaItemInner::MetaItem(meta_item) = &nested[0]
2860                && let MetaItemKind::NameValue(feature_name) = &meta_item.kind
2861            {
2862                let note = errors::ItemWasBehindFeature {
2863                    feature: feature_name.symbol,
2864                    span: meta_item.span,
2865                };
2866                err.subdiagnostic(note);
2867            } else {
2868                let note = errors::ItemWasCfgOut { span: cfg.span };
2869                err.subdiagnostic(note);
2870            }
2871        }
2872    }
2873}
2874
2875/// Given a `binding_span` of a binding within a use statement:
2876///
2877/// ```ignore (illustrative)
2878/// use foo::{a, b, c};
2879/// //           ^
2880/// ```
2881///
2882/// then return the span until the next binding or the end of the statement:
2883///
2884/// ```ignore (illustrative)
2885/// use foo::{a, b, c};
2886/// //           ^^^
2887/// ```
2888fn find_span_of_binding_until_next_binding(
2889    sess: &Session,
2890    binding_span: Span,
2891    use_span: Span,
2892) -> (bool, Span) {
2893    let source_map = sess.source_map();
2894
2895    // Find the span of everything after the binding.
2896    //   ie. `a, e};` or `a};`
2897    let binding_until_end = binding_span.with_hi(use_span.hi());
2898
2899    // Find everything after the binding but not including the binding.
2900    //   ie. `, e};` or `};`
2901    let after_binding_until_end = binding_until_end.with_lo(binding_span.hi());
2902
2903    // Keep characters in the span until we encounter something that isn't a comma or
2904    // whitespace.
2905    //   ie. `, ` or ``.
2906    //
2907    // Also note whether a closing brace character was encountered. If there
2908    // was, then later go backwards to remove any trailing commas that are left.
2909    let mut found_closing_brace = false;
2910    let after_binding_until_next_binding =
2911        source_map.span_take_while(after_binding_until_end, |&ch| {
2912            if ch == '}' {
2913                found_closing_brace = true;
2914            }
2915            ch == ' ' || ch == ','
2916        });
2917
2918    // Combine the two spans.
2919    //   ie. `a, ` or `a`.
2920    //
2921    // Removing these would leave `issue_52891::{d, e};` or `issue_52891::{d, e, };`
2922    let span = binding_span.with_hi(after_binding_until_next_binding.hi());
2923
2924    (found_closing_brace, span)
2925}
2926
2927/// Given a `binding_span`, return the span through to the comma or opening brace of the previous
2928/// binding.
2929///
2930/// ```ignore (illustrative)
2931/// use foo::a::{a, b, c};
2932/// //            ^^--- binding span
2933/// //            |
2934/// //            returned span
2935///
2936/// use foo::{a, b, c};
2937/// //        --- binding span
2938/// ```
2939fn extend_span_to_previous_binding(sess: &Session, binding_span: Span) -> Option<Span> {
2940    let source_map = sess.source_map();
2941
2942    // `prev_source` will contain all of the source that came before the span.
2943    // Then split based on a command and take the first (ie. closest to our span)
2944    // snippet. In the example, this is a space.
2945    let prev_source = source_map.span_to_prev_source(binding_span).ok()?;
2946
2947    let prev_comma = prev_source.rsplit(',').collect::<Vec<_>>();
2948    let prev_starting_brace = prev_source.rsplit('{').collect::<Vec<_>>();
2949    if prev_comma.len() <= 1 || prev_starting_brace.len() <= 1 {
2950        return None;
2951    }
2952
2953    let prev_comma = prev_comma.first().unwrap();
2954    let prev_starting_brace = prev_starting_brace.first().unwrap();
2955
2956    // If the amount of source code before the comma is greater than
2957    // the amount of source code before the starting brace then we've only
2958    // got one item in the nested item (eg. `issue_52891::{self}`).
2959    if prev_comma.len() > prev_starting_brace.len() {
2960        return None;
2961    }
2962
2963    Some(binding_span.with_lo(BytePos(
2964        // Take away the number of bytes for the characters we've found and an
2965        // extra for the comma.
2966        binding_span.lo().0 - (prev_comma.as_bytes().len() as u32) - 1,
2967    )))
2968}
2969
2970/// Given a `use_span` of a binding within a use statement, returns the highlighted span and if
2971/// it is a nested use tree.
2972///
2973/// ```ignore (illustrative)
2974/// use foo::a::{b, c};
2975/// //       ^^^^^^^^^^ -- false
2976///
2977/// use foo::{a, b, c};
2978/// //       ^^^^^^^^^^ -- true
2979///
2980/// use foo::{a, b::{c, d}};
2981/// //       ^^^^^^^^^^^^^^^ -- true
2982/// ```
2983#[instrument(level = "debug", skip(sess))]
2984fn find_span_immediately_after_crate_name(sess: &Session, use_span: Span) -> (bool, Span) {
2985    let source_map = sess.source_map();
2986
2987    // Using `use issue_59764::foo::{baz, makro};` as an example throughout..
2988    let mut num_colons = 0;
2989    // Find second colon.. `use issue_59764:`
2990    let until_second_colon = source_map.span_take_while(use_span, |c| {
2991        if *c == ':' {
2992            num_colons += 1;
2993        }
2994        !matches!(c, ':' if num_colons == 2)
2995    });
2996    // Find everything after the second colon.. `foo::{baz, makro};`
2997    let from_second_colon = use_span.with_lo(until_second_colon.hi() + BytePos(1));
2998
2999    let mut found_a_non_whitespace_character = false;
3000    // Find the first non-whitespace character in `from_second_colon`.. `f`
3001    let after_second_colon = source_map.span_take_while(from_second_colon, |c| {
3002        if found_a_non_whitespace_character {
3003            return false;
3004        }
3005        if !c.is_whitespace() {
3006            found_a_non_whitespace_character = true;
3007        }
3008        true
3009    });
3010
3011    // Find the first `{` in from_second_colon.. `foo::{`
3012    let next_left_bracket = source_map.span_through_char(from_second_colon, '{');
3013
3014    (next_left_bracket == after_second_colon, from_second_colon)
3015}
3016
3017/// A suggestion has already been emitted, change the wording slightly to clarify that both are
3018/// independent options.
3019enum Instead {
3020    Yes,
3021    No,
3022}
3023
3024/// Whether an existing place with an `use` item was found.
3025enum FoundUse {
3026    Yes,
3027    No,
3028}
3029
3030/// Whether a binding is part of a pattern or a use statement. Used for diagnostics.
3031pub(crate) enum DiagMode {
3032    Normal,
3033    /// The binding is part of a pattern
3034    Pattern,
3035    /// The binding is part of a use statement
3036    Import {
3037        /// `true` means diagnostics is for unresolved import
3038        unresolved_import: bool,
3039        /// `true` mean add the tips afterward for case `use a::{b,c}`,
3040        /// rather than replacing within.
3041        append: bool,
3042    },
3043}
3044
3045pub(crate) fn import_candidates(
3046    tcx: TyCtxt<'_>,
3047    err: &mut Diag<'_>,
3048    // This is `None` if all placement locations are inside expansions
3049    use_placement_span: Option<Span>,
3050    candidates: &[ImportSuggestion],
3051    mode: DiagMode,
3052    append: &str,
3053) {
3054    show_candidates(
3055        tcx,
3056        err,
3057        use_placement_span,
3058        candidates,
3059        Instead::Yes,
3060        FoundUse::Yes,
3061        mode,
3062        vec![],
3063        append,
3064    );
3065}
3066
3067type PathString<'a> = (String, &'a str, Option<Span>, &'a Option<String>, bool);
3068
3069/// When an entity with a given name is not available in scope, we search for
3070/// entities with that name in all crates. This method allows outputting the
3071/// results of this search in a programmer-friendly way. If any entities are
3072/// found and suggested, returns `true`, otherwise returns `false`.
3073fn show_candidates(
3074    tcx: TyCtxt<'_>,
3075    err: &mut Diag<'_>,
3076    // This is `None` if all placement locations are inside expansions
3077    use_placement_span: Option<Span>,
3078    candidates: &[ImportSuggestion],
3079    instead: Instead,
3080    found_use: FoundUse,
3081    mode: DiagMode,
3082    path: Vec<Segment>,
3083    append: &str,
3084) -> bool {
3085    if candidates.is_empty() {
3086        return false;
3087    }
3088
3089    let mut showed = false;
3090    let mut accessible_path_strings: Vec<PathString<'_>> = Vec::new();
3091    let mut inaccessible_path_strings: Vec<PathString<'_>> = Vec::new();
3092
3093    candidates.iter().for_each(|c| {
3094        if c.accessible {
3095            // Don't suggest `#[doc(hidden)]` items from other crates
3096            if c.doc_visible {
3097                accessible_path_strings.push((
3098                    pprust::path_to_string(&c.path),
3099                    c.descr,
3100                    c.did.and_then(|did| Some(tcx.source_span(did.as_local()?))),
3101                    &c.note,
3102                    c.via_import,
3103                ))
3104            }
3105        } else {
3106            inaccessible_path_strings.push((
3107                pprust::path_to_string(&c.path),
3108                c.descr,
3109                c.did.and_then(|did| Some(tcx.source_span(did.as_local()?))),
3110                &c.note,
3111                c.via_import,
3112            ))
3113        }
3114    });
3115
3116    // we want consistent results across executions, but candidates are produced
3117    // by iterating through a hash map, so make sure they are ordered:
3118    for path_strings in [&mut accessible_path_strings, &mut inaccessible_path_strings] {
3119        path_strings.sort_by(|a, b| a.0.cmp(&b.0));
3120        path_strings.dedup_by(|a, b| a.0 == b.0);
3121        let core_path_strings =
3122            path_strings.extract_if(.., |p| p.0.starts_with("core::")).collect::<Vec<_>>();
3123        let std_path_strings =
3124            path_strings.extract_if(.., |p| p.0.starts_with("std::")).collect::<Vec<_>>();
3125        let foreign_crate_path_strings =
3126            path_strings.extract_if(.., |p| !p.0.starts_with("crate::")).collect::<Vec<_>>();
3127
3128        // We list the `crate` local paths first.
3129        // Then we list the `std`/`core` paths.
3130        if std_path_strings.len() == core_path_strings.len() {
3131            // Do not list `core::` paths if we are already listing the `std::` ones.
3132            path_strings.extend(std_path_strings);
3133        } else {
3134            path_strings.extend(std_path_strings);
3135            path_strings.extend(core_path_strings);
3136        }
3137        // List all paths from foreign crates last.
3138        path_strings.extend(foreign_crate_path_strings);
3139    }
3140
3141    if !accessible_path_strings.is_empty() {
3142        let (determiner, kind, s, name, through) =
3143            if let [(name, descr, _, _, via_import)] = &accessible_path_strings[..] {
3144                (
3145                    "this",
3146                    *descr,
3147                    "",
3148                    format!(" `{name}`"),
3149                    if *via_import { " through its public re-export" } else { "" },
3150                )
3151            } else {
3152                // Get the unique item kinds and if there's only one, we use the right kind name
3153                // instead of the more generic "items".
3154                let kinds = accessible_path_strings
3155                    .iter()
3156                    .map(|(_, descr, _, _, _)| *descr)
3157                    .collect::<UnordSet<&str>>();
3158                let kind = if let Some(kind) = kinds.get_only() { kind } else { "item" };
3159                let s = if kind.ends_with('s') { "es" } else { "s" };
3160
3161                ("one of these", kind, s, String::new(), "")
3162            };
3163
3164        let instead = if let Instead::Yes = instead { " instead" } else { "" };
3165        let mut msg = if let DiagMode::Pattern = mode {
3166            format!(
3167                "if you meant to match on {kind}{s}{instead}{name}, use the full path in the \
3168                 pattern",
3169            )
3170        } else {
3171            format!("consider importing {determiner} {kind}{s}{through}{instead}")
3172        };
3173
3174        for note in accessible_path_strings.iter().flat_map(|cand| cand.3.as_ref()) {
3175            err.note(note.clone());
3176        }
3177
3178        let append_candidates = |msg: &mut String, accessible_path_strings: Vec<PathString<'_>>| {
3179            msg.push(':');
3180
3181            for candidate in accessible_path_strings {
3182                msg.push('\n');
3183                msg.push_str(&candidate.0);
3184            }
3185        };
3186
3187        if let Some(span) = use_placement_span {
3188            let (add_use, trailing) = match mode {
3189                DiagMode::Pattern => {
3190                    err.span_suggestions(
3191                        span,
3192                        msg,
3193                        accessible_path_strings.into_iter().map(|a| a.0),
3194                        Applicability::MaybeIncorrect,
3195                    );
3196                    return true;
3197                }
3198                DiagMode::Import { .. } => ("", ""),
3199                DiagMode::Normal => ("use ", ";\n"),
3200            };
3201            for candidate in &mut accessible_path_strings {
3202                // produce an additional newline to separate the new use statement
3203                // from the directly following item.
3204                let additional_newline = if let FoundUse::No = found_use
3205                    && let DiagMode::Normal = mode
3206                {
3207                    "\n"
3208                } else {
3209                    ""
3210                };
3211                candidate.0 =
3212                    format!("{add_use}{}{append}{trailing}{additional_newline}", candidate.0);
3213            }
3214
3215            match mode {
3216                DiagMode::Import { append: true, .. } => {
3217                    append_candidates(&mut msg, accessible_path_strings);
3218                    err.span_help(span, msg);
3219                }
3220                _ => {
3221                    err.span_suggestions_with_style(
3222                        span,
3223                        msg,
3224                        accessible_path_strings.into_iter().map(|a| a.0),
3225                        Applicability::MaybeIncorrect,
3226                        SuggestionStyle::ShowAlways,
3227                    );
3228                }
3229            }
3230
3231            if let [first, .., last] = &path[..] {
3232                let sp = first.ident.span.until(last.ident.span);
3233                // Our suggestion is empty, so make sure the span is not empty (or we'd ICE).
3234                // Can happen for derive-generated spans.
3235                if sp.can_be_used_for_suggestions() && !sp.is_empty() {
3236                    err.span_suggestion_verbose(
3237                        sp,
3238                        format!("if you import `{}`, refer to it directly", last.ident),
3239                        "",
3240                        Applicability::Unspecified,
3241                    );
3242                }
3243            }
3244        } else {
3245            append_candidates(&mut msg, accessible_path_strings);
3246            err.help(msg);
3247        }
3248        showed = true;
3249    }
3250    if !inaccessible_path_strings.is_empty()
3251        && (!matches!(mode, DiagMode::Import { unresolved_import: false, .. }))
3252    {
3253        let prefix =
3254            if let DiagMode::Pattern = mode { "you might have meant to match on " } else { "" };
3255        if let [(name, descr, source_span, note, _)] = &inaccessible_path_strings[..] {
3256            let msg = format!(
3257                "{prefix}{descr} `{name}`{} exists but is inaccessible",
3258                if let DiagMode::Pattern = mode { ", which" } else { "" }
3259            );
3260
3261            if let Some(source_span) = source_span {
3262                let span = tcx.sess.source_map().guess_head_span(*source_span);
3263                let mut multi_span = MultiSpan::from_span(span);
3264                multi_span.push_span_label(span, "not accessible");
3265                err.span_note(multi_span, msg);
3266            } else {
3267                err.note(msg);
3268            }
3269            if let Some(note) = (*note).as_deref() {
3270                err.note(note.to_string());
3271            }
3272        } else {
3273            let (_, descr_first, _, _, _) = &inaccessible_path_strings[0];
3274            let descr = if inaccessible_path_strings
3275                .iter()
3276                .skip(1)
3277                .all(|(_, descr, _, _, _)| descr == descr_first)
3278            {
3279                descr_first
3280            } else {
3281                "item"
3282            };
3283            let plural_descr =
3284                if descr.ends_with('s') { format!("{descr}es") } else { format!("{descr}s") };
3285
3286            let mut msg = format!("{prefix}these {plural_descr} exist but are inaccessible");
3287            let mut has_colon = false;
3288
3289            let mut spans = Vec::new();
3290            for (name, _, source_span, _, _) in &inaccessible_path_strings {
3291                if let Some(source_span) = source_span {
3292                    let span = tcx.sess.source_map().guess_head_span(*source_span);
3293                    spans.push((name, span));
3294                } else {
3295                    if !has_colon {
3296                        msg.push(':');
3297                        has_colon = true;
3298                    }
3299                    msg.push('\n');
3300                    msg.push_str(name);
3301                }
3302            }
3303
3304            let mut multi_span = MultiSpan::from_spans(spans.iter().map(|(_, sp)| *sp).collect());
3305            for (name, span) in spans {
3306                multi_span.push_span_label(span, format!("`{name}`: not accessible"));
3307            }
3308
3309            for note in inaccessible_path_strings.iter().flat_map(|cand| cand.3.as_ref()) {
3310                err.note(note.clone());
3311            }
3312
3313            err.span_note(multi_span, msg);
3314        }
3315        showed = true;
3316    }
3317    showed
3318}
3319
3320#[derive(Debug)]
3321struct UsePlacementFinder {
3322    target_module: NodeId,
3323    first_legal_span: Option<Span>,
3324    first_use_span: Option<Span>,
3325}
3326
3327impl UsePlacementFinder {
3328    fn check(krate: &Crate, target_module: NodeId) -> (Option<Span>, FoundUse) {
3329        let mut finder =
3330            UsePlacementFinder { target_module, first_legal_span: None, first_use_span: None };
3331        finder.visit_crate(krate);
3332        if let Some(use_span) = finder.first_use_span {
3333            (Some(use_span), FoundUse::Yes)
3334        } else {
3335            (finder.first_legal_span, FoundUse::No)
3336        }
3337    }
3338}
3339
3340impl<'tcx> visit::Visitor<'tcx> for UsePlacementFinder {
3341    fn visit_crate(&mut self, c: &Crate) {
3342        if self.target_module == CRATE_NODE_ID {
3343            let inject = c.spans.inject_use_span;
3344            if is_span_suitable_for_use_injection(inject) {
3345                self.first_legal_span = Some(inject);
3346            }
3347            self.first_use_span = search_for_any_use_in_items(&c.items);
3348        } else {
3349            visit::walk_crate(self, c);
3350        }
3351    }
3352
3353    fn visit_item(&mut self, item: &'tcx ast::Item) {
3354        if self.target_module == item.id {
3355            if let ItemKind::Mod(_, _, ModKind::Loaded(items, _inline, mod_spans, _)) = &item.kind {
3356                let inject = mod_spans.inject_use_span;
3357                if is_span_suitable_for_use_injection(inject) {
3358                    self.first_legal_span = Some(inject);
3359                }
3360                self.first_use_span = search_for_any_use_in_items(items);
3361            }
3362        } else {
3363            visit::walk_item(self, item);
3364        }
3365    }
3366}
3367
3368fn search_for_any_use_in_items(items: &[P<ast::Item>]) -> Option<Span> {
3369    for item in items {
3370        if let ItemKind::Use(..) = item.kind
3371            && is_span_suitable_for_use_injection(item.span)
3372        {
3373            let mut lo = item.span.lo();
3374            for attr in &item.attrs {
3375                if attr.span.eq_ctxt(item.span) {
3376                    lo = std::cmp::min(lo, attr.span.lo());
3377                }
3378            }
3379            return Some(Span::new(lo, lo, item.span.ctxt(), item.span.parent()));
3380        }
3381    }
3382    None
3383}
3384
3385fn is_span_suitable_for_use_injection(s: Span) -> bool {
3386    // don't suggest placing a use before the prelude
3387    // import or other generated ones
3388    !s.from_expansion()
3389}