solargraph 0.54.0 → 0.54.5

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 (83) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +45 -0
  3. data/lib/solargraph/api_map/cache.rb +10 -1
  4. data/lib/solargraph/api_map/index.rb +167 -0
  5. data/lib/solargraph/api_map/store.rb +72 -121
  6. data/lib/solargraph/api_map.rb +94 -36
  7. data/lib/solargraph/bench.rb +17 -1
  8. data/lib/solargraph/complex_type/type_methods.rb +17 -11
  9. data/lib/solargraph/complex_type/unique_type.rb +93 -10
  10. data/lib/solargraph/complex_type.rb +68 -18
  11. data/lib/solargraph/convention.rb +1 -0
  12. data/lib/solargraph/doc_map.rb +1 -0
  13. data/lib/solargraph/equality.rb +33 -0
  14. data/lib/solargraph/language_server/host/message_worker.rb +48 -5
  15. data/lib/solargraph/language_server/host.rb +12 -11
  16. data/lib/solargraph/language_server/message/base.rb +19 -12
  17. data/lib/solargraph/language_server/message/initialize.rb +3 -1
  18. data/lib/solargraph/language_server/message/text_document/completion.rb +0 -3
  19. data/lib/solargraph/language_server/message/text_document/definition.rb +3 -3
  20. data/lib/solargraph/language_server/message/text_document/document_symbol.rb +3 -3
  21. data/lib/solargraph/language_server/message/text_document/formatting.rb +4 -0
  22. data/lib/solargraph/language_server/message/text_document/hover.rb +1 -1
  23. data/lib/solargraph/language_server/message/text_document/type_definition.rb +3 -3
  24. data/lib/solargraph/language_server/message/workspace/workspace_symbol.rb +2 -2
  25. data/lib/solargraph/language_server/progress.rb +19 -2
  26. data/lib/solargraph/library.rb +31 -41
  27. data/lib/solargraph/location.rb +21 -1
  28. data/lib/solargraph/parser/node_methods.rb +1 -1
  29. data/lib/solargraph/parser/node_processor.rb +1 -0
  30. data/lib/solargraph/parser/parser_gem/class_methods.rb +2 -6
  31. data/lib/solargraph/parser/parser_gem/node_methods.rb +3 -3
  32. data/lib/solargraph/parser/parser_gem/node_processors/args_node.rb +23 -19
  33. data/lib/solargraph/parser/parser_gem/node_processors/masgn_node.rb +8 -2
  34. data/lib/solargraph/parser/parser_gem/node_processors/send_node.rb +1 -1
  35. data/lib/solargraph/parser.rb +2 -5
  36. data/lib/solargraph/pin/base.rb +41 -17
  37. data/lib/solargraph/pin/base_variable.rb +4 -3
  38. data/lib/solargraph/pin/block.rb +6 -26
  39. data/lib/solargraph/pin/callable.rb +147 -0
  40. data/lib/solargraph/pin/closure.rb +8 -3
  41. data/lib/solargraph/pin/common.rb +2 -6
  42. data/lib/solargraph/pin/conversions.rb +3 -2
  43. data/lib/solargraph/pin/instance_variable.rb +2 -2
  44. data/lib/solargraph/pin/method.rb +57 -31
  45. data/lib/solargraph/pin/namespace.rb +5 -5
  46. data/lib/solargraph/pin/parameter.rb +11 -12
  47. data/lib/solargraph/pin/proxy_type.rb +1 -1
  48. data/lib/solargraph/pin/signature.rb +3 -129
  49. data/lib/solargraph/pin.rb +4 -1
  50. data/lib/solargraph/position.rb +7 -0
  51. data/lib/solargraph/range.rb +9 -4
  52. data/lib/solargraph/rbs_map/conversions.rb +77 -38
  53. data/lib/solargraph/rbs_map/core_fills.rb +6 -6
  54. data/lib/solargraph/rbs_map.rb +1 -0
  55. data/lib/solargraph/shell.rb +19 -2
  56. data/lib/solargraph/source/chain/array.rb +7 -6
  57. data/lib/solargraph/source/chain/block_symbol.rb +1 -1
  58. data/lib/solargraph/source/chain/block_variable.rb +1 -1
  59. data/lib/solargraph/source/chain/call.rb +90 -55
  60. data/lib/solargraph/source/chain/hash.rb +5 -0
  61. data/lib/solargraph/source/chain/if.rb +5 -0
  62. data/lib/solargraph/source/chain/link.rb +26 -5
  63. data/lib/solargraph/source/chain/literal.rb +5 -0
  64. data/lib/solargraph/source/chain/or.rb +1 -1
  65. data/lib/solargraph/source/chain.rb +68 -30
  66. data/lib/solargraph/source/cursor.rb +3 -2
  67. data/lib/solargraph/source.rb +104 -86
  68. data/lib/solargraph/source_map/clip.rb +5 -5
  69. data/lib/solargraph/source_map/data.rb +30 -0
  70. data/lib/solargraph/source_map.rb +28 -16
  71. data/lib/solargraph/type_checker/rules.rb +6 -1
  72. data/lib/solargraph/type_checker.rb +15 -15
  73. data/lib/solargraph/version.rb +1 -1
  74. data/lib/solargraph/views/environment.erb +3 -5
  75. data/lib/solargraph/workspace/config.rb +7 -3
  76. data/lib/solargraph/workspace.rb +1 -1
  77. data/lib/solargraph/yard_map/mapper/to_constant.rb +1 -0
  78. data/lib/solargraph/yard_map/mapper/to_namespace.rb +1 -0
  79. data/lib/solargraph/yard_map/mapper.rb +1 -0
  80. data/lib/solargraph/yardoc.rb +1 -1
  81. data/lib/solargraph.rb +1 -0
  82. data/solargraph.gemspec +5 -5
  83. metadata +29 -25
