1848: Parse `..` as a full pattern r=matklad a=ecstatic-morse

Resolves #1479.

This PR implements [RFC 2707](https://github.com/rust-lang/rfcs/pull/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>
This commit is contained in:
bors[bot] 2019-09-15 07:10:16 +00:00 committed by GitHub
commit 2d79a1ad83
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 573 additions and 17 deletions

View file

@ -2,7 +2,7 @@ use super::*;
pub(super) const PATTERN_FIRST: TokenSet = expressions::LITERAL_FIRST
.union(paths::PATH_FIRST)
.union(token_set![BOX_KW, REF_KW, MUT_KW, L_PAREN, L_BRACK, AMP, UNDERSCORE, MINUS]);
.union(token_set![BOX_KW, REF_KW, MUT_KW, L_PAREN, L_BRACK, AMP, UNDERSCORE, MINUS, DOT]);
pub(crate) fn pattern(p: &mut Parser) {
pattern_r(p, PAT_RECOVERY_SET);
@ -73,6 +73,7 @@ fn atom_pat(p: &mut Parser, recovery_set: TokenSet) -> Option<CompletedMarker> {
_ if paths::is_use_path_start(p) => path_pat(p),
_ if is_literal_pat_start(p) => literal_pat(p),
T![.] if p.at(T![..]) => dot_dot_pat(p),
T![_] => placeholder_pat(p),
T![&] => ref_pat(p),
T!['('] => tuple_pat(p),
@ -163,7 +164,9 @@ fn record_field_pat_list(p: &mut Parser) {
p.bump_any();
while !p.at(EOF) && !p.at(T!['}']) {
match p.current() {
// A trailing `..` is *not* treated as a DOT_DOT_PAT.
T![.] if p.at(T![..]) => p.bump(T![..]),
IDENT if p.nth(1) == T![:] => record_field_pat(p),
T!['{'] => error_block(p, "expected ident"),
T![box] => {
@ -201,6 +204,39 @@ fn placeholder_pat(p: &mut Parser) -> CompletedMarker {
m.complete(p, PLACEHOLDER_PAT)
}
// test dot_dot_pat
// fn main() {
// let .. = ();
// //
// // Tuples
// //
// let (a, ..) = ();
// let (a, ..,) = ();
// let Tuple(a, ..) = ();
// let Tuple(a, ..,) = ();
// let (.., ..) = ();
// let Tuple(.., ..) = ();
// let (.., a, ..) = ();
// let Tuple(.., a, ..) = ();
// //
// // Slices
// //
// let [..] = ();
// let [head, ..] = ();
// let [head, tail @ ..] = ();
// let [head, .., cons] = ();
// let [head, mid @ .., cons] = ();
// let [head, .., .., cons] = ();
// let [head, .., mid, tail @ ..] = ();
// let [head, .., mid, .., cons] = ();
// }
fn dot_dot_pat(p: &mut Parser) -> CompletedMarker {
assert!(p.at(T![..]));
let m = p.start();
p.bump(T![..]);
m.complete(p, DOT_DOT_PAT)
}
// test ref_pat
// fn main() {
// let &a = ();
@ -241,16 +277,12 @@ fn slice_pat(p: &mut Parser) -> CompletedMarker {
fn pat_list(p: &mut Parser, ket: SyntaxKind) {
while !p.at(EOF) && !p.at(ket) {
match p.current() {
T![.] if p.at(T![..]) => p.bump(T![..]),
_ => {
if !p.at_ts(PATTERN_FIRST) {
p.error("expected a pattern");
break;
}
pattern(p)
}
if !p.at_ts(PATTERN_FIRST) {
p.error("expected a pattern");
break;
}
pattern(p);
if !p.at(ket) {
p.expect(T![,]);
}

View file

@ -152,6 +152,7 @@ pub enum SyntaxKind {
BOX_PAT,
BIND_PAT,
PLACEHOLDER_PAT,
DOT_DOT_PAT,
PATH_PAT,
RECORD_PAT,
RECORD_FIELD_PAT_LIST,