steep 0.43.1 → 0.46.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (109) hide show
  1. checksums.yaml +4 -4
  2. data/.github/dependabot.yml +8 -0
  3. data/.github/workflows/ruby.yml +4 -2
  4. data/.gitignore +0 -1
  5. data/CHANGELOG.md +41 -0
  6. data/Gemfile +0 -1
  7. data/Gemfile.lock +77 -0
  8. data/bin/output_test.rb +8 -2
  9. data/lib/steep/ast/builtin.rb +7 -1
  10. data/lib/steep/ast/types/factory.rb +19 -25
  11. data/lib/steep/cli.rb +7 -1
  12. data/lib/steep/diagnostic/lsp_formatter.rb +59 -6
  13. data/lib/steep/diagnostic/ruby.rb +188 -60
  14. data/lib/steep/diagnostic/signature.rb +34 -0
  15. data/lib/steep/drivers/check.rb +3 -0
  16. data/lib/steep/drivers/init.rb +10 -3
  17. data/lib/steep/drivers/utils/driver_helper.rb +15 -0
  18. data/lib/steep/drivers/validate.rb +1 -1
  19. data/lib/steep/drivers/watch.rb +3 -0
  20. data/lib/steep/equatable.rb +21 -0
  21. data/lib/steep/index/source_index.rb +55 -5
  22. data/lib/steep/interface/block.rb +4 -0
  23. data/lib/steep/interface/function.rb +798 -579
  24. data/lib/steep/project/dsl.rb +105 -33
  25. data/lib/steep/project/options.rb +12 -53
  26. data/lib/steep/project/target.rb +21 -8
  27. data/lib/steep/server/interaction_worker.rb +239 -20
  28. data/lib/steep/server/master.rb +22 -1
  29. data/lib/steep/server/type_check_worker.rb +74 -9
  30. data/lib/steep/services/file_loader.rb +26 -19
  31. data/lib/steep/services/goto_service.rb +322 -0
  32. data/lib/steep/services/hover_content.rb +132 -80
  33. data/lib/steep/services/type_check_service.rb +25 -0
  34. data/lib/steep/source.rb +7 -10
  35. data/lib/steep/type_construction.rb +496 -518
  36. data/lib/steep/type_inference/block_params.rb +2 -5
  37. data/lib/steep/type_inference/method_params.rb +483 -0
  38. data/lib/steep/type_inference/send_args.rb +610 -128
  39. data/lib/steep/typing.rb +46 -21
  40. data/lib/steep/version.rb +1 -1
  41. data/lib/steep.rb +4 -1
  42. data/sample/Steepfile +10 -3
  43. data/sig/steep/type_inference/send_args.rbs +42 -0
  44. data/smoke/alias/Steepfile +2 -1
  45. data/smoke/and/Steepfile +2 -1
  46. data/smoke/array/Steepfile +2 -1
  47. data/smoke/array/test_expectations.yml +3 -3
  48. data/smoke/block/Steepfile +2 -2
  49. data/smoke/block/c.rb +0 -1
  50. data/smoke/case/Steepfile +2 -1
  51. data/smoke/class/Steepfile +2 -1
  52. data/smoke/class/test_expectations.yml +12 -15
  53. data/smoke/const/Steepfile +2 -1
  54. data/smoke/const/test_expectations.yml +0 -10
  55. data/smoke/diagnostics/Steepfile +2 -1
  56. data/smoke/diagnostics/a.rbs +0 -4
  57. data/smoke/diagnostics/different_method_parameter_kind.rb +9 -0
  58. data/smoke/diagnostics/method_arity_mismatch.rb +2 -2
  59. data/smoke/diagnostics/method_parameter_mismatch.rb +10 -0
  60. data/smoke/diagnostics/test_expectations.yml +108 -57
  61. data/smoke/diagnostics-rbs/Steepfile +1 -1
  62. data/smoke/diagnostics-rbs/mixin-class-error.rbs +6 -0
  63. data/smoke/diagnostics-rbs/test_expectations.yml +12 -0
  64. data/smoke/diagnostics-rbs-duplicated/Steepfile +2 -1
  65. data/smoke/diagnostics-ruby-unsat/Steepfile +6 -0
  66. data/smoke/diagnostics-ruby-unsat/a.rbs +3 -0
  67. data/smoke/diagnostics-ruby-unsat/test_expectations.yml +27 -0
  68. data/smoke/{diagnostics → diagnostics-ruby-unsat}/unsatisfiable_constraint.rb +0 -1
  69. data/smoke/dstr/Steepfile +2 -1
  70. data/smoke/ensure/Steepfile +2 -1
  71. data/smoke/ensure/test_expectations.yml +3 -3
  72. data/smoke/enumerator/Steepfile +2 -1
  73. data/smoke/enumerator/test_expectations.yml +1 -1
  74. data/smoke/extension/Steepfile +2 -1
  75. data/smoke/hash/Steepfile +2 -1
  76. data/smoke/hello/Steepfile +2 -1
  77. data/smoke/if/Steepfile +2 -1
  78. data/smoke/implements/Steepfile +2 -1
  79. data/smoke/initialize/Steepfile +2 -1
  80. data/smoke/integer/Steepfile +2 -1
  81. data/smoke/interface/Steepfile +2 -1
  82. data/smoke/kwbegin/Steepfile +2 -1
  83. data/smoke/lambda/Steepfile +2 -1
  84. data/smoke/literal/Steepfile +2 -1
  85. data/smoke/literal/test_expectations.yml +2 -2
  86. data/smoke/map/Steepfile +2 -1
  87. data/smoke/method/Steepfile +2 -1
  88. data/smoke/method/test_expectations.yml +11 -10
  89. data/smoke/module/Steepfile +2 -1
  90. data/smoke/regexp/Steepfile +2 -1
  91. data/smoke/regression/Steepfile +2 -1
  92. data/smoke/regression/issue_372.rb +8 -0
  93. data/smoke/regression/issue_372.rbs +4 -0
  94. data/smoke/regression/test_expectations.yml +0 -12
  95. data/smoke/rescue/Steepfile +2 -1
  96. data/smoke/rescue/test_expectations.yml +3 -3
  97. data/smoke/self/Steepfile +2 -1
  98. data/smoke/skip/Steepfile +2 -1
  99. data/smoke/stdout/Steepfile +2 -1
  100. data/smoke/super/Steepfile +2 -1
  101. data/smoke/toplevel/Steepfile +2 -1
  102. data/smoke/toplevel/test_expectations.yml +3 -3
  103. data/smoke/tsort/Steepfile +4 -5
  104. data/smoke/tsort/test_expectations.yml +2 -2
  105. data/smoke/type_case/Steepfile +2 -1
  106. data/smoke/unexpected/Steepfile +2 -1
  107. data/smoke/yield/Steepfile +2 -1
  108. data/steep.gemspec +2 -2
  109. metadata +24 -10
