aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--test/ruby/test_keyword.rb12
-rw-r--r--vm_args.c11
2 files changed, 19 insertions, 4 deletions
diff --git a/test/ruby/test_keyword.rb b/test/ruby/test_keyword.rb
index 9425e1df5d..59008f7d5b 100644
--- a/test/ruby/test_keyword.rb
+++ b/test/ruby/test_keyword.rb
@@ -507,6 +507,7 @@ class TestKeywordArguments < Test::Unit::TestCase
m = Object.new
def m.f() :ok; end
def m.f2(a = nil) a; end
+ def m.f3(**a) a; end
o = {a: 1}
assert_raise_with_message(ArgumentError, /unknown keyword: a/) {
m.f(**o)
@@ -517,9 +518,16 @@ class TestKeywordArguments < Test::Unit::TestCase
assert_equal(:ok, m.f(*a, **o), '[ruby-core:83638] [Bug #10856]')
o = {a: 42}
- assert_equal({a: 42}, m.f2(**o), '[ruby-core:82280] [Bug #13791]')
+ assert_warning(/splat keyword/) do
+ assert_equal({a: 42}, m.f2(**o), '[ruby-core:82280] [Bug #13791]')
+ end
+ assert_warning('') do
+ assert_equal({a: 42}, m.f3(**o), 'splat to kwrest')
+ end
- assert_equal({a: 42}, m.f2("a".to_sym => 42), '[ruby-core:82291] [Bug #13793]')
+ assert_warning('') do
+ assert_equal({a: 42}, m.f2("a".to_sym => 42), '[ruby-core:82291] [Bug #13793]')
+ end
o = {}
a = [:ok]
diff --git a/vm_args.c b/vm_args.c
index d1207f7f62..c5a83b9946 100644
--- a/vm_args.c
+++ b/vm_args.c
@@ -509,6 +509,7 @@ setup_parameters_complex(rb_execution_context_t * const ec, const rb_iseq_t * co
const int max_argc = (iseq->body->param.flags.has_rest == FALSE) ? min_argc + iseq->body->param.opt_num : UNLIMITED_ARGUMENTS;
int opt_pc = 0;
int given_argc;
+ int kw_splat = FALSE;
struct args_info args_body, *args;
VALUE keyword_hash = Qnil;
VALUE * const orig_sp = ec->cfp->sp;
@@ -600,10 +601,12 @@ setup_parameters_complex(rb_execution_context_t * const ec, const rb_iseq_t * co
}
}
+ if (ci->flag & VM_CALL_KW_SPLAT) {
+ kw_splat = !iseq->body->param.flags.has_rest;
+ }
if (given_argc > min_argc &&
(iseq->body->param.flags.has_kw || iseq->body->param.flags.has_kwrest ||
- (!iseq->body->param.flags.has_rest && given_argc > max_argc &&
- (ci->flag & VM_CALL_KW_SPLAT))) &&
+ (kw_splat && given_argc > max_argc)) &&
args->kw_argv == NULL) {
if (args_pop_keyword_hash(args, &keyword_hash)) {
given_argc--;
@@ -667,6 +670,10 @@ setup_parameters_complex(rb_execution_context_t * const ec, const rb_iseq_t * co
else if (!NIL_P(keyword_hash) && RHASH_SIZE(keyword_hash) > 0) {
argument_kw_error(ec, iseq, "unknown", rb_hash_keys(keyword_hash));
}
+ else if (kw_splat && NIL_P(keyword_hash)) {
+ rb_warning("passing splat keyword arguments as a single Hash"
+ " to `% "PRIsVALUE"'", rb_id2str(ci->mid));
+ }
if (iseq->body->param.flags.has_block) {
if (iseq->body->local_iseq == iseq) {