typeprof 0.2.0 → 0.5.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 (120) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/main.yml +1 -2
  3. data/.gitignore +1 -0
  4. data/Gemfile +2 -2
  5. data/Gemfile.lock +10 -21
  6. data/LICENSE +21 -0
  7. data/README.md +6 -0
  8. data/doc/demo.md +398 -0
  9. data/doc/doc.ja.md +6 -1
  10. data/doc/doc.md +7 -2
  11. data/exe/typeprof +2 -1
  12. data/lib/typeprof.rb +9 -0
  13. data/lib/typeprof/analyzer.rb +427 -325
  14. data/lib/typeprof/arguments.rb +405 -0
  15. data/lib/typeprof/block.rb +136 -0
  16. data/lib/typeprof/builtin.rb +36 -25
  17. data/lib/typeprof/cli.rb +51 -98
  18. data/lib/typeprof/config.rb +114 -0
  19. data/lib/typeprof/container-type.rb +280 -92
  20. data/lib/typeprof/export.rb +197 -108
  21. data/lib/typeprof/import.rb +134 -80
  22. data/lib/typeprof/iseq.rb +42 -1
  23. data/lib/typeprof/method.rb +178 -82
  24. data/lib/typeprof/type.rb +228 -369
  25. data/lib/typeprof/utils.rb +4 -18
  26. data/lib/typeprof/version.rb +3 -0
  27. data/smoke/arguments2.rb +55 -0
  28. data/smoke/array-each3.rb +1 -4
  29. data/smoke/array12.rb +1 -1
  30. data/smoke/array6.rb +1 -0
  31. data/smoke/block-ambiguous.rb +36 -0
  32. data/smoke/block-args1-rest.rb +62 -0
  33. data/smoke/block-args1.rb +59 -0
  34. data/smoke/block-args2-rest.rb +62 -0
  35. data/smoke/block-args2.rb +59 -0
  36. data/smoke/block-args3-rest.rb +73 -0
  37. data/smoke/block-args3.rb +70 -0
  38. data/smoke/block-blockarg.rb +27 -0
  39. data/smoke/block-kwarg.rb +52 -0
  40. data/smoke/block10.rb +1 -1
  41. data/smoke/block11.rb +1 -1
  42. data/smoke/block14.rb +17 -0
  43. data/smoke/block4.rb +2 -2
  44. data/smoke/block5.rb +1 -0
  45. data/smoke/block6.rb +1 -1
  46. data/smoke/block7.rb +0 -2
  47. data/smoke/block8.rb +2 -2
  48. data/smoke/block9.rb +1 -1
  49. data/smoke/blown.rb +1 -1
  50. data/smoke/class-hierarchy.rb +54 -0
  51. data/smoke/class-hierarchy2.rb +27 -0
  52. data/smoke/constant1.rb +11 -6
  53. data/smoke/constant2.rb +2 -0
  54. data/smoke/cvar.rb +1 -0
  55. data/smoke/demo10.rb +1 -1
  56. data/smoke/demo8.rb +2 -2
  57. data/smoke/demo9.rb +1 -3
  58. data/smoke/flow7.rb +1 -7
  59. data/smoke/flow8.rb +13 -0
  60. data/smoke/hash-fetch.rb +3 -3
  61. data/smoke/hash-merge-bang.rb +11 -0
  62. data/smoke/hash1.rb +1 -1
  63. data/smoke/hash3.rb +1 -1
  64. data/smoke/hash4.rb +1 -1
  65. data/smoke/instance_eval.rb +1 -1
  66. data/smoke/int_times.rb +1 -1
  67. data/smoke/ivar2.rb +1 -1
  68. data/smoke/keyword3.rb +1 -2
  69. data/smoke/keyword4.rb +1 -1
  70. data/smoke/kwsplat1.rb +1 -1
  71. data/smoke/kwsplat2.rb +1 -1
  72. data/smoke/module4.rb +2 -0
  73. data/smoke/multiple-superclass.rb +4 -0
  74. data/smoke/next2.rb +1 -1
  75. data/smoke/optional1.rb +1 -1
  76. data/smoke/optional2.rb +1 -1
  77. data/smoke/optional3.rb +10 -0
  78. data/smoke/pattern-match1.rb +23 -0
  79. data/smoke/pattern-match2.rb +15 -0
  80. data/smoke/proc4.rb +1 -1
  81. data/smoke/rbs-extend.rb +9 -0
  82. data/smoke/rbs-extend.rbs +7 -0
  83. data/smoke/rbs-interface.rb +24 -0
  84. data/smoke/rbs-interface.rbs +12 -0
  85. data/smoke/rbs-proc1.rb +9 -0
  86. data/smoke/rbs-proc1.rbs +3 -0
  87. data/smoke/rbs-proc2.rb +20 -0
  88. data/smoke/rbs-proc2.rbs +3 -0
  89. data/smoke/rbs-proc3.rb +13 -0
  90. data/smoke/rbs-proc3.rbs +4 -0
  91. data/smoke/rbs-record.rb +17 -0
  92. data/smoke/rbs-record.rbs +4 -0
  93. data/smoke/rbs-tyvar.rb +18 -0
  94. data/smoke/rbs-tyvar.rbs +5 -0
  95. data/smoke/rbs-tyvar2.rb +20 -0
  96. data/smoke/rbs-tyvar2.rbs +9 -0
  97. data/smoke/rbs-tyvar3.rb +17 -0
  98. data/smoke/rbs-tyvar3.rbs +5 -0
  99. data/smoke/rbs-tyvar4.rb +36 -0
  100. data/smoke/rbs-tyvar5.rb +12 -0
  101. data/smoke/rbs-tyvar5.rbs +8 -0
  102. data/smoke/rest1.rb +1 -1
  103. data/smoke/rest2.rb +1 -1
  104. data/smoke/rest3.rb +1 -1
  105. data/smoke/rest5.rb +1 -1
  106. data/smoke/rest6.rb +1 -1
  107. data/smoke/retry1.rb +1 -1
  108. data/smoke/return.rb +1 -1
  109. data/smoke/singleton_method.rb +3 -0
  110. data/smoke/step.rb +1 -1
  111. data/smoke/struct.rb +4 -3
  112. data/smoke/struct3.rb +14 -0
  113. data/smoke/symbol-proc.rb +24 -0
  114. data/smoke/uninitialize-var.rb +12 -0
  115. data/smoke/user-demo.rb +15 -0
  116. data/smoke/wrong-extend.rb +1 -0
  117. data/typeprof.gemspec +4 -2
  118. metadata +53 -6
  119. data/run.sh +0 -3
  120. data/smoke/variadic1.rb.notyet +0 -5
