sorbet-runtime 0.5.11144 → 0.5.11266

Sign up to get free protection for your applications and to get access to all the features.
Files changed (54) hide show
  1. checksums.yaml +4 -4
  2. data/lib/sorbet-runtime.rb +1 -1
  3. data/lib/types/compatibility_patches.rb +1 -1
  4. data/lib/types/configuration.rb +1 -1
  5. data/lib/types/private/abstract/declare.rb +4 -5
  6. data/lib/types/private/caller_utils.rb +21 -0
  7. data/lib/types/private/methods/_methods.rb +35 -30
  8. data/lib/types/private/methods/call_validation.rb +16 -2
  9. data/lib/types/private/methods/call_validation_2_6.rb +518 -0
  10. data/lib/types/private/methods/call_validation_2_7.rb +518 -0
  11. data/lib/types/private/methods/decl_builder.rb +1 -1
  12. data/lib/types/private/methods/signature.rb +10 -2
  13. data/lib/types/private/methods/signature_validation.rb +12 -6
  14. data/lib/types/private/sealed.rb +6 -6
  15. data/lib/types/private/types/not_typed.rb +4 -0
  16. data/lib/types/private/types/string_holder.rb +4 -0
  17. data/lib/types/private/types/type_alias.rb +4 -0
  18. data/lib/types/private/types/void.rb +4 -0
  19. data/lib/types/props/_props.rb +2 -2
  20. data/lib/types/props/decorator.rb +8 -7
  21. data/lib/types/props/has_lazily_specialized_methods.rb +2 -0
  22. data/lib/types/props/pretty_printable.rb +1 -1
  23. data/lib/types/props/private/deserializer_generator.rb +4 -1
  24. data/lib/types/props/private/setter_factory.rb +129 -69
  25. data/lib/types/props/serializable.rb +7 -1
  26. data/lib/types/types/anything.rb +4 -0
  27. data/lib/types/types/attached_class.rb +4 -0
  28. data/lib/types/types/base.rb +6 -0
  29. data/lib/types/types/class_of.rb +4 -0
  30. data/lib/types/types/enum.rb +4 -0
  31. data/lib/types/types/fixed_array.rb +19 -12
  32. data/lib/types/types/fixed_hash.rb +16 -9
  33. data/lib/types/types/intersection.rb +13 -6
  34. data/lib/types/types/noreturn.rb +4 -0
  35. data/lib/types/types/proc.rb +18 -8
  36. data/lib/types/types/self_type.rb +4 -0
  37. data/lib/types/types/simple.rb +9 -0
  38. data/lib/types/types/t_enum.rb +4 -0
  39. data/lib/types/types/type_parameter.rb +4 -0
  40. data/lib/types/types/type_variable.rb +4 -0
  41. data/lib/types/types/typed_array.rb +6 -1
  42. data/lib/types/types/typed_class.rb +21 -4
  43. data/lib/types/types/typed_enumerable.rb +19 -12
  44. data/lib/types/types/typed_enumerator.rb +1 -3
  45. data/lib/types/types/typed_enumerator_chain.rb +1 -3
  46. data/lib/types/types/typed_enumerator_lazy.rb +1 -3
  47. data/lib/types/types/typed_hash.rb +17 -7
  48. data/lib/types/types/typed_range.rb +1 -3
  49. data/lib/types/types/typed_set.rb +1 -3
  50. data/lib/types/types/union.rb +12 -5
  51. data/lib/types/types/untyped.rb +4 -0
  52. data/lib/types/utils.rb +6 -4
  53. metadata +16 -30
  54. data/lib/types/interface_wrapper.rb +0 -162
@@ -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
 
@@ -117,7 +117,9 @@ module T::Props
117
117
  def eagerly_define_lazy_methods!
118
118
  return if lazily_defined_methods.empty?
119
119
 
120
+ # rubocop:disable Style/StringConcatenation
120
121
  source = "# frozen_string_literal: true\n" + lazily_defined_methods.values.map(&:call).map(&:to_s).join("\n\n")
