typeprof 0.14.1 → 0.15.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (55) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile.lock +5 -5
  3. data/lib/typeprof/analyzer.rb +154 -85
  4. data/lib/typeprof/builtin.rb +22 -12
  5. data/lib/typeprof/cli.rb +1 -0
  6. data/lib/typeprof/config.rb +2 -1
  7. data/lib/typeprof/container-type.rb +7 -1
  8. data/lib/typeprof/export.rb +9 -5
  9. data/lib/typeprof/import.rb +60 -21
  10. data/lib/typeprof/iseq.rb +303 -201
  11. data/lib/typeprof/method.rb +2 -2
  12. data/lib/typeprof/type.rb +97 -47
  13. data/lib/typeprof/version.rb +1 -1
  14. data/smoke/alias2.rb +1 -1
  15. data/smoke/array15.rb +1 -1
  16. data/smoke/array3.rb +1 -1
  17. data/smoke/array6.rb +2 -2
  18. data/smoke/array8.rb +1 -1
  19. data/smoke/attr-module.rb +1 -4
  20. data/smoke/attr-vis.rb +1 -1
  21. data/smoke/attr.rb +1 -1
  22. data/smoke/block-args2.rb +3 -3
  23. data/smoke/block-args3.rb +4 -4
  24. data/smoke/break2.rb +1 -1
  25. data/smoke/gvar2.rb +0 -3
  26. data/smoke/hash-bot.rb +1 -1
  27. data/smoke/hash4.rb +1 -1
  28. data/smoke/huge_union.rb +86 -0
  29. data/smoke/identifier_keywords.rb +17 -0
  30. data/smoke/initialize.rb +1 -1
  31. data/smoke/ivar2.rb +1 -1
  32. data/smoke/ivar3.rb +1 -1
  33. data/smoke/kwrest.rb +2 -2
  34. data/smoke/kwrest.rbs +1 -1
  35. data/smoke/method_missing.rb +1 -1
  36. data/smoke/next2.rb +1 -1
  37. data/smoke/noname.rb +9 -0
  38. data/smoke/or_raise.rb +18 -0
  39. data/smoke/parameterizedd-self.rb +2 -2
  40. data/smoke/pattern-match1.rb +1 -6
  41. data/smoke/proc6.rb +13 -0
  42. data/smoke/proc7.rb +32 -0
  43. data/smoke/rbs-tyvar4.rb +1 -1
  44. data/smoke/rbs-vars.rb +0 -3
  45. data/smoke/require1.rb +13 -0
  46. data/smoke/require2.rb +13 -0
  47. data/smoke/struct5.rb +1 -1
  48. data/smoke/struct6.rb +1 -1
  49. data/smoke/struct7.rb +1 -1
  50. data/smoke/super3.rb +1 -1
  51. data/smoke/symbol-proc-attr.rb +1 -1
  52. data/smoke/symbol-proc-attr2.rb +1 -1
  53. data/testbed/ao.rb +1 -1
  54. data/typeprof.gemspec +1 -1
  55. metadata +12 -4
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d5828bf5dda203756a758bba9809d3b1fe81b284cc1373f00ff75ca175afe998
4
- data.tar.gz: c274d8bda556407a33c70227a4caea57f1ae91f79ee546f9076d6ffac01891a5
3
+ metadata.gz: 13f530c84fe1b38000dc93982adac87c01d6d3a3516f8502e3de252d56428a12
4
+ data.tar.gz: b799ff212fd16b59bb96f8b560252e687d206e9a3ba541eaa6033532108957e3
5
5
  SHA512:
