typeprof 0.12.0 → 0.15.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 239b17dbe8d61c729346c5dde966f6abff491951c88bc33c57c4c34cc99dc497
4
- data.tar.gz: 2696c83796a6af5c498cca59a3d98b7faccaf187fe60c0057ac3f052622009ff
3
+ metadata.gz: dcefd3a4da176820246ad53757286aa1f7f8b2d21a6d1300763c91ba252e95ca
4
+ data.tar.gz: 1bf7429a4cf7d59e1ab4ca10f5f065a22b85adbbda922c67060d0ede64aab60f
5
5
  SHA512:
6
- metadata.gz: 23a7a3313dadd2d0c63a5d83a3afd112893134a049861e6a9e11cf5097aaa78c19494326b6a07b44cf4d93f5dec5a2c893b91fe2c4f5571726229d1e8dc13229
7
- data.tar.gz: 3273f1bb24290af32db23aaae8cafa84905d4d2d576b5ab96178130fe843b73e4365827b60d47a022a2812621f7fe09a3801c32c205c9805516873ed9ac88659
6
+ metadata.gz: ff14f14aa923ca807db9d7f1bc7f537c46e735bd194a0b59758dfdba0e04c04175ca0505fe6c00f739fec7933eeeab5010646891f56e14d5245f5b8613dd7d3b
7
+ data.tar.gz: 73a05bece353a7b4dbefba9f16e723fb088795e9f029b143721b03543e53ae19a8adb9908b3de41c839fbfb10a8d34c76ed0fa4f1b072801d7334233be63b1c9
data/Gemfile.lock CHANGED
@@ -1,25 +1,25 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- typeprof (0.12.0)
5
- rbs (>= 1.0.0)
4
+ typeprof (0.15.0)
5
+ rbs (>= 1.3.1)
6
6
 
7
7
  GEM
8
8
  remote: https://rubygems.org/
9
9
  specs:
10
10
  coverage-helpers (1.0.0)
11
- docile (1.3.4)
12
- power_assert (1.2.0)
11
+ docile (1.4.0)
12
+ power_assert (2.0.0)
13
13
  rake (13.0.1)
14
- rbs (1.0.3)
15
- simplecov (0.20.0)
14
+ rbs (1.3.1)
15
+ simplecov (0.21.2)
16
16
  docile (~> 1.1)
17
17
  simplecov-html (~> 0.11)
18
18
  simplecov_json_formatter (~> 0.1)
19
19
  simplecov-html (0.12.3)
20
- simplecov_json_formatter (0.1.2)
21
- stackprof (0.2.16)
22
- test-unit (3.3.7)
20
+ simplecov_json_formatter (0.1.3)
21
+ stackprof (0.2.17)
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.2.3
39
+ 2.2.15
@@ -42,6 +42,10 @@ module TypeProf
42
42
  "<builtin>"
43
43
  end
44
44
  end
45
+
46
+ def replace_cref(cref)
47
+ Context.new(@iseq, cref, @mid)
48
+ end
45
49
  end
46
50
 
47
51
  class TypedContext
@@ -61,6 +65,10 @@ module TypeProf
61
65
  "<typed-context:#{ @mid }>"
62
66
  end
63
67
  end
68
+
69
+ def replace_cref(cref)
70
+ # What to do?
71
+ end
64
72
  end
65
73
 
66
74
  class ExecutionPoint
@@ -86,6 +94,10 @@ module TypeProf
86
94
  ExecutionPoint.new(@ctx, @pc + 1, @outer)
87
95
  end
88
96
 
97
+ def replace_cref(cref)
98
+ ExecutionPoint.new(@ctx.replace_cref(cref), @pc, @outer)
99
+ end
100
+
89
101
  def source_location
90
102
  @ctx.source_location(@pc)
91
103
  end
@@ -238,6 +250,8 @@ module TypeProf
238
250
  end
239
251
 
240
252
  def initialize
253
+ @entrypoints = []
254
+
241
255
  @worklist = Utils::WorkList.new
242
256
 
243
257
  @ep2env = {}
@@ -263,16 +277,22 @@ module TypeProf
263
277
  @pending_execution = {}
264
278
  @executed_iseqs = Utils::MutableSet.new
265
279
 
