aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAleksey Kladov <[email protected]>2018-08-27 10:22:09 +0100
committerAleksey Kladov <[email protected]>2018-08-27 10:22:09 +0100
commit07cbb7d73deed8dac3eecdbdc7e1eaf6938a6cd6 (patch)
tree4a1fa22fa8c908f0c3c9489a98aa2479f05def59
parentc16530c988e817c5596fa38ebe9e12a302886a8f (diff)
Support if-let in scopes
-rw-r--r--crates/libeditor/src/completion.rs101
-rw-r--r--crates/libeditor/tests/test.rs13
-rw-r--r--crates/libsyntax2/src/ast/generated.rs66
-rw-r--r--crates/libsyntax2/src/ast/mod.rs12
-rw-r--r--crates/libsyntax2/src/grammar.ron36
-rw-r--r--crates/libsyntax2/src/grammar/expressions/atom.rs4
-rw-r--r--crates/libsyntax2/src/syntax_kinds/generated.rs6
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0065_if_expr.txt31
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0076_cond.txt39
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0077_while_expr.txt60
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0086_no_semi_after_block.txt10
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0107_label.txt5
12 files changed, 284 insertions, 99 deletions
diff --git a/crates/libeditor/src/completion.rs b/crates/libeditor/src/completion.rs
index ec9388ee3..69c039e83 100644
--- a/crates/libeditor/src/completion.rs
+++ b/crates/libeditor/src/completion.rs
@@ -1,4 +1,7 @@
1use std::collections::HashMap; 1use std::{
2 fmt,
3 collections::HashMap,
4};
2 5
3use libsyntax2::{ 6use libsyntax2::{
4 File, TextUnit, AstNode, SyntaxNodeRef, SyntaxNode, SmolStr, 7 File, TextUnit, AstNode, SyntaxNodeRef, SyntaxNode, SmolStr,
@@ -49,33 +52,89 @@ fn compute_scopes(fn_def: ast::FnDef) -> FnScopes {
49 .filter_map(|it| it.pat()) 52 .filter_map(|it| it.pat())
50 .for_each(|it| scopes.add_bindings(root, it)); 53 .for_each(|it| scopes.add_bindings(root, it));
51 54
52 let mut scope = root;
53 if let Some(body) = fn_def.body() { 55 if let Some(body) = fn_def.body() {
54 for stmt in body.statements() { 56 compute_block_scopes(body, &mut scopes, root)
55 match stmt { 57 }
56 ast::Stmt::LetStmt(stmt) => { 58 scopes
57 scope = scopes.new_scope(scope); 59}
58 if let Some(pat) = stmt.pat() { 60
59 scopes.add_bindings(scope, pat); 61fn compute_block_scopes(block: ast::Block, scopes: &mut FnScopes, mut scope: ScopeId) {
60 } 62 for stmt in block.statements() {
61 if let Some(expr) = stmt.initializer() { 63 match stmt {
62 scopes.set_scope(expr.syntax(), scope) 64 ast::Stmt::LetStmt(stmt) => {
63 } 65 scope = scopes.new_scope(scope);
66 if let Some(pat) = stmt.pat() {
67 scopes.add_bindings(scope, pat);
64 } 68 }
65 ast::Stmt::ExprStmt(expr) => { 69 if let Some(expr) = stmt.initializer() {
66 scopes.set_scope(expr.syntax(), scope) 70 scopes.set_scope(expr.syntax(), scope)
67 } 71 }
68 } 72 }
73 ast::Stmt::ExprStmt(expr_stmt) => {
74 if let Some(expr) = expr_stmt.expr() {
75 scopes.set_scope(expr.syntax(), scope);
76 compute_expr_scopes(expr, scopes, scope);
77 }
78 }
79 }
80 }
81 if let Some(expr) = block.expr() {
82 scopes.set_scope(expr.syntax(), scope);
83 compute_expr_scopes(expr, scopes, scope);
84 }
85}
86
87fn compute_expr_scopes(expr: ast::Expr, scopes: &mut FnScopes, scope: ScopeId) {
88 match expr {
89 ast::Expr::IfExpr(e) => {
90 let cond_scope = e.condition().and_then(|cond| {
91 compute_cond_scopes(cond, scopes, scope)
92 });
93 if let Some(block) = e.then_branch() {
94 compute_block_scopes(block, scopes, cond_scope.unwrap_or(scope));
95 }
96 if let Some(block) = e.else_branch() {
97 compute_block_scopes(block, scopes, scope);
98 }
99 },
100 ast::Expr::WhileExpr(e) => {
101 let cond_scope = e.condition().and_then(|cond| {
102 compute_cond_scopes(cond, scopes, scope)
103 });
104 if let Some(block) = e.body() {
105 compute_block_scopes(block, scopes, cond_scope.unwrap_or(scope));
106 }
107 },
108 ast::Expr::BlockExpr(e) => {
109 if let Some(block) = e.block() {
110 compute_block_scopes(block, scopes, scope);
111 }
69 } 112 }
70 if let Some(expr) = body.expr() { 113 // ForExpr(e) => TODO,
71 scopes.set_scope(expr.syntax(), scope) 114 _ => {
115 expr.syntax().children()
116 .filter_map(ast::Expr::cast)
117 .for_each(|expr| compute_expr_scopes(expr, scopes, scope))
118 }
119 };
120
121 fn compute_cond_scopes(cond: ast::Condition, scopes: &mut FnScopes, scope: ScopeId) -> Option<ScopeId> {
122 if let Some(expr) = cond.expr() {
123 compute_expr_scopes(expr, scopes, scope);
124 }
125 if let Some(pat) = cond.pat() {
126 let s = scopes.new_scope(scope);
127 scopes.add_bindings(s, pat);
128 Some(s)
129 } else {
130 None
72 } 131 }
73 } 132 }
74 scopes
75} 133}
76 134
77type ScopeId = usize; 135type ScopeId = usize;
78 136
137#[derive(Debug)]
79struct FnScopes { 138struct FnScopes {
80 scopes: Vec<ScopeData>, 139 scopes: Vec<ScopeData>,
81 scope_for: HashMap<SyntaxNode, ScopeId>, 140 scope_for: HashMap<SyntaxNode, ScopeId>,
@@ -120,6 +179,7 @@ impl FnScopes {
120 } 179 }
121} 180}
122 181
182#[derive(Debug)]
123struct ScopeData { 183struct ScopeData {
124 parent: Option<ScopeId>, 184 parent: Option<ScopeId>,
125 entries: Vec<ScopeEntry> 185 entries: Vec<ScopeEntry>
@@ -149,3 +209,12 @@ impl ScopeEntry {
149 .unwrap() 209 .unwrap()
150 } 210 }
151} 211}
212
213impl fmt::Debug for ScopeEntry {
214 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
215 f.debug_struct("ScopeEntry")
216 .field("name", &self.name())
217 .field("syntax", &self.syntax)
218 .finish()
219 }
220}
diff --git a/crates/libeditor/tests/test.rs b/crates/libeditor/tests/test.rs
index 7979bfffe..d051980b0 100644
--- a/crates/libeditor/tests/test.rs
+++ b/crates/libeditor/tests/test.rs
@@ -273,6 +273,19 @@ fn quux(x: i32) {
273} 273}
274", r#"[CompletionItem { name: "y" }, 274", r#"[CompletionItem { name: "y" },
275 CompletionItem { name: "x" }]"#); 275 CompletionItem { name: "x" }]"#);
276
277 do_check(r"
278fn quux() {
279 if let Some(x) = foo() {
280 let y = 92;
281 };
282 if let Some(a) = bar() {
283 let b = 62;
284 1 + <|>
285 }
286}
287", r#"[CompletionItem { name: "b" },
288 CompletionItem { name: "a" }]"#);
276} 289}
277 290
278fn file(text: &str) -> File { 291fn file(text: &str) -> File {
diff --git a/crates/libsyntax2/src/ast/generated.rs b/crates/libsyntax2/src/ast/generated.rs
index 1dd161f52..6891e857c 100644
--- a/crates/libsyntax2/src/ast/generated.rs
+++ b/crates/libsyntax2/src/ast/generated.rs
@@ -141,7 +141,11 @@ impl<'a> AstNode<'a> for BlockExpr<'a> {
141 fn syntax(self) -> SyntaxNodeRef<'a> { self.syntax } 141 fn syntax(self) -> SyntaxNodeRef<'a> { self.syntax }
142} 142}
143 143
144impl<'a> BlockExpr<'a> {} 144impl<'a> BlockExpr<'a> {
145 pub fn block(self) -> Option<Block<'a>> {
146 super::child_opt(self)
147 }
148}
145 149
146// BreakExpr 150// BreakExpr
147#[derive(Debug, Clone, Copy)] 151#[derive(Debug, Clone, Copy)]
@@ -197,6 +201,32 @@ impl<'a> AstNode<'a> for CastExpr<'a> {
197 201
198impl<'a> CastExpr<'a> {} 202impl<'a> CastExpr<'a> {}
199 203
204// Condition
205#[derive(Debug, Clone, Copy)]
206pub struct Condition<'a> {
207 syntax: SyntaxNodeRef<'a>,
208}
209
210impl<'a> AstNode<'a> for Condition<'a> {
211 fn cast(syntax: SyntaxNodeRef<'a>) -> Option<Self> {
212 match syntax.kind() {
213 CONDITION => Some(Condition { syntax }),
214 _ => None,
215 }
216 }
217 fn syntax(self) -> SyntaxNodeRef<'a> { self.syntax }
218}
219
220impl<'a> Condition<'a> {
221 pub fn pat(self) -> Option<Pat<'a>> {
222 super::child_opt(self)
223 }
224
225 pub fn expr(self) -> Option<Expr<'a>> {
226 super::child_opt(self)
227 }
228}
229
200// ConstDef 230// ConstDef
201#[derive(Debug, Clone, Copy)] 231#[derive(Debug, Clone, Copy)]
202pub struct ConstDef<'a> { 232pub struct ConstDef<'a> {
@@ -403,7 +433,11 @@ impl<'a> AstNode<'a> for ExprStmt<'a> {
403 fn syntax(self) -> SyntaxNodeRef<'a> { self.syntax } 433 fn syntax(self) -> SyntaxNodeRef<'a> { self.syntax }
404} 434}
405 435
406impl<'a> ExprStmt<'a> {} 436impl<'a> ExprStmt<'a> {
437 pub fn expr(self) -> Option<Expr<'a>> {
438 super::child_opt(self)
439 }
440}
407 441
408// FieldExpr 442// FieldExpr
409#[derive(Debug, Clone, Copy)] 443#[derive(Debug, Clone, Copy)]
@@ -504,7 +538,11 @@ impl<'a> AstNode<'a> for ForExpr<'a> {
504 fn syntax(self) -> SyntaxNodeRef<'a> { self.syntax } 538 fn syntax(self) -> SyntaxNodeRef<'a> { self.syntax }
505} 539}
506 540
507impl<'a> ForExpr<'a> {} 541impl<'a> ForExpr<'a> {
542 pub fn body(self) -> Option<Block<'a>> {
543 super::child_opt(self)
544 }
545}
508 546
509// ForType 547// ForType
510#[derive(Debug, Clone, Copy)] 548#[derive(Debug, Clone, Copy)]
@@ -540,7 +578,11 @@ impl<'a> AstNode<'a> for IfExpr<'a> {
540 fn syntax(self) -> SyntaxNodeRef<'a> { self.syntax } 578 fn syntax(self) -> SyntaxNodeRef<'a> { self.syntax }
541} 579}
542 580
543impl<'a> IfExpr<'a> {} 581impl<'a> IfExpr<'a> {
582 pub fn condition(self) -> Option<Condition<'a>> {
583 super::child_opt(self)
584 }
585}
544 586
545// ImplItem 587// ImplItem
546#[derive(Debug, Clone, Copy)] 588#[derive(Debug, Clone, Copy)]
@@ -674,7 +716,11 @@ impl<'a> AstNode<'a> for LoopExpr<'a> {
674 fn syntax(self) -> SyntaxNodeRef<'a> { self.syntax } 716 fn syntax(self) -> SyntaxNodeRef<'a> { self.syntax }
675} 717}
676 718
677impl<'a> LoopExpr<'a> {} 719impl<'a> LoopExpr<'a> {
720 pub fn body(self) -> Option<Block<'a>> {
721 super::child_opt(self)
722 }
723}
678 724
679// MatchArm 725// MatchArm
680#[derive(Debug, Clone, Copy)] 726#[derive(Debug, Clone, Copy)]
@@ -1742,5 +1788,13 @@ impl<'a> AstNode<'a> for WhileExpr<'a> {
1742 fn syntax(self) -> SyntaxNodeRef<'a> { self.syntax } 1788 fn syntax(self) -> SyntaxNodeRef<'a> { self.syntax }
1743} 1789}
1744 1790
1745impl<'a> WhileExpr<'a> {} 1791impl<'a> WhileExpr<'a> {
1792 pub fn condition(self) -> Option<Condition<'a>> {
1793 super::child_opt(self)
1794 }
1795
1796 pub fn body(self) -> Option<Block<'a>> {
1797 super::child_opt(self)
1798 }
1799}
1746 1800
diff --git a/crates/libsyntax2/src/ast/mod.rs b/crates/libsyntax2/src/ast/mod.rs
index 6217c5b74..2ebee6a4f 100644
--- a/crates/libsyntax2/src/ast/mod.rs
+++ b/crates/libsyntax2/src/ast/mod.rs
@@ -115,6 +115,18 @@ impl<'a> Module<'a> {
115 } 115 }
116} 116}
117 117
118impl<'a> IfExpr<'a> {
119 pub fn then_branch(self) -> Option<Block<'a>> {
120 self.blocks().nth(0)
121 }
122 pub fn else_branch(self) -> Option<Block<'a>> {
123 self.blocks().nth(1)
124 }
125 fn blocks(self) -> impl Iterator<Item=Block<'a>> {
126 children(self)
127 }
128}
129
118fn child_opt<'a, P: AstNode<'a>, C: AstNode<'a>>(parent: P) -> Option<C> { 130fn child_opt<'a, P: AstNode<'a>, C: AstNode<'a>>(parent: P) -> Option<C> {
119 children(parent).next() 131 children(parent).next()
120} 132}
diff --git a/crates/libsyntax2/src/grammar.ron b/crates/libsyntax2/src/grammar.ron
index f3c3d3036..c9e128462 100644
--- a/crates/libsyntax2/src/grammar.ron
+++ b/crates/libsyntax2/src/grammar.ron
@@ -162,9 +162,10 @@ Grammar(
162 "PATH_EXPR", 162 "PATH_EXPR",
163 "LAMBDA_EXPR", 163 "LAMBDA_EXPR",
164 "IF_EXPR", 164 "IF_EXPR",
165 "WHILE_EXPR",
166 "CONDITION",
165 "LOOP_EXPR", 167 "LOOP_EXPR",
166 "FOR_EXPR", 168 "FOR_EXPR",
167 "WHILE_EXPR",
168 "CONTINUE_EXPR", 169 "CONTINUE_EXPR",
169 "BREAK_EXPR", 170 "BREAK_EXPR",
170 "LABEL", 171 "LABEL",
@@ -336,14 +337,27 @@ Grammar(
336 "ParenExpr": (), 337 "ParenExpr": (),
337 "PathExpr": (), 338 "PathExpr": (),
338 "LambdaExpr": (), 339 "LambdaExpr": (),
339 "IfExpr": (), 340 "IfExpr": (
340 "LoopExpr": (), 341 options: [ ["condition", "Condition"] ]
341 "ForExpr": (), 342 ),
342 "WhileExpr": (), 343 "LoopExpr": (
344 options: [ ["body", "Block"] ]
345 ),
346 "ForExpr": (
347 options: [ ["body", "Block"] ]
348 ),
349 "WhileExpr": (
350 options: [
351 ["condition", "Condition"],
352 ["body", "Block"],
353 ]
354 ),
343 "ContinueExpr": (), 355 "ContinueExpr": (),
344 "BreakExpr": (), 356 "BreakExpr": (),
345 "Label": (), 357 "Label": (),
346 "BlockExpr": (), 358 "BlockExpr": (
359 options: [ ["block", "Block"] ]
360 ),
347 "ReturnExpr": (), 361 "ReturnExpr": (),
348 "MatchExpr": (), 362 "MatchExpr": (),
349 "MatchArmList": (), 363 "MatchArmList": (),
@@ -432,11 +446,19 @@ Grammar(
432 "TypeParamList": ( collections: [ ["type_params", "TypeParam" ] ]), 446 "TypeParamList": ( collections: [ ["type_params", "TypeParam" ] ]),
433 "TypeParam": ( traits: ["NameOwner"] ), 447 "TypeParam": ( traits: ["NameOwner"] ),
434 "WhereClause": (), 448 "WhereClause": (),
435 "ExprStmt": (), 449 "ExprStmt": (
450 options: [ ["expr", "Expr"] ]
451 ),
436 "LetStmt": ( options: [ 452 "LetStmt": ( options: [
437 ["pat", "Pat"], 453 ["pat", "Pat"],
438 ["initializer", "Expr"], 454 ["initializer", "Expr"],
439 ]), 455 ]),
456 "Condition": (
457 options: [
458 [ "pat", "Pat" ],
459 [ "expr", "Expr" ],
460 ]
461 ),
440 "Stmt": ( 462 "Stmt": (
441 enum: ["ExprStmt", "LetStmt"], 463 enum: ["ExprStmt", "LetStmt"],
442 ), 464 ),
diff --git a/crates/libsyntax2/src/grammar/expressions/atom.rs b/crates/libsyntax2/src/grammar/expressions/atom.rs
index d9c3f998a..bb5402af7 100644
--- a/crates/libsyntax2/src/grammar/expressions/atom.rs
+++ b/crates/libsyntax2/src/grammar/expressions/atom.rs
@@ -237,11 +237,13 @@ fn for_expr(p: &mut Parser, m: Option<Marker>) -> CompletedMarker {
237// test cond 237// test cond
238// fn foo() { if let Some(_) = None {} } 238// fn foo() { if let Some(_) = None {} }
239fn cond(p: &mut Parser) { 239fn cond(p: &mut Parser) {
240 let m = p.start();
240 if p.eat(LET_KW) { 241 if p.eat(LET_KW) {
241 patterns::pattern(p); 242 patterns::pattern(p);
242 p.expect(EQ); 243 p.expect(EQ);
243 } 244 }
244 expr_no_struct(p) 245 expr_no_struct(p);
246 m.complete(p, CONDITION);
245} 247}
246 248
247// test match_expr 249// test match_expr
diff --git a/crates/libsyntax2/src/syntax_kinds/generated.rs b/crates/libsyntax2/src/syntax_kinds/generated.rs
index 6a24cb19e..0a22b11c2 100644
--- a/crates/libsyntax2/src/syntax_kinds/generated.rs
+++ b/crates/libsyntax2/src/syntax_kinds/generated.rs
@@ -158,9 +158,10 @@ pub enum SyntaxKind {
158 PATH_EXPR, 158 PATH_EXPR,
159 LAMBDA_EXPR, 159 LAMBDA_EXPR,
160 IF_EXPR, 160 IF_EXPR,
161 WHILE_EXPR,
162 CONDITION,
161 LOOP_EXPR, 163 LOOP_EXPR,
162 FOR_EXPR, 164 FOR_EXPR,
163 WHILE_EXPR,
164 CONTINUE_EXPR, 165 CONTINUE_EXPR,
165 BREAK_EXPR, 166 BREAK_EXPR,
166 LABEL, 167 LABEL,
@@ -418,9 +419,10 @@ impl SyntaxKind {
418 PATH_EXPR => &SyntaxInfo { name: "PATH_EXPR" }, 419 PATH_EXPR => &SyntaxInfo { name: "PATH_EXPR" },
419 LAMBDA_EXPR => &SyntaxInfo { name: "LAMBDA_EXPR" }, 420 LAMBDA_EXPR => &SyntaxInfo { name: "LAMBDA_EXPR" },
420 IF_EXPR => &SyntaxInfo { name: "IF_EXPR" }, 421 IF_EXPR => &SyntaxInfo { name: "IF_EXPR" },
422 WHILE_EXPR => &SyntaxInfo { name: "WHILE_EXPR" },
423 CONDITION => &SyntaxInfo { name: "CONDITION" },
421 LOOP_EXPR => &SyntaxInfo { name: "LOOP_EXPR" }, 424 LOOP_EXPR => &SyntaxInfo { name: "LOOP_EXPR" },
422 FOR_EXPR => &SyntaxInfo { name: "FOR_EXPR" }, 425 FOR_EXPR => &SyntaxInfo { name: "FOR_EXPR" },
423 WHILE_EXPR => &SyntaxInfo { name: "WHILE_EXPR" },
424 CONTINUE_EXPR => &SyntaxInfo { name: "CONTINUE_EXPR" }, 426 CONTINUE_EXPR => &SyntaxInfo { name: "CONTINUE_EXPR" },
425 BREAK_EXPR => &SyntaxInfo { name: "BREAK_EXPR" }, 427 BREAK_EXPR => &SyntaxInfo { name: "BREAK_EXPR" },
426 LABEL => &SyntaxInfo { name: "LABEL" }, 428 LABEL => &SyntaxInfo { name: "LABEL" },
diff --git a/crates/libsyntax2/tests/data/parser/inline/0065_if_expr.txt b/crates/libsyntax2/tests/data/parser/inline/0065_if_expr.txt
index 290b11d33..ae1a8101e 100644
--- a/crates/libsyntax2/tests/data/parser/inline/0065_if_expr.txt
+++ b/crates/libsyntax2/tests/data/parser/inline/0065_if_expr.txt
@@ -15,8 +15,9 @@ ROOT@[0; 107)
15 IF_EXPR@[15; 25) 15 IF_EXPR@[15; 25)
16 IF_KW@[15; 17) 16 IF_KW@[15; 17)
17 WHITESPACE@[17; 18) 17 WHITESPACE@[17; 18)
18 LITERAL@[18; 22) 18 CONDITION@[18; 22)
19 TRUE_KW@[18; 22) 19 LITERAL@[18; 22)
20 TRUE_KW@[18; 22)
20 WHITESPACE@[22; 23) 21 WHITESPACE@[22; 23)
21 BLOCK@[23; 25) 22 BLOCK@[23; 25)
22 L_CURLY@[23; 24) 23 L_CURLY@[23; 24)
@@ -27,8 +28,9 @@ ROOT@[0; 107)
27 IF_EXPR@[31; 49) 28 IF_EXPR@[31; 49)
28 IF_KW@[31; 33) 29 IF_KW@[31; 33)
29 WHITESPACE@[33; 34) 30 WHITESPACE@[33; 34)
30 LITERAL@[34; 38) 31 CONDITION@[34; 38)
31 TRUE_KW@[34; 38) 32 LITERAL@[34; 38)
33 TRUE_KW@[34; 38)
32 WHITESPACE@[38; 39) 34 WHITESPACE@[38; 39)
33 BLOCK@[39; 41) 35 BLOCK@[39; 41)
34 L_CURLY@[39; 40) 36 L_CURLY@[39; 40)
@@ -45,8 +47,9 @@ ROOT@[0; 107)
45 IF_EXPR@[55; 90) 47 IF_EXPR@[55; 90)
46 IF_KW@[55; 57) 48 IF_KW@[55; 57)
47 WHITESPACE@[57; 58) 49 WHITESPACE@[57; 58)
48 LITERAL@[58; 62) 50 CONDITION@[58; 62)
49 TRUE_KW@[58; 62) 51 LITERAL@[58; 62)
52 TRUE_KW@[58; 62)
50 WHITESPACE@[62; 63) 53 WHITESPACE@[62; 63)
51 BLOCK@[63; 65) 54 BLOCK@[63; 65)
52 L_CURLY@[63; 64) 55 L_CURLY@[63; 64)
@@ -57,8 +60,9 @@ ROOT@[0; 107)
57 IF_EXPR@[71; 90) 60 IF_EXPR@[71; 90)
58 IF_KW@[71; 73) 61 IF_KW@[71; 73)
59 WHITESPACE@[73; 74) 62 WHITESPACE@[73; 74)
60 LITERAL@[74; 79) 63 CONDITION@[74; 79)
61 FALSE_KW@[74; 79) 64 LITERAL@[74; 79)
65 FALSE_KW@[74; 79)
62 WHITESPACE@[79; 80) 66 WHITESPACE@[79; 80)
63 BLOCK@[80; 82) 67 BLOCK@[80; 82)
64 L_CURLY@[80; 81) 68 L_CURLY@[80; 81)
@@ -75,11 +79,12 @@ ROOT@[0; 107)
75 IF_EXPR@[96; 103) 79 IF_EXPR@[96; 103)
76 IF_KW@[96; 98) 80 IF_KW@[96; 98)
77 WHITESPACE@[98; 99) 81 WHITESPACE@[98; 99)
78 PATH_EXPR@[99; 100) 82 CONDITION@[99; 100)
79 PATH@[99; 100) 83 PATH_EXPR@[99; 100)
80 PATH_SEGMENT@[99; 100) 84 PATH@[99; 100)
81 NAME_REF@[99; 100) 85 PATH_SEGMENT@[99; 100)
82 IDENT@[99; 100) "S" 86 NAME_REF@[99; 100)
87 IDENT@[99; 100) "S"
83 WHITESPACE@[100; 101) 88 WHITESPACE@[100; 101)
84 BLOCK@[101; 103) 89 BLOCK@[101; 103)
85 L_CURLY@[101; 102) 90 L_CURLY@[101; 102)
diff --git a/crates/libsyntax2/tests/data/parser/inline/0076_cond.txt b/crates/libsyntax2/tests/data/parser/inline/0076_cond.txt
index 547d66fb3..1808f10fb 100644
--- a/crates/libsyntax2/tests/data/parser/inline/0076_cond.txt
+++ b/crates/libsyntax2/tests/data/parser/inline/0076_cond.txt
@@ -14,25 +14,26 @@ ROOT@[0; 38)
14 IF_EXPR@[11; 35) 14 IF_EXPR@[11; 35)
15 IF_KW@[11; 13) 15 IF_KW@[11; 13)
16 WHITESPACE@[13; 14) 16 WHITESPACE@[13; 14)
17 LET_KW@[14; 17) 17 CONDITION@[14; 32)
18 WHITESPACE@[17; 18) 18 LET_KW@[14; 17)
19 TUPLE_STRUCT_PAT@[18; 25) 19 WHITESPACE@[17; 18)
20 PATH@[18; 22) 20 TUPLE_STRUCT_PAT@[18; 25)
21 PATH_SEGMENT@[18; 22) 21 PATH@[18; 22)
22 NAME_REF@[18; 22) 22 PATH_SEGMENT@[18; 22)
23 IDENT@[18; 22) "Some" 23 NAME_REF@[18; 22)
24 L_PAREN@[22; 23) 24 IDENT@[18; 22) "Some"
25 PLACEHOLDER_PAT@[23; 24) 25 L_PAREN@[22; 23)
26 UNDERSCORE@[23; 24) 26 PLACEHOLDER_PAT@[23; 24)
27 R_PAREN@[24; 25) 27 UNDERSCORE@[23; 24)
28 WHITESPACE@[25; 26) 28 R_PAREN@[24; 25)
29 EQ@[26; 27) 29 WHITESPACE@[25; 26)
30 WHITESPACE@[27; 28) 30 EQ@[26; 27)
31 PATH_EXPR@[28; 32) 31 WHITESPACE@[27; 28)
32 PATH@[28; 32) 32 PATH_EXPR@[28; 32)
33 PATH_SEGMENT@[28; 32) 33 PATH@[28; 32)
34 NAME_REF@[28; 32) 34 PATH_SEGMENT@[28; 32)
35 IDENT@[28; 32) "None" 35 NAME_REF@[28; 32)
36 IDENT@[28; 32) "None"
36 WHITESPACE@[32; 33) 37 WHITESPACE@[32; 33)
37 BLOCK@[33; 35) 38 BLOCK@[33; 35)
38 L_CURLY@[33; 34) 39 L_CURLY@[33; 34)
diff --git a/crates/libsyntax2/tests/data/parser/inline/0077_while_expr.txt b/crates/libsyntax2/tests/data/parser/inline/0077_while_expr.txt
index 0ce157710..c73157c04 100644
--- a/crates/libsyntax2/tests/data/parser/inline/0077_while_expr.txt
+++ b/crates/libsyntax2/tests/data/parser/inline/0077_while_expr.txt
@@ -15,8 +15,9 @@ ROOT@[0; 70)
15 WHILE_EXPR@[15; 28) 15 WHILE_EXPR@[15; 28)
16 WHILE_KW@[15; 20) 16 WHILE_KW@[15; 20)
17 WHITESPACE@[20; 21) 17 WHITESPACE@[20; 21)
18 LITERAL@[21; 25) 18 CONDITION@[21; 25)
19 TRUE_KW@[21; 25) 19 LITERAL@[21; 25)
20 TRUE_KW@[21; 25)
20 WHITESPACE@[25; 26) 21 WHITESPACE@[25; 26)
21 BLOCK@[26; 28) 22 BLOCK@[26; 28)
22 L_CURLY@[26; 27) 23 L_CURLY@[26; 27)
@@ -27,33 +28,34 @@ ROOT@[0; 70)
27 WHILE_EXPR@[34; 66) 28 WHILE_EXPR@[34; 66)
28 WHILE_KW@[34; 39) 29 WHILE_KW@[34; 39)
29 WHITESPACE@[39; 40) 30 WHITESPACE@[39; 40)
30 LET_KW@[40; 43) 31 CONDITION@[40; 63)
31 WHITESPACE@[43; 44) 32 LET_KW@[40; 43)
32 TUPLE_STRUCT_PAT@[44; 51) 33 WHITESPACE@[43; 44)
33 PATH@[44; 48) 34 TUPLE_STRUCT_PAT@[44; 51)
34 PATH_SEGMENT@[44; 48) 35 PATH@[44; 48)
35 NAME_REF@[44; 48) 36 PATH_SEGMENT@[44; 48)
36 IDENT@[44; 48) "Some" 37 NAME_REF@[44; 48)
37 L_PAREN@[48; 49) 38 IDENT@[44; 48) "Some"
38 BIND_PAT@[49; 50) 39 L_PAREN@[48; 49)
39 NAME@[49; 50) 40 BIND_PAT@[49; 50)
40 IDENT@[49; 50) "x" 41 NAME@[49; 50)
41 R_PAREN@[50; 51) 42 IDENT@[49; 50) "x"
42 WHITESPACE@[51; 52) 43 R_PAREN@[50; 51)
43 EQ@[52; 53) 44 WHITESPACE@[51; 52)
44 WHITESPACE@[53; 54) 45 EQ@[52; 53)
45 METHOD_CALL_EXPR@[54; 63) 46 WHITESPACE@[53; 54)
46 PATH_EXPR@[54; 56) 47 METHOD_CALL_EXPR@[54; 63)
47 PATH@[54; 56) 48 PATH_EXPR@[54; 56)
48 PATH_SEGMENT@[54; 56) 49 PATH@[54; 56)
49 NAME_REF@[54; 56) 50 PATH_SEGMENT@[54; 56)
50 IDENT@[54; 56) "it" 51 NAME_REF@[54; 56)
51 DOT@[56; 57) 52 IDENT@[54; 56) "it"
52 NAME_REF@[57; 61) 53 DOT@[56; 57)
53 IDENT@[57; 61) "next" 54 NAME_REF@[57; 61)
54 ARG_LIST@[61; 63) 55 IDENT@[57; 61) "next"
55 L_PAREN@[61; 62) 56 ARG_LIST@[61; 63)
56 R_PAREN@[62; 63) 57 L_PAREN@[61; 62)
58 R_PAREN@[62; 63)
57 WHITESPACE@[63; 64) 59 WHITESPACE@[63; 64)
58 BLOCK@[64; 66) 60 BLOCK@[64; 66)
59 L_CURLY@[64; 65) 61 L_CURLY@[64; 65)
diff --git a/crates/libsyntax2/tests/data/parser/inline/0086_no_semi_after_block.txt b/crates/libsyntax2/tests/data/parser/inline/0086_no_semi_after_block.txt
index e3164f9cc..f1b0e2787 100644
--- a/crates/libsyntax2/tests/data/parser/inline/0086_no_semi_after_block.txt
+++ b/crates/libsyntax2/tests/data/parser/inline/0086_no_semi_after_block.txt
@@ -15,8 +15,9 @@ ROOT@[0; 107)
15 IF_EXPR@[15; 25) 15 IF_EXPR@[15; 25)
16 IF_KW@[15; 17) 16 IF_KW@[15; 17)
17 WHITESPACE@[17; 18) 17 WHITESPACE@[17; 18)
18 LITERAL@[18; 22) 18 CONDITION@[18; 22)
19 TRUE_KW@[18; 22) 19 LITERAL@[18; 22)
20 TRUE_KW@[18; 22)
20 WHITESPACE@[22; 23) 21 WHITESPACE@[22; 23)
21 BLOCK@[23; 25) 22 BLOCK@[23; 25)
22 L_CURLY@[23; 24) 23 L_CURLY@[23; 24)
@@ -46,8 +47,9 @@ ROOT@[0; 107)
46 WHILE_EXPR@[58; 71) 47 WHILE_EXPR@[58; 71)
47 WHILE_KW@[58; 63) 48 WHILE_KW@[58; 63)
48 WHITESPACE@[63; 64) 49 WHITESPACE@[63; 64)
49 LITERAL@[64; 68) 50 CONDITION@[64; 68)
50 TRUE_KW@[64; 68) 51 LITERAL@[64; 68)
52 TRUE_KW@[64; 68)
51 WHITESPACE@[68; 69) 53 WHITESPACE@[68; 69)
52 BLOCK@[69; 71) 54 BLOCK@[69; 71)
53 L_CURLY@[69; 70) 55 L_CURLY@[69; 70)
diff --git a/crates/libsyntax2/tests/data/parser/inline/0107_label.txt b/crates/libsyntax2/tests/data/parser/inline/0107_label.txt
index ccf22d8df..768515595 100644
--- a/crates/libsyntax2/tests/data/parser/inline/0107_label.txt
+++ b/crates/libsyntax2/tests/data/parser/inline/0107_label.txt
@@ -31,8 +31,9 @@ ROOT@[0; 74)
31 WHITESPACE@[34; 35) 31 WHITESPACE@[34; 35)
32 WHILE_KW@[35; 40) 32 WHILE_KW@[35; 40)
33 WHITESPACE@[40; 41) 33 WHITESPACE@[40; 41)
34 LITERAL@[41; 45) 34 CONDITION@[41; 45)
35 TRUE_KW@[41; 45) 35 LITERAL@[41; 45)
36 TRUE_KW@[41; 45)
36 WHITESPACE@[45; 46) 37 WHITESPACE@[45; 46)
37 BLOCK@[46; 48) 38 BLOCK@[46; 48)
38 L_CURLY@[46; 47) 39 L_CURLY@[46; 47)