sorbet-runtime 0.5.5835 → 0.5.5848
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/types/_types.rb +5 -2
- data/lib/types/private/casts.rb +27 -0
- data/lib/types/private/methods/_methods.rb +27 -16
- data/lib/types/private/types/type_alias.rb +5 -0
- data/lib/types/props/constructor.rb +9 -3
- data/lib/types/props/private/setter_factory.rb +12 -2
- data/lib/types/props/weak_constructor.rb +14 -9
- data/lib/types/types/base.rb +13 -0
- data/lib/types/types/fixed_array.rb +28 -2
- data/lib/types/types/fixed_hash.rb +10 -9
- data/lib/types/types/intersection.rb +5 -0
- data/lib/types/types/simple.rb +17 -0
- data/lib/types/types/typed_array.rb +6 -1
- data/lib/types/types/typed_enumerable.rb +10 -5
- data/lib/types/types/typed_enumerator.rb +6 -1
- data/lib/types/types/typed_hash.rb +6 -1
- data/lib/types/types/typed_range.rb +6 -1
- data/lib/types/types/typed_set.rb +6 -1
- data/lib/types/types/union.rb +35 -0
- data/lib/types/utils.rb +2 -2
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4e36df8a78c0d43e49da28e22b8b3a8db6094d50227f3be131ba05133b09cfd7
|
4
|
+
data.tar.gz: 1bfe28320c26f5749aff854bfbf9616d540a5f4d458dd35bc0e1add778a7e653
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a8d0946d74e2a13eb6ffad4eb44633161da79d42b1a0e39a099a126f081e3346e6b7eecba85c50dfd333b890530a6d75bc85e7676a889fe9a1d0043198e502f6
|
7
|
+
data.tar.gz: 8e44416ca05dd56362fc4a36457885713dc02ac4b9367cddabfefd33f80c0ec087befd957cc2c5dd4a66361313c82a87dc4e86157415c50e1ede2851fceb2d91
|
data/lib/types/_types.rb
CHANGED
@@ -26,12 +26,15 @@
|
|
26
26
|
module T
|
27
27
|
# T.any(<Type>, <Type>, ...) -- matches any of the types listed
|
28
28
|
def self.any(type_a, type_b, *types)
|
29
|
-
T::
|
29
|
+
type_a = T::Utils.coerce(type_a)
|
30
|
+
type_b = T::Utils.coerce(type_b)
|
31
|
+
types = types.map {|t| T::Utils.coerce(t)} if !types.empty?
|
32
|
+
T::Types::Union::Private::Pool.union_of_types(type_a, type_b, types)
|
30
33
|
end
|
31
34
|
|
32
35
|
# Shorthand for T.any(type, NilClass)
|
33
36
|
def self.nilable(type)
|
34
|
-
T::Types::Union.
|
37
|
+
T::Types::Union::Private::Pool.union_of_types(T::Utils.coerce(type), T::Utils::Nilable::NIL_TYPE)
|
35
38
|
end
|
36
39
|
|
37
40
|
# Matches any object. In the static checker, T.untyped allows any
|
data/lib/types/private/casts.rb
CHANGED
@@ -2,6 +2,14 @@
|
|
2
2
|
# typed: false
|
3
3
|
|
4
4
|
module T::Private
|
5
|
+
# Dynamically confirm that `value` is recursively a valid value of
|
6
|
+
# type `type`, including recursively through collections. Note that
|
7
|
+
# in some cases this runtime check can be very expensive, especially
|
8
|
+
# with large collections of objects.
|
9
|
+
def self.check_type_recursive!(value, type)
|
10
|
+
T::Private::Casts.cast_recursive(value, type, cast_method: "T.check_type_recursive!")
|
11
|
+
end
|
12
|
+
|
5
13
|
module Casts
|
6
14
|
def self.cast(value, type, cast_method:)
|
7
15
|
begin
|
@@ -18,5 +26,24 @@ module T::Private
|
|
18
26
|
value
|
19
27
|
end
|
20
28
|
end
|
29
|
+
|
30
|
+
# there's a lot of shared logic with the above one, but factoring
|
31
|
+
# it out like this makes it easier to hopefully one day delete
|
32
|
+
# this one
|
33
|
+
def self.cast_recursive(value, type, cast_method:)
|
34
|
+
begin
|
35
|
+
error = T::Utils.coerce(type).error_message_for_obj_recursive(value)
|
36
|
+
return value unless error
|
37
|
+
|
38
|
+
caller_loc = T.must(caller_locations(2..2)).first
|
39
|
+
|
40
|
+
suffix = "Caller: #{T.must(caller_loc).path}:#{T.must(caller_loc).lineno}"
|
41
|
+
|
42
|
+
raise TypeError.new("#{cast_method}: #{error}\n#{suffix}")
|
43
|
+
rescue TypeError => e # raise into rescue to ensure e.backtrace is populated
|
44
|
+
T::Configuration.inline_type_error_handler(e)
|
45
|
+
value
|
46
|
+
end
|
47
|
+
end
|
21
48
|
end
|
22
49
|
end
|
@@ -206,22 +206,8 @@ module T::Private::Methods
|
|
206
206
|
# (or unwrap back to the original method).
|
207
207
|
new_method = nil
|
208
208
|
T::Private::ClassUtils.replace_method(mod, method_name) do |*args, &blk|
|
209
|
-
|
210
|
-
|
211
|
-
# to the original pre-unwound `sig` method. I guess we'll just proxy the
|
212
|
-
# call forever since we don't know who is holding onto this handle to
|
213
|
-
# replace it.
|
214
|
-
new_new_method = mod.instance_method(method_name)
|
215
|
-
if new_method == new_new_method
|
216
|
-
raise "`sig` not present for method `#{method_name}` but you're trying to run it anyways. " \
|
217
|
-
"This should only be executed if you used `alias_method` to grab a handle to a method after `sig`ing it, but that clearly isn't what you are doing. " \
|
218
|
-
"Maybe look to see if an exception was thrown in your `sig` lambda or somehow else your `sig` wasn't actually applied to the method. " \
|
219
|
-
"Contact #dev-productivity if you're really stuck."
|
220
|
-
end
|
221
|
-
return new_new_method.bind(self).call(*args, &blk)
|
222
|
-
end
|
223
|
-
|
224
|
-
method_sig = T::Private::Methods.run_sig_block_for_method(new_method)
|
209
|
+
method_sig = T::Private::Methods.maybe_run_sig_block_for_method(new_method)
|
210
|
+
method_sig ||= T::Private::Methods._handle_missing_method_signature(mod, original_method, __callee__)
|
225
211
|
|
226
212
|
# Should be the same logic as CallValidation.wrap_method_if_needed but we
|
227
213
|
# don't want that extra layer of indirection in the callstack
|
@@ -252,6 +238,31 @@ module T::Private::Methods
|
|
252
238
|
end
|
253
239
|
end
|
254
240
|
|
241
|
+
def self._handle_missing_method_signature(mod, original_method, callee)
|
242
|
+
method_sig = T::Private::Methods.signature_for_method(original_method)
|
243
|
+
aliasing_method = mod.instance_method(callee)
|
244
|
+
|
245
|
+
if method_sig && aliasing_method != original_method && aliasing_method.original_name == original_method.name
|
246
|
+
# We're handling a case where `alias` or `alias_method` was called for a
|
247
|
+
# method which had already had a `sig` applied.
|
248
|
+
#
|
249
|
+
# Note, this logic is duplicated above, make sure to keep changes in sync.
|
250
|
+
if method_sig.check_level == :always || (method_sig.check_level == :tests && T::Private::RuntimeLevels.check_tests?)
|
251
|
+
# Checked, so copy the original signature to the aliased copy.
|
252
|
+
T::Private::Methods.unwrap_method(mod, method_sig, aliasing_method)
|
253
|
+
else
|
254
|
+
# Unchecked, so just make `alias_method` behave as if it had been called pre-sig.
|
255
|
+
mod.send(:alias_method, callee, original_method.name)
|
256
|
+
end
|
257
|
+
else
|
258
|
+
raise "`sig` not present for method `#{aliasing_method.name}` but you're trying to run it anyways. " \
|
259
|
+
"This should only be executed if you used `alias_method` to grab a handle to a method after `sig`ing it, but that clearly isn't what you are doing. " \
|
260
|
+
"Maybe look to see if an exception was thrown in your `sig` lambda or somehow else your `sig` wasn't actually applied to the method."
|
261
|
+
end
|
262
|
+
|
263
|
+
method_sig
|
264
|
+
end
|
265
|
+
|
255
266
|
# Executes the `sig` block, and converts the resulting Declaration
|
256
267
|
# to a Signature.
|
257
268
|
def self.run_sig(hook_mod, method_name, original_method, declaration_block)
|
@@ -17,11 +17,16 @@ module T::Props::Constructor::DecoratorMethods
|
|
17
17
|
# checked(:never) - O(runtime object construction)
|
18
18
|
sig {params(instance: T::Props::Constructor, hash: T::Hash[Symbol, T.untyped]).returns(Integer).checked(:never)}
|
19
19
|
def construct_props_without_defaults(instance, hash)
|
20
|
-
|
20
|
+
# Use `each_pair` rather than `count` because, as of Ruby 2.6, the latter delegates to Enumerator
|
21
|
+
# and therefore allocates for each entry.
|
22
|
+
result = 0
|
23
|
+
@props_without_defaults&.each_pair do |p, setter_proc|
|
21
24
|
begin
|
22
25
|
val = hash[p]
|
23
26
|
instance.instance_exec(val, &setter_proc)
|
24
|
-
val || hash.key?(p)
|
27
|
+
if val || hash.key?(p)
|
28
|
+
result += 1
|
29
|
+
end
|
25
30
|
rescue TypeError, T::Props::InvalidValueError
|
26
31
|
if !hash.key?(p)
|
27
32
|
raise ArgumentError.new("Missing required prop `#{p}` for class `#{instance.class.name}`")
|
@@ -29,6 +34,7 @@ module T::Props::Constructor::DecoratorMethods
|
|
29
34
|
raise
|
30
35
|
end
|
31
36
|
end
|
32
|
-
end
|
37
|
+
end
|
38
|
+
result
|
33
39
|
end
|
34
40
|
end
|
@@ -52,7 +52,12 @@ module T::Props
|
|
52
52
|
end
|
53
53
|
private_class_method def self.non_nil_proc(prop, accessor_key, non_nil_type, klass, validate)
|
54
54
|
proc do |val|
|
55
|
-
|
55
|
+
# this use of recursively_valid? is intentional: unlike for
|
56
|
+
# methods, we want to make sure data at the 'edge'
|
57
|
+
# (e.g. models that go into databases or structs serialized
|
58
|
+
# from disk) are correct, so we use more thorough runtime
|
59
|
+
# checks there
|
60
|
+
if non_nil_type.recursively_valid?(val)
|
56
61
|
if validate
|
57
62
|
validate.call(prop, val)
|
58
63
|
end
|
@@ -83,7 +88,12 @@ module T::Props
|
|
83
88
|
proc do |val|
|
84
89
|
if val.nil?
|
85
90
|
instance_variable_set(accessor_key, nil)
|
86
|
-
|
91
|
+
# this use of recursively_valid? is intentional: unlike for
|
92
|
+
# methods, we want to make sure data at the 'edge'
|
93
|
+
# (e.g. models that go into databases or structs serialized
|
94
|
+
# from disk) are correct, so we use more thorough runtime
|
95
|
+
# checks there
|
96
|
+
elsif non_nil_type.recursively_valid?(val)
|
87
97
|
if validate
|
88
98
|
validate.call(prop, val)
|
89
99
|
end
|
@@ -30,14 +30,16 @@ module T::Props::WeakConstructor::DecoratorMethods
|
|
30
30
|
# checked(:never) - O(runtime object construction)
|
31
31
|
sig {params(instance: T::Props::WeakConstructor, hash: T::Hash[Symbol, T.untyped]).returns(Integer).checked(:never)}
|
32
32
|
def construct_props_without_defaults(instance, hash)
|
33
|
-
|
33
|
+
# Use `each_pair` rather than `count` because, as of Ruby 2.6, the latter delegates to Enumerator
|
34
|
+
# and therefore allocates for each entry.
|
35
|
+
result = 0
|
36
|
+
@props_without_defaults&.each_pair do |p, setter_proc|
|
34
37
|
if hash.key?(p)
|
35
38
|
instance.instance_exec(hash[p], &setter_proc)
|
36
|
-
|
37
|
-
else
|
38
|
-
false
|
39
|
+
result += 1
|
39
40
|
end
|
40
|
-
end
|
41
|
+
end
|
42
|
+
result
|
41
43
|
end
|
42
44
|
|
43
45
|
# Set values for all props that have defaults. Use the default if and only if
|
@@ -49,14 +51,17 @@ module T::Props::WeakConstructor::DecoratorMethods
|
|
49
51
|
# checked(:never) - O(runtime object construction)
|
50
52
|
sig {params(instance: T::Props::WeakConstructor, hash: T::Hash[Symbol, T.untyped]).returns(Integer).checked(:never)}
|
51
53
|
def construct_props_with_defaults(instance, hash)
|
52
|
-
|
54
|
+
# Use `each_pair` rather than `count` because, as of Ruby 2.6, the latter delegates to Enumerator
|
55
|
+
# and therefore allocates for each entry.
|
56
|
+
result = 0
|
57
|
+
@props_with_defaults&.each_pair do |p, default_struct|
|
53
58
|
if hash.key?(p)
|
54
59
|
instance.instance_exec(hash[p], &default_struct.setter_proc)
|
55
|
-
|
60
|
+
result += 1
|
56
61
|
else
|
57
62
|
default_struct.set_default(instance)
|
58
|
-
false
|
59
63
|
end
|
60
|
-
end
|
64
|
+
end
|
65
|
+
result
|
61
66
|
end
|
62
67
|
end
|
data/lib/types/types/base.rb
CHANGED
@@ -16,6 +16,11 @@ module T::Types
|
|
16
16
|
end
|
17
17
|
end
|
18
18
|
|
19
|
+
# this will be redefined in certain subclasses
|
20
|
+
def recursively_valid?(obj)
|
21
|
+
valid?(obj)
|
22
|
+
end
|
23
|
+
|
19
24
|
def valid?(obj)
|
20
25
|
raise NotImplementedError
|
21
26
|
end
|
@@ -130,6 +135,14 @@ module T::Types
|
|
130
135
|
end
|
131
136
|
end
|
132
137
|
|
138
|
+
def error_message_for_obj_recursive(obj)
|
139
|
+
if recursively_valid?(obj)
|
140
|
+
nil
|
141
|
+
else
|
142
|
+
"Expected type #{self.name}, got #{describe_obj(obj)}"
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
133
146
|
def validate!(obj)
|
134
147
|
err = error_message_for_obj(obj)
|
135
148
|
raise TypeError.new(err) if err
|
@@ -17,10 +17,36 @@ module T::Types
|
|
17
17
|
"[#{@types.join(', ')}]"
|
18
18
|
end
|
19
19
|
|
20
|
+
# @override Base
|
21
|
+
def recursively_valid?(obj)
|
22
|
+
if obj.is_a?(Array) && obj.length == @types.length
|
23
|
+
i = 0
|
24
|
+
while i < @types.length
|
25
|
+
if !@types[i].recursively_valid?(obj[i])
|
26
|
+
return false
|
27
|
+
end
|
28
|
+
i += 1
|
29
|
+
end
|
30
|
+
true
|
31
|
+
else
|
32
|
+
false
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
20
36
|
# @override Base
|
21
37
|
def valid?(obj)
|
22
|
-
obj.is_a?(Array) && obj.length == @types.length
|
23
|
-
|
38
|
+
if obj.is_a?(Array) && obj.length == @types.length
|
39
|
+
i = 0
|
40
|
+
while i < @types.length
|
41
|
+
if !@types[i].valid?(obj[i])
|
42
|
+
return false
|
43
|
+
end
|
44
|
+
i += 1
|
45
|
+
end
|
46
|
+
true
|
47
|
+
else
|
48
|
+
false
|
49
|
+
end
|
24
50
|
end
|
25
51
|
|
26
52
|
# @override Base
|
@@ -17,17 +17,18 @@ module T::Types
|
|
17
17
|
end
|
18
18
|
|
19
19
|
# @override Base
|
20
|
-
def
|
20
|
+
def recursively_valid?(obj)
|
21
21
|
return false unless obj.is_a?(Hash)
|
22
|
+
return false if @types.any? {|key, type| !type.recursively_valid?(obj[key])}
|
23
|
+
return false if obj.any? {|key, _| !@types[key]}
|
24
|
+
true
|
25
|
+
end
|
22
26
|
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
obj.
|
28
|
-
return false unless @types[key]
|
29
|
-
end
|
30
|
-
|
27
|
+
# @override Base
|
28
|
+
def valid?(obj)
|
29
|
+
return false unless obj.is_a?(Hash)
|
30
|
+
return false if @types.any? {|key, type| !type.valid?(obj[key])}
|
31
|
+
return false if obj.any? {|key, _| !@types[key]}
|
31
32
|
true
|
32
33
|
end
|
33
34
|
|
@@ -23,6 +23,11 @@ module T::Types
|
|
23
23
|
"T.all(#{@types.map(&:name).sort.join(', ')})"
|
24
24
|
end
|
25
25
|
|
26
|
+
# @override Base
|
27
|
+
def recursively_valid?(obj)
|
28
|
+
@types.all? {|type| type.recursively_valid?(obj)}
|
29
|
+
end
|
30
|
+
|
26
31
|
# @override Base
|
27
32
|
def valid?(obj)
|
28
33
|
@types.all? {|type| type.valid?(obj)}
|
data/lib/types/types/simple.rb
CHANGED
@@ -29,5 +29,22 @@ module T::Types
|
|
29
29
|
false
|
30
30
|
end
|
31
31
|
end
|
32
|
+
|
33
|
+
def to_nilable
|
34
|
+
@nilable ||= T::Types::Union.new([self, T::Utils::Nilable::NIL_TYPE])
|
35
|
+
end
|
36
|
+
|
37
|
+
module Private
|
38
|
+
module Pool
|
39
|
+
def self.type_for_module(mod)
|
40
|
+
cached = mod.instance_variable_get(:@__as_sorbet_simple_type)
|
41
|
+
return cached if cached
|
42
|
+
|
43
|
+
type = Simple.new(mod)
|
44
|
+
mod.instance_variable_set(:@__as_sorbet_simple_type, type) unless mod.frozen?
|
45
|
+
type
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
32
49
|
end
|
33
50
|
end
|
@@ -13,10 +13,15 @@ module T::Types
|
|
13
13
|
end
|
14
14
|
|
15
15
|
# @override Base
|
16
|
-
def
|
16
|
+
def recursively_valid?(obj)
|
17
17
|
obj.is_a?(Array) && super
|
18
18
|
end
|
19
19
|
|
20
|
+
# @override Base
|
21
|
+
def valid?(obj)
|
22
|
+
obj.is_a?(Array)
|
23
|
+
end
|
24
|
+
|
20
25
|
def new(*args) # rubocop:disable PrisonGuard/BanBuiltinMethodOverride
|
21
26
|
Array.new(*T.unsafe(args))
|
22
27
|
end
|
@@ -23,13 +23,18 @@ module T::Types
|
|
23
23
|
|
24
24
|
# @override Base
|
25
25
|
def valid?(obj)
|
26
|
+
obj.is_a?(Enumerable)
|
27
|
+
end
|
28
|
+
|
29
|
+
# @override Base
|
30
|
+
def recursively_valid?(obj)
|
26
31
|
return false unless obj.is_a?(Enumerable)
|
27
32
|
case obj
|
28
33
|
when Array
|
29
34
|
begin
|
30
35
|
it = 0
|
31
36
|
while it < obj.count
|
32
|
-
return false unless @type.
|
37
|
+
return false unless @type.recursively_valid?(obj[it])
|
33
38
|
it += 1
|
34
39
|
end
|
35
40
|
return true
|
@@ -42,8 +47,8 @@ module T::Types
|
|
42
47
|
value_type = types[1]
|
43
48
|
obj.each_pair do |key, val|
|
44
49
|
# Some objects (I'm looking at you Rack::Utils::HeaderHash) don't
|
45
|
-
# iterate over a [key, value] array, so we can't juse use the @type.
|
46
|
-
return false if !key_type.
|
50
|
+
# iterate over a [key, value] array, so we can't juse use the @type.recursively_valid?(v)
|
51
|
+
return false if !key_type.recursively_valid?(key) || !value_type.recursively_valid?(val)
|
47
52
|
end
|
48
53
|
return true
|
49
54
|
when Enumerator
|
@@ -54,10 +59,10 @@ module T::Types
|
|
54
59
|
# boundlessness, it does not express a type. For example `(nil...nil)` is not a T::Range[NilClass], its a range
|
55
60
|
# of unknown types (T::Range[T.untyped]).
|
56
61
|
# Similarly, `(nil...1)` is not a `T::Range[T.nilable(Integer)]`, it's a boundless range of Integer.
|
57
|
-
(obj.begin.nil? || @type.
|
62
|
+
(obj.begin.nil? || @type.recursively_valid?(obj.begin)) && (obj.end.nil? || @type.recursively_valid?(obj.end))
|
58
63
|
when Set
|
59
64
|
obj.each do |item|
|
60
|
-
return false unless @type.
|
65
|
+
return false unless @type.recursively_valid?(item)
|
61
66
|
end
|
62
67
|
|
63
68
|
return true
|
@@ -15,10 +15,15 @@ module T::Types
|
|
15
15
|
end
|
16
16
|
|
17
17
|
# @override Base
|
18
|
-
def
|
18
|
+
def recursively_valid?(obj)
|
19
19
|
obj.is_a?(Enumerator) && super
|
20
20
|
end
|
21
21
|
|
22
|
+
# @override Base
|
23
|
+
def valid?(obj)
|
24
|
+
obj.is_a?(Enumerator)
|
25
|
+
end
|
26
|
+
|
22
27
|
def new(*args, &blk) # rubocop:disable PrisonGuard/BanBuiltinMethodOverride
|
23
28
|
T.unsafe(Enumerator).new(*args, &blk)
|
24
29
|
end
|
@@ -22,10 +22,15 @@ module T::Types
|
|
22
22
|
end
|
23
23
|
|
24
24
|
# @override Base
|
25
|
-
def
|
25
|
+
def recursively_valid?(obj)
|
26
26
|
obj.is_a?(Hash) && super
|
27
27
|
end
|
28
28
|
|
29
|
+
# @override Base
|
30
|
+
def valid?(obj)
|
31
|
+
obj.is_a?(Hash)
|
32
|
+
end
|
33
|
+
|
29
34
|
def new(*args, &blk) # rubocop:disable PrisonGuard/BanBuiltinMethodOverride
|
30
35
|
Hash.new(*T.unsafe(args), &blk) # rubocop:disable PrisonGuard/RestrictHashDefaults
|
31
36
|
end
|
@@ -15,10 +15,15 @@ module T::Types
|
|
15
15
|
end
|
16
16
|
|
17
17
|
# @override Base
|
18
|
-
def
|
18
|
+
def recursively_valid?(obj)
|
19
19
|
obj.is_a?(Range) && super
|
20
20
|
end
|
21
21
|
|
22
|
+
# @override Base
|
23
|
+
def valid?(obj)
|
24
|
+
obj.is_a?(Range)
|
25
|
+
end
|
26
|
+
|
22
27
|
def new(*args) # rubocop:disable PrisonGuard/BanBuiltinMethodOverride
|
23
28
|
T.unsafe(Range).new(*args)
|
24
29
|
end
|
@@ -15,10 +15,15 @@ module T::Types
|
|
15
15
|
end
|
16
16
|
|
17
17
|
# @override Base
|
18
|
-
def
|
18
|
+
def recursively_valid?(obj)
|
19
19
|
obj.is_a?(Set) && super
|
20
20
|
end
|
21
21
|
|
22
|
+
# @override Base
|
23
|
+
def valid?(obj)
|
24
|
+
obj.is_a?(Set)
|
25
|
+
end
|
26
|
+
|
22
27
|
def new(*args) # rubocop:disable PrisonGuard/BanBuiltinMethodOverride
|
23
28
|
Set.new(*T.unsafe(args))
|
24
29
|
end
|
data/lib/types/types/union.rb
CHANGED
@@ -42,6 +42,11 @@ module T::Types
|
|
42
42
|
end
|
43
43
|
end
|
44
44
|
|
45
|
+
# @override Base
|
46
|
+
def recursively_valid?(obj)
|
47
|
+
@types.any? {|type| type.recursively_valid?(obj)}
|
48
|
+
end
|
49
|
+
|
45
50
|
# @override Base
|
46
51
|
def valid?(obj)
|
47
52
|
@types.any? {|type| type.valid?(obj)}
|
@@ -52,5 +57,35 @@ module T::Types
|
|
52
57
|
raise "This should never be reached if you're going through `subtype_of?` (and you should be)"
|
53
58
|
end
|
54
59
|
|
60
|
+
module Private
|
61
|
+
module Pool
|
62
|
+
EMPTY_ARRAY = [].freeze
|
63
|
+
private_constant :EMPTY_ARRAY
|
64
|
+
|
65
|
+
# @param type_a [T::Types::Base]
|
66
|
+
# @param type_b [T::Types::Base]
|
67
|
+
# @param types [Array] optional array of additional T::Types::Base instances
|
68
|
+
def self.union_of_types(type_a, type_b, types=EMPTY_ARRAY)
|
69
|
+
if types.empty?
|
70
|
+
# We aren't guaranteed to detect a simple `T.nilable(<Module>)` type here
|
71
|
+
# in cases where there are duplicate types, nested unions, etc.
|
72
|
+
#
|
73
|
+
# That's ok, because this is an optimization which isn't necessary for
|
74
|
+
# correctness.
|
75
|
+
if type_b == T::Utils::Nilable::NIL_TYPE && type_a.is_a?(T::Types::Simple)
|
76
|
+
type_a.to_nilable
|
77
|
+
elsif type_a == T::Utils::Nilable::NIL_TYPE && type_b.is_a?(T::Types::Simple)
|
78
|
+
type_b.to_nilable
|
79
|
+
else
|
80
|
+
Union.new([type_a, type_b])
|
81
|
+
end
|
82
|
+
else
|
83
|
+
# This can't be a `T.nilable(<Module>)` case unless there are duplicates,
|
84
|
+
# which is possible but unexpected.
|
85
|
+
Union.new([type_a, type_b] + types)
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
55
90
|
end
|
56
91
|
end
|
data/lib/types/utils.rb
CHANGED
@@ -21,7 +21,7 @@ module T::Utils
|
|
21
21
|
elsif val == ::Range
|
22
22
|
T::Range[T.untyped]
|
23
23
|
elsif val.is_a?(Module)
|
24
|
-
T::Types::Simple.
|
24
|
+
T::Types::Simple::Private::Pool.type_for_module(val)
|
25
25
|
elsif val.is_a?(::Array)
|
26
26
|
T::Types::FixedArray.new(val) # rubocop:disable PrisonGuard/UseOpusTypesShortcut
|
27
27
|
elsif val.is_a?(::Hash)
|
@@ -162,7 +162,7 @@ module T::Utils
|
|
162
162
|
elsif classes.length > 1
|
163
163
|
T::Types::Union.new(classes)
|
164
164
|
else
|
165
|
-
T::Types::Simple.
|
165
|
+
T::Types::Simple::Private::Pool.type_for_module(classes.first)
|
166
166
|
end
|
167
167
|
end
|
168
168
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sorbet-runtime
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.5.
|
4
|
+
version: 0.5.5848
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Stripe
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-07-
|
11
|
+
date: 2020-07-28 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: minitest
|