sorbet-runtime 0.6.13412 → 0.6.13414
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 +4 -4
- data/lib/types/private/decl_state.rb +1 -0
- data/lib/types/private/methods/_methods.rb +123 -31
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: c785f4639764f63f21035a28e89190a76a91b8c03bed613c2a1173df0affb145
|
|
4
|
+
data.tar.gz: 17d9de2b1f8cff74c7d4793b64bcc5f50f37f6647ba1bdd3dc5566c087cc4a4b
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 7dabc7ec609291736c71f2fe2864b71f46cbc602266138cb9f9726175eb5a521d1e0ba4cf552e27ff138b4e1023ac1e47586f5340cbbf3c943f9eeeecf08bdad
|
|
7
|
+
data.tar.gz: 1150cd3d617f5c87aeb20d258320e52481857b4f00d14d1fdebd0b9cc2c88f0d01e48615be25a09cc92576ed3ce25c26960d00e773e5f96054a399a4b8f74308
|
|
@@ -42,13 +42,16 @@ module T::Private::Methods
|
|
|
42
42
|
end
|
|
43
43
|
# rubocop:enable Naming/ClassAndModuleCamelCase
|
|
44
44
|
|
|
45
|
-
#
|
|
45
|
+
# sig_state:
|
|
46
46
|
# - It's a `Proc` if we haven't forced the thunk yet.
|
|
47
47
|
# - It's a `Declaration` if we have, but we haven't finished building the sig
|
|
48
48
|
# (This can matter for circular load-time behavior, where a method is
|
|
49
49
|
# called while its Signature is being built)
|
|
50
|
-
# - It's `
|
|
51
|
-
|
|
50
|
+
# - It's a `Signature` if we've finished building the sig. This allows
|
|
51
|
+
# the first-call wrapper to find its own signature even if it was
|
|
52
|
+
# evaluated externally (e.g., by run_all_sig_blocks) and
|
|
53
|
+
# @signatures_by_method[key] was overwritten by a redefinition.
|
|
54
|
+
DeclarationBlock = Struct.new(:mod, :method_name, :loc, :sig_state, :final, :abstract, :override, :overridable)
|
|
52
55
|
|
|
53
56
|
def self.declare_sig(mod, loc, arg, &blk)
|
|
54
57
|
if T::Private::DeclState.current.active_declaration
|
|
@@ -76,7 +79,7 @@ module T::Private::Methods
|
|
|
76
79
|
raise DeclBuilder::BuilderError.new("You must declare a `sig` before using `#{dsl_name}` on the method `#{method_name}`")
|
|
77
80
|
end
|
|
78
81
|
|
|
79
|
-
if !previous_declaration.
|
|
82
|
+
if !previous_declaration.sig_state.is_a?(Proc)
|
|
80
83
|
raise DeclBuilder::BuilderError.new("Cannot call `#{dsl_name} #{method_name.inspect}`, because the sig block has already run")
|
|
81
84
|
end
|
|
82
85
|
|
|
@@ -320,6 +323,43 @@ module T::Private::Methods
|
|
|
320
323
|
end
|
|
321
324
|
|
|
322
325
|
if current_declaration.nil?
|
|
326
|
+
key = method_owner_and_name_to_key(mod, method_name)
|
|
327
|
+
|
|
328
|
+
# `last_method_key` guards against multiple calls to `_on_method_added`,
|
|
329
|
+
# from having multiple copies of the method in the ancestor chain (this
|
|
330
|
+
# can happen commonly if `Module` is monkey patched, because various
|
|
331
|
+
# files in sorbet-runtime itself run `extend T::Sig` before a monkey
|
|
332
|
+
# patch has a chance to fire).
|
|
333
|
+
#
|
|
334
|
+
# This is a performance optimization, to guarantee that methods with
|
|
335
|
+
# `.checked(:never)` sigs are unwrapped on first call rather than
|
|
336
|
+
# permanently trapped behind the first-call wrapper (which allocates via
|
|
337
|
+
# `|*args, &blk|` on every call). Without this guard, the duplicate
|
|
338
|
+
# `_on_method_added` deletes the key from `@sig_wrappers`, so the wrapper
|
|
339
|
+
# can never find its sig block and never unwraps.
|
|
340
|
+
if decl_state.last_method_key == key
|
|
341
|
+
return
|
|
342
|
+
end
|
|
343
|
+
|
|
344
|
+
# Drop any existing sig, because the `sig_block` closes over the
|
|
345
|
+
# `original_method` at the time that the sig wrapper was registered, and
|
|
346
|
+
# forcing the sig would thus redefine the the redefined method back to
|
|
347
|
+
# the original method.
|
|
348
|
+
old_sig = @sig_wrappers.delete(key)
|
|
349
|
+
|
|
350
|
+
# Ruby only reports method redefinitions if `$VERBOSE` is truthy. Let's
|
|
351
|
+
# do the same for sigs.
|
|
352
|
+
if old_sig && $VERBOSE
|
|
353
|
+
# We can probably get away with not printing any location information
|
|
354
|
+
# (like the Ruby VM would for method redefinition warnings) because the
|
|
355
|
+
# Ruby VM itself will have printed the location information in its
|
|
356
|
+
# method redefinition warning (and it does that faster, using functions
|
|
357
|
+
# that constult the CFP directly).
|
|
358
|
+
Warning.warn(
|
|
359
|
+
"sorbet-runtime: warning: Dropping unevaluated signature for #{mod}##{method_name} because it was redefined\n"
|
|
360
|
+
)
|
|
361
|
+
end
|
|
362
|
+
|
|
323
363
|
return
|
|
324
364
|
end
|
|
325
365
|
|
|
@@ -348,7 +388,7 @@ module T::Private::Methods
|
|
|
348
388
|
|
|
349
389
|
original_method = mod.instance_method(method_name)
|
|
350
390
|
sig_block = lambda do
|
|
351
|
-
T::Private::Methods.run_sig(method_name, original_method, current_declaration)
|
|
391
|
+
T::Private::Methods.run_sig(method_name, original_method, current_declaration, unwrap: true)
|
|
352
392
|
end
|
|
353
393
|
|
|
354
394
|
# Always replace the original method with this wrapper,
|
|
@@ -356,23 +396,56 @@ module T::Private::Methods
|
|
|
356
396
|
# This wrapper is very slow, so it will subsequently re-wrap with a much faster wrapper
|
|
357
397
|
# (or unwrap back to the original method).
|
|
358
398
|
key = method_owner_and_name_to_key(mod, method_name)
|
|
399
|
+
built_sig = nil
|
|
400
|
+
if T::Private::IS_TYPECHECKING
|
|
401
|
+
built_sig = T.let(nil, T.nilable(Signature))
|
|
402
|
+
end
|
|
359
403
|
T::Private::ClassUtils.replace_method(original_method, mod, method_name) do |*args, &blk|
|
|
360
|
-
|
|
404
|
+
callee = Kernel.__callee__ || raise("Unknown __callee__ for method without a signature")
|
|
405
|
+
method_sig = built_sig
|
|
361
406
|
if !method_sig
|
|
362
|
-
|
|
363
|
-
|
|
407
|
+
# Check if this wrapper's sig_block is still the active one for this key
|
|
408
|
+
#
|
|
409
|
+
# If not, the method was redefined and this wrapper is being called via
|
|
410
|
+
# a captured method object from reflection (e.g., `instance_method` or
|
|
411
|
+
# `method` from before the redefinition).
|
|
412
|
+
#
|
|
413
|
+
# We can only use maybe_run_sig_block_for_key if there was no
|
|
414
|
+
# redefinition, because it would otherwise call unwrap_method,
|
|
415
|
+
# overwriting the redefinition.
|
|
416
|
+
method_sig =
|
|
417
|
+
if T::Private::Methods._sig_block_is_current?(key, sig_block)
|
|
418
|
+
T::Private::Methods.maybe_run_sig_block_for_key(key)
|
|
419
|
+
elsif !(method_sig = current_declaration.sig_state).is_a?(Signature)
|
|
420
|
+
# This is essentially a permanent slow path: since the method was
|
|
421
|
+
# redefined before the sig block had a chance to run, we can't unwrap
|
|
422
|
+
# the method, as that would overwrite the redefinition, effectively
|
|
423
|
+
# putting the method back to its original definition. (Note that
|
|
424
|
+
# `run_sig` is what we call in the `sig_block`, but this one just
|
|
425
|
+
# doesn't unwrap.)
|
|
426
|
+
T::Private::Methods.run_sig(method_name, original_method, current_declaration, unwrap: false)
|
|
427
|
+
else
|
|
428
|
+
# The declaration was already consumed (e.g., module_function copies
|
|
429
|
+
# the first-call wrapper to the singleton class, sharing the same
|
|
430
|
+
# DeclarationBlock; if the instance method's sig is evaluated first,
|
|
431
|
+
# sig_state is a Signature when the singleton copy runs).
|
|
432
|
+
method_sig
|
|
433
|
+
end
|
|
364
434
|
if !method_sig
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
"
|
|
435
|
+
method_sig = T::Private::Methods.signature_for_method(original_method)
|
|
436
|
+
if !method_sig
|
|
437
|
+
raise "`sig` not present for method `#{callee}` on #{self.inspect} but you're trying to run it anyways. " \
|
|
438
|
+
"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. " \
|
|
439
|
+
"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."
|
|
440
|
+
end
|
|
368
441
|
end
|
|
442
|
+
built_sig = method_sig
|
|
443
|
+
end
|
|
369
444
|
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
callee,
|
|
375
|
-
)
|
|
445
|
+
# If this wrapper is being called via an alias, unwrap the alias so
|
|
446
|
+
# subsequent calls bypass the wrapper entirely.
|
|
447
|
+
if callee != method_name
|
|
448
|
+
T::Private::Methods._unwrap_alias(method_sig, self, original_method, callee)
|
|
376
449
|
end
|
|
377
450
|
|
|
378
451
|
# Should be the same logic as CallValidation.wrap_method_if_needed but we
|
|
@@ -397,6 +470,8 @@ module T::Private::Methods
|
|
|
397
470
|
if current_declaration.final
|
|
398
471
|
add_module_with_final_method(mod, method_name)
|
|
399
472
|
end
|
|
473
|
+
|
|
474
|
+
key
|
|
400
475
|
end
|
|
401
476
|
|
|
402
477
|
# Only public so that it can be accessed in the closure for _on_method_added
|
|
@@ -432,7 +507,7 @@ module T::Private::Methods
|
|
|
432
507
|
|
|
433
508
|
# Executes the `sig` block, and converts the resulting Declaration
|
|
434
509
|
# to a Signature.
|
|
435
|
-
def self.run_sig(method_name, original_method, declaration_block)
|
|
510
|
+
def self.run_sig(method_name, original_method, declaration_block, unwrap:)
|
|
436
511
|
current_declaration =
|
|
437
512
|
begin
|
|
438
513
|
run_builder(declaration_block)
|
|
@@ -451,21 +526,29 @@ module T::Private::Methods
|
|
|
451
526
|
Signature.new_untyped(method: original_method)
|
|
452
527
|
end
|
|
453
528
|
|
|
454
|
-
|
|
529
|
+
if unwrap
|
|
530
|
+
unwrap_method(signature.method.owner, signature, original_method)
|
|
531
|
+
end
|
|
455
532
|
|
|
456
|
-
#
|
|
457
|
-
#
|
|
458
|
-
#
|
|
459
|
-
# exception and
|
|
460
|
-
|
|
533
|
+
# Store the finished signature (dropping the Declaration in the process).
|
|
534
|
+
# Only do this after we've actually wrapped the method and recorded the
|
|
535
|
+
# signature, because that might raise an exception, leaving the
|
|
536
|
+
# declaration in a weird state if the program rescues that exception and
|
|
537
|
+
# continues.
|
|
538
|
+
#
|
|
539
|
+
# Storing the signature here allows the first-call wrapper to find its
|
|
540
|
+
# own signature even if it was evaluated externally (e.g., by
|
|
541
|
+
# run_all_sig_blocks) and @signatures_by_method[key] was later overwritten
|
|
542
|
+
# by a redefinition.
|
|
543
|
+
declaration_block.sig_state = signature
|
|
461
544
|
|
|
462
545
|
signature
|
|
463
546
|
end
|
|
464
547
|
|
|
465
548
|
def self.run_builder(declaration_block)
|
|
466
|
-
|
|
467
|
-
return
|
|
468
|
-
if
|
|
549
|
+
sig_state = declaration_block.sig_state
|
|
550
|
+
return sig_state if sig_state.is_a?(Declaration)
|
|
551
|
+
if !sig_state.is_a?(Proc)
|
|
469
552
|
raise "DeclarationBlock for #{declaration_block.mod} at #{declaration_block.loc} should have already been unwrapped"
|
|
470
553
|
end
|
|
471
554
|
|
|
@@ -475,9 +558,9 @@ module T::Private::Methods
|
|
|
475
558
|
declaration_block.override,
|
|
476
559
|
declaration_block.overridable
|
|
477
560
|
)
|
|
478
|
-
decl = builder.instance_exec(&
|
|
561
|
+
decl = builder.instance_exec(&sig_state).finalize!.decl
|
|
479
562
|
# Record that we've already run `blk` once and constructed a `Declaration`
|
|
480
|
-
declaration_block.
|
|
563
|
+
declaration_block.sig_state = decl
|
|
481
564
|
decl
|
|
482
565
|
end
|
|
483
566
|
|
|
@@ -536,6 +619,11 @@ module T::Private::Methods
|
|
|
536
619
|
has_sig_block_for_key(method_to_key(method))
|
|
537
620
|
end
|
|
538
621
|
|
|
622
|
+
# Only public because it needs to get called inside the first-call wrapper closure.
|
|
623
|
+
def self._sig_block_is_current?(key, sig_block)
|
|
624
|
+
@sig_wrappers[key].equal?(sig_block)
|
|
625
|
+
end
|
|
626
|
+
|
|
539
627
|
private_class_method def self.has_sig_block_for_key(key)
|
|
540
628
|
@sig_wrappers.key?(key)
|
|
541
629
|
end
|
|
@@ -685,15 +773,19 @@ module T::Private::Methods
|
|
|
685
773
|
|
|
686
774
|
module MethodHooks
|
|
687
775
|
def method_added(name)
|
|
688
|
-
::T::Private::Methods._on_method_added(T.unsafe(self), T.unsafe(self), name)
|
|
776
|
+
key = ::T::Private::Methods._on_method_added(T.unsafe(self), T.unsafe(self), name)
|
|
777
|
+
T::Private::DeclState.current.last_method_key = key if key
|
|
689
778
|
super(name)
|
|
779
|
+
T::Private::DeclState.current.last_method_key = nil if key
|
|
690
780
|
end
|
|
691
781
|
end
|
|
692
782
|
|
|
693
783
|
module SingletonMethodHooks
|
|
694
784
|
def singleton_method_added(name)
|
|
695
|
-
::T::Private::Methods._on_method_added(T.unsafe(self), singleton_class, name)
|
|
785
|
+
key = ::T::Private::Methods._on_method_added(T.unsafe(self), singleton_class, name)
|
|
786
|
+
T::Private::DeclState.current.last_method_key = key if key
|
|
696
787
|
super(name)
|
|
788
|
+
T::Private::DeclState.current.last_method_key = nil if key
|
|
697
789
|
end
|
|
698
790
|
end
|
|
699
791
|
|