katakata_irb 0.2.0 → 0.2.2

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,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