Skip to content

Commit c417c77

Browse files
bors[bot]matklad
andcommitted
Merge #1267
1267: Macro expand to r=edwin0cheng a=matklad closes #1264 The core problem this PR is trying to wrangle is that macros can expand to different stuffs, depending on context. That is, `foo!()` on the top-level expands to a list of items, but the same `foo!()` in expression position expands to expression. Our current `hir_parse(HirFileId) -> TreeArc<SourceFile>` does not really support this. So, the plan is to change `hir_parse` to untyped inreface (`TreeArc<Syntaxnode>`), and add `expands_to` field to `MacroCallLoc`, such that the *target* of macro expansion is selected by the calling code and is part of macro id. This unfortunately looses some type-safety :( Moreover, this doesn't really fix #1264 by itself, because we die due to some other error inside macro expansion: expander fails to produce a tree with a single root, which trips assert inside rowan. Co-authored-by: Aleksey Kladov <[email protected]>
2 parents ee0ab7c + caa8663 commit c417c77

File tree

9 files changed

+68
-43
lines changed

9 files changed

+68
-43
lines changed

crates/ra_hir/src/db.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use std::sync::{Arc, Mutex};
22

3-
use ra_syntax::{SyntaxNode, TreeArc, SourceFile, SmolStr, ast};
3+
use ra_syntax::{SyntaxNode, TreeArc, SmolStr, ast};
44
use ra_db::{SourceDatabase, salsa};
55

