]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_resolve/src/diagnostics.rs
Rollup merge of #106739 - WaffleLapkin:astconv, r=estebank
[rust.git] / compiler / rustc_resolve / src / diagnostics.rs
1 use std::ptr;
2
3 use rustc_ast::ptr::P;
4 use rustc_ast::visit::{self, Visitor};
5 use rustc_ast::{self as ast, Crate, ItemKind, ModKind, NodeId, Path, CRATE_NODE_ID};
6 use rustc_ast_pretty::pprust;
7 use rustc_data_structures::fx::FxHashSet;
8 use rustc_errors::struct_span_err;
9 use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, MultiSpan};
10 use rustc_feature::BUILTIN_ATTRIBUTES;
11 use rustc_hir::def::Namespace::{self, *};
12 use rustc_hir::def::{self, CtorKind, CtorOf, DefKind, NonMacroAttrKind, PerNS};
13 use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID, LOCAL_CRATE};
14 use rustc_hir::PrimTy;
15 use rustc_index::vec::IndexVec;
16 use rustc_middle::bug;
17 use rustc_middle::ty::DefIdTree;
18 use rustc_session::lint::builtin::ABSOLUTE_PATHS_NOT_STARTING_WITH_CRATE;
19 use rustc_session::lint::builtin::MACRO_EXPANDED_MACRO_EXPORTS_ACCESSED_BY_ABSOLUTE_PATHS;
20 use rustc_session::lint::BuiltinLintDiagnostics;
21 use rustc_session::Session;
22 use rustc_span::edition::Edition;
23 use rustc_span::hygiene::MacroKind;
24 use rustc_span::lev_distance::find_best_match_for_name;
25 use rustc_span::source_map::SourceMap;
26 use rustc_span::symbol::{kw, sym, Ident, Symbol};
27 use rustc_span::{BytePos, Span, SyntaxContext};
28 use thin_vec::ThinVec;
29
30 use crate::errors as errs;
31 use crate::imports::{Import, ImportKind, ImportResolver};
32 use crate::late::{PatternSource, Rib};
33 use crate::path_names_to_string;
34 use crate::{AmbiguityError, AmbiguityErrorMisc, AmbiguityKind, BindingError, Finalize};
35 use crate::{HasGenericParams, MacroRulesScope, Module, ModuleKind, ModuleOrUniformRoot};
36 use crate::{LexicalScopeBinding, NameBinding, NameBindingKind, PrivacyError, VisResolutionError};
37 use crate::{ParentScope, PathResult, ResolutionError, Resolver, Scope, ScopeSet};
38 use crate::{Segment, UseError};
39
40 #[cfg(test)]
41 mod tests;
42
43 type Res = def::Res<ast::NodeId>;
44
45 /// A vector of spans and replacements, a message and applicability.
46 pub(crate) type Suggestion = (Vec<(Span, String)>, String, Applicability);
47
48 /// Potential candidate for an undeclared or out-of-scope label - contains the ident of a
49 /// similarly named label and whether or not it is reachable.
50 pub(crate) type LabelSuggestion = (Ident, bool);
51
52 #[derive(Debug)]
53 pub(crate) enum SuggestionTarget {
54     /// The target has a similar name as the name used by the programmer (probably a typo)
55     SimilarlyNamed,
56     /// The target is the only valid item that can be used in the corresponding context
57     SingleItem,
58 }
59
60 #[derive(Debug)]
61 pub(crate) struct TypoSuggestion {
62     pub candidate: Symbol,
63     /// The source location where the name is defined; None if the name is not defined
64     /// in source e.g. primitives
65     pub span: Option<Span>,
66     pub res: Res,
67     pub target: SuggestionTarget,
68 }
69
70 impl TypoSuggestion {
71     pub(crate) fn typo_from_ident(ident: Ident, res: Res) -> TypoSuggestion {
72         Self {
73             candidate: ident.name,
74             span: Some(ident.span),
75             res,
76             target: SuggestionTarget::SimilarlyNamed,
77         }
78     }
79     pub(crate) fn typo_from_name(candidate: Symbol, res: Res) -> TypoSuggestion {
80         Self { candidate, span: None, res, target: SuggestionTarget::SimilarlyNamed }
81     }
82     pub(crate) fn single_item_from_ident(ident: Ident, res: Res) -> TypoSuggestion {
83         Self {
84             candidate: ident.name,
85             span: Some(ident.span),
86             res,
87             target: SuggestionTarget::SingleItem,
88         }
89     }
90 }
91
92 /// A free importable items suggested in case of resolution failure.
93 #[derive(Debug, Clone)]
94 pub(crate) struct ImportSuggestion {
95     pub did: Option<DefId>,
96     pub descr: &'static str,
97     pub path: Path,
98     pub accessible: bool,
99     /// An extra note that should be issued if this item is suggested
100     pub note: Option<String>,
101 }
102
103 /// Adjust the impl span so that just the `impl` keyword is taken by removing
104 /// everything after `<` (`"impl<T> Iterator for A<T> {}" -> "impl"`) and
105 /// everything after the first whitespace (`"impl Iterator for A" -> "impl"`).
106 ///
107 /// *Attention*: the method used is very fragile since it essentially duplicates the work of the
108 /// parser. If you need to use this function or something similar, please consider updating the
109 /// `source_map` functions and this function to something more robust.
110 fn reduce_impl_span_to_impl_keyword(sm: &SourceMap, impl_span: Span) -> Span {
111     let impl_span = sm.span_until_char(impl_span, '<');
112     sm.span_until_whitespace(impl_span)
113 }
114
115 impl<'a> Resolver<'a> {
116     pub(crate) fn report_errors(&mut self, krate: &Crate) {
117         self.report_with_use_injections(krate);
118
119         for &(span_use, span_def) in &self.macro_expanded_macro_export_errors {
120             let msg = "macro-expanded `macro_export` macros from the current crate \
121                        cannot be referred to by absolute paths";
122             self.lint_buffer.buffer_lint_with_diagnostic(
123                 MACRO_EXPANDED_MACRO_EXPORTS_ACCESSED_BY_ABSOLUTE_PATHS,
124                 CRATE_NODE_ID,
125                 span_use,
126                 msg,
127                 BuiltinLintDiagnostics::MacroExpandedMacroExportsAccessedByAbsolutePaths(span_def),
128             );
129         }
130
131         for ambiguity_error in &self.ambiguity_errors {
132             self.report_ambiguity_error(ambiguity_error);
133         }
134
135         let mut reported_spans = FxHashSet::default();
136         for error in &self.privacy_errors {
137             if reported_spans.insert(error.dedup_span) {
138                 self.report_privacy_error(error);
139             }
140         }
141     }
142
143     fn report_with_use_injections(&mut self, krate: &Crate) {
144         for UseError { mut err, candidates, def_id, instead, suggestion, path, is_call } in
145             self.use_injections.drain(..)
146         {
147             let (span, found_use) = if let Some(def_id) = def_id.as_local() {
148                 UsePlacementFinder::check(krate, self.def_id_to_node_id[def_id])
149             } else {
150                 (None, FoundUse::No)
151             };
152
153             if !candidates.is_empty() {
154                 show_candidates(
155                     &self.session,
156                     &self.untracked.source_span,
157                     &mut err,
158                     span,
159                     &candidates,
160                     if instead { Instead::Yes } else { Instead::No },
161                     found_use,
162                     DiagnosticMode::Normal,
163                     path,
164                     "",
165                 );
166                 err.emit();
167             } else if let Some((span, msg, sugg, appl)) = suggestion {
168                 err.span_suggestion(span, msg, sugg, appl);
169                 err.emit();
170             } else if let [segment] = path.as_slice() && is_call {
171                 err.stash(segment.ident.span, rustc_errors::StashKey::CallIntoMethod);
172             } else {
173                 err.emit();
174             }
175         }
176     }
177
178     pub(crate) fn report_conflict<'b>(
179         &mut self,
180         parent: Module<'_>,
181         ident: Ident,
182         ns: Namespace,
183         new_binding: &NameBinding<'b>,
184         old_binding: &NameBinding<'b>,
185     ) {
186         // Error on the second of two conflicting names
187         if old_binding.span.lo() > new_binding.span.lo() {
188             return self.report_conflict(parent, ident, ns, old_binding, new_binding);
189         }
190
191         let container = match parent.kind {
192             ModuleKind::Def(kind, _, _) => kind.descr(parent.def_id()),
193             ModuleKind::Block => "block",
194         };
195
196         let old_noun = match old_binding.is_import_user_facing() {
197             true => "import",
198             false => "definition",
199         };
200
201         let new_participle = match new_binding.is_import_user_facing() {
202             true => "imported",
203             false => "defined",
204         };
205
206         let (name, span) =
207             (ident.name, self.session.source_map().guess_head_span(new_binding.span));
208
209         if let Some(s) = self.name_already_seen.get(&name) {
210             if s == &span {
211                 return;
212             }
213         }
214
215         let old_kind = match (ns, old_binding.module()) {
216             (ValueNS, _) => "value",
217             (MacroNS, _) => "macro",
218             (TypeNS, _) if old_binding.is_extern_crate() => "extern crate",
219             (TypeNS, Some(module)) if module.is_normal() => "module",
220             (TypeNS, Some(module)) if module.is_trait() => "trait",
221             (TypeNS, _) => "type",
222         };
223
224         let msg = format!("the name `{}` is defined multiple times", name);
225
226         let mut err = match (old_binding.is_extern_crate(), new_binding.is_extern_crate()) {
227             (true, true) => struct_span_err!(self.session, span, E0259, "{}", msg),
228             (true, _) | (_, true) => match new_binding.is_import() && old_binding.is_import() {
229                 true => struct_span_err!(self.session, span, E0254, "{}", msg),
230                 false => struct_span_err!(self.session, span, E0260, "{}", msg),
231             },
232             _ => match (old_binding.is_import_user_facing(), new_binding.is_import_user_facing()) {
233                 (false, false) => struct_span_err!(self.session, span, E0428, "{}", msg),
234                 (true, true) => struct_span_err!(self.session, span, E0252, "{}", msg),
235                 _ => struct_span_err!(self.session, span, E0255, "{}", msg),
236             },
237         };
238
239         err.note(&format!(
240             "`{}` must be defined only once in the {} namespace of this {}",
241             name,
242             ns.descr(),
243             container
244         ));
245
246         err.span_label(span, format!("`{}` re{} here", name, new_participle));
247         if !old_binding.span.is_dummy() && old_binding.span != span {
248             err.span_label(
249                 self.session.source_map().guess_head_span(old_binding.span),
250                 format!("previous {} of the {} `{}` here", old_noun, old_kind, name),
251             );
252         }
253
254         // See https://github.com/rust-lang/rust/issues/32354
255         use NameBindingKind::Import;
256         let can_suggest = |binding: &NameBinding<'_>, import: &self::Import<'_>| {
257             !binding.span.is_dummy()
258                 && !matches!(import.kind, ImportKind::MacroUse | ImportKind::MacroExport)
259         };
260         let import = match (&new_binding.kind, &old_binding.kind) {
261             // If there are two imports where one or both have attributes then prefer removing the
262             // import without attributes.
263             (Import { import: new, .. }, Import { import: old, .. })
264                 if {
265                     (new.has_attributes || old.has_attributes)
266                         && can_suggest(old_binding, old)
267                         && can_suggest(new_binding, new)
268                 } =>
269             {
270                 if old.has_attributes {
271                     Some((new, new_binding.span, true))
272                 } else {
273                     Some((old, old_binding.span, true))
274                 }
275             }
276             // Otherwise prioritize the new binding.
277             (Import { import, .. }, other) if can_suggest(new_binding, import) => {
278                 Some((import, new_binding.span, other.is_import()))
279             }
280             (other, Import { import, .. }) if can_suggest(old_binding, import) => {
281                 Some((import, old_binding.span, other.is_import()))
282             }
283             _ => None,
284         };
285
286         // Check if the target of the use for both bindings is the same.
287         let duplicate = new_binding.res().opt_def_id() == old_binding.res().opt_def_id();
288         let has_dummy_span = new_binding.span.is_dummy() || old_binding.span.is_dummy();
289         let from_item =
290             self.extern_prelude.get(&ident).map_or(true, |entry| entry.introduced_by_item);
291         // Only suggest removing an import if both bindings are to the same def, if both spans
292         // aren't dummy spans. Further, if both bindings are imports, then the ident must have
293         // been introduced by an item.
294         let should_remove_import = duplicate
295             && !has_dummy_span
296             && ((new_binding.is_extern_crate() || old_binding.is_extern_crate()) || from_item);
297
298         match import {
299             Some((import, span, true)) if should_remove_import && import.is_nested() => {
300                 self.add_suggestion_for_duplicate_nested_use(&mut err, import, span)
301             }
302             Some((import, _, true)) if should_remove_import && !import.is_glob() => {
303                 // Simple case - remove the entire import. Due to the above match arm, this can
304                 // only be a single use so just remove it entirely.
305                 err.tool_only_span_suggestion(
306                     import.use_span_with_attributes,
307                     "remove unnecessary import",
308                     "",
309                     Applicability::MaybeIncorrect,
310                 );
311             }
312             Some((import, span, _)) => {
313                 self.add_suggestion_for_rename_of_use(&mut err, name, import, span)
314             }
315             _ => {}
316         }
317
318         err.emit();
319         self.name_already_seen.insert(name, span);
320     }
321
322     /// This function adds a suggestion to change the binding name of a new import that conflicts
323     /// with an existing import.
324     ///
325     /// ```text,ignore (diagnostic)
326     /// help: you can use `as` to change the binding name of the import
327     ///    |
328     /// LL | use foo::bar as other_bar;
329     ///    |     ^^^^^^^^^^^^^^^^^^^^^
330     /// ```
331     fn add_suggestion_for_rename_of_use(
332         &self,
333         err: &mut Diagnostic,
334         name: Symbol,
335         import: &Import<'_>,
336         binding_span: Span,
337     ) {
338         let suggested_name = if name.as_str().chars().next().unwrap().is_uppercase() {
339             format!("Other{}", name)
340         } else {
341             format!("other_{}", name)
342         };
343
344         let mut suggestion = None;
345         match import.kind {
346             ImportKind::Single { type_ns_only: true, .. } => {
347                 suggestion = Some(format!("self as {}", suggested_name))
348             }
349             ImportKind::Single { source, .. } => {
350                 if let Some(pos) =
351                     source.span.hi().0.checked_sub(binding_span.lo().0).map(|pos| pos as usize)
352                 {
353                     if let Ok(snippet) = self.session.source_map().span_to_snippet(binding_span) {
354                         if pos <= snippet.len() {
355                             suggestion = Some(format!(
356                                 "{} as {}{}",
357                                 &snippet[..pos],
358                                 suggested_name,
359                                 if snippet.ends_with(';') { ";" } else { "" }
360                             ))
361                         }
362                     }
363                 }
364             }
365             ImportKind::ExternCrate { source, target, .. } => {
366                 suggestion = Some(format!(
367                     "extern crate {} as {};",
368                     source.unwrap_or(target.name),
369                     suggested_name,
370                 ))
371             }
372             _ => unreachable!(),
373         }
374
375         let rename_msg = "you can use `as` to change the binding name of the import";
376         if let Some(suggestion) = suggestion {
377             err.span_suggestion(
378                 binding_span,
379                 rename_msg,
380                 suggestion,
381                 Applicability::MaybeIncorrect,
382             );
383         } else {
384             err.span_label(binding_span, rename_msg);
385         }
386     }
387
388     /// This function adds a suggestion to remove an unnecessary binding from an import that is
389     /// nested. In the following example, this function will be invoked to remove the `a` binding
390     /// in the second use statement:
391     ///
392     /// ```ignore (diagnostic)
393     /// use issue_52891::a;
394     /// use issue_52891::{d, a, e};
395     /// ```
396     ///
397     /// The following suggestion will be added:
398     ///
399     /// ```ignore (diagnostic)
400     /// use issue_52891::{d, a, e};
401     ///                      ^-- help: remove unnecessary import
402     /// ```
403     ///
404     /// If the nested use contains only one import then the suggestion will remove the entire
405     /// line.
406     ///
407     /// It is expected that the provided import is nested - this isn't checked by the
408     /// function. If this invariant is not upheld, this function's behaviour will be unexpected
409     /// as characters expected by span manipulations won't be present.
410     fn add_suggestion_for_duplicate_nested_use(
411         &self,
412         err: &mut Diagnostic,
413         import: &Import<'_>,
414         binding_span: Span,
415     ) {
416         assert!(import.is_nested());
417         let message = "remove unnecessary import";
418
419         // Two examples will be used to illustrate the span manipulations we're doing:
420         //
421         // - Given `use issue_52891::{d, a, e};` where `a` is a duplicate then `binding_span` is
422         //   `a` and `import.use_span` is `issue_52891::{d, a, e};`.
423         // - Given `use issue_52891::{d, e, a};` where `a` is a duplicate then `binding_span` is
424         //   `a` and `import.use_span` is `issue_52891::{d, e, a};`.
425
426         let (found_closing_brace, span) =
427             find_span_of_binding_until_next_binding(self.session, binding_span, import.use_span);
428
429         // If there was a closing brace then identify the span to remove any trailing commas from
430         // previous imports.
431         if found_closing_brace {
432             if let Some(span) = extend_span_to_previous_binding(self.session, span) {
433                 err.tool_only_span_suggestion(span, message, "", Applicability::MaybeIncorrect);
434             } else {
435                 // Remove the entire line if we cannot extend the span back, this indicates an
436                 // `issue_52891::{self}` case.
437                 err.span_suggestion(
438                     import.use_span_with_attributes,
439                     message,
440                     "",
441                     Applicability::MaybeIncorrect,
442                 );
443             }
444
445             return;
446         }
447
448         err.span_suggestion(span, message, "", Applicability::MachineApplicable);
449     }
450
451     pub(crate) fn lint_if_path_starts_with_module(
452         &mut self,
453         finalize: Option<Finalize>,
454         path: &[Segment],
455         second_binding: Option<&NameBinding<'_>>,
456     ) {
457         let Some(Finalize { node_id, root_span, .. }) = finalize else {
458             return;
459         };
460
461         let first_name = match path.get(0) {
462             // In the 2018 edition this lint is a hard error, so nothing to do
463             Some(seg) if seg.ident.span.rust_2015() && self.session.rust_2015() => seg.ident.name,
464             _ => return,
465         };
466
467         // We're only interested in `use` paths which should start with
468         // `{{root}}` currently.
469         if first_name != kw::PathRoot {
470             return;
471         }
472
473         match path.get(1) {
474             // If this import looks like `crate::...` it's already good
475             Some(Segment { ident, .. }) if ident.name == kw::Crate => return,
476             // Otherwise go below to see if it's an extern crate
477             Some(_) => {}
478             // If the path has length one (and it's `PathRoot` most likely)
479             // then we don't know whether we're gonna be importing a crate or an
480             // item in our crate. Defer this lint to elsewhere
481             None => return,
482         }
483
484         // If the first element of our path was actually resolved to an
485         // `ExternCrate` (also used for `crate::...`) then no need to issue a
486         // warning, this looks all good!
487         if let Some(binding) = second_binding {
488             if let NameBindingKind::Import { import, .. } = binding.kind {
489                 // Careful: we still want to rewrite paths from renamed extern crates.
490                 if let ImportKind::ExternCrate { source: None, .. } = import.kind {
491                     return;
492                 }
493             }
494         }
495
496         let diag = BuiltinLintDiagnostics::AbsPathWithModule(root_span);
497         self.lint_buffer.buffer_lint_with_diagnostic(
498             ABSOLUTE_PATHS_NOT_STARTING_WITH_CRATE,
499             node_id,
500             root_span,
501             "absolute paths must start with `self`, `super`, \
502              `crate`, or an external crate name in the 2018 edition",
503             diag,
504         );
505     }
506
507     pub(crate) fn add_module_candidates(
508         &mut self,
509         module: Module<'a>,
510         names: &mut Vec<TypoSuggestion>,
511         filter_fn: &impl Fn(Res) -> bool,
512         ctxt: Option<SyntaxContext>,
513     ) {
514         for (key, resolution) in self.resolutions(module).borrow().iter() {
515             if let Some(binding) = resolution.borrow().binding {
516                 let res = binding.res();
517                 if filter_fn(res) && ctxt.map_or(true, |ctxt| ctxt == key.ident.span.ctxt()) {
518                     names.push(TypoSuggestion::typo_from_ident(key.ident, res));
519                 }
520             }
521         }
522     }
523
524     /// Combines an error with provided span and emits it.
525     ///
526     /// This takes the error provided, combines it with the span and any additional spans inside the
527     /// error and emits it.
528     pub(crate) fn report_error(&mut self, span: Span, resolution_error: ResolutionError<'a>) {
529         self.into_struct_error(span, resolution_error).emit();
530     }
531
532     pub(crate) fn into_struct_error(
533         &mut self,
534         span: Span,
535         resolution_error: ResolutionError<'a>,
536     ) -> DiagnosticBuilder<'_, ErrorGuaranteed> {
537         match resolution_error {
538             ResolutionError::GenericParamsFromOuterFunction(outer_res, has_generic_params) => {
539                 let mut err = struct_span_err!(
540                     self.session,
541                     span,
542                     E0401,
543                     "can't use generic parameters from outer function",
544                 );
545                 err.span_label(span, "use of generic parameter from outer function");
546
547                 let sm = self.session.source_map();
548                 let def_id = match outer_res {
549                     Res::SelfTyParam { .. } => {
550                         err.span_label(span, "can't use `Self` here");
551                         return err;
552                     }
553                     Res::SelfTyAlias { alias_to: def_id, .. } => {
554                         if let Some(impl_span) = self.opt_span(def_id) {
555                             err.span_label(
556                                 reduce_impl_span_to_impl_keyword(sm, impl_span),
557                                 "`Self` type implicitly declared here, by this `impl`",
558                             );
559                         }
560                         err.span_label(span, "use a type here instead");
561                         return err;
562                     }
563                     Res::Def(DefKind::TyParam, def_id) => {
564                         if let Some(span) = self.opt_span(def_id) {
565                             err.span_label(span, "type parameter from outer function");
566                         }
567                         def_id
568                     }
569                     Res::Def(DefKind::ConstParam, def_id) => {
570                         if let Some(span) = self.opt_span(def_id) {
571                             err.span_label(span, "const parameter from outer function");
572                         }
573                         def_id
574                     }
575                     _ => {
576                         bug!(
577                             "GenericParamsFromOuterFunction should only be used with \
578                             Res::SelfTyParam, Res::SelfTyAlias, DefKind::TyParam or \
579                             DefKind::ConstParam"
580                         );
581                     }
582                 };
583
584                 if let HasGenericParams::Yes(span) = has_generic_params {
585                     // Try to retrieve the span of the function signature and generate a new
586                     // message with a local type or const parameter.
587                     let sugg_msg = "try using a local generic parameter instead";
588                     let name = self.opt_name(def_id).unwrap_or(sym::T);
589                     let (span, snippet) = if span.is_empty() {
590                         let snippet = format!("<{}>", name);
591                         (span, snippet)
592                     } else {
593                         let span = sm.span_through_char(span, '<').shrink_to_hi();
594                         let snippet = format!("{}, ", name);
595                         (span, snippet)
596                     };
597                     // Suggest the modification to the user
598                     err.span_suggestion(span, sugg_msg, snippet, Applicability::MaybeIncorrect);
599                 }
600
601                 err
602             }
603             ResolutionError::NameAlreadyUsedInParameterList(name, first_use_span) => self
604                 .session
605                 .create_err(errs::NameAlreadyUsedInParameterList { span, first_use_span, name }),
606             ResolutionError::MethodNotMemberOfTrait(method, trait_, candidate) => {
607                 self.session.create_err(errs::MethodNotMemberOfTrait {
608                     span,
609                     method,
610                     trait_,
611                     sub: candidate.map(|c| errs::AssociatedFnWithSimilarNameExists {
612                         span: method.span,
613                         candidate: c,
614                     }),
615                 })
616             }
617             ResolutionError::TypeNotMemberOfTrait(type_, trait_, candidate) => {
618                 self.session.create_err(errs::TypeNotMemberOfTrait {
619                     span,
620                     type_,
621                     trait_,
622                     sub: candidate.map(|c| errs::AssociatedTypeWithSimilarNameExists {
623                         span: type_.span,
624                         candidate: c,
625                     }),
626                 })
627             }
628             ResolutionError::ConstNotMemberOfTrait(const_, trait_, candidate) => {
629                 self.session.create_err(errs::ConstNotMemberOfTrait {
630                     span,
631                     const_,
632                     trait_,
633                     sub: candidate.map(|c| errs::AssociatedConstWithSimilarNameExists {
634                         span: const_.span,
635                         candidate: c,
636                     }),
637                 })
638             }
639             ResolutionError::VariableNotBoundInPattern(binding_error, parent_scope) => {
640                 let BindingError { name, target, origin, could_be_path } = binding_error;
641
642                 let target_sp = target.iter().copied().collect::<Vec<_>>();
643                 let origin_sp = origin.iter().copied().collect::<Vec<_>>();
644
645                 let msp = MultiSpan::from_spans(target_sp.clone());
646                 let mut err = struct_span_err!(
647                     self.session,
648                     msp,
649                     E0408,
650                     "variable `{}` is not bound in all patterns",
651                     name,
652                 );
653                 for sp in target_sp {
654                     err.span_label(sp, format!("pattern doesn't bind `{}`", name));
655                 }
656                 for sp in origin_sp {
657                     err.span_label(sp, "variable not in all patterns");
658                 }
659                 if could_be_path {
660                     let import_suggestions = self.lookup_import_candidates(
661                         Ident::with_dummy_span(name),
662                         Namespace::ValueNS,
663                         &parent_scope,
664                         &|res: Res| match res {
665                             Res::Def(
666                                 DefKind::Ctor(CtorOf::Variant, CtorKind::Const)
667                                 | DefKind::Ctor(CtorOf::Struct, CtorKind::Const)
668                                 | DefKind::Const
669                                 | DefKind::AssocConst,
670                                 _,
671                             ) => true,
672                             _ => false,
673                         },
674                     );
675
676                     if import_suggestions.is_empty() {
677                         let help_msg = format!(
678                             "if you meant to match on a variant or a `const` item, consider \
679                              making the path in the pattern qualified: `path::to::ModOrType::{}`",
680                             name,
681                         );
682                         err.span_help(span, &help_msg);
683                     }
684                     show_candidates(
685                         &self.session,
686                         &self.untracked.source_span,
687                         &mut err,
688                         Some(span),
689                         &import_suggestions,
690                         Instead::No,
691                         FoundUse::Yes,
692                         DiagnosticMode::Pattern,
693                         vec![],
694                         "",
695                     );
696                 }
697                 err
698             }
699             ResolutionError::VariableBoundWithDifferentMode(variable_name, first_binding_span) => {
700                 self.session.create_err(errs::VariableBoundWithDifferentMode {
701                     span,
702                     first_binding_span,
703                     variable_name,
704                 })
705             }
706             ResolutionError::IdentifierBoundMoreThanOnceInParameterList(identifier) => self
707                 .session
708                 .create_err(errs::IdentifierBoundMoreThanOnceInParameterList { span, identifier }),
709             ResolutionError::IdentifierBoundMoreThanOnceInSamePattern(identifier) => self
710                 .session
711                 .create_err(errs::IdentifierBoundMoreThanOnceInSamePattern { span, identifier }),
712             ResolutionError::UndeclaredLabel { name, suggestion } => {
713                 let ((sub_reachable, sub_reachable_suggestion), sub_unreachable) = match suggestion
714                 {
715                     // A reachable label with a similar name exists.
716                     Some((ident, true)) => (
717                         (
718                             Some(errs::LabelWithSimilarNameReachable(ident.span)),
719                             Some(errs::TryUsingSimilarlyNamedLabel {
720                                 span,
721                                 ident_name: ident.name,
722                             }),
723                         ),
724                         None,
725                     ),
726                     // An unreachable label with a similar name exists.
727                     Some((ident, false)) => (
728                         (None, None),
729                         Some(errs::UnreachableLabelWithSimilarNameExists {
730                             ident_span: ident.span,
731                         }),
732                     ),
733                     // No similarly-named labels exist.
734                     None => ((None, None), None),
735                 };
736                 self.session.create_err(errs::UndeclaredLabel {
737                     span,
738                     name,
739                     sub_reachable,
740                     sub_reachable_suggestion,
741                     sub_unreachable,
742                 })
743             }
744             ResolutionError::SelfImportsOnlyAllowedWithin { root, span_with_rename } => {
745                 // None of the suggestions below would help with a case like `use self`.
746                 let (suggestion, mpart_suggestion) = if root {
747                     (None, None)
748                 } else {
749                     // use foo::bar::self        -> foo::bar
750                     // use foo::bar::self as abc -> foo::bar as abc
751                     let suggestion = errs::SelfImportsOnlyAllowedWithinSuggestion { span };
752
753                     // use foo::bar::self        -> foo::bar::{self}
754                     // use foo::bar::self as abc -> foo::bar::{self as abc}
755                     let mpart_suggestion = errs::SelfImportsOnlyAllowedWithinMultipartSuggestion {
756                         multipart_start: span_with_rename.shrink_to_lo(),
757                         multipart_end: span_with_rename.shrink_to_hi(),
758                     };
759                     (Some(suggestion), Some(mpart_suggestion))
760                 };
761                 self.session.create_err(errs::SelfImportsOnlyAllowedWithin {
762                     span,
763                     suggestion,
764                     mpart_suggestion,
765                 })
766             }
767             ResolutionError::SelfImportCanOnlyAppearOnceInTheList => {
768                 self.session.create_err(errs::SelfImportCanOnlyAppearOnceInTheList { span })
769             }
770             ResolutionError::SelfImportOnlyInImportListWithNonEmptyPrefix => {
771                 self.session.create_err(errs::SelfImportOnlyInImportListWithNonEmptyPrefix { span })
772             }
773             ResolutionError::FailedToResolve { label, suggestion } => {
774                 let mut err =
775                     struct_span_err!(self.session, span, E0433, "failed to resolve: {}", &label);
776                 err.span_label(span, label);
777
778                 if let Some((suggestions, msg, applicability)) = suggestion {
779                     if suggestions.is_empty() {
780                         err.help(&msg);
781                         return err;
782                     }
783                     err.multipart_suggestion(&msg, suggestions, applicability);
784                 }
785
786                 err
787             }
788             ResolutionError::CannotCaptureDynamicEnvironmentInFnItem => {
789                 self.session.create_err(errs::CannotCaptureDynamicEnvironmentInFnItem { span })
790             }
791             ResolutionError::AttemptToUseNonConstantValueInConstant(ident, suggestion, current) => {
792                 // let foo =...
793                 //     ^^^ given this Span
794                 // ------- get this Span to have an applicable suggestion
795
796                 // edit:
797                 // only do this if the const and usage of the non-constant value are on the same line
798                 // the further the two are apart, the higher the chance of the suggestion being wrong
799
800                 let sp = self
801                     .session
802                     .source_map()
803                     .span_extend_to_prev_str(ident.span, current, true, false);
804
805                 let ((with, with_label), without) = match sp {
806                     Some(sp) if !self.session.source_map().is_multiline(sp) => {
807                         let sp = sp.with_lo(BytePos(sp.lo().0 - (current.len() as u32)));
808                         (
809                         (Some(errs::AttemptToUseNonConstantValueInConstantWithSuggestion {
810                                 span: sp,
811                                 ident,
812                                 suggestion,
813                                 current,
814                             }), Some(errs::AttemptToUseNonConstantValueInConstantLabelWithSuggestion {span})),
815                             None,
816                         )
817                     }
818                     _ => (
819                         (None, None),
820                         Some(errs::AttemptToUseNonConstantValueInConstantWithoutSuggestion {
821                             ident_span: ident.span,
822                             suggestion,
823                         }),
824                     ),
825                 };
826
827                 self.session.create_err(errs::AttemptToUseNonConstantValueInConstant {
828                     span,
829                     with,
830                     with_label,
831                     without,
832                 })
833             }
834             ResolutionError::BindingShadowsSomethingUnacceptable {
835                 shadowing_binding,
836                 name,
837                 participle,
838                 article,
839                 shadowed_binding,
840                 shadowed_binding_span,
841             } => self.session.create_err(errs::BindingShadowsSomethingUnacceptable {
842                 span,
843                 shadowing_binding,
844                 shadowed_binding,
845                 article,
846                 sub_suggestion: match (shadowing_binding, shadowed_binding) {
847                     (
848                         PatternSource::Match,
849                         Res::Def(DefKind::Ctor(CtorOf::Variant | CtorOf::Struct, CtorKind::Fn), _),
850                     ) => Some(errs::BindingShadowsSomethingUnacceptableSuggestion { span, name }),
851                     _ => None,
852                 },
853                 shadowed_binding_span,
854                 participle,
855                 name,
856             }),
857             ResolutionError::ForwardDeclaredGenericParam => {
858                 self.session.create_err(errs::ForwardDeclaredGenericParam { span })
859             }
860             ResolutionError::ParamInTyOfConstParam(name) => {
861                 self.session.create_err(errs::ParamInTyOfConstParam { span, name })
862             }
863             ResolutionError::ParamInNonTrivialAnonConst { name, is_type } => {
864                 self.session.create_err(errs::ParamInNonTrivialAnonConst {
865                     span,
866                     name,
867                     sub_is_type: if is_type {
868                         errs::ParamInNonTrivialAnonConstIsType::AType
869                     } else {
870                         errs::ParamInNonTrivialAnonConstIsType::NotAType { name }
871                     },
872                     help: self
873                         .session
874                         .is_nightly_build()
875                         .then_some(errs::ParamInNonTrivialAnonConstHelp),
876                 })
877             }
878             ResolutionError::SelfInGenericParamDefault => {
879                 self.session.create_err(errs::SelfInGenericParamDefault { span })
880             }
881             ResolutionError::UnreachableLabel { name, definition_span, suggestion } => {
882                 let ((sub_suggestion_label, sub_suggestion), sub_unreachable_label) =
883                     match suggestion {
884                         // A reachable label with a similar name exists.
885                         Some((ident, true)) => (
886                             (
887                                 Some(errs::UnreachableLabelSubLabel { ident_span: ident.span }),
888                                 Some(errs::UnreachableLabelSubSuggestion {
889                                     span,
890                                     // intentionally taking 'ident.name' instead of 'ident' itself, as this
891                                     // could be used in suggestion context
892                                     ident_name: ident.name,
893                                 }),
894                             ),
895                             None,
896                         ),
897                         // An unreachable label with a similar name exists.
898                         Some((ident, false)) => (
899                             (None, None),
900                             Some(errs::UnreachableLabelSubLabelUnreachable {
901                                 ident_span: ident.span,
902                             }),
903                         ),
904                         // No similarly-named labels exist.
905                         None => ((None, None), None),
906                     };
907                 self.session.create_err(errs::UnreachableLabel {
908                     span,
909                     name,
910                     definition_span,
911                     sub_suggestion,
912                     sub_suggestion_label,
913                     sub_unreachable_label,
914                 })
915             }
916             ResolutionError::TraitImplMismatch {
917                 name,
918                 kind,
919                 code,
920                 trait_item_span,
921                 trait_path,
922             } => {
923                 let mut err = self.session.struct_span_err_with_code(
924                     span,
925                     &format!(
926                         "item `{}` is an associated {}, which doesn't match its trait `{}`",
927                         name, kind, trait_path,
928                     ),
929                     code,
930                 );
931                 err.span_label(span, "does not match trait");
932                 err.span_label(trait_item_span, "item in trait");
933                 err
934             }
935             ResolutionError::TraitImplDuplicate { name, trait_item_span, old_span } => self
936                 .session
937                 .create_err(errs::TraitImplDuplicate { span, name, trait_item_span, old_span }),
938             ResolutionError::InvalidAsmSym => self.session.create_err(errs::InvalidAsmSym { span }),
939         }
940     }
941
942     pub(crate) fn report_vis_error(
943         &mut self,
944         vis_resolution_error: VisResolutionError<'_>,
945     ) -> ErrorGuaranteed {
946         match vis_resolution_error {
947             VisResolutionError::Relative2018(span, path) => {
948                 self.session.create_err(errs::Relative2018 {
949                     span,
950                     path_span: path.span,
951                     // intentionally converting to String, as the text would also be used as
952                     // in suggestion context
953                     path_str: pprust::path_to_string(&path),
954                 })
955             }
956             VisResolutionError::AncestorOnly(span) => {
957                 self.session.create_err(errs::AncestorOnly(span))
958             }
959             VisResolutionError::FailedToResolve(span, label, suggestion) => {
960                 self.into_struct_error(span, ResolutionError::FailedToResolve { label, suggestion })
961             }
962             VisResolutionError::ExpectedFound(span, path_str, res) => {
963                 self.session.create_err(errs::ExpectedFound { span, res, path_str })
964             }
965             VisResolutionError::Indeterminate(span) => {
966                 self.session.create_err(errs::Indeterminate(span))
967             }
968             VisResolutionError::ModuleOnly(span) => self.session.create_err(errs::ModuleOnly(span)),
969         }
970         .emit()
971     }
972
973     /// Lookup typo candidate in scope for a macro or import.
974     fn early_lookup_typo_candidate(
975         &mut self,
976         scope_set: ScopeSet<'a>,
977         parent_scope: &ParentScope<'a>,
978         ident: Ident,
979         filter_fn: &impl Fn(Res) -> bool,
980     ) -> Option<TypoSuggestion> {
981         let mut suggestions = Vec::new();
982         let ctxt = ident.span.ctxt();
983         self.visit_scopes(scope_set, parent_scope, ctxt, |this, scope, use_prelude, _| {
984             match scope {
985                 Scope::DeriveHelpers(expn_id) => {
986                     let res = Res::NonMacroAttr(NonMacroAttrKind::DeriveHelper);
987                     if filter_fn(res) {
988                         suggestions.extend(
989                             this.helper_attrs
990                                 .get(&expn_id)
991                                 .into_iter()
992                                 .flatten()
993                                 .map(|ident| TypoSuggestion::typo_from_ident(*ident, res)),
994                         );
995                     }
996                 }
997                 Scope::DeriveHelpersCompat => {
998                     let res = Res::NonMacroAttr(NonMacroAttrKind::DeriveHelperCompat);
999                     if filter_fn(res) {
1000                         for derive in parent_scope.derives {
1001                             let parent_scope = &ParentScope { derives: &[], ..*parent_scope };
1002                             if let Ok((Some(ext), _)) = this.resolve_macro_path(
1003                                 derive,
1004                                 Some(MacroKind::Derive),
1005                                 parent_scope,
1006                                 false,
1007                                 false,
1008                             ) {
1009                                 suggestions.extend(
1010                                     ext.helper_attrs
1011                                         .iter()
1012                                         .map(|name| TypoSuggestion::typo_from_name(*name, res)),
1013                                 );
1014                             }
1015                         }
1016                     }
1017                 }
1018                 Scope::MacroRules(macro_rules_scope) => {
1019                     if let MacroRulesScope::Binding(macro_rules_binding) = macro_rules_scope.get() {
1020                         let res = macro_rules_binding.binding.res();
1021                         if filter_fn(res) {
1022                             suggestions.push(TypoSuggestion::typo_from_ident(
1023                                 macro_rules_binding.ident,
1024                                 res,
1025                             ))
1026                         }
1027                     }
1028                 }
1029                 Scope::CrateRoot => {
1030                     let root_ident = Ident::new(kw::PathRoot, ident.span);
1031                     let root_module = this.resolve_crate_root(root_ident);
1032                     this.add_module_candidates(root_module, &mut suggestions, filter_fn, None);
1033                 }
1034                 Scope::Module(module) => {
1035                     this.add_module_candidates(module, &mut suggestions, filter_fn, None);
1036                 }
1037                 Scope::MacroUsePrelude => {
1038                     suggestions.extend(this.macro_use_prelude.iter().filter_map(
1039                         |(name, binding)| {
1040                             let res = binding.res();
1041                             filter_fn(res).then_some(TypoSuggestion::typo_from_name(*name, res))
1042                         },
1043                     ));
1044                 }
1045                 Scope::BuiltinAttrs => {
1046                     let res = Res::NonMacroAttr(NonMacroAttrKind::Builtin(kw::Empty));
1047                     if filter_fn(res) {
1048                         suggestions.extend(
1049                             BUILTIN_ATTRIBUTES
1050                                 .iter()
1051                                 .map(|attr| TypoSuggestion::typo_from_name(attr.name, res)),
1052                         );
1053                     }
1054                 }
1055                 Scope::ExternPrelude => {
1056                     suggestions.extend(this.extern_prelude.iter().filter_map(|(ident, _)| {
1057                         let res = Res::Def(DefKind::Mod, CRATE_DEF_ID.to_def_id());
1058                         filter_fn(res).then_some(TypoSuggestion::typo_from_ident(*ident, res))
1059                     }));
1060                 }
1061                 Scope::ToolPrelude => {
1062                     let res = Res::NonMacroAttr(NonMacroAttrKind::Tool);
1063                     suggestions.extend(
1064                         this.registered_tools
1065                             .iter()
1066                             .map(|ident| TypoSuggestion::typo_from_ident(*ident, res)),
1067                     );
1068                 }
1069                 Scope::StdLibPrelude => {
1070                     if let Some(prelude) = this.prelude {
1071                         let mut tmp_suggestions = Vec::new();
1072                         this.add_module_candidates(prelude, &mut tmp_suggestions, filter_fn, None);
1073                         suggestions.extend(
1074                             tmp_suggestions
1075                                 .into_iter()
1076                                 .filter(|s| use_prelude || this.is_builtin_macro(s.res)),
1077                         );
1078                     }
1079                 }
1080                 Scope::BuiltinTypes => {
1081                     suggestions.extend(PrimTy::ALL.iter().filter_map(|prim_ty| {
1082                         let res = Res::PrimTy(*prim_ty);
1083                         filter_fn(res)
1084                             .then_some(TypoSuggestion::typo_from_name(prim_ty.name(), res))
1085                     }))
1086                 }
1087             }
1088
1089             None::<()>
1090         });
1091
1092         // Make sure error reporting is deterministic.
1093         suggestions.sort_by(|a, b| a.candidate.as_str().partial_cmp(b.candidate.as_str()).unwrap());
1094
1095         match find_best_match_for_name(
1096             &suggestions.iter().map(|suggestion| suggestion.candidate).collect::<Vec<Symbol>>(),
1097             ident.name,
1098             None,
1099         ) {
1100             Some(found) if found != ident.name => {
1101                 suggestions.into_iter().find(|suggestion| suggestion.candidate == found)
1102             }
1103             _ => None,
1104         }
1105     }
1106
1107     fn lookup_import_candidates_from_module<FilterFn>(
1108         &mut self,
1109         lookup_ident: Ident,
1110         namespace: Namespace,
1111         parent_scope: &ParentScope<'a>,
1112         start_module: Module<'a>,
1113         crate_name: Ident,
1114         filter_fn: FilterFn,
1115     ) -> Vec<ImportSuggestion>
1116     where
1117         FilterFn: Fn(Res) -> bool,
1118     {
1119         let mut candidates = Vec::new();
1120         let mut seen_modules = FxHashSet::default();
1121         let mut worklist = vec![(start_module, ThinVec::<ast::PathSegment>::new(), true)];
1122         let mut worklist_via_import = vec![];
1123
1124         while let Some((in_module, path_segments, accessible)) = match worklist.pop() {
1125             None => worklist_via_import.pop(),
1126             Some(x) => Some(x),
1127         } {
1128             let in_module_is_extern = !in_module.def_id().is_local();
1129             // We have to visit module children in deterministic order to avoid
1130             // instabilities in reported imports (#43552).
1131             in_module.for_each_child(self, |this, ident, ns, name_binding| {
1132                 // avoid non-importable candidates
1133                 if !name_binding.is_importable() {
1134                     return;
1135                 }
1136
1137                 let child_accessible =
1138                     accessible && this.is_accessible_from(name_binding.vis, parent_scope.module);
1139
1140                 // do not venture inside inaccessible items of other crates
1141                 if in_module_is_extern && !child_accessible {
1142                     return;
1143                 }
1144
1145                 let via_import = name_binding.is_import() && !name_binding.is_extern_crate();
1146
1147                 // There is an assumption elsewhere that paths of variants are in the enum's
1148                 // declaration and not imported. With this assumption, the variant component is
1149                 // chopped and the rest of the path is assumed to be the enum's own path. For
1150                 // errors where a variant is used as the type instead of the enum, this causes
1151                 // funny looking invalid suggestions, i.e `foo` instead of `foo::MyEnum`.
1152                 if via_import && name_binding.is_possibly_imported_variant() {
1153                     return;
1154                 }
1155
1156                 // #90113: Do not count an inaccessible reexported item as a candidate.
1157                 if let NameBindingKind::Import { binding, .. } = name_binding.kind {
1158                     if this.is_accessible_from(binding.vis, parent_scope.module)
1159                         && !this.is_accessible_from(name_binding.vis, parent_scope.module)
1160                     {
1161                         return;
1162                     }
1163                 }
1164
1165                 // collect results based on the filter function
1166                 // avoid suggesting anything from the same module in which we are resolving
1167                 // avoid suggesting anything with a hygienic name
1168                 if ident.name == lookup_ident.name
1169                     && ns == namespace
1170                     && !ptr::eq(in_module, parent_scope.module)
1171                     && !ident.span.normalize_to_macros_2_0().from_expansion()
1172                 {
1173                     let res = name_binding.res();
1174                     if filter_fn(res) {
1175                         // create the path
1176                         let mut segms = path_segments.clone();
1177                         if lookup_ident.span.rust_2018() {
1178                             // crate-local absolute paths start with `crate::` in edition 2018
1179                             // FIXME: may also be stabilized for Rust 2015 (Issues #45477, #44660)
1180                             segms.insert(0, ast::PathSegment::from_ident(crate_name));
1181                         }
1182
1183                         segms.push(ast::PathSegment::from_ident(ident));
1184                         let path = Path { span: name_binding.span, segments: segms, tokens: None };
1185                         let did = match res {
1186                             Res::Def(DefKind::Ctor(..), did) => this.opt_parent(did),
1187                             _ => res.opt_def_id(),
1188                         };
1189
1190                         if child_accessible {
1191                             // Remove invisible match if exists
1192                             if let Some(idx) = candidates
1193                                 .iter()
1194                                 .position(|v: &ImportSuggestion| v.did == did && !v.accessible)
1195                             {
1196                                 candidates.remove(idx);
1197                             }
1198                         }
1199
1200                         if candidates.iter().all(|v: &ImportSuggestion| v.did != did) {
1201                             // See if we're recommending TryFrom, TryInto, or FromIterator and add
1202                             // a note about editions
1203                             let note = if let Some(did) = did {
1204                                 let requires_note = !did.is_local()
1205                                     && this.cstore().item_attrs_untracked(did, this.session).any(
1206                                         |attr| {
1207                                             if attr.has_name(sym::rustc_diagnostic_item) {
1208                                                 [sym::TryInto, sym::TryFrom, sym::FromIterator]
1209                                                     .map(|x| Some(x))
1210                                                     .contains(&attr.value_str())
1211                                             } else {
1212                                                 false
1213                                             }
1214                                         },
1215                                     );
1216
1217                                 requires_note.then(|| {
1218                                     format!(
1219                                         "'{}' is included in the prelude starting in Edition 2021",
1220                                         path_names_to_string(&path)
1221                                     )
1222                                 })
1223                             } else {
1224                                 None
1225                             };
1226
1227                             candidates.push(ImportSuggestion {
1228                                 did,
1229                                 descr: res.descr(),
1230                                 path,
1231                                 accessible: child_accessible,
1232                                 note,
1233                             });
1234                         }
1235                     }
1236                 }
1237
1238                 // collect submodules to explore
1239                 if let Some(module) = name_binding.module() {
1240                     // form the path
1241                     let mut path_segments = path_segments.clone();
1242                     path_segments.push(ast::PathSegment::from_ident(ident));
1243
1244                     let is_extern_crate_that_also_appears_in_prelude =
1245                         name_binding.is_extern_crate() && lookup_ident.span.rust_2018();
1246
1247                     if !is_extern_crate_that_also_appears_in_prelude {
1248                         // add the module to the lookup
1249                         if seen_modules.insert(module.def_id()) {
1250                             if via_import { &mut worklist_via_import } else { &mut worklist }
1251                                 .push((module, path_segments, child_accessible));
1252                         }
1253                     }
1254                 }
1255             })
1256         }
1257
1258         // If only some candidates are accessible, take just them
1259         if !candidates.iter().all(|v: &ImportSuggestion| !v.accessible) {
1260             candidates.retain(|x| x.accessible)
1261         }
1262
1263         candidates
1264     }
1265
1266     /// When name resolution fails, this method can be used to look up candidate
1267     /// entities with the expected name. It allows filtering them using the
1268     /// supplied predicate (which should be used to only accept the types of
1269     /// definitions expected, e.g., traits). The lookup spans across all crates.
1270     ///
1271     /// N.B., the method does not look into imports, but this is not a problem,
1272     /// since we report the definitions (thus, the de-aliased imports).
1273     pub(crate) fn lookup_import_candidates<FilterFn>(
1274         &mut self,
1275         lookup_ident: Ident,
1276         namespace: Namespace,
1277         parent_scope: &ParentScope<'a>,
1278         filter_fn: FilterFn,
1279     ) -> Vec<ImportSuggestion>
1280     where
1281         FilterFn: Fn(Res) -> bool,
1282     {
1283         let mut suggestions = self.lookup_import_candidates_from_module(
1284             lookup_ident,
1285             namespace,
1286             parent_scope,
1287             self.graph_root,
1288             Ident::with_dummy_span(kw::Crate),
1289             &filter_fn,
1290         );
1291
1292         if lookup_ident.span.rust_2018() {
1293             let extern_prelude_names = self.extern_prelude.clone();
1294             for (ident, _) in extern_prelude_names.into_iter() {
1295                 if ident.span.from_expansion() {
1296                     // Idents are adjusted to the root context before being
1297                     // resolved in the extern prelude, so reporting this to the
1298                     // user is no help. This skips the injected
1299                     // `extern crate std` in the 2018 edition, which would
1300                     // otherwise cause duplicate suggestions.
1301                     continue;
1302                 }
1303                 let crate_id = self.crate_loader().maybe_process_path_extern(ident.name);
1304                 if let Some(crate_id) = crate_id {
1305                     let crate_root = self.expect_module(crate_id.as_def_id());
1306                     suggestions.extend(self.lookup_import_candidates_from_module(
1307                         lookup_ident,
1308                         namespace,
1309                         parent_scope,
1310                         crate_root,
1311                         ident,
1312                         &filter_fn,
1313                     ));
1314                 }
1315             }
1316         }
1317
1318         suggestions
1319     }
1320
1321     pub(crate) fn unresolved_macro_suggestions(
1322         &mut self,
1323         err: &mut Diagnostic,
1324         macro_kind: MacroKind,
1325         parent_scope: &ParentScope<'a>,
1326         ident: Ident,
1327     ) {
1328         let is_expected = &|res: Res| res.macro_kind() == Some(macro_kind);
1329         let suggestion = self.early_lookup_typo_candidate(
1330             ScopeSet::Macro(macro_kind),
1331             parent_scope,
1332             ident,
1333             is_expected,
1334         );
1335         self.add_typo_suggestion(err, suggestion, ident.span);
1336
1337         let import_suggestions =
1338             self.lookup_import_candidates(ident, Namespace::MacroNS, parent_scope, is_expected);
1339         show_candidates(
1340             &self.session,
1341             &self.untracked.source_span,
1342             err,
1343             None,
1344             &import_suggestions,
1345             Instead::No,
1346             FoundUse::Yes,
1347             DiagnosticMode::Normal,
1348             vec![],
1349             "",
1350         );
1351
1352         if macro_kind == MacroKind::Derive && (ident.name == sym::Send || ident.name == sym::Sync) {
1353             let msg = format!("unsafe traits like `{}` should be implemented explicitly", ident);
1354             err.span_note(ident.span, &msg);
1355             return;
1356         }
1357         if self.macro_names.contains(&ident.normalize_to_macros_2_0()) {
1358             err.help("have you added the `#[macro_use]` on the module/import?");
1359             return;
1360         }
1361         if ident.name == kw::Default
1362             && let ModuleKind::Def(DefKind::Enum, def_id, _) = parent_scope.module.kind
1363             && let Some(span) = self.opt_span(def_id)
1364         {
1365             let source_map = self.session.source_map();
1366             let head_span = source_map.guess_head_span(span);
1367             if let Ok(head) = source_map.span_to_snippet(head_span) {
1368                 err.span_suggestion(head_span, "consider adding a derive", format!("#[derive(Default)]\n{head}"), Applicability::MaybeIncorrect);
1369             } else {
1370                 err.span_help(
1371                     head_span,
1372                     "consider adding `#[derive(Default)]` to this enum",
1373                 );
1374             }
1375         }
1376         for ns in [Namespace::MacroNS, Namespace::TypeNS, Namespace::ValueNS] {
1377             if let Ok(binding) = self.early_resolve_ident_in_lexical_scope(
1378                 ident,
1379                 ScopeSet::All(ns, false),
1380                 &parent_scope,
1381                 None,
1382                 false,
1383                 None,
1384             ) {
1385                 let desc = match binding.res() {
1386                     Res::Def(DefKind::Macro(MacroKind::Bang), _) => {
1387                         "a function-like macro".to_string()
1388                     }
1389                     Res::Def(DefKind::Macro(MacroKind::Attr), _) | Res::NonMacroAttr(..) => {
1390                         format!("an attribute: `#[{}]`", ident)
1391                     }
1392                     Res::Def(DefKind::Macro(MacroKind::Derive), _) => {
1393                         format!("a derive macro: `#[derive({})]`", ident)
1394                     }
1395                     Res::ToolMod => {
1396                         // Don't confuse the user with tool modules.
1397                         continue;
1398                     }
1399                     Res::Def(DefKind::Trait, _) if macro_kind == MacroKind::Derive => {
1400                         "only a trait, without a derive macro".to_string()
1401                     }
1402                     res => format!(
1403                         "{} {}, not {} {}",
1404                         res.article(),
1405                         res.descr(),
1406                         macro_kind.article(),
1407                         macro_kind.descr_expected(),
1408                     ),
1409                 };
1410                 if let crate::NameBindingKind::Import { import, .. } = binding.kind {
1411                     if !import.span.is_dummy() {
1412                         err.span_note(
1413                             import.span,
1414                             &format!("`{}` is imported here, but it is {}", ident, desc),
1415                         );
1416                         // Silence the 'unused import' warning we might get,
1417                         // since this diagnostic already covers that import.
1418                         self.record_use(ident, binding, false);
1419                         return;
1420                     }
1421                 }
1422                 err.note(&format!("`{}` is in scope, but it is {}", ident, desc));
1423                 return;
1424             }
1425         }
1426     }
1427
1428     pub(crate) fn add_typo_suggestion(
1429         &self,
1430         err: &mut Diagnostic,
1431         suggestion: Option<TypoSuggestion>,
1432         span: Span,
1433     ) -> bool {
1434         let suggestion = match suggestion {
1435             None => return false,
1436             // We shouldn't suggest underscore.
1437             Some(suggestion) if suggestion.candidate == kw::Underscore => return false,
1438             Some(suggestion) => suggestion,
1439         };
1440         let def_span = suggestion.res.opt_def_id().and_then(|def_id| match def_id.krate {
1441             LOCAL_CRATE => self.opt_span(def_id),
1442             _ => Some(self.cstore().get_span_untracked(def_id, self.session)),
1443         });
1444         if let Some(def_span) = def_span {
1445             if span.overlaps(def_span) {
1446                 // Don't suggest typo suggestion for itself like in the following:
1447                 // error[E0423]: expected function, tuple struct or tuple variant, found struct `X`
1448                 //   --> $DIR/issue-64792-bad-unicode-ctor.rs:3:14
1449                 //    |
1450                 // LL | struct X {}
1451                 //    | ----------- `X` defined here
1452                 // LL |
1453                 // LL | const Y: X = X("ö");
1454                 //    | -------------^^^^^^- similarly named constant `Y` defined here
1455                 //    |
1456                 // help: use struct literal syntax instead
1457                 //    |
1458                 // LL | const Y: X = X {};
1459                 //    |              ^^^^
1460                 // help: a constant with a similar name exists
1461                 //    |
1462                 // LL | const Y: X = Y("ö");
1463                 //    |              ^
1464                 return false;
1465             }
1466             let prefix = match suggestion.target {
1467                 SuggestionTarget::SimilarlyNamed => "similarly named ",
1468                 SuggestionTarget::SingleItem => "",
1469             };
1470
1471             err.span_label(
1472                 self.session.source_map().guess_head_span(def_span),
1473                 &format!(
1474                     "{}{} `{}` defined here",
1475                     prefix,
1476                     suggestion.res.descr(),
1477                     suggestion.candidate,
1478                 ),
1479             );
1480         }
1481         let msg = match suggestion.target {
1482             SuggestionTarget::SimilarlyNamed => format!(
1483                 "{} {} with a similar name exists",
1484                 suggestion.res.article(),
1485                 suggestion.res.descr()
1486             ),
1487             SuggestionTarget::SingleItem => {
1488                 format!("maybe you meant this {}", suggestion.res.descr())
1489             }
1490         };
1491         err.span_suggestion(span, &msg, suggestion.candidate, Applicability::MaybeIncorrect);
1492         true
1493     }
1494
1495     fn binding_description(&self, b: &NameBinding<'_>, ident: Ident, from_prelude: bool) -> String {
1496         let res = b.res();
1497         if b.span.is_dummy() || !self.session.source_map().is_span_accessible(b.span) {
1498             // These already contain the "built-in" prefix or look bad with it.
1499             let add_built_in =
1500                 !matches!(b.res(), Res::NonMacroAttr(..) | Res::PrimTy(..) | Res::ToolMod);
1501             let (built_in, from) = if from_prelude {
1502                 ("", " from prelude")
1503             } else if b.is_extern_crate()
1504                 && !b.is_import()
1505                 && self.session.opts.externs.get(ident.as_str()).is_some()
1506             {
1507                 ("", " passed with `--extern`")
1508             } else if add_built_in {
1509                 (" built-in", "")
1510             } else {
1511                 ("", "")
1512             };
1513
1514             let a = if built_in.is_empty() { res.article() } else { "a" };
1515             format!("{a}{built_in} {thing}{from}", thing = res.descr())
1516         } else {
1517             let introduced = if b.is_import_user_facing() { "imported" } else { "defined" };
1518             format!("the {thing} {introduced} here", thing = res.descr())
1519         }
1520     }
1521
1522     fn report_ambiguity_error(&self, ambiguity_error: &AmbiguityError<'_>) {
1523         let AmbiguityError { kind, ident, b1, b2, misc1, misc2 } = *ambiguity_error;
1524         let (b1, b2, misc1, misc2, swapped) = if b2.span.is_dummy() && !b1.span.is_dummy() {
1525             // We have to print the span-less alternative first, otherwise formatting looks bad.
1526             (b2, b1, misc2, misc1, true)
1527         } else {
1528             (b1, b2, misc1, misc2, false)
1529         };
1530
1531         let mut err = struct_span_err!(self.session, ident.span, E0659, "`{ident}` is ambiguous");
1532         err.span_label(ident.span, "ambiguous name");
1533         err.note(&format!("ambiguous because of {}", kind.descr()));
1534
1535         let mut could_refer_to = |b: &NameBinding<'_>, misc: AmbiguityErrorMisc, also: &str| {
1536             let what = self.binding_description(b, ident, misc == AmbiguityErrorMisc::FromPrelude);
1537             let note_msg = format!("`{ident}` could{also} refer to {what}");
1538
1539             let thing = b.res().descr();
1540             let mut help_msgs = Vec::new();
1541             if b.is_glob_import()
1542                 && (kind == AmbiguityKind::GlobVsGlob
1543                     || kind == AmbiguityKind::GlobVsExpanded
1544                     || kind == AmbiguityKind::GlobVsOuter && swapped != also.is_empty())
1545             {
1546                 help_msgs.push(format!(
1547                     "consider adding an explicit import of `{ident}` to disambiguate"
1548                 ))
1549             }
1550             if b.is_extern_crate() && ident.span.rust_2018() {
1551                 help_msgs.push(format!("use `::{ident}` to refer to this {thing} unambiguously"))
1552             }
1553             if misc == AmbiguityErrorMisc::SuggestCrate {
1554                 help_msgs
1555                     .push(format!("use `crate::{ident}` to refer to this {thing} unambiguously"))
1556             } else if misc == AmbiguityErrorMisc::SuggestSelf {
1557                 help_msgs
1558                     .push(format!("use `self::{ident}` to refer to this {thing} unambiguously"))
1559             }
1560
1561             err.span_note(b.span, &note_msg);
1562             for (i, help_msg) in help_msgs.iter().enumerate() {
1563                 let or = if i == 0 { "" } else { "or " };
1564                 err.help(&format!("{}{}", or, help_msg));
1565             }
1566         };
1567
1568         could_refer_to(b1, misc1, "");
1569         could_refer_to(b2, misc2, " also");
1570         err.emit();
1571     }
1572
1573     /// If the binding refers to a tuple struct constructor with fields,
1574     /// returns the span of its fields.
1575     fn ctor_fields_span(&self, binding: &NameBinding<'_>) -> Option<Span> {
1576         if let NameBindingKind::Res(Res::Def(
1577             DefKind::Ctor(CtorOf::Struct, CtorKind::Fn),
1578             ctor_def_id,
1579         )) = binding.kind
1580         {
1581             let def_id = self.parent(ctor_def_id);
1582             let fields = self.field_names.get(&def_id)?;
1583             return fields.iter().map(|name| name.span).reduce(Span::to); // None for `struct Foo()`
1584         }
1585         None
1586     }
1587
1588     fn report_privacy_error(&self, privacy_error: &PrivacyError<'_>) {
1589         let PrivacyError { ident, binding, .. } = *privacy_error;
1590
1591         let res = binding.res();
1592         let ctor_fields_span = self.ctor_fields_span(binding);
1593         let plain_descr = res.descr().to_string();
1594         let nonimport_descr =
1595             if ctor_fields_span.is_some() { plain_descr + " constructor" } else { plain_descr };
1596         let import_descr = nonimport_descr.clone() + " import";
1597         let get_descr =
1598             |b: &NameBinding<'_>| if b.is_import() { &import_descr } else { &nonimport_descr };
1599
1600         // Print the primary message.
1601         let descr = get_descr(binding);
1602         let mut err =
1603             struct_span_err!(self.session, ident.span, E0603, "{} `{}` is private", descr, ident);
1604         err.span_label(ident.span, &format!("private {}", descr));
1605         if let Some(span) = ctor_fields_span {
1606             err.span_label(span, "a constructor is private if any of the fields is private");
1607         }
1608
1609         // Print the whole import chain to make it easier to see what happens.
1610         let first_binding = binding;
1611         let mut next_binding = Some(binding);
1612         let mut next_ident = ident;
1613         while let Some(binding) = next_binding {
1614             let name = next_ident;
1615             next_binding = match binding.kind {
1616                 _ if res == Res::Err => None,
1617                 NameBindingKind::Import { binding, import, .. } => match import.kind {
1618                     _ if binding.span.is_dummy() => None,
1619                     ImportKind::Single { source, .. } => {
1620                         next_ident = source;
1621                         Some(binding)
1622                     }
1623                     ImportKind::Glob { .. } | ImportKind::MacroUse | ImportKind::MacroExport => {
1624                         Some(binding)
1625                     }
1626                     ImportKind::ExternCrate { .. } => None,
1627                 },
1628                 _ => None,
1629             };
1630
1631             let first = ptr::eq(binding, first_binding);
1632             let msg = format!(
1633                 "{and_refers_to}the {item} `{name}`{which} is defined here{dots}",
1634                 and_refers_to = if first { "" } else { "...and refers to " },
1635                 item = get_descr(binding),
1636                 which = if first { "" } else { " which" },
1637                 dots = if next_binding.is_some() { "..." } else { "" },
1638             );
1639             let def_span = self.session.source_map().guess_head_span(binding.span);
1640             let mut note_span = MultiSpan::from_span(def_span);
1641             if !first && binding.vis.is_public() {
1642                 note_span.push_span_label(def_span, "consider importing it directly");
1643             }
1644             err.span_note(note_span, &msg);
1645         }
1646
1647         err.emit();
1648     }
1649
1650     pub(crate) fn find_similarly_named_module_or_crate(
1651         &mut self,
1652         ident: Symbol,
1653         current_module: &Module<'a>,
1654     ) -> Option<Symbol> {
1655         let mut candidates = self
1656             .extern_prelude
1657             .iter()
1658             .map(|(ident, _)| ident.name)
1659             .chain(
1660                 self.module_map
1661                     .iter()
1662                     .filter(|(_, module)| {
1663                         current_module.is_ancestor_of(module) && !ptr::eq(current_module, *module)
1664                     })
1665                     .flat_map(|(_, module)| module.kind.name()),
1666             )
1667             .filter(|c| !c.to_string().is_empty())
1668             .collect::<Vec<_>>();
1669         candidates.sort();
1670         candidates.dedup();
1671         match find_best_match_for_name(&candidates, ident, None) {
1672             Some(sugg) if sugg == ident => None,
1673             sugg => sugg,
1674         }
1675     }
1676
1677     pub(crate) fn report_path_resolution_error(
1678         &mut self,
1679         path: &[Segment],
1680         opt_ns: Option<Namespace>, // `None` indicates a module path in import
1681         parent_scope: &ParentScope<'a>,
1682         ribs: Option<&PerNS<Vec<Rib<'a>>>>,
1683         ignore_binding: Option<&'a NameBinding<'a>>,
1684         module: Option<ModuleOrUniformRoot<'a>>,
1685         i: usize,
1686         ident: Ident,
1687     ) -> (String, Option<Suggestion>) {
1688         let is_last = i == path.len() - 1;
1689         let ns = if is_last { opt_ns.unwrap_or(TypeNS) } else { TypeNS };
1690         let module_res = match module {
1691             Some(ModuleOrUniformRoot::Module(module)) => module.res(),
1692             _ => None,
1693         };
1694         if module_res == self.graph_root.res() {
1695             let is_mod = |res| matches!(res, Res::Def(DefKind::Mod, _));
1696             let mut candidates = self.lookup_import_candidates(ident, TypeNS, parent_scope, is_mod);
1697             candidates
1698                 .sort_by_cached_key(|c| (c.path.segments.len(), pprust::path_to_string(&c.path)));
1699             if let Some(candidate) = candidates.get(0) {
1700                 (
1701                     String::from("unresolved import"),
1702                     Some((
1703                         vec![(ident.span, pprust::path_to_string(&candidate.path))],
1704                         String::from("a similar path exists"),
1705                         Applicability::MaybeIncorrect,
1706                     )),
1707                 )
1708             } else if self.session.edition() == Edition::Edition2015 {
1709                 (
1710                     format!("maybe a missing crate `{ident}`?"),
1711                     Some((
1712                         vec![],
1713                         format!(
1714                             "consider adding `extern crate {ident}` to use the `{ident}` crate"
1715                         ),
1716                         Applicability::MaybeIncorrect,
1717                     )),
1718                 )
1719             } else {
1720                 (format!("could not find `{ident}` in the crate root"), None)
1721             }
1722         } else if i > 0 {
1723             let parent = path[i - 1].ident.name;
1724             let parent = match parent {
1725                 // ::foo is mounted at the crate root for 2015, and is the extern
1726                 // prelude for 2018+
1727                 kw::PathRoot if self.session.edition() > Edition::Edition2015 => {
1728                     "the list of imported crates".to_owned()
1729                 }
1730                 kw::PathRoot | kw::Crate => "the crate root".to_owned(),
1731                 _ => format!("`{parent}`"),
1732             };
1733
1734             let mut msg = format!("could not find `{}` in {}", ident, parent);
1735             if ns == TypeNS || ns == ValueNS {
1736                 let ns_to_try = if ns == TypeNS { ValueNS } else { TypeNS };
1737                 let binding = if let Some(module) = module {
1738                     self.resolve_ident_in_module(
1739                         module,
1740                         ident,
1741                         ns_to_try,
1742                         parent_scope,
1743                         None,
1744                         ignore_binding,
1745                     ).ok()
1746                 } else if let Some(ribs) = ribs
1747                     && let Some(TypeNS | ValueNS) = opt_ns
1748                 {
1749                     match self.resolve_ident_in_lexical_scope(
1750                         ident,
1751                         ns_to_try,
1752                         parent_scope,
1753                         None,
1754                         &ribs[ns_to_try],
1755                         ignore_binding,
1756                     ) {
1757                         // we found a locally-imported or available item/module
1758                         Some(LexicalScopeBinding::Item(binding)) => Some(binding),
1759                         _ => None,
1760                     }
1761                 } else {
1762                     let scopes = ScopeSet::All(ns_to_try, opt_ns.is_none());
1763                     self.early_resolve_ident_in_lexical_scope(
1764                         ident,
1765                         scopes,
1766                         parent_scope,
1767                         None,
1768                         false,
1769                         ignore_binding,
1770                     ).ok()
1771                 };
1772                 if let Some(binding) = binding {
1773                     let mut found = |what| {
1774                         msg = format!(
1775                             "expected {}, found {} `{}` in {}",
1776                             ns.descr(),
1777                             what,
1778                             ident,
1779                             parent
1780                         )
1781                     };
1782                     if binding.module().is_some() {
1783                         found("module")
1784                     } else {
1785                         match binding.res() {
1786                             Res::Def(kind, id) => found(kind.descr(id)),
1787                             _ => found(ns_to_try.descr()),
1788                         }
1789                     }
1790                 };
1791             }
1792             (msg, None)
1793         } else if ident.name == kw::SelfUpper {
1794             ("`Self` is only available in impls, traits, and type definitions".to_string(), None)
1795         } else if ident.name.as_str().chars().next().map_or(false, |c| c.is_ascii_uppercase()) {
1796             // Check whether the name refers to an item in the value namespace.
1797             let binding = if let Some(ribs) = ribs {
1798                 self.resolve_ident_in_lexical_scope(
1799                     ident,
1800                     ValueNS,
1801                     parent_scope,
1802                     None,
1803                     &ribs[ValueNS],
1804                     ignore_binding,
1805                 )
1806             } else {
1807                 None
1808             };
1809             let match_span = match binding {
1810                 // Name matches a local variable. For example:
1811                 // ```
1812                 // fn f() {
1813                 //     let Foo: &str = "";
1814                 //     println!("{}", Foo::Bar); // Name refers to local
1815                 //                               // variable `Foo`.
1816                 // }
1817                 // ```
1818                 Some(LexicalScopeBinding::Res(Res::Local(id))) => {
1819                     Some(*self.pat_span_map.get(&id).unwrap())
1820                 }
1821                 // Name matches item from a local name binding
1822                 // created by `use` declaration. For example:
1823                 // ```
1824                 // pub Foo: &str = "";
1825                 //
1826                 // mod submod {
1827                 //     use super::Foo;
1828                 //     println!("{}", Foo::Bar); // Name refers to local
1829                 //                               // binding `Foo`.
1830                 // }
1831                 // ```
1832                 Some(LexicalScopeBinding::Item(name_binding)) => Some(name_binding.span),
1833                 _ => None,
1834             };
1835             let suggestion = if let Some(span) = match_span {
1836                 Some((
1837                     vec![(span, String::from(""))],
1838                     format!("`{}` is defined here, but is not a type", ident),
1839                     Applicability::MaybeIncorrect,
1840                 ))
1841             } else {
1842                 None
1843             };
1844
1845             (format!("use of undeclared type `{}`", ident), suggestion)
1846         } else {
1847             let mut suggestion = None;
1848             if ident.name == sym::alloc {
1849                 suggestion = Some((
1850                     vec![],
1851                     String::from("add `extern crate alloc` to use the `alloc` crate"),
1852                     Applicability::MaybeIncorrect,
1853                 ))
1854             }
1855
1856             suggestion = suggestion.or_else(|| {
1857                 self.find_similarly_named_module_or_crate(ident.name, &parent_scope.module).map(
1858                     |sugg| {
1859                         (
1860                             vec![(ident.span, sugg.to_string())],
1861                             String::from("there is a crate or module with a similar name"),
1862                             Applicability::MaybeIncorrect,
1863                         )
1864                     },
1865                 )
1866             });
1867             (format!("use of undeclared crate or module `{}`", ident), suggestion)
1868         }
1869     }
1870 }
1871
1872 impl<'a, 'b> ImportResolver<'a, 'b> {
1873     /// Adds suggestions for a path that cannot be resolved.
1874     pub(crate) fn make_path_suggestion(
1875         &mut self,
1876         span: Span,
1877         mut path: Vec<Segment>,
1878         parent_scope: &ParentScope<'b>,
1879     ) -> Option<(Vec<Segment>, Option<String>)> {
1880         debug!("make_path_suggestion: span={:?} path={:?}", span, path);
1881
1882         match (path.get(0), path.get(1)) {
1883             // `{{root}}::ident::...` on both editions.
1884             // On 2015 `{{root}}` is usually added implicitly.
1885             (Some(fst), Some(snd))
1886                 if fst.ident.name == kw::PathRoot && !snd.ident.is_path_segment_keyword() => {}
1887             // `ident::...` on 2018.
1888             (Some(fst), _)
1889                 if fst.ident.span.rust_2018() && !fst.ident.is_path_segment_keyword() =>
1890             {
1891                 // Insert a placeholder that's later replaced by `self`/`super`/etc.
1892                 path.insert(0, Segment::from_ident(Ident::empty()));
1893             }
1894             _ => return None,
1895         }
1896
1897         self.make_missing_self_suggestion(path.clone(), parent_scope)
1898             .or_else(|| self.make_missing_crate_suggestion(path.clone(), parent_scope))
1899             .or_else(|| self.make_missing_super_suggestion(path.clone(), parent_scope))
1900             .or_else(|| self.make_external_crate_suggestion(path, parent_scope))
1901     }
1902
1903     /// Suggest a missing `self::` if that resolves to an correct module.
1904     ///
1905     /// ```text
1906     ///    |
1907     /// LL | use foo::Bar;
1908     ///    |     ^^^ did you mean `self::foo`?
1909     /// ```
1910     fn make_missing_self_suggestion(
1911         &mut self,
1912         mut path: Vec<Segment>,
1913         parent_scope: &ParentScope<'b>,
1914     ) -> Option<(Vec<Segment>, Option<String>)> {
1915         // Replace first ident with `self` and check if that is valid.
1916         path[0].ident.name = kw::SelfLower;
1917         let result = self.r.maybe_resolve_path(&path, None, parent_scope);
1918         debug!("make_missing_self_suggestion: path={:?} result={:?}", path, result);
1919         if let PathResult::Module(..) = result { Some((path, None)) } else { None }
1920     }
1921
1922     /// Suggests a missing `crate::` if that resolves to an correct module.
1923     ///
1924     /// ```text
1925     ///    |
1926     /// LL | use foo::Bar;
1927     ///    |     ^^^ did you mean `crate::foo`?
1928     /// ```
1929     fn make_missing_crate_suggestion(
1930         &mut self,
1931         mut path: Vec<Segment>,
1932         parent_scope: &ParentScope<'b>,
1933     ) -> Option<(Vec<Segment>, Option<String>)> {
1934         // Replace first ident with `crate` and check if that is valid.
1935         path[0].ident.name = kw::Crate;
1936         let result = self.r.maybe_resolve_path(&path, None, parent_scope);
1937         debug!("make_missing_crate_suggestion:  path={:?} result={:?}", path, result);
1938         if let PathResult::Module(..) = result {
1939             Some((
1940                 path,
1941                 Some(
1942                     "`use` statements changed in Rust 2018; read more at \
1943                      <https://doc.rust-lang.org/edition-guide/rust-2018/module-system/path-\
1944                      clarity.html>"
1945                         .to_string(),
1946                 ),
1947             ))
1948         } else {
1949             None
1950         }
1951     }
1952
1953     /// Suggests a missing `super::` if that resolves to an correct module.
1954     ///
1955     /// ```text
1956     ///    |
1957     /// LL | use foo::Bar;
1958     ///    |     ^^^ did you mean `super::foo`?
1959     /// ```
1960     fn make_missing_super_suggestion(
1961         &mut self,
1962         mut path: Vec<Segment>,
1963         parent_scope: &ParentScope<'b>,
1964     ) -> Option<(Vec<Segment>, Option<String>)> {
1965         // Replace first ident with `crate` and check if that is valid.
1966         path[0].ident.name = kw::Super;
1967         let result = self.r.maybe_resolve_path(&path, None, parent_scope);
1968         debug!("make_missing_super_suggestion:  path={:?} result={:?}", path, result);
1969         if let PathResult::Module(..) = result { Some((path, None)) } else { None }
1970     }
1971
1972     /// Suggests a missing external crate name if that resolves to an correct module.
1973     ///
1974     /// ```text
1975     ///    |
1976     /// LL | use foobar::Baz;
1977     ///    |     ^^^^^^ did you mean `baz::foobar`?
1978     /// ```
1979     ///
1980     /// Used when importing a submodule of an external crate but missing that crate's
1981     /// name as the first part of path.
1982     fn make_external_crate_suggestion(
1983         &mut self,
1984         mut path: Vec<Segment>,
1985         parent_scope: &ParentScope<'b>,
1986     ) -> Option<(Vec<Segment>, Option<String>)> {
1987         if path[1].ident.span.rust_2015() {
1988             return None;
1989         }
1990
1991         // Sort extern crate names in *reverse* order to get
1992         // 1) some consistent ordering for emitted diagnostics, and
1993         // 2) `std` suggestions before `core` suggestions.
1994         let mut extern_crate_names =
1995             self.r.extern_prelude.iter().map(|(ident, _)| ident.name).collect::<Vec<_>>();
1996         extern_crate_names.sort_by(|a, b| b.as_str().partial_cmp(a.as_str()).unwrap());
1997
1998         for name in extern_crate_names.into_iter() {
1999             // Replace first ident with a crate name and check if that is valid.
2000             path[0].ident.name = name;
2001             let result = self.r.maybe_resolve_path(&path, None, parent_scope);
2002             debug!(
2003                 "make_external_crate_suggestion: name={:?} path={:?} result={:?}",
2004                 name, path, result
2005             );
2006             if let PathResult::Module(..) = result {
2007                 return Some((path, None));
2008             }
2009         }
2010
2011         None
2012     }
2013
2014     /// Suggests importing a macro from the root of the crate rather than a module within
2015     /// the crate.
2016     ///
2017     /// ```text
2018     /// help: a macro with this name exists at the root of the crate
2019     ///    |
2020     /// LL | use issue_59764::makro;
2021     ///    |     ^^^^^^^^^^^^^^^^^^
2022     ///    |
2023     ///    = note: this could be because a macro annotated with `#[macro_export]` will be exported
2024     ///            at the root of the crate instead of the module where it is defined
2025     /// ```
2026     pub(crate) fn check_for_module_export_macro(
2027         &mut self,
2028         import: &'b Import<'b>,
2029         module: ModuleOrUniformRoot<'b>,
2030         ident: Ident,
2031     ) -> Option<(Option<Suggestion>, Option<String>)> {
2032         let ModuleOrUniformRoot::Module(mut crate_module) = module else {
2033             return None;
2034         };
2035
2036         while let Some(parent) = crate_module.parent {
2037             crate_module = parent;
2038         }
2039
2040         if ModuleOrUniformRoot::same_def(ModuleOrUniformRoot::Module(crate_module), module) {
2041             // Don't make a suggestion if the import was already from the root of the
2042             // crate.
2043             return None;
2044         }
2045
2046         let resolutions = self.r.resolutions(crate_module).borrow();
2047         let resolution = resolutions.get(&self.r.new_key(ident, MacroNS))?;
2048         let binding = resolution.borrow().binding()?;
2049         if let Res::Def(DefKind::Macro(MacroKind::Bang), _) = binding.res() {
2050             let module_name = crate_module.kind.name().unwrap();
2051             let import_snippet = match import.kind {
2052                 ImportKind::Single { source, target, .. } if source != target => {
2053                     format!("{} as {}", source, target)
2054                 }
2055                 _ => format!("{}", ident),
2056             };
2057
2058             let mut corrections: Vec<(Span, String)> = Vec::new();
2059             if !import.is_nested() {
2060                 // Assume this is the easy case of `use issue_59764::foo::makro;` and just remove
2061                 // intermediate segments.
2062                 corrections.push((import.span, format!("{}::{}", module_name, import_snippet)));
2063             } else {
2064                 // Find the binding span (and any trailing commas and spaces).
2065                 //   ie. `use a::b::{c, d, e};`
2066                 //                      ^^^
2067                 let (found_closing_brace, binding_span) = find_span_of_binding_until_next_binding(
2068                     self.r.session,
2069                     import.span,
2070                     import.use_span,
2071                 );
2072                 debug!(
2073                     "check_for_module_export_macro: found_closing_brace={:?} binding_span={:?}",
2074                     found_closing_brace, binding_span
2075                 );
2076
2077                 let mut removal_span = binding_span;
2078                 if found_closing_brace {
2079                     // If the binding span ended with a closing brace, as in the below example:
2080                     //   ie. `use a::b::{c, d};`
2081                     //                      ^
2082                     // Then expand the span of characters to remove to include the previous
2083                     // binding's trailing comma.
2084                     //   ie. `use a::b::{c, d};`
2085                     //                    ^^^
2086                     if let Some(previous_span) =
2087                         extend_span_to_previous_binding(self.r.session, binding_span)
2088                     {
2089                         debug!("check_for_module_export_macro: previous_span={:?}", previous_span);
2090                         removal_span = removal_span.with_lo(previous_span.lo());
2091                     }
2092                 }
2093                 debug!("check_for_module_export_macro: removal_span={:?}", removal_span);
2094
2095                 // Remove the `removal_span`.
2096                 corrections.push((removal_span, "".to_string()));
2097
2098                 // Find the span after the crate name and if it has nested imports immediately
2099                 // after the crate name already.
2100                 //   ie. `use a::b::{c, d};`
2101                 //               ^^^^^^^^^
2102                 //   or  `use a::{b, c, d}};`
2103                 //               ^^^^^^^^^^^
2104                 let (has_nested, after_crate_name) = find_span_immediately_after_crate_name(
2105                     self.r.session,
2106                     module_name,
2107                     import.use_span,
2108                 );
2109                 debug!(
2110                     "check_for_module_export_macro: has_nested={:?} after_crate_name={:?}",
2111                     has_nested, after_crate_name
2112                 );
2113
2114                 let source_map = self.r.session.source_map();
2115
2116                 // Add the import to the start, with a `{` if required.
2117                 let start_point = source_map.start_point(after_crate_name);
2118                 if let Ok(start_snippet) = source_map.span_to_snippet(start_point) {
2119                     corrections.push((
2120                         start_point,
2121                         if has_nested {
2122                             // In this case, `start_snippet` must equal '{'.
2123                             format!("{}{}, ", start_snippet, import_snippet)
2124                         } else {
2125                             // In this case, add a `{`, then the moved import, then whatever
2126                             // was there before.
2127                             format!("{{{}, {}", import_snippet, start_snippet)
2128                         },
2129                     ));
2130                 }
2131
2132                 // Add a `};` to the end if nested, matching the `{` added at the start.
2133                 if !has_nested {
2134                     corrections.push((source_map.end_point(after_crate_name), "};".to_string()));
2135                 }
2136             }
2137
2138             let suggestion = Some((
2139                 corrections,
2140                 String::from("a macro with this name exists at the root of the crate"),
2141                 Applicability::MaybeIncorrect,
2142             ));
2143             Some((suggestion, Some("this could be because a macro annotated with `#[macro_export]` will be exported \
2144             at the root of the crate instead of the module where it is defined"
2145                .to_string())))
2146         } else {
2147             None
2148         }
2149     }
2150 }
2151
2152 /// Given a `binding_span` of a binding within a use statement:
2153 ///
2154 /// ```ignore (illustrative)
2155 /// use foo::{a, b, c};
2156 /// //           ^
2157 /// ```
2158 ///
2159 /// then return the span until the next binding or the end of the statement:
2160 ///
2161 /// ```ignore (illustrative)
2162 /// use foo::{a, b, c};
2163 /// //           ^^^
2164 /// ```
2165 fn find_span_of_binding_until_next_binding(
2166     sess: &Session,
2167     binding_span: Span,
2168     use_span: Span,
2169 ) -> (bool, Span) {
2170     let source_map = sess.source_map();
2171
2172     // Find the span of everything after the binding.
2173     //   ie. `a, e};` or `a};`
2174     let binding_until_end = binding_span.with_hi(use_span.hi());
2175
2176     // Find everything after the binding but not including the binding.
2177     //   ie. `, e};` or `};`
2178     let after_binding_until_end = binding_until_end.with_lo(binding_span.hi());
2179
2180     // Keep characters in the span until we encounter something that isn't a comma or
2181     // whitespace.
2182     //   ie. `, ` or ``.
2183     //
2184     // Also note whether a closing brace character was encountered. If there
2185     // was, then later go backwards to remove any trailing commas that are left.
2186     let mut found_closing_brace = false;
2187     let after_binding_until_next_binding =
2188         source_map.span_take_while(after_binding_until_end, |&ch| {
2189             if ch == '}' {
2190                 found_closing_brace = true;
2191             }
2192             ch == ' ' || ch == ','
2193         });
2194
2195     // Combine the two spans.
2196     //   ie. `a, ` or `a`.
2197     //
2198     // Removing these would leave `issue_52891::{d, e};` or `issue_52891::{d, e, };`
2199     let span = binding_span.with_hi(after_binding_until_next_binding.hi());
2200
2201     (found_closing_brace, span)
2202 }
2203
2204 /// Given a `binding_span`, return the span through to the comma or opening brace of the previous
2205 /// binding.
2206 ///
2207 /// ```ignore (illustrative)
2208 /// use foo::a::{a, b, c};
2209 /// //            ^^--- binding span
2210 /// //            |
2211 /// //            returned span
2212 ///
2213 /// use foo::{a, b, c};
2214 /// //        --- binding span
2215 /// ```
2216 fn extend_span_to_previous_binding(sess: &Session, binding_span: Span) -> Option<Span> {
2217     let source_map = sess.source_map();
2218
2219     // `prev_source` will contain all of the source that came before the span.
2220     // Then split based on a command and take the first (ie. closest to our span)
2221     // snippet. In the example, this is a space.
2222     let prev_source = source_map.span_to_prev_source(binding_span).ok()?;
2223
2224     let prev_comma = prev_source.rsplit(',').collect::<Vec<_>>();
2225     let prev_starting_brace = prev_source.rsplit('{').collect::<Vec<_>>();
2226     if prev_comma.len() <= 1 || prev_starting_brace.len() <= 1 {
2227         return None;
2228     }
2229
2230     let prev_comma = prev_comma.first().unwrap();
2231     let prev_starting_brace = prev_starting_brace.first().unwrap();
2232
2233     // If the amount of source code before the comma is greater than
2234     // the amount of source code before the starting brace then we've only
2235     // got one item in the nested item (eg. `issue_52891::{self}`).
2236     if prev_comma.len() > prev_starting_brace.len() {
2237         return None;
2238     }
2239
2240     Some(binding_span.with_lo(BytePos(
2241         // Take away the number of bytes for the characters we've found and an
2242         // extra for the comma.
2243         binding_span.lo().0 - (prev_comma.as_bytes().len() as u32) - 1,
2244     )))
2245 }
2246
2247 /// Given a `use_span` of a binding within a use statement, returns the highlighted span and if
2248 /// it is a nested use tree.
2249 ///
2250 /// ```ignore (illustrative)
2251 /// use foo::a::{b, c};
2252 /// //       ^^^^^^^^^^ -- false
2253 ///
2254 /// use foo::{a, b, c};
2255 /// //       ^^^^^^^^^^ -- true
2256 ///
2257 /// use foo::{a, b::{c, d}};
2258 /// //       ^^^^^^^^^^^^^^^ -- true
2259 /// ```
2260 fn find_span_immediately_after_crate_name(
2261     sess: &Session,
2262     module_name: Symbol,
2263     use_span: Span,
2264 ) -> (bool, Span) {
2265     debug!(
2266         "find_span_immediately_after_crate_name: module_name={:?} use_span={:?}",
2267         module_name, use_span
2268     );
2269     let source_map = sess.source_map();
2270
2271     // Using `use issue_59764::foo::{baz, makro};` as an example throughout..
2272     let mut num_colons = 0;
2273     // Find second colon.. `use issue_59764:`
2274     let until_second_colon = source_map.span_take_while(use_span, |c| {
2275         if *c == ':' {
2276             num_colons += 1;
2277         }
2278         !matches!(c, ':' if num_colons == 2)
2279     });
2280     // Find everything after the second colon.. `foo::{baz, makro};`
2281     let from_second_colon = use_span.with_lo(until_second_colon.hi() + BytePos(1));
2282
2283     let mut found_a_non_whitespace_character = false;
2284     // Find the first non-whitespace character in `from_second_colon`.. `f`
2285     let after_second_colon = source_map.span_take_while(from_second_colon, |c| {
2286         if found_a_non_whitespace_character {
2287             return false;
2288         }
2289         if !c.is_whitespace() {
2290             found_a_non_whitespace_character = true;
2291         }
2292         true
2293     });
2294
2295     // Find the first `{` in from_second_colon.. `foo::{`
2296     let next_left_bracket = source_map.span_through_char(from_second_colon, '{');
2297
2298     (next_left_bracket == after_second_colon, from_second_colon)
2299 }
2300
2301 /// A suggestion has already been emitted, change the wording slightly to clarify that both are
2302 /// independent options.
2303 enum Instead {
2304     Yes,
2305     No,
2306 }
2307
2308 /// Whether an existing place with an `use` item was found.
2309 enum FoundUse {
2310     Yes,
2311     No,
2312 }
2313
2314 /// Whether a binding is part of a pattern or a use statement. Used for diagnostics.
2315 pub(crate) enum DiagnosticMode {
2316     Normal,
2317     /// The binding is part of a pattern
2318     Pattern,
2319     /// The binding is part of a use statement
2320     Import,
2321 }
2322
2323 pub(crate) fn import_candidates(
2324     session: &Session,
2325     source_span: &IndexVec<LocalDefId, Span>,
2326     err: &mut Diagnostic,
2327     // This is `None` if all placement locations are inside expansions
2328     use_placement_span: Option<Span>,
2329     candidates: &[ImportSuggestion],
2330     mode: DiagnosticMode,
2331     append: &str,
2332 ) {
2333     show_candidates(
2334         session,
2335         source_span,
2336         err,
2337         use_placement_span,
2338         candidates,
2339         Instead::Yes,
2340         FoundUse::Yes,
2341         mode,
2342         vec![],
2343         append,
2344     );
2345 }
2346
2347 /// When an entity with a given name is not available in scope, we search for
2348 /// entities with that name in all crates. This method allows outputting the
2349 /// results of this search in a programmer-friendly way
2350 fn show_candidates(
2351     session: &Session,
2352     source_span: &IndexVec<LocalDefId, Span>,
2353     err: &mut Diagnostic,
2354     // This is `None` if all placement locations are inside expansions
2355     use_placement_span: Option<Span>,
2356     candidates: &[ImportSuggestion],
2357     instead: Instead,
2358     found_use: FoundUse,
2359     mode: DiagnosticMode,
2360     path: Vec<Segment>,
2361     append: &str,
2362 ) {
2363     if candidates.is_empty() {
2364         return;
2365     }
2366
2367     let mut accessible_path_strings: Vec<(String, &str, Option<DefId>, &Option<String>)> =
2368         Vec::new();
2369     let mut inaccessible_path_strings: Vec<(String, &str, Option<DefId>, &Option<String>)> =
2370         Vec::new();
2371
2372     candidates.iter().for_each(|c| {
2373         (if c.accessible { &mut accessible_path_strings } else { &mut inaccessible_path_strings })
2374             .push((path_names_to_string(&c.path), c.descr, c.did, &c.note))
2375     });
2376
2377     // we want consistent results across executions, but candidates are produced
2378     // by iterating through a hash map, so make sure they are ordered:
2379     for path_strings in [&mut accessible_path_strings, &mut inaccessible_path_strings] {
2380         path_strings.sort_by(|a, b| a.0.cmp(&b.0));
2381         let core_path_strings =
2382             path_strings.drain_filter(|p| p.0.starts_with("core::")).collect::<Vec<_>>();
2383         path_strings.extend(core_path_strings);
2384         path_strings.dedup_by(|a, b| a.0 == b.0);
2385     }
2386
2387     if !accessible_path_strings.is_empty() {
2388         let (determiner, kind, name) = if accessible_path_strings.len() == 1 {
2389             ("this", accessible_path_strings[0].1, format!(" `{}`", accessible_path_strings[0].0))
2390         } else {
2391             ("one of these", "items", String::new())
2392         };
2393
2394         let instead = if let Instead::Yes = instead { " instead" } else { "" };
2395         let mut msg = if let DiagnosticMode::Pattern = mode {
2396             format!(
2397                 "if you meant to match on {}{}{}, use the full path in the pattern",
2398                 kind, instead, name
2399             )
2400         } else {
2401             format!("consider importing {} {}{}", determiner, kind, instead)
2402         };
2403
2404         for note in accessible_path_strings.iter().flat_map(|cand| cand.3.as_ref()) {
2405             err.note(note);
2406         }
2407
2408         if let Some(span) = use_placement_span {
2409             let add_use = match mode {
2410                 DiagnosticMode::Pattern => {
2411                     err.span_suggestions(
2412                         span,
2413                         &msg,
2414                         accessible_path_strings.into_iter().map(|a| a.0),
2415                         Applicability::MaybeIncorrect,
2416                     );
2417                     return;
2418                 }
2419                 DiagnosticMode::Import => "",
2420                 DiagnosticMode::Normal => "use ",
2421             };
2422             for candidate in &mut accessible_path_strings {
2423                 // produce an additional newline to separate the new use statement
2424                 // from the directly following item.
2425                 let additional_newline = if let FoundUse::Yes = found_use { "" } else { "\n" };
2426                 candidate.0 = format!("{add_use}{}{append};\n{additional_newline}", &candidate.0);
2427             }
2428
2429             err.span_suggestions(
2430                 span,
2431                 &msg,
2432                 accessible_path_strings.into_iter().map(|a| a.0),
2433                 Applicability::MaybeIncorrect,
2434             );
2435             if let [first, .., last] = &path[..] {
2436                 let sp = first.ident.span.until(last.ident.span);
2437                 if sp.can_be_used_for_suggestions() {
2438                     err.span_suggestion_verbose(
2439                         sp,
2440                         &format!("if you import `{}`, refer to it directly", last.ident),
2441                         "",
2442                         Applicability::Unspecified,
2443                     );
2444                 }
2445             }
2446         } else {
2447             msg.push(':');
2448
2449             for candidate in accessible_path_strings {
2450                 msg.push('\n');
2451                 msg.push_str(&candidate.0);
2452             }
2453
2454             err.note(&msg);
2455         }
2456     } else if !matches!(mode, DiagnosticMode::Import) {
2457         assert!(!inaccessible_path_strings.is_empty());
2458
2459         let prefix = if let DiagnosticMode::Pattern = mode {
2460             "you might have meant to match on "
2461         } else {
2462             ""
2463         };
2464         if inaccessible_path_strings.len() == 1 {
2465             let (name, descr, def_id, note) = &inaccessible_path_strings[0];
2466             let msg = format!(
2467                 "{}{} `{}`{} exists but is inaccessible",
2468                 prefix,
2469                 descr,
2470                 name,
2471                 if let DiagnosticMode::Pattern = mode { ", which" } else { "" }
2472             );
2473
2474             if let Some(local_def_id) = def_id.and_then(|did| did.as_local()) {
2475                 let span = source_span[local_def_id];
2476                 let span = session.source_map().guess_head_span(span);
2477                 let mut multi_span = MultiSpan::from_span(span);
2478                 multi_span.push_span_label(span, "not accessible");
2479                 err.span_note(multi_span, &msg);
2480             } else {
2481                 err.note(&msg);
2482             }
2483             if let Some(note) = (*note).as_deref() {
2484                 err.note(note);
2485             }
2486         } else {
2487             let (_, descr_first, _, _) = &inaccessible_path_strings[0];
2488             let descr = if inaccessible_path_strings
2489                 .iter()
2490                 .skip(1)
2491                 .all(|(_, descr, _, _)| descr == descr_first)
2492             {
2493                 descr_first
2494             } else {
2495                 "item"
2496             };
2497             let plural_descr =
2498                 if descr.ends_with('s') { format!("{}es", descr) } else { format!("{}s", descr) };
2499
2500             let mut msg = format!("{}these {} exist but are inaccessible", prefix, plural_descr);
2501             let mut has_colon = false;
2502
2503             let mut spans = Vec::new();
2504             for (name, _, def_id, _) in &inaccessible_path_strings {
2505                 if let Some(local_def_id) = def_id.and_then(|did| did.as_local()) {
2506                     let span = source_span[local_def_id];
2507                     let span = session.source_map().guess_head_span(span);
2508                     spans.push((name, span));
2509                 } else {
2510                     if !has_colon {
2511                         msg.push(':');
2512                         has_colon = true;
2513                     }
2514                     msg.push('\n');
2515                     msg.push_str(name);
2516                 }
2517             }
2518
2519             let mut multi_span = MultiSpan::from_spans(spans.iter().map(|(_, sp)| *sp).collect());
2520             for (name, span) in spans {
2521                 multi_span.push_span_label(span, format!("`{}`: not accessible", name));
2522             }
2523
2524             for note in inaccessible_path_strings.iter().flat_map(|cand| cand.3.as_ref()) {
2525                 err.note(note);
2526             }
2527
2528             err.span_note(multi_span, &msg);
2529         }
2530     }
2531 }
2532
2533 #[derive(Debug)]
2534 struct UsePlacementFinder {
2535     target_module: NodeId,
2536     first_legal_span: Option<Span>,
2537     first_use_span: Option<Span>,
2538 }
2539
2540 impl UsePlacementFinder {
2541     fn check(krate: &Crate, target_module: NodeId) -> (Option<Span>, FoundUse) {
2542         let mut finder =
2543             UsePlacementFinder { target_module, first_legal_span: None, first_use_span: None };
2544         finder.visit_crate(krate);
2545         if let Some(use_span) = finder.first_use_span {
2546             (Some(use_span), FoundUse::Yes)
2547         } else {
2548             (finder.first_legal_span, FoundUse::No)
2549         }
2550     }
2551 }
2552
2553 impl<'tcx> visit::Visitor<'tcx> for UsePlacementFinder {
2554     fn visit_crate(&mut self, c: &Crate) {
2555         if self.target_module == CRATE_NODE_ID {
2556             let inject = c.spans.inject_use_span;
2557             if is_span_suitable_for_use_injection(inject) {
2558                 self.first_legal_span = Some(inject);
2559             }
2560             self.first_use_span = search_for_any_use_in_items(&c.items);
2561             return;
2562         } else {
2563             visit::walk_crate(self, c);
2564         }
2565     }
2566
2567     fn visit_item(&mut self, item: &'tcx ast::Item) {
2568         if self.target_module == item.id {
2569             if let ItemKind::Mod(_, ModKind::Loaded(items, _inline, mod_spans)) = &item.kind {
2570                 let inject = mod_spans.inject_use_span;
2571                 if is_span_suitable_for_use_injection(inject) {
2572                     self.first_legal_span = Some(inject);
2573                 }
2574                 self.first_use_span = search_for_any_use_in_items(items);
2575                 return;
2576             }
2577         } else {
2578             visit::walk_item(self, item);
2579         }
2580     }
2581 }
2582
2583 fn search_for_any_use_in_items(items: &[P<ast::Item>]) -> Option<Span> {
2584     for item in items {
2585         if let ItemKind::Use(..) = item.kind {
2586             if is_span_suitable_for_use_injection(item.span) {
2587                 return Some(item.span.shrink_to_lo());
2588             }
2589         }
2590     }
2591     return None;
2592 }
2593
2594 fn is_span_suitable_for_use_injection(s: Span) -> bool {
2595     // don't suggest placing a use before the prelude
2596     // import or other generated ones
2597     !s.from_expansion()
2598 }
2599
2600 /// Convert the given number into the corresponding ordinal
2601 pub(crate) fn ordinalize(v: usize) -> String {
2602     let suffix = match ((11..=13).contains(&(v % 100)), v % 10) {
2603         (false, 1) => "st",
2604         (false, 2) => "nd",
2605         (false, 3) => "rd",
2606         _ => "th",
2607     };
2608     format!("{v}{suffix}")
2609 }