Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

store macro def inside macro id #1055

Merged
merged 3 commits into from Mar 26, 2019
Merged
Changes from 1 commit
Commits
File filter...
Filter file types
Jump to…
Jump to file or symbol
Failed to load files and symbols.

Always

Just for now

Next

store macro def inside macro id

This solves the problem of "macro expansion can't call into name
resolution, because name resolution calls back into macro expansion"

Because we store macro def as a part of call id, macro expansion just
knows the def!
  • Loading branch information...
matklad committed Mar 26, 2019
commit 5270bca5f72fa65f0515be776e06d3d6a4d1efca
@@ -76,7 +76,7 @@ impl Module {
import: ImportId,
) -> TreeArc<ast::PathSegment> {
let (file_id, source) = self.definition_source(db);
let (_, source_map) = db.raw_items_with_source_map(file_id.original_file(db));
let (_, source_map) = db.raw_items_with_source_map(file_id);
source_map.get(&source, import)
}

@@ -1,7 +1,7 @@
use std::sync::Arc;

use ra_syntax::{SyntaxNode, TreeArc, SourceFile};
use ra_db::{SourceDatabase, salsa, FileId};
use ra_db::{SourceDatabase, salsa};

use crate::{
HirFileId, SourceFileItems, SourceItemId, Crate, Module, HirInterner,
@@ -38,10 +38,13 @@ pub trait DefDatabase: SourceDatabase + AsRef<HirInterner> {
fn file_item(&self, source_item_id: SourceItemId) -> TreeArc<SyntaxNode>;

#[salsa::invoke(RawItems::raw_items_query)]
fn raw_items(&self, file_id: FileId) -> Arc<RawItems>;
fn raw_items(&self, file_id: HirFileId) -> Arc<RawItems>;

#[salsa::invoke(RawItems::raw_items_with_source_map_query)]
fn raw_items_with_source_map(&self, file_id: FileId) -> (Arc<RawItems>, Arc<ImportSourceMap>);
fn raw_items_with_source_map(
&self,
file_id: HirFileId,
) -> (Arc<RawItems>, Arc<ImportSourceMap>);

#[salsa::invoke(CrateDefMap::crate_def_map_query)]
fn crate_def_map(&self, krate: Crate) -> Arc<CrateDefMap>;
@@ -7,6 +7,7 @@ use std::{
use ra_db::{LocationInterner, FileId};
use ra_syntax::{TreeArc, SyntaxNode, SourceFile, AstNode, SyntaxNodePtr, ast};
use ra_arena::{Arena, RawId, ArenaId, impl_arena_id};
use mbe::MacroRules;

use crate::{
Module,
@@ -100,10 +101,7 @@ fn parse_macro(db: &impl DefDatabase, macro_call_id: MacroCallId) -> Option<Tree
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 macro_rules = macro_def_query(db, loc.def)?;
let tt = macro_rules.expand(&macro_arg).ok()?;
Some(mbe::token_tree_to_ast_item_list(&tt))
}
@@ -126,6 +124,22 @@ impl From<MacroCallId> for HirFileId {
}
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub(crate) enum MacroDefId {
MacroByExample { source_item_id: SourceItemId },
}

fn macro_def_query(db: &impl DefDatabase, id: MacroDefId) -> Option<Arc<MacroRules>> {
let syntax_node = match id {
MacroDefId::MacroByExample { source_item_id } => db.file_item(source_item_id),
};
let macro_call = ast::MacroCall::cast(&syntax_node).unwrap();
let arg = macro_call.token_tree()?;
let (tt, _) = mbe::ast_to_token_tree(arg)?;
let rules = MacroRules::parse(&tt).ok()?;
Some(Arc::new(rules))
}

/// `MacroCallId` identifies a particular macro invocation, like
/// `println!("Hello, {}", world)`.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
@@ -134,7 +148,7 @@ impl_arena_id!(MacroCallId);

#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct MacroCallLoc {
pub(crate) module: Module,
pub(crate) def: MacroDefId,
pub(crate) source_item_id: SourceItemId,
}

@@ -63,7 +63,7 @@ use test_utils::tested_by;
use crate::{
ModuleDef, Name, Crate, Module,
DefDatabase, Path, PathKind, HirFileId, Trait,
ids::{SourceItemId, SourceFileItemId, MacroCallId},
ids::{SourceItemId, SourceFileItemId, MacroCallId, MacroDefId},
diagnostics::DiagnosticSink,
nameres::diagnostics::DefDiagnostic,
};
@@ -85,7 +85,7 @@ pub struct CrateDefMap {
root: CrateModuleId,
modules: Arena<CrateModuleId, ModuleData>,
macros: Arena<CrateMacroId, mbe::MacroRules>,
public_macros: FxHashMap<Name, CrateMacroId>,
public_macros: FxHashMap<Name, MacroDefId>,
macro_resolutions: FxHashMap<MacroCallId, (Crate, CrateMacroId)>,
diagnostics: Vec<DefDiagnostic>,
}
@@ -238,13 +238,6 @@ impl CrateDefMap {
self.diagnostics.iter().for_each(|it| it.add_to(db, module, sink))
}

pub(crate) fn resolve_macro(
&self,
macro_call_id: MacroCallId,
) -> Option<(Crate, CrateMacroId)> {
self.macro_resolutions.get(&macro_call_id).map(|&it| it)
}

pub(crate) fn find_module_by_source(
&self,
file_id: HirFileId,
@@ -6,15 +6,15 @@ use ra_db::FileId;

use crate::{
Function, Module, Struct, Enum, Const, Static, Trait, TypeAlias,
DefDatabase, HirFileId, Name, Path, Crate,
DefDatabase, HirFileId, Name, Path,
KnownName,
nameres::{
Resolution, PerNs, ModuleDef, ReachedFixedPoint, ResolveMode,
CrateDefMap, CrateModuleId, ModuleData, CrateMacroId,
CrateDefMap, CrateModuleId, ModuleData,
diagnostics::DefDiagnostic,
raw,
},
ids::{AstItemDef, LocationCtx, MacroCallLoc, SourceItemId, MacroCallId},
ids::{AstItemDef, LocationCtx, MacroCallLoc, SourceItemId, MacroCallId, MacroDefId},
};

pub(super) fn collect_defs(db: &impl DefDatabase, mut def_map: CrateDefMap) -> CrateDefMap {
@@ -51,8 +51,8 @@ struct DefCollector<DB> {
def_map: CrateDefMap,
glob_imports: FxHashMap<CrateModuleId, Vec<(CrateModuleId, raw::ImportId)>>,
unresolved_imports: Vec<(CrateModuleId, raw::ImportId, raw::ImportData)>,
unexpanded_macros: Vec<(CrateModuleId, MacroCallId, Path, tt::Subtree)>,
global_macro_scope: FxHashMap<Name, CrateMacroId>,
unexpanded_macros: Vec<(CrateModuleId, SourceItemId, Path)>,
global_macro_scope: FxHashMap<Name, MacroDefId>,
}

impl<'a, DB> DefCollector<&'a DB>
@@ -62,7 +62,7 @@ where
fn collect(&mut self) {
let crate_graph = self.db.crate_graph();
let file_id = crate_graph.crate_root(self.def_map.krate.crate_id());
let raw_items = self.db.raw_items(file_id);
let raw_items = self.db.raw_items(file_id.into());
let module_id = self.def_map.root;
self.def_map.modules[module_id].definition = Some(file_id);
ModCollector {
@@ -93,14 +93,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(), macro_id);
}
self.global_macro_scope.insert(name, macro_id);
fn define_macro(&mut self, name: Name, macro_id: MacroDefId, export: bool) {
if export {
self.def_map.public_macros.insert(name.clone(), macro_id);
}
self.global_macro_scope.insert(name, macro_id);
}

fn resolve_imports(&mut self) -> ReachedFixedPoint {
@@ -296,7 +293,7 @@ where
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)| {
macros.retain(|(module_id, source_item_id, path)| {
if path.segments.len() != 2 {
return true;
}
@@ -312,47 +309,24 @@ where
res = ReachedFixedPoint::No;
let def_map = self.db.crate_def_map(krate);
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()));
let call_id =
MacroCallLoc { def: macro_id, source_item_id: *source_item_id }.id(self.db);
resolved.push((*module_id, call_id));
}
false
});

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);
for (module_id, macro_call_id) in resolved {
self.collect_macro_expansion(module_id, macro_call_id);
}
res
}

