rdl 1.1.1 → 2.0.0.rc1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (67) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGES.md +6 -0
  3. data/README.md +211 -32
  4. data/gemfiles/Gemfile.travis +1 -1
  5. data/lib/rdl.rb +85 -18
  6. data/lib/rdl/info.rb +74 -0
  7. data/lib/rdl/query.rb +8 -9
  8. data/lib/rdl/typecheck.rb +1057 -0
  9. data/lib/rdl/types/annotated_arg.rb +5 -5
  10. data/lib/rdl/types/{nil.rb → bot.rb} +9 -13
  11. data/lib/rdl/types/dependent_arg.rb +5 -5
  12. data/lib/rdl/types/dots_query.rb +2 -0
  13. data/lib/rdl/types/finitehash.rb +67 -24
  14. data/lib/rdl/types/generic.rb +13 -21
  15. data/lib/rdl/types/intersection.rb +9 -8
  16. data/lib/rdl/types/method.rb +30 -32
  17. data/lib/rdl/types/nominal.rb +22 -16
  18. data/lib/rdl/types/optional.rb +8 -22
  19. data/lib/rdl/types/parser.racc +8 -3
  20. data/lib/rdl/types/parser.tab.rb +131 -118
  21. data/lib/rdl/types/singleton.rb +15 -10
  22. data/lib/rdl/types/structural.rb +6 -6
  23. data/lib/rdl/types/top.rb +6 -6
  24. data/lib/rdl/types/tuple.rb +56 -24
  25. data/lib/rdl/types/type.rb +9 -0
  26. data/lib/rdl/types/type_inferencer.rb +1 -1
  27. data/lib/rdl/types/union.rb +52 -26
  28. data/lib/rdl/types/var.rb +7 -6
  29. data/lib/rdl/types/vararg.rb +5 -6
  30. data/lib/rdl/types/wild_query.rb +9 -2
  31. data/lib/rdl/util.rb +9 -7
  32. data/lib/rdl/wrap.rb +90 -72
  33. data/lib/rdl_types.rb +2 -2
  34. data/rdl.gemspec +6 -8
  35. data/test/test_alias.rb +4 -3
  36. data/test/test_contract.rb +5 -4
  37. data/test/test_dsl.rb +2 -1
  38. data/test/test_generic.rb +30 -26
  39. data/test/test_intersection.rb +3 -3
  40. data/test/test_le.rb +129 -61
  41. data/test/test_lib_types.rb +3 -2
  42. data/test/test_member.rb +33 -46
  43. data/test/test_parser.rb +113 -116
  44. data/test/test_query.rb +2 -1
  45. data/test/test_rdl.rb +64 -6
  46. data/test/test_rdl_type.rb +3 -2
  47. data/test/test_type_contract.rb +30 -12
  48. data/test/test_typecheck.rb +893 -0
  49. data/test/test_types.rb +50 -54
  50. data/test/test_wrap.rb +2 -1
  51. data/types/ruby-2.x/_aliases.rb +13 -2
  52. data/types/ruby-2.x/bigdecimal.rb +60 -85
  53. data/types/ruby-2.x/bignum.rb +80 -119
  54. data/types/ruby-2.x/complex.rb +33 -40
  55. data/types/ruby-2.x/fixnum.rb +81 -120
  56. data/types/ruby-2.x/float.rb +79 -116
  57. data/types/ruby-2.x/integer.rb +187 -22
  58. data/types/ruby-2.x/nil.rb +12 -0
  59. data/types/ruby-2.x/numeric.rb +38 -38
  60. data/types/ruby-2.x/object.rb +3 -3
  61. data/types/ruby-2.x/random.rb +2 -0
  62. data/types/ruby-2.x/range.rb +20 -19
  63. data/types/ruby-2.x/rational.rb +40 -40
  64. data/types/ruby-2.x/regexp.rb +4 -4
  65. data/types/ruby-2.x/string.rb +15 -17
  66. metadata +17 -16
  67. data/lib/rdl/types/.#lexer.rex +0 -1
@@ -1,5 +1,6 @@
1
1
  require 'minitest/autorun'
2
- require_relative '../lib/rdl.rb'
2
+ $LOAD_PATH << File.dirname(__FILE__) + "/../lib"
3
+ require 'rdl'
3
4
 
4
5
  class TestQuery < Minitest::Test
5
6
  include RDL::Type
@@ -1,5 +1,6 @@
1
1
  require 'minitest/autorun'
2
- require_relative '../lib/rdl.rb'
2
+ $LOAD_PATH << File.dirname(__FILE__) + "/../lib"
3
+ require 'rdl'
3
4
 
4
5
  class TestRDL < Minitest::Test
5
6
 
@@ -282,11 +283,11 @@ RUBY
282
283
  end
283
284
 
284
285
  def test_cast
285
- ntyp = RDL::Type::NilType.new
286
- obj1 = 3.type_cast(ntyp)
287
- assert (ntyp.member? obj1)
288
- obj2 = 3.type_cast('nil')
289
- assert (ntyp.member? obj2)
286
+ obj1 = 3.type_cast($__rdl_nil_type, force: true)
287
+ assert ($__rdl_nil_type.member? obj1)
288
+ obj2 = 3.type_cast('nil', force: true)
289
+ assert ($__rdl_nil_type.member? obj2)
290
+ assert_raises(RuntimeError) { 3.type_cast($__rdl_nil_type) }
290
291
  end
291
292
 
292
293
  def test_pre_post_self
@@ -298,4 +299,61 @@ RUBY
298
299
  assert_equal 3, m23(3)
299
300
  end
300
301
 
302
+ def test_nowrap
303
+ pre(TestRDL, :nwrap1) { true }
304
+ def nwrap1(x) return x; end
305
+ assert(RDL::Wrap.wrapped?(TestRDL, :nwrap1))
306
+ pre(TestRDL, :nwrap2, wrap: false) { true }
307
+ def nwrap2(x) return x; end
308
+ assert(not(RDL::Wrap.wrapped?(TestRDL, :nwrap2)))
309
+
310
+ post(TestRDL, :nwrap3) { true }
311
+ def nwrap3(x) return x; end
312
+ assert(RDL::Wrap.wrapped?(TestRDL, :nwrap3))
313
+ post(TestRDL, :nwrap4, wrap: false) { true }
314
+ def nwrap4(x) return x; end
315
+ assert(not(RDL::Wrap.wrapped?(TestRDL, :nwrap4)))
316
+
317
+ type TestRDL, :nwrap5, "(Fixnum) -> Fixnum"
318
+ def nwrap5(x) return x; end
319
+ assert(RDL::Wrap.wrapped?(TestRDL, :nwrap5))
320
+ type TestRDL, :nwrap6, "(Fixnum) -> Fixnum", wrap: false
321
+ def nwrap6(x) return x; end
322
+ assert(not(RDL::Wrap.wrapped?(TestRDL, :nwrap6)))
323
+
324
+ self.class.class_eval {
325
+ type "(Fixnum) -> Fixnum"
326
+ def nwrap7(x) return x; end
327
+ }
328
+ assert(RDL::Wrap.wrapped?(TestRDL, :nwrap7))
329
+ self.class.class_eval {
330
+ type "(Fixnum) -> Fixnum", wrap: false
331
+ def nwrap8(x) return x; end
332
+ }
333
+ assert(not(RDL::Wrap.wrapped?(TestRDL, :nwrap8)))
334
+ end
335
+
336
+ def test_var_type
337
+ self.class.class_eval {
338
+ var_type :@foo, "Fixnum"
339
+ var_type :@@foo, "String"
340
+ var_type :$foo, "Symbol"
341
+ }
342
+ assert_equal $__rdl_fixnum_type, $__rdl_info.get(TestRDL, :@foo, :type)
343
+ assert_equal $__rdl_string_type, $__rdl_info.get(TestRDL, :@@foo, :type)
344
+ assert_equal $__rdl_symbol_type, $__rdl_info.get(RDL::Util::GLOBAL_NAME, :$foo, :type)
345
+ assert_raises(RuntimeError) {
346
+ self.class.class_eval { var_type :@foo, "String" }
347
+ }
348
+ assert_raises(RuntimeError) {
349
+ self.class.class_eval { var_type :@@foo, "Fixnum" }
350
+ }
351
+ assert_raises(RuntimeError) {
352
+ self.class.class_eval { var_type :Foo, "String" }
353
+ }
354
+ assert_raises(RuntimeError) {
355
+ self.class.class_eval { var_type :$foo, "String" }
356
+ }
357
+ end
358
+
301
359
  end
@@ -1,5 +1,6 @@
1
1
  require 'minitest/autorun'
2
- require_relative '../lib/rdl.rb'
2
+ $LOAD_PATH << File.dirname(__FILE__) + "/../lib"
3
+ require 'rdl'
3
4
 
4
5
  class TestRDLType < Minitest::Test
5
6
  def test_single_type_contract
@@ -67,4 +68,4 @@ class TestRDLType < Minitest::Test
67
68
  assert_raises(RDL::Type::TypeError) { TestRDLType::NI_B.new("3") }
68
69
  end
69
70
 
70
- end
71
+ end
@@ -1,5 +1,6 @@
1
1
  require 'minitest/autorun'
2
- require_relative '../lib/rdl.rb'
2
+ $LOAD_PATH << File.dirname(__FILE__) + "/../lib"
3
+ require 'rdl'
3
4
 
4
5
  class TestTypeContract < Minitest::Test
5
6
  include RDL::Type
@@ -8,10 +9,9 @@ class TestTypeContract < Minitest::Test
8
9
  def setup
9
10
  @p = Parser.new
10
11
  end
11
-
12
+
12
13
  def test_flat
13
- tnil = NilType.new
14
- cnil = tnil.to_contract
14
+ cnil = $__rdl_nil_type.to_contract
15
15
  assert (cnil.check self, nil)
16
16
  assert_raises(TypeError) { cnil.check self, true }
17
17
  tfixnum = NominalType.new :Fixnum
@@ -42,7 +42,7 @@ class TestTypeContract < Minitest::Test
42
42
  p3 = t3.to_contract.wrap(self) { nil }
