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.rs | 182 |
1 files changed, 96 insertions, 86 deletions
diff --git a/crates/hir_def/src/nameres/collector.rs b/crates/hir_def/src/nameres/collector.rs index 9176c90ae9..a6a90117f2 100644 --- a/crates/hir_def/src/nameres/collector.rs +++ b/crates/hir_def/src/nameres/collector.rs @@ -5,8 +5,9 @@ use std::iter; -use base_db::{CrateId, Edition, FileId, ProcMacroId}; +use base_db::{CrateId, Edition, FileId}; use cfg::{CfgExpr, CfgOptions}; +use either::Either; use hir_expand::{ ast_id_map::FileAstId, builtin_attr_macro::find_builtin_attr, @@ -34,7 +35,7 @@ use crate::{ self, Fields, FileItemTreeId, ImportKind, ItemTree, ItemTreeId, ItemTreeNode, MacroCall, MacroDef, MacroRules, Mod, ModItem, ModKind, TreeId, }, - macro_call_as_call_id, + macro_call_as_call_id, macro_id_to_def_id, nameres::{ diagnostics::DefDiagnostic, mod_resolution::ModDir, @@ -46,8 +47,9 @@ use crate::{ per_ns::PerNs, visibility::{RawVisibility, Visibility}, AdtId, AstId, AstIdWithPath, ConstLoc, EnumLoc, EnumVariantId, ExternBlockLoc, FunctionLoc, - ImplLoc, Intern, ItemContainerId, LocalModuleId, ModuleDefId, StaticLoc, StructLoc, TraitLoc, - TypeAliasLoc, UnionLoc, UnresolvedMacro, + ImplLoc, Intern, ItemContainerId, LocalModuleId, Macro2Id, Macro2Loc, MacroExpander, MacroId, + MacroRulesId, MacroRulesLoc, ModuleDefId, ModuleId, ProcMacroId, ProcMacroLoc, StaticLoc, + StructLoc, TraitLoc, TypeAliasLoc, UnionLoc, UnresolvedMacro, }; static GLOB_RECURSION_LIMIT: Limit = Limit::new(100); @@ -79,7 +81,10 @@ pub(super) fn collect_defs(db: &dyn DefDatabase, mut def_map: DefMap, tree_id: T .map(|(idx, it)| { // FIXME: a hacky way to create a Name from string. let name = tt::Ident { text: it.name.clone(), id: tt::TokenId::unspecified() }; - (name.as_name(), ProcMacroExpander::new(def_map.krate, ProcMacroId(idx as u32))) + ( + name.as_name(), + ProcMacroExpander::new(def_map.krate, base_db::ProcMacroId(idx as u32)), + ) }) .collect(); @@ -543,28 +548,26 @@ impl DefCollector<'_> { /// use a dummy expander that always errors. This comes with the drawback of macros potentially /// going out of sync with what the build system sees (since we resolve using VFS state, but /// Cargo builds only on-disk files). We could and probably should add diagnostics for that. - fn export_proc_macro(&mut self, def: ProcMacroDef, ast_id: AstId<ast::Fn>) { + fn export_proc_macro( + &mut self, + def: ProcMacroDef, + id: ItemTreeId<item_tree::Function>, + module_id: ModuleId, + ) { let kind = def.kind.to_basedb_kind(); self.exports_proc_macros = true; - let macro_def = match self.proc_macros.iter().find(|(n, _)| n == &def.name) { - Some(&(_, expander)) => MacroDefId { - krate: self.def_map.krate, - kind: MacroDefKind::ProcMacro(expander, kind, ast_id), - local_inner: false, - }, - None => MacroDefId { - krate: self.def_map.krate, - kind: MacroDefKind::ProcMacro( - ProcMacroExpander::dummy(self.def_map.krate), - kind, - ast_id, - ), - local_inner: false, - }, + + let (expander, kind) = match self.proc_macros.iter().find(|(n, _)| n == &def.name) { + Some(&(_, expander)) => (expander, kind), + None => (ProcMacroExpander::dummy(self.def_map.krate), kind), }; - self.define_proc_macro(def.name.clone(), macro_def); - self.def_map.exported_proc_macros.insert(macro_def, def); + let proc_macro_id = + ProcMacroLoc { container: module_id, id, expander, kind }.intern(self.db); + self.define_proc_macro(def.name.clone(), proc_macro_id.into()); + self.def_map + .exported_proc_macros + .insert(macro_id_to_def_id(self.db, proc_macro_id.into()), def); } /// Define a macro with `macro_rules`. @@ -596,11 +599,12 @@ impl DefCollector<'_> { &mut self, module_id: LocalModuleId, name: Name, - macro_: MacroDefId, + macro_: MacroRulesId, export: bool, ) { // Textual scoping self.define_legacy_macro(module_id, name.clone(), macro_); + let macro_ = macro_.into(); self.def_map.modules[module_id].scope.declare_macro(macro_); // Module scoping @@ -623,7 +627,7 @@ impl DefCollector<'_> { /// the definition of current module. /// And also, `macro_use` on a module will import all legacy macros visible inside to /// current legacy scope, with possible shadowing. - fn define_legacy_macro(&mut self, module_id: LocalModuleId, name: Name, mac: MacroDefId) { + fn define_legacy_macro(&mut self, module_id: LocalModuleId, name: Name, mac: MacroRulesId) { // Always shadowing self.def_map.modules[module_id].scope.define_legacy_macro(name, mac); } @@ -635,11 +639,12 @@ impl DefCollector<'_> { &mut self, module_id: LocalModuleId, name: Name, - macro_: MacroDefId, + macro_: Macro2Id, vis: &RawVisibility, ) { let vis = self.def_map.resolve_visibility(self.db, module_id, vis).unwrap_or(Visibility::Public); + let macro_ = macro_.into(); self.def_map.modules[module_id].scope.declare_macro(macro_); self.update(module_id, &[(Some(name), PerNs::macros(macro_, vis))], vis, ImportType::Named); } @@ -648,7 +653,8 @@ impl DefCollector<'_> { /// /// A proc macro is similar to normal macro scope, but it would not visible in legacy textual scoped. /// And unconditionally exported. - fn define_proc_macro(&mut self, name: Name, macro_: MacroDefId) { + fn define_proc_macro(&mut self, name: Name, macro_: ProcMacroId) { + let macro_ = macro_.into(); self.def_map.modules[self.def_map.root].scope.declare_macro(macro_); self.update( self.def_map.root, @@ -691,8 +697,10 @@ impl DefCollector<'_> { fn import_all_macros_exported(&mut self, current_module_id: LocalModuleId, krate: CrateId) { let def_map = self.db.crate_def_map(krate); for (name, def) in def_map[def_map.root].scope.macros() { - // `macro_use` only bring things into legacy scope. - self.define_legacy_macro(current_module_id, name.clone(), def); + if let MacroId::MacroRulesId(def) = def { + // `macro_use` only bring things into legacy scope. + self.define_legacy_macro(current_module_id, name.clone(), def); + } } } @@ -1049,7 +1057,7 @@ impl DefCollector<'_> { &path, BuiltinShadowMode::Module, ); - resolved_res.resolved_def.take_macros() + resolved_res.resolved_def.take_macros().map(|it| macro_id_to_def_id(self.db, it)) }; match &directive.kind { @@ -1339,7 +1347,10 @@ impl DefCollector<'_> { &path, BuiltinShadowMode::Module, ); - resolved_res.resolved_def.take_macros() + resolved_res + .resolved_def + .take_macros() + .map(|it| macro_id_to_def_id(self.db, it)) }, &mut |_| (), ); @@ -1525,10 +1536,9 @@ impl ModCollector<'_, '_> { ), ), ModItem::MacroCall(mac) => self.collect_macro_call(&self.item_tree[mac], container), - ModItem::MacroRules(id) => self.collect_macro_rules(id), - ModItem::MacroDef(id) => self.collect_macro_def(id), + ModItem::MacroRules(id) => self.collect_macro_rules(id, module), + ModItem::MacroDef(id) => self.collect_macro_def(id, module), ModItem::Impl(imp) => { - let module = self.def_collector.def_map.module_id(self.module_id); let impl_id = ImplLoc { container: module, id: ItemTreeId::new(self.tree_id, imp) } .intern(db); @@ -1541,9 +1551,13 @@ impl ModCollector<'_, '_> { let vis = match is_proc_macro { Some(proc_macro) => { // FIXME: this should only be done in the root module of `proc-macro` crates, not everywhere - let ast_id = InFile::new(self.tree_id.file_id(), it.ast_id); let module_id = def_map.module_id(def_map.root()); - self.def_collector.export_proc_macro(proc_macro, ast_id); + + self.def_collector.export_proc_macro( + proc_macro, + ItemTreeId::new(self.tree_id, id), + module_id, + ); Visibility::Module(module_id) } None => resolve_vis(def_map, &self.item_tree[it.visibility]), @@ -1845,7 +1859,7 @@ impl ModCollector<'_, '_> { Ok(()) } - fn collect_macro_rules(&mut self, id: FileItemTreeId<MacroRules>) { + fn collect_macro_rules(&mut self, id: FileItemTreeId<MacroRules>, module: ModuleId) { let krate = self.def_collector.def_map.krate; let mac = &self.item_tree[id]; let attrs = self.item_tree.attrs(self.def_collector.db, krate, ModItem::from(id).into()); @@ -1854,7 +1868,7 @@ impl ModCollector<'_, '_> { let export_attr = attrs.by_key("macro_export"); let is_export = export_attr.exists(); - let is_local_inner = if is_export { + let local_inner = if is_export { export_attr.tt_values().flat_map(|it| &it.token_trees).any(|it| match it { tt::TokenTree::Leaf(tt::Leaf::Ident(ident)) => { ident.text.contains("local_inner_macros") @@ -1866,7 +1880,7 @@ impl ModCollector<'_, '_> { }; // Case 1: builtin macros - if attrs.by_key("rustc_builtin_macro").exists() { + let expander = if attrs.by_key("rustc_builtin_macro").exists() { // `#[rustc_builtin_macro = "builtin_name"]` overrides the `macro_rules!` name. let name; let name = match attrs.by_key("rustc_builtin_macro").string_value() { @@ -1892,32 +1906,29 @@ impl ModCollector<'_, '_> { } } }; - let krate = self.def_collector.def_map.krate; - match find_builtin_macro(name, krate, ast_id) { - Some(macro_id) => { - self.def_collector.define_macro_rules( - self.module_id, - mac.name.clone(), - macro_id, - is_export, - ); - return; - } + match find_builtin_macro(name) { + Some(Either::Left(it)) => MacroExpander::BuiltIn(it), + Some(Either::Right(it)) => MacroExpander::BuiltInEager(it), None => { self.def_collector .def_map .diagnostics .push(DefDiagnostic::unimplemented_builtin_macro(self.module_id, ast_id)); + return; } } - } - - // Case 2: normal `macro_rules!` macro - let macro_id = MacroDefId { - krate: self.def_collector.def_map.krate, - kind: MacroDefKind::Declarative(ast_id), - local_inner: is_local_inner, + } else { + // Case 2: normal `macro_rules!` macro + MacroExpander::Declarative }; + + let macro_id = MacroRulesLoc { + container: module, + id: ItemTreeId::new(self.tree_id, id), + local_inner, + expander, + } + .intern(self.def_collector.db); self.def_collector.define_macro_rules( self.module_id, mac.name.clone(), @@ -1926,44 +1937,38 @@ impl ModCollector<'_, '_> { ); } - fn collect_macro_def(&mut self, id: FileItemTreeId<MacroDef>) { + fn collect_macro_def(&mut self, id: FileItemTreeId<MacroDef>, module: ModuleId) { let krate = self.def_collector.def_map.krate; let mac = &self.item_tree[id]; let ast_id = InFile::new(self.file_id(), mac.ast_id.upcast()); // Case 1: builtin macros let attrs = self.item_tree.attrs(self.def_collector.db, krate, ModItem::from(id).into()); - if attrs.by_key("rustc_builtin_macro").exists() { - let macro_id = find_builtin_macro(&mac.name, krate, ast_id) - .or_else(|| find_builtin_derive(&mac.name, krate, ast_id)) - .or_else(|| find_builtin_attr(&mac.name, krate, ast_id)); - - match macro_id { - Some(macro_id) => { - self.def_collector.define_macro_def( - self.module_id, - mac.name.clone(), - macro_id, - &self.item_tree[mac.visibility], - ); - return; - } - None => { - self.def_collector - .def_map - .diagnostics - .push(DefDiagnostic::unimplemented_builtin_macro(self.module_id, ast_id)); + let expander = if attrs.by_key("rustc_builtin_macro").exists() { + if let Some(expander) = find_builtin_macro(&mac.name) { + match expander { + Either::Left(it) => MacroExpander::BuiltIn(it), + Either::Right(it) => MacroExpander::BuiltInEager(it), } + } else if let Some(expander) = find_builtin_derive(&mac.name) { + MacroExpander::BuiltInDerive(expander) + } else if let Some(expander) = find_builtin_attr(&mac.name) { + MacroExpander::BuiltInAttr(expander) + } else { + self.def_collector + .def_map + .diagnostics + .push(DefDiagnostic::unimplemented_builtin_macro(self.module_id, ast_id)); + return; } - } - - // Case 2: normal `macro` - let macro_id = MacroDefId { - krate: self.def_collector.def_map.krate, - kind: MacroDefKind::Declarative(ast_id), - local_inner: false, + } else { + // Case 2: normal `macro` + MacroExpander::Declarative }; + let macro_id = + Macro2Loc { container: module, id: ItemTreeId::new(self.tree_id, id), expander } + .intern(self.def_collector.db); self.def_collector.define_macro_def( self.module_id, mac.name.clone(), @@ -1987,7 +1992,12 @@ impl ModCollector<'_, '_> { self.def_collector.def_map.with_ancestor_maps( self.def_collector.db, self.module_id, - &mut |map, module| map[module].scope.get_legacy_macro(name), + &mut |map, module| { + map[module] + .scope + .get_legacy_macro(name) + .map(|it| macro_id_to_def_id(self.def_collector.db, it.into())) + }, ) }) }, |