Skip to content

librustc: Change the syntax of subslice matching to use postfix .. #17054

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Sep 9, 2014
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/doc/rust.md
Original file line number Diff line number Diff line change
Expand Up @@ -3300,7 +3300,7 @@ it will bind the corresponding slice to the variable. Example:
fn is_symmetric(list: &[uint]) -> bool {
match list {
[] | [_] => true,
[x, ..inside, y] if x == y => is_symmetric(inside),
[x, inside.., y] if x == y => is_symmetric(inside),
_ => false
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/doc/tutorial.md
Original file line number Diff line number Diff line change
Expand Up @@ -1707,7 +1707,7 @@ let score = match numbers {
[] => 0,
[a] => a * 10,
[a, b] => a * 6 + b * 4,
[a, b, c, ..rest] => a * 5 + b * 3 + c * 2 + rest.len() as int
[a, b, c, rest..] => a * 5 + b * 3 + c * 2 + rest.len() as int
};
~~~~

Expand Down
19 changes: 7 additions & 12 deletions src/librustc/middle/resolve.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1549,18 +1549,13 @@ impl<'a> Resolver<'a> {
PathListMod { .. } => Some(item.span),
_ => None
}).collect::<Vec<Span>>();
match mod_spans.as_slice() {
[first, second, ..other] => {
self.resolve_error(first,
"`mod` import can only appear once in the list");
self.session.span_note(second,
"another `mod` import appears here");
for &other_span in other.iter() {
self.session.span_note(other_span,
"another `mod` import appears here");
}
},
[_] | [] => ()
if mod_spans.len() > 1 {
self.resolve_error(mod_spans[0],
"`mod` import can only appear once in the list");
for other_span in mod_spans.iter().skip(1) {
self.session.span_note(*other_span,
"another `mod` import appears here");
}
}

for source_item in source_items.iter() {
Expand Down
5 changes: 5 additions & 0 deletions src/libsyntax/parse/obsolete.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ pub enum ObsoleteSyntax {
ObsoleteManagedType,
ObsoleteManagedExpr,
ObsoleteImportRenaming,
ObsoleteSubsliceMatch,
}

pub trait ParserObsoleteMethods {
Expand Down Expand Up @@ -87,6 +88,10 @@ impl<'a> ParserObsoleteMethods for parser::Parser<'a> {
ObsoleteImportRenaming => (
"`use foo = bar` syntax",
"write `use bar as foo` instead"
),
ObsoleteSubsliceMatch => (
"subslice match syntax",
"instead of `..xs`, write `xs..` in a pattern"
)
};

Expand Down
68 changes: 37 additions & 31 deletions src/libsyntax/parse/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2858,43 +2858,42 @@ impl<'a> Parser<'a> {
let mut before_slice = true;

while self.token != token::RBRACKET {
if first { first = false; }
else { self.expect(&token::COMMA); }
if first {
first = false;
} else {
self.expect(&token::COMMA);
}

let mut is_slice = false;
if before_slice {
if self.token == token::DOTDOT {
self.bump();
is_slice = true;
before_slice = false;
}
}

if is_slice {
if self.token == token::COMMA || self.token == token::RBRACKET {
slice = Some(box(GC) ast::Pat {
id: ast::DUMMY_NODE_ID,
node: PatWild(PatWildMulti),
span: self.span,
})
} else {
let subpat = self.parse_pat();
match *subpat {
ast::Pat { node: PatIdent(_, _, _), .. } => {
slice = Some(subpat);
}
ast::Pat { span, .. } => self.span_fatal(
span, "expected an identifier or nothing"
)
if self.token == token::COMMA ||
self.token == token::RBRACKET {
slice = Some(box(GC) ast::Pat {
id: ast::DUMMY_NODE_ID,
node: PatWild(PatWildMulti),
span: self.span,
});
before_slice = false;
} else {
let _ = self.parse_pat();
let span = self.span;
self.obsolete(span, ObsoleteSubsliceMatch);
}
continue
}
}

let subpat = self.parse_pat();
if before_slice && self.token == token::DOTDOT {
self.bump();
slice = Some(subpat);
before_slice = false;
} else if before_slice {
before.push(subpat);
} else {
let subpat = self.parse_pat();
if before_slice {
before.push(subpat);
} else {
after.push(subpat);
}
after.push(subpat);
}
}

Expand Down Expand Up @@ -3065,7 +3064,11 @@ impl<'a> Parser<'a> {
// These expressions are limited to literals (possibly
// preceded by unary-minus) or identifiers.
let val = self.parse_literal_maybe_minus();
if self.eat(&token::DOTDOT) {
if self.token == token::DOTDOT &&
self.look_ahead(1, |t| {
*t != token::COMMA && *t != token::RBRACKET
}) {
self.bump();
let end = if is_ident_or_path(&self.token) {
let path = self.parse_path(LifetimeAndTypesWithColons)
.path;
Expand Down Expand Up @@ -3106,7 +3109,10 @@ impl<'a> Parser<'a> {
}
});

if self.look_ahead(1, |t| *t == token::DOTDOT) {
if self.look_ahead(1, |t| *t == token::DOTDOT) &&
self.look_ahead(2, |t| {
*t != token::COMMA && *t != token::RBRACKET
}) {
let start = self.parse_expr_res(RESTRICT_NO_BAR_OP);
self.eat(&token::DOTDOT);
let end = self.parse_expr_res(RESTRICT_NO_BAR_OP);
Expand Down
2 changes: 1 addition & 1 deletion src/libsyntax/print/pprust.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1912,13 +1912,13 @@ impl<'a> State<'a> {
|s, p| s.print_pat(&**p)));
for p in slice.iter() {
if !before.is_empty() { try!(self.word_space(",")); }
try!(self.print_pat(&**p));
match **p {
ast::Pat { node: ast::PatWild(ast::PatWildMulti), .. } => {
// this case is handled by print_pat
}
_ => try!(word(&mut self.s, "..")),
}
try!(self.print_pat(&**p));
if !after.is_empty() { try!(self.word_space(",")); }
}
try!(self.commasep(Inconsistent,
Expand Down
2 changes: 1 addition & 1 deletion src/test/compile-fail/borrowck-move-out-of-vec-tail.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ pub fn main() {
);
let x: &[Foo] = x.as_slice();
match x {
[_, ..tail] => {
[_, tail..] => {
match tail {
[Foo { string: a }, //~ ERROR cannot move out of dereference of `&`-pointer
Foo { string: b }] => {
Expand Down
6 changes: 3 additions & 3 deletions src/test/compile-fail/borrowck-vec-pattern-element-loan.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ fn a<'a>() -> &'a [int] {
let vec = vec!(1, 2, 3, 4);
let vec: &[int] = vec.as_slice(); //~ ERROR does not live long enough
let tail = match vec {
[_, ..tail] => tail,
[_, tail..] => tail,
_ => fail!("a")
};
tail
Expand All @@ -22,7 +22,7 @@ fn b<'a>() -> &'a [int] {
let vec = vec!(1, 2, 3, 4);
let vec: &[int] = vec.as_slice(); //~ ERROR does not live long enough
let init = match vec {
[..init, _] => init,
[init.., _] => init,
_ => fail!("b")
};
init
Expand All @@ -32,7 +32,7 @@ fn c<'a>() -> &'a [int] {
let vec = vec!(1, 2, 3, 4);
let vec: &[int] = vec.as_slice(); //~ ERROR does not live long enough
let slice = match vec {
[_, ..slice, _] => slice,
[_, slice.., _] => slice,
_ => fail!("c")
};
slice
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ fn a() {
let mut v = vec!(1, 2, 3);
let vb: &mut [int] = v.as_mut_slice();
match vb {
[_a, ..tail] => {
[_a, tail..] => {
v.push(tail[0] + tail[1]); //~ ERROR cannot borrow
}
_ => {}
Expand Down
2 changes: 1 addition & 1 deletion src/test/compile-fail/borrowck-vec-pattern-move-tail.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
fn main() {
let mut a = [1i, 2, 3, 4];
let t = match a {
[1, 2, ..tail] => tail,
[1, 2, tail..] => tail,
_ => unreachable!()
};
a[0] = 0; //~ ERROR cannot assign to `a[..]` because it is borrowed
Expand Down
6 changes: 3 additions & 3 deletions src/test/compile-fail/borrowck-vec-pattern-nesting.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ fn b() {
let mut vec = vec!(box 1i, box 2, box 3);
let vec: &mut [Box<int>] = vec.as_mut_slice();
match vec {
[.._b] => {
[_b..] => {
vec[0] = box 4; //~ ERROR cannot assign
}
}
Expand All @@ -33,7 +33,7 @@ fn c() {
let vec: &mut [Box<int>] = vec.as_mut_slice();
match vec {
[_a, //~ ERROR cannot move out
.._b] => { //~^ NOTE attempting to move value to here
_b..] => { //~^ NOTE attempting to move value to here

// Note: `_a` is *moved* here, but `b` is borrowing,
// hence illegal.
Expand All @@ -50,7 +50,7 @@ fn d() {
let mut vec = vec!(box 1i, box 2, box 3);
let vec: &mut [Box<int>] = vec.as_mut_slice();
match vec {
[.._a, //~ ERROR cannot move out
[_a.., //~ ERROR cannot move out
_b] => {} //~ NOTE attempting to move value to here
_ => {}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ fn a<'a>() -> &'a int {
let vec = vec!(1, 2, 3, 4);
let vec: &[int] = vec.as_slice(); //~ ERROR `vec` does not live long enough
let tail = match vec {
[_a, ..tail] => &tail[0],
[_a, tail..] => &tail[0],
_ => fail!("foo")
};
tail
Expand Down
4 changes: 2 additions & 2 deletions src/test/compile-fail/issue-12369.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ fn main() {
let v: int = match sl.as_slice() {
[] => 0,
[a,b,c] => 3,
[a, ..rest] => a,
[10,a, ..rest] => 10 //~ ERROR: unreachable pattern
[a, rest..] => a,
[10,a, rest..] => 10 //~ ERROR: unreachable pattern
};
}
4 changes: 2 additions & 2 deletions src/test/compile-fail/issue-12567.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,10 @@
fn match_vecs<'a, T>(l1: &'a [T], l2: &'a [T]) {
match (l1, l2) {
([], []) => println!("both empty"),
([], [hd, ..tl]) | ([hd, ..tl], []) => println!("one empty"),
([], [hd, tl..]) | ([hd, tl..], []) => println!("one empty"),
//~^ ERROR: cannot move out of dereference
//~^^ ERROR: cannot move out of dereference
([hd1, ..tl1], [hd2, ..tl2]) => println!("both nonempty"),
([hd1, tl1..], [hd2, tl2..]) => println!("both nonempty"),
//~^ ERROR: cannot move out of dereference
//~^^ ERROR: cannot move out of dereference
}
Expand Down
2 changes: 1 addition & 1 deletion src/test/compile-fail/match-vec-invalid.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
fn main() {
let a = Vec::new();
match a {
[1, ..tail, ..tail] => {}, //~ ERROR: unexpected token: `..`
[1, tail.., tail..] => {}, //~ ERROR: expected `,`, found `..`
_ => ()
}
}
2 changes: 1 addition & 1 deletion src/test/compile-fail/match-vec-unreachable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ fn main() {
let x: Vec<char> = vec!('a', 'b', 'c');
let x: &[char] = x.as_slice();
match x {
['a', 'b', 'c', .._tail] => {}
['a', 'b', 'c', _tail..] => {}
['a', 'b', 'c'] => {} //~ ERROR unreachable pattern
_ => {}
}
Expand Down
14 changes: 7 additions & 7 deletions src/test/compile-fail/non-exhaustive-match.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,14 +38,14 @@ fn main() {
let vec = vec!(Some(42i), None, Some(21i));
let vec: &[Option<int>] = vec.as_slice();
match vec { //~ ERROR non-exhaustive patterns: `[]` not covered
[Some(..), None, ..tail] => {}
[Some(..), Some(..), ..tail] => {}
[Some(..), None, tail..] => {}
[Some(..), Some(..), tail..] => {}
[None] => {}
}
let vec = vec!(1i);
let vec: &[int] = vec.as_slice();
match vec {
[_, ..tail] => (),
[_, tail..] => (),
[] => ()
}
let vec = vec!(0.5f32);
Expand All @@ -59,10 +59,10 @@ fn main() {
let vec = vec!(Some(42i), None, Some(21i));
let vec: &[Option<int>] = vec.as_slice();
match vec {
[Some(..), None, ..tail] => {}
[Some(..), Some(..), ..tail] => {}
[None, None, ..tail] => {}
[None, Some(..), ..tail] => {}
[Some(..), None, tail..] => {}
[Some(..), Some(..), tail..] => {}
[None, None, tail..] => {}
[None, Some(..), tail..] => {}
[Some(_)] => {}
[None] => {}
[] => {}
Expand Down
2 changes: 1 addition & 1 deletion src/test/compile-fail/non-exhaustive-pattern-witness.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ fn vectors_with_nested_enums() {
[Second(true), First] => (),
[Second(true), Second(true)] => (),
[Second(false), _] => (),
[_, _, ..tail, _] => ()
[_, _, tail.., _] => ()
}
}

Expand Down
22 changes: 22 additions & 0 deletions src/test/compile-fail/vec-matching-obsolete-syntax.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

fn main() {
let x = [1i, 2, 3];
match x {
[a, b, ..c] => { //~ ERROR obsolete syntax
assert_eq!(a, 1);
assert_eq!(b, 2);
let expected: &[_] = &[3];
assert_eq!(c, expected);
}
}
}

4 changes: 2 additions & 2 deletions src/test/run-pass/issue-15080.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,11 @@ fn main() {
let mut result = vec!();
loop {
x = match x {
[1, n, 3, ..rest] => {
[1, n, 3, rest..] => {
result.push(n);
rest
}
[n, ..rest] => {
[n, rest..] => {
result.push(n);
rest
}
Expand Down
2 changes: 1 addition & 1 deletion src/test/run-pass/issue-15104.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,6 @@ fn count_members(v: &[uint]) -> uint {
match v {
[] => 0,
[_] => 1,
[_x, ..xs] => 1 + count_members(xs)
[_x, xs..] => 1 + count_members(xs)
}
}
Loading