@@ -1,194 +1,676 @@
1
1
  module Steep
2
2
  module TypeInference
3
3
  class SendArgs
4
- attr_reader :args
5
- attr_reader :block_pass_arg
4
+ class PositionalArgs
5
+ class NodeParamPair
6
+ attr_reader :node
7
+ attr_reader :param
6
8
 
7
- def initialize(args:, block_pass_arg:)
8
- @args = args
9
- @block_pass_arg = block_pass_arg
10
- end
9
+ def initialize(node:, param:)
10
+ @node = node
11
+ @param = param
12
+ end
13
+
14
+ include Equatable
11
15
 
12
- def self.from_nodes(nodes)
13
- nodes = nodes.dup
16
+ def to_ary
17
+ [node, param]
18
+ end
19
+ end
14
20
 
15
- args = []
16
- block_pass_arg = nil
21
+ class NodeTypePair
22
+ attr_reader :node
23
+ attr_reader :type
17
24
 
18
- if nodes.last&.type == :block_pass
19
- block_pass_arg = nodes.pop
25
+ def initialize(node:, type:)
26
+ @node = node
27
+ @type = type
28
+ end
29
+
30
+ include Equatable
31
+
32
+ def node_type
33
+ case node.type
34
+ when :splat
35
+ AST::Builtin::Array.instance_type(type)
36
+ else
37
+ type
38
+ end
39
+ end
20
40
  end
