sorbet-runtime 0.4.4788 → 0.5.5400
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/sorbet-runtime.rb +7 -2
- data/lib/types/_types.rb +17 -9
- data/lib/types/boolean.rb +1 -1
- data/lib/types/configuration.rb +37 -0
- data/lib/types/enum.rb +358 -0
- data/lib/types/private/methods/_methods.rb +0 -1
- data/lib/types/private/methods/call_validation.rb +0 -45
- data/lib/types/private/methods/decl_builder.rb +1 -29
- data/lib/types/private/methods/signature.rb +9 -9
- data/lib/types/private/methods/signature_validation.rb +1 -5
- data/lib/types/private/sealed.rb +5 -0
- data/lib/types/private/types/type_alias.rb +26 -0
- data/lib/types/private/types/void.rb +4 -3
- data/lib/types/props/_props.rb +2 -2
- data/lib/types/props/constructor.rb +24 -10
- data/lib/types/props/decorator.rb +171 -190
- data/lib/types/props/optional.rb +38 -26
- data/lib/types/props/plugin.rb +23 -1
- data/lib/types/props/pretty_printable.rb +3 -3
- data/lib/types/props/private/apply_default.rb +170 -0
- data/lib/types/props/private/setter_factory.rb +127 -0
- data/lib/types/props/serializable.rb +7 -7
- data/lib/types/props/type_validation.rb +8 -4
- data/lib/types/props/utils.rb +3 -7
- data/lib/types/props/weak_constructor.rb +47 -15
- data/lib/types/sig.rb +6 -6
- data/lib/types/types/attached_class.rb +33 -0
- data/lib/types/types/base.rb +10 -1
- data/lib/types/types/intersection.rb +1 -0
- data/lib/types/types/{opus_enum.rb → t_enum.rb} +3 -3
- data/lib/types/types/typed_enumerable.rb +1 -6
- data/lib/types/types/union.rb +1 -0
- data/lib/types/utils.rb +22 -5
- metadata +38 -8
- data/lib/types/private/error_handler.rb +0 -0
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: f4f9fd0690e5e4161f08d170c0ad34c991b419d7718cb6d3cc3db90036c35387
|
|
4
|
+
data.tar.gz: acd9cfcc9cca1df5271b927d2dd85ffa0276337276a0df1ee522fe0c55dde9a4
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: c9935807087e676840c09e8e2c43b4c3bc25639264bb8ed793a0e677fce16742db55a14362a39e701da6e63b130ffa1213717e755a98695db849dc1c5ba9dcd5
|
|
7
|
+
data.tar.gz: b0ee575a179bb1a6da3a10d3f40a16e27a94f739c28ca47bd174b9f7c854d90e5a5085bea444d715f1dc4fa12ffef98cdc98166c2af962ac06c5ff27dce0f911
|
data/lib/sorbet-runtime.rb
CHANGED
|
@@ -24,7 +24,6 @@ require_relative 'types/_types'
|
|
|
24
24
|
require_relative 'types/private/decl_state'
|
|
25
25
|
require_relative 'types/runtime_profiled'
|
|
26
26
|
require_relative 'types/private/class_utils'
|
|
27
|
-
require_relative 'types/private/error_handler'
|
|
28
27
|
require_relative 'types/private/runtime_levels'
|
|
29
28
|
require_relative 'types/private/methods/_methods'
|
|
30
29
|
require_relative 'types/sig'
|
|
@@ -43,9 +42,10 @@ require_relative 'types/types/fixed_hash'
|
|
|
43
42
|
require_relative 'types/types/intersection'
|
|
44
43
|
require_relative 'types/types/noreturn'
|
|
45
44
|
require_relative 'types/types/proc'
|
|
45
|
+
require_relative 'types/types/attached_class'
|
|
46
46
|
require_relative 'types/types/self_type'
|
|
47
47
|
require_relative 'types/types/simple'
|
|
48
|
-
require_relative 'types/types/
|
|
48
|
+
require_relative 'types/types/t_enum'
|
|
49
49
|
require_relative 'types/types/type_parameter'
|
|
50
50
|
require_relative 'types/types/typed_array'
|
|
51
51
|
require_relative 'types/types/typed_enumerator'
|
|
@@ -57,6 +57,7 @@ require_relative 'types/types/untyped'
|
|
|
57
57
|
require_relative 'types/private/types/not_typed'
|
|
58
58
|
require_relative 'types/private/types/void'
|
|
59
59
|
require_relative 'types/private/types/string_holder'
|
|
60
|
+
require_relative 'types/private/types/type_alias'
|
|
60
61
|
|
|
61
62
|
require_relative 'types/types/type_variable'
|
|
62
63
|
require_relative 'types/types/type_member'
|
|
@@ -91,13 +92,17 @@ require_relative 'types/props/decorator'
|
|
|
91
92
|
require_relative 'types/props/errors'
|
|
92
93
|
require_relative 'types/props/plugin'
|
|
93
94
|
require_relative 'types/props/utils'
|
|
95
|
+
require_relative 'types/enum'
|
|
94
96
|
# Props that run sigs statically so have to be after all the others :(
|
|
97
|
+
require_relative 'types/props/private/setter_factory'
|
|
98
|
+
require_relative 'types/props/private/apply_default'
|
|
95
99
|
require_relative 'types/props/optional'
|
|
96
100
|
require_relative 'types/props/weak_constructor'
|
|
97
101
|
require_relative 'types/props/constructor'
|
|
98
102
|
require_relative 'types/props/pretty_printable'
|
|
99
103
|
require_relative 'types/props/serializable'
|
|
100
104
|
require_relative 'types/props/type_validation'
|
|
105
|
+
|
|
101
106
|
require_relative 'types/struct'
|
|
102
107
|
|
|
103
108
|
require_relative 'types/compatibility_patches'
|
data/lib/types/_types.rb
CHANGED
|
@@ -65,6 +65,11 @@ module T
|
|
|
65
65
|
T::Types::SelfType.new
|
|
66
66
|
end
|
|
67
67
|
|
|
68
|
+
# Matches the instance type in a singleton-class context
|
|
69
|
+
def self.attached_class
|
|
70
|
+
T::Types::AttachedClassType.new
|
|
71
|
+
end
|
|
72
|
+
|
|
68
73
|
# Matches any class that subclasses or includes the provided class
|
|
69
74
|
# or module
|
|
70
75
|
def self.class_of(klass)
|
|
@@ -75,11 +80,11 @@ module T
|
|
|
75
80
|
## END OF THE METHODS TO PASS TO `sig`.
|
|
76
81
|
|
|
77
82
|
|
|
78
|
-
# Constructs a type alias. Used to create a short name for a larger
|
|
79
|
-
#
|
|
80
|
-
# needed for support by the static checker. Example usage:
|
|
83
|
+
# Constructs a type alias. Used to create a short name for a larger type. In Ruby this returns a
|
|
84
|
+
# wrapper that contains a proc that is evaluated to get the underlying type. This syntax however
|
|
85
|
+
# is needed for support by the static checker. Example usage:
|
|
81
86
|
#
|
|
82
|
-
# NilableString = T.type_alias
|
|
87
|
+
# NilableString = T.type_alias {T.nilable(String)}
|
|
83
88
|
#
|
|
84
89
|
# sig {params(arg: NilableString, default: String).returns(String)}
|
|
85
90
|
# def or_else(arg, default)
|
|
@@ -88,8 +93,14 @@ module T
|
|
|
88
93
|
#
|
|
89
94
|
# The name of the type alias is not preserved; Error messages will
|
|
90
95
|
# be printed with reference to the underlying type.
|
|
91
|
-
|
|
92
|
-
|
|
96
|
+
#
|
|
97
|
+
# TODO Remove `type` parameter. This was left in to make life easier while migrating.
|
|
98
|
+
def self.type_alias(type=nil, &blk)
|
|
99
|
+
if blk
|
|
100
|
+
T::Private::Types::TypeAlias.new(blk)
|
|
101
|
+
else
|
|
102
|
+
T::Utils.coerce(type)
|
|
103
|
+
end
|
|
93
104
|
end
|
|
94
105
|
|
|
95
106
|
# References a type paramater which was previously defined with
|
|
@@ -270,8 +281,5 @@ module T
|
|
|
270
281
|
end
|
|
271
282
|
end
|
|
272
283
|
end
|
|
273
|
-
|
|
274
|
-
# When mixed into a module, indicates that Sorbet may export the CFG for methods in that module
|
|
275
|
-
module CFGExport; end
|
|
276
284
|
end
|
|
277
285
|
# rubocop:enable PrisonGuard/UseOpusTypesShortcut
|
data/lib/types/boolean.rb
CHANGED
|
@@ -4,5 +4,5 @@
|
|
|
4
4
|
module T
|
|
5
5
|
# T::Boolean is a type alias helper for the common `T.any(TrueClass, FalseClass)`.
|
|
6
6
|
# Defined separately from _types.rb because it has a dependency on T::Types::Union.
|
|
7
|
-
Boolean = T.type_alias
|
|
7
|
+
Boolean = T.type_alias {T.any(TrueClass, FalseClass)}
|
|
8
8
|
end
|
data/lib/types/configuration.rb
CHANGED
|
@@ -356,6 +356,7 @@ module T::Configuration
|
|
|
356
356
|
String
|
|
357
357
|
Symbol
|
|
358
358
|
Time
|
|
359
|
+
T::Enum
|
|
359
360
|
}).freeze
|
|
360
361
|
|
|
361
362
|
def self.scalar_types
|
|
@@ -382,6 +383,42 @@ module T::Configuration
|
|
|
382
383
|
end
|
|
383
384
|
end
|
|
384
385
|
|
|
386
|
+
def self.enable_legacy_t_enum_migration_mode
|
|
387
|
+
@legacy_t_enum_migration_mode = true
|
|
388
|
+
end
|
|
389
|
+
def self.disable_legacy_t_enum_migration_mode
|
|
390
|
+
@legacy_t_enum_migration_mode = false
|
|
391
|
+
end
|
|
392
|
+
def self.legacy_t_enum_migration_mode?
|
|
393
|
+
@legacy_t_enum_migration_mode || false
|
|
394
|
+
end
|
|
395
|
+
|
|
396
|
+
# @param [Array] sealed_violation_whitelist An array of Regexp to validate
|
|
397
|
+
# whether inheriting /including a sealed module outside the defining module
|
|
398
|
+
# should be allowed. Useful to whitelist benign violations, like shim files
|
|
399
|
+
# generated for an autoloader.
|
|
400
|
+
def self.sealed_violation_whitelist=(sealed_violation_whitelist)
|
|
401
|
+
if @sealed_violation_whitelist != nil
|
|
402
|
+
raise ArgumentError.new("Cannot overwrite sealed_violation_whitelist after setting it")
|
|
403
|
+
end
|
|
404
|
+
|
|
405
|
+
case sealed_violation_whitelist
|
|
406
|
+
when Array
|
|
407
|
+
sealed_violation_whitelist.each do |x|
|
|
408
|
+
case x
|
|
409
|
+
when Regexp then nil
|
|
410
|
+
else raise TypeError.new("sealed_violation_whitelist accepts an Array of Regexp")
|
|
411
|
+
end
|
|
412
|
+
end
|
|
413
|
+
else
|
|
414
|
+
raise TypeError.new("sealed_violation_whitelist= accepts an Array of Regexp")
|
|
415
|
+
end
|
|
416
|
+
|
|
417
|
+
@sealed_violation_whitelist = sealed_violation_whitelist
|
|
418
|
+
end
|
|
419
|
+
def self.sealed_violation_whitelist
|
|
420
|
+
@sealed_violation_whitelist
|
|
421
|
+
end
|
|
385
422
|
|
|
386
423
|
private_class_method def self.validate_lambda_given!(value)
|
|
387
424
|
if !value.nil? && !value.respond_to?(:call)
|
data/lib/types/enum.rb
ADDED
|
@@ -0,0 +1,358 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
# typed: strict
|
|
3
|
+
|
|
4
|
+
# Enumerations allow for type-safe declarations of a fixed set of values.
|
|
5
|
+
#
|
|
6
|
+
# Every value is a singleton instance of the class (i.e. `Suit::SPADE.is_a?(Suit) == true`).
|
|
7
|
+
#
|
|
8
|
+
# Each value has a corresponding serialized value. By default this is the constant's name converted
|
|
9
|
+
# to lowercase (e.g. `Suit::Club.serialize == 'club'`); however a custom value may be passed to the
|
|
10
|
+
# constructor. Enum will `freeze` the serialized value.
|
|
11
|
+
#
|
|
12
|
+
# @example Declaring an Enum:
|
|
13
|
+
# class Suit < T::Enum
|
|
14
|
+
# enums do
|
|
15
|
+
# CLUB = new
|
|
16
|
+
# SPADE = new
|
|
17
|
+
# DIAMOND = new
|
|
18
|
+
# HEART = new
|
|
19
|
+
# end
|
|
20
|
+
# end
|
|
21
|
+
#
|
|
22
|
+
# @example Custom serialization value:
|
|
23
|
+
# class Status < T::Enum
|
|
24
|
+
# enums do
|
|
25
|
+
# READY = new('rdy')
|
|
26
|
+
# ...
|
|
27
|
+
# end
|
|
28
|
+
# end
|
|
29
|
+
#
|
|
30
|
+
# @example Accessing values:
|
|
31
|
+
# Suit::SPADE
|
|
32
|
+
#
|
|
33
|
+
# @example Converting from serialized value to enum instance:
|
|
34
|
+
# Suit.deserialize('club') == Suit::CLUB
|
|
35
|
+
#
|
|
36
|
+
# @example Using enums in type signatures:
|
|
37
|
+
# sig {params(suit: Suit).returns(Boolean)}
|
|
38
|
+
# def is_red?(suit); ...; end
|
|
39
|
+
#
|
|
40
|
+
# WARNING: Enum instances are singletons that are shared among all their users. Their internals
|
|
41
|
+
# should be kept immutable to avoid unpredictable action at a distance.
|
|
42
|
+
class T::Enum
|
|
43
|
+
extend T::Sig
|
|
44
|
+
extend T::Props::CustomType
|
|
45
|
+
|
|
46
|
+
# TODO(jez) Might want to restrict this, or make subclasses provide this type
|
|
47
|
+
SerializedVal = T.type_alias {T.untyped}
|
|
48
|
+
private_constant :SerializedVal
|
|
49
|
+
|
|
50
|
+
## Enum class methods ##
|
|
51
|
+
sig {returns(T::Array[T.attached_class])}
|
|
52
|
+
def self.values
|
|
53
|
+
if @values.nil?
|
|
54
|
+
raise "Attempting to access values of #{self.class} before it has been initialized." \
|
|
55
|
+
" Enums are not initialized until the 'enums do' block they are defined in has finished running."
|
|
56
|
+
end
|
|
57
|
+
@values
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
# Convert from serialized value to enum instance
|
|
61
|
+
#
|
|
62
|
+
# Note: It would have been nice to make this method final before people started overriding it.
|
|
63
|
+
# Note: Failed CriticalMethodsNoRuntimeTypingTest
|
|
64
|
+
sig {params(serialized_val: SerializedVal).returns(T.nilable(T.attached_class)).checked(:never)}
|
|
65
|
+
def self.try_deserialize(serialized_val)
|
|
66
|
+
if @mapping.nil?
|
|
67
|
+
raise "Attempting to access serialization map of #{self.class} before it has been initialized." \
|
|
68
|
+
" Enums are not initialized until the 'enums do' block they are defined in has finished running."
|
|
69
|
+
end
|
|
70
|
+
@mapping[serialized_val]
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
# Convert from serialized value to enum instance.
|
|
74
|
+
#
|
|
75
|
+
# Note: It would have been nice to make this method final before people started overriding it.
|
|
76
|
+
# Note: Failed CriticalMethodsNoRuntimeTypingTest
|
|
77
|
+
#
|
|
78
|
+
# @return [self]
|
|
79
|
+
# @raise [KeyError] if serialized value does not match any instance.
|
|
80
|
+
sig {overridable.params(serialized_val: SerializedVal).returns(T.attached_class).checked(:never)}
|
|
81
|
+
def self.from_serialized(serialized_val)
|
|
82
|
+
res = try_deserialize(serialized_val)
|
|
83
|
+
if res.nil?
|
|
84
|
+
raise KeyError.new("Enum #{self} key not found: #{serialized_val.inspect}")
|
|
85
|
+
end
|
|
86
|
+
res
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
# Note: It would have been nice to make this method final before people started overriding it.
|
|
90
|
+
# @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)}
|
|
92
|
+
def self.has_serialized?(serialized_val)
|
|
93
|
+
if @mapping.nil?
|
|
94
|
+
raise "Attempting to access serialization map of #{self.class} before it has been initialized." \
|
|
95
|
+
" Enums are not initialized until the 'enums do' block they are defined in has finished running."
|
|
96
|
+
end
|
|
97
|
+
@mapping.include?(serialized_val)
|
|
98
|
+
end
|
|
99
|
+
|
|
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
|
+
# Note: Failed CriticalMethodsNoRuntimeTypingTest
|
|
110
|
+
sig {params(instance: T.nilable(T::Enum)).returns(SerializedVal).checked(:never)}
|
|
111
|
+
def self.serialize(instance)
|
|
112
|
+
# This is needed otherwise if a Chalk::ODM::Document with a property of the shape
|
|
113
|
+
# T::Hash[T.nilable(MyEnum), Integer] and a value that looks like {nil => 0} is
|
|
114
|
+
# serialized, we throw the error on L102.
|
|
115
|
+
return nil if instance.nil?
|
|
116
|
+
|
|
117
|
+
if self == T::Enum
|
|
118
|
+
raise "Cannot call T::Enum.serialize directly. You must call on a specific child class."
|
|
119
|
+
end
|
|
120
|
+
if instance.class != self
|
|
121
|
+
raise "Cannot call #serialize on a value that is not an instance of #{self}."
|
|
122
|
+
end
|
|
123
|
+
instance.serialize
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
# Note: Failed CriticalMethodsNoRuntimeTypingTest
|
|
127
|
+
sig {params(mongo_value: SerializedVal).returns(T.attached_class).checked(:never)}
|
|
128
|
+
def self.deserialize(mongo_value)
|
|
129
|
+
if self == T::Enum
|
|
130
|
+
raise "Cannot call T::Enum.deserialize directly. You must call on a specific child class."
|
|
131
|
+
end
|
|
132
|
+
self.from_serialized(mongo_value)
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
## Enum instance methods ##
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
sig {returns(T.self_type)}
|
|
140
|
+
def dup
|
|
141
|
+
self
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
sig {returns(T.self_type).checked(:tests)}
|
|
145
|
+
def clone
|
|
146
|
+
self
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
# Note: Failed CriticalMethodsNoRuntimeTypingTest
|
|
150
|
+
sig {returns(SerializedVal).checked(:never)}
|
|
151
|
+
def serialize
|
|
152
|
+
assert_bound!
|
|
153
|
+
@serialized_val
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
sig {params(args: T.untyped).returns(T.untyped)}
|
|
157
|
+
def to_json(*args)
|
|
158
|
+
serialize.to_json(*args)
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
sig {returns(String)}
|
|
162
|
+
def to_s
|
|
163
|
+
inspect
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
sig {returns(String)}
|
|
167
|
+
def inspect
|
|
168
|
+
"#<#{self.class.name}::#{@const_name || '__UNINITIALIZED__'}>"
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
sig {params(other: BasicObject).returns(T.nilable(Integer))}
|
|
172
|
+
def <=>(other)
|
|
173
|
+
case other
|
|
174
|
+
when self.class
|
|
175
|
+
self.serialize <=> other.serialize
|
|
176
|
+
else
|
|
177
|
+
nil
|
|
178
|
+
end
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
# NB: Do not call this method. This exists to allow for a safe migration path in places where enum
|
|
183
|
+
# values are compared directly against string values.
|
|
184
|
+
#
|
|
185
|
+
# Ruby's string has a weird quirk where `'my_string' == obj` calls obj.==('my_string') if obj
|
|
186
|
+
# responds to the `to_str` method. It does not actually call `to_str` however.
|
|
187
|
+
#
|
|
188
|
+
# See https://ruby-doc.org/core-2.4.0/String.html#method-i-3D-3D
|
|
189
|
+
sig {returns(String)}
|
|
190
|
+
def to_str
|
|
191
|
+
msg = 'Implicit conversion of Enum instances to strings is not allowed. Call #serialize instead.'
|
|
192
|
+
if T::Configuration.legacy_t_enum_migration_mode?
|
|
193
|
+
T::Configuration.soft_assert_handler(
|
|
194
|
+
msg,
|
|
195
|
+
storytime: {class: self.class.name},
|
|
196
|
+
)
|
|
197
|
+
serialize.to_s
|
|
198
|
+
else
|
|
199
|
+
raise NoMethodError.new(msg)
|
|
200
|
+
end
|
|
201
|
+
end
|
|
202
|
+
|
|
203
|
+
sig {params(other: BasicObject).returns(T::Boolean).checked(:never)}
|
|
204
|
+
def ==(other)
|
|
205
|
+
case other
|
|
206
|
+
when String
|
|
207
|
+
if T::Configuration.legacy_t_enum_migration_mode?
|
|
208
|
+
comparison_assertion_failed(:==, other)
|
|
209
|
+
self.serialize == other
|
|
210
|
+
else
|
|
211
|
+
false
|
|
212
|
+
end
|
|
213
|
+
else
|
|
214
|
+
super(other)
|
|
215
|
+
end
|
|
216
|
+
end
|
|
217
|
+
|
|
218
|
+
sig {params(other: BasicObject).returns(T::Boolean).checked(:never)}
|
|
219
|
+
def ===(other)
|
|
220
|
+
case other
|
|
221
|
+
when String
|
|
222
|
+
if T::Configuration.legacy_t_enum_migration_mode?
|
|
223
|
+
comparison_assertion_failed(:===, other)
|
|
224
|
+
self.serialize == other
|
|
225
|
+
else
|
|
226
|
+
false
|
|
227
|
+
end
|
|
228
|
+
else
|
|
229
|
+
super(other)
|
|
230
|
+
end
|
|
231
|
+
end
|
|
232
|
+
|
|
233
|
+
sig {params(method: Symbol, other: T.untyped).void}
|
|
234
|
+
private def comparison_assertion_failed(method, other)
|
|
235
|
+
T::Configuration.soft_assert_handler(
|
|
236
|
+
'Enum to string comparison not allowed. Compare to the Enum instance directly instead. See go/enum-migration',
|
|
237
|
+
storytime: {
|
|
238
|
+
class: self.class.name,
|
|
239
|
+
self: self.inspect,
|
|
240
|
+
other: other,
|
|
241
|
+
other_class: other.class.name,
|
|
242
|
+
method: method,
|
|
243
|
+
}
|
|
244
|
+
)
|
|
245
|
+
end
|
|
246
|
+
|
|
247
|
+
|
|
248
|
+
## Private implementation ##
|
|
249
|
+
|
|
250
|
+
|
|
251
|
+
sig {params(serialized_val: SerializedVal).void}
|
|
252
|
+
private def initialize(serialized_val=nil)
|
|
253
|
+
raise 'T::Enum is abstract' if self.class == T::Enum
|
|
254
|
+
if !self.class.started_initializing?
|
|
255
|
+
raise "Must instantiate all enum values of #{self.class} inside 'enums do'."
|
|
256
|
+
end
|
|
257
|
+
if self.class.fully_initialized?
|
|
258
|
+
raise "Cannot instantiate a new enum value of #{self.class} after it has been initialized."
|
|
259
|
+
end
|
|
260
|
+
|
|
261
|
+
serialized_val = serialized_val.frozen? ? serialized_val : serialized_val.dup.freeze
|
|
262
|
+
@serialized_val = T.let(serialized_val, T.nilable(SerializedVal))
|
|
263
|
+
@const_name = T.let(nil, T.nilable(Symbol))
|
|
264
|
+
self.class._register_instance(self)
|
|
265
|
+
end
|
|
266
|
+
|
|
267
|
+
sig {returns(NilClass).checked(:never)}
|
|
268
|
+
private def assert_bound!
|
|
269
|
+
if @const_name.nil?
|
|
270
|
+
raise "Attempting to access Enum value on #{self.class} before it has been initialized." \
|
|
271
|
+
" Enums are not initialized until the 'enums do' block they are defined in has finished running."
|
|
272
|
+
end
|
|
273
|
+
end
|
|
274
|
+
|
|
275
|
+
sig {params(const_name: Symbol).void}
|
|
276
|
+
def _bind_name(const_name)
|
|
277
|
+
@const_name = const_name
|
|
278
|
+
@serialized_val = const_to_serialized_val(const_name) if @serialized_val.nil?
|
|
279
|
+
freeze
|
|
280
|
+
end
|
|
281
|
+
|
|
282
|
+
sig {params(const_name: Symbol).returns(String)}
|
|
283
|
+
private def const_to_serialized_val(const_name)
|
|
284
|
+
# Historical note: We convert to lowercase names because the majority of existing calls to
|
|
285
|
+
# `make_accessible` were arrays of lowercase strings. Doing this conversion allowed for the
|
|
286
|
+
# least amount of repetition in migrated declarations.
|
|
287
|
+
const_name.to_s.downcase.freeze
|
|
288
|
+
end
|
|
289
|
+
|
|
290
|
+
sig {returns(T::Boolean)}
|
|
291
|
+
def self.started_initializing?
|
|
292
|
+
@started_initializing = T.let(@started_initializing, T.nilable(T::Boolean))
|
|
293
|
+
@started_initializing ||= false
|
|
294
|
+
end
|
|
295
|
+
|
|
296
|
+
sig {returns(T::Boolean)}
|
|
297
|
+
def self.fully_initialized?
|
|
298
|
+
@fully_initialized = T.let(@fully_initialized, T.nilable(T::Boolean))
|
|
299
|
+
@fully_initialized ||= false
|
|
300
|
+
end
|
|
301
|
+
|
|
302
|
+
# Maintains the order in which values are defined
|
|
303
|
+
sig {params(instance: T.untyped).void}
|
|
304
|
+
def self._register_instance(instance)
|
|
305
|
+
@values ||= []
|
|
306
|
+
@values << T.cast(instance, T.attached_class)
|
|
307
|
+
end
|
|
308
|
+
|
|
309
|
+
# Entrypoint for allowing people to register new enum values.
|
|
310
|
+
# All enum values must be defined within this block.
|
|
311
|
+
sig {params(blk: T.proc.void).void}
|
|
312
|
+
def self.enums(&blk)
|
|
313
|
+
raise "enums cannot be defined for T::Enum" if self == T::Enum
|
|
314
|
+
raise "Enum #{self} was already initialized" if @fully_initialized
|
|
315
|
+
raise "Enum #{self} is still initializing" if @started_initializing
|
|
316
|
+
|
|
317
|
+
@started_initializing = true
|
|
318
|
+
|
|
319
|
+
@values = T.let(nil, T.nilable(T::Array[T.attached_class]))
|
|
320
|
+
|
|
321
|
+
yield
|
|
322
|
+
|
|
323
|
+
@mapping = T.let(nil, T.nilable(T::Hash[SerializedVal, T.attached_class]))
|
|
324
|
+
@mapping = {}
|
|
325
|
+
|
|
326
|
+
# Freeze the Enum class and bind the constant names into each of the instances.
|
|
327
|
+
self.constants(false).each do |const_name|
|
|
328
|
+
instance = self.const_get(const_name, false)
|
|
329
|
+
if !instance.is_a?(self)
|
|
330
|
+
raise "Invalid constant #{self}::#{const_name} on enum. " \
|
|
331
|
+
"All constants defined for an enum must be instances itself (e.g. `Foo = new`)."
|
|
332
|
+
end
|
|
333
|
+
|
|
334
|
+
instance._bind_name(const_name)
|
|
335
|
+
serialized = instance.serialize
|
|
336
|
+
if @mapping.include?(serialized)
|
|
337
|
+
raise "Enum values must have unique serializations. Value '#{serialized}' is repeated on #{self}."
|
|
338
|
+
end
|
|
339
|
+
@mapping[serialized] = instance
|
|
340
|
+
end
|
|
341
|
+
@values.freeze
|
|
342
|
+
@mapping.freeze
|
|
343
|
+
|
|
344
|
+
orphaned_instances = T.must(@values) - @mapping.values
|
|
345
|
+
if !orphaned_instances.empty?
|
|
346
|
+
raise "Enum values must be assigned to constants: #{orphaned_instances.map {|v| v.instance_variable_get('@serialized_val')}}"
|
|
347
|
+
end
|
|
348
|
+
|
|
349
|
+
@fully_initialized = true
|
|
350
|
+
end
|
|
351
|
+
|
|
352
|
+
sig {params(child_class: Module).void}
|
|
353
|
+
def self.inherited(child_class)
|
|
354
|
+
super
|
|
355
|
+
|
|
356
|
+
raise "Inheriting from children of T::Enum is prohibited" if self != T::Enum
|
|
357
|
+
end
|
|
358
|
+
end
|
|
@@ -302,7 +302,6 @@ module T::Private::Methods
|
|
|
302
302
|
check_level: current_declaration.checked,
|
|
303
303
|
on_failure: current_declaration.on_failure,
|
|
304
304
|
override_allow_incompatible: current_declaration.override_allow_incompatible,
|
|
305
|
-
generated: current_declaration.generated,
|
|
306
305
|
)
|
|
307
306
|
|
|
308
307
|
SignatureValidation.validate(signature)
|
|
@@ -51,10 +51,6 @@ module T::Private::Methods::CallValidation
|
|
|
51
51
|
# This method is called for every `sig`. It's critical to keep it fast and
|
|
52
52
|
# reduce number of allocations that happen here.
|
|
53
53
|
|
|
54
|
-
if method_sig.ever_failed && method_sig.generated
|
|
55
|
-
return original_method.bind(instance).call(*args, &blk)
|
|
56
|
-
end
|
|
57
|
-
|
|
58
54
|
T::Profile.typecheck_sample_attempts -= 1
|
|
59
55
|
should_sample = T::Profile.typecheck_sample_attempts == 0
|
|
60
56
|
if should_sample
|
|
@@ -252,10 +248,6 @@ module T::Private::Methods::CallValidation
|
|
|
252
248
|
T::Profile.typecheck_duration += (Process.clock_gettime(Process::CLOCK_MONOTONIC) - t1)
|
|
253
249
|
end
|
|
254
250
|
|
|
255
|
-
if method_sig.ever_failed && method_sig.generated
|
|
256
|
-
return original_method.bind(self).call(&blk)
|
|
257
|
-
end
|
|
258
|
-
|
|
259
251
|
# The following line breaks are intentional to show nice pry message
|
|
260
252
|
|
|
261
253
|
|
|
@@ -303,10 +295,6 @@ module T::Private::Methods::CallValidation
|
|
|
303
295
|
# reduce number of allocations that happen here.
|
|
304
296
|
# This method is a manually sped-up version of more general code in `validate_call`
|
|
305
297
|
|
|
306
|
-
if method_sig.ever_failed && method_sig.generated
|
|
307
|
-
return original_method.bind(self).call(arg0, &blk)
|
|
308
|
-
end
|
|
309
|
-
|
|
310
298
|
T::Profile.typecheck_sample_attempts -= 1
|
|
311
299
|
should_sample = T::Profile.typecheck_sample_attempts == 0
|
|
312
300
|
if should_sample
|
|
@@ -392,10 +380,6 @@ module T::Private::Methods::CallValidation
|
|
|
392
380
|
# reduce number of allocations that happen here.
|
|
393
381
|
# This method is a manually sped-up version of more general code in `validate_call`
|
|
394
382
|
|
|
395
|
-
if method_sig.ever_failed && method_sig.generated
|
|
396
|
-
return original_method.bind(self).call(arg0, arg1, &blk)
|
|
397
|
-
end
|
|
398
|
-
|
|
399
383
|
T::Profile.typecheck_sample_attempts -= 1
|
|
400
384
|
should_sample = T::Profile.typecheck_sample_attempts == 0
|
|
401
385
|
if should_sample
|
|
@@ -493,10 +477,6 @@ module T::Private::Methods::CallValidation
|
|
|
493
477
|
# reduce number of allocations that happen here.
|
|
494
478
|
# This method is a manually sped-up version of more general code in `validate_call`
|
|
495
479
|
|
|
496
|
-
if method_sig.ever_failed && method_sig.generated
|
|
497
|
-
return original_method.bind(self).call(arg0, arg1, arg2, &blk)
|
|
498
|
-
end
|
|
499
|
-
|
|
500
480
|
T::Profile.typecheck_sample_attempts -= 1
|
|
501
481
|
should_sample = T::Profile.typecheck_sample_attempts == 0
|
|
502
482
|
if should_sample
|
|
@@ -607,10 +587,6 @@ module T::Private::Methods::CallValidation
|
|
|
607
587
|
# reduce number of allocations that happen here.
|
|
608
588
|
# This method is a manually sped-up version of more general code in `validate_call`
|
|
609
589
|
|
|
610
|
-
if method_sig.ever_failed && method_sig.generated
|
|
611
|
-
return original_method.bind(self).call(arg0, arg1, arg2, arg3, &blk)
|
|
612
|
-
end
|
|
613
|
-
|
|
614
590
|
T::Profile.typecheck_sample_attempts -= 1
|
|
615
591
|
should_sample = T::Profile.typecheck_sample_attempts == 0
|
|
616
592
|
if should_sample
|
|
@@ -760,10 +736,6 @@ module T::Private::Methods::CallValidation
|
|
|
760
736
|
# reduce number of allocations that happen here.
|
|
761
737
|
# This method is a manually sped-up version of more general code in `validate_call`
|
|
762
738
|
|
|
763
|
-
if method_sig.ever_failed && method_sig.generated
|
|
764
|
-
return original_method.bind(self).call(&blk)
|
|
765
|
-
end
|
|
766
|
-
|
|
767
739
|
T::Profile.typecheck_sample_attempts -= 1
|
|
768
740
|
should_sample = T::Profile.typecheck_sample_attempts == 0
|
|
769
741
|
if should_sample
|
|
@@ -817,10 +789,6 @@ module T::Private::Methods::CallValidation
|
|
|
817
789
|
# reduce number of allocations that happen here.
|
|
818
790
|
# This method is a manually sped-up version of more general code in `validate_call`
|
|
819
791
|
|
|
820
|
-
if method_sig.ever_failed && method_sig.generated
|
|
821
|
-
return original_method.bind(self).call(arg0, &blk)
|
|
822
|
-
end
|
|
823
|
-
|
|
824
792
|
T::Profile.typecheck_sample_attempts -= 1
|
|
825
793
|
should_sample = T::Profile.typecheck_sample_attempts == 0
|
|
826
794
|
if should_sample
|
|
@@ -884,10 +852,6 @@ module T::Private::Methods::CallValidation
|
|
|
884
852
|
# reduce number of allocations that happen here.
|
|
885
853
|
# This method is a manually sped-up version of more general code in `validate_call`
|
|
886
854
|
|
|
887
|
-
if method_sig.ever_failed && method_sig.generated
|
|
888
|
-
return original_method.bind(self).call(arg0, arg1, &blk)
|
|
889
|
-
end
|
|
890
|
-
|
|
891
855
|
T::Profile.typecheck_sample_attempts -= 1
|
|
892
856
|
should_sample = T::Profile.typecheck_sample_attempts == 0
|
|
893
857
|
if should_sample
|
|
@@ -964,10 +928,6 @@ module T::Private::Methods::CallValidation
|
|
|
964
928
|
# reduce number of allocations that happen here.
|
|
965
929
|
# This method is a manually sped-up version of more general code in `validate_call`
|
|
966
930
|
|
|
967
|
-
if method_sig.ever_failed && method_sig.generated
|
|
968
|
-
return original_method.bind(self).call(arg0, arg1, arg2, &blk)
|
|
969
|
-
end
|
|
970
|
-
|
|
971
931
|
T::Profile.typecheck_sample_attempts -= 1
|
|
972
932
|
should_sample = T::Profile.typecheck_sample_attempts == 0
|
|
973
933
|
if should_sample
|
|
@@ -1057,10 +1017,6 @@ module T::Private::Methods::CallValidation
|
|
|
1057
1017
|
# reduce number of allocations that happen here.
|
|
1058
1018
|
# This method is a manually sped-up version of more general code in `validate_call`
|
|
1059
1019
|
|
|
1060
|
-
if method_sig.ever_failed && method_sig.generated
|
|
1061
|
-
return original_method.bind(self).call(arg0, arg1, arg2, arg3, &blk)
|
|
1062
|
-
end
|
|
1063
|
-
|
|
1064
1020
|
T::Profile.typecheck_sample_attempts -= 1
|
|
1065
1021
|
should_sample = T::Profile.typecheck_sample_attempts == 0
|
|
1066
1022
|
if should_sample
|
|
@@ -1156,7 +1112,6 @@ module T::Private::Methods::CallValidation
|
|
|
1156
1112
|
end
|
|
1157
1113
|
|
|
1158
1114
|
def self.report_error(method_sig, error_message, kind, name, type, value, caller_offset: 0)
|
|
1159
|
-
method_sig.mark_failed
|
|
1160
1115
|
caller_loc = T.must(caller_locations(3 + caller_offset, 1))[0]
|
|
1161
1116
|
definition_file, definition_line = method_sig.method.source_location
|
|
1162
1117
|
|