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,288 @@
1
+ require_relative '../../spec_helper'
2
+
3
+ describe TypedRb::Types::TyGenericSingletonObject do
4
+ let(:language) { TypedRb::Language.new }
5
+
6
+ it 'materializes a correctly typed generic type' do
7
+
8
+ expr = <<__CODE
9
+ ts 'type GW1[T]'
10
+ class GW1
11
+
12
+ ts '#f / -> [T]'
13
+ def f
14
+ 2
15
+ end
16
+ end
17
+
18
+ GW1.(Integer)
19
+ __CODE
20
+
21
+ result = language.check(expr)
22
+ expect(result.type_vars.first.lower_bound.ruby_type).to eq(Integer)
23
+ expect(result.type_vars.first.upper_bound.ruby_type).to eq(Integer)
24
+ end
25
+
26
+ it 'materializes a correctly typed generic type and subtype' do
27
+
28
+ expr = <<__CODE
29
+ ts 'type GW2[T]'
30
+ class GW2
31
+
32
+ ts '#f / -> [T]'
33
+ def f
34
+ 2
35
+ end
36
+ end
37
+
38
+ GW2.(Numeric)
39
+ __CODE
40
+
41
+ result = language.check(expr)
42
+ expect(result.type_vars.first.lower_bound.ruby_type).to eq(Numeric)
43
+ expect(result.type_vars.first.upper_bound.ruby_type).to eq(Numeric)
44
+ end
45
+
46
+ it 'catches inconsistencies in the type application' do
47
+
48
+ expr = <<__CODE
49
+ ts 'type GW3[T]'
50
+ class GW3
51
+
52
+ ts '#f / -> [T]'
53
+ def f
54
+ 2
55
+ end
56
+ end
57
+
58
+ GW3.(String)
59
+ __CODE
60
+
61
+ expect {
62
+ language.check(expr)
63
+ }.to raise_error(TypedRb::Types::Polymorphism::UnificationError)
64
+ end
65
+
66
+ context 'with complex bounds in the argument type' do
67
+
68
+ it 'parses the type correctly upper bound' do
69
+ expr = <<__CODE
70
+ ts 'type GColl1[T]'
71
+ class GColl1
72
+
73
+ ts '#add / [T] -> unit'
74
+ def add(x)
75
+ @val = x
76
+ end
77
+
78
+ ts '#pop / -> [T]'
79
+ def pop
80
+ @val
81
+ end
82
+ end
83
+
84
+ GColl1.('[? < Numeric]')
85
+ __CODE
86
+ result = language.check(expr)
87
+ expect(result.type_vars.first.upper_bound.ruby_type).to eq(Numeric) # -> we can assign -> X = pop() -> X ALWAYS Numeric or greater
88
+ expect(result.type_vars.first.lower_bound).to be_nil # -> we cannot add -> add(X) : X lt NIL -> error
89
+ end
90
+
91
+ it 'parses the type correctly with lower bound' do
92
+ expr = <<__CODE
93
+ ts 'type GColl2[T]'
94
+ class GColl2
95
+
96
+ ts '#add / [T] -> unit'
97
+ def add(x)
98
+ @val = x
99
+ end
100
+
101
+ ts '#pop / -> [T]'
102
+ def pop
103
+ @val
104
+ end
105
+ end
106
+
107
+ GColl2.('[? > Numeric]')
108
+ __CODE
109
+ result = language.check(expr)
110
+ expect(result.type_vars.first.upper_bound).to be_nil # -> we cannot assign -> X = pop() -> X gt NIL -> error
111
+ expect(result.type_vars.first.lower_bound.ruby_type).to eq(Numeric) # -> we can add -> add(X) : X ALWAYS Numeric or smaller
112
+ end
113
+
114
+ it 'detects type errors with upper bounds' do
115
+ expr = <<__CODE
116
+ class AG1
117
+ ts '#ag1 / -> unit'
118
+ def ag1;
119
+ end
120
+ end
121
+
122
+ class AG2 < AG1
123
+ ts '#ag2 / -> unit'
124
+ def ag2
125
+ end
126
+ end
127
+
128
+ class AG3 < AG2; end
129
+
130
+ ts 'type GW6[T]'
131
+ class GW6
132
+
133
+ ts '#ag2_thing / AG2 -> unit'
134
+ def ag2_thing(ag2); end
135
+
136
+ ts '#f / [T] -> [T]'
137
+ def f(x)
138
+ AG2.new
139
+ end
140
+ end
141
+
142
+ GW6.('[? < AG3]')
143
+ __CODE
144
+ expect {
145
+ language.check(expr)
146
+ }.to raise_error(TypedRb::Types::Polymorphism::UnificationError)
147
+ end
148
+
149
+ it 'materializes a correctly typed generic type and subtype with different bounds' do
150
+
151
+ expr = <<__CODE
152
+ ts 'type GColl3[T]'
153
+ class GColl3
154
+
155
+ ts '#add / [T] -> unit'
156
+ def add(x)
157
+ @val = x
158
+ end
159
+
160
+ ts '#pop / -> [T]'
161
+ def pop
162
+ 2
163
+ end
164
+ end
165
+
166
+ GColl3.('[? < Numeric]')
167
+ __CODE
168
+
169
+ result = language.check(expr)
170
+ expect(result.type_vars.first.upper_bound.ruby_type).to eq(Numeric) # -> X pop() -> X > Numeric
171
+ expect(result.type_vars.first.lower_bound.ruby_type).to eq(Integer) # -> add(X) -> X < Integer
172
+
173
+ expr = <<__CODE
174
+ ts 'type GW8[T]'
175
+ class GW8
176
+
177
+ ts '#f / -> [T]'
178
+ def f
179
+ 2
180
+ end
181
+ end
182
+
183
+ GW8.('[? > Numeric]')
184
+ __CODE
185
+
186
+ result = language.check(expr)
187
+ expect(result.type_vars.first.upper_bound).to be_nil
188
+ expect(result.type_vars.first.lower_bound.ruby_type).to eq(Numeric)
189
+
190
+ expr = <<__CODE
191
+ ts 'type GW9[T]'
192
+ class GW9
193
+
194
+ ts '#f / -> [T]'
195
+ def f
196
+ 2
197
+ end
198
+
199
+ ts '#id / [T] -> [T]'
200
+ def id(x); x; end
201
+ end
202
+
203
+ GW9.('[? < Numeric]')
204
+ __CODE
205
+
206
+ result = language.check(expr)
207
+ expect(result.type_vars.first.upper_bound.ruby_type).to eq(Numeric)
208
+ expect(result.type_vars.first.lower_bound.ruby_type).to eq(Integer)
209
+ end
210
+ end
211
+
212
+ context 'mixing generic type definition constraints and instantiation constraints' do
213
+
214
+ it 'materializes generic types when passed as arguments' do
215
+
216
+ expr = <<__CODE
217
+ ts 'type GColl4[T]'
218
+ class GColl4
219
+
220
+ ts '#add / [T] -> unit'
221
+ def add(x)
222
+ @val = x
223
+ end
224
+
225
+ ts '#pop / -> [T]'
226
+ def pop
227
+ Numeric.new
228
+ end
229
+ end
230
+
231
+ ts '#test_fun / GColl4[? < Integer] -> unit'
232
+ def test_fun(x)
233
+ x.add(1)
234
+ end
235
+ __CODE
236
+ expect {
237
+ language.check(expr)
238
+ }.to raise_error(TypedRb::Types::Polymorphism::UnificationError,
239
+ /Numeric is not a subtype of Integer/)
240
+ end
241
+
242
+ it 'materializes generic types when found in arguments sent with a message' do
243
+
244
+ expr = <<__CODE
245
+ ts 'type GColl5[T]'
246
+ class GColl5
247
+
248
+ ts '#add / [T] -> unit'
249
+ def add(x)
250
+ @val = x
251
+ end
252
+
253
+ ts '#pop / -> [T]'
254
+ def pop
255
+ Numeric.new
256
+ end
257
+ end
258
+
259
+ ts '#test_fun2 / Object -> unit'
260
+ def test_fun2(x)
261
+ x
262
+ end
263
+
264
+ test_fun2(GColl5.('[? < Integer]').new)
265
+ __CODE
266
+ expect {
267
+ language.check(expr)
268
+ }.to raise_error(TypedRb::Types::Polymorphism::UnificationError,
269
+ /Numeric is not a subtype of Integer/)
270
+ end
271
+
272
+ it 'supports nested type parameters' do
273
+
274
+ expr = <<__CODE
275
+ ts 'type GColl6[T]'
276
+ class GColl6
277
+ ts '#id / [T] -> [T]'
278
+ def id(x); x; end
279
+ end
280
+
281
+ GColl6.('Array[Array[Integer]]')
282
+ __CODE
283
+
284
+ result = language.check(expr)
285
+ expect(result.to_s).to eq('GColl6[Array[Array[Integer]]]')
286
+ end
287
+ end
288
+ end
@@ -0,0 +1,86 @@
1
+ require_relative '../../spec_helper'
2
+
3
+ describe TypedRb::Types::TypingContext do
4
+
5
+ describe '.type_variable_for' do
6
+ before do
7
+ described_class.type_variables_register.clear
8
+ end
9
+
10
+ it 'should register and find an instance variable for a ruby type' do
11
+ result = described_class.type_variable_for(:instance_variable, '@a', tyobject(Integer).hierarchy)
12
+ expect(result).to be_a(TypedRb::Types::Polymorphism::TypeVariable)
13
+ result2 = described_class.type_variable_for(:instance_variable, '@a', tyobject(Integer).hierarchy)
14
+ expect(result).to eq(result2)
15
+ end
16
+
17
+ it 'should find instance variables in the class hierarchy' do
18
+ result = described_class.type_variable_for(:instance_variable, '@a', tyobject(Numeric).hierarchy)
19
+ result2 = described_class.type_variable_for(:instance_variable, '@a', tyobject(Integer).hierarchy)
20
+ expect(result).to eq(result2)
21
+ end
22
+
23
+ it 'should not mix instance variables with the same name for different classes' do
24
+ result = described_class.type_variable_for(:instance_variable, '@a', tyobject(Integer).hierarchy)
25
+ result2 = described_class.type_variable_for(:instance_variable, '@a', tyobject(String).hierarchy)
26
+ expect(result).to_not eq(result2)
27
+ end
28
+ end
29
+
30
+ describe 'namespaces' do
31
+ eval('module TCNS1; AC=0; module TCNS2; class A; end; class B; BC=1; end; end; end;')
32
+
33
+ before do
34
+ described_class.namespace.clear
35
+ end
36
+
37
+ it 'works like a stack' do
38
+ expect(described_class.namespace.count).to eq(0)
39
+ described_class.namespace_push('TCNS1')
40
+ described_class.namespace_push('TCNS2')
41
+ described_class.namespace_push('A')
42
+
43
+ expect(described_class.namespace).to eq(['TCNS1', 'TCNS2', 'A'])
44
+
45
+ described_class.namespace_pop
46
+ described_class.namespace_pop
47
+ described_class.namespace_pop
48
+ expect(described_class.namespace.count).to eq(0)
49
+ end
50
+
51
+ it 'handles compound class names' do
52
+ expect(described_class.namespace.count).to eq(0)
53
+ described_class.namespace_push('TCNS1')
54
+ described_class.namespace_push('TCNS2::A')
55
+
56
+ expect(described_class.namespace).to eq(['TCNS1', 'TCNS2', 'A'])
57
+ end
58
+
59
+ it 'is able to find nested classes' do
60
+ expect(described_class.namespace.count).to eq(0)
61
+ described_class.namespace_push('TCNS1')
62
+ described_class.namespace_push('TCNS2')
63
+
64
+ result = described_class.find_namespace('A')
65
+ expect(result).to eq(TCNS1::TCNS2::A)
66
+
67
+ result = described_class.find_namespace('AC')
68
+ expect(result).to eq(TCNS1::AC)
69
+
70
+ result = described_class.find_namespace('B::BC')
71
+ expect(result).to eq(TCNS1::TCNS2::B::BC)
72
+
73
+ result = described_class.find_namespace('TCNS2::B::BC')
74
+ expect(result).to eq(TCNS1::TCNS2::B::BC)
75
+
76
+ result = described_class.find_namespace('::String')
77
+ expect(result).to eq(String)
78
+
79
+ result = described_class.find_namespace('TCNS1::TCNS2::B::BC')
80
+ expect(result).to eq(TCNS1::TCNS2::B::BC)
81
+
82
+ result = described_class.find_namespace('::TCNS1::TCNS2::B::BC')
83
+ expect(result).to eq(TCNS1::TCNS2::B::BC)
84
+ end
85
+ end
86
+ end
@@ -0,0 +1,174 @@
1
+ require_relative '../spec_helper'
2
+
3
+ describe TypedRb::Types::TyObject do
4
+ let(:ty_object) { TypedRb::Types::TyObject.new(Object) }
5
+ let(:ty_numeric) { TypedRb::Types::TyObject.new(Numeric) }
6
+ let(:ty_integer) { TypedRb::Types::TyObject.new(Integer) }
7
+ let(:ty_string) { tyobject(String) }
8
+
9
+ it 'is possible to compare TyObjects' do
10
+
11
+ expect(ty_object > ty_numeric).to be_truthy
12
+ expect(ty_numeric > ty_integer).to be_truthy
13
+ expect(ty_object > ty_integer).to be_truthy
14
+
15
+ expect(ty_object >= ty_numeric).to be_truthy
16
+ expect(ty_object >= ty_object).to be_truthy
17
+ expect(ty_numeric >= ty_integer).to be_truthy
18
+ expect(ty_numeric >= ty_numeric).to be_truthy
19
+ expect(ty_object >= ty_integer).to be_truthy
20
+ expect(ty_object >= ty_object).to be_truthy
21
+
22
+ expect(ty_numeric < ty_object).to be_truthy
23
+ expect(ty_integer < ty_numeric).to be_truthy
24
+ expect(ty_integer < ty_object).to be_truthy
25
+
26
+ expect{ ty_string < ty_integer }.to raise_error ArgumentError
27
+ expect{ ty_integer < ty_string }.to raise_error ArgumentError
28
+ expect{ ty_string > ty_integer }.to raise_error ArgumentError
29
+ expect{ ty_integer > ty_string }.to raise_error ArgumentError
30
+
31
+
32
+ expect(ty_numeric <= ty_numeric).to be_truthy
33
+ expect(ty_integer <= ty_integer).to be_truthy
34
+ expect(ty_object <= ty_object).to be_truthy
35
+
36
+ expect(ty_numeric >= ty_numeric).to be_truthy
37
+ expect(ty_integer >= ty_integer).to be_truthy
38
+ expect(ty_object >= ty_object).to be_truthy
39
+
40
+
41
+ expect([ty_numeric, ty_integer, ty_object].sort).to eq([ty_integer, ty_numeric, ty_object])
42
+ end
43
+
44
+ it 'is possible to compare if two objects are compatible' do
45
+ expect(ty_object.compatible?(ty_numeric, :gt)).to be_truthy
46
+ expect(ty_object.compatible?(ty_numeric, :lt)).to be_falsey
47
+ expect(ty_object.compatible?(ty_numeric, :lt)).to be_falsey
48
+ expect(ty_object.compatible?(ty_numeric, :gt)).to be_truthy
49
+ end
50
+
51
+ describe '#find_function_type' do
52
+ before :each do
53
+ ::BasicObject::TypeRegistry.clear
54
+ end
55
+
56
+ it 'it can find methods in the base and super classes' do
57
+ $TYPECHECK = true
58
+ code = <<__CODE
59
+
60
+ class A1
61
+ ts 'A1#a / String -> unit'
62
+ def a(s); puts 'a'; end
63
+ end
64
+
65
+ class B1 < A1
66
+ ts 'B1#b / Numeric -> unit'
67
+ def b(n); puts 'a'; end
68
+ end
69
+ __CODE
70
+
71
+ eval(code)
72
+ ::BasicObject::TypeRegistry.normalize_types!
73
+
74
+ ty_b = described_class.new(B1)
75
+
76
+ klass, method = ty_b.find_function_type(:a, 1, false)
77
+ expect(method.to_s).to eq('(String -> NilClass)')
78
+ expect(klass).to eq(A1)
79
+
80
+ klass, method = ty_b.find_function_type(:b, 1, false)
81
+ expect(method.to_s).to eq('(Numeric -> NilClass)')
82
+ expect(klass).to eq(B1)
83
+ end
84
+
85
+ it 'can find methods with functions as arguments' do
86
+ $TYPECHECK = true
87
+ code = <<__CODE
88
+
89
+ class A1
90
+ ts '#a / String -> (String -> String) -> unit'
91
+ def a(s,f); f(s); end
92
+ end
93
+ __CODE
94
+
95
+ eval(code)
96
+ ::BasicObject::TypeRegistry.normalize_types!
97
+
98
+ ty_b = described_class.new(B1)
99
+
100
+ klass, method = ty_b.find_function_type(:a, 2, false)
101
+ function = method.from[1]
102
+ expect(function).to be_instance_of(TypedRb::Types::TyFunction)
103
+ expect(function.from.size).to eq(1)
104
+ expect(function.from[0]).to eq(ty_string)
105
+ expect(function.to).to eq(ty_string)
106
+ expect(klass).to eq(A1)
107
+ end
108
+
109
+ context 'with multiple signatures including block types' do
110
+ it 'find both versions with and without block type' do
111
+ $TYPECHECK = false
112
+ eval 'class A2; def t(x); end; end'
113
+ $TYPECHECK = true
114
+ code = <<__CODE
115
+ class A2
116
+ ts '#t / Integer -> Integer'
117
+ ts '#t / Integer -> &(Integer -> String) -> String'
118
+ end
119
+ __CODE
120
+
121
+ eval(code)
122
+ ::BasicObject::TypeRegistry.normalize_types!
123
+
124
+ ty_b = described_class.new(A2)
125
+
126
+ _, method = ty_b.find_function_type(:t, 1, false)
127
+ expect(method.from.count).to eq(1)
128
+ expect(method.block_type).to be_nil
129
+ expect(method.to.ruby_type).to eq(Integer)
130
+
131
+ _, method = ty_b.find_function_type(:t, 1, true)
132
+ expect(method.from.count).to eq(1)
133
+ expect(method.block_type).to_not be_nil
134
+ expect(method.to.ruby_type).to eq(String)
135
+ end
136
+ end
137
+ end
138
+
139
+ describe('#parse') do
140
+ before :each do
141
+ ::BasicObject::TypeRegistry.clear
142
+ end
143
+
144
+ context 'with a generic type' do
145
+
146
+ it 'should parse a generic singleton class if it the var is not bound' do
147
+ $TYPECHECK = true
148
+ code = <<__CODE
149
+
150
+ ts 'type A2[T]'
151
+ class A2
152
+ ts '#a / [T]... -> unit'
153
+ def a(*xs); end
154
+ end
155
+ __CODE
156
+
157
+ eval(code)
158
+ ::BasicObject::TypeRegistry.normalize_types!
159
+
160
+ result = TypedRb::Runtime::TypeParser.parse({:type => 'Array',
161
+ :parameters => [{:type=>"T", :bound=>"BasicObject", :kind=>:type_var}],
162
+ :kind => :rest}, A2)
163
+ expect(result).to be_instance_of(TypedRb::Types::TyGenericSingletonObject)
164
+ expect(result.type_vars[0].bound).to be_nil
165
+
166
+ result = TypedRb::Runtime::TypeParser.parse({:type => 'Array',
167
+ :parameters => ['Integer'],
168
+ :kind => :rest}, A2)
169
+ expect(result).to be_instance_of(TypedRb::Types::TyGenericObject)
170
+ expect(result.type_vars[0].bound.ruby_type).to eq(Integer)
171
+ end
172
+ end
173
+ end
174
+ end
@@ -0,0 +1,134 @@
1
+ require_relative '../../spec_helper'
2
+
3
+ describe 'boolean assign operations' do
4
+ let(:language) { TypedRb::Language.new }
5
+
6
+ context 'with instance level variables' do
7
+ it 'type-checks boolean assignment operations' do
8
+ expr = <<__END
9
+ class BAsgn1
10
+ ts '#test / -> Integer'
11
+ def test
12
+ @test ||= 1
13
+ end
14
+ end
15
+
16
+ BAsgn1.new.test
17
+ __END
18
+
19
+ result = language.check(expr)
20
+ expect(result.ruby_type).to eq(Integer)
21
+ end
22
+
23
+ it 'detects type errors' do
24
+
25
+ expr = <<__END
26
+ class BAsgn1
27
+ ts '#test / -> String'
28
+ def test
29
+ @test = 1
30
+ @test ||= 'string'
31
+ end
32
+ end
33
+
34
+ BAsgn1.new.test
35
+ __END
36
+
37
+ expect {
38
+ language.check(expr)
39
+ }.to raise_error(TypedRb::Types::Polymorphism::UnificationError)
40
+ end
41
+ end
42
+
43
+ context 'with global variables' do
44
+ it 'type-checks boolean assignment operations' do
45
+ expr = <<__END
46
+ $VAR_BASGN ||= 3
47
+ $VAR_BASGN
48
+ __END
49
+
50
+ result = language.check(expr)
51
+ expect(result.bound.ruby_type).to eq(Integer)
52
+ end
53
+
54
+ it 'type-checks boolean && assignment operations' do
55
+
56
+ expr = <<__END
57
+ $VAR_BASGN = 3
58
+ $VAR_BASGN &&= Numeric.new
59
+ __END
60
+
61
+ result = language.check(expr)
62
+ expect(result.bound.ruby_type).to eq(Numeric)
63
+ end
64
+ end
65
+
66
+ context 'with local variables' do
67
+ it 'type-checks boolean assignment operations' do
68
+ expr = <<__END
69
+ var ||= 3
70
+ var
71
+ __END
72
+ result = language.check(expr)
73
+ expect(result.ruby_type).to eq(Integer)
74
+ end
75
+
76
+ it 'detects type errors' do
77
+ expr = <<__END
78
+ var ||= 3
79
+ var = Numeric.new
80
+ var
81
+ __END
82
+ expect {
83
+ language.check(expr)
84
+ }.to raise_error(TypedRb::Types::UncomparableTypes)
85
+ end
86
+ end
87
+
88
+ context 'with attr_readers/attr_writers' do
89
+ it 'type-checks boolean assignment operations' do
90
+ expr = <<__END
91
+ class BAsgn2
92
+ ts '#t / -> Integer'
93
+ def t
94
+ @t
95
+ end
96
+
97
+ ts '#t= / Integer -> Integer'
98
+ def t=(t)
99
+ @t = t
100
+ end
101
+ end
102
+
103
+ ba2 = BAsgn2.new
104
+
105
+ ba2.t ||= 3
106
+ __END
107
+ result = language.check(expr)
108
+ expect(result.ruby_type).to eq(Integer)
109
+ end
110
+
111
+ it 'detects type errors' do
112
+ expr = <<__END
113
+ class BAsgn3
114
+ ts '#t / -> String'
115
+ def t
116
+ @t
117
+ end
118
+
119
+ ts '#t= / Integer -> Integer'
120
+ def t=(t)
121
+ @t = t
122
+ end
123
+ end
124
+
125
+ ba3 = BAsgn3.new
126
+
127
+ ba3.t ||= 3
128
+ __END
129
+ expect {
130
+ language.check(expr)
131
+ }.to raise_error(TypedRb::Types::UncomparableTypes)
132
+ end
133
+ end
134
+ end