21
41
 
22
- nodes.each do |node|
23
- args << node
42
+ class SplatArg
43
+ attr_reader :node
44
+ attr_accessor :type
45
+
46
+ def initialize(node:)
47
+ @node = node
48
+ @type = nil
49
+ end
50
+
51
+ include Equatable
24
52
  end
25
53
 
26
- new(args: args, block_pass_arg: block_pass_arg)
27
- end
54
+ class UnexpectedArg
55
+ attr_reader :node
28
56
 
29
- def drop_first
30
- raise "Cannot drop first from empty args" if args.empty?
31
- self.class.new(args: args.drop(1), block_pass_arg: block_pass_arg)
32
- end
57
+ def initialize(node:)
58
+ @node = node
59
+ end
33
60
 
34
- def drop_last
35
- raise "Cannot drop last from empty args" if args.empty?
36
- self.class.new(args: args.take(args.size - 1), block_pass_arg: block_pass_arg)
37
- end
61
+ include Equatable
62
+ end
38
63
 
39
- def each_keyword_arg
40
- if block_given?
41
- if kw_args
42
- kw_args.children.each do |node|
43
- if node.type == :pair
44
- yield node
45
- end
46
- end
64
+ class MissingArg
65
+ attr_reader :params
66
+
67
+ def initialize(params:)
68
+ @params = params
47
69
  end
48
- else
49
- enum_for :each_keyword_arg
70
+
71
+ include Equatable
50
72
  end
51
- end
52
73
 
53
- def kwsplat_nodes
54
- if kw_args
55
- kw_args.children.select do |node|
56
- node.type == :kwsplat
74
+ attr_reader :args
75
+ attr_reader :index
76
+ attr_reader :positional_params
77
+ attr_reader :uniform
78
+
79
+ def initialize(args:, index:, positional_params:, uniform: false)
80
+ @args = args
81
+ @index = index
82
+ @positional_params = positional_params
83
+ @uniform = uniform
84
+ end
85
+
86
+ def node
87
+ args[index]
88
+ end
89
+
90
+ def following_args
91
+ args[index..]
92
+ end
93
+
94
+ def param
95
+ positional_params&.head
96
+ end
97
+
98
+ def update(index: self.index, positional_params: self.positional_params, uniform: self.uniform)
99
+ PositionalArgs.new(args: args, index: index, positional_params: positional_params, uniform: uniform)
100
+ end
101
+
102
+ def uniform!
103
+ update(uniform: true)
104
+ end
105
+
106
+ def next()
107
+ if uniform
108
+ if node
109
+ return [node, uniform_type, update(index: index+1)]
110
+ else
111
+ return
112
+ end
113
+ end
114
+
115
+ case
116
+ when !node && param.is_a?(Interface::Function::Params::PositionalParams::Required)
117
+ [
118
+ MissingArg.new(params: positional_params),
119
+ update(index: index, positional_params: nil)
120
+ ]
121
+ when !node && param.is_a?(Interface::Function::Params::PositionalParams::Optional)
122
+ nil
123
+ when !node && param.is_a?(Interface::Function::Params::PositionalParams::Rest)
124
+ nil
125
+ when !node && !param
126
+ nil
127
+ when node && node.type != :splat && param.is_a?(Interface::Function::Params::PositionalParams::Required)
128
+ [
129
+ NodeParamPair.new(node: node, param: param),
130
+ update(index: index+1, positional_params: positional_params.tail)
131
+ ]
132
+ when node && node.type != :splat && param.is_a?(Interface::Function::Params::PositionalParams::Optional)
133
+ [
134
+ NodeParamPair.new(node: node, param: param),
135
+ update(index: index+1, positional_params: positional_params.tail)
136
+ ]
137
+ when node && node.type != :splat && param.is_a?(Interface::Function::Params::PositionalParams::Rest)
138
+ [
139
+ NodeParamPair.new(node: node, param: param),
140
+ update(index: index+1)
141
+ ]
142
+ when node && node.type != :splat && !param
143
+ [
144
+ UnexpectedArg.new(node: node),
145
+ update(index: index + 1)
146
+ ]
147
+ when node && node.type == :splat
148
+ [
149
+ SplatArg.new(node: node),
150
+ self
151
+ ]
57
152
  end
