solargraph 0.58.2 → 0.59.0.dev.1

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 (154) hide show
  1. checksums.yaml +4 -4
  2. data/.envrc +3 -0
  3. data/.github/workflows/linting.yml +4 -5
  4. data/.github/workflows/plugins.yml +40 -36
  5. data/.github/workflows/rspec.yml +45 -13
  6. data/.github/workflows/typecheck.yml +2 -2
  7. data/.gitignore +0 -1
  8. data/.rubocop_todo.yml +27 -49
  9. data/CHANGELOG.md +1 -7
  10. data/README.md +3 -3
  11. data/Rakefile +1 -0
  12. data/lib/solargraph/api_map/cache.rb +3 -3
  13. data/lib/solargraph/api_map/constants.rb +13 -3
  14. data/lib/solargraph/api_map/index.rb +22 -11
  15. data/lib/solargraph/api_map/source_to_yard.rb +13 -1
  16. data/lib/solargraph/api_map/store.rb +11 -8
  17. data/lib/solargraph/api_map.rb +105 -50
  18. data/lib/solargraph/complex_type/conformance.rb +176 -0
  19. data/lib/solargraph/complex_type/type_methods.rb +16 -2
  20. data/lib/solargraph/complex_type/unique_type.rb +170 -20
  21. data/lib/solargraph/complex_type.rb +119 -14
  22. data/lib/solargraph/convention/data_definition/data_definition_node.rb +3 -1
  23. data/lib/solargraph/convention/data_definition.rb +4 -1
  24. data/lib/solargraph/convention/struct_definition/struct_assignment_node.rb +1 -0
  25. data/lib/solargraph/convention/struct_definition/struct_definition_node.rb +1 -0
  26. data/lib/solargraph/convention/struct_definition.rb +5 -1
  27. data/lib/solargraph/diagnostics/require_not_found.rb +1 -0
  28. data/lib/solargraph/diagnostics/rubocop.rb +1 -0
  29. data/lib/solargraph/diagnostics/rubocop_helpers.rb +2 -0
  30. data/lib/solargraph/diagnostics/type_check.rb +1 -0
  31. data/lib/solargraph/doc_map.rb +134 -373
  32. data/lib/solargraph/equality.rb +1 -1
  33. data/lib/solargraph/gem_pins.rb +14 -15
  34. data/lib/solargraph/language_server/host/diagnoser.rb +89 -89
  35. data/lib/solargraph/language_server/host/dispatch.rb +1 -0
  36. data/lib/solargraph/language_server/host/message_worker.rb +2 -1
  37. data/lib/solargraph/language_server/host/sources.rb +1 -0
  38. data/lib/solargraph/language_server/host.rb +6 -1
  39. data/lib/solargraph/language_server/message/extended/check_gem_version.rb +2 -7
  40. data/lib/solargraph/language_server/message/extended/document.rb +1 -0
  41. data/lib/solargraph/language_server/message/text_document/completion.rb +2 -0
  42. data/lib/solargraph/language_server/message/text_document/definition.rb +2 -0
  43. data/lib/solargraph/language_server/message/text_document/document_symbol.rb +2 -0
  44. data/lib/solargraph/language_server/message/text_document/formatting.rb +2 -0
  45. data/lib/solargraph/language_server/message/text_document/hover.rb +2 -0
  46. data/lib/solargraph/language_server/message/text_document/signature_help.rb +1 -0
  47. data/lib/solargraph/language_server/message/text_document/type_definition.rb +2 -0
  48. data/lib/solargraph/language_server/message/workspace/workspace_symbol.rb +2 -0
  49. data/lib/solargraph/library.rb +59 -13
  50. data/lib/solargraph/location.rb +9 -4
  51. data/lib/solargraph/logging.rb +21 -1
  52. data/lib/solargraph/parser/comment_ripper.rb +7 -0
  53. data/lib/solargraph/parser/flow_sensitive_typing.rb +330 -102
  54. data/lib/solargraph/parser/node_processor/base.rb +32 -2
  55. data/lib/solargraph/parser/node_processor.rb +7 -6
  56. data/lib/solargraph/parser/parser_gem/class_methods.rb +28 -10
  57. data/lib/solargraph/parser/parser_gem/node_chainer.rb +31 -6
  58. data/lib/solargraph/parser/parser_gem/node_methods.rb +27 -7
  59. data/lib/solargraph/parser/parser_gem/node_processors/and_node.rb +4 -4
  60. data/lib/solargraph/parser/parser_gem/node_processors/args_node.rb +2 -0
  61. data/lib/solargraph/parser/parser_gem/node_processors/begin_node.rb +9 -0
  62. data/lib/solargraph/parser/parser_gem/node_processors/block_node.rb +11 -11
  63. data/lib/solargraph/parser/parser_gem/node_processors/def_node.rb +7 -0
  64. data/lib/solargraph/parser/parser_gem/node_processors/if_node.rb +36 -6
  65. data/lib/solargraph/parser/parser_gem/node_processors/ivasgn_node.rb +3 -2
  66. data/lib/solargraph/parser/parser_gem/node_processors/lvasgn_node.rb +1 -0
  67. data/lib/solargraph/parser/parser_gem/node_processors/masgn_node.rb +3 -1
  68. data/lib/solargraph/parser/parser_gem/node_processors/opasgn_node.rb +2 -2
  69. data/lib/solargraph/parser/parser_gem/node_processors/or_node.rb +22 -0
  70. data/lib/solargraph/parser/parser_gem/node_processors/orasgn_node.rb +1 -1
  71. data/lib/solargraph/parser/parser_gem/node_processors/resbody_node.rb +2 -1
  72. data/lib/solargraph/parser/parser_gem/node_processors/sclass_node.rb +1 -0
  73. data/lib/solargraph/parser/parser_gem/node_processors/send_node.rb +12 -7
  74. data/lib/solargraph/parser/parser_gem/node_processors/when_node.rb +23 -0
  75. data/lib/solargraph/parser/parser_gem/node_processors/while_node.rb +5 -1
  76. data/lib/solargraph/parser/parser_gem/node_processors.rb +4 -0
  77. data/lib/solargraph/parser/region.rb +9 -3
  78. data/lib/solargraph/parser/snippet.rb +1 -1
  79. data/lib/solargraph/pin/base.rb +53 -21
  80. data/lib/solargraph/pin/base_variable.rb +312 -20
  81. data/lib/solargraph/pin/block.rb +26 -4
  82. data/lib/solargraph/pin/breakable.rb +5 -1
  83. data/lib/solargraph/pin/callable.rb +50 -3
  84. data/lib/solargraph/pin/closure.rb +2 -6
  85. data/lib/solargraph/pin/common.rb +20 -5
  86. data/lib/solargraph/pin/compound_statement.rb +55 -0
  87. data/lib/solargraph/pin/conversions.rb +2 -1
  88. data/lib/solargraph/pin/delegated_method.rb +15 -4
  89. data/lib/solargraph/pin/documenting.rb +1 -0
  90. data/lib/solargraph/pin/instance_variable.rb +5 -1
  91. data/lib/solargraph/pin/keyword.rb +0 -4
  92. data/lib/solargraph/pin/local_variable.rb +13 -57
  93. data/lib/solargraph/pin/method.rb +90 -42
  94. data/lib/solargraph/pin/method_alias.rb +8 -0
  95. data/lib/solargraph/pin/namespace.rb +7 -1
  96. data/lib/solargraph/pin/parameter.rb +76 -13
  97. data/lib/solargraph/pin/proxy_type.rb +2 -1
  98. data/lib/solargraph/pin/reference/override.rb +1 -1
  99. data/lib/solargraph/pin/reference/superclass.rb +2 -0
  100. data/lib/solargraph/pin/reference.rb +2 -0
  101. data/lib/solargraph/pin/search.rb +1 -0
  102. data/lib/solargraph/pin/signature.rb +8 -0
  103. data/lib/solargraph/pin/symbol.rb +1 -1
  104. data/lib/solargraph/pin/until.rb +1 -1
  105. data/lib/solargraph/pin/while.rb +1 -1
  106. data/lib/solargraph/pin.rb +2 -0
  107. data/lib/solargraph/pin_cache.rb +477 -57
  108. data/lib/solargraph/position.rb +12 -26
  109. data/lib/solargraph/range.rb +6 -6
  110. data/lib/solargraph/rbs_map/conversions.rb +33 -10
  111. data/lib/solargraph/rbs_map/core_map.rb +24 -17
  112. data/lib/solargraph/rbs_map/stdlib_map.rb +34 -5
  113. data/lib/solargraph/rbs_map.rb +74 -20
  114. data/lib/solargraph/shell.rb +73 -28
  115. data/lib/solargraph/source/chain/call.rb +52 -17
  116. data/lib/solargraph/source/chain/constant.rb +2 -0
  117. data/lib/solargraph/source/chain/hash.rb +1 -0
  118. data/lib/solargraph/source/chain/if.rb +1 -0
  119. data/lib/solargraph/source/chain/instance_variable.rb +22 -1
  120. data/lib/solargraph/source/chain/literal.rb +5 -0
  121. data/lib/solargraph/source/chain/or.rb +9 -1
  122. data/lib/solargraph/source/chain.rb +25 -22
  123. data/lib/solargraph/source/change.rb +9 -2
  124. data/lib/solargraph/source/cursor.rb +7 -1
  125. data/lib/solargraph/source/source_chainer.rb +13 -3
  126. data/lib/solargraph/source/updater.rb +4 -0
  127. data/lib/solargraph/source.rb +33 -7
  128. data/lib/solargraph/source_map/clip.rb +13 -2
  129. data/lib/solargraph/source_map/data.rb +4 -1
  130. data/lib/solargraph/source_map/mapper.rb +24 -1
  131. data/lib/solargraph/source_map.rb +14 -6
  132. data/lib/solargraph/type_checker/problem.rb +3 -1
  133. data/lib/solargraph/type_checker/rules.rb +75 -2
  134. data/lib/solargraph/type_checker.rb +111 -30
  135. data/lib/solargraph/version.rb +1 -1
  136. data/lib/solargraph/workspace/config.rb +3 -1
  137. data/lib/solargraph/workspace/gemspecs.rb +367 -0
  138. data/lib/solargraph/workspace/require_paths.rb +1 -0
  139. data/lib/solargraph/workspace.rb +158 -16
  140. data/lib/solargraph/yard_map/helpers.rb +2 -1
  141. data/lib/solargraph/yard_map/mapper/to_method.rb +5 -1
  142. data/lib/solargraph/yard_map/mapper/to_namespace.rb +1 -0
  143. data/lib/solargraph/yard_map/mapper.rb +5 -0
  144. data/lib/solargraph/yardoc.rb +33 -23
  145. data/lib/solargraph.rb +24 -3
  146. data/rbs/fills/rubygems/0/dependency.rbs +193 -0
  147. data/rbs/fills/tuple/tuple.rbs +28 -0
  148. data/rbs/shims/ast/0/node.rbs +1 -1
  149. data/rbs/shims/diff-lcs/1.5/diff-lcs.rbs +11 -0
  150. data/solargraph.gemspec +2 -1
  151. metadata +12 -7
  152. data/lib/solargraph/type_checker/checks.rb +0 -124
  153. data/lib/solargraph/type_checker/param_def.rb +0 -37
  154. data/lib/solargraph/yard_map/to_method.rb +0 -89
