solargraph 0.58.2 → 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/.gitignore +0 -1
- data/.rubocop_todo.yml +27 -49
- data/CHANGELOG.md +1 -7
- data/README.md +3 -3
- data/Rakefile +1 -0
- data/lib/solargraph/api_map/cache.rb +3 -3
- data/lib/solargraph/api_map/constants.rb +13 -3
- data/lib/solargraph/api_map/index.rb +22 -11
- data/lib/solargraph/api_map/source_to_yard.rb +13 -1
- data/lib/solargraph/api_map/store.rb +11 -8
- data/lib/solargraph/api_map.rb +105 -50
- data/lib/solargraph/complex_type/conformance.rb +176 -0
- data/lib/solargraph/complex_type/type_methods.rb +16 -2
- data/lib/solargraph/complex_type/unique_type.rb +170 -20
- data/lib/solargraph/complex_type.rb +119 -14
- data/lib/solargraph/convention/data_definition/data_definition_node.rb +3 -1
- data/lib/solargraph/convention/data_definition.rb +4 -1
- data/lib/solargraph/convention/struct_definition/struct_assignment_node.rb +1 -0
- data/lib/solargraph/convention/struct_definition/struct_definition_node.rb +1 -0
- data/lib/solargraph/convention/struct_definition.rb +5 -1
- data/lib/solargraph/diagnostics/require_not_found.rb +1 -0
- data/lib/solargraph/diagnostics/rubocop.rb +1 -0
- data/lib/solargraph/diagnostics/rubocop_helpers.rb +2 -0
- data/lib/solargraph/diagnostics/type_check.rb +1 -0
- data/lib/solargraph/doc_map.rb +134 -373
- data/lib/solargraph/equality.rb +1 -1
- data/lib/solargraph/gem_pins.rb +14 -15
- data/lib/solargraph/language_server/host/diagnoser.rb +89 -89
- data/lib/solargraph/language_server/host/dispatch.rb +1 -0
- data/lib/solargraph/language_server/host/message_worker.rb +2 -1
- data/lib/solargraph/language_server/host/sources.rb +1 -0
- data/lib/solargraph/language_server/host.rb +6 -1
- data/lib/solargraph/language_server/message/extended/check_gem_version.rb +2 -7
- data/lib/solargraph/language_server/message/extended/document.rb +1 -0
- data/lib/solargraph/language_server/message/text_document/completion.rb +2 -0
- data/lib/solargraph/language_server/message/text_document/definition.rb +2 -0
- data/lib/solargraph/language_server/message/text_document/document_symbol.rb +2 -0
- data/lib/solargraph/language_server/message/text_document/formatting.rb +2 -0
- data/lib/solargraph/language_server/message/text_document/hover.rb +2 -0
- data/lib/solargraph/language_server/message/text_document/signature_help.rb +1 -0
- data/lib/solargraph/language_server/message/text_document/type_definition.rb +2 -0
- data/lib/solargraph/language_server/message/workspace/workspace_symbol.rb +2 -0
- data/lib/solargraph/library.rb +59 -13
- data/lib/solargraph/location.rb +9 -4
- data/lib/solargraph/logging.rb +21 -1
- data/lib/solargraph/parser/comment_ripper.rb +7 -0
- data/lib/solargraph/parser/flow_sensitive_typing.rb +330 -102
- data/lib/solargraph/parser/node_processor/base.rb +32 -2
- data/lib/solargraph/parser/node_processor.rb +7 -6
- data/lib/solargraph/parser/parser_gem/class_methods.rb +28 -10
- data/lib/solargraph/parser/parser_gem/node_chainer.rb +31 -6
- data/lib/solargraph/parser/parser_gem/node_methods.rb +27 -7
- data/lib/solargraph/parser/parser_gem/node_processors/and_node.rb +4 -4
- data/lib/solargraph/parser/parser_gem/node_processors/args_node.rb +2 -0
- data/lib/solargraph/parser/parser_gem/node_processors/begin_node.rb +9 -0
- data/lib/solargraph/parser/parser_gem/node_processors/block_node.rb +11 -11
- data/lib/solargraph/parser/parser_gem/node_processors/def_node.rb +7 -0
- data/lib/solargraph/parser/parser_gem/node_processors/if_node.rb +36 -6
- data/lib/solargraph/parser/parser_gem/node_processors/ivasgn_node.rb +3 -2
- data/lib/solargraph/parser/parser_gem/node_processors/lvasgn_node.rb +1 -0
- data/lib/solargraph/parser/parser_gem/node_processors/masgn_node.rb +3 -1
- data/lib/solargraph/parser/parser_gem/node_processors/opasgn_node.rb +2 -2
- data/lib/solargraph/parser/parser_gem/node_processors/or_node.rb +22 -0
- data/lib/solargraph/parser/parser_gem/node_processors/orasgn_node.rb +1 -1
- data/lib/solargraph/parser/parser_gem/node_processors/resbody_node.rb +2 -1
- data/lib/solargraph/parser/parser_gem/node_processors/sclass_node.rb +1 -0
- data/lib/solargraph/parser/parser_gem/node_processors/send_node.rb +12 -7
- data/lib/solargraph/parser/parser_gem/node_processors/when_node.rb +23 -0
- data/lib/solargraph/parser/parser_gem/node_processors/while_node.rb +5 -1
- data/lib/solargraph/parser/parser_gem/node_processors.rb +4 -0
- data/lib/solargraph/parser/region.rb +9 -3
- data/lib/solargraph/parser/snippet.rb +1 -1
- data/lib/solargraph/pin/base.rb +53 -21
- data/lib/solargraph/pin/base_variable.rb +312 -20
- data/lib/solargraph/pin/block.rb +26 -4
- data/lib/solargraph/pin/breakable.rb +5 -1
- data/lib/solargraph/pin/callable.rb +50 -3
- data/lib/solargraph/pin/closure.rb +2 -6
- data/lib/solargraph/pin/common.rb +20 -5
- data/lib/solargraph/pin/compound_statement.rb +55 -0
- data/lib/solargraph/pin/conversions.rb +2 -1
- data/lib/solargraph/pin/delegated_method.rb +15 -4
- data/lib/solargraph/pin/documenting.rb +1 -0
- data/lib/solargraph/pin/instance_variable.rb +5 -1
- data/lib/solargraph/pin/keyword.rb +0 -4
- data/lib/solargraph/pin/local_variable.rb +13 -57
- data/lib/solargraph/pin/method.rb +90 -42
- data/lib/solargraph/pin/method_alias.rb +8 -0
- data/lib/solargraph/pin/namespace.rb +7 -1
- data/lib/solargraph/pin/parameter.rb +76 -13
- data/lib/solargraph/pin/proxy_type.rb +2 -1
- data/lib/solargraph/pin/reference/override.rb +1 -1
- data/lib/solargraph/pin/reference/superclass.rb +2 -0
- data/lib/solargraph/pin/reference.rb +2 -0
- data/lib/solargraph/pin/search.rb +1 -0
- data/lib/solargraph/pin/signature.rb +8 -0
- data/lib/solargraph/pin/symbol.rb +1 -1
- data/lib/solargraph/pin/until.rb +1 -1
- data/lib/solargraph/pin/while.rb +1 -1
- data/lib/solargraph/pin.rb +2 -0
- data/lib/solargraph/pin_cache.rb +477 -57
- data/lib/solargraph/position.rb +12 -26
- data/lib/solargraph/range.rb +6 -6
- data/lib/solargraph/rbs_map/conversions.rb +33 -10
- data/lib/solargraph/rbs_map/core_map.rb +24 -17
- data/lib/solargraph/rbs_map/stdlib_map.rb +34 -5
- data/lib/solargraph/rbs_map.rb +74 -20
- data/lib/solargraph/shell.rb +73 -28
- data/lib/solargraph/source/chain/call.rb +52 -17
- data/lib/solargraph/source/chain/constant.rb +2 -0
- data/lib/solargraph/source/chain/hash.rb +1 -0
- data/lib/solargraph/source/chain/if.rb +1 -0
- data/lib/solargraph/source/chain/instance_variable.rb +22 -1
- data/lib/solargraph/source/chain/literal.rb +5 -0
- data/lib/solargraph/source/chain/or.rb +9 -1
- data/lib/solargraph/source/chain.rb +25 -22
- data/lib/solargraph/source/change.rb +9 -2
- data/lib/solargraph/source/cursor.rb +7 -1
- data/lib/solargraph/source/source_chainer.rb +13 -3
- data/lib/solargraph/source/updater.rb +4 -0
- data/lib/solargraph/source.rb +33 -7
- data/lib/solargraph/source_map/clip.rb +13 -2
- data/lib/solargraph/source_map/data.rb +4 -1
- data/lib/solargraph/source_map/mapper.rb +24 -1
- data/lib/solargraph/source_map.rb +14 -6
- data/lib/solargraph/type_checker/problem.rb +3 -1
- data/lib/solargraph/type_checker/rules.rb +75 -2
- data/lib/solargraph/type_checker.rb +111 -30
- data/lib/solargraph/version.rb +1 -1
- data/lib/solargraph/workspace/config.rb +3 -1
- data/lib/solargraph/workspace/gemspecs.rb +367 -0
- data/lib/solargraph/workspace/require_paths.rb +1 -0
- data/lib/solargraph/workspace.rb +158 -16
- data/lib/solargraph/yard_map/helpers.rb +2 -1
- data/lib/solargraph/yard_map/mapper/to_method.rb +5 -1
- data/lib/solargraph/yard_map/mapper/to_namespace.rb +1 -0
- data/lib/solargraph/yard_map/mapper.rb +5 -0
- data/lib/solargraph/yardoc.rb +33 -23
- data/lib/solargraph.rb +24 -3
- data/rbs/fills/rubygems/0/dependency.rbs +193 -0
- data/rbs/fills/tuple/tuple.rbs +28 -0
- data/rbs/shims/ast/0/node.rbs +1 -1
- data/rbs/shims/diff-lcs/1.5/diff-lcs.rbs +11 -0
- data/solargraph.gemspec +2 -1
- metadata +12 -7
- 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
|
@@ -11,7 +11,6 @@ module Solargraph
|
|
|
11
11
|
|
|
12
12
|
attr_reader :all_params, :subtypes, :key_types
|
|
13
13
|
|
|
14
|
-
# @sg-ignore Fix "Not enough arguments to Module#protected"
|
|
15
14
|
protected def equality_fields
|
|
16
15
|
[@name, @all_params, @subtypes, @key_types]
|
|
17
16
|
end
|
|
@@ -46,6 +45,7 @@ module Solargraph
|
|
|
46
45
|
parameters_type = nil
|
|
47
46
|
unless substring.empty?
|
|
48
47
|
subs = ComplexType.parse(substring[1..-2], partial: true)
|
|
48
|
+
# @sg-ignore Need to add nil check here
|
|
49
49
|
parameters_type = PARAMETERS_TYPE_BY_STARTING_TAG.fetch(substring[0])
|
|
50
50
|
if parameters_type == :hash
|
|
51
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)
|
|
@@ -62,6 +62,7 @@ module Solargraph
|
|
|
62
62
|
subtypes.concat subs
|
|
63
63
|
end
|
|
64
64
|
end
|
|
65
|
+
# @sg-ignore Need to add nil check here
|
|
65
66
|
new(name, key_types, subtypes, rooted: rooted, parameters_type: parameters_type)
|
|
66
67
|
end
|
|
67
68
|
|
|
@@ -109,6 +110,44 @@ module Solargraph
|
|
|
109
110
|
end
|
|
110
111
|
end
|
|
111
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
|
+
|
|
112
151
|
def literal?
|
|
113
152
|
non_literal_name != name
|
|
114
153
|
end
|
|
@@ -118,6 +157,13 @@ module Solargraph
|
|
|
118
157
|
@non_literal_name ||= determine_non_literal_name
|
|
119
158
|
end
|
|
120
159
|
|
|
160
|
+
# @return [self]
|
|
161
|
+
def without_nil
|
|
162
|
+
return UniqueType::UNDEFINED if nil_type?
|
|
163
|
+
|
|
164
|
+
self
|
|
165
|
+
end
|
|
166
|
+
|
|
121
167
|
# @return [String]
|
|
122
168
|
def determine_non_literal_name
|
|
123
169
|
# https://github.com/ruby/rbs/blob/master/docs/syntax.md
|
|
@@ -131,6 +177,7 @@ module Solargraph
|
|
|
131
177
|
return 'NilClass' if name == 'nil'
|
|
132
178
|
return 'Boolean' if ['true', 'false'].include?(name)
|
|
133
179
|
return 'Symbol' if name[0] == ':'
|
|
180
|
+
# @sg-ignore Need to add nil check here
|
|
134
181
|
return 'String' if ['"', "'"].include?(name[0])
|
|
135
182
|
return 'Integer' if name.match?(/^-?\d+$/)
|
|
136
183
|
name
|
|
@@ -138,17 +185,17 @@ module Solargraph
|
|
|
138
185
|
|
|
139
186
|
def eql?(other)
|
|
140
187
|
self.class == other.class &&
|
|
141
|
-
# @sg-ignore
|
|
188
|
+
# @sg-ignore flow sensitive typing should support .class == .class
|
|
142
189
|
@name == other.name &&
|
|
143
|
-
# @sg-ignore
|
|
190
|
+
# @sg-ignore flow sensitive typing should support .class == .class
|
|
144
191
|
@key_types == other.key_types &&
|
|
145
|
-
# @sg-ignore
|
|
192
|
+
# @sg-ignore flow sensitive typing should support .class == .class
|
|
146
193
|
@subtypes == other.subtypes &&
|
|
147
|
-
# @sg-ignore
|
|
194
|
+
# @sg-ignore flow sensitive typing should support .class == .class
|
|
148
195
|
@rooted == other.rooted? &&
|
|
149
|
-
# @sg-ignore
|
|
196
|
+
# @sg-ignore flow sensitive typing should support .class == .class
|
|
150
197
|
@all_params == other.all_params &&
|
|
151
|
-
# @sg-ignore
|
|
198
|
+
# @sg-ignore flow sensitive typing should support .class == .class
|
|
152
199
|
@parameters_type == other.parameters_type
|
|
153
200
|
end
|
|
154
201
|
|
|
@@ -156,10 +203,86 @@ module Solargraph
|
|
|
156
203
|
eql?(other)
|
|
157
204
|
end
|
|
158
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
|
+
|
|
159
277
|
def hash
|
|
160
278
|
[self.class, @name, @key_types, @sub_types, @rooted, @all_params, @parameters_type].hash
|
|
161
279
|
end
|
|
162
280
|
|
|
281
|
+
# @return [self]
|
|
282
|
+
def erase_parameters
|
|
283
|
+
UniqueType.new(name, rooted: rooted?, parameters_type: parameters_type)
|
|
284
|
+
end
|
|
285
|
+
|
|
163
286
|
# @return [Array<UniqueType>]
|
|
164
287
|
def items
|
|
165
288
|
[self]
|
|
@@ -181,6 +304,7 @@ module Solargraph
|
|
|
181
304
|
rooted_tags
|
|
182
305
|
end
|
|
183
306
|
|
|
307
|
+
# @sg-ignore Need better if/elseanalysis
|
|
184
308
|
# @return [String]
|
|
185
309
|
def to_rbs
|
|
186
310
|
if duck_type?
|
|
@@ -190,7 +314,7 @@ module Solargraph
|
|
|
190
314
|
elsif name.downcase == 'nil'
|
|
191
315
|
'nil'
|
|
192
316
|
elsif name == GENERIC_TAG_NAME
|
|
193
|
-
all_params.first
|
|
317
|
+
all_params.first&.name
|
|
194
318
|
elsif ['Class', 'Module'].include?(name)
|
|
195
319
|
rbs_name
|
|
196
320
|
elsif ['Tuple', 'Array'].include?(name) && fixed_parameters?
|
|
@@ -242,16 +366,13 @@ module Solargraph
|
|
|
242
366
|
name == GENERIC_TAG_NAME || all_params.any?(&:generic?)
|
|
243
367
|
end
|
|
244
368
|
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
end
|
|
253
|
-
logger.debug { "UniqueType#can_assign?(self=#{rooted_tags.inspect}, atype=#{atype.rooted_tags.inspect}) => #{out}" }
|
|
254
|
-
out
|
|
369
|
+
def nullable?
|
|
370
|
+
nil_type?
|
|
371
|
+
end
|
|
372
|
+
|
|
373
|
+
# @yieldreturn [Boolean]
|
|
374
|
+
def all? &block
|
|
375
|
+
block.yield self
|
|
255
376
|
end
|
|
256
377
|
|
|
257
378
|
# @return [UniqueType]
|
|
@@ -260,15 +381,18 @@ module Solargraph
|
|
|
260
381
|
end
|
|
261
382
|
|
|
262
383
|
# @param generics_to_resolve [Enumerable<String>]
|
|
263
|
-
# @param context_type [UniqueType, nil]
|
|
384
|
+
# @param context_type [ComplexType, UniqueType, nil]
|
|
264
385
|
# @param resolved_generic_values [Hash{String => ComplexType, ComplexType::UniqueType}] Added to as types are encountered or resolved
|
|
265
386
|
# @return [UniqueType, ComplexType]
|
|
266
387
|
def resolve_generics_from_context generics_to_resolve, context_type, resolved_generic_values: {}
|
|
267
388
|
if name == ComplexType::GENERIC_TAG_NAME
|
|
268
389
|
type_param = subtypes.first&.name
|
|
390
|
+
# @sg-ignore flow sensitive typing needs to eliminate literal from union with [:bar].include?(foo)
|
|
269
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)
|
|
270
393
|
unless context_type.nil? || !resolved_generic_values[type_param].nil?
|
|
271
394
|
new_binding = true
|
|
395
|
+
# @sg-ignore flow sensitive typing needs to eliminate literal from union with [:bar].include?(foo)
|
|
272
396
|
resolved_generic_values[type_param] = context_type
|
|
273
397
|
end
|
|
274
398
|
if new_binding
|
|
@@ -276,6 +400,7 @@ module Solargraph
|
|
|
276
400
|
complex_type.resolve_generics_from_context(generics_to_resolve, nil, resolved_generic_values: resolved_generic_values)
|
|
277
401
|
end
|
|
278
402
|
end
|
|
403
|
+
# @sg-ignore flow sensitive typing needs to eliminate literal from union with [:bar].include?(foo)
|
|
279
404
|
return resolved_generic_values[type_param] || self
|
|
280
405
|
end
|
|
281
406
|
|
|
@@ -286,7 +411,7 @@ module Solargraph
|
|
|
286
411
|
end
|
|
287
412
|
|
|
288
413
|
# @param generics_to_resolve [Enumerable<String>]
|
|
289
|
-
# @param context_type [UniqueType, nil]
|
|
414
|
+
# @param context_type [UniqueType, ComplexType, nil]
|
|
290
415
|
# @param resolved_generic_values [Hash{String => ComplexType}]
|
|
291
416
|
# @yieldreturn [Array<ComplexType>]
|
|
292
417
|
# @return [Array<ComplexType>]
|
|
@@ -337,6 +462,7 @@ module Solargraph
|
|
|
337
462
|
ComplexType::UNDEFINED
|
|
338
463
|
end
|
|
339
464
|
else
|
|
465
|
+
# @sg-ignore Need to add nil check here
|
|
340
466
|
context_type.all_params[idx] || definitions.generic_defaults[generic_name] || ComplexType::UNDEFINED
|
|
341
467
|
end
|
|
342
468
|
else
|
|
@@ -352,6 +478,13 @@ module Solargraph
|
|
|
352
478
|
[block.yield(self)]
|
|
353
479
|
end
|
|
354
480
|
|
|
481
|
+
# @yieldparam t [self]
|
|
482
|
+
# @yieldreturn [self]
|
|
483
|
+
# @return [Enumerable<self>]
|
|
484
|
+
def each &block
|
|
485
|
+
[self].each &block
|
|
486
|
+
end
|
|
487
|
+
|
|
355
488
|
# @return [Array<UniqueType>]
|
|
356
489
|
def to_a
|
|
357
490
|
[self]
|
|
@@ -370,6 +503,7 @@ module Solargraph
|
|
|
370
503
|
new_key_types ||= @key_types
|
|
371
504
|
new_subtypes ||= @subtypes
|
|
372
505
|
make_rooted = @rooted if make_rooted.nil?
|
|
506
|
+
# @sg-ignore flow sensitive typing needs better handling of ||= on lvars
|
|
373
507
|
UniqueType.new(new_name, new_key_types, new_subtypes, rooted: make_rooted, parameters_type: parameters_type)
|
|
374
508
|
end
|
|
375
509
|
|
|
@@ -443,6 +577,22 @@ module Solargraph
|
|
|
443
577
|
end
|
|
444
578
|
end
|
|
445
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
|
+
|
|
446
596
|
def all_rooted?
|
|
447
597
|
return true if name == GENERIC_TAG_NAME
|
|
448
598
|
rooted? && all_params.all?(&:rooted?)
|
|
@@ -9,6 +9,7 @@ module Solargraph
|
|
|
9
9
|
# include TypeMethods
|
|
10
10
|
include Equality
|
|
11
11
|
|
|
12
|
+
autoload :Conformance, 'solargraph/complex_type/conformance'
|
|
12
13
|
autoload :TypeMethods, 'solargraph/complex_type/type_methods'
|
|
13
14
|
autoload :UniqueType, 'solargraph/complex_type/unique_type'
|
|
14
15
|
|
|
@@ -19,13 +20,15 @@ module Solargraph
|
|
|
19
20
|
items = types.flat_map(&:items).uniq(&:to_s)
|
|
20
21
|
if items.any? { |i| i.name == 'false' } && items.any? { |i| i.name == 'true' }
|
|
21
22
|
items.delete_if { |i| i.name == 'false' || i.name == 'true' }
|
|
22
|
-
items.unshift(
|
|
23
|
+
items.unshift(UniqueType::BOOLEAN)
|
|
23
24
|
end
|
|
25
|
+
# @type [Array<UniqueType>]
|
|
24
26
|
items = [UniqueType::UNDEFINED] if items.any?(&:undefined?)
|
|
27
|
+
# @todo shouldn't need this cast - if statement above adds an 'Array' type
|
|
28
|
+
# @type [Array<UniqueType>]
|
|
25
29
|
@items = items
|
|
26
30
|
end
|
|
27
31
|
|
|
28
|
-
# @sg-ignore Fix "Not enough arguments to Module#protected"
|
|
29
32
|
protected def equality_fields
|
|
30
33
|
[self.class, items]
|
|
31
34
|
end
|
|
@@ -44,7 +47,7 @@ module Solargraph
|
|
|
44
47
|
end
|
|
45
48
|
|
|
46
49
|
# @param generics_to_resolve [Enumerable<String>]]
|
|
47
|
-
# @param context_type [UniqueType, nil]
|
|
50
|
+
# @param context_type [ComplexType, ComplexType::UniqueType, nil]
|
|
48
51
|
# @param resolved_generic_values [Hash{String => ComplexType}] Added to as types are encountered or resolved
|
|
49
52
|
# @return [self]
|
|
50
53
|
def resolve_generics_from_context generics_to_resolve, context_type, resolved_generic_values: {}
|
|
@@ -65,7 +68,7 @@ module Solargraph
|
|
|
65
68
|
(@items.length > 1 ? ')' : ''))
|
|
66
69
|
end
|
|
67
70
|
|
|
68
|
-
# @param dst [ComplexType]
|
|
71
|
+
# @param dst [ComplexType, ComplexType::UniqueType]
|
|
69
72
|
# @return [ComplexType]
|
|
70
73
|
def self_to_type dst
|
|
71
74
|
object_type_dst = dst.reduce_class_type
|
|
@@ -76,9 +79,13 @@ module Solargraph
|
|
|
76
79
|
end
|
|
77
80
|
|
|
78
81
|
# @yieldparam [UniqueType]
|
|
82
|
+
# @yieldreturn [UniqueType]
|
|
79
83
|
# @return [Array<UniqueType>]
|
|
80
|
-
|
|
81
|
-
|
|
84
|
+
# @sg-ignore Declared return type
|
|
85
|
+
# ::Array<::Solargraph::ComplexType::UniqueType> does not match
|
|
86
|
+
# inferred type ::Array<::Proc> for Solargraph::ComplexType#map
|
|
87
|
+
def map(&block)
|
|
88
|
+
@items.map(&block)
|
|
82
89
|
end
|
|
83
90
|
|
|
84
91
|
# @yieldparam [UniqueType]
|
|
@@ -99,12 +106,6 @@ module Solargraph
|
|
|
99
106
|
end
|
|
100
107
|
end
|
|
101
108
|
|
|
102
|
-
# @param atype [ComplexType] type which may be assigned to this type
|
|
103
|
-
# @param api_map [ApiMap] The ApiMap that performs qualification
|
|
104
|
-
def can_assign?(api_map, atype)
|
|
105
|
-
any? { |ut| ut.can_assign?(api_map, atype) }
|
|
106
|
-
end
|
|
107
|
-
|
|
108
109
|
# @param new_name [String, nil]
|
|
109
110
|
# @param make_rooted [Boolean, nil]
|
|
110
111
|
# @param new_key_types [Array<ComplexType>, nil]
|
|
@@ -194,6 +195,60 @@ module Solargraph
|
|
|
194
195
|
rooted_tags
|
|
195
196
|
end
|
|
196
197
|
|
|
198
|
+
# @param api_map [ApiMap]
|
|
199
|
+
# @param expected [ComplexType, ComplexType::UniqueType]
|
|
200
|
+
# @param situation [:method_call, :return_type, :assignment]
|
|
201
|
+
# @param allow_subtype_skew [Boolean] if false, check if any
|
|
202
|
+
# subtypes of the expected type match the inferred type
|
|
203
|
+
# @param allow_reverse_match [Boolean] if true, check if any subtypes
|
|
204
|
+
# of the expected type match the inferred type
|
|
205
|
+
# @param allow_empty_params [Boolean] if true, allow a general
|
|
206
|
+
# inferred type without parameters to conform to a more specific
|
|
207
|
+
# expected type
|
|
208
|
+
# @param allow_any_match [Boolean] if true, any unique type
|
|
209
|
+
# matched in the inferred qualifies as a match
|
|
210
|
+
# @param allow_undefined [Boolean] if true, treat undefined as a
|
|
211
|
+
# wildcard that matches anything
|
|
212
|
+
# @param rules [Array<:allow_subtype_skew, :allow_empty_params, :allow_reverse_match, :allow_any_match, :allow_undefined, :allow_unresolved_generic, :allow_unmatched_interface>]
|
|
213
|
+
# @param variance [:invariant, :covariant, :contravariant]
|
|
214
|
+
# @return [Boolean]
|
|
215
|
+
def conforms_to?(api_map, expected,
|
|
216
|
+
situation,
|
|
217
|
+
rules = [],
|
|
218
|
+
variance: erased_variance(situation))
|
|
219
|
+
expected = expected.downcast_to_literal_if_possible
|
|
220
|
+
inferred = downcast_to_literal_if_possible
|
|
221
|
+
|
|
222
|
+
return duck_types_match?(api_map, expected, inferred) if expected.duck_type?
|
|
223
|
+
|
|
224
|
+
if rules.include? :allow_any_match
|
|
225
|
+
inferred.any? do |inf|
|
|
226
|
+
inf.conforms_to?(api_map, expected, situation, rules,
|
|
227
|
+
variance: variance)
|
|
228
|
+
end
|
|
229
|
+
else
|
|
230
|
+
inferred.all? do |inf|
|
|
231
|
+
inf.conforms_to?(api_map, expected, situation, rules,
|
|
232
|
+
variance: variance)
|
|
233
|
+
end
|
|
234
|
+
end
|
|
235
|
+
end
|
|
236
|
+
|
|
237
|
+
# @param api_map [ApiMap]
|
|
238
|
+
# @param expected [ComplexType, UniqueType]
|
|
239
|
+
# @param inferred [ComplexType, UniqueType]
|
|
240
|
+
# @return [Boolean]
|
|
241
|
+
def duck_types_match? api_map, expected, inferred
|
|
242
|
+
raise ArgumentError, 'Expected type must be duck type' unless expected.duck_type?
|
|
243
|
+
expected.each do |exp|
|
|
244
|
+
next unless exp.duck_type?
|
|
245
|
+
quack = exp.to_s[1..]
|
|
246
|
+
# @sg-ignore Need to add nil check here
|
|
247
|
+
return false if api_map.get_method_stack(inferred.namespace, quack, scope: inferred.scope).empty?
|
|
248
|
+
end
|
|
249
|
+
true
|
|
250
|
+
end
|
|
251
|
+
|
|
197
252
|
# @return [String]
|
|
198
253
|
def rooted_tags
|
|
199
254
|
map(&:rooted_tag).join(', ')
|
|
@@ -252,6 +307,13 @@ module Solargraph
|
|
|
252
307
|
@items.any?(&:nil_type?)
|
|
253
308
|
end
|
|
254
309
|
|
|
310
|
+
# @return [ComplexType]
|
|
311
|
+
def without_nil
|
|
312
|
+
new_items = @items.reject(&:nil_type?)
|
|
313
|
+
return ComplexType::UNDEFINED if new_items.empty?
|
|
314
|
+
ComplexType.new(new_items)
|
|
315
|
+
end
|
|
316
|
+
|
|
255
317
|
# @return [Array<ComplexType>]
|
|
256
318
|
def all_params
|
|
257
319
|
@items.first.all_params || []
|
|
@@ -274,6 +336,13 @@ module Solargraph
|
|
|
274
336
|
all?(&:all_rooted?)
|
|
275
337
|
end
|
|
276
338
|
|
|
339
|
+
# @param other [ComplexType, UniqueType]
|
|
340
|
+
def erased_version_of?(other)
|
|
341
|
+
return false if items.length != 1 || other.items.length != 1
|
|
342
|
+
|
|
343
|
+
@items.first.erased_version_of?(other.items.first)
|
|
344
|
+
end
|
|
345
|
+
|
|
277
346
|
# every top-level type has resolved to be fully qualified; see
|
|
278
347
|
# #all_rooted? to check their subtypes as well
|
|
279
348
|
def rooted?
|
|
@@ -286,6 +355,40 @@ module Solargraph
|
|
|
286
355
|
@items.all?(&:rooted?)
|
|
287
356
|
end
|
|
288
357
|
|
|
358
|
+
# @param exclude_types [ComplexType, nil]
|
|
359
|
+
# @param api_map [ApiMap]
|
|
360
|
+
# @return [ComplexType, self]
|
|
361
|
+
def exclude exclude_types, api_map
|
|
362
|
+
return self if exclude_types.nil?
|
|
363
|
+
|
|
364
|
+
types = items - exclude_types.items
|
|
365
|
+
types = [ComplexType::UniqueType::UNDEFINED] if types.empty?
|
|
366
|
+
ComplexType.new(types)
|
|
367
|
+
end
|
|
368
|
+
|
|
369
|
+
# @see https://en.wikipedia.org/wiki/Intersection_type
|
|
370
|
+
#
|
|
371
|
+
# @param intersection_type [ComplexType, ComplexType::UniqueType, nil]
|
|
372
|
+
# @param api_map [ApiMap]
|
|
373
|
+
# @return [self, ComplexType::UniqueType]
|
|
374
|
+
def intersect_with intersection_type, api_map
|
|
375
|
+
return self if intersection_type.nil?
|
|
376
|
+
return intersection_type if undefined?
|
|
377
|
+
types = []
|
|
378
|
+
# try to find common types via conformance
|
|
379
|
+
items.each do |ut|
|
|
380
|
+
intersection_type.each do |int_type|
|
|
381
|
+
if int_type.conforms_to?(api_map, ut, :assignment)
|
|
382
|
+
types << int_type
|
|
383
|
+
elsif ut.conforms_to?(api_map, int_type, :assignment)
|
|
384
|
+
types << ut
|
|
385
|
+
end
|
|
386
|
+
end
|
|
387
|
+
end
|
|
388
|
+
types = [ComplexType::UniqueType::UNDEFINED] if types.empty?
|
|
389
|
+
ComplexType.new(types)
|
|
390
|
+
end
|
|
391
|
+
|
|
289
392
|
protected
|
|
290
393
|
|
|
291
394
|
# @return [ComplexType]
|
|
@@ -320,17 +423,18 @@ module Solargraph
|
|
|
320
423
|
# # @todo Need ability to use a literal true as a type below
|
|
321
424
|
# # @param partial [Boolean] True if the string is part of a another type
|
|
322
425
|
# # @return [Array<UniqueType>]
|
|
323
|
-
# @
|
|
426
|
+
# @sg-ignore To be able to select the right signature above,
|
|
324
427
|
# Chain::Call needs to know the decl type (:arg, :optarg,
|
|
325
428
|
# :kwarg, etc) of the arguments given, instead of just having
|
|
326
429
|
# an array of Chains as the arguments.
|
|
327
430
|
def parse *strings, partial: false
|
|
328
|
-
# @type [Hash{Array<String> => ComplexType}]
|
|
431
|
+
# @type [Hash{Array<String> => ComplexType, Array<ComplexType::UniqueType>}]
|
|
329
432
|
@cache ||= {}
|
|
330
433
|
unless partial
|
|
331
434
|
cached = @cache[strings]
|
|
332
435
|
return cached unless cached.nil?
|
|
333
436
|
end
|
|
437
|
+
# @types [Array<ComplexType::UniqueType>]
|
|
334
438
|
types = []
|
|
335
439
|
key_types = nil
|
|
336
440
|
strings.each do |type_string|
|
|
@@ -351,6 +455,7 @@ module Solargraph
|
|
|
351
455
|
elsif base.end_with?('=')
|
|
352
456
|
raise ComplexTypeError, "Invalid hash thing" unless key_types.nil?
|
|
353
457
|
# types.push ComplexType.new([UniqueType.new(base[0..-2].strip)])
|
|
458
|
+
# @sg-ignore Need to add nil check here
|
|
354
459
|
types.push UniqueType.parse(base[0..-2].strip, subtype_string)
|
|
355
460
|
# @todo this should either expand key_type's type
|
|
356
461
|
# automatically or complain about not being
|
|
@@ -66,7 +66,7 @@ module Solargraph
|
|
|
66
66
|
end.compact
|
|
67
67
|
end
|
|
68
68
|
|
|
69
|
-
# @return [Parser::AST::Node]
|
|
69
|
+
# @return [Parser::AST::Node, nil]
|
|
70
70
|
def body_node
|
|
71
71
|
node.children[2]
|
|
72
72
|
end
|
|
@@ -81,8 +81,10 @@ module Solargraph
|
|
|
81
81
|
node.children[1]
|
|
82
82
|
end
|
|
83
83
|
|
|
84
|
+
# @sg-ignore Need to add nil check here
|
|
84
85
|
# @return [Array<Parser::AST::Node>]
|
|
85
86
|
def data_attribute_nodes
|
|
87
|
+
# @sg-ignore Need to add nil check here
|
|
86
88
|
data_node.children[2..-1]
|
|
87
89
|
end
|
|
88
90
|
end
|
|
@@ -17,6 +17,7 @@ module Solargraph
|
|
|
17
17
|
type: :class,
|
|
18
18
|
location: loc,
|
|
19
19
|
closure: region.closure,
|
|
20
|
+
# @sg-ignore flow sensitive typing needs to handle attrs
|
|
20
21
|
name: data_definition_node.class_name,
|
|
21
22
|
comments: comments_for(node),
|
|
22
23
|
visibility: :public,
|
|
@@ -39,6 +40,7 @@ module Solargraph
|
|
|
39
40
|
# Solargraph::SourceMap::Clip#complete_keyword_parameters does not seem to currently take into account [Pin::Method#signatures] hence we only one for :kwarg
|
|
40
41
|
pins.push initialize_method_pin
|
|
41
42
|
|
|
43
|
+
# @sg-ignore flow sensitive typing needs to handle attrs
|
|
42
44
|
data_definition_node.attributes.map do |attribute_node, attribute_name|
|
|
43
45
|
initialize_method_pin.parameters.push(
|
|
44
46
|
Pin::Parameter.new(
|
|
@@ -51,6 +53,7 @@ module Solargraph
|
|
|
51
53
|
end
|
|
52
54
|
|
|
53
55
|
# define attribute readers and instance variables
|
|
56
|
+
# @sg-ignore flow sensitive typing needs to handle attrs
|
|
54
57
|
data_definition_node.attributes.each do |attribute_node, attribute_name|
|
|
55
58
|
name = attribute_name.to_s
|
|
56
59
|
method_pin = Pin::Method.new(
|
|
@@ -78,7 +81,7 @@ module Solargraph
|
|
|
78
81
|
|
|
79
82
|
private
|
|
80
83
|
|
|
81
|
-
# @return [DataDefintionNode, nil]
|
|
84
|
+
# @return [DataDefinition::DataDefintionNode, DataDefinition::DataAssignmentNode, nil]
|
|
82
85
|
def data_definition_node
|
|
83
86
|
@data_definition_node ||= if DataDefintionNode.match?(node)
|
|
84
87
|
DataDefintionNode.new(node)
|
|
@@ -17,6 +17,7 @@ module Solargraph
|
|
|
17
17
|
type: :class,
|
|
18
18
|
location: loc,
|
|
19
19
|
closure: region.closure,
|
|
20
|
+
# @sg-ignore flow sensitive typing needs to handle attrs
|
|
20
21
|
name: struct_definition_node.class_name,
|
|
21
22
|
docstring: docstring,
|
|
22
23
|
visibility: :public,
|
|
@@ -39,6 +40,7 @@ module Solargraph
|
|
|
39
40
|
|
|
40
41
|
pins.push initialize_method_pin
|
|
41
42
|
|
|
43
|
+
# @sg-ignore flow sensitive typing needs to handle attrs
|
|
42
44
|
struct_definition_node.attributes.map do |attribute_node, attribute_name|
|
|
43
45
|
initialize_method_pin.parameters.push(
|
|
44
46
|
Pin::Parameter.new(
|
|
@@ -52,6 +54,7 @@ module Solargraph
|
|
|
52
54
|
end
|
|
53
55
|
|
|
54
56
|
# define attribute accessors and instance variables
|
|
57
|
+
# @sg-ignore flow sensitive typing needs to handle attrs
|
|
55
58
|
struct_definition_node.attributes.each do |attribute_node, attribute_name|
|
|
56
59
|
[attribute_name, "#{attribute_name}="].each do |name|
|
|
57
60
|
docs = docstring.tags.find { |t| t.tag_name == 'param' && t.name == attribute_name }
|
|
@@ -102,7 +105,7 @@ module Solargraph
|
|
|
102
105
|
|
|
103
106
|
private
|
|
104
107
|
|
|
105
|
-
# @return [StructDefintionNode, StructAssignmentNode, nil]
|
|
108
|
+
# @return [StructDefinition::StructDefintionNode, StructDefinition::StructAssignmentNode, nil]
|
|
106
109
|
def struct_definition_node
|
|
107
110
|
@struct_definition_node ||= if StructDefintionNode.match?(node)
|
|
108
111
|
StructDefintionNode.new(node)
|
|
@@ -121,6 +124,7 @@ module Solargraph
|
|
|
121
124
|
# @return [YARD::Docstring]
|
|
122
125
|
def parse_comments
|
|
123
126
|
struct_comments = comments_for(node) || ''
|
|
127
|
+
# @sg-ignore Need to add nil check here
|
|
124
128
|
struct_definition_node.attributes.each do |attr_node, attr_name|
|
|
125
129
|
comment = comments_for(attr_node)
|
|
126
130
|
next if comment.nil?
|
|
@@ -10,6 +10,7 @@ module Solargraph
|
|
|
10
10
|
return [] unless source.parsed? && source.synchronized?
|
|
11
11
|
result = []
|
|
12
12
|
refs = {}
|
|
13
|
+
# @sg-ignore Need to add nil check here
|
|
13
14
|
map = api_map.source_map(source.filename)
|
|
14
15
|
map.requires.each { |ref| refs[ref.name] = ref }
|
|
15
16
|
api_map.missing_docs.each do |r|
|
|
@@ -25,6 +25,7 @@ module Solargraph
|
|
|
25
25
|
def diagnose source, _api_map
|
|
26
26
|
@source = source
|
|
27
27
|
require_rubocop(rubocop_version)
|
|
28
|
+
# @sg-ignore Need to add nil check here
|
|
28
29
|
options, paths = generate_options(source.filename, source.code)
|
|
29
30
|
store = RuboCop::ConfigStore.new
|
|
30
31
|
runner = RuboCop::Runner.new(options, store)
|