122
+ # rubocop:enable Style/StringConcatenation
121
123
 
122
124
  cls = decorated_class
123
125
  cls.class_eval(source)
@@ -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
@@ -264,7 +264,13 @@ module T::Props::Serializable::DecoratorMethods
264
264
  line_label = error.backtrace.find {|l| l.end_with?("in `#{generated_method}'")}
265
265
  return unless line_label
266
266
 
267
- line_num = line_label.split(':')[1]&.to_i
267
+ line_num = if line_label.start_with?("(eval)")
268
+ # (eval):13:in `__t_props_generated_serialize'
269
+ line_label.split(':')[1]&.to_i
270
+ else
271
+ # (eval at /Users/jez/stripe/sorbet/gems/sorbet-runtime/lib/types/props/has_lazily_specialized_methods.rb:65):13:in `__t_props_generated_serialize'
272
+ line_label.split(':')[2]&.to_i
273
+ end
268
274
  return unless line_num
269
275
 
270
276
  source_lines = self.send(generate_source_method).split("\n")
@@ -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"
@@ -33,6 +33,12 @@ 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
+ def build_type
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
43
  def name
38
44
  raise NotImplementedError
@@ -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})"
@@ -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)
@@ -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
@@ -5,30 +5,37 @@ module T::Types
5
5
  # Takes a hash of types. Validates each item in a hash using the type in the same position
6
6
  # in the list.
7
7
  class FixedHash < Base
8
- attr_reader :types
9
-
10
8
  def initialize(types)
11
- @types = types.transform_values {|v| T::Utils.coerce(v)}
9
+ @inner_types = types
10
+ end
11
+
12
+ def types
13
+ @types ||= @inner_types.transform_values {|v| T::Utils.coerce(v)}
14
+ end
15
+
16
+ def build_type
17
+ types
18
+ nil
12
19
  end
13
20
 
14
21
  # overrides Base
15
22
  def name
16
- serialize_hash(@types)
23
+ serialize_hash(types)
17
24
  end
18
25
 
19
26
  # overrides Base
20
27
  def recursively_valid?(obj)
21
28
  return false unless obj.is_a?(Hash)
22
- return false if @types.any? {|key, type| !type.recursively_valid?(obj[key])}
23
- return false if obj.any? {|key, _| !@types[key]}
29
+ return false if types.any? {|key, type| !type.recursively_valid?(obj[key])}
30
+ return false if obj.any? {|key, _| !types[key]}
24
31
  true
25
32
  end
26
33
 
27
34
  # overrides Base
28
35
  def valid?(obj)
29
36
  return false unless obj.is_a?(Hash)
30
- return false if @types.any? {|key, type| !type.valid?(obj[key])}
31
- return false if obj.any? {|key, _| !@types[key]}
37
+ return false if types.any? {|key, type| !type.valid?(obj[key])}
38
+ return false if obj.any? {|key, _| !types[key]}
32
39
  true
33
40
  end
34
41
 
@@ -37,7 +44,7 @@ module T::Types
37
44
  case other
38
45
  when FixedHash
39
46
  # Using `subtype_of?` here instead of == would be unsound
40
- @types == other.types
47
+ types == other.types
41
48
  when TypedHash
42
49
  # warning: covariant hashes
43
50
 
@@ -4,10 +4,12 @@
4
4
  module T::Types
5
5
  # Takes a list of types. Validates that an object matches all of the types.
6
6
  class Intersection < Base
7
- attr_reader :types
8
-
9
7
  def initialize(types)
10
- @types = types.flat_map do |type|
8
+ @inner_types = types
9
+ end
10
+
11
+ def types
12
+ @types ||= @inner_types.flat_map do |type|
11
13
  type = T::Utils.resolve_alias(type)
12
14
  if type.is_a?(Intersection)
13
15
  # Simplify nested intersections (mostly so `name` returns a nicer value)
