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,1177 @@
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
+ # get all the shims out of the way and put back the original method
39
+ mod.send(:define_method, method_sig.method_name, original_method)
40
+ mod.send(original_visibility, method_sig.method_name)
41
+ end
42
+ # Return the newly created method (or the original one if we didn't replace it)
43
+ mod.instance_method(method_sig.method_name)
44
+ end
45
+
46
+ def self.validate_call(instance, original_method, method_sig, args, blk)
47
+ # This method is called for every `sig`. It's critical to keep it fast and
48
+ # reduce number of allocations that happen here.
49
+
50
+ if method_sig.ever_failed && method_sig.generated
51
+ return original_method.bind(instance).call(*args, &blk)
52
+ end
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
+ if has_fixed_arity && has_simple_method_types && method_sig.arg_types.length < 5 && is_allowed_to_have_fast_path
171
+ create_validator_method_fast(mod, original_method, method_sig)
172
+ elsif has_fixed_arity && has_simple_procedure_types && method_sig.arg_types.length < 5 && is_allowed_to_have_fast_path
173
+ create_validator_procedure_fast(mod, original_method, method_sig)
174
+ else
175
+ create_validator_slow(mod, original_method, method_sig)
176
+ end
177
+ mod.send(original_visibility, method_sig.method_name)
178
+ end
179
+
180
+ def self.create_validator_slow(mod, original_method, method_sig)
181
+ mod.send(:define_method, method_sig.method_name) do |*args, &blk|
182
+ CallValidation.validate_call(self, original_method, method_sig, args, blk)
183
+ end
184
+ end
185
+
186
+ def self.create_validator_method_fast(mod, original_method, method_sig)
187
+ if method_sig.return_type.is_a?(T::Private::Types::Void)
188
+ raise "Should have used create_validator_procedure_fast"
189
+ end
190
+ # trampoline to reduce stack frame size
191
+ if method_sig.arg_types.length == 0
192
+ create_validator_method_fast0(mod, original_method, method_sig, method_sig.return_type.raw_type)
193
+ elsif method_sig.arg_types.length == 1
194
+ create_validator_method_fast1(mod, original_method, method_sig, method_sig.return_type.raw_type,
195
+ method_sig.arg_types[0][1].raw_type)
196
+ elsif method_sig.arg_types.length == 2
197
+ create_validator_method_fast2(mod, original_method, method_sig, method_sig.return_type.raw_type,
198
+ method_sig.arg_types[0][1].raw_type,
199
+ method_sig.arg_types[1][1].raw_type)
200
+ elsif method_sig.arg_types.length == 3
201
+ create_validator_method_fast3(mod, original_method, method_sig, method_sig.return_type.raw_type,
202
+ method_sig.arg_types[0][1].raw_type,
203
+ method_sig.arg_types[1][1].raw_type,
204
+ method_sig.arg_types[2][1].raw_type)
205
+ elsif method_sig.arg_types.length == 4
206
+ create_validator_method_fast4(mod, original_method, method_sig, method_sig.return_type.raw_type,
207
+ method_sig.arg_types[0][1].raw_type,
208
+ method_sig.arg_types[1][1].raw_type,
209
+ method_sig.arg_types[2][1].raw_type,
210
+ method_sig.arg_types[3][1].raw_type)
211
+ else
212
+ raise "should not happen"
213
+ end
214
+ end
215
+
216
+ def self.create_validator_method_fast0(mod, original_method, method_sig, return_type)
217
+ mod.send(:define_method, method_sig.method_name) do |&blk|
218
+ # This block is called for every `sig`. It's critical to keep it fast and
219
+ # reduce number of allocations that happen here.
220
+ # This method is a manually sped-up version of more general code in `validate_call`
221
+ T::Profile.typecheck_sample_attempts -= 1
222
+ should_sample = T::Profile.typecheck_sample_attempts == 0
223
+ if should_sample
224
+ T::Profile.typecheck_sample_attempts = T::Profile::SAMPLE_RATE
225
+ T::Profile.typecheck_samples += 1
226
+ t1 = Process.clock_gettime(Process::CLOCK_MONOTONIC)
227
+ end
228
+
229
+ if method_sig.bind
230
+ message = method_sig.bind.error_message_for_obj(self)
231
+ if message
232
+ CallValidation.report_error(
233
+ method_sig,
234
+ message,
235
+ 'Bind',
236
+ nil,
237
+ method_sig.bind,
238
+ self
239
+ )
240
+ end
241
+ end
242
+
243
+ if should_sample
244
+ T::Profile.typecheck_duration += (Process.clock_gettime(Process::CLOCK_MONOTONIC) - t1)
245
+ end
246
+
247
+ if method_sig.ever_failed && method_sig.generated
248
+ return original_method.bind(self).call(&blk)
249
+ end
250
+
251
+ # The following line breaks are intentional to show nice pry message
252
+
253
+
254
+
255
+
256
+
257
+
258
+
259
+
260
+
261
+
262
+ # PRY note:
263
+ # this code is sig validation code.
264
+ # Please issue `finish` to step out of it
265
+
266
+ return_value = original_method.bind(self).call(&blk)
267
+ if should_sample
268
+ t1 = Process.clock_gettime(Process::CLOCK_MONOTONIC)
269
+ end
270
+
271
+ unless return_value.is_a?(return_type)
272
+ message = method_sig.return_type.error_message_for_obj(return_value)
273
+ if message
274
+ CallValidation.report_error(
275
+ method_sig,
276
+ message,
277
+ 'Return value',
278
+ nil,
279
+ return_type,
280
+ return_value,
281
+ caller_offset: -1
282
+ )
283
+ end
284
+ end
285
+ if should_sample
286
+ T::Profile.typecheck_duration += (Process.clock_gettime(Process::CLOCK_MONOTONIC) - t1)
287
+ end
288
+ return_value
289
+ end
290
+ end
291
+
292
+ def self.create_validator_method_fast1(mod, original_method, method_sig, return_type, arg0_type)
293
+ mod.send(:define_method, method_sig.method_name) do |arg0, &blk|
294
+ # This block is called for every `sig`. It's critical to keep it fast and
295
+ # reduce number of allocations that happen here.
296
+ # This method is a manually sped-up version of more general code in `validate_call`
297
+
298
+ if method_sig.ever_failed && method_sig.generated
299
+ return original_method.bind(self).call(arg0, &blk)
300
+ end
301
+
302
+ T::Profile.typecheck_sample_attempts -= 1
303
+ should_sample = T::Profile.typecheck_sample_attempts == 0
304
+ if should_sample
305
+ T::Profile.typecheck_sample_attempts = T::Profile::SAMPLE_RATE
306
+ T::Profile.typecheck_samples += 1
307
+ t1 = Process.clock_gettime(Process::CLOCK_MONOTONIC)
308
+ end
309
+
310
+ if method_sig.bind
311
+ message = method_sig.bind.error_message_for_obj(self)
312
+ if message
313
+ CallValidation.report_error(
314
+ method_sig,
315
+ message,
316
+ 'Bind',
317
+ nil,
318
+ method_sig.bind,
319
+ self
320
+ )
321
+ end
322
+ end
323
+
324
+ unless arg0.is_a?(arg0_type)
325
+ CallValidation.report_error(
326
+ method_sig,
327
+ method_sig.arg_types[0][1].error_message_for_obj(arg0),
328
+ 'Parameter',
329
+ method_sig.arg_types[0][0],
330
+ arg0_type,
331
+ arg0,
332
+ caller_offset: -1
333
+ )
334
+ end
335
+
336
+ if should_sample
337
+ T::Profile.typecheck_duration += (Process.clock_gettime(Process::CLOCK_MONOTONIC) - t1)
338
+ end
339
+
340
+ # The following line breaks are intentional to show nice pry message
341
+
342
+
343
+
344
+
345
+
346
+
347
+
348
+
349
+
350
+
351
+ # PRY note:
352
+ # this code is sig validation code.
353
+ # Please issue `finish` to step out of it
354
+
355
+ return_value = original_method.bind(self).call(arg0, &blk)
356
+ if should_sample
357
+ t1 = Process.clock_gettime(Process::CLOCK_MONOTONIC)
358
+ end
359
+
360
+ unless return_value.is_a?(return_type)
361
+ message = method_sig.return_type.error_message_for_obj(return_value)
362
+ if message
363
+ CallValidation.report_error(
364
+ method_sig,
365
+ message,
366
+ 'Return value',
367
+ nil,
368
+ method_sig.return_type,
369
+ return_value,
370
+ caller_offset: -1
371
+ )
372
+ end
373
+ end
374
+ if should_sample
375
+ T::Profile.typecheck_duration += (Process.clock_gettime(Process::CLOCK_MONOTONIC) - t1)
376
+ end
377
+ return_value
378
+ end
379
+ end
380
+
381
+ def self.create_validator_method_fast2(mod, original_method, method_sig, return_type, arg0_type, arg1_type)
382
+ mod.send(:define_method, method_sig.method_name) do |arg0, arg1, &blk|
383
+ # This block is called for every `sig`. It's critical to keep it fast and
384
+ # reduce number of allocations that happen here.
385
+ # This method is a manually sped-up version of more general code in `validate_call`
386
+
387
+ if method_sig.ever_failed && method_sig.generated
388
+ return original_method.bind(self).call(arg0, arg1, &blk)
389
+ end
390
+
391
+ T::Profile.typecheck_sample_attempts -= 1
392
+ should_sample = T::Profile.typecheck_sample_attempts == 0
393
+ if should_sample
394
+ T::Profile.typecheck_sample_attempts = T::Profile::SAMPLE_RATE
395
+ T::Profile.typecheck_samples += 1
396
+ t1 = Process.clock_gettime(Process::CLOCK_MONOTONIC)
397
+ end
398
+
399
+ if method_sig.bind
400
+ message = method_sig.bind.error_message_for_obj(self)
401
+ if message
402
+ CallValidation.report_error(
403
+ method_sig,
404
+ message,
405
+ 'Bind',
406
+ nil,
407
+ method_sig.bind,
408
+ self
409
+ )
410
+ end
411
+ end
412
+
413
+ unless arg0.is_a?(arg0_type)
414
+ CallValidation.report_error(
415
+ method_sig,
416
+ method_sig.arg_types[0][1].error_message_for_obj(arg0),
417
+ 'Parameter',
418
+ method_sig.arg_types[0][0],
419
+ arg0_type,
420
+ arg0,
421
+ caller_offset: -1
422
+ )
423
+ end
424
+
425
+ unless arg1.is_a?(arg1_type)
426
+ CallValidation.report_error(
427
+ method_sig,
428
+ method_sig.arg_types[1][1].error_message_for_obj(arg1),
429
+ 'Parameter',
430
+ method_sig.arg_types[1][0],
431
+ arg1_type,
432
+ arg1,
433
+ caller_offset: -1
434
+ )
435
+ end
436
+
437
+ if should_sample
438
+ T::Profile.typecheck_duration += (Process.clock_gettime(Process::CLOCK_MONOTONIC) - t1)
439
+ end
440
+
441
+ # The following line breaks are intentional to show nice pry message
442
+
443
+
444
+
445
+
446
+
447
+
448
+
449
+
450
+
451
+
452
+ # PRY note:
453
+ # this code is sig validation code.
454
+ # Please issue `finish` to step out of it
455
+
456
+ return_value = original_method.bind(self).call(arg0, arg1, &blk)
457
+ if should_sample
458
+ t1 = Process.clock_gettime(Process::CLOCK_MONOTONIC)
459
+ end
460
+
461
+ unless return_value.is_a?(return_type)
462
+ message = method_sig.return_type.error_message_for_obj(return_value)
463
+ if message
464
+ CallValidation.report_error(
465
+ method_sig,
466
+ message,
467
+ 'Return value',
468
+ nil,
469
+ method_sig.return_type,
470
+ return_value,
471
+ caller_offset: -1
472
+ )
473
+ end
474
+ end
475
+ if should_sample
476
+ T::Profile.typecheck_duration += (Process.clock_gettime(Process::CLOCK_MONOTONIC) - t1)
477
+ end
478
+ return_value
479
+ end
480
+ end
481
+
482
+ def self.create_validator_method_fast3(mod, original_method, method_sig, return_type, arg0_type, arg1_type, arg2_type)
483
+ mod.send(:define_method, method_sig.method_name) do |arg0, arg1, arg2, &blk|
484
+ # This block is called for every `sig`. It's critical to keep it fast and
485
+ # reduce number of allocations that happen here.
486
+ # This method is a manually sped-up version of more general code in `validate_call`
487
+
488
+ if method_sig.ever_failed && method_sig.generated
489
+ return original_method.bind(self).call(arg0, arg1, arg2, &blk)
490
+ end
491
+
492
+ T::Profile.typecheck_sample_attempts -= 1
493
+ should_sample = T::Profile.typecheck_sample_attempts == 0
494
+ if should_sample
495
+ T::Profile.typecheck_sample_attempts = T::Profile::SAMPLE_RATE
496
+ T::Profile.typecheck_samples += 1
497
+ t1 = Process.clock_gettime(Process::CLOCK_MONOTONIC)
498
+ end
499
+
500
+ if method_sig.bind
501
+ message = method_sig.bind.error_message_for_obj(self)
502
+ if message
503
+ CallValidation.report_error(
504
+ method_sig,
505
+ message,
506
+ 'Bind',
507
+ nil,
508
+ method_sig.bind,
509
+ self
510
+ )
511
+ end
512
+ end
513
+
514
+ unless arg0.is_a?(arg0_type)
515
+ CallValidation.report_error(
516
+ method_sig,
517
+ method_sig.arg_types[0][1].error_message_for_obj(arg0),
518
+ 'Parameter',
519
+ method_sig.arg_types[0][0],
520
+ arg0_type,
521
+ arg0,
522
+ caller_offset: -1
523
+ )
524
+ end
525
+
526
+ unless arg1.is_a?(arg1_type)
527
+ CallValidation.report_error(
528
+ method_sig,
529
+ method_sig.arg_types[1][1].error_message_for_obj(arg1),
530
+ 'Parameter',
531
+ method_sig.arg_types[1][0],
532
+ arg1_type,
533
+ arg1,
534
+ caller_offset: -1
535
+ )
536
+ end
537
+
538
+ unless arg2.is_a?(arg2_type)
539
+ CallValidation.report_error(
540
+ method_sig,
541
+ method_sig.arg_types[2][1].error_message_for_obj(arg2),
542
+ 'Parameter',
543
+ method_sig.arg_types[2][0],
544
+ arg2_type,
545
+ arg2,
546
+ caller_offset: -1
547
+ )
548
+ end
549
+
550
+ if should_sample
551
+ T::Profile.typecheck_duration += (Process.clock_gettime(Process::CLOCK_MONOTONIC) - t1)
552
+ end
553
+
554
+ # The following line breaks are intentional to show nice pry message
555
+
556
+
557
+
558
+
559
+
560
+
561
+
562
+
563
+
564
+
565
+ # PRY note:
566
+ # this code is sig validation code.
567
+ # Please issue `finish` to step out of it
568
+
569
+ return_value = original_method.bind(self).call(arg0, arg1, arg2, &blk)
570
+ if should_sample
571
+ t1 = Process.clock_gettime(Process::CLOCK_MONOTONIC)
572
+ end
573
+
574
+ unless return_value.is_a?(return_type)
575
+ message = method_sig.return_type.error_message_for_obj(return_value)
576
+ if message
577
+ CallValidation.report_error(
578
+ method_sig,
579
+ message,
580
+ 'Return value',
581
+ nil,
582
+ method_sig.return_type,
583
+ return_value,
584
+ caller_offset: -1
585
+ )
586
+ end
587
+ end
588
+ if should_sample
589
+ T::Profile.typecheck_duration += (Process.clock_gettime(Process::CLOCK_MONOTONIC) - t1)
590
+ end
591
+ return_value
592
+ end
593
+ end
594
+
595
+ def self.create_validator_method_fast4(mod, original_method, method_sig, return_type,
596
+ arg0_type, arg1_type, arg2_type, arg3_type)
597
+ mod.send(:define_method, method_sig.method_name) do |arg0, arg1, arg2, arg3, &blk|
598
+ # This block is called for every `sig`. It's critical to keep it fast and
599
+ # reduce number of allocations that happen here.
600
+ # This method is a manually sped-up version of more general code in `validate_call`
601
+
602
+ if method_sig.ever_failed && method_sig.generated
603
+ return original_method.bind(self).call(arg0, arg1, arg2, arg3, &blk)
604
+ end
605
+
606
+ T::Profile.typecheck_sample_attempts -= 1
607
+ should_sample = T::Profile.typecheck_sample_attempts == 0
608
+ if should_sample
609
+ T::Profile.typecheck_sample_attempts = T::Profile::SAMPLE_RATE
610
+ T::Profile.typecheck_samples += 1
611
+ t1 = Process.clock_gettime(Process::CLOCK_MONOTONIC)
612
+ end
613
+
614
+ if method_sig.bind
615
+ message = method_sig.bind.error_message_for_obj(self)
616
+ if message
617
+ CallValidation.report_error(
618
+ method_sig,
619
+ message,
620
+ 'Bind',
621
+ nil,
622
+ method_sig.bind,
623
+ self
624
+ )
625
+ end
626
+ end
627
+
628
+ unless arg0.is_a?(arg0_type)
629
+ CallValidation.report_error(
630
+ method_sig,
631
+ method_sig.arg_types[0][1].error_message_for_obj(arg0),
632
+ 'Parameter',
633
+ method_sig.arg_types[0][0],
634
+ arg0_type,
635
+ arg0,
636
+ caller_offset: -1
637
+ )
638
+ end
639
+
640
+ unless arg1.is_a?(arg1_type)
641
+ CallValidation.report_error(
642
+ method_sig,
643
+ method_sig.arg_types[1][1].error_message_for_obj(arg1),
644
+ 'Parameter',
645
+ method_sig.arg_types[1][0],
646
+ arg1_type,
647
+ arg1,
648
+ caller_offset: -1
649
+ )
650
+ end
651
+
652
+ unless arg2.is_a?(arg2_type)
653
+ CallValidation.report_error(
654
+ method_sig,
655
+ method_sig.arg_types[2][1].error_message_for_obj(arg2),
656
+ 'Parameter',
657
+ method_sig.arg_types[2][0],
658
+ arg2_type,
659
+ arg2,
660
+ caller_offset: -1
661
+ )
662
+ end
663
+
664
+ unless arg3.is_a?(arg3_type)
665
+ CallValidation.report_error(
666
+ method_sig,
667
+ method_sig.arg_types[3][1].error_message_for_obj(arg3),
668
+ 'Parameter',
669
+ method_sig.arg_types[3][0],
670
+ arg3_type,
671
+ arg3,
672
+ caller_offset: -1
673
+ )
674
+ end
675
+
676
+ if should_sample
677
+ T::Profile.typecheck_duration += (Process.clock_gettime(Process::CLOCK_MONOTONIC) - t1)
678
+ end
679
+
680
+ # The following line breaks are intentional to show nice pry message
681
+
682
+
683
+
684
+
685
+
686
+
687
+
688
+
689
+
690
+
691
+ # PRY note:
692
+ # this code is sig validation code.
693
+ # Please issue `finish` to step out of it
694
+
695
+ return_value = original_method.bind(self).call(arg0, arg1, arg2, arg3, &blk)
696
+ if should_sample
697
+ t1 = Process.clock_gettime(Process::CLOCK_MONOTONIC)
698
+ end
699
+
700
+ unless return_value.is_a?(return_type)
701
+ message = method_sig.return_type.error_message_for_obj(return_value)
702
+ if message
703
+ CallValidation.report_error(
704
+ method_sig,
705
+ message,
706
+ 'Return value',
707
+ nil,
708
+ method_sig.return_type,
709
+ return_value,
710
+ caller_offset: -1
711
+ )
712
+ end
713
+ end
714
+
715
+ if should_sample
716
+ T::Profile.typecheck_duration += (Process.clock_gettime(Process::CLOCK_MONOTONIC) - t1)
717
+ end
718
+ return_value
719
+ end
720
+ end
721
+
722
+ def self.create_validator_procedure_fast(mod, original_method, method_sig)
723
+ # trampoline to reduce stack frame size
724
+ if method_sig.arg_types.length == 0
725
+ create_validator_procedure_fast0(mod, original_method, method_sig)
726
+ elsif method_sig.arg_types.length == 1
727
+ create_validator_procedure_fast1(mod, original_method, method_sig,
728
+ method_sig.arg_types[0][1].raw_type)
729
+ elsif method_sig.arg_types.length == 2
730
+ create_validator_procedure_fast2(mod, original_method, method_sig,
731
+ method_sig.arg_types[0][1].raw_type,
732
+ method_sig.arg_types[1][1].raw_type)
733
+ elsif method_sig.arg_types.length == 3
734
+ create_validator_procedure_fast3(mod, original_method, method_sig,
735
+ method_sig.arg_types[0][1].raw_type,
736
+ method_sig.arg_types[1][1].raw_type,
737
+ method_sig.arg_types[2][1].raw_type)
738
+ elsif method_sig.arg_types.length == 4
739
+ create_validator_procedure_fast4(mod, original_method, method_sig,
740
+ method_sig.arg_types[0][1].raw_type,
741
+ method_sig.arg_types[1][1].raw_type,
742
+ method_sig.arg_types[2][1].raw_type,
743
+ method_sig.arg_types[3][1].raw_type)
744
+ else
745
+ raise "should not happen"
746
+ end
747
+ end
748
+
749
+ def self.create_validator_procedure_fast0(mod, original_method, method_sig)
750
+ mod.send(:define_method, method_sig.method_name) do |&blk|
751
+ # This block is called for every `sig`. It's critical to keep it fast and
752
+ # reduce number of allocations that happen here.
753
+ # This method is a manually sped-up version of more general code in `validate_call`
754
+
755
+ if method_sig.ever_failed && method_sig.generated
756
+ return original_method.bind(self).call(&blk)
757
+ end
758
+
759
+ T::Profile.typecheck_sample_attempts -= 1
760
+ should_sample = T::Profile.typecheck_sample_attempts == 0
761
+ if should_sample
762
+ T::Profile.typecheck_sample_attempts = T::Profile::SAMPLE_RATE
763
+ T::Profile.typecheck_samples += 1
764
+ t1 = Process.clock_gettime(Process::CLOCK_MONOTONIC)
765
+ end
766
+
767
+ if method_sig.bind
768
+ message = method_sig.bind.error_message_for_obj(self)
769
+ if message
770
+ CallValidation.report_error(
771
+ method_sig,
772
+ message,
773
+ 'Bind',
774
+ nil,
775
+ method_sig.bind,
776
+ self
777
+ )
778
+ end
779
+ end
780
+
781
+ if should_sample
782
+ T::Profile.typecheck_duration += (Process.clock_gettime(Process::CLOCK_MONOTONIC) - t1)
783
+ end
784
+
785
+ # The following line breaks are intentional to show nice pry message
786
+
787
+
788
+
789
+
790
+
791
+
792
+
793
+
794
+
795
+
796
+ # PRY note:
797
+ # this code is sig validation code.
798
+ # Please issue `finish` to step out of it
799
+
800
+ original_method.bind(self).call(&blk)
801
+ T::Private::Types::Void::VOID
802
+ end
803
+ end
804
+
805
+ def self.create_validator_procedure_fast1(mod, original_method, method_sig, arg0_type)
806
+
807
+ mod.send(:define_method, method_sig.method_name) do |arg0, &blk|
808
+ # This block is called for every `sig`. It's critical to keep it fast and
809
+ # reduce number of allocations that happen here.
810
+ # This method is a manually sped-up version of more general code in `validate_call`
811
+
812
+ if method_sig.ever_failed && method_sig.generated
813
+ return original_method.bind(self).call(arg0, &blk)
814
+ end
815
+
816
+ T::Profile.typecheck_sample_attempts -= 1
817
+ should_sample = T::Profile.typecheck_sample_attempts == 0
818
+ if should_sample
819
+ T::Profile.typecheck_sample_attempts = T::Profile::SAMPLE_RATE
820
+ T::Profile.typecheck_samples += 1
821
+ t1 = Process.clock_gettime(Process::CLOCK_MONOTONIC)
822
+ end
823
+
824
+ if method_sig.bind
825
+ message = method_sig.bind.error_message_for_obj(self)
826
+ if message
827
+ CallValidation.report_error(
828
+ method_sig,
829
+ message,
830
+ 'Bind',
831
+ nil,
832
+ method_sig.bind,
833
+ self
834
+ )
835
+ end
836
+ end
837
+
838
+ unless arg0.is_a?(arg0_type)
839
+ CallValidation.report_error(
840
+ method_sig,
841
+ method_sig.arg_types[0][1].error_message_for_obj(arg0),
842
+ 'Parameter',
843
+ method_sig.arg_types[0][0],
844
+ arg0_type,
845
+ arg0,
846
+ caller_offset: -1
847
+ )
848
+ end
849
+
850
+ if should_sample
851
+ T::Profile.typecheck_duration += (Process.clock_gettime(Process::CLOCK_MONOTONIC) - t1)
852
+ end
853
+
854
+ # The following line breaks are intentional to show nice pry message
855
+
856
+
857
+
858
+
859
+
860
+
861
+
862
+
863
+
864
+
865
+ # PRY note:
866
+ # this code is sig validation code.
867
+ # Please issue `finish` to step out of it
868
+ original_method.bind(self).call(arg0, &blk)
869
+ T::Private::Types::Void::VOID
870
+ end
871
+ end
872
+
873
+ def self.create_validator_procedure_fast2(mod, original_method, method_sig, arg0_type, arg1_type)
874
+ mod.send(:define_method, method_sig.method_name) do |arg0, arg1, &blk|
875
+ # This block is called for every `sig`. It's critical to keep it fast and
876
+ # reduce number of allocations that happen here.
877
+ # This method is a manually sped-up version of more general code in `validate_call`
878
+
879
+ if method_sig.ever_failed && method_sig.generated
880
+ return original_method.bind(self).call(arg0, arg1, &blk)
881
+ end
882
+
883
+ T::Profile.typecheck_sample_attempts -= 1
884
+ should_sample = T::Profile.typecheck_sample_attempts == 0
885
+ if should_sample
886
+ T::Profile.typecheck_sample_attempts = T::Profile::SAMPLE_RATE
887
+ T::Profile.typecheck_samples += 1
888
+ t1 = Process.clock_gettime(Process::CLOCK_MONOTONIC)
889
+ end
890
+
891
+ if method_sig.bind
892
+ message = method_sig.bind.error_message_for_obj(self)
893
+ if message
894
+ CallValidation.report_error(
895
+ method_sig,
896
+ message,
897
+ 'Bind',
898
+ nil,
899
+ method_sig.bind,
900
+ self
901
+ )
902
+ end
903
+ end
904
+
905
+ unless arg0.is_a?(arg0_type)
906
+ CallValidation.report_error(
907
+ method_sig,
908
+ method_sig.arg_types[0][1].error_message_for_obj(arg0),
909
+ 'Parameter',
910
+ method_sig.arg_types[0][0],
911
+ arg0_type,
912
+ arg0,
913
+ caller_offset: -1
914
+ )
915
+ end
916
+
917
+ unless arg1.is_a?(arg1_type)
918
+ CallValidation.report_error(
919
+ method_sig,
920
+ method_sig.arg_types[1][1].error_message_for_obj(arg1),
921
+ 'Parameter',
922
+ method_sig.arg_types[1][0],
923
+ arg1_type,
924
+ arg1,
925
+ caller_offset: -1
926
+ )
927
+ end
928
+
929
+ if should_sample
930
+ T::Profile.typecheck_duration += (Process.clock_gettime(Process::CLOCK_MONOTONIC) - t1)
931
+ end
932
+
933
+ # The following line breaks are intentional to show nice pry message
934
+
935
+
936
+
937
+
938
+
939
+
940
+
941
+
942
+
943
+
944
+ # PRY note:
945
+ # this code is sig validation code.
946
+ # Please issue `finish` to step out of it
947
+
948
+ original_method.bind(self).call(arg0, arg1, &blk)
949
+ T::Private::Types::Void::VOID
950
+ end
951
+ end
952
+
953
+ def self.create_validator_procedure_fast3(mod, original_method, method_sig, arg0_type, arg1_type, arg2_type)
954
+ mod.send(:define_method, method_sig.method_name) do |arg0, arg1, arg2, &blk|
955
+ # This block is called for every `sig`. It's critical to keep it fast and
956
+ # reduce number of allocations that happen here.
957
+ # This method is a manually sped-up version of more general code in `validate_call`
958
+
959
+ if method_sig.ever_failed && method_sig.generated
960
+ return original_method.bind(self).call(arg0, arg1, arg2, &blk)
961
+ end
962
+
963
+ T::Profile.typecheck_sample_attempts -= 1
964
+ should_sample = T::Profile.typecheck_sample_attempts == 0
965
+ if should_sample
966
+ T::Profile.typecheck_sample_attempts = T::Profile::SAMPLE_RATE
967
+ T::Profile.typecheck_samples += 1
968
+ t1 = Process.clock_gettime(Process::CLOCK_MONOTONIC)
969
+ end
970
+
971
+ if method_sig.bind
972
+ message = method_sig.bind.error_message_for_obj(self)
973
+ if message
974
+ CallValidation.report_error(
975
+ method_sig,
976
+ message,
977
+ 'Bind',
978
+ nil,
979
+ method_sig.bind,
980
+ self
981
+ )
982
+ end
983
+ end
984
+
985
+ unless arg0.is_a?(arg0_type)
986
+ CallValidation.report_error(
987
+ method_sig,
988
+ method_sig.arg_types[0][1].error_message_for_obj(arg0),
989
+ 'Parameter',
990
+ method_sig.arg_types[0][0],
991
+ arg0_type,
992
+ arg0,
993
+ caller_offset: -1
994
+ )
995
+ end
996
+
997
+ unless arg1.is_a?(arg1_type)
998
+ CallValidation.report_error(
999
+ method_sig,
1000
+ method_sig.arg_types[1][1].error_message_for_obj(arg1),
1001
+ 'Parameter',
1002
+ method_sig.arg_types[1][0],
1003
+ arg1_type,
1004
+ arg1,
1005
+ caller_offset: -1
1006
+ )
1007
+ end
1008
+
1009
+ unless arg2.is_a?(arg2_type)
1010
+ CallValidation.report_error(
1011
+ method_sig,
1012
+ method_sig.arg_types[2][1].error_message_for_obj(arg2),
1013
+ 'Parameter',
1014
+ method_sig.arg_types[2][0],
1015
+ arg2_type,
1016
+ arg2,
1017
+ caller_offset: -1
1018
+ )
1019
+ end
1020
+
1021
+ if should_sample
1022
+ T::Profile.typecheck_duration += (Process.clock_gettime(Process::CLOCK_MONOTONIC) - t1)
1023
+ end
1024
+
1025
+ # The following line breaks are intentional to show nice pry message
1026
+
1027
+
1028
+
1029
+
1030
+
1031
+
1032
+
1033
+
1034
+
1035
+
1036
+ # PRY note:
1037
+ # this code is sig validation code.
1038
+ # Please issue `finish` to step out of it
1039
+
1040
+ original_method.bind(self).call(arg0, arg1, arg2, &blk)
1041
+ T::Private::Types::Void::VOID
1042
+ end
1043
+ end
1044
+
1045
+ def self.create_validator_procedure_fast4(mod, original_method, method_sig,
1046
+ arg0_type, arg1_type, arg2_type, arg3_type)
1047
+ mod.send(:define_method, method_sig.method_name) do |arg0, arg1, arg2, arg3, &blk|
1048
+ # This block is called for every `sig`. It's critical to keep it fast and
1049
+ # reduce number of allocations that happen here.
1050
+ # This method is a manually sped-up version of more general code in `validate_call`
1051
+
1052
+ if method_sig.ever_failed && method_sig.generated
1053
+ return original_method.bind(self).call(arg0, arg1, arg2, arg3, &blk)
1054
+ end
1055
+
1056
+ T::Profile.typecheck_sample_attempts -= 1
1057
+ should_sample = T::Profile.typecheck_sample_attempts == 0
1058
+ if should_sample
1059
+ T::Profile.typecheck_sample_attempts = T::Profile::SAMPLE_RATE
1060
+ T::Profile.typecheck_samples += 1
1061
+ t1 = Process.clock_gettime(Process::CLOCK_MONOTONIC)
1062
+ end
1063
+
1064
+ if method_sig.bind
1065
+ message = method_sig.bind.error_message_for_obj(self)
1066
+ if message
1067
+ CallValidation.report_error(
1068
+ method_sig,
1069
+ message,
1070
+ 'Bind',
1071
+ nil,
1072
+ method_sig.bind,
1073
+ self
1074
+ )
1075
+ end
1076
+ end
1077
+
1078
+ unless arg0.is_a?(arg0_type)
1079
+ CallValidation.report_error(
1080
+ method_sig,
1081
+ method_sig.arg_types[0][1].error_message_for_obj(arg0),
1082
+ 'Parameter',
1083
+ method_sig.arg_types[0][0],
1084
+ arg0_type,
1085
+ arg0,
1086
+ caller_offset: -1
1087
+ )
1088
+ end
1089
+
1090
+ unless arg1.is_a?(arg1_type)
1091
+ CallValidation.report_error(
1092
+ method_sig,
1093
+ method_sig.arg_types[1][1].error_message_for_obj(arg1),
1094
+ 'Parameter',
1095
+ method_sig.arg_types[1][0],
1096
+ arg1_type,
1097
+ arg1,
1098
+ caller_offset: -1
1099
+ )
1100
+ end
1101
+
1102
+ unless arg2.is_a?(arg2_type)
1103
+ CallValidation.report_error(
1104
+ method_sig,
1105
+ method_sig.arg_types[2][1].error_message_for_obj(arg2),
1106
+ 'Parameter',
1107
+ method_sig.arg_types[2][0],
1108
+ arg2_type,
1109
+ arg2,
1110
+ caller_offset: -1
1111
+ )
1112
+ end
1113
+
1114
+ unless arg3.is_a?(arg3_type)
1115
+ CallValidation.report_error(
1116
+ method_sig,
1117
+ method_sig.arg_types[3][1].error_message_for_obj(arg3),
1118
+ 'Parameter',
1119
+ method_sig.arg_types[3][0],
1120
+ arg3_type,
1121
+ arg3,
1122
+ caller_offset: -1
1123
+ )
1124
+ end
1125
+
1126
+ if should_sample
1127
+ T::Profile.typecheck_duration += (Process.clock_gettime(Process::CLOCK_MONOTONIC) - t1)
1128
+ end
1129
+
1130
+ # The following line breaks are intentional to show nice pry message
1131
+
1132
+
1133
+
1134
+
1135
+
1136
+
1137
+
1138
+
1139
+
1140
+
1141
+ # PRY note:
1142
+ # this code is sig validation code.
1143
+ # Please issue `finish` to step out of it
1144
+
1145
+ original_method.bind(self).call(arg0, arg1, arg2, arg3, &blk)
1146
+ T::Private::Types::Void::VOID
1147
+ end
1148
+ end
1149
+
1150
+ def self.report_error(method_sig, error_message, kind, name, type, value, caller_offset: 0)
1151
+ method_sig.mark_failed
1152
+ caller_loc = T.must(caller_locations(3 + caller_offset, 1))[0]
1153
+
1154
+ T::Private::ErrorHandler.handle_call_validation_error(
1155
+ method_sig,
1156
+ message: error_message,
1157
+ kind: kind,
1158
+ name: name,
1159
+ type: type,
1160
+ value: value,
1161
+ location: caller_loc
1162
+ )
1163
+ end
1164
+
1165
+ # `name` must be an instance method (for class methods, pass in mod.singleton_class)
1166
+ private_class_method def self.visibility_method_name(mod, name)
1167
+ if mod.public_method_defined?(name)
1168
+ :public
1169
+ elsif mod.protected_method_defined?(name)
1170
+ :protected
1171
+ elsif mod.private_method_defined?(name)
1172
+ :private
1173
+ else
1174
+ raise NameError.new("undefined method `#{name}` for `#{mod}`")
1175
+ end
1176
+ end
1177
+ end