solargraph 0.54.0 → 0.58.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 (200) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/linting.yml +127 -0
  3. data/.github/workflows/plugins.yml +184 -6
  4. data/.github/workflows/rspec.yml +55 -5
  5. data/.github/workflows/typecheck.yml +8 -3
  6. data/.gitignore +7 -0
  7. data/.overcommit.yml +72 -0
  8. data/.rspec +1 -0
  9. data/.rubocop.yml +66 -0
  10. data/.rubocop_todo.yml +1279 -0
  11. data/.yardopts +1 -0
  12. data/CHANGELOG.md +171 -0
  13. data/README.md +20 -6
  14. data/Rakefile +125 -13
  15. data/bin/solargraph +8 -5
  16. data/lib/solargraph/api_map/cache.rb +13 -3
  17. data/lib/solargraph/api_map/constants.rb +279 -0
  18. data/lib/solargraph/api_map/index.rb +193 -0
  19. data/lib/solargraph/api_map/source_to_yard.rb +13 -4
  20. data/lib/solargraph/api_map/store.rb +207 -132
  21. data/lib/solargraph/api_map.rb +394 -261
  22. data/lib/solargraph/bench.rb +18 -1
  23. data/lib/solargraph/complex_type/type_methods.rb +29 -12
  24. data/lib/solargraph/complex_type/unique_type.rb +205 -26
  25. data/lib/solargraph/complex_type.rb +126 -26
  26. data/lib/solargraph/convention/active_support_concern.rb +111 -0
  27. data/lib/solargraph/convention/base.rb +20 -3
  28. data/lib/solargraph/convention/data_definition/data_assignment_node.rb +61 -0
  29. data/lib/solargraph/convention/data_definition/data_definition_node.rb +91 -0
  30. data/lib/solargraph/convention/data_definition.rb +105 -0
  31. data/lib/solargraph/convention/gemspec.rb +3 -2
  32. data/lib/solargraph/convention/struct_definition/struct_assignment_node.rb +61 -0
  33. data/lib/solargraph/convention/struct_definition/struct_definition_node.rb +102 -0
  34. data/lib/solargraph/convention/struct_definition.rb +164 -0
  35. data/lib/solargraph/convention.rb +36 -4
  36. data/lib/solargraph/diagnostics/rubocop.rb +6 -1
  37. data/lib/solargraph/diagnostics/rubocop_helpers.rb +5 -3
  38. data/lib/solargraph/doc_map.rb +316 -64
  39. data/lib/solargraph/environ.rb +9 -2
  40. data/lib/solargraph/equality.rb +34 -0
  41. data/lib/solargraph/gem_pins.rb +64 -38
  42. data/lib/solargraph/language_server/host/dispatch.rb +2 -0
  43. data/lib/solargraph/language_server/host/message_worker.rb +54 -5
  44. data/lib/solargraph/language_server/host.rb +36 -18
  45. data/lib/solargraph/language_server/message/base.rb +20 -12
  46. data/lib/solargraph/language_server/message/extended/check_gem_version.rb +2 -0
  47. data/lib/solargraph/language_server/message/extended/document.rb +5 -2
  48. data/lib/solargraph/language_server/message/extended/document_gems.rb +3 -3
  49. data/lib/solargraph/language_server/message/initialize.rb +3 -1
  50. data/lib/solargraph/language_server/message/text_document/completion.rb +0 -3
  51. data/lib/solargraph/language_server/message/text_document/definition.rb +5 -3
  52. data/lib/solargraph/language_server/message/text_document/document_symbol.rb +3 -3
  53. data/lib/solargraph/language_server/message/text_document/formatting.rb +23 -2
  54. data/lib/solargraph/language_server/message/text_document/hover.rb +1 -1
  55. data/lib/solargraph/language_server/message/text_document/type_definition.rb +4 -3
  56. data/lib/solargraph/language_server/message/workspace/did_change_workspace_folders.rb +2 -0
  57. data/lib/solargraph/language_server/message/workspace/workspace_symbol.rb +2 -2
  58. data/lib/solargraph/language_server/progress.rb +27 -2
  59. data/lib/solargraph/language_server/request.rb +4 -1
  60. data/lib/solargraph/library.rb +83 -73
  61. data/lib/solargraph/location.rb +45 -1
  62. data/lib/solargraph/logging.rb +12 -2
  63. data/lib/solargraph/page.rb +3 -0
  64. data/lib/solargraph/parser/comment_ripper.rb +20 -7
  65. data/lib/solargraph/parser/flow_sensitive_typing.rb +255 -0
  66. data/lib/solargraph/parser/node_processor/base.rb +10 -5
  67. data/lib/solargraph/parser/node_processor.rb +26 -8
  68. data/lib/solargraph/parser/parser_gem/class_methods.rb +10 -18
  69. data/lib/solargraph/parser/parser_gem/flawed_builder.rb +1 -0
  70. data/lib/solargraph/parser/parser_gem/node_chainer.rb +13 -11
  71. data/lib/solargraph/parser/parser_gem/node_methods.rb +10 -19
  72. data/lib/solargraph/parser/parser_gem/node_processors/alias_node.rb +2 -1
  73. data/lib/solargraph/parser/parser_gem/node_processors/and_node.rb +22 -0
  74. data/lib/solargraph/parser/parser_gem/node_processors/args_node.rb +26 -20
  75. data/lib/solargraph/parser/parser_gem/node_processors/block_node.rb +7 -4
  76. data/lib/solargraph/parser/parser_gem/node_processors/casgn_node.rb +2 -1
  77. data/lib/solargraph/parser/parser_gem/node_processors/cvasgn_node.rb +2 -1
  78. data/lib/solargraph/parser/parser_gem/node_processors/def_node.rb +6 -3
  79. data/lib/solargraph/parser/parser_gem/node_processors/defs_node.rb +2 -1
  80. data/lib/solargraph/parser/parser_gem/node_processors/gvasgn_node.rb +2 -1
  81. data/lib/solargraph/parser/parser_gem/node_processors/if_node.rb +23 -0
  82. data/lib/solargraph/parser/parser_gem/node_processors/ivasgn_node.rb +4 -2
  83. data/lib/solargraph/parser/parser_gem/node_processors/lvasgn_node.rb +2 -1
  84. data/lib/solargraph/parser/parser_gem/node_processors/masgn_node.rb +14 -2
  85. data/lib/solargraph/parser/parser_gem/node_processors/namespace_node.rb +8 -7
  86. data/lib/solargraph/parser/parser_gem/node_processors/opasgn_node.rb +98 -0
  87. data/lib/solargraph/parser/parser_gem/node_processors/orasgn_node.rb +1 -0
  88. data/lib/solargraph/parser/parser_gem/node_processors/resbody_node.rb +3 -1
  89. data/lib/solargraph/parser/parser_gem/node_processors/sclass_node.rb +16 -6
  90. data/lib/solargraph/parser/parser_gem/node_processors/send_node.rb +64 -32
  91. data/lib/solargraph/parser/parser_gem/node_processors/sym_node.rb +3 -1
  92. data/lib/solargraph/parser/parser_gem/node_processors/until_node.rb +29 -0
  93. data/lib/solargraph/parser/parser_gem/node_processors/while_node.rb +29 -0
  94. data/lib/solargraph/parser/parser_gem/node_processors.rb +14 -0
  95. data/lib/solargraph/parser/region.rb +4 -1
  96. data/lib/solargraph/parser/snippet.rb +2 -0
  97. data/lib/solargraph/parser.rb +3 -5
  98. data/lib/solargraph/pin/base.rb +417 -42
  99. data/lib/solargraph/pin/base_variable.rb +21 -12
  100. data/lib/solargraph/pin/block.rb +9 -26
  101. data/lib/solargraph/pin/breakable.rb +9 -0
  102. data/lib/solargraph/pin/callable.rb +231 -0
  103. data/lib/solargraph/pin/closure.rb +30 -10
  104. data/lib/solargraph/pin/common.rb +12 -7
  105. data/lib/solargraph/pin/constant.rb +2 -0
  106. data/lib/solargraph/pin/conversions.rb +3 -2
  107. data/lib/solargraph/pin/delegated_method.rb +20 -1
  108. data/lib/solargraph/pin/documenting.rb +16 -0
  109. data/lib/solargraph/pin/instance_variable.rb +2 -2
  110. data/lib/solargraph/pin/keyword.rb +7 -2
  111. data/lib/solargraph/pin/local_variable.rb +15 -7
  112. data/lib/solargraph/pin/method.rb +241 -70
  113. data/lib/solargraph/pin/method_alias.rb +3 -0
  114. data/lib/solargraph/pin/namespace.rb +21 -13
  115. data/lib/solargraph/pin/parameter.rb +94 -32
  116. data/lib/solargraph/pin/proxy_type.rb +17 -7
  117. data/lib/solargraph/pin/reference/override.rb +24 -6
  118. data/lib/solargraph/pin/reference/require.rb +2 -2
  119. data/lib/solargraph/pin/reference/superclass.rb +5 -0
  120. data/lib/solargraph/pin/reference.rb +17 -0
  121. data/lib/solargraph/pin/search.rb +6 -1
  122. data/lib/solargraph/pin/signature.rb +39 -121
  123. data/lib/solargraph/pin/singleton.rb +1 -1
  124. data/lib/solargraph/pin/symbol.rb +8 -2
  125. data/lib/solargraph/pin/until.rb +18 -0
  126. data/lib/solargraph/pin/while.rb +18 -0
  127. data/lib/solargraph/pin.rb +8 -2
  128. data/lib/solargraph/pin_cache.rb +245 -0
  129. data/lib/solargraph/position.rb +19 -0
  130. data/lib/solargraph/range.rb +23 -4
  131. data/lib/solargraph/rbs_map/conversions.rb +315 -99
  132. data/lib/solargraph/rbs_map/core_fills.rb +50 -16
  133. data/lib/solargraph/rbs_map/core_map.rb +41 -11
  134. data/lib/solargraph/rbs_map/stdlib_map.rb +15 -5
  135. data/lib/solargraph/rbs_map.rb +87 -16
  136. data/lib/solargraph/shell.rb +117 -17
  137. data/lib/solargraph/source/chain/array.rb +13 -8
  138. data/lib/solargraph/source/chain/block_symbol.rb +1 -1
  139. data/lib/solargraph/source/chain/block_variable.rb +1 -1
  140. data/lib/solargraph/source/chain/call.rb +135 -66
  141. data/lib/solargraph/source/chain/constant.rb +3 -66
  142. data/lib/solargraph/source/chain/hash.rb +9 -3
  143. data/lib/solargraph/source/chain/head.rb +1 -1
  144. data/lib/solargraph/source/chain/if.rb +7 -2
  145. data/lib/solargraph/source/chain/link.rb +38 -6
  146. data/lib/solargraph/source/chain/literal.rb +27 -2
  147. data/lib/solargraph/source/chain/or.rb +2 -2
  148. data/lib/solargraph/source/chain/z_super.rb +1 -1
  149. data/lib/solargraph/source/chain.rb +140 -63
  150. data/lib/solargraph/source/change.rb +2 -2
  151. data/lib/solargraph/source/cursor.rb +4 -4
  152. data/lib/solargraph/source/source_chainer.rb +3 -3
  153. data/lib/solargraph/source.rb +110 -89
  154. data/lib/solargraph/source_map/clip.rb +22 -28
  155. data/lib/solargraph/source_map/data.rb +34 -0
  156. data/lib/solargraph/source_map/mapper.rb +11 -7
  157. data/lib/solargraph/source_map.rb +50 -43
  158. data/lib/solargraph/type_checker/checks.rb +4 -0
  159. data/lib/solargraph/type_checker/param_def.rb +2 -0
  160. data/lib/solargraph/type_checker/rules.rb +35 -8
  161. data/lib/solargraph/type_checker.rb +331 -189
  162. data/lib/solargraph/version.rb +1 -1
  163. data/lib/solargraph/views/_method.erb +10 -10
  164. data/lib/solargraph/views/_namespace.erb +3 -3
  165. data/lib/solargraph/views/document.erb +10 -10
  166. data/lib/solargraph/views/environment.erb +3 -5
  167. data/lib/solargraph/workspace/config.rb +25 -5
  168. data/lib/solargraph/workspace/require_paths.rb +97 -0
  169. data/lib/solargraph/workspace.rb +53 -72
  170. data/lib/solargraph/yard_map/helpers.rb +29 -1
  171. data/lib/solargraph/yard_map/mapper/to_constant.rb +8 -5
  172. data/lib/solargraph/yard_map/mapper/to_method.rb +55 -19
  173. data/lib/solargraph/yard_map/mapper/to_namespace.rb +11 -7
  174. data/lib/solargraph/yard_map/mapper.rb +5 -3
  175. data/lib/solargraph/yard_map/to_method.rb +6 -3
  176. data/lib/solargraph/yardoc.rb +45 -10
  177. data/lib/solargraph.rb +35 -1
  178. data/rbs/fills/bundler/0/bundler.rbs +4271 -0
  179. data/rbs/fills/open3/0/open3.rbs +172 -0
  180. data/rbs/fills/rubygems/0/basic_specification.rbs +326 -0
  181. data/rbs/fills/rubygems/0/errors.rbs +364 -0
  182. data/rbs/fills/rubygems/0/spec_fetcher.rbs +107 -0
  183. data/rbs/fills/rubygems/0/specification.rbs +1753 -0
  184. data/rbs/fills/tuple/tuple.rbs +149 -0
  185. data/rbs_collection.yaml +19 -0
  186. data/sig/shims/ast/0/node.rbs +5 -0
  187. data/sig/shims/ast/2.4/.rbs_meta.yaml +9 -0
  188. data/sig/shims/ast/2.4/ast.rbs +73 -0
  189. data/sig/shims/parser/3.2.0.1/builders/default.rbs +195 -0
  190. data/sig/shims/parser/3.2.0.1/manifest.yaml +7 -0
  191. data/sig/shims/parser/3.2.0.1/parser.rbs +201 -0
  192. data/sig/shims/parser/3.2.0.1/polyfill.rbs +4 -0
  193. data/sig/shims/thor/1.2.0.1/.rbs_meta.yaml +9 -0
  194. data/sig/shims/thor/1.2.0.1/manifest.yaml +7 -0
  195. data/sig/shims/thor/1.2.0.1/thor.rbs +17 -0
  196. data/solargraph.gemspec +32 -10
  197. metadata +237 -37
  198. data/lib/.rubocop.yml +0 -22
  199. data/lib/solargraph/cache.rb +0 -77
  200. data/lib/solargraph/parser/node_methods.rb +0 -83