6
- metadata.gz: e32f209894645a18b36a24c2347e86e249ffa0bcd2c93565d1920551ef143e73f6f3c58011250a545d761e9212aee032e99a44503e4dad5e1975d73de412d3c9
7
- data.tar.gz: f3463cbae97beff6b359acb14a3a871f83d0ed37332e46ce38d846b2c486a9af3e6864a5450fe82e0abae79763b71ed55a26f1ab03d6a04aa9eb62232dd435fe
6
+ metadata.gz: 6e11866f36a7570ba564bf2abe6912f2531f728e76c4afc32f9bfddc436ea03a86a996eb4d3ddd2bf8c24e9eeae0986b45f17f06575d80df21b812585976f1ba
7
+ data.tar.gz: 8e990ceee15c1dba1cf529990fbb6e26a4f48946088549f51471c48ff1aeccfdc7cb8b6547c1105e00767263acee681db4340240f94c786b39bbeff842d501dc
data/Gemfile.lock CHANGED
@@ -1,8 +1,8 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- typeprof (0.14.1)
5
- rbs (>= 1.2.0)
4
+ typeprof (0.15.3)
5
+ rbs (>= 1.3.1)
6
6
 
7
7
  GEM
8
8
  remote: https://rubygems.org/
@@ -11,7 +11,7 @@ GEM
11
11
  docile (1.4.0)
12
12
  power_assert (2.0.0)
13
13
  rake (13.0.1)
14
- rbs (1.2.0)
14
+ rbs (1.6.1)
15
15
  simplecov (0.21.2)
16
16
  docile (~> 1.1)
17
17
  simplecov-html (~> 0.11)
@@ -19,7 +19,7 @@ GEM
19
19
  simplecov-html (0.12.3)
20
20
  simplecov_json_formatter (0.1.3)
21
21
  stackprof (0.2.17)
22
- test-unit (3.4.1)
22
+ test-unit (3.4.2)
23
23
  power_assert
24
24
 
25
25
  PLATFORMS
@@ -36,4 +36,4 @@ DEPENDENCIES
36
36
  typeprof!
37
37
 
38
38
  BUNDLED WITH
39
- 2.3.0.dev
39
+ 2.2.15
@@ -277,20 +277,23 @@ module TypeProf
277
277
  @pending_execution = {}
278
278
  @executed_iseqs = Utils::MutableSet.new
279
279
 
280
- @loaded_features = {}
280
+ @loaded_files = {}
281
281
 
282
282
  @rbs_reader = RBSReader.new
283
283
 
284
284
  @terminated = false
285
285
 
286
286
  @anonymous_struct_gen_id = 0
287
+
288
+ @types_being_shown = []
289
+ @namespace = nil
287
290
  end
288
291
 
289
292
  def add_entrypoint(iseq)
290
293
  @entrypoints << iseq
291
294
  end
292
295
 
293
- attr_reader :return_envs, :loaded_features, :rbs_reader
296
+ attr_reader :return_envs, :loaded_files, :rbs_reader
294
297
 
295
298
  def get_env(ep)
296
299
  @ep2env[ep]
@@ -329,9 +332,10 @@ module TypeProf
329
332
  @cvars = VarTable.new
330
333
  @absolute_path = absolute_path
331
334
  @namespace = nil
335
+ @subclasses = []
332
336
  end
333
337
 
334
- attr_reader :kind, :modules, :consts, :methods, :ivars, :cvars, :absolute_path
338
+ attr_reader :kind, :modules, :consts, :methods, :ivars, :cvars, :absolute_path, :subclasses
335
339
  attr_accessor :name, :klass_obj
336
340
 
337
341
  def mix_module(kind, mod, type_args, singleton, absolute_path)
@@ -445,6 +449,7 @@ module TypeProf
445
449
  idx = @class_defs.size
446
450
  if superclass
447
451
  @class_defs[idx] = ClassDef.new(:class, show_name, absolute_path)
452
+ @class_defs[superclass.idx].subclasses << idx unless superclass == :__root__
448
453
  klass = Type::Class.new(:class, idx, type_params, superclass, show_name)
449
454
  @class_defs[idx].klass_obj = klass
450
455
  cbase ||= klass # for bootstrap
@@ -471,6 +476,7 @@ module TypeProf
471
476
  superclass = Type::Builtin[:struct]
