Skip to content

Commit eb678ff

Browse files
committed
librustc: Change the syntax of subslice matching to use postfix ..
instead of prefix `..`. This breaks code that looked like: match foo { [ first, ..middle, last ] => { ... } } Change this code to: match foo { [ first, middle.., last ] => { ... } } RFC #55. Closes #16967. [breaking-change]
1 parent 6f34760 commit eb678ff

26 files changed

+110
-82
lines changed

src/doc/rust.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -3300,7 +3300,7 @@ it will bind the corresponding slice to the variable. Example:
33003300
fn is_symmetric(list: &[uint]) -> bool {
33013301
match list {
33023302
[] | [_] => true,
3303-
[x, ..inside, y] if x == y => is_symmetric(inside),
3303+
[x, inside.., y] if x == y => is_symmetric(inside),
33043304
_ => false
33053305
}
33063306
}

src/doc/tutorial.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -1707,7 +1707,7 @@ let score = match numbers {
17071707
[] => 0,
17081708
[a] => a * 10,
17091709
[a, b] => a * 6 + b * 4,
1710-
[a, b, c, ..rest] => a * 5 + b * 3 + c * 2 + rest.len() as int
1710+
[a, b, c, rest..] => a * 5 + b * 3 + c * 2 + rest.len() as int
17111711
};
17121712
~~~~
17131713

src/librustc/middle/resolve.rs

