typeprof 0.5.3 → 0.8.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 (208) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile.lock +6 -4
  3. data/doc/doc.ja.md +3 -4
  4. data/doc/doc.md +3 -4
  5. data/lib/typeprof/analyzer.rb +248 -166
  6. data/lib/typeprof/arguments.rb +12 -6
  7. data/lib/typeprof/builtin.rb +123 -23
  8. data/lib/typeprof/cli.rb +33 -34
  9. data/lib/typeprof/config.rb +6 -4
  10. data/lib/typeprof/container-type.rb +175 -112
  11. data/lib/typeprof/export.rb +23 -17
  12. data/lib/typeprof/import.rb +58 -53
  13. data/lib/typeprof/method.rb +59 -125
  14. data/lib/typeprof/type.rb +26 -14
  15. data/lib/typeprof/version.rb +1 -1
  16. data/smoke/alias.rb +1 -0
  17. data/smoke/any1.rb +1 -0
  18. data/smoke/any2.rb +1 -0
  19. data/smoke/arguments.rb +1 -0
  20. data/smoke/arguments2.rb +1 -0
  21. data/smoke/array-each.rb +1 -0
  22. data/smoke/array-each2.rb +1 -0
  23. data/smoke/array-each3.rb +2 -1
  24. data/smoke/array-ltlt.rb +1 -0
  25. data/smoke/array-ltlt2.rb +1 -0
  26. data/smoke/array-map.rb +1 -0
  27. data/smoke/array-map2.rb +1 -0
  28. data/smoke/array-map3.rb +1 -0
  29. data/smoke/array-mul.rb +1 -0
  30. data/smoke/array-plus1.rb +1 -0
  31. data/smoke/array-pop.rb +1 -0
  32. data/smoke/array-range-aref.rb +71 -0
  33. data/smoke/array-replace.rb +1 -0
  34. data/smoke/array-s-aref.rb +1 -0
  35. data/smoke/array1.rb +1 -0
  36. data/smoke/array10.rb +1 -0
  37. data/smoke/array11.rb +2 -1
  38. data/smoke/array12.rb +1 -0
  39. data/smoke/array13.rb +1 -0
  40. data/smoke/array14.rb +1 -0
  41. data/smoke/array2.rb +1 -0
  42. data/smoke/array4.rb +1 -0
  43. data/smoke/array5.rb +1 -0
  44. data/smoke/array6.rb +3 -2
  45. data/smoke/array7.rb +1 -0
  46. data/smoke/array8.rb +1 -1
  47. data/smoke/array9.rb +1 -0
  48. data/smoke/autoload.rb +14 -0
  49. data/smoke/backtrace.rb +1 -0
  50. data/smoke/block-ambiguous.rb +1 -0
  51. data/smoke/block-args1-rest.rb +1 -0
  52. data/smoke/block-args1.rb +1 -0
  53. data/smoke/block-args2-rest.rb +1 -0
  54. data/smoke/block-args2.rb +4 -3
  55. data/smoke/block-args3-rest.rb +1 -0
  56. data/smoke/block-args3.rb +5 -4
  57. data/smoke/block-blockarg.rb +2 -1
  58. data/smoke/block-kwarg.rb +1 -0
  59. data/smoke/block1.rb +1 -0
  60. data/smoke/block10.rb +1 -0
  61. data/smoke/block11.rb +1 -0
  62. data/smoke/block12.rb +1 -0
  63. data/smoke/block14.rb +1 -0
  64. data/smoke/block2.rb +1 -0
  65. data/smoke/block4.rb +1 -0
  66. data/smoke/block5.rb +2 -1
  67. data/smoke/block6.rb +1 -0
  68. data/smoke/block7.rb +1 -0
  69. data/smoke/block8.rb +1 -0
  70. data/smoke/block9.rb +1 -0
  71. data/smoke/blown.rb +1 -0
  72. data/smoke/break1.rb +1 -0
  73. data/smoke/break2.rb +1 -0
  74. data/smoke/case.rb +1 -0
  75. data/smoke/case2.rb +1 -0
  76. data/smoke/class_method3.rb +2 -0
  77. data/smoke/constant2.rb +2 -2
  78. data/smoke/constant3.rb +1 -0
  79. data/smoke/constant4.rb +1 -0
  80. data/smoke/context-sensitive1.rb +1 -0
  81. data/smoke/cvar.rb +1 -0
  82. data/smoke/define_method.rb +16 -0
  83. data/smoke/define_method2.rb +18 -0
  84. data/smoke/demo.rb +1 -0
  85. data/smoke/demo1.rb +1 -0
  86. data/smoke/demo10.rb +1 -0
  87. data/smoke/demo11.rb +1 -0
  88. data/smoke/demo2.rb +1 -0
  89. data/smoke/demo3.rb +1 -0
  90. data/smoke/demo5.rb +1 -1
  91. data/smoke/demo7.rb +1 -0
  92. data/smoke/demo8.rb +1 -0
  93. data/smoke/demo9.rb +2 -1
  94. data/smoke/dummy-execution1.rb +1 -0
  95. data/smoke/ensure1.rb +1 -0
  96. data/smoke/enumerator.rb +1 -0
  97. data/smoke/expandarray1.rb +1 -0
  98. data/smoke/expandarray2.rb +1 -0
  99. data/smoke/flow1.rb +1 -0
  100. data/smoke/flow2.rb +1 -0
  101. data/smoke/flow3.rb +1 -0
  102. data/smoke/flow5.rb +1 -0
  103. data/smoke/flow6.rb +1 -0
  104. data/smoke/flow7.rb +1 -0
  105. data/smoke/flow8.rb +1 -0
  106. data/smoke/freeze.rb +1 -0
  107. data/smoke/function.rb +1 -0
  108. data/smoke/gvar.rb +1 -0
  109. data/smoke/gvar2.rb +1 -0
  110. data/smoke/hash-fetch.rb +1 -0
  111. data/smoke/hash-merge-bang.rb +1 -0
  112. data/smoke/hash1.rb +3 -1
  113. data/smoke/hash2.rb +1 -0
  114. data/smoke/hash3.rb +1 -0
  115. data/smoke/hash4.rb +2 -1
  116. data/smoke/inheritance2.rb +2 -2
  117. data/smoke/initialize.rb +1 -0
  118. data/smoke/int_times.rb +1 -0
  119. data/smoke/integer.rb +1 -0
  120. data/smoke/ivar.rb +1 -0
  121. data/smoke/ivar2.rb +1 -1
  122. data/smoke/kernel-class.rb +2 -1
  123. data/smoke/keyword1.rb +1 -0
  124. data/smoke/keyword2.rb +1 -0
  125. data/smoke/keyword3.rb +1 -0
  126. data/smoke/keyword4.rb +1 -0
  127. data/smoke/keyword5.rb +1 -0
  128. data/smoke/kwrest.rb +12 -0
  129. data/smoke/kwrest.rbs +3 -0
  130. data/smoke/kwsplat1.rb +2 -1
  131. data/smoke/kwsplat2.rb +1 -0
  132. data/smoke/manual-rbs.rb +1 -0
  133. data/smoke/manual-rbs2.rb +1 -0
  134. data/smoke/masgn1.rb +1 -0
  135. data/smoke/masgn2.rb +1 -0
  136. data/smoke/masgn3.rb +1 -0
  137. data/smoke/method_in_branch.rb +1 -0
  138. data/smoke/method_missing.rb +28 -0
  139. data/smoke/multiple-superclass.rb +1 -1
  140. data/smoke/next1.rb +1 -0
  141. data/smoke/next2.rb +1 -0
  142. data/smoke/object-send1.rb +1 -0
  143. data/smoke/once.rb +1 -0
  144. data/smoke/optional1.rb +1 -0
  145. data/smoke/optional2.rb +1 -0
  146. data/smoke/optional3.rb +1 -0
  147. data/smoke/parameterizedd-self.rb +3 -2
  148. data/smoke/parameterizedd-self2.rb +15 -0
  149. data/smoke/pathname1.rb +1 -0
  150. data/smoke/pathname2.rb +1 -0
  151. data/smoke/pattern-match1.rb +1 -0
  152. data/smoke/pattern-match2.rb +1 -0
  153. data/smoke/proc.rb +1 -0
  154. data/smoke/proc2.rb +1 -0
  155. data/smoke/proc3.rb +1 -0
  156. data/smoke/proc4.rb +1 -0
  157. data/smoke/range.rb +1 -0
  158. data/smoke/rbs-alias.rb +1 -0
  159. data/smoke/rbs-attr.rb +3 -2
  160. data/smoke/rbs-attr2.rb +11 -0
  161. data/smoke/rbs-attr2.rbs +3 -0
  162. data/smoke/rbs-extend.rb +1 -0
  163. data/smoke/rbs-interface.rb +1 -0
  164. data/smoke/rbs-proc1.rb +1 -0
  165. data/smoke/rbs-proc2.rb +1 -0
  166. data/smoke/rbs-proc3.rb +1 -0
  167. data/smoke/rbs-record.rb +1 -0
  168. data/smoke/rbs-tyvar.rb +1 -0
  169. data/smoke/rbs-tyvar2.rb +1 -0
  170. data/smoke/rbs-tyvar3.rb +1 -0
  171. data/smoke/rbs-tyvar5.rb +1 -0
  172. data/smoke/rbs-tyvar6.rb +18 -0
  173. data/smoke/rbs-tyvar6.rbs +12 -0
  174. data/smoke/rbs-tyvar7.rb +12 -0
  175. data/smoke/rbs-tyvar7.rbs +7 -0
  176. data/smoke/rbs-vars.rb +1 -2
  177. data/smoke/redo1.rb +1 -0
  178. data/smoke/redo2.rb +1 -0
  179. data/smoke/req-keyword.rb +1 -0
  180. data/smoke/rescue1.rb +1 -0
  181. data/smoke/rescue2.rb +1 -0
  182. data/smoke/respond_to.rb +1 -0
  183. data/smoke/rest-farg.rb +1 -0
  184. data/smoke/rest1.rb +1 -0
  185. data/smoke/rest2.rb +1 -0
  186. data/smoke/rest3.rb +1 -0
  187. data/smoke/rest4.rb +1 -0
  188. data/smoke/rest5.rb +1 -0
  189. data/smoke/rest6.rb +1 -0
  190. data/smoke/retry1.rb +1 -0
  191. data/smoke/return.rb +1 -0
  192. data/smoke/step.rb +1 -0
  193. data/smoke/string-split.rb +1 -0
  194. data/smoke/struct.rb +2 -2
  195. data/smoke/struct2.rb +1 -0
  196. data/smoke/super1.rb +1 -0
  197. data/smoke/super4.rb +43 -0
  198. data/smoke/super5.rb +36 -0
  199. data/smoke/svar1.rb +1 -0
  200. data/smoke/symbol-proc.rb +1 -0
  201. data/smoke/tap1.rb +1 -0
  202. data/smoke/toplevel.rb +1 -0
  203. data/smoke/two-map.rb +1 -0
  204. data/smoke/type_var.rb +1 -0
  205. data/smoke/typed_method.rb +1 -0
  206. data/smoke/uninitialize-var.rb +1 -0
  207. data/smoke/union-recv.rb +2 -2
  208. metadata +18 -2
