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.rs171
1 files changed, 106 insertions, 65 deletions
diff --git a/crates/hir-def/src/nameres/collector.rs b/crates/hir-def/src/nameres/collector.rs
index a18ac4b28c..1c0f4d4d35 100644
--- a/crates/hir-def/src/nameres/collector.rs
+++ b/crates/hir-def/src/nameres/collector.rs
@@ -3,7 +3,7 @@
//! `DefCollector::collect` contains the fixed-point iteration loop which
//! resolves imports and expands macros.
-use std::{cmp::Ordering, iter, mem};
+use std::{cmp::Ordering, iter, mem, ops::Not};
use base_db::{CrateId, Dependency, Edition, FileId};
use cfg::{CfgExpr, CfgOptions};
@@ -23,7 +23,7 @@ use itertools::{izip, Itertools};
use la_arena::Idx;
use limit::Limit;
use rustc_hash::{FxHashMap, FxHashSet};
-use span::{Span, SyntaxContextId};
+use span::{ErasedFileAstId, Span, SyntaxContextId};
use stdx::always;
use syntax::{ast, SmolStr};
use triomphe::Arc;
@@ -35,8 +35,8 @@ use crate::{
derive_macro_as_call_id,
item_scope::{ImportId, ImportOrExternCrate, ImportType, PerNsGlobImports},
item_tree::{
- self, ExternCrate, Fields, FileItemTreeId, ImportKind, ItemTree, ItemTreeId, ItemTreeNode,
- Macro2, MacroCall, MacroRules, Mod, ModItem, ModKind, TreeId,
+ self, ExternCrate, Fields, FileItemTreeId, ImportKind, ItemTree, ItemTreeId,
+ ItemTreeModItemNode, Macro2, MacroCall, MacroRules, Mod, ModItem, ModKind, TreeId,
},
macro_call_as_call_id, macro_call_as_call_id_with_eager,
nameres::{
@@ -51,7 +51,7 @@ use crate::{
per_ns::PerNs,
tt,
visibility::{RawVisibility, Visibility},
- AdtId, AstId, AstIdWithPath, ConstLoc, CrateRootModuleId, EnumLoc, EnumVariantId,
+ AdtId, AstId, AstIdWithPath, ConstLoc, CrateRootModuleId, EnumLoc, EnumVariantLoc,
ExternBlockLoc, ExternCrateId, ExternCrateLoc, FunctionId, FunctionLoc, ImplLoc, Intern,
ItemContainerId, LocalModuleId, Lookup, Macro2Id, Macro2Loc, MacroExpander, MacroId,
MacroRulesId, MacroRulesLoc, MacroRulesLocFlags, ModuleDefId, ModuleId, ProcMacroId,
@@ -980,24 +980,26 @@ impl DefCollector<'_> {
cov_mark::hit!(glob_enum);
// glob import from enum => just import all the variants
- // XXX: urgh, so this works by accident! Here, we look at
- // the enum data, and, in theory, this might require us to
- // look back at the crate_def_map, creating a cycle. For
- // example, `enum E { crate::some_macro!(); }`. Luckily, the
- // only kind of macro that is allowed inside enum is a
- // `cfg_macro`, and we don't need to run name resolution for
- // it, but this is sheer luck!
- let enum_data = self.db.enum_data(e);
- let resolutions = enum_data
- .variants
- .iter()
- .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, None);
- (Some(name), res)
- })
- .collect::<Vec<_>>();
+ // We need to check if the def map the enum is from is us, if it is we can't
+ // call the def-map query since we are currently constructing it!
+ let loc = e.lookup(self.db);
+ let tree = loc.id.item_tree(self.db);
+ let current_def_map = self.def_map.krate == loc.container.krate
+ && self.def_map.block_id() == loc.container.block;
+ let def_map;
+ let resolutions = if current_def_map {
+ &self.def_map.enum_definitions[&e]
+ } else {
+ def_map = loc.container.def_map(self.db);
+ &def_map.enum_definitions[&e]
+ }
+ .iter()
+ .map(|&variant| {
+ let name = tree[variant.lookup(self.db).id.value].name.clone();
+ let res = PerNs::both(variant.into(), variant.into(), vis, None);
+ (Some(name), res)
+ })
+ .collect::<Vec<_>>();
self.update(module_id, &resolutions, vis, Some(ImportType::Glob(id)));
}
Some(d) => {
@@ -1404,7 +1406,7 @@ impl DefCollector<'_> {
}
if let errors @ [_, ..] = &*value {
let loc: MacroCallLoc = self.db.lookup_intern_macro_call(macro_call_id);
- let diag = DefDiagnostic::macro_expansion_parse_error(module_id, loc.kind, &errors);
+ let diag = DefDiagnostic::macro_expansion_parse_error(module_id, loc.kind, errors);
self.def_map.diagnostics.push(diag);
}
@@ -1577,7 +1579,10 @@ impl ModCollector<'_, '_> {
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);
+ self.emit_unconfigured_diagnostic(
+ InFile::new(self.file_id(), item.ast_id(self.item_tree).erase()),
+ &cfg,
+ );
return;
}
}
@@ -1708,17 +1713,47 @@ impl ModCollector<'_, '_> {
}
ModItem::Enum(id) => {
let it = &self.item_tree[id];
+ let enum_ =
+ EnumLoc { container: module, id: ItemTreeId::new(self.tree_id, id) }
+ .intern(db);
let vis = resolve_vis(def_map, &self.item_tree[it.visibility]);
- update_def(
- self.def_collector,
- EnumLoc { container: module, id: ItemTreeId::new(self.tree_id, id) }
- .intern(db)
- .into(),
- &it.name,
- vis,
- false,
- );
+ update_def(self.def_collector, enum_.into(), &it.name, vis, false);
+
+ let mut index = 0;
+ let variants = FileItemTreeId::range_iter(it.variants.clone())
+ .filter_map(|variant| {
+ let is_enabled = self
+ .item_tree
+ .attrs(db, krate, variant.into())
+ .cfg()
+ .and_then(|cfg| self.is_cfg_enabled(&cfg).not().then_some(cfg))
+ .map_or(Ok(()), Err);
+ match is_enabled {
+ Err(cfg) => {
+ self.emit_unconfigured_diagnostic(
+ InFile::new(
+ self.file_id(),
+ self.item_tree[variant.index()].ast_id.erase(),
+ ),
+ &cfg,
+ );
+ None
+ }
+ Ok(()) => Some({
+ let loc = EnumVariantLoc {
+ id: ItemTreeId::new(self.tree_id, variant),
+ parent: enum_,
+ index,
+ }
+ .intern(db);
+ index += 1;
+ loc
+ }),
+ }
+ })
+ .collect();
+ self.def_collector.def_map.enum_definitions.insert(enum_, variants);
}
ModItem::Const(id) => {
let it = &self.item_tree[id];
@@ -1905,31 +1940,40 @@ impl ModCollector<'_, '_> {
let is_enabled = item_tree
.top_level_attrs(db, krate)
.cfg()
- .map_or(true, |cfg| self.is_cfg_enabled(&cfg));
- if is_enabled {
- let module_id = self.push_child_module(
- module.name.clone(),
- ast_id.value,
- Some((file_id, is_mod_rs)),
- &self.item_tree[module.visibility],
- module_id,
- );
- ModCollector {
- def_collector: self.def_collector,
- macro_depth: self.macro_depth,
- module_id,
- tree_id: TreeId::new(file_id.into(), None),
- item_tree: &item_tree,
- mod_dir,
+ .and_then(|cfg| self.is_cfg_enabled(&cfg).not().then_some(cfg))
+ .map_or(Ok(()), Err);
+ match is_enabled {
+ Err(cfg) => {
+ self.emit_unconfigured_diagnostic(
+ ast_id.map(|it| it.erase()),
+ &cfg,
+ );
}
- .collect_in_top_module(item_tree.top_level_items());
- let is_macro_use = is_macro_use
- || item_tree
- .top_level_attrs(db, krate)
- .by_key("macro_use")
- .exists();
- if is_macro_use {
- self.import_all_legacy_macros(module_id);
+ Ok(()) => {
+ let module_id = self.push_child_module(
+ module.name.clone(),
+ ast_id.value,
+ Some((file_id, is_mod_rs)),
+ &self.item_tree[module.visibility],
+ module_id,
+ );
+ ModCollector {
+ def_collector: self.def_collector,
+ macro_depth: self.macro_depth,
+ module_id,
+ tree_id: TreeId::new(file_id.into(), None),
+ item_tree: &item_tree,
+ mod_dir,
+ }
+ .collect_in_top_module(item_tree.top_level_items());
+ let is_macro_use = is_macro_use
+ || item_tree
+ .top_level_attrs(db, krate)
+ .by_key("macro_use")
+ .exists();
+ if is_macro_use {
+ self.import_all_legacy_macros(module_id);
+ }
}
}
}
@@ -2243,7 +2287,7 @@ impl ModCollector<'_, '_> {
&MacroCall { ref path, ast_id, expand_to, call_site }: &MacroCall,
container: ItemContainerId,
) {
- let ast_id = AstIdWithPath::new(self.file_id(), ast_id, ModPath::clone(&path));
+ let ast_id = AstIdWithPath::new(self.file_id(), ast_id, ModPath::clone(path));
let db = self.def_collector.db;
// FIXME: Immediately expanding in "Case 1" is insufficient since "Case 2" may also define
@@ -2327,9 +2371,9 @@ impl ModCollector<'_, '_> {
};
for (name, macs) in source.scope.legacy_macros() {
- macs.last().map(|&mac| {
+ if let Some(&mac) = macs.last() {
target.scope.define_legacy_macro(name.clone(), mac);
- });
+ }
}
}
@@ -2360,10 +2404,7 @@ impl ModCollector<'_, '_> {
self.def_collector.cfg_options.check(cfg) != Some(false)
}
- fn emit_unconfigured_diagnostic(&mut self, item: ModItem, cfg: &CfgExpr) {
- let ast_id = item.ast_id(self.item_tree);
-
- let ast_id = InFile::new(self.file_id(), ast_id.erase());
+ fn emit_unconfigured_diagnostic(&mut self, ast_id: InFile<ErasedFileAstId>, cfg: &CfgExpr) {
self.def_collector.def_map.diagnostics.push(DefDiagnostic::unconfigured_code(
self.module_id,
ast_id,