typeprof 0.21.11 → 0.30.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (72) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +15 -31
  3. data/bin/typeprof +5 -0
  4. data/doc/doc.ja.md +134 -0
  5. data/doc/doc.md +136 -0
  6. data/lib/typeprof/cli/cli.rb +178 -0
  7. data/lib/typeprof/cli.rb +3 -133
  8. data/lib/typeprof/code_range.rb +112 -0
  9. data/lib/typeprof/core/ast/base.rb +263 -0
  10. data/lib/typeprof/core/ast/call.rb +259 -0
  11. data/lib/typeprof/core/ast/const.rb +126 -0
  12. data/lib/typeprof/core/ast/control.rb +433 -0
  13. data/lib/typeprof/core/ast/meta.rb +150 -0
  14. data/lib/typeprof/core/ast/method.rb +339 -0
  15. data/lib/typeprof/core/ast/misc.rb +263 -0
  16. data/lib/typeprof/core/ast/module.rb +123 -0
  17. data/lib/typeprof/core/ast/pattern.rb +140 -0
  18. data/lib/typeprof/core/ast/sig_decl.rb +471 -0
  19. data/lib/typeprof/core/ast/sig_type.rb +663 -0
  20. data/lib/typeprof/core/ast/value.rb +319 -0
  21. data/lib/typeprof/core/ast/variable.rb +315 -0
  22. data/lib/typeprof/core/ast.rb +472 -0
  23. data/lib/typeprof/core/builtin.rb +146 -0
  24. data/lib/typeprof/core/env/method.rb +137 -0
  25. data/lib/typeprof/core/env/method_entity.rb +55 -0
  26. data/lib/typeprof/core/env/module_entity.rb +408 -0
  27. data/lib/typeprof/core/env/static_read.rb +155 -0
  28. data/lib/typeprof/core/env/type_alias_entity.rb +27 -0
  29. data/lib/typeprof/core/env/value_entity.rb +32 -0
  30. data/lib/typeprof/core/env.rb +366 -0
  31. data/lib/typeprof/core/graph/box.rb +998 -0
  32. data/lib/typeprof/core/graph/change_set.rb +224 -0
  33. data/lib/typeprof/core/graph/filter.rb +155 -0
  34. data/lib/typeprof/core/graph/vertex.rb +225 -0
  35. data/lib/typeprof/core/service.rb +514 -0
  36. data/lib/typeprof/core/type.rb +352 -0
  37. data/lib/typeprof/core/util.rb +81 -0
  38. data/lib/typeprof/core.rb +31 -0
  39. data/lib/typeprof/diagnostic.rb +35 -0
  40. data/lib/typeprof/lsp/messages.rb +415 -0
  41. data/lib/typeprof/lsp/server.rb +203 -0
  42. data/lib/typeprof/lsp/text.rb +69 -0
  43. data/lib/typeprof/lsp/util.rb +51 -0
  44. data/lib/typeprof/lsp.rb +4 -907
  45. data/lib/typeprof/version.rb +1 -1
  46. data/lib/typeprof.rb +4 -18
  47. data/typeprof.gemspec +5 -7
  48. metadata +47 -33
  49. data/.github/dependabot.yml +0 -6
  50. data/.github/workflows/main.yml +0 -39
  51. data/.gitignore +0 -9
  52. data/Gemfile +0 -17
  53. data/Gemfile.lock +0 -41
  54. data/Rakefile +0 -10
  55. data/exe/typeprof +0 -10
  56. data/lib/typeprof/analyzer.rb +0 -2598
  57. data/lib/typeprof/arguments.rb +0 -414
  58. data/lib/typeprof/block.rb +0 -176
  59. data/lib/typeprof/builtin.rb +0 -893
  60. data/lib/typeprof/code-range.rb +0 -177
  61. data/lib/typeprof/config.rb +0 -158
  62. data/lib/typeprof/container-type.rb +0 -912
  63. data/lib/typeprof/export.rb +0 -589
  64. data/lib/typeprof/import.rb +0 -852
  65. data/lib/typeprof/insns-def.rb +0 -65
  66. data/lib/typeprof/iseq.rb +0 -864
  67. data/lib/typeprof/method.rb +0 -355
  68. data/lib/typeprof/type.rb +0 -1140
  69. data/lib/typeprof/utils.rb +0 -212
  70. data/tools/coverage.rb +0 -14
  71. data/tools/setup-insns-def.rb +0 -30
  72. data/typeprof-lsp +0 -3
