typeprof 0.21.11 → 0.30.0

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 (73) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +15 -31
  3. data/bin/typeprof +5 -0
  4. data/doc/doc.ja.md +134 -0
  5. data/doc/doc.md +136 -0
  6. data/lib/typeprof/cli/cli.rb +180 -0
  7. data/lib/typeprof/cli.rb +2 -133
  8. data/lib/typeprof/code_range.rb +112 -0
  9. data/lib/typeprof/core/ast/base.rb +263 -0
  10. data/lib/typeprof/core/ast/call.rb +251 -0
  11. data/lib/typeprof/core/ast/const.rb +126 -0
  12. data/lib/typeprof/core/ast/control.rb +432 -0
  13. data/lib/typeprof/core/ast/meta.rb +150 -0
  14. data/lib/typeprof/core/ast/method.rb +335 -0
  15. data/lib/typeprof/core/ast/misc.rb +263 -0
  16. data/lib/typeprof/core/ast/module.rb +123 -0
  17. data/lib/typeprof/core/ast/pattern.rb +140 -0
  18. data/lib/typeprof/core/ast/sig_decl.rb +471 -0
  19. data/lib/typeprof/core/ast/sig_type.rb +663 -0
  20. data/lib/typeprof/core/ast/value.rb +319 -0
  21. data/lib/typeprof/core/ast/variable.rb +315 -0
  22. data/lib/typeprof/core/ast.rb +472 -0
  23. data/lib/typeprof/core/builtin.rb +146 -0
  24. data/lib/typeprof/core/env/method.rb +137 -0
  25. data/lib/typeprof/core/env/method_entity.rb +55 -0
  26. data/lib/typeprof/core/env/module_entity.rb +408 -0
  27. data/lib/typeprof/core/env/static_read.rb +155 -0
  28. data/lib/typeprof/core/env/type_alias_entity.rb +27 -0
  29. data/lib/typeprof/core/env/value_entity.rb +32 -0
  30. data/lib/typeprof/core/env.rb +360 -0
  31. data/lib/typeprof/core/graph/box.rb +991 -0
  32. data/lib/typeprof/core/graph/change_set.rb +224 -0
  33. data/lib/typeprof/core/graph/filter.rb +155 -0
  34. data/lib/typeprof/core/graph/vertex.rb +222 -0
  35. data/lib/typeprof/core/graph.rb +3 -0
  36. data/lib/typeprof/core/service.rb +522 -0
  37. data/lib/typeprof/core/type.rb +348 -0
  38. data/lib/typeprof/core/util.rb +81 -0
  39. data/lib/typeprof/core.rb +32 -0
  40. data/lib/typeprof/diagnostic.rb +35 -0
  41. data/lib/typeprof/lsp/messages.rb +430 -0
  42. data/lib/typeprof/lsp/server.rb +177 -0
  43. data/lib/typeprof/lsp/text.rb +69 -0
  44. data/lib/typeprof/lsp/util.rb +61 -0
  45. data/lib/typeprof/lsp.rb +4 -907
  46. data/lib/typeprof/version.rb +1 -1
  47. data/lib/typeprof.rb +4 -18
  48. data/typeprof.gemspec +5 -7
  49. metadata +48 -35
  50. data/.github/dependabot.yml +0 -6
  51. data/.github/workflows/main.yml +0 -39
  52. data/.gitignore +0 -9
  53. data/Gemfile +0 -17
  54. data/Gemfile.lock +0 -41
  55. data/Rakefile +0 -10
  56. data/exe/typeprof +0 -10
  57. data/lib/typeprof/analyzer.rb +0 -2598
  58. data/lib/typeprof/arguments.rb +0 -414
  59. data/lib/typeprof/block.rb +0 -176
  60. data/lib/typeprof/builtin.rb +0 -893
  61. data/lib/typeprof/code-range.rb +0 -177
  62. data/lib/typeprof/config.rb +0 -158
  63. data/lib/typeprof/container-type.rb +0 -912
  64. data/lib/typeprof/export.rb +0 -589
  65. data/lib/typeprof/import.rb +0 -852
  66. data/lib/typeprof/insns-def.rb +0 -65
  67. data/lib/typeprof/iseq.rb +0 -864
  68. data/lib/typeprof/method.rb +0 -355
  69. data/lib/typeprof/type.rb +0 -1140
  70. data/lib/typeprof/utils.rb +0 -212
  71. data/tools/coverage.rb +0 -14
  72. data/tools/setup-insns-def.rb +0 -30
  73. data/typeprof-lsp +0 -3
