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