58
- else
59
- []
60
153
  end
61
- end
62
154
 
63
- def zips(params, block_type)
64
- zip0(params, block_type).map do |pairs|
65
- group_pairs(pairs)
155
+ def uniform_type
156
+ if positional_params.each.any? {|param| param.is_a?(Interface::Function::Params::PositionalParams::Rest) }
157
+ AST::Types::Intersection.build(types: positional_params.each.map(&:type))
158
+ end
66
159
  end
67
- end
68
160
 
69
- def group_pairs(pairs)
70
- types = pairs.each_with_object({}) do |pair, hash|
71
- case pair
72
- when Array
73
- node, type = pair
74
- hash[node.__id__] ||= [node]
75
- hash[node.__id__] << type
161
+ def consume(n, node:)
162
+ ps = []
163
+ params = consume0(n, node: node, params: positional_params, ps: ps)
164
+ case params
165
+ when UnexpectedArg
166
+ [
167
+ params,
168
+ update(index: index+1, positional_params: nil)
169
+ ]
76
170
  else
77
- hash[node.__id__] = pair
171
+ [ps, update(index: index+1, positional_params: params)]
78
172
  end
79
173
  end
80
174
 
81
- types.map do |_, array|
82
- case array
83
- when Array
84
- node, *types_ = array
85
- [node, AST::Types::Intersection.build(types: types_)]
175
+ def consume0(n, node:, params:, ps:)
176
+ case n
177
+ when 0
178
+ params
86
179
  else
87
- array
180
+ head = params&.head
181
+ case head
182
+ when nil
183
+ UnexpectedArg.new(node: node)
184
+ when Interface::Function::Params::PositionalParams::Required, Interface::Function::Params::PositionalParams::Optional
185
+ ps << head
186
+ consume0(n-1, node: node, params: params.tail, ps: ps)
187
+ when Interface::Function::Params::PositionalParams::Rest
188
+ ps << head
189
+ consume0(n-1, node: node, params: params, ps: ps)
190
+ end
88
191
  end
89
192
  end
90
193
  end
91
194
 
92
- def add_pair(pairs, pair)
93
- pairs.map do |ps|
94
- if block_given?
95
- yield ps, pair
96
- else
97
- [pair] + ps
195
+ class KeywordArgs
196
+ class ArgTypePairs
197
+ attr_reader :pairs
198
+
199
+ def initialize(pairs:)
200
+ @pairs = pairs
201
+ end
202
+
203
+ include Equatable
204
+
205
+ def [](index)
206
+ pairs[index]
207
+ end
208
+
209
+ def size
210
+ pairs.size
98
211
  end
99
212
  end
100
- end
101
213
 
102
- def zip0(params, block_type)
103
- case
104
- when params.empty? && args.empty?
105
- [[]]
214
+ class SplatArg
215
+ attr_reader :node
216
+ attr_accessor :type
106
217
 