@@ -6,30 +6,226 @@ module TypeProf
6
6
  raise if !val.is_a?(Utils::StructuralEquality) && !val.is_a?(Integer) && !val.is_a?(Symbol)
7
7
  @val = val
8
8
  @parent = parent
9
- @_hash ||= (@val.hash ^ @parent.hash)
10
9
  end
11
10
 
12
11
  attr_reader :val, :parent
13
12
 
14
- def hash
15
- @_hash
16
- end
17
-
18
13
  def add_id(val)
19
14
  AllocationSite.new(val, self)
20
15
  end
21
16
  end
22
17
 
23
18
  class Type # or AbstractValue
24
- # This is a type for global interface, e.g., TypedISeq.
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
+ end
49
+
50
+ # The most basic container type for default type parameter class
51
+ class Cell < ContainerType
52
+ def initialize(elems, base_type)
53
+ raise if !elems.is_a?(Cell::Elements)
54
+ @elems = elems # Cell::Elements
55
+ raise unless base_type
56
+ @base_type = base_type
57
+ if base_type.klass.type_params.size != elems.elems.size
58
+ raise
59
+ end
60
+ end
61
+
62
+ attr_reader :elems, :base_type
63
+
64
+ def inspect
65
+ "Type::Cell[#{ @elems.inspect }, base_type: #{ @base_type.inspect }]"
66
+ end
67
+
68
+ def screen_name(scratch)
69
+ str = @elems.screen_name(scratch)
70
+ if str.start_with?("*")
71
+ str = @base_type.screen_name(scratch) + str[1..]
72
+ end
73
+ str
74
+ end
75
+
76
+ def localize(env, alloc_site, depth)
77
+ return env, Type.any if depth <= 0
78
+ alloc_site = alloc_site.add_id(:cell).add_id(@base_type)
79
+ env, elems = @elems.localize(env, alloc_site, depth)
80
+ env.deploy_type(LocalCell, alloc_site, elems, @base_type)
81
+ end
82
+
83
+ def limit_size(limit)
84
+ return Type.any if limit <= 0
85
+ Cell.new(@elems.limit_size(limit - 1), @base_type)
86
+ end
87
+
88
+ def get_method(mid, scratch)
89
+ raise
90
+ end
91
+
92
+ def substitute(subst, depth)
93
+ return Type.any if depth <= 0
94
+ elems = @elems.substitute(subst, depth)
95
+ Cell.new(elems, @base_type)
96
+ end
97
+
98
+ class Elements # Cell
99
+ include Utils::StructuralEquality
100
+
101
+ def initialize(elems)
102
+ @elems = elems
103
+ end
104
+
105
+ attr_reader :elems
106
+
107
+ def to_local_type(id, base_ty)
108
+ Type::LocalCell.new(id, base_ty)
109
+ end
110
+
111
+ def globalize(env, visited, depth)
112
+ Elements.new(@elems.map {|ty| ty.globalize(env, visited, depth) })
113
+ end
114
+
115
+ def localize(env, alloc_site, depth)
116
+ elems = @elems.map.with_index do |ty, i|
117
+ alloc_site2 = alloc_site.add_id(i)
118
+ env, ty = ty.localize(env, alloc_site2, depth)
119
+ ty
120
+ end
121
+ return env, Elements.new(elems)
122
+ end
123
+
124
+ def limit_size(limit)
125
+ Elements.new(@elems.map {|ty| ty.limit_size(limit) })
126
+ end
127
+
128
+ def screen_name(scratch)
129
+ "*[#{ @elems.map {|ty| ty.screen_name(scratch) }.join(", ") }]"
130
+ end
131
+
132
+ def pretty_print(q)
133
+ q.group(9, "Elements[", "]") do
134
+ q.seplist(@elems) do |elem|
135
+ q.pp elem
136
+ end
137
+ end
138
+ end
139
+
140
+ def match?(other)
141
+ return nil if @elems.size != other.elems.size
142
+ subst = nil
143
+ @elems.zip(other.elems) do |ty0, ty1|
144
+ subst2 = Type.match?(ty0, ty1)
145
+ return nil unless subst2
146
+ subst = Type.merge_substitution(subst, subst2)
147
+ end
148
+ subst
149
+ end
150
+
151
+ def each_free_type_variable(&blk)
152
+ @elems.each do |ty|
153
+ ty.each_free_type_variable(&blk)
154
+ end
155
+ end
156
+
157
+ def substitute(subst, depth)
158
+ Elements.new(@elems.map {|ty| ty.substitute(subst, depth) })
159
+ end
160
+
161
+ def [](idx)
162
+ @elems[idx]
163
+ end
164
+
165
+ def update(idx, ty)
166
+ Elements.new(Utils.array_update(@elems, idx, @elems[idx].union(ty)))
167
+ end
168
+
169
+ def union(other)
170
+ return self if self == other
171
+ if @elems.size != other.elems.size
172
+ raise "#{ @elems.size } != #{ other.elems.size }"
173
+ end
174
+ elems = []
175
+ @elems.zip(other.elems) do |ty0, ty1|
176
+ elems << ty0.union(ty1)
177
+ end
178
+ Elements.new(elems)
179
+ end
180
+ end
181
+ end
182
+
183
+ class LocalCell < ContainerType
184
+ def initialize(id, base_type)
185
+ @id = id
186
+ raise unless base_type
187
+ @base_type = base_type
188
+ end
189
+
190
+ attr_reader :id, :base_type
191
+
192
+ def inspect
193
+ "Type::LocalCell[#{ @id }, base_type: #{ @base_type.inspect }]"
194
+ end
195
+
196
+ def screen_name(scratch)
197
+ #raise "LocalArray must not be included in signature"
198
+ "LocalCell!"
199
+ end
200
+
201
+ def globalize(env, visited, depth)
202
+ if visited[self] || depth <= 0
203
+ Type.any
204
+ else
205
+ visited[self] = true
206
+ elems = env.get_container_elem_types(@id)
207
+ if elems
208
+ elems = elems.globalize(env, visited, depth - 1)
209
+ else
210
+ elems = Cell::Elements.new([]) # XXX
211
+ end
212
+ visited.delete(self)
213
+ Cell.new(elems, @base_type)
214
+ end
215
+ end
216
+
217
+ def get_method(mid, scratch)
218
+ @base_type.get_method(mid, scratch)
219
+ end
220
+ end
221
+
25
222
  # Do not insert Array type to local environment, stack, etc.
