typeprof 0.15.0 → 0.20.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (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