typeprof 0.30.1 → 0.31.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 +23 -4
- data/lib/typeprof/cli/cli.rb +27 -7
- data/lib/typeprof/code_range.rb +9 -7
- data/lib/typeprof/core/ast/base.rb +27 -10
- data/lib/typeprof/core/ast/call.rb +85 -24
- data/lib/typeprof/core/ast/const.rb +7 -12
- data/lib/typeprof/core/ast/control.rb +345 -71
- data/lib/typeprof/core/ast/meta.rb +5 -5
- data/lib/typeprof/core/ast/method.rb +15 -5
- data/lib/typeprof/core/ast/misc.rb +21 -2
- data/lib/typeprof/core/ast/module.rb +10 -7
- data/lib/typeprof/core/ast/pattern.rb +9 -1
- data/lib/typeprof/core/ast/sig_decl.rb +163 -42
- data/lib/typeprof/core/ast/sig_type.rb +394 -24
- data/lib/typeprof/core/ast/value.rb +10 -2
- data/lib/typeprof/core/ast/variable.rb +32 -2
- data/lib/typeprof/core/ast.rb +15 -4
- data/lib/typeprof/core/builtin.rb +15 -9
- data/lib/typeprof/core/env/method.rb +21 -16
- data/lib/typeprof/core/env/method_entity.rb +11 -2
- data/lib/typeprof/core/env/module_entity.rb +57 -0
- data/lib/typeprof/core/env/narrowing.rb +131 -0
- data/lib/typeprof/core/env/static_read.rb +9 -8
- data/lib/typeprof/core/env.rb +37 -12
- data/lib/typeprof/core/graph/box.rb +207 -97
- data/lib/typeprof/core/graph/change_set.rb +44 -37
- data/lib/typeprof/core/graph/vertex.rb +4 -21
- data/lib/typeprof/core/service.rb +30 -1
- data/lib/typeprof/core/type.rb +48 -123
- data/lib/typeprof/core.rb +1 -0
- data/lib/typeprof/diagnostic.rb +5 -6
- data/lib/typeprof/lsp/messages.rb +21 -15
- data/lib/typeprof/lsp/server.rb +132 -39
- data/lib/typeprof/lsp/text.rb +1 -0
- data/lib/typeprof/version.rb +1 -1
- data/typeprof.conf.jsonc +22 -0
- data/typeprof.gemspec +1 -0
- metadata +19 -6
|
@@ -13,6 +13,42 @@ module TypeProf::Core
|
|
|
13
13
|
return nil
|
|
14
14
|
end
|
|
15
15
|
|
|
16
|
+
# Apply multiple narrowings from the new narrowing system
|
|
17
|
+
def self.with_narrowing(genv, node, lenv, narrowing)
|
|
18
|
+
return yield if narrowing.map.empty?
|
|
19
|
+
|
|
20
|
+
# Store original vertices (only for local variables)
|
|
21
|
+
original_vtxs = {}
|
|
22
|
+
narrowing.map.each do |var, narrowing|
|
|
23
|
+
original_vtxs[var] = var.start_with?("@") ? nil : lenv.get_var(var)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# Apply all narrowings
|
|
27
|
+
narrowing.map.each do |var, narrowing|
|
|
28
|
+
if var.start_with?("@")
|
|
29
|
+
lenv.push_ivar_narrowing(var, narrowing)
|
|
30
|
+
else
|
|
31
|
+
original_vtx = original_vtxs[var]
|
|
32
|
+
narrowed_vtx = original_vtx.new_vertex(genv, node)
|
|
33
|
+
narrowed_vtx = narrowing.narrow(genv, node, narrowed_vtx)
|
|
34
|
+
lenv.set_var(var, narrowed_vtx)
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
result = yield
|
|
39
|
+
|
|
40
|
+
# Restore original vertices and remove instance variable filters
|
|
41
|
+
original_vtxs.each do |var, original_vtx|
|
|
42
|
+
if var.start_with?("@")
|
|
43
|
+
lenv.pop_ivar_narrowing(var)
|
|
44
|
+
else
|
|
45
|
+
lenv.set_var(var, original_vtx)
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
result
|
|
50
|
+
end
|
|
51
|
+
|
|
16
52
|
class BranchNode < Node
|
|
17
53
|
def initialize(raw_node, lenv)
|
|
18
54
|
super(raw_node, lenv)
|
|
@@ -37,11 +73,11 @@ module TypeProf::Core
|
|
|
37
73
|
@cond.install(genv)
|
|
38
74
|
|
|
39
75
|
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
76
|
@then.modified_vars(@lenv.locals.keys, vars) if @then
|
|
44
77
|
@else.modified_vars(@lenv.locals.keys, vars) if @else
|
|
78
|
+
then_narrowing, else_narrowing = @cond.narrowings
|
|
79
|
+
vars.concat(then_narrowing.map.keys.reject {|var| var.start_with?("@") })
|
|
80
|
+
vars.concat(else_narrowing.map.keys.reject {|var| var.start_with?("@") })
|
|
45
81
|
modified_vtxs = {}
|
|
46
82
|
vars.uniq.each do |var|
|
|
47
83
|
vtx = @lenv.get_var(var)
|
|
@@ -49,48 +85,30 @@ module TypeProf::Core
|
|
|
49
85
|
nvtx_else = vtx.new_vertex(genv, self)
|
|
50
86
|
modified_vtxs[var] = [nvtx_then, nvtx_else]
|
|
51
87
|
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
88
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
end
|
|
72
|
-
then_val = @then.install(genv)
|
|
73
|
-
if @cond.is_a?(InstanceVariableReadNode)
|
|
74
|
-
@lenv.pop_read_filter(@cond.var)
|
|
75
|
-
end
|
|
89
|
+
narrowing = self.is_a?(IfNode) ? then_narrowing : else_narrowing
|
|
90
|
+
modified_vtxs.each do |var, (nvtx_then, _)|
|
|
91
|
+
@lenv.set_var(var, nvtx_then)
|
|
92
|
+
end
|
|
93
|
+
then_val = AST.with_narrowing(genv, self, @lenv, narrowing) do
|
|
94
|
+
val = @then ? @then.install(genv) : Source.new(genv.nil_type)
|
|
76
95
|
modified_vtxs.each do |var, ary|
|
|
77
96
|
ary[0] = @lenv.get_var(var)
|
|
78
97
|
end
|
|
79
|
-
|
|
80
|
-
then_val = Source.new(genv.nil_type)
|
|
98
|
+
val
|
|
81
99
|
end
|
|
82
100
|
@changes.add_edge(genv, then_val, ret)
|
|
83
101
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
102
|
+
narrowing = self.is_a?(IfNode) ? else_narrowing : then_narrowing
|
|
103
|
+
modified_vtxs.each do |var, (_, nvtx_else)|
|
|
104
|
+
@lenv.set_var(var, nvtx_else)
|
|
105
|
+
end
|
|
106
|
+
else_val = AST.with_narrowing(genv, self, @lenv, narrowing) do
|
|
107
|
+
val = @else ? @else.install(genv) : Source.new(genv.nil_type)
|
|
89
108
|
modified_vtxs.each do |var, ary|
|
|
90
109
|
ary[1] = @lenv.get_var(var)
|
|
91
110
|
end
|
|
92
|
-
|
|
93
|
-
else_val = Source.new(genv.nil_type)
|
|
111
|
+
val
|
|
94
112
|
end
|
|
95
113
|
@changes.add_edge(genv, else_val, ret)
|
|
96
114
|
|
|
@@ -216,7 +234,7 @@ module TypeProf::Core
|
|
|
216
234
|
def install0(genv)
|
|
217
235
|
@arg.install(genv)
|
|
218
236
|
if @lenv.exist_var?(:"*expected_block_ret")
|
|
219
|
-
@lenv.add_next_box(@changes.add_escape_box(genv, @arg.ret
|
|
237
|
+
@lenv.add_next_box(@changes.add_escape_box(genv, @arg.ret))
|
|
220
238
|
end
|
|
221
239
|
Source.new(Type::Bot.new(genv))
|
|
222
240
|
end
|
|
@@ -233,31 +251,115 @@ module TypeProf::Core
|
|
|
233
251
|
end
|
|
234
252
|
end
|
|
235
253
|
|
|
254
|
+
class WhenNode < Node
|
|
255
|
+
def initialize(raw_when_node, lenv, pivot_var = nil)
|
|
256
|
+
super(raw_when_node, lenv)
|
|
257
|
+
@conditions = raw_when_node.conditions.map {|cond| AST.create_node(cond, lenv) }
|
|
258
|
+
@body = raw_when_node.statements ? AST.create_node(raw_when_node.statements, lenv) : DummyNilNode.new(code_range, lenv)
|
|
259
|
+
@pivot_var = pivot_var
|
|
260
|
+
end
|
|
261
|
+
|
|
262
|
+
attr_reader :conditions, :body, :pivot_var
|
|
263
|
+
|
|
264
|
+
def subnodes = { conditions:, body: }
|
|
265
|
+
|
|
266
|
+
def install0(genv)
|
|
267
|
+
@conditions.each {|condition| condition.install(genv) }
|
|
268
|
+
|
|
269
|
+
# 型絞り込みが必要な場合(pivot_varが設定されている場合)
|
|
270
|
+
if @pivot_var && @lenv.locals.key?(:"*pivot")
|
|
271
|
+
original_vtx = @lenv.locals[:"*pivot"]
|
|
272
|
+
|
|
273
|
+
# 複数条件のOR(union)処理
|
|
274
|
+
filtered_vtxs = []
|
|
275
|
+
|
|
276
|
+
@conditions.each do |condition|
|
|
277
|
+
if condition.is_a?(ConstantReadNode) && condition.static_ret
|
|
278
|
+
# 各条件に対して独立して型絞り込みを適用
|
|
279
|
+
condition_vtx = original_vtx.new_vertex(genv, self)
|
|
280
|
+
condition_vtx = IsAFilter.new(genv, self, condition_vtx, false, condition.static_ret).next_vtx
|
|
281
|
+
filtered_vtxs << condition_vtx
|
|
282
|
+
end
|
|
283
|
+
end
|
|
284
|
+
|
|
285
|
+
# 複数の絞り込み結果をマージして使用
|
|
286
|
+
if !filtered_vtxs.empty?
|
|
287
|
+
merged_vtx = Vertex.new(self)
|
|
288
|
+
filtered_vtxs.each do |vtx|
|
|
289
|
+
@changes.add_edge(genv, vtx, merged_vtx)
|
|
290
|
+
end
|
|
291
|
+
@lenv.set_var(@pivot_var, merged_vtx)
|
|
292
|
+
end
|
|
293
|
+
end
|
|
294
|
+
|
|
295
|
+
@body.install(genv)
|
|
296
|
+
end
|
|
297
|
+
|
|
298
|
+
# else節での型除外に使用する条件を取得
|
|
299
|
+
def get_exclusion_conditions
|
|
300
|
+
@conditions.select {|condition| condition.is_a?(ConstantReadNode) && condition.static_ret }
|
|
301
|
+
.map {|condition| condition.static_ret }
|
|
302
|
+
end
|
|
303
|
+
end
|
|
304
|
+
|
|
236
305
|
class CaseNode < Node
|
|
237
306
|
def initialize(raw_node, lenv)
|
|
238
307
|
super(raw_node, lenv)
|
|
239
308
|
@pivot = raw_node.predicate ? AST.create_node(raw_node.predicate, lenv) : nil
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
end
|
|
309
|
+
|
|
310
|
+
# pivot変数名を決定
|
|
311
|
+
pivot_var = @pivot.is_a?(LocalVariableReadNode) ? @pivot.var : nil
|
|
312
|
+
|
|
313
|
+
@when_nodes = raw_node.conditions.map {|raw_cond| WhenNode.new(raw_cond, lenv, pivot_var) }
|
|
246
314
|
@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
|
|
247
315
|
end
|
|
248
316
|
|
|
249
|
-
attr_reader :pivot, :
|
|
317
|
+
attr_reader :pivot, :when_nodes, :else_clause
|
|
250
318
|
|
|
251
|
-
def subnodes = { pivot:,
|
|
319
|
+
def subnodes = { pivot:, when_nodes:, else_clause: }
|
|
252
320
|
|
|
253
321
|
def install0(genv)
|
|
254
322
|
ret = Vertex.new(self)
|
|
255
323
|
@pivot&.install(genv)
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
324
|
+
|
|
325
|
+
# case文での型絞り込みを実装
|
|
326
|
+
if @pivot && @pivot.is_a?(LocalVariableReadNode)
|
|
327
|
+
var = @pivot.var
|
|
328
|
+
original_vtx = @lenv.get_var(var)
|
|
329
|
+
|
|
330
|
+
# ダミー変数に元の型情報を設定
|
|
331
|
+
@lenv.set_var(:"*pivot", original_vtx)
|
|
332
|
+
|
|
333
|
+
# 各when節を実行
|
|
334
|
+
@when_nodes.each do |when_node|
|
|
335
|
+
clause_result = when_node.install(genv)
|
|
336
|
+
@changes.add_edge(genv, clause_result, ret)
|
|
337
|
+
# 元の型に戻す
|
|
338
|
+
@lenv.set_var(var, original_vtx)
|
|
339
|
+
end
|
|
340
|
+
|
|
341
|
+
# else節(他のwhen節で除外された後の型)
|
|
342
|
+
filtered_else_vtx = original_vtx.new_vertex(genv, self)
|
|
343
|
+
@when_nodes.each do |when_node|
|
|
344
|
+
when_node.get_exclusion_conditions.each do |static_ret|
|
|
345
|
+
# 各when節の型を除外(negation)
|
|
346
|
+
filtered_else_vtx = IsAFilter.new(genv, self, filtered_else_vtx, true, static_ret).next_vtx
|
|
347
|
+
end
|
|
348
|
+
end
|
|
349
|
+
@lenv.set_var(var, filtered_else_vtx)
|
|
350
|
+
@changes.add_edge(genv, @else_clause.install(genv), ret)
|
|
351
|
+
@lenv.set_var(var, original_vtx)
|
|
352
|
+
|
|
353
|
+
# ダミー変数をクリア
|
|
354
|
+
@lenv.locals.delete(:"*pivot")
|
|
355
|
+
else
|
|
356
|
+
# pivotが変数でない場合は従来通り
|
|
357
|
+
@when_nodes.each do |when_node|
|
|
358
|
+
@changes.add_edge(genv, when_node.install(genv), ret)
|
|
359
|
+
end
|
|
360
|
+
@changes.add_edge(genv, @else_clause.install(genv), ret)
|
|
259
361
|
end
|
|
260
|
-
|
|
362
|
+
|
|
261
363
|
ret
|
|
262
364
|
end
|
|
263
365
|
end
|
|
@@ -293,8 +395,9 @@ module TypeProf::Core
|
|
|
293
395
|
end
|
|
294
396
|
|
|
295
397
|
class AndNode < Node
|
|
296
|
-
def initialize(raw_node, e1 = nil, raw_e2 =
|
|
398
|
+
def initialize(raw_node, e1 = nil, raw_e2 = raw_node.right, lenv)
|
|
297
399
|
super(raw_node, lenv)
|
|
400
|
+
|
|
298
401
|
@e1 = e1 || AST.create_node(raw_node.left, lenv)
|
|
299
402
|
@e2 = AST.create_node(raw_e2 || raw_node.right, lenv)
|
|
300
403
|
end
|
|
@@ -305,15 +408,39 @@ module TypeProf::Core
|
|
|
305
408
|
|
|
306
409
|
def install0(genv)
|
|
307
410
|
ret = Vertex.new(self)
|
|
308
|
-
|
|
309
|
-
|
|
411
|
+
|
|
412
|
+
v1 = @e1.install(genv)
|
|
413
|
+
|
|
414
|
+
# For AND: if left side is truthy, apply its narrowing to right side
|
|
415
|
+
# Use legacy detect_narrowing for now to maintain compatibility
|
|
416
|
+
then_narrowing, _else_narrowing = @e1.narrowings
|
|
417
|
+
if then_narrowing
|
|
418
|
+
v2 = AST.with_narrowing(genv, self, @lenv, then_narrowing) do
|
|
419
|
+
@e2.install(genv)
|
|
420
|
+
end
|
|
421
|
+
else
|
|
422
|
+
v2 = @e2.install(genv)
|
|
423
|
+
end
|
|
424
|
+
|
|
425
|
+
@changes.add_edge(genv, v1, ret)
|
|
426
|
+
@changes.add_edge(genv, v2, ret)
|
|
427
|
+
|
|
310
428
|
ret
|
|
311
429
|
end
|
|
430
|
+
|
|
431
|
+
def narrowings
|
|
432
|
+
@narrowings ||= begin
|
|
433
|
+
e1_then_narrowing, e1_else_narrowing = @e1.narrowings
|
|
434
|
+
e2_then_narrowing, e2_else_narrowing = @e2.narrowings
|
|
435
|
+
[e1_then_narrowing.and(e2_then_narrowing), e1_else_narrowing.or(e2_else_narrowing)]
|
|
436
|
+
end
|
|
437
|
+
end
|
|
312
438
|
end
|
|
313
439
|
|
|
314
440
|
class OrNode < Node
|
|
315
|
-
def initialize(raw_node, e1 = nil, raw_e2 =
|
|
441
|
+
def initialize(raw_node, e1 = nil, raw_e2 = raw_node.right, lenv)
|
|
316
442
|
super(raw_node, lenv)
|
|
443
|
+
|
|
317
444
|
@e1 = e1 || AST.create_node(raw_node.left, lenv)
|
|
318
445
|
@e2 = AST.create_node(raw_e2 || raw_node.right, lenv)
|
|
319
446
|
end
|
|
@@ -324,12 +451,35 @@ module TypeProf::Core
|
|
|
324
451
|
|
|
325
452
|
def install0(genv)
|
|
326
453
|
ret = Vertex.new(self)
|
|
454
|
+
|
|
327
455
|
v1 = @e1.install(genv)
|
|
328
456
|
v1 = NilFilter.new(genv, self, v1, false).next_vtx
|
|
457
|
+
|
|
458
|
+
# For OR: if left side is falsy, apply negated narrowing to right side
|
|
459
|
+
# Use legacy detect_narrowing for now to maintain compatibility
|
|
460
|
+
_then_narrowing, else_narrowing = @e1.narrowings
|
|
461
|
+
if else_narrowing
|
|
462
|
+
# For OR: negated narrowing (negate: true)
|
|
463
|
+
v2 = AST.with_narrowing(genv, self, @lenv, else_narrowing) do
|
|
464
|
+
@e2.install(genv)
|
|
465
|
+
end
|
|
466
|
+
else
|
|
467
|
+
v2 = @e2.install(genv)
|
|
468
|
+
end
|
|
469
|
+
|
|
329
470
|
@changes.add_edge(genv, v1, ret)
|
|
330
|
-
@changes.add_edge(genv,
|
|
471
|
+
@changes.add_edge(genv, v2, ret)
|
|
472
|
+
|
|
331
473
|
ret
|
|
332
474
|
end
|
|
475
|
+
|
|
476
|
+
def narrowings
|
|
477
|
+
@narrowings ||= begin
|
|
478
|
+
e1_then_narrowing, e1_else_narrowing = @e1.narrowings
|
|
479
|
+
e2_then_narrowing, e2_else_narrowing = @e2.narrowings
|
|
480
|
+
[e1_then_narrowing.or(e2_then_narrowing), e1_else_narrowing.and(e2_else_narrowing)]
|
|
481
|
+
end
|
|
482
|
+
end
|
|
333
483
|
end
|
|
334
484
|
|
|
335
485
|
class ReturnNode < Node
|
|
@@ -345,38 +495,86 @@ module TypeProf::Core
|
|
|
345
495
|
def install0(genv)
|
|
346
496
|
@arg.install(genv)
|
|
347
497
|
e_ret = @lenv.locals[:"*expected_method_ret"]
|
|
348
|
-
@lenv.add_return_box(@changes.add_escape_box(genv, @arg.ret
|
|
498
|
+
@lenv.add_return_box(@changes.add_escape_box(genv, @arg.ret)) if e_ret
|
|
349
499
|
Source.new(Type::Bot.new(genv))
|
|
350
500
|
end
|
|
351
501
|
end
|
|
352
502
|
|
|
503
|
+
class RescueNode < Node
|
|
504
|
+
def initialize(raw_node, lenv)
|
|
505
|
+
super(raw_node, lenv)
|
|
506
|
+
|
|
507
|
+
@exceptions = raw_node.exceptions.map {|raw_cond| AST.create_node(raw_cond, lenv) }
|
|
508
|
+
@statements = AST.create_node(raw_node.statements, lenv) if raw_node.statements
|
|
509
|
+
if raw_node.reference && @statements
|
|
510
|
+
@reference = AST.create_target_node(raw_node.reference, @statements.lenv)
|
|
511
|
+
end
|
|
512
|
+
end
|
|
513
|
+
|
|
514
|
+
attr_reader :exceptions, :reference, :statements
|
|
515
|
+
|
|
516
|
+
def subnodes = { exceptions:, reference:, statements: }
|
|
517
|
+
|
|
518
|
+
def define0(genv)
|
|
519
|
+
@exceptions.each {|exc| exc.define(genv) }
|
|
520
|
+
@reference.define(genv) if @reference
|
|
521
|
+
@statements.define(genv) if @statements
|
|
522
|
+
end
|
|
523
|
+
|
|
524
|
+
def undefine0(genv)
|
|
525
|
+
@exceptions.each {|exc| exc.undefine(genv) }
|
|
526
|
+
@reference.undefine(genv) if @reference
|
|
527
|
+
@statements.undefine(genv) if @statements
|
|
528
|
+
end
|
|
529
|
+
|
|
530
|
+
def install0(genv)
|
|
531
|
+
cond_vtxs = @exceptions.map do |exc|
|
|
532
|
+
case exc
|
|
533
|
+
when AST::SplatNode
|
|
534
|
+
ary_vtx = exc.expr.install(genv)
|
|
535
|
+
@changes.add_splat_box(genv, ary_vtx).ret
|
|
536
|
+
else
|
|
537
|
+
exc.install(genv)
|
|
538
|
+
end
|
|
539
|
+
end
|
|
540
|
+
|
|
541
|
+
if @reference
|
|
542
|
+
@reference.install(genv)
|
|
543
|
+
cond_vtxs.each do |cond_vtx|
|
|
544
|
+
instance_ty_box = @changes.add_instance_type_box(genv, cond_vtx)
|
|
545
|
+
@changes.add_edge(genv, instance_ty_box.ret, @reference.rhs.ret)
|
|
546
|
+
end
|
|
547
|
+
end
|
|
548
|
+
|
|
549
|
+
if @statements
|
|
550
|
+
@statements.install(genv)
|
|
551
|
+
else
|
|
552
|
+
Source.new(genv.nil_type)
|
|
553
|
+
end
|
|
554
|
+
end
|
|
555
|
+
end
|
|
556
|
+
|
|
353
557
|
class BeginNode < Node
|
|
354
558
|
def initialize(raw_node, lenv)
|
|
355
559
|
super(raw_node, lenv)
|
|
356
560
|
@body = raw_node.statements ? AST.create_node(raw_node.statements, lenv) : DummyNilNode.new(code_range, lenv)
|
|
357
|
-
|
|
561
|
+
|
|
358
562
|
@rescue_clauses = []
|
|
359
563
|
raw_res = raw_node.rescue_clause
|
|
360
564
|
while raw_res
|
|
361
|
-
raw_res
|
|
362
|
-
@rescue_conds << AST.create_node(raw_cond, lenv)
|
|
363
|
-
end
|
|
364
|
-
if raw_res.statements
|
|
365
|
-
@rescue_clauses << AST.create_node(raw_res.statements, lenv)
|
|
366
|
-
end
|
|
565
|
+
@rescue_clauses << AST.create_node(raw_res, lenv)
|
|
367
566
|
raw_res = raw_res.subsequent
|
|
368
567
|
end
|
|
369
|
-
@else_clause =
|
|
370
|
-
@ensure_clause =
|
|
568
|
+
@else_clause = AST.create_node(raw_node.else_clause.statements, lenv) if raw_node.else_clause&.statements
|
|
569
|
+
@ensure_clause = AST.create_node(raw_node.ensure_clause.statements, lenv) if raw_node.ensure_clause&.statements
|
|
371
570
|
end
|
|
372
571
|
|
|
373
|
-
attr_reader :body, :
|
|
572
|
+
attr_reader :body, :rescue_clauses, :else_clause, :ensure_clause
|
|
374
573
|
|
|
375
|
-
def subnodes = { body:,
|
|
574
|
+
def subnodes = { body:, rescue_clauses:, else_clause:, ensure_clause: }
|
|
376
575
|
|
|
377
576
|
def define0(genv)
|
|
378
577
|
@body.define(genv)
|
|
379
|
-
@rescue_conds.each {|cond| cond.define(genv) }
|
|
380
578
|
@rescue_clauses.each {|clause| clause.define(genv) }
|
|
381
579
|
@else_clause.define(genv) if @else_clause
|
|
382
580
|
@ensure_clause.define(genv) if @ensure_clause
|
|
@@ -384,7 +582,6 @@ module TypeProf::Core
|
|
|
384
582
|
|
|
385
583
|
def undefine0(genv)
|
|
386
584
|
@body.undefine(genv)
|
|
387
|
-
@rescue_conds.each {|cond| cond.undefine(genv) }
|
|
388
585
|
@rescue_clauses.each {|clause| clause.undefine(genv) }
|
|
389
586
|
@else_clause.undefine(genv) if @else_clause
|
|
390
587
|
@ensure_clause.undefine(genv) if @ensure_clause
|
|
@@ -392,11 +589,88 @@ module TypeProf::Core
|
|
|
392
589
|
|
|
393
590
|
def install0(genv)
|
|
394
591
|
ret = Vertex.new(self)
|
|
592
|
+
|
|
593
|
+
vars = []
|
|
594
|
+
@body.modified_vars(@lenv.locals.keys, vars) if @body
|
|
595
|
+
vars.uniq!
|
|
596
|
+
|
|
597
|
+
old_vtxs = {}
|
|
598
|
+
vars.each do |var|
|
|
599
|
+
vtx = @lenv.get_var(var)
|
|
600
|
+
old_vtxs[var] = vtx
|
|
601
|
+
end
|
|
602
|
+
|
|
395
603
|
@changes.add_edge(genv, @body.install(genv), ret)
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
604
|
+
|
|
605
|
+
body_vtxs = {}
|
|
606
|
+
vars.each do |var|
|
|
607
|
+
body_vtxs[var] = @lenv.get_var(var)
|
|
608
|
+
end
|
|
609
|
+
|
|
610
|
+
clause_vtxs_list = []
|
|
611
|
+
@rescue_clauses.each do |clause|
|
|
612
|
+
vars.each do |var|
|
|
613
|
+
old_vtx = old_vtxs[var]
|
|
614
|
+
nvtx = old_vtx.new_vertex(genv, self)
|
|
615
|
+
|
|
616
|
+
@changes.add_edge(genv, body_vtxs[var], nvtx) unless body_vtxs[var] == old_vtxs[var]
|
|
617
|
+
|
|
618
|
+
@lenv.set_var(var, nvtx)
|
|
619
|
+
end
|
|
620
|
+
|
|
621
|
+
@changes.add_edge(genv, clause.install(genv), ret)
|
|
622
|
+
|
|
623
|
+
clause_vtxs_list << {}
|
|
624
|
+
vars.each do |var|
|
|
625
|
+
clause_vtxs_list.last[var] = @lenv.get_var(var)
|
|
626
|
+
end
|
|
627
|
+
end
|
|
628
|
+
|
|
629
|
+
if @else_clause
|
|
630
|
+
vars.each do |var|
|
|
631
|
+
@lenv.set_var(var, body_vtxs[var])
|
|
632
|
+
end
|
|
633
|
+
@changes.add_edge(genv, @else_clause.install(genv), ret)
|
|
634
|
+
clause_vtxs_list << {}
|
|
635
|
+
vars.each do |var|
|
|
636
|
+
clause_vtxs_list.last[var] = @lenv.get_var(var)
|
|
637
|
+
end
|
|
638
|
+
end
|
|
639
|
+
|
|
640
|
+
if @ensure_clause
|
|
641
|
+
vars.each do |var|
|
|
642
|
+
union_vtx = old_vtxs[var].new_vertex(genv, self)
|
|
643
|
+
@changes.add_edge(genv, body_vtxs[var], union_vtx)
|
|
644
|
+
clause_vtxs_list.each do |clause_vtx|
|
|
645
|
+
@changes.add_edge(genv, clause_vtx[var], union_vtx)
|
|
646
|
+
end
|
|
647
|
+
@lenv.set_var(var, union_vtx)
|
|
648
|
+
end
|
|
649
|
+
|
|
650
|
+
@ensure_clause.install(genv)
|
|
651
|
+
|
|
652
|
+
clause_vtxs_list << {}
|
|
653
|
+
vars.each do |var|
|
|
654
|
+
clause_vtxs_list.last[var] = @lenv.get_var(var)
|
|
655
|
+
end
|
|
656
|
+
end
|
|
657
|
+
|
|
658
|
+
result_vtxs = {}
|
|
659
|
+
vars.each do |var|
|
|
660
|
+
result_vtx = old_vtxs[var].new_vertex(genv, self)
|
|
661
|
+
result_vtxs[var] = result_vtx
|
|
662
|
+
|
|
663
|
+
@changes.add_edge(genv, body_vtxs[var], result_vtx) unless body_vtxs[var] == old_vtxs[var]
|
|
664
|
+
|
|
665
|
+
clause_vtxs_list.each do |clause_vtx|
|
|
666
|
+
@changes.add_edge(genv, clause_vtx[var], result_vtx)
|
|
667
|
+
end
|
|
668
|
+
end
|
|
669
|
+
|
|
670
|
+
vars.each do |var|
|
|
671
|
+
@lenv.set_var(var, result_vtxs[var])
|
|
672
|
+
end
|
|
673
|
+
|
|
400
674
|
ret
|
|
401
675
|
end
|
|
402
676
|
end
|
|
@@ -6,7 +6,9 @@ module TypeProf::Core
|
|
|
6
6
|
# TODO: error for splat
|
|
7
7
|
@args = raw_node.arguments.arguments.map do |raw_arg|
|
|
8
8
|
next if raw_arg.is_a?(Prism::SplatNode)
|
|
9
|
-
|
|
9
|
+
lenv.use_strict_const_scope do
|
|
10
|
+
AST.create_node(raw_arg, lenv)
|
|
11
|
+
end
|
|
10
12
|
end.compact
|
|
11
13
|
# TODO: error for non-LIT
|
|
12
14
|
# TODO: fine-grained hover
|
|
@@ -77,8 +79,7 @@ module TypeProf::Core
|
|
|
77
79
|
@args.each do |arg|
|
|
78
80
|
ivar_name = :"@#{ arg }"
|
|
79
81
|
ivar_box = @changes.add_ivar_read_box(genv, @lenv.cref.cpath, false, ivar_name)
|
|
80
|
-
|
|
81
|
-
ret_box = @changes.add_escape_box(genv, ivar_box.ret, e_ret)
|
|
82
|
+
ret_box = @changes.add_escape_box(genv, ivar_box.ret)
|
|
82
83
|
@changes.add_method_def_box(genv, @lenv.cref.cpath, false, arg, FormalArguments::Empty, [ret_box])
|
|
83
84
|
end
|
|
84
85
|
Source.new
|
|
@@ -134,8 +135,7 @@ module TypeProf::Core
|
|
|
134
135
|
def install0(genv)
|
|
135
136
|
@args.zip(@static_ret) do |arg, ive|
|
|
136
137
|
ivar_box = @changes.add_ivar_read_box(genv, @lenv.cref.cpath, false, :"@#{ arg }")
|
|
137
|
-
|
|
138
|
-
ret_box = @changes.add_escape_box(genv, ivar_box.ret, e_ret)
|
|
138
|
+
ret_box = @changes.add_escape_box(genv, ivar_box.ret)
|
|
139
139
|
@changes.add_method_def_box(genv, @lenv.cref.cpath, false, arg, FormalArguments::Empty, [ret_box])
|
|
140
140
|
|
|
141
141
|
vtx = Vertex.new(self)
|
|
@@ -64,7 +64,7 @@ module TypeProf::Core
|
|
|
64
64
|
|
|
65
65
|
post_positionals = raw_args.posts.map {|n| (n.is_a?(Prism::MultiTargetNode) ? nil : n.name) }
|
|
66
66
|
|
|
67
|
-
rest_positionals = raw_args.rest
|
|
67
|
+
rest_positionals = raw_args.rest ? (raw_args.rest.name || :"*anonymous_rest") : nil
|
|
68
68
|
|
|
69
69
|
req_keywords = []
|
|
70
70
|
opt_keywords = []
|
|
@@ -82,7 +82,11 @@ module TypeProf::Core
|
|
|
82
82
|
|
|
83
83
|
case raw_args.keyword_rest
|
|
84
84
|
when Prism::KeywordRestParameterNode
|
|
85
|
-
rest_keywords = raw_args.keyword_rest.name
|
|
85
|
+
rest_keywords = raw_args.keyword_rest.name || :"**anonymous_keyword"
|
|
86
|
+
when Prism::ForwardingParameterNode
|
|
87
|
+
# TODO: The variable names might be subject to change when supporting the propagation of parameter values to the graph during method calls.
|
|
88
|
+
rest_positionals = :"..."
|
|
89
|
+
rest_keywords = :"..."
|
|
86
90
|
when Prism::NoKeywordsParameterNode
|
|
87
91
|
# what to do?
|
|
88
92
|
when nil
|
|
@@ -91,7 +95,7 @@ module TypeProf::Core
|
|
|
91
95
|
raise "unexpected keyword rest: #{ raw_args.keyword_rest.class }"
|
|
92
96
|
end
|
|
93
97
|
|
|
94
|
-
block = raw_args.block.name if raw_args.block
|
|
98
|
+
block = raw_args.block.name || :"*anonymous_block" if raw_args.block
|
|
95
99
|
|
|
96
100
|
{
|
|
97
101
|
req_positionals:,
|
|
@@ -224,6 +228,12 @@ module TypeProf::Core
|
|
|
224
228
|
@changes.add_edge(genv, Source.new(genv.gen_ary_type(Vertex.new(self))), rest_positionals)
|
|
225
229
|
end
|
|
226
230
|
|
|
231
|
+
if rest_keywords
|
|
232
|
+
if @rest_keywords == :"**anonymous_keyword"
|
|
233
|
+
@changes.add_edge(genv, Source.new(genv.gen_hash_type(Vertex.new(self), Vertex.new(self))), rest_keywords)
|
|
234
|
+
end
|
|
235
|
+
end
|
|
236
|
+
|
|
227
237
|
@opt_positional_defaults.zip(opt_positionals) do |expr, vtx|
|
|
228
238
|
@changes.add_edge(genv, expr.install(genv), vtx)
|
|
229
239
|
end
|
|
@@ -238,9 +248,9 @@ module TypeProf::Core
|
|
|
238
248
|
end
|
|
239
249
|
|
|
240
250
|
if @body
|
|
241
|
-
|
|
251
|
+
@body.lenv.locals[:"*expected_method_ret"] = Vertex.new(self)
|
|
242
252
|
@body.install(genv)
|
|
243
|
-
@body.lenv.add_return_box(@changes.add_escape_box(genv, @body.ret
|
|
253
|
+
@body.lenv.add_return_box(@changes.add_escape_box(genv, @body.ret))
|
|
244
254
|
end
|
|
245
255
|
|
|
246
256
|
f_args = FormalArguments.new(
|
|
@@ -20,9 +20,24 @@ module TypeProf::Core
|
|
|
20
20
|
|
|
21
21
|
def install0(genv)
|
|
22
22
|
ret = nil
|
|
23
|
+
|
|
24
|
+
post_stmts = []
|
|
25
|
+
|
|
23
26
|
@stmts.each do |stmt|
|
|
24
|
-
|
|
27
|
+
next if stmt.nil?
|
|
28
|
+
|
|
29
|
+
if stmt.is_a?(PostExecutionNode)
|
|
30
|
+
post_stmts << stmt
|
|
31
|
+
next
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
ret = stmt.install(genv)
|
|
25
35
|
end
|
|
36
|
+
|
|
37
|
+
post_stmts.each do |stmt|
|
|
38
|
+
stmt.install(genv)
|
|
39
|
+
end
|
|
40
|
+
|
|
26
41
|
if ret
|
|
27
42
|
ret2 = Vertex.new(self)
|
|
28
43
|
@changes.add_edge(genv, ret, ret2)
|
|
@@ -32,6 +47,10 @@ module TypeProf::Core
|
|
|
32
47
|
end
|
|
33
48
|
end
|
|
34
49
|
|
|
50
|
+
def narrowings
|
|
51
|
+
@stmts.size == 1 ? @stmts[0].narrowings : super
|
|
52
|
+
end
|
|
53
|
+
|
|
35
54
|
def diff(prev_node)
|
|
36
55
|
if prev_node.is_a?(StatementsNode)
|
|
37
56
|
i = 0
|
|
@@ -242,7 +261,7 @@ module TypeProf::Core
|
|
|
242
261
|
end
|
|
243
262
|
end
|
|
244
263
|
|
|
245
|
-
class
|
|
264
|
+
class MatchPredicateNode < Node
|
|
246
265
|
def initialize(raw_node, lenv)
|
|
247
266
|
super(raw_node, lenv)
|
|
248
267
|
@value = AST.create_node(raw_node.value, lenv)
|