266
- @loaded_features = {}
280
+ @loaded_files = {}
267
281
 
268
282
  @rbs_reader = RBSReader.new
269
283
 
270
284
  @terminated = false
271
285
 
272
286
  @anonymous_struct_gen_id = 0
287
+
288
+ @types_being_shown = []
289
+ end
290
+
291
+ def add_entrypoint(iseq)
292
+ @entrypoints << iseq
273
293
  end
274
294
 
275
- attr_reader :return_envs, :loaded_features, :rbs_reader
295
+ attr_reader :return_envs, :loaded_files, :rbs_reader
276
296
 
277
297
  def get_env(ep)
278
298
  @ep2env[ep]
@@ -311,9 +331,10 @@ module TypeProf
311
331
  @cvars = VarTable.new
312
332
  @absolute_path = absolute_path
313
333
  @namespace = nil
334
+ @subclasses = []
314
335
  end
315
336
 
316
- attr_reader :kind, :modules, :consts, :methods, :ivars, :cvars, :absolute_path
337
+ attr_reader :kind, :modules, :consts, :methods, :ivars, :cvars, :absolute_path, :subclasses
317
338
  attr_accessor :name, :klass_obj
318
339
 
319
340
  def mix_module(kind, mod, type_args, singleton, absolute_path)
@@ -427,6 +448,7 @@ module TypeProf
427
448
  idx = @class_defs.size
428
449
  if superclass
429
450
  @class_defs[idx] = ClassDef.new(:class, show_name, absolute_path)
451
+ @class_defs[superclass.idx].subclasses << idx unless superclass == :__root__
430
452
  klass = Type::Class.new(:class, idx, type_params, superclass, show_name)
431
453
  @class_defs[idx].klass_obj = klass
432
454
  cbase ||= klass # for bootstrap
@@ -453,6 +475,7 @@ module TypeProf
453
475
  superclass = Type::Builtin[:struct]
454
476
  name = "AnonymousStruct_generated_#{ @anonymous_struct_gen_id += 1 }"
455
477
  @class_defs[idx] = ClassDef.new(:class, [name], ep.ctx.iseq.absolute_path)
478
+ #@class_defs[superclass.idx].subclasses << idx # needed?
456
479
  klass = Type::Class.new(:class, idx, [], superclass, name)
457
480
  add_superclass_type_args!(klass, [Type.any])
458
481
  @class_defs[idx].klass_obj = klass
@@ -508,6 +531,13 @@ module TypeProf
508
531
  end
509
532
  end
510
533
 
534
+ def traverse_subclasses(klass, &blk)
535
+ @class_defs[klass.idx].subclasses.each do |subclass|
536
+ yield @class_defs[subclass]
537
+ traverse_subclasses(@class_defs[subclass].klass_obj, &blk)
538
+ end
539
+ end
540
+
511
541
  def search_method(klass, singleton, mid, &blk)
512
542
  # XXX: support method alias correctly
513
543
  klass_orig = klass
@@ -527,7 +557,18 @@ module TypeProf
527
557
  end
528
558
  end
529
559
 
530
- def get_method(klass, singleton, mid)
560
+ def get_method(klass, singleton, include_subclasses, mid)
561
+ if include_subclasses
562
+ subclasses_mthds = []
563
+ traverse_subclasses(klass) do |subclass|
564
+ subclass.search_method(singleton, mid, {}) do |mthds,|
565
+ subclasses_mthds.concat(mthds.to_a)
566
+ end
567
+ end
568
+ search_method(klass, singleton, mid) {|mthds,| return subclasses_mthds + mthds.to_a }
569
+ return subclasses_mthds
570
+ end
571
+
531
572
  search_method(klass, singleton, mid) {|mthds,| return mthds }
532
573
  end
533
574
 
@@ -628,9 +669,10 @@ module TypeProf
628
669
  if klass == Type.any
629
670
  self
630
671
  else
631
- mdefs = get_method(klass, singleton, orig_mid)
672
+ mdefs = get_method(klass, singleton, false, orig_mid) # XXX: include_subclass == false??
632
673
  if mdefs
