Skip to content
Permalink
Browse files

librustc: Forbid `..` in range patterns.

This breaks code that looks like:

    match foo {
        1..3 => { ... }
    }

Instead, write:

    match foo {
        1...3 => { ... }
    }

Closes #17295.

[breaking-change]
  • Loading branch information
pcwalton committed Sep 30, 2014
1 parent 38015ee commit 416144b8279fbffceacea6d0fd90e0fd1f8ce53d
@@ -1512,7 +1512,7 @@ fn _arm_exec_compiled_test(config: &Config,
for c in exitcode_out.as_slice().chars() {
if !c.is_digit() { break; }
exitcode = exitcode * 10 + match c {
'0' .. '9' => c as int - ('0' as int),
'0' ... '9' => c as int - ('0' as int),
_ => 101,
}
}
@@ -3757,27 +3757,27 @@ match x {
}
```
You can match a range of values with `..`:
You can match a range of values with `...`:
```{rust}
let x = 1i;
match x {
1 .. 5 => println!("one through five"),
1 ... 5 => println!("one through five"),
_ => println!("anything"),
}
```
Ranges are mostly used with integers and single characters.
If you're matching multiple things, via a `|` or a `..`, you can bind
If you're matching multiple things, via a `|` or a `...`, you can bind
the value to a name with `@`:
```{rust}
let x = 1i;
match x {
x @ 1 .. 5 => println!("got {}", x),
x @ 1 ... 5 => println!("got {}", x),
_ => println!("anything"),
}
```
@@ -3408,7 +3408,7 @@ may be specified with `..`. For example:
let message = match x {
0 | 1 => "not many",
2 .. 9 => "a few",
2 ... 9 => "a few",
_ => "lots"
};
```
@@ -199,10 +199,10 @@ impl String {
}
3 => {
match (byte, safe_get(v, i, total)) {
(0xE0 , 0xA0 .. 0xBF) => (),
(0xE1 .. 0xEC, 0x80 .. 0xBF) => (),
(0xED , 0x80 .. 0x9F) => (),
(0xEE .. 0xEF, 0x80 .. 0xBF) => (),
(0xE0 , 0xA0 ... 0xBF) => (),
(0xE1 ... 0xEC, 0x80 ... 0xBF) => (),
(0xED , 0x80 ... 0x9F) => (),
(0xEE ... 0xEF, 0x80 ... 0xBF) => (),
_ => {
error!();
continue;
@@ -217,9 +217,9 @@ impl String {
}
4 => {
match (byte, safe_get(v, i, total)) {
(0xF0 , 0x90 .. 0xBF) => (),
(0xF1 .. 0xF3, 0x80 .. 0xBF) => (),
(0xF4 , 0x80 .. 0x8F) => (),
(0xF0 , 0x90 ... 0xBF) => (),
(0xF1 ... 0xF3, 0x80 ... 0xBF) => (),
(0xF4 , 0x80 ... 0x8F) => (),
_ => {
error!();
continue;
@@ -123,9 +123,9 @@ pub fn to_digit(c: char, radix: uint) -> Option<uint> {
fail!("to_digit: radix is too high (maximum 36)");
}
let val = match c {
'0' .. '9' => c as uint - ('0' as uint),
'a' .. 'z' => c as uint + 10u - ('a' as uint),
'A' .. 'Z' => c as uint + 10u - ('A' as uint),
'0' ... '9' => c as uint - ('0' as uint),
'a' ... 'z' => c as uint + 10u - ('a' as uint),
'A' ... 'Z' => c as uint + 10u - ('A' as uint),
_ => return None,
};
if val < radix { Some(val) }
@@ -184,7 +184,7 @@ pub fn escape_unicode(c: char, f: |char|) {
let offset = offset as uint;
unsafe {
match ((c as i32) >> offset) & 0xf {
i @ 0 .. 9 => { f(transmute('0' as i32 + i)); }
i @ 0 ... 9 => { f(transmute('0' as i32 + i)); }
i => { f(transmute('a' as i32 + (i - 10))); }
}
}
@@ -211,7 +211,7 @@ pub fn escape_default(c: char, f: |char|) {
'\\' => { f('\\'); f('\\'); }
'\'' => { f('\\'); f('\''); }
'"' => { f('\\'); f('"'); }
'\x20' .. '\x7e' => { f(c); }
'\x20' ... '\x7e' => { f(c); }
_ => c.escape_unicode(f),
}
}
@@ -99,13 +99,13 @@ macro_rules! radix {
}
}

radix!(Binary, 2, "0b", x @ 0 .. 2 => b'0' + x)
radix!(Octal, 8, "0o", x @ 0 .. 7 => b'0' + x)
radix!(Decimal, 10, "", x @ 0 .. 9 => b'0' + x)
radix!(LowerHex, 16, "0x", x @ 0 .. 9 => b'0' + x,
x @ 10 ..15 => b'a' + (x - 10))
radix!(UpperHex, 16, "0x", x @ 0 .. 9 => b'0' + x,
x @ 10 ..15 => b'A' + (x - 10))
radix!(Binary, 2, "0b", x @ 0 ... 2 => b'0' + x)
radix!(Octal, 8, "0o", x @ 0 ... 7 => b'0' + x)
radix!(Decimal, 10, "", x @ 0 ... 9 => b'0' + x)
radix!(LowerHex, 16, "0x", x @ 0 ... 9 => b'0' + x,
x @ 10 ... 15 => b'a' + (x - 10))
radix!(UpperHex, 16, "0x", x @ 0 ... 9 => b'0' + x,
x @ 10 ... 15 => b'A' + (x - 10))

/// A radix with in the range of `2..36`.
#[deriving(Clone, PartialEq)]
@@ -124,7 +124,7 @@ impl GenericRadix for Radix {
fn base(&self) -> u8 { self.base }
fn digit(&self, x: u8) -> u8 {
match x {
x @ 0 ..9 => b'0' + x,
x @ 0 ... 9 => b'0' + x,
x if x < self.base() => b'a' + (x - 10),
x => fail!("number not in the range 0..{}: {}", self.base() - 1, x),
}
@@ -843,18 +843,18 @@ fn run_utf8_validation_iterator(iter: &mut slice::Items<u8>) -> bool {
2 => if second & !CONT_MASK != TAG_CONT_U8 {err!()},
3 => {
match (first, second, next!() & !CONT_MASK) {
(0xE0 , 0xA0 .. 0xBF, TAG_CONT_U8) |
(0xE1 .. 0xEC, 0x80 .. 0xBF, TAG_CONT_U8) |
(0xED , 0x80 .. 0x9F, TAG_CONT_U8) |
(0xEE .. 0xEF, 0x80 .. 0xBF, TAG_CONT_U8) => {}
(0xE0 , 0xA0 ... 0xBF, TAG_CONT_U8) |
(0xE1 ... 0xEC, 0x80 ... 0xBF, TAG_CONT_U8) |
(0xED , 0x80 ... 0x9F, TAG_CONT_U8) |
(0xEE ... 0xEF, 0x80 ... 0xBF, TAG_CONT_U8) => {}
_ => err!()
}
}
4 => {
match (first, second, next!() & !CONT_MASK, next!() & !CONT_MASK) {
(0xF0 , 0x90 .. 0xBF, TAG_CONT_U8, TAG_CONT_U8) |
(0xF1 .. 0xF3, 0x80 .. 0xBF, TAG_CONT_U8, TAG_CONT_U8) |
(0xF4 , 0x80 .. 0x8F, TAG_CONT_U8, TAG_CONT_U8) => {}
(0xF0 , 0x90 ... 0xBF, TAG_CONT_U8, TAG_CONT_U8) |
(0xF1 ... 0xF3, 0x80 ... 0xBF, TAG_CONT_U8, TAG_CONT_U8) |
(0xF4 , 0x80 ... 0x8F, TAG_CONT_U8, TAG_CONT_U8) => {}
_ => err!()
}
}
@@ -227,7 +227,7 @@ impl<'a> ReprVisitor<'a> {
self.writer.write("\"".as_bytes())
}
}
'\x20'..'\x7e' => self.writer.write([ch as u8]),
'\x20'...'\x7e' => self.writer.write([ch as u8]),
_ => {
char::escape_unicode(ch, |c| {
let _ = self.writer.write([c as u8]);
@@ -67,7 +67,7 @@ impl WindowsTTY {
// If the file descriptor is one of stdin, stderr, or stdout
// then it should not be closed by us
let closeme = match fd {
0..2 => false,
0...2 => false,
_ => true,
};
let handle = unsafe { get_osfhandle(fd) as HANDLE };
@@ -98,9 +98,9 @@ impl Gamma {
assert!(scale > 0.0, "Gamma::new called with scale <= 0");

let repr = match shape {
1.0 => One(Exp::new(1.0 / scale)),
0.0 .. 1.0 => Small(GammaSmallShape::new_raw(shape, scale)),
_ => Large(GammaLargeShape::new_raw(shape, scale))
1.0 => One(Exp::new(1.0 / scale)),
0.0 ... 1.0 => Small(GammaSmallShape::new_raw(shape, scale)),
_ => Large(GammaLargeShape::new_raw(shape, scale))
};
Gamma { repr: repr }
}
@@ -512,7 +512,7 @@ pub fn is_word(c: Option<char>) -> bool {
};
// Try the common ASCII case before invoking binary search.
match c {
'_' | '0' .. '9' | 'a' .. 'z' | 'A' .. 'Z' => true,
'_' | '0' ... '9' | 'a' ... 'z' | 'A' ... 'Z' => true,
_ => PERLW.binary_search(|&(start, end)| {
if c >= start && c <= end {
Equal
@@ -277,9 +277,9 @@ pub fn sanitize(s: &str) -> String {
'-' | ':' => result.push_char('.'),

// These are legal symbols
'a' .. 'z'
| 'A' .. 'Z'
| '0' .. '9'
'a' ... 'z'
| 'A' ... 'Z'
| '0' ... '9'
| '_' | '.' | '$' => result.push_char(c),

_ => {
@@ -110,7 +110,7 @@ impl Svh {
fn hex(b: u64) -> char {
let b = (b & 0xf) as u8;
let b = match b {
0 .. 9 => '0' as u8 + b,
0 ... 9 => '0' as u8 + b,
_ => 'a' as u8 + b - 10,
};
b as char
@@ -224,9 +224,9 @@ impl<'a> FromBase64 for &'a [u8] {
let val = byte as u32;

match byte {
b'A'..b'Z' => buf |= val - 0x41,
b'a'..b'z' => buf |= val - 0x47,
b'0'..b'9' => buf |= val + 0x04,
b'A'...b'Z' => buf |= val - 0x41,
b'a'...b'z' => buf |= val - 0x47,
b'0'...b'9' => buf |= val + 0x04,
b'+' | b'-' => buf |= 0x3E,
b'/' | b'_' => buf |= 0x3F,
b'\r' | b'\n' => continue,
@@ -113,9 +113,9 @@ impl<'a> FromHex for &'a str {
buf <<= 4;

match byte {
b'A'..b'F' => buf |= byte - b'A' + 10,
b'a'..b'f' => buf |= byte - b'a' + 10,
b'0'..b'9' => buf |= byte - b'0',
b'A'...b'F' => buf |= byte - b'A' + 10,
b'a'...b'f' => buf |= byte - b'a' + 10,
b'0'...b'9' => buf |= byte - b'0',
b' '|b'\r'|b'\n'|b'\t' => {
buf >>= 4;
continue
@@ -1392,14 +1392,14 @@ impl<T: Iterator<char>> Parser<T> {

// A leading '0' must be the only digit before the decimal point.
match self.ch_or_null() {
'0' .. '9' => return self.error(InvalidNumber),
'0' ... '9' => return self.error(InvalidNumber),
_ => ()
}
},
'1' .. '9' => {
'1' ... '9' => {
while !self.eof() {
match self.ch_or_null() {
c @ '0' .. '9' => {
c @ '0' ... '9' => {
accum *= 10;
accum += (c as u64) - ('0' as u64);

@@ -1423,14 +1423,14 @@ impl<T: Iterator<char>> Parser<T> {

// Make sure a digit follows the decimal place.
match self.ch_or_null() {
'0' .. '9' => (),
'0' ... '9' => (),
_ => return self.error(InvalidNumber)
}

let mut dec = 1.0;
while !self.eof() {
match self.ch_or_null() {
c @ '0' .. '9' => {
c @ '0' ... '9' => {
dec /= 10.0;
res += (((c as int) - ('0' as int)) as f64) * dec;
self.bump();
@@ -1457,12 +1457,12 @@ impl<T: Iterator<char>> Parser<T> {

// Make sure a digit follows the exponent place.
match self.ch_or_null() {
'0' .. '9' => (),
'0' ... '9' => (),
_ => return self.error(InvalidNumber)
}
while !self.eof() {
match self.ch_or_null() {
c @ '0' .. '9' => {
c @ '0' ... '9' => {
exp *= 10;
exp += (c as uint) - ('0' as uint);

@@ -1488,7 +1488,7 @@ impl<T: Iterator<char>> Parser<T> {
while i < 4 && !self.eof() {
self.bump();
n = match self.ch_or_null() {
c @ '0' .. '9' => n * 16 + ((c as u16) - ('0' as u16)),
c @ '0' ... '9' => n * 16 + ((c as u16) - ('0' as u16)),
'a' | 'A' => n * 16 + 10,
'b' | 'B' => n * 16 + 11,
'c' | 'C' => n * 16 + 12,
@@ -1530,11 +1530,13 @@ impl<T: Iterator<char>> Parser<T> {
'r' => res.push('\r'),
't' => res.push('\t'),
'u' => match try!(self.decode_hex_escape()) {
0xDC00 .. 0xDFFF => return self.error(LoneLeadingSurrogateInHexEscape),
0xDC00 ... 0xDFFF => {
return self.error(LoneLeadingSurrogateInHexEscape)
}

// Non-BMP characters are encoded as a sequence of
// two hex escapes, representing UTF-16 surrogates.
n1 @ 0xD800 .. 0xDBFF => {
n1 @ 0xD800 ... 0xDBFF => {
match (self.next_char(), self.next_char()) {
(Some('\\'), Some('u')) => (),
_ => return self.error(UnexpectedEndOfHexEscape),
@@ -1768,7 +1770,7 @@ impl<T: Iterator<char>> Parser<T> {
'n' => { self.parse_ident("ull", NullValue) }
't' => { self.parse_ident("rue", BooleanValue(true)) }
'f' => { self.parse_ident("alse", BooleanValue(false)) }
'0' .. '9' | '-' => self.parse_number(),
'0' ... '9' | '-' => self.parse_number(),
'"' => match self.parse_str() {
Ok(s) => StringValue(s),
Err(e) => Error(e),
@@ -199,8 +199,8 @@ pub fn int_to_str_bytes_common<T: Int>(num: T, radix: uint, sign: SignFormat, f:
current_digit_signed
};
buf[cur] = match current_digit.to_u8().unwrap() {
i @ 0..9 => b'0' + i,
i => b'a' + (i - 10),
i @ 0...9 => b'0' + i,
i => b'a' + (i - 10),
};
cur += 1;

@@ -637,7 +637,7 @@ impl<'a> StringReader<'a> {
'b' => { self.bump(); base = 2; num_digits = self.scan_digits(2); }
'o' => { self.bump(); base = 8; num_digits = self.scan_digits(8); }
'x' => { self.bump(); base = 16; num_digits = self.scan_digits(16); }
'0'..'9' | '_' | '.' => {
'0'...'9' | '_' | '.' => {
num_digits = self.scan_digits(10) + 1;
}
'u' | 'i' => {
@@ -3237,8 +3237,7 @@ impl<'a> Parser<'a> {
// These expressions are limited to literals (possibly
// preceded by unary-minus) or identifiers.
let val = self.parse_literal_maybe_minus();
// FIXME(#17295) remove the DOTDOT option.
if (self.token == token::DOTDOTDOT || self.token == token::DOTDOT) &&
if (self.token == token::DOTDOTDOT) &&
self.look_ahead(1, |t| {
*t != token::COMMA && *t != token::RBRACKET
}) {
@@ -3283,16 +3282,12 @@ impl<'a> Parser<'a> {
}
});

// FIXME(#17295) remove the DOTDOT option.
if self.look_ahead(1, |t| *t == token::DOTDOTDOT || *t == token::DOTDOT) &&
if self.look_ahead(1, |t| *t == token::DOTDOTDOT) &&
self.look_ahead(2, |t| {
*t != token::COMMA && *t != token::RBRACKET
}) {
let start = self.parse_expr_res(RestrictionNoBarOp);
// FIXME(#17295) remove the DOTDOT option (self.eat(&token::DOTDOTDOT)).
if self.token == token::DOTDOTDOT || self.token == token::DOTDOT {
self.bump();
}
self.eat(&token::DOTDOTDOT);
let end = self.parse_expr_res(RestrictionNoBarOp);
pat = PatRange(start, end);
} else if is_plain_ident(&self.token) && !can_be_enum_or_struct {

5 comments on commit 416144b

@bors

This comment has been minimized.

Copy link
Contributor

@bors bors replied Oct 1, 2014

saw approval from nick29581
at pcwalton@416144b

@bors

This comment has been minimized.

Copy link
Contributor

@bors bors replied Oct 1, 2014

merging pcwalton/rust/range-patterns-dotdotdot = 416144b into auto

@bors

This comment has been minimized.

Copy link
Contributor

@bors bors replied Oct 1, 2014

pcwalton/rust/range-patterns-dotdotdot = 416144b merged ok, testing candidate = 2f15dcd

@bors

This comment has been minimized.

Copy link
Contributor

@bors bors replied Oct 1, 2014

fast-forwarding master to auto = 2f15dcd

Please sign in to comment.
You can’t perform that action at this time.