sorbet-runtime 0.5.5841

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 (84) hide show
  1. checksums.yaml +7 -0
  2. data/lib/sorbet-runtime.rb +116 -0
  3. data/lib/types/_types.rb +285 -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 +95 -0
  7. data/lib/types/configuration.rb +428 -0
  8. data/lib/types/enum.rb +349 -0
  9. data/lib/types/generic.rb +23 -0
  10. data/lib/types/helpers.rb +39 -0
  11. data/lib/types/interface_wrapper.rb +158 -0
  12. data/lib/types/non_forcing_constants.rb +51 -0
  13. data/lib/types/private/abstract/data.rb +36 -0
  14. data/lib/types/private/abstract/declare.rb +48 -0
  15. data/lib/types/private/abstract/hooks.rb +43 -0
  16. data/lib/types/private/abstract/validate.rb +128 -0
  17. data/lib/types/private/casts.rb +22 -0
  18. data/lib/types/private/class_utils.rb +111 -0
  19. data/lib/types/private/decl_state.rb +30 -0
  20. data/lib/types/private/final.rb +51 -0
  21. data/lib/types/private/methods/_methods.rb +460 -0
  22. data/lib/types/private/methods/call_validation.rb +1149 -0
  23. data/lib/types/private/methods/decl_builder.rb +228 -0
  24. data/lib/types/private/methods/modes.rb +16 -0
  25. data/lib/types/private/methods/signature.rb +196 -0
  26. data/lib/types/private/methods/signature_validation.rb +229 -0
  27. data/lib/types/private/mixins/mixins.rb +27 -0
  28. data/lib/types/private/retry.rb +10 -0
  29. data/lib/types/private/runtime_levels.rb +56 -0
  30. data/lib/types/private/sealed.rb +65 -0
  31. data/lib/types/private/types/not_typed.rb +23 -0
  32. data/lib/types/private/types/string_holder.rb +26 -0
  33. data/lib/types/private/types/type_alias.rb +26 -0
  34. data/lib/types/private/types/void.rb +34 -0
  35. data/lib/types/profile.rb +31 -0
  36. data/lib/types/props/_props.rb +161 -0
  37. data/lib/types/props/constructor.rb +40 -0
  38. data/lib/types/props/custom_type.rb +108 -0
  39. data/lib/types/props/decorator.rb +672 -0
  40. data/lib/types/props/errors.rb +8 -0
  41. data/lib/types/props/generated_code_validation.rb +268 -0
  42. data/lib/types/props/has_lazily_specialized_methods.rb +92 -0
  43. data/lib/types/props/optional.rb +81 -0
  44. data/lib/types/props/plugin.rb +37 -0
  45. data/lib/types/props/pretty_printable.rb +107 -0
  46. data/lib/types/props/private/apply_default.rb +170 -0
  47. data/lib/types/props/private/deserializer_generator.rb +165 -0
  48. data/lib/types/props/private/parser.rb +32 -0
  49. data/lib/types/props/private/serde_transform.rb +192 -0
  50. data/lib/types/props/private/serializer_generator.rb +77 -0
  51. data/lib/types/props/private/setter_factory.rb +134 -0
  52. data/lib/types/props/serializable.rb +330 -0
  53. data/lib/types/props/type_validation.rb +111 -0
  54. data/lib/types/props/utils.rb +59 -0
  55. data/lib/types/props/weak_constructor.rb +67 -0
  56. data/lib/types/runtime_profiled.rb +24 -0
  57. data/lib/types/sig.rb +30 -0
  58. data/lib/types/struct.rb +18 -0
  59. data/lib/types/types/attached_class.rb +37 -0
  60. data/lib/types/types/base.rb +151 -0
  61. data/lib/types/types/class_of.rb +38 -0
  62. data/lib/types/types/enum.rb +42 -0
  63. data/lib/types/types/fixed_array.rb +60 -0
  64. data/lib/types/types/fixed_hash.rb +59 -0
  65. data/lib/types/types/intersection.rb +37 -0
  66. data/lib/types/types/noreturn.rb +29 -0
  67. data/lib/types/types/proc.rb +51 -0
  68. data/lib/types/types/self_type.rb +35 -0
  69. data/lib/types/types/simple.rb +33 -0
  70. data/lib/types/types/t_enum.rb +38 -0
  71. data/lib/types/types/type_member.rb +7 -0
  72. data/lib/types/types/type_parameter.rb +23 -0
  73. data/lib/types/types/type_template.rb +7 -0
  74. data/lib/types/types/type_variable.rb +31 -0
  75. data/lib/types/types/typed_array.rb +34 -0
  76. data/lib/types/types/typed_enumerable.rb +161 -0
  77. data/lib/types/types/typed_enumerator.rb +36 -0
  78. data/lib/types/types/typed_hash.rb +43 -0
  79. data/lib/types/types/typed_range.rb +26 -0
  80. data/lib/types/types/typed_set.rb +36 -0
  81. data/lib/types/types/union.rb +56 -0
  82. data/lib/types/types/untyped.rb +29 -0
  83. data/lib/types/utils.rb +217 -0
  84. metadata +223 -0