472
477
  name = "AnonymousStruct_generated_#{ @anonymous_struct_gen_id += 1 }"
473
478
  @class_defs[idx] = ClassDef.new(:class, [name], ep.ctx.iseq.absolute_path)
479
+ #@class_defs[superclass.idx].subclasses << idx # needed?
474
480
  klass = Type::Class.new(:class, idx, [], superclass, name)
475
481
  add_superclass_type_args!(klass, [Type.any])
476
482
  @class_defs[idx].klass_obj = klass
@@ -526,6 +532,13 @@ module TypeProf
526
532
  end
527
533
  end
528
534
 
535
+ def traverse_subclasses(klass, &blk)
536
+ @class_defs[klass.idx].subclasses.each do |subclass|
537
+ yield @class_defs[subclass]
538
+ traverse_subclasses(@class_defs[subclass].klass_obj, &blk)
539
+ end
540
+ end
541
+
529
542
  def search_method(klass, singleton, mid, &blk)
530
543
  # XXX: support method alias correctly
531
544
  klass_orig = klass
@@ -545,7 +558,18 @@ module TypeProf
545
558
  end
546
559
  end
547
560
 
548
- def get_method(klass, singleton, mid)
561
+ def get_method(klass, singleton, include_subclasses, mid)
562
+ if include_subclasses
563
+ subclasses_mthds = []
564
+ traverse_subclasses(klass) do |subclass|
565
+ subclass.search_method(singleton, mid, {}) do |mthds,|
566
+ subclasses_mthds.concat(mthds.to_a)
567
+ end
568
+ end
569
+ search_method(klass, singleton, mid) {|mthds,| return subclasses_mthds + mthds.to_a }
570
+ return subclasses_mthds
571
+ end
572
+
549
573
  search_method(klass, singleton, mid) {|mthds,| return mthds }
550
574
  end
551
575
 
@@ -646,9 +670,10 @@ module TypeProf
646
670
  if klass == Type.any
647
671
  self
648
672
  else
649
- mdefs = get_method(klass, singleton, orig_mid)
673
+ mdefs = get_method(klass, singleton, false, orig_mid) # XXX: include_subclass == false??
650
674
  if mdefs
651
- mdefs.each do |mdef|
675
+ # dup is needed for `alias foo foo` (otherwise, "can't add a new key into hash during iteration" error occurs)
676
+ mdefs.dup.each do |mdef|
652
677
  @class_defs[klass.idx].add_method(alias_mid, singleton, AliasMethodDef.new(orig_mid, mdef, ep))
653
678
  end
654
679
  end
@@ -755,24 +780,32 @@ module TypeProf
755
780
  end
756
781
  end
757
782
 
758
- def get_ivar(recv)
783
+ def identify_class_for_ivar(recv, var)
784
+ klass, singleton = recv.method_dispatch_info
785
+ return nil unless klass
786
+ search_method(klass, singleton, var) do |mthds, klass0, singleton0|
787
+ if mthds.any? {|mthd| mthd.is_a?(AttrMethodDef) }
788
+ return klass0, singleton
789
+ end
790
+ end
791
+ return klass, singleton
792
+ end
793
+
794
+ def get_ivar(recv, var)
759
795
  recv = recv.base_type while recv.respond_to?(:base_type)
760
- case recv
761
- when Type::Class
762
- [@class_defs[recv.idx], true]
763
- when Type::Instance
764
- [@class_defs[recv.klass.idx], false]
765
- when Type::Any
766
- return
796
+
797
+ klass, singleton = identify_class_for_ivar(recv, var.to_s[1..].to_sym) # search attr_reader
798
+
799
+ if klass
800
+ return @class_defs[klass.idx], singleton
767
801
  else
768
- warn "???"
769
- return
802
+ return nil
770
803
  end
771
804
  end
772
805
 
773
806
  def add_ivar_read!(recv, var, ep, &ctn)
774
807
  recv.each_child do |recv|
