rdl 1.1.1 → 2.0.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
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