sorbet-runtime 0.5.11144 → 0.5.11663

Sign up to get free protection for your applications and to get access to all the features.
Files changed (60) hide show
  1. checksums.yaml +4 -4
  2. data/lib/sorbet-runtime.rb +1 -4
  3. data/lib/types/compatibility_patches.rb +1 -1
  4. data/lib/types/configuration.rb +3 -2
  5. data/lib/types/enum.rb +63 -39
  6. data/lib/types/non_forcing_constants.rb +4 -14
  7. data/lib/types/private/abstract/declare.rb +4 -5
  8. data/lib/types/private/caller_utils.rb +27 -0
  9. data/lib/types/private/class_utils.rb +1 -1
  10. data/lib/types/private/methods/_methods.rb +35 -30
  11. data/lib/types/private/methods/call_validation.rb +48 -16
  12. data/lib/types/private/methods/call_validation_2_6.rb +518 -0
  13. data/lib/types/private/methods/call_validation_2_7.rb +518 -0
  14. data/lib/types/private/methods/decl_builder.rb +4 -4
  15. data/lib/types/private/methods/signature.rb +10 -2
  16. data/lib/types/private/methods/signature_validation.rb +13 -7
  17. data/lib/types/private/runtime_levels.rb +0 -3
  18. data/lib/types/private/sealed.rb +8 -8
  19. data/lib/types/private/types/not_typed.rb +4 -0
  20. data/lib/types/private/types/string_holder.rb +4 -0
  21. data/lib/types/private/types/type_alias.rb +4 -0
  22. data/lib/types/private/types/void.rb +4 -0
  23. data/lib/types/props/_props.rb +3 -3
  24. data/lib/types/props/decorator.rb +9 -8
  25. data/lib/types/props/has_lazily_specialized_methods.rb +5 -1
  26. data/lib/types/props/pretty_printable.rb +7 -7
  27. data/lib/types/props/private/deserializer_generator.rb +4 -1
  28. data/lib/types/props/private/setter_factory.rb +129 -69
  29. data/lib/types/props/serializable.rb +24 -3
  30. data/lib/types/struct.rb +1 -1
  31. data/lib/types/types/anything.rb +4 -0
  32. data/lib/types/types/attached_class.rb +4 -0
  33. data/lib/types/types/base.rb +8 -2
  34. data/lib/types/types/class_of.rb +6 -2
  35. data/lib/types/types/enum.rb +5 -1
  36. data/lib/types/types/fixed_array.rb +19 -12
  37. data/lib/types/types/fixed_hash.rb +16 -9
  38. data/lib/types/types/intersection.rb +13 -6
  39. data/lib/types/types/noreturn.rb +4 -0
  40. data/lib/types/types/proc.rb +19 -9
  41. data/lib/types/types/self_type.rb +4 -0
  42. data/lib/types/types/simple.rb +9 -0
  43. data/lib/types/types/t_enum.rb +4 -0
  44. data/lib/types/types/type_parameter.rb +4 -0
  45. data/lib/types/types/type_variable.rb +4 -0
  46. data/lib/types/types/typed_array.rb +7 -2
  47. data/lib/types/types/typed_class.rb +22 -5
  48. data/lib/types/types/typed_enumerable.rb +22 -16
  49. data/lib/types/types/typed_enumerator.rb +2 -4
  50. data/lib/types/types/typed_enumerator_chain.rb +2 -4
  51. data/lib/types/types/typed_enumerator_lazy.rb +2 -4
  52. data/lib/types/types/typed_hash.rb +17 -7
  53. data/lib/types/types/typed_range.rb +2 -4
  54. data/lib/types/types/typed_set.rb +3 -5
  55. data/lib/types/types/union.rb +12 -5
  56. data/lib/types/types/untyped.rb +4 -0
  57. data/lib/types/utils.rb +7 -5
  58. metadata +23 -24
  59. data/lib/types/interface_wrapper.rb +0 -162
  60. data/lib/types/private/compiler.rb +0 -24
@@ -6,6 +6,10 @@
6
6
  class T::Private::Types::NotTyped < T::Types::Base
7
7
  ERROR_MESSAGE = "Validation is being done on a `NotTyped`. Please report this bug at https://github.com/sorbet/sorbet/issues"
8
8
 
