rustc_resolve/
diagnostics.rs

1use rustc_ast::expand::StrippedCfgItem;
2use rustc_ast::ptr::P;
3use rustc_ast::visit::{self, Visitor};
4use rustc_ast::{
5    self as ast, CRATE_NODE_ID, Crate, ItemKind, MetaItemInner, MetaItemKind, ModKind, NodeId, Path,
6};
7use rustc_ast_pretty::pprust;
8use rustc_data_structures::fx::FxHashSet;
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::PrimTy;
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_middle::bug;
20use rustc_middle::ty::TyCtxt;
21use rustc_session::Session;
22use rustc_session::lint::builtin::{
23    ABSOLUTE_PATHS_NOT_STARTING_WITH_CRATE, AMBIGUOUS_GLOB_IMPORTS,
24    MACRO_EXPANDED_MACRO_EXPORTS_ACCESSED_BY_ABSOLUTE_PATHS,
25};
26use rustc_session::lint::{AmbiguityErrorDiag, BuiltinLintDiag};
27use rustc_session::utils::was_invoked_from_cargo;
28use rustc_span::edit_distance::find_best_match_for_name;
29use rustc_span::edition::Edition;
30use rustc_span::hygiene::MacroKind;
31use rustc_span::source_map::SourceMap;
32use rustc_span::{BytePos, Ident, Span, Symbol, SyntaxContext, kw, sym};
33use thin_vec::{ThinVec, thin_vec};
34use tracing::{debug, instrument};
35
36use crate::errors::{
37    self, AddedMacroUse, ChangeImportBinding, ChangeImportBindingSuggestion, ConsiderAddingADerive,
38    ExplicitUnsafeTraits, MacroDefinedLater, MacroRulesNot, MacroSuggMovePosition,
39    MaybeMissingMacroRulesName,
40};
41use crate::imports::{Import, ImportKind};
42use crate::late::{PatternSource, Rib};
43use crate::{
44    AmbiguityError, AmbiguityErrorMisc, AmbiguityKind, BindingError, BindingKey, Finalize,
45    HasGenericParams, LexicalScopeBinding, MacroRulesScope, Module, ModuleKind,
46    ModuleOrUniformRoot, NameBinding, NameBindingKind, ParentScope, PathResult, PrivacyError,
47    ResolutionError, Resolver, Scope, ScopeSet, Segment, UseError, Used, VisResolutionError,
48    errors as errs, path_names_to_string,
49};
50
51type Res = def::Res<ast::NodeId>;
52
53/// A vector of spans and replacements, a message and applicability.
54pub(crate) type Suggestion = (Vec<(Span, String)>, String, Applicability);
55
56/// Potential candidate for an undeclared or out-of-scope label - contains the ident of a
57/// similarly named label and whether or not it is reachable.
58pub(crate) type LabelSuggestion = (Ident, bool);
59
60#[derive(Debug)]
61pub(crate) enum SuggestionTarget {
62    /// The target has a similar name as the name used by the programmer (probably a typo)
63    SimilarlyNamed,
64    /// The target is the only valid item that can be used in the corresponding context
65    SingleItem,
66}
67
68#[derive(Debug)]
69pub(crate) struct TypoSuggestion {
70    pub candidate: Symbol,
71    /// The source location where the name is defined; None if the name is not defined
72    /// in source e.g. primitives
73    pub span: Option<Span>,
74    pub res: Res,
75    pub target: SuggestionTarget,
76}
77
78impl TypoSuggestion {
79    pub(crate) fn typo_from_ident(ident: Ident, res: Res) -> TypoSuggestion {
80        Self {
81            candidate: ident.name,
82            span: Some(ident.span),
83            res,
84            target: SuggestionTarget::SimilarlyNamed,
85        }
86    }
87    pub(crate) fn typo_from_name(candidate: Symbol, res: Res) -> TypoSuggestion {
88        Self { candidate, span: None, res, target: SuggestionTarget::SimilarlyNamed }
89    }
90    pub(crate) fn single_item_from_ident(ident: Ident, res: Res) -> TypoSuggestion {
91        Self {
92            candidate: ident.name,
93            span: Some(ident.span),
94            res,
95            target: SuggestionTarget::SingleItem,
96        }
97    }
98}
99
100/// A free importable items suggested in case of resolution failure.
101#[derive(Debug, Clone)]
102pub(crate) struct ImportSuggestion {
103    pub did: Option<DefId>,
104    pub descr: &'static str,
105    pub path: Path,
106    pub accessible: bool,
107    // false if the path traverses a foreign `#[doc(hidden)]` item.
108    pub doc_visible: bool,
109    pub via_import: bool,
110    /// An extra note that should be issued if this item is suggested
111    pub note: Option<String>,
112}
113
114/// Adjust the impl span so that just the `impl` keyword is taken by removing
115/// everything after `<` (`"impl<T> Iterator for A<T> {}" -> "impl"`) and
116/// everything after the first whitespace (`"impl Iterator for A" -> "impl"`).
117///
118/// *Attention*: the method used is very fragile since it essentially duplicates the work of the
119/// parser. If you need to use this function or something similar, please consider updating the
120/// `source_map` functions and this function to something more robust.
121fn reduce_impl_span_to_impl_keyword(sm: &SourceMap, impl_span: Span) -> Span {
122    let impl_span = sm.span_until_char(impl_span, '<');
123    sm.span_until_whitespace(impl_span)
124}
125
126impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
127    pub(crate) fn dcx(&self) -> DiagCtxtHandle<'tcx> {
128        self.tcx.dcx()
129    }
130
131    pub(crate) fn report_errors(&mut self, krate: &Crate) {
132        self.report_with_use_injections(krate);
133
134        for &(span_use, span_def) in &self.macro_expanded_macro_export_errors {
135            self.lint_buffer.buffer_lint(
136                MACRO_EXPANDED_MACRO_EXPORTS_ACCESSED_BY_ABSOLUTE_PATHS,
137                CRATE_NODE_ID,
138                span_use,
139                BuiltinLintDiag::MacroExpandedMacroExportsAccessedByAbsolutePaths(span_def),
140            );
141        }
142
143        for ambiguity_error in &self.ambiguity_errors {
144            let diag = self.ambiguity_diagnostics(ambiguity_error);
145            if ambiguity_error.warning {
146                let NameBindingKind::Import { import, .. } = ambiguity_error.b1.0.kind else {
147                    unreachable!()
148                };
149                self.lint_buffer.buffer_lint(
150                    AMBIGUOUS_GLOB_IMPORTS,
151                    import.root_id,
152                    ambiguity_error.ident.span,
153                    BuiltinLintDiag::AmbiguousGlobImports { diag },
154                );
155            } else {
156                let mut err = struct_span_code_err!(self.dcx(), diag.span, E0659, "{}", diag.msg);
157                report_ambiguity_error(&mut err, diag);
158                err.emit();
159            }
160        }
161
162        let mut reported_spans = FxHashSet::default();
163        for error in std::mem::take(&mut self.privacy_errors) {
164            if reported_spans.insert(error.dedup_span) {
165                self.report_privacy_error(&error);
166            }
167        }
168    }
169
170    fn report_with_use_injections(&mut self, krate: &Crate) {
171        for UseError { mut err, candidates, def_id, instead, suggestion, path, is_call } in
172            self.use_injections.drain(..)
173        {
174            let (span, found_use) = if let Some(def_id) = def_id.as_local() {
175                UsePlacementFinder::check(krate, self.def_id_to_node_id[def_id])
176            } else {
177                (None, FoundUse::No)
178            };
179
180            if !candidates.is_empty() {
181                show_candidates(
182                    self.tcx,
183                    &mut err,
184                    span,
185                    &candidates,
186                    if instead { Instead::Yes } else { Instead::No },
187                    found_use,
188                    DiagMode::Normal,
189                    path,
190                    "",
191                );
192                err.emit();
193            } else if let Some((span, msg, sugg, appl)) = suggestion {
194                err.span_suggestion_verbose(span, msg, sugg, appl);
195                err.emit();
196            } else if let [segment] = path.as_slice()
197                && is_call
198            {
199                err.stash(segment.ident.span, rustc_errors::StashKey::CallIntoMethod);
200            } else {
201                err.emit();
202            }
203        }
204    }
205
206    pub(crate) fn report_conflict(
207        &mut self,
208        parent: Module<'_>,
209        ident: Ident,
210        ns: Namespace,
211        new_binding: NameBinding<'ra>,
212        old_binding: NameBinding<'ra>,
213    ) {
214        // Error on the second of two conflicting names
215        if old_binding.span.lo() > new_binding.span.lo() {
216            return self.report_conflict(parent, ident, ns, old_binding, new_binding);
217        }
218
219        let container = match parent.kind {
220            // Avoid using TyCtxt::def_kind_descr in the resolver, because it
221            // indirectly *calls* the resolver, and would cause a query cycle.
222            ModuleKind::Def(kind, _, _) => kind.descr(parent.def_id()),
223            ModuleKind::Block => "block",
224        };
225
226        let (name, span) =
227            (ident.name, self.tcx.sess.source_map().guess_head_span(new_binding.span));
228
229        if self.name_already_seen.get(&name) == Some(&span) {
230            return;
231        }
232
233        let old_kind = match (ns, old_binding.module()) {
234            (ValueNS, _) => "value",
235            (MacroNS, _) => "macro",
236            (TypeNS, _) if old_binding.is_extern_crate() => "extern crate",
237            (TypeNS, Some(module)) if module.is_normal() => "module",
238            (TypeNS, Some(module)) if module.is_trait() => "trait",
239            (TypeNS, _) => "type",
240        };
241
242        let code = match (old_binding.is_extern_crate(), new_binding.is_extern_crate()) {
243            (true, true) => E0259,
244            (true, _) | (_, true) => match new_binding.is_import() && old_binding.is_import() {
245                true => E0254,
246                false => E0260,
247            },
248            _ => match (old_binding.is_import_user_facing(), new_binding.is_import_user_facing()) {
249                (false, false) => E0428,
250                (true, true) => E0252,
251                _ => E0255,
252            },
253        };
254
255        let label = match new_binding.is_import_user_facing() {
256            true => errors::NameDefinedMultipleTimeLabel::Reimported { span, name },
257            false => errors::NameDefinedMultipleTimeLabel::Redefined { span, name },
258        };
259
260        let old_binding_label =
261            (!old_binding.span.is_dummy() && old_binding.span != span).then(|| {
262                let span = self.tcx.sess.source_map().guess_head_span(old_binding.span);
263                match old_binding.is_import_user_facing() {
264                    true => errors::NameDefinedMultipleTimeOldBindingLabel::Import {
265                        span,
266                        name,
267                        old_kind,
268                    },
269                    false => errors::NameDefinedMultipleTimeOldBindingLabel::Definition {
270                        span,
271                        name,
272                        old_kind,
273                    },
274                }
275            });
276
277        let mut err = self
278            .dcx()
279            .create_err(errors::NameDefinedMultipleTime {
280                span,
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        &mut 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                if let Some(ModuleOrUniformRoot::Module(module)) = module
805                    && let Some(module) = module.opt_def_id()
806                    && let Some(segment) = segment
807                {
808                    self.find_cfg_stripped(&mut err, &segment, module);
809                }
810
811                err
812            }
813            ResolutionError::CannotCaptureDynamicEnvironmentInFnItem => {
814                self.dcx().create_err(errs::CannotCaptureDynamicEnvironmentInFnItem { span })
815            }
816            ResolutionError::AttemptToUseNonConstantValueInConstant {
817                ident,
818                suggestion,
819                current,
820                type_span,
821            } => {
822                // let foo =...
823                //     ^^^ given this Span
824                // ------- get this Span to have an applicable suggestion
825
826                // edit:
827                // only do this if the const and usage of the non-constant value are on the same line
828                // the further the two are apart, the higher the chance of the suggestion being wrong
829
830                let sp = self
831                    .tcx
832                    .sess
833                    .source_map()
834                    .span_extend_to_prev_str(ident.span, current, true, false);
835
836                let ((with, with_label), without) = match sp {
837                    Some(sp) if !self.tcx.sess.source_map().is_multiline(sp) => {
838                        let sp = sp
839                            .with_lo(BytePos(sp.lo().0 - (current.len() as u32)))
840                            .until(ident.span);
841                        (
842                        (Some(errs::AttemptToUseNonConstantValueInConstantWithSuggestion {
843                                span: sp,
844                                suggestion,
845                                current,
846                                type_span,
847                            }), Some(errs::AttemptToUseNonConstantValueInConstantLabelWithSuggestion {span})),
848                            None,
849                        )
850                    }
851                    _ => (
852                        (None, None),
853                        Some(errs::AttemptToUseNonConstantValueInConstantWithoutSuggestion {
854                            ident_span: ident.span,
855                            suggestion,
856                        }),
857                    ),
858                };
859
860                self.dcx().create_err(errs::AttemptToUseNonConstantValueInConstant {
861                    span,
862                    with,
863                    with_label,
864                    without,
865                })
866            }
867            ResolutionError::BindingShadowsSomethingUnacceptable {
868                shadowing_binding,
869                name,
870                participle,
871                article,
872                shadowed_binding,
873                shadowed_binding_span,
874            } => self.dcx().create_err(errs::BindingShadowsSomethingUnacceptable {
875                span,
876                shadowing_binding,
877                shadowed_binding,
878                article,
879                sub_suggestion: match (shadowing_binding, shadowed_binding) {
880                    (
881                        PatternSource::Match,
882                        Res::Def(DefKind::Ctor(CtorOf::Variant | CtorOf::Struct, CtorKind::Fn), _),
883                    ) => Some(errs::BindingShadowsSomethingUnacceptableSuggestion { span, name }),
884                    _ => None,
885                },
886                shadowed_binding_span,
887                participle,
888                name,
889            }),
890            ResolutionError::ForwardDeclaredGenericParam => {
891                self.dcx().create_err(errs::ForwardDeclaredGenericParam { span })
892            }
893            ResolutionError::ParamInTyOfConstParam { name, param_kind: is_type } => self
894                .dcx()
895                .create_err(errs::ParamInTyOfConstParam { span, name, param_kind: is_type }),
896            ResolutionError::ParamInNonTrivialAnonConst { name, param_kind: is_type } => {
897                self.dcx().create_err(errs::ParamInNonTrivialAnonConst {
898                    span,
899                    name,
900                    param_kind: is_type,
901                    help: self
902                        .tcx
903                        .sess
904                        .is_nightly_build()
905                        .then_some(errs::ParamInNonTrivialAnonConstHelp),
906                })
907            }
908            ResolutionError::ParamInEnumDiscriminant { name, param_kind: is_type } => self
909                .dcx()
910                .create_err(errs::ParamInEnumDiscriminant { span, name, param_kind: is_type }),
911            ResolutionError::SelfInGenericParamDefault => {
912                self.dcx().create_err(errs::SelfInGenericParamDefault { span })
913            }
914            ResolutionError::UnreachableLabel { name, definition_span, suggestion } => {
915                let ((sub_suggestion_label, sub_suggestion), sub_unreachable_label) =
916                    match suggestion {
917                        // A reachable label with a similar name exists.
918                        Some((ident, true)) => (
919                            (
920                                Some(errs::UnreachableLabelSubLabel { ident_span: ident.span }),
921                                Some(errs::UnreachableLabelSubSuggestion {
922                                    span,
923                                    // intentionally taking 'ident.name' instead of 'ident' itself, as this
924                                    // could be used in suggestion context
925                                    ident_name: ident.name,
926                                }),
927                            ),
928                            None,
929                        ),
930                        // An unreachable label with a similar name exists.
931                        Some((ident, false)) => (
932                            (None, None),
933                            Some(errs::UnreachableLabelSubLabelUnreachable {
934                                ident_span: ident.span,
935                            }),
936                        ),
937                        // No similarly-named labels exist.
938                        None => ((None, None), None),
939                    };
940                self.dcx().create_err(errs::UnreachableLabel {
941                    span,
942                    name,
943                    definition_span,
944                    sub_suggestion,
945                    sub_suggestion_label,
946                    sub_unreachable_label,
947                })
948            }
949            ResolutionError::TraitImplMismatch {
950                name,
951                kind,
952                code,
953                trait_item_span,
954                trait_path,
955            } => self
956                .dcx()
957                .create_err(errors::TraitImplMismatch {
958                    span,
959                    name,
960                    kind,
961                    trait_path,
962                    trait_item_span,
963                })
964                .with_code(code),
965            ResolutionError::TraitImplDuplicate { name, trait_item_span, old_span } => self
966                .dcx()
967                .create_err(errs::TraitImplDuplicate { span, name, trait_item_span, old_span }),
968            ResolutionError::InvalidAsmSym => self.dcx().create_err(errs::InvalidAsmSym { span }),
969            ResolutionError::LowercaseSelf => self.dcx().create_err(errs::LowercaseSelf { span }),
970            ResolutionError::BindingInNeverPattern => {
971                self.dcx().create_err(errs::BindingInNeverPattern { span })
972            }
973        }
974    }
975
976    pub(crate) fn report_vis_error(
977        &mut self,
978        vis_resolution_error: VisResolutionError<'_>,
979    ) -> ErrorGuaranteed {
980        match vis_resolution_error {
981            VisResolutionError::Relative2018(span, path) => {
982                self.dcx().create_err(errs::Relative2018 {
983                    span,
984                    path_span: path.span,
985                    // intentionally converting to String, as the text would also be used as
986                    // in suggestion context
987                    path_str: pprust::path_to_string(path),
988                })
989            }
990            VisResolutionError::AncestorOnly(span) => {
991                self.dcx().create_err(errs::AncestorOnly(span))
992            }
993            VisResolutionError::FailedToResolve(span, label, suggestion) => self.into_struct_error(
994                span,
995                ResolutionError::FailedToResolve { segment: None, label, suggestion, module: None },
996            ),
997            VisResolutionError::ExpectedFound(span, path_str, res) => {
998                self.dcx().create_err(errs::ExpectedModuleFound { span, res, path_str })
999            }
1000            VisResolutionError::Indeterminate(span) => {
1001                self.dcx().create_err(errs::Indeterminate(span))
1002            }
1003            VisResolutionError::ModuleOnly(span) => self.dcx().create_err(errs::ModuleOnly(span)),
1004        }
1005        .emit()
1006    }
1007
1008    /// Lookup typo candidate in scope for a macro or import.
1009    fn early_lookup_typo_candidate(
1010        &mut self,
1011        scope_set: ScopeSet<'ra>,
1012        parent_scope: &ParentScope<'ra>,
1013        ident: Ident,
1014        filter_fn: &impl Fn(Res) -> bool,
1015    ) -> Option<TypoSuggestion> {
1016        let mut suggestions = Vec::new();
1017        let ctxt = ident.span.ctxt();
1018        self.visit_scopes(scope_set, parent_scope, ctxt, |this, scope, use_prelude, _| {
1019            match scope {
1020                Scope::DeriveHelpers(expn_id) => {
1021                    let res = Res::NonMacroAttr(NonMacroAttrKind::DeriveHelper);
1022                    if filter_fn(res) {
1023                        suggestions.extend(
1024                            this.helper_attrs
1025                                .get(&expn_id)
1026                                .into_iter()
1027                                .flatten()
1028                                .map(|(ident, _)| TypoSuggestion::typo_from_ident(*ident, res)),
1029                        );
1030                    }
1031                }
1032                Scope::DeriveHelpersCompat => {
1033                    let res = Res::NonMacroAttr(NonMacroAttrKind::DeriveHelperCompat);
1034                    if filter_fn(res) {
1035                        for derive in parent_scope.derives {
1036                            let parent_scope = &ParentScope { derives: &[], ..*parent_scope };
1037                            let Ok((Some(ext), _)) = this.resolve_macro_path(
1038                                derive,
1039                                Some(MacroKind::Derive),
1040                                parent_scope,
1041                                false,
1042                                false,
1043                                None,
1044                            ) else {
1045                                continue;
1046                            };
1047                            suggestions.extend(
1048                                ext.helper_attrs
1049                                    .iter()
1050                                    .map(|name| TypoSuggestion::typo_from_name(*name, res)),
1051                            );
1052                        }
1053                    }
1054                }
1055                Scope::MacroRules(macro_rules_scope) => {
1056                    if let MacroRulesScope::Binding(macro_rules_binding) = macro_rules_scope.get() {
1057                        let res = macro_rules_binding.binding.res();
1058                        if filter_fn(res) {
1059                            suggestions.push(TypoSuggestion::typo_from_ident(
1060                                macro_rules_binding.ident,
1061                                res,
1062                            ))
1063                        }
1064                    }
1065                }
1066                Scope::CrateRoot => {
1067                    let root_ident = Ident::new(kw::PathRoot, ident.span);
1068                    let root_module = this.resolve_crate_root(root_ident);
1069                    this.add_module_candidates(root_module, &mut suggestions, filter_fn, None);
1070                }
1071                Scope::Module(module, _) => {
1072                    this.add_module_candidates(module, &mut suggestions, filter_fn, None);
1073                }
1074                Scope::MacroUsePrelude => {
1075                    suggestions.extend(this.macro_use_prelude.iter().filter_map(
1076                        |(name, binding)| {
1077                            let res = binding.res();
1078                            filter_fn(res).then_some(TypoSuggestion::typo_from_name(*name, res))
1079                        },
1080                    ));
1081                }
1082                Scope::BuiltinAttrs => {
1083                    let res = Res::NonMacroAttr(NonMacroAttrKind::Builtin(kw::Empty));
1084                    if filter_fn(res) {
1085                        suggestions.extend(
1086                            BUILTIN_ATTRIBUTES
1087                                .iter()
1088                                .map(|attr| TypoSuggestion::typo_from_name(attr.name, res)),
1089                        );
1090                    }
1091                }
1092                Scope::ExternPrelude => {
1093                    suggestions.extend(this.extern_prelude.iter().filter_map(|(ident, _)| {
1094                        let res = Res::Def(DefKind::Mod, CRATE_DEF_ID.to_def_id());
1095                        filter_fn(res).then_some(TypoSuggestion::typo_from_ident(*ident, res))
1096                    }));
1097                }
1098                Scope::ToolPrelude => {
1099                    let res = Res::NonMacroAttr(NonMacroAttrKind::Tool);
1100                    suggestions.extend(
1101                        this.registered_tools
1102                            .iter()
1103                            .map(|ident| TypoSuggestion::typo_from_ident(*ident, res)),
1104                    );
1105                }
1106                Scope::StdLibPrelude => {
1107                    if let Some(prelude) = this.prelude {
1108                        let mut tmp_suggestions = Vec::new();
1109                        this.add_module_candidates(prelude, &mut tmp_suggestions, filter_fn, None);
1110                        suggestions.extend(
1111                            tmp_suggestions
1112                                .into_iter()
1113                                .filter(|s| use_prelude.into() || this.is_builtin_macro(s.res)),
1114                        );
1115                    }
1116                }
1117                Scope::BuiltinTypes => {
1118                    suggestions.extend(PrimTy::ALL.iter().filter_map(|prim_ty| {
1119                        let res = Res::PrimTy(*prim_ty);
1120                        filter_fn(res)
1121                            .then_some(TypoSuggestion::typo_from_name(prim_ty.name(), res))
1122                    }))
1123                }
1124            }
1125
1126            None::<()>
1127        });
1128
1129        // Make sure error reporting is deterministic.
1130        suggestions.sort_by(|a, b| a.candidate.as_str().cmp(b.candidate.as_str()));
1131
1132        match find_best_match_for_name(
1133            &suggestions.iter().map(|suggestion| suggestion.candidate).collect::<Vec<Symbol>>(),
1134            ident.name,
1135            None,
1136        ) {
1137            Some(found) if found != ident.name => {
1138                suggestions.into_iter().find(|suggestion| suggestion.candidate == found)
1139            }
1140            _ => None,
1141        }
1142    }
1143
1144    fn lookup_import_candidates_from_module<FilterFn>(
1145        &mut self,
1146        lookup_ident: Ident,
1147        namespace: Namespace,
1148        parent_scope: &ParentScope<'ra>,
1149        start_module: Module<'ra>,
1150        crate_path: ThinVec<ast::PathSegment>,
1151        filter_fn: FilterFn,
1152    ) -> Vec<ImportSuggestion>
1153    where
1154        FilterFn: Fn(Res) -> bool,
1155    {
1156        let mut candidates = Vec::new();
1157        let mut seen_modules = FxHashSet::default();
1158        let start_did = start_module.def_id();
1159        let mut worklist = vec![(
1160            start_module,
1161            ThinVec::<ast::PathSegment>::new(),
1162            true,
1163            start_did.is_local() || !self.tcx.is_doc_hidden(start_did),
1164        )];
1165        let mut worklist_via_import = vec![];
1166
1167        while let Some((in_module, path_segments, accessible, doc_visible)) = match worklist.pop() {
1168            None => worklist_via_import.pop(),
1169            Some(x) => Some(x),
1170        } {
1171            let in_module_is_extern = !in_module.def_id().is_local();
1172            in_module.for_each_child(self, |this, ident, ns, name_binding| {
1173                // avoid non-importable candidates
1174                if !name_binding.is_importable()
1175                    // FIXME(import_trait_associated_functions): remove this when `import_trait_associated_functions` is stable
1176                    || name_binding.is_assoc_const_or_fn()
1177                        && !this.tcx.features().import_trait_associated_functions()
1178                {
1179                    return;
1180                }
1181
1182                if ident.name == kw::Underscore {
1183                    return;
1184                }
1185
1186                let child_accessible =
1187                    accessible && this.is_accessible_from(name_binding.vis, parent_scope.module);
1188
1189                // do not venture inside inaccessible items of other crates
1190                if in_module_is_extern && !child_accessible {
1191                    return;
1192                }
1193
1194                let via_import = name_binding.is_import() && !name_binding.is_extern_crate();
1195
1196                // There is an assumption elsewhere that paths of variants are in the enum's
1197                // declaration and not imported. With this assumption, the variant component is
1198                // chopped and the rest of the path is assumed to be the enum's own path. For
1199                // errors where a variant is used as the type instead of the enum, this causes
1200                // funny looking invalid suggestions, i.e `foo` instead of `foo::MyEnum`.
1201                if via_import && name_binding.is_possibly_imported_variant() {
1202                    return;
1203                }
1204
1205                // #90113: Do not count an inaccessible reexported item as a candidate.
1206                if let NameBindingKind::Import { binding, .. } = name_binding.kind
1207                    && this.is_accessible_from(binding.vis, parent_scope.module)
1208                    && !this.is_accessible_from(name_binding.vis, parent_scope.module)
1209                {
1210                    return;
1211                }
1212
1213                let res = name_binding.res();
1214                let did = match res {
1215                    Res::Def(DefKind::Ctor(..), did) => this.tcx.opt_parent(did),
1216                    _ => res.opt_def_id(),
1217                };
1218                let child_doc_visible = doc_visible
1219                    && did.is_none_or(|did| did.is_local() || !this.tcx.is_doc_hidden(did));
1220
1221                // collect results based on the filter function
1222                // avoid suggesting anything from the same module in which we are resolving
1223                // avoid suggesting anything with a hygienic name
1224                if ident.name == lookup_ident.name
1225                    && ns == namespace
1226                    && in_module != parent_scope.module
1227                    && !ident.span.normalize_to_macros_2_0().from_expansion()
1228                    && filter_fn(res)
1229                {
1230                    // create the path
1231                    let mut segms = if lookup_ident.span.at_least_rust_2018() {
1232                        // crate-local absolute paths start with `crate::` in edition 2018
1233                        // FIXME: may also be stabilized for Rust 2015 (Issues #45477, #44660)
1234                        crate_path.clone()
1235                    } else {
1236                        ThinVec::new()
1237                    };
1238                    segms.append(&mut path_segments.clone());
1239
1240                    segms.push(ast::PathSegment::from_ident(ident));
1241                    let path = Path { span: name_binding.span, segments: segms, tokens: None };
1242
1243                    if child_accessible
1244                        // Remove invisible match if exists
1245                        && let Some(idx) = candidates
1246                            .iter()
1247                            .position(|v: &ImportSuggestion| v.did == did && !v.accessible)
1248                    {
1249                        candidates.remove(idx);
1250                    }
1251
1252                    if candidates.iter().all(|v: &ImportSuggestion| v.did != did) {
1253                        // See if we're recommending TryFrom, TryInto, or FromIterator and add
1254                        // a note about editions
1255                        let note = if let Some(did) = did {
1256                            let requires_note = !did.is_local()
1257                                && this.tcx.get_attrs(did, sym::rustc_diagnostic_item).any(
1258                                    |attr| {
1259                                        [sym::TryInto, sym::TryFrom, sym::FromIterator]
1260                                            .map(|x| Some(x))
1261                                            .contains(&attr.value_str())
1262                                    },
1263                                );
1264
1265                            requires_note.then(|| {
1266                                format!(
1267                                    "'{}' is included in the prelude starting in Edition 2021",
1268                                    path_names_to_string(&path)
1269                                )
1270                            })
1271                        } else {
1272                            None
1273                        };
1274
1275                        candidates.push(ImportSuggestion {
1276                            did,
1277                            descr: res.descr(),
1278                            path,
1279                            accessible: child_accessible,
1280                            doc_visible: child_doc_visible,
1281                            note,
1282                            via_import,
1283                        });
1284                    }
1285                }
1286
1287                // collect submodules to explore
1288                if let Some(module) = name_binding.module() {
1289                    // form the path
1290                    let mut path_segments = path_segments.clone();
1291                    path_segments.push(ast::PathSegment::from_ident(ident));
1292
1293                    let alias_import = if let NameBindingKind::Import { import, .. } =
1294                        name_binding.kind
1295                        && let ImportKind::ExternCrate { source: Some(_), .. } = import.kind
1296                        && import.parent_scope.expansion == parent_scope.expansion
1297                    {
1298                        true
1299                    } else {
1300                        false
1301                    };
1302
1303                    let is_extern_crate_that_also_appears_in_prelude =
1304                        name_binding.is_extern_crate() && lookup_ident.span.at_least_rust_2018();
1305
1306                    if !is_extern_crate_that_also_appears_in_prelude || alias_import {
1307                        // add the module to the lookup
1308                        if seen_modules.insert(module.def_id()) {
1309                            if via_import { &mut worklist_via_import } else { &mut worklist }
1310                                .push((module, path_segments, child_accessible, child_doc_visible));
1311                        }
1312                    }
1313                }
1314            })
1315        }
1316
1317        // If only some candidates are accessible, take just them
1318        if !candidates.iter().all(|v: &ImportSuggestion| !v.accessible) {
1319            candidates.retain(|x| x.accessible)
1320        }
1321
1322        candidates
1323    }
1324
1325    /// When name resolution fails, this method can be used to look up candidate
1326    /// entities with the expected name. It allows filtering them using the
1327    /// supplied predicate (which should be used to only accept the types of
1328    /// definitions expected, e.g., traits). The lookup spans across all crates.
1329    ///
1330    /// N.B., the method does not look into imports, but this is not a problem,
1331    /// since we report the definitions (thus, the de-aliased imports).
1332    pub(crate) fn lookup_import_candidates<FilterFn>(
1333        &mut self,
1334        lookup_ident: Ident,
1335        namespace: Namespace,
1336        parent_scope: &ParentScope<'ra>,
1337        filter_fn: FilterFn,
1338    ) -> Vec<ImportSuggestion>
1339    where
1340        FilterFn: Fn(Res) -> bool,
1341    {
1342        let crate_path = thin_vec![ast::PathSegment::from_ident(Ident::with_dummy_span(kw::Crate))];
1343        let mut suggestions = self.lookup_import_candidates_from_module(
1344            lookup_ident,
1345            namespace,
1346            parent_scope,
1347            self.graph_root,
1348            crate_path,
1349            &filter_fn,
1350        );
1351
1352        if lookup_ident.span.at_least_rust_2018() {
1353            for ident in self.extern_prelude.clone().into_keys() {
1354                if ident.span.from_expansion() {
1355                    // Idents are adjusted to the root context before being
1356                    // resolved in the extern prelude, so reporting this to the
1357                    // user is no help. This skips the injected
1358                    // `extern crate std` in the 2018 edition, which would
1359                    // otherwise cause duplicate suggestions.
1360                    continue;
1361                }
1362                let Some(crate_id) = self.crate_loader(|c| c.maybe_process_path_extern(ident.name))
1363                else {
1364                    continue;
1365                };
1366
1367                let crate_def_id = crate_id.as_def_id();
1368                let crate_root = self.expect_module(crate_def_id);
1369
1370                // Check if there's already an item in scope with the same name as the crate.
1371                // If so, we have to disambiguate the potential import suggestions by making
1372                // the paths *global* (i.e., by prefixing them with `::`).
1373                let needs_disambiguation =
1374                    self.resolutions(parent_scope.module).borrow().iter().any(
1375                        |(key, name_resolution)| {
1376                            if key.ns == TypeNS
1377                                && key.ident == ident
1378                                && let Some(binding) = name_resolution.borrow().binding
1379                            {
1380                                match binding.res() {
1381                                    // No disambiguation needed if the identically named item we
1382                                    // found in scope actually refers to the crate in question.
1383                                    Res::Def(_, def_id) => def_id != crate_def_id,
1384                                    Res::PrimTy(_) => true,
1385                                    _ => false,
1386                                }
1387                            } else {
1388                                false
1389                            }
1390                        },
1391                    );
1392                let mut crate_path = ThinVec::new();
1393                if needs_disambiguation {
1394                    crate_path.push(ast::PathSegment::path_root(rustc_span::DUMMY_SP));
1395                }
1396                crate_path.push(ast::PathSegment::from_ident(ident));
1397
1398                suggestions.extend(self.lookup_import_candidates_from_module(
1399                    lookup_ident,
1400                    namespace,
1401                    parent_scope,
1402                    crate_root,
1403                    crate_path,
1404                    &filter_fn,
1405                ));
1406            }
1407        }
1408
1409        suggestions
1410    }
1411
1412    pub(crate) fn unresolved_macro_suggestions(
1413        &mut self,
1414        err: &mut Diag<'_>,
1415        macro_kind: MacroKind,
1416        parent_scope: &ParentScope<'ra>,
1417        ident: Ident,
1418        krate: &Crate,
1419    ) {
1420        let is_expected = &|res: Res| res.macro_kind() == Some(macro_kind);
1421        let suggestion = self.early_lookup_typo_candidate(
1422            ScopeSet::Macro(macro_kind),
1423            parent_scope,
1424            ident,
1425            is_expected,
1426        );
1427        self.add_typo_suggestion(err, suggestion, ident.span);
1428
1429        let import_suggestions =
1430            self.lookup_import_candidates(ident, Namespace::MacroNS, parent_scope, is_expected);
1431        let (span, found_use) = match parent_scope.module.nearest_parent_mod().as_local() {
1432            Some(def_id) => UsePlacementFinder::check(krate, self.def_id_to_node_id[def_id]),
1433            None => (None, FoundUse::No),
1434        };
1435        show_candidates(
1436            self.tcx,
1437            err,
1438            span,
1439            &import_suggestions,
1440            Instead::No,
1441            found_use,
1442            DiagMode::Normal,
1443            vec![],
1444            "",
1445        );
1446
1447        if macro_kind == MacroKind::Bang && ident.name == sym::macro_rules {
1448            let label_span = ident.span.shrink_to_hi();
1449            let mut spans = MultiSpan::from_span(label_span);
1450            spans.push_span_label(label_span, "put a macro name here");
1451            err.subdiagnostic(MaybeMissingMacroRulesName { spans });
1452            return;
1453        }
1454
1455        if macro_kind == MacroKind::Derive && (ident.name == sym::Send || ident.name == sym::Sync) {
1456            err.subdiagnostic(ExplicitUnsafeTraits { span: ident.span, ident });
1457            return;
1458        }
1459
1460        let unused_macro = self.unused_macros.iter().find_map(|(def_id, (_, unused_ident))| {
1461            if unused_ident.name == ident.name { Some((def_id, unused_ident)) } else { None }
1462        });
1463
1464        if let Some((def_id, unused_ident)) = unused_macro {
1465            let scope = self.local_macro_def_scopes[&def_id];
1466            let parent_nearest = parent_scope.module.nearest_parent_mod();
1467            if Some(parent_nearest) == scope.opt_def_id() {
1468                match macro_kind {
1469                    MacroKind::Bang => {
1470                        err.subdiagnostic(MacroDefinedLater { span: unused_ident.span });
1471                        err.subdiagnostic(MacroSuggMovePosition { span: ident.span, ident });
1472                    }
1473                    MacroKind::Attr => {
1474                        err.subdiagnostic(MacroRulesNot::Attr { span: unused_ident.span, ident });
1475                    }
1476                    MacroKind::Derive => {
1477                        err.subdiagnostic(MacroRulesNot::Derive { span: unused_ident.span, ident });
1478                    }
1479                }
1480
1481                return;
1482            }
1483        }
1484
1485        if self.macro_names.contains(&ident.normalize_to_macros_2_0()) {
1486            err.subdiagnostic(AddedMacroUse);
1487            return;
1488        }
1489
1490        if ident.name == kw::Default
1491            && let ModuleKind::Def(DefKind::Enum, def_id, _) = parent_scope.module.kind
1492        {
1493            let span = self.def_span(def_id);
1494            let source_map = self.tcx.sess.source_map();
1495            let head_span = source_map.guess_head_span(span);
1496            err.subdiagnostic(ConsiderAddingADerive {
1497                span: head_span.shrink_to_lo(),
1498                suggestion: "#[derive(Default)]\n".to_string(),
1499            });
1500        }
1501        for ns in [Namespace::MacroNS, Namespace::TypeNS, Namespace::ValueNS] {
1502            let Ok(binding) = self.early_resolve_ident_in_lexical_scope(
1503                ident,
1504                ScopeSet::All(ns),
1505                parent_scope,
1506                None,
1507                false,
1508                None,
1509                None,
1510            ) else {
1511                continue;
1512            };
1513
1514            let desc = match binding.res() {
1515                Res::Def(DefKind::Macro(MacroKind::Bang), _) => "a function-like macro".to_string(),
1516                Res::Def(DefKind::Macro(MacroKind::Attr), _) | Res::NonMacroAttr(..) => {
1517                    format!("an attribute: `#[{ident}]`")
1518                }
1519                Res::Def(DefKind::Macro(MacroKind::Derive), _) => {
1520                    format!("a derive macro: `#[derive({ident})]`")
1521                }
1522                Res::ToolMod => {
1523                    // Don't confuse the user with tool modules.
1524                    continue;
1525                }
1526                Res::Def(DefKind::Trait, _) if macro_kind == MacroKind::Derive => {
1527                    "only a trait, without a derive macro".to_string()
1528                }
1529                res => format!(
1530                    "{} {}, not {} {}",
1531                    res.article(),
1532                    res.descr(),
1533                    macro_kind.article(),
1534                    macro_kind.descr_expected(),
1535                ),
1536            };
1537            if let crate::NameBindingKind::Import { import, .. } = binding.kind
1538                && !import.span.is_dummy()
1539            {
1540                let note = errors::IdentImporterHereButItIsDesc {
1541                    span: import.span,
1542                    imported_ident: ident,
1543                    imported_ident_desc: &desc,
1544                };
1545                err.subdiagnostic(note);
1546                // Silence the 'unused import' warning we might get,
1547                // since this diagnostic already covers that import.
1548                self.record_use(ident, binding, Used::Other);
1549                return;
1550            }
1551            let note = errors::IdentInScopeButItIsDesc {
1552                imported_ident: ident,
1553                imported_ident_desc: &desc,
1554            };
1555            err.subdiagnostic(note);
1556            return;
1557        }
1558    }
1559
1560    pub(crate) fn add_typo_suggestion(
1561        &self,
1562        err: &mut Diag<'_>,
1563        suggestion: Option<TypoSuggestion>,
1564        span: Span,
1565    ) -> bool {
1566        let suggestion = match suggestion {
1567            None => return false,
1568            // We shouldn't suggest underscore.
1569            Some(suggestion) if suggestion.candidate == kw::Underscore => return false,
1570            Some(suggestion) => suggestion,
1571        };
1572
1573        let mut did_label_def_span = false;
1574
1575        if let Some(def_span) = suggestion.res.opt_def_id().map(|def_id| self.def_span(def_id)) {
1576            if span.overlaps(def_span) {
1577                // Don't suggest typo suggestion for itself like in the following:
1578                // error[E0423]: expected function, tuple struct or tuple variant, found struct `X`
1579                //   --> $DIR/issue-64792-bad-unicode-ctor.rs:3:14
1580                //    |
1581                // LL | struct X {}
1582                //    | ----------- `X` defined here
1583                // LL |
1584                // LL | const Y: X = X("ö");
1585                //    | -------------^^^^^^- similarly named constant `Y` defined here
1586                //    |
1587                // help: use struct literal syntax instead
1588                //    |
1589                // LL | const Y: X = X {};
1590                //    |              ^^^^
1591                // help: a constant with a similar name exists
1592                //    |
1593                // LL | const Y: X = Y("ö");
1594                //    |              ^
1595                return false;
1596            }
1597            let span = self.tcx.sess.source_map().guess_head_span(def_span);
1598            let candidate_descr = suggestion.res.descr();
1599            let candidate = suggestion.candidate;
1600            let label = match suggestion.target {
1601                SuggestionTarget::SimilarlyNamed => {
1602                    errors::DefinedHere::SimilarlyNamed { span, candidate_descr, candidate }
1603                }
1604                SuggestionTarget::SingleItem => {
1605                    errors::DefinedHere::SingleItem { span, candidate_descr, candidate }
1606                }
1607            };
1608            did_label_def_span = true;
1609            err.subdiagnostic(label);
1610        }
1611
1612        let (span, msg, sugg) = if let SuggestionTarget::SimilarlyNamed = suggestion.target
1613            && let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span)
1614            && let Some(span) = suggestion.span
1615            && let Some(candidate) = suggestion.candidate.as_str().strip_prefix('_')
1616            && snippet == candidate
1617        {
1618            let candidate = suggestion.candidate;
1619            // When the suggested binding change would be from `x` to `_x`, suggest changing the
1620            // original binding definition instead. (#60164)
1621            let msg = format!(
1622                "the leading underscore in `{candidate}` marks it as unused, consider renaming it to `{snippet}`"
1623            );
1624            if !did_label_def_span {
1625                err.span_label(span, format!("`{candidate}` defined here"));
1626            }
1627            (span, msg, snippet)
1628        } else {
1629            let msg = match suggestion.target {
1630                SuggestionTarget::SimilarlyNamed => format!(
1631                    "{} {} with a similar name exists",
1632                    suggestion.res.article(),
1633                    suggestion.res.descr()
1634                ),
1635                SuggestionTarget::SingleItem => {
1636                    format!("maybe you meant this {}", suggestion.res.descr())
1637                }
1638            };
1639            (span, msg, suggestion.candidate.to_ident_string())
1640        };
1641        err.span_suggestion(span, msg, sugg, Applicability::MaybeIncorrect);
1642        true
1643    }
1644
1645    fn binding_description(&self, b: NameBinding<'_>, ident: Ident, from_prelude: bool) -> String {
1646        let res = b.res();
1647        if b.span.is_dummy() || !self.tcx.sess.source_map().is_span_accessible(b.span) {
1648            // These already contain the "built-in" prefix or look bad with it.
1649            let add_built_in =
1650                !matches!(b.res(), Res::NonMacroAttr(..) | Res::PrimTy(..) | Res::ToolMod);
1651            let (built_in, from) = if from_prelude {
1652                ("", " from prelude")
1653            } else if b.is_extern_crate()
1654                && !b.is_import()
1655                && self.tcx.sess.opts.externs.get(ident.as_str()).is_some()
1656            {
1657                ("", " passed with `--extern`")
1658            } else if add_built_in {
1659                (" built-in", "")
1660            } else {
1661                ("", "")
1662            };
1663
1664            let a = if built_in.is_empty() { res.article() } else { "a" };
1665            format!("{a}{built_in} {thing}{from}", thing = res.descr())
1666        } else {
1667            let introduced = if b.is_import_user_facing() { "imported" } else { "defined" };
1668            format!("the {thing} {introduced} here", thing = res.descr())
1669        }
1670    }
1671
1672    fn ambiguity_diagnostics(&self, ambiguity_error: &AmbiguityError<'_>) -> AmbiguityErrorDiag {
1673        let AmbiguityError { kind, ident, b1, b2, misc1, misc2, .. } = *ambiguity_error;
1674        let (b1, b2, misc1, misc2, swapped) = if b2.span.is_dummy() && !b1.span.is_dummy() {
1675            // We have to print the span-less alternative first, otherwise formatting looks bad.
1676            (b2, b1, misc2, misc1, true)
1677        } else {
1678            (b1, b2, misc1, misc2, false)
1679        };
1680        let could_refer_to = |b: NameBinding<'_>, misc: AmbiguityErrorMisc, also: &str| {
1681            let what = self.binding_description(b, ident, misc == AmbiguityErrorMisc::FromPrelude);
1682            let note_msg = format!("`{ident}` could{also} refer to {what}");
1683
1684            let thing = b.res().descr();
1685            let mut help_msgs = Vec::new();
1686            if b.is_glob_import()
1687                && (kind == AmbiguityKind::GlobVsGlob
1688                    || kind == AmbiguityKind::GlobVsExpanded
1689                    || kind == AmbiguityKind::GlobVsOuter && swapped != also.is_empty())
1690            {
1691                help_msgs.push(format!(
1692                    "consider adding an explicit import of `{ident}` to disambiguate"
1693                ))
1694            }
1695            if b.is_extern_crate() && ident.span.at_least_rust_2018() {
1696                help_msgs.push(format!("use `::{ident}` to refer to this {thing} unambiguously"))
1697            }
1698            match misc {
1699                AmbiguityErrorMisc::SuggestCrate => help_msgs
1700                    .push(format!("use `crate::{ident}` to refer to this {thing} unambiguously")),
1701                AmbiguityErrorMisc::SuggestSelf => help_msgs
1702                    .push(format!("use `self::{ident}` to refer to this {thing} unambiguously")),
1703                AmbiguityErrorMisc::FromPrelude | AmbiguityErrorMisc::None => {}
1704            }
1705
1706            (
1707                b.span,
1708                note_msg,
1709                help_msgs
1710                    .iter()
1711                    .enumerate()
1712                    .map(|(i, help_msg)| {
1713                        let or = if i == 0 { "" } else { "or " };
1714                        format!("{or}{help_msg}")
1715                    })
1716                    .collect::<Vec<_>>(),
1717            )
1718        };
1719        let (b1_span, b1_note_msg, b1_help_msgs) = could_refer_to(b1, misc1, "");
1720        let (b2_span, b2_note_msg, b2_help_msgs) = could_refer_to(b2, misc2, " also");
1721
1722        AmbiguityErrorDiag {
1723            msg: format!("`{ident}` is ambiguous"),
1724            span: ident.span,
1725            label_span: ident.span,
1726            label_msg: "ambiguous name".to_string(),
1727            note_msg: format!("ambiguous because of {}", kind.descr()),
1728            b1_span,
1729            b1_note_msg,
1730            b1_help_msgs,
1731            b2_span,
1732            b2_note_msg,
1733            b2_help_msgs,
1734        }
1735    }
1736
1737    /// If the binding refers to a tuple struct constructor with fields,
1738    /// returns the span of its fields.
1739    fn ctor_fields_span(&self, binding: NameBinding<'_>) -> Option<Span> {
1740        let NameBindingKind::Res(Res::Def(
1741            DefKind::Ctor(CtorOf::Struct, CtorKind::Fn),
1742            ctor_def_id,
1743        )) = binding.kind
1744        else {
1745            return None;
1746        };
1747
1748        let def_id = self.tcx.parent(ctor_def_id);
1749        self.field_idents(def_id)?.iter().map(|&f| f.span).reduce(Span::to) // None for `struct Foo()`
1750    }
1751
1752    fn report_privacy_error(&mut self, privacy_error: &PrivacyError<'ra>) {
1753        let PrivacyError { ident, binding, outermost_res, parent_scope, single_nested, dedup_span } =
1754            *privacy_error;
1755
1756        let res = binding.res();
1757        let ctor_fields_span = self.ctor_fields_span(binding);
1758        let plain_descr = res.descr().to_string();
1759        let nonimport_descr =
1760            if ctor_fields_span.is_some() { plain_descr + " constructor" } else { plain_descr };
1761        let import_descr = nonimport_descr.clone() + " import";
1762        let get_descr =
1763            |b: NameBinding<'_>| if b.is_import() { &import_descr } else { &nonimport_descr };
1764
1765        // Print the primary message.
1766        let ident_descr = get_descr(binding);
1767        let mut err =
1768            self.dcx().create_err(errors::IsPrivate { span: ident.span, ident_descr, ident });
1769
1770        let mut not_publicly_reexported = false;
1771        if let Some((this_res, outer_ident)) = outermost_res {
1772            let import_suggestions = self.lookup_import_candidates(
1773                outer_ident,
1774                this_res.ns().unwrap_or(Namespace::TypeNS),
1775                &parent_scope,
1776                &|res: Res| res == this_res,
1777            );
1778            let point_to_def = !show_candidates(
1779                self.tcx,
1780                &mut err,
1781                Some(dedup_span.until(outer_ident.span.shrink_to_hi())),
1782                &import_suggestions,
1783                Instead::Yes,
1784                FoundUse::Yes,
1785                DiagMode::Import { append: single_nested },
1786                vec![],
1787                "",
1788            );
1789            // If we suggest importing a public re-export, don't point at the definition.
1790            if point_to_def && ident.span != outer_ident.span {
1791                not_publicly_reexported = true;
1792                let label = errors::OuterIdentIsNotPubliclyReexported {
1793                    span: outer_ident.span,
1794                    outer_ident_descr: this_res.descr(),
1795                    outer_ident,
1796                };
1797                err.subdiagnostic(label);
1798            }
1799        }
1800
1801        let mut non_exhaustive = None;
1802        // If an ADT is foreign and marked as `non_exhaustive`, then that's
1803        // probably why we have the privacy error.
1804        // Otherwise, point out if the struct has any private fields.
1805        if let Some(def_id) = res.opt_def_id()
1806            && !def_id.is_local()
1807            && let Some(attr) = self.tcx.get_attr(def_id, sym::non_exhaustive)
1808        {
1809            non_exhaustive = Some(attr.span);
1810        } else if let Some(span) = ctor_fields_span {
1811            let label = errors::ConstructorPrivateIfAnyFieldPrivate { span };
1812            err.subdiagnostic(label);
1813            if let Res::Def(_, d) = res
1814                && let Some(fields) = self.field_visibility_spans.get(&d)
1815            {
1816                let spans = fields.iter().map(|span| *span).collect();
1817                let sugg =
1818                    errors::ConsiderMakingTheFieldPublic { spans, number_of_fields: fields.len() };
1819                err.subdiagnostic(sugg);
1820            }
1821        }
1822
1823        let mut sugg_paths = vec![];
1824        if let Some(mut def_id) = res.opt_def_id() {
1825            // We can't use `def_path_str` in resolve.
1826            let mut path = vec![def_id];
1827            while let Some(parent) = self.tcx.opt_parent(def_id) {
1828                def_id = parent;
1829                if !def_id.is_top_level_module() {
1830                    path.push(def_id);
1831                } else {
1832                    break;
1833                }
1834            }
1835            // We will only suggest importing directly if it is accessible through that path.
1836            let path_names: Option<Vec<String>> = path
1837                .iter()
1838                .rev()
1839                .map(|def_id| {
1840                    self.tcx.opt_item_name(*def_id).map(|n| {
1841                        if def_id.is_top_level_module() {
1842                            "crate".to_string()
1843                        } else {
1844                            n.to_string()
1845                        }
1846                    })
1847                })
1848                .collect();
1849            if let Some(def_id) = path.get(0)
1850                && let Some(path) = path_names
1851            {
1852                if let Some(def_id) = def_id.as_local() {
1853                    if self.effective_visibilities.is_directly_public(def_id) {
1854                        sugg_paths.push((path, false));
1855                    }
1856                } else if self.is_accessible_from(self.tcx.visibility(def_id), parent_scope.module)
1857                {
1858                    sugg_paths.push((path, false));
1859                }
1860            }
1861        }
1862
1863        // Print the whole import chain to make it easier to see what happens.
1864        let first_binding = binding;
1865        let mut next_binding = Some(binding);
1866        let mut next_ident = ident;
1867        let mut path = vec![];
1868        while let Some(binding) = next_binding {
1869            let name = next_ident;
1870            next_binding = match binding.kind {
1871                _ if res == Res::Err => None,
1872                NameBindingKind::Import { binding, import, .. } => match import.kind {
1873                    _ if binding.span.is_dummy() => None,
1874                    ImportKind::Single { source, .. } => {
1875                        next_ident = source;
1876                        Some(binding)
1877                    }
1878                    ImportKind::Glob { .. }
1879                    | ImportKind::MacroUse { .. }
1880                    | ImportKind::MacroExport => Some(binding),
1881                    ImportKind::ExternCrate { .. } => None,
1882                },
1883                _ => None,
1884            };
1885
1886            match binding.kind {
1887                NameBindingKind::Import { import, .. } => {
1888                    for segment in import.module_path.iter().skip(1) {
1889                        path.push(segment.ident.to_string());
1890                    }
1891                    sugg_paths.push((
1892                        path.iter()
1893                            .cloned()
1894                            .chain(vec![ident.to_string()].into_iter())
1895                            .collect::<Vec<_>>(),
1896                        true, // re-export
1897                    ));
1898                }
1899                NameBindingKind::Res(_) | NameBindingKind::Module(_) => {}
1900            }
1901            let first = binding == first_binding;
1902            let def_span = self.tcx.sess.source_map().guess_head_span(binding.span);
1903            let mut note_span = MultiSpan::from_span(def_span);
1904            if !first && binding.vis.is_public() {
1905                let desc = match binding.kind {
1906                    NameBindingKind::Import { .. } => "re-export",
1907                    _ => "directly",
1908                };
1909                note_span.push_span_label(def_span, format!("you could import this {desc}"));
1910            }
1911            // Final step in the import chain, point out if the ADT is `non_exhaustive`
1912            // which is probably why this privacy violation occurred.
1913            if next_binding.is_none()
1914                && let Some(span) = non_exhaustive
1915            {
1916                note_span.push_span_label(
1917                    span,
1918                    "cannot be constructed because it is `#[non_exhaustive]`",
1919                );
1920            }
1921            let note = errors::NoteAndRefersToTheItemDefinedHere {
1922                span: note_span,
1923                binding_descr: get_descr(binding),
1924                binding_name: name,
1925                first,
1926                dots: next_binding.is_some(),
1927            };
1928            err.subdiagnostic(note);
1929        }
1930        // We prioritize shorter paths, non-core imports and direct imports over the alternatives.
1931        sugg_paths.sort_by_key(|(p, reexport)| (p.len(), p[0] == "core", *reexport));
1932        for (sugg, reexport) in sugg_paths {
1933            if not_publicly_reexported {
1934                break;
1935            }
1936            if sugg.len() <= 1 {
1937                // A single path segment suggestion is wrong. This happens on circular imports.
1938                // `tests/ui/imports/issue-55884-2.rs`
1939                continue;
1940            }
1941            let path = sugg.join("::");
1942            let sugg = if reexport {
1943                errors::ImportIdent::ThroughReExport { span: dedup_span, ident, path }
1944            } else {
1945                errors::ImportIdent::Directly { span: dedup_span, ident, path }
1946            };
1947            err.subdiagnostic(sugg);
1948            break;
1949        }
1950
1951        err.emit();
1952    }
1953
1954    pub(crate) fn find_similarly_named_module_or_crate(
1955        &mut self,
1956        ident: Symbol,
1957        current_module: Module<'ra>,
1958    ) -> Option<Symbol> {
1959        let mut candidates = self
1960            .extern_prelude
1961            .keys()
1962            .map(|ident| ident.name)
1963            .chain(
1964                self.module_map
1965                    .iter()
1966                    .filter(|(_, module)| {
1967                        current_module.is_ancestor_of(**module) && current_module != **module
1968                    })
1969                    .flat_map(|(_, module)| module.kind.name()),
1970            )
1971            .filter(|c| !c.to_string().is_empty())
1972            .collect::<Vec<_>>();
1973        candidates.sort();
1974        candidates.dedup();
1975        find_best_match_for_name(&candidates, ident, None).filter(|sugg| *sugg != ident)
1976    }
1977
1978    pub(crate) fn report_path_resolution_error(
1979        &mut self,
1980        path: &[Segment],
1981        opt_ns: Option<Namespace>, // `None` indicates a module path in import
1982        parent_scope: &ParentScope<'ra>,
1983        ribs: Option<&PerNS<Vec<Rib<'ra>>>>,
1984        ignore_binding: Option<NameBinding<'ra>>,
1985        ignore_import: Option<Import<'ra>>,
1986        module: Option<ModuleOrUniformRoot<'ra>>,
1987        failed_segment_idx: usize,
1988        ident: Ident,
1989    ) -> (String, Option<Suggestion>) {
1990        let is_last = failed_segment_idx == path.len() - 1;
1991        let ns = if is_last { opt_ns.unwrap_or(TypeNS) } else { TypeNS };
1992        let module_res = match module {
1993            Some(ModuleOrUniformRoot::Module(module)) => module.res(),
1994            _ => None,
1995        };
1996        if module_res == self.graph_root.res() {
1997            let is_mod = |res| matches!(res, Res::Def(DefKind::Mod, _));
1998            let mut candidates = self.lookup_import_candidates(ident, TypeNS, parent_scope, is_mod);
1999            candidates
2000                .sort_by_cached_key(|c| (c.path.segments.len(), pprust::path_to_string(&c.path)));
2001            if let Some(candidate) = candidates.get(0) {
2002                let path = {
2003                    // remove the possible common prefix of the path
2004                    let len = candidate.path.segments.len();
2005                    let start_index = (0..=failed_segment_idx.min(len - 1))
2006                        .find(|&i| path[i].ident.name != candidate.path.segments[i].ident.name)
2007                        .unwrap_or_default();
2008                    let segments =
2009                        (start_index..len).map(|s| candidate.path.segments[s].clone()).collect();
2010                    Path { segments, span: Span::default(), tokens: None }
2011                };
2012                (
2013                    String::from("unresolved import"),
2014                    Some((
2015                        vec![(ident.span, pprust::path_to_string(&path))],
2016                        String::from("a similar path exists"),
2017                        Applicability::MaybeIncorrect,
2018                    )),
2019                )
2020            } else if ident.name == sym::core {
2021                (
2022                    format!("you might be missing crate `{ident}`"),
2023                    Some((
2024                        vec![(ident.span, "std".to_string())],
2025                        "try using `std` instead of `core`".to_string(),
2026                        Applicability::MaybeIncorrect,
2027                    )),
2028                )
2029            } else if ident.name == kw::Underscore {
2030                (format!("`_` is not a valid crate or module name"), None)
2031            } else if self.tcx.sess.is_rust_2015() {
2032                (
2033                    format!("use of unresolved module or unlinked crate `{ident}`"),
2034                    Some((
2035                        vec![(
2036                            self.current_crate_outer_attr_insert_span,
2037                            format!("extern crate {ident};\n"),
2038                        )],
2039                        if was_invoked_from_cargo() {
2040                            format!(
2041                                "if you wanted to use a crate named `{ident}`, use `cargo add {ident}` \
2042                             to add it to your `Cargo.toml` and import it in your code",
2043                            )
2044                        } else {
2045                            format!(
2046                                "you might be missing a crate named `{ident}`, add it to your \
2047                                 project and import it in your code",
2048                            )
2049                        },
2050                        Applicability::MaybeIncorrect,
2051                    )),
2052                )
2053            } else {
2054                (format!("could not find `{ident}` in the crate root"), None)
2055            }
2056        } else if failed_segment_idx > 0 {
2057            let parent = path[failed_segment_idx - 1].ident.name;
2058            let parent = match parent {
2059                // ::foo is mounted at the crate root for 2015, and is the extern
2060                // prelude for 2018+
2061                kw::PathRoot if self.tcx.sess.edition() > Edition::Edition2015 => {
2062                    "the list of imported crates".to_owned()
2063                }
2064                kw::PathRoot | kw::Crate => "the crate root".to_owned(),
2065                _ => format!("`{parent}`"),
2066            };
2067
2068            let mut msg = format!("could not find `{ident}` in {parent}");
2069            if ns == TypeNS || ns == ValueNS {
2070                let ns_to_try = if ns == TypeNS { ValueNS } else { TypeNS };
2071                let binding = if let Some(module) = module {
2072                    self.resolve_ident_in_module(
2073                        module,
2074                        ident,
2075                        ns_to_try,
2076                        parent_scope,
2077                        None,
2078                        ignore_binding,
2079                        ignore_import,
2080                    )
2081                    .ok()
2082                } else if let Some(ribs) = ribs
2083                    && let Some(TypeNS | ValueNS) = opt_ns
2084                {
2085                    assert!(ignore_import.is_none());
2086                    match self.resolve_ident_in_lexical_scope(
2087                        ident,
2088                        ns_to_try,
2089                        parent_scope,
2090                        None,
2091                        &ribs[ns_to_try],
2092                        ignore_binding,
2093                    ) {
2094                        // we found a locally-imported or available item/module
2095                        Some(LexicalScopeBinding::Item(binding)) => Some(binding),
2096                        _ => None,
2097                    }
2098                } else {
2099                    self.early_resolve_ident_in_lexical_scope(
2100                        ident,
2101                        ScopeSet::All(ns_to_try),
2102                        parent_scope,
2103                        None,
2104                        false,
2105                        ignore_binding,
2106                        ignore_import,
2107                    )
2108                    .ok()
2109                };
2110                if let Some(binding) = binding {
2111                    let mut found = |what| {
2112                        msg = format!(
2113                            "expected {}, found {} `{}` in {}",
2114                            ns.descr(),
2115                            what,
2116                            ident,
2117                            parent
2118                        )
2119                    };
2120                    if binding.module().is_some() {
2121                        found("module")
2122                    } else {
2123                        match binding.res() {
2124                            // Avoid using TyCtxt::def_kind_descr in the resolver, because it
2125                            // indirectly *calls* the resolver, and would cause a query cycle.
2126                            Res::Def(kind, id) => found(kind.descr(id)),
2127                            _ => found(ns_to_try.descr()),
2128                        }
2129                    }
2130                };
2131            }
2132            (msg, None)
2133        } else if ident.name == kw::SelfUpper {
2134            // As mentioned above, `opt_ns` being `None` indicates a module path in import.
2135            // We can use this to improve a confusing error for, e.g. `use Self::Variant` in an
2136            // impl
2137            if opt_ns.is_none() {
2138                ("`Self` cannot be used in imports".to_string(), None)
2139            } else {
2140                (
2141                    "`Self` is only available in impls, traits, and type definitions".to_string(),
2142                    None,
2143                )
2144            }
2145        } else if ident.name.as_str().chars().next().is_some_and(|c| c.is_ascii_uppercase()) {
2146            // Check whether the name refers to an item in the value namespace.
2147            let binding = if let Some(ribs) = ribs {
2148                assert!(ignore_import.is_none());
2149                self.resolve_ident_in_lexical_scope(
2150                    ident,
2151                    ValueNS,
2152                    parent_scope,
2153                    None,
2154                    &ribs[ValueNS],
2155                    ignore_binding,
2156                )
2157            } else {
2158                None
2159            };
2160            let match_span = match binding {
2161                // Name matches a local variable. For example:
2162                // ```
2163                // fn f() {
2164                //     let Foo: &str = "";
2165                //     println!("{}", Foo::Bar); // Name refers to local
2166                //                               // variable `Foo`.
2167                // }
2168                // ```
2169                Some(LexicalScopeBinding::Res(Res::Local(id))) => {
2170                    Some(*self.pat_span_map.get(&id).unwrap())
2171                }
2172                // Name matches item from a local name binding
2173                // created by `use` declaration. For example:
2174                // ```
2175                // pub Foo: &str = "";
2176                //
2177                // mod submod {
2178                //     use super::Foo;
2179                //     println!("{}", Foo::Bar); // Name refers to local
2180                //                               // binding `Foo`.
2181                // }
2182                // ```
2183                Some(LexicalScopeBinding::Item(name_binding)) => Some(name_binding.span),
2184                _ => None,
2185            };
2186            let suggestion = match_span.map(|span| {
2187                (
2188                    vec![(span, String::from(""))],
2189                    format!("`{ident}` is defined here, but is not a type"),
2190                    Applicability::MaybeIncorrect,
2191                )
2192            });
2193
2194            (format!("use of undeclared type `{ident}`"), suggestion)
2195        } else {
2196            let mut suggestion = None;
2197            if ident.name == sym::alloc {
2198                suggestion = Some((
2199                    vec![],
2200                    String::from("add `extern crate alloc` to use the `alloc` crate"),
2201                    Applicability::MaybeIncorrect,
2202                ))
2203            }
2204
2205            suggestion = suggestion.or_else(|| {
2206                self.find_similarly_named_module_or_crate(ident.name, parent_scope.module).map(
2207                    |sugg| {
2208                        (
2209                            vec![(ident.span, sugg.to_string())],
2210                            String::from("there is a crate or module with a similar name"),
2211                            Applicability::MaybeIncorrect,
2212                        )
2213                    },
2214                )
2215            });
2216            if let Ok(binding) = self.early_resolve_ident_in_lexical_scope(
2217                ident,
2218                ScopeSet::All(ValueNS),
2219                parent_scope,
2220                None,
2221                false,
2222                ignore_binding,
2223                ignore_import,
2224            ) {
2225                let descr = binding.res().descr();
2226                (format!("{descr} `{ident}` is not a crate or module"), suggestion)
2227            } else {
2228                let suggestion = if suggestion.is_some() {
2229                    suggestion
2230                } else if was_invoked_from_cargo() {
2231                    Some((
2232                        vec![],
2233                        format!(
2234                            "if you wanted to use a crate named `{ident}`, use `cargo add {ident}` \
2235                             to add it to your `Cargo.toml`",
2236                        ),
2237                        Applicability::MaybeIncorrect,
2238                    ))
2239                } else {
2240                    Some((
2241                        vec![],
2242                        format!("you might be missing a crate named `{ident}`",),
2243                        Applicability::MaybeIncorrect,
2244                    ))
2245                };
2246                (format!("use of unresolved module or unlinked crate `{ident}`"), suggestion)
2247            }
2248        }
2249    }
2250
2251    /// Adds suggestions for a path that cannot be resolved.
2252    #[instrument(level = "debug", skip(self, parent_scope))]
2253    pub(crate) fn make_path_suggestion(
2254        &mut self,
2255        span: Span,
2256        mut path: Vec<Segment>,
2257        parent_scope: &ParentScope<'ra>,
2258    ) -> Option<(Vec<Segment>, Option<String>)> {
2259        match path[..] {
2260            // `{{root}}::ident::...` on both editions.
2261            // On 2015 `{{root}}` is usually added implicitly.
2262            [first, second, ..]
2263                if first.ident.name == kw::PathRoot && !second.ident.is_path_segment_keyword() => {}
2264            // `ident::...` on 2018.
2265            [first, ..]
2266                if first.ident.span.at_least_rust_2018()
2267                    && !first.ident.is_path_segment_keyword() =>
2268            {
2269                // Insert a placeholder that's later replaced by `self`/`super`/etc.
2270                path.insert(0, Segment::from_ident(Ident::empty()));
2271            }
2272            _ => return None,
2273        }
2274
2275        self.make_missing_self_suggestion(path.clone(), parent_scope)
2276            .or_else(|| self.make_missing_crate_suggestion(path.clone(), parent_scope))
2277            .or_else(|| self.make_missing_super_suggestion(path.clone(), parent_scope))
2278            .or_else(|| self.make_external_crate_suggestion(path, parent_scope))
2279    }
2280
2281    /// Suggest a missing `self::` if that resolves to an correct module.
2282    ///
2283    /// ```text
2284    ///    |
2285    /// LL | use foo::Bar;
2286    ///    |     ^^^ did you mean `self::foo`?
2287    /// ```
2288    #[instrument(level = "debug", skip(self, parent_scope))]
2289    fn make_missing_self_suggestion(
2290        &mut self,
2291        mut path: Vec<Segment>,
2292        parent_scope: &ParentScope<'ra>,
2293    ) -> Option<(Vec<Segment>, Option<String>)> {
2294        // Replace first ident with `self` and check if that is valid.
2295        path[0].ident.name = kw::SelfLower;
2296        let result = self.maybe_resolve_path(&path, None, parent_scope, None);
2297        debug!(?path, ?result);
2298        if let PathResult::Module(..) = result { Some((path, None)) } else { None }
2299    }
2300
2301    /// Suggests a missing `crate::` if that resolves to an correct module.
2302    ///
2303    /// ```text
2304    ///    |
2305    /// LL | use foo::Bar;
2306    ///    |     ^^^ did you mean `crate::foo`?
2307    /// ```
2308    #[instrument(level = "debug", skip(self, parent_scope))]
2309    fn make_missing_crate_suggestion(
2310        &mut self,
2311        mut path: Vec<Segment>,
2312        parent_scope: &ParentScope<'ra>,
2313    ) -> Option<(Vec<Segment>, Option<String>)> {
2314        // Replace first ident with `crate` and check if that is valid.
2315        path[0].ident.name = kw::Crate;
2316        let result = self.maybe_resolve_path(&path, None, parent_scope, None);
2317        debug!(?path, ?result);
2318        if let PathResult::Module(..) = result {
2319            Some((
2320                path,
2321                Some(
2322                    "`use` statements changed in Rust 2018; read more at \
2323                     <https://doc.rust-lang.org/edition-guide/rust-2018/module-system/path-\
2324                     clarity.html>"
2325                        .to_string(),
2326                ),
2327            ))
2328        } else {
2329            None
2330        }
2331    }
2332
2333    /// Suggests a missing `super::` if that resolves to an correct module.
2334    ///
2335    /// ```text
2336    ///    |
2337    /// LL | use foo::Bar;
2338    ///    |     ^^^ did you mean `super::foo`?
2339    /// ```
2340    #[instrument(level = "debug", skip(self, parent_scope))]
2341    fn make_missing_super_suggestion(
2342        &mut self,
2343        mut path: Vec<Segment>,
2344        parent_scope: &ParentScope<'ra>,
2345    ) -> Option<(Vec<Segment>, Option<String>)> {
2346        // Replace first ident with `crate` and check if that is valid.
2347        path[0].ident.name = kw::Super;
2348        let result = self.maybe_resolve_path(&path, None, parent_scope, None);
2349        debug!(?path, ?result);
2350        if let PathResult::Module(..) = result { Some((path, None)) } else { None }
2351    }
2352
2353    /// Suggests a missing external crate name if that resolves to an correct module.
2354    ///
2355    /// ```text
2356    ///    |
2357    /// LL | use foobar::Baz;
2358    ///    |     ^^^^^^ did you mean `baz::foobar`?
2359    /// ```
2360    ///
2361    /// Used when importing a submodule of an external crate but missing that crate's
2362    /// name as the first part of path.
2363    #[instrument(level = "debug", skip(self, parent_scope))]
2364    fn make_external_crate_suggestion(
2365        &mut self,
2366        mut path: Vec<Segment>,
2367        parent_scope: &ParentScope<'ra>,
2368    ) -> Option<(Vec<Segment>, Option<String>)> {
2369        if path[1].ident.span.is_rust_2015() {
2370            return None;
2371        }
2372
2373        // Sort extern crate names in *reverse* order to get
2374        // 1) some consistent ordering for emitted diagnostics, and
2375        // 2) `std` suggestions before `core` suggestions.
2376        let mut extern_crate_names =
2377            self.extern_prelude.keys().map(|ident| ident.name).collect::<Vec<_>>();
2378        extern_crate_names.sort_by(|a, b| b.as_str().cmp(a.as_str()));
2379
2380        for name in extern_crate_names.into_iter() {
2381            // Replace first ident with a crate name and check if that is valid.
2382            path[0].ident.name = name;
2383            let result = self.maybe_resolve_path(&path, None, parent_scope, None);
2384            debug!(?path, ?name, ?result);
2385            if let PathResult::Module(..) = result {
2386                return Some((path, None));
2387            }
2388        }
2389
2390        None
2391    }
2392
2393    /// Suggests importing a macro from the root of the crate rather than a module within
2394    /// the crate.
2395    ///
2396    /// ```text
2397    /// help: a macro with this name exists at the root of the crate
2398    ///    |
2399    /// LL | use issue_59764::makro;
2400    ///    |     ^^^^^^^^^^^^^^^^^^
2401    ///    |
2402    ///    = note: this could be because a macro annotated with `#[macro_export]` will be exported
2403    ///            at the root of the crate instead of the module where it is defined
2404    /// ```
2405    pub(crate) fn check_for_module_export_macro(
2406        &mut self,
2407        import: Import<'ra>,
2408        module: ModuleOrUniformRoot<'ra>,
2409        ident: Ident,
2410    ) -> Option<(Option<Suggestion>, Option<String>)> {
2411        let ModuleOrUniformRoot::Module(mut crate_module) = module else {
2412            return None;
2413        };
2414
2415        while let Some(parent) = crate_module.parent {
2416            crate_module = parent;
2417        }
2418
2419        if module == ModuleOrUniformRoot::Module(crate_module) {
2420            // Don't make a suggestion if the import was already from the root of the crate.
2421            return None;
2422        }
2423
2424        let resolutions = self.resolutions(crate_module).borrow();
2425        let binding_key = BindingKey::new(ident, MacroNS);
2426        let resolution = resolutions.get(&binding_key)?;
2427        let binding = resolution.borrow().binding()?;
2428        let Res::Def(DefKind::Macro(MacroKind::Bang), _) = binding.res() else {
2429            return None;
2430        };
2431        let module_name = crate_module.kind.name().unwrap();
2432        let import_snippet = match import.kind {
2433            ImportKind::Single { source, target, .. } if source != target => {
2434                format!("{source} as {target}")
2435            }
2436            _ => format!("{ident}"),
2437        };
2438
2439        let mut corrections: Vec<(Span, String)> = Vec::new();
2440        if !import.is_nested() {
2441            // Assume this is the easy case of `use issue_59764::foo::makro;` and just remove
2442            // intermediate segments.
2443            corrections.push((import.span, format!("{module_name}::{import_snippet}")));
2444        } else {
2445            // Find the binding span (and any trailing commas and spaces).
2446            //   ie. `use a::b::{c, d, e};`
2447            //                      ^^^
2448            let (found_closing_brace, binding_span) = find_span_of_binding_until_next_binding(
2449                self.tcx.sess,
2450                import.span,
2451                import.use_span,
2452            );
2453            debug!(found_closing_brace, ?binding_span);
2454
2455            let mut removal_span = binding_span;
2456
2457            // If the binding span ended with a closing brace, as in the below example:
2458            //   ie. `use a::b::{c, d};`
2459            //                      ^
2460            // Then expand the span of characters to remove to include the previous
2461            // binding's trailing comma.
2462            //   ie. `use a::b::{c, d};`
2463            //                    ^^^
2464            if found_closing_brace
2465                && let Some(previous_span) =
2466                    extend_span_to_previous_binding(self.tcx.sess, binding_span)
2467            {
2468                debug!(?previous_span);
2469                removal_span = removal_span.with_lo(previous_span.lo());
2470            }
2471            debug!(?removal_span);
2472
2473            // Remove the `removal_span`.
2474            corrections.push((removal_span, "".to_string()));
2475
2476            // Find the span after the crate name and if it has nested imports immediately
2477            // after the crate name already.
2478            //   ie. `use a::b::{c, d};`
2479            //               ^^^^^^^^^
2480            //   or  `use a::{b, c, d}};`
2481            //               ^^^^^^^^^^^
2482            let (has_nested, after_crate_name) =
2483                find_span_immediately_after_crate_name(self.tcx.sess, module_name, import.use_span);
2484            debug!(has_nested, ?after_crate_name);
2485
2486            let source_map = self.tcx.sess.source_map();
2487
2488            // Make sure this is actually crate-relative.
2489            let is_definitely_crate = import
2490                .module_path
2491                .first()
2492                .is_some_and(|f| f.ident.name != kw::SelfLower && f.ident.name != kw::Super);
2493
2494            // Add the import to the start, with a `{` if required.
2495            let start_point = source_map.start_point(after_crate_name);
2496            if is_definitely_crate
2497                && let Ok(start_snippet) = source_map.span_to_snippet(start_point)
2498            {
2499                corrections.push((
2500                    start_point,
2501                    if has_nested {
2502                        // In this case, `start_snippet` must equal '{'.
2503                        format!("{start_snippet}{import_snippet}, ")
2504                    } else {
2505                        // In this case, add a `{`, then the moved import, then whatever
2506                        // was there before.
2507                        format!("{{{import_snippet}, {start_snippet}")
2508                    },
2509                ));
2510
2511                // Add a `};` to the end if nested, matching the `{` added at the start.
2512                if !has_nested {
2513                    corrections.push((source_map.end_point(after_crate_name), "};".to_string()));
2514                }
2515            } else {
2516                // If the root import is module-relative, add the import separately
2517                corrections.push((
2518                    import.use_span.shrink_to_lo(),
2519                    format!("use {module_name}::{import_snippet};\n"),
2520                ));
2521            }
2522        }
2523
2524        let suggestion = Some((
2525            corrections,
2526            String::from("a macro with this name exists at the root of the crate"),
2527            Applicability::MaybeIncorrect,
2528        ));
2529        Some((
2530            suggestion,
2531            Some(
2532                "this could be because a macro annotated with `#[macro_export]` will be exported \
2533            at the root of the crate instead of the module where it is defined"
2534                    .to_string(),
2535            ),
2536        ))
2537    }
2538
2539    /// Finds a cfg-ed out item inside `module` with the matching name.
2540    pub(crate) fn find_cfg_stripped(&self, err: &mut Diag<'_>, segment: &Symbol, module: DefId) {
2541        let local_items;
2542        let symbols = if module.is_local() {
2543            local_items = self
2544                .stripped_cfg_items
2545                .iter()
2546                .filter_map(|item| {
2547                    let parent_module = self.opt_local_def_id(item.parent_module)?.to_def_id();
2548                    Some(StrippedCfgItem { parent_module, name: item.name, cfg: item.cfg.clone() })
2549                })
2550                .collect::<Vec<_>>();
2551            local_items.as_slice()
2552        } else {
2553            self.tcx.stripped_cfg_items(module.krate)
2554        };
2555
2556        for &StrippedCfgItem { parent_module, name, ref cfg } in symbols {
2557            if parent_module != module || name.name != *segment {
2558                continue;
2559            }
2560
2561            let note = errors::FoundItemConfigureOut { span: name.span };
2562            err.subdiagnostic(note);
2563
2564            if let MetaItemKind::List(nested) = &cfg.kind
2565                && let MetaItemInner::MetaItem(meta_item) = &nested[0]
2566                && let MetaItemKind::NameValue(feature_name) = &meta_item.kind
2567            {
2568                let note = errors::ItemWasBehindFeature {
2569                    feature: feature_name.symbol,
2570                    span: meta_item.span,
2571                };
2572                err.subdiagnostic(note);
2573            } else {
2574                let note = errors::ItemWasCfgOut { span: cfg.span };
2575                err.subdiagnostic(note);
2576            }
2577        }
2578    }
2579}
2580
2581/// Given a `binding_span` of a binding within a use statement:
2582///
2583/// ```ignore (illustrative)
2584/// use foo::{a, b, c};
2585/// //           ^
2586/// ```
2587///
2588/// then return the span until the next binding or the end of the statement:
2589///
2590/// ```ignore (illustrative)
2591/// use foo::{a, b, c};
2592/// //           ^^^
2593/// ```
2594fn find_span_of_binding_until_next_binding(
2595    sess: &Session,
2596    binding_span: Span,
2597    use_span: Span,
2598) -> (bool, Span) {
2599    let source_map = sess.source_map();
2600
2601    // Find the span of everything after the binding.
2602    //   ie. `a, e};` or `a};`
2603    let binding_until_end = binding_span.with_hi(use_span.hi());
2604
2605    // Find everything after the binding but not including the binding.
2606    //   ie. `, e};` or `};`
2607    let after_binding_until_end = binding_until_end.with_lo(binding_span.hi());
2608
2609    // Keep characters in the span until we encounter something that isn't a comma or
2610    // whitespace.
2611    //   ie. `, ` or ``.
2612    //
2613    // Also note whether a closing brace character was encountered. If there
2614    // was, then later go backwards to remove any trailing commas that are left.
2615    let mut found_closing_brace = false;
2616    let after_binding_until_next_binding =
2617        source_map.span_take_while(after_binding_until_end, |&ch| {
2618            if ch == '}' {
2619                found_closing_brace = true;
2620            }
2621            ch == ' ' || ch == ','
2622        });
2623
2624    // Combine the two spans.
2625    //   ie. `a, ` or `a`.
2626    //
2627    // Removing these would leave `issue_52891::{d, e};` or `issue_52891::{d, e, };`
2628    let span = binding_span.with_hi(after_binding_until_next_binding.hi());
2629
2630    (found_closing_brace, span)
2631}
2632
2633/// Given a `binding_span`, return the span through to the comma or opening brace of the previous
2634/// binding.
2635///
2636/// ```ignore (illustrative)
2637/// use foo::a::{a, b, c};
2638/// //            ^^--- binding span
2639/// //            |
2640/// //            returned span
2641///
2642/// use foo::{a, b, c};
2643/// //        --- binding span
2644/// ```
2645fn extend_span_to_previous_binding(sess: &Session, binding_span: Span) -> Option<Span> {
2646    let source_map = sess.source_map();
2647
2648    // `prev_source` will contain all of the source that came before the span.
2649    // Then split based on a command and take the first (ie. closest to our span)
2650    // snippet. In the example, this is a space.
2651    let prev_source = source_map.span_to_prev_source(binding_span).ok()?;
2652
2653    let prev_comma = prev_source.rsplit(',').collect::<Vec<_>>();
2654    let prev_starting_brace = prev_source.rsplit('{').collect::<Vec<_>>();
2655    if prev_comma.len() <= 1 || prev_starting_brace.len() <= 1 {
2656        return None;
2657    }
2658
2659    let prev_comma = prev_comma.first().unwrap();
2660    let prev_starting_brace = prev_starting_brace.first().unwrap();
2661
2662    // If the amount of source code before the comma is greater than
2663    // the amount of source code before the starting brace then we've only
2664    // got one item in the nested item (eg. `issue_52891::{self}`).
2665    if prev_comma.len() > prev_starting_brace.len() {
2666        return None;
2667    }
2668
2669    Some(binding_span.with_lo(BytePos(
2670        // Take away the number of bytes for the characters we've found and an
2671        // extra for the comma.
2672        binding_span.lo().0 - (prev_comma.as_bytes().len() as u32) - 1,
2673    )))
2674}
2675
2676/// Given a `use_span` of a binding within a use statement, returns the highlighted span and if
2677/// it is a nested use tree.
2678///
2679/// ```ignore (illustrative)
2680/// use foo::a::{b, c};
2681/// //       ^^^^^^^^^^ -- false
2682///
2683/// use foo::{a, b, c};
2684/// //       ^^^^^^^^^^ -- true
2685///
2686/// use foo::{a, b::{c, d}};
2687/// //       ^^^^^^^^^^^^^^^ -- true
2688/// ```
2689#[instrument(level = "debug", skip(sess))]
2690fn find_span_immediately_after_crate_name(
2691    sess: &Session,
2692    module_name: Symbol,
2693    use_span: Span,
2694) -> (bool, Span) {
2695    let source_map = sess.source_map();
2696
2697    // Using `use issue_59764::foo::{baz, makro};` as an example throughout..
2698    let mut num_colons = 0;
2699    // Find second colon.. `use issue_59764:`
2700    let until_second_colon = source_map.span_take_while(use_span, |c| {
2701        if *c == ':' {
2702            num_colons += 1;
2703        }
2704        !matches!(c, ':' if num_colons == 2)
2705    });
2706    // Find everything after the second colon.. `foo::{baz, makro};`
2707    let from_second_colon = use_span.with_lo(until_second_colon.hi() + BytePos(1));
2708
2709    let mut found_a_non_whitespace_character = false;
2710    // Find the first non-whitespace character in `from_second_colon`.. `f`
2711    let after_second_colon = source_map.span_take_while(from_second_colon, |c| {
2712        if found_a_non_whitespace_character {
2713            return false;
2714        }
2715        if !c.is_whitespace() {
2716            found_a_non_whitespace_character = true;
2717        }
2718        true
2719    });
2720
2721    // Find the first `{` in from_second_colon.. `foo::{`
2722    let next_left_bracket = source_map.span_through_char(from_second_colon, '{');
2723
2724    (next_left_bracket == after_second_colon, from_second_colon)
2725}
2726
2727/// A suggestion has already been emitted, change the wording slightly to clarify that both are
2728/// independent options.
2729enum Instead {
2730    Yes,
2731    No,
2732}
2733
2734/// Whether an existing place with an `use` item was found.
2735enum FoundUse {
2736    Yes,
2737    No,
2738}
2739
2740/// Whether a binding is part of a pattern or a use statement. Used for diagnostics.
2741pub(crate) enum DiagMode {
2742    Normal,
2743    /// The binding is part of a pattern
2744    Pattern,
2745    /// The binding is part of a use statement
2746    Import {
2747        /// `true` mean add the tips afterward for case `use a::{b,c}`,
2748        /// rather than replacing within.
2749        append: bool,
2750    },
2751}
2752
2753pub(crate) fn import_candidates(
2754    tcx: TyCtxt<'_>,
2755    err: &mut Diag<'_>,
2756    // This is `None` if all placement locations are inside expansions
2757    use_placement_span: Option<Span>,
2758    candidates: &[ImportSuggestion],
2759    mode: DiagMode,
2760    append: &str,
2761) {
2762    show_candidates(
2763        tcx,
2764        err,
2765        use_placement_span,
2766        candidates,
2767        Instead::Yes,
2768        FoundUse::Yes,
2769        mode,
2770        vec![],
2771        append,
2772    );
2773}
2774
2775type PathString<'a> = (String, &'a str, Option<Span>, &'a Option<String>, bool);
2776
2777/// When an entity with a given name is not available in scope, we search for
2778/// entities with that name in all crates. This method allows outputting the
2779/// results of this search in a programmer-friendly way. If any entities are
2780/// found and suggested, returns `true`, otherwise returns `false`.
2781fn show_candidates(
2782    tcx: TyCtxt<'_>,
2783    err: &mut Diag<'_>,
2784    // This is `None` if all placement locations are inside expansions
2785    use_placement_span: Option<Span>,
2786    candidates: &[ImportSuggestion],
2787    instead: Instead,
2788    found_use: FoundUse,
2789    mode: DiagMode,
2790    path: Vec<Segment>,
2791    append: &str,
2792) -> bool {
2793    if candidates.is_empty() {
2794        return false;
2795    }
2796
2797    let mut accessible_path_strings: Vec<PathString<'_>> = Vec::new();
2798    let mut inaccessible_path_strings: Vec<PathString<'_>> = Vec::new();
2799
2800    candidates.iter().for_each(|c| {
2801        if c.accessible {
2802            // Don't suggest `#[doc(hidden)]` items from other crates
2803            if c.doc_visible {
2804                accessible_path_strings.push((
2805                    pprust::path_to_string(&c.path),
2806                    c.descr,
2807                    c.did.and_then(|did| Some(tcx.source_span(did.as_local()?))),
2808                    &c.note,
2809                    c.via_import,
2810                ))
2811            }
2812        } else {
2813            inaccessible_path_strings.push((
2814                pprust::path_to_string(&c.path),
2815                c.descr,
2816                c.did.and_then(|did| Some(tcx.source_span(did.as_local()?))),
2817                &c.note,
2818                c.via_import,
2819            ))
2820        }
2821    });
2822
2823    // we want consistent results across executions, but candidates are produced
2824    // by iterating through a hash map, so make sure they are ordered:
2825    for path_strings in [&mut accessible_path_strings, &mut inaccessible_path_strings] {
2826        path_strings.sort_by(|a, b| a.0.cmp(&b.0));
2827        path_strings.dedup_by(|a, b| a.0 == b.0);
2828        let core_path_strings =
2829            path_strings.extract_if(.., |p| p.0.starts_with("core::")).collect::<Vec<_>>();
2830        let std_path_strings =
2831            path_strings.extract_if(.., |p| p.0.starts_with("std::")).collect::<Vec<_>>();
2832        let foreign_crate_path_strings =
2833            path_strings.extract_if(.., |p| !p.0.starts_with("crate::")).collect::<Vec<_>>();
2834
2835        // We list the `crate` local paths first.
2836        // Then we list the `std`/`core` paths.
2837        if std_path_strings.len() == core_path_strings.len() {
2838            // Do not list `core::` paths if we are already listing the `std::` ones.
2839            path_strings.extend(std_path_strings);
2840        } else {
2841            path_strings.extend(std_path_strings);
2842            path_strings.extend(core_path_strings);
2843        }
2844        // List all paths from foreign crates last.
2845        path_strings.extend(foreign_crate_path_strings);
2846    }
2847
2848    if !accessible_path_strings.is_empty() {
2849        let (determiner, kind, s, name, through) =
2850            if let [(name, descr, _, _, via_import)] = &accessible_path_strings[..] {
2851                (
2852                    "this",
2853                    *descr,
2854                    "",
2855                    format!(" `{name}`"),
2856                    if *via_import { " through its public re-export" } else { "" },
2857                )
2858            } else {
2859                // Get the unique item kinds and if there's only one, we use the right kind name
2860                // instead of the more generic "items".
2861                let mut kinds = accessible_path_strings
2862                    .iter()
2863                    .map(|(_, descr, _, _, _)| *descr)
2864                    .collect::<FxHashSet<&str>>()
2865                    .into_iter();
2866                let kind = if let Some(kind) = kinds.next()
2867                    && let None = kinds.next()
2868                {
2869                    kind
2870                } else {
2871                    "item"
2872                };
2873                let s = if kind.ends_with('s') { "es" } else { "s" };
2874
2875                ("one of these", kind, s, String::new(), "")
2876            };
2877
2878        let instead = if let Instead::Yes = instead { " instead" } else { "" };
2879        let mut msg = if let DiagMode::Pattern = mode {
2880            format!(
2881                "if you meant to match on {kind}{s}{instead}{name}, use the full path in the \
2882                 pattern",
2883            )
2884        } else {
2885            format!("consider importing {determiner} {kind}{s}{through}{instead}")
2886        };
2887
2888        for note in accessible_path_strings.iter().flat_map(|cand| cand.3.as_ref()) {
2889            err.note(note.clone());
2890        }
2891
2892        let append_candidates = |msg: &mut String, accessible_path_strings: Vec<PathString<'_>>| {
2893            msg.push(':');
2894
2895            for candidate in accessible_path_strings {
2896                msg.push('\n');
2897                msg.push_str(&candidate.0);
2898            }
2899        };
2900
2901        if let Some(span) = use_placement_span {
2902            let (add_use, trailing) = match mode {
2903                DiagMode::Pattern => {
2904                    err.span_suggestions(
2905                        span,
2906                        msg,
2907                        accessible_path_strings.into_iter().map(|a| a.0),
2908                        Applicability::MaybeIncorrect,
2909                    );
2910                    return true;
2911                }
2912                DiagMode::Import { .. } => ("", ""),
2913                DiagMode::Normal => ("use ", ";\n"),
2914            };
2915            for candidate in &mut accessible_path_strings {
2916                // produce an additional newline to separate the new use statement
2917                // from the directly following item.
2918                let additional_newline = if let FoundUse::No = found_use
2919                    && let DiagMode::Normal = mode
2920                {
2921                    "\n"
2922                } else {
2923                    ""
2924                };
2925                candidate.0 =
2926                    format!("{add_use}{}{append}{trailing}{additional_newline}", candidate.0);
2927            }
2928
2929            match mode {
2930                DiagMode::Import { append: true, .. } => {
2931                    append_candidates(&mut msg, accessible_path_strings);
2932                    err.span_help(span, msg);
2933                }
2934                _ => {
2935                    err.span_suggestions_with_style(
2936                        span,
2937                        msg,
2938                        accessible_path_strings.into_iter().map(|a| a.0),
2939                        Applicability::MaybeIncorrect,
2940                        SuggestionStyle::ShowAlways,
2941                    );
2942                }
2943            }
2944
2945            if let [first, .., last] = &path[..] {
2946                let sp = first.ident.span.until(last.ident.span);
2947                // Our suggestion is empty, so make sure the span is not empty (or we'd ICE).
2948                // Can happen for derive-generated spans.
2949                if sp.can_be_used_for_suggestions() && !sp.is_empty() {
2950                    err.span_suggestion_verbose(
2951                        sp,
2952                        format!("if you import `{}`, refer to it directly", last.ident),
2953                        "",
2954                        Applicability::Unspecified,
2955                    );
2956                }
2957            }
2958        } else {
2959            append_candidates(&mut msg, accessible_path_strings);
2960            err.help(msg);
2961        }
2962        true
2963    } else if !(inaccessible_path_strings.is_empty() || matches!(mode, DiagMode::Import { .. })) {
2964        let prefix =
2965            if let DiagMode::Pattern = mode { "you might have meant to match on " } else { "" };
2966        if let [(name, descr, source_span, note, _)] = &inaccessible_path_strings[..] {
2967            let msg = format!(
2968                "{prefix}{descr} `{name}`{} exists but is inaccessible",
2969                if let DiagMode::Pattern = mode { ", which" } else { "" }
2970            );
2971
2972            if let Some(source_span) = source_span {
2973                let span = tcx.sess.source_map().guess_head_span(*source_span);
2974                let mut multi_span = MultiSpan::from_span(span);
2975                multi_span.push_span_label(span, "not accessible");
2976                err.span_note(multi_span, msg);
2977            } else {
2978                err.note(msg);
2979            }
2980            if let Some(note) = (*note).as_deref() {
2981                err.note(note.to_string());
2982            }
2983        } else {
2984            let (_, descr_first, _, _, _) = &inaccessible_path_strings[0];
2985            let descr = if inaccessible_path_strings
2986                .iter()
2987                .skip(1)
2988                .all(|(_, descr, _, _, _)| descr == descr_first)
2989            {
2990                descr_first
2991            } else {
2992                "item"
2993            };
2994            let plural_descr =
2995                if descr.ends_with('s') { format!("{descr}es") } else { format!("{descr}s") };
2996
2997            let mut msg = format!("{prefix}these {plural_descr} exist but are inaccessible");
2998            let mut has_colon = false;
2999
3000            let mut spans = Vec::new();
3001            for (name, _, source_span, _, _) in &inaccessible_path_strings {
3002                if let Some(source_span) = source_span {
3003                    let span = tcx.sess.source_map().guess_head_span(*source_span);
3004                    spans.push((name, span));
3005                } else {
3006                    if !has_colon {
3007                        msg.push(':');
3008                        has_colon = true;
3009                    }
3010                    msg.push('\n');
3011                    msg.push_str(name);
3012                }
3013            }
3014
3015            let mut multi_span = MultiSpan::from_spans(spans.iter().map(|(_, sp)| *sp).collect());
3016            for (name, span) in spans {
3017                multi_span.push_span_label(span, format!("`{name}`: not accessible"));
3018            }
3019
3020            for note in inaccessible_path_strings.iter().flat_map(|cand| cand.3.as_ref()) {
3021                err.note(note.clone());
3022            }
3023
3024            err.span_note(multi_span, msg);
3025        }
3026        true
3027    } else {
3028        false
3029    }
3030}
3031
3032#[derive(Debug)]
3033struct UsePlacementFinder {
3034    target_module: NodeId,
3035    first_legal_span: Option<Span>,
3036    first_use_span: Option<Span>,
3037}
3038
3039impl UsePlacementFinder {
3040    fn check(krate: &Crate, target_module: NodeId) -> (Option<Span>, FoundUse) {
3041        let mut finder =
3042            UsePlacementFinder { target_module, first_legal_span: None, first_use_span: None };
3043        finder.visit_crate(krate);
3044        if let Some(use_span) = finder.first_use_span {
3045            (Some(use_span), FoundUse::Yes)
3046        } else {
3047            (finder.first_legal_span, FoundUse::No)
3048        }
3049    }
3050}
3051
3052impl<'tcx> visit::Visitor<'tcx> for UsePlacementFinder {
3053    fn visit_crate(&mut self, c: &Crate) {
3054        if self.target_module == CRATE_NODE_ID {
3055            let inject = c.spans.inject_use_span;
3056            if is_span_suitable_for_use_injection(inject) {
3057                self.first_legal_span = Some(inject);
3058            }
3059            self.first_use_span = search_for_any_use_in_items(&c.items);
3060        } else {
3061            visit::walk_crate(self, c);
3062        }
3063    }
3064
3065    fn visit_item(&mut self, item: &'tcx ast::Item) {
3066        if self.target_module == item.id {
3067            if let ItemKind::Mod(_, ModKind::Loaded(items, _inline, mod_spans, _)) = &item.kind {
3068                let inject = mod_spans.inject_use_span;
3069                if is_span_suitable_for_use_injection(inject) {
3070                    self.first_legal_span = Some(inject);
3071                }
3072                self.first_use_span = search_for_any_use_in_items(items);
3073            }
3074        } else {
3075            visit::walk_item(self, item);
3076        }
3077    }
3078}
3079
3080fn search_for_any_use_in_items(items: &[P<ast::Item>]) -> Option<Span> {
3081    for item in items {
3082        if let ItemKind::Use(..) = item.kind
3083            && is_span_suitable_for_use_injection(item.span)
3084        {
3085            let mut lo = item.span.lo();
3086            for attr in &item.attrs {
3087                if attr.span.eq_ctxt(item.span) {
3088                    lo = std::cmp::min(lo, attr.span.lo());
3089                }
3090            }
3091            return Some(Span::new(lo, lo, item.span.ctxt(), item.span.parent()));
3092        }
3093    }
3094    None
3095}
3096
3097fn is_span_suitable_for_use_injection(s: Span) -> bool {
3098    // don't suggest placing a use before the prelude
3099    // import or other generated ones
3100    !s.from_expansion()
3101}