sorbet-runtime 0.5.8993 → 0.5.9103

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c9b153e0e894eb0a81121fd2c9a2f52cccf1654a78b6fc72d75eacc10d6ee288
4
- data.tar.gz: c09b72a6a28a96d35e9076b206d9019df999659145842f6c2b5ec7d3481e4850
3
+ metadata.gz: dd50aa97fa3835f75f05ddad407ced4062053e791cb9c246a4ac617cb6e4eeb5
4
+ data.tar.gz: dd7a5031c72ae5ce3a09324d2b110c343e1409e350c12b1a8bf8a1bf21763c90
5
5
  SHA512:
6
- metadata.gz: 948194b8718dd728ecaa0668421480103ce052587c6ceebee0ec01818ecf529d0a62715f0c66409ff07594c6ad4c8c0f22a05921129c66cb405f2fe143b46705
7
- data.tar.gz: a788eea54fe2321d6060a79ef31ab784b21a6a4e9e15b299600abbe9699e4cc8095eaa69bedbfc07fa5f2a3e3ef959e002562db705050f8882878dbb15b6a14e
6
+ metadata.gz: fa6efdc3b42d1b42322af825df44bf33c625cc24b2d93f5474887218f686604e8603db6c19afae00c29c6e32e1e1ecceb52a07de68471ec9cf18aea01ab98ef4
7
+ data.tar.gz: a16780c9665e17e0666d2e2b04a5b60a04a7b02863f111d3a068e2b5c7b32b72334b246b00e76ddfa98d1a64fd78c79fa1467e03d19d80203c0bc5ccacf28b6c
@@ -112,3 +112,6 @@ require_relative 'types/struct'
112
112
  require_relative 'types/non_forcing_constants'
113
113
 
114
114
  require_relative 'types/compatibility_patches'
115
+
116
+ # Sorbet Compiler support module
117
+ require_relative 'types/private/compiler'
data/lib/types/_types.rb CHANGED
@@ -78,10 +78,8 @@ module T
78
78
  T::Types::ClassOf.new(klass)
79
79
  end
80
80
 
81
-
82
81
  ## END OF THE METHODS TO PASS TO `sig`.
83
82
 
84
-
85
83
  # Constructs a type alias. Used to create a short name for a larger type. In Ruby this returns a
86
84
  # wrapper that contains a proc that is evaluated to get the underlying type. This syntax however
87
85
  # is needed for support by the static checker. Example usage:
@@ -112,7 +112,7 @@ module T::Configuration
112
112
  # statically, so that methods don't have to guard themselves from being
113
113
  # called incorrectly by untyped code.
114
114
  #
115
- # @param [:never, :tests, :always] default_checked_level
115
+ # @param [:never, :compiled, :tests, :always] default_checked_level
116
116
  def self.default_checked_level=(default_checked_level)
117
117
  T::Private::RuntimeLevels.default_checked_level = default_checked_level
118
118
  end
@@ -429,10 +429,10 @@ module T::Configuration
429
429
  MODULE_NAME = Module.instance_method(:name)
430
430
  private_constant :MODULE_NAME
431
431
 
432
- if T::Configuration::AT_LEAST_RUBY_2_7
433
- @default_module_name_mangler = ->(type) {MODULE_NAME.bind_call(type)}
432
+ @default_module_name_mangler = if T::Configuration::AT_LEAST_RUBY_2_7
433
+ ->(type) {MODULE_NAME.bind_call(type)}
434
434
  else
435
- @default_module_name_mangler = ->(type) {MODULE_NAME.bind(type).call}
435
+ ->(type) {MODULE_NAME.bind(type).call}
436
436
  end
437
437
 
438
438
  @module_name_mangler = nil
@@ -523,6 +523,16 @@ module T::Configuration
523
523
  @legacy_t_enum_migration_mode || false
524
524
  end
525
525
 
526
+ @prop_freeze_handler = ->(instance, prop_name) {}
527
+
528
+ def self.prop_freeze_handler=(handler)
529
+ @prop_freeze_handler = handler
530
+ end
531
+
532
+ def self.prop_freeze_handler
533
+ @prop_freeze_handler
534
+ end
535
+
526
536
  # @param [Array] sealed_violation_whitelist An array of Regexp to validate
527
537
  # whether inheriting /including a sealed module outside the defining module
528
538
  # should be allowed. Useful to whitelist benign violations, like shim files
data/lib/types/enum.rb CHANGED
@@ -134,10 +134,8 @@ class T::Enum
134
134
  self.from_serialized(mongo_value)