@@ -10,6 +10,10 @@ module TypeProf
10
10
  raise unless blk_ty
11
11
  end
12
12
 
13
+ def for_method_missing(mid)
14
+ ActualArguments.new([mid] + @lead_tys, @rest_ty, @kw_tys, @blk_ty)
15
+ end
16
+
13
17
  attr_reader :lead_tys, :rest_ty, :kw_tys, :blk_ty
14
18
 
15
19
  def globalize(caller_env, visited, depth)
@@ -148,12 +152,14 @@ module TypeProf
148
152
  lead_tys = ty.elems.lead_tys
149
153
  rest_ty = ty.elems.rest_ty
150
154
  when Type::Union
151
- other_elems = nil
152
- ty.elems&.each do |(container_kind, base_type), elems|
153
- if container_kind == Type::Array
154
- rest_ty = rest_ty ? rest_ty.union(elems.squash) : elems.squash
155
- else
156
- other_elems = other_elems ? other_elems.union(elems) : elems
155
+ if ty.elems
156
+ other_elems = {}
157
+ ty.elems.each do |(container_kind, base_type), elems|
158
+ if container_kind == Type::Array
159
+ rest_ty = rest_ty ? rest_ty.union(elems.squash) : elems.squash
160
+ else
161
+ other_elems[[container_kind, base_type]] = elems
162
+ end
157
163
  end
