rdl 2.1.0 → 2.2.0

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