aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir_def
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_hir_def')
-rw-r--r--crates/ra_hir_def/src/body.rs136
-rw-r--r--crates/ra_hir_def/src/body/lower.rs90
-rw-r--r--crates/ra_hir_def/src/body/scope.rs165
-rw-r--r--crates/ra_hir_def/src/db.rs12
-rw-r--r--crates/ra_hir_def/src/lib.rs10
5 files changed, 328 insertions, 85 deletions
diff --git a/crates/ra_hir_def/src/body.rs b/crates/ra_hir_def/src/body.rs
index ac8f8261b..85dc4feb0 100644
--- a/crates/ra_hir_def/src/body.rs
+++ b/crates/ra_hir_def/src/body.rs
@@ -1,11 +1,15 @@
1//! FIXME: write short doc here 1//! FIXME: write short doc here
2mod lower; 2mod lower;
3pub mod scope;
3 4
4use std::{ops::Index, sync::Arc}; 5use std::{ops::Index, sync::Arc};
5 6
6use hir_expand::{either::Either, HirFileId, MacroDefId, Source}; 7use hir_expand::{
8 either::Either, hygiene::Hygiene, AstId, HirFileId, MacroCallLoc, MacroDefId, MacroFileKind,
9 Source,
10};
7use ra_arena::{map::ArenaMap, Arena}; 11use ra_arena::{map::ArenaMap, Arena};
8use ra_syntax::{ast, AstPtr}; 12use ra_syntax::{ast, AstNode, AstPtr};
9use rustc_hash::FxHashMap; 13use rustc_hash::FxHashMap;
10 14
11use crate::{ 15use crate::{
@@ -13,28 +17,87 @@ use crate::{
13 expr::{Expr, ExprId, Pat, PatId}, 17 expr::{Expr, ExprId, Pat, PatId},
14 nameres::CrateDefMap, 18 nameres::CrateDefMap,
15 path::Path, 19 path::Path,
16 ModuleId, 20 AstItemDef, DefWithBodyId, ModuleId,
17}; 21};
18 22
19pub struct MacroResolver { 23pub struct Expander {
20 crate_def_map: Arc<CrateDefMap>, 24 crate_def_map: Arc<CrateDefMap>,
25 current_file_id: HirFileId,
26 hygiene: Hygiene,
21 module: ModuleId, 27 module: ModuleId,
22} 28}
23 29
24impl MacroResolver { 30impl Expander {
25 pub fn new(db: &impl DefDatabase2, module: ModuleId) -> MacroResolver { 31 pub fn new(db: &impl DefDatabase2, current_file_id: HirFileId, module: ModuleId) -> Expander {
26 MacroResolver { crate_def_map: db.crate_def_map(module.krate), module } 32 let crate_def_map = db.crate_def_map(module.krate);
33 let hygiene = Hygiene::new(db, current_file_id);
34 Expander { crate_def_map, current_file_id, hygiene, module }
27 } 35 }
28 36
29 pub(crate) fn resolve_path_as_macro( 37 fn enter_expand(
30 &self, 38 &mut self,
31 db: &impl DefDatabase2, 39 db: &impl DefDatabase2,
32 path: &Path, 40 macro_call: ast::MacroCall,
33 ) -> Option<MacroDefId> { 41 ) -> Option<(Mark, ast::Expr)> {
42 let ast_id = AstId::new(
43 self.current_file_id,
44 db.ast_id_map(self.current_file_id).ast_id(&macro_call),
45 );
46
47 if let Some(path) = macro_call.path().and_then(|path| self.parse_path(path)) {
48 if let Some(def) = self.resolve_path_as_macro(db, &path) {
49 let call_id = db.intern_macro(MacroCallLoc { def, ast_id });
50 let file_id = call_id.as_file(MacroFileKind::Expr);
51 if let Some(node) = db.parse_or_expand(file_id) {
52 if let Some(expr) = ast::Expr::cast(node) {
53 log::debug!("macro expansion {:#?}", expr.syntax());
54
55 let mark = Mark { file_id: self.current_file_id };
56 self.hygiene = Hygiene::new(db, file_id);
57 self.current_file_id = file_id;
58
59 return Some((mark, expr));
60 }
61 }
62 }
63 }
64
65 // FIXME: Instead of just dropping the error from expansion
66 // report it
67 None
68 }
69
70 fn exit(&mut self, db: &impl DefDatabase2, mark: Mark) {
71 self.hygiene = Hygiene::new(db, mark.file_id);
72 self.current_file_id = mark.file_id;
73 std::mem::forget(mark);
74 }
75
76 fn to_source<T>(&self, ast: T) -> Source<T> {
77 Source { file_id: self.current_file_id, ast }
78 }
79
80 fn parse_path(&mut self, path: ast::Path) -> Option<Path> {
81 Path::from_src(path, &self.hygiene)
82 }
83
84 fn resolve_path_as_macro(&self, db: &impl DefDatabase2, path: &Path) -> Option<MacroDefId> {
34 self.crate_def_map.resolve_path(db, self.module.module_id, path).0.get_macros() 85 self.crate_def_map.resolve_path(db, self.module.module_id, path).0.get_macros()
35 } 86 }
36} 87}
37 88
89struct Mark {
90 file_id: HirFileId,
91}
92
93impl Drop for Mark {
94 fn drop(&mut self) {
95 if !std::thread::panicking() {
96 panic!("dropped mark")
97 }
98 }
99}
100
38/// The body of an item (function, const etc.). 101/// The body of an item (function, const etc.).
39#[derive(Debug, Eq, PartialEq)] 102#[derive(Debug, Eq, PartialEq)]
40pub struct Body { 103pub struct Body {
@@ -70,22 +133,51 @@ pub type PatSource = Source<PatPtr>;
70/// this properly for macros. 133/// this properly for macros.
71#[derive(Default, Debug, Eq, PartialEq)] 134#[derive(Default, Debug, Eq, PartialEq)]
72pub struct BodySourceMap { 135pub struct BodySourceMap {
73 expr_map: FxHashMap<ExprPtr, ExprId>, 136 expr_map: FxHashMap<ExprSource, ExprId>,
74 expr_map_back: ArenaMap<ExprId, ExprSource>, 137 expr_map_back: ArenaMap<ExprId, ExprSource>,
75 pat_map: FxHashMap<PatPtr, PatId>, 138 pat_map: FxHashMap<PatSource, PatId>,
76 pat_map_back: ArenaMap<PatId, PatSource>, 139 pat_map_back: ArenaMap<PatId, PatSource>,
77 field_map: FxHashMap<(ExprId, usize), AstPtr<ast::RecordField>>, 140 field_map: FxHashMap<(ExprId, usize), AstPtr<ast::RecordField>>,
78} 141}
79 142
80impl Body { 143impl Body {
81 pub fn new( 144 pub(crate) fn body_with_source_map_query(
145 db: &impl DefDatabase2,
146 def: DefWithBodyId,
147 ) -> (Arc<Body>, Arc<BodySourceMap>) {
148 let mut params = None;
149
150 let (file_id, module, body) = match def {
151 DefWithBodyId::FunctionId(f) => {
152 let src = f.source(db);
153 params = src.ast.param_list();
154 (src.file_id, f.module(db), src.ast.body().map(ast::Expr::from))
155 }
156 DefWithBodyId::ConstId(c) => {
157 let src = c.source(db);
158 (src.file_id, c.module(db), src.ast.body())
159 }
160 DefWithBodyId::StaticId(s) => {
161 let src = s.source(db);
162 (src.file_id, s.module(db), src.ast.body())
163 }
164 };
165 let expander = Expander::new(db, file_id, module);
166 let (body, source_map) = Body::new(db, expander, params, body);
167 (Arc::new(body), Arc::new(source_map))
168 }
169
170 pub(crate) fn body_query(db: &impl DefDatabase2, def: DefWithBodyId) -> Arc<Body> {
171 db.body_with_source_map(def).0
172 }
173
174 fn new(
82 db: &impl DefDatabase2, 175 db: &impl DefDatabase2,
83 resolver: MacroResolver, 176 expander: Expander,
84 file_id: HirFileId,
85 params: Option<ast::ParamList>, 177 params: Option<ast::ParamList>,
86 body: Option<ast::Expr>, 178 body: Option<ast::Expr>,
87 ) -> (Body, BodySourceMap) { 179 ) -> (Body, BodySourceMap) {
88 lower::lower(db, resolver, file_id, params, body) 180 lower::lower(db, expander, params, body)
89 } 181 }
90 182
91 pub fn params(&self) -> &[PatId] { 183 pub fn params(&self) -> &[PatId] {
@@ -126,16 +218,18 @@ impl BodySourceMap {
126 self.expr_map_back.get(expr).copied() 218 self.expr_map_back.get(expr).copied()
127 } 219 }
128 220
129 pub fn node_expr(&self, node: &ast::Expr) -> Option<ExprId> { 221 pub fn node_expr(&self, node: Source<&ast::Expr>) -> Option<ExprId> {
130 self.expr_map.get(&Either::A(AstPtr::new(node))).cloned() 222 let src = node.map(|it| Either::A(AstPtr::new(it)));
223 self.expr_map.get(&src).cloned()
131 } 224 }
132 225
133 pub fn pat_syntax(&self, pat: PatId) -> Option<PatSource> { 226 pub fn pat_syntax(&self, pat: PatId) -> Option<PatSource> {
134 self.pat_map_back.get(pat).copied() 227 self.pat_map_back.get(pat).copied()
135 } 228 }
136 229
137 pub fn node_pat(&self, node: &ast::Pat) -> Option<PatId> { 230 pub fn node_pat(&self, node: Source<&ast::Pat>) -> Option<PatId> {
138 self.pat_map.get(&Either::A(AstPtr::new(node))).cloned() 231 let src = node.map(|it| Either::A(AstPtr::new(it)));
232 self.pat_map.get(&src).cloned()
139 } 233 }
140 234
141 pub fn field_syntax(&self, expr: ExprId, field: usize) -> AstPtr<ast::RecordField> { 235 pub fn field_syntax(&self, expr: ExprId, field: usize) -> AstPtr<ast::RecordField> {
diff --git a/crates/ra_hir_def/src/body/lower.rs b/crates/ra_hir_def/src/body/lower.rs
index 2aa863c9e..a5bb60e85 100644
--- a/crates/ra_hir_def/src/body/lower.rs
+++ b/crates/ra_hir_def/src/body/lower.rs
@@ -2,9 +2,7 @@
2 2
3use hir_expand::{ 3use hir_expand::{
4 either::Either, 4 either::Either,
5 hygiene::Hygiene,
6 name::{self, AsName, Name}, 5 name::{self, AsName, Name},
7 AstId, HirFileId, MacroCallLoc, MacroFileKind, Source,
8}; 6};
9use ra_arena::Arena; 7use ra_arena::Arena;
10use ra_syntax::{ 8use ra_syntax::{
@@ -16,7 +14,7 @@ use ra_syntax::{
16}; 14};
17 15
18use crate::{ 16use crate::{
19 body::{Body, BodySourceMap, MacroResolver, PatPtr}, 17 body::{Body, BodySourceMap, Expander, PatPtr},
20 builtin_type::{BuiltinFloat, BuiltinInt}, 18 builtin_type::{BuiltinFloat, BuiltinInt},
21 db::DefDatabase2, 19 db::DefDatabase2,
22 expr::{ 20 expr::{
@@ -30,16 +28,13 @@ use crate::{
30 28
31pub(super) fn lower( 29pub(super) fn lower(
32 db: &impl DefDatabase2, 30 db: &impl DefDatabase2,
33 resolver: MacroResolver, 31 expander: Expander,
34 file_id: HirFileId,
35 params: Option<ast::ParamList>, 32 params: Option<ast::ParamList>,
36 body: Option<ast::Expr>, 33 body: Option<ast::Expr>,
37) -> (Body, BodySourceMap) { 34) -> (Body, BodySourceMap) {
38 ExprCollector { 35 ExprCollector {
39 resolver, 36 expander,
40 db, 37 db,
41 original_file_id: file_id,
42 current_file_id: file_id,
43 source_map: BodySourceMap::default(), 38 source_map: BodySourceMap::default(),
44 body: Body { 39 body: Body {
45 exprs: Arena::default(), 40 exprs: Arena::default(),
@@ -53,9 +48,7 @@ pub(super) fn lower(
53 48
54struct ExprCollector<DB> { 49struct ExprCollector<DB> {
55 db: DB, 50 db: DB,
56 resolver: MacroResolver, 51 expander: Expander,
57 original_file_id: HirFileId,
58 current_file_id: HirFileId,
59 52
60 body: Body, 53 body: Body,
61 source_map: BodySourceMap, 54 source_map: BodySourceMap,
@@ -101,12 +94,9 @@ where
101 fn alloc_expr(&mut self, expr: Expr, ptr: AstPtr<ast::Expr>) -> ExprId { 94 fn alloc_expr(&mut self, expr: Expr, ptr: AstPtr<ast::Expr>) -> ExprId {
102 let ptr = Either::A(ptr); 95 let ptr = Either::A(ptr);
103 let id = self.body.exprs.alloc(expr); 96 let id = self.body.exprs.alloc(expr);
104 if self.current_file_id == self.original_file_id { 97 let src = self.expander.to_source(ptr);
105 self.source_map.expr_map.insert(ptr, id); 98 self.source_map.expr_map.insert(src, id);
106 } 99 self.source_map.expr_map_back.insert(id, src);
107 self.source_map
108 .expr_map_back
109 .insert(id, Source { file_id: self.current_file_id, ast: ptr });
110 id 100 id
111 } 101 }
112 // desugared exprs don't have ptr, that's wrong and should be fixed 102 // desugared exprs don't have ptr, that's wrong and should be fixed
@@ -117,20 +107,16 @@ where
117 fn alloc_expr_field_shorthand(&mut self, expr: Expr, ptr: AstPtr<ast::RecordField>) -> ExprId { 107 fn alloc_expr_field_shorthand(&mut self, expr: Expr, ptr: AstPtr<ast::RecordField>) -> ExprId {
118 let ptr = Either::B(ptr); 108 let ptr = Either::B(ptr);
119 let id = self.body.exprs.alloc(expr); 109 let id = self.body.exprs.alloc(expr);
120 if self.current_file_id == self.original_file_id { 110 let src = self.expander.to_source(ptr);
121 self.source_map.expr_map.insert(ptr, id); 111 self.source_map.expr_map.insert(src, id);
122 } 112 self.source_map.expr_map_back.insert(id, src);
123 self.source_map
124 .expr_map_back
125 .insert(id, Source { file_id: self.current_file_id, ast: ptr });
126 id 113 id
127 } 114 }
128 fn alloc_pat(&mut self, pat: Pat, ptr: PatPtr) -> PatId { 115 fn alloc_pat(&mut self, pat: Pat, ptr: PatPtr) -> PatId {
129 let id = self.body.pats.alloc(pat); 116 let id = self.body.pats.alloc(pat);
130 if self.current_file_id == self.original_file_id { 117 let src = self.expander.to_source(ptr);
131 self.source_map.pat_map.insert(ptr, id); 118 self.source_map.pat_map.insert(src, id);
132 } 119 self.source_map.pat_map_back.insert(id, src);
133 self.source_map.pat_map_back.insert(id, Source { file_id: self.current_file_id, ast: ptr });
134 id 120 id
135 } 121 }
136 122
@@ -272,7 +258,7 @@ where
272 ast::Expr::PathExpr(e) => { 258 ast::Expr::PathExpr(e) => {
273 let path = e 259 let path = e
274 .path() 260 .path()
275 .and_then(|path| self.parse_path(path)) 261 .and_then(|path| self.expander.parse_path(path))
276 .map(Expr::Path) 262 .map(Expr::Path)
277 .unwrap_or(Expr::Missing); 263 .unwrap_or(Expr::Missing);
278 self.alloc_expr(path, syntax_ptr) 264 self.alloc_expr(path, syntax_ptr)
@@ -288,7 +274,8 @@ where
288 ast::Expr::ParenExpr(e) => { 274 ast::Expr::ParenExpr(e) => {
289 let inner = self.collect_expr_opt(e.expr()); 275 let inner = self.collect_expr_opt(e.expr());
290 // make the paren expr point to the inner expression as well 276 // make the paren expr point to the inner expression as well
291 self.source_map.expr_map.insert(Either::A(syntax_ptr), inner); 277 let src = self.expander.to_source(Either::A(syntax_ptr));
278 self.source_map.expr_map.insert(src, inner);
292 inner 279 inner
293 } 280 }
294 ast::Expr::ReturnExpr(e) => { 281 ast::Expr::ReturnExpr(e) => {
@@ -296,7 +283,7 @@ where
296 self.alloc_expr(Expr::Return { expr }, syntax_ptr) 283 self.alloc_expr(Expr::Return { expr }, syntax_ptr)
297 } 284 }
298 ast::Expr::RecordLit(e) => { 285 ast::Expr::RecordLit(e) => {
299 let path = e.path().and_then(|path| self.parse_path(path)); 286 let path = e.path().and_then(|path| self.expander.parse_path(path));
300 let mut field_ptrs = Vec::new(); 287 let mut field_ptrs = Vec::new();
301 let record_lit = if let Some(nfl) = e.record_field_list() { 288 let record_lit = if let Some(nfl) = e.record_field_list() {
302 let fields = nfl 289 let fields = nfl
@@ -443,32 +430,14 @@ where
443 // FIXME implement HIR for these: 430 // FIXME implement HIR for these:
444 ast::Expr::Label(_e) => self.alloc_expr(Expr::Missing, syntax_ptr), 431 ast::Expr::Label(_e) => self.alloc_expr(Expr::Missing, syntax_ptr),
445 ast::Expr::RangeExpr(_e) => self.alloc_expr(Expr::Missing, syntax_ptr), 432 ast::Expr::RangeExpr(_e) => self.alloc_expr(Expr::Missing, syntax_ptr),
446 ast::Expr::MacroCall(e) => { 433 ast::Expr::MacroCall(e) => match self.expander.enter_expand(self.db, e) {
447 let ast_id = AstId::new( 434 Some((mark, expansion)) => {
448 self.current_file_id, 435 let id = self.collect_expr(expansion);
449 self.db.ast_id_map(self.current_file_id).ast_id(&e), 436 self.expander.exit(self.db, mark);
450 ); 437 id
451
452 if let Some(path) = e.path().and_then(|path| self.parse_path(path)) {
453 if let Some(def) = self.resolver.resolve_path_as_macro(self.db, &path) {
454 let call_id = self.db.intern_macro(MacroCallLoc { def, ast_id });
455 let file_id = call_id.as_file(MacroFileKind::Expr);
456 if let Some(node) = self.db.parse_or_expand(file_id) {
457 if let Some(expr) = ast::Expr::cast(node) {
458 log::debug!("macro expansion {:#?}", expr.syntax());
459 let old_file_id =
460 std::mem::replace(&mut self.current_file_id, file_id);
461 let id = self.collect_expr(expr);
462 self.current_file_id = old_file_id;
463 return id;
464 }
465 }
466 }
467 } 438 }
468 // FIXME: Instead of just dropping the error from expansion 439 None => self.alloc_expr(Expr::Missing, syntax_ptr),
469 // report it 440 },
470 self.alloc_expr(Expr::Missing, syntax_ptr)
471 }
472 } 441 }
473 } 442 }
474 443
@@ -519,7 +488,7 @@ where
519 Pat::Bind { name, mode: annotation, subpat } 488 Pat::Bind { name, mode: annotation, subpat }
520 } 489 }
521 ast::Pat::TupleStructPat(p) => { 490 ast::Pat::TupleStructPat(p) => {
522 let path = p.path().and_then(|path| self.parse_path(path)); 491 let path = p.path().and_then(|path| self.expander.parse_path(path));
523 let args = p.args().map(|p| self.collect_pat(p)).collect(); 492 let args = p.args().map(|p| self.collect_pat(p)).collect();
524 Pat::TupleStruct { path, args } 493 Pat::TupleStruct { path, args }
525 } 494 }
@@ -529,7 +498,7 @@ where
529 Pat::Ref { pat, mutability } 498 Pat::Ref { pat, mutability }
530 } 499 }
531 ast::Pat::PathPat(p) => { 500 ast::Pat::PathPat(p) => {
532 let path = p.path().and_then(|path| self.parse_path(path)); 501 let path = p.path().and_then(|path| self.expander.parse_path(path));
533 path.map(Pat::Path).unwrap_or(Pat::Missing) 502 path.map(Pat::Path).unwrap_or(Pat::Missing)
534 } 503 }
535 ast::Pat::TuplePat(p) => { 504 ast::Pat::TuplePat(p) => {
@@ -538,7 +507,7 @@ where
538 } 507 }
539 ast::Pat::PlaceholderPat(_) => Pat::Wild, 508 ast::Pat::PlaceholderPat(_) => Pat::Wild,
540 ast::Pat::RecordPat(p) => { 509 ast::Pat::RecordPat(p) => {
541 let path = p.path().and_then(|path| self.parse_path(path)); 510 let path = p.path().and_then(|path| self.expander.parse_path(path));
542 let record_field_pat_list = 511 let record_field_pat_list =
543 p.record_field_pat_list().expect("every struct should have a field list"); 512 p.record_field_pat_list().expect("every struct should have a field list");
544 let mut fields: Vec<_> = record_field_pat_list 513 let mut fields: Vec<_> = record_field_pat_list
@@ -579,11 +548,6 @@ where
579 self.missing_pat() 548 self.missing_pat()
580 } 549 }
581 } 550 }
582
583 fn parse_path(&mut self, path: ast::Path) -> Option<Path> {
584 let hygiene = Hygiene::new(self.db, self.current_file_id);
585 Path::from_src(path, &hygiene)
586 }
587} 551}
588 552
589impl From<ast::BinOp> for BinaryOp { 553impl From<ast::BinOp> for BinaryOp {
diff --git a/crates/ra_hir_def/src/body/scope.rs b/crates/ra_hir_def/src/body/scope.rs
new file mode 100644
index 000000000..09a39e721
--- /dev/null
+++ b/crates/ra_hir_def/src/body/scope.rs
@@ -0,0 +1,165 @@
1//! FIXME: write short doc here
2use std::sync::Arc;
3
4use hir_expand::name::Name;
5use ra_arena::{impl_arena_id, Arena, RawId};
6use rustc_hash::FxHashMap;
7
8use crate::{
9 body::Body,
10 db::DefDatabase2,
11 expr::{Expr, ExprId, Pat, PatId, Statement},
12 DefWithBodyId,
13};
14
15#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
16pub struct ScopeId(RawId);
17impl_arena_id!(ScopeId);
18
19#[derive(Debug, PartialEq, Eq)]
20pub struct ExprScopes {
21 scopes: Arena<ScopeId, ScopeData>,
22 scope_by_expr: FxHashMap<ExprId, ScopeId>,
23}
24
25#[derive(Debug, PartialEq, Eq)]
26pub struct ScopeEntry {
27 name: Name,
28 pat: PatId,
29}
30
31impl ScopeEntry {
32 pub fn name(&self) -> &Name {
33 &self.name
34 }
35
36 pub fn pat(&self) -> PatId {
37 self.pat
38 }
39}
40
41#[derive(Debug, PartialEq, Eq)]
42pub struct ScopeData {
43 parent: Option<ScopeId>,
44 entries: Vec<ScopeEntry>,
45}
46
47impl ExprScopes {
48 pub(crate) fn expr_scopes_query(db: &impl DefDatabase2, def: DefWithBodyId) -> Arc<ExprScopes> {
49 let body = db.body(def);
50 Arc::new(ExprScopes::new(&*body))
51 }
52
53 fn new(body: &Body) -> ExprScopes {
54 let mut scopes =
55 ExprScopes { scopes: Arena::default(), scope_by_expr: FxHashMap::default() };
56 let root = scopes.root_scope();
57 scopes.add_params_bindings(body, root, body.params());
58 compute_expr_scopes(body.body_expr(), body, &mut scopes, root);
59 scopes
60 }
61
62 pub fn entries(&self, scope: ScopeId) -> &[ScopeEntry] {
63 &self.scopes[scope].entries
64 }
65
66 pub fn scope_chain(&self, scope: Option<ScopeId>) -> impl Iterator<Item = ScopeId> + '_ {
67 std::iter::successors(scope, move |&scope| self.scopes[scope].parent)
68 }
69
70 pub fn scope_for(&self, expr: ExprId) -> Option<ScopeId> {
71 self.scope_by_expr.get(&expr).copied()
72 }
73
74 pub fn scope_by_expr(&self) -> &FxHashMap<ExprId, ScopeId> {
75 &self.scope_by_expr
76 }
77
78 fn root_scope(&mut self) -> ScopeId {
79 self.scopes.alloc(ScopeData { parent: None, entries: vec![] })
80 }
81
82 fn new_scope(&mut self, parent: ScopeId) -> ScopeId {
83 self.scopes.alloc(ScopeData { parent: Some(parent), entries: vec![] })
84 }
85
86 fn add_bindings(&mut self, body: &Body, scope: ScopeId, pat: PatId) {
87 match &body[pat] {
88 Pat::Bind { name, .. } => {
89 // bind can have a sub pattern, but it's actually not allowed
90 // to bind to things in there
91 let entry = ScopeEntry { name: name.clone(), pat };
92 self.scopes[scope].entries.push(entry)
93 }
94 p => p.walk_child_pats(|pat| self.add_bindings(body, scope, pat)),
95 }
96 }
97
98 fn add_params_bindings(&mut self, body: &Body, scope: ScopeId, params: &[PatId]) {
99 params.iter().for_each(|pat| self.add_bindings(body, scope, *pat));
100 }
101
102 fn set_scope(&mut self, node: ExprId, scope: ScopeId) {
103 self.scope_by_expr.insert(node, scope);
104 }
105}
106
107fn compute_block_scopes(
108 statements: &[Statement],
109 tail: Option<ExprId>,
110 body: &Body,
111 scopes: &mut ExprScopes,
112 mut scope: ScopeId,
113) {
114 for stmt in statements {
115 match stmt {
116 Statement::Let { pat, initializer, .. } => {
117 if let Some(expr) = initializer {
118 scopes.set_scope(*expr, scope);
119 compute_expr_scopes(*expr, body, scopes, scope);
120 }
121 scope = scopes.new_scope(scope);
122 scopes.add_bindings(body, scope, *pat);
123 }
124 Statement::Expr(expr) => {
125 scopes.set_scope(*expr, scope);
126 compute_expr_scopes(*expr, body, scopes, scope);
127 }
128 }
129 }
130 if let Some(expr) = tail {
131 compute_expr_scopes(expr, body, scopes, scope);
132 }
133}
134
135fn compute_expr_scopes(expr: ExprId, body: &Body, scopes: &mut ExprScopes, scope: ScopeId) {
136 scopes.set_scope(expr, scope);
137 match &body[expr] {
138 Expr::Block { statements, tail } => {
139 compute_block_scopes(&statements, *tail, body, scopes, scope);
140 }
141 Expr::For { iterable, pat, body: body_expr } => {
142 compute_expr_scopes(*iterable, body, scopes, scope);
143 let scope = scopes.new_scope(scope);
144 scopes.add_bindings(body, scope, *pat);
145 compute_expr_scopes(*body_expr, body, scopes, scope);
146 }
147 Expr::Lambda { args, body: body_expr, .. } => {
148 let scope = scopes.new_scope(scope);
149 scopes.add_params_bindings(body, scope, &args);
150 compute_expr_scopes(*body_expr, body, scopes, scope);
151 }
152 Expr::Match { expr, arms } => {
153 compute_expr_scopes(*expr, body, scopes, scope);
154 for arm in arms {
155 let scope = scopes.new_scope(scope);
156 for pat in &arm.pats {
157 scopes.add_bindings(body, scope, *pat);
158 }
159 scopes.set_scope(arm.expr, scope);
160 compute_expr_scopes(arm.expr, body, scopes, scope);
161 }
162 }
163 e => e.walk_child_exprs(|e| compute_expr_scopes(e, body, scopes, scope)),
164 };
165}
diff --git a/crates/ra_hir_def/src/db.rs b/crates/ra_hir_def/src/db.rs
index 29cf71a59..40b5920d9 100644
--- a/crates/ra_hir_def/src/db.rs
+++ b/crates/ra_hir_def/src/db.rs
@@ -7,11 +7,12 @@ use ra_syntax::ast;
7 7
8use crate::{ 8use crate::{
9 adt::{EnumData, StructData}, 9 adt::{EnumData, StructData},
10 body::{scope::ExprScopes, Body, BodySourceMap},
10 nameres::{ 11 nameres::{
11 raw::{ImportSourceMap, RawItems}, 12 raw::{ImportSourceMap, RawItems},
12 CrateDefMap, 13 CrateDefMap,
13 }, 14 },
14 EnumId, StructOrUnionId, 15 DefWithBodyId, EnumId, StructOrUnionId,
15}; 16};
16 17
17#[salsa::query_group(InternDatabaseStorage)] 18#[salsa::query_group(InternDatabaseStorage)]
@@ -52,4 +53,13 @@ pub trait DefDatabase2: InternDatabase + AstDatabase {
52 53
53 #[salsa::invoke(EnumData::enum_data_query)] 54 #[salsa::invoke(EnumData::enum_data_query)]
54 fn enum_data(&self, e: EnumId) -> Arc<EnumData>; 55 fn enum_data(&self, e: EnumId) -> Arc<EnumData>;
56
57 #[salsa::invoke(Body::body_with_source_map_query)]
58 fn body_with_source_map(&self, def: DefWithBodyId) -> (Arc<Body>, Arc<BodySourceMap>);
59
60 #[salsa::invoke(Body::body_query)]
61 fn body(&self, def: DefWithBodyId) -> Arc<Body>;
62
63 #[salsa::invoke(ExprScopes::expr_scopes_query)]
64 fn expr_scopes(&self, def: DefWithBodyId) -> Arc<ExprScopes>;
55} 65}
diff --git a/crates/ra_hir_def/src/lib.rs b/crates/ra_hir_def/src/lib.rs
index 4a758bb83..3fab7965c 100644
--- a/crates/ra_hir_def/src/lib.rs
+++ b/crates/ra_hir_def/src/lib.rs
@@ -374,3 +374,13 @@ impl_froms!(
374 TypeAliasId, 374 TypeAliasId,
375 BuiltinType 375 BuiltinType
376); 376);
377
378/// The defs which have a body.
379#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
380pub enum DefWithBodyId {
381 FunctionId(FunctionId),
382 StaticId(StaticId),
383 ConstId(ConstId),
384}
385
386impl_froms!(DefWithBodyId: FunctionId, ConstId, StaticId);