Fix yielding to methods that take two params from Hash#each#6451
Fix yielding to methods that take two params from Hash#each#6451headius merged 2 commits intojruby:masterfrom
Conversation
|
Good find, thank you for the effort! We will review and get this merged in. Might be a candidate for 9.2.14, @kares @enebo? The JI spec failures can be ignored due to #6452. The test is great, but since this is a standard Ruby behavior it would be better as a Ruby spec. Can you migrate the test into spec/ruby (under core/method or language perhaps) so other Ruby impls will benefit from it? |
|
For sure! I've opened a PR to merge a spec that tests the same thing in ruby/spec: ruby/spec#811 What should I do with this PR while I wait for the ruby/spec one to get approved? Should I remove the test from this commit or will we merge this as is and remove the duplication later when JRuby syncs up with ruby/spec? |
|
See ruby/spec#811 (comment), I believe Method#to_proc is always strict and does not auto-splat. It seems specific behavior of Hash#{each/each_pair/map} rather, originating from an optimization not intentionally changing semantics. Note in Ruby 3 Hash#{each/each_pair} don't exhibit this strange behavior anymore |
|
Thanks @eregon! You're correct. I will try to come up with a better fix |
|
@marshalium I will wait to hear back from you about the correct behavior and fix for this. These special splatting behaviors have always been a mystery, and have gone back and forth over the years. In this case I'm getting that it's the combination of a proc-ified Method fed to Hash#each and friends resulting in unexpected behavior... where we are strictly enforcing the arity and not splatting the incoming argument array, CRuby passes two arguments explicitly rather than two arguments as an argument array. Needless to say these exceptions are confusing and frustrating, and I'm glad this will be more normalized for 3.0. |
|
@marshalium My five minute patch may be along the right lines: I have not confirmed whether this breaks anything but from discussions it sounds like this is close to the proper behavior. |
efdb8a9 to
430f8ad
Compare
|
Thx! I kept the removal of the unnecessary |
|
Ah, here's the thing I don't understand. It's the opposite bug where lambdas are too lenient. And it's why this looked like a Method#to_proc issue and not a general arity enforcing issue. On Ruby 2.5.8 you don't get auto-splatting when yielding two args to a lambda outside of special cases like Hash#each: In JRuby it works without error: And what's weird is that calling the lambda directly doesn't have this magic behavior: So this makes me more confident that the arity checking was just always missing and it wasn't very noticeable because this other lambda arity checking bug is here. EDIT: I think this is the same bug: #6165 |
430f8ad to
180f2b6
Compare
The only place this method is called from was hardcoding the param to false.
This matches what MRI ruby does. It allows methods to be called with either one or two args. And fixes issue jruby#5896
|
The behavior of a lambda fed to |
|
@marshalium The only failure in your latest push appears to be a JDK-downloading glitch which I have restarted. I am glad to see so many tags go away! We will review and get this merged soon. |
headius
left a comment
There was a problem hiding this comment.
Looks good to me. The only real change is the separate yield in Hash#each, which matches CRuby logic. The other changes just remove dead code.
This fixes issue #5896 by always splatting out the arguments if possible.
I was surprised that
Helpers.restructureBlockArgs()is only used here. Not sure why this is a special case.Overall I'm not 100% sure about this fix. But since I couldn't get the tests to all run locally I'm opening up this PR in hopes that CI can reveal issues or someone here can tell me what I'm missing.