Reduce duplicated warnings for the change of Ruby 3 keyword arguments
By this change, the following code prints only one warning. ``` def foo(**opt); end 100.times { foo({kw:1}) } ``` A global variable `st_table *caller_to_callees` is a map from caller to a set of callee methods. It remembers that a warning is already printed for each pair of caller and callee. [Feature #16289]
This commit is contained in:
parent
3a87826d0c
commit
191ce5344e
Notes:
git
2019-11-29 17:32:53 +09:00
@ -313,9 +313,19 @@ class TestKeywordArguments < Test::Unit::TestCase
|
|||||||
|
|
||||||
sc = Class.new
|
sc = Class.new
|
||||||
c = sc.new
|
c = sc.new
|
||||||
def c.m(*args, **kw)
|
redef = -> do
|
||||||
super
|
if defined?(c.m)
|
||||||
|
class << c
|
||||||
|
remove_method(:m)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
eval <<-END
|
||||||
|
def c.m(*args, **kw)
|
||||||
|
super(*args, **kw)
|
||||||
|
end
|
||||||
|
END
|
||||||
end
|
end
|
||||||
|
redef[]
|
||||||
sc.class_eval do
|
sc.class_eval do
|
||||||
def m(*args)
|
def m(*args)
|
||||||
args
|
args
|
||||||
@ -350,6 +360,7 @@ class TestKeywordArguments < Test::Unit::TestCase
|
|||||||
assert_warn(/The keyword argument is passed as the last hash parameter.* for `m'/m) do
|
assert_warn(/The keyword argument is passed as the last hash parameter.* for `m'/m) do
|
||||||
assert_equal(kw, c.m(**{}))
|
assert_equal(kw, c.m(**{}))
|
||||||
end
|
end
|
||||||
|
redef[]
|
||||||
assert_warn(/The keyword argument is passed as the last hash parameter.* for `m'/m) do
|
assert_warn(/The keyword argument is passed as the last hash parameter.* for `m'/m) do
|
||||||
assert_equal(kw, c.m(**kw))
|
assert_equal(kw, c.m(**kw))
|
||||||
end
|
end
|
||||||
@ -386,24 +397,31 @@ class TestKeywordArguments < Test::Unit::TestCase
|
|||||||
[arg, args]
|
[arg, args]
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
redef[]
|
||||||
assert_warn(/The keyword argument is passed as the last hash parameter.* for `m'/m) do
|
assert_warn(/The keyword argument is passed as the last hash parameter.* for `m'/m) do
|
||||||
c.m(**{})
|
c.m(**{})
|
||||||
end
|
end
|
||||||
|
redef[]
|
||||||
assert_warn(/The keyword argument is passed as the last hash parameter.* for `m'/m) do
|
assert_warn(/The keyword argument is passed as the last hash parameter.* for `m'/m) do
|
||||||
c.m(**kw)
|
c.m(**kw)
|
||||||
end
|
end
|
||||||
|
redef[]
|
||||||
assert_warn(/The keyword argument is passed as the last hash parameter.* for `m'/m) do
|
assert_warn(/The keyword argument is passed as the last hash parameter.* for `m'/m) do
|
||||||
assert_equal([h, kw], c.m(**h))
|
assert_equal([h, kw], c.m(**h))
|
||||||
end
|
end
|
||||||
|
redef[]
|
||||||
assert_warn(/The keyword argument is passed as the last hash parameter.* for `m'/m) do
|
assert_warn(/The keyword argument is passed as the last hash parameter.* for `m'/m) do
|
||||||
assert_equal([h, kw], c.m(a: 1))
|
assert_equal([h, kw], c.m(a: 1))
|
||||||
end
|
end
|
||||||
|
redef[]
|
||||||
assert_warn(/The keyword argument is passed as the last hash parameter.* for `m'/m) do
|
assert_warn(/The keyword argument is passed as the last hash parameter.* for `m'/m) do
|
||||||
assert_equal([h2, kw], c.m(**h2))
|
assert_equal([h2, kw], c.m(**h2))
|
||||||
end
|
end
|
||||||
|
redef[]
|
||||||
assert_warn(/The keyword argument is passed as the last hash parameter.* for `m'/m) do
|
assert_warn(/The keyword argument is passed as the last hash parameter.* for `m'/m) do
|
||||||
assert_equal([h3, kw], c.m(**h3))
|
assert_equal([h3, kw], c.m(**h3))
|
||||||
end
|
end
|
||||||
|
redef[]
|
||||||
assert_warn(/The keyword argument is passed as the last hash parameter.* for `m'/m) do
|
assert_warn(/The keyword argument is passed as the last hash parameter.* for `m'/m) do
|
||||||
assert_equal([h3, kw], c.m(a: 1, **h2))
|
assert_equal([h3, kw], c.m(a: 1, **h2))
|
||||||
end
|
end
|
||||||
@ -431,9 +449,19 @@ class TestKeywordArguments < Test::Unit::TestCase
|
|||||||
|
|
||||||
sc = Class.new
|
sc = Class.new
|
||||||
c = sc.new
|
c = sc.new
|
||||||
def c.m(*args, **kw)
|
redef = -> do
|
||||||
super(*args, **kw)
|
if defined?(c.m)
|
||||||
|
class << c
|
||||||
|
remove_method(:m)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
eval <<-END
|
||||||
|
def c.m(*args, **kw)
|
||||||
|
super(*args, **kw)
|
||||||
|
end
|
||||||
|
END
|
||||||
end
|
end
|
||||||
|
redef[]
|
||||||
sc.class_eval do
|
sc.class_eval do
|
||||||
def m(*args)
|
def m(*args)
|
||||||
args
|
args
|
||||||
@ -468,6 +496,7 @@ class TestKeywordArguments < Test::Unit::TestCase
|
|||||||
assert_warn(/The keyword argument is passed as the last hash parameter.* for `m'/m) do
|
assert_warn(/The keyword argument is passed as the last hash parameter.* for `m'/m) do
|
||||||
assert_equal(kw, c.m(**{}))
|
assert_equal(kw, c.m(**{}))
|
||||||
end
|
end
|
||||||
|
redef[]
|
||||||
assert_warn(/The keyword argument is passed as the last hash parameter.* for `m'/m) do
|
assert_warn(/The keyword argument is passed as the last hash parameter.* for `m'/m) do
|
||||||
assert_equal(kw, c.m(**kw))
|
assert_equal(kw, c.m(**kw))
|
||||||
end
|
end
|
||||||
@ -504,24 +533,31 @@ class TestKeywordArguments < Test::Unit::TestCase
|
|||||||
[arg, args]
|
[arg, args]
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
redef[]
|
||||||
assert_warn(/The keyword argument is passed as the last hash parameter.* for `m'/m) do
|
assert_warn(/The keyword argument is passed as the last hash parameter.* for `m'/m) do
|
||||||
c.m(**{})
|
c.m(**{})
|
||||||
end
|
end
|
||||||
|
redef[]
|
||||||
assert_warn(/The keyword argument is passed as the last hash parameter.* for `m'/m) do
|
assert_warn(/The keyword argument is passed as the last hash parameter.* for `m'/m) do
|
||||||
c.m(**kw)
|
c.m(**kw)
|
||||||
end
|
end
|
||||||
|
redef[]
|
||||||
assert_warn(/The keyword argument is passed as the last hash parameter.* for `m'/m) do
|
assert_warn(/The keyword argument is passed as the last hash parameter.* for `m'/m) do
|
||||||
assert_equal([h, kw], c.m(**h))
|
assert_equal([h, kw], c.m(**h))
|
||||||
end
|
end
|
||||||
|
redef[]
|
||||||
assert_warn(/The keyword argument is passed as the last hash parameter.* for `m'/m) do
|
assert_warn(/The keyword argument is passed as the last hash parameter.* for `m'/m) do
|
||||||
assert_equal([h, kw], c.m(a: 1))
|
assert_equal([h, kw], c.m(a: 1))
|
||||||
end
|
end
|
||||||
|
redef[]
|
||||||
assert_warn(/The keyword argument is passed as the last hash parameter.* for `m'/m) do
|
assert_warn(/The keyword argument is passed as the last hash parameter.* for `m'/m) do
|
||||||
assert_equal([h2, kw], c.m(**h2))
|
assert_equal([h2, kw], c.m(**h2))
|
||||||
end
|
end
|
||||||
|
redef[]
|
||||||
assert_warn(/The keyword argument is passed as the last hash parameter.* for `m'/m) do
|
assert_warn(/The keyword argument is passed as the last hash parameter.* for `m'/m) do
|
||||||
assert_equal([h3, kw], c.m(**h3))
|
assert_equal([h3, kw], c.m(**h3))
|
||||||
end
|
end
|
||||||
|
redef[]
|
||||||
assert_warn(/The keyword argument is passed as the last hash parameter.* for `m'/m) do
|
assert_warn(/The keyword argument is passed as the last hash parameter.* for `m'/m) do
|
||||||
assert_equal([h3, kw], c.m(a: 1, **h2))
|
assert_equal([h3, kw], c.m(a: 1, **h2))
|
||||||
end
|
end
|
||||||
@ -2092,13 +2128,19 @@ class TestKeywordArguments < Test::Unit::TestCase
|
|||||||
assert_raise(ArgumentError) { c.m(**h3) }
|
assert_raise(ArgumentError) { c.m(**h3) }
|
||||||
assert_raise(ArgumentError) { c.m(a: 1, **h2) }
|
assert_raise(ArgumentError) { c.m(a: 1, **h2) }
|
||||||
|
|
||||||
c.singleton_class.remove_method(:method_missing)
|
redef = -> do
|
||||||
def c.method_missing(_, args)
|
c.singleton_class.remove_method(:method_missing)
|
||||||
args
|
eval <<-END
|
||||||
|
def c.method_missing(_, args)
|
||||||
|
args
|
||||||
|
end
|
||||||
|
END
|
||||||
end
|
end
|
||||||
|
redef[]
|
||||||
assert_warn(/The keyword argument is passed as the last hash parameter.* for `method_missing'/m) do
|
assert_warn(/The keyword argument is passed as the last hash parameter.* for `method_missing'/m) do
|
||||||
assert_equal(kw, c.m(**{}))
|
assert_equal(kw, c.m(**{}))
|
||||||
end
|
end
|
||||||
|
redef[]
|
||||||
assert_warn(/The keyword argument is passed as the last hash parameter.* for `method_missing'/m) do
|
assert_warn(/The keyword argument is passed as the last hash parameter.* for `method_missing'/m) do
|
||||||
assert_equal(kw, c.m(**kw))
|
assert_equal(kw, c.m(**kw))
|
||||||
end
|
end
|
||||||
@ -2127,28 +2169,39 @@ class TestKeywordArguments < Test::Unit::TestCase
|
|||||||
assert_raise(ArgumentError) { c.m(h3) }
|
assert_raise(ArgumentError) { c.m(h3) }
|
||||||
end
|
end
|
||||||
|
|
||||||
c.singleton_class.remove_method(:method_missing)
|
redef = -> do
|
||||||
def c.method_missing(_, arg, **args)
|
c.singleton_class.remove_method(:method_missing)
|
||||||
[arg, args]
|
eval <<-END
|
||||||
|
def c.method_missing(_, arg, **args)
|
||||||
|
[arg, args]
|
||||||
|
end
|
||||||
|
END
|
||||||
end
|
end
|
||||||
|
redef[]
|
||||||
assert_warn(/The keyword argument is passed as the last hash parameter.* for `method_missing'/m) do
|
assert_warn(/The keyword argument is passed as the last hash parameter.* for `method_missing'/m) do
|
||||||
assert_equal([kw, kw], c.m(**{}))
|
assert_equal([kw, kw], c.m(**{}))
|
||||||
end
|
end
|
||||||
|
redef[]
|
||||||
assert_warn(/The keyword argument is passed as the last hash parameter.* for `method_missing'/m) do
|
assert_warn(/The keyword argument is passed as the last hash parameter.* for `method_missing'/m) do
|
||||||
assert_equal([kw, kw], c.m(**kw))
|
assert_equal([kw, kw], c.m(**kw))
|
||||||
end
|
end
|
||||||
|
redef[]
|
||||||
assert_warn(/The keyword argument is passed as the last hash parameter.* for `method_missing'/m) do
|
assert_warn(/The keyword argument is passed as the last hash parameter.* for `method_missing'/m) do
|
||||||
assert_equal([h, kw], c.m(**h))
|
assert_equal([h, kw], c.m(**h))
|
||||||
end
|
end
|
||||||
|
redef[]
|
||||||
assert_warn(/The keyword argument is passed as the last hash parameter.* for `method_missing'/m) do
|
assert_warn(/The keyword argument is passed as the last hash parameter.* for `method_missing'/m) do
|
||||||
assert_equal([h, kw], c.m(a: 1))
|
assert_equal([h, kw], c.m(a: 1))
|
||||||
end
|
end
|
||||||
|
redef[]
|
||||||
assert_warn(/The keyword argument is passed as the last hash parameter.* for `method_missing'/m) do
|
assert_warn(/The keyword argument is passed as the last hash parameter.* for `method_missing'/m) do
|
||||||
assert_equal([h2, kw], c.m(**h2))
|
assert_equal([h2, kw], c.m(**h2))
|
||||||
end
|
end
|
||||||
|
redef[]
|
||||||
assert_warn(/The keyword argument is passed as the last hash parameter.* for `method_missing'/m) do
|
assert_warn(/The keyword argument is passed as the last hash parameter.* for `method_missing'/m) do
|
||||||
assert_equal([h3, kw], c.m(**h3))
|
assert_equal([h3, kw], c.m(**h3))
|
||||||
end
|
end
|
||||||
|
redef[]
|
||||||
assert_warn(/The keyword argument is passed as the last hash parameter.* for `method_missing'/m) do
|
assert_warn(/The keyword argument is passed as the last hash parameter.* for `method_missing'/m) do
|
||||||
assert_equal([h3, kw], c.m(a: 1, **h2))
|
assert_equal([h3, kw], c.m(a: 1, **h2))
|
||||||
end
|
end
|
||||||
@ -2950,6 +3003,12 @@ class TestKeywordArguments < Test::Unit::TestCase
|
|||||||
assert_equal([1, h1], o.baz(1, h1))
|
assert_equal([1, h1], o.baz(1, h1))
|
||||||
assert_equal([h1], o.baz(h1, **{}))
|
assert_equal([h1], o.baz(h1, **{}))
|
||||||
|
|
||||||
|
c.class_eval do
|
||||||
|
remove_method(:bar)
|
||||||
|
def bar(*args, **kw)
|
||||||
|
[args, kw]
|
||||||
|
end
|
||||||
|
end
|
||||||
assert_warn(/The last argument is used as the keyword parameter.* for `bar'/m) do
|
assert_warn(/The last argument is used as the keyword parameter.* for `bar'/m) do
|
||||||
assert_equal([[1], h1], o.foo(:pass_bar, 1, :a=>1))
|
assert_equal([[1], h1], o.foo(:pass_bar, 1, :a=>1))
|
||||||
end
|
end
|
||||||
@ -4601,13 +4660,19 @@ class TestKeywordArgumentsSymProcRefinements < Test::Unit::TestCase
|
|||||||
assert_raise(ArgumentError) { c.call(**h3, &:m) }
|
assert_raise(ArgumentError) { c.call(**h3, &:m) }
|
||||||
assert_raise(ArgumentError) { c.call(a: 1, **h2, &:m) }
|
assert_raise(ArgumentError) { c.call(a: 1, **h2, &:m) }
|
||||||
|
|
||||||
c.singleton_class.remove_method(:m)
|
redef = -> do
|
||||||
def c.m(args)
|
c.singleton_class.remove_method(:m)
|
||||||
args
|
eval <<-END
|
||||||
|
def c.m(args)
|
||||||
|
args
|
||||||
|
end
|
||||||
|
END
|
||||||
end
|
end
|
||||||
|
redef[]
|
||||||
assert_warn(/The keyword argument is passed as the last hash parameter.* for `m'/m) do
|
assert_warn(/The keyword argument is passed as the last hash parameter.* for `m'/m) do
|
||||||
assert_equal(kw, c.call(**{}, &:m))
|
assert_equal(kw, c.call(**{}, &:m))
|
||||||
end
|
end
|
||||||
|
redef[]
|
||||||
assert_warn(/The keyword argument is passed as the last hash parameter.* for `m'/m) do
|
assert_warn(/The keyword argument is passed as the last hash parameter.* for `m'/m) do
|
||||||
assert_equal(kw, c.call(**kw, &:m))
|
assert_equal(kw, c.call(**kw, &:m))
|
||||||
end
|
end
|
||||||
@ -4636,28 +4701,39 @@ class TestKeywordArgumentsSymProcRefinements < Test::Unit::TestCase
|
|||||||
assert_raise(ArgumentError) { c.call(h3, &:m) }
|
assert_raise(ArgumentError) { c.call(h3, &:m) }
|
||||||
end
|
end
|
||||||
|
|
||||||
c.singleton_class.remove_method(:m)
|
redef = -> do
|
||||||
def c.m(arg, **args)
|
c.singleton_class.remove_method(:m)
|
||||||
[arg, args]
|
eval <<-END
|
||||||
|
def c.m(arg, **args)
|
||||||
|
[arg, args]
|
||||||
|
end
|
||||||
|
END
|
||||||
end
|
end
|
||||||
|
redef[]
|
||||||
assert_warn(/The keyword argument is passed as the last hash parameter.* for `m'/m) do
|
assert_warn(/The keyword argument is passed as the last hash parameter.* for `m'/m) do
|
||||||
assert_equal([kw, kw], c.call(**{}, &:m))
|
assert_equal([kw, kw], c.call(**{}, &:m))
|
||||||
end
|
end
|
||||||
|
redef[]
|
||||||
assert_warn(/The keyword argument is passed as the last hash parameter.* for `m'/m) do
|
assert_warn(/The keyword argument is passed as the last hash parameter.* for `m'/m) do
|
||||||
assert_equal([kw, kw], c.call(**kw, &:m))
|
assert_equal([kw, kw], c.call(**kw, &:m))
|
||||||
end
|
end
|
||||||
|
redef[]
|
||||||
assert_warn(/The keyword argument is passed as the last hash parameter.* for `m'/m) do
|
assert_warn(/The keyword argument is passed as the last hash parameter.* for `m'/m) do
|
||||||
assert_equal([h, kw], c.call(**h, &:m))
|
assert_equal([h, kw], c.call(**h, &:m))
|
||||||
end
|
end
|
||||||
|
redef[]
|
||||||
assert_warn(/The keyword argument is passed as the last hash parameter.* for `m'/m) do
|
assert_warn(/The keyword argument is passed as the last hash parameter.* for `m'/m) do
|
||||||
assert_equal([h, kw], c.call(a: 1, &:m))
|
assert_equal([h, kw], c.call(a: 1, &:m))
|
||||||
end
|
end
|
||||||
|
redef[]
|
||||||
assert_warn(/The keyword argument is passed as the last hash parameter.* for `m'/m) do
|
assert_warn(/The keyword argument is passed as the last hash parameter.* for `m'/m) do
|
||||||
assert_equal([h2, kw], c.call(**h2, &:m))
|
assert_equal([h2, kw], c.call(**h2, &:m))
|
||||||
end
|
end
|
||||||
|
redef[]
|
||||||
assert_warn(/The keyword argument is passed as the last hash parameter.* for `m'/m) do
|
assert_warn(/The keyword argument is passed as the last hash parameter.* for `m'/m) do
|
||||||
assert_equal([h3, kw], c.call(**h3, &:m))
|
assert_equal([h3, kw], c.call(**h3, &:m))
|
||||||
end
|
end
|
||||||
|
redef[]
|
||||||
assert_warn(/The keyword argument is passed as the last hash parameter.* for `m'/m) do
|
assert_warn(/The keyword argument is passed as the last hash parameter.* for `m'/m) do
|
||||||
assert_equal([h3, kw], c.call(a: 1, **h2, &:m))
|
assert_equal([h3, kw], c.call(a: 1, **h2, &:m))
|
||||||
end
|
end
|
||||||
@ -4704,13 +4780,19 @@ class TestKeywordArgumentsSymProcRefinements < Test::Unit::TestCase
|
|||||||
assert_raise(ArgumentError) { c.call(**h3, &:m) }
|
assert_raise(ArgumentError) { c.call(**h3, &:m) }
|
||||||
assert_raise(ArgumentError) { c.call(a: 1, **h2, &:m) }
|
assert_raise(ArgumentError) { c.call(a: 1, **h2, &:m) }
|
||||||
|
|
||||||
c.singleton_class.remove_method(:method_missing)
|
redef = -> do
|
||||||
def c.method_missing(_, args)
|
c.singleton_class.remove_method(:method_missing)
|
||||||
args
|
eval <<-END
|
||||||
|
def c.method_missing(_, args)
|
||||||
|
args
|
||||||
|
end
|
||||||
|
END
|
||||||
end
|
end
|
||||||
|
redef[]
|
||||||
assert_warn(/The keyword argument is passed as the last hash parameter.* for `method_missing'/m) do
|
assert_warn(/The keyword argument is passed as the last hash parameter.* for `method_missing'/m) do
|
||||||
assert_equal(kw, c.call(**{}, &:m))
|
assert_equal(kw, c.call(**{}, &:m))
|
||||||
end
|
end
|
||||||
|
redef[]
|
||||||
assert_warn(/The keyword argument is passed as the last hash parameter.* for `method_missing'/m) do
|
assert_warn(/The keyword argument is passed as the last hash parameter.* for `method_missing'/m) do
|
||||||
assert_equal(kw, c.call(**kw, &:m))
|
assert_equal(kw, c.call(**kw, &:m))
|
||||||
end
|
end
|
||||||
@ -4739,28 +4821,39 @@ class TestKeywordArgumentsSymProcRefinements < Test::Unit::TestCase
|
|||||||
assert_raise(ArgumentError) { c.call(h3, &:m2) }
|
assert_raise(ArgumentError) { c.call(h3, &:m2) }
|
||||||
end
|
end
|
||||||
|
|
||||||
c.singleton_class.remove_method(:method_missing)
|
redef = -> do
|
||||||
def c.method_missing(_, arg, **args)
|
c.singleton_class.remove_method(:method_missing)
|
||||||
[arg, args]
|
eval <<-END
|
||||||
|
def c.method_missing(_, arg, **args)
|
||||||
|
[arg, args]
|
||||||
|
end
|
||||||
|
END
|
||||||
end
|
end
|
||||||
|
redef[]
|
||||||
assert_warn(/The keyword argument is passed as the last hash parameter.* for `method_missing'/m) do
|
assert_warn(/The keyword argument is passed as the last hash parameter.* for `method_missing'/m) do
|
||||||
assert_equal([kw, kw], c.call(**{}, &:m))
|
assert_equal([kw, kw], c.call(**{}, &:m))
|
||||||
end
|
end
|
||||||
|
redef[]
|
||||||
assert_warn(/The keyword argument is passed as the last hash parameter.* for `method_missing'/m) do
|
assert_warn(/The keyword argument is passed as the last hash parameter.* for `method_missing'/m) do
|
||||||
assert_equal([kw, kw], c.call(**kw, &:m))
|
assert_equal([kw, kw], c.call(**kw, &:m))
|
||||||
end
|
end
|
||||||
|
redef[]
|
||||||
assert_warn(/The keyword argument is passed as the last hash parameter.* for `method_missing'/m) do
|
assert_warn(/The keyword argument is passed as the last hash parameter.* for `method_missing'/m) do
|
||||||
assert_equal([h, kw], c.call(**h, &:m))
|
assert_equal([h, kw], c.call(**h, &:m))
|
||||||
end
|
end
|
||||||
|
redef[]
|
||||||
assert_warn(/The keyword argument is passed as the last hash parameter.* for `method_missing'/m) do
|
assert_warn(/The keyword argument is passed as the last hash parameter.* for `method_missing'/m) do
|
||||||
assert_equal([h, kw], c.call(a: 1, &:m))
|
assert_equal([h, kw], c.call(a: 1, &:m))
|
||||||
end
|
end
|
||||||
|
redef[]
|
||||||
assert_warn(/The keyword argument is passed as the last hash parameter.* for `method_missing'/m) do
|
assert_warn(/The keyword argument is passed as the last hash parameter.* for `method_missing'/m) do
|
||||||
assert_equal([h2, kw], c.call(**h2, &:m))
|
assert_equal([h2, kw], c.call(**h2, &:m))
|
||||||
end
|
end
|
||||||
|
redef[]
|
||||||
assert_warn(/The keyword argument is passed as the last hash parameter.* for `method_missing'/m) do
|
assert_warn(/The keyword argument is passed as the last hash parameter.* for `method_missing'/m) do
|
||||||
assert_equal([h3, kw], c.call(**h3, &:m))
|
assert_equal([h3, kw], c.call(**h3, &:m))
|
||||||
end
|
end
|
||||||
|
redef[]
|
||||||
assert_warn(/The keyword argument is passed as the last hash parameter.* for `method_missing'/m) do
|
assert_warn(/The keyword argument is passed as the last hash parameter.* for `method_missing'/m) do
|
||||||
assert_equal([h3, kw], c.call(a: 1, **h2, &:m))
|
assert_equal([h3, kw], c.call(a: 1, **h2, &:m))
|
||||||
end
|
end
|
||||||
@ -4807,13 +4900,19 @@ class TestKeywordArgumentsSymProcRefinements < Test::Unit::TestCase
|
|||||||
assert_raise(ArgumentError) { c.call(**h3, &:m2) }
|
assert_raise(ArgumentError) { c.call(**h3, &:m2) }
|
||||||
assert_raise(ArgumentError) { c.call(a: 1, **h2, &:m2) }
|
assert_raise(ArgumentError) { c.call(a: 1, **h2, &:m2) }
|
||||||
|
|
||||||
c.singleton_class.remove_method(:method_missing)
|
redef = -> do
|
||||||
def c.method_missing(_, args)
|
c.singleton_class.remove_method(:method_missing)
|
||||||
args
|
eval <<-END
|
||||||
|
def c.method_missing(_, args)
|
||||||
|
args
|
||||||
|
end
|
||||||
|
END
|
||||||
end
|
end
|
||||||
|
redef[]
|
||||||
assert_warn(/The keyword argument is passed as the last hash parameter.* for `method_missing'/m) do
|
assert_warn(/The keyword argument is passed as the last hash parameter.* for `method_missing'/m) do
|
||||||
assert_equal(kw, c.call(**{}, &:m2))
|
assert_equal(kw, c.call(**{}, &:m2))
|
||||||
end
|
end
|
||||||
|
redef[]
|
||||||
assert_warn(/The keyword argument is passed as the last hash parameter.* for `method_missing'/m) do
|
assert_warn(/The keyword argument is passed as the last hash parameter.* for `method_missing'/m) do
|
||||||
assert_equal(kw, c.call(**kw, &:m2))
|
assert_equal(kw, c.call(**kw, &:m2))
|
||||||
end
|
end
|
||||||
@ -4842,28 +4941,39 @@ class TestKeywordArgumentsSymProcRefinements < Test::Unit::TestCase
|
|||||||
assert_raise(ArgumentError) { c.call(h3, &:m2) }
|
assert_raise(ArgumentError) { c.call(h3, &:m2) }
|
||||||
end
|
end
|
||||||
|
|
||||||
c.singleton_class.remove_method(:method_missing)
|
redef = -> do
|
||||||
def c.method_missing(_, arg, **args)
|
c.singleton_class.remove_method(:method_missing)
|
||||||
[arg, args]
|
eval <<-END
|
||||||
|
def c.method_missing(_, arg, **args)
|
||||||
|
[arg, args]
|
||||||
|
end
|
||||||
|
END
|
||||||
end
|
end
|
||||||
|
redef[]
|
||||||
assert_warn(/The keyword argument is passed as the last hash parameter.* for `method_missing'/m) do
|
assert_warn(/The keyword argument is passed as the last hash parameter.* for `method_missing'/m) do
|
||||||
assert_equal([kw, kw], c.call(**{}, &:m2))
|
assert_equal([kw, kw], c.call(**{}, &:m2))
|
||||||
end
|
end
|
||||||
|
redef[]
|
||||||
assert_warn(/The keyword argument is passed as the last hash parameter.* for `method_missing'/m) do
|
assert_warn(/The keyword argument is passed as the last hash parameter.* for `method_missing'/m) do
|
||||||
assert_equal([kw, kw], c.call(**kw, &:m2))
|
assert_equal([kw, kw], c.call(**kw, &:m2))
|
||||||
end
|
end
|
||||||
|
redef[]
|
||||||
assert_warn(/The keyword argument is passed as the last hash parameter.* for `method_missing'/m) do
|
assert_warn(/The keyword argument is passed as the last hash parameter.* for `method_missing'/m) do
|
||||||
assert_equal([h, kw], c.call(**h, &:m2))
|
assert_equal([h, kw], c.call(**h, &:m2))
|
||||||
end
|
end
|
||||||
|
redef[]
|
||||||
assert_warn(/The keyword argument is passed as the last hash parameter.* for `method_missing'/m) do
|
assert_warn(/The keyword argument is passed as the last hash parameter.* for `method_missing'/m) do
|
||||||
assert_equal([h, kw], c.call(a: 1, &:m2))
|
assert_equal([h, kw], c.call(a: 1, &:m2))
|
||||||
end
|
end
|
||||||
|
redef[]
|
||||||
assert_warn(/The keyword argument is passed as the last hash parameter.* for `method_missing'/m) do
|
assert_warn(/The keyword argument is passed as the last hash parameter.* for `method_missing'/m) do
|
||||||
assert_equal([h2, kw], c.call(**h2, &:m2))
|
assert_equal([h2, kw], c.call(**h2, &:m2))
|
||||||
end
|
end
|
||||||
|
redef[]
|
||||||
assert_warn(/The keyword argument is passed as the last hash parameter.* for `method_missing'/m) do
|
assert_warn(/The keyword argument is passed as the last hash parameter.* for `method_missing'/m) do
|
||||||
assert_equal([h3, kw], c.call(**h3, &:m2))
|
assert_equal([h3, kw], c.call(**h3, &:m2))
|
||||||
end
|
end
|
||||||
|
redef[]
|
||||||
assert_warn(/The keyword argument is passed as the last hash parameter.* for `method_missing'/m) do
|
assert_warn(/The keyword argument is passed as the last hash parameter.* for `method_missing'/m) do
|
||||||
assert_equal([h3, kw], c.call(a: 1, **h2, &:m2))
|
assert_equal([h3, kw], c.call(a: 1, **h2, &:m2))
|
||||||
end
|
end
|
||||||
|
@ -113,7 +113,8 @@ module TestStruct
|
|||||||
assert_equal @Struct::KeywordInitTrue.new(a: 1, b: 2).values, @Struct::KeywordInitFalse.new(1, 2).values
|
assert_equal @Struct::KeywordInitTrue.new(a: 1, b: 2).values, @Struct::KeywordInitFalse.new(1, 2).values
|
||||||
assert_equal "#{@Struct}::KeywordInitFalse", @Struct::KeywordInitFalse.inspect
|
assert_equal "#{@Struct}::KeywordInitFalse", @Struct::KeywordInitFalse.inspect
|
||||||
assert_equal "#{@Struct}::KeywordInitTrue(keyword_init: true)", @Struct::KeywordInitTrue.inspect
|
assert_equal "#{@Struct}::KeywordInitTrue(keyword_init: true)", @Struct::KeywordInitTrue.inspect
|
||||||
k = Class.new(@Struct::KeywordInitFalse) {def initialize(**) end}
|
# eval is neede to prevent the warning duplication filter
|
||||||
|
k = eval("Class.new(@Struct::KeywordInitFalse) {def initialize(**) end}")
|
||||||
assert_warn(/The last argument is used as the keyword parameter/) {k.new(a: 1, b: 2)}
|
assert_warn(/The last argument is used as the keyword parameter/) {k.new(a: 1, b: 2)}
|
||||||
k = Class.new(@Struct::KeywordInitTrue) {def initialize(**) end}
|
k = Class.new(@Struct::KeywordInitTrue) {def initialize(**) end}
|
||||||
assert_warn('') {k.new(a: 1, b: 2)}
|
assert_warn('') {k.new(a: 1, b: 2)}
|
||||||
|
73
vm_args.c
73
vm_args.c
@ -585,9 +585,56 @@ ignore_keyword_hash_p(VALUE keyword_hash, const rb_iseq_t * const iseq) {
|
|||||||
|
|
||||||
VALUE rb_iseq_location(const rb_iseq_t *iseq);
|
VALUE rb_iseq_location(const rb_iseq_t *iseq);
|
||||||
|
|
||||||
static inline void
|
/* -- Remove In 3.0 -- */
|
||||||
rb_warn_keyword_to_last_hash(struct rb_calling_info *calling, const struct rb_call_info *ci, const rb_iseq_t * const iseq)
|
|
||||||
|
/* This is a map from caller PC to a set of callee methods.
|
||||||
|
* When a warning about keyword argument change is printed,
|
||||||
|
* it keeps the pair of callee and caller.
|
||||||
|
*/
|
||||||
|
static st_table *caller_to_callees = 0;
|
||||||
|
|
||||||
|
static VALUE rb_warn_check(const rb_execution_context_t * const ec, const void *const callee)
|
||||||
{
|
{
|
||||||
|
const rb_control_frame_t * const cfp = rb_vm_get_ruby_level_next_cfp(ec, ec->cfp);
|
||||||
|
|
||||||
|
if (!cfp) return 0;
|
||||||
|
|
||||||
|
const void *const caller = cfp->pc;
|
||||||
|
|
||||||
|
if (!caller_to_callees) {
|
||||||
|
caller_to_callees = st_init_numtable();
|
||||||
|
}
|
||||||
|
|
||||||
|
st_data_t val;
|
||||||
|
if (st_lookup(caller_to_callees, (st_data_t) caller, &val)) {
|
||||||
|
st_table *callees;
|
||||||
|
|
||||||
|
if (val & 1) {
|
||||||
|
val &= ~(st_data_t)1;
|
||||||
|
if (val == (st_data_t) callee) return 1; /* already warned */
|
||||||
|
|
||||||
|
callees = st_init_numtable();
|
||||||
|
st_insert(callees, val, 1);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
callees = (st_table *) val;
|
||||||
|
if (st_is_member(callees, (st_data_t) callee)) return 1; /* already warned */
|
||||||
|
}
|
||||||
|
st_insert(callees, (st_data_t) callee, 1);
|
||||||
|
st_insert(caller_to_callees, (st_data_t) caller, (st_data_t) callees);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
st_insert(caller_to_callees, (st_data_t) caller, ((st_data_t) callee) | 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0; /* not warned yet for the pair of caller and callee */
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
rb_warn_keyword_to_last_hash(rb_execution_context_t * const ec, struct rb_calling_info *calling, const struct rb_call_info *ci, const rb_iseq_t * const iseq)
|
||||||
|
{
|
||||||
|
if (rb_warn_check(ec, iseq)) return;
|
||||||
|
|
||||||
VALUE name, loc;
|
VALUE name, loc;
|
||||||
if (calling->recv == Qundef) {
|
if (calling->recv == Qundef) {
|
||||||
rb_warn("The keyword argument is passed as the last hash parameter");
|
rb_warn("The keyword argument is passed as the last hash parameter");
|
||||||
@ -613,8 +660,10 @@ rb_warn_keyword_to_last_hash(struct rb_calling_info *calling, const struct rb_ca
|
|||||||
}
|
}
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
rb_warn_split_last_hash_to_keyword(struct rb_calling_info *calling, const struct rb_call_info *ci, const rb_iseq_t * const iseq)
|
rb_warn_split_last_hash_to_keyword(rb_execution_context_t * const ec, struct rb_calling_info *calling, const struct rb_call_info *ci, const rb_iseq_t * const iseq)
|
||||||
{
|
{
|
||||||
|
if (rb_warn_check(ec, iseq)) return;
|
||||||
|
|
||||||
VALUE name, loc;
|
VALUE name, loc;
|
||||||
name = rb_id2str(ci->mid);
|
name = rb_id2str(ci->mid);
|
||||||
loc = rb_iseq_location(iseq);
|
loc = rb_iseq_location(iseq);
|
||||||
@ -636,8 +685,10 @@ rb_warn_split_last_hash_to_keyword(struct rb_calling_info *calling, const struct
|
|||||||
}
|
}
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
rb_warn_last_hash_to_keyword(struct rb_calling_info *calling, const struct rb_call_info *ci, const rb_iseq_t * const iseq)
|
rb_warn_last_hash_to_keyword(rb_execution_context_t * const ec, struct rb_calling_info *calling, const struct rb_call_info *ci, const rb_iseq_t * const iseq)
|
||||||
{
|
{
|
||||||
|
if (rb_warn_check(ec, iseq)) return;
|
||||||
|
|
||||||
VALUE name, loc;
|
VALUE name, loc;
|
||||||
name = rb_id2str(ci->mid);
|
name = rb_id2str(ci->mid);
|
||||||
loc = rb_iseq_location(iseq);
|
loc = rb_iseq_location(iseq);
|
||||||
@ -766,7 +817,7 @@ setup_parameters_complex(rb_execution_context_t * const ec, const rb_iseq_t * co
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
rb_warn_keyword_to_last_hash(calling, ci, iseq);
|
rb_warn_keyword_to_last_hash(ec, calling, ci, iseq);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (!remove_empty_keyword_hash && rest_last) {
|
else if (!remove_empty_keyword_hash && rest_last) {
|
||||||
@ -789,7 +840,7 @@ setup_parameters_complex(rb_execution_context_t * const ec, const rb_iseq_t * co
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
rb_warn_keyword_to_last_hash(calling, ci, iseq);
|
rb_warn_keyword_to_last_hash(ec, calling, ci, iseq);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (!remove_empty_keyword_hash) {
|
else if (!remove_empty_keyword_hash) {
|
||||||
@ -856,10 +907,10 @@ setup_parameters_complex(rb_execution_context_t * const ec, const rb_iseq_t * co
|
|||||||
}
|
}
|
||||||
else if (check_only_symbol) {
|
else if (check_only_symbol) {
|
||||||
if (keyword_hash != Qnil) {
|
if (keyword_hash != Qnil) {
|
||||||
rb_warn_split_last_hash_to_keyword(calling, ci, iseq);
|
rb_warn_split_last_hash_to_keyword(ec, calling, ci, iseq);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
rb_warn_keyword_to_last_hash(calling, ci, iseq);
|
rb_warn_keyword_to_last_hash(ec, calling, ci, iseq);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -868,15 +919,15 @@ setup_parameters_complex(rb_execution_context_t * const ec, const rb_iseq_t * co
|
|||||||
* def foo(k:1) p [k]; end
|
* def foo(k:1) p [k]; end
|
||||||
* foo({k:42}) #=> 42
|
* foo({k:42}) #=> 42
|
||||||
*/
|
*/
|
||||||
rb_warn_last_hash_to_keyword(calling, ci, iseq);
|
rb_warn_last_hash_to_keyword(ec, calling, ci, iseq);
|
||||||
given_argc--;
|
given_argc--;
|
||||||
}
|
}
|
||||||
else if (keyword_hash != Qnil) {
|
else if (keyword_hash != Qnil) {
|
||||||
rb_warn_split_last_hash_to_keyword(calling, ci, iseq);
|
rb_warn_split_last_hash_to_keyword(ec, calling, ci, iseq);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (given_argc == min_argc && kw_flag) {
|
else if (given_argc == min_argc && kw_flag) {
|
||||||
rb_warn_keyword_to_last_hash(calling, ci, iseq);
|
rb_warn_keyword_to_last_hash(ec, calling, ci, iseq);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2926,7 +2926,7 @@ vm_call_method_each_type(rb_execution_context_t *ec, rb_control_frame_t *cfp, st
|
|||||||
case VM_METHOD_TYPE_ATTRSET:
|
case VM_METHOD_TYPE_ATTRSET:
|
||||||
CALLER_SETUP_ARG(cfp, calling, ci);
|
CALLER_SETUP_ARG(cfp, calling, ci);
|
||||||
if (calling->argc == 1 && calling->kw_splat && RHASH_EMPTY_P(cfp->sp[-1])) {
|
if (calling->argc == 1 && calling->kw_splat && RHASH_EMPTY_P(cfp->sp[-1])) {
|
||||||
rb_warn_keyword_to_last_hash(calling, ci, NULL);
|
rb_warn_keyword_to_last_hash(ec, calling, ci, NULL);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
CALLER_REMOVE_EMPTY_KW_SPLAT(cfp, calling, ci);
|
CALLER_REMOVE_EMPTY_KW_SPLAT(cfp, calling, ci);
|
||||||
@ -3264,7 +3264,7 @@ vm_callee_setup_block_arg(rb_execution_context_t *ec, struct rb_calling_info *ca
|
|||||||
|
|
||||||
CALLER_SETUP_ARG(cfp, calling, ci);
|
CALLER_SETUP_ARG(cfp, calling, ci);
|
||||||
if (calling->kw_splat && calling->argc == iseq->body->param.lead_num + iseq->body->param.post_num && RHASH_EMPTY_P(cfp->sp[-1])) {
|
if (calling->kw_splat && calling->argc == iseq->body->param.lead_num + iseq->body->param.post_num && RHASH_EMPTY_P(cfp->sp[-1])) {
|
||||||
rb_warn_keyword_to_last_hash(calling, ci, iseq);
|
rb_warn_keyword_to_last_hash(ec, calling, ci, iseq);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
CALLER_REMOVE_EMPTY_KW_SPLAT(cfp, calling, ci);
|
CALLER_REMOVE_EMPTY_KW_SPLAT(cfp, calling, ci);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user