Skip to content

Trailing typecast syntax error when used in functions #46466

Closed
@vojtechkral

Description

@vojtechkral
Contributor

This sort of construct causes a syntax error:

fn foo() -> u32 {
    if true { 3i32 } else { 4i32 } as u32
}
error: expected expression, found keyword `as`

Playground link

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
}

Playground link

The same applies to using match and presumably possibly other expressions as well.

Seems like a bug?

Activity

Havvy

Havvy commented on Dec 3, 2017

@Havvy
Contributor

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

vojtechkral commented on Dec 3, 2017

@vojtechkral
ContributorAuthor

@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

TimNN commented on Dec 5, 2017

@TimNN
Contributor

IIRC this is a known issue. The problem is basically that when the compiler see the if, it needs to decide if the if should be parsed as an expression or a statement, which it can only do from the preceding tokens (This is required so you can do if foo() { bar(); } /* no semicolon here */ foobar();). So in the first example the compiler parses the if as a statement and in the second as an expression.

Havvy

Havvy commented on Dec 6, 2017

@Havvy
Contributor

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.

added
A-parserArea: The lexing & parsing of Rust source code to an AST
C-bugCategory: This is a bug.
on Dec 6, 2017
vojtechkral

vojtechkral commented on Dec 6, 2017

@vojtechkral
ContributorAuthor

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

nodakai commented on Dec 17, 2017

@nodakai
Contributor

Minimal reproducer:

fn f() -> i8 {
    { 0 } as i8
}

I was bitten by this issue when I tried to cast an unsafe expression, actually.

Havvy

Havvy commented on Dec 29, 2017

@Havvy
Contributor

We've changed the documentation in the reference for now. (Via rust-lang/reference#183)

estebank

estebank commented on May 23, 2019

@estebank
Contributor

The compiler now suggests wrapping the expression with parentheses. We're tracking the grammar discussion in #54482.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-parserArea: The lexing & parsing of Rust source code to an ASTC-bugCategory: This is a bug.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

      Development

      No branches or pull requests

        Participants

        @nodakai@kennytm@vojtechkral@Havvy@TimNN

        Issue actions

          Trailing typecast syntax error when used in functions · Issue #46466 · rust-lang/rust