158
164
  end
159
165
  lead_tys = [Type::Union.new(ty.types, other_elems)]
@@ -33,10 +33,10 @@ module TypeProf
33
33
  h2 = aargs.lead_tys[1]
34
34
  elems = nil
35
35
  h1.each_child do |h1|
36
- if h1.is_a?(Type::LocalHash)
36
+ if h1.is_a?(Type::Local) && h1.kind == Type::Hash
37
37
  h1_elems = scratch.get_container_elem_types(env, ep, h1.id)
38
38
  h2.each_child do |h2|
39
- if h2.is_a?(Type::LocalHash)
39
+ if h2.is_a?(Type::Local) && h2.kind == Type::Hash
40
40
  h2_elems = scratch.get_container_elem_types(env, ep, h2.id)
41
41
  elems0 = h1_elems.union(h2_elems)
42
42
  if elems
@@ -100,7 +100,8 @@ module TypeProf
100
100
  raise unless aargs.lead_tys.size != 0
101
101
  sym = get_sym("respond_to?", aargs.lead_tys[0], ep, scratch)
102
102
  if sym
103
- if recv.get_method(sym, scratch)
103
+ klass, singleton = recv.method_dispatch_info
104
+ if scratch.get_method(klass, singleton, sym)
104
105
  true_val = Type::Instance.new(Type::Builtin[:true])
105
106
  ctn[true_val, ep, env]
106
107
  else
@@ -142,8 +143,8 @@ module TypeProf
142
143
 
143
144
  def object_instance_eval(recv, mid, aargs, ep, env, scratch, &ctn)
144
145
  if aargs.lead_tys.size >= 1
145
- scratch.warn(ep, "instance_eval with arguments are ignored")
146
- ctn[type.any, ep, env]
146
+ scratch.warn(ep, "instance_eval with arguments is ignored")
147
+ ctn[Type.any, ep, env]
147
148
  return
148
149
  end
149
150
  naargs = ActualArguments.new([recv], nil, {}, Type.nil)
@@ -153,20 +154,30 @@ module TypeProf
153
154
  end
154
155
 
155
156
  def module_include(recv, mid, aargs, ep, env, scratch, &ctn)
157
+ if aargs.lead_tys.size != 1
158
+ scratch.warn(ep, "Module#include without an argument is ignored")
159
+ ctn[Type.any, ep, env]
160
+ return
161
+ end
156
162
  arg = aargs.lead_tys[0]
157
163
  arg.each_child do |arg|
158
164
  if arg.is_a?(Type::Class)
159
- scratch.include_module(recv, arg, false, ep.ctx.iseq.absolute_path)
165
+ scratch.include_module(recv, arg, nil, false, ep.ctx.iseq.absolute_path)
160
166
  end
161
167
  end
162
168
  ctn[recv, ep, env]
163
169
  end
164
170
 
165
171
  def module_extend(recv, mid, aargs, ep, env, scratch, &ctn)
172
+ if aargs.lead_tys.size != 1
173
+ scratch.warn(ep, "Module#extend without an argument is ignored")
174
+ ctn[Type.any, ep, env]
175
+ return
176
+ end
166
177
  arg = aargs.lead_tys[0]
167
178
  arg.each_child do |arg|
168
179
  if arg.is_a?(Type::Class)
169
- scratch.include_module(recv, arg, true, ep.ctx.iseq.absolute_path)
180
+ scratch.include_module(recv, arg, nil, true, ep.ctx.iseq.absolute_path)
170
181
  end
171
182
  end
172
183
  ctn[recv, ep, env]
@@ -178,7 +189,7 @@ module TypeProf
178
189
  else
179
190
  aargs.lead_tys.each do |aarg|
180
191
  sym = get_sym("module_function", aarg, ep, scratch) or next
181
- meths = Type::Instance.new(recv).get_method(sym, scratch)
192
+ meths = scratch.get_method(recv, false, sym)
182
193
  meths.each do |mdef|
183
194
  scratch.add_method(recv, sym, true, mdef)
184
195
  end
@@ -187,6 +198,67 @@ module TypeProf
187
198
  end
188
199
  end
189
200
 
201
+ def module_public(recv, mid, aargs, ep, env, scratch, &ctn)
202
+ if aargs.lead_tys.empty?
203
+ ctn[recv, ep, env.method_public_set(true)]
204
+ else
205
+ aargs.lead_tys.each do |aarg|
206
+ sym = get_sym("public", aarg, ep, scratch) or next
207
+ meths = scratch.get_method(recv, false, sym)
208
+ next unless meths
209
+ meths.each do |mdef|
210
+ mdef.pub_meth = true
211
+ end
212
+ end
213
+ ctn[recv, ep, env]
214
+ end
215
+ end
216
+
217
+ def module_private(recv, mid, aargs, ep, env, scratch, &ctn)
218
+ if aargs.lead_tys.empty?
219
+ ctn[recv, ep, env.method_public_set(false)]
220
+ else
221
+ aargs.lead_tys.each do |aarg|
222
+ sym = get_sym("private", aarg, ep, scratch) or next
223
+ meths = scratch.get_method(recv, false, sym)
224
+ next unless meths
225
+ meths.each do |mdef|
226
+ mdef.pub_meth = false
227
+ end
228
+ end
229
+ ctn[recv, ep, env]
230
+ end
231
+ end
232
+
233
+ def module_define_method(recv, mid, aargs, ep, env, scratch, &ctn)
234
+ if aargs.lead_tys.size != 1
235
+ scratch.warn(ep, "Module#define with #{ aargs.lead_tys.size } argument is ignored")
236
+ ctn[Type.any, ep, env]
237
+ return
238
+ end
239
+
240
+ mid, = aargs.lead_tys
241
+ if mid.is_a?(Type::Symbol)
242
+ mid = mid.sym
243
+ aargs.blk_ty.each_child do |blk_ty|
244
+ if blk_ty.is_a?(Type::Proc)
245
+ blk = blk_ty.block_body
246
+ case blk
247
+ when ISeqBlock
248
+ scratch.do_define_iseq_method(ep, env, mid, blk.iseq, ep)
249
+ else
250
+ # XXX: what to do?
251
+ end
252
+ else
253
+ # XXX: what to do?
254
+ end
255
+ end
256
+ else
257
+ # XXX: what to do?
258
+ end
259
+ ctn[Type.any, ep, env]
260
+ end
261
+
190
262
  def module_attr_accessor(recv, mid, aargs, ep, env, scratch, &ctn)