@@ -0,0 +1,1149 @@
1
+ # frozen_string_literal: true
2
+ # typed: false
3
+
4
+ module T::Private::Methods::CallValidation
5
+ CallValidation = T::Private::Methods::CallValidation
6
+ Modes = T::Private::Methods::Modes
7
+
8
+ # Wraps a method with a layer of validation for the given type signature.
9
+ # This wrapper is meant to be fast, and is applied by a previous wrapper,
10
+ # which was placed by `_on_method_added`.
11
+ #
12
+ # @param method_sig [T::Private::Methods::Signature]
13
+ # @return [UnboundMethod] the new wrapper method (or the original one if we didn't wrap it)
14
+ def self.wrap_method_if_needed(mod, method_sig, original_method)
15
+ original_visibility = visibility_method_name(mod, method_sig.method_name)
16
+ if method_sig.mode == T::Private::Methods::Modes.abstract
17
+ T::Private::ClassUtils.replace_method(mod, method_sig.method_name) do |*args, &blk|
18
+ # TODO: write a cop to ensure that abstract methods have an empty body
19
+ #
20
+ # We allow abstract methods to be implemented by things further down the ancestor chain.
21
+ # So, if a super method exists, call it.
22
+ if defined?(super)
23
+ super(*args, &blk)
24
+ else
25
+ raise NotImplementedError.new(
26
+ "The method `#{method_sig.method_name}` on #{mod} is declared as `abstract`. It does not have an implementation."
27
+ )
28
+ end
29
+ end
30
+ # Note, this logic is duplicated (intentionally, for micro-perf) at `Methods._on_method_added`,
31
+ # make sure to keep changes in sync.
32
+ # This is a trapdoor point for each method:
33
+ # if a given method is wrapped, it stays wrapped; and if not, it's never wrapped.
34
+ # (Therefore, we need the `@wrapped_tests_with_validation` check in `T::RuntimeLevels`.)
35
+ elsif method_sig.check_level == :always || (method_sig.check_level == :tests && T::Private::RuntimeLevels.check_tests?)
36
+ create_validator_method(mod, original_method, method_sig, original_visibility)
37
+ else
38
+ T::Configuration.without_ruby_warnings do
39
+ # get all the shims out of the way and put back the original method
40
+ T::Private::DeclState.current.without_on_method_added do
41
+ mod.send(:define_method, method_sig.method_name, original_method)
42
+ end
43
+ mod.send(original_visibility, method_sig.method_name)
44
+ end
45
+ end
46
+ # Return the newly created method (or the original one if we didn't replace it)
47
+ mod.instance_method(method_sig.method_name)
48
+ end
49
+
50
+ def self.validate_call(instance, original_method, method_sig, args, blk)
51
+ # This method is called for every `sig`. It's critical to keep it fast and
52
+ # reduce number of allocations that happen here.
53
+
54
+ T::Profile.typecheck_sample_attempts -= 1
55
+ should_sample = T::Profile.typecheck_sample_attempts == 0
56
+ if should_sample
57
+ T::Profile.typecheck_sample_attempts = T::Profile::SAMPLE_RATE
58
+ T::Profile.typecheck_samples += 1
59
+ t1 = Process.clock_gettime(Process::CLOCK_MONOTONIC)
60
+ end
61
+
62
+ if method_sig.bind
63
+ message = method_sig.bind.error_message_for_obj(instance)
64
+ if message
65
+ CallValidation.report_error(
66
+ method_sig,
67
+ message,
68
+ 'Bind',
69
+ nil,
70
+ method_sig.bind,
71
+ instance
72
+ )
73
+ end
74
+ end
75
+
76
+ # NOTE: We don't bother validating for missing or extra kwargs;
77
+ # the method call itself will take care of that.
78
+ method_sig.each_args_value_type(args) do |name, arg, type|
79
+ message = type.error_message_for_obj(arg)
80
+ if message
81
+ CallValidation.report_error(
82
+ method_sig,
83
+ message,
84
+ 'Parameter',
85
+ name,
86
+ type,
87
+ arg,
88
+ caller_offset: 2
89
+ )
90
+ end
91
+ end
92
+
93
+ if method_sig.block_type
94
+ message = method_sig.block_type.error_message_for_obj(blk)
95
+ if message
96
+ CallValidation.report_error(
97
+ method_sig,
98
+ message,
99
+ 'Block parameter',
100
+ method_sig.block_name,
101
+ method_sig.block_type,
102
+ blk
103
+ )
104
+ end
105
+ end
106
+
107
+ if should_sample
108
+ T::Profile.typecheck_duration += (Process.clock_gettime(Process::CLOCK_MONOTONIC) - t1)
109
+ end
110
+
111
+ # The following line breaks are intentional to show nice pry message
112
+
113
+
114
+
115
+
116
+
117
+
118
+
119
+
120
+
121
+
122
+ # PRY note:
123
+ # this code is sig validation code.
124
+ # Please issue `finish` to step out of it
125
+
126
+ return_value = original_method.bind(instance).call(*args, &blk)
127
+ if should_sample
128
+ t1 = Process.clock_gettime(Process::CLOCK_MONOTONIC)
129
+ end
130
+
131
+ # The only type that is allowed to change the return value is `.void`.
132
+ # It ignores what you returned and changes it to be a private singleton.
133
+ if method_sig.return_type.is_a?(T::Private::Types::Void)
134
+ T::Private::Types::Void::VOID
135
+ else
136
+ message = method_sig.return_type.error_message_for_obj(return_value)
137
+ if message
138
+ CallValidation.report_error(
139
+ method_sig,
140
+ message,
141
+ 'Return value',
142
+ nil,
143
+ method_sig.return_type,
144
+ return_value,
145
+ )
146
+ end
147
+ if should_sample
148
+ T::Profile.typecheck_duration += (Process.clock_gettime(Process::CLOCK_MONOTONIC) - t1)
149
+ end
150
+ return_value
151
+ end
152
+ end
153
+
154
+ @is_allowed_to_have_fast_path = true
155
+ def self.is_allowed_to_have_fast_path
156
+ @is_allowed_to_have_fast_path
157
+ end
158
+
159
+ def self.disable_fast_path
160
+ @is_allowed_to_have_fast_path = false
161
+ end
162
+
163
+ def self.create_validator_method(mod, original_method, method_sig, original_visibility)
164
+ has_fixed_arity = method_sig.kwarg_types.empty? && !method_sig.has_rest && !method_sig.has_keyrest &&
165
+ original_method.parameters.all? {|(kind, _name)| kind == :req}
166
+ all_args_are_simple = method_sig.arg_types.all? {|_name, type| type.is_a?(T::Types::Simple)}
167
+ has_simple_method_types = all_args_are_simple && method_sig.return_type.is_a?(T::Types::Simple)
168
+ has_simple_procedure_types = all_args_are_simple && method_sig.return_type.is_a?(T::Private::Types::Void)
169
+
170
+ T::Configuration.without_ruby_warnings do
171
+ T::Private::DeclState.current.without_on_method_added do
172
+ if has_fixed_arity && has_simple_method_types && method_sig.arg_types.length < 5 && is_allowed_to_have_fast_path
173
+ create_validator_method_fast(mod, original_method, method_sig)
174
+ elsif has_fixed_arity && has_simple_procedure_types && method_sig.arg_types.length < 5 && is_allowed_to_have_fast_path
175
+ create_validator_procedure_fast(mod, original_method, method_sig)
176
+ else
177
+ create_validator_slow(mod, original_method, method_sig)
178
+ end
179
+ end
180
+ end
181
+ mod.send(original_visibility, method_sig.method_name)
182
+ end
183
+
184
+ def self.create_validator_slow(mod, original_method, method_sig)
185
+ mod.send(:define_method, method_sig.method_name) do |*args, &blk|
186
+ CallValidation.validate_call(self, original_method, method_sig, args, blk)
187
+ end
188
+ if mod.respond_to?(:ruby2_keywords, true)
189
+ mod.send(:ruby2_keywords, method_sig.method_name)
190
+ end
191
+ end
192
+
193
+ def self.create_validator_method_fast(mod, original_method, method_sig)
194
+ if method_sig.return_type.is_a?(T::Private::Types::Void)
195
+ raise "Should have used create_validator_procedure_fast"
196
+ end
197
+ # trampoline to reduce stack frame size
198
+ if method_sig.arg_types.length == 0
199
+ create_validator_method_fast0(mod, original_method, method_sig, method_sig.return_type.raw_type)
200
+ elsif method_sig.arg_types.length == 1
201
+ create_validator_method_fast1(mod, original_method, method_sig, method_sig.return_type.raw_type,
202
+ method_sig.arg_types[0][1].raw_type)
203
+ elsif method_sig.arg_types.length == 2
204
+ create_validator_method_fast2(mod, original_method, method_sig, method_sig.return_type.raw_type,
205
+ method_sig.arg_types[0][1].raw_type,
206
+ method_sig.arg_types[1][1].raw_type)
207
+ elsif method_sig.arg_types.length == 3
208
+ create_validator_method_fast3(mod, original_method, method_sig, method_sig.return_type.raw_type,
209
+ method_sig.arg_types[0][1].raw_type,
210
+ method_sig.arg_types[1][1].raw_type,
211
+ method_sig.arg_types[2][1].raw_type)
212
+ elsif method_sig.arg_types.length == 4
213
+ create_validator_method_fast4(mod, original_method, method_sig, method_sig.return_type.raw_type,
214
+ method_sig.arg_types[0][1].raw_type,
215
+ method_sig.arg_types[1][1].raw_type,
216
+ method_sig.arg_types[2][1].raw_type,
217
+ method_sig.arg_types[3][1].raw_type)
218
+ else
219
+ raise "should not happen"
220
+ end
221
+ end
222
+
223
+ def self.create_validator_method_fast0(mod, original_method, method_sig, return_type)
224
+ mod.send(:define_method, method_sig.method_name) do |&blk|
225
+ # This block is called for every `sig`. It's critical to keep it fast and
226
+ # reduce number of allocations that happen here.
227
+ # This method is a manually sped-up version of more general code in `validate_call`
228
+ T::Profile.typecheck_sample_attempts -= 1
229
+ should_sample = T::Profile.typecheck_sample_attempts == 0
230
+ if should_sample
231
+ T::Profile.typecheck_sample_attempts = T::Profile::SAMPLE_RATE
232
+ T::Profile.typecheck_samples += 1
233
+ t1 = Process.clock_gettime(Process::CLOCK_MONOTONIC)
234
+ end
235
+
236
+ if method_sig.bind
237
+ message = method_sig.bind.error_message_for_obj(self)
238
+ if message
239
+ CallValidation.report_error(
240
+ method_sig,
241
+ message,
242
+ 'Bind',
243
+ nil,
244
+ method_sig.bind,
245
+ self
246
+ )
247
+ end
248
+ end
249
+
250
+ if should_sample
251
+ T::Profile.typecheck_duration += (Process.clock_gettime(Process::CLOCK_MONOTONIC) - t1)
252
+ end
253
+
254
+ # The following line breaks are intentional to show nice pry message
255
+
256
+
257
+
258
+
259
+
260
+
261
+
262
+
263
+
264
+
265
+ # PRY note:
266
+ # this code is sig validation code.
267
+ # Please issue `finish` to step out of it
268
+
269
+ return_value = original_method.bind(self).call(&blk)
270
+ if should_sample
271
+ t1 = Process.clock_gettime(Process::CLOCK_MONOTONIC)
272
+ end
273
+
274
+ unless return_value.is_a?(return_type)
275
+ message = method_sig.return_type.error_message_for_obj(return_value)
276
+ if message
277
+ CallValidation.report_error(
278
+ method_sig,
279
+ message,
280
+ 'Return value',
281
+ nil,
282
+ return_type,
283
+ return_value,
284
+ caller_offset: -1
285
+ )
286
+ end
287
+ end
288
+ if should_sample
289
+ T::Profile.typecheck_duration += (Process.clock_gettime(Process::CLOCK_MONOTONIC) - t1)
290
+ end
291
+ return_value
292
+ end
293
+ end
294
+
295
+ def self.create_validator_method_fast1(mod, original_method, method_sig, return_type, arg0_type)
296
+ mod.send(:define_method, method_sig.method_name) do |arg0, &blk|
297
+ # This block is called for every `sig`. It's critical to keep it fast and
298
+ # reduce number of allocations that happen here.
299
+ # This method is a manually sped-up version of more general code in `validate_call`
300
+
301
+ T::Profile.typecheck_sample_attempts -= 1
302
+ should_sample = T::Profile.typecheck_sample_attempts == 0
303
+ if should_sample
304
+ T::Profile.typecheck_sample_attempts = T::Profile::SAMPLE_RATE
305
+ T::Profile.typecheck_samples += 1
306
+ t1 = Process.clock_gettime(Process::CLOCK_MONOTONIC)
307
+ end
308
+
309
+ if method_sig.bind
310
+ message = method_sig.bind.error_message_for_obj(self)
311
+ if message
312
+ CallValidation.report_error(
313
+ method_sig,
314
+ message,
315
+ 'Bind',
316
+ nil,
317
+ method_sig.bind,
318
+ self
319
+ )
320
+ end
321
+ end
322
+
323
+ unless arg0.is_a?(arg0_type)
324
+ CallValidation.report_error(
325
+ method_sig,
326
+ method_sig.arg_types[0][1].error_message_for_obj(arg0),
327
+ 'Parameter',
328
+ method_sig.arg_types[0][0],
329
+ arg0_type,
330
+ arg0,
331
+ caller_offset: -1
332
+ )
333
+ end
334
+
335
+ if should_sample
336
+ T::Profile.typecheck_duration += (Process.clock_gettime(Process::CLOCK_MONOTONIC) - t1)
337
+ end
338
+
339
+ # The following line breaks are intentional to show nice pry message
340
+
341
+
342
+
343
+
344
+
345
+
346
+
347
+
348
+
349
+
350
+ # PRY note:
351
+ # this code is sig validation code.
352
+ # Please issue `finish` to step out of it
353
+
354
+ return_value = original_method.bind(self).call(arg0, &blk)
355
+ if should_sample
356
+ t1 = Process.clock_gettime(Process::CLOCK_MONOTONIC)
357
+ end
358
+
359
+ unless return_value.is_a?(return_type)
360
+ message = method_sig.return_type.error_message_for_obj(return_value)
361
+ if message
362
+ CallValidation.report_error(
363
+ method_sig,
364
+ message,
365
+ 'Return value',
366
+ nil,
367
+ method_sig.return_type,
368
+ return_value,
369
+ caller_offset: -1
370
+ )
371
+ end
372
+ end
373
+ if should_sample
374
+ T::Profile.typecheck_duration += (Process.clock_gettime(Process::CLOCK_MONOTONIC) - t1)
375
+ end
376
+ return_value
377
+ end
378
+ end
379
+
380
+ def self.create_validator_method_fast2(mod, original_method, method_sig, return_type, arg0_type, arg1_type)
381
+ mod.send(:define_method, method_sig.method_name) do |arg0, arg1, &blk|
382
+ # This block is called for every `sig`. It's critical to keep it fast and
383
+ # reduce number of allocations that happen here.
384
+ # This method is a manually sped-up version of more general code in `validate_call`
385
+
386
+ T::Profile.typecheck_sample_attempts -= 1
387
+ should_sample = T::Profile.typecheck_sample_attempts == 0
388
+ if should_sample
389
+ T::Profile.typecheck_sample_attempts = T::Profile::SAMPLE_RATE
390
+ T::Profile.typecheck_samples += 1
391
+ t1 = Process.clock_gettime(Process::CLOCK_MONOTONIC)
392
+ end
393
+
394
+ if method_sig.bind
395
+ message = method_sig.bind.error_message_for_obj(self)
396
+ if message
397
+ CallValidation.report_error(
398
+ method_sig,
399
+ message,
400
+ 'Bind',
401
+ nil,
402
+ method_sig.bind,
403
+ self
404
+ )
405
+ end
406
+ end
407
+
408
+ unless arg0.is_a?(arg0_type)
409
+ CallValidation.report_error(
410
+ method_sig,
411
+ method_sig.arg_types[0][1].error_message_for_obj(arg0),
412
+ 'Parameter',
413
+ method_sig.arg_types[0][0],
414
+ arg0_type,
415
+ arg0,
416
+ caller_offset: -1
417
+ )
418
+ end
419
+
420
+ unless arg1.is_a?(arg1_type)
421
+ CallValidation.report_error(
422
+ method_sig,
423
+ method_sig.arg_types[1][1].error_message_for_obj(arg1),
424
+ 'Parameter',
425
+ method_sig.arg_types[1][0],
426
+ arg1_type,
427
+ arg1,
428
+ caller_offset: -1
429
+ )
430
+ end
431
+
432
+ if should_sample
433
+ T::Profile.typecheck_duration += (Process.clock_gettime(Process::CLOCK_MONOTONIC) - t1)
434
+ end
435
+
436
+ # The following line breaks are intentional to show nice pry message
437
+
438
+
439
+
440
+
441
+
442
+
443
+
444
+
445
+
446
+
447
+ # PRY note:
448
+ # this code is sig validation code.
449
+ # Please issue `finish` to step out of it
450
+
451
+ return_value = original_method.bind(self).call(arg0, arg1, &blk)
452
+ if should_sample
453
+ t1 = Process.clock_gettime(Process::CLOCK_MONOTONIC)
454
+ end
455
+
456
+ unless return_value.is_a?(return_type)
457
+ message = method_sig.return_type.error_message_for_obj(return_value)
458
+ if message
459
+ CallValidation.report_error(
460
+ method_sig,
461
+ message,
462
+ 'Return value',
463
+ nil,
464
+ method_sig.return_type,
465
+ return_value,
466
+ caller_offset: -1
467
+ )
468
+ end
469
+ end
470
+ if should_sample
471
+ T::Profile.typecheck_duration += (Process.clock_gettime(Process::CLOCK_MONOTONIC) - t1)
472
+ end
473
+ return_value
474
+ end
475
+ end
476
+
477
+ def self.create_validator_method_fast3(mod, original_method, method_sig, return_type, arg0_type, arg1_type, arg2_type)
478
+ mod.send(:define_method, method_sig.method_name) do |arg0, arg1, arg2, &blk|
479
+ # This block is called for every `sig`. It's critical to keep it fast and
480
+ # reduce number of allocations that happen here.
481
+ # This method is a manually sped-up version of more general code in `validate_call`
482
+
483
+ T::Profile.typecheck_sample_attempts -= 1
484
+ should_sample = T::Profile.typecheck_sample_attempts == 0
485
+ if should_sample
486
+ T::Profile.typecheck_sample_attempts = T::Profile::SAMPLE_RATE
487
+ T::Profile.typecheck_samples += 1
488
+ t1 = Process.clock_gettime(Process::CLOCK_MONOTONIC)
489
+ end
490
+
491
+ if method_sig.bind
492
+ message = method_sig.bind.error_message_for_obj(self)
493
+ if message
494
+ CallValidation.report_error(
495
+ method_sig,
496
+ message,
497
+ 'Bind',
498
+ nil,
499
+ method_sig.bind,
500
+ self
501
+ )
502
+ end
503
+ end
504
+
505
+ unless arg0.is_a?(arg0_type)
506
+ CallValidation.report_error(
507
+ method_sig,
508
+ method_sig.arg_types[0][1].error_message_for_obj(arg0),
509
+ 'Parameter',
510
+ method_sig.arg_types[0][0],
511
+ arg0_type,
512
+ arg0,
513
+ caller_offset: -1
514
+ )
515
+ end
516
+
517
+ unless arg1.is_a?(arg1_type)
518
+ CallValidation.report_error(
519
+ method_sig,
520
+ method_sig.arg_types[1][1].error_message_for_obj(arg1),
521
+ 'Parameter',
522
+ method_sig.arg_types[1][0],
523
+ arg1_type,
524
+ arg1,
525
+ caller_offset: -1
526
+ )
527
+ end
528
+
529
+ unless arg2.is_a?(arg2_type)
530
+ CallValidation.report_error(
531
+ method_sig,
532
+ method_sig.arg_types[2][1].error_message_for_obj(arg2),
533
+ 'Parameter',
534
+ method_sig.arg_types[2][0],
535
+ arg2_type,
536
+ arg2,
537
+ caller_offset: -1
538
+ )
539
+ end
540
+
541
+ if should_sample
542
+ T::Profile.typecheck_duration += (Process.clock_gettime(Process::CLOCK_MONOTONIC) - t1)
543
+ end
544
+
545
+ # The following line breaks are intentional to show nice pry message
546
+
547
+
548
+
549
+
550
+
551
+
552
+
553
+
554
+
555
+
556
+ # PRY note:
557
+ # this code is sig validation code.
558
+ # Please issue `finish` to step out of it
559
+
560
+ return_value = original_method.bind(self).call(arg0, arg1, arg2, &blk)
561
+ if should_sample
562
+ t1 = Process.clock_gettime(Process::CLOCK_MONOTONIC)
563
+ end
564
+
565
+ unless return_value.is_a?(return_type)
566
+ message = method_sig.return_type.error_message_for_obj(return_value)
567
+ if message
568
+ CallValidation.report_error(
569
+ method_sig,
570
+ message,
571
+ 'Return value',
572
+ nil,
573
+ method_sig.return_type,
574
+ return_value,
575
+ caller_offset: -1
576
+ )
577
+ end
578
+ end
579
+ if should_sample
580
+ T::Profile.typecheck_duration += (Process.clock_gettime(Process::CLOCK_MONOTONIC) - t1)
581
+ end
582
+ return_value
583
+ end
584
+ end
585
+
586
+ def self.create_validator_method_fast4(mod, original_method, method_sig, return_type,
587
+ arg0_type, arg1_type, arg2_type, arg3_type)
588
+ mod.send(:define_method, method_sig.method_name) do |arg0, arg1, arg2, arg3, &blk|
589
+ # This block is called for every `sig`. It's critical to keep it fast and
590
+ # reduce number of allocations that happen here.
591
+ # This method is a manually sped-up version of more general code in `validate_call`
592
+
593
+ T::Profile.typecheck_sample_attempts -= 1
594
+ should_sample = T::Profile.typecheck_sample_attempts == 0
595
+ if should_sample
596
+ T::Profile.typecheck_sample_attempts = T::Profile::SAMPLE_RATE
597
+ T::Profile.typecheck_samples += 1
598
+ t1 = Process.clock_gettime(Process::CLOCK_MONOTONIC)
599
+ end
600
+
601
+ if method_sig.bind
602
+ message = method_sig.bind.error_message_for_obj(self)
603
+ if message
604
+ CallValidation.report_error(
605
+ method_sig,
606
+ message,
607
+ 'Bind',
608
+ nil,
609
+ method_sig.bind,
610
+ self
611
+ )
612
+ end
613
+ end
614
+
615
+ unless arg0.is_a?(arg0_type)
616
+ CallValidation.report_error(
617
+ method_sig,
618
+ method_sig.arg_types[0][1].error_message_for_obj(arg0),
619
+ 'Parameter',
620
+ method_sig.arg_types[0][0],
621
+ arg0_type,
622
+ arg0,
623
+ caller_offset: -1
624
+ )
625
+ end
626
+
627
+ unless arg1.is_a?(arg1_type)
628
+ CallValidation.report_error(
629
+ method_sig,
630
+ method_sig.arg_types[1][1].error_message_for_obj(arg1),
631
+ 'Parameter',
632
+ method_sig.arg_types[1][0],
633
+ arg1_type,
634
+ arg1,
635
+ caller_offset: -1
636
+ )
637
+ end
638
+
639
+ unless arg2.is_a?(arg2_type)
640
+ CallValidation.report_error(
641
+ method_sig,
642
+ method_sig.arg_types[2][1].error_message_for_obj(arg2),
643
+ 'Parameter',
644
+ method_sig.arg_types[2][0],
645
+ arg2_type,
646
+ arg2,
647
+ caller_offset: -1
648
+ )
649
+ end
650
+
651
+ unless arg3.is_a?(arg3_type)
652
+ CallValidation.report_error(
653
+ method_sig,
654
+ method_sig.arg_types[3][1].error_message_for_obj(arg3),
655
+ 'Parameter',
656
+ method_sig.arg_types[3][0],
657
+ arg3_type,
658
+ arg3,
659
+ caller_offset: -1
660
+ )
661
+ end
662
+
663
+ if should_sample
664
+ T::Profile.typecheck_duration += (Process.clock_gettime(Process::CLOCK_MONOTONIC) - t1)
665
+ end
666
+
667
+ # The following line breaks are intentional to show nice pry message
668
+
669
+
670
+
671
+
672
+
673
+
674
+
675
+
676
+
677
+
678
+ # PRY note:
679
+ # this code is sig validation code.
680
+ # Please issue `finish` to step out of it
681
+
682
+ return_value = original_method.bind(self).call(arg0, arg1, arg2, arg3, &blk)
683
+ if should_sample
684
+ t1 = Process.clock_gettime(Process::CLOCK_MONOTONIC)
685
+ end
686
+
687
+ unless return_value.is_a?(return_type)
688
+ message = method_sig.return_type.error_message_for_obj(return_value)
689
+ if message
690
+ CallValidation.report_error(
691
+ method_sig,
692
+ message,
693
+ 'Return value',
694
+ nil,
695
+ method_sig.return_type,
696
+ return_value,
697
+ caller_offset: -1
698
+ )
699
+ end
700
+ end
701
+
702
+ if should_sample
703
+ T::Profile.typecheck_duration += (Process.clock_gettime(Process::CLOCK_MONOTONIC) - t1)
704
+ end
705
+ return_value
706
+ end
707
+ end
708
+
709
+ def self.create_validator_procedure_fast(mod, original_method, method_sig)
710
+ # trampoline to reduce stack frame size
711
+ if method_sig.arg_types.length == 0
712
+ create_validator_procedure_fast0(mod, original_method, method_sig)
713
+ elsif method_sig.arg_types.length == 1
714
+ create_validator_procedure_fast1(mod, original_method, method_sig,
715
+ method_sig.arg_types[0][1].raw_type)
716
+ elsif method_sig.arg_types.length == 2
717
+ create_validator_procedure_fast2(mod, original_method, method_sig,
718
+ method_sig.arg_types[0][1].raw_type,
719
+ method_sig.arg_types[1][1].raw_type)
720
+ elsif method_sig.arg_types.length == 3
721
+ create_validator_procedure_fast3(mod, original_method, method_sig,
722
+ method_sig.arg_types[0][1].raw_type,
723
+ method_sig.arg_types[1][1].raw_type,
724
+ method_sig.arg_types[2][1].raw_type)
725
+ elsif method_sig.arg_types.length == 4
726
+ create_validator_procedure_fast4(mod, original_method, method_sig,
727
+ method_sig.arg_types[0][1].raw_type,
728
+ method_sig.arg_types[1][1].raw_type,
729
+ method_sig.arg_types[2][1].raw_type,
730
+ method_sig.arg_types[3][1].raw_type)
731
+ else
732
+ raise "should not happen"
733
+ end
734
+ end
735
+
736
+ def self.create_validator_procedure_fast0(mod, original_method, method_sig)
737
+ mod.send(:define_method, method_sig.method_name) do |&blk|
738
+ # This block is called for every `sig`. It's critical to keep it fast and
739
+ # reduce number of allocations that happen here.
740
+ # This method is a manually sped-up version of more general code in `validate_call`
741
+
742
+ T::Profile.typecheck_sample_attempts -= 1
743
+ should_sample = T::Profile.typecheck_sample_attempts == 0
744
+ if should_sample
745
+ T::Profile.typecheck_sample_attempts = T::Profile::SAMPLE_RATE
746
+ T::Profile.typecheck_samples += 1
747
+ t1 = Process.clock_gettime(Process::CLOCK_MONOTONIC)
748
+ end
749
+
750
+ if method_sig.bind
751
+ message = method_sig.bind.error_message_for_obj(self)
752
+ if message
753
+ CallValidation.report_error(
754
+ method_sig,
755
+ message,
756
+ 'Bind',
757
+ nil,
758
+ method_sig.bind,
759
+ self
760
+ )
761
+ end
762
+ end
763
+
764
+ if should_sample
765
+ T::Profile.typecheck_duration += (Process.clock_gettime(Process::CLOCK_MONOTONIC) - t1)
766
+ end
767
+
768
+ # The following line breaks are intentional to show nice pry message
769
+
770
+
771
+
772
+
773
+
774
+
775
+
776
+
777
+
778
+
779
+ # PRY note:
780
+ # this code is sig validation code.
781
+ # Please issue `finish` to step out of it
782
+
783
+ original_method.bind(self).call(&blk)
784
+ T::Private::Types::Void::VOID
785
+ end
786
+ end
787
+
788
+ def self.create_validator_procedure_fast1(mod, original_method, method_sig, arg0_type)
789
+
790
+ mod.send(:define_method, method_sig.method_name) do |arg0, &blk|
791
+ # This block is called for every `sig`. It's critical to keep it fast and
792
+ # reduce number of allocations that happen here.
793
+ # This method is a manually sped-up version of more general code in `validate_call`
794
+
795
+ T::Profile.typecheck_sample_attempts -= 1
796
+ should_sample = T::Profile.typecheck_sample_attempts == 0
797
+ if should_sample
798
+ T::Profile.typecheck_sample_attempts = T::Profile::SAMPLE_RATE
799
+ T::Profile.typecheck_samples += 1
800
+ t1 = Process.clock_gettime(Process::CLOCK_MONOTONIC)
801
+ end
802
+
803
+ if method_sig.bind
804
+ message = method_sig.bind.error_message_for_obj(self)
805
+ if message
806
+ CallValidation.report_error(
807
+ method_sig,
808
+ message,
809
+ 'Bind',
810
+ nil,
811
+ method_sig.bind,
812
+ self
813
+ )
814
+ end
815
+ end
816
+
817
+ unless arg0.is_a?(arg0_type)
818
+ CallValidation.report_error(
819
+ method_sig,
820
+ method_sig.arg_types[0][1].error_message_for_obj(arg0),
821
+ 'Parameter',
822
+ method_sig.arg_types[0][0],
823
+ arg0_type,
824
+ arg0,
825
+ caller_offset: -1
826
+ )
827
+ end
828
+
829
+ if should_sample
830
+ T::Profile.typecheck_duration += (Process.clock_gettime(Process::CLOCK_MONOTONIC) - t1)
831
+ end
832
+
833
+ # The following line breaks are intentional to show nice pry message
834
+
835
+
836
+
837
+
838
+
839
+
840
+
841
+
842
+
843
+
844
+ # PRY note:
845
+ # this code is sig validation code.
846
+ # Please issue `finish` to step out of it
847
+ original_method.bind(self).call(arg0, &blk)
848
+ T::Private::Types::Void::VOID
849
+ end
850
+ end
851
+
852
+ def self.create_validator_procedure_fast2(mod, original_method, method_sig, arg0_type, arg1_type)
853
+ mod.send(:define_method, method_sig.method_name) do |arg0, arg1, &blk|
854
+ # This block is called for every `sig`. It's critical to keep it fast and
855
+ # reduce number of allocations that happen here.
856
+ # This method is a manually sped-up version of more general code in `validate_call`
857
+
858
+ T::Profile.typecheck_sample_attempts -= 1
859
+ should_sample = T::Profile.typecheck_sample_attempts == 0
860
+ if should_sample
861
+ T::Profile.typecheck_sample_attempts = T::Profile::SAMPLE_RATE
862
+ T::Profile.typecheck_samples += 1
863
+ t1 = Process.clock_gettime(Process::CLOCK_MONOTONIC)
864
+ end
865
+
866
+ if method_sig.bind
867
+ message = method_sig.bind.error_message_for_obj(self)
868
+ if message
869
+ CallValidation.report_error(
870
+ method_sig,
871
+ message,
872
+ 'Bind',
873
+ nil,
874
+ method_sig.bind,
875
+ self
876
+ )
877
+ end
878
+ end
879
+
880
+ unless arg0.is_a?(arg0_type)
881
+ CallValidation.report_error(
882
+ method_sig,
883
+ method_sig.arg_types[0][1].error_message_for_obj(arg0),
884
+ 'Parameter',
885
+ method_sig.arg_types[0][0],
886
+ arg0_type,
887
+ arg0,
888
+ caller_offset: -1
889
+ )
890
+ end
891
+
892
+ unless arg1.is_a?(arg1_type)
893
+ CallValidation.report_error(
894
+ method_sig,
895
+ method_sig.arg_types[1][1].error_message_for_obj(arg1),
896
+ 'Parameter',
897
+ method_sig.arg_types[1][0],
898
+ arg1_type,
899
+ arg1,
900
+ caller_offset: -1
901
+ )
902
+ end
903
+
904
+ if should_sample
905
+ T::Profile.typecheck_duration += (Process.clock_gettime(Process::CLOCK_MONOTONIC) - t1)
906
+ end
907
+
908
+ # The following line breaks are intentional to show nice pry message
909
+
910
+
911
+
912
+
913
+
914
+
915
+
916
+
917
+
918
+
919
+ # PRY note:
920
+ # this code is sig validation code.
921
+ # Please issue `finish` to step out of it
922
+
923
+ original_method.bind(self).call(arg0, arg1, &blk)
924
+ T::Private::Types::Void::VOID
925
+ end
926
+ end
927
+
928
+ def self.create_validator_procedure_fast3(mod, original_method, method_sig, arg0_type, arg1_type, arg2_type)
929
+ mod.send(:define_method, method_sig.method_name) do |arg0, arg1, arg2, &blk|
930
+ # This block is called for every `sig`. It's critical to keep it fast and
931
+ # reduce number of allocations that happen here.
932
+ # This method is a manually sped-up version of more general code in `validate_call`
933
+
934
+ T::Profile.typecheck_sample_attempts -= 1
935
+ should_sample = T::Profile.typecheck_sample_attempts == 0
936
+ if should_sample
937
+ T::Profile.typecheck_sample_attempts = T::Profile::SAMPLE_RATE
938
+ T::Profile.typecheck_samples += 1
939
+ t1 = Process.clock_gettime(Process::CLOCK_MONOTONIC)
940
+ end
941
+
942
+ if method_sig.bind
943
+ message = method_sig.bind.error_message_for_obj(self)
944
+ if message
945
+ CallValidation.report_error(
946
+ method_sig,
947
+ message,
948
+ 'Bind',
949
+ nil,
950
+ method_sig.bind,
951
+ self
952
+ )
953
+ end
954
+ end
955
+
956
+ unless arg0.is_a?(arg0_type)
957
+ CallValidation.report_error(
958
+ method_sig,
959
+ method_sig.arg_types[0][1].error_message_for_obj(arg0),
960
+ 'Parameter',
961
+ method_sig.arg_types[0][0],
962
+ arg0_type,
963
+ arg0,
964
+ caller_offset: -1
965
+ )
966
+ end
967
+
968
+ unless arg1.is_a?(arg1_type)
969
+ CallValidation.report_error(
970
+ method_sig,
971
+ method_sig.arg_types[1][1].error_message_for_obj(arg1),
972
+ 'Parameter',
973
+ method_sig.arg_types[1][0],
974
+ arg1_type,
975
+ arg1,
976
+ caller_offset: -1
977
+ )
978
+ end
979
+
980
+ unless arg2.is_a?(arg2_type)
981
+ CallValidation.report_error(
982
+ method_sig,
983
+ method_sig.arg_types[2][1].error_message_for_obj(arg2),
984
+ 'Parameter',
985
+ method_sig.arg_types[2][0],
986
+ arg2_type,
987
+ arg2,
988
+ caller_offset: -1
989
+ )
990
+ end
991
+
992
+ if should_sample
993
+ T::Profile.typecheck_duration += (Process.clock_gettime(Process::CLOCK_MONOTONIC) - t1)
994
+ end
995
+
996
+ # The following line breaks are intentional to show nice pry message
997
+
998
+
999
+
1000
+
1001
+
1002
+
1003
+
1004
+
1005
+
1006
+
1007
+ # PRY note:
1008
+ # this code is sig validation code.
1009
+ # Please issue `finish` to step out of it
1010
+
1011
+ original_method.bind(self).call(arg0, arg1, arg2, &blk)
1012
+ T::Private::Types::Void::VOID
1013
+ end
1014
+ end
1015
+
1016
+ def self.create_validator_procedure_fast4(mod, original_method, method_sig,
1017
+ arg0_type, arg1_type, arg2_type, arg3_type)
1018
+ mod.send(:define_method, method_sig.method_name) do |arg0, arg1, arg2, arg3, &blk|
1019
+ # This block is called for every `sig`. It's critical to keep it fast and
1020
+ # reduce number of allocations that happen here.
1021
+ # This method is a manually sped-up version of more general code in `validate_call`
1022
+
1023
+ T::Profile.typecheck_sample_attempts -= 1
1024
+ should_sample = T::Profile.typecheck_sample_attempts == 0
1025
+ if should_sample
1026
+ T::Profile.typecheck_sample_attempts = T::Profile::SAMPLE_RATE
1027
+ T::Profile.typecheck_samples += 1
1028
+ t1 = Process.clock_gettime(Process::CLOCK_MONOTONIC)
1029
+ end
1030
+
1031
+ if method_sig.bind
1032
+ message = method_sig.bind.error_message_for_obj(self)
1033
+ if message
1034
+ CallValidation.report_error(
1035
+ method_sig,
1036
+ message,
1037
+ 'Bind',
1038
+ nil,
1039
+ method_sig.bind,
1040
+ self
1041
+ )
1042
+ end
1043
+ end
1044
+
1045
+ unless arg0.is_a?(arg0_type)
1046
+ CallValidation.report_error(
1047
+ method_sig,
1048
+ method_sig.arg_types[0][1].error_message_for_obj(arg0),
1049
+ 'Parameter',
1050
+ method_sig.arg_types[0][0],
1051
+ arg0_type,
1052
+ arg0,
1053
+ caller_offset: -1
1054
+ )
1055
+ end
1056
+
1057
+ unless arg1.is_a?(arg1_type)
1058
+ CallValidation.report_error(
1059
+ method_sig,
1060
+ method_sig.arg_types[1][1].error_message_for_obj(arg1),
1061
+ 'Parameter',
1062
+ method_sig.arg_types[1][0],
1063
+ arg1_type,
1064
+ arg1,
1065
+ caller_offset: -1
1066
+ )
1067
+ end
1068
+
1069
+ unless arg2.is_a?(arg2_type)
1070
+ CallValidation.report_error(
1071
+ method_sig,
1072
+ method_sig.arg_types[2][1].error_message_for_obj(arg2),
1073
+ 'Parameter',
1074
+ method_sig.arg_types[2][0],
1075
+ arg2_type,
1076
+ arg2,
1077
+ caller_offset: -1
1078
+ )
1079
+ end
1080
+
1081
+ unless arg3.is_a?(arg3_type)
1082
+ CallValidation.report_error(
1083
+ method_sig,
1084
+ method_sig.arg_types[3][1].error_message_for_obj(arg3),
1085
+ 'Parameter',
1086
+ method_sig.arg_types[3][0],
1087
+ arg3_type,
1088
+ arg3,
1089
+ caller_offset: -1
1090
+ )
1091
+ end
1092
+
1093
+ if should_sample
1094
+ T::Profile.typecheck_duration += (Process.clock_gettime(Process::CLOCK_MONOTONIC) - t1)
1095
+ end
1096
+
1097
+ # The following line breaks are intentional to show nice pry message
1098
+
1099
+
1100
+
1101
+
1102
+
1103
+
1104
+
1105
+
1106
+
1107
+
1108
+ # PRY note:
1109
+ # this code is sig validation code.
1110
+ # Please issue `finish` to step out of it
1111
+
1112
+ original_method.bind(self).call(arg0, arg1, arg2, arg3, &blk)
1113
+ T::Private::Types::Void::VOID
1114
+ end
1115
+ end
1116
+
1117
+ def self.report_error(method_sig, error_message, kind, name, type, value, caller_offset: 0)
1118
+ caller_loc = T.must(caller_locations(3 + caller_offset, 1))[0]
1119
+ definition_file, definition_line = method_sig.method.source_location
1120
+
1121
+ pretty_message = "#{kind}#{name ? " '#{name}'" : ''}: #{error_message}\n" \
1122
+ "Caller: #{caller_loc.path}:#{caller_loc.lineno}\n" \
1123
+ "Definition: #{definition_file}:#{definition_line}"
1124
+
1125
+ T::Configuration.call_validation_error_handler(
1126
+ method_sig,
1127
+ message: error_message,
1128
+ pretty_message: pretty_message,
1129
+ kind: kind,
1130
+ name: name,
1131
+ type: type,
1132
+ value: value,
1133
+ location: caller_loc
1134
+ )
1135
+ end
1136
+
1137
+ # `name` must be an instance method (for class methods, pass in mod.singleton_class)
1138
+ private_class_method def self.visibility_method_name(mod, name)
1139
+ if mod.public_method_defined?(name)
1140
+ :public
1141
+ elsif mod.protected_method_defined?(name)
1142
+ :protected
1143
+ elsif mod.private_method_defined?(name)
1144
+ :private
1145
+ else
1146
+ raise NameError.new("undefined method `#{name}` for `#{mod}`")
1147
+ end
1148
+ end
1149
+ end