@@ -6,31 +6,139 @@ module Solargraph
6
6
  # include Solargraph::Source::NodeMethods
7
7
  include Solargraph::Parser::NodeMethods
8
8
 
9
- # @return [Parser::AST::Node, nil]
10
- attr_reader :assignment
9
+ # @return [Array<Parser::AST::Node>]
10
+ attr_reader :assignments
11
11
 
12
12
  attr_accessor :mass_assignment
13
13
 
14
+ # @return [Range, nil]
15
+ attr_reader :presence
16
+
14
17
  # @param return_type [ComplexType, nil]
18
+ # @param assignment [Parser::AST::Node, nil] First assignment
19
+ # that was made to this variable
20
+ # @param assignments [Array<Parser::AST::Node>] Possible
21
+ # assignments that may have been made to this variable
15
22
  # @param mass_assignment [::Array(Parser::AST::Node, Integer), nil]
16
- # @param assignment [Parser::AST::Node, nil]
17
- def initialize assignment: nil, return_type: nil, mass_assignment: nil, **splat
23
+ # @param assignment [Parser::AST::Node, nil] First assignment
24
+ # that was made to this variable
25
+ # @param assignments [Array<Parser::AST::Node>] Possible
26
+ # assignments that may have been made to this variable
27
+ # @param exclude_return_type [ComplexType, nil] Ensure any
28
+ # return type returned will never include any of these unique
29
+ # types in the unique types of its complex type.
30
+ #
31
+ # Example: If a return type is 'Float | Integer | nil' and the
32
+ # exclude_return_type is 'Integer', the resulting return
33
+ # type will be 'Float | nil' because Integer is excluded.
34
+ # @param intersection_return_type [ComplexType, nil] Ensure each unique
35
+ # return type is compatible with at least one element of this
36
+ # complex type. If a ComplexType used as a return type is an
37
+ # union type - we can return any of these - these are
38
+ # intersection types - everything we return needs to meet at least
39
+ # one of these unique types.
40
+ #
41
+ # Example: If a return type is 'Numeric | nil' and the
42
+ # intersection_return_type is 'Float | nil', the resulting return
43
+ # type will be 'Float | nil' because Float is compatible
44
+ # with Numeric and nil is compatible with nil.
45
+ # @see https://www.typescriptlang.org/docs/handbook/2/everyday-types.html#union-types
46
+ # @see https://en.wikipedia.org/wiki/Intersection_type#TypeScript_example
47
+ # @param presence [Range, nil]
48
+ # @param presence_certain [Boolean]
49
+ def initialize assignment: nil, assignments: [], mass_assignment: nil,
50
+ presence: nil, presence_certain: false, return_type: nil,
51
+ intersection_return_type: nil, exclude_return_type: nil,
52
+ **splat
18
53
  super(**splat)