107
- when params.required.any?
108
- if args.any?
109
- first_arg = args[0]
218
+ def initialize(node:)
219
+ @node = node
220
+ @type = nil
221
+ end
110
222
 
111
- case first_arg.type
112
- when :splat
113
- []
114
- else
115
- rest = drop_first.zip0(params.drop_first, block_type)
116
- pair = [first_arg, params.required[0]]
223
+ include Equatable
224
+ end
225
+
226
+ class UnexpectedKeyword
227
+ attr_reader :keyword
228
+ attr_reader :node
229
+
230
+ include Equatable
231
+
232
+ def initialize(keyword:, node:)
233
+ @keyword = keyword
234
+ @node = node
235
+ end
117
236
 
118
- add_pair(rest, pair)
237
+ def key_node
238
+ if node.type == :pair
239
+ node.children[0]
240
+ end
241
+ end
242
+
243
+ def value_node
244
+ if node.type == :pair
245
+ node.children[1]
119
246
  end
120
- else
121
- []
122
247
  end
248
+ end
249
+
250
+ class MissingKeyword
251
+ attr_reader :keywords
123
252
 
124
- when params.has_keywords? && params.required_keywords.any?
125
- if args.any?
126
- rest = drop_last.zip0(params.without_keywords, block_type)
127
- last_arg = args.last
253
+ include Equatable
128
254
 
129
- return [] if last_arg.type == :splat
255
+ def initialize(keywords:)
256
+ @keywords = keywords
257
+ end
258
+ end
259
+
260
+ attr_reader :kwarg_nodes
261
+ attr_reader :keyword_params
262
+ attr_reader :index
263
+ attr_reader :consumed_keywords
264
+
265
+ def initialize(kwarg_nodes:, keyword_params:, index: 0, consumed_keywords: Set[])
266
+ @kwarg_nodes = kwarg_nodes
267
+ @keyword_params = keyword_params
268
+ @index = index
269
+ @consumed_keywords = consumed_keywords
270
+ end
271
+
272
+ def update(index: self.index, consumed_keywords: self.consumed_keywords)
273
+ KeywordArgs.new(
274
+ kwarg_nodes: kwarg_nodes,
275
+ keyword_params: keyword_params,
276
+ index: index,
277
+ consumed_keywords: consumed_keywords
278
+ )
279
+ end
280
+
281
+ def keyword_pair
282
+ kwarg_nodes[index]
283
+ end
284
+
285
+ def required_keywords
286
+ keyword_params.requireds
287
+ end
288
+
289
+ def optional_keywords
290
+ keyword_params.optionals
291
+ end
292
+
293
+ def rest_type
294
+ keyword_params.rest
295
+ end
130
296
 
