typeprof 0.21.11 → 0.30.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.
Files changed (72) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +15 -31
  3. data/bin/typeprof +5 -0
  4. data/doc/doc.ja.md +134 -0
  5. data/doc/doc.md +136 -0
  6. data/lib/typeprof/cli/cli.rb +178 -0
  7. data/lib/typeprof/cli.rb +3 -133
  8. data/lib/typeprof/code_range.rb +112 -0
  9. data/lib/typeprof/core/ast/base.rb +263 -0
  10. data/lib/typeprof/core/ast/call.rb +259 -0
  11. data/lib/typeprof/core/ast/const.rb +126 -0
  12. data/lib/typeprof/core/ast/control.rb +433 -0
  13. data/lib/typeprof/core/ast/meta.rb +150 -0
  14. data/lib/typeprof/core/ast/method.rb +339 -0
  15. data/lib/typeprof/core/ast/misc.rb +263 -0
  16. data/lib/typeprof/core/ast/module.rb +123 -0
  17. data/lib/typeprof/core/ast/pattern.rb +140 -0
  18. data/lib/typeprof/core/ast/sig_decl.rb +471 -0
  19. data/lib/typeprof/core/ast/sig_type.rb +663 -0
  20. data/lib/typeprof/core/ast/value.rb +319 -0
  21. data/lib/typeprof/core/ast/variable.rb +315 -0
  22. data/lib/typeprof/core/ast.rb +472 -0
  23. data/lib/typeprof/core/builtin.rb +146 -0
  24. data/lib/typeprof/core/env/method.rb +137 -0
  25. data/lib/typeprof/core/env/method_entity.rb +55 -0
  26. data/lib/typeprof/core/env/module_entity.rb +408 -0
  27. data/lib/typeprof/core/env/static_read.rb +155 -0
  28. data/lib/typeprof/core/env/type_alias_entity.rb +27 -0
  29. data/lib/typeprof/core/env/value_entity.rb +32 -0
  30. data/lib/typeprof/core/env.rb +366 -0
  31. data/lib/typeprof/core/graph/box.rb +998 -0
  32. data/lib/typeprof/core/graph/change_set.rb +224 -0
  33. data/lib/typeprof/core/graph/filter.rb +155 -0
  34. data/lib/typeprof/core/graph/vertex.rb +225 -0
  35. data/lib/typeprof/core/service.rb +514 -0
  36. data/lib/typeprof/core/type.rb +352 -0
  37. data/lib/typeprof/core/util.rb +81 -0
  38. data/lib/typeprof/core.rb +31 -0
  39. data/lib/typeprof/diagnostic.rb +35 -0
  40. data/lib/typeprof/lsp/messages.rb +415 -0
  41. data/lib/typeprof/lsp/server.rb +203 -0
  42. data/lib/typeprof/lsp/text.rb +69 -0
  43. data/lib/typeprof/lsp/util.rb +51 -0
  44. data/lib/typeprof/lsp.rb +4 -907
  45. data/lib/typeprof/version.rb +1 -1
  46. data/lib/typeprof.rb +4 -18
  47. data/typeprof.gemspec +5 -7
  48. metadata +47 -33
  49. data/.github/dependabot.yml +0 -6
  50. data/.github/workflows/main.yml +0 -39
  51. data/.gitignore +0 -9
  52. data/Gemfile +0 -17
  53. data/Gemfile.lock +0 -41
  54. data/Rakefile +0 -10
  55. data/exe/typeprof +0 -10
  56. data/lib/typeprof/analyzer.rb +0 -2598
  57. data/lib/typeprof/arguments.rb +0 -414
  58. data/lib/typeprof/block.rb +0 -176
  59. data/lib/typeprof/builtin.rb +0 -893
  60. data/lib/typeprof/code-range.rb +0 -177
  61. data/lib/typeprof/config.rb +0 -158
  62. data/lib/typeprof/container-type.rb +0 -912
  63. data/lib/typeprof/export.rb +0 -589
  64. data/lib/typeprof/import.rb +0 -852
  65. data/lib/typeprof/insns-def.rb +0 -65
  66. data/lib/typeprof/iseq.rb +0 -864
  67. data/lib/typeprof/method.rb +0 -355
  68. data/lib/typeprof/type.rb +0 -1140
  69. data/lib/typeprof/utils.rb +0 -212
  70. data/tools/coverage.rb +0 -14
  71. data/tools/setup-insns-def.rb +0 -30
  72. 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,225 @@
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
+ Fiber[:show_rec] ||= Set[]
46
+ if Fiber[:show_rec].include?(self)
47
+ "untyped"
48
+ else
49
+ begin
50
+ Fiber[:show_rec] << self
51
+ types = []
52
+ bot = @types.keys.any? {|ty| ty.is_a?(Type::Bot) }
53
+ optional = true_exist = false_exist = false
54
+ each_type do |ty|
55
+ if ty.is_a?(Type::Instance)
56
+ case ty.mod.cpath
57
+ when [:NilClass] then optional = true
58
+ when [:TrueClass] then true_exist = true
59
+ when [:FalseClass] then false_exist = true
60
+ end
61
+ end
62
+ end
63
+ bool = true_exist && false_exist
64
+ types << "bool" if bool
65
+ each_type do |ty, _source|
66
+ if ty.is_a?(Type::Instance)
67
+ next if ty.mod.cpath == [:NilClass]
68
+ next if bool && (ty.mod.cpath == [:TrueClass] || ty.mod.cpath == [:FalseClass])
69
+ end
70
+ next if ty.is_a?(Type::Bot)
71
+ types << ty.show
72
+ end
73
+ types = types.uniq.sort
74
+ case types.size
75
+ when 0
76
+ optional ? "nil" : bot ? "bot" : "untyped"
77
+ when 1
78
+ types.first + (optional ? "?" : "")
79
+ else
80
+ "(#{ types.join(" | ") })" + (optional ? "?" : "")
81
+ end
82
+ ensure
83
+ Fiber[:show_rec].delete(self) || raise
84
+ end
85
+ end
86
+ end
87
+ end
88
+
89
+ class Source < BasicVertex
90
+ def initialize(*tys)
91
+ types = {}
92
+ tys.each do |ty|
93
+ raise ty.inspect unless ty.is_a?(Type)
94
+ types[ty] = true
95
+ end
96
+ super(types)
97
+ end
98
+
99
+ def on_type_added(genv, src_var, added_types)
100
+ # TODO: need to report error?
101
+ end
102
+
103
+ def on_type_removed(genv, src_var, removed_types)
104
+ end
105
+
106
+ def new_vertex(genv, origin)
107
+ nvtx = Vertex.new(origin)
108
+ add_edge(genv, nvtx)
109
+ nvtx
110
+ end
111
+
112
+ def add_edge(genv, nvtx)
113
+ nvtx.on_type_added(genv, self, @types.keys)
114
+ end
115
+
116
+ def remove_edge(genv, nvtx)
117
+ nvtx.on_type_removed(genv, self, @types.keys)
118
+ end
119
+
120
+ def show
121
+ Fiber[:show_rec] ||= Set[]
122
+ if Fiber[:show_rec].include?(self)
123
+ "...(recursive)..."
124
+ else
125
+ begin
126
+ Fiber[:show_rec] << self
127
+ @types.empty? ? "untyped" : @types.keys.map {|ty| ty.show }.sort.join(" | ")
128
+ ensure
129
+ Fiber[:show_rec].delete(self) || raise
130
+ end
131
+ end
132
+ end
133
+
134
+ def to_s
135
+ "<src:#{ show }>"
136
+ end
137
+
138
+ alias inspect to_s
139
+ end
140
+
141
+ class Vertex < BasicVertex
142
+ def initialize(origin)
143
+ # Note that origin is just for debug.
144
+ # When an AST node is reused, the value of the origin will be invalid.
145
+ case origin
146
+ when AST::Node
147
+ when RBS::AST::Declarations::Base
148
+ when ValueEntity
149
+ when ActualArguments
150
+ when Array
151
+ when Symbol
152
+ else
153
+ raise "unknown class: #{ origin.class }"
154
+ end
155
+ @next_vtxs = Set[]
156
+ super({})
157
+ end
158
+
159
+ attr_reader :next_vtxs, :types
160
+
161
+ def on_type_added(genv, src_var, added_types)
162
+ new_added_types = []
163
+ added_types.each do |ty|
164
+ if @types[ty]
165
+ @types[ty] << src_var
166
+ else
167
+ set = Set[]
168
+ begin
169
+ @types[ty] = set
170
+ rescue
171
+ @types_to_be_added[ty] = set
172
+ end
173
+ set << src_var
174
+ new_added_types << ty
175
+ end
176
+ end
177
+ unless new_added_types.empty?
178
+ @next_vtxs.each do |nvtx|
179
+ nvtx.on_type_added(genv, self, new_added_types)
180
+ end
181
+ end
182
+ end
183
+
184
+ def on_type_removed(genv, src_var, removed_types)
185
+ new_removed_types = []
186
+ removed_types.each do |ty|
187
+ raise "!!! not implemented" if @types_to_be_added[ty]
188
+ @types[ty].delete(src_var) || raise
189
+ if @types[ty].empty?
190
+ @types.delete(ty) || raise
191
+ new_removed_types << ty
192
+ end
193
+ end
194
+ unless new_removed_types.empty?
195
+ @next_vtxs.each do |nvtx|
196
+ nvtx.on_type_removed(genv, self, new_removed_types)
197
+ end
198
+ end
199
+ end
200
+
201
+ def new_vertex(genv, origin)
202
+ nvtx = Vertex.new(origin)
203
+ add_edge(genv, nvtx)
204
+ nvtx
205
+ end
206
+
207
+ def add_edge(genv, nvtx)
208
+ @next_vtxs << nvtx
209
+ nvtx.on_type_added(genv, self, @types.keys) unless @types.empty?
210
+ end
211
+
212
+ def remove_edge(genv, nvtx)
213
+ @next_vtxs.delete(nvtx) || raise
214
+ nvtx.on_type_removed(genv, self, @types.keys) unless @types.empty?
215
+ end
216
+
217
+ $new_id = 0 # TODO: Use class variable
218
+
219
+ def to_s
220
+ "v#{ @id ||= $new_id += 1 }"
221
+ end
222
+
223
+ alias inspect to_s
224
+ end
225
+ end