solargraph 0.53.4 → 0.54.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 (80) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +41 -0
  3. data/lib/solargraph/api_map/cache.rb +2 -12
  4. data/lib/solargraph/api_map/store.rb +14 -5
  5. data/lib/solargraph/api_map.rb +67 -24
  6. data/lib/solargraph/complex_type/type_methods.rb +70 -39
  7. data/lib/solargraph/complex_type/unique_type.rb +187 -73
  8. data/lib/solargraph/complex_type.rb +105 -40
  9. data/lib/solargraph/doc_map.rb +19 -3
  10. data/lib/solargraph/gem_pins.rb +9 -1
  11. data/lib/solargraph/language_server/host/dispatch.rb +8 -1
  12. data/lib/solargraph/language_server/host/message_worker.rb +29 -3
  13. data/lib/solargraph/language_server/host/sources.rb +1 -61
  14. data/lib/solargraph/language_server/host.rb +21 -68
  15. data/lib/solargraph/language_server/message/base.rb +1 -1
  16. data/lib/solargraph/language_server/message/initialize.rb +14 -0
  17. data/lib/solargraph/language_server/message/text_document/definition.rb +3 -3
  18. data/lib/solargraph/language_server/message/text_document/document_symbol.rb +3 -3
  19. data/lib/solargraph/language_server/message/text_document/formatting.rb +1 -0
  20. data/lib/solargraph/language_server/message/text_document/hover.rb +1 -1
  21. data/lib/solargraph/language_server/message/text_document/type_definition.rb +3 -3
  22. data/lib/solargraph/language_server/message/workspace/workspace_symbol.rb +2 -2
  23. data/lib/solargraph/language_server/progress.rb +135 -0
  24. data/lib/solargraph/language_server.rb +1 -0
  25. data/lib/solargraph/library.rb +144 -113
  26. data/lib/solargraph/location.rb +14 -1
  27. data/lib/solargraph/parser/node_processor/base.rb +3 -2
  28. data/lib/solargraph/parser/node_processor.rb +1 -0
  29. data/lib/solargraph/parser/parser_gem/class_methods.rb +3 -7
  30. data/lib/solargraph/parser/parser_gem/node_chainer.rb +13 -7
  31. data/lib/solargraph/parser/parser_gem/node_methods.rb +1 -5
  32. data/lib/solargraph/parser/parser_gem/node_processors/args_node.rb +23 -19
  33. data/lib/solargraph/parser/parser_gem/node_processors/lvasgn_node.rb +2 -2
  34. data/lib/solargraph/parser/parser_gem/node_processors/masgn_node.rb +53 -0
  35. data/lib/solargraph/parser/parser_gem/node_processors/send_node.rb +6 -4
  36. data/lib/solargraph/parser/parser_gem/node_processors.rb +2 -0
  37. data/lib/solargraph/parser.rb +2 -5
  38. data/lib/solargraph/pin/base.rb +15 -1
  39. data/lib/solargraph/pin/base_variable.rb +35 -6
  40. data/lib/solargraph/pin/block.rb +48 -11
  41. data/lib/solargraph/pin/callable.rb +147 -0
  42. data/lib/solargraph/pin/closure.rb +8 -3
  43. data/lib/solargraph/pin/common.rb +2 -6
  44. data/lib/solargraph/pin/conversions.rb +3 -2
  45. data/lib/solargraph/pin/delegated_method.rb +5 -1
  46. data/lib/solargraph/pin/documenting.rb +2 -0
  47. data/lib/solargraph/pin/instance_variable.rb +2 -2
  48. data/lib/solargraph/pin/method.rb +54 -32
  49. data/lib/solargraph/pin/namespace.rb +4 -4
  50. data/lib/solargraph/pin/parameter.rb +14 -39
  51. data/lib/solargraph/pin/proxy_type.rb +1 -1
  52. data/lib/solargraph/pin/signature.rb +3 -129
  53. data/lib/solargraph/pin.rb +4 -1
  54. data/lib/solargraph/range.rb +2 -4
  55. data/lib/solargraph/rbs_map/conversions.rb +79 -42
  56. data/lib/solargraph/rbs_map/core_fills.rb +6 -6
  57. data/lib/solargraph/rbs_map.rb +11 -3
  58. data/lib/solargraph/shell.rb +35 -15
  59. data/lib/solargraph/source/chain/array.rb +6 -5
  60. data/lib/solargraph/source/chain/block_symbol.rb +1 -1
  61. data/lib/solargraph/source/chain/block_variable.rb +1 -1
  62. data/lib/solargraph/source/chain/call.rb +78 -50
  63. data/lib/solargraph/source/chain/link.rb +9 -0
  64. data/lib/solargraph/source/chain/or.rb +1 -1
  65. data/lib/solargraph/source/chain.rb +60 -16
  66. data/lib/solargraph/source/cursor.rb +13 -2
  67. data/lib/solargraph/source/updater.rb +1 -0
  68. data/lib/solargraph/source.rb +102 -129
  69. data/lib/solargraph/source_map/clip.rb +4 -4
  70. data/lib/solargraph/source_map/data.rb +30 -0
  71. data/lib/solargraph/source_map/mapper.rb +3 -2
  72. data/lib/solargraph/source_map.rb +37 -15
  73. data/lib/solargraph/type_checker/rules.rb +6 -1
  74. data/lib/solargraph/type_checker.rb +50 -25
  75. data/lib/solargraph/version.rb +1 -1
  76. data/lib/solargraph/views/environment.erb +3 -5
  77. data/lib/solargraph/workspace/config.rb +2 -1
  78. data/lib/solargraph/workspace.rb +13 -0
  79. metadata +6 -3
  80. data/lib/solargraph/language_server/host/cataloger.rb +0 -57
