sorbet-runtime 0.6.13244 → 0.6.13245
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 +8 -16
- data/lib/types/sig.rb +71 -0
- 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: 2c95e19aa29070164c0a98a1d6d2dcf47c9ea2a5f12e98296d60c001472c1f01
|
|
4
|
+
data.tar.gz: cf5b34fe0327d15854d1115dd13ad26d3d687ae7471c36b18e952d3337dae68f
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 3927fc9602822bfa8f3ee986f90b26f196d123b89d151bbe8141c7c1528a8246528e3bf2f616d78d60f98b26e7dfe7e769f0adeb336c2125f5f9419c6026ec02
|
|
7
|
+
data.tar.gz: '014459f5f1cc56477fe4975e239efbff546d5cdf6bd14058c7d3f3a573d494925d8de5cb8aa7be38ff6344dc47dea247baff2574bb814f0312b8403fbee2580c'
|
|
@@ -51,8 +51,6 @@ module T::Private::Methods
|
|
|
51
51
|
DeclarationBlock = Struct.new(:mod, :loc, :blk_or_decl, :final)
|
|
52
52
|
|
|
53
53
|
def self.declare_sig(mod, loc, arg, &blk)
|
|
54
|
-
install_hooks(mod)
|
|
55
|
-
|
|
56
54
|
if T::Private::DeclState.current.active_declaration
|
|
57
55
|
T::Private::DeclState.current.reset!
|
|
58
56
|
raise "You called sig twice without declaring a method in between"
|
|
@@ -561,24 +559,18 @@ module T::Private::Methods
|
|
|
561
559
|
end
|
|
562
560
|
end
|
|
563
561
|
|
|
562
|
+
# Normally, this should be taken care of by simply `extend T::Sig`.
|
|
563
|
+
#
|
|
564
|
+
# But there are a few cases where we actually want the hooks to be "viral"
|
|
565
|
+
# for final modules and final methods, such that we actually want to forcibly
|
|
566
|
+
# install the hooks even if they would not have naturally been there via
|
|
567
|
+
# inheritance.
|
|
568
|
+
#
|
|
569
|
+
# As such, we don't have to handle quite as many edge cases as `lib/types/sig.rb` does
|
|
564
570
|
def self.install_hooks(mod)
|
|
565
571
|
return if @installed_hooks.include?(mod)
|
|
566
572
|
@installed_hooks[mod] = true
|
|
567
573
|
|
|
568
|
-
if mod == TOP_SELF
|
|
569
|
-
# self at the top-level of a file is weirdly special in Ruby
|
|
570
|
-
# The Ruby VM on startup creates an `Object.new` and stashes it.
|
|
571
|
-
# Unlike when we're using sig inside a module, `self` is actually a
|
|
572
|
-
# normal object, not an instance of Module.
|
|
573
|
-
#
|
|
574
|
-
# Thus we can't ask things like mod.singleton_class? (since that's
|
|
575
|
-
# defined only on Module, not on Object) and even if we could, the places
|
|
576
|
-
# where we need to install the hooks are special.
|
|
577
|
-
mod.extend(SingletonMethodHooks) # def self.foo; end (at top level)
|
|
578
|
-
Object.extend(MethodHooks) # def foo; end (at top level)
|
|
579
|
-
return
|
|
580
|
-
end
|
|
581
|
-
|
|
582
574
|
# See https://github.com/sorbet/sorbet/pull/3964 for an explanation of why this
|
|
583
575
|
# check (which theoretically should not be needed) is actually needed.
|
|
584
576
|
if !mod.is_a?(Module)
|
data/lib/types/sig.rb
CHANGED
|
@@ -4,6 +4,77 @@
|
|
|
4
4
|
# Used as a mixin to any class so that you can call `sig`.
|
|
5
5
|
# Docs at https://sorbet.org/docs/sigs
|
|
6
6
|
module T::Sig
|
|
7
|
+
include T::Private::Methods::MethodHooks
|
|
8
|
+
include T::Private::Methods::SingletonMethodHooks
|
|
9
|
+
|
|
10
|
+
private_class_method def self.included(other)
|
|
11
|
+
return unless Module == other
|
|
12
|
+
|
|
13
|
+
# Module#method_added is normally a no-op method that does not call
|
|
14
|
+
# `super` and immediately returns `nil`. This means that `method_added`
|
|
15
|
+
# methods defined on an ancestor of `Module` are never called, so for
|
|
16
|
+
# `Module` itself, we need to redefine to call `super` to forward to the
|
|
17
|
+
# `method_added` defined above and which is already in the hierarchy.
|
|
18
|
+
#
|
|
19
|
+
# (`singleton_method_added` is defined on `BasicObject`, so ours does
|
|
20
|
+
# override that one.)
|
|
21
|
+
other.prepend(T::Private::Methods::MethodHooks)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
private_class_method def self.extended(other)
|
|
25
|
+
if other == T::Private::Methods::TOP_SELF
|
|
26
|
+
# Methods defined via `def foo; end` at the top-level of a file are
|
|
27
|
+
# actually defined as private instance methods on `Object`, so we have to
|
|
28
|
+
# register our `method_added` hook there.
|
|
29
|
+
#
|
|
30
|
+
# Methods defined via `def self.foo; end` at the top-level are defined on
|
|
31
|
+
# a special instance of `Object` called `main` (initialized by the VM on
|
|
32
|
+
# startup), and putting `extend T::Sig` at the top-level of a file has
|
|
33
|
+
# the effect of putting `singleton_method_added` on the singleton class
|
|
34
|
+
# of `main`, which is catches those methods.
|
|
35
|
+
Object.extend(T::Private::Methods::MethodHooks)
|
|
36
|
+
return
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
return unless Module.===(other) && other.singleton_class?
|
|
40
|
+
|
|
41
|
+
# Given this:
|
|
42
|
+
#
|
|
43
|
+
# class A
|
|
44
|
+
# class << self
|
|
45
|
+
# extend T::Sig
|
|
46
|
+
# end
|
|
47
|
+
# end
|
|
48
|
+
#
|
|
49
|
+
# The `singleton_method_added` hook will end up defined as if
|
|
50
|
+
# `A.singleton_class.singleton_class#singleton_method_added`[1], so methods
|
|
51
|
+
# defined via `def self.` inside the `class << self` will be hooked, but
|
|
52
|
+
# not "instance" methods, because for better or worse Ruby chooses to call
|
|
53
|
+
# `A.singleton_method_added` even for `def foo` (an instance method) inside
|
|
54
|
+
# a `class << self` definition.[2]
|
|
55
|
+
#
|
|
56
|
+
# This forces a problem on users: they need `extend T::Sig` to make `sig`
|
|
57
|
+
# callable at the class body, but they need `include T::Sig` to make sure
|
|
58
|
+
# that the `singleton_method_added` hook lands on the right place. To
|
|
59
|
+
# avoid users needing to do that, we define an extra
|
|
60
|
+
# `singleton_method_added` on the `attached_object` of the singleton
|
|
61
|
+
# class, aka `A.singleton_method_added`.[3]
|
|
62
|
+
#
|
|
63
|
+
# [1] Not actually--it will be in the ancestor chain, but callable on
|
|
64
|
+
# values of that type.
|
|
65
|
+
#
|
|
66
|
+
# [2] I imagine this is for backwards compatibility in the common case of
|
|
67
|
+
# one level of `class << self` nesting, so that people can define a
|
|
68
|
+
# single `singleton_method_added` hook and have it fire for `def
|
|
69
|
+
# self.foo` methods outside and `def foo` inside.
|
|
70
|
+
#
|
|
71
|
+
# [3] Before switching to having the hooks defined eagerly `T::Sig`
|
|
72
|
+
# itself, this was done lazily via `include(SingletonMethodHooks)`
|
|
73
|
+
# instead of `extend(MethodHooks)` on the first call to `sig` inside
|
|
74
|
+
# the `class << self`.
|
|
75
|
+
other.include(T::Private::Methods::SingletonMethodHooks)
|
|
76
|
+
end
|
|
77
|
+
|
|
7
78
|
module WithoutRuntime
|
|
8
79
|
# At runtime, does nothing, but statically it is treated exactly the same
|
|
9
80
|
# as T::Sig#sig. Only use it in cases where you can't use T::Sig#sig.
|