typeprof 0.15.0 → 0.20.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (49) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/main.yml +1 -1
  3. data/Gemfile.lock +4 -4
  4. data/exe/typeprof +5 -1
  5. data/lib/typeprof/analyzer.rb +261 -66
  6. data/lib/typeprof/arguments.rb +1 -0
  7. data/lib/typeprof/builtin.rb +30 -22
  8. data/lib/typeprof/cli.rb +22 -2
  9. data/lib/typeprof/code-range.rb +177 -0
  10. data/lib/typeprof/config.rb +43 -18
  11. data/lib/typeprof/container-type.rb +10 -1
  12. data/lib/typeprof/export.rb +199 -20
  13. data/lib/typeprof/import.rb +30 -4
  14. data/lib/typeprof/iseq.rb +504 -200
  15. data/lib/typeprof/lsp.rb +865 -0
  16. data/lib/typeprof/method.rb +17 -13
  17. data/lib/typeprof/type.rb +46 -38
  18. data/lib/typeprof/utils.rb +18 -1
  19. data/lib/typeprof/version.rb +1 -1
  20. data/lib/typeprof.rb +3 -0
  21. data/smoke/array15.rb +1 -1
  22. data/smoke/array6.rb +2 -2
  23. data/smoke/array8.rb +1 -1
  24. data/smoke/block-args2.rb +3 -3
  25. data/smoke/block-args3.rb +4 -4
  26. data/smoke/break2.rb +1 -1
  27. data/smoke/gvar2.rb +0 -3
  28. data/smoke/hash-bot.rb +1 -1
  29. data/smoke/hash4.rb +1 -1
  30. data/smoke/identifier_keywords.rb +17 -0
  31. data/smoke/next2.rb +1 -1
  32. data/smoke/or_raise.rb +18 -0
  33. data/smoke/parameterizedd-self.rb +2 -2
  34. data/smoke/pattern-match1.rb +1 -6
  35. data/smoke/rbs-vars.rb +0 -3
  36. data/testbed/ao.rb +1 -1
  37. data/typeprof-lsp +3 -0
  38. data/typeprof.gemspec +1 -1
  39. data/vscode/.gitignore +5 -0
  40. data/vscode/.vscode/launch.json +16 -0
  41. data/vscode/.vscodeignore +7 -0
  42. data/vscode/README.md +22 -0
  43. data/vscode/development.md +31 -0
  44. data/vscode/package-lock.json +2211 -0
  45. data/vscode/package.json +71 -0
  46. data/vscode/sandbox/test.rb +24 -0
  47. data/vscode/src/extension.ts +285 -0
  48. data/vscode/tsconfig.json +15 -0
  49. metadata +20 -5
@@ -43,6 +43,14 @@ module TypeProf
43
43
  end
44
44
  end
45
45
 
46
+ def detailed_source_location(pc)
47
+ if @iseq
48
+ @iseq.detailed_source_location(pc)
49
+ else
50
+ nil
51
+ end
52
+ end
53
+
46
54
  def replace_cref(cref)
47
55
  Context.new(@iseq, cref, @mid)
48
56
  end
@@ -66,6 +74,14 @@ module TypeProf
66
74
  end
67
75
  end
68
76
 
77
+ def detailed_source_location(_pc)
78
+ if @caller_ep
79
+ @caller_ep.source_location
80
+ else
81
+ nil
82
+ end
83
+ end
84
+
69
85
  def replace_cref(cref)
70
86
  # What to do?
71
87
  end
@@ -101,6 +117,14 @@ module TypeProf
101
117
  def source_location
102
118
  @ctx.source_location(@pc)
103
119
  end
120
+
121
+ def detailed_source_location
122
+ @ctx.detailed_source_location(@pc)
123
+ end
124
+
125
+ def absolute_path
126
+ @ctx.iseq.absolute_path
127
+ end
104
128
  end
105
129
 
106
130
  class StaticEnv
@@ -286,6 +310,10 @@ module TypeProf
286
310
  @anonymous_struct_gen_id = 0
287
311
 
288
312
  @types_being_shown = []
313
+ @namespace = nil
314
+
315
+ @lsp_completion = nil
316
+ @lsp_signature_help = CodeRangeTable.new
289
317
  end
290
318
 
291
319
  def add_entrypoint(iseq)
@@ -334,7 +362,7 @@ module TypeProf
334
362
  @subclasses = []
335
363
  end
336
364
 
337
- attr_reader :kind, :modules, :consts, :methods, :ivars, :cvars, :absolute_path, :subclasses
365
+ attr_reader :kind, :modules, :methods, :ivars, :cvars, :absolute_path, :subclasses
338
366
  attr_accessor :name, :klass_obj
