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.
- checksums.yaml +7 -0
- data/Rakefile +26 -0
- data/bin/typed.rb +110 -0
- data/lib/typed/language.rb +131 -0
- data/lib/typed/model/tm_abs.rb +104 -0
- data/lib/typed/model/tm_array_literal.rb +25 -0
- data/lib/typed/model/tm_boolean.rb +15 -0
- data/lib/typed/model/tm_boolean_operator.rb +34 -0
- data/lib/typed/model/tm_break.rb +24 -0
- data/lib/typed/model/tm_case_when.rb +38 -0
- data/lib/typed/model/tm_class.rb +63 -0
- data/lib/typed/model/tm_const.rb +29 -0
- data/lib/typed/model/tm_defined.rb +19 -0
- data/lib/typed/model/tm_error.rb +16 -0
- data/lib/typed/model/tm_float.rb +15 -0
- data/lib/typed/model/tm_for.rb +42 -0
- data/lib/typed/model/tm_fun.rb +165 -0
- data/lib/typed/model/tm_global_var.rb +22 -0
- data/lib/typed/model/tm_global_var_assignment.rb +20 -0
- data/lib/typed/model/tm_hash_literal.rb +32 -0
- data/lib/typed/model/tm_if_else.rb +24 -0
- data/lib/typed/model/tm_instance_var.rb +23 -0
- data/lib/typed/model/tm_instance_var_assignment.rb +32 -0
- data/lib/typed/model/tm_int.rb +15 -0
- data/lib/typed/model/tm_local_var_asgn.rb +35 -0
- data/lib/typed/model/tm_mass_asgn.rb +60 -0
- data/lib/typed/model/tm_mlhs.rb +87 -0
- data/lib/typed/model/tm_module.rb +51 -0
- data/lib/typed/model/tm_next.rb +24 -0
- data/lib/typed/model/tm_nil.rb +14 -0
- data/lib/typed/model/tm_range_literal.rb +30 -0
- data/lib/typed/model/tm_regexp.rb +27 -0
- data/lib/typed/model/tm_rescue.rb +27 -0
- data/lib/typed/model/tm_return.rb +24 -0
- data/lib/typed/model/tm_s_class.rb +30 -0
- data/lib/typed/model/tm_self.rb +22 -0
- data/lib/typed/model/tm_send.rb +300 -0
- data/lib/typed/model/tm_sequencing.rb +53 -0
- data/lib/typed/model/tm_string.rb +15 -0
- data/lib/typed/model/tm_string_interpolation.rb +21 -0
- data/lib/typed/model/tm_super.rb +27 -0
- data/lib/typed/model/tm_symbol.rb +15 -0
- data/lib/typed/model/tm_symbol_interpolation.rb +21 -0
- data/lib/typed/model/tm_try.rb +29 -0
- data/lib/typed/model/tm_var.rb +28 -0
- data/lib/typed/model/tm_while.rb +43 -0
- data/lib/typed/model.rb +48 -0
- data/lib/typed/prelude.rb +939 -0
- data/lib/typed/prelude_existential_registry.bin +0 -0
- data/lib/typed/prelude_generic_registry.bin +0 -0
- data/lib/typed/prelude_registry.bin +0 -0
- data/lib/typed/runtime/ast_parser.rb +589 -0
- data/lib/typed/runtime/method_signature_processor.rb +72 -0
- data/lib/typed/runtime/normalization/validations.rb +47 -0
- data/lib/typed/runtime/normalization.rb +196 -0
- data/lib/typed/runtime/parser_context.rb +36 -0
- data/lib/typed/runtime/type_parser.rb +215 -0
- data/lib/typed/runtime/type_registry.rb +170 -0
- data/lib/typed/runtime/type_signature_processor.rb +34 -0
- data/lib/typed/runtime.rb +33 -0
- data/lib/typed/type_signature/parser.rb +240 -0
- data/lib/typed/types/polymorphism/existential_type_variable.rb +13 -0
- data/lib/typed/types/polymorphism/generic_comparisons.rb +134 -0
- data/lib/typed/types/polymorphism/generic_variables.rb +24 -0
- data/lib/typed/types/polymorphism/type_variable.rb +138 -0
- data/lib/typed/types/polymorphism/type_variable_register.rb +298 -0
- data/lib/typed/types/polymorphism/unification.rb +579 -0
- data/lib/typed/types/ty_boolean.rb +15 -0
- data/lib/typed/types/ty_dynamic.rb +39 -0
- data/lib/typed/types/ty_either.rb +168 -0
- data/lib/typed/types/ty_error.rb +18 -0
- data/lib/typed/types/ty_existential_type.rb +22 -0
- data/lib/typed/types/ty_function.rb +144 -0
- data/lib/typed/types/ty_generic_function.rb +115 -0
- data/lib/typed/types/ty_generic_object.rb +180 -0
- data/lib/typed/types/ty_generic_singleton_object.rb +238 -0
- data/lib/typed/types/ty_object.rb +256 -0
- data/lib/typed/types/ty_singleton_object.rb +78 -0
- data/lib/typed/types/ty_stack_jump.rb +44 -0
- data/lib/typed/types/ty_top_level_object.rb +38 -0
- data/lib/typed/types.rb +60 -0
- data/lib/typed/typing_context.rb +206 -0
- data/lib/typed/version.rb +3 -0
- data/lib/typed.rb +161 -0
- data/spec/lib/ast_parser_spec.rb +101 -0
- data/spec/lib/examples/animals.rb +44 -0
- data/spec/lib/examples/counter.rb +16 -0
- data/spec/lib/examples/if.rb +31 -0
- data/spec/lib/language_spec.rb +36 -0
- data/spec/lib/model/tm_abs_spec.rb +66 -0
- data/spec/lib/model/tm_array_literal_spec.rb +36 -0
- data/spec/lib/model/tm_case_when_spec.rb +39 -0
- data/spec/lib/model/tm_class_spec.rb +67 -0
- data/spec/lib/model/tm_defined_spec.rb +10 -0
- data/spec/lib/model/tm_for_spec.rb +150 -0
- data/spec/lib/model/tm_fun_spec.rb +11 -0
- data/spec/lib/model/tm_hash_literal_spec.rb +40 -0
- data/spec/lib/model/tm_mass_asgn_spec.rb +104 -0
- data/spec/lib/model/tm_module_spec.rb +42 -0
- data/spec/lib/model/tm_regexp_spec.rb +9 -0
- data/spec/lib/model/tm_return_spec.rb +47 -0
- data/spec/lib/model/tm_s_class_spec.rb +27 -0
- data/spec/lib/model/tm_self_spec.rb +19 -0
- data/spec/lib/model/tm_string_interpolation_spec.rb +10 -0
- data/spec/lib/model/tm_symbol_interpolation_spec.rb +10 -0
- data/spec/lib/model/tm_symbol_spec.rb +9 -0
- data/spec/lib/model/tm_while_spec.rb +141 -0
- data/spec/lib/polymorphism/type_variable_spec.rb +14 -0
- data/spec/lib/polymorphism/unification_spec.rb +328 -0
- data/spec/lib/prelude/array_spec.rb +263 -0
- data/spec/lib/prelude/class_spec.rb +12 -0
- data/spec/lib/prelude/enumerable_spec.rb +278 -0
- data/spec/lib/prelude/enumerator_spec.rb +101 -0
- data/spec/lib/prelude/hash_spec.rb +361 -0
- data/spec/lib/prelude/kernel_spec.rb +23 -0
- data/spec/lib/prelude/object_spec.rb +22 -0
- data/spec/lib/prelude/pair_spec.rb +16 -0
- data/spec/lib/prelude/showable_spec.rb +31 -0
- data/spec/lib/prelude/string_spec.rb +98 -0
- data/spec/lib/runtime/normalization_spec.rb +29 -0
- data/spec/lib/runtime/validations_spec.rb +56 -0
- data/spec/lib/runtime_spec.rb +503 -0
- data/spec/lib/type_signature/parser_spec.rb +239 -0
- data/spec/lib/types/comparisons_spec.rb +35 -0
- data/spec/lib/types/polymorphism/generic_comparisons_spec.rb +492 -0
- data/spec/lib/types/polymorphism/type_variable_register_spec.rb +128 -0
- data/spec/lib/types/ty_dynamic_spec.rb +103 -0
- data/spec/lib/types/ty_either_spec.rb +288 -0
- data/spec/lib/types/ty_error_spec.rb +18 -0
- data/spec/lib/types/ty_generic_object_spec.rb +78 -0
- data/spec/lib/types/ty_generic_singleton_object_spec.rb +288 -0
- data/spec/lib/types/typing_context_spec.rb +86 -0
- data/spec/lib/types_spec.rb +174 -0
- data/spec/lib/typing/boolean_asgn_spec.rb +134 -0
- data/spec/lib/typing/break_spec.rb +79 -0
- data/spec/lib/typing/generics_spec.rb +191 -0
- data/spec/lib/typing/instance_vars_spec.rb +103 -0
- data/spec/lib/typing/next_spec.rb +29 -0
- data/spec/lib/typing/op_asgn_spec.rb +104 -0
- data/spec/lib/typing/overriden_methods_spec.rb +31 -0
- data/spec/lib/typing/subtyping_spec.rb +112 -0
- data/spec/lib/typing/tm_boolean_operator_spec.rb +100 -0
- data/spec/lib/typing/tm_boolean_spec.rb +61 -0
- data/spec/lib/typing/tm_const_spec.rb +28 -0
- data/spec/lib/typing/tm_defined_spec.rb +12 -0
- data/spec/lib/typing/tm_fun_spec.rb +347 -0
- data/spec/lib/typing/tm_global_var_spec.rb +33 -0
- data/spec/lib/typing/tm_if_else_spec.rb +104 -0
- data/spec/lib/typing/tm_ignore_spec.rb +24 -0
- data/spec/lib/typing/tm_instance_vars_spec.rb +117 -0
- data/spec/lib/typing/tm_local_var_asgn_spec.rb +134 -0
- data/spec/lib/typing/tm_mlhs_spec.rb +164 -0
- data/spec/lib/typing/tm_module_spec.rb +89 -0
- data/spec/lib/typing/tm_raise_spec.rb +31 -0
- data/spec/lib/typing/tm_range_literal_spec.rb +25 -0
- data/spec/lib/typing/tm_regexp_spec.rb +14 -0
- data/spec/lib/typing/tm_return_spec.rb +45 -0
- data/spec/lib/typing/tm_send_casting_spec.rb +26 -0
- data/spec/lib/typing/tm_send_class_methods_spec.rb +42 -0
- data/spec/lib/typing/tm_send_generic_apply_spec.rb +103 -0
- data/spec/lib/typing/tm_send_generic_methods_spec.rb +77 -0
- data/spec/lib/typing/tm_send_initialize_spec.rb +68 -0
- data/spec/lib/typing/tm_send_lambda_spec.rb +135 -0
- data/spec/lib/typing/tm_send_spec.rb +217 -0
- data/spec/lib/typing/tm_send_yield_block_spec.rb +308 -0
- data/spec/lib/typing/tm_sequencing_spec.rb +174 -0
- data/spec/lib/typing/tm_string_interpolation_spec.rb +19 -0
- data/spec/lib/typing/tm_super_spec.rb +63 -0
- data/spec/lib/typing/tm_symbol_interpolation_spec.rb +19 -0
- data/spec/lib/typing/tm_symbol_spec.rb +14 -0
- data/spec/lib/typing/tm_try_spec.rb +73 -0
- data/spec/spec_helper.rb +140 -0
- 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
|