Skip to content

Commit 2d79a1a

Browse files
Merge #1848
1848: Parse `..` as a full pattern r=matklad a=ecstatic-morse Resolves #1479. This PR implements [RFC 2707](rust-lang/rfcs#2707) in the parser. It introduces a new `DotDotPat` AST node modeled on `PlaceholderPat` and changes the parsing of tuple and slice patterns to conform to the RFC. Notably, this PR does *not* change the resulting AST when `..` appears in a struct pattern (e.g. `Struct { a, b: c, .. }`). I *think* this is the behavior mandated by RFC 2707, but someone should confirm this. Co-authored-by: Dylan MacKenzie <ecstaticmorse@gmail.com>
2 parents bcdba77 + 0956323 commit 2d79a1a

File tree

12 files changed

+573
-17
lines changed

12 files changed

+573
-17
lines changed

crates/ra_hir/src/expr/lower.rs

+1
Original file line numberDiff line numberDiff line change
@@ -573,6 +573,7 @@ where
573573
}
574574

575575
// FIXME: implement
576+
ast::Pat::DotDotPat(_) => Pat::Missing,
576577
ast::Pat::BoxPat(_) => Pat::Missing,
577578
ast::Pat::LiteralPat(_) => Pat::Missing,
578579
ast::Pat::SlicePat(_) | ast::Pat::RangePat(_) => Pat::Missing,

crates/ra_parser/src/grammar/patterns.rs

+42-10
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use super::*;
22

33
pub(super) const PATTERN_FIRST: TokenSet = expressions::LITERAL_FIRST
44
.union(paths::PATH_FIRST)
5-
.union(token_set![BOX_KW, REF_KW, MUT_KW, L_PAREN, L_BRACK, AMP, UNDERSCORE, MINUS]);
5+
.union(token_set![BOX_KW, REF_KW, MUT_KW, L_PAREN, L_BRACK, AMP, UNDERSCORE, MINUS, DOT]);
66

