Skip to content

Commit cf89f1f

Browse files
authored
Merge pull request #77 from ruby/positional_type_params
Treat type params as positional params
2 parents 5616268 + 34f58df commit cf89f1f

3 files changed

Lines changed: 53 additions & 41 deletions

File tree

lib/repl_type_completor/type_analyzer.rb

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -177,15 +177,15 @@ def evaluate_hash(node, scope)
177177
hash = method_call hash, :to_hash, [], nil, nil, scope
178178
end
179179
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]
180+
keys << hash.params[0] if hash.params[0]
181+
values << hash.params[1] if hash.params[1]
182182
end
183183
end
184184
end
185185
if keys.empty? && values.empty?
186-
Types::InstanceType.new Hash
186+
Types::InstanceType.new(Hash)
187187
else
188-
Types::InstanceType.new Hash, K: Types::UnionType[*keys], V: Types::UnionType[*values]
188+
Types::InstanceType.new(Hash, [Types::UnionType[*keys], Types::UnionType[*values]])
189189
end
190190
end
191191

@@ -706,7 +706,7 @@ def evaluate_for_node(node, scope)
706706
inner_scope = Scope.new scope, { Scope::BREAK_RESULT => nil }
707707
ary_type = method_call collection, :to_ary, [], nil, nil, nil, name_match: false
708708
element_types = ary_type.types.filter_map do |ary|
709-
ary.params[:Elem] if ary.is_a?(Types::InstanceType) && ary.klass == Array
709+
ary.params[0] if ary.is_a?(Types::InstanceType) && ary.klass == Array
710710
end
711711
element_type = Types::UnionType[*element_types]
712712
inner_scope.conditional do |s|
@@ -761,7 +761,7 @@ def evaluate_range_node(node, scope)
761761
beg_type = evaluate node.left, scope if node.left
762762
end_type = evaluate node.right, scope if node.right
763763
elem = (Types::UnionType[*[beg_type, end_type].compact]).nonnillable
764-
Types::InstanceType.new Range, Elem: elem
764+
Types::InstanceType.new(Range, [elem])
765765
end
766766