775
- class_def, singleton = get_ivar(recv)
808
+ class_def, singleton = get_ivar(recv, var)
776
809
  next unless class_def
777
810
  class_def.ivars.add_read!([singleton, var], ep, &ctn)
778
811
  end
@@ -780,7 +813,7 @@ module TypeProf
780
813
 
781
814
  def add_ivar_write!(recv, var, ty, ep)
782
815
  recv.each_child do |recv|
783
- class_def, singleton = get_ivar(recv)
816
+ class_def, singleton = get_ivar(recv, var)
784
817
  next unless class_def
785
818
  class_def.ivars.add_write!([singleton, var], ty, ep, self)
786
819
  end
@@ -901,7 +934,16 @@ module TypeProf
901
934
  prologue_env = Env.new(StaticEnv.new(Type.bot, Type.nil, false, true), [], [], Utils::HashWrapper.new({}))
902
935
 
903
936
  until @entrypoints.empty?
904
- iseq = @entrypoints.shift
937
+ entrypoint = @entrypoints.shift
938
+ if entrypoint.is_a?(String)
939
+ file = entrypoint
940
+ next if @loaded_files[File.expand_path(file)]
941
+ iseq = ISeq.compile(file)
942
+ else
943
+ iseq = entrypoint
944
+ end
945
+
946
+ @loaded_files[iseq.absolute_path] = true
905
947
  ep, env = TypeProf.starting_state(iseq)
906
948
  merge_env(ep, env)
907
949
  add_callsite!(ep.ctx, prologue_ep, prologue_env) {|ty, ep| }
@@ -1077,15 +1119,16 @@ module TypeProf
1077
1119
  env = @ep2env[ep]
1078
1120
  raise "nil env" unless env
1079
1121
 
1080
- insn, operands = ep.ctx.iseq.insns[ep.pc]
1122
+ insn = ep.ctx.iseq.insns[ep.pc]
1123
+ operands = insn.operands
1081
1124
 
1082
1125
  if Config.verbose >= 2
1083
1126
  # XXX: more dedicated output
1084
1127
  puts "DEBUG: stack=%p" % [env.stack]
1085
- puts "DEBUG: %s (%s) PC=%d insn=%s sp=%d" % [ep.source_location, ep.ctx.iseq.name, ep.pc, insn, env.stack.size]
1128
+ puts "DEBUG: %s (%s) PC=%d insn=%s sp=%d" % [ep.source_location, ep.ctx.iseq.name, ep.pc, insn.insn, env.stack.size]
1086
1129
  end
1087
1130
 
1088
- case insn
1131
+ case insn.insn
1089
1132
  when :_iseq_body_start
1090
1133
  # XXX: reconstruct and record the method signature
1091
1134
  iseq = ep.ctx.iseq
@@ -1316,12 +1359,10 @@ module TypeProf
1316
1359
  when :send
1317
1360
  env, recvs, mid, aargs = setup_actual_arguments(:method, operands, ep, env)
1318
1361
  recvs = Type.any if recvs == Type.bot
1319
- recvs.each_child do |recv|
1320
- do_send(recv, mid, aargs, ep, env) do |ret_ty, ep, env|
1321
- nenv, ret_ty, = localize_type(ret_ty, env, ep)
1322
- nenv = nenv.push(ret_ty)
1323
- merge_env(ep.next, nenv)
1324
- end
1362
+ do_send(recvs, mid, aargs, ep, env) do |ret_ty, ep, env|
1363
+ nenv, ret_ty, = localize_type(ret_ty, env, ep)
1364
+ nenv = nenv.push(ret_ty)
1365
+ merge_env(ep.next, nenv)
1325
1366
  end
1326
1367
  return
1327
1368
  when :recv_getlocal_send_branch
@@ -1389,24 +1430,22 @@ module TypeProf
1389
1430
  send_operands, branch_operands = operands
1390
1431
  env, recvs, mid, aargs = setup_actual_arguments(:method, send_operands, ep, env)
1391
1432
  recvs = Type.any if recvs == Type.bot
