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,9 @@
1
+ require_relative '../../spec_helper'
2
+
3
+ describe TypedRb::Model::TmSymbol do
4
+
5
+ it 'parses a symbol' do
6
+ parsed = parse(':test')
7
+ expect(parsed).to be_instance_of(described_class)
8
+ end
9
+ end
@@ -0,0 +1,141 @@
1
+ require_relative '../../spec_helper'
2
+
3
+ describe TypedRb::Model::TmWhile do
4
+ let(:language) { TypedRb::Language.new }
5
+
6
+ it 'type checks a simple while statement' do
7
+ code = <<__CODE
8
+ while false
9
+ 1 - 1
10
+ 1 + 1
11
+ end
12
+ __CODE
13
+
14
+ parsed = language.check(code)
15
+ expect(parsed.ruby_type).to eq(Integer)
16
+ end
17
+
18
+ it 'type checks a simple post-while statement' do
19
+ code = <<__CODE
20
+ begin
21
+ 1 - 1
22
+ 1 + 1
23
+ end while false
24
+ __CODE
25
+
26
+ parsed = language.check(code)
27
+ expect(parsed.ruby_type).to eq(Integer)
28
+ end
29
+
30
+ it 'type checks a simple until statement' do
31
+ code = <<__CODE
32
+ until true
33
+ 1 - 1
34
+ 1 + 1
35
+ end
36
+ __CODE
37
+
38
+ parsed = language.check(code)
39
+ expect(parsed.ruby_type).to eq(Integer)
40
+ end
41
+
42
+ it 'type checks a simple post-until statement' do
43
+ code = <<__CODE
44
+ begin
45
+ 1 - 1
46
+ 1 + 1
47
+ end until true
48
+ __CODE
49
+
50
+ parsed = language.check(code)
51
+ expect(parsed.ruby_type).to eq(Integer)
52
+ end
53
+
54
+ it 'type checks a while statement without body' do
55
+ code = <<__CODE
56
+ while false
57
+ end
58
+ __CODE
59
+
60
+ parsed = language.check(code)
61
+ expect(parsed.ruby_type).to eq(NilClass)
62
+ end
63
+
64
+ it 'type checks a break statement in a while loop' do
65
+ code = <<__CODE
66
+ ts '#test_while_next / -> Integer'
67
+ def test_while_next
68
+ a = while(true) do
69
+ next(7)
70
+ end
71
+
72
+ a + 10
73
+ end
74
+ __CODE
75
+
76
+ parsed = language.check(code)
77
+ expect(parsed.to_s).to eq('( -> Integer)')
78
+ end
79
+
80
+ context 'with a either type' do
81
+ it 'type checks the while loop correctly, positive case' do
82
+ code = <<__CODE
83
+ ts '#test_while_next / -> Integer'
84
+ def test_while_next
85
+ a = while(true) do
86
+ if(false)
87
+ 1
88
+ else
89
+ next 0
90
+ end
91
+ end
92
+
93
+ a + 10
94
+ end
95
+ __CODE
96
+
97
+ parsed = language.check(code)
98
+ expect(parsed.to_s).to eq('( -> Integer)')
99
+ end
100
+
101
+ it 'type checks the while loop correctly, negative case' do
102
+ code = <<__CODE
103
+ ts '#test_while_next / -> Integer'
104
+ def test_while_next
105
+ while(true) do
106
+ if(false)
107
+ 1
108
+ else
109
+ next false
110
+ end
111
+ end
112
+ end
113
+ __CODE
114
+
115
+ expect {
116
+ language.check(code)
117
+ }.to raise_error(TypedRb::TypeCheckError)
118
+ end
119
+
120
+ it 'type checks the while loop correctly with a return, positive case' do
121
+ code = <<__CODE
122
+ ts '#test_while_next / -> Integer'
123
+ def test_while_next
124
+ while(true) do
125
+ if (false)
126
+ 1
127
+ elsif (true)
128
+ return 2
129
+ else
130
+ next 0
131
+ end
132
+ end
133
+ end
134
+ __CODE
135
+
136
+
137
+ parsed = language.check(code)
138
+ expect(parsed.to_s).to eq('( -> Integer)')
139
+ end
140
+ end
141
+ end
@@ -0,0 +1,14 @@
1
+ require_relative '../../spec_helper'
2
+
3
+ describe TypedRb::Types::Polymorphism::TypeVariable do
4
+ it 'should record constraints' do
5
+ type = tyobject(Integer)
6
+ type_var = TypedRb::Types::TypingContext.type_variable_for(:test, '@a', [Object])
7
+ type_var.compatible?(type)
8
+ expect(type_var.constraints).to eq([[type_var, :lt, type]])
9
+
10
+ type2 = tyobject(String)
11
+ type_var.compatible?(type2, :gt)
12
+ expect(type_var.constraints).to eq([[type_var, :lt, type], [type_var, :gt, type2]])
13
+ end
14
+ end
@@ -0,0 +1,328 @@
1
+ require_relative '../../spec_helper'
2
+
3
+ describe TypedRb::Types::Polymorphism::Unification do
4
+ it 'should be able to unify a simple constraint' do
5
+ type_var = TypedRb::Types::TypingContext.type_variable_for(:test, '@varx', [Object])
6
+ integer = tyobject(Integer)
7
+ type_var.compatible?(integer, :lt)
8
+
9
+ unification = described_class.new(type_var.constraints)
10
+ unification.run
11
+ expect(type_var.bound).to eq(integer)
12
+ expect(type_var.upper_bound).to eq(integer)
13
+ expect(type_var.lower_bound).to be_nil
14
+ end
15
+
16
+ context 'with variable instance assignations' do
17
+ it 'should be able to unify compatible types' do
18
+ type_var = TypedRb::Types::TypingContext.type_variable_for(:test, '@b', [Object])
19
+ integer = tyobject(Integer)
20
+ numeric = tyobject(Numeric)
21
+ # @a = Integer
22
+ type_var.compatible?(integer, :gt)
23
+ # @a = Numeric
24
+ type_var.compatible?(numeric, :gt)
25
+
26
+ unification = described_class.new(type_var.constraints)
27
+ unification.run.bindings
28
+
29
+ # @a = max(Integer, Numeric)
30
+ expect(type_var.bound).to eq(numeric)
31
+ expect(type_var.lower_bound).to eq(numeric)
32
+ expect(type_var.upper_bound).to be_nil
33
+ end
34
+
35
+ it 'should find the join of the types' do
36
+ type_var = TypedRb::Types::TypingContext.type_variable_for(:test, '@c', [Object])
37
+ integer = tyobject(Integer)
38
+ string = tyobject(String)
39
+ # @a = Integer
40
+ type_var.compatible?(integer, :gt)
41
+ # @a = String
42
+ type_var.compatible?(string, :gt)
43
+
44
+ unification = described_class.new(type_var.constraints)
45
+ unification.run.bindings
46
+
47
+ # @a = max(Integer, String) => join(Integer, Sring) => Object[Comparable,Kernel]
48
+ expect(type_var.bound.with_ruby_type).to be_falsey
49
+ expect(type_var.bound.ruby_type).to eq(Object)
50
+ expect(type_var.bound.modules).to include(Comparable)
51
+ expect(type_var.bound.modules).to include(Kernel)
52
+ expect(type_var.lower_bound.with_ruby_type).to be_falsey
53
+ expect(type_var.lower_bound.ruby_type).to eq(Object)
54
+ expect(type_var.lower_bound.modules).to include(Comparable)
55
+ expect(type_var.lower_bound.modules).to include(Kernel)
56
+ expect(type_var.upper_bound).to be_nil
57
+ end
58
+
59
+ it 'should be possible to unify multiple assignations' do
60
+ type_var = TypedRb::Types::TypingContext.type_variable_for(:test, '@d', [Object])
61
+ integer = tyobject(Integer)
62
+ string = tyobject(String)
63
+ type_var2 = TypedRb::Types::TypingContext.type_variable_for(:test, '@e', [Object])
64
+ type_var3 = TypedRb::Types::TypingContext.type_variable_for(:test, '@f', [Object])
65
+
66
+ # @a = Integer
67
+ type_var.compatible?(integer, :gt)
68
+ # @b = @a
69
+ type_var2.compatible?(type_var, :gt)
70
+ # @c = String
71
+ type_var3.compatible?(string, :gt)
72
+
73
+ unification = described_class.new(type_var.constraints + type_var2.constraints + type_var3.constraints)
74
+ unification.run.bindings
75
+
76
+ # @a = @b = Integer
77
+ # @c = String
78
+ expect(type_var.bound).to eq(integer)
79
+ expect(type_var2.bound).to eq(integer)
80
+ expect(type_var3.bound).to eq(string)
81
+ expect(type_var.lower_bound).to eq(integer)
82
+ expect(type_var2.lower_bound).to eq(integer)
83
+ expect(type_var3.lower_bound).to eq(string)
84
+ expect(type_var.upper_bound).to be_nil
85
+ expect(type_var2.upper_bound).to be_nil
86
+ expect(type_var3.upper_bound).to be_nil
87
+ end
88
+
89
+ it 'should be possible to unify multiple assignations' do
90
+ type_var = TypedRb::Types::TypingContext.type_variable_for(:test, '@g', [Object])
91
+ type_var2 = TypedRb::Types::TypingContext.type_variable_for(:test, '@h', [Object])
92
+ integer = tyobject(Integer)
93
+ numeric = tyobject(Numeric)
94
+
95
+
96
+ # @a = Numeric
97
+ type_var.compatible?(numeric, :gt)
98
+ # @b = @a
99
+ type_var2.compatible?(type_var, :gt)
100
+ # @b = Integer
101
+ type_var2.compatible?(integer, :gt)
102
+
103
+ unification = described_class.new(type_var.constraints + type_var2.constraints)
104
+ unification.run.bindings
105
+
106
+ # @a = @b = Numeric
107
+ expect(type_var.bound).to eq(numeric)
108
+ expect(type_var2.bound).to eq(numeric)
109
+ expect(type_var.lower_bound).to eq(numeric)
110
+ expect(type_var2.lower_bound).to eq(numeric)
111
+ expect(type_var.upper_bound).to be_nil
112
+ expect(type_var2.upper_bound).to be_nil
113
+ end
114
+
115
+ it 'should be possible to unify multiple assignations' do
116
+ type_var = TypedRb::Types::TypingContext.type_variable_for(:test, '@i', [Object])
117
+ type_var2 = TypedRb::Types::TypingContext.type_variable_for(:test, '@j', [Object])
118
+ integer = tyobject(Integer)
119
+ numeric = tyobject(Numeric)
120
+
121
+
122
+ # @a = Integer
123
+ type_var.compatible?(integer, :gt)
124
+ # @b = @a
125
+ type_var2.compatible?(type_var, :gt)
126
+ # @b = Numeric
127
+ type_var2.compatible?(numeric, :gt)
128
+
129
+ unification = described_class.new(type_var.constraints + type_var2.constraints)
130
+ unification.run.bindings
131
+
132
+ # @a = @b = Numeric
133
+ expect(type_var.bound).to eq(numeric)
134
+ expect(type_var2.bound).to eq(numeric)
135
+ expect(type_var.lower_bound).to eq(numeric)
136
+ expect(type_var2.lower_bound).to eq(numeric)
137
+ expect(type_var.upper_bound).to be_nil
138
+ expect(type_var2.upper_bound).to be_nil
139
+ end
140
+ end
141
+
142
+ context 'with variable instance application' do
143
+ it 'should be able to unify same type' do
144
+ type_var = TypedRb::Types::TypingContext.type_variable_for(:test, '@k', [Object])
145
+ integer = tyobject(Integer)
146
+ # @a = Integer
147
+ type_var.compatible?(integer, :gt)
148
+ # f(a::Integer = @a)
149
+ type_var.compatible?(integer, :lt)
150
+
151
+ unification = described_class.new(type_var.constraints)
152
+ unification.run.bindings
153
+
154
+ # @a = min(Integer, Integer) if Integer <= Integer
155
+ expect(type_var.bound).to eq(integer)
156
+ expect(type_var.lower_bound).to eq(integer)
157
+ expect(type_var.upper_bound).to eq(integer)
158
+ end
159
+
160
+ it 'should be able to unify matching types' do
161
+ type_var = TypedRb::Types::TypingContext.type_variable_for(:test, '@l', [Object])
162
+ integer = tyobject(Integer)
163
+ numeric = tyobject(Numeric)
164
+ # @a = Integer
165
+ type_var.compatible?(integer, :gt)
166
+ # f(a::Numeric = @a)
167
+ type_var.compatible?(numeric, :lt)
168
+
169
+ unification = described_class.new(type_var.constraints)
170
+ unification.run.bindings
171
+
172
+ # @a = min(Integer, Numeric) if Integer <= Numeric
173
+ expect(type_var.bound).to eq(integer)
174
+ expect(type_var.lower_bound).to eq(integer)
175
+ expect(type_var.upper_bound).to eq(numeric)
176
+ end
177
+
178
+ it 'should raise a unification exception for incompatible types' do
179
+ type_var = TypedRb::Types::TypingContext.type_variable_for(:test, '@m', [Object])
180
+ string = tyobject(String)
181
+ numeric = tyobject(Numeric)
182
+ # @a = String
183
+ type_var.compatible?(string, :gt)
184
+ # f(a::Numeric = @a)
185
+ type_var.compatible?(numeric, :lt)
186
+
187
+ unification = described_class.new(type_var.constraints)
188
+ expect do
189
+ # @a = min(String, Numeric) if String < Numeric => FAIL
190
+ unification.run.bindings
191
+ end.to raise_error TypedRb::Types::UncomparableTypes
192
+ end
193
+ end
194
+
195
+ context 'with send constraints' do
196
+
197
+ it 'should unify method invocations and detect errors' do
198
+ code = <<__CODE
199
+ class ClassV1
200
+ ts '#initialize / -> unit'
201
+
202
+ ts '#go! / String -> ClassP1'
203
+ def go!(s); end
204
+ end
205
+
206
+ class ClassP1
207
+ ts '#initialize / String -> unit'
208
+ def initialize(s); end
209
+
210
+ ts '#reached? / -> Boolean'
211
+ def reached?; end
212
+ end
213
+
214
+ class A1
215
+ ts '#initialize / ClassV1 -> unit'
216
+ def initialize(cv); end
217
+
218
+ ts '#do! / Integer -> Boolean'
219
+ def do!(i); end
220
+ end
221
+ __CODE
222
+
223
+ eval_with_ts(code)
224
+ string = tyobject(String)
225
+ integer = tyobject(Integer)
226
+ classv = tyobject(ClassV1)
227
+
228
+ # @iv1 = String
229
+ iv1 = TypedRb::Types::TypingContext.type_variable_for(:test, '@iv1', [Object])
230
+ iv1.compatible?(string, :gt)
231
+ # @iv2 = ClassV
232
+ iv2 = TypedRb::Types::TypingContext.type_variable_for(:test, '@iv2', [Object])
233
+ iv2.compatible?(classv, :gt)
234
+ # @iv2 :: go![Integer -> rt1]
235
+ rt1 = TypedRb::Types::TypingContext.type_variable_for(:test, 'rt1', [Object])
236
+ iv2.add_constraint(:send,
237
+ args: [integer],
238
+ return: rt1,
239
+ message: :go!)
240
+ # rt1 :: reached?[unit -> rt2]
241
+ rt2 = TypedRb::Types::TypingContext.type_variable_for(:test, 'rt2', [Object])
242
+ rt1.add_constraint(:send,
243
+ args: [],
244
+ return: rt2,
245
+ message: :reached!)
246
+
247
+ # rt2 = return Boolean
248
+ rt2.compatible?(tyboolean, :lt)
249
+
250
+
251
+ constraints = iv1.constraints + iv2.constraints + rt1.constraints + rt2.constraints
252
+ unification = described_class.new(constraints)
253
+ expect do
254
+ # iv2 => ClassV, E? ClassV::go! [Integer -> ?] => ERROR
255
+ unification.run.bindings
256
+ end.to raise_error TypedRb::Types::UncomparableTypes
257
+ end
258
+
259
+ it 'should unify method invocations and accept valid inputs' do
260
+ code = <<__CODE
261
+ class ClassV
262
+ ts '#initialize / -> unit'
263
+
264
+ ts '#go! / Integer -> ClassP'
265
+ def go!(s); end
266
+ end
267
+
268
+ class ClassP
269
+ ts '#initialize / String -> unit'
270
+ def initialize(s); end
271
+
272
+ ts '#reached? / -> Boolean'
273
+ def reached?; end
274
+ end
275
+
276
+ class A
277
+ ts '#initialize / ClassV -> unit'
278
+ def initialize(cv)
279
+ # @a = cv
280
+ end
281
+
282
+ ts '#do! / Integer -> Boolean'
283
+ def do!(i)
284
+ # @a.go!(n).reached?
285
+ end
286
+ end
287
+ __CODE
288
+
289
+ eval_with_ts(code)
290
+ string = tyobject(String)
291
+ integer = tyobject(Integer)
292
+ classv = tyobject(ClassV)
293
+ classp = tyobject(ClassP)
294
+
295
+ # @iv1 = String
296
+ iv1 = TypedRb::Types::TypingContext.type_variable_for(:test, '@iv1b', [Object])
297
+ iv1.compatible?(string, :gt)
298
+ # @iv2 = ClassV
299
+ iv2 = TypedRb::Types::TypingContext.type_variable_for(:test, '@iv2b', [Object])
300
+ iv2.compatible?(classv, :gt)
301
+ # @iv2 :: go![Integer -> rt1]
302
+ rt1 = TypedRb::Types::TypingContext.type_variable_for(:test, 'rt1_go!', [Object])
303
+ iv2.add_constraint(:send,
304
+ args: [integer],
305
+ return: rt1,
306
+ message: :go!)
307
+ # rt1 :: reached?[unit -> rt2]
308
+ rt2 = TypedRb::Types::TypingContext.type_variable_for(:test, 'rt2_reached', [Object])
309
+ rt1.add_constraint(:send,
310
+ args: [],
311
+ return: rt2,
312
+ message: :reached?)
313
+
314
+ # rt2 = return Boolean
315
+ rt2.compatible?(tyboolean, :lt)
316
+
317
+
318
+ constraints = iv1.constraints + iv2.constraints + rt1.constraints + rt2.constraints
319
+
320
+ described_class.new(constraints).run.bindings
321
+
322
+ expect(iv1.bound).to eq(string)
323
+ expect(iv2.bound).to eq(classv)
324
+ expect(rt1.bound).to eq(classp)
325
+ expect(rt2.bound).to eq(tyboolean)
326
+ end
327
+ end
328
+ end