typeprof 0.31.1 → 0.33.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +2 -1
- data/doc/report_guide.md +88 -0
- data/lib/typeprof/cli/cli.rb +9 -3
- data/lib/typeprof/code_range.rb +7 -5
- data/lib/typeprof/core/ast/base.rb +31 -6
- data/lib/typeprof/core/ast/call.rb +120 -39
- data/lib/typeprof/core/ast/const.rb +22 -11
- data/lib/typeprof/core/ast/control.rb +62 -32
- data/lib/typeprof/core/ast/meta.rb +279 -14
- data/lib/typeprof/core/ast/method.rb +82 -24
- data/lib/typeprof/core/ast/misc.rb +41 -12
- data/lib/typeprof/core/ast/module.rb +38 -4
- data/lib/typeprof/core/ast/pattern.rb +51 -23
- data/lib/typeprof/core/ast/sig_decl.rb +141 -27
- data/lib/typeprof/core/ast/sig_type.rb +113 -32
- data/lib/typeprof/core/ast/value.rb +14 -6
- data/lib/typeprof/core/ast/variable.rb +17 -4
- data/lib/typeprof/core/ast.rb +98 -14
- data/lib/typeprof/core/builtin.rb +184 -12
- data/lib/typeprof/core/env/method.rb +343 -6
- data/lib/typeprof/core/env/method_entity.rb +18 -15
- data/lib/typeprof/core/env/module_entity.rb +116 -18
- data/lib/typeprof/core/env/static_read.rb +4 -4
- data/lib/typeprof/core/env/type_alias_entity.rb +1 -1
- data/lib/typeprof/core/env/value_entity.rb +25 -3
- data/lib/typeprof/core/env.rb +113 -23
- data/lib/typeprof/core/graph/box.rb +508 -63
- data/lib/typeprof/core/graph/change_set.rb +64 -46
- data/lib/typeprof/core/graph/filter.rb +8 -5
- data/lib/typeprof/core/graph/vertex.rb +20 -19
- data/lib/typeprof/core/service.rb +340 -24
- data/lib/typeprof/core/type.rb +41 -7
- data/lib/typeprof/core/util.rb +6 -0
- data/lib/typeprof/lsp/messages.rb +5 -0
- data/lib/typeprof/lsp/server.rb +35 -4
- data/lib/typeprof/version.rb +1 -1
- metadata +3 -2
|
@@ -8,7 +8,7 @@ module TypeProf::Core
|
|
|
8
8
|
@cbase = nil
|
|
9
9
|
@toplevel = false
|
|
10
10
|
@cname = raw_node.name
|
|
11
|
-
@
|
|
11
|
+
@cname_code_range_loc = raw_node.location
|
|
12
12
|
when :constant_path_node, :constant_path_target_node
|
|
13
13
|
if raw_node.parent
|
|
14
14
|
@cbase = AST.create_node(raw_node.parent, lenv)
|
|
@@ -18,14 +18,18 @@ module TypeProf::Core
|
|
|
18
18
|
@toplevel = true
|
|
19
19
|
end
|
|
20
20
|
@cname = raw_node.name
|
|
21
|
-
@
|
|
21
|
+
@cname_code_range_loc = raw_node.name_loc
|
|
22
22
|
else
|
|
23
23
|
raise raw_node.type.to_s
|
|
24
24
|
end
|
|
25
25
|
@strict_const_scope = lenv.strict_const_scope
|
|
26
26
|
end
|
|
27
27
|
|
|
28
|
-
attr_reader :cname, :cbase, :toplevel, :
|
|
28
|
+
attr_reader :cname, :cbase, :toplevel, :strict_const_scope
|
|
29
|
+
|
|
30
|
+
def cname_code_range
|
|
31
|
+
@cname_code_range ||= @lenv.code_range_from_node(@cname_code_range_loc) if @cname_code_range_loc
|
|
32
|
+
end
|
|
29
33
|
|
|
30
34
|
def attrs = { cname:, toplevel:, strict_const_scope: }
|
|
31
35
|
def subnodes = { cbase: }
|
|
@@ -57,24 +61,28 @@ module TypeProf::Core
|
|
|
57
61
|
# C = expr
|
|
58
62
|
@cpath = nil
|
|
59
63
|
@static_cpath = lenv.cref.cpath + [raw_node.name]
|
|
60
|
-
@
|
|
64
|
+
@cname_code_range_loc = raw_node.respond_to?(:name_loc) ? raw_node.name_loc : raw_node.location
|
|
61
65
|
when :constant_path_write_node, :constant_path_operator_write_node, :constant_path_or_write_node, :constant_path_and_write_node
|
|
62
66
|
# expr::C = expr
|
|
63
67
|
@cpath = AST.create_node(raw_node.target, lenv)
|
|
64
68
|
@static_cpath = AST.parse_cpath(raw_node.target, lenv.cref)
|
|
65
|
-
@
|
|
69
|
+
@cname_code_range_loc = raw_node.target.location
|
|
66
70
|
when :constant_path_target_node
|
|
67
71
|
# expr::C, * = ary
|
|
68
72
|
@cpath = ConstantReadNode.new(raw_node, lenv)
|
|
69
73
|
@static_cpath = AST.parse_cpath(raw_node, lenv.cref)
|
|
70
|
-
@
|
|
74
|
+
@cname_code_range_loc = raw_node.location
|
|
71
75
|
else
|
|
72
76
|
raise
|
|
73
77
|
end
|
|
74
78
|
@rhs = rhs
|
|
75
79
|
end
|
|
76
80
|
|
|
77
|
-
attr_reader :cpath, :rhs, :static_cpath
|
|
81
|
+
attr_reader :cpath, :rhs, :static_cpath
|
|
82
|
+
|
|
83
|
+
def cname_code_range
|
|
84
|
+
@cname_code_range ||= @lenv.code_range_from_node(@cname_code_range_loc) if @cname_code_range_loc
|
|
85
|
+
end
|
|
78
86
|
|
|
79
87
|
def subnodes = { cpath:, rhs: }
|
|
80
88
|
def attrs = { static_cpath: }
|
|
@@ -83,9 +91,10 @@ module TypeProf::Core
|
|
|
83
91
|
@cpath.define(genv) if @cpath
|
|
84
92
|
@rhs.define(genv) if @rhs
|
|
85
93
|
if @static_cpath
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
94
|
+
cdef = genv.resolve_const(@static_cpath)
|
|
95
|
+
cdef.on_const_added(genv, @static_cpath)
|
|
96
|
+
cdef.add_def(self)
|
|
97
|
+
cdef
|
|
89
98
|
else
|
|
90
99
|
nil
|
|
91
100
|
end
|
|
@@ -102,7 +111,9 @@ module TypeProf::Core
|
|
|
102
111
|
|
|
103
112
|
def undefine0(genv)
|
|
104
113
|
if @static_cpath
|
|
105
|
-
genv.resolve_const(@static_cpath)
|
|
114
|
+
cdef = genv.resolve_const(@static_cpath)
|
|
115
|
+
cdef.remove_def(self)
|
|
116
|
+
cdef.on_const_removed(genv, @static_cpath)
|
|
106
117
|
end
|
|
107
118
|
@rhs.undefine(genv) if @rhs
|
|
108
119
|
@cpath.undefine(genv) if @cpath
|
|
@@ -203,7 +203,7 @@ module TypeProf::Core
|
|
|
203
203
|
|
|
204
204
|
def install0(genv)
|
|
205
205
|
arg = @arg.install(genv)
|
|
206
|
-
@changes.add_edge(genv, arg, @lenv.get_break_vtx)
|
|
206
|
+
@changes.add_edge(genv, arg.new_vertex(genv, self), @lenv.get_break_vtx)
|
|
207
207
|
Source.new()
|
|
208
208
|
end
|
|
209
209
|
end
|
|
@@ -236,7 +236,7 @@ module TypeProf::Core
|
|
|
236
236
|
if @lenv.exist_var?(:"*expected_block_ret")
|
|
237
237
|
@lenv.add_next_box(@changes.add_escape_box(genv, @arg.ret))
|
|
238
238
|
end
|
|
239
|
-
Source.new(
|
|
239
|
+
Source.new(genv.bot_type)
|
|
240
240
|
end
|
|
241
241
|
end
|
|
242
242
|
|
|
@@ -322,44 +322,74 @@ module TypeProf::Core
|
|
|
322
322
|
ret = Vertex.new(self)
|
|
323
323
|
@pivot&.install(genv)
|
|
324
324
|
|
|
325
|
-
#
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
325
|
+
# Collect modified variables across all branches
|
|
326
|
+
vars = []
|
|
327
|
+
@when_nodes.each {|wn| wn.body.modified_vars(@lenv.locals.keys, vars) }
|
|
328
|
+
@else_clause.modified_vars(@lenv.locals.keys, vars) if @else_clause
|
|
329
|
+
vars.uniq!
|
|
329
330
|
|
|
330
|
-
|
|
331
|
-
|
|
331
|
+
# Save original variable vertices
|
|
332
|
+
saved_vtxs = {}
|
|
333
|
+
vars.each do |var|
|
|
334
|
+
saved_vtxs[var] = @lenv.get_var(var)
|
|
335
|
+
end
|
|
332
336
|
|
|
333
|
-
|
|
334
|
-
|
|
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
|
|
337
|
+
# Prepare per-branch result vertices
|
|
338
|
+
branch_vtxs = []
|
|
340
339
|
|
|
341
|
-
|
|
342
|
-
|
|
340
|
+
# Setup pivot narrowing if applicable
|
|
341
|
+
pivot_var = @pivot.is_a?(LocalVariableReadNode) ? @pivot.var : nil
|
|
342
|
+
if pivot_var
|
|
343
|
+
original_pivot = @lenv.get_var(pivot_var)
|
|
344
|
+
@lenv.set_var(:"*pivot", original_pivot)
|
|
345
|
+
end
|
|
346
|
+
|
|
347
|
+
# Install each when branch
|
|
348
|
+
@when_nodes.each do |when_node|
|
|
349
|
+
# Reset variables to original for each branch
|
|
350
|
+
saved_vtxs.each {|var, vtx| @lenv.set_var(var, vtx.new_vertex(genv, self)) }
|
|
351
|
+
@lenv.set_var(pivot_var, original_pivot) if pivot_var
|
|
352
|
+
|
|
353
|
+
clause_val = when_node.install(genv)
|
|
354
|
+
@changes.add_edge(genv, clause_val, ret)
|
|
355
|
+
|
|
356
|
+
modified = {}
|
|
357
|
+
vars.each {|var| modified[var] = @lenv.get_var(var) }
|
|
358
|
+
branch_vtxs << [clause_val, modified]
|
|
359
|
+
end
|
|
360
|
+
|
|
361
|
+
# Install else branch
|
|
362
|
+
saved_vtxs.each {|var, vtx| @lenv.set_var(var, vtx.new_vertex(genv, self)) }
|
|
363
|
+
if pivot_var
|
|
364
|
+
# Apply exclusion filters for else
|
|
365
|
+
filtered_else_vtx = original_pivot.new_vertex(genv, self)
|
|
343
366
|
@when_nodes.each do |when_node|
|
|
344
367
|
when_node.get_exclusion_conditions.each do |static_ret|
|
|
345
|
-
# 各when節の型を除外(negation)
|
|
346
368
|
filtered_else_vtx = IsAFilter.new(genv, self, filtered_else_vtx, true, static_ret).next_vtx
|
|
347
369
|
end
|
|
348
370
|
end
|
|
349
|
-
@lenv.set_var(
|
|
350
|
-
|
|
351
|
-
|
|
371
|
+
@lenv.set_var(pivot_var, filtered_else_vtx)
|
|
372
|
+
end
|
|
373
|
+
else_val = @else_clause.install(genv)
|
|
374
|
+
@changes.add_edge(genv, else_val, ret)
|
|
352
375
|
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
376
|
+
else_modified = {}
|
|
377
|
+
vars.each {|var| else_modified[var] = @lenv.get_var(var) }
|
|
378
|
+
branch_vtxs << [else_val, else_modified]
|
|
379
|
+
|
|
380
|
+
# Join all branches
|
|
381
|
+
vars.each do |var|
|
|
382
|
+
joined = Vertex.new(self)
|
|
383
|
+
branch_vtxs.each do |branch_val, modified|
|
|
384
|
+
vtx = BotFilter.new(genv, self, modified[var], branch_val).next_vtx
|
|
385
|
+
@changes.add_edge(genv, vtx, joined)
|
|
359
386
|
end
|
|
360
|
-
@
|
|
387
|
+
@lenv.set_var(var, joined)
|
|
361
388
|
end
|
|
362
389
|
|
|
390
|
+
# Cleanup
|
|
391
|
+
@lenv.locals.delete(:"*pivot") if pivot_var
|
|
392
|
+
|
|
363
393
|
ret
|
|
364
394
|
end
|
|
365
395
|
end
|
|
@@ -384,9 +414,9 @@ module TypeProf::Core
|
|
|
384
414
|
|
|
385
415
|
def install0(genv)
|
|
386
416
|
ret = Vertex.new(self)
|
|
387
|
-
@pivot
|
|
417
|
+
subject = @pivot ? @pivot.install(genv) : Source.new(genv.nil_type)
|
|
388
418
|
@patterns.zip(@clauses) do |pattern, clause|
|
|
389
|
-
pattern.
|
|
419
|
+
pattern.install_pattern(genv, subject)
|
|
390
420
|
@changes.add_edge(genv, clause.install(genv), ret)
|
|
391
421
|
end
|
|
392
422
|
@changes.add_edge(genv, @else_clause.install(genv), ret) if @else_clause
|
|
@@ -496,7 +526,7 @@ module TypeProf::Core
|
|
|
496
526
|
@arg.install(genv)
|
|
497
527
|
e_ret = @lenv.locals[:"*expected_method_ret"]
|
|
498
528
|
@lenv.add_return_box(@changes.add_escape_box(genv, @arg.ret)) if e_ret
|
|
499
|
-
Source.new(
|
|
529
|
+
Source.new(genv.bot_type)
|
|
500
530
|
end
|
|
501
531
|
end
|
|
502
532
|
|
|
@@ -681,7 +711,7 @@ module TypeProf::Core
|
|
|
681
711
|
end
|
|
682
712
|
|
|
683
713
|
def install0(genv)
|
|
684
|
-
Source.new(
|
|
714
|
+
Source.new(genv.bot_type)
|
|
685
715
|
end
|
|
686
716
|
end
|
|
687
717
|
|
|
@@ -46,9 +46,56 @@ module TypeProf::Core
|
|
|
46
46
|
end
|
|
47
47
|
end
|
|
48
48
|
|
|
49
|
+
class ExtendMetaNode < Node
|
|
50
|
+
def initialize(raw_node, lenv)
|
|
51
|
+
super(raw_node, lenv)
|
|
52
|
+
# TODO: error for splat
|
|
53
|
+
@args = raw_node.arguments.arguments.map do |raw_arg|
|
|
54
|
+
next if raw_arg.is_a?(Prism::SplatNode)
|
|
55
|
+
lenv.use_strict_const_scope do
|
|
56
|
+
AST.create_node(raw_arg, lenv)
|
|
57
|
+
end
|
|
58
|
+
end.compact
|
|
59
|
+
# TODO: error for non-LIT
|
|
60
|
+
# TODO: fine-grained hover
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
attr_reader :args
|
|
64
|
+
|
|
65
|
+
def subnodes = { args: }
|
|
66
|
+
|
|
67
|
+
def define0(genv)
|
|
68
|
+
mod = genv.resolve_cpath(@lenv.cref.cpath)
|
|
69
|
+
@args.each do |arg|
|
|
70
|
+
arg.define(genv)
|
|
71
|
+
if arg.static_ret
|
|
72
|
+
arg.static_ret.followers << mod
|
|
73
|
+
mod.add_extend_def(genv, arg)
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def undefine0(genv)
|
|
79
|
+
mod = genv.resolve_cpath(@lenv.cref.cpath)
|
|
80
|
+
@args.each do |arg|
|
|
81
|
+
if arg.static_ret
|
|
82
|
+
mod.remove_extend_def(genv, arg)
|
|
83
|
+
end
|
|
84
|
+
arg.undefine(genv)
|
|
85
|
+
end
|
|
86
|
+
super(genv)
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def install0(genv)
|
|
90
|
+
@args.each {|arg| arg.install(genv) }
|
|
91
|
+
Source.new
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
|
|
49
95
|
class AttrReaderMetaNode < Node
|
|
50
96
|
def initialize(raw_node, lenv)
|
|
51
97
|
super(raw_node, lenv)
|
|
98
|
+
@singleton = lenv.cref.scope_level == :metaclass
|
|
52
99
|
@args = []
|
|
53
100
|
raw_node.arguments.arguments.each do |raw_arg|
|
|
54
101
|
@args << raw_arg.value.to_sym if raw_arg.type == :symbol_node
|
|
@@ -57,9 +104,9 @@ module TypeProf::Core
|
|
|
57
104
|
# TODO: fine-grained hover
|
|
58
105
|
end
|
|
59
106
|
|
|
60
|
-
attr_reader :args
|
|
107
|
+
attr_reader :singleton, :args
|
|
61
108
|
|
|
62
|
-
def attrs = { args: }
|
|
109
|
+
def attrs = { singleton:, args: }
|
|
63
110
|
|
|
64
111
|
def req_positionals = []
|
|
65
112
|
def opt_positionals = []
|
|
@@ -68,19 +115,83 @@ module TypeProf::Core
|
|
|
68
115
|
def req_keywords = []
|
|
69
116
|
def opt_keywords = []
|
|
70
117
|
def rest_keywords = nil
|
|
118
|
+
def no_keywords = false
|
|
71
119
|
|
|
72
120
|
def mname_code_range(name)
|
|
73
121
|
idx = @args.index(name.to_sym) # TODO: support string args
|
|
74
122
|
node = @raw_node.arguments.arguments[idx].location
|
|
75
|
-
|
|
123
|
+
@lenv.code_range_from_node(node)
|
|
76
124
|
end
|
|
77
125
|
|
|
78
126
|
def install0(genv)
|
|
79
127
|
@args.each do |arg|
|
|
80
128
|
ivar_name = :"@#{ arg }"
|
|
81
|
-
ivar_box = @changes.add_ivar_read_box(genv, @lenv.cref.cpath,
|
|
129
|
+
ivar_box = @changes.add_ivar_read_box(genv, @lenv.cref.cpath, @singleton, ivar_name)
|
|
82
130
|
ret_box = @changes.add_escape_box(genv, ivar_box.ret)
|
|
83
|
-
@changes.add_method_def_box(genv, @lenv.cref.cpath,
|
|
131
|
+
@changes.add_method_def_box(genv, @lenv.cref.cpath, @singleton, arg, FormalArguments::Empty, [ret_box])
|
|
132
|
+
end
|
|
133
|
+
Source.new
|
|
134
|
+
end
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
class AttrWriterMetaNode < Node
|
|
138
|
+
def initialize(raw_node, lenv)
|
|
139
|
+
super(raw_node, lenv)
|
|
140
|
+
@singleton = lenv.cref.scope_level == :metaclass
|
|
141
|
+
@args = []
|
|
142
|
+
raw_node.arguments.arguments.each do |raw_arg|
|
|
143
|
+
@args << raw_arg.value.to_sym if raw_arg.type == :symbol_node
|
|
144
|
+
end
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
attr_reader :singleton, :args
|
|
148
|
+
|
|
149
|
+
def attrs = { singleton:, args: }
|
|
150
|
+
|
|
151
|
+
# Interface expected by MethodDefBox
|
|
152
|
+
def req_keywords = []
|
|
153
|
+
def opt_keywords = []
|
|
154
|
+
def rest_keywords = nil
|
|
155
|
+
def no_keywords = false
|
|
156
|
+
|
|
157
|
+
def mname_code_range(name)
|
|
158
|
+
idx = @args.index(name.to_sym)
|
|
159
|
+
node = @raw_node.arguments.arguments[idx].location
|
|
160
|
+
@lenv.code_range_from_node(node)
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
def define0(genv)
|
|
164
|
+
@args.map do |arg|
|
|
165
|
+
mod = genv.resolve_ivar(lenv.cref.cpath, @singleton, :"@#{ arg }")
|
|
166
|
+
mod.add_def(self)
|
|
167
|
+
mod
|
|
168
|
+
end
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
def define_copy(genv)
|
|
172
|
+
@args.map do |arg|
|
|
173
|
+
mod = genv.resolve_ivar(lenv.cref.cpath, @singleton, :"@#{ arg }")
|
|
174
|
+
mod.add_def(self)
|
|
175
|
+
mod.remove_def(@prev_node)
|
|
176
|
+
mod
|
|
177
|
+
end
|
|
178
|
+
super(genv)
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
def undefine0(genv)
|
|
182
|
+
@args.each do |arg|
|
|
183
|
+
mod = genv.resolve_ivar(lenv.cref.cpath, @singleton, :"@#{ arg }")
|
|
184
|
+
mod.remove_def(self)
|
|
185
|
+
end
|
|
186
|
+
end
|
|
187
|
+
|
|
188
|
+
def install0(genv)
|
|
189
|
+
@args.zip(@static_ret) do |arg, ive|
|
|
190
|
+
vtx = Vertex.new(self)
|
|
191
|
+
@changes.add_edge(genv, vtx, ive.vtx)
|
|
192
|
+
ret_box = @changes.add_escape_box(genv, vtx)
|
|
193
|
+
f_args = FormalArguments.new([vtx], [], nil, [], [], [], nil, nil)
|
|
194
|
+
@changes.add_method_def_box(genv, @lenv.cref.cpath, @singleton, :"#{ arg }=", f_args, [ret_box])
|
|
84
195
|
end
|
|
85
196
|
Source.new
|
|
86
197
|
end
|
|
@@ -89,6 +200,7 @@ module TypeProf::Core
|
|
|
89
200
|
class AttrAccessorMetaNode < Node
|
|
90
201
|
def initialize(raw_node, lenv)
|
|
91
202
|
super(raw_node, lenv)
|
|
203
|
+
@singleton = lenv.cref.scope_level == :metaclass
|
|
92
204
|
@args = []
|
|
93
205
|
raw_node.arguments.arguments.each do |raw_arg|
|
|
94
206
|
@args << raw_arg.value.to_sym if raw_arg.type == :symbol_node
|
|
@@ -97,19 +209,25 @@ module TypeProf::Core
|
|
|
97
209
|
# TODO: fine-grained hover
|
|
98
210
|
end
|
|
99
211
|
|
|
100
|
-
attr_reader :args
|
|
212
|
+
attr_reader :singleton, :args
|
|
101
213
|
|
|
102
|
-
def attrs = { args: }
|
|
214
|
+
def attrs = { singleton:, args: }
|
|
215
|
+
|
|
216
|
+
# Interface expected by MethodDefBox
|
|
217
|
+
def req_keywords = []
|
|
218
|
+
def opt_keywords = []
|
|
219
|
+
def rest_keywords = nil
|
|
220
|
+
def no_keywords = false
|
|
103
221
|
|
|
104
222
|
def mname_code_range(name)
|
|
105
223
|
idx = @args.index(name.to_sym) # TODO: support string args
|
|
106
224
|
node = @raw_node.arguments.arguments[idx].location
|
|
107
|
-
|
|
225
|
+
@lenv.code_range_from_node(node)
|
|
108
226
|
end
|
|
109
227
|
|
|
110
228
|
def define0(genv)
|
|
111
229
|
@args.map do |arg|
|
|
112
|
-
mod = genv.resolve_ivar(lenv.cref.cpath,
|
|
230
|
+
mod = genv.resolve_ivar(lenv.cref.cpath, @singleton, :"@#{ arg }")
|
|
113
231
|
mod.add_def(self)
|
|
114
232
|
mod
|
|
115
233
|
end
|
|
@@ -117,7 +235,7 @@ module TypeProf::Core
|
|
|
117
235
|
|
|
118
236
|
def define_copy(genv)
|
|
119
237
|
@args.map do |arg|
|
|
120
|
-
mod = genv.resolve_ivar(lenv.cref.cpath,
|
|
238
|
+
mod = genv.resolve_ivar(lenv.cref.cpath, @singleton, :"@#{ arg }")
|
|
121
239
|
mod.add_def(self)
|
|
122
240
|
mod.remove_def(@prev_node)
|
|
123
241
|
mod
|
|
@@ -127,24 +245,171 @@ module TypeProf::Core
|
|
|
127
245
|
|
|
128
246
|
def undefine0(genv)
|
|
129
247
|
@args.each do |arg|
|
|
130
|
-
mod = genv.resolve_ivar(lenv.cref.cpath,
|
|
248
|
+
mod = genv.resolve_ivar(lenv.cref.cpath, @singleton, :"@#{ arg }")
|
|
131
249
|
mod.remove_def(self)
|
|
132
250
|
end
|
|
133
251
|
end
|
|
134
252
|
|
|
135
253
|
def install0(genv)
|
|
136
254
|
@args.zip(@static_ret) do |arg, ive|
|
|
137
|
-
ivar_box = @changes.add_ivar_read_box(genv, @lenv.cref.cpath,
|
|
255
|
+
ivar_box = @changes.add_ivar_read_box(genv, @lenv.cref.cpath, @singleton, :"@#{ arg }")
|
|
138
256
|
ret_box = @changes.add_escape_box(genv, ivar_box.ret)
|
|
139
|
-
@changes.add_method_def_box(genv, @lenv.cref.cpath,
|
|
257
|
+
@changes.add_method_def_box(genv, @lenv.cref.cpath, @singleton, arg, FormalArguments::Empty, [ret_box])
|
|
140
258
|
|
|
141
259
|
vtx = Vertex.new(self)
|
|
142
260
|
@changes.add_edge(genv, vtx, ive.vtx)
|
|
143
261
|
f_args = FormalArguments.new([vtx], [], nil, [], [], [], nil, nil)
|
|
144
|
-
@changes.add_method_def_box(genv, @lenv.cref.cpath,
|
|
262
|
+
@changes.add_method_def_box(genv, @lenv.cref.cpath, @singleton, :"#{ arg }=", f_args, [ret_box])
|
|
145
263
|
end
|
|
146
264
|
Source.new
|
|
147
265
|
end
|
|
148
266
|
end
|
|
267
|
+
class ModuleFunctionMetaNode < Node
|
|
268
|
+
def install0(genv)
|
|
269
|
+
@lenv.module_function = true
|
|
270
|
+
Source.new
|
|
271
|
+
end
|
|
272
|
+
end
|
|
273
|
+
|
|
274
|
+
class StructNewNode < Node
|
|
275
|
+
def initialize(raw_node, members, kind, lenv)
|
|
276
|
+
super(raw_node, lenv)
|
|
277
|
+
case raw_node.type
|
|
278
|
+
when :constant_write_node
|
|
279
|
+
@static_cpath = lenv.cref.cpath + [raw_node.name]
|
|
280
|
+
when :constant_path_write_node
|
|
281
|
+
@static_cpath = AST.parse_cpath(raw_node.target, lenv.cref)
|
|
282
|
+
else
|
|
283
|
+
raise
|
|
284
|
+
end
|
|
285
|
+
@members = members
|
|
286
|
+
@kind = kind # :struct or :data
|
|
287
|
+
|
|
288
|
+
# Parse block body if present (Struct.new(:foo) do ... end)
|
|
289
|
+
raw_value = raw_node.value
|
|
290
|
+
if raw_value.block && raw_value.block.type == :block_node && raw_value.block.body
|
|
291
|
+
ncref = CRef.new(@static_cpath, :instance, nil, lenv.cref)
|
|
292
|
+
nlenv = LocalEnv.new(lenv.file_context, ncref, {}, [])
|
|
293
|
+
@block_body = AST.create_node(raw_value.block.body, nlenv)
|
|
294
|
+
end
|
|
295
|
+
end
|
|
296
|
+
|
|
297
|
+
attr_reader :static_cpath, :members, :kind, :block_body
|
|
298
|
+
|
|
299
|
+
# Not a valid constant name, so no Ruby code can refer to it
|
|
300
|
+
BASE_CNAME = :"<struct base>"
|
|
301
|
+
|
|
302
|
+
def struct_base_cpath = @static_cpath + [BASE_CNAME]
|
|
303
|
+
|
|
304
|
+
def subnodes = { block_body: }
|
|
305
|
+
def attrs = { static_cpath:, members:, kind: }
|
|
306
|
+
|
|
307
|
+
# Interface expected by MethodDefBox
|
|
308
|
+
def req_positionals = @kind == :struct ? @members : []
|
|
309
|
+
def opt_positionals = []
|
|
310
|
+
def rest_positionals = nil
|
|
311
|
+
def post_positionals = []
|
|
312
|
+
def req_keywords = @kind == :data ? @members : []
|
|
313
|
+
def opt_keywords = []
|
|
314
|
+
def rest_keywords = nil
|
|
315
|
+
def no_keywords = @kind == :struct
|
|
316
|
+
|
|
317
|
+
def define0(genv)
|
|
318
|
+
mod = genv.resolve_cpath(@static_cpath)
|
|
319
|
+
# add_module_def internally calls get_const(name).add_def(self)
|
|
320
|
+
cdef = mod.add_module_def(genv, self)
|
|
321
|
+
genv.resolve_cpath(struct_base_cpath).add_module_def(genv, self)
|
|
322
|
+
@members.each do |member|
|
|
323
|
+
ive = genv.resolve_ivar(struct_base_cpath, false, member)
|
|
324
|
+
ive.add_def(self)
|
|
325
|
+
end
|
|
326
|
+
@block_body.define(genv) if @block_body
|
|
327
|
+
cdef
|
|
328
|
+
end
|
|
329
|
+
|
|
330
|
+
def define_copy(genv)
|
|
331
|
+
mod = genv.resolve_cpath(@static_cpath)
|
|
332
|
+
mod.add_module_def(genv, self)
|
|
333
|
+
mod.remove_module_def(genv, @prev_node)
|
|
334
|
+
base = genv.resolve_cpath(struct_base_cpath)
|
|
335
|
+
base.add_module_def(genv, self)
|
|
336
|
+
base.remove_module_def(genv, @prev_node)
|
|
337
|
+
@members.each do |member|
|
|
338
|
+
ive = genv.resolve_ivar(struct_base_cpath, false, member)
|
|
339
|
+
ive.add_def(self)
|
|
340
|
+
ive.remove_def(@prev_node)
|
|
341
|
+
end
|
|
342
|
+
super(genv)
|
|
343
|
+
end
|
|
344
|
+
|
|
345
|
+
def undefine0(genv)
|
|
346
|
+
mod = genv.resolve_cpath(@static_cpath)
|
|
347
|
+
mod.remove_module_def(genv, self)
|
|
348
|
+
genv.resolve_cpath(struct_base_cpath).remove_module_def(genv, self)
|
|
349
|
+
@members.each do |member|
|
|
350
|
+
ive = genv.resolve_ivar(struct_base_cpath, false, member)
|
|
351
|
+
ive.remove_def(self)
|
|
352
|
+
end
|
|
353
|
+
@block_body.undefine(genv) if @block_body
|
|
354
|
+
end
|
|
355
|
+
|
|
356
|
+
def install0(genv)
|
|
357
|
+
# Register the class singleton type as the constant value
|
|
358
|
+
mod_val = Source.new(Type::Singleton.new(genv, genv.resolve_cpath(@static_cpath)))
|
|
359
|
+
if @static_cpath
|
|
360
|
+
@changes.add_edge(genv, mod_val, @static_ret.vtx)
|
|
361
|
+
end
|
|
362
|
+
|
|
363
|
+
cpath = struct_base_cpath
|
|
364
|
+
@members.each do |member|
|
|
365
|
+
# Use bare `:member` (not `:@member`) so the slot can't collide with a
|
|
366
|
+
# user-written @member ivar — Struct/Data fields are not real ivars.
|
|
367
|
+
ivar_box = @changes.add_ivar_read_box(genv, cpath, false, member)
|
|
368
|
+
ret_box = @changes.add_escape_box(genv, ivar_box.ret)
|
|
369
|
+
@changes.add_method_def_box(genv, cpath, false, member, FormalArguments::Empty, [ret_box])
|
|
370
|
+
|
|
371
|
+
if @kind == :struct
|
|
372
|
+
# attr_writer (Struct only, Data is frozen)
|
|
373
|
+
ive = genv.resolve_ivar(cpath, false, member)
|
|
374
|
+
vtx = Vertex.new(self)
|
|
375
|
+
@changes.add_edge(genv, vtx, ive.vtx)
|
|
376
|
+
writer_ret = @changes.add_escape_box(genv, vtx)
|
|
377
|
+
f_args = FormalArguments.new([vtx], [], nil, [], [], [], nil, nil)
|
|
378
|
+
@changes.add_method_def_box(genv, cpath, false, :"#{ member }=", f_args, [writer_ret])
|
|
379
|
+
end
|
|
380
|
+
end
|
|
381
|
+
|
|
382
|
+
# initialize
|
|
383
|
+
init_vtxs = @members.map do |member|
|
|
384
|
+
ive = genv.resolve_ivar(cpath, false, member)
|
|
385
|
+
vtx = Vertex.new(self)
|
|
386
|
+
@changes.add_edge(genv, vtx, ive.vtx)
|
|
387
|
+
vtx
|
|
388
|
+
end
|
|
389
|
+
init_ret = @changes.add_escape_box(genv, Source.new(genv.nil_type))
|
|
390
|
+
if @kind == :struct
|
|
391
|
+
init_f_args = FormalArguments.new(init_vtxs, [], nil, [], [], [], nil, nil)
|
|
392
|
+
else
|
|
393
|
+
# Data.define uses keyword arguments
|
|
394
|
+
init_f_args = FormalArguments.new([], [], nil, [], init_vtxs, [], nil, nil)
|
|
395
|
+
end
|
|
396
|
+
@changes.add_method_def_box(genv, cpath, false, :initialize, init_f_args, [init_ret])
|
|
397
|
+
|
|
398
|
+
# Struct.[] is an alias for Struct.new
|
|
399
|
+
if @kind == :struct
|
|
400
|
+
# Struct.[] builds the struct class itself, not the base class
|
|
401
|
+
self_ret = @changes.add_escape_box(genv, Source.new(Type::Instance.new(genv, genv.resolve_cpath(@static_cpath), [])))
|
|
402
|
+
@changes.add_method_def_box(genv, cpath, true, :[], init_f_args, [self_ret])
|
|
403
|
+
end
|
|
404
|
+
|
|
405
|
+
# Install block body (additional method definitions)
|
|
406
|
+
if @block_body
|
|
407
|
+
@block_body.lenv.locals[:"*self"] = @block_body.lenv.cref.get_self(genv)
|
|
408
|
+
@block_body.install(genv)
|
|
409
|
+
end
|
|
410
|
+
|
|
411
|
+
mod_val
|
|
412
|
+
end
|
|
413
|
+
end
|
|
149
414
|
end
|
|
150
415
|
end
|