191
263
  aargs.lead_tys.each do |aarg|
192
264
  sym = get_sym("attr_accessor", aarg, ep, scratch) or next
@@ -222,21 +294,16 @@ module TypeProf
222
294
  end
223
295
 
224
296
  def array_aref(recv, mid, aargs, ep, env, scratch, &ctn)
225
- return ctn[Type.any, ep, env] unless recv.is_a?(Type::LocalArray)
297
+ return ctn[Type.any, ep, env] unless recv.is_a?(Type::Local) && recv.kind == Type::Array
226
298
 
227
299
  case aargs.lead_tys.size
228
300
  when 1
229
301
  idx = aargs.lead_tys.first
230
302
  if idx.is_a?(Type::Literal)
231
303
  idx = idx.lit
232
- if idx.is_a?(Range)
233
- ty = scratch.get_array_elem_type(env, ep, recv.id)
234
- base_ty = Type::Instance.new(Type::Builtin[:ary])
235
- ret_ty = Type::Array.new(Type::Array::Elements.new([], ty), base_ty)
236
- ctn[ret_ty, ep, env]
237
- return
238
- end
239
- idx = nil if !idx.is_a?(Integer)
304
+ idx = nil if !idx.is_a?(Integer) && !idx.is_a?(Range)
305
+ elsif idx == Type::Instance.new(Type::Builtin[:range])
306
+ idx = (nil..nil)
240
307
  else
241
308
  idx = nil
242
309
  end
@@ -253,7 +320,7 @@ module TypeProf
253
320
  end
254
321
 
255
322
  def array_aset(recv, mid, aargs, ep, env, scratch, &ctn)
256
- return ctn[Type.any, ep, env] unless recv.is_a?(Type::LocalArray)
323
+ return ctn[Type.any, ep, env] unless recv.is_a?(Type::Local) && recv.kind == Type::Array
257
324
 
258
325
  if aargs.lead_tys.size != 2
259
326
  #raise NotImplementedError # XXX
@@ -278,7 +345,7 @@ module TypeProf
278
345
  end
279
346
 
280
347
  def array_pop(recv, mid, aargs, ep, env, scratch, &ctn)
281
- return ctn[Type.any, ep, env] unless recv.is_a?(Type::LocalArray)
348
+ return ctn[Type.any, ep, env] unless recv.is_a?(Type::Local) && recv.kind == Type::Array
282
349
 
283
350
  if aargs.lead_tys.size != 0
284
351
  ctn[Type.any, ep, env]
@@ -290,7 +357,7 @@ module TypeProf
290
357
  end
291
358
 
292
359
  def hash_aref(recv, mid, aargs, ep, env, scratch, &ctn)
293
- return ctn[Type.any, ep, env] unless recv.is_a?(Type::LocalHash)
360
+ return ctn[Type.any, ep, env] unless recv.is_a?(Type::Local) && recv.kind == Type::Hash
294
361
 
295
362
  if aargs.lead_tys.size != 1
296
363
  ctn[Type.any, ep, env]
@@ -298,7 +365,7 @@ module TypeProf
298
365
  end
299
366
  idx = aargs.lead_tys.first
300
367
  recv.each_child do |recv|
301
- if recv.is_a?(Type::LocalHash)
368
+ if recv.is_a?(Type::Local) && recv.kind == Type::Hash
302
369
  ty = scratch.get_hash_elem_type(env, ep, recv.id, idx)
303
370
  else
304
371
  ty = Type.any
@@ -308,7 +375,7 @@ module TypeProf
308
375
  end
309
376
 
310
377
  def hash_aset(recv, mid, aargs, ep, env, scratch, &ctn)
311
- return ctn[Type.any, ep, env] unless recv.is_a?(Type::LocalHash)
378
+ return ctn[Type.any, ep, env] unless recv.is_a?(Type::Local) && recv.kind == Type::Hash
312
379
 
313
380
  raise NotImplementedError if aargs.lead_tys.size != 2
314
381
 
@@ -316,7 +383,7 @@ module TypeProf
316
383
  idx = scratch.globalize_type(idx, env, ep)
317
384
  ty = aargs.lead_tys.last
318
385
 
319
- unless recv.is_a?(Type::LocalHash)
386
+ unless recv.is_a?(Type::Local) && recv.kind == Type::Hash
320
387
  # to ignore: class OptionMap < Hash
321
388
  return ctn[ty, ep, env]
322
389
  end
@@ -473,6 +540,31 @@ module TypeProf
473
540
  ctn[result, ep, env]
474
541
  end
475
542
 
543
+ def kernel_autoload(recv, mid, aargs, ep, env, scratch, &ctn)
544
+ raise NotImplementedError if aargs.lead_tys.size != 2
545
+ feature = aargs.lead_tys[1]
546
+ if feature.is_a?(Type::Literal)
547
+ feature = feature.lit
548
+
549
+ action, arg = Builtin.file_require(feature, scratch)
550
+ case action
551
+ when :do
552
+ Builtin.file_load(arg, ep, env, scratch, &ctn)
553
+ when :done
554
+ when :error
555
+ scratch.warn(ep, arg)
556
+ end
557
+ ctn[Type.nil, ep, env]
558
+ else
559
+ scratch.warn(ep, "autoload target cannot be identified statically")
560
+ ctn[Type.nil, ep, env]
561
+ end
562
+ end
563
+
564
+ def module_autoload(recv, mid, aargs, ep, env, scratch, &ctn)
565
+ kernel_autoload(recv, mid, aargs, ep, env, scratch, &ctn)
566
+ end
567
+
476
568
  def kernel_Array(recv, mid, aargs, ep, env, scratch, &ctn)
477
569
  raise NotImplementedError if aargs.lead_tys.size != 1
478
570
  ty = aargs.lead_tys.first
@@ -546,6 +638,9 @@ module TypeProf
546
638
  scratch.set_custom_method(klass_module, :include, Builtin.method(:module_include))
