typeprof 0.32.0 → 0.33.1
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/lib/typeprof/core/ast/base.rb +13 -0
- data/lib/typeprof/core/ast/call.rb +47 -30
- data/lib/typeprof/core/ast/const.rb +15 -7
- data/lib/typeprof/core/ast/control.rb +2 -2
- data/lib/typeprof/core/ast/meta.rb +96 -23
- data/lib/typeprof/core/ast/method.rb +18 -14
- data/lib/typeprof/core/ast/misc.rb +16 -7
- data/lib/typeprof/core/ast/module.rb +6 -2
- data/lib/typeprof/core/ast/pattern.rb +51 -23
- data/lib/typeprof/core/ast/sig_decl.rb +67 -10
- data/lib/typeprof/core/ast/sig_type.rb +55 -6
- data/lib/typeprof/core/ast/variable.rb +6 -0
- data/lib/typeprof/core/ast.rb +15 -2
- data/lib/typeprof/core/env/method.rb +192 -20
- data/lib/typeprof/core/env/module_entity.rb +61 -1
- data/lib/typeprof/core/env.rb +17 -3
- data/lib/typeprof/core/graph/box.rb +135 -17
- data/lib/typeprof/core/graph/change_set.rb +11 -6
- data/lib/typeprof/core/service.rb +31 -4
- data/lib/typeprof/version.rb +1 -1
- metadata +2 -2
|
@@ -17,6 +17,7 @@ module TypeProf::Core
|
|
|
17
17
|
$box_counts[self.class] -= 1
|
|
18
18
|
$box_counts[Box] -= 1
|
|
19
19
|
@destroyed = true
|
|
20
|
+
destroy_symbol_proc_call_boxes(genv)
|
|
20
21
|
@changes.reinstall(genv) # rollback all changes
|
|
21
22
|
end
|
|
22
23
|
|
|
@@ -43,6 +44,24 @@ module TypeProf::Core
|
|
|
43
44
|
raise NotImplementedError
|
|
44
45
|
end
|
|
45
46
|
|
|
47
|
+
def add_symbol_proc_call_box(_changes, genv, sym, caller_positionals, caller_keywords = nil)
|
|
48
|
+
return if caller_positionals.empty?
|
|
49
|
+
|
|
50
|
+
recv = caller_positionals.first
|
|
51
|
+
positionals = caller_positionals[1..]
|
|
52
|
+
@symbol_proc_call_boxes ||= {}
|
|
53
|
+
@symbol_proc_call_boxes[[recv, sym, *positionals, caller_keywords]] ||= begin
|
|
54
|
+
a_args = ActualArguments.new(positionals, ::Array.new(positionals.size, false), caller_keywords, nil)
|
|
55
|
+
MethodCallBox.new(@node, genv, recv, sym, a_args, false)
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def destroy_symbol_proc_call_boxes(genv)
|
|
60
|
+
return unless @symbol_proc_call_boxes
|
|
61
|
+
@symbol_proc_call_boxes.each_value { |box| box.destroy(genv) }
|
|
62
|
+
@symbol_proc_call_boxes = nil
|
|
63
|
+
end
|
|
64
|
+
|
|
46
65
|
def to_s
|
|
47
66
|
"#{ self.class.to_s.split("::").last }#{ @id ||= $new_id += 1 }"
|
|
48
67
|
end
|
|
@@ -127,6 +146,12 @@ module TypeProf::Core
|
|
|
127
146
|
}
|
|
128
147
|
end
|
|
129
148
|
|
|
149
|
+
# lazy cache: overloads split into fixed-arity ones and rest-positional ones
|
|
150
|
+
def partition_by_rest_positionals
|
|
151
|
+
@partition_by_rest_positionals ||=
|
|
152
|
+
@method_types.partition {|method_type| !method_type.rest_positionals }
|
|
153
|
+
end
|
|
154
|
+
|
|
130
155
|
private
|
|
131
156
|
|
|
132
157
|
# Check if two method types have structurally identical positional
|
|
@@ -258,6 +283,7 @@ module TypeProf::Core
|
|
|
258
283
|
me = genv.resolve_method(@cpath, @singleton, @mid)
|
|
259
284
|
me.remove_decl(self)
|
|
260
285
|
me.add_run_all_method_call_boxes(genv)
|
|
286
|
+
destroy_symbol_proc_call_boxes(genv)
|
|
261
287
|
end
|
|
262
288
|
|
|
263
289
|
def match_arguments?(genv, changes, param_map, a_args, method_type)
|
|
@@ -382,6 +408,8 @@ module TypeProf::Core
|
|
|
382
408
|
end
|
|
383
409
|
end
|
|
384
410
|
end
|
|
411
|
+
when Type::Symbol
|
|
412
|
+
resolve_symbol_proc(changes, genv, ty.sym, blk_a_args, rbs_blk, param_map0)
|
|
385
413
|
end
|
|
386
414
|
end
|
|
387
415
|
end
|
|
@@ -396,6 +424,13 @@ module TypeProf::Core
|
|
|
396
424
|
end
|
|
397
425
|
end
|
|
398
426
|
|
|
427
|
+
def resolve_symbol_proc(changes, genv, sym, blk_a_args, rbs_blk, param_map)
|
|
428
|
+
box = add_symbol_proc_call_box(changes, genv, sym, blk_a_args)
|
|
429
|
+
return unless box
|
|
430
|
+
|
|
431
|
+
rbs_blk.return_type.typecheck(genv, changes, box.ret, param_map)
|
|
432
|
+
end
|
|
433
|
+
|
|
399
434
|
def resolve_overloads(changes, genv, node, param_map, a_args, ret, &blk)
|
|
400
435
|
if @method_types.size == 1
|
|
401
436
|
method_type = @method_types.first
|
|
@@ -451,11 +486,19 @@ module TypeProf::Core
|
|
|
451
486
|
return
|
|
452
487
|
end
|
|
453
488
|
|
|
489
|
+
# A splatted call can match only a rest-positional overload; otherwise prefer
|
|
490
|
+
# the fixed-arity ones, as a rest-positional one is usually a catch-all
|
|
491
|
+
overload_groups =
|
|
492
|
+
a_args.splat_flags.any? ? [@method_types] : @method_types.partition_by_rest_positionals
|
|
493
|
+
|
|
454
494
|
match_any_overload = false
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
495
|
+
overload_groups.each do |method_types|
|
|
496
|
+
method_types.each do |method_type|
|
|
497
|
+
if resolve_overload(changes, genv, method_type, node, param_map, a_args, ret, false, &blk)
|
|
498
|
+
match_any_overload = true
|
|
499
|
+
end
|
|
458
500
|
end
|
|
501
|
+
break if match_any_overload
|
|
459
502
|
end
|
|
460
503
|
unless match_any_overload
|
|
461
504
|
meth = node.mid_code_range ? :mid_code_range : :code_range
|
|
@@ -600,13 +643,13 @@ module TypeProf::Core
|
|
|
600
643
|
end
|
|
601
644
|
|
|
602
645
|
class SplatBox < Box
|
|
603
|
-
def initialize(node, genv, ary, idx,
|
|
646
|
+
def initialize(node, genv, ary, idx, unresolved_recv = nil)
|
|
604
647
|
super(node)
|
|
605
648
|
@ary = ary
|
|
606
649
|
@idx = idx
|
|
607
|
-
@
|
|
650
|
+
@unresolved_recv = unresolved_recv
|
|
608
651
|
@ary.add_edge(genv, self)
|
|
609
|
-
@
|
|
652
|
+
@unresolved_recv.add_edge(genv, self) if @unresolved_recv
|
|
610
653
|
@ret = Vertex.new(node)
|
|
611
654
|
end
|
|
612
655
|
|
|
@@ -632,14 +675,41 @@ module TypeProf::Core
|
|
|
632
675
|
end
|
|
633
676
|
end
|
|
634
677
|
# For types where to_a is not defined, [*x] wraps x as [x]
|
|
635
|
-
if @
|
|
636
|
-
@
|
|
678
|
+
if @unresolved_recv
|
|
679
|
+
@unresolved_recv.each_type do |ty|
|
|
637
680
|
changes.add_edge(genv, Source.new(ty), @ret)
|
|
638
681
|
end
|
|
639
682
|
end
|
|
640
683
|
end
|
|
641
684
|
end
|
|
642
685
|
|
|
686
|
+
# Merges the keywords being forwarded into the `**rest` hash while keeping the
|
|
687
|
+
# rest's own fields, so that the callee can still tell the two apart.
|
|
688
|
+
class KeywordMergeBox < Box
|
|
689
|
+
def initialize(node, genv, rest, literal_pairs, fallback)
|
|
690
|
+
super(node)
|
|
691
|
+
@rest = rest
|
|
692
|
+
@literal_pairs = literal_pairs
|
|
693
|
+
@fallback = fallback
|
|
694
|
+
@rest.add_edge(genv, self)
|
|
695
|
+
@ret = Vertex.new(node)
|
|
696
|
+
end
|
|
697
|
+
|
|
698
|
+
attr_reader :ret
|
|
699
|
+
|
|
700
|
+
def run0(genv, changes)
|
|
701
|
+
merged = false
|
|
702
|
+
@rest.each_type do |ty|
|
|
703
|
+
if ty.is_a?(Type::Record)
|
|
704
|
+
fields = ty.fields.merge(@literal_pairs)
|
|
705
|
+
changes.add_edge(genv, Source.new(Type::Record.new(genv, fields, ty.base_type(genv))), @ret)
|
|
706
|
+
merged = true
|
|
707
|
+
end
|
|
708
|
+
end
|
|
709
|
+
changes.add_edge(genv, @fallback, @ret) unless merged
|
|
710
|
+
end
|
|
711
|
+
end
|
|
712
|
+
|
|
643
713
|
class HashSplatBox < Box
|
|
644
714
|
def initialize(node, genv, hsh, unified_key, unified_val)
|
|
645
715
|
super(node)
|
|
@@ -1004,29 +1074,42 @@ module TypeProf::Core
|
|
|
1004
1074
|
end
|
|
1005
1075
|
|
|
1006
1076
|
class MethodCallBox < Box
|
|
1007
|
-
|
|
1077
|
+
# `unresolved_recv`, when given, collects the receiver types for which no
|
|
1078
|
+
# method entity was found. Without it those types only become "undefined
|
|
1079
|
+
# method" diagnostics; with it the caller can handle them itself, as `[*x]`
|
|
1080
|
+
# does to wrap a receiver that has no `to_a`.
|
|
1081
|
+
def initialize(node, genv, recv, mid, a_args, subclasses, suppress_errors: false, unresolved_recv: nil)
|
|
1008
1082
|
raise mid.to_s unless mid
|
|
1009
1083
|
super(node)
|
|
1010
1084
|
@recv = recv.new_vertex(genv, node)
|
|
1011
1085
|
@recv.add_edge(genv, self)
|
|
1012
1086
|
@mid = mid
|
|
1013
1087
|
@a_args = a_args.new_vertexes(genv, node)
|
|
1014
|
-
@a_args.
|
|
1015
|
-
@a_args.block.add_edge(genv, self) if @a_args.block
|
|
1088
|
+
@a_args.add_box_edges(genv, self)
|
|
1016
1089
|
@ret = Vertex.new(node)
|
|
1017
1090
|
@subclasses = subclasses
|
|
1018
1091
|
@suppress_errors = suppress_errors
|
|
1092
|
+
@unresolved_recv = unresolved_recv
|
|
1019
1093
|
@generics = {}
|
|
1020
1094
|
end
|
|
1021
1095
|
|
|
1022
1096
|
attr_reader :recv, :mid, :ret
|
|
1023
1097
|
|
|
1024
1098
|
def run0(genv, changes)
|
|
1099
|
+
a_args = @a_args.normalize_for_method_call(genv)
|
|
1100
|
+
return unless a_args
|
|
1101
|
+
|
|
1025
1102
|
edges = Set.empty
|
|
1026
1103
|
called_mdefs = Set.empty
|
|
1027
1104
|
error_count = 0
|
|
1028
1105
|
resolve(genv, changes) do |me, ty, mid, orig_ty|
|
|
1029
|
-
if
|
|
1106
|
+
if @node.is_a?(AST::YieldNode) && mid == :call && orig_ty.is_a?(Type::Symbol)
|
|
1107
|
+
box = add_symbol_proc_call_box(changes, genv, orig_ty.sym, a_args.positionals, a_args.keywords)
|
|
1108
|
+
changes.add_edge(genv, box.ret, @ret) if box
|
|
1109
|
+
elsif !me
|
|
1110
|
+
if @unresolved_recv
|
|
1111
|
+
changes.add_edge(genv, Source.new(orig_ty), @unresolved_recv)
|
|
1112
|
+
end
|
|
1030
1113
|
unless @suppress_errors
|
|
1031
1114
|
if error_count < 3
|
|
1032
1115
|
meth = @node.mid_code_range ? :mid_code_range : :code_range
|
|
@@ -1034,7 +1117,7 @@ module TypeProf::Core
|
|
|
1034
1117
|
end
|
|
1035
1118
|
end
|
|
1036
1119
|
error_count += 1
|
|
1037
|
-
elsif me.builtin && me.builtin[changes, @node, orig_ty,
|
|
1120
|
+
elsif me.builtin && me.builtin[changes, @node, orig_ty, a_args, @ret]
|
|
1038
1121
|
# do nothing
|
|
1039
1122
|
elsif !me.decls.empty?
|
|
1040
1123
|
# TODO: support "| ..."
|
|
@@ -1047,7 +1130,7 @@ module TypeProf::Core
|
|
|
1047
1130
|
ty_env[param] = arg || (default_ty ? default_ty.covariant_vertex(genv, changes, ty_env) : Source.new)
|
|
1048
1131
|
end
|
|
1049
1132
|
end
|
|
1050
|
-
mdecl.resolve_overloads(changes, genv, @node, ty_env,
|
|
1133
|
+
mdecl.resolve_overloads(changes, genv, @node, ty_env, a_args, @ret) do |method_type|
|
|
1051
1134
|
@generics[method_type] ||= method_type.type_params.map { Vertex.new(@node) }
|
|
1052
1135
|
end
|
|
1053
1136
|
end
|
|
@@ -1055,7 +1138,7 @@ module TypeProf::Core
|
|
|
1055
1138
|
me.defs.each do |mdef|
|
|
1056
1139
|
next if called_mdefs.include?(mdef)
|
|
1057
1140
|
called_mdefs << mdef
|
|
1058
|
-
mdef.call(changes, genv,
|
|
1141
|
+
mdef.call(changes, genv, a_args, @ret)
|
|
1059
1142
|
end
|
|
1060
1143
|
else
|
|
1061
1144
|
pp me
|
|
@@ -1068,7 +1151,7 @@ module TypeProf::Core
|
|
|
1068
1151
|
me.defs.each do |mdef|
|
|
1069
1152
|
next if called_mdefs.include?(mdef)
|
|
1070
1153
|
called_mdefs << mdef
|
|
1071
|
-
mdef.call(changes, genv,
|
|
1154
|
+
mdef.call(changes, genv, a_args, @ret)
|
|
1072
1155
|
end
|
|
1073
1156
|
end
|
|
1074
1157
|
end
|
|
@@ -1126,7 +1209,10 @@ module TypeProf::Core
|
|
|
1126
1209
|
skip = false
|
|
1127
1210
|
|
|
1128
1211
|
if ty.is_a?(Type::Singleton)
|
|
1129
|
-
#
|
|
1212
|
+
# Check extended modules (their instance methods are singleton methods here)
|
|
1213
|
+
break if resolve_extended_modules(genv, changes, base_ty_env, ty, mid) do |me, ty, mid|
|
|
1214
|
+
yield me, ty, mid, orig_ty
|
|
1215
|
+
end
|
|
1130
1216
|
else
|
|
1131
1217
|
# Finally check included modules
|
|
1132
1218
|
break if resolve_included_modules(genv, changes, base_ty_env, ty, mid) do |me, ty, mid|
|
|
@@ -1226,6 +1312,38 @@ module TypeProf::Core
|
|
|
1226
1312
|
found
|
|
1227
1313
|
end
|
|
1228
1314
|
|
|
1315
|
+
def resolve_extended_modules(genv, changes, base_ty_env, ty, mid, &blk)
|
|
1316
|
+
found = false
|
|
1317
|
+
|
|
1318
|
+
alias_limit = 0
|
|
1319
|
+
# An extended module's instance methods are resolved as the receiver's
|
|
1320
|
+
# singleton methods, so look them up with singleton = false.
|
|
1321
|
+
ty.mod.extended_modules.each do |ext_decl, ext_mod|
|
|
1322
|
+
if ext_decl.is_a?(AST::SigExtendNode) && ext_mod.type_params
|
|
1323
|
+
ext_ty = genv.get_instance_type(ext_mod, ext_decl.args, changes, base_ty_env, ty)
|
|
1324
|
+
else
|
|
1325
|
+
type_params = ext_mod.type_params.map { Source.new() } # TODO: better support
|
|
1326
|
+
ext_ty = Type::Instance.new(genv, ext_mod, type_params)
|
|
1327
|
+
end
|
|
1328
|
+
|
|
1329
|
+
me = ext_ty.mod.get_method(false, mid)
|
|
1330
|
+
changes.add_depended_method_entity(me) if changes
|
|
1331
|
+
if !me.aliases.empty?
|
|
1332
|
+
mid = me.aliases.values.first
|
|
1333
|
+
alias_limit += 1
|
|
1334
|
+
redo if alias_limit < 5
|
|
1335
|
+
end
|
|
1336
|
+
if me.exist?
|
|
1337
|
+
found = true
|
|
1338
|
+
yield me, ext_ty, mid
|
|
1339
|
+
else
|
|
1340
|
+
# The extended module may itself include other modules.
|
|
1341
|
+
found ||= resolve_included_modules(genv, changes, base_ty_env, ext_ty, mid, &blk)
|
|
1342
|
+
end
|
|
1343
|
+
end
|
|
1344
|
+
found
|
|
1345
|
+
end
|
|
1346
|
+
|
|
1229
1347
|
def resolve_subclasses(genv, changes)
|
|
1230
1348
|
# TODO: This does not follow new subclasses
|
|
1231
1349
|
@recv.each_type do |ty|
|
|
@@ -71,9 +71,9 @@ module TypeProf::Core
|
|
|
71
71
|
|
|
72
72
|
# TODO: if an edge is removed during one analysis, we may need to remove sub-boxes?
|
|
73
73
|
|
|
74
|
-
def add_method_call_box(genv, recv, mid, a_args, subclasses, suppress_errors: false)
|
|
75
|
-
key = [:mcall, recv, mid, a_args, subclasses, suppress_errors]
|
|
76
|
-
new_boxes[key] ||= MethodCallBox.new(@node, genv, recv, mid, a_args, subclasses, suppress_errors: suppress_errors)
|
|
74
|
+
def add_method_call_box(genv, recv, mid, a_args, subclasses, suppress_errors: false, unresolved_recv: nil)
|
|
75
|
+
key = [:mcall, recv, mid, a_args, subclasses, suppress_errors, unresolved_recv]
|
|
76
|
+
new_boxes[key] ||= MethodCallBox.new(@node, genv, recv, mid, a_args, subclasses, suppress_errors: suppress_errors, unresolved_recv: unresolved_recv)
|
|
77
77
|
end
|
|
78
78
|
|
|
79
79
|
def add_escape_box(genv, a_ret)
|
|
@@ -81,9 +81,14 @@ module TypeProf::Core
|
|
|
81
81
|
new_boxes[key] ||= EscapeBox.new(@node, genv, a_ret)
|
|
82
82
|
end
|
|
83
83
|
|
|
84
|
-
def add_splat_box(genv, arg, idx = nil,
|
|
85
|
-
key = [:splat, arg, idx,
|
|
86
|
-
new_boxes[key] ||= SplatBox.new(@node, genv, arg, idx,
|
|
84
|
+
def add_splat_box(genv, arg, idx = nil, unresolved_recv = nil)
|
|
85
|
+
key = [:splat, arg, idx, unresolved_recv]
|
|
86
|
+
new_boxes[key] ||= SplatBox.new(@node, genv, arg, idx, unresolved_recv)
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def add_keyword_merge_box(genv, rest, literal_pairs, fallback)
|
|
90
|
+
key = [:kw_merge, rest, literal_pairs, fallback]
|
|
91
|
+
new_boxes[key] ||= KeywordMergeBox.new(@node, genv, rest, literal_pairs, fallback)
|
|
87
92
|
end
|
|
88
93
|
|
|
89
94
|
def add_hash_splat_box(genv, arg, unified_key, unified_val)
|
|
@@ -55,10 +55,15 @@ module TypeProf::Core
|
|
|
55
55
|
end
|
|
56
56
|
|
|
57
57
|
def update_rb_file(path, code)
|
|
58
|
+
code = File.read(path) unless code
|
|
59
|
+
update_rb_ast(path, Prism.parse(code))
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
# path is used only as a key to find the previous analysis; the file is not read.
|
|
63
|
+
def update_rb_ast(path, parse_result)
|
|
58
64
|
prev_node = @rb_text_nodes[path]
|
|
59
65
|
|
|
60
|
-
|
|
61
|
-
node = AST.parse_rb(path, code, @options[:position_encoding])
|
|
66
|
+
node = AST.build_rb(path, parse_result, @options[:position_encoding])
|
|
62
67
|
return false unless node
|
|
63
68
|
|
|
64
69
|
node.diff(@rb_text_nodes[path]) if prev_node
|
|
@@ -405,7 +410,9 @@ module TypeProf::Core
|
|
|
405
410
|
break
|
|
406
411
|
end
|
|
407
412
|
end
|
|
408
|
-
|
|
413
|
+
# The base class has no name to show
|
|
414
|
+
owner = mod.cpath.last == AST::StructNewNode::BASE_CNAME ? base_ty.mod : mod
|
|
415
|
+
yield mid, "#{ owner.cpath.join("::" )}#{ singleton ? "." : "#" }#{ mid } : #{ sig }" if sig
|
|
409
416
|
end
|
|
410
417
|
end
|
|
411
418
|
end
|
|
@@ -456,6 +463,7 @@ module TypeProf::Core
|
|
|
456
463
|
def dump_declarations(path)
|
|
457
464
|
stack = []
|
|
458
465
|
out = []
|
|
466
|
+
seen_consts = Set.empty
|
|
459
467
|
@rb_text_nodes[path]&.traverse do |event, node|
|
|
460
468
|
case node
|
|
461
469
|
when AST::ModuleNode
|
|
@@ -480,6 +488,10 @@ module TypeProf::Core
|
|
|
480
488
|
s = "class #{ format_declared_const_path(node.static_cpath, stack) }"
|
|
481
489
|
mod = @genv.resolve_cpath(node.static_cpath)
|
|
482
490
|
superclass = mod.superclass
|
|
491
|
+
# The base class is not shown; its members are printed inline
|
|
492
|
+
while superclass && superclass.cpath.last == AST::StructNewNode::BASE_CNAME
|
|
493
|
+
superclass = superclass.superclass
|
|
494
|
+
end
|
|
483
495
|
if superclass == nil
|
|
484
496
|
s << " # failed to identify its superclass"
|
|
485
497
|
elsif superclass.cpath != []
|
|
@@ -496,8 +508,16 @@ module TypeProf::Core
|
|
|
496
508
|
out << " " * stack.size + "include #{ inc_mod.show_cpath }"
|
|
497
509
|
end
|
|
498
510
|
end
|
|
511
|
+
mod.extended_modules.each do |ext_def, ext_mod|
|
|
512
|
+
if ext_def.is_a?(AST::ConstantReadNode) && ext_def.lenv.path == path
|
|
513
|
+
out << " " * stack.size + "extend #{ ext_mod.show_cpath }"
|
|
514
|
+
end
|
|
515
|
+
end
|
|
499
516
|
# Output method definitions from meta nodes (StructNewNode etc.)
|
|
500
517
|
node.boxes(:mdef) do |mdef|
|
|
518
|
+
# A user-written method overrides the generated one
|
|
519
|
+
next if node.is_a?(AST::StructNewNode) &&
|
|
520
|
+
!@genv.resolve_method(node.static_cpath, mdef.singleton, mdef.mid).defs.empty?
|
|
501
521
|
out << " " * stack.size + "def #{ mdef.singleton ? "self." : "" }#{ mdef.mid }: " + mdef.show(@options[:output_parameter_names])
|
|
502
522
|
end
|
|
503
523
|
else
|
|
@@ -508,7 +528,14 @@ module TypeProf::Core
|
|
|
508
528
|
when AST::ConstantWriteNode
|
|
509
529
|
if node.static_cpath
|
|
510
530
|
if event == :enter
|
|
511
|
-
|
|
531
|
+
unless seen_consts.include?(node.static_cpath)
|
|
532
|
+
seen_consts << node.static_cpath
|
|
533
|
+
cdef = @genv.resolve_const(node.static_cpath)
|
|
534
|
+
# Use the assigned value for a single write so a same-named class
|
|
535
|
+
# or module (e.g. declared in RBS) is not mixed in; union the types otherwise.
|
|
536
|
+
ret = cdef.defs.size > 1 ? cdef.vtx : node.ret
|
|
537
|
+
out << " " * stack.size + "#{ format_declared_const_path(node.static_cpath, stack) }: #{ ret.show }"
|
|
538
|
+
end
|
|
512
539
|
end
|
|
513
540
|
end
|
|
514
541
|
else
|
data/lib/typeprof/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: typeprof
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.33.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Yusuke Endoh
|
|
@@ -118,7 +118,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
118
118
|
- !ruby/object:Gem::Version
|
|
119
119
|
version: '0'
|
|
120
120
|
requirements: []
|
|
121
|
-
rubygems_version: 4.0.
|
|
121
|
+
rubygems_version: 4.0.16
|
|
122
122
|
specification_version: 4
|
|
123
123
|
summary: TypeProf is a type analysis tool for Ruby code based on abstract interpretation
|
|
124
124
|
test_files: []
|