135
135
  end
136
136
 
137
-
138
137
  ## Enum instance methods ##
139
138
 
140
-
141
139
  sig {returns(T.self_type)}
142
140
  def dup
143
141
  self
@@ -180,7 +178,6 @@ class T::Enum
180
178
  end
181
179
  end
182
180
 
183
-
184
181
  # NB: Do not call this method. This exists to allow for a safe migration path in places where enum
185
182
  # values are compared directly against string values.
186
183
  #
@@ -246,10 +243,8 @@ class T::Enum
246
243
  )
247
244
  end
248
245
 
249
-
250
246
  ## Private implementation ##
251
247
 
252
-
253
248
  sig {params(serialized_val: SerializedVal).void}
254
249
  def initialize(serialized_val=nil)
255
250
  raise 'T::Enum is abstract' if self.class == T::Enum
@@ -366,6 +361,6 @@ class T::Enum
366
361
 
367
362
  sig {params(args: String).returns(T.attached_class)}
368
363
  def self._load(args)
369
- deserialize(Marshal.load(args))
364
+ deserialize(Marshal.load(args)) # rubocop:disable Security/MarshalLoad
370
365
  end
371
366
  end
@@ -2,14 +2,6 @@
2
2
  # typed: false
3
3
 
4
4
  module T::Private
5
- # Dynamically confirm that `value` is recursively a valid value of
6
- # type `type`, including recursively through collections. Note that
7
- # in some cases this runtime check can be very expensive, especially
8
- # with large collections of objects.
9
- def self.check_type_recursive!(value, type)
10
- T::Private::Casts.cast_recursive(value, type, cast_method: "T.check_type_recursive!")
11
- end
12
-
13
5
  module Casts
14
6
  def self.cast(value, type, cast_method:)
15
7
  begin
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+ # typed: true
3
+
4
+ module T::Private
5
+ module Compiler
6
+ # If this code ever runs, the caller is running interpreted (or the
7
+ # compiler didn't see the call to `running_compiled?` statically.)
8
+ #
9
+ # The Sorbet Compiler replaces calls to this method unconditionally (no
10
+ # runtime guards) to return `true` when compiling a file.
11
+ def self.running_compiled?
12
+ false
13
+ end
14
+
15
+ # Returns `nil` because the compiler isn't running.
16
+ #
17
+ # The Sorbet Compiler replaces calls to this method unconditionally (no
18
+ # runtime guards) to return a String showing the Sorbet Compiler's version
19
+ # string.
20
+ def self.compiler_version
21
+ nil
22
+ end
23
+ end
24
+ end
@@ -20,7 +20,7 @@ module T::Private::Methods
20
20
  # twice is permitted). we could do this with two tables, but it seems slightly
21
21
  # cleaner with a single table.
22
22
  # Effectively T::Hash[Module, T.nilable(Set))]
23
- @modules_with_final = Hash.new { |hash, key| hash[key] = nil }
23
+ @modules_with_final = Hash.new {|hash, key| hash[key] = nil}
24
24
  # this stores the old [included, extended] hooks for Module and inherited hook for Class that we override when
25
25
  # enabling final checks for when those hooks are called. the 'hooks' here don't have anything to do with the 'hooks'
26
26
  # in installed_hooks.
@@ -158,7 +158,7 @@ module T::Private::Methods
158
158
 
159
159
  definition_file, definition_line = T::Private::Methods.signature_for_method(ancestor.instance_method(method_name)).method.source_location
160
160
  is_redefined = target == ancestor
161
- caller_loc = caller_locations&.find {|l| !l.to_s.match?(%r{sorbet-runtime[^/]*/lib/}) }
161
+ caller_loc = caller_locations&.find {|l| !l.to_s.match?(%r{sorbet-runtime[^/]*/lib/})}
162
162
  extra_info = "\n"
163
163
  if caller_loc
164
164
  extra_info = (is_redefined ? "Redefined" : "Overridden") + " here: #{caller_loc.path}:#{caller_loc.lineno}\n"
@@ -456,6 +456,10 @@ module T::Private::Methods
456
456
  end
457
457
  end
458
458
 
459
+ def self.all_checked_tests_sigs
460
+ @signatures_by_method.values.select {|sig| sig.check_level == :tests}
461
+ end
462
+
459
463
  # the module target is adding the methods from the module source to itself. we need to check that for all instance
460
464
  # methods M on source, M is not defined on any of target's ancestors.