9
+ def build_type
10
+ nil
11
+ end
12
+
9
13
  # overrides Base
10
14
  def name
11
15
  "<NOT-TYPED>"
@@ -9,6 +9,10 @@ class T::Private::Types::StringHolder < T::Types::Base
9
9
  @string = string
10
10
  end
11
11
 
12
+ def build_type
13
+ nil
14
+ end
15
+
12
16
  # overrides Base
13
17
  def name
14
18
  string
@@ -9,6 +9,10 @@ module T::Private::Types
9
9
  @callable = callable
10
10
  end
11
11
 
12
+ def build_type
13
+ nil
14
+ end
15
+
12
16
  def aliased_type
13
17
  @aliased_type ||= T::Utils.coerce(@callable.call)
14
18
  end
@@ -18,6 +18,10 @@ module T::Private::Types
18
18
  freeze
19
19
  end
20
20
 
21
+ def build_type
22
+ nil
23
+ end
24
+
21
25
  # overrides Base
22
26
  def name
23
27
  "<VOID>"
@@ -110,7 +110,7 @@ module T::Props
110
110
  #
111
111
  # @return [void]
112
112
  sig {params(name: Symbol, cls: T.untyped, rules: T.untyped).void}
113
- def prop(name, cls, rules={})
113
+ def prop(name, cls, **rules)
114
114
  cls = T::Utils.coerce(cls) if !cls.is_a?(Module)
115
115
  decorator.prop_defined(name, cls, rules)
116
116
  end
@@ -132,8 +132,8 @@ module T::Props
132
132
  end
133
133
 
134
134
  # Shorthand helper to define a `prop` with `immutable => true`
135
- sig {params(name: Symbol, cls_or_args: T.untyped, args: T::Hash[Symbol, T.untyped]).void}
136
- def const(name, cls_or_args, args={})
135
+ sig {params(name: Symbol, cls_or_args: T.untyped, args: T.untyped).void}
136
+ def const(name, cls_or_args, **args)
137
137
  if (cls_or_args.is_a?(Hash) && cls_or_args.key?(:immutable)) || args.key?(:immutable)
138
138
  Kernel.raise ArgumentError.new("Cannot pass 'immutable' argument when using 'const' keyword to define a prop")
139
139
  end
@@ -100,10 +100,7 @@ class T::Props::Decorator
100
100
  # checked(:never) - potentially O(prop accesses) depending on usage pattern
101
101
  sig {params(prop: Symbol, val: T.untyped).void.checked(:never)}
102
102
  def validate_prop_value(prop, val)
103
- # We call `setter_proc` here without binding to an instance, so it'll run
104
- # `instance_variable_set` if validation passes, but nothing will care.
105
- # We only care about the validation.
106
- prop_rules(prop).fetch(:setter_proc).call(val)
103
+ prop_rules(prop).fetch(:value_validate_proc).call(val)
107
104
  end
108
105
 
109
106
  # For performance, don't use named params here.
@@ -296,7 +293,7 @@ class T::Props::Decorator
296
293
  cls: PropTypeOrClass,
297
294
  rules: Rules,
298
295
  )
299
- .void
296
+ .returns(T.anything)
300
297
  .checked(:never)
301
298
  end
302
299
  private def prop_nilable?(cls, rules)
@@ -335,7 +332,7 @@ class T::Props::Decorator
335
332
 
336
333
  prop_validate_definition!(name, cls, rules, type_object)
337
334
 
338
- # Retrive the possible underlying object with T.nilable.
335
+ # Retrieve the possible underlying object with T.nilable.
339
336
  type = T::Utils::Nilable.get_underlying_type(type)
340
337
 
341
338
  rules_sensitivity = rules[:sensitivity]
@@ -378,7 +375,11 @@ class T::Props::Decorator
378
375
  end
379
376
  end
380
377
 
381
- rules[:setter_proc] = T::Props::Private::SetterFactory.build_setter_proc(@class, name, rules).freeze
378
+ setter_proc, value_validate_proc = T::Props::Private::SetterFactory.build_setter_proc(@class, name, rules)
379
+ setter_proc.freeze
380
+ value_validate_proc.freeze
381
+ rules[:setter_proc] = setter_proc
382
+ rules[:value_validate_proc] = value_validate_proc
382
383
 