339
367
 
340
368
  def mix_module(kind, mod, type_args, singleton, absolute_path)
@@ -349,24 +377,43 @@ module TypeProf
349
377
  end
350
378
 
351
379
  def get_constant(name)
352
- ty, = @consts[name]
353
- ty || Type.any # XXX: warn?
380
+ ty, locs = @consts[name]
381
+ ty = ty || Type.any # XXX: warn?
382
+ return ty, locs
354
383
  end
355
384
 
356
- def add_constant(name, ty, absolute_path)
385
+ def add_constant(name, ty, def_ep)
357
386
  if @consts[name]
358
387
  # XXX: warn!
388
+ _, eps = @consts[name]
389
+ @consts[name] = [ty, eps + [def_ep&.detailed_source_location]]
390
+ return
359
391
  end
360
- @consts[name] = [ty, absolute_path]
392
+ @consts[name] = [ty, [def_ep&.detailed_source_location]]
361
393
  end
362
394
 
395
+ def consts
396
+ @consts.lazy.flat_map do |name, (ty, eps)|
397
+ eps.map do |ep|
398
+ [name, [ty, ep]]
399
+ end
400
+ end
401
+ end
402
+
403
+ def add_class_open(name, open_ep)
404
+ ty, eps = @consts[name]
405
+ raise "call this only if the class is opened more than once" if ty.nil?
406
+ @consts[name] = [ty, eps + [open_ep&.detailed_source_location]]
407
+ end
408
+
409
+
363
410
  def adjust_substitution_for_module(mods, mid, mthd, subst, &blk)
364
411
  mods.each do |mod_def, type_args,|
365
412
  if mod_def.klass_obj.type_params && type_args
366
413
  subst2 = {}
367
414
  mod_def.klass_obj.type_params.zip(type_args) do |(tyvar, *), tyarg|
368
415
  tyvar = Type::Var.new(tyvar)
369
- subst2[tyvar] = tyarg.substitute(subst, Config.options[:type_depth_limit])
416
+ subst2[tyvar] = tyarg.substitute(subst, Config.current.options[:type_depth_limit])
370
417
  end
371
418
  mod_def.adjust_substitution(false, mid, mthd, subst2, false, &blk)
372
419
  end
@@ -443,23 +490,23 @@ module TypeProf
443
490
  cbase && cbase.idx != 1 ? @class_defs[cbase.idx].name : []
444
491
  end
445
492
 
446
- def new_class(cbase, name, type_params, superclass, absolute_path)
493
+ def new_class(cbase, name, type_params, superclass, def_ep)
447
494
  show_name = cbase_path(cbase) + [name]
448
495
  idx = @class_defs.size
449
496
  if superclass
450
- @class_defs[idx] = ClassDef.new(:class, show_name, absolute_path)
497
+ @class_defs[idx] = ClassDef.new(:class, show_name, def_ep&.absolute_path)
451
498
  @class_defs[superclass.idx].subclasses << idx unless superclass == :__root__
452
499
  klass = Type::Class.new(:class, idx, type_params, superclass, show_name)
453
500
  @class_defs[idx].klass_obj = klass
454
501
  cbase ||= klass # for bootstrap
455
- add_constant(cbase, name, klass, absolute_path)
502
+ add_constant(cbase, name, klass, def_ep)
456
503
  return klass
457
504
  else
458
505
  # module
459
- @class_defs[idx] = ClassDef.new(:module, show_name, absolute_path)
506
+ @class_defs[idx] = ClassDef.new(:module, show_name, def_ep&.absolute_path)
460
507
  mod = Type::Class.new(:module, idx, type_params, nil, show_name)
461
508
  @class_defs[idx].klass_obj = mod
462
- add_constant(cbase, name, mod, absolute_path)
509
+ add_constant(cbase, name, mod, def_ep)
463
510
  return mod
464
511
  end
465
512
  end
@@ -518,7 +565,7 @@ module TypeProf
518
565
  subst2 = {}
519
566
  klass.superclass.type_params.zip(klass.superclass_type_args) do |(tyvar, *), tyarg|
520
567
  tyvar = Type::Var.new(tyvar)
521
- subst2[tyvar] = tyarg.substitute(subst, Config.options[:type_depth_limit])
568
+ subst2[tyvar] = tyarg.substitute(subst, Config.current.options[:type_depth_limit])
522
569
  end
523
570
  subst = subst2
524
571
  end
@@ -600,29 +647,53 @@ module TypeProf
600
647
  nil
