solargraph 0.54.0 → 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 +19 -0
- data/lib/solargraph/api_map/store.rb +6 -2
- data/lib/solargraph/api_map.rb +15 -8
- data/lib/solargraph/complex_type/type_methods.rb +10 -11
- data/lib/solargraph/complex_type/unique_type.rb +72 -9
- data/lib/solargraph/complex_type.rb +66 -17
- data/lib/solargraph/language_server/host/message_worker.rb +29 -3
- 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/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 +19 -2
- data/lib/solargraph/library.rb +30 -39
- data/lib/solargraph/location.rb +14 -1
- data/lib/solargraph/parser/parser_gem/node_chainer.rb +13 -7
- data/lib/solargraph/parser/parser_gem/node_methods.rb +1 -1
- 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 +8 -2
- data/lib/solargraph/parser/parser_gem/node_processors/send_node.rb +1 -1
- data/lib/solargraph/parser.rb +2 -5
- data/lib/solargraph/pin/base.rb +15 -1
- data/lib/solargraph/pin/base_variable.rb +1 -1
- data/lib/solargraph/pin/block.rb +5 -23
- 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/instance_variable.rb +2 -2
- data/lib/solargraph/pin/method.rb +51 -31
- data/lib/solargraph/pin/namespace.rb +4 -4
- data/lib/solargraph/pin/parameter.rb +9 -11
- 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 +70 -37
- data/lib/solargraph/rbs_map/core_fills.rb +6 -6
- data/lib/solargraph/shell.rb +17 -2
- 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 +41 -17
- data/lib/solargraph/source/cursor.rb +13 -2
- data/lib/solargraph/source.rb +102 -85
- data/lib/solargraph/source_map/clip.rb +4 -4
- data/lib/solargraph/source_map/data.rb +30 -0
- data/lib/solargraph/source_map.rb +28 -16
- data/lib/solargraph/type_checker/rules.rb +6 -1
- data/lib/solargraph/type_checker.rb +7 -7
- data/lib/solargraph/version.rb +1 -1
- data/lib/solargraph/views/environment.erb +3 -5
- metadata +4 -2
data/lib/solargraph/library.rb
CHANGED
@@ -27,11 +27,11 @@ module Solargraph
|
|
27
27
|
def initialize workspace = Solargraph::Workspace.new, name = nil
|
28
28
|
@workspace = workspace
|
29
29
|
@name = name
|
30
|
-
@threads = []
|
31
30
|
# @type [Integer, nil]
|
32
31
|
@total = nil
|
33
32
|
# @type [Source, nil]
|
34
33
|
@current = nil
|
34
|
+
@sync_count = 0
|
35
35
|
end
|
36
36
|
|
37
37
|
def inspect
|
@@ -44,7 +44,7 @@ module Solargraph
|
|
44
44
|
#
|
45
45
|
# @return [Boolean]
|
46
46
|
def synchronized?
|
47
|
-
|
47
|
+
@sync_count < 2
|
48
48
|
end
|
49
49
|
|
50
50
|
# Attach a source to the library.
|
@@ -174,9 +174,9 @@ module Solargraph
|
|
174
174
|
# @return [Array<Solargraph::Pin::Base>, nil]
|
175
175
|
# @todo Take filename/position instead of filename/line/column
|
176
176
|
def definitions_at filename, line, column
|
177
|
+
sync_catalog
|
177
178
|
position = Position.new(line, column)
|
178
179
|
cursor = Source::Cursor.new(read(filename), position)
|
179
|
-
sync_catalog
|
180
180
|
if cursor.comment?
|
181
181
|
source = read(filename)
|
182
182
|
offset = Solargraph::Position.to_offset(source.code, Solargraph::Position.new(line, column))
|
@@ -190,7 +190,14 @@ module Solargraph
|
|
190
190
|
[]
|
191
191
|
end
|
192
192
|
else
|
193
|
-
mutex.synchronize
|
193
|
+
mutex.synchronize do
|
194
|
+
clip = api_map.clip(cursor)
|
195
|
+
if cursor.assign?
|
196
|
+
[Pin::ProxyType.new(name: cursor.word, return_type: clip.infer)]
|
197
|
+
else
|
198
|
+
clip.define.map { |pin| pin.realize(api_map) }
|
199
|
+
end
|
200
|
+
end
|
194
201
|
end
|
195
202
|
rescue FileNotFoundError => e
|
196
203
|
handle_file_not_found(filename, e)
|
@@ -205,9 +212,9 @@ module Solargraph
|
|
205
212
|
# @return [Array<Solargraph::Pin::Base>, nil]
|
206
213
|
# @todo Take filename/position instead of filename/line/column
|
207
214
|
def type_definitions_at filename, line, column
|
215
|
+
sync_catalog
|
208
216
|
position = Position.new(line, column)
|
209
217
|
cursor = Source::Cursor.new(read(filename), position)
|
210
|
-
sync_catalog
|
211
218
|
mutex.synchronize { api_map.clip(cursor).types }
|
212
219
|
rescue FileNotFoundError => e
|
213
220
|
handle_file_not_found filename, e
|
@@ -222,9 +229,9 @@ module Solargraph
|
|
222
229
|
# @return [Array<Solargraph::Pin::Base>]
|
223
230
|
# @todo Take filename/position instead of filename/line/column
|
224
231
|
def signatures_at filename, line, column
|
232
|
+
sync_catalog
|
225
233
|
position = Position.new(line, column)
|
226
234
|
cursor = Source::Cursor.new(read(filename), position)
|
227
|
-
sync_catalog
|
228
235
|
mutex.synchronize { api_map.clip(cursor).signify }
|
229
236
|
end
|
230
237
|
|
@@ -416,20 +423,7 @@ module Solargraph
|
|
416
423
|
#
|
417
424
|
# @return [void]
|
418
425
|
def catalog
|
419
|
-
@
|
420
|
-
@threads.push(Thread.new do
|
421
|
-
sleep 0.05 if RUBY_PLATFORM =~ /mingw/
|
422
|
-
next unless @threads.last == Thread.current
|
423
|
-
|
424
|
-
mutex.synchronize do
|
425
|
-
logger.info "Cataloging #{workspace.directory.empty? ? 'generic workspace' : workspace.directory}"
|
426
|
-
api_map.catalog bench
|
427
|
-
logger.info "Catalog complete (#{api_map.source_maps.length} files, #{api_map.pins.length} pins)"
|
428
|
-
logger.info "#{api_map.uncached_gemspecs.length} uncached gemspecs"
|
429
|
-
cache_next_gemspec
|
430
|
-
end
|
431
|
-
end)
|
432
|
-
@threads.last.run if RUBY_PLATFORM =~ /mingw/
|
426
|
+
@sync_count += 1
|
433
427
|
end
|
434
428
|
|
435
429
|
# @return [Bench]
|
@@ -467,7 +461,6 @@ module Solargraph
|
|
467
461
|
# @param source [Source]
|
468
462
|
# @return [Boolean] True if the source was merged into the workspace.
|
469
463
|
def merge source
|
470
|
-
Logging.logger.debug "Merging source: #{source.filename}"
|
471
464
|
result = workspace.merge(source)
|
472
465
|
maybe_map source
|
473
466
|
result
|
@@ -489,7 +482,6 @@ module Solargraph
|
|
489
482
|
if src
|
490
483
|
Logging.logger.debug "Mapping #{src.filename}"
|
491
484
|
source_map_hash[src.filename] = Solargraph::SourceMap.map(src)
|
492
|
-
find_external_requires(source_map_hash[src.filename])
|
493
485
|
source_map_hash[src.filename]
|
494
486
|
else
|
495
487
|
false
|
@@ -500,7 +492,7 @@ module Solargraph
|
|
500
492
|
def map!
|
501
493
|
workspace.sources.each do |src|
|
502
494
|
source_map_hash[src.filename] = Solargraph::SourceMap.map(src)
|
503
|
-
find_external_requires
|
495
|
+
find_external_requires source_map_hash[src.filename]
|
504
496
|
end
|
505
497
|
self
|
506
498
|
end
|
@@ -580,22 +572,10 @@ module Solargraph
|
|
580
572
|
return unless source
|
581
573
|
return unless @current == source || workspace.has_file?(source.filename)
|
582
574
|
if source_map_hash.key?(source.filename)
|
583
|
-
|
584
|
-
|
585
|
-
source.synchronized?
|
586
|
-
if source.synchronized?
|
587
|
-
new_map = Solargraph::SourceMap.map(source)
|
588
|
-
unless source_map_hash[source.filename].try_merge!(new_map)
|
589
|
-
source_map_hash[source.filename] = new_map
|
590
|
-
find_external_requires(source_map_hash[source.filename])
|
591
|
-
end
|
592
|
-
else
|
593
|
-
# @todo Smelly instance variable access
|
594
|
-
source_map_hash[source.filename].instance_variable_set(:@source, source)
|
595
|
-
end
|
575
|
+
new_map = Solargraph::SourceMap.map(source)
|
576
|
+
source_map_hash[source.filename] = new_map
|
596
577
|
else
|
597
578
|
source_map_hash[source.filename] = Solargraph::SourceMap.map(source)
|
598
|
-
find_external_requires(source_map_hash[source.filename])
|
599
579
|
end
|
600
580
|
end
|
601
581
|
|
@@ -625,6 +605,7 @@ module Solargraph
|
|
625
605
|
ensure
|
626
606
|
end_cache_progress
|
627
607
|
catalog
|
608
|
+
sync_catalog
|
628
609
|
end
|
629
610
|
end
|
630
611
|
|
@@ -666,8 +647,18 @@ module Solargraph
|
|
666
647
|
end
|
667
648
|
|
668
649
|
def sync_catalog
|
669
|
-
@
|
670
|
-
|
650
|
+
return if @sync_count == 0
|
651
|
+
|
652
|
+
mutex.synchronize do
|
653
|
+
logger.warn "CATALOG"
|
654
|
+
logger.info "Cataloging #{workspace.directory.empty? ? 'generic workspace' : workspace.directory}"
|
655
|
+
api_map.catalog bench
|
656
|
+
source_map_hash.values.each { |map| find_external_requires(map) }
|
657
|
+
logger.info "Catalog complete (#{api_map.source_maps.length} files, #{api_map.pins.length} pins)"
|
658
|
+
logger.info "#{api_map.uncached_gemspecs.length} uncached gemspecs"
|
659
|
+
cache_next_gemspec
|
660
|
+
@sync_count = 0
|
661
|
+
end
|
671
662
|
end
|
672
663
|
end
|
673
664
|
end
|
data/lib/solargraph/location.rb
CHANGED
@@ -1,7 +1,8 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module Solargraph
|
4
|
-
# A section of text identified by its filename
|
4
|
+
# A pointer to a section of source text identified by its filename
|
5
|
+
# and Range.
|
5
6
|
#
|
6
7
|
class Location
|
7
8
|
# @return [String]
|
@@ -17,6 +18,11 @@ module Solargraph
|
|
17
18
|
@range = range
|
18
19
|
end
|
19
20
|
|
21
|
+
# @param location [self]
|
22
|
+
def contain? location
|
23
|
+
range.contain?(location.range.start) && range.contain?(location.range.ending) && filename == location.filename
|
24
|
+
end
|
25
|
+
|
20
26
|
# @return [Hash]
|
21
27
|
def to_hash
|
22
28
|
{
|
@@ -25,6 +31,13 @@ module Solargraph
|
|
25
31
|
}
|
26
32
|
end
|
27
33
|
|
34
|
+
# @param node [Parser::AST::Node, nil]
|
35
|
+
def self.from_node(node)
|
36
|
+
return nil if node.nil? || node.loc.nil?
|
37
|
+
range = Range.from_node(node)
|
38
|
+
self.new(node.loc.expression.source_buffer.name, range)
|
39
|
+
end
|
40
|
+
|
28
41
|
# @param other [BasicObject]
|
29
42
|
def == other
|
30
43
|
return false unless other.is_a?(Location)
|
@@ -89,15 +89,21 @@ module Solargraph
|
|
89
89
|
elsif n.type == :const
|
90
90
|
const = unpack_name(n)
|
91
91
|
result.push Chain::Constant.new(const)
|
92
|
-
elsif [:
|
92
|
+
elsif [:lvasgn, :ivasgn, :gvasgn, :cvasgn].include?(n.type)
|
93
|
+
result.concat generate_links(n.children[1])
|
94
|
+
elsif n.type == :lvar
|
93
95
|
result.push Chain::Call.new(n.children[0].to_s)
|
94
|
-
elsif
|
95
|
-
|
96
|
-
elsif
|
97
|
-
|
98
|
-
elsif
|
99
|
-
|
96
|
+
elsif n.type == :ivar
|
97
|
+
result.push Chain::InstanceVariable.new(n.children[0].to_s)
|
98
|
+
elsif n.type == :cvar
|
99
|
+
result.push Chain::ClassVariable.new(n.children[0].to_s)
|
100
|
+
elsif n.type == :gvar
|
101
|
+
result.push Chain::GlobalVariable.new(n.children[0].to_s)
|
100
102
|
elsif n.type == :or_asgn
|
103
|
+
# @todo: Need a new Link class here that evaluates the
|
104
|
+
# existing variable type with the RHS, and generates a
|
105
|
+
# union type of the LHS alone if never nil, or minus nil +
|
106
|
+
# RHS if it is nilable.
|
101
107
|
result.concat generate_links n.children[1]
|
102
108
|
elsif [:class, :module, :def, :defs].include?(n.type)
|
103
109
|
# @todo Undefined or what?
|
@@ -311,7 +311,7 @@ module Solargraph
|
|
311
311
|
# statements in value positions.
|
312
312
|
module DeepInference
|
313
313
|
class << self
|
314
|
-
CONDITIONAL_ALL_BUT_FIRST = [:if, :unless
|
314
|
+
CONDITIONAL_ALL_BUT_FIRST = [:if, :unless]
|
315
315
|
CONDITIONAL_ALL = [:or]
|
316
316
|
ONLY_ONE_CHILD = [:return]
|
317
317
|
FIRST_TWO_CHILDREN = [:rescue]
|
@@ -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,
|
@@ -30,11 +30,17 @@ module Solargraph
|
|
30
30
|
|
31
31
|
lhs_arr.each_with_index do |lhs, i|
|
32
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
|
33
40
|
# @todo in line below, nothing in typechecking alerts
|
34
41
|
# when a non-existant method is called on 'l'
|
35
|
-
pin = locals.find { |l| l.location == location }
|
36
42
|
if pin.nil?
|
37
|
-
Solargraph.logger.debug "Could not find
|
43
|
+
Solargraph.logger.debug { "Could not find local for masgn= value in location #{location.inspect} in #{lhs_arr} - masgn = #{masgn}, lhs.type = #{lhs.type}" }
|
38
44
|
next
|
39
45
|
end
|
40
46
|
pin.mass_assignment = [mass_rhs, i]
|
@@ -92,7 +92,7 @@ module Solargraph
|
|
92
92
|
pins.push method_pin
|
93
93
|
method_pin.parameters.push Pin::Parameter.new(name: 'value', decl: :arg, closure: pins.last)
|
94
94
|
if method_pin.return_type.defined?
|
95
|
-
pins.last.docstring.add_tag YARD::Tags::Tag.new(:param, '', pins.last.return_type.
|
95
|
+
pins.last.docstring.add_tag YARD::Tags::Tag.new(:param, '', pins.last.return_type.items.map(&:rooted_tags), 'value')
|
96
96
|
end
|
97
97
|
end
|
98
98
|
end
|
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
|
#
|
@@ -57,7 +57,7 @@ module Solargraph
|
|
57
57
|
# Use the return node for inference. The clip might infer from the
|
58
58
|
# first node in a method call instead of the entire call.
|
59
59
|
chain = Parser.chain(node, nil, nil)
|
60
|
-
result = chain.infer(api_map, closure, clip.locals).
|
60
|
+
result = chain.infer(api_map, closure, clip.locals).self_to_type(closure.context)
|
61
61
|
types.push result unless result.undefined?
|
62
62
|
end
|
63
63
|
end
|
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,9 @@ 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
|
21
20
|
@return_type = ComplexType.parse('::Proc')
|
22
21
|
@node = node
|
23
22
|
end
|
@@ -32,16 +31,6 @@ module Solargraph
|
|
32
31
|
@rebind&.defined? ? @rebind : closure.binder
|
33
32
|
end
|
34
33
|
|
35
|
-
# @return [::Array<Parameter>]
|
36
|
-
def parameters
|
37
|
-
@parameters ||= []
|
38
|
-
end
|
39
|
-
|
40
|
-
# @return [::Array<String>]
|
41
|
-
def parameter_names
|
42
|
-
@parameter_names ||= parameters.map(&:name)
|
43
|
-
end
|
44
|
-
|
45
34
|
# @param yield_types [::Array<ComplexType>]
|
46
35
|
# @param parameters [::Array<Parameter>]
|
47
36
|
#
|
@@ -57,13 +46,6 @@ module Solargraph
|
|
57
46
|
parameters.map { ComplexType::UNDEFINED }
|
58
47
|
end
|
59
48
|
|
60
|
-
# @todo the next step with parameters, arguments, destructuring,
|
61
|
-
# kwargs, etc logic is probably either creating a Parameters
|
62
|
-
# or Callable pin that encapsulates and shares the logic
|
63
|
-
# between methods, blocks and signatures. It could live in
|
64
|
-
# Signature if Method didn't also own potentially different
|
65
|
-
# set of parameters, generics and return types.
|
66
|
-
|
67
49
|
# @param api_map [ApiMap]
|
68
50
|
# @return [::Array<ComplexType>]
|
69
51
|
def typify_parameters(api_map)
|
@@ -87,7 +69,7 @@ module Solargraph
|
|
87
69
|
namespace_pin = api_map.get_namespace_pins(meth.namespace, closure.namespace).first
|
88
70
|
arg_type.resolve_generics(namespace_pin, param_type)
|
89
71
|
else
|
90
|
-
arg_type.
|
72
|
+
arg_type.self_to_type(chain.base.infer(api_map, self, locals)).qualify(api_map, meth.context.namespace)
|
91
73
|
end
|
92
74
|
end
|
93
75
|
end
|
@@ -105,7 +87,7 @@ module Solargraph
|
|
105
87
|
|
106
88
|
chain = Parser.chain(receiver, location.filename)
|
107
89
|
locals = api_map.source_map(location.filename).locals_at(location)
|
108
|
-
receiver_pin = chain.define(api_map,
|
90
|
+
receiver_pin = chain.define(api_map, closure, locals).first
|
109
91
|
return ComplexType::UNDEFINED unless receiver_pin
|
110
92
|
|
111
93
|
types = receiver_pin.docstring.tag(:yieldreceiver)&.types
|
@@ -114,7 +96,7 @@ module Solargraph
|
|
114
96
|
target = chain.base.infer(api_map, receiver_pin, locals)
|
115
97
|
target = full_context unless target.defined?
|
116
98
|
|
117
|
-
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)
|
118
100
|
end
|
119
101
|
end
|
120
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
|