solargraph 0.54.0 → 0.55.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 (105) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +58 -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 +75 -122
  6. data/lib/solargraph/api_map.rb +109 -41
  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 +181 -17
  10. data/lib/solargraph/complex_type.rb +103 -24
  11. data/lib/solargraph/convention/struct_definition/struct_assignment_node.rb +51 -0
  12. data/lib/solargraph/convention/struct_definition/struct_definition_node.rb +100 -0
  13. data/lib/solargraph/convention/struct_definition.rb +101 -0
  14. data/lib/solargraph/convention.rb +2 -0
  15. data/lib/solargraph/doc_map.rb +43 -18
  16. data/lib/solargraph/equality.rb +33 -0
  17. data/lib/solargraph/language_server/host/message_worker.rb +51 -5
  18. data/lib/solargraph/language_server/host.rb +13 -11
  19. data/lib/solargraph/language_server/message/base.rb +19 -12
  20. data/lib/solargraph/language_server/message/initialize.rb +3 -1
  21. data/lib/solargraph/language_server/message/text_document/completion.rb +0 -3
  22. data/lib/solargraph/language_server/message/text_document/definition.rb +3 -3
  23. data/lib/solargraph/language_server/message/text_document/document_symbol.rb +3 -3
  24. data/lib/solargraph/language_server/message/text_document/formatting.rb +4 -0
  25. data/lib/solargraph/language_server/message/text_document/hover.rb +1 -1
  26. data/lib/solargraph/language_server/message/text_document/type_definition.rb +3 -3
  27. data/lib/solargraph/language_server/message/workspace/workspace_symbol.rb +2 -2
  28. data/lib/solargraph/language_server/progress.rb +19 -2
  29. data/lib/solargraph/library.rb +31 -41
  30. data/lib/solargraph/location.rb +29 -1
  31. data/lib/solargraph/parser/comment_ripper.rb +11 -6
  32. data/lib/solargraph/parser/flow_sensitive_typing.rb +226 -0
  33. data/lib/solargraph/parser/node_methods.rb +15 -1
  34. data/lib/solargraph/parser/parser_gem/class_methods.rb +11 -6
  35. data/lib/solargraph/parser/parser_gem/node_chainer.rb +10 -10
  36. data/lib/solargraph/parser/parser_gem/node_methods.rb +6 -4
  37. data/lib/solargraph/parser/parser_gem/node_processors/and_node.rb +21 -0
  38. data/lib/solargraph/parser/parser_gem/node_processors/args_node.rb +23 -19
  39. data/lib/solargraph/parser/parser_gem/node_processors/casgn_node.rb +21 -1
  40. data/lib/solargraph/parser/parser_gem/node_processors/if_node.rb +21 -0
  41. data/lib/solargraph/parser/parser_gem/node_processors/masgn_node.rb +8 -2
  42. data/lib/solargraph/parser/parser_gem/node_processors/namespace_node.rb +26 -5
  43. data/lib/solargraph/parser/parser_gem/node_processors/opasgn_node.rb +41 -0
  44. data/lib/solargraph/parser/parser_gem/node_processors/send_node.rb +1 -1
  45. data/lib/solargraph/parser/parser_gem/node_processors/until_node.rb +28 -0
  46. data/lib/solargraph/parser/parser_gem/node_processors/while_node.rb +28 -0
  47. data/lib/solargraph/parser/parser_gem/node_processors.rb +10 -0
  48. data/lib/solargraph/parser.rb +3 -5
  49. data/lib/solargraph/pin/base.rb +47 -17
  50. data/lib/solargraph/pin/base_variable.rb +11 -4
  51. data/lib/solargraph/pin/block.rb +8 -26
  52. data/lib/solargraph/pin/breakable.rb +9 -0
  53. data/lib/solargraph/pin/callable.rb +147 -0
  54. data/lib/solargraph/pin/closure.rb +8 -3
  55. data/lib/solargraph/pin/common.rb +2 -6
  56. data/lib/solargraph/pin/conversions.rb +3 -2
  57. data/lib/solargraph/pin/instance_variable.rb +2 -2
  58. data/lib/solargraph/pin/local_variable.rb +7 -1
  59. data/lib/solargraph/pin/method.rb +76 -48
  60. data/lib/solargraph/pin/namespace.rb +14 -11
  61. data/lib/solargraph/pin/parameter.rb +24 -17
  62. data/lib/solargraph/pin/proxy_type.rb +13 -7
  63. data/lib/solargraph/pin/signature.rb +3 -129
  64. data/lib/solargraph/pin/until.rb +18 -0
  65. data/lib/solargraph/pin/while.rb +18 -0
  66. data/lib/solargraph/pin.rb +7 -1
  67. data/lib/solargraph/position.rb +7 -0
  68. data/lib/solargraph/range.rb +9 -4
  69. data/lib/solargraph/rbs_map/conversions.rb +84 -45
  70. data/lib/solargraph/rbs_map/core_fills.rb +16 -9
  71. data/lib/solargraph/rbs_map.rb +1 -0
  72. data/lib/solargraph/shell.rb +19 -2
  73. data/lib/solargraph/source/chain/array.rb +10 -8
  74. data/lib/solargraph/source/chain/block_symbol.rb +1 -1
  75. data/lib/solargraph/source/chain/block_variable.rb +1 -1
  76. data/lib/solargraph/source/chain/call.rb +125 -61
  77. data/lib/solargraph/source/chain/constant.rb +1 -1
  78. data/lib/solargraph/source/chain/hash.rb +8 -2
  79. data/lib/solargraph/source/chain/if.rb +5 -0
  80. data/lib/solargraph/source/chain/link.rb +28 -5
  81. data/lib/solargraph/source/chain/literal.rb +27 -2
  82. data/lib/solargraph/source/chain/or.rb +1 -1
  83. data/lib/solargraph/source/chain/z_super.rb +1 -1
  84. data/lib/solargraph/source/chain.rb +131 -63
  85. data/lib/solargraph/source/cursor.rb +3 -2
  86. data/lib/solargraph/source/source_chainer.rb +2 -2
  87. data/lib/solargraph/source.rb +104 -86
  88. data/lib/solargraph/source_map/clip.rb +8 -6
  89. data/lib/solargraph/source_map/data.rb +30 -0
  90. data/lib/solargraph/source_map.rb +28 -16
  91. data/lib/solargraph/type_checker/checks.rb +4 -0
  92. data/lib/solargraph/type_checker/rules.rb +6 -1
  93. data/lib/solargraph/type_checker.rb +48 -21
  94. data/lib/solargraph/version.rb +1 -1
  95. data/lib/solargraph/views/environment.erb +3 -5
  96. data/lib/solargraph/workspace/config.rb +7 -3
  97. data/lib/solargraph/workspace.rb +1 -1
  98. data/lib/solargraph/yard_map/mapper/to_constant.rb +1 -0
  99. data/lib/solargraph/yard_map/mapper/to_method.rb +42 -15
  100. data/lib/solargraph/yard_map/mapper/to_namespace.rb +1 -0
  101. data/lib/solargraph/yard_map/mapper.rb +1 -0
  102. data/lib/solargraph/yardoc.rb +1 -1
  103. data/lib/solargraph.rb +1 -0
  104. data/solargraph.gemspec +5 -5
  105. metadata +41 -25