547
639
  scratch.set_custom_method(klass_module, :extend, Builtin.method(:module_extend))
548
640
  scratch.set_custom_method(klass_module, :module_function, Builtin.method(:module_module_function))
641
+ scratch.set_custom_method(klass_module, :public, Builtin.method(:module_public))
642
+ scratch.set_custom_method(klass_module, :private, Builtin.method(:module_private))
643
+ scratch.set_custom_method(klass_module, :define_method, Builtin.method(:module_define_method))
549
644
 
550
645
  scratch.set_custom_method(klass_proc, :[], Builtin.method(:proc_call))
551
646
  scratch.set_custom_method(klass_proc, :call, Builtin.method(:proc_call))
@@ -563,6 +658,11 @@ module TypeProf
563
658
  scratch.set_custom_method(klass_obj, :require, Builtin.method(:kernel_require))
564
659
  scratch.set_custom_method(klass_obj, :require_relative, Builtin.method(:kernel_require_relative))
565
660
  scratch.set_custom_method(klass_obj, :Array, Builtin.method(:kernel_Array))
661
+ scratch.set_custom_method(klass_obj, :autoload, Builtin.method(:kernel_autoload))
662
+ scratch.set_custom_method(klass_module, :autoload, Builtin.method(:module_autoload))
663
+
664
+ # remove BasicObject#method_missing
665
+ scratch.set_method(klass_basic_obj, :method_missing, false, nil)
566
666
 
567
667
  # ENV: Hash[String, String]
568
668
  str_ty = Type::Instance.new(Type::Builtin[:str])
@@ -7,60 +7,59 @@ module TypeProf
7
7
  def parse(argv)
8
8
  opt = OptionParser.new
9
9
 
10
+ opt.banner = "Usage: #{ opt.program_name } [options] files..."
11
+
10
12
  output = nil
11
13
 
12
14
  # Verbose level:
13
- # * 0: no output
14
- # * 1: show indicator
15
- # * 2: debug print
15
+ # * 0: none
16
+ # * 1: default level
17
+ # * 2: debugging level
16
18
  verbose = 1
17
19
 
18
20
  options = {}
19
21
  dir_filter = nil
20
22
  gem_rbs_features = []
21
- version = false
23
+ show_version = false
22
24
  max_sec = max_iter = nil
23
25
 
24
- opt.on("-o OUTFILE") {|v| output = v }
25
- opt.on("-q", "--quiet") { verbose = 0 }
26
- opt.on("-v", "--verbose") { options[:show_errors] = true }
27
- opt.on("--version") { version = true }
28
- opt.on("-d", "--debug") { verbose = 2 }
29
- opt.on("-I DIR") {|v| $LOAD_PATH << v }
30
- opt.on("-r FEATURE") {|v| gem_rbs_features << v }
31
- opt.on("--max-second SECOND", Float) {|v| max_sec = v }
32
- opt.on("--max-iteration TIMES", Integer) {|v| max_iter = v }
26
+ opt.separator ""
27
+ opt.separator "Options:"
28
+ opt.on("-o OUTFILE", "Output to OUTFILE instead of stdout") {|v| output = v }
29
+ opt.on("-q", "--quiet", "Do not display progress indicator") { options[:show_indicator] = false }
30
+ opt.on("-v", "--verbose", "Alias to --show-errors") { options[:show_errors] = true }
31
+ opt.on("--version", "Display typeprof version") { show_version = true }
32
+ opt.on("-I DIR", "Add DIR to the load/require path") {|v| $LOAD_PATH << v }
33
+ opt.on("-r FEATURE", "Require RBS of the FEATURE gem") {|v| gem_rbs_features << v }
33
34
 
34
- opt.on("--include-dir DIR") do |dir|
35
+ opt.separator ""
36
+ opt.separator "Analysis output options:"
37
+ opt.on("--include-dir DIR", "Include the analysis result of .rb file in DIR") do |dir|
35
38
  # When `--include-dir` option is specified as the first directory option,
36
39
  # typeprof will exclude any files by default unless a file path matches the explicit option
37
40
  dir_filter ||= [[:exclude]]
38
41
  dir_filter << [:include, File.expand_path(dir)]
39
42
  end
40
- opt.on("--exclude-dir DIR") do |dir|
43
+ opt.on("--exclude-dir DIR", "Exclude the analysis result of .rb file in DIR") do |dir|
41
44
  # When `--exclude-dir` option is specified as the first directory option,
42
45
  # typeprof will include any files by default, except Ruby's install directory and Gem directories
43
46
  dir_filter ||= ConfigData::DEFAULT_DIR_FILTER
44
47
  dir_filter << [:exclude, File.expand_path(dir)]
45
48
  end
49
+ opt.on("--[no-]show-errors", "Display possible errors found during the analysis") {|v| options[:show_errors] = v }
50
+ opt.on("--[no-]show-untyped", "Display \"Foo | untyped\" instead of \"Foo\"") {|v| options[:show_untyped] = v }
46
51
 
47
- opt.on("-f OPTION") do |v|
48
- key, args = v.split("=", 2)
49
- case key
50
- when "type-depth-limit"
51
- options[:type_depth_limit] = Integer(args)
52
- when "pedantic-output"
53
- options[:pedantic_output] = true
54
- when "show-errors"
55
- options[:show_errors] = true
56
- when "show-container-raw-elements"
57
- options[:show_container_raw_elements] = true
58
- when "stackprof"
59
- options[:stackprof] = args ? args.to_sym : :cpu
60
- else
61
- raise OptionParser::InvalidOption.new("unknown option: #{ key }")
62
- end
63
- end
52
+ opt.separator ""
53
+ opt.separator "Analysis limit options:"
54
+ opt.on("--max-second SECOND", Float, "Limit the maxium time of analysis (in second)") {|v| max_sec = v }
55
+ opt.on("--max-iteration TIMES", Integer, "Limit the maxium instruction count of analysis") {|v| max_iter = v }
56
+
57
+ opt.separator ""
58
+ opt.separator "Advanced options:"
59
+ opt.on("--[no-]stub-execution", "Force to call all unreachable methods with \"untyped\" arguments") {|v| options[:stub_execution] = v }
60
+ opt.on("--type-depth-limit DEPTH", Integer, "Limit the maximum depth of nested types") {|v| options[:type_depth_limit] = v }
61
+ opt.on("--debug", "Display analysis log (for debugging purpose)") { verbose = 2 }
62
+ opt.on("--[no-]stackprof MODE", /\Acpu|wall|object\z/, "Enable stackprof (for debugging purpose)") {|v| options[:stackprof] = v.to_sym }
64
63
 
