typeprof 0.3.0 → 0.4.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 (74) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile.lock +1 -1
  3. data/doc/demo.md +398 -0
  4. data/doc/doc.ja.md +4 -0
  5. data/doc/doc.md +4 -0
  6. data/lib/typeprof.rb +8 -0
  7. data/lib/typeprof/analyzer.rb +229 -245
  8. data/lib/typeprof/arguments.rb +397 -0
  9. data/lib/typeprof/block.rb +133 -0
  10. data/lib/typeprof/builtin.rb +14 -10
  11. data/lib/typeprof/container-type.rb +94 -17
  12. data/lib/typeprof/export.rb +185 -108
  13. data/lib/typeprof/import.rb +76 -54
  14. data/lib/typeprof/iseq.rb +27 -2
  15. data/lib/typeprof/method.rb +87 -73
  16. data/lib/typeprof/type.rb +125 -309
  17. data/lib/typeprof/version.rb +1 -1
  18. data/smoke/arguments2.rb +1 -1
  19. data/smoke/array-each3.rb +1 -4
  20. data/smoke/array12.rb +1 -1
  21. data/smoke/array6.rb +1 -0
  22. data/smoke/block-ambiguous.rb +36 -0
  23. data/smoke/block-args1-rest.rb +62 -0
  24. data/smoke/block-args1.rb +59 -0
  25. data/smoke/block-args2-rest.rb +62 -0
  26. data/smoke/block-args2.rb +59 -0
  27. data/smoke/block-args3-rest.rb +73 -0
  28. data/smoke/block-args3.rb +70 -0
  29. data/smoke/block-blockarg.rb +27 -0
  30. data/smoke/block-kwarg.rb +52 -0
  31. data/smoke/block11.rb +1 -1
  32. data/smoke/block14.rb +17 -0
  33. data/smoke/block4.rb +2 -2
  34. data/smoke/block5.rb +1 -0
  35. data/smoke/block6.rb +1 -1
  36. data/smoke/block7.rb +0 -2
  37. data/smoke/block8.rb +2 -2
  38. data/smoke/block9.rb +1 -1
  39. data/smoke/blown.rb +1 -1
  40. data/smoke/class-hierarchy.rb +54 -0
  41. data/smoke/class-hierarchy2.rb +27 -0
  42. data/smoke/constant1.rb +11 -6
  43. data/smoke/constant2.rb +2 -0
  44. data/smoke/cvar.rb +1 -0
  45. data/smoke/demo10.rb +1 -1
  46. data/smoke/demo8.rb +2 -2
  47. data/smoke/demo9.rb +1 -3
  48. data/smoke/flow7.rb +1 -7
  49. data/smoke/flow8.rb +13 -0
  50. data/smoke/instance_eval.rb +1 -1
  51. data/smoke/int_times.rb +1 -1
  52. data/smoke/multiple-superclass.rb +4 -0
  53. data/smoke/next2.rb +1 -1
  54. data/smoke/optional3.rb +10 -0
  55. data/smoke/proc4.rb +1 -1
  56. data/smoke/rbs-proc1.rb +9 -0
  57. data/smoke/rbs-proc1.rbs +3 -0
  58. data/smoke/rbs-proc2.rb +20 -0
  59. data/smoke/rbs-proc2.rbs +3 -0
  60. data/smoke/rbs-proc3.rb +13 -0
  61. data/smoke/rbs-proc3.rbs +4 -0
  62. data/smoke/rbs-record.rb +17 -0
  63. data/smoke/rbs-record.rbs +4 -0
  64. data/smoke/rbs-tyvar3.rb +25 -0
  65. data/smoke/rbs-tyvar3.rbs +4 -0
  66. data/smoke/rest2.rb +1 -1
  67. data/smoke/rest5.rb +1 -1
  68. data/smoke/return.rb +1 -1
  69. data/smoke/singleton_method.rb +3 -0
  70. data/smoke/struct.rb +4 -3
  71. data/smoke/struct3.rb +14 -0
  72. data/smoke/symbol-proc.rb +24 -0
  73. metadata +31 -3
  74. data/smoke/variadic1.rb.notyet +0 -5
@@ -182,22 +182,8 @@ module TypeProf
182
182
  Env.new(@static_env, Utils.array_update(@locals, idx, ty), @stack, @type_params)
183
183
  end
184
184
 
185
- def deploy_cell_type(alloc_site, elems, base_ty)
186
- local_ty = Type::LocalCell.new(alloc_site, base_ty)
187
- type_params = Utils::HashWrapper.new(@type_params.internal_hash.merge({ alloc_site => elems }))
188
- nenv = Env.new(@static_env, @locals, @stack, type_params)
189
- return nenv, local_ty
190
- end
191
-
192
- def deploy_array_type(alloc_site, elems, base_ty)
193
- local_ty = Type::LocalArray.new(alloc_site, base_ty)
194
- type_params = Utils::HashWrapper.new(@type_params.internal_hash.merge({ alloc_site => elems }))
195
- nenv = Env.new(@static_env, @locals, @stack, type_params)
196
- return nenv, local_ty
197
- end
198
-
199
- def deploy_hash_type(alloc_site, elems, base_ty)
200
- local_ty = Type::LocalHash.new(alloc_site, base_ty)
185
+ def deploy_type(klass, alloc_site, elems, base_ty)
186
+ local_ty = klass.new(alloc_site, base_ty)
201
187
  type_params = Utils::HashWrapper.new(@type_params.internal_hash.merge({ alloc_site => elems }))
202
188
  nenv = Env.new(@static_env, @locals, @stack, type_params)
203
189
  return nenv, local_ty
@@ -244,8 +230,11 @@ module TypeProf
244
230
 
245
231
  @alloc_site_to_global_id = {}
246
232
 
