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
|
@@ -6,31 +6,139 @@ module Solargraph
|
|
|
6
6
|
# include Solargraph::Source::NodeMethods
|
|
7
7
|
include Solargraph::Parser::NodeMethods
|
|
8
8
|
|
|
9
|
-
# @return [Parser::AST::Node
|
|
10
|
-
attr_reader :
|
|
9
|
+
# @return [Array<Parser::AST::Node>]
|
|
10
|
+
attr_reader :assignments
|
|
11
11
|
|
|
12
12
|
attr_accessor :mass_assignment
|
|
13
13
|
|
|
14
|
+
# @return [Range, nil]
|
|
15
|
+
attr_reader :presence
|
|
16
|
+
|
|
14
17
|
# @param return_type [ComplexType, nil]
|
|
18
|
+
# @param assignment [Parser::AST::Node, nil] First assignment
|
|
19
|
+
# that was made to this variable
|
|
20
|
+
# @param assignments [Array<Parser::AST::Node>] Possible
|
|
21
|
+
# assignments that may have been made to this variable
|
|
15
22
|
# @param mass_assignment [::Array(Parser::AST::Node, Integer), nil]
|
|
16
|
-
# @param assignment [Parser::AST::Node, nil]
|
|
17
|
-
|
|
23
|
+
# @param assignment [Parser::AST::Node, nil] First assignment
|
|
24
|
+
# that was made to this variable
|
|
25
|
+
# @param assignments [Array<Parser::AST::Node>] Possible
|
|
26
|
+
# assignments that may have been made to this variable
|
|
27
|
+
# @param exclude_return_type [ComplexType, nil] Ensure any
|
|
28
|
+
# return type returned will never include any of these unique
|
|
29
|
+
# types in the unique types of its complex type.
|
|
30
|
+
#
|
|
31
|
+
# Example: If a return type is 'Float | Integer | nil' and the
|
|
32
|
+
# exclude_return_type is 'Integer', the resulting return
|
|
33
|
+
# type will be 'Float | nil' because Integer is excluded.
|
|
34
|
+
# @param intersection_return_type [ComplexType, nil] Ensure each unique
|
|
35
|
+
# return type is compatible with at least one element of this
|
|
36
|
+
# complex type. If a ComplexType used as a return type is an
|
|
37
|
+
# union type - we can return any of these - these are
|
|
38
|
+
# intersection types - everything we return needs to meet at least
|
|
39
|
+
# one of these unique types.
|
|
40
|
+
#
|
|
41
|
+
# Example: If a return type is 'Numeric | nil' and the
|
|
42
|
+
# intersection_return_type is 'Float | nil', the resulting return
|
|
43
|
+
# type will be 'Float | nil' because Float is compatible
|
|
44
|
+
# with Numeric and nil is compatible with nil.
|
|
45
|
+
# @see https://www.typescriptlang.org/docs/handbook/2/everyday-types.html#union-types
|
|
46
|
+
# @see https://en.wikipedia.org/wiki/Intersection_type#TypeScript_example
|
|
47
|
+
# @param presence [Range, nil]
|
|
48
|
+
# @param presence_certain [Boolean]
|
|
49
|
+
def initialize assignment: nil, assignments: [], mass_assignment: nil,
|
|
50
|
+
presence: nil, presence_certain: false, return_type: nil,
|
|
51
|
+
intersection_return_type: nil, exclude_return_type: nil,
|
|
52
|
+
**splat
|
|
18
53
|
super(**splat)
|
|
19
|
-
@
|
|
54
|
+
@assignments = (assignment.nil? ? [] : [assignment]) + assignments
|
|
20
55
|
# @type [nil, ::Array(Parser::AST::Node, Integer)]
|
|
21
|
-
@mass_assignment =
|
|
56
|
+
@mass_assignment = mass_assignment
|
|
22
57
|
@return_type = return_type
|
|
58
|
+
@intersection_return_type = intersection_return_type
|
|
59
|
+
@exclude_return_type = exclude_return_type
|
|
60
|
+
@presence = presence
|
|
61
|
+
@presence_certain = presence_certain
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
# @param presence [Range]
|
|
65
|
+
# @param exclude_return_type [ComplexType, nil]
|
|
66
|
+
# @param intersection_return_type [ComplexType, nil]
|
|
67
|
+
# @param source [::Symbol]
|
|
68
|
+
#
|
|
69
|
+
# @return [self]
|
|
70
|
+
def downcast presence:, exclude_return_type: nil, intersection_return_type: nil,
|
|
71
|
+
source: self.source
|
|
72
|
+
result = dup
|
|
73
|
+
result.exclude_return_type = exclude_return_type
|
|
74
|
+
result.intersection_return_type = intersection_return_type
|
|
75
|
+
result.source = source
|
|
76
|
+
result.presence = presence
|
|
77
|
+
result.reset_generated!
|
|
78
|
+
result
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def reset_generated!
|
|
82
|
+
@assignment = nil
|
|
83
|
+
super
|
|
23
84
|
end
|
|
24
85
|
|
|
25
86
|
def combine_with(other, attrs={})
|
|
87
|
+
new_assignments = combine_assignments(other)
|
|
26
88
|
new_attrs = attrs.merge({
|
|
27
|
-
|
|
28
|
-
|
|
89
|
+
# default values don't exist in RBS parameters; it just
|
|
90
|
+
# tells you if the arg is optional or not. Prefer a
|
|
91
|
+
# provided value if we have one here since we can't rely on
|
|
92
|
+
# it from RBS so we can infer from it and typecheck on it.
|
|
93
|
+
assignment: choose(other, :assignment),
|
|
94
|
+
assignments: new_assignments,
|
|
95
|
+
mass_assignment: combine_mass_assignment(other),
|
|
29
96
|
return_type: combine_return_type(other),
|
|
97
|
+
intersection_return_type: combine_types(other, :intersection_return_type),
|
|
98
|
+
exclude_return_type: combine_types(other, :exclude_return_type),
|
|
99
|
+
presence: combine_presence(other),
|
|
100
|
+
presence_certain: combine_presence_certain(other)
|
|
30
101
|
})
|
|
31
102
|
super(other, new_attrs)
|
|
32
103
|
end
|
|
33
104
|
|
|
105
|
+
# @param other [self]
|
|
106
|
+
#
|
|
107
|
+
# @return [Array(AST::Node, Integer), nil]
|
|
108
|
+
def combine_mass_assignment(other)
|
|
109
|
+
# @todo pick first non-nil arbitrarily - we don't yet support
|
|
110
|
+
# mass assignment merging
|
|
111
|
+
mass_assignment || other.mass_assignment
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
# If a certain pin is being combined with an uncertain pin, we
|
|
115
|
+
# end up with a certain result
|
|
116
|
+
#
|
|
117
|
+
# @param other [self]
|
|
118
|
+
#
|
|
119
|
+
# @return [Boolean]
|
|
120
|
+
def combine_presence_certain(other)
|
|
121
|
+
presence_certain? || other.presence_certain?
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
# @return [Parser::AST::Node, nil]
|
|
125
|
+
def assignment
|
|
126
|
+
@assignment ||= assignments.last
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
# @param other [self]
|
|
130
|
+
#
|
|
131
|
+
# @return [::Array<Parser::AST::Node>]
|
|
132
|
+
def combine_assignments(other)
|
|
133
|
+
(other.assignments + assignments).uniq
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
def inner_desc
|
|
137
|
+
super + ", presence=#{presence.inspect}, assignments=#{assignments}, " \
|
|
138
|
+
"intersection_return_type=#{intersection_return_type&.rooted_tags.inspect}, " \
|
|
139
|
+
"exclude_return_type=#{exclude_return_type&.rooted_tags.inspect}"
|
|
140
|
+
end
|
|
141
|
+
|
|
34
142
|
def completion_item_kind
|
|
35
143
|
Solargraph::LanguageServer::CompletionItemKinds::VARIABLE
|
|
36
144
|
end
|
|
@@ -40,10 +148,6 @@ module Solargraph
|
|
|
40
148
|
Solargraph::LanguageServer::SymbolKinds::VARIABLE
|
|
41
149
|
end
|
|
42
150
|
|
|
43
|
-
def return_type
|
|
44
|
-
@return_type ||= generate_complex_type
|
|
45
|
-
end
|
|
46
|
-
|
|
47
151
|
def nil_assignment?
|
|
48
152
|
# this will always be false - should it be return_type ==
|
|
49
153
|
# ComplexType::NIL or somesuch?
|
|
@@ -67,10 +171,12 @@ module Solargraph
|
|
|
67
171
|
rng = Range.from_node(node)
|
|
68
172
|
next if rng.nil?
|
|
69
173
|
pos = rng.ending
|
|
174
|
+
# @sg-ignore Need to add nil check here
|
|
70
175
|
clip = api_map.clip_at(location.filename, pos)
|
|
71
176
|
# Use the return node for inference. The clip might infer from the
|
|
72
177
|
# first node in a method call instead of the entire call.
|
|
73
178
|
chain = Parser.chain(node, nil, nil)
|
|
179
|
+
# @sg-ignore Need to add nil check here
|
|
74
180
|
result = chain.infer(api_map, closure, clip.locals).self_to_type(closure.context)
|
|
75
181
|
types.push result unless result.undefined?
|
|
76
182
|
end
|
|
@@ -79,13 +185,15 @@ module Solargraph
|
|
|
79
185
|
end
|
|
80
186
|
|
|
81
187
|
# @param api_map [ApiMap]
|
|
82
|
-
# @return [ComplexType]
|
|
188
|
+
# @return [ComplexType, ComplexType::UniqueType]
|
|
83
189
|
def probe api_map
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
end
|
|
190
|
+
assignment_types = assignments.flat_map { |node| return_types_from_node(node, api_map) }
|
|
191
|
+
type_from_assignment = ComplexType.new(assignment_types.flat_map(&:items).uniq) unless assignment_types.empty?
|
|
192
|
+
return adjust_type api_map, type_from_assignment unless type_from_assignment.nil?
|
|
88
193
|
|
|
194
|
+
# @todo should handle merging types from mass assignments as
|
|
195
|
+
# well so that we can do better flow sensitive typing with
|
|
196
|
+
# multiple assignments
|
|
89
197
|
unless @mass_assignment.nil?
|
|
90
198
|
mass_node, index = @mass_assignment
|
|
91
199
|
types = return_types_from_node(mass_node, api_map)
|
|
@@ -96,7 +204,10 @@ module Solargraph
|
|
|
96
204
|
type.all_params.first
|
|
97
205
|
end
|
|
98
206
|
end.compact!
|
|
99
|
-
|
|
207
|
+
|
|
208
|
+
return ComplexType::UNDEFINED if types.empty?
|
|
209
|
+
|
|
210
|
+
return adjust_type api_map, ComplexType.new(types.uniq).qualify(api_map, *gates)
|
|
100
211
|
end
|
|
101
212
|
|
|
102
213
|
ComplexType::UNDEFINED
|
|
@@ -113,13 +224,194 @@ module Solargraph
|
|
|
113
224
|
"#{super} = #{assignment&.type.inspect}"
|
|
114
225
|
end
|
|
115
226
|
|
|
227
|
+
# @return [ComplexType, nil]
|
|
228
|
+
def return_type
|
|
229
|
+
generate_complex_type || @return_type || intersection_return_type || ComplexType::UNDEFINED
|
|
230
|
+
end
|
|
231
|
+
|
|
232
|
+
def typify api_map
|
|
233
|
+
raw_return_type = super
|
|
234
|
+
|
|
235
|
+
adjust_type(api_map, raw_return_type)
|
|
236
|
+
end
|
|
237
|
+
|
|
238
|
+
# @sg-ignore need boolish support for ? methods
|
|
239
|
+
def presence_certain?
|
|
240
|
+
exclude_return_type || intersection_return_type
|
|
241
|
+
end
|
|
242
|
+
|
|
243
|
+
# @param other_loc [Location]
|
|
244
|
+
# @sg-ignore flow sensitive typing needs to handle attrs
|
|
245
|
+
def starts_at?(other_loc)
|
|
246
|
+
location&.filename == other_loc.filename &&
|
|
247
|
+
presence &&
|
|
248
|
+
# @sg-ignore flow sensitive typing needs to handle attrs
|
|
249
|
+
presence.start == other_loc.range.start
|
|
250
|
+
end
|
|
251
|
+
|
|
252
|
+
# Narrow the presence range to the intersection of both.
|
|
253
|
+
#
|
|
254
|
+
# @param other [self]
|
|
255
|
+
#
|
|
256
|
+
# @return [Range, nil]
|
|
257
|
+
def combine_presence(other)
|
|
258
|
+
return presence || other.presence if presence.nil? || other.presence.nil?
|
|
259
|
+
|
|
260
|
+
# @sg-ignore flow sensitive typing needs to handle attrs
|
|
261
|
+
Range.new([presence.start, other.presence.start].max, [presence.ending, other.presence.ending].min)
|
|
262
|
+
end
|
|
263
|
+
|
|
264
|
+
# @param other [self]
|
|
265
|
+
# @return [Pin::Closure, nil]
|
|
266
|
+
def combine_closure(other)
|
|
267
|
+
return closure if self.closure == other.closure
|
|
268
|
+
|
|
269
|
+
# choose first defined, as that establishes the scope of the variable
|
|
270
|
+
if closure.nil? || other.closure.nil?
|
|
271
|
+
Solargraph.assert_or_log(:varible_closure_missing) do
|
|
272
|
+
"One of the local variables being combined is missing a closure: " \
|
|
273
|
+
"#{self.inspect} vs #{other.inspect}"
|
|
274
|
+
end
|
|
275
|
+
return closure || other.closure
|
|
276
|
+
end
|
|
277
|
+
|
|
278
|
+
# @sg-ignore flow sensitive typing needs to handle attrs
|
|
279
|
+
if closure.location.nil? || other.closure.location.nil?
|
|
280
|
+
# @sg-ignore flow sensitive typing needs to handle attrs
|
|
281
|
+
return closure.location.nil? ? other.closure : closure
|
|
282
|
+
end
|
|
283
|
+
|
|
284
|
+
# if filenames are different, this will just pick one
|
|
285
|
+
# @sg-ignore flow sensitive typing needs to handle attrs
|
|
286
|
+
return closure if closure.location <= other.closure.location
|
|
287
|
+
|
|
288
|
+
other.closure
|
|
289
|
+
end
|
|
290
|
+
|
|
291
|
+
# @param other_closure [Pin::Closure]
|
|
292
|
+
# @param other_loc [Location]
|
|
293
|
+
def visible_at?(other_closure, other_loc)
|
|
294
|
+
# @sg-ignore flow sensitive typing needs to handle attrs
|
|
295
|
+
location.filename == other_loc.filename &&
|
|
296
|
+
# @sg-ignore flow sensitive typing needs to handle attrs
|
|
297
|
+
(!presence || presence.include?(other_loc.range.start)) &&
|
|
298
|
+
visible_in_closure?(other_closure)
|
|
299
|
+
end
|
|
300
|
+
|
|
301
|
+
def presence_certain?
|
|
302
|
+
@presence_certain
|
|
303
|
+
end
|
|
304
|
+
|
|
305
|
+
protected
|
|
306
|
+
|
|
307
|
+
attr_accessor :exclude_return_type, :intersection_return_type
|
|
308
|
+
|
|
309
|
+
# @return [Range]
|
|
310
|
+
attr_writer :presence
|
|
311
|
+
|
|
116
312
|
private
|
|
117
313
|
|
|
118
|
-
# @
|
|
314
|
+
# @param api_map [ApiMap]
|
|
315
|
+
# @param raw_return_type [ComplexType, ComplexType::UniqueType]
|
|
316
|
+
#
|
|
317
|
+
# @return [ComplexType, ComplexType::UniqueType]
|
|
318
|
+
def adjust_type(api_map, raw_return_type)
|
|
319
|
+
qualified_exclude = exclude_return_type&.qualify(api_map, *(closure&.gates || ['']))
|
|
320
|
+
minus_exclusions = raw_return_type.exclude qualified_exclude, api_map
|
|
321
|
+
qualified_intersection = intersection_return_type&.qualify(api_map, *(closure&.gates || ['']))
|
|
322
|
+
minus_exclusions.intersect_with qualified_intersection, api_map
|
|
323
|
+
end
|
|
324
|
+
|
|
325
|
+
# @param other [self]
|
|
326
|
+
# @return [Pin::Closure, nil]
|
|
327
|
+
def combine_closure(other)
|
|
328
|
+
return closure if self.closure == other.closure
|
|
329
|
+
|
|
330
|
+
# choose first defined, as that establishes the scope of the variable
|
|
331
|
+
if closure.nil? || other.closure.nil?
|
|
332
|
+
Solargraph.assert_or_log(:varible_closure_missing) do
|
|
333
|
+
"One of the local variables being combined is missing a closure: " \
|
|
334
|
+
"#{self.inspect} vs #{other.inspect}"
|
|
335
|
+
end
|
|
336
|
+
return closure || other.closure
|
|
337
|
+
end
|
|
338
|
+
|
|
339
|
+
# @sg-ignore Need to add nil check here
|
|
340
|
+
if closure.location.nil? || other.closure.location.nil?
|
|
341
|
+
# @sg-ignore Need to add nil check here
|
|
342
|
+
return closure.location.nil? ? other.closure : closure
|
|
343
|
+
end
|
|
344
|
+
|
|
345
|
+
# if filenames are different, this will just pick one
|
|
346
|
+
# @sg-ignore flow sensitive typing needs to handle attrs
|
|
347
|
+
return closure if closure.location <= other.closure.location
|
|
348
|
+
|
|
349
|
+
other.closure
|
|
350
|
+
end
|
|
351
|
+
|
|
352
|
+
# See if this variable is visible within 'viewing_closure'
|
|
353
|
+
#
|
|
354
|
+
# @param viewing_closure [Pin::Closure]
|
|
355
|
+
# @return [Boolean]
|
|
356
|
+
def visible_in_closure? viewing_closure
|
|
357
|
+
return false if closure.nil?
|
|
358
|
+
|
|
359
|
+
# if we're declared at top level, we can't be seen from within
|
|
360
|
+
# methods declared tere
|
|
361
|
+
|
|
362
|
+
# @sg-ignore Need to add nil check here
|
|
363
|
+
return false if viewing_closure.is_a?(Pin::Method) && closure.context.tags == 'Class<>'
|
|
364
|
+
|
|
365
|
+
# @sg-ignore Need to add nil check here
|
|
366
|
+
return true if viewing_closure.binder.namespace == closure.binder.namespace
|
|
367
|
+
|
|
368
|
+
# @sg-ignore Need to add nil check here
|
|
369
|
+
return true if viewing_closure.return_type == closure.context
|
|
370
|
+
|
|
371
|
+
# classes and modules can't see local variables declared
|
|
372
|
+
# in their parent closure, so stop here
|
|
373
|
+
return false if scope == :instance && viewing_closure.is_a?(Pin::Namespace)
|
|
374
|
+
|
|
375
|
+
parent_of_viewing_closure = viewing_closure.closure
|
|
376
|
+
|
|
377
|
+
return false if parent_of_viewing_closure.nil?
|
|
378
|
+
|
|
379
|
+
visible_in_closure?(parent_of_viewing_closure)
|
|
380
|
+
end
|
|
381
|
+
|
|
382
|
+
# @param other [self]
|
|
383
|
+
# @return [ComplexType, nil]
|
|
384
|
+
def combine_return_type(other)
|
|
385
|
+
combine_types(other, :return_type)
|
|
386
|
+
end
|
|
387
|
+
|
|
388
|
+
# @param other [self]
|
|
389
|
+
# @param attr [::Symbol]
|
|
390
|
+
#
|
|
391
|
+
# @return [ComplexType, nil]
|
|
392
|
+
def combine_types(other, attr)
|
|
393
|
+
# @type [ComplexType, nil]
|
|
394
|
+
type1 = send(attr)
|
|
395
|
+
# @type [ComplexType, nil]
|
|
396
|
+
type2 = other.send(attr)
|
|
397
|
+
if type1 && type2
|
|
398
|
+
types = (type1.items + type2.items).uniq
|
|
399
|
+
ComplexType.new(types)
|
|
400
|
+
else
|
|
401
|
+
type1 || type2
|
|
402
|
+
end
|
|
403
|
+
end
|
|
404
|
+
|
|
405
|
+
# @return [::Symbol]
|
|
406
|
+
def scope
|
|
407
|
+
:instance
|
|
408
|
+
end
|
|
409
|
+
|
|
410
|
+
# @return [ComplexType, nil]
|
|
119
411
|
def generate_complex_type
|
|
120
412
|
tag = docstring.tag(:type)
|
|
121
413
|
return ComplexType.try_parse(*tag.types) unless tag.nil? || tag.types.nil? || tag.types.empty?
|
|
122
|
-
|
|
414
|
+
nil
|
|
123
415
|
end
|
|
124
416
|
end
|
|
125
417
|
end
|
data/lib/solargraph/pin/block.rb
CHANGED
|
@@ -21,6 +21,7 @@ module Solargraph
|
|
|
21
21
|
@context = context
|
|
22
22
|
@return_type = ComplexType.parse('::Proc')
|
|
23
23
|
@node = node
|
|
24
|
+
@name = '<block>'
|
|
24
25
|
end
|
|
25
26
|
|
|
26
27
|
# @param api_map [ApiMap]
|
|
@@ -30,7 +31,13 @@ module Solargraph
|
|
|
30
31
|
end
|
|
31
32
|
|
|
32
33
|
def binder
|
|
33
|
-
@rebind
|
|
34
|
+
out = @rebind if @rebind&.defined?
|
|
35
|
+
out ||= super
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def context
|
|
39
|
+
@context = @rebind if @rebind&.defined?
|
|
40
|
+
super
|
|
34
41
|
end
|
|
35
42
|
|
|
36
43
|
# @param yield_types [::Array<ComplexType>]
|
|
@@ -50,14 +57,17 @@ module Solargraph
|
|
|
50
57
|
# @return [::Array<ComplexType>]
|
|
51
58
|
def typify_parameters(api_map)
|
|
52
59
|
chain = Parser.chain(receiver, filename, node)
|
|
60
|
+
# @sg-ignore Need to add nil check here
|
|
53
61
|
clip = api_map.clip_at(location.filename, location.range.start)
|
|
54
62
|
locals = clip.locals - [self]
|
|
63
|
+
# @sg-ignore Need to add nil check here
|
|
55
64
|
meths = chain.define(api_map, closure, locals)
|
|
56
65
|
# @todo Convert logic to use signatures
|
|
57
66
|
# @param meth [Pin::Method]
|
|
58
67
|
meths.each do |meth|
|
|
59
68
|
next if meth.block.nil?
|
|
60
69
|
|
|
70
|
+
# @sg-ignore flow sensitive typing needs to handle attrs
|
|
61
71
|
yield_types = meth.block.parameters.map(&:return_type)
|
|
62
72
|
# 'arguments' is what the method says it will yield to the
|
|
63
73
|
# block; 'parameters' is what the block accepts
|
|
@@ -67,6 +77,7 @@ module Solargraph
|
|
|
67
77
|
param_type = chain.base.infer(api_map, param, locals)
|
|
68
78
|
unless arg_type.nil?
|
|
69
79
|
if arg_type.generic? && param_type.defined?
|
|
80
|
+
# @sg-ignore Need to add nil check here
|
|
70
81
|
namespace_pin = api_map.get_namespace_pins(meth.namespace, closure.namespace).first
|
|
71
82
|
arg_type.resolve_generics(namespace_pin, param_type)
|
|
72
83
|
else
|
|
@@ -86,16 +97,27 @@ module Solargraph
|
|
|
86
97
|
def maybe_rebind api_map
|
|
87
98
|
return ComplexType::UNDEFINED unless receiver
|
|
88
99
|
|
|
89
|
-
|
|
100
|
+
# @sg-ignore Need to add nil check here
|
|
101
|
+
chain = Parser.chain(receiver, location.filename, node)
|
|
102
|
+
# @sg-ignore Need to add nil check here
|
|
90
103
|
locals = api_map.source_map(location.filename).locals_at(location)
|
|
104
|
+
# @sg-ignore Need to add nil check here
|
|
91
105
|
receiver_pin = chain.define(api_map, closure, locals).first
|
|
92
106
|
return ComplexType::UNDEFINED unless receiver_pin
|
|
93
107
|
|
|
94
108
|
types = receiver_pin.docstring.tag(:yieldreceiver)&.types
|
|
95
109
|
return ComplexType::UNDEFINED unless types&.any?
|
|
96
110
|
|
|
97
|
-
|
|
98
|
-
|
|
111
|
+
name_pin = self
|
|
112
|
+
# if we have Foo.bar { |x| ... }, and the bar method references self...
|
|
113
|
+
target = if chain.base.defined?
|
|
114
|
+
# figure out Foo
|
|
115
|
+
chain.base.infer(api_map, name_pin, locals)
|
|
116
|
+
else
|
|
117
|
+
# if not, any self there must be the context of our closure
|
|
118
|
+
# @sg-ignore Need to add nil check here
|
|
119
|
+
closure.full_context
|
|
120
|
+
end
|
|
99
121
|
|
|
100
122
|
ComplexType.try_parse(*types).qualify(api_map, *receiver_pin.gates).self_to_type(target)
|
|
101
123
|
end
|
|
@@ -1,9 +1,13 @@
|
|
|
1
1
|
module Solargraph
|
|
2
2
|
module Pin
|
|
3
|
-
# Mix-in for pins which enclose code which the 'break' statement
|
|
3
|
+
# Mix-in for pins which enclose code which the 'break' statement
|
|
4
|
+
# works with-in - e.g., blocks, when, until, ...
|
|
4
5
|
module Breakable
|
|
5
6
|
# @return [Parser::AST::Node]
|
|
6
7
|
attr_reader :node
|
|
8
|
+
|
|
9
|
+
# @return [Location, nil]
|
|
10
|
+
attr_reader :location
|
|
7
11
|
end
|
|
8
12
|
end
|
|
9
13
|
end
|
|
@@ -21,8 +21,15 @@ module Solargraph
|
|
|
21
21
|
@parameters = parameters
|
|
22
22
|
end
|
|
23
23
|
|
|
24
|
+
def reset_generated!
|
|
25
|
+
parameters.each(&:reset_generated!)
|
|
26
|
+
super
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# @sg-ignore Need to add nil check here
|
|
24
30
|
# @return [String]
|
|
25
31
|
def method_namespace
|
|
32
|
+
# @sg-ignore Need to add nil check here
|
|
26
33
|
closure.namespace
|
|
27
34
|
end
|
|
28
35
|
|
|
@@ -80,6 +87,7 @@ module Solargraph
|
|
|
80
87
|
end
|
|
81
88
|
end
|
|
82
89
|
|
|
90
|
+
# @sg-ignore Need to add nil check here
|
|
83
91
|
# @return [Array<Pin::Parameter>]
|
|
84
92
|
def blockless_parameters
|
|
85
93
|
if parameters.last&.block?
|
|
@@ -89,11 +97,33 @@ module Solargraph
|
|
|
89
97
|
end
|
|
90
98
|
end
|
|
91
99
|
|
|
92
|
-
#
|
|
100
|
+
# e.g., [["T"], "", "?", "foo:"] - parameter arity declarations,
|
|
101
|
+
# ignoring positional names. Used to match signatures.
|
|
102
|
+
#
|
|
103
|
+
# @return [Array<Array<String>, String, nil>]
|
|
93
104
|
def arity
|
|
94
105
|
[generics, blockless_parameters.map(&:arity_decl), block&.arity]
|
|
95
106
|
end
|
|
96
107
|
|
|
108
|
+
# e.g., [["T"], "1", "?3", "foo:5"] - parameter arity
|
|
109
|
+
# declarations, including the number of unique types in each
|
|
110
|
+
# parameter. Used to determine whether combining two
|
|
111
|
+
# signatures has lost useful information mapping specific
|
|
112
|
+
# parameter types to specific return types.
|
|
113
|
+
#
|
|
114
|
+
# @return [Array<Array, String, nil>]
|
|
115
|
+
def type_arity
|
|
116
|
+
[generics, blockless_parameters.map(&:type_arity_decl), block&.type_arity]
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
# Same as type_arity, but includes return type arity at the front.
|
|
120
|
+
#
|
|
121
|
+
# @return [Array<Array, String, nil>]
|
|
122
|
+
def full_type_arity
|
|
123
|
+
# @sg-ignore flow sensitive typing needs to handle attrs
|
|
124
|
+
[return_type ? return_type.items.count.to_s : nil] + type_arity
|
|
125
|
+
end
|
|
126
|
+
|
|
97
127
|
# @param generics_to_resolve [Enumerable<String>]
|
|
98
128
|
# @param arg_types [Array<ComplexType>, nil]
|
|
99
129
|
# @param return_type_context [ComplexType, nil]
|
|
@@ -101,6 +131,7 @@ module Solargraph
|
|
|
101
131
|
# @param yield_return_type_context [ComplexType, nil]
|
|
102
132
|
# @param context [ComplexType, nil]
|
|
103
133
|
# @param resolved_generic_values [Hash{String => ComplexType}]
|
|
134
|
+
#
|
|
104
135
|
# @return [self]
|
|
105
136
|
def resolve_generics_from_context(generics_to_resolve,
|
|
106
137
|
arg_types = nil,
|
|
@@ -137,9 +168,11 @@ module Solargraph
|
|
|
137
168
|
end
|
|
138
169
|
end
|
|
139
170
|
|
|
171
|
+
# @sg-ignore Need to add nil check here
|
|
140
172
|
# @return [String]
|
|
141
173
|
def method_name
|
|
142
174
|
raise "closure was nil in #{self.inspect}" if closure.nil?
|
|
175
|
+
# @sg-ignore Need to add nil check here
|
|
143
176
|
@method_name ||= closure.name
|
|
144
177
|
end
|
|
145
178
|
|
|
@@ -150,6 +183,7 @@ module Solargraph
|
|
|
150
183
|
# @param yield_return_type_context [ComplexType, nil]
|
|
151
184
|
# @param context [ComplexType, nil]
|
|
152
185
|
# @param resolved_generic_values [Hash{String => ComplexType}]
|
|
186
|
+
#
|
|
153
187
|
# @return [self]
|
|
154
188
|
def resolve_generics_from_context_until_complete(generics_to_resolve,
|
|
155
189
|
arg_types = nil,
|
|
@@ -184,7 +218,6 @@ module Solargraph
|
|
|
184
218
|
resolved_generic_values: resolved_generic_values)
|
|
185
219
|
end
|
|
186
220
|
|
|
187
|
-
# @return [Array<String>]
|
|
188
221
|
# @yieldparam [ComplexType]
|
|
189
222
|
# @yieldreturn [ComplexType]
|
|
190
223
|
# @return [self]
|
|
@@ -206,17 +239,31 @@ module Solargraph
|
|
|
206
239
|
parcount = mandatory_positional_param_count
|
|
207
240
|
parcount -= 1 if !parameters.empty? && parameters.last.block?
|
|
208
241
|
return false if block? && !with_block
|
|
242
|
+
# @todo this and its caller should be changed so that this can
|
|
243
|
+
# look at the kwargs provided and check names against what
|
|
244
|
+
# we acccept
|
|
209
245
|
return false if argcount < parcount && !(argcount == parcount - 1 && parameters.last.restarg?)
|
|
210
246
|
true
|
|
211
247
|
end
|
|
212
248
|
|
|
249
|
+
def reset_generated!
|
|
250
|
+
super
|
|
251
|
+
@parameters.each(&:reset_generated!)
|
|
252
|
+
end
|
|
253
|
+
|
|
213
254
|
# @return [Integer]
|
|
214
255
|
def mandatory_positional_param_count
|
|
215
256
|
parameters.count(&:arg?)
|
|
216
257
|
end
|
|
217
258
|
|
|
259
|
+
# @return [String]
|
|
260
|
+
def parameters_to_rbs
|
|
261
|
+
# @sg-ignore Need to add nil check here
|
|
262
|
+
rbs_generics + '(' + parameters.map { |param| param.to_rbs }.join(', ') + ') ' + (block.nil? ? '' : '{ ' + block.to_rbs + ' } ')
|
|
263
|
+
end
|
|
264
|
+
|
|
218
265
|
def to_rbs
|
|
219
|
-
|
|
266
|
+
parameters_to_rbs + '-> ' + (return_type&.to_rbs || 'untyped')
|
|
220
267
|
end
|
|
221
268
|
|
|
222
269
|
def block?
|
|
@@ -2,12 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
module Solargraph
|
|
4
4
|
module Pin
|
|
5
|
-
class Closure <
|
|
5
|
+
class Closure < CompoundStatement
|
|
6
6
|
# @return [::Symbol] :class or :instance
|
|
7
7
|
attr_reader :scope
|
|
8
8
|
|
|
9
9
|
# @param scope [::Symbol] :class or :instance
|
|
10
|
-
# @param generics [::Array<Pin::
|
|
10
|
+
# @param generics [::Array<Pin::String>, nil]
|
|
11
11
|
# @param generic_defaults [Hash{String => ComplexType}]
|
|
12
12
|
def initialize scope: :class, generics: nil, generic_defaults: {}, **splat
|
|
13
13
|
super(**splat)
|
|
@@ -44,10 +44,6 @@ module Solargraph
|
|
|
44
44
|
end
|
|
45
45
|
end
|
|
46
46
|
|
|
47
|
-
def binder
|
|
48
|
-
@binder || context
|
|
49
|
-
end
|
|
50
|
-
|
|
51
47
|
# @param api_map [Solargraph::ApiMap]
|
|
52
48
|
# @return [void]
|
|
53
49
|
def rebind api_map; end
|