65
64
  opt.parse!(argv)
66
65
 
@@ -75,9 +74,9 @@ module TypeProf
75
74
  end
76
75
  end
77
76
 
78
- puts "typeprof #{ VERSION }" if version
77
+ puts "typeprof #{ VERSION }" if show_version
79
78
  if rb_files.empty?
80
- exit if version
79
+ exit if show_version
81
80
  raise OptionParser::InvalidOption.new("no input files")
82
81
  end
83
82
 
@@ -22,9 +22,11 @@ module TypeProf
22
22
  opt[:verbose] ||= 0
23
23
  opt[:options] ||= {}
24
24
  opt[:options] = {
25
- type_depth_limit: 5,
26
- pedantic_output: false,
25
+ show_indicator: true,
26
+ show_untyped: false,
27
27
  show_errors: false,
28
+ stub_execution: true,
29
+ type_depth_limit: 5,
28
30
  stackprof: nil,
29
31
  }.merge(opt[:options])
30
32
  super(**opt)
@@ -67,7 +69,7 @@ module TypeProf
67
69
 
68
70
  prologue_ctx = Context.new(nil, nil, nil)
69
71
  prologue_ep = ExecutionPoint.new(prologue_ctx, -1, nil)
70
- prologue_env = Env.new(StaticEnv.new(:top, Type.nil, false), [], [], Utils::HashWrapper.new({}))
72
+ prologue_env = Env.new(StaticEnv.new(:top, Type.nil, false, true), [], [], Utils::HashWrapper.new({}))
71
73
 
72
74
  Config.rb_files.each do |rb|
73
75
  if rb.is_a?(Array) # [String name, String content]
@@ -111,7 +113,7 @@ module TypeProf
111
113
  ctx = Context.new(iseq, cref, nil)
112
114
  ep = ExecutionPoint.new(ctx, 0, nil)
113
115
  locals = [Type.nil] * iseq.locals.size
114
- env = Env.new(StaticEnv.new(recv, Type.nil, false), locals, [], Utils::HashWrapper.new({}))
116
+ env = Env.new(StaticEnv.new(recv, Type.nil, false, false), locals, [], Utils::HashWrapper.new({}))
115
117
 
116
118
  return ep, env
117
119
  end
@@ -77,7 +77,9 @@ module TypeProf
77
77
  return env, Type.any if depth <= 0
78
78
  alloc_site = alloc_site.add_id(:cell).add_id(@base_type)
79
79
  env, elems = @elems.localize(env, alloc_site, depth)
80
- env.deploy_type(LocalCell, alloc_site, elems, @base_type)
80
+ ty = Local.new(Cell, alloc_site, @base_type)
81
+ env = env.deploy_type(alloc_site, elems)
82
+ return env, ty
81
83
  end
82
84
 
83
85
  def limit_size(limit)
@@ -85,7 +87,7 @@ module TypeProf
85
87
  Cell.new(@elems.limit_size(limit - 1), @base_type)
86
88
  end
87
89
 
88
- def get_method(mid, scratch)
90
+ def method_dispatch_info
89
91
  raise
90
92
  end
91
93
 
@@ -95,6 +97,19 @@ module TypeProf
95
97
  Cell.new(elems, @base_type)
96
98
  end
97
99
 
100
+ def generate_substitution
101
+ subst = {}
102
+ tyvars = @base_type.klass.type_params.map {|name,| Type::Var.new(name) }
103
+ tyvars.zip(@elems.elems) do |tyvar, elem|
104
+ if subst[tyvar]
105
+ subst[tyvar] = subst[tyvar].union(elem)
106
+ else
107
+ subst[tyvar] = elem
108
+ end
109
+ end
110
+ subst
111
+ end
112
+
98
113
  class Elements # Cell
99
114
  include Utils::StructuralEquality
100
115
 
@@ -102,10 +117,14 @@ module TypeProf
102
117
  @elems = elems
103
118
  end
104
119
 
120
+ def self.dummy_elements
121
+ Elements.new([]) # XXX
122
+ end
123
+
105
124
  attr_reader :elems
106
125
 
107
126
  def to_local_type(id, base_ty)
108
- Type::LocalCell.new(id, base_ty)
127
+ Type::Local.new(Cell, id, base_ty)
109
128
  end
110
129
 
111
130
  def globalize(env, visited, depth)
@@ -180,45 +199,6 @@ module TypeProf
180
199
  end
181
200
  end
182
201
 
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
-
222
202
  # Do not insert Array type to local environment, stack, etc.
223
203
  class Array < ContainerType
224
204
  def initialize(elems, base_type)
@@ -228,6 +208,10 @@ module TypeProf
228
208
  @base_type = base_type
229
209
  end
230
210
 
211
+ def self.dummy_elements
212
+ Elements.new([], Type.any)
213
+ end
214
+
231
215
  attr_reader :elems, :base_type
232
216
 
233
217
  def inspect
@@ -247,7 +231,9 @@ module TypeProf
247
231
  return env, Type.any if depth <= 0
248
232
  alloc_site = alloc_site.add_id(:ary).add_id(@base_type)
249
233
  env, elems = @elems.localize(env, alloc_site, depth - 1)
250
- env.deploy_type(LocalArray, alloc_site, elems, @base_type)
234
+ ty = Local.new(Array, alloc_site, @base_type)
235
+ env = env.deploy_type(alloc_site, elems)
236
+ return env, ty
251
237
  end
252
238
 
253
239
  def limit_size(limit)
@@ -255,7 +241,7 @@ module TypeProf
255
241
  Array.new(@elems.limit_size(limit - 1), @base_type)
256
242
  end
257
243
 
258
- def get_method(mid, scratch)
244
+ def method_dispatch_info
259
245
  raise
260
246
  end
261
247
 
@@ -265,6 +251,10 @@ module TypeProf
265
251
  Array.new(elems, @base_type)
266
252
  end
267
253
 
254
+ def generate_substitution
255
+ { Type::Var.new(:Elem) => @elems.squash }
256
+ end
257
+
268
258
  class Elements # Array
