repl_type_completor 0.1.15 → 0.1.17
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/lib/repl_type_completor/result.rb +12 -8
- data/lib/repl_type_completor/type_analyzer.rb +19 -11
- data/lib/repl_type_completor/types.rb +137 -53
- data/lib/repl_type_completor/version.rb +1 -1
- data/lib/repl_type_completor.rb +16 -2
- metadata +3 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 2dce7fd408fd473356245c6b83f8ba3240ebe39946a7e9a929cbfdde6cd138a1
|
|
4
|
+
data.tar.gz: 78002d089560ede6af424b70a46f10f0b65218858bdf6dee8ec63c07bf7b2b45
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 3347f5df32b086a04a916d4e1b8def4352c392cc1a59564e2e87eceda50c4e50933117a8c9c72ca0e92d004a77f312d16d02a2923082de2df3babdc60e545426
|
|
7
|
+
data.tar.gz: 1c0916a0129ec721e14c20c166290f41db39a97f832b32dde332cef8140a3c47723ebef94cff4623d1e2738c3174070cfac462d5db88a4f4b9b7932213241919
|
|
@@ -46,7 +46,7 @@ module ReplTypeCompletor
|
|
|
46
46
|
in [:require_relative, name]
|
|
47
47
|
RequirePaths.require_relative_completions(name, @source_file)
|
|
48
48
|
in [:call_or_const, name, type, self_call]
|
|
49
|
-
((self_call ? type.all_methods : type.methods).map(&:to_s) - HIDDEN_METHODS) | type.constants
|
|
49
|
+
((self_call ? type.all_methods : type.methods).map(&:to_s) - HIDDEN_METHODS).sort | type.constants.sort
|
|
50
50
|
in [:const, name, type, scope]
|
|
51
51
|
if type
|
|
52
52
|
scope_constants = type.types.flat_map do |t|
|
|
@@ -60,28 +60,32 @@ module ReplTypeCompletor
|
|
|
60
60
|
ivars = scope.instance_variables.sort
|
|
61
61
|
name == '@' ? ivars + scope.class_variables.sort : ivars
|
|
62
62
|
in [:cvar, name, scope]
|
|
63
|
-
scope.class_variables
|
|
63
|
+
scope.class_variables.sort
|
|
64
64
|
in [:gvar, name, scope]
|
|
65
|
-
scope.global_variables
|
|
65
|
+
scope.global_variables.sort
|
|
66
66
|
in [:symbol, name]
|
|
67
67
|
filter_symbol_candidates(Symbol.all_symbols, name, limit: 100)
|
|
68
68
|
in [:aref, key_type, name, receiver_type]
|
|
69
69
|
key_type = key_type == :string ? String : Symbol
|
|
70
70
|
keys = receiver_type.types.grep(Types::InstanceType).select do |t|
|
|
71
|
-
Hash == t.klass
|
|
71
|
+
Hash == t.klass && t.instances
|
|
72
72
|
end.flat_map do |t|
|
|
73
|
-
t.instances.flat_map(&:keys).grep(key_type).uniq
|
|
73
|
+
t.instances.flat_map(&:keys).grep(key_type).uniq
|
|
74
74
|
end
|
|
75
75
|
if key_type == Symbol
|
|
76
76
|
keys = Symbol.all_symbols if keys.empty? && name.size >= 1
|
|
77
77
|
filter_symbol_candidates(keys, name, limit: 100)
|
|
78
78
|
else
|
|
79
|
-
keys.
|
|
79
|
+
keys.sort
|
|
80
80
|
end
|
|
81
81
|
in [:call, name, type, self_call]
|
|
82
|
-
(self_call ? type.all_methods : type.methods).map(&:to_s) - HIDDEN_METHODS
|
|
82
|
+
methods = (self_call ? type.all_methods : type.methods).map(&:to_s) - HIDDEN_METHODS
|
|
83
|
+
# Alphabetical order, but internal methods (leading underscore) last.
|
|
84
|
+
# `_1[0] == '_'` because `start_with?('_')` raises EncodingError if the
|
|
85
|
+
# method name's encoding is incompatible with US-ASCII.
|
|
86
|
+
methods.sort_by { [_1[0] == '_' ? 1 : 0, _1] }
|
|
83
87
|
in [:lvar_or_method, name, scope]
|
|
84
|
-
scope.self_type.all_methods.map(&:to_s)
|
|
88
|
+
scope.local_variables.sort | scope.self_type.all_methods.map(&:to_s).sort | RESERVED_WORDS
|
|
85
89
|
else
|
|
86
90
|
[]
|
|
87
91
|
end
|
|
@@ -3,9 +3,17 @@
|
|
|
3
3
|
require 'set'
|
|
4
4
|
require_relative 'types'
|
|
5
5
|
require_relative 'scope'
|
|
6
|
-
require 'prism'
|
|
7
|
-
|
|
8
6
|
module ReplTypeCompletor
|
|
7
|
+
# Prefer Ruby::Prism, the parser built into the interpreter (Ruby 4.1+),
|
|
8
|
+
# over the prism gem. Every reference to Prism in this gem is lexically
|
|
9
|
+
# inside the ReplTypeCompletor module, so it resolves to this constant.
|
|
10
|
+
if defined?(Ruby::Prism)
|
|
11
|
+
Prism = Ruby::Prism
|
|
12
|
+
else
|
|
13
|
+
require 'prism'
|
|
14
|
+
Prism = ::Prism
|
|
15
|
+
end
|
|
16
|
+
|
|
9
17
|
class TypeAnalyzer
|
|
10
18
|
class DigTarget
|
|
11
19
|
def initialize(parents, receiver, &block)
|
|
@@ -177,15 +185,15 @@ module ReplTypeCompletor
|
|
|
177
185
|
hash = method_call hash, :to_hash, [], nil, nil, scope
|
|
178
186
|
end
|
|
179
187
|
if hash.is_a?(Types::InstanceType) && hash.klass == Hash
|
|
180
|
-
keys << hash.params[
|
|
181
|
-
values << hash.params[
|
|
188
|
+
keys << hash.params[0] if hash.params[0]
|
|
189
|
+
values << hash.params[1] if hash.params[1]
|
|
182
190
|
end
|
|
183
191
|
end
|
|
184
192
|
end
|
|
185
193
|
if keys.empty? && values.empty?
|
|
186
|
-
Types::InstanceType.new
|
|
194
|
+
Types::InstanceType.new(Hash)
|
|
187
195
|
else
|
|
188
|
-
Types::InstanceType.new
|
|
196
|
+
Types::InstanceType.new(Hash, [Types::UnionType[*keys], Types::UnionType[*values]])
|
|
189
197
|
end
|
|
190
198
|
end
|
|
191
199
|
|
|
@@ -706,7 +714,7 @@ module ReplTypeCompletor
|
|
|
706
714
|
inner_scope = Scope.new scope, { Scope::BREAK_RESULT => nil }
|
|
707
715
|
ary_type = method_call collection, :to_ary, [], nil, nil, nil, name_match: false
|
|
708
716
|
element_types = ary_type.types.filter_map do |ary|
|
|
709
|
-
ary.params[
|
|
717
|
+
ary.params[0] if ary.is_a?(Types::InstanceType) && ary.klass == Array
|
|
710
718
|
end
|
|
711
719
|
element_type = Types::UnionType[*element_types]
|
|
712
720
|
inner_scope.conditional do |s|
|
|
@@ -761,7 +769,7 @@ module ReplTypeCompletor
|
|
|
761
769
|
beg_type = evaluate node.left, scope if node.left
|
|
762
770
|
end_type = evaluate node.right, scope if node.right
|
|
763
771
|
elem = (Types::UnionType[*[beg_type, end_type].compact]).nonnillable
|
|
764
|
-
Types::InstanceType.new
|
|
772
|
+
Types::InstanceType.new(Range, [elem])
|
|
765
773
|
end
|
|
766
774
|
|
|
767
775
|
def evaluate_defined_node(node, scope)
|
|
@@ -958,7 +966,7 @@ module ReplTypeCompletor
|
|
|
958
966
|
end
|
|
959
967
|
# node.keyword_rest is Prism::KeywordRestParameterNode or Prism::ForwardingParameterNode or Prism::NoKeywordsParameterNode
|
|
960
968
|
if node.keyword_rest.is_a?(Prism::KeywordRestParameterNode) && node.keyword_rest.name
|
|
961
|
-
scope[node.keyword_rest.name.to_s] = Types::InstanceType.new(Hash,
|
|
969
|
+
scope[node.keyword_rest.name.to_s] = Types::InstanceType.new(Hash, [Types::SYMBOL, Types::UnionType[*kwargs.values]])
|
|
962
970
|
end
|
|
963
971
|
if node.block&.name
|
|
964
972
|
# node.block is Prism::BlockParameterNode
|
|
@@ -1143,7 +1151,7 @@ module ReplTypeCompletor
|
|
|
1143
1151
|
true
|
|
1144
1152
|
end
|
|
1145
1153
|
end
|
|
1146
|
-
array_elem = arrays.empty? ? nil : Types::UnionType[*arrays.map { _1.params[
|
|
1154
|
+
array_elem = arrays.empty? ? nil : Types::UnionType[*arrays.map { _1.params[0] || Types::OBJECT }]
|
|
1147
1155
|
non_array = non_arrays.empty? ? nil : Types::UnionType[*non_arrays]
|
|
1148
1156
|
[array_elem, non_array]
|
|
1149
1157
|
end
|
|
@@ -1152,7 +1160,7 @@ module ReplTypeCompletor
|
|
|
1152
1160
|
methods = Types.rbs_methods receiver, method_name.to_sym, args, kwargs, !!block
|
|
1153
1161
|
block_called = false
|
|
1154
1162
|
type_breaks = methods.map do |method, given_params, method_params|
|
|
1155
|
-
receiver_vars = receiver.is_a?(Types::InstanceType) ? receiver.
|
|
1163
|
+
receiver_vars = receiver.is_a?(Types::InstanceType) || receiver.is_a?(Types::InterfaceType) ? receiver.named_params : {}
|
|
1156
1164
|
free_vars = method.type.free_variables - receiver_vars.keys.to_set
|
|
1157
1165
|
vars = receiver_vars.merge Types.match_free_variables(free_vars, method_params, given_params)
|
|
1158
1166
|
if block && method.block && method.block.type.respond_to?(:required_positionals)
|
|
@@ -8,6 +8,7 @@ require_relative 'methods'
|
|
|
8
8
|
module ReplTypeCompletor
|
|
9
9
|
module Types
|
|
10
10
|
OBJECT_TO_TYPE_SAMPLE_SIZE = 50
|
|
11
|
+
EXPANSION_NESTING_LIMIT = 3
|
|
11
12
|
|
|
12
13
|
singleton_class.attr_reader :rbs_builder, :rbs_load_error
|
|
13
14
|
|
|
@@ -36,6 +37,10 @@ module ReplTypeCompletor
|
|
|
36
37
|
gem_sig_path = File.expand_path("#{spec.gem_dir}/sig")
|
|
37
38
|
loader.add(library: spec.name, version: spec.version) if Dir.exist?(gem_sig_path) && expanded_sig_path != gem_sig_path
|
|
38
39
|
end
|
|
40
|
+
# A gem's sig/manifest.yaml can declare dependencies on stdlib libraries that
|
|
41
|
+
# the installed RBS version does not ship (e.g. prism >= 2.0 depends on pp,
|
|
42
|
+
# which was added in RBS 3.3). Skip those instead of failing to load everything.
|
|
43
|
+
loader.libs.delete_if { |lib| !loader.has_library?(library: lib.name, version: lib.version) }
|
|
39
44
|
end
|
|
40
45
|
|
|
41
46
|
# Hack to make this thread priority lower, not to block the main thread.
|
|
@@ -75,6 +80,11 @@ module ReplTypeCompletor
|
|
|
75
80
|
def self.rbs_search_method(klass, method_name, singleton)
|
|
76
81
|
return unless rbs_builder
|
|
77
82
|
|
|
83
|
+
if klass.is_a? InterfaceType
|
|
84
|
+
definition = klass.definition
|
|
85
|
+
return definition && definition.methods[method_name]
|
|
86
|
+
end
|
|
87
|
+
|
|
78
88
|
klass.ancestors.each do |ancestor|
|
|
79
89
|
next unless (name = Methods::MODULE_NAME_METHOD.bind_call(ancestor))
|
|
80
90
|
|
|
@@ -93,6 +103,8 @@ module ReplTypeCompletor
|
|
|
93
103
|
[t, t.module_or_class, true]
|
|
94
104
|
in InstanceType
|
|
95
105
|
[t, t.klass, false]
|
|
106
|
+
in InterfaceType
|
|
107
|
+
[t, t, false]
|
|
96
108
|
end
|
|
97
109
|
end
|
|
98
110
|
types = receivers.flat_map do |receiver_type, klass, singleton|
|
|
@@ -115,6 +127,8 @@ module ReplTypeCompletor
|
|
|
115
127
|
t.module_or_class
|
|
116
128
|
in InstanceType
|
|
117
129
|
t.instances
|
|
130
|
+
in InterfaceType
|
|
131
|
+
nil
|
|
118
132
|
end
|
|
119
133
|
end.flatten
|
|
120
134
|
instances = instances.sample(OBJECT_TO_TYPE_SAMPLE_SIZE) if instances.size > OBJECT_TO_TYPE_SAMPLE_SIZE
|
|
@@ -136,6 +150,8 @@ module ReplTypeCompletor
|
|
|
136
150
|
[t, t.module_or_class, true]
|
|
137
151
|
in InstanceType
|
|
138
152
|
[t, t.klass, false]
|
|
153
|
+
in InterfaceType
|
|
154
|
+
[t, t, false]
|
|
139
155
|
end
|
|
140
156
|
end
|
|
141
157
|
has_splat = args_types.include?(nil)
|
|
@@ -157,7 +173,7 @@ module ReplTypeCompletor
|
|
|
157
173
|
args = args_types
|
|
158
174
|
if kwargs_type&.any? && keyreqs.empty? && keyopts.empty? && keyrest.nil?
|
|
159
175
|
kw_value_type = UnionType[*kwargs_type.values]
|
|
160
|
-
args += [InstanceType.new(Hash,
|
|
176
|
+
args += [InstanceType.new(Hash, [SYMBOL, kw_value_type])]
|
|
161
177
|
end
|
|
162
178
|
if has_splat
|
|
163
179
|
score += 1 if args.count(&:itself) <= reqs.size + opts.size + trailings.size
|
|
@@ -193,7 +209,14 @@ module ReplTypeCompletor
|
|
|
193
209
|
end
|
|
194
210
|
|
|
195
211
|
aa, bb = [atypes, btypes].map {|types| (types[InstanceType] || []).map(&:klass) }
|
|
196
|
-
(aa.flat_map(&:ancestors) & bb).any?
|
|
212
|
+
return true if (aa.flat_map(&:ancestors) & bb).any?
|
|
213
|
+
|
|
214
|
+
[[atypes[InterfaceType], b], [btypes[InterfaceType], a]].any? do |interfaces, other|
|
|
215
|
+
interfaces&.any? do |interface|
|
|
216
|
+
methods = interface.methods
|
|
217
|
+
!methods.empty? && other.types.any? { |t| (methods - t.methods).empty? }
|
|
218
|
+
end
|
|
219
|
+
end
|
|
197
220
|
end
|
|
198
221
|
|
|
199
222
|
def self.type_from_object(object)
|
|
@@ -216,6 +239,13 @@ module ReplTypeCompletor
|
|
|
216
239
|
UnionType[*class_instances.map { InstanceType.new _1, nil, _2 }, *modules.uniq.map { SingletonType.new _1 }]
|
|
217
240
|
end
|
|
218
241
|
|
|
242
|
+
def self.union_type_from_objects_list(objects_list)
|
|
243
|
+
objects = objects_list.flat_map do |objects|
|
|
244
|
+
objects.size < OBJECT_TO_TYPE_SAMPLE_SIZE ? objects : objects.sample(OBJECT_TO_TYPE_SAMPLE_SIZE)
|
|
245
|
+
end
|
|
246
|
+
union_type_from_objects(objects)
|
|
247
|
+
end
|
|
248
|
+
|
|
219
249
|
class SingletonType
|
|
220
250
|
attr_reader :module_or_class
|
|
221
251
|
def initialize(module_or_class)
|
|
@@ -263,20 +293,29 @@ module ReplTypeCompletor
|
|
|
263
293
|
@params ||= expand_params
|
|
264
294
|
end
|
|
265
295
|
|
|
296
|
+
def named_params
|
|
297
|
+
return {} if params.empty?
|
|
298
|
+
if Types.rbs_builder
|
|
299
|
+
type_name = Types.rbs_absolute_type_name(Types.class_name_of(@klass))
|
|
300
|
+
names = Types.rbs_builder.build_instance(type_name)&.type_params rescue nil
|
|
301
|
+
end
|
|
302
|
+
names ? names.zip(params).to_h.compact : {}
|
|
303
|
+
end
|
|
304
|
+
|
|
266
305
|
def expand_params
|
|
267
|
-
params = @raw_params ||
|
|
306
|
+
params = @raw_params || []
|
|
268
307
|
return params unless @instances
|
|
269
308
|
|
|
270
309
|
if @klass == Array
|
|
271
|
-
type = Types.
|
|
272
|
-
|
|
310
|
+
type = Types.union_type_from_objects_list(@instances)
|
|
311
|
+
[UnionType[*params[0], *type]]
|
|
273
312
|
elsif @klass == Hash
|
|
274
|
-
key = Types.
|
|
275
|
-
value = Types.
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
313
|
+
key = Types.union_type_from_objects_list(@instances.map(&:keys))
|
|
314
|
+
value = Types.union_type_from_objects_list(@instances.map(&:values))
|
|
315
|
+
[
|
|
316
|
+
UnionType[*params[0], key],
|
|
317
|
+
UnionType[*params[1], value]
|
|
318
|
+
]
|
|
280
319
|
else
|
|
281
320
|
params
|
|
282
321
|
end
|
|
@@ -301,7 +340,12 @@ module ReplTypeCompletor
|
|
|
301
340
|
elsif params.empty?
|
|
302
341
|
inspect_without_params
|
|
303
342
|
else
|
|
304
|
-
|
|
343
|
+
named = named_params
|
|
344
|
+
if named.empty? && !params.empty?
|
|
345
|
+
params_string = "[#{params.map(&:inspect).join(', ')}]"
|
|
346
|
+
else
|
|
347
|
+
params_string = "[#{named.map { "#{_1}: #{_2.inspect}" }.join(', ')}]"
|
|
348
|
+
end
|
|
305
349
|
"#{inspect_without_params}#{params_string}"
|
|
306
350
|
end
|
|
307
351
|
end
|
|
@@ -319,6 +363,38 @@ module ReplTypeCompletor
|
|
|
319
363
|
end
|
|
320
364
|
end
|
|
321
365
|
|
|
366
|
+
class InterfaceType
|
|
367
|
+
attr_reader :name, :args
|
|
368
|
+
|
|
369
|
+
def initialize(name, args = [])
|
|
370
|
+
@name = name
|
|
371
|
+
@args = args
|
|
372
|
+
end
|
|
373
|
+
|
|
374
|
+
def definition
|
|
375
|
+
return @definition if defined?(@definition)
|
|
376
|
+
|
|
377
|
+
@definition = (Types.rbs_builder&.build_interface(@name) rescue nil)
|
|
378
|
+
end
|
|
379
|
+
|
|
380
|
+
def transform() = yield(self)
|
|
381
|
+
def methods() = definition ? definition.methods.keys : []
|
|
382
|
+
def all_methods() = methods
|
|
383
|
+
|
|
384
|
+
def named_params
|
|
385
|
+
definition ? definition.type_params.zip(@args).to_h.compact : {}
|
|
386
|
+
end
|
|
387
|
+
|
|
388
|
+
def constants() = []
|
|
389
|
+
def types() = [self]
|
|
390
|
+
def nillable?() = false
|
|
391
|
+
def nonnillable() = self
|
|
392
|
+
|
|
393
|
+
def inspect
|
|
394
|
+
args.empty? ? name.name.to_s : "#{name.name}[#{args.map(&:inspect).join(', ')}]"
|
|
395
|
+
end
|
|
396
|
+
end
|
|
397
|
+
|
|
322
398
|
NIL = InstanceType.new NilClass
|
|
323
399
|
OBJECT = InstanceType.new Object
|
|
324
400
|
TRUE = InstanceType.new TrueClass
|
|
@@ -343,24 +419,27 @@ module ReplTypeCompletor
|
|
|
343
419
|
def initialize(*types)
|
|
344
420
|
@types = []
|
|
345
421
|
singleton_types = []
|
|
422
|
+
interface_types = {}
|
|
346
423
|
instance_types = {}
|
|
347
424
|
collect = -> type do
|
|
348
425
|
case type
|
|
349
426
|
in UnionType
|
|
350
427
|
type.types.each(&collect)
|
|
351
428
|
in InstanceType
|
|
352
|
-
params, instances = (instance_types[type.klass] ||= [
|
|
429
|
+
params, instances = (instance_types[type.klass] ||= [[], []])
|
|
353
430
|
type.instances&.each { instances << _1 }
|
|
354
|
-
type.raw_params&.
|
|
355
|
-
(params[
|
|
431
|
+
type.raw_params&.each_with_index do |v, index|
|
|
432
|
+
(params[index] ||= []) << v
|
|
356
433
|
end
|
|
357
434
|
in SingletonType
|
|
358
435
|
singleton_types << type
|
|
436
|
+
in InterfaceType
|
|
437
|
+
interface_types[[type.name, type.args]] ||= type
|
|
359
438
|
end
|
|
360
439
|
end
|
|
361
440
|
types.each(&collect)
|
|
362
|
-
@types = singleton_types.uniq + instance_types.map do |klass, (params, instances)|
|
|
363
|
-
params = params.
|
|
441
|
+
@types = singleton_types.uniq + interface_types.values + instance_types.map do |klass, (params, instances)|
|
|
442
|
+
params = params.map { |v| UnionType[*v] }
|
|
364
443
|
InstanceType.new(klass, params, instances)
|
|
365
444
|
end
|
|
366
445
|
end
|
|
@@ -398,10 +477,18 @@ module ReplTypeCompletor
|
|
|
398
477
|
|
|
399
478
|
def self.array_of(*types)
|
|
400
479
|
type = types.size >= 2 ? UnionType[*types] : types.first || OBJECT
|
|
401
|
-
InstanceType.new
|
|
480
|
+
InstanceType.new(Array, [type])
|
|
402
481
|
end
|
|
403
482
|
|
|
404
|
-
|
|
483
|
+
# Alias may validly recurse through type args (`type json = Integer | Array[json]`)
|
|
484
|
+
# and can expand exponentially (`type b = a | [a]` chains), so expansion is depth limited.
|
|
485
|
+
def self.expand_alias_type(rbs_type, nesting)
|
|
486
|
+
return if nesting >= EXPANSION_NESTING_LIMIT
|
|
487
|
+
|
|
488
|
+
rbs_builder.expand_alias2 rbs_type.name, rbs_type.args rescue nil
|
|
489
|
+
end
|
|
490
|
+
|
|
491
|
+
def self.from_rbs_type(return_type, self_type, extra_vars = {}, nesting = 0)
|
|
405
492
|
case return_type
|
|
406
493
|
when RBS::Types::Bases::Self
|
|
407
494
|
self_type
|
|
@@ -413,12 +500,13 @@ module ReplTypeCompletor
|
|
|
413
500
|
self_type.transform do |type|
|
|
414
501
|
case type
|
|
415
502
|
in SingletonType
|
|
416
|
-
InstanceType.new(
|
|
503
|
+
InstanceType.new(type.module_or_class.is_a?(Class) ? Class : Module)
|
|
417
504
|
in InstanceType
|
|
418
505
|
SingletonType.new type.klass
|
|
506
|
+
in InterfaceType
|
|
507
|
+
CLASS
|
|
419
508
|
end
|
|
420
509
|
end
|
|
421
|
-
UnionType[*types]
|
|
422
510
|
when RBS::Types::Bases::Bool
|
|
423
511
|
BOOLEAN
|
|
424
512
|
when RBS::Types::Bases::Instance
|
|
@@ -433,54 +521,43 @@ module ReplTypeCompletor
|
|
|
433
521
|
end
|
|
434
522
|
when RBS::Types::Union, RBS::Types::Intersection
|
|
435
523
|
# Intersection is unsupported. fallback to union type
|
|
436
|
-
UnionType[*return_type.types.map { from_rbs_type _1, self_type, extra_vars }]
|
|
524
|
+
UnionType[*return_type.types.map { from_rbs_type _1, self_type, extra_vars, nesting }]
|
|
437
525
|
when RBS::Types::Proc
|
|
438
526
|
PROC
|
|
439
527
|
when RBS::Types::Tuple
|
|
440
|
-
elem = UnionType[*return_type.types.map { from_rbs_type _1, self_type, extra_vars }]
|
|
441
|
-
InstanceType.new
|
|
528
|
+
elem = UnionType[*return_type.types.map { from_rbs_type _1, self_type, extra_vars, nesting }]
|
|
529
|
+
InstanceType.new(Array, [elem])
|
|
442
530
|
when RBS::Types::Record
|
|
443
|
-
InstanceType.new
|
|
531
|
+
InstanceType.new(Hash, [SYMBOL, OBJECT])
|
|
444
532
|
when RBS::Types::Literal
|
|
445
533
|
InstanceType.new return_type.literal.class
|
|
446
534
|
when RBS::Types::Variable
|
|
447
535
|
if extra_vars.key? return_type.name
|
|
448
536
|
extra_vars[return_type.name]
|
|
449
|
-
elsif self_type.is_a?
|
|
450
|
-
self_type.
|
|
537
|
+
elsif self_type.is_a?(InstanceType) || self_type.is_a?(InterfaceType)
|
|
538
|
+
self_type.named_params[return_type.name] || OBJECT
|
|
451
539
|
elsif self_type.is_a? UnionType
|
|
452
540
|
types = self_type.types.filter_map do |t|
|
|
453
|
-
t.
|
|
541
|
+
t.named_params[return_type.name] if t.is_a?(InstanceType) || t.is_a?(InterfaceType)
|
|
454
542
|
end
|
|
455
543
|
UnionType[*types]
|
|
456
544
|
else
|
|
457
545
|
OBJECT
|
|
458
546
|
end
|
|
459
547
|
when RBS::Types::Optional
|
|
460
|
-
UnionType[from_rbs_type(return_type.type, self_type, extra_vars), NIL]
|
|
548
|
+
UnionType[from_rbs_type(return_type.type, self_type, extra_vars, nesting), NIL]
|
|
461
549
|
when RBS::Types::Alias
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
INTEGER
|
|
465
|
-
when :boolish
|
|
466
|
-
BOOLEAN
|
|
467
|
-
when :string
|
|
468
|
-
STRING
|
|
469
|
-
else
|
|
470
|
-
# TODO: ???
|
|
471
|
-
OBJECT
|
|
472
|
-
end
|
|
550
|
+
expanded = expand_alias_type(return_type, nesting)
|
|
551
|
+
expanded ? from_rbs_type(expanded, self_type, extra_vars, nesting + 1) : OBJECT
|
|
473
552
|
when RBS::Types::Interface
|
|
474
|
-
|
|
475
|
-
|
|
553
|
+
args = return_type.args.map { from_rbs_type _1, self_type, extra_vars, nesting }
|
|
554
|
+
InterfaceType.new return_type.name, args
|
|
476
555
|
when RBS::Types::ClassInstance
|
|
477
556
|
klass = return_type.name.to_namespace.path.reduce(Object) { _1.const_get _2 }
|
|
478
557
|
if return_type.args
|
|
479
|
-
|
|
480
|
-
names = rbs_builder.build_singleton(return_type.name).type_params
|
|
481
|
-
params = names.map.with_index { [_1, args[_2] || OBJECT] }.to_h
|
|
558
|
+
params = return_type.args.map { from_rbs_type _1, self_type, extra_vars, nesting }
|
|
482
559
|
end
|
|
483
|
-
InstanceType.new
|
|
560
|
+
InstanceType.new(klass, params || [])
|
|
484
561
|
else
|
|
485
562
|
OBJECT
|
|
486
563
|
end
|
|
@@ -498,24 +575,24 @@ module ReplTypeCompletor
|
|
|
498
575
|
accumulator.transform_values { UnionType[*_1] }
|
|
499
576
|
end
|
|
500
577
|
|
|
501
|
-
def self._match_free_variable(vars, rbs_type, value, accumulator)
|
|
578
|
+
def self._match_free_variable(vars, rbs_type, value, accumulator, nesting = 0)
|
|
502
579
|
case [rbs_type, value]
|
|
503
580
|
in [RBS::Types::Variable,]
|
|
504
581
|
(accumulator[rbs_type.name] ||= []) << value if vars.include? rbs_type.name
|
|
505
582
|
in [RBS::Types::ClassInstance, InstanceType]
|
|
506
583
|
names = rbs_builder.build_singleton(rbs_type.name).type_params
|
|
507
584
|
names.zip(rbs_type.args).each do |name, arg|
|
|
508
|
-
v = value.
|
|
509
|
-
_match_free_variable vars, arg, v, accumulator if v
|
|
585
|
+
v = value.named_params[name]
|
|
586
|
+
_match_free_variable vars, arg, v, accumulator, nesting if v
|
|
510
587
|
end
|
|
511
588
|
in [RBS::Types::Tuple, InstanceType] if value.klass == Array
|
|
512
|
-
v = value.params[
|
|
589
|
+
v = value.params[0]
|
|
513
590
|
rbs_type.types.each do |t|
|
|
514
|
-
_match_free_variable vars, t, v, accumulator
|
|
591
|
+
_match_free_variable vars, t, v, accumulator, nesting
|
|
515
592
|
end
|
|
516
593
|
in [RBS::Types::Record, InstanceType] if value.klass == Hash
|
|
517
594
|
# TODO
|
|
518
|
-
in [RBS::Types::Interface,]
|
|
595
|
+
in [RBS::Types::Interface,] if nesting < EXPANSION_NESTING_LIMIT
|
|
519
596
|
definition = rbs_builder.build_interface rbs_type.name
|
|
520
597
|
convert = {}
|
|
521
598
|
definition.type_params.zip(rbs_type.args).each do |from, arg|
|
|
@@ -527,13 +604,20 @@ module ReplTypeCompletor
|
|
|
527
604
|
return_type = method_return_type value, method_name
|
|
528
605
|
method.defs.each do |method_def|
|
|
529
606
|
interface_return_type = method_def.type.type.return_type
|
|
530
|
-
_match_free_variable convert, interface_return_type, return_type, ac
|
|
607
|
+
_match_free_variable convert, interface_return_type, return_type, ac, nesting + 1
|
|
531
608
|
end
|
|
532
609
|
end
|
|
533
610
|
convert.each do |from, to|
|
|
534
611
|
values = ac[from]
|
|
535
612
|
(accumulator[to] ||= []).concat values if values
|
|
536
613
|
end
|
|
614
|
+
in [RBS::Types::Union,]
|
|
615
|
+
rbs_type.types.each do |t|
|
|
616
|
+
_match_free_variable vars, t, value, accumulator, nesting
|
|
617
|
+
end
|
|
618
|
+
in [RBS::Types::Alias,]
|
|
619
|
+
expanded = expand_alias_type(rbs_type, nesting)
|
|
620
|
+
_match_free_variable vars, expanded, value, accumulator, nesting + 1 if expanded
|
|
537
621
|
else
|
|
538
622
|
end
|
|
539
623
|
end
|
data/lib/repl_type_completor.rb
CHANGED
|
@@ -45,7 +45,7 @@ module ReplTypeCompletor
|
|
|
45
45
|
|
|
46
46
|
def info
|
|
47
47
|
require 'rbs'
|
|
48
|
-
prism_info = "Prism: #{Prism::VERSION}"
|
|
48
|
+
prism_info = "#{Prism}: #{Prism::VERSION}"
|
|
49
49
|
rbs_info = "RBS: #{RBS::VERSION}"
|
|
50
50
|
if rbs_load_error
|
|
51
51
|
rbs_info << " #{rbs_load_error.inspect}"
|
|
@@ -69,7 +69,7 @@ module ReplTypeCompletor
|
|
|
69
69
|
end
|
|
70
70
|
|
|
71
71
|
def analyze_code(code, binding = Object::TOPLEVEL_BINDING)
|
|
72
|
-
ast = Prism.parse(code, scopes: [binding.local_variables]).value
|
|
72
|
+
ast = Prism.parse(code, scopes: [binding.local_variables], **prism_parse_options).value
|
|
73
73
|
*parents, target_node = find_target ast, code.bytesize
|
|
74
74
|
return unless target_node
|
|
75
75
|
|
|
@@ -81,6 +81,8 @@ module ReplTypeCompletor
|
|
|
81
81
|
return if target_node.opening == "?" || (target_node.closing_loc && !target_node.closing.empty?)
|
|
82
82
|
|
|
83
83
|
call_node = single_arg_call_node(parents) # require("target") or require_relative("target")
|
|
84
|
+
return unless call_node
|
|
85
|
+
|
|
84
86
|
if call_node.receiver.nil? && (call_node.name == :require || call_node.name == :require_relative)
|
|
85
87
|
[call_node.name, target_node.content]
|
|
86
88
|
elsif call_node.receiver && call_node.name == :[] # object["target"]
|
|
@@ -135,6 +137,18 @@ module ReplTypeCompletor
|
|
|
135
137
|
end
|
|
136
138
|
end
|
|
137
139
|
|
|
140
|
+
# Parse with the syntax of the running Ruby so that completion matches what will be executed.
|
|
141
|
+
# Fall back to Prism's default when `version: "current"` is not available (Prism < 1.6)
|
|
142
|
+
# or the running Ruby version is unknown to the installed Prism (Ruby < 3.3, or a newer Ruby).
|
|
143
|
+
def prism_parse_options
|
|
144
|
+
@prism_parse_options ||= begin
|
|
145
|
+
Prism.parse('', version: 'current')
|
|
146
|
+
{ version: 'current' }.freeze
|
|
147
|
+
rescue ArgumentError # includes Prism::CurrentVersionError
|
|
148
|
+
{}.freeze
|
|
149
|
+
end
|
|
150
|
+
end
|
|
151
|
+
|
|
138
152
|
def find_target(node, position)
|
|
139
153
|
# Skip because location of these nodes gives location of whole block
|
|
140
154
|
return if node.is_a?(Prism::NumberedParametersNode) || node.is_a?(Prism::ItParametersNode)
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: repl_type_completor
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.1.
|
|
4
|
+
version: 0.1.17
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- tompng
|
|
@@ -13,14 +13,14 @@ dependencies:
|
|
|
13
13
|
name: prism
|
|
14
14
|
requirement: !ruby/object:Gem::Requirement
|
|
15
15
|
requirements:
|
|
16
|
-
- - "
|
|
16
|
+
- - ">="
|
|
17
17
|
- !ruby/object:Gem::Version
|
|
18
18
|
version: '1.0'
|
|
19
19
|
type: :runtime
|
|
20
20
|
prerelease: false
|
|
21
21
|
version_requirements: !ruby/object:Gem::Requirement
|
|
22
22
|
requirements:
|
|
23
|
-
- - "
|
|
23
|
+
- - ">="
|
|
24
24
|
- !ruby/object:Gem::Version
|
|
25
25
|
version: '1.0'
|
|
26
26
|
- !ruby/object:Gem::Dependency
|