rdl 2.1.0 → 2.2.0

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 (102) hide show
  1. checksums.yaml +5 -5
  2. data/.gitignore +1 -0
  3. data/.travis.yml +7 -6
  4. data/CHANGES.md +29 -0
  5. data/README.md +94 -26
  6. data/lib/rdl/boot.rb +82 -41
  7. data/lib/rdl/boot_rails.rb +5 -0
  8. data/lib/rdl/config.rb +9 -1
  9. data/lib/rdl/query.rb +2 -2
  10. data/lib/rdl/typecheck.rb +972 -225
  11. data/lib/rdl/types/annotated_arg.rb +8 -0
  12. data/lib/rdl/types/ast_node.rb +73 -0
  13. data/lib/rdl/types/bot.rb +8 -0
  14. data/lib/rdl/types/bound_arg.rb +63 -0
  15. data/lib/rdl/types/computed.rb +48 -0
  16. data/lib/rdl/types/dependent_arg.rb +9 -0
  17. data/lib/rdl/types/dynamic.rb +61 -0
  18. data/lib/rdl/types/finite_hash.rb +54 -9
  19. data/lib/rdl/types/generic.rb +33 -0
  20. data/lib/rdl/types/intersection.rb +8 -0
  21. data/lib/rdl/types/lexer.rex +6 -1
  22. data/lib/rdl/types/lexer.rex.rb +13 -1
  23. data/lib/rdl/types/method.rb +14 -0
  24. data/lib/rdl/types/nominal.rb +8 -0
  25. data/lib/rdl/types/non_null.rb +8 -0
  26. data/lib/rdl/types/optional.rb +8 -0
  27. data/lib/rdl/types/parser.racc +31 -5
  28. data/lib/rdl/types/parser.tab.rb +540 -302
  29. data/lib/rdl/types/rdl_types.rb +45 -0
  30. data/lib/rdl/types/singleton.rb +14 -1
  31. data/lib/rdl/types/string.rb +104 -0
  32. data/lib/rdl/types/structural.rb +8 -0
  33. data/lib/rdl/types/top.rb +8 -0
  34. data/lib/rdl/types/tuple.rb +32 -8
  35. data/lib/rdl/types/type.rb +54 -11
  36. data/lib/rdl/types/union.rb +41 -2
  37. data/lib/rdl/types/var.rb +10 -0
  38. data/lib/rdl/types/vararg.rb +8 -0
  39. data/lib/rdl/util.rb +13 -10
  40. data/lib/rdl/wrap.rb +271 -27
  41. data/lib/rdl_disable.rb +16 -2
  42. data/lib/types/active_record.rb +1 -0
  43. data/lib/types/core/array.rb +442 -23
  44. data/lib/types/core/basic_object.rb +3 -3
  45. data/lib/types/core/bigdecimal.rb +5 -0
  46. data/lib/types/core/class.rb +2 -0
  47. data/lib/types/core/dir.rb +3 -3
  48. data/lib/types/core/enumerable.rb +4 -4
  49. data/lib/types/core/enumerator.rb +1 -1
  50. data/lib/types/core/file.rb +4 -4
  51. data/lib/types/core/float.rb +203 -0
  52. data/lib/types/core/hash.rb +390 -15
  53. data/lib/types/core/integer.rb +223 -10
  54. data/lib/types/core/io.rb +2 -2
  55. data/lib/types/core/kernel.rb +8 -5
  56. data/lib/types/core/marshal.rb +3 -0
  57. data/lib/types/core/module.rb +3 -3
  58. data/lib/types/core/numeric.rb +0 -2
  59. data/lib/types/core/object.rb +5 -5
  60. data/lib/types/core/pathname.rb +2 -2
  61. data/lib/types/core/process.rb +1 -3
  62. data/lib/types/core/range.rb +1 -1
  63. data/lib/types/core/regexp.rb +2 -2
  64. data/lib/types/core/set.rb +1 -1
  65. data/lib/types/core/string.rb +408 -16
  66. data/lib/types/core/symbol.rb +3 -3
  67. data/lib/types/core/time.rb +1 -1
  68. data/lib/types/core/uri.rb +13 -13
  69. data/lib/types/rails/_helpers.rb +7 -1
  70. data/lib/types/rails/action_controller/mime_responds.rb +2 -0
  71. data/lib/types/rails/active_record/associations.rb +42 -30
  72. data/lib/types/rails/active_record/comp_types.rb +637 -0
  73. data/lib/types/rails/active_record/finder_methods.rb +1 -1
  74. data/lib/types/rails/active_record/model_schema.rb +28 -16
  75. data/lib/types/rails/active_record/relation.rb +5 -3
  76. data/lib/types/rails/active_record/sql-strings.rb +166 -0
  77. data/lib/types/rails/string.rb +1 -1
  78. data/lib/types/sequel.rb +1 -0
  79. data/lib/types/sequel/comp_types.rb +581 -0
  80. data/rdl.gemspec +5 -4
  81. data/test/test_alias.rb +4 -0
  82. data/test/test_array_types.rb +244 -0
  83. data/test/test_bound_types.rb +80 -0
  84. data/test/test_contract.rb +4 -0
  85. data/test/test_dsl.rb +5 -0
  86. data/test/test_dyn_comptype_checks.rb +206 -0
  87. data/test/test_generic.rb +21 -20
  88. data/test/test_hash_types.rb +322 -0
  89. data/test/test_intersection.rb +1 -0
  90. data/test/test_le.rb +29 -4
  91. data/test/test_member.rb +3 -1
  92. data/test/test_parser.rb +5 -0
  93. data/test/test_query.rb +1 -0
  94. data/test/test_rdl.rb +63 -28
  95. data/test/test_rdl_type.rb +4 -0
  96. data/test/test_string_types.rb +102 -0
  97. data/test/test_type_contract.rb +59 -37
  98. data/test/test_typecheck.rb +480 -75
  99. data/test/test_types.rb +17 -0
  100. data/test/test_wrap.rb +5 -0
  101. metadata +35 -5
  102. data/lib/types/rails/active_record/schema_types.rb +0 -51
@@ -1,6 +1,7 @@
1
1
  require 'minitest/autorun'
2
2
  $LOAD_PATH << File.dirname(__FILE__) + "/../lib"
3
3
  require 'rdl'
4
+ RDL.reset
4
5
 
5
6
  class TestMember < Minitest::Test
6
7
  include RDL::Type
@@ -15,6 +16,7 @@ class TestMember < Minitest::Test
15
16
  end
16
17
 
17
18
  def setup
19
+ RDL.reset
18
20
  @tbasicobject = NominalType.new "BasicObject"
19
21
  @tsymfoo = SingletonType.new :foo
20
22
  @tarraystring = GenericType.new(RDL::Globals.types[:array], RDL::Globals.types[:string])
@@ -84,7 +86,7 @@ class TestMember < Minitest::Test
84
86
  assert (@tsymfoo.member? :foo)
85
87
  assert (not (@tsymfoo.member? :bar))
86
88
  assert (not (@tsymfoo.member? "foo"))
87
- assert (not(@tsymfoo.member? nil)) # nil no longer subtype of other singletons
89
+ #assert (not(@tsymfoo.member? nil)) # nil no longer subtype of other singletons
88
90
  end
89
91
 
90
92
  def test_union_intersection
@@ -10,6 +10,7 @@ class TestParser < Minitest::Test
10
10
  class C; end
11
11
 
12
12
  def setup
13
+ RDL.reset
13
14
  @tintegeropt = OptionalType.new RDL::Globals.types[:integer]
14
15
  @tintegervararg = VarargType.new RDL::Globals.types[:integer]
15
16
  @tstringopt = OptionalType.new RDL::Globals.types[:string]
@@ -170,6 +171,10 @@ class TestParser < Minitest::Test
170
171
  tm1 = MethodType.new [], nil, RDL::Globals.types[:string]
171
172
  ts1 = StructuralType.new(to_str: tm1)
172
173
  assert_equal ts1, t1
174
+ t2 = tt "[[]: (String) -> %any]"
175
+ tm2 = MethodType.new [RDL::Globals.types[:string]], nil, RDL::Globals.special_types['%any']
176
+ ts2 = StructuralType.new(:[] => tm2)
177
+ assert_equal ts2, t2
173
178
  end
174
179
 
175
180
  def test_finite_hash
@@ -6,6 +6,7 @@ class TestQuery < Minitest::Test
6
6
  include RDL::Type
7
7
 
8
8
  def setup
9
+ RDL.reset
9
10
  @p = Parser.new
10
11
  @tinteger = NominalType.new Integer
11
12
  @tarray = NominalType.new Array
@@ -5,6 +5,10 @@ require 'rdl'
5
5
  class TestRDL < Minitest::Test
6
6
  extend RDL::Annotate
7
7
 