247
- @callsites, @return_envs, @sig_fargs, @sig_ret, @yields = {}, {}, {}, {}, {}
233
+ @callsites, @return_envs = {}, {}
248
234
  @block_to_ctx = {}
235
+ @method_signatures = {}
236
+ @block_signatures = {}
237
+ @return_values = {}
249
238
  @gvar_table = VarTable.new
250
239
 
251
240
  @errors = []
@@ -288,6 +277,7 @@ module TypeProf
288
277
 
289
278
  class ClassDef # or ModuleDef
290
279
  def initialize(kind, name, superclass, absolute_path)
280
+ raise unless name.is_a?(Array)
291
281
  @kind = kind
292
282
  @superclass = superclass
293
283
  @modules = { true => {}, false => {} }
@@ -297,9 +287,10 @@ module TypeProf
297
287
  @ivars = VarTable.new
298
288
  @cvars = VarTable.new
299
289
  @absolute_path = absolute_path
290
+ @namespace = nil
300
291
  end
301
292
 
302
- attr_reader :kind, :modules, :methods, :superclass, :ivars, :cvars, :absolute_path
293
+ attr_reader :kind, :superclass, :modules, :consts, :methods, :ivars, :cvars, :absolute_path
303
294
  attr_accessor :name, :klass_obj
304
295
 
305
296
  def include_module(mod, absolute_path)
@@ -321,14 +312,15 @@ module TypeProf
321
312
  end
322
313
 
323
314
  def get_constant(name)
324
- @consts[name] || Type.any # XXX: warn?
315
+ ty, = @consts[name]
316
+ ty || Type.any # XXX: warn?
325
317
  end
326
318
 
327
- def add_constant(name, ty)
319
+ def add_constant(name, ty, absolute_path)
328
320
  if @consts[name]
329
321
  # XXX: warn!
330
322
  end
331
- @consts[name] = ty
323
+ @consts[name] = [ty, absolute_path]
332
324
  end
333
325
 
334
326
  def get_method(mid, singleton)
@@ -391,12 +383,12 @@ module TypeProf
391
383
  end
392
384
  end
393
385
 
386
+ def cbase_path(cbase)
387
+ cbase && cbase.idx != 1 ? @class_defs[cbase.idx].name : []
388
+ end
389
+
394
390
  def new_class(cbase, name, type_params, superclass, absolute_path)
395
- if cbase && cbase.idx != 1
396
- show_name = "#{ @class_defs[cbase.idx].name }::#{ name }"
397
- else
398
- show_name = name.to_s
399
- end
391
+ show_name = cbase_path(cbase) + [name]
400
392
  idx = @class_defs.size
401
393
  if superclass
402
394
  if superclass == :__root__
@@ -408,14 +400,14 @@ module TypeProf
408
400
  klass = Type::Class.new(:class, idx, type_params, superclass, show_name)
409
401
  @class_defs[idx].klass_obj = klass
410
402
  cbase ||= klass # for bootstrap
411
- add_constant(cbase, name, klass)
403
+ add_constant(cbase, name, klass, absolute_path)
412
404
  return klass
413
405
  else
414
406
  # module
415
407
  @class_defs[idx] = ClassDef.new(:module, show_name, nil, absolute_path)
416
408
  mod = Type::Class.new(:module, idx, type_params, nil, show_name)
417
409
  @class_defs[idx].klass_obj = mod
418
- add_constant(cbase, name, mod)
410
+ add_constant(cbase, name, mod, absolute_path)
419
411
  return mod
420
412
  end
421
413
  end
@@ -425,8 +417,8 @@ module TypeProf
425
417
 
426
418
  idx = @class_defs.size
427
419
  superclass = Type::Builtin[:struct]
428
- @class_defs[idx] = ClassDef.new(:class, "(Struct)", superclass.idx, ep.ctx.iseq.absolute_path)
429
- klass = Type::Class.new(:class, idx, [], superclass, "(Struct)")
420
+ @class_defs[idx] = ClassDef.new(:class, ["(Anonymous Struct)"], superclass.idx, ep.ctx.iseq.absolute_path)
421
+ klass = Type::Class.new(:class, idx, [], superclass, "(Anonymous Struct)")
430
422
  @class_defs[idx].klass_obj = klass
431
423
 
432
424
  @struct_defs[ep] = klass
@@ -434,11 +426,25 @@ module TypeProf
434
426
  klass
435
427
  end
436
428
 
429
+ attr_accessor :namespace
430
+
437
431
  def get_class_name(klass)
438
432
  if klass == Type.any
439
433
  "???"
440
434
  else
441
- @class_defs[klass.idx].name
435
+ path = @class_defs[klass.idx].name
436
+ if @namespace
437
+ i = 0
438
+ i += 1 while @namespace[i] && @namespace[i] == path[i]
439
+ if path[i]
440
+ path[i..].join("::")
441
+ else
442
+ path.last.to_s
443
+ end
444
+ else
445
+ #"::" + path.join("::")
446
+ path.join("::")
447
+ end
442
448
  end
443
449
  end
444
450
 
@@ -488,11 +494,11 @@ module TypeProf
488
494
  Type.any
489
495
  end
490
496
 
491
- def add_constant(klass, name, value)
497
+ def add_constant(klass, name, value, user_defined)
492
498
  if klass == Type.any
493
499
  self
494
500
  else
495
- @class_defs[klass.idx].add_constant(name, value)
501
+ @class_defs[klass.idx].add_constant(name, value, user_defined)
496
502
  end
497
503
  end
498
504
 
@@ -527,14 +533,6 @@ module TypeProf
527
533
  add_method(klass, mid, true, ISeqMethodDef.new(iseq, cref))
528
534
  end
529
535
 