601
648
  end
602
649
 
650
+ def get_all_methods(klass, singleton, _include_subclasses)
651
+ names = {}
652
+
653
+ if klass.kind == :class
654
+ while klass != :__root__
655
+ # TODO: module
656
+ @class_defs[klass.idx].methods.each_key do |singleton0, name|
657
+ if singleton == singleton0
658
+ names[name] = true
659
+ end
660
+ end
661
+ klass = klass.superclass
662
+ end
663
+ else
664
+ @class_defs[klass.idx].methods.each_key do |singleton0, name|
665
+ if singleton == singleton0
666
+ names[name] = true
667
+ end
668
+ end
669
+ end
670
+
671
+ names
672
+ end
673
+
603
674
  def get_constant(klass, name)
604
675
  if klass == Type.any
605
- Type.any
676
+ [Type.any, nil]
606
677
  elsif klass.is_a?(Type::Class)
607
678
  @class_defs[klass.idx].get_constant(name)
608
679
  else
609
- Type.any
680
+ [Type.any, nil]
610
681
  end
611
682
  end
612
683
 
613
684
  def search_constant(cref, name)
614
685
  while cref != :bottom
615
- val = get_constant(cref.klass, name)
616
- return val if val != Type.any
686
+ ty, locs = get_constant(cref.klass, name)
687
+ return ty, locs if ty != Type.any
617
688
  cref = cref.outer
618
689
  end
619
690
 
620
- Type.any
691
+ return Type.any, nil
621
692
  end
622
693
 
623
- def add_constant(klass, name, value, user_defined)
694
+ def add_constant(klass, name, value, def_ep)
624
695
  if klass.is_a?(Type::Class)
625
- @class_defs[klass.idx].add_constant(name, value, user_defined)
696
+ @class_defs[klass.idx].add_constant(name, value, def_ep)
626
697
  end
627
698
  end
628
699
 
@@ -693,7 +764,13 @@ module TypeProf
693
764
  end
694
765
 
695
766
  def add_callsite!(callee_ctx, caller_ep, caller_env, &ctn)
696
- @executed_iseqs << callee_ctx.iseq if callee_ctx.is_a?(Context)
767
+ if callee_ctx.is_a?(Context)
768
+ @executed_iseqs << callee_ctx.iseq
769
+ callee_type = callee_ctx.iseq.type
770
+ if caller_ep.ctx.is_a?(Context) && (callee_type == :method || callee_type == :block)
771
+ caller_ep.ctx.iseq&.add_called_iseq(caller_ep.pc, callee_ctx.iseq)
772
+ end
773
+ end
697
774
 
698
775
  @callsites[callee_ctx] ||= {}
699
776
  @callsites[callee_ctx][caller_ep] = ctn
@@ -742,23 +819,23 @@ module TypeProf
742
819
  end
743
820
 
744
821
  class VarTable
745
- Entry = Struct.new(:rbs_declared, :read_continuations, :type, :absolute_paths)
822
+ Entry = Struct.new(:rbs_declared, :read_continuations, :type, :absolute_paths, :write_eps)
746
823
 
747
824
  def initialize
748
825
  @tbl = {}
749
826
  end
750
827
 
751
828
  def add_read!(site, ep, &ctn)
752
- entry = @tbl[site] ||= Entry.new(false, {}, Type.bot, Utils::MutableSet.new)
829
+ entry = @tbl[site] ||= Entry.new(false, {}, Type.bot, Utils::MutableSet.new, Utils::MutableSet.new)
753
830
  entry.read_continuations[ep] = ctn
754
831
  entry.absolute_paths << ep.ctx.iseq.absolute_path if ep.ctx.is_a?(Context)
755
832
  ty = entry.type
756
833
  ty = Type.nil if ty == Type.bot
757
- ctn[ty, ep]
834
+ ctn[ty, ep, entry.write_eps]
758
835
  end
759
836
 
760
837
  def add_write!(site, ty, ep, scratch)
761
- entry = @tbl[site] ||= Entry.new(!ep, {}, Type.bot, Utils::MutableSet.new)
838
+ entry = @tbl[site] ||= Entry.new(!ep, {}, Type.bot, Utils::MutableSet.new, Utils::MutableSet.new)
762
839
  if ep
763
840
  if entry.rbs_declared
764
841
  unless Type.match?(ty, entry.type)
@@ -767,10 +844,11 @@ module TypeProf
767
844
  end
768
845
  end
769
846
  entry.absolute_paths << ep.ctx.iseq.absolute_path
847
+ entry.write_eps << ep
770
848
  end
771
849
  entry.type = entry.type.union(ty)
