solargraph 0.53.2 → 0.53.4

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: dd82572e0c8ca2d5e7477c4bbcd58fa66b318550a23b6944d8749f67913560e3
4
- data.tar.gz: 79ba0becff2e00fbcc7139ec540e91db5dec195cf5ae557cdcf599026b11b964
3
+ metadata.gz: 82af0b18d57296a8eef96680e60f131bad23268e4043d49407d197fc378dd3d2
4
+ data.tar.gz: 10c5622ac74f0feef06033ed0b851268c876a68581d846b2874fe61a29612acb
5
5
  SHA512:
6
- metadata.gz: 743c84f70a8d49f253f4fdf3e8b43a3061ad7cd6eec68fbbf592505d63d56666ae5654ca2664750a7963d43f5b131ff1c7bc52660266786d345c9a19b86856fa
7
- data.tar.gz: 8accd71eec8ce6f5ccf3aa5efd692a3ff71ea35eabf125446fe533049df80bd84fb33bf73d0cdadd7914598d485ed1f013c7cc898575b1a34238c90e92d8318e
6
+ metadata.gz: 1671b54ae2c314d5c566629706b6de94ca5de0902d1d56e7b96853a889d54b0caef084a5c416222f6fe9f4d40387ea3b56d34b6af917a36855ae902f0b8acf0d
7
+ data.tar.gz: e7b24e7c08164da0a0b60fc8f04281bfceef59e95470d3f3e78193b024d615da2ae62f94712222ffac722623f7de8207f7af29013bdad6787c63716556ecaf43
data/CHANGELOG.md CHANGED
@@ -1,3 +1,17 @@
1
+ ## 0.53.4 - March 30, 2025
2
+ - [regression] Restore 'Unresolved call' typecheck for stdlib objects (#849)
3
+ - Lazy dynamic rebinding (#851)
4
+ - Restore fill for Class#allocate (#848)
5
+ - [regression] Ensure YardMap gems have return type for Class<T>.new (#850)
6
+ - Create implicit .new pins in namespace method queries (#853)
7
+
8
+ ## 0.53.3 - March 29, 2025
9
+ - Remove redundant core fills (#824, #841)
10
+ - Resolve self type in variable assignments (#839)
11
+ - Eliminate splat-related false-alarms in strict typechecking (#840)
12
+ - Dynamic block binding with yieldreceiver (#842)
13
+ - Resolve generics by descending through context type (#847)
14
+
1
15
  ## 0.53.2 - March 27, 2025
2
16
  - Fix a self-type-related false-positive in strict typechecking (#834)
3
17
  - DocMap fetches gem dependencies (#835)
@@ -6,10 +6,13 @@ module Solargraph
6
6
 
7
7
  # Get the YARD CodeObject at the specified path.
8
8
  #
9
+ # @generic T
9
10
  # @param path [String]
10
- # @return [YARD::CodeObjects::Base]
11
- def code_object_at path
12
- code_object_map[path]
11
+ # @param klass [Class<generic<T>>]
12
+ # @return [generic<T>, nil]
13
+ def code_object_at path, klass = YARD::CodeObjects::Base
14
+ obj = code_object_map[path]
15
+ obj if obj&.is_a?(klass)
13
16
  end
14
17
 
15
18
  # @return [Array<String>]
@@ -41,11 +44,13 @@ module Solargraph
41
44
  end
42
45
  code_object_map[pin.path].docstring = pin.docstring
43
46
  store.get_includes(pin.path).each do |ref|
44
- code_object_map[pin.path].instance_mixins.push code_object_map[ref] unless code_object_map[ref].nil? or code_object_map[pin.path].nil?
47
+ include_object = code_object_at(pin.path, YARD::CodeObjects::ClassObject)
48
+ include_object.instance_mixins.push code_object_map[ref] unless include_object.nil? or include_object.nil?
45
49
  end
46
50
  store.get_extends(pin.path).each do |ref|
47
- code_object_map[pin.path].instance_mixins.push code_object_map[ref] unless code_object_map[ref].nil? or code_object_map[pin.path].nil?
48
- code_object_map[pin.path].class_mixins.push code_object_map[ref] unless code_object_map[ref].nil? or code_object_map[pin.path].nil?
51
+ extend_object = code_object_at(pin.path, YARD::CodeObjects::ClassObject)
52
+ extend_object.instance_mixins.push code_object_map[ref] unless extend_object.nil? or extend_object.nil?
53
+ extend_object.class_mixins.push code_object_map[ref] unless extend_object.nil? or extend_object.nil?
49
54
  end
50
55
  end
51
56
  store.method_pins.each do |pin|
@@ -53,13 +58,15 @@ module Solargraph
53
58
  code_object_map[pin.path] ||= pin.code_object
54
59
  next
55
60
  end
56
- code_object_map[pin.path] ||= YARD::CodeObjects::MethodObject.new(code_object_at(pin.namespace), pin.name, pin.scope) { |obj|
61
+
62
+ code_object_map[pin.path] ||= YARD::CodeObjects::MethodObject.new(code_object_at(pin.namespace, YARD::CodeObjects::NamespaceObject), pin.name, pin.scope) { |obj|
57
63
  next if pin.location.nil? || pin.location.filename.nil?
58
64
  obj.add_file pin.location.filename, pin.location.range.start.line
59
65
  }
60
- code_object_map[pin.path].docstring = pin.docstring
61
- code_object_map[pin.path].visibility = pin.visibility || :public
62
- code_object_map[pin.path].parameters = pin.parameters.map do |p|
66
+ method_object = code_object_at(pin.path, YARD::CodeObjects::MethodObject)
67
+ method_object.docstring = pin.docstring
68
+ method_object.visibility = pin.visibility || :public
69
+ method_object.parameters = pin.parameters.map do |p|
63
70
  [p.name, p.asgn_code]
64
71
  end
65
72
  end
@@ -68,8 +68,6 @@ module Solargraph
68
68
  @store = Store.new(@@core_map.pins + @doc_map.pins + implicit.pins + pins)
69
69
  @unresolved_requires = @doc_map.unresolved_requires
70
70
  @missing_docs = [] # @todo Implement missing docs
71
- @rebindable_method_names = nil
72
- store.block_pins.each { |blk| blk.rebind(self) }
73
71
  self
74
72
  end
75
73
 
@@ -154,17 +152,6 @@ module Solargraph
154
152
  store.pins
155
153
  end
156
154
 
157
- # @return [Set<String>]
158
- def rebindable_method_names
159
- @rebindable_method_names ||= begin
160
- result = ['instance_eval', 'instance_exec', 'class_eval', 'class_exec', 'module_eval', 'module_exec', 'define_method'].to_set
161
- source_maps.each do |map|
162
- result.merge map.rebindable_method_names
163
- end
164
- result
165
- end
166
- end
167
-
168
155
  # An array of pins based on Ruby keywords (`if`, `end`, etc.).
169
156
  #
170
157
  # @return [Enumerable<Solargraph::Pin::Keyword>]
@@ -324,6 +311,26 @@ module Solargraph
324
311
  result.concat inner_get_methods('Kernel', :instance, visibility, deep, skip)
325
312
  else
326
313
  result.concat inner_get_methods(rooted_tag, scope, visibility, deep, skip)
314
+ unless %w[Class Class<Class>].include?(rooted_tag)
315
+ result.map! do |pin|
316
+ next pin unless pin.path == 'Class#new'
317
+ init_pin = get_method_stack(rooted_tag, 'initialize').first
318
+ next pin unless init_pin
319
+
320
+ type = ComplexType.try_parse(ComplexType.try_parse(rooted_tag).namespace)
321
+ Pin::Method.new(
322
+ name: 'new',
323
+ scope: :class,
324
+ location: init_pin.location,
325
+ parameters: init_pin.parameters,
326
+ signatures: init_pin.signatures.map { |sig| sig.proxy(type) },
327
+ return_type: type,
328
+ comments: init_pin.comments,
329
+ closure: init_pin.closure
330
+ # @todo Hack to force TypeChecker#internal_or_core?
331
+ ).tap { |pin| pin.source = :rbs }
332
+ end
333
+ end
327
334
  result.concat inner_get_methods('Kernel', :instance, [:public], deep, skip) if visibility.include?(:private)
328
335
  result.concat inner_get_methods('Module', scope, visibility, deep, skip)
329
336
  end
@@ -737,23 +744,22 @@ module Solargraph
737
744
  # @param visibility [Enumerable<Symbol>]
738
745
  # @return [Array<Pin::Base>]
739
746
  def resolve_method_aliases pins, visibility = [:public, :private, :protected]
740
- result = []
741
- pins.each do |pin|
747
+ pins.map do |pin|
742
748
  resolved = resolve_method_alias(pin)
743
- next if resolved.respond_to?(:visibility) && !visibility.include?(resolved.visibility)
744
- result.push resolved
745
- end
746
- result
749
+ next pin if resolved.respond_to?(:visibility) && !visibility.include?(resolved.visibility)
750
+ resolved
751
+ end.compact
747
752
  end
748
753
 
749
754
  # @param pin [Pin::MethodAlias, Pin::Base]
750
755
  # @return [Pin::Method]
751
756
  def resolve_method_alias pin
752
- return pin if !pin.is_a?(Pin::MethodAlias) || @method_alias_stack.include?(pin.path)
757
+ return pin unless pin.is_a?(Pin::MethodAlias)
758
+ return nil if @method_alias_stack.include?(pin.path)
753
759
  @method_alias_stack.push pin.path
754
760
  origin = get_method_stack(pin.full_context.tag, pin.original, scope: pin.scope).first
755
761
  @method_alias_stack.pop
756
- return pin if origin.nil?
762
+ return nil if origin.nil?
757
763
  args = {
758
764
  location: pin.location,
759
765
  closure: pin.closure,
@@ -8,7 +8,7 @@ module Solargraph
8
8
  class UniqueType
9
9
  include TypeMethods
10
10
 
11
- attr_reader :all_params
11
+ attr_reader :all_params, :subtypes, :key_types
12
12
 
13
13
  # Create a UniqueType with the specified name and an optional substring.
14
14
  # The substring is the parameter section of a parametrized type, e.g.,
@@ -105,13 +105,9 @@ module Solargraph
105
105
  # @param resolved_generic_values [Hash{String => ComplexType}] Added to as types are encountered or resolved
106
106
  # @return [UniqueType, ComplexType]
107
107
  def resolve_generics_from_context generics_to_resolve, context_type, resolved_generic_values: {}
108
- transform(name) do |t|
109
- next t unless t.name == ComplexType::GENERIC_TAG_NAME
110
-
111
- new_binding = false
112
-
113
- type_param = t.subtypes.first&.name
114
- next t unless generics_to_resolve.include? type_param
108
+ if name == ComplexType::GENERIC_TAG_NAME
109
+ type_param = subtypes.first&.name
110
+ return self unless generics_to_resolve.include? type_param
115
111
  unless context_type.nil? || !resolved_generic_values[type_param].nil?
116
112
  new_binding = true
117
113
  resolved_generic_values[type_param] = context_type
@@ -121,7 +117,34 @@ module Solargraph
121
117
  complex_type.resolve_generics_from_context(generics_to_resolve, nil, resolved_generic_values: resolved_generic_values)
122
118
  end
123
119
  end
124
- resolved_generic_values[type_param] || t
120
+ return resolved_generic_values[type_param] || self
121
+ end
122
+
123
+ # @todo typechecking should complain when the method being called has no @yieldparam tag
124
+ new_key_types = resolve_param_generics_from_context(generics_to_resolve, context_type, resolved_generic_values, &:key_types)
125
+ new_subtypes = resolve_param_generics_from_context(generics_to_resolve, context_type, resolved_generic_values, &:subtypes)
126
+ recreate(new_key_types: new_key_types, new_subtypes: new_subtypes)
127
+ end
128
+
129
+ # @param generics_to_resolve [Enumerable<String>]
130
+ # @param context_type [UniqueType]
131
+ # @param resolved_generic_values [Hash{String => ComplexType}]
132
+ # @yieldreturn [Array<ComplexType>]
133
+ # @return [Array<ComplexType>]
134
+ def resolve_param_generics_from_context(generics_to_resolve, context_type, resolved_generic_values)
135
+ types = yield self
136
+ types.each_with_index.flat_map do |ct, i|
137
+ ct.items.flat_map do |ut|
138
+ context_params = yield context_type if context_type
139
+ if context_params && context_params[i]
140
+ type_arg = context_params[i]
141
+ type_arg.map do |new_unique_context_type|
142
+ ut.resolve_generics_from_context generics_to_resolve, new_unique_context_type, resolved_generic_values: resolved_generic_values
143
+ end
144
+ else
145
+ ut.resolve_generics_from_context generics_to_resolve, nil, resolved_generic_values: resolved_generic_values
146
+ end
147
+ end
125
148
  end
126
149
  end
127
150
 
@@ -20,7 +20,7 @@ module Solargraph
20
20
  combined = yard_pins.map do |yard|
21
21
  in_yard.add yard.path
22
22
  next yard unless yard.is_a?(Pin::Method)
23
- rbs = rbs_map.path_pin(yard.path)
23
+ rbs = rbs_map.path_pin(yard.path, Pin::Method)
24
24
  next yard unless rbs
25
25
  # @todo Could not include: attribute and anon_splat
26
26
  # @sg-ignore
@@ -493,6 +493,24 @@ module Solargraph
493
493
  end
494
494
  if params['data']['path']
495
495
  result.concat library.path_pins(params['data']['path'])
496
+ # @todo This exception is necessary because `Library#path_pins` does
497
+ # not perform a namespace method query, so the implicit `.new` pin
498
+ # might not exist.
499
+ if result.empty? && params['data']['path'] =~ /\.new$/
500
+ result.concat(library.path_pins(params['data']['path'].sub(/\.new$/, '#initialize')).map do |pin|
501
+ next pin unless pin.name == 'initialize'
502
+
503
+ Pin::Method.new(
504
+ name: 'new',
505
+ scope: :class,
506
+ location: pin.location,
507
+ parameters: pin.parameters,
508
+ return_type: ComplexType.try_parse(params['data']['path']),
509
+ comments: pin.comments,
510
+ closure: pin.closure
511
+ )
512
+ end)
513
+ end
496
514
  end
497
515
  # Selecting by both location and path can result in duplicate pins
498
516
  result.uniq { |p| [p.path, p.location] }
@@ -251,7 +251,19 @@ module Solargraph
251
251
  found = source.references(pin.name)
252
252
  found.select! do |loc|
253
253
  referenced = definitions_at(loc.filename, loc.range.ending.line, loc.range.ending.character).first
254
- referenced && referenced.path == pin.path
254
+ referenced&.path == pin.path
255
+ end
256
+ if pin.path == 'Class#new'
257
+ caller = cursor.chain.base.infer(api_map, clip.send(:block), clip.locals).first
258
+ if caller.defined?
259
+ found.select! do |loc|
260
+ clip = api_map.clip_at(loc.filename, loc.range.start)
261
+ other = clip.send(:cursor).chain.base.infer(api_map, clip.send(:block), clip.locals).first
262
+ caller == other
263
+ end
264
+ else
265
+ found.clear
266
+ end
255
267
  end
256
268
  # HACK: for language clients that exclude special characters from the start of variable names
257
269
  if strip && match = cursor.word.match(/^[^a-z0-9_]+/i)
@@ -7,6 +7,12 @@ require 'cgi'
7
7
 
8
8
  module Solargraph
9
9
  class Page
10
+ # @todo This method directive is necessary because OpenStruct.new confuses
11
+ # the typechecker.
12
+ # @!method self.new(locals, render_method)
13
+ # @param locals[Hash]
14
+ # @param render_method [Proc]
15
+ # @return [Binder]
10
16
  class Binder < OpenStruct
11
17
  # @param locals [Hash]
12
18
  # @param render_method [Proc]
@@ -6,31 +6,18 @@ module Solargraph
6
6
  module NodeProcessors
7
7
  class DefNode < Parser::NodeProcessor::Base
8
8
  def process
9
+ name = node.children[0].to_s
10
+ scope = region.scope || (region.closure.is_a?(Pin::Singleton) ? :class : :instance)
9
11
  methpin = Solargraph::Pin::Method.new(
10
12
  location: get_node_location(node),
11
13
  closure: region.closure,
12
- name: node.children[0].to_s,
14
+ name: name,
13
15
  comments: comments_for(node),
14
- scope: region.scope || (region.closure.is_a?(Pin::Singleton) ? :class : :instance),
15
- visibility: region.visibility,
16
+ scope: scope,
17
+ visibility: scope == :instance && name == 'initialize' ? :private : region.visibility,
16
18
  node: node
17
19
  )
18
- if methpin.name == 'initialize' and methpin.scope == :instance
19
- pins.push Solargraph::Pin::Method.new(
20
- location: methpin.location,
21
- closure: methpin.closure,
22
- name: 'new',
23
- comments: methpin.comments,
24
- scope: :class,
25
- parameters: methpin.parameters
26
- )
27
- # @todo Smelly instance variable access.
28
- pins.last.instance_variable_set(:@return_type, ComplexType::SELF)
29
- pins.push methpin
30
- # @todo Smelly instance variable access.
31
- methpin.instance_variable_set(:@visibility, :private)
32
- methpin.instance_variable_set(:@return_type, ComplexType::VOID)
33
- elsif region.visibility == :module_function
20
+ if region.visibility == :module_function
34
21
  pins.push Solargraph::Pin::Method.new(
35
22
  location: methpin.location,
36
23
  closure: methpin.closure,
@@ -51,7 +51,7 @@ module Solargraph
51
51
  # Use the return node for inference. The clip might infer from the
52
52
  # first node in a method call instead of the entire call.
53
53
  chain = Parser.chain(node, nil, nil)
54
- result = chain.infer(api_map, closure, clip.locals)
54
+ result = chain.infer(api_map, closure, clip.locals).self_to(closure.context.tag)
55
55
  types.push result unless result.undefined?
56
56
  end
57
57
  end
@@ -24,11 +24,11 @@ module Solargraph
24
24
  # @param api_map [ApiMap]
25
25
  # @return [void]
26
26
  def rebind api_map
27
- @binder ||= binder_or_nil(api_map)
27
+ @rebind ||= maybe_rebind(api_map)
28
28
  end
29
29
 
30
30
  def binder
31
- @binder || closure.binder
31
+ @rebind&.defined? ? @rebind : closure.binder
32
32
  end
33
33
 
34
34
  # @return [::Array<Parameter>]
@@ -44,39 +44,22 @@ module Solargraph
44
44
  private
45
45
 
46
46
  # @param api_map [ApiMap]
47
- # @return [ComplexType, nil]
48
- def binder_or_nil api_map
49
- return nil unless receiver
50
- word = receiver.children.find { |c| c.is_a?(::Symbol) }.to_s
51
- return nil unless api_map.rebindable_method_names.include?(word)
47
+ # @return [ComplexType]
48
+ def maybe_rebind api_map
49
+ return ComplexType::UNDEFINED unless receiver
50
+
52
51
  chain = Parser.chain(receiver, location.filename)
53
52
  locals = api_map.source_map(location.filename).locals_at(location)
54
- links_last_word = chain.links.last.word
55
- if %w[instance_eval instance_exec class_eval class_exec module_eval module_exec].include?(links_last_word)
56
- return chain.base.infer(api_map, self, locals)
57
- end
58
- if 'define_method' == links_last_word and chain.define(api_map, self, locals).first&.path == 'Module#define_method' # change class type to instance type
59
- if chain.links.size > 1 # Class.define_method
60
- ty = chain.base.infer(api_map, self, locals)
61
- return Solargraph::ComplexType.parse(ty.namespace)
62
- else # define_method without self
63
- return Solargraph::ComplexType.parse(closure.binder.namespace)
64
- end
65
- end
66
- # other case without early return, read block yieldreceiver tags
67
53
  receiver_pin = chain.define(api_map, self, locals).first
68
- if receiver_pin && receiver_pin.docstring
69
- ys = receiver_pin.docstring.tag(:yieldreceiver)
70
- if ys && ys.types && !ys.types.empty?
71
- target = if chain.links.first.is_a?(Source::Chain::Constant)
72
- receiver_pin.full_context.namespace
73
- else
74
- full_context.namespace
75
- end
76
- return ComplexType.try_parse(*ys.types).qualify(api_map, receiver_pin.context.namespace).self_to(target)
77
- end
78
- end
79
- nil
54
+ return ComplexType::UNDEFINED unless receiver_pin
55
+
56
+ types = receiver_pin.docstring.tag(:yieldreceiver)&.types
57
+ return ComplexType::UNDEFINED unless types&.any?
58
+
59
+ target = chain.base.infer(api_map, receiver_pin, locals)
60
+ target = full_context unless target.defined?
61
+
62
+ ComplexType.try_parse(*types).qualify(api_map, receiver_pin.context.namespace).self_to(target.to_s)
80
63
  end
81
64
  end
82
65
  end
@@ -135,7 +135,7 @@ module Solargraph
135
135
  result = []
136
136
  result.push generate_signature(parameters, top_type) if top_type.defined?
137
137
  result.concat(overloads.map { |meth| generate_signature(meth.parameters, meth.return_type) }) unless overloads.empty?
138
- result.push generate_signature(parameters, top_type) if result.empty?
138
+ result.push generate_signature(parameters, @return_type || ComplexType::UNDEFINED) if result.empty?
139
139
  result
140
140
  end
141
141
  end
@@ -39,24 +39,7 @@ module Solargraph
39
39
  cursor = pins.length
40
40
  environment.declarations.each { |decl| convert_decl_to_pin(decl, Solargraph::Pin::ROOT_PIN) }
41
41
  added_pins = pins[cursor..-1]
42
- add_back_implicit_pins(added_pins)
43
- end
44
-
45
- # @param added_pins [::Enumerable<Pin>]
46
- # @return [void]
47
- def add_back_implicit_pins(added_pins)
48
- added_pins.each do |pin|
49
- pin.source = :rbs
50
- next unless pin.is_a?(Pin::Namespace) && pin.type == :class
51
- next if pins.any? { |p| p.path == "#{pin.path}.new"}
52
- pins.push Solargraph::Pin::Method.new(
53
- location: nil,
54
- closure: pin,
55
- name: 'new',
56
- comments: pin.comments,
57
- scope: :class
58
- )
59
- end
42
+ added_pins.each { |pin| pin.source = :rbs }
60
43
  end
61
44
 
62
45
  # @param decl [RBS::AST::Declarations::Base]
@@ -303,26 +286,8 @@ module Solargraph
303
286
  pin.signatures.concat method_def_to_sigs(decl, pin)
304
287
  pins.push pin
305
288
  if pin.name == 'initialize'
306
- pins.push Solargraph::Pin::Method.new(
307
- location: pin.location,
308
- closure: pin.closure,
309
- name: 'new',
310
- comments: pin.comments,
311
- scope: :class,
312
- signatures: pin.signatures
313
- )
314
- pins.last.signatures.replace(
315
- pin.signatures.map do |p|
316
- Pin::Signature.new(
317
- p.generics,
318
- p.parameters,
319
- ComplexType::SELF
320
- )
321
- end
322
- )
323
- # @todo Is this necessary?
324
- # pin.instance_variable_set(:@visibility, :private)
325
- # pin.instance_variable_set(:@return_type, ComplexType::VOID)
289
+ pin.instance_variable_set(:@visibility, :private)
290
+ pin.instance_variable_set(:@return_type, ComplexType::VOID)
326
291
  end
327
292
  end
328
293
  if decl.singleton?
@@ -22,11 +22,17 @@ module Solargraph
22
22
  closure: Solargraph::Pin::Namespace.new(name: 'Object'), comments: '@return [Class<self>]')
23
23
  ]
24
24
 
25
- CLASS_RETURN_TYPES = [
26
- Override.method_return('Class#new', 'self'),
27
- Override.method_return('Class.new', 'Class<BasicObject>'),
28
- Override.method_return('Class#allocate', 'self'),
29
- Override.method_return('Class.allocate', 'Class<BasicObject>')
25
+ OVERRIDES = [
26
+ Override.from_comment('BasicObject#instance_eval', '@yieldreceiver [self]'),
27
+ Override.from_comment('BasicObject#instance_exec', '@yieldreceiver [self]'),
28
+ Override.from_comment('Module#define_method', '@yieldreceiver [Object<self>]'),
29
+ Override.from_comment('Module#class_eval', '@yieldreceiver [Class<self>]'),
30
+ Override.from_comment('Module#class_exec', '@yieldreceiver [Class<self>]'),
31
+ Override.from_comment('Module#module_eval', '@yieldreceiver [Module<self>]'),
32
+ Override.from_comment('Module#module_exec', '@yieldreceiver [Module<self>]'),
33
+ # RBS does not define Class with a generic, so all calls to
34
+ # generic() return an 'untyped'. We can do better:
35
+ Override.method_return('Class#allocate', 'self')
30
36
  ]
31
37
 
32
38
  # HACK: Add Errno exception classes
@@ -38,7 +44,7 @@ module Solargraph
38
44
  end
39
45
  ERRNOS = errnos
40
46
 
41
- ALL = KEYWORDS + MISSING + CLASS_RETURN_TYPES + ERRNOS
47
+ ALL = KEYWORDS + MISSING + OVERRIDES + ERRNOS
42
48
  end
43
49
  end
44
50
  end
@@ -13,27 +13,16 @@ module Solargraph
13
13
  pins.replace cache
14
14
  else
15
15
  loader = RBS::EnvironmentLoader.new(repository: RBS::Repository.new(no_stdlib: false))
16
- environment = RBS::Environment.from_loader(loader).resolve_type_names
16
+ RBS::Environment.from_loader(loader).resolve_type_names
17
17
  load_environment_to_pins(loader)
18
18
  pins.concat RbsMap::CoreFills::ALL
19
19
  processed = ApiMap::Store.new(pins).pins.reject { |p| p.is_a?(Solargraph::Pin::Reference::Override) }
20
+ processed.each { |pin| pin.source = :rbs }
20
21
  pins.replace processed
21
22
 
22
23
  Cache.save('core.ser', pins)
23
24
  end
24
25
  end
25
-
26
- def method_def_to_sigs decl, pin
27
- stubs = CoreSigns.sign(pin.path)
28
- return super unless stubs
29
- stubs.map do |stub|
30
- Pin::Signature.new(
31
- [],
32
- [],
33
- ComplexType.try_parse(stub.return_type)
34
- )
35
- end
36
- end
37
26
  end
38
27
  end
39
28
  end
@@ -7,7 +7,6 @@ module Solargraph
7
7
  autoload :Conversions, 'solargraph/rbs_map/conversions'
8
8
  autoload :CoreMap, 'solargraph/rbs_map/core_map'
9
9
  autoload :CoreFills, 'solargraph/rbs_map/core_fills'
10
- autoload :CoreSigns, 'solargraph/rbs_map/core_signs'
11
10
  autoload :StdlibMap, 'solargraph/rbs_map/stdlib_map'
12
11
 
13
12
  include Conversions
@@ -28,10 +27,13 @@ module Solargraph
28
27
  load_environment_to_pins(loader)
29
28
  end
30
29
 
30
+ # @generic T
31
31
  # @param path [String]
32
- # @return [Pin::Base, nil]
33
- def path_pin path
34
- pins.find { |p| p.path == path }
32
+ # @param klass [Class<generic<T>>]
33
+ # @return [generic<T>, nil]
34
+ def path_pin path, klass = Pin::Base
35
+ pin = pins.find { |p| p.path == path }
36
+ pin if pin&.is_a?(klass)
35
37
  end
36
38
 
37
39
  # @param path [String]
@@ -11,6 +11,7 @@ module Solargraph
11
11
  def initialize api_map, cursor
12
12
  @api_map = api_map
13
13
  @cursor = cursor
14
+ block.rebind(api_map) if block.is_a?(Pin::Block)
14
15
  end
15
16
 
16
17
  # @return [Array<Pin::Base>] Relevant pins for infering the type of the Cursor's position
@@ -50,9 +51,9 @@ module Solargraph
50
51
  def infer
51
52
  result = cursor.chain.infer(api_map, block, locals)
52
53
  if result.tag == 'Class'
53
- # HACK: Exception to return Object from Class#new
54
+ # HACK: Exception to return BasicObject from Class#new
54
55
  dfn = cursor.chain.define(api_map, block, locals).first
55
- return ComplexType.try_parse('Object') if dfn && dfn.path == 'Class#new'
56
+ return ComplexType.try_parse('BasicObject') if dfn && dfn.path == 'Class#new'
56
57
  end
57
58
  return result unless result.tag == 'self'
58
59
  ComplexType.try_parse(cursor.chain.base.infer(api_map, block, locals).tag)
@@ -40,14 +40,6 @@ module Solargraph
40
40
  @pin_select_cache[klass] ||= @pin_class_hash.select { |key, _| key <= klass }.values.flatten
41
41
  end
42
42
 
43
- # @return [Set<String>]
44
- def rebindable_method_names
45
- @rebindable_method_names ||= pins_by_class(Pin::Method)
46
- .select { |pin| pin.comments && pin.comments.include?('@yieldreceiver') }
47
- .map(&:name)
48
- .to_set
49
- end
50
-
51
43
  # @return [String]
52
44
  def filename
53
45
  source.filename
@@ -268,6 +268,7 @@ module Solargraph
268
268
  base = base.base
269
269
  end
270
270
  closest = found.typify(api_map) if found
271
+ # @todo remove the internal_or_core? check at a higher-than-strict level
271
272
  if !found || found.is_a?(Pin::BaseVariable) || (closest.defined? && internal_or_core?(found))
272
273
  unless closest.generic? || ignored_pins.include?(found)
273
274
  result.push Problem.new(location, "Unresolved call to #{missing.links.last.word}")
@@ -299,6 +300,14 @@ module Solargraph
299
300
  pin = pins.first
300
301
  ap = if base.links.last.is_a?(Solargraph::Source::Chain::ZSuper)
301
302
  arity_problems_for(pin, fake_args_for(block_pin), location)
303
+ elsif pin.path == 'Class#new'
304
+ fqns = if base.links.one?
305
+ block_pin.namespace
306
+ else
307
+ base.base.infer(api_map, block_pin, locals).namespace
308
+ end
309
+ init = api_map.get_method_stack(fqns, 'initialize').first
310
+ init ? arity_problems_for(init, base.links.last.arguments, location) : []
302
311
  else
303
312
  arity_problems_for(pin, base.links.last.arguments, location)
304
313
  end
@@ -320,8 +329,14 @@ module Solargraph
320
329
  argchain = base.links.last.arguments[idx]
321
330
  if argchain.nil?
322
331
  if par.decl == :arg
323
- errors.push Problem.new(location, "Not enough arguments to #{pin.path}")
324
- next
332
+ last = base.links.last.arguments.last
333
+ if last && last.node.type == :splat
334
+ argchain = last
335
+ next # don't try to apply the type of the splat - unlikely to be specific enough
336
+ else
337
+ errors.push Problem.new(location, "Not enough arguments to #{pin.path}")
338
+ next
339
+ end
325
340
  else
326
341
  last = base.links.last.arguments.last
327
342
  argchain = last if last && [:kwsplat, :hash].include?(last.node.type)
@@ -332,6 +347,10 @@ module Solargraph
332
347
  errors.concat kwarg_problems_for sig, argchain, api_map, block_pin, locals, location, pin, params, idx
333
348
  next
334
349
  else
350
+ last = base.links.last.arguments.last
351
+ if last && last.node.type == :splat
352
+ next # don't try to apply the type of the splat - unlikely to be specific enough
353
+ end
335
354
  ptype = params.key?(par.name) ? params[par.name][:qualified] : ComplexType::UNDEFINED
336
355
  ptype = ptype.self_to(par.context.namespace)
337
356
  if ptype.nil?
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Solargraph
4
- VERSION = '0.53.2'
4
+ VERSION = '0.53.4'
5
5
  end
@@ -19,17 +19,20 @@ module Solargraph
19
19
  gates: [code_object.namespace.to_s]
20
20
  )
21
21
  location = object_location(code_object, spec)
22
+ name ||= code_object.name.to_s
23
+ return_type = ComplexType::SELF if name == 'new'
22
24
  comments = code_object.docstring ? code_object.docstring.all.to_s : ''
23
25
  pin = Pin::Method.new(
24
26
  location: location,
25
27
  closure: closure,
26
- name: name || code_object.name.to_s,
28
+ name: name,
27
29
  comments: comments,
28
30
  scope: scope || code_object.scope,
29
31
  visibility: visibility || code_object.visibility,
30
32
  # @todo Might need to convert overloads to signatures
31
33
  parameters: [],
32
- explicit: code_object.is_explicit?
34
+ explicit: code_object.is_explicit?,
35
+ return_type: return_type
33
36
  )
34
37
  pin.parameters.concat get_parameters(code_object, location, comments, pin)
35
38
  pin
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: solargraph
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.53.2
4
+ version: 0.53.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Fred Snyder
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2025-03-27 00:00:00.000000000 Z
11
+ date: 2025-03-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: backport
@@ -558,7 +558,6 @@ files:
558
558
  - lib/solargraph/rbs_map/conversions.rb
559
559
  - lib/solargraph/rbs_map/core_fills.rb
560
560
  - lib/solargraph/rbs_map/core_map.rb
561
- - lib/solargraph/rbs_map/core_signs.rb
562
561
  - lib/solargraph/rbs_map/stdlib_map.rb
563
562
  - lib/solargraph/server_methods.rb
564
563
  - lib/solargraph/shell.rb
@@ -1,35 +0,0 @@
1
- module Solargraph
2
- class RbsMap
3
- module CoreSigns
4
- Override = Pin::Reference::Override
5
-
6
- class Stub
7
- attr_reader :parameters
8
-
9
- attr_reader :return_type
10
-
11
- # @param parameters [Array<Hash>]
12
- # @param return_type [String]
13
- def initialize parameters, return_type
14
- @parameters = parameters
15
- @return_type = return_type
16
- end
17
- end
18
-
19
- SIGNATURE_MAP = {
20
- 'Object#class' => [
21
- Stub.new(
22
- [],
23
- 'Class<self>'
24
- )
25
- ]
26
- }
27
-
28
- # @param path [String]
29
- # @return [Array<Stub>]
30
- def self.sign path
31
- SIGNATURE_MAP[path]
32
- end
33
- end
34
- end
35
- end