@@ -89,7 +89,7 @@ module Solargraph
89
89
  )
90
90
  # @return [void]
91
91
  def clear
92
- puts "Deleting the cached documentation"
92
+ puts "Deleting all cached documentation (gems, core and stdlib)"
93
93
  Solargraph::Cache.clear
94
94
  end
95
95
  map 'clear-cache' => :clear
@@ -105,11 +105,27 @@ module Solargraph
105
105
  Cache.save('gems', "#{spec.name}-#{spec.version}.ser", pins)
106
106
  end
107
107
 
108
- desc 'uncache GEM [...GEM]', "Delete cached gem documentation"
108
+ desc 'uncache GEM [...GEM]', "Delete specific cached gem documentation"
109
+ long_desc %(
110
+ Specify one or more gem names to clear. 'core' or 'stdlib' may
111
+ also be specified to clear cached system documentation.
112
+ Documentation will be regenerated as needed.
113
+ )
114
+ # @param gems [Array<String>]
109
115
  # @return [void]
110
116
  def uncache *gems
111
117
  raise ArgumentError, 'No gems specified.' if gems.empty?
112
118
  gems.each do |gem|
119
+ if gem == 'core'
120
+ Cache.uncache("core.ser")
121
+ next
122
+ end
123
+
124
+ if gem == 'stdlib'
125
+ Cache.uncache("stdlib")
126
+ next
127
+ end
128
+
113
129
  spec = Gem::Specification.find_by_name(gem)
114
130
  Cache.uncache('gems', "#{spec.name}-#{spec.version}.ser")
115
131
  Cache.uncache('gems', "#{spec.name}-#{spec.version}.yardoc")
@@ -118,6 +134,7 @@ module Solargraph
118
134
 
119
135
  desc 'gems [GEM[=VERSION]]', 'Cache documentation for installed gems'
120
136
  option :rebuild, type: :boolean, desc: 'Rebuild existing documentation', default: false
137
+ # @param names [Array<String>]
121
138
  # @return [void]
122
139
  def gems *names
123
140
  if names.empty?
@@ -14,17 +14,18 @@ module Solargraph
14
14
 
15
15
  # @param api_map [ApiMap]
16
16
  # @param name_pin [Pin::Base]