772
- entry.read_continuations.each do |ep, ctn|
773
- ctn[ty, ep]
850
+ entry.read_continuations.each do |read_ep, ctn|
851
+ ctn[ty, read_ep, [ep]]
774
852
  end
775
853
  end
776
854
 
@@ -814,7 +892,8 @@ module TypeProf
814
892
  recv.each_child do |recv|
815
893
  class_def, singleton = get_ivar(recv, var)
816
894
  next unless class_def
817
- class_def.ivars.add_write!([singleton, var], ty, ep, self)
895
+ site = [singleton, var]
896
+ class_def.ivars.add_write!(site, ty, ep, self)
818
897
  end
819
898
  end
820
899
 
@@ -845,18 +924,18 @@ module TypeProf
845
924
  end
846
925
 
847
926
  def error(ep, msg)
848
- p [ep.source_location, "[error] " + msg] if Config.verbose >= 2
927
+ p [ep.source_location, "[error] " + msg] if Config.current.verbose >= 2
849
928
  @errors << [ep, "[error] " + msg]
850
929
  end
851
930
 
852
931
  def warn(ep, msg)
853
- p [ep.source_location, "[warning] " + msg] if Config.verbose >= 2
932
+ p [ep.source_location, "[warning] " + msg] if Config.current.verbose >= 2
854
933
  @errors << [ep, "[warning] " + msg]
855
934
  end
856
935
 
857
936
  def reveal_type(ep, ty)
858
937
  key = ep.source_location
859
- puts "reveal:#{ ep.source_location }:#{ ty.screen_name(self) }" if Config.verbose >= 2
938
+ puts "reveal:#{ ep.source_location }:#{ ty.screen_name(self) }" if Config.current.verbose >= 2
860
939
  if @reveal_types[key]
861
940
  @reveal_types[key] = @reveal_types[key].union(ty)
862
941
  else
@@ -923,8 +1002,9 @@ module TypeProf
923
1002
  end
924
1003
  end
925
1004
 
926
- def type_profile
927
- start_time = tick = Time.now
1005
+ def type_profile(cancel_token = nil)
1006
+ cancel_token ||= Utils::TimerCancelToken.new(Config.current.max_sec)
1007
+ tick = Time.now
928
1008
  iter_counter = 0
929
1009
  stat_eps = Utils::MutableSet.new
930
1010
 
@@ -937,7 +1017,7 @@ module TypeProf
937
1017
  if entrypoint.is_a?(String)
938
1018
  file = entrypoint
939
1019
  next if @loaded_files[File.expand_path(file)]
940
- iseq = ISeq.compile(file)
1020
+ iseq, = ISeq.compile(file)
941
1021
  else
942
1022
  iseq = entrypoint
943
1023
  end
@@ -952,7 +1032,7 @@ module TypeProf
952
1032
  ep = @worklist.deletemin
953
1033
 
954
1034
  iter_counter += 1
955
- if Config.options[:show_indicator]
1035
+ if Config.current.options[:show_indicator]
956
1036
  tick2 = Time.now
957
1037
  if tick2 - tick >= 1
958
1038
  tick = tick2
@@ -961,7 +1041,7 @@ module TypeProf
961
1041
  end
962
1042
  end
963
1043
 
964
- if (Config.max_sec && Time.now - start_time >= Config.max_sec) || (Config.max_iter && Config.max_iter <= iter_counter)
1044
+ if (Config.current.max_iter && Config.current.max_iter <= iter_counter) || cancel_token.cancelled?
965
1045
  @terminated = true
966
1046
  break
967
1047
  end
@@ -972,7 +1052,7 @@ module TypeProf
972
1052
 
973
1053
  break if @terminated
974
1054
 
975
- break unless Config.options[:stub_execution]
1055
+ break unless Config.current.options[:stub_execution]
976
1056
 
977
1057
  begin
978
1058
  iseq, (kind, dummy_continuation) = @pending_execution.first
@@ -980,7 +1060,7 @@ module TypeProf
980
1060
  @pending_execution.delete(iseq)
981
1061
  end while @executed_iseqs.include?(iseq)
982
1062
 
983
- puts "DEBUG: trigger stub execution (#{ iseq&.name || "(nil)" }): rest #{ @pending_execution.size }" if Config.verbose >= 2
1063
+ puts "DEBUG: trigger stub execution (#{ iseq&.name || "(nil)" }): rest #{ @pending_execution.size }" if Config.current.verbose >= 2
984
1064
 
985
1065
  break if !iseq
986
1066
  case kind
