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,100 @@
|
|
1
|
+
require_relative '../../spec_helper'
|
2
|
+
|
3
|
+
describe TypedRb::Model::TmBooleanOperator do
|
4
|
+
let(:language) { TypedRb::Language.new }
|
5
|
+
|
6
|
+
it 'type checks boolean operations of the same type' do
|
7
|
+
expr = 'true && false'
|
8
|
+
|
9
|
+
result = language.check(expr)
|
10
|
+
expect(result.ruby_type).to eq(TrueClass)
|
11
|
+
|
12
|
+
expr = 'true || false'
|
13
|
+
|
14
|
+
result = language.check(expr)
|
15
|
+
expect(result.ruby_type).to eq(TrueClass)
|
16
|
+
|
17
|
+
expr = 'true or false'
|
18
|
+
|
19
|
+
result = language.check(expr)
|
20
|
+
expect(result.ruby_type).to eq(TrueClass)
|
21
|
+
|
22
|
+
expr = 'true and false'
|
23
|
+
|
24
|
+
result = language.check(expr)
|
25
|
+
expect(result.ruby_type).to eq(TrueClass)
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'type checks boolean operations with different types' do
|
29
|
+
expr = '1 && 0'
|
30
|
+
|
31
|
+
result = language.check(expr)
|
32
|
+
expect(result.ruby_type).to eq(Integer)
|
33
|
+
|
34
|
+
expr = '1 || Numeric.new'
|
35
|
+
|
36
|
+
result = language.check(expr)
|
37
|
+
expect(result.ruby_type).to eq(Numeric)
|
38
|
+
|
39
|
+
expr = '"string" or Numeric.new'
|
40
|
+
|
41
|
+
result = language.check(expr)
|
42
|
+
expect(result.ruby_type).to eq(Object)
|
43
|
+
end
|
44
|
+
|
45
|
+
|
46
|
+
it 'type checks boolean operations with nil values' do
|
47
|
+
expr = '1 && nil'
|
48
|
+
|
49
|
+
result = language.check(expr)
|
50
|
+
expect(result.ruby_type).to eq(Integer)
|
51
|
+
|
52
|
+
expr = 'nil || Numeric.new'
|
53
|
+
|
54
|
+
result = language.check(expr)
|
55
|
+
expect(result.ruby_type).to eq(Numeric)
|
56
|
+
|
57
|
+
expr = '"string" or nil'
|
58
|
+
|
59
|
+
result = language.check(expr)
|
60
|
+
expect(result.ruby_type).to eq(String)
|
61
|
+
end
|
62
|
+
|
63
|
+
it 'type checks operations with type variables' do
|
64
|
+
|
65
|
+
code = <<__CODE
|
66
|
+
class TBOp1
|
67
|
+
ts '#test / -> Boolean'
|
68
|
+
def test
|
69
|
+
@b || false
|
70
|
+
end
|
71
|
+
|
72
|
+
ts '#b / -> Boolean'
|
73
|
+
def b; @b; end
|
74
|
+
end
|
75
|
+
|
76
|
+
TBOp1.new.b
|
77
|
+
__CODE
|
78
|
+
|
79
|
+
result = language.check(code)
|
80
|
+
expect(result.ruby_type).to eq(TrueClass)
|
81
|
+
|
82
|
+
|
83
|
+
code = <<__CODE
|
84
|
+
class TBOp2
|
85
|
+
ts '#test / -> Boolean'
|
86
|
+
def test
|
87
|
+
@b || @c
|
88
|
+
end
|
89
|
+
|
90
|
+
ts '#b / -> Boolean'
|
91
|
+
def b; @b; end
|
92
|
+
end
|
93
|
+
|
94
|
+
TBOp2.new.b
|
95
|
+
__CODE
|
96
|
+
|
97
|
+
result = language.check(code)
|
98
|
+
expect(result.ruby_type).to eq(TrueClass)
|
99
|
+
end
|
100
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
require_relative '../../spec_helper'
|
2
|
+
|
3
|
+
describe TypedRb::Model::TmBoolean do
|
4
|
+
|
5
|
+
before :each do
|
6
|
+
::BasicObject::TypeRegistry.clear
|
7
|
+
end
|
8
|
+
|
9
|
+
let(:typed_code) do
|
10
|
+
$TYPECHECK = true
|
11
|
+
eval(code, TOPLEVEL_BINDING)
|
12
|
+
::BasicObject::TypeRegistry.normalize_types!
|
13
|
+
code
|
14
|
+
end
|
15
|
+
|
16
|
+
let(:ast) do
|
17
|
+
TypedRb::Model::GenSym.reset
|
18
|
+
parser = TypedRb::AstParser.new
|
19
|
+
parser.parse(typed_code)
|
20
|
+
end
|
21
|
+
|
22
|
+
context 'with validly typed code' do
|
23
|
+
let(:code) {
|
24
|
+
<<__CODE
|
25
|
+
ts '#f / Boolean -> Boolean'
|
26
|
+
def f(b)
|
27
|
+
b
|
28
|
+
end
|
29
|
+
|
30
|
+
f(true)
|
31
|
+
f(false)
|
32
|
+
__CODE
|
33
|
+
}
|
34
|
+
|
35
|
+
it 'should be possible to type check a method and method application' do
|
36
|
+
expect {
|
37
|
+
ast.check_type(TypedRb::Types::TypingContext.top_level)
|
38
|
+
}.to_not raise_error
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
context 'when used as a subtype' do
|
43
|
+
let(:code) {
|
44
|
+
<<__CODE
|
45
|
+
ts '#f / Object -> Object'
|
46
|
+
def f(b)
|
47
|
+
b
|
48
|
+
end
|
49
|
+
|
50
|
+
f(true)
|
51
|
+
f(false)
|
52
|
+
__CODE
|
53
|
+
}
|
54
|
+
|
55
|
+
it 'should be possible to type check method application' do
|
56
|
+
expect {
|
57
|
+
ast.check_type(TypedRb::Types::TypingContext.top_level)
|
58
|
+
}.to_not raise_error
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require_relative '../../spec_helper'
|
2
|
+
|
3
|
+
describe TypedRb::Model::TmConst do
|
4
|
+
|
5
|
+
let(:language) { TypedRb::Language.new }
|
6
|
+
|
7
|
+
it 'type checks class constants' do
|
8
|
+
result = language.check('class TmConstTest1; end; TmConstTest1')
|
9
|
+
expect(result.ruby_type).to eq(TmConstTest1)
|
10
|
+
end
|
11
|
+
|
12
|
+
it 'type checks module constants' do
|
13
|
+
result = language.check('module TmConstTest2; end; TmConstTest2')
|
14
|
+
expect(result.ruby_type).to eq(TmConstTest2)
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'type checks user defined constants' do
|
18
|
+
code = <<__END
|
19
|
+
module TestConstTest3
|
20
|
+
MY_CONSTANT = 2
|
21
|
+
end
|
22
|
+
|
23
|
+
TestConstTest3::MY_CONSTANT
|
24
|
+
__END
|
25
|
+
result = language.check(code)
|
26
|
+
expect(result.ruby_type).to eq(Fixnum)
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
require_relative '../../spec_helper'
|
2
|
+
|
3
|
+
describe TypedRb::Model::TmDefined do
|
4
|
+
let(:language) { TypedRb::Language.new }
|
5
|
+
|
6
|
+
it 'defined invocations' do
|
7
|
+
expr = 'defined? 2'
|
8
|
+
|
9
|
+
result = language.check(expr)
|
10
|
+
expect(result.ruby_type).to eq(String)
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,347 @@
|
|
1
|
+
require_relative '../../spec_helper'
|
2
|
+
|
3
|
+
describe TypedRb::Model::TmFun do
|
4
|
+
before :each do
|
5
|
+
::BasicObject::TypeRegistry.clear
|
6
|
+
end
|
7
|
+
|
8
|
+
let(:code) do
|
9
|
+
text = <<__CODE
|
10
|
+
class A
|
11
|
+
ts '#f1 / Integer -> String'
|
12
|
+
def f1(num)
|
13
|
+
'String'
|
14
|
+
end
|
15
|
+
|
16
|
+
ts '#f2 / Integer -> String'
|
17
|
+
def f2(num=2)
|
18
|
+
f1(num)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
__CODE
|
22
|
+
text
|
23
|
+
end
|
24
|
+
|
25
|
+
let(:typed_code) do
|
26
|
+
$TYPECHECK = true
|
27
|
+
eval(code, TOPLEVEL_BINDING)
|
28
|
+
::BasicObject::TypeRegistry.normalize_types!
|
29
|
+
code
|
30
|
+
end
|
31
|
+
|
32
|
+
let(:ast) do
|
33
|
+
TypedRb::Model::GenSym.reset
|
34
|
+
parser = TypedRb::AstParser.new
|
35
|
+
parser.parse(typed_code)
|
36
|
+
end
|
37
|
+
|
38
|
+
context 'with validly typed code' do
|
39
|
+
it 'is possible to type check a method and method application' do
|
40
|
+
expect do
|
41
|
+
ast.check_type(TypedRb::Types::TypingContext.new)
|
42
|
+
end.to_not raise_error
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
context 'with not matching arg type in function definition' do
|
47
|
+
let(:code) do
|
48
|
+
text = <<__CODE
|
49
|
+
class A
|
50
|
+
ts '#f1 / Integer -> String'
|
51
|
+
def f1(num='text')
|
52
|
+
'String'
|
53
|
+
end
|
54
|
+
|
55
|
+
ts '#f2 / Integer -> String'
|
56
|
+
def f2(num)
|
57
|
+
f1(num)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
__CODE
|
61
|
+
text
|
62
|
+
end
|
63
|
+
|
64
|
+
it 'raises a type error' do
|
65
|
+
expect do
|
66
|
+
ast.check_type(TypedRb::Types::TypingContext.new)
|
67
|
+
end.to raise_error(TypedRb::Types::UncomparableTypes)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
context 'with not matching return type in function definition' do
|
72
|
+
let(:code) do
|
73
|
+
text =<<__CODE
|
74
|
+
class A
|
75
|
+
ts '#f1 / Integer -> String'
|
76
|
+
def f1(num)
|
77
|
+
2
|
78
|
+
end
|
79
|
+
|
80
|
+
ts '#f2 / Integer -> String'
|
81
|
+
def f2(num)
|
82
|
+
f1(num)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
__CODE
|
86
|
+
text
|
87
|
+
end
|
88
|
+
|
89
|
+
it 'raises a type error' do
|
90
|
+
expect do
|
91
|
+
ast.check_type(TypedRb::Types::TypingContext.new)
|
92
|
+
end.to raise_error(TypedRb::Types::UncomparableTypes)
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
context 'with application without optional arguments' do
|
97
|
+
let(:code) do
|
98
|
+
text = <<__CODE
|
99
|
+
ts '#f / Integer -> Integer -> String'
|
100
|
+
def f(a,b=1)
|
101
|
+
'string'
|
102
|
+
end
|
103
|
+
|
104
|
+
f(2)
|
105
|
+
|
106
|
+
f(2,3)
|
107
|
+
__CODE
|
108
|
+
text
|
109
|
+
end
|
110
|
+
|
111
|
+
it 'does not raise a type error' do
|
112
|
+
expect do
|
113
|
+
ast.check_type(TypedRb::Types::TypingContext.top_level)
|
114
|
+
end.not_to raise_error
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
context 'with application without erroneus optional arguments' do
|
119
|
+
let(:code) do
|
120
|
+
text = <<__CODE
|
121
|
+
ts '#f / Integer -> Integer -> String'
|
122
|
+
def f(a,b='string')
|
123
|
+
'string'
|
124
|
+
end
|
125
|
+
|
126
|
+
f(2)
|
127
|
+
|
128
|
+
f(2,3)
|
129
|
+
__CODE
|
130
|
+
text
|
131
|
+
end
|
132
|
+
|
133
|
+
it 'does not raise a type error' do
|
134
|
+
expect do
|
135
|
+
ast.check_type(TypedRb::Types::TypingContext.top_level)
|
136
|
+
end.to raise_error(TypedRb::Types::UncomparableTypes)
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
context 'with application with rest args' do
|
141
|
+
|
142
|
+
context 'with correct types' do
|
143
|
+
let(:code) do
|
144
|
+
text = <<__CODE
|
145
|
+
ts 'type Array[T]'
|
146
|
+
|
147
|
+
ts '#f / Integer -> Integer... -> String'
|
148
|
+
def f(a, *b)
|
149
|
+
'string'
|
150
|
+
end
|
151
|
+
|
152
|
+
f(2, 3, 4, 5)
|
153
|
+
__CODE
|
154
|
+
text
|
155
|
+
end
|
156
|
+
|
157
|
+
it 'doest not raise a type error' do
|
158
|
+
|
159
|
+
expect do
|
160
|
+
res = ast.check_type(TypedRb::Types::TypingContext.top_level)
|
161
|
+
expect(res.ruby_type).to eq(String)
|
162
|
+
end.not_to raise_error
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
context 'with erroneous types' do
|
167
|
+
let(:code) do
|
168
|
+
text = <<__CODE
|
169
|
+
ts 'type Array[T]'
|
170
|
+
|
171
|
+
ts '#f / Integer -> Integer... -> String'
|
172
|
+
def f(a, *b)
|
173
|
+
'string'
|
174
|
+
end
|
175
|
+
|
176
|
+
f(2, 'a', 'b')
|
177
|
+
__CODE
|
178
|
+
text
|
179
|
+
end
|
180
|
+
|
181
|
+
it 'raises a type error' do
|
182
|
+
|
183
|
+
expect do
|
184
|
+
ast.check_type(TypedRb::Types::TypingContext.top_level)
|
185
|
+
end.to raise_error(TypedRb::TypeCheckError)
|
186
|
+
end
|
187
|
+
end
|
188
|
+
|
189
|
+
context 'with missing rest args' do
|
190
|
+
let(:code) do
|
191
|
+
text = <<__CODE
|
192
|
+
ts 'type Array[T]'
|
193
|
+
|
194
|
+
ts '#f / Integer -> Integer... -> String'
|
195
|
+
def f(a, *b)
|
196
|
+
'string'
|
197
|
+
end
|
198
|
+
|
199
|
+
f(2)
|
200
|
+
__CODE
|
201
|
+
text
|
202
|
+
end
|
203
|
+
|
204
|
+
it 'does not raise a type error' do
|
205
|
+
|
206
|
+
expect do
|
207
|
+
res = ast.check_type(TypedRb::Types::TypingContext.top_level)
|
208
|
+
expect(res.ruby_type).to eq(String)
|
209
|
+
end.not_to raise_error
|
210
|
+
end
|
211
|
+
end
|
212
|
+
|
213
|
+
context 'with a correctly typed class function' do
|
214
|
+
let(:code) do
|
215
|
+
text = <<__CODE
|
216
|
+
class CFA
|
217
|
+
ts '.a / String -> Integer'
|
218
|
+
def self.a(x); 1; end
|
219
|
+
end
|
220
|
+
|
221
|
+
CFA.a('string')
|
222
|
+
__CODE
|
223
|
+
end
|
224
|
+
|
225
|
+
it 'does not raise a type error' do
|
226
|
+
res = ast.check_type(TypedRb::Types::TypingContext.top_level)
|
227
|
+
expect(res.ruby_type).to eq(Integer)
|
228
|
+
end
|
229
|
+
end
|
230
|
+
|
231
|
+
context 'with a correctly typed class function added to the class object' do
|
232
|
+
let(:code) do
|
233
|
+
text = <<__CODE
|
234
|
+
class CFB; end
|
235
|
+
|
236
|
+
ts 'CFB.b / String -> Integer'
|
237
|
+
def CFB.b(x); 1; end
|
238
|
+
|
239
|
+
|
240
|
+
CFB.b('string')
|
241
|
+
__CODE
|
242
|
+
end
|
243
|
+
|
244
|
+
it 'does not raise a type error' do
|
245
|
+
res = ast.check_type(TypedRb::Types::TypingContext.top_level)
|
246
|
+
expect(res.ruby_type).to eq(Integer)
|
247
|
+
end
|
248
|
+
end
|
249
|
+
|
250
|
+
context 'with a mistmacth in the arg types' do
|
251
|
+
context 'with an untyped function' do
|
252
|
+
let(:code) do
|
253
|
+
text = <<__CODE
|
254
|
+
class CFC1
|
255
|
+
ts '#t / String -> Integer'
|
256
|
+
def t(x); 1; end
|
257
|
+
end
|
258
|
+
|
259
|
+
class CFC2 < CFC1
|
260
|
+
def t; 1; end
|
261
|
+
end
|
262
|
+
CFC2.new.t
|
263
|
+
__CODE
|
264
|
+
end
|
265
|
+
it 'does not raise an error' do
|
266
|
+
expect do
|
267
|
+
ast.check_type(TypedRb::Types::TypingContext.top_level)
|
268
|
+
end.not_to raise_error
|
269
|
+
end
|
270
|
+
end
|
271
|
+
|
272
|
+
context 'with a typed function' do
|
273
|
+
let(:code) do
|
274
|
+
text = <<__CODE
|
275
|
+
class CFD
|
276
|
+
ts '#t / String -> Integer'
|
277
|
+
def t(x); 1; end
|
278
|
+
end
|
279
|
+
__CODE
|
280
|
+
end
|
281
|
+
it 'does raises an error' do
|
282
|
+
expect do
|
283
|
+
ast.check_type(TypedRb::Types::TypingContext.top_level)
|
284
|
+
end.not_to raise_error
|
285
|
+
end
|
286
|
+
end
|
287
|
+
|
288
|
+
context 'with a missing block arg' do
|
289
|
+
let(:code) do
|
290
|
+
text = <<__CODE
|
291
|
+
class CFE
|
292
|
+
ts '#t / String -> Integer'
|
293
|
+
def t(x, &b); 1; end
|
294
|
+
end
|
295
|
+
__CODE
|
296
|
+
end
|
297
|
+
it 'does raises an error' do
|
298
|
+
expect do
|
299
|
+
ast.check_type(TypedRb::Types::TypingContext.top_level)
|
300
|
+
end.to raise_error(TypedRb::TypeCheckError)
|
301
|
+
end
|
302
|
+
end
|
303
|
+
end
|
304
|
+
end
|
305
|
+
|
306
|
+
context 'with a either conditional return, positive case' do
|
307
|
+
let(:code) do
|
308
|
+
<<__CODE
|
309
|
+
ts '#t / String -> Integer'
|
310
|
+
def t(s)
|
311
|
+
if s == 'foo'
|
312
|
+
0
|
313
|
+
else
|
314
|
+
return 1
|
315
|
+
end
|
316
|
+
end
|
317
|
+
t('bar')
|
318
|
+
__CODE
|
319
|
+
end
|
320
|
+
|
321
|
+
it 'does not raise an error' do
|
322
|
+
result = ast.check_type(TypedRb::Types::TypingContext.top_level)
|
323
|
+
expect(result.ruby_type).to eq(Integer)
|
324
|
+
end
|
325
|
+
end
|
326
|
+
|
327
|
+
context 'with a either conditional return, negative case' do
|
328
|
+
let(:code) do
|
329
|
+
<<__CODE
|
330
|
+
ts '#t / String -> Integer'
|
331
|
+
def t(s)
|
332
|
+
if s == 'foo'
|
333
|
+
0
|
334
|
+
else
|
335
|
+
return 'bar'
|
336
|
+
end
|
337
|
+
end
|
338
|
+
__CODE
|
339
|
+
end
|
340
|
+
|
341
|
+
it 'does not raise an error' do
|
342
|
+
expect {
|
343
|
+
ast.check_type(TypedRb::Types::TypingContext.top_level)
|
344
|
+
}.to raise_error(TypedRb::Types::UncomparableTypes)
|
345
|
+
end
|
346
|
+
end
|
347
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require_relative '../../spec_helper'
|
2
|
+
|
3
|
+
describe TypedRb::Model::TmGlobalVar do
|
4
|
+
let(:language) { TypedRb::Language.new }
|
5
|
+
|
6
|
+
context 'with a valid global var' do
|
7
|
+
it 'is possible to type-check the global var' do
|
8
|
+
expr = <<__END
|
9
|
+
$test = 1
|
10
|
+
$test
|
11
|
+
__END
|
12
|
+
|
13
|
+
result = language.check(expr)
|
14
|
+
expect(result.bound.ruby_type).to eq(Integer)
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'is possible to type-check errors in global var typing' do
|
18
|
+
expr = <<__END
|
19
|
+
$test = 1
|
20
|
+
$test = 'test'
|
21
|
+
|
22
|
+
ts '#x / Integer -> unit'
|
23
|
+
def x(n); end
|
24
|
+
|
25
|
+
x($test)
|
26
|
+
__END
|
27
|
+
|
28
|
+
expect {
|
29
|
+
language.check(expr)
|
30
|
+
}.to raise_error(TypedRb::Types::UncomparableTypes)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,104 @@
|
|
1
|
+
require_relative '../../spec_helper'
|
2
|
+
|
3
|
+
describe TypedRb::Model::TmIfElse do
|
4
|
+
let(:language) { TypedRb::Language.new }
|
5
|
+
|
6
|
+
it 'types correctly if/then/else branches' do
|
7
|
+
expr = <<__CODE
|
8
|
+
if true
|
9
|
+
1
|
10
|
+
else
|
11
|
+
2
|
12
|
+
end
|
13
|
+
__CODE
|
14
|
+
|
15
|
+
result = language.check(expr)
|
16
|
+
expect(result).to eq(tyinteger)
|
17
|
+
end
|
18
|
+
|
19
|
+
it 'types correctly if/then' do
|
20
|
+
expr = <<__CODE
|
21
|
+
1 if true
|
22
|
+
__CODE
|
23
|
+
|
24
|
+
result = language.check(expr)
|
25
|
+
expect(result).to eq(tyinteger)
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'types correctly if/else' do
|
29
|
+
expr = <<__CODE
|
30
|
+
1 unless true
|
31
|
+
__CODE
|
32
|
+
result = language.check(expr)
|
33
|
+
expect(result).to eq(tyinteger)
|
34
|
+
end
|
35
|
+
|
36
|
+
it 'types correctly return statements in if/then/else branches' do
|
37
|
+
expr = <<__CODE
|
38
|
+
ts '#fbite1 / -> Integer'
|
39
|
+
def fbite1
|
40
|
+
return 1 if true
|
41
|
+
end
|
42
|
+
fbite1
|
43
|
+
__CODE
|
44
|
+
|
45
|
+
result = language.check(expr)
|
46
|
+
expect(result).to eq(tyinteger)
|
47
|
+
end
|
48
|
+
|
49
|
+
it 'types correctly return statements in if/then branches' do
|
50
|
+
expr = <<__CODE
|
51
|
+
ts '#fbite2 / -> Integer'
|
52
|
+
def fbite2
|
53
|
+
return 2 unless true
|
54
|
+
end
|
55
|
+
fbite2
|
56
|
+
__CODE
|
57
|
+
|
58
|
+
result = language.check(expr)
|
59
|
+
expect(result).to eq(tyinteger)
|
60
|
+
end
|
61
|
+
|
62
|
+
it 'types correctly return statements in if/else branches' do
|
63
|
+
expr = <<__CODE
|
64
|
+
ts '#fbite3 / -> Integer'
|
65
|
+
def fbite3
|
66
|
+
if true
|
67
|
+
return 1
|
68
|
+
else
|
69
|
+
return 2
|
70
|
+
end
|
71
|
+
end
|
72
|
+
fbite3
|
73
|
+
__CODE
|
74
|
+
|
75
|
+
result = language.check(expr)
|
76
|
+
expect(result).to eq(tyinteger)
|
77
|
+
end
|
78
|
+
|
79
|
+
it 'types correctly if/then/else statements with errors in the then branch' do
|
80
|
+
expr = <<__CODE
|
81
|
+
if false
|
82
|
+
fail StandardError, 'error'
|
83
|
+
else
|
84
|
+
1
|
85
|
+
end
|
86
|
+
__CODE
|
87
|
+
|
88
|
+
result = language.check(expr)
|
89
|
+
expect(result.ruby_type).to eq(Integer)
|
90
|
+
end
|
91
|
+
|
92
|
+
it 'types correctly if/then/else statements with errors in the else branch' do
|
93
|
+
expr = <<__CODE
|
94
|
+
if true
|
95
|
+
1
|
96
|
+
else
|
97
|
+
fail StandardError, 'error'
|
98
|
+
end
|
99
|
+
__CODE
|
100
|
+
|
101
|
+
result = language.check(expr)
|
102
|
+
expect(result.ruby_type).to eq(Integer)
|
103
|
+
end
|
104
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require_relative '../../spec_helper'
|
2
|
+
|
3
|
+
describe BasicObject do
|
4
|
+
let(:language) { TypedRb::Language.new }
|
5
|
+
|
6
|
+
it 'Ignores functions marked with #ts_ignore' do
|
7
|
+
expr = <<__CODE
|
8
|
+
class TypeA
|
9
|
+
|
10
|
+
ts '#fa / -> String'
|
11
|
+
ts_ignore
|
12
|
+
def fa
|
13
|
+
2.0
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
17
|
+
|
18
|
+
TypeA.new.fa
|
19
|
+
__CODE
|
20
|
+
|
21
|
+
result = language.check(expr)
|
22
|
+
expect(result.to_s).to eq('String')
|
23
|
+
end
|
24
|
+
end
|