26
- class Array < Type
223
+ class Array < ContainerType
27
224
  def initialize(elems, base_type)
28
225
  raise unless elems.is_a?(Array::Elements)
29
226
  @elems = elems # Array::Elements
30
227
  raise unless base_type
31
228
  @base_type = base_type
32
- # XXX: need infinite recursion
33
229
  end
34
230
 
35
231
  attr_reader :elems, :base_type
@@ -47,18 +243,11 @@ module TypeProf
47
243
  str
48
244
  end
49
245
 
50
- def globalize(env, visited, depth)
51
- return Type.any if depth <= 0
52
- elems = @elems.globalize(env, visited, depth - 1)
53
- base_ty = @base_type.globalize(env, visited, depth - 1)
54
- Array.new(elems, base_ty)
55
- end
56
-
57
246
  def localize(env, alloc_site, depth)
58
247
  return env, Type.any if depth <= 0
59
- alloc_site = alloc_site.add_id(:ary)
248
+ alloc_site = alloc_site.add_id(:ary).add_id(@base_type)
60
249
  env, elems = @elems.localize(env, alloc_site, depth - 1)
61
- env.deploy_array_type(alloc_site, elems, @base_type)
250
+ env.deploy_type(LocalArray, alloc_site, elems, @base_type)
62
251
  end
