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,238 @@
1
+ require_relative 'ty_singleton_object'
2
+ require_relative 'polymorphism/generic_comparisons'
3
+ require_relative 'polymorphism/generic_variables'
4
+
5
+ module TypedRb
6
+ module Types
7
+ class TyGenericSingletonObject < TySingletonObject
8
+ include Polymorphism::GenericComparisons
9
+ include Polymorphism::GenericVariables
10
+
11
+ attr_accessor :local_typing_context, :super_type
12
+
13
+ def initialize(ruby_type, type_vars, super_type = nil, node = nil)
14
+ super(ruby_type, node)
15
+ @super_type = super_type
16
+ @type_vars = type_vars
17
+ @application_count = 0
18
+ end
19
+
20
+ def materialize_with_type_vars(type_vars, bound_type)
21
+ TypedRb.log binding, :debug, "Materialising generic singleton object with type vars '#{self}' <= #{type_vars.map(&:to_s).join(',')} :: #{bound_type}"
22
+ bound_type_vars = self.type_vars.map do |type_var|
23
+ maybe_class_bound = type_vars.detect do |bound_type_var|
24
+ type_var.variable == bound_type_var.variable
25
+ end
26
+ if maybe_class_bound.nil?
27
+ # it has to be method generic variable
28
+ type_var
29
+ else
30
+ maybe_class_bound
31
+ end
32
+ end
33
+ materialize(bound_type_vars.map { |bound_type_var| bound_type_var.send(bound_type) })
34
+ end
35
+
36
+ def self_materialize
37
+ TypedRb.log binding, :debug, "Materialising self for generic singleton object '#{self}'"
38
+ BasicObject::TypeRegistry.find_generic_type(ruby_type).materialize(type_vars)
39
+ end
40
+
41
+ # materialize will be invoked by the logic handling invocations like:
42
+ # ts 'MyClass[X][Y]'
43
+ # class MyClass
44
+ # ...
45
+ # end
46
+ # MyClass.(TypeArg1, TypeArg2) -> make X<TypeArg1, Y<TypeArg2, X>TypeArg1, X>TypeArg2
47
+ # MyClass.(TypeArg1, TypeArg2) -> Materialize here > make X<TypeArg1, Y<TypeArg2 > Unification
48
+ def materialize(actual_arguments)
49
+ TypedRb.log binding, :debug, "Materialising generic singleton object '#{self}' with args [#{actual_arguments.map(&:to_s).join(',')}]"
50
+ # This can happen when we're dealing with a generic singleton object that has only been
51
+ # annotated but we don't have the annotated implementation. e.g. Array[T]
52
+ # We need to provide a default local_type_context based on the upper bounds provided in the
53
+ # type annotation.
54
+ compute_minimal_typing_context if @local_typing_context.nil?
55
+
56
+ applied_typing_context, substitutions = @local_typing_context.clone(:class)
57
+ fresh_vars_generic_type = clone_with_substitutions(substitutions)
58
+ TypingContext.with_context(applied_typing_context) do
59
+ # Appy constraints for application of Type args
60
+ apply_type_arguments(fresh_vars_generic_type, actual_arguments)
61
+ end
62
+ # got all the constraints here
63
+ # do something with the context -> unification? merge context?
64
+ # applied_typing_context.all_constraints.each{|(l,t,r)| puts "#{l} #{t} #{r}" }
65
+ unification = Polymorphism::Unification.new(applied_typing_context.all_constraints).run
66
+ applied_typing_context.unlink # these constraints have already been satisfied
67
+ # - Create a new ty_generic_object for the unified types
68
+ # - Apply the unified types to all the methods in the class/instance
69
+ # - this can be dynamically done with the right implementation of find_function_type
70
+ # - Make the class available for the type checking system, so it can be found when
71
+ # - this can be done, just returning the new ty_singleton_object with the unified types
72
+ # - messages will be redirected to that instance and find_function_type/ find_var_type / as_object
73
+ # will handle the mesage
74
+ # - looking for messages at the instance level
75
+ # - this can be accomplished with the overloading version of as_object_type, that will return
76
+ # an instance of a new class ty_generic_object with overloaded versions of find_function_type /find_var_type
77
+ ########################
78
+ fresh_vars_generic_type.apply_bindings(unification.bindings_map)
79
+ end
80
+
81
+ # TODO: We do need this for cases like Array.(Int).class_method
82
+
83
+ # def find_function_type(message)
84
+ # function_type = BasicObject::TypeRegistry.find(:class, ruby_type, message)
85
+ # replace_bound_type_vars(function_type, type_vars)
86
+ # end
87
+
88
+ # def find_function_type(message)
89
+ # BasicObject::TypeRegistry.find(:class, ruby_type, message)
90
+ # end
91
+ #
92
+ # def find_var_type(var)
93
+ # var_type = BasicObject::TypeRegistry.find(:class_variable, ruby_type, var)
94
+ # if var_type
95
+ # var_type
96
+ # else
97
+ # Types::TypingContext.type_variable_for(:class_variable, var, hierarchy)
98
+ # end
99
+ # end
100
+
101
+ def as_object_type
102
+ # this should only be used to check the body type of this
103
+ # class. The variables are going to be unbound.
104
+ # This is also used in instantiation of the generic object.
105
+ TyGenericObject.new(ruby_type, @type_vars)
106
+ end
107
+
108
+ def compute_minimal_typing_context
109
+ Model::TmClass.with_fresh_bindings(self, nil, node)
110
+ end
111
+
112
+ def generic?
113
+ true
114
+ end
115
+
116
+ def apply_bindings(bindings_map)
117
+ type_vars(recursive: false).each_with_index do |var, _i|
118
+ if var.is_a?(Polymorphism::TypeVariable) && var.bound_to_generic?
119
+ var.bind(var.bound.apply_bindings(bindings_map))
120
+ elsif var.is_a?(Polymorphism::TypeVariable)
121
+ var.apply_bindings(bindings_map)
122
+ elsif var.is_a?(TyGenericSingletonObject) || var.is_a?(TyGenericObject)
123
+ var.apply_bindings(bindings_map)
124
+ end
125
+ end
126
+ self
127
+ end
128
+
129
+ def clone
130
+ cloned_type_vars = type_vars.map(&:clone)
131
+ TyGenericSingletonObject.new(ruby_type, cloned_type_vars, super_type, node)
132
+ end
133
+
134
+ def to_s
135
+ base_string = super
136
+ var_types_strings = @type_vars.map do |var_type|
137
+ if !var_type.is_a?(Polymorphism::TypeVariable)
138
+ "[#{var_type}]"
139
+ elsif var_type.bound && var_type.bound.is_a?(Polymorphism::TypeVariable)
140
+ "[#{var_type.variable} <= #{var_type.bound.bound || var_type.bound.variable}]"
141
+ else
142
+ "[#{var_type.bound || var_type.variable}]"
143
+ end
144
+ end
145
+ "#{base_string}#{var_types_strings.join}"
146
+ end
147
+
148
+ def clone_with_substitutions(substitutions)
149
+ materialized_type_vars = type_vars(recursive: false).map do |type_var|
150
+ if type_var.is_a?(Polymorphism::TypeVariable) && type_var.bound_to_generic?
151
+ new_type_var = Polymorphism::TypeVariable.new(type_var.variable, node: type_var.node, gen_name: false)
152
+ new_type_var.to_wildcard! if type_var.wildcard?
153
+ bound = type_var.bound.clone_with_substitutions(substitutions)
154
+ new_type_var.bind(bound)
155
+ new_type_var.upper_bound = bound if type_var.upper_bound
156
+ new_type_var.lower_bound = bound if type_var.lower_bound
157
+ new_type_var
158
+ elsif type_var.is_a?(Polymorphism::TypeVariable)
159
+ substitutions[type_var.variable] || type_var.clone
160
+ elsif type_var.is_a?(TyGenericSingletonObject) || type_var.is_a?(TyGenericObject)
161
+ type_var.clone_with_substitutions(substitutions)
162
+ else
163
+ type_var
164
+ end
165
+ end
166
+ self.class.new(ruby_type, materialized_type_vars, super_type, node)
167
+ end
168
+
169
+ protected
170
+
171
+ def apply_type_arguments(fresh_vars_generic_type, actual_arguments)
172
+ fresh_vars_generic_type.type_vars.each_with_index do |type_var, i|
173
+ if type_var.bound.is_a?(TyGenericSingletonObject)
174
+ type_var.bind(apply_type_arguments_recursively(type_var.bound, actual_arguments))
175
+ else
176
+ apply_type_argument(actual_arguments[i], type_var)
177
+ end
178
+ end
179
+ end
180
+
181
+ def apply_type_argument(argument, type_var)
182
+ if argument.is_a?(Polymorphism::TypeVariable)
183
+ if argument.wildcard?
184
+ # Wild card type
185
+ # If the type is T =:= E < Type1 or E > Type1 only that constraint should be added
186
+ { :lt => :upper_bound, :gt => :lower_bound }.each do |relation, bound|
187
+ if argument.send(bound)
188
+ value = if argument.send(bound).is_a?(TyGenericSingletonObject)
189
+ argument.send(bound).clone # .self_materialize
190
+ else
191
+ argument.send(bound)
192
+ end
193
+ type_var.compatible?(value, relation)
194
+ end
195
+ end
196
+ type_var.to_wildcard! # WILD CARD
197
+ elsif argument.bound # var type with a particular value
198
+ argument = argument.bound
199
+ if argument.is_a?(TyGenericSingletonObject)
200
+ argument = argument.clone # .self_materialize
201
+ end
202
+ # This is only for matches T =:= Type1 -> T < Type1, T > Type1
203
+ fail Types::UncomparableTypes.new(type_var, argument) unless type_var.compatible?(argument, :lt)
204
+ fail Types::UncomparableTypes.new(type_var, argument) unless type_var.compatible?(argument, :gt)
205
+ else
206
+ # Type variable
207
+ type_var.bound = argument
208
+ type_var.lower_bound = argument
209
+ type_var.upper_bound = argument
210
+ end
211
+ else
212
+ if argument.is_a?(TyGenericSingletonObject)
213
+ argument = argument.clone # .self_materialize
214
+ end
215
+ # This is only for matches T =:= Type1 -> T < Type1, T > Type1
216
+ fail Types::UncomparableTypes.new(type_var, argument) unless type_var.compatible?(argument, :lt)
217
+ fail Types::UncomparableTypes.new(type_var, argument) unless type_var.compatible?(argument, :gt)
218
+ end
219
+ end
220
+
221
+ def apply_type_arguments_recursively(generic_type_bound, actual_arguments)
222
+ arg_names = actual_arguments_hash(actual_arguments)
223
+ recursive_actual_arguments = generic_type_bound.type_vars.map do |type_var|
224
+ arg_names[type_var.variable] || fail("Unbound type variable #{type_var.variable} for recursive generic type #{generic_type_bound}")
225
+ end
226
+ generic_type_bound.materialize(recursive_actual_arguments)
227
+ end
228
+
229
+ def actual_arguments_hash(actual_arguments)
230
+ acc = {}
231
+ type_vars.each_with_index do |type_var, i|
232
+ acc[type_var.variable] = actual_arguments[i]
233
+ end
234
+ acc
235
+ end
236
+ end
237
+ end
238
+ end
@@ -0,0 +1,256 @@
1
+ module TypedRb
2
+ module Types
3
+ class UncomparableTypes < TypeCheckError
4
+ attr_reader :from, :to
5
+ def initialize(from, to, node = nil)
6
+ nodes = [from.node, to.node].compact
7
+ if node
8
+ super("Cannot compare types #{from} <=> #{to}", node)
9
+ elsif nodes.size == 2
10
+ super("Cannot compare types #{from} <=> #{to}", nodes)
11
+ elsif nodes.size == 1
12
+ super("Cannot compare types #{from} <=> #{to}", nodes.first)
13
+ else
14
+ super("Cannot compare types #{from} <=> #{to}", nil)
15
+ end
16
+ end
17
+ end
18
+
19
+ class TyObject < Type
20
+ include Comparable
21
+
22
+ attr_reader :hierarchy, :classes, :modules, :ruby_type, :with_ruby_type
23
+
24
+ def initialize(ruby_type, node = nil, classes = [], modules = [])
25
+ super(node)
26
+ if ruby_type
27
+ @ruby_type = ruby_type
28
+ @hierarchy = ruby_type.ancestors
29
+ @classes = @hierarchy.select { |klass| klass.instance_of?(Class) }
30
+ @modules = @hierarchy.select { |klass| klass.instance_of?(Module) }
31
+ @with_ruby_type = true
32
+ else
33
+ @ruby_type = classes.first
34
+ @classes = classes
35
+ @modules = modules
36
+ @hierarchy = (modules + classes).uniq
37
+ @with_ruby_type = false
38
+ end
39
+ end
40
+
41
+ def dynamic?
42
+ false
43
+ end
44
+
45
+ def generic?
46
+ false
47
+ end
48
+
49
+ def singleton?
50
+ false
51
+ end
52
+
53
+ def either?
54
+ false
55
+ end
56
+
57
+ def check_type(_context)
58
+ self
59
+ end
60
+
61
+ def compatible?(other_type, relation = :lt)
62
+ if other_type.is_a?(TyObject)
63
+ begin
64
+ if relation == :gt
65
+ self >= other_type
66
+ elsif relation == :lt
67
+ self <= other_type
68
+ end
69
+ rescue ArgumentError
70
+ raise UncomparableTypes.new(self, other_type)
71
+ end
72
+ else
73
+ other_type.compatible?(self, relation == :lt ? :gt : :lt)
74
+ end
75
+ end
76
+
77
+ def as_object_type
78
+ self
79
+ end
80
+
81
+ # Non generic type, the function is alwasy going to be concrete
82
+ def find_function_type(message, num_args, block)
83
+ klass, function = find_function_type_in_hierarchy(:instance, message, num_args, block)
84
+ if klass != ruby_type && function.generic?
85
+ generic_type = ::BasicObject::TypeRegistry.find_generic_type(klass)
86
+ if generic_type.nil?
87
+ return klass, function # generic method in non-generic class
88
+ elsif generic_type.type_vars.size == 1
89
+ generic_type.materialize([self]).find_function_type(message, num_args, block)
90
+ else
91
+ fail "Undeclared generic type variables for #{ruby_type} super class/mix-in #{klass.class} #{klass}##{message}, please add a 'super' type annotation"
92
+ end
93
+ else
94
+ return klass, function
95
+ end
96
+ end
97
+
98
+ def find_var_type(var, _type = ruby_type)
99
+ # This is only in case the type has been explicitely declared
100
+ var_type = BasicObject::TypeRegistry.find(:instance_variable, ruby_type, var)
101
+ if var_type
102
+ var_type
103
+ else
104
+ # If no types has been declared, we'll find a var type in the registry
105
+ var_type = Types::TypingContext.type_variable_for(:instance_variable, var, hierarchy)
106
+ var_type.node = node
107
+ var_type
108
+ end
109
+ end
110
+
111
+ def find_function_type_in_hierarchy(kind, message, num_args, block)
112
+ initial_value = select_matching_function_in_class(@hierarchy.first, kind, message, num_args, block)
113
+ @hierarchy.drop(1).inject([@hierarchy.first, initial_value]) do |(klass, acc), type|
114
+ if acc.nil? || acc.is_a?(TyDynamicFunction)
115
+ maybe_function = select_matching_function_in_class(type, kind, message, num_args, block)
116
+ [type, (maybe_function || TyDynamicFunction.new(klass, message))]
117
+ else
118
+ [klass, acc]
119
+ end
120
+ end
121
+ end
122
+
123
+ def resolve_ruby_method(message)
124
+ @ruby_type.instance_method(message)
125
+ end
126
+
127
+ def to_s
128
+ if @with_ruby_type
129
+ @ruby_type.name
130
+ else
131
+ "#{@classes.first} with [#{@modules.map(&:to_s).join(',')}]"
132
+ end
133
+ end
134
+
135
+ def union(other_type, node = nil)
136
+ smaller_common_class = (classes & other_type.classes).first
137
+ TyObject.new(smaller_common_class, (node || self.node || other_type.node))
138
+ end
139
+
140
+ def <=>(other)
141
+ if other.is_a?(TyObject)
142
+ if other.with_ruby_type
143
+ if with_ruby_type
144
+ compare_ruby_ruby(other)
145
+ else
146
+ compare_with_union(other)
147
+ end
148
+ else
149
+ if with_ruby_type
150
+ compare_with_union(other)
151
+ else
152
+ compare_with_union(other)
153
+ end
154
+ end
155
+ #else
156
+ # fail UncomparableTypes.new(self, other)
157
+ end
158
+ end
159
+
160
+ def join(other)
161
+ common_classes = classes & other.classes
162
+ common_modules = modules & other.modules
163
+ if common_modules.size == 1
164
+ TyObject.new(common_modules.first, (node || other.node))
165
+ else
166
+ TyObject.new(nil, (node || other.node), common_classes, common_modules)
167
+ end
168
+ end
169
+
170
+ protected
171
+
172
+ def compare_ruby_ruby(other)
173
+ if ruby_type == NilClass && other.ruby_type == NilClass
174
+ 0
175
+ elsif ruby_type == NilClass
176
+ -1
177
+ elsif other.ruby_type == NilClass
178
+ 1
179
+ else
180
+ if other.ruby_type == ruby_type
181
+ 0
182
+ elsif other.hierarchy.include?(ruby_type)
183
+ 1
184
+ elsif hierarchy.include?(other.ruby_type)
185
+ -1
186
+ #else
187
+ # fail UncomparableTypes.new(self, other)
188
+ end
189
+ end
190
+ end
191
+
192
+ def compare_with_union(other)
193
+ all_those_modules_included = other.modules.all? { |m| hierarchy.include?(m) }
194
+ all_these_modules_included = modules.all? { |m| other.hierarchy.include?(m) }
195
+
196
+ if other.ruby_type == ruby_type && all_these_modules_included && all_these_modules_included
197
+ 0
198
+ elsif other.hierarchy.include?(ruby_type) && all_these_modules_included && !all_those_modules_included
199
+ 1
200
+ elsif hierarchy.include?(ruby_type) && all_those_modules_included && !all_these_modules_included
201
+ -1
202
+ #else
203
+ # fail UncomparableTypes.new(self, other)
204
+ end
205
+ end
206
+
207
+ def select_matching_function_in_class(klass, kind, message, num_args, block)
208
+ functions = BasicObject::TypeRegistry.find(kind, klass, message)
209
+ initial_values = functions.select { |fn| fn.arg_compatible?(num_args) }
210
+ if initial_values.count == 2 && block
211
+ initial_values.detect(&:block_type)
212
+ elsif initial_values.count == 2 && !block
213
+ initial_values.detect { |f| f.block_type.nil? }
214
+ else
215
+ initial_values.first
216
+ end
217
+ end
218
+ end
219
+
220
+ class TyInteger < TyObject
221
+ def initialize(node = nil)
222
+ super(Integer, node)
223
+ end
224
+ end
225
+
226
+ class TyFloat < TyObject
227
+ def initialize(node = nil)
228
+ super(Float, node)
229
+ end
230
+ end
231
+
232
+ class TyString < TyObject
233
+ def initialize(node = nil)
234
+ super(String, node)
235
+ end
236
+ end
237
+
238
+ class TyUnit < TyObject
239
+ def initialize(node = nil)
240
+ super(NilClass, node)
241
+ end
242
+ end
243
+
244
+ class TySymbol < TyObject
245
+ def initialize(node = nil)
246
+ super(Symbol, node)
247
+ end
248
+ end
249
+
250
+ class TyRegexp < TyObject
251
+ def initialize(node = nil)
252
+ super(Regexp, node)
253
+ end
254
+ end
255
+ end
256
+ end
@@ -0,0 +1,78 @@
1
+ module TypedRb
2
+ module Types
3
+ class TySingletonObject < TyObject
4
+ def initialize(ruby_type, node = nil)
5
+ # super(ruby_type.class)
6
+ # @ruby_type = ruby_type
7
+ super(ruby_type, node)
8
+ end
9
+
10
+ # No generic type, function will always be concrete
11
+ def find_function_type(message, num_args, block)
12
+ maybe_function = select_matching_function_in_class(ruby_type, :class, message, num_args, block)
13
+ if maybe_function && !maybe_function.dynamic?
14
+ [ruby_type, maybe_function]
15
+ else
16
+ # This object is a class, we need to look in the hierarhcy of the meta-class
17
+ find_function_type_in_metaclass_hierarchy(message, num_args, block)
18
+ end
19
+ end
20
+
21
+ def find_function_type_in_metaclass_hierarchy(message, num_args, block)
22
+ hierarchy = Class.ancestors
23
+ initial_value = select_matching_function_in_class(hierarchy.first, :instance, message, num_args, block)
24
+ hierarchy.drop(1).inject([hierarchy.first, initial_value]) do |(klass, acc), type|
25
+ if acc.nil? || acc.is_a?(TyDynamicFunction)
26
+ maybe_function = select_matching_function_in_class(type, :instance, message, num_args, block)
27
+ [type, (maybe_function || TyDynamicFunction.new(klass, message))]
28
+ else
29
+ [klass, acc]
30
+ end
31
+ end
32
+ end
33
+
34
+ def find_var_type(var)
35
+ var_type = BasicObject::TypeRegistry.find(:class_variable, ruby_type, var)
36
+ if var_type
37
+ var_type
38
+ else
39
+ var_type = Types::TypingContext.type_variable_for(:class_variable, var, hierarchy)
40
+ var_type.node = node
41
+ var_type
42
+ end
43
+ end
44
+
45
+ def compatible?(other_type, relation = :lt)
46
+ if other_type.is_a?(TySingletonObject)
47
+ if ruby_type == Class || other_type.ruby_type == Class
48
+ if relation == :gt
49
+ Class.ancestors.include(ruby_type)
50
+ elsif relation == :lt
51
+ Class.ancestors.include?(other_type.ruby_type)
52
+ end
53
+ else
54
+ super(other_type, relation)
55
+ end
56
+ else
57
+ super(other_type, relation)
58
+ end
59
+ end
60
+
61
+ def resolve_ruby_method(message)
62
+ @ruby_type.singleton_method(message)
63
+ end
64
+
65
+ def as_object_type
66
+ TyObject.new(ruby_type, node)
67
+ end
68
+
69
+ def singleton?
70
+ true
71
+ end
72
+
73
+ def to_s
74
+ @ruby_type.name
75
+ end
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,44 @@
1
+ module TypedRb
2
+ module Types
3
+ class TyStackJump < TyUnit
4
+ attr_reader :jump_kind, :wrapped_type
5
+ def initialize(jump_kind, wrapped_type, node=nil)
6
+ super(node)
7
+ @jump_kind = jump_kind
8
+ @wrapped_type = wrapped_type
9
+ end
10
+
11
+ def stack_jump?
12
+ true
13
+ end
14
+
15
+ def self.return(return_type, node = nil)
16
+ TyStackJump.new(:return, return_type, node)
17
+ end
18
+
19
+ def self.break(return_type, node = nil)
20
+ TyStackJump.new(:break, return_type, node)
21
+ end
22
+
23
+ def self.next(return_type, node = nil)
24
+ TyStackJump.new(:next, return_type, node)
25
+ end
26
+
27
+ def return?
28
+ jump_kind == :return
29
+ end
30
+
31
+ def break?
32
+ jump_kind == :break
33
+ end
34
+
35
+ def next?
36
+ jump_kind == :next
37
+ end
38
+
39
+ def to_s
40
+ "Jump[#{jump_kind}:#{wrapped_type}]"
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,38 @@
1
+ module TypedRb
2
+ module Types
3
+ class TyTopLevelObject < TyObject
4
+ def initialize
5
+ super(TOPLEVEL_BINDING.receiver.class)
6
+ end
7
+
8
+ def compatible?(_other_type)
9
+ fail StandardError, 'invoking compatible? in the top level object'
10
+ end
11
+
12
+ def as_object_type
13
+ self
14
+ end
15
+
16
+ def find_function_type(message, num_args, block)
17
+ found_type = select_matching_function_in_class(:main, :instance, message, num_args, block)
18
+ if found_type && !found_type.is_a?(TyDynamicFunction)
19
+ [:main, found_type]
20
+ else
21
+ TyObject.new(ruby_type, node).find_function_type(message, num_args, block)
22
+ end
23
+ end
24
+
25
+ def find_var_type(var)
26
+ super(var, :main)
27
+ end
28
+
29
+ def resolve_ruby_method(message)
30
+ @ruby_type.method(message)
31
+ end
32
+
33
+ def to_s
34
+ 'Object[\'main\']'
35
+ end
36
+ end
37
+ end
38
+ end