131
- add_pair(rest, last_arg) do |ps, p|
132
- ps + [p]
297
+ def keyword_type(key)
298
+ required_keywords[key] || optional_keywords[key]
299
+ end
300
+
301
+ def all_keys
302
+ keys = Set.new
303
+ keys.merge(required_keywords.each_key)
304
+ keys.merge(optional_keywords.each_key)
305
+ keys.sort_by(&:to_s).to_a
306
+ end
307
+
308
+ def all_values
309
+ keys = Set.new
310
+ keys.merge(required_keywords.each_value)
311
+ keys.merge(optional_keywords.each_value)
312
+ keys.sort_by(&:to_s).to_a
313
+ end
314
+
315
+ def possible_key_type
316
+ key_types = all_keys.map {|key| AST::Types::Literal.new(value: key) }
317
+ key_types << AST::Builtin::Symbol.instance_type if rest_type
318
+
319
+ AST::Types::Union.build(types: key_types)
320
+ end
321
+
322
+ def possible_value_type
323
+ value_types = all_values
324
+ value_types << rest_type if rest_type
325
+
326
+ AST::Types::Intersection.build(types: value_types)
327
+ end
328
+
329
+ def next()
330
+ node = keyword_pair
331
+
332
+ if node
333
+ case node.type
334
+ when :pair
335
+ key_node, value_node = node.children
336
+
337
+ if key_node.type == :sym
338
+ key = key_node.children[0]
339
+
340
+ case
341
+ when value_type = keyword_type(key)
342
+ [
343
+ ArgTypePairs.new(
344
+ pairs: [
345
+ [key_node, AST::Types::Literal.new(value: key)],
346
+ [value_node, value_type]
347
+ ]
348
+ ),
349
+ update(
350
+ index: index+1,
351
+ consumed_keywords: consumed_keywords + [key]
352
+ )
353
+ ]
354
+ when value_type = rest_type
355
+ [
356
+ ArgTypePairs.new(
357
+ pairs: [
358
+ [key_node, AST::Builtin::Symbol.instance_type],
359
+ [value_node, value_type]
360
+ ]
361
+ ),
362
+ update(
363
+ index: index+1,
364
+ consumed_keywords: consumed_keywords + [key]
365
+ )
366
+ ]
367
+ else
368
+ [
369
+ UnexpectedKeyword.new(keyword: key, node: node),
370
+ update(index: index+1)
371
+ ]
372
+ end
373
+ else
374
+ if !all_keys.empty? || rest_type
375
+ [
376
+ ArgTypePairs.new(
377
+ pairs: [
378
+ [key_node, possible_key_type],
379
+ [value_node, possible_value_type]
380
+ ]
381
+ ),
382
+ update(index: index+1)
383
+ ]
384
+ else
385
+ [
386
+ UnexpectedKeyword.new(keyword: nil, node: node),
387
+ update(index: index+1)
388
+ ]
389
+ end
390
+ end
391
+ when :kwsplat
392
+ [
393
+ SplatArg.new(node: node),
394
+ self
395
+ ]
133
396
  end
134
397
  else
135
- []
398
+ left = Set.new(required_keywords.keys) - consumed_keywords
399
+ unless left.empty?
400
+ [
401
+ MissingKeyword.new(keywords: left),
402
+ update(consumed_keywords: consumed_keywords + left)
403
+ ]
404
+ end
136
405
  end
406
+ end
137
407
 
138
- when params.has_keywords? && params.required_keywords.empty?
139
- if args.any?
140
- rest = drop_last.zip0(params.without_keywords, block_type)
141
- last_arg = args.last
408
+ def consume_keys(keys, node:)
409
+ consumed_keys = []
410
+ types = []
142
411
 
143
- no_keyword = zip0(params.without_keywords, block_type)
412
+ unexpected_keyword = nil
144
413
 
145
- if last_arg.type == :splat
146
- no_keyword
414
+ keys.each do |key|
415
+ case
416
+ when type = keyword_type(key)
417
+ consumed_keys << key
418
+ types << type
419
+ when rest_type
420
+ types << rest_type
147
421
  else
148
- add_pair(rest, last_arg) do |ps, p|
149
- ps + [p]
150
- end + no_keyword
422
+ unexpected_keyword = key
151
423
  end
424
+ end
425
+
426
+ [
427
+ if unexpected_keyword
428
+ UnexpectedKeyword.new(keyword: unexpected_keyword, node: node)
429
+ else
430
+ types
431
+ end,
432
+ update(index: index + 1, consumed_keywords: consumed_keywords + consumed_keys)
433
+ ]
434
+ end
435
+ end
436
+
437
+ class BlockPassArg
438
+ attr_reader :node
439
+ attr_reader :block
440
+
441
+ def initialize(node:, block:)
442
+ @node = node
443
+ @block = block
444
+ end
445
+
446
+ include Equatable
447
+
448
+ def no_block?
449
+ !node && !block
450
+ end
451
+
452
+ def compatible?
453
+ if node
454
+ block ? true : false
152
455
  else
153
- zip0(params.without_keywords, block_type)
456
+ !block || block.optional?
154
457
  end
