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.
Files changed (73) 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 +180 -0
  7. data/lib/typeprof/cli.rb +2 -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 +251 -0
  11. data/lib/typeprof/core/ast/const.rb +126 -0
  12. data/lib/typeprof/core/ast/control.rb +432 -0
  13. data/lib/typeprof/core/ast/meta.rb +150 -0
  14. data/lib/typeprof/core/ast/method.rb +335 -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 +360 -0
  31. data/lib/typeprof/core/graph/box.rb +991 -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 +222 -0
  35. data/lib/typeprof/core/graph.rb +3 -0
  36. data/lib/typeprof/core/service.rb +522 -0
  37. data/lib/typeprof/core/type.rb +348 -0
  38. data/lib/typeprof/core/util.rb +81 -0
  39. data/lib/typeprof/core.rb +32 -0
  40. data/lib/typeprof/diagnostic.rb +35 -0
  41. data/lib/typeprof/lsp/messages.rb +430 -0
  42. data/lib/typeprof/lsp/server.rb +177 -0
  43. data/lib/typeprof/lsp/text.rb +69 -0
  44. data/lib/typeprof/lsp/util.rb +61 -0
  45. data/lib/typeprof/lsp.rb +4 -907
  46. data/lib/typeprof/version.rb +1 -1
  47. data/lib/typeprof.rb +4 -18
  48. data/typeprof.gemspec +5 -7
  49. metadata +48 -35
  50. data/.github/dependabot.yml +0 -6
  51. data/.github/workflows/main.yml +0 -39
  52. data/.gitignore +0 -9
  53. data/Gemfile +0 -17
  54. data/Gemfile.lock +0 -41
  55. data/Rakefile +0 -10
  56. data/exe/typeprof +0 -10
  57. data/lib/typeprof/analyzer.rb +0 -2598
  58. data/lib/typeprof/arguments.rb +0 -414
  59. data/lib/typeprof/block.rb +0 -176
  60. data/lib/typeprof/builtin.rb +0 -893
  61. data/lib/typeprof/code-range.rb +0 -177
  62. data/lib/typeprof/config.rb +0 -158
  63. data/lib/typeprof/container-type.rb +0 -912
  64. data/lib/typeprof/export.rb +0 -589
  65. data/lib/typeprof/import.rb +0 -852
  66. data/lib/typeprof/insns-def.rb +0 -65
  67. data/lib/typeprof/iseq.rb +0 -864
  68. data/lib/typeprof/method.rb +0 -355
  69. data/lib/typeprof/type.rb +0 -1140
  70. data/lib/typeprof/utils.rb +0 -212
  71. data/tools/coverage.rb +0 -14
  72. data/tools/setup-insns-def.rb +0 -30
  73. data/typeprof-lsp +0 -3
