typeprof 0.21.11 → 0.30.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (72) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +15 -31
  3. data/bin/typeprof +5 -0
  4. data/doc/doc.ja.md +134 -0
  5. data/doc/doc.md +136 -0
  6. data/lib/typeprof/cli/cli.rb +178 -0
  7. data/lib/typeprof/cli.rb +3 -133
  8. data/lib/typeprof/code_range.rb +112 -0
  9. data/lib/typeprof/core/ast/base.rb +263 -0
  10. data/lib/typeprof/core/ast/call.rb +259 -0
  11. data/lib/typeprof/core/ast/const.rb +126 -0
  12. data/lib/typeprof/core/ast/control.rb +433 -0
  13. data/lib/typeprof/core/ast/meta.rb +150 -0
  14. data/lib/typeprof/core/ast/method.rb +339 -0
  15. data/lib/typeprof/core/ast/misc.rb +263 -0
  16. data/lib/typeprof/core/ast/module.rb +123 -0
  17. data/lib/typeprof/core/ast/pattern.rb +140 -0
  18. data/lib/typeprof/core/ast/sig_decl.rb +471 -0
  19. data/lib/typeprof/core/ast/sig_type.rb +663 -0
  20. data/lib/typeprof/core/ast/value.rb +319 -0
  21. data/lib/typeprof/core/ast/variable.rb +315 -0
  22. data/lib/typeprof/core/ast.rb +472 -0
  23. data/lib/typeprof/core/builtin.rb +146 -0
  24. data/lib/typeprof/core/env/method.rb +137 -0
  25. data/lib/typeprof/core/env/method_entity.rb +55 -0
  26. data/lib/typeprof/core/env/module_entity.rb +408 -0
  27. data/lib/typeprof/core/env/static_read.rb +155 -0
  28. data/lib/typeprof/core/env/type_alias_entity.rb +27 -0
  29. data/lib/typeprof/core/env/value_entity.rb +32 -0
  30. data/lib/typeprof/core/env.rb +366 -0
  31. data/lib/typeprof/core/graph/box.rb +998 -0
  32. data/lib/typeprof/core/graph/change_set.rb +224 -0
  33. data/lib/typeprof/core/graph/filter.rb +155 -0
  34. data/lib/typeprof/core/graph/vertex.rb +225 -0
  35. data/lib/typeprof/core/service.rb +514 -0
  36. data/lib/typeprof/core/type.rb +352 -0
  37. data/lib/typeprof/core/util.rb +81 -0
  38. data/lib/typeprof/core.rb +31 -0
  39. data/lib/typeprof/diagnostic.rb +35 -0
  40. data/lib/typeprof/lsp/messages.rb +415 -0
  41. data/lib/typeprof/lsp/server.rb +203 -0
  42. data/lib/typeprof/lsp/text.rb +69 -0
  43. data/lib/typeprof/lsp/util.rb +51 -0
  44. data/lib/typeprof/lsp.rb +4 -907
  45. data/lib/typeprof/version.rb +1 -1
  46. data/lib/typeprof.rb +4 -18
  47. data/typeprof.gemspec +5 -7
  48. metadata +47 -33
  49. data/.github/dependabot.yml +0 -6
  50. data/.github/workflows/main.yml +0 -39
  51. data/.gitignore +0 -9
  52. data/Gemfile +0 -17
  53. data/Gemfile.lock +0 -41
  54. data/Rakefile +0 -10
  55. data/exe/typeprof +0 -10
  56. data/lib/typeprof/analyzer.rb +0 -2598
  57. data/lib/typeprof/arguments.rb +0 -414
  58. data/lib/typeprof/block.rb +0 -176
  59. data/lib/typeprof/builtin.rb +0 -893
  60. data/lib/typeprof/code-range.rb +0 -177
  61. data/lib/typeprof/config.rb +0 -158
  62. data/lib/typeprof/container-type.rb +0 -912
  63. data/lib/typeprof/export.rb +0 -589
  64. data/lib/typeprof/import.rb +0 -852
  65. data/lib/typeprof/insns-def.rb +0 -65
  66. data/lib/typeprof/iseq.rb +0 -864
  67. data/lib/typeprof/method.rb +0 -355
  68. data/lib/typeprof/type.rb +0 -1140
  69. data/lib/typeprof/utils.rb +0 -212
  70. data/tools/coverage.rb +0 -14
  71. data/tools/setup-insns-def.rb +0 -30
  72. data/typeprof-lsp +0 -3
@@ -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