+7-12
Original file line numberDiff line numberDiff line change
@@ -1549,18 +1549,13 @@ impl<'a> Resolver<'a> {
15491549
PathListMod { .. } => Some(item.span),
15501550
_ => None
15511551
}).collect::<Vec<Span>>();
1552-
match mod_spans.as_slice() {
1553-
[first, second, ..other] => {
1554-
self.resolve_error(first,
1555-
"`mod` import can only appear once in the list");
1556-
self.session.span_note(second,
1557-
"another `mod` import appears here");
1558-
for &other_span in other.iter() {
1559-
self.session.span_note(other_span,
1560-
"another `mod` import appears here");
1561-
}
1562-
},
1563-
[_] | [] => ()
1552+
if mod_spans.len() > 1 {
1553+
self.resolve_error(mod_spans[0],
1554+
"`mod` import can only appear once in the list");
1555+
for other_span in mod_spans.iter().skip(1) {
1556+
self.session.span_note(*other_span,
1557+
"another `mod` import appears here");
1558+
}
15641559
}
15651560

15661561
for source_item in source_items.iter() {

src/libsyntax/parse/obsolete.rs

+5
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ pub enum ObsoleteSyntax {
3535
ObsoleteManagedType,
3636
ObsoleteManagedExpr,
3737
ObsoleteImportRenaming,
38+
ObsoleteSubsliceMatch,
3839
}
3940

4041
pub trait ParserObsoleteMethods {
@@ -87,6 +88,10 @@ impl<'a> ParserObsoleteMethods for parser::Parser<'a> {
8788
ObsoleteImportRenaming => (
8889
"`use foo = bar` syntax",
8990
"write `use bar as foo` instead"
91+
),
92+
ObsoleteSubsliceMatch => (
93+
"subslice match syntax",
94+
"instead of `..xs`, write `xs..` in a pattern"
9095
)
9196
};
9297

src/libsyntax/parse/parser.rs

+37-31
Original file line numberDiff line numberDiff line change
@@ -2858,43 +2858,42 @@ impl<'a> Parser<'a> {
28582858
let mut before_slice = true;
28592859

28602860
while self.token != token::RBRACKET {
2861-
if first { first = false; }
2862-
else { self.expect(&token::COMMA); }
2861+
if first {
2862+
first = false;
2863+
} else {
2864+
self.expect(&token::COMMA);
2865+
}
28632866

2864-
let mut is_slice = false;
28652867
if before_slice {
28662868
if self.token == token::DOTDOT {
28672869
self.bump();
2868-
is_slice = true;
2869-
before_slice = false;
2870-
}
2871-
}
28722870

2873-
if is_slice {
2874-
if self.token == token::COMMA || self.token == token::RBRACKET {
2875-
slice = Some(box(GC) ast::Pat {
2876-
id: ast::DUMMY_NODE_ID,
2877-
node: PatWild(PatWildMulti),
2878-
span: self.span,
2879-
})
2880-
} else {
2881-
let subpat = self.parse_pat();
2882-
match *subpat {
2883-
ast::Pat { node: PatIdent(_, _, _), .. } => {
2884-
slice = Some(subpat);
2885-
}
2886-
ast::Pat { span, .. } => self.span_fatal(
2887-
span, "expected an identifier or nothing"
2888-
)
2871+
if self.token == token::COMMA ||
2872+
self.token == token::RBRACKET {
2873+
slice = Some(box(GC) ast::Pat {
2874+
id: ast::DUMMY_NODE_ID,
2875+
node: PatWild(PatWildMulti),
2876+
span: self.span,
2877+
});
2878+
before_slice = false;
2879+
} else {
2880+
let _ = self.parse_pat();
2881+
let span = self.span;
2882+
self.obsolete(span, ObsoleteSubsliceMatch);
28892883
}
2884+
continue
28902885
}
2886+
}
2887+
2888+
let subpat = self.parse_pat();
2889+
if before_slice && self.token == token::DOTDOT {
2890+
self.bump();
2891+
slice = Some(subpat);
2892+
before_slice = false;
2893+
} else if before_slice {
2894+
before.push(subpat);
28912895
} else {
2892-
let subpat = self.parse_pat();
2893-
if before_slice {
2894-
before.push(subpat);
2895-
} else {
2896-
after.push(subpat);
2897-
}
2896+
after.push(subpat);
28982897
}
28992898
}
29002899

@@ -3065,7 +3064,11 @@ impl<'a> Parser<'a> {
30653064
// These expressions are limited to literals (possibly
30663065
// preceded by unary-minus) or identifiers.
30673066
let val = self.parse_literal_maybe_minus();
3068-
if self.eat(&token::DOTDOT) {
3067+
if self.token == token::DOTDOT &&
3068+
self.look_ahead(1, |t| {
3069+
*t != token::COMMA && *t != token::RBRACKET
3070+
}) {
3071+
self.bump();
30693072
let end = if is_ident_or_path(&self.token) {
30703073
let path = self.parse_path(LifetimeAndTypesWithColons)
30713074
.path;
@@ -3106,7 +3109,10 @@ impl<'a> Parser<'a> {
31063109
}
31073110
});
31083111

3109-
if self.look_ahead(1, |t| *t == token::DOTDOT) {
3112+
if self.look_ahead(1, |t| *t == token::DOTDOT) &&
3113+
self.look_ahead(2, |t| {
3114+
*t != token::COMMA && *t != token::RBRACKET
3115+
}) {
31103116
let start = self.parse_expr_res(RESTRICT_NO_BAR_OP);
31113117
self.eat(&token::DOTDOT);
31123118
let end = self.parse_expr_res(RESTRICT_NO_BAR_OP);

src/libsyntax/print/pprust.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1912,13 +1912,13 @@ impl<'a> State<'a> {
19121912
|s, p| s.print_pat(&**p)));
19131913
for p in slice.iter() {
19141914
if !before.is_empty() { try!(self.word_space(",")); }
1915+
try!(self.print_pat(&**p));
19151916
match **p {
19161917
ast::Pat { node: ast::PatWild(ast::PatWildMulti), .. } => {
19171918
// this case is handled by print_pat
19181919
}
19191920
_ => try!(word(&mut self.s, "..")),
19201921
}
1921-
try!(self.print_pat(&**p));
19221922
if !after.is_empty() { try!(self.word_space(",")); }
19231923
}
19241924
try!(self.commasep(Inconsistent,

src/test/compile-fail/borrowck-move-out-of-vec-tail.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ pub fn main() {
2525
);
2626
let x: &[Foo] = x.as_slice();
2727
match x {
28-
[_, ..tail] => {
28+
[_, tail..] => {
2929
match tail {
3030
[Foo { string: a }, //~ ERROR cannot move out of dereference of `&`-pointer
3131
Foo { string: b }] => {

src/test/compile-fail/borrowck-vec-pattern-element-loan.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ fn a<'a>() -> &'a [int] {
1212
let vec = vec!(1, 2, 3, 4);
1313
let vec: &[int] = vec.as_slice(); //~ ERROR does not live long enough
1414
let tail = match vec {
15-
[_, ..tail] => tail,
15+
[_, tail..] => tail,
1616
_ => fail!("a")
1717
};
1818
tail
@@ -22,7 +22,7 @@ fn b<'a>() -> &'a [int] {
2222
let vec = vec!(1, 2, 3, 4);
2323
let vec: &[int] = vec.as_slice(); //~ ERROR does not live long enough
2424
let init = match vec {
25-
[..init, _] => init,
25+
[init.., _] => init,
2626
_ => fail!("b")
2727
};
2828
init
@@ -32,7 +32,7 @@ fn c<'a>() -> &'a [int] {
3232
let vec = vec!(1, 2, 3, 4);
3333
let vec: &[int] = vec.as_slice(); //~ ERROR does not live long enough
3434
let slice = match vec {
35-
[_, ..slice, _] => slice,
35+
[_, slice.., _] => slice,
3636
_ => fail!("c")
3737
};
3838
slice

src/test/compile-fail/borrowck-vec-pattern-loan-from-mut.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ fn a() {
1212
let mut v = vec!(1, 2, 3);
1313
let vb: &mut [int] = v.as_mut_slice();
1414
match vb {
15-
[_a, ..tail] => {
15+
[_a, tail..] => {
1616
v.push(tail[0] + tail[1]); //~ ERROR cannot borrow
1717
}
1818
_ => {}

src/test/compile-fail/borrowck-vec-pattern-move-tail.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
fn main() {
1212
let mut a = [1i, 2, 3, 4];
1313
let t = match a {
14-
[1, 2, ..tail] => tail,
14+
[1, 2, tail..] => tail,
1515
_ => unreachable!()
1616
};
1717
a[0] = 0; //~ ERROR cannot assign to `a[..]` because it is borrowed

src/test/compile-fail/borrowck-vec-pattern-nesting.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ fn b() {
2222
let mut vec = vec!(box 1i, box 2, box 3);
2323
let vec: &mut [Box<int>] = vec.as_mut_slice();
2424
match vec {
25-
[.._b] => {
25+
[_b..] => {
2626
vec[0] = box 4; //~ ERROR cannot assign
2727
}
2828
}
@@ -33,7 +33,7 @@ fn c() {
3333
let vec: &mut [Box<int>] = vec.as_mut_slice();
3434
match vec {
3535
[_a, //~ ERROR cannot move out
36-
.._b] => { //~^ NOTE attempting to move value to here
36+
_b..] => { //~^ NOTE attempting to move value to here
3737

3838
// Note: `_a` is *moved* here, but `b` is borrowing,
3939
// hence illegal.
@@ -50,7 +50,7 @@ fn d() {
5050
let mut vec = vec!(box 1i, box 2, box 3);
5151
let vec: &mut [Box<int>] = vec.as_mut_slice();
5252
match vec {
53-
[.._a, //~ ERROR cannot move out
53+
[_a.., //~ ERROR cannot move out
5454
_b] => {} //~ NOTE attempting to move value to here
5555
_ => {}
5656
}

src/test/compile-fail/borrowck-vec-pattern-tail-element-loan.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ fn a<'a>() -> &'a int {
1212
let vec = vec!(1, 2, 3, 4);
1313
let vec: &[int] = vec.as_slice(); //~ ERROR `vec` does not live long enough
1414
let tail = match vec {
15-
[_a, ..tail] => &tail[0],
15+
[_a, tail..] => &tail[0],
1616
_ => fail!("foo")
1717
};
1818
tail

src/test/compile-fail/issue-12369.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ fn main() {
1313
let v: int = match sl.as_slice() {
1414
[] => 0,
1515
[a,b,c] => 3,
16-
[a, ..rest] => a,
17-
[10,a, ..rest] => 10 //~ ERROR: unreachable pattern
16+
[a, rest..] => a,
17+
[10,a, rest..] => 10 //~ ERROR: unreachable pattern
1818
};
1919
}

src/test/compile-fail/issue-12567.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,10 @@
1111
fn match_vecs<'a, T>(l1: &'a [T], l2: &'a [T]) {
1212
match (l1, l2) {
1313
([], []) => println!("both empty"),
14-
([], [hd, ..tl]) | ([hd, ..tl], []) => println!("one empty"),
14+
([], [hd, tl..]) | ([hd, tl..], []) => println!("one empty"),
1515
//~^ ERROR: cannot move out of dereference
1616
//~^^ ERROR: cannot move out of dereference
17-
([hd1, ..tl1], [hd2, ..tl2]) => println!("both nonempty"),
17+
([hd1, tl1..], [hd2, tl2..]) => println!("both nonempty"),
1818
//~^ ERROR: cannot move out of dereference
1919
//~^^ ERROR: cannot move out of dereference
2020
}

src/test/compile-fail/match-vec-invalid.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
fn main() {
1212
let a = Vec::new();
1313
match a {
14-
[1, ..tail, ..tail] => {}, //~ ERROR: unexpected token: `..`
14+
[1, tail.., tail..] => {}, //~ ERROR: expected `,`, found `..`
1515
_ => ()
1616
}
1717
}

src/test/compile-fail/match-vec-unreachable.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ fn main() {
3131
let x: Vec<char> = vec!('a', 'b', 'c');
3232
let x: &[char] = x.as_slice();
3333
match x {
34-
['a', 'b', 'c', .._tail] => {}
34+
['a', 'b', 'c', _tail..] => {}
3535
['a', 'b', 'c'] => {} //~ ERROR unreachable pattern
3636
_ => {}
3737
}

src/test/compile-fail/non-exhaustive-match.rs

+7-7
Original file line numberDiff line numberDiff line change
@@ -38,14 +38,14 @@ fn main() {
3838
let vec = vec!(Some(42i), None, Some(21i));
3939
let vec: &[Option<int>] = vec.as_slice();
4040
match vec { //~ ERROR non-exhaustive patterns: `[]` not covered
41-
[Some(..), None, ..tail] => {}
42-
[Some(..), Some(..), ..tail] => {}
41+
[Some(..), None, tail..] => {}
42+
[Some(..), Some(..), tail..] => {}
4343
[None] => {}
4444
}
4545
let vec = vec!(1i);
4646
let vec: &[int] = vec.as_slice();
4747
match vec {
48-
[_, ..tail] => (),
48+
[_, tail..] => (),
4949
[] => ()
5050
}
5151
let vec = vec!(0.5f32);
@@ -59,10 +59,10 @@ fn main() {
5959
let vec = vec!(Some(42i), None, Some(21i));
6060
let vec: &[Option<int>] = vec.as_slice();
6161
match vec {
62-
[Some(..), None, ..tail] => {}
63-
[Some(..), Some(..), ..tail] => {}
64-
[None, None, ..tail] => {}
65-
[None, Some(..), ..tail] => {}
62+
[Some(..), None, tail..] => {}
63+
[Some(..), Some(..), tail..] => {}
64+
[None, None, tail..] => {}
65+
[None, Some(..), tail..] => {}
6666
[Some(_)] => {}
6767
[None] => {}
6868
[] => {}

src/test/compile-fail/non-exhaustive-pattern-witness.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ fn vectors_with_nested_enums() {
6363
[Second(true), First] => (),
6464
[Second(true), Second(true)] => (),
6565
[Second(false), _] => (),
66-
[_, _, ..tail, _] => ()
66+
[_, _, tail.., _] => ()
6767
}
6868
}
6969

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
fn main() {
12+
let x = [1i, 2, 3];
13+
match x {
14+
[a, b, ..c] => { //~ ERROR obsolete syntax
15+
assert_eq!(a, 1);
16+
assert_eq!(b, 2);
17+
let expected: &[_] = &[3];
18+
assert_eq!(c, expected);
19+
}
20+
}
21+
}
22+

src/test/run-pass/issue-15080.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,11 @@ fn main() {
1414
let mut result = vec!();
1515
loop {
1616
x = match x {
17-
[1, n, 3, ..rest] => {
17+
[1, n, 3, rest..] => {
1818
result.push(n);
1919
rest
2020
}
21-
[n, ..rest] => {
21+
[n, rest..] => {
2222
result.push(n);
2323
rest
2424
}

src/test/run-pass/issue-15104.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,6 @@ fn count_members(v: &[uint]) -> uint {
1616
match v {
1717
[] => 0,
1818
[_] => 1,
19-
[_x, ..xs] => 1 + count_members(xs)
19+
[_x, xs..] => 1 + count_members(xs)
2020
}
2121
}

0 commit comments

Comments
 (0)