aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir_expand/src
diff options
context:
space:
mode:
authorFlorian Diebold <[email protected]>2020-03-13 12:03:31 +0000
committerFlorian Diebold <[email protected]>2020-03-16 17:38:19 +0000
commitb973158aeb337041d4e1434cf5d8c609a0b02bef (patch)
treee3da1bb7a3c2d89623382865edc7ef64c039496d /crates/ra_hir_expand/src
parentd3773ec1522681de117d354f0c82e753c68c6d0b (diff)
Make MBE expansion more resilient (WIP)
Diffstat (limited to 'crates/ra_hir_expand/src')
-rw-r--r--crates/ra_hir_expand/src/db.rs90
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(
153pub(crate) fn macro_expand( 154pub(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, &macro_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, &macro_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
204pub(crate) fn parse_or_expand(db: &dyn AstDatabase, file_id: HirFileId) -> Option<SyntaxNode> { 213pub(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