383
384
  add_prop_definition(name, rules)
384
385
 
@@ -429,7 +430,7 @@ class T::Props::Decorator
429
430
  else
430
431
  nonnil_type = T::Utils.unwrap_nilable(type)
431
432
  if nonnil_type
432
- T.unsafe(T.nilable(T.all(nonnil_type, T.deprecated_enum(enum))))
433
+ T.unsafe(T.nilable(T.all(T.unsafe(nonnil_type), T.deprecated_enum(enum))))
433
434
  else
434
435
  T.unsafe(T.all(T.unsafe(type), T.deprecated_enum(enum)))
435
436
  end
@@ -62,7 +62,9 @@ module T::Props
62
62
  source = lazily_defined_methods.fetch(name).call
63
63
 
64
64
  cls = decorated_class
65
- cls.class_eval(source.to_s)
65
+ T::Configuration.without_ruby_warnings do
66
+ cls.class_eval(source.to_s)
67
+ end
66
68
  cls.send(:private, name)
67
69
  end
68
70
 
@@ -117,7 +119,9 @@ module T::Props
117
119
  def eagerly_define_lazy_methods!
118
120
  return if lazily_defined_methods.empty?
119
121
 
122
+ # rubocop:disable Style/StringConcatenation
120
123
  source = "# frozen_string_literal: true\n" + lazily_defined_methods.values.map(&:call).map(&:to_s).join("\n\n")
124
+ # rubocop:enable Style/StringConcatenation
121
125
 
122
126
  cls = decorated_class
123
127
  cls.class_eval(source)
@@ -7,13 +7,13 @@ module T::Props::PrettyPrintable
7
7
 
8
8
  # Override the PP gem with something that's similar, but gives us a hook to do redaction and customization
9
9
  def pretty_print(pp)
10
- clazz = T.unsafe(T.cast(self, Object).class).decorator
10
+ klass = T.unsafe(T.cast(self, Object).class).decorator
11
11
  multiline = pp.is_a?(PP)
12
- pp.group(1, "<#{clazz.inspect_class_with_decoration(self)}", ">") do
13
- clazz.all_props.sort.each do |prop|
12
+ pp.group(1, "<#{klass.inspect_class_with_decoration(self)}", ">") do
13
+ klass.all_props.sort.each do |prop|
14
14
  pp.breakable
15
- val = clazz.get(self, prop)
16
- rules = clazz.prop_rules(prop)
15
+ val = klass.get(self, prop)
16
+ rules = klass.prop_rules(prop)
17
17
  pp.text("#{prop}=")
18
18
  if (custom_inspect = rules[:inspect])
19
19
  inspected = if T::Utils.arity(custom_inspect) == 1
@@ -28,7 +28,7 @@ module T::Props::PrettyPrintable
28
28
  val.pretty_print(pp)
29
29
  end
30
30
  end
31
- clazz.pretty_print_extra(self, pp)
31
+ klass.pretty_print_extra(self, pp)
32
32
  end
33
33
  end
34
34
 
@@ -55,7 +55,7 @@ module T::Props::PrettyPrintable
55
55
  end
56
56
 
57
57
  # Overridable method to specify how the first part of a `pretty_print`d object's class should look like
58
- # NOTE: This is just to support Stripe's `PrettyPrintableModel` case, and not recommended to be overriden
58
+ # NOTE: This is just to support Stripe's `PrettyPrintableModel` case, and not recommended to be overridden
59
59
  sig {params(instance: T::Props::PrettyPrintable).returns(String)}
60
60
  def inspect_class_with_decoration(instance)
61
61
  T.unsafe(instance).class.to_s
@@ -137,7 +137,10 @@ module T::Props
137
137
  when ApplyPrimitiveDefault
138
138
  literal = default.default
139
139
  case literal
140
- when String, Integer, Symbol, Float, TrueClass, FalseClass, NilClass
140
+ # `Float` is intentionally left out here because `.inspect` does not produce the correct code
141
+ # representation for non-finite values like `Float::INFINITY` and `Float::NAN` and it's not totally
142
+ # clear that it won't cause issues with floating point precision.
143
+ when String, Integer, Symbol, TrueClass, FalseClass, NilClass
141
144
  literal.inspect
142
145
  else
