Don't guess macro expansion crate

This commit is contained in:
Aleksey Kladov 2020-06-11 12:08:24 +02:00
parent d8a5d39c2d
commit fac7b0e252
9 changed files with 89 additions and 62 deletions

View file

@ -122,8 +122,9 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> {
let macro_call = let macro_call =
self.find_file(actual_macro_call.syntax().clone()).with_value(actual_macro_call); self.find_file(actual_macro_call.syntax().clone()).with_value(actual_macro_call);
let sa = self.analyze2(macro_call.map(|it| it.syntax()), None); let sa = self.analyze2(macro_call.map(|it| it.syntax()), None);
let krate = sa.resolver.krate()?;
let macro_call_id = macro_call let macro_call_id = macro_call
.as_call_id(self.db, |path| sa.resolver.resolve_path_as_macro(self.db, &path))?; .as_call_id(self.db, krate, |path| sa.resolver.resolve_path_as_macro(self.db, &path))?;
hir_expand::db::expand_hypothetical(self.db, macro_call_id, hypothetical_args, token_to_map) hir_expand::db::expand_hypothetical(self.db, macro_call_id, hypothetical_args, token_to_map)
} }

View file

@ -307,7 +307,8 @@ impl SourceAnalyzer {
db: &dyn HirDatabase, db: &dyn HirDatabase,
macro_call: InFile<&ast::MacroCall>, macro_call: InFile<&ast::MacroCall>,
) -> Option<HirFileId> { ) -> Option<HirFileId> {
let macro_call_id = macro_call.as_call_id(db.upcast(), |path| { let krate = self.resolver.krate()?;
let macro_call_id = macro_call.as_call_id(db.upcast(), krate, |path| {
self.resolver.resolve_path_as_macro(db.upcast(), &path) self.resolver.resolve_path_as_macro(db.upcast(), &path)
})?; })?;
Some(macro_call_id.as_file()) Some(macro_call_id.as_file())

View file

@ -97,7 +97,7 @@ impl Expander {
let macro_call = InFile::new(self.current_file_id, &macro_call); let macro_call = InFile::new(self.current_file_id, &macro_call);
if let Some(call_id) = macro_call.as_call_id(db, |path| { if let Some(call_id) = macro_call.as_call_id(db, self.crate_def_map.krate, |path| {
if let Some(local_scope) = local_scope { if let Some(local_scope) = local_scope {
if let Some(def) = path.as_ident().and_then(|n| local_scope.get_legacy_macro(n)) { if let Some(def) = path.as_ident().and_then(|n| local_scope.get_legacy_macro(n)) {
return Some(def); return Some(def);

View file

@ -417,6 +417,7 @@ pub trait AsMacroCall {
fn as_call_id( fn as_call_id(
&self, &self,
db: &dyn db::DefDatabase, db: &dyn db::DefDatabase,
krate: CrateId,
resolver: impl Fn(path::ModPath) -> Option<MacroDefId>, resolver: impl Fn(path::ModPath) -> Option<MacroDefId>,
) -> Option<MacroCallId>; ) -> Option<MacroCallId>;
} }
@ -425,13 +426,14 @@ impl AsMacroCall for InFile<&ast::MacroCall> {
fn as_call_id( fn as_call_id(
&self, &self,
db: &dyn db::DefDatabase, db: &dyn db::DefDatabase,
krate: CrateId,
resolver: impl Fn(path::ModPath) -> Option<MacroDefId>, resolver: impl Fn(path::ModPath) -> Option<MacroDefId>,
) -> Option<MacroCallId> { ) -> Option<MacroCallId> {
let ast_id = AstId::new(self.file_id, db.ast_id_map(self.file_id).ast_id(self.value)); let ast_id = AstId::new(self.file_id, db.ast_id_map(self.file_id).ast_id(self.value));
let h = Hygiene::new(db.upcast(), self.file_id); let h = Hygiene::new(db.upcast(), self.file_id);
let path = path::ModPath::from_src(self.value.path()?, &h)?; let path = path::ModPath::from_src(self.value.path()?, &h)?;
AstIdWithPath::new(ast_id.file_id, ast_id.value, path).as_call_id(db, resolver) AstIdWithPath::new(ast_id.file_id, ast_id.value, path).as_call_id(db, krate, resolver)
} }
} }
@ -452,6 +454,7 @@ impl AsMacroCall for AstIdWithPath<ast::MacroCall> {
fn as_call_id( fn as_call_id(
&self, &self,
db: &dyn db::DefDatabase, db: &dyn db::DefDatabase,
krate: CrateId,
resolver: impl Fn(path::ModPath) -> Option<MacroDefId>, resolver: impl Fn(path::ModPath) -> Option<MacroDefId>,
) -> Option<MacroCallId> { ) -> Option<MacroCallId> {
let def: MacroDefId = resolver(self.path.clone())?; let def: MacroDefId = resolver(self.path.clone())?;
@ -461,13 +464,13 @@ impl AsMacroCall for AstIdWithPath<ast::MacroCall> {
let hygiene = Hygiene::new(db.upcast(), self.ast_id.file_id); let hygiene = Hygiene::new(db.upcast(), self.ast_id.file_id);
Some( Some(
expand_eager_macro(db.upcast(), macro_call, def, &|path: ast::Path| { expand_eager_macro(db.upcast(), krate, macro_call, def, &|path: ast::Path| {
resolver(path::ModPath::from_src(path, &hygiene)?) resolver(path::ModPath::from_src(path, &hygiene)?)
})? })?
.into(), .into(),
) )
} else { } else {
Some(def.as_lazy_macro(db.upcast(), MacroCallKind::FnLike(self.ast_id)).into()) Some(def.as_lazy_macro(db.upcast(), krate, MacroCallKind::FnLike(self.ast_id)).into())
} }
} }
} }
@ -476,12 +479,14 @@ impl AsMacroCall for AstIdWithPath<ast::ModuleItem> {
fn as_call_id( fn as_call_id(
&self, &self,
db: &dyn db::DefDatabase, db: &dyn db::DefDatabase,
krate: CrateId,
resolver: impl Fn(path::ModPath) -> Option<MacroDefId>, resolver: impl Fn(path::ModPath) -> Option<MacroDefId>,
) -> Option<MacroCallId> { ) -> Option<MacroCallId> {
let def = resolver(self.path.clone())?; let def = resolver(self.path.clone())?;
Some( Some(
def.as_lazy_macro( def.as_lazy_macro(
db.upcast(), db.upcast(),
krate,
MacroCallKind::Attr(self.ast_id, self.path.segments.last()?.to_string()), MacroCallKind::Attr(self.ast_id, self.path.segments.last()?.to_string()),
) )
.into(), .into(),

View file

@ -571,7 +571,8 @@ impl DefCollector<'_> {
return false; return false;
} }
if let Some(call_id) = directive.ast_id.as_call_id(self.db, |path| { if let Some(call_id) =
directive.ast_id.as_call_id(self.db, self.def_map.krate, |path| {
let resolved_res = self.def_map.resolve_path_fp_with_macro( let resolved_res = self.def_map.resolve_path_fp_with_macro(
self.db, self.db,
ResolveMode::Other, ResolveMode::Other,
@ -580,7 +581,8 @@ impl DefCollector<'_> {
BuiltinShadowMode::Module, BuiltinShadowMode::Module,
); );
resolved_res.resolved_def.take_macros() resolved_res.resolved_def.take_macros()
}) { })
{
resolved.push((directive.module_id, call_id, directive.depth)); resolved.push((directive.module_id, call_id, directive.depth));
res = ReachedFixedPoint::No; res = ReachedFixedPoint::No;
return false; return false;
@ -589,9 +591,10 @@ impl DefCollector<'_> {
true true
}); });
attribute_macros.retain(|directive| { attribute_macros.retain(|directive| {
if let Some(call_id) = directive if let Some(call_id) =
.ast_id directive.ast_id.as_call_id(self.db, self.def_map.krate, |path| {
.as_call_id(self.db, |path| self.resolve_attribute_macro(&directive, &path)) self.resolve_attribute_macro(&directive, &path)
})
{ {
resolved.push((directive.module_id, call_id, 0)); resolved.push((directive.module_id, call_id, 0));
res = ReachedFixedPoint::No; res = ReachedFixedPoint::No;
@ -957,11 +960,13 @@ impl ModCollector<'_, '_> {
} }
// Case 2: try to resolve in legacy scope and expand macro_rules // Case 2: try to resolve in legacy scope and expand macro_rules
if let Some(macro_call_id) = ast_id.as_call_id(self.def_collector.db, |path| { if let Some(macro_call_id) =
ast_id.as_call_id(self.def_collector.db, self.def_collector.def_map.krate, |path| {
path.as_ident().and_then(|name| { path.as_ident().and_then(|name| {
self.def_collector.def_map[self.module_id].scope.get_legacy_macro(&name) self.def_collector.def_map[self.module_id].scope.get_legacy_macro(&name)
}) })
}) { })
{
self.def_collector.unexpanded_macros.push(MacroDirective { self.def_collector.unexpanded_macros.push(MacroDirective {
module_id: self.module_id, module_id: self.module_id,
ast_id, ast_id,

View file

@ -8,8 +8,7 @@ use ra_syntax::{
match_ast, match_ast,
}; };
use crate::db::AstDatabase; use crate::{db::AstDatabase, name, quote, LazyMacroId, MacroDefId, MacroDefKind};
use crate::{guess_crate, name, quote, LazyMacroId, MacroCallId, MacroDefId, MacroDefKind};
macro_rules! register_builtin { macro_rules! register_builtin {
( $($trait:ident => $expand:ident),* ) => { ( $($trait:ident => $expand:ident),* ) => {
@ -156,17 +155,8 @@ fn expand_simple_derive(
fn find_builtin_crate(db: &dyn AstDatabase, id: LazyMacroId) -> tt::TokenTree { fn find_builtin_crate(db: &dyn AstDatabase, id: LazyMacroId) -> tt::TokenTree {
// FIXME: make hygiene works for builtin derive macro // FIXME: make hygiene works for builtin derive macro
// such that $crate can be used here. // such that $crate can be used here.
let m: MacroCallId = id.into();
let file_id = m.as_file().original_file(db);
let cg = db.crate_graph(); let cg = db.crate_graph();
let krate = match guess_crate(db, file_id) { let krate = db.lookup_intern_macro(id).krate;
Some(krate) => krate,
None => {
let tt = quote! { core };
return tt.token_trees[0].clone();
}
};
// XXX // XXX
// All crates except core itself should have a dependency on core, // All crates except core itself should have a dependency on core,
@ -263,10 +253,12 @@ fn partial_ord_expand(
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*;
use crate::{test_db::TestDB, AstId, MacroCallId, MacroCallKind, MacroCallLoc};
use name::{known, Name}; use name::{known, Name};
use ra_db::{fixture::WithFixture, SourceDatabase}; use ra_db::{fixture::WithFixture, CrateId, SourceDatabase};
use crate::{test_db::TestDB, AstId, MacroCallId, MacroCallKind, MacroCallLoc};
use super::*;
fn expand_builtin_derive(s: &str, name: Name) -> String { fn expand_builtin_derive(s: &str, name: Name) -> String {
let def = find_builtin_derive(&name).unwrap(); let def = find_builtin_derive(&name).unwrap();
@ -290,7 +282,11 @@ mod tests {
let attr_id = AstId::new(file_id.into(), ast_id_map.ast_id(&items[0])); let attr_id = AstId::new(file_id.into(), ast_id_map.ast_id(&items[0]));
let loc = MacroCallLoc { def, kind: MacroCallKind::Attr(attr_id, name.to_string()) }; let loc = MacroCallLoc {
def,
krate: CrateId(0),
kind: MacroCallKind::Attr(attr_id, name.to_string()),
};
let id: MacroCallId = db.intern_macro(loc).into(); let id: MacroCallId = db.intern_macro(loc).into();
let parsed = db.parse_or_expand(id.as_file()).unwrap(); let parsed = db.parse_or_expand(id.as_file()).unwrap();

View file

@ -1,15 +1,14 @@
//! Builtin macro //! Builtin macro
use crate::db::AstDatabase;
use crate::{ use crate::{
ast::{self, AstToken, HasStringValue}, db::AstDatabase, name, quote, AstId, CrateId, EagerMacroId, LazyMacroId, MacroCallId,
name, AstId, CrateId, MacroDefId, MacroDefKind, TextSize, MacroDefId, MacroDefKind, TextSize,
}; };
use crate::{guess_crate, quote, EagerMacroId, LazyMacroId, MacroCallId};
use either::Either; use either::Either;
use mbe::parse_to_token_tree; use mbe::parse_to_token_tree;
use ra_db::FileId; use ra_db::FileId;
use ra_parser::FragmentKind; use ra_parser::FragmentKind;
use ra_syntax::ast::{self, AstToken, HasStringValue};
macro_rules! register_builtin { macro_rules! register_builtin {
( LAZY: $(($name:ident, $kind: ident) => $expand:ident),* , EAGER: $(($e_name:ident, $e_kind: ident) => $e_expand:ident),* ) => { ( LAZY: $(($name:ident, $kind: ident) => $expand:ident),* , EAGER: $(($e_name:ident, $e_kind: ident) => $e_expand:ident),* ) => {
@ -333,9 +332,7 @@ fn include_expand(
} }
fn get_env_inner(db: &dyn AstDatabase, arg_id: EagerMacroId, key: &str) -> Option<String> { fn get_env_inner(db: &dyn AstDatabase, arg_id: EagerMacroId, key: &str) -> Option<String> {
let call_id: MacroCallId = arg_id.into(); let krate = db.lookup_intern_eager_expansion(arg_id).krate;
let original_file = call_id.as_file().original_file(db);
let krate = guess_crate(db, original_file)?;
db.crate_graph()[krate].env.get(key) db.crate_graph()[krate].env.get(key)
} }
@ -394,6 +391,7 @@ mod tests {
let expander = find_by_name(&macro_calls[0].name().unwrap().as_name()).unwrap(); let expander = find_by_name(&macro_calls[0].name().unwrap().as_name()).unwrap();
let krate = CrateId(0);
let file_id = match expander { let file_id = match expander {
Either::Left(expander) => { Either::Left(expander) => {
// the first one should be a macro_rules // the first one should be a macro_rules
@ -406,6 +404,7 @@ mod tests {
let loc = MacroCallLoc { let loc = MacroCallLoc {
def, def,
krate,
kind: MacroCallKind::FnLike(AstId::new( kind: MacroCallKind::FnLike(AstId::new(
file_id.into(), file_id.into(),
ast_id_map.ast_id(&macro_calls[1]), ast_id_map.ast_id(&macro_calls[1]),
@ -418,7 +417,7 @@ mod tests {
Either::Right(expander) => { Either::Right(expander) => {
// the first one should be a macro_rules // the first one should be a macro_rules
let def = MacroDefId { let def = MacroDefId {
krate: Some(CrateId(0)), krate: Some(krate),
ast_id: Some(AstId::new(file_id.into(), ast_id_map.ast_id(&macro_calls[0]))), ast_id: Some(AstId::new(file_id.into(), ast_id_map.ast_id(&macro_calls[0]))),
kind: MacroDefKind::BuiltInEager(expander), kind: MacroDefKind::BuiltInEager(expander),
local_inner: false, local_inner: false,
@ -432,6 +431,7 @@ mod tests {
def, def,
fragment: FragmentKind::Expr, fragment: FragmentKind::Expr,
subtree: Arc::new(parsed_args.clone()), subtree: Arc::new(parsed_args.clone()),
krate,
file_id: file_id.into(), file_id: file_id.into(),
} }
}); });
@ -441,6 +441,7 @@ mod tests {
def, def,
fragment, fragment,
subtree: Arc::new(subtree), subtree: Arc::new(subtree),
krate,
file_id: file_id.into(), file_id: file_id.into(),
}; };

View file

@ -25,12 +25,14 @@ use crate::{
EagerCallLoc, EagerMacroId, InFile, MacroCallId, MacroCallKind, MacroDefId, MacroDefKind, EagerCallLoc, EagerMacroId, InFile, MacroCallId, MacroCallKind, MacroDefId, MacroDefKind,
}; };
use ra_db::CrateId;
use ra_parser::FragmentKind; use ra_parser::FragmentKind;
use ra_syntax::{algo::SyntaxRewriter, SyntaxNode}; use ra_syntax::{algo::SyntaxRewriter, SyntaxNode};
use std::sync::Arc; use std::sync::Arc;
pub fn expand_eager_macro( pub fn expand_eager_macro(
db: &dyn AstDatabase, db: &dyn AstDatabase,
krate: CrateId,
macro_call: InFile<ast::MacroCall>, macro_call: InFile<ast::MacroCall>,
def: MacroDefId, def: MacroDefId,
resolver: &dyn Fn(ast::Path) -> Option<MacroDefId>, resolver: &dyn Fn(ast::Path) -> Option<MacroDefId>,
@ -47,6 +49,7 @@ pub fn expand_eager_macro(
def, def,
fragment: FragmentKind::Expr, fragment: FragmentKind::Expr,
subtree: Arc::new(parsed_args.clone()), subtree: Arc::new(parsed_args.clone()),
krate,
file_id: macro_call.file_id, file_id: macro_call.file_id,
} }
}); });
@ -56,14 +59,20 @@ pub fn expand_eager_macro(
let result = eager_macro_recur( let result = eager_macro_recur(
db, db,
InFile::new(arg_file_id.as_file(), parsed_args.syntax_node()), InFile::new(arg_file_id.as_file(), parsed_args.syntax_node()),
krate,
resolver, resolver,
)?; )?;
let subtree = to_subtree(&result)?; let subtree = to_subtree(&result)?;
if let MacroDefKind::BuiltInEager(eager) = def.kind { if let MacroDefKind::BuiltInEager(eager) = def.kind {
let (subtree, fragment) = eager.expand(db, arg_id, &subtree).ok()?; let (subtree, fragment) = eager.expand(db, arg_id, &subtree).ok()?;
let eager = let eager = EagerCallLoc {
EagerCallLoc { def, fragment, subtree: Arc::new(subtree), file_id: macro_call.file_id }; def,
fragment,
subtree: Arc::new(subtree),
krate,
file_id: macro_call.file_id,
};
Some(db.intern_eager_expansion(eager)) Some(db.intern_eager_expansion(eager))
} else { } else {
@ -81,11 +90,12 @@ fn lazy_expand(
db: &dyn AstDatabase, db: &dyn AstDatabase,
def: &MacroDefId, def: &MacroDefId,
macro_call: InFile<ast::MacroCall>, macro_call: InFile<ast::MacroCall>,
krate: CrateId,
) -> Option<InFile<SyntaxNode>> { ) -> Option<InFile<SyntaxNode>> {
let ast_id = db.ast_id_map(macro_call.file_id).ast_id(&macro_call.value); let ast_id = db.ast_id_map(macro_call.file_id).ast_id(&macro_call.value);
let id: MacroCallId = let id: MacroCallId =
def.as_lazy_macro(db, MacroCallKind::FnLike(macro_call.with_value(ast_id))).into(); def.as_lazy_macro(db, krate, MacroCallKind::FnLike(macro_call.with_value(ast_id))).into();
db.parse_or_expand(id.as_file()).map(|node| InFile::new(id.as_file(), node)) db.parse_or_expand(id.as_file()).map(|node| InFile::new(id.as_file(), node))
} }
@ -93,6 +103,7 @@ fn lazy_expand(
fn eager_macro_recur( fn eager_macro_recur(
db: &dyn AstDatabase, db: &dyn AstDatabase,
curr: InFile<SyntaxNode>, curr: InFile<SyntaxNode>,
krate: CrateId,
macro_resolver: &dyn Fn(ast::Path) -> Option<MacroDefId>, macro_resolver: &dyn Fn(ast::Path) -> Option<MacroDefId>,
) -> Option<SyntaxNode> { ) -> Option<SyntaxNode> {
let original = curr.value.clone(); let original = curr.value.clone();
@ -105,8 +116,13 @@ fn eager_macro_recur(
let def: MacroDefId = macro_resolver(child.path()?)?; let def: MacroDefId = macro_resolver(child.path()?)?;
let insert = match def.kind { let insert = match def.kind {
MacroDefKind::BuiltInEager(_) => { MacroDefKind::BuiltInEager(_) => {
let id: MacroCallId = let id: MacroCallId = expand_eager_macro(
expand_eager_macro(db, curr.with_value(child.clone()), def, macro_resolver)? db,
krate,
curr.with_value(child.clone()),
def,
macro_resolver,
)?
.into(); .into();
db.parse_or_expand(id.as_file())? db.parse_or_expand(id.as_file())?
} }
@ -114,9 +130,9 @@ fn eager_macro_recur(
| MacroDefKind::BuiltIn(_) | MacroDefKind::BuiltIn(_)
| MacroDefKind::BuiltInDerive(_) | MacroDefKind::BuiltInDerive(_)
| MacroDefKind::CustomDerive(_) => { | MacroDefKind::CustomDerive(_) => {
let expanded = lazy_expand(db, &def, curr.with_value(child.clone()))?; let expanded = lazy_expand(db, &def, curr.with_value(child.clone()), krate)?;
// replace macro inside // replace macro inside
eager_macro_recur(db, expanded, macro_resolver)? eager_macro_recur(db, expanded, krate, macro_resolver)?
} }
}; };

View file

@ -209,8 +209,13 @@ pub struct MacroDefId {
} }
impl MacroDefId { impl MacroDefId {
pub fn as_lazy_macro(self, db: &dyn db::AstDatabase, kind: MacroCallKind) -> LazyMacroId { pub fn as_lazy_macro(
db.intern_macro(MacroCallLoc { def: self, kind }) self,
db: &dyn db::AstDatabase,
krate: CrateId,
kind: MacroCallKind,
) -> LazyMacroId {
db.intern_macro(MacroCallLoc { def: self, krate, kind })
} }
} }
@ -227,6 +232,7 @@ pub enum MacroDefKind {
#[derive(Debug, Clone, PartialEq, Eq, Hash)] #[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct MacroCallLoc { pub struct MacroCallLoc {
pub(crate) def: MacroDefId, pub(crate) def: MacroDefId,
pub(crate) krate: CrateId,
pub(crate) kind: MacroCallKind, pub(crate) kind: MacroCallKind,
} }
@ -274,6 +280,7 @@ pub struct EagerCallLoc {
pub(crate) def: MacroDefId, pub(crate) def: MacroDefId,
pub(crate) fragment: FragmentKind, pub(crate) fragment: FragmentKind,
pub(crate) subtree: Arc<tt::Subtree>, pub(crate) subtree: Arc<tt::Subtree>,
pub(crate) krate: CrateId,
pub(crate) file_id: HirFileId, pub(crate) file_id: HirFileId,
} }
@ -424,8 +431,3 @@ impl<N: AstNode> InFile<N> {
self.with_value(self.value.syntax()) self.with_value(self.value.syntax())
} }
} }
// FIXME: this is obviously wrong, there shouldn't be any guesing here
fn guess_crate(db: &dyn db::AstDatabase, file_id: FileId) -> Option<CrateId> {
db.relevant_crates(file_id).iter().next().copied()
}