solargraph 0.56.0 → 0.58.2

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