sorbet-runtime 0.5.12155 → 0.6.12632
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 +1 -1
- data/lib/types/boolean.rb +1 -1
- data/lib/types/configuration.rb +4 -14
- data/lib/types/enum.rb +35 -35
- data/lib/types/non_forcing_constants.rb +1 -1
- data/lib/types/private/abstract/data.rb +1 -1
- data/lib/types/private/methods/_methods.rb +21 -5
- data/lib/types/private/methods/call_validation.rb +3 -16
- data/lib/types/private/methods/decl_builder.rb +6 -1
- data/lib/types/private/methods/signature.rb +8 -8
- data/lib/types/private/methods/signature_validation.rb +42 -3
- data/lib/types/private/mixins/mixins.rb +1 -1
- data/lib/types/private/runtime_levels.rb +1 -1
- data/lib/types/private/sealed.rb +5 -5
- data/lib/types/props/_props.rb +6 -9
- data/lib/types/props/constructor.rb +1 -1
- data/lib/types/props/custom_type.rb +5 -5
- data/lib/types/props/decorator.rb +127 -64
- data/lib/types/props/generated_code_validation.rb +4 -4
- data/lib/types/props/has_lazily_specialized_methods.rb +13 -13
- data/lib/types/props/optional.rb +2 -2
- data/lib/types/props/pretty_printable.rb +6 -6
- data/lib/types/props/private/apply_default.rb +15 -15
- data/lib/types/props/private/deserializer_generator.rb +10 -6
- data/lib/types/props/private/serde_transform.rb +8 -8
- data/lib/types/props/private/serializer_generator.rb +9 -5
- data/lib/types/props/private/setter_factory.rb +4 -4
- data/lib/types/props/serializable.rb +14 -19
- data/lib/types/props/type_validation.rb +5 -5
- data/lib/types/props/utils.rb +1 -1
- data/lib/types/props/weak_constructor.rb +3 -3
- data/lib/types/sig.rb +2 -2
- data/lib/types/struct.rb +2 -2
- data/lib/types/types/base.rb +6 -6
- data/lib/types/types/fixed_array.rb +1 -1
- data/lib/types/types/fixed_hash.rb +6 -6
- data/lib/types/types/intersection.rb +2 -2
- data/lib/types/types/t_enum.rb +2 -0
- data/lib/types/types/union.rb +7 -7
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ea99f1dfdea91215a996829b935d3a6d4786c593ce2da19993376780aecdf4b8
|
4
|
+
data.tar.gz: 19e206d285e07d226bc7d26cfedd275dbf4163c349d80ea4d93643818f5d6a6e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2f5dedcb3fc44905b5bd3903b1f0911405dcff78ea58141261a13fa4afe4186d4437a25fcef744a1a552755c52f1e8f25b8ad999d61ca6c86e152d9d3b9bc916
|
7
|
+
data.tar.gz: 95fdd94568a68c561f66f61a89ddbab8e2e95f66c9d649df63c4a90fbfd47965aacfe380c07f9f908cd775d134b19510c22a6518bcdc61e88cf142097fac6e0d
|
data/lib/types/_types.rb
CHANGED
@@ -27,7 +27,7 @@ module T
|
|
27
27
|
def self.any(type_a, type_b, *types)
|
28
28
|
type_a = T::Utils.coerce(type_a)
|
29
29
|
type_b = T::Utils.coerce(type_b)
|
30
|
-
types = types.map {|t| T::Utils.coerce(t)} if !types.empty?
|
30
|
+
types = types.map { |t| T::Utils.coerce(t) } if !types.empty?
|
31
31
|
T::Types::Union::Private::Pool.union_of_types(type_a, type_b, types)
|
32
32
|
end
|
33
33
|
|
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 {T.any(TrueClass, FalseClass)}
|
7
|
+
Boolean = T.type_alias { T.any(TrueClass, FalseClass) }
|
8
8
|
end
|
data/lib/types/configuration.rb
CHANGED
@@ -419,12 +419,12 @@ module T::Configuration
|
|
419
419
|
if values.nil?
|
420
420
|
@scalar_types = values
|
421
421
|
else
|
422
|
-
bad_values = values.reject {|v| v.class == String}
|
422
|
+
bad_values = values.reject { |v| v.class == String }
|
423
423
|
unless bad_values.empty?
|
424
424
|
raise ArgumentError.new("Provided values must all be class name strings.")
|
425
425
|
end
|
426
426
|
|
427
|
-
@scalar_types = values.each_with_object({}) {|x, acc| acc[x] = true}.freeze
|
427
|
+
@scalar_types = values.each_with_object({}) { |x, acc| acc[x] = true }.freeze
|
428
428
|
end
|
429
429
|
end
|
430
430
|
|
@@ -449,9 +449,9 @@ module T::Configuration
|
|
449
449
|
private_constant :MODULE_NAME
|
450
450
|
|
451
451
|
@default_module_name_mangler = if T::Configuration::AT_LEAST_RUBY_2_7
|
452
|
-
->(type) {MODULE_NAME.bind_call(type)}
|
452
|
+
->(type) { MODULE_NAME.bind_call(type) }
|
453
453
|
else
|
454
|
-
->(type) {MODULE_NAME.bind(type).call} # rubocop:disable Performance/BindCall
|
454
|
+
->(type) { MODULE_NAME.bind(type).call } # rubocop:disable Performance/BindCall
|
455
455
|
end
|
456
456
|
|
457
457
|
@module_name_mangler = nil
|
@@ -546,16 +546,6 @@ module T::Configuration
|
|
546
546
|
@legacy_t_enum_migration_mode || false
|
547
547
|
end
|
548
548
|
|
549
|
-
@prop_freeze_handler = ->(instance, prop_name) {}
|
550
|
-
|
551
|
-
def self.prop_freeze_handler=(handler)
|
552
|
-
@prop_freeze_handler = handler
|
553
|
-
end
|
554
|
-
|
555
|
-
def self.prop_freeze_handler
|
556
|
-
@prop_freeze_handler
|
557
|
-
end
|
558
|
-
|
559
549
|
@sealed_violation_whitelist = nil
|
560
550
|
# @param [Array] sealed_violation_whitelist An array of Regexp to validate
|
561
551
|
# whether inheriting /including a sealed module outside the defining module
|
data/lib/types/enum.rb
CHANGED
@@ -44,11 +44,11 @@ class T::Enum
|
|
44
44
|
extend T::Props::CustomType
|
45
45
|
|
46
46
|
# TODO(jez) Might want to restrict this, or make subclasses provide this type
|
47
|
-
SerializedVal = T.type_alias {T.untyped}
|
47
|
+
SerializedVal = T.type_alias { T.untyped }
|
48
48
|
private_constant :SerializedVal
|
49
49
|
|
50
50
|
### Enum class methods ###
|
51
|
-
sig {returns(T::Array[T.attached_class])}
|
51
|
+
sig { returns(T::Array[T.attached_class]) }
|
52
52
|
def self.values
|
53
53
|
if @values.nil?
|
54
54
|
raise "Attempting to access values of #{self.class} before it has been initialized." \
|
@@ -59,7 +59,7 @@ class T::Enum
|
|
59
59
|
|
60
60
|
# This exists for compatibility with the interface of `Hash` & mostly to support
|
61
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]))}
|
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
63
|
def self.each_value(&blk)
|
64
64
|
if blk
|
65
65
|
values.each(&blk)
|
@@ -72,7 +72,7 @@ class T::Enum
|
|
72
72
|
#
|
73
73
|
# Note: It would have been nice to make this method final before people started overriding it.
|
74
74
|
# Note: Failed CriticalMethodsNoRuntimeTypingTest
|
75
|
-
sig {params(serialized_val: SerializedVal).returns(T.nilable(T.attached_class)).checked(:never)}
|
75
|
+
sig { params(serialized_val: SerializedVal).returns(T.nilable(T.attached_class)).checked(:never) }
|
76
76
|
def self.try_deserialize(serialized_val)
|
77
77
|
if @mapping.nil?
|
78
78
|
raise "Attempting to access serialization map of #{self.class} before it has been initialized." \
|
@@ -88,7 +88,7 @@ class T::Enum
|
|
88
88
|
#
|
89
89
|
# @return [self]
|
90
90
|
# @raise [KeyError] if serialized value does not match any instance.
|
91
|
-
sig {overridable.params(serialized_val: SerializedVal).returns(T.attached_class).checked(:never)}
|
91
|
+
sig { overridable.params(serialized_val: SerializedVal).returns(T.attached_class).checked(:never) }
|
92
92
|
def self.from_serialized(serialized_val)
|
93
93
|
res = try_deserialize(serialized_val)
|
94
94
|
if res.nil?
|
@@ -99,7 +99,7 @@ class T::Enum
|
|
99
99
|
|
100
100
|
# Note: It would have been nice to make this method final before people started overriding it.
|
101
101
|
# @return [Boolean] Does the given serialized value correspond with any of this enum's values.
|
102
|
-
sig {overridable.params(serialized_val: SerializedVal).returns(T::Boolean).checked(:never)}
|
102
|
+
sig { overridable.params(serialized_val: SerializedVal).returns(T::Boolean).checked(:never) }
|
103
103
|
def self.has_serialized?(serialized_val)
|
104
104
|
if @mapping.nil?
|
105
105
|
raise "Attempting to access serialization map of #{self.class} before it has been initialized." \
|
@@ -109,7 +109,7 @@ class T::Enum
|
|
109
109
|
end
|
110
110
|
|
111
111
|
# Note: Failed CriticalMethodsNoRuntimeTypingTest
|
112
|
-
sig {override.params(instance: T.nilable(T::Enum)).returns(SerializedVal).checked(:never)}
|
112
|
+
sig { override.params(instance: T.nilable(T::Enum)).returns(SerializedVal).checked(:never) }
|
113
113
|
def self.serialize(instance)
|
114
114
|
# This is needed otherwise if a Chalk::ODM::Document with a property of the shape
|
115
115
|
# T::Hash[T.nilable(MyEnum), Integer] and a value that looks like {nil => 0} is
|
@@ -126,7 +126,7 @@ class T::Enum
|
|
126
126
|
end
|
127
127
|
|
128
128
|
# Note: Failed CriticalMethodsNoRuntimeTypingTest
|
129
|
-
sig {override.params(mongo_value: SerializedVal).returns(T.attached_class).checked(:never)}
|
129
|
+
sig { override.params(mongo_value: SerializedVal).returns(T.attached_class).checked(:never) }
|
130
130
|
def self.deserialize(mongo_value)
|
131
131
|
if self == T::Enum
|
132
132
|
raise "Cannot call T::Enum.deserialize directly. You must call on a specific child class."
|
@@ -136,46 +136,46 @@ class T::Enum
|
|
136
136
|
|
137
137
|
### Enum instance methods ###
|
138
138
|
|
139
|
-
sig {returns(T.self_type)}
|
139
|
+
sig { returns(T.self_type) }
|
140
140
|
def dup
|
141
141
|
self
|
142
142
|
end
|
143
143
|
|
144
|
-
sig {returns(T.self_type).checked(:tests)}
|
144
|
+
sig { returns(T.self_type).checked(:tests) }
|
145
145
|
def clone
|
146
146
|
self
|
147
147
|
end
|
148
148
|
|
149
149
|
# Note: Failed CriticalMethodsNoRuntimeTypingTest
|
150
|
-
sig {returns(SerializedVal).checked(:never)}
|
150
|
+
sig { returns(SerializedVal).checked(:never) }
|
151
151
|
def serialize
|
152
152
|
assert_bound!
|
153
153
|
@serialized_val
|
154
154
|
end
|
155
155
|
|
156
|
-
sig {params(args: T.untyped).returns(T.untyped)}
|
156
|
+
sig { params(args: T.untyped).returns(T.untyped) }
|
157
157
|
def to_json(*args)
|
158
158
|
serialize.to_json(*args)
|
159
159
|
end
|
160
160
|
|
161
|
-
sig {params(args: T.untyped).returns(T.untyped)}
|
161
|
+
sig { params(args: T.untyped).returns(T.untyped) }
|
162
162
|
def as_json(*args)
|
163
163
|
serialized_val = serialize
|
164
164
|
return serialized_val unless serialized_val.respond_to?(:as_json)
|
165
165
|
serialized_val.as_json(*args)
|
166
166
|
end
|
167
167
|
|
168
|
-
sig {returns(String)}
|
168
|
+
sig { returns(String) }
|
169
169
|
def to_s
|
170
170
|
inspect
|
171
171
|
end
|
172
172
|
|
173
|
-
sig {returns(String)}
|
173
|
+
sig { returns(String) }
|
174
174
|
def inspect
|
175
175
|
"#<#{self.class.name}::#{@const_name || '__UNINITIALIZED__'}>"
|
176
176
|
end
|
177
177
|
|
178
|
-
sig {params(other: BasicObject).returns(T.nilable(Integer))}
|
178
|
+
sig { params(other: BasicObject).returns(T.nilable(Integer)) }
|
179
179
|
def <=>(other)
|
180
180
|
case other
|
181
181
|
when self.class
|
@@ -192,7 +192,7 @@ class T::Enum
|
|
192
192
|
# responds to the `to_str` method. It does not actually call `to_str` however.
|
193
193
|
#
|
194
194
|
# See https://ruby-doc.org/core-2.4.0/String.html#method-i-3D-3D
|
195
|
-
T::Sig::WithoutRuntime.sig {returns(String)}
|
195
|
+
T::Sig::WithoutRuntime.sig { returns(String) }
|
196
196
|
def to_str
|
197
197
|
msg = 'Implicit conversion of Enum instances to strings is not allowed. Call #serialize instead.'
|
198
198
|
if T::Configuration.legacy_t_enum_migration_mode?
|
@@ -200,7 +200,7 @@ class T::Enum
|
|
200
200
|
msg,
|
201
201
|
storytime: {
|
202
202
|
class: self.class.name,
|
203
|
-
caller_location: Kernel.caller_locations(1..1)&.[](0)&.then {"#{_1.path}:#{_1.lineno}"},
|
203
|
+
caller_location: Kernel.caller_locations(1..1)&.[](0)&.then { "#{_1.path}:#{_1.lineno}" },
|
204
204
|
},
|
205
205
|
)
|
206
206
|
serialize.to_s
|
@@ -217,12 +217,12 @@ class T::Enum
|
|
217
217
|
if T.unsafe(false)
|
218
218
|
# Declare to the type system that the `serialize` method for sure exists
|
219
219
|
# on whatever we mix this into.
|
220
|
-
T::Sig::WithoutRuntime.sig {abstract.returns(T.untyped)}
|
220
|
+
T::Sig::WithoutRuntime.sig { abstract.returns(T.untyped) }
|
221
221
|
def serialize; end
|
222
222
|
end
|
223
223
|
|
224
224
|
# WithoutRuntime so that comparison_assertion_failed can assume a constant stack depth
|
225
|
-
T::Sig::WithoutRuntime.sig {params(other: BasicObject).returns(T::Boolean)}
|
225
|
+
T::Sig::WithoutRuntime.sig { params(other: BasicObject).returns(T::Boolean) }
|
226
226
|
def ==(other)
|
227
227
|
case other
|
228
228
|
when String
|
@@ -238,7 +238,7 @@ class T::Enum
|
|
238
238
|
end
|
239
239
|
|
240
240
|
# WithoutRuntime so that comparison_assertion_failed can assume a constant stack depth
|
241
|
-
T::Sig::WithoutRuntime.sig {params(other: BasicObject).returns(T::Boolean)}
|
241
|
+
T::Sig::WithoutRuntime.sig { params(other: BasicObject).returns(T::Boolean) }
|
242
242
|
def ===(other)
|
243
243
|
case other
|
244
244
|
when String
|
@@ -255,7 +255,7 @@ class T::Enum
|
|
255
255
|
|
256
256
|
# WithoutRuntime so that caller_locations can assume a constant stack depth
|
257
257
|
# (Otherwise, the first call would be the method with the wrapping, which would have a different stack depth.)
|
258
|
-
T::Sig::WithoutRuntime.sig {params(method: Symbol, other: T.untyped).void}
|
258
|
+
T::Sig::WithoutRuntime.sig { params(method: Symbol, other: T.untyped).void }
|
259
259
|
private def comparison_assertion_failed(method, other)
|
260
260
|
T::Configuration.soft_assert_handler(
|
261
261
|
'Enum to string comparison not allowed. Compare to the Enum instance directly instead. See go/enum-migration',
|
@@ -265,7 +265,7 @@ class T::Enum
|
|
265
265
|
other: other,
|
266
266
|
other_class: other.class.name,
|
267
267
|
method: method,
|
268
|
-
caller_location: Kernel.caller_locations(2..2)&.[](0)&.then {"#{_1.path}:#{_1.lineno}"},
|
268
|
+
caller_location: Kernel.caller_locations(2..2)&.[](0)&.then { "#{_1.path}:#{_1.lineno}" },
|
269
269
|
}
|
270
270
|
)
|
271
271
|
end
|
@@ -276,7 +276,7 @@ class T::Enum
|
|
276
276
|
UNSET = T.let(Module.new.freeze, Module)
|
277
277
|
private_constant :UNSET
|
278
278
|
|
279
|
-
sig {params(serialized_val: SerializedVal).void}
|
279
|
+
sig { params(serialized_val: SerializedVal).void }
|
280
280
|
def initialize(serialized_val=UNSET)
|
281
281
|
raise 'T::Enum is abstract' if self.class == T::Enum
|
282
282
|
if !self.class.started_initializing?
|
@@ -292,7 +292,7 @@ class T::Enum
|
|
292
292
|
self.class._register_instance(self)
|
293
293
|
end
|
294
294
|
|
295
|
-
sig {returns(NilClass).checked(:never)}
|
295
|
+
sig { returns(NilClass).checked(:never) }
|
296
296
|
private def assert_bound!
|
297
297
|
if @const_name.nil?
|
298
298
|
raise "Attempting to access Enum value on #{self.class} before it has been initialized." \
|
@@ -300,14 +300,14 @@ class T::Enum
|
|
300
300
|
end
|
301
301
|
end
|
302
302
|
|
303
|
-
sig {params(const_name: Symbol).void}
|
303
|
+
sig { params(const_name: Symbol).void }
|
304
304
|
def _bind_name(const_name)
|
305
305
|
@const_name = const_name
|
306
306
|
@serialized_val = const_to_serialized_val(const_name) if @serialized_val.equal?(UNSET)
|
307
307
|
freeze
|
308
308
|
end
|
309
309
|
|
310
|
-
sig {params(const_name: Symbol).returns(String)}
|
310
|
+
sig { params(const_name: Symbol).returns(String) }
|
311
311
|
private def const_to_serialized_val(const_name)
|
312
312
|
# Historical note: We convert to lowercase names because the majority of existing calls to
|
313
313
|
# `make_accessible` were arrays of lowercase strings. Doing this conversion allowed for the
|
@@ -315,7 +315,7 @@ class T::Enum
|
|
315
315
|
-const_name.to_s.downcase.freeze
|
316
316
|
end
|
317
317
|
|
318
|
-
sig {returns(T::Boolean)}
|
318
|
+
sig { returns(T::Boolean) }
|
319
319
|
def self.started_initializing?
|
320
320
|
unless defined?(@started_initializing)
|
321
321
|
@started_initializing = T.let(false, T.nilable(T::Boolean))
|
@@ -323,7 +323,7 @@ class T::Enum
|
|
323
323
|
T.must(@started_initializing)
|
324
324
|
end
|
325
325
|
|
326
|
-
sig {returns(T::Boolean)}
|
326
|
+
sig { returns(T::Boolean) }
|
327
327
|
def self.fully_initialized?
|
328
328
|
unless defined?(@fully_initialized)
|
329
329
|
@fully_initialized = T.let(false, T.nilable(T::Boolean))
|
@@ -332,7 +332,7 @@ class T::Enum
|
|
332
332
|
end
|
333
333
|
|
334
334
|
# Maintains the order in which values are defined
|
335
|
-
sig {params(instance: T.untyped).void}
|
335
|
+
sig { params(instance: T.untyped).void }
|
336
336
|
def self._register_instance(instance)
|
337
337
|
@values ||= []
|
338
338
|
@values << T.cast(instance, T.attached_class)
|
@@ -340,7 +340,7 @@ class T::Enum
|
|
340
340
|
|
341
341
|
# Entrypoint for allowing people to register new enum values.
|
342
342
|
# All enum values must be defined within this block.
|
343
|
-
sig {params(blk: T.proc.void).void}
|
343
|
+
sig { params(blk: T.proc.void).void }
|
344
344
|
def self.enums(&blk)
|
345
345
|
raise "enums cannot be defined for T::Enum" if self == T::Enum
|
346
346
|
raise "Enum #{self} was already initialized" if fully_initialized?
|
@@ -375,13 +375,13 @@ class T::Enum
|
|
375
375
|
|
376
376
|
orphaned_instances = T.must(@values) - @mapping.values
|
377
377
|
if !orphaned_instances.empty?
|
378
|
-
raise "Enum values must be assigned to constants: #{orphaned_instances.map {|v| v.instance_variable_get('@serialized_val')}}"
|
378
|
+
raise "Enum values must be assigned to constants: #{orphaned_instances.map { |v| v.instance_variable_get('@serialized_val') }}"
|
379
379
|
end
|
380
380
|
|
381
381
|
@fully_initialized = true
|
382
382
|
end
|
383
383
|
|
384
|
-
sig {params(child_class: T::Class[T.anything]).void}
|
384
|
+
sig { params(child_class: T::Class[T.anything]).void }
|
385
385
|
def self.inherited(child_class)
|
386
386
|
super
|
387
387
|
|
@@ -394,12 +394,12 @@ class T::Enum
|
|
394
394
|
end
|
395
395
|
|
396
396
|
# Marshal support
|
397
|
-
sig {params(_level: Integer).returns(String)}
|
397
|
+
sig { params(_level: Integer).returns(String) }
|
398
398
|
def _dump(_level)
|
399
399
|
Marshal.dump(serialize)
|
400
400
|
end
|
401
401
|
|
402
|
-
sig {params(args: String).returns(T.attached_class)}
|
402
|
+
sig { params(args: String).returns(T.attached_class) }
|
403
403
|
def self._load(args)
|
404
404
|
deserialize(Marshal.load(args)) # rubocop:disable Security/MarshalLoad
|
405
405
|
end
|
@@ -4,7 +4,7 @@
|
|
4
4
|
module T::NonForcingConstants
|
5
5
|
# NOTE: This method is documented on the RBI in Sorbet's payload, so that it
|
6
6
|
# shows up in the hover/completion documentation via LSP.
|
7
|
-
T::Sig::WithoutRuntime.sig {params(val: BasicObject, klass: String).returns(T::Boolean)}
|
7
|
+
T::Sig::WithoutRuntime.sig { params(val: BasicObject, klass: String).returns(T::Boolean) }
|
8
8
|
def self.non_forcing_is_a?(val, klass)
|
9
9
|
method_name = "T::NonForcingConstants.non_forcing_is_a?"
|
10
10
|
if klass.empty?
|
@@ -12,7 +12,7 @@
|
|
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)
|
@@ -25,7 +25,7 @@ module T::Private::Methods
|
|
25
25
|
# twice is permitted). we could do this with two tables, but it seems slightly
|
26
26
|
# cleaner with a single table.
|
27
27
|
# Effectively T::Hash[Module, T.nilable(Set))]
|
28
|
-
@modules_with_final = Hash.new {|hash, key| hash[key] = nil}.compare_by_identity
|
28
|
+
@modules_with_final = Hash.new { |hash, key| hash[key] = nil }.compare_by_identity
|
29
29
|
# this stores the old [included, extended] hooks for Module and inherited hook for Class that we override when
|
30
30
|
# enabling final checks for when those hooks are called. the 'hooks' here don't have anything to do with the 'hooks'
|
31
31
|
# in installed_hooks.
|
@@ -168,7 +168,7 @@ module T::Private::Methods
|
|
168
168
|
|
169
169
|
definition_file, definition_line = T::Private::Methods.signature_for_method(ancestor.instance_method(method_name)).method.source_location
|
170
170
|
is_redefined = target == ancestor
|
171
|
-
caller_loc = T::Private::CallerUtils.find_caller {|loc| !loc.path.to_s.start_with?(SORBET_RUNTIME_LIB_PATH)}
|
171
|
+
caller_loc = T::Private::CallerUtils.find_caller { |loc| !loc.path.to_s.start_with?(SORBET_RUNTIME_LIB_PATH) }
|
172
172
|
extra_info = "\n"
|
173
173
|
if caller_loc
|
174
174
|
extra_info = (is_redefined ? "Redefined" : "Overridden") + " here: #{caller_loc.path}:#{caller_loc.lineno}\n"
|
@@ -471,7 +471,7 @@ module T::Private::Methods
|
|
471
471
|
end
|
472
472
|
|
473
473
|
def self.all_checked_tests_sigs
|
474
|
-
@signatures_by_method.values.select {|sig| sig.check_level == :tests}
|
474
|
+
@signatures_by_method.values.select { |sig| sig.check_level == :tests }
|
475
475
|
end
|
476
476
|
|
477
477
|
# the module target is adding the methods from the module source to itself. we need to check that for all instance
|
@@ -545,15 +545,15 @@ module T::Private::Methods
|
|
545
545
|
|
546
546
|
module MethodHooks
|
547
547
|
def method_added(name)
|
548
|
-
super(name)
|
549
548
|
::T::Private::Methods._on_method_added(self, self, name)
|
549
|
+
super(name)
|
550
550
|
end
|
551
551
|
end
|
552
552
|
|
553
553
|
module SingletonMethodHooks
|
554
554
|
def singleton_method_added(name)
|
555
|
-
super(name)
|
556
555
|
::T::Private::Methods._on_method_added(self, singleton_class, name)
|
556
|
+
super(name)
|
557
557
|
end
|
558
558
|
end
|
559
559
|
|
@@ -589,6 +589,22 @@ module T::Private::Methods
|
|
589
589
|
mod.extend(SingletonMethodHooks)
|
590
590
|
end
|
591
591
|
|
592
|
+
# `name` must be an instance method (for class methods, pass in mod.singleton_class)
|
593
|
+
def self.visibility_method_name(mod, name)
|
594
|
+
if mod.public_method_defined?(name)
|
595
|
+
:public
|
596
|
+
elsif mod.protected_method_defined?(name)
|
597
|
+
:protected
|
598
|
+
elsif mod.private_method_defined?(name)
|
599
|
+
:private
|
600
|
+
else
|
601
|
+
# Raises a NameError formatted like the Ruby VM would (the exact text formatting
|
602
|
+
# of these errors changed across Ruby VM versions, in ways that would sometimes
|
603
|
+
# cause tests to fail if they were dependent on hard coding errors).
|
604
|
+
mod.method(name)
|
605
|
+
end
|
606
|
+
end
|
607
|
+
|
592
608
|
# use this directly if you don't want/need to box up the method into an object to pass to method_to_key.
|
593
609
|
private_class_method def self.method_owner_and_name_to_key(owner, name)
|
594
610
|
"#{owner.object_id}##{name}"
|
@@ -12,7 +12,7 @@ module T::Private::Methods::CallValidation
|
|
12
12
|
# @param method_sig [T::Private::Methods::Signature]
|
13
13
|
# @return [UnboundMethod] the new wrapper method (or the original one if we didn't wrap it)
|
14
14
|
def self.wrap_method_if_needed(mod, method_sig, original_method)
|
15
|
-
original_visibility = visibility_method_name(mod, method_sig.method_name)
|
15
|
+
original_visibility = T::Private::Methods.visibility_method_name(mod, method_sig.method_name)
|
16
16
|
if method_sig.mode == T::Private::Methods::Modes.abstract
|
17
17
|
create_abstract_wrapper(mod, method_sig, original_method, original_visibility)
|
18
18
|
# Do nothing in this case; this method was not wrapped in _on_method_added.
|
@@ -69,11 +69,11 @@ module T::Private::Methods::CallValidation
|
|
69
69
|
|
70
70
|
def self.create_validator_method(mod, original_method, method_sig, original_visibility)
|
71
71
|
has_fixed_arity = method_sig.kwarg_types.empty? && !method_sig.has_rest && !method_sig.has_keyrest &&
|
72
|
-
original_method.parameters.all? {|(kind, _name)| kind == :req || kind == :block}
|
72
|
+
original_method.parameters.all? { |(kind, _name)| kind == :req || kind == :block }
|
73
73
|
can_skip_block_type = method_sig.block_type.nil? || method_sig.block_type.valid?(nil)
|
74
74
|
ok_for_fast_path = has_fixed_arity && can_skip_block_type && !method_sig.bind && method_sig.arg_types.length < 5 && is_allowed_to_have_fast_path
|
75
75
|
|
76
|
-
all_args_are_simple = ok_for_fast_path && method_sig.arg_types.all? {|_name, type| type.is_a?(T::Types::Simple)}
|
76
|
+
all_args_are_simple = ok_for_fast_path && method_sig.arg_types.all? { |_name, type| type.is_a?(T::Types::Simple) }
|
77
77
|
simple_method = all_args_are_simple && method_sig.return_type.is_a?(T::Types::Simple)
|
78
78
|
simple_procedure = all_args_are_simple && method_sig.return_type.is_a?(T::Private::Types::Void)
|
79
79
|
|
@@ -330,19 +330,6 @@ module T::Private::Methods::CallValidation
|
|
330
330
|
location: caller_loc
|
331
331
|
)
|
332
332
|
end
|
333
|
-
|
334
|
-
# `name` must be an instance method (for class methods, pass in mod.singleton_class)
|
335
|
-
private_class_method def self.visibility_method_name(mod, name)
|
336
|
-
if mod.public_method_defined?(name)
|
337
|
-
:public
|
338
|
-
elsif mod.protected_method_defined?(name)
|
339
|
-
:protected
|
340
|
-
elsif mod.private_method_defined?(name)
|
341
|
-
:private
|
342
|
-
else
|
343
|
-
mod.method(name) # Raises
|
344
|
-
end
|
345
|
-
end
|
346
333
|
end
|
347
334
|
|
348
335
|
if T::Configuration::AT_LEAST_RUBY_2_7
|
@@ -154,7 +154,12 @@ module T::Private::Methods
|
|
154
154
|
case decl.mode
|
155
155
|
when Modes.standard
|
156
156
|
decl.mode = Modes.override
|
157
|
-
|
157
|
+
case allow_incompatible
|
158
|
+
when true, false, :visibility
|
159
|
+
decl.override_allow_incompatible = allow_incompatible
|
160
|
+
else
|
161
|
+
raise BuilderError.new(".override(allow_incompatible: ...) only accepts `true`, `false`, or `:visibility`, got: #{allow_incompatible.inspect}")
|
162
|
+
end
|
158
163
|
when Modes.override, Modes.overridable_override
|
159
164
|
raise BuilderError.new(".override cannot be repeated in a single signature")
|
160
165
|
when Modes.overridable
|
@@ -68,14 +68,14 @@ class T::Private::Methods::Signature
|
|
68
68
|
writer_method = !(raw_arg_types.size == 1 && raw_arg_types.key?(nil)) && parameters == UNNAMED_REQUIRED_PARAMETERS && method_name[-1] == "="
|
69
69
|
# For writer methods, map the single parameter to the method name without the "=" at the end
|
70
70
|
parameters = [[:req, method_name[0...-1].to_sym]] if writer_method
|
71
|
-
is_name_missing = parameters.any? {|_, name| !raw_arg_types.key?(name)}
|
71
|
+
is_name_missing = parameters.any? { |_, name| !raw_arg_types.key?(name) }
|
72
72
|
if is_name_missing
|
73
|
-
param_names = parameters.map {|_, name| name}
|
73
|
+
param_names = parameters.map { |_, name| name }
|
74
74
|
missing_names = param_names - raw_arg_types.keys
|
75
75
|
raise "The declaration for `#{method.name}` is missing parameter(s): #{missing_names.join(', ')}"
|
76
76
|
elsif parameters.length != raw_arg_types.size
|
77
|
-
param_names = parameters.map {|_, name| name}
|
78
|
-
has_extra_names = parameters.count {|_, name| raw_arg_types.key?(name)} < raw_arg_types.size
|
77
|
+
param_names = parameters.map { |_, name| name }
|
78
|
+
has_extra_names = parameters.count { |_, name| raw_arg_types.key?(name) } < raw_arg_types.size
|
79
79
|
if has_extra_names
|
80
80
|
extra_names = raw_arg_types.keys - param_names
|
81
81
|
raise "The declaration for `#{method.name}` has extra parameter(s): #{extra_names.join(', ')}"
|
@@ -95,7 +95,7 @@ class T::Private::Methods::Signature
|
|
95
95
|
# always precede optional keyword arguments. We can't tell
|
96
96
|
# whether the culprit is the Ruby reordering or user error, so
|
97
97
|
# we error but include a note
|
98
|
-
if param_kind == :keyreq && parameters.any? {|k, _| k == :key}
|
98
|
+
if param_kind == :keyreq && parameters.any? { |k, _| k == :key }
|
99
99
|
hint = "\n\nNote: Any required keyword arguments must precede any optional keyword " \
|
100
100
|
"arguments. If your method declaration matches your `def`, try reordering any " \
|
101
101
|
"optional keyword parameters to the end of the method list."
|
@@ -103,7 +103,7 @@ class T::Private::Methods::Signature
|
|
103
103
|
|
104
104
|
raise "Parameter `#{type_name}` is declared out of order (declared as arg number " \
|
105
105
|
"#{i + 1}, defined in the method as arg number " \
|
106
|
-
"#{parameters.index {|_, name| name == type_name} + 1}).#{hint}\nMethod: #{method_desc}"
|
106
|
+
"#{parameters.index { |_, name| name == type_name } + 1}).#{hint}\nMethod: #{method_desc}"
|
107
107
|
end
|
108
108
|
|
109
109
|
type = T::Utils.coerce(raw_type)
|
@@ -245,8 +245,8 @@ class T::Private::Methods::Signature
|
|
245
245
|
end
|
246
246
|
|
247
247
|
def force_type_init
|
248
|
-
@arg_types.each {|_, type| type.build_type}
|
249
|
-
@kwarg_types.each {|_, type| type.build_type}
|
248
|
+
@arg_types.each { |_, type| type.build_type }
|
249
|
+
@kwarg_types.each { |_, type| type.build_type }
|
250
250
|
@block_type&.build_type
|
251
251
|
@rest_type&.build_type
|
252
252
|
@keyrest_type&.build_type
|
@@ -72,7 +72,7 @@ module T::Private::Methods::SignatureValidation
|
|
72
72
|
|
73
73
|
# If the super_method has any kwargs we can't build a
|
74
74
|
# Signature for it, so we'll just skip validation in that case.
|
75
|
-
if !super_signature && !super_method.parameters.select {|kind, _| kind == :rest || kind == :kwrest}.empty?
|
75
|
+
if !super_signature && !super_method.parameters.select { |kind, _| kind == :rest || kind == :kwrest }.empty?
|
76
76
|
nil
|
77
77
|
else
|
78
78
|
# super_signature can be nil when we're overriding a method (perhaps a builtin) that didn't use
|
@@ -89,6 +89,7 @@ module T::Private::Methods::SignatureValidation
|
|
89
89
|
validate_override_mode(signature, super_signature)
|
90
90
|
validate_override_shape(signature, super_signature)
|
91
91
|
validate_override_types(signature, super_signature)
|
92
|
+
validate_override_visibility(signature, super_signature)
|
92
93
|
end
|
93
94
|
else
|
94
95
|
validate_non_override_mode(signature)
|
@@ -175,7 +176,7 @@ module T::Private::Methods::SignatureValidation
|
|
175
176
|
end
|
176
177
|
|
177
178
|
def self.validate_override_shape(signature, super_signature)
|
178
|
-
return if signature.override_allow_incompatible
|
179
|
+
return if signature.override_allow_incompatible == true
|
179
180
|
return if super_signature.mode == Modes.untyped
|
180
181
|
|
181
182
|
method_name = signature.method_name
|
@@ -231,7 +232,7 @@ module T::Private::Methods::SignatureValidation
|
|
231
232
|
end
|
232
233
|
|
233
234
|
def self.validate_override_types(signature, super_signature)
|
234
|
-
return if signature.override_allow_incompatible
|
235
|
+
return if signature.override_allow_incompatible == true
|
235
236
|
return if super_signature.mode == Modes.untyped
|
236
237
|
return unless [signature, super_signature].all? do |sig|
|
237
238
|
sig.check_level == :always || (sig.check_level == :tests && T::Private::RuntimeLevels.check_tests?)
|
@@ -276,6 +277,44 @@ module T::Private::Methods::SignatureValidation
|
|
276
277
|
end
|
277
278
|
end
|
278
279
|
|
280
|
+
ALLOW_INCOMPATIBLE_VISIBILITY = [:visibility, true].freeze
|
281
|
+
private_constant :ALLOW_INCOMPATIBLE_VISIBILITY
|
282
|
+
|
283
|
+
def self.validate_override_visibility(signature, super_signature)
|
284
|
+
return if super_signature.mode == Modes.untyped
|
285
|
+
# This departs from the behavior of other `validate_override_whatever` functions in that it
|
286
|
+
# only comes into effect when the child signature explicitly says the word `override`. This was
|
287
|
+
# done because the primary method for silencing these errors (`allow_incompatible: :visibility`)
|
288
|
+
# requires an `override` node to attach to. Once we have static override checking for implicitly
|
289
|
+
# overridden methods, we can remove this.
|
290
|
+
return unless Modes::OVERRIDE_MODES.include?(signature.mode)
|
291
|
+
return if ALLOW_INCOMPATIBLE_VISIBILITY.include?(signature.override_allow_incompatible)
|
292
|
+
method = signature.method
|
293
|
+
super_method = super_signature.method
|
294
|
+
mode_noun = super_signature.mode == Modes.abstract ? 'implementation' : 'override'
|
295
|
+
vis = method_visibility(method)
|
296
|
+
super_vis = method_visibility(super_method)
|
297
|
+
|
298
|
+
if visibility_strength(vis) > visibility_strength(super_vis)
|
299
|
+
raise "Incompatible visibility for #{mode_noun} of method #{method.name}\n" \
|
300
|
+
"* Base: #{super_vis} (in #{method_loc_str(super_method)})\n" \
|
301
|
+
"* #{mode_noun.capitalize}: #{vis} (in #{method_loc_str(method)})\n" \
|
302
|
+
"(The override must be at least as permissive as the supermethod)" \
|
303
|
+
end
|
304
|
+
end
|
305
|
+
|
306
|
+
private_class_method def self.method_visibility(method)
|
307
|
+
T::Private::Methods.visibility_method_name(method.owner, method.name)
|
308
|
+
end
|
309
|
+
|
310
|
+
# Higher = more restrictive.
|
311
|
+
METHOD_VISIBILITIES = %i[public protected private].freeze
|
312
|
+
private_constant :METHOD_VISIBILITIES
|
313
|
+
|
314
|
+
private_class_method def self.visibility_strength(vis)
|
315
|
+
METHOD_VISIBILITIES.find_index(vis)
|
316
|
+
end
|
317
|
+
|
279
318
|
private_class_method def self.base_override_loc_str(signature, super_signature)
|
280
319
|
mode_noun = super_signature.mode == Modes.abstract ? 'Implementation' : 'Override'
|
281
320
|
"\n * Base definition: in #{method_loc_str(super_signature.method)}" \
|
@@ -32,7 +32,7 @@ module T::Private::RuntimeLevels
|
|
32
32
|
def self.enable_checking_in_tests
|
33
33
|
if !@check_tests && @wrapped_tests_with_validation
|
34
34
|
all_checked_tests_sigs = T::Private::Methods.all_checked_tests_sigs
|
35
|
-
locations = all_checked_tests_sigs.map {|sig| sig.method.source_location.join(':')}.join("\n- ")
|
35
|
+
locations = all_checked_tests_sigs.map { |sig| sig.method.source_location.join(':') }.join("\n- ")
|
36
36
|
raise "Toggle `:tests`-level runtime type checking earlier. " \
|
37
37
|
"There are already some methods wrapped with `sig.checked(:tests)`:\n" \
|
38
38
|
"- #{locations}"
|