Skip to content

Commit 866b41d

Browse files
Merge #1733
1733: Parse arbitrarily complex `box` patterns. r=matklad a=ecstatic-morse This fully resolves the pattern part of #1412 by enabling the parsing of complex `box` patterns such as: ```rust let box Struct { box i, j: box Inner(box &x) } = todo!(); ``` This introduces a new `ast::BoxPat` (in the mold of `ast::RefPat`) that gets translated to `hir::Pat::Missing`. Co-authored-by: Dylan MacKenzie <[email protected]>
2 parents fdece91 + c93903e commit 866b41d

File tree

14 files changed

+305
-108
lines changed

14 files changed

+305
-108
lines changed

crates/ra_hir/src/expr.rs

+1
Original file line numberDiff line numberDiff line change
@@ -1020,6 +1020,7 @@ where
10201020
}
10211021

10221022
// FIXME: implement
1023+
ast::Pat::BoxPat(_) => Pat::Missing,
10231024
ast::Pat::LiteralPat(_) => Pat::Missing,
10241025
ast::Pat::SlicePat(_) | ast::Pat::RangePat(_) => Pat::Missing,
10251026
};

crates/ra_parser/src/grammar/expressions/atom.rs

-2
Original file line numberDiff line numberDiff line change
@@ -414,8 +414,6 @@ pub(crate) fn match_arm_list(p: &mut Parser) {
414414
// X | Y if Z => (),
415415
// | X | Y if Z => (),
416416
// | X => (),
417-
// box X => (),
418-
// Some(box X) => (),
419417
// };
420418
// }
421419
fn match_arm(p: &mut Parser) -> BlockLike {

crates/ra_parser/src/grammar/patterns.rs

+30-19
Original file line numberDiff line numberDiff line change
@@ -56,37 +56,33 @@ const PAT_RECOVERY_SET: TokenSet =
5656
token_set![LET_KW, IF_KW, WHILE_KW, LOOP_KW, MATCH_KW, R_PAREN, COMMA];
5757

5858
fn atom_pat(p: &mut Parser, recovery_set: TokenSet) -> Option<CompletedMarker> {
59-
let la0 = p.nth(0);
60-
let la1 = p.nth(1);
61-
if la0 == T![ref]
62-
|| la0 == T![mut]
63-
|| la0 == T![box]
64-
|| (la0 == IDENT && !(la1 == T![::] || la1 == T!['('] || la1 == T!['{'] || la1 == T![!]))
65-
{
66-
return Some(bind_pat(p, true));
67-
}
68-
if paths::is_use_path_start(p) {
69-
return Some(path_pat(p));
70-
}
59+
// Checks the token after an IDENT to see if a pattern is a path (Struct { .. }) or macro
60+
// (T![x]).
61+
let is_path_or_macro_pat =
62+
|la1| la1 == T![::] || la1 == T!['('] || la1 == T!['{'] || la1 == T![!];
7163

72-
if is_literal_pat_start(p) {
73-
return Some(literal_pat(p));
74-
}
64+
let m = match p.nth(0) {
65+
T![box] => box_pat(p),
66+
T![ref] | T![mut] | IDENT if !is_path_or_macro_pat(p.nth(1)) => bind_pat(p, true),
67+
68+
_ if paths::is_use_path_start(p) => path_pat(p),
69+
_ if is_literal_pat_start(p) => literal_pat(p),
7570

76-
let m = match la0 {
7771
T![_] => placeholder_pat(p),
7872
T![&] => ref_pat(p),
7973
T!['('] => tuple_pat(p),
8074
T!['['] => slice_pat(p),
75+
8176
_ => {
8277
p.err_recover("expected pattern", recovery_set);
8378
return None;
8479
}
8580
};
81+
8682
Some(m)
8783
}
8884

89-
fn is_literal_pat_start(p: &mut Parser) -> bool {
85+
fn is_literal_pat_start(p: &Parser) -> bool {
9086
p.at(T![-]) && (p.nth(1) == INT_NUMBER || p.nth(1) == FLOAT_NUMBER)
9187
|| p.at_ts(expressions::LITERAL_FIRST)
9288
}
@@ -165,6 +161,9 @@ fn record_field_pat_list(p: &mut Parser) {
165161
T![..] => p.bump(),
166162
IDENT if p.nth(1) == T![:] => record_field_pat(p),
167163
T!['{'] => error_block(p, "expected ident"),
164+
T![box] => {
165+
box_pat(p);
166+
}
168167
_ => {
169168
bind_pat(p, false);
170169
}
@@ -261,11 +260,9 @@ fn pat_list(p: &mut Parser, ket: SyntaxKind) {
261260
// let ref mut d = ();
262261
// let e @ _ = ();
263262
// let ref mut f @ g @ _ = ();
264-
// let box i = Box::new(1i32);
265263
// }
266264
fn bind_pat(p: &mut Parser, with_at: bool) -> CompletedMarker {
267265
let m = p.start();
268-
p.eat(T![box]);
269266
p.eat(T![ref]);
270267
p.eat(T![mut]);
271268
name(p);
@@ -274,3 +271,17 @@ fn bind_pat(p: &mut Parser, with_at: bool) -> CompletedMarker {
274271
}
275272
m.complete(p, BIND_PAT)
276273
}
274+
275+
// test box_pat
276+
// fn main() {
277+
// let box i = ();
278+
// let box Outer { box i, j: box Inner(box &x) } = ();
279+
// let box ref mut i = ();
280+
// }
281+
fn box_pat(p: &mut Parser) -> CompletedMarker {
282+
assert!(p.at(T![box]));
283+
let m = p.start();
284+
p.bump();
285+
pattern(p);
286+
m.complete(p, BOX_PAT)
287+
}

crates/ra_parser/src/syntax_kind/generated.rs

+1
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,7 @@ pub enum SyntaxKind {
149149
IMPL_TRAIT_TYPE,
150150
DYN_TRAIT_TYPE,
151151
REF_PAT,
152+
BOX_PAT,
152153
BIND_PAT,
153154
PLACEHOLDER_PAT,
154155
PATH_PAT,

crates/ra_syntax/src/ast/generated.rs

+37-2
Original file line numberDiff line numberDiff line change
@@ -307,6 +307,33 @@ impl BlockExpr {
307307
}
308308
}
309309
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
310+
pub struct BoxPat {
311+
pub(crate) syntax: SyntaxNode,
312+
}
313+
impl AstNode for BoxPat {
314+
fn can_cast(kind: SyntaxKind) -> bool {
315+
match kind {
316+
BOX_PAT => true,
317+
_ => false,
318+
}
319+
}
320+
fn cast(syntax: SyntaxNode) -> Option<Self> {
321+
if Self::can_cast(syntax.kind()) {
322+
Some(Self { syntax })
323+
} else {
324+
None
325+
}
326+
}
327+
fn syntax(&self) -> &SyntaxNode {
328+
&self.syntax
329+
}
330+
}
331+
impl BoxPat {
332+
pub fn pat(&self) -> Option<Pat> {
333+
AstChildren::new(&self.syntax).next()
334+
}
335+
}
336+
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
310337
pub struct BreakExpr {
311338
pub(crate) syntax: SyntaxNode,
312339
}
@@ -2063,6 +2090,7 @@ impl ParenType {
20632090
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
20642091
pub enum Pat {
20652092
RefPat(RefPat),
2093+
BoxPat(BoxPat),
20662094
BindPat(BindPat),
20672095
PlaceholderPat(PlaceholderPat),
20682096
PathPat(PathPat),
@@ -2078,6 +2106,11 @@ impl From<RefPat> for Pat {
20782106
Pat::RefPat(node)
20792107
}
20802108
}
2109+
impl From<BoxPat> for Pat {
2110+
fn from(node: BoxPat) -> Pat {
2111+
Pat::BoxPat(node)
2112+
}
2113+
}
20812114
impl From<BindPat> for Pat {
20822115
fn from(node: BindPat) -> Pat {
20832116
Pat::BindPat(node)
@@ -2126,14 +2159,15 @@ impl From<LiteralPat> for Pat {
21262159
impl AstNode for Pat {
21272160
fn can_cast(kind: SyntaxKind) -> bool {
21282161
match kind {
2129-
REF_PAT | BIND_PAT | PLACEHOLDER_PAT | PATH_PAT | RECORD_PAT | TUPLE_STRUCT_PAT
2130-
| TUPLE_PAT | SLICE_PAT | RANGE_PAT | LITERAL_PAT => true,
2162+
REF_PAT | BOX_PAT | BIND_PAT | PLACEHOLDER_PAT | PATH_PAT | RECORD_PAT
2163+
| TUPLE_STRUCT_PAT | TUPLE_PAT | SLICE_PAT | RANGE_PAT | LITERAL_PAT => true,
21312164
_ => false,
21322165
}
21332166
}
21342167
fn cast(syntax: SyntaxNode) -> Option<Self> {
21352168
let res = match syntax.kind() {
21362169
REF_PAT => Pat::RefPat(RefPat { syntax }),
2170+
BOX_PAT => Pat::BoxPat(BoxPat { syntax }),
21372171
BIND_PAT => Pat::BindPat(BindPat { syntax }),
21382172
PLACEHOLDER_PAT => Pat::PlaceholderPat(PlaceholderPat { syntax }),
21392173
PATH_PAT => Pat::PathPat(PathPat { syntax }),
@@ -2150,6 +2184,7 @@ impl AstNode for Pat {
21502184
fn syntax(&self) -> &SyntaxNode {
21512185
match self {
21522186
Pat::RefPat(it) => &it.syntax,
2187+
Pat::BoxPat(it) => &it.syntax,
21532188
Pat::BindPat(it) => &it.syntax,
21542189
Pat::PlaceholderPat(it) => &it.syntax,
21552190
Pat::PathPat(it) => &it.syntax,

crates/ra_syntax/src/grammar.ron

+3
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,7 @@ Grammar(
158158
"DYN_TRAIT_TYPE",
159159

160160
"REF_PAT",
161+
"BOX_PAT",
161162
"BIND_PAT",
162163
"PLACEHOLDER_PAT",
163164
"PATH_PAT",
@@ -523,6 +524,7 @@ Grammar(
523524
),
524525

525526
"RefPat": ( options: [ "Pat" ]),
527+
"BoxPat": ( options: [ "Pat" ]),
526528
"BindPat": (
527529
options: [ "Pat" ],
528530
traits: ["NameOwner"]
@@ -552,6 +554,7 @@ Grammar(
552554
"Pat": (
553555
enum: [
554556
"RefPat",
557+
"BoxPat",
555558
"BindPat",
556559
"PlaceholderPat",
557560
"PathPat",
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
fn main() {
2+
let ref box i = ();
3+
let mut box i = ();
4+
let ref mut box i = ();
5+
}
6+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
SOURCE_FILE@[0; 91)
2+
FN_DEF@[0; 89)
3+
FN_KW@[0; 2) "fn"
4+
WHITESPACE@[2; 3) " "
5+
NAME@[3; 7)
6+
IDENT@[3; 7) "main"
7+
PARAM_LIST@[7; 9)
8+
L_PAREN@[7; 8) "("
9+
R_PAREN@[8; 9) ")"
10+
WHITESPACE@[9; 10) " "
11+
BLOCK@[10; 89)
12+
L_CURLY@[10; 11) "{"
13+
WHITESPACE@[11; 16) "\n "
14+
LET_STMT@[16; 27)
15+
LET_KW@[16; 19) "let"
16+
WHITESPACE@[19; 20) " "
17+
BIND_PAT@[20; 27)
18+
REF_KW@[20; 23) "ref"
19+
WHITESPACE@[23; 24) " "
20+
ERROR@[24; 27)
21+
BOX_KW@[24; 27) "box"
22+
WHITESPACE@[27; 28) " "
23+
EXPR_STMT@[28; 35)
24+
BIN_EXPR@[28; 34)
25+
PATH_EXPR@[28; 29)
26+
PATH@[28; 29)
27+
PATH_SEGMENT@[28; 29)
28+
NAME_REF@[28; 29)
29+
IDENT@[28; 29) "i"
30+
WHITESPACE@[29; 30) " "
31+
EQ@[30; 31) "="
32+
WHITESPACE@[31; 32) " "
33+
TUPLE_EXPR@[32; 34)
34+
L_PAREN@[32; 33) "("
35+
R_PAREN@[33; 34) ")"
36+
SEMI@[34; 35) ";"
37+
WHITESPACE@[35; 40) "\n "
38+
LET_STMT@[40; 51)
39+
LET_KW@[40; 43) "let"
40+
WHITESPACE@[43; 44) " "
41+
BIND_PAT@[44; 51)
42+
MUT_KW@[44; 47) "mut"
43+
WHITESPACE@[47; 48) " "
44+
ERROR@[48; 51)
45+
BOX_KW@[48; 51) "box"
46+
WHITESPACE@[51; 52) " "
47+
EXPR_STMT@[52; 59)
48+
BIN_EXPR@[52; 58)
49+
PATH_EXPR@[52; 53)
50+
PATH@[52; 53)
51+
PATH_SEGMENT@[52; 53)
52+
NAME_REF@[52; 53)
53+
IDENT@[52; 53) "i"
54+
WHITESPACE@[53; 54) " "
55+
EQ@[54; 55) "="
56+
WHITESPACE@[55; 56) " "
57+
TUPLE_EXPR@[56; 58)
58+
L_PAREN@[56; 57) "("
59+
R_PAREN@[57; 58) ")"
60+
SEMI@[58; 59) ";"
61+
WHITESPACE@[59; 64) "\n "
62+
LET_STMT@[64; 79)
63+
LET_KW@[64; 67) "let"
64+
WHITESPACE@[67; 68) " "
65+
BIND_PAT@[68; 79)
66+
REF_KW@[68; 71) "ref"
67+
WHITESPACE@[71; 72) " "
68+
MUT_KW@[72; 75) "mut"
69+
WHITESPACE@[75; 76) " "
70+
ERROR@[76; 79)
71+
BOX_KW@[76; 79) "box"
72+
WHITESPACE@[79; 80) " "
73+
EXPR_STMT@[80; 87)
74+
BIN_EXPR@[80; 86)
75+
PATH_EXPR@[80; 81)
76+
PATH@[80; 81)
77+
PATH_SEGMENT@[80; 81)
78+
NAME_REF@[80; 81)
79+
IDENT@[80; 81) "i"
80+
WHITESPACE@[81; 82) " "
81+
EQ@[82; 83) "="
82+
WHITESPACE@[83; 84) " "
83+
TUPLE_EXPR@[84; 86)
84+
L_PAREN@[84; 85) "("
85+
R_PAREN@[85; 86) ")"
86+
SEMI@[86; 87) ";"
87+
WHITESPACE@[87; 88) "\n"
88+
R_CURLY@[88; 89) "}"
89+
WHITESPACE@[89; 91) "\n\n"
90+
error 24: expected a name
91+
error 27: expected SEMI
92+
error 48: expected a name
93+
error 51: expected SEMI
94+
error 76: expected a name
95+
error 79: expected SEMI

crates/ra_syntax/test_data/parser/inline/ok/0066_match_arm.rs

-2
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,5 @@ fn foo() {
55
X | Y if Z => (),
66
| X | Y if Z => (),
77
| X => (),
8-
box X => (),
9-
Some(box X) => (),
108
};
119
}

0 commit comments

Comments
 (0)