typeprof 0.21.11 → 0.30.1
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 +4 -4
- data/README.md +15 -31
- data/bin/typeprof +5 -0
- data/doc/doc.ja.md +134 -0
- data/doc/doc.md +136 -0
- data/lib/typeprof/cli/cli.rb +178 -0
- data/lib/typeprof/cli.rb +3 -133
- data/lib/typeprof/code_range.rb +112 -0
- data/lib/typeprof/core/ast/base.rb +263 -0
- data/lib/typeprof/core/ast/call.rb +259 -0
- data/lib/typeprof/core/ast/const.rb +126 -0
- data/lib/typeprof/core/ast/control.rb +433 -0
- data/lib/typeprof/core/ast/meta.rb +150 -0
- data/lib/typeprof/core/ast/method.rb +339 -0
- data/lib/typeprof/core/ast/misc.rb +263 -0
- data/lib/typeprof/core/ast/module.rb +123 -0
- data/lib/typeprof/core/ast/pattern.rb +140 -0
- data/lib/typeprof/core/ast/sig_decl.rb +471 -0
- data/lib/typeprof/core/ast/sig_type.rb +663 -0
- data/lib/typeprof/core/ast/value.rb +319 -0
- data/lib/typeprof/core/ast/variable.rb +315 -0
- data/lib/typeprof/core/ast.rb +472 -0
- data/lib/typeprof/core/builtin.rb +146 -0
- data/lib/typeprof/core/env/method.rb +137 -0
- data/lib/typeprof/core/env/method_entity.rb +55 -0
- data/lib/typeprof/core/env/module_entity.rb +408 -0
- data/lib/typeprof/core/env/static_read.rb +155 -0
- data/lib/typeprof/core/env/type_alias_entity.rb +27 -0
- data/lib/typeprof/core/env/value_entity.rb +32 -0
- data/lib/typeprof/core/env.rb +366 -0
- data/lib/typeprof/core/graph/box.rb +998 -0
- data/lib/typeprof/core/graph/change_set.rb +224 -0
- data/lib/typeprof/core/graph/filter.rb +155 -0
- data/lib/typeprof/core/graph/vertex.rb +225 -0
- data/lib/typeprof/core/service.rb +514 -0
- data/lib/typeprof/core/type.rb +352 -0
- data/lib/typeprof/core/util.rb +81 -0
- data/lib/typeprof/core.rb +31 -0
- data/lib/typeprof/diagnostic.rb +35 -0
- data/lib/typeprof/lsp/messages.rb +415 -0
- data/lib/typeprof/lsp/server.rb +203 -0
- data/lib/typeprof/lsp/text.rb +69 -0
- data/lib/typeprof/lsp/util.rb +51 -0
- data/lib/typeprof/lsp.rb +4 -907
- data/lib/typeprof/version.rb +1 -1
- data/lib/typeprof.rb +4 -18
- data/typeprof.gemspec +5 -7
- metadata +47 -33
- data/.github/dependabot.yml +0 -6
- data/.github/workflows/main.yml +0 -39
- data/.gitignore +0 -9
- data/Gemfile +0 -17
- data/Gemfile.lock +0 -41
- data/Rakefile +0 -10
- data/exe/typeprof +0 -10
- data/lib/typeprof/analyzer.rb +0 -2598
- data/lib/typeprof/arguments.rb +0 -414
- data/lib/typeprof/block.rb +0 -176
- data/lib/typeprof/builtin.rb +0 -893
- data/lib/typeprof/code-range.rb +0 -177
- data/lib/typeprof/config.rb +0 -158
- data/lib/typeprof/container-type.rb +0 -912
- data/lib/typeprof/export.rb +0 -589
- data/lib/typeprof/import.rb +0 -852
- data/lib/typeprof/insns-def.rb +0 -65
- data/lib/typeprof/iseq.rb +0 -864
- data/lib/typeprof/method.rb +0 -355
- data/lib/typeprof/type.rb +0 -1140
- data/lib/typeprof/utils.rb +0 -212
- data/tools/coverage.rb +0 -14
- data/tools/setup-insns-def.rb +0 -30
- data/typeprof-lsp +0 -3
data/lib/typeprof/type.rb
DELETED
@@ -1,1140 +0,0 @@
|
|
1
|
-
module TypeProf
|
2
|
-
class Type # or AbstractValue
|
3
|
-
include Utils::StructuralEquality
|
4
|
-
|
5
|
-
def initialize
|
6
|
-
raise "cannot instantiate abstract type"
|
7
|
-
end
|
8
|
-
|
9
|
-
Builtin = {}
|
10
|
-
|
11
|
-
def globalize(_env, _visited, _depth)
|
12
|
-
self
|
13
|
-
end
|
14
|
-
|
15
|
-
def localize(env, _alloc_site, _depth)
|
16
|
-
return env, self
|
17
|
-
end
|
18
|
-
|
19
|
-
def limit_size(limit)
|
20
|
-
self
|
21
|
-
end
|
22
|
-
|
23
|
-
def self.match?(ty1, ty2)
|
24
|
-
# both ty1 and ty2 should be global
|
25
|
-
# ty1 is always concrete; it should not have type variables
|
26
|
-
# ty2 might be abstract; it may have type variables
|
27
|
-
case ty2
|
28
|
-
when Type::Var
|
29
|
-
{ ty2 => ty1 }
|
30
|
-
when Type::Any
|
31
|
-
{}
|
32
|
-
when Type::Union
|
33
|
-
subst = nil
|
34
|
-
ty2.each_child_global do |ty2|
|
35
|
-
# this is very conservative to create subst:
|
36
|
-
# Type.match?( int | str, int | X) creates { X => int | str } but should be { X => str }???
|
37
|
-
subst2 = Type.match?(ty1, ty2)
|
38
|
-
next unless subst2
|
39
|
-
subst = Type.merge_substitution(subst, subst2)
|
40
|
-
end
|
41
|
-
subst
|
42
|
-
else
|
43
|
-
case ty1
|
44
|
-
when Type::Var then raise "should not occur"
|
45
|
-
when Type::Any
|
46
|
-
subst = {}
|
47
|
-
ty2.each_free_type_variable do |tyvar|
|
48
|
-
subst[tyvar] = Type.any
|
49
|
-
end
|
50
|
-
subst
|
51
|
-
when Type::Union
|
52
|
-
subst = nil
|
53
|
-
ty1.each_child_global do |ty1|
|
54
|
-
subst2 = Type.match?(ty1, ty2)
|
55
|
-
next unless subst2
|
56
|
-
subst = Type.merge_substitution(subst, subst2)
|
57
|
-
end
|
58
|
-
subst
|
59
|
-
else
|
60
|
-
if ty2.is_a?(Type::ContainerType)
|
61
|
-
# ty2 may have type variables
|
62
|
-
if ty1.class == ty2.class
|
63
|
-
ty1.match?(ty2)
|
64
|
-
else
|
65
|
-
Type.match?(ty1, ty2.base_type)
|
66
|
-
end
|
67
|
-
elsif ty1.is_a?(Type::ContainerType)
|
68
|
-
Type.match?(ty1.base_type, ty2)
|
69
|
-
else
|
70
|
-
ty1.consistent?(ty2) ? {} : nil
|
71
|
-
end
|
72
|
-
end
|
73
|
-
end
|
74
|
-
end
|
75
|
-
|
76
|
-
def self.merge_substitution(subst1, subst2)
|
77
|
-
if subst1
|
78
|
-
subst1 = subst1.dup
|
79
|
-
subst2.each do |tyvar, ty|
|
80
|
-
if subst1[tyvar]
|
81
|
-
subst1[tyvar] = subst1[tyvar].union(ty)
|
82
|
-
else
|
83
|
-
subst1[tyvar] = ty
|
84
|
-
end
|
85
|
-
end
|
86
|
-
subst1
|
87
|
-
else
|
88
|
-
subst2
|
89
|
-
end
|
90
|
-
end
|
91
|
-
|
92
|
-
def each_child
|
93
|
-
yield self
|
94
|
-
end
|
95
|
-
|
96
|
-
def each_child_global
|
97
|
-
yield self
|
98
|
-
end
|
99
|
-
|
100
|
-
def each_free_type_variable
|
101
|
-
end
|
102
|
-
|
103
|
-
def union(other)
|
104
|
-
return self if self == other # fastpath
|
105
|
-
|
106
|
-
ty1, ty2 = self, other
|
107
|
-
|
108
|
-
case
|
109
|
-
when ty1.is_a?(Union)
|
110
|
-
ty1_types = ty1.types
|
111
|
-
ty1_elems = ty1.elems
|
112
|
-
when ty1.is_a?(Array) || ty1.is_a?(Hash)
|
113
|
-
ty1_types = Utils::Set[]
|
114
|
-
ty1_elems = {[ty1.class, ty1.base_type] => ty1.elems}
|
115
|
-
else
|
116
|
-
ty1_types = ty1_elems = nil
|
117
|
-
end
|
118
|
-
|
119
|
-
case
|
120
|
-
when ty2.is_a?(Union)
|
121
|
-
ty2_types = ty2.types
|
122
|
-
ty2_elems = ty2.elems
|
123
|
-
when ty2.is_a?(Array) || ty2.is_a?(Hash)
|
124
|
-
ty2_types = Utils::Set[]
|
125
|
-
ty2_elems = {[ty2.class, ty2.base_type] => ty2.elems}
|
126
|
-
else
|
127
|
-
ty2_types = ty2_elems = nil
|
128
|
-
end
|
129
|
-
|
130
|
-
if ty1_types && ty2_types
|
131
|
-
ty = ty1_types.sum(ty2_types)
|
132
|
-
all_elems = ty1_elems.dup || {}
|
133
|
-
ty2_elems&.each do |key, elems|
|
134
|
-
all_elems[key] = union_elems(all_elems[key], elems)
|
135
|
-
end
|
136
|
-
all_elems = nil if all_elems.empty?
|
137
|
-
|
138
|
-
Type::Union.create(ty, all_elems)
|
139
|
-
elsif ty1_types
|
140
|
-
Type::Union.create(ty1_types.add(ty2), ty1_elems)
|
141
|
-
elsif ty2_types
|
142
|
-
Type::Union.create(ty2_types.add(ty1), ty2_elems)
|
143
|
-
else
|
144
|
-
Type::Union.create(Utils::Set[ty1, ty2], nil)
|
145
|
-
end
|
146
|
-
end
|
147
|
-
|
148
|
-
private def union_elems(e1, e2)
|
149
|
-
if e1
|
150
|
-
if e2
|
151
|
-
e1.union(e2)
|
152
|
-
else
|
153
|
-
e1
|
154
|
-
end
|
155
|
-
else
|
156
|
-
e2
|
157
|
-
end
|
158
|
-
end
|
159
|
-
|
160
|
-
def substitute(_subst, _depth)
|
161
|
-
raise "cannot substitute abstract type: #{ self.class }"
|
162
|
-
end
|
163
|
-
|
164
|
-
def generate_substitution
|
165
|
-
{}
|
166
|
-
end
|
167
|
-
|
168
|
-
DummySubstitution = Object.new
|
169
|
-
def DummySubstitution.[](_)
|
170
|
-
Type.any
|
171
|
-
end
|
172
|
-
|
173
|
-
def remove_type_vars
|
174
|
-
substitute(DummySubstitution, Config.current.options[:type_depth_limit])
|
175
|
-
end
|
176
|
-
|
177
|
-
def include_untyped?(_scratch)
|
178
|
-
false
|
179
|
-
end
|
180
|
-
|
181
|
-
class Any < Type
|
182
|
-
def initialize
|
183
|
-
end
|
184
|
-
|
185
|
-
def inspect
|
186
|
-
"Type::Any"
|
187
|
-
end
|
188
|
-
|
189
|
-
def screen_name(scratch)
|
190
|
-
"untyped"
|
191
|
-
end
|
192
|
-
|
193
|
-
def method_dispatch_info
|
194
|
-
nil
|
195
|
-
end
|
196
|
-
|
197
|
-
def consistent?(_other)
|
198
|
-
raise "should not be called"
|
199
|
-
end
|
200
|
-
|
201
|
-
def substitute(_subst, _depth)
|
202
|
-
self
|
203
|
-
end
|
204
|
-
|
205
|
-
def include_untyped?(_scratch)
|
206
|
-
true
|
207
|
-
end
|
208
|
-
end
|
209
|
-
|
210
|
-
class Void < Any
|
211
|
-
def inspect
|
212
|
-
"Type::Void"
|
213
|
-
end
|
214
|
-
|
215
|
-
def screen_name(scratch)
|
216
|
-
"void"
|
217
|
-
end
|
218
|
-
end
|
219
|
-
|
220
|
-
|
221
|
-
class Union < Type
|
222
|
-
def self.create(tys, elems)
|
223
|
-
if tys.size == 1 && !elems
|
224
|
-
tys.each {|ty| return ty }
|
225
|
-
elsif tys.size == 0
|
226
|
-
if elems && elems.size == 1
|
227
|
-
(container_kind, base_type), nelems = elems.first
|
228
|
-
# container_kind = Type::Array or Type::Hash
|
229
|
-
container_kind.new(nelems, base_type)
|
230
|
-
else
|
231
|
-
new(tys, elems)
|
232
|
-
end
|
233
|
-
else
|
234
|
-
class_instances = []
|
235
|
-
non_class_instances = []
|
236
|
-
degenerated = false
|
237
|
-
tys.each do |ty|
|
238
|
-
if ty != Type::Instance.new(Type::Builtin[:nil]) && ty.is_a?(Type::Instance) && ty.klass.kind == :class
|
239
|
-
class_instances << ty
|
240
|
-
degenerated = true if ty.include_subclasses
|
241
|
-
else
|
242
|
-
non_class_instances << ty
|
243
|
-
end
|
244
|
-
end
|
245
|
-
if (Config.current.options[:union_width_limit] >= 2 && class_instances.size >= Config.current.options[:union_width_limit]) || (degenerated && class_instances.size >= 2)
|
246
|
-
create(Utils::Set[Instance.new_degenerate(class_instances), *non_class_instances], elems)
|
247
|
-
else
|
248
|
-
new(tys, elems)
|
249
|
-
end
|
250
|
-
end
|
251
|
-
end
|
252
|
-
|
253
|
-
def initialize(tys, elems)
|
254
|
-
raise unless tys.is_a?(Utils::Set)
|
255
|
-
@types = tys # Set
|
256
|
-
|
257
|
-
# invariant check
|
258
|
-
local = nil
|
259
|
-
tys.each do |ty|
|
260
|
-
raise ty.inspect unless ty.is_a?(Type)
|
261
|
-
local = true if ty.is_a?(Local)
|
262
|
-
end
|
263
|
-
raise if local && elems
|
264
|
-
|
265
|
-
@elems = elems
|
266
|
-
raise elems.inspect if elems && !elems.is_a?(::Hash)
|
267
|
-
end
|
268
|
-
|
269
|
-
def each_free_type_variable(&blk)
|
270
|
-
each_child_global do |ty|
|
271
|
-
ty.each_free_type_variable(&blk)
|
272
|
-
end
|
273
|
-
end
|
274
|
-
|
275
|
-
def limit_size(limit)
|
276
|
-
return Type.any if limit <= 0
|
277
|
-
tys = Utils::Set[]
|
278
|
-
@types.each do |ty|
|
279
|
-
tys = tys.add(ty.limit_size(limit - 1))
|
280
|
-
end
|
281
|
-
elems = @elems&.to_h do |key, elems|
|
282
|
-
[key, elems.limit_size(limit - 1)]
|
283
|
-
end
|
284
|
-
Union.new(tys, elems)
|
285
|
-
end
|
286
|
-
|
287
|
-
attr_reader :types, :elems
|
288
|
-
|
289
|
-
def each_child(&blk) # local
|
290
|
-
@types.each(&blk)
|
291
|
-
raise if @elems
|
292
|
-
end
|
293
|
-
|
294
|
-
def each_child_global(&blk)
|
295
|
-
@types.each(&blk)
|
296
|
-
@elems&.each do |(container_kind, base_type), elems|
|
297
|
-
yield container_kind.new(elems, base_type)
|
298
|
-
end
|
299
|
-
end
|
300
|
-
|
301
|
-
def inspect
|
302
|
-
a = []
|
303
|
-
a << "Type::Union{#{ @types.to_a.map {|ty| ty.inspect }.join(", ") }"
|
304
|
-
@elems&.each do |(container_kind, base_type), elems|
|
305
|
-
a << ", #{ container_kind.new(elems, base_type).inspect }"
|
306
|
-
end
|
307
|
-
a << "}"
|
308
|
-
a.join
|
309
|
-
end
|
310
|
-
|
311
|
-
def screen_name(scratch)
|
312
|
-
types = @types.to_a
|
313
|
-
@elems&.each do |(container_kind, base_type), elems|
|
314
|
-
types << container_kind.new(elems, base_type)
|
315
|
-
end
|
316
|
-
if types.size == 0
|
317
|
-
"bot"
|
318
|
-
else
|
319
|
-
types = types.to_a
|
320
|
-
optional = !!types.delete(Type::Instance.new(Type::Builtin[:nil]))
|
321
|
-
bool = false
|
322
|
-
if types.include?(Type::Instance.new(Type::Builtin[:false])) &&
|
323
|
-
types.include?(Type::Instance.new(Type::Builtin[:true]))
|
324
|
-
types.delete(Type::Instance.new(Type::Builtin[:false]))
|
325
|
-
types.delete(Type::Instance.new(Type::Builtin[:true]))
|
326
|
-
bool = true
|
327
|
-
end
|
328
|
-
types.delete(Type.any) unless Config.current.options[:show_untyped]
|
329
|
-
proc_tys, types = types.partition {|ty| ty.is_a?(Proc) }
|
330
|
-
types = types.map {|ty| ty.screen_name(scratch) }
|
331
|
-
types << scratch.show_proc_signature(proc_tys) unless proc_tys.empty?
|
332
|
-
types << "bool" if bool
|
333
|
-
types = types.sort
|
334
|
-
if optional
|
335
|
-
case types.size
|
336
|
-
when 0 then "nil"
|
337
|
-
when 1 then types.first + "?"
|
338
|
-
else
|
339
|
-
"(#{ types.join (" | ") })?"
|
340
|
-
end
|
341
|
-
else
|
342
|
-
types.join (" | ")
|
343
|
-
end
|
344
|
-
end
|
345
|
-
end
|
346
|
-
|
347
|
-
def globalize(env, visited, depth)
|
348
|
-
return Type.any if depth <= 0
|
349
|
-
tys = Utils::Set[]
|
350
|
-
if @elems
|
351
|
-
# XXX: If @elems is non nil, the Union type should global, so calling globalize against such a type should not occur.
|
352
|
-
# However, currently, ActualArguments may contain global types for flag_args_kw_splat case.
|
353
|
-
# This should be fixed in future in ActualArguments side. See Scratch#setup_actual_arguments.
|
354
|
-
#raise
|
355
|
-
end
|
356
|
-
|
357
|
-
elems = @elems ? @elems.dup : {}
|
358
|
-
@types.each do |ty|
|
359
|
-
ty = ty.globalize(env, visited, depth - 1)
|
360
|
-
case ty
|
361
|
-
when Type::Array, Type::Hash
|
362
|
-
key = [ty.class, ty.base_type]
|
363
|
-
elems[key] = union_elems(elems[key], ty.elems)
|
364
|
-
else
|
365
|
-
tys = tys.add(ty)
|
366
|
-
end
|
367
|
-
end
|
368
|
-
elems = nil if elems.empty?
|
369
|
-
|
370
|
-
Type::Union.create(tys, elems)
|
371
|
-
end
|
372
|
-
|
373
|
-
def localize(env, alloc_site, depth)
|
374
|
-
return env, Type.any if depth <= 0
|
375
|
-
tys = @types.map do |ty|
|
376
|
-
env, ty2 = ty.localize(env, alloc_site, depth - 1)
|
377
|
-
ty2
|
378
|
-
end
|
379
|
-
@elems&.each do |(container_kind, base_type), elems|
|
380
|
-
ty = container_kind.new(elems, base_type)
|
381
|
-
env, ty = ty.localize(env, alloc_site, depth - 1)
|
382
|
-
tys = tys.add(ty)
|
383
|
-
end
|
384
|
-
ty = Union.create(tys, nil)
|
385
|
-
return env, ty
|
386
|
-
end
|
387
|
-
|
388
|
-
def consistent?(_other)
|
389
|
-
raise "should not be called"
|
390
|
-
end
|
391
|
-
|
392
|
-
def substitute(subst, depth)
|
393
|
-
return Type.any if depth <= 0
|
394
|
-
unions = []
|
395
|
-
tys = Utils::Set[]
|
396
|
-
@types.each do |ty|
|
397
|
-
ty = ty.substitute(subst, depth - 1)
|
398
|
-
case ty
|
399
|
-
when Union
|
400
|
-
unions << ty
|
401
|
-
else
|
402
|
-
tys = tys.add(ty)
|
403
|
-
end
|
404
|
-
end
|
405
|
-
elems = @elems&.to_h do |(container_kind, base_type), elems|
|
406
|
-
[[container_kind, base_type], elems.substitute(subst, depth - 1)]
|
407
|
-
end
|
408
|
-
ty = Union.create(tys, elems)
|
409
|
-
unions.each do |ty0|
|
410
|
-
ty = ty.union(ty0)
|
411
|
-
end
|
412
|
-
ty
|
413
|
-
end
|
414
|
-
|
415
|
-
def include_untyped?(scratch)
|
416
|
-
@types.each do |ty|
|
417
|
-
return true if ty.include_untyped?(scratch)
|
418
|
-
end
|
419
|
-
@elems&.each do |(container_kind, base_type), elems|
|
420
|
-
return true if base_type.include_untyped?(scratch)
|
421
|
-
return true if elems.include_untyped?(scratch)
|
422
|
-
end
|
423
|
-
false
|
424
|
-
end
|
425
|
-
end
|
426
|
-
|
427
|
-
def self.any
|
428
|
-
Thread.current[:any] ||= Any.new
|
429
|
-
end
|
430
|
-
|
431
|
-
def self.bot
|
432
|
-
Thread.current[:bot] ||= Union.new(Utils::Set[], nil)
|
433
|
-
end
|
434
|
-
|
435
|
-
def self.bool
|
436
|
-
Thread.current[:bool] ||= Union.new(Utils::Set[
|
437
|
-
Instance.new(Type::Builtin[:true]),
|
438
|
-
Instance.new(Type::Builtin[:false])
|
439
|
-
], nil)
|
440
|
-
end
|
441
|
-
|
442
|
-
def self.nil
|
443
|
-
Thread.current[:nil] ||= Instance.new(Type::Builtin[:nil])
|
444
|
-
end
|
445
|
-
|
446
|
-
def self.optional(ty)
|
447
|
-
ty.union(Type.nil)
|
448
|
-
end
|
449
|
-
|
450
|
-
class Var < Type
|
451
|
-
def initialize(name)
|
452
|
-
@name = name
|
453
|
-
end
|
454
|
-
|
455
|
-
def screen_name(scratch)
|
456
|
-
"Var[#{ @name }]"
|
457
|
-
end
|
458
|
-
|
459
|
-
def each_free_type_variable
|
460
|
-
yield self
|
461
|
-
end
|
462
|
-
|
463
|
-
def substitute(subst, depth)
|
464
|
-
if subst[self]
|
465
|
-
subst[self].limit_size(depth)
|
466
|
-
else
|
467
|
-
self
|
468
|
-
end
|
469
|
-
end
|
470
|
-
|
471
|
-
def consistent?(_other)
|
472
|
-
raise "should not be called: #{ self }"
|
473
|
-
end
|
474
|
-
|
475
|
-
def add_subst!(ty, subst)
|
476
|
-
if subst[self]
|
477
|
-
subst[self] = subst[self].union(ty)
|
478
|
-
else
|
479
|
-
subst[self] = ty
|
480
|
-
end
|
481
|
-
true
|
482
|
-
end
|
483
|
-
end
|
484
|
-
|
485
|
-
class Class < Type # or Module
|
486
|
-
def initialize(kind, idx, type_params, superclass, name)
|
487
|
-
@kind = kind # :class | :module
|
488
|
-
@idx = idx
|
489
|
-
@type_params = type_params
|
490
|
-
@superclass = superclass
|
491
|
-
raise if @kind == :class && !@superclass
|
492
|
-
@_name = name
|
493
|
-
end
|
494
|
-
|
495
|
-
attr_reader :kind, :idx, :type_params, :superclass
|
496
|
-
attr_accessor :superclass_type_args
|
497
|
-
|
498
|
-
def inspect
|
499
|
-
if @_name
|
500
|
-
"#{ @_name }@#{ @idx }"
|
501
|
-
else
|
502
|
-
"Class[#{ @idx }]"
|
503
|
-
end
|
504
|
-
end
|
505
|
-
|
506
|
-
def screen_name(scratch)
|
507
|
-
"singleton(#{ scratch.get_class_name(self) })"
|
508
|
-
end
|
509
|
-
|
510
|
-
def method_dispatch_info
|
511
|
-
[self, true, false]
|
512
|
-
end
|
513
|
-
|
514
|
-
def consistent?(other)
|
515
|
-
case other
|
516
|
-
when Type::Class
|
517
|
-
ty = self
|
518
|
-
loop do
|
519
|
-
# ad-hoc
|
520
|
-
return false if !ty || !other # module
|
521
|
-
|
522
|
-
return true if ty.idx == other.idx
|
523
|
-
return false if ty.idx == 0 # Object
|
524
|
-
ty = ty.superclass
|
525
|
-
end
|
526
|
-
when Type::Instance
|
527
|
-
return true if other.klass == Type::Builtin[:obj] || other.klass == Type::Builtin[:class] || other.klass == Type::Builtin[:module]
|
528
|
-
return false
|
529
|
-
else
|
530
|
-
false
|
531
|
-
end
|
532
|
-
end
|
533
|
-
|
534
|
-
def substitute(_subst, _depth)
|
535
|
-
self
|
536
|
-
end
|
537
|
-
end
|
538
|
-
|
539
|
-
class Instance < Type
|
540
|
-
def initialize(klass, include_subclasses=false)
|
541
|
-
raise unless klass
|
542
|
-
raise if klass == Type.any
|
543
|
-
raise if klass.is_a?(Type::Instance)
|
544
|
-
raise if klass.is_a?(Type::Union)
|
545
|
-
@klass = klass
|
546
|
-
@include_subclasses = include_subclasses
|
547
|
-
end
|
548
|
-
|
549
|
-
def self.new_degenerate(instances)
|
550
|
-
klass = instances.first.klass
|
551
|
-
ancestors = []
|
552
|
-
ancestor_idxs = {}
|
553
|
-
while klass != :__root__
|
554
|
-
ancestor_idxs[klass] = ancestors.size
|
555
|
-
ancestors << klass
|
556
|
-
klass = klass.superclass
|
557
|
-
end
|
558
|
-
common_superclass = nil
|
559
|
-
instances[1..].each do |instance|
|
560
|
-
klass = instance.klass
|
561
|
-
while !ancestor_idxs[klass]
|
562
|
-
klass = klass.superclass
|
563
|
-
end
|
564
|
-
common_superclass = klass
|
565
|
-
ancestor_idxs[klass].times do |i|
|
566
|
-
ancestor_idxs.delete(ancestors[i])
|
567
|
-
ancestors[i] = nil
|
568
|
-
end
|
569
|
-
end
|
570
|
-
new(common_superclass, true)
|
571
|
-
end
|
572
|
-
|
573
|
-
attr_reader :klass, :include_subclasses
|
574
|
-
|
575
|
-
def inspect
|
576
|
-
"I[#{ @klass.inspect }]"
|
577
|
-
end
|
578
|
-
|
579
|
-
def screen_name(scratch)
|
580
|
-
case @klass
|
581
|
-
when Type::Builtin[:nil] then "nil"
|
582
|
-
when Type::Builtin[:true] then "true"
|
583
|
-
when Type::Builtin[:false] then "false"
|
584
|
-
else
|
585
|
-
scratch.get_class_name(@klass) + (@include_subclasses ? "" : "")
|
586
|
-
end
|
587
|
-
end
|
588
|
-
|
589
|
-
def method_dispatch_info
|
590
|
-
[@klass, false, @include_subclasses]
|
591
|
-
end
|
592
|
-
|
593
|
-
def consistent?(other)
|
594
|
-
case other
|
595
|
-
when Type::Instance
|
596
|
-
@klass.consistent?(other.klass)
|
597
|
-
when Type::Class
|
598
|
-
return true if @klass == Type::Builtin[:obj] || @klass == Type::Builtin[:class] || @klass == Type::Builtin[:module]
|
599
|
-
return false
|
600
|
-
else
|
601
|
-
false
|
602
|
-
end
|
603
|
-
end
|
604
|
-
|
605
|
-
def substitute(subst, depth)
|
606
|
-
Instance.new(@klass.substitute(subst, depth))
|
607
|
-
end
|
608
|
-
end
|
609
|
-
|
610
|
-
# This is an internal object in MRI, so a user program cannot create this object explicitly
|
611
|
-
class ISeq < Type
|
612
|
-
def initialize(iseq)
|
613
|
-
@iseq = iseq
|
614
|
-
end
|
615
|
-
|
616
|
-
attr_reader :iseq
|
617
|
-
|
618
|
-
def inspect
|
619
|
-
"Type::ISeq[#{ @iseq }]"
|
620
|
-
end
|
621
|
-
|
622
|
-
def screen_name(_scratch)
|
623
|
-
raise NotImplementedError
|
624
|
-
end
|
625
|
-
end
|
626
|
-
|
627
|
-
class Proc < Type
|
628
|
-
def initialize(block_body, base_type)
|
629
|
-
@block_body, @base_type = block_body, base_type
|
630
|
-
end
|
631
|
-
|
632
|
-
attr_reader :block_body, :base_type
|
633
|
-
|
634
|
-
def consistent?(other)
|
635
|
-
case other
|
636
|
-
when Type::Proc
|
637
|
-
@block_body.consistent?(other.block_body)
|
638
|
-
else
|
639
|
-
self == other
|
640
|
-
end
|
641
|
-
end
|
642
|
-
|
643
|
-
def method_dispatch_info
|
644
|
-
@base_type.method_dispatch_info
|
645
|
-
end
|
646
|
-
|
647
|
-
def substitute(subst, depth)
|
648
|
-
Proc.new(@block_body.substitute(subst, depth), @base_type)
|
649
|
-
end
|
650
|
-
|
651
|
-
def screen_name(scratch)
|
652
|
-
scratch.show_proc_signature([self])
|
653
|
-
end
|
654
|
-
|
655
|
-
def include_untyped?(scratch)
|
656
|
-
false # XXX: need to check the block signatures recursively
|
657
|
-
end
|
658
|
-
end
|
659
|
-
|
660
|
-
class Symbol < Type
|
661
|
-
def initialize(sym, base_type)
|
662
|
-
@sym = sym
|
663
|
-
@base_type = base_type
|
664
|
-
end
|
665
|
-
|
666
|
-
attr_reader :sym, :base_type
|
667
|
-
|
668
|
-
def inspect
|
669
|
-
"Type::Symbol[#{ @sym ? @sym.inspect : "(dynamic symbol)" }, #{ @base_type.inspect }]"
|
670
|
-
end
|
671
|
-
|
672
|
-
def consistent?(other)
|
673
|
-
case other
|
674
|
-
when Symbol
|
675
|
-
@sym == other.sym
|
676
|
-
else
|
677
|
-
@base_type.consistent?(other)
|
678
|
-
end
|
679
|
-
end
|
680
|
-
|
681
|
-
def screen_name(scratch)
|
682
|
-
if @sym
|
683
|
-
@sym.inspect
|
684
|
-
else
|
685
|
-
@base_type.screen_name(scratch)
|
686
|
-
end
|
687
|
-
end
|
688
|
-
|
689
|
-
def method_dispatch_info
|
690
|
-
@base_type.method_dispatch_info
|
691
|
-
end
|
692
|
-
|
693
|
-
def substitute(_subst, _depth)
|
694
|
-
self # dummy
|
695
|
-
end
|
696
|
-
end
|
697
|
-
|
698
|
-
# A local type
|
699
|
-
class Literal < Type
|
700
|
-
def initialize(lit, base_type)
|
701
|
-
@lit = lit
|
702
|
-
@base_type = base_type
|
703
|
-
end
|
704
|
-
|
705
|
-
attr_reader :lit, :base_type
|
706
|
-
|
707
|
-
def inspect
|
708
|
-
"Type::Literal[#{ @lit.inspect }, #{ @base_type.inspect }]"
|
709
|
-
end
|
710
|
-
|
711
|
-
def screen_name(scratch)
|
712
|
-
@base_type.screen_name(scratch) + "<#{ @lit.inspect }>"
|
713
|
-
end
|
714
|
-
|
715
|
-
def globalize(_env, _visited, _depth)
|
716
|
-
@base_type
|
717
|
-
end
|
718
|
-
|
719
|
-
def method_dispatch_info
|
720
|
-
@base_type.method_dispatch_info
|
721
|
-
end
|
722
|
-
|
723
|
-
def consistent?(_other)
|
724
|
-
raise "should not called"
|
725
|
-
end
|
726
|
-
end
|
727
|
-
|
728
|
-
class HashGenerator
|
729
|
-
def initialize
|
730
|
-
@map_tys = {}
|
731
|
-
end
|
732
|
-
|
733
|
-
attr_reader :map_tys
|
734
|
-
|
735
|
-
def []=(k_ty, v_ty)
|
736
|
-
k_ty.each_child_global do |k_ty|
|
737
|
-
if k_ty.is_a?(Type::Union)
|
738
|
-
# Flatten recursive union
|
739
|
-
self[k_ty] = v_ty
|
740
|
-
else
|
741
|
-
# This is a temporal hack to mitigate type explosion
|
742
|
-
k_ty = Type.any if k_ty.is_a?(Type::Array)
|
743
|
-
k_ty = Type.any if k_ty.is_a?(Type::Hash)
|
744
|
-
|
745
|
-
if @map_tys[k_ty]
|
746
|
-
@map_tys[k_ty] = @map_tys[k_ty].union(v_ty)
|
747
|
-
else
|
748
|
-
@map_tys[k_ty] = v_ty
|
749
|
-
end
|
750
|
-
end
|
751
|
-
end
|
752
|
-
end
|
753
|
-
end
|
754
|
-
|
755
|
-
def self.gen_hash(base_ty = Type::Instance.new(Type::Builtin[:hash]))
|
756
|
-
hg = HashGenerator.new
|
757
|
-
yield hg
|
758
|
-
Type::Hash.new(Type::Hash::Elements.new(hg.map_tys), base_ty)
|
759
|
-
end
|
760
|
-
|
761
|
-
def self.guess_literal_type(obj)
|
762
|
-
case obj
|
763
|
-
when ::Symbol
|
764
|
-
Type::Symbol.new(obj, Type::Instance.new(Type::Builtin[:sym]))
|
765
|
-
when ::Integer
|
766
|
-
Type::Literal.new(obj, Type::Instance.new(Type::Builtin[:int]))
|
767
|
-
when ::Rational
|
768
|
-
Type::Literal.new(obj, Type::Instance.new(Type::Builtin[:rational]))
|
769
|
-
when ::Complex
|
770
|
-
Type::Literal.new(obj, Type::Instance.new(Type::Builtin[:complex]))
|
771
|
-
when ::Float
|
772
|
-
Type::Literal.new(obj, Type::Instance.new(Type::Builtin[:float]))
|
773
|
-
when ::Class
|
774
|
-
return Type.any if obj < Exception
|
775
|
-
case obj
|
776
|
-
when ::Object
|
777
|
-
Type::Builtin[:obj]
|
778
|
-
when ::Array
|
779
|
-
Type::Builtin[:ary]
|
780
|
-
else
|
781
|
-
raise "unknown class: #{ obj.inspect }"
|
782
|
-
end
|
783
|
-
when ::TrueClass
|
784
|
-
Type::Instance.new(Type::Builtin[:true])
|
785
|
-
when ::FalseClass
|
786
|
-
Type::Instance.new(Type::Builtin[:false])
|
787
|
-
when ::Array
|
788
|
-
base_ty = Type::Instance.new(Type::Builtin[:ary])
|
789
|
-
lead_tys = obj.map {|arg| guess_literal_type(arg) }
|
790
|
-
Type::Array.new(Type::Array::Elements.new(lead_tys), base_ty)
|
791
|
-
when ::Hash
|
792
|
-
Type.gen_hash do |h|
|
793
|
-
obj.each do |k, v|
|
794
|
-
k_ty = guess_literal_type(k).globalize(nil, {}, Config.current.options[:type_depth_limit])
|
795
|
-
v_ty = guess_literal_type(v)
|
796
|
-
h[k_ty] = v_ty
|
797
|
-
end
|
798
|
-
end
|
799
|
-
when ::String
|
800
|
-
Type::Literal.new(obj, Type::Instance.new(Type::Builtin[:str]))
|
801
|
-
when ::Regexp
|
802
|
-
Type::Literal.new(obj, Type::Instance.new(Type::Builtin[:regexp]))
|
803
|
-
when ::NilClass
|
804
|
-
Type.nil
|
805
|
-
when ::Range
|
806
|
-
Type::Literal.new(obj, Type::Instance.new(Type::Builtin[:range]))
|
807
|
-
when ::Encoding
|
808
|
-
Type::Literal.new(obj, Type::Instance.new(Type::Builtin[:encoding]))
|
809
|
-
else
|
810
|
-
raise "unknown object: #{ obj.inspect }"
|
811
|
-
end
|
812
|
-
end
|
813
|
-
|
814
|
-
def self.builtin_global_variable_type(var)
|
815
|
-
case var
|
816
|
-
when :$_, :$/, :$\, :$,, :$;
|
817
|
-
Type.optional(Type::Instance.new(Type::Builtin[:str]))
|
818
|
-
when :$0, :$PROGRAM_NAME
|
819
|
-
Type::Instance.new(Type::Builtin[:str])
|
820
|
-
when :$~
|
821
|
-
# optional type is tentatively disabled; it is too conservative
|
822
|
-
#Type.optional(Type::Instance.new(Type::Builtin[:matchdata]))
|
823
|
-
Type::Instance.new(Type::Builtin[:matchdata])
|
824
|
-
when :$., :$$
|
825
|
-
Type::Instance.new(Type::Builtin[:int])
|
826
|
-
when :$?
|
827
|
-
Type.optional(Type::Instance.new(Type::Builtin[:int]))
|
828
|
-
when :$!
|
829
|
-
Type.optional(Type::Instance.new(Type::Builtin[:exc]))
|
830
|
-
when :$@
|
831
|
-
str = Type::Instance.new(Type::Builtin[:str])
|
832
|
-
base_ty = Type::Instance.new(Type::Builtin[:ary])
|
833
|
-
Type.optional(Type::Array.new(Type::Array::Elements.new([], str), base_ty))
|
834
|
-
when :$*, :$:, :$LOAD_PATH, :$", :$LOADED_FEATURES
|
835
|
-
str = Type::Instance.new(Type::Builtin[:str])
|
836
|
-
base_ty = Type::Instance.new(Type::Builtin[:ary])
|
837
|
-
Type::Array.new(Type::Array::Elements.new([], str), base_ty)
|
838
|
-
when :$<
|
839
|
-
:ARGF
|
840
|
-
when :$>
|
841
|
-
:STDOUT
|
842
|
-
when :$DEBUG
|
843
|
-
Type.bool
|
844
|
-
when :$FILENAME
|
845
|
-
Type::Instance.new(Type::Builtin[:str])
|
846
|
-
when :$stdin
|
847
|
-
:STDIN
|
848
|
-
when :$stdout
|
849
|
-
:STDOUT
|
850
|
-
when :$stderr
|
851
|
-
:STDERR
|
852
|
-
when :$VERBOSE
|
853
|
-
Type.bool.union(Type.nil)
|
854
|
-
else
|
855
|
-
nil
|
856
|
-
end
|
857
|
-
end
|
858
|
-
end
|
859
|
-
|
860
|
-
class Signature
|
861
|
-
include Utils::StructuralEquality
|
862
|
-
|
863
|
-
def screen_name(iseq, scratch)
|
864
|
-
fargs_str = "("
|
865
|
-
sig_help = {}
|
866
|
-
add_farg = -> farg, name, help: false, key: sig_help.size do
|
867
|
-
name = "`#{ name }`" if RBS::Parser::KEYWORDS.key?(name.to_s)
|
868
|
-
name = "noname" if name.is_a?(Integer) || name == :"*"
|
869
|
-
fargs_str << ", " if fargs_str != "("
|
870
|
-
i = fargs_str.size
|
871
|
-
fargs_str << (Config.current.options[:show_parameter_names] && name ? "#{ farg } #{ name }" : farg)
|
872
|
-
sig_help[key] = (i...fargs_str.size)
|
873
|
-
end
|
874
|
-
|
875
|
-
@lead_tys.zip(iseq ? iseq.locals : []) do |ty, name|
|
876
|
-
add_farg.call(ty.screen_name(scratch), name, help: true)
|
877
|
-
end
|
878
|
-
|
879
|
-
@opt_tys&.zip(iseq ? iseq.locals[@lead_tys.size, @opt_tys.size] : []) do |ty, name|
|
880
|
-
add_farg.call("?" + ty.screen_name(scratch), name, help: true)
|
881
|
-
end
|
882
|
-
|
883
|
-
if @rest_ty
|
884
|
-
if iseq
|
885
|
-
rest_index = iseq.fargs_format[:rest_start]
|
886
|
-
name = rest_index ? iseq.locals[rest_index] : nil
|
887
|
-
end
|
888
|
-
add_farg.call("*" + @rest_ty.screen_name(scratch), name)
|
889
|
-
end
|
890
|
-
|
891
|
-
if iseq
|
892
|
-
post_start = iseq.fargs_format[:post_start]
|
893
|
-
names = post_start ? iseq.locals[post_start, @post_tys.size] : []
|
894
|
-
end
|
895
|
-
@post_tys&.zip(names || []) do |ty, name|
|
896
|
-
add_farg.call(ty.screen_name(scratch), name)
|
897
|
-
end
|
898
|
-
|
899
|
-
@kw_tys&.each do |req, sym, ty|
|
900
|
-
opt = req ? "" : "?"
|
901
|
-
add_farg.call("#{ opt }#{ sym }: #{ ty.screen_name(scratch) }", nil, help: true, key: sym)
|
902
|
-
end
|
903
|
-
|
904
|
-
if @kw_rest_ty
|
905
|
-
all_val_ty = Type.bot
|
906
|
-
@kw_rest_ty.each_child_global do |ty|
|
907
|
-
if ty == Type.any
|
908
|
-
val_ty = ty
|
909
|
-
else
|
910
|
-
# ty is a Type::Hash
|
911
|
-
_key_ty, val_ty = ty.elems.squash
|
912
|
-
end
|
913
|
-
all_val_ty = all_val_ty.union(val_ty)
|
914
|
-
end
|
915
|
-
add_farg.call("**" + all_val_ty.screen_name(scratch), nil)
|
916
|
-
end
|
917
|
-
|
918
|
-
fargs_str << ")"
|
919
|
-
|
920
|
-
fargs_str = "" if fargs_str == "()"
|
921
|
-
|
922
|
-
# Dirty Hack: Stop the iteration at most once!
|
923
|
-
# I'll remove this hack if RBS removes the limitation of nesting blocks
|
924
|
-
return fargs_str, sig_help if caller_locations.any? {|frame| frame.label =~ /\bshow_block_signature\z/ }
|
925
|
-
|
926
|
-
optional = false
|
927
|
-
blks = []
|
928
|
-
@blk_ty.each_child_global do |ty|
|
929
|
-
if ty.is_a?(Type::Proc)
|
930
|
-
blks << ty
|
931
|
-
else
|
932
|
-
# XXX: how should we handle types other than Type.nil
|
933
|
-
optional = true
|
934
|
-
end
|
935
|
-
end
|
936
|
-
if blks != []
|
937
|
-
fargs_str << " " if fargs_str != ""
|
938
|
-
fargs_str << "?" if optional
|
939
|
-
fargs_str << scratch.show_block_signature(blks)
|
940
|
-
end
|
941
|
-
|
942
|
-
return fargs_str, sig_help
|
943
|
-
end
|
944
|
-
end
|
945
|
-
|
946
|
-
class MethodSignature < Signature
|
947
|
-
def initialize(lead_tys, opt_tys, rest_ty, post_tys, kw_tys, kw_rest_ty, blk_ty)
|
948
|
-
@lead_tys = lead_tys
|
949
|
-
@opt_tys = opt_tys
|
950
|
-
raise unless opt_tys.is_a?(Array)
|
951
|
-
@rest_ty = rest_ty
|
952
|
-
@post_tys = post_tys
|
953
|
-
raise unless post_tys
|
954
|
-
@kw_tys = kw_tys
|
955
|
-
kw_tys.each {|a| raise if a.size != 3 } if kw_tys
|
956
|
-
@kw_rest_ty = kw_rest_ty
|
957
|
-
kw_rest_ty&.each_child_global do |ty|
|
958
|
-
raise ty.inspect if ty != Type.any && !ty.is_a?(Type::Hash)
|
959
|
-
end
|
960
|
-
@blk_ty = blk_ty
|
961
|
-
end
|
962
|
-
|
963
|
-
def include_untyped?(scratch)
|
964
|
-
return true if @lead_tys.any? {|ty| ty.include_untyped?(scratch) }
|
965
|
-
return true if @opt_tys.any? {|ty| ty.include_untyped?(scratch) }
|
966
|
-
return true if @rest_ty&.include_untyped?(scratch)
|
967
|
-
return true if @post_tys.any? {|ty| ty.include_untyped?(scratch) }
|
968
|
-
return true if @kw_tys&.any? {|_, _, ty| ty.include_untyped?(scratch) }
|
969
|
-
return true if @kw_rest_ty&.include_untyped?(scratch)
|
970
|
-
return true if @blk_ty&.include_untyped?(scratch)
|
971
|
-
false
|
972
|
-
end
|
973
|
-
|
974
|
-
attr_reader :lead_tys, :opt_tys, :rest_ty, :post_tys, :kw_tys, :kw_rest_ty, :blk_ty
|
975
|
-
|
976
|
-
def substitute(subst, depth)
|
977
|
-
lead_tys = @lead_tys.map {|ty| ty.substitute(subst, depth - 1) }
|
978
|
-
opt_tys = @opt_tys.map {|ty| ty.substitute(subst, depth - 1) }
|
979
|
-
rest_ty = @rest_ty&.substitute(subst, depth - 1)
|
980
|
-
post_tys = @post_tys.map {|ty| ty.substitute(subst, depth - 1) }
|
981
|
-
kw_tys = @kw_tys.map {|req, key, ty| [req, key, ty.substitute(subst, depth - 1)] }
|
982
|
-
kw_rest_ty = @kw_rest_ty&.substitute(subst, depth - 1)
|
983
|
-
blk_ty = @blk_ty.substitute(subst, depth - 1)
|
984
|
-
MethodSignature.new(lead_tys, opt_tys, rest_ty, post_tys, kw_tys, kw_rest_ty, blk_ty)
|
985
|
-
end
|
986
|
-
|
987
|
-
def merge_as_block_arguments(other)
|
988
|
-
lead_tys1, opt_tys1, rest_ty1, post_tys1 = @lead_tys, @opt_tys, @rest_ty, @post_tys
|
989
|
-
lead_tys2, opt_tys2, rest_ty2, post_tys2 = other.lead_tys, other.opt_tys, other.rest_ty, other.post_tys
|
990
|
-
|
991
|
-
case
|
992
|
-
when lead_tys1.size > lead_tys2.size
|
993
|
-
n = lead_tys2.size
|
994
|
-
lead_tys1, opt_tys1 = lead_tys1[0, n], lead_tys1[n..] + opt_tys1
|
995
|
-
when lead_tys1.size < lead_tys2.size
|
996
|
-
n = lead_tys1.size
|
997
|
-
lead_tys2, opt_tys2 = lead_tys2[0, n], lead_tys2[n..] + opt_tys2
|
998
|
-
end
|
999
|
-
case
|
1000
|
-
when post_tys1.size > post_tys2.size
|
1001
|
-
i = post_tys1.size - post_tys2.size
|
1002
|
-
if rest_ty1
|
1003
|
-
rest_ty1 = post_tys[0, i].inject(rest_ty1) {|ty1, ty2| ty1.union(ty2) }
|
1004
|
-
post_tys1 = post_tys1[i..]
|
1005
|
-
else
|
1006
|
-
opt_tys1, post_tys1 = opt_tys1 + post_tys1[0, i], post_tys1[i..]
|
1007
|
-
end
|
1008
|
-
when post_tys1.size < post_tys2.size
|
1009
|
-
i = post_tys2.size - post_tys1.size
|
1010
|
-
if rest_ty2
|
1011
|
-
rest_ty2 = post_tys[0, i].inject(rest_ty2) {|ty1, ty2| ty1.union(ty2) }
|
1012
|
-
post_tys2 = post_tys2[i..]
|
1013
|
-
else
|
1014
|
-
opt_tys2, post_tys2 = opt_tys2 + post_tys2[0, i], post_tys2[i..]
|
1015
|
-
end
|
1016
|
-
end
|
1017
|
-
|
1018
|
-
# XXX: tweak keywords too
|
1019
|
-
|
1020
|
-
msig1 = MethodSignature.new(lead_tys1, opt_tys1, rest_ty1, post_tys1, @kw_tys, @kw_rest_ty, @blk_ty)
|
1021
|
-
msig2 = MethodSignature.new(lead_tys2, opt_tys2, rest_ty2, post_tys2, other.kw_tys, other.kw_rest_ty, other.blk_ty)
|
1022
|
-
msig1.merge(msig2)
|
1023
|
-
end
|
1024
|
-
|
1025
|
-
def merge(other)
|
1026
|
-
raise if @lead_tys.size != other.lead_tys.size
|
1027
|
-
raise if @post_tys.size != other.post_tys.size
|
1028
|
-
if @kw_tys && other.kw_tys
|
1029
|
-
kws1 = {}
|
1030
|
-
@kw_tys.each {|req, kw, _| kws1[kw] = req }
|
1031
|
-
kws2 = {}
|
1032
|
-
other.kw_tys.each {|req, kw, _| kws2[kw] = req }
|
1033
|
-
(kws1.keys & kws2.keys).each do |kw|
|
1034
|
-
raise if !!kws1[kw] != !!kws2[kw]
|
1035
|
-
end
|
1036
|
-
elsif @kw_tys || other.kw_tys
|
1037
|
-
(@kw_tys || other.kw_tys).each do |req,|
|
1038
|
-
raise if req
|
1039
|
-
end
|
1040
|
-
end
|
1041
|
-
lead_tys = @lead_tys.zip(other.lead_tys).map {|ty1, ty2| ty1.union(ty2) }
|
1042
|
-
if @opt_tys || other.opt_tys
|
1043
|
-
opt_tys = []
|
1044
|
-
[@opt_tys.size, other.opt_tys.size].max.times do |i|
|
1045
|
-
ty1 = @opt_tys[i]
|
1046
|
-
ty2 = other.opt_tys[i]
|
1047
|
-
ty = ty1 ? ty2 ? ty1.union(ty2) : ty1 : ty2
|
1048
|
-
opt_tys << ty
|
1049
|
-
end
|
1050
|
-
end
|
1051
|
-
if @rest_ty || other.rest_ty
|
1052
|
-
if @rest_ty && other.rest_ty
|
1053
|
-
rest_ty = @rest_ty.union(other.rest_ty)
|
1054
|
-
else
|
1055
|
-
rest_ty = @rest_ty || other.rest_ty
|
1056
|
-
end
|
1057
|
-
end
|
1058
|
-
post_tys = @post_tys.zip(other.post_tys).map {|ty1, ty2| ty1.union(ty2) }
|
1059
|
-
if @kw_tys && other.kw_tys
|
1060
|
-
kws1 = {}
|
1061
|
-
@kw_tys.each {|req, kw, ty| kws1[kw] = [req, ty] }
|
1062
|
-
kws2 = {}
|
1063
|
-
other.kw_tys.each {|req, kw, ty| kws2[kw] = [req, ty] }
|
1064
|
-
kw_tys = (kws1.keys | kws2.keys).map do |kw|
|
1065
|
-
req1, ty1 = kws1[kw]
|
1066
|
-
_req2, ty2 = kws2[kw]
|
1067
|
-
ty1 ||= Type.bot
|
1068
|
-
ty2 ||= Type.bot
|
1069
|
-
[!!req1, kw, ty1.union(ty2)]
|
1070
|
-
end
|
1071
|
-
elsif @kw_tys || other.kw_tys
|
1072
|
-
kw_tys = @kw_tys || other.kw_tys
|
1073
|
-
else
|
1074
|
-
kw_tys = nil
|
1075
|
-
end
|
1076
|
-
if @kw_rest_ty || other.kw_rest_ty
|
1077
|
-
if @kw_rest_ty && other.kw_rest_ty
|
1078
|
-
kw_rest_ty = @kw_rest_ty.union(other.kw_rest_ty)
|
1079
|
-
else
|
1080
|
-
kw_rest_ty = @kw_rest_ty || other.kw_rest_ty
|
1081
|
-
end
|
1082
|
-
end
|
1083
|
-
blk_ty = @blk_ty.union(other.blk_ty) if @blk_ty
|
1084
|
-
MethodSignature.new(lead_tys, opt_tys, rest_ty, post_tys, kw_tys, kw_rest_ty, blk_ty)
|
1085
|
-
end
|
1086
|
-
end
|
1087
|
-
|
1088
|
-
class BlockSignature < Signature
|
1089
|
-
def initialize(lead_tys, opt_tys, rest_ty, blk_ty)
|
1090
|
-
@lead_tys = lead_tys
|
1091
|
-
@opt_tys = opt_tys
|
1092
|
-
@rest_ty = rest_ty
|
1093
|
-
@blk_ty = blk_ty
|
1094
|
-
# TODO: kw_tys
|
1095
|
-
end
|
1096
|
-
|
1097
|
-
attr_reader :lead_tys, :opt_tys, :rest_ty, :blk_ty
|
1098
|
-
|
1099
|
-
def merge(bsig)
|
1100
|
-
if @rest_ty && bsig.rest_ty
|
1101
|
-
rest_ty = @rest_ty.union(bsig.rest_ty)
|
1102
|
-
BlockSignature.new(@lead_tys, [], rest_ty, @blk_ty.union(bsig.blk_ty))
|
1103
|
-
elsif @rest_ty || bsig.rest_ty
|
1104
|
-
rest_ty = @rest_ty || bsig.rest_ty
|
1105
|
-
rest_ty = @opt_tys.inject(rest_ty, &:union)
|
1106
|
-
rest_ty = bsig.opt_tys.inject(rest_ty, &:union)
|
1107
|
-
|
1108
|
-
lead_tys = []
|
1109
|
-
[@lead_tys.size, bsig.lead_tys.size].max.times do |i|
|
1110
|
-
ty1 = @lead_tys[i]
|
1111
|
-
ty2 = bsig.lead_tys[i]
|
1112
|
-
if ty1 && ty2
|
1113
|
-
lead_tys << ty1.union(ty2)
|
1114
|
-
else
|
1115
|
-
rest_ty = rest_ty.union(ty1 || ty2)
|
1116
|
-
end
|
1117
|
-
end
|
1118
|
-
|
1119
|
-
BlockSignature.new(lead_tys, [], rest_ty, @blk_ty.union(bsig.blk_ty))
|
1120
|
-
else
|
1121
|
-
lead_tys = []
|
1122
|
-
n = [@lead_tys.size, bsig.lead_tys.size].min
|
1123
|
-
n.times do |i|
|
1124
|
-
lead_tys << @lead_tys[i].union(bsig.lead_tys[i])
|
1125
|
-
end
|
1126
|
-
opt_tys1 = @lead_tys[n..] + @opt_tys
|
1127
|
-
opt_tys2 = bsig.lead_tys[n..] + bsig.opt_tys
|
1128
|
-
opt_tys = []
|
1129
|
-
[opt_tys1.size, opt_tys2.size].max.times do |i|
|
1130
|
-
if opt_tys1[i] && opt_tys2[i]
|
1131
|
-
opt_tys << opt_tys1[i].union(opt_tys2[i])
|
1132
|
-
else
|
1133
|
-
opt_tys << (opt_tys1[i] || opt_tys2[i])
|
1134
|
-
end
|
1135
|
-
end
|
1136
|
-
BlockSignature.new(lead_tys, opt_tys, nil, @blk_ty.union(bsig.blk_ty))
|
1137
|
-
end
|
1138
|
-
end
|
1139
|
-
end
|
1140
|
-
end
|