@@ -3,10 +3,20 @@
3
3
  module Solargraph
4
4
  class Source
5
5
  class Chain
6
- class Call < Link
6
+ #
7
+ # Handles both method calls and local variable references by
8
+ # first looking for a variable with the name 'word', then
9
+ # proceeding to method signature resolution if not found.
10
+ #
11
+ class Call < Chain::Link
12
+ include Solargraph::Parser::NodeMethods
13
+
7
14
  # @return [String]
8
15
  attr_reader :word
9
16
 
17
+ # @return [Location]
18
+ attr_reader :location
19
+
10
20
  # @return [::Array<Chain>]
11
21
  attr_reader :arguments
12
22
 
@@ -14,47 +24,55 @@ module Solargraph
14
24
  attr_reader :block
15
25
 
16
26
  # @param word [String]
27
+ # @param location [Location, nil]
17
28
  # @param arguments [::Array<Chain>]
18
29
  # @param block [Chain, nil]
19
- def initialize word, arguments = [], block = nil
30
+ def initialize word, location = nil, arguments = [], block = nil
20
31
  @word = word
32
+ @location = location
21
33
  @arguments = arguments
22
34
  @block = block
23
35
  fix_block_pass
24
36
  end
25
37
 
38
+ # @sg-ignore Fix "Not enough arguments to Module#protected"
39
+ protected def equality_fields
40
+ super + [arguments, block]
41
+ end
42
+
26
43
  def with_block?
