Fix restrictions when parsing rhs of equalities

This commit is contained in:
Simonas Kazlauskas 2015-10-16 22:42:06 +03:00
parent 58c299f81d
commit 972c1c6a5f
3 changed files with 79 additions and 8 deletions

View File

@ -2666,13 +2666,18 @@ impl<'a> Parser<'a> {
} else {
try!(self.parse_prefix_expr())
};
if self.expr_is_complete(&*lhs) && min_prec == 0 {
if self.expr_is_complete(&*lhs) {
// Semi-statement forms are odd. See https://github.com/rust-lang/rust/issues/29071
return Ok(lhs);
}
let cur_op_span = self.span;
self.expected_tokens.push(TokenType::Operator);
while let Some(op) = AssocOp::from_token(&self.token) {
let restrictions = if op.is_assign_like() {
self.restrictions & Restrictions::RESTRICTION_NO_STRUCT_LITERAL
} else {
self.restrictions
};
if op.precedence() < min_prec {
break;
}
@ -2706,12 +2711,19 @@ impl<'a> Parser<'a> {
break
}
let rhs = try!(match op.fixity() {
Fixity::Right => self.parse_assoc_expr_with(op.precedence(), None),
Fixity::Left => self.parse_assoc_expr_with(op.precedence() + 1, None),
Fixity::Right => self.with_res(restrictions, |this|{
this.parse_assoc_expr_with(op.precedence(), None)
}),
Fixity::Left => self.with_res(restrictions, |this|{
this.parse_assoc_expr_with(op.precedence() + 1, None)
}),
// We currently have no non-associative operators that are not handled above by
// the special cases. The code is here only for future convenience.
Fixity::None => self.parse_assoc_expr_with(op.precedence() + 1, None),
Fixity::None => self.with_res(restrictions, |this|{
this.parse_assoc_expr_with(op.precedence() + 1, None)
}),
});
lhs = match op {
@ -2974,13 +2986,22 @@ impl<'a> Parser<'a> {
self.parse_expr_res(Restrictions::empty())
}
/// Parse an expression, subject to the given restrictions
pub fn parse_expr_res(&mut self, r: Restrictions) -> PResult<P<Expr>> {
/// Evaluate the closure with restrictions in place.
///
/// After the closure is evaluated, restrictions are reset.
pub fn with_res<F>(&mut self, r: Restrictions, f: F) -> PResult<P<Expr>>
where F: FnOnce(&mut Self) -> PResult<P<Expr>> {
let old = self.restrictions;
self.restrictions = r;
let e = try!(self.parse_assoc_expr());
let r = f(self);
self.restrictions = old;
return Ok(e);
return r;
}
/// Parse an expression, subject to the given restrictions
pub fn parse_expr_res(&mut self, r: Restrictions) -> PResult<P<Expr>> {
self.with_res(r, |this| this.parse_assoc_expr())
}
/// Parse the RHS of a local variable declaration (e.g. '= 14;')

View File

@ -172,6 +172,16 @@ impl AssocOp {
}
}
pub fn is_assign_like(&self) -> bool {
use self::AssocOp::*;
match *self {
Assign | AssignOp(_) | Inplace => true,
Less | Greater | LessEqual | GreaterEqual | Equal | NotEqual | As | Multiply | Divide |
Modulus | Add | Subtract | ShiftLeft | ShiftRight | BitAnd | BitXor | BitOr | LAnd |
LOr | DotDot => false
}
}
pub fn to_ast_binop(&self) -> Option<ast::BinOp_> {
use self::AssocOp::*;
match *self {

View File

@ -0,0 +1,40 @@
// 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.
fn t1() -> u32 {
let x;
x = if true { [1, 2, 3] } else { [2, 3, 4] }[0];
x
}
fn t2() -> [u32; 1] {
if true { [1, 2, 3]; } else { [2, 3, 4]; }
[0]
}
fn t3() -> u32 {
let x;
x = if true { i1 as F } else { i2 as F }();
x
}
fn t4() -> () {
if true { i1 as F; } else { i2 as F; }
()
}
type F = fn() -> u32;
fn i1() -> u32 { 1 }
fn i2() -> u32 { 2 }
fn main() {
assert_eq!(t1(), 1);
assert_eq!(t3(), 1);
}