diff options
author | bors[bot] <bors[bot]@users.noreply.github.com> | 2019-05-04 16:54:04 +0100 |
---|---|---|
committer | bors[bot] <bors[bot]@users.noreply.github.com> | 2019-05-04 16:54:04 +0100 |
commit | e1ea2500fcc5e136fbe6a14c488f558e28519c45 (patch) | |
tree | 1cbcefd57c0dd75cd1c834e34dd00f9f89e9dd17 /crates/ra_hir | |
parent | fcdb387f0d7e76f325a858e4463efd5d7ed3efc3 (diff) | |
parent | bcf45371ff19882e67300cc483b481450ee129fb (diff) |
Merge #1238
1238: Macro queries r=edwin0cheng a=matklad
In https://github.com/rust-analyzer/rust-analyzer/pull/1231, I've added aggressive clean up of `ast_id_to_node` query.
The result of this query is a `SyntaxTree`, and we don't want to retain syntax trees in memory unless absolutely necessary.
Moreover, `SyntaxTree` has identity equality semantics, meaning that we'll get a diffferent syntax tree for a file after every reparse. That means that `ast_id_to_node` query should not genereally be used in HIR, unless it is behind some kind of salsa firewall, like the `raw` module of name resoulution.
However, that PR resulted in the abysmal performance: turns out we were using ast_id_to_node quite heavily in hir when expanding macros!
So this PR installs the more incremental-friendly query structure:
* converting source to token tree is now a query; changing source without affecting token-trees will now preserve macro expansions
* expand macro (tt -> tt) is now a query as well, so we cache macro expansions *before* parsing them into item lists or expressions, which is nice: we can cache expansion without knowing the calling context!
r? @edwin0cheng
Co-authored-by: Aleksey Kladov <[email protected]>
Diffstat (limited to 'crates/ra_hir')
-rw-r--r-- | crates/ra_hir/src/db.rs | 10 | ||||
-rw-r--r-- | crates/ra_hir/src/expr.rs | 42 | ||||
-rw-r--r-- | crates/ra_hir/src/ids.rs | 77 | ||||
-rw-r--r-- | crates/ra_hir/src/source_id.rs | 2 |
4 files changed, 63 insertions, 68 deletions
diff --git a/crates/ra_hir/src/db.rs b/crates/ra_hir/src/db.rs index 3ac3c79a3..398e00c42 100644 --- a/crates/ra_hir/src/db.rs +++ b/crates/ra_hir/src/db.rs | |||
@@ -42,7 +42,13 @@ pub trait DefDatabase: SourceDatabase { | |||
42 | #[salsa::invoke(crate::ids::macro_def_query)] | 42 | #[salsa::invoke(crate::ids::macro_def_query)] |
43 | fn macro_def(&self, macro_id: MacroDefId) -> Option<Arc<mbe::MacroRules>>; | 43 | fn macro_def(&self, macro_id: MacroDefId) -> Option<Arc<mbe::MacroRules>>; |
44 | 44 | ||
45 | #[salsa::invoke(HirFileId::hir_parse_query)] | 45 | #[salsa::invoke(crate::ids::macro_arg_query)] |
46 | fn macro_arg(&self, macro_call: ids::MacroCallId) -> Option<Arc<tt::Subtree>>; | ||
47 | |||
48 | #[salsa::invoke(crate::ids::macro_expand_query)] | ||
49 | fn macro_expand(&self, macro_call: ids::MacroCallId) -> Result<Arc<tt::Subtree>, String>; | ||
50 | |||
51 | #[salsa::invoke(crate::ids::HirFileId::hir_parse_query)] | ||
46 | fn hir_parse(&self, file_id: HirFileId) -> TreeArc<SourceFile>; | 52 | fn hir_parse(&self, file_id: HirFileId) -> TreeArc<SourceFile>; |
47 | 53 | ||
48 | #[salsa::invoke(crate::adt::StructData::struct_data_query)] | 54 | #[salsa::invoke(crate::adt::StructData::struct_data_query)] |
@@ -60,7 +66,7 @@ pub trait DefDatabase: SourceDatabase { | |||
60 | #[salsa::invoke(crate::source_id::AstIdMap::ast_id_map_query)] | 66 | #[salsa::invoke(crate::source_id::AstIdMap::ast_id_map_query)] |
61 | fn ast_id_map(&self, file_id: HirFileId) -> Arc<AstIdMap>; | 67 | fn ast_id_map(&self, file_id: HirFileId) -> Arc<AstIdMap>; |
62 | 68 | ||
63 | #[salsa::invoke(crate::source_id::AstIdMap::ast_id_to_node_query)] | 69 | #[salsa::invoke(crate::source_id::AstIdMap::file_item_query)] |
64 | fn ast_id_to_node(&self, file_id: HirFileId, ast_id: ErasedFileAstId) -> TreeArc<SyntaxNode>; | 70 | fn ast_id_to_node(&self, file_id: HirFileId, ast_id: ErasedFileAstId) -> TreeArc<SyntaxNode>; |
65 | 71 | ||
66 | #[salsa::invoke(RawItems::raw_items_query)] | 72 | #[salsa::invoke(RawItems::raw_items_query)] |
diff --git a/crates/ra_hir/src/expr.rs b/crates/ra_hir/src/expr.rs index cdadf3ba6..692da2895 100644 --- a/crates/ra_hir/src/expr.rs +++ b/crates/ra_hir/src/expr.rs | |||
@@ -5,14 +5,13 @@ use rustc_hash::FxHashMap; | |||
5 | 5 | ||
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,TreeArc, | 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, | 13 | Path, Name, HirDatabase, Resolver,DefWithBody, Either, HirFileId, |
14 | name::AsName, | 14 | name::AsName, |
15 | ids::{MacroCallId}, | ||
16 | type_ref::{Mutability, TypeRef}, | 15 | type_ref::{Mutability, TypeRef}, |
17 | }; | 16 | }; |
18 | use crate::{path::GenericArgs, ty::primitive::{IntTy, UncertainIntTy, FloatTy, UncertainFloatTy}}; | 17 | use crate::{path::GenericArgs, ty::primitive::{IntTy, UncertainIntTy, FloatTy, UncertainFloatTy}}; |
@@ -826,21 +825,20 @@ where | |||
826 | .with_file_id(self.current_file_id); | 825 | .with_file_id(self.current_file_id); |
827 | 826 | ||
828 | if let Some(call_id) = self.resolver.resolve_macro_call(self.db, path, ast_id) { | 827 | if let Some(call_id) = self.resolver.resolve_macro_call(self.db, path, ast_id) { |
829 | if let Some(expr) = expand_macro_to_expr(self.db, call_id, e.token_tree()) { | 828 | if let Some(tt) = self.db.macro_expand(call_id).ok() { |
830 | log::debug!("macro expansion {}", expr.syntax().debug_dump()); | 829 | if let Some(expr) = mbe::token_tree_to_expr(&tt).ok() { |
831 | let old_file_id = | 830 | log::debug!("macro expansion {}", expr.syntax().debug_dump()); |
832 | std::mem::replace(&mut self.current_file_id, call_id.into()); | 831 | let old_file_id = |
833 | let id = self.collect_expr(&expr); | 832 | std::mem::replace(&mut self.current_file_id, call_id.into()); |
834 | self.current_file_id = old_file_id; | 833 | let id = self.collect_expr(&expr); |
835 | id | 834 | self.current_file_id = old_file_id; |
836 | } else { | 835 | return id; |
837 | // FIXME: Instead of just dropping the error from expansion | 836 | } |
838 | // report it | ||
839 | self.alloc_expr(Expr::Missing, syntax_ptr) | ||
840 | } | 837 | } |
841 | } else { | ||
842 | self.alloc_expr(Expr::Missing, syntax_ptr) | ||
843 | } | 838 | } |
839 | // FIXME: Instead of just dropping the error from expansion | ||
840 | // report it | ||
841 | self.alloc_expr(Expr::Missing, syntax_ptr) | ||
844 | } | 842 | } |
845 | } | 843 | } |
846 | } | 844 | } |
@@ -999,20 +997,6 @@ where | |||
999 | } | 997 | } |
1000 | } | 998 | } |
1001 | 999 | ||
1002 | fn expand_macro_to_expr( | ||
1003 | db: &impl HirDatabase, | ||
1004 | macro_call: MacroCallId, | ||
1005 | args: Option<&ast::TokenTree>, | ||
1006 | ) -> Option<TreeArc<ast::Expr>> { | ||
1007 | let rules = db.macro_def(macro_call.loc(db).def)?; | ||
1008 | |||
1009 | let args = mbe::ast_to_token_tree(args?)?.0; | ||
1010 | |||
1011 | let expanded = rules.expand(&args).ok()?; | ||
1012 | |||
1013 | mbe::token_tree_to_expr(&expanded).ok() | ||
1014 | } | ||
1015 | |||
1016 | pub(crate) fn body_with_source_map_query( | 1000 | pub(crate) fn body_with_source_map_query( |
1017 | db: &impl HirDatabase, | 1001 | db: &impl HirDatabase, |
1018 | def: DefWithBody, | 1002 | def: DefWithBody, |
diff --git a/crates/ra_hir/src/ids.rs b/crates/ra_hir/src/ids.rs index b0e9b1f9a..4102951c9 100644 --- a/crates/ra_hir/src/ids.rs +++ b/crates/ra_hir/src/ids.rs | |||
@@ -63,47 +63,27 @@ impl HirFileId { | |||
63 | match file_id.0 { | 63 | match file_id.0 { |
64 | HirFileIdRepr::File(file_id) => db.parse(file_id), | 64 | HirFileIdRepr::File(file_id) => db.parse(file_id), |
65 | HirFileIdRepr::Macro(macro_call_id) => { | 65 | HirFileIdRepr::Macro(macro_call_id) => { |
66 | parse_macro(db, macro_call_id).unwrap_or_else(|err| { | 66 | match db.macro_expand(macro_call_id) { |
67 | // Note: | 67 | Ok(tt) => mbe::token_tree_to_ast_item_list(&tt), |
68 | // The final goal we would like to make all parse_macro success, | 68 | Err(err) => { |
69 | // such that the following log will not call anyway. | 69 | // Note: |
70 | log::warn!( | 70 | // The final goal we would like to make all parse_macro success, |
71 | "fail on macro_parse: (reason: {}) {}", | 71 | // such that the following log will not call anyway. |
72 | err, | 72 | log::warn!( |
73 | macro_call_id.debug_dump(db) | 73 | "fail on macro_parse: (reason: {}) {}", |
74 | ); | 74 | err, |
75 | 75 | macro_call_id.debug_dump(db) | |
76 | // returning an empty string looks fishy... | 76 | ); |
77 | SourceFile::parse("") | 77 | |
78 | }) | 78 | // returning an empty string looks fishy... |
79 | SourceFile::parse("") | ||
80 | } | ||
81 | } | ||
79 | } | 82 | } |
80 | } | 83 | } |
81 | } | 84 | } |
82 | } | 85 | } |
83 | 86 | ||
84 | fn parse_macro( | ||
85 | db: &impl DefDatabase, | ||
86 | macro_call_id: MacroCallId, | ||
87 | ) -> Result<TreeArc<SourceFile>, String> { | ||
88 | let loc = macro_call_id.loc(db); | ||
89 | let macro_call = loc.ast_id.to_node(db); | ||
90 | let (macro_arg, _) = macro_call | ||
91 | .token_tree() | ||
92 | .and_then(mbe::ast_to_token_tree) | ||
93 | .ok_or("Fail to args in to tt::TokenTree")?; | ||
94 | |||
95 | let macro_rules = db.macro_def(loc.def).ok_or("Fail to find macro definition")?; | ||
96 | let tt = macro_rules.expand(¯o_arg).map_err(|err| format!("{:?}", err))?; | ||
97 | |||
98 | // Set a hard limit for the expanded tt | ||
99 | let count = tt.count(); | ||
100 | if count > 65536 { | ||
101 | return Err(format!("Total tokens count exceed limit : count = {}", count)); | ||
102 | } | ||
103 | |||
104 | Ok(mbe::token_tree_to_ast_item_list(&tt)) | ||
105 | } | ||
106 | |||
107 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | 87 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] |
108 | enum HirFileIdRepr { | 88 | enum HirFileIdRepr { |
109 | File(FileId), | 89 | File(FileId), |
@@ -139,6 +119,31 @@ pub(crate) fn macro_def_query(db: &impl DefDatabase, id: MacroDefId) -> Option<A | |||
139 | Some(Arc::new(rules)) | 119 | Some(Arc::new(rules)) |
140 | } | 120 | } |
141 | 121 | ||
122 | pub(crate) fn macro_arg_query(db: &impl DefDatabase, id: MacroCallId) -> Option<Arc<tt::Subtree>> { | ||
123 | let loc = id.loc(db); | ||
124 | let macro_call = loc.ast_id.to_node(db); | ||
125 | let arg = macro_call.token_tree()?; | ||
126 | let (tt, _) = mbe::ast_to_token_tree(arg)?; | ||
127 | Some(Arc::new(tt)) | ||
128 | } | ||
129 | |||
130 | pub(crate) fn macro_expand_query( | ||
131 | db: &impl DefDatabase, | ||
132 | id: MacroCallId, | ||
133 | ) -> Result<Arc<tt::Subtree>, String> { | ||
134 | let loc = id.loc(db); | ||
135 | let macro_arg = db.macro_arg(id).ok_or("Fail to args in to tt::TokenTree")?; | ||
136 | |||
137 | let macro_rules = db.macro_def(loc.def).ok_or("Fail to find macro definition")?; | ||
138 | let tt = macro_rules.expand(¯o_arg).map_err(|err| format!("{:?}", err))?; | ||
139 | // Set a hard limit for the expanded tt | ||
140 | let count = tt.count(); | ||
141 | if count > 65536 { | ||
142 | return Err(format!("Total tokens count exceed limit : count = {}", count)); | ||
143 | } | ||
144 | Ok(Arc::new(tt)) | ||
145 | } | ||
146 | |||
142 | macro_rules! impl_intern_key { | 147 | macro_rules! impl_intern_key { |
143 | ($name:ident) => { | 148 | ($name:ident) => { |
144 | impl salsa::InternKey for $name { | 149 | impl salsa::InternKey for $name { |
diff --git a/crates/ra_hir/src/source_id.rs b/crates/ra_hir/src/source_id.rs index a2bc9a799..0a8fb6d32 100644 --- a/crates/ra_hir/src/source_id.rs +++ b/crates/ra_hir/src/source_id.rs | |||
@@ -92,7 +92,7 @@ impl AstIdMap { | |||
92 | Arc::new(AstIdMap::from_source_file(&source_file)) | 92 | Arc::new(AstIdMap::from_source_file(&source_file)) |
93 | } | 93 | } |
94 | 94 | ||
95 | pub(crate) fn ast_id_to_node_query( | 95 | pub(crate) fn file_item_query( |
96 | db: &impl DefDatabase, | 96 | db: &impl DefDatabase, |
97 | file_id: HirFileId, | 97 | file_id: HirFileId, |
98 | ast_id: ErasedFileAstId, | 98 | ast_id: ErasedFileAstId, |