typed.rb 0.0.11

Sign up to get free protection for your applications and to get access to all the features.
Files changed (173) hide show
  1. checksums.yaml +7 -0
  2. data/Rakefile +26 -0
  3. data/bin/typed.rb +110 -0
  4. data/lib/typed/language.rb +131 -0
  5. data/lib/typed/model/tm_abs.rb +104 -0
  6. data/lib/typed/model/tm_array_literal.rb +25 -0
  7. data/lib/typed/model/tm_boolean.rb +15 -0
  8. data/lib/typed/model/tm_boolean_operator.rb +34 -0
  9. data/lib/typed/model/tm_break.rb +24 -0
  10. data/lib/typed/model/tm_case_when.rb +38 -0
  11. data/lib/typed/model/tm_class.rb +63 -0
  12. data/lib/typed/model/tm_const.rb +29 -0
  13. data/lib/typed/model/tm_defined.rb +19 -0
  14. data/lib/typed/model/tm_error.rb +16 -0
  15. data/lib/typed/model/tm_float.rb +15 -0
  16. data/lib/typed/model/tm_for.rb +42 -0
  17. data/lib/typed/model/tm_fun.rb +165 -0
  18. data/lib/typed/model/tm_global_var.rb +22 -0
  19. data/lib/typed/model/tm_global_var_assignment.rb +20 -0
  20. data/lib/typed/model/tm_hash_literal.rb +32 -0
  21. data/lib/typed/model/tm_if_else.rb +24 -0
  22. data/lib/typed/model/tm_instance_var.rb +23 -0
  23. data/lib/typed/model/tm_instance_var_assignment.rb +32 -0
  24. data/lib/typed/model/tm_int.rb +15 -0
  25. data/lib/typed/model/tm_local_var_asgn.rb +35 -0
  26. data/lib/typed/model/tm_mass_asgn.rb +60 -0
  27. data/lib/typed/model/tm_mlhs.rb +87 -0
  28. data/lib/typed/model/tm_module.rb +51 -0
  29. data/lib/typed/model/tm_next.rb +24 -0
  30. data/lib/typed/model/tm_nil.rb +14 -0
  31. data/lib/typed/model/tm_range_literal.rb +30 -0
  32. data/lib/typed/model/tm_regexp.rb +27 -0
  33. data/lib/typed/model/tm_rescue.rb +27 -0
  34. data/lib/typed/model/tm_return.rb +24 -0
  35. data/lib/typed/model/tm_s_class.rb +30 -0
  36. data/lib/typed/model/tm_self.rb +22 -0
  37. data/lib/typed/model/tm_send.rb +300 -0
  38. data/lib/typed/model/tm_sequencing.rb +53 -0
  39. data/lib/typed/model/tm_string.rb +15 -0
  40. data/lib/typed/model/tm_string_interpolation.rb +21 -0
  41. data/lib/typed/model/tm_super.rb +27 -0
  42. data/lib/typed/model/tm_symbol.rb +15 -0
  43. data/lib/typed/model/tm_symbol_interpolation.rb +21 -0
  44. data/lib/typed/model/tm_try.rb +29 -0
  45. data/lib/typed/model/tm_var.rb +28 -0
  46. data/lib/typed/model/tm_while.rb +43 -0
  47. data/lib/typed/model.rb +48 -0
  48. data/lib/typed/prelude.rb +939 -0
  49. data/lib/typed/prelude_existential_registry.bin +0 -0
  50. data/lib/typed/prelude_generic_registry.bin +0 -0
  51. data/lib/typed/prelude_registry.bin +0 -0
  52. data/lib/typed/runtime/ast_parser.rb +589 -0
  53. data/lib/typed/runtime/method_signature_processor.rb +72 -0
  54. data/lib/typed/runtime/normalization/validations.rb +47 -0
  55. data/lib/typed/runtime/normalization.rb +196 -0
  56. data/lib/typed/runtime/parser_context.rb +36 -0
  57. data/lib/typed/runtime/type_parser.rb +215 -0
  58. data/lib/typed/runtime/type_registry.rb +170 -0
  59. data/lib/typed/runtime/type_signature_processor.rb +34 -0
  60. data/lib/typed/runtime.rb +33 -0
  61. data/lib/typed/type_signature/parser.rb +240 -0
  62. data/lib/typed/types/polymorphism/existential_type_variable.rb +13 -0
  63. data/lib/typed/types/polymorphism/generic_comparisons.rb +134 -0
  64. data/lib/typed/types/polymorphism/generic_variables.rb +24 -0
  65. data/lib/typed/types/polymorphism/type_variable.rb +138 -0
  66. data/lib/typed/types/polymorphism/type_variable_register.rb +298 -0
  67. data/lib/typed/types/polymorphism/unification.rb +579 -0
  68. data/lib/typed/types/ty_boolean.rb +15 -0
  69. data/lib/typed/types/ty_dynamic.rb +39 -0
  70. data/lib/typed/types/ty_either.rb +168 -0
  71. data/lib/typed/types/ty_error.rb +18 -0
  72. data/lib/typed/types/ty_existential_type.rb +22 -0
  73. data/lib/typed/types/ty_function.rb +144 -0
  74. data/lib/typed/types/ty_generic_function.rb +115 -0
  75. data/lib/typed/types/ty_generic_object.rb +180 -0
  76. data/lib/typed/types/ty_generic_singleton_object.rb +238 -0
  77. data/lib/typed/types/ty_object.rb +256 -0
  78. data/lib/typed/types/ty_singleton_object.rb +78 -0
  79. data/lib/typed/types/ty_stack_jump.rb +44 -0
  80. data/lib/typed/types/ty_top_level_object.rb +38 -0
  81. data/lib/typed/types.rb +60 -0
  82. data/lib/typed/typing_context.rb +206 -0
  83. data/lib/typed/version.rb +3 -0
  84. data/lib/typed.rb +161 -0
  85. data/spec/lib/ast_parser_spec.rb +101 -0
  86. data/spec/lib/examples/animals.rb +44 -0
  87. data/spec/lib/examples/counter.rb +16 -0
  88. data/spec/lib/examples/if.rb +31 -0
  89. data/spec/lib/language_spec.rb +36 -0
  90. data/spec/lib/model/tm_abs_spec.rb +66 -0
  91. data/spec/lib/model/tm_array_literal_spec.rb +36 -0
  92. data/spec/lib/model/tm_case_when_spec.rb +39 -0
  93. data/spec/lib/model/tm_class_spec.rb +67 -0
  94. data/spec/lib/model/tm_defined_spec.rb +10 -0
  95. data/spec/lib/model/tm_for_spec.rb +150 -0
  96. data/spec/lib/model/tm_fun_spec.rb +11 -0
  97. data/spec/lib/model/tm_hash_literal_spec.rb +40 -0
  98. data/spec/lib/model/tm_mass_asgn_spec.rb +104 -0
  99. data/spec/lib/model/tm_module_spec.rb +42 -0
  100. data/spec/lib/model/tm_regexp_spec.rb +9 -0
  101. data/spec/lib/model/tm_return_spec.rb +47 -0
  102. data/spec/lib/model/tm_s_class_spec.rb +27 -0
  103. data/spec/lib/model/tm_self_spec.rb +19 -0
  104. data/spec/lib/model/tm_string_interpolation_spec.rb +10 -0
  105. data/spec/lib/model/tm_symbol_interpolation_spec.rb +10 -0
  106. data/spec/lib/model/tm_symbol_spec.rb +9 -0
  107. data/spec/lib/model/tm_while_spec.rb +141 -0
  108. data/spec/lib/polymorphism/type_variable_spec.rb +14 -0
  109. data/spec/lib/polymorphism/unification_spec.rb +328 -0
  110. data/spec/lib/prelude/array_spec.rb +263 -0
  111. data/spec/lib/prelude/class_spec.rb +12 -0
  112. data/spec/lib/prelude/enumerable_spec.rb +278 -0
  113. data/spec/lib/prelude/enumerator_spec.rb +101 -0
  114. data/spec/lib/prelude/hash_spec.rb +361 -0
  115. data/spec/lib/prelude/kernel_spec.rb +23 -0
  116. data/spec/lib/prelude/object_spec.rb +22 -0
  117. data/spec/lib/prelude/pair_spec.rb +16 -0
  118. data/spec/lib/prelude/showable_spec.rb +31 -0
  119. data/spec/lib/prelude/string_spec.rb +98 -0
  120. data/spec/lib/runtime/normalization_spec.rb +29 -0
  121. data/spec/lib/runtime/validations_spec.rb +56 -0
  122. data/spec/lib/runtime_spec.rb +503 -0
  123. data/spec/lib/type_signature/parser_spec.rb +239 -0
  124. data/spec/lib/types/comparisons_spec.rb +35 -0
  125. data/spec/lib/types/polymorphism/generic_comparisons_spec.rb +492 -0
  126. data/spec/lib/types/polymorphism/type_variable_register_spec.rb +128 -0
  127. data/spec/lib/types/ty_dynamic_spec.rb +103 -0
  128. data/spec/lib/types/ty_either_spec.rb +288 -0
  129. data/spec/lib/types/ty_error_spec.rb +18 -0
  130. data/spec/lib/types/ty_generic_object_spec.rb +78 -0
  131. data/spec/lib/types/ty_generic_singleton_object_spec.rb +288 -0
  132. data/spec/lib/types/typing_context_spec.rb +86 -0
  133. data/spec/lib/types_spec.rb +174 -0
  134. data/spec/lib/typing/boolean_asgn_spec.rb +134 -0
  135. data/spec/lib/typing/break_spec.rb +79 -0
  136. data/spec/lib/typing/generics_spec.rb +191 -0
  137. data/spec/lib/typing/instance_vars_spec.rb +103 -0
  138. data/spec/lib/typing/next_spec.rb +29 -0
  139. data/spec/lib/typing/op_asgn_spec.rb +104 -0
  140. data/spec/lib/typing/overriden_methods_spec.rb +31 -0
  141. data/spec/lib/typing/subtyping_spec.rb +112 -0
  142. data/spec/lib/typing/tm_boolean_operator_spec.rb +100 -0
  143. data/spec/lib/typing/tm_boolean_spec.rb +61 -0
  144. data/spec/lib/typing/tm_const_spec.rb +28 -0
  145. data/spec/lib/typing/tm_defined_spec.rb +12 -0
  146. data/spec/lib/typing/tm_fun_spec.rb +347 -0
  147. data/spec/lib/typing/tm_global_var_spec.rb +33 -0
  148. data/spec/lib/typing/tm_if_else_spec.rb +104 -0
  149. data/spec/lib/typing/tm_ignore_spec.rb +24 -0
  150. data/spec/lib/typing/tm_instance_vars_spec.rb +117 -0
  151. data/spec/lib/typing/tm_local_var_asgn_spec.rb +134 -0
  152. data/spec/lib/typing/tm_mlhs_spec.rb +164 -0
  153. data/spec/lib/typing/tm_module_spec.rb +89 -0
  154. data/spec/lib/typing/tm_raise_spec.rb +31 -0
  155. data/spec/lib/typing/tm_range_literal_spec.rb +25 -0
  156. data/spec/lib/typing/tm_regexp_spec.rb +14 -0
  157. data/spec/lib/typing/tm_return_spec.rb +45 -0
  158. data/spec/lib/typing/tm_send_casting_spec.rb +26 -0
  159. data/spec/lib/typing/tm_send_class_methods_spec.rb +42 -0
  160. data/spec/lib/typing/tm_send_generic_apply_spec.rb +103 -0
  161. data/spec/lib/typing/tm_send_generic_methods_spec.rb +77 -0
  162. data/spec/lib/typing/tm_send_initialize_spec.rb +68 -0
  163. data/spec/lib/typing/tm_send_lambda_spec.rb +135 -0
  164. data/spec/lib/typing/tm_send_spec.rb +217 -0
  165. data/spec/lib/typing/tm_send_yield_block_spec.rb +308 -0
  166. data/spec/lib/typing/tm_sequencing_spec.rb +174 -0
  167. data/spec/lib/typing/tm_string_interpolation_spec.rb +19 -0
  168. data/spec/lib/typing/tm_super_spec.rb +63 -0
  169. data/spec/lib/typing/tm_symbol_interpolation_spec.rb +19 -0
  170. data/spec/lib/typing/tm_symbol_spec.rb +14 -0
  171. data/spec/lib/typing/tm_try_spec.rb +73 -0
  172. data/spec/spec_helper.rb +140 -0
  173. metadata +216 -0
