about summary refs log tree commit diff
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.rs151
1 files changed, 91 insertions, 60 deletions
diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs
index f2cc50c199f..3b9bf943262 100644
--- a/compiler/rustc_resolve/src/imports.rs
+++ b/compiler/rustc_resolve/src/imports.rs
@@ -44,18 +44,33 @@ pub enum ImportKind<'a> {
         type_ns_only: bool,
         /// Did this import result from a nested import? ie. `use foo::{bar, baz};`
         nested: bool,
+        /// 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,
         /// Additional `NodeId`s allocated to a `ast::UseTree` for automatically generated `use` statement
         /// (eg. implicit struct constructors)
         additional_ids: (NodeId, 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,
 }
@@ -71,6 +86,7 @@ impl<'a> std::fmt::Debug for ImportKind<'a> {
                 ref target,
                 ref type_ns_only,
                 ref nested,
+                ref id,
                 ref additional_ids,
                 // Ignore the following to avoid an infinite loop while printing.
                 source_bindings: _,
@@ -81,17 +97,20 @@ impl<'a> std::fmt::Debug for ImportKind<'a> {
                 .field("target", target)
                 .field("type_ns_only", type_ns_only)
                 .field("nested", nested)
+                .field("id", id)
                 .field("additional_ids", additional_ids)
                 .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(),
         }
@@ -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 => None,
+        }
+    }
 }
 
 /// Records information about the resolution of a name in a namespace of a module.
@@ -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);
+            }
         }
     }
 }
@@ -718,47 +739,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| {
@@ -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,
                 );
@@ -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,