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.
- 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
|