sorbet-runtime 0.4.4667 → 0.5.6189
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/lib/sorbet-runtime.rb +15 -3
- data/lib/types/_types.rb +26 -17
- data/lib/types/boolean.rb +1 -1
- data/lib/types/compatibility_patches.rb +65 -10
- data/lib/types/configuration.rb +93 -7
- data/lib/types/enum.rb +371 -0
- data/lib/types/generic.rb +2 -2
- data/lib/types/interface_wrapper.rb +4 -4
- data/lib/types/non_forcing_constants.rb +61 -0
- data/lib/types/private/abstract/data.rb +2 -2
- data/lib/types/private/abstract/declare.rb +3 -0
- data/lib/types/private/abstract/validate.rb +7 -7
- data/lib/types/private/casts.rb +27 -0
- data/lib/types/private/class_utils.rb +8 -5
- data/lib/types/private/methods/_methods.rb +80 -28
- data/lib/types/private/methods/call_validation.rb +5 -47
- data/lib/types/private/methods/decl_builder.rb +14 -56
- data/lib/types/private/methods/modes.rb +5 -7
- data/lib/types/private/methods/signature.rb +32 -18
- data/lib/types/private/methods/signature_validation.rb +29 -35
- data/lib/types/private/retry.rb +10 -0
- data/lib/types/private/sealed.rb +21 -1
- data/lib/types/private/types/type_alias.rb +31 -0
- data/lib/types/private/types/void.rb +4 -3
- data/lib/types/profile.rb +5 -1
- data/lib/types/props/_props.rb +3 -7
- data/lib/types/props/constructor.rb +29 -9
- data/lib/types/props/custom_type.rb +51 -27
- data/lib/types/props/decorator.rb +248 -405
- 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 +37 -41
- data/lib/types/props/plugin.rb +23 -1
- data/lib/types/props/pretty_printable.rb +3 -3
- 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 +186 -0
- data/lib/types/props/private/serializer_generator.rb +77 -0
- data/lib/types/props/private/setter_factory.rb +139 -0
- data/lib/types/props/serializable.rb +137 -192
- data/lib/types/props/type_validation.rb +19 -6
- data/lib/types/props/utils.rb +3 -7
- data/lib/types/props/weak_constructor.rb +51 -14
- data/lib/types/sig.rb +6 -6
- data/lib/types/types/attached_class.rb +37 -0
- data/lib/types/types/base.rb +26 -2
- data/lib/types/types/fixed_array.rb +28 -2
- data/lib/types/types/fixed_hash.rb +11 -10
- data/lib/types/types/intersection.rb +6 -0
- data/lib/types/types/noreturn.rb +4 -0
- data/lib/types/types/self_type.rb +4 -0
- data/lib/types/types/simple.rb +22 -1
- data/lib/types/types/t_enum.rb +38 -0
- data/lib/types/types/type_parameter.rb +1 -1
- data/lib/types/types/type_variable.rb +1 -1
- data/lib/types/types/typed_array.rb +7 -2
- data/lib/types/types/typed_enumerable.rb +28 -17
- data/lib/types/types/typed_enumerator.rb +7 -2
- data/lib/types/types/typed_hash.rb +8 -3
- data/lib/types/types/typed_range.rb +7 -2
- data/lib/types/types/typed_set.rb +7 -2
- data/lib/types/types/union.rb +37 -5
- data/lib/types/types/untyped.rb +4 -0
- data/lib/types/utils.rb +43 -11
- metadata +103 -11
- data/lib/types/private/error_handler.rb +0 -0
- data/lib/types/runtime_profiled.rb +0 -24
- data/lib/types/types/opus_enum.rb +0 -33
data/lib/types/generic.rb
CHANGED
@@ -14,10 +14,10 @@ module T::Generic
|
|
14
14
|
end
|
15
15
|
|
16
16
|
def type_member(variance=:invariant, fixed: nil, lower: T.untyped, upper: BasicObject)
|
17
|
-
T::Types::TypeMember.new(variance)
|
17
|
+
T::Types::TypeMember.new(variance)
|
18
18
|
end
|
19
19
|
|
20
20
|
def type_template(variance=:invariant, fixed: nil, lower: T.untyped, upper: BasicObject)
|
21
|
-
T::Types::TypeTemplate.new(variance)
|
21
|
+
T::Types::TypeTemplate.new(variance)
|
22
22
|
end
|
23
23
|
end
|
@@ -83,11 +83,11 @@ class T::InterfaceWrapper
|
|
83
83
|
end
|
84
84
|
end
|
85
85
|
|
86
|
-
def kind_of?(other)
|
86
|
+
def kind_of?(other)
|
87
87
|
is_a?(other)
|
88
88
|
end
|
89
89
|
|
90
|
-
def is_a?(other)
|
90
|
+
def is_a?(other)
|
91
91
|
if !other.is_a?(Module)
|
92
92
|
raise TypeError.new("class or module required")
|
93
93
|
end
|
@@ -99,13 +99,13 @@ class T::InterfaceWrapper
|
|
99
99
|
|
100
100
|
# Prefixed because we're polluting the namespace of the interface we're wrapping, and we don't
|
101
101
|
# want anyone else (besides dynamic_cast) calling it.
|
102
|
-
def __target_obj_DO_NOT_USE
|
102
|
+
def __target_obj_DO_NOT_USE # rubocop:disable Naming/MethodName
|
103
103
|
@target_obj
|
104
104
|
end
|
105
105
|
|
106
106
|
# Prefixed because we're polluting the namespace of the interface we're wrapping, and we don't
|
107
107
|
# want anyone else (besides wrapped_dynamic_cast) calling it.
|
108
|
-
def __interface_mod_DO_NOT_USE
|
108
|
+
def __interface_mod_DO_NOT_USE # rubocop:disable Naming/MethodName
|
109
109
|
@interface_mod
|
110
110
|
end
|
111
111
|
|
@@ -0,0 +1,61 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
# typed: strict
|
3
|
+
|
4
|
+
module T::NonForcingConstants
|
5
|
+
# NOTE: This method is documented on the RBI in Sorbet's payload, so that it
|
6
|
+
# shows up in the hover/completion documentation via LSP.
|
7
|
+
T::Sig::WithoutRuntime.sig {params(val: BasicObject, klass: String, package: T.nilable(String)).returns(T::Boolean)}
|
8
|
+
def self.non_forcing_is_a?(val, klass, package: nil)
|
9
|
+
# TODO(gdritter): once we have a runtime implementation of
|
10
|
+
# packages, we'll need to actually handle the `package` argument
|
11
|
+
# here.
|
12
|
+
method_name = "T::NonForcingConstants.non_forcing_is_a?"
|
13
|
+
if klass.empty?
|
14
|
+
raise ArgumentError.new("The string given to `#{method_name}` must not be empty")
|
15
|
+
end
|
16
|
+
|
17
|
+
current_klass = T.let(nil, T.nilable(Module))
|
18
|
+
current_prefix = T.let(nil, T.nilable(String))
|
19
|
+
|
20
|
+
parts = klass.split('::')
|
21
|
+
parts.each do |part|
|
22
|
+
if current_klass.nil?
|
23
|
+
# First iteration
|
24
|
+
if part != "" && package.nil?
|
25
|
+
# if we've supplied a package, we're probably running in
|
26
|
+
# package mode, which means absolute references are
|
27
|
+
# meaningless
|
28
|
+
raise ArgumentError.new("The string given to `#{method_name}` must be an absolute constant reference that starts with `::`")
|
29
|
+
end
|
30
|
+
|
31
|
+
current_klass = Object
|
32
|
+
current_prefix = ''
|
33
|
+
|
34
|
+
# if this had a :: prefix, then there's no more loading to
|
35
|
+
# do---skip to the next one
|
36
|
+
next if part == ""
|
37
|
+
end
|
38
|
+
|
39
|
+
if current_klass.autoload?(part)
|
40
|
+
# There's an autoload registered for that constant, which means it's not
|
41
|
+
# yet loaded. `value` can't be an instance of something not yet loaded.
|
42
|
+
return false
|
43
|
+
end
|
44
|
+
|
45
|
+
# Sorbet guarantees that the string is an absolutely resolved name.
|
46
|
+
search_inheritance_chain = false
|
47
|
+
if !current_klass.const_defined?(part, search_inheritance_chain)
|
48
|
+
return false
|
49
|
+
end
|
50
|
+
|
51
|
+
current_klass = current_klass.const_get(part)
|
52
|
+
current_prefix = "#{current_prefix}::#{part}"
|
53
|
+
|
54
|
+
if !Module.===(current_klass)
|
55
|
+
raise ArgumentError.new("#{current_prefix} is not a class or module")
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
current_klass.===(val)
|
60
|
+
end
|
61
|
+
end
|
@@ -12,11 +12,11 @@
|
|
12
12
|
# modules that override the `hash` method with something completely broken.
|
13
13
|
module T::Private::Abstract::Data
|
14
14
|
def self.get(mod, key)
|
15
|
-
mod.instance_variable_get("@opus_abstract__#{key}")
|
15
|
+
mod.instance_variable_get("@opus_abstract__#{key}")
|
16
16
|
end
|
17
17
|
|
18
18
|
def self.set(mod, key, value)
|
19
|
-
mod.instance_variable_set("@opus_abstract__#{key}", value)
|
19
|
+
mod.instance_variable_set("@opus_abstract__#{key}", value)
|
20
20
|
end
|
21
21
|
|
22
22
|
def self.key?(mod, key)
|
@@ -61,7 +61,7 @@ module T::Private::Abstract::Validate
|
|
61
61
|
# In that case, get its untyped signature.
|
62
62
|
implementation_signature ||= Methods::Signature.new_untyped(
|
63
63
|
method: implementation_method,
|
64
|
-
mode: Methods::Modes.
|
64
|
+
mode: Methods::Modes.override
|
65
65
|
)
|
66
66
|
SignatureValidation.validate_override_shape(implementation_signature, abstract_signature)
|
67
67
|
SignatureValidation.validate_override_types(implementation_signature, abstract_signature)
|
@@ -111,16 +111,16 @@ module T::Private::Abstract::Validate
|
|
111
111
|
end
|
112
112
|
|
113
113
|
private_class_method def self.describe_method(method, show_owner: true)
|
114
|
-
if method.source_location
|
115
|
-
|
114
|
+
loc = if method.source_location
|
115
|
+
method.source_location.join(':')
|
116
116
|
else
|
117
|
-
|
117
|
+
"<unknown location>"
|
118
118
|
end
|
119
119
|
|
120
|
-
if show_owner
|
121
|
-
|
120
|
+
owner = if show_owner
|
121
|
+
" declared in #{method.owner}"
|
122
122
|
else
|
123
|
-
|
123
|
+
""
|
124
124
|
end
|
125
125
|
|
126
126
|
" * `#{method.name}`#{owner} at #{loc}"
|
data/lib/types/private/casts.rb
CHANGED
@@ -2,6 +2,14 @@
|
|
2
2
|
# typed: false
|
3
3
|
|
4
4
|
module T::Private
|
5
|
+
# Dynamically confirm that `value` is recursively a valid value of
|
6
|
+
# type `type`, including recursively through collections. Note that
|
7
|
+
# in some cases this runtime check can be very expensive, especially
|
8
|
+
# with large collections of objects.
|
9
|
+
def self.check_type_recursive!(value, type)
|
10
|
+
T::Private::Casts.cast_recursive(value, type, cast_method: "T.check_type_recursive!")
|
11
|
+
end
|
12
|
+
|
5
13
|
module Casts
|
6
14
|
def self.cast(value, type, cast_method:)
|
7
15
|
begin
|
@@ -18,5 +26,24 @@ module T::Private
|
|
18
26
|
value
|
19
27
|
end
|
20
28
|
end
|
29
|
+
|
30
|
+
# there's a lot of shared logic with the above one, but factoring
|
31
|
+
# it out like this makes it easier to hopefully one day delete
|
32
|
+
# this one
|
33
|
+
def self.cast_recursive(value, type, cast_method:)
|
34
|
+
begin
|
35
|
+
error = T::Utils.coerce(type).error_message_for_obj_recursive(value)
|
36
|
+
return value unless error
|
37
|
+
|
38
|
+
caller_loc = T.must(caller_locations(2..2)).first
|
39
|
+
|
40
|
+
suffix = "Caller: #{T.must(caller_loc).path}:#{T.must(caller_loc).lineno}"
|
41
|
+
|
42
|
+
raise TypeError.new("#{cast_method}: #{error}\n#{suffix}")
|
43
|
+
rescue TypeError => e # raise into rescue to ensure e.backtrace is populated
|
44
|
+
T::Configuration.inline_type_error_handler(e)
|
45
|
+
value
|
46
|
+
end
|
47
|
+
end
|
21
48
|
end
|
22
49
|
end
|
@@ -33,16 +33,16 @@ module T::Private::ClassUtils
|
|
33
33
|
if @overwritten
|
34
34
|
# The original method was overwritten. Overwrite again to restore it.
|
35
35
|
T::Configuration.without_ruby_warnings do
|
36
|
-
@mod.send(:define_method, @old_method.name, @old_method)
|
36
|
+
@mod.send(:define_method, @old_method.name, @old_method)
|
37
37
|
end
|
38
38
|
else
|
39
39
|
# The original method was in an ancestor. Restore it by removing the overriding method.
|
40
|
-
@mod.send(:remove_method, @old_method.name)
|
40
|
+
@mod.send(:remove_method, @old_method.name)
|
41
41
|
end
|
42
42
|
|
43
43
|
# Restore the visibility. Note that we need to do this even when we call remove_method
|
44
44
|
# above, because the module may have set custom visibility for a method it inherited.
|
45
|
-
@mod.send(@visibility, @old_method.name)
|
45
|
+
@mod.send(@visibility, @old_method.name)
|
46
46
|
|
47
47
|
nil
|
48
48
|
end
|
@@ -97,10 +97,13 @@ module T::Private::ClassUtils
|
|
97
97
|
overwritten = original_owner == mod
|
98
98
|
T::Configuration.without_ruby_warnings do
|
99
99
|
T::Private::DeclState.current.without_on_method_added do
|
100
|
-
mod.send(:define_method, name, &blk)
|
100
|
+
mod.send(:define_method, name, &blk)
|
101
|
+
if blk.arity < 0 && mod.respond_to?(:ruby2_keywords, true)
|
102
|
+
mod.send(:ruby2_keywords, name)
|
103
|
+
end
|
101
104
|
end
|
102
105
|
end
|
103
|
-
mod.send(original_visibility, name)
|
106
|
+
mod.send(original_visibility, name)
|
104
107
|
new_method = mod.instance_method(name)
|
105
108
|
|
106
109
|
ReplacedMethod.new(mod, original_method, new_method, overwritten, original_visibility)
|
@@ -72,7 +72,7 @@ module T::Private::Methods
|
|
72
72
|
decl.params = {}
|
73
73
|
end
|
74
74
|
|
75
|
-
T::Types::Proc.new(decl.params, decl.returns)
|
75
|
+
T::Types::Proc.new(decl.params, decl.returns)
|
76
76
|
end
|
77
77
|
|
78
78
|
# See docs at T::Utils.register_forwarder.
|
@@ -142,7 +142,10 @@ module T::Private::Methods
|
|
142
142
|
# method_to_key(ancestor.instance_method(method_name)) is not (just) an optimization, but also required for
|
143
143
|
# correctness, since ancestor.method_defined?(method_name) may return true even if method_name is not defined
|
144
144
|
# directly on ancestor but instead an ancestor of ancestor.
|
145
|
-
if ancestor.method_defined?(method_name)
|
145
|
+
if (ancestor.method_defined?(method_name) ||
|
146
|
+
ancestor.private_method_defined?(method_name) ||
|
147
|
+
ancestor.protected_method_defined?(method_name)) &&
|
148
|
+
final_method?(method_owner_and_name_to_key(ancestor, method_name))
|
146
149
|
raise(
|
147
150
|
"The method `#{method_name}` on #{ancestor} was declared as final and cannot be " +
|
148
151
|
(target == ancestor ? "redefined" : "overridden in #{target}")
|
@@ -190,7 +193,7 @@ module T::Private::Methods
|
|
190
193
|
|
191
194
|
if method_name == :method_added || method_name == :singleton_method_added
|
192
195
|
raise(
|
193
|
-
"Putting a `sig` on `#{method_name}` is not supported"
|
196
|
+
"Putting a `sig` on `#{method_name}` is not supported" \
|
194
197
|
" (sorbet-runtime uses this method internally to perform `sig` validation logic)"
|
195
198
|
)
|
196
199
|
end
|
@@ -206,22 +209,12 @@ module T::Private::Methods
|
|
206
209
|
# (or unwrap back to the original method).
|
207
210
|
new_method = nil
|
208
211
|
T::Private::ClassUtils.replace_method(mod, method_name) do |*args, &blk|
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
if new_method == new_new_method
|
216
|
-
raise "`sig` not present for method `#{method_name}` but you're trying to run it anyways. " \
|
217
|
-
"This should only be executed if you used `alias_method` to grab a handle to a method after `sig`ing it, but that clearly isn't what you are doing. " \
|
218
|
-
"Maybe look to see if an exception was thrown in your `sig` lambda or somehow else your `sig` wasn't actually applied to the method. " \
|
219
|
-
"Contact #dev-productivity if you're really stuck."
|
220
|
-
end
|
221
|
-
return new_new_method.bind(self).call(*args, &blk)
|
222
|
-
end
|
223
|
-
|
224
|
-
method_sig = T::Private::Methods.run_sig_block_for_method(new_method)
|
212
|
+
method_sig = T::Private::Methods.maybe_run_sig_block_for_method(new_method)
|
213
|
+
method_sig ||= T::Private::Methods._handle_missing_method_signature(
|
214
|
+
self,
|
215
|
+
original_method,
|
216
|
+
__callee__,
|
217
|
+
)
|
225
218
|
|
226
219
|
# Should be the same logic as CallValidation.wrap_method_if_needed but we
|
227
220
|
# don't want that extra layer of indirection in the callstack
|
@@ -252,6 +245,43 @@ module T::Private::Methods
|
|
252
245
|
end
|
253
246
|
end
|
254
247
|
|
248
|
+
def self._handle_missing_method_signature(receiver, original_method, callee)
|
249
|
+
method_sig = T::Private::Methods.signature_for_method(original_method)
|
250
|
+
if !method_sig
|
251
|
+
raise "`sig` not present for method `#{callee}` on #{receiver.inspect} but you're trying to run it anyways. " \
|
252
|
+
"This should only be executed if you used `alias_method` to grab a handle to a method after `sig`ing it, but that clearly isn't what you are doing. " \
|
253
|
+
"Maybe look to see if an exception was thrown in your `sig` lambda or somehow else your `sig` wasn't actually applied to the method."
|
254
|
+
end
|
255
|
+
|
256
|
+
if receiver.class <= original_method.owner
|
257
|
+
receiving_class = receiver.class
|
258
|
+
elsif receiver.singleton_class <= original_method.owner
|
259
|
+
receiving_class = receiver.singleton_class
|
260
|
+
elsif receiver.is_a?(Module) && receiver <= original_method.owner
|
261
|
+
receiving_class = receiver
|
262
|
+
else
|
263
|
+
raise "#{receiver} is not related to #{original_method} - how did we get here?"
|
264
|
+
end
|
265
|
+
|
266
|
+
# Check for a case where `alias` or `alias_method` was called for a
|
267
|
+
# method which had already had a `sig` applied. In that case, we want
|
268
|
+
# to avoid hitting this slow path again, by moving to a faster validator
|
269
|
+
# just like we did or will for the original method.
|
270
|
+
#
|
271
|
+
# If this isn't an `alias` or `alias_method` case, we're probably in the
|
272
|
+
# middle of some metaprogramming using a Method object, e.g. a pattern like
|
273
|
+
# `arr.map(&method(:foo))`. There's nothing really we can do to optimize
|
274
|
+
# that here.
|
275
|
+
receiving_method = receiving_class.instance_method(callee)
|
276
|
+
if receiving_method != original_method && receiving_method.original_name == original_method.name
|
277
|
+
aliasing_mod = receiving_method.owner
|
278
|
+
method_sig = method_sig.as_alias(callee)
|
279
|
+
unwrap_method(aliasing_mod, method_sig, original_method)
|
280
|
+
end
|
281
|
+
|
282
|
+
method_sig
|
283
|
+
end
|
284
|
+
|
255
285
|
# Executes the `sig` block, and converts the resulting Declaration
|
256
286
|
# to a Signature.
|
257
287
|
def self.run_sig(hook_mod, method_name, original_method, declaration_block)
|
@@ -270,7 +300,7 @@ module T::Private::Methods
|
|
270
300
|
Signature.new_untyped(method: original_method)
|
271
301
|
end
|
272
302
|
|
273
|
-
unwrap_method(
|
303
|
+
unwrap_method(signature.method.owner, signature, original_method)
|
274
304
|
signature
|
275
305
|
end
|
276
306
|
|
@@ -284,8 +314,12 @@ module T::Private::Methods
|
|
284
314
|
|
285
315
|
def self.build_sig(hook_mod, method_name, original_method, current_declaration, loc)
|
286
316
|
begin
|
287
|
-
# We allow `sig` in the current module's context (normal case) and
|
288
|
-
if hook_mod != current_declaration.mod &&
|
317
|
+
# We allow `sig` in the current module's context (normal case) and
|
318
|
+
if hook_mod != current_declaration.mod &&
|
319
|
+
# inside `class << self`, and
|
320
|
+
hook_mod.singleton_class != current_declaration.mod &&
|
321
|
+
# on `self` at the top level of a file
|
322
|
+
current_declaration.mod != TOP_SELF
|
289
323
|
raise "A method (#{method_name}) is being added on a different class/module (#{hook_mod}) than the " \
|
290
324
|
"last call to `sig` (#{current_declaration.mod}). Make sure each call " \
|
291
325
|
"to `sig` is immediately followed by a method definition on the same " \
|
@@ -302,7 +336,6 @@ module T::Private::Methods
|
|
302
336
|
check_level: current_declaration.checked,
|
303
337
|
on_failure: current_declaration.on_failure,
|
304
338
|
override_allow_incompatible: current_declaration.override_allow_incompatible,
|
305
|
-
generated: current_declaration.generated,
|
306
339
|
)
|
307
340
|
|
308
341
|
SignatureValidation.validate(signature)
|
@@ -323,8 +356,8 @@ module T::Private::Methods
|
|
323
356
|
end
|
324
357
|
end
|
325
358
|
|
326
|
-
def self.unwrap_method(
|
327
|
-
maybe_wrapped_method = CallValidation.wrap_method_if_needed(
|
359
|
+
def self.unwrap_method(mod, signature, original_method)
|
360
|
+
maybe_wrapped_method = CallValidation.wrap_method_if_needed(mod, signature, original_method)
|
328
361
|
@signatures_by_method[method_to_key(maybe_wrapped_method)] = signature
|
329
362
|
end
|
330
363
|
|
@@ -377,7 +410,7 @@ module T::Private::Methods
|
|
377
410
|
def self.run_all_sig_blocks
|
378
411
|
loop do
|
379
412
|
break if @sig_wrappers.empty?
|
380
|
-
key,
|
413
|
+
key, = @sig_wrappers.first
|
381
414
|
run_sig_block_for_key(key)
|
382
415
|
end
|
383
416
|
end
|
@@ -394,7 +427,7 @@ module T::Private::Methods
|
|
394
427
|
end
|
395
428
|
|
396
429
|
def self.set_final_checks_on_hooks(enable)
|
397
|
-
is_enabled =
|
430
|
+
is_enabled = !@old_hooks.nil?
|
398
431
|
if enable == is_enabled
|
399
432
|
return
|
400
433
|
end
|
@@ -436,6 +469,20 @@ module T::Private::Methods
|
|
436
469
|
return if @installed_hooks.include?(mod)
|
437
470
|
@installed_hooks << mod
|
438
471
|
|
472
|
+
if mod == TOP_SELF
|
473
|
+
# self at the top-level of a file is weirdly special in Ruby
|
474
|
+
# The Ruby VM on startup creates an `Object.new` and stashes it.
|
475
|
+
# Unlike when we're using sig inside a module, `self` is actually a
|
476
|
+
# normal object, not an instance of Module.
|
477
|
+
#
|
478
|
+
# Thus we can't ask things like mod.singleton_class? (since that's
|
479
|
+
# defined only on Module, not on Object) and even if we could, the places
|
480
|
+
# where we need to install the hooks are special.
|
481
|
+
mod.extend(SingletonMethodHooks) # def self.foo; end (at top level)
|
482
|
+
Object.extend(MethodHooks) # def foo; end (at top level)
|
483
|
+
return
|
484
|
+
end
|
485
|
+
|
439
486
|
if mod.singleton_class?
|
440
487
|
mod.include(SingletonMethodHooks)
|
441
488
|
else
|
@@ -455,7 +502,12 @@ module T::Private::Methods
|
|
455
502
|
|
456
503
|
private_class_method def self.key_to_method(key)
|
457
504
|
id, name = key.split("#")
|
458
|
-
obj = ObjectSpace._id2ref(id.to_i)
|
505
|
+
obj = ObjectSpace._id2ref(id.to_i)
|
459
506
|
obj.instance_method(name)
|
460
507
|
end
|
461
508
|
end
|
509
|
+
|
510
|
+
# This has to be here, and can't be nested inside `T::Private::Methods`,
|
511
|
+
# because the value of `self` depends on lexical (nesting) scope, and we
|
512
|
+
# specifically need a reference to the file-level self, i.e. `main:Object`
|
513
|
+
T::Private::Methods::TOP_SELF = self
|
@@ -51,10 +51,6 @@ module T::Private::Methods::CallValidation
|
|
51
51
|
# This method is called for every `sig`. It's critical to keep it fast and
|
52
52
|
# reduce number of allocations that happen here.
|
53
53
|
|
54
|
-
if method_sig.ever_failed && method_sig.generated
|
55
|
-
return original_method.bind(instance).call(*args, &blk)
|
56
|
-
end
|
57
|
-
|
58
54
|
T::Profile.typecheck_sample_attempts -= 1
|
59
55
|
should_sample = T::Profile.typecheck_sample_attempts == 0
|
60
56
|
if should_sample
|
@@ -189,6 +185,9 @@ module T::Private::Methods::CallValidation
|
|
189
185
|
mod.send(:define_method, method_sig.method_name) do |*args, &blk|
|
190
186
|
CallValidation.validate_call(self, original_method, method_sig, args, blk)
|
191
187
|
end
|
188
|
+
if mod.respond_to?(:ruby2_keywords, true)
|
189
|
+
mod.send(:ruby2_keywords, method_sig.method_name)
|
190
|
+
end
|
192
191
|
end
|
193
192
|
|
194
193
|
def self.create_validator_method_fast(mod, original_method, method_sig)
|
@@ -196,7 +195,7 @@ module T::Private::Methods::CallValidation
|
|
196
195
|
raise "Should have used create_validator_procedure_fast"
|
197
196
|
end
|
198
197
|
# trampoline to reduce stack frame size
|
199
|
-
if method_sig.arg_types.
|
198
|
+
if method_sig.arg_types.empty?
|
200
199
|
create_validator_method_fast0(mod, original_method, method_sig, method_sig.return_type.raw_type)
|
201
200
|
elsif method_sig.arg_types.length == 1
|
202
201
|
create_validator_method_fast1(mod, original_method, method_sig, method_sig.return_type.raw_type,
|
@@ -252,10 +251,6 @@ module T::Private::Methods::CallValidation
|
|
252
251
|
T::Profile.typecheck_duration += (Process.clock_gettime(Process::CLOCK_MONOTONIC) - t1)
|
253
252
|
end
|
254
253
|
|
255
|
-
if method_sig.ever_failed && method_sig.generated
|
256
|
-
return original_method.bind(self).call(&blk)
|
257
|
-
end
|
258
|
-
|
259
254
|
# The following line breaks are intentional to show nice pry message
|
260
255
|
|
261
256
|
|
@@ -303,10 +298,6 @@ module T::Private::Methods::CallValidation
|
|
303
298
|
# reduce number of allocations that happen here.
|
304
299
|
# This method is a manually sped-up version of more general code in `validate_call`
|
305
300
|
|
306
|
-
if method_sig.ever_failed && method_sig.generated
|
307
|
-
return original_method.bind(self).call(arg0, &blk)
|
308
|
-
end
|
309
|
-
|
310
301
|
T::Profile.typecheck_sample_attempts -= 1
|
311
302
|
should_sample = T::Profile.typecheck_sample_attempts == 0
|
312
303
|
if should_sample
|
@@ -392,10 +383,6 @@ module T::Private::Methods::CallValidation
|
|
392
383
|
# reduce number of allocations that happen here.
|
393
384
|
# This method is a manually sped-up version of more general code in `validate_call`
|
394
385
|
|
395
|
-
if method_sig.ever_failed && method_sig.generated
|
396
|
-
return original_method.bind(self).call(arg0, arg1, &blk)
|
397
|
-
end
|
398
|
-
|
399
386
|
T::Profile.typecheck_sample_attempts -= 1
|
400
387
|
should_sample = T::Profile.typecheck_sample_attempts == 0
|
401
388
|
if should_sample
|
@@ -493,10 +480,6 @@ module T::Private::Methods::CallValidation
|
|
493
480
|
# reduce number of allocations that happen here.
|
494
481
|
# This method is a manually sped-up version of more general code in `validate_call`
|
495
482
|
|
496
|
-
if method_sig.ever_failed && method_sig.generated
|
497
|
-
return original_method.bind(self).call(arg0, arg1, arg2, &blk)
|
498
|
-
end
|
499
|
-
|
500
483
|
T::Profile.typecheck_sample_attempts -= 1
|
501
484
|
should_sample = T::Profile.typecheck_sample_attempts == 0
|
502
485
|
if should_sample
|
@@ -607,10 +590,6 @@ module T::Private::Methods::CallValidation
|
|
607
590
|
# reduce number of allocations that happen here.
|
608
591
|
# This method is a manually sped-up version of more general code in `validate_call`
|
609
592
|
|
610
|
-
if method_sig.ever_failed && method_sig.generated
|
611
|
-
return original_method.bind(self).call(arg0, arg1, arg2, arg3, &blk)
|
612
|
-
end
|
613
|
-
|
614
593
|
T::Profile.typecheck_sample_attempts -= 1
|
615
594
|
should_sample = T::Profile.typecheck_sample_attempts == 0
|
616
595
|
if should_sample
|
@@ -729,7 +708,7 @@ module T::Private::Methods::CallValidation
|
|
729
708
|
|
730
709
|
def self.create_validator_procedure_fast(mod, original_method, method_sig)
|
731
710
|
# trampoline to reduce stack frame size
|
732
|
-
if method_sig.arg_types.
|
711
|
+
if method_sig.arg_types.empty?
|
733
712
|
create_validator_procedure_fast0(mod, original_method, method_sig)
|
734
713
|
elsif method_sig.arg_types.length == 1
|
735
714
|
create_validator_procedure_fast1(mod, original_method, method_sig,
|
@@ -760,10 +739,6 @@ module T::Private::Methods::CallValidation
|
|
760
739
|
# reduce number of allocations that happen here.
|
761
740
|
# This method is a manually sped-up version of more general code in `validate_call`
|
762
741
|
|
763
|
-
if method_sig.ever_failed && method_sig.generated
|
764
|
-
return original_method.bind(self).call(&blk)
|
765
|
-
end
|
766
|
-
|
767
742
|
T::Profile.typecheck_sample_attempts -= 1
|
768
743
|
should_sample = T::Profile.typecheck_sample_attempts == 0
|
769
744
|
if should_sample
|
@@ -817,10 +792,6 @@ module T::Private::Methods::CallValidation
|
|
817
792
|
# reduce number of allocations that happen here.
|
818
793
|
# This method is a manually sped-up version of more general code in `validate_call`
|
819
794
|
|
820
|
-
if method_sig.ever_failed && method_sig.generated
|
821
|
-
return original_method.bind(self).call(arg0, &blk)
|
822
|
-
end
|
823
|
-
|
824
795
|
T::Profile.typecheck_sample_attempts -= 1
|
825
796
|
should_sample = T::Profile.typecheck_sample_attempts == 0
|
826
797
|
if should_sample
|
@@ -884,10 +855,6 @@ module T::Private::Methods::CallValidation
|
|
884
855
|
# reduce number of allocations that happen here.
|
885
856
|
# This method is a manually sped-up version of more general code in `validate_call`
|
886
857
|
|
887
|
-
if method_sig.ever_failed && method_sig.generated
|
888
|
-
return original_method.bind(self).call(arg0, arg1, &blk)
|
889
|
-
end
|
890
|
-
|
891
858
|
T::Profile.typecheck_sample_attempts -= 1
|
892
859
|
should_sample = T::Profile.typecheck_sample_attempts == 0
|
893
860
|
if should_sample
|
@@ -964,10 +931,6 @@ module T::Private::Methods::CallValidation
|
|
964
931
|
# reduce number of allocations that happen here.
|
965
932
|
# This method is a manually sped-up version of more general code in `validate_call`
|
966
933
|
|
967
|
-
if method_sig.ever_failed && method_sig.generated
|
968
|
-
return original_method.bind(self).call(arg0, arg1, arg2, &blk)
|
969
|
-
end
|
970
|
-
|
971
934
|
T::Profile.typecheck_sample_attempts -= 1
|
972
935
|
should_sample = T::Profile.typecheck_sample_attempts == 0
|
973
936
|
if should_sample
|
@@ -1057,10 +1020,6 @@ module T::Private::Methods::CallValidation
|
|
1057
1020
|
# reduce number of allocations that happen here.
|
1058
1021
|
# This method is a manually sped-up version of more general code in `validate_call`
|
1059
1022
|
|
1060
|
-
if method_sig.ever_failed && method_sig.generated
|
1061
|
-
return original_method.bind(self).call(arg0, arg1, arg2, arg3, &blk)
|
1062
|
-
end
|
1063
|
-
|
1064
1023
|
T::Profile.typecheck_sample_attempts -= 1
|
1065
1024
|
should_sample = T::Profile.typecheck_sample_attempts == 0
|
1066
1025
|
if should_sample
|
@@ -1156,7 +1115,6 @@ module T::Private::Methods::CallValidation
|
|
1156
1115
|
end
|
1157
1116
|
|
1158
1117
|
def self.report_error(method_sig, error_message, kind, name, type, value, caller_offset: 0)
|
1159
|
-
method_sig.mark_failed
|
1160
1118
|
caller_loc = T.must(caller_locations(3 + caller_offset, 1))[0]
|
1161
1119
|
definition_file, definition_line = method_sig.method.source_location
|
1162
1120
|
|