3 use rustc_ast
::{self as ast, Path}
;
4 use rustc_ast_pretty
::pprust
;
5 use rustc_data_structures
::fx
::FxHashSet
;
6 use rustc_errors
::{struct_span_err, Applicability, DiagnosticBuilder}
;
7 use rustc_feature
::BUILTIN_ATTRIBUTES
;
8 use rustc_hir
::def
::Namespace
::{self, *}
;
9 use rustc_hir
::def
::{self, CtorKind, CtorOf, DefKind, NonMacroAttrKind}
;
10 use rustc_hir
::def_id
::{DefId, CRATE_DEF_INDEX, LOCAL_CRATE}
;
11 use rustc_hir
::PrimTy
;
12 use rustc_middle
::bug
;
13 use rustc_middle
::ty
::DefIdTree
;
14 use rustc_session
::Session
;
15 use rustc_span
::hygiene
::MacroKind
;
16 use rustc_span
::lev_distance
::find_best_match_for_name
;
17 use rustc_span
::source_map
::SourceMap
;
18 use rustc_span
::symbol
::{kw, sym, Ident, Symbol}
;
19 use rustc_span
::{BytePos, MultiSpan, Span}
;
22 use crate::imports
::{Import, ImportKind, ImportResolver}
;
23 use crate::path_names_to_string
;
24 use crate::{AmbiguityError, AmbiguityErrorMisc, AmbiguityKind}
;
26 BindingError
, CrateLint
, HasGenericParams
, MacroRulesScope
, Module
, ModuleOrUniformRoot
,
28 use crate::{NameBinding, NameBindingKind, PrivacyError, VisResolutionError}
;
29 use crate::{ParentScope, PathResult, ResolutionError, Resolver, Scope, ScopeSet, Segment}
;
31 type Res
= def
::Res
<ast
::NodeId
>;
33 /// A vector of spans and replacements, a message and applicability.
34 crate type Suggestion
= (Vec
<(Span
, String
)>, String
, Applicability
);
36 /// Potential candidate for an undeclared or out-of-scope label - contains the ident of a
37 /// similarly named label and whether or not it is reachable.
38 crate type LabelSuggestion
= (Ident
, bool
);
40 crate enum SuggestionTarget
{
41 /// The target has a similar name as the name used by the programmer (probably a typo)
43 /// The target is the only valid item that can be used in the corresponding context
47 crate struct TypoSuggestion
{
48 pub candidate
: Symbol
,
50 pub target
: SuggestionTarget
,
54 crate fn typo_from_res(candidate
: Symbol
, res
: Res
) -> TypoSuggestion
{
55 Self { candidate, res, target: SuggestionTarget::SimilarlyNamed }
57 crate fn single_item_from_res(candidate
: Symbol
, res
: Res
) -> TypoSuggestion
{
58 Self { candidate, res, target: SuggestionTarget::SingleItem }
62 /// A free importable items suggested in case of resolution failure.
63 crate struct ImportSuggestion
{
64 pub did
: Option
<DefId
>,
65 pub descr
: &'
static str,
68 /// An extra note that should be issued if this item is suggested
69 pub note
: Option
<String
>,
72 /// Adjust the impl span so that just the `impl` keyword is taken by removing
73 /// everything after `<` (`"impl<T> Iterator for A<T> {}" -> "impl"`) and
74 /// everything after the first whitespace (`"impl Iterator for A" -> "impl"`).
76 /// *Attention*: the method used is very fragile since it essentially duplicates the work of the
77 /// parser. If you need to use this function or something similar, please consider updating the
78 /// `source_map` functions and this function to something more robust.
79 fn reduce_impl_span_to_impl_keyword(sm
: &SourceMap
, impl_span
: Span
) -> Span
{
80 let impl_span
= sm
.span_until_char(impl_span
, '
<'
);
81 sm
.span_until_whitespace(impl_span
)
84 impl<'a
> Resolver
<'a
> {
85 crate fn add_module_candidates(
88 names
: &mut Vec
<TypoSuggestion
>,
89 filter_fn
: &impl Fn(Res
) -> bool
,
91 for (key
, resolution
) in self.resolutions(module
).borrow().iter() {
92 if let Some(binding
) = resolution
.borrow().binding
{
93 let res
= binding
.res();
95 names
.push(TypoSuggestion
::typo_from_res(key
.ident
.name
, res
));
101 /// Combines an error with provided span and emits it.
103 /// This takes the error provided, combines it with the span and any additional spans inside the
104 /// error and emits it.
105 crate fn report_error(&self, span
: Span
, resolution_error
: ResolutionError
<'_
>) {
106 self.into_struct_error(span
, resolution_error
).emit();
109 crate fn into_struct_error(
112 resolution_error
: ResolutionError
<'_
>,
113 ) -> DiagnosticBuilder
<'_
> {
114 match resolution_error
{
115 ResolutionError
::GenericParamsFromOuterFunction(outer_res
, has_generic_params
) => {
116 let mut err
= struct_span_err
!(
120 "can't use generic parameters from outer function",
122 err
.span_label(span
, "use of generic parameter from outer function".to_string());
124 let sm
= self.session
.source_map();
126 Res
::SelfTy(maybe_trait_defid
, maybe_impl_defid
) => {
127 if let Some(impl_span
) =
128 maybe_impl_defid
.and_then(|(def_id
, _
)| self.opt_span(def_id
))
131 reduce_impl_span_to_impl_keyword(sm
, impl_span
),
132 "`Self` type implicitly declared here, by this `impl`",
135 match (maybe_trait_defid
, maybe_impl_defid
) {
137 err
.span_label(span
, "can't use `Self` here");
140 err
.span_label(span
, "use a type here instead");
142 (None
, None
) => bug
!("`impl` without trait nor type?"),
146 Res
::Def(DefKind
::TyParam
, def_id
) => {
147 if let Some(span
) = self.opt_span(def_id
) {
148 err
.span_label(span
, "type parameter from outer function");
151 Res
::Def(DefKind
::ConstParam
, def_id
) => {
152 if let Some(span
) = self.opt_span(def_id
) {
153 err
.span_label(span
, "const parameter from outer function");
158 "GenericParamsFromOuterFunction should only be used with Res::SelfTy, \
159 DefKind::TyParam or DefKind::ConstParam"
164 if has_generic_params
== HasGenericParams
::Yes
{
165 // Try to retrieve the span of the function signature and generate a new
166 // message with a local type or const parameter.
167 let sugg_msg
= "try using a local generic parameter instead";
168 if let Some((sugg_span
, snippet
)) = sm
.generate_local_type_param_snippet(span
) {
169 // Suggest the modification to the user
174 Applicability
::MachineApplicable
,
176 } else if let Some(sp
) = sm
.generate_fn_name_span(span
) {
179 "try adding a local generic parameter in this method instead"
183 err
.help("try using a local generic parameter instead");
189 ResolutionError
::NameAlreadyUsedInParameterList(name
, first_use_span
) => {
190 let mut err
= struct_span_err
!(
194 "the name `{}` is already used for a generic \
195 parameter in this item's generic parameters",
198 err
.span_label(span
, "already used");
199 err
.span_label(first_use_span
, format
!("first use of `{}`", name
));
202 ResolutionError
::MethodNotMemberOfTrait(method
, trait_
, candidate
) => {
203 let mut err
= struct_span_err
!(
207 "method `{}` is not a member of trait `{}`",
211 err
.span_label(span
, format
!("not a member of trait `{}`", trait_
));
212 if let Some(candidate
) = candidate
{
215 "there is an associated function with a similar name",
216 candidate
.to_ident_string(),
217 Applicability
::MaybeIncorrect
,
222 ResolutionError
::TypeNotMemberOfTrait(type_
, trait_
, candidate
) => {
223 let mut err
= struct_span_err
!(
227 "type `{}` is not a member of trait `{}`",
231 err
.span_label(span
, format
!("not a member of trait `{}`", trait_
));
232 if let Some(candidate
) = candidate
{
235 "there is an associated type with a similar name",
236 candidate
.to_ident_string(),
237 Applicability
::MaybeIncorrect
,
242 ResolutionError
::ConstNotMemberOfTrait(const_
, trait_
, candidate
) => {
243 let mut err
= struct_span_err
!(
247 "const `{}` is not a member of trait `{}`",
251 err
.span_label(span
, format
!("not a member of trait `{}`", trait_
));
252 if let Some(candidate
) = candidate
{
255 "there is an associated constant with a similar name",
256 candidate
.to_ident_string(),
257 Applicability
::MaybeIncorrect
,
262 ResolutionError
::VariableNotBoundInPattern(binding_error
) => {
263 let BindingError { name, target, origin, could_be_path }
= binding_error
;
265 let target_sp
= target
.iter().copied().collect
::<Vec
<_
>>();
266 let origin_sp
= origin
.iter().copied().collect
::<Vec
<_
>>();
268 let msp
= MultiSpan
::from_spans(target_sp
.clone());
269 let mut err
= struct_span_err
!(
273 "variable `{}` is not bound in all patterns",
276 for sp
in target_sp
{
277 err
.span_label(sp
, format
!("pattern doesn't bind `{}`", name
));
279 for sp
in origin_sp
{
280 err
.span_label(sp
, "variable not in all patterns");
283 let help_msg
= format
!(
284 "if you meant to match on a variant or a `const` item, consider \
285 making the path in the pattern qualified: `?::{}`",
288 err
.span_help(span
, &help_msg
);
292 ResolutionError
::VariableBoundWithDifferentMode(variable_name
, first_binding_span
) => {
293 let mut err
= struct_span_err
!(
297 "variable `{}` is bound inconsistently across alternatives separated by `|`",
300 err
.span_label(span
, "bound in different ways");
301 err
.span_label(first_binding_span
, "first binding");
304 ResolutionError
::IdentifierBoundMoreThanOnceInParameterList(identifier
) => {
305 let mut err
= struct_span_err
!(
309 "identifier `{}` is bound more than once in this parameter list",
312 err
.span_label(span
, "used as parameter more than once");
315 ResolutionError
::IdentifierBoundMoreThanOnceInSamePattern(identifier
) => {
316 let mut err
= struct_span_err
!(
320 "identifier `{}` is bound more than once in the same pattern",
323 err
.span_label(span
, "used in a pattern more than once");
326 ResolutionError
::UndeclaredLabel { name, suggestion }
=> {
327 let mut err
= struct_span_err
!(
331 "use of undeclared label `{}`",
335 err
.span_label(span
, format
!("undeclared label `{}`", name
));
338 // A reachable label with a similar name exists.
339 Some((ident
, true)) => {
340 err
.span_label(ident
.span
, "a label with a similar name is reachable");
343 "try using similarly named label",
344 ident
.name
.to_string(),
345 Applicability
::MaybeIncorrect
,
348 // An unreachable label with a similar name exists.
349 Some((ident
, false)) => {
352 "a label with a similar name exists but is unreachable",
355 // No similarly-named labels exist.
361 ResolutionError
::SelfImportsOnlyAllowedWithin { root, span_with_rename }
=> {
362 let mut err
= struct_span_err
!(
367 "`self` imports are only allowed within a { } list"
370 // None of the suggestions below would help with a case like `use self`.
372 // use foo::bar::self -> foo::bar
373 // use foo::bar::self as abc -> foo::bar as abc
376 "consider importing the module directly",
378 Applicability
::MachineApplicable
,
381 // use foo::bar::self -> foo::bar::{self}
382 // use foo::bar::self as abc -> foo::bar::{self as abc}
384 (span_with_rename
.shrink_to_lo(), "{".to_string()),
385 (span_with_rename
.shrink_to_hi(), "}".to_string()),
387 err
.multipart_suggestion(
388 "alternatively, use the multi-path `use` syntax to import `self`",
390 Applicability
::MachineApplicable
,
395 ResolutionError
::SelfImportCanOnlyAppearOnceInTheList
=> {
396 let mut err
= struct_span_err
!(
400 "`self` import can only appear once in an import list"
402 err
.span_label(span
, "can only appear once in an import list");
405 ResolutionError
::SelfImportOnlyInImportListWithNonEmptyPrefix
=> {
406 let mut err
= struct_span_err
!(
410 "`self` import can only appear in an import list with \
413 err
.span_label(span
, "can only appear in an import list with a non-empty prefix");
416 ResolutionError
::FailedToResolve { label, suggestion }
=> {
418 struct_span_err
!(self.session
, span
, E0433
, "failed to resolve: {}", &label
);
419 err
.span_label(span
, label
);
421 if let Some((suggestions
, msg
, applicability
)) = suggestion
{
422 if suggestions
.is_empty() {
426 err
.multipart_suggestion(&msg
, suggestions
, applicability
);
431 ResolutionError
::CannotCaptureDynamicEnvironmentInFnItem
=> {
432 let mut err
= struct_span_err
!(
437 "can't capture dynamic environment in a fn item"
439 err
.help("use the `|| { ... }` closure form instead");
442 ResolutionError
::AttemptToUseNonConstantValueInConstant(ident
, sugg
, current
) => {
443 let mut err
= struct_span_err
!(
447 "attempt to use a non-constant value in a constant"
450 // ^^^ given this Span
451 // ------- get this Span to have an applicable suggestion
454 // only do this if the const and usage of the non-constant value are on the same line
455 // the further the two are apart, the higher the chance of the suggestion being wrong
456 // also make sure that the pos for the suggestion is not 0 (ICE #90878)
459 self.session
.source_map().span_extend_to_prev_str(ident
.span
, current
, true);
461 let pos_for_suggestion
= sp
.lo().0.saturating_sub(current
.len() as u32);
464 || pos_for_suggestion
== 0
465 || self.session
.source_map().is_multiline(sp
)
467 err
.span_label(ident
.span
, &format
!("this would need to be a `{}`", sugg
));
469 let sp
= sp
.with_lo(BytePos(pos_for_suggestion
));
472 &format
!("consider using `{}` instead of `{}`", sugg
, current
),
473 format
!("{} {}", sugg
, ident
),
474 Applicability
::MaybeIncorrect
,
476 err
.span_label(span
, "non-constant value");
480 ResolutionError
::BindingShadowsSomethingUnacceptable
{
481 shadowing_binding_descr
,
485 shadowed_binding_descr
,
486 shadowed_binding_span
,
488 let mut err
= struct_span_err
!(
492 "{}s cannot shadow {}s",
493 shadowing_binding_descr
,
494 shadowed_binding_descr
,
498 format
!("cannot be named the same as {} {}", article
, shadowed_binding_descr
),
501 format
!("the {} `{}` is {} here", shadowed_binding_descr
, name
, participle
);
502 err
.span_label(shadowed_binding_span
, msg
);
505 ResolutionError
::ForwardDeclaredGenericParam
=> {
506 let mut err
= struct_span_err
!(
510 "generic parameters with a default cannot use \
511 forward declared identifiers"
515 "defaulted generic parameters cannot be forward declared".to_string(),
519 ResolutionError
::ParamInTyOfConstParam(name
) => {
520 let mut err
= struct_span_err
!(
524 "the type of const parameters must not depend on other generic parameters"
528 format
!("the type must not depend on the parameter `{}`", name
),
532 ResolutionError
::ParamInNonTrivialAnonConst { name, is_type }
=> {
533 let mut err
= self.session
.struct_span_err(
535 "generic parameters may not be used in const operations",
537 err
.span_label(span
, &format
!("cannot perform const operation using `{}`", name
));
540 err
.note("type parameters may not be used in const expressions");
543 "const parameters may only be used as standalone arguments, i.e. `{}`",
548 if self.session
.is_nightly_build() {
550 "use `#![feature(generic_const_exprs)]` to allow generic const expressions",
556 ResolutionError
::SelfInGenericParamDefault
=> {
557 let mut err
= struct_span_err
!(
561 "generic parameters cannot use `Self` in their defaults"
563 err
.span_label(span
, "`Self` in generic parameter default".to_string());
566 ResolutionError
::UnreachableLabel { name, definition_span, suggestion }
=> {
567 let mut err
= struct_span_err
!(
571 "use of unreachable label `{}`",
575 err
.span_label(definition_span
, "unreachable label defined here");
576 err
.span_label(span
, format
!("unreachable label `{}`", name
));
578 "labels are unreachable through functions, closures, async blocks and modules",
582 // A reachable label with a similar name exists.
583 Some((ident
, true)) => {
584 err
.span_label(ident
.span
, "a label with a similar name is reachable");
587 "try using similarly named label",
588 ident
.name
.to_string(),
589 Applicability
::MaybeIncorrect
,
592 // An unreachable label with a similar name exists.
593 Some((ident
, false)) => {
596 "a label with a similar name exists but is also unreachable",
599 // No similarly-named labels exist.
608 crate fn report_vis_error(&self, vis_resolution_error
: VisResolutionError
<'_
>) {
609 match vis_resolution_error
{
610 VisResolutionError
::Relative2018(span
, path
) => {
611 let mut err
= self.session
.struct_span_err(
613 "relative paths are not supported in visibilities on 2018 edition",
618 format
!("crate::{}", pprust
::path_to_string(&path
)),
619 Applicability
::MaybeIncorrect
,
623 VisResolutionError
::AncestorOnly(span
) => struct_span_err
!(
627 "visibilities can only be restricted to ancestor modules"
629 VisResolutionError
::FailedToResolve(span
, label
, suggestion
) => {
630 self.into_struct_error(span
, ResolutionError
::FailedToResolve { label, suggestion }
)
632 VisResolutionError
::ExpectedFound(span
, path_str
, res
) => {
633 let mut err
= struct_span_err
!(
637 "expected module, found {} `{}`",
641 err
.span_label(span
, "not a module");
644 VisResolutionError
::Indeterminate(span
) => struct_span_err
!(
648 "cannot determine resolution for the visibility"
650 VisResolutionError
::ModuleOnly(span
) => {
651 self.session
.struct_span_err(span
, "visibility must resolve to a module")
657 /// Lookup typo candidate in scope for a macro or import.
658 fn early_lookup_typo_candidate(
660 scope_set
: ScopeSet
<'a
>,
661 parent_scope
: &ParentScope
<'a
>,
663 filter_fn
: &impl Fn(Res
) -> bool
,
664 ) -> Option
<TypoSuggestion
> {
665 let mut suggestions
= Vec
::new();
666 let ctxt
= ident
.span
.ctxt();
667 self.visit_scopes(scope_set
, parent_scope
, ctxt
, |this
, scope
, use_prelude
, _
| {
669 Scope
::DeriveHelpers(expn_id
) => {
670 let res
= Res
::NonMacroAttr(NonMacroAttrKind
::DeriveHelper
);
677 .map(|ident
| TypoSuggestion
::typo_from_res(ident
.name
, res
)),
681 Scope
::DeriveHelpersCompat
=> {
682 let res
= Res
::NonMacroAttr(NonMacroAttrKind
::DeriveHelperCompat
);
684 for derive
in parent_scope
.derives
{
685 let parent_scope
= &ParentScope { derives: &[], ..*parent_scope }
;
686 if let Ok((Some(ext
), _
)) = this
.resolve_macro_path(
688 Some(MacroKind
::Derive
),
696 .map(|name
| TypoSuggestion
::typo_from_res(*name
, res
)),
702 Scope
::MacroRules(macro_rules_scope
) => {
703 if let MacroRulesScope
::Binding(macro_rules_binding
) = macro_rules_scope
.get() {
704 let res
= macro_rules_binding
.binding
.res();
706 suggestions
.push(TypoSuggestion
::typo_from_res(
707 macro_rules_binding
.ident
.name
,
713 Scope
::CrateRoot
=> {
714 let root_ident
= Ident
::new(kw
::PathRoot
, ident
.span
);
715 let root_module
= this
.resolve_crate_root(root_ident
);
716 this
.add_module_candidates(root_module
, &mut suggestions
, filter_fn
);
718 Scope
::Module(module
, _
) => {
719 this
.add_module_candidates(module
, &mut suggestions
, filter_fn
);
721 Scope
::RegisteredAttrs
=> {
722 let res
= Res
::NonMacroAttr(NonMacroAttrKind
::Registered
);
725 this
.registered_attrs
727 .map(|ident
| TypoSuggestion
::typo_from_res(ident
.name
, res
)),
731 Scope
::MacroUsePrelude
=> {
732 suggestions
.extend(this
.macro_use_prelude
.iter().filter_map(
734 let res
= binding
.res();
735 filter_fn(res
).then_some(TypoSuggestion
::typo_from_res(*name
, res
))
739 Scope
::BuiltinAttrs
=> {
740 let res
= Res
::NonMacroAttr(NonMacroAttrKind
::Builtin(kw
::Empty
));
745 .map(|attr
| TypoSuggestion
::typo_from_res(attr
.name
, res
)),
749 Scope
::ExternPrelude
=> {
750 suggestions
.extend(this
.extern_prelude
.iter().filter_map(|(ident
, _
)| {
751 let res
= Res
::Def(DefKind
::Mod
, DefId
::local(CRATE_DEF_INDEX
));
752 filter_fn(res
).then_some(TypoSuggestion
::typo_from_res(ident
.name
, res
))
755 Scope
::ToolPrelude
=> {
756 let res
= Res
::NonMacroAttr(NonMacroAttrKind
::Tool
);
758 this
.registered_tools
760 .map(|ident
| TypoSuggestion
::typo_from_res(ident
.name
, res
)),
763 Scope
::StdLibPrelude
=> {
764 if let Some(prelude
) = this
.prelude
{
765 let mut tmp_suggestions
= Vec
::new();
766 this
.add_module_candidates(prelude
, &mut tmp_suggestions
, filter_fn
);
770 .filter(|s
| use_prelude
|| this
.is_builtin_macro(s
.res
)),
774 Scope
::BuiltinTypes
=> {
775 suggestions
.extend(PrimTy
::ALL
.iter().filter_map(|prim_ty
| {
776 let res
= Res
::PrimTy(*prim_ty
);
777 filter_fn(res
).then_some(TypoSuggestion
::typo_from_res(prim_ty
.name(), res
))
785 // Make sure error reporting is deterministic.
786 suggestions
.sort_by(|a
, b
| a
.candidate
.as_str().partial_cmp(b
.candidate
.as_str()).unwrap());
788 match find_best_match_for_name(
789 &suggestions
.iter().map(|suggestion
| suggestion
.candidate
).collect
::<Vec
<Symbol
>>(),
793 Some(found
) if found
!= ident
.name
=> {
794 suggestions
.into_iter().find(|suggestion
| suggestion
.candidate
== found
)
800 fn lookup_import_candidates_from_module
<FilterFn
>(
803 namespace
: Namespace
,
804 parent_scope
: &ParentScope
<'a
>,
805 start_module
: Module
<'a
>,
808 ) -> Vec
<ImportSuggestion
>
810 FilterFn
: Fn(Res
) -> bool
,
812 let mut candidates
= Vec
::new();
813 let mut seen_modules
= FxHashSet
::default();
814 let mut worklist
= vec
![(start_module
, Vec
::<ast
::PathSegment
>::new(), true)];
815 let mut worklist_via_import
= vec
![];
817 while let Some((in_module
, path_segments
, accessible
)) = match worklist
.pop() {
818 None
=> worklist_via_import
.pop(),
821 let in_module_is_extern
= !in_module
.def_id().is_local();
822 // We have to visit module children in deterministic order to avoid
823 // instabilities in reported imports (#43552).
824 in_module
.for_each_child(self, |this
, ident
, ns
, name_binding
| {
825 // avoid non-importable candidates
826 if !name_binding
.is_importable() {
830 let child_accessible
=
831 accessible
&& this
.is_accessible_from(name_binding
.vis
, parent_scope
.module
);
833 // do not venture inside inaccessible items of other crates
834 if in_module_is_extern
&& !child_accessible
{
838 let via_import
= name_binding
.is_import() && !name_binding
.is_extern_crate();
840 // There is an assumption elsewhere that paths of variants are in the enum's
841 // declaration and not imported. With this assumption, the variant component is
842 // chopped and the rest of the path is assumed to be the enum's own path. For
843 // errors where a variant is used as the type instead of the enum, this causes
844 // funny looking invalid suggestions, i.e `foo` instead of `foo::MyEnum`.
845 if via_import
&& name_binding
.is_possibly_imported_variant() {
849 // #90113: Do not count an inaccessible reexported item as a candidate.
850 if let NameBindingKind
::Import { binding, .. }
= name_binding
.kind
{
851 if this
.is_accessible_from(binding
.vis
, parent_scope
.module
)
852 && !this
.is_accessible_from(name_binding
.vis
, parent_scope
.module
)
858 // collect results based on the filter function
859 // avoid suggesting anything from the same module in which we are resolving
860 // avoid suggesting anything with a hygienic name
861 if ident
.name
== lookup_ident
.name
863 && !ptr
::eq(in_module
, parent_scope
.module
)
864 && !ident
.span
.normalize_to_macros_2_0().from_expansion()
866 let res
= name_binding
.res();
869 let mut segms
= path_segments
.clone();
870 if lookup_ident
.span
.rust_2018() {
871 // crate-local absolute paths start with `crate::` in edition 2018
872 // FIXME: may also be stabilized for Rust 2015 (Issues #45477, #44660)
873 segms
.insert(0, ast
::PathSegment
::from_ident(crate_name
));
876 segms
.push(ast
::PathSegment
::from_ident(ident
));
877 let path
= Path { span: name_binding.span, segments: segms, tokens: None }
;
878 let did
= match res
{
879 Res
::Def(DefKind
::Ctor(..), did
) => this
.parent(did
),
880 _
=> res
.opt_def_id(),
883 if child_accessible
{
884 // Remove invisible match if exists
885 if let Some(idx
) = candidates
887 .position(|v
: &ImportSuggestion
| v
.did
== did
&& !v
.accessible
)
889 candidates
.remove(idx
);
893 if candidates
.iter().all(|v
: &ImportSuggestion
| v
.did
!= did
) {
894 // See if we're recommending TryFrom, TryInto, or FromIterator and add
895 // a note about editions
896 let note
= if let Some(did
) = did
{
897 let requires_note
= !did
.is_local()
900 .item_attrs_untracked(did
, this
.session
)
903 if attr
.has_name(sym
::rustc_diagnostic_item
) {
904 [sym
::TryInto
, sym
::TryFrom
, sym
::FromIterator
]
906 .contains(&attr
.value_str())
912 requires_note
.then(|| {
914 "'{}' is included in the prelude starting in Edition 2021",
915 path_names_to_string(&path
)
922 candidates
.push(ImportSuggestion
{
926 accessible
: child_accessible
,
933 // collect submodules to explore
934 if let Some(module
) = name_binding
.module() {
936 let mut path_segments
= path_segments
.clone();
937 path_segments
.push(ast
::PathSegment
::from_ident(ident
));
939 let is_extern_crate_that_also_appears_in_prelude
=
940 name_binding
.is_extern_crate() && lookup_ident
.span
.rust_2018();
942 if !is_extern_crate_that_also_appears_in_prelude
{
943 // add the module to the lookup
944 if seen_modules
.insert(module
.def_id()) {
945 if via_import { &mut worklist_via_import }
else { &mut worklist }
946 .push((module
, path_segments
, child_accessible
));
953 // If only some candidates are accessible, take just them
954 if !candidates
.iter().all(|v
: &ImportSuggestion
| !v
.accessible
) {
955 candidates
= candidates
.into_iter().filter(|x
| x
.accessible
).collect();
961 /// When name resolution fails, this method can be used to look up candidate
962 /// entities with the expected name. It allows filtering them using the
963 /// supplied predicate (which should be used to only accept the types of
964 /// definitions expected, e.g., traits). The lookup spans across all crates.
966 /// N.B., the method does not look into imports, but this is not a problem,
967 /// since we report the definitions (thus, the de-aliased imports).
968 crate fn lookup_import_candidates
<FilterFn
>(
971 namespace
: Namespace
,
972 parent_scope
: &ParentScope
<'a
>,
974 ) -> Vec
<ImportSuggestion
>
976 FilterFn
: Fn(Res
) -> bool
,
978 let mut suggestions
= self.lookup_import_candidates_from_module(
983 Ident
::with_dummy_span(kw
::Crate
),
987 if lookup_ident
.span
.rust_2018() {
988 let extern_prelude_names
= self.extern_prelude
.clone();
989 for (ident
, _
) in extern_prelude_names
.into_iter() {
990 if ident
.span
.from_expansion() {
991 // Idents are adjusted to the root context before being
992 // resolved in the extern prelude, so reporting this to the
993 // user is no help. This skips the injected
994 // `extern crate std` in the 2018 edition, which would
995 // otherwise cause duplicate suggestions.
998 if let Some(crate_id
) = self.crate_loader
.maybe_process_path_extern(ident
.name
) {
999 let crate_root
= self.expect_module(crate_id
.as_def_id());
1000 suggestions
.extend(self.lookup_import_candidates_from_module(
1015 crate fn unresolved_macro_suggestions(
1017 err
: &mut DiagnosticBuilder
<'a
>,
1018 macro_kind
: MacroKind
,
1019 parent_scope
: &ParentScope
<'a
>,
1022 let is_expected
= &|res
: Res
| res
.macro_kind() == Some(macro_kind
);
1023 let suggestion
= self.early_lookup_typo_candidate(
1024 ScopeSet
::Macro(macro_kind
),
1029 self.add_typo_suggestion(err
, suggestion
, ident
.span
);
1031 let import_suggestions
=
1032 self.lookup_import_candidates(ident
, Namespace
::MacroNS
, parent_scope
, is_expected
);
1038 &import_suggestions
,
1043 if macro_kind
== MacroKind
::Derive
&& (ident
.name
== sym
::Send
|| ident
.name
== sym
::Sync
) {
1044 let msg
= format
!("unsafe traits like `{}` should be implemented explicitly", ident
);
1045 err
.span_note(ident
.span
, &msg
);
1048 if self.macro_names
.contains(&ident
.normalize_to_macros_2_0()) {
1049 err
.help("have you added the `#[macro_use]` on the module/import?");
1052 for ns
in [Namespace
::MacroNS
, Namespace
::TypeNS
, Namespace
::ValueNS
] {
1053 if let Ok(binding
) = self.early_resolve_ident_in_lexical_scope(
1055 ScopeSet
::All(ns
, false),
1061 let desc
= match binding
.res() {
1062 Res
::Def(DefKind
::Macro(MacroKind
::Bang
), _
) => {
1063 "a function-like macro".to_string()
1065 Res
::Def(DefKind
::Macro(MacroKind
::Attr
), _
) | Res
::NonMacroAttr(..) => {
1066 format
!("an attribute: `#[{}]`", ident
)
1068 Res
::Def(DefKind
::Macro(MacroKind
::Derive
), _
) => {
1069 format
!("a derive macro: `#[derive({})]`", ident
)
1072 // Don't confuse the user with tool modules.
1075 Res
::Def(DefKind
::Trait
, _
) if macro_kind
== MacroKind
::Derive
=> {
1076 "only a trait, without a derive macro".to_string()
1082 macro_kind
.article(),
1083 macro_kind
.descr_expected(),
1086 if let crate::NameBindingKind
::Import { import, .. }
= binding
.kind
{
1087 if !import
.span
.is_dummy() {
1090 &format
!("`{}` is imported here, but it is {}", ident
, desc
),
1092 // Silence the 'unused import' warning we might get,
1093 // since this diagnostic already covers that import.
1094 self.record_use(ident
, binding
, false);
1098 err
.note(&format
!("`{}` is in scope, but it is {}", ident
, desc
));
1104 crate fn add_typo_suggestion(
1106 err
: &mut DiagnosticBuilder
<'_
>,
1107 suggestion
: Option
<TypoSuggestion
>,
1110 let suggestion
= match suggestion
{
1111 None
=> return false,
1112 // We shouldn't suggest underscore.
1113 Some(suggestion
) if suggestion
.candidate
== kw
::Underscore
=> return false,
1114 Some(suggestion
) => suggestion
,
1116 let def_span
= suggestion
.res
.opt_def_id().and_then(|def_id
| match def_id
.krate
{
1117 LOCAL_CRATE
=> self.opt_span(def_id
),
1121 .guess_head_span(self.cstore().get_span_untracked(def_id
, self.session
)),
1124 if let Some(def_span
) = def_span
{
1125 if span
.overlaps(def_span
) {
1126 // Don't suggest typo suggestion for itself like in the following:
1127 // error[E0423]: expected function, tuple struct or tuple variant, found struct `X`
1128 // --> $DIR/issue-64792-bad-unicode-ctor.rs:3:14
1131 // | ----------- `X` defined here
1133 // LL | const Y: X = X("ö");
1134 // | -------------^^^^^^- similarly named constant `Y` defined here
1136 // help: use struct literal syntax instead
1138 // LL | const Y: X = X {};
1140 // help: a constant with a similar name exists
1142 // LL | const Y: X = Y("ö");
1146 let prefix
= match suggestion
.target
{
1147 SuggestionTarget
::SimilarlyNamed
=> "similarly named ",
1148 SuggestionTarget
::SingleItem
=> "",
1152 self.session
.source_map().guess_head_span(def_span
),
1154 "{}{} `{}` defined here",
1156 suggestion
.res
.descr(),
1157 suggestion
.candidate
.as_str(),
1161 let msg
= match suggestion
.target
{
1162 SuggestionTarget
::SimilarlyNamed
=> format
!(
1163 "{} {} with a similar name exists",
1164 suggestion
.res
.article(),
1165 suggestion
.res
.descr()
1167 SuggestionTarget
::SingleItem
=> {
1168 format
!("maybe you meant this {}", suggestion
.res
.descr())
1171 err
.span_suggestion(
1174 suggestion
.candidate
.to_string(),
1175 Applicability
::MaybeIncorrect
,
1180 fn binding_description(&self, b
: &NameBinding
<'_
>, ident
: Ident
, from_prelude
: bool
) -> String
{
1182 if b
.span
.is_dummy() || self.session
.source_map().span_to_snippet(b
.span
).is_err() {
1183 // These already contain the "built-in" prefix or look bad with it.
1185 !matches
!(b
.res(), Res
::NonMacroAttr(..) | Res
::PrimTy(..) | Res
::ToolMod
);
1186 let (built_in
, from
) = if from_prelude
{
1187 ("", " from prelude")
1188 } else if b
.is_extern_crate()
1190 && self.session
.opts
.externs
.get(ident
.as_str()).is_some()
1192 ("", " passed with `--extern`")
1193 } else if add_built_in
{
1199 let a
= if built_in
.is_empty() { res.article() }
else { "a" }
;
1200 format
!("{a}{built_in} {thing}{from}", thing
= res
.descr())
1202 let introduced
= if b
.is_import() { "imported" }
else { "defined" }
;
1203 format
!("the {thing} {introduced} here", thing
= res
.descr())
1207 crate fn report_ambiguity_error(&self, ambiguity_error
: &AmbiguityError
<'_
>) {
1208 let AmbiguityError { kind, ident, b1, b2, misc1, misc2 }
= *ambiguity_error
;
1209 let (b1
, b2
, misc1
, misc2
, swapped
) = if b2
.span
.is_dummy() && !b1
.span
.is_dummy() {
1210 // We have to print the span-less alternative first, otherwise formatting looks bad.
1211 (b2
, b1
, misc2
, misc1
, true)
1213 (b1
, b2
, misc1
, misc2
, false)
1216 let mut err
= struct_span_err
!(self.session
, ident
.span
, E0659
, "`{ident}` is ambiguous");
1217 err
.span_label(ident
.span
, "ambiguous name");
1218 err
.note(&format
!("ambiguous because of {}", kind
.descr()));
1220 let mut could_refer_to
= |b
: &NameBinding
<'_
>, misc
: AmbiguityErrorMisc
, also
: &str| {
1221 let what
= self.binding_description(b
, ident
, misc
== AmbiguityErrorMisc
::FromPrelude
);
1222 let note_msg
= format
!("`{ident}` could{also} refer to {what}");
1224 let thing
= b
.res().descr();
1225 let mut help_msgs
= Vec
::new();
1226 if b
.is_glob_import()
1227 && (kind
== AmbiguityKind
::GlobVsGlob
1228 || kind
== AmbiguityKind
::GlobVsExpanded
1229 || kind
== AmbiguityKind
::GlobVsOuter
&& swapped
!= also
.is_empty())
1231 help_msgs
.push(format
!(
1232 "consider adding an explicit import of `{ident}` to disambiguate"
1235 if b
.is_extern_crate() && ident
.span
.rust_2018() {
1236 help_msgs
.push(format
!("use `::{ident}` to refer to this {thing} unambiguously"))
1238 if misc
== AmbiguityErrorMisc
::SuggestCrate
{
1240 .push(format
!("use `crate::{ident}` to refer to this {thing} unambiguously"))
1241 } else if misc
== AmbiguityErrorMisc
::SuggestSelf
{
1243 .push(format
!("use `self::{ident}` to refer to this {thing} unambiguously"))
1246 err
.span_note(b
.span
, ¬e_msg
);
1247 for (i
, help_msg
) in help_msgs
.iter().enumerate() {
1248 let or
= if i
== 0 { "" }
else { "or " }
;
1249 err
.help(&format
!("{}{}", or
, help_msg
));
1253 could_refer_to(b1
, misc1
, "");
1254 could_refer_to(b2
, misc2
, " also");
1258 /// If the binding refers to a tuple struct constructor with fields,
1259 /// returns the span of its fields.
1260 fn ctor_fields_span(&self, binding
: &NameBinding
<'_
>) -> Option
<Span
> {
1261 if let NameBindingKind
::Res(
1262 Res
::Def(DefKind
::Ctor(CtorOf
::Struct
, CtorKind
::Fn
), ctor_def_id
),
1266 let def_id
= self.parent(ctor_def_id
).expect("no parent for a constructor");
1267 let fields
= self.field_names
.get(&def_id
)?
;
1268 return fields
.iter().map(|name
| name
.span
).reduce(Span
::to
); // None for `struct Foo()`
1273 crate fn report_privacy_error(&self, privacy_error
: &PrivacyError
<'_
>) {
1274 let PrivacyError { ident, binding, .. }
= *privacy_error
;
1276 let res
= binding
.res();
1277 let ctor_fields_span
= self.ctor_fields_span(binding
);
1278 let plain_descr
= res
.descr().to_string();
1279 let nonimport_descr
=
1280 if ctor_fields_span
.is_some() { plain_descr + " constructor" }
else { plain_descr }
;
1281 let import_descr
= nonimport_descr
.clone() + " import";
1283 |b
: &NameBinding
<'_
>| if b
.is_import() { &import_descr }
else { &nonimport_descr }
;
1285 // Print the primary message.
1286 let descr
= get_descr(binding
);
1288 struct_span_err
!(self.session
, ident
.span
, E0603
, "{} `{}` is private", descr
, ident
);
1289 err
.span_label(ident
.span
, &format
!("private {}", descr
));
1290 if let Some(span
) = ctor_fields_span
{
1291 err
.span_label(span
, "a constructor is private if any of the fields is private");
1294 // Print the whole import chain to make it easier to see what happens.
1295 let first_binding
= binding
;
1296 let mut next_binding
= Some(binding
);
1297 let mut next_ident
= ident
;
1298 while let Some(binding
) = next_binding
{
1299 let name
= next_ident
;
1300 next_binding
= match binding
.kind
{
1301 _
if res
== Res
::Err
=> None
,
1302 NameBindingKind
::Import { binding, import, .. }
=> match import
.kind
{
1303 _
if binding
.span
.is_dummy() => None
,
1304 ImportKind
::Single { source, .. }
=> {
1305 next_ident
= source
;
1308 ImportKind
::Glob { .. }
| ImportKind
::MacroUse
=> Some(binding
),
1309 ImportKind
::ExternCrate { .. }
=> None
,
1314 let first
= ptr
::eq(binding
, first_binding
);
1316 "{and_refers_to}the {item} `{name}`{which} is defined here{dots}",
1317 and_refers_to
= if first { "" }
else { "...and refers to " }
,
1318 item
= get_descr(binding
),
1319 which
= if first { "" }
else { " which" }
,
1320 dots
= if next_binding
.is_some() { "..." }
else { "" }
,
1322 let def_span
= self.session
.source_map().guess_head_span(binding
.span
);
1323 let mut note_span
= MultiSpan
::from_span(def_span
);
1324 if !first
&& binding
.vis
.is_public() {
1325 note_span
.push_span_label(def_span
, "consider importing it directly".into());
1327 err
.span_note(note_span
, &msg
);
1333 crate fn find_similarly_named_module_or_crate(
1336 current_module
: &Module
<'a
>,
1337 ) -> Option
<Symbol
> {
1338 let mut candidates
= self
1341 .map(|(ident
, _
)| ident
.name
)
1345 .filter(|(_
, module
)| {
1346 current_module
.is_ancestor_of(module
) && !ptr
::eq(current_module
, *module
)
1348 .map(|(_
, module
)| module
.kind
.name())
1351 .filter(|c
| !c
.to_string().is_empty())
1352 .collect
::<Vec
<_
>>();
1355 match find_best_match_for_name(&candidates
, ident
, None
) {
1356 Some(sugg
) if sugg
== ident
=> None
,
1362 impl<'a
, 'b
> ImportResolver
<'a
, 'b
> {
1363 /// Adds suggestions for a path that cannot be resolved.
1364 pub(crate) fn make_path_suggestion(
1367 mut path
: Vec
<Segment
>,
1368 parent_scope
: &ParentScope
<'b
>,
1369 ) -> Option
<(Vec
<Segment
>, Vec
<String
>)> {
1370 debug
!("make_path_suggestion: span={:?} path={:?}", span
, path
);
1372 match (path
.get(0), path
.get(1)) {
1373 // `{{root}}::ident::...` on both editions.
1374 // On 2015 `{{root}}` is usually added implicitly.
1375 (Some(fst
), Some(snd
))
1376 if fst
.ident
.name
== kw
::PathRoot
&& !snd
.ident
.is_path_segment_keyword() => {}
1377 // `ident::...` on 2018.
1379 if fst
.ident
.span
.rust_2018() && !fst
.ident
.is_path_segment_keyword() =>
1381 // Insert a placeholder that's later replaced by `self`/`super`/etc.
1382 path
.insert(0, Segment
::from_ident(Ident
::empty()));
1387 self.make_missing_self_suggestion(span
, path
.clone(), parent_scope
)
1388 .or_else(|| self.make_missing_crate_suggestion(span
, path
.clone(), parent_scope
))
1389 .or_else(|| self.make_missing_super_suggestion(span
, path
.clone(), parent_scope
))
1390 .or_else(|| self.make_external_crate_suggestion(span
, path
, parent_scope
))
1393 /// Suggest a missing `self::` if that resolves to an correct module.
1397 /// LL | use foo::Bar;
1398 /// | ^^^ did you mean `self::foo`?
1400 fn make_missing_self_suggestion(
1403 mut path
: Vec
<Segment
>,
1404 parent_scope
: &ParentScope
<'b
>,
1405 ) -> Option
<(Vec
<Segment
>, Vec
<String
>)> {
1406 // Replace first ident with `self` and check if that is valid.
1407 path
[0].ident
.name
= kw
::SelfLower
;
1408 let result
= self.r
.resolve_path(&path
, None
, parent_scope
, false, span
, CrateLint
::No
);
1409 debug
!("make_missing_self_suggestion: path={:?} result={:?}", path
, result
);
1410 if let PathResult
::Module(..) = result { Some((path, Vec::new())) }
else { None }
1413 /// Suggests a missing `crate::` if that resolves to an correct module.
1417 /// LL | use foo::Bar;
1418 /// | ^^^ did you mean `crate::foo`?
1420 fn make_missing_crate_suggestion(
1423 mut path
: Vec
<Segment
>,
1424 parent_scope
: &ParentScope
<'b
>,
1425 ) -> Option
<(Vec
<Segment
>, Vec
<String
>)> {
1426 // Replace first ident with `crate` and check if that is valid.
1427 path
[0].ident
.name
= kw
::Crate
;
1428 let result
= self.r
.resolve_path(&path
, None
, parent_scope
, false, span
, CrateLint
::No
);
1429 debug
!("make_missing_crate_suggestion: path={:?} result={:?}", path
, result
);
1430 if let PathResult
::Module(..) = result
{
1434 "`use` statements changed in Rust 2018; read more at \
1435 <https://doc.rust-lang.org/edition-guide/rust-2018/module-system/path-\
1445 /// Suggests a missing `super::` if that resolves to an correct module.
1449 /// LL | use foo::Bar;
1450 /// | ^^^ did you mean `super::foo`?
1452 fn make_missing_super_suggestion(
1455 mut path
: Vec
<Segment
>,
1456 parent_scope
: &ParentScope
<'b
>,
1457 ) -> Option
<(Vec
<Segment
>, Vec
<String
>)> {
1458 // Replace first ident with `crate` and check if that is valid.
1459 path
[0].ident
.name
= kw
::Super
;
1460 let result
= self.r
.resolve_path(&path
, None
, parent_scope
, false, span
, CrateLint
::No
);
1461 debug
!("make_missing_super_suggestion: path={:?} result={:?}", path
, result
);
1462 if let PathResult
::Module(..) = result { Some((path, Vec::new())) }
else { None }
1465 /// Suggests a missing external crate name if that resolves to an correct module.
1469 /// LL | use foobar::Baz;
1470 /// | ^^^^^^ did you mean `baz::foobar`?
1473 /// Used when importing a submodule of an external crate but missing that crate's
1474 /// name as the first part of path.
1475 fn make_external_crate_suggestion(
1478 mut path
: Vec
<Segment
>,
1479 parent_scope
: &ParentScope
<'b
>,
1480 ) -> Option
<(Vec
<Segment
>, Vec
<String
>)> {
1481 if path
[1].ident
.span
.rust_2015() {
1485 // Sort extern crate names in *reverse* order to get
1486 // 1) some consistent ordering for emitted diagnostics, and
1487 // 2) `std` suggestions before `core` suggestions.
1488 let mut extern_crate_names
=
1489 self.r
.extern_prelude
.iter().map(|(ident
, _
)| ident
.name
).collect
::<Vec
<_
>>();
1490 extern_crate_names
.sort_by(|a
, b
| b
.as_str().partial_cmp(a
.as_str()).unwrap());
1492 for name
in extern_crate_names
.into_iter() {
1493 // Replace first ident with a crate name and check if that is valid.
1494 path
[0].ident
.name
= name
;
1495 let result
= self.r
.resolve_path(&path
, None
, parent_scope
, false, span
, CrateLint
::No
);
1497 "make_external_crate_suggestion: name={:?} path={:?} result={:?}",
1500 if let PathResult
::Module(..) = result
{
1501 return Some((path
, Vec
::new()));
1508 /// Suggests importing a macro from the root of the crate rather than a module within
1512 /// help: a macro with this name exists at the root of the crate
1514 /// LL | use issue_59764::makro;
1515 /// | ^^^^^^^^^^^^^^^^^^
1517 /// = note: this could be because a macro annotated with `#[macro_export]` will be exported
1518 /// at the root of the crate instead of the module where it is defined
1520 pub(crate) fn check_for_module_export_macro(
1522 import
: &'b Import
<'b
>,
1523 module
: ModuleOrUniformRoot
<'b
>,
1525 ) -> Option
<(Option
<Suggestion
>, Vec
<String
>)> {
1526 let ModuleOrUniformRoot
::Module(mut crate_module
) = module
else {
1530 while let Some(parent
) = crate_module
.parent
{
1531 crate_module
= parent
;
1534 if ModuleOrUniformRoot
::same_def(ModuleOrUniformRoot
::Module(crate_module
), module
) {
1535 // Don't make a suggestion if the import was already from the root of the
1540 let resolutions
= self.r
.resolutions(crate_module
).borrow();
1541 let resolution
= resolutions
.get(&self.r
.new_key(ident
, MacroNS
))?
;
1542 let binding
= resolution
.borrow().binding()?
;
1543 if let Res
::Def(DefKind
::Macro(MacroKind
::Bang
), _
) = binding
.res() {
1544 let module_name
= crate_module
.kind
.name().unwrap();
1545 let import_snippet
= match import
.kind
{
1546 ImportKind
::Single { source, target, .. }
if source
!= target
=> {
1547 format
!("{} as {}", source
, target
)
1549 _
=> format
!("{}", ident
),
1552 let mut corrections
: Vec
<(Span
, String
)> = Vec
::new();
1553 if !import
.is_nested() {
1554 // Assume this is the easy case of `use issue_59764::foo::makro;` and just remove
1555 // intermediate segments.
1556 corrections
.push((import
.span
, format
!("{}::{}", module_name
, import_snippet
)));
1558 // Find the binding span (and any trailing commas and spaces).
1559 // ie. `use a::b::{c, d, e};`
1561 let (found_closing_brace
, binding_span
) = find_span_of_binding_until_next_binding(
1567 "check_for_module_export_macro: found_closing_brace={:?} binding_span={:?}",
1568 found_closing_brace
, binding_span
1571 let mut removal_span
= binding_span
;
1572 if found_closing_brace
{
1573 // If the binding span ended with a closing brace, as in the below example:
1574 // ie. `use a::b::{c, d};`
1576 // Then expand the span of characters to remove to include the previous
1577 // binding's trailing comma.
1578 // ie. `use a::b::{c, d};`
1580 if let Some(previous_span
) =
1581 extend_span_to_previous_binding(self.r
.session
, binding_span
)
1583 debug
!("check_for_module_export_macro: previous_span={:?}", previous_span
);
1584 removal_span
= removal_span
.with_lo(previous_span
.lo());
1587 debug
!("check_for_module_export_macro: removal_span={:?}", removal_span
);
1589 // Remove the `removal_span`.
1590 corrections
.push((removal_span
, "".to_string()));
1592 // Find the span after the crate name and if it has nested imports immediatately
1593 // after the crate name already.
1594 // ie. `use a::b::{c, d};`
1596 // or `use a::{b, c, d}};`
1598 let (has_nested
, after_crate_name
) = find_span_immediately_after_crate_name(
1604 "check_for_module_export_macro: has_nested={:?} after_crate_name={:?}",
1605 has_nested
, after_crate_name
1608 let source_map
= self.r
.session
.source_map();
1610 // Add the import to the start, with a `{` if required.
1611 let start_point
= source_map
.start_point(after_crate_name
);
1612 if let Ok(start_snippet
) = source_map
.span_to_snippet(start_point
) {
1616 // In this case, `start_snippet` must equal '{'.
1617 format
!("{}{}, ", start_snippet
, import_snippet
)
1619 // In this case, add a `{`, then the moved import, then whatever
1620 // was there before.
1621 format
!("{{{}, {}", import_snippet
, start_snippet
)
1626 // Add a `};` to the end if nested, matching the `{` added at the start.
1628 corrections
.push((source_map
.end_point(after_crate_name
), "};".to_string()));
1632 let suggestion
= Some((
1634 String
::from("a macro with this name exists at the root of the crate"),
1635 Applicability
::MaybeIncorrect
,
1638 "this could be because a macro annotated with `#[macro_export]` will be exported \
1639 at the root of the crate instead of the module where it is defined"
1642 Some((suggestion
, note
))
1649 /// Given a `binding_span` of a binding within a use statement:
1652 /// use foo::{a, b, c};
1656 /// then return the span until the next binding or the end of the statement:
1659 /// use foo::{a, b, c};
1662 pub(crate) fn find_span_of_binding_until_next_binding(
1667 let source_map
= sess
.source_map();
1669 // Find the span of everything after the binding.
1670 // ie. `a, e};` or `a};`
1671 let binding_until_end
= binding_span
.with_hi(use_span
.hi());
1673 // Find everything after the binding but not including the binding.
1674 // ie. `, e};` or `};`
1675 let after_binding_until_end
= binding_until_end
.with_lo(binding_span
.hi());
1677 // Keep characters in the span until we encounter something that isn't a comma or
1681 // Also note whether a closing brace character was encountered. If there
1682 // was, then later go backwards to remove any trailing commas that are left.
1683 let mut found_closing_brace
= false;
1684 let after_binding_until_next_binding
=
1685 source_map
.span_take_while(after_binding_until_end
, |&ch
| {
1687 found_closing_brace
= true;
1689 ch
== ' '
|| ch
== '
,'
1692 // Combine the two spans.
1693 // ie. `a, ` or `a`.
1695 // Removing these would leave `issue_52891::{d, e};` or `issue_52891::{d, e, };`
1696 let span
= binding_span
.with_hi(after_binding_until_next_binding
.hi());
1698 (found_closing_brace
, span
)
1701 /// Given a `binding_span`, return the span through to the comma or opening brace of the previous
1705 /// use foo::a::{a, b, c};
1706 /// ^^--- binding span
1710 /// use foo::{a, b, c};
1711 /// --- binding span
1713 pub(crate) fn extend_span_to_previous_binding(sess
: &Session
, binding_span
: Span
) -> Option
<Span
> {
1714 let source_map
= sess
.source_map();
1716 // `prev_source` will contain all of the source that came before the span.
1717 // Then split based on a command and take the first (ie. closest to our span)
1718 // snippet. In the example, this is a space.
1719 let prev_source
= source_map
.span_to_prev_source(binding_span
).ok()?
;
1721 let prev_comma
= prev_source
.rsplit('
,'
).collect
::<Vec
<_
>>();
1722 let prev_starting_brace
= prev_source
.rsplit('
{'
).collect
::<Vec
<_
>>();
1723 if prev_comma
.len() <= 1 || prev_starting_brace
.len() <= 1 {
1727 let prev_comma
= prev_comma
.first().unwrap();
1728 let prev_starting_brace
= prev_starting_brace
.first().unwrap();
1730 // If the amount of source code before the comma is greater than
1731 // the amount of source code before the starting brace then we've only
1732 // got one item in the nested item (eg. `issue_52891::{self}`).
1733 if prev_comma
.len() > prev_starting_brace
.len() {
1737 Some(binding_span
.with_lo(BytePos(
1738 // Take away the number of bytes for the characters we've found and an
1739 // extra for the comma.
1740 binding_span
.lo().0 - (prev_comma
.as_bytes().len() as u32) - 1,
1744 /// Given a `use_span` of a binding within a use statement, returns the highlighted span and if
1745 /// it is a nested use tree.
1748 /// use foo::a::{b, c};
1749 /// ^^^^^^^^^^ // false
1751 /// use foo::{a, b, c};
1752 /// ^^^^^^^^^^ // true
1754 /// use foo::{a, b::{c, d}};
1755 /// ^^^^^^^^^^^^^^^ // true
1757 fn find_span_immediately_after_crate_name(
1759 module_name
: Symbol
,
1763 "find_span_immediately_after_crate_name: module_name={:?} use_span={:?}",
1764 module_name
, use_span
1766 let source_map
= sess
.source_map();
1768 // Using `use issue_59764::foo::{baz, makro};` as an example throughout..
1769 let mut num_colons
= 0;
1770 // Find second colon.. `use issue_59764:`
1771 let until_second_colon
= source_map
.span_take_while(use_span
, |c
| {
1775 !matches
!(c
, '
:'
if num_colons
== 2)
1777 // Find everything after the second colon.. `foo::{baz, makro};`
1778 let from_second_colon
= use_span
.with_lo(until_second_colon
.hi() + BytePos(1));
1780 let mut found_a_non_whitespace_character
= false;
1781 // Find the first non-whitespace character in `from_second_colon`.. `f`
1782 let after_second_colon
= source_map
.span_take_while(from_second_colon
, |c
| {
1783 if found_a_non_whitespace_character
{
1786 if !c
.is_whitespace() {
1787 found_a_non_whitespace_character
= true;
1792 // Find the first `{` in from_second_colon.. `foo::{`
1793 let next_left_bracket
= source_map
.span_through_char(from_second_colon
, '
{'
);
1795 (next_left_bracket
== after_second_colon
, from_second_colon
)
1798 /// When an entity with a given name is not available in scope, we search for
1799 /// entities with that name in all crates. This method allows outputting the
1800 /// results of this search in a programmer-friendly way
1801 crate fn show_candidates(
1802 definitions
: &rustc_hir
::definitions
::Definitions
,
1804 err
: &mut DiagnosticBuilder
<'_
>,
1805 // This is `None` if all placement locations are inside expansions
1806 use_placement_span
: Option
<Span
>,
1807 candidates
: &[ImportSuggestion
],
1811 if candidates
.is_empty() {
1815 let mut accessible_path_strings
: Vec
<(String
, &str, Option
<DefId
>, &Option
<String
>)> =
1817 let mut inaccessible_path_strings
: Vec
<(String
, &str, Option
<DefId
>, &Option
<String
>)> =
1820 candidates
.iter().for_each(|c
| {
1821 (if c
.accessible { &mut accessible_path_strings }
else { &mut inaccessible_path_strings }
)
1822 .push((path_names_to_string(&c
.path
), c
.descr
, c
.did
, &c
.note
))
1825 // we want consistent results across executions, but candidates are produced
1826 // by iterating through a hash map, so make sure they are ordered:
1827 for path_strings
in [&mut accessible_path_strings
, &mut inaccessible_path_strings
] {
1828 path_strings
.sort_by(|a
, b
| a
.0.cmp(&b
.0));
1829 let core_path_strings
=
1830 path_strings
.drain_filter(|p
| p
.0.starts_with("core::")).collect
::<Vec
<_
>>();
1831 path_strings
.extend(core_path_strings
);
1832 path_strings
.dedup_by(|a
, b
| a
.0 == b
.0);
1835 if !accessible_path_strings
.is_empty() {
1836 let (determiner
, kind
) = if accessible_path_strings
.len() == 1 {
1837 ("this", accessible_path_strings
[0].1)
1839 ("one of these", "items")
1842 let instead
= if instead { " instead" }
else { "" }
;
1843 let mut msg
= format
!("consider importing {} {}{}", determiner
, kind
, instead
);
1845 for note
in accessible_path_strings
.iter().map(|cand
| cand
.3.as_ref()).flatten() {
1849 if let Some(span
) = use_placement_span
{
1850 for candidate
in &mut accessible_path_strings
{
1851 // produce an additional newline to separate the new use statement
1852 // from the directly following item.
1853 let additional_newline
= if found_use { "" }
else { "\n" }
;
1854 candidate
.0 = format
!("use {};\n{}", &candidate
.0, additional_newline
);
1857 err
.span_suggestions(
1860 accessible_path_strings
.into_iter().map(|a
| a
.0),
1861 Applicability
::Unspecified
,
1866 for candidate
in accessible_path_strings
{
1868 msg
.push_str(&candidate
.0);
1874 assert
!(!inaccessible_path_strings
.is_empty());
1876 if inaccessible_path_strings
.len() == 1 {
1877 let (name
, descr
, def_id
, note
) = &inaccessible_path_strings
[0];
1878 let msg
= format
!("{} `{}` exists but is inaccessible", descr
, name
);
1880 if let Some(local_def_id
) = def_id
.and_then(|did
| did
.as_local()) {
1881 let span
= definitions
.def_span(local_def_id
);
1882 let span
= session
.source_map().guess_head_span(span
);
1883 let mut multi_span
= MultiSpan
::from_span(span
);
1884 multi_span
.push_span_label(span
, "not accessible".to_string());
1885 err
.span_note(multi_span
, &msg
);
1889 if let Some(note
) = (*note
).as_deref() {
1893 let (_
, descr_first
, _
, _
) = &inaccessible_path_strings
[0];
1894 let descr
= if inaccessible_path_strings
1897 .all(|(_
, descr
, _
, _
)| descr
== descr_first
)
1899 descr_first
.to_string()
1904 let mut msg
= format
!("these {}s exist but are inaccessible", descr
);
1905 let mut has_colon
= false;
1907 let mut spans
= Vec
::new();
1908 for (name
, _
, def_id
, _
) in &inaccessible_path_strings
{
1909 if let Some(local_def_id
) = def_id
.and_then(|did
| did
.as_local()) {
1910 let span
= definitions
.def_span(local_def_id
);
1911 let span
= session
.source_map().guess_head_span(span
);
1912 spans
.push((name
, span
));
1923 let mut multi_span
= MultiSpan
::from_spans(spans
.iter().map(|(_
, sp
)| *sp
).collect());
1924 for (name
, span
) in spans
{
1925 multi_span
.push_span_label(span
, format
!("`{}`: not accessible", name
));
1928 for note
in inaccessible_path_strings
.iter().map(|cand
| cand
.3.as_ref()).flatten() {
1932 err
.span_note(multi_span
, &msg
);