From: "nobu (Nobuyoshi Nakada) via ruby-core" Date: 2025-12-05T11:08:16+00:00 Subject: [ruby-core:124036] [Ruby Bug#21669] Thoroughly implement void value expression check Issue #21669 has been updated by nobu (Nobuyoshi Nakada). Sorry, I've missed this issue. It is done to fix parse.y for 1 and 2. I think 1 is OK, and probably no problem in practice. But 2 is intentionally passed, IIRC, and bootraptest has such code. ```ruby #1526 test_syntax.rb:572: 1.times{ p(1, (next; 2)) }; :ok #=> "" (expected "ok") stderr output is not empty bootstraptest.test_syntax.rb_572_1526.rb: bootstraptest.test_syntax.rb_572_1526.rb:5: void value expression (SyntaxError) p(1, (next; 2)) ^~~~ #1528 test_syntax.rb:584: i = 0 1 + (while true break 2 if (i+=1) > 1 p(1, (next; 2)) end) #=> "" (expected "3") stderr output is not empty bootstraptest.test_syntax.rb_584_1528.rb: bootstraptest.test_syntax.rb_584_1528.rb:7: void value expression (SyntaxError) p(1, (next; 2)) ^~~~ #1529 test_syntax.rb:592: i = 0 1.times{ break if i>1 i+=1 p(1, (redo; 2)) }; :ok #=> "" (expected "ok") stderr output is not empty bootstraptest.test_syntax.rb_592_1529.rb: bootstraptest.test_syntax.rb_592_1529.rb:8: void value expression (SyntaxError) p(1, (redo; 2)) ^~~~ #1531 test_syntax.rb:607: i = 0 1 + (while true break 2 if (i+=1) > 1 p(1, (redo; 2)) end) #=> "" (expected "3") stderr output is not empty bootstraptest.test_syntax.rb_607_1531.rb: bootstraptest.test_syntax.rb_607_1531.rb:7: void value expression (SyntaxError) p(1, (redo; 2)) ^~~~ #259 test_flow.rb:374: $a = []; begin; ; $a << 1 def m1 *args; $a << 2 ; $a << 3 end; $a << 4 def m2; $a << 5 m1(:a, :b, (return 1; :c)); $a << 6 end; $a << 7 m2; $a << 8 ; $a << 9 ; rescue Exception; $a << 99; end; $a #=> "" (expected "[1, 4, 7, 5, 8, 9]") stderr output is not empty bootstraptest.test_flow.rb_374_259.rb: bootstraptest.test_flow.rb_374_259.rb:8: void value expression (SyntaxError) m1(:a, :b, (return 1; :c)); $a << 6 ^~~~~~~~ #261 test_flow.rb:395: $a = []; begin; ; $a << 1 def m2; $a << 2 end; $a << 3 def m(); $a << 4 m2(begin; $a << 5 2; $a << 6 ensure; $a << 7 return 3; $a << 8 end); $a << 9 4; $a << 10 end; $a << 11 m(); $a << 12 ; $a << 13 ; rescue Exception; $a << 99; end; $a #=> "" (expected "[1, 3, 11, 4, 5, 6, 7, 12, 13]") stderr output is not empty bootstraptest.test_flow.rb_395_261.rb: bootstraptest.test_flow.rb_395_261.rb:10: void value expression (SyntaxError) ``` ---------------------------------------- Bug #21669: Thoroughly implement void value expression check https://bugs.ruby-lang.org/issues/21669#change-115467 * 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/