19
- @assignment = assignment
54
+ @assignments = (assignment.nil? ? [] : [assignment]) + assignments
20
55
  # @type [nil, ::Array(Parser::AST::Node, Integer)]
21
- @mass_assignment = nil
56
+ @mass_assignment = mass_assignment
22
57
  @return_type = return_type
58
+ @intersection_return_type = intersection_return_type
59
+ @exclude_return_type = exclude_return_type
60
+ @presence = presence
61
+ @presence_certain = presence_certain
62
+ end
63
+
64
+ # @param presence [Range]
65
+ # @param exclude_return_type [ComplexType, nil]
66
+ # @param intersection_return_type [ComplexType, nil]
67
+ # @param source [::Symbol]
68
+ #
69
+ # @return [self]
70
+ def downcast presence:, exclude_return_type: nil, intersection_return_type: nil,
71
+ source: self.source
72
+ result = dup
73
+ result.exclude_return_type = exclude_return_type
74
+ result.intersection_return_type = intersection_return_type
75
+ result.source = source
76
+ result.presence = presence
77
+ result.reset_generated!
78
+ result
79
+ end
80
+
81
+ def reset_generated!
82
+ @assignment = nil
83
+ super
23
84
  end
24
85
 
25
86
  def combine_with(other, attrs={})
