[ruby-core:120628] [Ruby master Bug#21031] Incompatibility with prism and parse.y when eval'ing unnamed forwarding variables

Issue #21031 has been reported by ksss (Yuki Kurihara). ---------------------------------------- Bug #21031: Incompatibility with prism and parse.y when eval'ing unnamed forwarding variables https://bugs.ruby-lang.org/issues/21031 * Author: ksss (Yuki Kurihara) * Status: Open * ruby -v: ruby 3.5.0dev (2025-01-13T03:12:28Z master 384e6945ac) +PRISM [arm64-darwin23] * Backport: 3.1: UNKNOWN, 3.2: UNKNOWN, 3.3: UNKNOWN, 3.4: UNKNOWN ---------------------------------------- ## Case 1 ```rb # t.rb def foo(*) eval("p(*)") end foo(1) ``` ``` $ ruby --parser=prism t.rb t.rb:4:in 'Kernel#eval': (eval at t.rb:4):1: syntax error found (SyntaxError)
1 | p(*) | ^ unexpected `*`; no anonymous rest parameter
from t.rb:4:in 'Object#foo' from t.rb:7:in '<main>' ``` ``` $ ruby --parser=parse.y t.rb 1 ``` ## Case 2 ```rb # t.rb def foo(**) eval("p(**)") end foo(a: 1) ``` ``` $ ruby --parser=prism t.rb t.rb:4:in 'Kernel#eval': (eval at t.rb:4):1: syntax error found (SyntaxError)
1 | p(**) | ^~ unexpected `**`; no anonymous keyword rest parameter
from t.rb:4:in 'Object#foo' from t.rb:7:in '<main>' ``` ``` $ ruby --parser=parse.y t.rb {a: 1} ``` ## Case 3 ```rb # t.rb def foo(&) eval("p(&)") end foo{} ``` ``` $ ruby --parser=prism t.rb t.rb:4:in 'Kernel#eval': (eval at t.rb:4):1: syntax error found (SyntaxError)
1 | p(&) | ^ unexpected `&`; no anonymous block parameter
from t.rb:4:in 'Object#foo' from t.rb:7:in '<main>' ``` ``` $ ruby --parser=parse.y t.rb ``` ## Case 4 ```rb # t.rb def foo(...) eval("p(...)") end foo(1, 2, 3) ``` ``` $ ruby --parser=prism t.rb t.rb:4:in 'Kernel#eval': (eval at t.rb:4):1: syntax error found (SyntaxError)
1 | p(...) | ^~~ unexpected ... when the parent method is not forwarding
from t.rb:4:in 'Object#foo' from t.rb:7:in '<main>' ``` ``` $ ruby --parser=parse.y t.rb 1 2 3 ``` I expect to the parse.y behavior. -- https://bugs.ruby-lang.org/

Issue #21031 has been updated by Eregon (Benoit Daloze). @jeremyevans0 Isn't this parse.y behavior breaking the optimization to forward `*/**/&` efficiently (and maybe `...` too)? It means static analysis can't reason about where the `*/**/&/...` are used. IMO all these should be `SyntaxError`. I'm not sure the parse.y behavior is intentional. ---------------------------------------- Bug #21031: Incompatibility with prism and parse.y when eval'ing unnamed forwarding variables https://bugs.ruby-lang.org/issues/21031#change-111458 * Author: ksss (Yuki Kurihara) * Status: Open * ruby -v: ruby 3.5.0dev (2025-01-13T03:12:28Z master 384e6945ac) +PRISM [arm64-darwin23] * Backport: 3.1: UNKNOWN, 3.2: UNKNOWN, 3.3: UNKNOWN, 3.4: UNKNOWN ---------------------------------------- ## Case 1 ```rb # t.rb def foo(*) eval("p(*)") end foo(1) ``` ``` $ ruby --parser=prism t.rb t.rb:4:in 'Kernel#eval': (eval at t.rb:4):1: syntax error found (SyntaxError)
1 | p(*) | ^ unexpected `*`; no anonymous rest parameter
from t.rb:4:in 'Object#foo' from t.rb:7:in '<main>' ``` ``` $ ruby --parser=parse.y t.rb 1 ``` ## Case 2 ```rb # t.rb def foo(**) eval("p(**)") end foo(a: 1) ``` ``` $ ruby --parser=prism t.rb t.rb:4:in 'Kernel#eval': (eval at t.rb:4):1: syntax error found (SyntaxError)
1 | p(**) | ^~ unexpected `**`; no anonymous keyword rest parameter
from t.rb:4:in 'Object#foo' from t.rb:7:in '<main>' ``` ``` $ ruby --parser=parse.y t.rb {a: 1} ``` ## Case 3 ```rb # t.rb def foo(&) eval("p(&)") end foo{} ``` ``` $ ruby --parser=prism t.rb t.rb:4:in 'Kernel#eval': (eval at t.rb:4):1: syntax error found (SyntaxError)
1 | p(&) | ^ unexpected `&`; no anonymous block parameter
from t.rb:4:in 'Object#foo' from t.rb:7:in '<main>' ``` ``` $ ruby --parser=parse.y t.rb ``` ## Case 4 ```rb # t.rb def foo(...) eval("p(...)") end foo(1, 2, 3) ``` ``` $ ruby --parser=prism t.rb t.rb:4:in 'Kernel#eval': (eval at t.rb:4):1: syntax error found (SyntaxError)
1 | p(...) | ^~~ unexpected ... when the parent method is not forwarding
from t.rb:4:in 'Object#foo' from t.rb:7:in '<main>' ``` ``` $ ruby --parser=parse.y t.rb 1 2 3 ``` I expect to the parse.y behavior. -- https://bugs.ruby-lang.org/

Issue #21031 has been updated by Eregon (Benoit Daloze). As a note, I checked and the `*` and **` examples (Case 1 & 2) work in 3.2 and 3.3. Case 3 / `&` seems incorrect though, as it should print the block but doesn't. ---------------------------------------- Bug #21031: Incompatibility with prism and parse.y when eval'ing unnamed forwarding variables https://bugs.ruby-lang.org/issues/21031#change-111459 * Author: ksss (Yuki Kurihara) * Status: Open * ruby -v: ruby 3.5.0dev (2025-01-13T03:12:28Z master 384e6945ac) +PRISM [arm64-darwin23] * Backport: 3.1: UNKNOWN, 3.2: UNKNOWN, 3.3: UNKNOWN, 3.4: UNKNOWN ---------------------------------------- ## Case 1 ```rb # t.rb def foo(*) eval("p(*)") end foo(1) ``` ``` $ ruby --parser=prism t.rb t.rb:4:in 'Kernel#eval': (eval at t.rb:4):1: syntax error found (SyntaxError)
1 | p(*) | ^ unexpected `*`; no anonymous rest parameter
from t.rb:4:in 'Object#foo' from t.rb:7:in '<main>' ``` ``` $ ruby --parser=parse.y t.rb 1 ``` ## Case 2 ```rb # t.rb def foo(**) eval("p(**)") end foo(a: 1) ``` ``` $ ruby --parser=prism t.rb t.rb:4:in 'Kernel#eval': (eval at t.rb:4):1: syntax error found (SyntaxError)
1 | p(**) | ^~ unexpected `**`; no anonymous keyword rest parameter
from t.rb:4:in 'Object#foo' from t.rb:7:in '<main>' ``` ``` $ ruby --parser=parse.y t.rb {a: 1} ``` ## Case 3 ```rb # t.rb def foo(&) eval("p(&)") end foo{} ``` ``` $ ruby --parser=prism t.rb t.rb:4:in 'Kernel#eval': (eval at t.rb:4):1: syntax error found (SyntaxError)
1 | p(&) | ^ unexpected `&`; no anonymous block parameter
from t.rb:4:in 'Object#foo' from t.rb:7:in '<main>' ``` ``` $ ruby --parser=parse.y t.rb ``` ## Case 4 ```rb # t.rb def foo(...) eval("p(...)") end foo(1, 2, 3) ``` ``` $ ruby --parser=prism t.rb t.rb:4:in 'Kernel#eval': (eval at t.rb:4):1: syntax error found (SyntaxError)
1 | p(...) | ^~~ unexpected ... when the parent method is not forwarding
from t.rb:4:in 'Object#foo' from t.rb:7:in '<main>' ``` ``` $ ruby --parser=parse.y t.rb 1 2 3 ``` I expect to the parse.y behavior. -- https://bugs.ruby-lang.org/

Issue #21031 has been updated by jeremyevans0 (Jeremy Evans). Eregon (Benoit Daloze) wrote in #note-1:
@jeremyevans0 Isn't this parse.y behavior breaking the optimization to forward `*/**/&` efficiently (and maybe `...` too)? It means static analysis can't reason about where the `*/**/&/...` are used.
For `*` and `**`, it shouldn't break the allocationless anonymous splat forwarding optimization. The optimization just makes the parameter not allocate an array/hash, regardless of the content of the method, since you can only splat the arguments, not access them directly. For `&`, there is no optimization for anonymous block arguments. The block argument optimization to avoid Proc allocation was `getblockparamproxy` in Ruby 2.5, and applies to both named and anonymous blocks, and I believe works fine in `eval` (maybe @ko1 can confirm). For `...`, that never used allocationless anonymous splat forwarding in a shipped version of Ruby, only temporarily during the 3.4 development cycle. @tenderlovemaking applied a separate generic argument forwarding optimization (commit:cdf33ed5f37f9649c482c3ba1d245f0d80ac01ce). I assume it works inside `eval`, but @tenderlovemaking would know better than I. ---------------------------------------- Bug #21031: Incompatibility with prism and parse.y when eval'ing unnamed forwarding variables https://bugs.ruby-lang.org/issues/21031#change-111464 * Author: ksss (Yuki Kurihara) * Status: Open * ruby -v: ruby 3.5.0dev (2025-01-13T03:12:28Z master 384e6945ac) +PRISM [arm64-darwin23] * Backport: 3.1: UNKNOWN, 3.2: UNKNOWN, 3.3: UNKNOWN, 3.4: UNKNOWN ---------------------------------------- ## Case 1 ```rb # t.rb def foo(*) eval("p(*)") end foo(1) ``` ``` $ ruby --parser=prism t.rb t.rb:4:in 'Kernel#eval': (eval at t.rb:4):1: syntax error found (SyntaxError)
1 | p(*) | ^ unexpected `*`; no anonymous rest parameter
from t.rb:4:in 'Object#foo' from t.rb:7:in '<main>' ``` ``` $ ruby --parser=parse.y t.rb 1 ``` ## Case 2 ```rb # t.rb def foo(**) eval("p(**)") end foo(a: 1) ``` ``` $ ruby --parser=prism t.rb t.rb:4:in 'Kernel#eval': (eval at t.rb:4):1: syntax error found (SyntaxError)
1 | p(**) | ^~ unexpected `**`; no anonymous keyword rest parameter
from t.rb:4:in 'Object#foo' from t.rb:7:in '<main>' ``` ``` $ ruby --parser=parse.y t.rb {a: 1} ``` ## Case 3 ```rb # t.rb def foo(&) eval("p(&)") end foo{} ``` ``` $ ruby --parser=prism t.rb t.rb:4:in 'Kernel#eval': (eval at t.rb:4):1: syntax error found (SyntaxError)
1 | p(&) | ^ unexpected `&`; no anonymous block parameter
from t.rb:4:in 'Object#foo' from t.rb:7:in '<main>' ``` ``` $ ruby --parser=parse.y t.rb ``` ## Case 4 ```rb # t.rb def foo(...) eval("p(...)") end foo(1, 2, 3) ``` ``` $ ruby --parser=prism t.rb t.rb:4:in 'Kernel#eval': (eval at t.rb:4):1: syntax error found (SyntaxError)
1 | p(...) | ^~~ unexpected ... when the parent method is not forwarding
from t.rb:4:in 'Object#foo' from t.rb:7:in '<main>' ``` ``` $ ruby --parser=parse.y t.rb 1 2 3 ``` I expect to the parse.y behavior. -- https://bugs.ruby-lang.org/

Issue #21031 has been updated by Eregon (Benoit Daloze). Assignee set to prism Thanks for clarifying, I thought the allocationless anonymous splat forwarding optimization relied on some specific usage of `*`/`**` but it seems not, all good. Then given this all works on 3.2 and 3.3 as well this seems a clear bug of the Prism compiler. ---------------------------------------- Bug #21031: Incompatibility with prism and parse.y when eval'ing unnamed forwarding variables https://bugs.ruby-lang.org/issues/21031#change-111465 * Author: ksss (Yuki Kurihara) * Status: Open * Assignee: prism * ruby -v: ruby 3.5.0dev (2025-01-13T03:12:28Z master 384e6945ac) +PRISM [arm64-darwin23] * Backport: 3.1: UNKNOWN, 3.2: UNKNOWN, 3.3: UNKNOWN, 3.4: UNKNOWN ---------------------------------------- ## Case 1 ```rb # t.rb def foo(*) eval("p(*)") end foo(1) ``` ``` $ ruby --parser=prism t.rb t.rb:4:in 'Kernel#eval': (eval at t.rb:4):1: syntax error found (SyntaxError)
1 | p(*) | ^ unexpected `*`; no anonymous rest parameter
from t.rb:4:in 'Object#foo' from t.rb:7:in '<main>' ``` ``` $ ruby --parser=parse.y t.rb 1 ``` ## Case 2 ```rb # t.rb def foo(**) eval("p(**)") end foo(a: 1) ``` ``` $ ruby --parser=prism t.rb t.rb:4:in 'Kernel#eval': (eval at t.rb:4):1: syntax error found (SyntaxError)
1 | p(**) | ^~ unexpected `**`; no anonymous keyword rest parameter
from t.rb:4:in 'Object#foo' from t.rb:7:in '<main>' ``` ``` $ ruby --parser=parse.y t.rb {a: 1} ``` ## Case 3 ```rb # t.rb def foo(&) eval("p(&)") end foo{} ``` ``` $ ruby --parser=prism t.rb t.rb:4:in 'Kernel#eval': (eval at t.rb:4):1: syntax error found (SyntaxError)
1 | p(&) | ^ unexpected `&`; no anonymous block parameter
from t.rb:4:in 'Object#foo' from t.rb:7:in '<main>' ``` ``` $ ruby --parser=parse.y t.rb ``` ## Case 4 ```rb # t.rb def foo(...) eval("p(...)") end foo(1, 2, 3) ``` ``` $ ruby --parser=prism t.rb t.rb:4:in 'Kernel#eval': (eval at t.rb:4):1: syntax error found (SyntaxError)
1 | p(...) | ^~~ unexpected ... when the parent method is not forwarding
from t.rb:4:in 'Object#foo' from t.rb:7:in '<main>' ``` ``` $ ruby --parser=parse.y t.rb 1 2 3 ``` I expect to the parse.y behavior. -- https://bugs.ruby-lang.org/

Issue #21031 has been updated by k0kubun (Takashi Kokubun). Backport changed from 3.1: UNKNOWN, 3.2: UNKNOWN, 3.3: UNKNOWN, 3.4: REQUIRED to 3.1: UNKNOWN, 3.2: UNKNOWN, 3.3: UNKNOWN, 3.4: DONE ruby_3_4 commit:7adf89d7ad30552d7e57709d24eec266f601d38b merged revision(s) commit:cb419e3912f0514b8151469b0a4a4b83cbbcce78. ---------------------------------------- Bug #21031: Incompatibility with prism and parse.y when eval'ing unnamed forwarding variables https://bugs.ruby-lang.org/issues/21031#change-111925 * Author: ksss (Yuki Kurihara) * Status: Closed * Assignee: prism * ruby -v: ruby 3.5.0dev (2025-01-13T03:12:28Z master 384e6945ac) +PRISM [arm64-darwin23] * Backport: 3.1: UNKNOWN, 3.2: UNKNOWN, 3.3: UNKNOWN, 3.4: DONE ---------------------------------------- ## Case 1 ```rb # t.rb def foo(*) eval("p(*)") end foo(1) ``` ``` $ ruby --parser=prism t.rb t.rb:4:in 'Kernel#eval': (eval at t.rb:4):1: syntax error found (SyntaxError)
1 | p(*) | ^ unexpected `*`; no anonymous rest parameter
from t.rb:4:in 'Object#foo' from t.rb:7:in '<main>' ``` ``` $ ruby --parser=parse.y t.rb 1 ``` ## Case 2 ```rb # t.rb def foo(**) eval("p(**)") end foo(a: 1) ``` ``` $ ruby --parser=prism t.rb t.rb:4:in 'Kernel#eval': (eval at t.rb:4):1: syntax error found (SyntaxError)
1 | p(**) | ^~ unexpected `**`; no anonymous keyword rest parameter
from t.rb:4:in 'Object#foo' from t.rb:7:in '<main>' ``` ``` $ ruby --parser=parse.y t.rb {a: 1} ``` ## Case 3 ```rb # t.rb def foo(&) eval("p(&)") end foo{} ``` ``` $ ruby --parser=prism t.rb t.rb:4:in 'Kernel#eval': (eval at t.rb:4):1: syntax error found (SyntaxError)
1 | p(&) | ^ unexpected `&`; no anonymous block parameter
from t.rb:4:in 'Object#foo' from t.rb:7:in '<main>' ``` ``` $ ruby --parser=parse.y t.rb ``` ## Case 4 ```rb # t.rb def foo(...) eval("p(...)") end foo(1, 2, 3) ``` ``` $ ruby --parser=prism t.rb t.rb:4:in 'Kernel#eval': (eval at t.rb:4):1: syntax error found (SyntaxError)
1 | p(...) | ^~~ unexpected ... when the parent method is not forwarding
from t.rb:4:in 'Object#foo' from t.rb:7:in '<main>' ``` ``` $ ruby --parser=parse.y t.rb 1 2 3 ``` I expect to the parse.y behavior. -- https://bugs.ruby-lang.org/

Issue #21031 has been updated by k0kubun (Takashi Kokubun). Backport changed from 3.1: UNKNOWN, 3.2: UNKNOWN, 3.3: UNKNOWN, 3.4: DONE to 3.1: UNKNOWN, 3.2: UNKNOWN, 3.3: UNKNOWN, 3.4: REQUIRED Reverted the backport commit:7adf89d7ad30552d7e57709d24eec266f601d38b for now to fix undeclared identifier/function errors. ---------------------------------------- Bug #21031: Incompatibility with prism and parse.y when eval'ing unnamed forwarding variables https://bugs.ruby-lang.org/issues/21031#change-111943 * Author: ksss (Yuki Kurihara) * Status: Closed * Assignee: prism * ruby -v: ruby 3.5.0dev (2025-01-13T03:12:28Z master 384e6945ac) +PRISM [arm64-darwin23] * Backport: 3.1: UNKNOWN, 3.2: UNKNOWN, 3.3: UNKNOWN, 3.4: REQUIRED ---------------------------------------- ## Case 1 ```rb # t.rb def foo(*) eval("p(*)") end foo(1) ``` ``` $ ruby --parser=prism t.rb t.rb:4:in 'Kernel#eval': (eval at t.rb:4):1: syntax error found (SyntaxError)
1 | p(*) | ^ unexpected `*`; no anonymous rest parameter
from t.rb:4:in 'Object#foo' from t.rb:7:in '<main>' ``` ``` $ ruby --parser=parse.y t.rb 1 ``` ## Case 2 ```rb # t.rb def foo(**) eval("p(**)") end foo(a: 1) ``` ``` $ ruby --parser=prism t.rb t.rb:4:in 'Kernel#eval': (eval at t.rb:4):1: syntax error found (SyntaxError)
1 | p(**) | ^~ unexpected `**`; no anonymous keyword rest parameter
from t.rb:4:in 'Object#foo' from t.rb:7:in '<main>' ``` ``` $ ruby --parser=parse.y t.rb {a: 1} ``` ## Case 3 ```rb # t.rb def foo(&) eval("p(&)") end foo{} ``` ``` $ ruby --parser=prism t.rb t.rb:4:in 'Kernel#eval': (eval at t.rb:4):1: syntax error found (SyntaxError)
1 | p(&) | ^ unexpected `&`; no anonymous block parameter
from t.rb:4:in 'Object#foo' from t.rb:7:in '<main>' ``` ``` $ ruby --parser=parse.y t.rb ``` ## Case 4 ```rb # t.rb def foo(...) eval("p(...)") end foo(1, 2, 3) ``` ``` $ ruby --parser=prism t.rb t.rb:4:in 'Kernel#eval': (eval at t.rb:4):1: syntax error found (SyntaxError)
1 | p(...) | ^~~ unexpected ... when the parent method is not forwarding
from t.rb:4:in 'Object#foo' from t.rb:7:in '<main>' ``` ``` $ ruby --parser=parse.y t.rb 1 2 3 ``` I expect to the parse.y behavior. -- https://bugs.ruby-lang.org/

Issue #21031 has been updated by k0kubun (Takashi Kokubun). Backport changed from 3.1: UNKNOWN, 3.2: UNKNOWN, 3.3: UNKNOWN, 3.4: REQUIRED to 3.1: UNKNOWN, 3.2: UNKNOWN, 3.3: UNKNOWN, 3.4: DONE ruby_3_4 commit:45fe3c137b6cc0b2546493e37d6334d8f39e076d. ---------------------------------------- Bug #21031: Incompatibility with prism and parse.y when eval'ing unnamed forwarding variables https://bugs.ruby-lang.org/issues/21031#change-111969 * Author: ksss (Yuki Kurihara) * Status: Closed * Assignee: prism * ruby -v: ruby 3.5.0dev (2025-01-13T03:12:28Z master 384e6945ac) +PRISM [arm64-darwin23] * Backport: 3.1: UNKNOWN, 3.2: UNKNOWN, 3.3: UNKNOWN, 3.4: DONE ---------------------------------------- ## Case 1 ```rb # t.rb def foo(*) eval("p(*)") end foo(1) ``` ``` $ ruby --parser=prism t.rb t.rb:4:in 'Kernel#eval': (eval at t.rb:4):1: syntax error found (SyntaxError)
1 | p(*) | ^ unexpected `*`; no anonymous rest parameter
from t.rb:4:in 'Object#foo' from t.rb:7:in '<main>' ``` ``` $ ruby --parser=parse.y t.rb 1 ``` ## Case 2 ```rb # t.rb def foo(**) eval("p(**)") end foo(a: 1) ``` ``` $ ruby --parser=prism t.rb t.rb:4:in 'Kernel#eval': (eval at t.rb:4):1: syntax error found (SyntaxError)
1 | p(**) | ^~ unexpected `**`; no anonymous keyword rest parameter
from t.rb:4:in 'Object#foo' from t.rb:7:in '<main>' ``` ``` $ ruby --parser=parse.y t.rb {a: 1} ``` ## Case 3 ```rb # t.rb def foo(&) eval("p(&)") end foo{} ``` ``` $ ruby --parser=prism t.rb t.rb:4:in 'Kernel#eval': (eval at t.rb:4):1: syntax error found (SyntaxError)
1 | p(&) | ^ unexpected `&`; no anonymous block parameter
from t.rb:4:in 'Object#foo' from t.rb:7:in '<main>' ``` ``` $ ruby --parser=parse.y t.rb ``` ## Case 4 ```rb # t.rb def foo(...) eval("p(...)") end foo(1, 2, 3) ``` ``` $ ruby --parser=prism t.rb t.rb:4:in 'Kernel#eval': (eval at t.rb:4):1: syntax error found (SyntaxError)
1 | p(...) | ^~~ unexpected ... when the parent method is not forwarding
from t.rb:4:in 'Object#foo' from t.rb:7:in '<main>' ``` ``` $ ruby --parser=parse.y t.rb 1 2 3 ``` I expect to the parse.y behavior. -- https://bugs.ruby-lang.org/
participants (4)
-
Eregon (Benoit Daloze)
-
jeremyevans0 (Jeremy Evans)
-
k0kubun (Takashi Kokubun)
-
ksss (Yuki Kurihara)