@@ -5,10 +5,18 @@ require 'solargraph/source/chain/link'
5
5
 
6
6
  module Solargraph
7
7
  class Source
8
- # A chain of constants, variables, and method calls for inferring types of
9
- # values.
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.
10
15
  #
11
16
  class Chain
17
+ include Equality
18
+ include Logging
19
+
12
20
  autoload :Link, 'solargraph/source/chain/link'
13
21
  autoload :Call, 'solargraph/source/chain/call'
14
22
  autoload :QCall, 'solargraph/source/chain/q_call'
@@ -32,7 +40,7 @@ module Solargraph
32
40
  @@inference_invalidation_key = nil
33
41
  @@inference_cache = {}
34
42
 
35
- UNDEFINED_CALL = Chain::Call.new('<undefined>')
43
+ UNDEFINED_CALL = Chain::Call.new('<undefined>', nil)
36
44
  UNDEFINED_CONSTANT = Chain::Constant.new('<undefined>')
37
45
 
38
46
  # @return [::Array<Source::Chain::Link>]
@@ -40,6 +48,11 @@ module Solargraph
40
48
 
41
49
  attr_reader :node
42
50
 
51
+ # @sg-ignore Fix "Not enough arguments to Module#protected"
52
+ protected def equality_fields
53
+ [links, node]
54
+ end
55
+
43
56
  # @param node [Parser::AST::Node, nil]
