summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--test/ruby/test_keyword.rb49
-rw-r--r--vm_insnhelper.c6
-rw-r--r--vm_insnhelper.h1
3 files changed, 56 insertions, 0 deletions
diff --git a/test/ruby/test_keyword.rb b/test/ruby/test_keyword.rb
index 6212d582f5..000f55744d 100644
--- a/test/ruby/test_keyword.rb
+++ b/test/ruby/test_keyword.rb
@@ -177,6 +177,55 @@ class TestKeywordArguments < Test::Unit::TestCase
assert_equal(["bar", 111111], f[str: "bar", num: 111111])
end
+ def test_lambda_kwsplat_call
+ kw = {}
+ h = {'a'=>1}
+ h2 = {'a'=>1}
+ h3 = {'a'=>1, :a=>1}
+
+ f = -> { true }
+ assert_equal(true, f[**{}])
+ assert_equal(true, f[**kw])
+ assert_raise(ArgumentError) { f[**h] }
+ assert_raise(ArgumentError) { f[**h2] }
+ assert_raise(ArgumentError) { f[**h3] }
+
+ f = ->(a) { a }
+ assert_raise(ArgumentError) { f[**{}] }
+ assert_raise(ArgumentError) { f[**kw] }
+ assert_equal(h, f[**h])
+ assert_equal(h2, f[**h2])
+ assert_equal(h3, f[**h3])
+
+ f = ->(**x) { x }
+ assert_equal(kw, f[**{}])
+ assert_equal(kw, f[**kw])
+ assert_equal(h, f[**h])
+ assert_equal(h2, f[**h2])
+ assert_equal(h3, f[**h3])
+
+ f = ->(a, **x) { [a,x] }
+ assert_raise(ArgumentError) { f[**{}] }
+ assert_warn(/The keyword argument for `\[\]' .* is passed as the last hash parameter/) do
+ assert_equal([{}, {}], f[**kw])
+ end
+ assert_warn(/The keyword argument for `\[\]' .* is passed as the last hash parameter/) do
+ assert_equal([h, {}], f[**h])
+ end
+ assert_warn(/The keyword argument for `\[\]' .* is passed as the last hash parameter/) do
+ assert_equal([h2, {}], f[**h2])
+ end
+ assert_warn(/The keyword argument for `\[\]' .* is passed as the last hash parameter/) do
+ assert_equal([h3, {}], f[**h3])
+ end
+
+ f = ->(a=1, **x) { [a, x] }
+ assert_equal([1, kw], f[**{}])
+ assert_equal([1, kw], f[**kw])
+ assert_equal([1, h], f[**h])
+ assert_equal([1, h2], f[**h2])
+ assert_equal([1, h3], f[**h3])
+ end
def p1
Proc.new do |str: "foo", num: 424242|
diff --git a/vm_insnhelper.c b/vm_insnhelper.c
index 2e86a0d3a2..71c5930b2e 100644
--- a/vm_insnhelper.c
+++ b/vm_insnhelper.c
@@ -2912,6 +2912,12 @@ vm_callee_setup_block_arg(rb_execution_context_t *ec, struct rb_calling_info *ca
CALLER_SETUP_ARG(cfp, calling, ci, 1); /* splat arg */
+ if (UNLIKELY(IS_ARGS_KW_SPLAT(ci))) {
+ if (RHASH_EMPTY_P(argv[calling->argc-1])) {
+ calling->argc--;
+ }
+ }
+
if (arg_setup_type == arg_setup_block &&
calling->argc == 1 &&
iseq->body->param.flags.has_lead &&
diff --git a/vm_insnhelper.h b/vm_insnhelper.h
index f937af8b59..7709840930 100644
--- a/vm_insnhelper.h
+++ b/vm_insnhelper.h
@@ -240,6 +240,7 @@ THROW_DATA_CONSUMED_SET(struct vm_throw_data *obj)
#define IS_ARGS_SPLAT(ci) ((ci)->flag & VM_CALL_ARGS_SPLAT)
#define IS_ARGS_KEYWORD(ci) ((ci)->flag & VM_CALL_KWARG)
+#define IS_ARGS_KW_SPLAT(ci) ((ci)->flag & VM_CALL_KW_SPLAT)
/* If this returns true, an optimized function returned by `vm_call_iseq_setup_func`
can be used as a fastpath. */