530
- def add_typed_method(recv_ty, mid, fargs, ret_ty)
531
- add_method(recv_ty.klass, mid, false, TypedMethodDef.new([[fargs, ret_ty]]))
532
- end
533
-
534
- def add_singleton_typed_method(recv_ty, mid, fargs, ret_ty)
535
- add_method(recv_ty.klass, mid, true, TypedMethodDef.new([[fargs, ret_ty]]))
536
- end
537
-
538
536
  def set_custom_method(klass, mid, impl)
539
537
  set_method(klass, mid, false, CustomMethodDef.new(impl))
540
538
  end
@@ -572,7 +570,7 @@ module TypeProf
572
570
  @callsites[callee_ctx][caller_ep] = ctn
573
571
  merge_return_env(caller_ep) {|env| env ? env.merge(caller_env) : caller_env }
574
572
 
575
- ret_ty = @sig_ret[callee_ctx] ||= Type.bot
573
+ ret_ty = @return_values[callee_ctx] ||= Type.bot
576
574
  if ret_ty != Type.bot
577
575
  @callsites[callee_ctx].each do |caller_ep, ctn|
578
576
  ctn[ret_ty, caller_ep, @return_envs[caller_ep]]
@@ -580,11 +578,11 @@ module TypeProf
580
578
  end
581
579
  end
582
580
 
583
- def add_signature!(callee_ctx, fargs)
584
- if @sig_fargs[callee_ctx]
585
- @sig_fargs[callee_ctx] = @sig_fargs[callee_ctx].merge(fargs)
581
+ def add_method_signature!(callee_ctx, msig)
582
+ if @method_signatures[callee_ctx]
583
+ @method_signatures[callee_ctx] = @method_signatures[callee_ctx].merge(msig)
586
584
  else
587
- @sig_fargs[callee_ctx] = fargs
585
+ @method_signatures[callee_ctx] = msig
588
586
  end
589
587
  end
590
588
 
@@ -592,9 +590,9 @@ module TypeProf
592
590
  @return_envs[caller_ep] = yield @return_envs[caller_ep]
593
591
  end
594
592
 
595
- def add_return_type!(callee_ctx, ret_ty)
596
- @sig_ret[callee_ctx] ||= Type.bot
597
- @sig_ret[callee_ctx] = @sig_ret[callee_ctx].union(ret_ty)
593
+ def add_return_value!(callee_ctx, ret_ty)
594
+ @return_values[callee_ctx] ||= Type.bot
595
+ @return_values[callee_ctx] = @return_values[callee_ctx].union(ret_ty)
598
596
 
599
597
  @callsites[callee_ctx] ||= {}
600
598
  @callsites[callee_ctx].each do |caller_ep, ctn|
@@ -602,19 +600,18 @@ module TypeProf
602
600
  end
603
601
  end
604
602
 
605
- def add_yield!(caller_ctx, aargs, blk_ctx)
606
- aargs_acc, = @yields[caller_ctx]
607
- if aargs_acc
608
- @yields[caller_ctx][0] = aargs_acc.merge(aargs)
609
- else
610
- @yields[caller_ctx] = [aargs, Utils::MutableSet.new]
611
- end
612
- @yields[caller_ctx][1] << blk_ctx
603
+ def add_block_to_ctx!(block_body, ctx)
604
+ raise if !block_body.is_a?(Block)
605
+ @block_to_ctx[block_body] ||= Utils::MutableSet.new
606
+ @block_to_ctx[block_body] << ctx
613
607
  end
614
608
 
615
- def add_block_to_ctx!(blk, ctx)
616
- @block_to_ctx[blk] ||= Utils::MutableSet.new
617
- @block_to_ctx[blk] << ctx
609
+ def add_block_signature!(block_body, bsig)
610
+ if @block_signatures[block_body]
611
+ @block_signatures[block_body] = @block_signatures[block_body].merge(bsig)
612
+ else
613
+ @block_signatures[block_body] = bsig
614
+ end
618
615
  end
619
616
 
620
617
  class VarTable
@@ -736,7 +733,7 @@ module TypeProf
736
733
  env.get_container_elem_types(id)
737
734
  end
738
735
 
739
- def update_container_elem_types(env, ep, id)
736
+ def update_container_elem_types(env, ep, id, base_type)
740
737
  if ep.outer
741
738
  tmp_ep = ep
742
739
  tmp_ep = tmp_ep.outer while tmp_ep.outer
@@ -746,7 +743,7 @@ module TypeProf
746
743
  menv = menv.update_container_elem_types(id, elems)
747
744
  gid = @alloc_site_to_global_id[id]
748
745
  if gid
749
- ty = globalize_type(elems.to_local_type(id), env, ep)
746
+ ty = globalize_type(elems.to_local_type(id, base_type), env, ep)
750
747
  add_ivar_write!(*gid, ty, ep)
751
748
  end
752
749
  menv
@@ -758,7 +755,7 @@ module TypeProf
758
755
  env = env.update_container_elem_types(id, elems)
759
756
  gid = @alloc_site_to_global_id[id]
760
757
  if gid
761
- ty = globalize_type(elems.to_local_type(id), env, ep)
758
+ ty = globalize_type(elems.to_local_type(id, base_type), env, ep)
762
759
  add_ivar_write!(*gid, ty, ep)
763
760
  end
764
761
  env
@@ -770,7 +767,7 @@ module TypeProf
770
767
 
771
768
  if elems
772
769
  return elems[idx] || Type.nil if idx
773
- return elems.squash
770
+ return elems.squash_or_any
774
771
  else
775
772
  Type.any
776
773
  end
@@ -836,9 +833,10 @@ module TypeProf
836
833
  add_iseq_method_call!(meth, ep.ctx)
837
834
 
838
835
  when :block
839
- epenvs = dummy_continuation
836
+ blk, epenvs = dummy_continuation
840
837
  epenvs.each do |ep, env|