@@ -0,0 +1,126 @@
1
+ module TypeProf::Core
2
+ class AST
3
+ class ConstantReadNode < Node
4
+ def initialize(raw_node, lenv)
5
+ super(raw_node, lenv)
6
+ case raw_node.type
7
+ when :constant_read_node, :constant_operator_write_node, :constant_or_write_node, :constant_and_write_node
8
+ @cbase = nil
9
+ @toplevel = false
10
+ @cname = raw_node.name
11
+ @cname_code_range = TypeProf::CodeRange.from_node(raw_node.location)
12
+ when :constant_path_node, :constant_path_target_node
13
+ if raw_node.parent
14
+ @cbase = AST.create_node(raw_node.parent, lenv)
15
+ @toplevel = false
16
+ else
17
+ @cbase = nil
18
+ @toplevel = true
19
+ end
20
+ # temporarily support old Prism https://bugs.ruby-lang.org/issues/20467
21
+ if raw_node.respond_to?(:name)
22
+ @cname = raw_node.name
23
+ @cname_code_range = TypeProf::CodeRange.from_node(raw_node.name_loc)
24
+ else
25
+ @cname = raw_node.child.name
26
+ @cname_code_range = TypeProf::CodeRange.from_node(raw_node.child.location)
27
+ end
28
+ else
29
+ raise raw_node.type.to_s
30
+ end
31
+ end
32
+
33
+ attr_reader :cname, :cbase, :toplevel, :cname_code_range
34
+
35
+ def attrs = { cname:, toplevel: }
36
+ def subnodes = { cbase: }
37
+
38
+ def define0(genv)
39
+ if @cbase
40
+ ScopedConstRead.new(@cname, @cbase.define(genv))
41
+ else
42
+ BaseConstRead.new(genv, @cname, @toplevel ? CRef::Toplevel : @lenv.cref)
43
+ end
44
+ end
45
+
46
+ def undefine0(genv)
47
+ @static_ret.destroy(genv)
48
+ end
49
+
50
+ def install0(genv)
51
+ @cbase.install(genv) if @cbase
52
+ box = @changes.add_const_read_box(genv, @static_ret)
53
+ box.ret
54
+ end
55
+ end
56
+
57
+ class ConstantWriteNode < Node
58
+ def initialize(raw_node, rhs, lenv)
59
+ super(raw_node, lenv)
60
+ case raw_node.type
61
+ when :constant_write_node, :constant_target_node, :constant_operator_write_node, :constant_or_write_node, :constant_and_write_node
62
+ # C = expr
63
+ @cpath = nil
64
+ @static_cpath = lenv.cref.cpath + [raw_node.name]
65
+ @cname_code_range = TypeProf::CodeRange.from_node(raw_node.respond_to?(:name_loc) ? raw_node.name_loc : raw_node)
66
+ when :constant_path_write_node, :constant_path_operator_write_node, :constant_path_or_write_node, :constant_path_and_write_node
67
+ # expr::C = expr
68
+ @cpath = AST.create_node(raw_node.target, lenv)
69
+ @static_cpath = AST.parse_cpath(raw_node.target, lenv.cref)
70
+ @cname_code_range = TypeProf::CodeRange.from_node(raw_node.target)
71
+ when :constant_path_target_node
72
+ # expr::C, * = ary
73
+ @cpath = ConstantReadNode.new(raw_node, lenv)
74
+ @static_cpath = AST.parse_cpath(raw_node, lenv.cref)
75
+ @cname_code_range = TypeProf::CodeRange.from_node(raw_node)
76
+ else
77
+ raise
78
+ end
79
+ @rhs = rhs
80
+ end
81
+
82
+ attr_reader :cpath, :rhs, :static_cpath, :cname_code_range
83
+
84
+ def subnodes = { cpath:, rhs: }
85
+ def attrs = { static_cpath: }
86
+
87
+ def define0(genv)
88
+ @cpath.define(genv) if @cpath
89
+ @rhs.define(genv) if @rhs
90
+ if @static_cpath
91
+ mod = genv.resolve_const(@static_cpath)
92
+ mod.add_def(self)
93
+ mod
94
+ else
95
+ nil
96
+ end
97
+ end
98
+
99
+ def define_copy(genv)
100
+ if @static_cpath
101
+ mod = genv.resolve_const(@static_cpath)
102
+ mod.add_def(self)
103
+ mod.remove_def(@prev_node)
104
+ end
105
+ super(genv)
106
+ end
107
+
108
+ def undefine0(genv)
109
+ if @static_cpath
110
+ genv.resolve_const(@static_cpath).remove_def(self)
111
+ end
112
+ @rhs.undefine(genv) if @rhs
113
+ @cpath.undefine(genv) if @cpath
114
+ end
115
+
116
+ def install0(genv)
117
+ @cpath.install(genv) if @cpath
118
+ val = @rhs.install(genv)
119
+ if @static_cpath
120
+ @changes.add_edge(genv, val, @static_ret.vtx)
121
+ end
122
+ val
123
+ end
124
+ end
125
+ end
126
+ end
@@ -0,0 +1,432 @@
1
+ module TypeProf::Core
2
+ class AST
3
+ def self.is_a_class(node)
4
+ if node.is_a?(CallNode)
5
+ recv = node.recv
6
+ if recv.is_a?(LocalVariableReadNode)
7
+ if node.positional_args && node.positional_args.size == 1 && node.positional_args[0].static_ret
8
+ # TODO: need static resolusion of a constant
9
+ return [recv.var, node.positional_args[0].static_ret]
10
+ end
11
+ end
12
+ end
13
+ return nil
14
+ end
15
+
16
+ class BranchNode < Node
17
+ def initialize(raw_node, lenv)
18
+ super(raw_node, lenv)
19
+ @cond = AST.create_node(raw_node.predicate, lenv)
20
+ @then = raw_node.statements ? AST.create_node(raw_node.statements, lenv) : nil
21
+ else_clause = raw_node.is_a?(Prism::IfNode) ? raw_node.subsequent : raw_node.else_clause
22
+ if else_clause
23
+ else_clause = else_clause.statements if else_clause.type == :else_node
24
+ @else = else_clause ? AST.create_node(else_clause, lenv) : nil
25
+ else
26
+ @else = nil
27
+ end
28
+ end
29
+
30
+ attr_reader :cond, :then, :else
31
+
32
+ def subnodes = { cond:, then:, else: }
33
+
34
+ def install0(genv)
35
+ ret = Vertex.new(self)
36
+
37
+ @cond.install(genv)
38
+
39
+ vars = []
40
+ vars << @cond.var if @cond.is_a?(LocalVariableReadNode)
41
+ var, filter_class = AST.is_a_class(@cond)
42
+ vars << var if var
43
+ @then.modified_vars(@lenv.locals.keys, vars) if @then
44
+ @else.modified_vars(@lenv.locals.keys, vars) if @else
45
+ modified_vtxs = {}
46
+ vars.uniq.each do |var|
47
+ vtx = @lenv.get_var(var)
48
+ nvtx_then = vtx.new_vertex(genv, self)
49
+ nvtx_else = vtx.new_vertex(genv, self)
50
+ modified_vtxs[var] = [nvtx_then, nvtx_else]
51
+ end
52
+ if @cond.is_a?(LocalVariableReadNode)
53
+ nvtx_then, nvtx_else = modified_vtxs[@cond.var]
54
+ nvtx_then = NilFilter.new(genv, self, nvtx_then, !self.is_a?(IfNode)).next_vtx
55
+ nvtx_else = NilFilter.new(genv, self, nvtx_else, self.is_a?(IfNode)).next_vtx
56
+ modified_vtxs[@cond.var] = [nvtx_then, nvtx_else]
57
+ end
58
+ if filter_class
59
+ nvtx_then, nvtx_else = modified_vtxs[var]
60
+ nvtx_then = IsAFilter.new(genv, self, nvtx_then, !self.is_a?(IfNode), filter_class).next_vtx
61
+ nvtx_else = IsAFilter.new(genv, self, nvtx_else, self.is_a?(IfNode), filter_class).next_vtx
62
+ modified_vtxs[var] = [nvtx_then, nvtx_else]
63
+ end
64
+
65
+ if @then
66
+ modified_vtxs.each do |var, (nvtx_then, _)|
67
+ @lenv.set_var(var, nvtx_then)
68
+ end
69
+ if @cond.is_a?(InstanceVariableReadNode)
70
+ @lenv.push_read_filter(@cond.var, :non_nil)
71
+ end
72
+ then_val = @then.install(genv)
73
+ if @cond.is_a?(InstanceVariableReadNode)
74
+ @lenv.pop_read_filter(@cond.var)
75
+ end
76
+ modified_vtxs.each do |var, ary|
77
+ ary[0] = @lenv.get_var(var)
78
+ end
79
+ else
80
+ then_val = Source.new(genv.nil_type)
81
+ end
82
+ @changes.add_edge(genv, then_val, ret)
83
+
84
+ if @else
85
+ modified_vtxs.each do |var, (_, nvtx_else)|
86
+ @lenv.set_var(var, nvtx_else)
87
+ end
88
+ else_val = @else.install(genv)
89
+ modified_vtxs.each do |var, ary|
90
+ ary[1] = @lenv.get_var(var)
91
+ end
92
+ else
93
+ else_val = Source.new(genv.nil_type)
94
+ end
95
+ @changes.add_edge(genv, else_val, ret)
96
+
97
+ modified_vtxs.each do |var, (nvtx_then, nvtx_else)|
98
+ nvtx_then = BotFilter.new(genv, self, nvtx_then, then_val).next_vtx
99
+ nvtx_else = BotFilter.new(genv, self, nvtx_else, else_val).next_vtx
100
+ nvtx_join = nvtx_then.new_vertex(genv, self)
101
+ @changes.add_edge(genv, nvtx_else, nvtx_join)
102
+ @lenv.set_var(var, nvtx_join)
103
+ end
104
+
105
+ ret
106
+ end
107
+ end
108
+
109
+ class IfNode < BranchNode
110
+ end
111
+
112
+ class UnlessNode < BranchNode
113
+ end
114
+
115
+ class LoopNode < Node
116
+ def initialize(raw_node, lenv)
117
+ super(raw_node, lenv)
118
+ @cond = AST.create_node(raw_node.predicate, lenv)
119
+ @body = raw_node.statements ? AST.create_node(raw_node.statements, lenv) : DummyNilNode.new(code_range, lenv)
120
+ end
121
+
122
+ attr_reader :cond, :body
123
+
124
+ def subnodes = { cond:, body: }
125
+
126
+ def install0(genv)
127
+ vars = []
128
+ vars << @cond.var if @cond.is_a?(LocalVariableReadNode)
129
+ @cond.modified_vars(@lenv.locals.keys, vars)
130
+ @body.modified_vars(@lenv.locals.keys, vars)
131
+ vars.uniq!
132
+ old_vtxs = {}
133
+ vars.each do |var|
134
+ vtx = @lenv.get_var(var)
135
+ nvtx = vtx.new_vertex(genv, self)
136
+ old_vtxs[var] = nvtx
137
+ @lenv.set_var(var, nvtx)
138
+ end
139
+
140
+ @cond.install(genv)
141
+ if @cond.is_a?(LocalVariableReadNode)
142
+ nvtx_then = NilFilter.new(genv, self, old_vtxs[@cond.var], self.is_a?(UntilNode)).next_vtx
143
+ @lenv.set_var(@cond.var, nvtx_then)
144
+ end
145
+
146
+ if @lenv.exist_var?(:"*expected_block_ret")
147
+ expected_block_ret = @lenv.locals[:"*expected_block_ret"]
148
+ @lenv.set_var(:"*expected_block_ret", nil)
149
+ end
150
+
151
+ @body.install(genv)
152
+
153
+ if expected_block_ret
154
+ @lenv.set_var(:"*expected_block_ret", expected_block_ret)
155
+ end
156
+
157
+ vars.each do |var|
158
+ @changes.add_edge(genv, @lenv.get_var(var), old_vtxs[var])
159
+ @lenv.set_var(var, old_vtxs[var])
160
+ end
161
+ if @cond.is_a?(LocalVariableReadNode)
162
+ nvtx_then = NilFilter.new(genv, self, old_vtxs[@cond.var], !self.is_a?(UntilNode)).next_vtx
163
+ @lenv.set_var(@cond.var, nvtx_then)
164
+ end
165
+
166
+ Source.new(genv.nil_type)
167
+ end
168
+ end
169
+
170
+ class WhileNode < LoopNode
171
+ end
172
+
173
+ class UntilNode < LoopNode
174
+ end
175
+
176
+ class BreakNode < Node
177
+ def initialize(raw_node, lenv)
178
+ super(raw_node, lenv)
179
+ @arg = raw_node.arguments ? AST.create_node(raw_node.arguments.arguments.first, lenv) : nil
180
+ end
181
+
182
+ attr_reader :arg
183
+
184
+ def subnodes = { arg: }
185
+
186
+ def install0(genv)
187
+ _arg = @arg ? @arg.install(genv) : Source.new(genv.nil_type)
188
+ # TODO: implement!
189
+ end
190
+ end
191
+
192
+ def self.parse_return_arguments(raw_node, lenv, code_range)
193
+ if raw_node.arguments
194
+ elems = raw_node.arguments.arguments
195
+ if elems.one?
196
+ AST.create_node(elems.first, lenv)
197
+ else
198
+ ArrayNode.new(raw_node.arguments, lenv, elems)
199
+ end
200
+ else
201
+ DummyNilNode.new(code_range, lenv)
202
+ end
203
+ end
204
+
205
+ class NextNode < Node
206
+ def initialize(raw_node, lenv)
207
+ super(raw_node, lenv)
208
+ @arg = AST.parse_return_arguments(raw_node, lenv, code_range)
209
+ end
210
+
211
+ attr_reader :arg
212
+
213
+ def subnodes = { arg: }
214
+
215
+ def install0(genv)
216
+ @arg.install(genv)
217
+ if @lenv.exist_var?(:"*expected_block_ret")
218
+ @lenv.add_next_box(@changes.add_escape_box(genv, @arg.ret, @lenv.get_var(:"*expected_block_ret")))
219
+ end
220
+ Source.new(Type::Bot.new(genv))
221
+ end
222
+ end
223
+
224
+ class RedoNode < Node
225
+ def initialize(raw_node, lenv)
226
+ super(raw_node, lenv)
227
+ end
228
+
229
+ def install0(genv)
230
+ # TODO: This should return a bot type
231
+ Source.new()
232
+ end
233
+ end
234
+
235
+ class CaseNode < Node
236
+ def initialize(raw_node, lenv)
237
+ super(raw_node, lenv)
238
+ @pivot = raw_node.predicate ? AST.create_node(raw_node.predicate, lenv) : nil
239
+ @whens = []
240
+ @clauses = []
241
+ raw_node.conditions.each do |raw_cond|
242
+ @whens << AST.create_node(raw_cond.conditions.first, lenv) # XXX: multiple conditions
243
+ @clauses << (raw_cond.statements ? AST.create_node(raw_cond.statements, lenv) : DummyNilNode.new(code_range, lenv)) # TODO: code_range for NilNode
244
+ end
245
+ @else_clause = raw_node.else_clause && raw_node.else_clause.statements ? AST.create_node(raw_node.else_clause.statements, lenv) : DummyNilNode.new(code_range, lenv) # TODO: code_range for NilNode
246
+ end
247
+
248
+ attr_reader :pivot, :whens, :clauses, :else_clause
249
+
250
+ def subnodes = { pivot:, whens:, clauses:, else_clause: }
251
+
252
+ def install0(genv)
253
+ ret = Vertex.new(self)
254
+ @pivot&.install(genv)
255
+ @whens.zip(@clauses) do |vals, clause|
256
+ vals.install(genv)
257
+ @changes.add_edge(genv, clause.install(genv), ret)
258
+ end
259
+ @changes.add_edge(genv, @else_clause.install(genv), ret)
260
+ ret
261
+ end
262
+ end
263
+
264
+ class CaseMatchNode < Node
265
+ def initialize(raw_node, lenv)
266
+ super(raw_node, lenv)
267
+ @pivot = AST.create_node(raw_node.predicate, lenv)
268
+ @patterns = []
269
+ @clauses = []
270
+ raw_node.conditions.each do |raw_cond|
271
+ raise if raw_cond.type != :in_node
272
+ @patterns << AST.create_pattern_node(raw_cond.pattern, lenv)
273
+ @clauses << (raw_cond.statements ? AST.create_node(raw_cond.statements, lenv) : DummyNilNode.new(code_range, lenv)) # TODO: code_range for NilNode
274
+ end
275
+ @else_clause = raw_node.else_clause && raw_node.else_clause.statements ? AST.create_node(raw_node.else_clause.statements, lenv) : nil
276
+ end
277
+
278
+ attr_reader :pivot, :patterns, :clauses, :else_clause
279
+
280
+ def subnodes = { pivot:, patterns:, clauses:, else_clause: }
281
+
282
+ def install0(genv)
283
+ ret = Vertex.new(self)
284
+ @pivot&.install(genv)
285
+ @patterns.zip(@clauses) do |pattern, clause|
286
+ pattern.install(genv)
287
+ @changes.add_edge(genv, clause.install(genv), ret)
288
+ end
289
+ @changes.add_edge(genv, @else_clause.install(genv), ret) if @else_clause
290
+ ret
291
+ end
292
+ end
293
+
294
+ class AndNode < Node
295
+ def initialize(raw_node, e1 = nil, raw_e2 = nil, lenv)
296
+ super(raw_node, lenv)
297
+ @e1 = e1 || AST.create_node(raw_node.left, lenv)
298
+ @e2 = AST.create_node(raw_e2 || raw_node.right, lenv)
299
+ end
300
+
301
+ attr_reader :e1, :e2
302
+
303
+ def subnodes = { e1:, e2: }
304
+
305
+ def install0(genv)
306
+ ret = Vertex.new(self)
307
+ @changes.add_edge(genv, @e1.install(genv), ret)
308
+ @changes.add_edge(genv, @e2.install(genv), ret)
309
+ ret
310
+ end
311
+ end
312
+
313
+ class OrNode < Node
314
+ def initialize(raw_node, e1 = nil, raw_e2 = nil, lenv)
315
+ super(raw_node, lenv)
316
+ @e1 = e1 || AST.create_node(raw_node.left, lenv)
317
+ @e2 = AST.create_node(raw_e2 || raw_node.right, lenv)
318
+ end
319
+
320
+ attr_reader :e1, :e2
321
+
322
+ def subnodes = { e1:, e2: }
323
+
324
+ def install0(genv)
325
+ ret = Vertex.new(self)
326
+ v1 = @e1.install(genv)
327
+ v1 = NilFilter.new(genv, self, v1, false).next_vtx
328
+ @changes.add_edge(genv, v1, ret)
329
+ @changes.add_edge(genv, @e2.install(genv), ret)
330
+ ret
331
+ end
332
+ end
333
+
334
+ class ReturnNode < Node
335
+ def initialize(raw_node, lenv)
336
+ super(raw_node, lenv)
337
+ @arg = AST.parse_return_arguments(raw_node, lenv, code_range)
338
+ end
339
+
340
+ attr_reader :arg
341
+
342
+ def subnodes = { arg: }
343
+
344
+ def install0(genv)
345
+ @arg.install(genv)
346
+ e_ret = @lenv.locals[:"*expected_method_ret"]
347
+ @lenv.add_return_box(@changes.add_escape_box(genv, @arg.ret, e_ret)) if e_ret
348
+ Source.new(Type::Bot.new(genv))
349
+ end
350
+ end
351
+
352
+ class BeginNode < Node
353
+ def initialize(raw_node, lenv)
354
+ super(raw_node, lenv)
355
+ @body = raw_node.statements ? AST.create_node(raw_node.statements, lenv) : DummyNilNode.new(code_range, lenv)
356
+ @rescue_conds = []
357
+ @rescue_clauses = []
358
+ raw_res = raw_node.rescue_clause
359
+ while raw_res
360
+ raw_res.exceptions.each do |raw_cond|
361
+ @rescue_conds << AST.create_node(raw_cond, lenv)
362
+ end
363
+ if raw_res.statements
364
+ @rescue_clauses << AST.create_node(raw_res.statements, lenv)
365
+ end
366
+ raw_res = raw_res.subsequent
367
+ end
368
+ @else_clause = raw_node.else_clause ? AST.create_node(raw_node.else_clause.statements, lenv) : DummyNilNode.new(code_range, lenv)
369
+ @ensure_clause = raw_node.ensure_clause ? AST.create_node(raw_node.ensure_clause.statements, lenv) : DummyNilNode.new(code_range, lenv)
370
+ end
371
+
372
+ attr_reader :body, :rescue_conds, :rescue_clauses, :else_clause, :ensure_clause
373
+
374
+ def subnodes = { body:, rescue_conds:, rescue_clauses:, else_clause:, ensure_clause: }
375
+
376
+ def define0(genv)
377
+ @body.define(genv)
378
+ @rescue_conds.each {|cond| cond.define(genv) }
379
+ @rescue_clauses.each {|clause| clause.define(genv) }
380
+ @else_clause.define(genv) if @else_clause
381
+ @ensure_clause.define(genv) if @ensure_clause
382
+ end
383
+
384
+ def undefine0(genv)
385
+ @body.undefine(genv)
386
+ @rescue_conds.each {|cond| cond.undefine(genv) }
387
+ @rescue_clauses.each {|clause| clause.undefine(genv) }
388
+ @else_clause.undefine(genv) if @else_clause
389
+ @ensure_clause.undefine(genv) if @ensure_clause
390
+ end
391
+
392
+ def install0(genv)
393
+ ret = Vertex.new(self)
394
+ @changes.add_edge(genv, @body.install(genv), ret)
395
+ @rescue_conds.each {|cond| cond.install(genv) }
396
+ @rescue_clauses.each {|clause| @changes.add_edge(genv, clause.install(genv), ret) }
397
+ @changes.add_edge(genv, @else_clause.install(genv), ret) if @else_clause
398
+ @ensure_clause.install(genv) if @ensure_clause
399
+ ret
400
+ end
401
+ end
402
+
403
+ class RetryNode < Node
404
+ def initialize(raw_node, lenv)
405
+ super(raw_node, lenv)
406
+ end
407
+
408
+ def install0(genv)
409
+ Source.new(Type::Bot.new(genv))
410
+ end
411
+ end
412
+
413
+ class RescueModifierNode < Node
414
+ def initialize(raw_node, lenv)
415
+ super(raw_node, lenv)
416
+ @expression = AST.create_node(raw_node.expression, lenv)
417
+ @rescue_expression = AST.create_node(raw_node.rescue_expression, lenv)
418
+ end
419
+
420
+ attr_reader :expression, :rescue_expression
421
+
422
+ def subnodes = { expression:, rescue_expression: }
423
+
424
+ def install0(genv)
425
+ ret = Vertex.new(self)
426
+ @changes.add_edge(genv, @expression.install(genv), ret)
427
+ @changes.add_edge(genv, @rescue_expression.install(genv), ret)
428
+ ret
429
+ end
430
+ end
431
+ end
432
+ end
@@ -0,0 +1,150 @@
1
+ module TypeProf::Core
2
+ class AST
3
+ class IncludeMetaNode < Node
4
+ def initialize(raw_node, lenv)
5
+ super(raw_node, lenv)
6
+ # TODO: error for splat
7
+ @args = raw_node.arguments.arguments.map do |raw_arg|
8
+ next if raw_arg.is_a?(Prism::SplatNode)
9
+ AST.create_node(raw_arg, lenv)
10
+ end.compact
11
+ # TODO: error for non-LIT
12
+ # TODO: fine-grained hover
13
+ end
14
+
15
+ attr_reader :args
16
+
17
+ def subnodes = { args: }
18
+
19
+ def define0(genv)
20
+ mod = genv.resolve_cpath(@lenv.cref.cpath)
21
+ @args.each do |arg|
22
+ arg.define(genv)
23
+ if arg.static_ret
24
+ arg.static_ret.followers << mod
25
+ mod.add_include_def(genv, arg)
26
+ end
27
+ end
28
+ end
29
+
30
+ def undefine0(genv)
31
+ mod = genv.resolve_cpath(@lenv.cref.cpath)
32
+ @args.each do |arg|
33
+ if arg.static_ret
34
+ mod.remove_include_def(genv, arg)
35
+ end
36
+ arg.undefine(genv)
37
+ end
38
+ super(genv)
39
+ end
40
+
41
+ def install0(genv)
42
+ @args.each {|arg| arg.install(genv) }
43
+ Source.new
44
+ end
45
+ end
46
+
47
+ class AttrReaderMetaNode < Node
48
+ def initialize(raw_node, lenv)
49
+ super(raw_node, lenv)
50
+ @args = []
51
+ raw_node.arguments.arguments.each do |raw_arg|
52
+ @args << raw_arg.value.to_sym if raw_arg.type == :symbol_node
53
+ end
54
+ # TODO: error for non-LIT
55
+ # TODO: fine-grained hover
56
+ end
57
+
58
+ attr_reader :args
59
+
60
+ def attrs = { args: }
61
+
62
+ def req_positionals = []
63
+ def opt_positionals = []
64
+ def post_positionals = []
65
+ def rest_positionals = nil
66
+ def req_keywords = []
67
+ def opt_keywords = []
68
+ def rest_keywords = nil
69
+
70
+ def mname_code_range(name)
71
+ idx = @args.index(name.to_sym) # TODO: support string args
72
+ node = @raw_node.arguments.arguments[idx].location
73
+ TypeProf::CodeRange.from_node(node)
74
+ end
75
+
76
+ def install0(genv)
77
+ @args.each do |arg|
78
+ ivar_name = :"@#{ arg }"
79
+ ivar_box = @changes.add_ivar_read_box(genv, @lenv.cref.cpath, false, ivar_name)
80
+ e_ret = Vertex.new(self)
81
+ ret_box = @changes.add_escape_box(genv, ivar_box.ret, e_ret)
82
+ @changes.add_method_def_box(genv, @lenv.cref.cpath, false, arg, FormalArguments::Empty, [ret_box])
83
+ end
84
+ Source.new
85
+ end
86
+ end
87
+
88
+ class AttrAccessorMetaNode < Node
89
+ def initialize(raw_node, lenv)
90
+ super(raw_node, lenv)
91
+ @args = []
92
+ raw_node.arguments.arguments.each do |raw_arg|
93
+ @args << raw_arg.value.to_sym if raw_arg.type == :symbol_node
94
+ end
95
+ # TODO: error for non-LIT
96
+ # TODO: fine-grained hover
97
+ end
98
+
99
+ attr_reader :args
100
+
101
+ def attrs = { args: }
102
+
103
+ def mname_code_range(name)
104
+ idx = @args.index(name.to_sym) # TODO: support string args
105
+ node = @raw_node.arguments.arguments[idx].location
106
+ TypeProf::CodeRange.from_node(node)
107
+ end
108
+
109
+ def define0(genv)
110
+ @args.map do |arg|
111
+ mod = genv.resolve_ivar(lenv.cref.cpath, false, :"@#{ arg }")
112
+ mod.add_def(self)
113
+ mod
114
+ end
115
+ end
116
+
117
+ def define_copy(genv)
118
+ @args.map do |arg|
119
+ mod = genv.resolve_ivar(lenv.cref.cpath, false, :"@#{ arg }")
120
+ mod.add_def(self)
121
+ mod.remove_def(@prev_node)
122
+ mod
123
+ end
124
+ super(genv)
125
+ end
126
+
127
+ def undefine0(genv)
128
+ @args.each do |arg|
129
+ mod = genv.resolve_ivar(lenv.cref.cpath, false, :"@#{ arg }")
130
+ mod.remove_def(self)
131
+ end
132
+ end
133
+
134
+ def install0(genv)
135
+ @args.zip(@static_ret) do |arg, ive|
136
+ ivar_box = @changes.add_ivar_read_box(genv, @lenv.cref.cpath, false, :"@#{ arg }")
137
+ e_ret = Vertex.new(self)
138
+ ret_box = @changes.add_escape_box(genv, ivar_box.ret, e_ret)
139
+ @changes.add_method_def_box(genv, @lenv.cref.cpath, false, arg, FormalArguments::Empty, [ret_box])
140
+
141
+ vtx = Vertex.new(self)
142
+ @changes.add_edge(genv, vtx, ive.vtx)
143
+ f_args = FormalArguments.new([vtx], [], nil, [], [], [], nil, nil)
144
+ @changes.add_method_def_box(genv, @lenv.cref.cpath, false, :"#{ arg }=", f_args, [ret_box])
145
+ end
146
+ Source.new
147
+ end
148
+ end
149
+ end
150
+ end