typed.rb 0.0.11

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 (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