633
- mdefs.each do |mdef|
674
+ # dup is needed for `alias foo foo` (otherwise, "can't add a new key into hash during iteration" error occurs)
675
+ mdefs.dup.each do |mdef|
634
676
  @class_defs[klass.idx].add_method(alias_mid, singleton, AliasMethodDef.new(orig_mid, mdef, ep))
635
677
  end
636
678
  end
@@ -737,24 +779,32 @@ module TypeProf
737
779
  end
738
780
  end
739
781
 
740
- def get_ivar(recv)
782
+ def identify_class_for_ivar(recv, var)
783
+ klass, singleton = recv.method_dispatch_info
784
+ return nil unless klass
785
+ search_method(klass, singleton, var) do |mthds, klass0, singleton0|
786
+ if mthds.any? {|mthd| mthd.is_a?(AttrMethodDef) }
787
+ return klass0, singleton
788
+ end
789
+ end
790
+ return klass, singleton
791
+ end
792
+
793
+ def get_ivar(recv, var)
741
794
  recv = recv.base_type while recv.respond_to?(:base_type)
742
- case recv
743
- when Type::Class
744
- [@class_defs[recv.idx], true]
745
- when Type::Instance
746
- [@class_defs[recv.klass.idx], false]
747
- when Type::Any
748
- return
795
+
796
+ klass, singleton = identify_class_for_ivar(recv, var.to_s[1..].to_sym) # search attr_reader
797
+
798
+ if klass
799
+ return @class_defs[klass.idx], singleton
749
800
  else
750
- warn "???"
751
- return
801
+ return nil
752
802
  end
753
803
  end
754
804
 
755
805
  def add_ivar_read!(recv, var, ep, &ctn)
756
806
  recv.each_child do |recv|
757
- class_def, singleton = get_ivar(recv)
807
+ class_def, singleton = get_ivar(recv, var)
758
808
  next unless class_def
759
809
  class_def.ivars.add_read!([singleton, var], ep, &ctn)
760
810
  end
@@ -762,7 +812,7 @@ module TypeProf
762
812
 
763
813
  def add_ivar_write!(recv, var, ty, ep)
764
814
  recv.each_child do |recv|
765
- class_def, singleton = get_ivar(recv)
815
+ class_def, singleton = get_ivar(recv, var)
766
816
  next unless class_def
767
817
  class_def.ivars.add_write!([singleton, var], ty, ep, self)
768
818
  end
@@ -878,56 +928,77 @@ module TypeProf
878
928
  iter_counter = 0
879
929
  stat_eps = Utils::MutableSet.new
880
930
 
881
- while true
882
- until @worklist.empty?
883
- ep = @worklist.deletemin
884
-
885
- iter_counter += 1
886
- if Config.options[:show_indicator]
887
- tick2 = Time.now
888
- if tick2 - tick >= 1
889
- tick = tick2
890
- $stderr << "\rType Profiling... (%d instructions @ %s)\e[K" % [iter_counter, ep.source_location]
891
- $stderr.flush
931
+ prologue_ctx = Context.new(nil, nil, nil)
932
+ prologue_ep = ExecutionPoint.new(prologue_ctx, -1, nil)
933
+ prologue_env = Env.new(StaticEnv.new(Type.bot, Type.nil, false, true), [], [], Utils::HashWrapper.new({}))
934
+
935
+ until @entrypoints.empty?
936
+ entrypoint = @entrypoints.shift
937
+ if entrypoint.is_a?(String)
938
+ file = entrypoint
939
+ next if @loaded_files[File.expand_path(file)]
940
+ iseq = ISeq.compile(file)
941
+ else
942
+ iseq = entrypoint
943
+ end
944
+
945
+ @loaded_files[iseq.absolute_path] = true
946
+ ep, env = TypeProf.starting_state(iseq)
947
+ merge_env(ep, env)
948
+ add_callsite!(ep.ctx, prologue_ep, prologue_env) {|ty, ep| }
949
+
950
+ while true
951
+ until @worklist.empty?
952
+ ep = @worklist.deletemin
953
+
954
+ iter_counter += 1
955
+ if Config.options[:show_indicator]
956
+ tick2 = Time.now
957
+ if tick2 - tick >= 1
958
+ tick = tick2
959
+ $stderr << "\rType Profiling... (%d instructions @ %s)\e[K" % [iter_counter, ep.source_location]
960
+ $stderr.flush
961
+ end
892
962
  end
