Skip to content

Commit 4192ea1

Browse files
authored
Merge pull request #2004 from ruby/optional-generics-param
Use generic class definitions with default types in `Enumerator` and `Queue`
2 parents 684b730 + 19072d9 commit 4192ea1

File tree

8 files changed

+238
-79
lines changed

8 files changed

+238
-79
lines changed

core/enumerable.rbs

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1299,7 +1299,7 @@ module Enumerable[unchecked out Elem] : _Each[Elem]
12991299
# With no block given, returns an Enumerator.
13001300
#
13011301
def reverse_each: () { (Elem arg0) -> untyped } -> void
1302-
| () -> ::Enumerator[Elem, void]
1302+
| () -> ::Enumerator[Elem]
13031303

13041304
# <!--
13051305
# rdoc-file=enum.c
@@ -1760,7 +1760,7 @@ module Enumerable[unchecked out Elem] : _Each[Elem]
17601760
# # show pythagorean triples less than 100
17611761
# p pythagorean_triples.take_while { |*, z| z < 100 }.force
17621762
#
1763-
def lazy: () -> Enumerator::Lazy[Elem, void]
1763+
def lazy: () -> Enumerator::Lazy[Elem]
17641764

17651765
# <!--
17661766
# rdoc-file=enum.c
@@ -2092,8 +2092,8 @@ module Enumerable[unchecked out Elem] : _Each[Elem]
20922092
# pp lines
20932093
# }
20942094
#
2095-
def chunk: [U] () { (Elem elt) -> U } -> ::Enumerator[[ U, ::Array[Elem] ], void]
2096-
| () -> ::Enumerator[Elem, ::Enumerator[[ untyped, ::Array[Elem] ], void]]
2095+
def chunk: [U] () { (Elem elt) -> U } -> ::Enumerator[[ U, ::Array[Elem] ]]
2096+
| () -> ::Enumerator[Elem, ::Enumerator[[ untyped, ::Array[Elem] ]]]
20972097

20982098
# <!--
20992099
# rdoc-file=enum.c
@@ -2142,7 +2142,7 @@ module Enumerable[unchecked out Elem] : _Each[Elem]
21422142
# Enumerable#slice_when does the same, except splitting when the block returns
21432143
# `true` instead of `false`.
21442144
#
2145-
def chunk_while: () { (Elem elt_before, Elem elt_after) -> boolish } -> ::Enumerator[::Array[Elem], void]
2145+
def chunk_while: () { (Elem elt_before, Elem elt_after) -> boolish } -> ::Enumerator[::Array[Elem]]
21462146

21472147
# <!--
21482148
# rdoc-file=enum.c
@@ -2204,7 +2204,7 @@ module Enumerable[unchecked out Elem] : _Each[Elem]
22042204
# Enumerable#chunk_while does the same, except splitting when the block returns
22052205
# `false` instead of `true`.
22062206
#
2207-
def slice_when: () { (Elem elt_before, Elem elt_after) -> boolish } -> ::Enumerator[::Array[Elem], void]
2207+
def slice_when: () { (Elem elt_before, Elem elt_after) -> boolish } -> ::Enumerator[::Array[Elem]]
22082208

22092209
# <!--
22102210
# rdoc-file=enum.c
@@ -2239,8 +2239,8 @@ module Enumerable[unchecked out Elem] : _Each[Elem]
22392239
# p e.map {|ll| ll[0...-1].map {|l| l.sub(/\\\n\z/, "") }.join + ll.last }
22402240
# #=>["foo\n", "barbaz\n", "\n", "qux\n"]
22412241
#
2242-
def slice_after: (untyped pattern) -> ::Enumerator[::Array[Elem], void]
2243-
| () { (Elem elt) -> boolish } -> ::Enumerator[::Array[Elem], void]
2242+
def slice_after: (untyped pattern) -> ::Enumerator[::Array[Elem]]
2243+
| () { (Elem elt) -> boolish } -> ::Enumerator[::Array[Elem]]
22442244