17
- # @param locals [Enumerable<Pin::LocalVariable>]
17
+ # @param locals [::Array<Pin::Parameter, Pin::LocalVariable>]
18
18
  def resolve api_map, name_pin, locals
19
19
  child_types = @children.map do |child|
20
- child.infer(api_map, name_pin, locals).tag
20
+ child.infer(api_map, name_pin, locals)
21
21
  end
22
- type = if child_types.uniq.length == 1 && child_types.first != 'undefined'
23
- "::Array<#{child_types.first}>"
22
+
23
+ type = if child_types.uniq.length == 1 && child_types.first.defined?
24
+ ComplexType::UniqueType.new('Array', [], child_types.uniq, rooted: true, parameters_type: :list)
24
25
  else
25
- '::Array'
26
+ ComplexType::UniqueType.new('Array', rooted: true)
26
27
  end
27
- [Pin::ProxyType.anonymous(ComplexType.try_parse(type))]
28
+ [Pin::ProxyType.anonymous(type)]
28
29
  end
29
30
  end
30
31
  end
@@ -5,7 +5,7 @@ module Solargraph
5
5
  class Chain
6
6
  class BlockSymbol < Link
7
7
  def resolve api_map, name_pin, locals
8
- [Pin::ProxyType.anonymous(ComplexType.try_parse('Proc'))]
8
+ [Pin::ProxyType.anonymous(ComplexType.try_parse('::Proc'))]
9
9
  end
10
10
  end
11
11
  end
@@ -5,7 +5,7 @@ module Solargraph
5
5
  class Chain
6
6
  class BlockVariable < Link
7
7
  def resolve api_map, name_pin, locals
8
- [Pin::ProxyType.anonymous(ComplexType.try_parse('Proc'))]
8
+ [Pin::ProxyType.anonymous(ComplexType.try_parse('::Proc'))]
9
9
  end
10
10
  end
11
11
  end
@@ -3,7 +3,9 @@
3
3
  module Solargraph
4
4
  class Source
5
5
  class Chain
6
- class Call < Link
6
+ class Call < Chain::Link
7
+ include Solargraph::Parser::NodeMethods
8
+
7
9
  # @return [String]
8
10
  attr_reader :word
9
11
 
@@ -23,12 +25,17 @@ module Solargraph
23
25
  fix_block_pass
24
26
  end
25
27
 
28
+ # @sg-ignore Fix "Not enough arguments to Module#protected"
29
+ protected def equality_fields
30
+ super + [arguments, block]
31
+ end
32
+
26
33
  def with_block?
27
34
  !!@block
28
35
  end
29
36
 
30
37
  # @param api_map [ApiMap]
31
- # @param name_pin [Pin::Base]
38
+ # @param name_pin [Pin::Closure] name_pin.binder should give us the object on which 'word' will be invoked
32
39
  # @param locals [::Array<Pin::LocalVariable>]
33
40
  def resolve api_map, name_pin, locals
34
41
  return super_pins(api_map, name_pin) if word == 'super'
@@ -38,23 +45,23 @@ module Solargraph
38
45
  else
39
46
  []
40
47
  end
41
- return inferred_pins(found, api_map, name_pin.context, locals) unless found.empty?
42
- # @param [ComplexType::UniqueType]
48
+ return inferred_pins(found, api_map, name_pin, locals) unless found.empty?
43
49
  pins = name_pin.binder.each_unique_type.flat_map do |context|
44
- api_map.get_method_stack(context.namespace == '' ? '' : context.tag, word, scope: context.scope)
50
+ ns = context.namespace == '' ? '' : context.namespace_type.tag
51
+ api_map.get_method_stack(ns, word, scope: context.scope)
45
52
  end
46
53
  return [] if pins.empty?
47
- inferred_pins(pins, api_map, name_pin.context, locals)
54
+ inferred_pins(pins, api_map, name_pin, locals)
48
55
  end
49
56
 
50
57
  private
51
58
 
52
59
  # @param pins [::Enumerable<Pin::Method>]
53
60
  # @param api_map [ApiMap]
