diff options
author | robojumper <[email protected]> | 2020-05-31 09:59:40 +0100 |
---|---|---|
committer | robojumper <[email protected]> | 2020-05-31 10:40:18 +0100 |
commit | 1cd78a3355ea70d3070cabb00c80a5d195499752 (patch) | |
tree | 91b2b70dbf3ac73a2fe430fd92a26d41df2a60cb /crates | |
parent | fb469c3b31e7da962e91269b53b2f53d672cc4ba (diff) |
correctly infer labelled breaks
Diffstat (limited to 'crates')
-rw-r--r-- | crates/ra_hir_def/src/body/lower.rs | 56 | ||||
-rw-r--r-- | crates/ra_hir_def/src/body/scope.rs | 4 | ||||
-rw-r--r-- | crates/ra_hir_def/src/expr.rs | 19 | ||||
-rw-r--r-- | crates/ra_hir_expand/src/name.rs | 5 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/infer.rs | 11 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/infer/expr.rs | 45 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/tests/simple.rs | 20 | ||||
-rw-r--r-- | crates/ra_syntax/src/ast/generated/nodes.rs | 1 |
8 files changed, 116 insertions, 45 deletions
diff --git a/crates/ra_hir_def/src/body/lower.rs b/crates/ra_hir_def/src/body/lower.rs index 905c0cf5d..dc52c6bd9 100644 --- a/crates/ra_hir_def/src/body/lower.rs +++ b/crates/ra_hir_def/src/body/lower.rs | |||
@@ -134,7 +134,7 @@ impl ExprCollector<'_> { | |||
134 | self.make_expr(expr, Err(SyntheticSyntax)) | 134 | self.make_expr(expr, Err(SyntheticSyntax)) |
135 | } | 135 | } |
136 | fn empty_block(&mut self) -> ExprId { | 136 | fn empty_block(&mut self) -> ExprId { |
137 | self.alloc_expr_desugared(Expr::Block { statements: Vec::new(), tail: None }) | 137 | self.alloc_expr_desugared(Expr::Block { statements: Vec::new(), tail: None, label: None }) |
138 | } | 138 | } |
139 | fn missing_expr(&mut self) -> ExprId { | 139 | fn missing_expr(&mut self) -> ExprId { |
140 | self.alloc_expr_desugared(Expr::Missing) | 140 | self.alloc_expr_desugared(Expr::Missing) |
@@ -215,7 +215,13 @@ impl ExprCollector<'_> { | |||
215 | ast::Expr::BlockExpr(e) => self.collect_block(e), | 215 | ast::Expr::BlockExpr(e) => self.collect_block(e), |
216 | ast::Expr::LoopExpr(e) => { | 216 | ast::Expr::LoopExpr(e) => { |
217 | let body = self.collect_block_opt(e.loop_body()); | 217 | let body = self.collect_block_opt(e.loop_body()); |
218 | self.alloc_expr(Expr::Loop { body }, syntax_ptr) | 218 | self.alloc_expr( |
219 | Expr::Loop { | ||
220 | body, | ||
221 | label: e.label().and_then(|l| l.lifetime_token()).map(|l| Name::new_lifetime(&l)), | ||
222 | }, | ||
223 | syntax_ptr, | ||
224 | ) | ||
219 | } | 225 | } |
220 | ast::Expr::WhileExpr(e) => { | 226 | ast::Expr::WhileExpr(e) => { |
221 | let body = self.collect_block_opt(e.loop_body()); | 227 | let body = self.collect_block_opt(e.loop_body()); |
@@ -230,25 +236,47 @@ impl ExprCollector<'_> { | |||
230 | let pat = self.collect_pat(pat); | 236 | let pat = self.collect_pat(pat); |
231 | let match_expr = self.collect_expr_opt(condition.expr()); | 237 | let match_expr = self.collect_expr_opt(condition.expr()); |
232 | let placeholder_pat = self.missing_pat(); | 238 | let placeholder_pat = self.missing_pat(); |
233 | let break_ = self.alloc_expr_desugared(Expr::Break { expr: None }); | 239 | let break_ = |
240 | self.alloc_expr_desugared(Expr::Break { expr: None, label: None }); | ||
234 | let arms = vec![ | 241 | let arms = vec![ |
235 | MatchArm { pat, expr: body, guard: None }, | 242 | MatchArm { pat, expr: body, guard: None }, |
236 | MatchArm { pat: placeholder_pat, expr: break_, guard: None }, | 243 | MatchArm { pat: placeholder_pat, expr: break_, guard: None }, |
237 | ]; | 244 | ]; |
238 | let match_expr = | 245 | let match_expr = |
239 | self.alloc_expr_desugared(Expr::Match { expr: match_expr, arms }); | 246 | self.alloc_expr_desugared(Expr::Match { expr: match_expr, arms }); |
240 | return self.alloc_expr(Expr::Loop { body: match_expr }, syntax_ptr); | 247 | return self.alloc_expr( |
248 | Expr::Loop { | ||
249 | body: match_expr, | ||
250 | label: e.label().and_then(|l| l.lifetime_token()).map(|l| Name::new_lifetime(&l)), | ||
251 | }, | ||
252 | syntax_ptr, | ||
253 | ); | ||
241 | } | 254 | } |
242 | }, | 255 | }, |
243 | }; | 256 | }; |
244 | 257 | ||
245 | self.alloc_expr(Expr::While { condition, body }, syntax_ptr) | 258 | self.alloc_expr( |
259 | Expr::While { | ||
260 | condition, | ||
261 | body, | ||
262 | label: e.label().and_then(|l| l.lifetime_token()).map(|l| Name::new_lifetime(&l)), | ||
263 | }, | ||
264 | syntax_ptr, | ||
265 | ) | ||
246 | } | 266 | } |
247 | ast::Expr::ForExpr(e) => { | 267 | ast::Expr::ForExpr(e) => { |
248 | let iterable = self.collect_expr_opt(e.iterable()); | 268 | let iterable = self.collect_expr_opt(e.iterable()); |
249 | let pat = self.collect_pat_opt(e.pat()); | 269 | let pat = self.collect_pat_opt(e.pat()); |
250 | let body = self.collect_block_opt(e.loop_body()); | 270 | let body = self.collect_block_opt(e.loop_body()); |
251 | self.alloc_expr(Expr::For { iterable, pat, body }, syntax_ptr) | 271 | self.alloc_expr( |
272 | Expr::For { | ||
273 | iterable, | ||
274 | pat, | ||
275 | body, | ||
276 | label: e.label().and_then(|l| l.lifetime_token()).map(|l| Name::new_lifetime(&l)), | ||
277 | }, | ||
278 | syntax_ptr, | ||
279 | ) | ||
252 | } | 280 | } |
253 | ast::Expr::CallExpr(e) => { | 281 | ast::Expr::CallExpr(e) => { |
254 | let callee = self.collect_expr_opt(e.expr()); | 282 | let callee = self.collect_expr_opt(e.expr()); |
@@ -301,13 +329,18 @@ impl ExprCollector<'_> { | |||
301 | .unwrap_or(Expr::Missing); | 329 | .unwrap_or(Expr::Missing); |
302 | self.alloc_expr(path, syntax_ptr) | 330 | self.alloc_expr(path, syntax_ptr) |
303 | } | 331 | } |
304 | ast::Expr::ContinueExpr(_e) => { | 332 | ast::Expr::ContinueExpr(e) => { |
305 | // FIXME: labels | 333 | self.alloc_expr( |
306 | self.alloc_expr(Expr::Continue, syntax_ptr) | 334 | Expr::Continue { label: e.lifetime_token().map(|l| Name::new_lifetime(&l)) }, |
335 | syntax_ptr, | ||
336 | ) | ||
307 | } | 337 | } |
308 | ast::Expr::BreakExpr(e) => { | 338 | ast::Expr::BreakExpr(e) => { |
309 | let expr = e.expr().map(|e| self.collect_expr(e)); | 339 | let expr = e.expr().map(|e| self.collect_expr(e)); |
310 | self.alloc_expr(Expr::Break { expr }, syntax_ptr) | 340 | self.alloc_expr( |
341 | Expr::Break { expr, label: e.lifetime_token().map(|l| Name::new_lifetime(&l)) }, | ||
342 | syntax_ptr, | ||
343 | ) | ||
311 | } | 344 | } |
312 | ast::Expr::ParenExpr(e) => { | 345 | ast::Expr::ParenExpr(e) => { |
313 | let inner = self.collect_expr_opt(e.expr()); | 346 | let inner = self.collect_expr_opt(e.expr()); |
@@ -529,7 +562,8 @@ impl ExprCollector<'_> { | |||
529 | }) | 562 | }) |
530 | .collect(); | 563 | .collect(); |
531 | let tail = block.expr().map(|e| self.collect_expr(e)); | 564 | let tail = block.expr().map(|e| self.collect_expr(e)); |
532 | self.alloc_expr(Expr::Block { statements, tail }, syntax_node_ptr) | 565 | let label = block.label().and_then(|l| l.lifetime_token()).map(|t| Name::new_lifetime(&t)); |
566 | self.alloc_expr(Expr::Block { statements, tail, label }, syntax_node_ptr) | ||
533 | } | 567 | } |
534 | 568 | ||
535 | fn collect_block_items(&mut self, block: &ast::BlockExpr) { | 569 | fn collect_block_items(&mut self, block: &ast::BlockExpr) { |
diff --git a/crates/ra_hir_def/src/body/scope.rs b/crates/ra_hir_def/src/body/scope.rs index 09e92b74e..e48ff38f9 100644 --- a/crates/ra_hir_def/src/body/scope.rs +++ b/crates/ra_hir_def/src/body/scope.rs | |||
@@ -138,10 +138,10 @@ fn compute_block_scopes( | |||
138 | fn compute_expr_scopes(expr: ExprId, body: &Body, scopes: &mut ExprScopes, scope: ScopeId) { | 138 | fn compute_expr_scopes(expr: ExprId, body: &Body, scopes: &mut ExprScopes, scope: ScopeId) { |
139 | scopes.set_scope(expr, scope); | 139 | scopes.set_scope(expr, scope); |
140 | match &body[expr] { | 140 | match &body[expr] { |
141 | Expr::Block { statements, tail } => { | 141 | Expr::Block { statements, tail, .. } => { |
142 | compute_block_scopes(&statements, *tail, body, scopes, scope); | 142 | compute_block_scopes(&statements, *tail, body, scopes, scope); |
143 | } | 143 | } |
144 | Expr::For { iterable, pat, body: body_expr } => { | 144 | Expr::For { iterable, pat, body: body_expr, .. } => { |
145 | compute_expr_scopes(*iterable, body, scopes, scope); | 145 | compute_expr_scopes(*iterable, body, scopes, scope); |
146 | let scope = scopes.new_scope(scope); | 146 | let scope = scopes.new_scope(scope); |
147 | scopes.add_bindings(body, scope, *pat); | 147 | scopes.add_bindings(body, scope, *pat); |
diff --git a/crates/ra_hir_def/src/expr.rs b/crates/ra_hir_def/src/expr.rs index f25c6f958..8683f6c7f 100644 --- a/crates/ra_hir_def/src/expr.rs +++ b/crates/ra_hir_def/src/expr.rs | |||
@@ -52,18 +52,22 @@ pub enum Expr { | |||
52 | Block { | 52 | Block { |
53 | statements: Vec<Statement>, | 53 | statements: Vec<Statement>, |
54 | tail: Option<ExprId>, | 54 | tail: Option<ExprId>, |
55 | label: Option<Name>, | ||
55 | }, | 56 | }, |
56 | Loop { | 57 | Loop { |
57 | body: ExprId, | 58 | body: ExprId, |
59 | label: Option<Name>, | ||
58 | }, | 60 | }, |
59 | While { | 61 | While { |
60 | condition: ExprId, | 62 | condition: ExprId, |
61 | body: ExprId, | 63 | body: ExprId, |
64 | label: Option<Name>, | ||
62 | }, | 65 | }, |
63 | For { | 66 | For { |
64 | iterable: ExprId, | 67 | iterable: ExprId, |
65 | pat: PatId, | 68 | pat: PatId, |
66 | body: ExprId, | 69 | body: ExprId, |
70 | label: Option<Name>, | ||
67 | }, | 71 | }, |
68 | Call { | 72 | Call { |
69 | callee: ExprId, | 73 | callee: ExprId, |
@@ -79,9 +83,12 @@ pub enum Expr { | |||
79 | expr: ExprId, | 83 | expr: ExprId, |
80 | arms: Vec<MatchArm>, | 84 | arms: Vec<MatchArm>, |
81 | }, | 85 | }, |
82 | Continue, | 86 | Continue { |
87 | label: Option<Name>, | ||
88 | }, | ||
83 | Break { | 89 | Break { |
84 | expr: Option<ExprId>, | 90 | expr: Option<ExprId>, |
91 | label: Option<Name>, | ||
85 | }, | 92 | }, |
86 | Return { | 93 | Return { |
87 | expr: Option<ExprId>, | 94 | expr: Option<ExprId>, |
@@ -225,7 +232,7 @@ impl Expr { | |||
225 | f(*else_branch); | 232 | f(*else_branch); |
226 | } | 233 | } |
227 | } | 234 | } |
228 | Expr::Block { statements, tail } => { | 235 | Expr::Block { statements, tail, .. } => { |
229 | for stmt in statements { | 236 | for stmt in statements { |
230 | match stmt { | 237 | match stmt { |
231 | Statement::Let { initializer, .. } => { | 238 | Statement::Let { initializer, .. } => { |
@@ -241,8 +248,8 @@ impl Expr { | |||
241 | } | 248 | } |
242 | } | 249 | } |
243 | Expr::TryBlock { body } => f(*body), | 250 | Expr::TryBlock { body } => f(*body), |
244 | Expr::Loop { body } => f(*body), | 251 | Expr::Loop { body, .. } => f(*body), |
245 | Expr::While { condition, body } => { | 252 | Expr::While { condition, body, .. } => { |
246 | f(*condition); | 253 | f(*condition); |
247 | f(*body); | 254 | f(*body); |
248 | } | 255 | } |
@@ -268,8 +275,8 @@ impl Expr { | |||
268 | f(arm.expr); | 275 | f(arm.expr); |
269 | } | 276 | } |
270 | } | 277 | } |
271 | Expr::Continue => {} | 278 | Expr::Continue { .. } => {}, |
272 | Expr::Break { expr } | Expr::Return { expr } => { | 279 | Expr::Break { expr, .. } | Expr::Return { expr } => { |
273 | if let Some(expr) = expr { | 280 | if let Some(expr) = expr { |
274 | f(*expr); | 281 | f(*expr); |
275 | } | 282 | } |
diff --git a/crates/ra_hir_expand/src/name.rs b/crates/ra_hir_expand/src/name.rs index fecce224e..ea495cb11 100644 --- a/crates/ra_hir_expand/src/name.rs +++ b/crates/ra_hir_expand/src/name.rs | |||
@@ -37,6 +37,11 @@ impl Name { | |||
37 | Name(Repr::TupleField(idx)) | 37 | Name(Repr::TupleField(idx)) |
38 | } | 38 | } |
39 | 39 | ||
40 | pub fn new_lifetime(lt: &ra_syntax::SyntaxToken) -> Name { | ||
41 | assert!(lt.kind() == ra_syntax::SyntaxKind::LIFETIME); | ||
42 | Name(Repr::Text(lt.text().clone())) | ||
43 | } | ||
44 | |||
40 | /// Shortcut to create inline plain text name | 45 | /// Shortcut to create inline plain text name |
41 | const fn new_inline_ascii(text: &[u8]) -> Name { | 46 | const fn new_inline_ascii(text: &[u8]) -> Name { |
42 | Name::new_text(SmolStr::new_inline_from_ascii(text.len(), text)) | 47 | Name::new_text(SmolStr::new_inline_from_ascii(text.len(), text)) |
diff --git a/crates/ra_hir_ty/src/infer.rs b/crates/ra_hir_ty/src/infer.rs index 957d6e0b5..dc77e88e5 100644 --- a/crates/ra_hir_ty/src/infer.rs +++ b/crates/ra_hir_ty/src/infer.rs | |||
@@ -219,6 +219,17 @@ struct InferenceContext<'a> { | |||
219 | struct BreakableContext { | 219 | struct BreakableContext { |
220 | pub may_break: bool, | 220 | pub may_break: bool, |
221 | pub break_ty: Ty, | 221 | pub break_ty: Ty, |
222 | pub label: Option<name::Name>, | ||
223 | } | ||
224 | |||
225 | fn find_breakable<'c>( | ||
226 | ctxs: &'c mut [BreakableContext], | ||
227 | label: Option<&name::Name>, | ||
228 | ) -> Option<&'c mut BreakableContext> { | ||
229 | match label { | ||
230 | Some(_) => ctxs.iter_mut().rev().find(|ctx| ctx.label.as_ref() == label), | ||
231 | None => ctxs.last_mut(), | ||
232 | } | ||
222 | } | 233 | } |
223 | 234 | ||
224 | impl<'a> InferenceContext<'a> { | 235 | impl<'a> InferenceContext<'a> { |
diff --git a/crates/ra_hir_ty/src/infer/expr.rs b/crates/ra_hir_ty/src/infer/expr.rs index 78084cb57..4a98e2deb 100644 --- a/crates/ra_hir_ty/src/infer/expr.rs +++ b/crates/ra_hir_ty/src/infer/expr.rs | |||
@@ -22,8 +22,8 @@ use crate::{ | |||
22 | }; | 22 | }; |
23 | 23 | ||
24 | use super::{ | 24 | use super::{ |
25 | BindingMode, BreakableContext, Diverges, Expectation, InferenceContext, InferenceDiagnostic, | 25 | find_breakable, BindingMode, BreakableContext, Diverges, Expectation, InferenceContext, |
26 | TypeMismatch, | 26 | InferenceDiagnostic, TypeMismatch, |
27 | }; | 27 | }; |
28 | 28 | ||
29 | impl<'a> InferenceContext<'a> { | 29 | impl<'a> InferenceContext<'a> { |
@@ -86,16 +86,20 @@ impl<'a> InferenceContext<'a> { | |||
86 | 86 | ||
87 | self.coerce_merge_branch(&then_ty, &else_ty) | 87 | self.coerce_merge_branch(&then_ty, &else_ty) |
88 | } | 88 | } |
89 | Expr::Block { statements, tail } => self.infer_block(statements, *tail, expected), | 89 | Expr::Block { statements, tail, .. } => { |
90 | // FIXME: Breakable block inference | ||
91 | self.infer_block(statements, *tail, expected) | ||
92 | } | ||
90 | Expr::TryBlock { body } => { | 93 | Expr::TryBlock { body } => { |
91 | let _inner = self.infer_expr(*body, expected); | 94 | let _inner = self.infer_expr(*body, expected); |
92 | // FIXME should be std::result::Result<{inner}, _> | 95 | // FIXME should be std::result::Result<{inner}, _> |
93 | Ty::Unknown | 96 | Ty::Unknown |
94 | } | 97 | } |
95 | Expr::Loop { body } => { | 98 | Expr::Loop { body, label } => { |
96 | self.breakables.push(BreakableContext { | 99 | self.breakables.push(BreakableContext { |
97 | may_break: false, | 100 | may_break: false, |
98 | break_ty: self.table.new_type_var(), | 101 | break_ty: self.table.new_type_var(), |
102 | label: label.clone(), | ||
99 | }); | 103 | }); |
100 | self.infer_expr(*body, &Expectation::has_type(Ty::unit())); | 104 | self.infer_expr(*body, &Expectation::has_type(Ty::unit())); |
101 | 105 | ||
@@ -110,8 +114,12 @@ impl<'a> InferenceContext<'a> { | |||
110 | Ty::simple(TypeCtor::Never) | 114 | Ty::simple(TypeCtor::Never) |
111 | } | 115 | } |
112 | } | 116 | } |
113 | Expr::While { condition, body } => { | 117 | Expr::While { condition, body, label } => { |
114 | self.breakables.push(BreakableContext { may_break: false, break_ty: Ty::Unknown }); | 118 | self.breakables.push(BreakableContext { |
119 | may_break: false, | ||
120 | break_ty: Ty::Unknown, | ||
121 | label: label.clone(), | ||
122 | }); | ||
115 | // while let is desugared to a match loop, so this is always simple while | 123 | // while let is desugared to a match loop, so this is always simple while |
116 | self.infer_expr(*condition, &Expectation::has_type(Ty::simple(TypeCtor::Bool))); | 124 | self.infer_expr(*condition, &Expectation::has_type(Ty::simple(TypeCtor::Bool))); |
117 | self.infer_expr(*body, &Expectation::has_type(Ty::unit())); | 125 | self.infer_expr(*body, &Expectation::has_type(Ty::unit())); |
@@ -120,10 +128,14 @@ impl<'a> InferenceContext<'a> { | |||
120 | self.diverges = Diverges::Maybe; | 128 | self.diverges = Diverges::Maybe; |
121 | Ty::unit() | 129 | Ty::unit() |
122 | } | 130 | } |
123 | Expr::For { iterable, body, pat } => { | 131 | Expr::For { iterable, body, pat, label } => { |
124 | let iterable_ty = self.infer_expr(*iterable, &Expectation::none()); | 132 | let iterable_ty = self.infer_expr(*iterable, &Expectation::none()); |
125 | 133 | ||
126 | self.breakables.push(BreakableContext { may_break: false, break_ty: Ty::Unknown }); | 134 | self.breakables.push(BreakableContext { |
135 | may_break: false, | ||
136 | break_ty: Ty::Unknown, | ||
137 | label: label.clone(), | ||
138 | }); | ||
127 | let pat_ty = | 139 | let pat_ty = |
128 | self.resolve_associated_type(iterable_ty, self.resolve_into_iter_item()); | 140 | self.resolve_associated_type(iterable_ty, self.resolve_into_iter_item()); |
129 | 141 | ||
@@ -236,23 +248,24 @@ impl<'a> InferenceContext<'a> { | |||
236 | let resolver = resolver_for_expr(self.db.upcast(), self.owner, tgt_expr); | 248 | let resolver = resolver_for_expr(self.db.upcast(), self.owner, tgt_expr); |
237 | self.infer_path(&resolver, p, tgt_expr.into()).unwrap_or(Ty::Unknown) | 249 | self.infer_path(&resolver, p, tgt_expr.into()).unwrap_or(Ty::Unknown) |
238 | } | 250 | } |
239 | Expr::Continue => Ty::simple(TypeCtor::Never), | 251 | Expr::Continue { .. } => Ty::simple(TypeCtor::Never), |
240 | Expr::Break { expr } => { | 252 | Expr::Break { expr, label } => { |
241 | let val_ty = if let Some(expr) = expr { | 253 | let val_ty = if let Some(expr) = expr { |
242 | self.infer_expr(*expr, &Expectation::none()) | 254 | self.infer_expr(*expr, &Expectation::none()) |
243 | } else { | 255 | } else { |
244 | Ty::unit() | 256 | Ty::unit() |
245 | }; | 257 | }; |
246 | 258 | ||
247 | let last_ty = if let Some(ctxt) = self.breakables.last() { | 259 | let last_ty = |
248 | ctxt.break_ty.clone() | 260 | if let Some(ctxt) = find_breakable(&mut self.breakables, label.as_ref()) { |
249 | } else { | 261 | ctxt.break_ty.clone() |
250 | Ty::Unknown | 262 | } else { |
251 | }; | 263 | Ty::Unknown |
264 | }; | ||
252 | 265 | ||
253 | let merged_type = self.coerce_merge_branch(&last_ty, &val_ty); | 266 | let merged_type = self.coerce_merge_branch(&last_ty, &val_ty); |
254 | 267 | ||
255 | if let Some(ctxt) = self.breakables.last_mut() { | 268 | if let Some(ctxt) = find_breakable(&mut self.breakables, label.as_ref()) { |
256 | ctxt.break_ty = merged_type; | 269 | ctxt.break_ty = merged_type; |
257 | ctxt.may_break = true; | 270 | ctxt.may_break = true; |
258 | } else { | 271 | } else { |
diff --git a/crates/ra_hir_ty/src/tests/simple.rs b/crates/ra_hir_ty/src/tests/simple.rs index beceb8634..88309157b 100644 --- a/crates/ra_hir_ty/src/tests/simple.rs +++ b/crates/ra_hir_ty/src/tests/simple.rs | |||
@@ -1969,17 +1969,17 @@ fn foo() { | |||
1969 | 25..333 '|| 'ou... }': || -> bool | 1969 | 25..333 '|| 'ou... }': || -> bool |
1970 | 28..333 ''outer... }': bool | 1970 | 28..333 ''outer... }': bool |
1971 | 41..333 '{ ... }': () | 1971 | 41..333 '{ ... }': () |
1972 | 55..60 'inner': i32 | 1972 | 55..60 'inner': i8 |
1973 | 63..301 ''inner... }': i32 | 1973 | 63..301 ''inner... }': i8 |
1974 | 76..301 '{ ... }': () | 1974 | 76..301 '{ ... }': () |
1975 | 94..95 'i': i32 | 1975 | 94..95 'i': bool |
1976 | 98..114 'Defaul...efault': {unknown} | 1976 | 98..114 'Defaul...efault': {unknown} |
1977 | 98..116 'Defaul...ault()': i32 | 1977 | 98..116 'Defaul...ault()': bool |
1978 | 130..270 'if (br... }': () | 1978 | 130..270 'if (br... }': () |
1979 | 134..148 'break 'outer i': ! | 1979 | 134..148 'break 'outer i': ! |
1980 | 147..148 'i': i32 | 1980 | 147..148 'i': bool |
1981 | 150..209 '{ ... }': () | 1981 | 150..209 '{ ... }': () |
1982 | 168..194 'loop {...5i8; }': i8 | 1982 | 168..194 'loop {...5i8; }': ! |
1983 | 173..194 '{ brea...5i8; }': () | 1983 | 173..194 '{ brea...5i8; }': () |
1984 | 175..191 'break ...er 5i8': ! | 1984 | 175..191 'break ...er 5i8': ! |
1985 | 188..191 '5i8': i8 | 1985 | 188..191 '5i8': i8 |
@@ -1987,13 +1987,13 @@ fn foo() { | |||
1987 | 218..222 'true': bool | 1987 | 218..222 'true': bool |
1988 | 223..270 '{ ... }': () | 1988 | 223..270 '{ ... }': () |
1989 | 241..255 'break 'inner 6': ! | 1989 | 241..255 'break 'inner 6': ! |
1990 | 254..255 '6': i32 | 1990 | 254..255 '6': i8 |
1991 | 283..290 'break 7': ! | 1991 | 283..290 'break 7': ! |
1992 | 289..290 '7': i32 | 1992 | 289..290 '7': i8 |
1993 | 311..326 'break inner < 8': ! | 1993 | 311..326 'break inner < 8': ! |
1994 | 317..322 'inner': i32 | 1994 | 317..322 'inner': i8 |
1995 | 317..326 'inner < 8': bool | 1995 | 317..326 'inner < 8': bool |
1996 | 325..326 '8': i32 | 1996 | 325..326 '8': i8 |
1997 | "### | 1997 | "### |
1998 | ); | 1998 | ); |
1999 | } | 1999 | } |
diff --git a/crates/ra_syntax/src/ast/generated/nodes.rs b/crates/ra_syntax/src/ast/generated/nodes.rs index 255402fbc..cb430ca01 100644 --- a/crates/ra_syntax/src/ast/generated/nodes.rs +++ b/crates/ra_syntax/src/ast/generated/nodes.rs | |||
@@ -1081,6 +1081,7 @@ pub struct BlockExpr { | |||
1081 | impl ast::AttrsOwner for BlockExpr {} | 1081 | impl ast::AttrsOwner for BlockExpr {} |
1082 | impl ast::ModuleItemOwner for BlockExpr {} | 1082 | impl ast::ModuleItemOwner for BlockExpr {} |
1083 | impl BlockExpr { | 1083 | impl BlockExpr { |
1084 | pub fn label(&self) -> Option<Label> { support::child(&self.syntax) } | ||
1084 | pub fn l_curly_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['{']) } | 1085 | pub fn l_curly_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['{']) } |
1085 | pub fn statements(&self) -> AstChildren<Stmt> { support::children(&self.syntax) } | 1086 | pub fn statements(&self) -> AstChildren<Stmt> { support::children(&self.syntax) } |
1086 | pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) } | 1087 | pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) } |