sorbet-runtime 0.5.10470 → 0.5.10473

Sign up to get free protection for your applications and to get access to all the features.
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