Skip to content

Commit baa8254

Browse files
authored
Merge pull request jruby#9001 from headius/ruby2_kwargs_indy_fix_9.4
Backport indy ruby2_keywords ArgumentError fix
2 parents a9133e0 + 185d62e commit baa8254

4 files changed

Lines changed: 35 additions & 9 deletions

File tree

core/src/main/java/org/jruby/ir/runtime/IRRuntimeHelpers.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -739,12 +739,12 @@ private static IRubyObject receiverSpecificArityKwargsCommon(ThreadContext conte
739739
// This complicates check_arity but empty ** is special case.
740740
RubyHash hash = (RubyHash) last;
741741
return hash;
742-
} else if (!isKwarg) {
743-
// This is just an ordinary hash as last argument
744-
return last;
745-
} else {
742+
} else if (isKwarg || ((RubyHash) last).isRuby2KeywordHash()) {
746743
RubyHash hash = (RubyHash) last;
747744
return hash.dupFast(context);
745+
} else {
746+
// This is just an ordinary hash as last argument
747+
return last;
748748
}
749749
}
750750

core/src/main/java/org/jruby/ir/targets/indy/InvokeSite.java

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -704,13 +704,13 @@ private void finishBinding(CacheEntry entry, MethodHandle mh, IRubyObject self,
704704
SmartBinder baseBinder = SmartBinder.from(signature.changeReturn(void.class)).permute("context");
705705

706706
// if target method takes keywords and we are passing them, set callInfo
707-
boolean acceptsKeywords = true;
707+
boolean acceptsKeywords;
708708
DynamicMethod method = entry.method;
709709

710710
NativeCallMethod nativeMethod;
711-
if (method instanceof AbstractIRMethod && ((AbstractIRMethod) method).getRuby2Keywords()) {
712-
// Ruby methods with ruby2_keywords don't use formal keywords
713-
acceptsKeywords = false;
711+
if (method instanceof AbstractIRMethod) {
712+
// Ruby methods handle clearing kwargs flags on their own
713+
acceptsKeywords = true;
714714
} else if (method instanceof NativeCallMethod && (nativeMethod = (NativeCallMethod) method).getNativeCall() != null) {
715715
// native methods accept keywords only if specified
716716
DynamicMethod.NativeCall nativeCall = nativeMethod.getNativeCall();
@@ -720,6 +720,8 @@ private void finishBinding(CacheEntry entry, MethodHandle mh, IRubyObject self,
720720
} else {
721721
acceptsKeywords = false;
722722
}
723+
} else {
724+
acceptsKeywords = true;
723725
}
724726

725727
if (flags == 0 || !acceptsKeywords) {

spec/ruby/core/module/ruby2_keywords_spec.rb

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -294,4 +294,29 @@ def obj.foo(**a) end
294294
end
295295
}.should complain(/Skipping set of ruby2_keywords flag for/)
296296
end
297+
298+
describe "used on a method that forwards rest arguments" do
299+
it "properly forwards to a keyword arguments-receiving method" do
300+
obj = Class.new do
301+
def foo(*a, **b)
302+
[a, b]
303+
end
304+
305+
ruby2_keywords def bar(*d)
306+
foo(*d)
307+
end
308+
309+
def test(...)
310+
bar(...)
311+
end
312+
end.new
313+
314+
# Use test forwarding method to ensure bar call site is used repeatedly
315+
# See https://github.com/jruby/jruby/issues/8920#issuecomment-3097667358
316+
obj.test().should == [[], {}]
317+
obj.test(e: 3).should == [[], {e: 3}]
318+
obj.test(1).should == [[1], {}]
319+
obj.test(1, e: 3).should == [[1], {e: 3}]
320+
end
321+
end
297322
end
Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1 @@
11
fails:Module#ruby2_keywords does NOT copy the Hash when calling a method taking (*args)
2-
fails(JIT mode only):Module#ruby2_keywords makes a copy and unmark the Hash when calling a method taking (arg)

0 commit comments

Comments
 (0)