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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: caa50a983c879f278cedebb80cb2d5dc064ebb4b5640ae874cdd30ca39d38d21
4
- data.tar.gz: 3fe21b818e3badd2a11a6e7195fbe9c17e0c0ea485b3ff80056b155b2c4da1ee
3
+ metadata.gz: 2dce7fd408fd473356245c6b83f8ba3240ebe39946a7e9a929cbfdde6cd138a1
4
+ data.tar.gz: 78002d089560ede6af424b70a46f10f0b65218858bdf6dee8ec63c07bf7b2b45
5
5
  SHA512:
6
- metadata.gz: d0adf80cebeb80b7ddc6b962e125ad63c487d44e91752845e4b815c99893100bfcee10c8a561d43a91111a9de8e29351bf0e0e0879ec48cc0f335aeadf2b7892
7
- data.tar.gz: 66a6c6380adc0c60a2365b3da9915d978726c3ca1404750a576341c9c63bb2679748457c606833320f43c45f299ef43166eb73176aa5432eb18d2d345af19391
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.sort
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.select { _1.start_with?(name) }.sort
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) | scope.local_variables | RESERVED_WORDS
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[:K] if hash.params[:K]
181
- values << hash.params[:V] if hash.params[:V]
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 Hash
194
+ Types::InstanceType.new(Hash)
187
195
  else
188
- Types::InstanceType.new Hash, K: Types::UnionType[*keys], V: Types::UnionType[*values]
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[:Elem] if ary.is_a?(Types::InstanceType) && ary.klass == Array
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 Range, Elem: elem
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, K: Types::SYMBOL, V: Types::UnionType[*kwargs.values])
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[:Elem] || Types::OBJECT }]
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.params : {}
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, K: SYMBOL, V: kw_value_type)]
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.union_type_from_objects(@instances.flatten(1))
272
- { Elem: UnionType[*params[:Elem], *type] }
310
+ type = Types.union_type_from_objects_list(@instances)
311
+ [UnionType[*params[0], *type]]
273
312
  elsif @klass == Hash
274
- key = Types.union_type_from_objects(@instances.map(&:keys).flatten(1))
275
- value = Types.union_type_from_objects(@instances.map(&:values).flatten(1))
276
- {
277
- K: UnionType[*params[:K], key],
278
- V: UnionType[*params[:V], value]
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
- params_string = "[#{params.map { "#{_1}: #{_2.inspect}" }.join(', ')}]"
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&.each do |k, v|
355
- (params[k] ||= []) << v
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.transform_values { |v| UnionType[*v] }
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 Array, Elem: type
480
+ InstanceType.new(Array, [type])
402
481
  end
403
482
 
404
- def self.from_rbs_type(return_type, self_type, extra_vars = {})
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(self_type.module_or_class.is_a?(Class) ? Class : Module)
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 Array, Elem: elem
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 Hash, K: SYMBOL, V: OBJECT
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? InstanceType
450
- self_type.params[return_type.name] || OBJECT
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.params[return_type.name] if t.is_a? InstanceType
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
- case return_type.name.name
463
- when :int
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
- # unimplemented
475
- OBJECT
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
- args = return_type.args.map { from_rbs_type _1, self_type, extra_vars }
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 klass, params || {}
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.params[name]
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[:Elem]
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
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ReplTypeCompletor
4
- VERSION = "0.1.15"
4
+ VERSION = "0.1.17"
5
5
  end
@@ -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.15
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