reference icon indicating copy to clipboard operation
reference copied to clipboard

Flaw/inconsistency between block expression description and rustc.

Open crlf0710 opened this issue 4 years ago • 4 comments

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

crlf0710 avatar Feb 16 '20 03:02 crlf0710

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.

ehuss avatar Feb 16 '20 05:02 ehuss

@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.

crlf0710 avatar Feb 16 '20 07:02 crlf0710

cc https://github.com/rust-lang/rust/issues/61733

ehuss avatar Jun 22 '22 21:06 ehuss

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.

tczajka avatar Oct 10 '23 06:10 tczajka