Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/hir-def/src/nameres/collector.rs')
-rw-r--r--crates/hir-def/src/nameres/collector.rs434
1 files changed, 232 insertions, 202 deletions
diff --git a/crates/hir-def/src/nameres/collector.rs b/crates/hir-def/src/nameres/collector.rs
index eef54fc492..e9e71a8747 100644
--- a/crates/hir-def/src/nameres/collector.rs
+++ b/crates/hir-def/src/nameres/collector.rs
@@ -33,7 +33,7 @@ use crate::{
attr_macro_as_call_id,
db::DefDatabase,
derive_macro_as_call_id,
- item_scope::{ImportType, PerNsGlobImports},
+ item_scope::{ImportId, ImportOrExternCrate, ImportType, PerNsGlobImports},
item_tree::{
self, ExternCrate, Fields, FileItemTreeId, ImportKind, ItemTree, ItemTreeId, ItemTreeNode,
MacroCall, MacroDef, MacroRules, Mod, ModItem, ModKind, TreeId,
@@ -52,10 +52,10 @@ use crate::{
tt,
visibility::{RawVisibility, Visibility},
AdtId, AstId, AstIdWithPath, ConstLoc, CrateRootModuleId, EnumLoc, EnumVariantId,
- ExternBlockLoc, ExternCrateLoc, FunctionId, FunctionLoc, ImplLoc, Intern, ItemContainerId,
- LocalModuleId, Macro2Id, Macro2Loc, MacroExpander, MacroId, MacroRulesId, MacroRulesLoc,
- ModuleDefId, ModuleId, ProcMacroId, ProcMacroLoc, StaticLoc, StructLoc, TraitAliasLoc,
- TraitLoc, TypeAliasLoc, UnionLoc, UnresolvedMacro, UseLoc,
+ ExternBlockLoc, ExternCrateId, ExternCrateLoc, FunctionId, FunctionLoc, ImplLoc, Intern,
+ ItemContainerId, LocalModuleId, Lookup, Macro2Id, Macro2Loc, MacroExpander, MacroId,
+ MacroRulesId, MacroRulesLoc, ModuleDefId, ModuleId, ProcMacroId, ProcMacroLoc, StaticLoc,
+ StructLoc, TraitAliasLoc, TraitLoc, TypeAliasLoc, UnionLoc, UnresolvedMacro, UseId, UseLoc,
};
static GLOB_RECURSION_LIMIT: Limit = Limit::new(100);
@@ -146,8 +146,8 @@ impl PartialResolvedImport {
#[derive(Clone, Debug, Eq, PartialEq)]
enum ImportSource {
- Use { id: ItemTreeId<item_tree::Use>, use_tree: Idx<ast::UseTree> },
- ExternCrate(ItemTreeId<item_tree::ExternCrate>),
+ Use { use_tree: Idx<ast::UseTree>, id: UseId, is_prelude: bool, kind: ImportKind },
+ ExternCrate { id: ExternCrateId },
}
#[derive(Debug, Eq, PartialEq)]
@@ -155,54 +155,41 @@ struct Import {
path: ModPath,
alias: Option<ImportAlias>,
visibility: RawVisibility,
- kind: ImportKind,
source: ImportSource,
- is_prelude: bool,
- is_macro_use: bool,
}
impl Import {
fn from_use(
- db: &dyn DefDatabase,
- krate: CrateId,
tree: &ItemTree,
- id: ItemTreeId<item_tree::Use>,
+ item_tree_id: ItemTreeId<item_tree::Use>,
+ id: UseId,
+ is_prelude: bool,
mut cb: impl FnMut(Self),
) {
- let it = &tree[id.value];
- let attrs = &tree.attrs(db, krate, ModItem::from(id.value).into());
+ let it = &tree[item_tree_id.value];
let visibility = &tree[it.visibility];
- let is_prelude = attrs.by_key("prelude_import").exists();
it.use_tree.expand(|idx, path, kind, alias| {
cb(Self {
path,
alias,
visibility: visibility.clone(),
- kind,
- is_prelude,
- is_macro_use: false,
- source: ImportSource::Use { id, use_tree: idx },
+ source: ImportSource::Use { use_tree: idx, id, is_prelude, kind },
});
});
}
fn from_extern_crate(
- db: &dyn DefDatabase,
- krate: CrateId,
tree: &ItemTree,
- id: ItemTreeId<item_tree::ExternCrate>,
+ item_tree_id: ItemTreeId<item_tree::ExternCrate>,
+ id: ExternCrateId,
) -> Self {
- let it = &tree[id.value];
- let attrs = &tree.attrs(db, krate, ModItem::from(id.value).into());
+ let it = &tree[item_tree_id.value];
let visibility = &tree[it.visibility];
Self {
path: ModPath::from_segments(PathKind::Plain, iter::once(it.name.clone())),
alias: it.alias.clone(),
visibility: visibility.clone(),
- kind: ImportKind::Plain,
- is_prelude: false,
- is_macro_use: attrs.by_key("macro_use").exists(),
- source: ImportSource::ExternCrate(id),
+ source: ImportSource::ExternCrate { id },
}
}
}
@@ -235,7 +222,7 @@ struct DefCollector<'a> {
db: &'a dyn DefDatabase,
def_map: DefMap,
deps: FxHashMap<Name, Dependency>,
- glob_imports: FxHashMap<LocalModuleId, Vec<(LocalModuleId, Visibility)>>,
+ glob_imports: FxHashMap<LocalModuleId, Vec<(LocalModuleId, Visibility, UseId)>>,
unresolved_imports: Vec<ImportDirective>,
indeterminate_imports: Vec<ImportDirective>,
unresolved_macros: Vec<MacroDirective>,
@@ -280,7 +267,7 @@ impl DefCollector<'_> {
if dep.is_prelude() {
crate_data
.extern_prelude
- .insert(name.clone(), CrateRootModuleId { krate: dep.crate_id });
+ .insert(name.clone(), (CrateRootModuleId { krate: dep.crate_id }, None));
}
}
@@ -556,8 +543,12 @@ impl DefCollector<'_> {
self.def_map.resolve_path(self.db, DefMap::ROOT, &path, BuiltinShadowMode::Other, None);
match per_ns.types {
- Some((ModuleDefId::ModuleId(m), _)) => {
- self.def_map.prelude = Some(m);
+ Some((ModuleDefId::ModuleId(m), _, import)) => {
+ // FIXME: This should specifically look for a glob import somehow and record that here
+ self.def_map.prelude = Some((
+ m,
+ import.and_then(ImportOrExternCrate::into_import).map(|it| it.import),
+ ));
}
types => {
tracing::debug!(
@@ -657,9 +648,9 @@ impl DefCollector<'_> {
self.def_map.modules[module_id].scope.declare(macro_.into());
self.update(
module_id,
- &[(Some(name), PerNs::macros(macro_.into(), Visibility::Public))],
+ &[(Some(name), PerNs::macros(macro_.into(), Visibility::Public, None))],
Visibility::Public,
- ImportType::Named,
+ None,
);
}
}
@@ -693,9 +684,9 @@ impl DefCollector<'_> {
self.def_map.modules[module_id].scope.declare(macro_.into());
self.update(
module_id,
- &[(Some(name), PerNs::macros(macro_.into(), Visibility::Public))],
+ &[(Some(name), PerNs::macros(macro_.into(), Visibility::Public, None))],
vis,
- ImportType::Named,
+ None,
);
}
@@ -708,9 +699,9 @@ impl DefCollector<'_> {
self.def_map.modules[module_id].scope.declare(macro_.into());
self.update(
module_id,
- &[(Some(name), PerNs::macros(macro_.into(), Visibility::Public))],
+ &[(Some(name), PerNs::macros(macro_.into(), Visibility::Public, None))],
Visibility::Public,
- ImportType::Named,
+ None,
);
}
@@ -720,21 +711,29 @@ impl DefCollector<'_> {
/// 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
/// 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);
// `#[macro_use]` brings macros into macro_use prelude. Yes, even non-`macro_rules!`
// macros.
let root_scope = &def_map[DefMap::ROOT].scope;
- if let Some(names) = names {
- for name in names {
- // FIXME: Report diagnostic on 404.
- if let Some(def) = root_scope.get(&name).take_macros() {
- self.def_map.macro_use_prelude.insert(name, def);
+ match names {
+ Some(names) => {
+ for name in names {
+ // FIXME: Report diagnostic on 404.
+ if let Some(def) = root_scope.get(&name).take_macros() {
+ self.def_map.macro_use_prelude.insert(name, (def, extern_crate));
+ }
}
}
- } else {
- for (name, def) in root_scope.macros() {
- self.def_map.macro_use_prelude.insert(name.clone(), def);
+ None => {
+ for (name, def) in root_scope.macros() {
+ self.def_map.macro_use_prelude.insert(name.clone(), (def, extern_crate));
+ }
}
}
}
@@ -771,48 +770,53 @@ impl DefCollector<'_> {
let _p = profile::span("resolve_import")
.detail(|| format!("{}", import.path.display(self.db.upcast())));
tracing::debug!("resolving import: {:?} ({:?})", import, self.def_map.data.edition);
- if matches!(import.source, ImportSource::ExternCrate { .. }) {
- let name = import
- .path
- .as_ident()
- .expect("extern crate should have been desugared to one-element path");
-
- let res = self.resolve_extern_crate(name);
-
- match res {
- Some(res) => {
- PartialResolvedImport::Resolved(PerNs::types(res.into(), Visibility::Public))
+ match import.source {
+ ImportSource::ExternCrate { .. } => {
+ let name = import
+ .path
+ .as_ident()
+ .expect("extern crate should have been desugared to one-element path");
+
+ let res = self.resolve_extern_crate(name);
+
+ match res {
+ Some(res) => PartialResolvedImport::Resolved(PerNs::types(
+ res.into(),
+ Visibility::Public,
+ None,
+ )),
+ 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.
- );
+ 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.
+ );
- let def = res.resolved_def;
- if res.reached_fixedpoint == ReachedFixedPoint::No || def.is_none() {
- return PartialResolvedImport::Unresolved;
- }
+ 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)),
- );
+ 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)
+ // Check whether all namespaces are resolved.
+ if def.is_full() {
+ PartialResolvedImport::Resolved(def)
+ } else {
+ PartialResolvedImport::Indeterminate(def)
+ }
}
}
}
@@ -837,8 +841,9 @@ impl DefCollector<'_> {
.resolve_visibility(self.db, module_id, &directive.import.visibility, false)
.unwrap_or(Visibility::Public);
- match import.kind {
- ImportKind::Plain | ImportKind::TypeOnly => {
+ match import.source {
+ ImportSource::ExternCrate { .. }
+ | ImportSource::Use { kind: ImportKind::Plain | ImportKind::TypeOnly, .. } => {
let name = match &import.alias {
Some(ImportAlias::Alias(name)) => Some(name),
Some(ImportAlias::Underscore) => None,
@@ -851,40 +856,44 @@ impl DefCollector<'_> {
},
};
- if import.kind == ImportKind::TypeOnly {
- def.values = None;
- def.macros = None;
- }
-
- 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
- if matches!(import.source, ImportSource::ExternCrate { .. })
- && self.def_map.block.is_none()
- && module_id == DefMap::ROOT
- {
- if let (Some(ModuleDefId::ModuleId(def)), Some(name)) = (def.take_types(), name)
- {
- if let Ok(def) = def.try_into() {
- Arc::get_mut(&mut self.def_map.data)
- .unwrap()
- .extern_prelude
- .insert(name.clone(), def);
+ let imp = match import.source {
+ // extern crates in the crate root are special-cased to insert entries into the extern prelude: rust-lang/rust#54658
+ ImportSource::ExternCrate { id, .. } => {
+ if self.def_map.block.is_none() && module_id == DefMap::ROOT {
+ if let (Some(ModuleDefId::ModuleId(def)), Some(name)) =
+ (def.take_types(), name)
+ {
+ if let Ok(def) = def.try_into() {
+ Arc::get_mut(&mut self.def_map.data)
+ .unwrap()
+ .extern_prelude
+ .insert(name.clone(), (def, Some(id)));
+ }
+ }
}
+ ImportType::ExternCrate(id)
}
- }
+ ImportSource::Use { kind, id, use_tree, .. } => {
+ if kind == ImportKind::TypeOnly {
+ def.values = None;
+ def.macros = None;
+ }
+ ImportType::Import(ImportId { import: id, idx: use_tree })
+ }
+ };
+ tracing::debug!("resolved import {:?} ({:?}) to {:?}", name, import, def);
- self.update(module_id, &[(name.cloned(), def)], vis, ImportType::Named);
+ self.update(module_id, &[(name.cloned(), def)], vis, Some(imp));
}
- ImportKind::Glob => {
+ ImportSource::Use { kind: ImportKind::Glob, id, .. } => {
tracing::debug!("glob import: {:?}", import);
match def.take_types() {
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
// implementation seems to work the same though.
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 {
cov_mark::hit!(glob_across_crates);
// glob import from other crate => we can just import everything once
@@ -901,7 +910,7 @@ impl DefCollector<'_> {
.filter(|(_, res)| !res.is_none())
.collect::<Vec<_>>();
- self.update(module_id, &items, vis, ImportType::Glob);
+ self.update(module_id, &items, vis, Some(ImportType::Glob(id)));
} else {
// glob import from same crate => we do an initial
// import, and then need to propagate any further
@@ -933,11 +942,11 @@ impl DefCollector<'_> {
.filter(|(_, res)| !res.is_none())
.collect::<Vec<_>>();
- self.update(module_id, &items, vis, ImportType::Glob);
+ self.update(module_id, &items, vis, Some(ImportType::Glob(id)));
// record the glob import in case we add further items
let glob = self.glob_imports.entry(m.local_id).or_default();
- if !glob.iter().any(|(mid, _)| *mid == module_id) {
- glob.push((module_id, vis));
+ if !glob.iter().any(|(mid, _, _)| *mid == module_id) {
+ glob.push((module_id, vis, id));
}
}
}
@@ -959,11 +968,11 @@ impl DefCollector<'_> {
.map(|(local_id, variant_data)| {
let name = variant_data.name.clone();
let variant = EnumVariantId { parent: e, local_id };
- let res = PerNs::both(variant.into(), variant.into(), vis);
+ let res = PerNs::both(variant.into(), variant.into(), vis, None);
(Some(name), res)
})
.collect::<Vec<_>>();
- self.update(module_id, &resolutions, vis, ImportType::Glob);
+ self.update(module_id, &resolutions, vis, Some(ImportType::Glob(id)));
}
Some(d) => {
tracing::debug!("glob import {:?} from non-module/enum {:?}", import, d);
@@ -983,10 +992,10 @@ impl DefCollector<'_> {
resolutions: &[(Option<Name>, PerNs)],
// Visibility this import will have
vis: Visibility,
- import_type: ImportType,
+ import: Option<ImportType>,
) {
self.db.unwind_if_cancelled();
- self.update_recursive(module_id, resolutions, vis, import_type, 0)
+ self.update_recursive(module_id, resolutions, vis, import, 0)
}
fn update_recursive(
@@ -997,7 +1006,7 @@ impl DefCollector<'_> {
// All resolutions are imported with this visibility; the visibilities in
// the `PerNs` values are ignored and overwritten
vis: Visibility,
- import_type: ImportType,
+ import: Option<ImportType>,
depth: usize,
) {
if GLOB_RECURSION_LIMIT.check(depth).is_err() {
@@ -1014,7 +1023,7 @@ impl DefCollector<'_> {
&mut self.from_glob_import,
(module_id, name.clone()),
res.with_visibility(vis),
- import_type,
+ import,
);
}
None => {
@@ -1059,7 +1068,7 @@ impl DefCollector<'_> {
.get(&module_id)
.into_iter()
.flatten()
- .filter(|(glob_importing_module, _)| {
+ .filter(|(glob_importing_module, _, _)| {
// we know all resolutions have the same visibility (`vis`), so we
// just need to check that once
vis.is_visible_from_def_map(self.db, &self.def_map, *glob_importing_module)
@@ -1067,12 +1076,12 @@ impl DefCollector<'_> {
.cloned()
.collect::<Vec<_>>();
- for (glob_importing_module, glob_import_vis) in glob_imports {
+ for (glob_importing_module, glob_import_vis, use_) in glob_imports {
self.update_recursive(
glob_importing_module,
resolutions,
glob_import_vis,
- ImportType::Glob,
+ Some(ImportType::Glob(use_)),
depth + 1,
);
}
@@ -1460,31 +1469,34 @@ impl DefCollector<'_> {
// heuristic, but it works in practice.
let mut diagnosed_extern_crates = FxHashSet::default();
for directive in &self.unresolved_imports {
- if let ImportSource::ExternCrate(krate) = directive.import.source {
- let item_tree = krate.item_tree(self.db);
- let extern_crate = &item_tree[krate.value];
+ if let ImportSource::ExternCrate { id } = directive.import.source {
+ let item_tree_id = id.lookup(self.db).id;
+ 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());
self.def_map.diagnostics.push(DefDiagnostic::unresolved_extern_crate(
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 {
- if let ImportSource::Use { id: import, use_tree } = directive.import.source {
+ if let ImportSource::Use { use_tree, id, is_prelude: _, kind: _ } =
+ directive.import.source
+ {
if matches!(
(directive.import.path.segments().first(), &directive.import.path.kind),
(Some(krate), PathKind::Plain | PathKind::Abs) if diagnosed_extern_crates.contains(krate)
) {
continue;
}
-
+ let item_tree_id = id.lookup(self.db).id;
self.def_map.diagnostics.push(DefDiagnostic::unresolved_import(
directive.module_id,
- import,
+ item_tree_id,
use_tree,
));
}
@@ -1519,72 +1531,66 @@ impl ModCollector<'_, '_> {
self.def_collector.mod_dirs.insert(self.module_id, self.mod_dir.clone());
// 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 {
cov_mark::hit!(prelude_is_macro_use);
- self.def_collector.import_macros_from_extern_crate(prelude_module.krate, None);
- }
- }
-
- // This should be processed eagerly instead of deferred to resolving.
- // `#[macro_use] extern crate` is hoisted to imports macros before collecting
- // 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);
- }
+ 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, None))],
+ vis,
+ None,
+ )
+ };
+ let resolve_vis = |def_map: &DefMap, visibility| {
+ def_map
+ .resolve_visibility(db, module_id, visibility, false)
+ .unwrap_or(Visibility::Public)
+ };
- for &item in items {
- let attrs = self.item_tree.attrs(self.def_collector.db, krate, item.into());
+ let mut process_mod_item = |item: ModItem| {
+ let attrs = self.item_tree.attrs(db, krate, item.into());
if let Some(cfg) = attrs.cfg() {
if !self.is_cfg_enabled(&cfg) {
self.emit_unconfigured_diagnostic(item, &cfg);
- continue;
+ return;
}
}
if let Err(()) = self.resolve_attributes(&attrs, item, container) {
// 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.
- continue;
+ return;
}
- let db = self.def_collector.db;
- let module = self.def_collector.def_map.module_id(self.module_id);
+ let module = self.def_collector.def_map.module_id(module_id);
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 {
ModItem::Mod(m) => self.collect_module(m, &attrs),
- ModItem::Use(import_id) => {
- let _import_id =
- UseLoc { container: module, id: ItemTreeId::new(self.tree_id, import_id) }
- .intern(db);
+ ModItem::Use(item_tree_id) => {
+ let id = UseLoc {
+ container: module,
+ id: ItemTreeId::new(self.tree_id, item_tree_id),
+ }
+ .intern(db);
+ let is_prelude = attrs.by_key("prelude_import").exists();
Import::from_use(
- db,
- krate,
self.item_tree,
- ItemTreeId::new(self.tree_id, import_id),
+ ItemTreeId::new(self.tree_id, item_tree_id),
+ id,
+ is_prelude,
|import| {
self.def_collector.unresolved_imports.push(ImportDirective {
module_id: self.module_id,
@@ -1594,22 +1600,29 @@ impl ModCollector<'_, '_> {
},
)
}
- ModItem::ExternCrate(import_id) => {
- let extern_crate_id = ExternCrateLoc {
+ ModItem::ExternCrate(item_tree_id) => {
+ let id = ExternCrateLoc {
container: module,
- id: ItemTreeId::new(self.tree_id, import_id),
+ id: ItemTreeId::new(self.tree_id, item_tree_id),
}
.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]
.scope
- .define_extern_crate_decl(extern_crate_id);
+ .define_extern_crate_decl(id);
self.def_collector.unresolved_imports.push(ImportDirective {
module_id: self.module_id,
import: Import::from_extern_crate(
- db,
- krate,
self.item_tree,
- ItemTreeId::new(self.tree_id, import_id),
+ ItemTreeId::new(self.tree_id, item_tree_id),
+ id,
),
status: PartialResolvedImport::Unresolved,
})
@@ -1768,21 +1781,34 @@ impl ModCollector<'_, '_> {
);
}
}
+ };
+
+ // 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 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 =
match self.def_collector.resolve_extern_crate(&self.item_tree[extern_crate].name) {
@@ -1798,11 +1824,11 @@ impl ModCollector<'_, '_> {
let mut single_imports = Vec::new();
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 {
// `#[macro_use]` (without any paths) found, forget collected names and just import
// 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;
};
for path in paths {
@@ -1812,7 +1838,11 @@ impl ModCollector<'_, '_> {
}
}
- 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) {
@@ -1824,7 +1854,7 @@ impl ModCollector<'_, '_> {
ModKind::Inline { items } => {
let module_id = self.push_child_module(
module.name.clone(),
- AstId::new(self.file_id(), module.ast_id),
+ module.ast_id,
None,
&self.item_tree[module.visibility],
module_id,
@@ -1862,7 +1892,7 @@ impl ModCollector<'_, '_> {
if is_enabled {
let module_id = self.push_child_module(
module.name.clone(),
- ast_id,
+ ast_id.value,
Some((file_id, is_mod_rs)),
&self.item_tree[module.visibility],
module_id,
@@ -1889,7 +1919,7 @@ impl ModCollector<'_, '_> {
Err(candidates) => {
self.push_child_module(
module.name.clone(),
- ast_id,
+ ast_id.value,
None,
&self.item_tree[module.visibility],
module_id,
@@ -1906,7 +1936,7 @@ impl ModCollector<'_, '_> {
fn push_child_module(
&mut self,
name: Name,
- declaration: AstId<ast::Module>,
+ declaration: FileAstId<ast::Module>,
definition: Option<(FileId, bool)>,
visibility: &crate::visibility::RawVisibility,
mod_tree_id: FileItemTreeId<Mod>,
@@ -1948,9 +1978,9 @@ impl ModCollector<'_, '_> {
def_map.modules[self.module_id].scope.declare(def);
self.def_collector.update(
self.module_id,
- &[(Some(name), PerNs::from_def(def, vis, false))],
+ &[(Some(name), PerNs::from_def(def, vis, false, None))],
vis,
- ImportType::Named,
+ None,
);
res
}
@@ -2198,7 +2228,7 @@ impl ModCollector<'_, '_> {
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.macro_use_prelude.get(name).copied())
+ .or_else(|| Some(def_map.macro_use_prelude.get(name).copied()?.0))
.filter(|&id| {
sub_namespace_match(
Some(MacroSubNs::from_id(db, id)),