461
465
  def self._hook_impl(target, singleton_class, source)
@@ -88,8 +88,8 @@ module T::Private::Methods
88
88
  if !decl.checked.equal?(ARG_NOT_PROVIDED)
89
89
  raise BuilderError.new("You can't call .checked multiple times in a signature.")
90
90
  end
91
- if level == :never && !decl.on_failure.equal?(ARG_NOT_PROVIDED)
92
- raise BuilderError.new("You can't use .checked(:never) with .on_failure because .on_failure will have no effect.")
91
+ if (level == :never || level == :compiled) && !decl.on_failure.equal?(ARG_NOT_PROVIDED)
92
+ raise BuilderError.new("You can't use .checked(:#{level}) with .on_failure because .on_failure will have no effect.")
93
93
  end
94
94
  if !T::Private::RuntimeLevels::LEVELS.include?(level)
95
95
  raise BuilderError.new("Invalid `checked` level '#{level}'. Use one of: #{T::Private::RuntimeLevels::LEVELS}.")
@@ -106,8 +106,8 @@ module T::Private::Methods
106
106
  if !decl.on_failure.equal?(ARG_NOT_PROVIDED)
107
107
  raise BuilderError.new("You can't call .on_failure multiple times in a signature.")
108
108
  end
109
- if decl.checked == :never
110
- raise BuilderError.new("You can't use .on_failure with .checked(:never) because .on_failure will have no effect.")
109
+ if decl.checked == :never || decl.checked == :compiled
110
+ raise BuilderError.new("You can't use .on_failure with .checked(:#{decl.checked}) because .on_failure will have no effect.")
111
111
  end
112
112
 
113
113
  decl.on_failure = args
@@ -209,7 +209,7 @@ module T::Private::Methods
209
209
  end
210
210
  if decl.checked.equal?(ARG_NOT_PROVIDED)
211
211
  default_checked_level = T::Private::RuntimeLevels.default_checked_level
212
- if default_checked_level == :never && !decl.on_failure.equal?(ARG_NOT_PROVIDED)
212
+ if (default_checked_level == :never || default_checked_level == :compiled) && !decl.on_failure.equal?(ARG_NOT_PROVIDED)
213
213
  raise BuilderError.new("To use .on_failure you must additionally call .checked(:tests) or .checked(:always), otherwise, the .on_failure has no effect.")
214
214
  end
215
215
  decl.checked = default_checked_level
@@ -2,12 +2,24 @@
2
2
  # typed: true
3
3
 
4
4
  module T::Private::Methods::Modes
5
- def self.standard; 'standard'; end
6
- def self.abstract; 'abstract'; end
7
- def self.overridable; 'overridable'; end
8
- def self.override; 'override'; end
9
- def self.overridable_override; 'overridable_override'; end
10
- def self.untyped; 'untyped'; end
5
+ def self.standard
6
+ 'standard'
7
+ end
8
+ def self.abstract
9
+ 'abstract'
10
+ end
11
+ def self.overridable
12
+ 'overridable'
13
+ end
14
+ def self.override
15
+ 'override'
16
+ end
17
+ def self.overridable_override
18
+ 'overridable_override'
19
+ end
20
+ def self.untyped
21
+ 'untyped'
22
+ end
11
23
  MODES = [self.standard, self.abstract, self.overridable, self.override, self.overridable_override, self.untyped].freeze
12
24
 
13
25
  OVERRIDABLE_MODES = [self.override, self.overridable, self.overridable_override, self.untyped, self.abstract].freeze
@@ -154,7 +154,6 @@ module T::Private::Methods::SignatureValidation
154
154
  "#{base_override_loc_str(signature, super_signature)}"
155
155
  end
156
156
 
157
-
158
157
  # O(nm), but n and m are tiny here
159
158
  extra_req_kwargs = signature.req_kwarg_names - super_signature.req_kwarg_names
160
159
  if !extra_req_kwargs.empty?
@@ -174,7 +173,7 @@ module T::Private::Methods::SignatureValidation
174
173
  return if signature.override_allow_incompatible
175
174
  return if super_signature.mode == Modes.untyped
176
175
  return unless [signature, super_signature].all? do |sig|
177
- sig.check_level == :always || (sig.check_level == :tests && T::Private::RuntimeLevels.check_tests?)
176
+ sig.check_level == :always || sig.check_level == :compiled || (sig.check_level == :tests && T::Private::RuntimeLevels.check_tests?)
178
177
  end
179
178
  mode_noun = super_signature.mode == Modes.abstract ? 'implementation' : 'override'