54
- # @param context [ComplexType]
55
- # @param locals [::Array<Pin::LocalVariable>]
61
+ # @param name_pin [Pin::Base]
62
+ # @param locals [::Array<Solargraph::Pin::LocalVariable, Solargraph::Pin::Parameter>]
56
63
  # @return [::Array<Pin::Base>]
57
- def inferred_pins pins, api_map, context, locals
64
+ def inferred_pins pins, api_map, name_pin, locals
58
65
  result = pins.map do |p|
59
66
  next p unless p.is_a?(Pin::Method)
60
67
  overloads = p.signatures
@@ -68,7 +75,7 @@ module Solargraph
68
75
  sorted_overloads = overloads.sort { |ol| ol.block? ? -1 : 1 }
69
76
  new_signature_pin = nil
70
77
  sorted_overloads.each do |ol|
71
- next unless arity_matches?(arguments, ol)
78
+ next unless ol.arity_matches?(arguments, with_block?)
72
79
  match = true
73
80
 
74
81
  atypes = []
@@ -78,10 +85,13 @@ module Solargraph
78
85
  match = ol.parameters.any?(&:restarg?)
79
86
  break
80
87
  end
81
- atype = atypes[idx] ||= arg.infer(api_map, Pin::ProxyType.anonymous(context), locals)
88
+ atype = atypes[idx] ||= arg.infer(api_map, Pin::ProxyType.anonymous(name_pin.context), locals)
89
+ # make sure we get types from up the method
90
+ # inheritance chain if we don't have them on this pin
91
+ ptype = param.typify api_map
82
92
  # @todo Weak type comparison
83
93
  # unless atype.tag == param.return_type.tag || api_map.super_and_sub?(param.return_type.tag, atype.tag)
84
- unless param.return_type.undefined? || atype.name == param.return_type.name || api_map.super_and_sub?(param.return_type.name, atype.name) || param.return_type.generic?
94
+ unless ptype.undefined? || atype.name == ptype.name || ptype.any? { |current_ptype| api_map.super_and_sub?(current_ptype.name, atype.name) } || ptype.generic? || param.restarg?
85
95
  match = false
86
96
  break
87
97
  end
@@ -89,11 +99,16 @@ module Solargraph
89
99
  if match
90
100
  if ol.block && with_block?
91
101
  block_atypes = ol.block.parameters.map(&:return_type)
92
- blocktype = block_call_type(api_map, context, block_atypes, locals)
102
+ if block.links.map(&:class) == [BlockSymbol]
103
+ # like the bar in foo(&:bar)
104
+ blocktype = block_symbol_call_type(api_map, name_pin.context, block_atypes, locals)
105
+ else
106
+ blocktype = block_call_type(api_map, name_pin, locals)
107
+ end
93
108
  end
94
109
  new_signature_pin = ol.resolve_generics_from_context_until_complete(ol.generics, atypes, nil, nil, blocktype)
95
110
  new_return_type = new_signature_pin.return_type
96
- type = with_params(new_return_type.self_to(context.to_s), context).qualify(api_map, context.namespace) if new_return_type.defined?
111
+ type = with_params(new_return_type.self_to_type(name_pin.context), name_pin.context).qualify(api_map, name_pin.context.namespace) if new_return_type.defined?
97
112
  type ||= ComplexType::UNDEFINED
98
113
  end
99
114
  break if type.defined?
@@ -101,20 +116,21 @@ module Solargraph
101
116
  p = p.with_single_signature(new_signature_pin) unless new_signature_pin.nil?
102
117
  next p.proxy(type) if type.defined?
103
118
  if !p.macros.empty?
104
- result = process_macro(p, api_map, context, locals)
119
+ result = process_macro(p, api_map, name_pin.context, locals)
105
120
  next result unless result.return_type.undefined?
106
121
  elsif !p.directives.empty?
107
- result = process_directive(p, api_map, context, locals)
122
+ result = process_directive(p, api_map, name_pin.context, locals)
108
123
  next result unless result.return_type.undefined?
109
124
  end
110
125
  p
111
126
  end
