steep 0.43.0 → 0.45.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.github/dependabot.yml +8 -0
- data/.github/workflows/ruby.yml +3 -2
- data/.gitignore +0 -1
- data/CHANGELOG.md +30 -0
- data/Gemfile +0 -1
- data/Gemfile.lock +77 -0
- data/bin/output_test.rb +8 -2
- data/lib/steep.rb +4 -1
- data/lib/steep/ast/builtin.rb +7 -1
- data/lib/steep/ast/types/factory.rb +19 -25
- data/lib/steep/diagnostic/ruby.rb +137 -60
- data/lib/steep/diagnostic/signature.rb +34 -0
- data/lib/steep/equatable.rb +21 -0
- data/lib/steep/index/source_index.rb +55 -5
- data/lib/steep/interface/block.rb +4 -0
- data/lib/steep/interface/function.rb +798 -579
- data/lib/steep/server/interaction_worker.rb +239 -20
- data/lib/steep/server/master.rb +40 -19
- data/lib/steep/server/type_check_worker.rb +68 -0
- data/lib/steep/services/file_loader.rb +26 -19
- data/lib/steep/services/goto_service.rb +322 -0
- data/lib/steep/services/hover_content.rb +131 -79
- data/lib/steep/services/type_check_service.rb +25 -0
- data/lib/steep/source.rb +7 -10
- data/lib/steep/type_construction.rb +496 -518
- data/lib/steep/type_inference/block_params.rb +2 -5
- data/lib/steep/type_inference/method_params.rb +483 -0
- data/lib/steep/type_inference/send_args.rb +610 -128
- data/lib/steep/typing.rb +46 -21
- data/lib/steep/version.rb +1 -1
- data/sig/steep/type_inference/send_args.rbs +42 -0
- data/smoke/array/test_expectations.yml +3 -3
- data/smoke/block/c.rb +0 -1
- data/smoke/class/test_expectations.yml +12 -15
- data/smoke/const/test_expectations.yml +0 -10
- data/smoke/diagnostics-rbs/mixin-class-error.rbs +6 -0
- data/smoke/diagnostics-rbs/test_expectations.yml +12 -0
- data/smoke/diagnostics-ruby-unsat/Steepfile +5 -0
- data/smoke/diagnostics-ruby-unsat/a.rbs +3 -0
- data/smoke/diagnostics-ruby-unsat/test_expectations.yml +27 -0
- data/smoke/{diagnostics → diagnostics-ruby-unsat}/unsatisfiable_constraint.rb +0 -1
- data/smoke/diagnostics/a.rbs +0 -4
- data/smoke/diagnostics/different_method_parameter_kind.rb +9 -0
- data/smoke/diagnostics/method_arity_mismatch.rb +2 -2
- data/smoke/diagnostics/method_parameter_mismatch.rb +10 -0
- data/smoke/diagnostics/test_expectations.yml +108 -57
- data/smoke/ensure/test_expectations.yml +3 -3
- data/smoke/enumerator/test_expectations.yml +1 -1
- data/smoke/literal/test_expectations.yml +2 -2
- data/smoke/method/test_expectations.yml +11 -10
- data/smoke/regression/issue_372.rb +8 -0
- data/smoke/regression/issue_372.rbs +4 -0
- data/smoke/regression/test_expectations.yml +0 -12
- data/smoke/rescue/test_expectations.yml +3 -3
- data/smoke/toplevel/test_expectations.yml +3 -3
- data/smoke/tsort/test_expectations.yml +2 -2
- data/steep.gemspec +2 -2
- metadata +24 -10
@@ -1,194 +1,676 @@
|
|
1
1
|
module Steep
|
2
2
|
module TypeInference
|
3
3
|
class SendArgs
|
4
|
-
|
5
|
-
|
4
|
+
class PositionalArgs
|
5
|
+
class NodeParamPair
|
6
|
+
attr_reader :node
|
7
|
+
attr_reader :param
|
6
8
|
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
9
|
+
def initialize(node:, param:)
|
10
|
+
@node = node
|
11
|
+
@param = param
|
12
|
+
end
|
13
|
+
|
14
|
+
include Equatable
|
11
15
|
|
12
|
-
|
13
|
-
|
16
|
+
def to_ary
|
17
|
+
[node, param]
|
18
|
+
end
|
19
|
+
end
|
14
20
|
|
15
|
-
|
16
|
-
|
21
|
+
class NodeTypePair
|
22
|
+
attr_reader :node
|
23
|
+
attr_reader :type
|
17
24
|
|
18
|
-
|
19
|
-
|
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
|
-
|
23
|
-
|
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
|
-
|
27
|
-
|
54
|
+
class UnexpectedArg
|
55
|
+
attr_reader :node
|
28
56
|
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
end
|
57
|
+
def initialize(node:)
|
58
|
+
@node = node
|
59
|
+
end
|
33
60
|
|
34
|
-
|
35
|
-
|
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
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
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
|
-
|
49
|
-
|
70
|
+
|
71
|
+
include Equatable
|
50
72
|
end
|
51
|
-
end
|
52
73
|
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
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
|
-
|
64
|
-
|
65
|
-
|
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
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
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
|
-
|
171
|
+
[ps, update(index: index+1, positional_params: params)]
|
78
172
|
end
|
79
173
|
end
|
80
174
|
|
81
|
-
|
82
|
-
case
|
83
|
-
when
|
84
|
-
|
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
|
-
|
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
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
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
|
-
|
103
|
-
|
104
|
-
|
105
|
-
[[]]
|
214
|
+
class SplatArg
|
215
|
+
attr_reader :node
|
216
|
+
attr_accessor :type
|
106
217
|
|
107
|
-
|
108
|
-
|
109
|
-
|
218
|
+
def initialize(node:)
|
219
|
+
@node = node
|
220
|
+
@type = nil
|
221
|
+
end
|
110
222
|
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
132
|
-
|
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
|
-
|
139
|
-
|
140
|
-
|
141
|
-
last_arg = args.last
|
408
|
+
def consume_keys(keys, node:)
|
409
|
+
consumed_keys = []
|
410
|
+
types = []
|
142
411
|
|
143
|
-
|
412
|
+
unexpected_keyword = nil
|
144
413
|
|
145
|
-
|
146
|
-
|
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
|
-
|
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
|
-
|
456
|
+
!block || block.optional?
|
154
457
|
end
|
458
|
+
end
|
155
459
|
|
156
|
-
|
157
|
-
|
158
|
-
|
460
|
+
def block_missing?
|
461
|
+
!node && block&.required?
|
462
|
+
end
|
159
463
|
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
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
|
-
|
170
|
-
|
171
|
-
|
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
|
-
|
175
|
-
if
|
176
|
-
|
177
|
-
|
629
|
+
pass = block_pass_arg
|
630
|
+
# if pass.node
|
631
|
+
# yield pass
|
632
|
+
# end
|
178
633
|
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
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
|
-
|
187
|
-
|
188
|
-
|
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
|