@@ -1,912 +0,0 @@
1
- module TypeProf
2
- class AllocationSite
3
- include Utils::StructuralEquality
4
-
5
- def initialize(val, parent = nil)
6
- raise if !val.is_a?(Utils::StructuralEquality) && !val.is_a?(Integer) && !val.is_a?(Symbol)
7
- @val = val
8
- @parent = parent
9
- end
10
-
11
- attr_reader :val, :parent
12
-
13
- def add_id(val)
14
- AllocationSite.new(val, self)
15
- end
16
- end
17
-
18
- class Type # or AbstractValue
19
- # Cell, Array, and Hash are types for global interface, e.g., TypedISeq.
20
- # Do not push such types to local environment, stack, etc.
21
-
22
- class ContainerType < Type
23
- def match?(other)
24
- return nil if self.class != other.class
25
- return nil unless @base_type.consistent?(other.base_type)
26
- @elems.match?(other.elems)
27
- end
28
-
29
- def each_free_type_variable(&blk)
30
- @elems.each_free_type_variable(&blk)
31
- end
32
-
33
- def consistent?(other)
34
- raise "must not be used"
35
- end
36
-
37
- def self.create_empty_instance(klass)
38
- base_type = Type::Instance.new(klass)
39
- case klass
40
- when Type::Builtin[:ary] # XXX: check inheritance...
41
- Type::Array.new(Type::Array::Elements.new([], Type.bot), base_type)
42
- when Type::Builtin[:hash]
43
- Type.gen_hash(base_type) {|h| }
44
- else
45
- Type::Cell.new(Type::Cell::Elements.new([Type.bot] * klass.type_params.size), base_type)
46
- end
47
- end
48
-
49
- def include_untyped?(scratch)
50
- return true if @base_type.include_untyped?(scratch)
51
- return true if @elems.include_untyped?(scratch)
52
- false
53
- end
54
- end
55
-
56
- # The most basic container type for default type parameter class
57
- class Cell < ContainerType
58
- def initialize(elems, base_type)
59
- raise if !elems.is_a?(Cell::Elements)
60
- @elems = elems # Cell::Elements
61
- raise unless base_type
62
- @base_type = base_type
63
- if base_type.klass.type_params.size != elems.elems.size
64
- raise
65
- end
66
- end
67
-
68
- attr_reader :elems, :base_type
69
-
70
- def inspect
71
- "Type::Cell[#{ @elems.inspect }, base_type: #{ @base_type.inspect }]"
72
- end
73
-
74
- def screen_name(scratch)
75
- str = @elems.screen_name(scratch)
76
- if str.start_with?("*")
77
- str = @base_type.screen_name(scratch) + str[1..]
78
- end
79
- str
80
- end
81
-
82
- def localize(env, alloc_site, depth)
83
- return env, Type.any if depth <= 0
84
- alloc_site = alloc_site.add_id(:cell).add_id(@base_type)
85
- env, elems = @elems.localize(env, alloc_site, depth)
86
- ty = Local.new(Cell, alloc_site, @base_type)
87
- env = env.deploy_type(alloc_site, elems)
88
- return env, ty
89
- end
90
-
91
- def limit_size(limit)
92
- return Type.any if limit <= 0
93
- Cell.new(@elems.limit_size(limit - 1), @base_type)
94
- end
95
-
96
- def method_dispatch_info
97
- raise
98
- end
99
-
100
- def substitute(subst, depth)
101
- return Type.any if depth <= 0
102
- elems = @elems.substitute(subst, depth)
103
- Cell.new(elems, @base_type)
104
- end
105
-
106
- def generate_substitution
107
- subst = {}
108
- tyvars = @base_type.klass.type_params.map {|name,| Type::Var.new(name) }
109
- tyvars.zip(@elems.elems) do |tyvar, elem|
110
- if subst[tyvar]
111
- subst[tyvar] = subst[tyvar].union(elem)
112
- else
113
- subst[tyvar] = elem
114
- end
115
- end
116
- subst
117
- end
118
-
119
- class Elements # Cell
120
- include Utils::StructuralEquality
121
-
122
- def initialize(elems)
123
- @elems = elems
124
- end
125
-
126
- def self.dummy_elements
127
- Elements.new([]) # XXX
128
- end
129
-
130
- attr_reader :elems
131
-
132
- def to_local_type(id, base_ty)
133
- Type::Local.new(Cell, id, base_ty)
134
- end
135
-
136
- def globalize(env, visited, depth)
137
- Elements.new(@elems.map {|ty| ty.globalize(env, visited, depth) })
138
- end
139
-
140
- def localize(env, alloc_site, depth)
141
- elems = @elems.map.with_index do |ty, i|
142
- alloc_site2 = alloc_site.add_id(i)
143
- env, ty = ty.localize(env, alloc_site2, depth)
144
- ty
145
- end
146
- return env, Elements.new(elems)
147
- end
148
-
149
- def limit_size(limit)
150
- Elements.new(@elems.map {|ty| ty.limit_size(limit) })
151
- end
152
-
153
- def screen_name(scratch)
154
- "*[#{ @elems.map {|ty| ty.screen_name(scratch) }.join(", ") }]"
155
- end
156
-
157
- def pretty_print(q)
158
- q.group(9, "Elements[", "]") do
159
- q.seplist(@elems) do |elem|
160
- q.pp elem
161
- end
162
- end
163
- end
164
-
165
- def match?(other)
166
- return nil if @elems.size != other.elems.size
167
- subst = nil
168
- @elems.zip(other.elems) do |ty0, ty1|
169
- subst2 = Type.match?(ty0, ty1)
170
- return nil unless subst2
171
- subst = Type.merge_substitution(subst, subst2)
172
- end
173
- subst
174
- end
175
-
176
- def each_free_type_variable(&blk)
177
- @elems.each do |ty|
178
- ty.each_free_type_variable(&blk)
179
- end
180
- end
181
-
182
- def substitute(subst, depth)
183
- Elements.new(@elems.map {|ty| ty.substitute(subst, depth) })
184
- end
185
-
186
- def [](idx)
187
- @elems[idx]
188
- end
189
-
190
- def update(idx, ty)
191
- Elements.new(Utils.array_update(@elems, idx, @elems[idx].union(ty)))
192
- end
193
-
194
- def union(other)
195
- return self if self == other
196
- if @elems.size != other.elems.size
197
- raise "#{ @elems.size } != #{ other.elems.size }"
198
- end
199
- elems = []
200
- @elems.zip(other.elems) do |ty0, ty1|
201
- elems << ty0.union(ty1)
202
- end
203
- Elements.new(elems)
204
- end
205
-
206
- def include_untyped?(scratch)
207
- return @elems.any? {|ty| ty.include_untyped?(scratch) }
208
- end
209
- end
210
- end
211
-
212
- # Do not insert Array type to local environment, stack, etc.
213
- class Array < ContainerType
214
- def initialize(elems, base_type)
215
- raise unless elems.is_a?(Array::Elements)
216
- @elems = elems # Array::Elements
217
- raise unless base_type
218
- @base_type = base_type
219
- end
220
-
221
- attr_reader :elems, :base_type
222
-
223
- def inspect
224
- "Type::Array[#{ @elems.inspect }, base_type: #{ @base_type.inspect }]"
225
- #@base_type.inspect
226
- end
227
-
228
- def screen_name(scratch)
229
- str = @elems.screen_name(scratch)
230
- if str =~ /\A\*\[(.*)\]\z/
231
- str = @base_type.klass.type_params.map {|var_name,| var_name == :Elem ? $1 : "untyped" }.join(", ")
232
- str = "#{ @base_type.screen_name(scratch) }[#{ str }]"
233
- end
234
- str
235
- end
236
-
237
- def localize(env, alloc_site, depth)
238
- return env, Type.any if depth <= 0
239
- alloc_site = alloc_site.add_id(:ary).add_id(@base_type)
240
- env, elems = @elems.localize(env, alloc_site, depth - 1)
241
- ty = Local.new(Array, alloc_site, @base_type)
242
- env = env.deploy_type(alloc_site, elems)
243
- return env, ty
244
- end
245
-
246
- def limit_size(limit)
247
- return Type.any if limit <= 0
248
- Array.new(@elems.limit_size(limit - 1), @base_type)
249
- end
250
-
251
- def method_dispatch_info
252
- raise
253
- end
254
-
255
- def substitute(subst, depth)
256
- return Type.any if depth <= 0
257
- elems = @elems.substitute(subst, depth - 1)
258
- Array.new(elems, @base_type)
259
- end
260
-
261
- def generate_substitution
262
- { Type::Var.new(:Elem) => @elems.squash }
263
- end
264
-
265
- class Elements # Array
266
- include Utils::StructuralEquality
267
-
268
- def initialize(lead_tys, rest_ty = Type.bot)
269
- raise unless lead_tys.all? {|ty| ty.is_a?(Type) }
270
- raise unless rest_ty.is_a?(Type)
271
- @lead_tys, @rest_ty = lead_tys, rest_ty
272
- end
273
-
274
- def self.dummy_elements
275
- Elements.new([], Type.any)
276
- end
277
-
278
- attr_reader :lead_tys, :rest_ty
279
-
280
- def to_local_type(id, base_ty)
281
- Type::Local.new(Array, id, base_ty)
282
- end
283
-
284
- def globalize(env, visited, depth)
285
- lead_tys = []
286
- @lead_tys.each do |ty|
287
- lead_tys << ty.globalize(env, visited, depth)
288
- end
289
- rest_ty = @rest_ty&.globalize(env, visited, depth)
290
- Elements.new(lead_tys, rest_ty)
291
- end
292
-
293
- def localize(env, alloc_site, depth)
294
- lead_tys = @lead_tys.map.with_index do |ty, i|
295
- alloc_site2 = alloc_site.add_id(i)
296
- env, ty = ty.localize(env, alloc_site2, depth)
297
- ty
298
- end
299
- alloc_site_rest = alloc_site.add_id(:rest)
300
- env, rest_ty = @rest_ty.localize(env, alloc_site_rest, depth)
301
- return env, Elements.new(lead_tys, rest_ty)
302
- end
303
-
304
- def limit_size(limit)
305
- Elements.new(@lead_tys.map {|ty| ty.limit_size(limit) }, @rest_ty.limit_size(limit))
306
- end
307
-
308
- def screen_name(scratch)
309
- if @rest_ty == Type.bot
310
- if @lead_tys.empty?
311
- # This is heuristic: in general, an empty array is a wrong guess.
312
- # Note that an empty array is representable as "[ ]" in RBS, but
313
- # users often have to modify it to "Array[something]".
314
- # In this term, "Array[untyped]" is considered more useful than "[ ]".
315
- return "Array[untyped]"
316
- end
317
- s = @lead_tys.map do |ty|
318
- ty.screen_name(scratch)
319
- end
320
- s << "*" + @rest_ty.screen_name(scratch) if @rest_ty != Type.bot
321
- return "[#{ s.join(", ") }]"
322
- end
323
-
324
- "*[#{ squash.screen_name(scratch) }]"
325
- rescue SystemStackError
326
- p squash
327
- exit!
328
- end
329
-
330
- def pretty_print(q)
331
- q.group(9, "Elements[", "]") do
332
- q.seplist(@lead_tys + [@rest_ty]) do |elem|
333
- q.pp elem
334
- end
335
- end
336
- end
337
-
338
- def match?(other)
339
- n = [@lead_tys.size, other.lead_tys.size].min
340
- rest_ty1 = @lead_tys[n..].inject(@rest_ty) {|ty1, ty2| ty1.union(ty2) }
341
- rest_ty2 = other.lead_tys[n..].inject(other.rest_ty) {|ty1, ty2| ty1.union(ty2) }
342
- subst = nil
343
- (@lead_tys[0, n] + [rest_ty1]).zip(other.lead_tys[0, n] + [rest_ty2]) do |ty0, ty1|
344
- subst2 = Type.match?(ty0, ty1)
345
- return nil unless subst2
346
- subst = Type.merge_substitution(subst, subst2)
347
- end
348
- subst
349
- end
350
-
351
- def each_free_type_variable(&blk)
352
- @lead_tys.each do |ty|
353
- ty.each_free_type_variable(&blk)
354
- end
355
- @rest_ty&.each_free_type_variable(&blk)
356
- end
357
-
358
- def substitute(subst, depth)
359
- lead_tys = @lead_tys.map {|ty| ty.substitute(subst, depth) }
360
- rest_ty = @rest_ty.substitute(subst, depth)
361
- Elements.new(lead_tys, rest_ty)
362
- end
363
-
364
- def squash
365
- @lead_tys.inject(@rest_ty) {|ty1, ty2| ty1.union(ty2) } #.union(Type.nil) # is this needed?
366
- end
367
-
368
- def squash_or_any
369
- ty = squash
370
- ty == Type.bot ? Type.any : ty
371
- end
372
-
373
- def [](idx)
374
- if idx.is_a?(Range)
375
- if @rest_ty == Type.bot
376
- lead_tys = @lead_tys[idx]
377
- if lead_tys
378
- rest_ty = Type.bot
379
- else
380
- return Type.nil
381
- end
382
- else
383
- b, e = idx.begin, idx.end
384
- b = 0 if !b
385
- if !e
386
- lead_tys = @lead_tys[idx] || []
387
- rest_ty = @rest_ty
388
- elsif b >= 0
389
- if e >= 0
390
- if b <= e
391
- if e < @lead_tys.size
392
- lead_tys = @lead_tys[idx]
393
- rest_ty = Type.bot
394
- else
395
- lead_tys = @lead_tys[idx] || []
396
- rest_ty = @rest_ty
397
- end
398
- else
399
- return Type.nil
400
- end
401
- else
402
- lead_tys = @lead_tys[idx] || []
403
- e = idx.exclude_end? ? e : e == -1 ? @lead_tys.size : e + 1
404
- rest_ty = (@lead_tys[e + 1..] || []).inject(@rest_ty) {|ty0, ty1| ty0.union(ty1) }
405
- end
406
- else
407
- lead_tys = []
408
- if e >= 0
409
- rest_ty = e < @lead_tys.size ? Type.bot : @rest_ty
410
- range = [0, @lead_tys.size + b].max .. (idx.exclude_end? ? e - 1 : e)
411
- rest_ty = @lead_tys[range].inject(rest_ty) {|ty0, ty1| ty0.union(ty1) }
412
- else
413
- if b <= e
414
- range = [0, @lead_tys.size + b].max .. (idx.exclude_end? ? e - 1 : e)
415
- rest_ty = @lead_tys[range].inject(@rest_ty) {|ty0, ty1| ty0.union(ty1) }
416
- else
417
- return Type.nil
418
- end
419
- end
420
- end
421
- end
422
- base_ty = Type::Instance.new(Type::Builtin[:ary])
423
- Array.new(Elements.new(lead_tys, rest_ty), base_ty)
424
- elsif idx >= 0
425
- if idx < @lead_tys.size
426
- @lead_tys[idx]
427
- elsif @rest_ty == Type.bot
428
- Type.nil
429
- else
430
- @rest_ty
431
- end
432
- else
433
- i = @lead_tys.size + idx
434
- i = [i, 0].max
435
- ty = @rest_ty
436
- @lead_tys[i..].each do |ty2|
437
- ty = ty.union(ty2)
438
- end
439
- ty
440
- end
441
- end
442
-
443
- def update(idx, ty)
444
- if idx
445
- if idx >= 0
446
- if idx < @lead_tys.size
447
- lead_tys = Utils.array_update(@lead_tys, idx, ty)
448
- Elements.new(lead_tys, @rest_ty)
449
- else
450
- rest_ty = @rest_ty.union(ty)
451
- Elements.new(@lead_tys, rest_ty)
452
- end
453
- else
454
- i = @lead_tys.size + idx
455
- if @rest_ty == Type.bot
456
- if i >= 0
457
- lead_tys = Utils.array_update(@lead_tys, i, ty)
458
- Elements.new(lead_tys, Type.bot)
459
- else
460
- # TODO: out of bound? should we emit an error?
461
- Elements.new(@lead_tys, Type.bot)
462
- end
463
- else
464
- i = [i, 0].max
465
- lead_tys = @lead_tys[0, i] + @lead_tys[i..].map {|ty2| ty2.union(ty) }
466
- rest_ty = @rest_ty.union(ty)
467
- Elements.new(@lead_tys, rest_ty)
468
- end
469
- end
470
- else
471
- lead_tys = @lead_tys.map {|ty1| ty1.union(ty) }
472
- rest_ty = @rest_ty.union(ty)
473
- Elements.new(lead_tys, rest_ty)
474
- end
475
- end
476
-
477
- def append(ty)
478
- if @rest_ty == Type.bot
479
- if @lead_tys.size < 5 # XXX: should be configurable, or ...?
480
- lead_tys = @lead_tys + [ty]
481
- Elements.new(lead_tys, @rest_ty)
482
- else
483
- Elements.new(@lead_tys, ty)
484
- end
485
- else
486
- Elements.new(@lead_tys, @rest_ty.union(ty))
487
- end
488
- end
489
-
490
- def union(other)
491
- return self if self == other
492
- raise "Hash::Elements merge Array::Elements" if other.is_a?(Hash::Elements)
493
-
494
- lead_count = [@lead_tys.size, other.lead_tys.size].min
495
- lead_tys = (0...lead_count).map do |i|
496
- @lead_tys[i].union(other.lead_tys[i])
497
- end
498
-
499
- rest_ty = @rest_ty.union(other.rest_ty)
500
- (@lead_tys[lead_count..-1] + other.lead_tys[lead_count..-1]).each do |ty|
501
- rest_ty = rest_ty.union(ty)
502
- end
503
-
504
- Elements.new(lead_tys, rest_ty)
505
- end
506
-
507
- def take_first(num)
508
- base_ty = Type::Instance.new(Type::Builtin[:ary])
509
- if @lead_tys.size >= num
510
- lead_tys = @lead_tys[0, num]
511
- rest_ary_ty = Array.new(Elements.new(@lead_tys[num..-1], @rest_ty), base_ty)
512
- return lead_tys, rest_ary_ty
513
- else
514
- lead_tys = @lead_tys.dup
515
- until lead_tys.size == num
516
- # .union(Type.nil) is needed for `a, b, c = [42]` to assign nil to b and c
517
- lead_tys << @rest_ty.union(Type.nil)
518
- end
519
- rest_ary_ty = Array.new(Elements.new([], @rest_ty), base_ty)
520
- return lead_tys, rest_ary_ty
521
- end
522
- end
523
-
524
- def take_last(num)
525
- base_ty = Type::Instance.new(Type::Builtin[:ary])
526
- if @rest_ty == Type.bot
527
- if @lead_tys.size >= num
528
- following_tys = @lead_tys[-num, num]
529
- rest_ary_ty = Array.new(Elements.new(@lead_tys[0...-num], Type.bot), base_ty)
530
- return rest_ary_ty, following_tys
531
- else
532
- following_tys = @lead_tys[-num, num] || []
533
- until following_tys.size == num
534
- following_tys.unshift(Type.nil)
535
- end
536
- rest_ary_ty = Array.new(Elements.new([], Type.bot), base_ty)
537
- return rest_ary_ty, following_tys
538
- end
539
- else
540
- lead_tys = @lead_tys.dup
541
- last_ty = rest_ty
542
- following_tys = []
543
- until following_tys.size == num
544
- last_ty = last_ty.union(lead_tys.pop) unless lead_tys.empty?
545
- following_tys.unshift(last_ty)
546
- end
547
- rest_ty = lead_tys.inject(last_ty) {|ty1, ty2| ty1.union(ty2) }
548
- rest_ary_ty = Array.new(Elements.new([], rest_ty), base_ty)
549
- return rest_ary_ty, following_tys
550
- end
551
- end
552
-
553
- def include_untyped?(scratch)
554
- return true if @lead_tys.any? {|ty| ty.include_untyped?(scratch) }
555
- return true if @rest_ty.include_untyped?(scratch)
556
- false
557
- end
558
- end
559
- end
560
-
561
- class Hash < ContainerType
562
- def initialize(elems, base_type)
563
- @elems = elems
564
- raise unless elems
565
- @base_type = base_type
566
- end
567
-
568
- attr_reader :elems, :base_type
569
-
570
- def inspect
571
- "Type::Hash#{ @elems.inspect }"
572
- end
573
-
574
- def screen_name(scratch)
575
- @elems.screen_name(scratch)
576
- end
577
-
578
- def localize(env, alloc_site, depth)
579
- return env, Type.any if depth <= 0
580
- alloc_site = alloc_site.add_id(:hash).add_id(@base_type)
581
- env, elems = @elems.localize(env, alloc_site, depth - 1)
582
- ty = Local.new(Hash, alloc_site, @base_type)
583
- env = env.deploy_type(alloc_site, elems)
584
- return env, ty
585
- end
586
-
587
- def limit_size(limit)
588
- return Type.any if limit <= 0
589
- Hash.new(@elems.limit_size(limit - 1), @base_type)
590
- end
591
-
592
- def method_dispatch_info
593
- raise
594
- end
595
-
596
- def substitute(subst, depth)
597
- return Type.any if depth <= 0
598
- elems = @elems.substitute(subst, depth - 1)
599
- Hash.new(elems, @base_type)
600
- end
601
-
602
- def generate_substitution
603
- tyvar_k = Type::Var.new(:K)
604
- tyvar_v = Type::Var.new(:V)
605
- k_ty0, v_ty0 = @elems.squash
606
- # XXX: need to heuristically replace ret type Hash[K, V] with self, instead of conversative type?
607
- { tyvar_k => k_ty0, tyvar_v => v_ty0 }
608
- end
609
-
610
- class Elements # Hash
611
- include Utils::StructuralEquality
612
-
613
- def initialize(map_tys)
614
- map_tys.each do |k_ty, v_ty|
615
- raise unless k_ty.is_a?(Type)
616
- raise unless v_ty.is_a?(Type)
617
- raise if k_ty.is_a?(Type::Union)
618
- raise if k_ty.is_a?(Type::Local)
619
- raise if k_ty.is_a?(Type::Array)
620
- raise if k_ty.is_a?(Type::Hash)
621
- end
622
- @map_tys = map_tys
623
- end
624
-
625
- def self.dummy_elements
626
- Elements.new({Type.any => Type.any})
627
- end
628
-
629
- attr_reader :map_tys
630
-
631
- def to_local_type(id, base_ty)
632
- Type::Local.new(Hash, id, base_ty)
633
- end
634
-
635
- def globalize(env, visited, depth)
636
- map_tys = {}
637
- @map_tys.each do |k_ty, v_ty|
638
- v_ty = v_ty.globalize(env, visited, depth)
639
- if map_tys[k_ty]
640
- map_tys[k_ty] = map_tys[k_ty].union(v_ty)
641
- else
642
- map_tys[k_ty] = v_ty
643
- end
644
- end
645
- Elements.new(map_tys)
646
- end
647
-
648
- def localize(env, alloc_site, depth)
649
- map_tys = @map_tys.to_h do |k_ty, v_ty|
650
- alloc_site2 = alloc_site.add_id(k_ty)
651
- env, v_ty = v_ty.localize(env, alloc_site2, depth)
652
- [k_ty, v_ty]
653
- end
654
- return env, Elements.new(map_tys)
655
- end
656
-
657
- def limit_size(limit)
658
- map_tys = {}
659
- @map_tys.each do |k_ty, v_ty|
660
- k_ty = k_ty.limit_size(limit)
661
- v_ty = v_ty.limit_size(limit)
662
- if map_tys[k_ty]
663
- map_tys[k_ty] = map_tys[k_ty].union(v_ty)
664
- else
665
- map_tys[k_ty] = v_ty
666
- end
667
- end
668
- Elements.new(map_tys)
669
- end
670
-
671
- def screen_name(scratch)
672
- if !@map_tys.empty? && @map_tys.all? {|k_ty,| k_ty.is_a?(Type::Symbol) }
673
- s = @map_tys.map do |k_ty, v_ty|
674
- v = v_ty.screen_name(scratch)
675
- "#{ k_ty.sym }: #{ v }"
676
- end.join(", ")
677
- "{#{ s }}"
678
- else
679
- k_ty = v_ty = Type.bot
680
- @map_tys.each do |k, v|
681
- k_ty = k_ty.union(k)
682
- v_ty = v_ty.union(v)
683
- end
684
- k_ty = Type.any if k_ty == Type.bot
685
- v_ty = Type.any if v_ty == Type.bot
686
- k_ty = k_ty.screen_name(scratch)
687
- v_ty = v_ty.screen_name(scratch)
688
- "Hash[#{ k_ty }, #{ v_ty }]"
689
- end
690
- end
691
-
692
- def pretty_print(q)
693
- q.group(9, "Elements[", "]") do
694
- q.seplist(@map_tys) do |k_ty, v_ty|
695
- q.group do
696
- q.pp k_ty
697
- q.text '=>'
698
- q.group(1) do
699
- q.breakable ''
700
- q.pp v_ty
701
- end
702
- end
703
- end
704
- end
705
- end
706
-
707
- def match?(other)
708
- subst = nil
709
- other.map_tys.each do |k1, v1|
710
- subst2 = nil
711
- @map_tys.each do |k0, v0|
712
- subst3 = Type.match?(k0, k1)
713
- if subst3
714
- subst4 = Type.match?(v0, v1)
715
- if subst4
716
- subst2 = Type.merge_substitution(subst2, subst3)
717
- subst2 = Type.merge_substitution(subst2, subst4)
718
- end
719
- end
720
- end
721
- return nil unless subst2
722
- subst = Type.merge_substitution(subst, subst2)
723
- end
724
- subst
725
- end
726
-
727
- def each_free_type_variable(&blk)
728
- @map_tys.each do |k, v|
729
- k.each_free_type_variable(&blk)
730
- v.each_free_type_variable(&blk)
731
- end
732
- end
733
-
734
- def substitute(subst, depth)
735
- map_tys = {}
736
- @map_tys.each do |k_ty_orig, v_ty_orig|
737
- k_ty = k_ty_orig.substitute(subst, depth)
738
- v_ty = v_ty_orig.substitute(subst, depth)
739
- k_ty.each_child_global do |k_ty|
740
- # This is a temporal hack to mitigate type explosion
741
- k_ty = Type.any if k_ty.is_a?(Type::Array)
742
- k_ty = Type.any if k_ty.is_a?(Type::Hash)
743
- if map_tys[k_ty]
744
- map_tys[k_ty] = map_tys[k_ty].union(v_ty)
745
- else
746
- map_tys[k_ty] = v_ty
747
- end
748
- end
749
- end
750
- Elements.new(map_tys)
751
- end
752
-
753
- def squash
754
- all_k_ty, all_v_ty = Type.bot, Type.bot
755
- @map_tys.each do |k_ty, v_ty|
756
- all_k_ty = all_k_ty.union(k_ty)
757
- all_v_ty = all_v_ty.union(v_ty)
758
- end
759
- return all_k_ty, all_v_ty
760
- end
761
-
762
- def [](key_ty)
763
- val_ty = Type.bot
764
- @map_tys.each do |k_ty, v_ty|
765
- if Type.match?(k_ty, key_ty)
766
- val_ty = val_ty.union(v_ty)
767
- end
768
- end
769
- val_ty
770
- end
771
-
772
- def update(idx, ty)
773
- map_tys = @map_tys.dup
774
- idx.each_child_global do |idx|
775
- # This is a temporal hack to mitigate type explosion
776
- idx = Type.any if idx.is_a?(Type::Array)
777
- idx = Type.any if idx.is_a?(Type::Hash)
778
-
779
- if map_tys[idx]
780
- map_tys[idx] = map_tys[idx].union(ty)
781
- else
782
- map_tys[idx] = ty
783
- end
784
- end
785
- Elements.new(map_tys)
786
- end
787
-
788
- def union(other)
789
- return self if self == other
790
- raise "Array::Elements merge Hash::Elements" if other.is_a?(Array::Elements)
791
-
792
- map_tys = @map_tys.dup
793
- other.map_tys.each do |k_ty, v_ty|
794
- if map_tys[k_ty]
795
- map_tys[k_ty] = map_tys[k_ty].union(v_ty)
796
- else
797
- map_tys[k_ty] = v_ty
798
- end
799
- end
800
-
801
- Elements.new(map_tys)
802
- end
803
-
804
- def to_keywords
805
- kw_tys = {}
806
- @map_tys.each do |key_ty, val_ty|
807
- if key_ty.is_a?(Type::Symbol)
808
- kw_tys[key_ty.sym] = val_ty
809
- else
810
- all_val_ty = Type.bot
811
- @map_tys.each do |_key_ty, val_ty|
812
- all_val_ty = all_val_ty.union(val_ty)
813
- end
814
- return { nil => all_val_ty }
815
- end
816
- end
817
- kw_tys
818
- end
819
-
820
- def include_untyped?(scratch)
821
- @map_tys.each do |key, val|
822
- return true if key.include_untyped?(scratch)
823
- return true if val.include_untyped?(scratch)
824
- end
825
- false
826
- end
827
- end
828
- end
829
-
830
- class Local < ContainerType
831
- def initialize(kind, id, base_type)
832
- @kind = kind
833
- raise if @kind != Cell && @kind != Array && @kind != Hash
834
- @id = id
835
- raise unless base_type
836
- @base_type = base_type
837
- end
838
-
839
- attr_reader :kind, :id, :base_type
840
-
841
- def inspect
842
- "Type::Local[#{ @kind }, #{ @id }, base_type: #{ @base_type.inspect }]"
843
- end
844
-
845
- def screen_name(scratch)
846
- #raise "Local type must not be included in signature"
847
- "Local[#{ @kind }]"
848
- end
849
-
850
- def globalize(env, visited, depth)
851
- if visited[self] || depth <= 0
852
- Type.any
853
- else
854
- visited[self] = true
855
- elems = env.get_container_elem_types(@id)
856
- if elems
857
- elems = elems.globalize(env, visited, depth - 1)
858
- else
859
- # TODO: currently out-of-scope array cannot be accessed
860
- elems = @kind::Elements.dummy_elements
861
- end
862
- visited.delete(self)
863
- @kind.new(elems, @base_type)
864
- end
865
- end
866
-
867
- def method_dispatch_info
868
- @base_type.method_dispatch_info
869
- end
870
-
871
- def update_container_elem_type(subst, env, caller_ep, scratch)
872
- case
873
- when @kind == Cell
874
- tyvars = @base_type.klass.type_params.map {|name,| Type::Var.new(name) }
875
- # XXX: This should be skipped when the called methods belongs to superclass
876
- tyvars.each_with_index do |tyvar, idx|
877
- ty = subst[tyvar]
878
- if ty
879
- env, ty = scratch.localize_type(ty, env, caller_ep)
880
- env = scratch.update_container_elem_types(env, caller_ep, @id, @base_type) do |elems|
881
- elems.update(idx, ty)
882
- end
883
- end
884
- end
885
- when @kind == Array
886
- tyvar_elem = Type::Var.new(:Elem)
887
- if subst[tyvar_elem]
888
- ty = subst[tyvar_elem]
889
- env, ty = scratch.localize_type(ty, env, caller_ep)
890
- env = scratch.update_container_elem_types(env, caller_ep, @id, @base_type) do |elems|
891
- elems.update(nil, ty)
892
- end
893
- end
894
- when @kind == Hash
895
- tyvar_k = Type::Var.new(:K)
896
- tyvar_v = Type::Var.new(:V)
897
- if subst[tyvar_k] && subst[tyvar_v]
898
- k_ty = subst[tyvar_k]
899
- v_ty = subst[tyvar_v]
900
- alloc_site = AllocationSite.new(caller_ep)
901
- env, k_ty = scratch.localize_type(k_ty, env, caller_ep, alloc_site.add_id(:k))
902
- env, v_ty = scratch.localize_type(v_ty, env, caller_ep, alloc_site.add_id(:v))
903
- env = scratch.update_container_elem_types(env, caller_ep, @id, @base_type) do |elems|
904
- elems.update(k_ty, v_ty)
905
- end
906
- end
907
- end
908
- env
909
- end
910
- end
911
- end
912
- end