Skip to content

Commit fe2f1e1

Browse files
committed
Eliminate hardcoded type params such as :Elem, :K, :V
Always use type names from RBS::DefinitionBuilder. Array[Elem] will be changed to Array[E] in rbs > 4.1.0.pre.1
1 parent 5616268 commit fe2f1e1

3 files changed

Lines changed: 76 additions & 27 deletions

File tree

lib/repl_type_completor/type_analyzer.rb

Lines changed: 7 additions & 7 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[Types.hash_key_type_param] if hash.params[Types.hash_key_type_param]
181+
values << hash.params[Types.hash_value_type_param] if hash.params[Types.hash_value_type_param]
182182
end
183183
end
184184
end
185185
if keys.empty? && values.empty?
186186
Types::InstanceType.new Hash
187187
else
188-
Types::InstanceType.new Hash, K: Types::UnionType[*keys], V: Types::UnionType[*values]
188+
Types::InstanceType.hash_with_params(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[Types.array_elem_type_param] 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, Types.array_elem_type_param => 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.hash_with_params(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[Types.array_elem_type_param] || Types::OBJECT }]
11471147
non_array = non_arrays.empty? ? nil : Types::UnionType[*non_arrays]
11481148
[array_elem, non_array]
11491149
end

lib/repl_type_completor/types.rb

Lines changed: 35 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,25 @@ def self.load_rbs_builder
5252
nil
5353
end
5454

55+
def self.array_elem_type_param
56+
(@array_elem_type_param ||= _class_type_params(Array)&.first) || :E
57+
end
58+
59+
def self.hash_type_params
60+
(@hash_type_params ||= _class_type_params(Hash)) || [:K, :V]
61+
end
62+
63+
def self.hash_key_type_param = hash_type_params&.first
64+
65+
def self.hash_value_type_param = hash_type_params&.last
66+
67+
def self._class_type_params(klass)
68+
return unless rbs_builder
69+
70+
type_name = rbs_absolute_type_name(class_name_of(klass))
71+
rbs_builder.build_instance(type_name).type_params
72+
end
73+
5574
def self.class_name_of(klass)
5675
while true
5776
name = Methods::MODULE_NAME_METHOD.bind_call klass
@@ -156,8 +175,7 @@ def self.rbs_methods(type, method_name, args_types, kwargs_type, has_block)
156175
keyrest = method_type.type.rest_keywords
157176
args = args_types
158177
if kwargs_type&.any? && keyreqs.empty? && keyopts.empty? && keyrest.nil?
159-
kw_value_type = UnionType[*kwargs_type.values]
160-
args += [InstanceType.new(Hash, K: SYMBOL, V: kw_value_type)]
178+
args += [InstanceType.hash_with_params(Types::SYMBOL, UnionType[*kwargs_type.values])]
161179
end
162180
if has_splat
163181
score += 1 if args.count(&:itself) <= reqs.size + opts.size + trailings.size
@@ -276,13 +294,13 @@ def expand_params
276294

277295
if @klass == Array
278296
type = Types.union_type_from_objects_list(@instances)
279-
{ Elem: UnionType[*params[:Elem], *type] }
297+
{ Types.array_elem_type_param => UnionType[*params[Types.array_elem_type_param], *type] }
280298
elsif @klass == Hash
281299
key = Types.union_type_from_objects_list(@instances.map(&:keys))
282300
value = Types.union_type_from_objects_list(@instances.map(&:values))
283301
{
284-
K: UnionType[*params[:K], key],
285-
V: UnionType[*params[:V], value]
302+
Types.hash_key_type_param => UnionType[*params[Types.hash_key_type_param], key],
303+
Types.hash_value_type_param => UnionType[*params[Types.hash_value_type_param], value]
286304
}
287305
else
288306
params
@@ -324,6 +342,14 @@ def inspect_without_params
324342
klass.to_s
325343
end
326344
end
345+
346+
def self.array_with_params(elem_type)
347+
new(Array, { Types.array_elem_type_param => elem_type })
348+
end
349+
350+
def self.hash_with_params(key_type, value_type)
351+
new(Hash, { Types.hash_key_type_param => key_type, Types.hash_value_type_param => value_type })
352+
end
327353
end
328354

329355
NIL = InstanceType.new NilClass
@@ -405,7 +431,7 @@ def inspect() = @types.map(&:inspect).sort.join(' | ')
405431

406432
def self.array_of(*types)
407433
type = types.size >= 2 ? UnionType[*types] : types.first || OBJECT
408-
InstanceType.new Array, Elem: type
434+
InstanceType.array_with_params(type)
409435
end
410436

