typeprof 0.12.0 → 0.15.0

Sign up to get free protection for your applications and to get access to all the features.
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