841
838
  merge_env(ep, env)
839
+ add_block_to_ctx!(blk.block_body, ep.ctx)
842
840
  end
843
841
  end
844
842
  end
@@ -856,12 +854,7 @@ module TypeProf
856
854
 
857
855
  Reporters.show_gvars(self, @gvar_table, output)
858
856
 
859
- #RubySignatureExporter2.new(
860
- # self, @include_relations, @ivar_table.write, @cvar_table.write, @class_defs
861
- #).show
862
-
863
- #return
864
- RubySignatureExporter.new(self, @class_defs, @iseq_method_to_ctxs, @sig_fargs, @sig_ret, @yields).show(stat_eps, output)
857
+ RubySignatureExporter.new(self, @class_defs, @iseq_method_to_ctxs).show(stat_eps, output)
865
858
  end
866
859
 
867
860
  def globalize_type(ty, env, ep)
@@ -915,12 +908,12 @@ module TypeProf
915
908
  @pending_execution[iseq] ||= [:method, [meth, ep, env]]
916
909
  end
917
910
 
918
- def pend_block_dummy_execution(iseq, nep, nenv)
919
- @pending_execution[iseq] ||= [:block, {}]
920
- if @pending_execution[iseq][1][nep]
921
- @pending_execution[iseq][1][nep] = @pending_execution[iseq][1][nep].merge(nenv)
911
+ def pend_block_dummy_execution(blk, iseq, nep, nenv)
912
+ @pending_execution[iseq] ||= [:block, [blk, {}]]
913
+ if @pending_execution[iseq][1][1][nep]
914
+ @pending_execution[iseq][1][1][nep] = @pending_execution[iseq][1][1][nep].merge(nenv)
922
915
  else
923
- @pending_execution[iseq][1][nep] = nenv
916
+ @pending_execution[iseq][1][1][nep] = nenv
924
917
  end
925
918
  end
926
919
 
@@ -929,7 +922,7 @@ module TypeProf
929
922
  alloc_site = AllocationSite.new(ep)
930
923
  nenv, ty = localize_type(ty, env, ep, alloc_site)
931
924
  case ty
932
- when Type::LocalArray, Type::LocalHash
925
+ when Type::LocalCell, Type::LocalArray, Type::LocalHash
933
926
  @alloc_site_to_global_id[ty.id] = [recv, var] # need overwrite check??
934
927
  end
935
928
  yield ty, nenv
@@ -954,7 +947,7 @@ module TypeProf
954
947
  end
955
948
 
956
949
  case insn
957
- when :_method_body
950
+ when :_iseq_body_start
958
951
  # XXX: reconstruct and record the method signature
959
952
  iseq = ep.ctx.iseq
960
953
  lead_num = iseq.fargs_format[:lead_num] || 0
@@ -1006,9 +999,15 @@ module TypeProf
1006
999
  end
1007
1000
  end
1008
1001
  kw_rest_ty = globalize_type(env.locals[kw_rest], env, ep) if kw_rest
1009
- blk_ty = block_start ? globalize_type(env.locals[block_start], env, ep) : Type.nil
1010
- fargs = FormalArguments.new(lead_tys, opt_tys, rest_ty, post_tys, kw_tys, kw_rest_ty, blk_ty)
1011
- add_signature!(ep.ctx, fargs)
1002
+ if block_start
1003
+ blk_ty = globalize_type(env.locals[block_start], env, ep)
1004
+ elsif iseq.type == :method
1005
+ blk_ty = env.static_env.blk_ty
1006
+ else
1007
+ blk_ty = Type.nil
1008
+ end
1009
+ msig = MethodSignature.new(lead_tys, opt_tys, rest_ty, post_tys, kw_tys, kw_rest_ty, blk_ty)
1010
+ add_method_signature!(ep.ctx, msig)
1012
1011
  when :putspecialobject
1013
1012
  kind, = operands
1014
1013
  ty = case kind
@@ -1188,7 +1187,7 @@ module TypeProf
1188
1187
  end
1189
1188
  return
1190
1189
  when :send
1191
- env, recvs, mid, aargs = setup_actual_arguments(operands, ep, env)
1190
+ env, recvs, mid, aargs = setup_actual_arguments(:method, operands, ep, env)
1192
1191
  recvs = Type.any if recvs == Type.bot
1193
1192
  recvs.each_child do |recv|
1194
1193
  do_send(recv, mid, aargs, ep, env) do |ret_ty, ep, env|
@@ -1200,7 +1199,7 @@ module TypeProf
1200
1199
  return
1201
1200
  when :send_branch
1202
1201
  getlocal_operands, send_operands, branch_operands = operands
1203
- env, recvs, mid, aargs = setup_actual_arguments(send_operands, ep, env)
1202
+ env, recvs, mid, aargs = setup_actual_arguments(:method, send_operands, ep, env)
1204
1203
  recvs = Type.any if recvs == Type.bot
1205
1204
  recvs.each_child do |recv|
1206
1205
  do_send(recv, mid, aargs, ep, env) do |ret_ty, ep, env|
@@ -1227,11 +1226,7 @@ module TypeProf
1227
1226
  end
1228
1227
  return
1229
1228
  when :invokeblock
1230
- # XXX: need block parameter, unknown block, etc. Use setup_actual_arguments
1231
- opt, = operands
1232
- _flags = opt[:flag]
1233
- orig_argc = opt[:orig_argc]
1234
- env, aargs = env.pop(orig_argc)
1229
+ env, recvs, mid, aargs = setup_actual_arguments(:block, operands, ep, env)
1235
1230
  blk = env.static_env.blk_ty
1236
1231
  case
1237
1232
  when blk == Type.nil
@@ -1240,10 +1235,7 @@ module TypeProf
1240
1235
  #warn(ep, "block is any")
