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,34 @@
1
+ module TypedRb
2
+ module Runtime
3
+ class TypeSignatureProcessor
4
+ PARAMETRIC_TYPE_PREFIX = /\s*(module|class|type)\s*/
5
+ class << self
6
+ def type_signature?(signature)
7
+ signature.index(PARAMETRIC_TYPE_PREFIX) == 0
8
+ end
9
+
10
+ def process(signature)
11
+ type_signature = signature.split(PARAMETRIC_TYPE_PREFIX).last
12
+
13
+ type_signature, super_type_signature = parse_generic_supertype(type_signature)
14
+
15
+ generic_type = ::TypedRb::TypeSignature::Parser.parse(type_signature)
16
+ if super_type_signature
17
+ generic_super_type = ::TypedRb::TypeSignature::Parser.parse(super_type_signature)
18
+ end
19
+
20
+ BasicObject::TypeRegistry.register_generic_type_information(generic_type, generic_super_type)
21
+ end
22
+
23
+ private
24
+
25
+ # Generic types can have an explicit generic supertype.
26
+ # e.g:
27
+ # ts 'type Pair[S][T] super Array[Object]'
28
+ def parse_generic_supertype(type_signature)
29
+ type_signature.split(/\s*super\s*/)
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,33 @@
1
+ class BasicObject
2
+ def ts(signature)
3
+ # TODO: Add information about the script and line for the invocation here
4
+ # caller_infos = caller.first.split(":")
5
+ # puts "#{caller_infos[0]} : #{caller_infos[1]} : #{str}"
6
+ ::TypedRb.log(binding, :debug, "Parsing signature: #{signature}")
7
+ if $TYPECHECK
8
+ if ::TypedRb::Runtime::TypeSignatureProcessor.type_signature?(signature)
9
+ ::TypedRb::Runtime::TypeSignatureProcessor.process(signature)
10
+ else
11
+ ::TypedRb::Runtime::MethodSignatureProcessor.process(signature, self)
12
+ end
13
+ end
14
+ # rescue ::StandardError => ex
15
+ # puts ex.message
16
+ # puts ex.backtrace.join("\n")
17
+ # raise ::StandardError, "Error parsing type signature '#{signature}': #{ex.message}"
18
+ end
19
+
20
+ def ts_ignore; end
21
+
22
+ def cast(from, _to)
23
+ # noop
24
+ from
25
+ end
26
+ end
27
+
28
+ class Class
29
+ ts '.call / Class... -> unit'
30
+ def call(*_types)
31
+ self
32
+ end
33
+ end
@@ -0,0 +1,240 @@
1
+ module TypedRb
2
+ module TypeSignature
3
+ class ParsingError < StandardError
4
+ def initialize(expr, reason)
5
+ super "Error parsing type signature '#{expr}': #{reason}"
6
+ end
7
+ end
8
+
9
+ module TokenProcessor
10
+ def group_tokens(tokens)
11
+ next_group = []
12
+ groups = [next_group]
13
+ tokens.each do |token|
14
+ if token == :<
15
+ next_group = []
16
+ groups << next_group
17
+ else
18
+ next_group << token
19
+ end
20
+ end
21
+ groups
22
+ end
23
+
24
+ def transform_function_tokens(tokens)
25
+ group_tokens(tokens).map do |token_group|
26
+ if token_group.is_a?(Array)
27
+ transform_nested_function(token_group)
28
+ elsif token_group.is_a?(String)
29
+ token_group
30
+ end
31
+ end.compact
32
+ end
33
+
34
+ def variable_group?(token_group)
35
+ token_group.drop(1).all? do |token|
36
+ token.is_a?(Hash) &&
37
+ (token[:kind] == :type_var ||
38
+ token[:kind] == :generic_type)
39
+ end
40
+ end
41
+
42
+ def transform_nested_function(token_group)
43
+ if token_group.size > 1 &&
44
+ token_group.last.is_a?(Hash) &&
45
+ token_group.last[:kind] == :rest
46
+ remaining_tokens = transform_nested_function(token_group[0...-1] + token_group.last[:parameters])
47
+ {:kind => :rest,
48
+ :type => 'Array',
49
+ :parameters => [remaining_tokens]}
50
+ elsif token_group.size > 1 &&
51
+ variable_group?(token_group) &&
52
+ token_group[0].is_a?(String)
53
+ { :type => token_group.first,
54
+ :parameters => token_group.drop(1),
55
+ :kind => :generic_type }
56
+ elsif token_group.size < 2
57
+ token_group.first
58
+ else
59
+ token_group
60
+ end
61
+ end
62
+ end
63
+
64
+ module TypeProcessor
65
+ def parse_start_of_type
66
+ new_type = parse_new_type
67
+ @current_function << new_type unless @current_type.empty?
68
+ @stack << @current_function
69
+ @current_type = []
70
+ @current_function = []
71
+ end
72
+
73
+ def parse_end_of_function
74
+ new_type = parse_new_type
75
+ @current_function << new_type unless @current_type.empty?
76
+ parent_function = @stack.pop
77
+ next_function_elem = transform_function_tokens(@current_function)
78
+ parent_function << next_function_elem
79
+ parse_block_arg(parent_function) if block_arg?(parent_function)
80
+ @current_function = parent_function
81
+ @current_type = []
82
+ end
83
+
84
+ def block_arg?(function_tokens)
85
+ function_tokens[-2] == '&'
86
+ end
87
+
88
+ def parse_block_arg(function_tokens)
89
+ block = { :block => function_tokens.pop,
90
+ :kind => :block_arg }
91
+ function_tokens.pop
92
+ function_tokens << block
93
+ end
94
+
95
+ def parse_binding
96
+ new_type = parse_new_type
97
+ @current_function << new_type unless @current_type.empty?
98
+ @current_type = []
99
+ end
100
+
101
+ def parse_end_of_binding
102
+ bound = parse_variable_binding
103
+ # method variables
104
+ if bound[:kind] == :type_var && method_info[bound[:type]]
105
+ bound = method_info[bound[:type]].dup
106
+ bound[:sub_kind] = :method_type_var
107
+ end
108
+ @binding = nil
109
+ parent_function = @stack.pop
110
+ parent_function << bound
111
+ @current_function = parent_function
112
+ @current_type = []
113
+ end
114
+
115
+ def parse_variable_binding
116
+ new_type = parse_new_type
117
+ @current_function << new_type unless @current_type.empty?
118
+ if @current_function.size == 1
119
+ { :type => @current_function.first,
120
+ :kind => :type_var }
121
+ else
122
+ if @binding.nil?
123
+ # This is the case for nested generic types
124
+ { :type => @current_function.first,
125
+ :parameters => @current_function.drop(1),
126
+ :kind => :generic_type }
127
+ else
128
+ { :type => @current_function.first,
129
+ :bound => @current_function.last,
130
+ :binding => @binding,
131
+ :kind => :type_var }
132
+ end
133
+ end
134
+ end
135
+
136
+ def parse_next_elem
137
+ return parse_binding if @in_binding
138
+
139
+ new_type = parse_new_type
140
+ @current_function << new_type unless @current_type.empty?
141
+ @current_function << :<
142
+ @current_type = []
143
+ end
144
+
145
+ def parse_new_type
146
+ new_type = @current_type.join
147
+ new_type = :unit if new_type == 'unit'
148
+ if new_type.to_s.end_with?('...')
149
+ new_type = new_type.split('...').first
150
+ new_type = @current_function.pop if new_type.nil?
151
+ new_type = { :type => 'Array',
152
+ :kind => :rest,
153
+ :parameters => [new_type] }
154
+ end
155
+ new_type
156
+ end
157
+ end
158
+
159
+ class Parser
160
+ include TokenProcessor
161
+ include TypeProcessor
162
+
163
+ def self.parse(expr, method_info = {})
164
+ (@parser || Parser.new(method_info)).parse(expr)
165
+ end
166
+
167
+ attr_reader :method_info
168
+
169
+ def initialize(method_info = {})
170
+ @method_info = method_info
171
+ @current_type = []
172
+ @current_function = []
173
+ @stack = []
174
+ @in_binding = false
175
+ end
176
+
177
+ def parse(expr)
178
+ @input_expression = expr
179
+ expr = sanitize_input(expr)
180
+ expr.each_char { |elem| parse_next_char(elem) }
181
+ build_final_signature
182
+ rescue TypedRb::TypeSignature::ParsingError => e
183
+ raise e
184
+ rescue StandardError => e
185
+ raise TypedRb::TypeSignature::ParsingError.new(expr, e.message)
186
+ end
187
+
188
+ private
189
+
190
+ def sanitize_input(expr)
191
+ expr.gsub(/\s+/, '').gsub('->', '/')
192
+ end
193
+
194
+ PARSERS = {
195
+ '(' => ->(parser) { parser.parse_start_of_type },
196
+ '[' => ->(parser) { parser.parse_start_of_type },
197
+ ')' => ->(parser) { parser.parse_end_of_function },
198
+ '<' => ->(parser) { parser.parse_binding },
199
+ '>' => ->(parser) { parser.parse_binding },
200
+ ']' => ->(parser) { parser.parse_end_of_binding },
201
+ '/' => ->(parser) { parser.parse_next_elem }
202
+ }
203
+
204
+ def parse_next_char(elem)
205
+ setup_binding_context(elem)
206
+ if PARSERS[elem]
207
+ PARSERS[elem][self]
208
+ else
209
+ @current_type << elem
210
+ end
211
+ end
212
+
213
+ def setup_binding_context(elem)
214
+ @in_binding = true if elem == '['
215
+ @in_binding = false if elem == ']'
216
+ @binding = elem if elem == '<' || elem == '>'
217
+ end
218
+
219
+ def build_final_signature
220
+ fail ParsingError.new(@input_expression, 'Unbalanced parentheses.') unless @stack.empty?
221
+ new_type = parse_new_type
222
+
223
+ @current_function << new_type unless @current_type.empty?
224
+ @current_type = []
225
+ final_function = transform_function_tokens(@current_function)
226
+
227
+ # Distinguis between function without arguments:
228
+ # -> unit => [:<, 'unit']
229
+ # and generic type without function (e.g. in the
230
+ # type parameter of a class Array.('Array[Integer]'))
231
+ # Array[Integer] => ['Array', {:type ... }]
232
+ if @current_function.at(0) != :< && final_function.size == 1
233
+ final_function.last
234
+ else
235
+ final_function
236
+ end
237
+ end
238
+ end
239
+ end
240
+ end
@@ -0,0 +1,13 @@
1
+ require_relative './type_variable'
2
+ module TypedRb
3
+ module Types
4
+ module Polymorphism
5
+ class ExistentialTypeVariable < TypeVariable
6
+ attr_accessor :module_type
7
+ def find_var_type(var)
8
+ module_type.find_var_type(var)
9
+ end
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,134 @@
1
+ module TypedRb
2
+ module Types
3
+ module Polymorphism
4
+ module GenericComparisons
5
+ def ==(other)
6
+ return false if !other.is_a?(TyObject) || !other.generic?
7
+ return false if other.ruby_type != ruby_type
8
+ to_s == other.to_s
9
+ end
10
+
11
+ def !=(other)
12
+ ! (self == other)
13
+ end
14
+
15
+ def <(other)
16
+ self.compatible?(other, :lt)
17
+ end
18
+
19
+ def >(other)
20
+ self.compatible?(other, :gt)
21
+ end
22
+
23
+ def <=(other)
24
+ self == other || self.compatible?(other, :lt)
25
+ end
26
+
27
+ def >=(other)
28
+ self == other || self.compatible?(other, :gt)
29
+ end
30
+
31
+ def compatible?(other_type, relation = :lt)
32
+ if other_type.is_a?(TyDynamic) || other_type.is_a?(TyError)
33
+ true
34
+ elsif other_type.is_a?(TyGenericObject) || other_type.is_a?(TyGenericSingletonObject)
35
+ if check_generic_type_relation(other_type.ruby_type, relation)
36
+ type_vars.each_with_index do |type_var, i|
37
+ other_type_var = other_type.type_vars[i]
38
+ compatible = if incompatible_free_type_vars?(type_var, other_type_var)
39
+ false
40
+ elsif compatible_free_type_vars?(type_var, other_type_var)
41
+ true
42
+ else
43
+ check_type_var_inclusion(type_var, other_type_var, relation)
44
+ end
45
+ return false unless compatible
46
+ end
47
+ true
48
+ else
49
+ false
50
+ end
51
+ else
52
+ check_generic_type_relation(other_type.ruby_type, relation)
53
+ end
54
+ rescue ArgumentError
55
+ raise TypedRb::Types::UncomparableTypes.new(self, other_type)
56
+ end
57
+
58
+ def incompatible_free_type_vars?(type_var, other_type_var)
59
+ left_var = type_var.bound || type_var.lower_bound || type_var.upper_bound || type_var
60
+ right_var = other_type_var.bound || other_type_var.lower_bound || other_type_var.upper_bound || other_type_var
61
+
62
+ left_var.is_a?(Polymorphism::TypeVariable) &&
63
+ right_var.is_a?(Polymorphism::TypeVariable) &&
64
+ left_var.variable != right_var.variable &&
65
+ (TypingContext.bound_generic_type_var?(left_var) &&
66
+ TypingContext.bound_generic_type_var?(right_var))
67
+ end
68
+
69
+ def compatible_free_type_vars?(type_var, other_type_var)
70
+ left_var = type_var.bound || type_var.lower_bound || type_var.upper_bound || type_var
71
+ right_var = other_type_var.bound || other_type_var.lower_bound || other_type_var.upper_bound || other_type_var
72
+
73
+ left_var.is_a?(Polymorphism::TypeVariable) &&
74
+ right_var.is_a?(Polymorphism::TypeVariable) &&
75
+ left_var.variable == right_var.variable &&
76
+ (TypingContext.bound_generic_type_var?(left_var) &&
77
+ TypingContext.bound_generic_type_var?(right_var))
78
+ end
79
+
80
+ def check_generic_type_relation(other_ruby_type, relation)
81
+ if relation == :gt
82
+ TyObject.new(ruby_type) >= TyObject.new(other_ruby_type)
83
+ else
84
+ TyObject.new(ruby_type) <= TyObject.new(other_ruby_type)
85
+ end
86
+ end
87
+
88
+ def check_type_var_inclusion(type_var, other_type_var, relation)
89
+ if (!type_var.wildcard? && !type_var.fully_bound?) ||
90
+ (!other_type_var.wildcard? && !other_type_var.fully_bound?)
91
+ add_type_var_constraint(type_var, other_type_var, relation)
92
+ else
93
+ superset, subset = relation == :lt ? [other_type_var, type_var] : [type_var, other_type_var]
94
+
95
+ super_min, super_max, sub_min, sub_max = [superset.lower_bound, superset.upper_bound, subset.lower_bound, subset.upper_bound]. map do |bound|
96
+ if bound.nil?
97
+ nil
98
+ else
99
+ bound
100
+ end
101
+ end
102
+ super_max ||= TyObject.new(Object)
103
+ sub_max ||= TyObject.new(Object)
104
+
105
+ check_inferior_or_equal_binding(super_min, sub_min) &&
106
+ check_inferior_or_equal_binding(sub_max, super_max)
107
+ end
108
+ end
109
+
110
+ # nil < Type_i < Object
111
+ def check_inferior_or_equal_binding(binding_a, binding_b)
112
+ if binding_a.nil? && binding_b.nil?
113
+ true
114
+ elsif binding_a.nil? && !binding_b.nil?
115
+ true
116
+ elsif !binding_a.nil? && binding_b.nil?
117
+ false
118
+ else
119
+ binding_a <= binding_b
120
+ end
121
+ end
122
+
123
+ def add_type_var_constraint(type_var, other_type_var, relation)
124
+ if type_var.bound
125
+ type_var, other_type_var = other_type_var, type_var
126
+ relation = relation == :lt ? :gt : :lt
127
+ end
128
+ type_var.add_constraint(relation, other_type_var.bound)
129
+ true
130
+ end
131
+ end
132
+ end
133
+ end
134
+ end
@@ -0,0 +1,24 @@
1
+ module TypedRb
2
+ module Types
3
+ module Polymorphism
4
+ module GenericVariables
5
+ def type_vars(options = { recursive: true })
6
+ return @type_vars unless options[:recursive]
7
+ return @type_vars if self.class == TypedRb::Types::TyGenericObject
8
+ @type_vars.map do |type_var|
9
+ if type_var.is_a?(Polymorphism::TypeVariable) && type_var.bound_to_generic?
10
+ type_var.bound.type_vars
11
+ elsif type_var.is_a?(Polymorphism::TypeVariable)
12
+ type_var
13
+ else
14
+ type_var.type_vars
15
+ end
16
+ end.flatten
17
+ # .each_with_object({}) do |type_var, acc|
18
+ # acc[type_var.variable] = type_var
19
+ #end.values
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,138 @@
1
+ module TypedRb
2
+ module Types
3
+ module Polymorphism
4
+ class TypeVariable
5
+ attr_accessor :bound, :variable, :upper_bound, :lower_bound, :name, :node
6
+
7
+ def initialize(var_name, options = {})
8
+ gen_name = options[:gen_name].nil? ? true : options[:gen_name]
9
+ @upper_bound = options[:upper_bound]
10
+ @lower_bound = options[:lower_bound]
11
+ @node = options[:node]
12
+ @wildcard = var_name.to_s.end_with?('?')
13
+ var_name.sub!(/:?\?/, '') if @wildcard
14
+ @name = var_name
15
+ @variable = gen_name ? Model::GenSym.next("TV_#{var_name}") : var_name
16
+ @bound = options[:bound]
17
+ end
18
+
19
+ def stack_jump?
20
+ false
21
+ end
22
+
23
+ def either?
24
+ false
25
+ end
26
+
27
+ def add_constraint(relation, type)
28
+ if type.is_a?(TypeVariable) && type.bound
29
+ TypingContext.add_constraint(variable, relation, type.bound)
30
+ else
31
+ TypingContext.add_constraint(variable, relation, type)
32
+ end
33
+ end
34
+
35
+ def add_message_constraint(message, args)
36
+ return_type = TypingContext.type_variable_for_message(variable, message)
37
+ return_type.node = node
38
+ # add constraint for this
39
+ add_constraint(:send, args: args, return: return_type, message: message)
40
+ # return return type
41
+ return_type
42
+ end
43
+
44
+ def compatible?(type, relation = :lt)
45
+ if @bound
46
+ @bound.compatible?(type, relation)
47
+ elsif incompatible_vars?(type)
48
+ false
49
+ else
50
+ add_constraint(relation, type)
51
+ true
52
+ end
53
+ end
54
+
55
+ def constraints(register = TypingContext)
56
+ register.constraints_for(variable).map { |(t, c)| [self, t, c] }
57
+ end
58
+
59
+ def check_type(_context)
60
+ self
61
+ end
62
+
63
+ def bind(type)
64
+ @bound = type
65
+ end
66
+
67
+ def fully_bound?
68
+ !upper_bound.nil? && !lower_bound.nil?
69
+ end
70
+
71
+ def wildcard?
72
+ @wildcard
73
+ end
74
+
75
+ def to_wildcard!
76
+ @wildcard = true
77
+ end
78
+
79
+ def apply_bindings(bindings_map)
80
+ bound_var = bindings_map[variable]
81
+ if bound_var && bound.nil?
82
+ self.bound = bound_var.bound
83
+ self.upper_bound = bound_var.upper_bound
84
+ self.lower_bound = bound_var.lower_bound
85
+ self.to_wildcard! if bound_var.wildcard?
86
+ elsif bound && (bound.is_a?(TyGenericSingletonObject) || bound.is_a?(TyGenericObject))
87
+ bound.apply_bindings(bindings_map)
88
+ end
89
+ self
90
+ end
91
+
92
+ def unbind
93
+ @bound = nil
94
+ end
95
+
96
+ def clone
97
+ var = TypeVariable.new(variable,
98
+ node: node,
99
+ gen_name: false,
100
+ upper_bound: upper_bound,
101
+ lower_bound: lower_bound,
102
+ bound: bound)
103
+ var.to_wildcard! if wildcard?
104
+ var
105
+ end
106
+
107
+ def to_s
108
+ wildcard_part = wildcard? ? '*' : ''
109
+ bound_part = if @bound
110
+ @bound
111
+ else
112
+ "[#{lower_bound || '?'},#{upper_bound || '?'}]"
113
+ end
114
+ "#{@variable}#{wildcard_part}::#{bound_part}"
115
+ end
116
+
117
+ def bound_to_generic?
118
+ bound && bound.respond_to?(:generic?) && bound.generic?
119
+ end
120
+
121
+ private
122
+
123
+ def incompatible_vars?(type)
124
+ if type.is_a?(TypeVariable)
125
+ left_var = bound || self
126
+ right_var = type.bound || type
127
+
128
+ left_var.is_a?(TypeVariable) &&
129
+ right_var.is_a?(TypeVariable) &&
130
+ left_var.variable != right_var.variable &&
131
+ (TypingContext.bound_generic_type_var?(left_var) &&
132
+ TypingContext.bound_generic_type_var?(right_var))
133
+ end
134
+ end
135
+ end
136
+ end
137
+ end
138
+ end