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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4838c21772de1169f412a971cfe59e49fc482bda8de9fb70920fd4bcab5e654f
4
- data.tar.gz: 5e27052a663a22e70e5aa3afee7563f43be650946ec4673df2fb246535a28bb6
3
+ metadata.gz: b9ad14907c264d6ca3dae954f1bf9cdfdff0544411fad7a390fcb424465bf828
4
+ data.tar.gz: f02410f71f442e62a635881ec386a23911f1cb1a4d4c5eae77693d1a10a0695d
5
5
  SHA512:
6
- metadata.gz: 87abc9d8a3a9a753d96577a52856c4e04b2dfaaefb1908e696d9882c04a593ab6cdd9112660afa887d57fd3df62dbf99fded5a697b176ac1c043011b3fd43db1
7
- data.tar.gz: 6f10e93404924fbf7752eb01786e717d585472df7b2c77aaead247df1d170998ff46b8d3d8e5b51bad6773fc950280ebc3c922651078a249fef2d29929d75aef
6
+ metadata.gz: 1bb53ba112fb1793b4e138e1a65ed648e2e202af6e8ec79be17b444c11c02a63a7c385b0abb474e38dca78a03ad91f02149ff24b7c5f622f7d1943c4d4c846b1
7
+ data.tar.gz: bf301214903ea532fb931314c823f68a3017a2de5868f32d074a642664c4cf266864201d9ae4a62573a9713bb888d132cb0aadd23c77aaf628b8d443163bae36
@@ -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.
@@ -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.select {|v| v.class != String}
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
- }).freeze
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 @sealed_violation_whitelist != nil
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
- private def initialize(serialized_val=nil)
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
- # Sorbet guarantees that the string is an absolutely resolved name.
41
- search_inheritance_chain = false
42
- if !current_klass.const_defined?(part, search_inheritance_chain)
43
- return false
44
- end
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
- current_klass = current_klass.const_get(part)
47
- current_prefix = "#{current_prefix}::#{part}"
51
+ current_klass = current_klass.const_get(part)
52
+ current_prefix = "#{current_prefix}::#{part}"
48
53
 
49
- if !Module.===(current_klass)
50
- raise ArgumentError.new("#{current_prefix} is not a class or module")
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
- return current_klass.===(val)
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
- loc = method.source_location.join(':')
114
+ loc = if method.source_location
115
+ method.source_location.join(':')
116
116
  else
117
- loc = "<unknown location>"
117
+ "<unknown location>"
118
118
  end
119
119
 
120
- if show_owner
121
- owner = " declared in #{method.owner}"
120
+ owner = if show_owner
121
+ " declared in #{method.owner}"
122
122
  else
123
- owner = ""
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) && final_method?(method_owner_and_name_to_key(ancestor, 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
- # inside `class << self`, and
317
- hook_mod.singleton_class != current_declaration.mod &&
318
- # on `self` at the top level of a file
319
- current_declaration.mod != TOP_SELF
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, _ = @sig_wrappers.first
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 = @old_hooks != nil
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.length == 0
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.length == 0
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, on_failure:, override_allow_incompatible: false)
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
- loc = @method.source_location.join(':')
201
+ loc = if @method.source_location
202
+ @method.source_location.join(':')
199
203
  else
200
- loc = "<unknown location>"
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
- # Given a singleton class, we can check if it belongs to a
107
- # module by looking at its superclass; given `module M`,
108
- # `M.singleton_class.superclass == Module`, which is not true
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
- loc = method.source_location.join(':')
219
+ loc = if method.source_location
220
+ method.source_location.join(':')
224
221
  else
225
- loc = "<unknown location>"
222
+ "<unknown location>"
226
223
  end
227
224
  "#{method.owner} at #{loc}"
228
225
  end
@@ -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 != nil && whitelist.any? {|pattern| this_file =~ pattern}
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
- }.map {|k| [k, true]}.to_h.freeze, T::Hash[Symbol, T::Boolean])
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
- if (d = rules[:ifunset])
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 !(rules[:clobber_existing_method!]) && !(rules[:without_accessors])
223
- if BANNED_METHOD_NAMES.include?(name.to_sym)
224
- raise ArgumentError.new(
225
- "#{name} can't be used as a prop in #{@class} because a method with " \
226
- "that name already exists (defined by #{@class.instance_method(name).owner} " \
227
- "at #{@class.instance_method(name).source_location || '<unknown>'}). " \
228
- "(If using this name is unavoidable, try `without_accessors: true`.)"
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
- end
316
- # We check for Class so this is only applied on concrete
317
- # documents/models; We allow mixins containing props to not
318
- # specify their PII nature, as long as every class into which they
319
- # are ultimately included does.
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) && !(prop_cls.is_a?(T::Props::CustomType))
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
- opts = {}
544
+ opts = if allow_direct_mutation.nil?
545
+ {}
551
546
  else
