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