1use std::ops::ControlFlow;
2
3use itertools::Itertools as _;
4use rustc_ast::visit::{self, Visitor};
5use rustc_ast::{
6 self as ast, CRATE_NODE_ID, Crate, ItemKind, ModKind, NodeId, Path, join_path_idents,
7};
8use rustc_ast_pretty::pprust;
9use rustc_data_structures::fx::{FxHashMap, FxHashSet};
10use rustc_data_structures::unord::{UnordMap, UnordSet};
11use rustc_errors::codes::*;
12use rustc_errors::{
13 Applicability, Diag, DiagCtxtHandle, ErrorGuaranteed, MultiSpan, SuggestionStyle,
14 struct_span_code_err,
15};
16use rustc_feature::BUILTIN_ATTRIBUTES;
17use rustc_hir::attrs::{AttributeKind, CfgEntry, StrippedCfgItem};
18use rustc_hir::def::Namespace::{self, *};
19use rustc_hir::def::{self, CtorKind, CtorOf, DefKind, MacroKinds, NonMacroAttrKind, PerNS};
20use rustc_hir::def_id::{CRATE_DEF_ID, DefId};
21use rustc_hir::{PrimTy, Stability, StabilityLevel, find_attr};
22use rustc_middle::bug;
23use rustc_middle::ty::TyCtxt;
24use rustc_session::Session;
25use rustc_session::lint::BuiltinLintDiag;
26use rustc_session::lint::builtin::{
27 ABSOLUTE_PATHS_NOT_STARTING_WITH_CRATE, AMBIGUOUS_GLOB_IMPORTS,
28 MACRO_EXPANDED_MACRO_EXPORTS_ACCESSED_BY_ABSOLUTE_PATHS,
29};
30use rustc_session::utils::was_invoked_from_cargo;
31use rustc_span::edit_distance::find_best_match_for_name;
32use rustc_span::edition::Edition;
33use rustc_span::hygiene::MacroKind;
34use rustc_span::source_map::{SourceMap, Spanned};
35use rustc_span::{BytePos, Ident, Macros20NormalizedIdent, Span, Symbol, SyntaxContext, kw, sym};
36use thin_vec::{ThinVec, thin_vec};
37use tracing::{debug, instrument};
38
39use crate::errors::{
40 self, AddedMacroUse, ChangeImportBinding, ChangeImportBindingSuggestion, ConsiderAddingADerive,
41 ExplicitUnsafeTraits, MacroDefinedLater, MacroRulesNot, MacroSuggMovePosition,
42 MaybeMissingMacroRulesName,
43};
44use crate::imports::{Import, ImportKind};
45use crate::late::{DiagMetadata, PatternSource, Rib};
46use crate::{
47 AmbiguityError, AmbiguityErrorMisc, AmbiguityKind, BindingError, BindingKey, Finalize,
48 ForwardGenericParamBanReason, HasGenericParams, LexicalScopeBinding, MacroRulesScope, Module,
49 ModuleKind, ModuleOrUniformRoot, NameBinding, NameBindingKind, ParentScope, PathResult,
50 PrivacyError, ResolutionError, Resolver, Scope, ScopeSet, Segment, UseError, Used,
51 VisResolutionError, errors as errs, path_names_to_string,
52};
53
54type Res = def::Res<ast::NodeId>;
55
56pub(crate) type Suggestion = (Vec<(Span, String)>, String, Applicability);
58
59pub(crate) type LabelSuggestion = (Ident, bool);
62
63#[derive(Debug)]
64pub(crate) enum SuggestionTarget {
65 SimilarlyNamed,
67 SingleItem,
69}
70
71#[derive(Debug)]
72pub(crate) struct TypoSuggestion {
73 pub candidate: Symbol,
74 pub span: Option<Span>,
77 pub res: Res,
78 pub target: SuggestionTarget,
79}
80
81impl TypoSuggestion {
82 pub(crate) fn typo_from_ident(ident: Ident, res: Res) -> TypoSuggestion {
83 Self {
84 candidate: ident.name,
85 span: Some(ident.span),
86 res,
87 target: SuggestionTarget::SimilarlyNamed,
88 }
89 }
90 pub(crate) fn typo_from_name(candidate: Symbol, res: Res) -> TypoSuggestion {
91 Self { candidate, span: None, res, target: SuggestionTarget::SimilarlyNamed }
92 }
93 pub(crate) fn single_item_from_ident(ident: Ident, res: Res) -> TypoSuggestion {
94 Self {
95 candidate: ident.name,
96 span: Some(ident.span),
97 res,
98 target: SuggestionTarget::SingleItem,
99 }
100 }
101}
102
103#[derive(Debug, Clone)]
105pub(crate) struct ImportSuggestion {
106 pub did: Option<DefId>,
107 pub descr: &'static str,
108 pub path: Path,
109 pub accessible: bool,
110 pub doc_visible: bool,
112 pub via_import: bool,
113 pub note: Option<String>,
115 pub is_stable: bool,
116}
117
118fn reduce_impl_span_to_impl_keyword(sm: &SourceMap, impl_span: Span) -> Span {
126 let impl_span = sm.span_until_char(impl_span, '<');
127 sm.span_until_whitespace(impl_span)
128}
129
130impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
131 pub(crate) fn dcx(&self) -> DiagCtxtHandle<'tcx> {
132 self.tcx.dcx()
133 }
134
135 pub(crate) fn report_errors(&mut self, krate: &Crate) {
136 self.report_with_use_injections(krate);
137
138 for &(span_use, span_def) in &self.macro_expanded_macro_export_errors {
139 self.lint_buffer.buffer_lint(
140 MACRO_EXPANDED_MACRO_EXPORTS_ACCESSED_BY_ABSOLUTE_PATHS,
141 CRATE_NODE_ID,
142 span_use,
143 errors::MacroExpandedMacroExportsAccessedByAbsolutePaths { definition: span_def },
144 );
145 }
146
147 for ambiguity_error in &self.ambiguity_errors {
148 let diag = self.ambiguity_diagnostic(ambiguity_error);
149
150 if ambiguity_error.warning {
151 let NameBindingKind::Import { import, .. } = ambiguity_error.b1.0.kind else {
152 unreachable!()
153 };
154 self.lint_buffer.buffer_lint(
155 AMBIGUOUS_GLOB_IMPORTS,
156 import.root_id,
157 diag.ident.span,
158 diag,
159 );
160 } else {
161 self.dcx().emit_err(diag);
162 }
163 }
164
165 let mut reported_spans = FxHashSet::default();
166 for error in std::mem::take(&mut self.privacy_errors) {
167 if reported_spans.insert(error.dedup_span) {
168 self.report_privacy_error(&error);
169 }
170 }
171 }
172
173 fn report_with_use_injections(&mut self, krate: &Crate) {
174 for UseError { mut err, candidates, def_id, instead, suggestion, path, is_call } in
175 std::mem::take(&mut self.use_injections)
176 {
177 let (span, found_use) = if let Some(def_id) = def_id.as_local() {
178 UsePlacementFinder::check(krate, self.def_id_to_node_id(def_id))
179 } else {
180 (None, FoundUse::No)
181 };
182
183 if !candidates.is_empty() {
184 show_candidates(
185 self.tcx,
186 &mut err,
187 span,
188 &candidates,
189 if instead { Instead::Yes } else { Instead::No },
190 found_use,
191 DiagMode::Normal,
192 path,
193 "",
194 );
195 err.emit();
196 } else if let Some((span, msg, sugg, appl)) = suggestion {
197 err.span_suggestion_verbose(span, msg, sugg, appl);
198 err.emit();
199 } else if let [segment] = path.as_slice()
200 && is_call
201 {
202 err.stash(segment.ident.span, rustc_errors::StashKey::CallIntoMethod);
203 } else {
204 err.emit();
205 }
206 }
207 }
208
209 pub(crate) fn report_conflict(
210 &mut self,
211 parent: Module<'_>,
212 ident: Ident,
213 ns: Namespace,
214 new_binding: NameBinding<'ra>,
215 old_binding: NameBinding<'ra>,
216 ) {
217 if old_binding.span.lo() > new_binding.span.lo() {
219 return self.report_conflict(parent, ident, ns, old_binding, new_binding);
220 }
221
222 let container = match parent.kind {
223 ModuleKind::Def(kind, _, _) => kind.descr(parent.def_id()),
226 ModuleKind::Block => "block",
227 };
228
229 let (name, span) =
230 (ident.name, self.tcx.sess.source_map().guess_head_span(new_binding.span));
231
232 if self.name_already_seen.get(&name) == Some(&span) {
233 return;
234 }
235
236 let old_kind = match (ns, old_binding.res()) {
237 (ValueNS, _) => "value",
238 (MacroNS, _) => "macro",
239 (TypeNS, _) if old_binding.is_extern_crate() => "extern crate",
240 (TypeNS, Res::Def(DefKind::Mod, _)) => "module",
241 (TypeNS, Res::Def(DefKind::Trait, _)) => "trait",
242 (TypeNS, _) => "type",
243 };
244
245 let code = match (old_binding.is_extern_crate(), new_binding.is_extern_crate()) {
246 (true, true) => E0259,
247 (true, _) | (_, true) => match new_binding.is_import() && old_binding.is_import() {
248 true => E0254,
249 false => E0260,
250 },
251 _ => match (old_binding.is_import_user_facing(), new_binding.is_import_user_facing()) {
252 (false, false) => E0428,
253 (true, true) => E0252,
254 _ => E0255,
255 },
256 };
257
258 let label = match new_binding.is_import_user_facing() {
259 true => errors::NameDefinedMultipleTimeLabel::Reimported { span },
260 false => errors::NameDefinedMultipleTimeLabel::Redefined { span },
261 };
262
263 let old_binding_label =
264 (!old_binding.span.is_dummy() && old_binding.span != span).then(|| {
265 let span = self.tcx.sess.source_map().guess_head_span(old_binding.span);
266 match old_binding.is_import_user_facing() {
267 true => {
268 errors::NameDefinedMultipleTimeOldBindingLabel::Import { span, old_kind }
269 }
270 false => errors::NameDefinedMultipleTimeOldBindingLabel::Definition {
271 span,
272 old_kind,
273 },
274 }
275 });
276
277 let mut err = self
278 .dcx()
279 .create_err(errors::NameDefinedMultipleTime {
280 span,
281 name,
282 descr: ns.descr(),
283 container,
284 label,
285 old_binding_label,
286 })
287 .with_code(code);
288
289 use NameBindingKind::Import;
291 let can_suggest = |binding: NameBinding<'_>, import: self::Import<'_>| {
292 !binding.span.is_dummy()
293 && !matches!(import.kind, ImportKind::MacroUse { .. } | ImportKind::MacroExport)
294 };
295 let import = match (&new_binding.kind, &old_binding.kind) {
296 (Import { import: new, .. }, Import { import: old, .. })
299 if {
300 (new.has_attributes || old.has_attributes)
301 && can_suggest(old_binding, *old)
302 && can_suggest(new_binding, *new)
303 } =>
304 {
305 if old.has_attributes {
306 Some((*new, new_binding.span, true))
307 } else {
308 Some((*old, old_binding.span, true))
309 }
310 }
311 (Import { import, .. }, other) if can_suggest(new_binding, *import) => {
313 Some((*import, new_binding.span, other.is_import()))
314 }
315 (other, Import { import, .. }) if can_suggest(old_binding, *import) => {
316 Some((*import, old_binding.span, other.is_import()))
317 }
318 _ => None,
319 };
320
321 let duplicate = new_binding.res().opt_def_id() == old_binding.res().opt_def_id();
323 let has_dummy_span = new_binding.span.is_dummy() || old_binding.span.is_dummy();
324 let from_item = self
325 .extern_prelude
326 .get(&Macros20NormalizedIdent::new(ident))
327 .is_none_or(|entry| entry.introduced_by_item());
328 let should_remove_import = duplicate
332 && !has_dummy_span
333 && ((new_binding.is_extern_crate() || old_binding.is_extern_crate()) || from_item);
334
335 match import {
336 Some((import, span, true)) if should_remove_import && import.is_nested() => {
337 self.add_suggestion_for_duplicate_nested_use(&mut err, import, span);
338 }
339 Some((import, _, true)) if should_remove_import && !import.is_glob() => {
340 err.subdiagnostic(errors::ToolOnlyRemoveUnnecessaryImport {
343 span: import.use_span_with_attributes,
344 });
345 }
346 Some((import, span, _)) => {
347 self.add_suggestion_for_rename_of_use(&mut err, name, import, span);
348 }
349 _ => {}
350 }
351
352 err.emit();
353 self.name_already_seen.insert(name, span);
354 }
355
356 fn add_suggestion_for_rename_of_use(
366 &self,
367 err: &mut Diag<'_>,
368 name: Symbol,
369 import: Import<'_>,
370 binding_span: Span,
371 ) {
372 let suggested_name = if name.as_str().chars().next().unwrap().is_uppercase() {
373 format!("Other{name}")
374 } else {
375 format!("other_{name}")
376 };
377
378 let mut suggestion = None;
379 let mut span = binding_span;
380 match import.kind {
381 ImportKind::Single { type_ns_only: true, .. } => {
382 suggestion = Some(format!("self as {suggested_name}"))
383 }
384 ImportKind::Single { source, .. } => {
385 if let Some(pos) = source.span.hi().0.checked_sub(binding_span.lo().0)
386 && let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(binding_span)
387 && pos as usize <= snippet.len()
388 {
389 span = binding_span.with_lo(binding_span.lo() + BytePos(pos)).with_hi(
390 binding_span.hi() - BytePos(if snippet.ends_with(';') { 1 } else { 0 }),
391 );
392 suggestion = Some(format!(" as {suggested_name}"));
393 }
394 }
395 ImportKind::ExternCrate { source, target, .. } => {
396 suggestion = Some(format!(
397 "extern crate {} as {};",
398 source.unwrap_or(target.name),
399 suggested_name,
400 ))
401 }
402 _ => unreachable!(),
403 }
404
405 if let Some(suggestion) = suggestion {
406 err.subdiagnostic(ChangeImportBindingSuggestion { span, suggestion });
407 } else {
408 err.subdiagnostic(ChangeImportBinding { span });
409 }
410 }
411
412 fn add_suggestion_for_duplicate_nested_use(
435 &self,
436 err: &mut Diag<'_>,
437 import: Import<'_>,
438 binding_span: Span,
439 ) {
440 assert!(import.is_nested());
441
442 let (found_closing_brace, span) =
450 find_span_of_binding_until_next_binding(self.tcx.sess, binding_span, import.use_span);
451
452 if found_closing_brace {
455 if let Some(span) = extend_span_to_previous_binding(self.tcx.sess, span) {
456 err.subdiagnostic(errors::ToolOnlyRemoveUnnecessaryImport { span });
457 } else {
458 err.subdiagnostic(errors::RemoveUnnecessaryImport {
461 span: import.use_span_with_attributes,
462 });
463 }
464
465 return;
466 }
467
468 err.subdiagnostic(errors::RemoveUnnecessaryImport { span });
469 }
470
471 pub(crate) fn lint_if_path_starts_with_module(
472 &mut self,
473 finalize: Finalize,
474 path: &[Segment],
475 second_binding: Option<NameBinding<'_>>,
476 ) {
477 let Finalize { node_id, root_span, .. } = finalize;
478
479 let first_name = match path.get(0) {
480 Some(seg) if seg.ident.span.is_rust_2015() && self.tcx.sess.is_rust_2015() => {
482 seg.ident.name
483 }
484 _ => return,
485 };
486
487 if first_name != kw::PathRoot {
490 return;
491 }
492
493 match path.get(1) {
494 Some(Segment { ident, .. }) if ident.name == kw::Crate => return,
496 Some(_) => {}
498 None => return,
502 }
503
504 if let Some(binding) = second_binding
508 && let NameBindingKind::Import { import, .. } = binding.kind
509 && let ImportKind::ExternCrate { source: None, .. } = import.kind
511 {
512 return;
513 }
514
515 let diag = BuiltinLintDiag::AbsPathWithModule(root_span);
516 self.lint_buffer.buffer_lint(
517 ABSOLUTE_PATHS_NOT_STARTING_WITH_CRATE,
518 node_id,
519 root_span,
520 diag,
521 );
522 }
523
524 pub(crate) fn add_module_candidates(
525 &self,
526 module: Module<'ra>,
527 names: &mut Vec<TypoSuggestion>,
528 filter_fn: &impl Fn(Res) -> bool,
529 ctxt: Option<SyntaxContext>,
530 ) {
531 module.for_each_child(self, |_this, ident, _ns, binding| {
532 let res = binding.res();
533 if filter_fn(res) && ctxt.is_none_or(|ctxt| ctxt == ident.span.ctxt()) {
534 names.push(TypoSuggestion::typo_from_ident(ident.0, res));
535 }
536 });
537 }
538
539 pub(crate) fn report_error(
544 &mut self,
545 span: Span,
546 resolution_error: ResolutionError<'ra>,
547 ) -> ErrorGuaranteed {
548 self.into_struct_error(span, resolution_error).emit()
549 }
550
551 pub(crate) fn into_struct_error(
552 &mut self,
553 span: Span,
554 resolution_error: ResolutionError<'ra>,
555 ) -> Diag<'_> {
556 match resolution_error {
557 ResolutionError::GenericParamsFromOuterItem {
558 outer_res,
559 has_generic_params,
560 def_kind,
561 inner_item,
562 current_self_ty,
563 } => {
564 use errs::GenericParamsFromOuterItemLabel as Label;
565 let static_or_const = match def_kind {
566 DefKind::Static { .. } => {
567 Some(errs::GenericParamsFromOuterItemStaticOrConst::Static)
568 }
569 DefKind::Const => Some(errs::GenericParamsFromOuterItemStaticOrConst::Const),
570 _ => None,
571 };
572 let is_self =
573 matches!(outer_res, Res::SelfTyParam { .. } | Res::SelfTyAlias { .. });
574 let mut err = errs::GenericParamsFromOuterItem {
575 span,
576 label: None,
577 refer_to_type_directly: None,
578 sugg: None,
579 static_or_const,
580 is_self,
581 item: inner_item.as_ref().map(|(span, kind)| {
582 errs::GenericParamsFromOuterItemInnerItem {
583 span: *span,
584 descr: kind.descr().to_string(),
585 }
586 }),
587 };
588
589 let sm = self.tcx.sess.source_map();
590 let def_id = match outer_res {
591 Res::SelfTyParam { .. } => {
592 err.label = Some(Label::SelfTyParam(span));
593 return self.dcx().create_err(err);
594 }
595 Res::SelfTyAlias { alias_to: def_id, .. } => {
596 err.label = Some(Label::SelfTyAlias(reduce_impl_span_to_impl_keyword(
597 sm,
598 self.def_span(def_id),
599 )));
600 err.refer_to_type_directly =
601 current_self_ty.map(|snippet| errs::UseTypeDirectly { span, snippet });
602 return self.dcx().create_err(err);
603 }
604 Res::Def(DefKind::TyParam, def_id) => {
605 err.label = Some(Label::TyParam(self.def_span(def_id)));
606 def_id
607 }
608 Res::Def(DefKind::ConstParam, def_id) => {
609 err.label = Some(Label::ConstParam(self.def_span(def_id)));
610 def_id
611 }
612 _ => {
613 bug!(
614 "GenericParamsFromOuterItem should only be used with \
615 Res::SelfTyParam, Res::SelfTyAlias, DefKind::TyParam or \
616 DefKind::ConstParam"
617 );
618 }
619 };
620
621 if let HasGenericParams::Yes(span) = has_generic_params
622 && !matches!(inner_item, Some((_, ItemKind::Delegation(..))))
623 {
624 let name = self.tcx.item_name(def_id);
625 let (span, snippet) = if span.is_empty() {
626 let snippet = format!("<{name}>");
627 (span, snippet)
628 } else {
629 let span = sm.span_through_char(span, '<').shrink_to_hi();
630 let snippet = format!("{name}, ");
631 (span, snippet)
632 };
633 err.sugg = Some(errs::GenericParamsFromOuterItemSugg { span, snippet });
634 }
635
636 self.dcx().create_err(err)
637 }
638 ResolutionError::NameAlreadyUsedInParameterList(name, first_use_span) => self
639 .dcx()
640 .create_err(errs::NameAlreadyUsedInParameterList { span, first_use_span, name }),
641 ResolutionError::MethodNotMemberOfTrait(method, trait_, candidate) => {
642 self.dcx().create_err(errs::MethodNotMemberOfTrait {
643 span,
644 method,
645 trait_,
646 sub: candidate.map(|c| errs::AssociatedFnWithSimilarNameExists {
647 span: method.span,
648 candidate: c,
649 }),
650 })
651 }
652 ResolutionError::TypeNotMemberOfTrait(type_, trait_, candidate) => {
653 self.dcx().create_err(errs::TypeNotMemberOfTrait {
654 span,
655 type_,
656 trait_,
657 sub: candidate.map(|c| errs::AssociatedTypeWithSimilarNameExists {
658 span: type_.span,
659 candidate: c,
660 }),
661 })
662 }
663 ResolutionError::ConstNotMemberOfTrait(const_, trait_, candidate) => {
664 self.dcx().create_err(errs::ConstNotMemberOfTrait {
665 span,
666 const_,
667 trait_,
668 sub: candidate.map(|c| errs::AssociatedConstWithSimilarNameExists {
669 span: const_.span,
670 candidate: c,
671 }),
672 })
673 }
674 ResolutionError::VariableNotBoundInPattern(binding_error, parent_scope) => {
675 let BindingError { name, target, origin, could_be_path } = binding_error;
676
677 let mut target_sp = target.iter().map(|pat| pat.span).collect::<Vec<_>>();
678 target_sp.sort();
679 target_sp.dedup();
680 let mut origin_sp = origin.iter().map(|(span, _)| *span).collect::<Vec<_>>();
681 origin_sp.sort();
682 origin_sp.dedup();
683
684 let msp = MultiSpan::from_spans(target_sp.clone());
685 let mut err = self
686 .dcx()
687 .create_err(errors::VariableIsNotBoundInAllPatterns { multispan: msp, name });
688 for sp in target_sp {
689 err.subdiagnostic(errors::PatternDoesntBindName { span: sp, name });
690 }
691 for sp in &origin_sp {
692 err.subdiagnostic(errors::VariableNotInAllPatterns { span: *sp });
693 }
694 let mut suggested_typo = false;
695 if !target.iter().all(|pat| matches!(pat.kind, ast::PatKind::Ident(..)))
696 && !origin.iter().all(|(_, pat)| matches!(pat.kind, ast::PatKind::Ident(..)))
697 {
698 let mut target_visitor = BindingVisitor::default();
701 for pat in &target {
702 target_visitor.visit_pat(pat);
703 }
704 target_visitor.identifiers.sort();
705 target_visitor.identifiers.dedup();
706 let mut origin_visitor = BindingVisitor::default();
707 for (_, pat) in &origin {
708 origin_visitor.visit_pat(pat);
709 }
710 origin_visitor.identifiers.sort();
711 origin_visitor.identifiers.dedup();
712 if let Some(typo) =
714 find_best_match_for_name(&target_visitor.identifiers, name.name, None)
715 && !origin_visitor.identifiers.contains(&typo)
716 {
717 err.subdiagnostic(errors::PatternBindingTypo { spans: origin_sp, typo });
718 suggested_typo = true;
719 }
720 }
721 if could_be_path {
722 let import_suggestions = self.lookup_import_candidates(
723 name,
724 Namespace::ValueNS,
725 &parent_scope,
726 &|res: Res| {
727 matches!(
728 res,
729 Res::Def(
730 DefKind::Ctor(CtorOf::Variant, CtorKind::Const)
731 | DefKind::Ctor(CtorOf::Struct, CtorKind::Const)
732 | DefKind::Const
733 | DefKind::AssocConst,
734 _,
735 )
736 )
737 },
738 );
739
740 if import_suggestions.is_empty() && !suggested_typo {
741 let kinds = [
742 DefKind::Ctor(CtorOf::Variant, CtorKind::Const),
743 DefKind::Ctor(CtorOf::Struct, CtorKind::Const),
744 DefKind::Const,
745 DefKind::AssocConst,
746 ];
747 let mut local_names = vec![];
748 self.add_module_candidates(
749 parent_scope.module,
750 &mut local_names,
751 &|res| matches!(res, Res::Def(_, _)),
752 None,
753 );
754 let local_names: FxHashSet<_> = local_names
755 .into_iter()
756 .filter_map(|s| match s.res {
757 Res::Def(_, def_id) => Some(def_id),
758 _ => None,
759 })
760 .collect();
761
762 let mut local_suggestions = vec![];
763 let mut suggestions = vec![];
764 for kind in kinds {
765 if let Some(suggestion) = self.early_lookup_typo_candidate(
766 ScopeSet::All(Namespace::ValueNS),
767 &parent_scope,
768 name,
769 &|res: Res| match res {
770 Res::Def(k, _) => k == kind,
771 _ => false,
772 },
773 ) && let Res::Def(kind, mut def_id) = suggestion.res
774 {
775 if let DefKind::Ctor(_, _) = kind {
776 def_id = self.tcx.parent(def_id);
777 }
778 let kind = kind.descr(def_id);
779 if local_names.contains(&def_id) {
780 local_suggestions.push((
783 suggestion.candidate,
784 suggestion.candidate.to_string(),
785 kind,
786 ));
787 } else {
788 suggestions.push((
789 suggestion.candidate,
790 self.def_path_str(def_id),
791 kind,
792 ));
793 }
794 }
795 }
796 let suggestions = if !local_suggestions.is_empty() {
797 local_suggestions
800 } else {
801 suggestions
802 };
803 for (name, sugg, kind) in suggestions {
804 err.span_suggestion_verbose(
805 span,
806 format!(
807 "you might have meant to use the similarly named {kind} `{name}`",
808 ),
809 sugg,
810 Applicability::MaybeIncorrect,
811 );
812 suggested_typo = true;
813 }
814 }
815 if import_suggestions.is_empty() && !suggested_typo {
816 let help_msg = format!(
817 "if you meant to match on a unit struct, unit variant or a `const` \
818 item, consider making the path in the pattern qualified: \
819 `path::to::ModOrType::{name}`",
820 );
821 err.span_help(span, help_msg);
822 }
823 show_candidates(
824 self.tcx,
825 &mut err,
826 Some(span),
827 &import_suggestions,
828 Instead::No,
829 FoundUse::Yes,
830 DiagMode::Pattern,
831 vec![],
832 "",
833 );
834 }
835 err
836 }
837 ResolutionError::VariableBoundWithDifferentMode(variable_name, first_binding_span) => {
838 self.dcx().create_err(errs::VariableBoundWithDifferentMode {
839 span,
840 first_binding_span,
841 variable_name,
842 })
843 }
844 ResolutionError::IdentifierBoundMoreThanOnceInParameterList(identifier) => self
845 .dcx()
846 .create_err(errs::IdentifierBoundMoreThanOnceInParameterList { span, identifier }),
847 ResolutionError::IdentifierBoundMoreThanOnceInSamePattern(identifier) => self
848 .dcx()
849 .create_err(errs::IdentifierBoundMoreThanOnceInSamePattern { span, identifier }),
850 ResolutionError::UndeclaredLabel { name, suggestion } => {
851 let ((sub_reachable, sub_reachable_suggestion), sub_unreachable) = match suggestion
852 {
853 Some((ident, true)) => (
855 (
856 Some(errs::LabelWithSimilarNameReachable(ident.span)),
857 Some(errs::TryUsingSimilarlyNamedLabel {
858 span,
859 ident_name: ident.name,
860 }),
861 ),
862 None,
863 ),
864 Some((ident, false)) => (
866 (None, None),
867 Some(errs::UnreachableLabelWithSimilarNameExists {
868 ident_span: ident.span,
869 }),
870 ),
871 None => ((None, None), None),
873 };
874 self.dcx().create_err(errs::UndeclaredLabel {
875 span,
876 name,
877 sub_reachable,
878 sub_reachable_suggestion,
879 sub_unreachable,
880 })
881 }
882 ResolutionError::SelfImportsOnlyAllowedWithin { root, span_with_rename } => {
883 let (suggestion, mpart_suggestion) = if root {
885 (None, None)
886 } else {
887 let suggestion = errs::SelfImportsOnlyAllowedWithinSuggestion { span };
890
891 let mpart_suggestion = errs::SelfImportsOnlyAllowedWithinMultipartSuggestion {
894 multipart_start: span_with_rename.shrink_to_lo(),
895 multipart_end: span_with_rename.shrink_to_hi(),
896 };
897 (Some(suggestion), Some(mpart_suggestion))
898 };
899 self.dcx().create_err(errs::SelfImportsOnlyAllowedWithin {
900 span,
901 suggestion,
902 mpart_suggestion,
903 })
904 }
905 ResolutionError::SelfImportCanOnlyAppearOnceInTheList => {
906 self.dcx().create_err(errs::SelfImportCanOnlyAppearOnceInTheList { span })
907 }
908 ResolutionError::SelfImportOnlyInImportListWithNonEmptyPrefix => {
909 self.dcx().create_err(errs::SelfImportOnlyInImportListWithNonEmptyPrefix { span })
910 }
911 ResolutionError::FailedToResolve { segment, label, suggestion, module } => {
912 let mut err =
913 struct_span_code_err!(self.dcx(), span, E0433, "failed to resolve: {label}");
914 err.span_label(span, label);
915
916 if let Some((suggestions, msg, applicability)) = suggestion {
917 if suggestions.is_empty() {
918 err.help(msg);
919 return err;
920 }
921 err.multipart_suggestion(msg, suggestions, applicability);
922 }
923
924 if let Some(segment) = segment {
925 let module = match module {
926 Some(ModuleOrUniformRoot::Module(m)) if let Some(id) = m.opt_def_id() => id,
927 _ => CRATE_DEF_ID.to_def_id(),
928 };
929 self.find_cfg_stripped(&mut err, &segment, module);
930 }
931
932 err
933 }
934 ResolutionError::CannotCaptureDynamicEnvironmentInFnItem => {
935 self.dcx().create_err(errs::CannotCaptureDynamicEnvironmentInFnItem { span })
936 }
937 ResolutionError::AttemptToUseNonConstantValueInConstant {
938 ident,
939 suggestion,
940 current,
941 type_span,
942 } => {
943 let sp = self
952 .tcx
953 .sess
954 .source_map()
955 .span_extend_to_prev_str(ident.span, current, true, false);
956
957 let ((with, with_label), without) = match sp {
958 Some(sp) if !self.tcx.sess.source_map().is_multiline(sp) => {
959 let sp = sp
960 .with_lo(BytePos(sp.lo().0 - (current.len() as u32)))
961 .until(ident.span);
962 (
963 (Some(errs::AttemptToUseNonConstantValueInConstantWithSuggestion {
964 span: sp,
965 suggestion,
966 current,
967 type_span,
968 }), Some(errs::AttemptToUseNonConstantValueInConstantLabelWithSuggestion {span})),
969 None,
970 )
971 }
972 _ => (
973 (None, None),
974 Some(errs::AttemptToUseNonConstantValueInConstantWithoutSuggestion {
975 ident_span: ident.span,
976 suggestion,
977 }),
978 ),
979 };
980
981 self.dcx().create_err(errs::AttemptToUseNonConstantValueInConstant {
982 span,
983 with,
984 with_label,
985 without,
986 })
987 }
988 ResolutionError::BindingShadowsSomethingUnacceptable {
989 shadowing_binding,
990 name,
991 participle,
992 article,
993 shadowed_binding,
994 shadowed_binding_span,
995 } => self.dcx().create_err(errs::BindingShadowsSomethingUnacceptable {
996 span,
997 shadowing_binding,
998 shadowed_binding,
999 article,
1000 sub_suggestion: match (shadowing_binding, shadowed_binding) {
1001 (
1002 PatternSource::Match,
1003 Res::Def(DefKind::Ctor(CtorOf::Variant | CtorOf::Struct, CtorKind::Fn), _),
1004 ) => Some(errs::BindingShadowsSomethingUnacceptableSuggestion { span, name }),
1005 _ => None,
1006 },
1007 shadowed_binding_span,
1008 participle,
1009 name,
1010 }),
1011 ResolutionError::ForwardDeclaredGenericParam(param, reason) => match reason {
1012 ForwardGenericParamBanReason::Default => {
1013 self.dcx().create_err(errs::ForwardDeclaredGenericParam { param, span })
1014 }
1015 ForwardGenericParamBanReason::ConstParamTy => self
1016 .dcx()
1017 .create_err(errs::ForwardDeclaredGenericInConstParamTy { param, span }),
1018 },
1019 ResolutionError::ParamInTyOfConstParam { name } => {
1020 self.dcx().create_err(errs::ParamInTyOfConstParam { span, name })
1021 }
1022 ResolutionError::ParamInNonTrivialAnonConst { name, param_kind: is_type } => {
1023 self.dcx().create_err(errs::ParamInNonTrivialAnonConst {
1024 span,
1025 name,
1026 param_kind: is_type,
1027 help: self
1028 .tcx
1029 .sess
1030 .is_nightly_build()
1031 .then_some(errs::ParamInNonTrivialAnonConstHelp),
1032 })
1033 }
1034 ResolutionError::ParamInEnumDiscriminant { name, param_kind: is_type } => self
1035 .dcx()
1036 .create_err(errs::ParamInEnumDiscriminant { span, name, param_kind: is_type }),
1037 ResolutionError::ForwardDeclaredSelf(reason) => match reason {
1038 ForwardGenericParamBanReason::Default => {
1039 self.dcx().create_err(errs::SelfInGenericParamDefault { span })
1040 }
1041 ForwardGenericParamBanReason::ConstParamTy => {
1042 self.dcx().create_err(errs::SelfInConstGenericTy { span })
1043 }
1044 },
1045 ResolutionError::UnreachableLabel { name, definition_span, suggestion } => {
1046 let ((sub_suggestion_label, sub_suggestion), sub_unreachable_label) =
1047 match suggestion {
1048 Some((ident, true)) => (
1050 (
1051 Some(errs::UnreachableLabelSubLabel { ident_span: ident.span }),
1052 Some(errs::UnreachableLabelSubSuggestion {
1053 span,
1054 ident_name: ident.name,
1057 }),
1058 ),
1059 None,
1060 ),
1061 Some((ident, false)) => (
1063 (None, None),
1064 Some(errs::UnreachableLabelSubLabelUnreachable {
1065 ident_span: ident.span,
1066 }),
1067 ),
1068 None => ((None, None), None),
1070 };
1071 self.dcx().create_err(errs::UnreachableLabel {
1072 span,
1073 name,
1074 definition_span,
1075 sub_suggestion,
1076 sub_suggestion_label,
1077 sub_unreachable_label,
1078 })
1079 }
1080 ResolutionError::TraitImplMismatch {
1081 name,
1082 kind,
1083 code,
1084 trait_item_span,
1085 trait_path,
1086 } => self
1087 .dcx()
1088 .create_err(errors::TraitImplMismatch {
1089 span,
1090 name,
1091 kind,
1092 trait_path,
1093 trait_item_span,
1094 })
1095 .with_code(code),
1096 ResolutionError::TraitImplDuplicate { name, trait_item_span, old_span } => self
1097 .dcx()
1098 .create_err(errs::TraitImplDuplicate { span, name, trait_item_span, old_span }),
1099 ResolutionError::InvalidAsmSym => self.dcx().create_err(errs::InvalidAsmSym { span }),
1100 ResolutionError::LowercaseSelf => self.dcx().create_err(errs::LowercaseSelf { span }),
1101 ResolutionError::BindingInNeverPattern => {
1102 self.dcx().create_err(errs::BindingInNeverPattern { span })
1103 }
1104 }
1105 }
1106
1107 pub(crate) fn report_vis_error(
1108 &mut self,
1109 vis_resolution_error: VisResolutionError<'_>,
1110 ) -> ErrorGuaranteed {
1111 match vis_resolution_error {
1112 VisResolutionError::Relative2018(span, path) => {
1113 self.dcx().create_err(errs::Relative2018 {
1114 span,
1115 path_span: path.span,
1116 path_str: pprust::path_to_string(path),
1119 })
1120 }
1121 VisResolutionError::AncestorOnly(span) => {
1122 self.dcx().create_err(errs::AncestorOnly(span))
1123 }
1124 VisResolutionError::FailedToResolve(span, label, suggestion) => self.into_struct_error(
1125 span,
1126 ResolutionError::FailedToResolve { segment: None, label, suggestion, module: None },
1127 ),
1128 VisResolutionError::ExpectedFound(span, path_str, res) => {
1129 self.dcx().create_err(errs::ExpectedModuleFound { span, res, path_str })
1130 }
1131 VisResolutionError::Indeterminate(span) => {
1132 self.dcx().create_err(errs::Indeterminate(span))
1133 }
1134 VisResolutionError::ModuleOnly(span) => self.dcx().create_err(errs::ModuleOnly(span)),
1135 }
1136 .emit()
1137 }
1138
1139 fn def_path_str(&self, mut def_id: DefId) -> String {
1140 let mut path = vec![def_id];
1142 while let Some(parent) = self.tcx.opt_parent(def_id) {
1143 def_id = parent;
1144 path.push(def_id);
1145 if def_id.is_top_level_module() {
1146 break;
1147 }
1148 }
1149 path.into_iter()
1151 .rev()
1152 .map(|def_id| {
1153 self.tcx
1154 .opt_item_name(def_id)
1155 .map(|name| {
1156 match (
1157 def_id.is_top_level_module(),
1158 def_id.is_local(),
1159 self.tcx.sess.edition(),
1160 ) {
1161 (true, true, Edition::Edition2015) => String::new(),
1162 (true, true, _) => kw::Crate.to_string(),
1163 (true, false, _) | (false, _, _) => name.to_string(),
1164 }
1165 })
1166 .unwrap_or_else(|| "_".to_string())
1167 })
1168 .collect::<Vec<String>>()
1169 .join("::")
1170 }
1171
1172 pub(crate) fn add_scope_set_candidates(
1173 &mut self,
1174 suggestions: &mut Vec<TypoSuggestion>,
1175 scope_set: ScopeSet<'ra>,
1176 ps: &ParentScope<'ra>,
1177 ctxt: SyntaxContext,
1178 filter_fn: &impl Fn(Res) -> bool,
1179 ) {
1180 self.cm().visit_scopes(scope_set, ps, ctxt, None, |this, scope, use_prelude, _| {
1181 match scope {
1182 Scope::DeriveHelpers(expn_id) => {
1183 let res = Res::NonMacroAttr(NonMacroAttrKind::DeriveHelper);
1184 if filter_fn(res) {
1185 suggestions.extend(
1186 this.helper_attrs
1187 .get(&expn_id)
1188 .into_iter()
1189 .flatten()
1190 .map(|(ident, _)| TypoSuggestion::typo_from_ident(*ident, res)),
1191 );
1192 }
1193 }
1194 Scope::DeriveHelpersCompat => {
1195 }
1197 Scope::MacroRules(macro_rules_scope) => {
1198 if let MacroRulesScope::Binding(macro_rules_binding) = macro_rules_scope.get() {
1199 let res = macro_rules_binding.binding.res();
1200 if filter_fn(res) {
1201 suggestions.push(TypoSuggestion::typo_from_ident(
1202 macro_rules_binding.ident,
1203 res,
1204 ))
1205 }
1206 }
1207 }
1208 Scope::Module(module, _) => {
1209 this.add_module_candidates(module, suggestions, filter_fn, None);
1210 }
1211 Scope::MacroUsePrelude => {
1212 suggestions.extend(this.macro_use_prelude.iter().filter_map(
1213 |(name, binding)| {
1214 let res = binding.res();
1215 filter_fn(res).then_some(TypoSuggestion::typo_from_name(*name, res))
1216 },
1217 ));
1218 }
1219 Scope::BuiltinAttrs => {
1220 let res = Res::NonMacroAttr(NonMacroAttrKind::Builtin(sym::dummy));
1221 if filter_fn(res) {
1222 suggestions.extend(
1223 BUILTIN_ATTRIBUTES
1224 .iter()
1225 .map(|attr| TypoSuggestion::typo_from_name(attr.name, res)),
1226 );
1227 }
1228 }
1229 Scope::ExternPreludeItems => {
1230 suggestions.extend(this.extern_prelude.keys().filter_map(|ident| {
1232 let res = Res::Def(DefKind::Mod, CRATE_DEF_ID.to_def_id());
1233 filter_fn(res).then_some(TypoSuggestion::typo_from_ident(ident.0, res))
1234 }));
1235 }
1236 Scope::ExternPreludeFlags => {}
1237 Scope::ToolPrelude => {
1238 let res = Res::NonMacroAttr(NonMacroAttrKind::Tool);
1239 suggestions.extend(
1240 this.registered_tools
1241 .iter()
1242 .map(|ident| TypoSuggestion::typo_from_ident(*ident, res)),
1243 );
1244 }
1245 Scope::StdLibPrelude => {
1246 if let Some(prelude) = this.prelude {
1247 let mut tmp_suggestions = Vec::new();
1248 this.add_module_candidates(prelude, &mut tmp_suggestions, filter_fn, None);
1249 suggestions.extend(
1250 tmp_suggestions
1251 .into_iter()
1252 .filter(|s| use_prelude.into() || this.is_builtin_macro(s.res)),
1253 );
1254 }
1255 }
1256 Scope::BuiltinTypes => {
1257 suggestions.extend(PrimTy::ALL.iter().filter_map(|prim_ty| {
1258 let res = Res::PrimTy(*prim_ty);
1259 filter_fn(res)
1260 .then_some(TypoSuggestion::typo_from_name(prim_ty.name(), res))
1261 }))
1262 }
1263 }
1264
1265 ControlFlow::<()>::Continue(())
1266 });
1267 }
1268
1269 fn early_lookup_typo_candidate(
1271 &mut self,
1272 scope_set: ScopeSet<'ra>,
1273 parent_scope: &ParentScope<'ra>,
1274 ident: Ident,
1275 filter_fn: &impl Fn(Res) -> bool,
1276 ) -> Option<TypoSuggestion> {
1277 let mut suggestions = Vec::new();
1278 let ctxt = ident.span.ctxt();
1279 self.add_scope_set_candidates(&mut suggestions, scope_set, parent_scope, ctxt, filter_fn);
1280
1281 suggestions.sort_by(|a, b| a.candidate.as_str().cmp(b.candidate.as_str()));
1283
1284 match find_best_match_for_name(
1285 &suggestions.iter().map(|suggestion| suggestion.candidate).collect::<Vec<Symbol>>(),
1286 ident.name,
1287 None,
1288 ) {
1289 Some(found) if found != ident.name => {
1290 suggestions.into_iter().find(|suggestion| suggestion.candidate == found)
1291 }
1292 _ => None,
1293 }
1294 }
1295
1296 fn lookup_import_candidates_from_module<FilterFn>(
1297 &self,
1298 lookup_ident: Ident,
1299 namespace: Namespace,
1300 parent_scope: &ParentScope<'ra>,
1301 start_module: Module<'ra>,
1302 crate_path: ThinVec<ast::PathSegment>,
1303 filter_fn: FilterFn,
1304 ) -> Vec<ImportSuggestion>
1305 where
1306 FilterFn: Fn(Res) -> bool,
1307 {
1308 let mut candidates = Vec::new();
1309 let mut seen_modules = FxHashSet::default();
1310 let start_did = start_module.def_id();
1311 let mut worklist = vec![(
1312 start_module,
1313 ThinVec::<ast::PathSegment>::new(),
1314 true,
1315 start_did.is_local() || !self.tcx.is_doc_hidden(start_did),
1316 true,
1317 )];
1318 let mut worklist_via_import = vec![];
1319
1320 while let Some((in_module, path_segments, accessible, doc_visible, is_stable)) =
1321 match worklist.pop() {
1322 None => worklist_via_import.pop(),
1323 Some(x) => Some(x),
1324 }
1325 {
1326 let in_module_is_extern = !in_module.def_id().is_local();
1327 in_module.for_each_child(self, |this, ident, ns, name_binding| {
1328 if name_binding.is_assoc_item()
1330 && !this.tcx.features().import_trait_associated_functions()
1331 {
1332 return;
1333 }
1334
1335 if ident.name == kw::Underscore {
1336 return;
1337 }
1338
1339 let child_accessible =
1340 accessible && this.is_accessible_from(name_binding.vis, parent_scope.module);
1341
1342 if in_module_is_extern && !child_accessible {
1344 return;
1345 }
1346
1347 let via_import = name_binding.is_import() && !name_binding.is_extern_crate();
1348
1349 if via_import && name_binding.is_possibly_imported_variant() {
1355 return;
1356 }
1357
1358 if let NameBindingKind::Import { binding, .. } = name_binding.kind
1360 && this.is_accessible_from(binding.vis, parent_scope.module)
1361 && !this.is_accessible_from(name_binding.vis, parent_scope.module)
1362 {
1363 return;
1364 }
1365
1366 let res = name_binding.res();
1367 let did = match res {
1368 Res::Def(DefKind::Ctor(..), did) => this.tcx.opt_parent(did),
1369 _ => res.opt_def_id(),
1370 };
1371 let child_doc_visible = doc_visible
1372 && did.is_none_or(|did| did.is_local() || !this.tcx.is_doc_hidden(did));
1373
1374 if ident.name == lookup_ident.name
1378 && ns == namespace
1379 && in_module != parent_scope.module
1380 && !ident.span.normalize_to_macros_2_0().from_expansion()
1381 && filter_fn(res)
1382 {
1383 let mut segms = if lookup_ident.span.at_least_rust_2018() {
1385 crate_path.clone()
1388 } else {
1389 ThinVec::new()
1390 };
1391 segms.append(&mut path_segments.clone());
1392
1393 segms.push(ast::PathSegment::from_ident(ident.0));
1394 let path = Path { span: name_binding.span, segments: segms, tokens: None };
1395
1396 if child_accessible
1397 && let Some(idx) = candidates
1399 .iter()
1400 .position(|v: &ImportSuggestion| v.did == did && !v.accessible)
1401 {
1402 candidates.remove(idx);
1403 }
1404
1405 let is_stable = if is_stable
1406 && let Some(did) = did
1407 && this.is_stable(did, path.span)
1408 {
1409 true
1410 } else {
1411 false
1412 };
1413
1414 if is_stable
1419 && let Some(idx) = candidates
1420 .iter()
1421 .position(|v: &ImportSuggestion| v.did == did && !v.is_stable)
1422 {
1423 candidates.remove(idx);
1424 }
1425
1426 if candidates.iter().all(|v: &ImportSuggestion| v.did != did) {
1427 let note = if let Some(did) = did {
1430 let requires_note = !did.is_local()
1431 && this.tcx.get_attrs(did, sym::rustc_diagnostic_item).any(
1432 |attr| {
1433 [sym::TryInto, sym::TryFrom, sym::FromIterator]
1434 .map(|x| Some(x))
1435 .contains(&attr.value_str())
1436 },
1437 );
1438
1439 requires_note.then(|| {
1440 format!(
1441 "'{}' is included in the prelude starting in Edition 2021",
1442 path_names_to_string(&path)
1443 )
1444 })
1445 } else {
1446 None
1447 };
1448
1449 candidates.push(ImportSuggestion {
1450 did,
1451 descr: res.descr(),
1452 path,
1453 accessible: child_accessible,
1454 doc_visible: child_doc_visible,
1455 note,
1456 via_import,
1457 is_stable,
1458 });
1459 }
1460 }
1461
1462 if let Some(def_id) = name_binding.res().module_like_def_id() {
1464 let mut path_segments = path_segments.clone();
1466 path_segments.push(ast::PathSegment::from_ident(ident.0));
1467
1468 let alias_import = if let NameBindingKind::Import { import, .. } =
1469 name_binding.kind
1470 && let ImportKind::ExternCrate { source: Some(_), .. } = import.kind
1471 && import.parent_scope.expansion == parent_scope.expansion
1472 {
1473 true
1474 } else {
1475 false
1476 };
1477
1478 let is_extern_crate_that_also_appears_in_prelude =
1479 name_binding.is_extern_crate() && lookup_ident.span.at_least_rust_2018();
1480
1481 if !is_extern_crate_that_also_appears_in_prelude || alias_import {
1482 if seen_modules.insert(def_id) {
1484 if via_import { &mut worklist_via_import } else { &mut worklist }.push(
1485 (
1486 this.expect_module(def_id),
1487 path_segments,
1488 child_accessible,
1489 child_doc_visible,
1490 is_stable && this.is_stable(def_id, name_binding.span),
1491 ),
1492 );
1493 }
1494 }
1495 }
1496 })
1497 }
1498
1499 candidates
1500 }
1501
1502 fn is_stable(&self, did: DefId, span: Span) -> bool {
1503 if did.is_local() {
1504 return true;
1505 }
1506
1507 match self.tcx.lookup_stability(did) {
1508 Some(Stability {
1509 level: StabilityLevel::Unstable { implied_by, .. }, feature, ..
1510 }) => {
1511 if span.allows_unstable(feature) {
1512 true
1513 } else if self.tcx.features().enabled(feature) {
1514 true
1515 } else if let Some(implied_by) = implied_by
1516 && self.tcx.features().enabled(implied_by)
1517 {
1518 true
1519 } else {
1520 false
1521 }
1522 }
1523 Some(_) => true,
1524 None => false,
1525 }
1526 }
1527
1528 pub(crate) fn lookup_import_candidates<FilterFn>(
1536 &mut self,
1537 lookup_ident: Ident,
1538 namespace: Namespace,
1539 parent_scope: &ParentScope<'ra>,
1540 filter_fn: FilterFn,
1541 ) -> Vec<ImportSuggestion>
1542 where
1543 FilterFn: Fn(Res) -> bool,
1544 {
1545 let crate_path = thin_vec![ast::PathSegment::from_ident(Ident::with_dummy_span(kw::Crate))];
1546 let mut suggestions = self.lookup_import_candidates_from_module(
1547 lookup_ident,
1548 namespace,
1549 parent_scope,
1550 self.graph_root,
1551 crate_path,
1552 &filter_fn,
1553 );
1554
1555 if lookup_ident.span.at_least_rust_2018() {
1556 for &ident in self.extern_prelude.keys() {
1557 if ident.span.from_expansion() {
1558 continue;
1564 }
1565 let Some(crate_id) =
1566 self.cstore_mut().maybe_process_path_extern(self.tcx, ident.name)
1567 else {
1568 continue;
1569 };
1570
1571 let crate_def_id = crate_id.as_def_id();
1572 let crate_root = self.expect_module(crate_def_id);
1573
1574 let needs_disambiguation =
1578 self.resolutions(parent_scope.module).borrow().iter().any(
1579 |(key, name_resolution)| {
1580 if key.ns == TypeNS
1581 && key.ident == ident
1582 && let Some(binding) = name_resolution.borrow().best_binding()
1583 {
1584 match binding.res() {
1585 Res::Def(_, def_id) => def_id != crate_def_id,
1588 Res::PrimTy(_) => true,
1589 _ => false,
1590 }
1591 } else {
1592 false
1593 }
1594 },
1595 );
1596 let mut crate_path = ThinVec::new();
1597 if needs_disambiguation {
1598 crate_path.push(ast::PathSegment::path_root(rustc_span::DUMMY_SP));
1599 }
1600 crate_path.push(ast::PathSegment::from_ident(ident.0));
1601
1602 suggestions.extend(self.lookup_import_candidates_from_module(
1603 lookup_ident,
1604 namespace,
1605 parent_scope,
1606 crate_root,
1607 crate_path,
1608 &filter_fn,
1609 ));
1610 }
1611 }
1612
1613 suggestions
1614 }
1615
1616 pub(crate) fn unresolved_macro_suggestions(
1617 &mut self,
1618 err: &mut Diag<'_>,
1619 macro_kind: MacroKind,
1620 parent_scope: &ParentScope<'ra>,
1621 ident: Ident,
1622 krate: &Crate,
1623 sugg_span: Option<Span>,
1624 ) {
1625 self.register_macros_for_all_crates();
1628
1629 let is_expected =
1630 &|res: Res| res.macro_kinds().is_some_and(|k| k.contains(macro_kind.into()));
1631 let suggestion = self.early_lookup_typo_candidate(
1632 ScopeSet::Macro(macro_kind),
1633 parent_scope,
1634 ident,
1635 is_expected,
1636 );
1637 if !self.add_typo_suggestion(err, suggestion, ident.span) {
1638 self.detect_derive_attribute(err, ident, parent_scope, sugg_span);
1639 }
1640
1641 let import_suggestions =
1642 self.lookup_import_candidates(ident, Namespace::MacroNS, parent_scope, is_expected);
1643 let (span, found_use) = match parent_scope.module.nearest_parent_mod().as_local() {
1644 Some(def_id) => UsePlacementFinder::check(krate, self.def_id_to_node_id(def_id)),
1645 None => (None, FoundUse::No),
1646 };
1647 show_candidates(
1648 self.tcx,
1649 err,
1650 span,
1651 &import_suggestions,
1652 Instead::No,
1653 found_use,
1654 DiagMode::Normal,
1655 vec![],
1656 "",
1657 );
1658
1659 if macro_kind == MacroKind::Bang && ident.name == sym::macro_rules {
1660 let label_span = ident.span.shrink_to_hi();
1661 let mut spans = MultiSpan::from_span(label_span);
1662 spans.push_span_label(label_span, "put a macro name here");
1663 err.subdiagnostic(MaybeMissingMacroRulesName { spans });
1664 return;
1665 }
1666
1667 if macro_kind == MacroKind::Derive && (ident.name == sym::Send || ident.name == sym::Sync) {
1668 err.subdiagnostic(ExplicitUnsafeTraits { span: ident.span, ident });
1669 return;
1670 }
1671
1672 let unused_macro = self.unused_macros.iter().find_map(|(def_id, (_, unused_ident))| {
1673 if unused_ident.name == ident.name { Some((def_id, unused_ident)) } else { None }
1674 });
1675
1676 if let Some((def_id, unused_ident)) = unused_macro {
1677 let scope = self.local_macro_def_scopes[&def_id];
1678 let parent_nearest = parent_scope.module.nearest_parent_mod();
1679 let unused_macro_kinds = self.local_macro_map[def_id].ext.macro_kinds();
1680 if !unused_macro_kinds.contains(macro_kind.into()) {
1681 match macro_kind {
1682 MacroKind::Bang => {
1683 err.subdiagnostic(MacroRulesNot::Func { span: unused_ident.span, ident });
1684 }
1685 MacroKind::Attr => {
1686 err.subdiagnostic(MacroRulesNot::Attr { span: unused_ident.span, ident });
1687 }
1688 MacroKind::Derive => {
1689 err.subdiagnostic(MacroRulesNot::Derive { span: unused_ident.span, ident });
1690 }
1691 }
1692 return;
1693 }
1694 if Some(parent_nearest) == scope.opt_def_id() {
1695 err.subdiagnostic(MacroDefinedLater { span: unused_ident.span });
1696 err.subdiagnostic(MacroSuggMovePosition { span: ident.span, ident });
1697 return;
1698 }
1699 }
1700
1701 if ident.name == kw::Default
1702 && let ModuleKind::Def(DefKind::Enum, def_id, _) = parent_scope.module.kind
1703 {
1704 let span = self.def_span(def_id);
1705 let source_map = self.tcx.sess.source_map();
1706 let head_span = source_map.guess_head_span(span);
1707 err.subdiagnostic(ConsiderAddingADerive {
1708 span: head_span.shrink_to_lo(),
1709 suggestion: "#[derive(Default)]\n".to_string(),
1710 });
1711 }
1712 for ns in [Namespace::MacroNS, Namespace::TypeNS, Namespace::ValueNS] {
1713 let Ok(binding) = self.cm().resolve_ident_in_scope_set(
1714 ident,
1715 ScopeSet::All(ns),
1716 parent_scope,
1717 None,
1718 false,
1719 None,
1720 None,
1721 ) else {
1722 continue;
1723 };
1724
1725 let desc = match binding.res() {
1726 Res::Def(DefKind::Macro(MacroKinds::BANG), _) => {
1727 "a function-like macro".to_string()
1728 }
1729 Res::Def(DefKind::Macro(MacroKinds::ATTR), _) | Res::NonMacroAttr(..) => {
1730 format!("an attribute: `#[{ident}]`")
1731 }
1732 Res::Def(DefKind::Macro(MacroKinds::DERIVE), _) => {
1733 format!("a derive macro: `#[derive({ident})]`")
1734 }
1735 Res::Def(DefKind::Macro(kinds), _) => {
1736 format!("{} {}", kinds.article(), kinds.descr())
1737 }
1738 Res::ToolMod => {
1739 continue;
1741 }
1742 Res::Def(DefKind::Trait, _) if macro_kind == MacroKind::Derive => {
1743 "only a trait, without a derive macro".to_string()
1744 }
1745 res => format!(
1746 "{} {}, not {} {}",
1747 res.article(),
1748 res.descr(),
1749 macro_kind.article(),
1750 macro_kind.descr_expected(),
1751 ),
1752 };
1753 if let crate::NameBindingKind::Import { import, .. } = binding.kind
1754 && !import.span.is_dummy()
1755 {
1756 let note = errors::IdentImporterHereButItIsDesc {
1757 span: import.span,
1758 imported_ident: ident,
1759 imported_ident_desc: &desc,
1760 };
1761 err.subdiagnostic(note);
1762 self.record_use(ident, binding, Used::Other);
1765 return;
1766 }
1767 let note = errors::IdentInScopeButItIsDesc {
1768 imported_ident: ident,
1769 imported_ident_desc: &desc,
1770 };
1771 err.subdiagnostic(note);
1772 return;
1773 }
1774
1775 if self.macro_names.contains(&ident.normalize_to_macros_2_0()) {
1776 err.subdiagnostic(AddedMacroUse);
1777 return;
1778 }
1779 }
1780
1781 fn detect_derive_attribute(
1784 &self,
1785 err: &mut Diag<'_>,
1786 ident: Ident,
1787 parent_scope: &ParentScope<'ra>,
1788 sugg_span: Option<Span>,
1789 ) {
1790 let mut derives = vec![];
1795 let mut all_attrs: UnordMap<Symbol, Vec<_>> = UnordMap::default();
1796 #[allow(rustc::potential_query_instability)]
1798 for (def_id, data) in self
1799 .local_macro_map
1800 .iter()
1801 .map(|(local_id, data)| (local_id.to_def_id(), data))
1802 .chain(self.extern_macro_map.borrow().iter().map(|(id, d)| (*id, d)))
1803 {
1804 for helper_attr in &data.ext.helper_attrs {
1805 let item_name = self.tcx.item_name(def_id);
1806 all_attrs.entry(*helper_attr).or_default().push(item_name);
1807 if helper_attr == &ident.name {
1808 derives.push(item_name);
1809 }
1810 }
1811 }
1812 let kind = MacroKind::Derive.descr();
1813 if !derives.is_empty() {
1814 let mut derives: Vec<String> = derives.into_iter().map(|d| d.to_string()).collect();
1816 derives.sort();
1817 derives.dedup();
1818 let msg = match &derives[..] {
1819 [derive] => format!(" `{derive}`"),
1820 [start @ .., last] => format!(
1821 "s {} and `{last}`",
1822 start.iter().map(|d| format!("`{d}`")).collect::<Vec<_>>().join(", ")
1823 ),
1824 [] => unreachable!("we checked for this to be non-empty 10 lines above!?"),
1825 };
1826 let msg = format!(
1827 "`{}` is an attribute that can be used by the {kind}{msg}, you might be \
1828 missing a `derive` attribute",
1829 ident.name,
1830 );
1831 let sugg_span = if let ModuleKind::Def(DefKind::Enum, id, _) = parent_scope.module.kind
1832 {
1833 let span = self.def_span(id);
1834 if span.from_expansion() {
1835 None
1836 } else {
1837 Some(span.shrink_to_lo())
1839 }
1840 } else {
1841 sugg_span
1843 };
1844 match sugg_span {
1845 Some(span) => {
1846 err.span_suggestion_verbose(
1847 span,
1848 msg,
1849 format!("#[derive({})]\n", derives.join(", ")),
1850 Applicability::MaybeIncorrect,
1851 );
1852 }
1853 None => {
1854 err.note(msg);
1855 }
1856 }
1857 } else {
1858 let all_attr_names = all_attrs.keys().map(|s| *s).into_sorted_stable_ord();
1860 if let Some(best_match) = find_best_match_for_name(&all_attr_names, ident.name, None)
1861 && let Some(macros) = all_attrs.get(&best_match)
1862 {
1863 let mut macros: Vec<String> = macros.into_iter().map(|d| d.to_string()).collect();
1864 macros.sort();
1865 macros.dedup();
1866 let msg = match ¯os[..] {
1867 [] => return,
1868 [name] => format!(" `{name}` accepts"),
1869 [start @ .., end] => format!(
1870 "s {} and `{end}` accept",
1871 start.iter().map(|m| format!("`{m}`")).collect::<Vec<_>>().join(", "),
1872 ),
1873 };
1874 let msg = format!("the {kind}{msg} the similarly named `{best_match}` attribute");
1875 err.span_suggestion_verbose(
1876 ident.span,
1877 msg,
1878 best_match,
1879 Applicability::MaybeIncorrect,
1880 );
1881 }
1882 }
1883 }
1884
1885 pub(crate) fn add_typo_suggestion(
1886 &self,
1887 err: &mut Diag<'_>,
1888 suggestion: Option<TypoSuggestion>,
1889 span: Span,
1890 ) -> bool {
1891 let suggestion = match suggestion {
1892 None => return false,
1893 Some(suggestion) if suggestion.candidate == kw::Underscore => return false,
1895 Some(suggestion) => suggestion,
1896 };
1897
1898 let mut did_label_def_span = false;
1899
1900 if let Some(def_span) = suggestion.res.opt_def_id().map(|def_id| self.def_span(def_id)) {
1901 if span.overlaps(def_span) {
1902 return false;
1921 }
1922 let span = self.tcx.sess.source_map().guess_head_span(def_span);
1923 let candidate_descr = suggestion.res.descr();
1924 let candidate = suggestion.candidate;
1925 let label = match suggestion.target {
1926 SuggestionTarget::SimilarlyNamed => {
1927 errors::DefinedHere::SimilarlyNamed { span, candidate_descr, candidate }
1928 }
1929 SuggestionTarget::SingleItem => {
1930 errors::DefinedHere::SingleItem { span, candidate_descr, candidate }
1931 }
1932 };
1933 did_label_def_span = true;
1934 err.subdiagnostic(label);
1935 }
1936
1937 let (span, msg, sugg) = if let SuggestionTarget::SimilarlyNamed = suggestion.target
1938 && let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span)
1939 && let Some(span) = suggestion.span
1940 && let Some(candidate) = suggestion.candidate.as_str().strip_prefix('_')
1941 && snippet == candidate
1942 {
1943 let candidate = suggestion.candidate;
1944 let msg = format!(
1947 "the leading underscore in `{candidate}` marks it as unused, consider renaming it to `{snippet}`"
1948 );
1949 if !did_label_def_span {
1950 err.span_label(span, format!("`{candidate}` defined here"));
1951 }
1952 (span, msg, snippet)
1953 } else {
1954 let msg = match suggestion.target {
1955 SuggestionTarget::SimilarlyNamed => format!(
1956 "{} {} with a similar name exists",
1957 suggestion.res.article(),
1958 suggestion.res.descr()
1959 ),
1960 SuggestionTarget::SingleItem => {
1961 format!("maybe you meant this {}", suggestion.res.descr())
1962 }
1963 };
1964 (span, msg, suggestion.candidate.to_ident_string())
1965 };
1966 err.span_suggestion(span, msg, sugg, Applicability::MaybeIncorrect);
1967 true
1968 }
1969
1970 fn binding_description(&self, b: NameBinding<'_>, ident: Ident, from_prelude: bool) -> String {
1971 let res = b.res();
1972 if b.span.is_dummy() || !self.tcx.sess.source_map().is_span_accessible(b.span) {
1973 let add_built_in =
1975 !matches!(b.res(), Res::NonMacroAttr(..) | Res::PrimTy(..) | Res::ToolMod);
1976 let (built_in, from) = if from_prelude {
1977 ("", " from prelude")
1978 } else if b.is_extern_crate()
1979 && !b.is_import()
1980 && self.tcx.sess.opts.externs.get(ident.as_str()).is_some()
1981 {
1982 ("", " passed with `--extern`")
1983 } else if add_built_in {
1984 (" built-in", "")
1985 } else {
1986 ("", "")
1987 };
1988
1989 let a = if built_in.is_empty() { res.article() } else { "a" };
1990 format!("{a}{built_in} {thing}{from}", thing = res.descr())
1991 } else {
1992 let introduced = if b.is_import_user_facing() { "imported" } else { "defined" };
1993 format!("the {thing} {introduced} here", thing = res.descr())
1994 }
1995 }
1996
1997 fn ambiguity_diagnostic(&self, ambiguity_error: &AmbiguityError<'ra>) -> errors::Ambiguity {
1998 let AmbiguityError { kind, ident, b1, b2, misc1, misc2, .. } = *ambiguity_error;
1999 let extern_prelude_ambiguity = || {
2000 self.extern_prelude.get(&Macros20NormalizedIdent::new(ident)).is_some_and(|entry| {
2001 entry.item_binding.map(|(b, _)| b) == Some(b1)
2002 && entry.flag_binding.as_ref().and_then(|pb| pb.get().0.binding()) == Some(b2)
2003 })
2004 };
2005 let (b1, b2, misc1, misc2, swapped) = if b2.span.is_dummy() && !b1.span.is_dummy() {
2006 (b2, b1, misc2, misc1, true)
2008 } else {
2009 (b1, b2, misc1, misc2, false)
2010 };
2011
2012 let could_refer_to = |b: NameBinding<'_>, misc: AmbiguityErrorMisc, also: &str| {
2013 let what = self.binding_description(b, ident, misc == AmbiguityErrorMisc::FromPrelude);
2014 let note_msg = format!("`{ident}` could{also} refer to {what}");
2015
2016 let thing = b.res().descr();
2017 let mut help_msgs = Vec::new();
2018 if b.is_glob_import()
2019 && (kind == AmbiguityKind::GlobVsGlob
2020 || kind == AmbiguityKind::GlobVsExpanded
2021 || kind == AmbiguityKind::GlobVsOuter && swapped != also.is_empty())
2022 {
2023 help_msgs.push(format!(
2024 "consider adding an explicit import of `{ident}` to disambiguate"
2025 ))
2026 }
2027 if b.is_extern_crate() && ident.span.at_least_rust_2018() && !extern_prelude_ambiguity()
2028 {
2029 help_msgs.push(format!("use `::{ident}` to refer to this {thing} unambiguously"))
2030 }
2031 match misc {
2032 AmbiguityErrorMisc::SuggestCrate => help_msgs
2033 .push(format!("use `crate::{ident}` to refer to this {thing} unambiguously")),
2034 AmbiguityErrorMisc::SuggestSelf => help_msgs
2035 .push(format!("use `self::{ident}` to refer to this {thing} unambiguously")),
2036 AmbiguityErrorMisc::FromPrelude | AmbiguityErrorMisc::None => {}
2037 }
2038
2039 (
2040 Spanned { node: note_msg, span: b.span },
2041 help_msgs
2042 .iter()
2043 .enumerate()
2044 .map(|(i, help_msg)| {
2045 let or = if i == 0 { "" } else { "or " };
2046 format!("{or}{help_msg}")
2047 })
2048 .collect::<Vec<_>>(),
2049 )
2050 };
2051 let (b1_note, b1_help_msgs) = could_refer_to(b1, misc1, "");
2052 let (b2_note, b2_help_msgs) = could_refer_to(b2, misc2, " also");
2053
2054 errors::Ambiguity {
2055 ident,
2056 kind: kind.descr(),
2057 b1_note,
2058 b1_help_msgs,
2059 b2_note,
2060 b2_help_msgs,
2061 }
2062 }
2063
2064 fn ctor_fields_span(&self, binding: NameBinding<'_>) -> Option<Span> {
2067 let NameBindingKind::Res(Res::Def(
2068 DefKind::Ctor(CtorOf::Struct, CtorKind::Fn),
2069 ctor_def_id,
2070 )) = binding.kind
2071 else {
2072 return None;
2073 };
2074
2075 let def_id = self.tcx.parent(ctor_def_id);
2076 self.field_idents(def_id)?.iter().map(|&f| f.span).reduce(Span::to) }
2078
2079 fn report_privacy_error(&mut self, privacy_error: &PrivacyError<'ra>) {
2080 let PrivacyError {
2081 ident,
2082 binding,
2083 outermost_res,
2084 parent_scope,
2085 single_nested,
2086 dedup_span,
2087 ref source,
2088 } = *privacy_error;
2089
2090 let res = binding.res();
2091 let ctor_fields_span = self.ctor_fields_span(binding);
2092 let plain_descr = res.descr().to_string();
2093 let nonimport_descr =
2094 if ctor_fields_span.is_some() { plain_descr + " constructor" } else { plain_descr };
2095 let import_descr = nonimport_descr.clone() + " import";
2096 let get_descr =
2097 |b: NameBinding<'_>| if b.is_import() { &import_descr } else { &nonimport_descr };
2098
2099 let ident_descr = get_descr(binding);
2101 let mut err =
2102 self.dcx().create_err(errors::IsPrivate { span: ident.span, ident_descr, ident });
2103
2104 self.mention_default_field_values(source, ident, &mut err);
2105
2106 let mut not_publicly_reexported = false;
2107 if let Some((this_res, outer_ident)) = outermost_res {
2108 let import_suggestions = self.lookup_import_candidates(
2109 outer_ident,
2110 this_res.ns().unwrap_or(Namespace::TypeNS),
2111 &parent_scope,
2112 &|res: Res| res == this_res,
2113 );
2114 let point_to_def = !show_candidates(
2115 self.tcx,
2116 &mut err,
2117 Some(dedup_span.until(outer_ident.span.shrink_to_hi())),
2118 &import_suggestions,
2119 Instead::Yes,
2120 FoundUse::Yes,
2121 DiagMode::Import { append: single_nested, unresolved_import: false },
2122 vec![],
2123 "",
2124 );
2125 if point_to_def && ident.span != outer_ident.span {
2127 not_publicly_reexported = true;
2128 let label = errors::OuterIdentIsNotPubliclyReexported {
2129 span: outer_ident.span,
2130 outer_ident_descr: this_res.descr(),
2131 outer_ident,
2132 };
2133 err.subdiagnostic(label);
2134 }
2135 }
2136
2137 let mut non_exhaustive = None;
2138 if let Some(def_id) = res.opt_def_id()
2142 && !def_id.is_local()
2143 && let Some(attr_span) = find_attr!(self.tcx.get_all_attrs(def_id), AttributeKind::NonExhaustive(span) => *span)
2144 {
2145 non_exhaustive = Some(attr_span);
2146 } else if let Some(span) = ctor_fields_span {
2147 let label = errors::ConstructorPrivateIfAnyFieldPrivate { span };
2148 err.subdiagnostic(label);
2149 if let Res::Def(_, d) = res
2150 && let Some(fields) = self.field_visibility_spans.get(&d)
2151 {
2152 let spans = fields.iter().map(|span| *span).collect();
2153 let sugg =
2154 errors::ConsiderMakingTheFieldPublic { spans, number_of_fields: fields.len() };
2155 err.subdiagnostic(sugg);
2156 }
2157 }
2158
2159 let mut sugg_paths: Vec<(Vec<Ident>, bool)> = vec![];
2160 if let Some(mut def_id) = res.opt_def_id() {
2161 let mut path = vec![def_id];
2163 while let Some(parent) = self.tcx.opt_parent(def_id) {
2164 def_id = parent;
2165 if !def_id.is_top_level_module() {
2166 path.push(def_id);
2167 } else {
2168 break;
2169 }
2170 }
2171 let path_names: Option<Vec<Ident>> = path
2173 .iter()
2174 .rev()
2175 .map(|def_id| {
2176 self.tcx.opt_item_name(*def_id).map(|name| {
2177 Ident::with_dummy_span(if def_id.is_top_level_module() {
2178 kw::Crate
2179 } else {
2180 name
2181 })
2182 })
2183 })
2184 .collect();
2185 if let Some(def_id) = path.get(0)
2186 && let Some(path) = path_names
2187 {
2188 if let Some(def_id) = def_id.as_local() {
2189 if self.effective_visibilities.is_directly_public(def_id) {
2190 sugg_paths.push((path, false));
2191 }
2192 } else if self.is_accessible_from(self.tcx.visibility(def_id), parent_scope.module)
2193 {
2194 sugg_paths.push((path, false));
2195 }
2196 }
2197 }
2198
2199 let first_binding = binding;
2201 let mut next_binding = Some(binding);
2202 let mut next_ident = ident;
2203 let mut path = vec![];
2204 while let Some(binding) = next_binding {
2205 let name = next_ident;
2206 next_binding = match binding.kind {
2207 _ if res == Res::Err => None,
2208 NameBindingKind::Import { binding, import, .. } => match import.kind {
2209 _ if binding.span.is_dummy() => None,
2210 ImportKind::Single { source, .. } => {
2211 next_ident = source;
2212 Some(binding)
2213 }
2214 ImportKind::Glob { .. }
2215 | ImportKind::MacroUse { .. }
2216 | ImportKind::MacroExport => Some(binding),
2217 ImportKind::ExternCrate { .. } => None,
2218 },
2219 _ => None,
2220 };
2221
2222 match binding.kind {
2223 NameBindingKind::Import { import, .. } => {
2224 for segment in import.module_path.iter().skip(1) {
2225 path.push(segment.ident);
2226 }
2227 sugg_paths.push((
2228 path.iter().cloned().chain(std::iter::once(ident)).collect::<Vec<_>>(),
2229 true, ));
2231 }
2232 NameBindingKind::Res(_) => {}
2233 }
2234 let first = binding == first_binding;
2235 let def_span = self.tcx.sess.source_map().guess_head_span(binding.span);
2236 let mut note_span = MultiSpan::from_span(def_span);
2237 if !first && binding.vis.is_public() {
2238 let desc = match binding.kind {
2239 NameBindingKind::Import { .. } => "re-export",
2240 _ => "directly",
2241 };
2242 note_span.push_span_label(def_span, format!("you could import this {desc}"));
2243 }
2244 if next_binding.is_none()
2247 && let Some(span) = non_exhaustive
2248 {
2249 note_span.push_span_label(
2250 span,
2251 "cannot be constructed because it is `#[non_exhaustive]`",
2252 );
2253 }
2254 let note = errors::NoteAndRefersToTheItemDefinedHere {
2255 span: note_span,
2256 binding_descr: get_descr(binding),
2257 binding_name: name,
2258 first,
2259 dots: next_binding.is_some(),
2260 };
2261 err.subdiagnostic(note);
2262 }
2263 sugg_paths.sort_by_key(|(p, reexport)| (p.len(), p[0].name == sym::core, *reexport));
2265 for (sugg, reexport) in sugg_paths {
2266 if not_publicly_reexported {
2267 break;
2268 }
2269 if sugg.len() <= 1 {
2270 continue;
2273 }
2274 let path = join_path_idents(sugg);
2275 let sugg = if reexport {
2276 errors::ImportIdent::ThroughReExport { span: dedup_span, ident, path }
2277 } else {
2278 errors::ImportIdent::Directly { span: dedup_span, ident, path }
2279 };
2280 err.subdiagnostic(sugg);
2281 break;
2282 }
2283
2284 err.emit();
2285 }
2286
2287 fn mention_default_field_values(
2307 &self,
2308 source: &Option<ast::Expr>,
2309 ident: Ident,
2310 err: &mut Diag<'_>,
2311 ) {
2312 let Some(expr) = source else { return };
2313 let ast::ExprKind::Struct(struct_expr) = &expr.kind else { return };
2314 let Some(segment) = struct_expr.path.segments.last() else { return };
2317 let Some(partial_res) = self.partial_res_map.get(&segment.id) else { return };
2318 let Some(Res::Def(_, def_id)) = partial_res.full_res() else {
2319 return;
2320 };
2321 let Some(default_fields) = self.field_defaults(def_id) else { return };
2322 if struct_expr.fields.is_empty() {
2323 return;
2324 }
2325 let last_span = struct_expr.fields.iter().last().unwrap().span;
2326 let mut iter = struct_expr.fields.iter().peekable();
2327 let mut prev: Option<Span> = None;
2328 while let Some(field) = iter.next() {
2329 if field.expr.span.overlaps(ident.span) {
2330 err.span_label(field.ident.span, "while setting this field");
2331 if default_fields.contains(&field.ident.name) {
2332 let sugg = if last_span == field.span {
2333 vec![(field.span, "..".to_string())]
2334 } else {
2335 vec![
2336 (
2337 match (prev, iter.peek()) {
2339 (_, Some(next)) => field.span.with_hi(next.span.lo()),
2340 (Some(prev), _) => field.span.with_lo(prev.hi()),
2341 (None, None) => field.span,
2342 },
2343 String::new(),
2344 ),
2345 (last_span.shrink_to_hi(), ", ..".to_string()),
2346 ]
2347 };
2348 err.multipart_suggestion_verbose(
2349 format!(
2350 "the type `{ident}` of field `{}` is private, but you can construct \
2351 the default value defined for it in `{}` using `..` in the struct \
2352 initializer expression",
2353 field.ident,
2354 self.tcx.item_name(def_id),
2355 ),
2356 sugg,
2357 Applicability::MachineApplicable,
2358 );
2359 break;
2360 }
2361 }
2362 prev = Some(field.span);
2363 }
2364 }
2365
2366 pub(crate) fn find_similarly_named_module_or_crate(
2367 &self,
2368 ident: Symbol,
2369 current_module: Module<'ra>,
2370 ) -> Option<Symbol> {
2371 let mut candidates = self
2372 .extern_prelude
2373 .keys()
2374 .map(|ident| ident.name)
2375 .chain(
2376 self.local_module_map
2377 .iter()
2378 .filter(|(_, module)| {
2379 current_module.is_ancestor_of(**module) && current_module != **module
2380 })
2381 .flat_map(|(_, module)| module.kind.name()),
2382 )
2383 .chain(
2384 self.extern_module_map
2385 .borrow()
2386 .iter()
2387 .filter(|(_, module)| {
2388 current_module.is_ancestor_of(**module) && current_module != **module
2389 })
2390 .flat_map(|(_, module)| module.kind.name()),
2391 )
2392 .filter(|c| !c.to_string().is_empty())
2393 .collect::<Vec<_>>();
2394 candidates.sort();
2395 candidates.dedup();
2396 find_best_match_for_name(&candidates, ident, None).filter(|sugg| *sugg != ident)
2397 }
2398
2399 pub(crate) fn report_path_resolution_error(
2400 &mut self,
2401 path: &[Segment],
2402 opt_ns: Option<Namespace>, parent_scope: &ParentScope<'ra>,
2404 ribs: Option<&PerNS<Vec<Rib<'ra>>>>,
2405 ignore_binding: Option<NameBinding<'ra>>,
2406 ignore_import: Option<Import<'ra>>,
2407 module: Option<ModuleOrUniformRoot<'ra>>,
2408 failed_segment_idx: usize,
2409 ident: Ident,
2410 diag_metadata: Option<&DiagMetadata<'_>>,
2411 ) -> (String, Option<Suggestion>) {
2412 let is_last = failed_segment_idx == path.len() - 1;
2413 let ns = if is_last { opt_ns.unwrap_or(TypeNS) } else { TypeNS };
2414 let module_res = match module {
2415 Some(ModuleOrUniformRoot::Module(module)) => module.res(),
2416 _ => None,
2417 };
2418 if module_res == self.graph_root.res() {
2419 let is_mod = |res| matches!(res, Res::Def(DefKind::Mod, _));
2420 let mut candidates = self.lookup_import_candidates(ident, TypeNS, parent_scope, is_mod);
2421 candidates
2422 .sort_by_cached_key(|c| (c.path.segments.len(), pprust::path_to_string(&c.path)));
2423 if let Some(candidate) = candidates.get(0) {
2424 let path = {
2425 let len = candidate.path.segments.len();
2427 let start_index = (0..=failed_segment_idx.min(len - 1))
2428 .find(|&i| path[i].ident.name != candidate.path.segments[i].ident.name)
2429 .unwrap_or_default();
2430 let segments =
2431 (start_index..len).map(|s| candidate.path.segments[s].clone()).collect();
2432 Path { segments, span: Span::default(), tokens: None }
2433 };
2434 (
2435 String::from("unresolved import"),
2436 Some((
2437 vec![(ident.span, pprust::path_to_string(&path))],
2438 String::from("a similar path exists"),
2439 Applicability::MaybeIncorrect,
2440 )),
2441 )
2442 } else if ident.name == sym::core {
2443 (
2444 format!("you might be missing crate `{ident}`"),
2445 Some((
2446 vec![(ident.span, "std".to_string())],
2447 "try using `std` instead of `core`".to_string(),
2448 Applicability::MaybeIncorrect,
2449 )),
2450 )
2451 } else if ident.name == kw::Underscore {
2452 (format!("`_` is not a valid crate or module name"), None)
2453 } else if self.tcx.sess.is_rust_2015() {
2454 (
2455 format!("use of unresolved module or unlinked crate `{ident}`"),
2456 Some((
2457 vec![(
2458 self.current_crate_outer_attr_insert_span,
2459 format!("extern crate {ident};\n"),
2460 )],
2461 if was_invoked_from_cargo() {
2462 format!(
2463 "if you wanted to use a crate named `{ident}`, use `cargo add {ident}` \
2464 to add it to your `Cargo.toml` and import it in your code",
2465 )
2466 } else {
2467 format!(
2468 "you might be missing a crate named `{ident}`, add it to your \
2469 project and import it in your code",
2470 )
2471 },
2472 Applicability::MaybeIncorrect,
2473 )),
2474 )
2475 } else {
2476 (format!("could not find `{ident}` in the crate root"), None)
2477 }
2478 } else if failed_segment_idx > 0 {
2479 let parent = path[failed_segment_idx - 1].ident.name;
2480 let parent = match parent {
2481 kw::PathRoot if self.tcx.sess.edition() > Edition::Edition2015 => {
2484 "the list of imported crates".to_owned()
2485 }
2486 kw::PathRoot | kw::Crate => "the crate root".to_owned(),
2487 _ => format!("`{parent}`"),
2488 };
2489
2490 let mut msg = format!("could not find `{ident}` in {parent}");
2491 if ns == TypeNS || ns == ValueNS {
2492 let ns_to_try = if ns == TypeNS { ValueNS } else { TypeNS };
2493 let binding = if let Some(module) = module {
2494 self.cm()
2495 .resolve_ident_in_module(
2496 module,
2497 ident,
2498 ns_to_try,
2499 parent_scope,
2500 None,
2501 ignore_binding,
2502 ignore_import,
2503 )
2504 .ok()
2505 } else if let Some(ribs) = ribs
2506 && let Some(TypeNS | ValueNS) = opt_ns
2507 {
2508 assert!(ignore_import.is_none());
2509 match self.resolve_ident_in_lexical_scope(
2510 ident,
2511 ns_to_try,
2512 parent_scope,
2513 None,
2514 &ribs[ns_to_try],
2515 ignore_binding,
2516 diag_metadata,
2517 ) {
2518 Some(LexicalScopeBinding::Item(binding)) => Some(binding),
2520 _ => None,
2521 }
2522 } else {
2523 self.cm()
2524 .resolve_ident_in_scope_set(
2525 ident,
2526 ScopeSet::All(ns_to_try),
2527 parent_scope,
2528 None,
2529 false,
2530 ignore_binding,
2531 ignore_import,
2532 )
2533 .ok()
2534 };
2535 if let Some(binding) = binding {
2536 msg = format!(
2537 "expected {}, found {} `{ident}` in {parent}",
2538 ns.descr(),
2539 binding.res().descr(),
2540 );
2541 };
2542 }
2543 (msg, None)
2544 } else if ident.name == kw::SelfUpper {
2545 if opt_ns.is_none() {
2549 ("`Self` cannot be used in imports".to_string(), None)
2550 } else {
2551 (
2552 "`Self` is only available in impls, traits, and type definitions".to_string(),
2553 None,
2554 )
2555 }
2556 } else if ident.name.as_str().chars().next().is_some_and(|c| c.is_ascii_uppercase()) {
2557 let binding = if let Some(ribs) = ribs {
2559 assert!(ignore_import.is_none());
2560 self.resolve_ident_in_lexical_scope(
2561 ident,
2562 ValueNS,
2563 parent_scope,
2564 None,
2565 &ribs[ValueNS],
2566 ignore_binding,
2567 diag_metadata,
2568 )
2569 } else {
2570 None
2571 };
2572 let match_span = match binding {
2573 Some(LexicalScopeBinding::Res(Res::Local(id))) => {
2582 Some(*self.pat_span_map.get(&id).unwrap())
2583 }
2584 Some(LexicalScopeBinding::Item(name_binding)) => Some(name_binding.span),
2596 _ => None,
2597 };
2598 let suggestion = match_span.map(|span| {
2599 (
2600 vec![(span, String::from(""))],
2601 format!("`{ident}` is defined here, but is not a type"),
2602 Applicability::MaybeIncorrect,
2603 )
2604 });
2605
2606 (format!("use of undeclared type `{ident}`"), suggestion)
2607 } else {
2608 let mut suggestion = None;
2609 if ident.name == sym::alloc {
2610 suggestion = Some((
2611 vec![],
2612 String::from("add `extern crate alloc` to use the `alloc` crate"),
2613 Applicability::MaybeIncorrect,
2614 ))
2615 }
2616
2617 suggestion = suggestion.or_else(|| {
2618 self.find_similarly_named_module_or_crate(ident.name, parent_scope.module).map(
2619 |sugg| {
2620 (
2621 vec![(ident.span, sugg.to_string())],
2622 String::from("there is a crate or module with a similar name"),
2623 Applicability::MaybeIncorrect,
2624 )
2625 },
2626 )
2627 });
2628 if let Ok(binding) = self.cm().resolve_ident_in_scope_set(
2629 ident,
2630 ScopeSet::All(ValueNS),
2631 parent_scope,
2632 None,
2633 false,
2634 ignore_binding,
2635 ignore_import,
2636 ) {
2637 let descr = binding.res().descr();
2638 (format!("{descr} `{ident}` is not a crate or module"), suggestion)
2639 } else {
2640 let suggestion = if suggestion.is_some() {
2641 suggestion
2642 } else if let Some(m) = self.undeclared_module_exists(ident) {
2643 self.undeclared_module_suggest_declare(ident, m)
2644 } else if was_invoked_from_cargo() {
2645 Some((
2646 vec![],
2647 format!(
2648 "if you wanted to use a crate named `{ident}`, use `cargo add {ident}` \
2649 to add it to your `Cargo.toml`",
2650 ),
2651 Applicability::MaybeIncorrect,
2652 ))
2653 } else {
2654 Some((
2655 vec![],
2656 format!("you might be missing a crate named `{ident}`",),
2657 Applicability::MaybeIncorrect,
2658 ))
2659 };
2660 (format!("use of unresolved module or unlinked crate `{ident}`"), suggestion)
2661 }
2662 }
2663 }
2664
2665 fn undeclared_module_suggest_declare(
2666 &self,
2667 ident: Ident,
2668 path: std::path::PathBuf,
2669 ) -> Option<(Vec<(Span, String)>, String, Applicability)> {
2670 Some((
2671 vec![(self.current_crate_outer_attr_insert_span, format!("mod {ident};\n"))],
2672 format!(
2673 "to make use of source file {}, use `mod {ident}` \
2674 in this file to declare the module",
2675 path.display()
2676 ),
2677 Applicability::MaybeIncorrect,
2678 ))
2679 }
2680
2681 fn undeclared_module_exists(&self, ident: Ident) -> Option<std::path::PathBuf> {
2682 let map = self.tcx.sess.source_map();
2683
2684 let src = map.span_to_filename(ident.span).into_local_path()?;
2685 let i = ident.as_str();
2686 let dir = src.parent()?;
2688 let src = src.file_stem()?.to_str()?;
2689 for file in [
2690 dir.join(i).with_extension("rs"),
2692 dir.join(i).join("mod.rs"),
2694 ] {
2695 if file.exists() {
2696 return Some(file);
2697 }
2698 }
2699 if !matches!(src, "main" | "lib" | "mod") {
2700 for file in [
2701 dir.join(src).join(i).with_extension("rs"),
2703 dir.join(src).join(i).join("mod.rs"),
2705 ] {
2706 if file.exists() {
2707 return Some(file);
2708 }
2709 }
2710 }
2711 None
2712 }
2713
2714 #[instrument(level = "debug", skip(self, parent_scope))]
2716 pub(crate) fn make_path_suggestion(
2717 &mut self,
2718 mut path: Vec<Segment>,
2719 parent_scope: &ParentScope<'ra>,
2720 ) -> Option<(Vec<Segment>, Option<String>)> {
2721 match path[..] {
2722 [first, second, ..]
2725 if first.ident.name == kw::PathRoot && !second.ident.is_path_segment_keyword() => {}
2726 [first, ..]
2728 if first.ident.span.at_least_rust_2018()
2729 && !first.ident.is_path_segment_keyword() =>
2730 {
2731 path.insert(0, Segment::from_ident(Ident::dummy()));
2733 }
2734 _ => return None,
2735 }
2736
2737 self.make_missing_self_suggestion(path.clone(), parent_scope)
2738 .or_else(|| self.make_missing_crate_suggestion(path.clone(), parent_scope))
2739 .or_else(|| self.make_missing_super_suggestion(path.clone(), parent_scope))
2740 .or_else(|| self.make_external_crate_suggestion(path, parent_scope))
2741 }
2742
2743 #[instrument(level = "debug", skip(self, parent_scope))]
2751 fn make_missing_self_suggestion(
2752 &mut self,
2753 mut path: Vec<Segment>,
2754 parent_scope: &ParentScope<'ra>,
2755 ) -> Option<(Vec<Segment>, Option<String>)> {
2756 path[0].ident.name = kw::SelfLower;
2758 let result = self.cm().maybe_resolve_path(&path, None, parent_scope, None);
2759 debug!(?path, ?result);
2760 if let PathResult::Module(..) = result { Some((path, None)) } else { None }
2761 }
2762
2763 #[instrument(level = "debug", skip(self, parent_scope))]
2771 fn make_missing_crate_suggestion(
2772 &mut self,
2773 mut path: Vec<Segment>,
2774 parent_scope: &ParentScope<'ra>,
2775 ) -> Option<(Vec<Segment>, Option<String>)> {
2776 path[0].ident.name = kw::Crate;
2778 let result = self.cm().maybe_resolve_path(&path, None, parent_scope, None);
2779 debug!(?path, ?result);
2780 if let PathResult::Module(..) = result {
2781 Some((
2782 path,
2783 Some(
2784 "`use` statements changed in Rust 2018; read more at \
2785 <https://doc.rust-lang.org/edition-guide/rust-2018/module-system/path-\
2786 clarity.html>"
2787 .to_string(),
2788 ),
2789 ))
2790 } else {
2791 None
2792 }
2793 }
2794
2795 #[instrument(level = "debug", skip(self, parent_scope))]
2803 fn make_missing_super_suggestion(
2804 &mut self,
2805 mut path: Vec<Segment>,
2806 parent_scope: &ParentScope<'ra>,
2807 ) -> Option<(Vec<Segment>, Option<String>)> {
2808 path[0].ident.name = kw::Super;
2810 let result = self.cm().maybe_resolve_path(&path, None, parent_scope, None);
2811 debug!(?path, ?result);
2812 if let PathResult::Module(..) = result { Some((path, None)) } else { None }
2813 }
2814
2815 #[instrument(level = "debug", skip(self, parent_scope))]
2826 fn make_external_crate_suggestion(
2827 &mut self,
2828 mut path: Vec<Segment>,
2829 parent_scope: &ParentScope<'ra>,
2830 ) -> Option<(Vec<Segment>, Option<String>)> {
2831 if path[1].ident.span.is_rust_2015() {
2832 return None;
2833 }
2834
2835 let mut extern_crate_names =
2839 self.extern_prelude.keys().map(|ident| ident.name).collect::<Vec<_>>();
2840 extern_crate_names.sort_by(|a, b| b.as_str().cmp(a.as_str()));
2841
2842 for name in extern_crate_names.into_iter() {
2843 path[0].ident.name = name;
2845 let result = self.cm().maybe_resolve_path(&path, None, parent_scope, None);
2846 debug!(?path, ?name, ?result);
2847 if let PathResult::Module(..) = result {
2848 return Some((path, None));
2849 }
2850 }
2851
2852 None
2853 }
2854
2855 pub(crate) fn check_for_module_export_macro(
2868 &mut self,
2869 import: Import<'ra>,
2870 module: ModuleOrUniformRoot<'ra>,
2871 ident: Ident,
2872 ) -> Option<(Option<Suggestion>, Option<String>)> {
2873 let ModuleOrUniformRoot::Module(mut crate_module) = module else {
2874 return None;
2875 };
2876
2877 while let Some(parent) = crate_module.parent {
2878 crate_module = parent;
2879 }
2880
2881 if module == ModuleOrUniformRoot::Module(crate_module) {
2882 return None;
2884 }
2885
2886 let binding_key = BindingKey::new(ident, MacroNS);
2887 let binding = self.resolution(crate_module, binding_key)?.binding()?;
2888 let Res::Def(DefKind::Macro(kinds), _) = binding.res() else {
2889 return None;
2890 };
2891 if !kinds.contains(MacroKinds::BANG) {
2892 return None;
2893 }
2894 let module_name = crate_module.kind.name().unwrap_or(kw::Crate);
2895 let import_snippet = match import.kind {
2896 ImportKind::Single { source, target, .. } if source != target => {
2897 format!("{source} as {target}")
2898 }
2899 _ => format!("{ident}"),
2900 };
2901
2902 let mut corrections: Vec<(Span, String)> = Vec::new();
2903 if !import.is_nested() {
2904 corrections.push((import.span, format!("{module_name}::{import_snippet}")));
2907 } else {
2908 let (found_closing_brace, binding_span) = find_span_of_binding_until_next_binding(
2912 self.tcx.sess,
2913 import.span,
2914 import.use_span,
2915 );
2916 debug!(found_closing_brace, ?binding_span);
2917
2918 let mut removal_span = binding_span;
2919
2920 if found_closing_brace
2928 && let Some(previous_span) =
2929 extend_span_to_previous_binding(self.tcx.sess, binding_span)
2930 {
2931 debug!(?previous_span);
2932 removal_span = removal_span.with_lo(previous_span.lo());
2933 }
2934 debug!(?removal_span);
2935
2936 corrections.push((removal_span, "".to_string()));
2938
2939 let (has_nested, after_crate_name) =
2946 find_span_immediately_after_crate_name(self.tcx.sess, import.use_span);
2947 debug!(has_nested, ?after_crate_name);
2948
2949 let source_map = self.tcx.sess.source_map();
2950
2951 let is_definitely_crate = import
2953 .module_path
2954 .first()
2955 .is_some_and(|f| f.ident.name != kw::SelfLower && f.ident.name != kw::Super);
2956
2957 let start_point = source_map.start_point(after_crate_name);
2959 if is_definitely_crate
2960 && let Ok(start_snippet) = source_map.span_to_snippet(start_point)
2961 {
2962 corrections.push((
2963 start_point,
2964 if has_nested {
2965 format!("{start_snippet}{import_snippet}, ")
2967 } else {
2968 format!("{{{import_snippet}, {start_snippet}")
2971 },
2972 ));
2973
2974 if !has_nested {
2976 corrections.push((source_map.end_point(after_crate_name), "};".to_string()));
2977 }
2978 } else {
2979 corrections.push((
2981 import.use_span.shrink_to_lo(),
2982 format!("use {module_name}::{import_snippet};\n"),
2983 ));
2984 }
2985 }
2986
2987 let suggestion = Some((
2988 corrections,
2989 String::from("a macro with this name exists at the root of the crate"),
2990 Applicability::MaybeIncorrect,
2991 ));
2992 Some((
2993 suggestion,
2994 Some(
2995 "this could be because a macro annotated with `#[macro_export]` will be exported \
2996 at the root of the crate instead of the module where it is defined"
2997 .to_string(),
2998 ),
2999 ))
3000 }
3001
3002 pub(crate) fn find_cfg_stripped(&self, err: &mut Diag<'_>, segment: &Symbol, module: DefId) {
3004 let local_items;
3005 let symbols = if module.is_local() {
3006 local_items = self
3007 .stripped_cfg_items
3008 .iter()
3009 .filter_map(|item| {
3010 let parent_module = self.opt_local_def_id(item.parent_module)?.to_def_id();
3011 Some(StrippedCfgItem {
3012 parent_module,
3013 ident: item.ident,
3014 cfg: item.cfg.clone(),
3015 })
3016 })
3017 .collect::<Vec<_>>();
3018 local_items.as_slice()
3019 } else {
3020 self.tcx.stripped_cfg_items(module.krate)
3021 };
3022
3023 for &StrippedCfgItem { parent_module, ident, ref cfg } in symbols {
3024 if ident.name != *segment {
3025 continue;
3026 }
3027
3028 fn comes_from_same_module_for_glob(
3029 r: &Resolver<'_, '_>,
3030 parent_module: DefId,
3031 module: DefId,
3032 visited: &mut FxHashMap<DefId, bool>,
3033 ) -> bool {
3034 if let Some(&cached) = visited.get(&parent_module) {
3035 return cached;
3039 }
3040 visited.insert(parent_module, false);
3041 let m = r.expect_module(parent_module);
3042 let mut res = false;
3043 for importer in m.glob_importers.borrow().iter() {
3044 if let Some(next_parent_module) = importer.parent_scope.module.opt_def_id() {
3045 if next_parent_module == module
3046 || comes_from_same_module_for_glob(
3047 r,
3048 next_parent_module,
3049 module,
3050 visited,
3051 )
3052 {
3053 res = true;
3054 break;
3055 }
3056 }
3057 }
3058 visited.insert(parent_module, res);
3059 res
3060 }
3061
3062 let comes_from_same_module = parent_module == module
3063 || comes_from_same_module_for_glob(
3064 self,
3065 parent_module,
3066 module,
3067 &mut Default::default(),
3068 );
3069 if !comes_from_same_module {
3070 continue;
3071 }
3072
3073 let item_was = if let CfgEntry::NameValue { value: Some((feature, _)), .. } = cfg.0 {
3074 errors::ItemWas::BehindFeature { feature, span: cfg.1 }
3075 } else {
3076 errors::ItemWas::CfgOut { span: cfg.1 }
3077 };
3078 let note = errors::FoundItemConfigureOut { span: ident.span, item_was };
3079 err.subdiagnostic(note);
3080 }
3081 }
3082}
3083
3084fn find_span_of_binding_until_next_binding(
3098 sess: &Session,
3099 binding_span: Span,
3100 use_span: Span,
3101) -> (bool, Span) {
3102 let source_map = sess.source_map();
3103
3104 let binding_until_end = binding_span.with_hi(use_span.hi());
3107
3108 let after_binding_until_end = binding_until_end.with_lo(binding_span.hi());
3111
3112 let mut found_closing_brace = false;
3119 let after_binding_until_next_binding =
3120 source_map.span_take_while(after_binding_until_end, |&ch| {
3121 if ch == '}' {
3122 found_closing_brace = true;
3123 }
3124 ch == ' ' || ch == ','
3125 });
3126
3127 let span = binding_span.with_hi(after_binding_until_next_binding.hi());
3132
3133 (found_closing_brace, span)
3134}
3135
3136fn extend_span_to_previous_binding(sess: &Session, binding_span: Span) -> Option<Span> {
3149 let source_map = sess.source_map();
3150
3151 let prev_source = source_map.span_to_prev_source(binding_span).ok()?;
3155
3156 let prev_comma = prev_source.rsplit(',').collect::<Vec<_>>();
3157 let prev_starting_brace = prev_source.rsplit('{').collect::<Vec<_>>();
3158 if prev_comma.len() <= 1 || prev_starting_brace.len() <= 1 {
3159 return None;
3160 }
3161
3162 let prev_comma = prev_comma.first().unwrap();
3163 let prev_starting_brace = prev_starting_brace.first().unwrap();
3164
3165 if prev_comma.len() > prev_starting_brace.len() {
3169 return None;
3170 }
3171
3172 Some(binding_span.with_lo(BytePos(
3173 binding_span.lo().0 - (prev_comma.as_bytes().len() as u32) - 1,
3176 )))
3177}
3178
3179#[instrument(level = "debug", skip(sess))]
3193fn find_span_immediately_after_crate_name(sess: &Session, use_span: Span) -> (bool, Span) {
3194 let source_map = sess.source_map();
3195
3196 let mut num_colons = 0;
3198 let until_second_colon = source_map.span_take_while(use_span, |c| {
3200 if *c == ':' {
3201 num_colons += 1;
3202 }
3203 !matches!(c, ':' if num_colons == 2)
3204 });
3205 let from_second_colon = use_span.with_lo(until_second_colon.hi() + BytePos(1));
3207
3208 let mut found_a_non_whitespace_character = false;
3209 let after_second_colon = source_map.span_take_while(from_second_colon, |c| {
3211 if found_a_non_whitespace_character {
3212 return false;
3213 }
3214 if !c.is_whitespace() {
3215 found_a_non_whitespace_character = true;
3216 }
3217 true
3218 });
3219
3220 let next_left_bracket = source_map.span_through_char(from_second_colon, '{');
3222
3223 (next_left_bracket == after_second_colon, from_second_colon)
3224}
3225
3226enum Instead {
3229 Yes,
3230 No,
3231}
3232
3233enum FoundUse {
3235 Yes,
3236 No,
3237}
3238
3239pub(crate) enum DiagMode {
3241 Normal,
3242 Pattern,
3244 Import {
3246 unresolved_import: bool,
3248 append: bool,
3251 },
3252}
3253
3254pub(crate) fn import_candidates(
3255 tcx: TyCtxt<'_>,
3256 err: &mut Diag<'_>,
3257 use_placement_span: Option<Span>,
3259 candidates: &[ImportSuggestion],
3260 mode: DiagMode,
3261 append: &str,
3262) {
3263 show_candidates(
3264 tcx,
3265 err,
3266 use_placement_span,
3267 candidates,
3268 Instead::Yes,
3269 FoundUse::Yes,
3270 mode,
3271 vec![],
3272 append,
3273 );
3274}
3275
3276type PathString<'a> = (String, &'a str, Option<Span>, &'a Option<String>, bool);
3277
3278fn show_candidates(
3283 tcx: TyCtxt<'_>,
3284 err: &mut Diag<'_>,
3285 use_placement_span: Option<Span>,
3287 candidates: &[ImportSuggestion],
3288 instead: Instead,
3289 found_use: FoundUse,
3290 mode: DiagMode,
3291 path: Vec<Segment>,
3292 append: &str,
3293) -> bool {
3294 if candidates.is_empty() {
3295 return false;
3296 }
3297
3298 let mut showed = false;
3299 let mut accessible_path_strings: Vec<PathString<'_>> = Vec::new();
3300 let mut inaccessible_path_strings: Vec<PathString<'_>> = Vec::new();
3301
3302 candidates.iter().for_each(|c| {
3303 if c.accessible {
3304 if c.doc_visible {
3306 accessible_path_strings.push((
3307 pprust::path_to_string(&c.path),
3308 c.descr,
3309 c.did.and_then(|did| Some(tcx.source_span(did.as_local()?))),
3310 &c.note,
3311 c.via_import,
3312 ))
3313 }
3314 } else {
3315 inaccessible_path_strings.push((
3316 pprust::path_to_string(&c.path),
3317 c.descr,
3318 c.did.and_then(|did| Some(tcx.source_span(did.as_local()?))),
3319 &c.note,
3320 c.via_import,
3321 ))
3322 }
3323 });
3324
3325 for path_strings in [&mut accessible_path_strings, &mut inaccessible_path_strings] {
3328 path_strings.sort_by(|a, b| a.0.cmp(&b.0));
3329 path_strings.dedup_by(|a, b| a.0 == b.0);
3330 let core_path_strings =
3331 path_strings.extract_if(.., |p| p.0.starts_with("core::")).collect::<Vec<_>>();
3332 let std_path_strings =
3333 path_strings.extract_if(.., |p| p.0.starts_with("std::")).collect::<Vec<_>>();
3334 let foreign_crate_path_strings =
3335 path_strings.extract_if(.., |p| !p.0.starts_with("crate::")).collect::<Vec<_>>();
3336
3337 if std_path_strings.len() == core_path_strings.len() {
3340 path_strings.extend(std_path_strings);
3342 } else {
3343 path_strings.extend(std_path_strings);
3344 path_strings.extend(core_path_strings);
3345 }
3346 path_strings.extend(foreign_crate_path_strings);
3348 }
3349
3350 if !accessible_path_strings.is_empty() {
3351 let (determiner, kind, s, name, through) =
3352 if let [(name, descr, _, _, via_import)] = &accessible_path_strings[..] {
3353 (
3354 "this",
3355 *descr,
3356 "",
3357 format!(" `{name}`"),
3358 if *via_import { " through its public re-export" } else { "" },
3359 )
3360 } else {
3361 let kinds = accessible_path_strings
3364 .iter()
3365 .map(|(_, descr, _, _, _)| *descr)
3366 .collect::<UnordSet<&str>>();
3367 let kind = if let Some(kind) = kinds.get_only() { kind } else { "item" };
3368 let s = if kind.ends_with('s') { "es" } else { "s" };
3369
3370 ("one of these", kind, s, String::new(), "")
3371 };
3372
3373 let instead = if let Instead::Yes = instead { " instead" } else { "" };
3374 let mut msg = if let DiagMode::Pattern = mode {
3375 format!(
3376 "if you meant to match on {kind}{s}{instead}{name}, use the full path in the \
3377 pattern",
3378 )
3379 } else {
3380 format!("consider importing {determiner} {kind}{s}{through}{instead}")
3381 };
3382
3383 for note in accessible_path_strings.iter().flat_map(|cand| cand.3.as_ref()) {
3384 err.note(note.clone());
3385 }
3386
3387 let append_candidates = |msg: &mut String, accessible_path_strings: Vec<PathString<'_>>| {
3388 msg.push(':');
3389
3390 for candidate in accessible_path_strings {
3391 msg.push('\n');
3392 msg.push_str(&candidate.0);
3393 }
3394 };
3395
3396 if let Some(span) = use_placement_span {
3397 let (add_use, trailing) = match mode {
3398 DiagMode::Pattern => {
3399 err.span_suggestions(
3400 span,
3401 msg,
3402 accessible_path_strings.into_iter().map(|a| a.0),
3403 Applicability::MaybeIncorrect,
3404 );
3405 return true;
3406 }
3407 DiagMode::Import { .. } => ("", ""),
3408 DiagMode::Normal => ("use ", ";\n"),
3409 };
3410 for candidate in &mut accessible_path_strings {
3411 let additional_newline = if let FoundUse::No = found_use
3414 && let DiagMode::Normal = mode
3415 {
3416 "\n"
3417 } else {
3418 ""
3419 };
3420 candidate.0 =
3421 format!("{add_use}{}{append}{trailing}{additional_newline}", candidate.0);
3422 }
3423
3424 match mode {
3425 DiagMode::Import { append: true, .. } => {
3426 append_candidates(&mut msg, accessible_path_strings);
3427 err.span_help(span, msg);
3428 }
3429 _ => {
3430 err.span_suggestions_with_style(
3431 span,
3432 msg,
3433 accessible_path_strings.into_iter().map(|a| a.0),
3434 Applicability::MaybeIncorrect,
3435 SuggestionStyle::ShowAlways,
3436 );
3437 }
3438 }
3439
3440 if let [first, .., last] = &path[..] {
3441 let sp = first.ident.span.until(last.ident.span);
3442 if sp.can_be_used_for_suggestions() && !sp.is_empty() {
3445 err.span_suggestion_verbose(
3446 sp,
3447 format!("if you import `{}`, refer to it directly", last.ident),
3448 "",
3449 Applicability::Unspecified,
3450 );
3451 }
3452 }
3453 } else {
3454 append_candidates(&mut msg, accessible_path_strings);
3455 err.help(msg);
3456 }
3457 showed = true;
3458 }
3459 if !inaccessible_path_strings.is_empty()
3460 && (!matches!(mode, DiagMode::Import { unresolved_import: false, .. }))
3461 {
3462 let prefix =
3463 if let DiagMode::Pattern = mode { "you might have meant to match on " } else { "" };
3464 if let [(name, descr, source_span, note, _)] = &inaccessible_path_strings[..] {
3465 let msg = format!(
3466 "{prefix}{descr} `{name}`{} exists but is inaccessible",
3467 if let DiagMode::Pattern = mode { ", which" } else { "" }
3468 );
3469
3470 if let Some(source_span) = source_span {
3471 let span = tcx.sess.source_map().guess_head_span(*source_span);
3472 let mut multi_span = MultiSpan::from_span(span);
3473 multi_span.push_span_label(span, "not accessible");
3474 err.span_note(multi_span, msg);
3475 } else {
3476 err.note(msg);
3477 }
3478 if let Some(note) = (*note).as_deref() {
3479 err.note(note.to_string());
3480 }
3481 } else {
3482 let descr = inaccessible_path_strings
3483 .iter()
3484 .map(|&(_, descr, _, _, _)| descr)
3485 .all_equal_value()
3486 .unwrap_or("item");
3487 let plural_descr =
3488 if descr.ends_with('s') { format!("{descr}es") } else { format!("{descr}s") };
3489
3490 let mut msg = format!("{prefix}these {plural_descr} exist but are inaccessible");
3491 let mut has_colon = false;
3492
3493 let mut spans = Vec::new();
3494 for (name, _, source_span, _, _) in &inaccessible_path_strings {
3495 if let Some(source_span) = source_span {
3496 let span = tcx.sess.source_map().guess_head_span(*source_span);
3497 spans.push((name, span));
3498 } else {
3499 if !has_colon {
3500 msg.push(':');
3501 has_colon = true;
3502 }
3503 msg.push('\n');
3504 msg.push_str(name);
3505 }
3506 }
3507
3508 let mut multi_span = MultiSpan::from_spans(spans.iter().map(|(_, sp)| *sp).collect());
3509 for (name, span) in spans {
3510 multi_span.push_span_label(span, format!("`{name}`: not accessible"));
3511 }
3512
3513 for note in inaccessible_path_strings.iter().flat_map(|cand| cand.3.as_ref()) {
3514 err.note(note.clone());
3515 }
3516
3517 err.span_note(multi_span, msg);
3518 }
3519 showed = true;
3520 }
3521 showed
3522}
3523
3524#[derive(Debug)]
3525struct UsePlacementFinder {
3526 target_module: NodeId,
3527 first_legal_span: Option<Span>,
3528 first_use_span: Option<Span>,
3529}
3530
3531impl UsePlacementFinder {
3532 fn check(krate: &Crate, target_module: NodeId) -> (Option<Span>, FoundUse) {
3533 let mut finder =
3534 UsePlacementFinder { target_module, first_legal_span: None, first_use_span: None };
3535 finder.visit_crate(krate);
3536 if let Some(use_span) = finder.first_use_span {
3537 (Some(use_span), FoundUse::Yes)
3538 } else {
3539 (finder.first_legal_span, FoundUse::No)
3540 }
3541 }
3542}
3543
3544impl<'tcx> Visitor<'tcx> for UsePlacementFinder {
3545 fn visit_crate(&mut self, c: &Crate) {
3546 if self.target_module == CRATE_NODE_ID {
3547 let inject = c.spans.inject_use_span;
3548 if is_span_suitable_for_use_injection(inject) {
3549 self.first_legal_span = Some(inject);
3550 }
3551 self.first_use_span = search_for_any_use_in_items(&c.items);
3552 } else {
3553 visit::walk_crate(self, c);
3554 }
3555 }
3556
3557 fn visit_item(&mut self, item: &'tcx ast::Item) {
3558 if self.target_module == item.id {
3559 if let ItemKind::Mod(_, _, ModKind::Loaded(items, _inline, mod_spans)) = &item.kind {
3560 let inject = mod_spans.inject_use_span;
3561 if is_span_suitable_for_use_injection(inject) {
3562 self.first_legal_span = Some(inject);
3563 }
3564 self.first_use_span = search_for_any_use_in_items(items);
3565 }
3566 } else {
3567 visit::walk_item(self, item);
3568 }
3569 }
3570}
3571
3572#[derive(Default)]
3573struct BindingVisitor {
3574 identifiers: Vec<Symbol>,
3575 spans: FxHashMap<Symbol, Vec<Span>>,
3576}
3577
3578impl<'tcx> Visitor<'tcx> for BindingVisitor {
3579 fn visit_pat(&mut self, pat: &ast::Pat) {
3580 if let ast::PatKind::Ident(_, ident, _) = pat.kind {
3581 self.identifiers.push(ident.name);
3582 self.spans.entry(ident.name).or_default().push(ident.span);
3583 }
3584 visit::walk_pat(self, pat);
3585 }
3586}
3587
3588fn search_for_any_use_in_items(items: &[Box<ast::Item>]) -> Option<Span> {
3589 for item in items {
3590 if let ItemKind::Use(..) = item.kind
3591 && is_span_suitable_for_use_injection(item.span)
3592 {
3593 let mut lo = item.span.lo();
3594 for attr in &item.attrs {
3595 if attr.span.eq_ctxt(item.span) {
3596 lo = std::cmp::min(lo, attr.span.lo());
3597 }
3598 }
3599 return Some(Span::new(lo, lo, item.span.ctxt(), item.span.parent()));
3600 }
3601 }
3602 None
3603}
3604
3605fn is_span_suitable_for_use_injection(s: Span) -> bool {
3606 !s.from_expansion()
3609}