893
- end
894
963
 
895
- if (Config.max_sec && Time.now - start_time >= Config.max_sec) || (Config.max_iter && Config.max_iter <= iter_counter)
896
- @terminated = true
897
- break
898
- end
964
+ if (Config.max_sec && Time.now - start_time >= Config.max_sec) || (Config.max_iter && Config.max_iter <= iter_counter)
965
+ @terminated = true
966
+ break
967
+ end
899
968
 
900
- stat_eps << ep
901
- step(ep)
902
- end
969
+ stat_eps << ep
970
+ step(ep)
971
+ end
903
972
 
904
- break if @terminated
973
+ break if @terminated
905
974
 
906
- break unless Config.options[:stub_execution]
975
+ break unless Config.options[:stub_execution]
907
976
 
908
- begin
909
- iseq, (kind, dummy_continuation) = @pending_execution.first
910
- break if !iseq
911
- @pending_execution.delete(iseq)
912
- end while @executed_iseqs.include?(iseq)
977
+ begin
978
+ iseq, (kind, dummy_continuation) = @pending_execution.first
979
+ break if !iseq
980
+ @pending_execution.delete(iseq)
981
+ end while @executed_iseqs.include?(iseq)
913
982
 
914
- puts "DEBUG: trigger stub execution (#{ iseq&.name || "(nil)" }): rest #{ @pending_execution.size }" if Config.verbose >= 2
983
+ puts "DEBUG: trigger stub execution (#{ iseq&.name || "(nil)" }): rest #{ @pending_execution.size }" if Config.verbose >= 2
915
984
 
916
- break if !iseq
917
- case kind
918
- when :method
919
- meth, ep, env = dummy_continuation
920
- merge_env(ep, env)
921
- add_iseq_method_call!(meth, ep.ctx)
922
-
923
- when :block
924
- blk, epenvs = dummy_continuation
925
- epenvs.each do |ep, env|
985
+ break if !iseq
986
+ case kind
987
+ when :method
988
+ meth, ep, env = dummy_continuation
926
989
  merge_env(ep, env)
927
- add_block_to_ctx!(blk.block_body, ep.ctx)
990
+ add_iseq_method_call!(meth, ep.ctx)
991
+
992
+ when :block
993
+ blk, epenvs = dummy_continuation
994
+ epenvs.each do |ep, env|
995
+ merge_env(ep, env)
996
+ add_block_to_ctx!(blk.block_body, ep.ctx)
997
+ end
928
998
  end
929
999
  end
930
1000
  end
1001
+
931
1002
  $stderr.print "\r\e[K" if Config.options[:show_indicator]
932
1003
 
933
1004
  stat_eps
@@ -1245,7 +1316,13 @@ module TypeProf
1245
1316
  end
1246
1317
  if cbase.is_a?(Type::Class)
1247
1318
  klass = new_class(cbase, id, [], superclass, ep.ctx.iseq.absolute_path)
1248
- add_superclass_type_args!(klass, superclass.type_params.map { Type.any }) if superclass
1319
+ if superclass
1320
+ add_superclass_type_args!(klass, superclass.type_params.map { Type.any })
1321
+
1322
+ # inherited hook
1323
+ aargs = ActualArguments.new([klass], nil, {}, Type.nil)
1324
+ do_send(superclass, :inherited, aargs, ep, env) {|_ret_ty, _ep| }
1325
+ end
1249
1326
  else
1250
1327
  klass = Type.any
1251
1328
  end
@@ -1280,15 +1357,13 @@ module TypeProf
1280
1357
  when :send
1281
1358
  env, recvs, mid, aargs = setup_actual_arguments(:method, operands, ep, env)
1282
1359
  recvs = Type.any if recvs == Type.bot
1283
- recvs.each_child do |recv|
1284
- do_send(recv, mid, aargs, ep, env) do |ret_ty, ep, env|
1285
- nenv, ret_ty, = localize_type(ret_ty, env, ep)
1286
- nenv = nenv.push(ret_ty)
1287
- merge_env(ep.next, nenv)
1288
- end
1360
+ do_send(recvs, mid, aargs, ep, env) do |ret_ty, ep, env|
1361
+ nenv, ret_ty, = localize_type(ret_ty, env, ep)
1362
+ nenv = nenv.push(ret_ty)
1363
+ merge_env(ep.next, nenv)
1289
1364
  end