@@ -0,0 +1,103 @@
1
+ require_relative '../../spec_helper'
2
+
3
+ describe TypedRb::Model::TmSend do
4
+ let(:language) { TypedRb::Language.new }
5
+
6
+ context 'with a generic type' do
7
+ it 'creates the correct materialised type' do
8
+ code = <<__CODE
9
+ ts 'type Pod1[X<Numeric]'
10
+ class Pod1
11
+
12
+ ts '#initialize / [X] -> unit'
13
+ def initialize(x)
14
+ @value = x
15
+ end
16
+ ts '#get / -> [X]'
17
+ def get
18
+ @value
19
+ end
20
+
21
+ ts '#put / [X] -> unit'
22
+ def put(x)
23
+ @value = x
24
+ end
25
+
26
+ end
27
+
28
+ Pod1.(Integer)
29
+ __CODE
30
+
31
+ result = language.check(code)
32
+ expect(result.type_vars[0].bound.ruby_type).to eq(Integer)
33
+ end
34
+
35
+ it 'captures type errors in the materialization' do
36
+
37
+ code = <<__CODE
38
+ ts 'type Pod2[X<Numeric]'
39
+ class Pod2
40
+
41
+ ts '#initialize / -> unit'
42
+ def initialize
43
+ @value = base
44
+ end
45
+
46
+ ts '#base / -> Float'
47
+ def base
48
+ 1.0
49
+ end
50
+
51
+ ts '#get / -> [X]'
52
+ def get
53
+ @value
54
+ end
55
+
56
+ ts '#put / [X] -> unit'
57
+ def put(x)
58
+ @value = x
59
+ end
60
+
61
+ end
62
+ __CODE
63
+
64
+ expect {
65
+ language.check("#{code}; Pod2.(Integer)")
66
+ }.to raise_error(TypedRb::TypeCheckError)
67
+
68
+ result = language.check("#{code}; Pod2.(Float)")
69
+ expect(result.type_vars[0].bound.ruby_type).to eq(Float)
70
+ end
71
+
72
+ it 'returns the right type information for materialised methods' do
73
+
74
+ code = <<__CODE
75
+ ts 'type Pod3[X<Numeric]'
76
+ class Pod3
77
+
78
+ ts '#initialize / [X] -> unit'
79
+ def initialize(x)
80
+ @value = x
81
+ end
82
+
83
+ ts '#get / -> [X]'
84
+ def get
85
+ @value
86
+ end
87
+
88
+ ts '#put / [X] -> unit'
89
+ def put(x)
90
+ @value = x
91
+ end
92
+ end
93
+ __CODE
94
+
95
+ expect {
96
+ language.check("#{code}; p = Pod3.(Integer).new(0.0); p.put(2.0)")
97
+ }.to raise_error(TypedRb::TypeCheckError)
98
+
99
+ result = language.check("#{code}; p = Pod3.(Integer).new(0); p.put(2); p.get")
100
+ expect(result.ruby_type).to eq(Integer)
101
+ end
102
+ end
103
+ end
@@ -0,0 +1,77 @@
1
+ require_relative '../../spec_helper'
2
+
3
+ describe TypedRb::Model::TmSend do
4
+ let(:language) { TypedRb::Language.new }
5
+
6
+ it 'applies arguments to generic methods' do
7
+ code = <<__END
8
+ ts '#trs / Boolean -> String -> Integer'
9
+ def trs(a,b); 2; end
10
+
11
+ class TestGM1
12
+ ts '#gm[T][E] / [T] -> &([T] -> [E]) -> [E]'
13
+ def gm(t)
14
+ yield t
15
+ end
16
+ end
17
+
18
+ a = TestGM1.new.gm(true) { |t| false }
19
+ b = TestGM1.new.gm(1) { |t| 'string' }
20
+
21
+ trs(a,b)
22
+ __END
23
+ result = language.check(code)
24
+ expect(result.ruby_type).to eq(Integer)
25
+ end
26
+
27
+ it 'applies arguments to generic methods mixing class and method type variables' do
28
+ code = <<__END
29
+ ts 'type TestGM2Array[T]'
30
+ class TestGM2Array
31
+
32
+ ts '#initialize / [T] -> unit'
33
+ def initialize(t)
34
+ @t = t
35
+ end
36
+
37
+ ts '#map[E] / [T] -> Array[T] -> &([T] -> [E]) -> Array[E]'
38
+ def map(x, xs)
39
+ c = Array.('[E]').new
40
+ c << yield(@t)
41
+ c
42
+ end
43
+ end
44
+
45
+ ts '#c / String -> Integer'
46
+ def c(x)
47
+ 0
48
+ end
49
+
50
+ TestGM2Array.(Integer).new(1).map(1, nil) { |v| v + 1 }
51
+ TestGM2Array.(String).new('value').map('other', nil) { |v| c(v) }
52
+ __END
53
+ result = language.check(code)
54
+ expect(result.ruby_type).to eq(Array)
55
+ expect(result.type_vars[0].bound.ruby_type).to eq(Integer)
56
+ end
57
+
58
+ it 'type checks the body of generic methods' do
59
+ code = <<__END
60
+ class TestGM3
61
+
62
+ ts '#test[E] / [E] -> Array[E]'
63
+ def test(e)
64
+ es = Array.('[E]').new
65
+ es << e
66
+ es
67
+ end
68
+ end
69
+
70
+ TestGM3.new.test(2)
71
+ TestGM3.new.test('value')
72
+ __END
73
+ result = language.check(code)
74
+ expect(result.ruby_type).to eq(Array)
75
+ expect(result.type_vars[0].bound.ruby_type).to eq(String)
76
+ end
77
+ end
@@ -0,0 +1,68 @@
1
+ require_relative '../../spec_helper'
2
+
3
+ describe TypedRb::Model::TmSend do
4
+
5
+ before :each do
6
+ ::BasicObject::TypeRegistry.clear
7
+ end
8
+
9
+ let(:code) do
10
+ text =<<__CODE
11
+ class A
12
+
13
+ ts '#initialize / Integer -> unit'
14
+ def initialize(num)
15
+ 'String'
16
+ end
17
+
18
+ ts '#a / -> Integer'
19
+ def a
20
+ 1
21
+ end
22
+
23
+ end
24
+
25
+ a = A.new(3)
26
+ A.new(a.a)
27
+ __CODE
28
+ text
29
+ end
30
+
31
+ let(:typed_code) do
32
+ $TYPECHECK = true
33
+ eval(code, TOPLEVEL_BINDING)
34
+ ::BasicObject::TypeRegistry.normalize_types!
35
+ code
36
+ end
37
+
38
+ let(:ast) do
39
+ TypedRb::Model::GenSym.reset
40
+ parser = TypedRb::AstParser.new
41
+ parser.parse(typed_code)
42
+ end
43
+
44
+ context 'with validly typed code' do
45
+ it 'type checks a method and method application' do
46
+ type = ast.check_type(TypedRb::Types::TypingContext.new)
47
+ expect(type.to_s).to eq("A")
48
+ end
49
+ end
50
+
51
+ context 'within the class context' do
52
+ let(:code) do
53
+ text = <<__CODE
54
+ class TSICC
55
+
56
+ T = new
57
+ end
58
+
59
+ TSICC::T
60
+ __CODE
61
+ end
62
+
63
+ it 'it type checks the initialization correctly' do
64
+ type = ast.check_type(TypedRb::Types::TypingContext.new)
65
+ expect(type.to_s).to eq("TSICC")
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,135 @@
1
+ require_relative '../../spec_helper'
2
+
3
+ describe TypedRb::Model::TmSend do
4
+ let(:language) { TypedRb::Language.new }
5
+
6
+ context 'with lambda functions' do
7
+ it 'evaluates lambda functions applications' do
8
+ expr = <<__END
9
+ id = ->(x) { x }
10
+ id[1]
11
+ __END
12
+
13
+ result = language.check(expr)
14
+ expect(result).to eq(tyinteger)
15
+
16
+ expr = <<__END
17
+ id = ->(x) { x }
18
+ id[1]
19
+ id['string']
20
+ __END
21
+
22
+ result = language.check(expr)
23
+ expect(result).to eq(tystring)
24
+ end
25
+
26
+ it 'evaluates lambda functions with either types' do
27
+ expr = <<__END
28
+ f = ->() do
29
+ if(true)
30
+ 1.0
31
+ else
32
+ return 2
33
+ end
34
+ end
35
+ f[]
36
+ __END
37
+ result = language.check(expr)
38
+ expect(result.to_s).to eq('Numeric')
39
+ end
40
+
41
+ it 'evaluates lambda functions with either types including break type' do
42
+ expr = <<__END
43
+ f = ->() do
44
+ if(true)
45
+ 1.0
46
+ else
47
+ break 2
48
+ end
49
+ end
50
+ f[]
51
+ __END
52
+ result = language.check(expr)
53
+ expect(result).to be_instance_of(TypedRb::Types::TyEither)
54
+ expect(result[:normal].to_s).to eq('Float')
55
+ expect(result[:break].to_s).to eq('Jump[break:Integer]')
56
+ end
57
+
58
+ it 'evaluates lambda functions applications with message sending inside' do
59
+ expr = <<__END
60
+ class Integer
61
+ ts '#+ / Integer -> Integer'
62
+ end
63
+
64
+ class String
65
+ ts '#+ / String -> String'
66
+ end
67
+
68
+ add = ->(x,y) { x + y }
69
+ add[1,2]
70
+ __END
71
+
72
+ result = language.check(expr)
73
+ expect(result).to eq(tyinteger)
74
+
75
+ expr = <<__END
76
+ class Integer
77
+ ts '#+ / Integer -> Integer'
78
+ end
79
+
80
+ class String
81
+ ts '#+ / String -> String'
82
+ end
83
+
84
+ add = ->(x,y) { x + y }
85
+ add[1,2]
86
+ add['hello','world']
87
+ __END
88
+
89
+ result = language.check(expr)
90
+ expect(result).to eq(tystring)
91
+
92
+ expr = <<__END
93
+ class Integer
94
+ ts '#foo / Integer -> String'
95
+ def foo(x); 'foo'; end
96
+ end
97
+
98
+ f = ->(x,y) { x.foo(y) }
99
+ f[1,2]
100
+ __END
101
+
102
+ result = language.check(expr)
103
+ expect(result).to eq(tystring)
104
+
105
+ end
106
+
107
+ it 'catches expcetions in lambda applications' do
108
+
109
+ expr = <<__END
110
+ class Integer
111
+ ts '#foo / String -> String'
112
+ def foo(x); 'foo'; end
113
+ end
114
+
115
+ f = ->(x,y) { x.foo(y) }
116
+ f[1,2]
117
+ __END
118
+ expect {
119
+ language.check(expr)
120
+ }.to raise_error(TypedRb::TypeCheckError)
121
+
122
+ expr = <<__END
123
+ class Integer
124
+ ts '#foo / String -> String'
125
+ def foo(x); 'foo'; end
126
+ end
127
+
128
+ f = ->(x,y) { x.foo(y) }
129
+ f[1,'bar']
130
+ __END
131
+ result = language.check(expr)
132
+ expect(result).to eq(tystring)
133
+ end
134
+ end
135
+ end
@@ -0,0 +1,217 @@
1
+ require_relative '../../spec_helper'
2
+
3
+ #TODO: parsing function will return a symbol, not the function
4
+ # some of this specs expectations need to change
5
+ describe TypedRb::Model::TmSend do
6
+ let(:language) { TypedRb::Language.new }
7
+
8
+ context 'with functions receiving function' do
9
+ it 'is possible to pass lambda functions as arguments' do
10
+ expr = <<__END
11
+ ts '#t / (String -> Integer) -> Integer'
12
+ def t(f)
13
+ f['test']
14
+ end
15
+
16
+ f = ->(s) { 0 }
17
+
18
+ t(f)
19
+ __END
20
+
21
+ result = language.check(expr)
22
+ expect(result).to eq(tyinteger)
23
+ end
24
+
25
+ it 'detects type check errors in the lambda functions passed as arguments' do
26
+
27
+ classes = <<__END
28
+ class Animal
29
+ ts '#initialize / -> unit'
30
+
31
+ ts '#animal / -> unit'
32
+ def animal; end
33
+ end
34
+
35
+ class Mammal < Animal
36
+ ts '#initialize / -> unit'
37
+
38
+ ts '#mammal / -> unit'
39
+ def mammal; end
40
+ end
41
+
42
+ class Cat < Mammal
43
+ ts '#initialize / -> unit'
44
+
45
+ ts '#cat / -> unit'
46
+ def cat; end
47
+ end
48
+ __END
49
+
50
+ expr = <<__END
51
+ #{classes}
52
+
53
+ ts '#t / (Mammal -> Integer) -> Integer'
54
+ def t(f)
55
+ f[Mammal.new]
56
+ end
57
+
58
+ f = ->(s=Mammal.new) { 1.0 }
59
+
60
+ t(f)
61
+ __END
62
+
63
+ expect {
64
+ language.check(expr)
65
+ }.to raise_error(TypedRb::TypeCheckError)
66
+ end
67
+
68
+ it 'respects contravariance in the input type' do
69
+
70
+ classes = <<__END
71
+ class Animal
72
+ ts '#initialize / -> unit'
73
+
74
+ ts '#animal / -> unit'
75
+ def animal; end
76
+ end
77
+
78
+ class Mammal < Animal
79
+ ts '#initialize / -> unit'
80
+
81
+ ts '#mammal / -> unit'
82
+ def mammal; end
83
+ end
84
+
85
+ class Cat < Mammal
86
+ ts '#initialize / -> unit'
87
+
88
+ ts '#cat / -> unit'
89
+ def cat; end
90
+ end
91
+ __END
92
+
93
+ expr = <<__END
94
+ #{classes}
95
+
96
+ ts '#t / (Mammal -> Integer) -> Integer'
97
+ def t(f)
98
+ f[Mammal.new]
99
+ end
100
+
101
+ lambda {
102
+ f = ->(s=Cat.new) { s.cat }
103
+ t(f)
104
+ }
105
+ __END
106
+
107
+ #expect {
108
+ language.check(expr)
109
+ #cat undefined for Mammal,
110
+ # s => cat s :gt Cat, s :gt Mammal
111
+ #}.to raise_error(TypedRb::TypeCheckError)
112
+
113
+ # TODO: review this?
114
+ # Actually the previous code does not
115
+ # throw an error because
116
+ # Mammal#cat is resolved into
117
+ # a Dynamic function instead of
118
+ # failing because no type information
119
+ # can be found.
120
+
121
+ expr = <<__END
122
+ #{classes}
123
+
124
+ ts '#mammal_to_i / (Mammal -> Integer) -> Integer'
125
+ def mammal_to_i(mammalf)
126
+ mammalf[Mammal.new]
127
+ end
128
+
129
+ ts '#cat_to_i / (Cat -> Integer) -> Integer'
130
+ def cat_to_i(catf)
131
+ mammal_to_i(catf)
132
+ end
133
+ __END
134
+ expect {
135
+ language.check(expr)
136
+ # Cat not >= Mammal
137
+ }.to raise_error(TypedRb::TypeCheckError)
138
+
139
+ expr = <<__END
140
+ #{classes}
141
+
142
+ ts '#mammal_to_i / (Mammal -> Integer) -> Integer'
143
+ def mammal_to_i(mammalf)
144
+ mammalf[Mammal.new]
145
+ end
146
+
147
+ ts '#animal_to_i / (Animal -> Integer) -> Integer'
148
+ def animal_to_i(animalf)
149
+ mammal_to_i(animalf)
150
+ end
151
+ __END
152
+ result = language.check(expr)
153
+ expect(result.to_s).to eq('((Animal -> Integer) -> Integer)')
154
+ end
155
+
156
+ it 'respects covariance in the output type' do
157
+
158
+ classes = <<__END
159
+ class Animal
160
+ ts '#initialize / -> unit'
161
+
162
+ ts '#animal / -> unit'
163
+ def animal; end
164
+ end
165
+
166
+ class Mammal < Animal
167
+ ts '#initialize / -> unit'
168
+
169
+ ts '#mammal / -> unit'
170
+ def mammal; end
171
+ end
172
+
173
+ class Cat < Mammal
174
+ ts '#initialize / -> unit'
175
+
176
+ ts '#cat / -> unit'
177
+ def cat; end
178
+ end
179
+ __END
180
+
181
+ expr = <<__END
182
+ #{classes}
183
+
184
+ ts '#integer_to_mammal / (Integer -> Mammal) -> Mammal'
185
+ def integer_to_mammal(mammalf)
186
+ mammalf[1]
187
+ end
188
+
189
+ ts '#integer_to_animal / (Integer -> Animal) -> Mammal'
190
+ def integer_to_animal(animalf)
191
+ integer_to_mammal(animalf)
192
+ end
193
+ __END
194
+ expect do
195
+ language.check(expr)
196
+ end.to raise_error(TypedRb::TypeCheckError)
197
+
198
+
199
+ expr = <<__END
200
+ #{classes}
201
+
202
+ ts '#integer_to_mammal / (Integer -> Mammal) -> Mammal'
203
+ def integer_to_mammal(mammalf)
204
+ mammalf[1]
205
+ end
206
+
207
+ ts '#integer_to_cat / (Integer -> Cat) -> Mammal'
208
+ def integer_to_cat(catf)
209
+ integer_to_mammal(catf)
210
+ end
211
+ __END
212
+
213
+ result = language.check(expr)
214
+ expect(result.to_s).to eq('((Integer -> Cat) -> Mammal)')
215
+ end
216
+ end
217
+ end