sorbet-runtime 0.5.5942 → 0.5.6198
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 +0 -1
- data/lib/types/compatibility_patches.rb +0 -2
- data/lib/types/configuration.rb +53 -4
- data/lib/types/enum.rb +12 -1
- data/lib/types/non_forcing_constants.rb +21 -17
- data/lib/types/private/abstract/validate.rb +6 -6
- data/lib/types/private/methods/_methods.rb +11 -8
- data/lib/types/private/methods/call_validation.rb +2 -2
- data/lib/types/private/methods/decl_builder.rb +4 -1
- data/lib/types/private/methods/modes.rb +3 -3
- data/lib/types/private/methods/signature.rb +8 -4
- data/lib/types/private/methods/signature_validation.rb +11 -14
- data/lib/types/private/sealed.rb +16 -1
- data/lib/types/props/decorator.rb +39 -36
- data/lib/types/props/generated_code_validation.rb +6 -6
- data/lib/types/props/has_lazily_specialized_methods.rb +1 -1
- data/lib/types/props/private/deserializer_generator.rb +3 -3
- data/lib/types/props/private/serde_transform.rb +12 -18
- data/lib/types/props/private/setter_factory.rb +3 -8
- data/lib/types/props/serializable.rb +5 -5
- data/lib/types/props/type_validation.rb +2 -2
- data/lib/types/types/base.rb +3 -1
- data/lib/types/types/fixed_hash.rb +1 -1
- data/lib/types/types/type_variable.rb +1 -1
- data/lib/types/types/typed_enumerable.rb +4 -4
- data/lib/types/utils.rb +1 -1
- metadata +2 -3
- data/lib/types/runtime_profiled.rb +0 -24
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: b9ad14907c264d6ca3dae954f1bf9cdfdff0544411fad7a390fcb424465bf828
|
|
4
|
+
data.tar.gz: f02410f71f442e62a635881ec386a23911f1cb1a4d4c5eae77693d1a10a0695d
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 1bb53ba112fb1793b4e138e1a65ed648e2e202af6e8ec79be17b444c11c02a63a7c385b0abb474e38dca78a03ad91f02149ff24b7c5f622f7d1943c4d4c846b1
|
|
7
|
+
data.tar.gz: bf301214903ea532fb931314c823f68a3017a2de5868f32d074a642664c4cf266864201d9ae4a62573a9713bb888d132cb0aadd23c77aaf628b8d443163bae36
|
data/lib/sorbet-runtime.rb
CHANGED
|
@@ -22,7 +22,6 @@ require_relative 'types/configuration'
|
|
|
22
22
|
require_relative 'types/profile'
|
|
23
23
|
require_relative 'types/_types'
|
|
24
24
|
require_relative 'types/private/decl_state'
|
|
25
|
-
require_relative 'types/runtime_profiled'
|
|
26
25
|
require_relative 'types/private/class_utils'
|
|
27
26
|
require_relative 'types/private/runtime_levels'
|
|
28
27
|
require_relative 'types/private/methods/_methods'
|
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
# typed: ignore
|
|
3
3
|
|
|
4
|
-
require_relative 'private/methods/_methods'
|
|
5
|
-
|
|
6
4
|
# Work around an interaction bug with sorbet-runtime and rspec-mocks,
|
|
7
5
|
# which occurs when using message expectations (*_any_instance_of,
|
|
8
6
|
# expect, allow) and and_call_original.
|
data/lib/types/configuration.rb
CHANGED
|
@@ -42,6 +42,34 @@ module T::Configuration
|
|
|
42
42
|
T::Private::Methods.set_final_checks_on_hooks(false)
|
|
43
43
|
end
|
|
44
44
|
|
|
45
|
+
@include_value_in_type_errors = true
|
|
46
|
+
# Whether to include values in TypeError messages.
|
|
47
|
+
#
|
|
48
|
+
# Including values is useful for debugging, but can potentially leak
|
|
49
|
+
# sensitive information to logs.
|
|
50
|
+
#
|
|
51
|
+
# @return [T::Boolean]
|
|
52
|
+
def self.include_value_in_type_errors?
|
|
53
|
+
@include_value_in_type_errors
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
# Configure if type errors excludes the value of the problematic type.
|
|
57
|
+
#
|
|
58
|
+
# The default is to include values in type errors:
|
|
59
|
+
# TypeError: Expected type Integer, got String with value "foo"
|
|
60
|
+
#
|
|
61
|
+
# When values are excluded from type errors:
|
|
62
|
+
# TypeError: Expected type Integer, got String
|
|
63
|
+
def self.exclude_value_in_type_errors
|
|
64
|
+
@include_value_in_type_errors = false
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
# Opposite of exclude_value_in_type_errors.
|
|
68
|
+
# (Including values in type errors is the default)
|
|
69
|
+
def self.include_value_in_type_errors
|
|
70
|
+
@include_value_in_type_errors = true
|
|
71
|
+
end
|
|
72
|
+
|
|
45
73
|
# Configure the default checked level for a sig with no explicit `.checked`
|
|
46
74
|
# builder. When unset, the default checked level is `:always`.
|
|
47
75
|
#
|
|
@@ -338,7 +366,7 @@ module T::Configuration
|
|
|
338
366
|
if values.nil?
|
|
339
367
|
@scalar_types = values
|
|
340
368
|
else
|
|
341
|
-
bad_values = values.
|
|
369
|
+
bad_values = values.reject {|v| v.class == String}
|
|
342
370
|
unless bad_values.empty?
|
|
343
371
|
raise ArgumentError.new("Provided values must all be class name strings.")
|
|
344
372
|
end
|
|
@@ -347,7 +375,7 @@ module T::Configuration
|
|
|
347
375
|
end
|
|
348
376
|
end
|
|
349
377
|
|
|
350
|
-
@default_scalar_types = Set.new(%w
|
|
378
|
+
@default_scalar_types = Set.new(%w[
|
|
351
379
|
NilClass
|
|
352
380
|
TrueClass
|
|
353
381
|
FalseClass
|
|
@@ -357,12 +385,33 @@ module T::Configuration
|
|
|
357
385
|
Symbol
|
|
358
386
|
Time
|
|
359
387
|
T::Enum
|
|
360
|
-
|
|
388
|
+
]).freeze
|
|
361
389
|
|
|
362
390
|
def self.scalar_types
|
|
363
391
|
@scalar_types || @default_scalar_types
|
|
364
392
|
end
|
|
365
393
|
|
|
394
|
+
# Guard against overrides of `name` or `to_s`
|
|
395
|
+
MODULE_NAME = Module.instance_method(:name)
|
|
396
|
+
private_constant :MODULE_NAME
|
|
397
|
+
|
|
398
|
+
@default_module_name_mangler = ->(type) {MODULE_NAME.bind(type).call}
|
|
399
|
+
@module_name_mangler = nil
|
|
400
|
+
|
|
401
|
+
def self.module_name_mangler
|
|
402
|
+
@module_name_mangler || @default_module_name_mangler
|
|
403
|
+
end
|
|
404
|
+
|
|
405
|
+
# Set to override the default behavior for converting types
|
|
406
|
+
# to names in generated code. Used by the runtime implementation
|
|
407
|
+
# associated with `--stripe-packages` mode.
|
|
408
|
+
#
|
|
409
|
+
# @param [Lambda, Proc, nil] value Proc that converts a type (Class/Module)
|
|
410
|
+
# to a String (pass nil to reset to default behavior)
|
|
411
|
+
def self.module_name_mangler=(handler)
|
|
412
|
+
@module_name_mangler = handler
|
|
413
|
+
end
|
|
414
|
+
|
|
366
415
|
# Temporarily disable ruby warnings while executing the given block. This is
|
|
367
416
|
# useful when doing something that would normally cause a warning to be
|
|
368
417
|
# emitted in Ruby verbose mode ($VERBOSE = true).
|
|
@@ -398,7 +447,7 @@ module T::Configuration
|
|
|
398
447
|
# should be allowed. Useful to whitelist benign violations, like shim files
|
|
399
448
|
# generated for an autoloader.
|
|
400
449
|
def self.sealed_violation_whitelist=(sealed_violation_whitelist)
|
|
401
|
-
if
|
|
450
|
+
if !@sealed_violation_whitelist.nil?
|
|
402
451
|
raise ArgumentError.new("Cannot overwrite sealed_violation_whitelist after setting it")
|
|
403
452
|
end
|
|
404
453
|
|
data/lib/types/enum.rb
CHANGED
|
@@ -251,7 +251,7 @@ class T::Enum
|
|
|
251
251
|
|
|
252
252
|
|
|
253
253
|
sig {params(serialized_val: SerializedVal).void}
|
|
254
|
-
|
|
254
|
+
def initialize(serialized_val=nil)
|
|
255
255
|
raise 'T::Enum is abstract' if self.class == T::Enum
|
|
256
256
|
if !self.class.started_initializing?
|
|
257
257
|
raise "Must instantiate all enum values of #{self.class} inside 'enums do'."
|
|
@@ -357,4 +357,15 @@ class T::Enum
|
|
|
357
357
|
|
|
358
358
|
raise "Inheriting from children of T::Enum is prohibited" if self != T::Enum
|
|
359
359
|
end
|
|
360
|
+
|
|
361
|
+
# Marshal support
|
|
362
|
+
sig {params(_level: Integer).returns(String)}
|
|
363
|
+
def _dump(_level)
|
|
364
|
+
Marshal.dump(serialize)
|
|
365
|
+
end
|
|
366
|
+
|
|
367
|
+
sig {params(args: String).returns(T.attached_class)}
|
|
368
|
+
def self._load(args)
|
|
369
|
+
deserialize(Marshal.load(args))
|
|
370
|
+
end
|
|
360
371
|
end
|
|
@@ -30,28 +30,32 @@ module T::NonForcingConstants
|
|
|
30
30
|
|
|
31
31
|
current_klass = Object
|
|
32
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
33
|
|
|
40
|
-
#
|
|
41
|
-
|
|
42
|
-
if
|
|
43
|
-
|
|
44
|
-
|
|
34
|
+
# if this had a :: prefix, then there's no more loading to
|
|
35
|
+
# do---skip to the next one
|
|
36
|
+
next if part == ""
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
if current_klass.autoload?(part)
|
|
40
|
+
# There's an autoload registered for that constant, which means it's not
|
|
41
|
+
# yet loaded. `value` can't be an instance of something not yet loaded.
|
|
42
|
+
return false
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
# Sorbet guarantees that the string is an absolutely resolved name.
|
|
46
|
+
search_inheritance_chain = false
|
|
47
|
+
if !current_klass.const_defined?(part, search_inheritance_chain)
|
|
48
|
+
return false
|
|
49
|
+
end
|
|
45
50
|
|
|
46
|
-
|
|
47
|
-
|
|
51
|
+
current_klass = current_klass.const_get(part)
|
|
52
|
+
current_prefix = "#{current_prefix}::#{part}"
|
|
48
53
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
end
|
|
54
|
+
if !Module.===(current_klass)
|
|
55
|
+
raise ArgumentError.new("#{current_prefix} is not a class or module")
|
|
52
56
|
end
|
|
53
57
|
end
|
|
54
58
|
|
|
55
|
-
|
|
59
|
+
current_klass.===(val)
|
|
56
60
|
end
|
|
57
61
|
end
|
|
@@ -111,16 +111,16 @@ module T::Private::Abstract::Validate
|
|
|
111
111
|
end
|
|
112
112
|
|
|
113
113
|
private_class_method def self.describe_method(method, show_owner: true)
|
|
114
|
-
if method.source_location
|
|
115
|
-
|
|
114
|
+
loc = if method.source_location
|
|
115
|
+
method.source_location.join(':')
|
|
116
116
|
else
|
|
117
|
-
|
|
117
|
+
"<unknown location>"
|
|
118
118
|
end
|
|
119
119
|
|
|
120
|
-
if show_owner
|
|
121
|
-
|
|
120
|
+
owner = if show_owner
|
|
121
|
+
" declared in #{method.owner}"
|
|
122
122
|
else
|
|
123
|
-
|
|
123
|
+
""
|
|
124
124
|
end
|
|
125
125
|
|
|
126
126
|
" * `#{method.name}`#{owner} at #{loc}"
|
|
@@ -142,7 +142,10 @@ module T::Private::Methods
|
|
|
142
142
|
# method_to_key(ancestor.instance_method(method_name)) is not (just) an optimization, but also required for
|
|
143
143
|
# correctness, since ancestor.method_defined?(method_name) may return true even if method_name is not defined
|
|
144
144
|
# directly on ancestor but instead an ancestor of ancestor.
|
|
145
|
-
if ancestor.method_defined?(method_name)
|
|
145
|
+
if (ancestor.method_defined?(method_name) ||
|
|
146
|
+
ancestor.private_method_defined?(method_name) ||
|
|
147
|
+
ancestor.protected_method_defined?(method_name)) &&
|
|
148
|
+
final_method?(method_owner_and_name_to_key(ancestor, method_name))
|
|
146
149
|
raise(
|
|
147
150
|
"The method `#{method_name}` on #{ancestor} was declared as final and cannot be " +
|
|
148
151
|
(target == ancestor ? "redefined" : "overridden in #{target}")
|
|
@@ -190,7 +193,7 @@ module T::Private::Methods
|
|
|
190
193
|
|
|
191
194
|
if method_name == :method_added || method_name == :singleton_method_added
|
|
192
195
|
raise(
|
|
193
|
-
"Putting a `sig` on `#{method_name}` is not supported"
|
|
196
|
+
"Putting a `sig` on `#{method_name}` is not supported" \
|
|
194
197
|
" (sorbet-runtime uses this method internally to perform `sig` validation logic)"
|
|
195
198
|
)
|
|
196
199
|
end
|
|
@@ -313,10 +316,10 @@ module T::Private::Methods
|
|
|
313
316
|
begin
|
|
314
317
|
# We allow `sig` in the current module's context (normal case) and
|
|
315
318
|
if hook_mod != current_declaration.mod &&
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
319
|
+
# inside `class << self`, and
|
|
320
|
+
hook_mod.singleton_class != current_declaration.mod &&
|
|
321
|
+
# on `self` at the top level of a file
|
|
322
|
+
current_declaration.mod != TOP_SELF
|
|
320
323
|
raise "A method (#{method_name}) is being added on a different class/module (#{hook_mod}) than the " \
|
|
321
324
|
"last call to `sig` (#{current_declaration.mod}). Make sure each call " \
|
|
322
325
|
"to `sig` is immediately followed by a method definition on the same " \
|
|
@@ -407,7 +410,7 @@ module T::Private::Methods
|
|
|
407
410
|
def self.run_all_sig_blocks
|
|
408
411
|
loop do
|
|
409
412
|
break if @sig_wrappers.empty?
|
|
410
|
-
key,
|
|
413
|
+
key, = @sig_wrappers.first
|
|
411
414
|
run_sig_block_for_key(key)
|
|
412
415
|
end
|
|
413
416
|
end
|
|
@@ -424,7 +427,7 @@ module T::Private::Methods
|
|
|
424
427
|
end
|
|
425
428
|
|
|
426
429
|
def self.set_final_checks_on_hooks(enable)
|
|
427
|
-
is_enabled =
|
|
430
|
+
is_enabled = !@old_hooks.nil?
|
|
428
431
|
if enable == is_enabled
|
|
429
432
|
return
|
|
430
433
|
end
|
|
@@ -195,7 +195,7 @@ module T::Private::Methods::CallValidation
|
|
|
195
195
|
raise "Should have used create_validator_procedure_fast"
|
|
196
196
|
end
|
|
197
197
|
# trampoline to reduce stack frame size
|
|
198
|
-
if method_sig.arg_types.
|
|
198
|
+
if method_sig.arg_types.empty?
|
|
199
199
|
create_validator_method_fast0(mod, original_method, method_sig, method_sig.return_type.raw_type)
|
|
200
200
|
elsif method_sig.arg_types.length == 1
|
|
201
201
|
create_validator_method_fast1(mod, original_method, method_sig, method_sig.return_type.raw_type,
|
|
@@ -708,7 +708,7 @@ module T::Private::Methods::CallValidation
|
|
|
708
708
|
|
|
709
709
|
def self.create_validator_procedure_fast(mod, original_method, method_sig)
|
|
710
710
|
# trampoline to reduce stack frame size
|
|
711
|
-
if method_sig.arg_types.
|
|
711
|
+
if method_sig.arg_types.empty?
|
|
712
712
|
create_validator_procedure_fast0(mod, original_method, method_sig)
|
|
713
713
|
elsif method_sig.arg_types.length == 1
|
|
714
714
|
create_validator_procedure_fast1(mod, original_method, method_sig,
|
|
@@ -31,12 +31,15 @@ module T::Private::Methods
|
|
|
31
31
|
)
|
|
32
32
|
end
|
|
33
33
|
|
|
34
|
-
def params(params)
|
|
34
|
+
def params(**params)
|
|
35
35
|
check_live!
|
|
36
36
|
if !decl.params.equal?(ARG_NOT_PROVIDED)
|
|
37
37
|
raise BuilderError.new("You can't call .params twice")
|
|
38
38
|
end
|
|
39
39
|
|
|
40
|
+
if params.empty?
|
|
41
|
+
raise BuilderError.new("params expects keyword arguments")
|
|
42
|
+
end
|
|
40
43
|
decl.params = params
|
|
41
44
|
|
|
42
45
|
self
|
|
@@ -8,9 +8,9 @@ module T::Private::Methods::Modes
|
|
|
8
8
|
def self.override; 'override'; end
|
|
9
9
|
def self.overridable_override; 'overridable_override'; end
|
|
10
10
|
def self.untyped; 'untyped'; end
|
|
11
|
-
MODES = [self.standard, self.abstract, self.overridable, self.override, self.overridable_override, self.untyped]
|
|
11
|
+
MODES = [self.standard, self.abstract, self.overridable, self.override, self.overridable_override, self.untyped].freeze
|
|
12
12
|
|
|
13
|
-
OVERRIDABLE_MODES = [self.override, self.overridable, self.overridable_override, self.untyped, self.abstract]
|
|
14
|
-
OVERRIDE_MODES = [self.override, self.overridable_override]
|
|
13
|
+
OVERRIDABLE_MODES = [self.override, self.overridable, self.overridable_override, self.untyped, self.abstract].freeze
|
|
14
|
+
OVERRIDE_MODES = [self.override, self.overridable_override].freeze
|
|
15
15
|
NON_OVERRIDE_MODES = MODES - OVERRIDE_MODES
|
|
16
16
|
end
|
|
@@ -28,7 +28,7 @@ class T::Private::Methods::Signature
|
|
|
28
28
|
)
|
|
29
29
|
end
|
|
30
30
|
|
|
31
|
-
def initialize(method:, method_name:, raw_arg_types:, raw_return_type:, bind:, mode:, check_level:, parameters: method.parameters,
|
|
31
|
+
def initialize(method:, method_name:, raw_arg_types:, raw_return_type:, bind:, mode:, check_level:, on_failure:, parameters: method.parameters, override_allow_incompatible: false)
|
|
32
32
|
@method = method
|
|
33
33
|
@method_name = method_name
|
|
34
34
|
@arg_types = []
|
|
@@ -68,6 +68,10 @@ class T::Private::Methods::Signature
|
|
|
68
68
|
raise "The declaration for `#{method.name}` has extra parameter(s): #{extra_names.join(', ')}"
|
|
69
69
|
end
|
|
70
70
|
|
|
71
|
+
if parameters.size != raw_arg_types.size
|
|
72
|
+
raise "The declaration for `#{method.name}` has arguments with duplicate names"
|
|
73
|
+
end
|
|
74
|
+
|
|
71
75
|
parameters.zip(raw_arg_types) do |(param_kind, param_name), (type_name, raw_type)|
|
|
72
76
|
if type_name != param_name
|
|
73
77
|
hint = ""
|
|
@@ -194,10 +198,10 @@ class T::Private::Methods::Signature
|
|
|
194
198
|
end
|
|
195
199
|
|
|
196
200
|
def method_desc
|
|
197
|
-
if @method.source_location
|
|
198
|
-
|
|
201
|
+
loc = if @method.source_location
|
|
202
|
+
@method.source_location.join(':')
|
|
199
203
|
else
|
|
200
|
-
|
|
204
|
+
"<unknown location>"
|
|
201
205
|
end
|
|
202
206
|
"#{@method} at #{loc}"
|
|
203
207
|
end
|
|
@@ -100,19 +100,16 @@ module T::Private::Methods::SignatureValidation
|
|
|
100
100
|
raise "Unexpected mode: #{signature.mode}. Please report to #dev-productivity."
|
|
101
101
|
end
|
|
102
102
|
|
|
103
|
+
# Given a singleton class, we can check if it belongs to a
|
|
104
|
+
# module by looking at its superclass; given `module M`,
|
|
105
|
+
# `M.singleton_class.superclass == Module`, which is not true
|
|
106
|
+
# for any class.
|
|
103
107
|
owner = signature.method.owner
|
|
104
108
|
if (signature.mode == Modes.abstract || Modes::OVERRIDABLE_MODES.include?(signature.mode)) &&
|
|
105
|
-
owner.singleton_class?
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
# for any class.
|
|
110
|
-
if owner.superclass == Module
|
|
111
|
-
raise "Defining an overridable class method (via #{pretty_mode(signature)}) " \
|
|
112
|
-
"on a module is not allowed. Class methods on " \
|
|
113
|
-
"modules do not get inherited and thus cannot be overridden. For help, ask in " \
|
|
114
|
-
"#dev-productivity."
|
|
115
|
-
end
|
|
109
|
+
owner.singleton_class? && owner.superclass == Module
|
|
110
|
+
raise "Defining an overridable class method (via #{pretty_mode(signature)}) " \
|
|
111
|
+
"on a module is not allowed. Class methods on " \
|
|
112
|
+
"modules do not get inherited and thus cannot be overridden."
|
|
116
113
|
end
|
|
117
114
|
end
|
|
118
115
|
|
|
@@ -219,10 +216,10 @@ module T::Private::Methods::SignatureValidation
|
|
|
219
216
|
end
|
|
220
217
|
|
|
221
218
|
private_class_method def self.method_loc_str(method)
|
|
222
|
-
if method.source_location
|
|
223
|
-
|
|
219
|
+
loc = if method.source_location
|
|
220
|
+
method.source_location.join(':')
|
|
224
221
|
else
|
|
225
|
-
|
|
222
|
+
"<unknown location>"
|
|
226
223
|
end
|
|
227
224
|
"#{method.owner} at #{loc}"
|
|
228
225
|
end
|
data/lib/types/private/sealed.rb
CHANGED
|
@@ -7,6 +7,11 @@ module T::Private::Sealed
|
|
|
7
7
|
super
|
|
8
8
|
this_line = Kernel.caller.find {|line| !line.match(/in `inherited'$/)}
|
|
9
9
|
T::Private::Sealed.validate_inheritance(this_line, self, 'inherited')
|
|
10
|
+
@sorbet_sealed_module_all_subclasses << other
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def sealed_subclasses
|
|
14
|
+
@sorbet_sealed_module_all_subclasses
|
|
10
15
|
end
|
|
11
16
|
end
|
|
12
17
|
|
|
@@ -15,12 +20,21 @@ module T::Private::Sealed
|
|
|
15
20
|
super
|
|
16
21
|
this_line = Kernel.caller.find {|line| !line.match(/in `included'$/)}
|
|
17
22
|
T::Private::Sealed.validate_inheritance(this_line, self, 'included')
|
|
23
|
+
@sorbet_sealed_module_all_subclasses << other
|
|
18
24
|
end
|
|
19
25
|
|
|
20
26
|
def extended(other)
|
|
21
27
|
super
|
|
22
28
|
this_line = Kernel.caller.find {|line| !line.match(/in `extended'$/)}
|
|
23
29
|
T::Private::Sealed.validate_inheritance(this_line, self, 'extended')
|
|
30
|
+
@sorbet_sealed_module_all_subclasses << other
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def sealed_subclasses
|
|
34
|
+
# this will freeze the set so that you can never get into a
|
|
35
|
+
# state where you use the subclasses list and then something
|
|
36
|
+
# else will add to it
|
|
37
|
+
@sorbet_sealed_module_all_subclasses.freeze
|
|
24
38
|
end
|
|
25
39
|
end
|
|
26
40
|
|
|
@@ -39,6 +53,7 @@ module T::Private::Sealed
|
|
|
39
53
|
raise "Couldn't determine declaration file for sealed class."
|
|
40
54
|
end
|
|
41
55
|
mod.instance_variable_set(:@sorbet_sealed_module_decl_file, decl_file)
|
|
56
|
+
mod.instance_variable_set(:@sorbet_sealed_module_all_subclasses, Set.new)
|
|
42
57
|
end
|
|
43
58
|
|
|
44
59
|
def self.sealed_module?(mod)
|
|
@@ -55,7 +70,7 @@ module T::Private::Sealed
|
|
|
55
70
|
|
|
56
71
|
if !this_file.start_with?(decl_file)
|
|
57
72
|
whitelist = T::Configuration.sealed_violation_whitelist
|
|
58
|
-
if whitelist
|
|
73
|
+
if !whitelist.nil? && whitelist.any? {|pattern| this_file =~ pattern}
|
|
59
74
|
return
|
|
60
75
|
end
|
|
61
76
|
|
|
@@ -54,7 +54,7 @@ class T::Props::Decorator
|
|
|
54
54
|
@props = @props.merge(prop => rules.freeze).freeze
|
|
55
55
|
end
|
|
56
56
|
|
|
57
|
-
VALID_RULE_KEYS = T.let(%i
|
|
57
|
+
VALID_RULE_KEYS = T.let(%i[
|
|
58
58
|
enum
|
|
59
59
|
foreign
|
|
60
60
|
foreign_hint_only
|
|
@@ -68,7 +68,7 @@ class T::Props::Decorator
|
|
|
68
68
|
extra
|
|
69
69
|
setter_validate
|
|
70
70
|
_tnilable
|
|
71
|
-
|
|
71
|
+
].map {|k| [k, true]}.to_h.freeze, T::Hash[Symbol, T::Boolean])
|
|
72
72
|
private_constant :VALID_RULE_KEYS
|
|
73
73
|
|
|
74
74
|
sig {params(key: Symbol).returns(T::Boolean).checked(:never)}
|
|
@@ -153,12 +153,10 @@ class T::Props::Decorator
|
|
|
153
153
|
val = instance.instance_variable_get(rules[:accessor_key])
|
|
154
154
|
if !val.nil?
|
|
155
155
|
val
|
|
156
|
+
elsif (d = rules[:ifunset])
|
|
157
|
+
T::Props::Utils.deep_clone_object(d)
|
|
156
158
|
else
|
|
157
|
-
|
|
158
|
-
T::Props::Utils.deep_clone_object(d)
|
|
159
|
-
else
|
|
160
|
-
nil
|
|
161
|
-
end
|
|
159
|
+
nil
|
|
162
160
|
end
|
|
163
161
|
end
|
|
164
162
|
|
|
@@ -219,15 +217,13 @@ class T::Props::Decorator
|
|
|
219
217
|
raise ArgumentError.new("At least one invalid prop arg supplied in #{self}: #{rules.keys.inspect}")
|
|
220
218
|
end
|
|
221
219
|
|
|
222
|
-
if !
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
)
|
|
230
|
-
end
|
|
220
|
+
if !rules[:clobber_existing_method!] && !rules[:without_accessors] && BANNED_METHOD_NAMES.include?(name.to_sym)
|
|
221
|
+
raise ArgumentError.new(
|
|
222
|
+
"#{name} can't be used as a prop in #{@class} because a method with " \
|
|
223
|
+
"that name already exists (defined by #{@class.instance_method(name).owner} " \
|
|
224
|
+
"at #{@class.instance_method(name).source_location || '<unknown>'}). " \
|
|
225
|
+
"(If using this name is unavoidable, try `without_accessors: true`.)"
|
|
226
|
+
)
|
|
231
227
|
end
|
|
232
228
|
|
|
233
229
|
extra = rules[:extra]
|
|
@@ -238,7 +234,7 @@ class T::Props::Decorator
|
|
|
238
234
|
nil
|
|
239
235
|
end
|
|
240
236
|
|
|
241
|
-
SAFE_NAME = /\A[A-Za-z_][A-Za-z0-9_-]*\z
|
|
237
|
+
SAFE_NAME = T.let(/\A[A-Za-z_][A-Za-z0-9_-]*\z/.freeze, Regexp)
|
|
242
238
|
|
|
243
239
|
# Used to validate both prop names and serialized forms
|
|
244
240
|
sig {params(name: T.any(Symbol, String)).void}
|
|
@@ -312,13 +308,12 @@ class T::Props::Decorator
|
|
|
312
308
|
sensitivity_and_pii = {sensitivity: rules[:sensitivity]}
|
|
313
309
|
if defined?(Opus) && defined?(Opus::Sensitivity) && defined?(Opus::Sensitivity::Utils)
|
|
314
310
|
sensitivity_and_pii = Opus::Sensitivity::Utils.normalize_sensitivity_and_pii_annotation(sensitivity_and_pii)
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
if defined?(Opus) && defined?(Opus::Sensitivity) && defined?(Opus::Sensitivity::PIIable)
|
|
311
|
+
|
|
312
|
+
# We check for Class so this is only applied on concrete
|
|
313
|
+
# documents/models; We allow mixins containing props to not
|
|
314
|
+
# specify their PII nature, as long as every class into which they
|
|
315
|
+
# are ultimately included does.
|
|
316
|
+
#
|
|
322
317
|
if sensitivity_and_pii[:pii] && @class.is_a?(Class) && !T.unsafe(@class).contains_pii?
|
|
323
318
|
raise ArgumentError.new(
|
|
324
319
|
'Cannot include a pii prop in a class that declares `contains_no_pii`'
|
|
@@ -488,7 +483,7 @@ class T::Props::Decorator
|
|
|
488
483
|
.void
|
|
489
484
|
end
|
|
490
485
|
private def handle_foreign_hint_only_option(prop_name, prop_cls, foreign_hint_only)
|
|
491
|
-
if ![String, Array].include?(prop_cls) && !
|
|
486
|
+
if ![String, Array].include?(prop_cls) && !prop_cls.is_a?(T::Props::CustomType)
|
|
492
487
|
raise ArgumentError.new(
|
|
493
488
|
"`foreign_hint_only` can only be used with String or Array prop types"
|
|
494
489
|
)
|
|
@@ -546,10 +541,10 @@ class T::Props::Decorator
|
|
|
546
541
|
# of the method, optimizing it so this only runs on the first invocation.
|
|
547
542
|
foreign = resolved_foreign
|
|
548
543
|
end
|
|
549
|
-
if allow_direct_mutation.nil?
|
|
550
|
-
|
|
544
|
+
opts = if allow_direct_mutation.nil?
|
|
545
|
+
{}
|
|
551
546
|
else
|
|
552
|
-
|
|
547
|
+
{allow_direct_mutation: allow_direct_mutation}
|
|
553
548
|
end
|
|
554
549
|
|
|
555
550
|
T.unsafe(self.class).decorator.foreign_prop_get(self, prop_name, foreign, rules, opts)
|
|
@@ -644,25 +639,33 @@ class T::Props::Decorator
|
|
|
644
639
|
# (b) it's safe because the getter was defined by this file.
|
|
645
640
|
#
|
|
646
641
|
unless rules[:without_accessors]
|
|
647
|
-
if child
|
|
648
|
-
child.instance_method(name).source_location&.first == __FILE__
|
|
642
|
+
if clobber_getter?(child, name)
|
|
649
643
|
child.send(:define_method, name) do
|
|
650
644
|
T.unsafe(self.class).decorator.prop_get(self, name, rules)
|
|
651
645
|
end
|
|
652
646
|
end
|
|
653
647
|
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
child.send(:define_method, "#{name}=") do |val|
|
|
658
|
-
T.unsafe(self.class).decorator.prop_set(self, name, val, rules)
|
|
659
|
-
end
|
|
648
|
+
if !rules[:immutable] && clobber_setter?(child, name)
|
|
649
|
+
child.send(:define_method, "#{name}=") do |val|
|
|
650
|
+
T.unsafe(self.class).decorator.prop_set(self, name, val, rules)
|
|
660
651
|
end
|
|
661
652
|
end
|
|
662
653
|
end
|
|
663
654
|
end
|
|
664
655
|
end
|
|
665
656
|
|
|
657
|
+
sig {params(child: T.all(Module, T::Props::ClassMethods), prop: Symbol).returns(T::Boolean).checked(:never)}
|
|
658
|
+
private def clobber_getter?(child, prop)
|
|
659
|
+
!!(child.decorator.method(:prop_get).owner != method(:prop_get).owner &&
|
|
660
|
+
child.instance_method(prop).source_location&.first == __FILE__)
|
|
661
|
+
end
|
|
662
|
+
|
|
663
|
+
sig {params(child: T.all(Module, T::Props::ClassMethods), prop: Symbol).returns(T::Boolean).checked(:never)}
|
|
664
|
+
private def clobber_setter?(child, prop)
|
|
665
|
+
!!(child.decorator.method(:prop_set).owner != method(:prop_set).owner &&
|
|
666
|
+
child.instance_method("#{prop}=").source_location&.first == __FILE__)
|
|
667
|
+
end
|
|
668
|
+
|
|
666
669
|
sig {params(mod: Module).void.checked(:never)}
|
|
667
670
|
def plugin(mod)
|
|
668
671
|
decorated_class.plugins << mod
|
|
@@ -38,7 +38,7 @@ module T::Props
|
|
|
38
38
|
assert_equal(s(:lvar, :found), ret)
|
|
39
39
|
|
|
40
40
|
prop_clauses.each_with_index do |clause, i|
|
|
41
|
-
if i
|
|
41
|
+
if i.even?
|
|
42
42
|
validate_deserialize_hash_read(clause)
|
|
43
43
|
else
|
|
44
44
|
validate_deserialize_ivar_set(clause)
|
|
@@ -251,17 +251,17 @@ module T::Props
|
|
|
251
251
|
# Method calls generated by SerdeTransform
|
|
252
252
|
private_class_method def self.whitelisted_methods_for_serialize
|
|
253
253
|
@whitelisted_methods_for_serialize ||= {
|
|
254
|
-
:
|
|
255
|
-
:
|
|
256
|
-
:
|
|
254
|
+
lvar: %i{dup map transform_values transform_keys each_with_object nil? []= serialize},
|
|
255
|
+
ivar: %i[dup map transform_values transform_keys each_with_object serialize],
|
|
256
|
+
const: %i[checked_serialize deep_clone_object],
|
|
257
257
|
}
|
|
258
258
|
end
|
|
259
259
|
|
|
260
260
|
# Method calls generated by SerdeTransform
|
|
261
261
|
private_class_method def self.whitelisted_methods_for_deserialize
|
|
262
262
|
@whitelisted_methods_for_deserialize ||= {
|
|
263
|
-
:
|
|
264
|
-
:
|
|
263
|
+
lvar: %i{dup map transform_values transform_keys each_with_object nil? []= to_f},
|
|
264
|
+
const: %i[deserialize from_hash deep_clone_object soft_assert_handler],
|
|
265
265
|
}
|
|
266
266
|
end
|
|
267
267
|
end
|
|
@@ -48,12 +48,12 @@ module T::Props
|
|
|
48
48
|
SerdeTransform::Mode::DESERIALIZE,
|
|
49
49
|
'val'
|
|
50
50
|
)
|
|
51
|
-
if transformation
|
|
51
|
+
transformed_val = if transformation
|
|
52
52
|
# Rescuing exactly NoMethodError is intended as a temporary hack
|
|
53
53
|
# to preserve the semantics from before codegen. More generally
|
|
54
54
|
# we are inconsistent about typechecking on deser and need to decide
|
|
55
55
|
# our strategy here.
|
|
56
|
-
|
|
56
|
+
<<~RUBY
|
|
57
57
|
begin
|
|
58
58
|
#{transformation}
|
|
59
59
|
rescue NoMethodError => e
|
|
@@ -71,7 +71,7 @@ module T::Props
|
|
|
71
71
|
end
|
|
72
72
|
RUBY
|
|
73
73
|
else
|
|
74
|
-
|
|
74
|
+
'val'
|
|
75
75
|
end
|
|
76
76
|
|
|
77
77
|
nil_handler = generate_nil_handler(
|
|
@@ -99,20 +99,18 @@ module T::Props
|
|
|
99
99
|
else
|
|
100
100
|
"#{varname}.nil? ? nil : #{inner}"
|
|
101
101
|
end
|
|
102
|
-
|
|
102
|
+
elsif type.types.all? {|t| generate(t, mode, varname).nil?}
|
|
103
103
|
# Handle, e.g., T::Boolean
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
"T::Props::Utils.deep_clone_object(#{varname})"
|
|
115
|
-
end
|
|
104
|
+
nil
|
|
105
|
+
else
|
|
106
|
+
# We currently deep_clone_object if the type was T.any(Integer, Float).
|
|
107
|
+
# When we get better support for union types (maybe this specific
|
|
108
|
+
# union type, because it would be a replacement for
|
|
109
|
+
# Chalk::ODM::DeprecatedNumemric), we could opt to special case
|
|
110
|
+
# this union to have no specific serde transform (the only reason
|
|
111
|
+
# why Float has a special case is because round tripping through
|
|
112
|
+
# JSON might normalize Floats to Integers)
|
|
113
|
+
"T::Props::Utils.deep_clone_object(#{varname})"
|
|
116
114
|
end
|
|
117
115
|
when T::Types::Intersection
|
|
118
116
|
dynamic_fallback = "T::Props::Utils.deep_clone_object(#{varname})"
|
|
@@ -179,13 +177,9 @@ module T::Props
|
|
|
179
177
|
end
|
|
180
178
|
end
|
|
181
179
|
|
|
182
|
-
# Guard against overrides of `name` or `to_s`
|
|
183
|
-
MODULE_NAME = T.let(Module.instance_method(:name), UnboundMethod)
|
|
184
|
-
private_constant :MODULE_NAME
|
|
185
|
-
|
|
186
180
|
sig {params(type: Module).returns(T.nilable(String)).checked(:never)}
|
|
187
181
|
private_class_method def self.module_name(type)
|
|
188
|
-
|
|
182
|
+
T::Configuration.module_name_mangler.call(type)
|
|
189
183
|
end
|
|
190
184
|
end
|
|
191
185
|
end
|
|
@@ -58,10 +58,7 @@ module T::Props
|
|
|
58
58
|
# from disk) are correct, so we use more thorough runtime
|
|
59
59
|
# checks there
|
|
60
60
|
if non_nil_type.recursively_valid?(val)
|
|
61
|
-
|
|
62
|
-
validate.call(prop, val)
|
|
63
|
-
end
|
|
64
|
-
instance_variable_set(accessor_key, val)
|
|
61
|
+
validate&.call(prop, val)
|
|
65
62
|
else
|
|
66
63
|
T::Props::Private::SetterFactory.raise_pretty_error(
|
|
67
64
|
klass,
|
|
@@ -69,8 +66,8 @@ module T::Props
|
|
|
69
66
|
non_nil_type,
|
|
70
67
|
val,
|
|
71
68
|
)
|
|
72
|
-
instance_variable_set(accessor_key, val)
|
|
73
69
|
end
|
|
70
|
+
instance_variable_set(accessor_key, val)
|
|
74
71
|
end
|
|
75
72
|
end
|
|
76
73
|
|
|
@@ -94,9 +91,7 @@ module T::Props
|
|
|
94
91
|
# from disk) are correct, so we use more thorough runtime
|
|
95
92
|
# checks there
|
|
96
93
|
elsif non_nil_type.recursively_valid?(val)
|
|
97
|
-
|
|
98
|
-
validate.call(prop, val)
|
|
99
|
-
end
|
|
94
|
+
validate&.call(prop, val)
|
|
100
95
|
instance_variable_set(accessor_key, val)
|
|
101
96
|
else
|
|
102
97
|
T::Props::Private::SetterFactory.raise_pretty_error(
|
|
@@ -15,7 +15,7 @@ module T::Props::Serializable
|
|
|
15
15
|
# exception if this object has mandatory props with missing
|
|
16
16
|
# values.
|
|
17
17
|
# @return [Hash] A serialization of this object.
|
|
18
|
-
def serialize(strict=true)
|
|
18
|
+
def serialize(strict=true) # rubocop:disable Style/OptionalBooleanParameter (changing this API is unfortunately not feasible)
|
|
19
19
|
begin
|
|
20
20
|
h = __t_props_generated_serialize(strict)
|
|
21
21
|
rescue => e
|
|
@@ -56,7 +56,7 @@ module T::Props::Serializable
|
|
|
56
56
|
# the hash contains keys that do not correspond to any known
|
|
57
57
|
# props on this instance.
|
|
58
58
|
# @return [void]
|
|
59
|
-
def deserialize(hash, strict=false)
|
|
59
|
+
def deserialize(hash, strict=false) # rubocop:disable Style/OptionalBooleanParameter (changing this API is unfortunately not feasible)
|
|
60
60
|
begin
|
|
61
61
|
hash_keys_matching_props = __t_props_generated_deserialize(hash)
|
|
62
62
|
rescue => e
|
|
@@ -180,7 +180,7 @@ module T::Props::Serializable::DecoratorMethods
|
|
|
180
180
|
def prop_dont_store?(prop); prop_rules(prop)[:dont_store]; end
|
|
181
181
|
def prop_by_serialized_forms; @class.prop_by_serialized_forms; end
|
|
182
182
|
|
|
183
|
-
def from_hash(hash, strict=false)
|
|
183
|
+
def from_hash(hash, strict=false) # rubocop:disable Style/OptionalBooleanParameter (changing this API is unfortunately not feasible)
|
|
184
184
|
raise ArgumentError.new("#{hash.inspect} provided to from_hash") if !(hash && hash.is_a?(Hash))
|
|
185
185
|
|
|
186
186
|
i = @class.allocate
|
|
@@ -227,7 +227,7 @@ module T::Props::Serializable::DecoratorMethods
|
|
|
227
227
|
source_lines = self.send(generate_source_method).split("\n")
|
|
228
228
|
previous_blank = source_lines[0...line_num].rindex(&:empty?) || 0
|
|
229
229
|
next_blank = line_num + (source_lines[line_num..-1]&.find_index(&:empty?) || 0)
|
|
230
|
-
context = "
|
|
230
|
+
context = " #{source_lines[(previous_blank + 1)...next_blank].join("\n ")}"
|
|
231
231
|
<<~MSG
|
|
232
232
|
Error in #{decorated_class.name}##{generated_method}: #{error.message}
|
|
233
233
|
at line #{line_num-previous_blank-1} in:
|
|
@@ -318,7 +318,7 @@ module T::Props::Serializable::ClassMethods
|
|
|
318
318
|
# Allocate a new instance and call {#deserialize} to load a new
|
|
319
319
|
# object from a hash.
|
|
320
320
|
# @return [Serializable]
|
|
321
|
-
def from_hash(hash, strict=false)
|
|
321
|
+
def from_hash(hash, strict=false) # rubocop:disable Style/OptionalBooleanParameter (changing this API is unfortunately not feasible)
|
|
322
322
|
self.decorator.from_hash(hash, strict)
|
|
323
323
|
end
|
|
324
324
|
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
module T::Props::TypeValidation
|
|
5
5
|
include T::Props::Plugin
|
|
6
6
|
|
|
7
|
-
BANNED_TYPES = [Object, BasicObject, Kernel]
|
|
7
|
+
BANNED_TYPES = [Object, BasicObject, Kernel].freeze
|
|
8
8
|
|
|
9
9
|
class UnderspecifiedType < ArgumentError; end
|
|
10
10
|
|
|
@@ -13,7 +13,7 @@ module T::Props::TypeValidation
|
|
|
13
13
|
|
|
14
14
|
sig {params(key: Symbol).returns(T::Boolean).checked(:never)}
|
|
15
15
|
def valid_rule_key?(key)
|
|
16
|
-
super ||
|
|
16
|
+
super || key == :DEPRECATED_underspecified_type
|
|
17
17
|
end
|
|
18
18
|
|
|
19
19
|
sig do
|
data/lib/types/types/base.rb
CHANGED
|
@@ -119,8 +119,10 @@ module T::Types
|
|
|
119
119
|
# Default inspect behavior of, eg; `#<Object:0x0...>` is ugly; just print the hash instead, which is more concise/readable.
|
|
120
120
|
if obj.method(:inspect).owner == Kernel
|
|
121
121
|
"type #{obj.class} with hash #{obj.hash}"
|
|
122
|
-
|
|
122
|
+
elsif T::Configuration.include_value_in_type_errors?
|
|
123
123
|
"type #{obj.class} with value #{T::Utils.string_truncate_middle(obj.inspect, 30, 30)}"
|
|
124
|
+
else
|
|
125
|
+
"type #{obj.class}"
|
|
124
126
|
end
|
|
125
127
|
rescue StandardError, SystemStackError
|
|
126
128
|
"type #{obj.class} with unprintable value"
|
|
@@ -37,7 +37,7 @@ module T::Types
|
|
|
37
37
|
return false unless @type.recursively_valid?(obj[it])
|
|
38
38
|
it += 1
|
|
39
39
|
end
|
|
40
|
-
|
|
40
|
+
true
|
|
41
41
|
end
|
|
42
42
|
when Hash
|
|
43
43
|
return false unless @type.is_a?(FixedArray)
|
|
@@ -50,10 +50,10 @@ module T::Types
|
|
|
50
50
|
# iterate over a [key, value] array, so we can't juse use the @type.recursively_valid?(v)
|
|
51
51
|
return false if !key_type.recursively_valid?(key) || !value_type.recursively_valid?(val)
|
|
52
52
|
end
|
|
53
|
-
|
|
53
|
+
true
|
|
54
54
|
when Enumerator
|
|
55
55
|
# Enumerators can be unbounded: see `[:foo, :bar].cycle`
|
|
56
|
-
|
|
56
|
+
true
|
|
57
57
|
when Range
|
|
58
58
|
# A nil beginning or a nil end does not provide any type information. That is, nil in a range represents
|
|
59
59
|
# boundlessness, it does not express a type. For example `(nil...nil)` is not a T::Range[NilClass], its a range
|
|
@@ -65,7 +65,7 @@ module T::Types
|
|
|
65
65
|
return false unless @type.recursively_valid?(item)
|
|
66
66
|
end
|
|
67
67
|
|
|
68
|
-
|
|
68
|
+
true
|
|
69
69
|
else
|
|
70
70
|
# We don't check the enumerable since it isn't guaranteed to be
|
|
71
71
|
# rewindable (e.g. STDIN) and it may be expensive to enumerate
|
data/lib/types/utils.rb
CHANGED
|
@@ -176,7 +176,7 @@ module T::Utils
|
|
|
176
176
|
def self.get_type_info(prop_type)
|
|
177
177
|
if prop_type.is_a?(T::Types::Union)
|
|
178
178
|
non_nilable_type = T::Utils.unwrap_nilable(prop_type)
|
|
179
|
-
if non_nilable_type
|
|
179
|
+
if non_nilable_type&.is_a?(T::Types::Simple)
|
|
180
180
|
non_nilable_type = non_nilable_type.raw_type
|
|
181
181
|
end
|
|
182
182
|
TypeInfo.new(true, non_nilable_type)
|
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.6198
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Stripe
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date:
|
|
11
|
+
date: 2021-01-07 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: minitest
|
|
@@ -210,7 +210,6 @@ files:
|
|
|
210
210
|
- lib/types/props/type_validation.rb
|
|
211
211
|
- lib/types/props/utils.rb
|
|
212
212
|
- lib/types/props/weak_constructor.rb
|
|
213
|
-
- lib/types/runtime_profiled.rb
|
|
214
213
|
- lib/types/sig.rb
|
|
215
214
|
- lib/types/struct.rb
|
|
216
215
|
- lib/types/types/attached_class.rb
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
# typed: strict
|
|
2
|
-
# frozen_string_literal: true
|
|
3
|
-
|
|
4
|
-
#
|
|
5
|
-
# From the static system, T::Utils::RuntimeProfiled is T.untyped.
|
|
6
|
-
#
|
|
7
|
-
# But from the runtime system, it's a random class (specifically, a class that
|
|
8
|
-
# normal programs currently don't have any instances of).
|
|
9
|
-
#
|
|
10
|
-
# Thus, T::Utils::RuntimeProfiled can be used to introduce runtime-only type
|
|
11
|
-
# errors. This seems like a bad idea, but it's not. It can be used to gather
|
|
12
|
-
# runtime type information from running code via a custom T::Configuration
|
|
13
|
-
# handler.
|
|
14
|
-
#
|
|
15
|
-
# This process has only ever been used at Stripe, and is likely to have rough
|
|
16
|
-
# edges. If you've managed to find your way here and you're curious to try it,
|
|
17
|
-
# please chat with us on Slack. There are no docs.
|
|
18
|
-
#
|
|
19
|
-
# See also: the --suggest-runtime-profiled flag to sorbet.
|
|
20
|
-
#
|
|
21
|
-
|
|
22
|
-
module T; end
|
|
23
|
-
module T::Utils; end
|
|
24
|
-
class T::Utils::RuntimeProfiled; end
|