87
+ new_assignments = combine_assignments(other)
26
88
  new_attrs = attrs.merge({
27
- assignment: assert_same(other, :assignment),
28
- mass_assignment: assert_same(other, :mass_assignment),
89
+ # default values don't exist in RBS parameters; it just
90
+ # tells you if the arg is optional or not. Prefer a
91
+ # provided value if we have one here since we can't rely on
92
+ # it from RBS so we can infer from it and typecheck on it.
93
+ assignment: choose(other, :assignment),
94
+ assignments: new_assignments,
95
+ mass_assignment: combine_mass_assignment(other),
29
96
  return_type: combine_return_type(other),
97
+ intersection_return_type: combine_types(other, :intersection_return_type),
98
+ exclude_return_type: combine_types(other, :exclude_return_type),
99
+ presence: combine_presence(other),
100
+ presence_certain: combine_presence_certain(other)
30
101
  })
31
102
  super(other, new_attrs)
32
103
  end
33
104
 
105
+ # @param other [self]
106
+ #
107
+ # @return [Array(AST::Node, Integer), nil]
108
+ def combine_mass_assignment(other)
109
+ # @todo pick first non-nil arbitrarily - we don't yet support
110
+ # mass assignment merging
111
+ mass_assignment || other.mass_assignment
112
+ end
113
+
114
+ # If a certain pin is being combined with an uncertain pin, we
115
+ # end up with a certain result
116
+ #
117
+ # @param other [self]
118
+ #
119
+ # @return [Boolean]
120
+ def combine_presence_certain(other)
121
+ presence_certain? || other.presence_certain?
122
+ end
123
+
124
+ # @return [Parser::AST::Node, nil]
125
+ def assignment
126
+ @assignment ||= assignments.last
127
+ end
128
+
129
+ # @param other [self]
130
+ #
131
+ # @return [::Array<Parser::AST::Node>]
132
+ def combine_assignments(other)
133
+ (other.assignments + assignments).uniq
134
+ end
135
+
136
+ def inner_desc
137
+ super + ", presence=#{presence.inspect}, assignments=#{assignments}, " \
138
+ "intersection_return_type=#{intersection_return_type&.rooted_tags.inspect}, " \
139
+ "exclude_return_type=#{exclude_return_type&.rooted_tags.inspect}"
140
+ end
141
+
34
142
  def completion_item_kind
35
143
  Solargraph::LanguageServer::CompletionItemKinds::VARIABLE
36
144
  end
@@ -40,10 +148,6 @@ module Solargraph
40
148
  Solargraph::LanguageServer::SymbolKinds::VARIABLE
41
149
  end
42
150
 
43
- def return_type
44
- @return_type ||= generate_complex_type
45
- end
46
-
47
151
  def nil_assignment?
48
152
  # this will always be false - should it be return_type ==
49
153
  # ComplexType::NIL or somesuch?
@@ -67,10 +171,12 @@ module Solargraph
67
171
  rng = Range.from_node(node)
68
172
  next if rng.nil?
69
173
  pos = rng.ending
174
+ # @sg-ignore Need to add nil check here
70
175
  clip = api_map.clip_at(location.filename, pos)
71
176
  # Use the return node for inference. The clip might infer from the
72
177
  # first node in a method call instead of the entire call.
73
178
  chain = Parser.chain(node, nil, nil)
179
+ # @sg-ignore Need to add nil check here
74
180
  result = chain.infer(api_map, closure, clip.locals).self_to_type(closure.context)
75
181
  types.push result unless result.undefined?
76
182
  end
@@ -79,13 +185,15 @@ module Solargraph
79
185
  end
80
186
 
81
187
  # @param api_map [ApiMap]
82
- # @return [ComplexType]
188
+ # @return [ComplexType, ComplexType::UniqueType]
83
189
  def probe api_map
