rustc_resolve/
diagnostics.rs

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