458
+ end
155
459
 
156
- when params.optional.any?
157
- if args.any?
158
- first_arg = args[0]
460
+ def block_missing?
461
+ !node && block&.required?
462
+ end
159
463
 
160
- case first_arg.type
161
- when :splat
162
- rest = zip0(params.drop_first, block_type)
163
- pair = [args[0], AST::Builtin::Array.instance_type(params.optional[0])]
164
- else
165
- rest = drop_first.zip0(params.drop_first, block_type)
166
- pair = [args[0], params.optional[0]]
464
+ def unexpected_block?
465
+ node && !block
466
+ end
467
+
468
+ def pair
469
+ raise unless compatible?
470
+
471
+ if node && block
472
+ [
473
+ node,
474
+ block.type
475
+ ]
476
+ end
477
+ end
478
+
479
+ def node_type
480
+ type = AST::Types::Proc.new(type: block.type, block: nil)
481
+
482
+ if block.optional?
483
+ type = AST::Types::Union.build(types: [type, AST::Builtin.nil_type])
484
+ end
485
+
486
+ type
487
+ end
488
+ end
489
+
490
+ attr_reader :node
491
+ attr_reader :arguments
492
+ attr_reader :method_type
493
+ attr_reader :method_name
494
+
495
+ def initialize(node:, arguments:, method_name:, method_type:)
496
+ @node = node
497
+ @arguments = arguments
498
+ @method_type = method_type
499
+ @method_name = method_name
500
+ end
501
+
502
+ def positional_params
503
+ method_type.type.params.positional_params
504
+ end
505
+
506
+ def keyword_params
507
+ method_type.type.params.keyword_params
508
+ end
509
+
510
+ def kwargs_node
511
+ unless keyword_params.empty?
512
+ arguments.find {|node| node.type == :kwargs }
513
+ end
514
+ end
515
+
516
+ def positional_arg
517
+ args = if keyword_params.empty?
518
+ arguments.take_while {|node| node.type != :block_pass }
519
+ else
520
+ arguments.take_while {|node| node.type != :kwargs && node.type != :block_pass }
521
+ end
522
+ PositionalArgs.new(args: args, index: 0, positional_params: positional_params)
523
+ end
524
+
525
+ def keyword_args
526
+ KeywordArgs.new(
527
+ kwarg_nodes: kwargs_node&.children || [],
528
+ keyword_params: keyword_params
529
+ )
530
+ end
531
+
532
+ def block_pass_arg
533
+ node = arguments.find {|node| node.type == :block_pass }
534
+ block = method_type.block
535
+
536
+ BlockPassArg.new(node: node, block: block)
537
+ end
538
+
539
+ def each
540
+ if block_given?
541
+ errors = []
542
+ positional_count = 0
543
+
544
+ positional_arg.tap do |args|
545
+ while (value, args = args.next())
546
+ yield value
547
+
548
+ case value
549
+ when PositionalArgs::SplatArg
550
+ type = value.type
551
+
552
+ case type
553
+ when nil
554
+ raise
555
+ when AST::Types::Tuple
556
+ ts, args = args.consume(type.types.size, node: value.node)
557
+
558
+ case ts
559
+ when Array
560
+ ty = AST::Types::Tuple.new(types: ts.map(&:type))
561
+ yield PositionalArgs::NodeTypePair.new(node: value.node, type: ty)
562
+ when PositionalArgs::UnexpectedArg
563
+ errors << ts
564
+ yield ts
565
+ end
566
+ else
567
+ if t = args.uniform_type
568
+ args.following_args.each do |node|
569
+ yield PositionalArgs::NodeTypePair.new(node: node, type: t)
570
+ end
571
+ else
572
+ args.following_args.each do |node|
573
+ arg = PositionalArgs::UnexpectedArg.new(node: node)
574
+ yield arg
575
+ errors << arg
576
+ end
577
+ end
578
+
579
+ break
580
+ end
581
+ when PositionalArgs::UnexpectedArg, PositionalArgs::MissingArg
582
+ errors << value
583
+ end
167
584
  end