180
179
 
@@ -12,6 +12,9 @@ module T::Private::RuntimeLevels
12
12
  # Don't even validate in tests, b/c too expensive,
13
13
  # or b/c we fully trust the static typing
14
14
  :never,
15
+ # Validate the sig when the file is using the Sorbet Compiler.
16
+ # Behaves like :never when interpreted.
17
+ :compiled,
15
18
  ].freeze
16
19
 
17
20
  @check_tests = false
@@ -31,8 +34,11 @@ module T::Private::RuntimeLevels
31
34
 
32
35
  def self.enable_checking_in_tests
33
36
  if !@check_tests && @wrapped_tests_with_validation
37
+ all_checked_tests_sigs = T::Private::Methods.all_checked_tests_sigs
38
+ locations = all_checked_tests_sigs.map {|sig| sig.method.source_location.join(':')}.join("\n- ")
34
39
  raise "Toggle `:tests`-level runtime type checking earlier. " \
35
- "There are already some methods wrapped with `sig.checked(:tests)`." \
40
+ "There are already some methods wrapped with `sig.checked(:tests)`:\n" \
41
+ "- #{locations}"
36
42
  end
37
43
 
38
44
  _toggle_checking_tests(true)
@@ -20,13 +20,23 @@ module T::Props
20
20
  extend T::Sig
21
21
  extend T::Helpers
22
22
 
23
- def props; decorator.props; end
24
- def plugins; @plugins ||= []; end
23
+ def props
24
+ decorator.props
25
+ end
26
+ def plugins
27
+ @plugins ||= []
28
+ end
25
29
 
26
- def decorator_class; Decorator; end
30
+ def decorator_class
31
+ Decorator
32
+ end
27
33
 
28
- def decorator; @decorator ||= decorator_class.new(self); end
29
- def reload_decorator!; @decorator = decorator_class.new(self); end
34
+ def decorator
35
+ @decorator ||= decorator_class.new(self)
36
+ end
37
+ def reload_decorator!
38
+ @decorator = decorator_class.new(self)
39
+ end
30
40
 
31
41
  # @!method self.prop(name, type, opts={})
32
42
  #
@@ -34,11 +34,15 @@ class T::Props::Decorator
34
34
  attr_reader :props
35
35
 
36
36
  sig {returns(T::Array[Symbol])}
37
- def all_props; props.keys; end
37
+ def all_props
38
+ props.keys
39
+ end
38
40
 
39
41
  # checked(:never) - O(prop accesses)
40
42
  sig {params(prop: T.any(Symbol, String)).returns(Rules).checked(:never)}
41
- def prop_rules(prop); props[prop.to_sym] || raise("No such prop: #{prop.inspect}"); end
43
+ def prop_rules(prop)
44
+ props[prop.to_sym] || raise("No such prop: #{prop.inspect}")
45
+ end
42
46
 
43
47
  # checked(:never) - Rules hash is expensive to check
44
48
  sig {params(prop: Symbol, rules: Rules).void.checked(:never)}
@@ -78,7 +82,9 @@ class T::Props::Decorator
78
82
 
79
83
  # checked(:never) - O(prop accesses)
80
84
  sig {returns(T.all(Module, T::Props::ClassMethods)).checked(:never)}
81
- def decorated_class; @class; end
85
+ def decorated_class
86
+ @class
87
+ end
82
88
 
83
89
  # Accessors
84
90
 
@@ -157,7 +157,7 @@ module T::Props
157
157
  validate_lack_of_side_effects(try, whitelisted_methods_for_deserialize)
158
158
 
159
159
  assert_equal(:resbody, rescue_body.type)
160
- exceptions, assignment, handler = rescue_body.children
160
+ exceptions, assignment, handler = rescue_body.children
161
161
  assert_equal(:array, exceptions.type)
162
162
  exceptions.children.each {|c| assert_equal(:const, c.type)}
163
163
  assert_equal(:lvasgn, assignment.type)
@@ -5,10 +5,8 @@ module T::Props::Optional
5
5
  include T::Props::Plugin
6
6
  end
7
7
 
8
-
9
8
  ##############################################
10
9
 
11
-
12
10
  # NB: This must stay in the same file where T::Props::Optional is defined due to
13
11
  # T::Props::Decorator#apply_plugin; see https://git.corp.stripe.com/stripe-internal/pay-server/blob/fc7f15593b49875f2d0499ffecfd19798bac05b3/chalk/odm/lib/chalk-odm/document_decorator.rb#L716-L717
