steep-relaxed 1.9.3.3
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 +7 -0
- data/.gitignore +13 -0
- data/.gitmodules +0 -0
- data/CHANGELOG.md +1032 -0
- data/LICENSE +21 -0
- data/README.md +260 -0
- data/Rakefile +227 -0
- data/STDGEM_DEPENDENCIES.txt +59 -0
- data/Steepfile +68 -0
- data/bin/console +14 -0
- data/bin/generate-diagnostics-docs.rb +112 -0
- data/bin/mem_graph.rb +67 -0
- data/bin/mem_prof.rb +102 -0
- data/bin/output_rebaseline.rb +34 -0
- data/bin/output_test.rb +60 -0
- data/bin/rbs +20 -0
- data/bin/rbs-inline +19 -0
- data/bin/setup +9 -0
- data/bin/stackprof_test.rb +19 -0
- data/bin/steep +19 -0
- data/bin/steep-check.rb +251 -0
- data/bin/steep-prof +16 -0
- data/doc/narrowing.md +195 -0
- data/doc/shape.md +194 -0
- data/exe/steep +18 -0
- data/guides/README.md +5 -0
- data/guides/src/gem-rbs-collection/gem-rbs-collection.md +126 -0
- data/guides/src/getting-started/getting-started.md +163 -0
- data/guides/src/nil-optional/nil-optional.md +195 -0
- data/lib/steep/annotation_parser.rb +199 -0
- data/lib/steep/ast/annotation/collection.rb +172 -0
- data/lib/steep/ast/annotation.rb +137 -0
- data/lib/steep/ast/builtin.rb +104 -0
- data/lib/steep/ast/ignore.rb +148 -0
- data/lib/steep/ast/node/type_application.rb +88 -0
- data/lib/steep/ast/node/type_assertion.rb +81 -0
- data/lib/steep/ast/types/any.rb +35 -0
- data/lib/steep/ast/types/boolean.rb +45 -0
- data/lib/steep/ast/types/bot.rb +35 -0
- data/lib/steep/ast/types/class.rb +43 -0
- data/lib/steep/ast/types/factory.rb +557 -0
- data/lib/steep/ast/types/helper.rb +40 -0
- data/lib/steep/ast/types/instance.rb +42 -0
- data/lib/steep/ast/types/intersection.rb +93 -0
- data/lib/steep/ast/types/literal.rb +59 -0
- data/lib/steep/ast/types/logic.rb +84 -0
- data/lib/steep/ast/types/name.rb +128 -0
- data/lib/steep/ast/types/nil.rb +41 -0
- data/lib/steep/ast/types/proc.rb +117 -0
- data/lib/steep/ast/types/record.rb +79 -0
- data/lib/steep/ast/types/self.rb +43 -0
- data/lib/steep/ast/types/shared_instance.rb +11 -0
- data/lib/steep/ast/types/top.rb +35 -0
- data/lib/steep/ast/types/tuple.rb +60 -0
- data/lib/steep/ast/types/union.rb +97 -0
- data/lib/steep/ast/types/var.rb +65 -0
- data/lib/steep/ast/types/void.rb +35 -0
- data/lib/steep/cli.rb +401 -0
- data/lib/steep/diagnostic/deprecated/else_on_exhaustive_case.rb +20 -0
- data/lib/steep/diagnostic/deprecated/unknown_constant_assigned.rb +28 -0
- data/lib/steep/diagnostic/helper.rb +18 -0
- data/lib/steep/diagnostic/lsp_formatter.rb +78 -0
- data/lib/steep/diagnostic/result_printer2.rb +48 -0
- data/lib/steep/diagnostic/ruby.rb +1221 -0
- data/lib/steep/diagnostic/signature.rb +570 -0
- data/lib/steep/drivers/annotations.rb +52 -0
- data/lib/steep/drivers/check.rb +339 -0
- data/lib/steep/drivers/checkfile.rb +210 -0
- data/lib/steep/drivers/diagnostic_printer.rb +105 -0
- data/lib/steep/drivers/init.rb +66 -0
- data/lib/steep/drivers/langserver.rb +56 -0
- data/lib/steep/drivers/print_project.rb +113 -0
- data/lib/steep/drivers/stats.rb +203 -0
- data/lib/steep/drivers/utils/driver_helper.rb +143 -0
- data/lib/steep/drivers/utils/jobs_option.rb +26 -0
- data/lib/steep/drivers/vendor.rb +27 -0
- data/lib/steep/drivers/watch.rb +194 -0
- data/lib/steep/drivers/worker.rb +58 -0
- data/lib/steep/equatable.rb +23 -0
- data/lib/steep/expectations.rb +228 -0
- data/lib/steep/index/rbs_index.rb +350 -0
- data/lib/steep/index/signature_symbol_provider.rb +185 -0
- data/lib/steep/index/source_index.rb +167 -0
- data/lib/steep/interface/block.rb +103 -0
- data/lib/steep/interface/builder.rb +843 -0
- data/lib/steep/interface/function.rb +1090 -0
- data/lib/steep/interface/method_type.rb +330 -0
- data/lib/steep/interface/shape.rb +239 -0
- data/lib/steep/interface/substitution.rb +159 -0
- data/lib/steep/interface/type_param.rb +115 -0
- data/lib/steep/located_value.rb +20 -0
- data/lib/steep/method_name.rb +42 -0
- data/lib/steep/module_helper.rb +24 -0
- data/lib/steep/node_helper.rb +273 -0
- data/lib/steep/path_helper.rb +30 -0
- data/lib/steep/project/dsl.rb +268 -0
- data/lib/steep/project/group.rb +31 -0
- data/lib/steep/project/options.rb +63 -0
- data/lib/steep/project/pattern.rb +59 -0
- data/lib/steep/project/target.rb +92 -0
- data/lib/steep/project.rb +78 -0
- data/lib/steep/rake_task.rb +132 -0
- data/lib/steep/range_extension.rb +29 -0
- data/lib/steep/server/base_worker.rb +97 -0
- data/lib/steep/server/change_buffer.rb +73 -0
- data/lib/steep/server/custom_methods.rb +77 -0
- data/lib/steep/server/delay_queue.rb +45 -0
- data/lib/steep/server/interaction_worker.rb +492 -0
- data/lib/steep/server/lsp_formatter.rb +455 -0
- data/lib/steep/server/master.rb +922 -0
- data/lib/steep/server/target_group_files.rb +205 -0
- data/lib/steep/server/type_check_controller.rb +366 -0
- data/lib/steep/server/type_check_worker.rb +303 -0
- data/lib/steep/server/work_done_progress.rb +64 -0
- data/lib/steep/server/worker_process.rb +176 -0
- data/lib/steep/services/completion_provider.rb +802 -0
- data/lib/steep/services/content_change.rb +61 -0
- data/lib/steep/services/file_loader.rb +74 -0
- data/lib/steep/services/goto_service.rb +441 -0
- data/lib/steep/services/hover_provider/rbs.rb +88 -0
- data/lib/steep/services/hover_provider/ruby.rb +221 -0
- data/lib/steep/services/hover_provider/singleton_methods.rb +20 -0
- data/lib/steep/services/path_assignment.rb +46 -0
- data/lib/steep/services/signature_help_provider.rb +202 -0
- data/lib/steep/services/signature_service.rb +428 -0
- data/lib/steep/services/stats_calculator.rb +68 -0
- data/lib/steep/services/type_check_service.rb +394 -0
- data/lib/steep/services/type_name_completion.rb +236 -0
- data/lib/steep/signature/validator.rb +651 -0
- data/lib/steep/source/ignore_ranges.rb +69 -0
- data/lib/steep/source.rb +691 -0
- data/lib/steep/subtyping/cache.rb +30 -0
- data/lib/steep/subtyping/check.rb +1113 -0
- data/lib/steep/subtyping/constraints.rb +341 -0
- data/lib/steep/subtyping/relation.rb +101 -0
- data/lib/steep/subtyping/result.rb +324 -0
- data/lib/steep/subtyping/variable_variance.rb +89 -0
- data/lib/steep/test.rb +9 -0
- data/lib/steep/thread_waiter.rb +43 -0
- data/lib/steep/type_construction.rb +5183 -0
- data/lib/steep/type_inference/block_params.rb +416 -0
- data/lib/steep/type_inference/case_when.rb +303 -0
- data/lib/steep/type_inference/constant_env.rb +56 -0
- data/lib/steep/type_inference/context.rb +195 -0
- data/lib/steep/type_inference/logic_type_interpreter.rb +613 -0
- data/lib/steep/type_inference/method_call.rb +193 -0
- data/lib/steep/type_inference/method_params.rb +531 -0
- data/lib/steep/type_inference/multiple_assignment.rb +194 -0
- data/lib/steep/type_inference/send_args.rb +712 -0
- data/lib/steep/type_inference/type_env.rb +341 -0
- data/lib/steep/type_inference/type_env_builder.rb +138 -0
- data/lib/steep/typing.rb +321 -0
- data/lib/steep/version.rb +3 -0
- data/lib/steep.rb +369 -0
- data/manual/annotations.md +181 -0
- data/manual/ignore.md +20 -0
- data/manual/ruby-diagnostics.md +1879 -0
- data/sample/Steepfile +22 -0
- data/sample/lib/conference.rb +49 -0
- data/sample/lib/length.rb +35 -0
- data/sample/sig/conference.rbs +42 -0
- data/sample/sig/generics.rbs +15 -0
- data/sample/sig/length.rbs +34 -0
- data/steep-relaxed.gemspec +56 -0
- metadata +340 -0
@@ -0,0 +1,712 @@
|
|
1
|
+
module Steep
|
2
|
+
module TypeInference
|
3
|
+
class SendArgs
|
4
|
+
class PositionalArgs
|
5
|
+
class NodeParamPair
|
6
|
+
attr_reader :node
|
7
|
+
attr_reader :param
|
8
|
+
|
9
|
+
def initialize(node:, param:)
|
10
|
+
@node = node
|
11
|
+
@param = param
|
12
|
+
end
|
13
|
+
|
14
|
+
include Equatable
|
15
|
+
|
16
|
+
def to_ary
|
17
|
+
[node, param]
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
class NodeTypePair
|
22
|
+
attr_reader :node
|
23
|
+
attr_reader :type
|
24
|
+
|
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
|
40
|
+
end
|
41
|
+
|
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
|
52
|
+
end
|
53
|
+
|
54
|
+
class UnexpectedArg
|
55
|
+
attr_reader :node
|
56
|
+
|
57
|
+
def initialize(node:)
|
58
|
+
@node = node
|
59
|
+
end
|
60
|
+
|
61
|
+
include Equatable
|
62
|
+
end
|
63
|
+
|
64
|
+
class MissingArg
|
65
|
+
attr_reader :params
|
66
|
+
|
67
|
+
def initialize(params:)
|
68
|
+
@params = params
|
69
|
+
end
|
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]
|
88
|
+
end
|
89
|
+
|
90
|
+
def following_args
|
91
|
+
args[index..] or raise
|
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 && node.type == :forwarded_args
|
105
|
+
# If the node is a `:forwarded_args`, abort
|
106
|
+
nil
|
107
|
+
when !node && param.is_a?(Interface::Function::Params::PositionalParams::Required)
|
108
|
+
[
|
109
|
+
MissingArg.new(params: positional_params),
|
110
|
+
update(index: index, positional_params: nil)
|
111
|
+
]
|
112
|
+
when !node && param.is_a?(Interface::Function::Params::PositionalParams::Optional)
|
113
|
+
nil
|
114
|
+
when !node && param.is_a?(Interface::Function::Params::PositionalParams::Rest)
|
115
|
+
nil
|
116
|
+
when !node && !param
|
117
|
+
nil
|
118
|
+
when node && node.type != :splat && param.is_a?(Interface::Function::Params::PositionalParams::Required)
|
119
|
+
[
|
120
|
+
NodeParamPair.new(node: node, param: param),
|
121
|
+
update(index: index+1, positional_params: positional_params&.tail)
|
122
|
+
]
|
123
|
+
when node && node.type != :splat && param.is_a?(Interface::Function::Params::PositionalParams::Optional)
|
124
|
+
[
|
125
|
+
NodeParamPair.new(node: node, param: param),
|
126
|
+
update(index: index+1, positional_params: positional_params&.tail)
|
127
|
+
]
|
128
|
+
when node && node.type != :splat && param.is_a?(Interface::Function::Params::PositionalParams::Rest)
|
129
|
+
[
|
130
|
+
NodeParamPair.new(node: node, param: param),
|
131
|
+
update(index: index+1)
|
132
|
+
]
|
133
|
+
when node && node.type != :splat && !param
|
134
|
+
[
|
135
|
+
UnexpectedArg.new(node: node),
|
136
|
+
update(index: index + 1)
|
137
|
+
]
|
138
|
+
when node && node.type == :splat
|
139
|
+
[
|
140
|
+
SplatArg.new(node: node),
|
141
|
+
self
|
142
|
+
]
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
def uniform_type
|
147
|
+
return nil unless positional_params
|
148
|
+
if positional_params.each.any? {|param| param.is_a?(Interface::Function::Params::PositionalParams::Rest) }
|
149
|
+
AST::Types::Intersection.build(types: positional_params.each.map(&:type))
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
def consume(n, node:)
|
154
|
+
# @type var ps: Array[Interface::Function::Params::PositionalParams::param]
|
155
|
+
ps = []
|
156
|
+
params = consume0(n, node: node, params: positional_params, ps: ps)
|
157
|
+
case params
|
158
|
+
when UnexpectedArg
|
159
|
+
[
|
160
|
+
params,
|
161
|
+
update(index: index+1, positional_params: nil)
|
162
|
+
]
|
163
|
+
else
|
164
|
+
[ps, update(index: index+1, positional_params: params)]
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
def consume0(n, node:, params:, ps:)
|
169
|
+
case n
|
170
|
+
when 0
|
171
|
+
params
|
172
|
+
else
|
173
|
+
head = params&.head
|
174
|
+
case head
|
175
|
+
when nil
|
176
|
+
UnexpectedArg.new(node: node)
|
177
|
+
when Interface::Function::Params::PositionalParams::Required, Interface::Function::Params::PositionalParams::Optional
|
178
|
+
ps << head
|
179
|
+
consume0(n-1, node: node, params: params&.tail, ps: ps)
|
180
|
+
when Interface::Function::Params::PositionalParams::Rest
|
181
|
+
ps << head
|
182
|
+
consume0(n-1, node: node, params: params, ps: ps)
|
183
|
+
end
|
184
|
+
end
|
185
|
+
end
|
186
|
+
end
|
187
|
+
|
188
|
+
class KeywordArgs
|
189
|
+
class ArgTypePairs
|
190
|
+
attr_reader :pairs
|
191
|
+
|
192
|
+
def initialize(pairs:)
|
193
|
+
@pairs = pairs
|
194
|
+
end
|
195
|
+
|
196
|
+
include Equatable
|
197
|
+
|
198
|
+
def [](index)
|
199
|
+
pairs[index]
|
200
|
+
end
|
201
|
+
|
202
|
+
def size
|
203
|
+
pairs.size
|
204
|
+
end
|
205
|
+
end
|
206
|
+
|
207
|
+
class SplatArg
|
208
|
+
attr_reader :node
|
209
|
+
attr_accessor :type
|
210
|
+
|
211
|
+
def initialize(node:)
|
212
|
+
@node = node
|
213
|
+
@type = nil
|
214
|
+
end
|
215
|
+
|
216
|
+
include Equatable
|
217
|
+
end
|
218
|
+
|
219
|
+
class UnexpectedKeyword
|
220
|
+
attr_reader :keyword
|
221
|
+
attr_reader :node
|
222
|
+
|
223
|
+
include Equatable
|
224
|
+
|
225
|
+
def initialize(keyword:, node:)
|
226
|
+
@keyword = keyword
|
227
|
+
@node = node
|
228
|
+
end
|
229
|
+
|
230
|
+
def key_node
|
231
|
+
if node.type == :pair
|
232
|
+
node.children[0]
|
233
|
+
end
|
234
|
+
end
|
235
|
+
|
236
|
+
def value_node
|
237
|
+
if node.type == :pair
|
238
|
+
node.children[1]
|
239
|
+
end
|
240
|
+
end
|
241
|
+
end
|
242
|
+
|
243
|
+
class MissingKeyword
|
244
|
+
attr_reader :keywords
|
245
|
+
|
246
|
+
include Equatable
|
247
|
+
|
248
|
+
def initialize(keywords:)
|
249
|
+
@keywords = keywords
|
250
|
+
end
|
251
|
+
end
|
252
|
+
|
253
|
+
attr_reader :kwarg_nodes
|
254
|
+
attr_reader :keyword_params
|
255
|
+
attr_reader :index
|
256
|
+
attr_reader :consumed_keywords
|
257
|
+
|
258
|
+
def initialize(kwarg_nodes:, keyword_params:, index: 0, consumed_keywords: Set[])
|
259
|
+
@kwarg_nodes = kwarg_nodes
|
260
|
+
@keyword_params = keyword_params
|
261
|
+
@index = index
|
262
|
+
@consumed_keywords = consumed_keywords
|
263
|
+
end
|
264
|
+
|
265
|
+
def update(index: self.index, consumed_keywords: self.consumed_keywords)
|
266
|
+
KeywordArgs.new(
|
267
|
+
kwarg_nodes: kwarg_nodes,
|
268
|
+
keyword_params: keyword_params,
|
269
|
+
index: index,
|
270
|
+
consumed_keywords: consumed_keywords
|
271
|
+
)
|
272
|
+
end
|
273
|
+
|
274
|
+
def keyword_pair
|
275
|
+
kwarg_nodes[index]
|
276
|
+
end
|
277
|
+
|
278
|
+
def required_keywords
|
279
|
+
keyword_params.requireds
|
280
|
+
end
|
281
|
+
|
282
|
+
def optional_keywords
|
283
|
+
keyword_params.optionals
|
284
|
+
end
|
285
|
+
|
286
|
+
def rest_type
|
287
|
+
keyword_params.rest
|
288
|
+
end
|
289
|
+
|
290
|
+
def keyword_type(key)
|
291
|
+
required_keywords[key] || optional_keywords[key]
|
292
|
+
end
|
293
|
+
|
294
|
+
def all_keys
|
295
|
+
keys = Set.new
|
296
|
+
keys.merge(required_keywords.each_key)
|
297
|
+
keys.merge(optional_keywords.each_key)
|
298
|
+
keys.sort_by(&:to_s).to_a
|
299
|
+
end
|
300
|
+
|
301
|
+
def all_values
|
302
|
+
keys = Set.new
|
303
|
+
keys.merge(required_keywords.each_value)
|
304
|
+
keys.merge(optional_keywords.each_value)
|
305
|
+
keys.sort_by(&:to_s).to_a
|
306
|
+
end
|
307
|
+
|
308
|
+
def possible_key_type
|
309
|
+
# @type var key_types: Array[AST::Types::t]
|
310
|
+
key_types = all_keys.map {|key| AST::Types::Literal.new(value: key) }
|
311
|
+
key_types << AST::Builtin::Symbol.instance_type if rest_type
|
312
|
+
|
313
|
+
AST::Types::Union.build(types: key_types)
|
314
|
+
end
|
315
|
+
|
316
|
+
def possible_value_type
|
317
|
+
value_types = all_values
|
318
|
+
value_types << rest_type if rest_type
|
319
|
+
|
320
|
+
AST::Types::Intersection.build(types: value_types)
|
321
|
+
end
|
322
|
+
|
323
|
+
def next()
|
324
|
+
node = keyword_pair
|
325
|
+
|
326
|
+
if node
|
327
|
+
case node.type
|
328
|
+
when :pair
|
329
|
+
key_node, value_node = node.children
|
330
|
+
|
331
|
+
if key_node.type == :sym
|
332
|
+
key = key_node.children[0]
|
333
|
+
|
334
|
+
case
|
335
|
+
when value_type = keyword_type(key)
|
336
|
+
[
|
337
|
+
ArgTypePairs.new(
|
338
|
+
pairs: [
|
339
|
+
[key_node, AST::Types::Literal.new(value: key)],
|
340
|
+
[value_node, value_type]
|
341
|
+
]
|
342
|
+
),
|
343
|
+
update(
|
344
|
+
index: index+1,
|
345
|
+
consumed_keywords: consumed_keywords + [key]
|
346
|
+
)
|
347
|
+
]
|
348
|
+
when value_type = rest_type
|
349
|
+
[
|
350
|
+
ArgTypePairs.new(
|
351
|
+
pairs: [
|
352
|
+
[key_node, AST::Builtin::Symbol.instance_type],
|
353
|
+
[value_node, value_type]
|
354
|
+
]
|
355
|
+
),
|
356
|
+
update(
|
357
|
+
index: index+1,
|
358
|
+
consumed_keywords: consumed_keywords + [key]
|
359
|
+
)
|
360
|
+
]
|
361
|
+
else
|
362
|
+
[
|
363
|
+
UnexpectedKeyword.new(keyword: key, node: node),
|
364
|
+
update(index: index+1)
|
365
|
+
]
|
366
|
+
end
|
367
|
+
else
|
368
|
+
if !all_keys.empty? || rest_type
|
369
|
+
[
|
370
|
+
ArgTypePairs.new(
|
371
|
+
pairs: [
|
372
|
+
[key_node, possible_key_type],
|
373
|
+
[value_node, possible_value_type]
|
374
|
+
]
|
375
|
+
),
|
376
|
+
update(index: index+1)
|
377
|
+
]
|
378
|
+
else
|
379
|
+
[
|
380
|
+
UnexpectedKeyword.new(keyword: nil, node: node),
|
381
|
+
update(index: index+1)
|
382
|
+
]
|
383
|
+
end
|
384
|
+
end
|
385
|
+
when :kwsplat
|
386
|
+
[
|
387
|
+
SplatArg.new(node: node),
|
388
|
+
self
|
389
|
+
]
|
390
|
+
end
|
391
|
+
else
|
392
|
+
left = Set.new(required_keywords.keys) - consumed_keywords
|
393
|
+
unless left.empty?
|
394
|
+
[
|
395
|
+
MissingKeyword.new(keywords: left),
|
396
|
+
update(consumed_keywords: consumed_keywords + left)
|
397
|
+
]
|
398
|
+
end
|
399
|
+
end
|
400
|
+
end
|
401
|
+
|
402
|
+
def consume_keys(keys, node:)
|
403
|
+
# @type var consumed_keys: Array[Symbol]
|
404
|
+
consumed_keys = []
|
405
|
+
# @type var types: Array[AST::Types::t]
|
406
|
+
types = []
|
407
|
+
|
408
|
+
# @type var unexpected_keyword: Symbol?
|
409
|
+
unexpected_keyword = nil
|
410
|
+
|
411
|
+
keys.each do |key|
|
412
|
+
case
|
413
|
+
when type = keyword_type(key)
|
414
|
+
consumed_keys << key
|
415
|
+
types << type
|
416
|
+
when type = rest_type()
|
417
|
+
types << type
|
418
|
+
else
|
419
|
+
unexpected_keyword = key
|
420
|
+
end
|
421
|
+
end
|
422
|
+
|
423
|
+
[
|
424
|
+
if unexpected_keyword
|
425
|
+
UnexpectedKeyword.new(keyword: unexpected_keyword, node: node)
|
426
|
+
else
|
427
|
+
types
|
428
|
+
end,
|
429
|
+
update(index: index + 1, consumed_keywords: consumed_keywords + consumed_keys)
|
430
|
+
]
|
431
|
+
end
|
432
|
+
end
|
433
|
+
|
434
|
+
class BlockPassArg
|
435
|
+
attr_reader :node
|
436
|
+
attr_reader :block
|
437
|
+
|
438
|
+
def initialize(node:, block:)
|
439
|
+
@node = node
|
440
|
+
@block = block
|
441
|
+
end
|
442
|
+
|
443
|
+
include Equatable
|
444
|
+
|
445
|
+
def no_block?
|
446
|
+
!node && !block
|
447
|
+
end
|
448
|
+
|
449
|
+
def compatible?
|
450
|
+
if node
|
451
|
+
block ? true : false
|
452
|
+
else
|
453
|
+
!block || block.optional?
|
454
|
+
end
|
455
|
+
end
|
456
|
+
|
457
|
+
def block_missing?
|
458
|
+
!node && block&.required?
|
459
|
+
end
|
460
|
+
|
461
|
+
def unexpected_block?
|
462
|
+
node && !block
|
463
|
+
end
|
464
|
+
|
465
|
+
def pair
|
466
|
+
raise unless compatible?
|
467
|
+
|
468
|
+
if node && block
|
469
|
+
[
|
470
|
+
node,
|
471
|
+
block.type
|
472
|
+
]
|
473
|
+
end
|
474
|
+
end
|
475
|
+
|
476
|
+
def node_type
|
477
|
+
raise unless block
|
478
|
+
|
479
|
+
type = AST::Types::Proc.new(type: block.type, block: nil, self_type: block.self_type)
|
480
|
+
|
481
|
+
if block.optional?
|
482
|
+
type = AST::Types::Union.build(types: [type, AST::Builtin.nil_type])
|
483
|
+
end
|
484
|
+
|
485
|
+
type
|
486
|
+
end
|
487
|
+
end
|
488
|
+
|
489
|
+
class ForwardedArgs
|
490
|
+
attr_reader :node, :params
|
491
|
+
|
492
|
+
def initialize(node:, params:)
|
493
|
+
@node = node
|
494
|
+
@params = params
|
495
|
+
end
|
496
|
+
end
|
497
|
+
|
498
|
+
attr_reader :node
|
499
|
+
attr_reader :arguments
|
500
|
+
attr_reader :type
|
501
|
+
|
502
|
+
def initialize(node:, arguments:, type:)
|
503
|
+
raise "Untyped function is not supported" unless type.type.params
|
504
|
+
@node = node
|
505
|
+
@arguments = arguments
|
506
|
+
@type = type
|
507
|
+
end
|
508
|
+
|
509
|
+
def params
|
510
|
+
case type
|
511
|
+
when Interface::MethodType
|
512
|
+
type.type.params or raise
|
513
|
+
when AST::Types::Proc
|
514
|
+
type.type.params or raise
|
515
|
+
else
|
516
|
+
raise
|
517
|
+
end
|
518
|
+
end
|
519
|
+
|
520
|
+
def block
|
521
|
+
case type
|
522
|
+
when Interface::MethodType
|
523
|
+
type.block
|
524
|
+
when AST::Types::Proc
|
525
|
+
type.block
|
526
|
+
end
|
527
|
+
end
|
528
|
+
|
529
|
+
def positional_params
|
530
|
+
params or raise
|
531
|
+
params.positional_params
|
532
|
+
end
|
533
|
+
|
534
|
+
def keyword_params
|
535
|
+
params or raise
|
536
|
+
params.keyword_params
|
537
|
+
end
|
538
|
+
|
539
|
+
def kwargs_node
|
540
|
+
unless keyword_params.empty?
|
541
|
+
arguments.find {|node| node.type == :kwargs }
|
542
|
+
end
|
543
|
+
end
|
544
|
+
|
545
|
+
def positional_arg
|
546
|
+
args =
|
547
|
+
if keyword_params.empty?
|
548
|
+
arguments.take_while {|node| node.type != :block_pass }
|
549
|
+
else
|
550
|
+
arguments.take_while {|node| node.type != :kwargs && node.type != :block_pass }
|
551
|
+
end
|
552
|
+
|
553
|
+
PositionalArgs.new(args: args, index: 0, positional_params: positional_params)
|
554
|
+
end
|
555
|
+
|
556
|
+
def forwarded_args_node
|
557
|
+
arguments.find {|node| node.type == :forwarded_args }
|
558
|
+
end
|
559
|
+
|
560
|
+
def keyword_args
|
561
|
+
KeywordArgs.new(
|
562
|
+
kwarg_nodes: kwargs_node&.children || [],
|
563
|
+
keyword_params: keyword_params
|
564
|
+
)
|
565
|
+
end
|
566
|
+
|
567
|
+
def block_pass_arg
|
568
|
+
node = arguments.find {|node| node.type == :block_pass }
|
569
|
+
|
570
|
+
BlockPassArg.new(node: node, block: block)
|
571
|
+
end
|
572
|
+
|
573
|
+
def each
|
574
|
+
if block_given?
|
575
|
+
errors = [] #: Array[PositionalArgs::error_arg | KeywordArgs::error_arg]
|
576
|
+
|
577
|
+
last_positional_args = positional_arg
|
578
|
+
|
579
|
+
positional_arg.tap do |args|
|
580
|
+
while (value, args = args.next())
|
581
|
+
yield value
|
582
|
+
|
583
|
+
case value
|
584
|
+
when PositionalArgs::SplatArg
|
585
|
+
type = value.type
|
586
|
+
|
587
|
+
case type
|
588
|
+
when nil
|
589
|
+
raise
|
590
|
+
when AST::Types::Tuple
|
591
|
+
ts, args = args.consume(type.types.size, node: value.node)
|
592
|
+
|
593
|
+
case ts
|
594
|
+
when Array
|
595
|
+
ty = AST::Types::Tuple.new(types: ts.map(&:type))
|
596
|
+
yield PositionalArgs::NodeTypePair.new(node: value.node, type: ty)
|
597
|
+
when PositionalArgs::UnexpectedArg
|
598
|
+
errors << ts
|
599
|
+
yield ts
|
600
|
+
end
|
601
|
+
else
|
602
|
+
if t = args.uniform_type
|
603
|
+
args.following_args.each do |node|
|
604
|
+
yield PositionalArgs::NodeTypePair.new(node: node, type: t)
|
605
|
+
end
|
606
|
+
else
|
607
|
+
args.following_args.each do |node|
|
608
|
+
arg = PositionalArgs::UnexpectedArg.new(node: node)
|
609
|
+
yield arg
|
610
|
+
errors << arg
|
611
|
+
end
|
612
|
+
end
|
613
|
+
|
614
|
+
break
|
615
|
+
end
|
616
|
+
when PositionalArgs::UnexpectedArg, PositionalArgs::MissingArg
|
617
|
+
errors << value
|
618
|
+
end
|
619
|
+
|
620
|
+
last_positional_args = args
|
621
|
+
end
|
622
|
+
end
|
623
|
+
|
624
|
+
if fag = forwarded_args_node
|
625
|
+
forward_params = Interface::Function::Params.new(
|
626
|
+
positional_params: last_positional_args.positional_params,
|
627
|
+
keyword_params: keyword_params
|
628
|
+
)
|
629
|
+
|
630
|
+
forwarded_args = ForwardedArgs.new(node: fag, params: forward_params)
|
631
|
+
else
|
632
|
+
keyword_args.tap do |args|
|
633
|
+
while (a, args = args.next)
|
634
|
+
case a
|
635
|
+
when KeywordArgs::MissingKeyword
|
636
|
+
errors << a
|
637
|
+
when KeywordArgs::UnexpectedKeyword
|
638
|
+
errors << a
|
639
|
+
end
|
640
|
+
|
641
|
+
yield a
|
642
|
+
|
643
|
+
case a
|
644
|
+
when KeywordArgs::SplatArg
|
645
|
+
case type = a.type
|
646
|
+
when nil
|
647
|
+
raise
|
648
|
+
when AST::Types::Record
|
649
|
+
# @type var keys: Array[Symbol]
|
650
|
+
keys = _ = type.elements.keys
|
651
|
+
ts, args = args.consume_keys(keys, node: a.node)
|
652
|
+
|
653
|
+
case ts
|
654
|
+
when KeywordArgs::UnexpectedKeyword
|
655
|
+
yield ts
|
656
|
+
errors << ts
|
657
|
+
when Array
|
658
|
+
pairs = keys.zip(ts) #: Array[[Symbol, AST::Types::t]]
|
659
|
+
record = AST::Types::Record.new(elements: Hash[pairs], required_keys: Set.new(keys))
|
660
|
+
yield KeywordArgs::ArgTypePairs.new(pairs: [[a.node, record]])
|
661
|
+
end
|
662
|
+
else
|
663
|
+
args = args.update(index: args.index + 1)
|
664
|
+
|
665
|
+
if args.rest_type
|
666
|
+
type = AST::Builtin::Hash.instance_type(AST::Builtin::Symbol.instance_type, args.possible_value_type)
|
667
|
+
yield KeywordArgs::ArgTypePairs.new(pairs: [[a.node, type]])
|
668
|
+
else
|
669
|
+
yield KeywordArgs::UnexpectedKeyword.new(keyword: nil, node: a.node)
|
670
|
+
end
|
671
|
+
end
|
672
|
+
end
|
673
|
+
end
|
674
|
+
end
|
675
|
+
end
|
676
|
+
|
677
|
+
diagnostics = [] #: Array[Diagnostic::Ruby::Base]
|
678
|
+
|
679
|
+
missing_keywords = [] #: Array[Symbol]
|
680
|
+
errors.each do |error|
|
681
|
+
case error
|
682
|
+
when KeywordArgs::UnexpectedKeyword
|
683
|
+
diagnostics << Diagnostic::Ruby::UnexpectedKeywordArgument.new(node: error.node, params: params)
|
684
|
+
when KeywordArgs::MissingKeyword
|
685
|
+
missing_keywords.push(*error.keywords.to_a)
|
686
|
+
when PositionalArgs::UnexpectedArg
|
687
|
+
if error.node.type == :kwargs
|
688
|
+
error.node.children.each do |kwarg|
|
689
|
+
if kwarg.type == :pair
|
690
|
+
diagnostics << Diagnostic::Ruby::UnexpectedKeywordArgument.new(node: kwarg, params: params)
|
691
|
+
end
|
692
|
+
end
|
693
|
+
else
|
694
|
+
diagnostics << Diagnostic::Ruby::UnexpectedPositionalArgument.new(node: error.node, params: params)
|
695
|
+
end
|
696
|
+
when PositionalArgs::MissingArg
|
697
|
+
diagnostics << Diagnostic::Ruby::InsufficientPositionalArguments.new(node: node, params: params)
|
698
|
+
end
|
699
|
+
end
|
700
|
+
|
701
|
+
unless missing_keywords.empty?
|
702
|
+
diagnostics << Diagnostic::Ruby::InsufficientKeywordArguments.new(node: node, params: params, missing_keywords: missing_keywords)
|
703
|
+
end
|
704
|
+
|
705
|
+
[forwarded_args, diagnostics]
|
706
|
+
else
|
707
|
+
enum_for :each
|
708
|
+
end
|
709
|
+
end
|
710
|
+
end
|
711
|
+
end
|
712
|
+
end
|