44
57
  # @param links [::Array<Chain::Link>]
45
58
  # @param splat [Boolean]
@@ -61,54 +74,97 @@ module Solargraph
61
74
  @base ||= Chain.new(links[0..-2])
62
75
  end
63
76
 
77
+ # Determine potential Pins returned by this chain of words
78
+ #
64
79
  # @param api_map [ApiMap]
65
- # @param name_pin [Pin::Base]
66
- # @param locals [::Enumerable<Pin::LocalVariable>]
67
80
  #
68
- # @return [::Array<Pin::Base>]
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.
69
106
  def define api_map, name_pin, locals
70
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 '
71
115
  working_pin = name_pin
72
116
  links[0..-2].each do |link|
73
117
  pins = link.resolve(api_map, working_pin, locals)
74
- type = infer_first_defined(pins, working_pin, api_map, locals)
75
- return [] if type.undefined?
76
- working_pin = Pin::ProxyType.anonymous(type)
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}" }
77
130
  end
78
- links.last.last_context = name_pin
131
+ links.last.last_context = working_pin
79
132
  links.last.resolve(api_map, working_pin, locals)
80
133
  end
81
134
 
82
135
  # @param api_map [ApiMap]
83
- # @param name_pin [Pin::Base]
84
- # @param locals [::Enumerable<Pin::LocalVariable>]
136
+ # @param name_pin [Pin::Base] The pin for the closure in which this code runs
137
+ # @param locals [::Array<Pin::LocalVariable>]
85
138
  # @return [ComplexType]