14
12
  module T::Props::Optional::DecoratorMethods
@@ -27,7 +25,9 @@ module T::Props::Optional::DecoratorMethods
27
25
  super || VALID_RULE_KEYS[key]
28
26
  end
29
27
 
30
- def prop_optional?(prop); prop_rules(prop)[:fully_optional]; end
28
+ def prop_optional?(prop)
29
+ prop_rules(prop)[:fully_optional]
30
+ end
31
31
 
32
32
  def compute_derived_rules(rules)
33
33
  rules[:fully_optional] = !T::Props::Utils.need_nil_write_check?(rules)
@@ -74,4 +74,3 @@ module T::Props
74
74
  end
75
75
  end
76
76
  end
77
-
@@ -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) # rubocop:disable Style/OptionalBooleanParameter (changing this API is unfortunately not feasible)
18
+ def serialize(strict=true)
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) # rubocop:disable Style/OptionalBooleanParameter (changing this API is unfortunately not feasible)
59
+ def deserialize(hash, strict=false)
60
60
  begin
61
61
  hash_keys_matching_props = __t_props_generated_deserialize(hash)
62
62
  rescue => e
@@ -171,7 +171,6 @@ module T::Props::Serializable
171
171
  end
172
172
  end
173
173
 
174
-
175
174
  ##############################################
176
175
 
177
176
  # NB: This must stay in the same file where T::Props::Serializable is defined due to
@@ -190,10 +189,14 @@ module T::Props::Serializable::DecoratorMethods
190
189
  @class.props.select {|_, v| T::Props::Utils.required_prop?(v)}.keys
191
190
  end
192
191
 
193
- def prop_dont_store?(prop); prop_rules(prop)[:dont_store]; end
194
- def prop_by_serialized_forms; @class.prop_by_serialized_forms; end
192
+ def prop_dont_store?(prop)
193
+ prop_rules(prop)[:dont_store]
194
+ end
195
+ def prop_by_serialized_forms
196
+ @class.prop_by_serialized_forms
197
+ end
195
198
 
196
- def from_hash(hash, strict=false) # rubocop:disable Style/OptionalBooleanParameter (changing this API is unfortunately not feasible)
199
+ def from_hash(hash, strict=false)
197
200
  raise ArgumentError.new("#{hash.inspect} provided to from_hash") if !(hash && hash.is_a?(Hash))
198
201
 
199
202
  i = @class.allocate
@@ -260,7 +263,7 @@ module T::Props::Serializable::DecoratorMethods
260
263
  context = " #{source_lines[(previous_blank + 1)...next_blank].join("\n ")}"
261
264
  <<~MSG
262
265
  Error in #{decorated_class.name}##{generated_method}: #{error.message}
263
- at line #{line_num-previous_blank-1} in:
266
+ at line #{line_num - previous_blank - 1} in:
264
267
  #{context}
265
268
  MSG
266
269
  end
@@ -300,7 +303,7 @@ module T::Props::Serializable::DecoratorMethods
300
303
  end
301
304
 
302
305
  if !rules[:raise_on_nil_write].nil? && rules[:raise_on_nil_write] != true
303
- raise ArgumentError.new("The value of `raise_on_nil_write` if specified must be `true` (given: #{rules[:raise_on_nil_write]}).")
306
+ raise ArgumentError.new("The value of `raise_on_nil_write` if specified must be `true` (given: #{rules[:raise_on_nil_write]}).")
304
307
  end
305
308
 
306
309
  result
@@ -334,21 +337,21 @@ module T::Props::Serializable::DecoratorMethods
334
337
  end
335
338
  end
336
339
 
337
-
338
340
  ##############################################
339
341
 
340
-
341
342
  # NB: This must stay in the same file where T::Props::Serializable is defined due to
342
343
  # T::Props::Decorator#apply_plugin; see https://git.corp.stripe.com/stripe-internal/pay-server/blob/fc7f15593b49875f2d0499ffecfd19798bac05b3/chalk/odm/lib/chalk-odm/document_decorator.rb#L716-L717
343
344
  module T::Props::Serializable::ClassMethods
344
- def prop_by_serialized_forms; @prop_by_serialized_forms ||= {}; end
345
+ def prop_by_serialized_forms
346
+ @prop_by_serialized_forms ||= {}
347
+ end
345
348
 
346
349
  # @!method self.from_hash(hash, strict)
347
350
  #
348
351
  # Allocate a new instance and call {#deserialize} to load a new
349
352
  # object from a hash.