@@ -6,22 +6,25 @@ module Solargraph
6
6
  module NodeProcessors
7
7
  class ArgsNode < Parser::NodeProcessor::Base
8
8
  def process
9
- if node.type == :forward_args
10
- forward
11
- else
12
- node.children.each do |u|
13
- loc = get_node_location(u)
14
- locals.push Solargraph::Pin::Parameter.new(
15
- location: loc,
16
- closure: region.closure,
17
- comments: comments_for(node),
18
- name: u.children[0].to_s,
19
- assignment: u.children[1],
20
- asgn_code: u.children[1] ? region.code_for(u.children[1]) : nil,
21
- presence: region.closure.location.range,
22
- decl: get_decl(u)
23
- )
24
- region.closure.parameters.push locals.last
9
+ callable = region.closure
10
+ if callable.is_a? Pin::Callable
11
+ if node.type == :forward_args
12
+ forward(callable)
13
+ else
14
+ node.children.each do |u|
15
+ loc = get_node_location(u)
16
+ locals.push Solargraph::Pin::Parameter.new(
17
+ location: loc,
18
+ closure: callable,
19
+ comments: comments_for(node),
20
+ name: u.children[0].to_s,
21
+ assignment: u.children[1],
22
+ asgn_code: u.children[1] ? region.code_for(u.children[1]) : nil,
23
+ presence: callable.location.range,
24
+ decl: get_decl(u)
25
+ )
26
+ callable.parameters.push locals.last
27
+ end
25
28
  end
26
29
  end
27
30
  process_children
@@ -29,16 +32,17 @@ module Solargraph
29
32
 
30
33
  private
31
34
 
35
+ # @param callable [Pin::Callable]
32
36
  # @return [void]
33
- def forward
37
+ def forward(callable)
34
38
  loc = get_node_location(node)
35
39
  locals.push Solargraph::Pin::Parameter.new(
36
40
  location: loc,
37
- closure: region.closure,
41
+ closure: callable,
38
42
  presence: region.closure.location.range,
39
43
  decl: get_decl(node)
40
44
  )
41
- region.closure.parameters.push locals.last
45
+ callable.parameters.push locals.last
42
46
  end
43
47
 
44
48
  # @param node [AST::Node]
@@ -8,8 +8,8 @@ module Solargraph
8
8
  include ParserGem::NodeMethods
9
9
 
10
10
  def process
11
- here = get_node_start_position(node)
12
- presence = Range.new(here, region.closure.location.range.ending)
11
+ # variable not visible until next statement
12
+ presence = Range.new(get_node_end_position(node), region.closure.location.range.ending)
13
13
  loc = get_node_location(node)
