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.
- checksums.yaml +7 -0
- data/lib/sorbet-runtime.rb +116 -0
- data/lib/types/_types.rb +285 -0
- data/lib/types/abstract_utils.rb +50 -0
- data/lib/types/boolean.rb +8 -0
- data/lib/types/compatibility_patches.rb +95 -0
- data/lib/types/configuration.rb +428 -0
- data/lib/types/enum.rb +349 -0
- data/lib/types/generic.rb +23 -0
- data/lib/types/helpers.rb +39 -0
- data/lib/types/interface_wrapper.rb +158 -0
- data/lib/types/non_forcing_constants.rb +51 -0
- data/lib/types/private/abstract/data.rb +36 -0
- data/lib/types/private/abstract/declare.rb +48 -0
- data/lib/types/private/abstract/hooks.rb +43 -0
- data/lib/types/private/abstract/validate.rb +128 -0
- data/lib/types/private/casts.rb +22 -0
- data/lib/types/private/class_utils.rb +111 -0
- data/lib/types/private/decl_state.rb +30 -0
- data/lib/types/private/final.rb +51 -0
- data/lib/types/private/methods/_methods.rb +460 -0
- data/lib/types/private/methods/call_validation.rb +1149 -0
- data/lib/types/private/methods/decl_builder.rb +228 -0
- data/lib/types/private/methods/modes.rb +16 -0
- data/lib/types/private/methods/signature.rb +196 -0
- data/lib/types/private/methods/signature_validation.rb +229 -0
- data/lib/types/private/mixins/mixins.rb +27 -0
- data/lib/types/private/retry.rb +10 -0
- data/lib/types/private/runtime_levels.rb +56 -0
- data/lib/types/private/sealed.rb +65 -0
- data/lib/types/private/types/not_typed.rb +23 -0
- data/lib/types/private/types/string_holder.rb +26 -0
- data/lib/types/private/types/type_alias.rb +26 -0
- data/lib/types/private/types/void.rb +34 -0
- data/lib/types/profile.rb +31 -0
- data/lib/types/props/_props.rb +161 -0
- data/lib/types/props/constructor.rb +40 -0
- data/lib/types/props/custom_type.rb +108 -0
- data/lib/types/props/decorator.rb +672 -0
- data/lib/types/props/errors.rb +8 -0
- data/lib/types/props/generated_code_validation.rb +268 -0
- data/lib/types/props/has_lazily_specialized_methods.rb +92 -0
- data/lib/types/props/optional.rb +81 -0
- data/lib/types/props/plugin.rb +37 -0
- data/lib/types/props/pretty_printable.rb +107 -0
- data/lib/types/props/private/apply_default.rb +170 -0
- data/lib/types/props/private/deserializer_generator.rb +165 -0
- data/lib/types/props/private/parser.rb +32 -0
- data/lib/types/props/private/serde_transform.rb +192 -0
- data/lib/types/props/private/serializer_generator.rb +77 -0
- data/lib/types/props/private/setter_factory.rb +134 -0
- data/lib/types/props/serializable.rb +330 -0
- data/lib/types/props/type_validation.rb +111 -0
- data/lib/types/props/utils.rb +59 -0
- data/lib/types/props/weak_constructor.rb +67 -0
- data/lib/types/runtime_profiled.rb +24 -0
- data/lib/types/sig.rb +30 -0
- data/lib/types/struct.rb +18 -0
- data/lib/types/types/attached_class.rb +37 -0
- data/lib/types/types/base.rb +151 -0
- data/lib/types/types/class_of.rb +38 -0
- data/lib/types/types/enum.rb +42 -0
- data/lib/types/types/fixed_array.rb +60 -0
- data/lib/types/types/fixed_hash.rb +59 -0
- data/lib/types/types/intersection.rb +37 -0
- data/lib/types/types/noreturn.rb +29 -0
- data/lib/types/types/proc.rb +51 -0
- data/lib/types/types/self_type.rb +35 -0
- data/lib/types/types/simple.rb +33 -0
- data/lib/types/types/t_enum.rb +38 -0
- data/lib/types/types/type_member.rb +7 -0
- data/lib/types/types/type_parameter.rb +23 -0
- data/lib/types/types/type_template.rb +7 -0
- data/lib/types/types/type_variable.rb +31 -0
- data/lib/types/types/typed_array.rb +34 -0
- data/lib/types/types/typed_enumerable.rb +161 -0
- data/lib/types/types/typed_enumerator.rb +36 -0
- data/lib/types/types/typed_hash.rb +43 -0
- data/lib/types/types/typed_range.rb +26 -0
- data/lib/types/types/typed_set.rb +36 -0
- data/lib/types/types/union.rb +56 -0
- data/lib/types/types/untyped.rb +29 -0
- data/lib/types/utils.rb +217 -0
- 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
|