Auto merge of #15422 - Veykril:import-sources, r=Veykril

internal: Record import source IDs

cc https://github.com/rust-lang/rust-analyzer/issues/14079
This commit is contained in:
bors 2023-08-09 15:09:15 +00:00
commit b78d69c795
7 changed files with 220 additions and 185 deletions

View File

@ -487,7 +487,7 @@ pub(crate) fn extern_crate_decl_data_query(
db.crate_def_map(loc.container.krate()) db.crate_def_map(loc.container.krate())
.extern_prelude() .extern_prelude()
.find(|&(prelude_name, ..)| *prelude_name == name) .find(|&(prelude_name, ..)| *prelude_name == name)
.map(|(_, root)| root.krate()) .map(|(_, (root, _))| root.krate())
}; };
Arc::new(Self { Arc::new(Self {

View File

@ -11,7 +11,7 @@
nameres::DefMap, nameres::DefMap,
path::{ModPath, PathKind}, path::{ModPath, PathKind},
visibility::Visibility, visibility::Visibility,
ModuleDefId, ModuleId, CrateRootModuleId, ModuleDefId, ModuleId,
}; };
/// Find a path that can be used to refer to a certain item. This can depend on /// Find a path that can be used to refer to a certain item. This can depend on
@ -81,7 +81,7 @@ fn find_path_inner(
} }
let def_map = from.def_map(db); let def_map = from.def_map(db);
let crate_root = def_map.crate_root().into(); let crate_root = def_map.crate_root();
// - if the item is a module, jump straight to module search // - if the item is a module, jump straight to module search
if let ItemInNs::Types(ModuleDefId::ModuleId(module_id)) = item { if let ItemInNs::Types(ModuleDefId::ModuleId(module_id)) = item {
let mut visited_modules = FxHashSet::default(); let mut visited_modules = FxHashSet::default();
@ -149,7 +149,7 @@ fn find_path_for_module(
db: &dyn DefDatabase, db: &dyn DefDatabase,
def_map: &DefMap, def_map: &DefMap,
visited_modules: &mut FxHashSet<ModuleId>, visited_modules: &mut FxHashSet<ModuleId>,
crate_root: ModuleId, crate_root: CrateRootModuleId,
from: ModuleId, from: ModuleId,
module_id: ModuleId, module_id: ModuleId,
max_len: usize, max_len: usize,
@ -183,7 +183,7 @@ fn find_path_for_module(
// - if the item is the crate root of a dependency crate, return the name from the extern prelude // - if the item is the crate root of a dependency crate, return the name from the extern prelude
let root_def_map = crate_root.def_map(db); let root_def_map = crate_root.def_map(db);
for (name, def_id) in root_def_map.extern_prelude() { for (name, (def_id, _extern_crate)) in root_def_map.extern_prelude() {
if module_id == def_id { if module_id == def_id {
let name = scope_name.unwrap_or_else(|| name.clone()); let name = scope_name.unwrap_or_else(|| name.clone());
@ -192,7 +192,7 @@ fn find_path_for_module(
def_map[local_id] def_map[local_id]
.scope .scope
.type_(&name) .type_(&name)
.filter(|&(id, _)| id != ModuleDefId::ModuleId(def_id)) .filter(|&(id, _)| id != ModuleDefId::ModuleId(def_id.into()))
}) })
.is_some(); .is_some();
let kind = if name_already_occupied_in_type_ns { let kind = if name_already_occupied_in_type_ns {
@ -244,7 +244,7 @@ fn find_in_prelude(
item: ItemInNs, item: ItemInNs,
from: ModuleId, from: ModuleId,
) -> Option<ModPath> { ) -> Option<ModPath> {
let prelude_module = root_def_map.prelude()?; let (prelude_module, _) = root_def_map.prelude()?;
// Preludes in block DefMaps are ignored, only the crate DefMap is searched // Preludes in block DefMaps are ignored, only the crate DefMap is searched
let prelude_def_map = prelude_module.def_map(db); let prelude_def_map = prelude_module.def_map(db);
let prelude_scope = &prelude_def_map[prelude_module.local_id].scope; let prelude_scope = &prelude_def_map[prelude_module.local_id].scope;
@ -293,7 +293,7 @@ fn calculate_best_path(
db: &dyn DefDatabase, db: &dyn DefDatabase,
def_map: &DefMap, def_map: &DefMap,
visited_modules: &mut FxHashSet<ModuleId>, visited_modules: &mut FxHashSet<ModuleId>,
crate_root: ModuleId, crate_root: CrateRootModuleId,
max_len: usize, max_len: usize,
item: ItemInNs, item: ItemInNs,
from: ModuleId, from: ModuleId,

View File

@ -109,6 +109,17 @@ pub fn krate(self) -> CrateId {
} }
} }
impl PartialEq<ModuleId> for CrateRootModuleId {
fn eq(&self, other: &ModuleId) -> bool {
other.block.is_none() && other.local_id == DefMap::ROOT && self.krate == other.krate
}
}
impl PartialEq<CrateRootModuleId> for ModuleId {
fn eq(&self, other: &CrateRootModuleId) -> bool {
other == self
}
}
impl From<CrateRootModuleId> for ModuleId { impl From<CrateRootModuleId> for ModuleId {
fn from(CrateRootModuleId { krate }: CrateRootModuleId) -> Self { fn from(CrateRootModuleId { krate }: CrateRootModuleId) -> Self {
ModuleId { krate, block: None, local_id: DefMap::ROOT } ModuleId { krate, block: None, local_id: DefMap::ROOT }

View File

@ -77,8 +77,8 @@
path::ModPath, path::ModPath,
per_ns::PerNs, per_ns::PerNs,
visibility::Visibility, visibility::Visibility,
AstId, BlockId, BlockLoc, CrateRootModuleId, FunctionId, LocalModuleId, Lookup, MacroExpander, AstId, BlockId, BlockLoc, CrateRootModuleId, ExternCrateId, FunctionId, LocalModuleId, Lookup,
MacroId, ModuleId, ProcMacroId, MacroExpander, MacroId, ModuleId, ProcMacroId, UseId,
}; };
/// Contains the results of (early) name resolution. /// Contains the results of (early) name resolution.
@ -105,10 +105,10 @@ pub struct DefMap {
/// The prelude is empty for non-block DefMaps (unless `#[prelude_import]` was used, /// The prelude is empty for non-block DefMaps (unless `#[prelude_import]` was used,
/// but that attribute is nightly and when used in a block, it affects resolution globally /// but that attribute is nightly and when used in a block, it affects resolution globally
/// so we aren't handling this correctly anyways). /// so we aren't handling this correctly anyways).
prelude: Option<ModuleId>, prelude: Option<(ModuleId, Option<UseId>)>,
/// `macro_use` prelude that contains macros from `#[macro_use]`'d external crates. Note that /// `macro_use` prelude that contains macros from `#[macro_use]`'d external crates. Note that
/// this contains all kinds of macro, not just `macro_rules!` macro. /// this contains all kinds of macro, not just `macro_rules!` macro.
macro_use_prelude: FxHashMap<Name, MacroId>, macro_use_prelude: FxHashMap<Name, (MacroId, Option<ExternCrateId>)>,
/// Tracks which custom derives are in scope for an item, to allow resolution of derive helper /// Tracks which custom derives are in scope for an item, to allow resolution of derive helper
/// attributes. /// attributes.
@ -125,7 +125,7 @@ pub struct DefMap {
#[derive(Clone, Debug, PartialEq, Eq)] #[derive(Clone, Debug, PartialEq, Eq)]
struct DefMapCrateData { struct DefMapCrateData {
/// The extern prelude which contains all root modules of external crates that are in scope. /// The extern prelude which contains all root modules of external crates that are in scope.
extern_prelude: FxHashMap<Name, CrateRootModuleId>, extern_prelude: FxHashMap<Name, (CrateRootModuleId, Option<ExternCrateId>)>,
/// Side table for resolving derive helpers. /// Side table for resolving derive helpers.
exported_derives: FxHashMap<MacroDefId, Box<[Name]>>, exported_derives: FxHashMap<MacroDefId, Box<[Name]>>,
@ -427,15 +427,19 @@ pub(crate) fn block_id(&self) -> Option<BlockId> {
self.block.map(|block| block.block) self.block.map(|block| block.block)
} }
pub(crate) fn prelude(&self) -> Option<ModuleId> { pub(crate) fn prelude(&self) -> Option<(ModuleId, Option<UseId>)> {
self.prelude self.prelude
} }
pub(crate) fn extern_prelude(&self) -> impl Iterator<Item = (&Name, ModuleId)> + '_ { pub(crate) fn extern_prelude(
self.data.extern_prelude.iter().map(|(name, &def)| (name, def.into())) &self,
) -> impl Iterator<Item = (&Name, (CrateRootModuleId, Option<ExternCrateId>))> + '_ {
self.data.extern_prelude.iter().map(|(name, &def)| (name, def))
} }
pub(crate) fn macro_use_prelude(&self) -> impl Iterator<Item = (&Name, MacroId)> + '_ { pub(crate) fn macro_use_prelude(
&self,
) -> impl Iterator<Item = (&Name, (MacroId, Option<ExternCrateId>))> + '_ {
self.macro_use_prelude.iter().map(|(name, &def)| (name, def)) self.macro_use_prelude.iter().map(|(name, &def)| (name, def))
} }

View File

@ -52,10 +52,10 @@
tt, tt,
visibility::{RawVisibility, Visibility}, visibility::{RawVisibility, Visibility},
AdtId, AstId, AstIdWithPath, ConstLoc, CrateRootModuleId, EnumLoc, EnumVariantId, AdtId, AstId, AstIdWithPath, ConstLoc, CrateRootModuleId, EnumLoc, EnumVariantId,
ExternBlockLoc, ExternCrateLoc, FunctionId, FunctionLoc, ImplLoc, Intern, ItemContainerId, ExternBlockLoc, ExternCrateId, ExternCrateLoc, FunctionId, FunctionLoc, ImplLoc, Intern,
LocalModuleId, Macro2Id, Macro2Loc, MacroExpander, MacroId, MacroRulesId, MacroRulesLoc, ItemContainerId, LocalModuleId, Macro2Id, Macro2Loc, MacroExpander, MacroId, MacroRulesId,
ModuleDefId, ModuleId, ProcMacroId, ProcMacroLoc, StaticLoc, StructLoc, TraitAliasLoc, MacroRulesLoc, ModuleDefId, ModuleId, ProcMacroId, ProcMacroLoc, StaticLoc, StructLoc,
TraitLoc, TypeAliasLoc, UnionLoc, UnresolvedMacro, UseLoc, TraitAliasLoc, TraitLoc, TypeAliasLoc, UnionLoc, UnresolvedMacro, UseId, UseLoc,
}; };
static GLOB_RECURSION_LIMIT: Limit = Limit::new(100); static GLOB_RECURSION_LIMIT: Limit = Limit::new(100);
@ -146,8 +146,8 @@ fn namespaces(self) -> PerNs {
#[derive(Clone, Debug, Eq, PartialEq)] #[derive(Clone, Debug, Eq, PartialEq)]
enum ImportSource { enum ImportSource {
Use { id: ItemTreeId<item_tree::Use>, use_tree: Idx<ast::UseTree> }, Use { use_tree: Idx<ast::UseTree>, id: UseId, is_prelude: bool },
ExternCrate(ItemTreeId<item_tree::ExternCrate>), ExternCrate { id: ExternCrateId },
} }
#[derive(Debug, Eq, PartialEq)] #[derive(Debug, Eq, PartialEq)]
@ -157,52 +157,42 @@ struct Import {
visibility: RawVisibility, visibility: RawVisibility,
kind: ImportKind, kind: ImportKind,
source: ImportSource, source: ImportSource,
is_prelude: bool,
is_macro_use: bool,
} }
impl Import { impl Import {
fn from_use( fn from_use(
db: &dyn DefDatabase,
krate: CrateId,
tree: &ItemTree, tree: &ItemTree,
id: ItemTreeId<item_tree::Use>, item_tree_id: ItemTreeId<item_tree::Use>,
id: UseId,
is_prelude: bool,
mut cb: impl FnMut(Self), mut cb: impl FnMut(Self),
) { ) {
let it = &tree[id.value]; let it = &tree[item_tree_id.value];
let attrs = &tree.attrs(db, krate, ModItem::from(id.value).into());
let visibility = &tree[it.visibility]; let visibility = &tree[it.visibility];
let is_prelude = attrs.by_key("prelude_import").exists();
it.use_tree.expand(|idx, path, kind, alias| { it.use_tree.expand(|idx, path, kind, alias| {
cb(Self { cb(Self {
path, path,
alias, alias,
visibility: visibility.clone(), visibility: visibility.clone(),
kind, kind,
is_prelude, source: ImportSource::Use { use_tree: idx, id, is_prelude },
is_macro_use: false,
source: ImportSource::Use { id, use_tree: idx },
}); });
}); });
} }
fn from_extern_crate( fn from_extern_crate(
db: &dyn DefDatabase,
krate: CrateId,
tree: &ItemTree, tree: &ItemTree,
id: ItemTreeId<item_tree::ExternCrate>, item_tree_id: ItemTreeId<item_tree::ExternCrate>,
id: ExternCrateId,
) -> Self { ) -> Self {
let it = &tree[id.value]; let it = &tree[item_tree_id.value];
let attrs = &tree.attrs(db, krate, ModItem::from(id.value).into());
let visibility = &tree[it.visibility]; let visibility = &tree[it.visibility];
Self { Self {
path: ModPath::from_segments(PathKind::Plain, iter::once(it.name.clone())), path: ModPath::from_segments(PathKind::Plain, iter::once(it.name.clone())),
alias: it.alias.clone(), alias: it.alias.clone(),
visibility: visibility.clone(), visibility: visibility.clone(),
kind: ImportKind::Plain, kind: ImportKind::Plain,
is_prelude: false, source: ImportSource::ExternCrate { id },
is_macro_use: attrs.by_key("macro_use").exists(),
source: ImportSource::ExternCrate(id),
} }
} }
} }
@ -280,7 +270,7 @@ fn seed_with_top_level(&mut self) {
if dep.is_prelude() { if dep.is_prelude() {
crate_data crate_data
.extern_prelude .extern_prelude
.insert(name.clone(), CrateRootModuleId { krate: dep.crate_id }); .insert(name.clone(), (CrateRootModuleId { krate: dep.crate_id }, None));
} }
} }
@ -557,7 +547,7 @@ fn inject_prelude(&mut self) {
match per_ns.types { match per_ns.types {
Some((ModuleDefId::ModuleId(m), _)) => { Some((ModuleDefId::ModuleId(m), _)) => {
self.def_map.prelude = Some(m); self.def_map.prelude = Some((m, None));
} }
types => { types => {
tracing::debug!( tracing::debug!(
@ -720,7 +710,13 @@ fn define_proc_macro(&mut self, name: Name, macro_: ProcMacroId) {
/// Exported macros are just all macros in the root module scope. /// Exported macros are just all macros in the root module scope.
/// Note that it contains not only all `#[macro_export]` macros, but also all aliases /// Note that it contains not only all `#[macro_export]` macros, but also all aliases
/// created by `use` in the root module, ignoring the visibility of `use`. /// created by `use` in the root module, ignoring the visibility of `use`.
fn import_macros_from_extern_crate(&mut self, krate: CrateId, names: Option<Vec<Name>>) { fn import_macros_from_extern_crate(
&mut self,
krate: CrateId,
names: Option<Vec<Name>>,
extern_crate: Option<ExternCrateId>,
) {
let def_map = self.db.crate_def_map(krate); let def_map = self.db.crate_def_map(krate);
// `#[macro_use]` brings macros into macro_use prelude. Yes, even non-`macro_rules!` // `#[macro_use]` brings macros into macro_use prelude. Yes, even non-`macro_rules!`
// macros. // macros.
@ -729,12 +725,12 @@ fn import_macros_from_extern_crate(&mut self, krate: CrateId, names: Option<Vec<
for name in names { for name in names {
// FIXME: Report diagnostic on 404. // FIXME: Report diagnostic on 404.
if let Some(def) = root_scope.get(&name).take_macros() { if let Some(def) = root_scope.get(&name).take_macros() {
self.def_map.macro_use_prelude.insert(name, def); self.def_map.macro_use_prelude.insert(name, (def, extern_crate));
} }
} }
} else { } else {
for (name, def) in root_scope.macros() { for (name, def) in root_scope.macros() {
self.def_map.macro_use_prelude.insert(name.clone(), def); self.def_map.macro_use_prelude.insert(name.clone(), (def, extern_crate));
} }
} }
} }
@ -771,48 +767,52 @@ fn resolve_import(&self, module_id: LocalModuleId, import: &Import) -> PartialRe
let _p = profile::span("resolve_import") let _p = profile::span("resolve_import")
.detail(|| format!("{}", import.path.display(self.db.upcast()))); .detail(|| format!("{}", import.path.display(self.db.upcast())));
tracing::debug!("resolving import: {:?} ({:?})", import, self.def_map.data.edition); tracing::debug!("resolving import: {:?} ({:?})", import, self.def_map.data.edition);
if matches!(import.source, ImportSource::ExternCrate { .. }) { match import.source {
let name = import ImportSource::ExternCrate { .. } => {
.path let name = import
.as_ident() .path
.expect("extern crate should have been desugared to one-element path"); .as_ident()
.expect("extern crate should have been desugared to one-element path");
let res = self.resolve_extern_crate(name); let res = self.resolve_extern_crate(name);
match res { match res {
Some(res) => { Some(res) => PartialResolvedImport::Resolved(PerNs::types(
PartialResolvedImport::Resolved(PerNs::types(res.into(), Visibility::Public)) res.into(),
} Visibility::Public,
None => PartialResolvedImport::Unresolved, )),
} None => PartialResolvedImport::Unresolved,
} else {
let res = self.def_map.resolve_path_fp_with_macro(
self.db,
ResolveMode::Import,
module_id,
&import.path,
BuiltinShadowMode::Module,
None, // An import may resolve to any kind of macro.
);
let def = res.resolved_def;
if res.reached_fixedpoint == ReachedFixedPoint::No || def.is_none() {
return PartialResolvedImport::Unresolved;
}
if let Some(krate) = res.krate {
if krate != self.def_map.krate {
return PartialResolvedImport::Resolved(
def.filter_visibility(|v| matches!(v, Visibility::Public)),
);
} }
} }
ImportSource::Use { .. } => {
let res = self.def_map.resolve_path_fp_with_macro(
self.db,
ResolveMode::Import,
module_id,
&import.path,
BuiltinShadowMode::Module,
None, // An import may resolve to any kind of macro.
);
// Check whether all namespaces are resolved. let def = res.resolved_def;
if def.is_full() { if res.reached_fixedpoint == ReachedFixedPoint::No || def.is_none() {
PartialResolvedImport::Resolved(def) return PartialResolvedImport::Unresolved;
} else { }
PartialResolvedImport::Indeterminate(def)
if let Some(krate) = res.krate {
if krate != self.def_map.krate {
return PartialResolvedImport::Resolved(
def.filter_visibility(|v| matches!(v, Visibility::Public)),
);
}
}
// Check whether all namespaces are resolved.
if def.is_full() {
PartialResolvedImport::Resolved(def)
} else {
PartialResolvedImport::Indeterminate(def)
}
} }
} }
} }
@ -859,17 +859,17 @@ fn record_resolved_import(&mut self, directive: &ImportDirective) {
tracing::debug!("resolved import {:?} ({:?}) to {:?}", name, import, def); tracing::debug!("resolved import {:?} ({:?}) to {:?}", name, import, def);
// extern crates in the crate root are special-cased to insert entries into the extern prelude: rust-lang/rust#54658 // extern crates in the crate root are special-cased to insert entries into the extern prelude: rust-lang/rust#54658
if matches!(import.source, ImportSource::ExternCrate { .. }) if let ImportSource::ExternCrate { id, .. } = import.source {
&& self.def_map.block.is_none() if self.def_map.block.is_none() && module_id == DefMap::ROOT {
&& module_id == DefMap::ROOT if let (Some(ModuleDefId::ModuleId(def)), Some(name)) =
{ (def.take_types(), name)
if let (Some(ModuleDefId::ModuleId(def)), Some(name)) = (def.take_types(), name) {
{ if let Ok(def) = def.try_into() {
if let Ok(def) = def.try_into() { Arc::get_mut(&mut self.def_map.data)
Arc::get_mut(&mut self.def_map.data) .unwrap()
.unwrap() .extern_prelude
.extern_prelude .insert(name.clone(), (def, Some(id)));
.insert(name.clone(), def); }
} }
} }
} }
@ -880,11 +880,11 @@ fn record_resolved_import(&mut self, directive: &ImportDirective) {
tracing::debug!("glob import: {:?}", import); tracing::debug!("glob import: {:?}", import);
match def.take_types() { match def.take_types() {
Some(ModuleDefId::ModuleId(m)) => { Some(ModuleDefId::ModuleId(m)) => {
if import.is_prelude { if let ImportSource::Use { id, is_prelude: true, .. } = import.source {
// Note: This dodgily overrides the injected prelude. The rustc // Note: This dodgily overrides the injected prelude. The rustc
// implementation seems to work the same though. // implementation seems to work the same though.
cov_mark::hit!(std_prelude); cov_mark::hit!(std_prelude);
self.def_map.prelude = Some(m); self.def_map.prelude = Some((m, Some(id)));
} else if m.krate != self.def_map.krate { } else if m.krate != self.def_map.krate {
cov_mark::hit!(glob_across_crates); cov_mark::hit!(glob_across_crates);
// glob import from other crate => we can just import everything once // glob import from other crate => we can just import everything once
@ -1460,31 +1460,32 @@ fn finish(mut self) -> DefMap {
// heuristic, but it works in practice. // heuristic, but it works in practice.
let mut diagnosed_extern_crates = FxHashSet::default(); let mut diagnosed_extern_crates = FxHashSet::default();
for directive in &self.unresolved_imports { for directive in &self.unresolved_imports {
if let ImportSource::ExternCrate(krate) = directive.import.source { if let ImportSource::ExternCrate { id } = directive.import.source {
let item_tree = krate.item_tree(self.db); let item_tree_id = self.db.lookup_intern_extern_crate(id).id;
let extern_crate = &item_tree[krate.value]; let item_tree = item_tree_id.item_tree(self.db);
let extern_crate = &item_tree[item_tree_id.value];
diagnosed_extern_crates.insert(extern_crate.name.clone()); diagnosed_extern_crates.insert(extern_crate.name.clone());
self.def_map.diagnostics.push(DefDiagnostic::unresolved_extern_crate( self.def_map.diagnostics.push(DefDiagnostic::unresolved_extern_crate(
directive.module_id, directive.module_id,
InFile::new(krate.file_id(), extern_crate.ast_id), InFile::new(item_tree_id.file_id(), extern_crate.ast_id),
)); ));
} }
} }
for directive in &self.unresolved_imports { for directive in &self.unresolved_imports {
if let ImportSource::Use { id: import, use_tree } = directive.import.source { if let ImportSource::Use { use_tree, id, is_prelude: _ } = directive.import.source {
if matches!( if matches!(
(directive.import.path.segments().first(), &directive.import.path.kind), (directive.import.path.segments().first(), &directive.import.path.kind),
(Some(krate), PathKind::Plain | PathKind::Abs) if diagnosed_extern_crates.contains(krate) (Some(krate), PathKind::Plain | PathKind::Abs) if diagnosed_extern_crates.contains(krate)
) { ) {
continue; continue;
} }
let item_tree_id = self.db.lookup_intern_use(id).id;
self.def_map.diagnostics.push(DefDiagnostic::unresolved_import( self.def_map.diagnostics.push(DefDiagnostic::unresolved_import(
directive.module_id, directive.module_id,
import, item_tree_id,
use_tree, use_tree,
)); ));
} }
@ -1519,72 +1520,66 @@ fn collect(&mut self, items: &[ModItem], container: ItemContainerId) {
self.def_collector.mod_dirs.insert(self.module_id, self.mod_dir.clone()); self.def_collector.mod_dirs.insert(self.module_id, self.mod_dir.clone());
// Prelude module is always considered to be `#[macro_use]`. // Prelude module is always considered to be `#[macro_use]`.
if let Some(prelude_module) = self.def_collector.def_map.prelude { if let Some((prelude_module, _use)) = self.def_collector.def_map.prelude {
if prelude_module.krate != krate && is_crate_root { if prelude_module.krate != krate && is_crate_root {
cov_mark::hit!(prelude_is_macro_use); cov_mark::hit!(prelude_is_macro_use);
self.def_collector.import_macros_from_extern_crate(prelude_module.krate, None); self.def_collector.import_macros_from_extern_crate(
prelude_module.krate,
None,
None,
);
} }
} }
let db = self.def_collector.db;
let module_id = self.module_id;
let update_def =
|def_collector: &mut DefCollector<'_>, id, name: &Name, vis, has_constructor| {
def_collector.def_map.modules[module_id].scope.declare(id);
def_collector.update(
module_id,
&[(Some(name.clone()), PerNs::from_def(id, vis, has_constructor))],
vis,
ImportType::Named,
)
};
let resolve_vis = |def_map: &DefMap, visibility| {
def_map
.resolve_visibility(db, module_id, visibility, false)
.unwrap_or(Visibility::Public)
};
// This should be processed eagerly instead of deferred to resolving. let mut process_mod_item = |item: ModItem| {
// `#[macro_use] extern crate` is hoisted to imports macros before collecting let attrs = self.item_tree.attrs(db, krate, item.into());
// any other items.
//
// If we're not at the crate root, `macro_use`d extern crates are an error so let's just
// ignore them.
if is_crate_root {
for &item in items {
if let ModItem::ExternCrate(id) = item {
self.process_macro_use_extern_crate(id);
}
}
}
for &item in items {
let attrs = self.item_tree.attrs(self.def_collector.db, krate, item.into());
if let Some(cfg) = attrs.cfg() { if let Some(cfg) = attrs.cfg() {
if !self.is_cfg_enabled(&cfg) { if !self.is_cfg_enabled(&cfg) {
self.emit_unconfigured_diagnostic(item, &cfg); self.emit_unconfigured_diagnostic(item, &cfg);
continue; return;
} }
} }
if let Err(()) = self.resolve_attributes(&attrs, item, container) { if let Err(()) = self.resolve_attributes(&attrs, item, container) {
// Do not process the item. It has at least one non-builtin attribute, so the // Do not process the item. It has at least one non-builtin attribute, so the
// fixed-point algorithm is required to resolve the rest of them. // fixed-point algorithm is required to resolve the rest of them.
continue; return;
} }
let db = self.def_collector.db; let module = self.def_collector.def_map.module_id(module_id);
let module = self.def_collector.def_map.module_id(self.module_id);
let def_map = &mut self.def_collector.def_map; let def_map = &mut self.def_collector.def_map;
let update_def =
|def_collector: &mut DefCollector<'_>, id, name: &Name, vis, has_constructor| {
def_collector.def_map.modules[self.module_id].scope.declare(id);
def_collector.update(
self.module_id,
&[(Some(name.clone()), PerNs::from_def(id, vis, has_constructor))],
vis,
ImportType::Named,
)
};
let resolve_vis = |def_map: &DefMap, visibility| {
def_map
.resolve_visibility(db, self.module_id, visibility, false)
.unwrap_or(Visibility::Public)
};
match item { match item {
ModItem::Mod(m) => self.collect_module(m, &attrs), ModItem::Mod(m) => self.collect_module(m, &attrs),
ModItem::Use(import_id) => { ModItem::Use(item_tree_id) => {
let _import_id = let id = UseLoc {
UseLoc { container: module, id: ItemTreeId::new(self.tree_id, import_id) } container: module,
.intern(db); id: ItemTreeId::new(self.tree_id, item_tree_id),
}
.intern(db);
let is_prelude = attrs.by_key("prelude_import").exists();
Import::from_use( Import::from_use(
db,
krate,
self.item_tree, self.item_tree,
ItemTreeId::new(self.tree_id, import_id), ItemTreeId::new(self.tree_id, item_tree_id),
id,
is_prelude,
|import| { |import| {
self.def_collector.unresolved_imports.push(ImportDirective { self.def_collector.unresolved_imports.push(ImportDirective {
module_id: self.module_id, module_id: self.module_id,
@ -1594,22 +1589,29 @@ fn collect(&mut self, items: &[ModItem], container: ItemContainerId) {
}, },
) )
} }
ModItem::ExternCrate(import_id) => { ModItem::ExternCrate(item_tree_id) => {
let extern_crate_id = ExternCrateLoc { let id = ExternCrateLoc {
container: module, container: module,
id: ItemTreeId::new(self.tree_id, import_id), id: ItemTreeId::new(self.tree_id, item_tree_id),
} }
.intern(db); .intern(db);
if is_crate_root {
self.process_macro_use_extern_crate(
item_tree_id,
id,
attrs.by_key("macro_use").attrs(),
);
}
self.def_collector.def_map.modules[self.module_id] self.def_collector.def_map.modules[self.module_id]
.scope .scope
.define_extern_crate_decl(extern_crate_id); .define_extern_crate_decl(id);
self.def_collector.unresolved_imports.push(ImportDirective { self.def_collector.unresolved_imports.push(ImportDirective {
module_id: self.module_id, module_id: self.module_id,
import: Import::from_extern_crate( import: Import::from_extern_crate(
db,
krate,
self.item_tree, self.item_tree,
ItemTreeId::new(self.tree_id, import_id), ItemTreeId::new(self.tree_id, item_tree_id),
id,
), ),
status: PartialResolvedImport::Unresolved, status: PartialResolvedImport::Unresolved,
}) })
@ -1768,21 +1770,34 @@ fn collect(&mut self, items: &[ModItem], container: ItemContainerId) {
); );
} }
} }
};
// extern crates should be processed eagerly instead of deferred to resolving.
// `#[macro_use] extern crate` is hoisted to imports macros before collecting
// any other items.
if is_crate_root {
items
.iter()
.filter(|it| matches!(it, ModItem::ExternCrate(..)))
.copied()
.for_each(&mut process_mod_item);
items
.iter()
.filter(|it| !matches!(it, ModItem::ExternCrate(..)))
.copied()
.for_each(process_mod_item);
} else {
items.iter().copied().for_each(process_mod_item);
} }
} }
fn process_macro_use_extern_crate(&mut self, extern_crate: FileItemTreeId<ExternCrate>) { fn process_macro_use_extern_crate<'a>(
&mut self,
extern_crate: FileItemTreeId<ExternCrate>,
extern_crate_id: ExternCrateId,
macro_use_attrs: impl Iterator<Item = &'a Attr>,
) {
let db = self.def_collector.db; let db = self.def_collector.db;
let attrs = self.item_tree.attrs(
db,
self.def_collector.def_map.krate,
ModItem::from(extern_crate).into(),
);
if let Some(cfg) = attrs.cfg() {
if !self.is_cfg_enabled(&cfg) {
return;
}
}
let target_crate = let target_crate =
match self.def_collector.resolve_extern_crate(&self.item_tree[extern_crate].name) { match self.def_collector.resolve_extern_crate(&self.item_tree[extern_crate].name) {
@ -1798,11 +1813,11 @@ fn process_macro_use_extern_crate(&mut self, extern_crate: FileItemTreeId<Extern
let mut single_imports = Vec::new(); let mut single_imports = Vec::new();
let hygiene = Hygiene::new_unhygienic(); let hygiene = Hygiene::new_unhygienic();
for attr in attrs.by_key("macro_use").attrs() { for attr in macro_use_attrs {
let Some(paths) = attr.parse_path_comma_token_tree(db.upcast(), &hygiene) else { let Some(paths) = attr.parse_path_comma_token_tree(db.upcast(), &hygiene) else {
// `#[macro_use]` (without any paths) found, forget collected names and just import // `#[macro_use]` (without any paths) found, forget collected names and just import
// all visible macros. // all visible macros.
self.def_collector.import_macros_from_extern_crate(target_crate, None); self.def_collector.import_macros_from_extern_crate(target_crate, None, Some(extern_crate_id));
return; return;
}; };
for path in paths { for path in paths {
@ -1812,7 +1827,11 @@ fn process_macro_use_extern_crate(&mut self, extern_crate: FileItemTreeId<Extern
} }
} }
self.def_collector.import_macros_from_extern_crate(target_crate, Some(single_imports)); self.def_collector.import_macros_from_extern_crate(
target_crate,
Some(single_imports),
Some(extern_crate_id),
);
} }
fn collect_module(&mut self, module_id: FileItemTreeId<Mod>, attrs: &Attrs) { fn collect_module(&mut self, module_id: FileItemTreeId<Mod>, attrs: &Attrs) {
@ -2198,7 +2217,7 @@ fn collect_macro_call(&mut self, mac: &MacroCall, container: ItemContainerId) {
map[module].scope.get_legacy_macro(name)?.last().copied() map[module].scope.get_legacy_macro(name)?.last().copied()
}) })
.or_else(|| def_map[self.module_id].scope.get(name).take_macros()) .or_else(|| def_map[self.module_id].scope.get(name).take_macros())
.or_else(|| def_map.macro_use_prelude.get(name).copied()) .or_else(|| Some(def_map.macro_use_prelude.get(name).copied()?.0))
.filter(|&id| { .filter(|&id| {
sub_namespace_match( sub_namespace_match(
Some(MacroSubNs::from_id(db, id)), Some(MacroSubNs::from_id(db, id)),

View File

@ -299,7 +299,7 @@ pub(super) fn resolve_path_fp_with_macro_single(
Some((_, segment)) => segment, Some((_, segment)) => segment,
None => return ResolvePathResult::empty(ReachedFixedPoint::Yes), None => return ResolvePathResult::empty(ReachedFixedPoint::Yes),
}; };
if let Some(&def) = self.data.extern_prelude.get(segment) { if let Some(&(def, _extern_crate)) = self.data.extern_prelude.get(segment) {
tracing::debug!("absolute path {:?} resolved to crate {:?}", path, def); tracing::debug!("absolute path {:?} resolved to crate {:?}", path, def);
PerNs::types(def.into(), Visibility::Public) PerNs::types(def.into(), Visibility::Public)
} else { } else {
@ -452,15 +452,14 @@ fn resolve_name_in_module(
// Don't resolve extern prelude in block `DefMap`s. // Don't resolve extern prelude in block `DefMap`s.
return PerNs::none(); return PerNs::none();
} }
self.data self.data.extern_prelude.get(name).map_or(PerNs::none(), |&(it, _extern_crate)| {
.extern_prelude PerNs::types(it.into(), Visibility::Public)
.get(name) })
.map_or(PerNs::none(), |&it| PerNs::types(it.into(), Visibility::Public))
}; };
let macro_use_prelude = || { let macro_use_prelude = || {
self.macro_use_prelude self.macro_use_prelude.get(name).map_or(PerNs::none(), |&(it, _extern_crate)| {
.get(name) PerNs::macros(it.into(), Visibility::Public)
.map_or(PerNs::none(), |&it| PerNs::macros(it.into(), Visibility::Public)) })
}; };
let prelude = || self.resolve_in_prelude(db, name); let prelude = || self.resolve_in_prelude(db, name);
@ -492,14 +491,16 @@ fn resolve_name_in_crate_root_or_extern_prelude(
.extern_prelude .extern_prelude
.get(name) .get(name)
.copied() .copied()
.map_or(PerNs::none(), |it| PerNs::types(it.into(), Visibility::Public)) .map_or(PerNs::none(), |(it, _extern_crate)| {
PerNs::types(it.into(), Visibility::Public)
})
}; };
from_crate_root.or_else(from_extern_prelude) from_crate_root.or_else(from_extern_prelude)
} }
fn resolve_in_prelude(&self, db: &dyn DefDatabase, name: &Name) -> PerNs { fn resolve_in_prelude(&self, db: &dyn DefDatabase, name: &Name) -> PerNs {
if let Some(prelude) = self.prelude { if let Some((prelude, _use)) = self.prelude {
let keep; let keep;
let def_map = if prelude.krate == self.krate { let def_map = if prelude.krate == self.krate {
self self

View File

@ -433,16 +433,16 @@ pub fn names_in_scope(
res.add(name, ScopeDef::ModuleDef(ModuleDefId::MacroId(mac))); res.add(name, ScopeDef::ModuleDef(ModuleDefId::MacroId(mac)));
}) })
}); });
def_map.macro_use_prelude().for_each(|(name, def)| { def_map.macro_use_prelude().for_each(|(name, (def, _extern_crate))| {
res.add(name, ScopeDef::ModuleDef(def.into())); res.add(name, ScopeDef::ModuleDef(def.into()));
}); });
def_map.extern_prelude().for_each(|(name, def)| { def_map.extern_prelude().for_each(|(name, (def, _extern_crate))| {
res.add(name, ScopeDef::ModuleDef(ModuleDefId::ModuleId(def))); res.add(name, ScopeDef::ModuleDef(ModuleDefId::ModuleId(def.into())));
}); });
BUILTIN_SCOPE.iter().for_each(|(name, &def)| { BUILTIN_SCOPE.iter().for_each(|(name, &def)| {
res.add_per_ns(name, def); res.add_per_ns(name, def);
}); });
if let Some(prelude) = def_map.prelude() { if let Some((prelude, _use)) = def_map.prelude() {
let prelude_def_map = prelude.def_map(db); let prelude_def_map = prelude.def_map(db);
for (name, def) in prelude_def_map[prelude.local_id].scope.entries() { for (name, def) in prelude_def_map[prelude.local_id].scope.entries() {
res.add_per_ns(name, def) res.add_per_ns(name, def)
@ -473,7 +473,7 @@ pub fn traits_in_scope(&self, db: &dyn DefDatabase) -> FxHashSet<TraitId> {
} }
// Fill in the prelude traits // Fill in the prelude traits
if let Some(prelude) = self.module_scope.def_map.prelude() { if let Some((prelude, _use)) = self.module_scope.def_map.prelude() {
let prelude_def_map = prelude.def_map(db); let prelude_def_map = prelude.def_map(db);
traits.extend(prelude_def_map[prelude.local_id].scope.traits()); traits.extend(prelude_def_map[prelude.local_id].scope.traits());
} }