1392
- recvs.each_child do |recv|
1393
- do_send(recv, mid, aargs, ep, env) do |ret_ty, ep, env|
1394
- env, ret_ty, = localize_type(ret_ty, env, ep)
1433
+ do_send(recvs, mid, aargs, ep, env) do |ret_ty, ep, env|
1434
+ env, ret_ty, = localize_type(ret_ty, env, ep)
1395
1435
 
1396
- branchtype, target, = branch_operands
1397
- # branchtype: :if or :unless or :nil
1398
- ep_then = ep.next
1399
- ep_else = ep.jump(target)
1436
+ branchtype, target, = branch_operands
1437
+ # branchtype: :if or :unless or :nil
1438
+ ep_then = ep.next
1439
+ ep_else = ep.jump(target)
1400
1440
 
1401
- case ret_ty
1402
- when Type::Instance.new(Type::Builtin[:true])
1403
- merge_env(branchtype == :if ? ep_else : ep_then, env)
1404
- when Type::Instance.new(Type::Builtin[:false])
1405
- merge_env(branchtype == :if ? ep_then : ep_else, env)
1406
- else
1407
- merge_env(ep_then, env)
1408
- merge_env(ep_else, env)
1409
- end
1441
+ case ret_ty
1442
+ when Type::Instance.new(Type::Builtin[:true])
1443
+ merge_env(branchtype == :if ? ep_else : ep_then, env)
1444
+ when Type::Instance.new(Type::Builtin[:false])
1445
+ merge_env(branchtype == :if ? ep_then : ep_else, env)
1446
+ else
1447
+ merge_env(ep_then, env)
1448
+ merge_env(ep_else, env)
1410
1449
  end
1411
1450
  end
1412
1451
  return
@@ -1440,12 +1479,10 @@ module TypeProf
1440
1479
  # XXX: this decomposition is really needed??
1441
1480
  # It calls `Object.new` with union receiver which causes an error, but
1442
1481
  # it may be a fault of builtin Object.new implementation.
1443
- recv.each_child do |recv|
1444
- meth.do_send(recv, mid, aargs, ep, env, self) do |ret_ty, ep, env|
1445
- nenv, ret_ty, = localize_type(ret_ty, env, ep)
1446
- nenv = nenv.push(ret_ty)
1447
- merge_env(ep.next, nenv)
1448
- end
1482
+ meth.do_send(recv, mid, aargs, ep, env, self) do |ret_ty, ep, env|
1483
+ nenv, ret_ty, = localize_type(ret_ty, env, ep)
1484
+ nenv = nenv.push(ret_ty)
1485
+ merge_env(ep.next, nenv)
1449
1486
  end
1450
1487
  end
1451
1488
  end
@@ -1606,7 +1643,7 @@ module TypeProf
1606
1643
  return
1607
1644
  end
1608
1645
 
1609
- when :getlocal, :getblockparam, :getblockparamproxy
1646
+ when :getlocal
1610
1647
  var_idx, scope_idx, _escaped = operands
1611
1648
  if scope_idx == 0
1612
1649
  ty = env.get_local(-var_idx+2)
@@ -1647,18 +1684,12 @@ module TypeProf
1647
1684
  getlocal_operands, _dup_operands, branch_operands = operands
1648
1685
  var_idx, _scope_idx, _escaped = getlocal_operands
1649
1686
  ret_ty = env.get_local(-var_idx+2)
1650
- unless ret_ty
1651
- p env.locals
1652
- raise
1653
- end
1654
1687
 
1655
1688
  branchtype, target, = branch_operands
1656
1689
  # branchtype: :if or :unless or :nil
1657
1690
  ep_then = ep.next
1658
1691
  ep_else = ep.jump(target)
1659
1692
 
1660
- var_idx, _scope_idx, _escaped = getlocal_operands
1661
-
1662
1693
  ret_ty.each_child do |ret_ty|
