sorbet-runtime 0.6.13393 → 0.6.13398
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/methods/_methods.rb +98 -29
- 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: 6d0ef663103465c62f33bd4cbbb1d16a0ca815793189c06169f967d34a7f1801
|
|
4
|
+
data.tar.gz: b1521a442b3a1796232b01845cfa30ba3283d20e0ddc5eb8b2b81867dac951b7
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: c780f6b07da80a693165bc0867686b324c664e88c4473b09e4aed8ad05a82f496d356e02a9af5e5cbd07746d605990d71399bedd16fa0fab5d03e6a69504f4e5
|
|
7
|
+
data.tar.gz: 0cefee08a1abe28c7bb65b42d72e4d7cfb6eb8bf53b77c2541272904e609c6dbf7ac476f3b342b33a418f6d978de5622d0dc4a463c523df77a9572bd18c8d7cb
|
|
@@ -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,26 @@ 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
|
+
# Drop any existing sig, because the `sig_block` closes over the
|
|
328
|
+
# `original_method` at the time that the sig wrapper was registered, and
|
|
329
|
+
# forcing the sig would thus redefine the the redefined method back to
|
|
330
|
+
# the original method.
|
|
331
|
+
old_sig = @sig_wrappers.delete(key)
|
|
332
|
+
|
|
333
|
+
# Ruby only reports method redefinitions if `$VERBOSE` is truthy. Let's
|
|
334
|
+
# do the same for sigs.
|
|
335
|
+
if old_sig && $VERBOSE
|
|
336
|
+
# We can probably get away with not printing any location information
|
|
337
|
+
# (like the Ruby VM would for method redefinition warnings) because the
|
|
338
|
+
# Ruby VM itself will have printed the location information in its
|
|
339
|
+
# method redefinition warning (and it does that faster, using functions
|
|
340
|
+
# that constult the CFP directly).
|
|
341
|
+
Warning.warn(
|
|
342
|
+
"sorbet-runtime: warning: Dropping unevaluated signature for #{mod}##{method_name} because it was redefined\n"
|
|
343
|
+
)
|
|
344
|
+
end
|
|
345
|
+
|
|
323
346
|
return
|
|
324
347
|
end
|
|
325
348
|
|
|
@@ -348,7 +371,7 @@ module T::Private::Methods
|
|
|
348
371
|
|
|
349
372
|
original_method = mod.instance_method(method_name)
|
|
350
373
|
sig_block = lambda do
|
|
351
|
-
T::Private::Methods.run_sig(method_name, original_method, current_declaration)
|
|
374
|
+
T::Private::Methods.run_sig(method_name, original_method, current_declaration, unwrap: true)
|
|
352
375
|
end
|
|
353
376
|
|
|
354
377
|
# Always replace the original method with this wrapper,
|
|
@@ -356,23 +379,56 @@ module T::Private::Methods
|
|
|
356
379
|
# This wrapper is very slow, so it will subsequently re-wrap with a much faster wrapper
|
|
357
380
|
# (or unwrap back to the original method).
|
|
358
381
|
key = method_owner_and_name_to_key(mod, method_name)
|
|
382
|
+
built_sig = nil
|
|
383
|
+
if T::Private::IS_TYPECHECKING
|
|
384
|
+
built_sig = T.let(nil, T.nilable(Signature))
|
|
385
|
+
end
|
|
359
386
|
T::Private::ClassUtils.replace_method(original_method, mod, method_name) do |*args, &blk|
|
|
360
|
-
|
|
387
|
+
callee = Kernel.__callee__ || raise("Unknown __callee__ for method without a signature")
|
|
388
|
+
method_sig = built_sig
|
|
361
389
|
if !method_sig
|
|
362
|
-
|
|
363
|
-
|
|
390
|
+
# Check if this wrapper's sig_block is still the active one for this key
|
|
391
|
+
#
|
|
392
|
+
# If not, the method was redefined and this wrapper is being called via
|
|
393
|
+
# a captured method object from reflection (e.g., `instance_method` or
|
|
394
|
+
# `method` from before the redefinition).
|
|
395
|
+
#
|
|
396
|
+
# We can only use maybe_run_sig_block_for_key if there was no
|
|
397
|
+
# redefinition, because it would otherwise call unwrap_method,
|
|
398
|
+
# overwriting the redefinition.
|
|
399
|
+
method_sig =
|
|
400
|
+
if T::Private::Methods._sig_block_is_current?(key, sig_block)
|
|
401
|
+
T::Private::Methods.maybe_run_sig_block_for_key(key)
|
|
402
|
+
elsif !(method_sig = current_declaration.sig_state).is_a?(Signature)
|
|
403
|
+
# This is essentially a permanent slow path: since the method was
|
|
404
|
+
# redefined before the sig block had a chance to run, we can't unwrap
|
|
405
|
+
# the method, as that would overwrite the redefinition, effectively
|
|
406
|
+
# putting the method back to its original definition. (Note that
|
|
407
|
+
# `run_sig` is what we call in the `sig_block`, but this one just
|
|
408
|
+
# doesn't unwrap.)
|
|
409
|
+
T::Private::Methods.run_sig(method_name, original_method, current_declaration, unwrap: false)
|
|
410
|
+
else
|
|
411
|
+
# The declaration was already consumed (e.g., module_function copies
|
|
412
|
+
# the first-call wrapper to the singleton class, sharing the same
|
|
413
|
+
# DeclarationBlock; if the instance method's sig is evaluated first,
|
|
414
|
+
# sig_state is a Signature when the singleton copy runs).
|
|
415
|
+
method_sig
|
|
416
|
+
end
|
|
364
417
|
if !method_sig
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
"
|
|
418
|
+
method_sig = T::Private::Methods.signature_for_method(original_method)
|
|
419
|
+
if !method_sig
|
|
420
|
+
raise "`sig` not present for method `#{callee}` on #{self.inspect} but you're trying to run it anyways. " \
|
|
421
|
+
"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. " \
|
|
422
|
+
"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."
|
|
423
|
+
end
|
|
368
424
|
end
|
|
425
|
+
built_sig = method_sig
|
|
426
|
+
end
|
|
369
427
|
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
callee,
|
|
375
|
-
)
|
|
428
|
+
# If this wrapper is being called via an alias, unwrap the alias so
|
|
429
|
+
# subsequent calls bypass the wrapper entirely.
|
|
430
|
+
if callee != method_name
|
|
431
|
+
T::Private::Methods._unwrap_alias(method_sig, self, original_method, callee)
|
|
376
432
|
end
|
|
377
433
|
|
|
378
434
|
# Should be the same logic as CallValidation.wrap_method_if_needed but we
|
|
@@ -432,7 +488,7 @@ module T::Private::Methods
|
|
|
432
488
|
|
|
433
489
|
# Executes the `sig` block, and converts the resulting Declaration
|
|
434
490
|
# to a Signature.
|
|
435
|
-
def self.run_sig(method_name, original_method, declaration_block)
|
|
491
|
+
def self.run_sig(method_name, original_method, declaration_block, unwrap:)
|
|
436
492
|
current_declaration =
|
|
437
493
|
begin
|
|
438
494
|
run_builder(declaration_block)
|
|
@@ -451,21 +507,29 @@ module T::Private::Methods
|
|
|
451
507
|
Signature.new_untyped(method: original_method)
|
|
452
508
|
end
|
|
453
509
|
|
|
454
|
-
|
|
510
|
+
if unwrap
|
|
511
|
+
unwrap_method(signature.method.owner, signature, original_method)
|
|
512
|
+
end
|
|
455
513
|
|
|
456
|
-
#
|
|
457
|
-
#
|
|
458
|
-
#
|
|
459
|
-
# exception and
|
|
460
|
-
|
|
514
|
+
# Store the finished signature (dropping the Declaration in the process).
|
|
515
|
+
# Only do this after we've actually wrapped the method and recorded the
|
|
516
|
+
# signature, because that might raise an exception, leaving the
|
|
517
|
+
# declaration in a weird state if the program rescues that exception and
|
|
518
|
+
# continues.
|
|
519
|
+
#
|
|
520
|
+
# Storing the signature here allows the first-call wrapper to find its
|
|
521
|
+
# own signature even if it was evaluated externally (e.g., by
|
|
522
|
+
# run_all_sig_blocks) and @signatures_by_method[key] was later overwritten
|
|
523
|
+
# by a redefinition.
|
|
524
|
+
declaration_block.sig_state = signature
|
|
461
525
|
|
|
462
526
|
signature
|
|
463
527
|
end
|
|
464
528
|
|
|
465
529
|
def self.run_builder(declaration_block)
|
|
466
|
-
|
|
467
|
-
return
|
|
468
|
-
if
|
|
530
|
+
sig_state = declaration_block.sig_state
|
|
531
|
+
return sig_state if sig_state.is_a?(Declaration)
|
|
532
|
+
if !sig_state.is_a?(Proc)
|
|
469
533
|
raise "DeclarationBlock for #{declaration_block.mod} at #{declaration_block.loc} should have already been unwrapped"
|
|
470
534
|
end
|
|
471
535
|
|
|
@@ -475,9 +539,9 @@ module T::Private::Methods
|
|
|
475
539
|
declaration_block.override,
|
|
476
540
|
declaration_block.overridable
|
|
477
541
|
)
|
|
478
|
-
decl = builder.instance_exec(&
|
|
542
|
+
decl = builder.instance_exec(&sig_state).finalize!.decl
|
|
479
543
|
# Record that we've already run `blk` once and constructed a `Declaration`
|
|
480
|
-
declaration_block.
|
|
544
|
+
declaration_block.sig_state = decl
|
|
481
545
|
decl
|
|
482
546
|
end
|
|
483
547
|
|
|
@@ -536,6 +600,11 @@ module T::Private::Methods
|
|
|
536
600
|
has_sig_block_for_key(method_to_key(method))
|
|
537
601
|
end
|
|
538
602
|
|
|
603
|
+
# Only public because it needs to get called inside the first-call wrapper closure.
|
|
604
|
+
def self._sig_block_is_current?(key, sig_block)
|
|
605
|
+
@sig_wrappers[key].equal?(sig_block)
|
|
606
|
+
end
|
|
607
|
+
|
|
539
608
|
private_class_method def self.has_sig_block_for_key(key)
|
|
540
609
|
@sig_wrappers.key?(key)
|
|
541
610
|
end
|