143
146
  "self.class.decorator.props_with_defaults.fetch(#{prop.inspect}).default"
@@ -7,6 +7,7 @@ module T::Props
7
7
  extend T::Sig
8
8
 
9
9
  SetterProc = T.type_alias {T.proc.params(val: T.untyped).void}
10
+ ValueValidationProc = T.type_alias {T.proc.params(val: T.untyped).void}
10
11
  ValidateProc = T.type_alias {T.proc.params(prop: Symbol, value: T.untyped).void}
11
12
 
12
13
  sig do
@@ -15,7 +16,7 @@ module T::Props
15
16
  prop: Symbol,
16
17
  rules: T::Hash[Symbol, T.untyped]
17
18
  )
18
- .returns(SetterProc)
19
+ .returns([SetterProc, ValueValidationProc])
19
20
  .checked(:never)
20
21
  end
21
22
  def self.build_setter_proc(klass, prop, rules)
@@ -55,20 +56,32 @@ module T::Props
55
56
  non_nil_type: Module,
56
57
  klass: T.all(Module, T::Props::ClassMethods),
57
58
  )
58
- .returns(SetterProc)
59
+ .returns([SetterProc, ValueValidationProc])
59
60
  end
60
61
  private_class_method def self.simple_non_nil_proc(prop, accessor_key, non_nil_type, klass)
61
- proc do |val|
62
- unless val.is_a?(non_nil_type)
63
- T::Props::Private::SetterFactory.raise_pretty_error(
64
- klass,
65
- prop,
66
- T::Utils.coerce(non_nil_type),
67
- val,
68
- )
69
- end
70
- instance_variable_set(accessor_key, val)
71
- end
62
+ [
63
+ proc do |val|
64
+ unless val.is_a?(non_nil_type)
65
+ T::Props::Private::SetterFactory.raise_pretty_error(
66
+ klass,
67
+ prop,
68
+ T::Utils.coerce(non_nil_type),
69
+ val,
70
+ )
71
+ end
72
+ instance_variable_set(accessor_key, val)
73
+ end,
74
+ proc do |val|
75
+ unless val.is_a?(non_nil_type)
76
+ T::Props::Private::SetterFactory.raise_pretty_error(
77
+ klass,
78
+ prop,
79
+ T::Utils.coerce(non_nil_type),
80
+ val,
81
+ )
82
+ end
83
+ end,
84
+ ]
72
85
  end
73
86
 
74
87
  sig do
@@ -79,27 +92,46 @@ module T::Props
79
92
  klass: T.all(Module, T::Props::ClassMethods),
80
93
  validate: T.nilable(ValidateProc)
81
94
  )
82
- .returns(SetterProc)
95
+ .returns([SetterProc, ValueValidationProc])
83
96
  end
84
97
  private_class_method def self.non_nil_proc(prop, accessor_key, non_nil_type, klass, validate)
85
- proc do |val|
86
- # this use of recursively_valid? is intentional: unlike for
87
- # methods, we want to make sure data at the 'edge'
88
- # (e.g. models that go into databases or structs serialized
89
- # from disk) are correct, so we use more thorough runtime
90
- # checks there
91
- if non_nil_type.recursively_valid?(val)
92
- validate&.call(prop, val)
93
- else
94
- T::Props::Private::SetterFactory.raise_pretty_error(
95
- klass,
96
- prop,
97
- non_nil_type,
98
- val,
99
- )
100
- end
101
- instance_variable_set(accessor_key, val)
102
- end
98
+ [
99
+ proc do |val|
100
+ # this use of recursively_valid? is intentional: unlike for
101
+ # methods, we want to make sure data at the 'edge'
102
+ # (e.g. models that go into databases or structs serialized
103
+ # from disk) are correct, so we use more thorough runtime
104
+ # checks there
105
+ if non_nil_type.recursively_valid?(val)
106
+ validate&.call(prop, val)
107
+ else
108
+ T::Props::Private::SetterFactory.raise_pretty_error(
109
+ klass,
110
+ prop,
111
+ non_nil_type,
112
+ val,
113
+ )
114
+ end
115
+ instance_variable_set(accessor_key, val)
116
+ end,
117
+ proc do |val|
118
+ # this use of recursively_valid? is intentional: unlike for
119
+ # methods, we want to make sure data at the 'edge'
120
+ # (e.g. models that go into databases or structs serialized
121
+ # from disk) are correct, so we use more thorough runtime
122
+ # checks there
123
+ if non_nil_type.recursively_valid?(val)
124
+ validate&.call(prop, val)
125
+ else
126
+ T::Props::Private::SetterFactory.raise_pretty_error(
127
+ klass,
128
+ prop,
129
+ non_nil_type,
130
+ val,
131
+ )
132
+ end
133
+ end,
134
+ ]
103
135
  end
