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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +41 -0
- data/lib/solargraph/api_map/cache.rb +2 -12
- data/lib/solargraph/api_map/store.rb +14 -5
- data/lib/solargraph/api_map.rb +67 -24
- data/lib/solargraph/complex_type/type_methods.rb +70 -39
- data/lib/solargraph/complex_type/unique_type.rb +187 -73
- data/lib/solargraph/complex_type.rb +105 -40
- data/lib/solargraph/doc_map.rb +19 -3
- data/lib/solargraph/gem_pins.rb +9 -1
- data/lib/solargraph/language_server/host/dispatch.rb +8 -1
- data/lib/solargraph/language_server/host/message_worker.rb +29 -3
- data/lib/solargraph/language_server/host/sources.rb +1 -61
- data/lib/solargraph/language_server/host.rb +21 -68
- data/lib/solargraph/language_server/message/base.rb +1 -1
- data/lib/solargraph/language_server/message/initialize.rb +14 -0
- data/lib/solargraph/language_server/message/text_document/definition.rb +3 -3
- data/lib/solargraph/language_server/message/text_document/document_symbol.rb +3 -3
- data/lib/solargraph/language_server/message/text_document/formatting.rb +1 -0
- data/lib/solargraph/language_server/message/text_document/hover.rb +1 -1
- data/lib/solargraph/language_server/message/text_document/type_definition.rb +3 -3
- data/lib/solargraph/language_server/message/workspace/workspace_symbol.rb +2 -2
- data/lib/solargraph/language_server/progress.rb +135 -0
- data/lib/solargraph/language_server.rb +1 -0
- data/lib/solargraph/library.rb +144 -113
- data/lib/solargraph/location.rb +14 -1
- data/lib/solargraph/parser/node_processor/base.rb +3 -2
- data/lib/solargraph/parser/node_processor.rb +1 -0
- data/lib/solargraph/parser/parser_gem/class_methods.rb +3 -7
- data/lib/solargraph/parser/parser_gem/node_chainer.rb +13 -7
- data/lib/solargraph/parser/parser_gem/node_methods.rb +1 -5
- data/lib/solargraph/parser/parser_gem/node_processors/args_node.rb +23 -19
- data/lib/solargraph/parser/parser_gem/node_processors/lvasgn_node.rb +2 -2
- data/lib/solargraph/parser/parser_gem/node_processors/masgn_node.rb +53 -0
- data/lib/solargraph/parser/parser_gem/node_processors/send_node.rb +6 -4
- data/lib/solargraph/parser/parser_gem/node_processors.rb +2 -0
- data/lib/solargraph/parser.rb +2 -5
- data/lib/solargraph/pin/base.rb +15 -1
- data/lib/solargraph/pin/base_variable.rb +35 -6
- data/lib/solargraph/pin/block.rb +48 -11
- data/lib/solargraph/pin/callable.rb +147 -0
- data/lib/solargraph/pin/closure.rb +8 -3
- data/lib/solargraph/pin/common.rb +2 -6
- data/lib/solargraph/pin/conversions.rb +3 -2
- data/lib/solargraph/pin/delegated_method.rb +5 -1
- data/lib/solargraph/pin/documenting.rb +2 -0
- data/lib/solargraph/pin/instance_variable.rb +2 -2
- data/lib/solargraph/pin/method.rb +54 -32
- data/lib/solargraph/pin/namespace.rb +4 -4
- data/lib/solargraph/pin/parameter.rb +14 -39
- data/lib/solargraph/pin/proxy_type.rb +1 -1
- data/lib/solargraph/pin/signature.rb +3 -129
- data/lib/solargraph/pin.rb +4 -1
- data/lib/solargraph/range.rb +2 -4
- data/lib/solargraph/rbs_map/conversions.rb +79 -42
- data/lib/solargraph/rbs_map/core_fills.rb +6 -6
- data/lib/solargraph/rbs_map.rb +11 -3
- data/lib/solargraph/shell.rb +35 -15
- data/lib/solargraph/source/chain/array.rb +6 -5
- data/lib/solargraph/source/chain/block_symbol.rb +1 -1
- data/lib/solargraph/source/chain/block_variable.rb +1 -1
- data/lib/solargraph/source/chain/call.rb +78 -50
- data/lib/solargraph/source/chain/link.rb +9 -0
- data/lib/solargraph/source/chain/or.rb +1 -1
- data/lib/solargraph/source/chain.rb +60 -16
- data/lib/solargraph/source/cursor.rb +13 -2
- data/lib/solargraph/source/updater.rb +1 -0
- data/lib/solargraph/source.rb +102 -129
- data/lib/solargraph/source_map/clip.rb +4 -4
- data/lib/solargraph/source_map/data.rb +30 -0
- data/lib/solargraph/source_map/mapper.rb +3 -2
- data/lib/solargraph/source_map.rb +37 -15
- data/lib/solargraph/type_checker/rules.rb +6 -1
- data/lib/solargraph/type_checker.rb +50 -25
- data/lib/solargraph/version.rb +1 -1
- data/lib/solargraph/views/environment.erb +3 -5
- data/lib/solargraph/workspace/config.rb +2 -1
- data/lib/solargraph/workspace.rb +13 -0
- metadata +6 -3
- 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
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
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:
|
41
|
+
closure: callable,
|
38
42
|
presence: region.closure.location.range,
|
39
43
|
decl: get_decl(node)
|
40
44
|
)
|
41
|
-
|
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
|
-
|
12
|
-
presence = Range.new(
|
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
|
-
|
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.
|
93
|
-
|
94
|
-
|
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
|
data/lib/solargraph/parser.rb
CHANGED
@@ -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
|
data/lib/solargraph/pin/base.rb
CHANGED
@@ -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
|
-
|
40
|
-
|
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(
|
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).
|
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
|
-
|
59
|
-
|
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
|
data/lib/solargraph/pin/block.rb
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
module Solargraph
|
4
4
|
module Pin
|
5
|
-
class Block <
|
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
|
-
@
|
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
|
-
# @
|
35
|
-
|
36
|
-
|
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
|
-
# @
|
40
|
-
|
41
|
-
|
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,
|
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).
|
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
|
-
|
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
|
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
|
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
|
-
|
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
|
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
|