sorbet-runtime 0.0.1.pre.prealpha → 0.4.4253

Sign up to get free protection for your applications and to get access to all the features.
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