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, name },
260 false => errors::NameDefinedMultipleTimeLabel::Redefined { span, name },
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 => errors::NameDefinedMultipleTimeOldBindingLabel::Import {
268 span,
269 name,
270 old_kind,
271 },
272 false => errors::NameDefinedMultipleTimeOldBindingLabel::Definition {
273 span,
274 name,
275 old_kind,
276 },
277 }
278 });
279
280 let mut err = self
281 .dcx()
282 .create_err(errors::NameDefinedMultipleTime {
283 span,
284 descr: ns.descr(),
285 container,
286 label,
287 old_binding_label,
288 })
289 .with_code(code);
290
291 use NameBindingKind::Import;
293 let can_suggest = |binding: NameBinding<'_>, import: self::Import<'_>| {
294 !binding.span.is_dummy()
295 && !matches!(import.kind, ImportKind::MacroUse { .. } | ImportKind::MacroExport)
296 };
297 let import = match (&new_binding.kind, &old_binding.kind) {
298 (Import { import: new, .. }, Import { import: old, .. })
301 if {
302 (new.has_attributes || old.has_attributes)
303 && can_suggest(old_binding, *old)
304 && can_suggest(new_binding, *new)
305 } =>
306 {
307 if old.has_attributes {
308 Some((*new, new_binding.span, true))
309 } else {
310 Some((*old, old_binding.span, true))
311 }
312 }
313 (Import { import, .. }, other) if can_suggest(new_binding, *import) => {
315 Some((*import, new_binding.span, other.is_import()))
316 }
317 (other, Import { import, .. }) if can_suggest(old_binding, *import) => {
318 Some((*import, old_binding.span, other.is_import()))
319 }
320 _ => None,
321 };
322
323 let duplicate = new_binding.res().opt_def_id() == old_binding.res().opt_def_id();
325 let has_dummy_span = new_binding.span.is_dummy() || old_binding.span.is_dummy();
326 let from_item =
327 self.extern_prelude.get(&ident).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: Option<Finalize>,
474 path: &[Segment],
475 second_binding: Option<NameBinding<'_>>,
476 ) {
477 let Some(Finalize { node_id, root_span, .. }) = finalize else {
478 return;
479 };
480
481 let first_name = match path.get(0) {
482 Some(seg) if seg.ident.span.is_rust_2015() && self.tcx.sess.is_rust_2015() => {
484 seg.ident.name
485 }
486 _ => return,
487 };
488
489 if first_name != kw::PathRoot {
492 return;
493 }
494
495 match path.get(1) {
496 Some(Segment { ident, .. }) if ident.name == kw::Crate => return,
498 Some(_) => {}
500 None => return,
504 }
505
506 if let Some(binding) = second_binding
510 && let NameBindingKind::Import { import, .. } = binding.kind
511 && let ImportKind::ExternCrate { source: None, .. } = import.kind
513 {
514 return;
515 }
516
517 let diag = BuiltinLintDiag::AbsPathWithModule(root_span);
518 self.lint_buffer.buffer_lint(
519 ABSOLUTE_PATHS_NOT_STARTING_WITH_CRATE,
520 node_id,
521 root_span,
522 diag,
523 );
524 }
525
526 pub(crate) fn add_module_candidates(
527 &mut self,
528 module: Module<'ra>,
529 names: &mut Vec<TypoSuggestion>,
530 filter_fn: &impl Fn(Res) -> bool,
531 ctxt: Option<SyntaxContext>,
532 ) {
533 module.for_each_child(self, |_this, ident, _ns, binding| {
534 let res = binding.res();
535 if filter_fn(res) && ctxt.is_none_or(|ctxt| ctxt == ident.span.ctxt()) {
536 names.push(TypoSuggestion::typo_from_ident(ident, res));
537 }
538 });
539 }
540
541 pub(crate) fn report_error(
546 &mut self,
547 span: Span,
548 resolution_error: ResolutionError<'ra>,
549 ) -> ErrorGuaranteed {
550 self.into_struct_error(span, resolution_error).emit()
551 }
552
553 pub(crate) fn into_struct_error(
554 &mut self,
555 span: Span,
556 resolution_error: ResolutionError<'ra>,
557 ) -> Diag<'_> {
558 match resolution_error {
559 ResolutionError::GenericParamsFromOuterItem(
560 outer_res,
561 has_generic_params,
562 def_kind,
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 };
582
583 let sm = self.tcx.sess.source_map();
584 let def_id = match outer_res {
585 Res::SelfTyParam { .. } => {
586 err.label = Some(Label::SelfTyParam(span));
587 return self.dcx().create_err(err);
588 }
589 Res::SelfTyAlias { alias_to: def_id, .. } => {
590 err.label = Some(Label::SelfTyAlias(reduce_impl_span_to_impl_keyword(
591 sm,
592 self.def_span(def_id),
593 )));
594 err.refer_to_type_directly = Some(span);
595 return self.dcx().create_err(err);
596 }
597 Res::Def(DefKind::TyParam, def_id) => {
598 err.label = Some(Label::TyParam(self.def_span(def_id)));
599 def_id
600 }
601 Res::Def(DefKind::ConstParam, def_id) => {
602 err.label = Some(Label::ConstParam(self.def_span(def_id)));
603 def_id
604 }
605 _ => {
606 bug!(
607 "GenericParamsFromOuterItem should only be used with \
608 Res::SelfTyParam, Res::SelfTyAlias, DefKind::TyParam or \
609 DefKind::ConstParam"
610 );
611 }
612 };
613
614 if let HasGenericParams::Yes(span) = has_generic_params {
615 let name = self.tcx.item_name(def_id);
616 let (span, snippet) = if span.is_empty() {
617 let snippet = format!("<{name}>");
618 (span, snippet)
619 } else {
620 let span = sm.span_through_char(span, '<').shrink_to_hi();
621 let snippet = format!("{name}, ");
622 (span, snippet)
623 };
624 err.sugg = Some(errs::GenericParamsFromOuterItemSugg { span, snippet });
625 }
626
627 self.dcx().create_err(err)
628 }
629 ResolutionError::NameAlreadyUsedInParameterList(name, first_use_span) => self
630 .dcx()
631 .create_err(errs::NameAlreadyUsedInParameterList { span, first_use_span, name }),
632 ResolutionError::MethodNotMemberOfTrait(method, trait_, candidate) => {
633 self.dcx().create_err(errs::MethodNotMemberOfTrait {
634 span,
635 method,
636 trait_,
637 sub: candidate.map(|c| errs::AssociatedFnWithSimilarNameExists {
638 span: method.span,
639 candidate: c,
640 }),
641 })
642 }
643 ResolutionError::TypeNotMemberOfTrait(type_, trait_, candidate) => {
644 self.dcx().create_err(errs::TypeNotMemberOfTrait {
645 span,
646 type_,
647 trait_,
648 sub: candidate.map(|c| errs::AssociatedTypeWithSimilarNameExists {
649 span: type_.span,
650 candidate: c,
651 }),
652 })
653 }
654 ResolutionError::ConstNotMemberOfTrait(const_, trait_, candidate) => {
655 self.dcx().create_err(errs::ConstNotMemberOfTrait {
656 span,
657 const_,
658 trait_,
659 sub: candidate.map(|c| errs::AssociatedConstWithSimilarNameExists {
660 span: const_.span,
661 candidate: c,
662 }),
663 })
664 }
665 ResolutionError::VariableNotBoundInPattern(binding_error, parent_scope) => {
666 let BindingError { name, target, origin, could_be_path } = binding_error;
667
668 let target_sp = target.iter().copied().collect::<Vec<_>>();
669 let origin_sp = origin.iter().copied().collect::<Vec<_>>();
670
671 let msp = MultiSpan::from_spans(target_sp.clone());
672 let mut err = self
673 .dcx()
674 .create_err(errors::VariableIsNotBoundInAllPatterns { multispan: msp, name });
675 for sp in target_sp {
676 err.subdiagnostic(errors::PatternDoesntBindName { span: sp, name });
677 }
678 for sp in origin_sp {
679 err.subdiagnostic(errors::VariableNotInAllPatterns { span: sp });
680 }
681 if could_be_path {
682 let import_suggestions = self.lookup_import_candidates(
683 name,
684 Namespace::ValueNS,
685 &parent_scope,
686 &|res: Res| {
687 matches!(
688 res,
689 Res::Def(
690 DefKind::Ctor(CtorOf::Variant, CtorKind::Const)
691 | DefKind::Ctor(CtorOf::Struct, CtorKind::Const)
692 | DefKind::Const
693 | DefKind::AssocConst,
694 _,
695 )
696 )
697 },
698 );
699
700 if import_suggestions.is_empty() {
701 let help_msg = format!(
702 "if you meant to match on a variant or a `const` item, consider \
703 making the path in the pattern qualified: `path::to::ModOrType::{name}`",
704 );
705 err.span_help(span, help_msg);
706 }
707 show_candidates(
708 self.tcx,
709 &mut err,
710 Some(span),
711 &import_suggestions,
712 Instead::No,
713 FoundUse::Yes,
714 DiagMode::Pattern,
715 vec![],
716 "",
717 );
718 }
719 err
720 }
721 ResolutionError::VariableBoundWithDifferentMode(variable_name, first_binding_span) => {
722 self.dcx().create_err(errs::VariableBoundWithDifferentMode {
723 span,
724 first_binding_span,
725 variable_name,
726 })
727 }
728 ResolutionError::IdentifierBoundMoreThanOnceInParameterList(identifier) => self
729 .dcx()
730 .create_err(errs::IdentifierBoundMoreThanOnceInParameterList { span, identifier }),
731 ResolutionError::IdentifierBoundMoreThanOnceInSamePattern(identifier) => self
732 .dcx()
733 .create_err(errs::IdentifierBoundMoreThanOnceInSamePattern { span, identifier }),
734 ResolutionError::UndeclaredLabel { name, suggestion } => {
735 let ((sub_reachable, sub_reachable_suggestion), sub_unreachable) = match suggestion
736 {
737 Some((ident, true)) => (
739 (
740 Some(errs::LabelWithSimilarNameReachable(ident.span)),
741 Some(errs::TryUsingSimilarlyNamedLabel {
742 span,
743 ident_name: ident.name,
744 }),
745 ),
746 None,
747 ),
748 Some((ident, false)) => (
750 (None, None),
751 Some(errs::UnreachableLabelWithSimilarNameExists {
752 ident_span: ident.span,
753 }),
754 ),
755 None => ((None, None), None),
757 };
758 self.dcx().create_err(errs::UndeclaredLabel {
759 span,
760 name,
761 sub_reachable,
762 sub_reachable_suggestion,
763 sub_unreachable,
764 })
765 }
766 ResolutionError::SelfImportsOnlyAllowedWithin { root, span_with_rename } => {
767 let (suggestion, mpart_suggestion) = if root {
769 (None, None)
770 } else {
771 let suggestion = errs::SelfImportsOnlyAllowedWithinSuggestion { span };
774
775 let mpart_suggestion = errs::SelfImportsOnlyAllowedWithinMultipartSuggestion {
778 multipart_start: span_with_rename.shrink_to_lo(),
779 multipart_end: span_with_rename.shrink_to_hi(),
780 };
781 (Some(suggestion), Some(mpart_suggestion))
782 };
783 self.dcx().create_err(errs::SelfImportsOnlyAllowedWithin {
784 span,
785 suggestion,
786 mpart_suggestion,
787 })
788 }
789 ResolutionError::SelfImportCanOnlyAppearOnceInTheList => {
790 self.dcx().create_err(errs::SelfImportCanOnlyAppearOnceInTheList { span })
791 }
792 ResolutionError::SelfImportOnlyInImportListWithNonEmptyPrefix => {
793 self.dcx().create_err(errs::SelfImportOnlyInImportListWithNonEmptyPrefix { span })
794 }
795 ResolutionError::FailedToResolve { segment, label, suggestion, module } => {
796 let mut err =
797 struct_span_code_err!(self.dcx(), span, E0433, "failed to resolve: {label}");
798 err.span_label(span, label);
799
800 if let Some((suggestions, msg, applicability)) = suggestion {
801 if suggestions.is_empty() {
802 err.help(msg);
803 return err;
804 }
805 err.multipart_suggestion(msg, suggestions, applicability);
806 }
807 if let Some(ModuleOrUniformRoot::Module(module)) = module
808 && let Some(module) = module.opt_def_id()
809 && let Some(segment) = segment
810 {
811 self.find_cfg_stripped(&mut err, &segment, module);
812 }
813
814 err
815 }
816 ResolutionError::CannotCaptureDynamicEnvironmentInFnItem => {
817 self.dcx().create_err(errs::CannotCaptureDynamicEnvironmentInFnItem { span })
818 }
819 ResolutionError::AttemptToUseNonConstantValueInConstant {
820 ident,
821 suggestion,
822 current,
823 type_span,
824 } => {
825 let sp = self
834 .tcx
835 .sess
836 .source_map()
837 .span_extend_to_prev_str(ident.span, current, true, false);
838
839 let ((with, with_label), without) = match sp {
840 Some(sp) if !self.tcx.sess.source_map().is_multiline(sp) => {
841 let sp = sp
842 .with_lo(BytePos(sp.lo().0 - (current.len() as u32)))
843 .until(ident.span);
844 (
845 (Some(errs::AttemptToUseNonConstantValueInConstantWithSuggestion {
846 span: sp,
847 suggestion,
848 current,
849 type_span,
850 }), Some(errs::AttemptToUseNonConstantValueInConstantLabelWithSuggestion {span})),
851 None,
852 )
853 }
854 _ => (
855 (None, None),
856 Some(errs::AttemptToUseNonConstantValueInConstantWithoutSuggestion {
857 ident_span: ident.span,
858 suggestion,
859 }),
860 ),
861 };
862
863 self.dcx().create_err(errs::AttemptToUseNonConstantValueInConstant {
864 span,
865 with,
866 with_label,
867 without,
868 })
869 }
870 ResolutionError::BindingShadowsSomethingUnacceptable {
871 shadowing_binding,
872 name,
873 participle,
874 article,
875 shadowed_binding,
876 shadowed_binding_span,
877 } => self.dcx().create_err(errs::BindingShadowsSomethingUnacceptable {
878 span,
879 shadowing_binding,
880 shadowed_binding,
881 article,
882 sub_suggestion: match (shadowing_binding, shadowed_binding) {
883 (
884 PatternSource::Match,
885 Res::Def(DefKind::Ctor(CtorOf::Variant | CtorOf::Struct, CtorKind::Fn), _),
886 ) => Some(errs::BindingShadowsSomethingUnacceptableSuggestion { span, name }),
887 _ => None,
888 },
889 shadowed_binding_span,
890 participle,
891 name,
892 }),
893 ResolutionError::ForwardDeclaredGenericParam(param, reason) => match reason {
894 ForwardGenericParamBanReason::Default => {
895 self.dcx().create_err(errs::ForwardDeclaredGenericParam { param, span })
896 }
897 ForwardGenericParamBanReason::ConstParamTy => self
898 .dcx()
899 .create_err(errs::ForwardDeclaredGenericInConstParamTy { param, span }),
900 },
901 ResolutionError::ParamInTyOfConstParam { name } => {
902 self.dcx().create_err(errs::ParamInTyOfConstParam { span, name })
903 }
904 ResolutionError::ParamInNonTrivialAnonConst { name, param_kind: is_type } => {
905 self.dcx().create_err(errs::ParamInNonTrivialAnonConst {
906 span,
907 name,
908 param_kind: is_type,
909 help: self
910 .tcx
911 .sess
912 .is_nightly_build()
913 .then_some(errs::ParamInNonTrivialAnonConstHelp),
914 })
915 }
916 ResolutionError::ParamInEnumDiscriminant { name, param_kind: is_type } => self
917 .dcx()
918 .create_err(errs::ParamInEnumDiscriminant { span, name, param_kind: is_type }),
919 ResolutionError::ForwardDeclaredSelf(reason) => match reason {
920 ForwardGenericParamBanReason::Default => {
921 self.dcx().create_err(errs::SelfInGenericParamDefault { span })
922 }
923 ForwardGenericParamBanReason::ConstParamTy => {
924 self.dcx().create_err(errs::SelfInConstGenericTy { span })
925 }
926 },
927 ResolutionError::UnreachableLabel { name, definition_span, suggestion } => {
928 let ((sub_suggestion_label, sub_suggestion), sub_unreachable_label) =
929 match suggestion {
930 Some((ident, true)) => (
932 (
933 Some(errs::UnreachableLabelSubLabel { ident_span: ident.span }),
934 Some(errs::UnreachableLabelSubSuggestion {
935 span,
936 ident_name: ident.name,
939 }),
940 ),
941 None,
942 ),
943 Some((ident, false)) => (
945 (None, None),
946 Some(errs::UnreachableLabelSubLabelUnreachable {
947 ident_span: ident.span,
948 }),
949 ),
950 None => ((None, None), None),
952 };
953 self.dcx().create_err(errs::UnreachableLabel {
954 span,
955 name,
956 definition_span,
957 sub_suggestion,
958 sub_suggestion_label,
959 sub_unreachable_label,
960 })
961 }
962 ResolutionError::TraitImplMismatch {
963 name,
964 kind,
965 code,
966 trait_item_span,
967 trait_path,
968 } => self
969 .dcx()
970 .create_err(errors::TraitImplMismatch {
971 span,
972 name,
973 kind,
974 trait_path,
975 trait_item_span,
976 })
977 .with_code(code),
978 ResolutionError::TraitImplDuplicate { name, trait_item_span, old_span } => self
979 .dcx()
980 .create_err(errs::TraitImplDuplicate { span, name, trait_item_span, old_span }),
981 ResolutionError::InvalidAsmSym => self.dcx().create_err(errs::InvalidAsmSym { span }),
982 ResolutionError::LowercaseSelf => self.dcx().create_err(errs::LowercaseSelf { span }),
983 ResolutionError::BindingInNeverPattern => {
984 self.dcx().create_err(errs::BindingInNeverPattern { span })
985 }
986 }
987 }
988
989 pub(crate) fn report_vis_error(
990 &mut self,
991 vis_resolution_error: VisResolutionError<'_>,
992 ) -> ErrorGuaranteed {
993 match vis_resolution_error {
994 VisResolutionError::Relative2018(span, path) => {
995 self.dcx().create_err(errs::Relative2018 {
996 span,
997 path_span: path.span,
998 path_str: pprust::path_to_string(path),
1001 })
1002 }
1003 VisResolutionError::AncestorOnly(span) => {
1004 self.dcx().create_err(errs::AncestorOnly(span))
1005 }
1006 VisResolutionError::FailedToResolve(span, label, suggestion) => self.into_struct_error(
1007 span,
1008 ResolutionError::FailedToResolve { segment: None, label, suggestion, module: None },
1009 ),
1010 VisResolutionError::ExpectedFound(span, path_str, res) => {
1011 self.dcx().create_err(errs::ExpectedModuleFound { span, res, path_str })
1012 }
1013 VisResolutionError::Indeterminate(span) => {
1014 self.dcx().create_err(errs::Indeterminate(span))
1015 }
1016 VisResolutionError::ModuleOnly(span) => self.dcx().create_err(errs::ModuleOnly(span)),
1017 }
1018 .emit()
1019 }
1020
1021 fn early_lookup_typo_candidate(
1023 &mut self,
1024 scope_set: ScopeSet<'ra>,
1025 parent_scope: &ParentScope<'ra>,
1026 ident: Ident,
1027 filter_fn: &impl Fn(Res) -> bool,
1028 ) -> Option<TypoSuggestion> {
1029 let mut suggestions = Vec::new();
1030 let ctxt = ident.span.ctxt();
1031 self.visit_scopes(scope_set, parent_scope, ctxt, |this, scope, use_prelude, _| {
1032 match scope {
1033 Scope::DeriveHelpers(expn_id) => {
1034 let res = Res::NonMacroAttr(NonMacroAttrKind::DeriveHelper);
1035 if filter_fn(res) {
1036 suggestions.extend(
1037 this.helper_attrs
1038 .get(&expn_id)
1039 .into_iter()
1040 .flatten()
1041 .map(|(ident, _)| TypoSuggestion::typo_from_ident(*ident, res)),
1042 );
1043 }
1044 }
1045 Scope::DeriveHelpersCompat => {
1046 let res = Res::NonMacroAttr(NonMacroAttrKind::DeriveHelperCompat);
1047 if filter_fn(res) {
1048 for derive in parent_scope.derives {
1049 let parent_scope = &ParentScope { derives: &[], ..*parent_scope };
1050 let Ok((Some(ext), _)) = this.resolve_macro_path(
1051 derive,
1052 Some(MacroKind::Derive),
1053 parent_scope,
1054 false,
1055 false,
1056 None,
1057 None,
1058 ) else {
1059 continue;
1060 };
1061 suggestions.extend(
1062 ext.helper_attrs
1063 .iter()
1064 .map(|name| TypoSuggestion::typo_from_name(*name, res)),
1065 );
1066 }
1067 }
1068 }
1069 Scope::MacroRules(macro_rules_scope) => {
1070 if let MacroRulesScope::Binding(macro_rules_binding) = macro_rules_scope.get() {
1071 let res = macro_rules_binding.binding.res();
1072 if filter_fn(res) {
1073 suggestions.push(TypoSuggestion::typo_from_ident(
1074 macro_rules_binding.ident,
1075 res,
1076 ))
1077 }
1078 }
1079 }
1080 Scope::CrateRoot => {
1081 let root_ident = Ident::new(kw::PathRoot, ident.span);
1082 let root_module = this.resolve_crate_root(root_ident);
1083 this.add_module_candidates(root_module, &mut suggestions, filter_fn, None);
1084 }
1085 Scope::Module(module, _) => {
1086 this.add_module_candidates(module, &mut suggestions, filter_fn, None);
1087 }
1088 Scope::MacroUsePrelude => {
1089 suggestions.extend(this.macro_use_prelude.iter().filter_map(
1090 |(name, binding)| {
1091 let res = binding.res();
1092 filter_fn(res).then_some(TypoSuggestion::typo_from_name(*name, res))
1093 },
1094 ));
1095 }
1096 Scope::BuiltinAttrs => {
1097 let res = Res::NonMacroAttr(NonMacroAttrKind::Builtin(sym::dummy));
1098 if filter_fn(res) {
1099 suggestions.extend(
1100 BUILTIN_ATTRIBUTES
1101 .iter()
1102 .map(|attr| TypoSuggestion::typo_from_name(attr.name, res)),
1103 );
1104 }
1105 }
1106 Scope::ExternPrelude => {
1107 suggestions.extend(this.extern_prelude.iter().filter_map(|(ident, _)| {
1108 let res = Res::Def(DefKind::Mod, CRATE_DEF_ID.to_def_id());
1109 filter_fn(res).then_some(TypoSuggestion::typo_from_ident(*ident, res))
1110 }));
1111 }
1112 Scope::ToolPrelude => {
1113 let res = Res::NonMacroAttr(NonMacroAttrKind::Tool);
1114 suggestions.extend(
1115 this.registered_tools
1116 .iter()
1117 .map(|ident| TypoSuggestion::typo_from_ident(*ident, res)),
1118 );
1119 }
1120 Scope::StdLibPrelude => {
1121 if let Some(prelude) = this.prelude {
1122 let mut tmp_suggestions = Vec::new();
1123 this.add_module_candidates(prelude, &mut tmp_suggestions, filter_fn, None);
1124 suggestions.extend(
1125 tmp_suggestions
1126 .into_iter()
1127 .filter(|s| use_prelude.into() || this.is_builtin_macro(s.res)),
1128 );
1129 }
1130 }
1131 Scope::BuiltinTypes => {
1132 suggestions.extend(PrimTy::ALL.iter().filter_map(|prim_ty| {
1133 let res = Res::PrimTy(*prim_ty);
1134 filter_fn(res)
1135 .then_some(TypoSuggestion::typo_from_name(prim_ty.name(), res))
1136 }))
1137 }
1138 }
1139
1140 None::<()>
1141 });
1142
1143 suggestions.sort_by(|a, b| a.candidate.as_str().cmp(b.candidate.as_str()));
1145
1146 match find_best_match_for_name(
1147 &suggestions.iter().map(|suggestion| suggestion.candidate).collect::<Vec<Symbol>>(),
1148 ident.name,
1149 None,
1150 ) {
1151 Some(found) if found != ident.name => {
1152 suggestions.into_iter().find(|suggestion| suggestion.candidate == found)
1153 }
1154 _ => None,
1155 }
1156 }
1157
1158 fn lookup_import_candidates_from_module<FilterFn>(
1159 &mut self,
1160 lookup_ident: Ident,
1161 namespace: Namespace,
1162 parent_scope: &ParentScope<'ra>,
1163 start_module: Module<'ra>,
1164 crate_path: ThinVec<ast::PathSegment>,
1165 filter_fn: FilterFn,
1166 ) -> Vec<ImportSuggestion>
1167 where
1168 FilterFn: Fn(Res) -> bool,
1169 {
1170 let mut candidates = Vec::new();
1171 let mut seen_modules = FxHashSet::default();
1172 let start_did = start_module.def_id();
1173 let mut worklist = vec![(
1174 start_module,
1175 ThinVec::<ast::PathSegment>::new(),
1176 true,
1177 start_did.is_local() || !self.tcx.is_doc_hidden(start_did),
1178 true,
1179 )];
1180 let mut worklist_via_import = vec![];
1181
1182 while let Some((in_module, path_segments, accessible, doc_visible, is_stable)) =
1183 match worklist.pop() {
1184 None => worklist_via_import.pop(),
1185 Some(x) => Some(x),
1186 }
1187 {
1188 let in_module_is_extern = !in_module.def_id().is_local();
1189 in_module.for_each_child(self, |this, ident, ns, name_binding| {
1190 if name_binding.is_assoc_item()
1192 && !this.tcx.features().import_trait_associated_functions()
1193 {
1194 return;
1195 }
1196
1197 if ident.name == kw::Underscore {
1198 return;
1199 }
1200
1201 let child_accessible =
1202 accessible && this.is_accessible_from(name_binding.vis, parent_scope.module);
1203
1204 if in_module_is_extern && !child_accessible {
1206 return;
1207 }
1208
1209 let via_import = name_binding.is_import() && !name_binding.is_extern_crate();
1210
1211 if via_import && name_binding.is_possibly_imported_variant() {
1217 return;
1218 }
1219
1220 if let NameBindingKind::Import { binding, .. } = name_binding.kind
1222 && this.is_accessible_from(binding.vis, parent_scope.module)
1223 && !this.is_accessible_from(name_binding.vis, parent_scope.module)
1224 {
1225 return;
1226 }
1227
1228 let res = name_binding.res();
1229 let did = match res {
1230 Res::Def(DefKind::Ctor(..), did) => this.tcx.opt_parent(did),
1231 _ => res.opt_def_id(),
1232 };
1233 let child_doc_visible = doc_visible
1234 && did.is_none_or(|did| did.is_local() || !this.tcx.is_doc_hidden(did));
1235
1236 if ident.name == lookup_ident.name
1240 && ns == namespace
1241 && in_module != parent_scope.module
1242 && !ident.span.normalize_to_macros_2_0().from_expansion()
1243 && filter_fn(res)
1244 {
1245 let mut segms = if lookup_ident.span.at_least_rust_2018() {
1247 crate_path.clone()
1250 } else {
1251 ThinVec::new()
1252 };
1253 segms.append(&mut path_segments.clone());
1254
1255 segms.push(ast::PathSegment::from_ident(ident));
1256 let path = Path { span: name_binding.span, segments: segms, tokens: None };
1257
1258 if child_accessible
1259 && let Some(idx) = candidates
1261 .iter()
1262 .position(|v: &ImportSuggestion| v.did == did && !v.accessible)
1263 {
1264 candidates.remove(idx);
1265 }
1266
1267 let is_stable = if is_stable
1268 && let Some(did) = did
1269 && this.is_stable(did, path.span)
1270 {
1271 true
1272 } else {
1273 false
1274 };
1275
1276 if is_stable
1281 && let Some(idx) = candidates
1282 .iter()
1283 .position(|v: &ImportSuggestion| v.did == did && !v.is_stable)
1284 {
1285 candidates.remove(idx);
1286 }
1287
1288 if candidates.iter().all(|v: &ImportSuggestion| v.did != did) {
1289 let note = if let Some(did) = did {
1292 let requires_note = !did.is_local()
1293 && this.tcx.get_attrs(did, sym::rustc_diagnostic_item).any(
1294 |attr| {
1295 [sym::TryInto, sym::TryFrom, sym::FromIterator]
1296 .map(|x| Some(x))
1297 .contains(&attr.value_str())
1298 },
1299 );
1300
1301 requires_note.then(|| {
1302 format!(
1303 "'{}' is included in the prelude starting in Edition 2021",
1304 path_names_to_string(&path)
1305 )
1306 })
1307 } else {
1308 None
1309 };
1310
1311 candidates.push(ImportSuggestion {
1312 did,
1313 descr: res.descr(),
1314 path,
1315 accessible: child_accessible,
1316 doc_visible: child_doc_visible,
1317 note,
1318 via_import,
1319 is_stable,
1320 });
1321 }
1322 }
1323
1324 if let Some(module) = name_binding.module() {
1326 let mut path_segments = path_segments.clone();
1328 path_segments.push(ast::PathSegment::from_ident(ident));
1329
1330 let alias_import = if let NameBindingKind::Import { import, .. } =
1331 name_binding.kind
1332 && let ImportKind::ExternCrate { source: Some(_), .. } = import.kind
1333 && import.parent_scope.expansion == parent_scope.expansion
1334 {
1335 true
1336 } else {
1337 false
1338 };
1339
1340 let is_extern_crate_that_also_appears_in_prelude =
1341 name_binding.is_extern_crate() && lookup_ident.span.at_least_rust_2018();
1342
1343 if !is_extern_crate_that_also_appears_in_prelude || alias_import {
1344 if seen_modules.insert(module.def_id()) {
1346 if via_import { &mut worklist_via_import } else { &mut worklist }.push(
1347 (
1348 module,
1349 path_segments,
1350 child_accessible,
1351 child_doc_visible,
1352 is_stable && this.is_stable(module.def_id(), name_binding.span),
1353 ),
1354 );
1355 }
1356 }
1357 }
1358 })
1359 }
1360
1361 candidates
1362 }
1363
1364 fn is_stable(&self, did: DefId, span: Span) -> bool {
1365 if did.is_local() {
1366 return true;
1367 }
1368
1369 match self.tcx.lookup_stability(did) {
1370 Some(Stability {
1371 level: attr::StabilityLevel::Unstable { implied_by, .. },
1372 feature,
1373 ..
1374 }) => {
1375 if span.allows_unstable(feature) {
1376 true
1377 } else if self.tcx.features().enabled(feature) {
1378 true
1379 } else if let Some(implied_by) = implied_by
1380 && self.tcx.features().enabled(implied_by)
1381 {
1382 true
1383 } else {
1384 false
1385 }
1386 }
1387 Some(_) => true,
1388 None => false,
1389 }
1390 }
1391
1392 pub(crate) fn lookup_import_candidates<FilterFn>(
1400 &mut self,
1401 lookup_ident: Ident,
1402 namespace: Namespace,
1403 parent_scope: &ParentScope<'ra>,
1404 filter_fn: FilterFn,
1405 ) -> Vec<ImportSuggestion>
1406 where
1407 FilterFn: Fn(Res) -> bool,
1408 {
1409 let crate_path = thin_vec![ast::PathSegment::from_ident(Ident::with_dummy_span(kw::Crate))];
1410 let mut suggestions = self.lookup_import_candidates_from_module(
1411 lookup_ident,
1412 namespace,
1413 parent_scope,
1414 self.graph_root,
1415 crate_path,
1416 &filter_fn,
1417 );
1418
1419 if lookup_ident.span.at_least_rust_2018() {
1420 for ident in self.extern_prelude.clone().into_keys() {
1421 if ident.span.from_expansion() {
1422 continue;
1428 }
1429 let Some(crate_id) = self.crate_loader(|c| c.maybe_process_path_extern(ident.name))
1430 else {
1431 continue;
1432 };
1433
1434 let crate_def_id = crate_id.as_def_id();
1435 let crate_root = self.expect_module(crate_def_id);
1436
1437 let needs_disambiguation =
1441 self.resolutions(parent_scope.module).borrow().iter().any(
1442 |(key, name_resolution)| {
1443 if key.ns == TypeNS
1444 && key.ident == ident
1445 && let Some(binding) = name_resolution.borrow().binding
1446 {
1447 match binding.res() {
1448 Res::Def(_, def_id) => def_id != crate_def_id,
1451 Res::PrimTy(_) => true,
1452 _ => false,
1453 }
1454 } else {
1455 false
1456 }
1457 },
1458 );
1459 let mut crate_path = ThinVec::new();
1460 if needs_disambiguation {
1461 crate_path.push(ast::PathSegment::path_root(rustc_span::DUMMY_SP));
1462 }
1463 crate_path.push(ast::PathSegment::from_ident(ident));
1464
1465 suggestions.extend(self.lookup_import_candidates_from_module(
1466 lookup_ident,
1467 namespace,
1468 parent_scope,
1469 crate_root,
1470 crate_path,
1471 &filter_fn,
1472 ));
1473 }
1474 }
1475
1476 suggestions
1477 }
1478
1479 pub(crate) fn unresolved_macro_suggestions(
1480 &mut self,
1481 err: &mut Diag<'_>,
1482 macro_kind: MacroKind,
1483 parent_scope: &ParentScope<'ra>,
1484 ident: Ident,
1485 krate: &Crate,
1486 sugg_span: Option<Span>,
1487 ) {
1488 self.visit_scopes(
1491 ScopeSet::Macro(MacroKind::Derive),
1492 &parent_scope,
1493 ident.span.ctxt(),
1494 |this, scope, _use_prelude, _ctxt| {
1495 let Scope::Module(m, _) = scope else {
1496 return None;
1497 };
1498 for (_, resolution) in this.resolutions(m).borrow().iter() {
1499 let Some(binding) = resolution.borrow().binding else {
1500 continue;
1501 };
1502 let Res::Def(DefKind::Macro(MacroKind::Derive | MacroKind::Attr), def_id) =
1503 binding.res()
1504 else {
1505 continue;
1506 };
1507 let _ = this.get_macro_by_def_id(def_id);
1510 }
1511 None::<()>
1512 },
1513 );
1514
1515 let is_expected = &|res: Res| res.macro_kind() == Some(macro_kind);
1516 let suggestion = self.early_lookup_typo_candidate(
1517 ScopeSet::Macro(macro_kind),
1518 parent_scope,
1519 ident,
1520 is_expected,
1521 );
1522 if !self.add_typo_suggestion(err, suggestion, ident.span) {
1523 self.detect_derive_attribute(err, ident, parent_scope, sugg_span);
1524 }
1525
1526 let import_suggestions =
1527 self.lookup_import_candidates(ident, Namespace::MacroNS, parent_scope, is_expected);
1528 let (span, found_use) = match parent_scope.module.nearest_parent_mod().as_local() {
1529 Some(def_id) => UsePlacementFinder::check(krate, self.def_id_to_node_id(def_id)),
1530 None => (None, FoundUse::No),
1531 };
1532 show_candidates(
1533 self.tcx,
1534 err,
1535 span,
1536 &import_suggestions,
1537 Instead::No,
1538 found_use,
1539 DiagMode::Normal,
1540 vec![],
1541 "",
1542 );
1543
1544 if macro_kind == MacroKind::Bang && ident.name == sym::macro_rules {
1545 let label_span = ident.span.shrink_to_hi();
1546 let mut spans = MultiSpan::from_span(label_span);
1547 spans.push_span_label(label_span, "put a macro name here");
1548 err.subdiagnostic(MaybeMissingMacroRulesName { spans });
1549 return;
1550 }
1551
1552 if macro_kind == MacroKind::Derive && (ident.name == sym::Send || ident.name == sym::Sync) {
1553 err.subdiagnostic(ExplicitUnsafeTraits { span: ident.span, ident });
1554 return;
1555 }
1556
1557 let unused_macro = self.unused_macros.iter().find_map(|(def_id, (_, unused_ident))| {
1558 if unused_ident.name == ident.name { Some((def_id, unused_ident)) } else { None }
1559 });
1560
1561 if let Some((def_id, unused_ident)) = unused_macro {
1562 let scope = self.local_macro_def_scopes[&def_id];
1563 let parent_nearest = parent_scope.module.nearest_parent_mod();
1564 if Some(parent_nearest) == scope.opt_def_id() {
1565 match macro_kind {
1566 MacroKind::Bang => {
1567 err.subdiagnostic(MacroDefinedLater { span: unused_ident.span });
1568 err.subdiagnostic(MacroSuggMovePosition { span: ident.span, ident });
1569 }
1570 MacroKind::Attr => {
1571 err.subdiagnostic(MacroRulesNot::Attr { span: unused_ident.span, ident });
1572 }
1573 MacroKind::Derive => {
1574 err.subdiagnostic(MacroRulesNot::Derive { span: unused_ident.span, ident });
1575 }
1576 }
1577
1578 return;
1579 }
1580 }
1581
1582 if self.macro_names.contains(&ident.normalize_to_macros_2_0()) {
1583 err.subdiagnostic(AddedMacroUse);
1584 return;
1585 }
1586
1587 if ident.name == kw::Default
1588 && let ModuleKind::Def(DefKind::Enum, def_id, _) = parent_scope.module.kind
1589 {
1590 let span = self.def_span(def_id);
1591 let source_map = self.tcx.sess.source_map();
1592 let head_span = source_map.guess_head_span(span);
1593 err.subdiagnostic(ConsiderAddingADerive {
1594 span: head_span.shrink_to_lo(),
1595 suggestion: "#[derive(Default)]\n".to_string(),
1596 });
1597 }
1598 for ns in [Namespace::MacroNS, Namespace::TypeNS, Namespace::ValueNS] {
1599 let Ok(binding) = self.early_resolve_ident_in_lexical_scope(
1600 ident,
1601 ScopeSet::All(ns),
1602 parent_scope,
1603 None,
1604 false,
1605 None,
1606 None,
1607 ) else {
1608 continue;
1609 };
1610
1611 let desc = match binding.res() {
1612 Res::Def(DefKind::Macro(MacroKind::Bang), _) => "a function-like macro".to_string(),
1613 Res::Def(DefKind::Macro(MacroKind::Attr), _) | Res::NonMacroAttr(..) => {
1614 format!("an attribute: `#[{ident}]`")
1615 }
1616 Res::Def(DefKind::Macro(MacroKind::Derive), _) => {
1617 format!("a derive macro: `#[derive({ident})]`")
1618 }
1619 Res::ToolMod => {
1620 continue;
1622 }
1623 Res::Def(DefKind::Trait, _) if macro_kind == MacroKind::Derive => {
1624 "only a trait, without a derive macro".to_string()
1625 }
1626 res => format!(
1627 "{} {}, not {} {}",
1628 res.article(),
1629 res.descr(),
1630 macro_kind.article(),
1631 macro_kind.descr_expected(),
1632 ),
1633 };
1634 if let crate::NameBindingKind::Import { import, .. } = binding.kind
1635 && !import.span.is_dummy()
1636 {
1637 let note = errors::IdentImporterHereButItIsDesc {
1638 span: import.span,
1639 imported_ident: ident,
1640 imported_ident_desc: &desc,
1641 };
1642 err.subdiagnostic(note);
1643 self.record_use(ident, binding, Used::Other);
1646 return;
1647 }
1648 let note = errors::IdentInScopeButItIsDesc {
1649 imported_ident: ident,
1650 imported_ident_desc: &desc,
1651 };
1652 err.subdiagnostic(note);
1653 return;
1654 }
1655 }
1656
1657 fn detect_derive_attribute(
1660 &self,
1661 err: &mut Diag<'_>,
1662 ident: Ident,
1663 parent_scope: &ParentScope<'ra>,
1664 sugg_span: Option<Span>,
1665 ) {
1666 let mut derives = vec![];
1671 let mut all_attrs: UnordMap<Symbol, Vec<_>> = UnordMap::default();
1672 #[allow(rustc::potential_query_instability)]
1674 for (def_id, data) in &self.macro_map {
1675 for helper_attr in &data.ext.helper_attrs {
1676 let item_name = self.tcx.item_name(*def_id);
1677 all_attrs.entry(*helper_attr).or_default().push(item_name);
1678 if helper_attr == &ident.name {
1679 derives.push(item_name);
1680 }
1681 }
1682 }
1683 let kind = MacroKind::Derive.descr();
1684 if !derives.is_empty() {
1685 let mut derives: Vec<String> = derives.into_iter().map(|d| d.to_string()).collect();
1687 derives.sort();
1688 derives.dedup();
1689 let msg = match &derives[..] {
1690 [derive] => format!(" `{derive}`"),
1691 [start @ .., last] => format!(
1692 "s {} and `{last}`",
1693 start.iter().map(|d| format!("`{d}`")).collect::<Vec<_>>().join(", ")
1694 ),
1695 [] => unreachable!("we checked for this to be non-empty 10 lines above!?"),
1696 };
1697 let msg = format!(
1698 "`{}` is an attribute that can be used by the {kind}{msg}, you might be \
1699 missing a `derive` attribute",
1700 ident.name,
1701 );
1702 let sugg_span = if let ModuleKind::Def(DefKind::Enum, id, _) = parent_scope.module.kind
1703 {
1704 let span = self.def_span(id);
1705 if span.from_expansion() {
1706 None
1707 } else {
1708 Some(span.shrink_to_lo())
1710 }
1711 } else {
1712 sugg_span
1714 };
1715 match sugg_span {
1716 Some(span) => {
1717 err.span_suggestion_verbose(
1718 span,
1719 msg,
1720 format!("#[derive({})]\n", derives.join(", ")),
1721 Applicability::MaybeIncorrect,
1722 );
1723 }
1724 None => {
1725 err.note(msg);
1726 }
1727 }
1728 } else {
1729 let all_attr_names = all_attrs.keys().map(|s| *s).into_sorted_stable_ord();
1731 if let Some(best_match) = find_best_match_for_name(&all_attr_names, ident.name, None)
1732 && let Some(macros) = all_attrs.get(&best_match)
1733 {
1734 let mut macros: Vec<String> = macros.into_iter().map(|d| d.to_string()).collect();
1735 macros.sort();
1736 macros.dedup();
1737 let msg = match ¯os[..] {
1738 [] => return,
1739 [name] => format!(" `{name}` accepts"),
1740 [start @ .., end] => format!(
1741 "s {} and `{end}` accept",
1742 start.iter().map(|m| format!("`{m}`")).collect::<Vec<_>>().join(", "),
1743 ),
1744 };
1745 let msg = format!("the {kind}{msg} the similarly named `{best_match}` attribute");
1746 err.span_suggestion_verbose(
1747 ident.span,
1748 msg,
1749 best_match,
1750 Applicability::MaybeIncorrect,
1751 );
1752 }
1753 }
1754 }
1755
1756 pub(crate) fn add_typo_suggestion(
1757 &self,
1758 err: &mut Diag<'_>,
1759 suggestion: Option<TypoSuggestion>,
1760 span: Span,
1761 ) -> bool {
1762 let suggestion = match suggestion {
1763 None => return false,
1764 Some(suggestion) if suggestion.candidate == kw::Underscore => return false,
1766 Some(suggestion) => suggestion,
1767 };
1768
1769 let mut did_label_def_span = false;
1770
1771 if let Some(def_span) = suggestion.res.opt_def_id().map(|def_id| self.def_span(def_id)) {
1772 if span.overlaps(def_span) {
1773 return false;
1792 }
1793 let span = self.tcx.sess.source_map().guess_head_span(def_span);
1794 let candidate_descr = suggestion.res.descr();
1795 let candidate = suggestion.candidate;
1796 let label = match suggestion.target {
1797 SuggestionTarget::SimilarlyNamed => {
1798 errors::DefinedHere::SimilarlyNamed { span, candidate_descr, candidate }
1799 }
1800 SuggestionTarget::SingleItem => {
1801 errors::DefinedHere::SingleItem { span, candidate_descr, candidate }
1802 }
1803 };
1804 did_label_def_span = true;
1805 err.subdiagnostic(label);
1806 }
1807
1808 let (span, msg, sugg) = if let SuggestionTarget::SimilarlyNamed = suggestion.target
1809 && let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span)
1810 && let Some(span) = suggestion.span
1811 && let Some(candidate) = suggestion.candidate.as_str().strip_prefix('_')
1812 && snippet == candidate
1813 {
1814 let candidate = suggestion.candidate;
1815 let msg = format!(
1818 "the leading underscore in `{candidate}` marks it as unused, consider renaming it to `{snippet}`"
1819 );
1820 if !did_label_def_span {
1821 err.span_label(span, format!("`{candidate}` defined here"));
1822 }
1823 (span, msg, snippet)
1824 } else {
1825 let msg = match suggestion.target {
1826 SuggestionTarget::SimilarlyNamed => format!(
1827 "{} {} with a similar name exists",
1828 suggestion.res.article(),
1829 suggestion.res.descr()
1830 ),
1831 SuggestionTarget::SingleItem => {
1832 format!("maybe you meant this {}", suggestion.res.descr())
1833 }
1834 };
1835 (span, msg, suggestion.candidate.to_ident_string())
1836 };
1837 err.span_suggestion(span, msg, sugg, Applicability::MaybeIncorrect);
1838 true
1839 }
1840
1841 fn binding_description(&self, b: NameBinding<'_>, ident: Ident, from_prelude: bool) -> String {
1842 let res = b.res();
1843 if b.span.is_dummy() || !self.tcx.sess.source_map().is_span_accessible(b.span) {
1844 let add_built_in =
1846 !matches!(b.res(), Res::NonMacroAttr(..) | Res::PrimTy(..) | Res::ToolMod);
1847 let (built_in, from) = if from_prelude {
1848 ("", " from prelude")
1849 } else if b.is_extern_crate()
1850 && !b.is_import()
1851 && self.tcx.sess.opts.externs.get(ident.as_str()).is_some()
1852 {
1853 ("", " passed with `--extern`")
1854 } else if add_built_in {
1855 (" built-in", "")
1856 } else {
1857 ("", "")
1858 };
1859
1860 let a = if built_in.is_empty() { res.article() } else { "a" };
1861 format!("{a}{built_in} {thing}{from}", thing = res.descr())
1862 } else {
1863 let introduced = if b.is_import_user_facing() { "imported" } else { "defined" };
1864 format!("the {thing} {introduced} here", thing = res.descr())
1865 }
1866 }
1867
1868 fn ambiguity_diagnostics(&self, ambiguity_error: &AmbiguityError<'_>) -> AmbiguityErrorDiag {
1869 let AmbiguityError { kind, ident, b1, b2, misc1, misc2, .. } = *ambiguity_error;
1870 let (b1, b2, misc1, misc2, swapped) = if b2.span.is_dummy() && !b1.span.is_dummy() {
1871 (b2, b1, misc2, misc1, true)
1873 } else {
1874 (b1, b2, misc1, misc2, false)
1875 };
1876 let could_refer_to = |b: NameBinding<'_>, misc: AmbiguityErrorMisc, also: &str| {
1877 let what = self.binding_description(b, ident, misc == AmbiguityErrorMisc::FromPrelude);
1878 let note_msg = format!("`{ident}` could{also} refer to {what}");
1879
1880 let thing = b.res().descr();
1881 let mut help_msgs = Vec::new();
1882 if b.is_glob_import()
1883 && (kind == AmbiguityKind::GlobVsGlob
1884 || kind == AmbiguityKind::GlobVsExpanded
1885 || kind == AmbiguityKind::GlobVsOuter && swapped != also.is_empty())
1886 {
1887 help_msgs.push(format!(
1888 "consider adding an explicit import of `{ident}` to disambiguate"
1889 ))
1890 }
1891 if b.is_extern_crate() && ident.span.at_least_rust_2018() {
1892 help_msgs.push(format!("use `::{ident}` to refer to this {thing} unambiguously"))
1893 }
1894 match misc {
1895 AmbiguityErrorMisc::SuggestCrate => help_msgs
1896 .push(format!("use `crate::{ident}` to refer to this {thing} unambiguously")),
1897 AmbiguityErrorMisc::SuggestSelf => help_msgs
1898 .push(format!("use `self::{ident}` to refer to this {thing} unambiguously")),
1899 AmbiguityErrorMisc::FromPrelude | AmbiguityErrorMisc::None => {}
1900 }
1901
1902 (
1903 b.span,
1904 note_msg,
1905 help_msgs
1906 .iter()
1907 .enumerate()
1908 .map(|(i, help_msg)| {
1909 let or = if i == 0 { "" } else { "or " };
1910 format!("{or}{help_msg}")
1911 })
1912 .collect::<Vec<_>>(),
1913 )
1914 };
1915 let (b1_span, b1_note_msg, b1_help_msgs) = could_refer_to(b1, misc1, "");
1916 let (b2_span, b2_note_msg, b2_help_msgs) = could_refer_to(b2, misc2, " also");
1917
1918 AmbiguityErrorDiag {
1919 msg: format!("`{ident}` is ambiguous"),
1920 span: ident.span,
1921 label_span: ident.span,
1922 label_msg: "ambiguous name".to_string(),
1923 note_msg: format!("ambiguous because of {}", kind.descr()),
1924 b1_span,
1925 b1_note_msg,
1926 b1_help_msgs,
1927 b2_span,
1928 b2_note_msg,
1929 b2_help_msgs,
1930 }
1931 }
1932
1933 fn ctor_fields_span(&self, binding: NameBinding<'_>) -> Option<Span> {
1936 let NameBindingKind::Res(Res::Def(
1937 DefKind::Ctor(CtorOf::Struct, CtorKind::Fn),
1938 ctor_def_id,
1939 )) = binding.kind
1940 else {
1941 return None;
1942 };
1943
1944 let def_id = self.tcx.parent(ctor_def_id);
1945 self.field_idents(def_id)?.iter().map(|&f| f.span).reduce(Span::to) }
1947
1948 fn report_privacy_error(&mut self, privacy_error: &PrivacyError<'ra>) {
1949 let PrivacyError { ident, binding, outermost_res, parent_scope, single_nested, dedup_span } =
1950 *privacy_error;
1951
1952 let res = binding.res();
1953 let ctor_fields_span = self.ctor_fields_span(binding);
1954 let plain_descr = res.descr().to_string();
1955 let nonimport_descr =
1956 if ctor_fields_span.is_some() { plain_descr + " constructor" } else { plain_descr };
1957 let import_descr = nonimport_descr.clone() + " import";
1958 let get_descr =
1959 |b: NameBinding<'_>| if b.is_import() { &import_descr } else { &nonimport_descr };
1960
1961 let ident_descr = get_descr(binding);
1963 let mut err =
1964 self.dcx().create_err(errors::IsPrivate { span: ident.span, ident_descr, ident });
1965
1966 let mut not_publicly_reexported = false;
1967 if let Some((this_res, outer_ident)) = outermost_res {
1968 let import_suggestions = self.lookup_import_candidates(
1969 outer_ident,
1970 this_res.ns().unwrap_or(Namespace::TypeNS),
1971 &parent_scope,
1972 &|res: Res| res == this_res,
1973 );
1974 let point_to_def = !show_candidates(
1975 self.tcx,
1976 &mut err,
1977 Some(dedup_span.until(outer_ident.span.shrink_to_hi())),
1978 &import_suggestions,
1979 Instead::Yes,
1980 FoundUse::Yes,
1981 DiagMode::Import { append: single_nested, unresolved_import: false },
1982 vec![],
1983 "",
1984 );
1985 if point_to_def && ident.span != outer_ident.span {
1987 not_publicly_reexported = true;
1988 let label = errors::OuterIdentIsNotPubliclyReexported {
1989 span: outer_ident.span,
1990 outer_ident_descr: this_res.descr(),
1991 outer_ident,
1992 };
1993 err.subdiagnostic(label);
1994 }
1995 }
1996
1997 let mut non_exhaustive = None;
1998 if let Some(def_id) = res.opt_def_id()
2002 && !def_id.is_local()
2003 && let Some(attr) = self.tcx.get_attr(def_id, sym::non_exhaustive)
2004 {
2005 non_exhaustive = Some(attr.span());
2006 } else if let Some(span) = ctor_fields_span {
2007 let label = errors::ConstructorPrivateIfAnyFieldPrivate { span };
2008 err.subdiagnostic(label);
2009 if let Res::Def(_, d) = res
2010 && let Some(fields) = self.field_visibility_spans.get(&d)
2011 {
2012 let spans = fields.iter().map(|span| *span).collect();
2013 let sugg =
2014 errors::ConsiderMakingTheFieldPublic { spans, number_of_fields: fields.len() };
2015 err.subdiagnostic(sugg);
2016 }
2017 }
2018
2019 let mut sugg_paths = vec![];
2020 if let Some(mut def_id) = res.opt_def_id() {
2021 let mut path = vec![def_id];
2023 while let Some(parent) = self.tcx.opt_parent(def_id) {
2024 def_id = parent;
2025 if !def_id.is_top_level_module() {
2026 path.push(def_id);
2027 } else {
2028 break;
2029 }
2030 }
2031 let path_names: Option<Vec<String>> = path
2033 .iter()
2034 .rev()
2035 .map(|def_id| {
2036 self.tcx.opt_item_name(*def_id).map(|n| {
2037 if def_id.is_top_level_module() {
2038 "crate".to_string()
2039 } else {
2040 n.to_string()
2041 }
2042 })
2043 })
2044 .collect();
2045 if let Some(def_id) = path.get(0)
2046 && let Some(path) = path_names
2047 {
2048 if let Some(def_id) = def_id.as_local() {
2049 if self.effective_visibilities.is_directly_public(def_id) {
2050 sugg_paths.push((path, false));
2051 }
2052 } else if self.is_accessible_from(self.tcx.visibility(def_id), parent_scope.module)
2053 {
2054 sugg_paths.push((path, false));
2055 }
2056 }
2057 }
2058
2059 let first_binding = binding;
2061 let mut next_binding = Some(binding);
2062 let mut next_ident = ident;
2063 let mut path = vec![];
2064 while let Some(binding) = next_binding {
2065 let name = next_ident;
2066 next_binding = match binding.kind {
2067 _ if res == Res::Err => None,
2068 NameBindingKind::Import { binding, import, .. } => match import.kind {
2069 _ if binding.span.is_dummy() => None,
2070 ImportKind::Single { source, .. } => {
2071 next_ident = source;
2072 Some(binding)
2073 }
2074 ImportKind::Glob { .. }
2075 | ImportKind::MacroUse { .. }
2076 | ImportKind::MacroExport => Some(binding),
2077 ImportKind::ExternCrate { .. } => None,
2078 },
2079 _ => None,
2080 };
2081
2082 match binding.kind {
2083 NameBindingKind::Import { import, .. } => {
2084 for segment in import.module_path.iter().skip(1) {
2085 path.push(segment.ident.to_string());
2086 }
2087 sugg_paths.push((
2088 path.iter()
2089 .cloned()
2090 .chain(vec![ident.to_string()].into_iter())
2091 .collect::<Vec<_>>(),
2092 true, ));
2094 }
2095 NameBindingKind::Res(_) | NameBindingKind::Module(_) => {}
2096 }
2097 let first = binding == first_binding;
2098 let def_span = self.tcx.sess.source_map().guess_head_span(binding.span);
2099 let mut note_span = MultiSpan::from_span(def_span);
2100 if !first && binding.vis.is_public() {
2101 let desc = match binding.kind {
2102 NameBindingKind::Import { .. } => "re-export",
2103 _ => "directly",
2104 };
2105 note_span.push_span_label(def_span, format!("you could import this {desc}"));
2106 }
2107 if next_binding.is_none()
2110 && let Some(span) = non_exhaustive
2111 {
2112 note_span.push_span_label(
2113 span,
2114 "cannot be constructed because it is `#[non_exhaustive]`",
2115 );
2116 }
2117 let note = errors::NoteAndRefersToTheItemDefinedHere {
2118 span: note_span,
2119 binding_descr: get_descr(binding),
2120 binding_name: name,
2121 first,
2122 dots: next_binding.is_some(),
2123 };
2124 err.subdiagnostic(note);
2125 }
2126 sugg_paths.sort_by_key(|(p, reexport)| (p.len(), p[0] == "core", *reexport));
2128 for (sugg, reexport) in sugg_paths {
2129 if not_publicly_reexported {
2130 break;
2131 }
2132 if sugg.len() <= 1 {
2133 continue;
2136 }
2137 let path = sugg.join("::");
2138 let sugg = if reexport {
2139 errors::ImportIdent::ThroughReExport { span: dedup_span, ident, path }
2140 } else {
2141 errors::ImportIdent::Directly { span: dedup_span, ident, path }
2142 };
2143 err.subdiagnostic(sugg);
2144 break;
2145 }
2146
2147 err.emit();
2148 }
2149
2150 pub(crate) fn find_similarly_named_module_or_crate(
2151 &mut self,
2152 ident: Symbol,
2153 current_module: Module<'ra>,
2154 ) -> Option<Symbol> {
2155 let mut candidates = self
2156 .extern_prelude
2157 .keys()
2158 .map(|ident| ident.name)
2159 .chain(
2160 self.module_map
2161 .iter()
2162 .filter(|(_, module)| {
2163 current_module.is_ancestor_of(**module) && current_module != **module
2164 })
2165 .flat_map(|(_, module)| module.kind.name()),
2166 )
2167 .filter(|c| !c.to_string().is_empty())
2168 .collect::<Vec<_>>();
2169 candidates.sort();
2170 candidates.dedup();
2171 find_best_match_for_name(&candidates, ident, None).filter(|sugg| *sugg != ident)
2172 }
2173
2174 pub(crate) fn report_path_resolution_error(
2175 &mut self,
2176 path: &[Segment],
2177 opt_ns: Option<Namespace>, parent_scope: &ParentScope<'ra>,
2179 ribs: Option<&PerNS<Vec<Rib<'ra>>>>,
2180 ignore_binding: Option<NameBinding<'ra>>,
2181 ignore_import: Option<Import<'ra>>,
2182 module: Option<ModuleOrUniformRoot<'ra>>,
2183 failed_segment_idx: usize,
2184 ident: Ident,
2185 ) -> (String, Option<Suggestion>) {
2186 let is_last = failed_segment_idx == path.len() - 1;
2187 let ns = if is_last { opt_ns.unwrap_or(TypeNS) } else { TypeNS };
2188 let module_res = match module {
2189 Some(ModuleOrUniformRoot::Module(module)) => module.res(),
2190 _ => None,
2191 };
2192 if module_res == self.graph_root.res() {
2193 let is_mod = |res| matches!(res, Res::Def(DefKind::Mod, _));
2194 let mut candidates = self.lookup_import_candidates(ident, TypeNS, parent_scope, is_mod);
2195 candidates
2196 .sort_by_cached_key(|c| (c.path.segments.len(), pprust::path_to_string(&c.path)));
2197 if let Some(candidate) = candidates.get(0) {
2198 let path = {
2199 let len = candidate.path.segments.len();
2201 let start_index = (0..=failed_segment_idx.min(len - 1))
2202 .find(|&i| path[i].ident.name != candidate.path.segments[i].ident.name)
2203 .unwrap_or_default();
2204 let segments =
2205 (start_index..len).map(|s| candidate.path.segments[s].clone()).collect();
2206 Path { segments, span: Span::default(), tokens: None }
2207 };
2208 (
2209 String::from("unresolved import"),
2210 Some((
2211 vec![(ident.span, pprust::path_to_string(&path))],
2212 String::from("a similar path exists"),
2213 Applicability::MaybeIncorrect,
2214 )),
2215 )
2216 } else if ident.name == sym::core {
2217 (
2218 format!("you might be missing crate `{ident}`"),
2219 Some((
2220 vec![(ident.span, "std".to_string())],
2221 "try using `std` instead of `core`".to_string(),
2222 Applicability::MaybeIncorrect,
2223 )),
2224 )
2225 } else if ident.name == kw::Underscore {
2226 (format!("`_` is not a valid crate or module name"), None)
2227 } else if self.tcx.sess.is_rust_2015() {
2228 (
2229 format!("use of unresolved module or unlinked crate `{ident}`"),
2230 Some((
2231 vec![(
2232 self.current_crate_outer_attr_insert_span,
2233 format!("extern crate {ident};\n"),
2234 )],
2235 if was_invoked_from_cargo() {
2236 format!(
2237 "if you wanted to use a crate named `{ident}`, use `cargo add {ident}` \
2238 to add it to your `Cargo.toml` and import it in your code",
2239 )
2240 } else {
2241 format!(
2242 "you might be missing a crate named `{ident}`, add it to your \
2243 project and import it in your code",
2244 )
2245 },
2246 Applicability::MaybeIncorrect,
2247 )),
2248 )
2249 } else {
2250 (format!("could not find `{ident}` in the crate root"), None)
2251 }
2252 } else if failed_segment_idx > 0 {
2253 let parent = path[failed_segment_idx - 1].ident.name;
2254 let parent = match parent {
2255 kw::PathRoot if self.tcx.sess.edition() > Edition::Edition2015 => {
2258 "the list of imported crates".to_owned()
2259 }
2260 kw::PathRoot | kw::Crate => "the crate root".to_owned(),
2261 _ => format!("`{parent}`"),
2262 };
2263
2264 let mut msg = format!("could not find `{ident}` in {parent}");
2265 if ns == TypeNS || ns == ValueNS {
2266 let ns_to_try = if ns == TypeNS { ValueNS } else { TypeNS };
2267 let binding = if let Some(module) = module {
2268 self.resolve_ident_in_module(
2269 module,
2270 ident,
2271 ns_to_try,
2272 parent_scope,
2273 None,
2274 ignore_binding,
2275 ignore_import,
2276 )
2277 .ok()
2278 } else if let Some(ribs) = ribs
2279 && let Some(TypeNS | ValueNS) = opt_ns
2280 {
2281 assert!(ignore_import.is_none());
2282 match self.resolve_ident_in_lexical_scope(
2283 ident,
2284 ns_to_try,
2285 parent_scope,
2286 None,
2287 &ribs[ns_to_try],
2288 ignore_binding,
2289 ) {
2290 Some(LexicalScopeBinding::Item(binding)) => Some(binding),
2292 _ => None,
2293 }
2294 } else {
2295 self.early_resolve_ident_in_lexical_scope(
2296 ident,
2297 ScopeSet::All(ns_to_try),
2298 parent_scope,
2299 None,
2300 false,
2301 ignore_binding,
2302 ignore_import,
2303 )
2304 .ok()
2305 };
2306 if let Some(binding) = binding {
2307 let mut found = |what| {
2308 msg = format!(
2309 "expected {}, found {} `{}` in {}",
2310 ns.descr(),
2311 what,
2312 ident,
2313 parent
2314 )
2315 };
2316 if binding.module().is_some() {
2317 found("module")
2318 } else {
2319 match binding.res() {
2320 Res::Def(kind, id) => found(kind.descr(id)),
2323 _ => found(ns_to_try.descr()),
2324 }
2325 }
2326 };
2327 }
2328 (msg, None)
2329 } else if ident.name == kw::SelfUpper {
2330 if opt_ns.is_none() {
2334 ("`Self` cannot be used in imports".to_string(), None)
2335 } else {
2336 (
2337 "`Self` is only available in impls, traits, and type definitions".to_string(),
2338 None,
2339 )
2340 }
2341 } else if ident.name.as_str().chars().next().is_some_and(|c| c.is_ascii_uppercase()) {
2342 let binding = if let Some(ribs) = ribs {
2344 assert!(ignore_import.is_none());
2345 self.resolve_ident_in_lexical_scope(
2346 ident,
2347 ValueNS,
2348 parent_scope,
2349 None,
2350 &ribs[ValueNS],
2351 ignore_binding,
2352 )
2353 } else {
2354 None
2355 };
2356 let match_span = match binding {
2357 Some(LexicalScopeBinding::Res(Res::Local(id))) => {
2366 Some(*self.pat_span_map.get(&id).unwrap())
2367 }
2368 Some(LexicalScopeBinding::Item(name_binding)) => Some(name_binding.span),
2380 _ => None,
2381 };
2382 let suggestion = match_span.map(|span| {
2383 (
2384 vec![(span, String::from(""))],
2385 format!("`{ident}` is defined here, but is not a type"),
2386 Applicability::MaybeIncorrect,
2387 )
2388 });
2389
2390 (format!("use of undeclared type `{ident}`"), suggestion)
2391 } else {
2392 let mut suggestion = None;
2393 if ident.name == sym::alloc {
2394 suggestion = Some((
2395 vec![],
2396 String::from("add `extern crate alloc` to use the `alloc` crate"),
2397 Applicability::MaybeIncorrect,
2398 ))
2399 }
2400
2401 suggestion = suggestion.or_else(|| {
2402 self.find_similarly_named_module_or_crate(ident.name, parent_scope.module).map(
2403 |sugg| {
2404 (
2405 vec![(ident.span, sugg.to_string())],
2406 String::from("there is a crate or module with a similar name"),
2407 Applicability::MaybeIncorrect,
2408 )
2409 },
2410 )
2411 });
2412 if let Ok(binding) = self.early_resolve_ident_in_lexical_scope(
2413 ident,
2414 ScopeSet::All(ValueNS),
2415 parent_scope,
2416 None,
2417 false,
2418 ignore_binding,
2419 ignore_import,
2420 ) {
2421 let descr = binding.res().descr();
2422 (format!("{descr} `{ident}` is not a crate or module"), suggestion)
2423 } else {
2424 let suggestion = if suggestion.is_some() {
2425 suggestion
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 #[instrument(level = "debug", skip(self, parent_scope))]
2449 pub(crate) fn make_path_suggestion(
2450 &mut self,
2451 mut path: Vec<Segment>,
2452 parent_scope: &ParentScope<'ra>,
2453 ) -> Option<(Vec<Segment>, Option<String>)> {
2454 match path[..] {
2455 [first, second, ..]
2458 if first.ident.name == kw::PathRoot && !second.ident.is_path_segment_keyword() => {}
2459 [first, ..]
2461 if first.ident.span.at_least_rust_2018()
2462 && !first.ident.is_path_segment_keyword() =>
2463 {
2464 path.insert(0, Segment::from_ident(Ident::dummy()));
2466 }
2467 _ => return None,
2468 }
2469
2470 self.make_missing_self_suggestion(path.clone(), parent_scope)
2471 .or_else(|| self.make_missing_crate_suggestion(path.clone(), parent_scope))
2472 .or_else(|| self.make_missing_super_suggestion(path.clone(), parent_scope))
2473 .or_else(|| self.make_external_crate_suggestion(path, parent_scope))
2474 }
2475
2476 #[instrument(level = "debug", skip(self, parent_scope))]
2484 fn make_missing_self_suggestion(
2485 &mut self,
2486 mut path: Vec<Segment>,
2487 parent_scope: &ParentScope<'ra>,
2488 ) -> Option<(Vec<Segment>, Option<String>)> {
2489 path[0].ident.name = kw::SelfLower;
2491 let result = self.maybe_resolve_path(&path, None, parent_scope, None);
2492 debug!(?path, ?result);
2493 if let PathResult::Module(..) = result { Some((path, None)) } else { None }
2494 }
2495
2496 #[instrument(level = "debug", skip(self, parent_scope))]
2504 fn make_missing_crate_suggestion(
2505 &mut self,
2506 mut path: Vec<Segment>,
2507 parent_scope: &ParentScope<'ra>,
2508 ) -> Option<(Vec<Segment>, Option<String>)> {
2509 path[0].ident.name = kw::Crate;
2511 let result = self.maybe_resolve_path(&path, None, parent_scope, None);
2512 debug!(?path, ?result);
2513 if let PathResult::Module(..) = result {
2514 Some((
2515 path,
2516 Some(
2517 "`use` statements changed in Rust 2018; read more at \
2518 <https://doc.rust-lang.org/edition-guide/rust-2018/module-system/path-\
2519 clarity.html>"
2520 .to_string(),
2521 ),
2522 ))
2523 } else {
2524 None
2525 }
2526 }
2527
2528 #[instrument(level = "debug", skip(self, parent_scope))]
2536 fn make_missing_super_suggestion(
2537 &mut self,
2538 mut path: Vec<Segment>,
2539 parent_scope: &ParentScope<'ra>,
2540 ) -> Option<(Vec<Segment>, Option<String>)> {
2541 path[0].ident.name = kw::Super;
2543 let result = self.maybe_resolve_path(&path, None, parent_scope, None);
2544 debug!(?path, ?result);
2545 if let PathResult::Module(..) = result { Some((path, None)) } else { None }
2546 }
2547
2548 #[instrument(level = "debug", skip(self, parent_scope))]
2559 fn make_external_crate_suggestion(
2560 &mut self,
2561 mut path: Vec<Segment>,
2562 parent_scope: &ParentScope<'ra>,
2563 ) -> Option<(Vec<Segment>, Option<String>)> {
2564 if path[1].ident.span.is_rust_2015() {
2565 return None;
2566 }
2567
2568 let mut extern_crate_names =
2572 self.extern_prelude.keys().map(|ident| ident.name).collect::<Vec<_>>();
2573 extern_crate_names.sort_by(|a, b| b.as_str().cmp(a.as_str()));
2574
2575 for name in extern_crate_names.into_iter() {
2576 path[0].ident.name = name;
2578 let result = self.maybe_resolve_path(&path, None, parent_scope, None);
2579 debug!(?path, ?name, ?result);
2580 if let PathResult::Module(..) = result {
2581 return Some((path, None));
2582 }
2583 }
2584
2585 None
2586 }
2587
2588 pub(crate) fn check_for_module_export_macro(
2601 &mut self,
2602 import: Import<'ra>,
2603 module: ModuleOrUniformRoot<'ra>,
2604 ident: Ident,
2605 ) -> Option<(Option<Suggestion>, Option<String>)> {
2606 let ModuleOrUniformRoot::Module(mut crate_module) = module else {
2607 return None;
2608 };
2609
2610 while let Some(parent) = crate_module.parent {
2611 crate_module = parent;
2612 }
2613
2614 if module == ModuleOrUniformRoot::Module(crate_module) {
2615 return None;
2617 }
2618
2619 let resolutions = self.resolutions(crate_module).borrow();
2620 let binding_key = BindingKey::new(ident, MacroNS);
2621 let resolution = resolutions.get(&binding_key)?;
2622 let binding = resolution.borrow().binding()?;
2623 let Res::Def(DefKind::Macro(MacroKind::Bang), _) = binding.res() else {
2624 return None;
2625 };
2626 let module_name = crate_module.kind.name().unwrap_or(kw::Crate);
2627 let import_snippet = match import.kind {
2628 ImportKind::Single { source, target, .. } if source != target => {
2629 format!("{source} as {target}")
2630 }
2631 _ => format!("{ident}"),
2632 };
2633
2634 let mut corrections: Vec<(Span, String)> = Vec::new();
2635 if !import.is_nested() {
2636 corrections.push((import.span, format!("{module_name}::{import_snippet}")));
2639 } else {
2640 let (found_closing_brace, binding_span) = find_span_of_binding_until_next_binding(
2644 self.tcx.sess,
2645 import.span,
2646 import.use_span,
2647 );
2648 debug!(found_closing_brace, ?binding_span);
2649
2650 let mut removal_span = binding_span;
2651
2652 if found_closing_brace
2660 && let Some(previous_span) =
2661 extend_span_to_previous_binding(self.tcx.sess, binding_span)
2662 {
2663 debug!(?previous_span);
2664 removal_span = removal_span.with_lo(previous_span.lo());
2665 }
2666 debug!(?removal_span);
2667
2668 corrections.push((removal_span, "".to_string()));
2670
2671 let (has_nested, after_crate_name) =
2678 find_span_immediately_after_crate_name(self.tcx.sess, import.use_span);
2679 debug!(has_nested, ?after_crate_name);
2680
2681 let source_map = self.tcx.sess.source_map();
2682
2683 let is_definitely_crate = import
2685 .module_path
2686 .first()
2687 .is_some_and(|f| f.ident.name != kw::SelfLower && f.ident.name != kw::Super);
2688
2689 let start_point = source_map.start_point(after_crate_name);
2691 if is_definitely_crate
2692 && let Ok(start_snippet) = source_map.span_to_snippet(start_point)
2693 {
2694 corrections.push((
2695 start_point,
2696 if has_nested {
2697 format!("{start_snippet}{import_snippet}, ")
2699 } else {
2700 format!("{{{import_snippet}, {start_snippet}")
2703 },
2704 ));
2705
2706 if !has_nested {
2708 corrections.push((source_map.end_point(after_crate_name), "};".to_string()));
2709 }
2710 } else {
2711 corrections.push((
2713 import.use_span.shrink_to_lo(),
2714 format!("use {module_name}::{import_snippet};\n"),
2715 ));
2716 }
2717 }
2718
2719 let suggestion = Some((
2720 corrections,
2721 String::from("a macro with this name exists at the root of the crate"),
2722 Applicability::MaybeIncorrect,
2723 ));
2724 Some((
2725 suggestion,
2726 Some(
2727 "this could be because a macro annotated with `#[macro_export]` will be exported \
2728 at the root of the crate instead of the module where it is defined"
2729 .to_string(),
2730 ),
2731 ))
2732 }
2733
2734 pub(crate) fn find_cfg_stripped(&self, err: &mut Diag<'_>, segment: &Symbol, module: DefId) {
2736 let local_items;
2737 let symbols = if module.is_local() {
2738 local_items = self
2739 .stripped_cfg_items
2740 .iter()
2741 .filter_map(|item| {
2742 let parent_module = self.opt_local_def_id(item.parent_module)?.to_def_id();
2743 Some(StrippedCfgItem {
2744 parent_module,
2745 ident: item.ident,
2746 cfg: item.cfg.clone(),
2747 })
2748 })
2749 .collect::<Vec<_>>();
2750 local_items.as_slice()
2751 } else {
2752 self.tcx.stripped_cfg_items(module.krate)
2753 };
2754
2755 for &StrippedCfgItem { parent_module, ident, ref cfg } in symbols {
2756 if ident.name != *segment {
2757 continue;
2758 }
2759
2760 fn comes_from_same_module_for_glob(
2761 r: &Resolver<'_, '_>,
2762 parent_module: DefId,
2763 module: DefId,
2764 visited: &mut FxHashMap<DefId, bool>,
2765 ) -> bool {
2766 if let Some(&cached) = visited.get(&parent_module) {
2767 return cached;
2771 }
2772 visited.insert(parent_module, false);
2773 let res = r.module_map.get(&parent_module).is_some_and(|m| {
2774 for importer in m.glob_importers.borrow().iter() {
2775 if let Some(next_parent_module) = importer.parent_scope.module.opt_def_id()
2776 {
2777 if next_parent_module == module
2778 || comes_from_same_module_for_glob(
2779 r,
2780 next_parent_module,
2781 module,
2782 visited,
2783 )
2784 {
2785 return true;
2786 }
2787 }
2788 }
2789 false
2790 });
2791 visited.insert(parent_module, res);
2792 res
2793 }
2794
2795 let comes_from_same_module = parent_module == module
2796 || comes_from_same_module_for_glob(
2797 self,
2798 parent_module,
2799 module,
2800 &mut Default::default(),
2801 );
2802 if !comes_from_same_module {
2803 continue;
2804 }
2805
2806 let note = errors::FoundItemConfigureOut { span: ident.span };
2807 err.subdiagnostic(note);
2808
2809 if let MetaItemKind::List(nested) = &cfg.kind
2810 && let MetaItemInner::MetaItem(meta_item) = &nested[0]
2811 && let MetaItemKind::NameValue(feature_name) = &meta_item.kind
2812 {
2813 let note = errors::ItemWasBehindFeature {
2814 feature: feature_name.symbol,
2815 span: meta_item.span,
2816 };
2817 err.subdiagnostic(note);
2818 } else {
2819 let note = errors::ItemWasCfgOut { span: cfg.span };
2820 err.subdiagnostic(note);
2821 }
2822 }
2823 }
2824}
2825
2826fn find_span_of_binding_until_next_binding(
2840 sess: &Session,
2841 binding_span: Span,
2842 use_span: Span,
2843) -> (bool, Span) {
2844 let source_map = sess.source_map();
2845
2846 let binding_until_end = binding_span.with_hi(use_span.hi());
2849
2850 let after_binding_until_end = binding_until_end.with_lo(binding_span.hi());
2853
2854 let mut found_closing_brace = false;
2861 let after_binding_until_next_binding =
2862 source_map.span_take_while(after_binding_until_end, |&ch| {
2863 if ch == '}' {
2864 found_closing_brace = true;
2865 }
2866 ch == ' ' || ch == ','
2867 });
2868
2869 let span = binding_span.with_hi(after_binding_until_next_binding.hi());
2874
2875 (found_closing_brace, span)
2876}
2877
2878fn extend_span_to_previous_binding(sess: &Session, binding_span: Span) -> Option<Span> {
2891 let source_map = sess.source_map();
2892
2893 let prev_source = source_map.span_to_prev_source(binding_span).ok()?;
2897
2898 let prev_comma = prev_source.rsplit(',').collect::<Vec<_>>();
2899 let prev_starting_brace = prev_source.rsplit('{').collect::<Vec<_>>();
2900 if prev_comma.len() <= 1 || prev_starting_brace.len() <= 1 {
2901 return None;
2902 }
2903
2904 let prev_comma = prev_comma.first().unwrap();
2905 let prev_starting_brace = prev_starting_brace.first().unwrap();
2906
2907 if prev_comma.len() > prev_starting_brace.len() {
2911 return None;
2912 }
2913
2914 Some(binding_span.with_lo(BytePos(
2915 binding_span.lo().0 - (prev_comma.as_bytes().len() as u32) - 1,
2918 )))
2919}
2920
2921#[instrument(level = "debug", skip(sess))]
2935fn find_span_immediately_after_crate_name(sess: &Session, use_span: Span) -> (bool, Span) {
2936 let source_map = sess.source_map();
2937
2938 let mut num_colons = 0;
2940 let until_second_colon = source_map.span_take_while(use_span, |c| {
2942 if *c == ':' {
2943 num_colons += 1;
2944 }
2945 !matches!(c, ':' if num_colons == 2)
2946 });
2947 let from_second_colon = use_span.with_lo(until_second_colon.hi() + BytePos(1));
2949
2950 let mut found_a_non_whitespace_character = false;
2951 let after_second_colon = source_map.span_take_while(from_second_colon, |c| {
2953 if found_a_non_whitespace_character {
2954 return false;
2955 }
2956 if !c.is_whitespace() {
2957 found_a_non_whitespace_character = true;
2958 }
2959 true
2960 });
2961
2962 let next_left_bracket = source_map.span_through_char(from_second_colon, '{');
2964
2965 (next_left_bracket == after_second_colon, from_second_colon)
2966}
2967
2968enum Instead {
2971 Yes,
2972 No,
2973}
2974
2975enum FoundUse {
2977 Yes,
2978 No,
2979}
2980
2981pub(crate) enum DiagMode {
2983 Normal,
2984 Pattern,
2986 Import {
2988 unresolved_import: bool,
2990 append: bool,
2993 },
2994}
2995
2996pub(crate) fn import_candidates(
2997 tcx: TyCtxt<'_>,
2998 err: &mut Diag<'_>,
2999 use_placement_span: Option<Span>,
3001 candidates: &[ImportSuggestion],
3002 mode: DiagMode,
3003 append: &str,
3004) {
3005 show_candidates(
3006 tcx,
3007 err,
3008 use_placement_span,
3009 candidates,
3010 Instead::Yes,
3011 FoundUse::Yes,
3012 mode,
3013 vec![],
3014 append,
3015 );
3016}
3017
3018type PathString<'a> = (String, &'a str, Option<Span>, &'a Option<String>, bool);
3019
3020fn show_candidates(
3025 tcx: TyCtxt<'_>,
3026 err: &mut Diag<'_>,
3027 use_placement_span: Option<Span>,
3029 candidates: &[ImportSuggestion],
3030 instead: Instead,
3031 found_use: FoundUse,
3032 mode: DiagMode,
3033 path: Vec<Segment>,
3034 append: &str,
3035) -> bool {
3036 if candidates.is_empty() {
3037 return false;
3038 }
3039
3040 let mut showed = false;
3041 let mut accessible_path_strings: Vec<PathString<'_>> = Vec::new();
3042 let mut inaccessible_path_strings: Vec<PathString<'_>> = Vec::new();
3043
3044 candidates.iter().for_each(|c| {
3045 if c.accessible {
3046 if c.doc_visible {
3048 accessible_path_strings.push((
3049 pprust::path_to_string(&c.path),
3050 c.descr,
3051 c.did.and_then(|did| Some(tcx.source_span(did.as_local()?))),
3052 &c.note,
3053 c.via_import,
3054 ))
3055 }
3056 } else {
3057 inaccessible_path_strings.push((
3058 pprust::path_to_string(&c.path),
3059 c.descr,
3060 c.did.and_then(|did| Some(tcx.source_span(did.as_local()?))),
3061 &c.note,
3062 c.via_import,
3063 ))
3064 }
3065 });
3066
3067 for path_strings in [&mut accessible_path_strings, &mut inaccessible_path_strings] {
3070 path_strings.sort_by(|a, b| a.0.cmp(&b.0));
3071 path_strings.dedup_by(|a, b| a.0 == b.0);
3072 let core_path_strings =
3073 path_strings.extract_if(.., |p| p.0.starts_with("core::")).collect::<Vec<_>>();
3074 let std_path_strings =
3075 path_strings.extract_if(.., |p| p.0.starts_with("std::")).collect::<Vec<_>>();
3076 let foreign_crate_path_strings =
3077 path_strings.extract_if(.., |p| !p.0.starts_with("crate::")).collect::<Vec<_>>();
3078
3079 if std_path_strings.len() == core_path_strings.len() {
3082 path_strings.extend(std_path_strings);
3084 } else {
3085 path_strings.extend(std_path_strings);
3086 path_strings.extend(core_path_strings);
3087 }
3088 path_strings.extend(foreign_crate_path_strings);
3090 }
3091
3092 if !accessible_path_strings.is_empty() {
3093 let (determiner, kind, s, name, through) =
3094 if let [(name, descr, _, _, via_import)] = &accessible_path_strings[..] {
3095 (
3096 "this",
3097 *descr,
3098 "",
3099 format!(" `{name}`"),
3100 if *via_import { " through its public re-export" } else { "" },
3101 )
3102 } else {
3103 let kinds = accessible_path_strings
3106 .iter()
3107 .map(|(_, descr, _, _, _)| *descr)
3108 .collect::<UnordSet<&str>>();
3109 let kind = if let Some(kind) = kinds.get_only() { kind } else { "item" };
3110 let s = if kind.ends_with('s') { "es" } else { "s" };
3111
3112 ("one of these", kind, s, String::new(), "")
3113 };
3114
3115 let instead = if let Instead::Yes = instead { " instead" } else { "" };
3116 let mut msg = if let DiagMode::Pattern = mode {
3117 format!(
3118 "if you meant to match on {kind}{s}{instead}{name}, use the full path in the \
3119 pattern",
3120 )
3121 } else {
3122 format!("consider importing {determiner} {kind}{s}{through}{instead}")
3123 };
3124
3125 for note in accessible_path_strings.iter().flat_map(|cand| cand.3.as_ref()) {
3126 err.note(note.clone());
3127 }
3128
3129 let append_candidates = |msg: &mut String, accessible_path_strings: Vec<PathString<'_>>| {
3130 msg.push(':');
3131
3132 for candidate in accessible_path_strings {
3133 msg.push('\n');
3134 msg.push_str(&candidate.0);
3135 }
3136 };
3137
3138 if let Some(span) = use_placement_span {
3139 let (add_use, trailing) = match mode {
3140 DiagMode::Pattern => {
3141 err.span_suggestions(
3142 span,
3143 msg,
3144 accessible_path_strings.into_iter().map(|a| a.0),
3145 Applicability::MaybeIncorrect,
3146 );
3147 return true;
3148 }
3149 DiagMode::Import { .. } => ("", ""),
3150 DiagMode::Normal => ("use ", ";\n"),
3151 };
3152 for candidate in &mut accessible_path_strings {
3153 let additional_newline = if let FoundUse::No = found_use
3156 && let DiagMode::Normal = mode
3157 {
3158 "\n"
3159 } else {
3160 ""
3161 };
3162 candidate.0 =
3163 format!("{add_use}{}{append}{trailing}{additional_newline}", candidate.0);
3164 }
3165
3166 match mode {
3167 DiagMode::Import { append: true, .. } => {
3168 append_candidates(&mut msg, accessible_path_strings);
3169 err.span_help(span, msg);
3170 }
3171 _ => {
3172 err.span_suggestions_with_style(
3173 span,
3174 msg,
3175 accessible_path_strings.into_iter().map(|a| a.0),
3176 Applicability::MaybeIncorrect,
3177 SuggestionStyle::ShowAlways,
3178 );
3179 }
3180 }
3181
3182 if let [first, .., last] = &path[..] {
3183 let sp = first.ident.span.until(last.ident.span);
3184 if sp.can_be_used_for_suggestions() && !sp.is_empty() {
3187 err.span_suggestion_verbose(
3188 sp,
3189 format!("if you import `{}`, refer to it directly", last.ident),
3190 "",
3191 Applicability::Unspecified,
3192 );
3193 }
3194 }
3195 } else {
3196 append_candidates(&mut msg, accessible_path_strings);
3197 err.help(msg);
3198 }
3199 showed = true;
3200 }
3201 if !inaccessible_path_strings.is_empty()
3202 && (!matches!(mode, DiagMode::Import { unresolved_import: false, .. }))
3203 {
3204 let prefix =
3205 if let DiagMode::Pattern = mode { "you might have meant to match on " } else { "" };
3206 if let [(name, descr, source_span, note, _)] = &inaccessible_path_strings[..] {
3207 let msg = format!(
3208 "{prefix}{descr} `{name}`{} exists but is inaccessible",
3209 if let DiagMode::Pattern = mode { ", which" } else { "" }
3210 );
3211
3212 if let Some(source_span) = source_span {
3213 let span = tcx.sess.source_map().guess_head_span(*source_span);
3214 let mut multi_span = MultiSpan::from_span(span);
3215 multi_span.push_span_label(span, "not accessible");
3216 err.span_note(multi_span, msg);
3217 } else {
3218 err.note(msg);
3219 }
3220 if let Some(note) = (*note).as_deref() {
3221 err.note(note.to_string());
3222 }
3223 } else {
3224 let (_, descr_first, _, _, _) = &inaccessible_path_strings[0];
3225 let descr = if inaccessible_path_strings
3226 .iter()
3227 .skip(1)
3228 .all(|(_, descr, _, _, _)| descr == descr_first)
3229 {
3230 descr_first
3231 } else {
3232 "item"
3233 };
3234 let plural_descr =
3235 if descr.ends_with('s') { format!("{descr}es") } else { format!("{descr}s") };
3236
3237 let mut msg = format!("{prefix}these {plural_descr} exist but are inaccessible");
3238 let mut has_colon = false;
3239
3240 let mut spans = Vec::new();
3241 for (name, _, source_span, _, _) in &inaccessible_path_strings {
3242 if let Some(source_span) = source_span {
3243 let span = tcx.sess.source_map().guess_head_span(*source_span);
3244 spans.push((name, span));
3245 } else {
3246 if !has_colon {
3247 msg.push(':');
3248 has_colon = true;
3249 }
3250 msg.push('\n');
3251 msg.push_str(name);
3252 }
3253 }
3254
3255 let mut multi_span = MultiSpan::from_spans(spans.iter().map(|(_, sp)| *sp).collect());
3256 for (name, span) in spans {
3257 multi_span.push_span_label(span, format!("`{name}`: not accessible"));
3258 }
3259
3260 for note in inaccessible_path_strings.iter().flat_map(|cand| cand.3.as_ref()) {
3261 err.note(note.clone());
3262 }
3263
3264 err.span_note(multi_span, msg);
3265 }
3266 showed = true;
3267 }
3268 showed
3269}
3270
3271#[derive(Debug)]
3272struct UsePlacementFinder {
3273 target_module: NodeId,
3274 first_legal_span: Option<Span>,
3275 first_use_span: Option<Span>,
3276}
3277
3278impl UsePlacementFinder {
3279 fn check(krate: &Crate, target_module: NodeId) -> (Option<Span>, FoundUse) {
3280 let mut finder =
3281 UsePlacementFinder { target_module, first_legal_span: None, first_use_span: None };
3282 finder.visit_crate(krate);
3283 if let Some(use_span) = finder.first_use_span {
3284 (Some(use_span), FoundUse::Yes)
3285 } else {
3286 (finder.first_legal_span, FoundUse::No)
3287 }
3288 }
3289}
3290
3291impl<'tcx> visit::Visitor<'tcx> for UsePlacementFinder {
3292 fn visit_crate(&mut self, c: &Crate) {
3293 if self.target_module == CRATE_NODE_ID {
3294 let inject = c.spans.inject_use_span;
3295 if is_span_suitable_for_use_injection(inject) {
3296 self.first_legal_span = Some(inject);
3297 }
3298 self.first_use_span = search_for_any_use_in_items(&c.items);
3299 } else {
3300 visit::walk_crate(self, c);
3301 }
3302 }
3303
3304 fn visit_item(&mut self, item: &'tcx ast::Item) {
3305 if self.target_module == item.id {
3306 if let ItemKind::Mod(_, _, ModKind::Loaded(items, _inline, mod_spans, _)) = &item.kind {
3307 let inject = mod_spans.inject_use_span;
3308 if is_span_suitable_for_use_injection(inject) {
3309 self.first_legal_span = Some(inject);
3310 }
3311 self.first_use_span = search_for_any_use_in_items(items);
3312 }
3313 } else {
3314 visit::walk_item(self, item);
3315 }
3316 }
3317}
3318
3319fn search_for_any_use_in_items(items: &[P<ast::Item>]) -> Option<Span> {
3320 for item in items {
3321 if let ItemKind::Use(..) = item.kind
3322 && is_span_suitable_for_use_injection(item.span)
3323 {
3324 let mut lo = item.span.lo();
3325 for attr in &item.attrs {
3326 if attr.span.eq_ctxt(item.span) {
3327 lo = std::cmp::min(lo, attr.span.lo());
3328 }
3329 }
3330 return Some(Span::new(lo, lo, item.span.ctxt(), item.span.parent()));
3331 }
3332 }
3333 None
3334}
3335
3336fn is_span_suitable_for_use_injection(s: Span) -> bool {
3337 !s.from_expansion()
3340}