katakata_irb 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,1108 @@
1
+ require_relative 'types'
2
+ require 'ripper'
3
+ require 'set'
4
+
5
+ class KatakataIrb::TypeSimulator
6
+ class DigTarget
7
+ def initialize(parents, receiver, &block)
8
+ @dig_ids = parents.to_h { [_1.__id__, true] }
9
+ @target_id = receiver.__id__
10
+ @block = block
11
+ end
12
+
13
+ def dig?(node) = @dig_ids[node.__id__]
14
+ def target?(node) = @target_id == node.__id__
15
+ def resolve(type, scope)
16
+ @block.call type, scope
17
+ end
18
+ end
19
+
20
+ class BaseScope
21
+ def initialize(binding, self_object)
22
+ @binding, @self_object = binding, self_object
23
+ @cache = { SELF => KatakataIrb::Types.type_from_object(self_object) }
24
+ @local_variables = binding.local_variables.map(&:to_s).to_set
25
+ end
26
+
27
+ def mutable?() = false
28
+
29
+ def [](name)
30
+ @cache[name] ||= (
31
+ fallback = KatakataIrb::Types::NIL
32
+ case BaseScope.type_by_name name
33
+ when :cvar
34
+ KatakataIrb::TypeSimulator.type_of(fallback:) { @self_object.class_variable_get name }
35
+ when :ivar
36
+ KatakataIrb::TypeSimulator.type_of(fallback:) { @self_object.instance_variable_get name }
37
+ when :lvar
38
+ KatakataIrb::TypeSimulator.type_of(fallback:) { @binding.local_variable_get(name) }
39
+ when :const
40
+ KatakataIrb::TypeSimulator.type_of(fallback:) { @binding.eval name }
41
+ end
42
+ )
43
+ end
44
+
45
+ def self_type
46
+ self[SELF]
47
+ end
48
+
49
+ def local_variables
50
+ @local_variables.to_a
51
+ end
52
+
53
+ def self.type_by_name(name)
54
+ if name.start_with? '@@'
55
+ :cvar
56
+ elsif name.start_with? '@'
57
+ :ivar
58
+ elsif name.start_with? '$'
59
+ :gvar
60
+ elsif name.start_with? '%'
61
+ :internal
62
+ elsif name[0].downcase != name[0]
63
+ :const
64
+ else
65
+ :lvar
66
+ end
67
+ end
68
+
69
+ def has?(name)
70
+ case BaseScope.type_by_name name
71
+ when :cvar
72
+ @self_object.class_variable_defined? name
73
+ when :ivar
74
+ @self_object.instance_variable_defined? name
75
+ when :lvar
76
+ @local_variables.include? name
77
+ when :const
78
+ @binding.eval("#{name};true") rescue false
79
+ when :internal
80
+ true
81
+ end
82
+ end
83
+ end
84
+
85
+ class Scope
86
+ attr_reader :parent, :jump_branches
87
+
88
+ def self.from_binding(binding) = new BaseScope.new(binding, binding.eval('self'))
89
+
90
+ def initialize(parent, table = {}, trace_cvar: true, trace_ivar: true, trace_lvar: true, passthrough: false)
91
+ @tables = [table]
92
+ @parent = parent
93
+ @trace_cvar = trace_cvar
94
+ @trace_ivar = trace_ivar
95
+ @trace_lvar = trace_lvar
96
+ @passthrough = passthrough
97
+ @terminated = false
98
+ @jump_branches = []
99
+ end
100
+
101
+ def mutable? = true
102
+
103
+ def terminated?
104
+ @terminated
105
+ end
106
+
107
+ def terminate_with(type)
108
+ scopes = ancestors.select(&:mutable?)
109
+ scope = scopes.find { _1.has_own? type } || scopes.last
110
+ index = scopes.index scope
111
+ scope.jump_branches << scopes.drop(index).map(&:branch_table_clone)
112
+ terminate
113
+ end
114
+
115
+ def terminate
116
+ @terminated = true
117
+ end
118
+
119
+ def branch_table_clone() = @tables.last.dup
120
+
121
+ def trace?(name)
122
+ return false unless @parent
123
+ type = BaseScope.type_by_name(name)
124
+ type == :cvar ? @trace_cvar : type == :ivar ? @trace_ivar : type == :lvar ? @trace_lvar : true
125
+ end
126
+
127
+ def [](name)
128
+ @tables.reverse_each do |table|
129
+ return table[name] if table.key? name
130
+ end
131
+ @parent[name] if trace? name
132
+ end
133
+
134
+ def []=(name, type)
135
+ # return if terminated?
136
+ if @passthrough && !BaseScope.type_by_name(name) == :internal
137
+ @parent[name] = type
138
+ elsif trace?(name) && @parent.mutable? && !@tables.any? { _1.key? name } && @parent.has?(name)
139
+ @parent[name] = type
140
+ else
141
+ @tables.last[name] = type
142
+ end
143
+ end
144
+
145
+ def self_type
146
+ self[SELF]
147
+ end
148
+
149
+ def local_variables
150
+ lvar_keys = @tables.flat_map(&:keys).select do |name|
151
+ BaseScope.type_by_name(name) == :lvar
152
+ end
153
+ lvar_keys |= @parent.local_variables if @trace_lvar
154
+ lvar_keys
155
+ end
156
+
157
+ def start_branch
158
+ @tables << {}
159
+ end
160
+
161
+ def end_branch
162
+ @tables.pop
163
+ end
164
+
165
+ def merge_jumps
166
+ if terminated?
167
+ merge @jump_branches
168
+ else
169
+ merge [*@jump_branches, [{}] * ancestors.size]
170
+ end
171
+ end
172
+
173
+ def merge_branch(tables)
174
+ target_table = @tables.last
175
+ keys = tables.flat_map(&:keys).uniq
176
+ keys.each do |key|
177
+ original_value = self[key] || KatakataIrb::Types::NIL
178
+ target_table[key] = KatakataIrb::Types::UnionType[*tables.map { _1[key] || original_value }.uniq]
179
+ end
180
+ end
181
+
182
+ def ancestors
183
+ scopes = [self]
184
+ scopes << scopes.last.parent while scopes.last.parent&.mutable?
185
+ scopes
186
+ end
187
+
188
+ def conditional(&block)
189
+ run_branches(block, -> {}).first || KatakataIrb::Types::NIL
190
+ end
191
+
192
+ def run_branches(*blocks)
193
+ results = blocks.map { branch(&_1) }.reject(&:last)
194
+ merge results.map { _2 }
195
+ if results.empty?
196
+ terminate
197
+ []
198
+ else
199
+ results.map(&:first)
200
+ end
201
+ end
202
+
203
+ def branch
204
+ scopes = ancestors
205
+ scopes.each(&:start_branch)
206
+ @terminated = false
207
+ result = yield
208
+ terminated = @terminated
209
+ @terminated = false
210
+ [result, scopes.map(&:end_branch), terminated]
211
+ end
212
+
213
+ def merge(branches)
214
+ scopes = ancestors
215
+ scopes.zip(*branches).each do |scope, *tables|
216
+ scope.merge_branch(tables)
217
+ end
218
+ end
219
+
220
+ def base_scope
221
+ @parent&.mutable? ? @parent.base_scope : @parent
222
+ end
223
+
224
+ def has_own?(name)
225
+ @tables.any? { _1.key? name }
226
+ end
227
+
228
+ def has?(name)
229
+ has_own?(name) || (trace?(name) && @parent.has?(name))
230
+ end
231
+ end
232
+
233
+ module LexerElemMatcher
234
+ refine Ripper::Lexer::Elem do
235
+ def deconstruct_keys(_keys)
236
+ {
237
+ tok:,
238
+ event:,
239
+ label: state.allbits?(Ripper::EXPR_LABEL),
240
+ beg: state.allbits?(Ripper::EXPR_BEG),
241
+ dot: state.allbits?(Ripper::EXPR_DOT)
242
+ }
243
+ end
244
+ end
245
+ end
246
+ using LexerElemMatcher
247
+
248
+ OBJECT_METHODS = {
249
+ to_s: KatakataIrb::Types::STRING,
250
+ to_str: KatakataIrb::Types::STRING,
251
+ to_a: KatakataIrb::Types::ARRAY,
252
+ to_ary: KatakataIrb::Types::ARRAY,
253
+ to_h: KatakataIrb::Types::HASH,
254
+ to_hash: KatakataIrb::Types::HASH,
255
+ to_i: KatakataIrb::Types::INTEGER,
256
+ to_int: KatakataIrb::Types::INTEGER,
257
+ to_f: KatakataIrb::Types::FLOAT,
258
+ to_c: KatakataIrb::Types::COMPLEX,
259
+ to_r: KatakataIrb::Types::RATIONAL
260
+ }
261
+
262
+ SELF = '%self'
263
+ BREAK_RESULT = '%break'
264
+ NEXT_RESULT = '%next'
265
+ RETURN_RESULT = '%return'
266
+
267
+ def initialize(dig_targets)
268
+ @dig_targets = dig_targets
269
+ end
270
+
271
+ def simulate_evaluate(sexp, scope, case_target: nil)
272
+ result = simulate_evaluate_inner(sexp, scope, case_target:)
273
+ @dig_targets.resolve result, scope if @dig_targets.target?(sexp)
274
+ result
275
+ end
276
+
277
+ def simulate_evaluate_inner(sexp, scope, case_target: nil)
278
+ case sexp
279
+ in [:program, statements]
280
+ statements.map { simulate_evaluate _1, scope }.last
281
+ in [:def | :defs,]
282
+ sexp in [:def, method_name_exp, params, body_stmt]
283
+ sexp in [:defs, receiver_exp, dot_exp, method_name_exp, params, body_stmt]
284
+ if receiver_exp
285
+ receiver_exp in [:paren, receiver_exp]
286
+ self_type = simulate_evaluate receiver_exp, scope
287
+ else
288
+ current_self_types = scope.self_type.types
289
+ self_types = current_self_types.map do |type|
290
+ if (type in KatakataIrb::Types::SingletonType) && type.module_or_class.is_a?(Class)
291
+ KatakataIrb::Types::InstanceType.new type.module_or_class
292
+ else
293
+ type
294
+ end
295
+ end
296
+ self_type = KatakataIrb::Types::UnionType[*self_types]
297
+ end
298
+ if @dig_targets.dig? sexp
299
+ params in [:paren, params]
300
+ params_table = extract_param_names(params).to_h { [_1, KatakataIrb::Types::NIL] }
301
+ method_scope = Scope.new scope, { **params_table, SELF => self_type, BREAK_RESULT => nil, NEXT_RESULT => nil, RETURN_RESULT => nil }, trace_lvar: false
302
+ evaluate_assign_params params, [], method_scope
303
+ method_scope.conditional { evaluate_param_defaults params, method_scope }
304
+ simulate_evaluate body_stmt, method_scope
305
+ end
306
+ KatakataIrb::Types::SYMBOL
307
+ in [:@int,]
308
+ KatakataIrb::Types::INTEGER
309
+ in [:@float,]
310
+ KatakataIrb::Types::FLOAT
311
+ in [:@rational,]
312
+ KatakataIrb::Types::RATIONAL
313
+ in [:@imaginary,]
314
+ KatakataIrb::Types::COMPLEX
315
+ in [:@tstring_content,]
316
+ KatakataIrb::Types::STRING
317
+ in [:symbol_literal,]
318
+ KatakataIrb::Types::SYMBOL
319
+ in [:dyna_symbol, [:string_content, *statements]]
320
+ statements.each { simulate_evaluate _1, scope }
321
+ KatakataIrb::Types::SYMBOL
322
+ in [:@CHAR,]
323
+ KatakataIrb::Types::STRING
324
+ in [:@backref,]
325
+ KatakataIrb::Types::UnionType[KatakataIrb::Types::STRING, KatakataIrb::Types::NIL]
326
+ in [:string_literal, [:string_content, *statements]]
327
+ statements.each { simulate_evaluate _1, scope }
328
+ KatakataIrb::Types::STRING
329
+ in [:xstring_literal, statements]
330
+ statements.each { simulate_evaluate _1, scope }
331
+ KatakataIrb::Types::STRING
332
+ in [:string_embexpr, statements]
333
+ statements.each { simulate_evaluate _1, scope }
334
+ KatakataIrb::Types::STRING
335
+ in [:string_dvar,]
336
+ KatakataIrb::Types::STRING
337
+ in [:regexp_literal, statements, _regexp_end]
338
+ statements.each { simulate_evaluate _1, scope }
339
+ KatakataIrb::Types::REGEXP
340
+ in [:array, [:args_add_star,] => star]
341
+ args, kwargs = retrieve_method_args star
342
+ types = args.flat_map do |elem|
343
+ if elem in KatakataIrb::Types::Splat
344
+ splat = simulate_evaluate elem.item, scope
345
+ array_value = to_array splat, :to_a
346
+ array_value ? (array_value.params[:Elem] || []) : splat
347
+ else
348
+ simulate_evaluate elem, scope
349
+ end
350
+ end
351
+ types << kwargs_type(kwargs, scope) if kwargs && kwargs.any?
352
+ KatakataIrb::Types::InstanceType.new Array, Elem: KatakataIrb::Types::UnionType[*types]
353
+ in [:array, statements]
354
+ if statements.nil? || statements.empty?
355
+ KatakataIrb::Types::ARRAY
356
+ elsif statements.all? { _1 in [Symbol,] }
357
+ # normal array
358
+ elem = statements ? KatakataIrb::Types::UnionType[*statements.map { simulate_evaluate _1, scope }] : KatakataIrb::Types::NIL
359
+ KatakataIrb::Types::InstanceType.new Array, Elem: elem
360
+ else
361
+ # %I[] or %W[]
362
+ statements.each do |sub_statements|
363
+ sub_statements.each { simulate_evaluate _1, scope }
364
+ end
365
+ # TODO: use AST because Ripper.sexp('%I[a]') == Ripper.sexp('%W[a]')
366
+ elem = KatakataIrb::Types::UnionType[KatakataIrb::Types::STRING, KatakataIrb::Types::SYMBOL]
367
+ KatakataIrb::Types::InstanceType.new Array, Elem: elem
368
+ end
369
+ in [:bare_assoc_hash, args]
370
+ simulate_evaluate [:hash, [:assoclist_from_args, args]], scope
371
+ in [:hash, [:assoclist_from_args, args]]
372
+ keys = []
373
+ values = []
374
+ args.each do |arg|
375
+ case arg
376
+ in [:assoc_new, key, value]
377
+ if key in [:@label, label, pos]
378
+ keys << KatakataIrb::Types::SYMBOL
379
+ name = label.delete ':'
380
+ value ||= [:__var_ref_or_call, [name =~ /\A[A-Z]/ ? :@const : :@ident, name, pos]]
381
+ else
382
+ keys << simulate_evaluate(key, scope)
383
+ end
384
+ values << simulate_evaluate(value, scope)
385
+ in [:assoc_splat, value]
386
+ hash = simulate_evaluate value, scope
387
+ unless (hash in KatakataIrb::Types::InstanceType) && hash.klass == Hash
388
+ hash = simulate_call hash, :to_hash, [], nil, nil
389
+ end
390
+ if (hash in KatakataIrb::Types::InstanceType) && hash.klass == Hash
391
+ keys << hash.params[:K] if hash.params[:K]
392
+ values << hash.params[:V] if hash.params[:V]
393
+ end
394
+ end
395
+ end
396
+ KatakataIrb::Types::InstanceType.new Hash, K: KatakataIrb::Types::UnionType[*keys], V: KatakataIrb::Types::UnionType[*values]
397
+ in [:hash, nil]
398
+ KatakataIrb::Types::InstanceType.new Hash
399
+ in [:paren | :ensure | :else, statements]
400
+ statements.map { simulate_evaluate _1, scope }.last
401
+ in [:const_path_ref, receiver, [:@const, name,]]
402
+ r = simulate_evaluate receiver, scope
403
+ (r in KatakataIrb::Types::SingletonType) ? self.class.type_of { r.module_or_class.const_get name } : KatakataIrb::Types::NIL
404
+ in [:__var_ref_or_call, [type, name, pos]]
405
+ sexp = scope.has?(name) ? [:var_ref, [type, name, pos]] : [:vcall, [:@ident, name, pos]]
406
+ simulate_evaluate sexp, scope
407
+ in [:var_ref, [:@kw, name,]]
408
+ case name
409
+ in 'self'
410
+ scope.self_type
411
+ in 'true'
412
+ KatakataIrb::Types::TRUE
413
+ in 'false'
414
+ KatakataIrb::Types::FALSE
415
+ in 'nil'
416
+ KatakataIrb::Types::NIL
417
+ in '__FILE__'
418
+ KatakataIrb::Types::STRING
419
+ in '__LINE__'
420
+ KatakataIrb::Types::INTEGER
421
+ in '__ENCODING__'
422
+ KatakataIrb::Types::InstanceType.new Encoding
423
+ end
424
+ in [:var_ref, [:@const | :@ivar | :@cvar | :@gvar | :@ident, name,]]
425
+ scope[name] || KatakataIrb::Types::NIL
426
+ in [:const_ref, [:@const, name,]]
427
+ scope[name] || KatakataIrb::Types::NIL
428
+ in [:aref, receiver, args]
429
+ receiver_type = simulate_evaluate receiver, scope if receiver
430
+ args, kwargs, _block = retrieve_method_args args
431
+ args_type = args.map do |arg|
432
+ if arg in KatakataIrb::Types::Splat
433
+ simulate_evaluate arg.item, scope
434
+ nil # TODO: splat
435
+ else
436
+ simulate_evaluate arg, scope
437
+ end
438
+ end
439
+ simulate_call receiver_type, :[], args_type, kwargs_type(kwargs, scope), nil
440
+ in [:call | :vcall | :command | :command_call | :method_add_arg | :method_add_block,]
441
+ if (sexp in [:vcall, [:@ident, name,]]) && scope.has?(name)
442
+ # workaround for https://bugs.ruby-lang.org/issues/19175
443
+ return scope[name]
444
+ end
445
+ receiver, method, args, kwargs, block, conditional = retrieve_method_call sexp
446
+ receiver_type = receiver ? simulate_evaluate(receiver, scope) : scope.self_type
447
+ evaluate_method = lambda do
448
+ args_type = args.map do |arg|
449
+ if arg in KatakataIrb::Types::Splat
450
+ simulate_evaluate arg.item, scope
451
+ nil # TODO: splat
452
+ else
453
+ simulate_evaluate arg, scope
454
+ end
455
+ end
456
+
457
+ if block
458
+ if block in [:symbol_literal, [:symbol, [:@ident, block_name,]]]
459
+ call_block_proc = ->(block_args) do
460
+ block_receiver, *rest = block_args
461
+ block_receiver ? simulate_call(block_receiver || KatakataIrb::Types::OBJECT, block_name, rest, nil, nil) : KatakataIrb::Types::OBJECT
462
+ end
463
+ elsif block in [:do_block | :brace_block => type, block_var, body]
464
+ block_var in [:block_var, params,]
465
+ call_block_proc = ->(block_args) do
466
+ result, breaks, nexts = scope.conditional do
467
+ if params
468
+ names = extract_param_names(params)
469
+ else
470
+ names = (1..max_numbered_params(body)).map { "_#{_1}" }
471
+ params = [:params, names.map { [:@ident, _1, [0, 0]] }, nil, nil, nil, nil, nil, nil]
472
+ end
473
+ params_table = names.zip(block_args).to_h { [_1, _2 || KatakataIrb::Types::NIL] }
474
+ block_scope = Scope.new scope, { **params_table, BREAK_RESULT => nil, NEXT_RESULT => nil }
475
+ evaluate_assign_params params, block_args, block_scope
476
+ block_scope.conditional { evaluate_param_defaults params, block_scope } if params
477
+ if type == :do_block
478
+ result = simulate_evaluate body, block_scope
479
+ else
480
+ result = body.map { simulate_evaluate _1, block_scope }.last
481
+ end
482
+ block_scope.merge_jumps
483
+ result = KatakataIrb::Types::NIL if block_scope.terminated?
484
+ [result, block_scope[BREAK_RESULT], block_scope[NEXT_RESULT]]
485
+ end
486
+ [KatakataIrb::Types::UnionType[result, *nexts], breaks]
487
+ end
488
+ else
489
+ simulate_evaluate block, scope
490
+ end
491
+ end
492
+ simulate_call receiver_type, method, args_type, kwargs_type(kwargs, scope), call_block_proc
493
+ end
494
+ if conditional
495
+ scope.conditional { evaluate_method.call }
496
+ else
497
+ evaluate_method.call
498
+ end
499
+ in [:binary, a, Symbol => op, b]
500
+ atype = simulate_evaluate a, scope
501
+ case op
502
+ when :'&&', :and
503
+ btype = scope.conditional { simulate_evaluate b, scope }
504
+ KatakataIrb::Types::UnionType[btype, KatakataIrb::Types::NIL, KatakataIrb::Types::FALSE]
505
+ when :'||', :or
506
+ btype = scope.conditional { simulate_evaluate b, scope }
507
+ KatakataIrb::Types::UnionType[atype, btype]
508
+ else
509
+ btype = simulate_evaluate b, scope
510
+ simulate_call atype, op, [btype], nil, nil
511
+ end
512
+ in [:unary, op, receiver]
513
+ simulate_call simulate_evaluate(receiver, scope), op, [], nil, nil
514
+ in [:lambda, params, statements]
515
+ params in [:paren, params] # ->{}, -> do end
516
+ statements in [:bodystmt, statements, _unknown, _unknown, _unknown] # -> do end
517
+ params in [:paren, params]
518
+ params_table = extract_param_names(params).to_h { [_1, KatakataIrb::Types::NIL] }
519
+ block_scope = Scope.new scope, { **params_table, BREAK_RESULT => nil, NEXT_RESULT => nil, RETURN_RESULT => nil }
520
+ evaluate_assign_params params, [], block_scope
521
+ block_scope.conditional { evaluate_param_defaults params, block_scope }
522
+ statements.each { simulate_evaluate _1, block_scope }
523
+ block_scope.merge_jumps
524
+ KatakataIrb::Types::ProcType.new
525
+ in [:assign, [:var_field, [:@gvar | :@ivar | :@cvar | :@ident | :@const, name,]], value]
526
+ res = simulate_evaluate value, scope
527
+ scope[name] = res
528
+ res
529
+ in [:assign, [:aref_field, receiver, key], value]
530
+ simulate_evaluate receiver, scope
531
+ args, kwargs, _block = retrieve_method_args key
532
+ args.each do |arg|
533
+ item = ((arg in KatakataIrb::Types::Splat) ? arg.item : arg)
534
+ simulate_evaluate item, scope
535
+ end
536
+ kwargs_type kwargs, scope
537
+ simulate_evaluate value, scope
538
+ in [:assign, [:field, receiver, period, [:@ident,]], value]
539
+ simulate_evaluate receiver, scope
540
+ if period in [:@op, '&.',]
541
+ scope.conditional { simulate_evaluate value, scope }
542
+ else
543
+ simulate_evaluate value, scope
544
+ end
545
+ in [:opassign, target, [:@op, op,], value]
546
+ op = op.to_s.delete('=').to_sym
547
+ if target in [:var_field, *field]
548
+ receiver = [:var_ref, *field]
549
+ elsif target in [:field, *field]
550
+ receiver = [:call, *field]
551
+ elsif target in [:aref_field, *field]
552
+ receiver = [:aref, *field]
553
+ else
554
+ receiver = target
555
+ end
556
+ simulate_evaluate [:assign, target, [:binary, receiver, op, value]], scope
557
+ in [:assign, target, value]
558
+ simulate_evaluate target, scope
559
+ simulate_evaluate value, scope
560
+ in [:massign, targets, value]
561
+ rhs = simulate_evaluate value, scope
562
+ evaluate_massign targets, rhs, scope
563
+ rhs
564
+ in [:mrhs_new_from_args | :mrhs_add_star,]
565
+ values, = evaluate_mrhs sexp, scope
566
+ KatakataIrb::Types::InstanceType.new Array, Elem: KatakataIrb::Types::UnionType[*values]
567
+ in [:ifop, cond, tval, fval]
568
+ simulate_evaluate cond, scope
569
+ KatakataIrb::Types::UnionType[*scope.run_branches(
570
+ -> { simulate_evaluate tval, scope },
571
+ -> { simulate_evaluate fval, scope }
572
+ )]
573
+ in [:if_mod | :unless_mod, cond, statement]
574
+ simulate_evaluate cond, scope
575
+ KatakataIrb::Types::UnionType[scope.conditional { simulate_evaluate statement, scope }, KatakataIrb::Types::NIL]
576
+ in [:if | :unless | :elsif, cond, statements, else_statement]
577
+ simulate_evaluate cond, scope
578
+ results = scope.run_branches(
579
+ -> { statements.map { simulate_evaluate _1, scope }.last },
580
+ -> { else_statement ? simulate_evaluate(else_statement, scope) : KatakataIrb::Types::NIL }
581
+ )
582
+ results.empty? ? KatakataIrb::Types::NIL : KatakataIrb::Types::UnionType[*results]
583
+ in [:while | :until, cond, statements]
584
+ inner_scope = Scope.new scope, { BREAK_RESULT => nil }, passthrough: true
585
+ simulate_evaluate cond, inner_scope
586
+ scope.conditional { statements.each { simulate_evaluate _1, inner_scope } }
587
+ breaks = inner_scope[BREAK_RESULT]
588
+ inner_scope.merge_jumps
589
+ breaks ? KatakataIrb::Types::UnionType[breaks, KatakataIrb::Types::NIL] : KatakataIrb::Types::NIL
590
+ in [:while_mod | :until_mod, cond, statement]
591
+ simulate_evaluate cond, scope
592
+ scope.conditional { simulate_evaluate statement, scope }
593
+ KatakataIrb::Types::NIL
594
+ in [:break | :next | :return => jump_type, value]
595
+ internal_key = jump_type == :break ? BREAK_RESULT : jump_type == :next ? NEXT_RESULT : RETURN_RESULT
596
+ if value.empty?
597
+ scope[internal_key] = KatakataIrb::Types::NIL
598
+ else
599
+ values, kw = evaluate_mrhs value, scope
600
+ values << kw if kw
601
+ scope[internal_key] = values.size == 1 ? values.first : KatakataIrb::Types::InstanceType.new(Array, Elem: KatakataIrb::Types::UnionType[*values])
602
+ end
603
+ scope.terminate_with internal_key
604
+ KatakataIrb::Types::NIL
605
+ in [:return0]
606
+ scope[RETURN_RESULT] = KatakataIrb::Types::NIL
607
+ scope.terminate_with RETURN_RESULT
608
+ KatakataIrb::Types::NIL
609
+ in [:yield, args]
610
+ evaluate_mrhs args, scope
611
+ KatakataIrb::Types::OBJECT
612
+ in [:yield0]
613
+ KatakataIrb::Types::OBJECT
614
+ in [:super, args]
615
+ args, kwargs, _block = retrieve_method_args args
616
+ args.each do |arg|
617
+ item = ((arg in KatakataIrb::Types::Splat) ? arg.item : arg)
618
+ simulate_evaluate item, scope
619
+ end
620
+ kwargs_type kwargs, scope
621
+ KatakataIrb::Types::OBJECT
622
+ in [:begin, body_stmt]
623
+ simulate_evaluate body_stmt, scope
624
+ in [:bodystmt, statements, rescue_stmt, _unknown, ensure_stmt]
625
+ statements = [statements] if statements in [Symbol,] # oneliner-def body
626
+ return_type = statements.map { simulate_evaluate _1, scope }.last
627
+ if rescue_stmt
628
+ return_type = KatakataIrb::Types::UnionType[return_type, scope.conditional { simulate_evaluate rescue_stmt, scope }]
629
+ end
630
+ simulate_evaluate ensure_stmt, scope if ensure_stmt
631
+ return_type
632
+ in [:rescue, error_class_stmts, error_var_stmt, statements, rescue_stmt]
633
+ return_type = scope.conditional do
634
+ if error_var_stmt in [:var_field, [:@ident, error_var,]]
635
+ if (error_class_stmts in [:mrhs_new_from_args, Array => stmts, stmt])
636
+ error_class_stmts = [*stmts, stmt]
637
+ end
638
+ error_classes = (error_class_stmts || []).flat_map { simulate_evaluate _1, scope }.uniq
639
+ error_types = error_classes.filter_map { KatakataIrb::Types::InstanceType.new _1.module_or_class if _1 in KatakataIrb::Types::SingletonType }
640
+ error_types << KatakataIrb::Types::InstanceType.new(StandardError) if error_types.empty?
641
+ scope[error_var] = KatakataIrb::Types::UnionType[*error_types]
642
+ end
643
+ statements.map { simulate_evaluate _1, scope }.last
644
+ end
645
+ if rescue_stmt
646
+ return_type = KatakataIrb::Types::UnionType[return_type, scope.conditional { simulate_evaluate rescue_stmt, scope }]
647
+ end
648
+ return_type
649
+ in [:rescue_mod, statement1, statement2]
650
+ a = simulate_evaluate statement1, scope
651
+ b = scope.conditional { simulate_evaluate statement2, scope }
652
+ KatakataIrb::Types::UnionType[a, b]
653
+ in [:module, module_stmt, body_stmt]
654
+ module_types = simulate_evaluate(module_stmt, scope).types.grep(KatakataIrb::Types::SingletonType)
655
+ module_types << KatakataIrb::Types::MODULE if module_types.empty?
656
+ simulate_evaluate body_stmt, Scope.new(scope, { SELF => KatakataIrb::Types::UnionType[*module_types], BREAK_RESULT => nil, NEXT_RESULT => nil, RETURN_RESULT => nil }, trace_cvar: false, trace_ivar: false, trace_lvar: false)
657
+ in [:sclass, klass_stmt, body_stmt]
658
+ klass_types = simulate_evaluate(klass_stmt, scope).types.filter_map do |type|
659
+ KatakataIrb::Types::SingletonType.new type.klass if type in KatakataIrb::Types::InstanceType
660
+ end
661
+ klass_types = [KatakataIrb::Types::CLASS] if klass_types.empty?
662
+ simulate_evaluate body_stmt, Scope.new(scope, { SELF => KatakataIrb::Types::UnionType[*klass_types], BREAK_RESULT => nil, NEXT_RESULT => nil, RETURN_RESULT => nil }, trace_cvar: false, trace_ivar: false, trace_lvar: false)
663
+ in [:class, klass_stmt, superclass_stmt, body_stmt]
664
+ klass_types = simulate_evaluate(klass_stmt, scope).types
665
+ klass_types += simulate_evaluate(superclass_stmt, scope).types if superclass_stmt
666
+ klass_types = klass_types.select do |type|
667
+ (type in KatakataIrb::Types::SingletonType) && type.module_or_class.is_a?(Class)
668
+ end
669
+ klass_types << KatakataIrb::Types::CLASS if klass_types.empty?
670
+ simulate_evaluate body_stmt, Scope.new(scope, { SELF => KatakataIrb::Types::UnionType[*klass_types], BREAK_RESULT => nil, NEXT_RESULT => nil, RETURN_RESULT => nil }, trace_cvar: false, trace_ivar: false, trace_lvar: false)
671
+ in [:for, fields, enum, statements]
672
+ fields = [fields] if fields in [:var_field,]
673
+ params = [:params, fields, nil, nil, nil, nil, nil, nil]
674
+ enum = simulate_evaluate enum, scope
675
+ extract_param_names(params).each { scope[_1] = KatakataIrb::Types::NIL }
676
+ response = simulate_call enum, :first, [], nil, nil
677
+ evaluate_assign_params params, [response], scope
678
+ scope.conditional do
679
+ statements.each { simulate_evaluate _1, scope }
680
+ end
681
+ enum
682
+ in [:in | :when => mode, pattern, if_statements, else_statement]
683
+ if mode == :in
684
+ if_match = -> { match_pattern case_target, pattern, scope }
685
+ else_match = -> { scope.conditional { if_match.call } }
686
+ else
687
+ eval_pattern = lambda do |pattern, *rest|
688
+ simulate_evaluate pattern, scope
689
+ scope.conditional { eval_pattern.call(*rest) } if rest.any?
690
+ end
691
+ if_match = -> { eval_pattern.call(*pattern) }
692
+ else_match = -> { pattern.each { simulate_evaluate _1, scope } }
693
+ end
694
+ if_branch = lambda do
695
+ if_match.call
696
+ if_statements.map { simulate_evaluate _1, scope }.last
697
+ end
698
+ else_branch = lambda do
699
+ else_match.call
700
+ simulate_evaluate(else_statement, scope, case_target:)
701
+ end
702
+ if if_statements && else_statement
703
+ KatakataIrb::Types::UnionType[*scope.run_branches(if_branch, else_branch)]
704
+ elsif if_statements
705
+ KatakataIrb::Types::UnionType[scope.conditional { if_branch.call }, KatakataIrb::Types::NIL]
706
+ elsif else_statement
707
+ KatakataIrb::Types::UnionType[scope.conditional { else_branch.call }, KatakataIrb::Types::NIL]
708
+ else
709
+ KatakataIrb::Types::NIL
710
+ end
711
+ in [:case, target_exp, match_exp]
712
+ target = simulate_evaluate target_exp, scope
713
+ simulate_evaluate match_exp, scope, case_target: target
714
+ in [:void_stmt]
715
+ KatakataIrb::Types::NIL
716
+ in [:dot2 | :dot3, range_beg, range_end]
717
+ simulate_evaluate range_beg, scope if range_beg
718
+ simulate_evaluate range_end, scope if range_end
719
+ KatakataIrb::Types::RANGE
720
+ in [:top_const_ref, [:@const, name,]]
721
+ self.class.type_of { Object.const_get name }
722
+ else
723
+ KatakataIrb.log_puts
724
+ KatakataIrb.log_puts :NOMATCH
725
+ KatakataIrb.log_puts sexp.inspect
726
+ KatakataIrb::Types::NIL
727
+ end
728
+ end
729
+
730
+ def match_pattern(target, pattern, scope)
731
+ types = target.types
732
+ case pattern
733
+ in [:var_field, [:@ident, name,]]
734
+ scope[name] = target
735
+ in [:var_ref,] # in Array, in ^a, in nil
736
+ in [:@int | :@float | :@rational | :@imaginary | :@CHAR | :symbol_literal | :string_literal | :regexp_literal,]
737
+ in [:begin, statement] # in (statement)
738
+ simulate_evaluate statement, scope
739
+ in [:binary, lpattern, :|, rpattern]
740
+ match_pattern target, lpattern, scope
741
+ match_pattern target, rpattern, scope
742
+ in [:binary, lpattern, :'=>', [:var_field, [:@ident, name,]] => rpattern]
743
+ if lpattern in [:var_ref, [:@const, const_name,]]
744
+ const_value = simulate_evaluate lpattern, scope
745
+ if (const_value in KatakataIrb::Types::SingletonType) && const_value.module_or_class.is_a?(Class)
746
+ scope[name] = KatakataIrb::Types::InstanceType.new const_value.module_or_class
747
+ else
748
+ scope[name] = KatakataIrb::Types::OBJECT
749
+ end
750
+ else
751
+ match_pattern target, lpattern, scope
752
+ match_pattern target, rpattern, scope
753
+ end
754
+ in [:aryptn, _unknown, items, splat, post_items]
755
+ # TODO: deconstruct keys
756
+ array_types = types.select { (_1 in KatakataIrb::Types::InstanceType) && _1.klass == Array }
757
+ elem = KatakataIrb::Types::UnionType[*array_types.filter_map { _1.params[:Elem] }]
758
+ items&.each do |item|
759
+ match_pattern elem, item, scope
760
+ end
761
+ if splat in [:var_field, [:@ident, name,]]
762
+ scope[name] = KatakataIrb::Types::InstanceType.new Array, Elem: elem
763
+ end
764
+ post_items&.each do |item|
765
+ match_pattern elem, item, scope
766
+ end
767
+ in [:hshptn, _unknown, items, splat]
768
+ # TODO: deconstruct keys
769
+ hash_types = types.select { (_1 in KatakataIrb::Types::InstanceType) && _1.klass == Hash }
770
+ key_type = KatakataIrb::Types::UnionType[*hash_types.filter_map { _1.params[:K] }]
771
+ value_type = KatakataIrb::Types::UnionType[*hash_types.filter_map { _1.params[:V] }]
772
+ items&.each do |key_pattern, value_pattern|
773
+ if key_pattern in [:@label, label,]
774
+ name = label.delete ':'
775
+ scope[name] = value_type unless value_pattern
776
+ end
777
+ match_pattern value_type, value_pattern, scope if value_pattern
778
+ end
779
+ if splat in [:var_field, [:@ident, name,]]
780
+ scope[name] = KatakataIrb::Types::InstanceType.new Hash, K: key_type, V: value_type
781
+ end
782
+ in [:if_mod, cond, ifpattern]
783
+ simulate_evaluate cond, scope
784
+ match_pattern target, ifpattern, scope
785
+ in [:dyna_symbol,]
786
+ in [:const_path_ref,]
787
+ else
788
+ KatakataIrb.log_puts "Unimplemented match pattern: #{pattern}"
789
+ end
790
+ end
791
+
792
+ def evaluate_mrhs(sexp, scope)
793
+ args, kwargs, = retrieve_method_args sexp
794
+ values = args.filter_map do |t|
795
+ if t in KatakataIrb::Types::Splat
796
+ simulate_evaluate t.item, scope
797
+ # TODO
798
+ nil
799
+ else
800
+ simulate_evaluate t, scope
801
+ end
802
+ end
803
+ unless kwargs.empty?
804
+ kvs = kwargs.map do |t|
805
+ case t
806
+ in KatakataIrb::Types::Splat
807
+ simulate_evaluate t.item, scope
808
+ # TODO
809
+ [KatakataIrb::Types::SYMBOL, KatakataIrb::Types::OBJECT]
810
+ in [key, value]
811
+ key_type = (key in [:@label,]) ? KatakataIrb::Types::SYMBOL : simulate_evaluate(key, scope)
812
+ [key_type, simulate_evaluate(value, scope)]
813
+ end
814
+ end
815
+ key_type = KatakataIrb::Types::UnionType[*kvs.map(&:first)]
816
+ value_type = KatakataIrb::Types::UnionType[*kvs.map(&:last)]
817
+ kw = KatakataIrb::Types::InstanceType.new(Hash, K: key_type, V: value_type)
818
+ end
819
+ [values, kw]
820
+ end
821
+
822
+ def to_array(value, method)
823
+ return value if (value in KatakataIrb::Types::InstanceType) && value.klass == Array
824
+ to_array_result = simulate_call value, method, [], nil, nil, name_match: false
825
+ return to_array_result if (to_array_result in KatakataIrb::Types::InstanceType) && to_array_result.klass == Array
826
+ end
827
+
828
+ def evaluate_massign(sexp, values, scope)
829
+ unless values in Array
830
+ array_value = to_array values, :to_ary
831
+ values = array_value ? [array_value.params[:Elem] || KatakataIrb::Types::OBJECT] * sexp.size : [values]
832
+ end
833
+
834
+ rest_index = sexp.find_index { _1 in [:rest_param, ]}
835
+ if rest_index
836
+ pre = rest_index ? sexp[0...rest_index] : sexp
837
+ post = rest_index ? sexp[rest_index + 1..] : []
838
+ sexp[rest_index] in [:rest_param, rest_field]
839
+ rest_values = values[pre.size...-post.size] || []
840
+ rest_type = KatakataIrb::Types::InstanceType.new Array, Elem: KatakataIrb::Types::UnionType[*rest_values]
841
+ pairs = pre.zip(values.first(pre.size)) + [[rest_field, rest_type]] + post.zip(values.last(post.size))
842
+ else
843
+ pairs = sexp.zip values
844
+ end
845
+ pairs.each do |field, value|
846
+ case field
847
+ in [:@ident, name,]
848
+ # block arg mlhs
849
+ scope[name] = value || KatakataIrb::Types::OBJECT
850
+ in [:var_field, [:@ident | :@ivar | :@cvar | :@gvar, name,]]
851
+ # massign
852
+ scope[name] = value || KatakataIrb::Types::OBJECT
853
+ in [:mlhs, *mlhs]
854
+ evaluate_massign mlhs, value || [], scope
855
+ end
856
+ end
857
+ end
858
+
859
+ def kwargs_type(kwargs, scope)
860
+ return if kwargs.empty?
861
+ keys = []
862
+ values = []
863
+ kwargs.each do |kv|
864
+ if kv in KatakataIrb::Types::Splat
865
+ hash = simulate_evaluate kv.item, scope
866
+ unless (hash in KatakataIrb::Types::InstanceType) && hash.klass == Hash
867
+ hash = simulate_call hash, :to_hash, [], nil, nil
868
+ end
869
+ if (hash in KatakataIrb::Types::InstanceType) && hash.klass == Hash
870
+ keys << hash.params[:K] if hash.params[:K]
871
+ values << hash.params[:V] if hash.params[:V]
872
+ end
873
+ else
874
+ key, value = kv
875
+ keys << ((key in [:@label,]) ? KatakataIrb::Types::SYMBOL : simulate_evaluate(key, scope))
876
+ values << simulate_evaluate(value, scope)
877
+ end
878
+ end
879
+ KatakataIrb::Types::InstanceType.new(Hash, K: KatakataIrb::Types::UnionType[*keys], V: KatakataIrb::Types::UnionType[*values])
880
+ end
881
+
882
+ def self.type_of(fallback: KatakataIrb::Types::OBJECT)
883
+ begin
884
+ KatakataIrb::Types.type_from_object yield
885
+ rescue
886
+ fallback
887
+ end
888
+ end
889
+
890
+ def retrieve_method_call(sexp)
891
+ conditional = -> { _1 in [:@op, '&.',] }
892
+ case sexp
893
+ in [:fcall | :vcall, [:@ident | :@const | :@kw | :@op, method,]] # hoge
894
+ [nil, method, [], [], nil, false]
895
+ in [:call, receiver, [:@period,] | [:@op, '&.',] | :'::' => dot, :call]
896
+ [receiver, :call, [], [], nil, conditional[dot]]
897
+ in [:call, receiver, [:@period,] | [:@op, '&.',] | :'::' => dot, method]
898
+ method => [:@ident | :@const | :@kw | :@op, method,] unless method == :call
899
+ [receiver, method, [], [], nil, conditional[dot]]
900
+ in [:command, [:@ident | :@const | :@kw | :@op, method,], args] # hoge 1, 2
901
+ args, kwargs, block = retrieve_method_args args
902
+ [nil, method, args, kwargs, block, false]
903
+ in [:command_call, receiver, [:@period,] | [:@op, '&.',] | :'::' => dot, [:@ident | :@const | :@kw | :@op, method,], args] # a.hoge 1; a.hoge 1, 2;
904
+ args, kwargs, block = retrieve_method_args args
905
+ [receiver, method, args, kwargs, block, conditional[dot]]
906
+ in [:method_add_arg, call, args]
907
+ receiver, method, _arg, _kwarg, _block, cond = retrieve_method_call call
908
+ args, kwargs, block = retrieve_method_args args
909
+ [receiver, method, args, kwargs, block, cond]
910
+ in [:method_add_block, call, block]
911
+ receiver, method, args, kwargs, cond = retrieve_method_call call
912
+ [receiver, method, args, kwargs, block, cond]
913
+ end
914
+ end
915
+
916
+ def retrieve_method_args(sexp)
917
+ case sexp
918
+ in [:mrhs_add_star, args, star]
919
+ args, = retrieve_method_args args
920
+ [[*args, KatakataIrb::Types::Splat.new(star)], [], nil]
921
+ in [:mrhs_new_from_args, [:args_add_star,] => args]
922
+ args, = retrieve_method_args args
923
+ [args, [], nil]
924
+ in [:mrhs_new_from_args, [:args_add_star,] => args, last_arg]
925
+ args, = retrieve_method_args args
926
+ [[*args, last_arg], [], nil]
927
+ in [:mrhs_new_from_args, args, last_arg]
928
+ [[*args, last_arg], [], nil]
929
+ in [:mrhs_new_from_args, args]
930
+ [args, [], nil]
931
+ in [:args_add_block, [:args_add_star,] => args, block_arg]
932
+ args, kwargs, = retrieve_method_args args
933
+ [args, kwargs, block_arg]
934
+ in [:args_add_block, [*args, [:bare_assoc_hash,] => kw], block_arg]
935
+ _, kwargs = retrieve_method_args kw
936
+ [args, kwargs, block_arg]
937
+ in [:args_add_block, [*args], block_arg]
938
+ [args, [], block_arg]
939
+ in [:bare_assoc_hash, kws]
940
+ kwargs = []
941
+ kws.each do |kw|
942
+ if kw in [:assoc_splat, value,]
943
+ kwargs << KatakataIrb::Types::Splat.new(value)
944
+ elsif kw in [:assoc_new, [:@label, label,] => key, nil]
945
+ name = label.delete ':'
946
+ kwargs << [key, [:__var_ref_or_call, [name =~ /\A[A-Z]/ ? :@const : :@ident, name, [0, 0]]]]
947
+ elsif kw in [:assoc_new, key, value]
948
+ kwargs << [key, value]
949
+ end
950
+ end
951
+ [[], kwargs, nil]
952
+ in [:args_add_star, *args, [:bare_assoc_hash,] => kwargs]
953
+ args, = retrieve_method_args [:args_add_star, *args]
954
+ _, kwargs = retrieve_method_args kwargs
955
+ [args, kwargs, nil]
956
+ in [:args_add_star, pre_args, star_arg, *post_args]
957
+ pre_args, = retrieve_method_args pre_args if pre_args in [:args_add_star,]
958
+ args = [*pre_args, KatakataIrb::Types::Splat.new(star_arg), *post_args]
959
+ [args, [], nil]
960
+ in [:arg_paren, args]
961
+ args ? retrieve_method_args(args) : [[], [], nil]
962
+ else
963
+ [[], [], nil]
964
+ end
965
+ end
966
+
967
+ def simulate_call(receiver, method_name, args, kwargs, block, name_match: true)
968
+ methods = KatakataIrb::Types.rbs_methods receiver, method_name.to_sym, args, kwargs, !!block
969
+ block_called = false
970
+ type_breaks = methods.map do |method, given_params, method_params|
971
+ receiver_vars = (receiver in KatakataIrb::Types::InstanceType) ? receiver.params : {}
972
+ free_vars = method.type.free_variables - receiver_vars.keys.to_set
973
+ vars = receiver_vars.merge KatakataIrb::Types.match_free_variables(free_vars, method_params, given_params)
974
+ if block && method.block
975
+ params_type = method.block.type.required_positionals.map do |func_param|
976
+ KatakataIrb::Types.from_rbs_type func_param.type, receiver, vars
977
+ end
978
+ block_response, breaks = block.call params_type
979
+ block_called = true
980
+ vars.merge! KatakataIrb::Types.match_free_variables(free_vars - vars.keys.to_set, [method.block.type.return_type], [block_response])
981
+ end
982
+ [KatakataIrb::Types.from_rbs_type(method.type.return_type, receiver, vars || {}), breaks]
983
+ end
984
+ block&.call [] unless block_called
985
+ types = type_breaks.map(&:first)
986
+ breaks = type_breaks.map(&:last).compact
987
+ types << OBJECT_METHODS[method_name.to_sym] if name_match && OBJECT_METHODS.has_key?(method_name.to_sym)
988
+ KatakataIrb::Types::UnionType[*types, *breaks]
989
+ end
990
+
991
+ def extract_param_names(params)
992
+ params => [:params, pre_required, optional, rest, post_required, keywords, keyrest, block]
993
+ names = []
994
+ extract_mlhs = ->(item) do
995
+ case item
996
+ in [:var_field, [:@ident, name,],]
997
+ names << name
998
+ in [:@ident, name,]
999
+ names << name
1000
+ in [:mlhs, *items]
1001
+ items.each(&extract_mlhs)
1002
+ in [:rest_param, item]
1003
+ extract_mlhs.call item if item
1004
+ in [:excessed_comma]
1005
+ end
1006
+ end
1007
+ [*pre_required, *post_required].each(&extract_mlhs)
1008
+ extract_mlhs.call rest if rest
1009
+ optional&.each do |key, _value|
1010
+ key => [:@ident, name,]
1011
+ names << name
1012
+ end
1013
+ keywords&.each do |key, _value|
1014
+ key => [:@label, label,]
1015
+ names << label.delete(':')
1016
+ end
1017
+ if keyrest in [:kwrest_params, [:@ident, name,]]
1018
+ names << name
1019
+ end
1020
+ if block in [:blockarg, [:@ident, name,]]
1021
+ names << name
1022
+ end
1023
+ names
1024
+ end
1025
+
1026
+ def evaluate_assign_params(params, values, scope)
1027
+ values = values.dup
1028
+ params => [:params, pre_required, optional, rest, post_required, keywords, keyrest, block]
1029
+ size = (pre_required&.size || 0) + (optional&.size || 0) + (post_required&.size || 0) + (rest ? 1 : 0)
1030
+ if values.size == 1 && size >= 2
1031
+ value = values.first
1032
+ array_value = to_array value, :to_ary if value
1033
+ values = [array_value.params[:Elem] || KatakataIrb::Types::OBJECT] * size if array_value
1034
+ end
1035
+ pre_values = values.shift pre_required.size if pre_required
1036
+ post_values = values.pop post_required.size if post_required
1037
+ opt_values = values.shift optional.size if optional
1038
+ rest_values = values
1039
+ evaluate_massign pre_required, pre_values, scope if pre_required
1040
+ evaluate_massign optional.map(&:first), opt_values, scope if optional
1041
+ if rest in [:rest_param, [:@ident, name,]]
1042
+ scope[name] = KatakataIrb::Types::InstanceType.new Array, Elem: KatakataIrb::Types::UnionType[*rest_values]
1043
+ end
1044
+ evaluate_massign post_required, post_values, scope if post_required
1045
+ if keyrest in [:kwrest_param, [:@ident, name,]]
1046
+ scope[name] = KatakataIrb::Types::InstanceType.new Hash, K: KatakataIrb::Types::SYMBOL, V: KatakataIrb::Types::OBJECT
1047
+ end
1048
+ if block in [:blockarg, [:@ident, name,]]
1049
+ scope[name] = KatakataIrb::Types::PROC
1050
+ end
1051
+ end
1052
+
1053
+ def evaluate_param_defaults(params, scope)
1054
+ params => [:params, _pre_required, optional, rest, _post_required, keywords, keyrest, block]
1055
+ optional&.each do |item, value|
1056
+ item => [:@ident, name,]
1057
+ scope[name] = simulate_evaluate value, scope
1058
+ end
1059
+ if rest in [:rest_param, [:@ident, name,]]
1060
+ scope[name] = KatakataIrb::Types::ARRAY
1061
+ end
1062
+ keywords&.each do |key, value|
1063
+ key => [:@label, label,]
1064
+ name = label.delete ':'
1065
+ scope[name] = value ? simulate_evaluate(value, scope) : KatakataIrb::Types::OBJECT
1066
+ end
1067
+ case keyrest
1068
+ in [:args_forward] | nil
1069
+ in [:kwrest_param, [:@ident, name,]]
1070
+ scope[name] = KatakataIrb::Types::HASH
1071
+ end
1072
+ case block
1073
+ in :& | nil
1074
+ in [:blockarg, [:@ident, name,]]
1075
+ scope[name] = KatakataIrb::Types::PROC
1076
+ end
1077
+ end
1078
+
1079
+ def max_numbered_params(sexp)
1080
+ case sexp
1081
+ in [:do_block | :brace_block | :def | :class | :module,]
1082
+ 0
1083
+ in [:var_ref, [:@ident, name,]]
1084
+ name.match?(/\A_[1-9]\z/) ? name[1..].to_i : 0
1085
+ else
1086
+ sexp.filter_map do |s|
1087
+ max_numbered_params s if s in Array
1088
+ end.max || 0
1089
+ end
1090
+ end
1091
+
1092
+ def self.calculate_binding_scope(binding, parents, target)
1093
+ dig_targets = DigTarget.new(parents, target) do |_types, scope|
1094
+ return scope
1095
+ end
1096
+ scope = Scope.from_binding(binding)
1097
+ new(dig_targets).simulate_evaluate parents[0], scope
1098
+ scope
1099
+ end
1100
+
1101
+ def self.calculate_receiver(binding, parents, receiver)
1102
+ dig_targets = DigTarget.new(parents, receiver) do |type, _scope|
1103
+ return type
1104
+ end
1105
+ new(dig_targets).simulate_evaluate parents[0], Scope.from_binding(binding)
1106
+ KatakataIrb::Types::NIL
1107
+ end
1108
+ end