summaryrefslogtreecommitdiff
path: root/test/ruby/test_allocation.rb
diff options
context:
space:
mode:
Diffstat (limited to 'test/ruby/test_allocation.rb')
-rw-r--r--test/ruby/test_allocation.rb440
1 files changed, 310 insertions, 130 deletions
diff --git a/test/ruby/test_allocation.rb b/test/ruby/test_allocation.rb
index fbe0548899..90d7c04f9b 100644
--- a/test/ruby/test_allocation.rb
+++ b/test/ruby/test_allocation.rb
@@ -2,7 +2,22 @@
require 'test/unit'
class TestAllocation < Test::Unit::TestCase
+ def setup
+ # The namespace changes on i686 platform triggers a bug to allocate objects unexpectedly.
+ # For now, skip these tests only on i686
+ pend if RUBY_PLATFORM =~ /^i686/
+ end
+
+ def munge_checks(checks)
+ checks
+ end
+
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?
+
+ checks = munge_checks(checks)
+
assert_separately([], <<~RUBY)
$allocations = [0, 0]
$counts = {}
@@ -51,9 +66,7 @@ class TestAllocation < Test::Unit::TestCase
#{checks}
- unless failures.empty?
- assert_equal(true, false, failures.join("\n"))
- end
+ assert_empty(failures)
RUBY
end
@@ -85,13 +98,14 @@ class TestAllocation < Test::Unit::TestCase
def block
''
end
+ alias only_block block
def test_no_parameters
- only_block = block.empty? ? block : block[2..]
check_allocations(<<~RUBY)
def self.none(#{only_block}); end
check_allocations(0, 0, "none(#{only_block})")
+ check_allocations(0, 0, "none(*nil#{block})")
check_allocations(0, 0, "none(*empty_array#{block})")
check_allocations(0, 0, "none(**empty_hash#{block})")
check_allocations(0, 0, "none(*empty_array, **empty_hash#{block})")
@@ -123,8 +137,7 @@ class TestAllocation < Test::Unit::TestCase
check_allocations(0, 0, "required(*r2k_empty_array1#{block})")
check_allocations(0, 1, "required(*r2k_array#{block})")
- # Currently allocates 1 array unnecessarily due to splatarray true
- check_allocations(1, 1, "required(*empty_array, **hash1, **empty_hash#{block})")
+ check_allocations(0, 1, "required(*empty_array, **hash1, **empty_hash#{block})")
RUBY
end
@@ -148,8 +161,10 @@ class TestAllocation < Test::Unit::TestCase
check_allocations(0, 0, "optional(*r2k_empty_array1#{block})")
check_allocations(0, 1, "optional(*r2k_array#{block})")
- # Currently allocates 1 array unnecessarily due to splatarray true
- check_allocations(1, 1, "optional(*empty_array, **hash1, **empty_hash#{block})")
+ check_allocations(0, 0, "optional(*empty_array#{block})")
+ check_allocations(0, 0, "optional(*nil#{block})")
+ check_allocations(0, 0, "optional(#{only_block})")
+ check_allocations(0, 1, "optional(*empty_array, **hash1, **empty_hash#{block})")
RUBY
end
@@ -172,12 +187,11 @@ class TestAllocation < Test::Unit::TestCase
check_allocations(1, 0, "splat(1, *array1, **empty_hash#{block})")
check_allocations(1, 0, "splat(1, *array1, *empty_array, **empty_hash#{block})")
- check_allocations(1, 0, "splat(*array1#{block})")
+ check_allocations(1, 0, "splat(*nil#{block})")
+ check_allocations(1, 0, "splat(#{only_block})")
check_allocations(1, 1, "splat(**hash1#{block})")
- check_allocations(1, 0, "splat(*array1, *empty_array#{block})")
check_allocations(1, 1, "splat(**hash1, **empty_hash#{block})")
- check_allocations(1, 0, "splat(*array1, *empty_array, **empty_hash#{block})")
check_allocations(1, 1, "splat(*empty_array, **hash1, **empty_hash#{block})")
check_allocations(1, 0, "splat(*r2k_empty_array#{block})")
@@ -192,6 +206,7 @@ class TestAllocation < Test::Unit::TestCase
def self.req_splat(x, *y#{block}); end
check_allocations(1, 0, "req_splat(1#{block})")
+ check_allocations(1, 0, "req_splat(1, *nil#{block})")
check_allocations(1, 0, "req_splat(1, *empty_array#{block})")
check_allocations(1, 0, "req_splat(1, **empty_hash#{block})")
check_allocations(1, 0, "req_splat(1, *empty_array, **empty_hash#{block})")
@@ -206,12 +221,9 @@ class TestAllocation < Test::Unit::TestCase
check_allocations(1, 0, "req_splat(1, *array1, **empty_hash#{block})")
check_allocations(1, 0, "req_splat(1, *array1, *empty_array, **empty_hash#{block})")
- check_allocations(1, 0, "req_splat(*array1#{block})")
check_allocations(1, 1, "req_splat(**hash1#{block})")
- check_allocations(1, 0, "req_splat(*array1, *empty_array#{block})")
check_allocations(1, 1, "req_splat(**hash1, **empty_hash#{block})")
- check_allocations(1, 0, "req_splat(*array1, *empty_array, **empty_hash#{block})")
check_allocations(1, 1, "req_splat(*empty_array, **hash1, **empty_hash#{block})")
check_allocations(1, 0, "req_splat(*r2k_empty_array1#{block})")
@@ -225,6 +237,7 @@ class TestAllocation < Test::Unit::TestCase
def self.splat_post(*x, y#{block}); end
check_allocations(1, 0, "splat_post(1#{block})")
+ check_allocations(1, 0, "splat_post(1, *nil#{block})")
check_allocations(1, 0, "splat_post(1, *empty_array#{block})")
check_allocations(1, 0, "splat_post(1, **empty_hash#{block})")
check_allocations(1, 0, "splat_post(1, *empty_array, **empty_hash#{block})")
@@ -239,12 +252,9 @@ class TestAllocation < Test::Unit::TestCase
check_allocations(1, 0, "splat_post(1, *array1, **empty_hash#{block})")
check_allocations(1, 0, "splat_post(1, *array1, *empty_array, **empty_hash#{block})")
- check_allocations(1, 0, "splat_post(*array1#{block})")
check_allocations(1, 1, "splat_post(**hash1#{block})")
- check_allocations(1, 0, "splat_post(*array1, *empty_array#{block})")
check_allocations(1, 1, "splat_post(**hash1, **empty_hash#{block})")
- check_allocations(1, 0, "splat_post(*array1, *empty_array, **empty_hash#{block})")
check_allocations(1, 1, "splat_post(*empty_array, **hash1, **empty_hash#{block})")
check_allocations(1, 0, "splat_post(*r2k_empty_array1#{block})")
@@ -269,20 +279,15 @@ class TestAllocation < Test::Unit::TestCase
check_allocations(0, 1, "keyword(**hash1, **empty_hash#{block})")
check_allocations(0, 1, "keyword(**empty_hash, **hash1#{block})")
+ check_allocations(0, 0, "keyword(*nil#{block})")
check_allocations(0, 0, "keyword(*empty_array#{block})")
- check_allocations(0, 1, "keyword(**hash1, **empty_hash#{block})")
- check_allocations(1, 0, "keyword(*empty_array, *empty_array, **empty_hash#{block})")
-
- check_allocations(0, 0, "keyword(*empty_array#{block})")
- check_allocations(0, 1, "keyword(**hash1, **empty_hash#{block})")
check_allocations(1, 0, "keyword(*empty_array, *empty_array, **empty_hash#{block})")
- check_allocations(1, 0, "keyword(*r2k_empty_array#{block})")
- check_allocations(1, 1, "keyword(*r2k_array#{block})")
+ check_allocations(0, 0, "keyword(*r2k_empty_array#{block})")
+ check_allocations(0, 0, "keyword(*r2k_array#{block})")
- # Currently allocates 1 array unnecessarily due to splatarray true
- check_allocations(1, 1, "keyword(*empty_array, a: 2, **empty_hash#{block})")
- check_allocations(1, 1, "keyword(*empty_array, **hash1, **empty_hash#{block})")
+ check_allocations(0, 1, "keyword(*empty_array, a: 2, **empty_hash#{block})")
+ check_allocations(0, 1, "keyword(*empty_array, **hash1, **empty_hash#{block})")
RUBY
end
@@ -302,20 +307,15 @@ class TestAllocation < Test::Unit::TestCase
check_allocations(0, 1, "keyword_splat(**hash1, **empty_hash#{block})")
check_allocations(0, 1, "keyword_splat(**empty_hash, **hash1#{block})")
+ check_allocations(0, 1, "keyword_splat(*nil#{block})")
check_allocations(0, 1, "keyword_splat(*empty_array#{block})")
- check_allocations(0, 1, "keyword_splat(**hash1, **empty_hash#{block})")
- check_allocations(1, 1, "keyword_splat(*empty_array, *empty_array, **empty_hash#{block})")
-
- check_allocations(0, 1, "keyword_splat(*empty_array#{block})")
- check_allocations(0, 1, "keyword_splat(**hash1, **empty_hash#{block})")
check_allocations(1, 1, "keyword_splat(*empty_array, *empty_array, **empty_hash#{block})")
- check_allocations(1, 1, "keyword_splat(*r2k_empty_array#{block})")
- check_allocations(1, 1, "keyword_splat(*r2k_array#{block})")
+ check_allocations(0, 1, "keyword_splat(*r2k_empty_array#{block})")
+ check_allocations(0, 1, "keyword_splat(*r2k_array#{block})")
- # Currently allocates 1 array unnecessarily due to splatarray true
- check_allocations(1, 1, "keyword_splat(*empty_array, a: 2, **empty_hash#{block})")
- check_allocations(1, 1, "keyword_splat(*empty_array, **hash1, **empty_hash#{block})")
+ check_allocations(0, 1, "keyword_splat(*empty_array, a: 2, **empty_hash#{block})")
+ check_allocations(0, 1, "keyword_splat(*empty_array, **hash1, **empty_hash#{block})")
RUBY
end
@@ -335,20 +335,15 @@ class TestAllocation < Test::Unit::TestCase
check_allocations(0, 1, "keyword_and_keyword_splat(**hash1, **empty_hash#{block})")
check_allocations(0, 1, "keyword_and_keyword_splat(**empty_hash, **hash1#{block})")
+ check_allocations(0, 1, "keyword_and_keyword_splat(*nil#{block})")
check_allocations(0, 1, "keyword_and_keyword_splat(*empty_array#{block})")
- check_allocations(0, 1, "keyword_and_keyword_splat(**hash1, **empty_hash#{block})")
- check_allocations(1, 1, "keyword_and_keyword_splat(*empty_array, *empty_array, **empty_hash#{block})")
-
- check_allocations(0, 1, "keyword_and_keyword_splat(*empty_array#{block})")
- check_allocations(0, 1, "keyword_and_keyword_splat(**hash1, **empty_hash#{block})")
check_allocations(1, 1, "keyword_and_keyword_splat(*empty_array, *empty_array, **empty_hash#{block})")
- check_allocations(1, 1, "keyword_and_keyword_splat(*r2k_empty_array#{block})")
- check_allocations(1, 1, "keyword_and_keyword_splat(*r2k_array#{block})")
+ check_allocations(0, 1, "keyword_and_keyword_splat(*r2k_empty_array#{block})")
+ check_allocations(0, 1, "keyword_and_keyword_splat(*r2k_array#{block})")
- # Currently allocates 1 array unnecessarily due to splatarray true
- check_allocations(1, 1, "keyword_and_keyword_splat(*empty_array, a: 2, **empty_hash#{block})")
- check_allocations(1, 1, "keyword_and_keyword_splat(*empty_array, **hash1, **empty_hash#{block})")
+ check_allocations(0, 1, "keyword_and_keyword_splat(*empty_array, a: 2, **empty_hash#{block})")
+ check_allocations(0, 1, "keyword_and_keyword_splat(*empty_array, **hash1, **empty_hash#{block})")
RUBY
end
@@ -368,8 +363,8 @@ class TestAllocation < Test::Unit::TestCase
check_allocations(0, 1, "required_and_keyword(1, **hash1, **empty_hash#{block})")
check_allocations(0, 1, "required_and_keyword(1, **empty_hash, **hash1#{block})")
+ check_allocations(0, 0, "required_and_keyword(1, *nil#{block})")
check_allocations(0, 0, "required_and_keyword(1, *empty_array#{block})")
- check_allocations(0, 1, "required_and_keyword(1, **hash1, **empty_hash#{block})")
check_allocations(1, 0, "required_and_keyword(1, *empty_array, *empty_array, **empty_hash#{block})")
check_allocations(0, 0, "required_and_keyword(*array1, a: 2#{block})")
@@ -385,15 +380,14 @@ class TestAllocation < Test::Unit::TestCase
check_allocations(1, 1, "required_and_keyword(*array1, *empty_array, a: 2, **empty_hash#{block})")
check_allocations(1, 1, "required_and_keyword(*array1, *empty_array, **hash1, **empty_hash#{block})")
- check_allocations(1, 0, "required_and_keyword(*r2k_empty_array1#{block})")
- check_allocations(1, 1, "required_and_keyword(*r2k_array1#{block})")
+ check_allocations(0, 0, "required_and_keyword(*r2k_empty_array1#{block})")
+ check_allocations(0, 0, "required_and_keyword(*r2k_array1#{block})")
- # Currently allocates 1 array unnecessarily due to splatarray true
- check_allocations(1, 1, "required_and_keyword(1, *empty_array, a: 2, **empty_hash#{block})")
- check_allocations(1, 1, "required_and_keyword(1, *empty_array, **hash1, **empty_hash#{block})")
- check_allocations(1, 1, "required_and_keyword(*array1, **empty_hash, a: 2#{block})")
- check_allocations(1, 1, "required_and_keyword(*array1, **hash1, **empty_hash#{block})")
- check_allocations(1, 0, "required_and_keyword(*array1, **nil#{block})")
+ check_allocations(0, 1, "required_and_keyword(1, *empty_array, a: 2, **empty_hash#{block})")
+ check_allocations(0, 1, "required_and_keyword(1, *empty_array, **hash1, **empty_hash#{block})")
+ check_allocations(0, 1, "required_and_keyword(*array1, **empty_hash, a: 2#{block})")
+ check_allocations(0, 1, "required_and_keyword(*array1, **hash1, **empty_hash#{block})")
+ check_allocations(0, 0, "required_and_keyword(*array1, **nil#{block})")
RUBY
end
@@ -413,8 +407,8 @@ class TestAllocation < Test::Unit::TestCase
check_allocations(1, 1, "splat_and_keyword(1, **hash1, **empty_hash#{block})")
check_allocations(1, 1, "splat_and_keyword(1, **empty_hash, **hash1#{block})")
+ check_allocations(1, 0, "splat_and_keyword(1, *nil#{block})")
check_allocations(1, 0, "splat_and_keyword(1, *empty_array#{block})")
- check_allocations(1, 1, "splat_and_keyword(1, **hash1, **empty_hash#{block})")
check_allocations(1, 0, "splat_and_keyword(1, *empty_array, *empty_array, **empty_hash#{block})")
check_allocations(1, 0, "splat_and_keyword(*array1, a: 2#{block})")
@@ -437,9 +431,9 @@ class TestAllocation < Test::Unit::TestCase
check_allocations(1, 0, "splat_and_keyword(*array1, **nil#{block})")
check_allocations(1, 0, "splat_and_keyword(*r2k_empty_array#{block})")
- check_allocations(1, 1, "splat_and_keyword(*r2k_array#{block})")
+ check_allocations(1, 0, "splat_and_keyword(*r2k_array#{block})")
check_allocations(1, 0, "splat_and_keyword(*r2k_empty_array1#{block})")
- check_allocations(1, 1, "splat_and_keyword(*r2k_array1#{block})")
+ check_allocations(1, 0, "splat_and_keyword(*r2k_array1#{block})")
RUBY
end
@@ -459,8 +453,8 @@ class TestAllocation < Test::Unit::TestCase
check_allocations(0, 1, "required_and_keyword_splat(1, **hash1, **empty_hash#{block})")
check_allocations(0, 1, "required_and_keyword_splat(1, **empty_hash, **hash1#{block})")
+ check_allocations(0, 1, "required_and_keyword_splat(1, *nil#{block})")
check_allocations(0, 1, "required_and_keyword_splat(1, *empty_array#{block})")
- check_allocations(0, 1, "required_and_keyword_splat(1, **hash1, **empty_hash#{block})")
check_allocations(1, 1, "required_and_keyword_splat(1, *empty_array, *empty_array, **empty_hash#{block})")
check_allocations(0, 1, "required_and_keyword_splat(*array1, a: 2#{block})")
@@ -476,15 +470,14 @@ class TestAllocation < Test::Unit::TestCase
check_allocations(1, 1, "required_and_keyword_splat(*array1, *empty_array, a: 2, **empty_hash#{block})")
check_allocations(1, 1, "required_and_keyword_splat(*array1, *empty_array, **hash1, **empty_hash#{block})")
- check_allocations(1, 1, "required_and_keyword_splat(*r2k_empty_array1#{block})")
- check_allocations(1, 1, "required_and_keyword_splat(*r2k_array1#{block})")
+ check_allocations(0, 1, "required_and_keyword_splat(*r2k_empty_array1#{block})")
+ check_allocations(0, 1, "required_and_keyword_splat(*r2k_array1#{block})")
- # Currently allocates 1 array unnecessarily due to splatarray true
- check_allocations(1, 1, "required_and_keyword_splat(1, *empty_array, a: 2, **empty_hash#{block})")
- check_allocations(1, 1, "required_and_keyword_splat(1, *empty_array, **hash1, **empty_hash#{block})")
- check_allocations(1, 1, "required_and_keyword_splat(*array1, **empty_hash, a: 2#{block})")
- check_allocations(1, 1, "required_and_keyword_splat(*array1, **hash1, **empty_hash#{block})")
- check_allocations(1, 1, "required_and_keyword_splat(*array1, **nil#{block})")
+ check_allocations(0, 1, "required_and_keyword_splat(1, *empty_array, a: 2, **empty_hash#{block})")
+ check_allocations(0, 1, "required_and_keyword_splat(1, *empty_array, **hash1, **empty_hash#{block})")
+ check_allocations(0, 1, "required_and_keyword_splat(*array1, **empty_hash, a: 2#{block})")
+ check_allocations(0, 1, "required_and_keyword_splat(*array1, **hash1, **empty_hash#{block})")
+ check_allocations(0, 1, "required_and_keyword_splat(*array1, **nil#{block})")
RUBY
end
@@ -504,8 +497,8 @@ class TestAllocation < Test::Unit::TestCase
check_allocations(1, 1, "splat_and_keyword_splat(1, **hash1, **empty_hash#{block})")
check_allocations(1, 1, "splat_and_keyword_splat(1, **empty_hash, **hash1#{block})")
+ check_allocations(1, 1, "splat_and_keyword_splat(1, *nil#{block})")
check_allocations(1, 1, "splat_and_keyword_splat(1, *empty_array#{block})")
- check_allocations(1, 1, "splat_and_keyword_splat(1, **hash1, **empty_hash#{block})")
check_allocations(1, 1, "splat_and_keyword_splat(1, *empty_array, *empty_array, **empty_hash#{block})")
check_allocations(1, 1, "splat_and_keyword_splat(*array1, a: 2#{block})")
@@ -534,7 +527,61 @@ class TestAllocation < Test::Unit::TestCase
RUBY
end
+ def test_anonymous_splat_parameter
+ only_block = block.empty? ? block : block[2..]
+ check_allocations(<<~RUBY)
+ def self.anon_splat(*#{block}); end
+
+ check_allocations(1, 1, "anon_splat(1, a: 2#{block})")
+ check_allocations(1, 1, "anon_splat(1, *empty_array, a: 2#{block})")
+ check_allocations(1, 1, "anon_splat(1, a:2, **empty_hash#{block})")
+ check_allocations(1, 1, "anon_splat(1, **empty_hash, a: 2#{block})")
+
+ check_allocations(1, 0, "anon_splat(1, **nil#{block})")
+ check_allocations(1, 0, "anon_splat(1, **empty_hash#{block})")
+ check_allocations(1, 1, "anon_splat(1, **hash1#{block})")
+ check_allocations(1, 1, "anon_splat(1, *empty_array, **hash1#{block})")
+ check_allocations(1, 1, "anon_splat(1, **hash1, **empty_hash#{block})")
+ check_allocations(1, 1, "anon_splat(1, **empty_hash, **hash1#{block})")
+
+ check_allocations(1, 0, "anon_splat(1, *empty_array#{block})")
+ check_allocations(1, 0, "anon_splat(1, *empty_array, *empty_array, **empty_hash#{block})")
+
+ check_allocations(1, 1, "anon_splat(*array1, a: 2#{block})")
+
+ check_allocations(0, 0, "anon_splat(*nil, **nill#{block})")
+ check_allocations(0, 0, "anon_splat(*array1, **nill#{block})")
+ check_allocations(0, 0, "anon_splat(*array1, **empty_hash#{block})")
+ check_allocations(1, 1, "anon_splat(*array1, **hash1#{block})")
+ check_allocations(1, 1, "anon_splat(*array1, *empty_array, **hash1#{block})")
+
+ check_allocations(1, 0, "anon_splat(*array1, *empty_array#{block})")
+ check_allocations(1, 0, "anon_splat(*array1, *empty_array, **empty_hash#{block})")
+
+ check_allocations(1, 1, "anon_splat(*array1, *empty_array, a: 2, **empty_hash#{block})")
+ check_allocations(1, 1, "anon_splat(*array1, *empty_array, **hash1, **empty_hash#{block})")
+
+ check_allocations(0, 0, "anon_splat(#{only_block})")
+ check_allocations(1, 1, "anon_splat(a: 2#{block})")
+ check_allocations(0, 0, "anon_splat(**empty_hash#{block})")
+
+ check_allocations(1, 1, "anon_splat(1, *empty_array, a: 2, **empty_hash#{block})")
+ check_allocations(1, 1, "anon_splat(1, *empty_array, **hash1, **empty_hash#{block})")
+ check_allocations(1, 1, "anon_splat(*array1, **empty_hash, a: 2#{block})")
+ check_allocations(1, 1, "anon_splat(*array1, **hash1, **empty_hash#{block})")
+
+ unless defined?(RubyVM::YJIT.enabled?) && RubyVM::YJIT.enabled?
+ check_allocations(0, 0, "anon_splat(*array1, **nil#{block})")
+ check_allocations(1, 0, "anon_splat(*r2k_empty_array#{block})")
+ check_allocations(1, 1, "anon_splat(*r2k_array#{block})")
+ check_allocations(1, 0, "anon_splat(*r2k_empty_array1#{block})")
+ check_allocations(1, 1, "anon_splat(*r2k_array1#{block})")
+ end
+ RUBY
+ end
+
def test_anonymous_splat_and_anonymous_keyword_splat_parameters
+ only_block = block.empty? ? block : block[2..]
check_allocations(<<~RUBY)
def self.anon_splat_and_anon_keyword_splat(*, **#{block}); end
@@ -551,11 +598,11 @@ class TestAllocation < Test::Unit::TestCase
check_allocations(1, 1, "anon_splat_and_anon_keyword_splat(1, **empty_hash, **hash1#{block})")
check_allocations(1, 0, "anon_splat_and_anon_keyword_splat(1, *empty_array#{block})")
- check_allocations(1, 1, "anon_splat_and_anon_keyword_splat(1, **hash1, **empty_hash#{block})")
check_allocations(1, 0, "anon_splat_and_anon_keyword_splat(1, *empty_array, *empty_array, **empty_hash#{block})")
check_allocations(0, 0, "anon_splat_and_anon_keyword_splat(*array1, a: 2#{block})")
+ check_allocations(0, 0, "anon_splat_and_anon_keyword_splat(*nil, **nill#{block})")
check_allocations(0, 0, "anon_splat_and_anon_keyword_splat(*array1, **nill#{block})")
check_allocations(0, 0, "anon_splat_and_anon_keyword_splat(*array1, **empty_hash#{block})")
check_allocations(0, 0, "anon_splat_and_anon_keyword_splat(*array1, **hash1#{block})")
@@ -567,11 +614,15 @@ class TestAllocation < Test::Unit::TestCase
check_allocations(1, 1, "anon_splat_and_anon_keyword_splat(*array1, *empty_array, a: 2, **empty_hash#{block})")
check_allocations(1, 1, "anon_splat_and_anon_keyword_splat(*array1, *empty_array, **hash1, **empty_hash#{block})")
+ check_allocations(0, 0, "anon_splat_and_anon_keyword_splat(#{only_block})")
+ check_allocations(0, 1, "anon_splat_and_anon_keyword_splat(a: 2#{block})")
+ check_allocations(0, 0, "anon_splat_and_anon_keyword_splat(**empty_hash#{block})")
+
check_allocations(1, 1, "anon_splat_and_anon_keyword_splat(1, *empty_array, a: 2, **empty_hash#{block})")
check_allocations(1, 1, "anon_splat_and_anon_keyword_splat(1, *empty_array, **hash1, **empty_hash#{block})")
- check_allocations(1, 1, "anon_splat_and_anon_keyword_splat(*array1, **empty_hash, a: 2#{block})")
- check_allocations(1, 1, "anon_splat_and_anon_keyword_splat(*array1, **hash1, **empty_hash#{block})")
- check_allocations(1, 0, "anon_splat_and_anon_keyword_splat(*array1, **nil#{block})")
+ check_allocations(0, 1, "anon_splat_and_anon_keyword_splat(*array1, **empty_hash, a: 2#{block})")
+ check_allocations(0, 1, "anon_splat_and_anon_keyword_splat(*array1, **hash1, **empty_hash#{block})")
+ check_allocations(0, 0, "anon_splat_and_anon_keyword_splat(*array1, **nil#{block})")
check_allocations(1, 1, "anon_splat_and_anon_keyword_splat(*r2k_empty_array#{block})")
check_allocations(1, 1, "anon_splat_and_anon_keyword_splat(*r2k_array#{block})")
@@ -581,8 +632,10 @@ class TestAllocation < Test::Unit::TestCase
end
def test_nested_anonymous_splat_and_anonymous_keyword_splat_parameters
+ only_block = block.empty? ? block : block[2..]
check_allocations(<<~RUBY)
- def self.anon_splat_and_anon_keyword_splat(*, **#{block}); t(*, **) end; def self.t(*, **#{block}); end
+ def self.t(*, **#{block}); end
+ def self.anon_splat_and_anon_keyword_splat(*, **#{block}); t(*, **) 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})")
@@ -597,11 +650,11 @@ class TestAllocation < Test::Unit::TestCase
check_allocations(1, 1, "anon_splat_and_anon_keyword_splat(1, **empty_hash, **hash1#{block})")
check_allocations(1, 0, "anon_splat_and_anon_keyword_splat(1, *empty_array#{block})")
- check_allocations(1, 1, "anon_splat_and_anon_keyword_splat(1, **hash1, **empty_hash#{block})")
check_allocations(1, 0, "anon_splat_and_anon_keyword_splat(1, *empty_array, *empty_array, **empty_hash#{block})")
check_allocations(0, 0, "anon_splat_and_anon_keyword_splat(*array1, a: 2#{block})")
+ check_allocations(0, 0, "anon_splat_and_anon_keyword_splat(*nil, **nill#{block})")
check_allocations(0, 0, "anon_splat_and_anon_keyword_splat(*array1, **nill#{block})")
check_allocations(0, 0, "anon_splat_and_anon_keyword_splat(*array1, **empty_hash#{block})")
check_allocations(0, 0, "anon_splat_and_anon_keyword_splat(*array1, **hash1#{block})")
@@ -613,11 +666,15 @@ class TestAllocation < Test::Unit::TestCase
check_allocations(1, 1, "anon_splat_and_anon_keyword_splat(*array1, *empty_array, a: 2, **empty_hash#{block})")
check_allocations(1, 1, "anon_splat_and_anon_keyword_splat(*array1, *empty_array, **hash1, **empty_hash#{block})")
+ check_allocations(0, 0, "anon_splat_and_anon_keyword_splat(#{only_block})")
+ check_allocations(0, 1, "anon_splat_and_anon_keyword_splat(a: 2#{block})")
+ check_allocations(0, 0, "anon_splat_and_anon_keyword_splat(**empty_hash#{block})")
+
check_allocations(1, 1, "anon_splat_and_anon_keyword_splat(1, *empty_array, a: 2, **empty_hash#{block})")
check_allocations(1, 1, "anon_splat_and_anon_keyword_splat(1, *empty_array, **hash1, **empty_hash#{block})")
- check_allocations(1, 1, "anon_splat_and_anon_keyword_splat(*array1, **empty_hash, a: 2#{block})")
- check_allocations(1, 1, "anon_splat_and_anon_keyword_splat(*array1, **hash1, **empty_hash#{block})")
- check_allocations(1, 0, "anon_splat_and_anon_keyword_splat(*array1, **nil#{block})")
+ check_allocations(0, 1, "anon_splat_and_anon_keyword_splat(*array1, **empty_hash, a: 2#{block})")
+ check_allocations(0, 1, "anon_splat_and_anon_keyword_splat(*array1, **hash1, **empty_hash#{block})")
+ check_allocations(0, 0, "anon_splat_and_anon_keyword_splat(*array1, **nil#{block})")
check_allocations(1, 1, "anon_splat_and_anon_keyword_splat(*r2k_empty_array#{block})")
check_allocations(1, 1, "anon_splat_and_anon_keyword_splat(*r2k_array#{block})")
@@ -630,24 +687,25 @@ class TestAllocation < Test::Unit::TestCase
check_allocations(<<~RUBY)
def self.argument_forwarding(...); end
- check_allocations(1, 1, "argument_forwarding(1, a: 2#{block})")
- check_allocations(1, 0, "argument_forwarding(1, *empty_array, a: 2#{block})")
- check_allocations(1, 1, "argument_forwarding(1, a:2, **empty_hash#{block})")
- check_allocations(1, 1, "argument_forwarding(1, **empty_hash, a: 2#{block})")
+ check_allocations(0, 0, "argument_forwarding(1, a: 2#{block})")
+ check_allocations(0, 0, "argument_forwarding(1, *empty_array, a: 2#{block})")
+ check_allocations(0, 1, "argument_forwarding(1, a:2, **empty_hash#{block})")
+ check_allocations(0, 1, "argument_forwarding(1, **empty_hash, a: 2#{block})")
- check_allocations(1, 0, "argument_forwarding(1, **nil#{block})")
- check_allocations(1, 0, "argument_forwarding(1, **empty_hash#{block})")
- check_allocations(1, 0, "argument_forwarding(1, **hash1#{block})")
- check_allocations(1, 0, "argument_forwarding(1, *empty_array, **hash1#{block})")
- check_allocations(1, 1, "argument_forwarding(1, **hash1, **empty_hash#{block})")
- check_allocations(1, 1, "argument_forwarding(1, **empty_hash, **hash1#{block})")
+ check_allocations(0, 0, "argument_forwarding(1, **nil#{block})")
+ check_allocations(0, 0, "argument_forwarding(1, **empty_hash#{block})")
+ check_allocations(0, 0, "argument_forwarding(1, **hash1#{block})")
+ check_allocations(0, 0, "argument_forwarding(1, *empty_array, **hash1#{block})")
+ check_allocations(0, 1, "argument_forwarding(1, **hash1, **empty_hash#{block})")
+ check_allocations(0, 1, "argument_forwarding(1, **empty_hash, **hash1#{block})")
- check_allocations(1, 0, "argument_forwarding(1, *empty_array#{block})")
- check_allocations(1, 1, "argument_forwarding(1, **hash1, **empty_hash#{block})")
+ check_allocations(0, 0, "argument_forwarding(1, *empty_array#{block})")
check_allocations(1, 0, "argument_forwarding(1, *empty_array, *empty_array, **empty_hash#{block})")
check_allocations(0, 0, "argument_forwarding(*array1, a: 2#{block})")
+ check_allocations(0, 0, "argument_forwarding(**nill#{block})")
+ check_allocations(0, 0, "argument_forwarding(*nil, **nill#{block})")
check_allocations(0, 0, "argument_forwarding(*array1, **nill#{block})")
check_allocations(0, 0, "argument_forwarding(*array1, **empty_hash#{block})")
check_allocations(0, 0, "argument_forwarding(*array1, **hash1#{block})")
@@ -659,41 +717,43 @@ class TestAllocation < Test::Unit::TestCase
check_allocations(1, 1, "argument_forwarding(*array1, *empty_array, a: 2, **empty_hash#{block})")
check_allocations(1, 1, "argument_forwarding(*array1, *empty_array, **hash1, **empty_hash#{block})")
- check_allocations(1, 1, "argument_forwarding(1, *empty_array, a: 2, **empty_hash#{block})")
- check_allocations(1, 1, "argument_forwarding(1, *empty_array, **hash1, **empty_hash#{block})")
- check_allocations(1, 1, "argument_forwarding(*array1, **empty_hash, a: 2#{block})")
- check_allocations(1, 1, "argument_forwarding(*array1, **hash1, **empty_hash#{block})")
- check_allocations(1, 0, "argument_forwarding(*array1, **nil#{block})")
+ check_allocations(0, 1, "argument_forwarding(1, *empty_array, a: 2, **empty_hash#{block})")
+ check_allocations(0, 1, "argument_forwarding(1, *empty_array, **hash1, **empty_hash#{block})")
+ check_allocations(0, 1, "argument_forwarding(*array1, **empty_hash, a: 2#{block})")
+ check_allocations(0, 1, "argument_forwarding(*array1, **hash1, **empty_hash#{block})")
+ check_allocations(0, 0, "argument_forwarding(*array1, **nil#{block})")
- check_allocations(1, 1, "argument_forwarding(*r2k_empty_array#{block})")
- check_allocations(1, 1, "argument_forwarding(*r2k_array#{block})")
- check_allocations(1, 1, "argument_forwarding(*r2k_empty_array1#{block})")
- check_allocations(1, 1, "argument_forwarding(*r2k_array1#{block})")
+ check_allocations(0, 0, "argument_forwarding(*r2k_empty_array#{block})")
+ check_allocations(0, 0, "argument_forwarding(*r2k_array#{block})")
+ check_allocations(0, 0, "argument_forwarding(*r2k_empty_array1#{block})")
+ check_allocations(0, 0, "argument_forwarding(*r2k_array1#{block})")
RUBY
end
def test_nested_argument_forwarding
check_allocations(<<~RUBY)
- def self.argument_forwarding(...); t(...) end; def self.t(...) end
-
- check_allocations(1, 1, "argument_forwarding(1, a: 2#{block})")
- check_allocations(1, 0, "argument_forwarding(1, *empty_array, a: 2#{block})")
- check_allocations(1, 1, "argument_forwarding(1, a:2, **empty_hash#{block})")
- check_allocations(1, 1, "argument_forwarding(1, **empty_hash, a: 2#{block})")
-
- check_allocations(1, 0, "argument_forwarding(1, **nil#{block})")
- check_allocations(1, 0, "argument_forwarding(1, **empty_hash#{block})")
- check_allocations(1, 0, "argument_forwarding(1, **hash1#{block})")
- check_allocations(1, 0, "argument_forwarding(1, *empty_array, **hash1#{block})")
- check_allocations(1, 1, "argument_forwarding(1, **hash1, **empty_hash#{block})")
- check_allocations(1, 1, "argument_forwarding(1, **empty_hash, **hash1#{block})")
-
- check_allocations(1, 0, "argument_forwarding(1, *empty_array#{block})")
- check_allocations(1, 1, "argument_forwarding(1, **hash1, **empty_hash#{block})")
+ def self.t(...) end
+ def self.argument_forwarding(...); t(...) end
+
+ check_allocations(0, 0, "argument_forwarding(1, a: 2#{block})")
+ check_allocations(0, 0, "argument_forwarding(1, *empty_array, a: 2#{block})")
+ check_allocations(0, 1, "argument_forwarding(1, a:2, **empty_hash#{block})")
+ check_allocations(0, 1, "argument_forwarding(1, **empty_hash, a: 2#{block})")
+
+ check_allocations(0, 0, "argument_forwarding(1, **nil#{block})")
+ check_allocations(0, 0, "argument_forwarding(1, **empty_hash#{block})")
+ check_allocations(0, 0, "argument_forwarding(1, **hash1#{block})")
+ check_allocations(0, 0, "argument_forwarding(1, *empty_array, **hash1#{block})")
+ check_allocations(0, 1, "argument_forwarding(1, **hash1, **empty_hash#{block})")
+ check_allocations(0, 1, "argument_forwarding(1, **empty_hash, **hash1#{block})")
+
+ check_allocations(0, 0, "argument_forwarding(1, *empty_array#{block})")
check_allocations(1, 0, "argument_forwarding(1, *empty_array, *empty_array, **empty_hash#{block})")
check_allocations(0, 0, "argument_forwarding(*array1, a: 2#{block})")
+ check_allocations(0, 0, "argument_forwarding(**nill#{block})")
+ check_allocations(0, 0, "argument_forwarding(*nil, **nill#{block})")
check_allocations(0, 0, "argument_forwarding(*array1, **nill#{block})")
check_allocations(0, 0, "argument_forwarding(*array1, **empty_hash#{block})")
check_allocations(0, 0, "argument_forwarding(*array1, **hash1#{block})")
@@ -705,16 +765,16 @@ class TestAllocation < Test::Unit::TestCase
check_allocations(1, 1, "argument_forwarding(*array1, *empty_array, a: 2, **empty_hash#{block})")
check_allocations(1, 1, "argument_forwarding(*array1, *empty_array, **hash1, **empty_hash#{block})")
- check_allocations(1, 1, "argument_forwarding(1, *empty_array, a: 2, **empty_hash#{block})")
- check_allocations(1, 1, "argument_forwarding(1, *empty_array, **hash1, **empty_hash#{block})")
- check_allocations(1, 1, "argument_forwarding(*array1, **empty_hash, a: 2#{block})")
- check_allocations(1, 1, "argument_forwarding(*array1, **hash1, **empty_hash#{block})")
- check_allocations(1, 0, "argument_forwarding(*array1, **nil#{block})")
+ check_allocations(0, 1, "argument_forwarding(1, *empty_array, a: 2, **empty_hash#{block})")
+ check_allocations(0, 1, "argument_forwarding(1, *empty_array, **hash1, **empty_hash#{block})")
+ check_allocations(0, 1, "argument_forwarding(*array1, **empty_hash, a: 2#{block})")
+ check_allocations(0, 1, "argument_forwarding(*array1, **hash1, **empty_hash#{block})")
+ check_allocations(0, 0, "argument_forwarding(*array1, **nil#{block})")
- check_allocations(1, 1, "argument_forwarding(*r2k_empty_array#{block})")
- check_allocations(1, 1, "argument_forwarding(*r2k_array#{block})")
- check_allocations(1, 1, "argument_forwarding(*r2k_empty_array1#{block})")
- check_allocations(1, 1, "argument_forwarding(*r2k_array1#{block})")
+ check_allocations(0, 0, "argument_forwarding(*r2k_empty_array#{block})")
+ check_allocations(0, 0, "argument_forwarding(*r2k_array#{block})")
+ check_allocations(0, 0, "argument_forwarding(*r2k_empty_array1#{block})")
+ check_allocations(0, 0, "argument_forwarding(*r2k_array1#{block})")
RUBY
end
@@ -729,25 +789,26 @@ class TestAllocation < Test::Unit::TestCase
check_allocations(1, 1, "r2k(1, **empty_hash, a: 2#{block})")
check_allocations(1, 0, "r2k(1, **nil#{block})")
- check_allocations(1, 1, "r2k(1, **empty_hash#{block})")
+ check_allocations(1, 0, "r2k(1, **empty_hash#{block})")
check_allocations(1, 1, "r2k(1, **hash1#{block})")
check_allocations(1, 1, "r2k(1, *empty_array, **hash1#{block})")
check_allocations(1, 1, "r2k(1, **hash1, **empty_hash#{block})")
check_allocations(1, 1, "r2k(1, **empty_hash, **hash1#{block})")
check_allocations(1, 0, "r2k(1, *empty_array#{block})")
- check_allocations(1, 1, "r2k(1, **hash1, **empty_hash#{block})")
- check_allocations(1, 1, "r2k(1, *empty_array, *empty_array, **empty_hash#{block})")
+ check_allocations(1, 0, "r2k(1, *empty_array, *empty_array, **empty_hash#{block})")
check_allocations(1, 1, "r2k(*array1, a: 2#{block})")
+ check_allocations(1, 0, "r2k(**nill#{block})")
+ check_allocations(1, 0, "r2k(*nil, **nill#{block})")
check_allocations(1, 0, "r2k(*array1, **nill#{block})")
- check_allocations(1, 1, "r2k(*array1, **empty_hash#{block})")
+ check_allocations(1, 0, "r2k(*array1, **empty_hash#{block})")
check_allocations(1, 1, "r2k(*array1, **hash1#{block})")
check_allocations(1, 1, "r2k(*array1, *empty_array, **hash1#{block})")
check_allocations(1, 0, "r2k(*array1, *empty_array#{block})")
- check_allocations(1, 1, "r2k(*array1, *empty_array, **empty_hash#{block})")
+ check_allocations(1, 0, "r2k(*array1, *empty_array, **empty_hash#{block})")
check_allocations(1, 1, "r2k(*array1, *empty_array, a: 2, **empty_hash#{block})")
check_allocations(1, 1, "r2k(*array1, *empty_array, **hash1, **empty_hash#{block})")
@@ -759,19 +820,138 @@ class TestAllocation < Test::Unit::TestCase
check_allocations(1, 0, "r2k(*array1, **nil#{block})")
check_allocations(1, 0, "r2k(*r2k_empty_array#{block})")
- check_allocations(1, 1, "r2k(*r2k_array#{block})")
unless defined?(RubyVM::YJIT.enabled?) && RubyVM::YJIT.enabled?
# YJIT may or may not allocate depending on arch?
+ check_allocations(1, 1, "r2k(*r2k_array#{block})")
check_allocations(1, 0, "r2k(*r2k_empty_array1#{block})")
check_allocations(1, 1, "r2k(*r2k_array1#{block})")
end
RUBY
end
+ def test_no_array_allocation_with_splat_and_nonstatic_keywords
+ check_allocations(<<~RUBY)
+ def self.keyword(a: nil, b: nil#{block}); end
+ def self.Object; Object end
+
+ check_allocations(0, 1, "keyword(*nil, a: empty_array#{block})") # LVAR
+ check_allocations(0, 1, "keyword(*empty_array, a: empty_array#{block})") # LVAR
+ check_allocations(0, 1, "->{keyword(*empty_array, a: empty_array#{block})}.call") # DVAR
+ check_allocations(0, 1, "$x = empty_array; keyword(*empty_array, a: $x#{block})") # GVAR
+ check_allocations(0, 1, "@x = empty_array; keyword(*empty_array, a: @x#{block})") # IVAR
+ check_allocations(0, 1, "self.class.const_set(:X, empty_array); keyword(*empty_array, a: X#{block})") # CONST
+ check_allocations(0, 1, "keyword(*empty_array, a: Object::X#{block})") # COLON2 - safe
+ check_allocations(1, 1, "keyword(*empty_array, a: Object()::X#{block})") # COLON2 - unsafe
+ check_allocations(0, 1, "keyword(*empty_array, a: ::X#{block})") # COLON3
+ check_allocations(0, 1, "T = self; #{'B = block' unless block.empty?}; class Object; @@x = X; T.keyword(*X, a: @@x#{', &B' unless block.empty?}) end") # CVAR
+ check_allocations(0, 1, "keyword(*empty_array, a: empty_array, b: 1#{block})") # INTEGER
+ check_allocations(0, 1, "keyword(*empty_array, a: empty_array, b: 1.0#{block})") # FLOAT
+ check_allocations(0, 1, "keyword(*empty_array, a: empty_array, b: 1.0r#{block})") # RATIONAL
+ check_allocations(0, 1, "keyword(*empty_array, a: empty_array, b: 1.0i#{block})") # IMAGINARY
+ check_allocations(0, 1, "keyword(*empty_array, a: empty_array, b: 'a'#{block})") # STR
+ check_allocations(0, 1, "keyword(*empty_array, a: empty_array, b: :b#{block})") # SYM
+ check_allocations(0, 1, "keyword(*empty_array, a: empty_array, b: /a/#{block})") # REGX
+ check_allocations(0, 1, "keyword(*empty_array, a: self#{block})") # SELF
+ check_allocations(0, 1, "keyword(*empty_array, a: empty_array, b: nil#{block})") # NIL
+ check_allocations(0, 1, "keyword(*empty_array, a: empty_array, b: true#{block})") # TRUE
+ check_allocations(0, 1, "keyword(*empty_array, a: empty_array, b: false#{block})") # FALSE
+ check_allocations(0, 1, "keyword(*empty_array, a: ->{}#{block})") # LAMBDA
+ check_allocations(0, 1, "keyword(*empty_array, a: $1#{block})") # NTH_REF
+ check_allocations(0, 1, "keyword(*empty_array, a: $`#{block})") # BACK_REF
+
+ # LIST: Only 1 array (literal [:c]), not 2 (one for [:c] and one for *empty_array)
+ check_allocations(1, 1, "keyword(*empty_array, a: empty_array, b: [:c]#{block})")
+ check_allocations(1, 1, "keyword(*empty_array, a: empty_array, b: [:c, $x]#{block})")
+ # LIST unsafe: 2 (one for [Object()] and one for *empty_array)
+ check_allocations(2, 1, "keyword(*empty_array, a: empty_array, b: [Object()]#{block})")
+ check_allocations(2, 1, "keyword(*empty_array, a: empty_array, b: [:c, $x, Object()]#{block})")
+ RUBY
+ end
+
+ class WithBlock < self
+ def block
+ ', &block'
+ end
+ def only_block
+ '&block'
+ end
+ end
+ end
+
+ class ProcCall < MethodCall
+ def munge_checks(checks)
+ return checks if @no_munge
+ sub = rep = nil
+ checks.split("\n").map do |line|
+ case line
+ when "singleton_class.send(:ruby2_keywords, :r2k)"
+ "r2k.ruby2_keywords"
+ when /\Adef self.([a-z0-9_]+)\((.*)\);(.*)end\z/
+ sub = $1 + '('
+ rep = $1 + '.('
+ "#{$1} = #{$1} = proc{ |#{$2}| #{$3} }"
+ when /check_allocations/
+ line.gsub(sub, rep)
+ else
+ line
+ end
+ end.join("\n")
+ end
+
+ # Generic argument forwarding not supported in proc definitions
+ undef_method :test_argument_forwarding
+ undef_method :test_nested_argument_forwarding
+
+ # Proc anonymous arguments cannot be used directly
+ undef_method :test_nested_anonymous_splat_and_anonymous_keyword_splat_parameters
+
+ def test_no_array_allocation_with_splat_and_nonstatic_keywords
+ @no_munge = true
+
+ check_allocations(<<~RUBY)
+ keyword = keyword = proc{ |a: nil, b: nil #{block}| }
+ def self.Object; Object end
+
+ check_allocations(0, 1, "keyword.(*empty_array, a: empty_array#{block})") # LVAR
+ check_allocations(0, 1, "->{keyword.(*empty_array, a: empty_array#{block})}.call") # DVAR
+ check_allocations(0, 1, "$x = empty_array; keyword.(*empty_array, a: $x#{block})") # GVAR
+ check_allocations(0, 1, "@x = empty_array; keyword.(*empty_array, a: @x#{block})") # IVAR
+ check_allocations(0, 1, "self.class.const_set(:X, empty_array); keyword.(*empty_array, a: X#{block})") # CONST
+ check_allocations(0, 1, "keyword.(*empty_array, a: Object::X#{block})") # COLON2 - safe
+ check_allocations(1, 1, "keyword.(*empty_array, a: Object()::X#{block})") # COLON2 - unsafe
+ check_allocations(0, 1, "keyword.(*empty_array, a: ::X#{block})") # COLON3
+ check_allocations(0, 1, "T = keyword; #{'B = block' unless block.empty?}; class Object; @@x = X; T.(*X, a: @@x#{', &B' unless block.empty?}) end") # CVAR
+ check_allocations(0, 1, "keyword.(*empty_array, a: empty_array, b: 1#{block})") # INTEGER
+ check_allocations(0, 1, "keyword.(*empty_array, a: empty_array, b: 1.0#{block})") # FLOAT
+ check_allocations(0, 1, "keyword.(*empty_array, a: empty_array, b: 1.0r#{block})") # RATIONAL
+ check_allocations(0, 1, "keyword.(*empty_array, a: empty_array, b: 1.0i#{block})") # IMAGINARY
+ check_allocations(0, 1, "keyword.(*empty_array, a: empty_array, b: 'a'#{block})") # STR
+ check_allocations(0, 1, "keyword.(*empty_array, a: empty_array, b: :b#{block})") # SYM
+ check_allocations(0, 1, "keyword.(*empty_array, a: empty_array, b: /a/#{block})") # REGX
+ check_allocations(0, 1, "keyword.(*empty_array, a: self#{block})") # SELF
+ check_allocations(0, 1, "keyword.(*empty_array, a: empty_array, b: nil#{block})") # NIL
+ check_allocations(0, 1, "keyword.(*empty_array, a: empty_array, b: true#{block})") # TRUE
+ check_allocations(0, 1, "keyword.(*empty_array, a: empty_array, b: false#{block})") # FALSE
+ check_allocations(0, 1, "keyword.(*empty_array, a: ->{}#{block})") # LAMBDA
+ check_allocations(0, 1, "keyword.(*empty_array, a: $1#{block})") # NTH_REF
+ check_allocations(0, 1, "keyword.(*empty_array, a: $`#{block})") # BACK_REF
+
+ # LIST safe: Only 1 array (literal [:c]), not 2 (one for [:c] and one for *empty_array)
+ check_allocations(1, 1, "keyword.(*empty_array, a: empty_array, b: [:c]#{block})")
+ check_allocations(1, 1, "keyword.(*empty_array, a: empty_array, b: [:c, $x]#{block})")
+ # LIST unsafe: 2 (one for [:c] and one for *empty_array)
+ check_allocations(2, 1, "keyword.(*empty_array, a: empty_array, b: [Object()]#{block})")
+ check_allocations(2, 1, "keyword.(*empty_array, a: empty_array, b: [:c, $x, Object()]#{block})")
+ RUBY
+ end
+
class WithBlock < self
def block
', &block'
end
+ def only_block
+ '&block'
+ end
end
end
end