63
252
 
64
253
  def limit_size(limit)
@@ -70,28 +259,13 @@ module TypeProf
70
259
  raise
71
260
  end
72
261
 
73
- def consistent?(other, subst)
74
- case other
75
- when Type::Any then true
76
- when Type::Var then other.add_subst!(self, subst)
77
- when Type::Union
78
- other.types.each do |ty2|
79
- return true if consistent?(ty2, subst)
80
- end
81
- when Type::Array
82
- @base_type.consistent?(other.base_type, subst) && @elems.consistent?(other.elems, subst)
83
- else
84
- self == other
85
- end
86
- end
87
-
88
262
  def substitute(subst, depth)
89
263
  return Type.any if depth <= 0
90
264
  elems = @elems.substitute(subst, depth - 1)
91
265
  Array.new(elems, @base_type)
92
266
  end
93
267
 
94
- class Elements
268
+ class Elements # Array
95
269
  include Utils::StructuralEquality
96
270
 
97
271
  def initialize(lead_tys, rest_ty = Type.bot)
@@ -102,8 +276,7 @@ module TypeProf
102
276
 
103
277
  attr_reader :lead_tys, :rest_ty
104
278
 
105
- def to_local_type(id)
106
- base_ty = Type::Instance.new(Type::Builtin[:ary])
279
+ def to_local_type(id, base_ty)
107
280
  Type::LocalArray.new(id, base_ty)
108
281
  end
109
282
 
@@ -151,14 +324,24 @@ module TypeProf
151
324
  end
152
325
  end
153
326
 
154
- def consistent?(other, subst)
327
+ def match?(other)
155
328
  n = [@lead_tys.size, other.lead_tys.size].min
156
- n.times do |i|
157
- return false unless @lead_tys[i].consistent?(other.lead_tys[i], subst)
158
- end
159
329
  rest_ty1 = @lead_tys[n..].inject(@rest_ty) {|ty1, ty2| ty1.union(ty2) }
160
330
  rest_ty2 = other.lead_tys[n..].inject(other.rest_ty) {|ty1, ty2| ty1.union(ty2) }