14
14
  locals.push Solargraph::Pin::LocalVariable.new(
15
15
  location: loc,
@@ -0,0 +1,53 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Solargraph
4
+ module Parser
5
+ module ParserGem
6
+ module NodeProcessors
7
+ class MasgnNode < Parser::NodeProcessor::Base
8
+ include ParserGem::NodeMethods
9
+
10
+ def process
11
+ # Example:
12
+ #
13
+ # s(:masgn,
14
+ # s(:mlhs,
15
+ # s(:send,
16
+ # s(:send, nil, :a), :b=),
17
+ # s(:lvasgn, :b),
18
+ # s(:ivasgn, :@c)),
19
+ # s(:array,
20
+ # s(:int, 1),
21
+ # s(:int, 2),
22
+ # s(:int, 3)))
23
+ masgn = node
24
+ mlhs = masgn.children.fetch(0)
25
+ lhs_arr = mlhs.children
26
+ mass_rhs = node.children.fetch(1)
27
+
28
+ # Get pins created for the mlhs node
29
+ process_children
30
+
31
+ lhs_arr.each_with_index do |lhs, i|
32
+ location = get_node_location(lhs)
33
+ pin = if lhs.type == :lvasgn
34
+ # lvasgn is a local variable
35
+ locals.find { |l| l.location == location }
36
+ else
37
+ # e.g., ivasgn is an instance variable, etc
38
+ pins.find { |iv| iv.location == location && iv.is_a?(Pin::BaseVariable) }
39
+ end
40
+ # @todo in line below, nothing in typechecking alerts
41
+ # when a non-existant method is called on 'l'
42
+ if pin.nil?
43
+ Solargraph.logger.debug { "Could not find local for masgn= value in location #{location.inspect} in #{lhs_arr} - masgn = #{masgn}, lhs.type = #{lhs.type}" }
44
+ next
45
+ end
46
+ pin.mass_assignment = [mass_rhs, i]
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
@@ -80,7 +80,7 @@ module Solargraph
80
80
  )
81
81
  end
82
82
  if node.children[1] == :attr_writer || node.children[1] == :attr_accessor
