summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_resolve/src/imports.rs
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_resolve/src/imports.rs')
-rw-r--r--compiler/rustc_resolve/src/imports.rs220
1 files changed, 126 insertions, 94 deletions
diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs
index f2cc50c19..b100a8c17 100644
--- a/compiler/rustc_resolve/src/imports.rs
+++ b/compiler/rustc_resolve/src/imports.rs
@@ -4,7 +4,10 @@ use crate::diagnostics::{import_candidates, Suggestion};
use crate::Determinacy::{self, *};
use crate::Namespace::*;
use crate::{module_to_string, names_to_string, ImportSuggestion};
-use crate::{AmbiguityKind, BindingKey, ModuleKind, ResolutionError, Resolver, Segment};
+use crate::{
+ AmbiguityError, AmbiguityErrorMisc, AmbiguityKind, BindingKey, ModuleKind, ResolutionError,
+ Resolver, Segment,
+};
use crate::{Finalize, Module, ModuleOrUniformRoot, ParentScope, PerNS, ScopeSet};
use crate::{NameBinding, NameBindingKind, PathResult};
@@ -44,20 +47,33 @@ pub enum ImportKind<'a> {
type_ns_only: bool,
/// Did this import result from a nested import? ie. `use foo::{bar, baz};`
nested: bool,
- /// Additional `NodeId`s allocated to a `ast::UseTree` for automatically generated `use` statement
- /// (eg. implicit struct constructors)
- additional_ids: (NodeId, NodeId),
+ /// The ID of the `UseTree` that imported this `Import`.
+ ///
+ /// In the case where the `Import` was expanded from a "nested" use tree,
+ /// this id is the ID of the leaf tree. For example:
+ ///
+ /// ```ignore (pacify the merciless tidy)
+ /// use foo::bar::{a, b}
+ /// ```
+ ///
+ /// If this is the import for `foo::bar::a`, we would have the ID of the `UseTree`
+ /// for `a` in this field.
+ id: NodeId,
},
Glob {
is_prelude: bool,
- max_vis: Cell<Option<ty::Visibility>>, // The visibility of the greatest re-export.
- // n.b. `max_vis` is only used in `finalize_import` to check for re-export errors.
+ // The visibility of the greatest re-export.
+ // n.b. `max_vis` is only used in `finalize_import` to check for re-export errors.
+ max_vis: Cell<Option<ty::Visibility>>,
+ id: NodeId,
},
ExternCrate {
source: Option<Symbol>,
target: Ident,
+ id: NodeId,
},
MacroUse,
+ MacroExport,
}
/// Manually implement `Debug` for `ImportKind` because the `source/target_bindings`
@@ -71,7 +87,7 @@ impl<'a> std::fmt::Debug for ImportKind<'a> {
ref target,
ref type_ns_only,
ref nested,
- ref additional_ids,
+ ref id,
// Ignore the following to avoid an infinite loop while printing.
source_bindings: _,
target_bindings: _,
@@ -81,19 +97,22 @@ impl<'a> std::fmt::Debug for ImportKind<'a> {
.field("target", target)
.field("type_ns_only", type_ns_only)
.field("nested", nested)
- .field("additional_ids", additional_ids)
+ .field("id", id)
.finish_non_exhaustive(),
- Glob { ref is_prelude, ref max_vis } => f
+ Glob { ref is_prelude, ref max_vis, ref id } => f
.debug_struct("Glob")
.field("is_prelude", is_prelude)
.field("max_vis", max_vis)
+ .field("id", id)
.finish(),
- ExternCrate { ref source, ref target } => f
+ ExternCrate { ref source, ref target, ref id } => f
.debug_struct("ExternCrate")
.field("source", source)
.field("target", target)
+ .field("id", id)
.finish(),
MacroUse => f.debug_struct("MacroUse").finish(),
+ MacroExport => f.debug_struct("MacroExport").finish(),
}
}
}
@@ -103,24 +122,15 @@ impl<'a> std::fmt::Debug for ImportKind<'a> {
pub(crate) struct Import<'a> {
pub kind: ImportKind<'a>,
- /// The ID of the `extern crate`, `UseTree` etc that imported this `Import`.
- ///
- /// In the case where the `Import` was expanded from a "nested" use tree,
- /// this id is the ID of the leaf tree. For example:
- ///
- /// ```ignore (pacify the merciless tidy)
+ /// Node ID of the "root" use item -- this is always the same as `ImportKind`'s `id`
+ /// (if it exists) except in the case of "nested" use trees, in which case
+ /// it will be the ID of the root use tree. e.g., in the example
+ /// ```ignore (incomplete code)
/// use foo::bar::{a, b}
/// ```
- ///
- /// If this is the import for `foo::bar::a`, we would have the ID of the `UseTree`
- /// for `a` in this field.
- pub id: NodeId,
-
- /// The `id` of the "root" use-kind -- this is always the same as
- /// `id` except in the case of "nested" use trees, in which case
- /// it will be the `id` of the root use tree. e.g., in the example
- /// from `id`, this would be the ID of the `use foo::bar`
- /// `UseTree` node.
+ /// this would be the ID of the `use foo::bar` `UseTree` node.
+ /// In case of imports without their own node ID it's the closest node that can be used,
+ /// for example, for reporting lints.
pub root_id: NodeId,
/// Span of the entire use statement.
@@ -161,6 +171,15 @@ impl<'a> Import<'a> {
pub(crate) fn expect_vis(&self) -> ty::Visibility {
self.vis.get().expect("encountered cleared import visibility")
}
+
+ pub(crate) fn id(&self) -> Option<NodeId> {
+ match self.kind {
+ ImportKind::Single { id, .. }
+ | ImportKind::Glob { id, .. }
+ | ImportKind::ExternCrate { id, .. } => Some(id),
+ ImportKind::MacroUse | ImportKind::MacroExport => None,
+ }
+ }
}
/// Records information about the resolution of a name in a namespace of a module.
@@ -175,7 +194,7 @@ pub(crate) struct NameResolution<'a> {
}
impl<'a> NameResolution<'a> {
- // Returns the binding for the name if it is known or None if it not known.
+ /// Returns the binding for the name if it is known or None if it not known.
pub(crate) fn binding(&self) -> Option<&'a NameBinding<'a>> {
self.binding.and_then(|binding| {
if !binding.is_glob_import() || self.single_imports.is_empty() {
@@ -207,8 +226,8 @@ fn pub_use_of_private_extern_crate_hack(import: &Import<'_>, binding: &NameBindi
}
impl<'a> Resolver<'a> {
- // Given a binding and an import that resolves to it,
- // return the corresponding binding defined by the import.
+ /// Given a binding and an import that resolves to it,
+ /// return the corresponding binding defined by the import.
pub(crate) fn import(
&self,
binding: &'a NameBinding<'a>,
@@ -240,7 +259,7 @@ impl<'a> Resolver<'a> {
})
}
- // Define the name or return the existing binding if there is a collision.
+ /// Define the name or return the existing binding if there is a collision.
pub(crate) fn try_define(
&mut self,
module: Module<'a>,
@@ -368,7 +387,9 @@ impl<'a> Resolver<'a> {
self.record_use(target, dummy_binding, false);
} else if import.imported_module.get().is_none() {
import.used.set(true);
- self.used_imports.insert(import.id);
+ if let Some(id) = import.id() {
+ self.used_imports.insert(id);
+ }
}
}
}
@@ -450,7 +471,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
{
// In the case of a new import line, throw a diagnostic message
// for the previous line.
- self.throw_unresolved_import_error(errors, None);
+ self.throw_unresolved_import_error(errors);
errors = vec![];
}
if seen_spans.insert(err.span) {
@@ -482,29 +503,21 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
}
if !errors.is_empty() {
- self.throw_unresolved_import_error(errors, None);
+ self.throw_unresolved_import_error(errors);
}
}
- fn throw_unresolved_import_error(
- &self,
- errors: Vec<(String, UnresolvedImportError)>,
- span: Option<MultiSpan>,
- ) {
+ fn throw_unresolved_import_error(&self, errors: Vec<(String, UnresolvedImportError)>) {
+ if errors.is_empty() {
+ return;
+ }
+
/// Upper limit on the number of `span_label` messages.
const MAX_LABEL_COUNT: usize = 10;
- let (span, msg) = if errors.is_empty() {
- (span.unwrap(), "unresolved import".to_string())
- } else {
- let span = MultiSpan::from_spans(errors.iter().map(|(_, err)| err.span).collect());
-
- let paths = errors.iter().map(|(path, _)| format!("`{}`", path)).collect::<Vec<_>>();
-
- let msg = format!("unresolved import{} {}", pluralize!(paths.len()), paths.join(", "),);
-
- (span, msg)
- };
+ let span = MultiSpan::from_spans(errors.iter().map(|(_, err)| err.span).collect());
+ let paths = errors.iter().map(|(path, _)| format!("`{}`", path)).collect::<Vec<_>>();
+ let msg = format!("unresolved import{} {}", pluralize!(paths.len()), paths.join(", "),);
let mut diag = struct_span_err!(self.r.session, span, E0432, "{}", &msg);
@@ -718,47 +731,51 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
PathResult::Indeterminate => unreachable!(),
};
- let (ident, target, source_bindings, target_bindings, type_ns_only) = match import.kind {
- ImportKind::Single {
- source,
- target,
- ref source_bindings,
- ref target_bindings,
- type_ns_only,
- ..
- } => (source, target, source_bindings, target_bindings, type_ns_only),
- ImportKind::Glob { is_prelude, ref max_vis } => {
- if import.module_path.len() <= 1 {
- // HACK(eddyb) `lint_if_path_starts_with_module` needs at least
- // 2 segments, so the `resolve_path` above won't trigger it.
- let mut full_path = import.module_path.clone();
- full_path.push(Segment::from_ident(Ident::empty()));
- self.r.lint_if_path_starts_with_module(Some(finalize), &full_path, None);
- }
+ let (ident, target, source_bindings, target_bindings, type_ns_only, import_id) =
+ match import.kind {
+ ImportKind::Single {
+ source,
+ target,
+ ref source_bindings,
+ ref target_bindings,
+ type_ns_only,
+ id,
+ ..
+ } => (source, target, source_bindings, target_bindings, type_ns_only, id),
+ ImportKind::Glob { is_prelude, ref max_vis, id } => {
+ if import.module_path.len() <= 1 {
+ // HACK(eddyb) `lint_if_path_starts_with_module` needs at least
+ // 2 segments, so the `resolve_path` above won't trigger it.
+ let mut full_path = import.module_path.clone();
+ full_path.push(Segment::from_ident(Ident::empty()));
+ self.r.lint_if_path_starts_with_module(Some(finalize), &full_path, None);
+ }
- if let ModuleOrUniformRoot::Module(module) = module {
- if ptr::eq(module, import.parent_scope.module) {
- // Importing a module into itself is not allowed.
- return Some(UnresolvedImportError {
- span: import.span,
- label: Some(String::from("cannot glob-import a module into itself")),
- note: None,
- suggestion: None,
- candidate: None,
- });
+ if let ModuleOrUniformRoot::Module(module) = module {
+ if ptr::eq(module, import.parent_scope.module) {
+ // Importing a module into itself is not allowed.
+ return Some(UnresolvedImportError {
+ span: import.span,
+ label: Some(String::from(
+ "cannot glob-import a module into itself",
+ )),
+ note: None,
+ suggestion: None,
+ candidate: None,
+ });
+ }
}
- }
- if !is_prelude
+ if !is_prelude
&& let Some(max_vis) = max_vis.get()
&& !max_vis.is_at_least(import.expect_vis(), &*self.r)
{
let msg = "glob import doesn't reexport anything because no candidate is public enough";
- self.r.lint_buffer.buffer_lint(UNUSED_IMPORTS, import.id, import.span, msg);
+ self.r.lint_buffer.buffer_lint(UNUSED_IMPORTS, id, import.span, msg);
}
- return None;
- }
- _ => unreachable!(),
- };
+ return None;
+ }
+ _ => unreachable!(),
+ };
let mut all_ns_err = true;
self.r.per_ns(|this, ns| {
@@ -777,7 +794,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
match binding {
Ok(binding) => {
// Consistency checks, analogous to `finalize_macro_resolutions`.
- let initial_res = source_bindings[ns].get().map(|initial_binding| {
+ let initial_binding = source_bindings[ns].get().map(|initial_binding| {
all_ns_err = false;
if let Some(target_binding) = target_bindings[ns].get() {
if target.name == kw::Underscore
@@ -791,12 +808,20 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
);
}
}
- initial_binding.res()
+ initial_binding
});
let res = binding.res();
- if let Ok(initial_res) = initial_res {
+ if let Ok(initial_binding) = initial_binding {
+ let initial_res = initial_binding.res();
if res != initial_res && this.ambiguity_errors.is_empty() {
- span_bug!(import.span, "inconsistent resolution for an import");
+ this.ambiguity_errors.push(AmbiguityError {
+ kind: AmbiguityKind::Import,
+ ident,
+ b1: initial_binding,
+ b2: binding,
+ misc1: AmbiguityErrorMisc::None,
+ misc2: AmbiguityErrorMisc::None,
+ });
}
} else if res != Res::Err
&& this.ambiguity_errors.is_empty()
@@ -858,7 +883,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
match binding.kind {
// Never suggest the name that has binding error
// i.e., the name that cannot be previously resolved
- NameBindingKind::Res(Res::Err, _) => None,
+ NameBindingKind::Res(Res::Err) => None,
_ => Some(i.name),
}
}
@@ -960,7 +985,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
);
self.r.lint_buffer.buffer_lint(
PUB_USE_OF_PRIVATE_EXTERN_CRATE,
- import.id,
+ import_id,
import.span,
&msg,
);
@@ -989,7 +1014,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
let mut err =
struct_span_err!(self.r.session, import.span, E0364, "{error_msg}");
match binding.kind {
- NameBindingKind::Res(Res::Def(DefKind::Macro(_), def_id), _)
+ NameBindingKind::Res(Res::Def(DefKind::Macro(_), def_id))
// exclude decl_macro
if self.r.get_macro_by_def_id(def_id).macro_rules =>
{
@@ -1029,7 +1054,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
// purposes it's good enough to just favor one over the other.
self.r.per_ns(|this, ns| {
if let Ok(binding) = source_bindings[ns].get() {
- this.import_res_map.entry(import.id).or_default()[ns] = Some(binding.res());
+ this.import_res_map.entry(import_id).or_default()[ns] = Some(binding.res());
}
});
@@ -1047,6 +1072,9 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
target_bindings: &PerNS<Cell<Option<&'b NameBinding<'b>>>>,
target: Ident,
) {
+ // This function is only called for single imports.
+ let ImportKind::Single { id, .. } = import.kind else { unreachable!() };
+
// Skip if the import was produced by a macro.
if import.parent_scope.expansion != LocalExpnId::ROOT {
return;
@@ -1094,7 +1122,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
redundant_spans.dedup();
self.r.lint_buffer.buffer_lint_with_diagnostic(
UNUSED_IMPORTS,
- import.id,
+ id,
import.span,
&format!("the item `{}` is imported redundantly", ident),
BuiltinLintDiagnostics::RedundantImport(redundant_spans, ident),
@@ -1103,6 +1131,9 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
}
fn resolve_glob_import(&mut self, import: &'b Import<'b>) {
+ // This function is only called for glob imports.
+ let ImportKind::Glob { id, is_prelude, .. } = import.kind else { unreachable!() };
+
let ModuleOrUniformRoot::Module(module) = import.imported_module.get().unwrap() else {
self.r.session.span_err(import.span, "cannot glob-import all possible crates");
return;
@@ -1113,7 +1144,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
return;
} else if ptr::eq(module, import.parent_scope.module) {
return;
- } else if let ImportKind::Glob { is_prelude: true, .. } = import.kind {
+ } else if is_prelude {
self.r.prelude = Some(module);
return;
}
@@ -1145,7 +1176,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
}
// Record the destination of this import
- self.r.record_partial_res(import.id, PartialRes::new(module.res().unwrap()));
+ self.r.record_partial_res(id, PartialRes::new(module.res().unwrap()));
}
// Miscellaneous post-processing, including recording re-exports,
@@ -1204,5 +1235,6 @@ fn import_kind_to_string(import_kind: &ImportKind<'_>) -> String {
ImportKind::Glob { .. } => "*".to_string(),
ImportKind::ExternCrate { .. } => "<extern crate>".to_string(),
ImportKind::MacroUse => "#[macro_use]".to_string(),
+ ImportKind::MacroExport => "#[macro_export]".to_string(),
}
}