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.
Files changed (162) hide show
  1. checksums.yaml +4 -4
  2. data/.envrc +3 -0
  3. data/.github/workflows/linting.yml +4 -5
  4. data/.github/workflows/plugins.yml +40 -36
  5. data/.github/workflows/rspec.yml +45 -13
  6. data/.github/workflows/typecheck.yml +2 -2
  7. data/.rubocop_todo.yml +27 -49
  8. data/README.md +3 -3
  9. data/Rakefile +1 -0
  10. data/lib/solargraph/api_map/cache.rb +110 -110
  11. data/lib/solargraph/api_map/constants.rb +289 -279
  12. data/lib/solargraph/api_map/index.rb +204 -193
  13. data/lib/solargraph/api_map/source_to_yard.rb +109 -97
  14. data/lib/solargraph/api_map/store.rb +387 -384
  15. data/lib/solargraph/api_map.rb +1000 -945
  16. data/lib/solargraph/complex_type/conformance.rb +176 -0
  17. data/lib/solargraph/complex_type/type_methods.rb +242 -228
  18. data/lib/solargraph/complex_type/unique_type.rb +632 -482
  19. data/lib/solargraph/complex_type.rb +549 -444
  20. data/lib/solargraph/convention/data_definition/data_definition_node.rb +93 -91
  21. data/lib/solargraph/convention/data_definition.rb +108 -105
  22. data/lib/solargraph/convention/struct_definition/struct_assignment_node.rb +62 -61
  23. data/lib/solargraph/convention/struct_definition/struct_definition_node.rb +103 -102
  24. data/lib/solargraph/convention/struct_definition.rb +168 -164
  25. data/lib/solargraph/diagnostics/require_not_found.rb +54 -53
  26. data/lib/solargraph/diagnostics/rubocop.rb +119 -118
  27. data/lib/solargraph/diagnostics/rubocop_helpers.rb +70 -68
  28. data/lib/solargraph/diagnostics/type_check.rb +56 -55
  29. data/lib/solargraph/doc_map.rb +200 -439
  30. data/lib/solargraph/equality.rb +34 -34
  31. data/lib/solargraph/gem_pins.rb +97 -98
  32. data/lib/solargraph/language_server/host/dispatch.rb +131 -130
  33. data/lib/solargraph/language_server/host/message_worker.rb +113 -112
  34. data/lib/solargraph/language_server/host/sources.rb +100 -99
  35. data/lib/solargraph/language_server/host.rb +883 -878
  36. data/lib/solargraph/language_server/message/extended/check_gem_version.rb +109 -114
  37. data/lib/solargraph/language_server/message/extended/document.rb +24 -23
  38. data/lib/solargraph/language_server/message/text_document/completion.rb +58 -56
  39. data/lib/solargraph/language_server/message/text_document/definition.rb +42 -40
  40. data/lib/solargraph/language_server/message/text_document/document_symbol.rb +28 -26
  41. data/lib/solargraph/language_server/message/text_document/formatting.rb +150 -148
  42. data/lib/solargraph/language_server/message/text_document/hover.rb +60 -58
  43. data/lib/solargraph/language_server/message/text_document/signature_help.rb +25 -24
  44. data/lib/solargraph/language_server/message/text_document/type_definition.rb +27 -25
  45. data/lib/solargraph/language_server/message/workspace/workspace_symbol.rb +25 -23
  46. data/lib/solargraph/library.rb +729 -683
  47. data/lib/solargraph/location.rb +87 -82
  48. data/lib/solargraph/logging.rb +57 -37
  49. data/lib/solargraph/parser/comment_ripper.rb +76 -69
  50. data/lib/solargraph/parser/flow_sensitive_typing.rb +483 -255
  51. data/lib/solargraph/parser/node_processor/base.rb +122 -92
  52. data/lib/solargraph/parser/node_processor.rb +63 -62
  53. data/lib/solargraph/parser/parser_gem/class_methods.rb +167 -149
  54. data/lib/solargraph/parser/parser_gem/node_chainer.rb +191 -166
  55. data/lib/solargraph/parser/parser_gem/node_methods.rb +506 -486
  56. data/lib/solargraph/parser/parser_gem/node_processors/and_node.rb +22 -22
  57. data/lib/solargraph/parser/parser_gem/node_processors/args_node.rb +61 -59
  58. data/lib/solargraph/parser/parser_gem/node_processors/begin_node.rb +24 -15
  59. data/lib/solargraph/parser/parser_gem/node_processors/block_node.rb +46 -46
  60. data/lib/solargraph/parser/parser_gem/node_processors/def_node.rb +60 -53
  61. data/lib/solargraph/parser/parser_gem/node_processors/if_node.rb +53 -23
  62. data/lib/solargraph/parser/parser_gem/node_processors/ivasgn_node.rb +41 -40
  63. data/lib/solargraph/parser/parser_gem/node_processors/lvasgn_node.rb +30 -29
  64. data/lib/solargraph/parser/parser_gem/node_processors/masgn_node.rb +61 -59
  65. data/lib/solargraph/parser/parser_gem/node_processors/opasgn_node.rb +98 -98
  66. data/lib/solargraph/parser/parser_gem/node_processors/or_node.rb +22 -0
  67. data/lib/solargraph/parser/parser_gem/node_processors/orasgn_node.rb +17 -17
  68. data/lib/solargraph/parser/parser_gem/node_processors/resbody_node.rb +39 -38
  69. data/lib/solargraph/parser/parser_gem/node_processors/sclass_node.rb +53 -52
  70. data/lib/solargraph/parser/parser_gem/node_processors/send_node.rb +296 -291
  71. data/lib/solargraph/parser/parser_gem/node_processors/when_node.rb +23 -0
  72. data/lib/solargraph/parser/parser_gem/node_processors/while_node.rb +33 -29
  73. data/lib/solargraph/parser/parser_gem/node_processors.rb +74 -70
  74. data/lib/solargraph/parser/region.rb +75 -69
  75. data/lib/solargraph/parser/snippet.rb +17 -17
  76. data/lib/solargraph/pin/base.rb +761 -729
  77. data/lib/solargraph/pin/base_variable.rb +418 -126
  78. data/lib/solargraph/pin/block.rb +126 -104
  79. data/lib/solargraph/pin/breakable.rb +13 -9
  80. data/lib/solargraph/pin/callable.rb +278 -231
  81. data/lib/solargraph/pin/closure.rb +68 -72
  82. data/lib/solargraph/pin/common.rb +94 -79
  83. data/lib/solargraph/pin/compound_statement.rb +55 -0
  84. data/lib/solargraph/pin/conversions.rb +124 -123
  85. data/lib/solargraph/pin/delegated_method.rb +131 -120
  86. data/lib/solargraph/pin/documenting.rb +115 -114
  87. data/lib/solargraph/pin/instance_variable.rb +38 -34
  88. data/lib/solargraph/pin/keyword.rb +16 -20
  89. data/lib/solargraph/pin/local_variable.rb +31 -75
  90. data/lib/solargraph/pin/method.rb +720 -672
  91. data/lib/solargraph/pin/method_alias.rb +42 -34
  92. data/lib/solargraph/pin/namespace.rb +121 -115
  93. data/lib/solargraph/pin/parameter.rb +338 -275
  94. data/lib/solargraph/pin/proxy_type.rb +40 -39
  95. data/lib/solargraph/pin/reference/override.rb +47 -47
  96. data/lib/solargraph/pin/reference/superclass.rb +17 -15
  97. data/lib/solargraph/pin/reference.rb +41 -39
  98. data/lib/solargraph/pin/search.rb +62 -61
  99. data/lib/solargraph/pin/signature.rb +69 -61
  100. data/lib/solargraph/pin/symbol.rb +53 -53
  101. data/lib/solargraph/pin/until.rb +18 -18
  102. data/lib/solargraph/pin/while.rb +18 -18
  103. data/lib/solargraph/pin.rb +46 -44
  104. data/lib/solargraph/pin_cache.rb +665 -245
  105. data/lib/solargraph/position.rb +118 -119
  106. data/lib/solargraph/range.rb +112 -112
  107. data/lib/solargraph/rbs_map/conversions.rb +846 -823
  108. data/lib/solargraph/rbs_map/core_map.rb +65 -58
  109. data/lib/solargraph/rbs_map/stdlib_map.rb +72 -43
  110. data/lib/solargraph/rbs_map.rb +217 -163
  111. data/lib/solargraph/shell.rb +397 -352
  112. data/lib/solargraph/source/chain/call.rb +372 -337
  113. data/lib/solargraph/source/chain/constant.rb +28 -26
  114. data/lib/solargraph/source/chain/hash.rb +35 -34
  115. data/lib/solargraph/source/chain/if.rb +29 -28
  116. data/lib/solargraph/source/chain/instance_variable.rb +34 -13
  117. data/lib/solargraph/source/chain/literal.rb +53 -48
  118. data/lib/solargraph/source/chain/or.rb +31 -23
  119. data/lib/solargraph/source/chain.rb +294 -291
  120. data/lib/solargraph/source/change.rb +89 -82
  121. data/lib/solargraph/source/cursor.rb +172 -166
  122. data/lib/solargraph/source/source_chainer.rb +204 -194
  123. data/lib/solargraph/source/updater.rb +59 -55
  124. data/lib/solargraph/source.rb +524 -498
  125. data/lib/solargraph/source_map/clip.rb +237 -226
  126. data/lib/solargraph/source_map/data.rb +37 -34
  127. data/lib/solargraph/source_map/mapper.rb +282 -259
  128. data/lib/solargraph/source_map.rb +220 -212
  129. data/lib/solargraph/type_checker/problem.rb +34 -32
  130. data/lib/solargraph/type_checker/rules.rb +157 -84
  131. data/lib/solargraph/type_checker.rb +895 -814
  132. data/lib/solargraph/version.rb +1 -1
  133. data/lib/solargraph/workspace/config.rb +257 -255
  134. data/lib/solargraph/workspace/gemspecs.rb +367 -0
  135. data/lib/solargraph/workspace/require_paths.rb +98 -97
  136. data/lib/solargraph/workspace.rb +362 -220
  137. data/lib/solargraph/yard_map/helpers.rb +45 -44
  138. data/lib/solargraph/yard_map/mapper/to_method.rb +134 -130
  139. data/lib/solargraph/yard_map/mapper/to_namespace.rb +32 -31
  140. data/lib/solargraph/yard_map/mapper.rb +84 -79
  141. data/lib/solargraph/yardoc.rb +97 -87
  142. data/lib/solargraph.rb +126 -105
  143. data/rbs/fills/rubygems/0/dependency.rbs +193 -0
  144. data/rbs/fills/tuple/tuple.rbs +28 -0
  145. data/rbs/shims/ast/0/node.rbs +5 -0
  146. data/rbs/shims/diff-lcs/1.5/diff-lcs.rbs +11 -0
  147. data/rbs_collection.yaml +1 -1
  148. data/solargraph.gemspec +2 -1
  149. metadata +22 -17
  150. data/lib/solargraph/type_checker/checks.rb +0 -124
  151. data/lib/solargraph/type_checker/param_def.rb +0 -37
  152. data/lib/solargraph/yard_map/to_method.rb +0 -89
  153. data/sig/shims/ast/0/node.rbs +0 -5
  154. /data/{sig → rbs}/shims/ast/2.4/.rbs_meta.yaml +0 -0
  155. /data/{sig → rbs}/shims/ast/2.4/ast.rbs +0 -0
  156. /data/{sig → rbs}/shims/parser/3.2.0.1/builders/default.rbs +0 -0
  157. /data/{sig → rbs}/shims/parser/3.2.0.1/manifest.yaml +0 -0
  158. /data/{sig → rbs}/shims/parser/3.2.0.1/parser.rbs +0 -0
  159. /data/{sig → rbs}/shims/parser/3.2.0.1/polyfill.rbs +0 -0
  160. /data/{sig → rbs}/shims/thor/1.2.0.1/.rbs_meta.yaml +0 -0
  161. /data/{sig → rbs}/shims/thor/1.2.0.1/manifest.yaml +0 -0
  162. /data/{sig → rbs}/shims/thor/1.2.0.1/thor.rbs +0 -0
