diff options
author | bors[bot] <bors[bot]@users.noreply.github.com> | 2019-05-14 07:12:09 +0100 |
---|---|---|
committer | bors[bot] <bors[bot]@users.noreply.github.com> | 2019-05-14 07:12:09 +0100 |
commit | c417c77b681f10cc7585507bd874e9fd2cea63b8 (patch) | |
tree | d05cf30716a7791cfc0d8fcfe522a7132b5fff06 /crates | |
parent | ee0ab7c00b4b8c5375c14b44e3d7288ebf0d732d (diff) | |
parent | caa8663c08e1724af2abcde11fa937937d76aa14 (diff) |
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]>
Diffstat (limited to 'crates')
-rw-r--r-- | crates/ra_hir/src/db.rs | 6 | ||||
-rw-r--r-- | crates/ra_hir/src/diagnostics.rs | 6 | ||||
-rw-r--r-- | crates/ra_hir/src/expr.rs | 12 | ||||
-rw-r--r-- | crates/ra_hir/src/ids.rs | 59 | ||||
-rw-r--r-- | crates/ra_hir/src/lib.rs | 1 | ||||
-rw-r--r-- | crates/ra_hir/src/nameres/collector.rs | 4 | ||||
-rw-r--r-- | crates/ra_hir/src/nameres/raw.rs | 7 | ||||
-rw-r--r-- | crates/ra_hir/src/source_id.rs | 14 | ||||
-rw-r--r-- | crates/ra_ide_api/src/change.rs | 2 |
9 files changed, 68 insertions, 43 deletions
diff --git a/crates/ra_hir/src/db.rs b/crates/ra_hir/src/db.rs index 8f98ca3a5..8e827d4f5 100644 --- a/crates/ra_hir/src/db.rs +++ b/crates/ra_hir/src/db.rs | |||
@@ -1,6 +1,6 @@ | |||
1 | use std::sync::{Arc, Mutex}; | 1 | use std::sync::{Arc, Mutex}; |
2 | 2 | ||
3 | use ra_syntax::{SyntaxNode, TreeArc, SourceFile, SmolStr, ast}; | 3 | use ra_syntax::{SyntaxNode, TreeArc, SmolStr, ast}; |
4 | use ra_db::{SourceDatabase, salsa}; | 4 | use ra_db::{SourceDatabase, salsa}; |
5 | 5 | ||
6 | use crate::{ | 6 | use crate::{ |
@@ -54,8 +54,8 @@ pub trait DefDatabase: SourceDatabase { | |||
54 | #[salsa::invoke(crate::ids::macro_expand_query)] | 54 | #[salsa::invoke(crate::ids::macro_expand_query)] |
55 | fn macro_expand(&self, macro_call: ids::MacroCallId) -> Result<Arc<tt::Subtree>, String>; | 55 | fn macro_expand(&self, macro_call: ids::MacroCallId) -> Result<Arc<tt::Subtree>, String>; |
56 | 56 | ||
57 | #[salsa::invoke(crate::ids::HirFileId::hir_parse_query)] | 57 | #[salsa::invoke(crate::ids::HirFileId::parse_or_expand_query)] |
58 | fn hir_parse(&self, file_id: HirFileId) -> TreeArc<SourceFile>; | 58 | fn parse_or_expand(&self, file_id: HirFileId) -> Option<TreeArc<SyntaxNode>>; |
59 | 59 | ||
60 | #[salsa::invoke(crate::adt::StructData::struct_data_query)] | 60 | #[salsa::invoke(crate::adt::StructData::struct_data_query)] |
61 | fn struct_data(&self, s: Struct) -> Arc<StructData>; | 61 | fn struct_data(&self, s: Struct) -> Arc<StructData>; |
diff --git a/crates/ra_hir/src/diagnostics.rs b/crates/ra_hir/src/diagnostics.rs index d41525779..4b7b2dbee 100644 --- a/crates/ra_hir/src/diagnostics.rs +++ b/crates/ra_hir/src/diagnostics.rs | |||
@@ -1,6 +1,6 @@ | |||
1 | use std::{fmt, any::Any}; | 1 | use std::{fmt, any::Any}; |
2 | 2 | ||
3 | use ra_syntax::{SyntaxNodePtr, TreeArc, AstPtr, TextRange, ast, SyntaxNode, AstNode}; | 3 | use ra_syntax::{SyntaxNodePtr, TreeArc, AstPtr, TextRange, ast, SyntaxNode}; |
4 | use relative_path::RelativePathBuf; | 4 | use relative_path::RelativePathBuf; |
5 | 5 | ||
6 | use crate::{HirFileId, HirDatabase, Name}; | 6 | use crate::{HirFileId, HirDatabase, Name}; |
@@ -29,8 +29,8 @@ pub trait Diagnostic: Any + Send + Sync + fmt::Debug + 'static { | |||
29 | 29 | ||
30 | impl dyn Diagnostic { | 30 | impl dyn Diagnostic { |
31 | pub fn syntax_node(&self, db: &impl HirDatabase) -> TreeArc<SyntaxNode> { | 31 | pub fn syntax_node(&self, db: &impl HirDatabase) -> TreeArc<SyntaxNode> { |
32 | let source_file = db.hir_parse(self.file()); | 32 | let node = db.parse_or_expand(self.file()).unwrap(); |
33 | self.syntax_node_ptr().to_node(source_file.syntax()).to_owned() | 33 | self.syntax_node_ptr().to_node(&*node).to_owned() |
34 | } | 34 | } |
35 | pub fn downcast_ref<D: Diagnostic>(&self) -> Option<&D> { | 35 | pub fn downcast_ref<D: Diagnostic>(&self) -> Option<&D> { |
36 | self.as_any().downcast_ref() | 36 | self.as_any().downcast_ref() |
diff --git a/crates/ra_hir/src/expr.rs b/crates/ra_hir/src/expr.rs index a2b5db1a1..9618236e5 100644 --- a/crates/ra_hir/src/expr.rs +++ b/crates/ra_hir/src/expr.rs | |||
@@ -6,11 +6,11 @@ use rustc_hash::FxHashMap; | |||
6 | use ra_arena::{Arena, RawId, impl_arena_id, map::ArenaMap}; | 6 | use ra_arena::{Arena, RawId, impl_arena_id, map::ArenaMap}; |
7 | use ra_syntax::{ | 7 | use ra_syntax::{ |
8 | SyntaxNodePtr, AstPtr, AstNode, | 8 | SyntaxNodePtr, AstPtr, AstNode, |
9 | ast::{self, LoopBodyOwner, ArgListOwner, NameOwner, LiteralKind,ArrayExprKind, TypeAscriptionOwner} | 9 | ast::{self, LoopBodyOwner, ArgListOwner, NameOwner, LiteralKind,ArrayExprKind, TypeAscriptionOwner}, |
10 | }; | 10 | }; |
11 | 11 | ||
12 | use crate::{ | 12 | use crate::{ |
13 | Path, Name, HirDatabase, Resolver,DefWithBody, Either, HirFileId, MacroCallLoc, | 13 | Path, Name, HirDatabase, Resolver,DefWithBody, Either, HirFileId, MacroCallLoc, MacroFileKind, |
14 | name::AsName, | 14 | name::AsName, |
15 | type_ref::{Mutability, TypeRef}, | 15 | type_ref::{Mutability, TypeRef}, |
16 | }; | 16 | }; |
@@ -830,11 +830,11 @@ where | |||
830 | 830 | ||
831 | if let Some(def) = self.resolver.resolve_macro_call(path) { | 831 | if let Some(def) = self.resolver.resolve_macro_call(path) { |
832 | let call_id = MacroCallLoc { def, ast_id }.id(self.db); | 832 | let call_id = MacroCallLoc { def, ast_id }.id(self.db); |
833 | if let Some(tt) = self.db.macro_expand(call_id).ok() { | 833 | let file_id = call_id.as_file(MacroFileKind::Expr); |
834 | if let Some(expr) = mbe::token_tree_to_expr(&tt).ok() { | 834 | if let Some(node) = self.db.parse_or_expand(file_id) { |
835 | if let Some(expr) = ast::Expr::cast(&*node) { | ||
835 | log::debug!("macro expansion {}", expr.syntax().debug_dump()); | 836 | log::debug!("macro expansion {}", expr.syntax().debug_dump()); |
836 | let old_file_id = | 837 | let old_file_id = std::mem::replace(&mut self.current_file_id, file_id); |
837 | std::mem::replace(&mut self.current_file_id, call_id.into()); | ||
838 | let id = self.collect_expr(&expr); | 838 | let id = self.collect_expr(&expr); |
839 | self.current_file_id = old_file_id; | 839 | self.current_file_id = old_file_id; |
840 | return id; | 840 | return id; |
diff --git a/crates/ra_hir/src/ids.rs b/crates/ra_hir/src/ids.rs index ff4a81e59..f901a7432 100644 --- a/crates/ra_hir/src/ids.rs +++ b/crates/ra_hir/src/ids.rs | |||
@@ -4,7 +4,7 @@ use std::{ | |||
4 | }; | 4 | }; |
5 | 5 | ||
6 | use ra_db::{FileId, salsa}; | 6 | use ra_db::{FileId, salsa}; |
7 | use ra_syntax::{TreeArc, SourceFile, AstNode, ast}; | 7 | use ra_syntax::{TreeArc, AstNode, ast, SyntaxNode}; |
8 | use mbe::MacroRules; | 8 | use mbe::MacroRules; |
9 | 9 | ||
10 | use crate::{ | 10 | use crate::{ |
@@ -39,8 +39,8 @@ impl HirFileId { | |||
39 | pub fn original_file(self, db: &impl DefDatabase) -> FileId { | 39 | pub fn original_file(self, db: &impl DefDatabase) -> FileId { |
40 | match self.0 { | 40 | match self.0 { |
41 | HirFileIdRepr::File(file_id) => file_id, | 41 | HirFileIdRepr::File(file_id) => file_id, |
42 | HirFileIdRepr::Macro(macro_call_id) => { | 42 | HirFileIdRepr::Macro(macro_file) => { |
43 | let loc = macro_call_id.loc(db); | 43 | let loc = macro_file.macro_call_id.loc(db); |
44 | loc.ast_id.file_id().original_file(db) | 44 | loc.ast_id.file_id().original_file(db) |
45 | } | 45 | } |
46 | } | 46 | } |
@@ -56,16 +56,17 @@ impl HirFileId { | |||
56 | } | 56 | } |
57 | } | 57 | } |
58 | 58 | ||
59 | pub(crate) fn hir_parse_query( | 59 | pub(crate) fn parse_or_expand_query( |
60 | db: &impl DefDatabase, | 60 | db: &impl DefDatabase, |
61 | file_id: HirFileId, | 61 | file_id: HirFileId, |
62 | ) -> TreeArc<SourceFile> { | 62 | ) -> Option<TreeArc<SyntaxNode>> { |
63 | match file_id.0 { | 63 | match file_id.0 { |
64 | HirFileIdRepr::File(file_id) => db.parse(file_id), | 64 | HirFileIdRepr::File(file_id) => Some(db.parse(file_id).syntax().to_owned()), |
65 | HirFileIdRepr::Macro(macro_call_id) => { | 65 | HirFileIdRepr::Macro(macro_file) => { |
66 | match db.macro_expand(macro_call_id) { | 66 | let macro_call_id = macro_file.macro_call_id; |
67 | Ok(tt) => mbe::token_tree_to_ast_item_list(&tt), | 67 | let tt = db |
68 | Err(err) => { | 68 | .macro_expand(macro_call_id) |
69 | .map_err(|err| { | ||
69 | // Note: | 70 | // Note: |
70 | // The final goal we would like to make all parse_macro success, | 71 | // The final goal we would like to make all parse_macro success, |
71 | // such that the following log will not call anyway. | 72 | // such that the following log will not call anyway. |
@@ -74,9 +75,14 @@ impl HirFileId { | |||
74 | err, | 75 | err, |
75 | macro_call_id.debug_dump(db) | 76 | macro_call_id.debug_dump(db) |
76 | ); | 77 | ); |
77 | 78 | }) | |
78 | // returning an empty string looks fishy... | 79 | .ok()?; |
79 | SourceFile::parse("") | 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()) | ||
80 | } | 86 | } |
81 | } | 87 | } |
82 | } | 88 | } |
@@ -87,7 +93,19 @@ impl HirFileId { | |||
87 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | 93 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] |
88 | enum HirFileIdRepr { | 94 | enum HirFileIdRepr { |
89 | File(FileId), | 95 | 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, | ||
91 | } | 109 | } |
92 | 110 | ||
93 | impl From<FileId> for HirFileId { | 111 | impl From<FileId> for HirFileId { |
@@ -96,12 +114,6 @@ impl From<FileId> for HirFileId { | |||
96 | } | 114 | } |
97 | } | 115 | } |
98 | 116 | ||
99 | impl From<MacroCallId> for HirFileId { | ||
100 | fn from(macro_call_id: MacroCallId) -> HirFileId { | ||
101 | HirFileId(HirFileIdRepr::Macro(macro_call_id)) | ||
102 | } | ||
103 | } | ||
104 | |||
105 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | 117 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] |
106 | pub struct MacroDefId(pub(crate) AstId<ast::MacroCall>); | 118 | pub struct MacroDefId(pub(crate) AstId<ast::MacroCall>); |
107 | 119 | ||
@@ -173,6 +185,11 @@ impl MacroCallId { | |||
173 | pub(crate) fn loc(self, db: &impl DefDatabase) -> MacroCallLoc { | 185 | pub(crate) fn loc(self, db: &impl DefDatabase) -> MacroCallLoc { |
174 | db.lookup_intern_macro(self) | 186 | db.lookup_intern_macro(self) |
175 | } | 187 | } |
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 | } | ||
176 | } | 193 | } |
177 | 194 | ||
178 | impl MacroCallLoc { | 195 | impl MacroCallLoc { |
@@ -342,7 +359,7 @@ impl MacroCallId { | |||
342 | let syntax_str = node.syntax().text().chunks().collect::<Vec<_>>().join(" "); | 359 | let syntax_str = node.syntax().text().chunks().collect::<Vec<_>>().join(" "); |
343 | 360 | ||
344 | // dump the file name | 361 | // dump the file name |
345 | let file_id: HirFileId = self.clone().into(); | 362 | let file_id: HirFileId = self.loc(db).ast_id.file_id(); |
346 | let original = file_id.original_file(db); | 363 | let original = file_id.original_file(db); |
347 | let macro_rules = db.macro_def(loc.def); | 364 | let macro_rules = db.macro_def(loc.def); |
348 | 365 | ||
diff --git a/crates/ra_hir/src/lib.rs b/crates/ra_hir/src/lib.rs index 03b1063b6..0c6d7c2b7 100644 --- a/crates/ra_hir/src/lib.rs +++ b/crates/ra_hir/src/lib.rs | |||
@@ -53,6 +53,7 @@ use crate::{ | |||
53 | name::{AsName, KnownName}, | 53 | name::{AsName, KnownName}, |
54 | source_id::{FileAstId, AstId}, | 54 | source_id::{FileAstId, AstId}, |
55 | resolve::Resolver, | 55 | resolve::Resolver, |
56 | ids::MacroFileKind, | ||
56 | }; | 57 | }; |
57 | 58 | ||
58 | pub use self::{ | 59 | pub use self::{ |
diff --git a/crates/ra_hir/src/nameres/collector.rs b/crates/ra_hir/src/nameres/collector.rs index 4640b3b74..c615d80c3 100644 --- a/crates/ra_hir/src/nameres/collector.rs +++ b/crates/ra_hir/src/nameres/collector.rs | |||
@@ -15,7 +15,7 @@ use crate::{ | |||
15 | diagnostics::DefDiagnostic, | 15 | diagnostics::DefDiagnostic, |
16 | raw, | 16 | raw, |
17 | }, | 17 | }, |
18 | ids::{AstItemDef, LocationCtx, MacroCallLoc, MacroCallId, MacroDefId}, | 18 | ids::{AstItemDef, LocationCtx, MacroCallLoc, MacroCallId, MacroDefId, MacroFileKind}, |
19 | AstId, | 19 | AstId, |
20 | }; | 20 | }; |
21 | 21 | ||
@@ -371,7 +371,7 @@ where | |||
371 | self.macro_stack_monitor.increase(macro_def_id); | 371 | self.macro_stack_monitor.increase(macro_def_id); |
372 | 372 | ||
373 | if !self.macro_stack_monitor.is_poison(macro_def_id) { | 373 | 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); |
375 | let raw_items = self.db.raw_items(file_id); | 375 | let raw_items = self.db.raw_items(file_id); |
376 | ModCollector { def_collector: &mut *self, file_id, module_id, raw_items: &raw_items } | 376 | ModCollector { def_collector: &mut *self, file_id, module_id, raw_items: &raw_items } |
377 | .collect(raw_items.items()); | 377 | .collect(raw_items.items()); |
diff --git a/crates/ra_hir/src/nameres/raw.rs b/crates/ra_hir/src/nameres/raw.rs index 211e02068..bd32b264b 100644 --- a/crates/ra_hir/src/nameres/raw.rs +++ b/crates/ra_hir/src/nameres/raw.rs | |||
@@ -75,8 +75,11 @@ impl RawItems { | |||
75 | source_ast_id_map: db.ast_id_map(file_id.into()), | 75 | source_ast_id_map: db.ast_id_map(file_id.into()), |
76 | source_map: ImportSourceMap::default(), | 76 | source_map: ImportSourceMap::default(), |
77 | }; | 77 | }; |
78 | let source_file = db.hir_parse(file_id); | 78 | if let Some(node) = db.parse_or_expand(file_id) { |
79 | collector.process_module(None, &*source_file); | 79 | if let Some(source_file) = ast::SourceFile::cast(&node) { |
80 | collector.process_module(None, &*source_file); | ||
81 | } | ||
82 | } | ||
80 | (Arc::new(collector.raw_items), Arc::new(collector.source_map)) | 83 | (Arc::new(collector.raw_items), Arc::new(collector.source_map)) |
81 | } | 84 | } |
82 | 85 | ||
diff --git a/crates/ra_hir/src/source_id.rs b/crates/ra_hir/src/source_id.rs index 7a39be779..13f548eaf 100644 --- a/crates/ra_hir/src/source_id.rs +++ b/crates/ra_hir/src/source_id.rs | |||
@@ -81,15 +81,19 @@ pub struct ErasedFileAstId(RawId); | |||
81 | impl_arena_id!(ErasedFileAstId); | 81 | impl_arena_id!(ErasedFileAstId); |
82 | 82 | ||
83 | /// Maps items' `SyntaxNode`s to `ErasedFileAstId`s and back. | 83 | /// Maps items' `SyntaxNode`s to `ErasedFileAstId`s and back. |
84 | #[derive(Debug, PartialEq, Eq)] | 84 | #[derive(Debug, PartialEq, Eq, Default)] |
85 | pub struct AstIdMap { | 85 | pub struct AstIdMap { |
86 | arena: Arena<ErasedFileAstId, SyntaxNodePtr>, | 86 | arena: Arena<ErasedFileAstId, SyntaxNodePtr>, |
87 | } | 87 | } |
88 | 88 | ||
89 | impl AstIdMap { | 89 | impl AstIdMap { |
90 | pub(crate) fn ast_id_map_query(db: &impl DefDatabase, file_id: HirFileId) -> Arc<AstIdMap> { | 90 | pub(crate) fn ast_id_map_query(db: &impl DefDatabase, file_id: HirFileId) -> Arc<AstIdMap> { |
91 | let source_file = db.hir_parse(file_id); | 91 | let map = if let Some(node) = db.parse_or_expand(file_id) { |
92 | Arc::new(AstIdMap::from_source(source_file.syntax())) | 92 | AstIdMap::from_source(&*node) |
93 | } else { | ||
94 | AstIdMap::default() | ||
95 | }; | ||
96 | Arc::new(map) | ||
93 | } | 97 | } |
94 | 98 | ||
95 | pub(crate) fn file_item_query( | 99 | pub(crate) fn file_item_query( |
@@ -97,8 +101,8 @@ impl AstIdMap { | |||
97 | file_id: HirFileId, | 101 | file_id: HirFileId, |
98 | ast_id: ErasedFileAstId, | 102 | ast_id: ErasedFileAstId, |
99 | ) -> TreeArc<SyntaxNode> { | 103 | ) -> TreeArc<SyntaxNode> { |
100 | let source_file = db.hir_parse(file_id); | 104 | let node = db.parse_or_expand(file_id).unwrap(); |
101 | db.ast_id_map(file_id).arena[ast_id].to_node(source_file.syntax()).to_owned() | 105 | db.ast_id_map(file_id).arena[ast_id].to_node(&*node).to_owned() |
102 | } | 106 | } |
103 | 107 | ||
104 | pub(crate) fn ast_id<N: AstNode>(&self, item: &N) -> FileAstId<N> { | 108 | pub(crate) fn ast_id<N: AstNode>(&self, item: &N) -> FileAstId<N> { |
diff --git a/crates/ra_ide_api/src/change.rs b/crates/ra_ide_api/src/change.rs index dc6a433c4..2434f428f 100644 --- a/crates/ra_ide_api/src/change.rs +++ b/crates/ra_ide_api/src/change.rs | |||
@@ -222,7 +222,7 @@ impl RootDatabase { | |||
222 | 222 | ||
223 | self.query(ra_db::ParseQuery).sweep(sweep); | 223 | self.query(ra_db::ParseQuery).sweep(sweep); |
224 | 224 | ||
225 | self.query(hir::db::HirParseQuery).sweep(sweep); | 225 | self.query(hir::db::ParseOrExpandQuery).sweep(sweep); |
226 | self.query(hir::db::AstIdMapQuery).sweep(sweep); | 226 | self.query(hir::db::AstIdMapQuery).sweep(sweep); |
227 | self.query(hir::db::AstIdToNodeQuery).sweep(sweep); | 227 | self.query(hir::db::AstIdToNodeQuery).sweep(sweep); |
228 | 228 | ||