27
44
  !!@block
28
45
  end
29
46
 
30
47
  # @param api_map [ApiMap]
31
- # @param name_pin [Pin::Base]
48
+ # @param name_pin [Pin::Closure] name_pin.binder should give us the type of the object on which 'word' will be invoked
32
49
  # @param locals [::Array<Pin::LocalVariable>]
33
50
  def resolve api_map, name_pin, locals
34
51
  return super_pins(api_map, name_pin) if word == 'super'
35
52
  return yield_pins(api_map, name_pin) if word == 'yield'
36
53
  found = if head?
37
- locals.select { |p| p.name == word }
54
+ api_map.visible_pins(locals, word, name_pin, location)
38
55
  else
39
56
  []
40
57
  end
41
- return inferred_pins(found, api_map, name_pin.context, locals) unless found.empty?
42
- # @param [ComplexType::UniqueType]
58
+ return inferred_pins(found, api_map, name_pin, locals) unless found.empty?
43
59
  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)
60
+ ns_tag = context.namespace == '' ? '' : context.namespace_type.tag
61
+ stack = api_map.get_method_stack(ns_tag, word, scope: context.scope)
62
+ [stack.first].compact
45
63
  end
46
64
  return [] if pins.empty?
47
- inferred_pins(pins, api_map, name_pin.context, locals)
65
+ inferred_pins(pins, api_map, name_pin, locals)
48
66
  end
49
67
 
50
68
  private
51
69
 
52
70
  # @param pins [::Enumerable<Pin::Method>]
53
71
  # @param api_map [ApiMap]
54
- # @param context [ComplexType]
55
- # @param locals [::Array<Pin::LocalVariable>]
72
+ # @param name_pin [Pin::Base]
73
+ # @param locals [::Array<Solargraph::Pin::LocalVariable, Solargraph::Pin::Parameter>]
56
74
  # @return [::Array<Pin::Base>]
57
- def inferred_pins pins, api_map, context, locals
75
+ def inferred_pins pins, api_map, name_pin, locals
58
76
  result = pins.map do |p|
59
77
  next p unless p.is_a?(Pin::Method)
60
78
  overloads = p.signatures
@@ -65,10 +83,11 @@ module Solargraph
65
83
  # use it. If we didn't pass a block, the logic below will
66
84
  # reject it regardless
67
85
 
68
- sorted_overloads = overloads.sort { |ol| ol.block? ? -1 : 1 }
86
+ with_block, without_block = overloads.partition(&:block?)
87
+ sorted_overloads = with_block + without_block
69
88
  new_signature_pin = nil
70
89
  sorted_overloads.each do |ol|
71
- next unless arity_matches?(arguments, ol)
90
+ next unless ol.arity_matches?(arguments, with_block?)
72
91
  match = true
73
92
 
74
93
  atypes = []
@@ -78,10 +97,9 @@ module Solargraph
78
97
  match = ol.parameters.any?(&:restarg?)
79
98
  break
80
99
  end
81
- atype = atypes[idx] ||= arg.infer(api_map, Pin::ProxyType.anonymous(context), locals)
82
- # @todo Weak type comparison
83
- # 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?
100
+
101
+ atype = atypes[idx] ||= arg.infer(api_map, Pin::ProxyType.anonymous(name_pin.context), locals)
102
+ unless param.compatible_arg?(atype, api_map) || param.restarg?
85
103
  match = false
86
104
  break
87
105
  end
@@ -89,11 +107,36 @@ module Solargraph
89
107
  if match
90
108
  if ol.block && with_block?
91
109
  block_atypes = ol.block.parameters.map(&:return_type)