84
- unless @assignment.nil?
85
- types = return_types_from_node(@assignment, api_map)
86
- return ComplexType.new(types.uniq) unless types.empty?
87
- end
190
+ assignment_types = assignments.flat_map { |node| return_types_from_node(node, api_map) }
191
+ type_from_assignment = ComplexType.new(assignment_types.flat_map(&:items).uniq) unless assignment_types.empty?
192
+ return adjust_type api_map, type_from_assignment unless type_from_assignment.nil?
88
193
 
194
+ # @todo should handle merging types from mass assignments as
195
+ # well so that we can do better flow sensitive typing with
196
+ # multiple assignments
89
197
  unless @mass_assignment.nil?
90
198
  mass_node, index = @mass_assignment
91
199
  types = return_types_from_node(mass_node, api_map)
@@ -96,7 +204,10 @@ module Solargraph
96
204
  type.all_params.first
97
205
  end
98
206
  end.compact!
99
- return ComplexType.new(types.uniq) unless types.empty?
207
+
208
+ return ComplexType::UNDEFINED if types.empty?
209
+
210
+ return adjust_type api_map, ComplexType.new(types.uniq).qualify(api_map, *gates)
100
211
  end
101
212
 
102
213
  ComplexType::UNDEFINED
@@ -113,13 +224,194 @@ module Solargraph
113
224
  "#{super} = #{assignment&.type.inspect}"
114
225
  end
115
226
 
227
+ # @return [ComplexType, nil]
228
+ def return_type
229
+ generate_complex_type || @return_type || intersection_return_type || ComplexType::UNDEFINED
230
+ end
231
+
232
+ def typify api_map
233
+ raw_return_type = super
234
+
235
+ adjust_type(api_map, raw_return_type)
236
+ end
237
+
238
+ # @sg-ignore need boolish support for ? methods
239
+ def presence_certain?
240
+ exclude_return_type || intersection_return_type
241
+ end
242
+
243
+ # @param other_loc [Location]
244
+ # @sg-ignore flow sensitive typing needs to handle attrs
245
+ def starts_at?(other_loc)
246
+ location&.filename == other_loc.filename &&
247
+ presence &&
248
+ # @sg-ignore flow sensitive typing needs to handle attrs
249
+ presence.start == other_loc.range.start
250
+ end
251
+
252
+ # Narrow the presence range to the intersection of both.
253
+ #
254
+ # @param other [self]
255
+ #
256
+ # @return [Range, nil]
257
+ def combine_presence(other)
258
+ return presence || other.presence if presence.nil? || other.presence.nil?
259
+
260
+ # @sg-ignore flow sensitive typing needs to handle attrs
261
+ Range.new([presence.start, other.presence.start].max, [presence.ending, other.presence.ending].min)
262
+ end
263
+
264
+ # @param other [self]
265
+ # @return [Pin::Closure, nil]
266
+ def combine_closure(other)
267
+ return closure if self.closure == other.closure
268
+
269
+ # choose first defined, as that establishes the scope of the variable
270
+ if closure.nil? || other.closure.nil?
271
+ Solargraph.assert_or_log(:varible_closure_missing) do
272
+ "One of the local variables being combined is missing a closure: " \
273
+ "#{self.inspect} vs #{other.inspect}"
274
+ end
275
+ return closure || other.closure
276
+ end
277
+
278
+ # @sg-ignore flow sensitive typing needs to handle attrs
279
+ if closure.location.nil? || other.closure.location.nil?
280
+ # @sg-ignore flow sensitive typing needs to handle attrs
281
+ return closure.location.nil? ? other.closure : closure
282
+ end
283
+
284
+ # if filenames are different, this will just pick one
285
+ # @sg-ignore flow sensitive typing needs to handle attrs
286
+ return closure if closure.location <= other.closure.location
287
+
288
+ other.closure
289
+ end
290
+
291
+ # @param other_closure [Pin::Closure]
292
+ # @param other_loc [Location]
293
+ def visible_at?(other_closure, other_loc)
294
+ # @sg-ignore flow sensitive typing needs to handle attrs
295
+ location.filename == other_loc.filename &&
296
+ # @sg-ignore flow sensitive typing needs to handle attrs
297
+ (!presence || presence.include?(other_loc.range.start)) &&
298
+ visible_in_closure?(other_closure)
299
+ end
300
+
301
+ def presence_certain?
302
+ @presence_certain
303
+ end
304
+
305
+ protected
306
+
307
+ attr_accessor :exclude_return_type, :intersection_return_type
308
+
309
+ # @return [Range]
310
+ attr_writer :presence
311
+
116
312
  private
117
313
 