83
- pins.push Solargraph::Pin::Method.new(
83
+ method_pin = Solargraph::Pin::Method.new(
84
84
  location: loc,
85
85
  closure: clos,
86
86
  name: "#{a.children[0]}=",
@@ -89,9 +89,10 @@ module Solargraph
89
89
  visibility: region.visibility,
90
90
  attribute: true
91
91
  )
92
- pins.last.parameters.push Pin::Parameter.new(name: 'value', decl: :arg, closure: pins.last)
93
- if pins.last.return_type.defined?
94
- pins.last.docstring.add_tag YARD::Tags::Tag.new(:param, '', pins.last.return_type.to_s.split(', '), 'value')
92
+ pins.push method_pin
93
+ method_pin.parameters.push Pin::Parameter.new(name: 'value', decl: :arg, closure: pins.last)
94
+ if method_pin.return_type.defined?
95
+ pins.last.docstring.add_tag YARD::Tags::Tag.new(:param, '', pins.last.return_type.items.map(&:rooted_tags), 'value')
95
96
  end
96
97
  end
97
98
  end
@@ -112,6 +113,7 @@ module Solargraph
112
113
  end
113
114
  end
114
115
 
116
+ # @return [void]
115
117
  def process_prepend
116
118
  if node.children[2].is_a?(AST::Node) && node.children[2].type == :const
117
119
  cp = region.closure
@@ -17,6 +17,7 @@ module Solargraph
17
17
  autoload :LvasgnNode, 'solargraph/parser/parser_gem/node_processors/lvasgn_node'
18
18
  autoload :GvasgnNode, 'solargraph/parser/parser_gem/node_processors/gvasgn_node'
19
19
  autoload :CasgnNode, 'solargraph/parser/parser_gem/node_processors/casgn_node'
20
+ autoload :MasgnNode, 'solargraph/parser/parser_gem/node_processors/masgn_node'
20
21
  autoload :AliasNode, 'solargraph/parser/parser_gem/node_processors/alias_node'
21
22
  autoload :ArgsNode, 'solargraph/parser/parser_gem/node_processors/args_node'
22
23
  autoload :BlockNode, 'solargraph/parser/parser_gem/node_processors/block_node'
@@ -43,6 +44,7 @@ module Solargraph
43
44
  register :lvasgn, ParserGem::NodeProcessors::LvasgnNode
44
45
  register :gvasgn, ParserGem::NodeProcessors::GvasgnNode
45
46
  register :casgn, ParserGem::NodeProcessors::CasgnNode
47
+ register :masgn, ParserGem::NodeProcessors::MasgnNode
46
48
  register :alias, ParserGem::NodeProcessors::AliasNode
47
49
  register :args, ParserGem::NodeProcessors::ArgsNode
48
50
  register :forward_args, ParserGem::NodeProcessors::ArgsNode
@@ -9,15 +9,12 @@ module Solargraph
9
9
  class SyntaxError < StandardError
10
10
  end
11
11
 
12
- def self.rubyvm?
13
- false
14
- end
15
-
16
12
  # @deprecated
17
13
  Legacy = ParserGem
18
14
 
19
15
  ClassMethods = ParserGem::ClassMethods
20
-
16
+ # @todo should be able to just 'extend ClassMethods' here and
17
+ # typecheck things off it in strict mode
21
18
  extend ParserGem::ClassMethods
22
19
 
23
20
  NodeMethods = ParserGem::NodeMethods
@@ -15,6 +15,9 @@ module Solargraph
15
15
  # @return [Solargraph::Location]
16
16
  attr_reader :location
17
17
 
18
+ # @return [Solargraph::Location]
19
+ attr_reader :type_location
20
+
18
21
  # @return [String]
19
22
  attr_reader :name
20
23
 
@@ -25,11 +28,13 @@ module Solargraph
25
28
  attr_accessor :source
26
29
 
27
30
  # @param location [Solargraph::Location, nil]
31
+ # @param type_location [Solargraph::Location, nil]
28
32
  # @param closure [Solargraph::Pin::Closure, nil]
29
33
  # @param name [String]
30
34
  # @param comments [String]
31
- def initialize location: nil, closure: nil, name: '', comments: ''
35
+ def initialize location: nil, type_location: nil, closure: nil, name: '', comments: ''
32
36
  @location = location
37
+ @type_location = type_location
33
38
  @closure = closure
34
39
  @name = name
35
40
  @comments = comments
@@ -70,6 +75,10 @@ module Solargraph
70
75
  transformed.erase_generics(definitions.generics)
71
76
  end
72
77
 
78
+ def all_rooted?
79
+ !return_type || return_type.all_rooted?
80
+ end
81
+
73
82
  # @param generics_to_erase [Enumerable<String>]
74
83
  # @return [self]
75
84
  def erase_generics(generics_to_erase)
@@ -102,6 +111,11 @@ module Solargraph
102
111
  false
103
112
  end
104
113
 
114
+ # @return [Location, nil]
115
+ def best_location
116
+ location || type_location
117
+ end
118
+
105
119
  # Pin equality is determined using the #nearly? method and also
106
120
  # requiring both pins to have the same location.
107
121
  #
@@ -9,10 +9,14 @@ module Solargraph
9
9
  # @return [Parser::AST::Node, nil]
10
10
  attr_reader :assignment
11
11
 
12
+ attr_accessor :mass_assignment
13
+
12
14
  # @param assignment [Parser::AST::Node, nil]
13
15
  def initialize assignment: nil, **splat
14
16
  super(**splat)
15
17
  @assignment = assignment
18
+ # @type [nil, ::Array(Parser::AST::Node, Integer)]
19
+ @mass_assignment = nil
16
20
  end
17
21
 
18
22
  def completion_item_kind
@@ -36,10 +40,12 @@ module Solargraph
36
40
  true
37
41
  end
38
42
 
39
- def probe api_map
40
- return ComplexType::UNDEFINED if @assignment.nil?
43
+ # @param parent_node [Parser::AST::Node]
44
+ # @param api_map [ApiMap]
45
+ # @return [::Array<ComplexType>]
46
+ def return_types_from_node(parent_node, api_map)
41
47
  types = []
42
- value_position_nodes_only(@assignment).each do |node|
48
+ value_position_nodes_only(parent_node).each do |node|
43
49
  # Nil nodes may not have a location
44
50
  if node.nil? || node.type == :NIL || node.type == :nil
45
51
  types.push ComplexType::NIL
@@ -51,12 +57,35 @@ module Solargraph
51
57
  # Use the return node for inference. The clip might infer from the
52
58
  # first node in a method call instead of the entire call.
53
59
  chain = Parser.chain(node, nil, nil)
54
- result = chain.infer(api_map, closure, clip.locals).self_to(closure.context.tag)
60
+ result = chain.infer(api_map, closure, clip.locals).self_to_type(closure.context)
55
61
  types.push result unless result.undefined?
56
62
  end
57
63
  end
58
- return ComplexType::UNDEFINED if types.empty?
59
- ComplexType.try_parse(*types.map(&:to_s))
64
+ types
65
+ end
66
+
67
+ # @param api_map [ApiMap]
68
+ # @return [ComplexType]
69
+ def probe api_map
70
+ unless @assignment.nil?
71
+ types = return_types_from_node(@assignment, api_map)
72
+ return ComplexType.new(types.uniq) unless types.empty?
73
+ end
74
+
75
+ unless @mass_assignment.nil?
76
+ mass_node, index = @mass_assignment
77
+ types = return_types_from_node(mass_node, api_map)
78
+ types.map! do |type|
79
+ if type.tuple?
80
+ type.all_params[index]
81
+ elsif ['::Array', '::Set', '::Enumerable'].include?(type.rooted_name)
82
+ type.all_params.first
83
+ end
84
+ end.compact!
85
+ return ComplexType.new(types.uniq) unless types.empty?
86
+ end
87
+
88
+ ComplexType::UNDEFINED
60
89
  end
61
90
 
62
91
  def == other
@@ -2,7 +2,7 @@
2
2
 
3
3
  module Solargraph
4
4
  module Pin
5
- class Block < Closure
5
+ class Block < Callable
6
6
  # @return [Parser::AST::Node]
7
7
  attr_reader :receiver
8
8
 
@@ -14,10 +14,10 @@ module Solargraph
14
14
  # @param context [ComplexType, nil]
15
15
  # @param args [::Array<Parameter>]
16
16
  def initialize receiver: nil, args: [], context: nil, node: nil, **splat
17
- super(**splat)
17
+ super(**splat, parameters: args)
18
18
  @receiver = receiver
19
19
  @context = context
20
- @parameters = args
20
+ @return_type = ComplexType.parse('::Proc')
21
21
  @node = node
22
22
  end
23
23
 
@@ -31,14 +31,51 @@ module Solargraph
31
31
  @rebind&.defined? ? @rebind : closure.binder
32
32
  end
33
33
 
34
- # @return [::Array<Parameter>]
35
- def parameters
36
- @parameters ||= []
34
+ # @param yield_types [::Array<ComplexType>]
35
+ # @param parameters [::Array<Parameter>]
36
+ #
37
+ # @return [::Array<ComplexType>]
38
+ def destructure_yield_types(yield_types, parameters)
39
+ return yield_types if yield_types.length == parameters.length
40
+
41
+ # yielding a tuple into a block will destructure the tuple
42
+ if yield_types.length == 1
43
+ yield_type = yield_types.first
44
+ return yield_type.all_params if yield_type.tuple? && yield_type.all_params.length == parameters.length
45
+ end
46
+ parameters.map { ComplexType::UNDEFINED }
37
47
  end
38
48
 
39
- # @return [::Array<String>]
40
- def parameter_names
41
- @parameter_names ||= parameters.map(&:name)
49
+ # @param api_map [ApiMap]
50
+ # @return [::Array<ComplexType>]
51
+ def typify_parameters(api_map)
52
+ chain = Parser.chain(receiver, filename, node)
53
+ clip = api_map.clip_at(location.filename, location.range.start)
54
+ locals = clip.locals - [self]
55
+ meths = chain.define(api_map, closure, locals)
56
+ # @todo Convert logic to use signatures
57
+ meths.each do |meth|
58
+ next if meth.block.nil?
59
+
60
+ yield_types = meth.block.parameters.map(&:return_type)
61
+ # 'arguments' is what the method says it will yield to the
62
+ # block; 'parameters' is what the block accepts
63
+ argument_types = destructure_yield_types(yield_types, parameters)
64
+ param_types = argument_types.each_with_index.map do |arg_type, idx|
65
+ param = parameters[idx]
66
+ param_type = chain.base.infer(api_map, param, locals)
67
+ unless arg_type.nil?
68
+ if arg_type.generic? && param_type.defined?
69
+ namespace_pin = api_map.get_namespace_pins(meth.namespace, closure.namespace).first
70
+ arg_type.resolve_generics(namespace_pin, param_type)
71
+ else
72
+ arg_type.self_to_type(chain.base.infer(api_map, self, locals)).qualify(api_map, meth.context.namespace)
73
+ end
74
+ end
75
+ end
76
+ return param_types if param_types.all?(&:defined?)
77
+ end
78
+ parameters.map { ComplexType::UNDEFINED }
42
79
  end
43
80
 
44
81
  private
@@ -50,7 +87,7 @@ module Solargraph
50
87
 
51
88
  chain = Parser.chain(receiver, location.filename)
52
89
  locals = api_map.source_map(location.filename).locals_at(location)
53
- receiver_pin = chain.define(api_map, self, locals).first
90
+ receiver_pin = chain.define(api_map, closure, locals).first
54
91
  return ComplexType::UNDEFINED unless receiver_pin
55
92
 
56
93
  types = receiver_pin.docstring.tag(:yieldreceiver)&.types
@@ -59,7 +96,7 @@ module Solargraph
59
96
  target = chain.base.infer(api_map, receiver_pin, locals)
60
97
  target = full_context unless target.defined?
61
98
 
62
- ComplexType.try_parse(*types).qualify(api_map, receiver_pin.context.namespace).self_to(target.to_s)
99
+ ComplexType.try_parse(*types).qualify(api_map, receiver_pin.context.namespace).self_to_type(target)
63
100
  end
64
101
  end
65
102
  end
@@ -0,0 +1,147 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Solargraph
4
+ module Pin
5
+ class Callable < Closure
6
+ # @return [self]
7
+ attr_reader :block
8
+
9
+ attr_reader :parameters
10
+
11
+ # @return [ComplexType, nil]
12
+ attr_reader :return_type
13
+
14
+ # @param block [Signature, nil]
15
+ # @param return_type [ComplexType, nil]
16
+ # @param parameters [::Array<Pin::Parameter>]
17
+ def initialize block: nil, return_type: nil, parameters: [], **splat
18
+ super(**splat)
19
+ @block = block
20
+ @return_type = return_type
21
+ @parameters = parameters
22
+ end
23
+
24
+ # @return [::Array<String>]
25
+ def parameter_names
26
+ @parameter_names ||= parameters.map(&:name)
27
+ end
28
+
29
+ # @param generics_to_resolve [Enumerable<String>]
30
+ # @param arg_types [Array<ComplexType>, nil]
31
+ # @param return_type_context [ComplexType, nil]
32
+ # @param yield_arg_types [Array<ComplexType>, nil]
33
+ # @param yield_return_type_context [ComplexType, nil]
34
+ # @param context [ComplexType, nil]
35
+ # @param resolved_generic_values [Hash{String => ComplexType}]
36
+ # @return [self]
37
+ def resolve_generics_from_context(generics_to_resolve,
38
+ arg_types = nil,
39
+ return_type_context = nil,
40
+ yield_arg_types = nil,
41
+ yield_return_type_context = nil,
42
+ resolved_generic_values: {})
43
+ callable = super(generics_to_resolve, return_type_context, resolved_generic_values: resolved_generic_values)
44
+ callable.parameters = callable.parameters.each_with_index.map do |param, i|
45
+ if arg_types.nil?
46
+ param.dup
47
+ else
48
+ param.resolve_generics_from_context(generics_to_resolve,
49
+ arg_types[i],
50
+ resolved_generic_values: resolved_generic_values)
51
+ end
52
+ end
53
+ callable.block = block.resolve_generics_from_context(generics_to_resolve,
54
+ yield_arg_types,
55
+ yield_return_type_context,
56
+ resolved_generic_values: resolved_generic_values) if callable.block?
57
+ callable
58
+ end
59
+
60
+ # @param generics_to_resolve [Enumerable<String>]
61
+ # @param arg_types [Array<ComplexType>, nil]
62
+ # @param return_type_context [ComplexType, nil]
63
+ # @param yield_arg_types [Array<ComplexType>, nil]
64
+ # @param yield_return_type_context [ComplexType, nil]
65
+ # @param context [ComplexType, nil]
66
+ # @param resolved_generic_values [Hash{String => ComplexType}]
67
+ # @return [self]
68
+ def resolve_generics_from_context_until_complete(generics_to_resolve,
69
+ arg_types = nil,
70
+ return_type_context = nil,
71
+ yield_arg_types = nil,
72
+ yield_return_type_context = nil,
73
+ resolved_generic_values: {})
74
+ # See
75
+ # https://github.com/soutaro/steep/tree/master/lib/steep/type_inference
76
+ # and
77
+ # https://github.com/sorbet/sorbet/blob/master/infer/inference.cc
78
+ # for other implementations
79
+
80
+ return self if generics_to_resolve.empty?
81
+
82
+ last_resolved_generic_values = resolved_generic_values.dup
83
+ new_pin = resolve_generics_from_context(generics_to_resolve,
84
+ arg_types,
85
+ return_type_context,
86
+ yield_arg_types,
87
+ yield_return_type_context,
88
+ resolved_generic_values: resolved_generic_values)
89
+ if last_resolved_generic_values == resolved_generic_values
90
+ # erase anything unresolved
91
+ return new_pin.erase_generics(self.generics)
92
+ end
93
+ new_pin.resolve_generics_from_context_until_complete(generics_to_resolve,
94
+ arg_types,
95
+ return_type_context,
96
+ yield_arg_types,
97
+ yield_return_type_context,
98
+ resolved_generic_values: resolved_generic_values)
99
+ end
100
+
101
+ # @return [Array<String>]
102
+ # @yieldparam [ComplexType]
103
+ # @yieldreturn [ComplexType]
104
+ # @return [self]
105
+ def transform_types(&transform)
106
+ # @todo 'super' alone should work here I think, but doesn't typecheck at level typed
107
+ callable = super(&transform)
108
+ callable.block = block.transform_types(&transform) if block?
109
+ callable.parameters = parameters.map do |param|
110
+ param.transform_types(&transform)
111
+ end
112
+ callable
113
+ end
114
+
115
+ # @param arguments [::Array<Chain>]
116
+ # @param signature [Pin::Signature]
117
+ # @return [Boolean]
118
+ def arity_matches? arguments, with_block
119
+ argcount = arguments.length
120
+ parcount = mandatory_positional_param_count
121
+ parcount -= 1 if !parameters.empty? && parameters.last.block?
122
+ return false if block? && !with_block
123
+ return false if argcount < parcount && !(argcount == parcount - 1 && parameters.last.restarg?)
124
+ true
125
+ end
126
+
127
+ def mandatory_positional_param_count
128
+ parameters.count(&:arg?)
129
+ end
130
+
131
+ # @return [String]
132
+ def to_rbs
133
+ rbs_generics + '(' + parameters.map { |param| param.to_rbs }.join(', ') + ') ' + (block.nil? ? '' : '{ ' + block.to_rbs + ' } ') + '-> ' + return_type.to_rbs
134
+ end
135
+
136
+ def block?
137
+ !!@block
138
+ end
139
+
140
+ protected
141
+
142
+ attr_writer :block
143
+
144
+ attr_writer :parameters
145
+ end
146
+ end
147
+ end
@@ -18,7 +18,7 @@ module Solargraph
18
18
  @context ||= begin
19
19
  result = super
20
20
  if scope == :instance
21
- Solargraph::ComplexType.parse(result.namespace)
21
+ result.reduce_class_type
22
22
  else
23
23
  result
24
24
  end
@@ -42,10 +42,15 @@ module Solargraph
42
42
  end
43
43
 
44
44
  # @return [String]
45
- def generics_as_rbs
45
+ def to_rbs
46
+ rbs_generics + return_type.to_rbs
47
+ end
48
+
49
+ # @return [String]
50
+ def rbs_generics
46
51
  return '' if generics.empty?
47
52
 
48
- generics.join(', ') + ' '
53
+ '[' + generics.map { |gen| gen.to_s }.join(', ') + '] '
49
54
  end
50
55
  end
51
56
  end
@@ -19,7 +19,7 @@ module Solargraph
19
19
  @return_type ||= ComplexType::UNDEFINED
20
20
  end
21
21
 
22
- # @return [ComplexType, Array<UniqueType>]
22
+ # @return [ComplexType]
23
23
  def context
24
24
  # Get the static context from the nearest namespace
25
25
  @context ||= find_context
@@ -59,11 +59,7 @@ module Solargraph
59
59
  if here.is_a?(Pin::Namespace)
60
60
  return here.return_type
61
61
  elsif here.is_a?(Pin::Method)
62
- if here.scope == :instance
63
- return ComplexType.try_parse(here.context.tag)
64
- else
65
- return here.context
66
- end
62
+ return here.context
67
63
  end
68
64
  here = here.closure
69
65
  end
@@ -87,7 +87,7 @@ module Solargraph
87
87
 
88
88
  # @return [String, nil]
89
89
  def text_documentation
90
- this_path = path || return_type.tag
90
+ this_path = path || name || return_type.tag
91
91
  return nil if this_path == 'undefined'
92
92
  escape_brackets this_path
93
93
  end
@@ -105,9 +105,10 @@ module Solargraph
105
105
 
106
106
  # @return [String, nil]
107
107
  def generate_link
108
- this_path = path || return_type.tag
108
+ this_path = path || name || return_type.tag
109
109
  return nil if this_path == 'undefined'
110
110
  return nil if this_path.nil? || this_path == 'undefined'
111
+ return this_path if path.nil?
111
112
  "[#{escape_brackets(this_path).gsub('_', '\\\\_')}](solargraph:/document?query=#{CGI.escape(this_path)})"
112
113
  end
113
114
 
@@ -11,8 +11,9 @@ module Solargraph
11
11
  # given closure/scope, and the delegated method will then be resolved
12
12
  # to a method pin on that type.
13
13
  #
14
- # @param resolved_method [Method] an already resolved method pin.
14
+ # @param method [Method, nil] an already resolved method pin.
15
15
  # @param receiver [Source::Chain, nil] the source code used to resolve the receiver for this delegated method.
16
+ # @param name [String]
16
17
  # @param receiver_method_name [String] the method name that will be called on the receiver (defaults to :name).
17
18
  def initialize(method: nil, receiver: nil, name: method&.name, receiver_method_name: name, **splat)
18
19
  raise ArgumentError, 'either :method or :receiver is required' if (method && receiver) || (!method && !receiver)
@@ -37,6 +38,7 @@ module Solargraph
37
38
  end
38
39
  end
39
40
 
41
+ # @param api_map [ApiMap]
40
42
  def resolvable?(api_map)
41
43
  resolve_method(api_map)
42
44
  !!@resolved_method
@@ -79,6 +81,7 @@ module Solargraph
79
81
  # helper to print a source chain as code, probably not 100% correct.
80
82
  #
81
83
  # @param chain [Source::Chain]
84
+ # @return [String]
82
85
  def print_chain(chain)
83
86
  out = +''
84
87
  chain.links.each_with_index do |link, index|
@@ -91,6 +94,7 @@ module Solargraph
91
94
  end
92
95
  out << link.word
93
96
  end
97
+ out
94
98
  end
95
99
  end
96
100
  end
@@ -76,6 +76,8 @@ module Solargraph
76
76
  end
77
77
  end
78
78
 
79
+ # @param text [String]
80
+ # @return [String]
79
81
  def self.strip_html_comments text
80
82
  text.gsub(/<!--([\s\S]*?)-->/, '').strip
81
83
  end