161
- rest_ty1.consistent?(rest_ty2, subst)
331
+ subst = nil
332
+ (@lead_tys[0, n] + [rest_ty1]).zip(other.lead_tys[0, n] + [rest_ty2]) do |ty0, ty1|
333
+ subst2 = Type.match?(ty0, ty1)
334
+ return nil unless subst2
335
+ subst = Type.merge_substitution(subst, subst2)
336
+ end
337
+ subst
338
+ end
339
+
340
+ def each_free_type_variable(&blk)
341
+ @lead_tys.each do |ty|
342
+ ty.each_free_type_variable(&blk)
343
+ end
344
+ @rest_ty&.each_free_type_variable(&blk)
162
345
  end
163
346
 
164
347
  def substitute(subst, depth)
@@ -171,6 +354,11 @@ module TypeProf
171
354
  @lead_tys.inject(@rest_ty) {|ty1, ty2| ty1.union(ty2) } #.union(Type.nil) # is this needed?
172
355
  end
173
356
 
357
+ def squash_or_any
358
+ ty = squash
359
+ ty == Type.bot ? Type.any : ty
360
+ end
361
+
174
362
  def [](idx)
175
363
  if idx >= 0
176
364
  if idx < @lead_tys.size
@@ -304,7 +492,7 @@ module TypeProf
304
492
  end
305
493
 
306
494
  # Do not insert Array type to local environment, stack, etc.
307
- class LocalArray < Type
495
+ class LocalArray < ContainerType
308
496
  def initialize(id, base_type)
309
497
  @id = id
310
498
  raise unless base_type
@@ -334,6 +522,7 @@ module TypeProf
334
522
  # TODO: currently out-of-scope array cannot be accessed
335
523
  elems = Array::Elements.new([], Type.any)
336
524
  end
525
+ visited.delete(self)
337
526
  Array.new(elems, @base_type)
338
527
  end
339
528
  end
@@ -341,14 +530,10 @@ module TypeProf
341
530
  def get_method(mid, scratch)
342
531
  @base_type.get_method(mid, scratch)
343
532
  end
344
-
345
- def consistent?(other, subst)
346
- raise "must not be used"
347
- end
348
533
  end
349
534
 
350
535
 
351
- class Hash < Type
536
+ class Hash < ContainerType
352
537
  def initialize(elems, base_type)
353
538
  @elems = elems
354
539
  raise unless elems
@@ -365,18 +550,11 @@ module TypeProf
365
550
  @elems.screen_name(scratch)
366
551
  end
367
552
 
368
- def globalize(env, visited, depth)
369
- return Type.any if depth <= 0
370
- elems = @elems.globalize(env, visited, depth - 1)
371
- base_ty = @base_type.globalize(env, visited, depth - 1)
372
- Hash.new(elems, base_ty)
373
- end
374
-
375
553
  def localize(env, alloc_site, depth)
376
554
  return env, Type.any if depth <= 0
377
- alloc_site = alloc_site.add_id(:hash)
555
+ alloc_site = alloc_site.add_id(:hash).add_id(@base_type)
378
556
  env, elems = @elems.localize(env, alloc_site, depth - 1)
379
- env.deploy_hash_type(alloc_site, elems, @base_type)
557
+ env.deploy_type(LocalHash, alloc_site, elems, @base_type)
380
558
  end
381
559
 
382
560
  def limit_size(limit)
@@ -388,28 +566,13 @@ module TypeProf
388
566
  raise
389
567
  end
390
568
 
391
- def consistent?(other, subst)
392
- case other
393
- when Type::Any then true
394
- when Type::Var then other.add_subst!(self, subst)
395
- when Type::Union
396
- other.types.each do |ty2|
397
- return true if consistent?(ty2, subst)
398
- end
399
- when Type::Hash
400
- @base_type.consistent?(other.base_type, subst) && @elems.consistent?(other.elems, subst)
401
- else
402
- self == other
403
- end
404
- end
405
-
406
569
  def substitute(subst, depth)
407
570
  return Type.any if depth <= 0
408
571
  elems = @elems.substitute(subst, depth - 1)
409
572
  Hash.new(elems, @base_type)
410
573
  end
411
574
 
412
- class Elements
575
+ class Elements # Hash
413
576
  include Utils::StructuralEquality
414
577
 
415
578
  def initialize(map_tys)
@@ -427,8 +590,7 @@ module TypeProf
427
590
 
428
591
  attr_reader :map_tys
429
592
 