@@ -999,7 +1079,7 @@ module TypeProf
999
1079
  end
1000
1080
  end
1001
1081
 
1002
- $stderr.print "\r\e[K" if Config.options[:show_indicator]
1082
+ $stderr.print "\r\e[K" if Config.current.options[:show_indicator]
1003
1083
 
1004
1084
  stat_eps
1005
1085
  end
@@ -1016,13 +1096,70 @@ module TypeProf
1016
1096
  RubySignatureExporter.new(self, @class_defs, @iseq_method_to_ctxs).show(stat_eps, output)
1017
1097
  end
1018
1098
 
1099
+ def report_lsp
1100
+ errs = @errors.map do |ep, msg|
1101
+ [ep&.detailed_source_location, msg]
1102
+ end
1103
+
1104
+ res = RubySignatureExporter.new(self, @class_defs, @iseq_method_to_ctxs).show_lsp
1105
+
1106
+ path, loc = Config.current.options[:signature_help_loc]
1107
+ if path
1108
+ sig_help_res = []
1109
+ sig_help = @lsp_signature_help[loc]
1110
+ if sig_help
1111
+ recv = sig_help[:recv]
1112
+ mid = sig_help[:mid]
1113
+ singleton = sig_help[:singleton]
1114
+ mdefs = sig_help[:mdefs]
1115
+ node_id = sig_help[:node_id]
1116
+ mdefs.each do |mdef|
1117
+ case mdef
1118
+ when ISeqMethodDef
1119
+ ctxs = @iseq_method_to_ctxs[mdef]
1120
+ next unless ctxs
1121
+
1122
+ ctx = ctxs.find {|ctx| ctx.mid == mid } || ctxs.first
1123
+
1124
+ method_name = mid
1125
+ method_name = "self.#{ method_name }" if singleton
1126
+
1127
+ str = recv.screen_name(self)
1128
+ str += singleton ? "." : "#"
1129
+ str += method_name.to_s
1130
+ str += ": "
1131
+ sig, _, sig_help = show_method_signature(ctx)
1132
+ offset = str.size
1133
+ sig_help = sig_help.transform_values {|r| (r.begin + offset ... r.end + offset) }
1134
+ str += sig
1135
+ sig_help_res << [str, sig_help, node_id]
1136
+ when AliasMethodDef
1137
+ # TODO
1138
+ when TypedMethodDef
1139
+ mdef.rbs_source&.[](1)&.each do |rbs|
1140
+ # TODO: sig_help
1141
+ sig_help_res << [rbs, {}, node_id]
1142
+ end
1143
+ end
1144
+ end
1145
+ end
1146
+ end
1147
+
1148
+ {
1149
+ sigs: res,
1150
+ errors: errs,
1151
+ completion: @lsp_completion,
1152
+ signature_help: sig_help_res,
1153
+ }
1154
+ end
1155
+
1019
1156
  def globalize_type(ty, env, ep)
1020
1157
  if ep.outer
1021
1158
  tmp_ep = ep
1022
1159
  tmp_ep = tmp_ep.outer while tmp_ep.outer
1023
1160
  env = @return_envs[tmp_ep]
1024
1161
  end
1025
- ty.globalize(env, {}, Config.options[:type_depth_limit])
1162
+ ty.globalize(env, {}, Config.current.options[:type_depth_limit])
1026
1163
  end
1027
1164
 
1028
1165
  def localize_type(ty, env, ep, alloc_site = AllocationSite.new(ep))
@@ -1030,13 +1167,13 @@ module TypeProf
1030
1167
  tmp_ep = ep
1031
1168
  tmp_ep = tmp_ep.outer while tmp_ep.outer
1032
1169
  target_env = @return_envs[tmp_ep]
1033
- target_env, ty = ty.localize(target_env, alloc_site, Config.options[:type_depth_limit])
1170
+ target_env, ty = ty.localize(target_env, alloc_site, Config.current.options[:type_depth_limit])
1034
1171
  merge_return_env(tmp_ep) do |env|
1035
1172
  env ? env.merge(target_env) : target_env
1036
1173
  end
1037
1174
  return env, ty
1038
1175
  else
1039
- return ty.localize(env, alloc_site, Config.options[:type_depth_limit])
1176
+ return ty.localize(env, alloc_site, Config.current.options[:type_depth_limit])
1040
1177
  end
1041
1178
  end
1042
1179
 
@@ -1098,13 +1235,16 @@ module TypeProf
1098
1235
  end
1099
1236
 
1100
1237
  def get_instance_variable(recv, var, ep, env)
