1use rustc_ast::expand::StrippedCfgItem;
2use rustc_ast::ptr::P;
3use rustc_ast::visit::{self, Visitor};
4use rustc_ast::{
5 self as ast, CRATE_NODE_ID, Crate, ItemKind, MetaItemInner, MetaItemKind, ModKind, NodeId, Path,
6};
7use rustc_ast_pretty::pprust;
8use rustc_attr_data_structures::{self as attr, Stability};
9use rustc_data_structures::fx::{FxHashMap, FxHashSet};
10use rustc_data_structures::unord::{UnordMap, UnordSet};
11use rustc_errors::codes::*;
12use rustc_errors::{
13 Applicability, Diag, DiagCtxtHandle, ErrorGuaranteed, MultiSpan, SuggestionStyle,
14 report_ambiguity_error, struct_span_code_err,
15};
16use rustc_feature::BUILTIN_ATTRIBUTES;
17use rustc_hir::PrimTy;
18use rustc_hir::def::Namespace::{self, *};
19use rustc_hir::def::{self, CtorKind, CtorOf, DefKind, NonMacroAttrKind, PerNS};
20use rustc_hir::def_id::{CRATE_DEF_ID, DefId};
21use rustc_middle::bug;
22use rustc_middle::ty::TyCtxt;
23use rustc_session::Session;
24use rustc_session::lint::builtin::{
25 ABSOLUTE_PATHS_NOT_STARTING_WITH_CRATE, AMBIGUOUS_GLOB_IMPORTS,
26 MACRO_EXPANDED_MACRO_EXPORTS_ACCESSED_BY_ABSOLUTE_PATHS,
27};
28use rustc_session::lint::{AmbiguityErrorDiag, BuiltinLintDiag};
29use rustc_session::utils::was_invoked_from_cargo;
30use rustc_span::edit_distance::find_best_match_for_name;
31use rustc_span::edition::Edition;
32use rustc_span::hygiene::MacroKind;
33use rustc_span::source_map::SourceMap;
34use rustc_span::{BytePos, Ident, Span, Symbol, SyntaxContext, kw, sym};
35use thin_vec::{ThinVec, thin_vec};
36use tracing::{debug, instrument};
37
38use crate::errors::{
39 self, AddedMacroUse, ChangeImportBinding, ChangeImportBindingSuggestion, ConsiderAddingADerive,
40 ExplicitUnsafeTraits, MacroDefinedLater, MacroRulesNot, MacroSuggMovePosition,
41 MaybeMissingMacroRulesName,
42};
43use crate::imports::{Import, ImportKind};
44use crate::late::{PatternSource, Rib};
45use crate::{
46 AmbiguityError, AmbiguityErrorMisc, AmbiguityKind, BindingError, BindingKey, Finalize,
47 ForwardGenericParamBanReason, HasGenericParams, LexicalScopeBinding, MacroRulesScope, Module,
48 ModuleKind, ModuleOrUniformRoot, NameBinding, NameBindingKind, ParentScope, PathResult,
49 PrivacyError, ResolutionError, Resolver, Scope, ScopeSet, Segment, UseError, Used,
50 VisResolutionError, errors as errs, path_names_to_string,
51};
52
53type Res = def::Res<ast::NodeId>;
54
55pub(crate) type Suggestion = (Vec<(Span, String)>, String, Applicability);
57
58pub(crate) type LabelSuggestion = (Ident, bool);
61
62#[derive(Debug)]
63pub(crate) enum SuggestionTarget {
64 SimilarlyNamed,
66 SingleItem,
68}
69
70#[derive(Debug)]
71pub(crate) struct TypoSuggestion {
72 pub candidate: Symbol,
73 pub span: Option<Span>,
76 pub res: Res,
77 pub target: SuggestionTarget,
78}
79
80impl TypoSuggestion {
81 pub(crate) fn typo_from_ident(ident: Ident, res: Res) -> TypoSuggestion {
82 Self {
83 candidate: ident.name,
84 span: Some(ident.span),
85 res,
86 target: SuggestionTarget::SimilarlyNamed,
87 }
88 }
89 pub(crate) fn typo_from_name(candidate: Symbol, res: Res) -> TypoSuggestion {
90 Self { candidate, span: None, res, target: SuggestionTarget::SimilarlyNamed }
91 }
92 pub(crate) fn single_item_from_ident(ident: Ident, res: Res) -> TypoSuggestion {
93 Self {
94 candidate: ident.name,
95 span: Some(ident.span),
96 res,
97 target: SuggestionTarget::SingleItem,
98 }
99 }
100}
101
102#[derive(Debug, Clone)]
104pub(crate) struct ImportSuggestion {
105 pub did: Option<DefId>,
106 pub descr: &'static str,
107 pub path: Path,
108 pub accessible: bool,
109 pub doc_visible: bool,
111 pub via_import: bool,
112 pub note: Option<String>,
114 pub is_stable: bool,
115}
116
117fn reduce_impl_span_to_impl_keyword(sm: &SourceMap, impl_span: Span) -> Span {
125 let impl_span = sm.span_until_char(impl_span, '<');
126 sm.span_until_whitespace(impl_span)
127}
128
129impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
130 pub(crate) fn dcx(&self) -> DiagCtxtHandle<'tcx> {
131 self.tcx.dcx()
132 }
133
134 pub(crate) fn report_errors(&mut self, krate: &Crate) {
135 self.report_with_use_injections(krate);
136
137 for &(span_use, span_def) in &self.macro_expanded_macro_export_errors {
138 self.lint_buffer.buffer_lint(
139 MACRO_EXPANDED_MACRO_EXPORTS_ACCESSED_BY_ABSOLUTE_PATHS,
140 CRATE_NODE_ID,
141 span_use,
142 BuiltinLintDiag::MacroExpandedMacroExportsAccessedByAbsolutePaths(span_def),
143 );
144 }
145
146 for ambiguity_error in &self.ambiguity_errors {
147 let diag = self.ambiguity_diagnostics(ambiguity_error);
148 if ambiguity_error.warning {
149 let NameBindingKind::Import { import, .. } = ambiguity_error.b1.0.kind else {
150 unreachable!()
151 };
152 self.lint_buffer.buffer_lint(
153 AMBIGUOUS_GLOB_IMPORTS,
154 import.root_id,
155 ambiguity_error.ident.span,
156 BuiltinLintDiag::AmbiguousGlobImports { diag },
157 );
158 } else {
159 let mut err = struct_span_code_err!(self.dcx(), diag.span, E0659, "{}", diag.msg);
160 report_ambiguity_error(&mut err, diag);
161 err.emit();
162 }
163 }
164
165 let mut reported_spans = FxHashSet::default();
166 for error in std::mem::take(&mut self.privacy_errors) {
167 if reported_spans.insert(error.dedup_span) {
168 self.report_privacy_error(&error);
169 }
170 }
171 }
172
173 fn report_with_use_injections(&mut self, krate: &Crate) {
174 for UseError { mut err, candidates, def_id, instead, suggestion, path, is_call } in
175 std::mem::take(&mut self.use_injections)
176 {
177 let (span, found_use) = if let Some(def_id) = def_id.as_local() {
178 UsePlacementFinder::check(krate, self.def_id_to_node_id(def_id))
179 } else {
180 (None, FoundUse::No)
181 };
182
183 if !candidates.is_empty() {
184 show_candidates(
185 self.tcx,
186 &mut err,
187 span,
188 &candidates,
189 if instead { Instead::Yes } else { Instead::No },
190 found_use,
191 DiagMode::Normal,
192 path,
193 "",
194 );
195 err.emit();
196 } else if let Some((span, msg, sugg, appl)) = suggestion {
197 err.span_suggestion_verbose(span, msg, sugg, appl);
198 err.emit();
199 } else if let [segment] = path.as_slice()
200 && is_call
201 {
202 err.stash(segment.ident.span, rustc_errors::StashKey::CallIntoMethod);
203 } else {
204 err.emit();
205 }
206 }
207 }
208
209 pub(crate) fn report_conflict(
210 &mut self,
211 parent: Module<'_>,
212 ident: Ident,
213 ns: Namespace,
214 new_binding: NameBinding<'ra>,
215 old_binding: NameBinding<'ra>,
216 ) {
217 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.module()) {
237 (ValueNS, _) => "value",
238 (MacroNS, _) => "macro",
239 (TypeNS, _) if old_binding.is_extern_crate() => "extern crate",
240 (TypeNS, Some(module)) if module.is_normal() => "module",
241 (TypeNS, Some(module)) if module.is_trait() => "trait",
242 (TypeNS, _) => "type",
243 };
244
245 let code = match (old_binding.is_extern_crate(), new_binding.is_extern_crate()) {
246 (true, true) => E0259,
247 (true, _) | (_, true) => match new_binding.is_import() && old_binding.is_import() {
248 true => E0254,
249 false => E0260,
250 },
251 _ => match (old_binding.is_import_user_facing(), new_binding.is_import_user_facing()) {
252 (false, false) => E0428,
253 (true, true) => E0252,
254 _ => E0255,
255 },
256 };
257
258 let label = match new_binding.is_import_user_facing() {
259 true => errors::NameDefinedMultipleTimeLabel::Reimported { span },
260 false => errors::NameDefinedMultipleTimeLabel::Redefined { span },
261 };
262
263 let old_binding_label =
264 (!old_binding.span.is_dummy() && old_binding.span != span).then(|| {
265 let span = self.tcx.sess.source_map().guess_head_span(old_binding.span);
266 match old_binding.is_import_user_facing() {
267 true => {
268 errors::NameDefinedMultipleTimeOldBindingLabel::Import { span, old_kind }
269 }
270 false => errors::NameDefinedMultipleTimeOldBindingLabel::Definition {
271 span,
272 old_kind,
273 },
274 }
275 });
276
277 let mut err = self
278 .dcx()
279 .create_err(errors::NameDefinedMultipleTime {
280 span,
281 name,
282 descr: ns.descr(),
283 container,
284 label,
285 old_binding_label,
286 })
287 .with_code(code);
288
289 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 =
325 self.extern_prelude.get(&ident).is_none_or(|entry| entry.introduced_by_item);
326 let should_remove_import = duplicate
330 && !has_dummy_span
331 && ((new_binding.is_extern_crate() || old_binding.is_extern_crate()) || from_item);
332
333 match import {
334 Some((import, span, true)) if should_remove_import && import.is_nested() => {
335 self.add_suggestion_for_duplicate_nested_use(&mut err, import, span);
336 }
337 Some((import, _, true)) if should_remove_import && !import.is_glob() => {
338 err.subdiagnostic(errors::ToolOnlyRemoveUnnecessaryImport {
341 span: import.use_span_with_attributes,
342 });
343 }
344 Some((import, span, _)) => {
345 self.add_suggestion_for_rename_of_use(&mut err, name, import, span);
346 }
347 _ => {}
348 }
349
350 err.emit();
351 self.name_already_seen.insert(name, span);
352 }
353
354 fn add_suggestion_for_rename_of_use(
364 &self,
365 err: &mut Diag<'_>,
366 name: Symbol,
367 import: Import<'_>,
368 binding_span: Span,
369 ) {
370 let suggested_name = if name.as_str().chars().next().unwrap().is_uppercase() {
371 format!("Other{name}")
372 } else {
373 format!("other_{name}")
374 };
375
376 let mut suggestion = None;
377 let mut span = binding_span;
378 match import.kind {
379 ImportKind::Single { type_ns_only: true, .. } => {
380 suggestion = Some(format!("self as {suggested_name}"))
381 }
382 ImportKind::Single { source, .. } => {
383 if let Some(pos) = source.span.hi().0.checked_sub(binding_span.lo().0)
384 && let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(binding_span)
385 && pos as usize <= snippet.len()
386 {
387 span = binding_span.with_lo(binding_span.lo() + BytePos(pos)).with_hi(
388 binding_span.hi() - BytePos(if snippet.ends_with(';') { 1 } else { 0 }),
389 );
390 suggestion = Some(format!(" as {suggested_name}"));
391 }
392 }
393 ImportKind::ExternCrate { source, target, .. } => {
394 suggestion = Some(format!(
395 "extern crate {} as {};",
396 source.unwrap_or(target.name),
397 suggested_name,
398 ))
399 }
400 _ => unreachable!(),
401 }
402
403 if let Some(suggestion) = suggestion {
404 err.subdiagnostic(ChangeImportBindingSuggestion { span, suggestion });
405 } else {
406 err.subdiagnostic(ChangeImportBinding { span });
407 }
408 }
409
410 fn add_suggestion_for_duplicate_nested_use(
433 &self,
434 err: &mut Diag<'_>,
435 import: Import<'_>,
436 binding_span: Span,
437 ) {
438 assert!(import.is_nested());
439
440 let (found_closing_brace, span) =
448 find_span_of_binding_until_next_binding(self.tcx.sess, binding_span, import.use_span);
449
450 if found_closing_brace {
453 if let Some(span) = extend_span_to_previous_binding(self.tcx.sess, span) {
454 err.subdiagnostic(errors::ToolOnlyRemoveUnnecessaryImport { span });
455 } else {
456 err.subdiagnostic(errors::RemoveUnnecessaryImport {
459 span: import.use_span_with_attributes,
460 });
461 }
462
463 return;
464 }
465
466 err.subdiagnostic(errors::RemoveUnnecessaryImport { span });
467 }
468
469 pub(crate) fn lint_if_path_starts_with_module(
470 &mut self,
471 finalize: Option<Finalize>,
472 path: &[Segment],
473 second_binding: Option<NameBinding<'_>>,
474 ) {
475 let Some(Finalize { node_id, root_span, .. }) = finalize else {
476 return;
477 };
478
479 let first_name = match path.get(0) {
480 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 &mut self,
526 module: Module<'ra>,
527 names: &mut Vec<TypoSuggestion>,
528 filter_fn: &impl Fn(Res) -> bool,
529 ctxt: Option<SyntaxContext>,
530 ) {
531 module.for_each_child(self, |_this, ident, _ns, binding| {
532 let res = binding.res();
533 if filter_fn(res) && ctxt.is_none_or(|ctxt| ctxt == ident.span.ctxt()) {
534 names.push(TypoSuggestion::typo_from_ident(ident, res));
535 }
536 });
537 }
538
539 pub(crate) fn report_error(
544 &mut self,
545 span: Span,
546 resolution_error: ResolutionError<'ra>,
547 ) -> ErrorGuaranteed {
548 self.into_struct_error(span, resolution_error).emit()
549 }
550
551 pub(crate) fn into_struct_error(
552 &mut self,
553 span: Span,
554 resolution_error: ResolutionError<'ra>,
555 ) -> Diag<'_> {
556 match resolution_error {
557 ResolutionError::GenericParamsFromOuterItem(
558 outer_res,
559 has_generic_params,
560 def_kind,
561 ) => {
562 use errs::GenericParamsFromOuterItemLabel as Label;
563 let static_or_const = match def_kind {
564 DefKind::Static { .. } => {
565 Some(errs::GenericParamsFromOuterItemStaticOrConst::Static)
566 }
567 DefKind::Const => Some(errs::GenericParamsFromOuterItemStaticOrConst::Const),
568 _ => None,
569 };
570 let is_self =
571 matches!(outer_res, Res::SelfTyParam { .. } | Res::SelfTyAlias { .. });
572 let mut err = errs::GenericParamsFromOuterItem {
573 span,
574 label: None,
575 refer_to_type_directly: None,
576 sugg: None,
577 static_or_const,
578 is_self,
579 };
580
581 let sm = self.tcx.sess.source_map();
582 let def_id = match outer_res {
583 Res::SelfTyParam { .. } => {
584 err.label = Some(Label::SelfTyParam(span));
585 return self.dcx().create_err(err);
586 }
587 Res::SelfTyAlias { alias_to: def_id, .. } => {
588 err.label = Some(Label::SelfTyAlias(reduce_impl_span_to_impl_keyword(
589 sm,
590 self.def_span(def_id),
591 )));
592 err.refer_to_type_directly = Some(span);
593 return self.dcx().create_err(err);
594 }
595 Res::Def(DefKind::TyParam, def_id) => {
596 err.label = Some(Label::TyParam(self.def_span(def_id)));
597 def_id
598 }
599 Res::Def(DefKind::ConstParam, def_id) => {
600 err.label = Some(Label::ConstParam(self.def_span(def_id)));
601 def_id
602 }
603 _ => {
604 bug!(
605 "GenericParamsFromOuterItem should only be used with \
606 Res::SelfTyParam, Res::SelfTyAlias, DefKind::TyParam or \
607 DefKind::ConstParam"
608 );
609 }
610 };
611
612 if let HasGenericParams::Yes(span) = has_generic_params {
613 let name = self.tcx.item_name(def_id);
614 let (span, snippet) = if span.is_empty() {
615 let snippet = format!("<{name}>");
616 (span, snippet)
617 } else {
618 let span = sm.span_through_char(span, '<').shrink_to_hi();
619 let snippet = format!("{name}, ");
620 (span, snippet)
621 };
622 err.sugg = Some(errs::GenericParamsFromOuterItemSugg { span, snippet });
623 }
624
625 self.dcx().create_err(err)
626 }
627 ResolutionError::NameAlreadyUsedInParameterList(name, first_use_span) => self
628 .dcx()
629 .create_err(errs::NameAlreadyUsedInParameterList { span, first_use_span, name }),
630 ResolutionError::MethodNotMemberOfTrait(method, trait_, candidate) => {
631 self.dcx().create_err(errs::MethodNotMemberOfTrait {
632 span,
633 method,
634 trait_,
635 sub: candidate.map(|c| errs::AssociatedFnWithSimilarNameExists {
636 span: method.span,
637 candidate: c,
638 }),
639 })
640 }
641 ResolutionError::TypeNotMemberOfTrait(type_, trait_, candidate) => {
642 self.dcx().create_err(errs::TypeNotMemberOfTrait {
643 span,
644 type_,
645 trait_,
646 sub: candidate.map(|c| errs::AssociatedTypeWithSimilarNameExists {
647 span: type_.span,
648 candidate: c,
649 }),
650 })
651 }
652 ResolutionError::ConstNotMemberOfTrait(const_, trait_, candidate) => {
653 self.dcx().create_err(errs::ConstNotMemberOfTrait {
654 span,
655 const_,
656 trait_,
657 sub: candidate.map(|c| errs::AssociatedConstWithSimilarNameExists {
658 span: const_.span,
659 candidate: c,
660 }),
661 })
662 }
663 ResolutionError::VariableNotBoundInPattern(binding_error, parent_scope) => {
664 let BindingError { name, target, origin, could_be_path } = binding_error;
665
666 let target_sp = target.iter().copied().collect::<Vec<_>>();
667 let origin_sp = origin.iter().copied().collect::<Vec<_>>();
668
669 let msp = MultiSpan::from_spans(target_sp.clone());
670 let mut err = self
671 .dcx()
672 .create_err(errors::VariableIsNotBoundInAllPatterns { multispan: msp, name });
673 for sp in target_sp {
674 err.subdiagnostic(errors::PatternDoesntBindName { span: sp, name });
675 }
676 for sp in origin_sp {
677 err.subdiagnostic(errors::VariableNotInAllPatterns { span: sp });
678 }
679 if could_be_path {
680 let import_suggestions = self.lookup_import_candidates(
681 name,
682 Namespace::ValueNS,
683 &parent_scope,
684 &|res: Res| {
685 matches!(
686 res,
687 Res::Def(
688 DefKind::Ctor(CtorOf::Variant, CtorKind::Const)
689 | DefKind::Ctor(CtorOf::Struct, CtorKind::Const)
690 | DefKind::Const
691 | DefKind::AssocConst,
692 _,
693 )
694 )
695 },
696 );
697
698 if import_suggestions.is_empty() {
699 let help_msg = format!(
700 "if you meant to match on a variant or a `const` item, consider \
701 making the path in the pattern qualified: `path::to::ModOrType::{name}`",
702 );
703 err.span_help(span, help_msg);
704 }
705 show_candidates(
706 self.tcx,
707 &mut err,
708 Some(span),
709 &import_suggestions,
710 Instead::No,
711 FoundUse::Yes,
712 DiagMode::Pattern,
713 vec![],
714 "",
715 );
716 }
717 err
718 }
719 ResolutionError::VariableBoundWithDifferentMode(variable_name, first_binding_span) => {
720 self.dcx().create_err(errs::VariableBoundWithDifferentMode {
721 span,
722 first_binding_span,
723 variable_name,
724 })
725 }
726 ResolutionError::IdentifierBoundMoreThanOnceInParameterList(identifier) => self
727 .dcx()
728 .create_err(errs::IdentifierBoundMoreThanOnceInParameterList { span, identifier }),
729 ResolutionError::IdentifierBoundMoreThanOnceInSamePattern(identifier) => self
730 .dcx()
731 .create_err(errs::IdentifierBoundMoreThanOnceInSamePattern { span, identifier }),
732 ResolutionError::UndeclaredLabel { name, suggestion } => {
733 let ((sub_reachable, sub_reachable_suggestion), sub_unreachable) = match suggestion
734 {
735 Some((ident, true)) => (
737 (
738 Some(errs::LabelWithSimilarNameReachable(ident.span)),
739 Some(errs::TryUsingSimilarlyNamedLabel {
740 span,
741 ident_name: ident.name,
742 }),
743 ),
744 None,
745 ),
746 Some((ident, false)) => (
748 (None, None),
749 Some(errs::UnreachableLabelWithSimilarNameExists {
750 ident_span: ident.span,
751 }),
752 ),
753 None => ((None, None), None),
755 };
756 self.dcx().create_err(errs::UndeclaredLabel {
757 span,
758 name,
759 sub_reachable,
760 sub_reachable_suggestion,
761 sub_unreachable,
762 })
763 }
764 ResolutionError::SelfImportsOnlyAllowedWithin { root, span_with_rename } => {
765 let (suggestion, mpart_suggestion) = if root {
767 (None, None)
768 } else {
769 let suggestion = errs::SelfImportsOnlyAllowedWithinSuggestion { span };
772
773 let mpart_suggestion = errs::SelfImportsOnlyAllowedWithinMultipartSuggestion {
776 multipart_start: span_with_rename.shrink_to_lo(),
777 multipart_end: span_with_rename.shrink_to_hi(),
778 };
779 (Some(suggestion), Some(mpart_suggestion))
780 };
781 self.dcx().create_err(errs::SelfImportsOnlyAllowedWithin {
782 span,
783 suggestion,
784 mpart_suggestion,
785 })
786 }
787 ResolutionError::SelfImportCanOnlyAppearOnceInTheList => {
788 self.dcx().create_err(errs::SelfImportCanOnlyAppearOnceInTheList { span })
789 }
790 ResolutionError::SelfImportOnlyInImportListWithNonEmptyPrefix => {
791 self.dcx().create_err(errs::SelfImportOnlyInImportListWithNonEmptyPrefix { span })
792 }
793 ResolutionError::FailedToResolve { segment, label, suggestion, module } => {
794 let mut err =
795 struct_span_code_err!(self.dcx(), span, E0433, "failed to resolve: {label}");
796 err.span_label(span, label);
797
798 if let Some((suggestions, msg, applicability)) = suggestion {
799 if suggestions.is_empty() {
800 err.help(msg);
801 return err;
802 }
803 err.multipart_suggestion(msg, suggestions, applicability);
804 }
805 if let Some(ModuleOrUniformRoot::Module(module)) = module
806 && let Some(module) = module.opt_def_id()
807 && let Some(segment) = segment
808 {
809 self.find_cfg_stripped(&mut err, &segment, module);
810 }
811
812 err
813 }
814 ResolutionError::CannotCaptureDynamicEnvironmentInFnItem => {
815 self.dcx().create_err(errs::CannotCaptureDynamicEnvironmentInFnItem { span })
816 }
817 ResolutionError::AttemptToUseNonConstantValueInConstant {
818 ident,
819 suggestion,
820 current,
821 type_span,
822 } => {
823 let sp = self
832 .tcx
833 .sess
834 .source_map()
835 .span_extend_to_prev_str(ident.span, current, true, false);
836
837 let ((with, with_label), without) = match sp {
838 Some(sp) if !self.tcx.sess.source_map().is_multiline(sp) => {
839 let sp = sp
840 .with_lo(BytePos(sp.lo().0 - (current.len() as u32)))
841 .until(ident.span);
842 (
843 (Some(errs::AttemptToUseNonConstantValueInConstantWithSuggestion {
844 span: sp,
845 suggestion,
846 current,
847 type_span,
848 }), Some(errs::AttemptToUseNonConstantValueInConstantLabelWithSuggestion {span})),
849 None,
850 )
851 }
852 _ => (
853 (None, None),
854 Some(errs::AttemptToUseNonConstantValueInConstantWithoutSuggestion {
855 ident_span: ident.span,
856 suggestion,
857 }),
858 ),
859 };
860
861 self.dcx().create_err(errs::AttemptToUseNonConstantValueInConstant {
862 span,
863 with,
864 with_label,
865 without,
866 })
867 }
868 ResolutionError::BindingShadowsSomethingUnacceptable {
869 shadowing_binding,
870 name,
871 participle,
872 article,
873 shadowed_binding,
874 shadowed_binding_span,
875 } => self.dcx().create_err(errs::BindingShadowsSomethingUnacceptable {
876 span,
877 shadowing_binding,
878 shadowed_binding,
879 article,
880 sub_suggestion: match (shadowing_binding, shadowed_binding) {
881 (
882 PatternSource::Match,
883 Res::Def(DefKind::Ctor(CtorOf::Variant | CtorOf::Struct, CtorKind::Fn), _),
884 ) => Some(errs::BindingShadowsSomethingUnacceptableSuggestion { span, name }),
885 _ => None,
886 },
887 shadowed_binding_span,
888 participle,
889 name,
890 }),
891 ResolutionError::ForwardDeclaredGenericParam(param, reason) => match reason {
892 ForwardGenericParamBanReason::Default => {
893 self.dcx().create_err(errs::ForwardDeclaredGenericParam { param, span })
894 }
895 ForwardGenericParamBanReason::ConstParamTy => self
896 .dcx()
897 .create_err(errs::ForwardDeclaredGenericInConstParamTy { param, span }),
898 },
899 ResolutionError::ParamInTyOfConstParam { name } => {
900 self.dcx().create_err(errs::ParamInTyOfConstParam { span, name })
901 }
902 ResolutionError::ParamInNonTrivialAnonConst { name, param_kind: is_type } => {
903 self.dcx().create_err(errs::ParamInNonTrivialAnonConst {
904 span,
905 name,
906 param_kind: is_type,
907 help: self
908 .tcx
909 .sess
910 .is_nightly_build()
911 .then_some(errs::ParamInNonTrivialAnonConstHelp),
912 })
913 }
914 ResolutionError::ParamInEnumDiscriminant { name, param_kind: is_type } => self
915 .dcx()
916 .create_err(errs::ParamInEnumDiscriminant { span, name, param_kind: is_type }),
917 ResolutionError::ForwardDeclaredSelf(reason) => match reason {
918 ForwardGenericParamBanReason::Default => {
919 self.dcx().create_err(errs::SelfInGenericParamDefault { span })
920 }
921 ForwardGenericParamBanReason::ConstParamTy => {
922 self.dcx().create_err(errs::SelfInConstGenericTy { span })
923 }
924 },
925 ResolutionError::UnreachableLabel { name, definition_span, suggestion } => {
926 let ((sub_suggestion_label, sub_suggestion), sub_unreachable_label) =
927 match suggestion {
928 Some((ident, true)) => (
930 (
931 Some(errs::UnreachableLabelSubLabel { ident_span: ident.span }),
932 Some(errs::UnreachableLabelSubSuggestion {
933 span,
934 ident_name: ident.name,
937 }),
938 ),
939 None,
940 ),
941 Some((ident, false)) => (
943 (None, None),
944 Some(errs::UnreachableLabelSubLabelUnreachable {
945 ident_span: ident.span,
946 }),
947 ),
948 None => ((None, None), None),
950 };
951 self.dcx().create_err(errs::UnreachableLabel {
952 span,
953 name,
954 definition_span,
955 sub_suggestion,
956 sub_suggestion_label,
957 sub_unreachable_label,
958 })
959 }
960 ResolutionError::TraitImplMismatch {
961 name,
962 kind,
963 code,
964 trait_item_span,
965 trait_path,
966 } => self
967 .dcx()
968 .create_err(errors::TraitImplMismatch {
969 span,
970 name,
971 kind,
972 trait_path,
973 trait_item_span,
974 })
975 .with_code(code),
976 ResolutionError::TraitImplDuplicate { name, trait_item_span, old_span } => self
977 .dcx()
978 .create_err(errs::TraitImplDuplicate { span, name, trait_item_span, old_span }),
979 ResolutionError::InvalidAsmSym => self.dcx().create_err(errs::InvalidAsmSym { span }),
980 ResolutionError::LowercaseSelf => self.dcx().create_err(errs::LowercaseSelf { span }),
981 ResolutionError::BindingInNeverPattern => {
982 self.dcx().create_err(errs::BindingInNeverPattern { span })
983 }
984 }
985 }
986
987 pub(crate) fn report_vis_error(
988 &mut self,
989 vis_resolution_error: VisResolutionError<'_>,
990 ) -> ErrorGuaranteed {
991 match vis_resolution_error {
992 VisResolutionError::Relative2018(span, path) => {
993 self.dcx().create_err(errs::Relative2018 {
994 span,
995 path_span: path.span,
996 path_str: pprust::path_to_string(path),
999 })
1000 }
1001 VisResolutionError::AncestorOnly(span) => {
1002 self.dcx().create_err(errs::AncestorOnly(span))
1003 }
1004 VisResolutionError::FailedToResolve(span, label, suggestion) => self.into_struct_error(
1005 span,
1006 ResolutionError::FailedToResolve { segment: None, label, suggestion, module: None },
1007 ),
1008 VisResolutionError::ExpectedFound(span, path_str, res) => {
1009 self.dcx().create_err(errs::ExpectedModuleFound { span, res, path_str })
1010 }
1011 VisResolutionError::Indeterminate(span) => {
1012 self.dcx().create_err(errs::Indeterminate(span))
1013 }
1014 VisResolutionError::ModuleOnly(span) => self.dcx().create_err(errs::ModuleOnly(span)),
1015 }
1016 .emit()
1017 }
1018
1019 fn early_lookup_typo_candidate(
1021 &mut self,
1022 scope_set: ScopeSet<'ra>,
1023 parent_scope: &ParentScope<'ra>,
1024 ident: Ident,
1025 filter_fn: &impl Fn(Res) -> bool,
1026 ) -> Option<TypoSuggestion> {
1027 let mut suggestions = Vec::new();
1028 let ctxt = ident.span.ctxt();
1029 self.visit_scopes(scope_set, parent_scope, ctxt, |this, scope, use_prelude, _| {
1030 match scope {
1031 Scope::DeriveHelpers(expn_id) => {
1032 let res = Res::NonMacroAttr(NonMacroAttrKind::DeriveHelper);
1033 if filter_fn(res) {
1034 suggestions.extend(
1035 this.helper_attrs
1036 .get(&expn_id)
1037 .into_iter()
1038 .flatten()
1039 .map(|(ident, _)| TypoSuggestion::typo_from_ident(*ident, res)),
1040 );
1041 }
1042 }
1043 Scope::DeriveHelpersCompat => {
1044 let res = Res::NonMacroAttr(NonMacroAttrKind::DeriveHelperCompat);
1045 if filter_fn(res) {
1046 for derive in parent_scope.derives {
1047 let parent_scope = &ParentScope { derives: &[], ..*parent_scope };
1048 let Ok((Some(ext), _)) = this.resolve_macro_path(
1049 derive,
1050 Some(MacroKind::Derive),
1051 parent_scope,
1052 false,
1053 false,
1054 None,
1055 None,
1056 ) else {
1057 continue;
1058 };
1059 suggestions.extend(
1060 ext.helper_attrs
1061 .iter()
1062 .map(|name| TypoSuggestion::typo_from_name(*name, res)),
1063 );
1064 }
1065 }
1066 }
1067 Scope::MacroRules(macro_rules_scope) => {
1068 if let MacroRulesScope::Binding(macro_rules_binding) = macro_rules_scope.get() {
1069 let res = macro_rules_binding.binding.res();
1070 if filter_fn(res) {
1071 suggestions.push(TypoSuggestion::typo_from_ident(
1072 macro_rules_binding.ident,
1073 res,
1074 ))
1075 }
1076 }
1077 }
1078 Scope::CrateRoot => {
1079 let root_ident = Ident::new(kw::PathRoot, ident.span);
1080 let root_module = this.resolve_crate_root(root_ident);
1081 this.add_module_candidates(root_module, &mut suggestions, filter_fn, None);
1082 }
1083 Scope::Module(module, _) => {
1084 this.add_module_candidates(module, &mut suggestions, filter_fn, None);
1085 }
1086 Scope::MacroUsePrelude => {
1087 suggestions.extend(this.macro_use_prelude.iter().filter_map(
1088 |(name, binding)| {
1089 let res = binding.res();
1090 filter_fn(res).then_some(TypoSuggestion::typo_from_name(*name, res))
1091 },
1092 ));
1093 }
1094 Scope::BuiltinAttrs => {
1095 let res = Res::NonMacroAttr(NonMacroAttrKind::Builtin(sym::dummy));
1096 if filter_fn(res) {
1097 suggestions.extend(
1098 BUILTIN_ATTRIBUTES
1099 .iter()
1100 .map(|attr| TypoSuggestion::typo_from_name(attr.name, res)),
1101 );
1102 }
1103 }
1104 Scope::ExternPrelude => {
1105 suggestions.extend(this.extern_prelude.iter().filter_map(|(ident, _)| {
1106 let res = Res::Def(DefKind::Mod, CRATE_DEF_ID.to_def_id());
1107 filter_fn(res).then_some(TypoSuggestion::typo_from_ident(*ident, res))
1108 }));
1109 }
1110 Scope::ToolPrelude => {
1111 let res = Res::NonMacroAttr(NonMacroAttrKind::Tool);
1112 suggestions.extend(
1113 this.registered_tools
1114 .iter()
1115 .map(|ident| TypoSuggestion::typo_from_ident(*ident, res)),
1116 );
1117 }
1118 Scope::StdLibPrelude => {
1119 if let Some(prelude) = this.prelude {
1120 let mut tmp_suggestions = Vec::new();
1121 this.add_module_candidates(prelude, &mut tmp_suggestions, filter_fn, None);
1122 suggestions.extend(
1123 tmp_suggestions
1124 .into_iter()
1125 .filter(|s| use_prelude.into() || this.is_builtin_macro(s.res)),
1126 );
1127 }
1128 }
1129 Scope::BuiltinTypes => {
1130 suggestions.extend(PrimTy::ALL.iter().filter_map(|prim_ty| {
1131 let res = Res::PrimTy(*prim_ty);
1132 filter_fn(res)
1133 .then_some(TypoSuggestion::typo_from_name(prim_ty.name(), res))
1134 }))
1135 }
1136 }
1137
1138 None::<()>
1139 });
1140
1141 suggestions.sort_by(|a, b| a.candidate.as_str().cmp(b.candidate.as_str()));
1143
1144 match find_best_match_for_name(
1145 &suggestions.iter().map(|suggestion| suggestion.candidate).collect::<Vec<Symbol>>(),
1146 ident.name,
1147 None,
1148 ) {
1149 Some(found) if found != ident.name => {
1150 suggestions.into_iter().find(|suggestion| suggestion.candidate == found)
1151 }
1152 _ => None,
1153 }
1154 }
1155
1156 fn lookup_import_candidates_from_module<FilterFn>(
1157 &mut self,
1158 lookup_ident: Ident,
1159 namespace: Namespace,
1160 parent_scope: &ParentScope<'ra>,
1161 start_module: Module<'ra>,
1162 crate_path: ThinVec<ast::PathSegment>,
1163 filter_fn: FilterFn,
1164 ) -> Vec<ImportSuggestion>
1165 where
1166 FilterFn: Fn(Res) -> bool,
1167 {
1168 let mut candidates = Vec::new();
1169 let mut seen_modules = FxHashSet::default();
1170 let start_did = start_module.def_id();
1171 let mut worklist = vec![(
1172 start_module,
1173 ThinVec::<ast::PathSegment>::new(),
1174 true,
1175 start_did.is_local() || !self.tcx.is_doc_hidden(start_did),
1176 true,
1177 )];
1178 let mut worklist_via_import = vec![];
1179
1180 while let Some((in_module, path_segments, accessible, doc_visible, is_stable)) =
1181 match worklist.pop() {
1182 None => worklist_via_import.pop(),
1183 Some(x) => Some(x),
1184 }
1185 {
1186 let in_module_is_extern = !in_module.def_id().is_local();
1187 in_module.for_each_child(self, |this, ident, ns, name_binding| {
1188 if name_binding.is_assoc_item()
1190 && !this.tcx.features().import_trait_associated_functions()
1191 {
1192 return;
1193 }
1194
1195 if ident.name == kw::Underscore {
1196 return;
1197 }
1198
1199 let child_accessible =
1200 accessible && this.is_accessible_from(name_binding.vis, parent_scope.module);
1201
1202 if in_module_is_extern && !child_accessible {
1204 return;
1205 }
1206
1207 let via_import = name_binding.is_import() && !name_binding.is_extern_crate();
1208
1209 if via_import && name_binding.is_possibly_imported_variant() {
1215 return;
1216 }
1217
1218 if let NameBindingKind::Import { binding, .. } = name_binding.kind
1220 && this.is_accessible_from(binding.vis, parent_scope.module)
1221 && !this.is_accessible_from(name_binding.vis, parent_scope.module)
1222 {
1223 return;
1224 }
1225
1226 let res = name_binding.res();
1227 let did = match res {
1228 Res::Def(DefKind::Ctor(..), did) => this.tcx.opt_parent(did),
1229 _ => res.opt_def_id(),
1230 };
1231 let child_doc_visible = doc_visible
1232 && did.is_none_or(|did| did.is_local() || !this.tcx.is_doc_hidden(did));
1233
1234 if ident.name == lookup_ident.name
1238 && ns == namespace
1239 && in_module != parent_scope.module
1240 && !ident.span.normalize_to_macros_2_0().from_expansion()
1241 && filter_fn(res)
1242 {
1243 let mut segms = if lookup_ident.span.at_least_rust_2018() {
1245 crate_path.clone()
1248 } else {
1249 ThinVec::new()
1250 };
1251 segms.append(&mut path_segments.clone());
1252
1253 segms.push(ast::PathSegment::from_ident(ident));
1254 let path = Path { span: name_binding.span, segments: segms, tokens: None };
1255
1256 if child_accessible
1257 && let Some(idx) = candidates
1259 .iter()
1260 .position(|v: &ImportSuggestion| v.did == did && !v.accessible)
1261 {
1262 candidates.remove(idx);
1263 }
1264
1265 let is_stable = if is_stable
1266 && let Some(did) = did
1267 && this.is_stable(did, path.span)
1268 {
1269 true
1270 } else {
1271 false
1272 };
1273
1274 if is_stable
1279 && let Some(idx) = candidates
1280 .iter()
1281 .position(|v: &ImportSuggestion| v.did == did && !v.is_stable)
1282 {
1283 candidates.remove(idx);
1284 }
1285
1286 if candidates.iter().all(|v: &ImportSuggestion| v.did != did) {
1287 let note = if let Some(did) = did {
1290 let requires_note = !did.is_local()
1291 && this.tcx.get_attrs(did, sym::rustc_diagnostic_item).any(
1292 |attr| {
1293 [sym::TryInto, sym::TryFrom, sym::FromIterator]
1294 .map(|x| Some(x))
1295 .contains(&attr.value_str())
1296 },
1297 );
1298
1299 requires_note.then(|| {
1300 format!(
1301 "'{}' is included in the prelude starting in Edition 2021",
1302 path_names_to_string(&path)
1303 )
1304 })
1305 } else {
1306 None
1307 };
1308
1309 candidates.push(ImportSuggestion {
1310 did,
1311 descr: res.descr(),
1312 path,
1313 accessible: child_accessible,
1314 doc_visible: child_doc_visible,
1315 note,
1316 via_import,
1317 is_stable,
1318 });
1319 }
1320 }
1321
1322 if let Some(module) = name_binding.module() {
1324 let mut path_segments = path_segments.clone();
1326 path_segments.push(ast::PathSegment::from_ident(ident));
1327
1328 let alias_import = if let NameBindingKind::Import { import, .. } =
1329 name_binding.kind
1330 && let ImportKind::ExternCrate { source: Some(_), .. } = import.kind
1331 && import.parent_scope.expansion == parent_scope.expansion
1332 {
1333 true
1334 } else {
1335 false
1336 };
1337
1338 let is_extern_crate_that_also_appears_in_prelude =
1339 name_binding.is_extern_crate() && lookup_ident.span.at_least_rust_2018();
1340
1341 if !is_extern_crate_that_also_appears_in_prelude || alias_import {
1342 if seen_modules.insert(module.def_id()) {
1344 if via_import { &mut worklist_via_import } else { &mut worklist }.push(
1345 (
1346 module,
1347 path_segments,
1348 child_accessible,
1349 child_doc_visible,
1350 is_stable && this.is_stable(module.def_id(), name_binding.span),
1351 ),
1352 );
1353 }
1354 }
1355 }
1356 })
1357 }
1358
1359 candidates
1360 }
1361
1362 fn is_stable(&self, did: DefId, span: Span) -> bool {
1363 if did.is_local() {
1364 return true;
1365 }
1366
1367 match self.tcx.lookup_stability(did) {
1368 Some(Stability {
1369 level: attr::StabilityLevel::Unstable { implied_by, .. },
1370 feature,
1371 ..
1372 }) => {
1373 if span.allows_unstable(feature) {
1374 true
1375 } else if self.tcx.features().enabled(feature) {
1376 true
1377 } else if let Some(implied_by) = implied_by
1378 && self.tcx.features().enabled(implied_by)
1379 {
1380 true
1381 } else {
1382 false
1383 }
1384 }
1385 Some(_) => true,
1386 None => false,
1387 }
1388 }
1389
1390 pub(crate) fn lookup_import_candidates<FilterFn>(
1398 &mut self,
1399 lookup_ident: Ident,
1400 namespace: Namespace,
1401 parent_scope: &ParentScope<'ra>,
1402 filter_fn: FilterFn,
1403 ) -> Vec<ImportSuggestion>
1404 where
1405 FilterFn: Fn(Res) -> bool,
1406 {
1407 let crate_path = thin_vec![ast::PathSegment::from_ident(Ident::with_dummy_span(kw::Crate))];
1408 let mut suggestions = self.lookup_import_candidates_from_module(
1409 lookup_ident,
1410 namespace,
1411 parent_scope,
1412 self.graph_root,
1413 crate_path,
1414 &filter_fn,
1415 );
1416
1417 if lookup_ident.span.at_least_rust_2018() {
1418 for ident in self.extern_prelude.clone().into_keys() {
1419 if ident.span.from_expansion() {
1420 continue;
1426 }
1427 let Some(crate_id) = self.crate_loader(|c| c.maybe_process_path_extern(ident.name))
1428 else {
1429 continue;
1430 };
1431
1432 let crate_def_id = crate_id.as_def_id();
1433 let crate_root = self.expect_module(crate_def_id);
1434
1435 let needs_disambiguation =
1439 self.resolutions(parent_scope.module).borrow().iter().any(
1440 |(key, name_resolution)| {
1441 if key.ns == TypeNS
1442 && key.ident == ident
1443 && let Some(binding) = name_resolution.borrow().binding
1444 {
1445 match binding.res() {
1446 Res::Def(_, def_id) => def_id != crate_def_id,
1449 Res::PrimTy(_) => true,
1450 _ => false,
1451 }
1452 } else {
1453 false
1454 }
1455 },
1456 );
1457 let mut crate_path = ThinVec::new();
1458 if needs_disambiguation {
1459 crate_path.push(ast::PathSegment::path_root(rustc_span::DUMMY_SP));
1460 }
1461 crate_path.push(ast::PathSegment::from_ident(ident));
1462
1463 suggestions.extend(self.lookup_import_candidates_from_module(
1464 lookup_ident,
1465 namespace,
1466 parent_scope,
1467 crate_root,
1468 crate_path,
1469 &filter_fn,
1470 ));
1471 }
1472 }
1473
1474 suggestions
1475 }
1476
1477 pub(crate) fn unresolved_macro_suggestions(
1478 &mut self,
1479 err: &mut Diag<'_>,
1480 macro_kind: MacroKind,
1481 parent_scope: &ParentScope<'ra>,
1482 ident: Ident,
1483 krate: &Crate,
1484 sugg_span: Option<Span>,
1485 ) {
1486 self.visit_scopes(
1489 ScopeSet::Macro(MacroKind::Derive),
1490 &parent_scope,
1491 ident.span.ctxt(),
1492 |this, scope, _use_prelude, _ctxt| {
1493 let Scope::Module(m, _) = scope else {
1494 return None;
1495 };
1496 for (_, resolution) in this.resolutions(m).borrow().iter() {
1497 let Some(binding) = resolution.borrow().binding else {
1498 continue;
1499 };
1500 let Res::Def(DefKind::Macro(MacroKind::Derive | MacroKind::Attr), def_id) =
1501 binding.res()
1502 else {
1503 continue;
1504 };
1505 let _ = this.get_macro_by_def_id(def_id);
1508 }
1509 None::<()>
1510 },
1511 );
1512
1513 let is_expected = &|res: Res| res.macro_kind() == Some(macro_kind);
1514 let suggestion = self.early_lookup_typo_candidate(
1515 ScopeSet::Macro(macro_kind),
1516 parent_scope,
1517 ident,
1518 is_expected,
1519 );
1520 if !self.add_typo_suggestion(err, suggestion, ident.span) {
1521 self.detect_derive_attribute(err, ident, parent_scope, sugg_span);
1522 }
1523
1524 let import_suggestions =
1525 self.lookup_import_candidates(ident, Namespace::MacroNS, parent_scope, is_expected);
1526 let (span, found_use) = match parent_scope.module.nearest_parent_mod().as_local() {
1527 Some(def_id) => UsePlacementFinder::check(krate, self.def_id_to_node_id(def_id)),
1528 None => (None, FoundUse::No),
1529 };
1530 show_candidates(
1531 self.tcx,
1532 err,
1533 span,
1534 &import_suggestions,
1535 Instead::No,
1536 found_use,
1537 DiagMode::Normal,
1538 vec![],
1539 "",
1540 );
1541
1542 if macro_kind == MacroKind::Bang && ident.name == sym::macro_rules {
1543 let label_span = ident.span.shrink_to_hi();
1544 let mut spans = MultiSpan::from_span(label_span);
1545 spans.push_span_label(label_span, "put a macro name here");
1546 err.subdiagnostic(MaybeMissingMacroRulesName { spans });
1547 return;
1548 }
1549
1550 if macro_kind == MacroKind::Derive && (ident.name == sym::Send || ident.name == sym::Sync) {
1551 err.subdiagnostic(ExplicitUnsafeTraits { span: ident.span, ident });
1552 return;
1553 }
1554
1555 let unused_macro = self.unused_macros.iter().find_map(|(def_id, (_, unused_ident))| {
1556 if unused_ident.name == ident.name { Some((def_id, unused_ident)) } else { None }
1557 });
1558
1559 if let Some((def_id, unused_ident)) = unused_macro {
1560 let scope = self.local_macro_def_scopes[&def_id];
1561 let parent_nearest = parent_scope.module.nearest_parent_mod();
1562 if Some(parent_nearest) == scope.opt_def_id() {
1563 match macro_kind {
1564 MacroKind::Bang => {
1565 err.subdiagnostic(MacroDefinedLater { span: unused_ident.span });
1566 err.subdiagnostic(MacroSuggMovePosition { span: ident.span, ident });
1567 }
1568 MacroKind::Attr => {
1569 err.subdiagnostic(MacroRulesNot::Attr { span: unused_ident.span, ident });
1570 }
1571 MacroKind::Derive => {
1572 err.subdiagnostic(MacroRulesNot::Derive { span: unused_ident.span, ident });
1573 }
1574 }
1575
1576 return;
1577 }
1578 }
1579
1580 if self.macro_names.contains(&ident.normalize_to_macros_2_0()) {
1581 err.subdiagnostic(AddedMacroUse);
1582 return;
1583 }
1584
1585 if ident.name == kw::Default
1586 && let ModuleKind::Def(DefKind::Enum, def_id, _) = parent_scope.module.kind
1587 {
1588 let span = self.def_span(def_id);
1589 let source_map = self.tcx.sess.source_map();
1590 let head_span = source_map.guess_head_span(span);
1591 err.subdiagnostic(ConsiderAddingADerive {
1592 span: head_span.shrink_to_lo(),
1593 suggestion: "#[derive(Default)]\n".to_string(),
1594 });
1595 }
1596 for ns in [Namespace::MacroNS, Namespace::TypeNS, Namespace::ValueNS] {
1597 let Ok(binding) = self.early_resolve_ident_in_lexical_scope(
1598 ident,
1599 ScopeSet::All(ns),
1600 parent_scope,
1601 None,
1602 false,
1603 None,
1604 None,
1605 ) else {
1606 continue;
1607 };
1608
1609 let desc = match binding.res() {
1610 Res::Def(DefKind::Macro(MacroKind::Bang), _) => "a function-like macro".to_string(),
1611 Res::Def(DefKind::Macro(MacroKind::Attr), _) | Res::NonMacroAttr(..) => {
1612 format!("an attribute: `#[{ident}]`")
1613 }
1614 Res::Def(DefKind::Macro(MacroKind::Derive), _) => {
1615 format!("a derive macro: `#[derive({ident})]`")
1616 }
1617 Res::ToolMod => {
1618 continue;
1620 }
1621 Res::Def(DefKind::Trait, _) if macro_kind == MacroKind::Derive => {
1622 "only a trait, without a derive macro".to_string()
1623 }
1624 res => format!(
1625 "{} {}, not {} {}",
1626 res.article(),
1627 res.descr(),
1628 macro_kind.article(),
1629 macro_kind.descr_expected(),
1630 ),
1631 };
1632 if let crate::NameBindingKind::Import { import, .. } = binding.kind
1633 && !import.span.is_dummy()
1634 {
1635 let note = errors::IdentImporterHereButItIsDesc {
1636 span: import.span,
1637 imported_ident: ident,
1638 imported_ident_desc: &desc,
1639 };
1640 err.subdiagnostic(note);
1641 self.record_use(ident, binding, Used::Other);
1644 return;
1645 }
1646 let note = errors::IdentInScopeButItIsDesc {
1647 imported_ident: ident,
1648 imported_ident_desc: &desc,
1649 };
1650 err.subdiagnostic(note);
1651 return;
1652 }
1653 }
1654
1655 fn detect_derive_attribute(
1658 &self,
1659 err: &mut Diag<'_>,
1660 ident: Ident,
1661 parent_scope: &ParentScope<'ra>,
1662 sugg_span: Option<Span>,
1663 ) {
1664 let mut derives = vec![];
1669 let mut all_attrs: UnordMap<Symbol, Vec<_>> = UnordMap::default();
1670 #[allow(rustc::potential_query_instability)]
1672 for (def_id, data) in &self.macro_map {
1673 for helper_attr in &data.ext.helper_attrs {
1674 let item_name = self.tcx.item_name(*def_id);
1675 all_attrs.entry(*helper_attr).or_default().push(item_name);
1676 if helper_attr == &ident.name {
1677 derives.push(item_name);
1678 }
1679 }
1680 }
1681 let kind = MacroKind::Derive.descr();
1682 if !derives.is_empty() {
1683 let mut derives: Vec<String> = derives.into_iter().map(|d| d.to_string()).collect();
1685 derives.sort();
1686 derives.dedup();
1687 let msg = match &derives[..] {
1688 [derive] => format!(" `{derive}`"),
1689 [start @ .., last] => format!(
1690 "s {} and `{last}`",
1691 start.iter().map(|d| format!("`{d}`")).collect::<Vec<_>>().join(", ")
1692 ),
1693 [] => unreachable!("we checked for this to be non-empty 10 lines above!?"),
1694 };
1695 let msg = format!(
1696 "`{}` is an attribute that can be used by the {kind}{msg}, you might be \
1697 missing a `derive` attribute",
1698 ident.name,
1699 );
1700 let sugg_span = if let ModuleKind::Def(DefKind::Enum, id, _) = parent_scope.module.kind
1701 {
1702 let span = self.def_span(id);
1703 if span.from_expansion() {
1704 None
1705 } else {
1706 Some(span.shrink_to_lo())
1708 }
1709 } else {
1710 sugg_span
1712 };
1713 match sugg_span {
1714 Some(span) => {
1715 err.span_suggestion_verbose(
1716 span,
1717 msg,
1718 format!("#[derive({})]\n", derives.join(", ")),
1719 Applicability::MaybeIncorrect,
1720 );
1721 }
1722 None => {
1723 err.note(msg);
1724 }
1725 }
1726 } else {
1727 let all_attr_names = all_attrs.keys().map(|s| *s).into_sorted_stable_ord();
1729 if let Some(best_match) = find_best_match_for_name(&all_attr_names, ident.name, None)
1730 && let Some(macros) = all_attrs.get(&best_match)
1731 {
1732 let mut macros: Vec<String> = macros.into_iter().map(|d| d.to_string()).collect();
1733 macros.sort();
1734 macros.dedup();
1735 let msg = match ¯os[..] {
1736 [] => return,
1737 [name] => format!(" `{name}` accepts"),
1738 [start @ .., end] => format!(
1739 "s {} and `{end}` accept",
1740 start.iter().map(|m| format!("`{m}`")).collect::<Vec<_>>().join(", "),
1741 ),
1742 };
1743 let msg = format!("the {kind}{msg} the similarly named `{best_match}` attribute");
1744 err.span_suggestion_verbose(
1745 ident.span,
1746 msg,
1747 best_match,
1748 Applicability::MaybeIncorrect,
1749 );
1750 }
1751 }
1752 }
1753
1754 pub(crate) fn add_typo_suggestion(
1755 &self,
1756 err: &mut Diag<'_>,
1757 suggestion: Option<TypoSuggestion>,
1758 span: Span,
1759 ) -> bool {
1760 let suggestion = match suggestion {
1761 None => return false,
1762 Some(suggestion) if suggestion.candidate == kw::Underscore => return false,
1764 Some(suggestion) => suggestion,
1765 };
1766
1767 let mut did_label_def_span = false;
1768
1769 if let Some(def_span) = suggestion.res.opt_def_id().map(|def_id| self.def_span(def_id)) {
1770 if span.overlaps(def_span) {
1771 return false;
1790 }
1791 let span = self.tcx.sess.source_map().guess_head_span(def_span);
1792 let candidate_descr = suggestion.res.descr();
1793 let candidate = suggestion.candidate;
1794 let label = match suggestion.target {
1795 SuggestionTarget::SimilarlyNamed => {
1796 errors::DefinedHere::SimilarlyNamed { span, candidate_descr, candidate }
1797 }
1798 SuggestionTarget::SingleItem => {
1799 errors::DefinedHere::SingleItem { span, candidate_descr, candidate }
1800 }
1801 };
1802 did_label_def_span = true;
1803 err.subdiagnostic(label);
1804 }
1805
1806 let (span, msg, sugg) = if let SuggestionTarget::SimilarlyNamed = suggestion.target
1807 && let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span)
1808 && let Some(span) = suggestion.span
1809 && let Some(candidate) = suggestion.candidate.as_str().strip_prefix('_')
1810 && snippet == candidate
1811 {
1812 let candidate = suggestion.candidate;
1813 let msg = format!(
1816 "the leading underscore in `{candidate}` marks it as unused, consider renaming it to `{snippet}`"
1817 );
1818 if !did_label_def_span {
1819 err.span_label(span, format!("`{candidate}` defined here"));
1820 }
1821 (span, msg, snippet)
1822 } else {
1823 let msg = match suggestion.target {
1824 SuggestionTarget::SimilarlyNamed => format!(
1825 "{} {} with a similar name exists",
1826 suggestion.res.article(),
1827 suggestion.res.descr()
1828 ),
1829 SuggestionTarget::SingleItem => {
1830 format!("maybe you meant this {}", suggestion.res.descr())
1831 }
1832 };
1833 (span, msg, suggestion.candidate.to_ident_string())
1834 };
1835 err.span_suggestion(span, msg, sugg, Applicability::MaybeIncorrect);
1836 true
1837 }
1838
1839 fn binding_description(&self, b: NameBinding<'_>, ident: Ident, from_prelude: bool) -> String {
1840 let res = b.res();
1841 if b.span.is_dummy() || !self.tcx.sess.source_map().is_span_accessible(b.span) {
1842 let add_built_in =
1844 !matches!(b.res(), Res::NonMacroAttr(..) | Res::PrimTy(..) | Res::ToolMod);
1845 let (built_in, from) = if from_prelude {
1846 ("", " from prelude")
1847 } else if b.is_extern_crate()
1848 && !b.is_import()
1849 && self.tcx.sess.opts.externs.get(ident.as_str()).is_some()
1850 {
1851 ("", " passed with `--extern`")
1852 } else if add_built_in {
1853 (" built-in", "")
1854 } else {
1855 ("", "")
1856 };
1857
1858 let a = if built_in.is_empty() { res.article() } else { "a" };
1859 format!("{a}{built_in} {thing}{from}", thing = res.descr())
1860 } else {
1861 let introduced = if b.is_import_user_facing() { "imported" } else { "defined" };
1862 format!("the {thing} {introduced} here", thing = res.descr())
1863 }
1864 }
1865
1866 fn ambiguity_diagnostics(&self, ambiguity_error: &AmbiguityError<'_>) -> AmbiguityErrorDiag {
1867 let AmbiguityError { kind, ident, b1, b2, misc1, misc2, .. } = *ambiguity_error;
1868 let (b1, b2, misc1, misc2, swapped) = if b2.span.is_dummy() && !b1.span.is_dummy() {
1869 (b2, b1, misc2, misc1, true)
1871 } else {
1872 (b1, b2, misc1, misc2, false)
1873 };
1874 let could_refer_to = |b: NameBinding<'_>, misc: AmbiguityErrorMisc, also: &str| {
1875 let what = self.binding_description(b, ident, misc == AmbiguityErrorMisc::FromPrelude);
1876 let note_msg = format!("`{ident}` could{also} refer to {what}");
1877
1878 let thing = b.res().descr();
1879 let mut help_msgs = Vec::new();
1880 if b.is_glob_import()
1881 && (kind == AmbiguityKind::GlobVsGlob
1882 || kind == AmbiguityKind::GlobVsExpanded
1883 || kind == AmbiguityKind::GlobVsOuter && swapped != also.is_empty())
1884 {
1885 help_msgs.push(format!(
1886 "consider adding an explicit import of `{ident}` to disambiguate"
1887 ))
1888 }
1889 if b.is_extern_crate() && ident.span.at_least_rust_2018() {
1890 help_msgs.push(format!("use `::{ident}` to refer to this {thing} unambiguously"))
1891 }
1892 match misc {
1893 AmbiguityErrorMisc::SuggestCrate => help_msgs
1894 .push(format!("use `crate::{ident}` to refer to this {thing} unambiguously")),
1895 AmbiguityErrorMisc::SuggestSelf => help_msgs
1896 .push(format!("use `self::{ident}` to refer to this {thing} unambiguously")),
1897 AmbiguityErrorMisc::FromPrelude | AmbiguityErrorMisc::None => {}
1898 }
1899
1900 (
1901 b.span,
1902 note_msg,
1903 help_msgs
1904 .iter()
1905 .enumerate()
1906 .map(|(i, help_msg)| {
1907 let or = if i == 0 { "" } else { "or " };
1908 format!("{or}{help_msg}")
1909 })
1910 .collect::<Vec<_>>(),
1911 )
1912 };
1913 let (b1_span, b1_note_msg, b1_help_msgs) = could_refer_to(b1, misc1, "");
1914 let (b2_span, b2_note_msg, b2_help_msgs) = could_refer_to(b2, misc2, " also");
1915
1916 AmbiguityErrorDiag {
1917 msg: format!("`{ident}` is ambiguous"),
1918 span: ident.span,
1919 label_span: ident.span,
1920 label_msg: "ambiguous name".to_string(),
1921 note_msg: format!("ambiguous because of {}", kind.descr()),
1922 b1_span,
1923 b1_note_msg,
1924 b1_help_msgs,
1925 b2_span,
1926 b2_note_msg,
1927 b2_help_msgs,
1928 }
1929 }
1930
1931 fn ctor_fields_span(&self, binding: NameBinding<'_>) -> Option<Span> {
1934 let NameBindingKind::Res(Res::Def(
1935 DefKind::Ctor(CtorOf::Struct, CtorKind::Fn),
1936 ctor_def_id,
1937 )) = binding.kind
1938 else {
1939 return None;
1940 };
1941
1942 let def_id = self.tcx.parent(ctor_def_id);
1943 self.field_idents(def_id)?.iter().map(|&f| f.span).reduce(Span::to) }
1945
1946 fn report_privacy_error(&mut self, privacy_error: &PrivacyError<'ra>) {
1947 let PrivacyError { ident, binding, outermost_res, parent_scope, single_nested, dedup_span } =
1948 *privacy_error;
1949
1950 let res = binding.res();
1951 let ctor_fields_span = self.ctor_fields_span(binding);
1952 let plain_descr = res.descr().to_string();
1953 let nonimport_descr =
1954 if ctor_fields_span.is_some() { plain_descr + " constructor" } else { plain_descr };
1955 let import_descr = nonimport_descr.clone() + " import";
1956 let get_descr =
1957 |b: NameBinding<'_>| if b.is_import() { &import_descr } else { &nonimport_descr };
1958
1959 let ident_descr = get_descr(binding);
1961 let mut err =
1962 self.dcx().create_err(errors::IsPrivate { span: ident.span, ident_descr, ident });
1963
1964 let mut not_publicly_reexported = false;
1965 if let Some((this_res, outer_ident)) = outermost_res {
1966 let import_suggestions = self.lookup_import_candidates(
1967 outer_ident,
1968 this_res.ns().unwrap_or(Namespace::TypeNS),
1969 &parent_scope,
1970 &|res: Res| res == this_res,
1971 );
1972 let point_to_def = !show_candidates(
1973 self.tcx,
1974 &mut err,
1975 Some(dedup_span.until(outer_ident.span.shrink_to_hi())),
1976 &import_suggestions,
1977 Instead::Yes,
1978 FoundUse::Yes,
1979 DiagMode::Import { append: single_nested, unresolved_import: false },
1980 vec![],
1981 "",
1982 );
1983 if point_to_def && ident.span != outer_ident.span {
1985 not_publicly_reexported = true;
1986 let label = errors::OuterIdentIsNotPubliclyReexported {
1987 span: outer_ident.span,
1988 outer_ident_descr: this_res.descr(),
1989 outer_ident,
1990 };
1991 err.subdiagnostic(label);
1992 }
1993 }
1994
1995 let mut non_exhaustive = None;
1996 if let Some(def_id) = res.opt_def_id()
2000 && !def_id.is_local()
2001 && let Some(attr) = self.tcx.get_attr(def_id, sym::non_exhaustive)
2002 {
2003 non_exhaustive = Some(attr.span());
2004 } else if let Some(span) = ctor_fields_span {
2005 let label = errors::ConstructorPrivateIfAnyFieldPrivate { span };
2006 err.subdiagnostic(label);
2007 if let Res::Def(_, d) = res
2008 && let Some(fields) = self.field_visibility_spans.get(&d)
2009 {
2010 let spans = fields.iter().map(|span| *span).collect();
2011 let sugg =
2012 errors::ConsiderMakingTheFieldPublic { spans, number_of_fields: fields.len() };
2013 err.subdiagnostic(sugg);
2014 }
2015 }
2016
2017 let mut sugg_paths = vec![];
2018 if let Some(mut def_id) = res.opt_def_id() {
2019 let mut path = vec![def_id];
2021 while let Some(parent) = self.tcx.opt_parent(def_id) {
2022 def_id = parent;
2023 if !def_id.is_top_level_module() {
2024 path.push(def_id);
2025 } else {
2026 break;
2027 }
2028 }
2029 let path_names: Option<Vec<String>> = path
2031 .iter()
2032 .rev()
2033 .map(|def_id| {
2034 self.tcx.opt_item_name(*def_id).map(|n| {
2035 if def_id.is_top_level_module() {
2036 "crate".to_string()
2037 } else {
2038 n.to_string()
2039 }
2040 })
2041 })
2042 .collect();
2043 if let Some(def_id) = path.get(0)
2044 && let Some(path) = path_names
2045 {
2046 if let Some(def_id) = def_id.as_local() {
2047 if self.effective_visibilities.is_directly_public(def_id) {
2048 sugg_paths.push((path, false));
2049 }
2050 } else if self.is_accessible_from(self.tcx.visibility(def_id), parent_scope.module)
2051 {
2052 sugg_paths.push((path, false));
2053 }
2054 }
2055 }
2056
2057 let first_binding = binding;
2059 let mut next_binding = Some(binding);
2060 let mut next_ident = ident;
2061 let mut path = vec![];
2062 while let Some(binding) = next_binding {
2063 let name = next_ident;
2064 next_binding = match binding.kind {
2065 _ if res == Res::Err => None,
2066 NameBindingKind::Import { binding, import, .. } => match import.kind {
2067 _ if binding.span.is_dummy() => None,
2068 ImportKind::Single { source, .. } => {
2069 next_ident = source;
2070 Some(binding)
2071 }
2072 ImportKind::Glob { .. }
2073 | ImportKind::MacroUse { .. }
2074 | ImportKind::MacroExport => Some(binding),
2075 ImportKind::ExternCrate { .. } => None,
2076 },
2077 _ => None,
2078 };
2079
2080 match binding.kind {
2081 NameBindingKind::Import { import, .. } => {
2082 for segment in import.module_path.iter().skip(1) {
2083 path.push(segment.ident.to_string());
2084 }
2085 sugg_paths.push((
2086 path.iter()
2087 .cloned()
2088 .chain(vec![ident.to_string()].into_iter())
2089 .collect::<Vec<_>>(),
2090 true, ));
2092 }
2093 NameBindingKind::Res(_) | NameBindingKind::Module(_) => {}
2094 }
2095 let first = binding == first_binding;
2096 let def_span = self.tcx.sess.source_map().guess_head_span(binding.span);
2097 let mut note_span = MultiSpan::from_span(def_span);
2098 if !first && binding.vis.is_public() {
2099 let desc = match binding.kind {
2100 NameBindingKind::Import { .. } => "re-export",
2101 _ => "directly",
2102 };
2103 note_span.push_span_label(def_span, format!("you could import this {desc}"));
2104 }
2105 if next_binding.is_none()
2108 && let Some(span) = non_exhaustive
2109 {
2110 note_span.push_span_label(
2111 span,
2112 "cannot be constructed because it is `#[non_exhaustive]`",
2113 );
2114 }
2115 let note = errors::NoteAndRefersToTheItemDefinedHere {
2116 span: note_span,
2117 binding_descr: get_descr(binding),
2118 binding_name: name,
2119 first,
2120 dots: next_binding.is_some(),
2121 };
2122 err.subdiagnostic(note);
2123 }
2124 sugg_paths.sort_by_key(|(p, reexport)| (p.len(), p[0] == "core", *reexport));
2126 for (sugg, reexport) in sugg_paths {
2127 if not_publicly_reexported {
2128 break;
2129 }
2130 if sugg.len() <= 1 {
2131 continue;
2134 }
2135 let path = sugg.join("::");
2136 let sugg = if reexport {
2137 errors::ImportIdent::ThroughReExport { span: dedup_span, ident, path }
2138 } else {
2139 errors::ImportIdent::Directly { span: dedup_span, ident, path }
2140 };
2141 err.subdiagnostic(sugg);
2142 break;
2143 }
2144
2145 err.emit();
2146 }
2147
2148 pub(crate) fn find_similarly_named_module_or_crate(
2149 &mut self,
2150 ident: Symbol,
2151 current_module: Module<'ra>,
2152 ) -> Option<Symbol> {
2153 let mut candidates = self
2154 .extern_prelude
2155 .keys()
2156 .map(|ident| ident.name)
2157 .chain(
2158 self.module_map
2159 .iter()
2160 .filter(|(_, module)| {
2161 current_module.is_ancestor_of(**module) && current_module != **module
2162 })
2163 .flat_map(|(_, module)| module.kind.name()),
2164 )
2165 .filter(|c| !c.to_string().is_empty())
2166 .collect::<Vec<_>>();
2167 candidates.sort();
2168 candidates.dedup();
2169 find_best_match_for_name(&candidates, ident, None).filter(|sugg| *sugg != ident)
2170 }
2171
2172 pub(crate) fn report_path_resolution_error(
2173 &mut self,
2174 path: &[Segment],
2175 opt_ns: Option<Namespace>, parent_scope: &ParentScope<'ra>,
2177 ribs: Option<&PerNS<Vec<Rib<'ra>>>>,
2178 ignore_binding: Option<NameBinding<'ra>>,
2179 ignore_import: Option<Import<'ra>>,
2180 module: Option<ModuleOrUniformRoot<'ra>>,
2181 failed_segment_idx: usize,
2182 ident: Ident,
2183 ) -> (String, Option<Suggestion>) {
2184 let is_last = failed_segment_idx == path.len() - 1;
2185 let ns = if is_last { opt_ns.unwrap_or(TypeNS) } else { TypeNS };
2186 let module_res = match module {
2187 Some(ModuleOrUniformRoot::Module(module)) => module.res(),
2188 _ => None,
2189 };
2190 if module_res == self.graph_root.res() {
2191 let is_mod = |res| matches!(res, Res::Def(DefKind::Mod, _));
2192 let mut candidates = self.lookup_import_candidates(ident, TypeNS, parent_scope, is_mod);
2193 candidates
2194 .sort_by_cached_key(|c| (c.path.segments.len(), pprust::path_to_string(&c.path)));
2195 if let Some(candidate) = candidates.get(0) {
2196 let path = {
2197 let len = candidate.path.segments.len();
2199 let start_index = (0..=failed_segment_idx.min(len - 1))
2200 .find(|&i| path[i].ident.name != candidate.path.segments[i].ident.name)
2201 .unwrap_or_default();
2202 let segments =
2203 (start_index..len).map(|s| candidate.path.segments[s].clone()).collect();
2204 Path { segments, span: Span::default(), tokens: None }
2205 };
2206 (
2207 String::from("unresolved import"),
2208 Some((
2209 vec![(ident.span, pprust::path_to_string(&path))],
2210 String::from("a similar path exists"),
2211 Applicability::MaybeIncorrect,
2212 )),
2213 )
2214 } else if ident.name == sym::core {
2215 (
2216 format!("you might be missing crate `{ident}`"),
2217 Some((
2218 vec![(ident.span, "std".to_string())],
2219 "try using `std` instead of `core`".to_string(),
2220 Applicability::MaybeIncorrect,
2221 )),
2222 )
2223 } else if ident.name == kw::Underscore {
2224 (format!("`_` is not a valid crate or module name"), None)
2225 } else if self.tcx.sess.is_rust_2015() {
2226 (
2227 format!("use of unresolved module or unlinked crate `{ident}`"),
2228 Some((
2229 vec![(
2230 self.current_crate_outer_attr_insert_span,
2231 format!("extern crate {ident};\n"),
2232 )],
2233 if was_invoked_from_cargo() {
2234 format!(
2235 "if you wanted to use a crate named `{ident}`, use `cargo add {ident}` \
2236 to add it to your `Cargo.toml` and import it in your code",
2237 )
2238 } else {
2239 format!(
2240 "you might be missing a crate named `{ident}`, add it to your \
2241 project and import it in your code",
2242 )
2243 },
2244 Applicability::MaybeIncorrect,
2245 )),
2246 )
2247 } else {
2248 (format!("could not find `{ident}` in the crate root"), None)
2249 }
2250 } else if failed_segment_idx > 0 {
2251 let parent = path[failed_segment_idx - 1].ident.name;
2252 let parent = match parent {
2253 kw::PathRoot if self.tcx.sess.edition() > Edition::Edition2015 => {
2256 "the list of imported crates".to_owned()
2257 }
2258 kw::PathRoot | kw::Crate => "the crate root".to_owned(),
2259 _ => format!("`{parent}`"),
2260 };
2261
2262 let mut msg = format!("could not find `{ident}` in {parent}");
2263 if ns == TypeNS || ns == ValueNS {
2264 let ns_to_try = if ns == TypeNS { ValueNS } else { TypeNS };
2265 let binding = if let Some(module) = module {
2266 self.resolve_ident_in_module(
2267 module,
2268 ident,
2269 ns_to_try,
2270 parent_scope,
2271 None,
2272 ignore_binding,
2273 ignore_import,
2274 )
2275 .ok()
2276 } else if let Some(ribs) = ribs
2277 && let Some(TypeNS | ValueNS) = opt_ns
2278 {
2279 assert!(ignore_import.is_none());
2280 match self.resolve_ident_in_lexical_scope(
2281 ident,
2282 ns_to_try,
2283 parent_scope,
2284 None,
2285 &ribs[ns_to_try],
2286 ignore_binding,
2287 ) {
2288 Some(LexicalScopeBinding::Item(binding)) => Some(binding),
2290 _ => None,
2291 }
2292 } else {
2293 self.early_resolve_ident_in_lexical_scope(
2294 ident,
2295 ScopeSet::All(ns_to_try),
2296 parent_scope,
2297 None,
2298 false,
2299 ignore_binding,
2300 ignore_import,
2301 )
2302 .ok()
2303 };
2304 if let Some(binding) = binding {
2305 let mut found = |what| {
2306 msg = format!(
2307 "expected {}, found {} `{}` in {}",
2308 ns.descr(),
2309 what,
2310 ident,
2311 parent
2312 )
2313 };
2314 if binding.module().is_some() {
2315 found("module")
2316 } else {
2317 match binding.res() {
2318 Res::Def(kind, id) => found(kind.descr(id)),
2321 _ => found(ns_to_try.descr()),
2322 }
2323 }
2324 };
2325 }
2326 (msg, None)
2327 } else if ident.name == kw::SelfUpper {
2328 if opt_ns.is_none() {
2332 ("`Self` cannot be used in imports".to_string(), None)
2333 } else {
2334 (
2335 "`Self` is only available in impls, traits, and type definitions".to_string(),
2336 None,
2337 )
2338 }
2339 } else if ident.name.as_str().chars().next().is_some_and(|c| c.is_ascii_uppercase()) {
2340 let binding = if let Some(ribs) = ribs {
2342 assert!(ignore_import.is_none());
2343 self.resolve_ident_in_lexical_scope(
2344 ident,
2345 ValueNS,
2346 parent_scope,
2347 None,
2348 &ribs[ValueNS],
2349 ignore_binding,
2350 )
2351 } else {
2352 None
2353 };
2354 let match_span = match binding {
2355 Some(LexicalScopeBinding::Res(Res::Local(id))) => {
2364 Some(*self.pat_span_map.get(&id).unwrap())
2365 }
2366 Some(LexicalScopeBinding::Item(name_binding)) => Some(name_binding.span),
2378 _ => None,
2379 };
2380 let suggestion = match_span.map(|span| {
2381 (
2382 vec![(span, String::from(""))],
2383 format!("`{ident}` is defined here, but is not a type"),
2384 Applicability::MaybeIncorrect,
2385 )
2386 });
2387
2388 (format!("use of undeclared type `{ident}`"), suggestion)
2389 } else {
2390 let mut suggestion = None;
2391 if ident.name == sym::alloc {
2392 suggestion = Some((
2393 vec![],
2394 String::from("add `extern crate alloc` to use the `alloc` crate"),
2395 Applicability::MaybeIncorrect,
2396 ))
2397 }
2398
2399 suggestion = suggestion.or_else(|| {
2400 self.find_similarly_named_module_or_crate(ident.name, parent_scope.module).map(
2401 |sugg| {
2402 (
2403 vec![(ident.span, sugg.to_string())],
2404 String::from("there is a crate or module with a similar name"),
2405 Applicability::MaybeIncorrect,
2406 )
2407 },
2408 )
2409 });
2410 if let Ok(binding) = self.early_resolve_ident_in_lexical_scope(
2411 ident,
2412 ScopeSet::All(ValueNS),
2413 parent_scope,
2414 None,
2415 false,
2416 ignore_binding,
2417 ignore_import,
2418 ) {
2419 let descr = binding.res().descr();
2420 (format!("{descr} `{ident}` is not a crate or module"), suggestion)
2421 } else {
2422 let suggestion = if suggestion.is_some() {
2423 suggestion
2424 } else if let Some(m) = self.undeclared_module_exists(ident) {
2425 self.undeclared_module_suggest_declare(ident, m)
2426 } else if was_invoked_from_cargo() {
2427 Some((
2428 vec![],
2429 format!(
2430 "if you wanted to use a crate named `{ident}`, use `cargo add {ident}` \
2431 to add it to your `Cargo.toml`",
2432 ),
2433 Applicability::MaybeIncorrect,
2434 ))
2435 } else {
2436 Some((
2437 vec![],
2438 format!("you might be missing a crate named `{ident}`",),
2439 Applicability::MaybeIncorrect,
2440 ))
2441 };
2442 (format!("use of unresolved module or unlinked crate `{ident}`"), suggestion)
2443 }
2444 }
2445 }
2446
2447 fn undeclared_module_suggest_declare(
2448 &mut self,
2449 ident: Ident,
2450 path: std::path::PathBuf,
2451 ) -> Option<(Vec<(Span, String)>, String, Applicability)> {
2452 Some((
2453 vec![(self.current_crate_outer_attr_insert_span, format!("mod {ident};\n"))],
2454 format!(
2455 "to make use of source file {}, use `mod {ident}` \
2456 in this file to declare the module",
2457 path.display()
2458 ),
2459 Applicability::MaybeIncorrect,
2460 ))
2461 }
2462
2463 fn undeclared_module_exists(&mut self, ident: Ident) -> Option<std::path::PathBuf> {
2464 let map = self.tcx.sess.source_map();
2465
2466 let src = map.span_to_filename(ident.span).into_local_path()?;
2467 let i = ident.as_str();
2468 let dir = src.parent()?;
2470 let src = src.file_stem()?.to_str()?;
2471 for file in [
2472 dir.join(i).with_extension("rs"),
2474 dir.join(i).join("mod.rs"),
2476 ] {
2477 if file.exists() {
2478 return Some(file);
2479 }
2480 }
2481 if !matches!(src, "main" | "lib" | "mod") {
2482 for file in [
2483 dir.join(src).join(i).with_extension("rs"),
2485 dir.join(src).join(i).join("mod.rs"),
2487 ] {
2488 if file.exists() {
2489 return Some(file);
2490 }
2491 }
2492 }
2493 None
2494 }
2495
2496 #[instrument(level = "debug", skip(self, parent_scope))]
2498 pub(crate) fn make_path_suggestion(
2499 &mut self,
2500 mut path: Vec<Segment>,
2501 parent_scope: &ParentScope<'ra>,
2502 ) -> Option<(Vec<Segment>, Option<String>)> {
2503 match path[..] {
2504 [first, second, ..]
2507 if first.ident.name == kw::PathRoot && !second.ident.is_path_segment_keyword() => {}
2508 [first, ..]
2510 if first.ident.span.at_least_rust_2018()
2511 && !first.ident.is_path_segment_keyword() =>
2512 {
2513 path.insert(0, Segment::from_ident(Ident::dummy()));
2515 }
2516 _ => return None,
2517 }
2518
2519 self.make_missing_self_suggestion(path.clone(), parent_scope)
2520 .or_else(|| self.make_missing_crate_suggestion(path.clone(), parent_scope))
2521 .or_else(|| self.make_missing_super_suggestion(path.clone(), parent_scope))
2522 .or_else(|| self.make_external_crate_suggestion(path, parent_scope))
2523 }
2524
2525 #[instrument(level = "debug", skip(self, parent_scope))]
2533 fn make_missing_self_suggestion(
2534 &mut self,
2535 mut path: Vec<Segment>,
2536 parent_scope: &ParentScope<'ra>,
2537 ) -> Option<(Vec<Segment>, Option<String>)> {
2538 path[0].ident.name = kw::SelfLower;
2540 let result = self.maybe_resolve_path(&path, None, parent_scope, None);
2541 debug!(?path, ?result);
2542 if let PathResult::Module(..) = result { Some((path, None)) } else { None }
2543 }
2544
2545 #[instrument(level = "debug", skip(self, parent_scope))]
2553 fn make_missing_crate_suggestion(
2554 &mut self,
2555 mut path: Vec<Segment>,
2556 parent_scope: &ParentScope<'ra>,
2557 ) -> Option<(Vec<Segment>, Option<String>)> {
2558 path[0].ident.name = kw::Crate;
2560 let result = self.maybe_resolve_path(&path, None, parent_scope, None);
2561 debug!(?path, ?result);
2562 if let PathResult::Module(..) = result {
2563 Some((
2564 path,
2565 Some(
2566 "`use` statements changed in Rust 2018; read more at \
2567 <https://doc.rust-lang.org/edition-guide/rust-2018/module-system/path-\
2568 clarity.html>"
2569 .to_string(),
2570 ),
2571 ))
2572 } else {
2573 None
2574 }
2575 }
2576
2577 #[instrument(level = "debug", skip(self, parent_scope))]
2585 fn make_missing_super_suggestion(
2586 &mut self,
2587 mut path: Vec<Segment>,
2588 parent_scope: &ParentScope<'ra>,
2589 ) -> Option<(Vec<Segment>, Option<String>)> {
2590 path[0].ident.name = kw::Super;
2592 let result = self.maybe_resolve_path(&path, None, parent_scope, None);
2593 debug!(?path, ?result);
2594 if let PathResult::Module(..) = result { Some((path, None)) } else { None }
2595 }
2596
2597 #[instrument(level = "debug", skip(self, parent_scope))]
2608 fn make_external_crate_suggestion(
2609 &mut self,
2610 mut path: Vec<Segment>,
2611 parent_scope: &ParentScope<'ra>,
2612 ) -> Option<(Vec<Segment>, Option<String>)> {
2613 if path[1].ident.span.is_rust_2015() {
2614 return None;
2615 }
2616
2617 let mut extern_crate_names =
2621 self.extern_prelude.keys().map(|ident| ident.name).collect::<Vec<_>>();
2622 extern_crate_names.sort_by(|a, b| b.as_str().cmp(a.as_str()));
2623
2624 for name in extern_crate_names.into_iter() {
2625 path[0].ident.name = name;
2627 let result = self.maybe_resolve_path(&path, None, parent_scope, None);
2628 debug!(?path, ?name, ?result);
2629 if let PathResult::Module(..) = result {
2630 return Some((path, None));
2631 }
2632 }
2633
2634 None
2635 }
2636
2637 pub(crate) fn check_for_module_export_macro(
2650 &mut self,
2651 import: Import<'ra>,
2652 module: ModuleOrUniformRoot<'ra>,
2653 ident: Ident,
2654 ) -> Option<(Option<Suggestion>, Option<String>)> {
2655 let ModuleOrUniformRoot::Module(mut crate_module) = module else {
2656 return None;
2657 };
2658
2659 while let Some(parent) = crate_module.parent {
2660 crate_module = parent;
2661 }
2662
2663 if module == ModuleOrUniformRoot::Module(crate_module) {
2664 return None;
2666 }
2667
2668 let resolutions = self.resolutions(crate_module).borrow();
2669 let binding_key = BindingKey::new(ident, MacroNS);
2670 let resolution = resolutions.get(&binding_key)?;
2671 let binding = resolution.borrow().binding()?;
2672 let Res::Def(DefKind::Macro(MacroKind::Bang), _) = binding.res() else {
2673 return None;
2674 };
2675 let module_name = crate_module.kind.name().unwrap_or(kw::Crate);
2676 let import_snippet = match import.kind {
2677 ImportKind::Single { source, target, .. } if source != target => {
2678 format!("{source} as {target}")
2679 }
2680 _ => format!("{ident}"),
2681 };
2682
2683 let mut corrections: Vec<(Span, String)> = Vec::new();
2684 if !import.is_nested() {
2685 corrections.push((import.span, format!("{module_name}::{import_snippet}")));
2688 } else {
2689 let (found_closing_brace, binding_span) = find_span_of_binding_until_next_binding(
2693 self.tcx.sess,
2694 import.span,
2695 import.use_span,
2696 );
2697 debug!(found_closing_brace, ?binding_span);
2698
2699 let mut removal_span = binding_span;
2700
2701 if found_closing_brace
2709 && let Some(previous_span) =
2710 extend_span_to_previous_binding(self.tcx.sess, binding_span)
2711 {
2712 debug!(?previous_span);
2713 removal_span = removal_span.with_lo(previous_span.lo());
2714 }
2715 debug!(?removal_span);
2716
2717 corrections.push((removal_span, "".to_string()));
2719
2720 let (has_nested, after_crate_name) =
2727 find_span_immediately_after_crate_name(self.tcx.sess, import.use_span);
2728 debug!(has_nested, ?after_crate_name);
2729
2730 let source_map = self.tcx.sess.source_map();
2731
2732 let is_definitely_crate = import
2734 .module_path
2735 .first()
2736 .is_some_and(|f| f.ident.name != kw::SelfLower && f.ident.name != kw::Super);
2737
2738 let start_point = source_map.start_point(after_crate_name);
2740 if is_definitely_crate
2741 && let Ok(start_snippet) = source_map.span_to_snippet(start_point)
2742 {
2743 corrections.push((
2744 start_point,
2745 if has_nested {
2746 format!("{start_snippet}{import_snippet}, ")
2748 } else {
2749 format!("{{{import_snippet}, {start_snippet}")
2752 },
2753 ));
2754
2755 if !has_nested {
2757 corrections.push((source_map.end_point(after_crate_name), "};".to_string()));
2758 }
2759 } else {
2760 corrections.push((
2762 import.use_span.shrink_to_lo(),
2763 format!("use {module_name}::{import_snippet};\n"),
2764 ));
2765 }
2766 }
2767
2768 let suggestion = Some((
2769 corrections,
2770 String::from("a macro with this name exists at the root of the crate"),
2771 Applicability::MaybeIncorrect,
2772 ));
2773 Some((
2774 suggestion,
2775 Some(
2776 "this could be because a macro annotated with `#[macro_export]` will be exported \
2777 at the root of the crate instead of the module where it is defined"
2778 .to_string(),
2779 ),
2780 ))
2781 }
2782
2783 pub(crate) fn find_cfg_stripped(&self, err: &mut Diag<'_>, segment: &Symbol, module: DefId) {
2785 let local_items;
2786 let symbols = if module.is_local() {
2787 local_items = self
2788 .stripped_cfg_items
2789 .iter()
2790 .filter_map(|item| {
2791 let parent_module = self.opt_local_def_id(item.parent_module)?.to_def_id();
2792 Some(StrippedCfgItem {
2793 parent_module,
2794 ident: item.ident,
2795 cfg: item.cfg.clone(),
2796 })
2797 })
2798 .collect::<Vec<_>>();
2799 local_items.as_slice()
2800 } else {
2801 self.tcx.stripped_cfg_items(module.krate)
2802 };
2803
2804 for &StrippedCfgItem { parent_module, ident, ref cfg } in symbols {
2805 if ident.name != *segment {
2806 continue;
2807 }
2808
2809 fn comes_from_same_module_for_glob(
2810 r: &Resolver<'_, '_>,
2811 parent_module: DefId,
2812 module: DefId,
2813 visited: &mut FxHashMap<DefId, bool>,
2814 ) -> bool {
2815 if let Some(&cached) = visited.get(&parent_module) {
2816 return cached;
2820 }
2821 visited.insert(parent_module, false);
2822 let res = r.module_map.get(&parent_module).is_some_and(|m| {
2823 for importer in m.glob_importers.borrow().iter() {
2824 if let Some(next_parent_module) = importer.parent_scope.module.opt_def_id()
2825 {
2826 if next_parent_module == module
2827 || comes_from_same_module_for_glob(
2828 r,
2829 next_parent_module,
2830 module,
2831 visited,
2832 )
2833 {
2834 return true;
2835 }
2836 }
2837 }
2838 false
2839 });
2840 visited.insert(parent_module, res);
2841 res
2842 }
2843
2844 let comes_from_same_module = parent_module == module
2845 || comes_from_same_module_for_glob(
2846 self,
2847 parent_module,
2848 module,
2849 &mut Default::default(),
2850 );
2851 if !comes_from_same_module {
2852 continue;
2853 }
2854
2855 let note = errors::FoundItemConfigureOut { span: ident.span };
2856 err.subdiagnostic(note);
2857
2858 if let MetaItemKind::List(nested) = &cfg.kind
2859 && let MetaItemInner::MetaItem(meta_item) = &nested[0]
2860 && let MetaItemKind::NameValue(feature_name) = &meta_item.kind
2861 {
2862 let note = errors::ItemWasBehindFeature {
2863 feature: feature_name.symbol,
2864 span: meta_item.span,
2865 };
2866 err.subdiagnostic(note);
2867 } else {
2868 let note = errors::ItemWasCfgOut { span: cfg.span };
2869 err.subdiagnostic(note);
2870 }
2871 }
2872 }
2873}
2874
2875fn find_span_of_binding_until_next_binding(
2889 sess: &Session,
2890 binding_span: Span,
2891 use_span: Span,
2892) -> (bool, Span) {
2893 let source_map = sess.source_map();
2894
2895 let binding_until_end = binding_span.with_hi(use_span.hi());
2898
2899 let after_binding_until_end = binding_until_end.with_lo(binding_span.hi());
2902
2903 let mut found_closing_brace = false;
2910 let after_binding_until_next_binding =
2911 source_map.span_take_while(after_binding_until_end, |&ch| {
2912 if ch == '}' {
2913 found_closing_brace = true;
2914 }
2915 ch == ' ' || ch == ','
2916 });
2917
2918 let span = binding_span.with_hi(after_binding_until_next_binding.hi());
2923
2924 (found_closing_brace, span)
2925}
2926
2927fn extend_span_to_previous_binding(sess: &Session, binding_span: Span) -> Option<Span> {
2940 let source_map = sess.source_map();
2941
2942 let prev_source = source_map.span_to_prev_source(binding_span).ok()?;
2946
2947 let prev_comma = prev_source.rsplit(',').collect::<Vec<_>>();
2948 let prev_starting_brace = prev_source.rsplit('{').collect::<Vec<_>>();
2949 if prev_comma.len() <= 1 || prev_starting_brace.len() <= 1 {
2950 return None;
2951 }
2952
2953 let prev_comma = prev_comma.first().unwrap();
2954 let prev_starting_brace = prev_starting_brace.first().unwrap();
2955
2956 if prev_comma.len() > prev_starting_brace.len() {
2960 return None;
2961 }
2962
2963 Some(binding_span.with_lo(BytePos(
2964 binding_span.lo().0 - (prev_comma.as_bytes().len() as u32) - 1,
2967 )))
2968}
2969
2970#[instrument(level = "debug", skip(sess))]
2984fn find_span_immediately_after_crate_name(sess: &Session, use_span: Span) -> (bool, Span) {
2985 let source_map = sess.source_map();
2986
2987 let mut num_colons = 0;
2989 let until_second_colon = source_map.span_take_while(use_span, |c| {
2991 if *c == ':' {
2992 num_colons += 1;
2993 }
2994 !matches!(c, ':' if num_colons == 2)
2995 });
2996 let from_second_colon = use_span.with_lo(until_second_colon.hi() + BytePos(1));
2998
2999 let mut found_a_non_whitespace_character = false;
3000 let after_second_colon = source_map.span_take_while(from_second_colon, |c| {
3002 if found_a_non_whitespace_character {
3003 return false;
3004 }
3005 if !c.is_whitespace() {
3006 found_a_non_whitespace_character = true;
3007 }
3008 true
3009 });
3010
3011 let next_left_bracket = source_map.span_through_char(from_second_colon, '{');
3013
3014 (next_left_bracket == after_second_colon, from_second_colon)
3015}
3016
3017enum Instead {
3020 Yes,
3021 No,
3022}
3023
3024enum FoundUse {
3026 Yes,
3027 No,
3028}
3029
3030pub(crate) enum DiagMode {
3032 Normal,
3033 Pattern,
3035 Import {
3037 unresolved_import: bool,
3039 append: bool,
3042 },
3043}
3044
3045pub(crate) fn import_candidates(
3046 tcx: TyCtxt<'_>,
3047 err: &mut Diag<'_>,
3048 use_placement_span: Option<Span>,
3050 candidates: &[ImportSuggestion],
3051 mode: DiagMode,
3052 append: &str,
3053) {
3054 show_candidates(
3055 tcx,
3056 err,
3057 use_placement_span,
3058 candidates,
3059 Instead::Yes,
3060 FoundUse::Yes,
3061 mode,
3062 vec![],
3063 append,
3064 );
3065}
3066
3067type PathString<'a> = (String, &'a str, Option<Span>, &'a Option<String>, bool);
3068
3069fn show_candidates(
3074 tcx: TyCtxt<'_>,
3075 err: &mut Diag<'_>,
3076 use_placement_span: Option<Span>,
3078 candidates: &[ImportSuggestion],
3079 instead: Instead,
3080 found_use: FoundUse,
3081 mode: DiagMode,
3082 path: Vec<Segment>,
3083 append: &str,
3084) -> bool {
3085 if candidates.is_empty() {
3086 return false;
3087 }
3088
3089 let mut showed = false;
3090 let mut accessible_path_strings: Vec<PathString<'_>> = Vec::new();
3091 let mut inaccessible_path_strings: Vec<PathString<'_>> = Vec::new();
3092
3093 candidates.iter().for_each(|c| {
3094 if c.accessible {
3095 if c.doc_visible {
3097 accessible_path_strings.push((
3098 pprust::path_to_string(&c.path),
3099 c.descr,
3100 c.did.and_then(|did| Some(tcx.source_span(did.as_local()?))),
3101 &c.note,
3102 c.via_import,
3103 ))
3104 }
3105 } else {
3106 inaccessible_path_strings.push((
3107 pprust::path_to_string(&c.path),
3108 c.descr,
3109 c.did.and_then(|did| Some(tcx.source_span(did.as_local()?))),
3110 &c.note,
3111 c.via_import,
3112 ))
3113 }
3114 });
3115
3116 for path_strings in [&mut accessible_path_strings, &mut inaccessible_path_strings] {
3119 path_strings.sort_by(|a, b| a.0.cmp(&b.0));
3120 path_strings.dedup_by(|a, b| a.0 == b.0);
3121 let core_path_strings =
3122 path_strings.extract_if(.., |p| p.0.starts_with("core::")).collect::<Vec<_>>();
3123 let std_path_strings =
3124 path_strings.extract_if(.., |p| p.0.starts_with("std::")).collect::<Vec<_>>();
3125 let foreign_crate_path_strings =
3126 path_strings.extract_if(.., |p| !p.0.starts_with("crate::")).collect::<Vec<_>>();
3127
3128 if std_path_strings.len() == core_path_strings.len() {
3131 path_strings.extend(std_path_strings);
3133 } else {
3134 path_strings.extend(std_path_strings);
3135 path_strings.extend(core_path_strings);
3136 }
3137 path_strings.extend(foreign_crate_path_strings);
3139 }
3140
3141 if !accessible_path_strings.is_empty() {
3142 let (determiner, kind, s, name, through) =
3143 if let [(name, descr, _, _, via_import)] = &accessible_path_strings[..] {
3144 (
3145 "this",
3146 *descr,
3147 "",
3148 format!(" `{name}`"),
3149 if *via_import { " through its public re-export" } else { "" },
3150 )
3151 } else {
3152 let kinds = accessible_path_strings
3155 .iter()
3156 .map(|(_, descr, _, _, _)| *descr)
3157 .collect::<UnordSet<&str>>();
3158 let kind = if let Some(kind) = kinds.get_only() { kind } else { "item" };
3159 let s = if kind.ends_with('s') { "es" } else { "s" };
3160
3161 ("one of these", kind, s, String::new(), "")
3162 };
3163
3164 let instead = if let Instead::Yes = instead { " instead" } else { "" };
3165 let mut msg = if let DiagMode::Pattern = mode {
3166 format!(
3167 "if you meant to match on {kind}{s}{instead}{name}, use the full path in the \
3168 pattern",
3169 )
3170 } else {
3171 format!("consider importing {determiner} {kind}{s}{through}{instead}")
3172 };
3173
3174 for note in accessible_path_strings.iter().flat_map(|cand| cand.3.as_ref()) {
3175 err.note(note.clone());
3176 }
3177
3178 let append_candidates = |msg: &mut String, accessible_path_strings: Vec<PathString<'_>>| {
3179 msg.push(':');
3180
3181 for candidate in accessible_path_strings {
3182 msg.push('\n');
3183 msg.push_str(&candidate.0);
3184 }
3185 };
3186
3187 if let Some(span) = use_placement_span {
3188 let (add_use, trailing) = match mode {
3189 DiagMode::Pattern => {
3190 err.span_suggestions(
3191 span,
3192 msg,
3193 accessible_path_strings.into_iter().map(|a| a.0),
3194 Applicability::MaybeIncorrect,
3195 );
3196 return true;
3197 }
3198 DiagMode::Import { .. } => ("", ""),
3199 DiagMode::Normal => ("use ", ";\n"),
3200 };
3201 for candidate in &mut accessible_path_strings {
3202 let additional_newline = if let FoundUse::No = found_use
3205 && let DiagMode::Normal = mode
3206 {
3207 "\n"
3208 } else {
3209 ""
3210 };
3211 candidate.0 =
3212 format!("{add_use}{}{append}{trailing}{additional_newline}", candidate.0);
3213 }
3214
3215 match mode {
3216 DiagMode::Import { append: true, .. } => {
3217 append_candidates(&mut msg, accessible_path_strings);
3218 err.span_help(span, msg);
3219 }
3220 _ => {
3221 err.span_suggestions_with_style(
3222 span,
3223 msg,
3224 accessible_path_strings.into_iter().map(|a| a.0),
3225 Applicability::MaybeIncorrect,
3226 SuggestionStyle::ShowAlways,
3227 );
3228 }
3229 }
3230
3231 if let [first, .., last] = &path[..] {
3232 let sp = first.ident.span.until(last.ident.span);
3233 if sp.can_be_used_for_suggestions() && !sp.is_empty() {
3236 err.span_suggestion_verbose(
3237 sp,
3238 format!("if you import `{}`, refer to it directly", last.ident),
3239 "",
3240 Applicability::Unspecified,
3241 );
3242 }
3243 }
3244 } else {
3245 append_candidates(&mut msg, accessible_path_strings);
3246 err.help(msg);
3247 }
3248 showed = true;
3249 }
3250 if !inaccessible_path_strings.is_empty()
3251 && (!matches!(mode, DiagMode::Import { unresolved_import: false, .. }))
3252 {
3253 let prefix =
3254 if let DiagMode::Pattern = mode { "you might have meant to match on " } else { "" };
3255 if let [(name, descr, source_span, note, _)] = &inaccessible_path_strings[..] {
3256 let msg = format!(
3257 "{prefix}{descr} `{name}`{} exists but is inaccessible",
3258 if let DiagMode::Pattern = mode { ", which" } else { "" }
3259 );
3260
3261 if let Some(source_span) = source_span {
3262 let span = tcx.sess.source_map().guess_head_span(*source_span);
3263 let mut multi_span = MultiSpan::from_span(span);
3264 multi_span.push_span_label(span, "not accessible");
3265 err.span_note(multi_span, msg);
3266 } else {
3267 err.note(msg);
3268 }
3269 if let Some(note) = (*note).as_deref() {
3270 err.note(note.to_string());
3271 }
3272 } else {
3273 let (_, descr_first, _, _, _) = &inaccessible_path_strings[0];
3274 let descr = if inaccessible_path_strings
3275 .iter()
3276 .skip(1)
3277 .all(|(_, descr, _, _, _)| descr == descr_first)
3278 {
3279 descr_first
3280 } else {
3281 "item"
3282 };
3283 let plural_descr =
3284 if descr.ends_with('s') { format!("{descr}es") } else { format!("{descr}s") };
3285
3286 let mut msg = format!("{prefix}these {plural_descr} exist but are inaccessible");
3287 let mut has_colon = false;
3288
3289 let mut spans = Vec::new();
3290 for (name, _, source_span, _, _) in &inaccessible_path_strings {
3291 if let Some(source_span) = source_span {
3292 let span = tcx.sess.source_map().guess_head_span(*source_span);
3293 spans.push((name, span));
3294 } else {
3295 if !has_colon {
3296 msg.push(':');
3297 has_colon = true;
3298 }
3299 msg.push('\n');
3300 msg.push_str(name);
3301 }
3302 }
3303
3304 let mut multi_span = MultiSpan::from_spans(spans.iter().map(|(_, sp)| *sp).collect());
3305 for (name, span) in spans {
3306 multi_span.push_span_label(span, format!("`{name}`: not accessible"));
3307 }
3308
3309 for note in inaccessible_path_strings.iter().flat_map(|cand| cand.3.as_ref()) {
3310 err.note(note.clone());
3311 }
3312
3313 err.span_note(multi_span, msg);
3314 }
3315 showed = true;
3316 }
3317 showed
3318}
3319
3320#[derive(Debug)]
3321struct UsePlacementFinder {
3322 target_module: NodeId,
3323 first_legal_span: Option<Span>,
3324 first_use_span: Option<Span>,
3325}
3326
3327impl UsePlacementFinder {
3328 fn check(krate: &Crate, target_module: NodeId) -> (Option<Span>, FoundUse) {
3329 let mut finder =
3330 UsePlacementFinder { target_module, first_legal_span: None, first_use_span: None };
3331 finder.visit_crate(krate);
3332 if let Some(use_span) = finder.first_use_span {
3333 (Some(use_span), FoundUse::Yes)
3334 } else {
3335 (finder.first_legal_span, FoundUse::No)
3336 }
3337 }
3338}
3339
3340impl<'tcx> visit::Visitor<'tcx> for UsePlacementFinder {
3341 fn visit_crate(&mut self, c: &Crate) {
3342 if self.target_module == CRATE_NODE_ID {
3343 let inject = c.spans.inject_use_span;
3344 if is_span_suitable_for_use_injection(inject) {
3345 self.first_legal_span = Some(inject);
3346 }
3347 self.first_use_span = search_for_any_use_in_items(&c.items);
3348 } else {
3349 visit::walk_crate(self, c);
3350 }
3351 }
3352
3353 fn visit_item(&mut self, item: &'tcx ast::Item) {
3354 if self.target_module == item.id {
3355 if let ItemKind::Mod(_, _, ModKind::Loaded(items, _inline, mod_spans, _)) = &item.kind {
3356 let inject = mod_spans.inject_use_span;
3357 if is_span_suitable_for_use_injection(inject) {
3358 self.first_legal_span = Some(inject);
3359 }
3360 self.first_use_span = search_for_any_use_in_items(items);
3361 }
3362 } else {
3363 visit::walk_item(self, item);
3364 }
3365 }
3366}
3367
3368fn search_for_any_use_in_items(items: &[P<ast::Item>]) -> Option<Span> {
3369 for item in items {
3370 if let ItemKind::Use(..) = item.kind
3371 && is_span_suitable_for_use_injection(item.span)
3372 {
3373 let mut lo = item.span.lo();
3374 for attr in &item.attrs {
3375 if attr.span.eq_ctxt(item.span) {
3376 lo = std::cmp::min(lo, attr.span.lo());
3377 }
3378 }
3379 return Some(Span::new(lo, lo, item.span.ctxt(), item.span.parent()));
3380 }
3381 }
3382 None
3383}
3384
3385fn is_span_suitable_for_use_injection(s: Span) -> bool {
3386 !s.from_expansion()
3389}