katakata_irb 0.1.12 → 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,1168 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'set'
4
+ require_relative 'types'
5
+ require_relative 'scope'
6
+ require 'prism'
7
+
8
+ class KatakataIrb::TypeAnalyzer
9
+ class DigTarget
10
+ def initialize(parents, receiver, &block)
11
+ @dig_ids = parents.to_h { [_1.__id__, true] }
12
+ @target_id = receiver.__id__
13
+ @block = block
14
+ end
15
+
16
+ def dig?(node) = @dig_ids[node.__id__]
17
+ def target?(node) = @target_id == node.__id__
18
+ def resolve(type, scope)
19
+ @block.call type, scope
20
+ end
21
+ end
22
+
23
+ OBJECT_METHODS = {
24
+ to_s: KatakataIrb::Types::STRING,
25
+ to_str: KatakataIrb::Types::STRING,
26
+ to_a: KatakataIrb::Types::ARRAY,
27
+ to_ary: KatakataIrb::Types::ARRAY,
28
+ to_h: KatakataIrb::Types::HASH,
29
+ to_hash: KatakataIrb::Types::HASH,
30
+ to_i: KatakataIrb::Types::INTEGER,
31
+ to_int: KatakataIrb::Types::INTEGER,
32
+ to_f: KatakataIrb::Types::FLOAT,
33
+ to_c: KatakataIrb::Types::COMPLEX,
34
+ to_r: KatakataIrb::Types::RATIONAL
35
+ }
36
+
37
+ def initialize(dig_targets)
38
+ @dig_targets = dig_targets
39
+ end
40
+
41
+ def evaluate(node, scope)
42
+ method = "evaluate_#{node.type}"
43
+ if respond_to? method
44
+ result = send method, node, scope
45
+ else
46
+ KatakataIrb.log_puts
47
+ KatakataIrb.log_puts :NOMATCH
48
+ KatakataIrb.log_puts node.inspect
49
+ result = KatakataIrb::Types::NIL
50
+ end
51
+ @dig_targets.resolve result, scope if @dig_targets.target? node
52
+ result
53
+ end
54
+
55
+ def evaluate_program_node(node, scope)
56
+ evaluate node.statements, scope
57
+ end
58
+
59
+ def evaluate_statements_node(node, scope)
60
+ if node.body.empty?
61
+ KatakataIrb::Types::NIL
62
+ else
63
+ node.body.map { evaluate _1, scope }.last
64
+ end
65
+ end
66
+
67
+ def evaluate_def_node(node, scope)
68
+ if node.receiver
69
+ self_type = evaluate node.receiver, scope
70
+ else
71
+ current_self_types = scope.self_type.types
72
+ self_types = current_self_types.map do |type|
73
+ if type.is_a?(KatakataIrb::Types::SingletonType) && type.module_or_class.is_a?(Class)
74
+ KatakataIrb::Types::InstanceType.new type.module_or_class
75
+ else
76
+ type
77
+ end
78
+ end
79
+ self_type = KatakataIrb::Types::UnionType[*self_types]
80
+ end
81
+ if @dig_targets.dig?(node.body) || @dig_targets.dig?(node.parameters)
82
+ params_table = node.locals.to_h { [_1.to_s, KatakataIrb::Types::NIL] }
83
+ method_scope = KatakataIrb::Scope.new(
84
+ scope,
85
+ { **params_table, KatakataIrb::Scope::BREAK_RESULT => nil, KatakataIrb::Scope::NEXT_RESULT => nil, KatakataIrb::Scope::RETURN_RESULT => nil },
86
+ self_type: self_type,
87
+ trace_lvar: false,
88
+ trace_ivar: false
89
+ )
90
+ if node.parameters
91
+ # node.parameters is Prism::ParametersNode
92
+ assign_parameters node.parameters, method_scope, [], {}
93
+ end
94
+
95
+ if @dig_targets.dig?(node.body)
96
+ method_scope.conditional do |s|
97
+ evaluate node.body, s
98
+ end
99
+ end
100
+ method_scope.merge_jumps
101
+ scope.update method_scope
102
+ end
103
+ KatakataIrb::Types::SYMBOL
104
+ end
105
+
106
+ def evaluate_integer_node(_node, _scope) = KatakataIrb::Types::INTEGER
107
+
108
+ def evaluate_float_node(_node, _scope) = KatakataIrb::Types::FLOAT
109
+
110
+ def evaluate_rational_node(_node, _scope) = KatakataIrb::Types::RATIONAL
111
+
112
+ def evaluate_imaginary_node(_node, _scope) = KatakataIrb::Types::COMPLEX
113
+
114
+ def evaluate_string_node(_node, _scope) = KatakataIrb::Types::STRING
115
+
116
+ def evaluate_x_string_node(_node, _scope)
117
+ KatakataIrb::Types::UnionType[KatakataIrb::Types::STRING, KatakataIrb::Types::NIL]
118
+ end
119
+
120
+ def evaluate_symbol_node(_node, _scope) = KatakataIrb::Types::SYMBOL
121
+
122
+ def evaluate_regular_expression_node(_node, _scope) = KatakataIrb::Types::REGEXP
123
+
124
+ def evaluate_string_concat_node(node, scope)
125
+ evaluate node.left, scope
126
+ evaluate node.right, scope
127
+ KatakataIrb::Types::STRING
128
+ end
129
+
130
+ def evaluate_interpolated_string_node(node, scope)
131
+ node.parts.each { evaluate _1, scope }
132
+ KatakataIrb::Types::STRING
133
+ end
134
+
135
+ def evaluate_interpolated_x_string_node(node, scope)
136
+ node.parts.each { evaluate _1, scope }
137
+ KatakataIrb::Types::STRING
138
+ end
139
+
140
+ def evaluate_interpolated_symbol_node(node, scope)
141
+ node.parts.each { evaluate _1, scope }
142
+ KatakataIrb::Types::SYMBOL
143
+ end
144
+
145
+ def evaluate_interpolated_regular_expression_node(node, scope)
146
+ node.parts.each { evaluate _1, scope }
147
+ KatakataIrb::Types::REGEXP
148
+ end
149
+
150
+ def evaluate_embedded_statements_node(node, scope)
151
+ node.statements ? evaluate(node.statements, scope) : KatakataIrb::Types::NIL
152
+ KatakataIrb::Types::STRING
153
+ end
154
+
155
+ def evaluate_embedded_variable_node(node, scope)
156
+ evaluate node.variable, scope
157
+ KatakataIrb::Types::STRING
158
+ end
159
+
160
+ def evaluate_array_node(node, scope)
161
+ KatakataIrb::Types.array_of evaluate_list_splat_items(node.elements, scope)
162
+ end
163
+
164
+ def evaluate_hash_node(node, scope) = evaluate_hash(node, scope)
165
+ def evaluate_keyword_hash_node(node, scope) = evaluate_hash(node, scope)
166
+ def evaluate_hash(node, scope)
167
+ keys = []
168
+ values = []
169
+ node.elements.each do |assoc|
170
+ case assoc
171
+ when Prism::AssocNode
172
+ keys << evaluate(assoc.key, scope)
173
+ values << evaluate(assoc.value, scope)
174
+ when Prism::AssocSplatNode
175
+ hash = evaluate assoc.value, scope
176
+ unless hash.is_a?(KatakataIrb::Types::InstanceType) && hash.klass == Hash
177
+ hash = method_call hash, :to_hash, [], nil, nil, scope
178
+ end
179
+ if hash.is_a?(KatakataIrb::Types::InstanceType) && hash.klass == Hash
180
+ keys << hash.params[:K] if hash.params[:K]
181
+ values << hash.params[:V] if hash.params[:V]
182
+ end
183
+ end
184
+ end
185
+ if keys.empty? && values.empty?
186
+ KatakataIrb::Types::InstanceType.new Hash
187
+ else
188
+ KatakataIrb::Types::InstanceType.new Hash, K: KatakataIrb::Types::UnionType[*keys], V: KatakataIrb::Types::UnionType[*values]
189
+ end
190
+ end
191
+
192
+ def evaluate_parentheses_node(node, scope)
193
+ node.body ? evaluate(node.body, scope) : KatakataIrb::Types::NIL
194
+ end
195
+
196
+ def evaluate_constant_path_node(node, scope)
197
+ type, = evaluate_constant_node_info node, scope
198
+ type
199
+ end
200
+
201
+ def evaluate_self_node(_node, scope) = scope.self_type
202
+
203
+ def evaluate_true_node(_node, _scope) = KatakataIrb::Types::TRUE
204
+
205
+ def evaluate_false_node(_node, _scope) = KatakataIrb::Types::FALSE
206
+
207
+ def evaluate_nil_node(_node, _scope) = KatakataIrb::Types::NIL
208
+
209
+ def evaluate_source_file_node(_node, _scope) = KatakataIrb::Types::STRING
210
+
211
+ def evaluate_source_line_node(_node, _scope) = KatakataIrb::Types::INTEGER
212
+
213
+ def evaluate_source_encoding_node(_node, _scope) = KatakataIrb::Types::InstanceType.new(Encoding)
214
+
215
+ def evaluate_numbered_reference_read_node(_node, _scope)
216
+ KatakataIrb::Types::UnionType[KatakataIrb::Types::STRING, KatakataIrb::Types::NIL]
217
+ end
218
+
219
+ def evaluate_back_reference_read_node(_node, _scope)
220
+ KatakataIrb::Types::UnionType[KatakataIrb::Types::STRING, KatakataIrb::Types::NIL]
221
+ end
222
+
223
+ def evaluate_reference_read(node, scope)
224
+ scope[node.name.to_s] || KatakataIrb::Types::NIL
225
+ end
226
+ alias evaluate_constant_read_node evaluate_reference_read
227
+ alias evaluate_global_variable_read_node evaluate_reference_read
228
+ alias evaluate_local_variable_read_node evaluate_reference_read
229
+ alias evaluate_class_variable_read_node evaluate_reference_read
230
+ alias evaluate_instance_variable_read_node evaluate_reference_read
231
+
232
+
233
+ def evaluate_call_node(node, scope)
234
+ # TODO: return type of []=, field= when operator_loc.nil?
235
+ receiver_type = node.receiver ? evaluate(node.receiver, scope) : scope.self_type
236
+ evaluate_method = lambda do |scope|
237
+ args_types, kwargs_types, block_sym_node, has_block = evaluate_call_node_arguments node, scope
238
+
239
+ if block_sym_node
240
+ block_sym = block_sym_node.value
241
+ if @dig_targets.target? block_sym_node
242
+ # method(args, &:completion_target)
243
+ call_block_proc = ->(block_args, _self_type) do
244
+ block_receiver = block_args.first || KatakataIrb::Types::OBJECT
245
+ @dig_targets.resolve block_receiver, scope
246
+ KatakataIrb::Types::OBJECT
247
+ end
248
+ else
249
+ call_block_proc = ->(block_args, _self_type) do
250
+ block_receiver, *rest = block_args
251
+ block_receiver ? method_call(block_receiver || KatakataIrb::Types::OBJECT, block_sym, rest, nil, nil, scope) : KatakataIrb::Types::OBJECT
252
+ end
253
+ end
254
+ elsif node.block.is_a? Prism::BlockNode
255
+ call_block_proc = ->(block_args, block_self_type) do
256
+ scope.conditional do |s|
257
+ numbered_parameters = node.block.locals.grep(/\A_[1-9]/).map(&:to_s)
258
+ params_table = node.block.locals.to_h { [_1.to_s, KatakataIrb::Types::NIL] }
259
+ table = { **params_table, KatakataIrb::Scope::BREAK_RESULT => nil, KatakataIrb::Scope::NEXT_RESULT => nil }
260
+ block_scope = KatakataIrb::Scope.new s, table, self_type: block_self_type, trace_ivar: !block_self_type
261
+ # TODO kwargs
262
+ if node.block.parameters&.parameters
263
+ # node.block.parameters is Prism::BlockParametersNode
264
+ assign_parameters node.block.parameters.parameters, block_scope, block_args, {}
265
+ elsif !numbered_parameters.empty?
266
+ assign_numbered_parameters numbered_parameters, block_scope, block_args, {}
267
+ end
268
+ result = node.block.body ? evaluate(node.block.body, block_scope) : KatakataIrb::Types::NIL
269
+ block_scope.merge_jumps
270
+ s.update block_scope
271
+ nexts = block_scope[KatakataIrb::Scope::NEXT_RESULT]
272
+ breaks = block_scope[KatakataIrb::Scope::BREAK_RESULT]
273
+ if block_scope.terminated?
274
+ [KatakataIrb::Types::UnionType[*nexts], breaks]
275
+ else
276
+ [KatakataIrb::Types::UnionType[result, *nexts], breaks]
277
+ end
278
+ end
279
+ end
280
+ elsif has_block
281
+ call_block_proc = ->(_block_args, _self_type) { KatakataIrb::Types::OBJECT }
282
+ end
283
+ method_call receiver_type, node.name, args_types, kwargs_types, call_block_proc, scope
284
+ end
285
+ if node.call_operator == '&.'
286
+ result = scope.conditional { evaluate_method.call _1 }
287
+ if receiver_type.nillable?
288
+ KatakataIrb::Types::UnionType[result, KatakataIrb::Types::NIL]
289
+ else
290
+ result
291
+ end
292
+ else
293
+ evaluate_method.call scope
294
+ end
295
+ end
296
+
297
+ def evaluate_and_node(node, scope) = evaluate_and_or(node, scope, and_op: true)
298
+ def evaluate_or_node(node, scope) = evaluate_and_or(node, scope, and_op: false)
299
+ def evaluate_and_or(node, scope, and_op:)
300
+ left = evaluate node.left, scope
301
+ right = scope.conditional { evaluate node.right, _1 }
302
+ if and_op
303
+ KatakataIrb::Types::UnionType[right, KatakataIrb::Types::NIL, KatakataIrb::Types::FALSE]
304
+ else
305
+ KatakataIrb::Types::UnionType[left, right]
306
+ end
307
+ end
308
+
309
+ def evaluate_call_operator_write_node(node, scope) = evaluate_call_write(node, scope, :operator, node.write_name)
310
+ def evaluate_call_and_write_node(node, scope) = evaluate_call_write(node, scope, :and, node.write_name)
311
+ def evaluate_call_or_write_node(node, scope) = evaluate_call_write(node, scope, :or, node.write_name)
312
+ def evaluate_index_operator_write_node(node, scope) = evaluate_call_write(node, scope, :operator, :[]=)
313
+ def evaluate_index_and_write_node(node, scope) = evaluate_call_write(node, scope, :and, :[]=)
314
+ def evaluate_index_or_write_node(node, scope) = evaluate_call_write(node, scope, :or, :[]=)
315
+ def evaluate_call_write(node, scope, operator, write_name)
316
+ receiver_type = evaluate node.receiver, scope
317
+ if node.respond_to? :arguments
318
+ # Prism >= 0.15.0, Call{Operator,And,Or}WriteNode does not have arguments
319
+ args_types, kwargs_types, block_sym_node, has_block = evaluate_call_node_arguments node, scope
320
+ else
321
+ args_types = []
322
+ end
323
+ if block_sym_node
324
+ block_sym = block_sym_node.value
325
+ call_block_proc = ->(block_args, _self_type) do
326
+ block_receiver, *rest = block_args
327
+ block_receiver ? method_call(block_receiver || KatakataIrb::Types::OBJECT, block_sym, rest, nil, nil, scope) : KatakataIrb::Types::OBJECT
328
+ end
329
+ elsif has_block
330
+ call_block_proc = ->(_block_args, _self_type) { KatakataIrb::Types::OBJECT }
331
+ end
332
+ method = write_name.to_s.delete_suffix('=')
333
+ left = method_call receiver_type, method, args_types, kwargs_types, call_block_proc, scope
334
+ case operator
335
+ when :and
336
+ right = scope.conditional { evaluate node.value, _1 }
337
+ KatakataIrb::Types::UnionType[right, KatakataIrb::Types::NIL, KatakataIrb::Types::FALSE]
338
+ when :or
339
+ right = scope.conditional { evaluate node.value, _1 }
340
+ KatakataIrb::Types::UnionType[left, right]
341
+ else
342
+ right = evaluate node.value, scope
343
+ method_call left, node.operator, [right], nil, nil, scope, name_match: false
344
+ end
345
+ end
346
+
347
+ def evaluate_variable_operator_write(node, scope)
348
+ left = scope[node.name.to_s] || KatakataIrb::Types::OBJECT
349
+ right = evaluate node.value, scope
350
+ scope[node.name.to_s] = method_call left, node.operator, [right], nil, nil, scope, name_match: false
351
+ end
352
+ alias evaluate_global_variable_operator_write_node evaluate_variable_operator_write
353
+ alias evaluate_local_variable_operator_write_node evaluate_variable_operator_write
354
+ alias evaluate_class_variable_operator_write_node evaluate_variable_operator_write
355
+ alias evaluate_instance_variable_operator_write_node evaluate_variable_operator_write
356
+
357
+ def evaluate_variable_and_write(node, scope)
358
+ right = scope.conditional { evaluate node.value, scope }
359
+ scope[node.name.to_s] = KatakataIrb::Types::UnionType[right, KatakataIrb::Types::NIL, KatakataIrb::Types::FALSE]
360
+ end
361
+ alias evaluate_global_variable_and_write_node evaluate_variable_and_write
362
+ alias evaluate_local_variable_and_write_node evaluate_variable_and_write
363
+ alias evaluate_class_variable_and_write_node evaluate_variable_and_write
364
+ alias evaluate_instance_variable_and_write_node evaluate_variable_and_write
365
+
366
+ def evaluate_variable_or_write(node, scope)
367
+ left = scope[node.name.to_s] || KatakataIrb::Types::OBJECT
368
+ right = scope.conditional { evaluate node.value, scope }
369
+ scope[node.name.to_s] = KatakataIrb::Types::UnionType[left, right]
370
+ end
371
+ alias evaluate_global_variable_or_write_node evaluate_variable_or_write
372
+ alias evaluate_local_variable_or_write_node evaluate_variable_or_write
373
+ alias evaluate_class_variable_or_write_node evaluate_variable_or_write
374
+ alias evaluate_instance_variable_or_write_node evaluate_variable_or_write
375
+
376
+ def evaluate_constant_operator_write_node(node, scope)
377
+ left = scope[node.name.to_s] || KatakataIrb::Types::OBJECT
378
+ right = evaluate node.value, scope
379
+ scope[node.name.to_s] = method_call left, node.operator, [right], nil, nil, scope, name_match: false
380
+ end
381
+
382
+ def evaluate_constant_and_write_node(node, scope)
383
+ right = scope.conditional { evaluate node.value, scope }
384
+ scope[node.name.to_s] = KatakataIrb::Types::UnionType[right, KatakataIrb::Types::NIL, KatakataIrb::Types::FALSE]
385
+ end
386
+
387
+ def evaluate_constant_or_write_node(node, scope)
388
+ left = scope[node.name.to_s] || KatakataIrb::Types::OBJECT
389
+ right = scope.conditional { evaluate node.value, scope }
390
+ scope[node.name.to_s] = KatakataIrb::Types::UnionType[left, right]
391
+ end
392
+
393
+ def evaluate_constant_path_operator_write_node(node, scope)
394
+ left, receiver, _parent_module, name = evaluate_constant_node_info node.target, scope
395
+ right = evaluate node.value, scope
396
+ value = method_call left, node.operator, [right], nil, nil, scope, name_match: false
397
+ const_path_write receiver, name, value, scope
398
+ value
399
+ end
400
+
401
+ def evaluate_constant_path_and_write_node(node, scope)
402
+ _left, receiver, _parent_module, name = evaluate_constant_node_info node.target, scope
403
+ right = scope.conditional { evaluate node.value, scope }
404
+ value = KatakataIrb::Types::UnionType[right, KatakataIrb::Types::NIL, KatakataIrb::Types::FALSE]
405
+ const_path_write receiver, name, value, scope
406
+ value
407
+ end
408
+
409
+ def evaluate_constant_path_or_write_node(node, scope)
410
+ left, receiver, _parent_module, name = evaluate_constant_node_info node.target, scope
411
+ right = scope.conditional { evaluate node.value, scope }
412
+ value = KatakataIrb::Types::UnionType[left, right]
413
+ const_path_write receiver, name, value, scope
414
+ value
415
+ end
416
+
417
+ def evaluate_constant_path_write_node(node, scope)
418
+ receiver = evaluate node.target.parent, scope if node.target.parent
419
+ value = evaluate node.value, scope
420
+ const_path_write receiver, node.target.child.name.to_s, value, scope
421
+ value
422
+ end
423
+
424
+ def evaluate_lambda_node(node, scope)
425
+ local_table = node.locals.to_h { [_1.to_s, KatakataIrb::Types::OBJECT] }
426
+ block_scope = KatakataIrb::Scope.new scope, { **local_table, KatakataIrb::Scope::BREAK_RESULT => nil, KatakataIrb::Scope::NEXT_RESULT => nil, KatakataIrb::Scope::RETURN_RESULT => nil }
427
+ block_scope.conditional do |s|
428
+ assign_parameters node.parameters.parameters, s, [], {} if node.parameters&.parameters
429
+ evaluate node.body, s if node.body
430
+ end
431
+ block_scope.merge_jumps
432
+ scope.update block_scope
433
+ KatakataIrb::Types::ProcType.new
434
+ end
435
+
436
+ def evaluate_reference_write(node, scope)
437
+ scope[node.name.to_s] = evaluate node.value, scope
438
+ end
439
+ alias evaluate_constant_write_node evaluate_reference_write
440
+ alias evaluate_global_variable_write_node evaluate_reference_write
441
+ alias evaluate_local_variable_write_node evaluate_reference_write
442
+ alias evaluate_class_variable_write_node evaluate_reference_write
443
+ alias evaluate_instance_variable_write_node evaluate_reference_write
444
+
445
+ def evaluate_multi_write_node(node, scope)
446
+ evaluated_receivers = {}
447
+ evaluate_multi_write_receiver node, scope, evaluated_receivers
448
+ value = (
449
+ if node.value.is_a? Prism::ArrayNode
450
+ if node.value.elements.any?(Prism::SplatNode)
451
+ evaluate node.value, scope
452
+ else
453
+ node.value.elements.map do |n|
454
+ evaluate n, scope
455
+ end
456
+ end
457
+ elsif node.value
458
+ evaluate node.value, scope
459
+ else
460
+ # For syntax invalid code like `(*a).b`
461
+ KatakataIrb::Types::NIL
462
+ end
463
+ )
464
+ evaluate_multi_write node, value, scope, evaluated_receivers
465
+ value.is_a?(Array) ? KatakataIrb::Types.array_of(*value) : value
466
+ end
467
+
468
+ def evaluate_if_node(node, scope) = evaluate_if_unless(node, scope)
469
+ def evaluate_unless_node(node, scope) = evaluate_if_unless(node, scope)
470
+ def evaluate_if_unless(node, scope)
471
+ evaluate node.predicate, scope
472
+ KatakataIrb::Types::UnionType[*scope.run_branches(
473
+ -> { node.statements ? evaluate(node.statements, _1) : KatakataIrb::Types::NIL },
474
+ -> { node.consequent ? evaluate(node.consequent, _1) : KatakataIrb::Types::NIL }
475
+ )]
476
+ end
477
+
478
+ def evaluate_else_node(node, scope)
479
+ node.statements ? evaluate(node.statements, scope) : KatakataIrb::Types::NIL
480
+ end
481
+
482
+ def evaluate_while_until(node, scope)
483
+ inner_scope = KatakataIrb::Scope.new scope, { KatakataIrb::Scope::BREAK_RESULT => nil }
484
+ evaluate node.predicate, inner_scope
485
+ if node.statements
486
+ inner_scope.conditional do |s|
487
+ evaluate node.statements, s
488
+ end
489
+ end
490
+ inner_scope.merge_jumps
491
+ scope.update inner_scope
492
+ breaks = inner_scope[KatakataIrb::Scope::BREAK_RESULT]
493
+ breaks ? KatakataIrb::Types::UnionType[breaks, KatakataIrb::Types::NIL] : KatakataIrb::Types::NIL
494
+ end
495
+ alias evaluate_while_node evaluate_while_until
496
+ alias evaluate_until_node evaluate_while_until
497
+
498
+ def evaluate_break_node(node, scope) = evaluate_jump(node, scope, :break)
499
+ def evaluate_next_node(node, scope) = evaluate_jump(node, scope, :next)
500
+ def evaluate_return_node(node, scope) = evaluate_jump(node, scope, :return)
501
+ def evaluate_jump(node, scope, mode)
502
+ internal_key = (
503
+ case mode
504
+ when :break
505
+ KatakataIrb::Scope::BREAK_RESULT
506
+ when :next
507
+ KatakataIrb::Scope::NEXT_RESULT
508
+ when :return
509
+ KatakataIrb::Scope::RETURN_RESULT
510
+ end
511
+ )
512
+ jump_value = (
513
+ arguments = node.arguments&.arguments
514
+ if arguments.nil? || arguments.empty?
515
+ KatakataIrb::Types::NIL
516
+ elsif arguments.size == 1 && !arguments.first.is_a?(Prism::SplatNode)
517
+ evaluate arguments.first, scope
518
+ else
519
+ KatakataIrb::Types.array_of evaluate_list_splat_items(arguments, scope)
520
+ end
521
+ )
522
+ scope.terminate_with internal_key, jump_value
523
+ KatakataIrb::Types::NIL
524
+ end
525
+
526
+ def evaluate_yield_node(node, scope)
527
+ evaluate_list_splat_items node.arguments.arguments, scope if node.arguments
528
+ KatakataIrb::Types::OBJECT
529
+ end
530
+
531
+ def evaluate_redo_node(_node, scope)
532
+ scope.terminate
533
+ KatakataIrb::Types::NIL
534
+ end
535
+
536
+ def evaluate_retry_node(_node, scope)
537
+ scope.terminate
538
+ KatakataIrb::Types::NIL
539
+ end
540
+
541
+ def evaluate_forwarding_super_node(_node, _scope) = KatakataIrb::Types::OBJECT
542
+
543
+ def evaluate_super_node(node, scope)
544
+ evaluate_list_splat_items node.arguments.arguments, scope if node.arguments
545
+ KatakataIrb::Types::OBJECT
546
+ end
547
+
548
+ def evaluate_begin_node(node, scope)
549
+ return_type = node.statements ? evaluate(node.statements, scope) : KatakataIrb::Types::NIL
550
+ if node.rescue_clause
551
+ if node.else_clause
552
+ return_types = scope.run_branches(
553
+ ->{ evaluate node.rescue_clause, _1 },
554
+ ->{ evaluate node.else_clause, _1 }
555
+ )
556
+ else
557
+ return_types = [
558
+ return_type,
559
+ scope.conditional { evaluate node.rescue_clause, _1 }
560
+ ]
561
+ end
562
+ return_type = KatakataIrb::Types::UnionType[*return_types]
563
+ end
564
+ if node.ensure_clause&.statements
565
+ # ensure_clause is Prism::EnsureNode
566
+ evaluate node.ensure_clause.statements, scope
567
+ end
568
+ return_type
569
+ end
570
+
571
+ def evaluate_rescue_node(node, scope)
572
+ run_rescue = lambda do |s|
573
+ if node.reference
574
+ error_classes_type = evaluate_list_splat_items node.exceptions, s
575
+ error_types = error_classes_type.types.filter_map do
576
+ KatakataIrb::Types::InstanceType.new _1.module_or_class if _1.is_a?(KatakataIrb::Types::SingletonType)
577
+ end
578
+ error_types << KatakataIrb::Types::InstanceType.new(StandardError) if error_types.empty?
579
+ error_type = KatakataIrb::Types::UnionType[*error_types]
580
+ case node.reference
581
+ when Prism::LocalVariableTargetNode, Prism::InstanceVariableTargetNode, Prism::ClassVariableTargetNode, Prism::GlobalVariableTargetNode, Prism::ConstantTargetNode
582
+ s[node.reference.name.to_s] = error_type
583
+ when Prism::CallNode
584
+ evaluate node.reference, s
585
+ end
586
+ end
587
+ node.statements ? evaluate(node.statements, s) : KatakataIrb::Types::NIL
588
+ end
589
+ if node.consequent # begin; rescue A; rescue B; end
590
+ types = scope.run_branches(
591
+ run_rescue,
592
+ -> { evaluate node.consequent, _1 }
593
+ )
594
+ KatakataIrb::Types::UnionType[*types]
595
+ else
596
+ run_rescue.call scope
597
+ end
598
+ end
599
+
600
+ def evaluate_rescue_modifier_node(node, scope)
601
+ a = evaluate node.expression, scope
602
+ b = scope.conditional { evaluate node.rescue_expression, _1 }
603
+ KatakataIrb::Types::UnionType[a, b]
604
+ end
605
+
606
+ def evaluate_singleton_class_node(node, scope)
607
+ klass_types = evaluate(node.expression, scope).types.filter_map do |type|
608
+ KatakataIrb::Types::SingletonType.new type.klass if type.is_a? KatakataIrb::Types::InstanceType
609
+ end
610
+ klass_types = [KatakataIrb::Types::CLASS] if klass_types.empty?
611
+ table = node.locals.to_h { [_1.to_s, KatakataIrb::Types::NIL] }
612
+ sclass_scope = KatakataIrb::Scope.new(
613
+ scope,
614
+ { **table, KatakataIrb::Scope::BREAK_RESULT => nil, KatakataIrb::Scope::NEXT_RESULT => nil, KatakataIrb::Scope::RETURN_RESULT => nil },
615
+ trace_ivar: false,
616
+ trace_lvar: false,
617
+ self_type: KatakataIrb::Types::UnionType[*klass_types]
618
+ )
619
+ result = node.body ? evaluate(node.body, sclass_scope) : KatakataIrb::Types::NIL
620
+ scope.update sclass_scope
621
+ result
622
+ end
623
+
624
+ def evaluate_class_node(node, scope) = evaluate_class_module(node, scope, true)
625
+ def evaluate_module_node(node, scope) = evaluate_class_module(node, scope, false)
626
+ def evaluate_class_module(node, scope, is_class)
627
+ unless node.constant_path.is_a?(Prism::ConstantReadNode) || node.constant_path.is_a?(Prism::ConstantPathNode)
628
+ # Incomplete class/module `class (statement[cursor_here])::Name; end`
629
+ evaluate node.constant_path, scope
630
+ return KatakataIrb::Types::NIL
631
+ end
632
+ const_type, _receiver, parent_module, name = evaluate_constant_node_info node.constant_path, scope
633
+ if is_class
634
+ select_class_type = -> { _1.is_a?(KatakataIrb::Types::SingletonType) && _1.module_or_class.is_a?(Class) }
635
+ module_types = const_type.types.select(&select_class_type)
636
+ module_types += evaluate(node.superclass, scope).types.select(&select_class_type) if node.superclass
637
+ module_types << KatakataIrb::Types::CLASS if module_types.empty?
638
+ else
639
+ module_types = const_type.types.select { _1.is_a?(KatakataIrb::Types::SingletonType) && !_1.module_or_class.is_a?(Class) }
640
+ module_types << KatakataIrb::Types::MODULE if module_types.empty?
641
+ end
642
+ return KatakataIrb::Types::NIL unless node.body
643
+
644
+ table = node.locals.to_h { [_1.to_s, KatakataIrb::Types::NIL] }
645
+ if !name.empty? && (parent_module.is_a?(Module) || parent_module.nil?)
646
+ value = parent_module.const_get name if parent_module&.const_defined? name
647
+ unless value
648
+ value_type = scope[name]
649
+ value = value_type.module_or_class if value_type.is_a? KatakataIrb::Types::SingletonType
650
+ end
651
+
652
+ if value.is_a? Module
653
+ nesting = [value, []]
654
+ else
655
+ if parent_module
656
+ nesting = [parent_module, [name]]
657
+ else
658
+ parent_nesting, parent_path = scope.module_nesting.first
659
+ nesting = [parent_nesting, parent_path + [name]]
660
+ end
661
+ nesting_key = [nesting[0].__id__, nesting[1]].join('::')
662
+ nesting_value = is_class ? KatakataIrb::Types::CLASS : KatakataIrb::Types::MODULE
663
+ end
664
+ else
665
+ # parent_module == :unknown
666
+ # TODO: dummy module
667
+ end
668
+ module_scope = KatakataIrb::Scope.new(
669
+ scope,
670
+ { **table, KatakataIrb::Scope::BREAK_RESULT => nil, KatakataIrb::Scope::NEXT_RESULT => nil, KatakataIrb::Scope::RETURN_RESULT => nil },
671
+ trace_ivar: false,
672
+ trace_lvar: false,
673
+ self_type: KatakataIrb::Types::UnionType[*module_types],
674
+ nesting: nesting
675
+ )
676
+ module_scope[nesting_key] = nesting_value if nesting_value
677
+ result = evaluate(node.body, module_scope)
678
+ scope.update module_scope
679
+ result
680
+ end
681
+
682
+ def evaluate_for_node(node, scope)
683
+ node.statements
684
+ collection = evaluate node.collection, scope
685
+ inner_scope = KatakataIrb::Scope.new scope, { KatakataIrb::Scope::BREAK_RESULT => nil }
686
+ ary_type = method_call collection, :to_ary, [], nil, nil, nil, name_match: false
687
+ element_types = ary_type.types.filter_map do |ary|
688
+ ary.params[:Elem] if ary.is_a?(KatakataIrb::Types::InstanceType) && ary.klass == Array
689
+ end
690
+ element_type = KatakataIrb::Types::UnionType[*element_types]
691
+ inner_scope.conditional do |s|
692
+ evaluate_write node.index, element_type, s, nil
693
+ evaluate node.statements, s if node.statements
694
+ end
695
+ inner_scope.merge_jumps
696
+ scope.update inner_scope
697
+ breaks = inner_scope[KatakataIrb::Scope::BREAK_RESULT]
698
+ breaks ? KatakataIrb::Types::UnionType[breaks, collection] : collection
699
+ end
700
+
701
+ def evaluate_case_node(node, scope)
702
+ target = evaluate(node.predicate, scope) if node.predicate
703
+ # TODO
704
+ branches = node.conditions.map do |condition|
705
+ ->(s) { evaluate_case_match target, condition, s }
706
+ end
707
+ if node.consequent
708
+ branches << ->(s) { evaluate node.consequent, s }
709
+ elsif node.conditions.any? { _1.is_a? Prism::WhenNode }
710
+ branches << ->(_s) { KatakataIrb::Types::NIL }
711
+ end
712
+ KatakataIrb::Types::UnionType[*scope.run_branches(*branches)]
713
+ end
714
+
715
+ def evaluate_match_required_node(node, scope)
716
+ value_type = evaluate node.value, scope
717
+ evaluate_match_pattern value_type, node.pattern, scope
718
+ KatakataIrb::Types::NIL # void value
719
+ end
720
+
721
+ def evaluate_match_predicate_node(node, scope)
722
+ value_type = evaluate node.value, scope
723
+ scope.conditional { evaluate_match_pattern value_type, node.pattern, _1 }
724
+ KatakataIrb::Types::BOOLEAN
725
+ end
726
+
727
+ def evaluate_range_node(node, scope)
728
+ beg_type = evaluate node.left, scope if node.left
729
+ end_type = evaluate node.right, scope if node.right
730
+ elem = (KatakataIrb::Types::UnionType[*[beg_type, end_type].compact]).nonnillable
731
+ KatakataIrb::Types::InstanceType.new Range, Elem: elem
732
+ end
733
+
734
+ def evaluate_defined_node(node, scope)
735
+ scope.conditional { evaluate node.value, _1 }
736
+ KatakataIrb::Types::UnionType[KatakataIrb::Types::STRING, KatakataIrb::Types::NIL]
737
+ end
738
+
739
+ def evaluate_flip_flop_node(node, scope)
740
+ scope.conditional { evaluate node.left, _1 } if node.left
741
+ scope.conditional { evaluate node.right, _1 } if node.right
742
+ KatakataIrb::Types::BOOLEAN
743
+ end
744
+
745
+ def evaluate_multi_target_node(node, scope)
746
+ # Raw MultiTargetNode, incomplete code like `a,b`, `*a`.
747
+ evaluate_multi_write_receiver node, scope, nil
748
+ KatakataIrb::Types::NIL
749
+ end
750
+
751
+ def evaluate_implicit_node(node, scope)
752
+ evaluate node.value, scope
753
+ end
754
+
755
+ def evaluate_match_write_node(node, scope)
756
+ # /(?<a>)(?<b>)/ =~ string
757
+ evaluate node.call, scope
758
+ node.locals.each { scope[_1.to_s] = KatakataIrb::Types::UnionType[KatakataIrb::Types::STRING, KatakataIrb::Types::NIL] }
759
+ KatakataIrb::Types::BOOLEAN
760
+ end
761
+
762
+ def evaluate_match_last_line_node(_node, _scope)
763
+ KatakataIrb::Types::BOOLEAN
764
+ end
765
+
766
+ def evaluate_interpolated_match_last_line_node(node, scope)
767
+ node.parts.each { evaluate _1, scope }
768
+ KatakataIrb::Types::BOOLEAN
769
+ end
770
+
771
+ def evaluate_pre_execution_node(node, scope)
772
+ node.statements ? evaluate(node.statements, scope) : KatakataIrb::Types::NIL
773
+ end
774
+
775
+ def evaluate_post_execution_node(node, scope)
776
+ node.statements && @dig_targets.dig?(node.statements) ? evaluate(node.statements, scope) : KatakataIrb::Types::NIL
777
+ end
778
+
779
+ def evaluate_alias_method_node(_node, _scope) = KatakataIrb::Types::NIL
780
+ def evaluate_alias_global_variable_node(_node, _scope) = KatakataIrb::Types::NIL
781
+ def evaluate_undef_node(_node, _scope) = KatakataIrb::Types::NIL
782
+ def evaluate_missing_node(_node, _scope) = KatakataIrb::Types::NIL
783
+
784
+ def evaluate_call_node_arguments(call_node, scope)
785
+ # call_node.arguments is Prism::ArgumentsNode
786
+ arguments = call_node.arguments&.arguments&.dup || []
787
+ block_arg = call_node.block.expression if call_node.respond_to?(:block) && call_node.block.is_a?(Prism::BlockArgumentNode)
788
+ kwargs = arguments.pop.elements if arguments.last.is_a?(Prism::KeywordHashNode)
789
+ args_types = arguments.map do |arg|
790
+ case arg
791
+ when Prism::ForwardingArgumentsNode
792
+ # `f(a, ...)` treat like splat
793
+ nil
794
+ when Prism::SplatNode
795
+ evaluate arg.expression, scope
796
+ nil # TODO: splat
797
+ else
798
+ evaluate arg, scope
799
+ end
800
+ end
801
+ if kwargs
802
+ kwargs_types = kwargs.map do |arg|
803
+ case arg
804
+ when Prism::AssocNode
805
+ if arg.key.is_a?(Prism::SymbolNode)
806
+ [arg.key.value, evaluate(arg.value, scope)]
807
+ else
808
+ evaluate arg.key, scope
809
+ evaluate arg.value, scope
810
+ nil
811
+ end
812
+ when Prism::AssocSplatNode
813
+ evaluate arg.value, scope
814
+ nil
815
+ end
816
+ end.compact.to_h
817
+ end
818
+ if block_arg.is_a? Prism::SymbolNode
819
+ block_sym_node = block_arg
820
+ elsif block_arg
821
+ evaluate block_arg, scope
822
+ end
823
+ [args_types, kwargs_types, block_sym_node, !!block_arg]
824
+ end
825
+
826
+ def const_path_write(receiver, name, value, scope)
827
+ if receiver # receiver::A = value
828
+ singleton_type = receiver.types.find { _1.is_a? KatakataIrb::Types::SingletonType }
829
+ scope.set_const singleton_type.module_or_class, name, value if singleton_type
830
+ else # ::A = value
831
+ scope.set_const Object, name, value
832
+ end
833
+ end
834
+
835
+ def assign_required_parameter(node, value, scope)
836
+ case node
837
+ when Prism::RequiredParameterNode
838
+ scope[node.name.to_s] = value || KatakataIrb::Types::OBJECT
839
+ when Prism::RequiredDestructuredParameterNode
840
+ values = value ? sized_splat(value, :to_ary, node.parameters.size) : []
841
+ node.parameters.zip values do |n, v|
842
+ assign_required_parameter n, v, scope
843
+ end
844
+ when Prism::SplatNode
845
+ splat_value = value ? KatakataIrb::Types.array_of(value) : KatakataIrb::Types::ARRAY
846
+ assign_required_parameter node.expression, splat_value, scope
847
+ end
848
+ end
849
+
850
+ def evaluate_constant_node_info(node, scope)
851
+ case node
852
+ when Prism::ConstantPathNode
853
+ name = node.child.name.to_s
854
+ if node.parent
855
+ receiver = evaluate node.parent, scope
856
+ if receiver.is_a? KatakataIrb::Types::SingletonType
857
+ parent_module = receiver.module_or_class
858
+ end
859
+ else
860
+ parent_module = Object
861
+ end
862
+ if parent_module
863
+ type = scope.get_const(parent_module, [name]) || KatakataIrb::Types::NIL
864
+ else
865
+ parent_module = :unknown
866
+ type = KatakataIrb::Types::NIL
867
+ end
868
+ when Prism::ConstantReadNode
869
+ name = node.name.to_s
870
+ type = scope[name]
871
+ end
872
+ @dig_targets.resolve type, scope if @dig_targets.target? node
873
+ [type, receiver, parent_module, name]
874
+ end
875
+
876
+
877
+ def assign_parameters(node, scope, args, kwargs)
878
+ args = args.dup
879
+ kwargs = kwargs.dup
880
+ size = node.requireds.size + node.optionals.size + (node.rest ? 1 : 0) + node.posts.size
881
+ args = sized_splat(args.first, :to_ary, size) if size >= 2 && args.size == 1
882
+ reqs = args.shift node.requireds.size
883
+ if node.rest
884
+ # node.rest.class is Prism::RestParameterNode
885
+ posts = []
886
+ opts = args.shift node.optionals.size
887
+ rest = args
888
+ else
889
+ posts = args.pop node.posts.size
890
+ opts = args
891
+ rest = []
892
+ end
893
+ node.requireds.zip reqs do |n, v|
894
+ assign_required_parameter n, v, scope
895
+ end
896
+ node.optionals.zip opts do |n, v|
897
+ # n is Prism::OptionalParameterNode
898
+ values = [v]
899
+ values << evaluate(n.value, scope) if n.value
900
+ scope[n.name.to_s] = KatakataIrb::Types::UnionType[*values.compact]
901
+ end
902
+ node.posts.zip posts do |n, v|
903
+ assign_required_parameter n, v, scope
904
+ end
905
+ if node.rest&.name
906
+ # node.rest is Prism::RestParameterNode
907
+ scope[node.rest.name.to_s] = KatakataIrb::Types.array_of(*rest)
908
+ end
909
+ node.keywords.each do |n|
910
+ # n is Prism::KeywordParameterNode
911
+ name = n.name.to_s.delete(':')
912
+ values = [kwargs.delete(name)]
913
+ values << evaluate(n.value, scope) if n.value
914
+ scope[name] = KatakataIrb::Types::UnionType[*values.compact]
915
+ end
916
+ # node.keyword_rest is Prism::KeywordRestParameterNode or Prism::ForwardingParameterNode or Prism::NoKeywordsParameterNode
917
+ if node.keyword_rest.is_a?(Prism::KeywordRestParameterNode) && node.keyword_rest.name
918
+ scope[node.keyword_rest.name.to_s] = KatakataIrb::Types::InstanceType.new(Hash, K: KatakataIrb::Types::SYMBOL, V: KatakataIrb::Types::UnionType[*kwargs.values])
919
+ end
920
+ if node.block&.name
921
+ # node.block is Prism::BlockParameterNode
922
+ scope[node.block.name.to_s] = KatakataIrb::Types::PROC
923
+ end
924
+ end
925
+
926
+ def assign_numbered_parameters(numbered_parameters, scope, args, _kwargs)
927
+ return if numbered_parameters.empty?
928
+ max_num = numbered_parameters.map { _1[1].to_i }.max
929
+ if max_num == 1
930
+ if args.size == 0
931
+ scope['_1'] = KatakataIrb::Types::NIL
932
+ elsif args.size == 1
933
+ scope['_1'] = args.first
934
+ else
935
+ scope['_1'] = KatakataIrb::Types.array_of(*args)
936
+ end
937
+ else
938
+ args = sized_splat(args.first, :to_ary, max_num) if args.size == 1
939
+ numbered_parameters.each do |name|
940
+ index = name[1].to_i - 1
941
+ scope[name] = args[index] || KatakataIrb::Types::NIL
942
+ end
943
+ end
944
+ end
945
+
946
+ def evaluate_case_match(target, node, scope)
947
+ case node
948
+ when Prism::WhenNode
949
+ node.conditions.each { evaluate _1, scope }
950
+ node.statements ? evaluate(node.statements, scope) : KatakataIrb::Types::NIL
951
+ when Prism::InNode
952
+ pattern = node.pattern
953
+ if pattern.is_a?(Prism::IfNode) || pattern.is_a?(Prism::UnlessNode)
954
+ cond_node = pattern.predicate
955
+ pattern = pattern.statements.body.first
956
+ end
957
+ evaluate_match_pattern(target, pattern, scope)
958
+ evaluate cond_node, scope if cond_node # TODO: conditional branch
959
+ node.statements ? evaluate(node.statements, scope) : KatakataIrb::Types::NIL
960
+ end
961
+ end
962
+
963
+ def evaluate_match_pattern(value, pattern, scope)
964
+ # TODO: scope.terminate_with KatakataIrb::Scope::PATTERNMATCH_BREAK, KatakataIrb::Types::NIL
965
+ case pattern
966
+ when Prism::FindPatternNode
967
+ # TODO
968
+ evaluate_match_pattern KatakataIrb::Types::OBJECT, pattern.left, scope
969
+ pattern.requireds.each { evaluate_match_pattern KatakataIrb::Types::OBJECT, _1, scope }
970
+ evaluate_match_pattern KatakataIrb::Types::OBJECT, pattern.right, scope
971
+ when Prism::ArrayPatternNode
972
+ # TODO
973
+ pattern.requireds.each { evaluate_match_pattern KatakataIrb::Types::OBJECT, _1, scope }
974
+ evaluate_match_pattern KatakataIrb::Types::OBJECT, pattern.rest, scope if pattern.rest
975
+ pattern.posts.each { evaluate_match_pattern KatakataIrb::Types::OBJECT, _1, scope }
976
+ KatakataIrb::Types::ARRAY
977
+ when Prism::HashPatternNode
978
+ # TODO
979
+ pattern.assocs.each { evaluate_match_pattern KatakataIrb::Types::OBJECT, _1, scope }
980
+ KatakataIrb::Types::HASH
981
+ when Prism::AssocNode
982
+ evaluate_match_pattern value, pattern.value, scope if pattern.value
983
+ KatakataIrb::Types::OBJECT
984
+ when Prism::AssocSplatNode
985
+ # TODO
986
+ evaluate_match_pattern KatakataIrb::Types::HASH, pattern.value, scope
987
+ KatakataIrb::Types::OBJECT
988
+ when Prism::PinnedVariableNode
989
+ evaluate pattern.variable, scope
990
+ when Prism::PinnedExpressionNode
991
+ evaluate pattern.expression, scope
992
+ when Prism::LocalVariableTargetNode
993
+ scope[pattern.name.to_s] = value
994
+ when Prism::AlternationPatternNode
995
+ KatakataIrb::Types::UnionType[evaluate_match_pattern(value, pattern.left, scope), evaluate_match_pattern(value, pattern.right, scope)]
996
+ when Prism::CapturePatternNode
997
+ capture_type = class_or_value_to_instance evaluate_match_pattern(value, pattern.value, scope)
998
+ value = capture_type unless capture_type.types.empty? || capture_type.types == [KatakataIrb::Types::OBJECT]
999
+ evaluate_match_pattern value, pattern.target, scope
1000
+ when Prism::SplatNode
1001
+ value = KatakataIrb::Types.array_of value
1002
+ evaluate_match_pattern value, pattern.expression, scope if pattern.expression
1003
+ value
1004
+ else
1005
+ # literal node
1006
+ type = evaluate(pattern, scope)
1007
+ class_or_value_to_instance(type)
1008
+ end
1009
+ end
1010
+
1011
+ def class_or_value_to_instance(type)
1012
+ instance_types = type.types.map do |t|
1013
+ t.is_a?(KatakataIrb::Types::SingletonType) ? KatakataIrb::Types::InstanceType.new(t.module_or_class) : t
1014
+ end
1015
+ KatakataIrb::Types::UnionType[*instance_types]
1016
+ end
1017
+
1018
+ def evaluate_write(node, value, scope, evaluated_receivers)
1019
+ case node
1020
+ when Prism::MultiTargetNode
1021
+ evaluate_multi_write node, value, scope, evaluated_receivers
1022
+ when Prism::CallNode
1023
+ evaluated_receivers&.[](node.receiver) || evaluate(node.receiver, scope) if node.receiver
1024
+ when Prism::SplatNode
1025
+ evaluate_write node.expression, KatakataIrb::Types.array_of(value), scope, evaluated_receivers
1026
+ when Prism::LocalVariableTargetNode, Prism::GlobalVariableTargetNode, Prism::InstanceVariableTargetNode, Prism::ClassVariableTargetNode, Prism::ConstantTargetNode
1027
+ scope[node.name.to_s] = value
1028
+ when Prism::ConstantPathTargetNode
1029
+ receiver = evaluated_receivers&.[](node.parent) || evaluate(node.parent, scope) if node.parent
1030
+ const_path_write receiver, node.child.name.to_s, value, scope
1031
+ value
1032
+ end
1033
+ end
1034
+
1035
+ def evaluate_multi_write(node, values, scope, evaluated_receivers)
1036
+ values = sized_splat values, :to_ary, node.targets.size unless values.is_a? Array
1037
+ splat_index = node.targets.find_index { _1.is_a? Prism::SplatNode }
1038
+ if splat_index
1039
+ pre_targets = node.targets[0...splat_index]
1040
+ splat_target = node.targets[splat_index]
1041
+ post_targets = node.targets[splat_index + 1..]
1042
+ pre_values = values.shift pre_targets.size
1043
+ post_values = values.pop post_targets.size
1044
+ splat_value = KatakataIrb::Types::UnionType[*values]
1045
+ zips = pre_targets.zip(pre_values) + [[splat_target, splat_value]] + post_targets.zip(post_values)
1046
+ else
1047
+ zips = node.targets.zip(values)
1048
+ end
1049
+ zips.each do |target, value|
1050
+ evaluate_write target, value || KatakataIrb::Types::NIL, scope, evaluated_receivers
1051
+ end
1052
+ end
1053
+
1054
+ def evaluate_multi_write_receiver(node, scope, evaluated_receivers)
1055
+ case node
1056
+ when Prism::MultiWriteNode, Prism::MultiTargetNode
1057
+ node.targets.each { evaluate_multi_write_receiver _1, scope, evaluated_receivers }
1058
+ when Prism::CallNode
1059
+ if node.receiver
1060
+ receiver = evaluate(node.receiver, scope)
1061
+ evaluated_receivers[node.receiver] = receiver if evaluated_receivers
1062
+ end
1063
+ if node.arguments
1064
+ node.arguments.arguments&.each do |arg|
1065
+ if arg.is_a? Prism::SplatNode
1066
+ evaluate arg.expression, scope
1067
+ else
1068
+ evaluate arg, scope
1069
+ end
1070
+ end
1071
+ end
1072
+ when Prism::SplatNode
1073
+ evaluate_multi_write_receiver node.expression, scope, evaluated_receivers if node.expression
1074
+ end
1075
+ end
1076
+
1077
+ def evaluate_list_splat_items(list, scope)
1078
+ items = list.flat_map do |node|
1079
+ if node.is_a? Prism::SplatNode
1080
+ splat = evaluate node.expression, scope
1081
+ array_elem, non_array = partition_to_array splat.nonnillable, :to_a
1082
+ [*array_elem, *non_array]
1083
+ else
1084
+ evaluate node, scope
1085
+ end
1086
+ end.uniq
1087
+ KatakataIrb::Types::UnionType[*items]
1088
+ end
1089
+
1090
+ def sized_splat(value, method, size)
1091
+ array_elem, non_array = partition_to_array value, method
1092
+ values = [KatakataIrb::Types::UnionType[*array_elem, *non_array]]
1093
+ values += [array_elem] * (size - 1) if array_elem && size >= 1
1094
+ values
1095
+ end
1096
+
1097
+ def partition_to_array(value, method)
1098
+ arrays, non_arrays = value.types.partition { _1.is_a?(KatakataIrb::Types::InstanceType) && _1.klass == Array }
1099
+ non_arrays.select! do |type|
1100
+ to_array_result = method_call type, method, [], nil, nil, nil, name_match: false
1101
+ if to_array_result.is_a?(KatakataIrb::Types::InstanceType) && to_array_result.klass == Array
1102
+ arrays << to_array_result
1103
+ false
1104
+ else
1105
+ true
1106
+ end
1107
+ end
1108
+ array_elem = arrays.empty? ? nil : KatakataIrb::Types::UnionType[*arrays.map { _1.params[:Elem] || KatakataIrb::Types::OBJECT }]
1109
+ non_array = non_arrays.empty? ? nil : KatakataIrb::Types::UnionType[*non_arrays]
1110
+ [array_elem, non_array]
1111
+ end
1112
+
1113
+ def method_call(receiver, method_name, args, kwargs, block, scope, name_match: true)
1114
+ methods = KatakataIrb::Types.rbs_methods receiver, method_name.to_sym, args, kwargs, !!block
1115
+ block_called = false
1116
+ type_breaks = methods.map do |method, given_params, method_params|
1117
+ receiver_vars = receiver.is_a?(KatakataIrb::Types::InstanceType) ? receiver.params : {}
1118
+ free_vars = method.type.free_variables - receiver_vars.keys.to_set
1119
+ vars = receiver_vars.merge KatakataIrb::Types.match_free_variables(free_vars, method_params, given_params)
1120
+ if block && method.block
1121
+ params_type = method.block.type.required_positionals.map do |func_param|
1122
+ KatakataIrb::Types.from_rbs_type func_param.type, receiver, vars
1123
+ end
1124
+ self_type = KatakataIrb::Types.from_rbs_type method.block.self_type, receiver, vars if method.block.self_type
1125
+ block_response, breaks = block.call params_type, self_type
1126
+ block_called = true
1127
+ vars.merge! KatakataIrb::Types.match_free_variables(free_vars - vars.keys.to_set, [method.block.type.return_type], [block_response])
1128
+ end
1129
+ if KatakataIrb::Types.method_return_bottom?(method)
1130
+ [nil, breaks]
1131
+ else
1132
+ [KatakataIrb::Types.from_rbs_type(method.type.return_type, receiver, vars || {}), breaks]
1133
+ end
1134
+ end
1135
+ block&.call [], nil unless block_called
1136
+ terminates = !type_breaks.empty? && type_breaks.map(&:first).all?(&:nil?)
1137
+ types = type_breaks.map(&:first).compact
1138
+ breaks = type_breaks.map(&:last).compact
1139
+ types << OBJECT_METHODS[method_name.to_sym] if name_match && OBJECT_METHODS.has_key?(method_name.to_sym)
1140
+
1141
+ if method_name.to_sym == :new
1142
+ receiver.types.each do |type|
1143
+ if type.is_a?(KatakataIrb::Types::SingletonType) && type.module_or_class.is_a?(Class)
1144
+ types << KatakataIrb::Types::InstanceType.new(type.module_or_class)
1145
+ end
1146
+ end
1147
+ end
1148
+ scope&.terminate if terminates && breaks.empty?
1149
+ KatakataIrb::Types::UnionType[*types, *breaks]
1150
+ end
1151
+
1152
+ def evaluate_program(program, scope)
1153
+ # statements.body[0] is local variable assign code
1154
+ program.statements.body[1..].each do |statement|
1155
+ evaluate statement, scope
1156
+ end
1157
+ end
1158
+
1159
+ def self.calculate_target_type_scope(binding, parents, target)
1160
+ dig_targets = DigTarget.new(parents, target) do |type, scope|
1161
+ return type, scope
1162
+ end
1163
+ program = parents.first
1164
+ scope = KatakataIrb::Scope.from_binding(binding, program.locals)
1165
+ new(dig_targets).evaluate_program program, scope
1166
+ [KatakataIrb::Types::NIL, scope]
1167
+ end
1168
+ end