22452245
# <!--
22462246
# rdoc-file=enum.c
@@ -2396,6 +2396,6 @@ module Enumerable[unchecked out Elem] : _Each[Elem]
23962396
# }
23972397
# }
23982398
#
2399-
def slice_before: (untyped pattern) -> ::Enumerator[::Array[Elem], void]
2400-
| () { (Elem elt) -> boolish } -> ::Enumerator[::Array[Elem], void]
2399+
def slice_before: (untyped pattern) -> ::Enumerator[::Array[Elem]]
2400+
| () { (Elem elt) -> boolish } -> ::Enumerator[::Array[Elem]]
24012401
end

core/enumerator.rbs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@
127127
# puts ext_each(o.to_enum) {|*x| puts x; [:b, *x] }
128128
# # => [], [:b], [1], [:b, 1], [1, 2], [:b, 1, 2], 3
129129
#
130-
class Enumerator[unchecked out Elem, out Return] < Object
130+
class Enumerator[unchecked out Elem, out Return = void] < Object
131131
include Enumerable[Elem]
132132

133133
# A convenience interface for `each` with optional block
@@ -567,7 +567,7 @@ end
567567
# # This returns an array of items like a normal enumerator does.
568568
# all_checked = active_items.select(&:checked)
569569
#
570-
class Enumerator::Lazy[out Elem, out Return] < Enumerator[Elem, Return]
570+
class Enumerator::Lazy[out Elem, out Return = void] < Enumerator[Elem, Return]
571571
# <!-- rdoc-file=enumerator.c -->
572572
# Expands `lazy` enumerator to an array. See Enumerable#to_a.
573573
#

core/enumerator/product.rbs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
%a{annotate:rdoc:skip}
2-
class Enumerator[unchecked out Elem, out Return]
2+
class Enumerator[unchecked out Elem, out Return = void]
33
# <!-- rdoc-file=enumerator.c -->
44
# Enumerator::Product generates a Cartesian product of any number of enumerable
55
# objects. Iterating over the product of enumerable objects is roughly

core/integer.rbs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1168,10 +1168,10 @@ class Integer < Numeric
11681168
| (to: Numeric, ?by: Integer) { (Integer) -> void } -> void
11691169
| (by: Numeric, ?to: Numeric) { (Numeric) -> void } -> void
11701170
| () -> Enumerator[Integer, bot]
1171-
| (Numeric limit, ?Integer step) -> Enumerator[Integer, void]
1172-
| (Numeric limit, ?Numeric step) -> Enumerator[Numeric, void]
1173-
| (to: Numeric, ?by: Integer) -> Enumerator[Integer, void]
1174-
| (by: Numeric, ?to: Numeric) -> Enumerator[Numeric, void]
1171+
| (Numeric limit, ?Integer step) -> Enumerator[Integer]
1172+
| (Numeric limit, ?Numeric step) -> Enumerator[Numeric]
1173+
| (to: Numeric, ?by: Integer) -> Enumerator[Integer]
1174+
| (by: Numeric, ?to: Numeric) -> Enumerator[Numeric]
11751175

11761176
# <!--
11771177
# rdoc-file=numeric.c

core/thread.rbs

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1545,7 +1545,7 @@ end
15451545
#
15461546
# consumer.join
15471547
#
1548-
class Thread::Queue < Object
1548+
class Thread::Queue[Elem = untyped] < Object
15491549
# <!-- rdoc-file=thread_sync.c -->
15501550
# Pushes the given `object` to the queue.
15511551
#
@@ -1661,7 +1661,7 @@ class Thread::Queue < Object
16611661
# If `timeout` seconds have passed and no data is available `nil` is returned.
16621662
# If `timeout` is `0` it returns immediately.
16631663
#
1664-
def pop: (?boolish non_block, ?timeout: _ToF?) -> untyped
1664+
def pop: (?boolish non_block, ?timeout: _ToF?) -> Elem?
16651665

16661666
# <!--
16671667
# rdoc-file=thread_sync.c
@@ -1671,7 +1671,7 @@ class Thread::Queue < Object
16711671
# -->
16721672
# Pushes the given `object` to the queue.
16731673
#
1674-
def push: (untyped obj) -> void
1674+
def push: (Elem obj) -> void
16751675

