1
0
Fork 0
mirror of https://github.com/ruby/ruby.git synced 2022-11-09 12:17:21 -05:00

Don't pass an empty keyword hash when double splatting empty hash when calling cfunc

This mirrors earlier changes in keyword argument separation for
calling Ruby methods and calling procs/lambdas, so that behavior
is kept the same.
This commit is contained in:
Jeremy Evans 2019-08-31 21:51:02 -07:00
parent e80a6f65c8
commit 15757390ff
2 changed files with 146 additions and 1 deletions

View file

@ -227,6 +227,144 @@ class TestKeywordArguments < Test::Unit::TestCase
assert_equal([1, h3], f[**h3])
end
def test_cfunc_kwsplat_call
kw = {}
h = {'a'=>1}
h2 = {'a'=>1}
h3 = {'a'=>1, :a=>1}
sc = Class.new do
attr_reader :args
class << self
alias [] new
end
end
c = Class.new(sc) do
def initialize(*args)
@args = args
end
end
assert_equal([], c[**{}].args)
assert_equal([], c[**kw].args)
assert_equal([h], c[**h].args)
assert_equal([h2], c[**h2].args)
assert_equal([h3], c[**h3].args)
c = Class.new(sc) do
def initialize; end
end
assert_nil(c[**{}].args)
assert_nil(c[**kw].args)
assert_raise(ArgumentError) { c[**h] }
assert_raise(ArgumentError) { c[**h2] }
assert_raise(ArgumentError) { c[**h3] }
c = Class.new(sc) do
def initialize(args)
@args = args
end
end
assert_raise(ArgumentError) { c[**{}] }
assert_raise(ArgumentError) { c[**kw] }
assert_equal(h, c[**h].args)
assert_equal(h2, c[**h2].args)
assert_equal(h3, c[**h3].args)
c = Class.new(sc) do
def initialize(**args)
@args = args
end
end
assert_equal(kw, c[**{}].args)
assert_equal(kw, c[**kw].args)
assert_equal(h, c[**h].args)
assert_equal(h2, c[**h2].args)
assert_equal(h3, c[**h3].args)
c = Class.new(sc) do
def initialize(arg, **args)
@args = [arg, args]
end
end
assert_raise(ArgumentError) { c[**{}] }
assert_raise(ArgumentError) { c[**kw] }
assert_equal([h, kw], c[**h].args)
assert_equal([h2, kw], c[**h2].args)
assert_equal([h3, kw], c[**h3].args)
c = Class.new(sc) do
def initialize(arg=1, **args)
@args = [arg=1, args]
end
end
assert_equal([1, kw], c[**{}].args)
assert_equal([1, kw], c[**kw].args)
assert_equal([1, h], c[**h].args)
assert_equal([1, h2], c[**h2].args)
assert_equal([1, h3], c[**h3].args)
end
def test_method_kwsplat_call
kw = {}
h = {'a'=>1}
h2 = {'a'=>1}
h3 = {'a'=>1, :a=>1}
c = Object.new
def c.m(*args)
args
end
assert_equal([], c.method(:m)[**{}])
assert_equal([], c.method(:m)[**kw])
assert_equal([h], c.method(:m)[**h])
assert_equal([h2], c.method(:m)[**h2])
assert_equal([h3], c.method(:m)[**h3])
def c.m; end
assert_nil(c.method(:m)[**{}])
assert_nil(c.method(:m)[**kw])
assert_raise(ArgumentError) { c.method(:m)[**h] }
assert_raise(ArgumentError) { c.method(:m)[**h2] }
assert_raise(ArgumentError) { c.method(:m)[**h3] }
def c.m(args)
args
end
assert_raise(ArgumentError) { c.method(:m)[**{}] }
assert_raise(ArgumentError) { c.method(:m)[**kw] }
assert_equal(h, c.method(:m)[**h])
assert_equal(h2, c.method(:m)[**h2])
assert_equal(h3, c.method(:m)[**h3])
def c.m(**args)
args
end
assert_equal(kw, c.method(:m)[**{}])
assert_equal(kw, c.method(:m)[**kw])
assert_equal(h, c.method(:m)[**h])
assert_equal(h2, c.method(:m)[**h2])
assert_equal(h3, c.method(:m)[**h3])
def c.m(arg, **args)
[arg, args]
end
assert_raise(ArgumentError) { c.method(:m)[**{}] }
assert_raise(ArgumentError) { c.method(:m)[**kw] }
assert_equal([h, kw], c.method(:m)[**h])
assert_equal([h2, kw], c.method(:m)[**h2])
assert_equal([h3, kw], c.method(:m)[**h3])
def c.m(arg=1, **args)
[arg=1, args]
end
assert_equal([1, kw], c.method(:m)[**{}])
assert_equal([1, kw], c.method(:m)[**kw])
assert_equal([1, h], c.method(:m)[**h])
assert_equal([1, h2], c.method(:m)[**h2])
assert_equal([1, h3], c.method(:m)[**h3])
end
def p1
Proc.new do |str: "foo", num: 424242|
[str, num]

View file

@ -2186,6 +2186,13 @@ vm_call_cfunc_with_frame(rb_execution_context_t *ec, rb_control_frame_t *reg_cfp
VALUE recv = calling->recv;
VALUE block_handler = calling->block_handler;
int argc = calling->argc;
int orig_argc = argc;
if (UNLIKELY(IS_ARGS_KW_SPLAT(ci))) {
if (RHASH_EMPTY_P(*(GET_SP()-1))) {
argc--;
}
}
RUBY_DTRACE_CMETHOD_ENTRY_HOOK(ec, me->owner, me->def->original_id);
EXEC_EVENT_HOOK(ec, RUBY_EVENT_C_CALL, recv, me->def->original_id, ci->mid, me->owner, Qundef);
@ -2196,7 +2203,7 @@ vm_call_cfunc_with_frame(rb_execution_context_t *ec, rb_control_frame_t *reg_cfp
if (len >= 0) rb_check_arity(argc, len, len);
reg_cfp->sp -= argc + 1;
reg_cfp->sp -= orig_argc + 1;
val = (*cfunc->invoker)(recv, argc, reg_cfp->sp + 1, cfunc->func);
CHECK_CFP_CONSISTENCY("vm_call_cfunc");