92
- blocktype = block_call_type(api_map, context, block_atypes, locals)
110
+ if block.links.map(&:class) == [BlockSymbol]
111
+ # like the bar in foo(&:bar)
112
+ blocktype = block_symbol_call_type(api_map, name_pin.context, block_atypes, locals)
113
+ else
114
+ blocktype = block_call_type(api_map, name_pin, locals)
115
+ end
93
116
  end
94
117
  new_signature_pin = ol.resolve_generics_from_context_until_complete(ol.generics, atypes, nil, nil, blocktype)
95
118
  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?
119
+ if head?
120
+ # If we're at the head of the chain, we called a
121
+ # method somewhere that marked itself as returning
122
+ # self. Given we didn't invoke this on an object,
123
+ # this must be a method in this same class - so we
124
+ # use our own self type
125
+ self_type = name_pin.context
126
+ else
127
+ # if we're past the head in the chain, whatever the
128
+ # type of the lhs side is what 'self' will be in its
129
+ # declaration - we can't just use the type of the
130
+ # method pin, as this might be a subclass of the
131
+ # place where the method is defined
132
+ self_type = name_pin.binder
133
+ end
134
+ # This same logic applies to the YARD work done by
135
+ # 'with_params()'.
136
+ #
137
+ # qualify(), however, happens in the namespace where
138
+ # the docs were written - from the method pin.
139
+ type = with_params(new_return_type.self_to_type(self_type), self_type).qualify(api_map, p.namespace) if new_return_type.defined?
97
140
  type ||= ComplexType::UNDEFINED
98
141
  end
99
142
  break if type.defined?
@@ -101,20 +144,22 @@ module Solargraph
101
144
  p = p.with_single_signature(new_signature_pin) unless new_signature_pin.nil?
102
145
  next p.proxy(type) if type.defined?
103
146
  if !p.macros.empty?
104
- result = process_macro(p, api_map, context, locals)
147
+ result = process_macro(p, api_map, name_pin.context, locals)
105
148
  next result unless result.return_type.undefined?
106
149
  elsif !p.directives.empty?
107
- result = process_directive(p, api_map, context, locals)
150
+ result = process_directive(p, api_map, name_pin.context, locals)
108
151
  next result unless result.return_type.undefined?
109
152
  end
110
153
  p
111
154
  end
112
- result.map do |pin|
113
- if pin.path == 'Class#new' && context.tag != 'Class'
114
- pin.proxy(ComplexType.try_parse(context.namespace))
155
+ logger.debug { "Call#inferred_pins(name_pin.binder=#{name_pin.binder}, word=#{word}, pins=#{pins.map(&:desc)}, name_pin=#{name_pin}) - result=#{result}" }
156
+ out = result.map do |pin|
157
+ if pin.path == 'Class#new' && name_pin.binder.tag != 'Class'
158
+ reduced_context = name_pin.binder.reduce_class_type
159
+ pin.proxy(reduced_context)
115
160
  else
116
161
  next pin if pin.return_type.undefined?
117
- selfy = pin.return_type.self_to(context.tag)
162
+ selfy = pin.return_type.self_to_type(name_pin.binder)
118
163
  selfy == pin.return_type ? pin : pin.proxy(selfy)
119
164
  end
120
165
  end
@@ -123,7 +168,7 @@ module Solargraph
123
168
  # @param pin [Pin::Base]
124
169
  # @param api_map [ApiMap]
125
170
  # @param context [ComplexType]
126
- # @param locals [Enumerable<Pin::Base>]
171
+ # @param locals [::Array<Solargraph::Pin::LocalVariable, Solargraph::Pin::Parameter>]
127
172
  # @return [Pin::Base]
128
173
  def process_macro pin, api_map, context, locals
129
174
  pin.macros.each do |macro|
@@ -142,7 +187,7 @@ module Solargraph
142
187
  # @param pin [Pin::Method]
143
188
  # @param api_map [ApiMap]
144
189
  # @param context [ComplexType]
145
- # @param locals [Enumerable<Pin::Base>]
190
+ # @param locals [::Array<Solargraph::Pin::LocalVariable, Solargraph::Pin::Parameter>]
146
191
  # @return [Pin::ProxyType]
