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.
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