diff options
author | Florian Diebold <[email protected]> | 2020-03-13 12:03:31 +0000 |
---|---|---|
committer | Florian Diebold <[email protected]> | 2020-03-16 17:38:19 +0000 |
commit | b973158aeb337041d4e1434cf5d8c609a0b02bef (patch) | |
tree | e3da1bb7a3c2d89623382865edc7ef64c039496d /crates/ra_hir_expand | |
parent | d3773ec1522681de117d354f0c82e753c68c6d0b (diff) |
Make MBE expansion more resilient (WIP)
Diffstat (limited to 'crates/ra_hir_expand')
-rw-r--r-- | crates/ra_hir_expand/src/db.rs | 90 |
1 files changed, 49 insertions, 41 deletions
diff --git a/crates/ra_hir_expand/src/db.rs b/crates/ra_hir_expand/src/db.rs index c3e1c68b7..e7b81a1e6 100644 --- a/crates/ra_hir_expand/src/db.rs +++ b/crates/ra_hir_expand/src/db.rs | |||
@@ -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).map_or_else(|e| (tt::Subtree::default(), Some(e)), |r| (r, None)), |
35 | TokenExpander::BuiltinDerive(it) => it.expand(db, id, tt).map_or_else(|e| (tt::Subtree::default(), Some(e)), |r| (r, None)), | ||
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,39 @@ 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 (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 |
205 | eprintln!("expansion size: {}", tt.count()); | ||
197 | let count = tt.count(); | 206 | let count = tt.count(); |
198 | if count > 65536 { | 207 | if count > 65536 { |
199 | return Err(format!("Total tokens count exceed limit : count = {}", count)); | 208 | return (None, Some(format!("Total tokens count exceed limit : count = {}", count))); |
200 | } | 209 | } |
201 | Ok(Arc::new(tt)) | 210 | (Some(Arc::new(tt)), err.map(|e| format!("{:?}", e))) |
202 | } | 211 | } |
203 | 212 | ||
204 | pub(crate) fn parse_or_expand(db: &dyn AstDatabase, file_id: HirFileId) -> Option<SyntaxNode> { | 213 | pub(crate) fn parse_or_expand(db: &dyn AstDatabase, file_id: HirFileId) -> Option<SyntaxNode> { |
@@ -225,42 +234,41 @@ pub fn parse_macro_with_arg( | |||
225 | let _p = profile("parse_macro_query"); | 234 | let _p = profile("parse_macro_query"); |
226 | 235 | ||
227 | let macro_call_id = macro_file.macro_call_id; | 236 | let macro_call_id = macro_file.macro_call_id; |
228 | let expansion = if let Some(arg) = arg { | 237 | let (tt, err) = if let Some(arg) = arg { |
229 | macro_expand_with_arg(db, macro_call_id, Some(arg)) | 238 | macro_expand_with_arg(db, macro_call_id, Some(arg)) |
230 | } else { | 239 | } else { |
231 | db.macro_expand(macro_call_id) | 240 | db.macro_expand(macro_call_id) |
232 | }; | 241 | }; |
233 | let tt = expansion | 242 | if let Some(err) = err { |
234 | .map_err(|err| { | 243 | // Note: |
235 | // Note: | 244 | // 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, | 245 | // such that the following log will not call anyway. |
237 | // such that the following log will not call anyway. | 246 | match macro_call_id { |
238 | match macro_call_id { | 247 | MacroCallId::LazyMacro(id) => { |
239 | MacroCallId::LazyMacro(id) => { | 248 | let loc: MacroCallLoc = db.lookup_intern_macro(id); |
240 | let loc: MacroCallLoc = db.lookup_intern_macro(id); | 249 | let node = loc.kind.node(db); |
241 | let node = loc.kind.node(db); | 250 | |
242 | 251 | // collect parent information for warning log | |
243 | // collect parent information for warning log | 252 | 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| { | 253 | it.file_id.call_node(db) |
245 | it.file_id.call_node(db) | 254 | }) |
246 | }) | ||
247 | .map(|n| format!("{:#}", n.value)) | 255 | .map(|n| format!("{:#}", n.value)) |
248 | .collect::<Vec<_>>() | 256 | .collect::<Vec<_>>() |
249 | .join("\n"); | 257 | .join("\n"); |
250 | 258 | ||
251 | log::warn!( | 259 | log::warn!( |
252 | "fail on macro_parse: (reason: {} macro_call: {:#}) parents: {}", | 260 | "fail on macro_parse: (reason: {} macro_call: {:#}) parents: {}", |
253 | err, | 261 | err, |
254 | node.value, | 262 | node.value, |
255 | parents | 263 | parents |
256 | ); | 264 | ); |
257 | } | 265 | } |
258 | _ => { | 266 | _ => { |
259 | log::warn!("fail on macro_parse: (reason: {})", err); | 267 | log::warn!("fail on macro_parse: (reason: {})", err); |
260 | } | ||
261 | } | 268 | } |
262 | }) | 269 | } |
263 | .ok()?; | 270 | }; |
271 | let tt = tt?; | ||
264 | 272 | ||
265 | let fragment_kind = to_fragment_kind(db, macro_call_id); | 273 | let fragment_kind = to_fragment_kind(db, macro_call_id); |
266 | 274 | ||