767767
def evaluate_defined_node(node, scope)
@@ -958,7 +958,7 @@ def assign_parameters(node, scope, args, kwargs)
958958
end
959959
# node.keyword_rest is Prism::KeywordRestParameterNode or Prism::ForwardingParameterNode or Prism::NoKeywordsParameterNode
960960
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])
961+
scope[node.keyword_rest.name.to_s] = Types::InstanceType.new(Hash, [Types::SYMBOL, Types::UnionType[*kwargs.values]])
962962
end
963963
if node.block&.name
964964
# node.block is Prism::BlockParameterNode
@@ -1143,7 +1143,7 @@ def partition_to_array(value, method)
11431143
true
11441144
end
11451145
end
1146-
array_elem = arrays.empty? ? nil : Types::UnionType[*arrays.map { _1.params[:Elem] || Types::OBJECT }]
1146+
array_elem = arrays.empty? ? nil : Types::UnionType[*arrays.map { _1.params[0] || Types::OBJECT }]
11471147
non_array = non_arrays.empty? ? nil : Types::UnionType[*non_arrays]
11481148
[array_elem, non_array]
11491149
end
@@ -1152,7 +1152,7 @@ def method_call(receiver, method_name, args, kwargs, block, scope, name_match: t
11521152
methods = Types.rbs_methods receiver, method_name.to_sym, args, kwargs, !!block
11531153
block_called = false
11541154
type_breaks = methods.map do |method, given_params, method_params|
1155-
receiver_vars = receiver.is_a?(Types::InstanceType) ? receiver.params : {}
1155+
receiver_vars = receiver.is_a?(Types::InstanceType) ? receiver.named_params : {}
11561156
free_vars = method.type.free_variables - receiver_vars.keys.to_set
11571157
vars = receiver_vars.merge Types.match_free_variables(free_vars, method_params, given_params)
11581158
if block && method.block && method.block.type.respond_to?(:required_positionals)

lib/repl_type_completor/types.rb

Lines changed: 35 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,7 @@ def self.rbs_methods(type, method_name, args_types, kwargs_type, has_block)
157157
args = args_types
158158
if kwargs_type&.any? && keyreqs.empty? && keyopts.empty? && keyrest.nil?
159159
kw_value_type = UnionType[*kwargs_type.values]
160-
args += [InstanceType.new(Hash, K: SYMBOL, V: kw_value_type)]
160+
args += [InstanceType.new(Hash, [SYMBOL, kw_value_type])]
161161
end
162162
if has_splat
163163
score += 1 if args.count(&:itself) <= reqs.size + opts.size + trailings.size
@@ -270,20 +270,29 @@ def params
270270
@params ||= expand_params
271271
end
272272

273+
def named_params
274+
return {} if params.empty?
275+
if Types.rbs_builder
276+
type_name = Types.rbs_absolute_type_name(Types.class_name_of(@klass))
277+
names = Types.rbs_builder.build_instance(type_name)&.type_params rescue nil
278+
end
279+
names ? names.zip(params).to_h.compact : {}
280+
end
281+
273282
def expand_params
274-
params = @raw_params || {}
283+
params = @raw_params || []
275284
return params unless @instances
276285

277286
if @klass == Array
278287
type = Types.union_type_from_objects_list(@instances)
279-
{ Elem: UnionType[*params[:Elem], *type] }
288+
[UnionType[*params[0], *type]]
280289
elsif @klass == Hash
281290
key = Types.union_type_from_objects_list(@instances.map(&:keys))
282291
value = Types.union_type_from_objects_list(@instances.map(&:values))
283-
{
284-
K: UnionType[*params[:K], key],
285-
V: UnionType[*params[:V], value]
286-
}
292+
[
293+
UnionType[*params[0], key],
294+
UnionType[*params[1], value]
295+
]
287296
else
288297
params
289298
end
@@ -308,7 +317,12 @@ def inspect
308317
elsif params.empty?
309318
inspect_without_params
310319
else
311-
params_string = "[#{params.map { "#{_1}: #{_2.inspect}" }.join(', ')}]"
320+
named = named_params
321+
if named.empty? && !params.empty?
322+
params_string = "[#{params.map(&:inspect).join(', ')}]"
323+
else
324+
params_string = "[#{named.map { "#{_1}: #{_2.inspect}" }.join(', ')}]"
325+
end
312326
"#{inspect_without_params}#{params_string}"
313327
end
314328
end
@@ -356,18 +370,18 @@ def initialize(*types)
356370
in UnionType
357371
type.types.each(&collect)
358372
in InstanceType
359-
params, instances = (instance_types[type.klass] ||= [{}, []])
373+
params, instances = (instance_types[type.klass] ||= [[], []])
360374
type.instances&.each { instances << _1 }
361-
type.raw_params&.each do |k, v|
362-
(params[k] ||= []) << v
375+
type.raw_params&.each_with_index do |v, index|
376+
(params[index] ||= []) << v
363377
end
364378
in SingletonType
365379
singleton_types << type
366380
end
367381
end
368382
types.each(&collect)
369383
@types = singleton_types.uniq + instance_types.map do |klass, (params, instances)|
370-
params = params.transform_values { |v| UnionType[*v] }
384+
params = params.map { |v| UnionType[*v] }
371385
InstanceType.new(klass, params, instances)
372386
end
373387
end
@@ -405,7 +419,7 @@ def inspect() = @types.map(&:inspect).sort.join(' | ')
405419

406420
def self.array_of(*types)
407421
type = types.size >= 2 ? UnionType[*types] : types.first || OBJECT
408-
InstanceType.new Array, Elem: type
422+
InstanceType.new(Array, [type])
409423
end
410424

411425
def self.from_rbs_type(return_type, self_type, extra_vars = {})
@@ -445,19 +459,19 @@ def self.from_rbs_type(return_type, self_type, extra_vars = {})
445459
PROC
446460
when RBS::Types::Tuple
447461
elem = UnionType[*return_type.types.map { from_rbs_type _1, self_type, extra_vars }]
448-
InstanceType.new Array, Elem: elem
462+
InstanceType.new(Array, [elem])
449463
when RBS::Types::Record
450-
InstanceType.new Hash, K: SYMBOL, V: OBJECT
464+
InstanceType.new(Hash, [SYMBOL, OBJECT])
451465
when RBS::Types::Literal
452466
InstanceType.new return_type.literal.class
453467
when RBS::Types::Variable
454468
if extra_vars.key? return_type.name
455469
extra_vars[return_type.name]
456470
elsif self_type.is_a? InstanceType
457-
self_type.params[return_type.name] || OBJECT
471+
self_type.named_params[return_type.name] || OBJECT
458472
elsif self_type.is_a? UnionType
459473
types = self_type.types.filter_map do |t|
460-
t.params[return_type.name] if t.is_a? InstanceType
474+
t.named_params[return_type.name] if t.is_a? InstanceType
461475
end
462476
UnionType[*types]
463477
else
@@ -483,11 +497,9 @@ def self.from_rbs_type(return_type, self_type, extra_vars = {})
483497
when RBS::Types::ClassInstance
484498
klass = return_type.name.to_namespace.path.reduce(Object) { _1.const_get _2 }
485499
if return_type.args
486-
args = return_type.args.map { from_rbs_type _1, self_type, extra_vars }
487-
names = rbs_builder.build_singleton(return_type.name).type_params
488-
params = names.map.with_index { [_1, args[_2] || OBJECT] }.to_h
500+
params = return_type.args.map { from_rbs_type _1, self_type, extra_vars }
489501
end
490-
InstanceType.new klass, params || {}
502+
InstanceType.new(klass, params || [])
491503
else
492504
OBJECT
493505
end
@@ -512,11 +524,11 @@ def self._match_free_variable(vars, rbs_type, value, accumulator)
512524
in [RBS::Types::ClassInstance, InstanceType]
513525
names = rbs_builder.build_singleton(rbs_type.name).type_params
514526
names.zip(rbs_type.args).each do |name, arg|
515-
v = value.params[name]
527+
v = value.named_params[name]
516528
_match_free_variable vars, arg, v, accumulator if v
517529
end
518530
in [RBS::Types::Tuple, InstanceType] if value.klass == Array
519-
v = value.params[:Elem]
531+
v = value.params[0]
520532
rbs_type.types.each do |t|
521533
_match_free_variable vars, t, v, accumulator
522534
end

test/repl_type_completor/test_types.rb

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,14 @@ def test_type_inspect
1111
nil_type = ReplTypeCompletor::Types::NIL
1212
string_type = ReplTypeCompletor::Types::STRING
1313
true_or_false = ReplTypeCompletor::Types::UnionType[true_type, false_type]
14-
array_type = ReplTypeCompletor::Types::InstanceType.new Array, { Elem: true_or_false }
14+
array_type = ReplTypeCompletor::Types::InstanceType.new(Array, [true_or_false])
1515
assert_equal 'nil', nil_type.inspect
1616
assert_equal 'true', true_type.inspect
1717
assert_equal 'false', false_type.inspect
1818
assert_equal 'String', string_type.inspect
1919
assert_equal 'Array', ReplTypeCompletor::Types::InstanceType.new(Array).inspect
2020
assert_equal 'false | true', true_or_false.inspect
21-
assert_equal 'Array[Elem: false | true]', array_type.inspect
21+
assert_include ['Array[E: false | true]', 'Array[Elem: false | true]'], array_type.inspect
2222
assert_equal 'Array', array_type.inspect_without_params
2323
assert_equal 'Proc', ReplTypeCompletor::Types::PROC.inspect
2424
assert_equal 'Array.itself', ReplTypeCompletor::Types::SingletonType.new(Array).inspect
@@ -51,12 +51,12 @@ def bo.hash; 42; end # Needed to use this object as a hash key
5151
assert_equal Hash, hash_type.klass
5252
assert_equal Hash, bo_key_hash_type.klass
5353
assert_equal Hash, bo_value_hash_type.klass
54-
assert_equal BasicObject, bo_arr_type.params[:Elem].klass
55-
assert_equal BasicObject, bo_key_hash_type.params[:K].klass
56-
assert_equal BasicObject, bo_value_hash_type.params[:V].klass
54+
assert_equal BasicObject, bo_arr_type.params[0].klass
55+
assert_equal BasicObject, bo_key_hash_type.params[0].klass
56+
assert_equal BasicObject, bo_value_hash_type.params[1].klass
5757
assert_equal 'Object', obj_type.inspect
5858
assert_equal 'Array[unresolved]', arr_type.inspect
59-
assert_equal 'Array[Elem: Integer | String]', arr_type.tap(&:params).inspect
59+
assert_include ['Array[E: Integer | String]', 'Array[Elem: Integer | String]'], arr_type.tap(&:params).inspect
6060
assert_equal 'Hash[unresolved]', hash_type.inspect
6161
assert_equal 'Hash[K: String, V: Symbol]', hash_type.tap(&:params).inspect
6262
assert_equal 'Array.itself', ReplTypeCompletor::Types.type_from_object(Array).inspect
@@ -109,12 +109,12 @@ def test_params_lazily_expanded_on_recursive_type
109109
type = ReplTypeCompletor::Types.type_from_object a
110110
assert_equal Array, type.klass
111111
10.times do |i|
112-
elem_type = type.params[:Elem]
112+
elem_type = type.params[0]
113113
expected = i.even? ? [Array, String] : [Array, Symbol]
114114
assert_equal expected, elem_type.types.map(&:klass).sort_by(&:name)
115115
type = elem_type.types.find { _1.klass == Array }
116116
end
117-
hash_type = type.params[:Elem].types.find { _1.klass == Hash }
117+
hash_type = type.params[0].types.find { _1.klass == Hash }
118118
assert_equal 'Hash[unresolved]', hash_type.inspect
119119
assert_equal 'Hash[K: Integer, V: Float]', hash_type.tap(&:params).inspect
120120
end
@@ -124,7 +124,7 @@ def test_infinite_nested_type_inspect
124124
a << a
125125
type = ReplTypeCompletor::Types.type_from_object a
126126
assert_equal 'Array[unresolved]', type.inspect
127-
assert_equal 'Array[Elem: Array[unresolved]]', type.tap(&:params).inspect
127+
assert_include ['Array[E: Array[unresolved]]', 'Array[Elem: Array[unresolved]]'], type.tap(&:params).inspect
128128
end
129129
end
130130
end

0 commit comments

Comments
 (0)