1663
1694
  flow_env = env.local_update(-var_idx+2, ret_ty).push(ret_ty)
1664
1695
  case ret_ty
@@ -1672,6 +1703,31 @@ module TypeProf
1672
1703
  end
1673
1704
  end
1674
1705
  return
1706
+ when :dup_setlocal_branch
1707
+ _dup_operands, setlocal_operands, branch_operands = operands
1708
+
1709
+ env, (ret_ty,) = env.pop(1)
1710
+
1711
+ var_idx, _scope_idx, _escaped = setlocal_operands
1712
+
1713
+ branchtype, target, = branch_operands
1714
+ # branchtype: :if or :unless or :nil
1715
+ ep_then = ep.next
1716
+ ep_else = ep.jump(target)
1717
+
1718
+ ret_ty.each_child do |ret_ty|
1719
+ flow_env = env.local_update(-var_idx+2, ret_ty)
1720
+ case ret_ty
1721
+ when Type.any
1722
+ merge_env(ep_then, flow_env)
1723
+ merge_env(ep_else, flow_env)
1724
+ when Type::Instance.new(Type::Builtin[:false]), Type.nil
1725
+ merge_env(branchtype == :if ? ep_then : ep_else, flow_env)
1726
+ else
1727
+ merge_env(branchtype == :if ? ep_else : ep_then, flow_env)
1728
+ end
1729
+ end
1730
+ return
1675
1731
  when :getlocal_checkmatch_branch
1676
1732
  getlocal_operands, branch_operands = operands
1677
1733
  var_idx, _scope_idx, _escaped = getlocal_operands
@@ -1935,7 +1991,7 @@ module TypeProf
1935
1991
  end
1936
1992
  env = env.push(ty)
1937
1993
  else
1938
- raise "Unknown insn: #{ insn }"
1994
+ raise "Unknown insn: #{ insn.insn }"
1939
1995
  end
1940
1996
 
1941
1997
  add_edge(ep, ep)
@@ -2133,30 +2189,32 @@ module TypeProf
2133
2189
  return env, recv, mid, aargs
2134
2190
  end
2135
2191
 
2136
- def do_send(recv, mid, aargs, ep, env, &ctn)
2137
- case recv
2138
- when Type::Void
2139
- error(ep, "void's method is called: #{ globalize_type(recv, env, ep).screen_name(self) }##{ mid }")
2140
- ctn[Type.any, ep, env]
2141
- when Type::Any
2142
- ctn[Type.any, ep, env]
2143
- else
2144
- klass, singleton = recv.method_dispatch_info
2145
- meths = get_method(klass, singleton, mid) if klass
2146
- if meths
2147
- meths.each do |meth|
2148
- meth.do_send(recv, mid, aargs, ep, env, self, &ctn)
2149
- end
2192
+ def do_send(recvs, mid, aargs, ep, env, &ctn)
2193
+ recvs.each_child do |recv|
2194
+ case recv
2195
+ when Type::Void
2196
+ error(ep, "void's method is called: #{ globalize_type(recv, env, ep).screen_name(self) }##{ mid }")
2197
+ ctn[Type.any, ep, env]
2198
+ when Type::Any
2199
+ ctn[Type.any, ep, env]
2150
2200
  else
2151
- meths = get_method(klass, singleton, :method_missing) if klass
2201
+ klass, singleton, include_subclasses = recv.method_dispatch_info
2202
+ meths = get_method(klass, singleton, include_subclasses, mid) if klass
2152
2203
  if meths
2153
- aargs = aargs.for_method_missing(Type::Symbol.new(mid, Type::Instance.new(Type::Builtin[:sym])))
2154
2204
  meths.each do |meth|
2155
- meth.do_send(recv, :method_missing, aargs, ep, env, self, &ctn)
2205
+ meth.do_send(recv, mid, aargs, ep, env, self, &ctn)
2156
2206
  end
2157
2207
  else