1241
1236
  env = env.push(Type.any)
1242
1237
  else # Proc
1243
- blk_nil = Type.nil
1244
- #
1245
- aargs = ActualArguments.new(aargs, nil, {}, blk_nil)
1246
- do_invoke_block(true, env.static_env.blk_ty, aargs, ep, env) do |ret_ty, ep, env|
1238
+ do_invoke_block(blk, aargs, ep, env) do |ret_ty, ep, env|
1247
1239
  nenv, ret_ty, = localize_type(ret_ty, env, ep)
1248
1240
  nenv = nenv.push(ret_ty)
1249
1241
  merge_env(ep.next, nenv)
@@ -1251,7 +1243,7 @@ module TypeProf
1251
1243
  return
1252
1244
  end
1253
1245
  when :invokesuper
1254
- env, recv, _, aargs = setup_actual_arguments(operands, ep, env)
1246
+ env, recv, _, aargs = setup_actual_arguments(:method, operands, ep, env)
1255
1247
 
1256
1248
  env, recv = localize_type(env.static_env.recv_ty, env, ep)
1257
1249
  mid = ep.ctx.mid
@@ -1284,7 +1276,7 @@ module TypeProf
1284
1276
  end
1285
1277
  env, (ty,) = env.pop(1)
1286
1278
  ty = globalize_type(ty, env, ep)
1287
- add_return_type!(ep.ctx, ty)
1279
+ add_return_value!(ep.ctx, ty)
1288
1280
  return
1289
1281
  when :throw
1290
1282
  throwtype, = operands
@@ -1298,7 +1290,7 @@ module TypeProf
1298
1290
  ty = globalize_type(ty, env, ep)
1299
1291
  tmp_ep = ep
1300
1292
  tmp_ep = tmp_ep.outer while tmp_ep.outer
1301
- add_return_type!(tmp_ep.ctx, ty)
1293
+ add_return_value!(tmp_ep.ctx, ty)
1302
1294
  return
1303
1295
  when :break
1304
1296
  tmp_ep = ep
@@ -1444,8 +1436,37 @@ module TypeProf
1444
1436
  flow_env = env.local_update(-var_idx+2, ret_ty)
1445
1437
  case ret_ty
1446
1438
  when Type.any
1447
- merge_env(ep_then, env)
1448
- merge_env(ep_else, env)
1439
+ merge_env(ep_then, flow_env)
1440
+ merge_env(ep_else, flow_env)
1441
+ when Type::Instance.new(Type::Builtin[:false]), Type.nil
1442
+ merge_env(branchtype == :if ? ep_then : ep_else, flow_env)
1443
+ else
1444
+ merge_env(branchtype == :if ? ep_else : ep_then, flow_env)
1445
+ end
1446
+ end
1447
+ return
1448
+ when :getlocal_dup_branch
1449
+ getlocal_operands, _dup_operands, branch_operands = operands
1450
+ var_idx, _scope_idx, _escaped = getlocal_operands
1451
+ ret_ty = env.get_local(-var_idx+2)
1452
+ unless ret_ty
1453
+ p env.locals
1454
+ raise
1455
+ end
1456
+
1457
+ branchtype, target, = branch_operands
1458
+ # branchtype: :if or :unless or :nil
1459
+ ep_then = ep.next
1460
+ ep_else = ep.jump(target)
1461
+
1462
+ var_idx, _scope_idx, _escaped = getlocal_operands
1463
+
1464
+ ret_ty.each_child do |ret_ty|
1465
+ flow_env = env.local_update(-var_idx+2, ret_ty).push(ret_ty)
1466
+ case ret_ty
1467
+ when Type.any
1468
+ merge_env(ep_then, flow_env)
1469
+ merge_env(ep_else, flow_env)
1449
1470
  when Type::Instance.new(Type::Builtin[:false]), Type.nil
1450
1471
  merge_env(branchtype == :if ? ep_then : ep_else, flow_env)
1451
1472
  else
@@ -1469,6 +1490,10 @@ module TypeProf
1469
1490
 
1470
1491
  ret_ty.each_child do |ret_ty|
1471
1492
  flow_env = env.local_update(-var_idx+2, ret_ty)
1493
+ ret_ty = ret_ty.base_type if ret_ty.is_a?(Type::Symbol)
1494
+ ret_ty = ret_ty.base_type if ret_ty.is_a?(Type::LocalCell)
1495
+ ret_ty = ret_ty.base_type if ret_ty.is_a?(Type::LocalArray)
1496
+ ret_ty = ret_ty.base_type if ret_ty.is_a?(Type::LocalHash)
1472
1497
  if ret_ty.is_a?(Type::Instance)
1473
1498
  if ret_ty.klass == pattern_ty # XXX: inheritance
1474
1499
  merge_env(branchtype == :if ? ep_else : ep_then, flow_env)
@@ -1476,8 +1501,8 @@ module TypeProf
1476
1501
  merge_env(branchtype == :if ? ep_then : ep_else, flow_env)
1477
1502
  end
1478
1503
  else
1479
- merge_env(ep_then, env)
1480
- merge_env(ep_else, env)
1504
+ merge_env(ep_then, flow_env)
1505
+ merge_env(ep_else, flow_env)
1481
1506
  end
1482
1507
  end
1483
1508
  return
@@ -1518,10 +1543,10 @@ module TypeProf
1518
1543
  end
1519
1544
  ty.each_child do |ty|
1520
1545
  if ty.is_a?(Type::Class) && ty.superclass == Type::Builtin[:struct]
1521
- @class_defs[ty.idx].name = name.to_s
1546
+ @class_defs[ty.idx].name = cbase_path(cbase) + [name]
1522
1547
  end
1523
1548
  end
