aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir_def/src/body.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_hir_def/src/body.rs')
-rw-r--r--crates/ra_hir_def/src/body.rs65
1 files changed, 59 insertions, 6 deletions
diff --git a/crates/ra_hir_def/src/body.rs b/crates/ra_hir_def/src/body.rs
index 4f2350915..2fe04db2b 100644
--- a/crates/ra_hir_def/src/body.rs
+++ b/crates/ra_hir_def/src/body.rs
@@ -14,6 +14,7 @@ use ra_db::CrateId;
14use ra_prof::profile; 14use ra_prof::profile;
15use ra_syntax::{ast, AstNode, AstPtr}; 15use ra_syntax::{ast, AstNode, AstPtr};
16use rustc_hash::FxHashMap; 16use rustc_hash::FxHashMap;
17use test_utils::mark;
17 18
18pub(crate) use lower::LowerCtx; 19pub(crate) use lower::LowerCtx;
19 20
@@ -42,9 +43,15 @@ pub(crate) struct Expander {
42 current_file_id: HirFileId, 43 current_file_id: HirFileId,
43 ast_id_map: Arc<AstIdMap>, 44 ast_id_map: Arc<AstIdMap>,
44 module: ModuleId, 45 module: ModuleId,
45 recursive_limit: usize, 46 recursion_limit: usize,
46} 47}
47 48
49#[cfg(test)]
50const EXPANSION_RECURSION_LIMIT: usize = 32;
51
52#[cfg(not(test))]
53const EXPANSION_RECURSION_LIMIT: usize = 128;
54
48impl CfgExpander { 55impl CfgExpander {
49 pub(crate) fn new( 56 pub(crate) fn new(
50 db: &dyn DefDatabase, 57 db: &dyn DefDatabase,
@@ -81,7 +88,7 @@ impl Expander {
81 current_file_id, 88 current_file_id,
82 ast_id_map, 89 ast_id_map,
83 module, 90 module,
84 recursive_limit: 0, 91 recursion_limit: 0,
85 } 92 }
86 } 93 }
87 94
@@ -91,7 +98,9 @@ impl Expander {
91 local_scope: Option<&ItemScope>, 98 local_scope: Option<&ItemScope>,
92 macro_call: ast::MacroCall, 99 macro_call: ast::MacroCall,
93 ) -> Option<(Mark, T)> { 100 ) -> Option<(Mark, T)> {
94 if self.recursive_limit > 1024 { 101 self.recursion_limit += 1;
102 if self.recursion_limit > EXPANSION_RECURSION_LIMIT {
103 mark::hit!(your_stack_belongs_to_me);
95 return None; 104 return None;
96 } 105 }
97 106
@@ -118,8 +127,6 @@ impl Expander {
118 self.cfg_expander.hygiene = Hygiene::new(db.upcast(), file_id); 127 self.cfg_expander.hygiene = Hygiene::new(db.upcast(), file_id);
119 self.current_file_id = file_id; 128 self.current_file_id = file_id;
120 self.ast_id_map = db.ast_id_map(file_id); 129 self.ast_id_map = db.ast_id_map(file_id);
121 self.recursive_limit += 1;
122
123 return Some((mark, expr)); 130 return Some((mark, expr));
124 } 131 }
125 } 132 }
@@ -134,7 +141,7 @@ impl Expander {
134 self.cfg_expander.hygiene = Hygiene::new(db.upcast(), mark.file_id); 141 self.cfg_expander.hygiene = Hygiene::new(db.upcast(), mark.file_id);
135 self.current_file_id = mark.file_id; 142 self.current_file_id = mark.file_id;
136 self.ast_id_map = mem::take(&mut mark.ast_id_map); 143 self.ast_id_map = mem::take(&mut mark.ast_id_map);
137 self.recursive_limit -= 1; 144 self.recursion_limit -= 1;
138 mark.bomb.defuse(); 145 mark.bomb.defuse();
139 } 146 }
140 147
@@ -302,7 +309,53 @@ impl BodySourceMap {
302 self.pat_map.get(&src).cloned() 309 self.pat_map.get(&src).cloned()
303 } 310 }
304 311
312 pub fn node_self_param(&self, node: InFile<&ast::SelfParam>) -> Option<PatId> {
313 let src = node.map(|it| Either::Right(AstPtr::new(it)));
314 self.pat_map.get(&src).cloned()
315 }
316
305 pub fn field_syntax(&self, expr: ExprId, field: usize) -> InFile<AstPtr<ast::RecordField>> { 317 pub fn field_syntax(&self, expr: ExprId, field: usize) -> InFile<AstPtr<ast::RecordField>> {
306 self.field_map[&(expr, field)].clone() 318 self.field_map[&(expr, field)].clone()
307 } 319 }
308} 320}
321
322#[cfg(test)]
323mod tests {
324 use ra_db::{fixture::WithFixture, SourceDatabase};
325 use test_utils::mark;
326
327 use crate::ModuleDefId;
328
329 use super::*;
330
331 fn lower(ra_fixture: &str) -> Arc<Body> {
332 let (db, file_id) = crate::test_db::TestDB::with_single_file(ra_fixture);
333
334 let krate = db.crate_graph().iter().next().unwrap();
335 let def_map = db.crate_def_map(krate);
336 let module = def_map.modules_for_file(file_id).next().unwrap();
337 let module = &def_map[module];
338 let fn_def = match module.scope.declarations().next().unwrap() {
339 ModuleDefId::FunctionId(it) => it,
340 _ => panic!(),
341 };
342
343 db.body(fn_def.into())
344 }
345
346 #[test]
347 fn your_stack_belongs_to_me() {
348 mark::check!(your_stack_belongs_to_me);
349 lower(
350 "
351macro_rules! n_nuple {
352 ($e:tt) => ();
353 ($($rest:tt)*) => {{
354 (n_nuple!($($rest)*)None,)
355 }};
356}
357fn main() { n_nuple!(1,2,3); }
358",
359 );
360 }
361}