Skip to content

Flaw/inconsistency between block expression description and rustc. #762

Description

@crlf0710

Currently this compiles:

fn foo() -> i32 {
    {3}
}

According to https://doc.rust-lang.org/nightly/reference/expressions/block-expr.html , the {3} part cannot be parsed as tail expression, since it's not ExpressionWithoutBlock. If it is parsed as Statement, then there should be a compile error, because its type is not () and the semicolon could not be not eliminated.

@Centril

Activity

  1. ehuss commented on Feb 16, 2020

    @ehuss
    Contributor

    ExpressionWithoutBlock isn't intended to convey that it is the only kind of "tail expression" in a block. It's intended to convey that ExpressionWithoutBlock can only appear at the end of a block. Blocks as expressions are part of the Statement rule (ExpressionStatement -> ExpressionWithBlock). This is subtly organized to properly handle ; between statements.

    This was written with the concept that a block consists of N statements with ; separating statements, and the last one is the value of the block. I agree it is a little confusing. Looking at it a bit, I think Statements could maybe be changed to use Expression at the end, and it should be the same. I don't remember, but I think I was trying to avoid ambiguity with ExpressionStatement, but that probably isn't too important. Just assume + isn't greedy; the reference doesn't really specify how the grammar is to be interpreted.

    Should also probably clarify the sentence "The type of ExpressionWithBlock expressions when used as statements must be the unit type." as this was intended to cover this case, but that is worded poorly.

    I guess we should decide if a block is defined as "N statements plus a tail expression" or if it is "N statements, and the value is the last statement". I think rustc uses the latter (probably easier to implement), but maybe the former is a better mental model? The former is how I think of it conceptually.

  2. crlf0710 commented on Feb 16, 2020

    @crlf0710
    MemberAuthor

    @ehuss Thank you for confirming that the compiler's behavior is the source of truth in this case here!

    I don't have opinion on which is the better choice here. If the first is chosen, i think it'll be good to also unify the wording of "tail expression" and "final expression" too, since both are occurring in the text; if the second is chosen, maybe we'll need to write something about "value of statement", e.g. assign unit values to declaration statements, and use the expression values as the value of expression statements.

  3. ehuss commented on Jun 22, 2022

    @ehuss
    Contributor
  4. tczajka commented on Oct 10, 2023

    @tczajka
    Contributor

    Just assume + isn't greedy

    This doesn't help: the grammar is actually unambiguous here, so it doesn't matter whether + is greedy. It's just that the grammar has a symbol called Statement when in fact the last Statement is sometimes not a statement (when it's an ExpressionStatement without a semicolon).

    Also the textual description below isn't clear about this. It talks about "final optional expression" but it doesn't say that when the last thing in a block is an ExpressionWithBlock then it's considered the final expression rather than a statement, despite the syntax.

  5. traviscross commented on Jul 16, 2024

    @traviscross
    Contributor

    The grammar in the Reference is correct here, but could be improved for clarity. We'll close this issue in favor of:

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-grammarArea: Syntax and parsing

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions