typeprof 0.15.0 → 0.20.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/main.yml +1 -1
- data/Gemfile.lock +4 -4
- data/exe/typeprof +5 -1
- data/lib/typeprof/analyzer.rb +261 -66
- data/lib/typeprof/arguments.rb +1 -0
- data/lib/typeprof/builtin.rb +30 -22
- data/lib/typeprof/cli.rb +22 -2
- data/lib/typeprof/code-range.rb +177 -0
- data/lib/typeprof/config.rb +43 -18
- data/lib/typeprof/container-type.rb +10 -1
- data/lib/typeprof/export.rb +199 -20
- data/lib/typeprof/import.rb +30 -4
- data/lib/typeprof/iseq.rb +504 -200
- data/lib/typeprof/lsp.rb +865 -0
- data/lib/typeprof/method.rb +17 -13
- data/lib/typeprof/type.rb +46 -38
- data/lib/typeprof/utils.rb +18 -1
- data/lib/typeprof/version.rb +1 -1
- data/lib/typeprof.rb +3 -0
- data/smoke/array15.rb +1 -1
- data/smoke/array6.rb +2 -2
- data/smoke/array8.rb +1 -1
- data/smoke/block-args2.rb +3 -3
- data/smoke/block-args3.rb +4 -4
- data/smoke/break2.rb +1 -1
- data/smoke/gvar2.rb +0 -3
- data/smoke/hash-bot.rb +1 -1
- data/smoke/hash4.rb +1 -1
- data/smoke/identifier_keywords.rb +17 -0
- data/smoke/next2.rb +1 -1
- data/smoke/or_raise.rb +18 -0
- data/smoke/parameterizedd-self.rb +2 -2
- data/smoke/pattern-match1.rb +1 -6
- data/smoke/rbs-vars.rb +0 -3
- data/testbed/ao.rb +1 -1
- data/typeprof-lsp +3 -0
- data/typeprof.gemspec +1 -1
- data/vscode/.gitignore +5 -0
- data/vscode/.vscode/launch.json +16 -0
- data/vscode/.vscodeignore +7 -0
- data/vscode/README.md +22 -0
- data/vscode/development.md +31 -0
- data/vscode/package-lock.json +2211 -0
- data/vscode/package.json +71 -0
- data/vscode/sandbox/test.rb +24 -0
- data/vscode/src/extension.ts +285 -0
- data/vscode/tsconfig.json +15 -0
- metadata +20 -5
data/lib/typeprof/analyzer.rb
CHANGED
@@ -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, :
|
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,
|
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,
|
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,
|
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,
|
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,
|
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
|
-
|
616
|
-
return
|
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,
|
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,
|
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
|
-
|
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 |
|
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
|
-
|
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
|
-
|
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.
|
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
|
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
|
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
|
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
|
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
|
-
|
2515
|
+
return "#{ (farg_tys.empty? ? "" : "#{ farg_tys } ") }-> #{ ret_ty }", untyped, ranges
|
2321
2516
|
end
|
2322
2517
|
end
|
2323
2518
|
end
|