typeprof 0.21.11 → 0.30.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (73) 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 +180 -0
  7. data/lib/typeprof/cli.rb +2 -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 +251 -0
  11. data/lib/typeprof/core/ast/const.rb +126 -0
  12. data/lib/typeprof/core/ast/control.rb +432 -0
  13. data/lib/typeprof/core/ast/meta.rb +150 -0
  14. data/lib/typeprof/core/ast/method.rb +335 -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 +360 -0
  31. data/lib/typeprof/core/graph/box.rb +991 -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 +222 -0
  35. data/lib/typeprof/core/graph.rb +3 -0
  36. data/lib/typeprof/core/service.rb +522 -0
  37. data/lib/typeprof/core/type.rb +348 -0
  38. data/lib/typeprof/core/util.rb +81 -0
  39. data/lib/typeprof/core.rb +32 -0
  40. data/lib/typeprof/diagnostic.rb +35 -0
  41. data/lib/typeprof/lsp/messages.rb +430 -0
  42. data/lib/typeprof/lsp/server.rb +177 -0
  43. data/lib/typeprof/lsp/text.rb +69 -0
  44. data/lib/typeprof/lsp/util.rb +61 -0
  45. data/lib/typeprof/lsp.rb +4 -907
  46. data/lib/typeprof/version.rb +1 -1
  47. data/lib/typeprof.rb +4 -18
  48. data/typeprof.gemspec +5 -7
  49. metadata +48 -35
  50. data/.github/dependabot.yml +0 -6
  51. data/.github/workflows/main.yml +0 -39
  52. data/.gitignore +0 -9
  53. data/Gemfile +0 -17
  54. data/Gemfile.lock +0 -41
  55. data/Rakefile +0 -10
  56. data/exe/typeprof +0 -10
  57. data/lib/typeprof/analyzer.rb +0 -2598
  58. data/lib/typeprof/arguments.rb +0 -414
  59. data/lib/typeprof/block.rb +0 -176
  60. data/lib/typeprof/builtin.rb +0 -893
  61. data/lib/typeprof/code-range.rb +0 -177
  62. data/lib/typeprof/config.rb +0 -158
  63. data/lib/typeprof/container-type.rb +0 -912
  64. data/lib/typeprof/export.rb +0 -589
  65. data/lib/typeprof/import.rb +0 -852
  66. data/lib/typeprof/insns-def.rb +0 -65
  67. data/lib/typeprof/iseq.rb +0 -864
  68. data/lib/typeprof/method.rb +0 -355
  69. data/lib/typeprof/type.rb +0 -1140
  70. data/lib/typeprof/utils.rb +0 -212
  71. data/tools/coverage.rb +0 -14
  72. data/tools/setup-insns-def.rb +0 -30
  73. data/typeprof-lsp +0 -3
