typeprof 0.21.11 → 0.30.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 +15 -31
- data/bin/typeprof +5 -0
- data/doc/doc.ja.md +134 -0
- data/doc/doc.md +136 -0
- data/lib/typeprof/cli/cli.rb +180 -0
- data/lib/typeprof/cli.rb +2 -133
- data/lib/typeprof/code_range.rb +112 -0
- data/lib/typeprof/core/ast/base.rb +263 -0
- data/lib/typeprof/core/ast/call.rb +251 -0
- data/lib/typeprof/core/ast/const.rb +126 -0
- data/lib/typeprof/core/ast/control.rb +432 -0
- data/lib/typeprof/core/ast/meta.rb +150 -0
- data/lib/typeprof/core/ast/method.rb +335 -0
- data/lib/typeprof/core/ast/misc.rb +263 -0
- data/lib/typeprof/core/ast/module.rb +123 -0
- data/lib/typeprof/core/ast/pattern.rb +140 -0
- data/lib/typeprof/core/ast/sig_decl.rb +471 -0
- data/lib/typeprof/core/ast/sig_type.rb +663 -0
- data/lib/typeprof/core/ast/value.rb +319 -0
- data/lib/typeprof/core/ast/variable.rb +315 -0
- data/lib/typeprof/core/ast.rb +472 -0
- data/lib/typeprof/core/builtin.rb +146 -0
- data/lib/typeprof/core/env/method.rb +137 -0
- data/lib/typeprof/core/env/method_entity.rb +55 -0
- data/lib/typeprof/core/env/module_entity.rb +408 -0
- data/lib/typeprof/core/env/static_read.rb +155 -0
- data/lib/typeprof/core/env/type_alias_entity.rb +27 -0
- data/lib/typeprof/core/env/value_entity.rb +32 -0
- data/lib/typeprof/core/env.rb +360 -0
- data/lib/typeprof/core/graph/box.rb +991 -0
- data/lib/typeprof/core/graph/change_set.rb +224 -0
- data/lib/typeprof/core/graph/filter.rb +155 -0
- data/lib/typeprof/core/graph/vertex.rb +222 -0
- data/lib/typeprof/core/graph.rb +3 -0
- data/lib/typeprof/core/service.rb +522 -0
- data/lib/typeprof/core/type.rb +348 -0
- data/lib/typeprof/core/util.rb +81 -0
- data/lib/typeprof/core.rb +32 -0
- data/lib/typeprof/diagnostic.rb +35 -0
- data/lib/typeprof/lsp/messages.rb +430 -0
- data/lib/typeprof/lsp/server.rb +177 -0
- data/lib/typeprof/lsp/text.rb +69 -0
- data/lib/typeprof/lsp/util.rb +61 -0
- data/lib/typeprof/lsp.rb +4 -907
- data/lib/typeprof/version.rb +1 -1
- data/lib/typeprof.rb +4 -18
- data/typeprof.gemspec +5 -7
- metadata +48 -35
- data/.github/dependabot.yml +0 -6
- data/.github/workflows/main.yml +0 -39
- data/.gitignore +0 -9
- data/Gemfile +0 -17
- data/Gemfile.lock +0 -41
- data/Rakefile +0 -10
- data/exe/typeprof +0 -10
- data/lib/typeprof/analyzer.rb +0 -2598
- data/lib/typeprof/arguments.rb +0 -414
- data/lib/typeprof/block.rb +0 -176
- data/lib/typeprof/builtin.rb +0 -893
- data/lib/typeprof/code-range.rb +0 -177
- data/lib/typeprof/config.rb +0 -158
- data/lib/typeprof/container-type.rb +0 -912
- data/lib/typeprof/export.rb +0 -589
- data/lib/typeprof/import.rb +0 -852
- data/lib/typeprof/insns-def.rb +0 -65
- data/lib/typeprof/iseq.rb +0 -864
- data/lib/typeprof/method.rb +0 -355
- data/lib/typeprof/type.rb +0 -1140
- data/lib/typeprof/utils.rb +0 -212
- data/tools/coverage.rb +0 -14
- data/tools/setup-insns-def.rb +0 -30
- data/typeprof-lsp +0 -3
@@ -0,0 +1,224 @@
|
|
1
|
+
module TypeProf::Core
|
2
|
+
class ChangeSet
|
3
|
+
def initialize(node, target)
|
4
|
+
@node = node
|
5
|
+
@target = target
|
6
|
+
@covariant_types = {}
|
7
|
+
@contravariant_types = {}
|
8
|
+
@edges = []
|
9
|
+
@new_edges = []
|
10
|
+
@boxes = {}
|
11
|
+
@new_boxes = {}
|
12
|
+
@diagnostics = []
|
13
|
+
@new_diagnostics = []
|
14
|
+
@depended_value_entities = []
|
15
|
+
@new_depended_value_entities = []
|
16
|
+
@depended_method_entities = []
|
17
|
+
@new_depended_method_entities = []
|
18
|
+
@depended_static_reads = []
|
19
|
+
@new_depended_static_reads = []
|
20
|
+
@depended_superclasses = []
|
21
|
+
@new_depended_superclasses = []
|
22
|
+
end
|
23
|
+
|
24
|
+
attr_reader :node, :covariant_types, :edges, :boxes, :diagnostics
|
25
|
+
|
26
|
+
def reuse(new_node)
|
27
|
+
@node = new_node
|
28
|
+
@boxes.each_value do |box|
|
29
|
+
box.reuse(new_node)
|
30
|
+
end
|
31
|
+
@diagnostics.each do |diag|
|
32
|
+
diag.reuse(new_node)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def copy_from(other)
|
37
|
+
@covariant_types = other.covariant_types.dup
|
38
|
+
@edges = other.edges.dup
|
39
|
+
@boxes = other.boxes.dup
|
40
|
+
@diagnostics = other.diagnostics.dup
|
41
|
+
|
42
|
+
other.covariant_types.clear
|
43
|
+
other.edges.clear
|
44
|
+
other.boxes.clear
|
45
|
+
other.diagnostics.clear
|
46
|
+
end
|
47
|
+
|
48
|
+
def new_covariant_vertex(genv, sig_type_node)
|
49
|
+
# This is used to avoid duplicated vertex generation for the same sig node
|
50
|
+
@covariant_types[sig_type_node] ||= Vertex.new(sig_type_node)
|
51
|
+
end
|
52
|
+
|
53
|
+
def new_contravariant_vertex(genv, sig_type_node)
|
54
|
+
# This is used to avoid duplicated vertex generation for the same sig node
|
55
|
+
@contravariant_types[sig_type_node] ||= Vertex.new(sig_type_node)
|
56
|
+
end
|
57
|
+
|
58
|
+
def add_edge(genv, src, dst)
|
59
|
+
raise src.class.to_s unless src.is_a?(BasicVertex)
|
60
|
+
src.add_edge(genv, dst) if !@edges.include?([src, dst]) && !@new_edges.include?([src, dst])
|
61
|
+
@new_edges << [src, dst]
|
62
|
+
end
|
63
|
+
|
64
|
+
# TODO: if an edge is removed during one analysis, we may need to remove sub-boxes?
|
65
|
+
|
66
|
+
def add_method_call_box(genv, recv, mid, a_args, subclasses)
|
67
|
+
key = [:mcall, recv, mid, a_args, subclasses]
|
68
|
+
return if @new_boxes[key]
|
69
|
+
@new_boxes[key] = MethodCallBox.new(@node, genv, recv, mid, a_args, subclasses)
|
70
|
+
end
|
71
|
+
|
72
|
+
def add_escape_box(genv, a_ret, f_ret)
|
73
|
+
key = [:return, a_ret]
|
74
|
+
return if @new_boxes[key]
|
75
|
+
@new_boxes[key] = EscapeBox.new(@node, genv, a_ret, f_ret)
|
76
|
+
end
|
77
|
+
|
78
|
+
def add_splat_box(genv, arg)
|
79
|
+
key = [:splat, arg]
|
80
|
+
return if @new_boxes[key]
|
81
|
+
@new_boxes[key] = SplatBox.new(@node, genv, arg)
|
82
|
+
end
|
83
|
+
|
84
|
+
def add_hash_splat_box(genv, arg, unified_key, unified_val)
|
85
|
+
key = [:hash_splat, arg, unified_key, unified_val]
|
86
|
+
return if @new_boxes[key]
|
87
|
+
@new_boxes[key] = HashSplatBox.new(@node, genv, arg, unified_key, unified_val)
|
88
|
+
end
|
89
|
+
|
90
|
+
def add_masgn_box(genv, value, lefts, rest_elem, rights)
|
91
|
+
key = [:masgn, value, lefts, rest_elem, rights]
|
92
|
+
return if @new_boxes[key]
|
93
|
+
@new_boxes[key] = MAsgnBox.new(@node, genv, value, lefts, rest_elem, rights)
|
94
|
+
end
|
95
|
+
|
96
|
+
def add_method_def_box(genv, cpath, singleton, mid, f_args, ret_boxes)
|
97
|
+
key = [:mdef, cpath, singleton, mid, f_args, ret_boxes]
|
98
|
+
return if @new_boxes[key]
|
99
|
+
@new_boxes[key] = MethodDefBox.new(@node, genv, cpath, singleton, mid, f_args, ret_boxes)
|
100
|
+
end
|
101
|
+
|
102
|
+
def add_method_decl_box(genv, cpath, singleton, mid, method_types, overloading)
|
103
|
+
key = [:mdecl, cpath, singleton, mid, method_types, overloading]
|
104
|
+
return if @new_boxes[key]
|
105
|
+
@new_boxes[key] = MethodDeclBox.new(@node, genv, cpath, singleton, mid, method_types, overloading)
|
106
|
+
end
|
107
|
+
|
108
|
+
def add_method_alias_box(genv, cpath, singleton, new_mid, old_mid)
|
109
|
+
key = [:mdecl, cpath, singleton, new_mid, old_mid]
|
110
|
+
return if @new_boxes[key]
|
111
|
+
@new_boxes[key] = MethodAliasBox.new(@node, genv, cpath, singleton, new_mid, old_mid)
|
112
|
+
end
|
113
|
+
|
114
|
+
def add_const_read_box(genv, static_ret)
|
115
|
+
key = [:cread, static_ret]
|
116
|
+
return if @new_boxes[key]
|
117
|
+
@new_boxes[key] = ConstReadBox.new(@node, genv, static_ret)
|
118
|
+
end
|
119
|
+
|
120
|
+
def add_gvar_read_box(genv, var)
|
121
|
+
key = [:gvar_read, var]
|
122
|
+
return if @new_boxes[key]
|
123
|
+
@new_boxes[key] = GVarReadBox.new(@node, genv, var)
|
124
|
+
end
|
125
|
+
|
126
|
+
def add_ivar_read_box(genv, cpath, singleton, name)
|
127
|
+
key = [:ivar_read, cpath, singleton, name]
|
128
|
+
return if @new_boxes[key]
|
129
|
+
@new_boxes[key] = IVarReadBox.new(@node, genv, cpath, singleton, name)
|
130
|
+
end
|
131
|
+
|
132
|
+
def add_cvar_read_box(genv, cpath, name)
|
133
|
+
key = [:cvar_read, cpath, name]
|
134
|
+
return if @new_boxes[key]
|
135
|
+
@new_boxes[key] = CVarReadBox.new(@node, genv, cpath, name)
|
136
|
+
end
|
137
|
+
|
138
|
+
def add_type_read_box(genv, type)
|
139
|
+
key = [:type_read, type]
|
140
|
+
return if @new_boxes[key]
|
141
|
+
@new_boxes[key] = TypeReadBox.new(@node, genv, type)
|
142
|
+
end
|
143
|
+
|
144
|
+
def add_diagnostic(meth, msg)
|
145
|
+
@new_diagnostics << TypeProf::Diagnostic.new(@node, meth, msg)
|
146
|
+
end
|
147
|
+
|
148
|
+
def add_depended_value_entity(ve)
|
149
|
+
@new_depended_value_entities << ve
|
150
|
+
end
|
151
|
+
|
152
|
+
def add_depended_method_entity(me)
|
153
|
+
@new_depended_method_entities << me
|
154
|
+
end
|
155
|
+
|
156
|
+
def add_depended_static_read(static_read)
|
157
|
+
@new_depended_static_reads << static_read
|
158
|
+
end
|
159
|
+
|
160
|
+
def add_depended_superclass(mod)
|
161
|
+
@new_depended_superclasses << mod
|
162
|
+
end
|
163
|
+
|
164
|
+
def reinstall(genv)
|
165
|
+
@new_edges.uniq!
|
166
|
+
@edges.each do |src, dst|
|
167
|
+
src.remove_edge(genv, dst) unless @new_edges.include?([src, dst])
|
168
|
+
end
|
169
|
+
@edges, @new_edges = @new_edges, @edges
|
170
|
+
@new_edges.clear
|
171
|
+
|
172
|
+
@boxes.each do |key, box|
|
173
|
+
box.destroy(genv)
|
174
|
+
end
|
175
|
+
@boxes, @new_boxes = @new_boxes, @boxes
|
176
|
+
@new_boxes.clear
|
177
|
+
|
178
|
+
@diagnostics, @new_diagnostics = @new_diagnostics, @diagnostics
|
179
|
+
@new_diagnostics.clear
|
180
|
+
|
181
|
+
@depended_value_entities.each do |ve|
|
182
|
+
ve.read_boxes.delete(@target) || raise
|
183
|
+
end
|
184
|
+
@new_depended_value_entities.uniq!
|
185
|
+
@new_depended_value_entities.each do |ve|
|
186
|
+
ve.read_boxes << @target
|
187
|
+
end
|
188
|
+
@depended_value_entities, @new_depended_value_entities = @new_depended_value_entities, @depended_value_entities
|
189
|
+
@new_depended_value_entities.clear
|
190
|
+
|
191
|
+
@depended_method_entities.each do |me|
|
192
|
+
me.method_call_boxes.delete(@target) || raise
|
193
|
+
end
|
194
|
+
@new_depended_method_entities.uniq!
|
195
|
+
@new_depended_method_entities.each do |me|
|
196
|
+
me.method_call_boxes << @target
|
197
|
+
end
|
198
|
+
@depended_method_entities, @new_depended_method_entities = @new_depended_method_entities, @depended_method_entities
|
199
|
+
@new_depended_method_entities.clear
|
200
|
+
|
201
|
+
@depended_static_reads.each do |static_read|
|
202
|
+
static_read.followers.delete(@target)
|
203
|
+
end
|
204
|
+
@new_depended_static_reads.uniq!
|
205
|
+
@new_depended_static_reads.each do |static_read|
|
206
|
+
static_read.followers << @target
|
207
|
+
end
|
208
|
+
|
209
|
+
@depended_static_reads, @new_depended_static_reads = @new_depended_static_reads, @depended_static_reads
|
210
|
+
@new_depended_static_reads.clear
|
211
|
+
|
212
|
+
@depended_superclasses.each do |mod|
|
213
|
+
mod.subclass_checks.delete(@target)
|
214
|
+
end
|
215
|
+
@new_depended_superclasses.uniq!
|
216
|
+
@new_depended_superclasses.each do |mod|
|
217
|
+
mod.subclass_checks << @target
|
218
|
+
end
|
219
|
+
|
220
|
+
@depended_superclasses, @new_depended_superclasses = @new_depended_superclasses, @depended_superclasses
|
221
|
+
@new_depended_superclasses.clear
|
222
|
+
end
|
223
|
+
end
|
224
|
+
end
|
@@ -0,0 +1,155 @@
|
|
1
|
+
module TypeProf::Core
|
2
|
+
class Filter
|
3
|
+
def destroyed
|
4
|
+
false
|
5
|
+
end
|
6
|
+
end
|
7
|
+
|
8
|
+
class NilFilter < Filter
|
9
|
+
def initialize(genv, node, prev_vtx, allow_nil)
|
10
|
+
@node = node
|
11
|
+
@next_vtx = Vertex.new(node)
|
12
|
+
@allow_nil = allow_nil
|
13
|
+
prev_vtx.add_edge(genv, self)
|
14
|
+
end
|
15
|
+
|
16
|
+
attr_reader :next_vtx, :allow_nil
|
17
|
+
|
18
|
+
def filter(types, nil_type)
|
19
|
+
types.select {|ty| (ty == nil_type) == @allow_nil }
|
20
|
+
end
|
21
|
+
|
22
|
+
def on_type_added(genv, src_var, added_types)
|
23
|
+
types = filter(added_types, genv.nil_type)
|
24
|
+
@next_vtx.on_type_added(genv, self, types) unless types.empty?
|
25
|
+
end
|
26
|
+
|
27
|
+
def on_type_removed(genv, src_var, removed_types)
|
28
|
+
types = filter(removed_types, genv.nil_type)
|
29
|
+
@next_vtx.on_type_removed(genv, self, types) unless types.empty?
|
30
|
+
end
|
31
|
+
|
32
|
+
#@@new_id = 0
|
33
|
+
|
34
|
+
def to_s
|
35
|
+
"NF#{ @id ||= $new_id += 1 } -> #{ @next_vtx }"
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
class IsAFilter < Filter
|
40
|
+
def initialize(genv, node, prev_vtx, neg, const_read)
|
41
|
+
@node = node
|
42
|
+
@types = Set[]
|
43
|
+
@const_read = const_read
|
44
|
+
@const_read.followers << self
|
45
|
+
@next_vtx = Vertex.new(node)
|
46
|
+
prev_vtx.add_edge(genv, self)
|
47
|
+
@neg = neg
|
48
|
+
end
|
49
|
+
|
50
|
+
attr_reader :next_vtx
|
51
|
+
|
52
|
+
def on_type_added(genv, src_var, added_types)
|
53
|
+
added_types.each do |ty|
|
54
|
+
@types << ty
|
55
|
+
end
|
56
|
+
run(genv)
|
57
|
+
end
|
58
|
+
|
59
|
+
def on_type_removed(genv, src_var, removed_types)
|
60
|
+
removed_types.each do |ty|
|
61
|
+
@types.delete(ty) || raise
|
62
|
+
end
|
63
|
+
run(genv)
|
64
|
+
end
|
65
|
+
|
66
|
+
def run(genv)
|
67
|
+
if @const_read && @const_read.cpath
|
68
|
+
passed_types = []
|
69
|
+
@types.each do |ty|
|
70
|
+
base_ty = ty.base_type(genv)
|
71
|
+
subclass = false
|
72
|
+
genv.each_superclass(base_ty.mod, base_ty.is_a?(Type::Singleton)) do |mod, singleton|
|
73
|
+
if mod.cpath == @const_read.cpath
|
74
|
+
subclass = true
|
75
|
+
break
|
76
|
+
end
|
77
|
+
end
|
78
|
+
passed_types << ty if subclass != @neg
|
79
|
+
end
|
80
|
+
else
|
81
|
+
passed_types = @types.to_a
|
82
|
+
end
|
83
|
+
added_types = passed_types - @next_vtx.types.keys
|
84
|
+
removed_types = @next_vtx.types.keys - passed_types
|
85
|
+
@next_vtx.on_type_added(genv, self, added_types)
|
86
|
+
@next_vtx.on_type_removed(genv, self, removed_types)
|
87
|
+
end
|
88
|
+
|
89
|
+
#@@new_id = 0
|
90
|
+
|
91
|
+
def to_s
|
92
|
+
"NF#{ @id ||= $new_id += 1 } -> #{ @next_vtx }"
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
class BotFilter < Filter
|
97
|
+
def initialize(genv, node, prev_vtx, base_vtx)
|
98
|
+
@node = node
|
99
|
+
@types = {}
|
100
|
+
@prev_vtx = prev_vtx
|
101
|
+
@next_vtx = Vertex.new(node)
|
102
|
+
@base_vtx = base_vtx
|
103
|
+
base_vtx.add_edge(genv, self)
|
104
|
+
prev_vtx.add_edge(genv, self) if prev_vtx != base_vtx
|
105
|
+
end
|
106
|
+
|
107
|
+
attr_reader :types, :prev_vtx, :next_vtx, :base_vtx
|
108
|
+
|
109
|
+
def filter(types)
|
110
|
+
types.select {|ty| (ty == genv.nil_type) == @allow_nil }
|
111
|
+
end
|
112
|
+
|
113
|
+
def on_type_added(genv, src_var, added_types)
|
114
|
+
if src_var == @base_vtx
|
115
|
+
if @base_vtx.types.size == 1 && @base_vtx.types.include?(Type::Bot.new(genv))
|
116
|
+
@next_vtx.on_type_removed(genv, self, @types.keys & @next_vtx.types.keys) # XXX: smoke/control/bot2.rb
|
117
|
+
end
|
118
|
+
else
|
119
|
+
added_types.each do |ty|
|
120
|
+
@types[ty] = true
|
121
|
+
end
|
122
|
+
if @base_vtx.types.size == 1 && @base_vtx.types.include?(Type::Bot.new(genv))
|
123
|
+
# ignore
|
124
|
+
else
|
125
|
+
@next_vtx.on_type_added(genv, self, added_types - @next_vtx.types.keys) # XXX: smoke/control/bot4.rb
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
def on_type_removed(genv, src_var, removed_types)
|
131
|
+
if src_var == @base_vtx
|
132
|
+
if @base_vtx.types.size == 1 && @base_vtx.types.include?(Type::Bot.new(genv))
|
133
|
+
# ignore
|
134
|
+
else
|
135
|
+
@next_vtx.on_type_added(genv, self, @types.keys - @next_vtx.types.keys) # XXX: smoke/control/bot4.rb
|
136
|
+
end
|
137
|
+
else
|
138
|
+
removed_types.each do |ty|
|
139
|
+
@types.delete(ty) || raise
|
140
|
+
end
|
141
|
+
if @base_vtx.types.size == 1 && @base_vtx.types.include?(Type::Bot.new(genv))
|
142
|
+
# ignore
|
143
|
+
else
|
144
|
+
@next_vtx.on_type_removed(genv, self, removed_types & @next_vtx.types.keys) # XXX: smoke/control/bot2.rb
|
145
|
+
end
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
#@@new_id = 0
|
150
|
+
|
151
|
+
def to_s
|
152
|
+
"BF#{ @id ||= $new_id += 1 } -> #{ @next_vtx }"
|
153
|
+
end
|
154
|
+
end
|
155
|
+
end
|
@@ -0,0 +1,222 @@
|
|
1
|
+
module TypeProf::Core
|
2
|
+
class BasicVertex
|
3
|
+
def initialize(types)
|
4
|
+
@types = types
|
5
|
+
@types_to_be_added = {}
|
6
|
+
end
|
7
|
+
|
8
|
+
attr_reader :types
|
9
|
+
|
10
|
+
def each_type(&blk)
|
11
|
+
@types.each_key(&blk)
|
12
|
+
|
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)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def check_match(genv, changes, vtx)
|
24
|
+
vtx.each_type do |ty|
|
25
|
+
if ty.is_a?(Type::Var)
|
26
|
+
changes.add_edge(genv, self, ty.vtx) if self != ty.vtx
|
27
|
+
return true
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
return true if @types.empty?
|
32
|
+
return true if vtx.types.empty?
|
33
|
+
|
34
|
+
each_type do |ty|
|
35
|
+
return true if vtx.types.include?(ty) # fast path
|
36
|
+
if ty.check_match(genv, changes, vtx)
|
37
|
+
return true
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
return false
|
42
|
+
end
|
43
|
+
|
44
|
+
def show
|
45
|
+
if Fiber[:show_rec].include?(self)
|
46
|
+
"untyped"
|
47
|
+
else
|
48
|
+
begin
|
49
|
+
Fiber[:show_rec] << self
|
50
|
+
types = []
|
51
|
+
bot = @types.keys.any? {|ty| ty.is_a?(Type::Bot) }
|
52
|
+
optional = true_exist = false_exist = false
|
53
|
+
each_type do |ty|
|
54
|
+
if ty.is_a?(Type::Instance)
|
55
|
+
case ty.mod.cpath
|
56
|
+
when [:NilClass] then optional = true
|
57
|
+
when [:TrueClass] then true_exist = true
|
58
|
+
when [:FalseClass] then false_exist = true
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
bool = true_exist && false_exist
|
63
|
+
types << "bool" if bool
|
64
|
+
each_type do |ty, _source|
|
65
|
+
if ty.is_a?(Type::Instance)
|
66
|
+
next if ty.mod.cpath == [:NilClass]
|
67
|
+
next if bool && (ty.mod.cpath == [:TrueClass] || ty.mod.cpath == [:FalseClass])
|
68
|
+
end
|
69
|
+
next if ty.is_a?(Type::Bot)
|
70
|
+
types << ty.show
|
71
|
+
end
|
72
|
+
types = types.uniq.sort
|
73
|
+
case types.size
|
74
|
+
when 0
|
75
|
+
optional ? "nil" : bot ? "bot" : "untyped"
|
76
|
+
when 1
|
77
|
+
types.first + (optional ? "?" : "")
|
78
|
+
else
|
79
|
+
"(#{ types.join(" | ") })" + (optional ? "?" : "")
|
80
|
+
end
|
81
|
+
ensure
|
82
|
+
Fiber[:show_rec].delete(self) || raise
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
class Source < BasicVertex
|
89
|
+
def initialize(*tys)
|
90
|
+
types = {}
|
91
|
+
tys.each do |ty|
|
92
|
+
raise ty.inspect unless ty.is_a?(Type)
|
93
|
+
types[ty] = true
|
94
|
+
end
|
95
|
+
super(types)
|
96
|
+
end
|
97
|
+
|
98
|
+
def on_type_added(genv, src_var, added_types)
|
99
|
+
# TODO: need to report error?
|
100
|
+
end
|
101
|
+
|
102
|
+
def on_type_removed(genv, src_var, removed_types)
|
103
|
+
end
|
104
|
+
|
105
|
+
def new_vertex(genv, origin)
|
106
|
+
nvtx = Vertex.new(origin)
|
107
|
+
add_edge(genv, nvtx)
|
108
|
+
nvtx
|
109
|
+
end
|
110
|
+
|
111
|
+
def add_edge(genv, nvtx)
|
112
|
+
nvtx.on_type_added(genv, self, @types.keys)
|
113
|
+
end
|
114
|
+
|
115
|
+
def remove_edge(genv, nvtx)
|
116
|
+
nvtx.on_type_removed(genv, self, @types.keys)
|
117
|
+
end
|
118
|
+
|
119
|
+
def show
|
120
|
+
if Fiber[:show_rec].include?(self)
|
121
|
+
"...(recursive)..."
|
122
|
+
else
|
123
|
+
begin
|
124
|
+
Fiber[:show_rec] << self
|
125
|
+
@types.empty? ? "untyped" : @types.keys.map {|ty| ty.show }.sort.join(" | ")
|
126
|
+
ensure
|
127
|
+
Fiber[:show_rec].delete(self) || raise
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
def to_s
|
133
|
+
"<src:#{ show }>"
|
134
|
+
end
|
135
|
+
|
136
|
+
alias inspect to_s
|
137
|
+
end
|
138
|
+
|
139
|
+
class Vertex < BasicVertex
|
140
|
+
def initialize(origin)
|
141
|
+
# Note that origin is just for debug.
|
142
|
+
# When an AST node is reused, the value of the origin will be invalid.
|
143
|
+
case origin
|
144
|
+
when AST::Node
|
145
|
+
when RBS::AST::Declarations::Base
|
146
|
+
when ValueEntity
|
147
|
+
when ActualArguments
|
148
|
+
when Array
|
149
|
+
else
|
150
|
+
raise "unknown class: #{ origin.class }"
|
151
|
+
end
|
152
|
+
@next_vtxs = Set[]
|
153
|
+
super({})
|
154
|
+
end
|
155
|
+
|
156
|
+
attr_reader :next_vtxs, :types
|
157
|
+
|
158
|
+
def on_type_added(genv, src_var, added_types)
|
159
|
+
new_added_types = []
|
160
|
+
added_types.each do |ty|
|
161
|
+
if @types[ty]
|
162
|
+
@types[ty] << src_var
|
163
|
+
else
|
164
|
+
set = Set[]
|
165
|
+
begin
|
166
|
+
@types[ty] = set
|
167
|
+
rescue
|
168
|
+
@types_to_be_added[ty] = set
|
169
|
+
end
|
170
|
+
set << src_var
|
171
|
+
new_added_types << ty
|
172
|
+
end
|
173
|
+
end
|
174
|
+
unless new_added_types.empty?
|
175
|
+
@next_vtxs.each do |nvtx|
|
176
|
+
nvtx.on_type_added(genv, self, new_added_types)
|
177
|
+
end
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
181
|
+
def on_type_removed(genv, src_var, removed_types)
|
182
|
+
new_removed_types = []
|
183
|
+
removed_types.each do |ty|
|
184
|
+
raise "!!! not implemented" if @types_to_be_added[ty]
|
185
|
+
@types[ty].delete(src_var) || raise
|
186
|
+
if @types[ty].empty?
|
187
|
+
@types.delete(ty) || raise
|
188
|
+
new_removed_types << ty
|
189
|
+
end
|
190
|
+
end
|
191
|
+
unless new_removed_types.empty?
|
192
|
+
@next_vtxs.each do |nvtx|
|
193
|
+
nvtx.on_type_removed(genv, self, new_removed_types)
|
194
|
+
end
|
195
|
+
end
|
196
|
+
end
|
197
|
+
|
198
|
+
def new_vertex(genv, origin)
|
199
|
+
nvtx = Vertex.new(origin)
|
200
|
+
add_edge(genv, nvtx)
|
201
|
+
nvtx
|
202
|
+
end
|
203
|
+
|
204
|
+
def add_edge(genv, nvtx)
|
205
|
+
@next_vtxs << nvtx
|
206
|
+
nvtx.on_type_added(genv, self, @types.keys) unless @types.empty?
|
207
|
+
end
|
208
|
+
|
209
|
+
def remove_edge(genv, nvtx)
|
210
|
+
@next_vtxs.delete(nvtx) || raise
|
211
|
+
nvtx.on_type_removed(genv, self, @types.keys) unless @types.empty?
|
212
|
+
end
|
213
|
+
|
214
|
+
$new_id = 0 # TODO: Use class variable
|
215
|
+
|
216
|
+
def to_s
|
217
|
+
"v#{ @id ||= $new_id += 1 }"
|
218
|
+
end
|
219
|
+
|
220
|
+
alias inspect to_s
|
221
|
+
end
|
222
|
+
end
|