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

Fix keyword argument separation issues in Enumerator::Generator#each

This requires adding rb_proc_call_kw to pass the keyword flag.
This commit is contained in:
Jeremy Evans 2019-09-26 09:10:42 -07:00
parent dd2068ac8d
commit 37f9213f89
Notes: git 2019-09-27 07:31:16 +09:00
4 changed files with 97 additions and 1 deletions

View file

@ -1506,7 +1506,7 @@ generator_each(int argc, VALUE *argv, VALUE obj)
rb_ary_cat(args, argv, argc);
}
return rb_proc_call(ptr->proc, args);
return rb_proc_call_kw(ptr->proc, args, RB_PASS_CALLED_KEYWORDS);
}
/* Lazy Enumerator methods */

View file

@ -454,6 +454,7 @@ VALUE rb_block_lambda(void);
VALUE rb_proc_new(rb_block_call_func_t, VALUE);
VALUE rb_obj_is_proc(VALUE);
VALUE rb_proc_call(VALUE, VALUE);
VALUE rb_proc_call_kw(VALUE, VALUE, int);
VALUE rb_proc_call_with_block(VALUE, int argc, const VALUE *argv, VALUE);
VALUE rb_proc_call_with_block_kw(VALUE, int argc, const VALUE *argv, VALUE, int);
int rb_proc_arity(VALUE);

18
proc.c
View file

@ -934,6 +934,24 @@ check_argc(long argc)
#define check_argc(argc) (argc)
#endif
VALUE
rb_proc_call_kw(VALUE self, VALUE args, int kw_splat)
{
VALUE vret;
rb_proc_t *proc;
VALUE v;
int argc = check_argc(RARRAY_LEN(args));
const VALUE *argv = RARRAY_CONST_PTR(args);
GetProcPtr(self, proc);
v = rb_adjust_argv_kw_splat(&argc, &argv, &kw_splat);
vret = rb_vm_invoke_proc(GET_EC(), proc, argc, argv,
kw_splat, VM_BLOCK_HANDLER_NONE);
rb_free_tmp_buffer(&v);
RB_GC_GUARD(self);
RB_GC_GUARD(args);
return vret;
}
VALUE
rb_proc_call(VALUE self, VALUE args)
{

View file

@ -841,6 +841,83 @@ class TestKeywordArguments < Test::Unit::TestCase
assert_equal([1, h3], t.new(&f).resume(a: 1, **h2))
end
def test_Enumerator_Generator_each_kwsplat
kw = {}
h = {:a=>1}
h2 = {'a'=>1}
h3 = {'a'=>1, :a=>1}
g = Enumerator::Generator
f = ->(_) { true }
assert_equal(true, g.new(&f).each(**{}))
assert_equal(true, g.new(&f).each(**kw))
assert_raise(ArgumentError) { g.new(&f).each(**h) }
assert_raise(ArgumentError) { g.new(&f).each(a: 1) }
assert_raise(ArgumentError) { g.new(&f).each(**h2) }
assert_raise(ArgumentError) { g.new(&f).each(**h3) }
f = ->(_, a) { a }
assert_warn(/The keyword argument is passed as the last hash parameter/m) do
assert_equal(kw, g.new(&f).each(**{}))
end
assert_warn(/The keyword argument is passed as the last hash parameter/m) do
assert_equal(kw, g.new(&f).each(**kw))
end
assert_equal(h, g.new(&f).each(**h))
assert_equal(h, g.new(&f).each(a: 1))
assert_equal(h2, g.new(&f).each(**h2))
assert_equal(h3, g.new(&f).each(**h3))
assert_equal(h3, g.new(&f).each(a: 1, **h2))
f = ->(_, **x) { x }
assert_equal(kw, g.new(&f).each(**{}))
assert_equal(kw, g.new(&f).each(**kw))
assert_equal(h, g.new(&f).each(**h))
assert_equal(h, g.new(&f).each(a: 1))
assert_equal(h2, g.new(&f).each(**h2))
assert_equal(h3, g.new(&f).each(**h3))
assert_equal(h3, g.new(&f).each(a: 1, **h2))
assert_warn(/The last argument is used as the keyword parameter.*for method/m) do
assert_equal(h, g.new(&f).each(h))
end
assert_raise(ArgumentError) { g.new(&f).each(h2) }
assert_warn(/The last argument is split into positional and keyword parameters.*for method/m) do
assert_raise(ArgumentError) { g.new(&f).each(h3) }
end
f = ->(_, a, **x) { [a,x] }
assert_warn(/The keyword argument is passed as the last hash parameter/) do
assert_equal([{}, {}], g.new(&f).each(**{}))
end
assert_warn(/The keyword argument is passed as the last hash parameter/) do
assert_equal([{}, {}], g.new(&f).each(**kw))
end
assert_warn(/The keyword argument is passed as the last hash parameter/) do
assert_equal([h, {}], g.new(&f).each(**h))
end
assert_warn(/The keyword argument is passed as the last hash parameter/) do
assert_equal([h, {}], g.new(&f).each(a: 1))
end
assert_warn(/The keyword argument is passed as the last hash parameter/) do
assert_equal([h2, {}], g.new(&f).each(**h2))
end
assert_warn(/The keyword argument is passed as the last hash parameter/) do
assert_equal([h3, {}], g.new(&f).each(**h3))
end
assert_warn(/The keyword argument is passed as the last hash parameter/) do
assert_equal([h3, {}], g.new(&f).each(a: 1, **h2))
end
f = ->(_, a=1, **x) { [a, x] }
assert_equal([1, kw], g.new(&f).each(**{}))
assert_equal([1, kw], g.new(&f).each(**kw))
assert_equal([1, h], g.new(&f).each(**h))
assert_equal([1, h], g.new(&f).each(a: 1))
assert_equal([1, h2], g.new(&f).each(**h2))
assert_equal([1, h3], g.new(&f).each(**h3))
assert_equal([1, h3], g.new(&f).each(a: 1, **h2))
end
def test_Class_new_kwsplat_call
kw = {}
h = {:a=>1}