@@ -0,0 +1,991 @@
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
+ changes.add_edge(genv, vtx, @f_args.rest_positionals)
489
+ end
490
+ end
491
+ else
492
+ # there is no splat actual argument
493
+
494
+ lower = @f_args.req_positionals.size + @f_args.post_positionals.size
495
+ upper = @f_args.rest_positionals ? nil : lower + @f_args.opt_positionals.size
496
+ if a_args.positionals.size < lower || (upper && upper < a_args.positionals.size)
497
+ meth = changes.node.mid_code_range ? :mid_code_range : :code_range
498
+ err = "#{ a_args.positionals.size } for #{ lower }#{ upper ? lower < upper ? "...#{ upper }" : "" : "+" }"
499
+ changes.add_diagnostic(meth, "wrong number of arguments (#{ err })")
500
+ return false
501
+ end
502
+
503
+ @f_args.req_positionals.each_with_index do |f_vtx, i|
504
+ changes.add_edge(genv, a_args.positionals[i], f_vtx)
505
+ end
506
+ @f_args.post_positionals.each_with_index do |f_vtx, i|
507
+ i -= @f_args.post_positionals.size
508
+ changes.add_edge(genv, a_args.positionals[i], f_vtx)
509
+ end
510
+ start_rest = @f_args.req_positionals.size
511
+ end_rest = a_args.positionals.size - @f_args.post_positionals.size
512
+ i = 0
513
+ while i < @f_args.opt_positionals.size && start_rest < end_rest
514
+ f_arg = @f_args.opt_positionals[i]
515
+ changes.add_edge(genv, a_args.positionals[start_rest], f_arg)
516
+ i += 1
517
+ start_rest += 1
518
+ end
519
+
520
+ if start_rest < end_rest
521
+ if @f_args.rest_positionals
522
+ f_arg = @f_args.rest_positionals
523
+ (start_rest..end_rest-1).each do |i|
524
+ changes.add_edge(genv, a_args.positionals[i], f_arg)
525
+ end
526
+ end
527
+ end
528
+ end
529
+
530
+ if a_args.keywords
531
+ # TODO: support diagnostics
532
+ @node.req_keywords.zip(@f_args.req_keywords) do |name, f_vtx|
533
+ changes.add_edge(genv, a_args.get_keyword_arg(genv, changes, name), f_vtx)
534
+ end
535
+
536
+ @node.opt_keywords.zip(@f_args.opt_keywords).each do |name, f_vtx|
537
+ changes.add_edge(genv, a_args.get_keyword_arg(genv, changes, name), f_vtx)
538
+ end
539
+
540
+ if @node.rest_keywords
541
+ # FIXME: Extract the rest keywords excluding req_keywords and opt_keywords.
542
+ changes.add_edge(genv, a_args.keywords, @f_args.rest_keywords)
543
+ end
544
+ end
545
+
546
+ return true
547
+ end
548
+
549
+ def call(changes, genv, a_args, ret)
550
+ if pass_arguments(changes, genv, a_args)
551
+ changes.add_edge(genv, a_args.block, @f_args.block) if @f_args.block && a_args.block
552
+
553
+ changes.add_edge(genv, @ret, ret)
554
+ end
555
+ end
556
+
557
+ def show(output_parameter_names)
558
+ block_show = []
559
+ if @record_block.used
560
+ blk_f_args = @record_block.f_args.map {|arg| arg.show }.join(", ")
561
+ blk_ret = @record_block.ret.show
562
+ block_show << "{ (#{ blk_f_args }) -> #{ blk_ret } }"
563
+ end
564
+ args = []
565
+ @f_args.req_positionals.each do |f_vtx|
566
+ args << Type.strip_parens(f_vtx.show)
567
+ end
568
+ @f_args.opt_positionals.each do |f_vtx|
569
+ args << ("?" + Type.strip_parens(f_vtx.show))
570
+ end
571
+ if @f_args.rest_positionals
572
+ args << ("*" + Type.strip_parens(@f_args.rest_positionals.show))
573
+ end
574
+ @f_args.post_positionals.each do |var|
575
+ args << Type.strip_parens(var.show)
576
+ end
577
+ if @node.is_a?(AST::DefNode)
578
+ @node.req_keywords.zip(@f_args.req_keywords) do |name, f_vtx|
579
+ args << "#{ name }: #{Type.strip_parens(f_vtx.show)}"
580
+ end
581
+ @node.opt_keywords.zip(@f_args.opt_keywords) do |name, f_vtx|
582
+ args << "?#{ name }: #{Type.strip_parens(f_vtx.show)}"
583
+ end
584
+ end
585
+ if @f_args.rest_keywords
586
+ args << "**#{ Type.strip_parens(@f_args.rest_keywords.show) }"
587
+ end
588
+
589
+ if output_parameter_names && @node.is_a?(AST::DefNode)
590
+ names = []
591
+ names.concat(@node.req_positionals)
592
+ names.concat(@node.opt_positionals)
593
+ names.concat(@node.rest_positionals) if @node.rest_positionals
594
+ names.concat(@node.post_positionals)
595
+ names.concat(@node.req_keywords)
596
+ names.concat(@node.opt_keywords)
597
+ names.concat(@node.rest_keywords) if @node.rest_keywords
598
+ args = args.zip(names).map do |arg, name|
599
+ name ? "#{ arg } #{ name }" : arg
600
+ end
601
+ end
602
+
603
+ args = args.join(", ")
604
+ s = args.empty? ? [] : ["(#{ args })"]
605
+ s << "#{ block_show.sort.join(" | ") }" unless block_show.empty?
606
+ s << "-> #{ @ret.show }"
607
+ s.join(" ")
608
+ end
609
+ end
610
+
611
+ class MethodAliasBox < Box
612
+ def initialize(node, genv, cpath, singleton, new_mid, old_mid)
613
+ super(node)
614
+ @cpath = cpath
615
+ @singleton = singleton
616
+ @new_mid = new_mid
617
+ @old_mid = old_mid
618
+ @ret = Source.new(genv.nil_type)
619
+
620
+ me = genv.resolve_method(@cpath, @singleton, @new_mid)
621
+ me.add_alias(self, @old_mid)
622
+ if me.decls.empty?
623
+ me.add_run_all_method_call_boxes(genv)
624
+ else
625
+ genv.add_run(self)
626
+ end
627
+ end
628
+
629
+ attr_accessor :node
630
+
631
+ attr_reader :cpath, :singleton, :new_mid, :old_mid, :ret
632
+
633
+ def destroy(genv)
634
+ me = genv.resolve_method(@cpath, @singleton, @new_mid)
635
+ me.remove_alias(self)
636
+ if me.decls.empty?
637
+ me.add_run_all_method_call_boxes(genv)
638
+ else
639
+ genv.add_run(self)
640
+ end
641
+ super(genv)
642
+ end
643
+
644
+ def run0(genv, changes)
645
+ # TODO: what to do?
646
+ end
647
+ end
648
+
649
+ class MethodCallBox < Box
650
+ def initialize(node, genv, recv, mid, a_args, subclasses)
651
+ raise mid.to_s unless mid
652
+ super(node)
653
+ @recv = recv.new_vertex(genv, node)
654
+ @recv.add_edge(genv, self)
655
+ @mid = mid
656
+ @a_args = a_args.new_vertexes(genv, node)
657
+ @a_args.positionals.each {|arg| arg.add_edge(genv, self) }
658
+ @a_args.keywords.add_edge(genv, self) if @a_args.keywords
659
+ @a_args.block.add_edge(genv, self) if @a_args.block
660
+ @ret = Vertex.new(node)
661
+ @subclasses = subclasses
662
+ @generics = {}
663
+ end
664
+
665
+ attr_reader :recv, :mid, :ret
666
+
667
+ def run0(genv, changes)
668
+ edges = Set[]
669
+ called_mdefs = Set[]
670
+ error_count = 0
671
+ resolve(genv, changes) do |me, ty, mid, orig_ty|
672
+ if !me
673
+ # TODO: undefined method error
674
+ if error_count < 3
675
+ meth = @node.mid_code_range ? :mid_code_range : :code_range
676
+ changes.add_diagnostic(meth, "undefined method: #{ orig_ty.show }##{ mid }")
677
+ end
678
+ error_count += 1
679
+ elsif me.builtin && me.builtin[changes, @node, orig_ty, @a_args, @ret]
680
+ # do nothing
681
+ elsif !me.decls.empty?
682
+ # TODO: support "| ..."
683
+ me.decls.each do |mdecl|
684
+ # TODO: union type is ok?
685
+ # TODO: add_depended_method_entity for types used to resolve overloads
686
+ ty_env = Type.default_param_map(genv, orig_ty)
687
+ if ty.is_a?(Type::Instance)
688
+ ty.mod.type_params.zip(ty.args) do |param, arg|
689
+ ty_env[param] = arg
690
+ end
691
+ end
692
+ mdecl.resolve_overloads(changes, genv, @node, ty_env, @a_args, @ret) do |method_type|
693
+ @generics[method_type] ||= method_type.type_params.map {|var| Vertex.new(@node) }
694
+ end
695
+ end
696
+ elsif !me.defs.empty?
697
+ me.defs.each do |mdef|
698
+ next if called_mdefs.include?(mdef)
699
+ called_mdefs << mdef
700
+ mdef.call(changes, genv, @a_args, @ret)
701
+ end
702
+ else
703
+ pp me
704
+ raise
705
+ end
706
+ end
707
+ if @subclasses
708
+ resolve_subclasses(genv, changes) do |recv_ty, me|
709
+ if !me.defs.empty?
710
+ me.defs.each do |mdef|
711
+ next if called_mdefs.include?(mdef)
712
+ called_mdefs << mdef
713
+ mdef.call(changes, genv, @a_args, @ret)
714
+ end
715
+ end
716
+ end
717
+ end
718
+ edges.each do |src, dst|
719
+ changes.add_edge(genv, src, dst)
720
+ end
721
+ if error_count > 3
722
+ meth = @node.mid_code_range ? :mid_code_range : :code_range
723
+ changes.add_diagnostic(meth, "... and other #{ error_count - 3 } errors")
724
+ end
725
+ end
726
+
727
+ def resolve(genv, changes, &blk)
728
+ @recv.each_type do |orig_ty|
729
+ next if orig_ty == Type::Bot.new(genv)
730
+ if @mid == :"*super"
731
+ mid = @node.lenv.cref.mid
732
+ skip = true
733
+ else
734
+ mid = @mid
735
+ skip = false
736
+ end
737
+
738
+ ty = orig_ty.base_type(genv)
739
+
740
+ base_ty_env = Type.default_param_map(genv, ty)
741
+
742
+ alias_limit = 0
743
+ while ty
744
+ unless skip
745
+ me = ty.mod.get_method(ty.is_a?(Type::Singleton), mid)
746
+ changes.add_depended_method_entity(me) if changes
747
+ if !me.aliases.empty?
748
+ mid = me.aliases.values.first
749
+ alias_limit += 1
750
+ redo if alias_limit < 5
751
+ end
752
+ if me.exist?
753
+ yield me, ty, mid, orig_ty
754
+ break
755
+ end
756
+ end
757
+
758
+ skip = false
759
+
760
+ if ty.is_a?(Type::Singleton)
761
+ # TODO: extended modules
762
+ else
763
+ break if resolve_included_modules(genv, changes, base_ty_env, ty, mid) do |me, ty, mid|
764
+ yield me, ty, mid, orig_ty
765
+ end
766
+ end
767
+
768
+ ty = genv.get_superclass_type(ty, changes, base_ty_env)
769
+ end
770
+
771
+ yield nil, nil, mid, orig_ty unless ty
772
+ end
773
+ end
774
+
775
+ def resolve_included_modules(genv, changes, base_ty_env, ty, mid, &blk)
776
+ found = false
777
+
778
+ alias_limit = 0
779
+ ty.mod.self_types.each do |(mdecl, idx), self_ty_mod|
780
+ raise unless mdecl.is_a?(AST::SigModuleNode)
781
+ if self_ty_mod.type_params
782
+ self_ty = genv.get_instance_type(self_ty_mod, mdecl.self_type_args[idx], changes, base_ty_env, ty)
783
+ else
784
+ self_ty = Type::Instance.new(genv, self_ty_mod, [])
785
+ end
786
+
787
+ me = self_ty.mod.get_method(false, mid)
788
+ changes.add_depended_method_entity(me) if changes
789
+ if !me.aliases.empty?
790
+ mid = me.aliases.values.first
791
+ alias_limit += 1
792
+ redo if alias_limit < 5
793
+ end
794
+ if me.exist?
795
+ found = true
796
+ yield me, self_ty, mid
797
+ else
798
+ found ||= resolve_included_modules(genv, changes, base_ty_env, self_ty, mid, &blk)
799
+ end
800
+ end
801
+
802
+ alias_limit = 0
803
+ ty.mod.included_modules.each do |inc_decl, inc_mod|
804
+ if inc_decl.is_a?(AST::SigIncludeNode) && inc_mod.type_params
805
+ inc_ty = genv.get_instance_type(inc_mod, inc_decl.args, changes, base_ty_env, ty)
806
+ else
807
+ type_params = inc_mod.type_params.map {|ty_param| Source.new() } # TODO: better support
808
+ inc_ty = Type::Instance.new(genv, inc_mod, type_params)
809
+ end
810
+
811
+ me = inc_ty.mod.get_method(false, mid)
812
+ changes.add_depended_method_entity(me) if changes
813
+ if !me.aliases.empty?
814
+ mid = me.aliases.values.first
815
+ alias_limit += 1
816
+ redo if alias_limit < 5
817
+ end
818
+ if me.exist?
819
+ found = true
820
+ yield me, inc_ty, mid
821
+ else
822
+ found ||= resolve_included_modules(genv, changes, base_ty_env, inc_ty, mid, &blk)
823
+ end
824
+ end
825
+ found
826
+ end
827
+
828
+ def resolve_subclasses(genv, changes)
829
+ # TODO: This does not follow new subclasses
830
+ @recv.each_type do |ty|
831
+ next if ty == Type::Bot.new(genv)
832
+ base_ty = ty.base_type(genv)
833
+ singleton = base_ty.is_a?(Type::Singleton)
834
+ mod = base_ty.mod
835
+ mod.each_descendant do |desc_mod|
836
+ next if mod == desc_mod
837
+ me = desc_mod.get_method(singleton, @mid)
838
+ changes.add_depended_method_entity(me)
839
+ if me && me.exist?
840
+ yield ty, me
841
+ end
842
+ end
843
+ end
844
+ end
845
+ end
846
+
847
+ class GVarReadBox < Box
848
+ def initialize(node, genv, name)
849
+ super(node)
850
+ @vtx = genv.resolve_gvar(name).vtx
851
+ @ret = Vertex.new(node)
852
+ genv.add_run(self)
853
+ end
854
+
855
+ attr_reader :node, :const_read, :ret
856
+
857
+ def run0(genv, changes)
858
+ changes.add_edge(genv, @vtx, @ret)
859
+ end
860
+ end
861
+
862
+ class IVarReadBox < Box
863
+ def initialize(node, genv, cpath, singleton, name)
864
+ super(node)
865
+ @cpath = cpath
866
+ @singleton = singleton
867
+ @name = name
868
+ genv.resolve_cpath(cpath).ivar_reads << self
869
+ @proxy = Vertex.new(node)
870
+ @ret = Vertex.new(node)
871
+ genv.add_run(self)
872
+ end
873
+
874
+ attr_reader :node, :const_read, :ret
875
+
876
+ def destroy(genv)
877
+ genv.resolve_cpath(@cpath).ivar_reads.delete(self)
878
+ super(genv)
879
+ end
880
+
881
+ def run0(genv, changes)
882
+ mod = genv.resolve_cpath(@cpath)
883
+ singleton = @singleton
884
+ cur_ive = mod.get_ivar(singleton, @name)
885
+ target_vtx = nil
886
+ genv.each_direct_superclass(mod, singleton) do |mod, singleton|
887
+ ive = mod.get_ivar(singleton, @name)
888
+ if ive.exist?
889
+ target_vtx = ive.vtx
890
+ end
891
+ end
892
+ edges = []
893
+ if target_vtx
894
+ if target_vtx != cur_ive.vtx
895
+ edges << [cur_ive.vtx, @proxy] << [@proxy, target_vtx]
896
+ end
897
+ edges << [target_vtx, @ret]
898
+ else
899
+ # TODO: error?
900
+ end
901
+ edges.each do |src, dst|
902
+ changes.add_edge(genv, src, dst)
903
+ end
904
+ end
905
+ end
906
+
907
+ class CVarReadBox < Box
908
+ def initialize(node, genv, cpath, name)
909
+ super(node)
910
+ @cpath = cpath
911
+ @name = name
912
+ genv.resolve_cpath(cpath).cvar_reads << self
913
+ @proxy = Vertex.new(node)
914
+ @ret = Vertex.new(node)
915
+ genv.add_run(self)
916
+ end
917
+
918
+ attr_reader :node, :const_read, :ret
919
+
920
+ def destroy(genv)
921
+ genv.resolve_cpath(@cpath).cvar_reads.delete(self)
922
+ super(genv)
923
+ end
924
+
925
+ def run0(genv, changes)
926
+ mod = genv.resolve_cpath(@cpath)
927
+ cur_cve = mod.get_cvar(@name)
928
+ target_vtx = nil
929
+ genv.each_direct_superclass(mod, nil) do |mod, _|
930
+ cve = mod.get_cvar(@name)
931
+ if cve.exist?
932
+ target_vtx = cve.vtx
933
+ end
934
+ end
935
+
936
+ edges = []
937
+ if target_vtx
938
+ if target_vtx != cur_cve.vtx
939
+ edges << [cur_cve.vtx, @proxy] << [@proxy, target_vtx]
940
+ end
941
+ edges << [target_vtx, @ret]
942
+ end
943
+
944
+ edges.each do |src, dst|
945
+ changes.add_edge(genv, src, dst)
946
+ end
947
+ end
948
+ end
949
+
950
+ class MAsgnBox < Box
951
+ def initialize(node, genv, value, lefts, rest_elem, rights)
952
+ super(node)
953
+ @value = value
954
+ @lefts = lefts
955
+ @rest_elem = rest_elem
956
+ @rights = rights
957
+ @value.add_edge(genv, self)
958
+ end
959
+
960
+ attr_reader :node, :value, :lefts, :rest_elem, :rights
961
+
962
+ def destroy(genv)
963
+ @value.remove_edge(genv, self) # TODO: Is this really needed?
964
+ super(genv)
965
+ end
966
+
967
+ def ret = @rhs
968
+
969
+ def run0(genv, changes)
970
+ edges = []
971
+ @value.each_type do |ty|
972
+ # TODO: call to_ary?
973
+ case ty
974
+ when Type::Array
975
+ edges.concat(ty.splat_assign(genv, @lefts, @rest_elem, @rights))
976
+ else
977
+ if @lefts.size >= 1
978
+ edges << [Source.new(ty), @lefts[0]]
979
+ elsif @rights.size >= 1
980
+ edges << [Source.new(ty), @rights[0]]
981
+ else
982
+ edges << [Source.new(ty), @rest_elem]
983
+ end
984
+ end
985
+ end
986
+ edges.each do |src, dst|
987
+ changes.add_edge(genv, src, dst)
988
+ end
989
+ end
990
+ end
991
+ end