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.
- checksums.yaml +7 -0
- data/Rakefile +26 -0
- data/bin/typed.rb +110 -0
- data/lib/typed/language.rb +131 -0
- data/lib/typed/model/tm_abs.rb +104 -0
- data/lib/typed/model/tm_array_literal.rb +25 -0
- data/lib/typed/model/tm_boolean.rb +15 -0
- data/lib/typed/model/tm_boolean_operator.rb +34 -0
- data/lib/typed/model/tm_break.rb +24 -0
- data/lib/typed/model/tm_case_when.rb +38 -0
- data/lib/typed/model/tm_class.rb +63 -0
- data/lib/typed/model/tm_const.rb +29 -0
- data/lib/typed/model/tm_defined.rb +19 -0
- data/lib/typed/model/tm_error.rb +16 -0
- data/lib/typed/model/tm_float.rb +15 -0
- data/lib/typed/model/tm_for.rb +42 -0
- data/lib/typed/model/tm_fun.rb +165 -0
- data/lib/typed/model/tm_global_var.rb +22 -0
- data/lib/typed/model/tm_global_var_assignment.rb +20 -0
- data/lib/typed/model/tm_hash_literal.rb +32 -0
- data/lib/typed/model/tm_if_else.rb +24 -0
- data/lib/typed/model/tm_instance_var.rb +23 -0
- data/lib/typed/model/tm_instance_var_assignment.rb +32 -0
- data/lib/typed/model/tm_int.rb +15 -0
- data/lib/typed/model/tm_local_var_asgn.rb +35 -0
- data/lib/typed/model/tm_mass_asgn.rb +60 -0
- data/lib/typed/model/tm_mlhs.rb +87 -0
- data/lib/typed/model/tm_module.rb +51 -0
- data/lib/typed/model/tm_next.rb +24 -0
- data/lib/typed/model/tm_nil.rb +14 -0
- data/lib/typed/model/tm_range_literal.rb +30 -0
- data/lib/typed/model/tm_regexp.rb +27 -0
- data/lib/typed/model/tm_rescue.rb +27 -0
- data/lib/typed/model/tm_return.rb +24 -0
- data/lib/typed/model/tm_s_class.rb +30 -0
- data/lib/typed/model/tm_self.rb +22 -0
- data/lib/typed/model/tm_send.rb +300 -0
- data/lib/typed/model/tm_sequencing.rb +53 -0
- data/lib/typed/model/tm_string.rb +15 -0
- data/lib/typed/model/tm_string_interpolation.rb +21 -0
- data/lib/typed/model/tm_super.rb +27 -0
- data/lib/typed/model/tm_symbol.rb +15 -0
- data/lib/typed/model/tm_symbol_interpolation.rb +21 -0
- data/lib/typed/model/tm_try.rb +29 -0
- data/lib/typed/model/tm_var.rb +28 -0
- data/lib/typed/model/tm_while.rb +43 -0
- data/lib/typed/model.rb +48 -0
- data/lib/typed/prelude.rb +939 -0
- data/lib/typed/prelude_existential_registry.bin +0 -0
- data/lib/typed/prelude_generic_registry.bin +0 -0
- data/lib/typed/prelude_registry.bin +0 -0
- data/lib/typed/runtime/ast_parser.rb +589 -0
- data/lib/typed/runtime/method_signature_processor.rb +72 -0
- data/lib/typed/runtime/normalization/validations.rb +47 -0
- data/lib/typed/runtime/normalization.rb +196 -0
- data/lib/typed/runtime/parser_context.rb +36 -0
- data/lib/typed/runtime/type_parser.rb +215 -0
- data/lib/typed/runtime/type_registry.rb +170 -0
- data/lib/typed/runtime/type_signature_processor.rb +34 -0
- data/lib/typed/runtime.rb +33 -0
- data/lib/typed/type_signature/parser.rb +240 -0
- data/lib/typed/types/polymorphism/existential_type_variable.rb +13 -0
- data/lib/typed/types/polymorphism/generic_comparisons.rb +134 -0
- data/lib/typed/types/polymorphism/generic_variables.rb +24 -0
- data/lib/typed/types/polymorphism/type_variable.rb +138 -0
- data/lib/typed/types/polymorphism/type_variable_register.rb +298 -0
- data/lib/typed/types/polymorphism/unification.rb +579 -0
- data/lib/typed/types/ty_boolean.rb +15 -0
- data/lib/typed/types/ty_dynamic.rb +39 -0
- data/lib/typed/types/ty_either.rb +168 -0
- data/lib/typed/types/ty_error.rb +18 -0
- data/lib/typed/types/ty_existential_type.rb +22 -0
- data/lib/typed/types/ty_function.rb +144 -0
- data/lib/typed/types/ty_generic_function.rb +115 -0
- data/lib/typed/types/ty_generic_object.rb +180 -0
- data/lib/typed/types/ty_generic_singleton_object.rb +238 -0
- data/lib/typed/types/ty_object.rb +256 -0
- data/lib/typed/types/ty_singleton_object.rb +78 -0
- data/lib/typed/types/ty_stack_jump.rb +44 -0
- data/lib/typed/types/ty_top_level_object.rb +38 -0
- data/lib/typed/types.rb +60 -0
- data/lib/typed/typing_context.rb +206 -0
- data/lib/typed/version.rb +3 -0
- data/lib/typed.rb +161 -0
- data/spec/lib/ast_parser_spec.rb +101 -0
- data/spec/lib/examples/animals.rb +44 -0
- data/spec/lib/examples/counter.rb +16 -0
- data/spec/lib/examples/if.rb +31 -0
- data/spec/lib/language_spec.rb +36 -0
- data/spec/lib/model/tm_abs_spec.rb +66 -0
- data/spec/lib/model/tm_array_literal_spec.rb +36 -0
- data/spec/lib/model/tm_case_when_spec.rb +39 -0
- data/spec/lib/model/tm_class_spec.rb +67 -0
- data/spec/lib/model/tm_defined_spec.rb +10 -0
- data/spec/lib/model/tm_for_spec.rb +150 -0
- data/spec/lib/model/tm_fun_spec.rb +11 -0
- data/spec/lib/model/tm_hash_literal_spec.rb +40 -0
- data/spec/lib/model/tm_mass_asgn_spec.rb +104 -0
- data/spec/lib/model/tm_module_spec.rb +42 -0
- data/spec/lib/model/tm_regexp_spec.rb +9 -0
- data/spec/lib/model/tm_return_spec.rb +47 -0
- data/spec/lib/model/tm_s_class_spec.rb +27 -0
- data/spec/lib/model/tm_self_spec.rb +19 -0
- data/spec/lib/model/tm_string_interpolation_spec.rb +10 -0
- data/spec/lib/model/tm_symbol_interpolation_spec.rb +10 -0
- data/spec/lib/model/tm_symbol_spec.rb +9 -0
- data/spec/lib/model/tm_while_spec.rb +141 -0
- data/spec/lib/polymorphism/type_variable_spec.rb +14 -0
- data/spec/lib/polymorphism/unification_spec.rb +328 -0
- data/spec/lib/prelude/array_spec.rb +263 -0
- data/spec/lib/prelude/class_spec.rb +12 -0
- data/spec/lib/prelude/enumerable_spec.rb +278 -0
- data/spec/lib/prelude/enumerator_spec.rb +101 -0
- data/spec/lib/prelude/hash_spec.rb +361 -0
- data/spec/lib/prelude/kernel_spec.rb +23 -0
- data/spec/lib/prelude/object_spec.rb +22 -0
- data/spec/lib/prelude/pair_spec.rb +16 -0
- data/spec/lib/prelude/showable_spec.rb +31 -0
- data/spec/lib/prelude/string_spec.rb +98 -0
- data/spec/lib/runtime/normalization_spec.rb +29 -0
- data/spec/lib/runtime/validations_spec.rb +56 -0
- data/spec/lib/runtime_spec.rb +503 -0
- data/spec/lib/type_signature/parser_spec.rb +239 -0
- data/spec/lib/types/comparisons_spec.rb +35 -0
- data/spec/lib/types/polymorphism/generic_comparisons_spec.rb +492 -0
- data/spec/lib/types/polymorphism/type_variable_register_spec.rb +128 -0
- data/spec/lib/types/ty_dynamic_spec.rb +103 -0
- data/spec/lib/types/ty_either_spec.rb +288 -0
- data/spec/lib/types/ty_error_spec.rb +18 -0
- data/spec/lib/types/ty_generic_object_spec.rb +78 -0
- data/spec/lib/types/ty_generic_singleton_object_spec.rb +288 -0
- data/spec/lib/types/typing_context_spec.rb +86 -0
- data/spec/lib/types_spec.rb +174 -0
- data/spec/lib/typing/boolean_asgn_spec.rb +134 -0
- data/spec/lib/typing/break_spec.rb +79 -0
- data/spec/lib/typing/generics_spec.rb +191 -0
- data/spec/lib/typing/instance_vars_spec.rb +103 -0
- data/spec/lib/typing/next_spec.rb +29 -0
- data/spec/lib/typing/op_asgn_spec.rb +104 -0
- data/spec/lib/typing/overriden_methods_spec.rb +31 -0
- data/spec/lib/typing/subtyping_spec.rb +112 -0
- data/spec/lib/typing/tm_boolean_operator_spec.rb +100 -0
- data/spec/lib/typing/tm_boolean_spec.rb +61 -0
- data/spec/lib/typing/tm_const_spec.rb +28 -0
- data/spec/lib/typing/tm_defined_spec.rb +12 -0
- data/spec/lib/typing/tm_fun_spec.rb +347 -0
- data/spec/lib/typing/tm_global_var_spec.rb +33 -0
- data/spec/lib/typing/tm_if_else_spec.rb +104 -0
- data/spec/lib/typing/tm_ignore_spec.rb +24 -0
- data/spec/lib/typing/tm_instance_vars_spec.rb +117 -0
- data/spec/lib/typing/tm_local_var_asgn_spec.rb +134 -0
- data/spec/lib/typing/tm_mlhs_spec.rb +164 -0
- data/spec/lib/typing/tm_module_spec.rb +89 -0
- data/spec/lib/typing/tm_raise_spec.rb +31 -0
- data/spec/lib/typing/tm_range_literal_spec.rb +25 -0
- data/spec/lib/typing/tm_regexp_spec.rb +14 -0
- data/spec/lib/typing/tm_return_spec.rb +45 -0
- data/spec/lib/typing/tm_send_casting_spec.rb +26 -0
- data/spec/lib/typing/tm_send_class_methods_spec.rb +42 -0
- data/spec/lib/typing/tm_send_generic_apply_spec.rb +103 -0
- data/spec/lib/typing/tm_send_generic_methods_spec.rb +77 -0
- data/spec/lib/typing/tm_send_initialize_spec.rb +68 -0
- data/spec/lib/typing/tm_send_lambda_spec.rb +135 -0
- data/spec/lib/typing/tm_send_spec.rb +217 -0
- data/spec/lib/typing/tm_send_yield_block_spec.rb +308 -0
- data/spec/lib/typing/tm_sequencing_spec.rb +174 -0
- data/spec/lib/typing/tm_string_interpolation_spec.rb +19 -0
- data/spec/lib/typing/tm_super_spec.rb +63 -0
- data/spec/lib/typing/tm_symbol_interpolation_spec.rb +19 -0
- data/spec/lib/typing/tm_symbol_spec.rb +14 -0
- data/spec/lib/typing/tm_try_spec.rb +73 -0
- data/spec/spec_helper.rb +140 -0
- metadata +216 -0
@@ -0,0 +1,79 @@
|
|
1
|
+
require_relative '../../spec_helper'
|
2
|
+
|
3
|
+
describe ':break term' do
|
4
|
+
let(:language) { TypedRb::Language.new }
|
5
|
+
|
6
|
+
it 'is type checked correctly, positive case' do
|
7
|
+
code = <<__END
|
8
|
+
ts '#test_break / Integer -> &(Integer -> unit) -> Integer'
|
9
|
+
def test_break(x)
|
10
|
+
yield(x)
|
11
|
+
end
|
12
|
+
|
13
|
+
test_break(0) { |x| break(1) }
|
14
|
+
__END
|
15
|
+
|
16
|
+
result = language.check(code)
|
17
|
+
expect(result.to_s).to eq('Integer')
|
18
|
+
end
|
19
|
+
|
20
|
+
it 'is type checked correctly, no break value, positive case' do
|
21
|
+
code = <<__END
|
22
|
+
ts '#test_break / Integer -> &(Integer -> unit) -> Integer'
|
23
|
+
def test_break(x)
|
24
|
+
yield(x)
|
25
|
+
end
|
26
|
+
|
27
|
+
test_break(0) { |x| break }
|
28
|
+
__END
|
29
|
+
|
30
|
+
result = language.check(code)
|
31
|
+
expect(result.to_s).to eq('Integer')
|
32
|
+
end
|
33
|
+
|
34
|
+
it 'is type checked correctly, negative case' do
|
35
|
+
code = <<__END
|
36
|
+
ts '#test_break / Integer -> &(Integer -> unit) -> Integer'
|
37
|
+
def test_break(x)
|
38
|
+
yield(x)
|
39
|
+
end
|
40
|
+
|
41
|
+
test_break(0) { |x| break("") }
|
42
|
+
__END
|
43
|
+
|
44
|
+
expect {
|
45
|
+
language.check(code)
|
46
|
+
}.to raise_error(TypedRb::Types::UncomparableTypes)
|
47
|
+
end
|
48
|
+
|
49
|
+
context 'with not matching return type' do
|
50
|
+
it 'is type checked correctly, positive case' do
|
51
|
+
code = <<__END
|
52
|
+
ts '#test_break / Integer -> &(Integer -> Integer) -> Integer'
|
53
|
+
def test_break(x)
|
54
|
+
yield(x)
|
55
|
+
end
|
56
|
+
|
57
|
+
test_break(0) { |x| break(1) }
|
58
|
+
__END
|
59
|
+
|
60
|
+
result = language.check(code)
|
61
|
+
expect(result.to_s).to eq('Integer')
|
62
|
+
end
|
63
|
+
|
64
|
+
it 'is type checked correctly, negative case' do
|
65
|
+
code = <<__END
|
66
|
+
ts '#test_break / Integer -> &(String -> Integer) -> Integer'
|
67
|
+
def test_break(x)
|
68
|
+
yield(x)
|
69
|
+
end
|
70
|
+
|
71
|
+
test_break(0) { |x| break(1) }
|
72
|
+
__END
|
73
|
+
|
74
|
+
expect {
|
75
|
+
language.check(code)
|
76
|
+
}.to raise_error(TypedRb::Types::UncomparableTypes)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
@@ -0,0 +1,191 @@
|
|
1
|
+
require_relative '../../spec_helper'
|
2
|
+
|
3
|
+
describe 'generics use caes' do
|
4
|
+
let(:language) { TypedRb::Language.new }
|
5
|
+
|
6
|
+
it 'applies arguments to generic types' do
|
7
|
+
code = <<__END
|
8
|
+
ts 'type TestGen1[T]'
|
9
|
+
class TestGen1
|
10
|
+
ts '#gm / [T] -> [T]'
|
11
|
+
def gm(t)
|
12
|
+
t
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
TestGen1.(String).new.gm('string')
|
17
|
+
__END
|
18
|
+
result = language.check(code)
|
19
|
+
expect(result.ruby_type).to eq(String)
|
20
|
+
|
21
|
+
code = <<__END
|
22
|
+
ts 'type TestGen1[T]'
|
23
|
+
class TestGen1
|
24
|
+
ts '#gm / [T] -> &([T] -> [T]) -> [T]'
|
25
|
+
def gm(t)
|
26
|
+
yield t
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
TestGen1.(String).new.gm('string') { |t| 'string' }
|
31
|
+
__END
|
32
|
+
result = language.check(code)
|
33
|
+
expect(result.ruby_type).to eq(String)
|
34
|
+
|
35
|
+
code = <<__END
|
36
|
+
ts 'type TestGen1[T]'
|
37
|
+
class TestGen1
|
38
|
+
ts '#gm / [T] -> &([T] -> [T]) -> [T]'
|
39
|
+
def gm(t)
|
40
|
+
yield t
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
TestGen1.(String).new.gm('string') { |t| 2 }
|
45
|
+
__END
|
46
|
+
|
47
|
+
expect do
|
48
|
+
language.check(code)
|
49
|
+
end.to raise_error(TypedRb::TypeCheckError)
|
50
|
+
end
|
51
|
+
|
52
|
+
|
53
|
+
it 'applies arguments to generic types without implementation' do
|
54
|
+
code = <<__END
|
55
|
+
xs = Array.(String).new
|
56
|
+
xs << 'string'
|
57
|
+
xs.at(0)
|
58
|
+
__END
|
59
|
+
result = language.check(code)
|
60
|
+
expect(result.ruby_type).to eq(String)
|
61
|
+
|
62
|
+
code = <<__END
|
63
|
+
xs = Array.(String).new
|
64
|
+
xs << 2
|
65
|
+
xs.at(0)
|
66
|
+
__END
|
67
|
+
|
68
|
+
expect do
|
69
|
+
language.check(code)
|
70
|
+
end.to raise_error(TypedRb::TypeCheckError)
|
71
|
+
end
|
72
|
+
|
73
|
+
it 'materializes generic types using type variables' do
|
74
|
+
code = <<__END
|
75
|
+
ts 'type TestGen2[T]'
|
76
|
+
class TestGen2
|
77
|
+
|
78
|
+
ts '#gm / [T] -> Array[T]'
|
79
|
+
def gm(x)
|
80
|
+
xs = Array.('[T]').new
|
81
|
+
xs << x
|
82
|
+
xs
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
TestGen2.(String).new.gm('x')
|
87
|
+
__END
|
88
|
+
|
89
|
+
result = language.check(code)
|
90
|
+
expect(result.to_s).to eq('Array[String]')
|
91
|
+
end
|
92
|
+
|
93
|
+
it 'detects errors materializing generic types using type variables' do
|
94
|
+
code = <<__END
|
95
|
+
ts 'type TestGen2[T][U]'
|
96
|
+
class TestGen2
|
97
|
+
|
98
|
+
ts '#gm / [T] -> [U] -> Array[T]'
|
99
|
+
def gm(x,y)
|
100
|
+
xs = Array.('[T]').new
|
101
|
+
xs << y
|
102
|
+
xs
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
TestGen2.(String,Integer).new.gm('x',2)
|
107
|
+
__END
|
108
|
+
|
109
|
+
expect do
|
110
|
+
language.check(code)
|
111
|
+
end.to raise_error(TypedRb::TypeCheckError,
|
112
|
+
/TestGen2\:T\:\:\[\?,\?\] expected, TestGen2\:U\:\:\[\?,\?\]/)
|
113
|
+
end
|
114
|
+
|
115
|
+
it 'type-checks correctly super type generics' do
|
116
|
+
code = <<__END
|
117
|
+
class Array
|
118
|
+
ts '#last / Integer... -> [T]'
|
119
|
+
end
|
120
|
+
|
121
|
+
ts 'type MyContainerG1[T] super Array[Object]'
|
122
|
+
class MyContainerG1 < Array
|
123
|
+
ts '#first / -> [T]'
|
124
|
+
end
|
125
|
+
|
126
|
+
MyContainerG1.(String).new.last
|
127
|
+
__END
|
128
|
+
|
129
|
+
result = language.check(code)
|
130
|
+
expect(result.ruby_type).to eq(Object)
|
131
|
+
end
|
132
|
+
|
133
|
+
it 'type-checks correctly super type generics detecting type errors based on the super-type parameter' do
|
134
|
+
code = <<__END
|
135
|
+
ts 'type BaseGen1[T]'
|
136
|
+
class BaseGen1
|
137
|
+
ts '#getString / -> String'
|
138
|
+
def getString
|
139
|
+
'a string'
|
140
|
+
end
|
141
|
+
|
142
|
+
ts '#in_subclass / -> [T]'
|
143
|
+
def in_subclass
|
144
|
+
getString
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
ts 'type MyContainerG2[T] super BaseGen1[String]'
|
149
|
+
class MyContainerG2 < BaseGen1
|
150
|
+
end
|
151
|
+
|
152
|
+
ts 'type MyContainerG3[T] super BaseGen1[Integer]'
|
153
|
+
class MyContainerG3 < BaseGen1
|
154
|
+
end
|
155
|
+
__END
|
156
|
+
|
157
|
+
expect do
|
158
|
+
language.check(code)
|
159
|
+
end.to raise_error(TypedRb::Types::UncomparableTypes,
|
160
|
+
/Cannot compare types Object with.*Integer/)
|
161
|
+
end
|
162
|
+
|
163
|
+
it 'type-checks correctly super type generics detecting type errors based on the super-type parameter on type instantiation' do
|
164
|
+
code = <<__END
|
165
|
+
ts 'type BaseGen2[T]'
|
166
|
+
class BaseGen2
|
167
|
+
ts '#getString / -> String'
|
168
|
+
def getString
|
169
|
+
'a string'
|
170
|
+
end
|
171
|
+
|
172
|
+
ts '#in_subclass / -> [T]'
|
173
|
+
def in_subclass
|
174
|
+
getString
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
ts 'type MyContainerG4[T] super BaseGen2[T]'
|
179
|
+
class MyContainerG4 < BaseGen2
|
180
|
+
end
|
181
|
+
BaseGen2.(String).new
|
182
|
+
MyContainerG4.(Integer).new
|
183
|
+
__END
|
184
|
+
|
185
|
+
expect do
|
186
|
+
language.check(code)
|
187
|
+
end.to raise_error(TypedRb::Types::UncomparableTypes,
|
188
|
+
/Cannot compare types Object with.*Integer/)
|
189
|
+
end
|
190
|
+
|
191
|
+
end
|
@@ -0,0 +1,103 @@
|
|
1
|
+
require_relative '../../spec_helper'
|
2
|
+
|
3
|
+
describe 'instance vars' do
|
4
|
+
let(:language) { TypedRb::Language.new }
|
5
|
+
|
6
|
+
it 'types correctly instance vars, case 1' do
|
7
|
+
code = <<__END
|
8
|
+
class TestIVar
|
9
|
+
|
10
|
+
ts '#gm1 / -> Integer'
|
11
|
+
def gm1
|
12
|
+
@a = 1
|
13
|
+
end
|
14
|
+
|
15
|
+
ts '#gm2 / -> String'
|
16
|
+
def gm2
|
17
|
+
@a = 'hey'
|
18
|
+
'hey'
|
19
|
+
end
|
20
|
+
|
21
|
+
ts '#gm3 / -> Object'
|
22
|
+
def gm3
|
23
|
+
@a
|
24
|
+
end
|
25
|
+
end
|
26
|
+
__END
|
27
|
+
|
28
|
+
language.check(code)
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'types correctly instance vars, positive case 2' do
|
32
|
+
code = <<__END
|
33
|
+
class TestIVar
|
34
|
+
|
35
|
+
ts '#gm1 / -> Integer'
|
36
|
+
def gm1
|
37
|
+
@a = 1
|
38
|
+
end
|
39
|
+
|
40
|
+
ts '#gm2 / -> String'
|
41
|
+
def gm2
|
42
|
+
@a = 'hey'
|
43
|
+
'hey'
|
44
|
+
end
|
45
|
+
|
46
|
+
ts '#gm3 / -> Float'
|
47
|
+
def gm3
|
48
|
+
@a
|
49
|
+
end
|
50
|
+
end
|
51
|
+
__END
|
52
|
+
|
53
|
+
expect {
|
54
|
+
language.check(code)
|
55
|
+
}.to raise_error(TypedRb::Types::Polymorphism::UnificationError)
|
56
|
+
end
|
57
|
+
|
58
|
+
it 'types correctly instance vars, positive case 3' do
|
59
|
+
code = <<__END
|
60
|
+
class TestIVar
|
61
|
+
|
62
|
+
ts '#gm1 / -> Integer'
|
63
|
+
def gm1
|
64
|
+
@a = 1
|
65
|
+
end
|
66
|
+
|
67
|
+
ts '#gm2 / -> String'
|
68
|
+
def gm2
|
69
|
+
@a = 'hey'
|
70
|
+
'hey'
|
71
|
+
end
|
72
|
+
end
|
73
|
+
__END
|
74
|
+
|
75
|
+
expect {
|
76
|
+
language.check(code)
|
77
|
+
}.not_to raise_error
|
78
|
+
end
|
79
|
+
|
80
|
+
|
81
|
+
it 'types correctly instance vars, positive case 5' do
|
82
|
+
code = <<__END
|
83
|
+
class TestIVar5
|
84
|
+
ts '#gm1 / -> Integer'
|
85
|
+
def gm1
|
86
|
+
@a = 1
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
class TestIVar5
|
91
|
+
ts '#gm2 / -> String'
|
92
|
+
def gm2
|
93
|
+
@a = 'hey'
|
94
|
+
@a
|
95
|
+
end
|
96
|
+
end
|
97
|
+
__END
|
98
|
+
|
99
|
+
expect {
|
100
|
+
language.check(code)
|
101
|
+
}.to raise_error
|
102
|
+
end
|
103
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require_relative '../../spec_helper'
|
2
|
+
|
3
|
+
describe ':next term' do
|
4
|
+
let(:language) { TypedRb::Language.new }
|
5
|
+
|
6
|
+
it 'is type checked correctly, positive case' do
|
7
|
+
code = <<__END
|
8
|
+
[1,2,3,4].map { |i| next(i * 2) }
|
9
|
+
__END
|
10
|
+
|
11
|
+
result = language.check(code)
|
12
|
+
expect(result.to_s).to eq('Array[Integer]')
|
13
|
+
end
|
14
|
+
|
15
|
+
it 'is type checked correctly, negative case' do
|
16
|
+
code = <<__END
|
17
|
+
ts '#test_break / Integer -> &(Integer -> Integer) -> Integer'
|
18
|
+
def test_break(x)
|
19
|
+
yield(x)
|
20
|
+
end
|
21
|
+
|
22
|
+
test_break(0) { |x| next("") }
|
23
|
+
__END
|
24
|
+
|
25
|
+
expect {
|
26
|
+
language.check(code)
|
27
|
+
}.to raise_error(TypedRb::Types::UncomparableTypes)
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,104 @@
|
|
1
|
+
require_relative '../../spec_helper'
|
2
|
+
|
3
|
+
describe 'operator assign operations' do
|
4
|
+
let(:language) { TypedRb::Language.new }
|
5
|
+
|
6
|
+
context 'with a local variable' do
|
7
|
+
it 'type checks assignment operations over local variables, positive case' do
|
8
|
+
expr = <<__CODE
|
9
|
+
a = 0
|
10
|
+
a += 1
|
11
|
+
__CODE
|
12
|
+
|
13
|
+
result = language.check(expr)
|
14
|
+
expect(result.ruby_type).to eq(Integer)
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'type checks assignment operations over local variables, negative case' do
|
18
|
+
expr = <<__CODE
|
19
|
+
class LocalVarTest
|
20
|
+
ts '#+ / LocalVarTest -> LocalVarTest'
|
21
|
+
def +(other)
|
22
|
+
self
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
ts '#x / -> LocalVarTest'
|
27
|
+
def x
|
28
|
+
a = LocalVarTest.new
|
29
|
+
a += 1
|
30
|
+
end
|
31
|
+
__CODE
|
32
|
+
|
33
|
+
expect {
|
34
|
+
language.check(expr)
|
35
|
+
}.to raise_error(TypedRb::Types::UncomparableTypes)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
context 'with an instance variable' do
|
40
|
+
it 'type checks assignment operations over instance variables, positive case' do
|
41
|
+
expr = <<__CODE
|
42
|
+
@a = 0
|
43
|
+
@a += 1
|
44
|
+
__CODE
|
45
|
+
result = language.check(expr)
|
46
|
+
expect(result.bound.ruby_type).to eq(Integer)
|
47
|
+
end
|
48
|
+
|
49
|
+
it 'type checks assignment operations over instance variables, negative case' do
|
50
|
+
expr = <<__CODE
|
51
|
+
class LocalVarTest
|
52
|
+
ts '#+ / LocalVarTest -> LocalVarTest'
|
53
|
+
def +(other)
|
54
|
+
self
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
ts '#x / -> LocalVarTest'
|
59
|
+
def x
|
60
|
+
@a = LocalVarTest.new
|
61
|
+
@a += 1
|
62
|
+
end
|
63
|
+
__CODE
|
64
|
+
|
65
|
+
expect {
|
66
|
+
language.check(expr)
|
67
|
+
}.to raise_error(TypedRb::Types::UncomparableTypes)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
context 'with a global variable' do
|
72
|
+
it 'type checks assignment operations over global variables, positive case' do
|
73
|
+
expr = <<__CODE
|
74
|
+
$TEST_GLOBAL_OPS = 0
|
75
|
+
$TEST_GLOBAL_OPS += 1
|
76
|
+
__CODE
|
77
|
+
result = language.check(expr)
|
78
|
+
expect(result.bound.ruby_type).to eq(Integer)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
context 'with a constant' do
|
83
|
+
it 'type checks assignment operations over global variables, positive case' do
|
84
|
+
expr = <<__CODE
|
85
|
+
TEST_GLOBAL_OPS = 0
|
86
|
+
TEST_GLOBAL_OPS += 1
|
87
|
+
__CODE
|
88
|
+
result = language.check(expr)
|
89
|
+
expect(result.ruby_type).to eq(Integer)
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
context 'with a message sent as the receiver' do
|
94
|
+
it 'type checks assignment operations over sending of messages, positive case' do
|
95
|
+
expr = <<__CODE
|
96
|
+
a = [1]
|
97
|
+
a[0] += 2
|
98
|
+
__CODE
|
99
|
+
|
100
|
+
result = language.check(expr)
|
101
|
+
expect(result.ruby_type).to eq(Object)
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require_relative '../../spec_helper'
|
2
|
+
|
3
|
+
describe TypedRb::Model::TmSend do
|
4
|
+
let(:language) { TypedRb::Language.new }
|
5
|
+
|
6
|
+
context 'with a function with multiple type signatures' do
|
7
|
+
it 'type checks methods with multiple type signatures' do
|
8
|
+
eval('class TOM1; def f(a, *args, &b); end; end')
|
9
|
+
|
10
|
+
base = <<__CODE
|
11
|
+
class TOM1
|
12
|
+
ts '#f / String -> Integer'
|
13
|
+
ts '#f / String -> Integer -> String'
|
14
|
+
end
|
15
|
+
|
16
|
+
__CODE
|
17
|
+
|
18
|
+
expr1 = "#{base}TOM1.new.f('a')"
|
19
|
+
result = language.check(expr1)
|
20
|
+
expect(result).to eq(tyinteger)
|
21
|
+
|
22
|
+
expr2 = "#{base}TOM1.new.f('a', 2)"
|
23
|
+
result = language.check(expr2)
|
24
|
+
expect(result).to eq(tystring)
|
25
|
+
|
26
|
+
expr3 = "#{base}TOM1.new.f('a', 2, nil)"
|
27
|
+
result = language.check(expr3)
|
28
|
+
expect(result).to eq(tydynamic)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,112 @@
|
|
1
|
+
require_relative '../../spec_helper'
|
2
|
+
|
3
|
+
describe TypedRb::Types::Type do
|
4
|
+
before :each do
|
5
|
+
::BasicObject::TypeRegistry.clear
|
6
|
+
end
|
7
|
+
|
8
|
+
let(:typed_code) do
|
9
|
+
$TYPECHECK = true
|
10
|
+
eval(code, TOPLEVEL_BINDING)
|
11
|
+
::BasicObject::TypeRegistry.normalize_types!
|
12
|
+
code
|
13
|
+
end
|
14
|
+
|
15
|
+
let(:ast) do
|
16
|
+
TypedRb::Model::GenSym.reset
|
17
|
+
parser = TypedRb::AstParser.new
|
18
|
+
parser.parse(typed_code)
|
19
|
+
end
|
20
|
+
|
21
|
+
context 'with valid exact type' do
|
22
|
+
let(:code) do
|
23
|
+
text = <<__CODE
|
24
|
+
ts '#test / Integer -> Integer'
|
25
|
+
def test(x)
|
26
|
+
x
|
27
|
+
end
|
28
|
+
__CODE
|
29
|
+
text
|
30
|
+
end
|
31
|
+
|
32
|
+
it 'should not raise a type error' do
|
33
|
+
expect do
|
34
|
+
ast.check_type(TypedRb::Types::TypingContext.top_level)
|
35
|
+
end.to_not raise_error
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
context 'with a super-type class' do
|
40
|
+
let(:code) do
|
41
|
+
text = <<__CODE
|
42
|
+
ts '#test / Integer -> Numeric'
|
43
|
+
def test(x)
|
44
|
+
x
|
45
|
+
end
|
46
|
+
__CODE
|
47
|
+
text
|
48
|
+
end
|
49
|
+
|
50
|
+
it 'should not raise a type error' do
|
51
|
+
expect do
|
52
|
+
ast.check_type(TypedRb::Types::TypingContext.top_level)
|
53
|
+
end.to_not raise_error
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
context 'with a super-type argument' do
|
58
|
+
let(:code) do
|
59
|
+
text = <<__CODE
|
60
|
+
ts '#test / Numeric -> Numeric'
|
61
|
+
def test(x)
|
62
|
+
x
|
63
|
+
end
|
64
|
+
|
65
|
+
test(1)
|
66
|
+
__CODE
|
67
|
+
text
|
68
|
+
end
|
69
|
+
|
70
|
+
it 'should not raise a type error' do
|
71
|
+
expect {
|
72
|
+
ast.check_type(TypedRb::Types::TypingContext.top_level)
|
73
|
+
}.to_not raise_error
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
context 'with a sub-type class' do
|
78
|
+
let(:code) do
|
79
|
+
text = <<__CODE
|
80
|
+
ts '#test / Numeric -> Integer'
|
81
|
+
def test(x)
|
82
|
+
x
|
83
|
+
end
|
84
|
+
__CODE
|
85
|
+
text
|
86
|
+
end
|
87
|
+
|
88
|
+
it 'should raise a type error' do
|
89
|
+
expect {
|
90
|
+
ast.check_type(TypedRb::Types::TypingContext.top_level)
|
91
|
+
}.to raise_error(TypedRb::TypeCheckError)
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
context 'with a sub-type optional argument' do
|
96
|
+
let(:code) do
|
97
|
+
text = <<__CODE
|
98
|
+
ts '#test / Numeric -> Numeric'
|
99
|
+
def test(x = 1)
|
100
|
+
x
|
101
|
+
end
|
102
|
+
__CODE
|
103
|
+
text
|
104
|
+
end
|
105
|
+
|
106
|
+
it 'should not raise a type error' do
|
107
|
+
expect do
|
108
|
+
ast.check_type(TypedRb::Types::TypingContext.top_level)
|
109
|
+
end.to_not raise_error
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|