269
259
  include Utils::StructuralEquality
270
260
 
@@ -277,7 +267,7 @@ module TypeProf
277
267
  attr_reader :lead_tys, :rest_ty
278
268
 
279
269
  def to_local_type(id, base_ty)
280
- Type::LocalArray.new(id, base_ty)
270
+ Type::Local.new(Array, id, base_ty)
281
271
  end
282
272
 
283
273
  def globalize(env, visited, depth)
@@ -305,7 +295,10 @@ module TypeProf
305
295
  end
306
296
 
307
297
  def screen_name(scratch)
308
- if Config.options[:show_container_raw_elements] || @rest_ty == Type.bot
298
+ if @rest_ty == Type.bot
299
+ if @lead_tys.empty?
300
+ return "Array[bot]" # RBS does not allow an empty tuple "[]"
301
+ end
309
302
  s = @lead_tys.map do |ty|
310
303
  ty.screen_name(scratch)
311
304
  end
@@ -360,7 +353,57 @@ module TypeProf
360
353
  end
361
354
 
362
355
  def [](idx)
363
- if idx >= 0
356
+ if idx.is_a?(Range)
357
+ if @rest_ty == Type.bot
358
+ lead_tys = @lead_tys[idx]
359
+ if lead_tys
360
+ rest_ty = Type.bot
361
+ else
362
+ return Type.nil
363
+ end
364
+ else
365
+ b, e = idx.begin, idx.end
366
+ b = 0 if !b
367
+ if !e
368
+ lead_tys = @lead_tys[idx] || []
369
+ rest_ty = @rest_ty
370
+ elsif b >= 0
371
+ if e >= 0
372
+ if b <= e
373
+ if e < @lead_tys.size
374
+ lead_tys = @lead_tys[idx]
375
+ rest_ty = Type.bot
376
+ else
377
+ lead_tys = @lead_tys[idx] || []
378
+ rest_ty = @rest_ty
379
+ end
380
+ else
381
+ return Type.nil
382
+ end
383
+ else
384
+ lead_tys = @lead_tys[idx] || []
385
+ e = idx.exclude_end? ? e : e == -1 ? @lead_tys.size : e + 1
386
+ rest_ty = (@lead_tys[e + 1..] || []).inject(@rest_ty) {|ty0, ty1| ty0.union(ty1) }
387
+ end
388
+ else
389
+ lead_tys = []
390
+ if e >= 0
391
+ rest_ty = e < @lead_tys.size ? Type.bot : @rest_ty
392
+ range = [0, @lead_tys.size + b].max .. (idx.exclude_end? ? e - 1 : e)
393
+ rest_ty = @lead_tys[range].inject(rest_ty) {|ty0, ty1| ty0.union(ty1) }
394
+ else
395
+ if b <= e
396
+ range = [0, @lead_tys.size + b].max .. (idx.exclude_end? ? e - 1 : e)
397
+ rest_ty = @lead_tys[range].inject(@rest_ty) {|ty0, ty1| ty0.union(ty1) }
398
+ else
399
+ return Type.nil
400
+ end
401
+ end
402
+ end
403
+ end
404
+ base_ty = Type::Instance.new(Type::Builtin[:ary])
405
+ Array.new(Elements.new(lead_tys, rest_ty), base_ty)
406
+ elsif idx >= 0
364
407
  if idx < @lead_tys.size
365
408
  @lead_tys[idx]
366
409
  elsif @rest_ty == Type.bot
@@ -491,48 +534,6 @@ module TypeProf
491
534
  end
492
535
  end
493
536
 
494
- # Do not insert Array type to local environment, stack, etc.
495
- class LocalArray < ContainerType
496
- def initialize(id, base_type)
497
- @id = id
498
- raise unless base_type
499
- @base_type = base_type
500
- end
501
-
502
- attr_reader :id, :base_type
503
-
504
- def inspect
505
- "Type::LocalArray[#{ @id }, base_type: #{ @base_type.inspect }]"
506
- end
507
-
508
- def screen_name(scratch)
509
- #raise "LocalArray must not be included in signature"
510
- "LocalArray!"
511
- end
512
-
513
- def globalize(env, visited, depth)
514
- if visited[self] || depth <= 0
515
- Type.any
516
- else
517
- visited[self] = true
518
- elems = env.get_container_elem_types(@id)
519
- if elems
520
- elems = elems.globalize(env, visited, depth - 1)
521
- else
522
- # TODO: currently out-of-scope array cannot be accessed
523
- elems = Array::Elements.new([], Type.any)
524
- end
525
- visited.delete(self)
526
- Array.new(elems, @base_type)
527
- end
528
- end
529
-
530
- def get_method(mid, scratch)
531
- @base_type.get_method(mid, scratch)
532
- end
533
- end
534
-
535
-
536
537
  class Hash < ContainerType
537
538
  def initialize(elems, base_type)
538
539
  @elems = elems
@@ -554,7 +555,9 @@ module TypeProf
554
555
  return env, Type.any if depth <= 0
555
556
  alloc_site = alloc_site.add_id(:hash).add_id(@base_type)
556
557
  env, elems = @elems.localize(env, alloc_site, depth - 1)
557
- env.deploy_type(LocalHash, alloc_site, elems, @base_type)
558
+ ty = Local.new(Hash, alloc_site, @base_type)
559
+ env = env.deploy_type(alloc_site, elems)
560
+ return env, ty
558
561
  end
559
562
 
560
563
  def limit_size(limit)
@@ -562,7 +565,7 @@ module TypeProf
562
565
  Hash.new(@elems.limit_size(limit - 1), @base_type)
563
566
  end
564
567
 
565
- def get_method(mid, scratch)
568
+ def method_dispatch_info
566
569
  raise
567
570
  end
568
571
 
@@ -572,6 +575,14 @@ module TypeProf
572
575
  Hash.new(elems, @base_type)
573
576
  end
574
577
 
578
+ def generate_substitution
579
+ tyvar_k = Type::Var.new(:K)
580
+ tyvar_v = Type::Var.new(:V)
581
+ k_ty0, v_ty0 = @elems.squash
582
+ # XXX: need to heuristically replace ret type Hash[K, V] with self, instead of conversative type?
583
+ { tyvar_k => k_ty0, tyvar_v => v_ty0 }
584
+ end
585
+
575
586
  class Elements # Hash
