typeprof 0.21.11 → 0.30.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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