From 6955e392f8c1cd49e769328b14e10b84ede26744 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Sat, 16 Mar 2019 19:40:41 +0300 Subject: remove old macro support --- crates/ra_hir/src/db.rs | 7 +- crates/ra_hir/src/ids.rs | 25 ++++-- crates/ra_hir/src/lib.rs | 2 - crates/ra_hir/src/macros.rs | 135 --------------------------------- crates/ra_hir/src/nameres.rs | 29 ++++++- crates/ra_hir/src/nameres/collector.rs | 76 +++++++++++-------- 6 files changed, 91 insertions(+), 183 deletions(-) delete mode 100644 crates/ra_hir/src/macros.rs (limited to 'crates/ra_hir') diff --git a/crates/ra_hir/src/db.rs b/crates/ra_hir/src/db.rs index d2cc19b0f..c7bad7e2b 100644 --- a/crates/ra_hir/src/db.rs +++ b/crates/ra_hir/src/db.rs @@ -4,12 +4,10 @@ use ra_syntax::{SyntaxNode, TreeArc, SourceFile}; use ra_db::{SourceDatabase, salsa, FileId}; use crate::{ - MacroCallId, HirFileId, - SourceFileItems, SourceItemId, Crate, Module, HirInterner, + HirFileId, SourceFileItems, SourceItemId, Crate, Module, HirInterner, Function, FnSignature, ExprScopes, TypeAlias, Struct, Enum, StructField, Const, ConstSignature, Static, - macros::MacroExpansion, nameres::{Namespace, ImportSourceMap, RawItems, CrateDefMap}, ty::{InferenceResult, Ty, method_resolution::CrateImplBlocks, TypableDef, CallableDef, FnSig}, adt::{StructData, EnumData}, @@ -23,9 +21,6 @@ pub trait PersistentHirDatabase: SourceDatabase + AsRef { #[salsa::invoke(HirFileId::hir_parse)] fn hir_parse(&self, file_id: HirFileId) -> TreeArc; - #[salsa::invoke(crate::macros::expand_macro_invocation)] - fn expand_macro_invocation(&self, invoc: MacroCallId) -> Option>; - #[salsa::invoke(crate::adt::StructData::struct_data_query)] fn struct_data(&self, s: Struct) -> Arc; diff --git a/crates/ra_hir/src/ids.rs b/crates/ra_hir/src/ids.rs index a144e4a1e..9596488d3 100644 --- a/crates/ra_hir/src/ids.rs +++ b/crates/ra_hir/src/ids.rs @@ -89,17 +89,31 @@ impl HirFileId { ) -> TreeArc { match file_id.0 { HirFileIdRepr::File(file_id) => db.parse(file_id), - HirFileIdRepr::Macro(m) => { - if let Some(exp) = db.expand_macro_invocation(m) { - return exp.file(); - } + HirFileIdRepr::Macro(macro_call_id) => { // returning an empty string looks fishy... - SourceFile::parse("") + parse_macro(db, macro_call_id).unwrap_or_else(|| SourceFile::parse("")) } } } } +fn parse_macro( + db: &impl PersistentHirDatabase, + macro_call_id: MacroCallId, +) -> Option> { + let loc = macro_call_id.loc(db); + let syntax = db.file_item(loc.source_item_id); + let macro_call = ast::MacroCall::cast(&syntax).unwrap(); + let (macro_arg, _) = macro_call.token_tree().and_then(mbe::ast_to_token_tree)?; + + let def_map = db.crate_def_map(loc.module.krate); + let (krate, macro_id) = def_map.resolve_macro(macro_call_id)?; + let def_map = db.crate_def_map(krate); + let macro_rules = &def_map[macro_id]; + let tt = macro_rules.expand(¯o_arg).ok()?; + Some(mbe::token_tree_to_ast_item_list(&tt)) +} + #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] enum HirFileIdRepr { File(FileId), @@ -373,7 +387,6 @@ impl SourceFileItems { impl std::ops::Index for SourceFileItems { type Output = SyntaxNodePtr; fn index(&self, idx: SourceFileItemId) -> &SyntaxNodePtr { - eprintln!("invalid SourceFileItemId({:?}) for file({:?})", idx, self.file_id); &self.arena[idx] } } diff --git a/crates/ra_hir/src/lib.rs b/crates/ra_hir/src/lib.rs index a188a3cc8..75c977d32 100644 --- a/crates/ra_hir/src/lib.rs +++ b/crates/ra_hir/src/lib.rs @@ -24,7 +24,6 @@ mod path; pub mod source_binder; mod ids; -mod macros; mod name; mod nameres; mod adt; @@ -53,7 +52,6 @@ pub use self::{ path::{Path, PathKind}, name::Name, ids::{HirFileId, MacroCallId, MacroCallLoc, HirInterner}, - macros::{MacroDef, MacroInput, MacroExpansion}, nameres::{PerNs, Namespace}, ty::{Ty, Substs, display::HirDisplay}, impl_block::{ImplBlock, ImplItem}, diff --git a/crates/ra_hir/src/macros.rs b/crates/ra_hir/src/macros.rs deleted file mode 100644 index 45128c7df..000000000 --- a/crates/ra_hir/src/macros.rs +++ /dev/null @@ -1,135 +0,0 @@ -/// Machinery for macro expansion. -/// -/// One of the more complicated things about macros is managing the source code -/// that is produced after expansion. See `HirFileId` and `MacroCallId` for how -/// do we do that. -/// -/// When the file-management question is resolved, all that is left is a -/// token-tree-to-token-tree transformation plus hygiene. We don't have either of -/// those yet, so all macros are string based at the moment! -use std::sync::Arc; - -use ra_syntax::{ - TextRange, TextUnit, SourceFile, AstNode, SyntaxNode, TreeArc, SyntaxNodePtr, - ast, -}; - -use crate::{MacroCallId, PersistentHirDatabase}; - -// Hard-coded defs for now :-( -#[derive(Debug, Clone, PartialEq, Eq)] -pub enum MacroDef { - Vec, -} - -impl MacroDef { - /// Expands macro call, returning the expansion and offset to be used to - /// convert ranges between expansion and original source. - pub fn ast_expand(macro_call: &ast::MacroCall) -> Option<(TextUnit, MacroExpansion)> { - let (def, input) = MacroDef::from_call(macro_call)?; - let exp = def.expand(input)?; - let off = macro_call.token_tree()?.syntax().range().start(); - Some((off, exp)) - } - - fn from_call(macro_call: &ast::MacroCall) -> Option<(MacroDef, MacroInput)> { - let def = { - let path = macro_call.path()?; - let name_ref = path.segment()?.name_ref()?; - if name_ref.text() == "vec" { - MacroDef::Vec - } else { - return None; - } - }; - - let input = { - let arg = macro_call.token_tree()?.syntax(); - MacroInput { text: arg.text().to_string() } - }; - Some((def, input)) - } - - fn expand(self, input: MacroInput) -> Option { - match self { - MacroDef::Vec => self.expand_vec(input), - } - } - fn expand_vec(self, input: MacroInput) -> Option { - let text = format!(r"fn dummy() {{ {}; }}", input.text); - let file = SourceFile::parse(&text); - let array_expr = file.syntax().descendants().find_map(ast::ArrayExpr::cast)?; - let ptr = SyntaxNodePtr::new(array_expr.syntax()); - let src_range = TextRange::offset_len(0.into(), TextUnit::of_str(&input.text)); - let ranges_map = vec![(src_range, array_expr.syntax().range())]; - let res = MacroExpansion { text, ranges_map, ptr }; - Some(res) - } -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct MacroInput { - // Should be token trees - pub text: String, -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct MacroExpansion { - /// The result of macro expansion. Should be token tree as well. - text: String, - /// Correspondence between ranges in the original source code and ranges in - /// the macro. - ranges_map: Vec<(TextRange, TextRange)>, - /// Implementation detail: internally, a macro is expanded to the whole file, - /// even if it is an expression. This `ptr` selects the actual expansion from - /// the expanded file. - ptr: SyntaxNodePtr, -} - -impl MacroExpansion { - // FIXME: does not really make sense, macro expansion is not necessary a - // whole file. See `MacroExpansion::ptr` as well. - pub(crate) fn file(&self) -> TreeArc { - SourceFile::parse(&self.text) - } - - pub fn syntax(&self) -> TreeArc { - self.ptr.to_node(&self.file()).to_owned() - } - /// Maps range in the source code to the range in the expanded code. - pub fn map_range_forward(&self, src_range: TextRange) -> Option { - for (s_range, t_range) in self.ranges_map.iter() { - if src_range.is_subrange(&s_range) { - let src_at_zero_range = src_range - src_range.start(); - let src_range_offset = src_range.start() - s_range.start(); - let src_range = src_at_zero_range + src_range_offset + t_range.start(); - return Some(src_range); - } - } - None - } - /// Maps range in the expanded code to the range in the source code. - pub fn map_range_back(&self, tgt_range: TextRange) -> Option { - for (s_range, t_range) in self.ranges_map.iter() { - if tgt_range.is_subrange(&t_range) { - let tgt_at_zero_range = tgt_range - tgt_range.start(); - let tgt_range_offset = tgt_range.start() - t_range.start(); - let src_range = tgt_at_zero_range + tgt_range_offset + s_range.start(); - return Some(src_range); - } - } - None - } -} - -pub(crate) fn expand_macro_invocation( - db: &impl PersistentHirDatabase, - invoc: MacroCallId, -) -> Option> { - let loc = invoc.loc(db); - let syntax = db.file_item(loc.source_item_id); - let macro_call = ast::MacroCall::cast(&syntax).unwrap(); - - let (def, input) = MacroDef::from_call(macro_call)?; - def.expand(input).map(Arc::new) -} diff --git a/crates/ra_hir/src/nameres.rs b/crates/ra_hir/src/nameres.rs index eabaa5691..17602ee6b 100644 --- a/crates/ra_hir/src/nameres.rs +++ b/crates/ra_hir/src/nameres.rs @@ -57,7 +57,7 @@ use test_utils::tested_by; use crate::{ ModuleDef, Name, Crate, Module, Problem, PersistentHirDatabase, Path, PathKind, HirFileId, - ids::{SourceItemId, SourceFileItemId}, + ids::{SourceItemId, SourceFileItemId, MacroCallId}, }; pub(crate) use self::raw::{RawItems, ImportId, ImportSourceMap}; @@ -76,7 +76,9 @@ pub struct CrateDefMap { extern_prelude: FxHashMap, root: CrateModuleId, modules: Arena, - public_macros: FxHashMap, + macros: Arena, + public_macros: FxHashMap, + macro_resolutions: FxHashMap, problems: CrateDefMapProblems, } @@ -87,9 +89,21 @@ impl std::ops::Index for CrateDefMap { } } +impl std::ops::Index for CrateDefMap { + type Output = mbe::MacroRules; + fn index(&self, id: CrateMacroId) -> &mbe::MacroRules { + &self.macros[id] + } +} + +/// An ID of a macro, **local** to a specific crate +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub(crate) struct CrateMacroId(RawId); +impl_arena_id!(CrateMacroId); + /// An ID of a module, **local** to a specific crate #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] -struct CrateModuleId(RawId); +pub(crate) struct CrateModuleId(RawId); impl_arena_id!(CrateModuleId); #[derive(Default, Debug, PartialEq, Eq)] @@ -192,7 +206,9 @@ impl CrateDefMap { prelude: None, root, modules, + macros: Arena::default(), public_macros: FxHashMap::default(), + macro_resolutions: FxHashMap::default(), problems: CrateDefMapProblems::default(), } }; @@ -221,6 +237,13 @@ impl CrateDefMap { &self.extern_prelude } + pub(crate) fn resolve_macro( + &self, + macro_call_id: MacroCallId, + ) -> Option<(Crate, CrateMacroId)> { + self.macro_resolutions.get(¯o_call_id).map(|&it| it) + } + pub(crate) fn find_module_by_source( &self, file_id: HirFileId, diff --git a/crates/ra_hir/src/nameres/collector.rs b/crates/ra_hir/src/nameres/collector.rs index f2336c271..9992e054d 100644 --- a/crates/ra_hir/src/nameres/collector.rs +++ b/crates/ra_hir/src/nameres/collector.rs @@ -6,13 +6,13 @@ use ra_db::FileId; use crate::{ Function, Module, Struct, Enum, Const, Static, Trait, TypeAlias, - PersistentHirDatabase, HirFileId, Name, Path, Problem, + PersistentHirDatabase, HirFileId, Name, Path, Problem, Crate, KnownName, nameres::{Resolution, PerNs, ModuleDef, ReachedFixedPoint, ResolveMode, raw}, ids::{AstItemDef, LocationCtx, MacroCallLoc, SourceItemId, MacroCallId}, }; -use super::{CrateDefMap, CrateModuleId, ModuleData}; +use super::{CrateDefMap, CrateModuleId, ModuleData, CrateMacroId}; pub(super) fn collect_defs( db: &impl PersistentHirDatabase, @@ -52,7 +52,7 @@ struct DefCollector { glob_imports: FxHashMap>, unresolved_imports: Vec<(CrateModuleId, raw::ImportId, raw::ImportData)>, unexpanded_macros: Vec<(CrateModuleId, MacroCallId, Path, tt::Subtree)>, - global_macro_scope: FxHashMap, + global_macro_scope: FxHashMap, } impl<'a, DB> DefCollector<&'a DB> @@ -95,10 +95,11 @@ where fn define_macro(&mut self, name: Name, tt: &tt::Subtree, export: bool) { if let Ok(rules) = mbe::MacroRules::parse(tt) { + let macro_id = self.def_map.macros.alloc(rules); if export { - self.def_map.public_macros.insert(name.clone(), rules.clone()); + self.def_map.public_macros.insert(name.clone(), macro_id); } - self.global_macro_scope.insert(name, rules); + self.global_macro_scope.insert(name, macro_id); } } @@ -295,6 +296,7 @@ where fn resolve_macros(&mut self) -> ReachedFixedPoint { let mut macros = std::mem::replace(&mut self.unexpanded_macros, Vec::new()); let mut resolved = Vec::new(); + let mut res = ReachedFixedPoint::Yes; macros.retain(|(module_id, call_id, path, tt)| { if path.segments.len() != 2 { return true; @@ -308,19 +310,16 @@ where Some(it) => it, _ => return true, }; + res = ReachedFixedPoint::No; let def_map = self.db.crate_def_map(krate); - let rules = def_map.public_macros.get(&path.segments[1].name).cloned(); - resolved.push((*module_id, *call_id, rules, tt.clone())); + if let Some(macro_id) = def_map.public_macros.get(&path.segments[1].name).cloned() { + resolved.push((*module_id, *call_id, (krate, macro_id), tt.clone())); + } false }); - let res = if resolved.is_empty() { ReachedFixedPoint::Yes } else { ReachedFixedPoint::No }; - for (module_id, macro_call_id, rules, arg) in resolved { - if let Some(rules) = rules { - if let Ok(tt) = rules.expand(&arg) { - self.collect_macro_expansion(module_id, macro_call_id, tt); - } - } + for (module_id, macro_call_id, macro_def_id, arg) in resolved { + self.collect_macro_expansion(module_id, macro_call_id, macro_def_id, arg); } res } @@ -329,20 +328,32 @@ where &mut self, module_id: CrateModuleId, macro_call_id: MacroCallId, - expansion: tt::Subtree, + macro_def_id: (Crate, CrateMacroId), + macro_arg: tt::Subtree, ) { - // XXX: this **does not** go through a database, because we can't - // identify macro_call without adding the whole state of name resolution - // as a parameter to the query. - // - // So, we run the queries "manually" and we must ensure that - // `db.hir_parse(macro_call_id)` returns the same source_file. - let file_id: HirFileId = macro_call_id.into(); - let source_file = mbe::token_tree_to_ast_item_list(&expansion); - - let raw_items = raw::RawItems::from_source_file(&source_file, file_id); - ModCollector { def_collector: &mut *self, file_id, module_id, raw_items: &raw_items } - .collect(raw_items.items()) + let (macro_krate, macro_id) = macro_def_id; + let dm; + let rules = if macro_krate == self.def_map.krate { + &self.def_map[macro_id] + } else { + dm = self.db.crate_def_map(macro_krate); + &dm[macro_id] + }; + if let Ok(expansion) = rules.expand(¯o_arg) { + self.def_map.macro_resolutions.insert(macro_call_id, macro_def_id); + // XXX: this **does not** go through a database, because we can't + // identify macro_call without adding the whole state of name resolution + // as a parameter to the query. + // + // So, we run the queries "manually" and we must ensure that + // `db.hir_parse(macro_call_id)` returns the same source_file. + let file_id: HirFileId = macro_call_id.into(); + let source_file = mbe::token_tree_to_ast_item_list(&expansion); + + let raw_items = raw::RawItems::from_source_file(&source_file, file_id); + ModCollector { def_collector: &mut *self, file_id, module_id, raw_items: &raw_items } + .collect(raw_items.items()) + } } fn finish(self) -> CrateDefMap { @@ -486,12 +497,15 @@ where // Case 2: try to expand macro_rules from this crate, triggering // recursive item collection. - if let Some(rules) = + if let Some(¯o_id) = mac.path.as_ident().and_then(|name| self.def_collector.global_macro_scope.get(name)) { - if let Ok(tt) = rules.expand(&mac.arg) { - self.def_collector.collect_macro_expansion(self.module_id, macro_call_id, tt); - } + self.def_collector.collect_macro_expansion( + self.module_id, + macro_call_id, + (self.def_collector.def_map.krate, macro_id), + mac.arg.clone(), + ); return; } -- cgit v1.2.3