66
use crate::{
@@ -54,8 +54,8 @@ pub trait DefDatabase: SourceDatabase {
5454
#[salsa::invoke(crate::ids::macro_expand_query)]
5555
fn macro_expand(&self, macro_call: ids::MacroCallId) -> Result<Arc<tt::Subtree>, String>;
5656

57-
#[salsa::invoke(crate::ids::HirFileId::hir_parse_query)]
58-
fn hir_parse(&self, file_id: HirFileId) -> TreeArc<SourceFile>;
57+
#[salsa::invoke(crate::ids::HirFileId::parse_or_expand_query)]
58+
fn parse_or_expand(&self, file_id: HirFileId) -> Option<TreeArc<SyntaxNode>>;
5959

6060
#[salsa::invoke(crate::adt::StructData::struct_data_query)]
6161
fn struct_data(&self, s: Struct) -> Arc<StructData>;

crates/ra_hir/src/diagnostics.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use std::{fmt, any::Any};
22

3-
use ra_syntax::{SyntaxNodePtr, TreeArc, AstPtr, TextRange, ast, SyntaxNode, AstNode};
3+
use ra_syntax::{SyntaxNodePtr, TreeArc, AstPtr, TextRange, ast, SyntaxNode};
44
use relative_path::RelativePathBuf;
55

66
use crate::{HirFileId, HirDatabase, Name};
@@ -29,8 +29,8 @@ pub trait Diagnostic: Any + Send + Sync + fmt::Debug + 'static {
2929

3030
impl dyn Diagnostic {
3131
pub fn syntax_node(&self, db: &impl HirDatabase) -> TreeArc<SyntaxNode> {
32-
let source_file = db.hir_parse(self.file());
33-
self.syntax_node_ptr().to_node(source_file.syntax()).to_owned()
32+
let node = db.parse_or_expand(self.file()).unwrap();
33+
self.syntax_node_ptr().to_node(&*node).to_owned()
3434
}
3535
pub fn downcast_ref<D: Diagnostic>(&self) -> Option<&D> {
3636
self.as_any().downcast_ref()

crates/ra_hir/src/expr.rs

+6-6
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,11 @@ use rustc_hash::FxHashMap;
66
use ra_arena::{Arena, RawId, impl_arena_id, map::ArenaMap};
77
use ra_syntax::{
88
SyntaxNodePtr, AstPtr, AstNode,
9-
ast::{self, LoopBodyOwner, ArgListOwner, NameOwner, LiteralKind,ArrayExprKind, TypeAscriptionOwner}
9+
ast::{self, LoopBodyOwner, ArgListOwner, NameOwner, LiteralKind,ArrayExprKind, TypeAscriptionOwner},
1010
};
1111

1212
use crate::{
13-
Path, Name, HirDatabase, Resolver,DefWithBody, Either, HirFileId, MacroCallLoc,
13+
Path, Name, HirDatabase, Resolver,DefWithBody, Either, HirFileId, MacroCallLoc, MacroFileKind,
1414
name::AsName,
1515
type_ref::{Mutability, TypeRef},
1616
};
@@ -830,11 +830,11 @@ where
830830

831831
if let Some(def) = self.resolver.resolve_macro_call(path) {
832832
let call_id = MacroCallLoc { def, ast_id }.id(self.db);
833-
if let Some(tt) = self.db.macro_expand(call_id).ok() {
834-
if let Some(expr) = mbe::token_tree_to_expr(&tt).ok() {
833+
let file_id = call_id.as_file(MacroFileKind::Expr);
834+
if let Some(node) = self.db.parse_or_expand(file_id) {
835+
if let Some(expr) = ast::Expr::cast(&*node) {
835836
log::debug!("macro expansion {}", expr.syntax().debug_dump());
836-
let old_file_id =
837-
std::mem::replace(&mut self.current_file_id, call_id.into());
837+
let old_file_id = std::mem::replace(&mut self.current_file_id, file_id);
838838
let id = self.collect_expr(&expr);
839839
self.current_file_id = old_file_id;
840840
return id;

crates/ra_hir/src/ids.rs

+38-21
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use std::{
44
};
55

66
use ra_db::{FileId, salsa};
7-
use ra_syntax::{TreeArc, SourceFile, AstNode, ast};
7+
use ra_syntax::{TreeArc, AstNode, ast, SyntaxNode};
88
use mbe::MacroRules;
99

1010
use crate::{
@@ -39,8 +39,8 @@ impl HirFileId {
3939
pub fn original_file(self, db: &impl DefDatabase) -> FileId {
4040
match self.0 {
4141
HirFileIdRepr::File(file_id) => file_id,
42-
HirFileIdRepr::Macro(macro_call_id) => {
43-
let loc = macro_call_id.loc(db);
42+
HirFileIdRepr::Macro(macro_file) => {
43+
let loc = macro_file.macro_call_id.loc(db);
4444
loc.ast_id.file_id().original_file(db)
4545
}
4646
}
@@ -56,16 +56,17 @@ impl HirFileId {
5656
}
5757
}
5858

59-
pub(crate) fn hir_parse_query(
59+
pub(crate) fn parse_or_expand_query(
6060
db: &impl DefDatabase,
6161
file_id: HirFileId,
62-
) -> TreeArc<SourceFile> {
62+
) -> Option<TreeArc<SyntaxNode>> {
6363
match file_id.0 {
64-
HirFileIdRepr::File(file_id) => db.parse(file_id),
65-
HirFileIdRepr::Macro(macro_call_id) => {
66-
match db.macro_expand(macro_call_id) {
67-
Ok(tt) => mbe::token_tree_to_ast_item_list(&tt),
68-
Err(err) => {
64+
HirFileIdRepr::File(file_id) => Some(db.parse(file_id).syntax().to_owned()),
65+
HirFileIdRepr::Macro(macro_file) => {
66+
let macro_call_id = macro_file.macro_call_id;
67+
let tt = db
68+
.macro_expand(macro_call_id)
69+
.map_err(|err| {
6970
// Note:
7071
// The final goal we would like to make all parse_macro success,
7172
// such that the following log will not call anyway.
@@ -74,9 +75,14 @@ impl HirFileId {
7475
err,
7576
macro_call_id.debug_dump(db)
7677
);
77-
78-
// returning an empty string looks fishy...
79-
SourceFile::parse("")
78+
})
79+
.ok()?;
80+
match macro_file.macro_file_kind {
81+
MacroFileKind::Items => {
82+
Some(mbe::token_tree_to_ast_item_list(&tt).syntax().to_owned())
83+
}
84+
MacroFileKind::Expr => {
85+
mbe::token_tree_to_expr(&tt).ok().map(|it| it.syntax().to_owned())
8086
}
8187
}
8288
}
@@ -87,7 +93,19 @@ impl HirFileId {
8793
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
8894
enum HirFileIdRepr {
8995
File(FileId),
90-
Macro(MacroCallId),
96+
Macro(MacroFile),
97+
}
98+
99+
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
100+
struct MacroFile {
101+
macro_call_id: MacroCallId,
102+
macro_file_kind: MacroFileKind,
103+
}
104+
105+
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
106+
pub(crate) enum MacroFileKind {
107+
Items,
108+
Expr,
91109
}
92110

93111
impl From<FileId> for HirFileId {
@@ -96,12 +114,6 @@ impl From<FileId> for HirFileId {
96114
}
97115
}
98116

99-
impl From<MacroCallId> for HirFileId {
100-
fn from(macro_call_id: MacroCallId) -> HirFileId {
101-
HirFileId(HirFileIdRepr::Macro(macro_call_id))
102-
}
103-
}
104-
105117
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
106118
pub struct MacroDefId(pub(crate) AstId<ast::MacroCall>);
107119

@@ -173,6 +185,11 @@ impl MacroCallId {
173185
pub(crate) fn loc(self, db: &impl DefDatabase) -> MacroCallLoc {
174186
db.lookup_intern_macro(self)
175187
}
188+
189+
pub(crate) fn as_file(self, kind: MacroFileKind) -> HirFileId {
190+
let macro_file = MacroFile { macro_call_id: self, macro_file_kind: kind };
191+
HirFileId(HirFileIdRepr::Macro(macro_file))
192+
}
176193
}
177194

178195
impl MacroCallLoc {
@@ -342,7 +359,7 @@ impl MacroCallId {
342359
let syntax_str = node.syntax().text().chunks().collect::<Vec<_>>().join(" ");
343360

344361
// dump the file name
345-
let file_id: HirFileId = self.clone().into();
362+
let file_id: HirFileId = self.loc(db).ast_id.file_id();
346363
let original = file_id.original_file(db);
347364
let macro_rules = db.macro_def(loc.def);
348365

crates/ra_hir/src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ use crate::{
5353
name::{AsName, KnownName},
5454
source_id::{FileAstId, AstId},
5555
resolve::Resolver,
56+
ids::MacroFileKind,
5657
};
5758

5859
pub use self::{

crates/ra_hir/src/nameres/collector.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ use crate::{
1515
diagnostics::DefDiagnostic,
1616
raw,
1717
},
18-
ids::{AstItemDef, LocationCtx, MacroCallLoc, MacroCallId, MacroDefId},
18+
ids::{AstItemDef, LocationCtx, MacroCallLoc, MacroCallId, MacroDefId, MacroFileKind},
1919
AstId,
2020
};
2121

@@ -371,7 +371,7 @@ where
371371
self.macro_stack_monitor.increase(macro_def_id);
372372

373373
if !self.macro_stack_monitor.is_poison(macro_def_id) {
374-
let file_id: HirFileId = macro_call_id.into();
374+
let file_id: HirFileId = macro_call_id.as_file(MacroFileKind::Items);
375375
let raw_items = self.db.raw_items(file_id);
376376
ModCollector { def_collector: &mut *self, file_id, module_id, raw_items: &raw_items }
377377
.collect(raw_items.items());

crates/ra_hir/src/nameres/raw.rs

+5-2
Original file line numberDiff line numberDiff line change
@@ -75,8 +75,11 @@ impl RawItems {
7575
source_ast_id_map: db.ast_id_map(file_id.into()),
7676
source_map: ImportSourceMap::default(),
7777
};
78-
let source_file = db.hir_parse(file_id);
79-
collector.process_module(None, &*source_file);
78+
if let Some(node) = db.parse_or_expand(file_id) {
79+
if let Some(source_file) = ast::SourceFile::cast(&node) {
80+
collector.process_module(None, &*source_file);
81+
}
82+
}
8083
(Arc::new(collector.raw_items), Arc::new(collector.source_map))
8184
}
8285

crates/ra_hir/src/source_id.rs

+9-5
Original file line numberDiff line numberDiff line change
@@ -81,24 +81,28 @@ pub struct ErasedFileAstId(RawId);
8181
impl_arena_id!(ErasedFileAstId);
8282

8383
/// Maps items' `SyntaxNode`s to `ErasedFileAstId`s and back.
84-
#[derive(Debug, PartialEq, Eq)]
84+
#[derive(Debug, PartialEq, Eq, Default)]
8585
pub struct AstIdMap {
8686
arena: Arena<ErasedFileAstId, SyntaxNodePtr>,
8787
}
8888

8989
impl AstIdMap {
9090
pub(crate) fn ast_id_map_query(db: &impl DefDatabase, file_id: HirFileId) -> Arc<AstIdMap> {
91-
let source_file = db.hir_parse(file_id);
92-
Arc::new(AstIdMap::from_source(source_file.syntax()))
91+
let map = if let Some(node) = db.parse_or_expand(file_id) {
92+
AstIdMap::from_source(&*node)
93+
} else {
94+
AstIdMap::default()
95+
};
96+
Arc::new(map)
9397
}
9498

9599
pub(crate) fn file_item_query(
96100
db: &impl DefDatabase,
97101
file_id: HirFileId,
98102
ast_id: ErasedFileAstId,
99103
) -> TreeArc<SyntaxNode> {
100-
let source_file = db.hir_parse(file_id);
101-
db.ast_id_map(file_id).arena[ast_id].to_node(source_file.syntax()).to_owned()
104+
let node = db.parse_or_expand(file_id).unwrap();
105+
db.ast_id_map(file_id).arena[ast_id].to_node(&*node).to_owned()
102106
}
103107

104108
pub(crate) fn ast_id<N: AstNode>(&self, item: &N) -> FileAstId<N> {

crates/ra_ide_api/src/change.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -222,7 +222,7 @@ impl RootDatabase {
222222

223223
self.query(ra_db::ParseQuery).sweep(sweep);
224224

225-
self.query(hir::db::HirParseQuery).sweep(sweep);
225+
self.query(hir::db::ParseOrExpandQuery).sweep(sweep);
226226
self.query(hir::db::AstIdMapQuery).sweep(sweep);
227227
self.query(hir::db::AstIdToNodeQuery).sweep(sweep);
228228

0 commit comments

Comments
 (0)