1101
- add_ivar_read!(recv, var, ep) do |ty, ep|
1238
+ add_ivar_read!(recv, var, ep) do |ty, ep, write_eps|
1102
1239
  alloc_site = AllocationSite.new(ep)
1103
1240
  nenv, ty = localize_type(ty, env, ep, alloc_site)
1104
1241
  case ty
1105
1242
  when Type::Local
1106
1243
  @alloc_site_to_global_id[ty.id] = [recv, var] # need overwrite check??
1107
1244
  end
1245
+ write_eps.each do |write_ep|
1246
+ ep.ctx.iseq.add_def_loc(ep.pc, write_ep.detailed_source_location)
1247
+ end
1108
1248
  yield ty, nenv
1109
1249
  end
1110
1250
  end
@@ -1118,15 +1258,16 @@ module TypeProf
1118
1258
  env = @ep2env[ep]
1119
1259
  raise "nil env" unless env
1120
1260
 
1121
- insn, operands = ep.ctx.iseq.insns[ep.pc]
1261
+ insn = ep.ctx.iseq.insns[ep.pc]
1262
+ operands = insn.operands
1122
1263
 
1123
- if Config.verbose >= 2
1264
+ if Config.current.verbose >= 2
1124
1265
  # XXX: more dedicated output
1125
1266
  puts "DEBUG: stack=%p" % [env.stack]
1126
- puts "DEBUG: %s (%s) PC=%d insn=%s sp=%d" % [ep.source_location, ep.ctx.iseq.name, ep.pc, insn, env.stack.size]
1267
+ puts "DEBUG: %s (%s) PC=%d insn=%s sp=%d" % [ep.source_location, ep.ctx.iseq.name, ep.pc, insn.insn, env.stack.size]
1127
1268
  end
1128
1269
 
1129
- case insn
1270
+ case insn.insn
1130
1271
  when :_iseq_body_start
1131
1272
  # XXX: reconstruct and record the method signature
1132
1273
  iseq = ep.ctx.iseq
@@ -1289,8 +1430,10 @@ module TypeProf
1289
1430
  case flags & 7
1290
1431
  when 0, 2 # CLASS / MODULE
1291
1432
  type = (flags & 7) == 2 ? :module : :class
1292
- existing_klass = get_constant(cbase, id) # TODO: multiple return values
1433
+ existing_klass, = get_constant(cbase, id) # TODO: multiple return values
1293
1434
  if existing_klass.is_a?(Type::Class)
1435
+ # record re-opening location
1436
+ @class_defs[cbase.idx].add_class_open(id, ep)
1294
1437
  klass = existing_klass
1295
1438
  else
1296
1439
  if existing_klass != Type.any
@@ -1315,7 +1458,7 @@ module TypeProf
1315
1458
  superclass = nil
1316
1459
  end
1317
1460
  if cbase.is_a?(Type::Class)
1318
- klass = new_class(cbase, id, [], superclass, ep.ctx.iseq.absolute_path)
1461
+ klass = new_class(cbase, id, [], superclass, ep)
1319
1462
  if superclass
1320
1463
  add_superclass_type_args!(klass, superclass.type_params.map { Type.any })
1321
1464
 
@@ -1629,7 +1772,7 @@ module TypeProf
1629
1772
  var, = operands
1630
1773
  ty = Type.builtin_global_variable_type(var)
1631
1774
  if ty
1632
- ty = get_constant(Type::Builtin[:obj], ty) if ty.is_a?(Symbol)
1775
+ ty, locs = get_constant(Type::Builtin[:obj], ty) if ty.is_a?(Symbol)
1633
1776
  env, ty = localize_type(ty, env, ep)
1634
1777
  env = env.push(ty)
1635
1778
  else
@@ -1641,7 +1784,7 @@ module TypeProf
1641
1784
  return
1642
1785
  end
1643
1786
 
1644
- when :getlocal, :getblockparam, :getblockparamproxy
1787
+ when :getlocal
1645
1788
  var_idx, scope_idx, _escaped = operands
1646
1789
  if scope_idx == 0
1647
1790
  ty = env.get_local(-var_idx+2)
@@ -1682,18 +1825,12 @@ module TypeProf
1682
1825
  getlocal_operands, _dup_operands, branch_operands = operands
1683
1826
  var_idx, _scope_idx, _escaped = getlocal_operands
1684
1827
  ret_ty = env.get_local(-var_idx+2)
1685
- unless ret_ty
1686
- p env.locals
1687
- raise
1688
- end
1689
1828
 
1690
1829
  branchtype, target, = branch_operands
1691
1830
  # branchtype: :if or :unless or :nil
1692
1831
  ep_then = ep.next
