Skip to content

Commit

Permalink
Fix precedence for ranges.
Browse files Browse the repository at this point in the history
Technically this is a

[breaking-change]

but it probably shouldn't affect your code.

Closes #20256
  • Loading branch information
nrc committed Jan 7, 2015
1 parent e15f043 commit 63a9bd5
Show file tree
Hide file tree
Showing 2 changed files with 75 additions and 18 deletions.
41 changes: 23 additions & 18 deletions src/libsyntax/parse/parser.rs
Expand Up @@ -2536,7 +2536,7 @@ impl<'a> Parser<'a> {
}

// expr[...]
// An index expression.
// Could be either an index expression or a slicing expression.
token::OpenDelim(token::Bracket) => {
let bracket_pos = self.span.lo;
self.bump();
Expand Down Expand Up @@ -2576,22 +2576,6 @@ impl<'a> Parser<'a> {
"use `&expr[]` to construct a slice of the whole of expr");
}
}

// A range expression, either `expr..expr` or `expr..`.
token::DotDot if !self.restrictions.contains(RESTRICTION_NO_DOTS) => {
self.bump();

let opt_end = if self.token.can_begin_expr() {
let end = self.parse_expr_res(RESTRICTION_NO_DOTS);
Some(end)
} else {
None
};

let hi = self.span.hi;
let range = self.mk_range(Some(e), opt_end);
return self.mk_expr(lo, hi, range);
}
_ => return e
}
}
Expand Down Expand Up @@ -2834,7 +2818,7 @@ impl<'a> Parser<'a> {
token::DotDot if !self.restrictions.contains(RESTRICTION_NO_DOTS) => {
// A range, closed above: `..expr`.
self.bump();
let e = self.parse_prefix_expr();
let e = self.parse_expr();
hi = e.span.hi;
ex = self.mk_range(None, Some(e));
}
Expand Down Expand Up @@ -2901,6 +2885,7 @@ impl<'a> Parser<'a> {
self.restrictions.contains(RESTRICTION_NO_BAR_OP) {
return lhs;
}

self.expected_tokens.push(TokenType::Operator);

let cur_opt = self.token.to_binop();
Expand All @@ -2909,6 +2894,7 @@ impl<'a> Parser<'a> {
let cur_prec = operator_prec(cur_op);
if cur_prec > min_prec {
self.bump();
// TODO
let expr = self.parse_prefix_expr();
let rhs = self.parse_more_binops(expr, cur_prec);
let lhs_span = lhs.span;
Expand Down Expand Up @@ -2970,6 +2956,25 @@ impl<'a> Parser<'a> {
let assign_op = self.mk_assign_op(aop, lhs, rhs);
self.mk_expr(span.lo, rhs_span.hi, assign_op)
}
// TODO
// A range expression, either `expr..expr` or `expr..`.
token::DotDot if !self.restrictions.contains(RESTRICTION_NO_DOTS) => {
self.bump();

let opt_end = if self.token.can_begin_expr() {
// TODO only use of RES...DOT
let end = self.parse_expr_res(RESTRICTION_NO_DOTS);
Some(end)
} else {
None
};

let lo = lhs.span.lo;
let hi = self.span.hi;
let range = self.mk_range(Some(lhs), opt_end);
return self.mk_expr(lo, hi, range);
}

_ => {
lhs
}
Expand Down
52 changes: 52 additions & 0 deletions src/test/run-pass/ranges-precedence.rs
@@ -0,0 +1,52 @@
// Copyright 2015 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.

// Test that the precedence of ranges is correct

#![feature(slicing_syntax)]

struct Foo {
foo: uint,
}

impl Foo {
fn bar(&self) -> uint { 5 }
}

fn main() {
let x = 1+3..4+5;
assert!(x == (4..9));

let x = 1..4+5;
assert!(x == (1..9));

let x = 1+3..4;
assert!(x == (4..4));

let a = Foo { foo: 3 };
let x = a.foo..a.bar();
assert!(x == (3..5));

let x = 1+3..;
assert!(x == (4..));
let x = ..1+3;
assert!(x == (..4));

let a = &[0i32, 1, 2, 3, 4, 5, 6];
let x = &a[1+1..2+2];
assert!(x == &a[2..4]);
let x = &a[..1+2];
assert!(x == &a[..3]);
let x = &a[1+2..];
assert!(x == &a[3..]);

for _i in 2+4..10-3 {}
}

0 comments on commit 63a9bd5

Please sign in to comment.