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
@@ -1,2598 +0,0 @@
1
- module TypeProf
2
- class CRef
3
- include Utils::StructuralEquality
4
-
5
- def initialize(outer, klass, singleton)
6
- @outer = outer
7
- @klass = klass
8
- @singleton = singleton
9
- # flags
10
- # scope_visi (= method_visi * module_func_flag)
11
- # refinements
12
- end
13
-
14
- def extend(klass, singleton)
15
- CRef.new(self, klass, singleton)
16
- end
17
-
18
- attr_reader :outer, :klass, :singleton
19
-
20
- def pretty_print(q)
21
- q.text "CRef["
22
- q.pp @klass
23
- q.text "]"
24
- end
25
- end
26
-
27
- class Context
28
- include Utils::StructuralEquality
29
-
30
- def initialize(iseq, cref, mid)
31
- @iseq = iseq
32
- @cref = cref
33
- @mid = mid
34
- end
35
-
36
- attr_reader :iseq, :cref, :mid
37
-
38
- def source_location(pc)
39
- if @iseq
40
- @iseq.source_location(pc)
41
- else
42
- "<builtin>"
43
- end
44
- end
45
-
46
- def detailed_source_location(pc)
47
- if @iseq
48
- @iseq.detailed_source_location(pc)
49
- else
50
- nil
51
- end
52
- end
53
-
54
- def replace_cref(cref)
55
- Context.new(@iseq, cref, @mid)
56
- end
57
- end
58
-
59
- class TypedContext
60
- include Utils::StructuralEquality
61
-
62
- def initialize(caller_ep, mid)
63
- @caller_ep = caller_ep
64
- @mid = mid
65
- end
66
-
67
- attr_reader :caller_ep, :mid
68
-
69
- def source_location(_pc)
70
- if @caller_ep
71
- @caller_ep.source_location
72
- else
73
- "<typed-context:#{ @mid }>"
74
- end
75
- end
76
-
77
- def detailed_source_location(_pc)
78
- if @caller_ep
79
- @caller_ep.source_location
80
- else
81
- nil
82
- end
83
- end
84
-
85
- def replace_cref(cref)
86
- # What to do?
87
- end
88
- end
89
-
90
- class ExecutionPoint
91
- include Utils::StructuralEquality
92
-
93
- def initialize(ctx, pc, outer)
94
- @ctx = ctx
95
- @pc = pc
96
- @outer = outer
97
- end
98
-
99
- def key
100
- [@ctx.iseq, @pc]
101
- end
102
-
103
- attr_reader :ctx, :pc, :outer
104
-
105
- def jump(pc)
106
- ExecutionPoint.new(@ctx, pc, @outer)
107
- end
108
-
109
- def next
110
- ExecutionPoint.new(@ctx, @pc + 1, @outer)
111
- end
112
-
113
- def replace_cref(cref)
114
- ExecutionPoint.new(@ctx.replace_cref(cref), @pc, @outer)
115
- end
116
-
117
- def source_location
118
- @ctx.source_location(@pc)
119
- end
120
-
121
- def detailed_source_location
122
- @ctx.detailed_source_location(@pc)
123
- end
124
-
125
- def absolute_path
126
- @ctx.iseq.absolute_path
127
- end
128
- end
129
-
130
- class StaticEnv
131
- include Utils::StructuralEquality
132
-
133
- def initialize(recv_ty, blk_ty, mod_func, pub_meth)
134
- @recv_ty = recv_ty
135
- @blk_ty = blk_ty
136
- @mod_func = mod_func
137
- @pub_meth = pub_meth
138
-
139
- return if recv_ty == :top #OK
140
- recv_ty.each_child_global do |ty|
141
- raise ty.inspect if !ty.is_a?(Type::Instance) && !ty.is_a?(Type::Class) && !ty.is_a?(Type::Symbol) && ty != Type.any
142
- end
143
- end
144
-
145
- attr_reader :recv_ty, :blk_ty, :mod_func, :pub_meth
146
-
147
- def merge(other)
148
- recv_ty = @recv_ty.union(other.recv_ty)
149
- blk_ty = @blk_ty.union(other.blk_ty)
150
- mod_func = @mod_func & other.mod_func # ??
151
- pub_meth = @pub_meth & other.pub_meth # ??
152
- StaticEnv.new(recv_ty, blk_ty, mod_func, pub_meth)
153
- end
154
- end
155
-
156
- class Env
157
- include Utils::StructuralEquality
158
-
159
- def initialize(static_env, locals, stack, type_params)
160
- @static_env = static_env
161
- @locals = locals
162
- @stack = stack
163
- @type_params = type_params
164
- end
165
-
166
- attr_reader :static_env, :locals, :stack, :type_params
167
-
168
- def merge(other)
169
- raise if @locals.size != other.locals.size
170
- raise if @stack.size != other.stack.size
171
- static_env = @static_env.merge(other.static_env)
172
- locals = []
173
- @locals.zip(other.locals) {|ty1, ty2| locals << ty1.union(ty2) }
174
- stack = []
175
- @stack.zip(other.stack) {|ty1, ty2| stack << ty1.union(ty2) }
176
- if @type_params
177
- raise if !other.type_params
178
- if @type_params == other.type_params
179
- type_params = @type_params
180
- else
181
- type_params = @type_params.internal_hash.dup
182
- other.type_params.internal_hash.each do |id, elems|
183
- elems2 = type_params[id]
184
- if elems2
185
- if elems != elems2
186
- type_params[id] = elems.union(elems2)
187
- end
188
- else
189
- type_params[id] = elems
190
- end
191
- end
192
- type_params = Utils::HashWrapper.new(type_params)
193
- end
194
- else
195
- raise if other.type_params
196
- end
197
- Env.new(static_env, locals, stack, type_params)
198
- end
199
-
200
- def push(*tys)
201
- tys.each do |ty|
202
- raise "nil cannot be pushed to the stack" if ty.nil?
203
- ty.each_child do |ty|
204
- raise if ty.is_a?(Type::Var)
205
- #raise if ty.is_a?(Type::Instance) && ty.klass.type_params.size > 1
206
- raise "Array cannot be pushed to the stack" if ty.is_a?(Type::Array)
207
- raise "Hash cannot be pushed to the stack" if ty.is_a?(Type::Hash)
208
- end
209
- end
210
- Env.new(@static_env, @locals, @stack + tys, @type_params)
211
- end
212
-
213
- def pop(n)
214
- stack = @stack.dup
215
- tys = stack.pop(n)
216
- nenv = Env.new(@static_env, @locals, stack, @type_params)
217
- return nenv, tys
218
- end
219
-
220
- def setn(i, ty)
221
- stack = Utils.array_update(@stack, -i, ty)
222
- Env.new(@static_env, @locals, stack, @type_params)
223
- end
224
-
225
- def topn(i)
226
- push(@stack[-i - 1])
227
- end
228
-
229
- def get_local(idx)
230
- @locals[idx]
231
- end
232
-
233
- def local_update(idx, ty)
234
- Env.new(@static_env, Utils.array_update(@locals, idx, ty), @stack, @type_params)
235
- end
236
-
237
- def get_container_elem_types(id)
238
- @type_params.internal_hash[id]
239
- end
240
-
241
- def deploy_type(id, elems)
242
- type_params = Utils::HashWrapper.new(@type_params.internal_hash.merge({ id => elems }))
243
- Env.new(@static_env, @locals, @stack, type_params)
244
- end
245
-
246
- def enable_module_function
247
- senv = StaticEnv.new(@static_env.recv_ty, @static_env.blk_ty, true, @static_env.pub_meth)
248
- Env.new(senv, @locals, @stack, @type_params)
249
- end
250
-
251
- def method_public_set(flag)
252
- senv = StaticEnv.new(@static_env.recv_ty, @static_env.blk_ty, @static_env.mod_func, flag)
253
- Env.new(senv, @locals, @stack, @type_params)
254
- end
255
-
256
- def replace_recv_ty(ty)
257
- senv = StaticEnv.new(ty, @static_env.blk_ty, @static_env.mod_func, @static_env.pub_meth)
258
- Env.new(senv, @locals, @stack, @type_params)
259
- end
260
-
261
- def replace_blk_ty(ty)
262
- senv = StaticEnv.new(@static_env.recv_ty, ty, @static_env.mod_func, @static_env.pub_meth)
263
- Env.new(senv, @locals, @stack, @type_params)
264
- end
265
-
266
- def inspect
267
- "Env[#{ @static_env.inspect }, locals:#{ @locals.inspect }, stack:#{ @stack.inspect }, type_params:#{ (@type_params&.internal_hash).inspect }]"
268
- end
269
- end
270
-
271
- class Scratch
272
- def inspect
273
- "#<Scratch>"
274
- end
275
-
276
- def initialize
277
- @entrypoints = []
278
-
279
- @worklist = Utils::WorkList.new
280
-
281
- @ep2env = {}
282
-
283
- @class_defs = {}
284
- @struct_defs = {}
285
-
286
- @iseq_method_to_ctxs = {}
287
-
288
- @alloc_site_to_global_id = {}
289
-
290
- @callsites, @return_envs = {}, {}
291
- @block_to_ctx = {}
292
- @method_signatures = {}
293
- @block_signatures = {}
294
- @return_values = {}
295
- @gvar_table = VarTable.new
296
-
297
- @errors = []
298
- @reveal_types = {}
299
- @backward_edges = {}
300
-
301
- @pending_execution = {}
302
- @executed_iseqs = Utils::MutableSet.new
303
-
304
- @loaded_files = {}
305
-
306
- @rbs_reader = RBSReader.new
307
-
308
- @terminated = false
309
-
310
- @anonymous_struct_gen_id = 0
311
-
312
- @types_being_shown = []
313
- @namespace = nil
314
-
315
- @lsp_completion = nil
316
- @lsp_signature_help = CodeRangeTable.new
317
- end
318
-
319
- def add_entrypoint(iseq)
320
- @entrypoints << iseq
321
- end
322
-
323
- attr_reader :return_envs, :loaded_files, :rbs_reader
324
-
325
- def get_env(ep)
326
- @ep2env[ep]
327
- end
328
-
329
- def merge_env(ep, env)
330
- # TODO: this is wrong; it include not only proceeds but also indirect propagation like out-of-block variable modification
331
- #add_edge(ep, @ep)
332
- env2 = @ep2env[ep]
333
- if env2
334
- nenv = env2.merge(env)
335
- if nenv != env2 && !@worklist.member?(ep)
336
- @worklist.insert(ep.key, ep)
337
- end
338
- @ep2env[ep] = nenv
339
- else
340
- @worklist.insert(ep.key, ep)
341
- @ep2env[ep] = env
342
- end
343
- end
344
-
345
- attr_reader :class_defs
346
-
347
- class ClassDef # or ModuleDef
348
- def initialize(kind, name, absolute_path, superclass)
349
- raise unless name.is_a?(Array)
350
- @kind = kind
351
- @modules = {
352
- :before => { true => [], false => [] }, # before = include/extend
353
- :after => { true => [], false => [] }, # after = prepend
354
- }
355
- @name = name
356
- @consts = {}
357
- @methods = {}
358
- @ivars = VarTable.new
359
- @cvars = VarTable.new
360
- @absolute_path = absolute_path
361
- @namespace = nil
362
- @superclass = superclass
363
- @subclasses = []
364
- end
365
-
366
- attr_reader :kind, :modules, :methods, :ivars, :cvars, :absolute_path, :superclass, :subclasses
367
- attr_accessor :name, :klass_obj
368
-
369
- def mix_module(kind, mod, type_args, singleton, absolute_path)
370
- mod_, module_type_args, absolute_paths = @modules[kind][singleton].find {|m,| m == mod }
371
- if mod_
372
- raise "inconsistent #{ kind == :after ? "include/extend" : "prepend" } type args in RBS?" if module_type_args != type_args && type_args != [] && type_args != nil
373
- else
374
- absolute_paths = Utils::MutableSet.new
375
- @modules[kind][singleton].unshift([mod, type_args, absolute_paths])
376
- end
377
- absolute_paths << absolute_path
378
- end
379
-
380
- def get_constant(name)
381
- ty, locs = @consts[name]
382
- ty = ty || Type.any # XXX: warn?
383
- return ty, locs
384
- end
385
-
386
- def add_constant(name, ty, def_ep)
387
- if @consts[name]
388
- # XXX: warn!
389
- _, eps = @consts[name]
390
- @consts[name] = [ty, eps + [def_ep&.detailed_source_location]]
391
- return
392
- end
393
- @consts[name] = [ty, [def_ep&.detailed_source_location]]
394
- end
395
-
396
- def consts
397
- @consts.lazy.flat_map do |name, (ty, eps)|
398
- eps.map do |ep|
399
- [name, [ty, ep]]
400
- end
401
- end
402
- end
403
-
404
- def add_class_open(name, open_ep)
405
- ty, eps = @consts[name]
406
- raise "call this only if the class is opened more than once" if ty.nil?
407
- @consts[name] = [ty, eps + [open_ep&.detailed_source_location]]
408
- end
409
-
410
-
411
- def adjust_substitution_for_module(mods, mid, mthd, subst, &blk)
412
- mods.each do |mod_def, type_args,|
413
- if mod_def.klass_obj.type_params && type_args
414
- subst2 = {}
415
- mod_def.klass_obj.type_params.zip(type_args) do |(tyvar, *), tyarg|
416
- tyvar = Type::Var.new(tyvar)
417
- subst2[tyvar] = tyarg.substitute(subst, Config.current.options[:type_depth_limit])
418
- end
419
- mod_def.adjust_substitution(false, mid, mthd, subst2, false, &blk)
420
- end
421
- end
422
- end
423
-
424
- def adjust_substitution(singleton, mid, mthd, subst, direct, &blk)
425
- adjust_substitution_for_module(@modules[:before][singleton], mid, mthd, subst, &blk)
426
-
427
- mthds = @methods[[singleton, mid]]
428
- yield subst, direct if mthds&.include?(mthd)
429
-
430
- adjust_substitution_for_module(@modules[:after][singleton], mid, mthd, subst, &blk)
431
- end
432
-
433
- def search_method(singleton, mid, visited, &blk)
434
- # Currently, circular inclusion of modules is allowed
435
- return if visited[self]
436
- visited[self] = true
437
-
438
- @modules[:before][singleton].each do |mod_def,|
439
- mod_def.search_method(false, mid, visited, &blk)
440
- end
441
-
442
- mthds = @methods[[singleton, mid]]
443
- yield mthds, @klass_obj, singleton if mthds
444
-
445
- @modules[:after][singleton].each do |mod_def,|
446
- mod_def.search_method(false, mid, visited, &blk)
447
- end
448
- end
449
-
450
- def check_typed(mid, singleton, klass)
451
- set = @methods[[singleton, mid]]
452
- return nil unless set
453
- set = set.select {|mdef| mdef.is_a?(klass) }
454
- return nil if set.empty?
455
- return set
456
- end
457
-
458
- def check_typed_method(mid, singleton)
459
- check_typed(mid, singleton, TypedMethodDef)
460
- end
461
-
462
- def check_typed_attr(mid, singleton)
463
- check_typed(mid, singleton, TypedAttrMethodDef)
464
- end
465
-
466
- def add_method(mid, singleton, mdef)
467
- @methods[[singleton, mid]] ||= Utils::MutableSet.new
468
- @methods[[singleton, mid]] << mdef
469
- # Need to restart...?
470
- end
471
-
472
- def set_method(mid, singleton, mdef)
473
- if mdef
474
- @methods[[singleton, mid]] = Utils::MutableSet.new
475
- @methods[[singleton, mid]] << mdef
476
- else
477
- @methods.delete([singleton, mid])
478
- end
479
- end
480
- end
481
-
482
- def mix_module(kind, mixing_mod, mixed_mod, type_args, singleton, caller_ep)
483
- return if mixed_mod == Type.any
484
-
485
- mixing_mod = @class_defs[mixing_mod.idx]
486
- mixed_mod.each_child do |mixed_mod|
487
- if mixed_mod.is_a?(Type::Class)
488
- mixed_mod = @class_defs[mixed_mod.idx]
489
- if mixed_mod && mixed_mod.kind == :module
490
- mixing_mod.mix_module(kind, mixed_mod, type_args, singleton, caller_ep ? caller_ep.ctx.iseq.absolute_path : nil)
491
- else
492
- warn(caller_ep, "attempted to #{ kind == :after ? "include/extend" : "prepend" } non-module; ignored")
493
- end
494
- end
495
- end
496
- end
497
-
498
- def cbase_path(cbase)
499
- cbase && cbase.idx != 1 ? @class_defs[cbase.idx].name : []
500
- end
501
-
502
- def new_class(cbase, name, type_params, superclass, def_ep)
503
- show_name = cbase_path(cbase) + [name]
504
- idx = @class_defs.size
505
- if superclass
506
- superclass_def = @class_defs[superclass.idx] unless superclass == :__root__
507
- @class_defs[idx] = ClassDef.new(:class, show_name, def_ep&.absolute_path, superclass_def)
508
- superclass_def.subclasses << idx if superclass_def
509
- klass = Type::Class.new(:class, idx, type_params, superclass, show_name)
510
- @class_defs[idx].klass_obj = klass
511
- cbase ||= klass # for bootstrap
512
- add_constant(cbase, name, klass, def_ep)
513
- return klass
514
- else
515
- # module
516
- @class_defs[idx] = ClassDef.new(:module, show_name, def_ep&.absolute_path, nil)
517
- mod = Type::Class.new(:module, idx, type_params, nil, show_name)
518
- @class_defs[idx].klass_obj = mod
519
- add_constant(cbase, name, mod, def_ep)
520
- return mod
521
- end
522
- end
523
-
524
- def add_superclass_type_args!(klass, tyargs)
525
- klass.superclass_type_args = tyargs
526
- end
527
-
528
- def new_struct(ep)
529
- return @struct_defs[ep] if @struct_defs[ep]
530
-
531
- idx = @class_defs.size
532
- superclass = Type::Builtin[:struct]
533
- name = "AnonymousStruct_generated_#{ @anonymous_struct_gen_id += 1 }"
534
- # Should we pass a superclass here?
535
- @class_defs[idx] = ClassDef.new(:class, [name], ep.ctx.iseq.absolute_path, nil)
536
- #@class_defs[superclass.idx].subclasses << idx # needed?
537
- klass = Type::Class.new(:class, idx, [], superclass, name)
538
- add_superclass_type_args!(klass, [Type.any])
539
- @class_defs[idx].klass_obj = klass
540
-
541
- @struct_defs[ep] = klass
542
-
543
- klass
544
- end
545
-
546
- attr_accessor :namespace
547
-
548
- def get_class_name(klass)
549
- if klass == Type.any
550
- "???"
551
- else
552
- path = @class_defs[klass.idx].name
553
- if @namespace
554
- i = 0
555
- i += 1 while @namespace[i] && @namespace[i] == path[i]
556
- if path[i]
557
- path[i..].join("::")
558
- else
559
- path.last.to_s
560
- end
561
- else
562
- #"::" + path.join("::")
563
- path.join("::")
564
- end
565
- end
566
- end
567
-
568
- def adjust_substitution(klass, singleton, mid, mthd, subst, &blk)
569
- direct = true
570
- if klass.kind == :class
571
- while klass != :__root__
572
- class_def = @class_defs[klass.idx]
573
- class_def.adjust_substitution(singleton, mid, mthd, subst, direct, &blk)
574
- direct = false
575
- if klass.superclass && klass.superclass_type_args
576
- subst2 = {}
577
- klass.superclass.type_params.zip(klass.superclass_type_args) do |(tyvar, *), tyarg|
578
- tyvar = Type::Var.new(tyvar)
579
- subst2[tyvar] = tyarg.substitute(subst, Config.current.options[:type_depth_limit])
580
- end
581
- subst = subst2
582
- end
583
- klass = klass.superclass
584
- end
585
- else
586
- # module
587
- class_def = @class_defs[klass.idx]
588
- class_def.adjust_substitution(singleton, mid, mthd, subst, direct, &blk)
589
- end
590
- end
591
-
592
- def traverse_subclasses(klass, &blk)
593
- @class_defs[klass.idx].subclasses.each do |subclass|
594
- yield @class_defs[subclass]
595
- traverse_subclasses(@class_defs[subclass].klass_obj, &blk)
596
- end
597
- end
598
-
599
- def search_method(klass, singleton, mid, &blk)
600
- # XXX: support method alias correctly
601
- klass_orig = klass
602
- if klass.kind == :class
603
- while klass != :__root__
604
- class_def = @class_defs[klass.idx]
605
- class_def.search_method(singleton, mid, {}, &blk)
606
- klass = klass.superclass
607
- end
608
- else
609
- # module
610
- class_def = @class_defs[klass.idx]
611
- class_def.search_method(singleton, mid, {}, &blk)
612
- end
613
- if singleton
614
- search_method(Type::Builtin[klass_orig.kind], false, mid, &blk)
615
- end
616
- end
617
-
618
- def get_method(klass, singleton, include_subclasses, mid)
619
- if include_subclasses
620
- subclasses_mthds = []
621
- traverse_subclasses(klass) do |subclass|
622
- subclass.search_method(singleton, mid, {}) do |mthds,|
623
- subclasses_mthds.concat(mthds.to_a)
624
- end
625
- end
626
- search_method(klass, singleton, mid) {|mthds,| return subclasses_mthds + mthds.to_a }
627
- return subclasses_mthds
628
- end
629
-
630
- search_method(klass, singleton, mid) {|mthds,| return mthds }
631
- end
632
-
633
- def get_all_super_methods(klass, singleton, current_klass, mid)
634
- hit = false
635
- search_method(klass, singleton, mid) do |mthds, klass0, singleton0|
636
- yield mthds, klass0, singleton0 if hit
637
- hit = klass0 == current_klass
638
- end
639
- end
640
-
641
- def get_super_method(ctx, singleton)
642
- klass = ctx.cref.klass
643
- mid = ctx.mid
644
- if klass.kind == :class
645
- klass = klass.superclass
646
- while klass != :__root__
647
- class_def = @class_defs[klass.idx]
648
- mthd = class_def.get_method(mid, singleton)
649
- return mthd if mthd
650
- klass = klass.superclass
651
- end
652
- else
653
- # module
654
- class_def = @class_defs[klass.idx]
655
- mthd = class_def.get_method(mid, singleton)
656
- return mthd if mthd
657
- end
658
- nil
659
- end
660
-
661
- def get_all_methods(klass, singleton, _include_subclasses)
662
- names = {}
663
-
664
- if klass.kind == :class
665
- while klass != :__root__
666
- # TODO: module
667
- @class_defs[klass.idx].methods.each_key do |singleton0, name|
668
- if singleton == singleton0
669
- names[name] = true
670
- end
671
- end
672
- klass = klass.superclass
673
- end
674
- else
675
- @class_defs[klass.idx].methods.each_key do |singleton0, name|
676
- if singleton == singleton0
677
- names[name] = true
678
- end
679
- end
680
- end
681
-
682
- names
683
- end
684
-
685
- def get_constant(klass, name)
686
- if klass == Type.any
687
- [Type.any, nil]
688
- elsif klass.is_a?(Type::Class)
689
- @class_defs[klass.idx].get_constant(name)
690
- else
691
- [Type.any, nil]
692
- end
693
- end
694
-
695
- def search_constant(cref, name)
696
- while cref != :bottom
697
- ty, locs = get_constant(cref.klass, name)
698
- return ty, locs if ty != Type.any
699
- cref = cref.outer
700
- end
701
-
702
- return Type.any, nil
703
- end
704
-
705
- def add_constant(klass, name, value, def_ep)
706
- if klass.is_a?(Type::Class)
707
- @class_defs[klass.idx].add_constant(name, value, def_ep)
708
- end
709
- end
710
-
711
- def check_typed_method(klass, mid, singleton)
712
- @class_defs[klass.idx].check_typed_method(mid, singleton)
713
- end
714
-
715
- def check_typed_attr(klass, mid, singleton)
716
- @class_defs[klass.idx].check_typed_attr(mid, singleton)
717
- end
718
-
719
- def add_method(klass, mid, singleton, mdef)
720
- @class_defs[klass.idx].add_method(mid, singleton, mdef)
721
- mdef
722
- end
723
-
724
- def set_method(klass, mid, singleton, mdef)
725
- @class_defs[klass.idx].set_method(mid, singleton, mdef)
726
- mdef
727
- end
728
-
729
- def add_attr_method(klass, mid, ivar, kind, pub_meth, ep)
730
- if kind == :reader || kind == :accessor
731
- typed_mdef = check_typed_attr(klass, mid, ep.ctx.cref.singleton)
732
- unless typed_mdef
733
- add_method(klass, mid, false, ExecutedAttrMethodDef.new(ivar, :reader, pub_meth, ep))
734
- end
735
- end
736
- if kind == :writer || kind == :accessor
737
- mid = :"#{ mid }="
738
- typed_mdef = check_typed_attr(klass, mid, ep.ctx.cref.singleton)
739
- unless typed_mdef
740
- add_method(klass, mid, false, ExecutedAttrMethodDef.new(ivar, :writer, pub_meth, ep))
741
- end
742
- end
743
- end
744
-
745
- def add_typed_attr_method(klass, mdef)
746
- name = mdef.ivar[1..-1]
747
- name = mdef.kind == :writer ? :"#{ name }=" : name.to_sym
748
- add_method(klass, name, false, mdef)
749
- end
750
-
751
- def add_iseq_method(klass, mid, iseq, cref, outer_ep, pub_meth)
752
- add_method(klass, mid, false, ISeqMethodDef.new(iseq, cref, outer_ep, pub_meth))
753
- end
754
-
755
- def add_singleton_iseq_method(klass, mid, iseq, cref, outer_ep, pub_meth)
756
- add_method(klass, mid, true, ISeqMethodDef.new(iseq, cref, outer_ep, pub_meth))
757
- end
758
-
759
- def set_custom_method(klass, mid, impl, pub_meth = true)
760
- set_method(klass, mid, false, CustomMethodDef.new(impl, pub_meth))
761
- end
762
-
763
- def set_singleton_custom_method(klass, mid, impl, pub_meth = true)
764
- set_method(klass, mid, true, CustomMethodDef.new(impl, pub_meth))
765
- end
766
-
767
- def alias_method(klass, singleton, alias_mid, orig_mid, ep)
768
- if klass == Type.any
769
- self
770
- else
771
- mdefs = get_method(klass, singleton, false, orig_mid) # XXX: include_subclass == false??
772
- if mdefs
773
- # dup is needed for `alias foo foo` (otherwise, "can't add a new key into hash during iteration" error occurs)
774
- mdefs.dup.each do |mdef|
775
- @class_defs[klass.idx].add_method(alias_mid, singleton, AliasMethodDef.new(orig_mid, mdef, ep))
776
- end
777
- end
778
- end
779
- end
780
-
781
- def add_edge(ep, next_ep)
782
- (@backward_edges[next_ep] ||= {})[ep] = true
783
- end
784
-
785
- def add_iseq_method_call!(iseq_mdef, ctx)
786
- @iseq_method_to_ctxs[iseq_mdef] ||= Utils::MutableSet.new
787
- @iseq_method_to_ctxs[iseq_mdef] << ctx
788
- end
789
-
790
- def add_executed_iseq(iseq)
791
- @executed_iseqs << iseq
792
- end
793
-
794
- def add_callsite!(callee_ctx, caller_ep, caller_env, &ctn)
795
- if callee_ctx.is_a?(Context)
796
- @executed_iseqs << callee_ctx.iseq
797
- callee_type = callee_ctx.iseq.type
798
- if caller_ep.ctx.is_a?(Context) && (callee_type == :method || callee_type == :block)
799
- caller_ep.ctx.iseq&.add_called_iseq(caller_ep.pc, callee_ctx.iseq)
800
- end
801
- end
802
-
803
- @callsites[callee_ctx] ||= {}
804
- @callsites[callee_ctx][caller_ep] = ctn
805
- merge_return_env(caller_ep) {|env| env ? env.merge(caller_env) : caller_env }
806
-
807
- ret_ty = @return_values[callee_ctx] ||= Type.bot
808
- if ret_ty != Type.bot
809
- ctn[ret_ty, caller_ep, @return_envs[caller_ep]]
810
- end
811
- end
812
-
813
- def add_method_signature!(callee_ctx, msig)
814
- if @method_signatures[callee_ctx]
815
- @method_signatures[callee_ctx] = @method_signatures[callee_ctx].merge(msig)
816
- else
817
- @method_signatures[callee_ctx] = msig
818
- end
819
- end
820
-
821
- def merge_return_env(caller_ep)
822
- @return_envs[caller_ep] = yield @return_envs[caller_ep]
823
- end
824
-
825
- def add_return_value!(callee_ctx, ret_ty)
826
- @return_values[callee_ctx] ||= Type.bot
827
- @return_values[callee_ctx] = @return_values[callee_ctx].union(ret_ty)
828
-
829
- @callsites[callee_ctx] ||= {}
830
- @callsites[callee_ctx].each do |caller_ep, ctn|
831
- ctn[ret_ty, caller_ep, @return_envs[caller_ep]]
832
- end
833
- end
834
-
835
- def add_block_to_ctx!(block_body, ctx)
836
- raise if !block_body.is_a?(Block)
837
- @block_to_ctx[block_body] ||= Utils::MutableSet.new
838
- @block_to_ctx[block_body] << ctx
839
- end
840
-
841
- def add_block_signature!(block_body, bsig)
842
- if @block_signatures[block_body]
843
- @block_signatures[block_body] = @block_signatures[block_body].merge(bsig)
844
- else
845
- @block_signatures[block_body] = bsig
846
- end
847
- end
848
-
849
- class VarTable
850
- Entry = Struct.new(:rbs_declared, :read_continuations, :type, :absolute_paths, :write_eps)
851
-
852
- def initialize
853
- @tbl = {}
854
- end
855
-
856
- def add_read!(site, ep, &ctn)
857
- entry = @tbl[site] ||= Entry.new(false, {}, Type.bot, Utils::MutableSet.new, Utils::MutableSet.new)
858
- entry.read_continuations[ep] = ctn
859
- entry.absolute_paths << ep.ctx.iseq.absolute_path if ep.ctx.is_a?(Context)
860
- ty = entry.type
861
- ty = Type.nil if ty == Type.bot
862
- ctn[ty, ep, entry.write_eps]
863
- end
864
-
865
- def add_write!(site, ty, ep, scratch)
866
- entry = @tbl[site] ||= Entry.new(!ep, {}, Type.bot, Utils::MutableSet.new, Utils::MutableSet.new)
867
- if ep
868
- if entry.rbs_declared
869
- unless Type.match?(ty, entry.type)
870
- scratch.warn(ep, "inconsistent assignment to RBS-declared variable")
871
- return
872
- end
873
- end
874
- entry.absolute_paths << ep.ctx.iseq.absolute_path
875
- entry.write_eps << ep
876
- end
877
- entry.type = entry.type.union(ty)
878
- entry.read_continuations.each do |read_ep, ctn|
879
- ctn[ty, read_ep, ep ? [ep] : []]
880
- end
881
- end
882
-
883
- def dump
884
- @tbl
885
- end
886
- end
887
-
888
- def identify_class_for_ivar(recv, var)
889
- klass, singleton = recv.method_dispatch_info
890
- return nil unless klass
891
- search_method(klass, singleton, var) do |mthds, klass0, singleton0|
892
- if mthds.any? {|mthd| mthd.is_a?(AttrMethodDef) }
893
- return klass0, singleton
894
- end
895
- end
896
- return klass, singleton
897
- end
898
-
899
- def get_ivar(recv, var)
900
- recv = recv.base_type while recv.respond_to?(:base_type)
901
-
902
- klass, singleton = identify_class_for_ivar(recv, var.to_s[1..].to_sym) # search attr_reader
903
-
904
- if klass
905
- return @class_defs[klass.idx], singleton
906
- else
907
- return nil
908
- end
909
- end
910
-
911
- def add_ivar_read!(recv, var, ep, &ctn)
912
- recv.each_child do |recv|
913
- class_def, singleton = get_ivar(recv, var)
914
- next unless class_def
915
- class_def.ivars.add_read!([singleton, var], ep, &ctn)
916
- end
917
- end
918
-
919
- def add_ivar_write!(recv, var, ty, ep)
920
- recv.each_child do |recv|
921
- class_def, singleton = get_ivar(recv, var)
922
- next unless class_def
923
- site = [singleton, var]
924
- class_def.ivars.add_write!(site, ty, ep, self)
925
- end
926
- end
927
-
928
- def add_cvar_read!(klass, var, ep, &ctn)
929
- klass.each_child do |klass|
930
- next unless klass.is_a?(Type::Class)
931
- class_def = @class_defs[klass.idx]
932
- next unless class_def
933
- class_def.cvars.add_read!(var, ep, &ctn)
934
- end
935
- end
936
-
937
- def add_cvar_write!(klass, var, ty, ep)
938
- klass.each_child do |klass|
939
- next unless klass.is_a?(Type::Class)
940
- class_def = @class_defs[klass.idx]
941
- next unless class_def
942
- class_def.cvars.add_write!(var, ty, ep, self)
943
- end
944
- end
945
-
946
- def add_gvar_read!(var, ep, &ctn)
947
- @gvar_table.add_read!(var, ep, &ctn)
948
- end
949
-
950
- def add_gvar_write!(var, ty, ep)
951
- @gvar_table.add_write!(var, ty, ep, self)
952
- end
953
-
954
- def error(ep, msg)
955
- p [ep.source_location, "[error] " + msg] if Config.current.verbose >= 2
956
- @errors << [ep, "[error] " + msg]
957
- end
958
-
959
- def warn(ep, msg)
960
- p [ep.source_location, "[warning] " + msg] if Config.current.verbose >= 2
961
- @errors << [ep, "[warning] " + msg]
962
- end
963
-
964
- def reveal_type(ep, ty)
965
- key = ep.source_location
966
- puts "reveal:#{ ep.source_location }:#{ ty.screen_name(self) }" if Config.current.verbose >= 2
967
- if @reveal_types[key]
968
- @reveal_types[key] = @reveal_types[key].union(ty)
969
- else
970
- @reveal_types[key] = ty
971
- end
972
- end
973
-
974
- def get_container_elem_types(env, ep, id)
975
- if ep.outer
976
- tmp_ep = ep
977
- tmp_ep = tmp_ep.outer while tmp_ep.outer
978
- env = @return_envs[tmp_ep]
979
- end
980
- env.get_container_elem_types(id)
981
- end
982
-
983
- def update_container_elem_types(env, ep, id, base_type)
984
- if ep.outer
985
- tmp_ep = ep
986
- tmp_ep = tmp_ep.outer while tmp_ep.outer
987
- merge_return_env(tmp_ep) do |menv|
988
- elems = menv.get_container_elem_types(id)
989
- elems = yield elems
990
- menv = menv.deploy_type(id, elems)
991
- gid = @alloc_site_to_global_id[id]
992
- if gid
993
- ty = globalize_type(elems.to_local_type(id, base_type), env, ep)
994
- add_ivar_write!(*gid, ty, ep)
995
- end
996
- menv
997
- end
998
- env
999
- else
1000
- elems = env.get_container_elem_types(id)
1001
- elems = yield elems
1002
- env = env.deploy_type(id, elems)
1003
- gid = @alloc_site_to_global_id[id]
1004
- if gid
1005
- ty = globalize_type(elems.to_local_type(id, base_type), env, ep)
1006
- add_ivar_write!(*gid, ty, ep)
1007
- end
1008
- env
1009
- end
1010
- end
1011
-
1012
- def get_array_elem_type(env, ep, id, idx = nil)
1013
- elems = get_container_elem_types(env, ep, id)
1014
-
1015
- if elems
1016
- return elems[idx] || Type.nil if idx
1017
- return elems.squash_or_any
1018
- else
1019
- Type.any
1020
- end
1021
- end
1022
-
1023
- def get_hash_elem_type(env, ep, id, key_ty = nil)
1024
- elems = get_container_elem_types(env, ep, id)
1025
-
1026
- if elems
1027
- elems[globalize_type(key_ty, env, ep) || Type.any]
1028
- else
1029
- Type.any
1030
- end
1031
- end
1032
-
1033
- def type_profile(cancel_token = nil)
1034
- cancel_token ||= Utils::TimerCancelToken.new(Config.current.max_sec)
1035
- tick = Time.now
1036
- iter_counter = 0
1037
- stat_eps = Utils::MutableSet.new
1038
-
1039
- prologue_ctx = Context.new(nil, nil, nil)
1040
- prologue_ep = ExecutionPoint.new(prologue_ctx, -1, nil)
1041
- prologue_env = Env.new(StaticEnv.new(Type.bot, Type.nil, false, true), [], [], Utils::HashWrapper.new({}))
1042
-
1043
- until @entrypoints.empty?
1044
- entrypoint = @entrypoints.shift
1045
- if entrypoint.is_a?(String)
1046
- file = entrypoint
1047
- next if @loaded_files[File.expand_path(file)]
1048
- iseq, = ISeq.compile(file)
1049
- else
1050
- iseq = entrypoint
1051
- end
1052
-
1053
- @loaded_files[iseq.absolute_path] = true
1054
- ep, env = TypeProf.starting_state(iseq)
1055
- merge_env(ep, env)
1056
- add_callsite!(ep.ctx, prologue_ep, prologue_env) {|ty, ep| }
1057
-
1058
- while true
1059
- until @worklist.empty?
1060
- ep = @worklist.deletemin
1061
-
1062
- iter_counter += 1
1063
- if Config.current.options[:show_indicator]
1064
- tick2 = Time.now
1065
- if tick2 - tick >= 1
1066
- tick = tick2
1067
- $stderr << "\rType Profiling... (%d instructions @ %s)\e[K" % [iter_counter, ep.source_location]
1068
- $stderr.flush
1069
- end
1070
- end
1071
-
1072
- if (Config.current.max_iter && Config.current.max_iter <= iter_counter) || cancel_token.cancelled?
1073
- @terminated = true
1074
- break
1075
- end
1076
-
1077
- stat_eps << ep
1078
- step(ep)
1079
- end
1080
-
1081
- break if @terminated
1082
-
1083
- break unless Config.current.options[:stub_execution]
1084
-
1085
- begin
1086
- iseq, (kind, dummy_continuation) = @pending_execution.first
1087
- break if !iseq
1088
- @pending_execution.delete(iseq)
1089
- end while @executed_iseqs.include?(iseq)
1090
-
1091
- puts "DEBUG: trigger stub execution (#{ iseq&.name || "(nil)" }): rest #{ @pending_execution.size }" if Config.current.verbose >= 2
1092
-
1093
- break if !iseq
1094
- case kind
1095
- when :method
1096
- meth, ep, env = dummy_continuation
1097
- merge_env(ep, env)
1098
- add_iseq_method_call!(meth, ep.ctx)
1099
-
1100
- when :block
1101
- blk, epenvs = dummy_continuation
1102
- epenvs.each do |ep, env|
1103
- merge_env(ep, env)
1104
- add_block_to_ctx!(blk.block_body, ep.ctx)
1105
- end
1106
- end
1107
- end
1108
- end
1109
-
1110
- $stderr.print "\r\e[K" if Config.current.options[:show_indicator]
1111
-
1112
- stat_eps
1113
- end
1114
-
1115
- def report(stat_eps, output)
1116
- Reporters.show_message(@terminated, output)
1117
-
1118
- Reporters.show_error(@errors, @backward_edges, output)
1119
-
1120
- Reporters.show_reveal_types(self, @reveal_types, output)
1121
-
1122
- Reporters.show_gvars(self, @gvar_table, output)
1123
-
1124
- RubySignatureExporter.new(self, @class_defs, @iseq_method_to_ctxs).show(stat_eps, output)
1125
- end
1126
-
1127
- def report_lsp
1128
- errs = @errors.map do |ep, msg|
1129
- [ep&.detailed_source_location, msg]
1130
- end
1131
-
1132
- res = RubySignatureExporter.new(self, @class_defs, @iseq_method_to_ctxs).show_lsp
1133
-
1134
- path, loc = Config.current.options[:signature_help_loc]
1135
- if path
1136
- sig_help_res = []
1137
- sig_help = @lsp_signature_help[loc]
1138
- if sig_help
1139
- recv = sig_help[:recv]
1140
- mid = sig_help[:mid]
1141
- singleton = sig_help[:singleton]
1142
- mdefs = sig_help[:mdefs]
1143
- node_id = sig_help[:node_id]
1144
- mdefs.each do |mdef|
1145
- case mdef
1146
- when ISeqMethodDef
1147
- ctxs = @iseq_method_to_ctxs[mdef]
1148
- next unless ctxs
1149
-
1150
- ctx = ctxs.find {|ctx| ctx.mid == mid } || ctxs.first
1151
-
1152
- method_name = mid
1153
- method_name = "self.#{ method_name }" if singleton
1154
-
1155
- str = recv.screen_name(self)
1156
- str += singleton ? "." : "#"
1157
- str += method_name.to_s
1158
- str += ": "
1159
- sig, _, sig_help = show_method_signature(ctx)
1160
- offset = str.size
1161
- sig_help = sig_help.transform_values {|r| (r.begin + offset ... r.end + offset) }
1162
- str += sig
1163
- sig_help_res << [str, sig_help, node_id]
1164
- when AliasMethodDef
1165
- # TODO
1166
- when TypedMethodDef
1167
- mdef.rbs_source&.[](1)&.each do |rbs|
1168
- # TODO: sig_help
1169
- sig_help_res << [rbs, {}, node_id]
1170
- end
1171
- end
1172
- end
1173
- end
1174
- end
1175
-
1176
- {
1177
- sigs: res,
1178
- errors: errs,
1179
- completion: @lsp_completion,
1180
- signature_help: sig_help_res,
1181
- }
1182
- end
1183
-
1184
- def globalize_type(ty, env, ep)
1185
- if ep.outer
1186
- tmp_ep = ep
1187
- tmp_ep = tmp_ep.outer while tmp_ep.outer
1188
- env = @return_envs[tmp_ep]
1189
- end
1190
- ty.globalize(env, {}, Config.current.options[:type_depth_limit])
1191
- end
1192
-
1193
- def localize_type(ty, env, ep, alloc_site = AllocationSite.new(ep))
1194
- if ep.outer
1195
- tmp_ep = ep
1196
- tmp_ep = tmp_ep.outer while tmp_ep.outer
1197
- target_env = @return_envs[tmp_ep]
1198
- target_env, ty = ty.localize(target_env, alloc_site, Config.current.options[:type_depth_limit])
1199
- merge_return_env(tmp_ep) do |env|
1200
- env ? env.merge(target_env) : target_env
1201
- end
1202
- return env, ty
1203
- else
1204
- return ty.localize(env, alloc_site, Config.current.options[:type_depth_limit])
1205
- end
1206
- end
1207
-
1208
- def pend_method_execution(iseq, meth, recv, mid, cref, ep)
1209
- ctx = Context.new(iseq, cref, mid)
1210
- ep = ExecutionPoint.new(ctx, 0, ep)
1211
- locals = [Type.nil] * iseq.locals.size
1212
-
1213
- fargs_format = iseq.fargs_format
1214
- lead_num = fargs_format[:lead_num] || 0
1215
- post_num = fargs_format[:post_num] || 0
1216
- post_index = fargs_format[:post_start]
1217
- rest_index = fargs_format[:rest_start]
1218
- keyword = fargs_format[:keyword]
1219
- kw_index = fargs_format[:kwbits] - keyword.size if keyword
1220
- kwrest_index = fargs_format[:kwrest]
1221
- block_index = fargs_format[:block_start]
1222
- opt = fargs_format[:opt] || [0]
1223
-
1224
- (lead_num + opt.size - 1).times {|i| locals[i] = Type.any }
1225
- post_num.times {|i| locals[i + post_index] = Type.any } if post_index
1226
- locals[rest_index] = Type.any if rest_index
1227
- if keyword
1228
- keyword.each_with_index do |kw, i|
1229
- case
1230
- when kw.is_a?(Symbol) # required keyword
1231
- locals[kw_index + i] = Type.any
1232
- when kw.size == 2 # optional keyword (default value is a literal)
1233
- _key, default_ty = *kw
1234
- default_ty = Type.guess_literal_type(default_ty)
1235
- default_ty = default_ty.base_type if default_ty.is_a?(Type::Literal)
1236
- locals[kw_index + i] = default_ty.union(Type.any)
1237
- else # optional keyword (default value is an expression)
1238
- locals[kw_index + i] = Type.any
1239
- end
1240
- end
1241
- end
1242
- locals[kwrest_index] = Type.any if kwrest_index
1243
- locals[block_index] = Type.nil if block_index
1244
-
1245
- env = Env.new(StaticEnv.new(recv, Type.nil, false, true), locals, [], Utils::HashWrapper.new({}))
1246
-
1247
- if !@pending_execution[iseq] || @pending_execution[iseq][0] == :block
1248
- @pending_execution[iseq] = [:method, [meth, ep, env]]
1249
- end
1250
- end
1251
-
1252
- def pend_block_dummy_execution(blk, iseq, nep, nenv)
1253
- @pending_execution[iseq] ||= [:block, [blk, {}]]
1254
- if @pending_execution[iseq][0] == :block
1255
- if @pending_execution[iseq][1][1][nep]
1256
- @pending_execution[iseq][1][1][nep] = @pending_execution[iseq][1][1][nep].merge(nenv)
1257
- else
1258
- @pending_execution[iseq][1][1][nep] = nenv
1259
- end
1260
- else
1261
- # XXX: what to do?
1262
- end
1263
- end
1264
-
1265
- def get_instance_variable(recv, var, ep, env)
1266
- add_ivar_read!(recv, var, ep) do |ty, ep, write_eps|
1267
- alloc_site = AllocationSite.new(ep)
1268
- nenv, ty = localize_type(ty, env, ep, alloc_site)
1269
- case ty
1270
- when Type::Local
1271
- @alloc_site_to_global_id[ty.id] = [recv, var] # need overwrite check??
1272
- end
1273
- write_eps.each do |write_ep|
1274
- ep.ctx.iseq.add_def_loc(ep.pc, write_ep.detailed_source_location)
1275
- end
1276
- yield ty, nenv
1277
- end
1278
- end
1279
-
1280
- def set_instance_variable(recv, var, ty, ep, env)
1281
- ty = globalize_type(ty, env, ep)
1282
- add_ivar_write!(recv, var, ty, ep)
1283
- end
1284
-
1285
- def step(ep)
1286
- env = @ep2env[ep]
1287
- raise "nil env" unless env
1288
-
1289
- insn = ep.ctx.iseq.insns[ep.pc]
1290
- operands = insn.operands
1291
-
1292
- if Config.current.verbose >= 2
1293
- # XXX: more dedicated output
1294
- puts "DEBUG: stack=%p" % [env.stack]
1295
- puts "DEBUG: %s (%s) PC=%d insn=%s sp=%d" % [ep.source_location, ep.ctx.iseq.name, ep.pc, insn.insn, env.stack.size]
1296
- end
1297
-
1298
- case insn.insn
1299
- when :_iseq_body_start
1300
- # XXX: reconstruct and record the method signature
1301
- iseq = ep.ctx.iseq
1302
- lead_num = iseq.fargs_format[:lead_num] || 0
1303
- opt = iseq.fargs_format[:opt] || [0]
1304
- rest_start = iseq.fargs_format[:rest_start]
1305
- post_start = iseq.fargs_format[:post_start]
1306
- post_num = iseq.fargs_format[:post_num] || 0
1307
- kw_start = iseq.fargs_format[:kwbits]
1308
- keyword = iseq.fargs_format[:keyword]
1309
- kw_start -= keyword.size if kw_start
1310
- kw_rest = iseq.fargs_format[:kwrest]
1311
- block_start = iseq.fargs_format[:block_start]
1312
-
1313
- lead_tys = env.locals[0, lead_num].map {|ty| globalize_type(ty, env, ep) }
1314
- opt_tys = opt.size > 1 ? env.locals[lead_num, opt.size - 1].map {|ty| globalize_type(ty, env, ep) } : []
1315
- if rest_start # XXX:squash
1316
- ty = globalize_type(env.locals[rest_start], env, ep)
1317
- rest_ty = Type.bot
1318
- ty.each_child_global do |ty|
1319
- if ty.is_a?(Type::Array)
1320
- rest_ty = rest_ty.union(ty.elems.squash)
1321
- else
1322
- # XXX: to_ary?
1323
- rest_ty = rest_ty.union(ty)
1324
- end
1325
- end
1326
- end
1327
- post_tys = (post_start ? env.locals[post_start, post_num] : []).map {|ty| globalize_type(ty, env, ep) }
1328
- if keyword
1329
- kw_tys = []
1330
- keyword.each_with_index do |kw, i|
1331
- case
1332
- when kw.is_a?(Symbol) # required keyword
1333
- key = kw
1334
- req = true
1335
- when kw.size == 2 # optional keyword (default value is a literal)
1336
- key, default_ty = *kw
1337
- default_ty = Type.guess_literal_type(default_ty)
1338
- default_ty = default_ty.base_type if default_ty.is_a?(Type::Literal)
1339
- req = false
1340
- else # optional keyword (default value is an expression)
1341
- key, = kw
1342
- req = false
1343
- end
1344
- ty = env.locals[kw_start + i]
1345
- ty = ty.union(default_ty) if default_ty
1346
- ty = globalize_type(ty, env, ep)
1347
- kw_tys << [req, key, ty]
1348
- end
1349
- end
1350
- kw_rest_ty = globalize_type(env.locals[kw_rest], env, ep) if kw_rest
1351
- kw_rest_ty = nil if kw_rest_ty == Type.nil
1352
- if block_start
1353
- blk_ty = globalize_type(env.locals[block_start], env, ep)
1354
- elsif iseq.type == :method
1355
- blk_ty = env.static_env.blk_ty
1356
- else
1357
- blk_ty = Type.nil
1358
- end
1359
- msig = MethodSignature.new(lead_tys, opt_tys, rest_ty, post_tys, kw_tys, kw_rest_ty, blk_ty)
1360
- add_method_signature!(ep.ctx, msig)
1361
- when :putspecialobject
1362
- kind, = operands
1363
- ty = case kind
1364
- when 1 then Type::Instance.new(Type::Builtin[:vmcore])
1365
- when 2, 3 # CBASE / CONSTBASE
1366
- ep.ctx.cref.klass
1367
- else
1368
- raise NotImplementedError, "unknown special object: #{ type }"
1369
- end
1370
- env = env.push(ty)
1371
- when :putnil
1372
- env = env.push(Type.nil)
1373
- when :putobject, :duparray
1374
- obj, = operands
1375
- env, ty = localize_type(Type.guess_literal_type(obj), env, ep)
1376
- env = env.push(ty)
1377
- when :putstring
1378
- str, = operands
1379
- ty = Type::Literal.new(str, Type::Instance.new(Type::Builtin[:str]))
1380
- env = env.push(ty)
1381
- when :putself
1382
- ty = env.static_env.recv_ty
1383
- if ty.is_a?(Type::Instance)
1384
- klass = ty.klass
1385
- if klass.type_params.size >= 1
1386
- ty = Type::ContainerType.create_empty_instance(klass)
1387
- env, ty = localize_type(ty, env, ep, AllocationSite.new(ep))
1388
- else
1389
- ty = Type::Instance.new(klass)
1390
- end
1391
- env, ty = localize_type(ty, env, ep)
1392
- end
1393
- env = env.push(ty)
1394
- when :newarray, :newarraykwsplat
1395
- len, = operands
1396
- env, elems = env.pop(len)
1397
- ty = Type::Array.new(Type::Array::Elements.new(elems), Type::Instance.new(Type::Builtin[:ary]))
1398
- env, ty = localize_type(ty, env, ep)
1399
- env = env.push(ty)
1400
- when :newhash
1401
- num, = operands
1402
- env, tys = env.pop(num)
1403
-
1404
- ty = Type.gen_hash do |h|
1405
- tys.each_slice(2) do |k_ty, v_ty|
1406
- k_ty = globalize_type(k_ty, env, ep)
1407
- h[k_ty] = v_ty
1408
- end
1409
- end
1410
-
1411
- env, ty = localize_type(ty, env, ep)
1412
- env = env.push(ty)
1413
- when :newhashfromarray
1414
- raise NotImplementedError, "newhashfromarray"
1415
- when :newrange
1416
- env, tys = env.pop(2)
1417
- # XXX: need generics
1418
- env = env.push(Type::Instance.new(Type::Builtin[:range]))
1419
-
1420
- when :concatstrings
1421
- num, = operands
1422
- env, = env.pop(num)
1423
- env = env.push(Type::Instance.new(Type::Builtin[:str]))
1424
- when :tostring, :anytostring
1425
- env, (_ty1, _ty2,) = env.pop(2)
1426
- env = env.push(Type::Instance.new(Type::Builtin[:str]))
1427
- when :objtostring
1428
- env, (_ty1,) = env.pop(1)
1429
- env = env.push(Type::Instance.new(Type::Builtin[:str]))
1430
- when :freezestring
1431
- # do nothing
1432
- when :toregexp
1433
- _regexp_opt, str_count = operands
1434
- env, tys = env.pop(str_count)
1435
- # TODO: check if tys are all strings?
1436
- env = env.push(Type::Instance.new(Type::Builtin[:regexp]))
1437
- when :intern
1438
- env, (ty,) = env.pop(1)
1439
- # XXX check if ty is String
1440
- env = env.push(Type::Instance.new(Type::Builtin[:sym]))
1441
-
1442
- when :definemethod
1443
- mid, iseq = operands
1444
- do_define_iseq_method(ep, env, mid, iseq, nil)
1445
-
1446
- when :definesmethod
1447
- mid, iseq = operands
1448
- env, (recv,) = env.pop(1)
1449
- cref = ep.ctx.cref
1450
- recv.each_child do |recv|
1451
- if recv.is_a?(Type::Class)
1452
- typed_mdef = check_typed_method(recv, mid, true)
1453
- if typed_mdef
1454
- mdef = ISeqMethodDef.new(iseq, cref, nil, env.static_env.pub_meth)
1455
- typed_mdef.each do |typed_mdef|
1456
- typed_mdef.do_match_iseq_mdef(mdef, recv, mid, env, ep, self)
1457
- end
1458
- else
1459
- meth = add_singleton_iseq_method(recv, mid, iseq, cref, nil, env.static_env.pub_meth)
1460
- end
1461
-
1462
- pend_method_execution(iseq, meth, recv, mid, ep.ctx.cref, nil)
1463
- else
1464
- recv = Type.any # XXX: what to do?
1465
- end
1466
- end
1467
- when :defineclass
1468
- id, iseq, flags = operands
1469
- env, (cbase, superclass) = env.pop(2)
1470
- case flags & 7
1471
- when 0, 2 # CLASS / MODULE
1472
- type = (flags & 7) == 2 ? :module : :class
1473
- existing_klass, = get_constant(cbase, id) # TODO: multiple return values
1474
- if existing_klass.is_a?(Type::Class)
1475
- # record re-opening location
1476
- @class_defs[cbase.idx].add_class_open(id, ep)
1477
- klass = existing_klass
1478
- else
1479
- if existing_klass != Type.any
1480
- error(ep, "the class \"#{ id }\" is #{ existing_klass.screen_name(self) }")
1481
- end
1482
- if type == :class
1483
- if superclass.is_a?(Type::Class)
1484
- # okay
1485
- elsif superclass == Type.any
1486
- warn(ep, "superclass is any; Object is used instead")
1487
- superclass = Type::Builtin[:obj]
1488
- elsif superclass == Type.nil
1489
- superclass = Type::Builtin[:obj]
1490
- elsif superclass.is_a?(Type::Instance)
1491
- warn(ep, "superclass is an instance; Object is used instead")
1492
- superclass = Type::Builtin[:obj]
1493
- else
1494
- warn(ep, "superclass is not a class; Object is used instead")
1495
- superclass = Type::Builtin[:obj]
1496
- end
1497
- else # module
1498
- superclass = nil
1499
- end
1500
- if cbase.is_a?(Type::Class)
1501
- klass = new_class(cbase, id, [], superclass, ep)
1502
- if superclass
1503
- add_superclass_type_args!(klass, superclass.type_params.map { Type.any })
1504
-
1505
- # inherited hook
1506
- aargs = ActualArguments.new([klass], nil, {}, Type.nil)
1507
- do_send(superclass, :inherited, aargs, ep, env) {|_ret_ty, _ep| }
1508
- end
1509
- else
1510
- klass = Type.any
1511
- end
1512
- end
1513
- singleton = false
1514
- when 1 # SINGLETON_CLASS
1515
- singleton = true
1516
- klass = cbase
1517
- if klass.is_a?(Type::Class)
1518
- elsif klass.is_a?(Type::Any)
1519
- else
1520
- warn(ep, "A singleton class is open for #{ klass.screen_name(self) }; handled as any")
1521
- klass = Type.any
1522
- end
1523
- else
1524
- raise NotImplementedError, "unknown defineclass flag: #{ flags }"
1525
- end
1526
- ncref = ep.ctx.cref.extend(klass, singleton)
1527
- recv = singleton ? Type.any : klass
1528
- blk = env.static_env.blk_ty
1529
- nctx = Context.new(iseq, ncref, nil)
1530
- nep = ExecutionPoint.new(nctx, 0, nil)
1531
- locals = [Type.nil] * iseq.locals.size
1532
- nenv = Env.new(StaticEnv.new(recv, blk, false, true), locals, [], Utils::HashWrapper.new({}))
1533
- merge_env(nep, nenv)
1534
- add_callsite!(nep.ctx, ep, env) do |ret_ty, ep, env|
1535
- nenv, ret_ty = localize_type(ret_ty, env, ep)
1536
- nenv = nenv.push(ret_ty)
1537
- merge_env(ep.next, nenv)
1538
- end
1539
- return
1540
- when :send
1541
- env, recvs, mid, aargs = setup_actual_arguments(:method, operands, ep, env)
1542
- recvs = Type.any if recvs == Type.bot
1543
- do_send(recvs, mid, aargs, ep, env) do |ret_ty, ep, env|
1544
- nenv, ret_ty, = localize_type(ret_ty, env, ep)
1545
- nenv = nenv.push(ret_ty)
1546
- merge_env(ep.next, nenv)
1547
- end
1548
- return
1549
- when :recv_getlocal_send_branch
1550
- getlocal_operands, send_operands, branch_operands = operands
1551
- env, recvs, mid, aargs = setup_actual_arguments(:method, send_operands, ep, env)
1552
- recvs = Type.any if recvs == Type.bot
1553
- recvs.each_child do |recv|
1554
- do_send(recv, mid, aargs, ep, env) do |ret_ty, ep, env|
1555
- env, ret_ty, = localize_type(ret_ty, env, ep)
1556
-
1557
- branchtype, target, = branch_operands
1558
- # branchtype: :if or :unless or :nil
1559
- ep_then = ep.next
1560
- ep_else = ep.jump(target)
1561
-
1562
- var_idx, _scope_idx, _escaped = getlocal_operands
1563
- flow_env = env.local_update(-var_idx+2, recv)
1564
-
1565
- case ret_ty
1566
- when Type::Instance.new(Type::Builtin[:true])
1567
- merge_env(branchtype == :if ? ep_else : ep_then, flow_env)
1568
- when Type::Instance.new(Type::Builtin[:false])
1569
- merge_env(branchtype == :if ? ep_then : ep_else, flow_env)
1570
- else
1571
- merge_env(ep_then, env)
1572
- merge_env(ep_else, env)
1573
- end
1574
- end
1575
- end
1576
- return
1577
- when :arg_getlocal_send_branch
1578
- getlocal_operands, send_operands, branch_operands = operands
1579
- env, recvs, mid, aargs = setup_actual_arguments(:method, send_operands, ep, env)
1580
- raise if aargs.lead_tys.size != 1
1581
- aarg = aargs.lead_tys[0]
1582
- aarg = Type.any if aarg == Type.bot
1583
- recvs.each_child do |recv|
1584
- aarg.each_child do |aarg|
1585
- aargs_tmp = ActualArguments.new([aarg], nil, {}, aargs.blk_ty)
1586
- do_send(recv, mid, aargs_tmp, ep, env) do |ret_ty, ep, env|
1587
- env, ret_ty, = localize_type(ret_ty, env, ep)
1588
-
1589
- branchtype, target, = branch_operands
1590
- # branchtype: :if or :unless or :nil
1591
- ep_then = ep.next
1592
- ep_else = ep.jump(target)
1593
-
1594
- var_idx, _scope_idx, _escaped = getlocal_operands
1595
- flow_env = env.local_update(-var_idx+2, aarg)
1596
-
1597
- case ret_ty
1598
- when Type::Instance.new(Type::Builtin[:true])
1599
- merge_env(branchtype == :if ? ep_else : ep_then, flow_env)
1600
- when Type::Instance.new(Type::Builtin[:false])
1601
- merge_env(branchtype == :if ? ep_then : ep_else, flow_env)
1602
- else
1603
- merge_env(ep_then, env)
1604
- merge_env(ep_else, env)
1605
- end
1606
- end
1607
- end
1608
- end
1609
- return
1610
- when :send_branch
1611
- send_operands, branch_operands = operands
1612
- env, recvs, mid, aargs = setup_actual_arguments(:method, send_operands, ep, env)
1613
- recvs = Type.any if recvs == Type.bot
1614
- do_send(recvs, mid, aargs, ep, env) do |ret_ty, ep, env|
1615
- env, ret_ty, = localize_type(ret_ty, env, ep)
1616
-
1617
- branchtype, target, = branch_operands
1618
- # branchtype: :if or :unless or :nil
1619
- ep_then = ep.next
1620
- ep_else = ep.jump(target)
1621
-
1622
- case ret_ty
1623
- when Type::Instance.new(Type::Builtin[:true])
1624
- merge_env(branchtype == :if ? ep_else : ep_then, env)
1625
- when Type::Instance.new(Type::Builtin[:false])
1626
- merge_env(branchtype == :if ? ep_then : ep_else, env)
1627
- else
1628
- merge_env(ep_then, env)
1629
- merge_env(ep_else, env)
1630
- end
1631
- end
1632
- return
1633
- when :invokeblock
1634
- env, recvs, mid, aargs = setup_actual_arguments(:block, operands, ep, env)
1635
- blk = env.static_env.blk_ty
1636
- case
1637
- when blk == Type.nil
1638
- env = env.push(Type.any)
1639
- when blk == Type.any
1640
- #warn(ep, "block is any")
1641
- env = env.push(Type.any)
1642
- else # Proc
1643
- do_invoke_block(blk, aargs, ep, env) do |ret_ty, ep, env|
1644
- nenv, ret_ty, = localize_type(ret_ty, env, ep)
1645
- nenv = nenv.push(ret_ty)
1646
- merge_env(ep.next, nenv)
1647
- end
1648
- return
1649
- end
1650
- when :invokesuper
1651
- env, recv, _, aargs = setup_actual_arguments(:method, operands, ep, env)
1652
- mid = ep.ctx.mid
1653
- found = false
1654
- recv.each_child_global do |recv|
1655
- klass, singleton = recv.method_dispatch_info
1656
- next unless klass
1657
- get_all_super_methods(klass, singleton, ep.ctx.cref.klass, ep.ctx.mid) do |meths, klass|
1658
- found = true
1659
- meths.each do |meth|
1660
- # XXX: this decomposition is really needed??
1661
- # It calls `Object.new` with union receiver which causes an error, but
1662
- # it may be a fault of builtin Object.new implementation.
1663
- meth.do_send(recv, mid, aargs, ep, env, self) do |ret_ty, ep, env|
1664
- nenv, ret_ty, = localize_type(ret_ty, env, ep)
1665
- nenv = nenv.push(ret_ty)
1666
- merge_env(ep.next, nenv)
1667
- end
1668
- end
1669
- end
1670
- end
1671
- return if found
1672
- error(ep, "no superclass method: #{ env.static_env.recv_ty.screen_name(self) }##{ mid }")
1673
- env = env.push(Type.any)
1674
- when :invokebuiltin
1675
- raise NotImplementedError
1676
- when :leave
1677
- if env.stack.size != 1
1678
- raise "stack inconsistency error: #{ env.stack.inspect }"
1679
- end
1680
- env, (ty,) = env.pop(1)
1681
- ty = globalize_type(ty, env, ep)
1682
- add_return_value!(ep.ctx, ty)
1683
- return
1684
- when :throw
1685
- throwtype, = operands
1686
- env, (ty,) = env.pop(1)
1687
- _no_escape = !!(throwtype & 0x8000)
1688
- throwtype = [:none, :return, :break, :next, :retry, :redo][throwtype & 0xff]
1689
- case throwtype
1690
- when :none
1691
-
1692
- when :return
1693
- ty = globalize_type(ty, env, ep)
1694
- tmp_ep = ep
1695
- tmp_ep = tmp_ep.outer while tmp_ep.outer
1696
- add_return_value!(tmp_ep.ctx, ty)
1697
- return
1698
- when :break
1699
- tmp_ep = ep
1700
- while true
1701
- if tmp_ep.ctx.iseq.type == :block
1702
- tmp_ep = tmp_ep.outer
1703
- nenv = @return_envs[tmp_ep].push(ty)
1704
- merge_env(tmp_ep.next, nenv)
1705
- break
1706
- end
1707
- _type, _iseq, cont, stack_depth = tmp_ep.ctx.iseq.catch_table[tmp_ep.pc]&.find {|type,| type == :break }
1708
- if cont
1709
- nenv = @return_envs[tmp_ep] || env
1710
- nenv, = nenv.pop(nenv.stack.size - stack_depth)
1711
- nenv = nenv.push(ty)
1712
- tmp_ep = tmp_ep.jump(cont)
1713
- merge_env(tmp_ep, nenv)
1714
- break
1715
- end
1716
- tmp_ep = tmp_ep.outer
1717
- end
1718
- when :next, :redo
1719
- # begin; rescue; next; end
1720
- tmp_ep = ep.outer
1721
- _type, _iseq, cont, stack_depth = tmp_ep.ctx.iseq.catch_table[tmp_ep.pc].find {|type,| type == throwtype }
1722
- nenv = @return_envs[tmp_ep]
1723
- nenv, = nenv.pop(nenv.stack.size - stack_depth)
1724
- nenv = nenv.push(ty) if throwtype == :next
1725
- tmp_ep = tmp_ep.jump(cont)
1726
- merge_env(tmp_ep, nenv)
1727
- when :retry
1728
- tmp_ep = ep.outer
1729
- _type, _iseq, cont, stack_depth = tmp_ep.ctx.iseq.catch_table[tmp_ep.pc].find {|type,| type == :retry }
1730
- nenv = @return_envs[tmp_ep]
1731
- nenv, = nenv.pop(nenv.stack.size - stack_depth)
1732
- tmp_ep = tmp_ep.jump(cont)
1733
- merge_env(tmp_ep, nenv)
1734
- else
1735
- p throwtype
1736
- raise NotImplementedError
1737
- end
1738
- return
1739
- when :once
1740
- iseq, = operands
1741
-
1742
- nctx = Context.new(iseq, ep.ctx.cref, ep.ctx.mid)
1743
- nep = ExecutionPoint.new(nctx, 0, ep)
1744
- raise if iseq.locals != []
1745
- nenv = Env.new(env.static_env, [], [], nil)
1746
- merge_env(nep, nenv)
1747
- add_callsite!(nep.ctx, ep, env) do |ret_ty, ep, env|
1748
- nenv, ret_ty = localize_type(ret_ty, env, ep)
1749
- nenv = nenv.push(ret_ty)
1750
- merge_env(ep.next, nenv)
1751
- end
1752
- return
1753
-
1754
- when :branch # TODO: check how branchnil is used
1755
- branchtype, target, = operands
1756
- # branchtype: :if or :unless or :nil
1757
- env, (ty,) = env.pop(1)
1758
- ep_then = ep.next
1759
- ep_else = ep.jump(target)
1760
-
1761
- # TODO: it works for only simple cases: `x = nil; x || 1`
1762
- # It would be good to merge "dup; branchif" to make it context-sensitive-like
1763
- falsy = ty == Type.nil
1764
-
1765
- merge_env(ep_then, env)
1766
- merge_env(ep_else, env) unless branchtype == :if && falsy
1767
- return
1768
- when :jump
1769
- target, = operands
1770
- merge_env(ep.jump(target), env)
1771
- return
1772
-
1773
- when :setinstancevariable
1774
- var, = operands
1775
- env, (ty,) = env.pop(1)
1776
- recv = env.static_env.recv_ty
1777
- set_instance_variable(recv, var, ty, ep, env)
1778
-
1779
- when :getinstancevariable
1780
- var, = operands
1781
- recv = env.static_env.recv_ty
1782
- get_instance_variable(recv, var, ep, env) do |ty, nenv|
1783
- merge_env(ep.next, nenv.push(ty))
1784
- end
1785
- return
1786
-
1787
- when :setclassvariable
1788
- var, = operands
1789
- env, (ty,) = env.pop(1)
1790
- cbase = ep.ctx.cref.klass
1791
- ty = globalize_type(ty, env, ep)
1792
- # TODO: if superclass has the variable, it should be updated
1793
- add_cvar_write!(cbase, var, ty, ep)
1794
-
1795
- when :getclassvariable
1796
- var, = operands
1797
- cbase = ep.ctx.cref.klass
1798
- # TODO: if superclass has the variable, it should be read
1799
- add_cvar_read!(cbase, var, ep) do |ty, ep|
1800
- nenv, ty = localize_type(ty, env, ep)
1801
- merge_env(ep.next, nenv.push(ty))
1802
- end
1803
- return
1804
-
1805
- when :setglobal
1806
- var, = operands
1807
- env, (ty,) = env.pop(1)
1808
- ty = globalize_type(ty, env, ep)
1809
- add_gvar_write!(var, ty, ep)
1810
-
1811
- when :getglobal
1812
- var, = operands
1813
- ty = Type.builtin_global_variable_type(var)
1814
- if ty
1815
- ty, locs = get_constant(Type::Builtin[:obj], ty) if ty.is_a?(Symbol)
1816
- env, ty = localize_type(ty, env, ep)
1817
- env = env.push(ty)
1818
- else
1819
- add_gvar_read!(var, ep) do |ty, ep|
1820
- nenv, ty = localize_type(ty, env, ep)
1821
- merge_env(ep.next, nenv.push(ty))
1822
- end
1823
- # need to return default nil of global variables
1824
- return
1825
- end
1826
-
1827
- when :getlocal
1828
- var_idx, scope_idx, _escaped = operands
1829
- if scope_idx == 0
1830
- ty = env.get_local(-var_idx+2)
1831
- else
1832
- tmp_ep = ep
1833
- scope_idx.times do
1834
- tmp_ep = tmp_ep.outer
1835
- end
1836
- ty = @return_envs[tmp_ep].get_local(-var_idx+2)
1837
- end
1838
- env = env.push(ty)
1839
- when :getlocal_branch
1840
- getlocal_operands, branch_operands = operands
1841
- var_idx, _scope_idx, _escaped = getlocal_operands
1842
- ret_ty = env.get_local(-var_idx+2)
1843
-
1844
- branchtype, target, = branch_operands
1845
- # branchtype: :if or :unless or :nil
1846
- ep_then = ep.next
1847
- ep_else = ep.jump(target)
1848
-
1849
- var_idx, _scope_idx, _escaped = getlocal_operands
1850
-
1851
- ret_ty.each_child do |ret_ty|
1852
- flow_env = env.local_update(-var_idx+2, ret_ty)
1853
- case ret_ty
1854
- when Type.any
1855
- merge_env(ep_then, flow_env)
1856
- merge_env(ep_else, flow_env)
1857
- when Type::Instance.new(Type::Builtin[:false]), Type.nil
1858
- merge_env(branchtype == :if ? ep_then : ep_else, flow_env)
1859
- else
1860
- merge_env(branchtype == :if ? ep_else : ep_then, flow_env)
1861
- end
1862
- end
1863
- return
1864
- when :getlocal_dup_branch
1865
- getlocal_operands, _dup_operands, branch_operands = operands
1866
- var_idx, _scope_idx, _escaped = getlocal_operands
1867
- ret_ty = env.get_local(-var_idx+2)
1868
-
1869
- branchtype, target, = branch_operands
1870
- # branchtype: :if or :unless or :nil
1871
- ep_then = ep.next
1872
- ep_else = ep.jump(target)
1873
-
1874
- ret_ty.each_child do |ret_ty|
1875
- flow_env = env.local_update(-var_idx+2, ret_ty).push(ret_ty)
1876
- case ret_ty
1877
- when Type.any
1878
- merge_env(ep_then, flow_env)
1879
- merge_env(ep_else, flow_env)
1880
- when Type::Instance.new(Type::Builtin[:false]), Type.nil
1881
- merge_env(branchtype == :if ? ep_then : ep_else, flow_env)
1882
- else
1883
- merge_env(branchtype == :if ? ep_else : ep_then, flow_env)
1884
- end
1885
- end
1886
- return
1887
- when :dup_setlocal_branch
1888
- _dup_operands, setlocal_operands, branch_operands = operands
1889
-
1890
- env, (ret_ty,) = env.pop(1)
1891
-
1892
- var_idx, _scope_idx, _escaped = setlocal_operands
1893
-
1894
- branchtype, target, = branch_operands
1895
- # branchtype: :if or :unless or :nil
1896
- ep_then = ep.next
1897
- ep_else = ep.jump(target)
1898
-
1899
- ret_ty.each_child do |ret_ty|
1900
- flow_env = env.local_update(-var_idx+2, ret_ty)
1901
- case ret_ty
1902
- when Type.any
1903
- merge_env(ep_then, flow_env)
1904
- merge_env(ep_else, flow_env)
1905
- when Type::Instance.new(Type::Builtin[:false]), Type.nil
1906
- merge_env(branchtype == :if ? ep_then : ep_else, flow_env)
1907
- else
1908
- merge_env(branchtype == :if ? ep_else : ep_then, flow_env)
1909
- end
1910
- end
1911
- return
1912
- when :getlocal_checkmatch_branch
1913
- getlocal_operands, branch_operands = operands
1914
- var_idx, _scope_idx, _escaped = getlocal_operands
1915
- ret_ty = env.get_local(-var_idx+2)
1916
-
1917
- env, (pattern_ty,) = env.pop(1)
1918
-
1919
- branchtype, target, = branch_operands
1920
- # branchtype: :if or :unless or :nil
1921
- ep_then = ep.next
1922
- ep_else = ep.jump(target)
1923
-
1924
- var_idx, _scope_idx, _escaped = getlocal_operands
1925
-
1926
- ret_ty.each_child do |ret_ty|
1927
- flow_env = env.local_update(-var_idx+2, ret_ty)
1928
- ret_ty = ret_ty.base_type if ret_ty.is_a?(Type::Symbol)
1929
- ret_ty = ret_ty.base_type if ret_ty.is_a?(Type::Local)
1930
- if ret_ty.is_a?(Type::Instance)
1931
- if ret_ty.klass == pattern_ty # XXX: inheritance
1932
- merge_env(branchtype == :if ? ep_else : ep_then, flow_env)
1933
- else
1934
- merge_env(branchtype == :if ? ep_then : ep_else, flow_env)
1935
- end
1936
- else
1937
- merge_env(ep_then, flow_env)
1938
- merge_env(ep_else, flow_env)
1939
- end
1940
- end
1941
- return
1942
- when :setlocal, :setblockparam
1943
- var_idx, scope_idx, _escaped = operands
1944
- env, (ty,) = env.pop(1)
1945
- if scope_idx == 0
1946
- env = env.local_update(-var_idx+2, ty)
1947
- else
1948
- tmp_ep = ep
1949
- scope_idx.times do
1950
- tmp_ep = tmp_ep.outer
1951
- end
1952
- merge_return_env(tmp_ep) do |env|
1953
- env.merge(env.local_update(-var_idx+2, ty))
1954
- end
1955
- end
1956
- when :getconstant
1957
- name, = operands
1958
- env, (cbase, _allow_nil,) = env.pop(2)
1959
- if cbase == Type.nil
1960
- ty, locs = search_constant(ep.ctx.cref, name)
1961
- env, ty = localize_type(ty, env, ep)
1962
- env = env.push(ty)
1963
- elsif cbase == Type.any
1964
- env = env.push(Type.any) # XXX: warning needed?
1965
- else
1966
- ty, locs = get_constant(cbase, name)
1967
- env, ty = localize_type(ty, env, ep)
1968
- env = env.push(ty)
1969
- end
1970
- locs&.each do |loc|
1971
- ep.ctx.iseq.add_def_loc(ep.pc, loc)
1972
- end
1973
- when :setconstant
1974
- name, = operands
1975
- env, (ty, cbase) = env.pop(2)
1976
- old_ty, old_locs = get_constant(cbase, name)
1977
- if old_locs == [nil] # RBS defined
1978
- # TODO: it would be better to check if ty is consistent with old_ty (defined in RBS)
1979
- # instead of extending the type
1980
- env, old_ty = localize_type(globalize_type(old_ty, env, ep), env, ep)
1981
- ty = ty.union(old_ty)
1982
- elsif old_ty != Type.any # XXX???
1983
- warn(ep, "already initialized constant #{ Type::Instance.new(cbase).screen_name(self) }::#{ name }")
1984
- end
1985
- ty.each_child do |ty|
1986
- if ty.is_a?(Type::Class) && cbase.is_a?(Type::Class) && ty.superclass == Type::Builtin[:struct]
1987
- @class_defs[ty.idx].name = cbase_path(cbase) + [name]
1988
- end
1989
- end
1990
- add_constant(cbase, name, globalize_type(ty, env, ep), ep)
1991
-
1992
- when :getspecial
1993
- key, type = operands
1994
- if type == 0
1995
- case key
1996
- when 0 # VM_SVAR_LASTLINE
1997
- env = env.push(Type.any) # or String | NilClass only?
1998
- when 1 # VM_SVAR_BACKREF ($~)
1999
- merge_env(ep.next, env.push(Type::Instance.new(Type::Builtin[:matchdata])))
2000
- # tentatively disabled; it is too conservative
2001
- #merge_env(ep.next, env.push(Type.nil))
2002
- return
2003
- else # flip-flop
2004
- env = env.push(Type.bool)
2005
- end
2006
- else
2007
- # NTH_REF ($1, $2, ...) / BACK_REF ($&, $+, ...)
2008
- merge_env(ep.next, env.push(Type::Instance.new(Type::Builtin[:str])))
2009
- # tentatively disabled; it is too conservative
2010
- #merge_env(ep.next, env.push(Type.nil))
2011
- return
2012
- end
2013
- when :setspecial
2014
- key, = operands
2015
- if key >= 2 # flip-flop
2016
- env, = env.pop(1)
2017
- else
2018
- raise "unknown setspecial key: #{ key }"
2019
- end
2020
-
2021
- when :dup
2022
- env, (ty,) = env.pop(1)
2023
- env = env.push(ty).push(ty)
2024
- when :dup_branch
2025
- _dup_operands, branch_operands = operands
2026
- env, (ty,) = env.pop(1)
2027
-
2028
- branchtype, target, = branch_operands
2029
- # branchtype: :if or :unless or :nil
2030
- ep_then = ep.next
2031
- ep_else = ep.jump(target)
2032
-
2033
- ty.each_child do |ty|
2034
- flow_env = env.push(ty)
2035
- case ty
2036
- when Type.any
2037
- merge_env(ep_then, flow_env)
2038
- merge_env(ep_else, flow_env)
2039
- when Type::Instance.new(Type::Builtin[:false]), Type.nil
2040
- merge_env(branchtype == :if ? ep_then : ep_else, flow_env)
2041
- else
2042
- merge_env(branchtype == :if ? ep_else : ep_then, flow_env)
2043
- end
2044
- end
2045
- return
2046
- when :duphash
2047
- raw_hash, = operands
2048
- ty = Type.guess_literal_type(raw_hash)
2049
- env, ty = localize_type(globalize_type(ty, env, ep), env, ep)
2050
- env = env.push(ty)
2051
- when :dupn
2052
- n, = operands
2053
- _, tys = env.pop(n)
2054
- tys.each {|ty| env = env.push(ty) }
2055
- when :pop
2056
- env, = env.pop(1)
2057
- when :swap
2058
- env, (a, b) = env.pop(2)
2059
- env = env.push(a).push(b)
2060
- when :reverse
2061
- n, = operands
2062
- env, tys = env.pop(n)
2063
- tys.reverse_each {|ty| env = env.push(ty) }
2064
- when :defined
2065
- env, = env.pop(1)
2066
- sym_ty = Type::Symbol.new(nil, Type::Instance.new(Type::Builtin[:sym]))
2067
- env = env.push(Type.optional(sym_ty))
2068
- when :checkmatch
2069
- flag, = operands
2070
-
2071
- # This flag means that the stack top is an array, and the check needs to be applied to find all elements
2072
- # However, currently TypeProf uses very conservative interpretation (all check returns both true and false),
2073
- # so we just ignore the flag now
2074
- _array = flag & 4 != 0
2075
-
2076
- case flag & 3
2077
- when 1 # VM_CHECKMATCH_TYPE_WHEN
2078
- env, = env.pop(2)
2079
- env = env.push(Type.bool)
2080
- when 2 # VM_CHECKMATCH_TYPE_CASE
2081
- env, = env.pop(2)
2082
- env = env.push(Type.bool)
2083
- when 3 # VM_CHECKMATCH_TYPE_RESCUE
2084
- env, = env.pop(2)
2085
- env = env.push(Type.bool)
2086
- else
2087
- raise "unknown checkmatch flag"
2088
- end
2089
- when :checkkeyword
2090
- env = env.push(Type.bool)
2091
- when :adjuststack
2092
- n, = operands
2093
- env, _ = env.pop(n)
2094
- when :nop
2095
- when :setn
2096
- idx, = operands
2097
- if idx >= 1
2098
- env, (ty,) = env.pop(1)
2099
- env = env.setn(idx, ty).push(ty)
2100
- end
2101
- when :topn
2102
- idx, = operands
2103
- env = env.topn(idx)
2104
-
2105
- when :splatarray
2106
- env, (ty,) = env.pop(1)
2107
- # XXX: vm_splat_array
2108
- env = env.push(ty)
2109
- when :expandarray
2110
- num, flag = operands
2111
- env, (ary,) = env.pop(1)
2112
- splat = flag & 1 == 1
2113
- from_head = flag & 2 == 0
2114
- ary.each_child do |ary|
2115
- case ary
2116
- when Type::Local
2117
- if ary.kind == Type::Array
2118
- elems = get_container_elem_types(env, ep, ary.id)
2119
- elems ||= Type::Array::Elements.new([], Type.any) # XXX
2120
- else
2121
- elems = Type::Array::Elements.new([], Type.any) # XXX
2122
- end
2123
- do_expand_array(ep, env, elems, num, splat, from_head)
2124
- when Type::Any
2125
- nnum = num
2126
- nnum += 1 if splat
2127
- nenv = env
2128
- nnum.times do
2129
- nenv = nenv.push(Type.any)
2130
- end
2131
- add_edge(ep, ep)
2132
- merge_env(ep.next, nenv)
2133
- else
2134
- # TODO: call to_ary (or to_a?)
2135
- elems = Type::Array::Elements.new([ary], Type.bot)
2136
- do_expand_array(ep, env, elems, num, splat, from_head)
2137
- end
2138
- end
2139
- return
2140
- when :concatarray, :concattoarray
2141
- env, (ary1, ary2) = env.pop(2)
2142
- if ary1.is_a?(Type::Local) && ary1.kind == Type::Array
2143
- elems1 = get_container_elem_types(env, ep, ary1.id)
2144
- if ary2.is_a?(Type::Local) && ary2.kind == Type::Array
2145
- elems2 = get_container_elem_types(env, ep, ary2.id)
2146
- elems = Type::Array::Elements.new([], elems1.squash.union(elems2.squash))
2147
- env = update_container_elem_types(env, ep, ary1.id, ary1.base_type) { elems }
2148
- env = env.push(ary1)
2149
- else
2150
- elems = Type::Array::Elements.new([], Type.any)
2151
- env = update_container_elem_types(env, ep, ary1.id, ary1.base_type) { elems }
2152
- env = env.push(ary1)
2153
- end
2154
- else
2155
- ty = Type::Array.new(Type::Array::Elements.new([], Type.any), Type::Instance.new(Type::Builtin[:ary]))
2156
- env, ty = localize_type(ty, env, ep)
2157
- env = env.push(ty)
2158
- end
2159
- when :pushtoarray
2160
- num, = operands
2161
- env, (ary, ty, *tys) = env.pop(num + 1)
2162
- if ary.is_a?(Type::Local) && ary.kind == Type::Array
2163
- tys.each {|ty0| ty = ty.union(ty0) }
2164
- elems = get_container_elem_types(env, ep, ary.id)
2165
- elems = Type::Array::Elements.new([], elems.squash.union(ty))
2166
- env = update_container_elem_types(env, ep, ary.id, ary.base_type) { elems }
2167
- env = env.push(ary)
2168
- else
2169
- elems = Type::Array::Elements.new([], Type.any)
2170
- env = update_container_elem_types(env, ep, ary.id, ary.base_type) { elems }
2171
- env = env.push(ary)
2172
- end
2173
-
2174
- when :checktype
2175
- kind, = operands
2176
- case kind
2177
- when 5 then klass = :str # T_STRING
2178
- when 7 then klass = :ary # T_ARRAY
2179
- when 8 then klass = :hash # T_HASH
2180
- else
2181
- raise NotImplementedError
2182
- end
2183
- env, (val,) = env.pop(1)
2184
- ty = Type.bot
2185
- val.each_child do |val|
2186
- #globalize_type(val, env, ep).each_child_global do |val|
2187
- val = val.base_type while val.respond_to?(:base_type)
2188
- case val
2189
- when Type::Instance.new(Type::Builtin[klass])
2190
- ty = ty.union(Type::Instance.new(Type::Builtin[:true]))
2191
- when Type.any
2192
- ty = Type.bool
2193
- else
2194
- ty = ty.union(Type::Instance.new(Type::Builtin[:false]))
2195
- end
2196
- end
2197
- env = env.push(ty)
2198
- else
2199
- raise "Unknown insn: #{ insn.insn }"
2200
- end
2201
-
2202
- add_edge(ep, ep)
2203
- merge_env(ep.next, env)
2204
-
2205
- if ep.ctx.iseq.catch_table[ep.pc]
2206
- ep.ctx.iseq.catch_table[ep.pc].each do |type, iseq, cont, stack_depth|
2207
- next if type != :rescue && type != :ensure
2208
- next if env.stack.size < stack_depth
2209
- cont_ep = ep.jump(cont)
2210
- cont_env, = env.pop(env.stack.size - stack_depth)
2211
- nctx = Context.new(iseq, ep.ctx.cref, ep.ctx.mid)
2212
- nep = ExecutionPoint.new(nctx, 0, cont_ep)
2213
- locals = [Type.nil] * iseq.locals.size
2214
- nenv = Env.new(env.static_env, locals, [], Utils::HashWrapper.new({}))
2215
- merge_env(nep, nenv)
2216
- add_callsite!(nep.ctx, cont_ep, cont_env) do |ret_ty, ep, env|
2217
- nenv, ret_ty = localize_type(ret_ty, env, ep)
2218
- nenv = nenv.push(ret_ty)
2219
- merge_env(ep.jump(cont), nenv)
2220
- end
2221
- end
2222
- end
2223
- end
2224
-
2225
- private def do_expand_array(ep, env, elems, num, splat, from_head)
2226
- if from_head
2227
- lead_tys, rest_ary_ty = elems.take_first(num)
2228
- if splat
2229
- env, local_ary_ty = localize_type(rest_ary_ty, env, ep)
2230
- env = env.push(local_ary_ty)
2231
- end
2232
- lead_tys.reverse_each do |ty|
2233
- env = env.push(ty)
2234
- end
2235
- else
2236
- rest_ary_ty, following_tys = elems.take_last(num)
2237
- following_tys.each do |ty|
2238
- env = env.push(ty)
2239
- end
2240
- if splat
2241
- env, local_ary_ty = localize_type(rest_ary_ty, env, ep)
2242
- env = env.push(local_ary_ty)
2243
- end
2244
- end
2245
- merge_env(ep.next, env)
2246
- end
2247
-
2248
- private def ruby_3_3_keywords?
2249
- @ruby_3_3_keywords ||=
2250
- RubyVM::InstructionSequence.compile("foo(*a, **b)").to_a.last[-2][1][:orig_argc] == 2
2251
- end
2252
-
2253
- private def type_to_keywords(ty, ep)
2254
- case ty
2255
- when Type::Hash
2256
- ty.elems.to_keywords
2257
- when Type::Union
2258
- hash_elems = nil
2259
- ty.elems&.each do |(container_kind, base_type), elems|
2260
- if container_kind == Type::Hash
2261
- elems.to_keywords
2262
- hash_elems = hash_elems ? hash_elems.union(elems) : elems
2263
- end
2264
- end
2265
- if hash_elems
2266
- hash_elems.to_keywords
2267
- else
2268
- { nil => Type.any }
2269
- end
2270
- else
2271
- warn(ep, "non hash is passed to **kwarg?") unless ty == Type.any
2272
- { nil => Type.any }
2273
- end
2274
- end
2275
-
2276
- private def setup_actual_arguments(kind, operands, ep, env)
2277
- opt, blk_iseq = operands
2278
- flags = opt[:flag]
2279
- mid = opt[:mid]
2280
- kw_arg = opt[:kw_arg]
2281
- argc = opt[:orig_argc]
2282
- argc += 1 if kind == :method # for the receiver
2283
- argc += kw_arg.size if kw_arg
2284
-
2285
- flag_args_splat = flags[ 0] != 0
2286
- flag_args_blockarg = flags[ 1] != 0
2287
- _flag_args_fcall = flags[ 2] != 0
2288
- _flag_args_vcall = flags[ 3] != 0
2289
- _flag_args_simple = flags[ 4] != 0 # unused in TP
2290
- flags <<= 1 if RUBY_VERSION >= "3.3" # blockiseq flag was removed in 3.3
2291
- flag_args_kwarg = flags[ 6] != 0
2292
- flag_args_kw_splat = flags[ 7] != 0
2293
- _flag_tailcall = flags[ 8] != 0
2294
- _flag_super = flags[ 9] != 0
2295
- _flag_zsuper = flags[10] != 0
2296
-
2297
- argc += 1 if flag_args_blockarg
2298
-
2299
- env, aargs = env.pop(argc)
2300
-
2301
- recv = aargs.shift if kind == :method
2302
-
2303
- if flag_args_blockarg
2304
- blk_ty = aargs.pop
2305
- elsif blk_iseq
2306
- blk_ty = Type::Proc.new(ISeqBlock.new(blk_iseq, ep), Type::Instance.new(Type::Builtin[:proc]))
2307
- else
2308
- blk_ty = Type.nil
2309
- end
2310
-
2311
- new_blk_ty = Type.bot
2312
- blk_ty.each_child do |blk_ty|
2313
- case blk_ty
2314
- when Type.nil
2315
- when Type.any
2316
- when Type::Proc
2317
- when Type::Symbol
2318
- blk_ty = Type::Proc.new(SymbolBlock.new(blk_ty.sym), Type::Instance.new(Type::Builtin[:proc]))
2319
- else
2320
- # XXX: attempt to call to_proc
2321
- error(ep, "wrong argument type #{ blk_ty.screen_name(self) } (expected Proc)")
2322
- blk_ty = Type.any
2323
- end
2324
- new_blk_ty = new_blk_ty.union(blk_ty)
2325
- end
2326
- blk_ty = new_blk_ty
2327
-
2328
- if flag_args_splat
2329
- if ruby_3_3_keywords?
2330
- if flag_args_kw_splat
2331
- kw_tys = type_to_keywords(globalize_type(aargs[-1], env, ep), ep)
2332
- aargs = aargs[0..-2]
2333
- else
2334
- kw_tys = {}
2335
- end
2336
- rest_ty = aargs.last
2337
- aargs = aargs[0..-2]
2338
- else
2339
- rest_ty = aargs.last
2340
- aargs = aargs[0..-2]
2341
- if flag_args_kw_splat
2342
- # XXX: The types contained in ActualArguments are expected to be all local types.
2343
- # This "globalize_type" breaks the invariant, and violates the assertion of Union#globalize that asserts @elems be nil.
2344
- # To fix this issue fundamentally, ActualArguments should keep all arguments as-is (as like the VM does),
2345
- # and globalize some types on the on-demand bases.
2346
- ty = globalize_type(rest_ty, env, ep)
2347
- if ty.is_a?(Type::Array)
2348
- _, (ty,) = ty.elems.take_last(1)
2349
- kw_tys = type_to_keywords(ty, ep)
2350
- else
2351
- raise NotImplementedError
2352
- end
2353
- else
2354
- kw_tys = {}
2355
- end
2356
- end
2357
- aargs = ActualArguments.new(aargs, rest_ty, kw_tys, blk_ty)
2358
- elsif flag_args_kw_splat
2359
- last = aargs.last
2360
- # XXX: The types contained in ActualArguments are expected to be all local types.
2361
- # This "globalize_type" breaks the invariant, and violates the assertion of Union#globalize that asserts @elems be nil.
2362
- # To fix this issue fundamentally, ActualArguments should keep all arguments as-is (as like the VM does),
2363
- # and globalize some types on the on-demand bases.
2364
- ty = globalize_type(last, env, ep)
2365
- case ty
2366
- when Type::Hash
2367
- aargs = aargs[0..-2]
2368
- kw_tys = ty.elems.to_keywords
2369
- when Type::Union
2370
- hash_elems = nil
2371
- ty.elems&.each do |(container_kind, base_type), elems|
2372
- if container_kind == Type::Hash
2373
- hash_elems = hash_elems ? hash_elems.union(elems) : elems
2374
- end
2375
- end
2376
- if hash_elems
2377
- kw_tys = hash_elems.to_keywords
2378
- else
2379
- kw_tys = { nil => Type.any }
2380
- end
2381
- when Type::Any
2382
- aargs = aargs[0..-2]
2383
- kw_tys = { nil => Type.any }
2384
- else
2385
- warn(ep, "non hash is passed to **kwarg?")
2386
- kw_tys = { nil => Type.any }
2387
- end
2388
- aargs = ActualArguments.new(aargs, nil, kw_tys, blk_ty)
2389
- elsif flag_args_kwarg
2390
- kw_vals = aargs.pop(kw_arg.size)
2391
-
2392
- kw_tys = {}
2393
- kw_arg.zip(kw_vals) do |key, v_ty|
2394
- kw_tys[key] = v_ty
2395
- end
2396
-
2397
- aargs = ActualArguments.new(aargs, nil, kw_tys, blk_ty)
2398
- else
2399
- aargs = ActualArguments.new(aargs, nil, {}, blk_ty)
2400
- end
2401
-
2402
- if blk_iseq
2403
- # pending dummy execution
2404
- nctx = Context.new(blk_iseq, ep.ctx.cref, ep.ctx.mid)
2405
- nep = ExecutionPoint.new(nctx, 0, ep)
2406
- nlocals = [Type.any] * blk_iseq.locals.size
2407
- nsenv = StaticEnv.new(env.static_env.recv_ty, Type.any, env.static_env.mod_func, env.static_env.pub_meth)
2408
- nenv = Env.new(nsenv, nlocals, [], nil)
2409
- pend_block_dummy_execution(blk_ty, blk_iseq, nep, nenv)
2410
- merge_return_env(ep) {|tenv| tenv ? tenv.merge(env) : env }
2411
- end
2412
-
2413
- aargs.node_id = opt[:node_id]
2414
-
2415
- return env, recv, mid, aargs
2416
- end
2417
-
2418
- def do_send(recvs, mid, aargs, ep, env, &ctn)
2419
- if mid == :__typeprof_lsp_completion
2420
- names = {}
2421
- recvs.each_child do |recv|
2422
- case recv
2423
- when Type::Void, Type::Any
2424
- else
2425
- klass, singleton, include_subclasses = recv.method_dispatch_info
2426
- names.merge!(get_all_methods(klass, singleton, include_subclasses)) if klass
2427
- end
2428
- end
2429
- @lsp_completion = names
2430
- return ctn[Type.any, ep, env]
2431
- end
2432
-
2433
- recvs.each_child do |recv|
2434
- case recv
2435
- when Type::Void
2436
- error(ep, "void's method is called: #{ globalize_type(recv, env, ep).screen_name(self) }##{ mid }")
2437
- ctn[Type.any, ep, env]
2438
- when Type::Any
2439
- ctn[Type.any, ep, env]
2440
- else
2441
- klass, singleton, include_subclasses = recv.method_dispatch_info
2442
- meths = get_method(klass, singleton, include_subclasses, mid) if klass
2443
- if meths
2444
- path, loc = Config.current.options[:signature_help_loc]
2445
- if path && path == ep.ctx.iseq.path && mid != :inherited # XXX: too ad-hoc!!!
2446
- path, code_range = ep&.detailed_source_location
2447
- if path && code_range&.contain_loc?(loc)
2448
- @lsp_signature_help[code_range] = {
2449
- recv: recv,
2450
- mid: mid,
2451
- singleton: singleton,
2452
- mdefs: meths,
2453
- node_id: aargs.node_id,
2454
- }
2455
- end
2456
- end
2457
- meths.each do |meth|
2458
- meth.do_send(recv, mid, aargs, ep, env, self, &ctn)
2459
- end
2460
- else
2461
- meths = get_method(klass, singleton, include_subclasses, :method_missing) if klass
2462
- if meths
2463
- aargs = aargs.for_method_missing(Type::Symbol.new(mid, Type::Instance.new(Type::Builtin[:sym])))
2464
- meths.each do |meth|
2465
- meth.do_send(recv, :method_missing, aargs, ep, env, self, &ctn)
2466
- end
2467
- else
2468
- error(ep, "undefined method: #{ globalize_type(recv, env, ep).screen_name(self) }##{ mid }")
2469
- ctn[Type.any, ep, env]
2470
- end
2471
- end
2472
- end
2473
- end
2474
- end
2475
-
2476
- def do_invoke_block(blk, aargs, ep, env, replace_recv_ty: nil, replace_cref: nil, &ctn)
2477
- blk.each_child do |blk|
2478
- if blk.is_a?(Type::Proc)
2479
- blk.block_body.do_call(aargs, ep, env, self, replace_recv_ty: replace_recv_ty, replace_cref: replace_cref, &ctn)
2480
- else
2481
- warn(ep, "non-proc is passed as a block") if blk != Type.any
2482
- ctn[Type.any, ep, env]
2483
- end
2484
- end
2485
- end
2486
-
2487
- def do_define_iseq_method(ep, env, mid, iseq, outer_ep)
2488
- cref = ep.ctx.cref
2489
- if cref.klass.is_a?(Type::Class)
2490
- typed_mdef = check_typed_method(cref.klass, mid, ep.ctx.cref.singleton)
2491
- recv = cref.klass
2492
- recv = Type::Instance.new(recv) unless ep.ctx.cref.singleton
2493
- if typed_mdef
2494
- mdef = ISeqMethodDef.new(iseq, cref, outer_ep, env.static_env.pub_meth)
2495
- typed_mdef.each do |typed_mdef|
2496
- typed_mdef.do_match_iseq_mdef(mdef, recv, mid, env, ep, self)
2497
- end
2498
- else
2499
- if ep.ctx.cref.singleton
2500
- meth = add_singleton_iseq_method(cref.klass, mid, iseq, cref, outer_ep, true)
2501
- else
2502
- meth = add_iseq_method(cref.klass, mid, iseq, cref, outer_ep, env.static_env.pub_meth)
2503
- if env.static_env.mod_func
2504
- add_singleton_iseq_method(cref.klass, mid, iseq, cref, outer_ep, true)
2505
- end
2506
- end
2507
- end
2508
-
2509
- pend_method_execution(iseq, meth, recv, mid, ep.ctx.cref, outer_ep)
2510
- else
2511
- # XXX: what to do?
2512
- end
2513
- end
2514
-
2515
- def show_block_signature(blks)
2516
- bsig = nil
2517
- ret_ty = Type.bot
2518
-
2519
- blks.each do |blk|
2520
- blk.each_child_global do |blk|
2521
- bsig0 = @block_signatures[blk.block_body]
2522
- if bsig0
2523
- if bsig
2524
- bsig = bsig.merge(bsig0)
2525
- else
2526
- bsig = bsig0
2527
- end
2528
- end
2529
-
2530
- @block_to_ctx[blk.block_body]&.each do |blk_ctx|
2531
- ret_ty = ret_ty.union(@return_values[blk_ctx]) if @return_values[blk_ctx]
2532
- end
2533
- end
2534
- end
2535
-
2536
- bsig ||= BlockSignature.new([], [], nil, Type.nil)
2537
-
2538
- bsig, = bsig.screen_name(nil, self)
2539
- ret_ty = ret_ty.screen_name(self)
2540
- ret_ty = (ret_ty.include?("|") ? "(#{ ret_ty })" : ret_ty) # XXX?
2541
-
2542
- bsig = bsig + " " if bsig != ""
2543
- "{ #{ bsig }-> #{ ret_ty } }"
2544
- end
2545
-
2546
- def show_proc_signature(blks)
2547
- farg_tys, ret_ty = nil, Type.bot
2548
-
2549
- blks.each do |blk|
2550
- blk.each_child_global do |blk|
2551
- next if blk.block_body.is_a?(TypedBlock) # XXX: Support TypedBlock
2552
- next unless @block_to_ctx[blk.block_body] # this occurs when screen_name is called before type-profiling finished (e.g., error message)
2553
- @block_to_ctx[blk.block_body].each do |blk_ctx|
2554
- if farg_tys
2555
- if @method_signatures[blk_ctx]
2556
- farg_tys = farg_tys.merge_as_block_arguments(@method_signatures[blk_ctx])
2557
- else
2558
- # this occurs when screen_name is called before type-profiling finished (e.g., error message)
2559
- end
2560
- else
2561
- farg_tys = @method_signatures[blk_ctx]
2562
- end
2563
-
2564
- ret_ty = ret_ty.union(@return_values[blk_ctx]) if @return_values[blk_ctx]
2565
- end
2566
- end
2567
- end
2568
-
2569
- return Type.any.screen_name(self) if @types_being_shown.include?(farg_tys) || @types_being_shown.include?(ret_ty)
2570
-
2571
- begin
2572
- @types_being_shown << farg_tys << ret_ty
2573
- farg_tys, = farg_tys ? farg_tys.screen_name(nil, self) : ["(unknown)"]
2574
- ret_ty = ret_ty.screen_name(self)
2575
- ret_ty = (ret_ty.include?("|") ? "(#{ ret_ty })" : ret_ty) # XXX?
2576
-
2577
- farg_tys = farg_tys + " " if farg_tys != ""
2578
- "^#{ farg_tys }-> #{ ret_ty }"
2579
- ensure
2580
- @types_being_shown.pop(2)
2581
- end
2582
- end
2583
-
2584
- def show_method_signature(ctx)
2585
- farg_tys = @method_signatures[ctx]
2586
- return nil unless farg_tys
2587
- ret_ty = ctx.mid == :initialize ? Type::Void.new : @return_values[ctx] || Type.bot
2588
-
2589
- untyped = farg_tys.include_untyped?(self) || ret_ty.include_untyped?(self)
2590
-
2591
- farg_tys, ranges = farg_tys.screen_name(ctx.iseq, self)
2592
- ret_ty = ret_ty.screen_name(self)
2593
- ret_ty = (ret_ty.include?("|") ? "(#{ ret_ty })" : ret_ty) # XXX?
2594
-
2595
- return "#{ (farg_tys.empty? ? "" : "#{ farg_tys } ") }-> #{ ret_ty }", untyped, ranges
2596
- end
2597
- end
2598
- end