typeprof 0.31.1 → 0.32.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/README.md +2 -1
- data/doc/report_guide.md +88 -0
- data/lib/typeprof/cli/cli.rb +9 -3
- data/lib/typeprof/code_range.rb +7 -5
- data/lib/typeprof/core/ast/base.rb +18 -6
- data/lib/typeprof/core/ast/call.rb +96 -32
- data/lib/typeprof/core/ast/const.rb +12 -9
- data/lib/typeprof/core/ast/control.rb +60 -30
- data/lib/typeprof/core/ast/meta.rb +194 -2
- data/lib/typeprof/core/ast/method.rb +74 -20
- data/lib/typeprof/core/ast/misc.rb +27 -7
- data/lib/typeprof/core/ast/module.rb +33 -3
- data/lib/typeprof/core/ast/sig_decl.rb +85 -24
- data/lib/typeprof/core/ast/sig_type.rb +77 -31
- data/lib/typeprof/core/ast/value.rb +14 -6
- data/lib/typeprof/core/ast/variable.rb +11 -4
- data/lib/typeprof/core/ast.rb +95 -14
- data/lib/typeprof/core/builtin.rb +184 -12
- data/lib/typeprof/core/env/method.rb +171 -6
- data/lib/typeprof/core/env/method_entity.rb +18 -15
- data/lib/typeprof/core/env/module_entity.rb +56 -18
- data/lib/typeprof/core/env/static_read.rb +4 -4
- data/lib/typeprof/core/env/type_alias_entity.rb +1 -1
- data/lib/typeprof/core/env/value_entity.rb +25 -3
- data/lib/typeprof/core/env.rb +79 -17
- data/lib/typeprof/core/graph/box.rb +379 -52
- data/lib/typeprof/core/graph/change_set.rb +59 -46
- data/lib/typeprof/core/graph/filter.rb +8 -5
- data/lib/typeprof/core/graph/vertex.rb +20 -19
- data/lib/typeprof/core/service.rb +317 -23
- data/lib/typeprof/core/type.rb +41 -7
- data/lib/typeprof/core/util.rb +6 -0
- data/lib/typeprof/lsp/messages.rb +5 -0
- data/lib/typeprof/lsp/server.rb +35 -4
- data/lib/typeprof/version.rb +1 -1
- metadata +3 -2
|
@@ -3,30 +3,33 @@ module TypeProf::Core
|
|
|
3
3
|
def initialize(node, target)
|
|
4
4
|
@node = node
|
|
5
5
|
@target = target
|
|
6
|
-
@new_vertexes = {}
|
|
7
|
-
@covariant_types = {}
|
|
8
|
-
@contravariant_types = {}
|
|
9
|
-
@edges = []
|
|
10
|
-
@new_edges = []
|
|
11
|
-
@boxes = {}
|
|
12
|
-
@new_boxes = {}
|
|
13
6
|
@diagnostics = []
|
|
14
7
|
@new_diagnostics = []
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
8
|
+
if target
|
|
9
|
+
@depended_value_entities = []
|
|
10
|
+
@new_depended_value_entities = []
|
|
11
|
+
@depended_method_entities = []
|
|
12
|
+
@new_depended_method_entities = []
|
|
13
|
+
@depended_static_reads = []
|
|
14
|
+
@new_depended_static_reads = []
|
|
15
|
+
@depended_superclasses = []
|
|
16
|
+
@new_depended_superclasses = []
|
|
17
|
+
end
|
|
23
18
|
end
|
|
24
19
|
|
|
25
|
-
attr_reader :node, :target, :
|
|
20
|
+
attr_reader :node, :target, :diagnostics
|
|
21
|
+
|
|
22
|
+
def covariant_types = @covariant_types ||= {}
|
|
23
|
+
def contravariant_types = @contravariant_types ||= {}
|
|
24
|
+
def edges = @edges ||= {}
|
|
25
|
+
def boxes = @boxes ||= {}
|
|
26
|
+
|
|
27
|
+
private def new_edges = @new_edges ||= {}
|
|
28
|
+
private def new_boxes = @new_boxes ||= {}
|
|
26
29
|
|
|
27
30
|
def reuse(new_node)
|
|
28
31
|
@node = new_node
|
|
29
|
-
|
|
32
|
+
boxes.each_value do |box|
|
|
30
33
|
box.reuse(new_node)
|
|
31
34
|
end
|
|
32
35
|
end
|
|
@@ -46,6 +49,7 @@ module TypeProf::Core
|
|
|
46
49
|
end
|
|
47
50
|
|
|
48
51
|
def new_vertex(genv, origin, base_vtx)
|
|
52
|
+
@new_vertexes ||= {}
|
|
49
53
|
new_vtx = @new_vertexes[base_vtx] ||= Vertex.new(origin)
|
|
50
54
|
add_edge(genv, base_vtx, new_vtx)
|
|
51
55
|
new_vtx
|
|
@@ -53,88 +57,88 @@ module TypeProf::Core
|
|
|
53
57
|
|
|
54
58
|
def new_covariant_vertex(genv, sig_type_node)
|
|
55
59
|
# This is used to avoid duplicated vertex generation for the same sig node
|
|
56
|
-
|
|
60
|
+
covariant_types[sig_type_node] ||= Vertex.new(sig_type_node)
|
|
57
61
|
end
|
|
58
62
|
|
|
59
63
|
def new_contravariant_vertex(genv, sig_type_node)
|
|
60
64
|
# This is used to avoid duplicated vertex generation for the same sig node
|
|
61
|
-
|
|
65
|
+
contravariant_types[sig_type_node] ||= Vertex.new(sig_type_node)
|
|
62
66
|
end
|
|
63
67
|
|
|
64
68
|
def add_edge(genv, src, dst)
|
|
65
|
-
|
|
69
|
+
(new_edges[src] ||= {})[dst] = true
|
|
66
70
|
end
|
|
67
71
|
|
|
68
72
|
# TODO: if an edge is removed during one analysis, we may need to remove sub-boxes?
|
|
69
73
|
|
|
70
|
-
def add_method_call_box(genv, recv, mid, a_args, subclasses)
|
|
71
|
-
key = [:mcall, recv, mid, a_args, subclasses]
|
|
72
|
-
|
|
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)
|
|
73
77
|
end
|
|
74
78
|
|
|
75
79
|
def add_escape_box(genv, a_ret)
|
|
76
80
|
key = [:return, a_ret]
|
|
77
|
-
|
|
81
|
+
new_boxes[key] ||= EscapeBox.new(@node, genv, a_ret)
|
|
78
82
|
end
|
|
79
83
|
|
|
80
|
-
def add_splat_box(genv, arg, idx = nil)
|
|
81
|
-
key = [:splat, arg, idx]
|
|
82
|
-
|
|
84
|
+
def add_splat_box(genv, arg, idx = nil, orig = nil)
|
|
85
|
+
key = [:splat, arg, idx, orig]
|
|
86
|
+
new_boxes[key] ||= SplatBox.new(@node, genv, arg, idx, orig)
|
|
83
87
|
end
|
|
84
88
|
|
|
85
89
|
def add_hash_splat_box(genv, arg, unified_key, unified_val)
|
|
86
90
|
key = [:hash_splat, arg, unified_key, unified_val]
|
|
87
|
-
|
|
91
|
+
new_boxes[key] ||= HashSplatBox.new(@node, genv, arg, unified_key, unified_val)
|
|
88
92
|
end
|
|
89
93
|
|
|
90
94
|
def add_masgn_box(genv, value, lefts, rest_elem, rights)
|
|
91
95
|
key = [:masgn, value, lefts, rest_elem, rights]
|
|
92
|
-
|
|
96
|
+
new_boxes[key] ||= MAsgnBox.new(@node, genv, value, lefts, rest_elem, rights)
|
|
93
97
|
end
|
|
94
98
|
|
|
95
99
|
def add_method_def_box(genv, cpath, singleton, mid, f_args, ret_boxes)
|
|
96
100
|
key = [:mdef, cpath, singleton, mid, f_args, ret_boxes]
|
|
97
|
-
|
|
101
|
+
new_boxes[key] ||= MethodDefBox.new(@node, genv, cpath, singleton, mid, f_args, ret_boxes)
|
|
98
102
|
end
|
|
99
103
|
|
|
100
104
|
def add_method_decl_box(genv, cpath, singleton, mid, method_types, overloading)
|
|
101
105
|
key = [:mdecl, cpath, singleton, mid, method_types, overloading]
|
|
102
|
-
|
|
106
|
+
new_boxes[key] ||= MethodDeclBox.new(@node, genv, cpath, singleton, mid, method_types, overloading)
|
|
103
107
|
end
|
|
104
108
|
|
|
105
109
|
def add_method_alias_box(genv, cpath, singleton, new_mid, old_mid)
|
|
106
110
|
key = [:mdecl, cpath, singleton, new_mid, old_mid]
|
|
107
|
-
|
|
111
|
+
new_boxes[key] ||= MethodAliasBox.new(@node, genv, cpath, singleton, new_mid, old_mid)
|
|
108
112
|
end
|
|
109
113
|
|
|
110
114
|
def add_const_read_box(genv, static_ret)
|
|
111
115
|
key = [:cread, static_ret]
|
|
112
|
-
|
|
116
|
+
new_boxes[key] ||= ConstReadBox.new(@node, genv, static_ret)
|
|
113
117
|
end
|
|
114
118
|
|
|
115
119
|
def add_gvar_read_box(genv, var)
|
|
116
120
|
key = [:gvar_read, var]
|
|
117
|
-
|
|
121
|
+
new_boxes[key] ||= GVarReadBox.new(@node, genv, var)
|
|
118
122
|
end
|
|
119
123
|
|
|
120
124
|
def add_ivar_read_box(genv, cpath, singleton, name)
|
|
121
125
|
key = [:ivar_read, cpath, singleton, name]
|
|
122
|
-
|
|
126
|
+
new_boxes[key] ||= IVarReadBox.new(@node, genv, cpath, singleton, name)
|
|
123
127
|
end
|
|
124
128
|
|
|
125
129
|
def add_cvar_read_box(genv, cpath, name)
|
|
126
130
|
key = [:cvar_read, cpath, name]
|
|
127
|
-
|
|
131
|
+
new_boxes[key] ||= CVarReadBox.new(@node, genv, cpath, name)
|
|
128
132
|
end
|
|
129
133
|
|
|
130
134
|
def add_type_read_box(genv, type)
|
|
131
135
|
key = [:type_read, type]
|
|
132
|
-
|
|
136
|
+
new_boxes[key] ||= TypeReadBox.new(@node, genv, type)
|
|
133
137
|
end
|
|
134
138
|
|
|
135
139
|
def add_instance_type_box(genv, singleton_ty_vtx)
|
|
136
140
|
key = [:instance_type, singleton_ty_vtx]
|
|
137
|
-
|
|
141
|
+
new_boxes[key] ||= InstanceTypeBox.new(@node, genv, singleton_ty_vtx)
|
|
138
142
|
end
|
|
139
143
|
|
|
140
144
|
def add_diagnostic(meth, msg, node = @node)
|
|
@@ -158,21 +162,28 @@ module TypeProf::Core
|
|
|
158
162
|
end
|
|
159
163
|
|
|
160
164
|
def reinstall(genv)
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
165
|
+
# Edges stored as nested hashes: {src => {dst => true}}
|
|
166
|
+
new_edges.each do |src, new_dsts|
|
|
167
|
+
old_dsts = edges[src]
|
|
168
|
+
new_dsts.each_key do |dst|
|
|
169
|
+
src.add_edge(genv, dst) unless old_dsts&.key?(dst)
|
|
170
|
+
end
|
|
164
171
|
end
|
|
165
|
-
|
|
166
|
-
|
|
172
|
+
edges.each do |src, old_dsts|
|
|
173
|
+
new_dsts = new_edges[src]
|
|
174
|
+
old_dsts.each_key do |dst|
|
|
175
|
+
src.remove_edge(genv, dst) unless new_dsts&.key?(dst)
|
|
176
|
+
end
|
|
167
177
|
end
|
|
168
178
|
@edges, @new_edges = @new_edges, @edges
|
|
169
|
-
|
|
179
|
+
new_edges.each_value(&:clear)
|
|
180
|
+
new_edges.clear
|
|
170
181
|
|
|
171
|
-
|
|
182
|
+
boxes.each do |key, box|
|
|
172
183
|
box.destroy(genv)
|
|
173
184
|
end
|
|
174
185
|
@boxes, @new_boxes = @new_boxes, @boxes
|
|
175
|
-
|
|
186
|
+
new_boxes.clear
|
|
176
187
|
|
|
177
188
|
@diagnostics.each do |diag|
|
|
178
189
|
genv.add_diagnostic_path(diag.node.lenv.path)
|
|
@@ -185,6 +196,8 @@ module TypeProf::Core
|
|
|
185
196
|
@diagnostics, @new_diagnostics = @new_diagnostics, @diagnostics
|
|
186
197
|
@new_diagnostics.clear
|
|
187
198
|
|
|
199
|
+
return unless @target
|
|
200
|
+
|
|
188
201
|
@depended_value_entities.each do |ve|
|
|
189
202
|
ve.read_boxes.delete(@target) || raise
|
|
190
203
|
end
|
|
@@ -39,7 +39,7 @@ module TypeProf::Core
|
|
|
39
39
|
class IsAFilter < Filter
|
|
40
40
|
def initialize(genv, node, prev_vtx, neg, const_read)
|
|
41
41
|
@node = node
|
|
42
|
-
@types = Set
|
|
42
|
+
@types = Set.empty
|
|
43
43
|
@const_read = const_read
|
|
44
44
|
@const_read.followers << self
|
|
45
45
|
@next_vtx = Vertex.new(node)
|
|
@@ -112,14 +112,17 @@ module TypeProf::Core
|
|
|
112
112
|
|
|
113
113
|
def on_type_added(genv, src_var, added_types)
|
|
114
114
|
if src_var == @base_vtx
|
|
115
|
-
if @base_vtx.types.size == 1 && @base_vtx.types.include?(
|
|
115
|
+
if @base_vtx.types.size == 1 && @base_vtx.types.include?(genv.bot_type)
|
|
116
116
|
@next_vtx.on_type_removed(genv, self, @types.keys & @next_vtx.types.keys) # XXX: smoke/control/bot2.rb
|
|
117
|
+
else
|
|
118
|
+
# base_vtx is no longer bot-only; restore any previously suppressed types
|
|
119
|
+
@next_vtx.on_type_added(genv, self, @types.keys - @next_vtx.types.keys)
|
|
117
120
|
end
|
|
118
121
|
else
|
|
119
122
|
added_types.each do |ty|
|
|
120
123
|
@types[ty] = true
|
|
121
124
|
end
|
|
122
|
-
if @base_vtx.types.size == 1 && @base_vtx.types.include?(
|
|
125
|
+
if @base_vtx.types.size == 1 && @base_vtx.types.include?(genv.bot_type)
|
|
123
126
|
# ignore
|
|
124
127
|
else
|
|
125
128
|
@next_vtx.on_type_added(genv, self, added_types - @next_vtx.types.keys) # XXX: smoke/control/bot4.rb
|
|
@@ -129,7 +132,7 @@ module TypeProf::Core
|
|
|
129
132
|
|
|
130
133
|
def on_type_removed(genv, src_var, removed_types)
|
|
131
134
|
if src_var == @base_vtx
|
|
132
|
-
if @base_vtx.types.size == 1 && @base_vtx.types.include?(
|
|
135
|
+
if @base_vtx.types.size == 1 && @base_vtx.types.include?(genv.bot_type)
|
|
133
136
|
# ignore
|
|
134
137
|
else
|
|
135
138
|
@next_vtx.on_type_added(genv, self, @types.keys - @next_vtx.types.keys) # XXX: smoke/control/bot4.rb
|
|
@@ -138,7 +141,7 @@ module TypeProf::Core
|
|
|
138
141
|
removed_types.each do |ty|
|
|
139
142
|
@types.delete(ty) || raise
|
|
140
143
|
end
|
|
141
|
-
if @base_vtx.types.size == 1 && @base_vtx.types.include?(
|
|
144
|
+
if @base_vtx.types.size == 1 && @base_vtx.types.include?(genv.bot_type)
|
|
142
145
|
# ignore
|
|
143
146
|
else
|
|
144
147
|
@next_vtx.on_type_removed(genv, self, removed_types & @next_vtx.types.keys) # XXX: smoke/control/bot2.rb
|
|
@@ -2,7 +2,6 @@ module TypeProf::Core
|
|
|
2
2
|
class BasicVertex
|
|
3
3
|
def initialize(types)
|
|
4
4
|
@types = types
|
|
5
|
-
@types_to_be_added = {}
|
|
6
5
|
end
|
|
7
6
|
|
|
8
7
|
attr_reader :types
|
|
@@ -10,18 +9,20 @@ module TypeProf::Core
|
|
|
10
9
|
def each_type(&blk)
|
|
11
10
|
@types.each_key(&blk)
|
|
12
11
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
12
|
+
if @types_to_be_added
|
|
13
|
+
until @types_to_be_added.empty?
|
|
14
|
+
h = @types_to_be_added.dup
|
|
15
|
+
h.each do |ty, source|
|
|
16
|
+
@types[ty] = source
|
|
17
|
+
end
|
|
18
|
+
@types_to_be_added.clear
|
|
19
|
+
h.each_key(&blk)
|
|
17
20
|
end
|
|
18
|
-
@types_to_be_added.clear
|
|
19
|
-
h.each_key(&blk)
|
|
20
21
|
end
|
|
21
22
|
end
|
|
22
23
|
|
|
23
24
|
def show
|
|
24
|
-
Fiber[:show_rec] ||= Set
|
|
25
|
+
Fiber[:show_rec] ||= Set.empty
|
|
25
26
|
if Fiber[:show_rec].include?(self)
|
|
26
27
|
"untyped"
|
|
27
28
|
else
|
|
@@ -101,7 +102,7 @@ module TypeProf::Core
|
|
|
101
102
|
end
|
|
102
103
|
|
|
103
104
|
def show
|
|
104
|
-
Fiber[:show_rec] ||= Set
|
|
105
|
+
Fiber[:show_rec] ||= Set.empty
|
|
105
106
|
if Fiber[:show_rec].include?(self)
|
|
106
107
|
"...(recursive)..."
|
|
107
108
|
else
|
|
@@ -135,29 +136,29 @@ module TypeProf::Core
|
|
|
135
136
|
else
|
|
136
137
|
raise "unknown class: #{ origin.class }"
|
|
137
138
|
end
|
|
138
|
-
@next_vtxs = Set
|
|
139
|
+
@next_vtxs = Set.empty
|
|
139
140
|
super({})
|
|
140
141
|
end
|
|
141
142
|
|
|
142
143
|
attr_reader :next_vtxs, :types
|
|
143
144
|
|
|
144
145
|
def on_type_added(genv, src_var, added_types)
|
|
145
|
-
new_added_types =
|
|
146
|
+
new_added_types = nil
|
|
146
147
|
added_types.each do |ty|
|
|
147
148
|
if @types[ty]
|
|
148
149
|
@types[ty] << src_var
|
|
149
150
|
else
|
|
150
|
-
set = Set
|
|
151
|
+
set = Set.empty
|
|
151
152
|
begin
|
|
152
153
|
@types[ty] = set
|
|
153
154
|
rescue
|
|
154
|
-
@types_to_be_added[ty] = set
|
|
155
|
+
(@types_to_be_added ||= {})[ty] = set
|
|
155
156
|
end
|
|
156
157
|
set << src_var
|
|
157
|
-
new_added_types << ty
|
|
158
|
+
(new_added_types ||= []) << ty
|
|
158
159
|
end
|
|
159
160
|
end
|
|
160
|
-
|
|
161
|
+
if new_added_types
|
|
161
162
|
@next_vtxs.each do |nvtx|
|
|
162
163
|
nvtx.on_type_added(genv, self, new_added_types)
|
|
163
164
|
end
|
|
@@ -165,16 +166,16 @@ module TypeProf::Core
|
|
|
165
166
|
end
|
|
166
167
|
|
|
167
168
|
def on_type_removed(genv, src_var, removed_types)
|
|
168
|
-
new_removed_types =
|
|
169
|
+
new_removed_types = nil
|
|
169
170
|
removed_types.each do |ty|
|
|
170
|
-
raise "!!! not implemented" if @types_to_be_added[ty
|
|
171
|
+
raise "!!! not implemented" if @types_to_be_added&.[](ty)
|
|
171
172
|
@types[ty].delete(src_var) || raise
|
|
172
173
|
if @types[ty].empty?
|
|
173
174
|
@types.delete(ty) || raise
|
|
174
|
-
new_removed_types << ty
|
|
175
|
+
(new_removed_types ||= []) << ty
|
|
175
176
|
end
|
|
176
177
|
end
|
|
177
|
-
|
|
178
|
+
if new_removed_types
|
|
178
179
|
@next_vtxs.each do |nvtx|
|
|
179
180
|
nvtx.on_type_removed(genv, self, new_removed_types)
|
|
180
181
|
end
|