diff options
Diffstat (limited to 'crates/ra_hir_expand')
-rw-r--r-- | crates/ra_hir_expand/src/db.rs | 99 |
1 files changed, 53 insertions, 46 deletions
diff --git a/crates/ra_hir_expand/src/db.rs b/crates/ra_hir_expand/src/db.rs index c3e1c68b7..d171d2dfd 100644 --- a/crates/ra_hir_expand/src/db.rs +++ b/crates/ra_hir_expand/src/db.rs | |||
@@ -2,7 +2,7 @@ | |||
2 | 2 | ||
3 | use std::sync::Arc; | 3 | use std::sync::Arc; |
4 | 4 | ||
5 | use mbe::MacroRules; | 5 | use mbe::{ExpandResult, MacroRules}; |
6 | use ra_db::{salsa, SourceDatabase}; | 6 | use ra_db::{salsa, SourceDatabase}; |
7 | use ra_parser::FragmentKind; | 7 | use ra_parser::FragmentKind; |
8 | use ra_prof::profile; | 8 | use ra_prof::profile; |
@@ -27,11 +27,12 @@ impl TokenExpander { | |||
27 | db: &dyn AstDatabase, | 27 | db: &dyn AstDatabase, |
28 | id: LazyMacroId, | 28 | id: LazyMacroId, |
29 | tt: &tt::Subtree, | 29 | tt: &tt::Subtree, |
30 | ) -> Result<tt::Subtree, mbe::ExpandError> { | 30 | ) -> mbe::ExpandResult<tt::Subtree> { |
31 | match self { | 31 | match self { |
32 | TokenExpander::MacroRules(it) => it.expand(tt), | 32 | TokenExpander::MacroRules(it) => it.expand(tt), |
33 | TokenExpander::Builtin(it) => it.expand(db, id, tt), | 33 | // FIXME switch these to ExpandResult as well |
34 | TokenExpander::BuiltinDerive(it) => it.expand(db, id, tt), | 34 | TokenExpander::Builtin(it) => it.expand(db, id, tt).into(), |
35 | TokenExpander::BuiltinDerive(it) => it.expand(db, id, tt).into(), | ||
35 | } | 36 | } |
36 | } | 37 | } |
37 | 38 | ||
@@ -66,7 +67,7 @@ pub trait AstDatabase: SourceDatabase { | |||
66 | fn macro_def(&self, id: MacroDefId) -> Option<Arc<(TokenExpander, mbe::TokenMap)>>; | 67 | fn macro_def(&self, id: MacroDefId) -> Option<Arc<(TokenExpander, mbe::TokenMap)>>; |
67 | fn parse_macro(&self, macro_file: MacroFile) | 68 | fn parse_macro(&self, macro_file: MacroFile) |
68 | -> Option<(Parse<SyntaxNode>, Arc<mbe::TokenMap>)>; | 69 | -> Option<(Parse<SyntaxNode>, Arc<mbe::TokenMap>)>; |
69 | fn macro_expand(&self, macro_call: MacroCallId) -> Result<Arc<tt::Subtree>, String>; | 70 | fn macro_expand(&self, macro_call: MacroCallId) -> (Option<Arc<tt::Subtree>>, Option<String>); |
70 | 71 | ||
71 | #[salsa::interned] | 72 | #[salsa::interned] |
72 | fn intern_eager_expansion(&self, eager: EagerCallLoc) -> EagerMacroId; | 73 | fn intern_eager_expansion(&self, eager: EagerCallLoc) -> EagerMacroId; |
@@ -153,7 +154,7 @@ pub(crate) fn macro_arg( | |||
153 | pub(crate) fn macro_expand( | 154 | pub(crate) fn macro_expand( |
154 | db: &dyn AstDatabase, | 155 | db: &dyn AstDatabase, |
155 | id: MacroCallId, | 156 | id: MacroCallId, |
156 | ) -> Result<Arc<tt::Subtree>, String> { | 157 | ) -> (Option<Arc<tt::Subtree>>, Option<String>) { |
157 | macro_expand_with_arg(db, id, None) | 158 | macro_expand_with_arg(db, id, None) |
158 | } | 159 | } |
159 | 160 | ||
@@ -174,31 +175,38 @@ fn macro_expand_with_arg( | |||
174 | db: &dyn AstDatabase, | 175 | db: &dyn AstDatabase, |
175 | id: MacroCallId, | 176 | id: MacroCallId, |
176 | arg: Option<Arc<(tt::Subtree, mbe::TokenMap)>>, | 177 | arg: Option<Arc<(tt::Subtree, mbe::TokenMap)>>, |
177 | ) -> Result<Arc<tt::Subtree>, String> { | 178 | ) -> (Option<Arc<tt::Subtree>>, Option<String>) { |
178 | let lazy_id = match id { | 179 | let lazy_id = match id { |
179 | MacroCallId::LazyMacro(id) => id, | 180 | MacroCallId::LazyMacro(id) => id, |
180 | MacroCallId::EagerMacro(id) => { | 181 | MacroCallId::EagerMacro(id) => { |
181 | if arg.is_some() { | 182 | if arg.is_some() { |
182 | return Err( | 183 | return ( |
183 | "hypothetical macro expansion not implemented for eager macro".to_owned() | 184 | None, |
185 | Some("hypothetical macro expansion not implemented for eager macro".to_owned()), | ||
184 | ); | 186 | ); |
185 | } else { | 187 | } else { |
186 | return Ok(db.lookup_intern_eager_expansion(id).subtree); | 188 | return (Some(db.lookup_intern_eager_expansion(id).subtree), None); |
187 | } | 189 | } |
188 | } | 190 | } |
189 | }; | 191 | }; |
190 | 192 | ||
191 | let loc = db.lookup_intern_macro(lazy_id); | 193 | let loc = db.lookup_intern_macro(lazy_id); |
192 | let macro_arg = arg.or_else(|| db.macro_arg(id)).ok_or("Fail to args in to tt::TokenTree")?; | 194 | let macro_arg = match arg.or_else(|| db.macro_arg(id)) { |
195 | Some(it) => it, | ||
196 | None => return (None, Some("Fail to args in to tt::TokenTree".into())), | ||
197 | }; | ||
193 | 198 | ||
194 | let macro_rules = db.macro_def(loc.def).ok_or("Fail to find macro definition")?; | 199 | let macro_rules = match db.macro_def(loc.def) { |
195 | let tt = macro_rules.0.expand(db, lazy_id, ¯o_arg.0).map_err(|err| format!("{:?}", err))?; | 200 | Some(it) => it, |
201 | None => return (None, Some("Fail to find macro definition".into())), | ||
202 | }; | ||
203 | let ExpandResult(tt, err) = macro_rules.0.expand(db, lazy_id, ¯o_arg.0); | ||
196 | // Set a hard limit for the expanded tt | 204 | // Set a hard limit for the expanded tt |
197 | let count = tt.count(); | 205 | let count = tt.count(); |
198 | if count > 65536 { | 206 | if count > 65536 { |
199 | return Err(format!("Total tokens count exceed limit : count = {}", count)); | 207 | return (None, Some(format!("Total tokens count exceed limit : count = {}", count))); |
200 | } | 208 | } |
201 | Ok(Arc::new(tt)) | 209 | (Some(Arc::new(tt)), err.map(|e| format!("{:?}", e))) |
202 | } | 210 | } |
203 | 211 | ||
204 | pub(crate) fn parse_or_expand(db: &dyn AstDatabase, file_id: HirFileId) -> Option<SyntaxNode> { | 212 | pub(crate) fn parse_or_expand(db: &dyn AstDatabase, file_id: HirFileId) -> Option<SyntaxNode> { |
@@ -225,42 +233,41 @@ pub fn parse_macro_with_arg( | |||
225 | let _p = profile("parse_macro_query"); | 233 | let _p = profile("parse_macro_query"); |
226 | 234 | ||
227 | let macro_call_id = macro_file.macro_call_id; | 235 | let macro_call_id = macro_file.macro_call_id; |
228 | let expansion = if let Some(arg) = arg { | 236 | let (tt, err) = if let Some(arg) = arg { |
229 | macro_expand_with_arg(db, macro_call_id, Some(arg)) | 237 | macro_expand_with_arg(db, macro_call_id, Some(arg)) |
230 | } else { | 238 | } else { |
231 | db.macro_expand(macro_call_id) | 239 | db.macro_expand(macro_call_id) |
232 | }; | 240 | }; |
233 | let tt = expansion | 241 | if let Some(err) = err { |
234 | .map_err(|err| { | 242 | // Note: |
235 | // Note: | 243 | // The final goal we would like to make all parse_macro success, |
236 | // The final goal we would like to make all parse_macro success, | 244 | // such that the following log will not call anyway. |
237 | // such that the following log will not call anyway. | 245 | match macro_call_id { |
238 | match macro_call_id { | 246 | MacroCallId::LazyMacro(id) => { |
239 | MacroCallId::LazyMacro(id) => { | 247 | let loc: MacroCallLoc = db.lookup_intern_macro(id); |
240 | let loc: MacroCallLoc = db.lookup_intern_macro(id); | 248 | let node = loc.kind.node(db); |
241 | let node = loc.kind.node(db); | 249 | |
242 | 250 | // collect parent information for warning log | |
243 | // collect parent information for warning log | 251 | let parents = std::iter::successors(loc.kind.file_id().call_node(db), |it| { |
244 | let parents = std::iter::successors(loc.kind.file_id().call_node(db), |it| { | 252 | it.file_id.call_node(db) |
245 | it.file_id.call_node(db) | 253 | }) |
246 | }) | 254 | .map(|n| format!("{:#}", n.value)) |
247 | .map(|n| format!("{:#}", n.value)) | 255 | .collect::<Vec<_>>() |
248 | .collect::<Vec<_>>() | 256 | .join("\n"); |
249 | .join("\n"); | 257 | |
250 | 258 | log::warn!( | |
251 | log::warn!( | 259 | "fail on macro_parse: (reason: {} macro_call: {:#}) parents: {}", |
252 | "fail on macro_parse: (reason: {} macro_call: {:#}) parents: {}", | 260 | err, |
253 | err, | 261 | node.value, |
254 | node.value, | 262 | parents |
255 | parents | 263 | ); |
256 | ); | 264 | } |
257 | } | 265 | _ => { |
258 | _ => { | 266 | log::warn!("fail on macro_parse: (reason: {})", err); |
259 | log::warn!("fail on macro_parse: (reason: {})", err); | ||
260 | } | ||
261 | } | 267 | } |
262 | }) | 268 | } |
263 | .ok()?; | 269 | }; |
270 | let tt = tt?; | ||
264 | 271 | ||
265 | let fragment_kind = to_fragment_kind(db, macro_call_id); | 272 | let fragment_kind = to_fragment_kind(db, macro_call_id); |
266 | 273 | ||