1290
1365
  return
1291
- when :getlocal_send_branch
1366
+ when :recv_getlocal_send_branch
1292
1367
  getlocal_operands, send_operands, branch_operands = operands
1293
1368
  env, recvs, mid, aargs = setup_actual_arguments(:method, send_operands, ep, env)
1294
1369
  recvs = Type.any if recvs == Type.bot
@@ -1316,28 +1391,59 @@ module TypeProf
1316
1391
  end
1317
1392
  end
1318
1393
  return
1394
+ when :arg_getlocal_send_branch
1395
+ getlocal_operands, send_operands, branch_operands = operands
1396
+ env, recvs, mid, aargs = setup_actual_arguments(:method, send_operands, ep, env)
1397
+ raise if aargs.lead_tys.size != 1
1398
+ aarg = aargs.lead_tys[0]
1399
+ aarg = Type.any if aarg == Type.bot
1400
+ recvs.each_child do |recv|
1401
+ aarg.each_child do |aarg|
1402
+ aargs_tmp = ActualArguments.new([aarg], nil, {}, aargs.blk_ty)
1403
+ do_send(recv, mid, aargs_tmp, ep, env) do |ret_ty, ep, env|
1404
+ env, ret_ty, = localize_type(ret_ty, env, ep)
1405
+
1406
+ branchtype, target, = branch_operands
1407
+ # branchtype: :if or :unless or :nil
1408
+ ep_then = ep.next
1409
+ ep_else = ep.jump(target)
1410
+
1411
+ var_idx, _scope_idx, _escaped = getlocal_operands
1412
+ flow_env = env.local_update(-var_idx+2, aarg)
1413
+
1414
+ case ret_ty
1415
+ when Type::Instance.new(Type::Builtin[:true])
1416
+ merge_env(branchtype == :if ? ep_else : ep_then, flow_env)
1417
+ when Type::Instance.new(Type::Builtin[:false])
1418
+ merge_env(branchtype == :if ? ep_then : ep_else, flow_env)
1419
+ else
1420
+ merge_env(ep_then, env)
1421
+ merge_env(ep_else, env)
1422
+ end
1423
+ end
1424
+ end
1425
+ end
1426
+ return
1319
1427
  when :send_branch
1320
1428
  send_operands, branch_operands = operands
1321
1429
  env, recvs, mid, aargs = setup_actual_arguments(:method, send_operands, ep, env)
1322
1430
  recvs = Type.any if recvs == Type.bot
1323
- recvs.each_child do |recv|
1324
- do_send(recv, mid, aargs, ep, env) do |ret_ty, ep, env|
1325
- env, ret_ty, = localize_type(ret_ty, env, ep)
1431
+ do_send(recvs, mid, aargs, ep, env) do |ret_ty, ep, env|
1432
+ env, ret_ty, = localize_type(ret_ty, env, ep)
1326
1433
 
1327
- branchtype, target, = branch_operands
1328
- # branchtype: :if or :unless or :nil
1329
- ep_then = ep.next
1330
- ep_else = ep.jump(target)
1434
+ branchtype, target, = branch_operands
1435
+ # branchtype: :if or :unless or :nil
1436
+ ep_then = ep.next
1437
+ ep_else = ep.jump(target)
1331
1438
 
1332
- case ret_ty
1333
- when Type::Instance.new(Type::Builtin[:true])
1334
- merge_env(branchtype == :if ? ep_else : ep_then, env)
1335
- when Type::Instance.new(Type::Builtin[:false])
1336
- merge_env(branchtype == :if ? ep_then : ep_else, env)
1337
- else
1338
- merge_env(ep_then, env)
1339
- merge_env(ep_else, env)
1340
- end
1439
+ case ret_ty
1440
+ when Type::Instance.new(Type::Builtin[:true])
1441
+ merge_env(branchtype == :if ? ep_else : ep_then, env)
1442
+ when Type::Instance.new(Type::Builtin[:false])
1443
+ merge_env(branchtype == :if ? ep_then : ep_else, env)
1444
+ else
1445
+ merge_env(ep_then, env)
1446
+ merge_env(ep_else, env)
1341
1447
  end
