steep 0.44.1 → 0.47.1

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