1524
- add_constant(cbase, name, globalize_type(ty, env, ep))
1549
+ add_constant(cbase, name, globalize_type(ty, env, ep), ep.ctx.iseq.absolute_path)
1525
1550
 
1526
1551
  when :getspecial
1527
1552
  key, type = operands
@@ -1550,6 +1575,28 @@ module TypeProf
1550
1575
  when :dup
1551
1576
  env, (ty,) = env.pop(1)
1552
1577
  env = env.push(ty).push(ty)
1578
+ when :dup_branch
1579
+ _dup_operands, branch_operands = operands
1580
+ env, (ty,) = env.pop(1)
1581
+
1582
+ branchtype, target, = branch_operands
1583
+ # branchtype: :if or :unless or :nil
1584
+ ep_then = ep.next
1585
+ ep_else = ep.jump(target)
1586
+
1587
+ ty.each_child do |ty|
1588
+ flow_env = env.push(ty)
1589
+ case ty
1590
+ when Type.any
1591
+ merge_env(ep_then, flow_env)
1592
+ merge_env(ep_else, flow_env)
1593
+ when Type::Instance.new(Type::Builtin[:false]), Type.nil
1594
+ merge_env(branchtype == :if ? ep_then : ep_else, flow_env)
1595
+ else
1596
+ merge_env(branchtype == :if ? ep_else : ep_then, flow_env)
1597
+ end
1598
+ end
1599
+ return
1553
1600
  when :duphash
1554
1601
  raw_hash, = operands
1555
1602
  ty = Type.guess_literal_type(raw_hash)
@@ -1639,11 +1686,11 @@ module TypeProf
1639
1686
  if ary2.is_a?(Type::LocalArray)
1640
1687
  elems2 = get_container_elem_types(env, ep, ary2.id)
1641
1688
  elems = Type::Array::Elements.new([], elems1.squash.union(elems2.squash))
1642
- env = update_container_elem_types(env, ep, ary1.id) { elems }
1689
+ env = update_container_elem_types(env, ep, ary1.id, ary1.base_type) { elems }
1643
1690
  env = env.push(ary1)
1644
1691
  else
1645
1692
  elems = Type::Array::Elements.new([], Type.any)
1646
- env = update_container_elem_types(env, ep, ary1.id) { elems }
1693
+ env = update_container_elem_types(env, ep, ary1.id, ary1.base_type) { elems }
1647
1694
  env = env.push(ary1)
1648
1695
  end
1649
1696
  else
@@ -1714,13 +1761,13 @@ module TypeProf
1714
1761
  merge_env(ep.next, env)
1715
1762
  end
1716
1763
 
1717
- private def setup_actual_arguments(operands, ep, env)
1764
+ private def setup_actual_arguments(kind, operands, ep, env)
1718
1765
  opt, blk_iseq = operands
1719
1766
  flags = opt[:flag]
1720
1767
  mid = opt[:mid]
1721
1768
  kw_arg = opt[:kw_arg]
1722
1769
  argc = opt[:orig_argc]
1723
- argc += 1 # receiver
1770
+ argc += 1 if kind == :method # for the receiver
1724
1771
  argc += kw_arg.size if kw_arg
1725
1772
 
1726
1773
  flag_args_splat = flags[ 0] != 0
@@ -1735,29 +1782,36 @@ module TypeProf
1735
1782
  _flag_super = flags[ 9] != 0
1736
1783
  _flag_zsuper = flags[10] != 0
1737
1784
 
1785
+ argc += 1 if flag_args_blockarg
1786
+
1787
+ env, aargs = env.pop(argc)
1788
+
1789
+ recv = aargs.shift if kind == :method
1790
+
1738
1791
  if flag_args_blockarg
1739
- env, (recv, *aargs, blk_ty) = env.pop(argc + 1)
1740
- raise "both block arg and actual block given" if blk_iseq
1792
+ blk_ty = aargs.pop
1793
+ elsif blk_iseq
1794
+ blk_ty = Type::Proc.new(ISeqBlock.new(blk_iseq, ep), Type::Instance.new(Type::Builtin[:proc]))
1741
1795
  else
1742
- env, (recv, *aargs) = env.pop(argc)
1743
- if blk_iseq
1744
- # check
1745
- blk_ty = Type::ISeqProc.new(blk_iseq, ep, Type::Instance.new(Type::Builtin[:proc]))
1746
- else
1747
- blk_ty = Type.nil
1748
- end
1796
+ blk_ty = Type.nil
1749
1797
  end
1750
1798
 
1799
+ new_blk_ty = Type.bot
1751
1800
  blk_ty.each_child do |blk_ty|
1752
1801
  case blk_ty
1753
1802
  when Type.nil
1754
1803
  when Type.any
1755
- when Type::ISeqProc
1804
+ when Type::Proc
1805
+ when Type::Symbol
1806
+ blk_ty = Type::Proc.new(SymbolBlock.new(blk_ty.sym), Type::Instance.new(Type::Builtin[:proc]))
1756
1807
  else
1808
+ # XXX: attempt to call to_proc
1757
1809
  error(ep, "wrong argument type #{ blk_ty.screen_name(self) } (expected Proc)")
1758
1810
  blk_ty = Type.any
1759
1811
  end
1812
+ new_blk_ty = new_blk_ty.union(blk_ty)
1760
1813
  end
1814
+ blk_ty = new_blk_ty
1761
1815
 
1762
1816
  if flag_args_splat
1763
1817
  # assert !flag_args_kwarg
@@ -1841,7 +1895,7 @@ module TypeProf
1841
1895
  nlocals = [Type.any] * blk_iseq.locals.size
1842
1896
  nsenv = StaticEnv.new(env.static_env.recv_ty, Type.any, env.static_env.mod_func)
1843
1897
  nenv = Env.new(nsenv, nlocals, [], nil)