552
- opts = {allow_direct_mutation: allow_direct_mutation}
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.decorator.method(:prop_get).owner != method(:prop_get).owner &&
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
- unless rules[:immutable]
655
- if child.decorator.method(:prop_set).owner != method(:prop_set).owner &&
656
- child.instance_method("#{name}=").source_location&.first == __FILE__
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 % 2 == 0
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
- :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},
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
- :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},
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
@@ -84,7 +84,7 @@ module T::Props
84
84
 
85
85
  cls = decorated_class
86
86
  cls.class_eval(source)
87
- lazily_defined_methods.keys.each {|name| cls.send(:private, name)}
87
+ lazily_defined_methods.each_key {|name| cls.send(:private, name)}
88
88
  lazily_defined_methods.clear
89
89
  end
90
90
  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
- transformed_val = <<~RUBY
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
- transformed_val = 'val'
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
- else
102
+ elsif type.types.all? {|t| generate(t, mode, varname).nil?}
103
103
  # Handle, e.g., T::Boolean
104
- if type.types.all? {|t| generate(t, mode, varname).nil?}
105
- nil
106
- else
107
- # We currently deep_clone_object if the type was T.any(Integer, Float).
108
- # When we get better support for union types (maybe this specific
109
- # union type, because it would be a replacement for
110
- # Chalk::ODM::DeprecatedNumemric), we could opt to special case
111
- # this union to have no specific serde transform (the only reason
112
- # why Float has a special case is because round tripping through
113
- # JSON might normalize Floats to Integers)
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
- MODULE_NAME.bind(type).call
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
- if validate
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
- if validate
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 = " " + source_lines[(previous_blank + 1)...(next_blank)].join("\n ")
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 || :DEPRECATED_underspecified_type == key
16
+ super || key == :DEPRECATED_underspecified_type
17
17
  end
18
18
 
19
19
  sig do
@@ -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
- else
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"
@@ -8,7 +8,7 @@ module T::Types
8
8
  attr_reader :types
9
9
 
10
10
  def initialize(types)
11
- @types = types.each_with_object({}) {|(k, v), h| h[k] = T::Utils.coerce(v)}
11
+ @types = types.transform_values {|v| T::Utils.coerce(v)}
12
12
  end
13
13
 
14
14
  # @override Base
@@ -7,7 +7,7 @@ module T::Types
7
7
  class TypeVariable < Base
8
8
  attr_reader :variance
9
9
 
10
- VALID_VARIANCES = [:in, :out, :invariant]
10
+ VALID_VARIANCES = %i[in out invariant].freeze
11
11
 
12
12
  def initialize(variance)
13
13
  if !VALID_VARIANCES.include?(variance)
@@ -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
- return true
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
- return true
53
+ true
54
54
  when Enumerator
55
55
  # Enumerators can be unbounded: see `[:foo, :bar].cycle`
56
- return true
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
- return true
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 && non_nilable_type.is_a?(T::Types::Simple)
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.5942
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: 2020-10-09 00:00:00.000000000 Z
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