350
353
  # @return [Serializable]
351
- def from_hash(hash, strict=false) # rubocop:disable Style/OptionalBooleanParameter (changing this API is unfortunately not feasible)
354
+ def from_hash(hash, strict=false)
352
355
  self.decorator.from_hash(hash, strict)
353
356
  end
354
357
 
@@ -13,15 +13,7 @@ module T::Types
13
13
 
14
14
  # @override Base
15
15
  def name
16
- entries = @types.map do |(k, v)|
17
- if Symbol === k && ":#{k}" == k.inspect
18
- "#{k}: #{v}"
19
- else
20
- "#{k.inspect} => #{v}"
21
- end
22
- end
23
-
24
- "{#{entries.join(', ')}}"
16
+ serialize_hash(@types)
25
17
  end
26
18
 
27
19
  # @override Base
@@ -59,10 +51,24 @@ module T::Types
59
51
  # @override Base
60
52
  def describe_obj(obj)
61
53
  if obj.is_a?(Hash)
62
- "type {#{obj.map {|(k, v)| "#{k}: #{v.class}"}.join(', ')}}"
54
+ "type #{serialize_hash(obj.transform_values(&:class))}"
63
55
  else
64
56
  super
65
57
  end
66
58
  end
59
+
60
+ private
61
+
62
+ def serialize_hash(hash)
63
+ entries = hash.map do |(k, v)|
64
+ if Symbol === k && ":#{k}" == k.inspect
65
+ "#{k}: #{v}"
66
+ else
67
+ "#{k.inspect} => #{v}"
68
+ end
69
+ end
70
+
71
+ "{#{entries.join(', ')}}"
72
+ end
67
73
  end
68
74
  end
@@ -22,9 +22,9 @@ module T::Types
22
22
  private def subtype_of_single?(other)
23
23
  case other
24
24
  when SelfType
25
- true
26
- else
27
- false
25
+ true
26
+ else
27
+ false
28
28
  end
29
29
  end
30
30
 
@@ -40,8 +40,10 @@ module T::Types
40
40
 
41
41
  module Private
42
42
  module Pool
43
+ @cache = ObjectSpace::WeakMap.new
44
+
43
45
  def self.type_for_module(mod)
44
- cached = mod.instance_variable_get(:@__as_sorbet_type)
46
+ cached = @cache[mod]
45
47
  return cached if cached
46
48
 
47
49
  type = if mod == ::Array
@@ -60,7 +62,13 @@ module T::Types
60
62
  Simple.new(mod)
61
63
  end
62
64
 
63
- mod.instance_variable_set(:@__as_sorbet_type, type) unless mod.frozen?
65
+ # Unfortunately, we still need to check if the module is frozen,
66
+ # since WeakMap adds a finalizer to the key that is added
67
+ # to the map, so that it can clear the map entry when the key is
68
+ # garbage collected.
69
+ # For a frozen object, though, adding a finalizer is not a valid
70
+ # operation, so this still raises if `mod` is frozen.
71
+ @cache[mod] = type unless mod.frozen?
64
72
  type
65
73
  end
66
74
  end
data/lib/types/utils.rb CHANGED
@@ -27,6 +27,14 @@ module T::Utils
27
27
  end
28
28
  end
29
29
 
30
+ # Dynamically confirm that `value` is recursively a valid value of
31
+ # type `type`, including recursively through collections. Note that
32
+ # in some cases this runtime check can be very expensive, especially
33
+ # with large collections of objects.
34
+ def self.check_type_recursive!(value, type)
35
+ T::Private::Casts.cast_recursive(value, type, cast_method: "T.check_type_recursive!")
36
+ end
37
+
30
38
  # Returns the set of all methods (public, protected, private) defined on a module or its
31
39
  # ancestors, excluding Object and its ancestors. Overrides of methods from Object (and its
32
40
  # ancestors) are included.
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.8993
4
+ version: 0.5.9103
5
5
  platform: ruby
6
6
  authors:
7
7
  - Stripe
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-07-31 00:00:00.000000000 Z
11
+ date: 2021-09-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: minitest
@@ -173,6 +173,7 @@ files:
173
173
  - lib/types/private/abstract/validate.rb
174
174
  - lib/types/private/casts.rb
175
175
  - lib/types/private/class_utils.rb
176
+ - lib/types/private/compiler.rb
176
177
  - lib/types/private/decl_state.rb
177
178
  - lib/types/private/final.rb
178
179
  - lib/types/private/methods/_methods.rb