diff options
Diffstat (limited to 'crates/hir_def/src/body')
-rw-r--r-- | crates/hir_def/src/body/scope.rs | 57 |
1 files changed, 47 insertions, 10 deletions
diff --git a/crates/hir_def/src/body/scope.rs b/crates/hir_def/src/body/scope.rs index 1bbb54fc6..bd7005ca6 100644 --- a/crates/hir_def/src/body/scope.rs +++ b/crates/hir_def/src/body/scope.rs | |||
@@ -8,7 +8,7 @@ use rustc_hash::FxHashMap; | |||
8 | use crate::{ | 8 | use crate::{ |
9 | body::Body, | 9 | body::Body, |
10 | db::DefDatabase, | 10 | db::DefDatabase, |
11 | expr::{Expr, ExprId, Pat, PatId, Statement}, | 11 | expr::{Expr, ExprId, LabelId, Pat, PatId, Statement}, |
12 | BlockId, DefWithBodyId, | 12 | BlockId, DefWithBodyId, |
13 | }; | 13 | }; |
14 | 14 | ||
@@ -40,6 +40,7 @@ impl ScopeEntry { | |||
40 | pub struct ScopeData { | 40 | pub struct ScopeData { |
41 | parent: Option<ScopeId>, | 41 | parent: Option<ScopeId>, |
42 | block: Option<BlockId>, | 42 | block: Option<BlockId>, |
43 | label: Option<(LabelId, Name)>, | ||
43 | entries: Vec<ScopeEntry>, | 44 | entries: Vec<ScopeEntry>, |
44 | } | 45 | } |
45 | 46 | ||
@@ -67,6 +68,11 @@ impl ExprScopes { | |||
67 | self.scopes[scope].block | 68 | self.scopes[scope].block |
68 | } | 69 | } |
69 | 70 | ||
71 | /// If `scope` refers to a labeled expression scope, returns the corresponding `Label`. | ||
72 | pub fn label(&self, scope: ScopeId) -> Option<(LabelId, Name)> { | ||
73 | self.scopes[scope].label.clone() | ||
74 | } | ||
75 | |||
70 | pub fn scope_chain(&self, scope: Option<ScopeId>) -> impl Iterator<Item = ScopeId> + '_ { | 76 | pub fn scope_chain(&self, scope: Option<ScopeId>) -> impl Iterator<Item = ScopeId> + '_ { |
71 | std::iter::successors(scope, move |&scope| self.scopes[scope].parent) | 77 | std::iter::successors(scope, move |&scope| self.scopes[scope].parent) |
72 | } | 78 | } |
@@ -85,15 +91,34 @@ impl ExprScopes { | |||
85 | } | 91 | } |
86 | 92 | ||
87 | fn root_scope(&mut self) -> ScopeId { | 93 | fn root_scope(&mut self) -> ScopeId { |
88 | self.scopes.alloc(ScopeData { parent: None, block: None, entries: vec![] }) | 94 | self.scopes.alloc(ScopeData { parent: None, block: None, label: None, entries: vec![] }) |
89 | } | 95 | } |
90 | 96 | ||
91 | fn new_scope(&mut self, parent: ScopeId) -> ScopeId { | 97 | fn new_scope(&mut self, parent: ScopeId) -> ScopeId { |
92 | self.scopes.alloc(ScopeData { parent: Some(parent), block: None, entries: vec![] }) | 98 | self.scopes.alloc(ScopeData { |
99 | parent: Some(parent), | ||
100 | block: None, | ||
101 | label: None, | ||
102 | entries: vec![], | ||
103 | }) | ||
93 | } | 104 | } |
94 | 105 | ||
95 | fn new_block_scope(&mut self, parent: ScopeId, block: BlockId) -> ScopeId { | 106 | fn new_labeled_scope(&mut self, parent: ScopeId, label: Option<(LabelId, Name)>) -> ScopeId { |
96 | self.scopes.alloc(ScopeData { parent: Some(parent), block: Some(block), entries: vec![] }) | 107 | self.scopes.alloc(ScopeData { parent: Some(parent), block: None, label, entries: vec![] }) |
108 | } | ||
109 | |||
110 | fn new_block_scope( | ||
111 | &mut self, | ||
112 | parent: ScopeId, | ||
113 | block: BlockId, | ||
114 | label: Option<(LabelId, Name)>, | ||
115 | ) -> ScopeId { | ||
116 | self.scopes.alloc(ScopeData { | ||
117 | parent: Some(parent), | ||
118 | block: Some(block), | ||
119 | label, | ||
120 | entries: vec![], | ||
121 | }) | ||
97 | } | 122 | } |
98 | 123 | ||
99 | fn add_bindings(&mut self, body: &Body, scope: ScopeId, pat: PatId) { | 124 | fn add_bindings(&mut self, body: &Body, scope: ScopeId, pat: PatId) { |
@@ -144,21 +169,33 @@ fn compute_block_scopes( | |||
144 | } | 169 | } |
145 | 170 | ||
146 | fn compute_expr_scopes(expr: ExprId, body: &Body, scopes: &mut ExprScopes, scope: ScopeId) { | 171 | fn compute_expr_scopes(expr: ExprId, body: &Body, scopes: &mut ExprScopes, scope: ScopeId) { |
172 | let make_label = | ||
173 | |label: &Option<_>| label.map(|label| (label, body.labels[label].name.clone())); | ||
174 | |||
147 | scopes.set_scope(expr, scope); | 175 | scopes.set_scope(expr, scope); |
148 | match &body[expr] { | 176 | match &body[expr] { |
149 | Expr::Block { statements, tail, id, .. } => { | 177 | Expr::Block { statements, tail, id, label } => { |
150 | let scope = scopes.new_block_scope(scope, *id); | 178 | let scope = scopes.new_block_scope(scope, *id, make_label(label)); |
151 | // Overwrite the old scope for the block expr, so that every block scope can be found | 179 | // Overwrite the old scope for the block expr, so that every block scope can be found |
152 | // via the block itself (important for blocks that only contain items, no expressions). | 180 | // via the block itself (important for blocks that only contain items, no expressions). |
153 | scopes.set_scope(expr, scope); | 181 | scopes.set_scope(expr, scope); |
154 | compute_block_scopes(&statements, *tail, body, scopes, scope); | 182 | compute_block_scopes(statements, *tail, body, scopes, scope); |
155 | } | 183 | } |
156 | Expr::For { iterable, pat, body: body_expr, .. } => { | 184 | Expr::For { iterable, pat, body: body_expr, label } => { |
157 | compute_expr_scopes(*iterable, body, scopes, scope); | 185 | compute_expr_scopes(*iterable, body, scopes, scope); |
158 | let scope = scopes.new_scope(scope); | 186 | let scope = scopes.new_labeled_scope(scope, make_label(label)); |
159 | scopes.add_bindings(body, scope, *pat); | 187 | scopes.add_bindings(body, scope, *pat); |
160 | compute_expr_scopes(*body_expr, body, scopes, scope); | 188 | compute_expr_scopes(*body_expr, body, scopes, scope); |
161 | } | 189 | } |
190 | Expr::While { condition, body: body_expr, label } => { | ||
191 | let scope = scopes.new_labeled_scope(scope, make_label(label)); | ||
192 | compute_expr_scopes(*condition, body, scopes, scope); | ||
193 | compute_expr_scopes(*body_expr, body, scopes, scope); | ||
194 | } | ||
195 | Expr::Loop { body: body_expr, label } => { | ||
196 | let scope = scopes.new_labeled_scope(scope, make_label(label)); | ||
197 | compute_expr_scopes(*body_expr, body, scopes, scope); | ||
198 | } | ||
162 | Expr::Lambda { args, body: body_expr, .. } => { | 199 | Expr::Lambda { args, body: body_expr, .. } => { |
163 | let scope = scopes.new_scope(scope); | 200 | let scope = scopes.new_scope(scope); |
164 | scopes.add_params_bindings(body, scope, &args); | 201 | scopes.add_params_bindings(body, scope, &args); |