Fix parsing of block expressions in "forbid_structs" contexts.

Forbidding block expressions entirely is too strict; instead, we should only
forbid them in contexts where we are parsing an optional RHS (i.e. the RHS of a
range expression).
This commit is contained in:
Geoffry Song 2019-10-02 23:38:03 -07:00
parent e1c3675951
commit 9638adaa40
11 changed files with 242 additions and 54 deletions

View file

@ -335,7 +335,13 @@ fn lhs(p: &mut Parser, r: Restrictions) -> Option<(CompletedMarker, BlockLike)>
// }
//
let (lhs, blocklike) = atom::atom_expr(p, r)?;
return Some(postfix_expr(p, lhs, blocklike, !(r.prefer_stmt && blocklike.is_block())));
return Some(postfix_expr(
p,
lhs,
blocklike,
!(r.prefer_stmt && blocklike.is_block()),
r.forbid_structs,
));
}
};
expr_bp(p, r, 255);
@ -350,6 +356,7 @@ fn postfix_expr(
// `while true {break}; ();`
mut block_like: BlockLike,
mut allow_calls: bool,
forbid_structs: bool,
) -> (CompletedMarker, BlockLike) {
loop {
lhs = match p.current() {
@ -363,7 +370,7 @@ fn postfix_expr(
// }
T!['('] if allow_calls => call_expr(p, lhs),
T!['['] if allow_calls => index_expr(p, lhs),
T![.] => match postfix_dot_expr(p, lhs) {
T![.] => match postfix_dot_expr(p, lhs, forbid_structs) {
Ok(it) => it,
Err(it) => {
lhs = it;
@ -382,6 +389,7 @@ fn postfix_expr(
fn postfix_dot_expr(
p: &mut Parser,
lhs: CompletedMarker,
forbid_structs: bool,
) -> Result<CompletedMarker, CompletedMarker> {
assert!(p.at(T![.]));
if p.nth(1) == IDENT && (p.nth(2) == T!['('] || p.nth_at(2, T![::])) {
@ -402,10 +410,17 @@ fn postfix_expr(
}
// test postfix_range
// fn foo() { let x = 1..; }
for &(op, la) in [(T![..=], 3), (T![..], 2)].iter() {
// fn foo() {
// let x = 1..;
// match 1.. { _ => () };
// match a.b()..S { _ => () };
// }
for &(op, la) in &[(T![..=], 3), (T![..], 2)] {
if p.at(op) {
return if EXPR_FIRST.contains(p.nth(la)) {
let next_token = p.nth(la);
let has_trailing_expression =
!(forbid_structs && next_token == T!['{']) && EXPR_FIRST.contains(next_token);
return if has_trailing_expression {
Err(lhs)
} else {
let m = lhs.precede(p);

View file

@ -121,11 +121,7 @@ pub(super) fn atom_expr(p: &mut Parser, r: Restrictions) -> Option<(CompletedMar
// break;
// }
// }
if r.forbid_structs {
return None;
} else {
block_expr(p, None)
}
block_expr(p, None)
}
T![return] => return_expr(p),
T![continue] => continue_expr(p),
@ -261,6 +257,7 @@ fn lambda_expr(p: &mut Parser) -> CompletedMarker {
// if true {} else {};
// if true {} else if false {} else {};
// if S {};
// if { true } { } else { };
// }
fn if_expr(p: &mut Parser) -> CompletedMarker {
assert!(p.at(T![if]));
@ -309,6 +306,7 @@ fn loop_expr(p: &mut Parser, m: Option<Marker>) -> CompletedMarker {
// fn foo() {
// while true {};
// while let Some(x) = it.next() {};
// while { true } {};
// }
fn while_expr(p: &mut Parser, m: Option<Marker>) -> CompletedMarker {
assert!(p.at(T![while]));
@ -356,6 +354,8 @@ fn cond(p: &mut Parser) {
// fn foo() {
// match () { };
// match S {};
// match { } { _ => () };
// match { S {} } {};
// }
fn match_expr(p: &mut Parser) -> CompletedMarker {
assert!(p.at(T![match]));