@@ -0,0 +1,998 @@
1
+ module TypeProf::Core
2
+ $box_counts = Hash.new(0)
3
+ class Box
4
+ def initialize(node)
5
+ @node = node
6
+ @changes = ChangeSet.new(node, self)
7
+ @destroyed = false
8
+ $box_counts[Box] += 1
9
+ $box_counts[self.class] += 1
10
+ end
11
+
12
+ attr_reader :changes
13
+
14
+ attr_reader :node, :destroyed
15
+
16
+ def destroy(genv)
17
+ $box_counts[self.class] -= 1
18
+ $box_counts[Box] -= 1
19
+ @destroyed = true
20
+ @changes.reinstall(genv) # rollback all changes
21
+ end
22
+
23
+ def reuse(new_node)
24
+ @node = new_node
25
+ @changes.reuse(new_node)
26
+ end
27
+
28
+ def on_type_added(genv, src_tyvar, added_types)
29
+ genv.add_run(self)
30
+ end
31
+
32
+ def on_type_removed(genv, src_tyvar, removed_types)
33
+ genv.add_run(self)
34
+ end
35
+
36
+ def run(genv)
37
+ return if @destroyed
38
+ run0(genv, @changes)
39
+ @changes.reinstall(genv)
40
+ end
41
+
42
+ def diagnostics(genv, &blk)
43
+ raise self.to_s if !@changes
44
+ @changes.diagnostics.each(&blk)
45
+ @changes.boxes.each_value do |box|
46
+ box.diagnostics(genv, &blk)
47
+ end
48
+ end
49
+
50
+ #@@new_id = 0
51
+
52
+ def to_s
53
+ "#{ self.class.to_s.split("::").last[0] }#{ @id ||= $new_id += 1 }"
54
+ end
55
+
56
+ alias inspect to_s
57
+ end
58
+
59
+ class ConstReadBox < Box
60
+ def initialize(node, genv, const_read)
61
+ super(node)
62
+ @const_read = const_read
63
+ const_read.followers << self
64
+ @ret = Vertex.new(node)
65
+ genv.add_run(self)
66
+ end
67
+
68
+ attr_reader :node, :const_read, :ret
69
+
70
+ def run0(genv, changes)
71
+ cdef = @const_read.cdef
72
+ if cdef
73
+ changes.add_depended_value_entity(cdef)
74
+ changes.add_edge(genv, cdef.vtx, @ret)
75
+ end
76
+ end
77
+ end
78
+
79
+ class TypeReadBox < Box
80
+ def initialize(node, genv, rbs_type)
81
+ super(node)
82
+ @rbs_type = rbs_type
83
+ @ret = Vertex.new(node)
84
+ genv.add_run(self)
85
+ end
86
+
87
+ attr_reader :node, :rbs_type, :ret
88
+
89
+ def run0(genv, changes)
90
+ vtx = @rbs_type.covariant_vertex(genv, changes, {})
91
+ changes.add_edge(genv, vtx, @ret)
92
+ end
93
+ end
94
+
95
+ class MethodDeclBox < Box
96
+ def initialize(node, genv, cpath, singleton, mid, method_types, overloading)
97
+ super(node)
98
+ @cpath = cpath
99
+ @singleton = singleton
100
+ @mid = mid
101
+ @method_types = method_types
102
+ @overloading = overloading
103
+ @ret = Source.new
104
+
105
+ me = genv.resolve_method(@cpath, @singleton, @mid)
106
+ me.add_decl(self)
107
+ me.add_run_all_method_call_boxes(genv)
108
+ me.add_run_all_mdefs(genv)
109
+ end
110
+
111
+ attr_accessor :node
112
+
113
+ attr_reader :cpath, :singleton, :mid, :method_types, :overloading, :ret
114
+
115
+ def destroy(genv)
116
+ me = genv.resolve_method(@cpath, @singleton, @mid)
117
+ me.remove_decl(self)
118
+ me.add_run_all_method_call_boxes(genv)
119
+ end
120
+
121
+ def match_arguments?(genv, changes, param_map, a_args, method_type)
122
+ # TODO: handle a tuple as a splat argument?
123
+ if a_args.splat_flags.any?
124
+ return false unless method_type.rest_positionals
125
+ method_type.req_positionals.size.times do |i|
126
+ return false if a_args.splat_flags[i]
127
+ end
128
+ method_type.post_positionals.size.times do |i|
129
+ return false if a_args.splat_flags[-i - 1]
130
+ end
131
+ else
132
+ actual = a_args.positionals.size
133
+ required_formal = method_type.req_positionals.size + method_type.post_positionals.size
134
+ if actual < required_formal
135
+ # too few actual arguments
136
+ return false
137
+ end
138
+ if !method_type.rest_positionals && actual > required_formal + method_type.opt_positionals.size
139
+ # too many actual arguments
140
+ return false
141
+ end
142
+ end
143
+
144
+ method_type.req_positionals.each_with_index do |ty, i|
145
+ f_arg = ty.contravariant_vertex(genv, changes, param_map)
146
+ return false unless a_args.positionals[i].check_match(genv, changes, f_arg)
147
+ end
148
+ method_type.post_positionals.each_with_index do |ty, i|
149
+ f_arg = ty.contravariant_vertex(genv, changes, param_map)
150
+ i -= method_type.post_positionals.size
151
+ return false unless a_args.positionals[i].check_match(genv, changes, f_arg)
152
+ end
153
+
154
+ start_rest = method_type.req_positionals.size
155
+ end_rest = a_args.positionals.size - method_type.post_positionals.size
156
+
157
+ i = 0
158
+ while i < method_type.opt_positionals.size && start_rest < end_rest
159
+ break if a_args.splat_flags[start_rest]
160
+ f_arg = method_type.opt_positionals[i].contravariant_vertex(genv, changes, param_map)
161
+ return false unless a_args.positionals[start_rest].check_match(genv, changes, f_arg)
162
+ i += 1
163
+ start_rest += 1
164
+ end
165
+
166
+ if start_rest < end_rest
167
+ vtxs = a_args.get_rest_args(genv, start_rest, end_rest)
168
+ while i < method_type.opt_positionals.size
169
+ f_arg = method_type.opt_positionals[i].contravariant_vertex(genv, changes, param_map)
170
+ return false if vtxs.any? {|vtx| !vtx.check_match(genv, changes, f_arg) }
171
+ i += 1
172
+ end
173
+ if method_type.rest_positionals
174
+ f_arg = method_type.rest_positionals.contravariant_vertex(genv, changes, param_map)
175
+ return false if vtxs.any? {|vtx| !vtx.check_match(genv, changes, f_arg) }
176
+ end
177
+ end
178
+
179
+ return true
180
+ end
181
+
182
+ def resolve_overloads(changes, genv, node, param_map, a_args, ret)
183
+ match_any_overload = false
184
+ @method_types.each do |method_type|
185
+ param_map0 = param_map.dup
186
+ if method_type.type_params
187
+ method_type.type_params.zip(yield(method_type)) do |var, vtx|
188
+ param_map0[var] = vtx
189
+ end
190
+ end
191
+
192
+ next unless match_arguments?(genv, changes, param_map0, a_args, method_type)
193
+
194
+ rbs_blk = method_type.block
195
+ next if method_type.block_required && !a_args.block
196
+ next if !rbs_blk && a_args.block
197
+ if rbs_blk && a_args.block
198
+ # rbs_blk_func.optional_keywords, ...
199
+ a_args.block.each_type do |ty|
200
+ case ty
201
+ when Type::Proc
202
+ blk_f_ret = rbs_blk.return_type.contravariant_vertex(genv, changes, param_map0)
203
+ blk_a_args = rbs_blk.req_positionals.map do |blk_a_arg|
204
+ blk_a_arg.covariant_vertex(genv, changes, param_map0)
205
+ end
206
+
207
+ ty.block.accept_args(genv, changes, blk_a_args, blk_f_ret, true)
208
+ end
209
+ end
210
+ end
211
+ ret_vtx = method_type.return_type.covariant_vertex(genv, changes, param_map0)
212
+
213
+ changes.add_edge(genv, ret_vtx, ret)
214
+ match_any_overload = true
215
+ end
216
+ unless match_any_overload
217
+ meth = node.mid_code_range ? :mid_code_range : :code_range
218
+ changes.add_diagnostic(meth, "failed to resolve overloads")
219
+ end
220
+ end
221
+
222
+ def show
223
+ @method_types.map do |method_type|
224
+ args = []
225
+ method_type.req_positionals.each do |arg|
226
+ args << arg.show
227
+ end
228
+ method_type.opt_positionals.each do |arg|
229
+ args << "?#{arg.show}"
230
+ end
231
+ if method_type.rest_positionals
232
+ args << "*#{method_type.rest_positionals.show}"
233
+ end
234
+ method_type.post_positionals.each do |arg|
235
+ args << arg.show
236
+ end
237
+
238
+ method_type.req_keywords.each do |key, arg|
239
+ args << "#{ key }: #{arg.show}"
240
+ end
241
+ method_type.opt_keywords.each do |key, arg|
242
+ args << "?#{ key }: #{arg.show}"
243
+ end
244
+ if method_type.rest_keywords
245
+ args << "**#{method_type.rest_keywords.show}"
246
+ end
247
+
248
+ s = args.empty? ? "-> " : "(#{ args.join(", ") }) -> "
249
+ s += method_type.return_type.show
250
+ end.join(" | ")
251
+ end
252
+ end
253
+
254
+ class EscapeBox < Box
255
+ def initialize(node, genv, a_ret, f_ret)
256
+ super(node)
257
+ @a_ret = a_ret.new_vertex(genv, node)
258
+ @f_ret = f_ret
259
+ @f_ret.add_edge(genv, self)
260
+ end
261
+
262
+ attr_reader :a_ret, :f_ret
263
+
264
+ def ret = @a_ret
265
+
266
+ def run0(genv, changes)
267
+ unless @a_ret.check_match(genv, changes, @f_ret)
268
+ msg = "expected: #{ @f_ret.show }; actual: #{ @a_ret.show }"
269
+ case @node
270
+ when AST::ReturnNode
271
+ changes.add_diagnostic(:code_range, msg)
272
+ when AST::DefNode
273
+ changes.add_diagnostic(:last_stmt_code_range, msg)
274
+ when AST::NextNode
275
+ changes.add_diagnostic(:code_range, msg)
276
+ when AST::CallNode
277
+ changes.add_diagnostic(:block_last_stmt_code_range, msg)
278
+ when AST::AttrReaderMetaNode, AST::AttrAccessorMetaNode
279
+ changes.add_diagnostic(:code_range, msg)
280
+ else
281
+ pp @node.class
282
+ end
283
+ end
284
+ end
285
+ end
286
+
287
+ class SplatBox < Box
288
+ def initialize(node, genv, ary)
289
+ super(node)
290
+ @ary = ary
291
+ @ary.add_edge(genv, self)
292
+ @ret = Vertex.new(node)
293
+ end
294
+
295
+ attr_reader :ary, :ret
296
+
297
+ def run0(genv, changes)
298
+ @ary.each_type do |ty|
299
+ ty = ty.base_type(genv)
300
+ if ty.mod == genv.mod_ary
301
+ changes.add_edge(genv, ty.args[0], @ret)
302
+ else
303
+ "???"
304
+ end
305
+ end
306
+ end
307
+ end
308
+
309
+ class HashSplatBox < Box
310
+ def initialize(node, genv, hsh, unified_key, unified_val)
311
+ super(node)
312
+ @hsh = hsh
313
+ @unified_key = unified_key
314
+ @unified_val = unified_val
315
+ @hsh.add_edge(genv, self)
316
+ end
317
+
318
+ def ret = @hsh # dummy
319
+
320
+ attr_reader :hsh, :unified_key, :unified_val
321
+
322
+ def run0(genv, changes)
323
+ @hsh.each_type do |ty|
324
+ ty = ty.base_type(genv)
325
+ if ty.mod == genv.mod_hash
326
+ changes.add_edge(genv, ty.args[0], @unified_key)
327
+ changes.add_edge(genv, ty.args[1], @unified_val)
328
+ else
329
+ "???"
330
+ end
331
+ end
332
+ end
333
+ end
334
+
335
+ class MethodDefBox < Box
336
+ def initialize(node, genv, cpath, singleton, mid, f_args, ret_boxes)
337
+ super(node)
338
+ @cpath = cpath
339
+ @singleton = singleton
340
+ @mid = mid
341
+ raise unless f_args
342
+ @f_args = f_args
343
+ raise unless f_args.is_a?(FormalArguments)
344
+
345
+ @record_block = RecordBlock.new(@node)
346
+ if @f_args.block
347
+ record_blk_ty = Source.new(Type::Proc.new(genv, @record_block))
348
+ record_blk_ty.add_edge(genv, @f_args.block)
349
+ end
350
+
351
+ @ret_boxes = ret_boxes
352
+ @ret = Vertex.new(node)
353
+ ret_boxes.each do |box|
354
+ @changes.add_edge(genv, box.ret, @ret)
355
+ end
356
+ me = genv.resolve_method(@cpath, @singleton, @mid)
357
+ me.add_def(self)
358
+ if me.decls.empty?
359
+ me.add_run_all_method_call_boxes(genv)
360
+ else
361
+ genv.add_run(self)
362
+ end
363
+ end
364
+
365
+ attr_accessor :node
366
+
367
+ attr_reader :cpath, :singleton, :mid, :f_args, :ret
368
+
369
+ def destroy(genv)
370
+ me = genv.resolve_method(@cpath, @singleton, @mid)
371
+ me.remove_def(self)
372
+ if me.decls.empty?
373
+ me.add_run_all_method_call_boxes(genv)
374
+ else
375
+ genv.add_run(self)
376
+ end
377
+ super(genv)
378
+ end
379
+
380
+ def run0(genv, changes)
381
+ me = genv.resolve_method(@cpath, @singleton, @mid)
382
+ return if me.decls.empty?
383
+
384
+ # TODO: support "| ..."
385
+ decl = me.decls.to_a.first
386
+ # TODO: support overload?
387
+ method_type = decl.method_types.first
388
+ _block = method_type.block
389
+
390
+ mod = genv.resolve_cpath(@cpath)
391
+ if @singleton
392
+ ty = Type::Singleton.new(genv, mod)
393
+ param_map0 = Type.default_param_map(genv, ty)
394
+ else
395
+ type_params = mod.type_params.map {|ty_param| Source.new() } # TODO: better support
396
+ ty = Type::Instance.new(genv, mod, type_params)
397
+ param_map0 = Type.default_param_map(genv, ty)
398
+ if ty.is_a?(Type::Instance)
399
+ ty.mod.type_params.zip(ty.args) do |param, arg|
400
+ param_map0[param] = arg
401
+ end
402
+ end
403
+ end
404
+ method_type.type_params.each do |param|
405
+ param_map0[param] = Source.new()
406
+ end
407
+
408
+ positional_args = []
409
+ splat_flags = []
410
+
411
+ method_type.req_positionals.each do |a_arg|
412
+ positional_args << a_arg.contravariant_vertex(genv, changes, param_map0)
413
+ splat_flags << false
414
+ end
415
+ method_type.opt_positionals.each do |a_arg|
416
+ positional_args << a_arg.contravariant_vertex(genv, changes, param_map0)
417
+ splat_flags << false
418
+ end
419
+ if method_type.rest_positionals
420
+ elems = method_type.rest_positionals.contravariant_vertex(genv, changes, param_map0)
421
+ positional_args << Source.new(genv.gen_ary_type(elems))
422
+ splat_flags << true
423
+ end
424
+ method_type.post_positionals.each do |a_arg|
425
+ positional_args << a_arg.contravariant_vertex(genv, changes, param_map0)
426
+ splat_flags << false
427
+ end
428
+
429
+ a_args = ActualArguments.new(positional_args, splat_flags, nil, nil) # TODO: keywords and block
430
+ if pass_arguments(changes, genv, a_args)
431
+ # TODO: block
432
+ f_ret = method_type.return_type.contravariant_vertex(genv, changes, param_map0)
433
+ @ret_boxes.each do |ret_box|
434
+ changes.add_edge(genv, f_ret, ret_box.f_ret)
435
+ end
436
+ end
437
+ end
438
+
439
+ def pass_arguments(changes, genv, a_args)
440
+ if a_args.splat_flags.any?
441
+ # there is at least one splat actual argument
442
+
443
+ lower = @f_args.req_positionals.size + @f_args.post_positionals.size
444
+ upper = @f_args.rest_positionals ? nil : lower + @f_args.opt_positionals.size
445
+ if upper && upper < a_args.positionals.size
446
+ meth = changes.node.mid_code_range ? :mid_code_range : :code_range
447
+ err = "#{ a_args.positionals.size } for #{ lower }#{ upper ? lower < upper ? "...#{ upper }" : "" : "+" }"
448
+ changes.add_diagnostic(meth, "wrong number of arguments (#{ err })")
449
+ return false
450
+ end
451
+
452
+ start_rest = [a_args.splat_flags.index(true), @f_args.req_positionals.size + @f_args.opt_positionals.size].min
453
+ end_rest = [a_args.splat_flags.rindex(true) + 1, a_args.positionals.size - @f_args.post_positionals.size].max
454
+ rest_vtxs = a_args.get_rest_args(genv, start_rest, end_rest)
455
+
456
+ @f_args.req_positionals.each_with_index do |f_vtx, i|
457
+ if i < start_rest
458
+ changes.add_edge(genv, a_args.positionals[i], f_vtx)
459
+ else
460
+ rest_vtxs.each do |vtx|
461
+ changes.add_edge(genv, vtx, f_vtx)
462
+ end
463
+ end
464
+ end
465
+ @f_args.opt_positionals.each_with_index do |f_vtx, i|
466
+ i += @f_args.opt_positionals.size
467
+ if i < start_rest
468
+ changes.add_edge(genv, a_args.positionals[i], f_vtx)
469
+ else
470
+ rest_vtxs.each do |vtx|
471
+ changes.add_edge(genv, vtx, f_vtx)
472
+ end
473
+ end
474
+ end
475
+ @f_args.post_positionals.each_with_index do |f_vtx, i|
476
+ i += a_args.positionals.size - @f_args.post_positionals.size
477
+ if end_rest <= i
478
+ changes.add_edge(genv, a_args.positionals[i], f_vtx)
479
+ else
480
+ rest_vtxs.each do |vtx|
481
+ changes.add_edge(genv, vtx, f_vtx)
482
+ end
483
+ end
484
+ end
485
+
486
+ if @f_args.rest_positionals
487
+ rest_vtxs.each do |vtx|
488
+ @f_args.rest_positionals.each_type do |ty|
489
+ if ty.is_a?(Type::Instance) && ty.mod == genv.mod_ary && ty.args[0]
490
+ changes.add_edge(genv, vtx, ty.args[0])
491
+ end
492
+ end
493
+ end
494
+ end
495
+ else
496
+ # there is no splat actual argument
497
+
498
+ lower = @f_args.req_positionals.size + @f_args.post_positionals.size
499
+ upper = @f_args.rest_positionals ? nil : lower + @f_args.opt_positionals.size
500
+ if a_args.positionals.size < lower || (upper && upper < a_args.positionals.size)
501
+ meth = changes.node.mid_code_range ? :mid_code_range : :code_range
502
+ err = "#{ a_args.positionals.size } for #{ lower }#{ upper ? lower < upper ? "...#{ upper }" : "" : "+" }"
503
+ changes.add_diagnostic(meth, "wrong number of arguments (#{ err })")
504
+ return false
505
+ end
506
+
507
+ @f_args.req_positionals.each_with_index do |f_vtx, i|
508
+ changes.add_edge(genv, a_args.positionals[i], f_vtx)
509
+ end
510
+ @f_args.post_positionals.each_with_index do |f_vtx, i|
511
+ i -= @f_args.post_positionals.size
512
+ changes.add_edge(genv, a_args.positionals[i], f_vtx)
513
+ end
514
+ start_rest = @f_args.req_positionals.size
515
+ end_rest = a_args.positionals.size - @f_args.post_positionals.size
516
+ i = 0
517
+ while i < @f_args.opt_positionals.size && start_rest < end_rest
518
+ f_arg = @f_args.opt_positionals[i]
519
+ changes.add_edge(genv, a_args.positionals[start_rest], f_arg)
520
+ i += 1
521
+ start_rest += 1
522
+ end
523
+
524
+ if start_rest < end_rest
525
+ if @f_args.rest_positionals
526
+ (start_rest..end_rest-1).each do |i|
527
+ @f_args.rest_positionals.each_type do |ty|
528
+ if ty.is_a?(Type::Instance) && ty.mod == genv.mod_ary && ty.args[0]
529
+ changes.add_edge(genv, a_args.positionals[i], ty.args[0])
530
+ end
531
+ end
532
+ end
533
+ end
534
+ end
535
+ end
536
+
537
+ if a_args.keywords
538
+ # TODO: support diagnostics
539
+ @node.req_keywords.zip(@f_args.req_keywords) do |name, f_vtx|
540
+ changes.add_edge(genv, a_args.get_keyword_arg(genv, changes, name), f_vtx)
541
+ end
542
+
543
+ @node.opt_keywords.zip(@f_args.opt_keywords).each do |name, f_vtx|
544
+ changes.add_edge(genv, a_args.get_keyword_arg(genv, changes, name), f_vtx)
545
+ end
546
+
547
+ if @node.rest_keywords
548
+ # FIXME: Extract the rest keywords excluding req_keywords and opt_keywords.
549
+ changes.add_edge(genv, a_args.keywords, @f_args.rest_keywords)
550
+ end
551
+ end
552
+
553
+ return true
554
+ end
555
+
556
+ def call(changes, genv, a_args, ret)
557
+ if pass_arguments(changes, genv, a_args)
558
+ changes.add_edge(genv, a_args.block, @f_args.block) if @f_args.block && a_args.block
559
+
560
+ changes.add_edge(genv, @ret, ret)
561
+ end
562
+ end
563
+
564
+ def show(output_parameter_names)
565
+ block_show = []
566
+ if @record_block.used
567
+ blk_f_args = @record_block.f_args.map {|arg| arg.show }.join(", ")
568
+ blk_ret = @record_block.ret.show
569
+ block_show << "{ (#{ blk_f_args }) -> #{ blk_ret } }"
570
+ end
571
+ args = []
572
+ @f_args.req_positionals.each do |f_vtx|
573
+ args << Type.strip_parens(f_vtx.show)
574
+ end
575
+ @f_args.opt_positionals.each do |f_vtx|
576
+ args << ("?" + Type.strip_parens(f_vtx.show))
577
+ end
578
+ if @f_args.rest_positionals
579
+ args << ("*" + Type.strip_array(Type.strip_parens(@f_args.rest_positionals.show)))
580
+ end
581
+ @f_args.post_positionals.each do |var|
582
+ args << Type.strip_parens(var.show)
583
+ end
584
+ if @node.is_a?(AST::DefNode)
585
+ @node.req_keywords.zip(@f_args.req_keywords) do |name, f_vtx|
586
+ args << "#{ name }: #{Type.strip_parens(f_vtx.show)}"
587
+ end
588
+ @node.opt_keywords.zip(@f_args.opt_keywords) do |name, f_vtx|
589
+ args << "?#{ name }: #{Type.strip_parens(f_vtx.show)}"
590
+ end
591
+ end
592
+ if @f_args.rest_keywords
593
+ args << "**#{ Type.strip_parens(@f_args.rest_keywords.show) }"
594
+ end
595
+
596
+ if output_parameter_names && @node.is_a?(AST::DefNode)
597
+ names = []
598
+ names.concat(@node.req_positionals)
599
+ names.concat(@node.opt_positionals)
600
+ names.concat(@node.rest_positionals) if @node.rest_positionals
601
+ names.concat(@node.post_positionals)
602
+ names.concat(@node.req_keywords)
603
+ names.concat(@node.opt_keywords)
604
+ names.concat(@node.rest_keywords) if @node.rest_keywords
605
+ args = args.zip(names).map do |arg, name|
606
+ name ? "#{ arg } #{ name }" : arg
607
+ end
608
+ end
609
+
610
+ args = args.join(", ")
611
+ s = args.empty? ? [] : ["(#{ args })"]
612
+ s << "#{ block_show.sort.join(" | ") }" unless block_show.empty?
613
+ s << "-> #{ @ret.show }"
614
+ s.join(" ")
615
+ end
616
+ end
617
+
618
+ class MethodAliasBox < Box
619
+ def initialize(node, genv, cpath, singleton, new_mid, old_mid)
620
+ super(node)
621
+ @cpath = cpath
622
+ @singleton = singleton
623
+ @new_mid = new_mid
624
+ @old_mid = old_mid
625
+ @ret = Source.new(genv.nil_type)
626
+
627
+ me = genv.resolve_method(@cpath, @singleton, @new_mid)
628
+ me.add_alias(self, @old_mid)
629
+ if me.decls.empty?
630
+ me.add_run_all_method_call_boxes(genv)
631
+ else
632
+ genv.add_run(self)
633
+ end
634
+ end
635
+
636
+ attr_accessor :node
637
+
638
+ attr_reader :cpath, :singleton, :new_mid, :old_mid, :ret
639
+
640
+ def destroy(genv)
641
+ me = genv.resolve_method(@cpath, @singleton, @new_mid)
642
+ me.remove_alias(self)
643
+ if me.decls.empty?
644
+ me.add_run_all_method_call_boxes(genv)
645
+ else
646
+ genv.add_run(self)
647
+ end
648
+ super(genv)
649
+ end
650
+
651
+ def run0(genv, changes)
652
+ # TODO: what to do?
653
+ end
654
+ end
655
+
656
+ class MethodCallBox < Box
657
+ def initialize(node, genv, recv, mid, a_args, subclasses)
658
+ raise mid.to_s unless mid
659
+ super(node)
660
+ @recv = recv.new_vertex(genv, node)
661
+ @recv.add_edge(genv, self)
662
+ @mid = mid
663
+ @a_args = a_args.new_vertexes(genv, node)
664
+ @a_args.positionals.each {|arg| arg.add_edge(genv, self) }
665
+ @a_args.keywords.add_edge(genv, self) if @a_args.keywords
666
+ @a_args.block.add_edge(genv, self) if @a_args.block
667
+ @ret = Vertex.new(node)
668
+ @subclasses = subclasses
669
+ @generics = {}
670
+ end
671
+
672
+ attr_reader :recv, :mid, :ret
673
+
674
+ def run0(genv, changes)
675
+ edges = Set[]
676
+ called_mdefs = Set[]
677
+ error_count = 0
678
+ resolve(genv, changes) do |me, ty, mid, orig_ty|
679
+ if !me
680
+ # TODO: undefined method error
681
+ if error_count < 3
682
+ meth = @node.mid_code_range ? :mid_code_range : :code_range
683
+ changes.add_diagnostic(meth, "undefined method: #{ orig_ty.show }##{ mid }")
684
+ end
685
+ error_count += 1
686
+ elsif me.builtin && me.builtin[changes, @node, orig_ty, @a_args, @ret]
687
+ # do nothing
688
+ elsif !me.decls.empty?
689
+ # TODO: support "| ..."
690
+ me.decls.each do |mdecl|
691
+ # TODO: union type is ok?
692
+ # TODO: add_depended_method_entity for types used to resolve overloads
693
+ ty_env = Type.default_param_map(genv, orig_ty)
694
+ if ty.is_a?(Type::Instance)
695
+ ty.mod.type_params.zip(ty.args) do |param, arg|
696
+ ty_env[param] = arg
697
+ end
698
+ end
699
+ mdecl.resolve_overloads(changes, genv, @node, ty_env, @a_args, @ret) do |method_type|
700
+ @generics[method_type] ||= method_type.type_params.map {|var| Vertex.new(@node) }
701
+ end
702
+ end
703
+ elsif !me.defs.empty?
704
+ me.defs.each do |mdef|
705
+ next if called_mdefs.include?(mdef)
706
+ called_mdefs << mdef
707
+ mdef.call(changes, genv, @a_args, @ret)
708
+ end
709
+ else
710
+ pp me
711
+ raise
712
+ end
713
+ end
714
+ if @subclasses
715
+ resolve_subclasses(genv, changes) do |recv_ty, me|
716
+ if !me.defs.empty?
717
+ me.defs.each do |mdef|
718
+ next if called_mdefs.include?(mdef)
719
+ called_mdefs << mdef
720
+ mdef.call(changes, genv, @a_args, @ret)
721
+ end
722
+ end
723
+ end
724
+ end
725
+ edges.each do |src, dst|
726
+ changes.add_edge(genv, src, dst)
727
+ end
728
+ if error_count > 3
729
+ meth = @node.mid_code_range ? :mid_code_range : :code_range
730
+ changes.add_diagnostic(meth, "... and other #{ error_count - 3 } errors")
731
+ end
732
+ end
733
+
734
+ def resolve(genv, changes, &blk)
735
+ @recv.each_type do |orig_ty|
736
+ next if orig_ty == Type::Bot.new(genv)
737
+ if @mid == :"*super"
738
+ mid = @node.lenv.cref.mid
739
+ skip = true
740
+ else
741
+ mid = @mid
742
+ skip = false
743
+ end
744
+
745
+ ty = orig_ty.base_type(genv)
746
+
747
+ base_ty_env = Type.default_param_map(genv, ty)
748
+
749
+ alias_limit = 0
750
+ while ty
751
+ unless skip
752
+ me = ty.mod.get_method(ty.is_a?(Type::Singleton), mid)
753
+ changes.add_depended_method_entity(me) if changes
754
+ if !me.aliases.empty?
755
+ mid = me.aliases.values.first
756
+ alias_limit += 1
757
+ redo if alias_limit < 5
758
+ end
759
+ if me.exist?
760
+ yield me, ty, mid, orig_ty
761
+ break
762
+ end
763
+ end
764
+
765
+ skip = false
766
+
767
+ if ty.is_a?(Type::Singleton)
768
+ # TODO: extended modules
769
+ else
770
+ break if resolve_included_modules(genv, changes, base_ty_env, ty, mid) do |me, ty, mid|
771
+ yield me, ty, mid, orig_ty
772
+ end
773
+ end
774
+
775
+ ty = genv.get_superclass_type(ty, changes, base_ty_env)
776
+ end
777
+
778
+ yield nil, nil, mid, orig_ty unless ty
779
+ end
780
+ end
781
+
782
+ def resolve_included_modules(genv, changes, base_ty_env, ty, mid, &blk)
783
+ found = false
784
+
785
+ alias_limit = 0
786
+ ty.mod.self_types.each do |(mdecl, idx), self_ty_mod|
787
+ raise unless mdecl.is_a?(AST::SigModuleNode)
788
+ if self_ty_mod.type_params
789
+ self_ty = genv.get_instance_type(self_ty_mod, mdecl.self_type_args[idx], changes, base_ty_env, ty)
790
+ else
791
+ self_ty = Type::Instance.new(genv, self_ty_mod, [])
792
+ end
793
+
794
+ me = self_ty.mod.get_method(false, mid)
795
+ changes.add_depended_method_entity(me) if changes
796
+ if !me.aliases.empty?
797
+ mid = me.aliases.values.first
798
+ alias_limit += 1
799
+ redo if alias_limit < 5
800
+ end
801
+ if me.exist?
802
+ found = true
803
+ yield me, self_ty, mid
804
+ else
805
+ found ||= resolve_included_modules(genv, changes, base_ty_env, self_ty, mid, &blk)
806
+ end
807
+ end
808
+
809
+ alias_limit = 0
810
+ ty.mod.included_modules.each do |inc_decl, inc_mod|
811
+ if inc_decl.is_a?(AST::SigIncludeNode) && inc_mod.type_params
812
+ inc_ty = genv.get_instance_type(inc_mod, inc_decl.args, changes, base_ty_env, ty)
813
+ else
814
+ type_params = inc_mod.type_params.map {|ty_param| Source.new() } # TODO: better support
815
+ inc_ty = Type::Instance.new(genv, inc_mod, type_params)
816
+ end
817
+
818
+ me = inc_ty.mod.get_method(false, mid)
819
+ changes.add_depended_method_entity(me) if changes
820
+ if !me.aliases.empty?
821
+ mid = me.aliases.values.first
822
+ alias_limit += 1
823
+ redo if alias_limit < 5
824
+ end
825
+ if me.exist?
826
+ found = true
827
+ yield me, inc_ty, mid
828
+ else
829
+ found ||= resolve_included_modules(genv, changes, base_ty_env, inc_ty, mid, &blk)
830
+ end
831
+ end
832
+ found
833
+ end
834
+
835
+ def resolve_subclasses(genv, changes)
836
+ # TODO: This does not follow new subclasses
837
+ @recv.each_type do |ty|
838
+ next if ty == Type::Bot.new(genv)
839
+ base_ty = ty.base_type(genv)
840
+ singleton = base_ty.is_a?(Type::Singleton)
841
+ mod = base_ty.mod
842
+ mod.each_descendant do |desc_mod|
843
+ next if mod == desc_mod
844
+ me = desc_mod.get_method(singleton, @mid)
845
+ changes.add_depended_method_entity(me)
846
+ if me && me.exist?
847
+ yield ty, me
848
+ end
849
+ end
850
+ end
851
+ end
852
+ end
853
+
854
+ class GVarReadBox < Box
855
+ def initialize(node, genv, name)
856
+ super(node)
857
+ @vtx = genv.resolve_gvar(name).vtx
858
+ @ret = Vertex.new(node)
859
+ genv.add_run(self)
860
+ end
861
+
862
+ attr_reader :node, :const_read, :ret
863
+
864
+ def run0(genv, changes)
865
+ changes.add_edge(genv, @vtx, @ret)
866
+ end
867
+ end
868
+
869
+ class IVarReadBox < Box
870
+ def initialize(node, genv, cpath, singleton, name)
871
+ super(node)
872
+ @cpath = cpath
873
+ @singleton = singleton
874
+ @name = name
875
+ genv.resolve_cpath(cpath).ivar_reads << self
876
+ @proxy = Vertex.new(node)
877
+ @ret = Vertex.new(node)
878
+ genv.add_run(self)
879
+ end
880
+
881
+ attr_reader :node, :const_read, :ret
882
+
883
+ def destroy(genv)
884
+ genv.resolve_cpath(@cpath).ivar_reads.delete(self)
885
+ super(genv)
886
+ end
887
+
888
+ def run0(genv, changes)
889
+ mod = genv.resolve_cpath(@cpath)
890
+ singleton = @singleton
891
+ cur_ive = mod.get_ivar(singleton, @name)
892
+ target_vtx = nil
893
+ genv.each_direct_superclass(mod, singleton) do |mod, singleton|
894
+ ive = mod.get_ivar(singleton, @name)
895
+ if ive.exist?
896
+ target_vtx = ive.vtx
897
+ end
898
+ end
899
+ edges = []
900
+ if target_vtx
901
+ if target_vtx != cur_ive.vtx
902
+ edges << [cur_ive.vtx, @proxy] << [@proxy, target_vtx]
903
+ end
904
+ edges << [target_vtx, @ret]
905
+ else
906
+ # TODO: error?
907
+ end
908
+ edges.each do |src, dst|
909
+ changes.add_edge(genv, src, dst)
910
+ end
911
+ end
912
+ end
913
+
914
+ class CVarReadBox < Box
915
+ def initialize(node, genv, cpath, name)
916
+ super(node)
917
+ @cpath = cpath
918
+ @name = name
919
+ genv.resolve_cpath(cpath).cvar_reads << self
920
+ @proxy = Vertex.new(node)
921
+ @ret = Vertex.new(node)
922
+ genv.add_run(self)
923
+ end
924
+
925
+ attr_reader :node, :const_read, :ret
926
+
927
+ def destroy(genv)
928
+ genv.resolve_cpath(@cpath).cvar_reads.delete(self)
929
+ super(genv)
930
+ end
931
+
932
+ def run0(genv, changes)
933
+ mod = genv.resolve_cpath(@cpath)
934
+ cur_cve = mod.get_cvar(@name)
935
+ target_vtx = nil
936
+ genv.each_direct_superclass(mod, nil) do |mod, _|
937
+ cve = mod.get_cvar(@name)
938
+ if cve.exist?
939
+ target_vtx = cve.vtx
940
+ end
941
+ end
942
+
943
+ edges = []
944
+ if target_vtx
945
+ if target_vtx != cur_cve.vtx
946
+ edges << [cur_cve.vtx, @proxy] << [@proxy, target_vtx]
947
+ end
948
+ edges << [target_vtx, @ret]
949
+ end
950
+
951
+ edges.each do |src, dst|
952
+ changes.add_edge(genv, src, dst)
953
+ end
954
+ end
955
+ end
956
+
957
+ class MAsgnBox < Box
958
+ def initialize(node, genv, value, lefts, rest_elem, rights)
959
+ super(node)
960
+ @value = value
961
+ @lefts = lefts
962
+ @rest_elem = rest_elem
963
+ @rights = rights
964
+ @value.add_edge(genv, self)
965
+ end
966
+
967
+ attr_reader :node, :value, :lefts, :rest_elem, :rights
968
+
969
+ def destroy(genv)
970
+ @value.remove_edge(genv, self) # TODO: Is this really needed?
971
+ super(genv)
972
+ end
973
+
974
+ def ret = @rhs
975
+
976
+ def run0(genv, changes)
977
+ edges = []
978
+ @value.each_type do |ty|
979
+ # TODO: call to_ary?
980
+ case ty
981
+ when Type::Array
982
+ edges.concat(ty.splat_assign(genv, @lefts, @rest_elem, @rights))
983
+ else
984
+ if @lefts.size >= 1
985
+ edges << [Source.new(ty), @lefts[0]]
986
+ elsif @rights.size >= 1
987
+ edges << [Source.new(ty), @rights[0]]
988
+ else
989
+ edges << [Source.new(ty), @rest_elem]
990
+ end
991
+ end
992
+ end
993
+ edges.each do |src, dst|
994
+ changes.add_edge(genv, src, dst)
995
+ end
996
+ end
997
+ end
998
+ end