8
+ def setup
9
+ RDL.reset
10
+ end
11
+
8
12
  # Test wrapping with no types or contracts
9
13
  def test_wrap
10
14
  def m1(x) return x; end
@@ -239,27 +243,27 @@ RUBY
239
243
  end
240
244
 
241
245
  def test_wrap_new
242
- self.class.class_eval "class B; def initialize(x); @x = x end; def get(); return @x end end"
243
- RDL.pre("TestRDL::B", "self.new") { |x| x > 0 }
244
- assert_equal 3, TestRDL::B.new(3).get
245
- assert_raises(RDL::Contract::ContractError) { TestRDL::B.new(-3) }
246
+ self.class.class_eval "class WrapB; def initialize(x); @x = x end; def get(); return @x end end"
247
+ RDL.pre("TestRDL::WrapB", "self.new") { |x| x > 0 }
248
+ assert_equal 3, TestRDL::WrapB.new(3).get
249
+ assert_raises(RDL::Contract::ContractError) { TestRDL::WrapB.new(-3) }
246
250
 
247
- self.class.class_eval "class C; extend RDL::Annotate; pre { |x| x > 0 }; def initialize(x); @x = x end; def get(); return @x end end"
248
- assert_equal 3, TestRDL::C.new(3).get
249
- assert_raises(RDL::Contract::ContractError) { TestRDL::C.new(-3) }
251
+ self.class.class_eval "class WrapC; extend RDL::Annotate; pre { |x| x > 0 }; def initialize(x); @x = x end; def get(); return @x end end"
252
+ assert_equal 3, TestRDL::WrapC.new(3).get
253
+ assert_raises(RDL::Contract::ContractError) { TestRDL::WrapC.new(-3) }
250
254
 
251
- self.class.class_eval "class D; def get(); return @x end end"
252
- RDL.pre("TestRDL::D", "self.new") { |x| x > 0 }
253
- self.class.class_eval "class D; def initialize(x); @x = x end end"
254
- assert_equal 3, TestRDL::D.new(3).get
255
- assert_raises(RDL::Contract::ContractError) { TestRDL::D.new(-3) }
255
+ self.class.class_eval "class WrapD; def get(); return @x end end"
256
+ RDL.pre("TestRDL::WrapD", "self.new") { |x| x > 0 }
257
+ self.class.class_eval "class WrapD; def initialize(x); @x = x end end"
258
+ assert_equal 3, TestRDL::WrapD.new(3).get
259
+ assert_raises(RDL::Contract::ContractError) { TestRDL::WrapD.new(-3) }
256
260
 
257
261
  skip "Can't defer contracts on new yet"
258
262
  RDL.
259
- pre("TestRDL::E", "self.new") { |x| x > 0 }
260
- self.class.class_eval "class E; def initialize(x); @x = x end end"
261
- assert (TestRDL::E.new(3))
262
- assert_raises(RDL::Contract::ContractError) { TestRDL::E.new(-3) }
263
+ pre("TestRDL::WrapE", "self.new") { |x| x > 0 }
264
+ self.class.class_eval "class WrapE; def initialize(x); @x = x end end"
265
+ assert (TestRDL::WrapE.new(3))
266
+ assert_raises(RDL::Contract::ContractError) { TestRDL::WrapE.new(-3) }
263
267
  end
264
268
 
265
269
  def test_class_method
@@ -388,25 +392,56 @@ RUBY
388
392
  assert !(RDL::Globals.info.has? "TestRDL::TestVersion", "m4", :post)
389
393
  end
390
394
 
391
- class TestRDLAnnotate
392
- extend RDL::RDLAnnotate
393
-
394
- rdl_pre { |x| x > 0 }
395
- def m1(x) return x; end
396
-
397
- rdl_post { |x| x < 0 }
398
- def m2(x) return 3; end
395
+ def test_pre_rdl_annotate_contract
396
+ self.class.class_eval <<-RUBY, __FILE__, __LINE__
397
+ class TestRDLAnnotate
398
+ extend RDL::RDLAnnotate
399
399
 
400
- rdl_type '(Integer) -> Integer'
401
- def m3(x) return x; end
400
+ rdl_pre { |x| x > 0 }
401
+ def m1(x) return x; end
402
402
 
403
- end
403
+ rdl_post { |x| x < 0 }
404
+ def m2(x) return 3; end
404
405
 
405
- def test_pre_rdl_annotate_contract
406
+ rdl_type '(Integer) -> Integer'
407
+ def m3(x) return x; end
408
+ end
409
+ RUBY
406
410
  assert_equal 3, TestRDLAnnotate.new.m1(3)
407
411
  assert_raises(RDL::Contract::ContractError) { TestRDLAnnotate.new.m1(-1) }
408
412
  assert_raises(RDL::Contract::ContractError) { TestRDLAnnotate.new.m2(42) }
409
413
  assert_raises(RDL::Type::TypeError) { TestRDLAnnotate.new.m3('one') }
410
414
  end
411
415
 
416
+ class TC0
417
+ def foo
418
+ 's'
419
+ end
420
+
421
+ def bar
422
+ 0
423
+ end
424
+ end
425
+
426
+ class TC1 < TC0
427
+ def foo
428
+ 's'
429
+ end
430
+
431
+ def bar
432
+ 0
433
+ end
434
+ end
435
+
436
+ def test_wrap_inheritance
437
+ RDL.type TC0, :foo, '() -> Integer', typecheck: :call
438
+ RDL.type TC0, :bar, '() -> Integer', typecheck: :call
439
+ RDL.type TC1, :foo, '() -> String', typecheck: :call
440
+ RDL.type TC1, :bar, '() -> String', typecheck: :call
441
+ assert_raises(RDL::Typecheck::StaticTypeError) { TC0.new.foo }
442
+ assert_equal 0, TC0.new.bar
443
+ assert_equal 's', TC1.new.foo
444
+ assert_raises(RDL::Typecheck::StaticTypeError) { TC1.new.bar }
445
+ end
446
+
412
447
  end
@@ -5,6 +5,10 @@ require 'rdl'
5
5
  class TestRDLType < Minitest::Test
6
6
  extend RDL::Annotate
7
7
 
8
+ def setup
9
+ RDL.reset
10
+ end
11
+
8
12
  def test_single_type_contract
9
13
  def m1(x) return x; end
10
14
  RDL.type TestRDLType, :m1, "(Integer) -> Integer"
@@ -0,0 +1,102 @@
1
+ require 'minitest/autorun'
2
+ $LOAD_PATH << File.dirname(__FILE__) + "/../lib"
3
+ require 'rdl'
4
+ require 'types/core'
5
+
6
+
7
+ class TestStringTypes < Minitest::Test
8
+ extend RDL::Annotate
9
+
10
+ def setup
11
+ RDL.reset
12
+ RDL.readd_comp_types
13
+ end
14
+
15
+ def test_string_methods
16
+ self.class.class_eval {
17
+
18
+ type '(String) -> "hello"', typecheck: :append_fail1
19
+ def append_fail_test1(x)
20
+ "he" << x
21
+ end
22
+
23
+ type '("hello") -> Integer', typecheck: :append_fail2
24
+ def append_fail_test2(x)
25
+ takes_hello(x)
26
+ x << 'blah'
27
+ 1
28
+ end
29
+
30
+
31
+ type "('he') -> 'hello'", typecheck: :now
32
+ def append_test1(x)
33
+ x << "llo"
34
+ end
35
+
36
+ type '(String) -> String', typecheck: :now
37
+ def append_test2(x)
38
+ "he" << x
39
+ end
40
+
41
+ type '("llo") -> String', typecheck: :now
42
+ def append_test3(x)
43
+ "he" << x
44
+ end
45
+
46
+ type :takes_hello, "('hello') -> Integer"
47
+
48
+ type '("he") -> Integer', typecheck: :now
49
+ def append_test4(y)
50
+ takes_hello(y << "llo")
51
+ end
52
+
53
+ type '("hello") -> "Hello"', typecheck: :now
54
+ def capitalize_test1(x)
55
+ x.capitalize
56
+ end
57
+
58
+ type '("hello") -> "Hello"', typecheck: :now
59
+ def capitalize_test2(x)
60
+ x.capitalize!
61
+ end
62
+
63
+ type '("hello") -> "o"', typecheck: :now
64
+ def access_test1(x)
65
+ x[4]
66
+ end
67
+
68
+ type '("he") -> "hello"', typecheck: :now
69
+ def concat_test1(x)
70
+ x + "llo"
71
+ end
72
+
73
+ type '("hello") -> 5', typecheck: :now
74
+ def size_test1(x)
75
+ x.size
76
+ end
77
+
78
+ type '(String) -> Integer', typecheck: :now
79
+ def size_test2(x)
80
+ x.size
81
+ end
82
+
83
+ type '(:world) -> "hello, world!"', typecheck: :now
84
+ def interp_test1(y)
85
+ "hello, #{y}!"
86
+ end
87
+
88
+ type '(Symbol) -> String', typecheck: :now
89
+ def interp_test2(y)
90
+ "hello, #{y}!"
91
+ end
92
+
93
+ type '("hi") -> "bye"', typecheck: :now
94
+ def replace_test1(x)
95
+ x.replace "bye"
96
+ x
97
+ end
98
+ }
99
+ assert_raises(RDL::Typecheck::StaticTypeError) { RDL.do_typecheck :append_fail1 }
100
+ assert_raises(RDL::Typecheck::StaticTypeError) { RDL.do_typecheck :append_fail2 }
101
+ end
102
+ end
@@ -8,6 +8,7 @@ class TestTypeContract < Minitest::Test
8
8
  extend RDL::Annotate
