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
|
@@ -46,7 +46,7 @@ module TypeProf::Core
|
|
|
46
46
|
def initialize(raw_node, rhs, lenv)
|
|
47
47
|
super(raw_node, lenv)
|
|
48
48
|
@var = raw_node.name
|
|
49
|
-
@var_code_range =
|
|
49
|
+
@var_code_range = lenv.code_range_from_node(raw_node.respond_to?(:name_loc) ? raw_node.name_loc : raw_node)
|
|
50
50
|
@rhs = rhs
|
|
51
51
|
end
|
|
52
52
|
|
|
@@ -63,11 +63,24 @@ module TypeProf::Core
|
|
|
63
63
|
val
|
|
64
64
|
end
|
|
65
65
|
|
|
66
|
+
def install_pattern0(genv, subject)
|
|
67
|
+
install0(genv)
|
|
68
|
+
@changes.add_edge(genv, subject, @rhs.ret)
|
|
69
|
+
subject
|
|
70
|
+
end
|
|
71
|
+
|
|
66
72
|
def retrieve_at(pos, &blk)
|
|
67
73
|
yield self if @var_code_range && @var_code_range.include?(pos)
|
|
68
74
|
super(pos, &blk)
|
|
69
75
|
end
|
|
70
76
|
|
|
77
|
+
def narrowings
|
|
78
|
+
@narrowings ||= [
|
|
79
|
+
Narrowing.new({ @var => Narrowing::NilConstraint.new(false) }),
|
|
80
|
+
Narrowing.new({ @var => Narrowing::NilConstraint.new(true) }),
|
|
81
|
+
]
|
|
82
|
+
end
|
|
83
|
+
|
|
71
84
|
def modified_vars(tbl, vars)
|
|
72
85
|
vars << self.var if tbl.include?(self.var)
|
|
73
86
|
end
|
|
@@ -109,7 +122,7 @@ module TypeProf::Core
|
|
|
109
122
|
def initialize(raw_node, rhs, lenv)
|
|
110
123
|
super(raw_node, lenv)
|
|
111
124
|
@var = raw_node.name
|
|
112
|
-
@var_code_range =
|
|
125
|
+
@var_code_range = lenv.code_range_from_node(raw_node.respond_to?(:name_loc) ? raw_node.name_loc : raw_node)
|
|
113
126
|
@rhs = rhs
|
|
114
127
|
end
|
|
115
128
|
|
|
@@ -191,7 +204,7 @@ module TypeProf::Core
|
|
|
191
204
|
def initialize(raw_node, rhs, lenv)
|
|
192
205
|
super(raw_node, lenv)
|
|
193
206
|
@var = raw_node.name
|
|
194
|
-
@var_code_range =
|
|
207
|
+
@var_code_range = lenv.code_range_from_node(raw_node.respond_to?(:name_loc) ? raw_node.name_loc : raw_node)
|
|
195
208
|
@rhs = rhs
|
|
196
209
|
end
|
|
197
210
|
|
|
@@ -264,7 +277,7 @@ module TypeProf::Core
|
|
|
264
277
|
def initialize(raw_node, rhs, lenv)
|
|
265
278
|
super(raw_node, lenv)
|
|
266
279
|
@var = raw_node.name
|
|
267
|
-
@var_code_range =
|
|
280
|
+
@var_code_range = lenv.code_range_from_node(raw_node.respond_to?(:name_loc) ? raw_node.name_loc : raw_node)
|
|
268
281
|
@rhs = rhs
|
|
269
282
|
end
|
|
270
283
|
|
data/lib/typeprof/core/ast.rb
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
module TypeProf::Core
|
|
2
2
|
class AST
|
|
3
|
-
def self.parse_rb(path, src)
|
|
3
|
+
def self.parse_rb(path, src, position_encoding)
|
|
4
4
|
result = Prism.parse(src)
|
|
5
5
|
|
|
6
6
|
return nil unless result.errors.empty?
|
|
@@ -10,19 +10,58 @@ module TypeProf::Core
|
|
|
10
10
|
|
|
11
11
|
raise unless raw_scope.type == :program_node
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
prism_source = result.source
|
|
14
|
+
file_context = FileContext.new(path, position_encoding, prism_source, result.comments)
|
|
14
15
|
|
|
15
16
|
cref = CRef::Toplevel
|
|
16
|
-
lenv = LocalEnv.new(
|
|
17
|
+
lenv = LocalEnv.new(file_context, cref, {}, [])
|
|
17
18
|
|
|
18
|
-
|
|
19
|
+
ignore_ranges = collect_ignore_ranges(result)
|
|
20
|
+
ProgramNode.new(raw_scope, lenv, ignore_ranges: ignore_ranges)
|
|
19
21
|
end
|
|
20
22
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
+
# Collect line ranges marked with `# typeprof:ignore` comments.
|
|
24
|
+
# Each range is suppressed in ProgramNode#each_diagnostic.
|
|
25
|
+
#
|
|
26
|
+
# Inline form (suppresses the line containing the comment):
|
|
27
|
+
# foo(1, 2) # typeprof:ignore
|
|
28
|
+
#
|
|
29
|
+
# Block form (suppresses lines between :start and :end):
|
|
30
|
+
# # typeprof:ignore:start
|
|
31
|
+
# foo(1, 2)
|
|
32
|
+
# # typeprof:ignore:end
|
|
33
|
+
#
|
|
34
|
+
# An unmatched `:start` extends to the end of the file.
|
|
35
|
+
IGNORE_RE = /\A#\s*typeprof:ignore\s*\z/
|
|
36
|
+
IGNORE_START_RE = /\A#\s*typeprof:ignore:start\s*\z/
|
|
37
|
+
IGNORE_END_RE = /\A#\s*typeprof:ignore:end\s*\z/
|
|
38
|
+
def self.collect_ignore_ranges(prism_result)
|
|
39
|
+
ranges = []
|
|
40
|
+
start_line = nil
|
|
41
|
+
prism_result.comments.each do |c|
|
|
42
|
+
text = c.location.slice
|
|
43
|
+
line = c.location.start_line
|
|
44
|
+
if text.match?(IGNORE_START_RE)
|
|
45
|
+
start_line ||= line
|
|
46
|
+
elsif text.match?(IGNORE_END_RE)
|
|
47
|
+
if start_line
|
|
48
|
+
ranges << (start_line..line)
|
|
49
|
+
start_line = nil
|
|
50
|
+
end
|
|
51
|
+
elsif text.match?(IGNORE_RE)
|
|
52
|
+
ranges << (line..line)
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
ranges << (start_line..Float::INFINITY) if start_line
|
|
56
|
+
ranges
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
#: (untyped, TypeProf::Core::LocalEnv, ?bool, ?bool) -> TypeProf::Core::AST::Node
|
|
60
|
+
def self.create_node(raw_node, lenv, use_result = true, allow_meta = false)
|
|
23
61
|
while true
|
|
24
62
|
case raw_node.type
|
|
25
63
|
when :parentheses_node
|
|
64
|
+
return DummyNilNode.new(lenv.code_range_from_node(raw_node), lenv) if raw_node.body.nil?
|
|
26
65
|
raw_node = raw_node.body
|
|
27
66
|
when :implicit_node
|
|
28
67
|
raw_node = raw_node.value
|
|
@@ -64,7 +103,13 @@ module TypeProf::Core
|
|
|
64
103
|
when :constant_read_node, :constant_path_node
|
|
65
104
|
ConstantReadNode.new(raw_node, lenv)
|
|
66
105
|
when :constant_write_node, :constant_path_write_node
|
|
67
|
-
|
|
106
|
+
if (members = detect_struct_new(raw_node.value))
|
|
107
|
+
StructNewNode.new(raw_node, members, :struct, lenv)
|
|
108
|
+
elsif (members = detect_data_define(raw_node.value))
|
|
109
|
+
StructNewNode.new(raw_node, members, :data, lenv)
|
|
110
|
+
else
|
|
111
|
+
ConstantWriteNode.new(raw_node, AST.create_node(raw_node.value, lenv), lenv)
|
|
112
|
+
end
|
|
68
113
|
when :constant_operator_write_node
|
|
69
114
|
read = ConstantReadNode.new(raw_node, lenv)
|
|
70
115
|
rhs = OperatorNode.new(raw_node, read, lenv)
|
|
@@ -132,6 +177,7 @@ module TypeProf::Core
|
|
|
132
177
|
when :class_variable_operator_write_node
|
|
133
178
|
read = ClassVariableReadNode.new(raw_node, lenv)
|
|
134
179
|
rhs = OperatorNode.new(raw_node, read, lenv)
|
|
180
|
+
ClassVariableWriteNode.new(raw_node, rhs, lenv)
|
|
135
181
|
when :class_variable_or_write_node
|
|
136
182
|
read = ClassVariableReadNode.new(raw_node, lenv)
|
|
137
183
|
rhs = OrNode.new(raw_node, read, raw_node.value, lenv)
|
|
@@ -233,15 +279,22 @@ module TypeProf::Core
|
|
|
233
279
|
when :forwarding_super_node then ForwardingSuperNode.new(raw_node, lenv)
|
|
234
280
|
when :yield_node then YieldNode.new(raw_node, lenv)
|
|
235
281
|
when :call_node
|
|
236
|
-
if !raw_node.receiver
|
|
237
|
-
# TODO: handle them only when it is directly under class or module
|
|
282
|
+
if allow_meta && !raw_node.receiver && !lenv.cref.mid && [:class, :metaclass].include?(lenv.cref.scope_level)
|
|
238
283
|
case raw_node.name
|
|
239
284
|
when :include
|
|
240
285
|
return IncludeMetaNode.new(raw_node, lenv)
|
|
286
|
+
when :extend
|
|
287
|
+
return ExtendMetaNode.new(raw_node, lenv)
|
|
241
288
|
when :attr_reader
|
|
242
289
|
return AttrReaderMetaNode.new(raw_node, lenv)
|
|
290
|
+
when :attr_writer
|
|
291
|
+
return AttrWriterMetaNode.new(raw_node, lenv)
|
|
243
292
|
when :attr_accessor
|
|
244
293
|
return AttrAccessorMetaNode.new(raw_node, lenv)
|
|
294
|
+
when :module_function
|
|
295
|
+
if raw_node.arguments.nil?
|
|
296
|
+
return ModuleFunctionMetaNode.new(raw_node, lenv)
|
|
297
|
+
end
|
|
245
298
|
end
|
|
246
299
|
end
|
|
247
300
|
CallNode.new(raw_node, lenv)
|
|
@@ -252,7 +305,7 @@ module TypeProf::Core
|
|
|
252
305
|
end
|
|
253
306
|
|
|
254
307
|
def self.create_target_node(raw_node, lenv)
|
|
255
|
-
dummy_node = DummyRHSNode.new(
|
|
308
|
+
dummy_node = DummyRHSNode.new(lenv.code_range_from_node(raw_node.location), lenv)
|
|
256
309
|
case raw_node.type
|
|
257
310
|
when :local_variable_target_node
|
|
258
311
|
LocalVariableWriteNode.new(raw_node, dummy_node, lenv)
|
|
@@ -305,7 +358,7 @@ module TypeProf::Core
|
|
|
305
358
|
when :pinned_expression_node then PinnedPatternNode.new(raw_node, lenv)
|
|
306
359
|
|
|
307
360
|
when :local_variable_target_node
|
|
308
|
-
dummy_node = DummyRHSNode.new(
|
|
361
|
+
dummy_node = DummyRHSNode.new(lenv.code_range_from_node(raw_node.location), lenv)
|
|
309
362
|
LocalVariableWriteNode.new(raw_node, dummy_node, lenv)
|
|
310
363
|
|
|
311
364
|
when :constant_read_node, :constant_path_node
|
|
@@ -364,11 +417,12 @@ module TypeProf::Core
|
|
|
364
417
|
return cpath + names.reverse if cpath
|
|
365
418
|
end
|
|
366
419
|
|
|
367
|
-
def self.parse_rbs(path, src)
|
|
420
|
+
def self.parse_rbs(path, src, position_encoding)
|
|
368
421
|
_buffer, _directives, raw_decls = RBS::Parser.parse_signature(src)
|
|
369
422
|
|
|
370
423
|
cref = CRef::Toplevel
|
|
371
|
-
|
|
424
|
+
file_context = FileContext.new(path, position_encoding)
|
|
425
|
+
lenv = LocalEnv.new(file_context, cref, {}, [])
|
|
372
426
|
|
|
373
427
|
raw_decls.map do |raw_decl|
|
|
374
428
|
AST.create_rbs_decl(raw_decl, lenv)
|
|
@@ -385,7 +439,10 @@ module TypeProf::Core
|
|
|
385
439
|
SigInterfaceNode.new(raw_decl, lenv)
|
|
386
440
|
when RBS::AST::Declarations::Constant
|
|
387
441
|
SigConstNode.new(raw_decl, lenv)
|
|
388
|
-
when RBS::AST::Declarations::
|
|
442
|
+
when RBS::AST::Declarations::ClassAlias
|
|
443
|
+
SigClassAliasNode.new(raw_decl, lenv)
|
|
444
|
+
when RBS::AST::Declarations::ModuleAlias
|
|
445
|
+
SigModuleAliasNode.new(raw_decl, lenv)
|
|
389
446
|
when RBS::AST::Declarations::TypeAlias
|
|
390
447
|
SigTypeAliasNode.new(raw_decl, lenv)
|
|
391
448
|
# TODO: check
|
|
@@ -405,6 +462,7 @@ module TypeProf::Core
|
|
|
405
462
|
when RBS::AST::Members::Prepend
|
|
406
463
|
SigPrependNode.new(raw_decl, lenv)
|
|
407
464
|
when RBS::AST::Members::Extend
|
|
465
|
+
SigExtendNode.new(raw_decl, lenv)
|
|
408
466
|
when RBS::AST::Members::Public
|
|
409
467
|
when RBS::AST::Members::Private
|
|
410
468
|
when RBS::AST::Members::Alias
|
|
@@ -481,5 +539,31 @@ module TypeProf::Core
|
|
|
481
539
|
raise "unknown RBS type: #{ raw_decl.class }"
|
|
482
540
|
end
|
|
483
541
|
end
|
|
542
|
+
|
|
543
|
+
def self.detect_struct_new(raw_value)
|
|
544
|
+
return nil unless raw_value.type == :call_node
|
|
545
|
+
return nil unless raw_value.name == :new
|
|
546
|
+
recv = raw_value.receiver
|
|
547
|
+
return nil unless recv&.type == :constant_read_node && recv.name == :Struct
|
|
548
|
+
extract_symbol_args(raw_value)
|
|
549
|
+
end
|
|
550
|
+
|
|
551
|
+
def self.detect_data_define(raw_value)
|
|
552
|
+
return nil unless raw_value.type == :call_node
|
|
553
|
+
return nil unless raw_value.name == :define
|
|
554
|
+
recv = raw_value.receiver
|
|
555
|
+
return nil unless recv&.type == :constant_read_node && recv.name == :Data
|
|
556
|
+
extract_symbol_args(raw_value)
|
|
557
|
+
end
|
|
558
|
+
|
|
559
|
+
def self.extract_symbol_args(raw_call)
|
|
560
|
+
return nil unless raw_call.arguments
|
|
561
|
+
members = []
|
|
562
|
+
raw_call.arguments.arguments.each do |arg|
|
|
563
|
+
return nil unless arg.type == :symbol_node
|
|
564
|
+
members << arg.value.to_sym
|
|
565
|
+
end
|
|
566
|
+
members
|
|
567
|
+
end
|
|
484
568
|
end
|
|
485
569
|
end
|
|
@@ -69,6 +69,20 @@ module TypeProf::Core
|
|
|
69
69
|
else
|
|
70
70
|
false
|
|
71
71
|
end
|
|
72
|
+
elsif a_args.positionals.size == 3
|
|
73
|
+
# ary[start, len] = val
|
|
74
|
+
# Use SplatBox to extract element types from the assigned value
|
|
75
|
+
elem_vtx = case ty
|
|
76
|
+
when Type::Array
|
|
77
|
+
ty.get_elem(@genv)
|
|
78
|
+
when Type::Instance
|
|
79
|
+
ty.mod == @genv.mod_ary ? ty.args[0] : nil
|
|
80
|
+
end
|
|
81
|
+
return false unless elem_vtx
|
|
82
|
+
val = a_args.positionals[2]
|
|
83
|
+
splat_ret = changes.add_splat_box(@genv, val).ret
|
|
84
|
+
changes.add_edge(@genv, splat_ret, elem_vtx)
|
|
85
|
+
true
|
|
72
86
|
else
|
|
73
87
|
false
|
|
74
88
|
end
|
|
@@ -90,7 +104,7 @@ module TypeProf::Core
|
|
|
90
104
|
def hash_aref(changes, node, ty, a_args, ret)
|
|
91
105
|
if a_args.positionals.size == 1
|
|
92
106
|
case ty
|
|
93
|
-
when Type::Hash
|
|
107
|
+
when Type::Hash
|
|
94
108
|
idx = node.positional_args[0]
|
|
95
109
|
idx = idx.is_a?(AST::SymbolNode) ? idx.lit : nil
|
|
96
110
|
value = ty.get_value(idx)
|
|
@@ -101,6 +115,20 @@ module TypeProf::Core
|
|
|
101
115
|
changes.add_edge(@genv, Source.new(), ret)
|
|
102
116
|
end
|
|
103
117
|
true
|
|
118
|
+
when Type::Record
|
|
119
|
+
idx = node.positional_args[0]
|
|
120
|
+
idx = idx.is_a?(AST::SymbolNode) ? idx.lit : nil
|
|
121
|
+
value = ty.get_value(idx)
|
|
122
|
+
if value
|
|
123
|
+
changes.add_edge(@genv, value, ret)
|
|
124
|
+
else
|
|
125
|
+
changes.add_edge(@genv, Source.new(@genv.nil_type), ret)
|
|
126
|
+
end
|
|
127
|
+
# Symbol variable access - add nil possibility
|
|
128
|
+
if idx.nil?
|
|
129
|
+
changes.add_edge(@genv, Source.new(@genv.nil_type), ret)
|
|
130
|
+
end
|
|
131
|
+
true
|
|
104
132
|
else
|
|
105
133
|
false
|
|
106
134
|
end
|
|
@@ -125,6 +153,15 @@ module TypeProf::Core
|
|
|
125
153
|
end
|
|
126
154
|
changes.add_edge(@genv, val, ret)
|
|
127
155
|
true
|
|
156
|
+
when Type::Record
|
|
157
|
+
val = a_args.positionals[1]
|
|
158
|
+
idx = node.positional_args[0]
|
|
159
|
+
if idx.is_a?(AST::SymbolNode)
|
|
160
|
+
field_vtx = ty.get_value(idx.lit)
|
|
161
|
+
changes.add_edge(@genv, val, field_vtx) if field_vtx
|
|
162
|
+
end
|
|
163
|
+
changes.add_edge(@genv, val, ret)
|
|
164
|
+
true
|
|
128
165
|
else
|
|
129
166
|
false
|
|
130
167
|
end
|
|
@@ -133,19 +170,154 @@ module TypeProf::Core
|
|
|
133
170
|
end
|
|
134
171
|
end
|
|
135
172
|
|
|
173
|
+
def object_method(changes, node, ty, a_args, ret)
|
|
174
|
+
if a_args.positionals.size == 1
|
|
175
|
+
sym_node = node.positional_args[0]
|
|
176
|
+
if sym_node.is_a?(AST::SymbolNode)
|
|
177
|
+
method_ty = Type::Method.new(@genv, ty, sym_node.lit)
|
|
178
|
+
changes.add_edge(@genv, Source.new(method_ty), ret)
|
|
179
|
+
return true
|
|
180
|
+
end
|
|
181
|
+
end
|
|
182
|
+
false
|
|
183
|
+
end
|
|
184
|
+
|
|
185
|
+
def method_call(changes, node, ty, a_args, ret)
|
|
186
|
+
case ty
|
|
187
|
+
when Type::Method
|
|
188
|
+
recv = Source.new(ty.recv_ty)
|
|
189
|
+
box = changes.add_method_call_box(@genv, recv, ty.mid, a_args, false)
|
|
190
|
+
changes.add_edge(@genv, box.ret, ret)
|
|
191
|
+
true
|
|
192
|
+
else
|
|
193
|
+
false
|
|
194
|
+
end
|
|
195
|
+
end
|
|
196
|
+
|
|
197
|
+
def kernel_send(changes, node, ty, a_args, ret)
|
|
198
|
+
return false if a_args.positionals.empty?
|
|
199
|
+
|
|
200
|
+
if a_args.splat_flags[0]
|
|
201
|
+
# send(*array) case: extract method name and args from array elements
|
|
202
|
+
splat_vtx = a_args.positionals[0]
|
|
203
|
+
changes.add_edge(@genv, splat_vtx, changes.target)
|
|
204
|
+
|
|
205
|
+
rest_positionals = a_args.positionals[1..]
|
|
206
|
+
rest_splat_flags = a_args.splat_flags[1..]
|
|
207
|
+
|
|
208
|
+
splat_vtx.each_type do |ary_ty|
|
|
209
|
+
next unless ary_ty.is_a?(Type::Array)
|
|
210
|
+
|
|
211
|
+
if ary_ty.elems && ary_ty.elems.size >= 1
|
|
212
|
+
# Tuple: use per-element precision
|
|
213
|
+
method_name_vtx = ary_ty.elems[0]
|
|
214
|
+
changes.add_edge(@genv, method_name_vtx, changes.target)
|
|
215
|
+
|
|
216
|
+
elem_args = ary_ty.elems[1..] + rest_positionals
|
|
217
|
+
elem_flags = ::Array.new(ary_ty.elems.size - 1, false) + rest_splat_flags
|
|
218
|
+
send_a_args = ActualArguments.new(elem_args, elem_flags, a_args.keywords, a_args.block)
|
|
219
|
+
|
|
220
|
+
method_name_vtx.each_type do |sym_ty|
|
|
221
|
+
if sym_ty.is_a?(Type::Symbol)
|
|
222
|
+
recv = Source.new(ty)
|
|
223
|
+
box = changes.add_method_call_box(@genv, recv, sym_ty.sym, send_a_args, false)
|
|
224
|
+
changes.add_edge(@genv, box.ret, ret)
|
|
225
|
+
end
|
|
226
|
+
end
|
|
227
|
+
else
|
|
228
|
+
# Non-tuple array: use unified element type for method name
|
|
229
|
+
elem_vtx = ary_ty.get_elem(@genv)
|
|
230
|
+
next unless elem_vtx
|
|
231
|
+
changes.add_edge(@genv, elem_vtx, changes.target)
|
|
232
|
+
|
|
233
|
+
send_a_args = ActualArguments.new(rest_positionals, rest_splat_flags, a_args.keywords, a_args.block)
|
|
234
|
+
|
|
235
|
+
elem_vtx.each_type do |sym_ty|
|
|
236
|
+
if sym_ty.is_a?(Type::Symbol)
|
|
237
|
+
recv = Source.new(ty)
|
|
238
|
+
box = changes.add_method_call_box(@genv, recv, sym_ty.sym, send_a_args, false)
|
|
239
|
+
changes.add_edge(@genv, box.ret, ret)
|
|
240
|
+
end
|
|
241
|
+
end
|
|
242
|
+
end
|
|
243
|
+
end
|
|
244
|
+
else
|
|
245
|
+
# send(:sym, ...) case
|
|
246
|
+
changes.add_edge(@genv, a_args.positionals[0], changes.target)
|
|
247
|
+
send_a_args = ActualArguments.new(
|
|
248
|
+
a_args.positionals[1..],
|
|
249
|
+
a_args.splat_flags[1..],
|
|
250
|
+
a_args.keywords,
|
|
251
|
+
a_args.block,
|
|
252
|
+
)
|
|
253
|
+
a_args.positionals[0].each_type do |sym_ty|
|
|
254
|
+
if sym_ty.is_a?(Type::Symbol)
|
|
255
|
+
recv = Source.new(ty)
|
|
256
|
+
box = changes.add_method_call_box(@genv, recv, sym_ty.sym, send_a_args, false)
|
|
257
|
+
changes.add_edge(@genv, box.ret, ret)
|
|
258
|
+
end
|
|
259
|
+
end
|
|
260
|
+
end
|
|
261
|
+
true
|
|
262
|
+
end
|
|
263
|
+
|
|
264
|
+
def kernel_array(changes, node, ty, a_args, ret)
|
|
265
|
+
return false unless a_args.positionals.size == 1
|
|
266
|
+
|
|
267
|
+
arg_vtx = a_args.positionals[0]
|
|
268
|
+
elem_vtx = Vertex.new(node)
|
|
269
|
+
handled = false
|
|
270
|
+
needs_elem_wrap = false
|
|
271
|
+
|
|
272
|
+
arg_vtx.each_type do |arg_ty|
|
|
273
|
+
handled = true
|
|
274
|
+
case arg_ty
|
|
275
|
+
when Type::Instance
|
|
276
|
+
if arg_ty.mod == @genv.mod_range && arg_ty.args && !arg_ty.args.empty?
|
|
277
|
+
changes.add_edge(@genv, arg_ty.args[0], elem_vtx)
|
|
278
|
+
needs_elem_wrap = true
|
|
279
|
+
elsif arg_ty.mod == @genv.mod_ary
|
|
280
|
+
changes.add_edge(@genv, Source.new(arg_ty), ret)
|
|
281
|
+
else
|
|
282
|
+
changes.add_edge(@genv, Source.new(arg_ty), elem_vtx)
|
|
283
|
+
needs_elem_wrap = true
|
|
284
|
+
end
|
|
285
|
+
when Type::Array
|
|
286
|
+
changes.add_edge(@genv, Source.new(arg_ty), ret)
|
|
287
|
+
else
|
|
288
|
+
changes.add_edge(@genv, Source.new(arg_ty), elem_vtx)
|
|
289
|
+
needs_elem_wrap = true
|
|
290
|
+
end
|
|
291
|
+
end
|
|
292
|
+
|
|
293
|
+
return false unless handled
|
|
294
|
+
|
|
295
|
+
if needs_elem_wrap
|
|
296
|
+
ary_ty = @genv.gen_ary_type(elem_vtx)
|
|
297
|
+
changes.add_edge(@genv, Source.new(ary_ty), ret)
|
|
298
|
+
end
|
|
299
|
+
true
|
|
300
|
+
end
|
|
301
|
+
|
|
136
302
|
def deploy
|
|
137
|
-
|
|
138
|
-
class_new
|
|
139
|
-
object_class
|
|
140
|
-
proc_call
|
|
141
|
-
array_aref
|
|
142
|
-
array_aset
|
|
143
|
-
array_push
|
|
144
|
-
hash_aref
|
|
145
|
-
hash_aset
|
|
146
|
-
|
|
303
|
+
[
|
|
304
|
+
[method(:class_new), [:Class], false, :new],
|
|
305
|
+
[method(:object_class), [:Object], false, :class],
|
|
306
|
+
[method(:proc_call), [:Proc], false, :call],
|
|
307
|
+
[method(:array_aref), [:Array], false, :[]],
|
|
308
|
+
[method(:array_aset), [:Array], false, :[]=],
|
|
309
|
+
[method(:array_push), [:Array], false, :<<],
|
|
310
|
+
[method(:hash_aref), [:Hash], false, :[]],
|
|
311
|
+
[method(:hash_aset), [:Hash], false, :[]=],
|
|
312
|
+
[method(:object_method), [:Kernel], false, :method],
|
|
313
|
+
[method(:method_call), [:Method], false, :call],
|
|
314
|
+
[method(:kernel_send), [:BasicObject], false, :__send__],
|
|
315
|
+
[method(:kernel_send), [:Kernel], false, :public_send],
|
|
316
|
+
[method(:kernel_send), [:Kernel], false, :send],
|
|
317
|
+
[method(:kernel_array), [:Kernel], false, :Array],
|
|
318
|
+
].each do |builtin, cpath, singleton, mid|
|
|
147
319
|
me = @genv.resolve_method(cpath, singleton, mid)
|
|
148
|
-
me.builtin =
|
|
320
|
+
me.builtin = builtin
|
|
149
321
|
end
|
|
150
322
|
end
|
|
151
323
|
end
|