86
139
  # @sg-ignore
87
140
  def infer api_map, name_pin, locals
88
- out = nil
89
- cached = @@inference_cache[[node, node.location, links.map(&:word), name_pin&.return_type, locals]] unless node.nil?
90
- return cached if cached && @@inference_invalidation_key == api_map.hash
91
- out = infer_uncached api_map, name_pin, locals
92
- if @@inference_invalidation_key != api_map.hash
93
- @@inference_cache = {}
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
94
146
  @@inference_invalidation_key = api_map.hash
147
+ @@inference_cache = {}
95
148
  end
96
- @@inference_cache[[node, node.location, links.map(&:word), name_pin&.return_type, locals]] = out unless node.nil?
97
- out
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
98
152
  end
99
153
 
100
154
  # @param api_map [ApiMap]
101
155
  # @param name_pin [Pin::Base]
102
- # @param locals [::Enumerable<Pin::LocalVariable>]
156
+ # @param locals [::Array<Pin::LocalVariable>]
103
157
  # @return [ComplexType]
104
158
  def infer_uncached api_map, name_pin, locals
105
- from_here = base.infer(api_map, name_pin, locals) unless links.length == 1
106
- if from_here
107
- name_pin = name_pin.proxy(from_here)
108
- end
109
159
  pins = define(api_map, name_pin, locals)