16761676
# <!--
16771677
# rdoc-file=thread_sync.rb
@@ -1692,7 +1692,7 @@ end
16921692
#
16931693
# See Thread::Queue for an example of how a Thread::SizedQueue works.
16941694
#
1695-
class Thread::SizedQueue < Thread::Queue
1695+
class Thread::SizedQueue[Elem = untyped] < Thread::Queue[Elem]
16961696
# <!--
16971697
# rdoc-file=thread_sync.rb
16981698
# - <<(object, non_block = false, timeout: nil)
@@ -1755,7 +1755,8 @@ class Thread::SizedQueue < Thread::Queue
17551755
# If `timeout` seconds have passed and no space is available `nil` is returned.
17561756
# If `timeout` is `0` it returns immediately. Otherwise it returns `self`.
17571757
#
1758-
def push: (untyped obj, ?boolish non_block, timeout: _ToF?) -> void
1758+
def push: (Elem obj, ?boolish non_block) -> void
1759+
| (Elem obj, timeout: _ToF?) -> self?
17591760
end
17601761

17611762
class ConditionVariable = Thread::ConditionVariable

lib/rbs/cli/validate.rb

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,7 @@ def validate_class_module_definition
164164
end
165165

166166
if dt = param.default_type
167-
void_type_context_validator(dt)
167+
void_type_context_validator(dt, true)
168168
no_self_type_validator(dt)
169169
no_classish_type_validator(dt)
170170
@validator.validate_type(dt, context: nil)
@@ -232,6 +232,22 @@ def validate_interface
232232
location: decl.decl.location&.aref(:type_params)
233233
)
234234

235+
decl.decl.type_params.each do |param|
236+
if ub = param.upper_bound_type
237+
void_type_context_validator(ub)
238+
no_self_type_validator(ub)
239+
no_classish_type_validator(ub)
240+
@validator.validate_type(ub, context: nil)
241+
end
242+
243+
if dt = param.default_type
244+
void_type_context_validator(dt, true)
245+
no_self_type_validator(dt)
246+
no_classish_type_validator(dt)
247+
@validator.validate_type(dt, context: nil)
248+
end
249+
end
250+
235251
decl.decl.members.each do |member|
236252
case member
237253
when AST::Members::MethodDefinition
@@ -278,7 +294,31 @@ def validate_type_alias
278294
@builder.expand_alias1(name).tap do |type|
279295
@validator.validate_type type, context: nil
280296
end
297+
281298
@validator.validate_type_alias(entry: decl)
299+
300+
@validator.validate_type_params(
301+
decl.decl.type_params,
302+
type_name: name,
303+
location: decl.decl.location&.aref(:type_params)
304+
)
305+
306+
decl.decl.type_params.each do |param|
307+
if ub = param.upper_bound_type
308+
void_type_context_validator(ub)
309+
no_self_type_validator(ub)
310+
no_classish_type_validator(ub)
311+
@validator.validate_type(ub, context: nil)
312+
end
313+
314+
if dt = param.default_type
315+
void_type_context_validator(dt, true)
316+
no_self_type_validator(dt)
317+
no_classish_type_validator(dt)
318+
@validator.validate_type(dt, context: nil)
319+
end
320+
end
321+
282322
no_self_type_validator(decl.decl.type)
283323
no_classish_type_validator(decl.decl.type)
284324
void_type_context_validator(decl.decl.type)

lib/rbs/test/type_check.rb

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -260,6 +260,13 @@ def value(val, type)
260260
Test.call(val, IS_AP, instance_class)
261261
when Types::ClassInstance
262262
klass = get_class(type.name) or return false
263+
if params = builder.env.normalized_module_class_entry(type.name.absolute!)&.type_params
264+
args = AST::TypeParam.normalize_args(params, type.args)
265+
unless args == type.args
266+
type = Types::ClassInstance.new(name: type.name, args: args, location: type.location)
267+
end
268+
end
269+
263270
case
264271
when klass == ::Array
265272
Test.call(val, IS_AP, klass) && each_sample(val).all? {|v| value(v, type.args[0]) }

0 commit comments

Comments
 (0)