summaryrefslogtreecommitdiff
path: root/test/ruby/test_syntax.rb
diff options
context:
space:
mode:
Diffstat (limited to 'test/ruby/test_syntax.rb')
-rw-r--r--test/ruby/test_syntax.rb1033
1 files changed, 949 insertions, 84 deletions
diff --git a/test/ruby/test_syntax.rb b/test/ruby/test_syntax.rb
index f9e27be33e..53036cab3b 100644
--- a/test/ruby/test_syntax.rb
+++ b/test/ruby/test_syntax.rb
@@ -46,7 +46,7 @@ class TestSyntax < Test::Unit::TestCase
assert_raise(ArgumentError, enc.name) {load(f.path)}
end
ensure
- f.close! if f
+ f&.close!
end
def test_script_lines
@@ -63,7 +63,82 @@ class TestSyntax < Test::Unit::TestCase
end
end
ensure
- f.close! if f
+ f&.close!
+ end
+
+ def test_script_lines_encoding
+ require 'tmpdir'
+ Dir.mktmpdir do |dir|
+ File.write(File.join(dir, "script_lines.rb"), "SCRIPT_LINES__ = {}\n")
+ assert_in_out_err(%w"-r./script_lines -w -Ke", "puts __ENCODING__.name",
+ %w"EUC-JP", /-K is specified/, chdir: dir)
+ end
+ end
+
+ def test_anonymous_block_forwarding
+ assert_syntax_error("def b; c(&); end", /no anonymous block parameter/)
+ assert_separately([], "#{<<-"begin;"}\n#{<<-'end;'}")
+ begin;
+ def b(&); c(&) end
+ def c(&); yield 1 end
+ a = nil
+ b{|c| a = c}
+ assert_equal(1, a)
+
+ def inner
+ yield
+ end
+
+ def block_only(&)
+ inner(&)
+ end
+ assert_equal(1, block_only{1})
+
+ def pos(arg1, &)
+ inner(&)
+ end
+ assert_equal(2, pos(nil){2})
+
+ def pos_kwrest(arg1, **kw, &)
+ inner(&)
+ end
+ assert_equal(3, pos_kwrest(nil){3})
+
+ def no_kw(arg1, **nil, &)
+ inner(&)
+ end
+ assert_equal(4, no_kw(nil){4})
+
+ def rest_kw(*a, kwarg: 1, &)
+ inner(&)
+ end
+ assert_equal(5, rest_kw{5})
+
+ def kw(kwarg:1, &)
+ inner(&)
+ end
+ assert_equal(6, kw{6})
+
+ def pos_kw_kwrest(arg1, kwarg:1, **kw, &)
+ inner(&)
+ end
+ assert_equal(7, pos_kw_kwrest(nil){7})
+
+ def pos_rkw(arg1, kwarg1:, &)
+ inner(&)
+ end
+ assert_equal(8, pos_rkw(nil, kwarg1: nil){8})
+
+ def all(arg1, arg2, *rest, post1, post2, kw1: 1, kw2: 2, okw1:, okw2:, &)
+ inner(&)
+ end
+ assert_equal(9, all(nil, nil, nil, nil, okw1: nil, okw2: nil){9})
+
+ def all_kwrest(arg1, arg2, *rest, post1, post2, kw1: 1, kw2: 2, okw1:, okw2:, **kw, &)
+ inner(&)
+ end
+ assert_equal(10, all_kwrest(nil, nil, nil, nil, okw1: nil, okw2: nil){10})
+ end;
end
def test_newline_in_block_parameters
@@ -93,6 +168,51 @@ class TestSyntax < Test::Unit::TestCase
assert_valid_syntax("tap (proc do end)", __FILE__, bug9726)
end
+ def test_hash_kwsplat_hash
+ kw = {}
+ h = {a: 1}
+ assert_equal({}, {**{}})
+ assert_equal({}, {**kw})
+ assert_equal(h, {**h})
+ assert_equal(false, {**{}}.frozen?)
+ assert_equal(false, {**kw}.equal?(kw))
+ assert_equal(false, {**h}.equal?(h))
+ end
+
+ def test_array_kwsplat_hash
+ kw = {}
+ h = {a: 1}
+ assert_equal([], [**{}])
+ assert_equal([], [**kw])
+ assert_equal([h], [**h])
+ assert_equal([{}], [{}])
+ assert_equal([kw], [kw])
+ assert_equal([h], [h])
+
+ assert_equal([1], [1, **{}])
+ assert_equal([1], [1, **kw])
+ assert_equal([1, h], [1, **h])
+ assert_equal([1, {}], [1, {}])
+ assert_equal([1, kw], [1, kw])
+ assert_equal([1, h], [1, h])
+
+ assert_equal([], [**kw, **kw])
+ assert_equal([], [**kw, **{}, **kw])
+ assert_equal([1], [1, **kw, **{}, **kw])
+
+ assert_equal([{}], [{}, **kw, **kw])
+ assert_equal([kw], [kw, **kw, **kw])
+ assert_equal([h], [h, **kw, **kw])
+ assert_equal([h, h], [h, **kw, **kw, **h])
+
+ assert_equal([h, {:a=>2}], [h, **{}, **h, a: 2])
+ assert_equal([h, h], [h, **{}, a: 2, **h])
+ assert_equal([h, h], [h, a: 2, **{}, **h])
+ assert_equal([h, h], [h, a: 2, **h, **{}])
+ assert_equal([h, {:a=>2}], [h, **h, a: 2, **{}])
+ assert_equal([h, {:a=>2}], [h, **h, **{}, a: 2])
+ end
+
def test_normal_argument
assert_valid_syntax('def foo(x) end')
assert_syntax_error('def foo(X) end', /constant/)
@@ -148,24 +268,36 @@ class TestSyntax < Test::Unit::TestCase
h = {k3: 31}
assert_raise(ArgumentError) {o.kw(**h)}
h = {"k1"=>11, k2: 12}
- assert_raise(TypeError) {o.kw(**h)}
+ assert_raise(ArgumentError) {o.kw(**h)}
end
def test_keyword_duplicated
bug10315 = '[ruby-core:65625] [Bug #10315]'
a = []
def a.add(x) push(x); x; end
- def a.f(k:) k; end
+ b = a.clone
+ def a.f(k:, **) k; end
+ def b.f(k:) k; end
a.clear
r = nil
- assert_warn(/duplicated/) {r = eval("a.f(k: a.add(1), k: a.add(2))")}
+ assert_warn(/duplicated/) {r = eval("b.f(k: b.add(1), k: b.add(2))")}
assert_equal(2, r)
- assert_equal([1, 2], a, bug10315)
+ assert_equal([1, 2], b, bug10315)
+ b.clear
+ r = nil
+ assert_warn(/duplicated/) {r = eval("a.f(k: a.add(1), j: a.add(2), k: a.add(3), k: a.add(4))")}
+ assert_equal(4, r)
+ assert_equal([1, 2, 3, 4], a)
a.clear
r = nil
- assert_warn(/duplicated/) {r = eval("a.f({k: a.add(1), k: a.add(2)})")}
+ assert_warn(/duplicated/) {r = eval("b.f(**{k: b.add(1), k: b.add(2)})")}
assert_equal(2, r)
- assert_equal([1, 2], a, bug10315)
+ assert_equal([1, 2], b, bug10315)
+ b.clear
+ r = nil
+ assert_warn(/duplicated/) {r = eval("a.f(**{k: a.add(1), j: a.add(2), k: a.add(3), k: a.add(4)})")}
+ assert_equal(4, r)
+ assert_equal([1, 2, 3, 4], a)
end
def test_keyword_empty_splat
@@ -179,36 +311,33 @@ class TestSyntax < Test::Unit::TestCase
bug13756 = '[ruby-core:82113] [Bug #13756]'
assert_valid_syntax("defined? foo(**{})", bug13756)
end;
+ assert_separately([], "#{<<~"begin;"}\n#{<<~'end;'}")
+ begin;
+ bug15271 = '[ruby-core:89648] [Bug #15271]'
+ assert_valid_syntax("a **{}", bug15271)
+ end;
end
def test_keyword_self_reference
- bug9593 = '[ruby-core:61299] [Bug #9593]'
- o = Object.new
- assert_warn(/circular argument reference - var/) do
- o.instance_eval("def foo(var: defined?(var)) var end")
- end
- assert_equal(42, o.foo(var: 42))
- assert_equal("local-variable", o.foo, bug9593)
-
- o = Object.new
- assert_warn(/circular argument reference - var/) do
- o.instance_eval("def foo(var: var) var end")
- end
- assert_nil(o.foo, bug9593)
+ message = /circular argument reference - var/
+ assert_syntax_error("def foo(var: defined?(var)) var end", message)
+ assert_syntax_error("def foo(var: var) var end", message)
+ assert_syntax_error("def foo(var: bar(var)) var end", message)
+ assert_syntax_error("def foo(var: bar {var}) var end", message)
o = Object.new
- assert_warn(/circular argument reference - var/) do
- o.instance_eval("def foo(var: bar(var)) var end")
+ assert_warn("") do
+ o.instance_eval("def foo(var: bar {|var| var}) var end")
end
o = Object.new
- assert_warn(/circular argument reference - var/) do
- o.instance_eval("def foo(var: bar {var}) var end")
+ assert_warn("") do
+ o.instance_eval("def foo(var: bar {| | var}) var end")
end
o = Object.new
assert_warn("") do
- o.instance_eval("def foo(var: bar {|var| var}) var end")
+ o.instance_eval("def foo(var: bar {|| var}) var end")
end
o = Object.new
@@ -225,56 +354,55 @@ class TestSyntax < Test::Unit::TestCase
def test_keyword_invalid_name
bug11663 = '[ruby-core:71356] [Bug #11663]'
- o = o = Object.new
- assert_syntax_error('def o.foo(arg1?:) end', /arg1\?/, bug11663)
- assert_syntax_error('def o.foo(arg1?:, arg2:) end', /arg1\?/, bug11663)
+ assert_syntax_error('def foo(arg1?:) end', /arg1\?/, bug11663)
+ assert_syntax_error('def foo(arg1?:, arg2:) end', /arg1\?/, bug11663)
assert_syntax_error('proc {|arg1?:|}', /arg1\?/, bug11663)
assert_syntax_error('proc {|arg1?:, arg2:|}', /arg1\?/, bug11663)
bug10545 = '[ruby-dev:48742] [Bug #10545]'
- assert_syntax_error('def o.foo(FOO: a) end', /constant/, bug10545)
- assert_syntax_error('def o.foo(@foo: a) end', /instance variable/)
- assert_syntax_error('def o.foo(@@foo: a) end', /class variable/)
+ assert_syntax_error('def foo(FOO: a) end', /constant/, bug10545)
+ assert_syntax_error('def foo(@foo: a) end', /instance variable/)
+ assert_syntax_error('def foo(@@foo: a) end', /class variable/)
end
- def test_optional_self_reference
- bug9593 = '[ruby-core:61299] [Bug #9593]'
- o = Object.new
- assert_warn(/circular argument reference - var/) do
- o.instance_eval("def foo(var = defined?(var)) var end")
- end
- assert_equal(42, o.foo(42))
- assert_equal("local-variable", o.foo, bug9593)
-
- o = Object.new
- assert_warn(/circular argument reference - var/) do
- o.instance_eval("def foo(var = var) var end")
- end
- assert_nil(o.foo, bug9593)
+ def test_keywords_specified_and_not_accepted
+ assert_syntax_error('def foo(a:, **nil) end', /unexpected/)
+ assert_syntax_error('def foo(a:, **nil, &b) end', /unexpected/)
+ assert_syntax_error('def foo(**a, **nil) end', /unexpected/)
+ assert_syntax_error('def foo(**a, **nil, &b) end', /unexpected/)
+ assert_syntax_error('def foo(**nil, **a) end', /unexpected/)
+ assert_syntax_error('def foo(**nil, **a, &b) end', /unexpected/)
- o = Object.new
- assert_warn(/circular argument reference - var/) do
- o.instance_eval("def foo(var = bar(var)) var end")
- end
+ assert_syntax_error('proc do |a:, **nil| end', /unexpected/)
+ assert_syntax_error('proc do |a:, **nil, &b| end', /unexpected/)
+ assert_syntax_error('proc do |**a, **nil| end', /unexpected/)
+ assert_syntax_error('proc do |**a, **nil, &b| end', /unexpected/)
+ assert_syntax_error('proc do |**nil, **a| end', /unexpected/)
+ assert_syntax_error('proc do |**nil, **a, &b| end', /unexpected/)
+ end
- o = Object.new
- assert_warn(/circular argument reference - var/) do
- o.instance_eval("def foo(var = bar {var}) var end")
- end
+ def test_optional_self_reference
+ message = /circular argument reference - var/
+ assert_syntax_error("def foo(var = defined?(var)) var end", message)
+ assert_syntax_error("def foo(var = var) var end", message)
+ assert_syntax_error("def foo(var = bar(var)) var end", message)
+ assert_syntax_error("def foo(var = bar {var}) var end", message)
+ assert_syntax_error("def foo(var = (def bar;end; var)) var end", message)
+ assert_syntax_error("def foo(var = (def self.bar;end; var)) var end", message)
o = Object.new
- assert_warn(/circular argument reference - var/) do
- o.instance_eval("def foo(var = (def bar;end; var)) var end")
+ assert_warn("") do
+ o.instance_eval("def foo(var = bar {|var| var}) var end")
end
o = Object.new
- assert_warn(/circular argument reference - var/) do
- o.instance_eval("def foo(var = (def self.bar;end; var)) var end")
+ assert_warn("") do
+ o.instance_eval("def foo(var = bar {| | var}) var end")
end
o = Object.new
assert_warn("") do
- o.instance_eval("def foo(var = bar {|var| var}) var end")
+ o.instance_eval("def foo(var = bar {|| var}) var end")
end
o = Object.new
@@ -401,21 +529,30 @@ WARN
def test_duplicated_arg
assert_syntax_error("def foo(a, a) end", /duplicated argument name/)
assert_valid_syntax("def foo(_, _) end")
+ (obj = Object.new).instance_eval("def foo(_, x, _) x end")
+ assert_equal(2, obj.foo(1, 2, 3))
end
def test_duplicated_rest
assert_syntax_error("def foo(a, *a) end", /duplicated argument name/)
assert_valid_syntax("def foo(_, *_) end")
+ (obj = Object.new).instance_eval("def foo(_, x, *_) x end")
+ assert_equal(2, obj.foo(1, 2, 3))
end
def test_duplicated_opt
assert_syntax_error("def foo(a, a=1) end", /duplicated argument name/)
assert_valid_syntax("def foo(_, _=1) end")
+ (obj = Object.new).instance_eval("def foo(_, x, _=42) x end")
+ assert_equal(2, obj.foo(1, 2))
end
def test_duplicated_opt_rest
assert_syntax_error("def foo(a=1, *a) end", /duplicated argument name/)
assert_valid_syntax("def foo(_=1, *_) end")
+ (obj = Object.new).instance_eval("def foo(_, x=42, *_) x end")
+ assert_equal(42, obj.foo(1))
+ assert_equal(2, obj.foo(1, 2))
end
def test_duplicated_rest_opt
@@ -424,46 +561,85 @@ WARN
def test_duplicated_rest_post
assert_syntax_error("def foo(*a, a) end", /duplicated argument name/)
+ assert_valid_syntax("def foo(*_, _) end")
+ (obj = Object.new).instance_eval("def foo(*_, x, _) x end")
+ assert_equal(2, obj.foo(1, 2, 3))
+ assert_equal(2, obj.foo(2, 3))
+ (obj = Object.new).instance_eval("def foo(*_, _, x) x end")
+ assert_equal(3, obj.foo(1, 2, 3))
+ assert_equal(3, obj.foo(2, 3))
end
def test_duplicated_opt_post
assert_syntax_error("def foo(a=1, a) end", /duplicated argument name/)
assert_valid_syntax("def foo(_=1, _) end")
+ (obj = Object.new).instance_eval("def foo(_=1, x, _) x end")
+ assert_equal(2, obj.foo(1, 2, 3))
+ assert_equal(2, obj.foo(2, 3))
+ (obj = Object.new).instance_eval("def foo(_=1, _, x) x end")
+ assert_equal(3, obj.foo(1, 2, 3))
+ assert_equal(3, obj.foo(2, 3))
end
def test_duplicated_kw
assert_syntax_error("def foo(a, a: 1) end", /duplicated argument name/)
assert_valid_syntax("def foo(_, _: 1) end")
+ (obj = Object.new).instance_eval("def foo(_, x, _: 1) x end")
+ assert_equal(3, obj.foo(2, 3))
+ assert_equal(3, obj.foo(2, 3, _: 42))
+ (obj = Object.new).instance_eval("def foo(x, _, _: 1) x end")
+ assert_equal(2, obj.foo(2, 3))
+ assert_equal(2, obj.foo(2, 3, _: 42))
end
def test_duplicated_rest_kw
assert_syntax_error("def foo(*a, a: 1) end", /duplicated argument name/)
assert_nothing_raised {def foo(*_, _: 1) end}
+ (obj = Object.new).instance_eval("def foo(*_, x: 42, _: 1) x end")
+ assert_equal(42, obj.foo(42))
+ assert_equal(42, obj.foo(2, _: 0))
+ assert_equal(2, obj.foo(x: 2, _: 0))
end
def test_duplicated_opt_kw
assert_syntax_error("def foo(a=1, a: 1) end", /duplicated argument name/)
assert_valid_syntax("def foo(_=1, _: 1) end")
+ (obj = Object.new).instance_eval("def foo(_=42, x, _: 1) x end")
+ assert_equal(0, obj.foo(0))
+ assert_equal(0, obj.foo(0, _: 3))
end
def test_duplicated_kw_kwrest
assert_syntax_error("def foo(a: 1, **a) end", /duplicated argument name/)
assert_valid_syntax("def foo(_: 1, **_) end")
+ (obj = Object.new).instance_eval("def foo(_: 1, x: 42, **_) x end")
+ assert_equal(42, obj.foo())
+ assert_equal(42, obj.foo(a: 0))
+ assert_equal(42, obj.foo(_: 0, a: 0))
+ assert_equal(1, obj.foo(_: 0, x: 1, a: 0))
end
def test_duplicated_rest_kwrest
assert_syntax_error("def foo(*a, **a) end", /duplicated argument name/)
assert_valid_syntax("def foo(*_, **_) end")
+ (obj = Object.new).instance_eval("def foo(*_, x, **_) x end")
+ assert_equal(1, obj.foo(1))
+ assert_equal(1, obj.foo(1, a: 0))
+ assert_equal(2, obj.foo(1, 2, a: 0))
end
def test_duplicated_opt_kwrest
assert_syntax_error("def foo(a=1, **a) end", /duplicated argument name/)
assert_valid_syntax("def foo(_=1, **_) end")
+ (obj = Object.new).instance_eval("def foo(_=42, x, **_) x end")
+ assert_equal(1, obj.foo(1))
+ assert_equal(1, obj.foo(1, a: 0))
+ assert_equal(1, obj.foo(0, 1, a: 0))
end
def test_duplicated_when
- w = 'warning: duplicated when clause is ignored'
- assert_warning(/3: #{w}.+4: #{w}.+4: #{w}.+5: #{w}.+5: #{w}/m){
+ w = 'warning: duplicated `when\' clause with line 3 is ignored'
+ assert_warning(/3: #{w}.+4: #{w}.+4: #{w}.+5: #{w}.+5: #{w}/m) {
eval %q{
case 1
when 1, 1
@@ -472,7 +648,7 @@ WARN
end
}
}
- assert_warning(/#{w}/){#/3: #{w}.+4: #{w}.+5: #{w}.+5: #{w}/m){
+ assert_warning(/#{w}/) {#/3: #{w}.+4: #{w}.+5: #{w}.+5: #{w}/m){
a = a = 1
eval %q{
case 1
@@ -484,6 +660,17 @@ WARN
}
end
+ def test_duplicated_when_check_option
+ w = /duplicated `when\' clause with line 3 is ignored/
+ assert_in_out_err(%[-wc], "#{<<~"begin;"}\n#{<<~'end;'}", ["Syntax OK"], w)
+ begin;
+ case 1
+ when 1
+ when 1
+ end
+ end;
+ end
+
def test_invalid_break
assert_syntax_error("def m; break; end", /Invalid break/)
assert_syntax_error('/#{break}/', /Invalid break/)
@@ -519,6 +706,11 @@ WARN
def test_do_block_after_lambda
bug11380 = '[ruby-core:70067] [Bug #11380]'
assert_valid_syntax('p -> { :hello }, a: 1 do end', bug11380)
+
+ assert_valid_syntax('->(opt = (foo.[] bar)) {}')
+ assert_valid_syntax('->(opt = (foo.[]= bar)) {}')
+ assert_valid_syntax('->(opt = (foo.[] bar)) do end')
+ assert_valid_syntax('->(opt = (foo.[]= bar)) do end')
end
def test_reserved_method_no_args
@@ -529,7 +721,7 @@ WARN
def test_unassignable
gvar = global_variables
%w[self nil true false __FILE__ __LINE__ __ENCODING__].each do |kwd|
- assert_raise(SyntaxError) {eval("#{kwd} = nil")}
+ assert_syntax_error("#{kwd} = nil", /Can't .* #{kwd}$/)
assert_equal(gvar, global_variables)
end
end
@@ -667,6 +859,32 @@ e"
assert_dedented_heredoc(expected, result)
end
+ def test_dedented_heredoc_expr_string
+ result = ' one#{" two "}'"\n"
+ expected = 'one#{" two "}'"\n"
+ assert_dedented_heredoc(expected, result)
+ end
+
+ def test_dedented_heredoc_continued_line
+ result = " 1\\\n" " 2\n"
+ expected = "1\\\n" "2\n"
+ assert_dedented_heredoc(expected, result)
+ assert_syntax_error("#{<<~"begin;"}\n#{<<~'end;'}", /can't find string "TEXT"/)
+ begin;
+ <<-TEXT
+ \
+ TEXT
+ end;
+ assert_syntax_error("#{<<~"begin;"}\n#{<<~'end;'}", /can't find string "TEXT"/)
+ begin;
+ <<~TEXT
+ \
+ TEXT
+ end;
+
+ assert_equal(" TEXT\n", eval("<<~eos\n" " \\\n" "TEXT\n" "eos\n"))
+ end
+
def test_lineno_after_heredoc
bug7559 = '[ruby-dev:46737]'
expected, _, actual = __LINE__, <<eom, __LINE__
@@ -682,6 +900,46 @@ eom
assert_syntax_error('<<~ "#{}"', /unexpected <</)
end
+ def test_dedented_heredoc_concatenation
+ assert_equal("\n0\n1", eval("<<~0 '1'\n \n0\#{}\n0"))
+ end
+
+ def test_heredoc_mixed_encoding
+ e = assert_syntax_error(<<-'HEREDOC', 'UTF-8 mixed within Windows-31J source')
+ #encoding: cp932
+ <<-TEXT
+ \xe9\x9d\u1234
+ TEXT
+ HEREDOC
+ assert_not_match(/end-of-input/, e.message)
+
+ e = assert_syntax_error(<<-'HEREDOC', 'UTF-8 mixed within Windows-31J source')
+ #encoding: cp932
+ <<-TEXT
+ \xe9\x9d
+ \u1234
+ TEXT
+ HEREDOC
+ assert_not_match(/end-of-input/, e.message)
+
+ e = assert_syntax_error(<<-'HEREDOC', 'UTF-8 mixed within Windows-31J source')
+ #encoding: cp932
+ <<-TEXT
+ \u1234\xe9\x9d
+ TEXT
+ HEREDOC
+ assert_not_match(/end-of-input/, e.message)
+
+ e = assert_syntax_error(<<-'HEREDOC', 'UTF-8 mixed within Windows-31J source')
+ #encoding: cp932
+ <<-TEXT
+ \u1234
+ \xe9\x9d
+ TEXT
+ HEREDOC
+ assert_not_match(/end-of-input/, e.message)
+ end
+
def test_lineno_operation_brace_block
expected = __LINE__ + 1
actual = caller_lineno\
@@ -771,9 +1029,20 @@ eom
assert_syntax_error("puts <<""EOS\n""ng\n""EOS\r""NO\n", /can't find string "EOS" anywhere before EOF/)
end
- def test_heredoc_newline
- assert_warn(/ends with a newline/) do
- eval("<<\"EOS\n\"\nEOS\n")
+ def test_heredoc_no_terminator
+ assert_syntax_error("puts <<""A\n", /can't find string "A" anywhere before EOF/)
+ assert_syntax_error("puts <<""A + <<""B\n", /can't find string "A" anywhere before EOF/)
+ assert_syntax_error("puts <<""A + <<""B\n", /can't find string "B" anywhere before EOF/)
+ end
+
+ def test_unterminated_heredoc
+ assert_syntax_error("<<\"EOS\n\nEOS\n", /unterminated/)
+ assert_syntax_error("<<\"EOS\n\"\nEOS\n", /unterminated/)
+ end
+
+ def test_unterminated_heredoc_cr
+ %W[\r\n \n].each do |nl|
+ assert_syntax_error("<<\"\r\"#{nl}\r#{nl}", /unterminated/, nil, "CR with #{nl.inspect}")
end
end
@@ -783,9 +1052,14 @@ eom
def test_warning_for_cr
feature8699 = '[ruby-core:56240] [Feature #8699]'
- assert_warning(/encountered \\r/, feature8699) do
- eval("\r""__id__\r")
+ s = assert_warning(/encountered \\r/, feature8699) do
+ eval("'\r'\r")
+ end
+ assert_equal("\r", s)
+ s = assert_warning('') do
+ eval("'\r'\r\n")
end
+ assert_equal("\r", s)
end
def test_unexpected_fraction
@@ -807,8 +1081,28 @@ eom
bug10957 = '[ruby-core:68477] [Bug #10957]'
assert_ruby_status(['-c', '-e', 'p ()..0'], "", bug10957)
assert_ruby_status(['-c', '-e', 'p ()...0'], "", bug10957)
- assert_syntax_error('0..%w.', /unterminated string/, bug10957)
- assert_syntax_error('0...%w.', /unterminated string/, bug10957)
+ assert_syntax_error('0..%q.', /unterminated string/, bug10957)
+ assert_syntax_error('0...%q.', /unterminated string/, bug10957)
+ end
+
+ def test_range_at_eol
+ assert_warn(/\.\.\. at EOL/) {eval("1...\n2")}
+ assert_warn('') {eval("(1...)")}
+ assert_warn('') {eval("(1...\n2)")}
+ assert_warn('') {eval("{a: 1...\n2}")}
+
+ assert_warn(/\.\.\. at EOL/) do
+ assert_valid_syntax('foo.[]= ...', verbose: true)
+ end
+ assert_warn(/\.\.\. at EOL/) do
+ assert_valid_syntax('foo.[] ...', verbose: true)
+ end
+ assert_warn(/\.\.\. at EOL/) do
+ assert_syntax_error('foo.[]= bar, ...', /unexpected/, verbose: true)
+ end
+ assert_warn(/\.\.\. at EOL/) do
+ assert_syntax_error('foo.[] bar, ...', /unexpected/, verbose: true)
+ end
end
def test_too_big_nth_ref
@@ -824,9 +1118,21 @@ eom
assert_syntax_error(":#\n foo", /unexpected ':'/)
end
+ def test_invalid_literal_message
+ assert_syntax_error("def :foo", /unexpected symbol literal/)
+ assert_syntax_error("def 'foo'", /unexpected string literal/)
+ end
+
def test_fluent_dot
assert_valid_syntax("a\n.foo")
assert_valid_syntax("a\n&.foo")
+ assert_valid_syntax("a #\n#\n.foo\n")
+ assert_valid_syntax("a #\n#\n&.foo\n")
+ end
+
+ def test_safe_call_in_massign_lhs
+ assert_syntax_error("*a&.x=0", /multiple assignment destination/)
+ assert_syntax_error("a&.x,=0", /multiple assignment destination/)
end
def test_no_warning_logop_literal
@@ -842,22 +1148,19 @@ eom
end
def test_warning_literal_in_condition
- assert_warn(/literal in condition/) do
+ assert_warn(/string literal in condition/) do
eval('1 if ""')
end
- assert_warn(/literal in condition/) do
+ assert_warn(/regex literal in condition/) do
eval('1 if //')
end
- assert_warn(/literal in condition/) do
- eval('1 if true..false')
- end
assert_warning(/literal in condition/) do
eval('1 if 1')
end
- assert_warning(/literal in condition/) do
+ assert_warning(/symbol literal in condition/) do
eval('1 if :foo')
end
- assert_warning(/literal in condition/) do
+ assert_warning(/symbol literal in condition/) do
eval('1 if :"#{"foo".upcase}"')
end
@@ -881,6 +1184,27 @@ eom
end
end
+ def test_warning_literal_in_flip_flop
+ assert_warn(/literal in flip-flop/) do
+ eval('1 if ""..false')
+ end
+ assert_warning(/literal in flip-flop/) do
+ eval('1 if :foo..false')
+ end
+ assert_warning(/literal in flip-flop/) do
+ eval('1 if :"#{"foo".upcase}"..false')
+ end
+ assert_warn(/literal in flip-flop/) do
+ eval('1 if ""...false')
+ end
+ assert_warning(/literal in flip-flop/) do
+ eval('1 if :foo...false')
+ end
+ assert_warning(/literal in flip-flop/) do
+ eval('1 if :"#{"foo".upcase}"...false')
+ end
+ end
+
def test_alias_symbol
bug8851 = '[ruby-dev:47681] [Bug #8851]'
formats = ['%s', ":'%s'", ':"%s"', '%%s(%s)']
@@ -906,7 +1230,7 @@ eom
end
def test_parenthesised_statement_argument
- assert_syntax_error("foo(bar rescue nil)", /unexpected modifier_rescue/)
+ assert_syntax_error("foo(bar rescue nil)", /unexpected `rescue' modifier/)
assert_valid_syntax("foo (bar rescue nil)")
end
@@ -982,11 +1306,16 @@ eom
assert_syntax_error('m 1.0 {}', error, bug)
assert_syntax_error('m :m {}', error, bug)
assert_syntax_error('m :"#{m}" {}', error, bug)
+ assert_syntax_error('m ?x {}', error, bug)
+ assert_syntax_error('m %[] {}', error, bug)
+ assert_syntax_error('m 0..1 {}', error, bug)
+ assert_syntax_error('m [] {}', error, bug)
end
def test_return_toplevel
feature4840 = '[ruby-core:36785] [Feature #4840]'
- code = "#{<<~"begin;"}\n#{<<~'end;'}"
+ line = __LINE__+2
+ code = "#{<<~"begin;"}#{<<~'end;'}"
begin;
return; raise
begin return; rescue SystemExit; exit false; end
@@ -1001,17 +1330,44 @@ eom
begin raise; ensure return; end; self
begin raise; ensure return; end and self
nil&defined?0--begin e=no_method_error(); return; 0;end
+ return puts('ignored') #=> ignored
end;
- all_assertions(feature4840) do |a|
- code.each_line do |s|
- s.chomp!
- a.for(s) do
- assert_ruby_status([], s, proc {RubyVM::InstructionSequence.compile(s).disasm})
+ .split(/\n/).map {|s|[(line+=1), *s.split(/#=> /, 2)]}
+ failed = proc do |n, s|
+ RubyVM::InstructionSequence.compile(s, __FILE__, nil, n).disasm
+ end
+ Tempfile.create(%w"test_return_ .rb") do |lib|
+ lib.close
+ args = %W[-W0 -r#{lib.path}]
+ all_assertions_foreach(feature4840, *[:main, :lib].product([:class, :top], code)) do |main, klass, (n, s, *ex)|
+ if klass == :class
+ s = "class X; #{s}; end"
+ if main == :main
+ assert_in_out_err(%[-W0], s, [], /return/, proc {failed[n, s]}, success: false)
+ else
+ File.write(lib, s)
+ assert_in_out_err(args, "", [], /return/, proc {failed[n, s]}, success: false)
+ end
+ else
+ if main == :main
+ assert_in_out_err(%[-W0], s, ex, [], proc {failed[n, s]}, success: true)
+ else
+ File.write(lib, s)
+ assert_in_out_err(args, "", ex, [], proc {failed[n, s]}, success: true)
+ end
end
end
end
end
+ def test_return_toplevel_with_argument
+ assert_warn(/argument of top-level return is ignored/) {eval("return 1")}
+ end
+
+ def test_return_in_proc_in_class
+ assert_in_out_err(['-e', 'class TestSyntax; proc{ return }.call; end'], "", [], /^-e:1:.*unexpected return \(LocalJumpError\)/)
+ end
+
def test_syntax_error_in_rescue
bug12613 = '[ruby-core:76531] [Bug #12613]'
assert_syntax_error("#{<<-"begin;"}\n#{<<-"end;"}", /Invalid retry/, bug12613)
@@ -1029,6 +1385,515 @@ eom
end;
end
+ def test_syntax_error_at_newline
+ expected = "\n ^"
+ assert_syntax_error("%[abcdef", expected)
+ assert_syntax_error("%[abcdef\n", expected)
+ end
+
+ def test_invalid_jump
+ assert_in_out_err(%w[-e redo], "", [], /^-e:1: /)
+ end
+
+ def test_keyword_not_parens
+ assert_valid_syntax("not()")
+ end
+
+ def test_rescue_do_end_raised
+ result = []
+ assert_raise(RuntimeError) do
+ eval("#{<<-"begin;"}\n#{<<-"end;"}")
+ begin;
+ tap do
+ result << :begin
+ raise "An exception occurred!"
+ ensure
+ result << :ensure
+ end
+ end;
+ end
+ assert_equal([:begin, :ensure], result)
+ end
+
+ def test_rescue_do_end_rescued
+ result = []
+ assert_nothing_raised(RuntimeError) do
+ eval("#{<<-"begin;"}\n#{<<-"end;"}")
+ begin;
+ tap do
+ result << :begin
+ raise "An exception occurred!"
+ rescue
+ result << :rescue
+ else
+ result << :else
+ ensure
+ result << :ensure
+ end
+ end;
+ end
+ assert_equal([:begin, :rescue, :ensure], result)
+ end
+
+ def test_rescue_do_end_no_raise
+ result = []
+ assert_nothing_raised(RuntimeError) do
+ eval("#{<<-"begin;"}\n#{<<-"end;"}")
+ begin;
+ tap do
+ result << :begin
+ rescue
+ result << :rescue
+ else
+ result << :else
+ ensure
+ result << :ensure
+ end
+ end;
+ end
+ assert_equal([:begin, :else, :ensure], result)
+ end
+
+ def test_rescue_do_end_ensure_result
+ result = eval("#{<<-"begin;"}\n#{<<-"end;"}")
+ begin;
+ proc do
+ :begin
+ ensure
+ :ensure
+ end.call
+ end;
+ assert_equal(:begin, result)
+ end
+
+ def test_rescue_do_end_ensure_in_lambda
+ result = []
+ eval("#{<<-"begin;"}\n#{<<-"end;"}")
+ begin;
+ -> do
+ result << :begin
+ raise "An exception occurred!"
+ rescue
+ result << :rescue
+ else
+ result << :else
+ ensure
+ result << :ensure
+ end.call
+ end;
+ assert_equal([:begin, :rescue, :ensure], result)
+ end
+
+ def test_return_in_loop
+ obj = Object.new
+ def obj.test
+ x = nil
+ return until x unless x
+ end
+ assert_nil obj.test
+ end
+
+ def test_assignment_return_in_loop
+ obj = Object.new
+ def obj.test
+ x = nil
+ _y = (return until x unless x)
+ end
+ assert_nil obj.test, "[Bug #16695]"
+ end
+
+ def test_method_call_location
+ line = __LINE__+5
+ e = assert_raise(NoMethodError) do
+ 1.upto(0) do
+ end
+ .
+ foo(
+ 1,
+ 2,
+ )
+ end
+ assert_equal(line, e.backtrace_locations[0].lineno)
+
+ line = __LINE__+5
+ e = assert_raise(NoMethodError) do
+ 1.upto 0 do
+ end
+ .
+ foo(
+ 1,
+ 2,
+ )
+ end
+ assert_equal(line, e.backtrace_locations[0].lineno)
+ end
+
+ def test_methoddef_endless
+ assert_valid_syntax('private def foo = 42')
+ assert_valid_syntax('private def foo() = 42')
+ assert_valid_syntax('private def inc(x) = x + 1')
+ assert_valid_syntax('private def obj.foo = 42')
+ assert_valid_syntax('private def obj.foo() = 42')
+ assert_valid_syntax('private def obj.inc(x) = x + 1')
+ k = Class.new do
+ class_eval('def rescued(x) = raise("to be caught") rescue "instance #{x}"')
+ class_eval('def self.rescued(x) = raise("to be caught") rescue "class #{x}"')
+ end
+ assert_equal("class ok", k.rescued("ok"))
+ assert_equal("instance ok", k.new.rescued("ok"))
+
+ error = /setter method cannot be defined in an endless method definition/
+ assert_syntax_error('def foo=() = 42', error)
+ assert_syntax_error('def obj.foo=() = 42', error)
+ assert_syntax_error('def foo=() = 42 rescue nil', error)
+ assert_syntax_error('def obj.foo=() = 42 rescue nil', error)
+ end
+
+ def test_methoddef_endless_command
+ assert_valid_syntax('def foo = puts "Hello"')
+ assert_valid_syntax('def foo() = puts "Hello"')
+ assert_valid_syntax('def foo(x) = puts x')
+ assert_valid_syntax('def obj.foo = puts "Hello"')
+ assert_valid_syntax('def obj.foo() = puts "Hello"')
+ assert_valid_syntax('def obj.foo(x) = puts x')
+ k = Class.new do
+ class_eval('def rescued(x) = raise "to be caught" rescue "instance #{x}"')
+ class_eval('def self.rescued(x) = raise "to be caught" rescue "class #{x}"')
+ end
+ assert_equal("class ok", k.rescued("ok"))
+ assert_equal("instance ok", k.new.rescued("ok"))
+
+ # Current technical limitation: cannot prepend "private" or something for command endless def
+ error = /syntax error, unexpected string literal/
+ error2 = /syntax error, unexpected local variable or method/
+ assert_syntax_error('private def foo = puts "Hello"', error)
+ assert_syntax_error('private def foo() = puts "Hello"', error)
+ assert_syntax_error('private def foo(x) = puts x', error2)
+ assert_syntax_error('private def obj.foo = puts "Hello"', error)
+ assert_syntax_error('private def obj.foo() = puts "Hello"', error)
+ assert_syntax_error('private def obj.foo(x) = puts x', error2)
+ end
+
+ def test_methoddef_in_cond
+ assert_valid_syntax('while def foo; tap do end; end; break; end')
+ assert_valid_syntax('while def foo a = tap do end; end; break; end')
+ end
+
+ def test_classdef_in_cond
+ assert_valid_syntax('while class Foo; tap do end; end; break; end')
+ assert_valid_syntax('while class Foo a = tap do end; end; break; end')
+ end
+
+ def test_command_with_cmd_brace_block
+ assert_valid_syntax('obj.foo (1) {}')
+ assert_valid_syntax('obj::foo (1) {}')
+ end
+
+ def test_numbered_parameter
+ assert_valid_syntax('proc {_1}')
+ assert_equal(3, eval('[1,2].then {_1+_2}'))
+ assert_equal("12", eval('[1,2].then {"#{_1}#{_2}"}'))
+ assert_equal([1, 2], eval('[1,2].then {_1}'))
+ assert_equal(3, eval('->{_1+_2}.call(1,2)'))
+ assert_equal(4, eval('->(a=->{_1}){a}.call.call(4)'))
+ assert_equal(5, eval('-> a: ->{_1} {a}.call.call(5)'))
+ assert_syntax_error('proc {|| _1}', /ordinary parameter is defined/)
+ assert_syntax_error('proc {|;a| _1}', /ordinary parameter is defined/)
+ assert_syntax_error("proc {|\n| _1}", /ordinary parameter is defined/)
+ assert_syntax_error('proc {|x| _1}', /ordinary parameter is defined/)
+ assert_syntax_error('proc {_1; proc {_2}}', /numbered parameter is already used/)
+ assert_syntax_error('proc {proc {_1}; _2}', /numbered parameter is already used/)
+ assert_syntax_error('->(){_1}', /ordinary parameter is defined/)
+ assert_syntax_error('->(x){_1}', /ordinary parameter is defined/)
+ assert_syntax_error('->x{_1}', /ordinary parameter is defined/)
+ assert_syntax_error('->x:_2{}', /ordinary parameter is defined/)
+ assert_syntax_error('->x=_1{}', /ordinary parameter is defined/)
+ assert_syntax_error('-> {_1; -> {_2}}', /numbered parameter is already used/)
+ assert_syntax_error('-> {-> {_1}; _2}', /numbered parameter is already used/)
+ assert_syntax_error('proc {_1; _1 = nil}', /Can't assign to numbered parameter _1/)
+ assert_syntax_error('proc {_1 = nil}', /_1 is reserved for numbered parameter/)
+ assert_syntax_error('_2=1', /_2 is reserved for numbered parameter/)
+ assert_syntax_error('proc {|_3|}', /_3 is reserved for numbered parameter/)
+ assert_syntax_error('def x(_4) end', /_4 is reserved for numbered parameter/)
+ assert_syntax_error('def _5; end', /_5 is reserved for numbered parameter/)
+ assert_syntax_error('def self._6; end', /_6 is reserved for numbered parameter/)
+ assert_raise_with_message(NameError, /undefined local variable or method `_1'/) {
+ eval('_1')
+ }
+ ['class C', 'class << C', 'module M', 'def m', 'def o.m'].each do |c|
+ assert_valid_syntax("->{#{c};->{_1};end;_1}\n")
+ assert_valid_syntax("->{_1;#{c};->{_1};end}\n")
+ end
+
+ 1.times {
+ [
+ _1,
+ assert_equal([:a], eval("[:a].map{_1}")),
+ assert_raise(NameError) {eval("_1")},
+ ]
+ }
+ end
+
+ def test_value_expr_in_condition
+ mesg = /void value expression/
+ assert_syntax_error("tap {a = (true ? next : break)}", mesg)
+ assert_valid_syntax("tap {a = (true ? true : break)}")
+ assert_valid_syntax("tap {a = (break if false)}")
+ assert_valid_syntax("tap {a = (break unless true)}")
+ end
+
+ def test_tautological_condition
+ assert_valid_syntax("def f() return if false and invalid; nil end")
+ assert_valid_syntax("def f() return unless true or invalid; nil end")
+ end
+
+ def test_argument_forwarding
+ assert_valid_syntax('def foo(...) bar(...) end')
+ assert_valid_syntax('def foo(...) end')
+ assert_valid_syntax('def foo(a, ...) bar(...) end')
+ assert_valid_syntax("def foo ...\n bar(...)\nend")
+ assert_valid_syntax("def foo a, ...\n bar(...)\nend")
+ assert_valid_syntax("def foo b = 1, ...\n bar(...)\nend")
+ assert_valid_syntax("def foo ...; bar(...); end")
+ assert_valid_syntax("def foo a, ...; bar(...); end")
+ assert_valid_syntax("def foo b = 1, ...; bar(...); end")
+ assert_valid_syntax("(def foo ...\n bar(...)\nend)")
+ assert_valid_syntax("(def foo ...; bar(...); end)")
+ assert_valid_syntax('def ==(...) end')
+ assert_valid_syntax('def [](...) end')
+ assert_valid_syntax('def nil(...) end')
+ assert_valid_syntax('def true(...) end')
+ assert_valid_syntax('def false(...) end')
+ unexpected = /unexpected \.{3}/
+ assert_syntax_error('iter do |...| end', /unexpected/)
+ assert_syntax_error('iter {|...|}', /unexpected/)
+ assert_syntax_error('->... {}', unexpected)
+ assert_syntax_error('->(...) {}', unexpected)
+ assert_syntax_error('def foo(x, y, z) bar(...); end', /unexpected/)
+ assert_syntax_error('def foo(x, y, z) super(...); end', /unexpected/)
+ assert_syntax_error('def foo(...) yield(...); end', /unexpected/)
+ assert_syntax_error('def foo(...) return(...); end', /unexpected/)
+ assert_syntax_error('def foo(...) a = (...); end', /unexpected/)
+ assert_syntax_error('def foo(...) [...]; end', /unexpected/)
+ assert_syntax_error('def foo(...) foo[...]; end', /unexpected/)
+ assert_syntax_error('def foo(...) foo[...] = x; end', /unexpected/)
+ assert_syntax_error('def foo(...) foo(...) { }; end', /both block arg and actual block given/)
+ assert_syntax_error('def foo(...) defined?(...); end', /unexpected/)
+
+ obj1 = Object.new
+ def obj1.bar(*args, **kws, &block)
+ if block
+ block.call(args, kws)
+ else
+ [args, kws]
+ end
+ end
+ obj4 = obj1.clone
+ obj5 = obj1.clone
+ obj1.instance_eval('def foo(...) bar(...) end', __FILE__, __LINE__)
+ obj4.instance_eval("def foo ...\n bar(...)\n""end", __FILE__, __LINE__)
+ obj5.instance_eval("def foo ...; bar(...); end", __FILE__, __LINE__)
+
+ klass = Class.new {
+ def foo(*args, **kws, &block)
+ if block
+ block.call(args, kws)
+ else
+ [args, kws]
+ end
+ end
+ }
+ obj2 = klass.new
+ obj2.instance_eval('def foo(...) super(...) end', __FILE__, __LINE__)
+
+ obj3 = Object.new
+ def obj3.bar(*args, &block)
+ if kws = Hash.try_convert(args.last)
+ args.pop
+ else
+ kws = {}
+ end
+ if block
+ block.call(args, kws)
+ else
+ [args, kws]
+ end
+ end
+ obj3.instance_eval('def foo(...) bar(...) end', __FILE__, __LINE__)
+
+ [obj1, obj2, obj3, obj4, obj5].each do |obj|
+ assert_warning('') {
+ assert_equal([[1, 2, 3], {k1: 4, k2: 5}], obj.foo(1, 2, 3, k1: 4, k2: 5) {|*x| x})
+ }
+ assert_warning('') {
+ assert_equal([[1, 2, 3], {k1: 4, k2: 5}], obj.foo(1, 2, 3, k1: 4, k2: 5))
+ }
+ array = obj == obj3 ? [] : [{}]
+ assert_warning('') {
+ assert_equal([array, {}], obj.foo({}) {|*x| x})
+ }
+ assert_warning('') {
+ assert_equal([array, {}], obj.foo({}))
+ }
+ assert_equal(-1, obj.method(:foo).arity)
+ parameters = obj.method(:foo).parameters
+ assert_equal(:rest, parameters.dig(0, 0))
+ assert_equal(:keyrest, parameters.dig(1, 0))
+ assert_equal(:block, parameters.dig(2, 0))
+ end
+ end
+
+ def test_argument_forwarding_with_leading_arguments
+ obj = Object.new
+ def obj.bar(*args, **kws, &block)
+ if block
+ block.call(args, kws)
+ else
+ [args, kws]
+ end
+ end
+ obj.instance_eval('def foo(_a, ...) bar(...) end', __FILE__, __LINE__)
+ assert_equal [[], {}], obj.foo(1)
+ assert_equal [[2], {}], obj.foo(1, 2)
+ assert_equal [[2, 3], {}], obj.foo(1, 2, 3)
+ assert_equal [[], {a: 1}], obj.foo(1, a: 1)
+ assert_equal [[2], {a: 1}], obj.foo(1, 2, a: 1)
+ assert_equal [[2, 3], {a: 1}], obj.foo(1, 2, 3, a: 1)
+ assert_equal [[2, 3], {a: 1}], obj.foo(1, 2, 3, a: 1){|args, kws| [args, kws]}
+
+ obj.singleton_class.send(:remove_method, :foo)
+ obj.instance_eval('def foo(...) bar(1, ...) end', __FILE__, __LINE__)
+ assert_equal [[1], {}], obj.foo
+ assert_equal [[1, 1], {}], obj.foo(1)
+ assert_equal [[1, 1, 2], {}], obj.foo(1, 2)
+ assert_equal [[1, 1, 2, 3], {}], obj.foo(1, 2, 3)
+ assert_equal [[1], {a: 1}], obj.foo(a: 1)
+ assert_equal [[1, 1], {a: 1}], obj.foo(1, a: 1)
+ assert_equal [[1, 1, 2], {a: 1}], obj.foo(1, 2, a: 1)
+ assert_equal [[1, 1, 2, 3], {a: 1}], obj.foo(1, 2, 3, a: 1)
+ assert_equal [[1, 1, 2, 3], {a: 1}], obj.foo(1, 2, 3, a: 1){|args, kws| [args, kws]}
+
+ obj.singleton_class.send(:remove_method, :foo)
+ obj.instance_eval('def foo(a, ...) bar(a, ...) end', __FILE__, __LINE__)
+ assert_equal [[4], {}], obj.foo(4)
+ assert_equal [[4, 2], {}], obj.foo(4, 2)
+ assert_equal [[4, 2, 3], {}], obj.foo(4, 2, 3)
+ assert_equal [[4], {a: 1}], obj.foo(4, a: 1)
+ assert_equal [[4, 2], {a: 1}], obj.foo(4, 2, a: 1)
+ assert_equal [[4, 2, 3], {a: 1}], obj.foo(4, 2, 3, a: 1)
+ assert_equal [[4, 2, 3], {a: 1}], obj.foo(4, 2, 3, a: 1){|args, kws| [args, kws]}
+
+ obj.singleton_class.send(:remove_method, :foo)
+ obj.instance_eval('def foo(_a, ...) bar(1, ...) end', __FILE__, __LINE__)
+ assert_equal [[1], {}], obj.foo(4)
+ assert_equal [[1, 2], {}], obj.foo(4, 2)
+ assert_equal [[1, 2, 3], {}], obj.foo(4, 2, 3)
+ assert_equal [[1], {a: 1}], obj.foo(4, a: 1)
+ assert_equal [[1, 2], {a: 1}], obj.foo(4, 2, a: 1)
+ assert_equal [[1, 2, 3], {a: 1}], obj.foo(4, 2, 3, a: 1)
+ assert_equal [[1, 2, 3], {a: 1}], obj.foo(4, 2, 3, a: 1){|args, kws| [args, kws]}
+
+ obj.singleton_class.send(:remove_method, :foo)
+ obj.instance_eval('def foo(_a, _b, ...) bar(...) end', __FILE__, __LINE__)
+ assert_equal [[], {}], obj.foo(4, 5)
+ assert_equal [[2], {}], obj.foo(4, 5, 2)
+ assert_equal [[2, 3], {}], obj.foo(4, 5, 2, 3)
+ assert_equal [[], {a: 1}], obj.foo(4, 5, a: 1)
+ assert_equal [[2], {a: 1}], obj.foo(4, 5, 2, a: 1)
+ assert_equal [[2, 3], {a: 1}], obj.foo(4, 5, 2, 3, a: 1)
+ assert_equal [[2, 3], {a: 1}], obj.foo(4, 5, 2, 3, a: 1){|args, kws| [args, kws]}
+
+ obj.singleton_class.send(:remove_method, :foo)
+ obj.instance_eval('def foo(_a, _b, ...) bar(1, ...) end', __FILE__, __LINE__)
+ assert_equal [[1], {}], obj.foo(4, 5)
+ assert_equal [[1, 2], {}], obj.foo(4, 5, 2)
+ assert_equal [[1, 2, 3], {}], obj.foo(4, 5, 2, 3)
+ assert_equal [[1], {a: 1}], obj.foo(4, 5, a: 1)
+ assert_equal [[1, 2], {a: 1}], obj.foo(4, 5, 2, a: 1)
+ assert_equal [[1, 2, 3], {a: 1}], obj.foo(4, 5, 2, 3, a: 1)
+ assert_equal [[1, 2, 3], {a: 1}], obj.foo(4, 5, 2, 3, a: 1){|args, kws| [args, kws]}
+
+ obj.singleton_class.send(:remove_method, :foo)
+ obj.instance_eval('def foo(_a, ...) bar(1, 2, ...) end', __FILE__, __LINE__)
+ assert_equal [[1, 2], {}], obj.foo(5)
+ assert_equal [[1, 2, 5], {}], obj.foo(4, 5)
+ assert_equal [[1, 2, 5, 2], {}], obj.foo(4, 5, 2)
+ assert_equal [[1, 2, 5, 2, 3], {}], obj.foo(4, 5, 2, 3)
+ assert_equal [[1, 2, 5], {a: 1}], obj.foo(4, 5, a: 1)
+ assert_equal [[1, 2, 5, 2], {a: 1}], obj.foo(4, 5, 2, a: 1)
+ assert_equal [[1, 2, 5, 2, 3], {a: 1}], obj.foo(4, 5, 2, 3, a: 1)
+ assert_equal [[1, 2, 5, 2, 3], {a: 1}], obj.foo(4, 5, 2, 3, a: 1){|args, kws| [args, kws]}
+
+ obj.singleton_class.send(:remove_method, :foo)
+ obj.instance_eval('def foo(a, b, ...) bar(b, a, ...) end', __FILE__, __LINE__)
+ assert_equal [[5, 4], {}], obj.foo(4, 5)
+ assert_equal [[5, 4, 2], {}], obj.foo(4, 5, 2)
+ assert_equal [[5, 4, 2, 3], {}], obj.foo(4, 5, 2, 3)
+ assert_equal [[5, 4], {a: 1}], obj.foo(4, 5, a: 1)
+ assert_equal [[5, 4, 2], {a: 1}], obj.foo(4, 5, 2, a: 1)
+ assert_equal [[5, 4, 2, 3], {a: 1}], obj.foo(4, 5, 2, 3, a: 1)
+ assert_equal [[5, 4, 2, 3], {a: 1}], obj.foo(4, 5, 2, 3, a: 1){|args, kws| [args, kws]}
+
+ obj.singleton_class.send(:remove_method, :foo)
+ obj.instance_eval('def foo(a, _b, ...) bar(a, ...) end', __FILE__, __LINE__)
+ assert_equal [[4], {}], obj.foo(4, 5)
+ assert_equal [[4, 2], {}], obj.foo(4, 5, 2)
+ assert_equal [[4, 2, 3], {}], obj.foo(4, 5, 2, 3)
+ assert_equal [[4], {a: 1}], obj.foo(4, 5, a: 1)
+ assert_equal [[4, 2], {a: 1}], obj.foo(4, 5, 2, a: 1)
+ assert_equal [[4, 2, 3], {a: 1}], obj.foo(4, 5, 2, 3, a: 1)
+ assert_equal [[4, 2, 3], {a: 1}], obj.foo(4, 5, 2, 3, a: 1){|args, kws| [args, kws]}
+
+ obj.singleton_class.send(:remove_method, :foo)
+ obj.instance_eval('def foo(a, ...) bar(a, 1, ...) end', __FILE__, __LINE__)
+ assert_equal [[4, 1], {}], obj.foo(4)
+ assert_equal [[4, 1, 5], {}], obj.foo(4, 5)
+ assert_equal [[4, 1, 5, 2], {}], obj.foo(4, 5, 2)
+ assert_equal [[4, 1, 5, 2, 3], {}], obj.foo(4, 5, 2, 3)
+ assert_equal [[4, 1, 5], {a: 1}], obj.foo(4, 5, a: 1)
+ assert_equal [[4, 1, 5, 2], {a: 1}], obj.foo(4, 5, 2, a: 1)
+ assert_equal [[4, 1, 5, 2, 3], {a: 1}], obj.foo(4, 5, 2, 3, a: 1)
+ assert_equal [[4, 1, 5, 2, 3], {a: 1}], obj.foo(4, 5, 2, 3, a: 1){|args, kws| [args, kws]}
+
+ obj.singleton_class.send(:remove_method, :foo)
+ obj.instance_eval("def foo a, ...\n bar(a, ...)\n"" end", __FILE__, __LINE__)
+ assert_equal [[4], {}], obj.foo(4)
+ assert_equal [[4, 2], {}], obj.foo(4, 2)
+ assert_equal [[4, 2, 3], {}], obj.foo(4, 2, 3)
+ assert_equal [[4], {a: 1}], obj.foo(4, a: 1)
+ assert_equal [[4, 2], {a: 1}], obj.foo(4, 2, a: 1)
+ assert_equal [[4, 2, 3], {a: 1}], obj.foo(4, 2, 3, a: 1)
+ assert_equal [[4, 2, 3], {a: 1}], obj.foo(4, 2, 3, a: 1){|args, kws| [args, kws]}
+
+ obj.singleton_class.send(:remove_method, :foo)
+ obj.instance_eval("def foo a, ...; bar(a, ...); end", __FILE__, __LINE__)
+ assert_equal [[4], {}], obj.foo(4)
+ assert_equal [[4, 2], {}], obj.foo(4, 2)
+ assert_equal [[4, 2, 3], {}], obj.foo(4, 2, 3)
+ assert_equal [[4], {a: 1}], obj.foo(4, a: 1)
+ assert_equal [[4, 2], {a: 1}], obj.foo(4, 2, a: 1)
+ assert_equal [[4, 2, 3], {a: 1}], obj.foo(4, 2, 3, a: 1)
+ assert_equal [[4, 2, 3], {a: 1}], obj.foo(4, 2, 3, a: 1){|args, kws| [args, kws]}
+
+ exp = eval("-> (a: nil) {a...1}")
+ assert_equal 0...1, exp.call(a: 0)
+ end
+
+ def test_cdhash
+ assert_separately([], <<-RUBY)
+ n = case 1 when 2r then false else true end
+ assert_equal(n, true, '[ruby-core:103759] [Bug #17854]')
+ RUBY
+ assert_separately([], <<-RUBY)
+ n = case 3/2r when 1.5r then true else false end
+ assert_equal(n, true, '[ruby-core:103759] [Bug #17854]')
+ RUBY
+ assert_separately([], <<-RUBY)
+ n = case 1i when 1i then true else false end
+ assert_equal(n, true, '[ruby-core:103759] [Bug #17854]')
+ RUBY
+ end
+
private
def not_label(x) @result = x; @not_label ||= nil end