Skip to content

Commit cd199ea

Browse files
authored
Merge pull request #18908 from jnyfah/error-braces
Fix: Detect missing errors for } braces before else in let...else statements
2 parents 903bc81 + 31c07e4 commit cd199ea

23 files changed

+637
-12
lines changed

Diff for: crates/parser/src/event.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ use crate::{
1212
/// `Parser` produces a flat list of `Event`s.
1313
/// They are converted to a tree-structure in
1414
/// a separate pass, via `TreeBuilder`.
15-
#[derive(Debug)]
15+
#[derive(Debug, PartialEq)]
1616
pub(crate) enum Event {
1717
/// This event signifies the start of the node.
1818
/// It should be either abandoned (in which case the

Diff for: crates/parser/src/grammar/expressions.rs

+6-4
Original file line numberDiff line numberDiff line change
@@ -134,10 +134,12 @@ pub(super) fn let_stmt(p: &mut Parser<'_>, with_semi: Semicolon) {
134134
// test_err let_else_right_curly_brace
135135
// fn func() { let Some(_) = {Some(1)} else { panic!("h") };}
136136
if let Some(expr) = expr_after_eq {
137-
if BlockLike::is_blocklike(expr.kind()) {
138-
p.error(
139-
"right curly brace `}` before `else` in a `let...else` statement not allowed",
140-
)
137+
if let Some(token) = expr.last_token(p) {
138+
if token == T!['}'] {
139+
p.error(
140+
"right curly brace `}` before `else` in a `let...else` statement not allowed"
141+
)
142+
}
141143
}
142144
}
143145

Diff for: crates/parser/src/parser.rs

+18-7
Original file line numberDiff line numberDiff line change
@@ -318,7 +318,8 @@ impl Marker {
318318
_ => unreachable!(),
319319
}
320320
p.push_event(Event::Finish);
321-
CompletedMarker::new(self.pos, kind)
321+
let end_pos = p.events.len() as u32;
322+
CompletedMarker::new(self.pos, end_pos, kind)
322323
}
323324

324325
/// Abandons the syntax tree node. All its children
@@ -336,13 +337,14 @@ impl Marker {
336337
}
337338

338339
pub(crate) struct CompletedMarker {
339-
pos: u32,
340+
start_pos: u32,
341+
end_pos: u32,
340342
kind: SyntaxKind,
341343
}
342344

343345
impl CompletedMarker {
344-
fn new(pos: u32, kind: SyntaxKind) -> Self {
345-
CompletedMarker { pos, kind }
346+
fn new(start_pos: u32, end_pos: u32, kind: SyntaxKind) -> Self {
347+
CompletedMarker { start_pos, end_pos, kind }
346348
}
347349

348350
/// This method allows to create a new node which starts
@@ -360,10 +362,10 @@ impl CompletedMarker {
360362
/// distance to `NEWSTART` into forward_parent(=2 in this case);
361363
pub(crate) fn precede(self, p: &mut Parser<'_>) -> Marker {
362364
let new_pos = p.start();
363-
let idx = self.pos as usize;
365+
let idx = self.start_pos as usize;
364366
match &mut p.events[idx] {
365367
Event::Start { forward_parent, .. } => {
366-
*forward_parent = Some(new_pos.pos - self.pos);
368+
*forward_parent = Some(new_pos.pos - self.start_pos);
367369
}
368370
_ => unreachable!(),
369371
}
@@ -376,7 +378,7 @@ impl CompletedMarker {
376378
let idx = m.pos as usize;
377379
match &mut p.events[idx] {
378380
Event::Start { forward_parent, .. } => {
379-
*forward_parent = Some(self.pos - m.pos);
381+
*forward_parent = Some(self.start_pos - m.pos);
380382
}
381383
_ => unreachable!(),
382384
}
@@ -386,4 +388,13 @@ impl CompletedMarker {
386388
pub(crate) fn kind(&self) -> SyntaxKind {
387389
self.kind
388390
}
391+
392+
pub(crate) fn last_token(&self, p: &Parser<'_>) -> Option<SyntaxKind> {
393+
let end_pos = self.end_pos as usize;
394+
debug_assert_eq!(p.events[end_pos - 1], Event::Finish);
395+
p.events[..end_pos].iter().rev().find_map(|event| match event {
396+
Event::Token { kind, .. } => Some(*kind),
397+
_ => None,
398+
})
399+
}
389400
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
SOURCE_FILE
2+
STRUCT
3+
STRUCT_KW "struct"
4+
WHITESPACE " "
5+
NAME
6+
IDENT "X"
7+
WHITESPACE " "
8+
RECORD_FIELD_LIST
9+
L_CURLY "{"
10+
RECORD_FIELD
11+
NAME
12+
IDENT "a"
13+
COLON ":"
14+
WHITESPACE " "
15+
PATH_TYPE
16+
PATH
17+
PATH_SEGMENT
18+
NAME_REF
19+
IDENT "i32"
20+
R_CURLY "}"
21+
WHITESPACE "\n"
22+
FN
23+
FN_KW "fn"
24+
WHITESPACE " "
25+
NAME
26+
IDENT "f"
27+
PARAM_LIST
28+
L_PAREN "("
29+
R_PAREN ")"
30+
WHITESPACE " "
31+
BLOCK_EXPR
32+
STMT_LIST
33+
L_CURLY "{"
34+
WHITESPACE "\n "
35+
LET_STMT
36+
LET_KW "let"
37+
WHITESPACE " "
38+
IDENT_PAT
39+
NAME
40+
IDENT "foo"
41+
WHITESPACE " "
42+
EQ "="
43+
WHITESPACE " "
44+
RECORD_EXPR
45+
PATH
46+
PATH_SEGMENT
47+
NAME_REF
48+
IDENT "X"
49+
WHITESPACE " "
50+
RECORD_EXPR_FIELD_LIST
51+
L_CURLY "{"
52+
WHITESPACE "\n "
53+
RECORD_EXPR_FIELD
54+
NAME_REF
55+
IDENT "a"
56+
COLON ":"
57+
WHITESPACE " "
58+
LITERAL
59+
INT_NUMBER "1"
60+
WHITESPACE "\n "
61+
R_CURLY "}"
62+
WHITESPACE " "
63+
LET_ELSE
64+
ELSE_KW "else"
65+
WHITESPACE " "
66+
BLOCK_EXPR
67+
STMT_LIST
68+
L_CURLY "{"
69+
WHITESPACE "\n "
70+
EXPR_STMT
71+
RETURN_EXPR
72+
RETURN_KW "return"
73+
SEMICOLON ";"
74+
WHITESPACE "\n "
75+
R_CURLY "}"
76+
SEMICOLON ";"
77+
WHITESPACE "\n"
78+
R_CURLY "}"
79+
error 63: right curly brace `}` before `else` in a `let...else` statement not allowed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
struct X {a: i32}
2+
fn f() {
3+
let foo = X {
4+
a: 1
5+
} else {
6+
return;
7+
};
8+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
SOURCE_FILE
2+
ERROR
3+
LET_KW "let"
4+
WHITESPACE " "
5+
IDENT_PAT
6+
NAME
7+
IDENT "foo"
8+
WHITESPACE " "
9+
EQ "="
10+
WHITESPACE " "
11+
BIN_EXPR
12+
LITERAL
13+
INT_NUMBER "1"
14+
WHITESPACE " "
15+
PLUS "+"
16+
WHITESPACE " "
17+
BLOCK_EXPR
18+
STMT_LIST
19+
L_CURLY "{"
20+
WHITESPACE "\n "
21+
LITERAL
22+
INT_NUMBER "1"
23+
WHITESPACE "\n"
24+
R_CURLY "}"
25+
WHITESPACE " "
26+
LET_ELSE
27+
ELSE_KW "else"
28+
WHITESPACE " "
29+
BLOCK_EXPR
30+
STMT_LIST
31+
L_CURLY "{"
32+
WHITESPACE "\n "
33+
EXPR_STMT
34+
RETURN_EXPR
35+
RETURN_KW "return"
36+
SEMICOLON ";"
37+
WHITESPACE "\n"
38+
R_CURLY "}"
39+
SEMICOLON ";"
40+
WHITESPACE "\n"
41+
error 0: expected an item
42+
error 23: right curly brace `}` before `else` in a `let...else` statement not allowed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
let foo = 1 + {
2+
1
3+
} else {
4+
return;
5+
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
SOURCE_FILE
2+
FN
3+
FN_KW "fn"
4+
WHITESPACE " "
5+
NAME
6+
IDENT "r"
7+
PARAM_LIST
8+
L_PAREN "("
9+
R_PAREN ")"
10+
WHITESPACE " "
11+
BLOCK_EXPR
12+
STMT_LIST
13+
L_CURLY "{"
14+
WHITESPACE "\n "
15+
LET_STMT
16+
LET_KW "let"
17+
WHITESPACE " "
18+
IDENT_PAT
19+
NAME
20+
IDENT "ok"
21+
WHITESPACE " "
22+
EQ "="
23+
WHITESPACE " "
24+
MACRO_EXPR
25+
MACRO_CALL
26+
PATH
27+
PATH_SEGMENT
28+
NAME_REF
29+
IDENT "format_args"
30+
BANG "!"
31+
TOKEN_TREE
32+
L_PAREN "("
33+
STRING "\"\""
34+
R_PAREN ")"
35+
WHITESPACE " "
36+
LET_ELSE
37+
ELSE_KW "else"
38+
WHITESPACE " "
39+
BLOCK_EXPR
40+
STMT_LIST
41+
L_CURLY "{"
42+
WHITESPACE " "
43+
EXPR_STMT
44+
RETURN_EXPR
45+
RETURN_KW "return"
46+
SEMICOLON ";"
47+
WHITESPACE " "
48+
R_CURLY "}"
49+
SEMICOLON ";"
50+
WHITESPACE "\n\n "
51+
LET_STMT
52+
LET_KW "let"
53+
WHITESPACE " "
54+
IDENT_PAT
55+
NAME
56+
IDENT "bad"
57+
WHITESPACE " "
58+
EQ "="
59+
WHITESPACE " "
60+
MACRO_EXPR
61+
MACRO_CALL
62+
PATH
63+
PATH_SEGMENT
64+
NAME_REF
65+
IDENT "format_args"
66+
BANG "!"
67+
WHITESPACE " "
68+
TOKEN_TREE
69+
L_CURLY "{"
70+
STRING "\"\""
71+
R_CURLY "}"
72+
WHITESPACE " "
73+
LET_ELSE
74+
ELSE_KW "else"
75+
WHITESPACE " "
76+
BLOCK_EXPR
77+
STMT_LIST
78+
L_CURLY "{"
79+
WHITESPACE " "
80+
EXPR_STMT
81+
RETURN_EXPR
82+
RETURN_KW "return"
83+
SEMICOLON ";"
84+
WHITESPACE " "
85+
R_CURLY "}"
86+
SEMICOLON ";"
87+
WHITESPACE "\n"
88+
R_CURLY "}"
89+
WHITESPACE "\n"
90+
error 89: right curly brace `}` before `else` in a `let...else` statement not allowed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
fn r() {
2+
let ok = format_args!("") else { return; };
3+
4+
let bad = format_args! {""} else { return; };
5+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
SOURCE_FILE
2+
ERROR
3+
LET_KW "let"
4+
WHITESPACE " "
5+
IDENT_PAT
6+
NAME
7+
IDENT "foo"
8+
WHITESPACE " "
9+
EQ "="
10+
WHITESPACE " "
11+
RANGE_EXPR
12+
LITERAL
13+
INT_NUMBER "1"
14+
DOT2 ".."
15+
BLOCK_EXPR
16+
STMT_LIST
17+
L_CURLY "{"
18+
WHITESPACE "\n "
19+
LITERAL
20+
INT_NUMBER "1"
21+
WHITESPACE "\n"
22+
R_CURLY "}"
23+
WHITESPACE " "
24+
LET_ELSE
25+
ELSE_KW "else"
26+
WHITESPACE " "
27+
BLOCK_EXPR
28+
STMT_LIST
29+
L_CURLY "{"
30+
WHITESPACE "\n "
31+
EXPR_STMT
32+
RETURN_EXPR
33+
RETURN_KW "return"
34+
SEMICOLON ";"
35+
WHITESPACE "\n"
36+
R_CURLY "}"
37+
SEMICOLON ";"
38+
WHITESPACE "\n"
39+
error 0: expected an item
40+
error 22: right curly brace `}` before `else` in a `let...else` statement not allowed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
let foo = 1..{
2+
1
3+
} else {
4+
return;
5+
};

0 commit comments

Comments
 (0)