typed.rb 0.0.11

Sign up to get free protection for your applications and to get access to all the features.
Files changed (173) hide show
  1. checksums.yaml +7 -0
  2. data/Rakefile +26 -0
  3. data/bin/typed.rb +110 -0
  4. data/lib/typed/language.rb +131 -0
  5. data/lib/typed/model/tm_abs.rb +104 -0
  6. data/lib/typed/model/tm_array_literal.rb +25 -0
  7. data/lib/typed/model/tm_boolean.rb +15 -0
  8. data/lib/typed/model/tm_boolean_operator.rb +34 -0
  9. data/lib/typed/model/tm_break.rb +24 -0
  10. data/lib/typed/model/tm_case_when.rb +38 -0
  11. data/lib/typed/model/tm_class.rb +63 -0
  12. data/lib/typed/model/tm_const.rb +29 -0
  13. data/lib/typed/model/tm_defined.rb +19 -0
  14. data/lib/typed/model/tm_error.rb +16 -0
  15. data/lib/typed/model/tm_float.rb +15 -0
  16. data/lib/typed/model/tm_for.rb +42 -0
  17. data/lib/typed/model/tm_fun.rb +165 -0
  18. data/lib/typed/model/tm_global_var.rb +22 -0
  19. data/lib/typed/model/tm_global_var_assignment.rb +20 -0
  20. data/lib/typed/model/tm_hash_literal.rb +32 -0
  21. data/lib/typed/model/tm_if_else.rb +24 -0
  22. data/lib/typed/model/tm_instance_var.rb +23 -0
  23. data/lib/typed/model/tm_instance_var_assignment.rb +32 -0
  24. data/lib/typed/model/tm_int.rb +15 -0
  25. data/lib/typed/model/tm_local_var_asgn.rb +35 -0
  26. data/lib/typed/model/tm_mass_asgn.rb +60 -0
  27. data/lib/typed/model/tm_mlhs.rb +87 -0
  28. data/lib/typed/model/tm_module.rb +51 -0
  29. data/lib/typed/model/tm_next.rb +24 -0
  30. data/lib/typed/model/tm_nil.rb +14 -0
  31. data/lib/typed/model/tm_range_literal.rb +30 -0
  32. data/lib/typed/model/tm_regexp.rb +27 -0
  33. data/lib/typed/model/tm_rescue.rb +27 -0
  34. data/lib/typed/model/tm_return.rb +24 -0
  35. data/lib/typed/model/tm_s_class.rb +30 -0
  36. data/lib/typed/model/tm_self.rb +22 -0
  37. data/lib/typed/model/tm_send.rb +300 -0
  38. data/lib/typed/model/tm_sequencing.rb +53 -0
  39. data/lib/typed/model/tm_string.rb +15 -0
  40. data/lib/typed/model/tm_string_interpolation.rb +21 -0
  41. data/lib/typed/model/tm_super.rb +27 -0
  42. data/lib/typed/model/tm_symbol.rb +15 -0
  43. data/lib/typed/model/tm_symbol_interpolation.rb +21 -0
  44. data/lib/typed/model/tm_try.rb +29 -0
  45. data/lib/typed/model/tm_var.rb +28 -0
  46. data/lib/typed/model/tm_while.rb +43 -0
  47. data/lib/typed/model.rb +48 -0
  48. data/lib/typed/prelude.rb +939 -0
  49. data/lib/typed/prelude_existential_registry.bin +0 -0
  50. data/lib/typed/prelude_generic_registry.bin +0 -0
  51. data/lib/typed/prelude_registry.bin +0 -0
  52. data/lib/typed/runtime/ast_parser.rb +589 -0
  53. data/lib/typed/runtime/method_signature_processor.rb +72 -0
  54. data/lib/typed/runtime/normalization/validations.rb +47 -0
  55. data/lib/typed/runtime/normalization.rb +196 -0
  56. data/lib/typed/runtime/parser_context.rb +36 -0
  57. data/lib/typed/runtime/type_parser.rb +215 -0
  58. data/lib/typed/runtime/type_registry.rb +170 -0
  59. data/lib/typed/runtime/type_signature_processor.rb +34 -0
  60. data/lib/typed/runtime.rb +33 -0
  61. data/lib/typed/type_signature/parser.rb +240 -0
  62. data/lib/typed/types/polymorphism/existential_type_variable.rb +13 -0
  63. data/lib/typed/types/polymorphism/generic_comparisons.rb +134 -0
  64. data/lib/typed/types/polymorphism/generic_variables.rb +24 -0
  65. data/lib/typed/types/polymorphism/type_variable.rb +138 -0
  66. data/lib/typed/types/polymorphism/type_variable_register.rb +298 -0
  67. data/lib/typed/types/polymorphism/unification.rb +579 -0
  68. data/lib/typed/types/ty_boolean.rb +15 -0
  69. data/lib/typed/types/ty_dynamic.rb +39 -0
  70. data/lib/typed/types/ty_either.rb +168 -0
  71. data/lib/typed/types/ty_error.rb +18 -0
  72. data/lib/typed/types/ty_existential_type.rb +22 -0
  73. data/lib/typed/types/ty_function.rb +144 -0
  74. data/lib/typed/types/ty_generic_function.rb +115 -0
  75. data/lib/typed/types/ty_generic_object.rb +180 -0
  76. data/lib/typed/types/ty_generic_singleton_object.rb +238 -0
  77. data/lib/typed/types/ty_object.rb +256 -0
  78. data/lib/typed/types/ty_singleton_object.rb +78 -0
  79. data/lib/typed/types/ty_stack_jump.rb +44 -0
  80. data/lib/typed/types/ty_top_level_object.rb +38 -0
  81. data/lib/typed/types.rb +60 -0
  82. data/lib/typed/typing_context.rb +206 -0
  83. data/lib/typed/version.rb +3 -0
  84. data/lib/typed.rb +161 -0
  85. data/spec/lib/ast_parser_spec.rb +101 -0
  86. data/spec/lib/examples/animals.rb +44 -0
  87. data/spec/lib/examples/counter.rb +16 -0
  88. data/spec/lib/examples/if.rb +31 -0
  89. data/spec/lib/language_spec.rb +36 -0
  90. data/spec/lib/model/tm_abs_spec.rb +66 -0
  91. data/spec/lib/model/tm_array_literal_spec.rb +36 -0
  92. data/spec/lib/model/tm_case_when_spec.rb +39 -0
  93. data/spec/lib/model/tm_class_spec.rb +67 -0
  94. data/spec/lib/model/tm_defined_spec.rb +10 -0
  95. data/spec/lib/model/tm_for_spec.rb +150 -0
  96. data/spec/lib/model/tm_fun_spec.rb +11 -0
  97. data/spec/lib/model/tm_hash_literal_spec.rb +40 -0
  98. data/spec/lib/model/tm_mass_asgn_spec.rb +104 -0
  99. data/spec/lib/model/tm_module_spec.rb +42 -0
  100. data/spec/lib/model/tm_regexp_spec.rb +9 -0
  101. data/spec/lib/model/tm_return_spec.rb +47 -0
  102. data/spec/lib/model/tm_s_class_spec.rb +27 -0
  103. data/spec/lib/model/tm_self_spec.rb +19 -0
  104. data/spec/lib/model/tm_string_interpolation_spec.rb +10 -0
  105. data/spec/lib/model/tm_symbol_interpolation_spec.rb +10 -0
  106. data/spec/lib/model/tm_symbol_spec.rb +9 -0
  107. data/spec/lib/model/tm_while_spec.rb +141 -0
  108. data/spec/lib/polymorphism/type_variable_spec.rb +14 -0
  109. data/spec/lib/polymorphism/unification_spec.rb +328 -0
  110. data/spec/lib/prelude/array_spec.rb +263 -0
  111. data/spec/lib/prelude/class_spec.rb +12 -0
  112. data/spec/lib/prelude/enumerable_spec.rb +278 -0
  113. data/spec/lib/prelude/enumerator_spec.rb +101 -0
  114. data/spec/lib/prelude/hash_spec.rb +361 -0
  115. data/spec/lib/prelude/kernel_spec.rb +23 -0
  116. data/spec/lib/prelude/object_spec.rb +22 -0
  117. data/spec/lib/prelude/pair_spec.rb +16 -0
  118. data/spec/lib/prelude/showable_spec.rb +31 -0
  119. data/spec/lib/prelude/string_spec.rb +98 -0
  120. data/spec/lib/runtime/normalization_spec.rb +29 -0
  121. data/spec/lib/runtime/validations_spec.rb +56 -0
  122. data/spec/lib/runtime_spec.rb +503 -0
  123. data/spec/lib/type_signature/parser_spec.rb +239 -0
  124. data/spec/lib/types/comparisons_spec.rb +35 -0
  125. data/spec/lib/types/polymorphism/generic_comparisons_spec.rb +492 -0
  126. data/spec/lib/types/polymorphism/type_variable_register_spec.rb +128 -0
  127. data/spec/lib/types/ty_dynamic_spec.rb +103 -0
  128. data/spec/lib/types/ty_either_spec.rb +288 -0
  129. data/spec/lib/types/ty_error_spec.rb +18 -0
  130. data/spec/lib/types/ty_generic_object_spec.rb +78 -0
  131. data/spec/lib/types/ty_generic_singleton_object_spec.rb +288 -0
  132. data/spec/lib/types/typing_context_spec.rb +86 -0
  133. data/spec/lib/types_spec.rb +174 -0
  134. data/spec/lib/typing/boolean_asgn_spec.rb +134 -0
  135. data/spec/lib/typing/break_spec.rb +79 -0
  136. data/spec/lib/typing/generics_spec.rb +191 -0
  137. data/spec/lib/typing/instance_vars_spec.rb +103 -0
  138. data/spec/lib/typing/next_spec.rb +29 -0
  139. data/spec/lib/typing/op_asgn_spec.rb +104 -0
  140. data/spec/lib/typing/overriden_methods_spec.rb +31 -0
  141. data/spec/lib/typing/subtyping_spec.rb +112 -0
  142. data/spec/lib/typing/tm_boolean_operator_spec.rb +100 -0
  143. data/spec/lib/typing/tm_boolean_spec.rb +61 -0
  144. data/spec/lib/typing/tm_const_spec.rb +28 -0
  145. data/spec/lib/typing/tm_defined_spec.rb +12 -0
  146. data/spec/lib/typing/tm_fun_spec.rb +347 -0
  147. data/spec/lib/typing/tm_global_var_spec.rb +33 -0
  148. data/spec/lib/typing/tm_if_else_spec.rb +104 -0
  149. data/spec/lib/typing/tm_ignore_spec.rb +24 -0
  150. data/spec/lib/typing/tm_instance_vars_spec.rb +117 -0
  151. data/spec/lib/typing/tm_local_var_asgn_spec.rb +134 -0
  152. data/spec/lib/typing/tm_mlhs_spec.rb +164 -0
  153. data/spec/lib/typing/tm_module_spec.rb +89 -0
  154. data/spec/lib/typing/tm_raise_spec.rb +31 -0
  155. data/spec/lib/typing/tm_range_literal_spec.rb +25 -0
  156. data/spec/lib/typing/tm_regexp_spec.rb +14 -0
  157. data/spec/lib/typing/tm_return_spec.rb +45 -0
  158. data/spec/lib/typing/tm_send_casting_spec.rb +26 -0
  159. data/spec/lib/typing/tm_send_class_methods_spec.rb +42 -0
  160. data/spec/lib/typing/tm_send_generic_apply_spec.rb +103 -0
  161. data/spec/lib/typing/tm_send_generic_methods_spec.rb +77 -0
  162. data/spec/lib/typing/tm_send_initialize_spec.rb +68 -0
  163. data/spec/lib/typing/tm_send_lambda_spec.rb +135 -0
  164. data/spec/lib/typing/tm_send_spec.rb +217 -0
  165. data/spec/lib/typing/tm_send_yield_block_spec.rb +308 -0
  166. data/spec/lib/typing/tm_sequencing_spec.rb +174 -0
  167. data/spec/lib/typing/tm_string_interpolation_spec.rb +19 -0
  168. data/spec/lib/typing/tm_super_spec.rb +63 -0
  169. data/spec/lib/typing/tm_symbol_interpolation_spec.rb +19 -0
  170. data/spec/lib/typing/tm_symbol_spec.rb +14 -0
  171. data/spec/lib/typing/tm_try_spec.rb +73 -0
  172. data/spec/spec_helper.rb +140 -0
  173. metadata +216 -0