fn collect_macro_expansion(
&mut self,
module_id: CrateModuleId,
macro_call_id: MacroCallId,
macro_def_id: (Crate, CrateMacroId),
macro_arg: tt::Subtree,
) {
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(&macro_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 collect_macro_expansion(&mut self, module_id: CrateModuleId, macro_call_id: MacroCallId) {
let file_id: HirFileId = macro_call_id.into();
let raw_items = self.db.raw_items(file_id);
ModCollector { def_collector: &mut *self, file_id, module_id, raw_items: &raw_items }
.collect(raw_items.items())
}

fn finish(self) -> CrateDefMap {
@@ -412,7 +386,7 @@ where
Ok(file_id) => {
let module_id =
self.push_child_module(name.clone(), source_item_id, Some(file_id));
let raw_items = self.def_collector.db.raw_items(file_id);
let raw_items = self.def_collector.db.raw_items(file_id.into());
ModCollector {
def_collector: &mut *self.def_collector,
module_id,
@@ -484,38 +458,33 @@ where
// Case 1: macro rules, define a macro in crate-global mutable scope
if is_macro_rules(&mac.path) {
if let Some(name) = &mac.name {
self.def_collector.define_macro(name.clone(), &mac.arg, mac.export)
let macro_id = MacroDefId::MacroByExample {
source_item_id: mac.source_item_id.with_file_id(self.file_id),
};
self.def_collector.define_macro(name.clone(), macro_id, mac.export)
}
return;
}

let source_item_id = SourceItemId { file_id: self.file_id, item_id: mac.source_item_id };
let macro_call_id = MacroCallLoc {
module: Module { krate: self.def_collector.def_map.krate, module_id: self.module_id },
source_item_id,
}
.id(self.def_collector.db);

// Case 2: try to expand macro_rules from this crate, triggering
// recursive item collection.
if let Some(&macro_id) =
mac.path.as_ident().and_then(|name| self.def_collector.global_macro_scope.get(name))
{
self.def_collector.collect_macro_expansion(
self.module_id,
macro_call_id,
(self.def_collector.def_map.krate, macro_id),
mac.arg.clone(),
);
let macro_call_id =
MacroCallLoc { def: macro_id, source_item_id }.id(self.def_collector.db);

self.def_collector.collect_macro_expansion(self.module_id, macro_call_id);
return;
}

// Case 3: path to a macro from another crate, expand during name resolution
self.def_collector.unexpanded_macros.push((
self.module_id,
macro_call_id,
source_item_id,
mac.path.clone(),
mac.arg.clone(),
))
}
}
@@ -4,7 +4,6 @@ use std::{
};

use test_utils::tested_by;
use ra_db::FileId;
use ra_arena::{Arena, impl_arena_id, RawId, map::ArenaMap};
use ra_syntax::{
AstNode, SourceFile, AstPtr, TreeArc,
@@ -47,40 +46,27 @@ impl ImportSourceMap {
}

impl RawItems {
pub(crate) fn raw_items_query(db: &impl DefDatabase, file_id: FileId) -> Arc<RawItems> {
pub(crate) fn raw_items_query(db: &impl DefDatabase, file_id: HirFileId) -> Arc<RawItems> {
db.raw_items_with_source_map(file_id).0
}

pub(crate) fn raw_items_with_source_map_query(
db: &impl DefDatabase,
file_id: FileId,
file_id: HirFileId,
) -> (Arc<RawItems>, Arc<ImportSourceMap>) {
let mut collector = RawItemsCollector {
raw_items: RawItems::default(),
source_file_items: db.file_items(file_id.into()),
source_map: ImportSourceMap::default(),
};
let source_file = db.parse(file_id);
let source_file = db.hir_parse(file_id);
collector.process_module(None, &*source_file);
(Arc::new(collector.raw_items), Arc::new(collector.source_map))
}

pub(crate) fn items(&self) -> &[RawItem] {
&self.items
}

// We can't use queries during name resolution for fear of cycles, so this
// is a query-less variant of the above function.
pub(crate) fn from_source_file(source_file: &SourceFile, file_id: HirFileId) -> RawItems {
let source_file_items = SourceFileItems::from_source_file(source_file, file_id);
let mut collector = RawItemsCollector {
raw_items: RawItems::default(),
source_file_items: Arc::new(source_file_items),
source_map: ImportSourceMap::default(),
};
collector.process_module(None, &*source_file);
collector.raw_items
}
}

impl Index<Module> for RawItems {
@@ -173,7 +159,6 @@ pub(crate) struct MacroData {
pub(crate) source_item_id: SourceFileItemId,
pub(crate) path: Path,
pub(crate) name: Option<Name>,
pub(crate) arg: tt::Subtree,
pub(crate) export: bool,
}

@@ -291,18 +276,15 @@ impl RawItemsCollector {
}

fn add_macro(&mut self, current_module: Option<Module>, m: &ast::MacroCall) {
let (path, arg) = match (
m.path().and_then(Path::from_ast),
m.token_tree().and_then(mbe::ast_to_token_tree),
) {
(Some(path), Some((token_tree, _token_map))) => (path, token_tree),
let path = match m.path().and_then(Path::from_ast) {
Some(it) => it,
_ => return,
};

let name = m.name().map(|it| it.as_name());
let source_item_id = self.source_file_items.id_of_unchecked(m.syntax());
let export = m.has_atom_attr("macro_export");
let m = self.raw_items.macros.alloc(MacroData { source_item_id, path, arg, name, export });
let m = self.raw_items.macros.alloc(MacroData { source_item_id, path, name, export });
self.push_item(current_module, RawItem::Macro(m));
}

ProTip! Use n and p to navigate between commits in a pull request.
You can’t perform that action at this time.