katakata_irb 0.2.0 → 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,990 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'set'
4
- require_relative 'types'
5
- require_relative 'scope'
6
- require 'prism'
7
-
8
- class KatakataIrb::TypeSimulator
9
- class DigTarget
10
- def initialize(parents, receiver, &block)
11
- @dig_ids = parents.to_h { [_1.__id__, true] }
12
- @target_id = receiver.__id__
13
- @block = block
14
- end
15
-
16
- def dig?(node) = @dig_ids[node.__id__]
17
- def target?(node) = @target_id == node.__id__
18
- def resolve(type, scope)
19
- @block.call type, scope
20
- end
21
- end
22
-
23
- OBJECT_METHODS = {
24
- to_s: KatakataIrb::Types::STRING,
25
- to_str: KatakataIrb::Types::STRING,
26
- to_a: KatakataIrb::Types::ARRAY,
27
- to_ary: KatakataIrb::Types::ARRAY,
28
- to_h: KatakataIrb::Types::HASH,
29
- to_hash: KatakataIrb::Types::HASH,
30
- to_i: KatakataIrb::Types::INTEGER,
31
- to_int: KatakataIrb::Types::INTEGER,
32
- to_f: KatakataIrb::Types::FLOAT,
33
- to_c: KatakataIrb::Types::COMPLEX,
34
- to_r: KatakataIrb::Types::RATIONAL
35
- }
36
-
37
- def initialize(dig_targets)
38
- @dig_targets = dig_targets
39
- end
40
-
41
- def evaluate(node, scope)
42
- result = evaluate_inner(node, scope)
43
- @dig_targets.resolve result, scope if @dig_targets.target?(node)
44
- result
45
- end
46
-
47
- def evaluate_inner(node, scope)
48
- case node
49
- when Prism::ProgramNode
50
- evaluate node.statements, scope
51
- when Prism::StatementsNode
52
- if node.body.empty?
53
- KatakataIrb::Types::NIL
54
- else
55
- node.body.map { evaluate _1, scope }.last
56
- end
57
- when Prism::DefNode
58
- if node.receiver
59
- self_type = evaluate node.receiver, scope
60
- else
61
- current_self_types = scope.self_type.types
62
- self_types = current_self_types.map do |type|
63
- if type.is_a?(KatakataIrb::Types::SingletonType) && type.module_or_class.is_a?(Class)
64
- KatakataIrb::Types::InstanceType.new type.module_or_class
65
- else
66
- type
67
- end
68
- end
69
- self_type = KatakataIrb::Types::UnionType[*self_types]
70
- end
71
- if @dig_targets.dig?(node.body) || @dig_targets.dig?(node.parameters)
72
- params_table = node.locals.to_h { [_1.to_s, KatakataIrb::Types::NIL] }
73
- method_scope = KatakataIrb::Scope.new(
74
- scope,
75
- { **params_table, KatakataIrb::Scope::BREAK_RESULT => nil, KatakataIrb::Scope::NEXT_RESULT => nil, KatakataIrb::Scope::RETURN_RESULT => nil },
76
- self_type: self_type,
77
- trace_lvar: false,
78
- trace_ivar: false
79
- )
80
- if node.parameters
81
- # node.parameters is Prism::ParametersNode
82
- assign_parameters node.parameters, method_scope, [], {}
83
- end
84
-
85
- if @dig_targets.dig?(node.body)
86
- method_scope.conditional do |s|
87
- evaluate node.body, s
88
- end
89
- end
90
- method_scope.merge_jumps
91
- scope.update method_scope
92
- end
93
- KatakataIrb::Types::SYMBOL
94
- when Prism::IntegerNode
95
- KatakataIrb::Types::INTEGER
96
- when Prism::FloatNode
97
- KatakataIrb::Types::FLOAT
98
- when Prism::RationalNode
99
- KatakataIrb::Types::RATIONAL
100
- when Prism::ImaginaryNode
101
- KatakataIrb::Types::COMPLEX
102
- when Prism::StringNode
103
- KatakataIrb::Types::STRING
104
- when Prism::XStringNode
105
- KatakataIrb::Types::UnionType[KatakataIrb::Types::STRING, KatakataIrb::Types::NIL]
106
- when Prism::SymbolNode
107
- KatakataIrb::Types::SYMBOL
108
- when Prism::RegularExpressionNode
109
- KatakataIrb::Types::REGEXP
110
- when Prism::StringConcatNode
111
- evaluate node.left, scope
112
- evaluate node.right, scope
113
- KatakataIrb::Types::STRING
114
- when Prism::InterpolatedStringNode
115
- node.parts.each { evaluate _1, scope }
116
- KatakataIrb::Types::STRING
117
- when Prism::InterpolatedXStringNode
118
- node.parts.each { evaluate _1, scope }
119
- KatakataIrb::Types::STRING
120
- when Prism::InterpolatedSymbolNode
121
- node.parts.each { evaluate _1, scope }
122
- KatakataIrb::Types::SYMBOL
123
- when Prism::InterpolatedRegularExpressionNode
124
- node.parts.each { evaluate _1, scope }
125
- KatakataIrb::Types::REGEXP
126
- when Prism::EmbeddedStatementsNode
127
- node.statements ? evaluate(node.statements, scope) : KatakataIrb::Types::NIL
128
- KatakataIrb::Types::STRING
129
- when Prism::EmbeddedVariableNode
130
- evaluate node.variable, scope
131
- KatakataIrb::Types::STRING
132
- when Prism::ArrayNode
133
- KatakataIrb::Types.array_of evaluate_list_splat_items(node.elements, scope)
134
- when Prism::HashNode, Prism::KeywordHashNode
135
- keys = []
136
- values = []
137
- node.elements.each do |assoc|
138
- case assoc
139
- when Prism::AssocNode
140
- keys << evaluate(assoc.key, scope)
141
- values << evaluate(assoc.value, scope)
142
- when Prism::AssocSplatNode
143
- hash = evaluate assoc.value, scope
144
- unless hash.is_a?(KatakataIrb::Types::InstanceType) && hash.klass == Hash
145
- hash = simulate_call hash, :to_hash, [], nil, nil, scope
146
- end
147
- if hash.is_a?(KatakataIrb::Types::InstanceType) && hash.klass == Hash
148
- keys << hash.params[:K] if hash.params[:K]
149
- values << hash.params[:V] if hash.params[:V]
150
- end
151
- end
152
- end
153
- if keys.empty? && values.empty?
154
- KatakataIrb::Types::InstanceType.new Hash
155
- else
156
- KatakataIrb::Types::InstanceType.new Hash, K: KatakataIrb::Types::UnionType[*keys], V: KatakataIrb::Types::UnionType[*values]
157
- end
158
- when Prism::ParenthesesNode
159
- node.body ? evaluate(node.body, scope) : KatakataIrb::Types::NIL
160
- when Prism::ConstantPathNode
161
- type, = evaluate_constant_node node, scope
162
- type
163
- when Prism::SelfNode
164
- scope.self_type
165
- when Prism::TrueNode
166
- KatakataIrb::Types::TRUE
167
- when Prism::FalseNode
168
- KatakataIrb::Types::FALSE
169
- when Prism::NilNode
170
- KatakataIrb::Types::NIL
171
- when Prism::SourceFileNode
172
- KatakataIrb::Types::STRING
173
- when Prism::SourceLineNode
174
- KatakataIrb::Types::INTEGER
175
- when Prism::SourceEncodingNode
176
- KatakataIrb::Types::InstanceType.new Encoding
177
- when Prism::NumberedReferenceReadNode, Prism::BackReferenceReadNode
178
- KatakataIrb::Types::UnionType[KatakataIrb::Types::STRING, KatakataIrb::Types::NIL]
179
- when Prism::LocalVariableReadNode
180
- scope[node.name.to_s] || KatakataIrb::Types::NIL
181
- when Prism::ConstantReadNode, Prism::GlobalVariableReadNode, Prism::InstanceVariableReadNode, Prism::ClassVariableReadNode
182
- scope[node.name.to_s] || KatakataIrb::Types::NIL
183
- when Prism::CallNode
184
- # TODO: return type of []=, field= when operator_loc.nil?
185
- receiver_type = node.receiver ? evaluate(node.receiver, scope) : scope.self_type
186
- evaluate_method = lambda do |scope|
187
- args_types, kwargs_types, block_sym_node, has_block = evaluate_call_node_arguments node, scope
188
-
189
- if block_sym_node
190
- block_sym = block_sym_node.value
191
- if @dig_targets.target? block_sym_node
192
- # method(args, &:completion_target)
193
- call_block_proc = ->(block_args, _self_type) do
194
- block_receiver = block_args.first || KatakataIrb::Types::OBJECT
195
- @dig_targets.resolve block_receiver, scope
196
- KatakataIrb::Types::OBJECT
197
- end
198
- else
199
- call_block_proc = ->(block_args, _self_type) do
200
- block_receiver, *rest = block_args
201
- block_receiver ? simulate_call(block_receiver || KatakataIrb::Types::OBJECT, block_sym, rest, nil, nil, scope) : KatakataIrb::Types::OBJECT
202
- end
203
- end
204
- elsif node.block.is_a? Prism::BlockNode
205
- call_block_proc = ->(block_args, block_self_type) do
206
- scope.conditional do |s|
207
- numbered_parameters = node.block.locals.grep(/\A_[1-9]/).map(&:to_s)
208
- params_table = node.block.locals.to_h { [_1.to_s, KatakataIrb::Types::NIL] }
209
- table = { **params_table, KatakataIrb::Scope::BREAK_RESULT => nil, KatakataIrb::Scope::NEXT_RESULT => nil }
210
- block_scope = KatakataIrb::Scope.new s, table, self_type: block_self_type, trace_ivar: !block_self_type
211
- # TODO kwargs
212
- if node.block.parameters&.parameters
213
- # node.block.parameters is Prism::BlockParametersNode
214
- assign_parameters node.block.parameters.parameters, block_scope, block_args, {}
215
- elsif !numbered_parameters.empty?
216
- assign_numbered_parameters numbered_parameters, block_scope, block_args, {}
217
- end
218
- result = node.block.body ? evaluate(node.block.body, block_scope) : KatakataIrb::Types::NIL
219
- block_scope.merge_jumps
220
- s.update block_scope
221
- nexts = block_scope[KatakataIrb::Scope::NEXT_RESULT]
222
- breaks = block_scope[KatakataIrb::Scope::BREAK_RESULT]
223
- if block_scope.terminated?
224
- [KatakataIrb::Types::UnionType[*nexts], breaks]
225
- else
226
- [KatakataIrb::Types::UnionType[result, *nexts], breaks]
227
- end
228
- end
229
- end
230
- elsif has_block
231
- call_block_proc = ->(_block_args, _self_type) { KatakataIrb::Types::OBJECT }
232
- end
233
- simulate_call receiver_type, node.name, args_types, kwargs_types, call_block_proc, scope
234
- end
235
- if node.call_operator == '&.'
236
- result = scope.conditional { evaluate_method.call _1 }
237
- if receiver_type.nillable?
238
- KatakataIrb::Types::UnionType[result, KatakataIrb::Types::NIL]
239
- else
240
- result
241
- end
242
- else
243
- evaluate_method.call scope
244
- end
245
- when Prism::AndNode, Prism::OrNode
246
- left = evaluate node.left, scope
247
- right = scope.conditional { evaluate node.right, _1 }
248
- if node.operator == '&&'
249
- KatakataIrb::Types::UnionType[right, KatakataIrb::Types::NIL, KatakataIrb::Types::FALSE]
250
- else
251
- KatakataIrb::Types::UnionType[left, right]
252
- end
253
- when Prism::CallOperatorWriteNode, Prism::CallAndWriteNode, Prism::CallOrWriteNode
254
- receiver_type = evaluate node.receiver, scope
255
- args_types, kwargs_types, block_sym_node, has_block = evaluate_call_node_arguments node, scope
256
- if block_sym_node
257
- block_sym = block_sym_node.value
258
- call_block_proc = ->(block_args, _self_type) do
259
- block_receiver, *rest = block_args
260
- block_receiver ? simulate_call(block_receiver || KatakataIrb::Types::OBJECT, block_sym, rest, nil, nil, scope) : KatakataIrb::Types::OBJECT
261
- end
262
- elsif has_block
263
- call_block_proc = ->(_block_args, _self_type) { KatakataIrb::Types::OBJECT }
264
- end
265
- method = node.write_name.to_s.delete_suffix('=')
266
- left = simulate_call receiver_type, method, args_types, kwargs_types, call_block_proc, scope
267
- if node.operator == '&&='
268
- right = scope.conditional { evaluate node.value, _1 }
269
- KatakataIrb::Types::UnionType[right, KatakataIrb::Types::NIL, KatakataIrb::Types::FALSE]
270
- elsif node.operator == '||='
271
- right = scope.conditional { evaluate node.value, _1 }
272
- KatakataIrb::Types::UnionType[left, right]
273
- else
274
- right = evaluate node.value, scope
275
- simulate_call left, node.operator, [right], nil, nil, scope, name_match: false
276
- end
277
- when Prism::ClassVariableOperatorWriteNode, Prism::InstanceVariableOperatorWriteNode, Prism::LocalVariableOperatorWriteNode, Prism::GlobalVariableOperatorWriteNode
278
- left = scope[node.name.to_s] || KatakataIrb::Types::OBJECT
279
- right = evaluate node.value, scope
280
- scope[node.name.to_s] = simulate_call left, node.operator, [right], nil, nil, scope, name_match: false
281
- when Prism::ClassVariableAndWriteNode, Prism::InstanceVariableAndWriteNode, Prism::LocalVariableAndWriteNode, Prism::GlobalVariableAndWriteNode
282
- right = scope.conditional { evaluate node.value, scope }
283
- scope[node.name.to_s] = KatakataIrb::Types::UnionType[right, KatakataIrb::Types::NIL, KatakataIrb::Types::FALSE]
284
- when Prism::ClassVariableOrWriteNode, Prism::InstanceVariableOrWriteNode, Prism::LocalVariableOrWriteNode, Prism::GlobalVariableOrWriteNode
285
- left = scope[node.name.to_s] || KatakataIrb::Types::OBJECT
286
- right = scope.conditional { evaluate node.value, scope }
287
- scope[node.name.to_s] = KatakataIrb::Types::UnionType[left, right]
288
- when Prism::ConstantOperatorWriteNode
289
- left = scope[node.name.to_s] || KatakataIrb::Types::OBJECT
290
- right = evaluate node.value, scope
291
- scope[node.name.to_s] = simulate_call left, node.operator, [right], nil, nil, scope, name_match: false
292
- when Prism::ConstantAndWriteNode
293
- right = scope.conditional { evaluate node.value, scope }
294
- scope[node.name.to_s] = KatakataIrb::Types::UnionType[right, KatakataIrb::Types::NIL, KatakataIrb::Types::FALSE]
295
- when Prism::ConstantOrWriteNode
296
- left = scope[node.name.to_s] || KatakataIrb::Types::OBJECT
297
- right = scope.conditional { evaluate node.value, scope }
298
- scope[node.name.to_s] = KatakataIrb::Types::UnionType[left, right]
299
- when Prism::ConstantPathOperatorWriteNode
300
- left, receiver, _parent_module, name = evaluate_constant_node node.target, scope
301
- right = evaluate node.value, scope
302
- value = simulate_call left, node.operator, [right], nil, nil, scope, name_match: false
303
- const_path_write receiver, name, value, scope
304
- value
305
- when Prism::ConstantPathAndWriteNode
306
- _left, receiver, _parent_module, name = evaluate_constant_node node.target, scope
307
- right = scope.conditional { evaluate node.value, scope }
308
- value = KatakataIrb::Types::UnionType[right, KatakataIrb::Types::NIL, KatakataIrb::Types::FALSE]
309
- const_path_write receiver, name, value, scope
310
- value
311
- when Prism::ConstantPathOrWriteNode
312
- left, receiver, _parent_module, name = evaluate_constant_node node.target, scope
313
- right = scope.conditional { evaluate node.value, scope }
314
- value = KatakataIrb::Types::UnionType[left, right]
315
- const_path_write receiver, name, value, scope
316
- value
317
- when Prism::ConstantPathWriteNode
318
- receiver = evaluate node.target.parent, scope if node.target.parent
319
- value = evaluate node.value, scope
320
- const_path_write receiver, node.target.child.name.to_s, value, scope
321
- value
322
- when Prism::LambdaNode
323
- local_table = node.locals.to_h { [_1.to_s, KatakataIrb::Types::OBJECT] }
324
- block_scope = KatakataIrb::Scope.new scope, { **local_table, KatakataIrb::Scope::BREAK_RESULT => nil, KatakataIrb::Scope::NEXT_RESULT => nil, KatakataIrb::Scope::RETURN_RESULT => nil }
325
- block_scope.conditional do |s|
326
- assign_parameters node.parameters.parameters, s, [], {} if node.parameters&.parameters
327
- evaluate node.body, s if node.body
328
- end
329
- block_scope.merge_jumps
330
- scope.update block_scope
331
- KatakataIrb::Types::ProcType.new
332
- when Prism::LocalVariableWriteNode, Prism::GlobalVariableWriteNode, Prism::InstanceVariableWriteNode, Prism::ClassVariableWriteNode, Prism::ConstantWriteNode
333
- scope[node.name.to_s] = evaluate node.value, scope
334
- when Prism::MultiWriteNode
335
- evaluated_receivers = {}
336
- evaluate_multi_write_receiver node, scope, evaluated_receivers
337
- value = (
338
- if node.value.is_a? Prism::ArrayNode
339
- if node.value.elements.any?(Prism::SplatNode)
340
- evaluate node.value, scope
341
- else
342
- node.value.elements.map do |n|
343
- evaluate n, scope
344
- end
345
- end
346
- elsif node.value
347
- evaluate node.value, scope
348
- else
349
- # For syntax invalid code like `(*a).b`
350
- KatakataIrb::Types::NIL
351
- end
352
- )
353
- evaluate_multi_write node, value, scope, evaluated_receivers
354
- when Prism::IfNode, Prism::UnlessNode
355
- evaluate node.predicate, scope
356
- KatakataIrb::Types::UnionType[*scope.run_branches(
357
- -> { node.statements ? evaluate(node.statements, _1) : KatakataIrb::Types::NIL },
358
- -> { node.consequent ? evaluate(node.consequent, _1) : KatakataIrb::Types::NIL }
359
- )]
360
- when Prism::ElseNode
361
- node.statements ? evaluate(node.statements, scope) : KatakataIrb::Types::NIL
362
- when Prism::WhileNode, Prism::UntilNode
363
- inner_scope = KatakataIrb::Scope.new scope, { KatakataIrb::Scope::BREAK_RESULT => nil }
364
- evaluate node.predicate, inner_scope
365
- if node.statements
366
- inner_scope.conditional do |s|
367
- evaluate node.statements, s
368
- end
369
- end
370
- inner_scope.merge_jumps
371
- scope.update inner_scope
372
- breaks = inner_scope[KatakataIrb::Scope::BREAK_RESULT]
373
- breaks ? KatakataIrb::Types::UnionType[breaks, KatakataIrb::Types::NIL] : KatakataIrb::Types::NIL
374
- when Prism::BreakNode, Prism::NextNode, Prism::ReturnNode
375
- internal_key = (
376
- case node
377
- when Prism::BreakNode
378
- KatakataIrb::Scope::BREAK_RESULT
379
- when Prism::NextNode
380
- KatakataIrb::Scope::NEXT_RESULT
381
- when Prism::ReturnNode
382
- KatakataIrb::Scope::RETURN_RESULT
383
- end
384
- )
385
- jump_value = (
386
- arguments = node.arguments&.arguments
387
- if arguments.nil? || arguments.empty?
388
- KatakataIrb::Types::NIL
389
- elsif arguments.size == 1 && !arguments.first.is_a?(Prism::SplatNode)
390
- evaluate arguments.first, scope
391
- else
392
- KatakataIrb::Types.array_of evaluate_list_splat_items(arguments, scope)
393
- end
394
- )
395
- scope.terminate_with internal_key, jump_value
396
- KatakataIrb::Types::NIL
397
- when Prism::YieldNode
398
- evaluate_list_splat_items node.arguments.arguments, scope if node.arguments
399
- KatakataIrb::Types::OBJECT
400
- when Prism::RedoNode, Prism::RetryNode
401
- scope.terminate
402
- when Prism::ForwardingSuperNode
403
- KatakataIrb::Types::OBJECT
404
- when Prism::SuperNode
405
- evaluate_list_splat_items node.arguments.arguments, scope if node.arguments
406
- KatakataIrb::Types::OBJECT
407
- when Prism::BeginNode
408
- return_type = node.statements ? evaluate(node.statements, scope) : KatakataIrb::Types::NIL
409
- if node.rescue_clause
410
- if node.else_clause
411
- return_types = scope.run_branches(
412
- ->{ evaluate node.rescue_clause, _1 },
413
- ->{ evaluate node.else_clause, _1 }
414
- )
415
- else
416
- return_types = [
417
- return_type,
418
- scope.conditional { evaluate node.rescue_clause, _1 }
419
- ]
420
- end
421
- return_type = KatakataIrb::Types::UnionType[*return_types]
422
- end
423
- if node.ensure_clause&.statements
424
- # ensure_clause is Prism::EnsureNode
425
- evaluate node.ensure_clause.statements, scope
426
- end
427
- return_type
428
- when Prism::RescueNode
429
- run_rescue = lambda do |s|
430
- if node.reference
431
- error_classes_type = evaluate_list_splat_items node.exceptions, s
432
- error_types = error_classes_type.types.filter_map do
433
- KatakataIrb::Types::InstanceType.new _1.module_or_class if _1.is_a?(KatakataIrb::Types::SingletonType)
434
- end
435
- error_types << KatakataIrb::Types::InstanceType.new(StandardError) if error_types.empty?
436
- error_type = KatakataIrb::Types::UnionType[*error_types]
437
- case node.reference
438
- when Prism::LocalVariableTargetNode, Prism::InstanceVariableTargetNode, Prism::ClassVariableTargetNode, Prism::GlobalVariableTargetNode, Prism::ConstantTargetNode
439
- s[node.reference.name.to_s] = error_type
440
- when Prism::CallNode
441
- evaluate node.reference, s
442
- end
443
- end
444
- node.statements ? evaluate(node.statements, s) : KatakataIrb::Types::NIL
445
- end
446
- if node.consequent # begin; rescue A; rescue B; end
447
- types = scope.run_branches(
448
- run_rescue,
449
- -> { evaluate node.consequent, _1 }
450
- )
451
- KatakataIrb::Types::UnionType[*types]
452
- else
453
- run_rescue.call scope
454
- end
455
- when Prism::RescueModifierNode
456
- a = evaluate node.expression, scope
457
- b = scope.conditional { evaluate node.rescue_expression, _1 }
458
- KatakataIrb::Types::UnionType[a, b]
459
- when Prism::SingletonClassNode
460
- klass_types = evaluate(node.expression, scope).types.filter_map do |type|
461
- KatakataIrb::Types::SingletonType.new type.klass if type.is_a? KatakataIrb::Types::InstanceType
462
- end
463
- klass_types = [KatakataIrb::Types::CLASS] if klass_types.empty?
464
- table = node.locals.to_h { [_1.to_s, KatakataIrb::Types::NIL] }
465
- sclass_scope = KatakataIrb::Scope.new(
466
- scope,
467
- { **table, KatakataIrb::Scope::BREAK_RESULT => nil, KatakataIrb::Scope::NEXT_RESULT => nil, KatakataIrb::Scope::RETURN_RESULT => nil },
468
- trace_ivar: false,
469
- trace_lvar: false,
470
- self_type: KatakataIrb::Types::UnionType[*klass_types]
471
- )
472
- result = node.body ? evaluate(node.body, sclass_scope) : KatakataIrb::Types::NIL
473
- scope.update sclass_scope
474
- result
475
- when Prism::ModuleNode, Prism::ClassNode
476
- unless node.constant_path.is_a?(Prism::ConstantReadNode) || node.constant_path.is_a?(Prism::ConstantPathNode)
477
- # Syntax error code, example: `module a.b; end`
478
- return KatakataIrb::Types::NIL
479
- end
480
- const_type, _receiver, parent_module, name = evaluate_constant_node node.constant_path, scope
481
- if node.is_a? Prism::ModuleNode
482
- module_types = const_type.types.select { _1.is_a?(KatakataIrb::Types::SingletonType) && !_1.module_or_class.is_a?(Class) }
483
- module_types << KatakataIrb::Types::MODULE if module_types.empty?
484
- else
485
- select_class_type = -> { _1.is_a?(KatakataIrb::Types::SingletonType) && _1.module_or_class.is_a?(Class) }
486
- module_types = const_type.types.select(&select_class_type)
487
- module_types += evaluate(node.superclass, scope).types.select(&select_class_type) if node.superclass
488
- module_types << KatakataIrb::Types::CLASS if module_types.empty?
489
- end
490
- return KatakataIrb::Types::NIL unless node.body
491
-
492
- table = node.locals.to_h { [_1.to_s, KatakataIrb::Types::NIL] }
493
- if parent_module.is_a?(Module) || parent_module.nil?
494
- value = parent_module.const_get name if parent_module&.const_defined?(name)
495
- unless value
496
- value_type = scope[name]
497
- value = value_type.module_or_class if value_type.is_a? KatakataIrb::Types::SingletonType
498
- end
499
-
500
- if value.is_a? Module
501
- nesting = [value, []]
502
- else
503
- if parent_module
504
- nesting = [parent_module, [name]]
505
- else
506
- parent_nesting, parent_path = scope.module_nesting.first
507
- nesting = [parent_nesting, parent_path + [name]]
508
- end
509
- nesting_key = [nesting[0].__id__, nesting[1]].join('::')
510
- nesting_value = node.is_a?(Prism::ModuleNode) ? KatakataIrb::Types::MODULE : KatakataIrb::Types::CLASS
511
- end
512
- else
513
- # parent_module == :unknown
514
- # TODO: dummy module
515
- end
516
- module_scope = KatakataIrb::Scope.new(
517
- scope,
518
- { **table, KatakataIrb::Scope::BREAK_RESULT => nil, KatakataIrb::Scope::NEXT_RESULT => nil, KatakataIrb::Scope::RETURN_RESULT => nil },
519
- trace_cvar: false,
520
- trace_ivar: false,
521
- trace_lvar: false,
522
- self_type: KatakataIrb::Types::UnionType[*module_types],
523
- nesting: nesting
524
- )
525
- module_scope[nesting_key] = nesting_value if nesting_value
526
- result = evaluate(node.body, module_scope)
527
- scope.update module_scope
528
- result
529
- when Prism::ForNode
530
- node.statements
531
- collection = evaluate node.collection, scope
532
- inner_scope = KatakataIrb::Scope.new scope, { KatakataIrb::Scope::BREAK_RESULT => nil }
533
- ary_type = simulate_call collection, :to_ary, [], nil, nil, nil, name_match: false
534
- element_types = ary_type.types.filter_map do |ary|
535
- ary.params[:Elem] if ary.is_a?(KatakataIrb::Types::InstanceType) && ary.klass == Array
536
- end
537
- element_type = KatakataIrb::Types::UnionType[*element_types]
538
- inner_scope.conditional do |s|
539
- evaluate_write node.index, element_type, s, nil
540
- evaluate node.statements, s if node.statements
541
- end
542
- inner_scope.merge_jumps
543
- scope.update inner_scope
544
- breaks = inner_scope[KatakataIrb::Scope::BREAK_RESULT]
545
- breaks ? KatakataIrb::Types::UnionType[breaks, collection] : collection
546
- when Prism::CaseNode
547
- target = evaluate(node.predicate, scope) if node.predicate
548
- # TODO
549
- branches = node.conditions.map do |condition|
550
- ->(s) { evaluate_case_match target, condition, s }
551
- end
552
- if node.consequent
553
- branches << ->(s) { evaluate node.consequent, s }
554
- elsif node.conditions.any? { _1.is_a? Prism::WhenNode }
555
- branches << ->(s) { KatakataIrb::Types::NIL }
556
- end
557
- KatakataIrb::Types::UnionType[*scope.run_branches(*branches)]
558
- when Prism::MatchRequiredNode
559
- value_type = evaluate node.value, scope
560
- evaluate_match_pattern value_type, node.pattern, scope
561
- KatakataIrb::Types::NIL # void value
562
- when Prism::MatchPredicateNode
563
- value_type = evaluate node.value, scope
564
- scope.conditional { evaluate_match_pattern value_type, node.pattern, _1 }
565
- KatakataIrb::Types::BOOLEAN
566
- when Prism::RangeNode
567
- beg_type = evaluate node.left, scope if node.left
568
- end_type = evaluate node.right, scope if node.right
569
- elem = (KatakataIrb::Types::UnionType[*[beg_type, end_type].compact]).nonnillable
570
- KatakataIrb::Types::InstanceType.new Range, Elem: elem
571
- when Prism::DefinedNode
572
- scope.conditional { evaluate node.value, _1 }
573
- KatakataIrb::Types::UnionType[KatakataIrb::Types::STRING, KatakataIrb::Types::NIL]
574
- when Prism::FlipFlopNode
575
- scope.conditional { evaluate node.left, _1 } if node.left
576
- scope.conditional { evaluate node.right, _1 } if node.right
577
- KatakataIrb::Types::BOOLEAN
578
- when Prism::MultiTargetNode
579
- # Raw MultiTargetNode, incomplete code like `a,b`, `*a`.
580
- evaluate_multi_write_receiver node, scope, nil
581
- KatakataIrb::Types::NIL
582
- when Prism::ImplicitNode
583
- evaluate node.value, scope
584
- when Prism::MatchWriteNode
585
- # /(?<a>)(?<b>)/ =~ string
586
- evaluate node.call, scope
587
- node.locals.each { scope[_1.to_s] = KatakataIrb::Types::UnionType[KatakataIrb::Types::STRING, KatakataIrb::Types::NIL] }
588
- KatakataIrb::Types::BOOLEAN
589
- when Prism::MatchLastLineNode
590
- KatakataIrb::Types::BOOLEAN
591
- when Prism::InterpolatedMatchLastLineNode
592
- node.parts.each { evaluate _1, scope }
593
- KatakataIrb::Types::BOOLEAN
594
- when Prism::PreExecutionNode, Prism::PostExecutionNode
595
- node.statements ? evaluate(node.statements, scope) : KatakataIrb::Types::NIL
596
- when Prism::AliasMethodNode, Prism::AliasGlobalVariableNode, Prism::UndefNode, Prism::MissingNode
597
- # do nothing
598
- KatakataIrb::Types::NIL
599
- else
600
- KatakataIrb.log_puts
601
- KatakataIrb.log_puts :NOMATCH
602
- KatakataIrb.log_puts node.inspect
603
- KatakataIrb::Types::NIL
604
- end
605
- end
606
-
607
- def evaluate_call_node_arguments(call_node, scope)
608
- # call_node.arguments is Prism::ArgumentsNode
609
- arguments = call_node.arguments&.arguments&.dup || []
610
- block_arg = call_node.block.expression if call_node.respond_to?(:block) && call_node.block.is_a?(Prism::BlockArgumentNode)
611
- kwargs = arguments.pop.elements if arguments.last.is_a?(Prism::KeywordHashNode)
612
- args_types = arguments.map do |arg|
613
- case arg
614
- when Prism::ForwardingArgumentsNode
615
- # `f(a, ...)` treat like splat
616
- nil
617
- when Prism::SplatNode
618
- evaluate arg.expression, scope
619
- nil # TODO: splat
620
- else
621
- evaluate arg, scope
622
- end
623
- end
624
- if kwargs
625
- kwargs_types = kwargs.map do |arg|
626
- case arg
627
- when Prism::AssocNode
628
- if arg.key.is_a?(Prism::SymbolNode)
629
- [arg.key.value, evaluate(arg.value, scope)]
630
- else
631
- evaluate arg.key, scope
632
- evaluate arg.value, scope
633
- nil
634
- end
635
- when Prism::AssocSplatNode
636
- evaluate arg.value, scope
637
- nil
638
- end
639
- end.compact.to_h
640
- end
641
- if block_arg.is_a? Prism::SymbolNode
642
- block_sym_node = block_arg
643
- elsif block_arg
644
- evaluate block_arg, scope
645
- end
646
- [args_types, kwargs_types, block_sym_node, !!block_arg]
647
- end
648
-
649
- def const_path_write(receiver, name, value, scope)
650
- if receiver # receiver::A = value
651
- singleton_type = receiver.types.find { _1.is_a? KatakataIrb::Types::SingletonType }
652
- scope.set_const singleton_type.module_or_class, name, value if singleton_type
653
- else # ::A = value
654
- scope.set_const Object, name, value
655
- end
656
- end
657
-
658
- def assign_required_parameter(node, value, scope)
659
- case node
660
- when Prism::RequiredParameterNode
661
- scope[node.name.to_s] = value || KatakataIrb::Types::OBJECT
662
- when Prism::RequiredDestructuredParameterNode
663
- values = value ? sized_splat(value, :to_ary, node.parameters.size) : []
664
- node.parameters.zip values do |n, v|
665
- assign_required_parameter n, v, scope
666
- end
667
- when Prism::SplatNode
668
- splat_value = value ? KatakataIrb::Types.array_of(value) : KatakataIrb::Types::ARRAY
669
- assign_required_parameter node.expression, splat_value, scope
670
- end
671
- end
672
-
673
- def evaluate_constant_node(node, scope)
674
- case node
675
- when Prism::ConstantPathNode
676
- name = node.child.name.to_s
677
- if node.parent
678
- receiver = evaluate node.parent, scope
679
- if receiver.is_a? KatakataIrb::Types::SingletonType
680
- parent_module = receiver.module_or_class
681
- end
682
- else
683
- parent_module = Object
684
- end
685
- if parent_module
686
- type = scope.get_const(parent_module, [name]) || KatakataIrb::Types::NIL
687
- else
688
- parent_module = :unknown
689
- type = KatakataIrb::Types::NIL
690
- end
691
- when Prism::ConstantReadNode
692
- name = node.name.to_s
693
- type = scope[name]
694
- end
695
- [type, receiver, parent_module, name]
696
- end
697
-
698
-
699
- def assign_parameters(node, scope, args, kwargs)
700
- args = args.dup
701
- kwargs = kwargs.dup
702
- size = node.requireds.size + node.optionals.size + (node.rest ? 1 : 0) + node.posts.size
703
- args = sized_splat(args.first, :to_ary, size) if size >= 2 && args.size == 1
704
- reqs = args.shift node.requireds.size
705
- if node.rest
706
- # node.rest.class is Prism::RestParameterNode
707
- posts = []
708
- opts = args.shift node.optionals.size
709
- rest = args
710
- else
711
- posts = args.pop node.posts.size
712
- opts = args
713
- rest = []
714
- end
715
- node.requireds.zip reqs do |n, v|
716
- assign_required_parameter n, v, scope
717
- end
718
- node.optionals.zip opts do |n, v|
719
- # n is Prism::OptionalParameterNode
720
- values = [v]
721
- values << evaluate(n.value, scope) if n.value
722
- scope[n.name.to_s] = KatakataIrb::Types::UnionType[*values.compact]
723
- end
724
- node.posts.zip posts do |n, v|
725
- assign_required_parameter n, v, scope
726
- end
727
- if node.rest&.name
728
- # node.rest is Prism::RestParameterNode
729
- scope[node.rest.name.to_s] = KatakataIrb::Types.array_of(*rest)
730
- end
731
- node.keywords.each do |n|
732
- # n is Prism::KeywordParameterNode
733
- name = n.name.to_s.delete(':')
734
- values = [kwargs.delete(name)]
735
- values << evaluate(n.value, scope) if n.value
736
- scope[name] = KatakataIrb::Types::UnionType[*values.compact]
737
- end
738
- # node.keyword_rest is Prism::KeywordRestParameterNode or Prism::ForwardingParameterNode or Prism::NoKeywordsParameterNode
739
- if node.keyword_rest.is_a?(Prism::KeywordRestParameterNode) && node.keyword_rest.name
740
- scope[node.keyword_rest.name.to_s] = KatakataIrb::Types::InstanceType.new(Hash, K: KatakataIrb::Types::SYMBOL, V: KatakataIrb::Types::UnionType[*kwargs.values])
741
- end
742
- if node.block&.name
743
- # node.block is Prism::BlockParameterNode
744
- scope[node.block.name.to_s] = KatakataIrb::Types::PROC
745
- end
746
- end
747
-
748
- def assign_numbered_parameters(numbered_parameters, scope, args, _kwargs)
749
- return if numbered_parameters.empty?
750
- max_num = numbered_parameters.map { _1[1].to_i }.max
751
- if max_num == 1
752
- if args.size == 0
753
- scope['_1'] = KatakataIrb::Types::NIL
754
- elsif args.size == 1
755
- scope['_1'] = args.first
756
- else
757
- scope['_1'] = KatakataIrb::Types.array_of(*args)
758
- end
759
- else
760
- args = sized_splat(args.first, :to_ary, max_num) if args.size == 1
761
- numbered_parameters.each do |name|
762
- index = name[1].to_i - 1
763
- scope[name] = args[index] || KatakataIrb::Types::NIL
764
- end
765
- end
766
- end
767
-
768
- def evaluate_case_match(target, node, scope)
769
- case node
770
- when Prism::WhenNode
771
- node.conditions.each { evaluate _1, scope }
772
- node.statements ? evaluate(node.statements, scope) : KatakataIrb::Types::NIL
773
- when Prism::InNode
774
- pattern = node.pattern
775
- if pattern in Prism::IfNode | Prism::UnlessNode
776
- cond_node = pattern.predicate
777
- pattern = pattern.statements.body.first
778
- end
779
- evaluate_match_pattern(target, pattern, scope)
780
- evaluate cond_node, scope if cond_node # TODO: conditional branch
781
- node.statements ? evaluate(node.statements, scope) : KatakataIrb::Types::NIL
782
- end
783
- end
784
-
785
- def evaluate_match_pattern(value, pattern, scope)
786
- # TODO: scope.terminate_with KatakataIrb::Scope::PATTERNMATCH_BREAK, KatakataIrb::Types::NIL
787
- case pattern
788
- when Prism::FindPatternNode
789
- # TODO
790
- evaluate_match_pattern KatakataIrb::Types::OBJECT, pattern.left, scope
791
- pattern.requireds.each { evaluate_match_pattern KatakataIrb::Types::OBJECT, _1, scope }
792
- evaluate_match_pattern KatakataIrb::Types::OBJECT, pattern.right, scope
793
- when Prism::ArrayPatternNode
794
- # TODO
795
- pattern.requireds.each { evaluate_match_pattern KatakataIrb::Types::OBJECT, _1, scope }
796
- evaluate_match_pattern KatakataIrb::Types::OBJECT, pattern.rest, scope if pattern.rest
797
- pattern.posts.each { evaluate_match_pattern KatakataIrb::Types::OBJECT, _1, scope }
798
- KatakataIrb::Types::ARRAY
799
- when Prism::HashPatternNode
800
- # TODO
801
- pattern.assocs.each { evaluate_match_pattern KatakataIrb::Types::OBJECT, _1, scope }
802
- KatakataIrb::Types::HASH
803
- when Prism::AssocNode
804
- evaluate_match_pattern value, pattern.value, scope if pattern.value
805
- KatakataIrb::Types::OBJECT
806
- when Prism::AssocSplatNode
807
- # TODO
808
- evaluate_match_pattern KatakataIrb::Types::HASH, pattern.value, scope
809
- KatakataIrb::Types::OBJECT
810
- when Prism::PinnedVariableNode
811
- evaluate pattern.variable, scope
812
- when Prism::PinnedExpressionNode
813
- evaluate pattern.expression, scope
814
- when Prism::LocalVariableTargetNode
815
- scope[pattern.name.to_s] = value
816
- when Prism::AlternationPatternNode
817
- KatakataIrb::Types::UnionType[evaluate_match_pattern(value, pattern.left, scope), evaluate_match_pattern(value, pattern.right, scope)]
818
- when Prism::CapturePatternNode
819
- capture_type = class_or_value_to_instance evaluate_match_pattern(value, pattern.value, scope)
820
- value = capture_type unless capture_type.types.empty? || capture_type.types == [KatakataIrb::Types::OBJECT]
821
- evaluate_match_pattern value, pattern.target, scope
822
- when Prism::SplatNode
823
- value = KatakataIrb::Types.array_of value
824
- evaluate_match_pattern value, pattern.expression, scope if pattern.expression
825
- value
826
- else
827
- # literal node
828
- type = evaluate(pattern, scope)
829
- class_or_value_to_instance(type)
830
- end
831
- end
832
-
833
- def class_or_value_to_instance(type)
834
- instance_types = type.types.map do |t|
835
- t.is_a?(KatakataIrb::Types::SingletonType) ? KatakataIrb::Types::InstanceType.new(t.module_or_class) : t
836
- end
837
- KatakataIrb::Types::UnionType[*instance_types]
838
- end
839
-
840
- def evaluate_write(node, value, scope, evaluated_receivers)
841
- case node
842
- when Prism::MultiTargetNode
843
- evaluate_multi_write node, value, scope, evaluated_receivers
844
- when Prism::CallNode
845
- evaluated_receivers&.[](node.receiver) || evaluate(node.receiver, scope) if node.receiver
846
- when Prism::SplatNode
847
- evaluate_write node.expression, KatakataIrb::Types.array_of(value), scope, evaluated_receivers
848
- when Prism::LocalVariableTargetNode, Prism::GlobalVariableTargetNode, Prism::InstanceVariableTargetNode, Prism::ClassVariableTargetNode, Prism::ConstantTargetNode
849
- scope[node.name.to_s] = value
850
- when Prism::ConstantPathTargetNode
851
- receiver = evaluated_receivers&.[](node.parent) || evaluate(node.parent, scope) if node.parent
852
- const_path_write receiver, node.child.name.to_s, value, scope
853
- value
854
- end
855
- end
856
-
857
- def evaluate_multi_write(node, values, scope, evaluated_receivers)
858
- values = sized_splat values, :to_ary, node.targets.size unless values.is_a? Array
859
- splat_index = node.targets.find_index { _1.is_a? Prism::SplatNode }
860
- if splat_index
861
- pre_targets = node.targets[0...splat_index]
862
- splat_target = node.targets[splat_index]
863
- post_targets = node.targets[splat_index + 1..]
864
- pre_values = values.shift pre_targets.size
865
- post_values = values.pop post_targets.size
866
- splat_value = KatakataIrb::Types::UnionType[*values]
867
- zips = pre_targets.zip(pre_values) + [[splat_target, splat_value]] + post_targets.zip(post_values)
868
- else
869
- zips = node.targets.zip(values)
870
- end
871
- zips.each do |target, value|
872
- evaluate_write target, value || KatakataIrb::Types::NIL, scope, evaluated_receivers
873
- end
874
- end
875
-
876
- def evaluate_multi_write_receiver(node, scope, evaluated_receivers)
877
- case node
878
- when Prism::MultiWriteNode, Prism::MultiTargetNode
879
- node.targets.each { evaluate_multi_write_receiver _1, scope, evaluated_receivers }
880
- when Prism::CallNode
881
- if node.receiver
882
- receiver = evaluate(node.receiver, scope)
883
- evaluated_receivers[node.receiver] = receiver if evaluated_receivers
884
- end
885
- if node.arguments
886
- node.arguments.arguments&.each do |arg|
887
- if arg.is_a? Prism::SplatNode
888
- evaluate arg.expression, scope
889
- else
890
- evaluate arg, scope
891
- end
892
- end
893
- end
894
- when Prism::SplatNode
895
- evaluate_multi_write_receiver node.expression, scope, evaluated_receivers if node.expression
896
- end
897
- end
898
-
899
- def evaluate_list_splat_items(list, scope)
900
- items = list.flat_map do |node|
901
- if node.is_a? Prism::SplatNode
902
- splat = evaluate node.expression, scope
903
- array_elem, non_array = partition_to_array splat.nonnillable, :to_a
904
- [*array_elem, *non_array]
905
- else
906
- evaluate node, scope
907
- end
908
- end.uniq
909
- KatakataIrb::Types::UnionType[*items]
910
- end
911
-
912
- def sized_splat(value, method, size)
913
- array_elem, non_array = partition_to_array value, method
914
- values = [KatakataIrb::Types::UnionType[*array_elem, *non_array]]
915
- values += [array_elem] * (size - 1) if array_elem && size >= 1
916
- values
917
- end
918
-
919
- def partition_to_array(value, method)
920
- arrays, non_arrays = value.types.partition { _1.is_a?(KatakataIrb::Types::InstanceType) && _1.klass == Array }
921
- non_arrays.select! do |type|
922
- to_array_result = simulate_call type, method, [], nil, nil, nil, name_match: false
923
- if to_array_result.is_a?(KatakataIrb::Types::InstanceType) && to_array_result.klass == Array
924
- arrays << to_array_result
925
- false
926
- else
927
- true
928
- end
929
- end
930
- array_elem = arrays.empty? ? nil : KatakataIrb::Types::UnionType[*arrays.map { _1.params[:Elem] || KatakataIrb::Types::OBJECT }]
931
- non_array = non_arrays.empty? ? nil : KatakataIrb::Types::UnionType[*non_arrays]
932
- [array_elem, non_array]
933
- end
934
-
935
- def simulate_call(receiver, method_name, args, kwargs, block, scope, name_match: true)
936
- methods = KatakataIrb::Types.rbs_methods receiver, method_name.to_sym, args, kwargs, !!block
937
- block_called = false
938
- type_breaks = methods.map do |method, given_params, method_params|
939
- receiver_vars = (receiver in KatakataIrb::Types::InstanceType) ? receiver.params : {}
940
- free_vars = method.type.free_variables - receiver_vars.keys.to_set
941
- vars = receiver_vars.merge KatakataIrb::Types.match_free_variables(free_vars, method_params, given_params)
942
- if block && method.block
943
- params_type = method.block.type.required_positionals.map do |func_param|
944
- KatakataIrb::Types.from_rbs_type func_param.type, receiver, vars
945
- end
946
- self_type = KatakataIrb::Types.from_rbs_type method.block.self_type, receiver, vars if method.block.self_type
947
- block_response, breaks = block.call params_type, self_type
948
- block_called = true
949
- vars.merge! KatakataIrb::Types.match_free_variables(free_vars - vars.keys.to_set, [method.block.type.return_type], [block_response])
950
- end
951
- if KatakataIrb::Types.method_return_bottom?(method)
952
- [nil, breaks]
953
- else
954
- [KatakataIrb::Types.from_rbs_type(method.type.return_type, receiver, vars || {}), breaks]
955
- end
956
- end
957
- block&.call [], nil unless block_called
958
- terminates = !type_breaks.empty? && type_breaks.map(&:first).all?(&:nil?)
959
- types = type_breaks.map(&:first).compact
960
- breaks = type_breaks.map(&:last).compact
961
- types << OBJECT_METHODS[method_name.to_sym] if name_match && OBJECT_METHODS.has_key?(method_name.to_sym)
962
-
963
- if method_name.to_sym == :new
964
- receiver.types.each do |type|
965
- if (type in KatakataIrb::Types::SingletonType) && type.module_or_class.is_a?(Class)
966
- types << KatakataIrb::Types::InstanceType.new(type.module_or_class)
967
- end
968
- end
969
- end
970
- scope&.terminate if terminates && breaks.empty?
971
- KatakataIrb::Types::UnionType[*types, *breaks]
972
- end
973
-
974
- def evaluate_program(program, scope)
975
- # statements.body[0] is local variable assign code
976
- program.statements.body[1..].each do |statement|
977
- evaluate statement, scope
978
- end
979
- end
980
-
981
- def self.calculate_target_type_scope(binding, parents, target)
982
- dig_targets = DigTarget.new(parents, target) do |type, scope|
983
- return type, scope
984
- end
985
- program = parents.first
986
- scope = KatakataIrb::Scope.from_binding(binding, program.locals)
987
- new(dig_targets).evaluate_program program, scope
988
- [KatakataIrb::Types::NIL, scope]
989
- end
990
- end