110
- type = infer_first_defined(pins, links.last.last_context, api_map, locals)
111
- maybe_nil(type)
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
112
168
  end
113
169
 
114
170
  # @return [Boolean]
@@ -137,6 +193,19 @@ module Solargraph
137
193
  links.any?(&:nullable?)
138
194
  end
139
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
+
140
209
  private
141
210
 
142
211
  # @param pins [::Array<Pin::Base>]
@@ -144,16 +213,18 @@ module Solargraph
144
213
  # @param api_map [ApiMap]
145
214
  # @param locals [::Enumerable<Pin::LocalVariable>]
146
215
  # @return [ComplexType]
147
- def infer_first_defined pins, context, api_map, locals
148
- possibles = []
216
+ def infer_from_definitions pins, context, api_map, locals
217
+ # @type [::Array<ComplexType>]
218
+ types = []
219
+ unresolved_pins = []
149
220
  # @todo this param tag shouldn't be needed to probe the type
150
221
  # @todo ...but given it is needed, typecheck should complain that it is needed
151
222
  # @param pin [Pin::Base]
152
223
  pins.each do |pin|
153
224
  # Avoid infinite recursion
154
- next if @@inference_stack.include?(pin.identity)
225
+ next if @@inference_stack.include?(pin)
155
226
 
156
- @@inference_stack.push pin.identity
227
+ @@inference_stack.push pin
157
228
  type = pin.typify(api_map)
158
229
  @@inference_stack.pop
159
230
  if type.defined?
@@ -161,45 +232,51 @@ module Solargraph
161
232
  # @todo even at strong, no typechecking complaint
162
233
  # happens when a [Pin::Base,nil] is passed into a method
163
234
  # that accepts only [Pin::Namespace] as an argument
164
- type = type.resolve_generics(pin.closure, context.return_type)
165
- end
166
- if type.defined?
167
- possibles.push type
168
- break if pin.is_a?(Pin::Method)
235
+ type = type.resolve_generics(pin.closure, context.binder)
169
236
  end
237
+ types << type
238
+ else
239
+ unresolved_pins << pin
170
240
  end
171
241
  end
172
- if possibles.empty?
173
- # Limit method inference recursion
174
- return ComplexType::UNDEFINED if @@inference_depth >= 10 && pins.first.is_a?(Pin::Method)
175
-
176
- @@inference_depth += 1
177
- # @param pin [Pin::Base]
178
- pins.each do |pin|
179
- # Avoid infinite recursion
180
- next if @@inference_stack.include?(pin.identity)
181
-
182
- @@inference_stack.push pin.identity
183
- type = pin.probe(api_map)
184
- @@inference_stack.pop
185
- if type.defined?
186
- possibles.push type
187
- break if pin.is_a?(Pin::Method)
188
- 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
189
254
  end
190
- @@inference_depth -= 1
255
+
256
+ @@inference_stack.push(pin.identity)
257
+ type = pin.probe(api_map)
258
+ @@inference_stack.pop
259
+ types.push type if type
191
260
  end
192
- return ComplexType::UNDEFINED if possibles.empty?
261
+ @@inference_depth -= 1
193
262
 