104
136
 
105
137
  sig do
@@ -109,24 +141,32 @@ module T::Props
109
141
  non_nil_type: Module,
110
142
  klass: T.all(Module, T::Props::ClassMethods),
111
143
  )
112
- .returns(SetterProc)
144
+ .returns([SetterProc, ValueValidationProc])
113
145
  end
114
146
  private_class_method def self.simple_nilable_proc(prop, accessor_key, non_nil_type, klass)
115
- proc do |val|
116
- if val.nil?
117
- instance_variable_set(accessor_key, nil)
118
- elsif val.is_a?(non_nil_type)
119
- instance_variable_set(accessor_key, val)
120
- else
121
- T::Props::Private::SetterFactory.raise_pretty_error(
122
- klass,
123
- prop,
124
- T::Utils.coerce(non_nil_type),
125
- val,
126
- )
147
+ [
148
+ proc do |val|
149
+ unless val.nil? || val.is_a?(non_nil_type)
150
+ T::Props::Private::SetterFactory.raise_pretty_error(
151
+ klass,
152
+ prop,
153
+ T::Utils.coerce(non_nil_type),
154
+ val,
155
+ )
156
+ end
127
157
  instance_variable_set(accessor_key, val)
128
- end
129
- end
158
+ end,
159
+ proc do |val|
160
+ unless val.nil? || val.is_a?(non_nil_type)
161
+ T::Props::Private::SetterFactory.raise_pretty_error(
162
+ klass,
163
+ prop,
164
+ T::Utils.coerce(non_nil_type),
165
+ val,
166
+ )
167
+ end
168
+ end,
169
+ ]
130
170
  end
131
171
 
132
172
  sig do
@@ -137,30 +177,50 @@ module T::Props
137
177
  klass: T.all(Module, T::Props::ClassMethods),
138
178
  validate: T.nilable(ValidateProc),
139
179
  )
140
- .returns(SetterProc)
180
+ .returns([SetterProc, ValueValidationProc])
141
181
  end
142
182
  private_class_method def self.nilable_proc(prop, accessor_key, non_nil_type, klass, validate)
143
- proc do |val|
144
- if val.nil?
145
- instance_variable_set(accessor_key, nil)
146
- # this use of recursively_valid? is intentional: unlike for
147
- # methods, we want to make sure data at the 'edge'
148
- # (e.g. models that go into databases or structs serialized
149
- # from disk) are correct, so we use more thorough runtime
150
- # checks there
151
- elsif non_nil_type.recursively_valid?(val)
152
- validate&.call(prop, val)
153
- instance_variable_set(accessor_key, val)
154
- else
155
- T::Props::Private::SetterFactory.raise_pretty_error(
156
- klass,
157
- prop,
158
- non_nil_type,
159
- val,
160
- )
161
- instance_variable_set(accessor_key, val)
162
- end
163
- end
183
+ [
184
+ proc do |val|
185
+ if val.nil?
186
+ instance_variable_set(accessor_key, nil)
187
+ # this use of recursively_valid? is intentional: unlike for
188
+ # methods, we want to make sure data at the 'edge'
189
+ # (e.g. models that go into databases or structs serialized
190
+ # from disk) are correct, so we use more thorough runtime
191
+ # checks there
192
+ elsif non_nil_type.recursively_valid?(val)
193
+ validate&.call(prop, val)
194
+ instance_variable_set(accessor_key, val)
195
+ else
196
+ T::Props::Private::SetterFactory.raise_pretty_error(
197
+ klass,
198
+ prop,
199
+ non_nil_type,
200
+ val,
201
+ )
202
+ instance_variable_set(accessor_key, val)
203
+ end
204
+ end,
205
+ proc do |val|
206
+ if val.nil?
207
+ # this use of recursively_valid? is intentional: unlike for
208
+ # methods, we want to make sure data at the 'edge'
209
+ # (e.g. models that go into databases or structs serialized
210
+ # from disk) are correct, so we use more thorough runtime
211
+ # checks there
212
+ elsif non_nil_type.recursively_valid?(val)
213
+ validate&.call(prop, val)
214
+ else
215
+ T::Props::Private::SetterFactory.raise_pretty_error(
216
+ klass,
217
+ prop,
218
+ non_nil_type,
219
+ val,
220
+ )
221
+ end
222
+ end,
223
+ ]
164
224
  end
