solargraph 0.53.4 → 0.54.0
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 +22 -0
- data/lib/solargraph/api_map/cache.rb +2 -12
- data/lib/solargraph/api_map/store.rb +11 -6
- data/lib/solargraph/api_map.rb +53 -17
- data/lib/solargraph/complex_type/type_methods.rb +62 -30
- data/lib/solargraph/complex_type/unique_type.rb +117 -66
- data/lib/solargraph/complex_type.rb +41 -25
- 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/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/formatting.rb +1 -0
- data/lib/solargraph/language_server/progress.rb +118 -0
- data/lib/solargraph/language_server.rb +1 -0
- data/lib/solargraph/library.rb +136 -96
- 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_methods.rb +0 -4
- data/lib/solargraph/parser/parser_gem/node_processors/masgn_node.rb +47 -0
- data/lib/solargraph/parser/parser_gem/node_processors/send_node.rb +5 -3
- data/lib/solargraph/parser/parser_gem/node_processors.rb +2 -0
- data/lib/solargraph/pin/base_variable.rb +34 -5
- data/lib/solargraph/pin/block.rb +55 -0
- data/lib/solargraph/pin/delegated_method.rb +5 -1
- data/lib/solargraph/pin/documenting.rb +2 -0
- data/lib/solargraph/pin/method.rb +3 -1
- data/lib/solargraph/pin/parameter.rb +5 -28
- data/lib/solargraph/rbs_map/conversions.rb +10 -6
- data/lib/solargraph/rbs_map.rb +11 -3
- data/lib/solargraph/shell.rb +18 -13
- data/lib/solargraph/source/chain.rb +20 -0
- data/lib/solargraph/source/updater.rb +1 -0
- data/lib/solargraph/source.rb +0 -44
- data/lib/solargraph/source_map/mapper.rb +3 -2
- data/lib/solargraph/source_map.rb +10 -0
- data/lib/solargraph/type_checker.rb +43 -18
- data/lib/solargraph/version.rb +1 -1
- data/lib/solargraph/workspace/config.rb +2 -1
- data/lib/solargraph/workspace.rb +13 -0
- metadata +4 -3
- data/lib/solargraph/language_server/host/cataloger.rb +0 -57
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 39ad27afe3afb59299f8701f9a7ea3f25a9f95379ef68e53ac0e22eb60f50e21
|
4
|
+
data.tar.gz: 1f01a9d5cdf4aec5b50c245a25b1f7d83e5d6762e5b8f65bc9ce3555654e21ed
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 788f17e92a54e782ea1dcf03cb44245df823ba33b4fe866d1afa5d06c7171b40a4e1f93c97c8b26c13b58be7478b9b07cd75d6735da65ecef21ab6a4a61dbb0e
|
7
|
+
data.tar.gz: 742f43fcdce4a592a80ebe8e3acbd020f39f569cf323621a527e626ae8c6154f7dedb32739b8b62f38e98997ed414ec30471160332ecfb4a2fe5d5052e871333
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,25 @@
|
|
1
|
+
## 0.54.0 - April 14, 2025
|
2
|
+
- Add support for simple block argument destructuring (#821)
|
3
|
+
- Benchmark the typecheck command (#852)
|
4
|
+
- Send Gem Caching Progress Notifications to LSP Clients (#855)
|
5
|
+
- [breaking] Fix more complex_type_spec.rb cases (#813)
|
6
|
+
- Mass assignment support - e.g., a, b = ['1', '2'] (#843)
|
7
|
+
- Memoize result of Chain#infer (#857)
|
8
|
+
- Ignore malformed mixins and overloads (#862)
|
9
|
+
- Drop Parser::ParserGem::ClassMethods#returns_from_node (#866)
|
10
|
+
- Refactor TypeChecker#argument_problems_for for type safety (#867)
|
11
|
+
- Specify more type behavior for variable reassignment (#863)
|
12
|
+
- One-step source synchronization (#871)
|
13
|
+
- Show cache progress in shell commands (#874)
|
14
|
+
- Fix miscellaneous scan errors (#875)
|
15
|
+
- Synchronous libraries (#876)
|
16
|
+
- Fix parsing of Set#classify method signature from RBS (#878)
|
17
|
+
- Sync Library#diagnose (#882)
|
18
|
+
- Doesn't false-alarm over splatted non-final args in typechecking (#883)
|
19
|
+
- Remove accidental inclusion of Module's methods in objects (#884)
|
20
|
+
- Remove another splat-related false alarm in strict typechecking (#889)
|
21
|
+
- Change require path `warn` to `debug` (#897)
|
22
|
+
|
1
23
|
## 0.53.4 - March 30, 2025
|
2
24
|
- [regression] Restore 'Unresolved call' typecheck for stdlib objects (#849)
|
3
25
|
- Lazy dynamic rebinding (#851)
|
@@ -78,20 +78,10 @@ module Solargraph
|
|
78
78
|
@receiver_definitions[path] = pin
|
79
79
|
end
|
80
80
|
|
81
|
-
# @param cursor [Source::Cursor]
|
82
|
-
# @return [SourceMap::Clip, nil]
|
83
|
-
def get_clip(cursor)
|
84
|
-
@clips["#{cursor.filename}|#{cursor.range.inspect}|#{cursor.node&.to_sexp}"]
|
85
|
-
end
|
86
|
-
|
87
|
-
# @param cursor [Source::Cursor]
|
88
|
-
# @param clip [SourceMap::Clip]
|
89
|
-
def set_clip(cursor, clip)
|
90
|
-
@clips["#{cursor.filename}|#{cursor.range.inspect}|#{cursor.node&.to_sexp}"] = clip
|
91
|
-
end
|
92
|
-
|
93
81
|
# @return [void]
|
94
82
|
def clear
|
83
|
+
return if empty?
|
84
|
+
|
95
85
|
all_caches.each(&:clear)
|
96
86
|
end
|
97
87
|
|
@@ -65,6 +65,10 @@ module Solargraph
|
|
65
65
|
path_pin_hash[path] || []
|
66
66
|
end
|
67
67
|
|
68
|
+
def cacheable_pins
|
69
|
+
@cacheable_pins ||= pins_by_class(Pin::Namespace) + pins_by_class(Pin::Constant) + pins_by_class(Pin::Method) + pins_by_class(Pin::Reference)
|
70
|
+
end
|
71
|
+
|
68
72
|
# @param fqns [String]
|
69
73
|
# @param scope [Symbol] :class or :instance
|
70
74
|
# @return [Enumerable<Solargraph::Pin::Base>]
|
@@ -96,7 +100,7 @@ module Solargraph
|
|
96
100
|
@namespaces ||= Set.new
|
97
101
|
end
|
98
102
|
|
99
|
-
# @return [
|
103
|
+
# @return [Array<Solargraph::Pin::Base>]
|
100
104
|
def namespace_pins
|
101
105
|
pins_by_class(Solargraph::Pin::Namespace)
|
102
106
|
end
|
@@ -140,8 +144,9 @@ module Solargraph
|
|
140
144
|
to_s
|
141
145
|
end
|
142
146
|
|
143
|
-
# @
|
144
|
-
# @
|
147
|
+
# @generic T
|
148
|
+
# @param klass [Class<T>]
|
149
|
+
# @return [Array<T>]
|
145
150
|
def pins_by_class klass
|
146
151
|
# @type [Set<Solargraph::Pin::Base>]
|
147
152
|
s = Set.new
|
@@ -165,7 +170,7 @@ module Solargraph
|
|
165
170
|
|
166
171
|
private
|
167
172
|
|
168
|
-
# @return [Hash{Array(String, String) => Array<Pin::Namespace>}]
|
173
|
+
# @return [Hash{::Array(String, String) => ::Array<Pin::Namespace>}]
|
169
174
|
def fqns_pins_map
|
170
175
|
@fqns_pins_map ||= Hash.new do |h, (base, name)|
|
171
176
|
value = namespace_children(base).select { |pin| pin.name == name && pin.is_a?(Pin::Namespace) }
|
@@ -178,7 +183,7 @@ module Solargraph
|
|
178
183
|
pins_by_class(Pin::Symbol)
|
179
184
|
end
|
180
185
|
|
181
|
-
# @return [Hash{String =>
|
186
|
+
# @return [Hash{String => Array<String>}]
|
182
187
|
def superclass_references
|
183
188
|
@superclass_references ||= {}
|
184
189
|
end
|
@@ -243,7 +248,7 @@ module Solargraph
|
|
243
248
|
def index
|
244
249
|
set = pins.to_set
|
245
250
|
@pin_class_hash = set.classify(&:class).transform_values(&:to_a)
|
246
|
-
# @type [Hash{Class =>
|
251
|
+
# @type [Hash{Class => ::Array<Solargraph::Pin::Base>}]
|
247
252
|
@pin_select_cache = {}
|
248
253
|
@namespace_map = set.classify(&:namespace)
|
249
254
|
@path_pin_hash = set.classify(&:path)
|
data/lib/solargraph/api_map.rb
CHANGED
@@ -29,6 +29,25 @@ module Solargraph
|
|
29
29
|
index pins
|
30
30
|
end
|
31
31
|
|
32
|
+
#
|
33
|
+
# This is a mutable object, which is cached in the Chain class -
|
34
|
+
# if you add any fields which change the results of calls (not
|
35
|
+
# just caches), please also change `equality_fields` below.
|
36
|
+
#
|
37
|
+
|
38
|
+
def eql?(other)
|
39
|
+
self.class == other.class &&
|
40
|
+
equality_fields == other.equality_fields
|
41
|
+
end
|
42
|
+
|
43
|
+
def ==(other)
|
44
|
+
self.eql?(other)
|
45
|
+
end
|
46
|
+
|
47
|
+
def hash
|
48
|
+
equality_fields.hash
|
49
|
+
end
|
50
|
+
|
32
51
|
# @param pins [Array<Pin::Base>]
|
33
52
|
# @return [self]
|
34
53
|
def index pins
|
@@ -56,21 +75,31 @@ module Solargraph
|
|
56
75
|
# @param bench [Bench]
|
57
76
|
# @return [self]
|
58
77
|
def catalog bench
|
59
|
-
|
60
|
-
|
78
|
+
old_api_hash = @source_map_hash&.values&.map(&:api_hash)
|
79
|
+
need_to_uncache = (old_api_hash != bench.source_maps.map(&:api_hash))
|
61
80
|
@source_map_hash = bench.source_maps.map { |s| [s.filename, s] }.to_h
|
62
|
-
pins = bench.source_maps.
|
81
|
+
pins = bench.source_maps.flat_map(&:pins).flatten
|
82
|
+
implicit.clear
|
63
83
|
source_map_hash.each_value do |map|
|
64
84
|
implicit.merge map.environ
|
65
85
|
end
|
66
|
-
unresolved_requires = (bench.external_requires + implicit.requires + bench.workspace.config.required).uniq
|
67
|
-
@
|
86
|
+
unresolved_requires = (bench.external_requires + implicit.requires + bench.workspace.config.required).to_a.compact.uniq
|
87
|
+
if @unresolved_requires != unresolved_requires || @doc_map&.uncached_gemspecs&.any?
|
88
|
+
@doc_map = DocMap.new(unresolved_requires, [], bench.workspace.rbs_collection_path) # @todo Implement gem preferences
|
89
|
+
@unresolved_requires = unresolved_requires
|
90
|
+
need_to_uncache = true
|
91
|
+
end
|
68
92
|
@store = Store.new(@@core_map.pins + @doc_map.pins + implicit.pins + pins)
|
69
|
-
@
|
93
|
+
@cache.clear if need_to_uncache
|
94
|
+
|
70
95
|
@missing_docs = [] # @todo Implement missing docs
|
71
96
|
self
|
72
97
|
end
|
73
98
|
|
99
|
+
protected def equality_fields
|
100
|
+
[self.class, @source_map_hash, implicit, @doc_map, @unresolved_requires, @missing_docs]
|
101
|
+
end
|
102
|
+
|
74
103
|
# @return [::Array<Gem::Specification>]
|
75
104
|
def uncached_gemspecs
|
76
105
|
@doc_map&.uncached_gemspecs || []
|
@@ -133,14 +162,19 @@ module Solargraph
|
|
133
162
|
# Create an ApiMap with a workspace in the specified directory and cache
|
134
163
|
# any missing gems.
|
135
164
|
#
|
165
|
+
#
|
166
|
+
# @todo IO::NULL is incorrectly inferred to be a String.
|
167
|
+
# @sg-ignore
|
168
|
+
#
|
136
169
|
# @param directory [String]
|
170
|
+
# @param out [IO] The output stream for messages
|
137
171
|
# @return [ApiMap]
|
138
|
-
def self.load_with_cache directory
|
172
|
+
def self.load_with_cache directory, out = IO::NULL
|
139
173
|
api_map = load(directory)
|
140
174
|
return api_map if api_map.uncached_gemspecs.empty?
|
141
175
|
|
142
176
|
api_map.uncached_gemspecs.each do |gemspec|
|
143
|
-
|
177
|
+
out.puts "Caching gem #{gemspec.name} #{gemspec.version}"
|
144
178
|
pins = GemPins.build(gemspec)
|
145
179
|
Solargraph::Cache.save('gems', "#{gemspec.name}-#{gemspec.version}.ser", pins)
|
146
180
|
end
|
@@ -221,10 +255,15 @@ module Solargraph
|
|
221
255
|
# @return [String, nil] fully qualified tag
|
222
256
|
def qualify tag, context_tag = ''
|
223
257
|
return tag if ['self', nil].include?(tag)
|
224
|
-
context_type = ComplexType.
|
225
|
-
|
258
|
+
context_type = ComplexType.try_parse(context_tag)
|
259
|
+
return unless context_type
|
260
|
+
|
261
|
+
type = ComplexType.try_parse(tag)
|
262
|
+
return unless type
|
263
|
+
|
226
264
|
fqns = qualify_namespace(type.rooted_namespace, context_type.rooted_namespace)
|
227
|
-
return
|
265
|
+
return unless fqns
|
266
|
+
|
228
267
|
fqns + type.substring
|
229
268
|
end
|
230
269
|
|
@@ -332,7 +371,7 @@ module Solargraph
|
|
332
371
|
end
|
333
372
|
end
|
334
373
|
result.concat inner_get_methods('Kernel', :instance, [:public], deep, skip) if visibility.include?(:private)
|
335
|
-
result.concat inner_get_methods('Module', scope, visibility, deep, skip)
|
374
|
+
result.concat inner_get_methods('Module', scope, visibility, deep, skip) if scope == :module
|
336
375
|
end
|
337
376
|
resolved = resolve_method_aliases(result, visibility)
|
338
377
|
cache.set_methods(rooted_tag, scope, visibility, deep, resolved)
|
@@ -466,9 +505,6 @@ module Solargraph
|
|
466
505
|
def clip cursor
|
467
506
|
raise FileNotFoundError, "ApiMap did not catalog #{cursor.filename}" unless source_map_hash.key?(cursor.filename)
|
468
507
|
|
469
|
-
# @todo Clip caches are disabled pending resolution of a stale cache bug
|
470
|
-
# cache.get_clip(cursor) ||
|
471
|
-
# SourceMap::Clip.new(self, cursor).tap { |clip| cache.set_clip(cursor, clip) }
|
472
508
|
SourceMap::Clip.new(self, cursor)
|
473
509
|
end
|
474
510
|
|
@@ -573,8 +609,8 @@ module Solargraph
|
|
573
609
|
# namespaces; resolving the generics in the method pins is this
|
574
610
|
# class' responsibility
|
575
611
|
raw_methods = store.get_methods(fqns, scope: scope, visibility: visibility).sort{ |a, b| a.name <=> b.name }
|
576
|
-
namespace_pin = store.get_path_pins(fqns).select{|p| p.is_a?(Pin::Namespace)}.first
|
577
|
-
methods = if rooted_tag != fqns
|
612
|
+
namespace_pin = store.get_path_pins(fqns).select { |p| p.is_a?(Pin::Namespace) }.first
|
613
|
+
methods = if namespace_pin && rooted_tag != fqns
|
578
614
|
methods = raw_methods.map do |method_pin|
|
579
615
|
method_pin.resolve_generics(namespace_pin, rooted_type)
|
580
616
|
end
|
@@ -22,14 +22,18 @@ module Solargraph
|
|
22
22
|
# @return [String]
|
23
23
|
attr_reader :name
|
24
24
|
|
25
|
-
# @return [
|
26
|
-
attr_reader :
|
25
|
+
# @return [Array<ComplexType>]
|
26
|
+
attr_reader :subtypes
|
27
27
|
|
28
28
|
# @return [String]
|
29
|
-
|
29
|
+
def tag
|
30
|
+
@tag ||= "#{name}#{substring}"
|
31
|
+
end
|
30
32
|
|
31
|
-
# @return [
|
32
|
-
|
33
|
+
# @return [String]
|
34
|
+
def rooted_tag
|
35
|
+
@rooted_tag ||= rooted_name + rooted_substring
|
36
|
+
end
|
33
37
|
|
34
38
|
# @return [Boolean]
|
35
39
|
def duck_type?
|
@@ -46,6 +50,10 @@ module Solargraph
|
|
46
50
|
!substring.empty?
|
47
51
|
end
|
48
52
|
|
53
|
+
def tuple?
|
54
|
+
@tuple_type ||= (name == 'Tuple') || (name == 'Array' && subtypes.length >= 1 && fixed_parameters?)
|
55
|
+
end
|
56
|
+
|
49
57
|
def void?
|
50
58
|
name == 'void'
|
51
59
|
end
|
@@ -74,19 +82,28 @@ module Solargraph
|
|
74
82
|
end
|
75
83
|
end
|
76
84
|
|
85
|
+
# @return [Symbol, nil]
|
86
|
+
attr_reader :parameters_type
|
87
|
+
|
88
|
+
PARAMETERS_TYPE_BY_STARTING_TAG = {
|
89
|
+
'{' => :hash,
|
90
|
+
'(' => :fixed,
|
91
|
+
'<' => :list
|
92
|
+
}.freeze
|
93
|
+
|
77
94
|
# @return [Boolean]
|
78
95
|
def list_parameters?
|
79
|
-
|
96
|
+
parameters_type == :list
|
80
97
|
end
|
81
98
|
|
82
99
|
# @return [Boolean]
|
83
100
|
def fixed_parameters?
|
84
|
-
|
101
|
+
parameters_type == :fixed
|
85
102
|
end
|
86
103
|
|
87
104
|
# @return [Boolean]
|
88
105
|
def hash_parameters?
|
89
|
-
|
106
|
+
parameters_type == :hash
|
90
107
|
end
|
91
108
|
|
92
109
|
# @return [Array<ComplexType>]
|
@@ -121,6 +138,33 @@ module Solargraph
|
|
121
138
|
"::#{name}"
|
122
139
|
end
|
123
140
|
|
141
|
+
# @return [String]
|
142
|
+
def substring
|
143
|
+
@substring ||= generate_substring_from(&:tags)
|
144
|
+
end
|
145
|
+
|
146
|
+
# @return [String]
|
147
|
+
def rooted_substring
|
148
|
+
@rooted_substring = generate_substring_from(&:rooted_tags)
|
149
|
+
end
|
150
|
+
|
151
|
+
# @return [String]
|
152
|
+
def generate_substring_from(&to_str)
|
153
|
+
key_types_str = key_types.map(&to_str).join(', ')
|
154
|
+
subtypes_str = subtypes.map(&to_str).join(', ')
|
155
|
+
if key_types.none?(&:defined?) && subtypes.none?(&:defined?)
|
156
|
+
''
|
157
|
+
elsif key_types.empty? && subtypes.empty?
|
158
|
+
''
|
159
|
+
elsif hash_parameters?
|
160
|
+
"{#{key_types_str} => #{subtypes_str}}"
|
161
|
+
elsif fixed_parameters?
|
162
|
+
"(#{subtypes_str})"
|
163
|
+
else
|
164
|
+
"<#{subtypes_str}>"
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
124
168
|
# @return [::Symbol] :class or :instance
|
125
169
|
def scope
|
126
170
|
@scope ||= :instance if duck_type? || nil_type?
|
@@ -143,28 +187,16 @@ module Solargraph
|
|
143
187
|
# @param context [String] The namespace from which to resolve names
|
144
188
|
# @return [self, ComplexType, UniqueType] The generated ComplexType
|
145
189
|
def qualify api_map, context = ''
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
all_rtypes = value_types.map { |t| t.qualify api_map, context }
|
157
|
-
if list_parameters?
|
158
|
-
rtypes = all_rtypes.uniq
|
159
|
-
Solargraph::ComplexType.parse("#{fqns}<#{rtypes.map(&:tag).join(', ')}>")
|
160
|
-
elsif fixed_parameters?
|
161
|
-
Solargraph::ComplexType.parse("#{fqns}(#{all_rtypes.map(&:tag).join(', ')})")
|
162
|
-
elsif hash_parameters?
|
163
|
-
ltypes = all_ltypes.uniq
|
164
|
-
rtypes = all_rtypes.uniq
|
165
|
-
Solargraph::ComplexType.parse("#{fqns}{#{ltypes.map(&:tag).join(', ')} => #{rtypes.map(&:tag).join(', ')}}")
|
166
|
-
else
|
167
|
-
Solargraph::ComplexType.parse(fqns)
|
190
|
+
transform do |t|
|
191
|
+
next t if t.name == GENERIC_TAG_NAME
|
192
|
+
next t if t.duck_type? || t.void? || t.undefined?
|
193
|
+
recon = (t.rooted? ? '' : context)
|
194
|
+
fqns = api_map.qualify(t.name, recon)
|
195
|
+
if fqns.nil?
|
196
|
+
next UniqueType::BOOLEAN if t.tag == 'Boolean'
|
197
|
+
next UniqueType::UNDEFINED
|
198
|
+
end
|
199
|
+
t.recreate(new_name: fqns, make_rooted: true)
|
168
200
|
end
|
169
201
|
end
|
170
202
|
|
@@ -17,43 +17,61 @@ module Solargraph
|
|
17
17
|
#
|
18
18
|
# @param name [String] The name of the type
|
19
19
|
# @param substring [String] The substring of the type
|
20
|
-
|
20
|
+
# @param make_rooted [Boolean, nil]
|
21
|
+
# @return [UniqueType]
|
22
|
+
def self.parse name, substring = '', make_rooted: nil
|
23
|
+
if name.start_with?(':::')
|
24
|
+
raise "Illegal prefix: #{name}"
|
25
|
+
end
|
21
26
|
if name.start_with?('::')
|
22
|
-
|
23
|
-
|
27
|
+
name = name[2..-1]
|
28
|
+
rooted = true
|
24
29
|
else
|
25
|
-
|
26
|
-
@rooted = false
|
30
|
+
rooted = false
|
27
31
|
end
|
28
|
-
|
29
|
-
|
30
|
-
# @type [Array<ComplexType>]
|
31
|
-
@key_types = []
|
32
|
+
rooted = make_rooted unless make_rooted.nil?
|
33
|
+
|
32
34
|
# @type [Array<ComplexType>]
|
33
|
-
|
35
|
+
key_types = []
|
34
36
|
# @type [Array<ComplexType>]
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
@subtypes.concat subs[1].map { |u| ComplexType.new([u]) }
|
52
|
-
else
|
53
|
-
@subtypes.concat subs
|
37
|
+
subtypes = []
|
38
|
+
parameters_type = nil
|
39
|
+
unless substring.empty?
|
40
|
+
subs = ComplexType.parse(substring[1..-2], partial: true)
|
41
|
+
parameters_type = PARAMETERS_TYPE_BY_STARTING_TAG.fetch(substring[0])
|
42
|
+
if parameters_type == :hash
|
43
|
+
raise ComplexTypeError, "Bad hash type" unless !subs.is_a?(ComplexType) and subs.length == 2 and !subs[0].is_a?(UniqueType) and !subs[1].is_a?(UniqueType)
|
44
|
+
# @todo should be able to resolve map; both types have it
|
45
|
+
# with same return type
|
46
|
+
# @sg-ignore
|
47
|
+
key_types.concat(subs[0].map { |u| ComplexType.new([u]) })
|
48
|
+
# @sg-ignore
|
49
|
+
subtypes.concat(subs[1].map { |u| ComplexType.new([u]) })
|
50
|
+
else
|
51
|
+
subtypes.concat subs
|
52
|
+
end
|
54
53
|
end
|
55
|
-
|
56
|
-
|
54
|
+
new(name, key_types, subtypes, rooted: rooted, parameters_type: parameters_type)
|
55
|
+
end
|
56
|
+
|
57
|
+
# @param name [String]
|
58
|
+
# @param key_types [Array<ComplexType>]
|
59
|
+
# @param subtypes [Array<ComplexType>]
|
60
|
+
# @param rooted [Boolean]
|
61
|
+
# @param parameters_type [Symbol, nil]
|
62
|
+
def initialize(name, key_types = [], subtypes = [], rooted:, parameters_type: nil)
|
63
|
+
if parameters_type.nil?
|
64
|
+
raise "You must supply parameters_type if you provide parameters" unless key_types.empty? && subtypes.empty?
|
65
|
+
end
|
66
|
+
raise "Please remove leading :: and set rooted instead - #{name}" if name.start_with?('::')
|
67
|
+
@name = name
|
68
|
+
@key_types = key_types
|
69
|
+
@subtypes = subtypes
|
70
|
+
@rooted = rooted
|
71
|
+
@all_params = []
|
72
|
+
@all_params.concat key_types
|
73
|
+
@all_params.concat subtypes
|
74
|
+
@parameters_type = parameters_type
|
57
75
|
end
|
58
76
|
|
59
77
|
def to_s
|
@@ -76,7 +94,17 @@ module Solargraph
|
|
76
94
|
|
77
95
|
# @return [String]
|
78
96
|
def to_rbs
|
79
|
-
if
|
97
|
+
if duck_type?
|
98
|
+
'untyped'
|
99
|
+
elsif name == 'Boolean'
|
100
|
+
'bool'
|
101
|
+
elsif name.downcase == 'nil'
|
102
|
+
'nil'
|
103
|
+
elsif name == GENERIC_TAG_NAME
|
104
|
+
all_params.first.name
|
105
|
+
elsif ['Class', 'Module'].include?(name)
|
106
|
+
rbs_name
|
107
|
+
elsif ['Tuple', 'Array'].include?(name) && fixed_parameters?
|
80
108
|
# tuples don't have a name; they're just [foo, bar, baz].
|
81
109
|
if substring == '()'
|
82
110
|
# but there are no zero element tuples, so we go with an array
|
@@ -90,16 +118,37 @@ module Solargraph
|
|
90
118
|
end
|
91
119
|
end
|
92
120
|
|
121
|
+
# @return [Boolean]
|
122
|
+
def parameters?
|
123
|
+
!all_params.empty?
|
124
|
+
end
|
125
|
+
|
126
|
+
# @param types [Array<UniqueType, ComplexType>]
|
127
|
+
# @return [String]
|
128
|
+
def rbs_union(types)
|
129
|
+
if types.length == 1
|
130
|
+
types.first.to_rbs
|
131
|
+
else
|
132
|
+
"(#{types.map(&:to_rbs).join(' | ')})"
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
93
136
|
# @return [String]
|
94
137
|
def parameters_as_rbs
|
95
|
-
|
138
|
+
return '' unless parameters?
|
139
|
+
|
140
|
+
return "[#{all_params.map(&:to_rbs).join(', ')}]" if key_types.empty?
|
141
|
+
|
142
|
+
# handle, e.g., Hash[K, V] case
|
143
|
+
key_types_str = rbs_union(key_types)
|
144
|
+
subtypes_str = rbs_union(subtypes)
|
145
|
+
"[#{key_types_str}, #{subtypes_str}]"
|
96
146
|
end
|
97
147
|
|
98
148
|
def generic?
|
99
149
|
name == GENERIC_TAG_NAME || all_params.any?(&:generic?)
|
100
150
|
end
|
101
151
|
|
102
|
-
|
103
152
|
# @param generics_to_resolve [Enumerable<String>]
|
104
153
|
# @param context_type [UniqueType, nil]
|
105
154
|
# @param resolved_generic_values [Hash{String => ComplexType}] Added to as types are encountered or resolved
|
@@ -182,39 +231,34 @@ module Solargraph
|
|
182
231
|
end
|
183
232
|
|
184
233
|
# @param new_name [String, nil]
|
234
|
+
# @param make_rooted [Boolean, nil]
|
185
235
|
# @param new_key_types [Array<UniqueType>, nil]
|
236
|
+
# @param rooted [Boolean, nil]
|
186
237
|
# @param new_subtypes [Array<UniqueType>, nil]
|
187
238
|
# @return [self]
|
188
|
-
def recreate(new_name: nil, new_key_types: nil, new_subtypes: nil)
|
239
|
+
def recreate(new_name: nil, make_rooted: nil, new_key_types: nil, new_subtypes: nil)
|
240
|
+
raise "Please remove leading :: and set rooted instead - #{new_name}" if new_name&.start_with?('::')
|
189
241
|
new_name ||= name
|
190
242
|
new_key_types ||= @key_types
|
191
243
|
new_subtypes ||= @subtypes
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
# Array<(String), Integer> is not ambiguous if we accept
|
211
|
-
# (String) as a tuple type, but not currently understood
|
212
|
-
# by Solargraph.
|
213
|
-
UniqueType.new(new_name, "<(#{new_subtypes.join(', ')})>")
|
214
|
-
elsif fixed_parameters?
|
215
|
-
UniqueType.new(new_name, "(#{new_subtypes.join(', ')})")
|
216
|
-
else
|
217
|
-
UniqueType.new(new_name, "<#{new_subtypes.join(', ')}>")
|
244
|
+
make_rooted = @rooted if make_rooted.nil?
|
245
|
+
UniqueType.new(new_name, new_key_types, new_subtypes, rooted: make_rooted, parameters_type: parameters_type)
|
246
|
+
end
|
247
|
+
|
248
|
+
# @return [String]
|
249
|
+
def rooted_tags
|
250
|
+
rooted_tag
|
251
|
+
end
|
252
|
+
|
253
|
+
# @return [String]
|
254
|
+
def tags
|
255
|
+
tag
|
256
|
+
end
|
257
|
+
|
258
|
+
# @return [self]
|
259
|
+
def force_rooted
|
260
|
+
transform do |t|
|
261
|
+
t.recreate(make_rooted: true)
|
218
262
|
end
|
219
263
|
end
|
220
264
|
|
@@ -225,9 +269,16 @@ module Solargraph
|
|
225
269
|
# @yieldreturn [self]
|
226
270
|
# @return [self]
|
227
271
|
def transform(new_name = nil, &transform_type)
|
228
|
-
|
229
|
-
|
230
|
-
|
272
|
+
raise "Please remove leading :: and set rooted with recreate() instead - #{new_name}" if new_name&.start_with?('::')
|
273
|
+
if name == ComplexType::GENERIC_TAG_NAME
|
274
|
+
# doesn't make sense to manipulate the name of the generic
|
275
|
+
new_key_types = @key_types
|
276
|
+
new_subtypes = @subtypes
|
277
|
+
else
|
278
|
+
new_key_types = @key_types.flat_map { |ct| ct.items.map { |ut| ut.transform(&transform_type) } }
|
279
|
+
new_subtypes = @subtypes.flat_map { |ct| ct.items.map { |ut| ut.transform(&transform_type) } }
|
280
|
+
end
|
281
|
+
new_type = recreate(new_name: new_name || name, new_key_types: new_key_types, new_subtypes: new_subtypes)
|
231
282
|
yield new_type
|
232
283
|
end
|
233
284
|
|
@@ -245,8 +296,8 @@ module Solargraph
|
|
245
296
|
@name == 'self' || @key_types.any?(&:selfy?) || @subtypes.any?(&:selfy?)
|
246
297
|
end
|
247
298
|
|
248
|
-
UNDEFINED = UniqueType.new('undefined')
|
249
|
-
BOOLEAN = UniqueType.new('Boolean')
|
299
|
+
UNDEFINED = UniqueType.new('undefined', rooted: false)
|
300
|
+
BOOLEAN = UniqueType.new('Boolean', rooted: true)
|
250
301
|
end
|
251
302
|
end
|
252
303
|
end
|