9
9
 
10
10
  def setup
11
+ RDL.reset
11
12
  @p = Parser.new
12
13
  end
13
14
 
@@ -23,6 +24,28 @@ class TestTypeContract < Minitest::Test
23
24
  end
24
25
 
25
26
  def test_proc
27
+ self.class.class_eval <<-RUBY, __FILE__, __LINE__
28
+ type '(Integer) { (Integer) -> Integer } -> Integer'
29
+ def block_contract_test1(x)
30
+ x+yield(5)
31
+ end
32
+
33
+ type '(Integer) { (Integer) -> Integer } -> Float'
34
+ def block_contract_test2(x)
35
+ x+yield(4.5)
36
+ end
37
+
38
+ type '(Integer) -> Integer'
39
+ def block_contract_test3(x)
40
+ 42
41
+ end
42
+
43
+ type '(Integer) ?{(Integer) -> Integer} -> Integer'
44
+ def block_contract_test4(x,&blk)
45
+ return yield(x) if blk
46
+ return x
47
+ end
48
+ RUBY
26
49
  t1 = @p.scan_str "(nil) -> nil"
27
50
  p1 = t1.to_contract.wrap(self) { |x| nil }
28
51
  assert_nil p1.call(nil)
@@ -187,29 +210,6 @@ class TestTypeContract < Minitest::Test
187
210
  assert_raises(TypeError) { p18.call(41, Proc.new {|x| x+1.5}) }
188
211
  p18b = t18.to_higher_contract(self) { |x,p=nil| if p then p.call(x+0.5) else x end }
189
212
  assert_raises(TypeError) { p18b.call(41, Proc.new {|x| x+1}) }
190
-
191
-
192
- end
193
-
194
- type '(Integer) { (Integer) -> Integer } -> Integer'
195
- def block_contract_test1(x)
196
- x+yield(5)
197
- end
198
-
199
- type '(Integer) { (Integer) -> Integer } -> Float'
200
- def block_contract_test2(x)
201
- x+yield(4.5)
202
- end
203
-
204
- type '(Integer) -> Integer'
205
- def block_contract_test3(x)
206
- 42
207
- end
208
-
209
- type '(Integer) ?{(Integer) -> Integer} -> Integer'
210
- def block_contract_test4(x,&blk)
211
- return yield(x) if blk
212
- return x
213
213
  end
214
214
 
215
215
  def test_proc_names
@@ -298,23 +298,45 @@ class TestTypeContract < Minitest::Test
298
298
  assert_raises(TypeError) { p9.call(43, x: "foo", y: 44, pi: 3.14, e: 3) }
299
299
  end
300
300
 
301
- type '() { () -> nil } -> nil'
302
- def _test_with_block
303
- nil
304
- end
305
-
306
- type '() -> nil'
307
- def _test_without_block
308
- nil
309
- end
310
-
311
- type '() -> nil'
312
- type '() { () -> nil } -> nil'
313
- def _test_with_without_block
314
- nil
301
+ def test_initialize
302
+ self.class.class_eval <<-RUBY, __FILE__, __LINE__
303
+ class TestTypeContract_A
304
+ extend RDL::Annotate
305
+ type "(Integer) -> self"
306
+ def initialize(x)
307
+ x
308
+ end
309
+ end
310
+ class TestTypeContract_B
311
+ extend RDL::Annotate
312
+ type "(Integer) -> Integer"
313
+ def initialize(x)
314
+ x
315
+ end
316
+ end
317
+ RUBY
318
+ assert TestTypeContract_A.new(1)
319
+ assert_raises(ArgumentError) { TestTypeContract_B.new(1) }
315
320
  end
316
321
 
317
322
  def test_block
323
+ self.class.class_eval <<-RUBY, __FILE__, __LINE__
324
+ type '() { () -> nil } -> nil'
325
+ def _test_with_block
326
+ nil
327
+ end
328
+
329
+ type '() -> nil'
330
+ def _test_without_block
331
+ nil
332
+ end
333
+
334
+ type '() -> nil'
335
+ type '() { () -> nil } -> nil'
336
+ def _test_with_without_block
337
+ nil
338
+ end
339
+ RUBY
318
340
  assert_nil(_test_with_block { nil })
319
341
  assert_raises(TypeError) { _test_with_block }
320
342
 
@@ -67,10 +67,6 @@ end
67
67
 
68
68
  class TestTypecheckC
69
69
  extend RDL::Annotate
70
- type 'self.bar', '() -> Integer or String ret'
71
- type 'self.foo', '() -> :A'
72
- type 'foo', '() -> Integer'
73
- type '(Integer) -> self'
74
70
  def initialize(x); end
75
71
  end
76
72
 
@@ -79,7 +75,6 @@ end
79
75
 
80
76
  class TestTypecheckE
81
77
  extend RDL::Annotate
82
- type '(Integer) -> self', typecheck: :einit
83
78
  def initialize(x)
84
79
  x
85
80
  end
@@ -87,7 +82,6 @@ end
87
82
 
88
83
  class TestTypecheckF
89
84
  extend RDL::Annotate
90
- type '(Integer) -> F', typecheck: :finit
91
85
  def initialize(x)
92
86
  x
93
87
  end
@@ -95,7 +89,6 @@ end
95
89
 
96
90
  module TestTypecheckM
97
91
  extend RDL::Annotate
98
- type 'self.foo', '() -> :B'
99
92
  end
100
93
 
101
94
  class TestTypecheckOuter
@@ -140,12 +133,67 @@ class MethodMissing2
140
133
  end
141
134
  end
142
135
 
136
+ class SingletonInheritA
137
+ extend RDL::Annotate
138
+ end
139
+
140
+ class SingletonInheritB < SingletonInheritA; end
141
+
143
142
 
144
143
  class TestTypecheck < Minitest::Test
145
144
  extend RDL::Annotate
146
- type :_any_object, "() -> Object" # a method that could return true or false
147
145
 
148
146
  def setup