1342
1448
  end
1343
1449
  return
@@ -1371,12 +1477,10 @@ module TypeProf
1371
1477
  # XXX: this decomposition is really needed??
1372
1478
  # It calls `Object.new` with union receiver which causes an error, but
1373
1479
  # it may be a fault of builtin Object.new implementation.
1374
- recv.each_child do |recv|
1375
- meth.do_send(recv, mid, aargs, ep, env, self) do |ret_ty, ep, env|
1376
- nenv, ret_ty, = localize_type(ret_ty, env, ep)
1377
- nenv = nenv.push(ret_ty)
1378
- merge_env(ep.next, nenv)
1379
- end
1480
+ meth.do_send(recv, mid, aargs, ep, env, self) do |ret_ty, ep, env|
1481
+ nenv, ret_ty, = localize_type(ret_ty, env, ep)
1482
+ nenv = nenv.push(ret_ty)
1483
+ merge_env(ep.next, nenv)
1380
1484
  end
1381
1485
  end
1382
1486
  end
@@ -1419,7 +1523,7 @@ module TypeProf
1419
1523
  end
1420
1524
  _type, _iseq, cont, stack_depth = tmp_ep.ctx.iseq.catch_table[tmp_ep.pc]&.find {|type,| type == :break }
1421
1525
  if cont
1422
- nenv = @return_envs[tmp_ep]
1526
+ nenv = @return_envs[tmp_ep] || env
1423
1527
  nenv, = nenv.pop(nenv.stack.size - stack_depth)
1424
1528
  nenv = nenv.push(ty)
1425
1529
  tmp_ep = tmp_ep.jump(cont)
@@ -1778,8 +1882,10 @@ module TypeProf
1778
1882
  when :nop
1779
1883
  when :setn
1780
1884
  idx, = operands
1781
- env, (ty,) = env.pop(1)
1782
- env = env.setn(idx, ty).push(ty)
1885
+ if idx >= 1
1886
+ env, (ty,) = env.pop(1)
1887
+ env = env.setn(idx, ty).push(ty)
1888
+ end
1783
1889
  when :topn
1784
1890
  idx, = operands
1785
1891
  env = env.topn(idx)
@@ -2062,39 +2168,41 @@ module TypeProf
2062
2168
  return env, recv, mid, aargs
2063
2169
  end
2064
2170
 
2065
- def do_send(recv, mid, aargs, ep, env, &ctn)
2066
- case recv
2067
- when Type::Void
2068
- error(ep, "void's method is called: #{ globalize_type(recv, env, ep).screen_name(self) }##{ mid }")
2069
- ctn[Type.any, ep, env]
2070
- when Type::Any
2071
- ctn[Type.any, ep, env]
2072
- else
2073
- klass, singleton = recv.method_dispatch_info
2074
- meths = get_method(klass, singleton, mid) if klass
2075
- if meths
2076
- meths.each do |meth|
2077
- meth.do_send(recv, mid, aargs, ep, env, self, &ctn)
2078
- end
2171
+ def do_send(recvs, mid, aargs, ep, env, &ctn)
2172
+ recvs.each_child do |recv|
2173
+ case recv
2174
+ when Type::Void
2175
+ error(ep, "void's method is called: #{ globalize_type(recv, env, ep).screen_name(self) }##{ mid }")
2176
+ ctn[Type.any, ep, env]
2177
+ when Type::Any
2178
+ ctn[Type.any, ep, env]
2079
2179
  else
2080
- meths = get_method(klass, singleton, :method_missing) if klass
2180
+ klass, singleton, include_subclasses = recv.method_dispatch_info
2181
+ meths = get_method(klass, singleton, include_subclasses, mid) if klass
2081
2182
  if meths
2082
- aargs = aargs.for_method_missing(Type::Symbol.new(mid, Type::Instance.new(Type::Builtin[:sym])))
2083
2183
  meths.each do |meth|
2084
- meth.do_send(recv, :method_missing, aargs, ep, env, self, &ctn)
2184
+ meth.do_send(recv, mid, aargs, ep, env, self, &ctn)
2085
2185
  end
2086
2186
  else
