sorbet-runtime 0.5.10470 → 0.5.10473

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: 379d84e84abe1b5c02ec69fa64d931ad61c1b8d52e9f9fc03dc4123c37f3299f
4
- data.tar.gz: 3531d39402cd628392b8a17a80c207fcfc0ac3a82c3409e6445da8178fc87fc9
3
+ metadata.gz: b189a0adf5472e2cae48a050abe2697c03c44048fd3c59b1f104928ed09771d2
4
+ data.tar.gz: 7aa59c471cf94a8539c610c96b11f36884da152d2b6e37e6f8fb630c781b51fb
5
5
  SHA512:
6
- metadata.gz: edd9ae63bc0220474cf4210514ed2563e7b77eab79704a9e845f23d8a1023ae13238159bddba0174de7467f2dffc05757c4c346a0a4fa0fc5605ffb571b78849
7
- data.tar.gz: bb5e4c7796c5270f49e1b935ae4627c2e6891f2b39eb4adca3421964c8819e7c61e77fa1c2ae590d38810dc5936dd391dce13447565e508ce06179f53167bf65
6
+ metadata.gz: 8cfcd118c9529eb878a9838deb129d246c7594030553a448116b6f6c30250476367aa2a19ff3b555ba58398b25827fbb7d3d82c45ef267d01076f6810bdcf95d
7
+ data.tar.gz: 8848028f5f9dd560ce4600a8ff8ead2bf9eb05dc969897bc714f6a6868e5f73fbb36ed3c73979da0f01ead482d1f4a5c4bb0b1d04edde09190f5ba26f6ed1af8
@@ -55,6 +55,7 @@ require_relative 'types/private/types/not_typed'
55
55
  require_relative 'types/private/types/void'
56
56
  require_relative 'types/private/types/string_holder'
57
57
  require_relative 'types/private/types/type_alias'
58
+ require_relative 'types/private/types/simple_pair_union'
58
59
 
59
60
  require_relative 'types/types/type_variable'
60
61
  require_relative 'types/types/type_member'
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+ # typed: true
3
+
4
+ # Specialization of Union for the common case of the union of two simple types.
5
+ #
6
+ # This covers e.g. T.nilable(SomeModule), T.any(Integer, Float), and T::Boolean.
7
+ class T::Private::Types::SimplePairUnion < T::Types::Union
8
+ class DuplicateType < RuntimeError; end
9
+
10
+ # @param type_a [T::Types::Simple]
11
+ # @param type_b [T::Types::Simple]
12
+ def initialize(type_a, type_b)
13
+ if type_a == type_b
14
+ raise DuplicateType.new("#{type_a} == #{type_b}")
15
+ end
16
+
17
+ @raw_a = type_a.raw_type
18
+ @raw_b = type_b.raw_type
19
+ end
20
+
21
+ # @override Union
22
+ def recursively_valid?(obj)
23
+ obj.is_a?(@raw_a) || obj.is_a?(@raw_b)
24
+ end
25
+
26
+ # @override Union
27
+ def valid?(obj)
28
+ obj.is_a?(@raw_a) || obj.is_a?(@raw_b)
29
+ end
30
+
31
+ # @override Union
32
+ def types
33
+ # We reconstruct the simple types rather than just storing them because
34
+ # (1) this is normally not a hot path and (2) we want to keep the instance
35
+ # variable count <= 3 so that we can fit in a 40 byte heap entry along
36
+ # with object headers.
37
+ @types ||= [
38
+ T::Types::Simple::Private::Pool.type_for_module(@raw_a),
39
+ T::Types::Simple::Private::Pool.type_for_module(@raw_b),
40
+ ]
41
+ end
42
+ end
@@ -163,8 +163,12 @@ module T::Types
163
163
  # Type equivalence, defined by serializing the type to a string (with
164
164
  # `#name`) and comparing the resulting strings for equality.
165
165
  def ==(other)
166
- (T::Utils.resolve_alias(other).class == T::Utils.resolve_alias(self).class) &&
166
+ case other
167
+ when T::Types::Base
167
168
  other.name == self.name
169
+ else
170
+ false
171
+ end
168
172
  end
169
173
 
170
174
  alias_method :eql?, :==
@@ -52,7 +52,10 @@ module T::Types
52
52
  end
53
53
 
54
54
  def to_nilable
55
- @nilable ||= T::Types::Union.new([self, T::Utils::Nilable::NIL_TYPE])
55
+ @nilable ||= T::Private::Types::SimplePairUnion.new(
56
+ self,
57
+ T::Utils::Nilable::NIL_TYPE,
58
+ )
56
59
  end
57
60
 
58
61
  module Private