@@ -0,0 +1,66 @@
1
+ require_relative '../../spec_helper'
2
+
3
+ describe TypedRb::Model::TmAbs do
4
+
5
+ it 'parses a lambda function with multiple args' do
6
+ parsed = parse('->(x,y) { x + y }')
7
+
8
+ expect(parsed).to be_instance_of(described_class)
9
+ expect(parsed.arity).to eq(2)
10
+ expect(parsed.abs_type).to eq(:lambda)
11
+
12
+ result = parsed.check_type(top_level_typing_context)
13
+
14
+ expect(result.from[0]).to be_instance_of(TypedRb::Types::Polymorphism::TypeVariable)
15
+ expect(result.from[1]).to be_instance_of(TypedRb::Types::Polymorphism::TypeVariable)
16
+ expect(result.from.size).to eq(2)
17
+ expect(result.from[0].variable.index("lambda:#{parsed.term.receiver.val}")).to_not be_nil
18
+ expect(result.from[1].variable.index("lambda:#{parsed.term.args[0].val}")).to_not be_nil
19
+ end
20
+
21
+ it 'check types creating the right constraints for the type variables' do
22
+ parsed = parse('->(x,y) { x + y }')
23
+ expect(parsed.arity).to eq(2)
24
+ expect(parsed.abs_type).to eq(:lambda)
25
+
26
+ result = parsed.check_type(top_level_typing_context)
27
+
28
+ TypedRb::Types::TypingContext.with_context(result.local_typing_context) do
29
+ expect(result.from.size).to eq(2)
30
+ expect(result.from[0]).to be_a(TypedRb::Types::Polymorphism::TypeVariable)
31
+ expect(result.from[0].constraints[0][1]).to eq(:send)
32
+ expect(result.from[1]).to be_a(TypedRb::Types::Polymorphism::TypeVariable)
33
+ expect(result.to).to be_a(TypedRb::Types::Polymorphism::TypeVariable)
34
+ end
35
+ end
36
+
37
+ it 'parses a Proc with multiple args' do
38
+ parsed = parse('Proc.new{ |x,y| x + y }')
39
+
40
+ expect(parsed).to be_instance_of(described_class)
41
+ expect(parsed.arity).to eq(2)
42
+ expect(parsed.abs_type).to eq(:proc)
43
+
44
+ result = parsed.check_type(top_level_typing_context)
45
+
46
+ expect(result.from[0]).to be_instance_of(TypedRb::Types::Polymorphism::TypeVariable)
47
+ expect(result.from[1]).to be_instance_of(TypedRb::Types::Polymorphism::TypeVariable)
48
+ expect(result.from.size).to eq(2)
49
+ expect(result.from[0].variable.index("lambda:#{parsed.term.receiver.val}")).to_not be_nil
50
+ expect(result.from[1].variable.index("lambda:#{parsed.term.args[0].val}")).to_not be_nil
51
+ end
52
+
53
+ it 'check types creating the right constraints for the type variables' do
54
+ parsed = parse('Proc.new { |x,y| x + y }')
55
+ expect(parsed.arity).to eq(2)
56
+ expect(parsed.abs_type).to eq(:proc)
57
+ result = parsed.check_type(top_level_typing_context)
58
+ TypedRb::Types::TypingContext.with_context(result.local_typing_context) do
59
+ expect(result.from.size).to eq(2)
60
+ expect(result.from[0]).to be_a(TypedRb::Types::Polymorphism::TypeVariable)
61
+ expect(result.from[0].constraints[0][1]).to eq(:send)
62
+ expect(result.from[1]).to be_a(TypedRb::Types::Polymorphism::TypeVariable)
63
+ expect(result.to).to be_a(TypedRb::Types::Polymorphism::TypeVariable)
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,36 @@
1
+ require_relative '../../spec_helper'
2
+
3
+ describe TypedRb::Model::TmArrayLiteral do
4
+
5
+ it 'parses array literals with the same type' do
6
+ code = '[1, 2, 3]'
7
+
8
+ parsed = TypedRb::Language.new.check(code)
9
+ expect(parsed.ruby_type).to eq(Array)
10
+ expect(parsed.type_vars.first.bound.ruby_type).to eq(Integer)
11
+ end
12
+
13
+ it 'parses array literals with compatible types' do
14
+ code = '[1, Numeric.new, 3]'
15
+
16
+ parsed = TypedRb::Language.new.check(code)
17
+ expect(parsed.ruby_type).to eq(Array)
18
+ expect(parsed.type_vars.first.bound.ruby_type).to eq(Numeric)
19
+ end
20
+
21
+ it 'parses array literals with nil values' do
22
+ code = '[1, Numeric.new, nil]'
23
+
24
+ parsed = TypedRb::Language.new.check(code)
25
+ expect(parsed.ruby_type).to eq(Array)
26
+ expect(parsed.type_vars.first.bound.ruby_type).to eq(Numeric)
27
+ end
28
+
29
+ it 'parses array literals with incompatible values' do
30
+ code = '[1, "string"]'
31
+
32
+ parsed = TypedRb::Language.new.check(code)
33
+ expect(parsed.ruby_type).to eq(Array)
34
+ expect(parsed.type_vars.first.bound.ruby_type).to eq(Object)
35
+ end
36
+ end
@@ -0,0 +1,39 @@
1
+ require_relative '../../spec_helper'
2
+
3
+ describe TypedRb::Model::TmCaseWhen do
4
+ let(:language) { TypedRb::Language.new }
5
+
6
+ it 'type checks a simple case/when statement' do
7
+ code = <<__CODE
8
+ a = 'a'
9
+ case a
10
+ when 'a'
11
+ a
12
+ when 'b'
13
+ a
14
+ else
15
+ 'other'
16
+ end
17
+ __CODE
18
+
19
+ parsed = language.check(code)
20
+ expect(parsed.ruby_type).to eq(String)
21
+ end
22
+
23
+ it 'Promotes types to union type in case/when expressions' do
24
+ code = <<__CODE
25
+ a = 'a'
26
+ case a
27
+ when 'a'
28
+ a
29
+ when 'b'
30
+ 0
31
+ else
32
+ 'other'
33
+ end
34
+ __CODE
35
+
36
+ parsed = language.check(code)
37
+ expect(parsed.ruby_type).to eq(Object)
38
+ end
39
+ end
@@ -0,0 +1,67 @@
1
+ require_relative '../../spec_helper'
2
+
3
+ describe TypedRb::Model::TmClass do
4
+ let(:language) { TypedRb::Language.new }
5
+
6
+ it 'parses a generic type' do
7
+ code = <<__CODE
8
+ ts 'type Pod[X<Numeric]'
9
+ class Pod
10
+
11
+ ts '#put / [X] -> unit'
12
+ def put(n)
13
+ @value = n
14
+ end
15
+
16
+ ts '#take / -> [X]'
17
+ def take
18
+ @value
19
+ end
20
+ end
21
+
22
+ Pod
23
+ __CODE
24
+
25
+ parsed = language.check(code)
26
+
27
+ expect(parsed).to be_instance_of(TypedRb::Types::TyGenericSingletonObject)
28
+ value_instance_var = parsed.local_typing_context.type_variables_register[[:instance_variable, Pod, :@value]]
29
+ expect(value_instance_var).to_not be_nil
30
+ expect(value_instance_var.variable.index('Pod:@value')).to_not be_nil
31
+ value_instance_var_constraints = parsed.local_typing_context.constraints[value_instance_var.variable]
32
+ expect(value_instance_var_constraints.size).to eq(2)
33
+ end
34
+
35
+ it 'handles nested classes' do
36
+ code = <<__CODE
37
+ module TCNS
38
+ class TC
39
+ ts '#test / -> Integer'
40
+ def test; 1; end
41
+ end
42
+ end
43
+
44
+ TCNS::TC.new.test
45
+ __CODE
46
+
47
+ result = language.check(code)
48
+ expect(result.ruby_type).to eq(Integer)
49
+ end
50
+
51
+ it 'handles nested classes in return arguments' do
52
+ code = <<__CODE
53
+ module TCNS
54
+ class TC2; end
55
+ class TC3
56
+ ts '#test / -> Class'
57
+ def test; TC2; end
58
+ end
59
+ end
60
+
61
+ TCNS::TC3.new.test
62
+ __CODE
63
+
64
+ result = language.check(code)
65
+ expect(result.ruby_type).to eq(Class)
66
+ end
67
+ end
@@ -0,0 +1,10 @@
1
+ require_relative '../../spec_helper'
2
+
3
+ describe TypedRb::Model::TmDefined do
4
+
5
+ it 'parses a defined invocation' do
6
+ parsed = parse('defined? 2')
7
+ expect(parsed).to be_instance_of(described_class)
8
+ expect(parsed.expression).to be_instance_of(TypedRb::Model::TmInt)
9
+ end
10
+ end
@@ -0,0 +1,150 @@
1
+ require_relative '../../spec_helper'
2
+
3
+ describe TypedRb::Model::TmFor 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); x + 1; end
12
+
13
+ for i in 0..3
14
+ test_i_fn(i)
15
+ end
16
+ __CODE
17
+
18
+ parsed = language.check(code)
19
+ expect(parsed.ruby_type).to eq(Integer)
20
+ end
21
+
22
+ it 'type checks a for statement, negative case' do
23
+ code = <<__CODE
24
+ ts '#test_s_fn / String -> Integer'
25
+ def test_s_fn(x); 0; end
26
+
27
+ for i in 0..3
28
+ test_s_fn(i)
29
+ end
30
+ __CODE
31
+
32
+ expect {
33
+ language.check(code)
34
+ }.to raise_error(TypedRb::Types::UncomparableTypes)
35
+ end
36
+ end
37
+
38
+ describe 'Simple for loop, break' do
39
+ let(:language) { TypedRb::Language.new }
40
+
41
+ it 'type checks a for statement' do
42
+ code = <<__CODE
43
+ ts '#test_i_fn / Integer -> Integer'
44
+ def test_i_fn(x); x + 1; end
45
+
46
+ for i in 0..3
47
+ break 7
48
+ ""
49
+ end
50
+ __CODE
51
+
52
+ parsed = language.check(code)
53
+ expect(parsed.ruby_type).to eq(Integer)
54
+ end
55
+
56
+ it 'type checks a for statement, no value' do
57
+ code = <<__CODE
58
+ ts '#test_i_fn / Integer -> Integer'
59
+ def test_i_fn(x); x + 1; end
60
+
61
+ for i in 0..3
62
+ break
63
+ ""
64
+ end
65
+ __CODE
66
+
67
+ parsed = language.check(code)
68
+ expect(parsed.ruby_type).to eq(NilClass)
69
+ end
70
+
71
+ it 'type checks a for statement returning an array' do
72
+ code = <<__CODE
73
+ for i in 0..3
74
+ break 7,3
75
+ ""
76
+ end
77
+ __CODE
78
+
79
+ parsed = language.check(code)
80
+ expect(parsed.to_s).to eq('Array[Integer]')
81
+ end
82
+ end
83
+
84
+ describe 'Simple for loop, next' do
85
+ let(:language) { TypedRb::Language.new }
86
+
87
+ it 'type checks a for statement' do
88
+ code = <<__CODE
89
+ a = for i in 0..3
90
+ next(3)
91
+ nil
92
+ end
93
+ a
94
+ __CODE
95
+
96
+ parsed = language.check(code)
97
+ expect(parsed.ruby_type).to eq(Integer)
98
+ end
99
+
100
+ it 'type checks a for statement, no value' do
101
+ code = <<__CODE
102
+ a = for i in 0..3
103
+ next
104
+ nil
105
+ end
106
+ a
107
+ __CODE
108
+
109
+ parsed = language.check(code)
110
+ expect(parsed.ruby_type).to eq(NilClass)
111
+ end
112
+ end
113
+
114
+ describe 'Simple for loop, next array' do
115
+ let(:language) { TypedRb::Language.new }
116
+
117
+ it 'type checks a for statement' do
118
+ code = <<__CODE
119
+ a = for i in 0..3
120
+ next 3,4
121
+ nil
122
+ end
123
+ a
124
+ __CODE
125
+
126
+ parsed = language.check(code)
127
+ expect(parsed.to_s).to eq('Array[Integer]')
128
+ end
129
+ end
130
+
131
+ describe 'Simple for loop, either' do
132
+ let(:language) { TypedRb::Language.new }
133
+
134
+ it 'type checks a for statement' do
135
+ code = <<__CODE
136
+ a = for i in 0..3
137
+ if i == 0
138
+ next(3)
139
+ else
140
+ i
141
+ end
142
+ end
143
+ a
144
+ __CODE
145
+
146
+ parsed = language.check(code)
147
+ expect(parsed.ruby_type).to eq(Integer)
148
+ end
149
+ end
150
+ end
@@ -0,0 +1,11 @@
1
+ require_relative '../../spec_helper'
2
+
3
+ describe TypedRb::Model::TmFun do
4
+ it 'parses a function with rest args' do
5
+ parsed = parse('def f(a,*rest); end')
6
+ expect(parsed).to be_instance_of(described_class)
7
+ expect(parsed.args.size).to eq(2)
8
+ expect(parsed.args.last.first).to eq(:restarg)
9
+ parsed.check_type(TypedRb::Types::TypingContext.top_level)
10
+ end
11
+ end
@@ -0,0 +1,40 @@
1
+ require_relative '../../spec_helper'
2
+
3
+ describe TypedRb::Model::TmHashLiteral do
4
+
5
+ it 'parses hash literals with the same type' do
6
+ code = '{:a => 1, :b => 2}'
7
+
8
+ parsed = TypedRb::Language.new.check(code)
9
+ expect(parsed.ruby_type).to eq(Hash)
10
+ expect(parsed.type_vars.first.bound.ruby_type).to eq(Symbol)
11
+ expect(parsed.type_vars.last.bound.ruby_type).to eq(Integer)
12
+ end
13
+
14
+ it 'parses hash literals with compatible types' do
15
+ code = '{2 => 1, 3 => Numeric.new, Numeric.new => 4}'
16
+
17
+ parsed = TypedRb::Language.new.check(code)
18
+ expect(parsed.ruby_type).to eq(Hash)
19
+ expect(parsed.type_vars.first.bound.ruby_type).to eq(Numeric)
20
+ expect(parsed.type_vars.last.bound.ruby_type).to eq(Numeric)
21
+ end
22
+
23
+ it 'parses array literals with nil values' do
24
+ code = '{:x => 1, nil => Numeric.new, :z => nil}'
25
+
26
+ parsed = TypedRb::Language.new.check(code)
27
+ expect(parsed.ruby_type).to eq(Hash)
28
+ expect(parsed.type_vars.first.bound.ruby_type).to eq(Symbol)
29
+ expect(parsed.type_vars.last.bound.ruby_type).to eq(Numeric)
30
+ end
31
+
32
+ it 'parses array literals with incompatible values' do
33
+ code = '{:x => 1, 2 => "string"}'
34
+
35
+ parsed = TypedRb::Language.new.check(code)
36
+ expect(parsed.ruby_type).to eq(Hash)
37
+ expect(parsed.type_vars.first.bound.ruby_type).to eq(Object)
38
+ expect(parsed.type_vars.last.bound.ruby_type).to eq(Object)
39
+ end
40
+ end
@@ -0,0 +1,104 @@
1
+ require_relative '../../spec_helper'
2
+
3
+ describe TypedRb::Model::TmMassAsgn do
4
+
5
+ it 'parses mass assignment' do
6
+ code = <<__CODE
7
+ ts '#fma1 / -> Array[Integer]'
8
+ def fma1; Array.(Integer).new; end
9
+
10
+ a,b = fma1
11
+ __CODE
12
+
13
+ parsed = TypedRb::Language.new.check(code)
14
+ expect(parsed.ruby_type).to eq(Array)
15
+
16
+ code = <<__CODE
17
+ ts '#fma1 / -> Array[Integer]'
18
+ def fma1; Array.(Integer).new; end
19
+
20
+ a,b = fma1
21
+ a
22
+ __CODE
23
+
24
+ parsed = TypedRb::Language.new.check(code)
25
+ expect(parsed.bound.ruby_type).to eq(Integer)
26
+
27
+
28
+ code = <<__CODE
29
+ ts '#fma1 / -> Array[Integer]'
30
+ def fma1; Array.(Integer).new; end
31
+
32
+ a,b = fma1
33
+ b
34
+ __CODE
35
+
36
+ parsed = TypedRb::Language.new.check(code)
37
+ expect(parsed.bound.ruby_type).to eq(Integer)
38
+
39
+ code = <<__CODE
40
+ ts '#fma1 / -> Array[Integer]'
41
+ def fma1; Array.(Integer).new; end
42
+
43
+ ts '#fmai1 / -> Integer'
44
+ def fmai1
45
+ a,b = fma1
46
+ a
47
+ end
48
+
49
+ fmai1
50
+ __CODE
51
+ parsed = TypedRb::Language.new.check(code)
52
+ expect(parsed.ruby_type).to eq(Integer)
53
+ end
54
+
55
+ it 'parses mass assignment when returning scalar types' do
56
+ code = <<__CODE
57
+ ts '#fma2 / -> String'
58
+ def fma2; 'string'; end
59
+
60
+ a,b = fma2
61
+ __CODE
62
+
63
+ parsed = TypedRb::Language.new.check(code)
64
+ expect(parsed.ruby_type).to eq(String)
65
+
66
+ code = <<__CODE
67
+ ts '#fma2 / -> String'
68
+ def fma2; 'string'; end
69
+
70
+ a,b = fma2
71
+ a
72
+ __CODE
73
+
74
+ parsed = TypedRb::Language.new.check(code)
75
+ expect(parsed.ruby_type).to eq(String)
76
+
77
+
78
+ code = <<__CODE
79
+ ts '#fma2 / -> String'
80
+ def fma2; 'string'; end
81
+
82
+ a,b = fma2
83
+ b
84
+ __CODE
85
+
86
+ parsed = TypedRb::Language.new.check(code)
87
+ expect(parsed).to eq(tyunit)
88
+
89
+ code = <<__CODE
90
+ ts '#fma2 / -> String'
91
+ def fma2; 'string'; end
92
+
93
+ ts '#fmai2 / -> String'
94
+ def fmai2
95
+ a,b = fma2
96
+ a
97
+ end
98
+
99
+ fmai2
100
+ __CODE
101
+ parsed = TypedRb::Language.new.check(code)
102
+ expect(parsed.ruby_type).to eq(String)
103
+ end
104
+ end
@@ -0,0 +1,42 @@
1
+ require_relative '../../spec_helper'
2
+
3
+ describe TypedRb::Model::TmModule do
4
+
5
+ it 'parses ruby modules' do
6
+ code = <<__CODE
7
+ module TMod1
8
+ ts '#x / -> unit'
9
+ def x; 'test'; end
10
+ end
11
+ __CODE
12
+
13
+ parsed = TypedRb::Language.new.check(code)
14
+ expect(parsed.is_a?(TypedRb::Types::TyExistentialType)).to eq(true)
15
+ expect(parsed.ruby_type).to eq(TMod1)
16
+ end
17
+
18
+ it 'parses nested modules' do
19
+ code = <<__CODE
20
+ module TMod1
21
+ module TMod2
22
+ module TMod3
23
+ module TMod4
24
+ class TMod4C1
25
+ ts '#x / -> Integer'
26
+ def x
27
+ 0
28
+ end
29
+ end
30
+ end
31
+ end
32
+ class TMod4C2; end
33
+ end
34
+ end
35
+
36
+ TMod1::TMod2::TMod3::TMod4::TMod4C1.new.x
37
+ __CODE
38
+
39
+ parsed = TypedRb::Language.new.check(code)
40
+ expect(parsed.ruby_type).to eq(Integer)
41
+ end
42
+ end
@@ -0,0 +1,9 @@
1
+ require_relative '../../spec_helper'
2
+
3
+ describe TypedRb::Model::TmRegexp do
4
+
5
+ it 'parses a regular expression' do
6
+ parsed = parse('/[Rr]eg[Ee]xp/')
7
+ expect(parsed).to be_instance_of(described_class)
8
+ end
9
+ end
@@ -0,0 +1,47 @@
1
+ require_relative '../../spec_helper'
2
+
3
+ describe TypedRb::Model::TmArrayLiteral do
4
+ it 'parses return instructions with single types' do
5
+ code = <<__CODE
6
+ ts '#fret1 / -> Integer'
7
+ def fret1
8
+ return 1
9
+ end
10
+
11
+ fret1
12
+ __CODE
13
+
14
+ parsed = TypedRb::Language.new.check(code)
15
+ expect(parsed.ruby_type).to eq(Integer)
16
+ end
17
+
18
+ it 'parses return instructions with multiple compatible types' do
19
+ code = <<__CODE
20
+ ts '#fret2 / -> Array[Integer]'
21
+ def fret2
22
+ return 1, 2
23
+ end
24
+
25
+ fret2
26
+ __CODE
27
+
28
+ parsed = TypedRb::Language.new.check(code)
29
+ expect(parsed.ruby_type).to eq(Array)
30
+ expect(parsed.type_vars.first.bound.ruby_type).to eq(Integer)
31
+ end
32
+
33
+ it 'parses return instructions with multiple incompatible types' do
34
+ code = <<__CODE
35
+ ts '#fret3 / -> Array[Object]'
36
+ def fret3
37
+ return 1, 'string'
38
+ end
39
+
40
+ fret3
41
+ __CODE
42
+
43
+ parsed = TypedRb::Language.new.check(code)
44
+ expect(parsed.ruby_type).to eq(Array)
45
+ expect(parsed.type_vars.first.bound.ruby_type).to eq(Object)
46
+ end
47
+ end
@@ -0,0 +1,27 @@
1
+ require_relative '../../spec_helper'
2
+
3
+ describe TypedRb::Model::TmSClass do
4
+
5
+ it 'parses a singleton class' do
6
+ code = <<__CODE
7
+ ts 'type Pod1[X<Numeric]'
8
+ class Pod1
9
+
10
+ ts '.put / [X] -> unit'
11
+ def self.put(n)
12
+ @value = n
13
+ end
14
+
15
+ class << self
16
+ ts '.take / -> [X]'
17
+ def take
18
+ @value
19
+ end
20
+ end
21
+ end
22
+ __CODE
23
+
24
+ TypedRb::Language.new.check(code)
25
+ expect(BasicObject::TypeRegistry.send(:registry)[[:class,Pod1]].keys).to eq(['put', 'take'])
26
+ end
27
+ end
@@ -0,0 +1,19 @@
1
+ require_relative '../../spec_helper'
2
+
3
+ describe TypedRb::Model::TmSelf do
4
+ it 'returns the self reference type' do
5
+ code = <<__CODE
6
+ class TSelfRef1
7
+ ts '#test / -> TSelfRef1'
8
+ def test
9
+ self
10
+ end
11
+ end
12
+
13
+ TSelfRef1.new.test
14
+ __CODE
15
+
16
+ parsed = TypedRb::Language.new.check(code)
17
+ expect(parsed.ruby_type).to eq(TSelfRef1)
18
+ end
19
+ end
@@ -0,0 +1,10 @@
1
+ require_relative '../../spec_helper'
2
+
3
+ describe TypedRb::Model::TmStringInterpolation do
4
+
5
+ it 'parses interpolation of strings' do
6
+ parsed = parse('"this #{is} an #{interpolation}"')
7
+ expect(parsed).to be_instance_of(described_class)
8
+ expect(parsed.units.size).to eq(4)
9
+ end
10
+ end
@@ -0,0 +1,10 @@
1
+ require_relative '../../spec_helper'
2
+
3
+ describe TypedRb::Model::TmSymbolInterpolation do
4
+
5
+ it 'parses interpolation of strings' do
6
+ parsed = parse(':"this #{is} an #{interpolation}"')
7
+ expect(parsed).to be_instance_of(described_class)
8
+ expect(parsed.units.size).to eq(4)
9
+ end
10
+ end