147
+ RDL.reset
148
+ RDL.type TestTypecheck, :_any_object, '() -> Object', wrap: false # a method that could return true or false
149
+ RDL.readd_comp_types
150
+ RDL.type_params :Hash, [:k, :v], :all? unless RDL::Globals.type_params["Hash"]
151
+ RDL.type_params :Array, [:t], :all? unless RDL::Globals.type_params["Array"]
152
+ RDL.rdl_alias :Array, :size, :length
153
+ RDL.type_params 'RDL::Type::SingletonType', [:t], :satisfies? unless RDL::Globals.type_params["RDL::Type::SingletonType"]
154
+ =begin
155
+ RDL.type_params :Array, [:t], :all?
156
+ RDL.type :Array, :[]=, '(Integer, t) -> t', wrap: false
157
+ RDL.type :Array, :[]=, '(Integer, Integer, t) -> t', wrap: false
158
+ RDL.type :Array, :[]=, '(Range<Integer>, t) -> t', wrap: false
159
+ RDL.type :Array, :each, '() -> Enumerator<t>', wrap: false
160
+ RDL.type :Array, :each, '() { (t) -> %any } -> Array<t>', wrap: false
161
+ RDL.type :Array, :length, '() -> Integer', wrap: false
162
+ RDL.type :Array, :index, '(u) -> Integer', wrap: false
163
+ RDL.type :Array, :index, '() { (t) -> %bool } -> Integer', wrap: false
164
+ RDL.type :Array, :index, '() -> Enumerator<t>', wrap: false
165
+ RDL.type :Array, :map, '() {(t) -> u} -> Array<u>', wrap: false
166
+ RDL.type :Array, :map, '() -> Enumerator<t>', wrap: false
167
+ RDL.type_params :Hash, [:k, :v], :all?
168
+ RDL.type :Hash, :length, '() -> Integer', wrap: false
169
+ RDL.rdl_alias :Array, :size, :length
170
+ RDL.type :Hash, :[], '(k) -> v', wrap: false
171
+ RDL.type :Hash, :[]=, '(k, v) -> v', wrap: false
172
+ =end
173
+ RDL.type_params(:Range, [:t], nil, variance: [:+]) { |t| t.member?(self.begin) && t.member?(self.end) } unless RDL::Globals.type_params["Range"]
174
+ RDL.type :Range, :each, '() { (t) -> %any } -> self'
175
+ RDL.type :Range, :each, '() -> Enumerator<t>'
176
+ =begin
177
+ RDL.type :Integer, :<, '(Integer) -> %bool', wrap: false
178
+ RDL.type :Integer, :>, '(Integer) -> %bool', wrap: false
179
+ RDL.type :Integer, :>=, '(Integer) -> %bool', wrap: false
180
+ RDL.type :Integer, :+, '(Integer) -> Integer', wrap: false
181
+ RDL.type :Integer, :&, '(Integer) -> Integer', wrap: false
182
+ RDL.type :Integer, :*, '(Integer) -> Integer', wrap: false
183
+ =end
184
+ RDL.type :Integer, :to_s, '() -> String', wrap: false
185
+ RDL.type :Kernel, 'self.puts', '(*[to_s : () -> String]) -> nil', wrap: false
186
+ RDL.type :Kernel, :raise, '() -> %bot', wrap: false
187
+ RDL.type :Kernel, :raise, '(String) -> %bot', wrap: false
188
+ RDL.type :Kernel, :raise, '(Class, ?String, ?Array<String>) -> %bot', wrap: false
189
+ RDL.type :Kernel, :raise, '(Exception, ?String, ?Array<String>) -> %bot', wrap: false
190
+ RDL.type :Object, :===, '(%any other) -> %bool', wrap: false
191
+ RDL.type :Object, :clone, '() -> self', wrap: false
192
+ # RDL.type :String, :*, '(Integer) -> String', wrap: false
193
+ # RDL.type :String, :+, '(String) -> String', wrap: false
194
+ # RDL.type :String, :===, '(%any) -> %bool', wrap: false
195
+ # RDL.type :String, :length, '() -> Integer', wrap: false
196
+ RDL.type :NilClass, :&, '(%any obj) -> false', wrap: false
149
197
  @t3 = RDL::Type::SingletonType.new 3
150
198
  @t4 = RDL::Type::SingletonType.new 4
151
199
  @t5 = RDL::Type::SingletonType.new 5
@@ -161,6 +209,8 @@ class TestTypecheck < Minitest::Test
161
209
  @scopef = { tret: RDL::Globals.types[:integer] }
162
210
  @tfs = RDL::Type::UnionType.new(RDL::Globals.types[:integer], RDL::Globals.types[:string])
163
211
  @scopefs = { tret: @tfs, tblock: nil }
212
+ ### Uncomment below to see test names. Useful for hanging tests.
213
+ #puts "Start #{@NAME}"
164
214
  end
165
215
 
166
216
  # [+ a +] is the environment, a map from symbols to types; empty if omitted
@@ -400,6 +450,20 @@ class TestTypecheck < Minitest::Test
400
450
  assert_equal t, do_tc("TestTypecheckOuter::A", env: @env)
401
451
  t = RDL::Type::SingletonType.new(TestTypecheckOuter::A::B::C)
402
452
  assert_equal t, do_tc("TestTypecheckOuter::A::B::C", env: @env)
453
+
454
+ self.class.class_eval {
455
+ const_set(:CONST_STRING, 'string')
456
+
457
+ type '() -> String', typecheck: :now
458
+ def const1() CONST_STRING; end
459
+ }
460
+
461
+ assert_raises(RDL::Typecheck::StaticTypeError) {
462
+ self.class.class_eval {
463
+ type '() -> Integer', typecheck: :now
464
+ def const2() CONST_STRING; end
465
+ }
466
+ }
403
467
  end
404
468
 
405
469
  def test_defined
@@ -505,33 +569,14 @@ class TestTypecheck < Minitest::Test
505
569
  end
506
570
 
507
571
  class A
508
- extend RDL::Annotate
509
- type :_send_inherit1, "() -> Integer"
510
572
  end
511
573
  class B < A
512
574
  end
513
575
 
514
- class A1
515
- extend RDL::Annotate
516
- type "() -> nil"
517
- def _send_inherit2; end
518
- end
519
- class A2 < A1
520
- def _send_inherit2; end
521
- end
522
- class A3 < A2
523
- end
524
-
525
- def test_send_inherit
526
- assert do_tc("B.new._send_inherit1", env: @env) <= RDL::Globals.types[:integer]
527
- assert_raises(RDL::Typecheck::StaticTypeError) { do_tc("A3.new._send_inherit2", env: @env) }
528
- end
529
-
530
576
  def test_send_inter
531
- self.class.class_eval {
532
- type :_send_inter1, "(Integer) -> Integer"
533
- type :_send_inter1, "(String) -> String"
534
- }
577
+ RDL.type A, :_send_inherit1, "() -> Integer", wrap: false
578
+ RDL.type TestTypecheck, :_send_inter1, "(Integer) -> Integer", wrap: false
579
+ RDL.type TestTypecheck, :_send_inter1, "(String) -> String", wrap: false
535
580
  assert do_tc("_send_inter1(42)", env: @env) <= RDL::Globals.types[:integer]
536
581
  assert do_tc("_send_inter1('42')", env: @env) <= RDL::Globals.types[:string]
537
582
 
@@ -540,15 +585,13 @@ class TestTypecheck < Minitest::Test
540
585
 
541
586
  def test_send_opt_varargs
542
587
  # from test_type_contract.rb
543
- self.class.class_eval {
544
- type :_send_opt_varargs1, "(Integer, ?Integer) -> Integer"
545
- type :_send_opt_varargs2, "(Integer, *Integer) -> Integer"
546
- type :_send_opt_varargs3, "(Integer, ?Integer, ?Integer, *Integer) -> Integer"
547
- type :_send_opt_varargs4, "(?Integer) -> Integer"
548
- type :_send_opt_varargs5, "(*Integer) -> Integer"
549
- type :_send_opt_varargs6, "(?Integer, String) -> Integer"
550
- type :_send_opt_varargs7, "(Integer, *String, Integer) -> Integer"
551
- }
588
+ RDL.type TestTypecheck, :_send_opt_varargs1, "(Integer, ?Integer) -> Integer", wrap: false
589
+ RDL.type TestTypecheck, :_send_opt_varargs2, "(Integer, *Integer) -> Integer", wrap: false
590
+ RDL.type TestTypecheck, :_send_opt_varargs3, "(Integer, ?Integer, ?Integer, *Integer) -> Integer", wrap: false
591
+ RDL.type TestTypecheck, :_send_opt_varargs4, "(?Integer) -> Integer", wrap: false
592
+ RDL.type TestTypecheck, :_send_opt_varargs5, "(*Integer) -> Integer", wrap: false
593
+ RDL.type TestTypecheck, :_send_opt_varargs6, "(?Integer, String) -> Integer", wrap: false
594
+ RDL.type TestTypecheck, :_send_opt_varargs7, "(Integer, *String, Integer) -> Integer", wrap: false
552
595
  assert do_tc("_send_opt_varargs1(42)", env: @env) <= RDL::Globals.types[:integer]
553
596
  assert do_tc("_send_opt_varargs1(42, 43)", env: @env) <= RDL::Globals.types[:integer]
554
597
  assert_raises(RDL::Typecheck::StaticTypeError) { assert do_tc("_send_opt_varargs1()", env: @env) }
@@ -679,7 +722,7 @@ class TestTypecheck < Minitest::Test
679
722
  end
680
723
 
681
724
  def test_send_singleton
682
- RDL.type Integer, :_send_singleton, "() -> String"
725
+ RDL.type Integer, :_send_singleton, "() -> String", wrap: false
683
726
  assert do_tc("3._send_singleton", env: @env) <= RDL::Globals.types[:string]
684
727
  assert_raises(RDL::Typecheck::StaticTypeError) { do_tc("3._send_singleton_nexists", env: @env) }
685
728
  end
@@ -696,10 +739,8 @@ class TestTypecheck < Minitest::Test
696
739
  end
697
740
 
698
741
  def test_send_block
699
- self.class.class_eval {
700
- type :_send_block1, "(Integer) { (Integer) -> Integer } -> Integer"
701
- type :_send_block2, "(Integer) -> Integer"
702
- }
742
+ RDL.type TestTypecheck, :_send_block1, "(Integer) { (Integer) -> Integer } -> Integer"
743
+ RDL.type TestTypecheck, :_send_block2, "(Integer) -> Integer"
703
744
  assert_raises(RDL::Typecheck::StaticTypeError) { do_tc("_send_block1(42)", env: @env) }
704
745
  assert_raises(RDL::Typecheck::StaticTypeError) { do_tc("_send_block2(42) { |x| x + 1 }", env: @env) }