112
127
  result.map do |pin|
113
- if pin.path == 'Class#new' && context.tag != 'Class'
114
- pin.proxy(ComplexType.try_parse(context.namespace))
128
+ if pin.path == 'Class#new' && name_pin.context.tag != 'Class'
129
+ reduced_context = name_pin.context.reduce_class_type
130
+ pin.proxy(reduced_context)
115
131
  else
116
132
  next pin if pin.return_type.undefined?
117
- selfy = pin.return_type.self_to(context.tag)
133
+ selfy = pin.return_type.self_to_type(name_pin.context)
118
134
  selfy == pin.return_type ? pin : pin.proxy(selfy)
119
135
  end
120
136
  end
@@ -123,7 +139,7 @@ module Solargraph
123
139
  # @param pin [Pin::Base]
124
140
  # @param api_map [ApiMap]
125
141
  # @param context [ComplexType]
126
- # @param locals [Enumerable<Pin::Base>]
142
+ # @param locals [::Array<Solargraph::Pin::LocalVariable, Solargraph::Pin::Parameter>]
127
143
  # @return [Pin::Base]
128
144
  def process_macro pin, api_map, context, locals
129
145
  pin.macros.each do |macro|
@@ -142,7 +158,7 @@ module Solargraph
142
158
  # @param pin [Pin::Method]
143
159
  # @param api_map [ApiMap]
144
160
  # @param context [ComplexType]
145
- # @param locals [Enumerable<Pin::Base>]
161
+ # @param locals [::Array<Solargraph::Pin::LocalVariable, Solargraph::Pin::Parameter>]
146
162
  # @return [Pin::ProxyType]
147
163
  def process_directive pin, api_map, context, locals
148
164
  pin.directives.each do |dir|
@@ -158,7 +174,7 @@ module Solargraph
158
174
  # @param macro [YARD::Tags::MacroDirective]
159
175
  # @param api_map [ApiMap]
160
176
  # @param context [ComplexType]
161
- # @param locals [Enumerable<Pin::Base>]
177
+ # @param locals [::Array<Pin::LocalVariable, Pin::Parameter>]
162
178
  # @return [Pin::ProxyType]
163
179
  def inner_process_macro pin, macro, api_map, context, locals
164
180
  vals = arguments.map{ |c| Pin::ProxyType.anonymous(c.infer(api_map, pin, locals)) }
@@ -192,24 +208,24 @@ module Solargraph
192
208
  nil
193
209
  end
194
210
 
195
- # @param arguments [::Array<Chain>]
196
- # @param signature [Pin::Signature]
197
- # @return [Boolean]
198
- def arity_matches? arguments, signature
199
- parameters = signature.parameters
200
- argcount = arguments.length
201
- parcount = parameters.length
202
- parcount -= 1 if !parameters.empty? && parameters.last.block?
203
- return false if signature.block? && !with_block?
204
- return false if argcount < parcount && !(argcount == parcount - 1 && parameters.last.restarg?)
205
- true
211
+ # @param name_pin [Pin::Base]
212
+ # @return [Pin::Method, nil]
213
+ def find_method_pin(name_pin)
214
+ method_pin = name_pin
215
+ until method_pin.is_a?(Pin::Method)
216
+ method_pin = method_pin.closure
217
+ return if method_pin.nil?
218
+ end
219
+ method_pin
206
220
  end
207
221
 
208
222
  # @param api_map [ApiMap]
209
223
  # @param name_pin [Pin::Base]
210
224
  # @return [::Array<Pin::Base>]
211
225
  def super_pins api_map, name_pin
212
- pins = api_map.get_method_stack(name_pin.namespace, name_pin.name, scope: name_pin.context.scope)
226
+ method_pin = find_method_pin(name_pin)
227
+ return [] if method_pin.nil?
228
+ pins = api_map.get_method_stack(method_pin.namespace, method_pin.name, scope: method_pin.context.scope)
213
229
  pins.reject{|p| p.path == name_pin.path}
214
230
  end
215
231
 
@@ -217,10 +233,13 @@ module Solargraph
217
233
  # @param name_pin [Pin::Base]
