repl_type_completor 0.1.0

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