165
225
 
166
226
  sig do
@@ -261,10 +261,31 @@ module T::Props::Serializable::DecoratorMethods
261
261
  end
262
262
 
263
263
  def message_with_generated_source_context(error, generated_method, generate_source_method)
264
- line_label = error.backtrace.find {|l| l.end_with?("in `#{generated_method}'")}
265
- return unless line_label
264
+ generated_method = generated_method.to_s
265
+ if error.backtrace_locations
266
+ line_loc = error.backtrace_locations.find {|l| l.base_label == generated_method}
267
+ return unless line_loc
266
268
 
267
- line_num = line_label.split(':')[1]&.to_i
269
+ line_num = line_loc.lineno
270
+ else
271
+ label = if RUBY_VERSION >= "3.4"
272
+ # in 'ClassName#__t_props_generated_serialize'"
273
+ "##{generated_method}'"
274
+ else
275
+ # in `__t_props_generated_serialize'"
276
+ "in `#{generated_method}'"
277
+ end
278
+ line_label = error.backtrace.find {|l| l.end_with?(label)}
279
+ return unless line_label
280
+
281
+ line_num = if line_label.start_with?("(eval)")
282
+ # (eval):13:in ...
283
+ line_label.split(':')[1]&.to_i
284
+ else
285
+ # (eval at /Users/jez/stripe/sorbet/gems/sorbet-runtime/lib/types/props/has_lazily_specialized_methods.rb:65):13:in ...
286
+ line_label.split(':')[2]&.to_i
287
+ end
288
+ end
268
289
  return unless line_num
269
290
 
270
291
  source_lines = self.send(generate_source_method).split("\n")
data/lib/types/struct.rb CHANGED
@@ -39,7 +39,7 @@ class T::ImmutableStruct < T::InexactStruct
39
39
 
40
40
  # Matches the signature in Props, but raises since this is an immutable struct and only const is allowed
41
41
  sig {params(name: Symbol, cls: T.untyped, rules: T.untyped).void}
42
- def self.prop(name, cls, rules={})
42
+ def self.prop(name, cls, **rules)
43
43
  return super if (cls.is_a?(Hash) && cls[:immutable]) || rules[:immutable]
44
44
 
45
45
  raise "Cannot use `prop` in #{self.name} because it is an immutable struct. Use `const` instead"
@@ -6,6 +6,10 @@ module T::Types
6
6
  class Anything < Base
7
7
  def initialize; end
8
8
 
9
+ def build_type
10
+ nil
11
+ end
12
+
9
13
  # overrides Base
10
14
  def name
11
15
  "T.anything"
@@ -10,6 +10,10 @@ module T::Types
10
10
 
11
11
  def initialize(); end
12
12
 
13
+ def build_type
14
+ nil
15
+ end
16
+
13
17
  # overrides Base
14
18
  def name
15
19
  "T.attached_class"
@@ -21,7 +21,7 @@ module T::Types
21
21
  valid?(obj)
22
22
  end
23
23
 
24
- def valid?(obj)
24
+ define_method(:valid?) do |_obj|
25
25
  raise NotImplementedError
26
26
  end
27
27
 
@@ -33,8 +33,14 @@ module T::Types
33
33
  raise NotImplementedError
34
34
  end
35
35
 
36
+ # Force any lazy initialization that this type might need to do
37
+ # It's unusual to call this directly; you probably want to call it indirectly via `T::Utils.run_all_sig_blocks`.
38
+ define_method(:build_type) do
39
+ raise NotImplementedError
40
+ end
41
+
36
42
  # Equality is based on name, so be sure the name reflects all relevant state when implementing.