77
pub(crate) fn pattern(p: &mut Parser) {
88
pattern_r(p, PAT_RECOVERY_SET);
@@ -73,6 +73,7 @@ fn atom_pat(p: &mut Parser, recovery_set: TokenSet) -> Option<CompletedMarker> {
7373
_ if paths::is_use_path_start(p) => path_pat(p),
7474
_ if is_literal_pat_start(p) => literal_pat(p),
7575

76+
T![.] if p.at(T![..]) => dot_dot_pat(p),
7677
T![_] => placeholder_pat(p),
7778
T![&] => ref_pat(p),
7879
T!['('] => tuple_pat(p),
@@ -163,7 +164,9 @@ fn record_field_pat_list(p: &mut Parser) {
163164
p.bump_any();
164165
while !p.at(EOF) && !p.at(T!['}']) {
165166
match p.current() {
167+
// A trailing `..` is *not* treated as a DOT_DOT_PAT.
166168
T![.] if p.at(T![..]) => p.bump(T![..]),
169+
167170
IDENT if p.nth(1) == T![:] => record_field_pat(p),
168171
T!['{'] => error_block(p, "expected ident"),
169172
T![box] => {
@@ -201,6 +204,39 @@ fn placeholder_pat(p: &mut Parser) -> CompletedMarker {
201204
m.complete(p, PLACEHOLDER_PAT)
202205
}
203206

207+
// test dot_dot_pat
208+
// fn main() {
209+
// let .. = ();
210+
// //
211+
// // Tuples
212+
// //
213+
// let (a, ..) = ();
214+
// let (a, ..,) = ();
215+
// let Tuple(a, ..) = ();
216+
// let Tuple(a, ..,) = ();
217+
// let (.., ..) = ();
218+
// let Tuple(.., ..) = ();
219+
// let (.., a, ..) = ();
220+
// let Tuple(.., a, ..) = ();
221+
// //
222+
// // Slices
223+
// //
224+
// let [..] = ();
225+
// let [head, ..] = ();
226+
// let [head, tail @ ..] = ();
227+
// let [head, .., cons] = ();
228+
// let [head, mid @ .., cons] = ();
229+
// let [head, .., .., cons] = ();
230+
// let [head, .., mid, tail @ ..] = ();
231+
// let [head, .., mid, .., cons] = ();
232+
// }
233+
fn dot_dot_pat(p: &mut Parser) -> CompletedMarker {
234+
assert!(p.at(T![..]));
235+
let m = p.start();
236+
p.bump(T![..]);
237+
m.complete(p, DOT_DOT_PAT)
238+
}
239+
204240
// test ref_pat
205241
// fn main() {
206242
// let &a = ();
@@ -241,16 +277,12 @@ fn slice_pat(p: &mut Parser) -> CompletedMarker {
241277

242278
fn pat_list(p: &mut Parser, ket: SyntaxKind) {
243279
while !p.at(EOF) && !p.at(ket) {
244-
match p.current() {
245-
T![.] if p.at(T![..]) => p.bump(T![..]),
246-
_ => {
247-
if !p.at_ts(PATTERN_FIRST) {
248-
p.error("expected a pattern");
249-
break;
250-
}
251-
pattern(p)
252-
}
280+
if !p.at_ts(PATTERN_FIRST) {
281+
p.error("expected a pattern");
282+
break;
253283
}
284+
285+
pattern(p);
254286
if !p.at(ket) {
255287
p.expect(T![,]);
256288
}

crates/ra_parser/src/syntax_kind/generated.rs

+1
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,7 @@ pub enum SyntaxKind {
152152
BOX_PAT,
153153
BIND_PAT,
154154
PLACEHOLDER_PAT,
155+
DOT_DOT_PAT,
155156
PATH_PAT,
156157
RECORD_PAT,
157158
RECORD_FIELD_PAT_LIST,

crates/ra_syntax/src/ast/generated.rs

+35-2
Original file line numberDiff line numberDiff line change
@@ -532,6 +532,29 @@ impl AstNode for ContinueExpr {
532532
}
533533
impl ContinueExpr {}
534534
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
535+
pub struct DotDotPat {
536+
pub(crate) syntax: SyntaxNode,
537+
}
538+
impl AstNode for DotDotPat {
539+
fn can_cast(kind: SyntaxKind) -> bool {
540+
match kind {
541+
DOT_DOT_PAT => true,
542+
_ => false,
543+
}
544+
}
545+
fn cast(syntax: SyntaxNode) -> Option<Self> {
546+
if Self::can_cast(syntax.kind()) {
547+
Some(Self { syntax })
548+
} else {
549+
None
550+
}
551+
}
552+
fn syntax(&self) -> &SyntaxNode {
553+
&self.syntax
554+
}
555+
}
556+
impl DotDotPat {}
557+
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
535558
pub struct DynTraitType {
536559
pub(crate) syntax: SyntaxNode,
537560
}
@@ -2128,6 +2151,7 @@ pub enum Pat {
21282151
BoxPat(BoxPat),
21292152
BindPat(BindPat),
21302153
PlaceholderPat(PlaceholderPat),
2154+
DotDotPat(DotDotPat),
21312155
PathPat(PathPat),
21322156
RecordPat(RecordPat),
21332157
TupleStructPat(TupleStructPat),
@@ -2156,6 +2180,11 @@ impl From<PlaceholderPat> for Pat {
21562180
Pat::PlaceholderPat(node)
21572181
}
21582182
}
2183+
impl From<DotDotPat> for Pat {
2184+
fn from(node: DotDotPat) -> Pat {
2185+
Pat::DotDotPat(node)
2186+
}
2187+
}
21592188
impl From<PathPat> for Pat {
21602189
fn from(node: PathPat) -> Pat {
21612190
Pat::PathPat(node)
@@ -2194,8 +2223,10 @@ impl From<LiteralPat> for Pat {
21942223
impl AstNode for Pat {
21952224
fn can_cast(kind: SyntaxKind) -> bool {
21962225
match kind {
2197-
REF_PAT | BOX_PAT | BIND_PAT | PLACEHOLDER_PAT | PATH_PAT | RECORD_PAT
2198-
| TUPLE_STRUCT_PAT | TUPLE_PAT | SLICE_PAT | RANGE_PAT | LITERAL_PAT => true,
2226+
REF_PAT | BOX_PAT | BIND_PAT | PLACEHOLDER_PAT | DOT_DOT_PAT | PATH_PAT
2227+
| RECORD_PAT | TUPLE_STRUCT_PAT | TUPLE_PAT | SLICE_PAT | RANGE_PAT | LITERAL_PAT => {
2228+
true
2229+
}
21992230
_ => false,
22002231
}
22012232
}
@@ -2205,6 +2236,7 @@ impl AstNode for Pat {
22052236
BOX_PAT => Pat::BoxPat(BoxPat { syntax }),
22062237
BIND_PAT => Pat::BindPat(BindPat { syntax }),
22072238
PLACEHOLDER_PAT => Pat::PlaceholderPat(PlaceholderPat { syntax }),
2239+
DOT_DOT_PAT => Pat::DotDotPat(DotDotPat { syntax }),
22082240
PATH_PAT => Pat::PathPat(PathPat { syntax }),
22092241
RECORD_PAT => Pat::RecordPat(RecordPat { syntax }),
22102242
TUPLE_STRUCT_PAT => Pat::TupleStructPat(TupleStructPat { syntax }),
@@ -2222,6 +2254,7 @@ impl AstNode for Pat {
22222254
Pat::BoxPat(it) => &it.syntax,
22232255
Pat::BindPat(it) => &it.syntax,
22242256
Pat::PlaceholderPat(it) => &it.syntax,
2257+
Pat::DotDotPat(it) => &it.syntax,
22252258
Pat::PathPat(it) => &it.syntax,
22262259
Pat::RecordPat(it) => &it.syntax,
22272260
Pat::TupleStructPat(it) => &it.syntax,

crates/ra_syntax/src/grammar.ron

+3
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,7 @@ Grammar(
161161
"BOX_PAT",
162162
"BIND_PAT",
163163
"PLACEHOLDER_PAT",
164+
"DOT_DOT_PAT",
164165
"PATH_PAT",
165166
"RECORD_PAT",
166167
"RECORD_FIELD_PAT_LIST",
@@ -532,6 +533,7 @@ Grammar(
532533
traits: ["NameOwner"]
533534
),
534535
"PlaceholderPat": (),
536+
"DotDotPat": (),
535537
"PathPat": ( options: [ "Path" ] ),
536538
"RecordPat": ( options: ["RecordFieldPatList", "Path"] ),
537539
"RecordFieldPatList": (
@@ -559,6 +561,7 @@ Grammar(
559561
"BoxPat",
560562
"BindPat",
561563
"PlaceholderPat",
564+
"DotDotPat",
562565
"PathPat",
563566
"RecordPat",
564567
"TupleStructPat",

crates/ra_syntax/test_data/parser/inline/ok/0008_path_part.txt

+2-1
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,8 @@ SOURCE_FILE@[0; 103)
8282
NAME_REF@[87; 90)
8383
IDENT@[87; 90) "Bar"
8484
L_PAREN@[90; 91) "("
85-
DOTDOT@[91; 93) ".."
85+
DOT_DOT_PAT@[91; 93)
86+
DOTDOT@[91; 93) ".."
8687
R_PAREN@[93; 94) ")"
8788
WHITESPACE@[94; 95) " "
8889
EQ@[95; 96) "="

crates/ra_syntax/test_data/parser/inline/ok/0024_slice_pat.txt

+2-1
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,8 @@ SOURCE_FILE@[0; 39)
2727
IDENT@[24; 25) "b"
2828
COMMA@[25; 26) ","
2929
WHITESPACE@[26; 27) " "
30-
DOTDOT@[27; 29) ".."
30+
DOT_DOT_PAT@[27; 29)
31+
DOTDOT@[27; 29) ".."
3132
R_BRACK@[29; 30) "]"
3233
WHITESPACE@[30; 31) " "
3334
EQ@[31; 32) "="

crates/ra_syntax/test_data/parser/inline/ok/0026_tuple_pat_fields.txt

+2-1
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,8 @@ SOURCE_FILE@[0; 97)
8484
UNDERSCORE@[78; 79) "_"
8585
COMMA@[79; 80) ","
8686
WHITESPACE@[80; 81) " "
87-
DOTDOT@[81; 83) ".."
87+
DOT_DOT_PAT@[81; 83)
88+
DOTDOT@[81; 83) ".."
8889
WHITESPACE@[83; 84) " "
8990
COMMA@[84; 85) ","
9091
WHITESPACE@[85; 86) " "

crates/ra_syntax/test_data/parser/inline/ok/0111_tuple_pat.txt

+2-1
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,8 @@ SOURCE_FILE@[0; 39)
2727
IDENT@[24; 25) "b"
2828
COMMA@[25; 26) ","
2929
WHITESPACE@[26; 27) " "
30-
DOTDOT@[27; 29) ".."
30+
DOT_DOT_PAT@[27; 29)
31+
DOTDOT@[27; 29) ".."
3132
R_PAREN@[29; 30) ")"
3233
WHITESPACE@[30; 31) " "
3334
EQ@[31; 32) "="
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
fn main() {
2+
let .. = ();
3+
//
4+
// Tuples
5+
//
6+
let (a, ..) = ();
7+
let (a, ..,) = ();
8+
let Tuple(a, ..) = ();
9+
let Tuple(a, ..,) = ();
10+
let (.., ..) = ();
11+
let Tuple(.., ..) = ();
12+
let (.., a, ..) = ();
13+
let Tuple(.., a, ..) = ();
14+
//
15+
// Slices
16+
//
17+
let [..] = ();
18+
let [head, ..] = ();
19+
let [head, tail @ ..] = ();
20+
let [head, .., cons] = ();
21+
let [head, mid @ .., cons] = ();
22+
let [head, .., .., cons] = ();
23+
let [head, .., mid, tail @ ..] = ();
24+
let [head, .., mid, .., cons] = ();
25+
}

0 commit comments

Comments
 (0)