118
- # @return [ComplexType]
314
+ # @param api_map [ApiMap]
315
+ # @param raw_return_type [ComplexType, ComplexType::UniqueType]
316
+ #
317
+ # @return [ComplexType, ComplexType::UniqueType]
318
+ def adjust_type(api_map, raw_return_type)
319
+ qualified_exclude = exclude_return_type&.qualify(api_map, *(closure&.gates || ['']))
320
+ minus_exclusions = raw_return_type.exclude qualified_exclude, api_map
321
+ qualified_intersection = intersection_return_type&.qualify(api_map, *(closure&.gates || ['']))
322
+ minus_exclusions.intersect_with qualified_intersection, api_map
323
+ end
324
+
325
+ # @param other [self]
326
+ # @return [Pin::Closure, nil]
327
+ def combine_closure(other)
328
+ return closure if self.closure == other.closure
329
+
330
+ # choose first defined, as that establishes the scope of the variable
331
+ if closure.nil? || other.closure.nil?
332
+ Solargraph.assert_or_log(:varible_closure_missing) do
333
+ "One of the local variables being combined is missing a closure: " \
334
+ "#{self.inspect} vs #{other.inspect}"
335
+ end
336
+ return closure || other.closure
337
+ end
338
+
339
+ # @sg-ignore Need to add nil check here
340
+ if closure.location.nil? || other.closure.location.nil?
341
+ # @sg-ignore Need to add nil check here
342
+ return closure.location.nil? ? other.closure : closure
343
+ end
344
+
345
+ # if filenames are different, this will just pick one
346
+ # @sg-ignore flow sensitive typing needs to handle attrs
347
+ return closure if closure.location <= other.closure.location
348
+
349
+ other.closure
350
+ end
351
+
352
+ # See if this variable is visible within 'viewing_closure'
353
+ #
354
+ # @param viewing_closure [Pin::Closure]
355
+ # @return [Boolean]
356
+ def visible_in_closure? viewing_closure
357
+ return false if closure.nil?
358
+
359
+ # if we're declared at top level, we can't be seen from within
360
+ # methods declared tere
361
+
362
+ # @sg-ignore Need to add nil check here
363
+ return false if viewing_closure.is_a?(Pin::Method) && closure.context.tags == 'Class<>'
364
+
365
+ # @sg-ignore Need to add nil check here
366
+ return true if viewing_closure.binder.namespace == closure.binder.namespace
367
+
368
+ # @sg-ignore Need to add nil check here
369
+ return true if viewing_closure.return_type == closure.context
370
+
371
+ # classes and modules can't see local variables declared
372
+ # in their parent closure, so stop here
373
+ return false if scope == :instance && viewing_closure.is_a?(Pin::Namespace)
374
+
375
+ parent_of_viewing_closure = viewing_closure.closure
376
+
377
+ return false if parent_of_viewing_closure.nil?
378
+
379
+ visible_in_closure?(parent_of_viewing_closure)
380
+ end
381
+
382
+ # @param other [self]
383
+ # @return [ComplexType, nil]
384
+ def combine_return_type(other)
385
+ combine_types(other, :return_type)
386
+ end
387
+
388
+ # @param other [self]
389
+ # @param attr [::Symbol]
390
+ #
391
+ # @return [ComplexType, nil]
392
+ def combine_types(other, attr)
393
+ # @type [ComplexType, nil]
394
+ type1 = send(attr)
395
+ # @type [ComplexType, nil]
396
+ type2 = other.send(attr)
397
+ if type1 && type2
398
+ types = (type1.items + type2.items).uniq
399
+ ComplexType.new(types)
400
+ else
401
+ type1 || type2
402
+ end
403
+ end
404
+
405
+ # @return [::Symbol]
406
+ def scope
407
+ :instance
408
+ end
409
+
410
+ # @return [ComplexType, nil]
119
411
  def generate_complex_type
120
412
  tag = docstring.tag(:type)
121
413
  return ComplexType.try_parse(*tag.types) unless tag.nil? || tag.types.nil? || tag.types.empty?
122
- ComplexType.new
414
+ nil
123
415
  end
124
416
  end
125
417
  end
@@ -21,6 +21,7 @@ module Solargraph
21
21
  @context = context
22
22
  @return_type = ComplexType.parse('::Proc')
23
23
  @node = node
24
+ @name = '<block>'
24
25
  end
25
26
 
26
27
  # @param api_map [ApiMap]
@@ -30,7 +31,13 @@ module Solargraph
30
31
  end
31
32
 
32
33
  def binder
33
- @rebind&.defined? ? @rebind : closure.binder
34
+ out = @rebind if @rebind&.defined?
35
+ out ||= super
36
+ end
37
+
38
+ def context
39
+ @context = @rebind if @rebind&.defined?
40
+ super
34
41
  end
35
42
 
36
43
  # @param yield_types [::Array<ComplexType>]
@@ -50,14 +57,17 @@ module Solargraph
50
57
  # @return [::Array<ComplexType>]
51
58
  def typify_parameters(api_map)