1693
1832
  ep_else = ep.jump(target)
1694
1833
 
1695
- var_idx, _scope_idx, _escaped = getlocal_operands
1696
-
1697
1834
  ret_ty.each_child do |ret_ty|
1698
1835
  flow_env = env.local_update(-var_idx+2, ret_ty).push(ret_ty)
1699
1836
  case ret_ty
@@ -1707,6 +1844,31 @@ module TypeProf
1707
1844
  end
1708
1845
  end
1709
1846
  return
1847
+ when :dup_setlocal_branch
1848
+ _dup_operands, setlocal_operands, branch_operands = operands
1849
+
1850
+ env, (ret_ty,) = env.pop(1)
1851
+
1852
+ var_idx, _scope_idx, _escaped = setlocal_operands
1853
+
1854
+ branchtype, target, = branch_operands
1855
+ # branchtype: :if or :unless or :nil
1856
+ ep_then = ep.next
1857
+ ep_else = ep.jump(target)
1858
+
1859
+ ret_ty.each_child do |ret_ty|
1860
+ flow_env = env.local_update(-var_idx+2, ret_ty)
1861
+ case ret_ty
1862
+ when Type.any
1863
+ merge_env(ep_then, flow_env)
1864
+ merge_env(ep_else, flow_env)
1865
+ when Type::Instance.new(Type::Builtin[:false]), Type.nil
1866
+ merge_env(branchtype == :if ? ep_then : ep_else, flow_env)
1867
+ else
1868
+ merge_env(branchtype == :if ? ep_else : ep_then, flow_env)
1869
+ end
1870
+ end
1871
+ return
1710
1872
  when :getlocal_checkmatch_branch
1711
1873
  getlocal_operands, branch_operands = operands
1712
1874
  var_idx, _scope_idx, _escaped = getlocal_operands
@@ -1755,20 +1917,23 @@ module TypeProf
1755
1917
  name, = operands
1756
1918
  env, (cbase, _allow_nil,) = env.pop(2)
1757
1919
  if cbase == Type.nil
1758
- ty = search_constant(ep.ctx.cref, name)
1920
+ ty, locs = search_constant(ep.ctx.cref, name)
1759
1921
  env, ty = localize_type(ty, env, ep)
1760
1922
  env = env.push(ty)
1761
1923
  elsif cbase == Type.any
1762
1924
  env = env.push(Type.any) # XXX: warning needed?
1763
1925
  else
1764
- ty = get_constant(cbase, name)
1926
+ ty, locs = get_constant(cbase, name)
1765
1927
  env, ty = localize_type(ty, env, ep)
1766
1928
  env = env.push(ty)
1767
1929
  end
1930
+ locs&.each do |loc|
1931
+ ep.ctx.iseq.add_def_loc(ep.pc, loc)
1932
+ end
1768
1933
  when :setconstant
1769
1934
  name, = operands
1770
1935
  env, (ty, cbase) = env.pop(2)
1771
- old_ty = get_constant(cbase, name)
1936
+ old_ty, = get_constant(cbase, name)
1772
1937
  if old_ty != Type.any # XXX???
1773
1938
  warn(ep, "already initialized constant #{ Type::Instance.new(cbase).screen_name(self) }::#{ name }")
1774
1939
  end
@@ -1777,7 +1942,7 @@ module TypeProf
1777
1942
  @class_defs[ty.idx].name = cbase_path(cbase) + [name]
1778
1943
  end
1779
1944
  end
1780
- add_constant(cbase, name, globalize_type(ty, env, ep), ep.ctx.iseq.absolute_path)
1945
+ add_constant(cbase, name, globalize_type(ty, env, ep), ep)
1781
1946
 
1782
1947
  when :getspecial
1783
1948
  key, type = operands
@@ -1970,7 +2135,7 @@ module TypeProf
1970
2135
  end
1971
2136
  env = env.push(ty)
1972
2137
  else
1973
- raise "Unknown insn: #{ insn }"
2138
+ raise "Unknown insn: #{ insn.insn }"
1974
2139
  end
1975
2140
 
1976
2141
  add_edge(ep, ep)
@@ -2165,10 +2330,26 @@ module TypeProf
2165
2330
  merge_return_env(ep) {|tenv| tenv ? tenv.merge(env) : env }
2166
2331
  end
2167
2332
 
2333
+ aargs.node_id = opt[:node_id]
2334
+
2168
2335
  return env, recv, mid, aargs
2169
2336
  end
2170
2337
 
2171
2338
  def do_send(recvs, mid, aargs, ep, env, &ctn)