1844
- pend_block_dummy_execution(blk_iseq, nep, nenv)
1898
+ pend_block_dummy_execution(blk_ty, blk_iseq, nep, nenv)
1845
1899
  merge_return_env(ep) {|tenv| tenv ? tenv.merge(env) : env }
1846
1900
  end
1847
1901
 
@@ -1866,153 +1920,83 @@ module TypeProf
1866
1920
  end
1867
1921
  end
1868
1922
 
1869
- def do_invoke_block(given_block, blk, aargs, ep, env, replace_recv_ty: nil, &ctn)
1923
+ def do_invoke_block(blk, aargs, ep, env, replace_recv_ty: nil, &ctn)
1870
1924
  blk.each_child do |blk|
1871
- unless blk.is_a?(Type::ISeqProc)
1872
- warn(ep, "non-iseq-proc is passed as a block")
1873
- next
1874
- end
1875
- blk_iseq = blk.iseq
1876
- blk_ep = blk.ep
1877
- blk_env = @return_envs[blk_ep]
1878
- blk_env = blk_env.replace_recv_ty(replace_recv_ty) if replace_recv_ty
1879
- arg_blk = aargs.blk_ty
1880
- aargs_ = aargs.lead_tys.map {|aarg| globalize_type(aarg, env, ep) }
1881
- # XXX: aargs.opt_tys and aargs.kw_tys
1882
- argc = blk_iseq.fargs_format[:lead_num] || 0
1883
- # actual argc == 1, not array, formal argc == 1: yield 42 => do |x| : x=42
1884
- # actual argc == 1, array, formal argc == 1: yield [42,43,44] => do |x| : x=[42,43,44]
1885
- # actual argc >= 2, formal argc == 1: yield 42,43,44 => do |x| : x=42
1886
- # actual argc == 1, not array, formal argc >= 2: yield 42 => do |x,y| : x,y=42,nil
1887
- # actual argc == 1, array, formal argc >= 2: yield [42,43,44] => do |x,y| : x,y=42,43
1888
- # actual argc >= 2, formal argc >= 2: yield 42,43,44 => do |x,y| : x,y=42,43
1889
- if aargs_.size >= 2 || argc == 0
1890
- aargs_.pop while argc < aargs_.size
1891
- aargs_ << Type.nil while argc > aargs_.size
1925
+ if blk.is_a?(Type::Proc)
1926
+ blk.block_body.do_call(aargs, ep, env, self, replace_recv_ty: replace_recv_ty, &ctn)
1892
1927
  else
1893
- aarg_ty, = aargs_
1894
- if argc == 1
1895
- aargs_ = [aarg_ty || Type.nil]
1896
- else # actual argc == 1 && formal argc >= 2
1897
- ary_elems = nil
1898
- any_ty = nil
1899
- case aarg_ty
1900
- when Type::Union
1901
- ary_elems = nil
1902
- other_elems = nil
1903
- aarg_ty.elems&.each do |(container_kind, base_type), elems|
1904
- if container_kind == Type::Array
1905
- ary_elems = ary_elems ? ary_elems.union(elems) : elems
1906
- else
1907
- other_elems = other_elems ? other_elems.union(elems) : elems
1908
- end
1909
- end
1910
- aarg_ty = Type::Union.new(aarg_ty.types, other_elems)
1911
- any_ty = Type.any if aarg_ty.types.include?(Type.any)
1912
- when Type::Array
1913
- ary_elems = aarg_ty.elems
1914
- aarg_ty = nil
1915
- when Type::Any
1916
- any_ty = Type.any
1917
- end
1918
- aargs_ = [Type.bot] * argc
1919
- aargs_[0] = aargs_[0].union(aarg_ty) if aarg_ty
1920
- argc.times do |i|
1921
- ty = aargs_[i]
1922
- ty = ty.union(ary_elems[i]) if ary_elems
1923
- ty = ty.union(Type.any) if any_ty
1924
- ty = ty.union(Type.nil) if i >= 1 && aarg_ty
1925
- aargs_[i] = ty
1926
- end
1927
- end
1928
+ warn(ep, "non-proc is passed as a block")
1929
+ ctn[Type.any, ep, env]
1928
1930
  end
1929
- locals = [Type.nil] * blk_iseq.locals.size
1930
- locals[blk_iseq.fargs_format[:block_start]] = arg_blk if blk_iseq.fargs_format[:block_start]
1931
- env_blk = blk_env.static_env.blk_ty
1932
- nfargs = FormalArguments.new(aargs_, [], nil, [], nil, nil, env_blk)
1933
- nctx = Context.new(blk_iseq, blk_ep.ctx.cref, nil)
1934
- nep = ExecutionPoint.new(nctx, 0, blk_ep)
1935
- nenv = Env.new(blk_env.static_env, locals, [], nil)
1936
- alloc_site = AllocationSite.new(nep)
1937
- aargs_.each_with_index do |ty, i|
1938
- alloc_site2 = alloc_site.add_id(i)
1939
- nenv, ty = localize_type(ty, nenv, nep, alloc_site2) # Use Scratch#localize_type?
1940
- nenv = nenv.local_update(i, ty)
1941
- end
1942
-
1943
- merge_env(nep, nenv)
1944
-
1945
- # caution: given_block flag is not complete
1946
- #
1947
- # def foo
1948
- # bar do |&blk|
1949
- # yield
1950
- # blk.call
1951
- # end
1952
- # end
1953
- #
1954
- # yield and blk.call call different blocks.
1955
- # So, a context can have two blocks.
1956
- # given_block is calculated by comparing "context's block (yield target)" and "blk", but it is not a correct result
1957
-
1958
- add_yield!(ep.ctx, globalize_type(aargs, env, ep), nep.ctx) if given_block
1959
- add_block_to_ctx!(blk, nep.ctx)
1960
- add_callsite!(nep.ctx, ep, env, &ctn)
1961
- add_signature!(nep.ctx, nfargs)
1962
1931
  end