52
59
  chain = Parser.chain(receiver, filename, node)
60
+ # @sg-ignore Need to add nil check here
53
61
  clip = api_map.clip_at(location.filename, location.range.start)
54
62
  locals = clip.locals - [self]
63
+ # @sg-ignore Need to add nil check here
55
64
  meths = chain.define(api_map, closure, locals)
56
65
  # @todo Convert logic to use signatures
57
66
  # @param meth [Pin::Method]
58
67
  meths.each do |meth|
59
68
  next if meth.block.nil?
60
69
 
70
+ # @sg-ignore flow sensitive typing needs to handle attrs
61
71
  yield_types = meth.block.parameters.map(&:return_type)
62
72
  # 'arguments' is what the method says it will yield to the
63
73
  # block; 'parameters' is what the block accepts
@@ -67,6 +77,7 @@ module Solargraph
67
77
  param_type = chain.base.infer(api_map, param, locals)
68
78
  unless arg_type.nil?
69
79
  if arg_type.generic? && param_type.defined?
80
+ # @sg-ignore Need to add nil check here
70
81
  namespace_pin = api_map.get_namespace_pins(meth.namespace, closure.namespace).first
71
82
  arg_type.resolve_generics(namespace_pin, param_type)
72
83
  else
@@ -86,16 +97,27 @@ module Solargraph
86
97
  def maybe_rebind api_map
87
98
  return ComplexType::UNDEFINED unless receiver
88
99
 
89
- chain = Parser.chain(receiver, location.filename)
100
+ # @sg-ignore Need to add nil check here
101
+ chain = Parser.chain(receiver, location.filename, node)
102
+ # @sg-ignore Need to add nil check here
90
103
  locals = api_map.source_map(location.filename).locals_at(location)
104
+ # @sg-ignore Need to add nil check here
91
105
  receiver_pin = chain.define(api_map, closure, locals).first
92
106
  return ComplexType::UNDEFINED unless receiver_pin
93
107
 
94
108
  types = receiver_pin.docstring.tag(:yieldreceiver)&.types
95
109
  return ComplexType::UNDEFINED unless types&.any?
96
110
 
97
- target = chain.base.infer(api_map, receiver_pin, locals)
98
- target = full_context unless target.defined?
111
+ name_pin = self
112
+ # if we have Foo.bar { |x| ... }, and the bar method references self...
113
+ target = if chain.base.defined?
114
+ # figure out Foo
115
+ chain.base.infer(api_map, name_pin, locals)
116
+ else
117
+ # if not, any self there must be the context of our closure
118
+ # @sg-ignore Need to add nil check here
119
+ closure.full_context
120
+ end
99
121
 
100
122
  ComplexType.try_parse(*types).qualify(api_map, *receiver_pin.gates).self_to_type(target)
101
123
  end
@@ -1,9 +1,13 @@
1
1
  module Solargraph
2
2
  module Pin
3
- # Mix-in for pins which enclose code which the 'break' statement works with-in - e.g., blocks, when, until, ...
3
+ # Mix-in for pins which enclose code which the 'break' statement
4
+ # works with-in - e.g., blocks, when, until, ...
4
5
  module Breakable
5
6
  # @return [Parser::AST::Node]
6
7
  attr_reader :node
8
+
9
+ # @return [Location, nil]
10
+ attr_reader :location
7
11
  end
8
12
  end
9
13
  end
@@ -21,8 +21,15 @@ module Solargraph
21
21
  @parameters = parameters
22
22
  end
23
23
 
24
+ def reset_generated!
25
+ parameters.each(&:reset_generated!)
26
+ super
27
+ end
28
+
29
+ # @sg-ignore Need to add nil check here
24
30
  # @return [String]
25
31
  def method_namespace
32
+ # @sg-ignore Need to add nil check here
26
33
  closure.namespace
27
34
  end
28
35
 
@@ -80,6 +87,7 @@ module Solargraph
80
87
  end
81
88
  end
82
89
 
90
+ # @sg-ignore Need to add nil check here
83
91
  # @return [Array<Pin::Parameter>]
84
92
  def blockless_parameters
85
93
  if parameters.last&.block?
@@ -89,11 +97,33 @@ module Solargraph
89
97
  end
90
98
  end
91
99
 
92
- # @return [Array]
100
+ # e.g., [["T"], "", "?", "foo:"] - parameter arity declarations,
101
+ # ignoring positional names. Used to match signatures.
102
+ #
103
+ # @return [Array<Array<String>, String, nil>]
93
104
  def arity
94
105
  [generics, blockless_parameters.map(&:arity_decl), block&.arity]
95
106
  end
96
107
 
