sorbet-runtime 0.0.1.pre.prealpha → 0.4.4253

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.
Files changed (69) hide show
  1. checksums.yaml +5 -5
  2. data/lib/sorbet-runtime.rb +100 -0
  3. data/lib/types/_types.rb +245 -0
  4. data/lib/types/abstract_utils.rb +50 -0
  5. data/lib/types/boolean.rb +8 -0
  6. data/lib/types/compatibility_patches.rb +37 -0
  7. data/lib/types/configuration.rb +368 -0
  8. data/lib/types/generic.rb +23 -0
  9. data/lib/types/helpers.rb +31 -0
  10. data/lib/types/interface_wrapper.rb +158 -0
  11. data/lib/types/private/abstract/data.rb +36 -0
  12. data/lib/types/private/abstract/declare.rb +39 -0
  13. data/lib/types/private/abstract/hooks.rb +43 -0
  14. data/lib/types/private/abstract/validate.rb +128 -0
  15. data/lib/types/private/casts.rb +22 -0
  16. data/lib/types/private/class_utils.rb +102 -0
  17. data/lib/types/private/decl_state.rb +18 -0
  18. data/lib/types/private/error_handler.rb +37 -0
  19. data/lib/types/private/methods/_methods.rb +344 -0
  20. data/lib/types/private/methods/call_validation.rb +1177 -0
  21. data/lib/types/private/methods/decl_builder.rb +275 -0
  22. data/lib/types/private/methods/modes.rb +18 -0
  23. data/lib/types/private/methods/signature.rb +196 -0
  24. data/lib/types/private/methods/signature_validation.rb +232 -0
  25. data/lib/types/private/mixins/mixins.rb +27 -0
  26. data/lib/types/private/runtime_levels.rb +41 -0
  27. data/lib/types/private/types/not_typed.rb +23 -0
  28. data/lib/types/private/types/string_holder.rb +26 -0
  29. data/lib/types/private/types/void.rb +33 -0
  30. data/lib/types/profile.rb +27 -0
  31. data/lib/types/props/_props.rb +165 -0
  32. data/lib/types/props/constructor.rb +20 -0
  33. data/lib/types/props/custom_type.rb +84 -0
  34. data/lib/types/props/decorator.rb +826 -0
  35. data/lib/types/props/errors.rb +8 -0
  36. data/lib/types/props/optional.rb +73 -0
  37. data/lib/types/props/plugin.rb +15 -0
  38. data/lib/types/props/pretty_printable.rb +106 -0
  39. data/lib/types/props/serializable.rb +376 -0
  40. data/lib/types/props/type_validation.rb +98 -0
  41. data/lib/types/props/utils.rb +49 -0
  42. data/lib/types/props/weak_constructor.rb +30 -0
  43. data/lib/types/runtime_profiled.rb +36 -0
  44. data/lib/types/sig.rb +28 -0
  45. data/lib/types/struct.rb +8 -0
  46. data/lib/types/types/base.rb +141 -0
  47. data/lib/types/types/class_of.rb +38 -0
  48. data/lib/types/types/enum.rb +42 -0
  49. data/lib/types/types/fixed_array.rb +60 -0
  50. data/lib/types/types/fixed_hash.rb +59 -0
  51. data/lib/types/types/intersection.rb +36 -0
  52. data/lib/types/types/noreturn.rb +25 -0
  53. data/lib/types/types/proc.rb +51 -0
  54. data/lib/types/types/self_type.rb +31 -0
  55. data/lib/types/types/simple.rb +33 -0
  56. data/lib/types/types/type_member.rb +7 -0
  57. data/lib/types/types/type_parameter.rb +23 -0
  58. data/lib/types/types/type_template.rb +7 -0
  59. data/lib/types/types/type_variable.rb +31 -0
  60. data/lib/types/types/typed_array.rb +20 -0
  61. data/lib/types/types/typed_enumerable.rb +141 -0
  62. data/lib/types/types/typed_enumerator.rb +22 -0
  63. data/lib/types/types/typed_hash.rb +29 -0
  64. data/lib/types/types/typed_range.rb +22 -0
  65. data/lib/types/types/typed_set.rb +22 -0
  66. data/lib/types/types/union.rb +59 -0
  67. data/lib/types/types/untyped.rb +25 -0
  68. data/lib/types/utils.rb +223 -0
  69. metadata +122 -15