218
234
  # @return [::Array<Pin::Base>]
219
235
  def yield_pins api_map, name_pin
220
- method_pin = api_map.get_method_stack(name_pin.namespace, name_pin.name, scope: name_pin.context.scope).first
221
- return [] if method_pin.nil?
236
+ method_pin = find_method_pin(name_pin)
237
+ return [] unless method_pin
222
238
 
223
- method_pin.signatures.map(&:block).compact
239
+ method_pin.signatures.map(&:block).compact.map do |signature_pin|
240
+ return_type = signature_pin.return_type.qualify(api_map, name_pin.namespace)
241
+ signature_pin.proxy(return_type)
242
+ end
224
243
  end
225
244
 
226
245
  # @param type [ComplexType]
@@ -228,7 +247,7 @@ module Solargraph
228
247
  # @return [ComplexType]
229
248
  def with_params type, context
230
249
  return type unless type.to_s.include?('$')
231
- ComplexType.try_parse(type.to_s.gsub('$', context.value_types.map(&:tag).join(', ')).gsub('<>', ''))
250
+ ComplexType.try_parse(type.to_s.gsub('$', context.value_types.map(&:rooted_tag).join(', ')).gsub('<>', ''))
232
251
  end
233
252
 
234
253
  # @return [void]
@@ -242,25 +261,41 @@ module Solargraph
242
261
  # @param block_parameter_types [::Array<ComplexType>]
243
262
  # @param locals [::Array<Pin::LocalVariable>]
244
263
  # @return [ComplexType, nil]
245
- def block_call_type(api_map, context, block_parameter_types, locals)
264
+ def block_symbol_call_type(api_map, context, block_parameter_types, locals)
265
+ # Ruby's shorthand for sending the passed in method name
266
+ # to the first yield parameter with no arguments
267
+ block_symbol_name = block.links.first.word
268
+ block_symbol_call_path = "#{block_parameter_types.first}##{block_symbol_name}"
269
+ callee = api_map.get_path_pins(block_symbol_call_path).first
270
+ return_type = callee&.return_type
271
+ # @todo: Figure out why we get unresolved generics at
272
+ # this point and need to assume method return types
273
+ # based on the generic type
274
+ return_type ||= api_map.get_path_pins("#{context.subtypes.first}##{block.links.first.word}").first&.return_type
275
+ return_type || ComplexType::UNDEFINED
276
+ end
277
+
278
+ # @param api_map [ApiMap]
279
+ # @return [Pin::Block, nil]
280
+ def find_block_pin(api_map)
281
+ node_location = Solargraph::Location.from_node(block.node)
282
+ return if node_location.nil?
283
+ block_pins = api_map.get_block_pins
284
+ block_pins.find { |pin| pin.location.contain?(node_location) }
285
+ end
286
+
287
+ # @param api_map [ApiMap]
288
+ # @param name_pin [Pin::Base]
289
+ # @param block_parameter_types [::Array<ComplexType>]
290
+ # @param locals [::Array<Pin::LocalVariable>]
291
+ # @return [ComplexType, nil]
292
+ def block_call_type(api_map, name_pin, locals)
246
293
  return nil unless with_block?
247
294
 
248
- # @todo Handle BlockVariable
249
- if block.links.map(&:class) == [BlockSymbol]
250
- # Ruby's shorthand for sending the passed in method name
251
- # to the first yield parameter with no arguments
252
- block_symbol_name = block.links.first.word
253
- block_symbol_call_path = "#{block_parameter_types.first}##{block_symbol_name}"
254
- callee = api_map.get_path_pins(block_symbol_call_path).first
255
- return_type = callee&.return_type
256
- # @todo: Figure out why we get unresolved generics at
257
- # this point and need to assume method return types
258
- # based on the generic type
259
- return_type ||= api_map.get_path_pins("#{context.subtypes.first}##{block.links.first.word}").first&.return_type
260
- return_type || ComplexType::UNDEFINED
261
- else
262
- block.infer(api_map, Pin::ProxyType.anonymous(context), locals)
263
- end
295
+ block_context_pin = name_pin
296
+ block_pin = find_block_pin(api_map)
297
+ block_context_pin = block_pin.closure if block_pin
298
+ block.infer(api_map, block_context_pin, locals)
264
299
  end