108
+ # e.g., [["T"], "1", "?3", "foo:5"] - parameter arity
109
+ # declarations, including the number of unique types in each
110
+ # parameter. Used to determine whether combining two
111
+ # signatures has lost useful information mapping specific
112
+ # parameter types to specific return types.
113
+ #
114
+ # @return [Array<Array, String, nil>]
115
+ def type_arity
116
+ [generics, blockless_parameters.map(&:type_arity_decl), block&.type_arity]
117
+ end
118
+
119
+ # Same as type_arity, but includes return type arity at the front.
120
+ #
121
+ # @return [Array<Array, String, nil>]
122
+ def full_type_arity
123
+ # @sg-ignore flow sensitive typing needs to handle attrs
124
+ [return_type ? return_type.items.count.to_s : nil] + type_arity
125
+ end
126
+
97
127
  # @param generics_to_resolve [Enumerable<String>]
98
128
  # @param arg_types [Array<ComplexType>, nil]
99
129
  # @param return_type_context [ComplexType, nil]
@@ -101,6 +131,7 @@ module Solargraph
101
131
  # @param yield_return_type_context [ComplexType, nil]
102
132
  # @param context [ComplexType, nil]
103
133
  # @param resolved_generic_values [Hash{String => ComplexType}]
134
+ #
104
135
  # @return [self]
105
136
  def resolve_generics_from_context(generics_to_resolve,
106
137
  arg_types = nil,
@@ -137,9 +168,11 @@ module Solargraph
137
168
  end
138
169
  end
139
170
 
171
+ # @sg-ignore Need to add nil check here
140
172
  # @return [String]
141
173
  def method_name
142
174
  raise "closure was nil in #{self.inspect}" if closure.nil?
175
+ # @sg-ignore Need to add nil check here
143
176
  @method_name ||= closure.name
144
177
  end
145
178
 
@@ -150,6 +183,7 @@ module Solargraph
150
183
  # @param yield_return_type_context [ComplexType, nil]
151
184
  # @param context [ComplexType, nil]
152
185
  # @param resolved_generic_values [Hash{String => ComplexType}]
186
+ #
153
187
  # @return [self]
154
188
  def resolve_generics_from_context_until_complete(generics_to_resolve,
155
189
  arg_types = nil,
@@ -184,7 +218,6 @@ module Solargraph
184
218
  resolved_generic_values: resolved_generic_values)
185
219
  end
186
220
 
187
- # @return [Array<String>]
188
221
  # @yieldparam [ComplexType]
189
222
  # @yieldreturn [ComplexType]
190
223
  # @return [self]
@@ -206,17 +239,31 @@ module Solargraph
206
239
  parcount = mandatory_positional_param_count
207
240
  parcount -= 1 if !parameters.empty? && parameters.last.block?
208
241
  return false if block? && !with_block
242
+ # @todo this and its caller should be changed so that this can
243
+ # look at the kwargs provided and check names against what
244
+ # we acccept
209
245
  return false if argcount < parcount && !(argcount == parcount - 1 && parameters.last.restarg?)
210
246
  true
211
247
  end
212
248
 
249
+ def reset_generated!
250
+ super
251
+ @parameters.each(&:reset_generated!)
252
+ end
253
+
213
254
  # @return [Integer]
214
255
  def mandatory_positional_param_count
215
256
  parameters.count(&:arg?)
216
257
  end
217
258
 
259
+ # @return [String]
260
+ def parameters_to_rbs
261
+ # @sg-ignore Need to add nil check here
262
+ rbs_generics + '(' + parameters.map { |param| param.to_rbs }.join(', ') + ') ' + (block.nil? ? '' : '{ ' + block.to_rbs + ' } ')
263
+ end
264
+
218
265
  def to_rbs
219
- rbs_generics + '(' + parameters.map { |param| param.to_rbs }.join(', ') + ') ' + (block.nil? ? '' : '{ ' + block.to_rbs + ' } ') + '-> ' + return_type.to_rbs
266
+ parameters_to_rbs + '-> ' + (return_type&.to_rbs || 'untyped')
220
267
  end
221
268
 
222
269
  def block?
@@ -2,12 +2,12 @@
2
2
 
3
3
  module Solargraph
4
4
  module Pin
5
- class Closure < Base
5
+ class Closure < CompoundStatement
6
6
  # @return [::Symbol] :class or :instance
7
7
  attr_reader :scope
8
8
 
9
9
  # @param scope [::Symbol] :class or :instance
10
- # @param generics [::Array<Pin::Parameter>, nil]
10
+ # @param generics [::Array<Pin::String>, nil]
11
11
  # @param generic_defaults [Hash{String => ComplexType}]
12
12
  def initialize scope: :class, generics: nil, generic_defaults: {}, **splat
13
13
  super(**splat)
@@ -44,10 +44,6 @@ module Solargraph
44
44
  end
45
45
  end
46
46
 
47
- def binder
48
- @binder || context
49
- end
50
-
51
47
  # @param api_map [Solargraph::ApiMap]
52
48
  # @return [void]
53
49
  def rebind api_map; end