2158
- error(ep, "undefined method: #{ globalize_type(recv, env, ep).screen_name(self) }##{ mid }")
2159
- ctn[Type.any, ep, env]
2208
+ meths = get_method(klass, singleton, include_subclasses, :method_missing) if klass
2209
+ if meths
2210
+ aargs = aargs.for_method_missing(Type::Symbol.new(mid, Type::Instance.new(Type::Builtin[:sym])))
2211
+ meths.each do |meth|
2212
+ meth.do_send(recv, :method_missing, aargs, ep, env, self, &ctn)
2213
+ end
2214
+ else
2215
+ error(ep, "undefined method: #{ globalize_type(recv, env, ep).screen_name(self) }##{ mid }")
2216
+ ctn[Type.any, ep, env]
2217
+ end
2160
2218
  end
2161
2219
  end
2162
2220
  end
@@ -2167,7 +2225,7 @@ module TypeProf
2167
2225
  if blk.is_a?(Type::Proc)
2168
2226
  blk.block_body.do_call(aargs, ep, env, self, replace_recv_ty: replace_recv_ty, replace_cref: replace_cref, &ctn)
2169
2227
  else
2170
- warn(ep, "non-proc is passed as a block")
2228
+ warn(ep, "non-proc is passed as a block") if blk != Type.any
2171
2229
  ctn[Type.any, ep, env]
2172
2230
  end
2173
2231
  end
@@ -2241,7 +2299,11 @@ module TypeProf
2241
2299
  next unless @block_to_ctx[blk.block_body] # this occurs when screen_name is called before type-profiling finished (e.g., error message)
2242
2300
  @block_to_ctx[blk.block_body].each do |blk_ctx|
2243
2301
  if farg_tys
2244
- farg_tys = farg_tys.merge_as_block_arguments(@method_signatures[blk_ctx])
2302
+ if @method_signatures[blk_ctx]
2303
+ farg_tys = farg_tys.merge_as_block_arguments(@method_signatures[blk_ctx])
2304
+ else
2305
+ # this occurs when screen_name is called before type-profiling finished (e.g., error message)
2306
+ end
2245
2307
  else
2246
2308
  farg_tys = @method_signatures[blk_ctx]
2247
2309
  end
@@ -2251,17 +2313,24 @@ module TypeProf
2251
2313
  end
2252
2314
  end
2253
2315
 
2254
- farg_tys = farg_tys ? farg_tys.screen_name(nil, self) : "(unknown)"
2255
- ret_ty = ret_ty.screen_name(self)
2256
- ret_ty = (ret_ty.include?("|") ? "(#{ ret_ty })" : ret_ty) # XXX?
2316
+ return Type.any.screen_name(self) if @types_being_shown.include?(farg_tys) || @types_being_shown.include?(ret_ty)
2257
2317
 
2258
- farg_tys = farg_tys + " " if farg_tys != ""
2259
- "^#{ farg_tys }-> #{ ret_ty }"
2318
+ begin
2319
+ @types_being_shown << farg_tys << ret_ty
2320
+ farg_tys = farg_tys ? farg_tys.screen_name(nil, self) : "(unknown)"
2321
+ ret_ty = ret_ty.screen_name(self)
2322
+ ret_ty = (ret_ty.include?("|") ? "(#{ ret_ty })" : ret_ty) # XXX?
2323
+
2324
+ farg_tys = farg_tys + " " if farg_tys != ""
2325
+ "^#{ farg_tys }-> #{ ret_ty }"
2326
+ ensure
2327
+ @types_being_shown.pop(2)
2328
+ end
2260
2329
  end
2261
2330
 
2262
2331
  def show_method_signature(ctx)
2263
2332
  farg_tys = @method_signatures[ctx]
2264
- ret_ty = @return_values[ctx] || Type.bot
2333
+ ret_ty = ctx.mid == :initialize ? Type::Void.new : @return_values[ctx] || Type.bot
2265
2334
 
2266
2335
  untyped = farg_tys.include_untyped?(self) || ret_ty.include_untyped?(self)
2267
2336