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,103 @@
|
|
1
|
+
require_relative '../../spec_helper'
|
2
|
+
|
3
|
+
describe TypedRb::Model::TmSend do
|
4
|
+
let(:language) { TypedRb::Language.new }
|
5
|
+
|
6
|
+
context 'with a generic type' do
|
7
|
+
it 'creates the correct materialised type' do
|
8
|
+
code = <<__CODE
|
9
|
+
ts 'type Pod1[X<Numeric]'
|
10
|
+
class Pod1
|
11
|
+
|
12
|
+
ts '#initialize / [X] -> unit'
|
13
|
+
def initialize(x)
|
14
|
+
@value = x
|
15
|
+
end
|
16
|
+
ts '#get / -> [X]'
|
17
|
+
def get
|
18
|
+
@value
|
19
|
+
end
|
20
|
+
|
21
|
+
ts '#put / [X] -> unit'
|
22
|
+
def put(x)
|
23
|
+
@value = x
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
|
28
|
+
Pod1.(Integer)
|
29
|
+
__CODE
|
30
|
+
|
31
|
+
result = language.check(code)
|
32
|
+
expect(result.type_vars[0].bound.ruby_type).to eq(Integer)
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'captures type errors in the materialization' do
|
36
|
+
|
37
|
+
code = <<__CODE
|
38
|
+
ts 'type Pod2[X<Numeric]'
|
39
|
+
class Pod2
|
40
|
+
|
41
|
+
ts '#initialize / -> unit'
|
42
|
+
def initialize
|
43
|
+
@value = base
|
44
|
+
end
|
45
|
+
|
46
|
+
ts '#base / -> Float'
|
47
|
+
def base
|
48
|
+
1.0
|
49
|
+
end
|
50
|
+
|
51
|
+
ts '#get / -> [X]'
|
52
|
+
def get
|
53
|
+
@value
|
54
|
+
end
|
55
|
+
|
56
|
+
ts '#put / [X] -> unit'
|
57
|
+
def put(x)
|
58
|
+
@value = x
|
59
|
+
end
|
60
|
+
|
61
|
+
end
|
62
|
+
__CODE
|
63
|
+
|
64
|
+
expect {
|
65
|
+
language.check("#{code}; Pod2.(Integer)")
|
66
|
+
}.to raise_error(TypedRb::TypeCheckError)
|
67
|
+
|
68
|
+
result = language.check("#{code}; Pod2.(Float)")
|
69
|
+
expect(result.type_vars[0].bound.ruby_type).to eq(Float)
|
70
|
+
end
|
71
|
+
|
72
|
+
it 'returns the right type information for materialised methods' do
|
73
|
+
|
74
|
+
code = <<__CODE
|
75
|
+
ts 'type Pod3[X<Numeric]'
|
76
|
+
class Pod3
|
77
|
+
|
78
|
+
ts '#initialize / [X] -> unit'
|
79
|
+
def initialize(x)
|
80
|
+
@value = x
|
81
|
+
end
|
82
|
+
|
83
|
+
ts '#get / -> [X]'
|
84
|
+
def get
|
85
|
+
@value
|
86
|
+
end
|
87
|
+
|
88
|
+
ts '#put / [X] -> unit'
|
89
|
+
def put(x)
|
90
|
+
@value = x
|
91
|
+
end
|
92
|
+
end
|
93
|
+
__CODE
|
94
|
+
|
95
|
+
expect {
|
96
|
+
language.check("#{code}; p = Pod3.(Integer).new(0.0); p.put(2.0)")
|
97
|
+
}.to raise_error(TypedRb::TypeCheckError)
|
98
|
+
|
99
|
+
result = language.check("#{code}; p = Pod3.(Integer).new(0); p.put(2); p.get")
|
100
|
+
expect(result.ruby_type).to eq(Integer)
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
require_relative '../../spec_helper'
|
2
|
+
|
3
|
+
describe TypedRb::Model::TmSend do
|
4
|
+
let(:language) { TypedRb::Language.new }
|
5
|
+
|
6
|
+
it 'applies arguments to generic methods' do
|
7
|
+
code = <<__END
|
8
|
+
ts '#trs / Boolean -> String -> Integer'
|
9
|
+
def trs(a,b); 2; end
|
10
|
+
|
11
|
+
class TestGM1
|
12
|
+
ts '#gm[T][E] / [T] -> &([T] -> [E]) -> [E]'
|
13
|
+
def gm(t)
|
14
|
+
yield t
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
a = TestGM1.new.gm(true) { |t| false }
|
19
|
+
b = TestGM1.new.gm(1) { |t| 'string' }
|
20
|
+
|
21
|
+
trs(a,b)
|
22
|
+
__END
|
23
|
+
result = language.check(code)
|
24
|
+
expect(result.ruby_type).to eq(Integer)
|
25
|
+
end
|
26
|
+
|
27
|
+
it 'applies arguments to generic methods mixing class and method type variables' do
|
28
|
+
code = <<__END
|
29
|
+
ts 'type TestGM2Array[T]'
|
30
|
+
class TestGM2Array
|
31
|
+
|
32
|
+
ts '#initialize / [T] -> unit'
|
33
|
+
def initialize(t)
|
34
|
+
@t = t
|
35
|
+
end
|
36
|
+
|
37
|
+
ts '#map[E] / [T] -> Array[T] -> &([T] -> [E]) -> Array[E]'
|
38
|
+
def map(x, xs)
|
39
|
+
c = Array.('[E]').new
|
40
|
+
c << yield(@t)
|
41
|
+
c
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
ts '#c / String -> Integer'
|
46
|
+
def c(x)
|
47
|
+
0
|
48
|
+
end
|
49
|
+
|
50
|
+
TestGM2Array.(Integer).new(1).map(1, nil) { |v| v + 1 }
|
51
|
+
TestGM2Array.(String).new('value').map('other', nil) { |v| c(v) }
|
52
|
+
__END
|
53
|
+
result = language.check(code)
|
54
|
+
expect(result.ruby_type).to eq(Array)
|
55
|
+
expect(result.type_vars[0].bound.ruby_type).to eq(Integer)
|
56
|
+
end
|
57
|
+
|
58
|
+
it 'type checks the body of generic methods' do
|
59
|
+
code = <<__END
|
60
|
+
class TestGM3
|
61
|
+
|
62
|
+
ts '#test[E] / [E] -> Array[E]'
|
63
|
+
def test(e)
|
64
|
+
es = Array.('[E]').new
|
65
|
+
es << e
|
66
|
+
es
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
TestGM3.new.test(2)
|
71
|
+
TestGM3.new.test('value')
|
72
|
+
__END
|
73
|
+
result = language.check(code)
|
74
|
+
expect(result.ruby_type).to eq(Array)
|
75
|
+
expect(result.type_vars[0].bound.ruby_type).to eq(String)
|
76
|
+
end
|
77
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
require_relative '../../spec_helper'
|
2
|
+
|
3
|
+
describe TypedRb::Model::TmSend do
|
4
|
+
|
5
|
+
before :each do
|
6
|
+
::BasicObject::TypeRegistry.clear
|
7
|
+
end
|
8
|
+
|
9
|
+
let(:code) do
|
10
|
+
text =<<__CODE
|
11
|
+
class A
|
12
|
+
|
13
|
+
ts '#initialize / Integer -> unit'
|
14
|
+
def initialize(num)
|
15
|
+
'String'
|
16
|
+
end
|
17
|
+
|
18
|
+
ts '#a / -> Integer'
|
19
|
+
def a
|
20
|
+
1
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
|
25
|
+
a = A.new(3)
|
26
|
+
A.new(a.a)
|
27
|
+
__CODE
|
28
|
+
text
|
29
|
+
end
|
30
|
+
|
31
|
+
let(:typed_code) do
|
32
|
+
$TYPECHECK = true
|
33
|
+
eval(code, TOPLEVEL_BINDING)
|
34
|
+
::BasicObject::TypeRegistry.normalize_types!
|
35
|
+
code
|
36
|
+
end
|
37
|
+
|
38
|
+
let(:ast) do
|
39
|
+
TypedRb::Model::GenSym.reset
|
40
|
+
parser = TypedRb::AstParser.new
|
41
|
+
parser.parse(typed_code)
|
42
|
+
end
|
43
|
+
|
44
|
+
context 'with validly typed code' do
|
45
|
+
it 'type checks a method and method application' do
|
46
|
+
type = ast.check_type(TypedRb::Types::TypingContext.new)
|
47
|
+
expect(type.to_s).to eq("A")
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
context 'within the class context' do
|
52
|
+
let(:code) do
|
53
|
+
text = <<__CODE
|
54
|
+
class TSICC
|
55
|
+
|
56
|
+
T = new
|
57
|
+
end
|
58
|
+
|
59
|
+
TSICC::T
|
60
|
+
__CODE
|
61
|
+
end
|
62
|
+
|
63
|
+
it 'it type checks the initialization correctly' do
|
64
|
+
type = ast.check_type(TypedRb::Types::TypingContext.new)
|
65
|
+
expect(type.to_s).to eq("TSICC")
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
@@ -0,0 +1,135 @@
|
|
1
|
+
require_relative '../../spec_helper'
|
2
|
+
|
3
|
+
describe TypedRb::Model::TmSend do
|
4
|
+
let(:language) { TypedRb::Language.new }
|
5
|
+
|
6
|
+
context 'with lambda functions' do
|
7
|
+
it 'evaluates lambda functions applications' do
|
8
|
+
expr = <<__END
|
9
|
+
id = ->(x) { x }
|
10
|
+
id[1]
|
11
|
+
__END
|
12
|
+
|
13
|
+
result = language.check(expr)
|
14
|
+
expect(result).to eq(tyinteger)
|
15
|
+
|
16
|
+
expr = <<__END
|
17
|
+
id = ->(x) { x }
|
18
|
+
id[1]
|
19
|
+
id['string']
|
20
|
+
__END
|
21
|
+
|
22
|
+
result = language.check(expr)
|
23
|
+
expect(result).to eq(tystring)
|
24
|
+
end
|
25
|
+
|
26
|
+
it 'evaluates lambda functions with either types' do
|
27
|
+
expr = <<__END
|
28
|
+
f = ->() do
|
29
|
+
if(true)
|
30
|
+
1.0
|
31
|
+
else
|
32
|
+
return 2
|
33
|
+
end
|
34
|
+
end
|
35
|
+
f[]
|
36
|
+
__END
|
37
|
+
result = language.check(expr)
|
38
|
+
expect(result.to_s).to eq('Numeric')
|
39
|
+
end
|
40
|
+
|
41
|
+
it 'evaluates lambda functions with either types including break type' do
|
42
|
+
expr = <<__END
|
43
|
+
f = ->() do
|
44
|
+
if(true)
|
45
|
+
1.0
|
46
|
+
else
|
47
|
+
break 2
|
48
|
+
end
|
49
|
+
end
|
50
|
+
f[]
|
51
|
+
__END
|
52
|
+
result = language.check(expr)
|
53
|
+
expect(result).to be_instance_of(TypedRb::Types::TyEither)
|
54
|
+
expect(result[:normal].to_s).to eq('Float')
|
55
|
+
expect(result[:break].to_s).to eq('Jump[break:Integer]')
|
56
|
+
end
|
57
|
+
|
58
|
+
it 'evaluates lambda functions applications with message sending inside' do
|
59
|
+
expr = <<__END
|
60
|
+
class Integer
|
61
|
+
ts '#+ / Integer -> Integer'
|
62
|
+
end
|
63
|
+
|
64
|
+
class String
|
65
|
+
ts '#+ / String -> String'
|
66
|
+
end
|
67
|
+
|
68
|
+
add = ->(x,y) { x + y }
|
69
|
+
add[1,2]
|
70
|
+
__END
|
71
|
+
|
72
|
+
result = language.check(expr)
|
73
|
+
expect(result).to eq(tyinteger)
|
74
|
+
|
75
|
+
expr = <<__END
|
76
|
+
class Integer
|
77
|
+
ts '#+ / Integer -> Integer'
|
78
|
+
end
|
79
|
+
|
80
|
+
class String
|
81
|
+
ts '#+ / String -> String'
|
82
|
+
end
|
83
|
+
|
84
|
+
add = ->(x,y) { x + y }
|
85
|
+
add[1,2]
|
86
|
+
add['hello','world']
|
87
|
+
__END
|
88
|
+
|
89
|
+
result = language.check(expr)
|
90
|
+
expect(result).to eq(tystring)
|
91
|
+
|
92
|
+
expr = <<__END
|
93
|
+
class Integer
|
94
|
+
ts '#foo / Integer -> String'
|
95
|
+
def foo(x); 'foo'; end
|
96
|
+
end
|
97
|
+
|
98
|
+
f = ->(x,y) { x.foo(y) }
|
99
|
+
f[1,2]
|
100
|
+
__END
|
101
|
+
|
102
|
+
result = language.check(expr)
|
103
|
+
expect(result).to eq(tystring)
|
104
|
+
|
105
|
+
end
|
106
|
+
|
107
|
+
it 'catches expcetions in lambda applications' do
|
108
|
+
|
109
|
+
expr = <<__END
|
110
|
+
class Integer
|
111
|
+
ts '#foo / String -> String'
|
112
|
+
def foo(x); 'foo'; end
|
113
|
+
end
|
114
|
+
|
115
|
+
f = ->(x,y) { x.foo(y) }
|
116
|
+
f[1,2]
|
117
|
+
__END
|
118
|
+
expect {
|
119
|
+
language.check(expr)
|
120
|
+
}.to raise_error(TypedRb::TypeCheckError)
|
121
|
+
|
122
|
+
expr = <<__END
|
123
|
+
class Integer
|
124
|
+
ts '#foo / String -> String'
|
125
|
+
def foo(x); 'foo'; end
|
126
|
+
end
|
127
|
+
|
128
|
+
f = ->(x,y) { x.foo(y) }
|
129
|
+
f[1,'bar']
|
130
|
+
__END
|
131
|
+
result = language.check(expr)
|
132
|
+
expect(result).to eq(tystring)
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
@@ -0,0 +1,217 @@
|
|
1
|
+
require_relative '../../spec_helper'
|
2
|
+
|
3
|
+
#TODO: parsing function will return a symbol, not the function
|
4
|
+
# some of this specs expectations need to change
|
5
|
+
describe TypedRb::Model::TmSend do
|
6
|
+
let(:language) { TypedRb::Language.new }
|
7
|
+
|
8
|
+
context 'with functions receiving function' do
|
9
|
+
it 'is possible to pass lambda functions as arguments' do
|
10
|
+
expr = <<__END
|
11
|
+
ts '#t / (String -> Integer) -> Integer'
|
12
|
+
def t(f)
|
13
|
+
f['test']
|
14
|
+
end
|
15
|
+
|
16
|
+
f = ->(s) { 0 }
|
17
|
+
|
18
|
+
t(f)
|
19
|
+
__END
|
20
|
+
|
21
|
+
result = language.check(expr)
|
22
|
+
expect(result).to eq(tyinteger)
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'detects type check errors in the lambda functions passed as arguments' do
|
26
|
+
|
27
|
+
classes = <<__END
|
28
|
+
class Animal
|
29
|
+
ts '#initialize / -> unit'
|
30
|
+
|
31
|
+
ts '#animal / -> unit'
|
32
|
+
def animal; end
|
33
|
+
end
|
34
|
+
|
35
|
+
class Mammal < Animal
|
36
|
+
ts '#initialize / -> unit'
|
37
|
+
|
38
|
+
ts '#mammal / -> unit'
|
39
|
+
def mammal; end
|
40
|
+
end
|
41
|
+
|
42
|
+
class Cat < Mammal
|
43
|
+
ts '#initialize / -> unit'
|
44
|
+
|
45
|
+
ts '#cat / -> unit'
|
46
|
+
def cat; end
|
47
|
+
end
|
48
|
+
__END
|
49
|
+
|
50
|
+
expr = <<__END
|
51
|
+
#{classes}
|
52
|
+
|
53
|
+
ts '#t / (Mammal -> Integer) -> Integer'
|
54
|
+
def t(f)
|
55
|
+
f[Mammal.new]
|
56
|
+
end
|
57
|
+
|
58
|
+
f = ->(s=Mammal.new) { 1.0 }
|
59
|
+
|
60
|
+
t(f)
|
61
|
+
__END
|
62
|
+
|
63
|
+
expect {
|
64
|
+
language.check(expr)
|
65
|
+
}.to raise_error(TypedRb::TypeCheckError)
|
66
|
+
end
|
67
|
+
|
68
|
+
it 'respects contravariance in the input type' do
|
69
|
+
|
70
|
+
classes = <<__END
|
71
|
+
class Animal
|
72
|
+
ts '#initialize / -> unit'
|
73
|
+
|
74
|
+
ts '#animal / -> unit'
|
75
|
+
def animal; end
|
76
|
+
end
|
77
|
+
|
78
|
+
class Mammal < Animal
|
79
|
+
ts '#initialize / -> unit'
|
80
|
+
|
81
|
+
ts '#mammal / -> unit'
|
82
|
+
def mammal; end
|
83
|
+
end
|
84
|
+
|
85
|
+
class Cat < Mammal
|
86
|
+
ts '#initialize / -> unit'
|
87
|
+
|
88
|
+
ts '#cat / -> unit'
|
89
|
+
def cat; end
|
90
|
+
end
|
91
|
+
__END
|
92
|
+
|
93
|
+
expr = <<__END
|
94
|
+
#{classes}
|
95
|
+
|
96
|
+
ts '#t / (Mammal -> Integer) -> Integer'
|
97
|
+
def t(f)
|
98
|
+
f[Mammal.new]
|
99
|
+
end
|
100
|
+
|
101
|
+
lambda {
|
102
|
+
f = ->(s=Cat.new) { s.cat }
|
103
|
+
t(f)
|
104
|
+
}
|
105
|
+
__END
|
106
|
+
|
107
|
+
#expect {
|
108
|
+
language.check(expr)
|
109
|
+
#cat undefined for Mammal,
|
110
|
+
# s => cat s :gt Cat, s :gt Mammal
|
111
|
+
#}.to raise_error(TypedRb::TypeCheckError)
|
112
|
+
|
113
|
+
# TODO: review this?
|
114
|
+
# Actually the previous code does not
|
115
|
+
# throw an error because
|
116
|
+
# Mammal#cat is resolved into
|
117
|
+
# a Dynamic function instead of
|
118
|
+
# failing because no type information
|
119
|
+
# can be found.
|
120
|
+
|
121
|
+
expr = <<__END
|
122
|
+
#{classes}
|
123
|
+
|
124
|
+
ts '#mammal_to_i / (Mammal -> Integer) -> Integer'
|
125
|
+
def mammal_to_i(mammalf)
|
126
|
+
mammalf[Mammal.new]
|
127
|
+
end
|
128
|
+
|
129
|
+
ts '#cat_to_i / (Cat -> Integer) -> Integer'
|
130
|
+
def cat_to_i(catf)
|
131
|
+
mammal_to_i(catf)
|
132
|
+
end
|
133
|
+
__END
|
134
|
+
expect {
|
135
|
+
language.check(expr)
|
136
|
+
# Cat not >= Mammal
|
137
|
+
}.to raise_error(TypedRb::TypeCheckError)
|
138
|
+
|
139
|
+
expr = <<__END
|
140
|
+
#{classes}
|
141
|
+
|
142
|
+
ts '#mammal_to_i / (Mammal -> Integer) -> Integer'
|
143
|
+
def mammal_to_i(mammalf)
|
144
|
+
mammalf[Mammal.new]
|
145
|
+
end
|
146
|
+
|
147
|
+
ts '#animal_to_i / (Animal -> Integer) -> Integer'
|
148
|
+
def animal_to_i(animalf)
|
149
|
+
mammal_to_i(animalf)
|
150
|
+
end
|
151
|
+
__END
|
152
|
+
result = language.check(expr)
|
153
|
+
expect(result.to_s).to eq('((Animal -> Integer) -> Integer)')
|
154
|
+
end
|
155
|
+
|
156
|
+
it 'respects covariance in the output type' do
|
157
|
+
|
158
|
+
classes = <<__END
|
159
|
+
class Animal
|
160
|
+
ts '#initialize / -> unit'
|
161
|
+
|
162
|
+
ts '#animal / -> unit'
|
163
|
+
def animal; end
|
164
|
+
end
|
165
|
+
|
166
|
+
class Mammal < Animal
|
167
|
+
ts '#initialize / -> unit'
|
168
|
+
|
169
|
+
ts '#mammal / -> unit'
|
170
|
+
def mammal; end
|
171
|
+
end
|
172
|
+
|
173
|
+
class Cat < Mammal
|
174
|
+
ts '#initialize / -> unit'
|
175
|
+
|
176
|
+
ts '#cat / -> unit'
|
177
|
+
def cat; end
|
178
|
+
end
|
179
|
+
__END
|
180
|
+
|
181
|
+
expr = <<__END
|
182
|
+
#{classes}
|
183
|
+
|
184
|
+
ts '#integer_to_mammal / (Integer -> Mammal) -> Mammal'
|
185
|
+
def integer_to_mammal(mammalf)
|
186
|
+
mammalf[1]
|
187
|
+
end
|
188
|
+
|
189
|
+
ts '#integer_to_animal / (Integer -> Animal) -> Mammal'
|
190
|
+
def integer_to_animal(animalf)
|
191
|
+
integer_to_mammal(animalf)
|
192
|
+
end
|
193
|
+
__END
|
194
|
+
expect do
|
195
|
+
language.check(expr)
|
196
|
+
end.to raise_error(TypedRb::TypeCheckError)
|
197
|
+
|
198
|
+
|
199
|
+
expr = <<__END
|
200
|
+
#{classes}
|
201
|
+
|
202
|
+
ts '#integer_to_mammal / (Integer -> Mammal) -> Mammal'
|
203
|
+
def integer_to_mammal(mammalf)
|
204
|
+
mammalf[1]
|
205
|
+
end
|
206
|
+
|
207
|
+
ts '#integer_to_cat / (Integer -> Cat) -> Mammal'
|
208
|
+
def integer_to_cat(catf)
|
209
|
+
integer_to_mammal(catf)
|
210
|
+
end
|
211
|
+
__END
|
212
|
+
|
213
|
+
result = language.check(expr)
|
214
|
+
expect(result.to_s).to eq('((Integer -> Cat) -> Mammal)')
|
215
|
+
end
|
216
|
+
end
|
217
|
+
end
|