solargraph 0.58.0 → 0.59.0

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