147
192
  def process_directive pin, api_map, context, locals
148
193
  pin.directives.each do |dir|
@@ -158,7 +203,7 @@ module Solargraph
158
203
  # @param macro [YARD::Tags::MacroDirective]
159
204
  # @param api_map [ApiMap]
160
205
  # @param context [ComplexType]
161
- # @param locals [Enumerable<Pin::Base>]
206
+ # @param locals [::Array<Pin::LocalVariable, Pin::Parameter>]
162
207
  # @return [Pin::ProxyType]
163
208
  def inner_process_macro pin, macro, api_map, context, locals
164
209
  vals = arguments.map{ |c| Pin::ProxyType.anonymous(c.infer(api_map, pin, locals)) }
@@ -192,24 +237,24 @@ module Solargraph
192
237
  nil
193
238
  end
194
239
 
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
240
+ # @param name_pin [Pin::Base]
241
+ # @return [Pin::Method, nil]
242
+ def find_method_pin(name_pin)
243
+ method_pin = name_pin
244
+ until method_pin.is_a?(Pin::Method)
245
+ method_pin = method_pin.closure
246
+ return if method_pin.nil?
247
+ end
248
+ method_pin
206
249
  end
207
250
 
208
251
  # @param api_map [ApiMap]
209
252
  # @param name_pin [Pin::Base]
210
253
  # @return [::Array<Pin::Base>]
211
254
  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)
255
+ method_pin = find_method_pin(name_pin)
256
+ return [] if method_pin.nil?
257
+ pins = api_map.get_method_stack(method_pin.namespace, method_pin.name, scope: method_pin.context.scope)
213
258
  pins.reject{|p| p.path == name_pin.path}
214
259
  end
215
260
 
@@ -217,10 +262,13 @@ module Solargraph
217
262
  # @param name_pin [Pin::Base]
218
263
  # @return [::Array<Pin::Base>]
219
264
  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?
265
+ method_pin = find_method_pin(name_pin)
266
+ return [] unless method_pin
222
267
 
223
- method_pin.signatures.map(&:block).compact
268
+ method_pin.signatures.map(&:block).compact.map do |signature_pin|
269
+ return_type = signature_pin.return_type.qualify(api_map, name_pin.namespace)
270
+ signature_pin.proxy(return_type)
271
+ end
224
272
  end
225
273
 
226
274
  # @param type [ComplexType]
@@ -228,7 +276,7 @@ module Solargraph
228
276
  # @return [ComplexType]
229
277
  def with_params type, context
230
278
  return type unless type.to_s.include?('$')
231
- ComplexType.try_parse(type.to_s.gsub('$', context.value_types.map(&:tag).join(', ')).gsub('<>', ''))
279
+ ComplexType.try_parse(type.to_s.gsub('$', context.value_types.map(&:rooted_tag).join(', ')).gsub('<>', ''))
232
280
  end
233
281
 
234
282
  # @return [void]
@@ -242,25 +290,41 @@ module Solargraph
242
290
  # @param block_parameter_types [::Array<ComplexType>]
243
291
  # @param locals [::Array<Pin::LocalVariable>]
244
292
  # @return [ComplexType, nil]
245
- def block_call_type(api_map, context, block_parameter_types, locals)
293
+ def block_symbol_call_type(api_map, context, block_parameter_types, locals)
294
+ # Ruby's shorthand for sending the passed in method name
295
+ # to the first yield parameter with no arguments
296
+ block_symbol_name = block.links.first.word
297
+ block_symbol_call_path = "#{block_parameter_types.first}##{block_symbol_name}"
298
+ callee = api_map.get_path_pins(block_symbol_call_path).first
299
+ return_type = callee&.return_type
300
+ # @todo: Figure out why we get unresolved generics at
301
+ # this point and need to assume method return types
302
+ # based on the generic type
303
+ return_type ||= api_map.get_path_pins("#{context.subtypes.first}##{block.links.first.word}").first&.return_type
304
+ return_type || ComplexType::UNDEFINED
305
+ end
306
+
307
+ # @param api_map [ApiMap]
308
+ # @return [Pin::Block, nil]
309
+ def find_block_pin(api_map)
310
+ node_location = Solargraph::Location.from_node(block.node)
311
+ return if node_location.nil?
312
+ block_pins = api_map.get_block_pins
313
+ block_pins.find { |pin| pin.location.contain?(node_location) }
314
+ end
315
+
316
+ # @param api_map [ApiMap]
317
+ # @param name_pin [Pin::Base]
318
+ # @param block_parameter_types [::Array<ComplexType>]
319
+ # @param locals [::Array<Pin::LocalVariable>]
320
+ # @return [ComplexType, nil]
321
+ def block_call_type(api_map, name_pin, locals)
246
322
  return nil unless with_block?
