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,117 @@
|
|
1
|
+
require_relative '../../spec_helper'
|
2
|
+
|
3
|
+
describe TypedRb::Model::TmInstanceVar do
|
4
|
+
|
5
|
+
before :each do
|
6
|
+
::BasicObject::TypeRegistry.clear
|
7
|
+
end
|
8
|
+
|
9
|
+
let(:code) do
|
10
|
+
text =<<__CODE
|
11
|
+
class A
|
12
|
+
ts '\#@a / Integer'
|
13
|
+
ts '#initialize / -> unit'
|
14
|
+
def initialize
|
15
|
+
@a = 'error'
|
16
|
+
end
|
17
|
+
end
|
18
|
+
__CODE
|
19
|
+
text
|
20
|
+
end
|
21
|
+
|
22
|
+
let(:typed_code) do
|
23
|
+
$TYPECHECK = true
|
24
|
+
eval(code, TOPLEVEL_BINDING)
|
25
|
+
::BasicObject::TypeRegistry.normalize_types!
|
26
|
+
code
|
27
|
+
end
|
28
|
+
|
29
|
+
let(:ast) do
|
30
|
+
TypedRb::Model::GenSym.reset
|
31
|
+
parser = TypedRb::AstParser.new
|
32
|
+
parser.parse(typed_code)
|
33
|
+
end
|
34
|
+
|
35
|
+
context 'with invalid type assignment' do
|
36
|
+
it 'should raise a type error' do
|
37
|
+
expect {
|
38
|
+
ast.check_type(TypedRb::Types::TypingContext.new)
|
39
|
+
}.to raise_error(TypedRb::Types::UncomparableTypes)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
context 'with valid type assignment' do
|
44
|
+
let(:code) do
|
45
|
+
text =<<__CODE
|
46
|
+
class A
|
47
|
+
ts '\#@a / Integer'
|
48
|
+
|
49
|
+
ts '#initialize / -> unit'
|
50
|
+
def initialize
|
51
|
+
@a = 10
|
52
|
+
a(@a)
|
53
|
+
end
|
54
|
+
|
55
|
+
ts '#a / Integer -> Integer'
|
56
|
+
def a(x)
|
57
|
+
x
|
58
|
+
end
|
59
|
+
end
|
60
|
+
__CODE
|
61
|
+
text
|
62
|
+
end
|
63
|
+
|
64
|
+
it 'should not raise a type error' do
|
65
|
+
expect {
|
66
|
+
ast.check_type(TypedRb::Types::TypingContext.new)
|
67
|
+
}.to_not raise_error
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
context 'with a valid singleton class instance variable' do
|
72
|
+
let(:code) do
|
73
|
+
<<__CODE
|
74
|
+
class A
|
75
|
+
ts '.@a / Integer'
|
76
|
+
|
77
|
+
ts 'A.a / -> Integer'
|
78
|
+
def self.a
|
79
|
+
@a
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
A.a
|
84
|
+
__CODE
|
85
|
+
end
|
86
|
+
|
87
|
+
it 'should not raise a type error' do
|
88
|
+
expect {
|
89
|
+
result = ast.check_type(TypedRb::Types::TypingContext.new)
|
90
|
+
expect(result.to_s).to eq('Integer')
|
91
|
+
}.to_not raise_error
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
context 'with an invalid type annotation' do
|
96
|
+
let(:code) do
|
97
|
+
<<__CODE
|
98
|
+
class A
|
99
|
+
ts '.@a / Integer'
|
100
|
+
|
101
|
+
ts 'A.a / -> String'
|
102
|
+
def self.a
|
103
|
+
@a
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
A.a
|
108
|
+
__CODE
|
109
|
+
end
|
110
|
+
|
111
|
+
it 'should raise a type error' do
|
112
|
+
expect {
|
113
|
+
result = ast.check_type(TypedRb::Types::TypingContext.new)
|
114
|
+
}.to raise_error(TypedRb::Types::UncomparableTypes)
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
@@ -0,0 +1,134 @@
|
|
1
|
+
require_relative '../../spec_helper'
|
2
|
+
|
3
|
+
describe TypedRb::Model::TmLocalVarAsgn do
|
4
|
+
before :each do
|
5
|
+
::BasicObject::TypeRegistry.clear
|
6
|
+
end
|
7
|
+
|
8
|
+
let(:code) do
|
9
|
+
text =<<__CODE
|
10
|
+
a = 3
|
11
|
+
a
|
12
|
+
__CODE
|
13
|
+
text
|
14
|
+
end
|
15
|
+
|
16
|
+
let(:typed_code) do
|
17
|
+
$TYPECHECK = true
|
18
|
+
eval(code, TOPLEVEL_BINDING)
|
19
|
+
::BasicObject::TypeRegistry.normalize_types!
|
20
|
+
code
|
21
|
+
end
|
22
|
+
|
23
|
+
let(:ast) do
|
24
|
+
TypedRb::Model::GenSym.reset
|
25
|
+
parser = TypedRb::AstParser.new
|
26
|
+
parser.parse(typed_code)
|
27
|
+
end
|
28
|
+
|
29
|
+
context 'with simple assignment' do
|
30
|
+
it 'should be possible to get the right type' do
|
31
|
+
type = ast.check_type(TypedRb::Types::TypingContext.top_level)
|
32
|
+
expect(type.to_s).to eq('Integer')
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
|
37
|
+
context 'with variable assignment' do
|
38
|
+
let(:code) do
|
39
|
+
text =<<__CODE
|
40
|
+
a = 3
|
41
|
+
b = a
|
42
|
+
b
|
43
|
+
__CODE
|
44
|
+
text
|
45
|
+
end
|
46
|
+
|
47
|
+
it 'should be possible to get the right type' do
|
48
|
+
type = ast.check_type(TypedRb::Types::TypingContext.top_level)
|
49
|
+
expect(type.to_s).to eq('Integer')
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
|
54
|
+
context 'with multiple variable assignment' do
|
55
|
+
let(:code) do
|
56
|
+
text =<<__CODE
|
57
|
+
a = 3
|
58
|
+
b = "blah"
|
59
|
+
a = b
|
60
|
+
a
|
61
|
+
__CODE
|
62
|
+
text
|
63
|
+
end
|
64
|
+
|
65
|
+
it 'should be possible to get the right type' do
|
66
|
+
expect {
|
67
|
+
ast.check_type(TypedRb::Types::TypingContext.top_level)
|
68
|
+
}.to raise_error(TypedRb::Types::UncomparableTypes)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
context 'in function application' do
|
73
|
+
context 'with correctly typed code' do
|
74
|
+
let(:code) do
|
75
|
+
<<__CODE
|
76
|
+
ts '#f / Integer -> String'
|
77
|
+
def f(x)
|
78
|
+
a = 'hola'
|
79
|
+
a
|
80
|
+
end
|
81
|
+
|
82
|
+
ts '#g / Integer -> String'
|
83
|
+
def g(y)
|
84
|
+
a = y
|
85
|
+
f(a)
|
86
|
+
end
|
87
|
+
__CODE
|
88
|
+
end
|
89
|
+
|
90
|
+
it 'should be possible to be passed as an argument to a function' do
|
91
|
+
expect {
|
92
|
+
ast.check_type(TypedRb::Types::TypingContext.top_level)
|
93
|
+
}.to_not raise_error
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
context 'with incorrectly typed code' do
|
98
|
+
let(:code) do
|
99
|
+
<<__CODE
|
100
|
+
ts '#f / String -> String'
|
101
|
+
def f(x)
|
102
|
+
x
|
103
|
+
end
|
104
|
+
|
105
|
+
ts '#g / Integer -> String'
|
106
|
+
def g(y)
|
107
|
+
a = y
|
108
|
+
f(a)
|
109
|
+
end
|
110
|
+
__CODE
|
111
|
+
end
|
112
|
+
|
113
|
+
it 'should be possible to check the error' do
|
114
|
+
expect {
|
115
|
+
ast.check_type(TypedRb::Types::TypingContext.top_level)
|
116
|
+
}.to raise_error(TypedRb::Types::UncomparableTypes)
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
context 'with variable assignment using casting' do
|
121
|
+
let(:code) do
|
122
|
+
<<__CODE
|
123
|
+
a = cast(1,Numeric)
|
124
|
+
a = 2.5
|
125
|
+
__CODE
|
126
|
+
end
|
127
|
+
|
128
|
+
it 'should be possible to be passed as an argument to a function using casting' do
|
129
|
+
result = ast.check_type(TypedRb::Types::TypingContext.top_level)
|
130
|
+
expect(result.ruby_type).to eq(Numeric)
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
@@ -0,0 +1,164 @@
|
|
1
|
+
require_relative '../../spec_helper'
|
2
|
+
|
3
|
+
describe TypedRb::Model::TmMlhs do
|
4
|
+
let(:language) { TypedRb::Language.new }
|
5
|
+
|
6
|
+
it 'type checks array args, positive case' do
|
7
|
+
code = <<__CODE
|
8
|
+
ts '#mlhsaddition / Integer -> Integer -> Integer'
|
9
|
+
def mlhsaddition(a,b); a + b; end
|
10
|
+
|
11
|
+
ts '#mlhstest1 / Array[Integer] -> Integer'
|
12
|
+
def mlhstest1((a,b))
|
13
|
+
mlhsaddition(a,b)
|
14
|
+
end
|
15
|
+
|
16
|
+
mlhstest1([1,2])
|
17
|
+
__CODE
|
18
|
+
|
19
|
+
result = language.check(code)
|
20
|
+
expect(result.ruby_type).to eq(Integer)
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'type checks array args, negative case' do
|
24
|
+
code = <<__CODE
|
25
|
+
ts '#mlhsaddition2 / String -> Integer'
|
26
|
+
def mlhsaddition2(a); 0; end
|
27
|
+
|
28
|
+
ts '#mlhstest2 / Array[Integer] -> Integer'
|
29
|
+
def mlhstest2((a,b))
|
30
|
+
mlhsaddition2(a)
|
31
|
+
end
|
32
|
+
|
33
|
+
mlhstest2([1,2])
|
34
|
+
__CODE
|
35
|
+
|
36
|
+
expect {
|
37
|
+
language.check(code)
|
38
|
+
}.to raise_error(TypedRb::Types::UncomparableTypes)
|
39
|
+
end
|
40
|
+
|
41
|
+
it 'type checks array Pair arg, positive case' do
|
42
|
+
code = <<__CODE
|
43
|
+
ts '#mlhstestpair1 / Pair[String][Integer] -> Integer'
|
44
|
+
def mlhstestpair1((a,b)); b; end
|
45
|
+
__CODE
|
46
|
+
|
47
|
+
expect {
|
48
|
+
language.check(code)
|
49
|
+
}.to_not raise_error
|
50
|
+
end
|
51
|
+
|
52
|
+
it 'type checks array Pair arg, negative case' do
|
53
|
+
code = <<__CODE
|
54
|
+
ts '#mlhstestpair1 / Pair[String][Integer] -> Integer'
|
55
|
+
def mlhstestpair1((a,b,c)); a; end
|
56
|
+
__CODE
|
57
|
+
|
58
|
+
expect {
|
59
|
+
language.check(code)
|
60
|
+
}.to raise_error(TypedRb::Types::UncomparableTypes)
|
61
|
+
end
|
62
|
+
|
63
|
+
it 'raises an error if the type of the argument is not an array or tuple' do
|
64
|
+
code = <<__CODE
|
65
|
+
ts '#mlhstest_error / Integer -> Integer'
|
66
|
+
def mlhstest_error((a,b))
|
67
|
+
a + b
|
68
|
+
end
|
69
|
+
__CODE
|
70
|
+
|
71
|
+
expect {
|
72
|
+
language.check(code)
|
73
|
+
}.to raise_error(TypedRb::TypeCheckError)
|
74
|
+
end
|
75
|
+
|
76
|
+
it 'type checks array args for blocks, positive case' do
|
77
|
+
code = <<__CODE
|
78
|
+
ts '#mlhsaddition3 / Integer -> Integer -> Integer'
|
79
|
+
def mlhsaddition3(a,b); a + b; end
|
80
|
+
|
81
|
+
ts '#mlhstest3 / Array[Integer] -> &(Array[Integer] -> Integer) -> Integer'
|
82
|
+
def mlhstest3(a)
|
83
|
+
yield a
|
84
|
+
end
|
85
|
+
|
86
|
+
mlhstest3([1,2]) { |(a,b)| mlhsaddition3(a,b) }
|
87
|
+
__CODE
|
88
|
+
|
89
|
+
result = language.check(code)
|
90
|
+
expect(result.ruby_type).to eq(Integer)
|
91
|
+
end
|
92
|
+
|
93
|
+
it 'type checks array args for blocks, negative case' do
|
94
|
+
code = <<__CODE
|
95
|
+
ts '#mlhsaddition4 / Integer -> Integer -> Integer'
|
96
|
+
def mlhsaddition4(a,b); a + b; end
|
97
|
+
|
98
|
+
ts '#mlhstest4 / Array[String] -> &(Array[String] -> String) -> Integer'
|
99
|
+
def mlhstest4(a)
|
100
|
+
yield a
|
101
|
+
end
|
102
|
+
|
103
|
+
mlhstest4(['a','b']) { |(a,b)| mlhsaddition4(a,b) }
|
104
|
+
__CODE
|
105
|
+
|
106
|
+
expect {
|
107
|
+
language.check(code)
|
108
|
+
}.to raise_error(TypedRb::Types::UncomparableTypes)
|
109
|
+
end
|
110
|
+
|
111
|
+
it 'type checks pair args for blocks, positive case' do
|
112
|
+
code = <<__CODE
|
113
|
+
ts '#mlhstestpair3 / Pair[String][Integer] -> &(Pair[String][Integer] -> Integer) -> Integer'
|
114
|
+
def mlhstestpair3(p)
|
115
|
+
yield p
|
116
|
+
end
|
117
|
+
|
118
|
+
mlhstestpair3(cast(['a',1],'Pair[String][Integer]')) { |(a,b)| b }
|
119
|
+
__CODE
|
120
|
+
|
121
|
+
result = language.check(code)
|
122
|
+
expect(result.ruby_type).to eq(Integer)
|
123
|
+
end
|
124
|
+
|
125
|
+
it 'type checks pair args for blocks, negative case' do
|
126
|
+
code = <<__CODE
|
127
|
+
ts '#mlhstestpair3 / Pair[String][Integer] -> &(Pair[String][Integer] -> Integer) -> Integer'
|
128
|
+
def mlhstestpair3(p)
|
129
|
+
yield p
|
130
|
+
end
|
131
|
+
|
132
|
+
mlhstestpair3(cast(['a',1],'Pair[String][Integer]')) { |(a,b)| a }
|
133
|
+
__CODE
|
134
|
+
expect {
|
135
|
+
language.check(code)
|
136
|
+
}.to raise_error(TypedRb::Types::UncomparableTypes)
|
137
|
+
end
|
138
|
+
|
139
|
+
it 'type checks assignation of pairs, positive case' do
|
140
|
+
code = <<__CODE
|
141
|
+
ts '#x / Pair[String][Integer] -> String'
|
142
|
+
def x(p)
|
143
|
+
a,b = p
|
144
|
+
a
|
145
|
+
end
|
146
|
+
__CODE
|
147
|
+
expect {
|
148
|
+
language.check(code)
|
149
|
+
}.to_not raise_error
|
150
|
+
end
|
151
|
+
|
152
|
+
it 'type checks assignation of pairs, negative case' do
|
153
|
+
code = <<__CODE
|
154
|
+
ts '#x / Pair[String][Integer] -> String'
|
155
|
+
def x(p)
|
156
|
+
a,b = p
|
157
|
+
b
|
158
|
+
end
|
159
|
+
__CODE
|
160
|
+
expect {
|
161
|
+
language.check(code)
|
162
|
+
}.to raise_error(TypedRb::Types::UncomparableTypes)
|
163
|
+
end
|
164
|
+
end
|
@@ -0,0 +1,89 @@
|
|
1
|
+
require_relative '../../spec_helper'
|
2
|
+
|
3
|
+
describe TypedRb::Model::TmModule do
|
4
|
+
let(:language) { TypedRb::Language.new }
|
5
|
+
|
6
|
+
it 'includes a module in a class' do
|
7
|
+
code = <<__CODE
|
8
|
+
module TMod2
|
9
|
+
ts '#x / -> String'
|
10
|
+
def x; 'test'; end
|
11
|
+
end
|
12
|
+
|
13
|
+
include TMod2
|
14
|
+
__CODE
|
15
|
+
|
16
|
+
expect do
|
17
|
+
language.check(code)
|
18
|
+
end.to_not raise_error
|
19
|
+
end
|
20
|
+
|
21
|
+
it 'detects errors in the mixed in type' do
|
22
|
+
code = <<__CODE
|
23
|
+
module TMod3
|
24
|
+
ts '#x / -> String'
|
25
|
+
def x
|
26
|
+
return_string
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
class TMod3C1
|
31
|
+
include TMod3
|
32
|
+
ts '#return_string / -> Integer'
|
33
|
+
def return_string; 2; end
|
34
|
+
end
|
35
|
+
__CODE
|
36
|
+
|
37
|
+
expect {
|
38
|
+
language.check(code)
|
39
|
+
}.to raise_error(TypedRb::Types::UncomparableTypes,
|
40
|
+
'Cannot compare types Integer <=> String')
|
41
|
+
end
|
42
|
+
|
43
|
+
it 'includes a module referencing instance variables in a class' do
|
44
|
+
code = <<__CODE
|
45
|
+
module TMod4
|
46
|
+
ts '#x / Integer -> unit'
|
47
|
+
def x(i); @a = i; end
|
48
|
+
end
|
49
|
+
|
50
|
+
class TMod4C1
|
51
|
+
include TMod4
|
52
|
+
|
53
|
+
ts '#a / -> Integer'
|
54
|
+
def a; @a; end
|
55
|
+
end
|
56
|
+
|
57
|
+
TMod4C1.new.a
|
58
|
+
__CODE
|
59
|
+
|
60
|
+
result = language.check(code)
|
61
|
+
expect(result.ruby_type).to eq(Integer)
|
62
|
+
end
|
63
|
+
|
64
|
+
it 'typechecks the inclusion of a module in multiple classes' do
|
65
|
+
code = <<__CODE
|
66
|
+
module TMod4
|
67
|
+
ts '#x / Integer -> unit'
|
68
|
+
def x(i); @a = i; end
|
69
|
+
end
|
70
|
+
|
71
|
+
class TMod4C1
|
72
|
+
include TMod4
|
73
|
+
|
74
|
+
ts '#a / -> Integer'
|
75
|
+
def a; @a; end
|
76
|
+
end
|
77
|
+
|
78
|
+
class TMod4C2
|
79
|
+
include TMod4
|
80
|
+
end
|
81
|
+
|
82
|
+
TMod4C2.new.x(3)
|
83
|
+
TMod4C1.new.a
|
84
|
+
__CODE
|
85
|
+
|
86
|
+
result = language.check(code)
|
87
|
+
expect(result.ruby_type).to eq(Integer)
|
88
|
+
end
|
89
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require_relative '../../spec_helper'
|
2
|
+
|
3
|
+
describe TypedRb::Model::TmError do
|
4
|
+
|
5
|
+
let(:language) { TypedRb::Language.new }
|
6
|
+
|
7
|
+
context 'with raise, one error' do
|
8
|
+
it 'type-checks it correctly' do
|
9
|
+
code = <<__END
|
10
|
+
1 || raise(StandardError)
|
11
|
+
__END
|
12
|
+
result = language.check(code)
|
13
|
+
expect(result.to_s).to eq('Integer')
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
context 'with raise, only errors' do
|
18
|
+
it 'type-checks it correctly' do
|
19
|
+
code = <<__END
|
20
|
+
ts '#x / -> Integer'
|
21
|
+
def x
|
22
|
+
raise(StandardError) || raise(StandardError)
|
23
|
+
end
|
24
|
+
__END
|
25
|
+
expect {
|
26
|
+
language.check(code)
|
27
|
+
}.not_to raise_error(TypedRb::Types::UncomparableTypes)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require_relative '../../spec_helper'
|
2
|
+
|
3
|
+
describe TypedRb::Model::TmRangeLiteral do
|
4
|
+
|
5
|
+
let(:language) { TypedRb::Language.new }
|
6
|
+
|
7
|
+
it 'parses ranges with the same type' do
|
8
|
+
code = '0..10'
|
9
|
+
result = language.check(code)
|
10
|
+
expect(result.ruby_type).to eq(Range)
|
11
|
+
expect(result.type_vars.first.bound.ruby_type).to eq(Integer)
|
12
|
+
|
13
|
+
code = '"a"..."z"'
|
14
|
+
result = language.check(code)
|
15
|
+
expect(result.ruby_type).to eq(Range)
|
16
|
+
expect(result.type_vars.first.bound.ruby_type).to eq(String)
|
17
|
+
end
|
18
|
+
|
19
|
+
it 'fails for incompatible types' do
|
20
|
+
code = '0..10.0'
|
21
|
+
expect {
|
22
|
+
language.check(code)
|
23
|
+
}.to raise_error
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
require_relative '../../spec_helper'
|
2
|
+
|
3
|
+
describe TypedRb::Model::TmRegexp do
|
4
|
+
|
5
|
+
let(:language) { TypedRb::Language.new }
|
6
|
+
|
7
|
+
context 'with a regular expression' do
|
8
|
+
|
9
|
+
it 'parsed the Regexp type correctly' do
|
10
|
+
result = language.check('/test/')
|
11
|
+
expect(result).to eq(tyregexp)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require_relative '../../spec_helper'
|
2
|
+
|
3
|
+
describe TypedRb::Model::TmReturn do
|
4
|
+
|
5
|
+
describe 'Simple for loop' do
|
6
|
+
let(:language) { TypedRb::Language.new }
|
7
|
+
|
8
|
+
it 'type checks a for statement, positive case' do
|
9
|
+
code = <<__CODE
|
10
|
+
ts '#test_i_fn / Integer -> Integer'
|
11
|
+
def test_i_fn(x); return 1; end
|
12
|
+
|
13
|
+
test_i_fn(1)
|
14
|
+
__CODE
|
15
|
+
|
16
|
+
parsed = language.check(code)
|
17
|
+
expect(parsed.ruby_type).to eq(Integer)
|
18
|
+
end
|
19
|
+
|
20
|
+
it 'type checks a for statement, no return value' do
|
21
|
+
code = <<__CODE
|
22
|
+
ts '#test_i_fn / Integer -> Integer'
|
23
|
+
def test_i_fn(x); return; end
|
24
|
+
|
25
|
+
test_i_fn(1)
|
26
|
+
__CODE
|
27
|
+
|
28
|
+
parsed = language.check(code)
|
29
|
+
expect(parsed.ruby_type).to eq(Integer)
|
30
|
+
end
|
31
|
+
|
32
|
+
it 'type checks a for statement, negative case' do
|
33
|
+
code = <<__CODE
|
34
|
+
ts '#test_i_fn / Integer -> Integer'
|
35
|
+
def test_i_fn(x); return '1'; end
|
36
|
+
|
37
|
+
test_i_fn(1)
|
38
|
+
__CODE
|
39
|
+
|
40
|
+
expect {
|
41
|
+
language.check(code)
|
42
|
+
}.to raise_error(TypedRb::Types::UncomparableTypes)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require_relative '../../spec_helper'
|
2
|
+
|
3
|
+
describe TypedRb::Model::TmSend do
|
4
|
+
let(:language) { TypedRb::Language.new }
|
5
|
+
|
6
|
+
it 'casts any value to the provided type' do
|
7
|
+
expr = 'cast(\'string\', Integer)'
|
8
|
+
|
9
|
+
result = language.check(expr)
|
10
|
+
expect(result).to eq(tyinteger)
|
11
|
+
end
|
12
|
+
|
13
|
+
it 'casts values when provided as strings' do
|
14
|
+
expr = 'cast(\'string\', \'Integer\')'
|
15
|
+
|
16
|
+
result = language.check(expr)
|
17
|
+
expect(result).to eq(tyinteger)
|
18
|
+
end
|
19
|
+
|
20
|
+
it 'casts values when provided as a generic type' do
|
21
|
+
expr = 'cast(\'string\', \'Array[Integer]\')'
|
22
|
+
|
23
|
+
result = language.check(expr)
|
24
|
+
expect(result.to_s).to eq('Array[Integer]')
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require_relative '../../spec_helper'
|
2
|
+
|
3
|
+
describe TypedRb::Model::TmSend do
|
4
|
+
let(:language) { TypedRb::Language.new }
|
5
|
+
|
6
|
+
context 'with class methods' do
|
7
|
+
it 'is possible to send messages to the class objects' do
|
8
|
+
expr = <<__END
|
9
|
+
class Integer
|
10
|
+
ts '#+ / Integer -> Integer'
|
11
|
+
end
|
12
|
+
|
13
|
+
class TypeCM1
|
14
|
+
|
15
|
+
ts '.a / -> Integer'
|
16
|
+
def self.a
|
17
|
+
1
|
18
|
+
end
|
19
|
+
|
20
|
+
class << self
|
21
|
+
ts '.b / -> Integer'
|
22
|
+
def b
|
23
|
+
2
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
class << TypeCM1
|
28
|
+
ts '.c / -> Integer'
|
29
|
+
def c
|
30
|
+
3
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
TypeCM1.a + TypeCM1.c + TypeCM1.c
|
36
|
+
__END
|
37
|
+
|
38
|
+
result = language.check(expr)
|
39
|
+
expect(result.ruby_type).to eq(Integer)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|