43
43
  assert_nil p3.call
44
44
  assert_raises(TypeError) { p3.call(42) }
45
-
45
+
46
46
  t4 = @p.scan_str "(Fixnum, ?Fixnum) -> Fixnum"
47
47
  p4 = t4.to_contract.wrap(self) { |x| x }
48
48
  assert_equal 42, p4.call(42)
@@ -125,11 +125,11 @@ class TestTypeContract < Minitest::Test
125
125
  assert_raises(TypeError) { p12b.call(9, 10) }
126
126
 
127
127
  t13 = @p.scan_str "(Fixnum, {(Fixnum x {{x>10}}) -> Fixnum}) -> Float"
128
- p13 = t13.to_higher_contract(self) { |x,y| x+y.call(11)+0.5 }
128
+ p13 = t13.to_higher_contract(self) { |x,y| x+y.call(11)+0.5 }
129
129
  assert_equal 53.5, p13.call(42, Proc.new { |x| x })
130
130
  assert_raises(TypeError) { p13.call(42.5, Proc.new { |x| x} ) }
131
131
  assert_raises(TypeError) { p13.call(42, Proc.new { |x| 0.5 } ) }
132
- p13b = t13.to_higher_contract(self) { |x,y| x+y.call(10)+0.5 }
132
+ p13b = t13.to_higher_contract(self) { |x,y| x+y.call(10)+0.5 }
133
133
  assert_raises(TypeError) { p13b.call(42, Proc.new { |x| x } ) }
134
134
  p13c = t13.to_higher_contract(self) { |x,y| x+y.call(11.5)+0.5 }
135
135
  assert_raises(TypeError) { p13c.call(42, Proc.new { |x| x } ) }
@@ -146,31 +146,49 @@ class TestTypeContract < Minitest::Test
146
146
  p14d = p14c.call(42,42)
147
147
  assert_raises(TypeError) { p14d.call(42) }
148
148
 
149
+ #contracts involving method blocks
149
150
  assert_equal 47, block_contract_test1(42) {|z| z}
150
- assert_raises(TypeError) { block_contract_test1(42) {|z| 0.5} }
151
+ assert_raises(TypeError) { block_contract_test1(42) {|z| 0.5} }
151
152
  assert_raises(TypeError) { block_contract_test2(42) {|z| z} }
152
-
153
+ assert_raises(TypeError) { block_contract_test1(42) }
154
+ assert_raises(TypeError) { block_contract_test3(42) { |x| x } }
153
155
 
154
156
  t15 = @p.scan_str "(Fixnum x {{x>y}}, Fixnum y) -> Fixnum"
155
- p15 = t15.to_contract.wrap(self) { |x, y| x+y }
157
+ p15 = t15.to_contract.wrap(self) { |x, y| x+y }
156
158
  assert_equal 21, p15.call(11, 10)
157
159
  assert_raises(TypeError) { p15.call(10, 11) }
158
160
 
159
161
  t16 = @p.scan_str "(Fixnum x {{x > undefvar}}, Fixnum) -> Fixnum"
160
162
  p16 = t16.to_contract.wrap(self) { |x,y| x }
161
- assert_raises(NameError) { p16.call(10,10) }
163
+ assert_raises(NameError) { p16.call(10,10) }
164
+
165
+ t17 = @p.scan_str "(Fixnum, *String, Fixnum) -> Fixnum"
166
+ p17 = t17.to_contract.wrap(self) { |x| x }
167
+ assert_equal 42, p17.call(42, 43)
168
+ assert_equal 42, p17.call(42, 'foo', 43)
169
+ assert_equal 42, p17.call(42, 'foo', 'bar', 43)
170
+ assert_raises(TypeError) { p17.call }
171
+ assert_raises(TypeError) { p17.call('42') }
172
+ assert_raises(TypeError) { p17.call(42) }
173
+ assert_raises(TypeError) { p17.call(42, '43') }
174
+ assert_raises(TypeError) { p17.call(42, 43, '44') }
162
175
  end
163
176
 
164
177
  type '(Fixnum) { (Fixnum) -> Fixnum } -> Fixnum'
165
178
  def block_contract_test1(x)
166
179
  x+yield(5)
167
180
  end
168
-
181
+
169
182
  type '(Fixnum) { (Fixnum) -> Fixnum } -> Float'
170
183
  def block_contract_test2(x)
171
184
  x+yield(4.5)
172
185
  end
173
186
 
187
+ type '(Fixnum) -> Fixnum'
188
+ def block_contract_test3(x)
189
+ 42
190
+ end
191
+
174
192
  def test_proc_names
175
193
  t1 = @p.scan_str "(x: Fixnum) -> Fixnum"
176
194
  p1 = t1.to_contract.wrap(self) { |x:| x }
