Skip to content

Commit

Permalink
Fix restrictions when parsing rhs of equalities
Browse files Browse the repository at this point in the history
  • Loading branch information
nagisa committed Oct 27, 2015
1 parent 58c299f commit 972c1c6
Show file tree
Hide file tree
Showing 3 changed files with 79 additions and 8 deletions.
37 changes: 29 additions & 8 deletions src/libsyntax/parse/parser.rs
Expand Up @@ -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;
}
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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;')
Expand Down
10 changes: 10 additions & 0 deletions src/libsyntax/util/parser.rs
Expand Up @@ -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 {
Expand Down
40 changes: 40 additions & 0 deletions src/test/run-pass/issue-29071-2.rs
@@ -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);
}

0 comments on commit 972c1c6

Please sign in to comment.