585
+ end
168
586
 
169
- add_pair(rest, pair)
170
- else
171
- zip0(params.drop_first, block_type)
587
+ keyword_args.tap do |args|
588
+ while (a, args = args.next)
589
+ case a
590
+ when KeywordArgs::MissingKeyword
591
+ errors << a
592
+ when KeywordArgs::UnexpectedKeyword
593
+ errors << a
594
+ end
595
+
596
+ yield a
597
+
598
+ case a
599
+ when KeywordArgs::SplatArg
600
+ case type = a.type
601
+ when nil
602
+ raise
603
+ when AST::Types::Record
604
+ keys = type.elements.keys
605
+ ts, args = args.consume_keys(keys, node: a.node)
606
+
607
+ case ts
608
+ when KeywordArgs::UnexpectedKeyword
609
+ yield ts
610
+ errors << ts
611
+ when Array
612
+ record = AST::Types::Record.new(elements: Hash[keys.zip(ts)])
613
+ yield KeywordArgs::ArgTypePairs.new(pairs: [[a.node, record]])
614
+ end
615
+ else
616
+ args = args.update(index: args.index + 1)
617
+
618
+ if args.rest_type
619
+ type = AST::Builtin::Hash.instance_type(AST::Builtin::Symbol.instance_type, args.possible_value_type)
620
+ yield KeywordArgs::ArgTypePairs.new(pairs: [[a.node, type]])
621
+ else
622
+ yield KeywordArgs::UnexpectedKeyword.new(keyword: nil, node: a.node)
623
+ end
624
+ end
625
+ end
626
+ end
172
627
  end
173
628
 
174
- when params.rest
175
- if args.any?
176
- rest = drop_first.zip0(params, block_type)
177
- first_arg = args[0]
629
+ pass = block_pass_arg
630
+ # if pass.node
631
+ # yield pass
632
+ # end
178
633
 
179
- case first_arg.type
180
- when :splat
181
- pair = [first_arg, AST::Builtin::Array.instance_type(params.rest)]
182
- else
183
- pair = [first_arg, params.rest]
634
+ diagnostics = []
635
+
636
+ missing_keywords = []
637
+ errors.each do |error|
638
+ case error
639
+ when KeywordArgs::UnexpectedKeyword
640
+ diagnostics << Diagnostic::Ruby::UnexpectedKeywordArgument.new(
641
+ node: error.node,
642
+ method_type: method_type,
643
+ method_name: method_name
644
+ )
645
+ when KeywordArgs::MissingKeyword
646
+ missing_keywords.push(*error.keywords)
647
+ when PositionalArgs::UnexpectedArg
648
+ diagnostics << Diagnostic::Ruby::UnexpectedPositionalArgument.new(
649
+ node: error.node,
650
+ method_type: method_type,
651
+ method_name: method_name
652
+ )
653
+ when PositionalArgs::MissingArg
654
+ diagnostics << Diagnostic::Ruby::InsufficientPositionalArguments.new(
655
+ node: node,
656
+ method_name: method_name,
657
+ method_type: method_type
658
+ )
184
659
  end
660
+ end
185
661
 
186
- add_pair(rest, pair)
187
- else
188
- zip0(params.drop_first, block_type)
662
+ unless missing_keywords.empty?
663
+ diagnostics << Diagnostic::Ruby::InsufficientKeywordArguments.new(
664
+ node: node,
665
+ method_name: method_name,
666
+ method_type: method_type,
667
+ missing_keywords: missing_keywords
668
+ )
189
669
  end
670
+
671
+ diagnostics
190
672
  else
191
- []
673
+ enum_for :each
192
674
  end
193
675
  end
194
676
  end