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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 015a7fae1ca90c8ad080f993749625b36a1024c2829216de43df9390a8be2b1a
4
- data.tar.gz: a557477677d13ba37a1ec5e2ca923d844fadaf5414761d6fffcf49a5afebd1eb
3
+ metadata.gz: 6d0ef663103465c62f33bd4cbbb1d16a0ca815793189c06169f967d34a7f1801
4
+ data.tar.gz: b1521a442b3a1796232b01845cfa30ba3283d20e0ddc5eb8b2b81867dac951b7
5
5
  SHA512:
6
- metadata.gz: b5e388569d319cf4d60add09c4f82fef1510e6de7a1d763b9bf442980157dbd2e251376abf1b21120026732970cd186df5c85cd40ced3b7215a46e31b884840f
7
- data.tar.gz: 6df95518c869b5c12a0f7ac873be2b38359f249a03dbc68020d20199f104d55055df9dc9c1bb51e83165dd3bf241f504362b46fdddd6b100632c2bea0e4a9a96
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
- # blk_or_decl:
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 `nil` if we've finished building the sig
51
- DeclarationBlock = Struct.new(:mod, :method_name, :loc, :blk_or_decl, :final, :abstract, :override, :overridable)
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.blk_or_decl.is_a?(Proc)
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
- method_sig = T::Private::Methods.maybe_run_sig_block_for_key(key)
387
+ callee = Kernel.__callee__ || raise("Unknown __callee__ for method without a signature")
388
+ method_sig = built_sig
361
389
  if !method_sig
362
- callee = __callee__ || raise("Unknown __callee__ for method without a signature")
363
- method_sig = T::Private::Methods.signature_for_method(original_method)
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
- raise "`sig` not present for method `#{callee}` on #{self.inspect} but you're trying to run it anyways. " \
366
- "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. " \
367
- "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."
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
- method_sig = T::Private::Methods._unwrap_alias(
371
- method_sig,
372
- self,
373
- original_method,
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
- unwrap_method(signature.method.owner, signature, original_method)
510
+ if unwrap
511
+ unwrap_method(signature.method.owner, signature, original_method)
512
+ end
455
513
 
456
- # Drop this declaration. Only drop it after we've actually wrapped the
457
- # method and recorded the signature, because that might raise an exception,
458
- # leaving the declaration in a weird state if the program rescues that
459
- # exception and continues.
460
- declaration_block.blk_or_decl = nil
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
- blk_or_decl = declaration_block.blk_or_decl
467
- return blk_or_decl if blk_or_decl.is_a?(Declaration)
468
- if blk_or_decl.nil?
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(&blk_or_decl).finalize!.decl
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.blk_or_decl = decl
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
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sorbet-runtime
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.13393
4
+ version: 0.6.13398
5
5
  platform: ruby
6
6
  authors:
7
7
  - Stripe