37
- def name
43
+ define_method(:name) do
38
44
  raise NotImplementedError
39
45
  end
40
46
 
@@ -10,6 +10,10 @@ module T::Types
10
10
  @type = type
11
11
  end
12
12
 
13
+ def build_type
14
+ nil
15
+ end
16
+
13
17
  # overrides Base
14
18
  def name
15
19
  "T.class_of(#{@type})"
@@ -17,7 +21,7 @@ module T::Types
17
21
 
18
22
  # overrides Base
19
23
  def valid?(obj)
20
- obj.is_a?(Module) && obj <= @type
24
+ obj.is_a?(Module) && (obj <= @type || false)
21
25
  end
22
26
 
23
27
  # overrides Base
@@ -28,7 +32,7 @@ module T::Types
28
32
  when Simple
29
33
  @type.is_a?(other.raw_type)
30
34
  when TypedClass
31
- true
35
+ @type.is_a?(other.underlying_class)
32
36
  else
33
37
  false
34
38
  end
@@ -12,6 +12,10 @@ module T::Types
12
12
  @values = values
13
13
  end
14
14
 
15
+ def build_type
16
+ nil
17
+ end
18
+
15
19
  # overrides Base
16
20
  def valid?(obj)
17
21
  @values.member?(obj)
@@ -29,7 +33,7 @@ module T::Types
29
33
 
30
34
  # overrides Base
31
35
  def name
32
- @name ||= "T.deprecated_enum([#{@values.map(&:inspect).join(', ')}])"
36
+ @name ||= "T.deprecated_enum([#{@values.map(&:inspect).sort.join(', ')}])"
33
37
  end
34
38
 
35
39
  # overrides Base
@@ -6,23 +6,30 @@ module T::Types
6
6
  # Takes a list of types. Validates each item in an array using the type in the same position
7
7
  # in the list.
8
8
  class FixedArray < Base
9
- attr_reader :types
10
-
11
9
  def initialize(types)
12
- @types = types.map {|type| T::Utils.coerce(type)}
10
+ @inner_types = types
11
+ end
12
+
13
+ def types
14
+ @types ||= @inner_types.map {|type| T::Utils.coerce(type)}
15
+ end
16
+
17
+ def build_type
18
+ types
19
+ nil
13
20
  end
14
21
 
15
22
  # overrides Base
16
23
  def name
17
- "[#{@types.join(', ')}]"
24
+ "[#{types.join(', ')}]"
18
25
  end
19
26
 
20
27
  # overrides Base
21
28
  def recursively_valid?(obj)
22
- if obj.is_a?(Array) && obj.length == @types.length
29
+ if obj.is_a?(Array) && obj.length == types.length
23
30
  i = 0
24
- while i < @types.length
25
- if !@types[i].recursively_valid?(obj[i])
31
+ while i < types.length
32
+ if !types[i].recursively_valid?(obj[i])
26
33
  return false
27
34
  end
28
35
  i += 1
@@ -35,10 +42,10 @@ module T::Types
35
42
 
36
43
  # overrides Base
37
44
  def valid?(obj)
38
- if obj.is_a?(Array) && obj.length == @types.length
45
+ if obj.is_a?(Array) && obj.length == types.length
39
46
  i = 0
40
- while i < @types.length
41
- if !@types[i].valid?(obj[i])
47
+ while i < types.length
48
+ if !types[i].valid?(obj[i])
42
49
  return false
43
50
  end
44
51
  i += 1
@@ -56,7 +63,7 @@ module T::Types
56
63
  # Properly speaking, covariance here is unsound since arrays
57
64
  # can be mutated, but sorbet implements covariant tuples for
58
65
  # ease of adoption.
59
- @types.size == other.types.size && @types.zip(other.types).all? do |t1, t2|
66
+ types.size == other.types.size && types.zip(other.types).all? do |t1, t2|
60
67
  t1.subtype_of?(t2)
61
68
  end
62
69
  when TypedArray
@@ -85,7 +92,7 @@ module T::Types
85
92
  # overrides Base
86
93
  def describe_obj(obj)
87
94
  if obj.is_a?(Array)
88
- if obj.length == @types.length
95
+ if obj.length == types.length
89
96
  item_classes = obj.map(&:class).join(', ')
90
97
  "type [#{item_classes}]"
91
98
  else