Closed
Description
This sort of construct causes a syntax error:
fn foo() -> u32 {
if true { 3i32 } else { 4i32 } as u32
}
error: expected expression, found keyword `as`
The same syntax works fine in an assignment form:
let foo = if true { 3i32 } else { 4i32 } as u32;
And so it is surprising that it doesn't work in a function context.
When parentheses are added, it parses in the function context too:
fn foo() -> u32 {
(if true { 3i32 } else { 4i32 }) as u32
}
The same applies to using match
and presumably possibly other expressions as well.
Seems like a bug?
Metadata
Metadata
Assignees
Type
Projects
Milestone
Relationships
Development
No branches or pull requests
Activity
Havvy commentedon Dec 3, 2017
Not so much when used as functions, but when a block expression or control flow expression is used as the left expression of a binary expression that is the outer expression of an expression statement or block expression.
The Reference says An expression that consists of only a block expression or control flow expression, that doesn't end a block and evaluates to
()
can also be used as an expression statement by omitting the trailing semicolon. In these examples, the control flow expression is evaluating to a non-unit value. So either this is a legitimate bug (which I think should be the case) or the reference is wrong.vojtechkral commentedon Dec 3, 2017
@Havvy Thanks!
If this is indeed a bug, might I perhaps grab the opportunity and get a bit more familiar with the parsing internals by fixing it myself?
TimNN commentedon Dec 5, 2017
IIRC this is a known issue. The problem is basically that when the compiler see the
if
, it needs to decide if theif
should be parsed as an expression or a statement, which it can only do from the preceding tokens (This is required so you can doif foo() { bar(); } /* no semicolon here */ foobar();
). So in the first example the compiler parses theif
as a statement and in the second as an expression.Havvy commentedon Dec 6, 2017
Likewise, if the reference is wrong here, it might be useful to have a diagnostic for when a binary operator starts an expression statement after the implied semicolon from the control flow/block expression.
vojtechkral commentedon Dec 6, 2017
I can see a bit of a problem with the specification in the reference: It makes parsing depend on types. Correct me if I'm wrong, but isn't type inferrence a later pass?
nodakai commentedon Dec 17, 2017
Minimal reproducer:
I was bitten by this issue when I tried to cast an
unsafe
expression, actually.Havvy commentedon Dec 29, 2017
We've changed the documentation in the reference for now. (Via rust-lang/reference#183)
estebank commentedon May 23, 2019
The compiler now suggests wrapping the expression with parentheses. We're tracking the grammar discussion in #54482.