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
|
@@ -41,6 +41,40 @@ module TypeProf::Core
|
|
|
41
41
|
ActualArguments.new(positionals, splat_flags, keywords, block)
|
|
42
42
|
end
|
|
43
43
|
|
|
44
|
+
def with_keywords_as_last_positional_hash
|
|
45
|
+
return self unless @keywords
|
|
46
|
+
|
|
47
|
+
ActualArguments.new(
|
|
48
|
+
@positionals + [@keywords],
|
|
49
|
+
@splat_flags + [false],
|
|
50
|
+
nil,
|
|
51
|
+
@block,
|
|
52
|
+
)
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def prepend_positionals(positionals, splat_flags)
|
|
56
|
+
return self if positionals.empty?
|
|
57
|
+
|
|
58
|
+
ActualArguments.new(positionals + @positionals, splat_flags + @splat_flags, @keywords, @block)
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def with_keywords(keywords)
|
|
62
|
+
ActualArguments.new(@positionals, @splat_flags, keywords, @block)
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def with_block(block, omittable: false)
|
|
66
|
+
ActualArguments.new(@positionals, @splat_flags, @keywords, block)
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def add_box_edges(genv, box)
|
|
70
|
+
@keywords.add_edge(genv, box) if @keywords
|
|
71
|
+
@block.add_edge(genv, box) if @block
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def normalize_for_method_call(_genv)
|
|
75
|
+
self
|
|
76
|
+
end
|
|
77
|
+
|
|
44
78
|
def get_rest_args(genv, changes, start_rest, end_rest)
|
|
45
79
|
vtxs = []
|
|
46
80
|
|
|
@@ -69,6 +103,9 @@ module TypeProf::Core
|
|
|
69
103
|
case ty
|
|
70
104
|
when Type::Hash
|
|
71
105
|
changes.add_edge(genv, ty.get_value(name), vtx)
|
|
106
|
+
when Type::Record
|
|
107
|
+
field_vtx = ty.get_value(name)
|
|
108
|
+
changes.add_edge(genv, field_vtx, vtx) if field_vtx
|
|
72
109
|
when Type::Instance
|
|
73
110
|
if ty.mod == genv.mod_hash
|
|
74
111
|
changes.add_edge(genv, ty.args[1], vtx)
|
|
@@ -81,6 +118,311 @@ module TypeProf::Core
|
|
|
81
118
|
end
|
|
82
119
|
end
|
|
83
120
|
|
|
121
|
+
class ForwardingActualArguments < ActualArguments
|
|
122
|
+
def initialize(positionals, splat_flags, keywords, block, positionals_omittable, keywords_omittable, block_omittable, activation, activation_required)
|
|
123
|
+
super(positionals, splat_flags, keywords, block)
|
|
124
|
+
@positionals_omittable = positionals_omittable
|
|
125
|
+
@keywords_omittable = keywords_omittable
|
|
126
|
+
@block_omittable = block_omittable
|
|
127
|
+
@activation = activation
|
|
128
|
+
@activation_required = activation_required
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
attr_reader :positionals_omittable, :keywords_omittable, :block_omittable
|
|
132
|
+
|
|
133
|
+
def new_vertexes(genv, node)
|
|
134
|
+
positionals = @positionals.map {|arg| arg.new_vertex(genv, node) }
|
|
135
|
+
splat_flags = @splat_flags
|
|
136
|
+
keywords = @keywords ? @keywords.new_vertex(genv, node) : nil
|
|
137
|
+
block = @block ? @block.new_vertex(genv, node) : nil
|
|
138
|
+
activation = @activation.new_vertex(genv, node)
|
|
139
|
+
ForwardingActualArguments.new(positionals, splat_flags, keywords, block, @positionals_omittable, @keywords_omittable, @block_omittable, activation, @activation_required)
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
def with_keywords_as_last_positional_hash
|
|
143
|
+
return self unless @keywords
|
|
144
|
+
|
|
145
|
+
ForwardingActualArguments.new(
|
|
146
|
+
@positionals + [@keywords],
|
|
147
|
+
@splat_flags + [false],
|
|
148
|
+
nil,
|
|
149
|
+
@block,
|
|
150
|
+
@positionals_omittable + [false],
|
|
151
|
+
false,
|
|
152
|
+
@block_omittable,
|
|
153
|
+
@activation,
|
|
154
|
+
@activation_required,
|
|
155
|
+
)
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
def prepend_positionals(positionals, splat_flags)
|
|
159
|
+
return self if positionals.empty?
|
|
160
|
+
|
|
161
|
+
ForwardingActualArguments.new(
|
|
162
|
+
positionals + @positionals,
|
|
163
|
+
splat_flags + @splat_flags,
|
|
164
|
+
@keywords,
|
|
165
|
+
@block,
|
|
166
|
+
::Array.new(positionals.size, false) + @positionals_omittable,
|
|
167
|
+
@keywords_omittable,
|
|
168
|
+
@block_omittable,
|
|
169
|
+
@activation,
|
|
170
|
+
@activation_required,
|
|
171
|
+
)
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
def with_keywords(keywords, keywords_omittable: false)
|
|
175
|
+
ForwardingActualArguments.new(
|
|
176
|
+
@positionals,
|
|
177
|
+
@splat_flags,
|
|
178
|
+
keywords,
|
|
179
|
+
@block,
|
|
180
|
+
@positionals_omittable,
|
|
181
|
+
keywords_omittable,
|
|
182
|
+
@block_omittable,
|
|
183
|
+
@activation,
|
|
184
|
+
@activation_required,
|
|
185
|
+
)
|
|
186
|
+
end
|
|
187
|
+
|
|
188
|
+
def with_block(block, omittable: false)
|
|
189
|
+
ForwardingActualArguments.new(
|
|
190
|
+
@positionals,
|
|
191
|
+
@splat_flags,
|
|
192
|
+
@keywords,
|
|
193
|
+
block,
|
|
194
|
+
@positionals_omittable,
|
|
195
|
+
@keywords_omittable,
|
|
196
|
+
omittable,
|
|
197
|
+
@activation,
|
|
198
|
+
@activation_required,
|
|
199
|
+
)
|
|
200
|
+
end
|
|
201
|
+
|
|
202
|
+
def add_box_edges(genv, box)
|
|
203
|
+
@activation.add_edge(genv, box)
|
|
204
|
+
super
|
|
205
|
+
end
|
|
206
|
+
|
|
207
|
+
def normalize_for_method_call(genv)
|
|
208
|
+
if @activation.types.empty?
|
|
209
|
+
return nil if @activation_required
|
|
210
|
+
return self
|
|
211
|
+
end
|
|
212
|
+
|
|
213
|
+
positionals = []
|
|
214
|
+
splat_flags = []
|
|
215
|
+
|
|
216
|
+
@positionals.each_with_index do |arg, i|
|
|
217
|
+
unless @positionals_omittable[i] && @splat_flags[i] && empty_omittable_splat_argument?(genv, arg)
|
|
218
|
+
positionals << arg
|
|
219
|
+
splat_flags << @splat_flags[i]
|
|
220
|
+
end
|
|
221
|
+
end
|
|
222
|
+
|
|
223
|
+
keywords = @keywords
|
|
224
|
+
keywords = nil if @keywords_omittable && keywords && keywords.types.empty?
|
|
225
|
+
|
|
226
|
+
block = @block
|
|
227
|
+
block = nil if @block_omittable && block && block.types.empty?
|
|
228
|
+
|
|
229
|
+
ActualArguments.new(positionals, splat_flags, keywords, block)
|
|
230
|
+
end
|
|
231
|
+
|
|
232
|
+
private
|
|
233
|
+
|
|
234
|
+
def empty_omittable_splat_argument?(genv, arg)
|
|
235
|
+
empty = true
|
|
236
|
+
arg.each_type do |ty|
|
|
237
|
+
ty = ty.base_type(genv)
|
|
238
|
+
unless ty.is_a?(Type::Instance) && ty.mod == genv.mod_ary && ty.args[0] && ty.args[0].types.empty?
|
|
239
|
+
empty = false
|
|
240
|
+
break
|
|
241
|
+
end
|
|
242
|
+
end
|
|
243
|
+
empty
|
|
244
|
+
end
|
|
245
|
+
end
|
|
246
|
+
|
|
247
|
+
class ForwardingArguments
|
|
248
|
+
def initialize(req_positionals, opt_positionals, rest_positionals, post_positionals, req_keyword_pairs, opt_keyword_pairs, rest_keywords, block, activation)
|
|
249
|
+
@req_positionals = req_positionals
|
|
250
|
+
@opt_positionals = opt_positionals
|
|
251
|
+
@rest_positionals = rest_positionals
|
|
252
|
+
@post_positionals = post_positionals
|
|
253
|
+
@req_keyword_pairs = req_keyword_pairs
|
|
254
|
+
@opt_keyword_pairs = opt_keyword_pairs
|
|
255
|
+
@rest_keywords = rest_keywords
|
|
256
|
+
@block = block
|
|
257
|
+
@activation = activation
|
|
258
|
+
end
|
|
259
|
+
|
|
260
|
+
def to_actual_arguments(genv, changes, node, include_leading_positionals: true, activation_required: false)
|
|
261
|
+
positionals = include_leading_positionals ? @req_positionals.dup : []
|
|
262
|
+
splat_flags = ::Array.new(positionals.size, false)
|
|
263
|
+
positionals_omittable = ::Array.new(positionals.size, false)
|
|
264
|
+
|
|
265
|
+
@opt_positionals.each do |elem_vtx|
|
|
266
|
+
positionals << Source.new(genv.gen_ary_type(elem_vtx))
|
|
267
|
+
splat_flags << true
|
|
268
|
+
positionals_omittable << true
|
|
269
|
+
end
|
|
270
|
+
|
|
271
|
+
if @rest_positionals
|
|
272
|
+
positionals << Source.new(genv.gen_ary_type(@rest_positionals))
|
|
273
|
+
splat_flags << true
|
|
274
|
+
positionals_omittable << true
|
|
275
|
+
end
|
|
276
|
+
|
|
277
|
+
@post_positionals.each do |arg|
|
|
278
|
+
positionals << arg
|
|
279
|
+
splat_flags << false
|
|
280
|
+
positionals_omittable << false
|
|
281
|
+
end
|
|
282
|
+
|
|
283
|
+
keywords, keywords_omittable = build_keyword_args(genv, changes, node)
|
|
284
|
+
ForwardingActualArguments.new(positionals, splat_flags, keywords, @block, positionals_omittable, keywords_omittable, true, @activation, activation_required)
|
|
285
|
+
end
|
|
286
|
+
|
|
287
|
+
def accept_actual_arguments(genv, changes, a_args)
|
|
288
|
+
changes.add_edge(genv, Source.new(genv.true_type), @activation)
|
|
289
|
+
|
|
290
|
+
if a_args.splat_flags.any?
|
|
291
|
+
start_rest = [a_args.splat_flags.index(true), @req_positionals.size + @opt_positionals.size].min
|
|
292
|
+
end_rest = [a_args.splat_flags.rindex(true) + 1, a_args.positionals.size - @post_positionals.size].max
|
|
293
|
+
rest_vtxs = a_args.get_rest_args(genv, changes, start_rest, end_rest)
|
|
294
|
+
|
|
295
|
+
@req_positionals.each_with_index do |f_vtx, i|
|
|
296
|
+
if i < start_rest
|
|
297
|
+
changes.add_edge(genv, a_args.positionals[i], f_vtx)
|
|
298
|
+
else
|
|
299
|
+
rest_vtxs.each do |vtx|
|
|
300
|
+
changes.add_edge(genv, vtx, f_vtx)
|
|
301
|
+
end
|
|
302
|
+
end
|
|
303
|
+
end
|
|
304
|
+
|
|
305
|
+
@opt_positionals.each_with_index do |elem_vtx, i|
|
|
306
|
+
i += @req_positionals.size
|
|
307
|
+
if i < start_rest
|
|
308
|
+
changes.add_edge(genv, a_args.positionals[i], elem_vtx)
|
|
309
|
+
else
|
|
310
|
+
rest_vtxs.each do |vtx|
|
|
311
|
+
changes.add_edge(genv, vtx, elem_vtx)
|
|
312
|
+
end
|
|
313
|
+
end
|
|
314
|
+
end
|
|
315
|
+
|
|
316
|
+
@post_positionals.each_with_index do |f_vtx, i|
|
|
317
|
+
i += a_args.positionals.size - @post_positionals.size
|
|
318
|
+
if end_rest <= i
|
|
319
|
+
changes.add_edge(genv, a_args.positionals[i], f_vtx)
|
|
320
|
+
else
|
|
321
|
+
rest_vtxs.each do |vtx|
|
|
322
|
+
changes.add_edge(genv, vtx, f_vtx)
|
|
323
|
+
end
|
|
324
|
+
end
|
|
325
|
+
end
|
|
326
|
+
|
|
327
|
+
if @rest_positionals
|
|
328
|
+
rest_vtxs.each do |vtx|
|
|
329
|
+
changes.add_edge(genv, vtx, @rest_positionals)
|
|
330
|
+
end
|
|
331
|
+
end
|
|
332
|
+
|
|
333
|
+
else
|
|
334
|
+
@req_positionals.each_with_index do |f_vtx, i|
|
|
335
|
+
changes.add_edge(genv, a_args.positionals[i], f_vtx)
|
|
336
|
+
end
|
|
337
|
+
|
|
338
|
+
@post_positionals.each_with_index do |f_vtx, i|
|
|
339
|
+
i -= @post_positionals.size
|
|
340
|
+
changes.add_edge(genv, a_args.positionals[i], f_vtx)
|
|
341
|
+
end
|
|
342
|
+
|
|
343
|
+
start_rest = @req_positionals.size
|
|
344
|
+
end_rest = a_args.positionals.size - @post_positionals.size
|
|
345
|
+
i = 0
|
|
346
|
+
while i < @opt_positionals.size && start_rest < end_rest
|
|
347
|
+
changes.add_edge(genv, a_args.positionals[start_rest], @opt_positionals[i])
|
|
348
|
+
i += 1
|
|
349
|
+
start_rest += 1
|
|
350
|
+
end
|
|
351
|
+
|
|
352
|
+
if @rest_positionals
|
|
353
|
+
start_rest.upto(end_rest - 1) do |i|
|
|
354
|
+
changes.add_edge(genv, a_args.positionals[i], @rest_positionals)
|
|
355
|
+
end
|
|
356
|
+
end
|
|
357
|
+
end
|
|
358
|
+
|
|
359
|
+
changes.add_edge(genv, a_args.block, @block) if @block && a_args.block
|
|
360
|
+
|
|
361
|
+
return unless a_args.keywords
|
|
362
|
+
|
|
363
|
+
@req_keyword_pairs.each do |name, f_vtx|
|
|
364
|
+
changes.add_edge(genv, a_args.get_keyword_arg(genv, changes, name), f_vtx)
|
|
365
|
+
end
|
|
366
|
+
|
|
367
|
+
@opt_keyword_pairs.each do |name, f_vtx|
|
|
368
|
+
changes.add_edge(genv, a_args.get_keyword_arg(genv, changes, name), f_vtx)
|
|
369
|
+
end
|
|
370
|
+
|
|
371
|
+
if @rest_keywords
|
|
372
|
+
named_keys = @req_keyword_pairs.map(&:first) + @opt_keyword_pairs.map(&:first)
|
|
373
|
+
a_args.keywords.each_type do |kw_ty|
|
|
374
|
+
case kw_ty
|
|
375
|
+
when Type::Record
|
|
376
|
+
rest_fields = kw_ty.fields.reject {|key, _| named_keys.include?(key) }
|
|
377
|
+
base = kw_ty.base_type(genv)
|
|
378
|
+
rest_record = Type::Record.new(genv, rest_fields, base)
|
|
379
|
+
changes.add_edge(genv, Source.new(rest_record), @rest_keywords)
|
|
380
|
+
when Type::Hash, Type::Instance
|
|
381
|
+
changes.add_edge(genv, Source.new(kw_ty), @rest_keywords)
|
|
382
|
+
end
|
|
383
|
+
end
|
|
384
|
+
end
|
|
385
|
+
end
|
|
386
|
+
|
|
387
|
+
private
|
|
388
|
+
|
|
389
|
+
def build_keyword_args(genv, changes, node)
|
|
390
|
+
opt_keyword_pairs = @opt_keyword_pairs
|
|
391
|
+
|
|
392
|
+
if @req_keyword_pairs.empty? && opt_keyword_pairs.empty?
|
|
393
|
+
return @rest_keywords, !!@rest_keywords
|
|
394
|
+
end
|
|
395
|
+
|
|
396
|
+
unified_key = Vertex.new(node)
|
|
397
|
+
unified_val = Vertex.new(node)
|
|
398
|
+
literal_pairs = {}
|
|
399
|
+
|
|
400
|
+
@req_keyword_pairs.each do |name, vtx|
|
|
401
|
+
changes.add_edge(genv, Source.new(Type::Symbol.new(genv, name)), unified_key)
|
|
402
|
+
changes.add_edge(genv, vtx, unified_val)
|
|
403
|
+
literal_pairs[name] = vtx
|
|
404
|
+
end
|
|
405
|
+
|
|
406
|
+
opt_keyword_pairs.each do |name, vtx|
|
|
407
|
+
changes.add_edge(genv, Source.new(Type::Symbol.new(genv, name)), unified_key)
|
|
408
|
+
changes.add_edge(genv, vtx, unified_val)
|
|
409
|
+
literal_pairs[name] = vtx
|
|
410
|
+
end
|
|
411
|
+
|
|
412
|
+
base_hash_type = genv.gen_hash_type(unified_key, unified_val)
|
|
413
|
+
changes.add_hash_splat_box(genv, @rest_keywords, unified_key, unified_val) if @rest_keywords
|
|
414
|
+
|
|
415
|
+
if literal_pairs.empty?
|
|
416
|
+
[Source.new(base_hash_type), false]
|
|
417
|
+
elsif @rest_keywords
|
|
418
|
+
fallback = Source.new(Type::Record.new(genv, literal_pairs, base_hash_type))
|
|
419
|
+
[changes.add_keyword_merge_box(genv, @rest_keywords, literal_pairs, fallback).ret, false]
|
|
420
|
+
else
|
|
421
|
+
[Source.new(Type::Record.new(genv, literal_pairs, base_hash_type)), false]
|
|
422
|
+
end
|
|
423
|
+
end
|
|
424
|
+
end
|
|
425
|
+
|
|
84
426
|
class Block
|
|
85
427
|
#: (AST::CallBaseNode, Vertex, Array[Vertex], Array[EscapeBox]) -> void
|
|
86
428
|
def initialize(node, f_ary_arg, f_args, next_boxes)
|
|
@@ -94,12 +436,7 @@ module TypeProf::Core
|
|
|
94
436
|
|
|
95
437
|
def accept_args(genv, changes, caller_positionals)
|
|
96
438
|
if caller_positionals.size == 1 && @f_args.size >= 2
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
@f_args.each_with_index do |f_arg, i|
|
|
100
|
-
elem_vtx = changes.add_splat_box(genv, single_arg, i).ret
|
|
101
|
-
changes.add_edge(genv, elem_vtx, f_arg)
|
|
102
|
-
end
|
|
439
|
+
changes.add_edge(genv, caller_positionals[0], @f_ary_arg)
|
|
103
440
|
else
|
|
104
441
|
caller_positionals.zip(@f_args) do |a_arg, f_arg|
|
|
105
442
|
changes.add_edge(genv, a_arg, f_arg) if f_arg
|
|
@@ -2,60 +2,63 @@ module TypeProf::Core
|
|
|
2
2
|
class MethodEntity
|
|
3
3
|
def initialize
|
|
4
4
|
@builtin = nil
|
|
5
|
-
@decls = Set[]
|
|
6
|
-
@overloading_decls = Set[]
|
|
7
|
-
@defs = Set[]
|
|
8
|
-
@aliases = {}
|
|
9
|
-
@method_call_boxes = Set[]
|
|
10
5
|
end
|
|
11
6
|
|
|
12
|
-
attr_reader :decls, :defs, :aliases, :method_call_boxes
|
|
13
7
|
attr_accessor :builtin
|
|
14
8
|
|
|
9
|
+
def decls = @decls ||= Set.empty
|
|
10
|
+
def defs = @defs ||= Set.empty
|
|
11
|
+
def aliases = @aliases ||= {}
|
|
12
|
+
def method_call_boxes = @method_call_boxes ||= Set.empty
|
|
13
|
+
|
|
14
|
+
private def overloading_decls = @overloading_decls ||= Set.empty
|
|
15
|
+
|
|
15
16
|
def add_decl(decl)
|
|
16
17
|
if decl.overloading
|
|
17
|
-
|
|
18
|
+
overloading_decls << decl
|
|
18
19
|
else
|
|
19
|
-
|
|
20
|
+
decls << decl
|
|
20
21
|
end
|
|
21
22
|
end
|
|
22
23
|
|
|
23
24
|
def remove_decl(decl)
|
|
24
25
|
if decl.overloading
|
|
25
|
-
|
|
26
|
+
overloading_decls.delete(decl) || raise
|
|
26
27
|
else
|
|
27
|
-
|
|
28
|
+
decls.delete(decl) || raise
|
|
28
29
|
end
|
|
29
30
|
end
|
|
30
31
|
|
|
31
32
|
def add_def(mdef)
|
|
32
|
-
|
|
33
|
+
defs << mdef
|
|
33
34
|
self
|
|
34
35
|
end
|
|
35
36
|
|
|
36
37
|
def remove_def(mdef)
|
|
37
|
-
|
|
38
|
+
defs.delete(mdef) || raise
|
|
38
39
|
end
|
|
39
40
|
|
|
40
41
|
def add_alias(node, old_mid)
|
|
41
|
-
|
|
42
|
+
aliases[node] = old_mid
|
|
42
43
|
end
|
|
43
44
|
|
|
44
45
|
def remove_alias(node)
|
|
45
|
-
|
|
46
|
+
aliases.delete(node) || raise
|
|
46
47
|
end
|
|
47
48
|
|
|
48
49
|
def exist?
|
|
49
|
-
@builtin || !@decls.empty? || !@defs.empty?
|
|
50
|
+
@builtin || (@decls && !@decls.empty?) || (@defs && !@defs.empty?)
|
|
50
51
|
end
|
|
51
52
|
|
|
52
53
|
def add_run_all_mdefs(genv)
|
|
54
|
+
return unless @defs
|
|
53
55
|
@defs.each do |mdef|
|
|
54
56
|
genv.add_run(mdef)
|
|
55
57
|
end
|
|
56
58
|
end
|
|
57
59
|
|
|
58
60
|
def add_run_all_method_call_boxes(genv)
|
|
61
|
+
return unless @method_call_boxes
|
|
59
62
|
@method_call_boxes.each do |box|
|
|
60
63
|
genv.add_run(box)
|
|
61
64
|
end
|
|
@@ -3,12 +3,19 @@ module TypeProf::Core
|
|
|
3
3
|
def initialize(cpath, outer_module = self)
|
|
4
4
|
@cpath = cpath
|
|
5
5
|
|
|
6
|
-
@module_decls = Set
|
|
7
|
-
@module_defs = Set
|
|
8
|
-
@include_decls = Set
|
|
9
|
-
@include_defs = Set
|
|
6
|
+
@module_decls = Set.empty
|
|
7
|
+
@module_defs = Set.empty
|
|
8
|
+
@include_decls = Set.empty
|
|
9
|
+
@include_defs = Set.empty
|
|
10
10
|
@prepend_decls = []
|
|
11
11
|
@prepend_defs = []
|
|
12
|
+
@extend_decls = Set.empty
|
|
13
|
+
@extend_defs = Set.empty
|
|
14
|
+
|
|
15
|
+
# `class Foo = Bar` / `module Foo = Bar` declarations attached to this entity.
|
|
16
|
+
# Maps an alias decl to the target ModuleEntity at the time of registration.
|
|
17
|
+
@alias_decls = {}
|
|
18
|
+
@alias_target = nil
|
|
12
19
|
|
|
13
20
|
@inner_modules = {}
|
|
14
21
|
@outer_module = outer_module
|
|
@@ -18,6 +25,7 @@ module TypeProf::Core
|
|
|
18
25
|
@self_types = {}
|
|
19
26
|
@included_modules = {}
|
|
20
27
|
@prepended_modules = {}
|
|
28
|
+
@extended_modules = {}
|
|
21
29
|
@basic_object = @cpath == [:BasicObject]
|
|
22
30
|
|
|
23
31
|
# child modules (subclasses and all modules that include me)
|
|
@@ -25,7 +33,7 @@ module TypeProf::Core
|
|
|
25
33
|
|
|
26
34
|
# class Foo[X, Y, Z] < Bar[A, B, C]
|
|
27
35
|
@superclass_type_args = nil # A, B, C
|
|
28
|
-
@type_params =
|
|
36
|
+
@type_params = {} # X, Y, Z
|
|
29
37
|
|
|
30
38
|
@consts = {}
|
|
31
39
|
@methods = { true => {}, false => {} }
|
|
@@ -34,14 +42,16 @@ module TypeProf::Core
|
|
|
34
42
|
@type_aliases = {}
|
|
35
43
|
|
|
36
44
|
@static_reads = {}
|
|
37
|
-
@subclass_checks = Set
|
|
38
|
-
@ivar_reads = Set
|
|
39
|
-
@cvar_reads = Set
|
|
45
|
+
@subclass_checks = Set.empty
|
|
46
|
+
@ivar_reads = Set.empty # should be handled in @ivars ??
|
|
47
|
+
@cvar_reads = Set.empty
|
|
40
48
|
end
|
|
41
49
|
|
|
42
50
|
attr_reader :cpath
|
|
43
51
|
attr_reader :module_decls
|
|
44
52
|
attr_reader :module_defs
|
|
53
|
+
attr_reader :alias_decls
|
|
54
|
+
attr_reader :alias_target
|
|
45
55
|
|
|
46
56
|
attr_reader :inner_modules
|
|
47
57
|
attr_reader :outer_module
|
|
@@ -50,6 +60,7 @@ module TypeProf::Core
|
|
|
50
60
|
attr_reader :self_types
|
|
51
61
|
attr_reader :included_modules
|
|
52
62
|
attr_reader :prepended_modules
|
|
63
|
+
attr_reader :extended_modules
|
|
53
64
|
attr_reader :child_modules
|
|
54
65
|
|
|
55
66
|
attr_reader :superclass_type_args
|
|
@@ -79,7 +90,7 @@ module TypeProf::Core
|
|
|
79
90
|
end
|
|
80
91
|
|
|
81
92
|
def exist?
|
|
82
|
-
!@module_decls.empty? || !@module_defs.empty?
|
|
93
|
+
!@module_decls.empty? || !@module_defs.empty? || !@alias_decls.empty?
|
|
83
94
|
end
|
|
84
95
|
|
|
85
96
|
def on_inner_modules_changed(genv, changed_cname)
|
|
@@ -115,9 +126,10 @@ module TypeProf::Core
|
|
|
115
126
|
@module_decls << decl
|
|
116
127
|
|
|
117
128
|
if @type_params
|
|
118
|
-
update_type_params
|
|
129
|
+
update_type_params
|
|
119
130
|
else
|
|
120
|
-
@type_params =
|
|
131
|
+
@type_params = {}
|
|
132
|
+
decl.params.zip(decl.params_default_types) {|name, default_type| @type_params[name] = default_type }
|
|
121
133
|
end
|
|
122
134
|
|
|
123
135
|
if decl.is_a?(AST::SigClassNode) && !@superclass_type_args
|
|
@@ -133,7 +145,7 @@ module TypeProf::Core
|
|
|
133
145
|
@outer_module.get_const(get_cname).remove_decl(decl)
|
|
134
146
|
@module_decls.delete(decl) || raise
|
|
135
147
|
|
|
136
|
-
update_type_params
|
|
148
|
+
update_type_params
|
|
137
149
|
if decl.is_a?(AST::SigClassNode) && @superclass_type_args == decl.superclass_args
|
|
138
150
|
@superclass_type_args = nil
|
|
139
151
|
@module_decls.each do |decl|
|
|
@@ -152,13 +164,12 @@ module TypeProf::Core
|
|
|
152
164
|
@module_decls.each do |decl|
|
|
153
165
|
params = decl.params
|
|
154
166
|
next unless params
|
|
155
|
-
if @type_params
|
|
156
|
-
@type_params =
|
|
157
|
-
|
|
158
|
-
@type_params = params
|
|
167
|
+
if !@type_params || @type_params.size < params.size
|
|
168
|
+
@type_params = {}
|
|
169
|
+
params.zip(decl.params_default_types) {|name, default_type| @type_params[name] = default_type }
|
|
159
170
|
end
|
|
160
171
|
end
|
|
161
|
-
@type_params ||=
|
|
172
|
+
@type_params ||= {}
|
|
162
173
|
# TODO: report an error if there are multiple inconsistent declarations
|
|
163
174
|
end
|
|
164
175
|
|
|
@@ -176,6 +187,22 @@ module TypeProf::Core
|
|
|
176
187
|
on_module_removed(genv)
|
|
177
188
|
end
|
|
178
189
|
|
|
190
|
+
def add_alias_decl(genv, decl, target_mod)
|
|
191
|
+
on_module_added(genv)
|
|
192
|
+
@alias_decls[decl] = target_mod
|
|
193
|
+
@alias_target = @alias_decls.values.first
|
|
194
|
+
ce = @outer_module.get_const(get_cname)
|
|
195
|
+
ce.add_decl(decl)
|
|
196
|
+
ce
|
|
197
|
+
end
|
|
198
|
+
|
|
199
|
+
def remove_alias_decl(genv, decl)
|
|
200
|
+
@outer_module.get_const(get_cname).remove_decl(decl)
|
|
201
|
+
@alias_decls.delete(decl) || raise
|
|
202
|
+
@alias_target = @alias_decls.values.first
|
|
203
|
+
on_module_removed(genv)
|
|
204
|
+
end
|
|
205
|
+
|
|
179
206
|
def add_include_decl(genv, node)
|
|
180
207
|
@include_decls << node
|
|
181
208
|
genv.add_static_eval_queue(:parent_modules_changed, self)
|
|
@@ -196,6 +223,26 @@ module TypeProf::Core
|
|
|
196
223
|
genv.add_static_eval_queue(:parent_modules_changed, self)
|
|
197
224
|
end
|
|
198
225
|
|
|
226
|
+
def add_extend_decl(genv, node)
|
|
227
|
+
@extend_decls << node
|
|
228
|
+
genv.add_static_eval_queue(:parent_modules_changed, self)
|
|
229
|
+
end
|
|
230
|
+
|
|
231
|
+
def remove_extend_decl(genv, node)
|
|
232
|
+
@extend_decls.delete(node) || raise
|
|
233
|
+
genv.add_static_eval_queue(:parent_modules_changed, self)
|
|
234
|
+
end
|
|
235
|
+
|
|
236
|
+
def add_extend_def(genv, node)
|
|
237
|
+
@extend_defs << node
|
|
238
|
+
genv.add_static_eval_queue(:parent_modules_changed, self)
|
|
239
|
+
end
|
|
240
|
+
|
|
241
|
+
def remove_extend_def(genv, node)
|
|
242
|
+
@extend_defs.delete(node) || raise
|
|
243
|
+
genv.add_static_eval_queue(:parent_modules_changed, self)
|
|
244
|
+
end
|
|
245
|
+
|
|
199
246
|
def add_prepend_decl(genv, node)
|
|
200
247
|
@prepend_decls << node
|
|
201
248
|
genv.add_static_eval_queue(:parent_modules_changed, self)
|
|
@@ -237,7 +284,7 @@ module TypeProf::Core
|
|
|
237
284
|
old_parent.child_modules.delete(self) if set.empty?
|
|
238
285
|
end
|
|
239
286
|
if new_parent
|
|
240
|
-
set = new_parent.child_modules[self] ||= Set
|
|
287
|
+
set = new_parent.child_modules[self] ||= Set.empty
|
|
241
288
|
set << origin
|
|
242
289
|
end
|
|
243
290
|
return [new_parent, true]
|
|
@@ -261,6 +308,9 @@ module TypeProf::Core
|
|
|
261
308
|
next
|
|
262
309
|
when AST::ModuleNode
|
|
263
310
|
return nil
|
|
311
|
+
when AST::StructNewNode
|
|
312
|
+
base_cpath = mdef.struct_base_cpath
|
|
313
|
+
return base_cpath == @cpath ? [] : base_cpath
|
|
264
314
|
else
|
|
265
315
|
raise
|
|
266
316
|
end
|
|
@@ -371,6 +421,30 @@ module TypeProf::Core
|
|
|
371
421
|
any_updated = true
|
|
372
422
|
end
|
|
373
423
|
end
|
|
424
|
+
@extend_decls.each do |edecl|
|
|
425
|
+
new_parent_cpath = edecl.static_ret.last.cpath
|
|
426
|
+
new_parent, updated = update_parent(genv, edecl, @extended_modules[edecl], new_parent_cpath)
|
|
427
|
+
if updated
|
|
428
|
+
if new_parent
|
|
429
|
+
@extended_modules[edecl] = new_parent
|
|
430
|
+
else
|
|
431
|
+
@extended_modules.delete(edecl) || raise
|
|
432
|
+
end
|
|
433
|
+
any_updated = true
|
|
434
|
+
end
|
|
435
|
+
end
|
|
436
|
+
@extend_defs.each do |edef|
|
|
437
|
+
new_parent_cpath = edef.static_ret ? edef.static_ret.cpath : nil
|
|
438
|
+
new_parent, updated = update_parent(genv, edef, @extended_modules[edef], new_parent_cpath)
|
|
439
|
+
if updated
|
|
440
|
+
if new_parent
|
|
441
|
+
@extended_modules[edef] = new_parent
|
|
442
|
+
else
|
|
443
|
+
@extended_modules.delete(edef) || raise
|
|
444
|
+
end
|
|
445
|
+
any_updated = true
|
|
446
|
+
end
|
|
447
|
+
end
|
|
374
448
|
@included_modules.delete_if do |origin, old_mod|
|
|
375
449
|
if @include_decls.include?(origin) || @include_defs.include?(origin)
|
|
376
450
|
false
|
|
@@ -389,6 +463,15 @@ module TypeProf::Core
|
|
|
389
463
|
true
|
|
390
464
|
end
|
|
391
465
|
end
|
|
466
|
+
@extended_modules.delete_if do |origin, old_mod|
|
|
467
|
+
if @extend_decls.include?(origin) || @extend_defs.include?(origin)
|
|
468
|
+
false
|
|
469
|
+
else
|
|
470
|
+
_new_parent, updated = update_parent(genv, origin, old_mod, nil)
|
|
471
|
+
any_updated ||= updated
|
|
472
|
+
true
|
|
473
|
+
end
|
|
474
|
+
end
|
|
392
475
|
|
|
393
476
|
if any_updated
|
|
394
477
|
@subclass_checks.each do |mcall_box|
|
|
@@ -399,6 +482,8 @@ module TypeProf::Core
|
|
|
399
482
|
end
|
|
400
483
|
|
|
401
484
|
def on_ancestors_updated(genv, base_mod)
|
|
485
|
+
# `include` and `extend` can form a cycle in valid Ruby
|
|
486
|
+
return if base_mod == self
|
|
402
487
|
@child_modules.each_key {|child_mod| child_mod.on_ancestors_updated(genv, base_mod || self) }
|
|
403
488
|
@static_reads.each_value do |static_reads|
|
|
404
489
|
static_reads.each do |static_read|
|
|
@@ -436,6 +521,19 @@ module TypeProf::Core
|
|
|
436
521
|
@ivars[singleton][name] ||= ValueEntity.new
|
|
437
522
|
end
|
|
438
523
|
|
|
524
|
+
def add_ivar_decl(genv, singleton, name, decl)
|
|
525
|
+
ive = get_ivar(singleton, name)
|
|
526
|
+
ive.add_decl(decl)
|
|
527
|
+
ive.on_decl_changed(genv)
|
|
528
|
+
ive
|
|
529
|
+
end
|
|
530
|
+
|
|
531
|
+
def remove_ivar_decl(genv, singleton, name, decl)
|
|
532
|
+
ive = get_ivar(singleton, name)
|
|
533
|
+
ive.remove_decl(decl)
|
|
534
|
+
ive.on_decl_changed(genv)
|
|
535
|
+
end
|
|
536
|
+
|
|
439
537
|
def get_cvar(name)
|
|
440
538
|
@cvars[name] ||= ValueEntity.new
|
|
441
539
|
end
|