@@ -0,0 +1,275 @@
1
+ # frozen_string_literal: true
2
+ # typed: true
3
+
4
+ module T::Private::Methods
5
+ Declaration = Struct.new(:mod, :params, :returns, :bind, :mode, :checked, :finalized, :soft_notify, :override_allow_incompatible, :type_parameters, :generated)
6
+
7
+ class DeclBuilder
8
+ attr_reader :decl
9
+
10
+ class BuilderError < StandardError; end
11
+
12
+ private def check_live!
13
+ if decl.finalized
14
+ raise BuilderError.new("You can't modify a signature declaration after it has been used.")
15
+ end
16
+ end
17
+
18
+ def initialize(mod)
19
+ # TODO RUBYPLAT-1278 - with ruby 2.5, use kwargs here
20
+ @decl = Declaration.new(
21
+ mod,
22
+ ARG_NOT_PROVIDED, # params
23
+ ARG_NOT_PROVIDED, # returns
24
+ ARG_NOT_PROVIDED, # bind
25
+ Modes.standard, # mode
26
+ ARG_NOT_PROVIDED, # checked
27
+ false, # finalized
28
+ ARG_NOT_PROVIDED, # soft_notify
29
+ nil, # override_allow_incompatible
30
+ ARG_NOT_PROVIDED, # type_parameters
31
+ ARG_NOT_PROVIDED, # generated
32
+ )
33
+ end
34
+
35
+ def params(params)
36
+ check_live!
37
+ if !decl.params.equal?(ARG_NOT_PROVIDED)
38
+ raise BuilderError.new("You can't call .params twice")
39
+ end
40
+
41
+ decl.params = params
42
+
43
+ self
44
+ end
45
+
46
+ def returns(type)
47
+ check_live!
48
+ if decl.returns.is_a?(T::Private::Types::Void)
49
+ raise BuilderError.new("You can't call .returns after calling .void.")
50
+ end
51
+ if !decl.returns.equal?(ARG_NOT_PROVIDED)
52
+ raise BuilderError.new("You can't call .returns multiple times in a signature.")
53
+ end
54
+
55
+ decl.returns = type
56
+
57
+ self
58
+ end
59
+
60
+ def void
61
+ check_live!
62
+ if !decl.returns.equal?(ARG_NOT_PROVIDED)
63
+ raise BuilderError.new("You can't call .void after calling .returns.")
64
+ end
65
+
66
+ decl.returns = T::Private::Types::Void.new
67
+
68
+ self
69
+ end
70
+
71
+ def bind(type)
72
+ check_live!
73
+ if !decl.bind.equal?(ARG_NOT_PROVIDED)
74
+ raise BuilderError.new("You can't call .bind multiple times in a signature.")
75
+ end
76
+
77
+ decl.bind = type
78
+
79
+ self
80
+ end
81
+
82
+ def checked(level)
83
+ if T.unsafe(true)
84
+ raise "The .checked API is unstable, so we don't want it used until we redesign it. To change Sorbet's runtime behavior, see https://sorbet.org/docs/tconfiguration"
85
+ end
86
+ check_live!
87
+
88
+ if !decl.checked.equal?(ARG_NOT_PROVIDED)
89
+ raise BuilderError.new("You can't call .checked multiple times in a signature.")
90
+ end
91
+ if !decl.soft_notify.equal?(ARG_NOT_PROVIDED)
92
+ raise BuilderError.new("You can't use .checked with .soft.")
93
+ end
94
+ if !decl.generated.equal?(ARG_NOT_PROVIDED)
95
+ raise BuilderError.new("You can't use .checked with .generated.")
96
+ end
97
+ if !T::Private::RuntimeLevels::LEVELS.include?(level)
98
+ raise BuilderError.new("Invalid `checked` level '#{level}'. Use one of: #{T::Private::RuntimeLevels::LEVELS}.")
99
+ end
100
+
101
+ decl.checked = level
102
+
103
+ self
104
+ end
105
+
106
+ def soft(notify:)
107
+ if T.unsafe(true)
108
+ raise "The .soft API is unstable, so we don't want it used until we redesign it. To change Sorbet's runtime behavior, see https://sorbet.org/docs/tconfiguration"
109
+ end
110
+ check_live!
111
+
112
+ if !decl.soft_notify.equal?(ARG_NOT_PROVIDED)
113
+ raise BuilderError.new("You can't call .soft multiple times in a signature.")
114
+ end
115
+ if !decl.checked.equal?(ARG_NOT_PROVIDED)
116
+ raise BuilderError.new("You can't use .soft with .checked.")
117
+ end
118
+ if !decl.generated.equal?(ARG_NOT_PROVIDED)
119
+ raise BuilderError.new("You can't use .soft with .generated.")
120
+ end
121
+
122
+ # TODO consider validating that :notify is a project that sentry knows about,
123
+ # as per https://git.corp.stripe.com/stripe-internal/pay-server/blob/master/lib/event/job/sentry_job.rb#L125
124
+ if !notify || notify == ''
125
+ raise BuilderError.new("You can't provide an empty notify to .soft().")
126
+ end
127
+
128
+ decl.soft_notify = notify
129
+
130
+ self
131
+ end
132
+
133
+ def generated
134
+ if T.unsafe(true)
135
+ raise "The .generated API is unstable, so we don't want it used until we redesign it. To change Sorbet's runtime behavior, see https://sorbet.org/docs/tconfiguration"
136
+ end
137
+ check_live!
138
+
139
+ if !decl.generated.equal?(ARG_NOT_PROVIDED)
140
+ raise BuilderError.new("You can't call .generated multiple times in a signature.")
141
+ end
142
+ if !decl.checked.equal?(ARG_NOT_PROVIDED)
143
+ raise BuilderError.new("You can't use .generated with .checked.")
144
+ end
145
+ if !decl.soft_notify.equal?(ARG_NOT_PROVIDED)
146
+ raise BuilderError.new("You can't use .generated with .soft.")
147
+ end
148
+
149
+ decl.generated = true
150
+
151
+ self
152
+ end
153
+
154
+ def abstract
155
+ check_live!
156
+
157
+ case decl.mode
158
+ when Modes.standard
159
+ decl.mode = Modes.abstract
160
+ when Modes.abstract
161
+ raise BuilderError.new(".abstract cannot be repeated in a single signature")
162
+ else
163
+ raise BuilderError.new("`.abstract` cannot be combined with any of `.override`, `.implementation`, or "\
164
+ "`.overridable`.")
165
+ end
166
+
167
+ self
168
+ end
169
+
170
+ def override(allow_incompatible: false)
171
+ check_live!
172
+
173
+ case decl.mode
174
+ when Modes.standard
175
+ decl.mode = Modes.override
176
+ decl.override_allow_incompatible = allow_incompatible
177
+ when Modes.override
178
+ raise BuilderError.new(".override cannot be repeated in a single signature")
179
+ else
180
+ raise BuilderError.new("`.override` cannot be combined with any of `.abstract`, `.implementation`, or "\
181
+ "`.overridable`.")
182
+ end
183
+
184
+ self
185
+ end
186
+
187
+ def overridable
188
+ check_live!
189
+
190
+ case decl.mode
191
+ when Modes.abstract, Modes.override
192
+ raise BuilderError.new("`.overridable` cannot be combined with `.#{decl.mode}`")
193
+ when Modes.standard
194
+ decl.mode = Modes.overridable
195
+ when Modes.implementation
196
+ decl.mode = Modes.overridable_implementation
197
+ when Modes.overridable, Modes.overridable_implementation
198
+ raise BuilderError.new(".overridable cannot be repeated in a single signature")
199
+ end
200
+
201
+ self
202
+ end
203
+
204
+ def implementation
205
+ check_live!
206
+
207
+ case decl.mode
208
+ when Modes.abstract, Modes.override
209
+ raise BuilderError.new("`.implementation` cannot be combined with `.#{decl.mode}`")
210
+ when Modes.standard
211
+ decl.mode = Modes.implementation
212
+ when Modes.overridable
213
+ decl.mode = Modes.overridable_implementation
214
+ when Modes.implementation, Modes.overridable_implementation
215
+ raise BuilderError.new(".implementation cannot be repeated in a single signature")
216
+ end
217
+
218
+ self
219
+ end
220
+
221
+ # Declares valid type paramaters which can be used with `T.type_parameter` in
222
+ # this `sig`.
223
+ #
224
+ # This is used for generic methods. Example usage:
225
+ #
226
+ # sig do
227
+ # type_parameters(:U)
228
+ # .params(blk: T.proc.params(arg0: Elem).returns(T.type_parameter(:U)))
229
+ # .returns(T::Array[T.type_parameter(:U)])
230
+ # end
231
+ # def map(&blk); end
232
+ def type_parameters(*names)
233
+ check_live!
234
+
235
+ names.each do |name|
236
+ raise BuilderError.new("not a symbol: #{name}") unless name.is_a?(Symbol)
237
+ end
238
+
239
+ if !decl.type_parameters.equal?(ARG_NOT_PROVIDED)
240
+ raise BuilderError.new("You can't call .type_parameters multiple times in a signature.")
241
+ end
242
+
243
+ decl.type_parameters = names
244
+
245
+ self
246
+ end
247
+
248
+ def finalize!
249
+ check_live!
250
+
251
+ if decl.bind.equal?(ARG_NOT_PROVIDED)
252
+ decl.bind = nil
253
+ end
254
+ if decl.checked.equal?(ARG_NOT_PROVIDED)
255
+ decl.checked = :always
256
+ end
257
+ if decl.soft_notify.equal?(ARG_NOT_PROVIDED)
258
+ decl.soft_notify = nil
259
+ end
260
+ if decl.generated.equal?(ARG_NOT_PROVIDED)
261
+ decl.generated = false
262
+ end
263
+ if decl.params.equal?(ARG_NOT_PROVIDED)
264
+ decl.params = {}
265
+ end
266
+ if decl.type_parameters.equal?(ARG_NOT_PROVIDED)
267
+ decl.type_parameters = {}
268
+ end
269
+
270
+ decl.finalized = true
271
+
272
+ self
273
+ end
274
+ end
275
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+ # typed: true
3
+
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.implementation; 'implementation'; end
9
+ def self.override; 'override'; end
10
+ def self.overridable_implementation; 'overridable_implementation'; end
11
+ def self.untyped; 'untyped'; end
12
+ MODES = [self.standard, self.abstract, self.overridable, self.implementation, self.override, self.overridable_implementation, self.untyped]
13
+
14
+ IMPLEMENT_MODES = [self.implementation, self.overridable_implementation]
15
+ OVERRIDABLE_MODES = [self.override, self.overridable, self.overridable_implementation, self.untyped]
16
+ OVERRIDE_MODES = [self.override]
17
+ NON_OVERRIDE_MODES = MODES - OVERRIDE_MODES - IMPLEMENT_MODES
18
+ end
@@ -0,0 +1,196 @@
1
+ # frozen_string_literal: true
2
+ # typed: true
3
+
4
+ class T::Private::Methods::Signature
5
+ attr_reader :method, :method_name, :arg_types, :kwarg_types, :block_type, :block_name,
6
+ :rest_type, :rest_name, :keyrest_type, :keyrest_name, :bind,
7
+ :return_type, :mode, :req_arg_count, :req_kwarg_names, :has_rest, :has_keyrest,
8
+ :check_level, :generated, :parameters, :soft_notify, :override_allow_incompatible, :ever_failed
9
+
10
+ def self.new_untyped(method:, mode: T::Private::Methods::Modes.untyped, parameters: method.parameters)
11
+ # Using `Untyped` ensures we'll get an error if we ever try validation on these.
12
+ not_typed = T::Private::Types::NotTyped.new
13
+ raw_return_type = not_typed
14
+ raw_arg_types = parameters.map do |_param_kind, param_name|
15
+ [param_name, not_typed]
16
+ end.to_h
17
+
18
+ self.new(
19
+ method: method,
20
+ method_name: method.name,
21
+ raw_arg_types: raw_arg_types,
22
+ raw_return_type: raw_return_type,
23
+ bind: nil,
24
+ mode: mode,
25
+ check_level: :never,
26
+ parameters: parameters,
27
+ soft_notify: nil,
28
+ )
29
+ end
30
+
31
+ def mark_failed
32
+ @ever_failed = true
33
+ end
34
+
35
+ def initialize(method:, method_name:, raw_arg_types:, raw_return_type:, bind:, mode:, check_level:, parameters: method.parameters, soft_notify:, generated: false, override_allow_incompatible: false)
36
+ @method = method
37
+ @method_name = method_name
38
+ @arg_types = []
39
+ @kwarg_types = {}
40
+ @block_type = nil
41
+ @block_name = nil
42
+ @rest_type = nil
43
+ @rest_name = nil
44
+ @keyrest_type = nil
45
+ @keyrest_name = nil
46
+ @return_type = T::Utils.coerce(raw_return_type)
47
+ @bind = bind ? T::Utils.coerce(bind) : bind
48
+ @mode = mode
49
+ @check_level = check_level
50
+ @req_arg_count = 0
51
+ @req_kwarg_names = []
52
+ @has_rest = false
53
+ @has_keyrest = false
54
+ @parameters = parameters
55
+ @soft_notify = soft_notify
56
+ @override_allow_incompatible = override_allow_incompatible
57
+ @generated = generated
58
+ @ever_failed = false
59
+
60
+ param_names = parameters.map {|_, name| name}
61
+ declared_param_names = raw_arg_types.keys
62
+ missing_names = param_names - declared_param_names
63
+ extra_names = declared_param_names - param_names
64
+ if !missing_names.empty?
65
+ raise "The declaration for `#{method.name}` is missing parameter(s): #{missing_names.join(', ')}"
66
+ end
67
+ if !extra_names.empty?
68
+ raise "The declaration for `#{method.name}` has extra parameter(s): #{extra_names.join(', ')}"
69
+ end
70
+
71
+ parameters.zip(raw_arg_types) do |(param_kind, param_name), (type_name, raw_type)|
72
+ if type_name != param_name
73
+ hint = ""
74
+ # Ruby reorders params so that required keyword arguments
75
+ # always precede optional keyword arguments. We can't tell
76
+ # whether the culprit is the Ruby reordering or user error, so
77
+ # we error but include a note
78
+ if param_kind == :keyreq && parameters.any? {|k, _| k == :key}
79
+ hint = "\n\nNote: Any required keyword arguments must precede any optional keyword " \
80
+ "arguments. If your method declaration matches your `def`, try reordering any " \
81
+ "optional keyword parameters to the end of the method list."
82
+ end
83
+
84
+ raise "Parameter `#{type_name}` is declared out of order (declared as arg number " \
85
+ "#{declared_param_names.index(type_name) + 1}, defined in the method as arg number " \
86
+ "#{param_names.index(type_name) + 1}).#{hint}\nMethod: #{method_desc}"
87
+ end
88
+
89
+ type = T::Utils.coerce(raw_type)
90
+
91
+ case param_kind
92
+ when :req
93
+ if @arg_types.length > @req_arg_count
94
+ # Note that this is actually is supported by Ruby, but it would add complexity to
95
+ # support it here, and I'm happy to discourage its use anyway.
96
+ raise "Required params after optional params are not supported in method declarations. Method: #{method_desc}"
97
+ end
98
+ @arg_types << [param_name, type]
99
+ @req_arg_count += 1
100
+ when :opt
101
+ @arg_types << [param_name, type]
102
+ when :key, :keyreq
103
+ @kwarg_types[param_name] = type
104
+ if param_kind == :keyreq
105
+ @req_kwarg_names << param_name
106
+ end
107
+ when :block
108
+ @block_name = param_name
109
+ @block_type = type
110
+ when :rest
111
+ @has_rest = true
112
+ @rest_name = param_name
113
+ @rest_type = type
114
+ when :keyrest
115
+ @has_keyrest = true
116
+ @keyrest_name = param_name
117
+ @keyrest_type = type
118
+ else
119
+ raise "Unexpected param_kind: `#{param_kind}`. Method: #{method_desc}"
120
+ end
121
+ end
122
+ end
123
+
124
+ def arg_count
125
+ @arg_types.length
126
+ end
127
+
128
+ def kwarg_names
129
+ @kwarg_types.keys
130
+ end
131
+
132
+ def owner
133
+ @method.owner
134
+ end
135
+
136
+ def dsl_method
137
+ "#{@mode}_method"
138
+ end
139
+
140
+ # @return [Hash] a mapping like {arg_name: [val, type], ...}, for only those args actually present.
141
+ def each_args_value_type(args)
142
+ # Manually split out args and kwargs based on ruby's behavior. Do not try to implement this by
143
+ # getting ruby to determine the kwargs for you (e.g., by defining this method to take *args and
144
+ # **kwargs). That won't work, because ruby's behavior for determining kwargs is dependent on the
145
+ # the other parameters in the method definition, and our method definition here doesn't (and
146
+ # can't) match the definition of the method we're validating. In addition, Ruby has a bug that
147
+ # causes forwarding **kwargs to do the wrong thing: see https://bugs.ruby-lang.org/issues/10708
148
+ # and https://bugs.ruby-lang.org/issues/11860.
149
+ if (args.length > @req_arg_count) && (!@kwarg_types.empty? || @has_keyrest) && args[-1].is_a?(Hash)
150
+ kwargs = args[-1]
151
+ args = args[0...-1]
152
+ else
153
+ kwargs = EMPTY_HASH
154
+ end
155
+
156
+ arg_types = @arg_types
157
+
158
+ if @has_rest
159
+ arg_types += [[@rest_name, @rest_type]] * (args.length - @arg_types.length)
160
+
161
+ elsif (args.length < @req_arg_count) || (args.length > @arg_types.length)
162
+ expected_str = @req_arg_count.to_s
163
+ if @arg_types.length != @req_arg_count
164
+ expected_str += "..#{@arg_types.length}"
165
+ end
166
+ raise ArgumentError.new("wrong number of arguments (given #{args.length}, expected #{expected_str})")
167
+ end
168
+
169
+ begin
170
+ it = 0
171
+ while it < args.length
172
+ yield arg_types[it][0], args[it], arg_types[it][1]
173
+ it += 1
174
+ end
175
+ end
176
+
177
+ kwargs.each do |name, val|
178
+ type = @kwarg_types[name]
179
+ if !type && @has_keyrest
180
+ type = @keyrest_type
181
+ end
182
+ yield name, val, type if type
183
+ end
184
+ end
185
+
186
+ def method_desc
187
+ if @method.source_location
188
+ loc = @method.source_location.join(':')
189
+ else
190
+ loc = "<unknown location>"
191
+ end
192
+ "#{@method} at #{loc}"
193
+ end
194
+
195
+ EMPTY_HASH = {}.freeze
196
+ end