@@ -1,291 +1,294 @@
1
- # frozen_string_literal: true
2
-
3
- # HACK: Fix autoload issue
4
- require 'solargraph/source/chain/link'
5
-
6
- module Solargraph
7
- class Source
8
- #
9
- # Represents an expression as a single call chain at the parse
10
- # tree level, made up of constants, variables, and method calls,
11
- # each represented as a Link object.
12
- #
13
- # Computes Pins and/or ComplexTypes representing the interpreted
14
- # expression.
15
- #
16
- class Chain
17
- include Equality
18
- include Logging
19
-
20
- autoload :Link, 'solargraph/source/chain/link'
21
- autoload :Call, 'solargraph/source/chain/call'
22
- autoload :QCall, 'solargraph/source/chain/q_call'
23
- autoload :Variable, 'solargraph/source/chain/variable'
24
- autoload :ClassVariable, 'solargraph/source/chain/class_variable'
25
- autoload :Constant, 'solargraph/source/chain/constant'
26
- autoload :InstanceVariable, 'solargraph/source/chain/instance_variable'
27
- autoload :GlobalVariable, 'solargraph/source/chain/global_variable'
28
- autoload :Literal, 'solargraph/source/chain/literal'
29
- autoload :Head, 'solargraph/source/chain/head'
30
- autoload :If, 'solargraph/source/chain/if'
31
- autoload :Or, 'solargraph/source/chain/or'
32
- autoload :BlockVariable, 'solargraph/source/chain/block_variable'
33
- autoload :BlockSymbol, 'solargraph/source/chain/block_symbol'
34
- autoload :ZSuper, 'solargraph/source/chain/z_super'
35
- autoload :Hash, 'solargraph/source/chain/hash'
36
- autoload :Array, 'solargraph/source/chain/array'
37
-
38
- @@inference_stack = []
39
- @@inference_depth = 0
40
- @@inference_invalidation_key = nil
41
- @@inference_cache = {}
42
-
43
- UNDEFINED_CALL = Chain::Call.new('<undefined>', nil)
44
- UNDEFINED_CONSTANT = Chain::Constant.new('<undefined>')
45
-
46
- # @return [::Array<Source::Chain::Link>]
47
- attr_reader :links
48
-
49
- attr_reader :node
50
-
51
- # @sg-ignore Fix "Not enough arguments to Module#protected"
52
- protected def equality_fields
53
- [links, node]
54
- end
55
-
56
- # @param node [Parser::AST::Node, nil]
57
- # @param links [::Array<Chain::Link>]
58
- # @param splat [Boolean]
59
- def initialize links, node = nil, splat = false
60
- @links = links.clone
61
- @links.push UNDEFINED_CALL if @links.empty?
62
- head = true
63
- @links.map! do |link|
64
- result = (head ? link.clone_head : link.clone_body)
65
- head = false
66
- result
67
- end
68
- @node = node
69
- @splat = splat
70
- end
71
-
72
- # @return [Chain]
73
- def base
74
- @base ||= Chain.new(links[0..-2])
75
- end
76
-
77
- # Determine potential Pins returned by this chain of words
78
- #
79
- # @param api_map [ApiMap]
80
- #
81
- # @param name_pin [Pin::Base] A pin
82
- # representing the place in which expression is evaluated (e.g.,
83
- # a Method pin, or a Module or Class pin if not run within a
84
- # method - both in terms of the closure around the chain, as well
85
- # as the self type used for any method calls in head position.
86
- #
87
- # Requirements for name_pin:
88
- #
89
- # * name_pin.context: This should be a type representing the
90
- # namespace where we can look up non-local variables and
91
- # method names. If it is a Class<X>, we will look up
92
- # :class scoped methods/variables.
93
- #
94
- # * name_pin.binder: Used for method call lookups only
95
- # (Chain::Call links). For method calls as the first
96
- # element in the chain, 'name_pin.binder' should be the
97
- # same as name_pin.context above. For method calls later
98
- # in the chain (e.g., 'b' in a.b.c), it should represent
99
- # 'a'.
100
- #
101
- # @param locals [::Array<Pin::LocalVariable>] Any local
102
- # variables / method parameters etc visible by the statement
103
- #
104
- # @return [::Array<Pin::Base>] Pins representing possible return
105
- # types of this method.
106
- def define api_map, name_pin, locals
107
- return [] if undefined?
108
-
109
- # working_pin is the surrounding closure pin for the link
110
- # being processed, whose #binder method will provide the LHS /
111
- # 'self type' of the next link (same as the #return_type method
112
- # --the type of the result so far).
113
- #
114
- # @todo ProxyType uses 'type' for the binder, but '
115
- working_pin = name_pin
116
- links[0..-2].each do |link|
117
- pins = link.resolve(api_map, working_pin, locals)
118
- type = infer_from_definitions(pins, working_pin, api_map, locals)
119
- if type.undefined?
120
- logger.debug { "Chain#define(links=#{links.map(&:desc)}, name_pin=#{name_pin.inspect}, locals=#{locals}) => [] - undefined type from #{link.desc}" }
121
- return []
122
- end
123
- # We continue to use the context from the head pin, in case
124
- # we need it to, for instance, provide context for a block
125
- # evaluation. However, we use the last link's return type
126
- # for the binder, as this is chaining off of it, and the
127
- # binder is now the lhs of the rhs we are evaluating.
128
- working_pin = Pin::ProxyType.anonymous(name_pin.context, binder: type, closure: name_pin, source: :chain)
129
- logger.debug { "Chain#define(links=#{links.map(&:desc)}, name_pin=#{name_pin.inspect}, locals=#{locals}) - after processing #{link.desc}, new working_pin=#{working_pin} with binder #{working_pin.binder}" }
130
- end
131
- links.last.last_context = working_pin
132
- links.last.resolve(api_map, working_pin, locals)
133
- end
134
-
135
- # @param api_map [ApiMap]
136
- # @param name_pin [Pin::Base] The pin for the closure in which this code runs
137
- # @param locals [::Array<Pin::LocalVariable>]
138
- # @return [ComplexType]
139
- # @sg-ignore
140
- def infer api_map, name_pin, locals
141
- cache_key = [node, node&.location, links, name_pin&.return_type, locals]
142
- if @@inference_invalidation_key == api_map.hash
143
- cached = @@inference_cache[cache_key]
144
- return cached if cached
145
- else
146
- @@inference_invalidation_key = api_map.hash
147
- @@inference_cache = {}
148
- end
149
- out = infer_uncached(api_map, name_pin, locals).downcast_to_literal_if_possible
150
- logger.debug { "Chain#infer() - caching result - cache_key_hash=#{cache_key.hash}, links.map(&:hash)=#{links.map(&:hash)}, links=#{links}, cache_key.map(&:hash) = #{cache_key.map(&:hash)}, cache_key=#{cache_key}" }
151
- @@inference_cache[cache_key] = out
152
- end
153
-
154
- # @param api_map [ApiMap]
155
- # @param name_pin [Pin::Base]
156
- # @param locals [::Array<Pin::LocalVariable>]
157
- # @return [ComplexType]
158
- def infer_uncached api_map, name_pin, locals
159
- pins = define(api_map, name_pin, locals)
160
- if pins.empty?
161
- logger.debug { "Chain#infer_uncached(links=#{links.map(&:desc)}, locals=#{locals.map(&:desc)}) => undefined - no pins" }
162
- return ComplexType::UNDEFINED
163
- end
164
- type = infer_from_definitions(pins, links.last.last_context, api_map, locals)
165
- out = maybe_nil(type)
166
- logger.debug { "Chain#infer_uncached(links=#{self.links.map(&:desc)}, locals=#{locals.map(&:desc)}, name_pin=#{name_pin}, name_pin.closure=#{name_pin.closure.inspect}, name_pin.binder=#{name_pin.binder}) => #{out.rooted_tags.inspect}" }
167
- out
168
- end
169
-
170
- # @return [Boolean]
171
- def literal?
172
- links.last.is_a?(Chain::Literal)
173
- end
174
-
175
- def undefined?
176
- links.any?(&:undefined?)
177
- end
178
-
179
- def defined?
180
- !undefined?
181
- end
182
-
183
- # @return [Boolean]
184
- def constant?
185
- links.last.is_a?(Chain::Constant)
186
- end
187
-
188
- def splat?
189
- @splat
190
- end
191
-
192
- def nullable?
193
- links.any?(&:nullable?)
194
- end
195
-
196
- include Logging
197
-
198
- # @return [String]
199
- def desc
200
- links.map(&:desc).to_s
201
- end
202
-
203
- def to_s
204
- desc
205
- end
206
-
207
- include Logging
208
-
209
- private
210
-
211
- # @param pins [::Array<Pin::Base>]
212
- # @param context [Pin::Base]
213
- # @param api_map [ApiMap]
214
- # @param locals [::Enumerable<Pin::LocalVariable>]
215
- # @return [ComplexType]
216
- def infer_from_definitions pins, context, api_map, locals
217
- # @type [::Array<ComplexType>]
218
- types = []
219
- unresolved_pins = []
220
- # @todo this param tag shouldn't be needed to probe the type
221
- # @todo ...but given it is needed, typecheck should complain that it is needed
222
- # @param pin [Pin::Base]
223
- pins.each do |pin|
224
- # Avoid infinite recursion
225
- next if @@inference_stack.include?(pin)
226
-
227
- @@inference_stack.push pin
228
- type = pin.typify(api_map)
229
- @@inference_stack.pop
230
- if type.defined?
231
- if type.generic?
232
- # @todo even at strong, no typechecking complaint
233
- # happens when a [Pin::Base,nil] is passed into a method
234
- # that accepts only [Pin::Namespace] as an argument
235
- type = type.resolve_generics(pin.closure, context.binder)
236
- end
237
- types << type
238
- else
239
- unresolved_pins << pin
240
- end
241
- end
242
-
243
- # Limit method inference recursion
244
- if @@inference_depth >= 10 && pins.first.is_a?(Pin::Method)
245
- return ComplexType::UNDEFINED
246
- end
247
-
248
- @@inference_depth += 1
249
- # @param pin [Pin::Base]
250
- unresolved_pins.each do |pin|
251
- # Avoid infinite recursion
252
- if @@inference_stack.include?(pin.identity)
253
- next
254
- end
255
-
256
- @@inference_stack.push(pin.identity)
257
- type = pin.probe(api_map)
258
- @@inference_stack.pop
259
- types.push type if type
260
- end
261
- @@inference_depth -= 1
262
-
263
- type = if types.empty?
264
- ComplexType::UNDEFINED
265
- elsif types.length > 1
266
- # Move nil to the end by convention
267
-
268
- # @param a [ComplexType::UniqueType]
269
- sorted = types.flat_map(&:items).sort { |a, _| a.tag == 'nil' ? 1 : 0 }
270
- ComplexType.new(sorted.uniq)
271
- else
272
- ComplexType.new(types)
273
- end
274
- if context.nil? || context.return_type.undefined?
275
- # up to downstream to resolve self type
276
- return type
277
- end
278
-
279
- type.self_to_type(context.return_type)
280
- end
281
-
282
- # @param type [ComplexType]
283
- # @return [ComplexType]
284
- def maybe_nil type
285
- return type if type.undefined? || type.void? || type.nullable?
286
- return type unless nullable?
287
- ComplexType.new(type.items + [ComplexType::NIL])
288
- end
289
- end
290
- end
291
- end
1
+ # frozen_string_literal: true
2
+
3
+ # HACK: Fix autoload issue
4
+ require 'solargraph/source/chain/link'
5
+
6
+ module Solargraph
7
+ class Source
8
+ #
9
+ # Represents an expression as a single call chain at the parse
10
+ # tree level, made up of constants, variables, and method calls,
11
+ # each represented as a Link object.
12
+ #
13
+ # Computes Pins and/or ComplexTypes representing the interpreted
14
+ # expression.
15
+ #
16
+ class Chain
17
+ include Equality
18
+ include Logging
19
+
20
+ autoload :Link, 'solargraph/source/chain/link'
21
+ autoload :Call, 'solargraph/source/chain/call'
22
+ autoload :QCall, 'solargraph/source/chain/q_call'
23
+ autoload :Variable, 'solargraph/source/chain/variable'
24
+ autoload :ClassVariable, 'solargraph/source/chain/class_variable'
25
+ autoload :Constant, 'solargraph/source/chain/constant'
26
+ autoload :InstanceVariable, 'solargraph/source/chain/instance_variable'
27
+ autoload :GlobalVariable, 'solargraph/source/chain/global_variable'
28
+ autoload :Literal, 'solargraph/source/chain/literal'
29
+ autoload :Head, 'solargraph/source/chain/head'
30
+ autoload :If, 'solargraph/source/chain/if'
31
+ autoload :Or, 'solargraph/source/chain/or'
32
+ autoload :BlockVariable, 'solargraph/source/chain/block_variable'
33
+ autoload :BlockSymbol, 'solargraph/source/chain/block_symbol'
34
+ autoload :ZSuper, 'solargraph/source/chain/z_super'
35
+ autoload :Hash, 'solargraph/source/chain/hash'
36
+ autoload :Array, 'solargraph/source/chain/array'
37
+
38
+ @@inference_stack = []
39
+ @@inference_depth = 0
40
+ @@inference_invalidation_key = nil
41
+ @@inference_cache = {}
42
+
43
+ UNDEFINED_CALL = Chain::Call.new('<undefined>', nil)
44
+ UNDEFINED_CONSTANT = Chain::Constant.new('<undefined>')
45
+
46
+ # @return [::Array<Source::Chain::Link>]
47
+ attr_reader :links
48
+
49
+ attr_reader :node
50
+
51
+ # @sg-ignore Fix "Not enough arguments to Module#protected"
52
+ protected def equality_fields
53
+ [links, node]
54
+ end
55
+
56
+ # @param node [Parser::AST::Node, nil]
57
+ # @param links [::Array<Chain::Link>]
58
+ # @param splat [Boolean]
59
+ def initialize links, node = nil, splat = false
60
+ @links = links.clone
61
+ @links.push UNDEFINED_CALL if @links.empty?
62
+ head = true
63
+ @links.map! do |link|
64
+ result = (head ? link.clone_head : link.clone_body)
65
+ head = false
66
+ result
67
+ end
68
+ @node = node
69
+ @splat = splat
70
+ end
71
+
72
+ # @return [Chain]
73
+ def base
74
+ # @sg-ignore Need to add nil check here
75
+ @base ||= Chain.new(links[0..-2])
76
+ end
77
+
78
+ # Determine potential Pins returned by this chain of words
79
+ #
80
+ # @param api_map [ApiMap]
81
+ #
82
+ # @param name_pin [Pin::Base] A pin representing the closure in
83
+ # which expression is evaluated (e.g., a Method pin, or a
84
+ # Module or Class pin if not run within a method - both in
85
+ # terms of the closure around the chain, as well as the self
86
+ # type used for any method calls in head position.
87
+ #
88
+ # Requirements for name_pin:
89
+ #
90
+ # * name_pin.context: This should be a type representing the
91
+ # namespace where we can look up non-local variables. If
92
+ # it is a Class<X>, we will look up :class scoped
93
+ # instance variables.
94
+ #
95
+ # * name_pin.binder: Used for method call lookups only
96
+ # (Chain::Call links). For method calls as the first
97
+ # element in the chain, 'name_pin.binder' should be the
98
+ # same as name_pin.context above. For method calls later
99
+ # in the chain, it changes. (e.g., for 'b' in a.b.c, it
100
+ # should represent the type of 'a').
101
+ #
102
+ # @param locals [::Array<Pin::LocalVariable>] Any local
103
+ # variables / method parameters etc visible by the statement
104
+ #
105
+ # @return [::Array<Pin::Base>] Pins representing possible return
106
+ # types of this method.
107
+ def define api_map, name_pin, locals
108
+ return [] if undefined?
109
+
110
+ # working_pin is the surrounding closure pin for the link
111
+ # being processed, whose #binder method will provide the LHS /
112
+ # 'self type' of the next link (same as the #return_type method
113
+ # --the type of the result so far).
114
+ #
115
+ # @todo ProxyType uses 'type' for the binder, but '
116
+ working_pin = name_pin
117
+ # @sg-ignore Need to add nil check here
118
+ links[0..-2].each do |link|
119
+ pins = link.resolve(api_map, working_pin, locals)
120
+ type = infer_from_definitions(pins, working_pin, api_map, locals)
121
+ if type.undefined?
122
+ logger.debug { "Chain#define(links=#{links.map(&:desc)}, name_pin=#{name_pin.inspect}, locals=#{locals}) => [] - undefined type from #{link.desc}" }
123
+ return []
124
+ end
125
+ # We continue to use the context from the head pin, in case
126
+ # we need it to, for instance, provide context for a block
127
+ # evaluation. However, we use the last link's return type
128
+ # for the binder, as this is chaining off of it, and the
129
+ # binder is now the lhs of the rhs we are evaluating.
130
+ working_pin = Pin::ProxyType.anonymous(name_pin.context, binder: type, closure: name_pin, source: :chain)
131
+ logger.debug { "Chain#define(links=#{links.map(&:desc)}, name_pin=#{name_pin.inspect}, locals=#{locals}) - after processing #{link.desc}, new working_pin=#{working_pin} with binder #{working_pin.binder}" }
132
+ end
133
+ links.last.last_context = working_pin
134
+ links.last.resolve(api_map, working_pin, locals)
135
+ end
136
+
137
+ # @param api_map [ApiMap]
138
+ # @param name_pin [Pin::Base] The pin for the closure in which this code runs
139
+ # @param locals [::Array<Pin::LocalVariable>]
140
+ # @return [ComplexType]
141
+ # @sg-ignore
142
+ def infer api_map, name_pin, locals
143
+ # includes binder as it is mutable in Pin::Block
144
+ cache_key = [node, node&.location, links, name_pin&.return_type, name_pin&.binder, locals]
145
+ if @@inference_invalidation_key == api_map.hash
146
+ cached = @@inference_cache[cache_key]
147
+ return cached if cached
148
+ else
149
+ @@inference_invalidation_key = api_map.hash
150
+ @@inference_cache = {}
151
+ end
152
+ out = infer_uncached(api_map, name_pin, locals).downcast_to_literal_if_possible
153
+ logger.debug { "Chain#infer() - caching result - cache_key_hash=#{cache_key.hash}, links.map(&:hash)=#{links.map(&:hash)}, links=#{links}, cache_key.map(&:hash) = #{cache_key.map(&:hash)}, cache_key=#{cache_key}" }
154
+ @@inference_cache[cache_key] = out
155
+ end
156
+
157
+ # @param api_map [ApiMap]
158
+ # @param name_pin [Pin::Base]
159
+ # @param locals [::Array<Pin::LocalVariable>]
160
+ # @return [ComplexType, ComplexType::UniqueType]
161
+ def infer_uncached api_map, name_pin, locals
162
+ pins = define(api_map, name_pin, locals)
163
+ if pins.empty?
164
+ logger.debug { "Chain#infer_uncached(links=#{links.map(&:desc)}, locals=#{locals.map(&:desc)}) => undefined - no pins" }
165
+ return ComplexType::UNDEFINED
166
+ end
167
+ type = infer_from_definitions(pins, links.last.last_context, api_map, locals)
168
+ out = maybe_nil(type)
169
+ logger.debug { "Chain#infer_uncached(links=#{self.links.map(&:desc)}, locals=#{locals.map(&:desc)}, name_pin=#{name_pin}, name_pin.closure=#{name_pin.closure.inspect}, name_pin.binder=#{name_pin.binder}) => #{out.rooted_tags.inspect}" }
170
+ out
171
+ end
172
+
173
+ # @return [Boolean]
174
+ def literal?
175
+ links.last.is_a?(Chain::Literal)
176
+ end
177
+
178
+ def undefined?
179
+ links.any?(&:undefined?)
180
+ end
181
+
182
+ def defined?
183
+ !undefined?
184
+ end
185
+
186
+ # @return [Boolean]
187
+ def constant?
188
+ links.last.is_a?(Chain::Constant)
189
+ end
190
+
191
+ def splat?
192
+ @splat
193
+ end
194
+
195
+ def nullable?
196
+ links.any?(&:nullable?)
197
+ end
198
+
199
+ include Logging
200
+
201
+ # @return [String]
202
+ def desc
203
+ links.map(&:desc).to_s
204
+ end
205
+
206
+ def to_s
207
+ desc
208
+ end
209
+
210
+ include Logging
211
+
212
+ private
213
+
214
+ # @param pins [::Array<Pin::Base>]
215
+ # @param name_pin [Pin::Base]
216
+ # @param api_map [ApiMap]
217
+ # @param locals [::Enumerable<Pin::LocalVariable>]
218
+ # @return [ComplexType, ComplexType::UniqueType]
219
+ def infer_from_definitions pins, name_pin, api_map, locals
220
+ # @type [::Array<ComplexType, ComplexType::UniqueType>]
221
+ types = []
222
+ unresolved_pins = []
223
+ # @todo this param tag shouldn't be needed to probe the type
224
+ # @todo ...but given it is needed, typecheck should complain that it is needed
225
+ # @param pin [Pin::Base]
226
+ pins.each do |pin|
227
+ # Avoid infinite recursion
228
+ next if @@inference_stack.include?(pin)
229
+
230
+ @@inference_stack.push pin
231
+ type = pin.typify(api_map)
232
+ @@inference_stack.pop
233
+ if type.defined?
234
+ if type.generic?
235
+ # @todo even at strong, no typechecking complaint
236
+ # happens when a [Pin::Base,nil] is passed into a method
237
+ # that accepts only [Pin::Namespace] as an argument
238
+ # @sg-ignore Need to add nil check here
239
+ type = type.resolve_generics(pin.closure, name_pin.binder)
240
+ end
241
+ types << type
242
+ else
243
+ unresolved_pins << pin
244
+ end
245
+ end
246
+
247
+ # Limit method inference recursion
248
+ if @@inference_depth >= 10 && pins.first.is_a?(Pin::Method)
249
+ return ComplexType::UNDEFINED
250
+ end
251
+
252
+ @@inference_depth += 1
253
+ # @param pin [Pin::Base]
254
+ unresolved_pins.each do |pin|
255
+ # Avoid infinite recursion
256
+ if @@inference_stack.include?(pin.identity)
257
+ next
258
+ end
259
+
260
+ @@inference_stack.push(pin.identity)
261
+ type = pin.probe(api_map)
262
+ @@inference_stack.pop
263
+ types.push type if type
264
+ end
265
+ @@inference_depth -= 1
266
+
267
+ type = if types.empty?
268
+ ComplexType::UNDEFINED
269
+ elsif types.length > 1
270
+ # Move nil to the end by convention
271
+
272
+ # @param a [ComplexType::UniqueType]
273
+ sorted = types.flat_map(&:items).sort { |a, _| a.tag == 'nil' ? 1 : 0 }
274
+ ComplexType.new(sorted.uniq)
275
+ else
276
+ ComplexType.new(types)
277
+ end
278
+ if name_pin.nil? || name_pin.context.undefined?
279
+ # up to downstream to resolve self type
280
+ return type
281
+ end
282
+ type.self_to_type(name_pin.context)
283
+ end
284
+
285
+ # @param type [ComplexType, ComplexType::UniqueType]
286
+ # @return [ComplexType, ComplexType::UniqueType]
287
+ def maybe_nil type
288
+ return type if type.undefined? || type.void? || type.nullable?
289
+ return type unless nullable?
290
+ ComplexType.new(type.items + [ComplexType::NIL])
291
+ end
292
+ end
293
+ end
294
+ end