repl_type_completor 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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