diff options
Diffstat (limited to 'crates/hir_def')
-rw-r--r-- | crates/hir_def/src/body/scope.rs | 57 | ||||
-rw-r--r-- | crates/hir_def/src/resolver.rs | 6 |
2 files changed, 52 insertions, 11 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); |
diff --git a/crates/hir_def/src/resolver.rs b/crates/hir_def/src/resolver.rs index 42736171e..4a2d1c087 100644 --- a/crates/hir_def/src/resolver.rs +++ b/crates/hir_def/src/resolver.rs | |||
@@ -12,7 +12,7 @@ use crate::{ | |||
12 | body::scope::{ExprScopes, ScopeId}, | 12 | body::scope::{ExprScopes, ScopeId}, |
13 | builtin_type::BuiltinType, | 13 | builtin_type::BuiltinType, |
14 | db::DefDatabase, | 14 | db::DefDatabase, |
15 | expr::{ExprId, PatId}, | 15 | expr::{ExprId, LabelId, PatId}, |
16 | generics::GenericParams, | 16 | generics::GenericParams, |
17 | item_scope::{BuiltinShadowMode, BUILTIN_SCOPE}, | 17 | item_scope::{BuiltinShadowMode, BUILTIN_SCOPE}, |
18 | nameres::DefMap, | 18 | nameres::DefMap, |
@@ -409,6 +409,7 @@ pub enum ScopeDef { | |||
409 | AdtSelfType(AdtId), | 409 | AdtSelfType(AdtId), |
410 | GenericParam(GenericParamId), | 410 | GenericParam(GenericParamId), |
411 | Local(PatId), | 411 | Local(PatId), |
412 | Label(LabelId), | ||
412 | } | 413 | } |
413 | 414 | ||
414 | impl Scope { | 415 | impl Scope { |
@@ -470,6 +471,9 @@ impl Scope { | |||
470 | f(name![Self], ScopeDef::AdtSelfType(*i)); | 471 | f(name![Self], ScopeDef::AdtSelfType(*i)); |
471 | } | 472 | } |
472 | Scope::ExprScope(scope) => { | 473 | Scope::ExprScope(scope) => { |
474 | if let Some((label, name)) = scope.expr_scopes.label(scope.scope_id) { | ||
475 | f(name.clone(), ScopeDef::Label(label)) | ||
476 | } | ||
473 | scope.expr_scopes.entries(scope.scope_id).iter().for_each(|e| { | 477 | scope.expr_scopes.entries(scope.scope_id).iter().for_each(|e| { |
474 | f(e.name().clone(), ScopeDef::Local(e.pat())); | 478 | f(e.name().clone(), ScopeDef::Local(e.pat())); |
475 | }); | 479 | }); |