2339
+ if mid == :__typeprof_lsp_completion
2340
+ names = {}
2341
+ recvs.each_child do |recv|
2342
+ case recv
2343
+ when Type::Void, Type::Any
2344
+ else
2345
+ klass, singleton, include_subclasses = recv.method_dispatch_info
2346
+ names.merge!(get_all_methods(klass, singleton, include_subclasses)) if klass
2347
+ end
2348
+ end
2349
+ @lsp_completion = names
2350
+ return ctn[Type.any, ep, env]
2351
+ end
2352
+
2172
2353
  recvs.each_child do |recv|
2173
2354
  case recv
2174
2355
  when Type::Void
@@ -2180,6 +2361,19 @@ module TypeProf
2180
2361
  klass, singleton, include_subclasses = recv.method_dispatch_info
2181
2362
  meths = get_method(klass, singleton, include_subclasses, mid) if klass
2182
2363
  if meths
2364
+ path, loc = Config.current.options[:signature_help_loc]
2365
+ if path && path == ep.ctx.iseq.path && mid != :inherited # XXX: too ad-hoc!!!
2366
+ path, code_range = ep&.detailed_source_location
2367
+ if path && code_range&.contain_loc?(loc)
2368
+ @lsp_signature_help[code_range] = {
2369
+ recv: recv,
2370
+ mid: mid,
2371
+ singleton: singleton,
2372
+ mdefs: meths,
2373
+ node_id: aargs.node_id,
2374
+ }
2375
+ end
2376
+ end
2183
2377
  meths.each do |meth|
2184
2378
  meth.do_send(recv, mid, aargs, ep, env, self, &ctn)
2185
2379
  end
@@ -2204,7 +2398,7 @@ module TypeProf
2204
2398
  if blk.is_a?(Type::Proc)
2205
2399
  blk.block_body.do_call(aargs, ep, env, self, replace_recv_ty: replace_recv_ty, replace_cref: replace_cref, &ctn)
2206
2400
  else
2207
- warn(ep, "non-proc is passed as a block")
2401
+ warn(ep, "non-proc is passed as a block") if blk != Type.any
2208
2402
  ctn[Type.any, ep, env]
2209
2403
  end
2210
2404
  end
@@ -2261,7 +2455,7 @@ module TypeProf
2261
2455
 
2262
2456
  bsig ||= BlockSignature.new([], [], nil, Type.nil)
2263
2457
 
2264
- bsig = bsig.screen_name(nil, self)
2458
+ bsig, = bsig.screen_name(nil, self)
2265
2459
  ret_ty = ret_ty.screen_name(self)
2266
2460
  ret_ty = (ret_ty.include?("|") ? "(#{ ret_ty })" : ret_ty) # XXX?
2267
2461
 
@@ -2296,7 +2490,7 @@ module TypeProf
2296
2490
 
2297
2491
  begin
2298
2492
  @types_being_shown << farg_tys << ret_ty
2299
- farg_tys = farg_tys ? farg_tys.screen_name(nil, self) : "(unknown)"
2493
+ farg_tys, = farg_tys ? farg_tys.screen_name(nil, self) : ["(unknown)"]
2300
2494
  ret_ty = ret_ty.screen_name(self)
2301
2495
  ret_ty = (ret_ty.include?("|") ? "(#{ ret_ty })" : ret_ty) # XXX?
2302
2496
 
@@ -2309,15 +2503,16 @@ module TypeProf
2309
2503
 
2310
2504
  def show_method_signature(ctx)
2311
2505
  farg_tys = @method_signatures[ctx]
2506
+ return nil unless farg_tys
2312
2507
  ret_ty = ctx.mid == :initialize ? Type::Void.new : @return_values[ctx] || Type.bot
2313
2508
 
2314
2509
  untyped = farg_tys.include_untyped?(self) || ret_ty.include_untyped?(self)
2315
2510
 
2316
- farg_tys = farg_tys.screen_name(ctx.iseq, self)
2511
+ farg_tys, ranges = farg_tys.screen_name(ctx.iseq, self)
2317
2512
  ret_ty = ret_ty.screen_name(self)
2318
2513
  ret_ty = (ret_ty.include?("|") ? "(#{ ret_ty })" : ret_ty) # XXX?
2319
2514
 
2320
- ["#{ (farg_tys.empty? ? "" : "#{ farg_tys } ") }-> #{ ret_ty }", untyped]
2515
+ return "#{ (farg_tys.empty? ? "" : "#{ farg_tys } ") }-> #{ ret_ty }", untyped, ranges
2321
2516
  end
2322
2517
  end
2323
2518
  end