typeprof 0.21.11 → 0.30.1

Sign up to get free protection for your applications and to get access to all the features.
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