705
746
  assert_raises(RDL::Typecheck::StaticTypeError) { do_tc("_send_block1(42) { |x, y| x + y }", env: @env) }
@@ -733,7 +774,7 @@ class TestTypecheck < Minitest::Test
733
774
  type :_send_method_generic4, '(t) { (t) -> t } -> t'
734
775
  type :_send_method_generic5, '() { (u) -> u } -> u'
735
776
  type :_send_method_generic6, '() { (Integer) -> u } -> u'
736
- }
777
+ }
737
778
  assert do_tc('_send_method_generic1 3', env: @env) <= @t3
738
779
  assert do_tc('_send_method_generic1 "foo"', env: @env) <= RDL::Globals.types[:string]
739
780
  assert do_tc('_send_method_generic2 3, "foo"', env: @env) <= tt("3 or String")
@@ -912,7 +953,7 @@ class TestTypecheck < Minitest::Test
912
953
  # end
913
954
 
914
955
  def test_new
915
- assert do_tc("B.new", env: @env) <= RDL::Type::NominalType.new(B)
956
+ assert do_tc("B.new", env: @env) <= RDL::Type::NominalType.new(TestTypecheck::B)
916
957
  assert_raises(RDL::Typecheck::StaticTypeError) { do_tc("B.new(3)", env: @env) }
917
958
  end
918
959
 
@@ -961,16 +1002,14 @@ class TestTypecheck < Minitest::Test
961
1002
  end
962
1003
 
963
1004
  class C
964
- extend RDL::Annotate
965
- type :===, "(Object) -> %bool"
966
1005
  end
967
1006
 
968
1007
  class D
969
- extend RDL::Annotate
970
- type :===, "(String) -> %bool"
971
1008
  end
972
1009
 
973
1010
  def test_when
1011
+ RDL.type C, :===, "(Object) -> %bool"
1012
+ RDL.type D, :===, "(String) -> %bool"
974
1013
  assert do_tc("case when C.new then 3 end", env: @env) <= @t3
975
1014
  assert do_tc("x = 4; case when _any_object then x = 3 end; x", env: @env) <= @t34
976
1015
  assert do_tc("case when _any_object then 3 else 'foo' end", env: @env) <= @ts3
@@ -998,6 +1037,7 @@ class TestTypecheck < Minitest::Test
998
1037
  assert do_tc("until false do end") <= RDL::Globals.types[:nil]
999
1038
  assert do_tc("begin end while true") <= RDL::Globals.types[:nil]
1000
1039
  assert do_tc("begin end until false") <= RDL::Globals.types[:nil]
1040
+
1001
1041
  assert do_tc("i = 0; while i < 5 do i = 1 + i end; i") <= RDL::Globals.types[:integer]
1002
1042
  assert do_tc("i = 0; while i < 5 do i = i + 1 end; i") <= RDL::Globals.types[:integer]
1003
1043
  assert do_tc("i = 0; until i >= 5 do i = 1 + i end; i") <= RDL::Globals.types[:integer]
@@ -1008,10 +1048,10 @@ class TestTypecheck < Minitest::Test
1008
1048
  assert do_tc("i = 0; begin i = i + 1 end until i >= 5; i") <= RDL::Globals.types[:integer]
1009
1049
 
1010
1050
  # break, redo, next, no args
1011
- assert do_tc("i = 0; while i < 5 do if i > 2 then break end; i = 1 + i end; i") <= RDL::Globals.types[:integer]
1012
- assert do_tc("i = 0; while i < 5 do break end; i") <= tt("0")
1013
- assert do_tc("i = 0; while i < 5 do redo end; i") # infinite loop, ok for typing <= tt("0")
1014
- assert do_tc("i = 0; while i < 5 do next end; i") # infinite loop, ok for typing <= tt("0")
1051
+ # assert do_tc("i = 0; while i < 5 do if i > 2 then break end; i = 1 + i end; i") <= RDL::Globals.types[:integer]
1052
+ # assert do_tc("i = 0; while i < 5 do break end; i") <= tt("0")
1053
+ # assert do_tc("i = 0; while i < 5 do redo end; i") # infinite loop, ok for typing <= tt("0")
1054
+ # assert do_tc("i = 0; while i < 5 do next end; i") # infinite loop, ok for typing <= tt("0")
1015
1055
  assert_raises(RDL::Typecheck::StaticTypeError) { do_tc("i = 0; while i < 5 do retry end; i") }
1016
1056
  assert do_tc("i = 0; begin i = i + 1; break if i > 2; end while i < 5; i") <= RDL::Globals.types[:integer]
1017
1057
  assert do_tc("i = 0; begin i = i + 1; redo if i > 2; end while i < 5; i") <= RDL::Globals.types[:integer]
@@ -1023,16 +1063,21 @@ class TestTypecheck < Minitest::Test
1023
1063
  assert_raises(RDL::Typecheck::StaticTypeError) { do_tc("while _any_object do next 3 end", env: @env) }
1024
1064
  assert do_tc("begin break 3 end while _any_object", env: @env) <= @t3n
1025
1065
  assert_raises(RDL::Typecheck::StaticTypeError) { do_tc("begin next 3 end while _any_object", env: @env) }
1066
+
1026
1067
  end
1027
1068
 
1028
1069
  def test_for
1029
1070
  assert do_tc("for i in 1..5 do end; i") <= RDL::Globals.types[:integer]
1030
1071
  assert do_tc("for i in [1,2,3,4,5] do end; i") <= tt("1 or 2 or 3 or 4 or 5")
1072
+ ## TODO: figure out why above fails to terminate
1031
1073
  assert do_tc("for i in 1..5 do break end", env: @env) <= tt("Range<Integer>")
1032
1074
  assert do_tc("for i in 1..5 do next end", env: @env) <= tt("Range<Integer>")
1033
1075
  assert do_tc("for i in 1..5 do redo end", env: @env) <= tt("Range<Integer>") #infinite loop, ok for typing
1034
1076
  assert do_tc("for i in 1..5 do break 3 end", env: @env) <= tt("Range<Integer> or 3")
1035
- assert do_tc("for i in 1..5 do next 'three' end; i", env: @env) <= @tfs
1077
+ #assert do_tc("for i in 1..5 do next 'three' end; i", env: @env) <= @tfs
1078
+ ## Commented out above after implementing PreciseStringType. It no longer holds because 'three'
1079
+ ## gets upper bound(s) of 'three', but then is promote!-ed to be compared to String, and because
1080
+ ## String is not <= 'three', the previous bounds do not hold and this case fails.
1036
1081
  end
1037
1082
 
1038
1083
  def test_return
@@ -1060,12 +1105,11 @@ class TestTypecheck < Minitest::Test
1060
1105
  end
1061
1106
 
1062
1107
  class E
1063
- extend RDL::Annotate
1064
- type :f, '() -> Integer'
1065
- type :f=, '(Integer) -> nil'
1066
1108
  end
1067
1109
 
1068
1110
  def test_op_asgn
1111
+ RDL.type E, :f, '() -> Integer', wrap: false
1112
+ RDL.type E, :f=, '(Integer) -> nil', wrap: false
1069
1113
  assert RDL::Globals.types[:integer], do_tc("x = 0; x += 1")
1070
1114
  assert_raises(RDL::Typecheck::StaticTypeError) { do_tc("x += 1") }
1071
1115
  assert_raises(RDL::Typecheck::StaticTypeError) { do_tc("x = Object.new; x += 1", env: @env) }
@@ -1075,9 +1119,12 @@ class TestTypecheck < Minitest::Test
1075
1119
  end
1076
1120
 
1077
1121
  def test_and_or_asgn
1122
+ RDL.type E, :f, '() -> Integer', wrap: false
1123
+ RDL.type E, :f=, '(Integer) -> nil', wrap: false
1078
1124
  self.class.class_eval {
1079
1125
  var_type :@f_and_or_asgn, "Integer"
1080
1126
  }
1127
+ RDL.type TestTypecheckE, :initialize, '(Integer) -> self', wrap: false, typecheck: :einit
1081
1128
  assert do_tc("x ||= 3") <= @t3 # weird
1082
1129
  assert do_tc("x &&= 3") <= RDL::Globals.types[:nil] # weirder
1083
1130
  assert do_tc("@f_and_or_asgn &&= 4", env: @env) <= RDL::Globals.types[:integer]
@@ -1088,6 +1135,8 @@ class TestTypecheck < Minitest::Test
1088
1135
  end
1089
1136
 
1090
1137
  def test_masgn
1138
+ RDL.type E, :f, '() -> Integer', wrap: false
1139
+ RDL.type E, :f=, '(Integer) -> nil', wrap: false
1091
1140
  self.class.class_eval {
1092
1141
  var_type :@f_masgn, "Array<Integer>"
1093
1142
  }