411437
def self.from_rbs_type(return_type, self_type, extra_vars = {})
@@ -445,9 +471,9 @@ def self.from_rbs_type(return_type, self_type, extra_vars = {})
445471
PROC
446472
when RBS::Types::Tuple
447473
elem = UnionType[*return_type.types.map { from_rbs_type _1, self_type, extra_vars }]
448-
InstanceType.new Array, Elem: elem
474+
InstanceType.array_with_params(elem)
449475
when RBS::Types::Record
450-
InstanceType.new Hash, K: SYMBOL, V: OBJECT
476+
InstanceType.hash_with_params(Types::SYMBOL, Types::OBJECT)
451477
when RBS::Types::Literal
452478
InstanceType.new return_type.literal.class
453479
when RBS::Types::Variable
@@ -516,7 +542,7 @@ def self._match_free_variable(vars, rbs_type, value, accumulator)
516542
_match_free_variable vars, arg, v, accumulator if v
517543
end
518544
in [RBS::Types::Tuple, InstanceType] if value.klass == Array
519-
v = value.params[:Elem]
545+
v = value.params[array_elem_type_param]
520546
rbs_type.types.each do |t|
521547
_match_free_variable vars, t, v, accumulator
522548
end

test/repl_type_completor/test_types.rb

Lines changed: 34 additions & 11 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.array_with_params(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_equal "Array[#{ReplTypeCompletor::Types.array_elem_type_param}: 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,14 +51,14 @@ 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[ReplTypeCompletor::Types.array_elem_type_param].klass
55+
assert_equal BasicObject, bo_key_hash_type.params[ReplTypeCompletor::Types.hash_key_type_param].klass
56+
assert_equal BasicObject, bo_value_hash_type.params[ReplTypeCompletor::Types.hash_value_type_param].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_equal "Array[#{ReplTypeCompletor::Types.array_elem_type_param}: Integer | String]", arr_type.tap(&:params).inspect
6060
assert_equal 'Hash[unresolved]', hash_type.inspect
61-
assert_equal 'Hash[K: String, V: Symbol]', hash_type.tap(&:params).inspect
61+
assert_equal "Hash[#{ReplTypeCompletor::Types.hash_key_type_param}: String, #{ReplTypeCompletor::Types.hash_value_type_param}: Symbol]", hash_type.tap(&:params).inspect
6262
assert_equal 'Array.itself', ReplTypeCompletor::Types.type_from_object(Array).inspect
6363
assert_equal 'ReplTypeCompletor.itself', ReplTypeCompletor::Types.type_from_object(ReplTypeCompletor).inspect
6464
end
@@ -109,22 +109,45 @@ 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[ReplTypeCompletor::Types.array_elem_type_param]
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[ReplTypeCompletor::Types.array_elem_type_param].types.find { _1.klass == Hash }
118118
assert_equal 'Hash[unresolved]', hash_type.inspect
119-
assert_equal 'Hash[K: Integer, V: Float]', hash_type.tap(&:params).inspect
119+
assert_equal "Hash[#{ReplTypeCompletor::Types.hash_key_type_param}: Integer, #{ReplTypeCompletor::Types.hash_value_type_param}: Float]", hash_type.tap(&:params).inspect
120120
end
121121

122122
def test_infinite_nested_type_inspect
123123
a = []
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_equal "Array[#{ReplTypeCompletor::Types.array_elem_type_param}: Array[unresolved]]", type.tap(&:params).inspect
128+
end
129+
130+
def test_array_hash_type_params_fallback
131+
rbs_builder = ReplTypeCompletor::Types.instance_variable_get(:@rbs_builder)
132+
assert_include [:E, :Elem], ReplTypeCompletor::Types.array_elem_type_param
133+
assert_equal :K, ReplTypeCompletor::Types.hash_key_type_param
134+
assert_equal :V, ReplTypeCompletor::Types.hash_value_type_param
135+
136+
ReplTypeCompletor::Types.instance_variable_set(:@rbs_builder, nil)
137+
type_param_cach_ivars = %i[@array_elem_type_param @hash_type_params]
138+
type_param_cach_ivars.each do |ivar|
139+
assert ReplTypeCompletor::Types.instance_variable_get(ivar)
140+
ReplTypeCompletor::Types.instance_variable_set(ivar, nil)
141+
end
142+
143+
assert_equal :E, ReplTypeCompletor::Types.array_elem_type_param
144+
assert_equal :K, ReplTypeCompletor::Types.hash_key_type_param
145+
assert_equal :V, ReplTypeCompletor::Types.hash_value_type_param
146+
type_param_cach_ivars.each do |ivar|
147+
refute ReplTypeCompletor::Types.instance_variable_get(ivar)
148+
end
149+
ensure
150+
ReplTypeCompletor::Types.instance_variable_set(:@rbs_builder, rbs_builder) if rbs_builder
128151
end
129152
end
130153
end

0 commit comments

Comments
 (0)