1963
1932
  end
1964
1933
 
1965
- def proc_screen_name(blk)
1966
- blk_ctxs = []
1967
- blk.each_child_global do |blk|
1968
- if @block_to_ctx[blk]
1969
- @block_to_ctx[blk].each do |ctx|
1970
- blk_ctxs << [ctx, @sig_fargs[ctx]]
1934
+ def show_block_signature(blks)
1935
+ bsig = nil
1936
+ ret_ty = Type.bot
1937
+
1938
+ blks.each do |blk|
1939
+ blk.each_child_global do |blk|
1940
+ bsig0 = @block_signatures[blk.block_body]
1941
+ if bsig0
1942
+ if bsig
1943
+ bsig = bsig.merge(bsig0)
1944
+ else
1945
+ bsig = bsig0
1946
+ end
1947
+ end
1948
+
1949
+ @block_to_ctx[blk.block_body].each do |blk_ctx|
1950
+ ret_ty = ret_ty.union(@return_values[blk_ctx]) if @return_values[blk_ctx]
1971
1951
  end
1972
- else
1973
- # uncalled proc? dummy execution doesn't work?
1974
- #p blk
1975
1952
  end
1976
1953
  end
1977
- show_block_signature(blk_ctxs)
1954
+
1955
+ bsig ||= BlockSignature.new([], [], nil, Type.nil)
1956
+
1957
+ bsig = bsig.screen_name(self)#, block: true)
1958
+ ret_ty = ret_ty.screen_name(self)
1959
+ ret_ty = (ret_ty.include?("|") ? "(#{ ret_ty })" : ret_ty) # XXX?
1960
+
1961
+ bsig = bsig + " " if bsig != ""
1962
+ "{ #{ bsig }-> #{ ret_ty } }"
1978
1963
  end
1979
1964
 
1980
- def show_block_signature(blk_ctxs)
1981
- all_farg_tys = all_ret_tys = nil
1982
- blk_ctxs.each do |blk_ctx, farg_tys|
1983
- if all_farg_tys
1984
- all_farg_tys = all_farg_tys.merge(farg_tys)
1985
- else
1986
- all_farg_tys = farg_tys
1987
- end
1965
+ def show_proc_signature(blks)
1966
+ farg_tys, ret_ty = nil, Type.bot
1988
1967
 
1989
- if all_ret_tys
1990
- all_ret_tys = all_ret_tys.union(@sig_ret[blk_ctx])
1991
- else
1992
- all_ret_tys = @sig_ret[blk_ctx]
1968
+ blks.each do |blk|
1969
+ blk.each_child_global do |blk|
1970
+ next if blk.block_body.is_a?(TypedBlock) # XXX: Support TypedBlock
1971
+ next unless @block_to_ctx[blk.block_body] # this occurs when screen_name is called before type-profiling finished (e.g., error message)
1972
+ @block_to_ctx[blk.block_body].each do |blk_ctx|
1973
+ if farg_tys
1974
+ farg_tys = farg_tys.merge(@method_signatures[blk_ctx])
1975
+ else
1976
+ farg_tys = @method_signatures[blk_ctx]
1977
+ end
1978
+
1979
+ ret_ty = ret_ty.union(@return_values[blk_ctx]) if @return_values[blk_ctx]
1980
+ end
1993
1981
  end
1994
1982
  end
1995
- return "" if !all_farg_tys
1996
- # XXX: should support @yields[blk_ctx] (block's block)
1997
- show_signature(all_farg_tys, nil, all_ret_tys)
1983
+
1984
+ farg_tys = farg_tys ? farg_tys.screen_name(self) : "(unknown)"
1985
+ ret_ty = ret_ty.screen_name(self)
1986
+ ret_ty = (ret_ty.include?("|") ? "(#{ ret_ty })" : ret_ty) # XXX?
1987
+
1988
+ farg_tys = farg_tys + " " if farg_tys != ""
1989
+ "^#{ farg_tys }-> #{ ret_ty }"
1998
1990
  end
1999
1991
 
2000
- def show_signature(farg_tys, yield_data, ret_ty)
1992
+ def show_method_signature(ctx)
1993
+ farg_tys = @method_signatures[ctx]
1994
+ ret_ty = @return_values[ctx] || Type.bot
1995
+
2001
1996
  farg_tys = farg_tys.screen_name(self)
2002
1997
  ret_ty = ret_ty.screen_name(self)
2003
- s = farg_tys.empty? ? "" : "(#{ farg_tys.join(", ") }) "
2004
- if yield_data
2005
- aargs, blk_ctxs = yield_data
2006
- all_blk_ret_ty = Type.bot
2007
- blk_ctxs.each do |blk_ctx|
2008
- all_blk_ret_ty = all_blk_ret_ty.union(@sig_ret[blk_ctx])
2009
- end
2010
- all_blk_ret_ty = all_blk_ret_ty.screen_name(self)
2011
- all_blk_ret_ty = all_blk_ret_ty.include?("|") ? "(#{ all_blk_ret_ty })" : all_blk_ret_ty
2012
- s << "{ #{ aargs.screen_name(self) } -> #{ all_blk_ret_ty } } " if aargs
2013
- end
2014
- s << "-> "
2015
- s << (ret_ty.include?("|") ? "(#{ ret_ty })" : ret_ty)
1998
+ ret_ty = (ret_ty.include?("|") ? "(#{ ret_ty })" : ret_ty) # XXX?
1999
+ "#{ (farg_tys.empty? ? "" : "#{ farg_tys } ") }-> #{ ret_ty }"
2016
2000
  end
2017
2001
  end
2018
2002
  end