@@ -0,0 +1,893 @@
1
+ require 'minitest/autorun'
2
+ $LOAD_PATH << File.dirname(__FILE__) + "/../lib"
3
+ require 'rdl'
4
+ require 'rdl_types'
5
+
6
+ class TestTypecheck < Minitest::Test
7
+
8
+ type :_any_object, "() -> Object" # a method that could return true or false
9
+
10
+ def setup
11
+ @t3 = RDL::Type::SingletonType.new 3
12
+ @t4 = RDL::Type::SingletonType.new 4
13
+ @t5 = RDL::Type::SingletonType.new 5
14
+ @t34 = RDL::Type::UnionType.new(@t3, @t4)
15
+ @t45 = RDL::Type::UnionType.new(@t4, @t5)
16
+ @t35 = RDL::Type::UnionType.new(@t3, @t5)
17
+ @t345 = RDL::Type::UnionType.new(@t34, @t5)
18
+ @ts3 = RDL::Type::UnionType.new($__rdl_string_type, @t3)
19
+ @ts34 = RDL::Type::UnionType.new(@ts3, @t4)
20
+ @t3n = RDL::Type::UnionType.new(@t3, $__rdl_nil_type)
21
+ @t4n = RDL::Type::UnionType.new(@t4, $__rdl_nil_type)
22
+ @env = RDL::Typecheck::Env.new(self: tt("TestTypecheck"))
23
+ @scopef = { tret: $__rdl_fixnum_type }
24
+ @tfs = RDL::Type::UnionType.new($__rdl_fixnum_type, $__rdl_string_type)
25
+ @scopefs = { tret: @tfs }
26
+ end
27
+
28
+ # [+ a +] is the environment, a map from symbols to types; empty if omitted
29
+ # [+ expr +] is a string containing the expression to typecheck
30
+ # returns the type of the expression
31
+ def do_tc(expr, scope: Hash.new, env: RDL::Typecheck::Env.new)
32
+ ast = Parser::CurrentRuby.parse expr
33
+ _, t = RDL::Typecheck.tc scope, env, ast
34
+ return t
35
+ end
36
+
37
+ # convert arg string to a type
38
+ def tt(t)
39
+ $__rdl_parser.scan_str('#T ' + t)
40
+ end
41
+
42
+ def test_def
43
+ self.class.class_eval {
44
+ type "(Fixnum) -> Fixnum", typecheck_now: true
45
+ def def_ff(x) x; end
46
+ }
47
+
48
+ assert_raises(RDL::Typecheck::StaticTypeError) {
49
+ self.class.class_eval {
50
+ type "(Fixnum) -> Fixnum", typecheck_now: true
51
+ def def_fs(x) "42"; end
52
+ }
53
+ }
54
+
55
+ self.class.class_eval {
56
+ type "(Fixnum) -> Fixnum", typecheck_now: true
57
+ def def_ff2(x) x; end
58
+ }
59
+ assert_equal 42, def_ff2(42)
60
+
61
+ self.class.class_eval {
62
+ type "(Fixnum) -> Fixnum", typecheck: true
63
+ def def_fs2(x) "42"; end
64
+ }
65
+ assert_raises(RDL::Typecheck::StaticTypeError) { def_fs2(42) }
66
+
67
+ assert_raises(RDL::Typecheck::StaticTypeError) {
68
+ self.class.class_eval {
69
+ type "(Fixnum) -> Fixnum", typecheck_now: true
70
+ def def_ff3(x, y) 42; end
71
+ }
72
+ }
73
+ end
74
+
75
+ def test_defs
76
+ self.class.class_eval {
77
+ type "(Fixnum) -> Class", typecheck_now: true
78
+ def self.defs_ff(x) self; end
79
+ }
80
+
81
+ self.class.class_eval {
82
+ type "() -> Class", typecheck_now: true
83
+ def self.defs_nn() defs_ff(42); end
84
+ }
85
+
86
+ assert_raises(RDL::Typecheck::StaticTypeError) {
87
+ self.class.class_eval {
88
+ type "() -> Class", typecheck_now: true
89
+ def self.defs_other() fdsakjfhds(42); end
90
+ }
91
+ }
92
+ end
93
+
94
+ def test_lits
95
+ assert_equal $__rdl_nil_type, do_tc("nil")
96
+ assert_equal $__rdl_true_type, do_tc("true")
97
+ assert_equal $__rdl_false_type, do_tc("false")
98
+ assert_equal tt("42"), do_tc("42")
99
+ assert do_tc("123456789123456789123456789") <= $__rdl_bignum_type
100
+ assert_equal tt("3.14"), do_tc("3.14")
101
+ assert_equal $__rdl_complex_type, do_tc("1i")
102
+ assert_equal $__rdl_rational_type, do_tc("2.0r")
103
+ assert_equal $__rdl_string_type, do_tc("'42'")
104
+ assert_equal $__rdl_string_type, do_tc("\"42\"")
105
+ assert_equal tt(":foo"), do_tc(":foo")
106
+ end
107
+
108
+ def test_empty
109
+ self.class.class_eval {
110
+ type "() -> nil", typecheck_now: true
111
+ def empty() end
112
+ }
113
+ end
114
+
115
+ def test_dstr_xstr
116
+ # Hard to read if these are inside of strings, so leave like this
117
+ self.class.class_eval {
118
+ type "() -> String", typecheck_now: true
119
+ def dstr() "Foo #{42} Bar #{43}"; end
120
+
121
+ type "() -> String", typecheck_now: true
122
+ def xstr() `ls #{42}`; end
123
+ }
124
+ end
125
+
126
+ def test_seq
127
+ assert_equal $__rdl_string_type, do_tc("_ = 42; _ = 43; 'foo'")
128
+ end
129
+
130
+ def test_dsym
131
+ # Hard to read if these are inside of strings, so leave like this
132
+ self.class.class_eval {
133
+ type "() -> Symbol", typecheck_now: true
134
+ def dsym() :"foo#{42}"; end
135
+ }
136
+ end
137
+
138
+ def test_regexp
139
+ assert_equal $__rdl_regexp_type, do_tc("/foo/")
140
+
141
+ self.class.class_eval {
142
+ # Hard to read if these are inside of strings, so leave like this
143
+ type "() -> Regexp", typecheck_now: true
144
+ def regexp2() /foo#{42}bar#{"baz"}/i; end
145
+ }
146
+ end
147
+
148
+ def test_tuple
149
+ assert_equal tt("[TrueClass, String]"), do_tc("[true, '42']")
150
+ assert_equal tt("[42, String]"), do_tc("[42, '42']")
151
+ end
152
+
153
+ def test_hash
154
+ assert_equal tt("{x: TrueClass, y: FalseClass}"), do_tc("{x: true, y: false}")
155
+ assert_equal tt("Hash<String, 1 or 2>"), do_tc("{'a' => 1, 'b' => 2}")
156
+ assert_equal tt("{1 => String, 2 => String}"), do_tc("{1 => 'a', 2 => 'b'}")
157
+ assert_equal tt("{}"), do_tc("{}")
158
+ end
159
+
160
+ def test_range
161
+ assert_equal tt("Range<Fixnum>"), do_tc("1..5")
162
+ assert_equal tt("Range<Fixnum>"), do_tc("1...5")
163
+ assert_raises(RDL::Typecheck::StaticTypeError) { do_tc("1..'foo'") }
164
+ end
165
+
166
+ def test_self
167
+ # These need to be inside an actual class
168
+ self.class.class_eval {
169
+ type "() -> self", typecheck_now: true
170
+ def self1() self; end
171
+ }
172
+
173
+ self.class.class_eval {
174
+ type "() -> self", typecheck_now: true
175
+ def self2() TestTypecheck.new; end
176
+ }
177
+
178
+ assert_raises(RDL::Typecheck::StaticTypeError) {
179
+ self.class.class_eval {
180
+ type "() -> self", typecheck_now: true
181
+ def self3() Object.new; end
182
+ }
183
+ }
184
+ end
185
+
186
+ def test_nth_back
187
+ assert_equal $__rdl_string_type, do_tc("$4")
188
+ assert_equal $__rdl_string_type, do_tc("$+")
189
+ end
190
+
191
+ def test_const
192
+ assert_equal tt("${String}"), do_tc("String", env: @env)
193
+ assert_equal $__rdl_nil_type, do_tc("NIL", env: @env)
194
+ end
195
+
196
+ def test_defined
197
+ assert_equal $__rdl_string_type, do_tc("defined?(x)")
198
+ end
199
+
200
+ def test_lvar
201
+ self.class.class_eval {
202
+ type "(Fixnum, String) -> Fixnum", typecheck_now: true
203
+ def lvar1(x, y) x; end
204
+ }
205
+
206
+ self.class.class_eval {
207
+ type "(Fixnum, String) -> String", typecheck_now: true
208
+ def lvar2(x, y) y; end
209
+ }
210
+
211
+ assert_raises(RDL::Typecheck::StaticTypeError) {
212
+ # really a send
213
+ self.class.class_eval {
214
+ type "(Fixnum, String) -> String", typecheck_now: true
215
+ def lvar3(x, y) z; end
216
+ }
217
+ }
218
+ end
219
+
220
+ def test_lvasgn
221
+ assert_equal tt("42"), do_tc("x = 42; x")
222
+ assert_equal tt("42"), do_tc("x = 42; y = x; y")
223
+ assert_equal tt("42"), do_tc("x = y = 42; x")
224
+ assert_equal $__rdl_nil_type, do_tc("x = x") # weird behavior - lhs bound to nil always before assignment!
225
+ end
226
+
227
+ def test_lvar_type
228
+ # var_type arg type and formattests
229
+ assert_raises(RDL::Typecheck::StaticTypeError) { do_tc("var_type :x", env: @env) }
230
+ assert_raises(RDL::Typecheck::StaticTypeError) { do_tc("var_type :x, 3", env: @env) }
231
+ assert_raises(RDL::Typecheck::StaticTypeError) { do_tc("var_type 'x', 'Fixnum'", env: @env) }
232
+ assert_raises(RDL::Typecheck::StaticTypeError) { do_tc("var_type :@x, 'Fixnum'", env: @env) }
233
+ assert_raises(RDL::Typecheck::StaticTypeError) { do_tc("var_type :x, 'Fluffy Bunny'", env: @env) }
234
+
235
+ assert_equal $__rdl_fixnum_type, do_tc("var_type :x, 'Fixnum'; x = 3; x", env: @env)
236
+ assert_raises(RDL::Typecheck::StaticTypeError) { do_tc("var_type :x, 'Fixnum'; x = 'three'", env: @env) }
237
+ self.class.class_eval {
238
+ type "(Fixnum) -> nil", typecheck_now: true
239
+ def lvar_type_ff(x) x = 42; nil; end
240
+ }
241
+ assert_raises(RDL::Typecheck::StaticTypeError) {
242
+ self.class.class_eval {
243
+ type "(Fixnum) -> nil", typecheck_now: true
244
+ def lvar_type_ff2(x) x = "forty-two"; nil; end
245
+ }
246
+ }
247
+ end
248
+
249
+ def test_ivar_ivasgn
250
+ self.class.class_eval {
251
+ var_type :@foo, "Fixnum"
252
+ var_type :@@foo, "Fixnum"
253
+ var_type :$test_ivar_ivasgn_global, "Fixnum"
254
+ var_type :@object, "Object"
255
+ }
256
+
257
+ assert_equal $__rdl_fixnum_type, do_tc("@foo", env: @env)
258
+ assert_equal $__rdl_fixnum_type, do_tc("@@foo", env: @env)
259
+ assert_equal $__rdl_fixnum_type, do_tc("$test_ivar_ivasgn_global")
260
+ assert_raises(RDL::Typecheck::StaticTypeError) { do_tc("@bar", env: @env) }
261
+ assert_raises(RDL::Typecheck::StaticTypeError) { do_tc("@bar", env: @env) }
262
+ assert_raises(RDL::Typecheck::StaticTypeError) { do_tc("@@bar", env: @env) }
263
+ assert_raises(RDL::Typecheck::StaticTypeError) { do_tc("$_test_ivar_ivasgn_global_2") }
264
+
265
+ assert_equal @t3, do_tc("@foo = 3", env: @env)
266
+ assert_raises(RDL::Typecheck::StaticTypeError) { do_tc("@foo = 'three'", env: @env) }
267
+ assert_raises(RDL::Typecheck::StaticTypeError) { do_tc("@bar = 'three'", env: @env) }
268
+ assert_equal @t3, do_tc("@@foo = 3", env: @env)
269
+ assert_raises(RDL::Typecheck::StaticTypeError) { do_tc("@@foo = 'three'", env: @env) }
270
+ assert_raises(RDL::Typecheck::StaticTypeError) { do_tc("@@bar = 'three'", env: @env) }
271
+ assert_equal @t3, do_tc("$test_ivar_ivasgn_global = 3")
272
+ assert_raises(RDL::Typecheck::StaticTypeError) { do_tc("$test_ivar_ivasgn_global = 'three'") }
273
+ assert_raises(RDL::Typecheck::StaticTypeError) { do_tc("$test_ivar_ivasgn_global_2 = 'three'") }
274
+ assert_equal @t3, do_tc("@object = 3", env: @env) # type of assignment is type of rhs
275
+ end
276
+
277
+ def test_send_basic
278
+ self.class.class_eval {
279
+ type :_send_basic2, "() -> Fixnum"
280
+ type :_send_basic3, "(Fixnum) -> Fixnum"
281
+ type :_send_basic4, "(Fixnum, String) -> Fixnum"
282
+ type "self._send_basic5", "(Fixnum) -> Fixnum"
283
+ }
284
+
285
+ assert_raises(RDL::Typecheck::StaticTypeError) { do_tc("z", env: @env) }
286
+ assert_equal $__rdl_fixnum_type, do_tc("_send_basic2", env: @env)
287
+ assert_equal $__rdl_fixnum_type, do_tc("_send_basic3(42)", env: @env)
288
+ assert_raises(RDL::Typecheck::StaticTypeError) { assert do_tc("_send_basic3('42')", env: @env) }
289
+ assert_equal $__rdl_fixnum_type, do_tc("_send_basic4(42, '42')", env: @env)
290
+ assert_raises(RDL::Typecheck::StaticTypeError) { assert do_tc("_send_basic4(42, 43)", env: @env) }
291
+ assert_raises(RDL::Typecheck::StaticTypeError) { assert do_tc("_send_basic4('42', '43')", env: @env) }
292
+ assert_equal $__rdl_fixnum_type, do_tc("TestTypecheck._send_basic5(42)", env: @env)
293
+ assert_raises(RDL::Typecheck::StaticTypeError) { do_tc("TestTypecheck._send_basic5('42')", env: @env) }
294
+ assert_equal $__rdl_nil_type, do_tc("puts 42", env: @env)
295
+ end
296
+
297
+ class A
298
+ type :_send_inherit1, "() -> Fixnum"
299
+ end
300
+ class B < A
301
+ end
302
+
303
+ class A1
304
+ type "() -> nil"
305
+ def _send_inherit2; end
306
+ end
307
+ class A2 < A1
308
+ def _send_inherit2; end
309
+ end
310
+ class A3 < A2
311
+ end
312
+
313
+ def test_send_inherit
314
+ assert_equal $__rdl_fixnum_type, do_tc("B.new._send_inherit1", env: @env)
315
+ assert_raises(RDL::Typecheck::StaticTypeError) { do_tc("A3.new._send_inherit2", env: @env) }
316
+ end
317
+
318
+ def test_send_inter
319
+ self.class.class_eval {
320
+ type :_send_inter1, "(Fixnum) -> Fixnum"
321
+ type :_send_inter1, "(String) -> String"
322
+ }
323
+ assert_equal $__rdl_fixnum_type, do_tc("_send_inter1(42)", env: @env)
324
+ assert_equal $__rdl_string_type, do_tc("_send_inter1('42')", env: @env)
325
+
326
+ assert_raises(RDL::Typecheck::StaticTypeError) { do_tc("_send_inter1(:forty_two)", env: @env) }
327
+ end
328
+
329
+ def test_send_opt_varargs
330
+ # from test_type_contract.rb
331
+ self.class.class_eval {
332
+ type :_send_opt_varargs1, "(Fixnum, ?Fixnum) -> Fixnum"
333
+ type :_send_opt_varargs2, "(Fixnum, *Fixnum) -> Fixnum"
334
+ type :_send_opt_varargs3, "(Fixnum, ?Fixnum, ?Fixnum, *Fixnum) -> Fixnum"
335
+ type :_send_opt_varargs4, "(?Fixnum) -> Fixnum"
336
+ type :_send_opt_varargs5, "(*Fixnum) -> Fixnum"
337
+ type :_send_opt_varargs6, "(?Fixnum, String) -> Fixnum"
338
+ type :_send_opt_varargs7, "(Fixnum, *String, Fixnum) -> Fixnum"
339
+ }
340
+ assert_equal $__rdl_fixnum_type, do_tc("_send_opt_varargs1(42)", env: @env)
341
+ assert_equal $__rdl_fixnum_type, do_tc("_send_opt_varargs1(42, 43)", env: @env)
342
+ assert_raises(RDL::Typecheck::StaticTypeError) { assert do_tc("_send_opt_varargs1()", env: @env) }
343
+ assert_raises(RDL::Typecheck::StaticTypeError) { assert do_tc("_send_opt_varargs1(42, 43, 44)", env: @env) }
344
+ assert_equal $__rdl_fixnum_type, do_tc("_send_opt_varargs2(42)", env: @env)
345
+ assert_equal $__rdl_fixnum_type, do_tc("_send_opt_varargs2(42, 43)", env: @env)
346
+ assert_equal $__rdl_fixnum_type, do_tc("_send_opt_varargs2(42, 43, 44)", env: @env)
347
+ assert_equal $__rdl_fixnum_type, do_tc("_send_opt_varargs2(42, 43, 44, 45)", env: @env)
348
+ assert_raises(RDL::Typecheck::StaticTypeError) { assert do_tc("_send_opt_varargs2()", env: @env) }
349
+ assert_raises(RDL::Typecheck::StaticTypeError) { assert do_tc("_send_opt_varargs2('42')", env: @env) }
350
+ assert_raises(RDL::Typecheck::StaticTypeError) { assert do_tc("_send_opt_varargs2(42, '43')", env: @env) }
351
+ assert_raises(RDL::Typecheck::StaticTypeError) { assert do_tc("_send_opt_varargs2(42, 43, '44')", env: @env) }
352
+ assert_raises(RDL::Typecheck::StaticTypeError) { assert do_tc("_send_opt_varargs2(42, 43, 44, '45')", env: @env) }
353
+ assert_equal $__rdl_fixnum_type, do_tc("_send_opt_varargs3(42)", env: @env)
354
+ assert_equal $__rdl_fixnum_type, do_tc("_send_opt_varargs3(42, 43)", env: @env)
355
+ assert_equal $__rdl_fixnum_type, do_tc("_send_opt_varargs3(42, 43, 44)", env: @env)
356
+ assert_equal $__rdl_fixnum_type, do_tc("_send_opt_varargs3(42, 43, 45)", env: @env)
357
+ assert_equal $__rdl_fixnum_type, do_tc("_send_opt_varargs3(42, 43, 46)", env: @env)
358
+ assert_raises(RDL::Typecheck::StaticTypeError) { assert do_tc("_send_opt_varargs3()", env: @env) }
359
+ assert_raises(RDL::Typecheck::StaticTypeError) { assert do_tc("_send_opt_varargs3('42')", env: @env) }
360
+ assert_raises(RDL::Typecheck::StaticTypeError) { assert do_tc("_send_opt_varargs3(42, '43')", env: @env) }
361
+ assert_raises(RDL::Typecheck::StaticTypeError) { assert do_tc("_send_opt_varargs3(42, 43, '44')", env: @env) }
362
+ assert_raises(RDL::Typecheck::StaticTypeError) { assert do_tc("_send_opt_varargs3(42, 43, 44, '45')", env: @env) }
363
+ assert_raises(RDL::Typecheck::StaticTypeError) { assert do_tc("_send_opt_varargs3(42, 43, 44, 45, '46')", env: @env) }
364
+ assert_equal $__rdl_fixnum_type, do_tc("_send_opt_varargs4()", env: @env)
365
+ assert_equal $__rdl_fixnum_type, do_tc("_send_opt_varargs4(42)", env: @env)
366
+ assert_raises(RDL::Typecheck::StaticTypeError) { assert do_tc("_send_opt_varargs4('42')", env: @env) }
367
+ assert_raises(RDL::Typecheck::StaticTypeError) { assert do_tc("_send_opt_varargs4(42, 43)", env: @env) }
368
+ assert_raises(RDL::Typecheck::StaticTypeError) { assert do_tc("_send_opt_varargs4(42, 43, 44)", env: @env) }
369
+ assert_equal $__rdl_fixnum_type, do_tc("_send_opt_varargs5()", env: @env)
370
+ assert_equal $__rdl_fixnum_type, do_tc("_send_opt_varargs5(42)", env: @env)
371
+ assert_equal $__rdl_fixnum_type, do_tc("_send_opt_varargs5(42, 43)", env: @env)
372
+ assert_equal $__rdl_fixnum_type, do_tc("_send_opt_varargs5(42, 43, 44)", env: @env)
373
+ assert_raises(RDL::Typecheck::StaticTypeError) { assert do_tc("_send_opt_varargs5('42')", env: @env) }
374
+ assert_raises(RDL::Typecheck::StaticTypeError) { assert do_tc("_send_opt_varargs5(42, '43')", env: @env) }
375
+ assert_raises(RDL::Typecheck::StaticTypeError) { assert do_tc("_send_opt_varargs5(42, 43, '44')", env: @env) }
376
+ assert_equal $__rdl_fixnum_type, do_tc("_send_opt_varargs6('44')", env: @env)
377
+ assert_equal $__rdl_fixnum_type, do_tc("_send_opt_varargs6(43, '44')", env: @env)
378
+ assert_raises(RDL::Typecheck::StaticTypeError) { assert do_tc("_send_opt_varargs6()", env: @env) }
379
+ assert_raises(RDL::Typecheck::StaticTypeError) { assert do_tc("_send_opt_varargs6(43, '44', 45)", env: @env) }
380
+ assert_equal $__rdl_fixnum_type, do_tc("_send_opt_varargs7(42, 43)", env: @env)
381
+ assert_equal $__rdl_fixnum_type, do_tc("_send_opt_varargs7(42, 'foo', 43)", env: @env)
382
+ assert_equal $__rdl_fixnum_type, do_tc("_send_opt_varargs7(42, 'foo', 'bar', 43)", env: @env)
383
+ assert_raises(RDL::Typecheck::StaticTypeError) { do_tc("_send_opt_varargs7", env: @env) }
384
+ assert_raises(RDL::Typecheck::StaticTypeError) { do_tc("_send_opt_varargs7('42')", env: @env) }
385
+ assert_raises(RDL::Typecheck::StaticTypeError) { do_tc("_send_opt_varargs7(42)", env: @env) }
386
+ assert_raises(RDL::Typecheck::StaticTypeError) { do_tc("_send_opt_varargs7(42, '43')", env: @env) }
387
+ assert_raises(RDL::Typecheck::StaticTypeError) { do_tc("_send_opt_varargs7(42, '43', '44')", env: @env) }
388
+ end
389
+
390
+ def test_send_named_args
391
+ # from test_type_contract.rb
392
+ self.class.class_eval {
393
+ type :_send_named_args1, "(x: Fixnum) -> Fixnum"
394
+ type :_send_named_args2, "(x: Fixnum, y: String) -> Fixnum"
395
+ type :_send_named_args3, "(Fixnum, y: String) -> Fixnum"
396
+ type :_send_named_args4, "(Fixnum, x: Fixnum, y: String) -> Fixnum"
397
+ type :_send_named_args5, "(x: Fixnum, y: ?String) -> Fixnum"
398
+ type :_send_named_args6, "(x: ?Fixnum, y: String) -> Fixnum"
399
+ type :_send_named_args7, "(x: ?Fixnum, y: ?String) -> Fixnum"
400
+ type :_send_named_args8, "(?Fixnum, x: ?Symbol, y: ?String) -> Fixnum"
401
+ }
402
+ assert_equal $__rdl_fixnum_type, do_tc("_send_named_args1(x: 42)", env: @env)
403
+ assert_raises(RDL::Typecheck::StaticTypeError) { assert do_tc("_send_named_args1(x: '42')", env: @env) }
404
+ assert_raises(RDL::Typecheck::StaticTypeError) { assert do_tc("_send_named_args1()", env: @env) }
405
+ assert_raises(RDL::Typecheck::StaticTypeError) { assert do_tc("_send_named_args1(x: 42, y: 42)", env: @env) }
406
+ assert_raises(RDL::Typecheck::StaticTypeError) { assert do_tc("_send_named_args1(y: 42)", env: @env) }
407
+ assert_raises(RDL::Typecheck::StaticTypeError) { assert do_tc("_send_named_args1(42)", env: @env) }
408
+ assert_raises(RDL::Typecheck::StaticTypeError) { assert do_tc("_send_named_args1(42, x: '42')", env: @env) }
409
+ assert_equal $__rdl_fixnum_type, do_tc("_send_named_args2(x: 42, y: '43')", env: @env)
410
+ assert_raises(RDL::Typecheck::StaticTypeError) { assert do_tc("_send_named_args2()", env: @env) }
411
+ assert_raises(RDL::Typecheck::StaticTypeError) { assert do_tc("_send_named_args2(x: 42)", env: @env) }
412
+ assert_raises(RDL::Typecheck::StaticTypeError) { assert do_tc("_send_named_args2(x: '42', y: '43')", env: @env) }
413
+ assert_raises(RDL::Typecheck::StaticTypeError) { assert do_tc("_send_named_args2(42, '43')", env: @env) }
414
+ assert_raises(RDL::Typecheck::StaticTypeError) { assert do_tc("_send_named_args2(42, x: 42, y: '43')", env: @env) }
415
+ assert_raises(RDL::Typecheck::StaticTypeError) { assert do_tc("_send_named_args2(x: 42, y: '43', z: 44)", env: @env) }
416
+ assert_equal $__rdl_fixnum_type, do_tc("_send_named_args3(42, y: '43')", env: @env)
417
+ assert_raises(RDL::Typecheck::StaticTypeError) { assert do_tc("_send_named_args3(42, y: 43)", env: @env) }
418
+ assert_raises(RDL::Typecheck::StaticTypeError) { assert do_tc("_send_named_args3()", env: @env) }
419
+ assert_raises(RDL::Typecheck::StaticTypeError) { assert do_tc("_send_named_args3(42, 43, y: 44)", env: @env) }
420
+ assert_raises(RDL::Typecheck::StaticTypeError) { assert do_tc("_send_named_args3(42, y: 43, z: 44)", env: @env) }
421
+ assert_equal $__rdl_fixnum_type, do_tc("_send_named_args4(42, x: 43, y: '44')", env: @env)
422
+ assert_raises(RDL::Typecheck::StaticTypeError) { assert do_tc("_send_named_args4(42, x: 43)", env: @env) }
423
+ assert_raises(RDL::Typecheck::StaticTypeError) { assert do_tc("_send_named_args4(42, y: '43')", env: @env) }
424
+ assert_raises(RDL::Typecheck::StaticTypeError) { assert do_tc("_send_named_args4()", env: @env) }
425
+ assert_raises(RDL::Typecheck::StaticTypeError) { assert do_tc("_send_named_args4(42, 43, x: 44, y: '45')", env: @env) }
426
+ assert_raises(RDL::Typecheck::StaticTypeError) { assert do_tc("_send_named_args4(42, x: 43, y: '44', z: 45)", env: @env) }
427
+ assert_equal $__rdl_fixnum_type, do_tc("_send_named_args5(x: 42, y: '43')", env: @env)
428
+ assert_equal $__rdl_fixnum_type, do_tc("_send_named_args5(x: 42)", env: @env)
429
+ assert_raises(RDL::Typecheck::StaticTypeError) { assert do_tc("_send_named_args5()", env: @env) }
430
+ assert_raises(RDL::Typecheck::StaticTypeError) { assert do_tc("_send_named_args5(x: 42, y: 43)", env: @env) }
431
+ assert_raises(RDL::Typecheck::StaticTypeError) { assert do_tc("_send_named_args5(x: 42, y: 43, z: 44)", env: @env) }
432
+ assert_raises(RDL::Typecheck::StaticTypeError) { assert do_tc("_send_named_args5(3, x: 42, y: 43)", env: @env) }
433
+ assert_raises(RDL::Typecheck::StaticTypeError) { assert do_tc("_send_named_args5(3, x: 42)", env: @env) }
434
+ assert_equal $__rdl_fixnum_type, do_tc("_send_named_args6(x: 43, y: '44')", env: @env)
435
+ assert_equal $__rdl_fixnum_type, do_tc("_send_named_args6(y: '44')", env: @env)
436
+ assert_raises(RDL::Typecheck::StaticTypeError) { assert do_tc("_send_named_args6()", env: @env) }
437
+ assert_raises(RDL::Typecheck::StaticTypeError) { assert do_tc("_send_named_args6(x: '43', y: '44')", env: @env) }
438
+ assert_raises(RDL::Typecheck::StaticTypeError) { assert do_tc("_send_named_args6(42, x: 43, y: '44')", env: @env) }
439
+ assert_raises(RDL::Typecheck::StaticTypeError) { assert do_tc("_send_named_args6(x: 43, y: '44', z: 45)", env: @env) }
440
+ assert_equal $__rdl_fixnum_type, do_tc("_send_named_args7()", env: @env)
441
+ assert_equal $__rdl_fixnum_type, do_tc("_send_named_args7(x: 43)", env: @env)
442
+ assert_equal $__rdl_fixnum_type, do_tc("_send_named_args7(y: '44')", env: @env)
443
+ assert_equal $__rdl_fixnum_type, do_tc("_send_named_args7(x: 43, y: '44')", env: @env)
444
+ assert_raises(RDL::Typecheck::StaticTypeError) { assert do_tc("_send_named_args7(x: '43', y: '44')", env: @env) }
445
+ assert_raises(RDL::Typecheck::StaticTypeError) { assert do_tc("_send_named_args7(41, x: 43, y: '44')", env: @env) }
446
+ assert_raises(RDL::Typecheck::StaticTypeError) { assert do_tc("_send_named_args7(x: 43, y: '44', z: 45)", env: @env) }
447
+ assert_equal $__rdl_fixnum_type, do_tc("_send_named_args8()", env: @env)
448
+ assert_equal $__rdl_fixnum_type, do_tc("_send_named_args8(43)", env: @env)
449
+ assert_equal $__rdl_fixnum_type, do_tc("_send_named_args8(x: :foo)", env: @env)
450
+ assert_equal $__rdl_fixnum_type, do_tc("_send_named_args8(43, x: :foo)", env: @env)
451
+ assert_equal $__rdl_fixnum_type, do_tc("_send_named_args8(y: 'foo')", env: @env)
452
+ assert_equal $__rdl_fixnum_type, do_tc("_send_named_args8(43, y: 'foo')", env: @env)
453
+ assert_equal $__rdl_fixnum_type, do_tc("_send_named_args8(x: :foo, y: 'foo')", env: @env)
454
+ assert_equal $__rdl_fixnum_type, do_tc("_send_named_args8(43, x: :foo, y: 'foo')", env: @env)
455
+ assert_raises(RDL::Typecheck::StaticTypeError) { assert do_tc("_send_named_args8(43, 44, x: :foo, y: 'foo')", env: @env) }
456
+ assert_raises(RDL::Typecheck::StaticTypeError) { assert do_tc("_send_named_args8(43, x: 'foo', y: 'foo')", env: @env) }
457
+ assert_raises(RDL::Typecheck::StaticTypeError) { assert do_tc("_send_named_args8(43, x: :foo, y: 'foo', z: 44)", env: @env) }
458
+ end
459
+
460
+ def test_send_singleton
461
+ type Fixnum, :_send_singleton, "() -> String"
462
+ assert_equal $__rdl_string_type, do_tc("3._send_singleton", env: @env)
463
+ assert_raises(RDL::Typecheck::StaticTypeError) { do_tc("3._send_singleton_nexists", env: @env) }
464
+ end
465
+
466
+ def test_send_generic
467
+ assert_equal $__rdl_fixnum_type, do_tc("[1,2,3].length", env: @env)
468
+ assert_equal $__rdl_fixnum_type, do_tc("{a:1, b:2}.length", env: @env)
469
+ assert_equal $__rdl_string_type, do_tc("String.new.clone", env: @env)
470
+ # TODO test case with other generic
471
+ end
472
+
473
+ def test_send_alias
474
+ assert_equal $__rdl_fixnum_type, do_tc("[1,2,3].size", env: @env)
475
+ end
476
+
477
+ def test_send_block
478
+ self.class.class_eval {
479
+ type :_send_block1, "(Fixnum) { (Fixnum) -> Fixnum } -> Fixnum"
480
+ type :_send_block2, "(Fixnum) -> Fixnum"
481
+ }
482
+ assert_raises(RDL::Typecheck::StaticTypeError) { do_tc("_send_block1(42)", env: @env) }
483
+ assert_raises(RDL::Typecheck::StaticTypeError) { do_tc("_send_block2(42) { |x| x + 1 }", env: @env) }
484
+ assert_raises(RDL::Typecheck::StaticTypeError) { do_tc("_send_block1(42) { |x, y| x + y }", env: @env) }
485
+ assert_equal $__rdl_fixnum_type, do_tc("_send_block1(42) { |x| x }", env: @env)
486
+ assert_raises(RDL::Typecheck::StaticTypeError) { do_tc("_send_block1(42) { |x| 'forty-two' }", env: @env) }
487
+ assert_raises(RDL::Typecheck::StaticTypeError) { do_tc("x = 1; _send_block1(42) { |y| x }", env: @env) }
488
+ assert_raises(RDL::Typecheck::StaticTypeError) { do_tc("x = 1; _send_block1(42) { |y| x = 2 }", env: @env) }
489
+ assert_raises(RDL::Typecheck::StaticTypeError) { do_tc("x = 1; _send_block1(42) { |y| for x in 1..5 do end }", env: @env) } # odd case...
490
+ end
491
+
492
+ def test_send_union
493
+ assert_equal RDL::Type::UnionType.new(@tfs, $__rdl_bignum_type), do_tc("(if _any_object then Fixnum.new else String.new end) * 2", env: @env)
494
+ assert_raises(RDL::Typecheck::StaticTypeError) { do_tc("(if _any_object then Object.new else Fixnum.new end) + 2", env: @env) }
495
+ end
496
+
497
+ def test_send_splat
498
+ self.class.class_eval {
499
+ type :_send_splat1, "(Fixnum, String, Fixnum, String) -> Fixnum"
500
+ type :_send_splat2, "(String, *Fixnum, Float) -> Fixnum"
501
+ type :_send_splat_fa, "() -> Array<Fixnum>"
502
+ }
503
+ assert_equal $__rdl_fixnum_type, do_tc("x = ['foo', 42]; _send_splat1(1, *x, 'bar')", env: @env)
504
+ assert_equal $__rdl_fixnum_type, do_tc("x = _send_splat_fa; _send_splat2('foo', *x, 3.14)", env: @env)
505
+ assert_raises(RDL::Typecheck::StaticTypeError) { do_tc("x = _send_splat_fa; _send_splat1(*x, 'foo', 2, 'bar')", env: @env) }
506
+ end
507
+
508
+
509
+ def test_yield
510
+ self.class.class_eval {
511
+ type "(Fixnum) { (Fixnum) -> Fixnum } -> Fixnum", typecheck_now: true
512
+ def _yield1(x)
513
+ yield x
514
+ end
515
+ }
516
+
517
+ assert_raises(RDL::Typecheck::StaticTypeError) {
518
+ self.class.class_eval {
519
+ type "(Fixnum) { (Fixnum) -> Fixnum } -> Fixnum", typecheck_now: true
520
+ def _yield2(x)
521
+ yield 'forty-two'
522
+ end
523
+ }
524
+ }
525
+
526
+ assert_raises(RDL::Typecheck::StaticTypeError) {
527
+ self.class.class_eval {
528
+ type "(Fixnum) { (Fixnum) -> String } -> Fixnum", typecheck_now: true
529
+ def _yield3(x)
530
+ yield 42
531
+ end
532
+ }
533
+ }
534
+
535
+ assert_raises(RDL::Typecheck::StaticTypeError) {
536
+ self.class.class_eval {
537
+ type "(Fixnum) -> Fixnum", typecheck_now: true
538
+ def _yield4(x)
539
+ yield 42
540
+ end
541
+ }
542
+ }
543
+
544
+ assert_raises(RDL::Typecheck::StaticTypeError) {
545
+ self.class.class_eval {
546
+ type "(Fixnum) { (Fixnum) { (Fixnum) -> Fixnum } -> Fixnum } -> Fixnum", typecheck_now: true
547
+ def _yield5(x)
548
+ yield 42
549
+ end
550
+ }
551
+ }
552
+ end
553
+
554
+ # class Sup1
555
+ # type '(Fixnum) -> Fixnum', typecheck: true
556
+ # def foo(y)
557
+ # return y
558
+ # end
559
+ # end
560
+ #
561
+ # class Sup2 < Sup1
562
+ # type '(Fixnum) -> Fixnum', typecheck: true
563
+ # def foo(x)
564
+ # super(x+1)
565
+ # end
566
+ # end
567
+ #
568
+ # def test_super
569
+ # assert_equal 43, Sup2.new.foo(42)
570
+ # end
571
+
572
+ def test_new
573
+ assert_equal RDL::Type::NominalType.new(B), do_tc("B.new", env: @env)
574
+ assert_raises(RDL::Typecheck::StaticTypeError) { do_tc("B.new(3)", env: @env) }
575
+ end
576
+
577
+ def test_if
578
+ assert_equal @t3n, do_tc("if _any_object then 3 end", env: @env)
579
+ assert_equal @t3n, do_tc("unless _any_object then 3 end", env: @env)
580
+ assert_equal @t34, do_tc("if _any_object then 3 else 4 end", env: @env)
581
+ assert_equal @t34, do_tc("unless _any_object then 3 else 4 end", env: @env)
582
+ assert_equal @ts3, do_tc("if _any_object then 3 else 'three' end", env: @env)
583
+ assert_equal @ts3, do_tc("unless _any_object then 3 else 'three' end", env: @env)
584
+ assert_equal @t3n, do_tc("3 if _any_object", env: @env)
585
+ assert_equal @t3n, do_tc("3 unless _any_object", env: @env)
586
+ assert_equal @t3, do_tc("if true then 3 else 'three' end", env: @env)
587
+ assert_equal @t3, do_tc("if :foo then 3 else 'three' end", env: @env)
588
+ assert_equal $__rdl_string_type, do_tc("if false then 3 else 'three' end", env: @env)
589
+ assert_equal $__rdl_string_type, do_tc("if nil then 3 else 'three' end", env: @env)
590
+
591
+ assert_equal @t45, do_tc("x = 'three'; if _any_object then x = 4 else x = 5 end; x", env: @env)
592
+ assert_equal @ts3, do_tc("x = 'three'; if _any_object then x = 3 end; x", env: @env)
593
+ assert_equal @ts3, do_tc("x = 'three'; unless _any_object then x = 3 end; x", env: @env)
594
+ assert_equal @t4n, do_tc("if _any_object then y = 4 end; y", env: @env) # vars are nil if not defined on branch
595
+ assert_equal @t35, do_tc("if _any_object then x = 3; y = 4 else x = 5 end; x", env: @env)
596
+ assert_equal @t4n, do_tc("if _any_object then x = 3; y = 4 else x = 5 end; y", env: @env)
597
+ end
598
+
599
+ def test_and_or
600
+ assert_equal @ts3, do_tc("'foo' and 3")
601
+ assert_equal @ts3, do_tc("'foo' && 3")
602
+ assert_equal $__rdl_string_type, do_tc("3 and 'foo'")
603
+ assert_equal $__rdl_nil_type, do_tc("nil and 'foo'")
604
+ assert_equal $__rdl_false_type, do_tc("false and 'foo'")
605
+ assert_equal @ts3, do_tc("(x = 'foo') and (x = 3); x")
606
+ assert_equal $__rdl_string_type, do_tc("(x = 3) and (x = 'foo'); x")
607
+ assert_equal $__rdl_nil_type, do_tc("(x = nil) and (x = 'foo'); x")
608
+ assert_equal $__rdl_false_type, do_tc("(x = false) and (x = 'foo'); x")
609
+
610
+ assert_equal @ts3, do_tc("'foo' or 3")
611
+ assert_equal @ts3, do_tc("'foo' || 3")
612
+ assert_equal @t3, do_tc("3 or 'foo'")
613
+ assert_equal @t3, do_tc("nil or 3")
614
+ assert_equal @t3, do_tc("false or 3")
615
+ assert_equal @ts3, do_tc("(x = 'foo') or (x = 3); x")
616
+ assert_equal @t3, do_tc("(x = 3) or (x = 'foo'); x")
617
+ assert_equal @t3, do_tc("(x = nil) or (x = 3); x")
618
+ assert_equal @t3, do_tc("(x = false) or (x = 3); x")
619
+ end
620
+
621
+ class C
622
+ type :===, "(Object) -> %bool"
623
+ end
624
+
625
+ class D
626
+ type :===, "(String) -> %bool"
627
+ end
628
+
629
+ def test_when
630
+ assert_equal @t3, do_tc("case when C.new then 3 end", env: @env)
631
+ assert_equal @t34, do_tc("x = 4; case when _any_object then x = 3 end; x", env: @env)
632
+ assert_equal @ts3, do_tc("case when _any_object then 3 else 'foo' end", env: @env)
633
+ assert_equal @ts3, do_tc("x = 4; case when _any_object then x = 3 else x = 'foo' end; x", env: @env)
634
+
635
+ assert_equal $__rdl_string_type, do_tc("case _any_object when C.new then 'foo' end", env: @env)
636
+ assert_equal @ts3, do_tc("x = 3; case _any_object when C.new then x = 'foo' end; x", env: @env)
637
+ assert_raises(RDL::Typecheck::StaticTypeError) { do_tc("case _any_object when D.new then 'foo' end", env: @env) }
638
+ assert_equal @ts3, do_tc("case _any_object when C.new then 'foo' else 3 end", env: @env)
639
+ assert_equal @ts3, do_tc("x = 4; case _any_object when C.new then x = 'foo' else x = 3 end; x", env: @env)
640
+ assert_equal @ts34, do_tc("case _any_object when C.new then 'foo' when C.new then 4 else 3 end", env: @env)
641
+ assert_equal @ts34, do_tc("x = 5; case _any_object when C.new then x = 'foo' when C.new then x = 4 else x = 3 end; x", env: @env)
642
+
643
+ assert_equal @t3, do_tc("case when (x = 3) then 'foo' end; x", env: @env)
644
+ assert_equal @t34, do_tc("case when (x = 3), (x = 4) then 'foo' end; x", env: @env)
645
+ assert_equal @t34, do_tc("case when (x = 3), (x = 4) then 'foo' end; x", env: @env)
646
+ assert_equal @t34, do_tc("case when (x = 4) then x = 3 end; x", env: @env)
647
+ assert_equal @t34, do_tc("x = 5; case when (x = 3) then 'foo' when (x = 4) then 'foo' end; x", env: @env) # first guard always executed!
648
+ assert_equal @t345, do_tc("x = 6; case when (x = 3) then 'foo' when (x = 4) then 'foo' else x = 5 end; x", env: @env)
649
+ end
650
+
651
+ def test_while_until
652
+ # TODO these don't do a great job checking control flow
653
+ assert_equal $__rdl_nil_type, do_tc("while true do end")
654
+ assert_equal $__rdl_nil_type, do_tc("until false do end")
655
+ assert_equal $__rdl_nil_type, do_tc("begin end while true")
656
+ assert_equal $__rdl_nil_type, do_tc("begin end until false")
657
+ assert_equal $__rdl_integer_type, do_tc("i = 0; while i < 5 do i = 1 + i end; i")
658
+ assert_equal $__rdl_integer_type, do_tc("i = 0; while i < 5 do i = i + 1 end; i")
659
+ assert_equal $__rdl_integer_type, do_tc("i = 0; until i >= 5 do i = 1 + i end; i")
660
+ assert_equal $__rdl_integer_type, do_tc("i = 0; until i >= 5 do i = i + 1 end; i")
661
+ assert_equal $__rdl_integer_type, do_tc("i = 0; begin i = 1 + i end while i < 5; i")
662
+ assert_equal $__rdl_integer_type, do_tc("i = 0; begin i = i + 1 end while i < 5; i")
663
+ assert_equal $__rdl_integer_type, do_tc("i = 0; begin i = 1 + i end until i >= 5; i")
664
+ assert_equal $__rdl_integer_type, do_tc("i = 0; begin i = i + 1 end until i >= 5; i")
665
+
666
+ # break, redo, next, no args
667
+ assert_equal $__rdl_integer_type, do_tc("i = 0; while i < 5 do if i > 2 then break end; i = 1 + i end; i")
668
+ assert_equal tt("0"), do_tc("i = 0; while i < 5 do break end; i")
669
+ assert_equal tt("0"), do_tc("i = 0; while i < 5 do redo end; i") # infinite loop, ok for typing
670
+ assert_equal tt("0"), do_tc("i = 0; while i < 5 do next end; i") # infinite loop, ok for typing
671
+ assert_raises(RDL::Typecheck::StaticTypeError) { do_tc("i = 0; while i < 5 do retry end; i") }
672
+ assert_equal $__rdl_integer_type, do_tc("i = 0; begin i = i + 1; break if i > 2; end while i < 5; i")
673
+ assert_equal $__rdl_integer_type, do_tc("i = 0; begin i = i + 1; redo if i > 2; end while i < 5; i")
674
+ assert_equal $__rdl_integer_type, do_tc("i = 0; begin i = i + 1; next if i > 2; end while i < 5; i")
675
+ assert_raises(RDL::Typecheck::StaticTypeError) { do_tc("i = 0; begin i = i + 1; retry if i > 2; end while i < 5; i") }
676
+
677
+ # break w/arg, next can't take arg
678
+ assert_equal @t3n, do_tc("while _any_object do break 3 end", env: @env)
679
+ assert_raises(RDL::Typecheck::StaticTypeError) { do_tc("while _any_object do next 3 end", env: @env) }
680
+ assert_equal @t3n, do_tc("begin break 3 end while _any_object", env: @env)
681
+ assert_raises(RDL::Typecheck::StaticTypeError) { do_tc("begin next 3 end while _any_object", env: @env) }
682
+ end
683
+
684
+ def test_for
685
+ assert_equal $__rdl_fixnum_type, do_tc("for i in 1..5 do end; i")
686
+ assert_equal tt("1 or 2 or 3 or 4 or 5"), do_tc("for i in [1,2,3,4,5] do end; i")
687
+ assert_equal tt("Range<Fixnum>"), do_tc("for i in 1..5 do break end", env: @env)
688
+ assert_equal tt("Range<Fixnum>"), do_tc("for i in 1..5 do next end", env: @env)
689
+ assert_equal tt("Range<Fixnum>"), do_tc("for i in 1..5 do redo end", env: @env) #infinite loop, ok for typing
690
+ assert_equal tt("Range<Fixnum> or 3"), do_tc("for i in 1..5 do break 3 end", env: @env)
691
+ assert_equal @tfs, do_tc("for i in 1..5 do next 'three' end; i", env: @env)
692
+ end
693
+
694
+ def test_return
695
+ assert self.class.class_eval {
696
+ type "(Fixnum) -> Fixnum", typecheck_now: true
697
+ def return_ff(x)
698
+ return 42
699
+ end
700
+ }
701
+
702
+ assert_raises(RDL::Typecheck::StaticTypeError) {
703
+ self.class.class_eval {
704
+ type "(Fixnum) -> Fixnum", typecheck_now: true
705
+ def return_ff2(x)
706
+ return "forty-two"
707
+ end
708
+ }
709
+ }
710
+
711
+ assert_equal $__rdl_bot_type, do_tc("return 42", scope: @scopefs)
712
+ assert_equal $__rdl_bot_type, do_tc("if _any_object then return 42 else return 'forty-two' end", env: @env, scope: @scopefs)
713
+ assert_raises(RDL::Typecheck::StaticTypeError) { do_tc("if _any_object then return 42 else return 'forty-two' end", env: @env, scope: @scopef) }
714
+ assert_equal $__rdl_string_type, do_tc("return 42 if _any_object; 'forty-two'", env: @env, scope: @scopef)
715
+ assert_raises(RDL::Typecheck::StaticTypeError) { do_tc("return 'forty-two' if _any_object; 42", env: @env, scope: @scopef) }
716
+ end
717
+
718
+ class E
719
+ type :f, '() -> %integer'
720
+ type :f=, '(%integer) -> nil'
721
+ end
722
+
723
+ def test_op_asgn
724
+ assert $__rdl_integer_type, do_tc("x = 0; x += 1")
725
+ assert_raises(RDL::Typecheck::StaticTypeError) { do_tc("x += 1") }
726
+ assert_raises(RDL::Typecheck::StaticTypeError) { do_tc("x = Object.new; x += 1", env: @env) }
727
+ assert_equal $__rdl_nil_type, do_tc("e = E.new; e.f += 1", env: @env) # return type of f=
728
+ assert_equal $__rdl_false_type, do_tc("x &= false") # weird
729
+ end
730
+
731
+ def test_and_or_asgn
732
+ self.class.class_eval {
733
+ var_type :@f_and_or_asgn, "Fixnum"
734
+ }
735
+ assert_equal @t3, do_tc("x ||= 3") # weird
736
+ assert_equal $__rdl_nil_type, do_tc("x &&= 3") # weirder
737
+ assert_equal $__rdl_fixnum_type, do_tc("@f_and_or_asgn &&= 4", env: @env)
738
+ assert_equal @t3, do_tc("x = 3; x ||= 'three'")
739
+ assert_equal @ts3, do_tc("x = 'three'; x ||= 3")
740
+ assert_equal $__rdl_nil_type, do_tc("e = E.new; e.f ||= 3", env: @env) # return type of f=
741
+ assert_equal $__rdl_nil_type, do_tc("e = E.new; e.f &&= 3", env: @env) # return type of f=
742
+ end
743
+
744
+ def test_masgn
745
+ self.class.class_eval {
746
+ var_type :@f_masgn, "Array<Fixnum>"
747
+ }
748
+ assert_raises(RDL::Typecheck::StaticTypeError) { do_tc("x, y = 3") } # allowed in Ruby but probably has surprising behavior
749
+ assert_equal tt("Array<Fixnum>"), do_tc("a, b = @f_masgn", env: @env)
750
+ assert_equal $__rdl_fixnum_type, do_tc("a, b = @f_masgn; a", env: @env)
751
+ assert_equal $__rdl_fixnum_type, do_tc("a, b = @f_masgn; b", env: @env)
752
+ assert_raises(RDL::Typecheck::StaticTypeError) { do_tc("var_type :a, 'String'; a, b = @f_masgn", env: @env) }
753
+ assert_raises(RDL::Typecheck::StaticTypeError) { do_tc("a, b = 1, 2, 3") }
754
+ assert_equal @t3, do_tc("a, b = 3, 'two'; a")
755
+ assert_equal $__rdl_string_type, do_tc("a, b = 3, 'two'; b")
756
+ assert_equal @t3, do_tc("a = [3, 'two']; x, y = a; x")
757
+ assert_equal $__rdl_string_type, do_tc("a = [3, 'two']; x, y = a; y")
758
+ assert_raises(RDL::Typecheck::StaticTypeError) { do_tc("a = [3, 'two']; x, y = a; a.length", env: @env) }
759
+
760
+ # w/send
761
+ assert_equal tt("2"), do_tc("e = E.new; e.f, b = 1, 2; b", env: @env)
762
+ assert_equal $__rdl_fixnum_type, do_tc("e = E.new; e.f, b = @f_masgn; b", env: @env)
763
+
764
+ # w/splat
765
+ assert_equal tt("[1, 2, 3]"), do_tc("*x = [1, 2, 3]")
766
+ assert_raises(RDL::Typecheck::StaticTypeError) { do_tc("*x = 1") } # allowed in Ruby, but why would you write this code?
767
+
768
+ # w/splat on right
769
+ assert_equal tt("1"), do_tc("x, *y = [1, 2, 3]; x")
770
+ assert_equal tt("[2, 3]"), do_tc("x, *y = [1, 2, 3]; y")
771
+ assert_equal tt("1"), do_tc("x, *y = [1]; x")
772
+ assert_equal tt("[]"), do_tc("x, *y = [1]; y")
773
+ assert_raises(RDL::Typecheck::StaticTypeError) { do_tc("x, *y = 1") } # allowed in Ruby, but hard to justify, so RDL error
774
+ assert_equal $__rdl_fixnum_type, do_tc("x, *y = @f_masgn; x", env: @env)
775
+ assert_equal tt("Array<Fixnum>"), do_tc("x, *y = @f_masgn; y", env: @env)
776
+ assert_raises(RDL::Typecheck::StaticTypeError) { do_tc("x, y, *z = [1]") } # works in Ruby, but confusing so RDL reports error
777
+
778
+ # w/splat on left
779
+ assert_equal tt("[1, 2]"), do_tc("*x, y = [1, 2, 3]; x")
780
+ assert_equal tt("3"), do_tc("*x, y = [1, 2, 3]; y")
781
+ assert_equal tt("[]"), do_tc("*x, y = [1]; x")
782
+ assert_equal tt("1"), do_tc("*x, y = [1]; y")
783
+ assert_raises(RDL::Typecheck::StaticTypeError) { do_tc("*x, y = 1") } # as above
784
+ assert_equal tt("Array<Fixnum>"), do_tc("*x, y = @f_masgn; x", env: @env)
785
+ assert_equal $__rdl_fixnum_type, do_tc("*x, y = @f_masgn; y", env: @env)
786
+ assert_raises(RDL::Typecheck::StaticTypeError) { do_tc("*x, y, z = [1]") } # as above
787
+
788
+ # w/splat in middle
789
+ assert_equal tt("1"), do_tc("x, *y, z = [1, 2]; x")
790
+ assert_equal tt("[]"), do_tc("x, *y, z = [1, 2]; y")
791
+ assert_equal tt("2"), do_tc("x, *y, z = [1, 2]; z")
792
+ assert_equal tt("1"), do_tc("x, *y, z = [1, 2, 3, 4]; x")
793
+ assert_equal tt("[2, 3]"), do_tc("x, *y, z = [1, 2, 3, 4]; y")
794
+ assert_equal tt("4"), do_tc("x, *y, z = [1, 2, 3, 4]; z")
795
+ assert_raises(RDL::Typecheck::StaticTypeError) { do_tc("x, *y, z = 1") } # as above
796
+ assert_equal $__rdl_fixnum_type, do_tc("x, *y, z = @f_masgn; x", env: @env)
797
+ assert_equal tt("Array<Fixnum>"), do_tc("x, *y, z = @f_masgn; y", env: @env)
798
+ assert_equal $__rdl_fixnum_type, do_tc("x, *y, z = @f_masgn; z", env: @env)
799
+ end
800
+
801
+ def test_cast
802
+ assert_equal $__rdl_fixnum_type, do_tc("(1 + 2).type_cast('Fixnum')", env: @env)
803
+ assert_raises(RDL::Typecheck::StaticTypeError) { do_tc("1.type_cast('Fixnum', 42)", env: @env) }
804
+ assert_raises(RDL::Typecheck::StaticTypeError) { do_tc("1.type_cast(Fixnum)", env: @env) }
805
+ assert_equal $__rdl_fixnum_type, do_tc("(1 + 2).type_cast('Fixnum', force: true)", env: @env)
806
+ assert_equal $__rdl_fixnum_type, do_tc("(1 + 2).type_cast('Fixnum', force: false)", env: @env)
807
+ assert_equal $__rdl_fixnum_type, do_tc("(1 + 2).type_cast('Fixnum', force: :blah)", env: @env)
808
+ assert_raises(RDL::Typecheck::StaticTypeError) { do_tc("(1 + 2).type_cast('Fixnum', forc: true)", env: @env) }
809
+ assert_raises(RDL::Typecheck::StaticTypeError) { do_tc("(1 + 2).type_cast('Fluffy Bunny')") }
810
+ end
811
+
812
+ def test_rescue_ensure
813
+ assert_equal @t3, do_tc("begin 3; rescue; 4; end") # rescue clause can never be executed
814
+ assert_equal @t34, do_tc("begin puts 'foo'; 3; rescue; 4; end", env: @env)
815
+ assert_equal tt("StandardError or 3"), do_tc("begin puts 'foo'; 3; rescue => e; e; end", env: @env)
816
+ assert_equal tt("RuntimeError or 3"), do_tc("begin puts 'foo'; 3; rescue RuntimeError => e; e; end", env: @env)
817
+ assert_equal tt("3"), do_tc("begin puts 'foo'; 3; else; 4; end", env: @env) # parser discards else clause!
818
+ assert_equal tt("RuntimeError or ArgumentError or 3"), do_tc("begin puts 'foo'; 3; rescue RuntimeError => e; e; rescue ArgumentError => x; x; end", env: @env)
819
+ assert_equal tt("RuntimeError or ArgumentError or 42 or 3"), do_tc("begin puts 'foo'; 3; rescue RuntimeError => e; e; rescue ArgumentError => x; x; else 42; end", env: @env)
820
+ assert_equal tt("RuntimeError or ArgumentError or 3"), do_tc("begin puts 'foo'; 3; rescue RuntimeError, ArgumentError => e; e; end", env: @env)
821
+ assert_equal tt("1 or String"), do_tc("tries = 0; begin puts 'foo'; x = 1; rescue; tries = tries + 1; retry unless tries > 5; x = 'one'; end; x", env: @env)
822
+ assert_equal @t3, do_tc("begin 3; ensure 4; end", env: @env)
823
+ assert_equal @t4, do_tc("begin x = 3; ensure x = 4; end; x", env: @env)
824
+ assert_equal @t5, do_tc("begin puts 'foo'; x = 3; rescue; x = 4; ensure x = 5; end; x", env: @env)
825
+ assert_equal @t34, do_tc("begin puts 'foo'; 3; rescue; 4; ensure 5; end", env: @env)
826
+ end
827
+
828
+ class SubArray < Array
829
+ end
830
+
831
+ class SubHash < Hash
832
+ end
833
+
834
+ def test_array_splat
835
+ self.class.class_eval {
836
+ type :_splataf, "() -> Array<Fixnum>"
837
+ type :_splatas, "() -> Array<String>"
838
+ type :_splathsf, "() -> Hash<Symbol, Fixnum>"
839
+ }
840
+ assert_equal tt("[1]"), do_tc("x = *1")
841
+ assert_equal tt("[1, 2, 3]"), do_tc("x = [1, *2, 3]")
842
+ assert_raises(RDL::Typecheck::StaticTypeError) { do_tc("x = [1, *Object.new, 3]", env: @env) } # the Object might or might not be an array...
843
+ assert_raises(RDL::Typecheck::StaticTypeError) { do_tc("x = [1, *SubArray.new, 3]", env: @env) } # the SubArray is an Array, but unclear how to splat
844
+ assert_equal tt("[1]"), do_tc("x = *[1]")
845
+ assert_equal tt("[1, 2, 3]"), do_tc("x = *[1, 2, 3]")
846
+ assert_equal tt("[1, 2, 3]"), do_tc("x = [1, *[2], 3]")
847
+ assert_equal tt("[1, 2, 3, 4]"), do_tc("x = [1, *[2, 3], 4]")
848
+ assert_equal tt("[1, 2, 3, 4]"), do_tc("x = [1, *[2, *[3]], 4]")
849
+ assert_equal tt("[1, [2, 3], 4]"), do_tc("x = [1, [2, *[3]], 4]")
850
+ assert_equal tt("[1, 2, 3, 4]"), do_tc("x = [*[1,2], *[3,4]]")
851
+ assert_equal tt("[]"), do_tc("x = *nil")
852
+ assert_equal tt("[1, 2]"), do_tc("x = [1, *nil, 2]")
853
+ assert_equal tt("[[:a, 1]]"), do_tc("x = *{a: 1}")
854
+ assert_raises(RDL::Typecheck::StaticTypeError) { do_tc("x = [1, *SubHash.new, 3]", env: @env) } # the SubHash is an Hash, but unclear how to splat
855
+ assert_equal tt("[[:a, 1], [:b, 2], [:c, 3]]"), do_tc("x = *{a: 1, b: 2, c: 3}")
856
+ assert_equal tt("[1, [:a, 2], 3]"), do_tc("x = [1, *{a: 2}, 3]")
857
+ assert_equal tt("[1, 2, 3]"), do_tc("y = [2]; x = [1, *y, 3]; ")
858
+ assert_raises(RDL::Typecheck::StaticTypeError) { do_tc("y = [2]; x = [1, *y, 3]; y.length") }
859
+ assert_equal tt("[1, [:a, 2], 3]"), do_tc("y = {a: 2}; x = [1, *y, 3]")
860
+ assert_raises(RDL::Typecheck::StaticTypeError) { do_tc("y = {a: 2}; x = [1, *y, 3]; y.length") }
861
+
862
+ assert_equal tt("Array<Fixnum>"), do_tc("x = *_splataf", env: @env)
863
+ assert_equal tt("Array<Fixnum>"), do_tc("x = [1, *_splataf, 2]", env: @env)
864
+ assert_equal tt("Array<Fixnum>"), do_tc("x = [*_splataf, *_splataf]", env: @env)
865
+ assert_equal tt("Array<Fixnum or String>"), do_tc("x = [*_splataf, *_splatas]", env: @env)
866
+ assert_equal tt("Array<Fixnum or String>"), do_tc("x = [1, *_splataf, 2, *_splatas, 3]", env: @env)
867
+ assert_equal tt("Array<Fixnum or String or 3.0>"), do_tc("x = [1, *_splataf, 2, *_splatas, 3.0]", env: @env)
868
+ assert_equal tt("Array<[Symbol, Fixnum]>"), do_tc("x = *_splathsf", env: @env)
869
+ assert_equal tt("Array<1 or 3 or [Symbol, Fixnum]>"), do_tc("x = [1, *_splathsf, 3]", env: @env)
870
+ end
871
+
872
+ def test_hash_kwsplat
873
+ self.class.class_eval {
874
+ type :_kwsplathsf, "() -> Hash<Symbol, Fixnum>"
875
+ type :_kwsplathos, "() -> Hash<Float, String>"
876
+ }
877
+ assert_equal tt("{a: 1, b: 2}"), do_tc("x = {a: 1, **{b: 2}}")
878
+ assert_equal tt("{a: 1}"), do_tc("x = {a: 1, **{}}")
879
+ assert_equal tt("{a: 1, b: 2, c: 3}"), do_tc("x = {a: 1, **{b: 2}, c: 3}")
880
+ assert_equal tt("{a: 1, b: 2, c: 3}"), do_tc("x = {a: 1, **{b: 2}, **{c: 3}}")
881
+ assert_equal tt("{a: 1, b: 2, c: 3}"), do_tc("x = {a: 1, **{b: 2, c: 3}}")
882
+ assert_equal tt("{a: 1, b: 2, c: 3}"), do_tc("x = {**{a: 1}, b: 2, **{c: 3}}")
883
+ assert_raises(RDL::Typecheck::StaticTypeError) { do_tc("x = {a: 1, **Object.new}", env: @env) } # may or may not be hash
884
+ assert_raises(RDL::Typecheck::StaticTypeError) { do_tc("x = {a: 1, **SubHash.new}", env: @env) } # is a how, but unclear how to splat
885
+ assert_raises(RDL::Typecheck::StaticTypeError) { do_tc("y = {b: 2}; x = {a: 1, **y}; y.length") }
886
+
887
+ assert_equal tt("Hash<Symbol, Fixnum>"), do_tc("x = {**_kwsplathsf}", env: @env)
888
+ assert_equal tt("Hash<Symbol or Float, Fixnum or String>"), do_tc("x = {**_kwsplathsf, **_kwsplathos}", env: @env)
889
+ assert_equal tt("Hash<Symbol, Fixnum>"), do_tc("x = {a: 1, **_kwsplathsf, b: 2}", env: @env)
890
+ assert_equal tt("Hash<Symbol or String, Fixnum or String>"), do_tc("x = {'a' => 1, **_kwsplathsf, b: 'two'}", env: @env)
891
+ end
892
+
893
+ end