@@ -18,19 +20,24 @@ module T::Types
18
20
  end.uniq
19
21
  end
20
22
 
23
+ def build_type
24
+ types
25
+ nil
26
+ end
27
+
21
28
  # overrides Base
22
29
  def name
23
- "T.all(#{@types.map(&:name).compact.sort.join(', ')})"
30
+ "T.all(#{types.map(&:name).compact.sort.join(', ')})"
24
31
  end
25
32
 
26
33
  # overrides Base
27
34
  def recursively_valid?(obj)
28
- @types.all? {|type| type.recursively_valid?(obj)}
35
+ types.all? {|type| type.recursively_valid?(obj)}
29
36
  end
30
37
 
31
38
  # overrides Base
32
39
  def valid?(obj)
33
- @types.all? {|type| type.valid?(obj)}
40
+ types.all? {|type| type.valid?(obj)}
34
41
  end
35
42
 
36
43
  # overrides Base
@@ -6,6 +6,10 @@ module T::Types
6
6
  class NoReturn < 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.noreturn"
@@ -8,21 +8,31 @@ module T::Types
8
8
  # At present, we only support fixed-arity procs with no optional or
9
9
  # keyword arguments.
10
10
  class Proc < Base
11
- attr_reader :arg_types
12
- attr_reader :returns
13
-
14
11
  def initialize(arg_types, returns)
15
- @arg_types = {}
16
- arg_types.each do |key, raw_type|
17
- @arg_types[key] = T::Utils.coerce(raw_type)
12
+ @inner_arg_types = arg_types
13
+ @inner_returns = returns
14
+ end
15
+
16
+ def arg_types
17
+ @arg_types ||= @inner_arg_types.transform_values do |raw_type|
18
+ T::Utils.coerce(raw_type)
18
19
  end
19
- @returns = T::Utils.coerce(returns)
20
+ end
21
+
22
+ def returns
23
+ @returns ||= T::Utils.coerce(@inner_returns)
24
+ end
25
+
26
+ def build_type
27
+ arg_types
28
+ returns
29
+ nil
20
30
  end
21
31
 
22
32
  # overrides Base
23
33
  def name
24
34
  args = []
25
- @arg_types.each do |k, v|
35
+ arg_types.each do |k, v|
26
36
  args << "#{k}: #{v.name}"
27
37
  end
28
38
  "T.proc.params(#{args.join(', ')}).returns(#{returns})"
@@ -8,6 +8,10 @@ module T::Types
8
8
 
9
9
  def initialize(); end
10
10
 
11
+ def build_type
12
+ nil
13
+ end
14
+
11
15
  # overrides Base
12
16
  def name
13
17
  "T.self_type"
@@ -13,13 +13,22 @@ module T::Types
13
13
  @raw_type = raw_type
14
14
  end
15
15
 
16
+ def build_type
17
+ nil
18
+ end
19
+
16
20
  # overrides Base
17
21
  def name
18
22
  # Memoize to mitigate pathological performance with anonymous modules (https://bugs.ruby-lang.org/issues/11119)
19
23
  #
20
24
  # `name` isn't normally a hot path for types, but it is used in initializing a T::Types::Union,
21
25
  # and so in `T.nilable`, and so in runtime constructions like `x = T.let(nil, T.nilable(Integer))`.
26
+ #
27
+ # Care more about back compat than we do about performance here.
28
+ # Once 2.6 is well in the rear view mirror, we can replace this.
29
+ # rubocop:disable Performance/BindCall
22
30
  @name ||= (NAME_METHOD.bind(@raw_type).call || @raw_type.name).freeze
31
+ # rubocop:enable Performance/BindCall
23
32
  end
24
33
 
25
34
  # overrides Base
@@ -10,6 +10,10 @@ module T::Types
10
10
  @val = val
11
11
  end
12
12
 
13
+ def build_type
14
+ nil
15
+ end
16
+
13
17
  # overrides Base
14
18
  def name
15
19
  # Strips the #<...> off, just leaving the ...