576
587
  include Utils::StructuralEquality
577
588
 
@@ -580,18 +591,21 @@ module TypeProf
580
591
  raise unless k_ty.is_a?(Type)
581
592
  raise unless v_ty.is_a?(Type)
582
593
  raise if k_ty.is_a?(Type::Union)
583
- raise if k_ty.is_a?(Type::LocalArray)
584
- raise if k_ty.is_a?(Type::LocalHash)
594
+ raise if k_ty.is_a?(Type::Local)
585
595
  raise if k_ty.is_a?(Type::Array)
586
596
  raise if k_ty.is_a?(Type::Hash)
587
597
  end
588
598
  @map_tys = map_tys
589
599
  end
590
600
 
601
+ def self.dummy_elements
602
+ Elements.new({Type.any => Type.any})
603
+ end
604
+
591
605
  attr_reader :map_tys
592
606
 
593
607
  def to_local_type(id, base_ty)
594
- Type::LocalHash.new(id, base_ty)
608
+ Type::Local.new(Hash, id, base_ty)
595
609
  end
596
610
 
597
611
  def globalize(env, visited, depth)
@@ -631,16 +645,22 @@ module TypeProf
631
645
  end
632
646
 
633
647
  def screen_name(scratch)
634
- s = @map_tys.map do |k_ty, v_ty|
635
- v = v_ty.screen_name(scratch)
636
- if k_ty.is_a?(Type::Symbol)
648
+ if !@map_tys.empty? && @map_tys.all? {|k_ty,| k_ty.is_a?(Type::Symbol) }
649
+ s = @map_tys.map do |k_ty, v_ty|
650
+ v = v_ty.screen_name(scratch)
637
651
  "#{ k_ty.sym }: #{ v }"
638
- else
639
- k = k_ty.screen_name(scratch)
640
- "#{ k }=>#{ v }"
652
+ end.join(", ")
653
+ "{#{ s }}"
654
+ else
655
+ k_ty = v_ty = Type.bot
656
+ @map_tys.each do |k, v|
657
+ k_ty = k_ty.union(k)
658
+ v_ty = v_ty.union(v)
641
659
  end
642
- end.join(", ")
643
- "{#{ s }}"
660
+ k_ty = k_ty.screen_name(scratch)
661
+ v_ty = v_ty.screen_name(scratch)
662
+ "Hash[#{ k_ty }, #{ v_ty }]"
663
+ end
644
664
  end
645
665
 
646
666
  def pretty_print(q)
@@ -773,21 +793,23 @@ module TypeProf
773
793
  end
774
794
  end
775
795
 
776
- class LocalHash < ContainerType
777
- def initialize(id, base_type)
796
+ class Local < ContainerType
797
+ def initialize(kind, id, base_type)
798
+ @kind = kind
778
799
  @id = id
800
+ raise unless base_type
779
801
  @base_type = base_type
780
802
  end
781
803
 
782
- attr_reader :id, :base_type
804
+ attr_reader :kind, :id, :base_type
783
805
 
784
806
  def inspect
785
- "Type::LocalHash[#{ @id }]"
807
+ "Type::Local[#{ @kind }, #{ @id }, base_type: #{ @base_type.inspect }]"
786
808
  end
787
809
 
788
810
  def screen_name(scratch)
789
- #raise "LocalHash must not be included in signature"
790
- "LocalHash!"
811
+ #raise "Local type must not be included in signature"
812
+ "Local[#{ @kind }]"
791
813
  end
792
814
 
793
815
  def globalize(env, visited, depth)
@@ -799,15 +821,56 @@ module TypeProf
799
821
  if elems
800
822
  elems = elems.globalize(env, visited, depth - 1)
801
823
  else
802
- elems = Hash::Elements.new({Type.any => Type.any})
824
+ # TODO: currently out-of-scope array cannot be accessed
825
+ elems = @kind::Elements.dummy_elements
803
826
  end
804
827
  visited.delete(self)
805
- Hash.new(elems, @base_type)
828
+ @kind.new(elems, @base_type)
806
829
  end
807
830
  end
808
831
 
809
- def get_method(mid, scratch)
810
- @base_type.get_method(mid, scratch)
832
+ def method_dispatch_info
833
+ @base_type.method_dispatch_info
834
+ end
835
+
836
+ def update_container_elem_type(subst, env, caller_ep, scratch)
837
+ case
838
+ when @kind == Cell
839
+ tyvars = @base_type.klass.type_params.map {|name,| Type::Var.new(name) }
840
+ # XXX: This should be skipped when the called methods belongs to superclass
841
+ tyvars.each_with_index do |tyvar, idx|
842
+ ty = subst[tyvar]
843
+ if ty
844
+ env, ty = scratch.localize_type(ty, env, caller_ep)
845
+ env = scratch.update_container_elem_types(env, caller_ep, @id, @base_type) do |elems|
846
+ elems.update(idx, ty)
847
+ end
848
+ end
849
+ end
850
+ when @kind == Array
851
+ tyvar_elem = Type::Var.new(:Elem)
852
+ if subst[tyvar_elem]
853
+ ty = subst[tyvar_elem]
854
+ env, ty = scratch.localize_type(ty, env, caller_ep)
855
+ env = scratch.update_container_elem_types(env, caller_ep, @id, @base_type) do |elems|
856
+ elems.update(nil, ty)
857
+ end
858
+ end
859
+ when @kind == Hash
860
+ tyvar_k = Type::Var.new(:K)
861
+ tyvar_v = Type::Var.new(:V)
862
+ if subst[tyvar_k] && subst[tyvar_v]
863
+ k_ty = subst[tyvar_k]
864
+ v_ty = subst[tyvar_v]
865
+ alloc_site = AllocationSite.new(caller_ep)
866
+ env, k_ty = scratch.localize_type(k_ty, env, caller_ep, alloc_site.add_id(:k))
867
+ env, v_ty = scratch.localize_type(v_ty, env, caller_ep, alloc_site.add_id(:v))
868
+ env = scratch.update_container_elem_types(env, caller_ep, @id, @base_type) do |elems|
869
+ elems.update(k_ty, v_ty)
870
+ end
871
+ end
872
+ end
873
+ env
811
874
  end
812
875
  end
813
876
  end