sorbet-runtime 0.5.5316 → 0.5.5956
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/sorbet-runtime.rb +10 -1
- data/lib/types/_types.rb +10 -9
- data/lib/types/compatibility_patches.rb +65 -8
- data/lib/types/configuration.rb +3 -3
- data/lib/types/enum.rb +33 -16
- data/lib/types/generic.rb +2 -2
- data/lib/types/interface_wrapper.rb +4 -4
- data/lib/types/non_forcing_constants.rb +57 -0
- data/lib/types/private/abstract/data.rb +2 -2
- data/lib/types/private/abstract/declare.rb +3 -0
- data/lib/types/private/casts.rb +27 -0
- data/lib/types/private/class_utils.rb +8 -5
- data/lib/types/private/methods/_methods.rb +73 -23
- data/lib/types/private/methods/call_validation.rb +3 -0
- data/lib/types/private/methods/signature.rb +16 -6
- data/lib/types/private/retry.rb +10 -0
- data/lib/types/private/sealed.rb +1 -1
- data/lib/types/private/types/type_alias.rb +5 -0
- data/lib/types/private/types/void.rb +4 -3
- data/lib/types/profile.rb +5 -1
- data/lib/types/props/_props.rb +1 -5
- data/lib/types/props/constructor.rb +29 -9
- data/lib/types/props/custom_type.rb +51 -27
- data/lib/types/props/decorator.rb +70 -207
- data/lib/types/props/generated_code_validation.rb +268 -0
- data/lib/types/props/has_lazily_specialized_methods.rb +92 -0
- data/lib/types/props/optional.rb +28 -28
- data/lib/types/props/plugin.rb +2 -2
- data/lib/types/props/private/apply_default.rb +170 -0
- data/lib/types/props/private/deserializer_generator.rb +165 -0
- data/lib/types/props/private/parser.rb +32 -0
- data/lib/types/props/private/serde_transform.rb +192 -0
- data/lib/types/props/private/serializer_generator.rb +77 -0
- data/lib/types/props/private/setter_factory.rb +78 -26
- data/lib/types/props/serializable.rb +126 -181
- data/lib/types/props/type_validation.rb +10 -1
- data/lib/types/props/weak_constructor.rb +51 -14
- data/lib/types/sig.rb +3 -3
- data/lib/types/types/attached_class.rb +5 -1
- 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/noreturn.rb +4 -0
- data/lib/types/types/self_type.rb +4 -0
- data/lib/types/types/simple.rb +22 -1
- data/lib/types/types/t_enum.rb +6 -1
- data/lib/types/types/type_parameter.rb +1 -1
- data/lib/types/types/typed_array.rb +7 -2
- data/lib/types/types/typed_enumerable.rb +23 -7
- data/lib/types/types/typed_enumerator.rb +7 -2
- data/lib/types/types/typed_hash.rb +8 -3
- data/lib/types/types/typed_range.rb +7 -2
- data/lib/types/types/typed_set.rb +7 -2
- data/lib/types/types/union.rb +36 -5
- data/lib/types/types/untyped.rb +4 -0
- data/lib/types/utils.rb +21 -6
- metadata +95 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 569e1e784f7d9e4c911cc92571704e406dfe981df3285218ae06b245b2e113db
|
4
|
+
data.tar.gz: 2d7b5f9878d6fe05add390255cdfe0dd70c69a77bbd06d5a32a1d02deec7f1b1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e93ae059f1d875a26242803edbae96a335a179a3ef2862ad1c2ad9c1729cb8041ec44c8fcd4520a25e33de9ff421a7edd67032579a1d60b6e8d6c649f6b6d0a1
|
7
|
+
data.tar.gz: 8b9b92b336911870b563666c7495b2f5ac52ddb3b2ec805dfcb1fbd48393dbfc63c89dd35c13f18ffeed04b7cdb9ff619591e011cf115975fc5392b6ab01be2b
|
data/lib/sorbet-runtime.rb
CHANGED
@@ -80,6 +80,7 @@ require_relative 'types/private/abstract/hooks'
|
|
80
80
|
require_relative 'types/private/casts'
|
81
81
|
require_relative 'types/private/methods/decl_builder'
|
82
82
|
require_relative 'types/private/methods/signature'
|
83
|
+
require_relative 'types/private/retry'
|
83
84
|
require_relative 'types/utils'
|
84
85
|
require_relative 'types/boolean'
|
85
86
|
|
@@ -92,16 +93,24 @@ require_relative 'types/props/decorator'
|
|
92
93
|
require_relative 'types/props/errors'
|
93
94
|
require_relative 'types/props/plugin'
|
94
95
|
require_relative 'types/props/utils'
|
96
|
+
require_relative 'types/enum'
|
95
97
|
# Props that run sigs statically so have to be after all the others :(
|
96
98
|
require_relative 'types/props/private/setter_factory'
|
99
|
+
require_relative 'types/props/private/apply_default'
|
100
|
+
require_relative 'types/props/has_lazily_specialized_methods'
|
97
101
|
require_relative 'types/props/optional'
|
98
102
|
require_relative 'types/props/weak_constructor'
|
99
103
|
require_relative 'types/props/constructor'
|
100
104
|
require_relative 'types/props/pretty_printable'
|
105
|
+
require_relative 'types/props/private/serde_transform'
|
106
|
+
require_relative 'types/props/private/deserializer_generator'
|
107
|
+
require_relative 'types/props/private/serializer_generator'
|
101
108
|
require_relative 'types/props/serializable'
|
102
109
|
require_relative 'types/props/type_validation'
|
110
|
+
require_relative 'types/props/private/parser'
|
111
|
+
require_relative 'types/props/generated_code_validation'
|
103
112
|
|
104
113
|
require_relative 'types/struct'
|
105
|
-
require_relative 'types/
|
114
|
+
require_relative 'types/non_forcing_constants'
|
106
115
|
|
107
116
|
require_relative 'types/compatibility_patches'
|
data/lib/types/_types.rb
CHANGED
@@ -1,7 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
# typed: true
|
3
3
|
# This is where we define the shortcuts, so we can't use them here
|
4
|
-
# rubocop:disable PrisonGuard/UseOpusTypesShortcut
|
5
4
|
|
6
5
|
# _____
|
7
6
|
# |_ _| _ _ __ ___ ___
|
@@ -26,23 +25,26 @@
|
|
26
25
|
module T
|
27
26
|
# T.any(<Type>, <Type>, ...) -- matches any of the types listed
|
28
27
|
def self.any(type_a, type_b, *types)
|
29
|
-
T::
|
28
|
+
type_a = T::Utils.coerce(type_a)
|
29
|
+
type_b = T::Utils.coerce(type_b)
|
30
|
+
types = types.map {|t| T::Utils.coerce(t)} if !types.empty?
|
31
|
+
T::Types::Union::Private::Pool.union_of_types(type_a, type_b, types)
|
30
32
|
end
|
31
33
|
|
32
34
|
# Shorthand for T.any(type, NilClass)
|
33
35
|
def self.nilable(type)
|
34
|
-
T::Types::Union.
|
36
|
+
T::Types::Union::Private::Pool.union_of_types(T::Utils.coerce(type), T::Utils::Nilable::NIL_TYPE)
|
35
37
|
end
|
36
38
|
|
37
39
|
# Matches any object. In the static checker, T.untyped allows any
|
38
40
|
# method calls or operations.
|
39
41
|
def self.untyped
|
40
|
-
T::Types::Untyped
|
42
|
+
T::Types::Untyped::Private::INSTANCE
|
41
43
|
end
|
42
44
|
|
43
45
|
# Indicates a function never returns (e.g. "Kernel#raise")
|
44
46
|
def self.noreturn
|
45
|
-
T::Types::NoReturn
|
47
|
+
T::Types::NoReturn::Private::INSTANCE
|
46
48
|
end
|
47
49
|
|
48
50
|
# T.all(<Type>, <Type>, ...) -- matches an object that has all of the types listed
|
@@ -62,12 +64,12 @@ module T
|
|
62
64
|
|
63
65
|
# Matches `self`:
|
64
66
|
def self.self_type
|
65
|
-
T::Types::SelfType
|
67
|
+
T::Types::SelfType::Private::INSTANCE
|
66
68
|
end
|
67
69
|
|
68
70
|
# Matches the instance type in a singleton-class context
|
69
71
|
def self.attached_class
|
70
|
-
T::Types::AttachedClassType
|
72
|
+
T::Types::AttachedClassType::Private::INSTANCE
|
71
73
|
end
|
72
74
|
|
73
75
|
# Matches any class that subclasses or includes the provided class
|
@@ -103,7 +105,7 @@ module T
|
|
103
105
|
end
|
104
106
|
end
|
105
107
|
|
106
|
-
# References a type
|
108
|
+
# References a type parameter which was previously defined with
|
107
109
|
# `type_parameters`.
|
108
110
|
#
|
109
111
|
# This is used for generic methods. Example usage:
|
@@ -282,4 +284,3 @@ module T
|
|
282
284
|
end
|
283
285
|
end
|
284
286
|
end
|
285
|
-
# rubocop:enable PrisonGuard/UseOpusTypesShortcut
|
@@ -4,7 +4,8 @@
|
|
4
4
|
require_relative 'private/methods/_methods'
|
5
5
|
|
6
6
|
# Work around an interaction bug with sorbet-runtime and rspec-mocks,
|
7
|
-
# which occurs when using *_any_instance_of
|
7
|
+
# which occurs when using message expectations (*_any_instance_of,
|
8
|
+
# expect, allow) and and_call_original.
|
8
9
|
#
|
9
10
|
# When a sig is defined, sorbet-runtime will replace the sigged method
|
10
11
|
# with a wrapper that, upon first invocation, re-wraps the method with a faster
|
@@ -22,17 +23,73 @@ require_relative 'private/methods/_methods'
|
|
22
23
|
#
|
23
24
|
# We work around this by forcing re-wrapping before rspec stores a reference
|
24
25
|
# to the method.
|
25
|
-
if defined? ::RSpec::Mocks
|
26
|
+
if defined? ::RSpec::Mocks
|
26
27
|
module T
|
27
28
|
module CompatibilityPatches
|
28
|
-
module
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
29
|
+
module RSpecCompatibility
|
30
|
+
module RecorderExtensions
|
31
|
+
def observe!(method_name)
|
32
|
+
method = @klass.instance_method(method_name.to_sym)
|
33
|
+
T::Private::Methods.maybe_run_sig_block_for_method(method)
|
34
|
+
super(method_name)
|
35
|
+
end
|
33
36
|
end
|
37
|
+
::RSpec::Mocks::AnyInstance::Recorder.prepend(RecorderExtensions) if defined?(::RSpec::Mocks::AnyInstance::Recorder)
|
38
|
+
|
39
|
+
module MethodDoubleExtensions
|
40
|
+
def initialize(object, method_name, proxy)
|
41
|
+
if ::Kernel.instance_method(:respond_to?).bind(object).call(method_name, true)
|
42
|
+
method = ::RSpec::Support.method_handle_for(object, method_name)
|
43
|
+
T::Private::Methods.maybe_run_sig_block_for_method(method)
|
44
|
+
end
|
45
|
+
super(object, method_name, proxy)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
::RSpec::Mocks::MethodDouble.prepend(MethodDoubleExtensions) if defined?(::RSpec::Mocks::MethodDouble)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
# Work around for sorbet-runtime wrapped methods.
|
55
|
+
#
|
56
|
+
# When a sig is defined, sorbet-runtime will replace the sigged method
|
57
|
+
# with a wrapper. Those wrapper methods look like `foo(*args, &blk)`
|
58
|
+
# so that wrappers can handle and pass on all the arguments supplied.
|
59
|
+
#
|
60
|
+
# However, that creates a problem with runtime reflection on the methods,
|
61
|
+
# since when a sigged method is introspected, it will always return its
|
62
|
+
# `arity` as `-1`, its `parameters` as `[[:rest, :args], [:block, :blk]]`,
|
63
|
+
# and its `source_location` as `[<some_file_in_sorbet>, <some_line_number>]`.
|
64
|
+
#
|
65
|
+
# This might be a problem for some applications that rely on getting the
|
66
|
+
# correct information from these methods.
|
67
|
+
#
|
68
|
+
# This compatibility module, when prepended to the `Method` class, would fix
|
69
|
+
# the return values of `arity`, `parameters` and `source_location`.
|
70
|
+
#
|
71
|
+
# @example
|
72
|
+
# require 'sorbet-runtime'
|
73
|
+
# ::Method.prepend(T::CompatibilityPatches::MethodExtensions)
|
74
|
+
module T
|
75
|
+
module CompatibilityPatches
|
76
|
+
module MethodExtensions
|
77
|
+
def arity
|
78
|
+
arity = super
|
79
|
+
return arity if arity != -1 || self.is_a?(Proc)
|
80
|
+
sig = T::Private::Methods.signature_for_method(self)
|
81
|
+
sig ? sig.method.arity : arity
|
82
|
+
end
|
83
|
+
|
84
|
+
def source_location
|
85
|
+
sig = T::Private::Methods.signature_for_method(self)
|
86
|
+
sig ? sig.method.source_location : super
|
87
|
+
end
|
88
|
+
|
89
|
+
def parameters
|
90
|
+
sig = T::Private::Methods.signature_for_method(self)
|
91
|
+
sig ? sig.method.parameters : super
|
34
92
|
end
|
35
|
-
::RSpec::Mocks::AnyInstance::Recorder.prepend(RecorderExtensions)
|
36
93
|
end
|
37
94
|
end
|
38
95
|
end
|
data/lib/types/configuration.rb
CHANGED
@@ -248,7 +248,7 @@ module T::Configuration
|
|
248
248
|
end
|
249
249
|
|
250
250
|
private_class_method def self.log_info_handler_default(str, extra)
|
251
|
-
puts "#{str}, extra: #{extra}"
|
251
|
+
puts "#{str}, extra: #{extra}"
|
252
252
|
end
|
253
253
|
|
254
254
|
def self.log_info_handler(str, extra)
|
@@ -282,7 +282,7 @@ module T::Configuration
|
|
282
282
|
end
|
283
283
|
|
284
284
|
private_class_method def self.soft_assert_handler_default(str, extra)
|
285
|
-
puts "#{str}, extra: #{extra}"
|
285
|
+
puts "#{str}, extra: #{extra}"
|
286
286
|
end
|
287
287
|
|
288
288
|
def self.soft_assert_handler(str, extra)
|
@@ -336,7 +336,7 @@ module T::Configuration
|
|
336
336
|
# T::Configuration.scalar_types = ["NilClass", "TrueClass", "FalseClass", ...]
|
337
337
|
def self.scalar_types=(values)
|
338
338
|
if values.nil?
|
339
|
-
@
|
339
|
+
@scalar_types = values
|
340
340
|
else
|
341
341
|
bad_values = values.select {|v| v.class != String}
|
342
342
|
unless bad_values.empty?
|
data/lib/types/enum.rb
CHANGED
@@ -57,6 +57,17 @@ class T::Enum
|
|
57
57
|
@values
|
58
58
|
end
|
59
59
|
|
60
|
+
# This exists for compatibility with the interface of `Hash` & mostly to support
|
61
|
+
# the HashEachMethods Rubocop.
|
62
|
+
sig {params(blk: T.nilable(T.proc.params(arg0: T.attached_class).void)).returns(T.any(T::Enumerator[T.attached_class], T::Array[T.attached_class]))}
|
63
|
+
def self.each_value(&blk)
|
64
|
+
if blk
|
65
|
+
values.each(&blk)
|
66
|
+
else
|
67
|
+
values.each
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
60
71
|
# Convert from serialized value to enum instance
|
61
72
|
#
|
62
73
|
# Note: It would have been nice to make this method final before people started overriding it.
|
@@ -88,7 +99,7 @@ class T::Enum
|
|
88
99
|
|
89
100
|
# Note: It would have been nice to make this method final before people started overriding it.
|
90
101
|
# @return [Boolean] Does the given serialized value correspond with any of this enum's values.
|
91
|
-
sig {overridable.params(serialized_val: SerializedVal).returns(T::Boolean)}
|
102
|
+
sig {overridable.params(serialized_val: SerializedVal).returns(T::Boolean).checked(:never)}
|
92
103
|
def self.has_serialized?(serialized_val)
|
93
104
|
if @mapping.nil?
|
94
105
|
raise "Attempting to access serialization map of #{self.class} before it has been initialized." \
|
@@ -97,17 +108,8 @@ class T::Enum
|
|
97
108
|
@mapping.include?(serialized_val)
|
98
109
|
end
|
99
110
|
|
100
|
-
|
101
|
-
## T::Props::CustomType
|
102
|
-
|
103
|
-
# Note: Failed CriticalMethodsNoRuntimeTypingTest
|
104
|
-
sig {params(value: T.untyped).returns(T::Boolean).checked(:never)}
|
105
|
-
def self.instance?(value)
|
106
|
-
value.is_a?(self)
|
107
|
-
end
|
108
|
-
|
109
111
|
# Note: Failed CriticalMethodsNoRuntimeTypingTest
|
110
|
-
sig {params(instance: T.nilable(T::Enum)).returns(SerializedVal).checked(:never)}
|
112
|
+
sig {override.params(instance: T.nilable(T::Enum)).returns(SerializedVal).checked(:never)}
|
111
113
|
def self.serialize(instance)
|
112
114
|
# This is needed otherwise if a Chalk::ODM::Document with a property of the shape
|
113
115
|
# T::Hash[T.nilable(MyEnum), Integer] and a value that looks like {nil => 0} is
|
@@ -124,7 +126,7 @@ class T::Enum
|
|
124
126
|
end
|
125
127
|
|
126
128
|
# Note: Failed CriticalMethodsNoRuntimeTypingTest
|
127
|
-
sig {params(mongo_value: SerializedVal).returns(T.attached_class).checked(:never)}
|
129
|
+
sig {override.params(mongo_value: SerializedVal).returns(T.attached_class).checked(:never)}
|
128
130
|
def self.deserialize(mongo_value)
|
129
131
|
if self == T::Enum
|
130
132
|
raise "Cannot call T::Enum.deserialize directly. You must call on a specific child class."
|
@@ -249,7 +251,7 @@ class T::Enum
|
|
249
251
|
|
250
252
|
|
251
253
|
sig {params(serialized_val: SerializedVal).void}
|
252
|
-
|
254
|
+
def initialize(serialized_val=nil)
|
253
255
|
raise 'T::Enum is abstract' if self.class == T::Enum
|
254
256
|
if !self.class.started_initializing?
|
255
257
|
raise "Must instantiate all enum values of #{self.class} inside 'enums do'."
|
@@ -261,6 +263,7 @@ class T::Enum
|
|
261
263
|
serialized_val = serialized_val.frozen? ? serialized_val : serialized_val.dup.freeze
|
262
264
|
@serialized_val = T.let(serialized_val, T.nilable(SerializedVal))
|
263
265
|
@const_name = T.let(nil, T.nilable(Symbol))
|
266
|
+
self.class._register_instance(self)
|
264
267
|
end
|
265
268
|
|
266
269
|
sig {returns(NilClass).checked(:never)}
|
@@ -298,6 +301,13 @@ class T::Enum
|
|
298
301
|
@fully_initialized ||= false
|
299
302
|
end
|
300
303
|
|
304
|
+
# Maintains the order in which values are defined
|
305
|
+
sig {params(instance: T.untyped).void}
|
306
|
+
def self._register_instance(instance)
|
307
|
+
@values ||= []
|
308
|
+
@values << T.cast(instance, T.attached_class)
|
309
|
+
end
|
310
|
+
|
301
311
|
# Entrypoint for allowing people to register new enum values.
|
302
312
|
# All enum values must be defined within this block.
|
303
313
|
sig {params(blk: T.proc.void).void}
|
@@ -308,13 +318,14 @@ class T::Enum
|
|
308
318
|
|
309
319
|
@started_initializing = true
|
310
320
|
|
321
|
+
@values = T.let(nil, T.nilable(T::Array[T.attached_class]))
|
322
|
+
|
311
323
|
yield
|
312
324
|
|
313
|
-
@values = T.let(nil, T.nilable(T::Array[T.attached_class]))
|
314
325
|
@mapping = T.let(nil, T.nilable(T::Hash[SerializedVal, T.attached_class]))
|
326
|
+
@mapping = {}
|
315
327
|
|
316
328
|
# Freeze the Enum class and bind the constant names into each of the instances.
|
317
|
-
@mapping = {}
|
318
329
|
self.constants(false).each do |const_name|
|
319
330
|
instance = self.const_get(const_name, false)
|
320
331
|
if !instance.is_a?(self)
|
@@ -329,8 +340,14 @@ class T::Enum
|
|
329
340
|
end
|
330
341
|
@mapping[serialized] = instance
|
331
342
|
end
|
332
|
-
@values
|
343
|
+
@values.freeze
|
333
344
|
@mapping.freeze
|
345
|
+
|
346
|
+
orphaned_instances = T.must(@values) - @mapping.values
|
347
|
+
if !orphaned_instances.empty?
|
348
|
+
raise "Enum values must be assigned to constants: #{orphaned_instances.map {|v| v.instance_variable_get('@serialized_val')}}"
|
349
|
+
end
|
350
|
+
|
334
351
|
@fully_initialized = true
|
335
352
|
end
|
336
353
|
|
data/lib/types/generic.rb
CHANGED
@@ -14,10 +14,10 @@ module T::Generic
|
|
14
14
|
end
|
15
15
|
|
16
16
|
def type_member(variance=:invariant, fixed: nil, lower: T.untyped, upper: BasicObject)
|
17
|
-
T::Types::TypeMember.new(variance)
|
17
|
+
T::Types::TypeMember.new(variance)
|
18
18
|
end
|
19
19
|
|
20
20
|
def type_template(variance=:invariant, fixed: nil, lower: T.untyped, upper: BasicObject)
|
21
|
-
T::Types::TypeTemplate.new(variance)
|
21
|
+
T::Types::TypeTemplate.new(variance)
|
22
22
|
end
|
23
23
|
end
|
@@ -83,11 +83,11 @@ class T::InterfaceWrapper
|
|
83
83
|
end
|
84
84
|
end
|
85
85
|
|
86
|
-
def kind_of?(other)
|
86
|
+
def kind_of?(other)
|
87
87
|
is_a?(other)
|
88
88
|
end
|
89
89
|
|
90
|
-
def is_a?(other)
|
90
|
+
def is_a?(other)
|
91
91
|
if !other.is_a?(Module)
|
92
92
|
raise TypeError.new("class or module required")
|
93
93
|
end
|
@@ -99,13 +99,13 @@ class T::InterfaceWrapper
|
|
99
99
|
|
100
100
|
# Prefixed because we're polluting the namespace of the interface we're wrapping, and we don't
|
101
101
|
# want anyone else (besides dynamic_cast) calling it.
|
102
|
-
def __target_obj_DO_NOT_USE
|
102
|
+
def __target_obj_DO_NOT_USE # rubocop:disable Naming/MethodName
|
103
103
|
@target_obj
|
104
104
|
end
|
105
105
|
|
106
106
|
# Prefixed because we're polluting the namespace of the interface we're wrapping, and we don't
|
107
107
|
# want anyone else (besides wrapped_dynamic_cast) calling it.
|
108
|
-
def __interface_mod_DO_NOT_USE
|
108
|
+
def __interface_mod_DO_NOT_USE # rubocop:disable Naming/MethodName
|
109
109
|
@interface_mod
|
110
110
|
end
|
111
111
|
|
@@ -0,0 +1,57 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
# typed: strict
|
3
|
+
|
4
|
+
module T::NonForcingConstants
|
5
|
+
# NOTE: This method is documented on the RBI in Sorbet's payload, so that it
|
6
|
+
# shows up in the hover/completion documentation via LSP.
|
7
|
+
T::Sig::WithoutRuntime.sig {params(val: BasicObject, klass: String, package: T.nilable(String)).returns(T::Boolean)}
|
8
|
+
def self.non_forcing_is_a?(val, klass, package: nil)
|
9
|
+
# TODO(gdritter): once we have a runtime implementation of
|
10
|
+
# packages, we'll need to actually handle the `package` argument
|
11
|
+
# here.
|
12
|
+
method_name = "T::NonForcingConstants.non_forcing_is_a?"
|
13
|
+
if klass.empty?
|
14
|
+
raise ArgumentError.new("The string given to `#{method_name}` must not be empty")
|
15
|
+
end
|
16
|
+
|
17
|
+
current_klass = T.let(nil, T.nilable(Module))
|
18
|
+
current_prefix = T.let(nil, T.nilable(String))
|
19
|
+
|
20
|
+
parts = klass.split('::')
|
21
|
+
parts.each do |part|
|
22
|
+
if current_klass.nil?
|
23
|
+
# First iteration
|
24
|
+
if part != "" && package.nil?
|
25
|
+
# if we've supplied a package, we're probably running in
|
26
|
+
# package mode, which means absolute references are
|
27
|
+
# meaningless
|
28
|
+
raise ArgumentError.new("The string given to `#{method_name}` must be an absolute constant reference that starts with `::`")
|
29
|
+
end
|
30
|
+
|
31
|
+
current_klass = Object
|
32
|
+
current_prefix = ''
|
33
|
+
else
|
34
|
+
if current_klass.autoload?(part)
|
35
|
+
# There's an autoload registered for that constant, which means it's not
|
36
|
+
# yet loaded. `value` can't be an instance of something not yet loaded.
|
37
|
+
return false
|
38
|
+
end
|
39
|
+
|
40
|
+
# Sorbet guarantees that the string is an absolutely resolved name.
|
41
|
+
search_inheritance_chain = false
|
42
|
+
if !current_klass.const_defined?(part, search_inheritance_chain)
|
43
|
+
return false
|
44
|
+
end
|
45
|
+
|
46
|
+
current_klass = current_klass.const_get(part)
|
47
|
+
current_prefix = "#{current_prefix}::#{part}"
|
48
|
+
|
49
|
+
if !Module.===(current_klass)
|
50
|
+
raise ArgumentError.new("#{current_prefix} is not a class or module")
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
return current_klass.===(val)
|
56
|
+
end
|
57
|
+
end
|
@@ -12,11 +12,11 @@
|
|
12
12
|
# modules that override the `hash` method with something completely broken.
|
13
13
|
module T::Private::Abstract::Data
|
14
14
|
def self.get(mod, key)
|
15
|
-
mod.instance_variable_get("@opus_abstract__#{key}")
|
15
|
+
mod.instance_variable_get("@opus_abstract__#{key}")
|
16
16
|
end
|
17
17
|
|
18
18
|
def self.set(mod, key, value)
|
19
|
-
mod.instance_variable_set("@opus_abstract__#{key}", value)
|
19
|
+
mod.instance_variable_set("@opus_abstract__#{key}", value)
|
20
20
|
end
|
21
21
|
|
22
22
|
def self.key?(mod, key)
|
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
|
@@ -33,16 +33,16 @@ module T::Private::ClassUtils
|
|
33
33
|
if @overwritten
|
34
34
|
# The original method was overwritten. Overwrite again to restore it.
|
35
35
|
T::Configuration.without_ruby_warnings do
|
36
|
-
@mod.send(:define_method, @old_method.name, @old_method)
|
36
|
+
@mod.send(:define_method, @old_method.name, @old_method)
|
37
37
|
end
|
38
38
|
else
|
39
39
|
# The original method was in an ancestor. Restore it by removing the overriding method.
|
40
|
-
@mod.send(:remove_method, @old_method.name)
|
40
|
+
@mod.send(:remove_method, @old_method.name)
|
41
41
|
end
|
42
42
|
|
43
43
|
# Restore the visibility. Note that we need to do this even when we call remove_method
|
44
44
|
# above, because the module may have set custom visibility for a method it inherited.
|
45
|
-
@mod.send(@visibility, @old_method.name)
|
45
|
+
@mod.send(@visibility, @old_method.name)
|
46
46
|
|
47
47
|
nil
|
48
48
|
end
|
@@ -97,10 +97,13 @@ module T::Private::ClassUtils
|
|
97
97
|
overwritten = original_owner == mod
|
98
98
|
T::Configuration.without_ruby_warnings do
|
99
99
|
T::Private::DeclState.current.without_on_method_added do
|
100
|
-
mod.send(:define_method, name, &blk)
|
100
|
+
mod.send(:define_method, name, &blk)
|
101
|
+
if blk.arity < 0 && mod.respond_to?(:ruby2_keywords, true)
|
102
|
+
mod.send(:ruby2_keywords, name)
|
103
|
+
end
|
101
104
|
end
|
102
105
|
end
|
103
|
-
mod.send(original_visibility, name)
|
106
|
+
mod.send(original_visibility, name)
|
104
107
|
new_method = mod.instance_method(name)
|
105
108
|
|
106
109
|
ReplacedMethod.new(mod, original_method, new_method, overwritten, original_visibility)
|