194
- type = if possibles.length > 1
195
- sorted = possibles.map { |t| t.rooted? ? "::#{t}" : t.to_s }.sort { |a, _| a == 'nil' ? 1 : 0 }
196
- ComplexType.parse(*sorted)
197
- else
198
- ComplexType.parse(possibles.map(&:to_s).join(', '))
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
199
277
  end
200
- return type if context.nil? || context.return_type.undefined?
201
278
 
202
- type.self_to(context.return_type.tag)
279
+ type.self_to_type(context.return_type)
203
280
  end
204
281
 
205
282
  # @param type [ComplexType]
@@ -207,7 +284,7 @@ module Solargraph
207
284
  def maybe_nil type
208
285
  return type if type.undefined? || type.void? || type.nullable?
209
286
  return type unless nullable?
210
- ComplexType.try_parse("#{type}, nil")
287
+ ComplexType.new(type.items + [ComplexType::NIL])
211
288
  end
212
289
  end
213
290
  end
@@ -28,7 +28,7 @@ module Solargraph
28
28
  # syntax errors will be repaired.
29
29
  # @return [String] The updated text.
30
30
  def write text, nullable = false
31
- if nullable and !range.nil? and new_text.match(/[\.\[\{\(@\$:]$/)
31
+ if nullable and !range.nil? and new_text.match(/[.\[{(@$:]$/)
32
32
  [':', '@'].each do |dupable|
33
33
  next unless new_text == dupable
34
34
  offset = Position.to_offset(text, range.start)
@@ -59,7 +59,7 @@ module Solargraph
59
59
  else
60
60
  result = commit text, fixed
61
61
  off = Position.to_offset(text, range.start)
62
- match = result[0, off].match(/[\.:]+\z/)
62
+ match = result[0, off].match(/[.:]+\z/)
63
63
  if match
64
64
  result = result[0, off].sub(/#{match[0]}\z/, ' ' * match[0].length) + result[off..-1]
65
65
  end
@@ -2,8 +2,8 @@
2
2
 
3
3
  module Solargraph
4
4
  class Source
5
- # Information about a position in a source, including the word located
6
- # there.
5
+ # Information about a single Position in a Source, including the
6
+ # word located there.
7
7
  #
8
8
  class Cursor
9
9
  # @return [Position]
@@ -124,7 +124,7 @@ module Solargraph
124
124
  def node_position
125
125
  @node_position ||= begin
126
126
  if start_of_word.empty?
127
- match = source.code[0, offset].match(/[\s]*(\.|:+)[\s]*$/)
127
+ match = source.code[0, offset].match(/\s*(\.|:+)\s*$/)
128
128
  if match
129
129
  Position.from_offset(source.code, offset - match[0].length)
130
130
  else
@@ -159,7 +159,7 @@ module Solargraph
159
159
  #
160
160
  # @return [Regexp]
161
161
  def end_word_pattern
162
- /^([a-z0-9_]|[^\u0000-\u007F])*[\?\!]?/i
162
+ /^([a-z0-9_]|[^\u0000-\u007F])*[?!]?/i
163
163
  end
164
164
  end
165
165
  end
@@ -32,8 +32,8 @@ module Solargraph
32
32
  # @return [Source::Chain]
33
33
  def chain
34
34
  # Special handling for files that end with an integer and a period
35
- return Chain.new([Chain::Literal.new('Integer'), Chain::UNDEFINED_CALL]) if phrase =~ /^[0-9]+\.$/
36
- return Chain.new([Chain::Literal.new('Symbol')]) if phrase.start_with?(':') && !phrase.start_with?('::')
35
+ return Chain.new([Chain::Literal.new('Integer', Integer(phrase[0..-2])), Chain::UNDEFINED_CALL]) if phrase =~ /^[0-9]+\.$/
36
+ return Chain.new([Chain::Literal.new('Symbol', phrase[1..].to_sym)]) if phrase.start_with?(':') && !phrase.start_with?('::')
37
37
  return SourceChainer.chain(source, Position.new(position.line, position.character + 1)) if end_of_phrase.strip == '::' && source.code[Position.to_offset(source.code, position)].to_s.match?(/[a-z]/i)
38
38
  begin
39
39
  return Chain.new([]) if phrase.end_with?('..')
@@ -97,7 +97,7 @@ module Solargraph
97
97
  # @return [String]
98
98
  def end_of_phrase
99
99
  @end_of_phrase ||= begin
100
- match = phrase.match(/[\s]*(\.{1}|::)[\s]*$/)
100
+ match = phrase.match(/\s*(\.{1}|::)\s*$/)
101
101
  if match
102
102
  match[0]
103
103
  else