247
323
 
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
324
+ block_context_pin = name_pin
325
+ block_pin = find_block_pin(api_map)
326
+ block_context_pin = block_pin.closure if block_pin
327
+ block.infer(api_map, block_context_pin, locals)
264
328
  end
265
329
  end
266
330
  end
@@ -41,7 +41,7 @@ module Solargraph
41
41
 
42
42
  private
43
43
 
44
- # @param pin [Pin::Base]
44
+ # @param pin [Pin::Closure]
45
45
  # @return [::Array<String>]
46
46
  def crawl_gates pin
47
47
  clos = pin
@@ -5,12 +5,18 @@ module Solargraph
5
5
  class Chain
6
6
  class Hash < Literal
7
7
  # @param type [String]
8
+ # @param node [Parser::AST::Node]
8
9
  # @param splatted [Boolean]
9
- def initialize type, splatted = false
10
- super(type)
10
+ def initialize type, node, splatted = false
11
+ super(type, node)
11
12
  @splatted = splatted
12
13
  end
13
14
 
15
+ # @sg-ignore Fix "Not enough arguments to Module#protected"
16
+ protected def equality_fields
17
+ super + [@splatted]
18
+ end
19
+
14
20
  def word
15
21
  @word ||= "<#{@type}>"
16
22
  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,17 @@ 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
+
85
+ include Logging
86
+
64
87
  protected
65
88
 
66
89
  # Mark whether this link is the head of a chain
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'parser'
4
+
3
5
  module Solargraph
4
6
  class Source
5
7
  class Chain
@@ -8,14 +10,37 @@ module Solargraph
8
10
  @word ||= "<#{@type}>"
9
11
  end
10
12
 
13
+ attr_reader :value
14
+
11
15
  # @param type [String]
12
- def initialize type
16
+ # @param node [Parser::AST::Node, Object]
17
+ def initialize type, node
18
+ if node.is_a?(::Parser::AST::Node)
19
+ if node.type == :true
20
+ @value = true
21
+ elsif node.type == :false
22
+ @value = false
23
+ elsif [:int, :sym].include?(node.type)
24
+ @value = node.children.first
25
+ end
26
+ end
13
27
  @type = type
28
+ @literal_type = ComplexType.try_parse(@value.inspect)
14
29
  @complex_type = ComplexType.try_parse(type)
15
30
  end
16
31
 
32
+ # @sg-ignore Fix "Not enough arguments to Module#protected"
33
+ protected def equality_fields
34
+ super + [@value, @type, @literal_type, @complex_type]
35
+ end
36
+
17
37
  def resolve api_map, name_pin, locals
18
- [Pin::ProxyType.anonymous(@complex_type)]
38
+ if api_map.super_and_sub?(@complex_type.name, @literal_type.name)
39
+ [Pin::ProxyType.anonymous(@literal_type)]
40
+ else
41
+ # we don't support this value as a literal type
42
+ [Pin::ProxyType.anonymous(@complex_type)]
43
+ end
19
44
  end
20
45
  end
21
46
  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
@@ -15,7 +15,7 @@ module Solargraph
15
15
  # @param with_block [Boolean] True if the chain is inside a block
16
16
  # @param head [Boolean] True if the call is the start of its chain
17
17
  def initialize word, with_block = false
18
- super(word, [], with_block)
18
+ super(word, nil, [], with_block)
19
19
  end
20
20
 
21
21
  # @param api_map [ApiMap]