@@ -1101,7 +1150,8 @@ class TestTypecheck < Minitest::Test
1101
1150
  assert do_tc("a, b = 3, 'two'; b") <= RDL::Globals.types[:string]
1102
1151
  assert do_tc("a = [3, 'two']; x, y = a; x") <= @t3
1103
1152
  assert do_tc("a = [3, 'two']; x, y = a; y") <= RDL::Globals.types[:string]
1104
- assert_raises(RDL::Typecheck::StaticTypeError) { do_tc("a = [3, 'two']; x, y = a; a.length", env: @env) }
1153
+ #assert_raises(RDL::Typecheck::StaticTypeError) { do_tc("a = [3, 'two']; x, y = a; a.length", env: @env) }
1154
+ ## the above works after computational type changes
1105
1155
 
1106
1156
  # w/send
1107
1157
  assert do_tc("e = E.new; e.f, b = 1, 2; b", env: @env) <= tt("2")
@@ -1154,9 +1204,14 @@ class TestTypecheck < Minitest::Test
1154
1204
  assert do_tc("RDL.type_cast(1 + 2, 'Integer', force: :blah)", env: @env) <= RDL::Globals.types[:integer]
1155
1205
  assert_raises(RDL::Typecheck::StaticTypeError) { do_tc("RDL.type_cast(1 + 2, 'Integer', forc: true)", env: @env) }
1156
1206
  assert_raises(RDL::Typecheck::StaticTypeError) { do_tc("RDL.type_cast(1 + 2, 'Fluffy Bunny')") }
1207
+ assert_raises(RDL::Typecheck::StaticTypeError) { do_tc("RDL.type_cast(:nonsense + 2, 'Integer')") }
1208
+ assert do_tc("RDL.type_cast(RDL.type_cast(:nonsense, 'Integer') + 2, 'Integer')")
1157
1209
  end
1158
1210
 
1159
1211
  def test_instantiate
1212
+ RDL.type :Array, :initialize, '() -> self', wrap: false
1213
+ RDL.type :Array, :initialize, '(Integer) -> self', wrap: false
1214
+ RDL.type :Array, :initialize, '(Integer, t) -> self<t>', wrap: false
1160
1215
  assert_raises(RDL::Typecheck::StaticTypeError) {
1161
1216
  self.class.class_eval {
1162
1217
  type "(Integer, Integer) -> Array<Integer>", typecheck: :now
@@ -1169,18 +1224,26 @@ class TestTypecheck < Minitest::Test
1169
1224
  def def_inst_pass(x, y) a = Array.new(x,y); RDL.instantiate!(a, "Integer"); a; end
1170
1225
  }
1171
1226
  )
1172
- assert_raises(RDL::Typecheck::StaticTypeError) {
1227
+
1228
+ # below works with computational types
1229
+ #assert_raises(RDL::Typecheck::StaticTypeError) {
1230
+ assert (
1173
1231
  self.class.class_eval {
1174
1232
  type "(Integer) -> Integer", typecheck: :now
1175
1233
  def def_inst_hash_fail(x) hash = {}; hash["test"] = x; hash["test"]; end
1176
1234
  }
1177
- }
1235
+ )
1236
+ # }
1237
+
1238
+ =begin
1239
+ # below works with computational types
1178
1240
  assert_raises(RDL::Typecheck::StaticTypeError) {
1179
1241
  self.class.class_eval {
1180
1242
  type "(Integer) -> Integer", typecheck: :now
1181
1243
  def def_inst_hash_fail2(x) hash = {}; hash.instantiate("Integer", "String") ; hash["test"] = x; hash["test"]; end
1182
1244
  }
1183
1245
  }