2087
- error(ep, "undefined method: #{ globalize_type(recv, env, ep).screen_name(self) }##{ mid }")
2088
- ctn[Type.any, ep, env]
2187
+ meths = get_method(klass, singleton, include_subclasses, :method_missing) if klass
2188
+ if meths
2189
+ aargs = aargs.for_method_missing(Type::Symbol.new(mid, Type::Instance.new(Type::Builtin[:sym])))
2190
+ meths.each do |meth|
2191
+ meth.do_send(recv, :method_missing, aargs, ep, env, self, &ctn)
2192
+ end
2193
+ else
2194
+ error(ep, "undefined method: #{ globalize_type(recv, env, ep).screen_name(self) }##{ mid }")
2195
+ ctn[Type.any, ep, env]
2196
+ end
2089
2197
  end
2090
2198
  end
2091
2199
  end
2092
2200
  end
2093
2201
 
2094
- def do_invoke_block(blk, aargs, ep, env, replace_recv_ty: nil, &ctn)
2202
+ def do_invoke_block(blk, aargs, ep, env, replace_recv_ty: nil, replace_cref: nil, &ctn)
2095
2203
  blk.each_child do |blk|
2096
2204
  if blk.is_a?(Type::Proc)
2097
- blk.block_body.do_call(aargs, ep, env, self, replace_recv_ty: replace_recv_ty, &ctn)
2205
+ blk.block_body.do_call(aargs, ep, env, self, replace_recv_ty: replace_recv_ty, replace_cref: replace_cref, &ctn)
2098
2206
  else
2099
2207
  warn(ep, "non-proc is passed as a block")
2100
2208
  ctn[Type.any, ep, env]
@@ -2170,7 +2278,11 @@ module TypeProf
2170
2278
  next unless @block_to_ctx[blk.block_body] # this occurs when screen_name is called before type-profiling finished (e.g., error message)
2171
2279
  @block_to_ctx[blk.block_body].each do |blk_ctx|
2172
2280
  if farg_tys
2173
- farg_tys = farg_tys.merge_as_block_arguments(@method_signatures[blk_ctx])
2281
+ if @method_signatures[blk_ctx]
2282
+ farg_tys = farg_tys.merge_as_block_arguments(@method_signatures[blk_ctx])
2283
+ else
2284
+ # this occurs when screen_name is called before type-profiling finished (e.g., error message)
2285
+ end
2174
2286
  else
2175
2287
  farg_tys = @method_signatures[blk_ctx]
2176
2288
  end
@@ -2180,17 +2292,24 @@ module TypeProf
2180
2292
  end
2181
2293
  end
2182
2294
 
2183
- farg_tys = farg_tys ? farg_tys.screen_name(nil, self) : "(unknown)"
2184
- ret_ty = ret_ty.screen_name(self)
2185
- ret_ty = (ret_ty.include?("|") ? "(#{ ret_ty })" : ret_ty) # XXX?
2295
+ return Type.any.screen_name(self) if @types_being_shown.include?(farg_tys) || @types_being_shown.include?(ret_ty)
2296
+
2297
+ begin
2298
+ @types_being_shown << farg_tys << ret_ty
2299
+ farg_tys = farg_tys ? farg_tys.screen_name(nil, self) : "(unknown)"
2300
+ ret_ty = ret_ty.screen_name(self)
2301
+ ret_ty = (ret_ty.include?("|") ? "(#{ ret_ty })" : ret_ty) # XXX?
2186
2302
 
2187
- farg_tys = farg_tys + " " if farg_tys != ""
2188
- "^#{ farg_tys }-> #{ ret_ty }"
2303
+ farg_tys = farg_tys + " " if farg_tys != ""
2304
+ "^#{ farg_tys }-> #{ ret_ty }"
2305
+ ensure
2306
+ @types_being_shown.pop(2)
2307
+ end
2189
2308
  end
2190
2309
 
2191
2310
  def show_method_signature(ctx)
2192
2311
  farg_tys = @method_signatures[ctx]
2193
- ret_ty = @return_values[ctx] || Type.bot
2312
+ ret_ty = ctx.mid == :initialize ? Type::Void.new : @return_values[ctx] || Type.bot
2194
2313
 
2195
2314
  untyped = farg_tys.include_untyped?(self) || ret_ty.include_untyped?(self)
2196
2315