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