From: "Earlopain (Earlopain _) via ruby-core" Date: 2025-11-05T13:54:06+00:00 Subject: [ruby-core:123684] [Ruby Bug#21669] Thoroughly implement void value expression check Issue #21669 has been updated by Earlopain (Earlopain _). In prism, that whole check fits in about 130 lines: https://github.com/ruby/ruby/blob/05deec695df55bb72bae8aace673dd2926729d39/src/prism.c#L1027-L1166. Looking at that function, probably it would not be very difficult for prism to support this new behaviour. Not so much complexity, but the runtime cost is there of course (I haven't measured it, I just know it's not zero). I do believe this check has value. Consider `return 1 and 2`, which it currently rejects and also highlights that because of `and` precedence this basically becomes `(return 1) and 2`. That said, the cases here are certainly contrived. ---------------------------------------- Bug #21669: Thoroughly implement void value expression check https://bugs.ruby-lang.org/issues/21669#change-115067 * Author: mame (Yusuke Endoh) * Status: Open * Assignee: prism * Backport: 3.2: UNKNOWN, 3.3: UNKNOWN, 3.4: UNKNOWN ---------------------------------------- A void-value-expression check is a syntax check that raises a `SyntaxError` if an expression that cannot grammatically return a value (a "void value expression," such as a `return` expression) appears in a context where a value is expected (e.g., the right-hand side of an assignment, the argument of a method call, etc.). A typical example rejected by this check is `x = return`. However, it has become clear that this check is incomplete. This ticket summarizes the results of a discussion with @matz at the hackathon before RubyWorld Conference today. ## 1\. Expressions containing branches @matz said that an expression containing branches should be considered a void value expression only if it can be grammatically determined that all possible branches do not return a value. Based on this, both parse.y and prism currently reject the following code with a "void value expression" `SyntaxError`, but it should be accepted: ```ruby x = begin raise return rescue "OK" else return end # Expected: Code parses and executes successfully. # Actual: Rejected with "unexpected void value expression" SyntaxError. ``` Reason: The `rescue` clause can return a value ("OK"), so the entire `begin` expression is not void. Conversely, the following code is currently accepted by both parse.y and prism, but it should be rejected: ```ruby x = begin foo rescue return else return end # Expected: Rejected with SyntaxError. # Actual: Code parses and executes. ``` Reason: This expression always does `return`, so it is void whether `foo` raises an exception or not. Furthermore, `case` expressions must also be rejected similarly when all branches are void: ```ruby x = case when 1; return when 2; return else return end # Expected: Rejected with SyntaxError. # Actual: Code parses and executes. ``` Note that `if` expressions appear to be implemented correctly as intended: ```ruby x = if rand < 0.5 return else return end # Expected: Rejected with SyntaxError. # Actual: Rejected. (OK!) ``` ## 2\. Statement lists containing a void value expression @matz also said that if a statements node contains a void value expression, the entire statement list should be treated as a void value expression, even if the void expression is not the last one. Therefore, the following code is currently accepted but should be rejected: ```ruby x = begin return "NG" end # Expected: Rejected with SyntaxError. # Actual: Code parses and executes. ``` The same applies to branches within other expressions: ```ruby x = if rand < 0.5 return "NG" else return end # Expected: Rejected with SyntaxError. # Actual: Code parses and executes. ``` Note that if a return statement is inside a branch, that statement cannot be considered a void value expression, so the entire expression also cannot be a void value expression. ```ruby x = begin return if true "NG" end # Expected: Code parses and executes. # Actual: Code parses and executes as expected. (OK!) ``` --- This is considered a bug, but if it causes practical compatibility issues, it may be necessary to plan a migration path or revisit the specifications. (Both prism and parse.y need to be fixed, but I'll assign it to the prism team for now.) -- https://bugs.ruby-lang.org/ ______________________________________________ ruby-core mailing list -- ruby-core@ml.ruby-lang.org To unsubscribe send an email to ruby-core-leave@ml.ruby-lang.org ruby-core info -- https://ml.ruby-lang.org/mailman3/lists/ruby-core.ml.ruby-lang.org/