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,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