265
300
  end
266
301
  end
@@ -11,6 +11,11 @@ module Solargraph
11
11
  @splatted = splatted
12
12
  end
13
13
 
14
+ # @sg-ignore Fix "Not enough arguments to Module#protected"
15
+ protected def equality_fields
16
+ super + [@splatted]
17
+ end
18
+
14
19
  def word
15
20
  @word ||= "<#{@type}>"
16
21
  end
@@ -13,6 +13,11 @@ module Solargraph
13
13
  @links = links
14
14
  end
15
15
 
16
+ # @sg-ignore Fix "Not enough arguments to Module#protected"
17
+ protected def equality_fields
18
+ super + [@links]
19
+ end
20
+
16
21
  def resolve api_map, name_pin, locals
17
22
  types = @links.map { |link| link.infer(api_map, name_pin, locals) }
18
23
  [Solargraph::Pin::ProxyType.anonymous(Solargraph::ComplexType.try_parse(types.map(&:tag).uniq.join(', ')))]
@@ -4,6 +4,8 @@ module Solargraph
4
4
  class Source
5
5
  class Chain
6
6
  class Link
7
+ include Equality
8
+
7
9
  # @return [String]
8
10
  attr_reader :word
9
11
 
@@ -15,6 +17,11 @@ module Solargraph
15
17
  @word = word
16
18
  end
17
19
 
20
+ # @sg-ignore Fix "Not enough arguments to Module#protected"
21
+ protected def equality_fields
22
+ [self.class, word]
23
+ end
24
+
18
25
  def undefined?
19
26
  word == '<undefined>'
20
27
  end
@@ -31,18 +38,23 @@ module Solargraph
31
38
  []
32
39
  end
33
40
 
41
+ # debugging description of contents; not for machine use
42
+ def desc
43
+ word
44
+ end
45
+
46
+ def to_s
47
+ desc
48
+ end
49
+
34
50
  def inspect
35
- "#{self.class} #{word}"
51
+ "#<#{self.class} - `#{self.desc}`>"
36
52
  end
37
53
 
38
54
  def head?
39
55
  @head ||= false
40
56
  end
41
57
 
42
- def == other
43
- self.class == other.class and word == other.word
44
- end
45
-
46
58
  # Make a copy of this link marked as the head of a chain
47
59
  #
48
60
  # @return [self]
@@ -61,6 +73,15 @@ module Solargraph
61
73
  false
62
74
  end
63
75
 
76
+ # debugging description of contents; not for machine use
77
+ def desc
78
+ word
79
+ end
80
+
81
+ def inspect
82
+ "#<#{self.class} - `#{self.desc}`>"
83
+ end
84
+
64
85
  protected
65
86
 
66
87
  # Mark whether this link is the head of a chain
@@ -14,6 +14,11 @@ module Solargraph
14
14
  @complex_type = ComplexType.try_parse(type)
15
15
  end
16
16
 
17
+ # @sg-ignore Fix "Not enough arguments to Module#protected"
18
+ protected def equality_fields
19
+ super + [@value, @type, @literal_type, @complex_type]
20
+ end
21
+
17
22
  def resolve api_map, name_pin, locals
18
23
  [Pin::ProxyType.anonymous(@complex_type)]
19
24
  end
@@ -15,7 +15,7 @@ module Solargraph
15
15
 
16
16
  def resolve api_map, name_pin, locals
17
17
  types = @links.map { |link| link.infer(api_map, name_pin, locals) }
18
- [Solargraph::Pin::ProxyType.anonymous(Solargraph::ComplexType.try_parse(types.map(&:tag).uniq.join(', ')))]
18
+ [Solargraph::Pin::ProxyType.anonymous(Solargraph::ComplexType.new(types.uniq))]
19
19
  end
20
20
  end
21
21
  end