1246
+ =end
1184
1247
  assert(
1185
1248
  self.class.class_eval {
1186
1249
  type "(Integer) -> Integer", typecheck: :now
@@ -1203,11 +1266,11 @@ class TestTypecheck < Minitest::Test
1203
1266
  end
1204
1267
 
1205
1268
  def test_rescue_ensure
1269
+
1206
1270
  assert do_tc("begin 3; rescue; 4; end") <= @t3 # rescue clause can never be executed
1207
1271
  assert do_tc("begin puts 'foo'; 3; rescue; 4; end", env: @env) <= @t34
1208
1272
  assert do_tc("begin puts 'foo'; 3; rescue => e; e; end", env: @env) <= tt("StandardError or 3")
1209
1273
  assert do_tc("begin puts 'foo'; 3; rescue RuntimeError => e; e; end", env: @env) <= tt("RuntimeError or 3")
1210
- assert do_tc("begin puts 'foo'; 3; else; 4; end", env: @env) <= tt("4") # parser discards else clause!
1211
1274
  assert do_tc("begin puts 'foo'; 3; rescue RuntimeError => e; e; rescue ArgumentError => x; x; end", env: @env) <= tt("RuntimeError or ArgumentError or 3")
1212
1275
  assert do_tc("begin puts 'foo'; 3; rescue RuntimeError => e; e; rescue ArgumentError => x; x; else 42; end", env: @env) <= tt("RuntimeError or ArgumentError or 42 or 3")
1213
1276
  assert do_tc("begin puts 'foo'; 3; rescue RuntimeError, ArgumentError => e; e; end", env: @env) <= tt("RuntimeError or ArgumentError or 3")
@@ -1216,6 +1279,7 @@ class TestTypecheck < Minitest::Test
1216
1279
  assert do_tc("begin x = 3; ensure x = 4; end; x", env: @env) <= @t4
1217
1280
  assert do_tc("begin puts 'foo'; x = 3; rescue; x = 4; ensure x = 5; end; x", env: @env) <= @t5
1218
1281
  assert do_tc("begin puts 'foo'; 3; rescue; 4; ensure 5; end", env: @env) <= @t34
1282
+
1219
1283
  end
1220
1284
 
1221
1285
  class SubArray < Array
@@ -1225,11 +1289,9 @@ class TestTypecheck < Minitest::Test
1225
1289
  end
1226
1290
 
1227
1291
  def test_array_splat
1228
- self.class.class_eval {
1229
- type :_splataf, "() -> Array<Integer>"
1230
- type :_splatas, "() -> Array<String>"
1231
- type :_splathsf, "() -> Hash<Symbol, Integer>"
1232
- }
1292
+ RDL.type TestTypecheck, :_splataf, "() -> Array<Integer>", wrap: false
1293
+ RDL.type TestTypecheck, :_splatas, "() -> Array<String>", wrap: false
1294
+ RDL.type TestTypecheck, :_splathsf, "() -> Hash<Symbol, Integer>", wrap: false
1233
1295
  assert do_tc("x = *1") <= tt("[1]")
1234
1296
  assert do_tc("x = [1, *2, 3]") <= tt("[1, 2, 3]")
1235
1297
  assert_raises(RDL::Typecheck::StaticTypeError) { do_tc("x = [1, *Object.new, 3]", env: @env) } # the Object might or might not be an array...
@@ -1248,9 +1310,11 @@ class TestTypecheck < Minitest::Test
1248
1310
  assert do_tc("x = *{a: 1, b: 2, c: 3}") <= tt("[[:a, 1], [:b, 2], [:c, 3]]")
1249
1311
  assert do_tc("x = [1, *{a: 2}, 3]") <= tt("[1, [:a, 2], 3]")
1250
1312
  assert do_tc("y = [2]; x = [1, *y, 3]; ") <= tt("[1, 2, 3]")
1251
- assert_raises(RDL::Typecheck::StaticTypeError) { do_tc("y = [2]; x = [1, *y, 3]; y.length") }
1313
+ #assert_raises(RDL::Typecheck::StaticTypeError) { do_tc("y = [2]; x = [1, *y, 3]; y.length") }
1314
+ # the above works after computational type changes
1252
1315
  assert do_tc("y = {a: 2}; x = [1, *y, 3]") <= tt("[1, [:a, 2], 3]")
1253
- assert_raises(RDL::Typecheck::StaticTypeError) { do_tc("y = {a: 2}; x = [1, *y, 3]; y.length") }
1316
+ #assert_raises(RDL::Typecheck::StaticTypeError) { do_tc("y = {a: 2}; x = [1, *y, 3]; y.length") }
1317
+ # the above works after computational type changes
1254
1318
 
1255
1319
  assert do_tc("x = *_splataf", env: @env) <= tt("Array<Integer>")
1256
1320
  assert do_tc("x = [1, *_splataf, 2]", env: @env) <= tt("Array<Integer>")
@@ -1275,7 +1339,8 @@ class TestTypecheck < Minitest::Test
1275
1339
  assert do_tc("x = {**{a: 1}, b: 2, **{c: 3}}") <= tt("{a: 1, b: 2, c: 3}")
1276
1340
  assert_raises(RDL::Typecheck::StaticTypeError) { do_tc("x = {a: 1, **Object.new}", env: @env) } # may or may not be hash
1277
1341
  assert_raises(RDL::Typecheck::StaticTypeError) { do_tc("x = {a: 1, **SubHash.new}", env: @env) } # is a how, but unclear how to splat
1278
- assert_raises(RDL::Typecheck::StaticTypeError) { do_tc("y = {b: 2}; x = {a: 1, **y}; y.length") }
1342
+ #assert_raises(RDL::Typecheck::StaticTypeError) { do_tc("y = {b: 2}; x = {a: 1, **y}; y.length") }
1343
+ # the above works after computational type changes
1279
1344
 
1280
1345
  assert do_tc("x = {**_kwsplathsf}", env: @env) <= tt("Hash<Symbol, Integer>")
1281
1346
  assert do_tc("x = {**_kwsplathsf, **_kwsplathos}", env: @env) <= tt("Hash<Symbol or Float, Integer or String>")
@@ -1403,6 +1468,22 @@ class TestTypecheck < Minitest::Test
1403
1468
  end
1404
1469
  }
1405
1470
 
1471
+ self.class.class_eval {
1472
+ type '(?Integer x) -> Integer', typecheck: :now
1473
+ def _optional_varargs_mapping9(x=42)
1474
+ x
1475
+ end
1476
+ }
1477
+
1478
+ assert_raises(RDL::Typecheck::StaticTypeError) {
1479
+ self.class.class_eval {
1480
+ type '(?Integer x) -> Integer', typecheck: :now
1481
+ def _optional_varargs_mapping10(x='hi')
1482
+ x
1483
+ end
1484
+ }
1485
+ }
1486
+
1406
1487
  end
1407
1488
 
1408
1489
  def test_kw_mapping
@@ -1508,6 +1589,7 @@ class TestTypecheck < Minitest::Test
1508
1589
 
1509
1590
  def test_class_call
1510
1591
  TestTypecheckE.class_eval {
1592
+ type :initialize, '(Integer) -> self', wrap: false
1511
1593
  type '(Integer) -> Class', typecheck: :now
1512
1594
  def call_class1(x)
1513
1595
  x.class
@@ -1526,19 +1608,32 @@ class TestTypecheck < Minitest::Test
1526
1608
  end
1527
1609
 
1528
1610
  def test_singleton
1611
+ TestTypecheckC.class_eval {
1612
+ type :'self.foo', '() -> :A'
1613
+ }
1614
+ TestTypecheckM.class_eval {
1615
+ type :'self.foo', '() -> :B'
1616
+ }
1529
1617
  assert_equal ':A', do_tc("TestTypecheckC.foo", env: @env).to_s
1530
1618
  assert_equal ':B', do_tc("TestTypecheckM.foo", env: @env).to_s
1531
1619
  end
1532
1620
 
1533
1621
  def test_annotated_ret
1622
+ TestTypecheckC.class_eval {
1623
+ type 'self.bar', '() -> Integer or String ret'
1624
+ }
1534
1625
  assert do_tc("TestTypecheckC.bar", env: @env) <= tt('Integer or String')
1535
1626
  end
1536
1627
 
1537
1628
  def test_constructor
1629
+ RDL.type TestTypecheckC, :'self.bar', '() -> Integer or String ret'
1630
+ RDL.type TestTypecheckC, :'self.foo', '() -> :A'
1631
+ RDL.type TestTypecheckC, :foo, '() -> Integer'
1632
+ RDL.type TestTypecheckC, :initialize, '(Integer) -> self'
1633
+ RDL.type TestTypecheckF, :initialize, '(Integer) -> F', typecheck: :finit
1538
1634
  t = do_tc("TestTypecheckC.new(1)", env: @env)
1539
1635
  assert_equal 'TestTypecheckC', t.to_s
1540
1636
 
1541
-
1542
1637
  assert_raises(RDL::Typecheck::StaticTypeError) {
1543
1638
  self.class.class_eval {
1544
1639
  type '(Integer) -> Integer', typecheck: :now
@@ -1583,6 +1678,80 @@ class TestTypecheck < Minitest::Test
1583
1678
  }
1584
1679
  end
1585
1680
 
1681
+ def test_dyn
1682
+ # any method call on %dyn type return %dyn
1683
+ self.class.class_eval {
1684
+ type "(%dyn) -> %dyn", typecheck: :now
1685
+ def self.do_add(x); x + 1; end
1686
+ }
1687
+
1688
+ # any method can return a %dyn type
1689
+ self.class.class_eval {
1690
+ type "() -> %dyn", typecheck: :now
1691
+ def self.ret_dyn; "blah"; end
1692
+ }
1693
+
1694
+ # somewhat larger program
1695
+ self.class.class_eval {
1696
+ def inc(x); x + 1; end
1697
+ def use_val; v = get_val; inc(v); end
1698
+ def get_val; return "blah"; end
1699
+
1700
+ type :inc, '(Integer) -> Integer', typecheck: :dyntest
1701
+ type :use_val, '() -> Integer', typecheck: :dyntest
1702
+ type :get_val, '() -> %dyn', typecheck: :dyntest
1703
+
1704
+ RDL.do_typecheck :dyntest
1705
+ }
1706
+ end
1707
+
1708
+ def test_assume_dynamic
1709
+ RDL.config { |config| config.assume_dyn_type = true }
1710
+
1711
+ dynamic = do_tc('unknown', env: @env)
1712
+ assert dynamic <= tt('Integer')
1713
+ assert tt('Integer') <= dynamic
1714
+ assert dynamic <= tt('Array<Integer>')
1715
+ assert tt('Array<Integer>') <= dynamic
1716
+
1717
+ tuple_of_dynamic = do_tc('[unknown]', env: @env)
1718
+ refute tuple_of_dynamic <= tt('Integer')
1719
+ assert tuple_of_dynamic <= tt('[Integer]')
1720
+ refute tt('Integer') <= tuple_of_dynamic
1721
+ assert tt('[Integer]') <= tuple_of_dynamic
1722
+
1723
+ assert_equal(dynamic, do_tc('unknown.unknown', env: @env))
1724
+ assert_equal(dynamic, do_tc('a,b = unknown', env: @env))
1725
+ assert_equal(dynamic, do_tc('(a,b = unknown).unknown', env: @env))
1726
+ assert_equal(dynamic, do_tc('unknown[1]', env: @env))
1727
+
1728
+ self.class.class_eval {
1729
+ type "() -> String", typecheck: :now
1730
+ def dynamic_1()
1731
+ unknown
1732
+ end
1733
+ type "() -> Array<Integer>", typecheck: :now
1734
+ def dynamic_2()
1735
+ unknown(unknown)
1736
+ end
1737
+ type "() -> %bot", typecheck: :now
1738
+ def dynamic_3()
1739
+ unknown(3)
1740
+ end
1741
+ }
1742
+
1743
+ RDL.config { |config| config.assume_dyn_type = false }
1744
+
1745
+ assert_raises(RDL::Typecheck::StaticTypeError) {
1746
+ self.class.class_eval {
1747
+ type "() -> String", typecheck: :now
1748
+ def dynamic_4()
1749
+ unknown
1750
+ end
1751
+ }
1752
+ }
1753
+ end
1754
+
1586
1755
  def test_method_missing
1587
1756
  skip "method_missing not supported yet"
1588
1757
  RDL.do_typecheck :later_mm1
@@ -1616,8 +1785,8 @@ class TestTypecheck < Minitest::Test
1616
1785
  def bar(x); 1 + x; end
1617
1786
  def baz(x); 1 + x; end
1618
1787
  type 'self.foo', '() -> :a0'
1619
- type 'bar', '(Fixnum) -> Fixnum'
1620
- type 'baz', '(Fixnum) -> Fixnum'
1788
+ type 'bar', '(Integer) -> Integer'
1789
+ type 'baz', '(Integer) -> Integer'
1621
1790
  end
1622
1791
  TestTypecheck::SA1.class_eval do
1623
1792
  extend RDL::Annotate
@@ -1625,8 +1794,8 @@ class TestTypecheck < Minitest::Test
1625
1794
  def bar(x); super(x); end
1626
1795
  def baz(x); super; end
1627
1796
  type 'self.foo', '() -> :a0', typecheck: :call
1628
- type :bar, '(Fixnum) -> Fixnum', typecheck: :call
1629
- type :baz, '(Fixnum) -> Fixnum', typecheck: :call
1797
+ type :bar, '(Integer) -> Integer', typecheck: :call
1798
+ type :baz, '(Integer) -> Integer', typecheck: :call
1630
1799
  end
1631
1800
 
1632
1801
  r = TestTypecheck::SA1.foo
@@ -1655,4 +1824,240 @@ class TestTypecheck < Minitest::Test
1655
1824
 
1656
1825
  assert_nil TestTypecheck::A5.new.foo(:a)
1657
1826
  end
1827
+
1828
+ module ModuleNesting
1829
+ module Foo
1830
+ extend RDL::Annotate
1831
+ MYFOO = 'foo'
1832
+ type '() -> String', :typecheck => :call
1833
+ def self.foo
1834
+ MYFOO
1835
+ end
1836
+ end
1837
+ module Bar
1838
+ extend RDL::Annotate
1839
+ type '() -> NilClass', :typecheck => :call
1840
+ def self.bar
1841
+ TestTypecheck::ModuleNesting::Foo.foo
1842
+ Foo.foo
1843
+ Foo::MYFOO
1844
+ nil
1845
+ end
1846
+ end
1847
+ class Baz
1848
+ extend RDL::Annotate
1849
+ type '() -> NilClass', :typecheck => :call
1850
+ def self.baz
1851
+ TestTypecheck::ModuleNesting::Foo.foo
1852
+ Foo.foo
1853
+ Foo::MYFOO
1854
+ nil
1855
+ end
1856
+ type '() -> NilClass', :typecheck => :call
1857
+ def baz
1858
+ TestTypecheck::ModuleNesting::Foo.foo
1859
+ Foo.foo
1860
+ Foo::MYFOO
1861
+ nil
1862
+ end
1863
+ end
1864
+
1865
+ class Parent
1866
+ MY_CONST = 'foo'
1867
+ end
1868
+ module Mixin
1869
+ MY_MIXIN_CONST = 'bar'
1870
+ end
1871
+ class Child < Parent
1872
+ include Mixin
1873
+ extend RDL::Annotate
1874
+ type '() -> String', :typecheck => :call
1875
+ def self.no_context
1876
+ MY_CONST
1877
+ end
1878
+ type '() -> String', :typecheck => :call
1879
+ def self.parent_context
1880
+ Parent::MY_CONST
1881
+ end
1882
+ type '() -> String', :typecheck => :call
1883
+ def self.mixin
1884
+ MY_MIXIN_CONST
1885
+ end
1886
+ end
1887
+ end
1888
+
1889
+ def test_module_nesting
1890
+ assert_nil ModuleNesting::Bar.bar
1891
+ assert_nil ModuleNesting::Baz.baz
1892
+ assert_nil ModuleNesting::Baz.new.baz
1893
+ assert_equal 'foo', ModuleNesting::Child.no_context
1894
+ assert_equal 'foo', ModuleNesting::Child.parent_context
1895
+ assert_equal 'bar', ModuleNesting::Child.mixin
1896
+ end
1897
+
1898
+ def test_module_fully_qualfieds_calls
1899
+ self.class.class_eval "module FullyQualfied; end"
1900
+ FullyQualfied.class_eval do
1901
+ extend RDL::Annotate
1902
+ type '() -> nil', :typecheck => :call
1903
+ def self.foo
1904
+ TestTypecheck::FullyQualfied.bar
1905
+ end
1906
+ type '() -> nil', :typecheck => :call
1907
+ def self.bar
1908
+ end
1909
+ end
1910
+
1911
+ assert_nil FullyQualfied.foo
1912
+ end
1913
+
1914
+ def test_grandparent_with_type
1915
+ self.class.class_eval "class GrandParentWithType; end"
1916
+ self.class.class_eval "class ParentWithoutType < GrandParentWithType; end"
1917
+ self.class.class_eval "class ChildWithoutType < ParentWithoutType; end"
1918
+ GrandParentWithType.class_eval do
1919
+ extend RDL::Annotate
1920
+ type '(Integer) -> nil', typecheck: :call
1921
+ def foo(x); end
1922
+ end
1923
+
1924
+ ParentWithoutType.class_eval do
1925
+ def foo(x); end
1926
+ end
1927
+
1928
+ ChildWithoutType.class_eval do
1929
+ def foo(x); end
1930
+ end
1931
+
1932
+ assert_nil ChildWithoutType.new.foo(1)
1933
+ end
1934
+
1935
+ def test_object_sing_method
1936
+ assert_raises(RDL::Typecheck::StaticTypeError) {
1937
+ Object.class_eval do
1938
+ extend RDL::Annotate
1939
+ type '(Integer) -> String', typecheck: :now
1940
+ def self.add_one(x)
1941
+ x+1
1942
+ end
1943
+ end
1944
+ }
1945
+ end
1946
+
1947
+ def test_raise_typechecks
1948
+ self.class.class_eval "module RaiseTypechecks; end"
1949
+ RaiseTypechecks.class_eval do
1950
+ extend RDL::Annotate
1951
+ type '() -> nil', :typecheck => :call
1952
+ def self.foo
1953
+ raise "strings are good"
1954
+ end
1955
+
1956
+ type '() -> nil', :typecheck => :call
1957
+ def self.bar
1958
+ raise RuntimeError.new, "so are two-args"
1959
+ end
1960
+
1961
+ type '() -> nil', :typecheck => :call
1962
+ def self.baz
1963
+ raise RuntimeError, "and just class is ok"
1964
+ end
1965
+ end
1966
+
1967
+ assert_raises(RuntimeError) do
1968
+ RaiseTypechecks.foo
1969
+ end
1970
+ assert_raises(RuntimeError) do
1971
+ RaiseTypechecks.bar
1972
+ end
1973
+ assert_raises(RuntimeError) do
1974
+ RaiseTypechecks.baz
1975
+ end
1976
+ end
1977
+
1978
+
1979
+ def test_sing_method_inheritence
1980
+ RDL.type SingletonInheritA, 'self.foo', '(Integer) -> Integer'
1981
+ self.class.class_eval do
1982
+ type '(Integer) -> Integer', typecheck: :now
1983
+ def calls_inherited_sing_meth(x)
1984
+ SingletonInheritB.foo(x)
1985
+ end
1986
+ end
1987
+ end
1988
+
1989
+
1990
+ def test_comp_types
1991
+ self.class.class_eval "class CompTypes; end"
1992
+ CompTypes.class_eval do
1993
+ ### Tests where return type is computed
1994
+ extend RDL::Annotate
1995
+ type :bar, '(Integer or String) -> ``gen_return_type(targs)``'
1996
+ def self.gen_return_type(targs)
1997
+ raise RDL::Typecheck::StaticTypeError, "Unexpected number of arguments to bar." unless targs.size == 1
1998
+ if targs[0] == RDL::Globals.types[:integer]
1999
+ return RDL::Globals.types[:string]
2000
+ elsif targs[0] == RDL::Globals.types[:string]
2001
+ return RDL::Globals.types[:integer]
2002
+ else
2003
+ raise RDL::Typecheck::StaticTypeError, "Unexpected input type."
2004
+ end
2005
+ end
2006
+
2007
+ type '(Integer) -> String', typecheck: :now
2008
+ def uses_bar1(x)
2009
+ bar(x)
2010
+ end
2011
+
2012
+ type '(String) -> Integer', typecheck: :now
2013
+ def uses_bar2(x)
2014
+ bar(x)
2015
+ end
2016
+ end
2017
+
2018
+ assert_raises(RDL::Typecheck::StaticTypeError) {
2019
+ CompTypes.class_eval do
2020
+ type '(String) -> String', typecheck: :now
2021
+ def uses_bar3(x)
2022
+ bar(x)
2023
+ end
2024
+ end
2025
+ }
2026
+
2027
+ CompTypes.class_eval do
2028
+ ### Tests where input type is computed
2029
+ type :baz, '(Integer or String, ``gen_input_type(targs)``) -> Integer'
2030
+
2031
+ def self.gen_input_type(targs)
2032
+ raise RDL::Typecheck::StaticTypeError, "Unexpected number of arguments to bar." unless targs.size == 2
2033
+ if targs[0] == RDL::Globals.types[:integer]
2034
+ return RDL::Globals.types[:string]
2035
+ elsif targs[0] == RDL::Globals.types[:string]
2036
+ return RDL::Globals.types[:integer]
2037
+ else
2038
+ raise RDL::Typecheck::StaticTypeError, "Unexpected input type."
2039
+ end
2040
+ end
2041
+
2042
+ type '(Integer, String) -> Integer', typecheck: :now
2043
+ def uses_baz1(x, y)
2044
+ baz(x, y)
2045
+ end
2046
+
2047
+ type '(String, Integer) -> Integer', typecheck: :now
2048
+ def uses_baz2(x, y)
2049
+ baz(x, y)
2050
+ end
2051
+ end
2052
+
2053
+ assert_raises(RDL::Typecheck::StaticTypeError) {
2054
+ CompTypes.class_eval do
2055
+ type '(Integer, Integer) -> Integer', typecheck: :now
2056
+ def uses_baz3(x, y)
2057
+ baz(x, y)
2058
+ end
2059
+ end
2060
+ }
2061
+
2062
+ end
1658
2063
  end