diff --git a/crates/ra_hir_def/src/lib.rs b/crates/ra_hir_def/src/lib.rs index c9b14d0c80..a3d617e1f0 100644 --- a/crates/ra_hir_def/src/lib.rs +++ b/crates/ra_hir_def/src/lib.rs @@ -47,8 +47,8 @@ mod marks; use std::hash::Hash; use hir_expand::{ - ast_id_map::FileAstId, db::AstDatabase, hygiene::Hygiene, AstId, HirFileId, InFile, - MacroCallId, MacroCallKind, MacroDefId, + ast_id_map::FileAstId, db::AstDatabase, eager::expand_eager_macro, hygiene::Hygiene, AstId, + HirFileId, InFile, MacroCallId, MacroCallKind, MacroDefId, MacroDefKind, }; use ra_arena::{impl_arena_id, RawId}; use ra_db::{impl_intern_key, salsa, CrateId}; @@ -459,8 +459,21 @@ impl AsMacroCall for AstIdWithPath { db: &impl AstDatabase, resolver: impl Fn(path::ModPath) -> Option, ) -> Option { - let def = resolver(self.path.clone())?; - Some(def.as_call_id(db, MacroCallKind::FnLike(self.ast_id))) + let def: MacroDefId = resolver(self.path.clone())?; + + if let MacroDefKind::BuiltInEager(_) = def.kind { + let macro_call = InFile::new(self.ast_id.file_id, self.ast_id.to_node(db)); + let hygiene = Hygiene::new(db, self.ast_id.file_id); + + Some( + expand_eager_macro(db, macro_call, def, &|path: ast::Path| { + resolver(path::ModPath::from_src(path, &hygiene)?) + })? + .into(), + ) + } else { + Some(def.as_lazy_macro(db, MacroCallKind::FnLike(self.ast_id)).into()) + } } } @@ -471,6 +484,6 @@ impl AsMacroCall for AstIdWithPath { resolver: impl Fn(path::ModPath) -> Option, ) -> Option { let def = resolver(self.path.clone())?; - Some(def.as_call_id(db, MacroCallKind::Attr(self.ast_id))) + Some(def.as_lazy_macro(db, MacroCallKind::Attr(self.ast_id)).into()) } } diff --git a/crates/ra_hir_expand/src/builtin_derive.rs b/crates/ra_hir_expand/src/builtin_derive.rs index 0b70fb9e1f..87224481ce 100644 --- a/crates/ra_hir_expand/src/builtin_derive.rs +++ b/crates/ra_hir_expand/src/builtin_derive.rs @@ -9,7 +9,7 @@ use ra_syntax::{ }; use crate::db::AstDatabase; -use crate::{name, quote, MacroCallId, MacroDefId, MacroDefKind}; +use crate::{name, quote, LazyMacroId, MacroDefId, MacroDefKind}; macro_rules! register_builtin { ( $($trait:ident => $expand:ident),* ) => { @@ -22,7 +22,7 @@ macro_rules! register_builtin { pub fn expand( &self, db: &dyn AstDatabase, - id: MacroCallId, + id: LazyMacroId, tt: &tt::Subtree, ) -> Result { let expander = match *self { @@ -155,7 +155,7 @@ fn expand_simple_derive( fn copy_expand( _db: &dyn AstDatabase, - _id: MacroCallId, + _id: LazyMacroId, tt: &tt::Subtree, ) -> Result { expand_simple_derive(tt, quote! { std::marker::Copy }) @@ -163,7 +163,7 @@ fn copy_expand( fn clone_expand( _db: &dyn AstDatabase, - _id: MacroCallId, + _id: LazyMacroId, tt: &tt::Subtree, ) -> Result { expand_simple_derive(tt, quote! { std::clone::Clone }) @@ -171,7 +171,7 @@ fn clone_expand( fn default_expand( _db: &dyn AstDatabase, - _id: MacroCallId, + _id: LazyMacroId, tt: &tt::Subtree, ) -> Result { expand_simple_derive(tt, quote! { std::default::Default }) @@ -179,7 +179,7 @@ fn default_expand( fn debug_expand( _db: &dyn AstDatabase, - _id: MacroCallId, + _id: LazyMacroId, tt: &tt::Subtree, ) -> Result { expand_simple_derive(tt, quote! { std::fmt::Debug }) @@ -187,7 +187,7 @@ fn debug_expand( fn hash_expand( _db: &dyn AstDatabase, - _id: MacroCallId, + _id: LazyMacroId, tt: &tt::Subtree, ) -> Result { expand_simple_derive(tt, quote! { std::hash::Hash }) @@ -195,7 +195,7 @@ fn hash_expand( fn eq_expand( _db: &dyn AstDatabase, - _id: MacroCallId, + _id: LazyMacroId, tt: &tt::Subtree, ) -> Result { expand_simple_derive(tt, quote! { std::cmp::Eq }) @@ -203,7 +203,7 @@ fn eq_expand( fn partial_eq_expand( _db: &dyn AstDatabase, - _id: MacroCallId, + _id: LazyMacroId, tt: &tt::Subtree, ) -> Result { expand_simple_derive(tt, quote! { std::cmp::PartialEq }) @@ -211,7 +211,7 @@ fn partial_eq_expand( fn ord_expand( _db: &dyn AstDatabase, - _id: MacroCallId, + _id: LazyMacroId, tt: &tt::Subtree, ) -> Result { expand_simple_derive(tt, quote! { std::cmp::Ord }) @@ -219,7 +219,7 @@ fn ord_expand( fn partial_ord_expand( _db: &dyn AstDatabase, - _id: MacroCallId, + _id: LazyMacroId, tt: &tt::Subtree, ) -> Result { expand_simple_derive(tt, quote! { std::cmp::PartialOrd }) @@ -228,7 +228,7 @@ fn partial_ord_expand( #[cfg(test)] mod tests { use super::*; - use crate::{test_db::TestDB, AstId, MacroCallKind, MacroCallLoc}; + use crate::{test_db::TestDB, AstId, MacroCallId, MacroCallKind, MacroCallLoc}; use ra_db::{fixture::WithFixture, SourceDatabase}; fn expand_builtin_derive(s: &str, expander: BuiltinDeriveExpander) -> String { diff --git a/crates/ra_hir_expand/src/builtin_macro.rs b/crates/ra_hir_expand/src/builtin_macro.rs index d91aa4ffa0..1f380b5716 100644 --- a/crates/ra_hir_expand/src/builtin_macro.rs +++ b/crates/ra_hir_expand/src/builtin_macro.rs @@ -1,24 +1,31 @@ //! Builtin macro use crate::db::AstDatabase; use crate::{ - ast::{self}, - name, AstId, CrateId, MacroCallId, MacroDefId, MacroDefKind, TextUnit, + ast::{self, AstToken, HasStringValue}, + name, AstId, CrateId, MacroDefId, MacroDefKind, TextUnit, }; -use crate::quote; +use crate::{quote, LazyMacroId}; +use either::Either; +use ra_parser::FragmentKind; macro_rules! register_builtin { - ( $(($name:ident, $kind: ident) => $expand:ident),* ) => { + ( LAZY: $(($name:ident, $kind: ident) => $expand:ident),* , EAGER: $(($e_name:ident, $e_kind: ident) => $e_expand:ident),* ) => { #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub enum BuiltinFnLikeExpander { $($kind),* } + #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] + pub enum EagerExpander { + $($e_kind),* + } + impl BuiltinFnLikeExpander { pub fn expand( &self, db: &dyn AstDatabase, - id: MacroCallId, + id: LazyMacroId, tt: &tt::Subtree, ) -> Result { let expander = match *self { @@ -26,28 +33,54 @@ macro_rules! register_builtin { }; expander(db, id, tt) } + } - fn by_name(ident: &name::Name) -> Option { - match ident { - $( id if id == &name::name![$name] => Some(BuiltinFnLikeExpander::$kind), )* - _ => return None, - } + impl EagerExpander { + pub fn expand( + &self, + tt: &tt::Subtree, + ) -> Result<(tt::Subtree, FragmentKind), mbe::ExpandError> { + let expander = match *self { + $( EagerExpander::$e_kind => $e_expand, )* + }; + expander(tt) } } - pub fn find_builtin_macro( - ident: &name::Name, - krate: CrateId, - ast_id: AstId, - ) -> Option { - let kind = BuiltinFnLikeExpander::by_name(ident)?; - - Some(MacroDefId { krate: Some(krate), ast_id: Some(ast_id), kind: MacroDefKind::BuiltIn(kind) }) + fn find_by_name(ident: &name::Name) -> Option> { + match ident { + $( id if id == &name::name![$name] => Some(Either::Left(BuiltinFnLikeExpander::$kind)), )* + $( id if id == &name::name![$e_name] => Some(Either::Right(EagerExpander::$e_kind)), )* + _ => return None, + } } }; } +pub fn find_builtin_macro( + ident: &name::Name, + krate: CrateId, + ast_id: AstId, +) -> Option { + let kind = find_by_name(ident)?; + + match kind { + Either::Left(kind) => Some(MacroDefId { + krate: Some(krate), + ast_id: Some(ast_id), + kind: MacroDefKind::BuiltIn(kind), + }), + Either::Right(kind) => Some(MacroDefId { + krate: Some(krate), + ast_id: Some(ast_id), + kind: MacroDefKind::BuiltInEager(kind), + }), + } +} + register_builtin! { + LAZY: + (column, Column) => column_expand, (compile_error, CompileError) => compile_error_expand, (file, File) => file_expand, @@ -58,12 +91,16 @@ register_builtin! { (option_env, OptionEnv) => option_env_expand, // format_args_nl only differs in that it adds a newline in the end, // so we use the same stub expansion for now - (format_args_nl, FormatArgsNl) => format_args_expand + (format_args_nl, FormatArgsNl) => format_args_expand, + + EAGER: + // eagers + (concat, Concat) => concat_expand } fn line_expand( _db: &dyn AstDatabase, - _id: MacroCallId, + _id: LazyMacroId, _tt: &tt::Subtree, ) -> Result { // dummy implementation for type-checking purposes @@ -77,13 +114,9 @@ fn line_expand( fn stringify_expand( db: &dyn AstDatabase, - id: MacroCallId, + id: LazyMacroId, _tt: &tt::Subtree, ) -> Result { - let id = match id { - MacroCallId::LazyMacro(id) => id, - }; - let loc = db.lookup_intern_macro(id); let macro_content = { @@ -103,7 +136,7 @@ fn stringify_expand( fn env_expand( _db: &dyn AstDatabase, - _id: MacroCallId, + _id: LazyMacroId, _tt: &tt::Subtree, ) -> Result { // dummy implementation for type-checking purposes @@ -114,7 +147,7 @@ fn env_expand( fn option_env_expand( _db: &dyn AstDatabase, - _id: MacroCallId, + _id: LazyMacroId, _tt: &tt::Subtree, ) -> Result { // dummy implementation for type-checking purposes @@ -125,7 +158,7 @@ fn option_env_expand( fn column_expand( _db: &dyn AstDatabase, - _id: MacroCallId, + _id: LazyMacroId, _tt: &tt::Subtree, ) -> Result { // dummy implementation for type-checking purposes @@ -139,7 +172,7 @@ fn column_expand( fn file_expand( _db: &dyn AstDatabase, - _id: MacroCallId, + _id: LazyMacroId, _tt: &tt::Subtree, ) -> Result { // FIXME: RA purposefully lacks knowledge of absolute file names @@ -155,7 +188,7 @@ fn file_expand( fn compile_error_expand( _db: &dyn AstDatabase, - _id: MacroCallId, + _id: LazyMacroId, tt: &tt::Subtree, ) -> Result { if tt.count() == 1 { @@ -172,7 +205,7 @@ fn compile_error_expand( fn format_args_expand( _db: &dyn AstDatabase, - _id: MacroCallId, + _id: LazyMacroId, tt: &tt::Subtree, ) -> Result { // We expand `format_args!("", a1, a2)` to @@ -212,23 +245,44 @@ fn format_args_expand( Ok(expanded) } +fn unquote_str(lit: &tt::Literal) -> Option { + let lit = ast::make::tokens::literal(&lit.to_string()); + let token = ast::String::cast(lit)?; + token.value() +} + +fn concat_expand(tt: &tt::Subtree) -> Result<(tt::Subtree, FragmentKind), mbe::ExpandError> { + let mut text = String::new(); + for (i, t) in tt.token_trees.iter().enumerate() { + match t { + tt::TokenTree::Leaf(tt::Leaf::Literal(it)) if i % 2 == 0 => { + text += &unquote_str(&it).ok_or_else(|| mbe::ExpandError::ConversionError)?; + } + tt::TokenTree::Leaf(tt::Leaf::Punct(punct)) if i % 2 == 1 && punct.char == ',' => (), + _ => return Err(mbe::ExpandError::UnexpectedToken), + } + } + + Ok((quote!(#text), FragmentKind::Expr)) +} + #[cfg(test)] mod tests { use super::*; - use crate::{name::AsName, test_db::TestDB, AstNode, MacroCallKind, MacroCallLoc}; + use crate::{name::AsName, test_db::TestDB, AstNode, MacroCallId, MacroCallKind, MacroCallLoc}; use ra_db::{fixture::WithFixture, SourceDatabase}; use ra_syntax::ast::NameOwner; - fn expand_builtin_macro(s: &str) -> String { - let (db, file_id) = TestDB::with_single_file(&s); + fn expand_builtin_macro(ra_fixture: &str) -> String { + let (db, file_id) = TestDB::with_single_file(&ra_fixture); let parsed = db.parse(file_id); let macro_calls: Vec<_> = parsed.syntax_node().descendants().filter_map(ast::MacroCall::cast).collect(); let ast_id_map = db.ast_id_map(file_id.into()); - let expander = - BuiltinFnLikeExpander::by_name(¯o_calls[0].name().unwrap().as_name()).unwrap(); + let expander = find_by_name(¯o_calls[0].name().unwrap().as_name()).unwrap(); + let expander = expander.left().unwrap(); // the first one should be a macro_rules let def = MacroDefId { diff --git a/crates/ra_hir_expand/src/db.rs b/crates/ra_hir_expand/src/db.rs index b695c5b8d5..ac8256a845 100644 --- a/crates/ra_hir_expand/src/db.rs +++ b/crates/ra_hir_expand/src/db.rs @@ -9,8 +9,9 @@ use ra_prof::profile; use ra_syntax::{AstNode, Parse, SyntaxKind::*, SyntaxNode}; use crate::{ - ast_id_map::AstIdMap, BuiltinDeriveExpander, BuiltinFnLikeExpander, HirFileId, HirFileIdRepr, - LazyMacroId, MacroCallId, MacroCallLoc, MacroDefId, MacroDefKind, MacroFile, + ast_id_map::AstIdMap, BuiltinDeriveExpander, BuiltinFnLikeExpander, EagerCallLoc, EagerMacroId, + HirFileId, HirFileIdRepr, LazyMacroId, MacroCallId, MacroCallLoc, MacroDefId, MacroDefKind, + MacroFile, }; #[derive(Debug, Clone, Eq, PartialEq)] @@ -24,7 +25,7 @@ impl TokenExpander { pub fn expand( &self, db: &dyn AstDatabase, - id: MacroCallId, + id: LazyMacroId, tt: &tt::Subtree, ) -> Result { match self { @@ -66,6 +67,9 @@ pub trait AstDatabase: SourceDatabase { fn parse_macro(&self, macro_file: MacroFile) -> Option<(Parse, Arc)>; fn macro_expand(&self, macro_call: MacroCallId) -> Result, String>; + + #[salsa::interned] + fn intern_eager_expansion(&self, eager: EagerCallLoc) -> EagerMacroId; } pub(crate) fn ast_id_map(db: &dyn AstDatabase, file_id: HirFileId) -> Arc { @@ -101,6 +105,7 @@ pub(crate) fn macro_def( MacroDefKind::BuiltInDerive(expander) => { Some(Arc::new((TokenExpander::BuiltinDerive(expander), mbe::TokenMap::default()))) } + MacroDefKind::BuiltInEager(_expander) => None, } } @@ -110,6 +115,10 @@ pub(crate) fn macro_arg( ) -> Option> { let id = match id { MacroCallId::LazyMacro(id) => id, + MacroCallId::EagerMacro(_id) => { + // FIXME: support macro_arg for eager macro + return None; + } }; let loc = db.lookup_intern_macro(id); let arg = loc.kind.arg(db)?; @@ -123,13 +132,16 @@ pub(crate) fn macro_expand( ) -> Result, String> { let lazy_id = match id { MacroCallId::LazyMacro(id) => id, + MacroCallId::EagerMacro(id) => { + return Ok(db.lookup_intern_eager_expansion(id).subtree); + } }; let loc = db.lookup_intern_macro(lazy_id); let macro_arg = db.macro_arg(id).ok_or("Fail to args in to tt::TokenTree")?; let macro_rules = db.macro_def(loc.def).ok_or("Fail to find macro definition")?; - let tt = macro_rules.0.expand(db, id, ¯o_arg.0).map_err(|err| format!("{:?}", err))?; + let tt = macro_rules.0.expand(db, lazy_id, ¯o_arg.0).map_err(|err| format!("{:?}", err))?; // Set a hard limit for the expanded tt let count = tt.count(); if count > 65536 { @@ -177,6 +189,9 @@ pub(crate) fn parse_macro( fn to_fragment_kind(db: &dyn AstDatabase, id: MacroCallId) -> FragmentKind { let lazy_id = match id { MacroCallId::LazyMacro(id) => id, + MacroCallId::EagerMacro(id) => { + return db.lookup_intern_eager_expansion(id).fragment; + } }; let syn = db.lookup_intern_macro(lazy_id).kind.node(db).value; diff --git a/crates/ra_hir_expand/src/eager.rs b/crates/ra_hir_expand/src/eager.rs new file mode 100644 index 0000000000..8caf8497e8 --- /dev/null +++ b/crates/ra_hir_expand/src/eager.rs @@ -0,0 +1,93 @@ +//! Eager expansion related utils + +use crate::{ + ast::{self, AstNode}, + db::AstDatabase, + EagerCallLoc, EagerMacroId, InFile, MacroCallId, MacroCallKind, MacroDefId, MacroDefKind, +}; + +use ra_parser::FragmentKind; +use ra_syntax::{algo::replace_descendants, SyntaxElement, SyntaxNode}; +use std::{collections::HashMap, sync::Arc}; + +fn to_subtree(node: &SyntaxNode) -> Option { + let mut subtree = mbe::syntax_node_to_token_tree(node)?.0; + subtree.delimiter = None; + Some(subtree) +} + +fn lazy_expand( + db: &impl AstDatabase, + def: &MacroDefId, + macro_call: InFile, +) -> Option> { + let ast_id = db.ast_id_map(macro_call.file_id).ast_id(¯o_call.value); + + let id: MacroCallId = + def.as_lazy_macro(db, MacroCallKind::FnLike(macro_call.with_value(ast_id))).into(); + + db.parse_or_expand(id.as_file()).map(|node| InFile::new(id.as_file(), node)) +} + +fn eager_macro_recur( + db: &impl AstDatabase, + curr: InFile, + macro_resolver: &dyn Fn(ast::Path) -> Option, +) -> Option { + let mut original = curr.value.clone(); + + let children = curr.value.descendants().filter_map(ast::MacroCall::cast); + let mut replaces: HashMap = HashMap::default(); + + // Collect replacement + for child in children { + let def: MacroDefId = macro_resolver(child.path()?)?; + let insert = match def.kind { + MacroDefKind::BuiltInEager(_) => { + let id: MacroCallId = + expand_eager_macro(db, curr.with_value(child.clone()), def, macro_resolver)? + .into(); + db.parse_or_expand(id.as_file())? + } + MacroDefKind::Declarative + | MacroDefKind::BuiltIn(_) + | MacroDefKind::BuiltInDerive(_) => { + let expanded = lazy_expand(db, &def, curr.with_value(child.clone()))?; + // replace macro inside + eager_macro_recur(db, expanded, macro_resolver)? + } + }; + + replaces.insert(child.syntax().clone().into(), insert.into()); + } + + if !replaces.is_empty() { + original = replace_descendants(&original, |n| replaces.get(n).cloned()); + } + + Some(original) +} + +pub fn expand_eager_macro( + db: &impl AstDatabase, + macro_call: InFile, + def: MacroDefId, + resolver: &dyn Fn(ast::Path) -> Option, +) -> Option { + let args = macro_call.value.token_tree()?; + let parsed_args = mbe::ast_to_token_tree(&args)?.0; + let parsed_args = mbe::token_tree_to_syntax_node(&parsed_args, FragmentKind::Expr).ok()?.0; + let result = eager_macro_recur(db, macro_call.with_value(parsed_args.syntax_node()), resolver)?; + + let subtree = to_subtree(&result)?; + + if let MacroDefKind::BuiltInEager(eager) = def.kind { + let (subtree, fragment) = eager.expand(&subtree).ok()?; + let eager = + EagerCallLoc { def, fragment, subtree: Arc::new(subtree), file_id: macro_call.file_id }; + + Some(db.intern_eager_expansion(eager)) + } else { + None + } +} diff --git a/crates/ra_hir_expand/src/hygiene.rs b/crates/ra_hir_expand/src/hygiene.rs index ed0e7aa782..cb554ae4be 100644 --- a/crates/ra_hir_expand/src/hygiene.rs +++ b/crates/ra_hir_expand/src/hygiene.rs @@ -9,7 +9,7 @@ use ra_syntax::ast; use crate::{ db::AstDatabase, name::{AsName, Name}, - HirFileId, HirFileIdRepr, MacroDefKind, + HirFileId, HirFileIdRepr, MacroCallId, MacroDefKind, }; #[derive(Debug)] @@ -22,17 +22,18 @@ impl Hygiene { pub fn new(db: &impl AstDatabase, file_id: HirFileId) -> Hygiene { let def_crate = match file_id.0 { HirFileIdRepr::FileId(_) => None, - HirFileIdRepr::MacroFile(macro_file) => { - let lazy_id = match macro_file.macro_call_id { - crate::MacroCallId::LazyMacro(id) => id, - }; - let loc = db.lookup_intern_macro(lazy_id); - match loc.def.kind { - MacroDefKind::Declarative => loc.def.krate, - MacroDefKind::BuiltIn(_) => None, - MacroDefKind::BuiltInDerive(_) => None, + HirFileIdRepr::MacroFile(macro_file) => match macro_file.macro_call_id { + MacroCallId::LazyMacro(id) => { + let loc = db.lookup_intern_macro(id); + match loc.def.kind { + MacroDefKind::Declarative => loc.def.krate, + MacroDefKind::BuiltIn(_) => None, + MacroDefKind::BuiltInDerive(_) => None, + MacroDefKind::BuiltInEager(_) => None, + } } - } + MacroCallId::EagerMacro(_id) => None, + }, }; Hygiene { def_crate } } diff --git a/crates/ra_hir_expand/src/lib.rs b/crates/ra_hir_expand/src/lib.rs index 3a1c6d2b0b..3fce73e8ad 100644 --- a/crates/ra_hir_expand/src/lib.rs +++ b/crates/ra_hir_expand/src/lib.rs @@ -12,6 +12,7 @@ pub mod diagnostics; pub mod builtin_derive; pub mod builtin_macro; pub mod quote; +pub mod eager; use std::hash::Hash; use std::sync::Arc; @@ -25,7 +26,7 @@ use ra_syntax::{ use crate::ast_id_map::FileAstId; use crate::builtin_derive::BuiltinDeriveExpander; -use crate::builtin_macro::BuiltinFnLikeExpander; +use crate::builtin_macro::{BuiltinFnLikeExpander, EagerExpander}; #[cfg(test)] mod test_db; @@ -70,11 +71,17 @@ impl HirFileId { match self.0 { HirFileIdRepr::FileId(file_id) => file_id, HirFileIdRepr::MacroFile(macro_file) => { - let lazy_id = match macro_file.macro_call_id { - MacroCallId::LazyMacro(id) => id, + let file_id = match macro_file.macro_call_id { + MacroCallId::LazyMacro(id) => { + let loc = db.lookup_intern_macro(id); + loc.kind.file_id() + } + MacroCallId::EagerMacro(id) => { + let loc = db.lookup_intern_eager_expansion(id); + loc.file_id + } }; - let loc = db.lookup_intern_macro(lazy_id); - loc.kind.file_id().original_file(db) + file_id.original_file(db) } } } @@ -86,6 +93,10 @@ impl HirFileId { HirFileIdRepr::MacroFile(macro_file) => { let lazy_id = match macro_file.macro_call_id { MacroCallId::LazyMacro(id) => id, + MacroCallId::EagerMacro(_id) => { + // FIXME: handle call node for eager macro + return None; + } }; let loc = db.lookup_intern_macro(lazy_id); Some(loc.kind.node(db)) @@ -100,6 +111,10 @@ impl HirFileId { HirFileIdRepr::MacroFile(macro_file) => { let lazy_id = match macro_file.macro_call_id { MacroCallId::LazyMacro(id) => id, + MacroCallId::EagerMacro(_id) => { + // FIXME: handle expansion_info for eager macro + return None; + } }; let loc: MacroCallLoc = db.lookup_intern_macro(lazy_id); @@ -129,6 +144,9 @@ impl HirFileId { HirFileIdRepr::MacroFile(macro_file) => { let lazy_id = match macro_file.macro_call_id { MacroCallId::LazyMacro(id) => id, + MacroCallId::EagerMacro(_id) => { + return None; + } }; let loc: MacroCallLoc = db.lookup_intern_macro(lazy_id); let item = match loc.def.kind { @@ -151,6 +169,7 @@ pub struct MacroFile { #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub enum MacroCallId { LazyMacro(LazyMacroId), + EagerMacro(EagerMacroId), } #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] @@ -164,11 +183,27 @@ impl salsa::InternKey for LazyMacroId { } } +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub struct EagerMacroId(salsa::InternId); +impl salsa::InternKey for EagerMacroId { + fn from_intern_id(v: salsa::InternId) -> Self { + EagerMacroId(v) + } + fn as_intern_id(&self) -> salsa::InternId { + self.0 + } +} + impl From for MacroCallId { fn from(it: LazyMacroId) -> Self { MacroCallId::LazyMacro(it) } } +impl From for MacroCallId { + fn from(it: EagerMacroId) -> Self { + MacroCallId::EagerMacro(it) + } +} #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct MacroDefId { @@ -184,8 +219,8 @@ pub struct MacroDefId { } impl MacroDefId { - pub fn as_call_id(self, db: &dyn db::AstDatabase, kind: MacroCallKind) -> MacroCallId { - db.intern_macro(MacroCallLoc { def: self, kind }).into() + pub fn as_lazy_macro(self, db: &dyn db::AstDatabase, kind: MacroCallKind) -> LazyMacroId { + db.intern_macro(MacroCallLoc { def: self, kind }) } } @@ -195,6 +230,7 @@ pub enum MacroDefKind { BuiltIn(BuiltinFnLikeExpander), // FIXME: maybe just Builtin and rename BuiltinFnLikeExpander to BuiltinExpander BuiltInDerive(BuiltinDeriveExpander), + BuiltInEager(EagerExpander), } #[derive(Debug, Clone, PartialEq, Eq, Hash)] @@ -240,6 +276,14 @@ impl MacroCallId { } } +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct EagerCallLoc { + pub(crate) def: MacroDefId, + pub(crate) fragment: FragmentKind, + pub(crate) subtree: Arc, + pub(crate) file_id: HirFileId, +} + /// ExpansionInfo mainly describes how to map text range between src and expanded macro #[derive(Debug, Clone, PartialEq, Eq)] pub struct ExpansionInfo { @@ -253,6 +297,7 @@ pub struct ExpansionInfo { } pub use mbe::Origin; +use ra_parser::FragmentKind; impl ExpansionInfo { pub fn call_node(&self) -> Option> { diff --git a/crates/ra_hir_expand/src/name.rs b/crates/ra_hir_expand/src/name.rs index b2e10f445f..036cf7d1e0 100644 --- a/crates/ra_hir_expand/src/name.rs +++ b/crates/ra_hir_expand/src/name.rs @@ -173,6 +173,7 @@ pub mod known { compile_error, line, stringify, + concat, format_args, format_args_nl, env, diff --git a/crates/ra_parser/src/lib.rs b/crates/ra_parser/src/lib.rs index 81055746b5..652492c1ed 100644 --- a/crates/ra_parser/src/lib.rs +++ b/crates/ra_parser/src/lib.rs @@ -83,7 +83,7 @@ pub fn parse(token_source: &mut dyn TokenSource, tree_sink: &mut dyn TreeSink) { parse_from_tokens(token_source, tree_sink, grammar::root); } -#[derive(Clone, Copy)] +#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)] pub enum FragmentKind { Path, Expr, diff --git a/crates/ra_syntax/src/ast/make.rs b/crates/ra_syntax/src/ast/make.rs index 3f11b747f0..0da24560ea 100644 --- a/crates/ra_syntax/src/ast/make.rs +++ b/crates/ra_syntax/src/ast/make.rs @@ -219,7 +219,7 @@ fn unroot(n: SyntaxNode) -> SyntaxNode { } pub mod tokens { - use crate::{AstNode, Parse, SourceFile, SyntaxKind::*, SyntaxToken, T}; + use crate::{ast, AstNode, Parse, SourceFile, SyntaxKind::*, SyntaxToken, T}; use once_cell::sync::Lazy; pub(super) static SOURCE_FILE: Lazy> = @@ -251,6 +251,12 @@ pub mod tokens { sf.syntax().first_child_or_token().unwrap().into_token().unwrap() } + pub fn literal(text: &str) -> SyntaxToken { + assert_eq!(text.trim(), text); + let lit: ast::Literal = super::ast_from_text(&format!("fn f() {{ let _ = {}; }}", text)); + lit.syntax().first_child_or_token().unwrap().into_token().unwrap() + } + pub fn single_newline() -> SyntaxToken { SOURCE_FILE .tree()