ruby-changes:57597
From: Yusuke <ko1@a...>
Date: Fri, 6 Sep 2019 14:05:13 +0900 (JST)
Subject: [ruby-changes:57597] 55b96c5d2d (master): Add a keyword-to-last-hash warning for some case of define_method method
https://git.ruby-lang.org/ruby.git/commit/?id=55b96c5d2d From 55b96c5d2d7d8bcc2953484bd2f9c9519b252dae Mon Sep 17 00:00:00 2001 From: Yusuke Endoh <mame@r...> Date: Thu, 5 Sep 2019 19:29:25 +0900 Subject: Add a keyword-to-last-hash warning for some case of define_method method and lambda. When define_method is a simple iseq (`define_method(:m) {|x| ... }`), passing keywords to it (`m(**kw)`) didn't print a warning. diff --git a/test/ruby/test_keyword.rb b/test/ruby/test_keyword.rb index 229f0b3..71b72bd 100644 --- a/test/ruby/test_keyword.rb +++ b/test/ruby/test_keyword.rb @@ -185,20 +185,42 @@ class TestKeywordArguments < Test::Unit::TestCase https://github.com/ruby/ruby/blob/trunk/test/ruby/test_keyword.rb#L185 f = -> { true } assert_equal(true, f[**{}]) - assert_raise(ArgumentError) { f[**kw] } - assert_raise(ArgumentError) { f[**h] } - assert_raise(ArgumentError) { f[a: 1] } - assert_raise(ArgumentError) { f[**h2] } - assert_raise(ArgumentError) { f[**h3] } + assert_warn(/The keyword argument is passed as the last hash parameter/m) do + assert_raise(ArgumentError) { f[**kw] } + end + assert_warn(/The keyword argument is passed as the last hash parameter/m) do + assert_raise(ArgumentError) { f[**h] } + end + assert_warn(/The keyword argument is passed as the last hash parameter/m) do + assert_raise(ArgumentError) { f[a: 1] } + end + assert_warn(/The keyword argument is passed as the last hash parameter/m) do + assert_raise(ArgumentError) { f[**h2] } + end + assert_warn(/The keyword argument is passed as the last hash parameter/m) do + assert_raise(ArgumentError) { f[**h3] } + end f = ->(a) { a } assert_raise(ArgumentError) { f[**{}] } - assert_equal(kw, f[**kw]) - assert_equal(h, f[**h]) - assert_equal(h, f[a: 1]) - assert_equal(h2, f[**h2]) - assert_equal(h3, f[**h3]) - assert_equal(h3, f[a: 1, **h2]) + assert_warn(/The keyword argument is passed as the last hash parameter/m) do + assert_equal(kw, f[**kw]) + end + assert_warn(/The keyword argument is passed as the last hash parameter/m) do + assert_equal(h, f[**h]) + end + assert_warn(/The keyword argument is passed as the last hash parameter/m) do + assert_equal(h, f[a: 1]) + end + assert_warn(/The keyword argument is passed as the last hash parameter/m) do + assert_equal(h2, f[**h2]) + end + assert_warn(/The keyword argument is passed as the last hash parameter/m) do + assert_equal(h3, f[**h3]) + end + assert_warn(/The keyword argument is passed as the last hash parameter/m) do + assert_equal(h3, f[a: 1, **h2]) + end f = ->(**x) { x } assert_equal(kw, f[**{}]) @@ -685,24 +707,48 @@ class TestKeywordArguments < Test::Unit::TestCase https://github.com/ruby/ruby/blob/trunk/test/ruby/test_keyword.rb#L707 define_method(:m) { } end assert_nil(c.m(**{})) - assert_raise(ArgumentError) { c.m(**kw) } - assert_raise(ArgumentError) { c.m(**h) } - assert_raise(ArgumentError) { c.m(a: 1) } - assert_raise(ArgumentError) { c.m(**h2) } - assert_raise(ArgumentError) { c.m(**h3) } - assert_raise(ArgumentError) { c.m(a: 1, **h2) } + assert_warn(/The keyword argument is passed as the last hash parameter/m) do + assert_raise(ArgumentError) { c.m(**kw) } + end + assert_warn(/The keyword argument is passed as the last hash parameter/m) do + assert_raise(ArgumentError) { c.m(**h) } + end + assert_warn(/The keyword argument is passed as the last hash parameter/m) do + assert_raise(ArgumentError) { c.m(a: 1) } + end + assert_warn(/The keyword argument is passed as the last hash parameter/m) do + assert_raise(ArgumentError) { c.m(**h2) } + end + assert_warn(/The keyword argument is passed as the last hash parameter/m) do + assert_raise(ArgumentError) { c.m(**h3) } + end + assert_warn(/The keyword argument is passed as the last hash parameter/m) do + assert_raise(ArgumentError) { c.m(a: 1, **h2) } + end c = Object.new class << c define_method(:m) {|arg| arg } end assert_raise(ArgumentError) { c.m(**{}) } - assert_equal(kw, c.m(**kw)) - assert_equal(h, c.m(**h)) - assert_equal(h, c.m(a: 1)) - assert_equal(h2, c.m(**h2)) - assert_equal(h3, c.m(**h3)) - assert_equal(h3, c.m(a: 1, **h2)) + assert_warn(/The keyword argument is passed as the last hash parameter/m) do + assert_equal(kw, c.m(**kw)) + end + assert_warn(/The keyword argument is passed as the last hash parameter/m) do + assert_equal(h, c.m(**h)) + end + assert_warn(/The keyword argument is passed as the last hash parameter/m) do + assert_equal(h, c.m(a: 1)) + end + assert_warn(/The keyword argument is passed as the last hash parameter/m) do + assert_equal(h2, c.m(**h2)) + end + assert_warn(/The keyword argument is passed as the last hash parameter/m) do + assert_equal(h3, c.m(**h3)) + end + assert_warn(/The keyword argument is passed as the last hash parameter/m) do + assert_equal(h3, c.m(a: 1, **h2)) + end c = Object.new class << c @@ -1211,10 +1257,14 @@ class TestKeywordArguments < Test::Unit::TestCase https://github.com/ruby/ruby/blob/trunk/test/ruby/test_keyword.rb#L1257 o = Object.new def o.to_hash() { a: 1 } end - assert_equal({a: 1}, m1(**o) {|x| break x}, bug9898) + assert_warn(/The keyword argument is passed as the last hash parameter/m) do + assert_equal({a: 1}, m1(**o) {|x| break x}, bug9898) + end o2 = Object.new def o2.to_hash() { b: 2 } end - assert_equal({a: 1, b: 2}, m1(**o, **o2) {|x| break x}, bug9898) + assert_warn(/The keyword argument is passed as the last hash parameter/m) do + assert_equal({a: 1, b: 2}, m1(**o, **o2) {|x| break x}, bug9898) + end end def test_implicit_hash_conversion diff --git a/vm_insnhelper.c b/vm_insnhelper.c index 92a9bc6..baf93de 100644 --- a/vm_insnhelper.c +++ b/vm_insnhelper.c @@ -2929,6 +2929,10 @@ vm_callee_setup_block_arg(rb_execution_context_t *ec, struct rb_calling_info *ca https://github.com/ruby/ruby/blob/trunk/vm_insnhelper.c#L2929 CALLER_SETUP_ARG(cfp, calling, ci, 0); /* splat arg */ + if (calling->kw_splat) { + rb_warn_keyword_to_last_hash(calling, ci, iseq); + } + if (arg_setup_type == arg_setup_block && calling->argc == 1 && iseq->body->param.flags.has_lead && -- cgit v0.10.2 -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/