@@ -6,6 +6,8 @@ module T::Types
6
6
  class Union < Base
7
7
  attr_reader :types
8
8
 
9
+ # Don't use Union.new directly, use `Private::Pool.union_of_types`
10
+ # inside sorbet-runtime and `T.any` elsewhere.
9
11
  def initialize(types)
10
12
  @types = types.flat_map do |type|
11
13
  type = T::Utils.coerce(type)
@@ -20,11 +22,16 @@ module T::Types
20
22
 
21
23
  # overrides Base
22
24
  def name
23
- type_shortcuts(@types)
25
+ # Use the attr_reader here so we can override it in SimplePairUnion
26
+ type_shortcuts(types)
24
27
  end
25
28
 
26
29
  private def type_shortcuts(types)
27
30
  if types.size == 1
31
+ # We shouldn't generally get here but it's possible if initializing the type
32
+ # evades Sorbet's static check and we end up on the slow path, or if someone
33
+ # is using the T:Types::Union constructor directly (the latter possibility
34
+ # is why we don't just move the `uniq` into `Private::Pool.union_of_types`).
28
35
  return types[0].name
29
36
  end
30
37
  nilable = T::Utils.coerce(NilClass)
@@ -62,27 +69,45 @@ module T::Types
62
69
  EMPTY_ARRAY = [].freeze
63
70
  private_constant :EMPTY_ARRAY
64
71
 
72
+ # Try to use `to_nilable` on a type to get memoization, or failing that
73
+ # try to at least use SimplePairUnion to get faster init and typechecking.
74
+ #
75
+ # We aren't guaranteed to detect a simple `T.nilable(<Module>)` type here
76
+ # in cases where there are duplicate types, nested unions, etc.
77
+ #
78
+ # That's ok, because returning is SimplePairUnion an optimization which
79
+ # isn't necessary for correctness.
80
+ #
65
81
  # @param type_a [T::Types::Base]
66
82
  # @param type_b [T::Types::Base]
67
83
  # @param types [Array] optional array of additional T::Types::Base instances
68
84
  def self.union_of_types(type_a, type_b, types=EMPTY_ARRAY)
69
- if types.empty?
70
- # We aren't guaranteed to detect a simple `T.nilable(<Module>)` type here
71
- # in cases where there are duplicate types, nested unions, etc.
72
- #
73
- # That's ok, because this is an optimization which isn't necessary for
74
- # correctness.
75
- if type_b == T::Utils::Nilable::NIL_TYPE && type_a.is_a?(T::Types::Simple)
85
+ if !types.empty?
86
+ # Slow path
87
+ return Union.new([type_a, type_b] + types)
88
+ elsif !type_a.is_a?(T::Types::Simple) || !type_b.is_a?(T::Types::Simple)
89
+ # Slow path
90
+ return Union.new([type_a, type_b])
91
+ end
92
+
93
+ begin
94
+ if type_b == T::Utils::Nilable::NIL_TYPE
76
95
  type_a.to_nilable
77
- elsif type_a == T::Utils::Nilable::NIL_TYPE && type_b.is_a?(T::Types::Simple)
96
+ elsif type_a == T::Utils::Nilable::NIL_TYPE
78
97
  type_b.to_nilable
79
98
  else
80
- Union.new([type_a, type_b])
99
+ T::Private::Types::SimplePairUnion.new(type_a, type_b)
81
100
  end
82
- else
83
- # This can't be a `T.nilable(<Module>)` case unless there are duplicates,
84
- # which is possible but unexpected.
85
- Union.new([type_a, type_b] + types)
101
+ rescue T::Private::Types::SimplePairUnion::DuplicateType
102
+ # Slow path
103
+ #
104
+ # This shouldn't normally be possible due to static checks,
105
+ # but we can get here if we're constructing a type dynamically.
106
+ #
107
+ # Relying on the duplicate check in the constructor has the
108
+ # advantage that we avoid it when we hit the memoized case
109
+ # of `to_nilable`.
110
+ type_a
86
111
  end
87
112
  end
88
113
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sorbet-runtime
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.10470
4
+ version: 0.5.10473
5
5
  platform: ruby
6
6
  authors:
7
7
  - Stripe
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-09-30 00:00:00.000000000 Z
11
+ date: 2022-10-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: minitest
@@ -189,6 +189,7 @@ files:
189
189
  - lib/types/private/runtime_levels.rb
190
190
  - lib/types/private/sealed.rb
191
191
  - lib/types/private/types/not_typed.rb
192
+ - lib/types/private/types/simple_pair_union.rb
192
193
  - lib/types/private/types/string_holder.rb
193
194
  - lib/types/private/types/type_alias.rb
194
195
  - lib/types/private/types/void.rb