430
- def to_local_type(id)
431
- base_ty = Type::Instance.new(Type::Builtin[:hash])
593
+ def to_local_type(id, base_ty)
432
594
  Type::LocalHash.new(id, base_ty)
433
595
  end
434
596
 
@@ -470,9 +632,13 @@ module TypeProf
470
632
 
471
633
  def screen_name(scratch)
472
634
  s = @map_tys.map do |k_ty, v_ty|
473
- k = k_ty.screen_name(scratch)
474
635
  v = v_ty.screen_name(scratch)
475
- "#{ k }=>#{ v }"
636
+ if k_ty.is_a?(Type::Symbol)
637
+ "#{ k_ty.sym }: #{ v }"
638
+ else
639
+ k = k_ty.screen_name(scratch)
640
+ "#{ k }=>#{ v }"
641
+ end
476
642
  end.join(", ")
477
643
  "{#{ s }}"
478
644
  end
@@ -492,22 +658,31 @@ module TypeProf
492
658
  end
493
659
  end
494
660
 
495
- def consistent?(other, subst)
496
- subst2 = subst.dup
661
+ def match?(other)
662
+ subst = nil
497
663
  other.map_tys.each do |k1, v1|
498
- found = false
664
+ subst2 = nil
499
665
  @map_tys.each do |k0, v0|
500
- subst3 = subst2.dup
501
- if k0.consistent?(k1, subst3) && v0.consistent?(v1, subst3)
502
- subst2.replace(subst3)
503
- found = true
504
- break
666
+ subst3 = Type.match?(k0, k1)
667
+ if subst3
668
+ subst4 = Type.match?(v0, v1)
669
+ if subst4
670
+ subst2 = Type.merge_substitution(subst2, subst3)
671
+ subst2 = Type.merge_substitution(subst2, subst4)
672
+ end
505
673
  end
506
674
  end
507
- return false unless found
675
+ return nil unless subst2
676
+ subst = Type.merge_substitution(subst, subst2)
677
+ end
678
+ subst
679
+ end
680
+
681
+ def each_free_type_variable(&blk)
682
+ @map_tys.each do |k, v|
683
+ k.each_free_type_variable(&blk)
684
+ v.each_free_type_variable(&blk)
508
685
  end
509
- subst.replace(subst2)
510
- true
511
686
  end
512
687
 
513
688
  def substitute(subst, depth)
@@ -541,7 +716,7 @@ module TypeProf
541
716
  def [](key_ty)
542
717
  val_ty = Type.bot
543
718
  @map_tys.each do |k_ty, v_ty|
544
- if k_ty.consistent?(key_ty, {})
719
+ if Type.match?(k_ty, key_ty)
545
720
  val_ty = val_ty.union(v_ty)
546
721
  end
547
722
  end
@@ -579,10 +754,26 @@ module TypeProf
579
754
 
580
755
  Elements.new(map_tys)
581
756
  end
757
+
758
+ def to_keywords
759
+ kw_tys = {}
760
+ @map_tys.each do |key_ty, val_ty|
761
+ if key_ty.is_a?(Type::Symbol)
762
+ kw_tys[key_ty.sym] = val_ty
763
+ else
764
+ all_val_ty = Type.bot
765
+ @map_tys.each do |_key_ty, val_ty|
766
+ all_val_ty = all_val_ty.union(val_ty)
767
+ end
768
+ return { nil => all_val_ty }
769
+ end
770
+ end
771
+ kw_tys
772
+ end
582
773
  end
583
774
  end
584
775
 
585
- class LocalHash < Type
776
+ class LocalHash < ContainerType
586
777
  def initialize(id, base_type)
587
778
  @id = id
588
779
  @base_type = base_type
@@ -610,6 +801,7 @@ module TypeProf
610
801
  else
611
802
  elems = Hash::Elements.new({Type.any => Type.any})
612
803
  end
804
+ visited.delete(self)
613
805
  Hash.new(elems, @base_type)
614
806
  end
615
807
  end
@@ -617,10 +809,6 @@ module TypeProf
617
809
  def get_method(mid, scratch)
618
810
  @base_type.get_method(mid, scratch)
619
811
  end
620
-
621
- def consistent?(other, subst)
622
- raise "must not be used"
623
- end
624
812
  end
625
813
  end
626
814
  end