solargraph 0.58.1 → 0.59.0.dev.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.
- checksums.yaml +4 -4
- data/.envrc +3 -0
- data/.github/workflows/linting.yml +4 -5
- data/.github/workflows/plugins.yml +40 -36
- data/.github/workflows/rspec.yml +45 -13
- data/.github/workflows/typecheck.yml +2 -2
- data/.rubocop_todo.yml +27 -49
- data/README.md +3 -3
- data/Rakefile +1 -0
- data/lib/solargraph/api_map/cache.rb +110 -110
- data/lib/solargraph/api_map/constants.rb +289 -279
- data/lib/solargraph/api_map/index.rb +204 -193
- data/lib/solargraph/api_map/source_to_yard.rb +109 -97
- data/lib/solargraph/api_map/store.rb +387 -384
- data/lib/solargraph/api_map.rb +1000 -945
- data/lib/solargraph/complex_type/conformance.rb +176 -0
- data/lib/solargraph/complex_type/type_methods.rb +242 -228
- data/lib/solargraph/complex_type/unique_type.rb +632 -482
- data/lib/solargraph/complex_type.rb +549 -444
- data/lib/solargraph/convention/data_definition/data_definition_node.rb +93 -91
- data/lib/solargraph/convention/data_definition.rb +108 -105
- data/lib/solargraph/convention/struct_definition/struct_assignment_node.rb +62 -61
- data/lib/solargraph/convention/struct_definition/struct_definition_node.rb +103 -102
- data/lib/solargraph/convention/struct_definition.rb +168 -164
- data/lib/solargraph/diagnostics/require_not_found.rb +54 -53
- data/lib/solargraph/diagnostics/rubocop.rb +119 -118
- data/lib/solargraph/diagnostics/rubocop_helpers.rb +70 -68
- data/lib/solargraph/diagnostics/type_check.rb +56 -55
- data/lib/solargraph/doc_map.rb +200 -439
- data/lib/solargraph/equality.rb +34 -34
- data/lib/solargraph/gem_pins.rb +97 -98
- data/lib/solargraph/language_server/host/dispatch.rb +131 -130
- data/lib/solargraph/language_server/host/message_worker.rb +113 -112
- data/lib/solargraph/language_server/host/sources.rb +100 -99
- data/lib/solargraph/language_server/host.rb +883 -878
- data/lib/solargraph/language_server/message/extended/check_gem_version.rb +109 -114
- data/lib/solargraph/language_server/message/extended/document.rb +24 -23
- data/lib/solargraph/language_server/message/text_document/completion.rb +58 -56
- data/lib/solargraph/language_server/message/text_document/definition.rb +42 -40
- data/lib/solargraph/language_server/message/text_document/document_symbol.rb +28 -26
- data/lib/solargraph/language_server/message/text_document/formatting.rb +150 -148
- data/lib/solargraph/language_server/message/text_document/hover.rb +60 -58
- data/lib/solargraph/language_server/message/text_document/signature_help.rb +25 -24
- data/lib/solargraph/language_server/message/text_document/type_definition.rb +27 -25
- data/lib/solargraph/language_server/message/workspace/workspace_symbol.rb +25 -23
- data/lib/solargraph/library.rb +729 -683
- data/lib/solargraph/location.rb +87 -82
- data/lib/solargraph/logging.rb +57 -37
- data/lib/solargraph/parser/comment_ripper.rb +76 -69
- data/lib/solargraph/parser/flow_sensitive_typing.rb +483 -255
- data/lib/solargraph/parser/node_processor/base.rb +122 -92
- data/lib/solargraph/parser/node_processor.rb +63 -62
- data/lib/solargraph/parser/parser_gem/class_methods.rb +167 -149
- data/lib/solargraph/parser/parser_gem/node_chainer.rb +191 -166
- data/lib/solargraph/parser/parser_gem/node_methods.rb +506 -486
- data/lib/solargraph/parser/parser_gem/node_processors/and_node.rb +22 -22
- data/lib/solargraph/parser/parser_gem/node_processors/args_node.rb +61 -59
- data/lib/solargraph/parser/parser_gem/node_processors/begin_node.rb +24 -15
- data/lib/solargraph/parser/parser_gem/node_processors/block_node.rb +46 -46
- data/lib/solargraph/parser/parser_gem/node_processors/def_node.rb +60 -53
- data/lib/solargraph/parser/parser_gem/node_processors/if_node.rb +53 -23
- data/lib/solargraph/parser/parser_gem/node_processors/ivasgn_node.rb +41 -40
- data/lib/solargraph/parser/parser_gem/node_processors/lvasgn_node.rb +30 -29
- data/lib/solargraph/parser/parser_gem/node_processors/masgn_node.rb +61 -59
- data/lib/solargraph/parser/parser_gem/node_processors/opasgn_node.rb +98 -98
- data/lib/solargraph/parser/parser_gem/node_processors/or_node.rb +22 -0
- data/lib/solargraph/parser/parser_gem/node_processors/orasgn_node.rb +17 -17
- data/lib/solargraph/parser/parser_gem/node_processors/resbody_node.rb +39 -38
- data/lib/solargraph/parser/parser_gem/node_processors/sclass_node.rb +53 -52
- data/lib/solargraph/parser/parser_gem/node_processors/send_node.rb +296 -291
- data/lib/solargraph/parser/parser_gem/node_processors/when_node.rb +23 -0
- data/lib/solargraph/parser/parser_gem/node_processors/while_node.rb +33 -29
- data/lib/solargraph/parser/parser_gem/node_processors.rb +74 -70
- data/lib/solargraph/parser/region.rb +75 -69
- data/lib/solargraph/parser/snippet.rb +17 -17
- data/lib/solargraph/pin/base.rb +761 -729
- data/lib/solargraph/pin/base_variable.rb +418 -126
- data/lib/solargraph/pin/block.rb +126 -104
- data/lib/solargraph/pin/breakable.rb +13 -9
- data/lib/solargraph/pin/callable.rb +278 -231
- data/lib/solargraph/pin/closure.rb +68 -72
- data/lib/solargraph/pin/common.rb +94 -79
- data/lib/solargraph/pin/compound_statement.rb +55 -0
- data/lib/solargraph/pin/conversions.rb +124 -123
- data/lib/solargraph/pin/delegated_method.rb +131 -120
- data/lib/solargraph/pin/documenting.rb +115 -114
- data/lib/solargraph/pin/instance_variable.rb +38 -34
- data/lib/solargraph/pin/keyword.rb +16 -20
- data/lib/solargraph/pin/local_variable.rb +31 -75
- data/lib/solargraph/pin/method.rb +720 -672
- data/lib/solargraph/pin/method_alias.rb +42 -34
- data/lib/solargraph/pin/namespace.rb +121 -115
- data/lib/solargraph/pin/parameter.rb +338 -275
- data/lib/solargraph/pin/proxy_type.rb +40 -39
- data/lib/solargraph/pin/reference/override.rb +47 -47
- data/lib/solargraph/pin/reference/superclass.rb +17 -15
- data/lib/solargraph/pin/reference.rb +41 -39
- data/lib/solargraph/pin/search.rb +62 -61
- data/lib/solargraph/pin/signature.rb +69 -61
- data/lib/solargraph/pin/symbol.rb +53 -53
- data/lib/solargraph/pin/until.rb +18 -18
- data/lib/solargraph/pin/while.rb +18 -18
- data/lib/solargraph/pin.rb +46 -44
- data/lib/solargraph/pin_cache.rb +665 -245
- data/lib/solargraph/position.rb +118 -119
- data/lib/solargraph/range.rb +112 -112
- data/lib/solargraph/rbs_map/conversions.rb +846 -823
- data/lib/solargraph/rbs_map/core_map.rb +65 -58
- data/lib/solargraph/rbs_map/stdlib_map.rb +72 -43
- data/lib/solargraph/rbs_map.rb +217 -163
- data/lib/solargraph/shell.rb +397 -352
- data/lib/solargraph/source/chain/call.rb +372 -337
- data/lib/solargraph/source/chain/constant.rb +28 -26
- data/lib/solargraph/source/chain/hash.rb +35 -34
- data/lib/solargraph/source/chain/if.rb +29 -28
- data/lib/solargraph/source/chain/instance_variable.rb +34 -13
- data/lib/solargraph/source/chain/literal.rb +53 -48
- data/lib/solargraph/source/chain/or.rb +31 -23
- data/lib/solargraph/source/chain.rb +294 -291
- data/lib/solargraph/source/change.rb +89 -82
- data/lib/solargraph/source/cursor.rb +172 -166
- data/lib/solargraph/source/source_chainer.rb +204 -194
- data/lib/solargraph/source/updater.rb +59 -55
- data/lib/solargraph/source.rb +524 -498
- data/lib/solargraph/source_map/clip.rb +237 -226
- data/lib/solargraph/source_map/data.rb +37 -34
- data/lib/solargraph/source_map/mapper.rb +282 -259
- data/lib/solargraph/source_map.rb +220 -212
- data/lib/solargraph/type_checker/problem.rb +34 -32
- data/lib/solargraph/type_checker/rules.rb +157 -84
- data/lib/solargraph/type_checker.rb +895 -814
- data/lib/solargraph/version.rb +1 -1
- data/lib/solargraph/workspace/config.rb +257 -255
- data/lib/solargraph/workspace/gemspecs.rb +367 -0
- data/lib/solargraph/workspace/require_paths.rb +98 -97
- data/lib/solargraph/workspace.rb +362 -220
- data/lib/solargraph/yard_map/helpers.rb +45 -44
- data/lib/solargraph/yard_map/mapper/to_method.rb +134 -130
- data/lib/solargraph/yard_map/mapper/to_namespace.rb +32 -31
- data/lib/solargraph/yard_map/mapper.rb +84 -79
- data/lib/solargraph/yardoc.rb +97 -87
- data/lib/solargraph.rb +126 -105
- data/rbs/fills/rubygems/0/dependency.rbs +193 -0
- data/rbs/fills/tuple/tuple.rbs +28 -0
- data/rbs/shims/ast/0/node.rbs +5 -0
- data/rbs/shims/diff-lcs/1.5/diff-lcs.rbs +11 -0
- data/rbs_collection.yaml +1 -1
- data/solargraph.gemspec +2 -1
- metadata +22 -17
- data/lib/solargraph/type_checker/checks.rb +0 -124
- data/lib/solargraph/type_checker/param_def.rb +0 -37
- data/lib/solargraph/yard_map/to_method.rb +0 -89
- data/sig/shims/ast/0/node.rbs +0 -5
- /data/{sig → rbs}/shims/ast/2.4/.rbs_meta.yaml +0 -0
- /data/{sig → rbs}/shims/ast/2.4/ast.rbs +0 -0
- /data/{sig → rbs}/shims/parser/3.2.0.1/builders/default.rbs +0 -0
- /data/{sig → rbs}/shims/parser/3.2.0.1/manifest.yaml +0 -0
- /data/{sig → rbs}/shims/parser/3.2.0.1/parser.rbs +0 -0
- /data/{sig → rbs}/shims/parser/3.2.0.1/polyfill.rbs +0 -0
- /data/{sig → rbs}/shims/thor/1.2.0.1/.rbs_meta.yaml +0 -0
- /data/{sig → rbs}/shims/thor/1.2.0.1/manifest.yaml +0 -0
- /data/{sig → rbs}/shims/thor/1.2.0.1/thor.rbs +0 -0
|
@@ -1,482 +1,632 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Solargraph
|
|
4
|
-
class ComplexType
|
|
5
|
-
# An individual type signature. A complex type can consist of multiple
|
|
6
|
-
# unique types.
|
|
7
|
-
#
|
|
8
|
-
class UniqueType
|
|
9
|
-
include TypeMethods
|
|
10
|
-
include Equality
|
|
11
|
-
|
|
12
|
-
attr_reader :all_params, :subtypes, :key_types
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
#
|
|
20
|
-
#
|
|
21
|
-
#
|
|
22
|
-
#
|
|
23
|
-
#
|
|
24
|
-
# @param
|
|
25
|
-
# @param
|
|
26
|
-
# @
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
parameters_type = PARAMETERS_TYPE_BY_STARTING_TAG.fetch(substring[0])
|
|
50
|
-
if parameters_type == :hash
|
|
51
|
-
raise ComplexTypeError, "Bad hash type: name=#{name}, substring=#{substring}" unless !subs.is_a?(ComplexType) and subs.length == 2 and !subs[0].is_a?(UniqueType) and !subs[1].is_a?(UniqueType)
|
|
52
|
-
key_types.concat(subs[0].map { |u| ComplexType.new([u]) })
|
|
53
|
-
subtypes.concat(subs[1].map { |u| ComplexType.new([u]) })
|
|
54
|
-
elsif parameters_type == :list && name == 'Hash'
|
|
55
|
-
# Treat Hash<A, B> as Hash{A => B}
|
|
56
|
-
if subs.length != 2
|
|
57
|
-
raise ComplexTypeError, "Bad hash type: name=#{name}, substring=#{substring} - must have exactly two parameters"
|
|
58
|
-
end
|
|
59
|
-
key_types.concat(subs[0].map { |u| ComplexType.new([u]) })
|
|
60
|
-
subtypes.concat(subs[1].map { |u| ComplexType.new([u]) })
|
|
61
|
-
else
|
|
62
|
-
subtypes.concat subs
|
|
63
|
-
end
|
|
64
|
-
end
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
# @param
|
|
70
|
-
# @param
|
|
71
|
-
# @param
|
|
72
|
-
# @param
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
@
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
@
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
@
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
@
|
|
89
|
-
@all_params
|
|
90
|
-
@all_params.concat @
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
#
|
|
96
|
-
#
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
t
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
return
|
|
131
|
-
return
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
end
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
#
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
# @
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
end
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
# @param
|
|
247
|
-
def
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
# @
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
[
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
# @return [
|
|
387
|
-
def
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
end
|
|
412
|
-
|
|
413
|
-
#
|
|
414
|
-
#
|
|
415
|
-
# @param
|
|
416
|
-
# @
|
|
417
|
-
# @return [
|
|
418
|
-
def
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
#
|
|
437
|
-
#
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Solargraph
|
|
4
|
+
class ComplexType
|
|
5
|
+
# An individual type signature. A complex type can consist of multiple
|
|
6
|
+
# unique types.
|
|
7
|
+
#
|
|
8
|
+
class UniqueType
|
|
9
|
+
include TypeMethods
|
|
10
|
+
include Equality
|
|
11
|
+
|
|
12
|
+
attr_reader :all_params, :subtypes, :key_types
|
|
13
|
+
|
|
14
|
+
protected def equality_fields
|
|
15
|
+
[@name, @all_params, @subtypes, @key_types]
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
# Create a UniqueType with the specified name and an optional substring.
|
|
19
|
+
# The substring is the parameter section of a parametrized type, e.g.,
|
|
20
|
+
# for the type `Array<String>`, the name is `Array` and the substring is
|
|
21
|
+
# `<String>`.
|
|
22
|
+
#
|
|
23
|
+
# @param name [String] The name of the type
|
|
24
|
+
# @param substring [String] The substring of the type
|
|
25
|
+
# @param make_rooted [Boolean, nil]
|
|
26
|
+
# @return [UniqueType]
|
|
27
|
+
def self.parse name, substring = '', make_rooted: nil
|
|
28
|
+
if name.start_with?(':::')
|
|
29
|
+
raise ComplexTypeError, "Illegal prefix: #{name}"
|
|
30
|
+
end
|
|
31
|
+
if name.start_with?('::')
|
|
32
|
+
name = name[2..-1]
|
|
33
|
+
rooted = true
|
|
34
|
+
elsif !can_root_name?(name)
|
|
35
|
+
rooted = true
|
|
36
|
+
else
|
|
37
|
+
rooted = false
|
|
38
|
+
end
|
|
39
|
+
rooted = make_rooted unless make_rooted.nil?
|
|
40
|
+
|
|
41
|
+
# @type [Array<ComplexType>]
|
|
42
|
+
key_types = []
|
|
43
|
+
# @type [Array<ComplexType>]
|
|
44
|
+
subtypes = []
|
|
45
|
+
parameters_type = nil
|
|
46
|
+
unless substring.empty?
|
|
47
|
+
subs = ComplexType.parse(substring[1..-2], partial: true)
|
|
48
|
+
# @sg-ignore Need to add nil check here
|
|
49
|
+
parameters_type = PARAMETERS_TYPE_BY_STARTING_TAG.fetch(substring[0])
|
|
50
|
+
if parameters_type == :hash
|
|
51
|
+
raise ComplexTypeError, "Bad hash type: name=#{name}, substring=#{substring}" unless !subs.is_a?(ComplexType) and subs.length == 2 and !subs[0].is_a?(UniqueType) and !subs[1].is_a?(UniqueType)
|
|
52
|
+
key_types.concat(subs[0].map { |u| ComplexType.new([u]) })
|
|
53
|
+
subtypes.concat(subs[1].map { |u| ComplexType.new([u]) })
|
|
54
|
+
elsif parameters_type == :list && name == 'Hash'
|
|
55
|
+
# Treat Hash<A, B> as Hash{A => B}
|
|
56
|
+
if subs.length != 2
|
|
57
|
+
raise ComplexTypeError, "Bad hash type: name=#{name}, substring=#{substring} - must have exactly two parameters"
|
|
58
|
+
end
|
|
59
|
+
key_types.concat(subs[0].map { |u| ComplexType.new([u]) })
|
|
60
|
+
subtypes.concat(subs[1].map { |u| ComplexType.new([u]) })
|
|
61
|
+
else
|
|
62
|
+
subtypes.concat subs
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
# @sg-ignore Need to add nil check here
|
|
66
|
+
new(name, key_types, subtypes, rooted: rooted, parameters_type: parameters_type)
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
# @param name [String]
|
|
70
|
+
# @param key_types [Array<ComplexType>]
|
|
71
|
+
# @param subtypes [Array<ComplexType>]
|
|
72
|
+
# @param rooted [Boolean]
|
|
73
|
+
# @param parameters_type [Symbol, nil]
|
|
74
|
+
def initialize(name, key_types = [], subtypes = [], rooted:, parameters_type: nil)
|
|
75
|
+
if parameters_type.nil?
|
|
76
|
+
raise "You must supply parameters_type if you provide parameters" unless key_types.empty? && subtypes.empty?
|
|
77
|
+
end
|
|
78
|
+
raise "Please remove leading :: and set rooted instead - #{name.inspect}" if name.start_with?('::')
|
|
79
|
+
@name = name
|
|
80
|
+
@parameters_type = parameters_type
|
|
81
|
+
if implicit_union?
|
|
82
|
+
@key_types = key_types.uniq
|
|
83
|
+
@subtypes = subtypes.uniq
|
|
84
|
+
else
|
|
85
|
+
@key_types = key_types
|
|
86
|
+
@subtypes = subtypes
|
|
87
|
+
end
|
|
88
|
+
@rooted = rooted
|
|
89
|
+
@all_params = []
|
|
90
|
+
@all_params.concat @key_types
|
|
91
|
+
@all_params.concat @subtypes
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def implicit_union?
|
|
95
|
+
# @todo use api_map to establish number of generics in type;
|
|
96
|
+
# if only one is allowed but multiple are passed in, treat
|
|
97
|
+
# those as implicit unions
|
|
98
|
+
['Hash', 'Array', 'Set', '_ToAry', 'Enumerable', '_Each'].include?(name) && parameters_type != :fixed
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
def to_s
|
|
102
|
+
tag
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
# @return [self]
|
|
106
|
+
def simplify_literals
|
|
107
|
+
transform do |t|
|
|
108
|
+
next t unless t.literal?
|
|
109
|
+
t.recreate(new_name: t.non_literal_name)
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
# @param exclude_types [ComplexType, nil]
|
|
114
|
+
# @param api_map [ApiMap]
|
|
115
|
+
# @return [ComplexType, self]
|
|
116
|
+
def exclude exclude_types, api_map
|
|
117
|
+
return self if exclude_types.nil?
|
|
118
|
+
|
|
119
|
+
types = items - exclude_types.items
|
|
120
|
+
types = [ComplexType::UniqueType::UNDEFINED] if types.empty?
|
|
121
|
+
ComplexType.new(types)
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
# @see https://en.wikipedia.org/wiki/Intersection_type
|
|
125
|
+
#
|
|
126
|
+
# @param intersection_type [ComplexType, ComplexType::UniqueType, nil]
|
|
127
|
+
# @param api_map [ApiMap]
|
|
128
|
+
# @return [self, ComplexType]
|
|
129
|
+
def intersect_with intersection_type, api_map
|
|
130
|
+
return self if intersection_type.nil?
|
|
131
|
+
return intersection_type if undefined?
|
|
132
|
+
types = []
|
|
133
|
+
# try to find common types via conformance
|
|
134
|
+
items.each do |ut|
|
|
135
|
+
intersection_type.each do |int_type|
|
|
136
|
+
if ut.conforms_to?(api_map, int_type, :assignment)
|
|
137
|
+
types << ut
|
|
138
|
+
elsif int_type.conforms_to?(api_map, ut, :assignment)
|
|
139
|
+
types << int_type
|
|
140
|
+
end
|
|
141
|
+
end
|
|
142
|
+
end
|
|
143
|
+
types = [ComplexType::UniqueType::UNDEFINED] if types.empty?
|
|
144
|
+
ComplexType.new(types)
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
def simplifyable_literal?
|
|
148
|
+
literal? && name != 'nil'
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
def literal?
|
|
152
|
+
non_literal_name != name
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
# @return [String]
|
|
156
|
+
def non_literal_name
|
|
157
|
+
@non_literal_name ||= determine_non_literal_name
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
# @return [self]
|
|
161
|
+
def without_nil
|
|
162
|
+
return UniqueType::UNDEFINED if nil_type?
|
|
163
|
+
|
|
164
|
+
self
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
# @return [String]
|
|
168
|
+
def determine_non_literal_name
|
|
169
|
+
# https://github.com/ruby/rbs/blob/master/docs/syntax.md
|
|
170
|
+
#
|
|
171
|
+
# _literal_ ::= _string-literal_
|
|
172
|
+
# | _symbol-literal_
|
|
173
|
+
# | _integer-literal_
|
|
174
|
+
# | `true`
|
|
175
|
+
# | `false`
|
|
176
|
+
return name if name.empty?
|
|
177
|
+
return 'NilClass' if name == 'nil'
|
|
178
|
+
return 'Boolean' if ['true', 'false'].include?(name)
|
|
179
|
+
return 'Symbol' if name[0] == ':'
|
|
180
|
+
# @sg-ignore Need to add nil check here
|
|
181
|
+
return 'String' if ['"', "'"].include?(name[0])
|
|
182
|
+
return 'Integer' if name.match?(/^-?\d+$/)
|
|
183
|
+
name
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
def eql?(other)
|
|
187
|
+
self.class == other.class &&
|
|
188
|
+
# @sg-ignore flow sensitive typing should support .class == .class
|
|
189
|
+
@name == other.name &&
|
|
190
|
+
# @sg-ignore flow sensitive typing should support .class == .class
|
|
191
|
+
@key_types == other.key_types &&
|
|
192
|
+
# @sg-ignore flow sensitive typing should support .class == .class
|
|
193
|
+
@subtypes == other.subtypes &&
|
|
194
|
+
# @sg-ignore flow sensitive typing should support .class == .class
|
|
195
|
+
@rooted == other.rooted? &&
|
|
196
|
+
# @sg-ignore flow sensitive typing should support .class == .class
|
|
197
|
+
@all_params == other.all_params &&
|
|
198
|
+
# @sg-ignore flow sensitive typing should support .class == .class
|
|
199
|
+
@parameters_type == other.parameters_type
|
|
200
|
+
end
|
|
201
|
+
|
|
202
|
+
def ==(other)
|
|
203
|
+
eql?(other)
|
|
204
|
+
end
|
|
205
|
+
|
|
206
|
+
# https://www.playfulpython.com/type-hinting-covariance-contra-variance/
|
|
207
|
+
|
|
208
|
+
# "[Expected] type variables that are COVARIANT can be substituted with
|
|
209
|
+
# a more specific [inferred] type without causing errors"
|
|
210
|
+
#
|
|
211
|
+
# "[Expected] type variables that are CONTRAVARIANT can be substituted
|
|
212
|
+
# with a more general [inferred] type without causing errors"
|
|
213
|
+
#
|
|
214
|
+
# "[Expected] types where neither is possible are INVARIANT"
|
|
215
|
+
#
|
|
216
|
+
# @param _situation [:method_call, :return_type]
|
|
217
|
+
# @param default [Symbol] The default variance to return if the type is not one of the special cases
|
|
218
|
+
#
|
|
219
|
+
# @return [:invariant, :covariant, :contravariant]
|
|
220
|
+
def parameter_variance _situation, default = :covariant
|
|
221
|
+
# @todo RBS can specify variance - maybe we can use that info
|
|
222
|
+
# and also let folks specify?
|
|
223
|
+
#
|
|
224
|
+
# Array/Set: ideally invariant, since we don't know if user is
|
|
225
|
+
# going to add new stuff into it or read it. But we don't
|
|
226
|
+
# have a way to specify, so we use covariant
|
|
227
|
+
# Enumerable: covariant: can't be changed, so we can pass
|
|
228
|
+
# in more specific subtypes
|
|
229
|
+
# Hash: read-only would be covariant, read-write would be
|
|
230
|
+
# invariant if we could distinguish that - should default to
|
|
231
|
+
# covariant
|
|
232
|
+
# contravariant?: Proc - can be changed, so we can pass
|
|
233
|
+
# in less specific super types
|
|
234
|
+
if ['Hash', 'Tuple', 'Array', 'Set', 'Enumerable'].include?(name) && fixed_parameters?
|
|
235
|
+
:covariant
|
|
236
|
+
else
|
|
237
|
+
default
|
|
238
|
+
end
|
|
239
|
+
end
|
|
240
|
+
|
|
241
|
+
# Whether this is an RBS interface like _ToAry or _Each.
|
|
242
|
+
def interface?
|
|
243
|
+
name.start_with?('_')
|
|
244
|
+
end
|
|
245
|
+
|
|
246
|
+
# @param other [UniqueType]
|
|
247
|
+
def erased_version_of?(other)
|
|
248
|
+
name == other.name && (all_params.empty? || all_params.all?(&:undefined?))
|
|
249
|
+
end
|
|
250
|
+
|
|
251
|
+
# @param api_map [ApiMap]
|
|
252
|
+
# @param expected [ComplexType::UniqueType, ComplexType]
|
|
253
|
+
# @param situation [:method_call, :assignment, :return_type]
|
|
254
|
+
# @param rules [Array<:allow_subtype_skew, :allow_empty_params, :allow_reverse_match, :allow_any_match, :allow_undefined, :allow_unresolved_generic>]
|
|
255
|
+
# @param variance [:invariant, :covariant, :contravariant]
|
|
256
|
+
def conforms_to?(api_map, expected, situation, rules = [],
|
|
257
|
+
variance: erased_variance(situation))
|
|
258
|
+
return true if undefined? && rules.include?(:allow_undefined)
|
|
259
|
+
|
|
260
|
+
# @todo teach this to validate duck types as inferred type
|
|
261
|
+
return true if duck_type?
|
|
262
|
+
|
|
263
|
+
# complex types as expectations are unions - we only need to
|
|
264
|
+
# match one of their unique types
|
|
265
|
+
expected.any? do |expected_unique_type|
|
|
266
|
+
# :nocov:
|
|
267
|
+
unless expected_unique_type.instance_of?(UniqueType)
|
|
268
|
+
raise "Expected type must be a UniqueType, got #{expected_unique_type.class} in #{expected.inspect}"
|
|
269
|
+
end
|
|
270
|
+
# :nocov:
|
|
271
|
+
conformance = Conformance.new(api_map, self, expected_unique_type, situation,
|
|
272
|
+
rules, variance: variance)
|
|
273
|
+
conformance.conforms_to_unique_type?
|
|
274
|
+
end
|
|
275
|
+
end
|
|
276
|
+
|
|
277
|
+
def hash
|
|
278
|
+
[self.class, @name, @key_types, @sub_types, @rooted, @all_params, @parameters_type].hash
|
|
279
|
+
end
|
|
280
|
+
|
|
281
|
+
# @return [self]
|
|
282
|
+
def erase_parameters
|
|
283
|
+
UniqueType.new(name, rooted: rooted?, parameters_type: parameters_type)
|
|
284
|
+
end
|
|
285
|
+
|
|
286
|
+
# @return [Array<UniqueType>]
|
|
287
|
+
def items
|
|
288
|
+
[self]
|
|
289
|
+
end
|
|
290
|
+
|
|
291
|
+
# @return [String]
|
|
292
|
+
def rbs_name
|
|
293
|
+
if name == 'undefined'
|
|
294
|
+
'untyped'
|
|
295
|
+
elsif literal?
|
|
296
|
+
name
|
|
297
|
+
else
|
|
298
|
+
rooted_name
|
|
299
|
+
end
|
|
300
|
+
end
|
|
301
|
+
|
|
302
|
+
# @return [String]
|
|
303
|
+
def desc
|
|
304
|
+
rooted_tags
|
|
305
|
+
end
|
|
306
|
+
|
|
307
|
+
# @sg-ignore Need better if/elseanalysis
|
|
308
|
+
# @return [String]
|
|
309
|
+
def to_rbs
|
|
310
|
+
if duck_type?
|
|
311
|
+
'untyped'
|
|
312
|
+
elsif name == 'Boolean'
|
|
313
|
+
'bool'
|
|
314
|
+
elsif name.downcase == 'nil'
|
|
315
|
+
'nil'
|
|
316
|
+
elsif name == GENERIC_TAG_NAME
|
|
317
|
+
all_params.first&.name
|
|
318
|
+
elsif ['Class', 'Module'].include?(name)
|
|
319
|
+
rbs_name
|
|
320
|
+
elsif ['Tuple', 'Array'].include?(name) && fixed_parameters?
|
|
321
|
+
# tuples don't have a name; they're just [foo, bar, baz].
|
|
322
|
+
if substring == '()'
|
|
323
|
+
# but there are no zero element tuples, so we go with an array
|
|
324
|
+
if rooted?
|
|
325
|
+
'::Array[]'
|
|
326
|
+
else
|
|
327
|
+
'Array[]'
|
|
328
|
+
end
|
|
329
|
+
else
|
|
330
|
+
# already generated surrounded by []
|
|
331
|
+
parameters_as_rbs
|
|
332
|
+
end
|
|
333
|
+
else
|
|
334
|
+
"#{rbs_name}#{parameters_as_rbs}"
|
|
335
|
+
end
|
|
336
|
+
end
|
|
337
|
+
|
|
338
|
+
# @return [Boolean]
|
|
339
|
+
def parameters?
|
|
340
|
+
!all_params.empty?
|
|
341
|
+
end
|
|
342
|
+
|
|
343
|
+
# @param types [Array<UniqueType, ComplexType>]
|
|
344
|
+
# @return [String]
|
|
345
|
+
def rbs_union(types)
|
|
346
|
+
if types.length == 1
|
|
347
|
+
types.first.to_rbs
|
|
348
|
+
else
|
|
349
|
+
"(#{types.map(&:to_rbs).join(' | ')})"
|
|
350
|
+
end
|
|
351
|
+
end
|
|
352
|
+
|
|
353
|
+
# @return [String]
|
|
354
|
+
def parameters_as_rbs
|
|
355
|
+
return '' unless parameters?
|
|
356
|
+
|
|
357
|
+
return "[#{all_params.map(&:to_rbs).join(', ')}]" if key_types.empty?
|
|
358
|
+
|
|
359
|
+
# handle, e.g., Hash[K, V] case
|
|
360
|
+
key_types_str = rbs_union(key_types)
|
|
361
|
+
subtypes_str = rbs_union(subtypes)
|
|
362
|
+
"[#{key_types_str}, #{subtypes_str}]"
|
|
363
|
+
end
|
|
364
|
+
|
|
365
|
+
def generic?
|
|
366
|
+
name == GENERIC_TAG_NAME || all_params.any?(&:generic?)
|
|
367
|
+
end
|
|
368
|
+
|
|
369
|
+
def nullable?
|
|
370
|
+
nil_type?
|
|
371
|
+
end
|
|
372
|
+
|
|
373
|
+
# @yieldreturn [Boolean]
|
|
374
|
+
def all? &block
|
|
375
|
+
block.yield self
|
|
376
|
+
end
|
|
377
|
+
|
|
378
|
+
# @return [UniqueType]
|
|
379
|
+
def downcast_to_literal_if_possible
|
|
380
|
+
SINGLE_SUBTYPE.fetch(rooted_tag, self)
|
|
381
|
+
end
|
|
382
|
+
|
|
383
|
+
# @param generics_to_resolve [Enumerable<String>]
|
|
384
|
+
# @param context_type [ComplexType, UniqueType, nil]
|
|
385
|
+
# @param resolved_generic_values [Hash{String => ComplexType, ComplexType::UniqueType}] Added to as types are encountered or resolved
|
|
386
|
+
# @return [UniqueType, ComplexType]
|
|
387
|
+
def resolve_generics_from_context generics_to_resolve, context_type, resolved_generic_values: {}
|
|
388
|
+
if name == ComplexType::GENERIC_TAG_NAME
|
|
389
|
+
type_param = subtypes.first&.name
|
|
390
|
+
# @sg-ignore flow sensitive typing needs to eliminate literal from union with [:bar].include?(foo)
|
|
391
|
+
return self unless generics_to_resolve.include? type_param
|
|
392
|
+
# @sg-ignore flow sensitive typing needs to eliminate literal from union with [:bar].include?(foo)
|
|
393
|
+
unless context_type.nil? || !resolved_generic_values[type_param].nil?
|
|
394
|
+
new_binding = true
|
|
395
|
+
# @sg-ignore flow sensitive typing needs to eliminate literal from union with [:bar].include?(foo)
|
|
396
|
+
resolved_generic_values[type_param] = context_type
|
|
397
|
+
end
|
|
398
|
+
if new_binding
|
|
399
|
+
resolved_generic_values.transform_values! do |complex_type|
|
|
400
|
+
complex_type.resolve_generics_from_context(generics_to_resolve, nil, resolved_generic_values: resolved_generic_values)
|
|
401
|
+
end
|
|
402
|
+
end
|
|
403
|
+
# @sg-ignore flow sensitive typing needs to eliminate literal from union with [:bar].include?(foo)
|
|
404
|
+
return resolved_generic_values[type_param] || self
|
|
405
|
+
end
|
|
406
|
+
|
|
407
|
+
# @todo typechecking should complain when the method being called has no @yieldparam tag
|
|
408
|
+
new_key_types = resolve_param_generics_from_context(generics_to_resolve, context_type, resolved_generic_values, &:key_types)
|
|
409
|
+
new_subtypes = resolve_param_generics_from_context(generics_to_resolve, context_type, resolved_generic_values, &:subtypes)
|
|
410
|
+
recreate(new_key_types: new_key_types, new_subtypes: new_subtypes)
|
|
411
|
+
end
|
|
412
|
+
|
|
413
|
+
# @param generics_to_resolve [Enumerable<String>]
|
|
414
|
+
# @param context_type [UniqueType, ComplexType, nil]
|
|
415
|
+
# @param resolved_generic_values [Hash{String => ComplexType}]
|
|
416
|
+
# @yieldreturn [Array<ComplexType>]
|
|
417
|
+
# @return [Array<ComplexType>]
|
|
418
|
+
def resolve_param_generics_from_context(generics_to_resolve, context_type, resolved_generic_values)
|
|
419
|
+
types = yield self
|
|
420
|
+
types.each_with_index.flat_map do |ct, i|
|
|
421
|
+
ct.items.flat_map do |ut|
|
|
422
|
+
context_params = yield context_type if context_type
|
|
423
|
+
if context_params && context_params[i]
|
|
424
|
+
type_arg = context_params[i]
|
|
425
|
+
type_arg.map do |new_unique_context_type|
|
|
426
|
+
ut.resolve_generics_from_context generics_to_resolve, new_unique_context_type, resolved_generic_values: resolved_generic_values
|
|
427
|
+
end
|
|
428
|
+
else
|
|
429
|
+
ut.resolve_generics_from_context generics_to_resolve, nil, resolved_generic_values: resolved_generic_values
|
|
430
|
+
end
|
|
431
|
+
end
|
|
432
|
+
end
|
|
433
|
+
end
|
|
434
|
+
|
|
435
|
+
# Probe the concrete type for each of the generic type
|
|
436
|
+
# parameters used in this type, and return a new type if
|
|
437
|
+
# possible.
|
|
438
|
+
#
|
|
439
|
+
# @param definitions [Pin::Namespace, Pin::Method] The module/class/method which uses generic types
|
|
440
|
+
# @param context_type [ComplexType] The receiver type
|
|
441
|
+
# @return [UniqueType, ComplexType]
|
|
442
|
+
def resolve_generics definitions, context_type
|
|
443
|
+
return self if definitions.nil? || definitions.generics.empty?
|
|
444
|
+
|
|
445
|
+
transform(name) do |t|
|
|
446
|
+
if t.name == GENERIC_TAG_NAME
|
|
447
|
+
generic_name = t.subtypes.first&.name
|
|
448
|
+
idx = definitions.generics.index(generic_name)
|
|
449
|
+
next t if idx.nil?
|
|
450
|
+
if context_type.parameters_type == :hash
|
|
451
|
+
if idx == 0
|
|
452
|
+
next ComplexType.new(context_type.key_types)
|
|
453
|
+
elsif idx == 1
|
|
454
|
+
next ComplexType.new(context_type.subtypes)
|
|
455
|
+
else
|
|
456
|
+
next ComplexType::UNDEFINED
|
|
457
|
+
end
|
|
458
|
+
elsif context_type.all?(&:implicit_union?)
|
|
459
|
+
if idx == 0 && !context_type.all_params.empty?
|
|
460
|
+
ComplexType.new(context_type.all_params)
|
|
461
|
+
else
|
|
462
|
+
ComplexType::UNDEFINED
|
|
463
|
+
end
|
|
464
|
+
else
|
|
465
|
+
# @sg-ignore Need to add nil check here
|
|
466
|
+
context_type.all_params[idx] || definitions.generic_defaults[generic_name] || ComplexType::UNDEFINED
|
|
467
|
+
end
|
|
468
|
+
else
|
|
469
|
+
t
|
|
470
|
+
end
|
|
471
|
+
end
|
|
472
|
+
end
|
|
473
|
+
|
|
474
|
+
# @yieldparam t [self]
|
|
475
|
+
# @yieldreturn [self]
|
|
476
|
+
# @return [Array<self>]
|
|
477
|
+
def map &block
|
|
478
|
+
[block.yield(self)]
|
|
479
|
+
end
|
|
480
|
+
|
|
481
|
+
# @yieldparam t [self]
|
|
482
|
+
# @yieldreturn [self]
|
|
483
|
+
# @return [Enumerable<self>]
|
|
484
|
+
def each &block
|
|
485
|
+
[self].each &block
|
|
486
|
+
end
|
|
487
|
+
|
|
488
|
+
# @return [Array<UniqueType>]
|
|
489
|
+
def to_a
|
|
490
|
+
[self]
|
|
491
|
+
end
|
|
492
|
+
|
|
493
|
+
# @param new_name [String, nil]
|
|
494
|
+
# @param make_rooted [Boolean, nil]
|
|
495
|
+
# @param new_key_types [Array<ComplexType>, nil]
|
|
496
|
+
# @param rooted [Boolean, nil]
|
|
497
|
+
# @param new_subtypes [Array<ComplexType>, nil]
|
|
498
|
+
# @return [self]
|
|
499
|
+
def recreate(new_name: nil, make_rooted: nil, new_key_types: nil, new_subtypes: nil)
|
|
500
|
+
raise "Please remove leading :: and set rooted instead - #{new_name}" if new_name&.start_with?('::')
|
|
501
|
+
|
|
502
|
+
new_name ||= name
|
|
503
|
+
new_key_types ||= @key_types
|
|
504
|
+
new_subtypes ||= @subtypes
|
|
505
|
+
make_rooted = @rooted if make_rooted.nil?
|
|
506
|
+
# @sg-ignore flow sensitive typing needs better handling of ||= on lvars
|
|
507
|
+
UniqueType.new(new_name, new_key_types, new_subtypes, rooted: make_rooted, parameters_type: parameters_type)
|
|
508
|
+
end
|
|
509
|
+
|
|
510
|
+
# @return [String]
|
|
511
|
+
def rooted_tags
|
|
512
|
+
rooted_tag
|
|
513
|
+
end
|
|
514
|
+
|
|
515
|
+
# @return [String]
|
|
516
|
+
def tags
|
|
517
|
+
tag
|
|
518
|
+
end
|
|
519
|
+
|
|
520
|
+
# @return [self]
|
|
521
|
+
def force_rooted
|
|
522
|
+
transform do |t|
|
|
523
|
+
t.recreate(make_rooted: true)
|
|
524
|
+
end
|
|
525
|
+
end
|
|
526
|
+
|
|
527
|
+
# Apply the given transformation to each subtype and then finally to this type
|
|
528
|
+
#
|
|
529
|
+
# @param new_name [String, nil]
|
|
530
|
+
# @yieldparam t [UniqueType]
|
|
531
|
+
# @yieldreturn [self]
|
|
532
|
+
# @return [self]
|
|
533
|
+
def transform(new_name = nil, &transform_type)
|
|
534
|
+
raise "Please remove leading :: and set rooted with recreate() instead - #{new_name}" if new_name&.start_with?('::')
|
|
535
|
+
if name == ComplexType::GENERIC_TAG_NAME
|
|
536
|
+
# doesn't make sense to manipulate the name of the generic
|
|
537
|
+
new_key_types = @key_types
|
|
538
|
+
new_subtypes = @subtypes
|
|
539
|
+
else
|
|
540
|
+
new_key_types = @key_types.flat_map { |ct| ct.items.map { |ut| ut.transform(&transform_type) } }
|
|
541
|
+
new_subtypes = @subtypes.flat_map { |ct| ct.items.map { |ut| ut.transform(&transform_type) } }
|
|
542
|
+
end
|
|
543
|
+
new_type = recreate(new_name: new_name || name, new_key_types: new_key_types, new_subtypes: new_subtypes, make_rooted: @rooted)
|
|
544
|
+
yield new_type
|
|
545
|
+
end
|
|
546
|
+
|
|
547
|
+
# Generate a ComplexType that fully qualifies this type's namespaces.
|
|
548
|
+
#
|
|
549
|
+
# @param api_map [ApiMap] The ApiMap that performs qualification
|
|
550
|
+
# @param context [String] The namespace from which to resolve names
|
|
551
|
+
# @return [self, ComplexType, UniqueType] The generated ComplexType
|
|
552
|
+
def qualify api_map, *gates
|
|
553
|
+
transform do |t|
|
|
554
|
+
next t if t.name == GENERIC_TAG_NAME
|
|
555
|
+
next t if t.duck_type? || t.void? || t.undefined? || t.literal?
|
|
556
|
+
open = t.rooted? ? [''] : gates
|
|
557
|
+
fqns = api_map.qualify(t.non_literal_name, *open)
|
|
558
|
+
if fqns.nil?
|
|
559
|
+
next UniqueType::BOOLEAN if t.tag == 'Boolean'
|
|
560
|
+
next UniqueType::UNDEFINED
|
|
561
|
+
end
|
|
562
|
+
t.recreate(new_name: fqns, make_rooted: true)
|
|
563
|
+
end
|
|
564
|
+
end
|
|
565
|
+
|
|
566
|
+
def selfy?
|
|
567
|
+
@name == 'self' || @key_types.any?(&:selfy?) || @subtypes.any?(&:selfy?)
|
|
568
|
+
end
|
|
569
|
+
|
|
570
|
+
# @param dst [ComplexType]
|
|
571
|
+
# @return [self]
|
|
572
|
+
def self_to_type dst
|
|
573
|
+
object_type_dst = dst.reduce_class_type
|
|
574
|
+
transform do |t|
|
|
575
|
+
next t if t.name != 'self'
|
|
576
|
+
object_type_dst
|
|
577
|
+
end
|
|
578
|
+
end
|
|
579
|
+
|
|
580
|
+
# @yieldreturn [Boolean]
|
|
581
|
+
def any? &block
|
|
582
|
+
block.yield self
|
|
583
|
+
end
|
|
584
|
+
|
|
585
|
+
# @return [ComplexType]
|
|
586
|
+
def reduce_class_type
|
|
587
|
+
new_items = items.flat_map do |type|
|
|
588
|
+
next type unless ['Module', 'Class'].include?(type.name)
|
|
589
|
+
next type if type.all_params.empty?
|
|
590
|
+
|
|
591
|
+
type.all_params
|
|
592
|
+
end
|
|
593
|
+
ComplexType.new(new_items)
|
|
594
|
+
end
|
|
595
|
+
|
|
596
|
+
def all_rooted?
|
|
597
|
+
return true if name == GENERIC_TAG_NAME
|
|
598
|
+
rooted? && all_params.all?(&:rooted?)
|
|
599
|
+
end
|
|
600
|
+
|
|
601
|
+
def rooted?
|
|
602
|
+
!can_root_name? || @rooted
|
|
603
|
+
end
|
|
604
|
+
|
|
605
|
+
# @param name_to_check [String]
|
|
606
|
+
def can_root_name?(name_to_check = name)
|
|
607
|
+
self.class.can_root_name?(name_to_check)
|
|
608
|
+
end
|
|
609
|
+
|
|
610
|
+
# @param name [String]
|
|
611
|
+
def self.can_root_name?(name)
|
|
612
|
+
# name is not lowercase
|
|
613
|
+
!name.empty? && name != name.downcase
|
|
614
|
+
end
|
|
615
|
+
|
|
616
|
+
UNDEFINED = UniqueType.new('undefined', rooted: false)
|
|
617
|
+
BOOLEAN = UniqueType.new('Boolean', rooted: true)
|
|
618
|
+
TRUE = UniqueType.new('true', rooted: true)
|
|
619
|
+
FALSE = UniqueType.new('false', rooted: true)
|
|
620
|
+
NIL = UniqueType.new('nil', rooted: true)
|
|
621
|
+
# @type [Hash{String => UniqueType}]
|
|
622
|
+
SINGLE_SUBTYPE = {
|
|
623
|
+
'::TrueClass' => UniqueType::TRUE,
|
|
624
|
+
'::FalseClass' => UniqueType::FALSE,
|
|
625
|
+
'::NilClass' => UniqueType::NIL
|
|
626
|
+
}.freeze
|
|
627
|
+
|
|
628
|
+
|
|
629
|
+
include Logging
|
|
630
|
+
end
|
|
631
|
+
end
|
|
632
|
+
end
|