summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--test/ruby/test_allocation.rb77
-rw-r--r--test/ruby/test_keyword.rb14
-rw-r--r--vm_args.c39
-rw-r--r--vm_insnhelper.c4
4 files changed, 118 insertions, 16 deletions
@@ -2,10 +2,16 @@
require 'test/unit'
class TestAllocation < Test::Unit::TestCase
def check_allocations(checks)
dups = checks.split("\n").reject(&:empty?).tally.select{|_,v| v > 1}
raise "duplicate checks:\n#{dups.keys.join("\n")}" unless dups.empty?
assert_separately([], <<~RUBY)
$allocations = [0, 0]
$counts = {}
@@ -549,7 +555,8 @@ class TestAllocation < Test::Unit::TestCase
def test_nested_anonymous_splat_and_anonymous_keyword_splat_parameters
check_allocations(<<~RUBY)
- def self.anon_splat_and_anon_keyword_splat(*, **#{block}); t(*, **) end; def self.t(*, **#{block}); end
check_allocations(1, 1, "anon_splat_and_anon_keyword_splat(1, a: 2#{block})")
check_allocations(1, 0, "anon_splat_and_anon_keyword_splat(1, *empty_array, a: 2#{block})")
@@ -639,7 +646,8 @@ class TestAllocation < Test::Unit::TestCase
def test_nested_argument_forwarding
check_allocations(<<~RUBY)
- def self.argument_forwarding(...); t(...) end; def self.t(...) end
check_allocations(0, 0, "argument_forwarding(1, a: 2#{block})")
check_allocations(0, 0, "argument_forwarding(1, *empty_array, a: 2#{block})")
@@ -766,4 +774,69 @@ class TestAllocation < Test::Unit::TestCase
end
end
end
end
@@ -2848,6 +2848,20 @@ class TestKeywordArguments < Test::Unit::TestCase
assert_equal(1, process(:foo, bar: :baz))
end
def test_top_ruby2_keywords
assert_in_out_err([], <<-INPUT, ["[1, 2, 3]", "{:k=>1}"], [])
def bar(*a, **kw)
@@ -571,6 +571,22 @@ check_kwrestarg(VALUE keyword_hash, unsigned int *kw_flag)
}
}
static int
setup_parameters_complex(rb_execution_context_t * const ec, const rb_iseq_t * const iseq,
struct rb_calling_info *const calling,
@@ -727,35 +743,32 @@ setup_parameters_complex(rb_execution_context_t * const ec, const rb_iseq_t * co
args->rest_dupped = false;
if (ignore_keyword_hash_p(rest_last, iseq, &kw_flag, &converted_keyword_hash)) {
- if (ISEQ_BODY(iseq)->param.flags.has_rest || arg_setup_type != arg_setup_method) {
// Only duplicate/modify splat array if it will be used
arg_rest_dup(args);
rb_ary_pop(args->rest);
}
given_argc--;
}
else if (!ISEQ_BODY(iseq)->param.flags.has_rest) {
// Avoid duping rest when not necessary
// Copy rest elements and converted keyword hash directly to VM stack
- const VALUE *argv = RARRAY_CONST_PTR(args->rest);
- int j, i=args->argc, rest_len = RARRAY_LENINT(args->rest)-1;
- args->argc += rest_len;
- if (rest_len) {
- CHECK_VM_STACK_OVERFLOW(ec->cfp, rest_len+1);
- for (i, j=0; rest_len > 0; rest_len--, i++, j++) {
- locals[i] = argv[j];
- }
- }
- args->rest = Qfalse;
- ci_flag &= ~VM_CALL_ARGS_SPLAT;
if (ISEQ_BODY(iseq)->param.flags.has_kw || ISEQ_BODY(iseq)->param.flags.has_kwrest) {
given_argc--;
keyword_hash = converted_keyword_hash;
}
else {
args->argc += 1;
- locals[i] = converted_keyword_hash;
keyword_hash = Qnil;
kw_flag = 0;
}
@@ -2739,9 +2739,11 @@ vm_caller_setup_keyword_hash(const struct rb_callinfo *ci, VALUE keyword_hash)
keyword_hash = rb_hash_dup(rb_to_hash_type(keyword_hash));
}
}
- else if (!IS_ARGS_KW_SPLAT_MUT(ci)) {
/* Convert a hash keyword splat to a new hash unless
* a mutable keyword splat was passed.
*/
keyword_hash = rb_hash_dup(keyword_hash);
}