sorbet-runtime 0.4.4667 → 0.5.6189

Sign up to get free protection for your applications and to get access to all the features.
Files changed (70) hide show
  1. checksums.yaml +5 -5
  2. data/lib/sorbet-runtime.rb +15 -3
  3. data/lib/types/_types.rb +26 -17
  4. data/lib/types/boolean.rb +1 -1
  5. data/lib/types/compatibility_patches.rb +65 -10
  6. data/lib/types/configuration.rb +93 -7
  7. data/lib/types/enum.rb +371 -0
  8. data/lib/types/generic.rb +2 -2
  9. data/lib/types/interface_wrapper.rb +4 -4
  10. data/lib/types/non_forcing_constants.rb +61 -0
  11. data/lib/types/private/abstract/data.rb +2 -2
  12. data/lib/types/private/abstract/declare.rb +3 -0
  13. data/lib/types/private/abstract/validate.rb +7 -7
  14. data/lib/types/private/casts.rb +27 -0
  15. data/lib/types/private/class_utils.rb +8 -5
  16. data/lib/types/private/methods/_methods.rb +80 -28
  17. data/lib/types/private/methods/call_validation.rb +5 -47
  18. data/lib/types/private/methods/decl_builder.rb +14 -56
  19. data/lib/types/private/methods/modes.rb +5 -7
  20. data/lib/types/private/methods/signature.rb +32 -18
  21. data/lib/types/private/methods/signature_validation.rb +29 -35
  22. data/lib/types/private/retry.rb +10 -0
  23. data/lib/types/private/sealed.rb +21 -1
  24. data/lib/types/private/types/type_alias.rb +31 -0
  25. data/lib/types/private/types/void.rb +4 -3
  26. data/lib/types/profile.rb +5 -1
  27. data/lib/types/props/_props.rb +3 -7
  28. data/lib/types/props/constructor.rb +29 -9
  29. data/lib/types/props/custom_type.rb +51 -27
  30. data/lib/types/props/decorator.rb +248 -405
  31. data/lib/types/props/generated_code_validation.rb +268 -0
  32. data/lib/types/props/has_lazily_specialized_methods.rb +92 -0
  33. data/lib/types/props/optional.rb +37 -41
  34. data/lib/types/props/plugin.rb +23 -1
  35. data/lib/types/props/pretty_printable.rb +3 -3
  36. data/lib/types/props/private/apply_default.rb +170 -0
  37. data/lib/types/props/private/deserializer_generator.rb +165 -0
  38. data/lib/types/props/private/parser.rb +32 -0
  39. data/lib/types/props/private/serde_transform.rb +186 -0
  40. data/lib/types/props/private/serializer_generator.rb +77 -0
  41. data/lib/types/props/private/setter_factory.rb +139 -0
  42. data/lib/types/props/serializable.rb +137 -192
  43. data/lib/types/props/type_validation.rb +19 -6
  44. data/lib/types/props/utils.rb +3 -7
  45. data/lib/types/props/weak_constructor.rb +51 -14
  46. data/lib/types/sig.rb +6 -6
  47. data/lib/types/types/attached_class.rb +37 -0
  48. data/lib/types/types/base.rb +26 -2
  49. data/lib/types/types/fixed_array.rb +28 -2
  50. data/lib/types/types/fixed_hash.rb +11 -10
  51. data/lib/types/types/intersection.rb +6 -0
  52. data/lib/types/types/noreturn.rb +4 -0
  53. data/lib/types/types/self_type.rb +4 -0
  54. data/lib/types/types/simple.rb +22 -1
  55. data/lib/types/types/t_enum.rb +38 -0
  56. data/lib/types/types/type_parameter.rb +1 -1
  57. data/lib/types/types/type_variable.rb +1 -1
  58. data/lib/types/types/typed_array.rb +7 -2
  59. data/lib/types/types/typed_enumerable.rb +28 -17
  60. data/lib/types/types/typed_enumerator.rb +7 -2
  61. data/lib/types/types/typed_hash.rb +8 -3
  62. data/lib/types/types/typed_range.rb +7 -2
  63. data/lib/types/types/typed_set.rb +7 -2
  64. data/lib/types/types/union.rb +37 -5
  65. data/lib/types/types/untyped.rb +4 -0
  66. data/lib/types/utils.rb +43 -11
  67. metadata +103 -11
  68. data/lib/types/private/error_handler.rb +0 -0
  69. data/lib/types/runtime_profiled.rb +0 -24
  70. data/lib/types/types/opus_enum.rb +0 -33
@@ -2,7 +2,7 @@
2
2
  # typed: true
3
3
 
4
4
  module T::Private::Methods
5
- Declaration = Struct.new(:mod, :params, :returns, :bind, :mode, :checked, :finalized, :on_failure, :override_allow_incompatible, :type_parameters, :generated)
5
+ Declaration = Struct.new(:mod, :params, :returns, :bind, :mode, :checked, :finalized, :on_failure, :override_allow_incompatible, :type_parameters)
6
6
 
7
7
  class DeclBuilder
8
8
  attr_reader :decl
@@ -28,16 +28,18 @@ module T::Private::Methods
28
28
  ARG_NOT_PROVIDED, # on_failure
29
29
  nil, # override_allow_incompatible
30
30
  ARG_NOT_PROVIDED, # type_parameters
31
- ARG_NOT_PROVIDED, # generated
32
31
  )
33
32
  end
34
33
 
35
- def params(params)
34
+ def params(**params)
36
35
  check_live!
37
36
  if !decl.params.equal?(ARG_NOT_PROVIDED)
38
37
  raise BuilderError.new("You can't call .params twice")
39
38
  end
40
39
 
40
+ if params.empty?
41
+ raise BuilderError.new("params expects keyword arguments")
42
+ end
41
43
  decl.params = params
42
44
 
43
45
  self
@@ -88,9 +90,6 @@ module T::Private::Methods
88
90
  if level == :never && !decl.on_failure.equal?(ARG_NOT_PROVIDED)
89
91
  raise BuilderError.new("You can't use .checked(:never) with .on_failure because .on_failure will have no effect.")
90
92
  end
91
- if !decl.generated.equal?(ARG_NOT_PROVIDED)
92
- raise BuilderError.new("You can't use .checked with .generated.")
93
- end
94
93
  if !T::Private::RuntimeLevels::LEVELS.include?(level)
95
94
  raise BuilderError.new("Invalid `checked` level '#{level}'. Use one of: #{T::Private::RuntimeLevels::LEVELS}.")
96
95
  end
@@ -109,33 +108,12 @@ module T::Private::Methods
109
108
  if decl.checked == :never
110
109
  raise BuilderError.new("You can't use .on_failure with .checked(:never) because .on_failure will have no effect.")
111
110
  end
112
- if !decl.generated.equal?(ARG_NOT_PROVIDED)
113
- raise BuilderError.new("You can't use .on_failure with .generated.")
114
- end
115
111
 
116
112
  decl.on_failure = args
117
113
 
118
114
  self
119
115
  end
120
116
 
121
- def generated
122
- check_live!
123
-
124
- if !decl.generated.equal?(ARG_NOT_PROVIDED)
125
- raise BuilderError.new("You can't call .generated multiple times in a signature.")
126
- end
127
- if !decl.checked.equal?(ARG_NOT_PROVIDED)
128
- raise BuilderError.new("You can't use .generated with .checked.")
129
- end
130
- if !decl.on_failure.equal?(ARG_NOT_PROVIDED)
131
- raise BuilderError.new("You can't use .generated with .on_failure.")
132
- end
133
-
134
- decl.generated = true
135
-
136
- self
137
- end
138
-
139
117
  def abstract
140
118
  check_live!
141
119
 
@@ -145,8 +123,7 @@ module T::Private::Methods
145
123
  when Modes.abstract
146
124
  raise BuilderError.new(".abstract cannot be repeated in a single signature")
147
125
  else
148
- raise BuilderError.new("`.abstract` cannot be combined with any of `.override`, `.implementation`, or "\
149
- "`.overridable`.")
126
+ raise BuilderError.new("`.abstract` cannot be combined with `.override` or `.overridable`.")
150
127
  end
151
128
 
152
129
  self
@@ -164,11 +141,12 @@ module T::Private::Methods
164
141
  when Modes.standard
165
142
  decl.mode = Modes.override
166
143
  decl.override_allow_incompatible = allow_incompatible
167
- when Modes.override
144
+ when Modes.override, Modes.overridable_override
168
145
  raise BuilderError.new(".override cannot be repeated in a single signature")
146
+ when Modes.overridable
147
+ decl.mode = Modes.overridable_override
169
148
  else
170
- raise BuilderError.new("`.override` cannot be combined with any of `.abstract`, `.implementation`, or "\
171
- "`.overridable`.")
149
+ raise BuilderError.new("`.override` cannot be combined with `.abstract`.")
172
150
  end
173
151
 
174
152
  self
@@ -178,36 +156,19 @@ module T::Private::Methods
178
156
  check_live!
179
157
 
180
158
  case decl.mode
181
- when Modes.abstract, Modes.override
159
+ when Modes.abstract
182
160
  raise BuilderError.new("`.overridable` cannot be combined with `.#{decl.mode}`")
161
+ when Modes.override
162
+ decl.mode = Modes.overridable_override
183
163
  when Modes.standard
184
164
  decl.mode = Modes.overridable
185
- when Modes.implementation
186
- decl.mode = Modes.overridable_implementation
187
- when Modes.overridable, Modes.overridable_implementation
165
+ when Modes.overridable, Modes.overridable_override
188
166
  raise BuilderError.new(".overridable cannot be repeated in a single signature")
189
167
  end
190
168
 
191
169
  self
192
170
  end
193
171
 
194
- def implementation
195
- check_live!
196
-
197
- case decl.mode
198
- when Modes.abstract, Modes.override
199
- raise BuilderError.new("`.implementation` cannot be combined with `.#{decl.mode}`")
200
- when Modes.standard
201
- decl.mode = Modes.implementation
202
- when Modes.overridable
203
- decl.mode = Modes.overridable_implementation
204
- when Modes.implementation, Modes.overridable_implementation
205
- raise BuilderError.new(".implementation cannot be repeated in a single signature")
206
- end
207
-
208
- self
209
- end
210
-
211
172
  # Declares valid type paramaters which can be used with `T.type_parameter` in
212
173
  # this `sig`.
213
174
  #
@@ -255,9 +216,6 @@ module T::Private::Methods
255
216
  if decl.on_failure.equal?(ARG_NOT_PROVIDED)
256
217
  decl.on_failure = nil
257
218
  end
258
- if decl.generated.equal?(ARG_NOT_PROVIDED)
259
- decl.generated = false
260
- end
261
219
  if decl.params.equal?(ARG_NOT_PROVIDED)
262
220
  decl.params = {}
263
221
  end
@@ -5,14 +5,12 @@ module T::Private::Methods::Modes
5
5
  def self.standard; 'standard'; end
6
6
  def self.abstract; 'abstract'; end
7
7
  def self.overridable; 'overridable'; end
8
- def self.implementation; 'implementation'; end
9
8
  def self.override; 'override'; end
10
- def self.overridable_implementation; 'overridable_implementation'; end
9
+ def self.overridable_override; 'overridable_override'; end
11
10
  def self.untyped; 'untyped'; end
12
- MODES = [self.standard, self.abstract, self.overridable, self.implementation, self.override, self.overridable_implementation, self.untyped]
11
+ MODES = [self.standard, self.abstract, self.overridable, self.override, self.overridable_override, self.untyped].freeze
13
12
 
14
- IMPLEMENT_MODES = [self.implementation, self.overridable_implementation]
15
- OVERRIDABLE_MODES = [self.override, self.overridable, self.overridable_implementation, self.untyped]
16
- OVERRIDE_MODES = [self.override]
17
- NON_OVERRIDE_MODES = MODES - OVERRIDE_MODES - IMPLEMENT_MODES
13
+ OVERRIDABLE_MODES = [self.override, self.overridable, self.overridable_override, self.untyped, self.abstract].freeze
14
+ OVERRIDE_MODES = [self.override, self.overridable_override].freeze
15
+ NON_OVERRIDE_MODES = MODES - OVERRIDE_MODES
18
16
  end
@@ -5,7 +5,7 @@ class T::Private::Methods::Signature
5
5
  attr_reader :method, :method_name, :arg_types, :kwarg_types, :block_type, :block_name,
6
6
  :rest_type, :rest_name, :keyrest_type, :keyrest_name, :bind,
7
7
  :return_type, :mode, :req_arg_count, :req_kwarg_names, :has_rest, :has_keyrest,
8
- :check_level, :generated, :parameters, :on_failure, :override_allow_incompatible, :ever_failed
8
+ :check_level, :parameters, :on_failure, :override_allow_incompatible
9
9
 
10
10
  def self.new_untyped(method:, mode: T::Private::Methods::Modes.untyped, parameters: method.parameters)
11
11
  # Using `Untyped` ensures we'll get an error if we ever try validation on these.
@@ -28,11 +28,7 @@ class T::Private::Methods::Signature
28
28
  )
29
29
  end
30
30
 
31
- def mark_failed
32
- @ever_failed = true
33
- end
34
-
35
- def initialize(method:, method_name:, raw_arg_types:, raw_return_type:, bind:, mode:, check_level:, parameters: method.parameters, on_failure:, generated: false, override_allow_incompatible: false)
31
+ def initialize(method:, method_name:, raw_arg_types:, raw_return_type:, bind:, mode:, check_level:, on_failure:, parameters: method.parameters, override_allow_incompatible: false)
36
32
  @method = method
37
33
  @method_name = method_name
38
34
  @arg_types = []
@@ -54,11 +50,15 @@ class T::Private::Methods::Signature
54
50
  @parameters = parameters
55
51
  @on_failure = on_failure
56
52
  @override_allow_incompatible = override_allow_incompatible
57
- @generated = generated
58
- @ever_failed = false
59
53
 
60
- param_names = parameters.map {|_, name| name}
61
54
  declared_param_names = raw_arg_types.keys
55
+ # If sig params are declared but there is a single parameter with a missing name
56
+ # **and** the method ends with a "=", assume it is a writer method generated
57
+ # by attr_writer or attr_accessor
58
+ writer_method = declared_param_names != [nil] && parameters == [[:req]] && method_name[-1] == "="
59
+ # For writer methods, map the single parameter to the method name without the "=" at the end
60
+ parameters = [[:req, method_name[0...-1].to_sym]] if writer_method
61
+ param_names = parameters.map {|_, name| name}
62
62
  missing_names = param_names - declared_param_names
63
63
  extra_names = declared_param_names - param_names
64
64
  if !missing_names.empty?
@@ -68,6 +68,10 @@ class T::Private::Methods::Signature
68
68
  raise "The declaration for `#{method.name}` has extra parameter(s): #{extra_names.join(', ')}"
69
69
  end
70
70
 
71
+ if parameters.size != raw_arg_types.size
72
+ raise "The declaration for `#{method.name}` has arguments with duplicate names"
73
+ end
74
+
71
75
  parameters.zip(raw_arg_types) do |(param_kind, param_name), (type_name, raw_type)|
72
76
  if type_name != param_name
73
77
  hint = ""
@@ -121,6 +125,15 @@ class T::Private::Methods::Signature
121
125
  end
122
126
  end
123
127
 
128
+ attr_writer :method_name
129
+ protected :method_name=
130
+
131
+ def as_alias(alias_name)
132
+ new_sig = clone
133
+ new_sig.method_name = alias_name
134
+ new_sig
135
+ end
136
+
124
137
  def arg_count
125
138
  @arg_types.length
126
139
  end
@@ -146,9 +159,10 @@ class T::Private::Methods::Signature
146
159
  # can't) match the definition of the method we're validating. In addition, Ruby has a bug that
147
160
  # causes forwarding **kwargs to do the wrong thing: see https://bugs.ruby-lang.org/issues/10708
148
161
  # and https://bugs.ruby-lang.org/issues/11860.
149
- if (args.length > @req_arg_count) && (!@kwarg_types.empty? || @has_keyrest) && args[-1].is_a?(Hash)
162
+ args_length = args.length
163
+ if (args_length > @req_arg_count) && (!@kwarg_types.empty? || @has_keyrest) && args[-1].is_a?(Hash)
150
164
  kwargs = args[-1]
151
- args = args[0...-1]
165
+ args_length -= 1
152
166
  else
153
167
  kwargs = EMPTY_HASH
154
168
  end
@@ -156,19 +170,19 @@ class T::Private::Methods::Signature
156
170
  arg_types = @arg_types
157
171
 
158
172
  if @has_rest
159
- arg_types += [[@rest_name, @rest_type]] * (args.length - @arg_types.length)
173
+ arg_types += [[@rest_name, @rest_type]] * (args_length - @arg_types.length)
160
174
 
161
- elsif (args.length < @req_arg_count) || (args.length > @arg_types.length)
175
+ elsif (args_length < @req_arg_count) || (args_length > @arg_types.length)
162
176
  expected_str = @req_arg_count.to_s
163
177
  if @arg_types.length != @req_arg_count
164
178
  expected_str += "..#{@arg_types.length}"
165
179
  end
166
- raise ArgumentError.new("wrong number of arguments (given #{args.length}, expected #{expected_str})")
180
+ raise ArgumentError.new("wrong number of arguments (given #{args_length}, expected #{expected_str})")
167
181
  end
168
182
 
169
183
  begin
170
184
  it = 0
171
- while it < args.length
185
+ while it < args_length
172
186
  yield arg_types[it][0], args[it], arg_types[it][1]
173
187
  it += 1
174
188
  end
@@ -184,10 +198,10 @@ class T::Private::Methods::Signature
184
198
  end
185
199
 
186
200
  def method_desc
187
- if @method.source_location
188
- loc = @method.source_location.join(':')
201
+ loc = if @method.source_location
202
+ @method.source_location.join(':')
189
203
  else
190
- loc = "<unknown location>"
204
+ "<unknown location>"
191
205
  end
192
206
  "#{@method} at #{loc}"
193
207
  end
@@ -48,8 +48,8 @@ module T::Private::Methods::SignatureValidation
48
48
  end
49
49
 
50
50
  private_class_method def self.pretty_mode(signature)
51
- if signature.mode == Modes.overridable_implementation
52
- '.overridable.implementation'
51
+ if signature.mode == Modes.overridable_override
52
+ '.overridable.override'
53
53
  else
54
54
  ".#{signature.mode}"
55
55
  end
@@ -58,22 +58,12 @@ module T::Private::Methods::SignatureValidation
58
58
  def self.validate_override_mode(signature, super_signature)
59
59
  case signature.mode
60
60
  when *Modes::OVERRIDE_MODES
61
- if !Modes::OVERRIDABLE_MODES.include?(super_signature.mode)
62
- raise "You declared `#{signature.method_name}` as #{pretty_mode(signature)}, but the method it overrides is not declared as `overridable`.\n" \
63
- " Parent definition: #{method_loc_str(super_signature.method)}\n" \
64
- " Child definition: #{method_loc_str(signature.method)}\n"
65
- end
66
- when *Modes::IMPLEMENT_MODES
67
- if super_signature.mode != Modes.abstract
68
- raise "You declared `#{signature.method_name}` as #{pretty_mode(signature)}, but the method it overrides is not declared as abstract.\n" \
69
- " Either mark #{super_signature.method_name} as `abstract.` in the parent: #{method_loc_str(super_signature.method)}\n" \
70
- " ... or mark #{signature.method_name} as `override.` in the child: #{method_loc_str(signature.method)}\n"
71
- end
61
+ # Peaceful
72
62
  when *Modes::NON_OVERRIDE_MODES
73
63
  if super_signature.mode == Modes.standard
74
64
  # Peaceful
75
65
  elsif super_signature.mode == Modes.abstract
76
- raise "You must use `.implementation` when overriding the abstract method `#{signature.method_name}`.\n" \
66
+ raise "You must use `.override` when overriding the abstract method `#{signature.method_name}`.\n" \
77
67
  " Abstract definition: #{method_loc_str(super_signature.method)}\n" \
78
68
  " Implementation definition: #{method_loc_str(signature.method)}\n"
79
69
  elsif super_signature.mode != Modes.untyped
@@ -89,33 +79,37 @@ module T::Private::Methods::SignatureValidation
89
79
  def self.validate_non_override_mode(signature)
90
80
  case signature.mode
91
81
  when Modes.override
92
- raise "You marked `#{signature.method_name}` as #{pretty_mode(signature)}, but that method doesn't already exist in this class/module to be overriden.\n" \
93
- " Either check for typos and for missing includes or super classes to make the parent method shows up\n" \
94
- " ... or remove #{pretty_mode(signature)} here: #{method_loc_str(signature.method)}\n"
82
+ if signature.method_name == :each && signature.method.owner < Enumerable
83
+ # Enumerable#each is the only method in Sorbet's RBI payload that defines an abstract method.
84
+ # Enumerable#each does not actually exist at runtime, but it is required to be implemented by
85
+ # any class which includes Enumerable. We want to declare Enumerable#each as abstract so that
86
+ # people can call it anything which implements the Enumerable interface, and so that it's a
87
+ # static error to forget to implement it.
88
+ #
89
+ # This is a one-off hack, and we should think carefully before adding more methods here.
90
+ nil
91
+ else
92
+ raise "You marked `#{signature.method_name}` as #{pretty_mode(signature)}, but that method doesn't already exist in this class/module to be overriden.\n" \
93
+ " Either check for typos and for missing includes or super classes to make the parent method shows up\n" \
94
+ " ... or remove #{pretty_mode(signature)} here: #{method_loc_str(signature.method)}\n"
95
+ end
95
96
  when Modes.standard, *Modes::NON_OVERRIDE_MODES
96
97
  # Peaceful
97
98
  nil
98
- when *Modes::IMPLEMENT_MODES
99
- raise "You marked `#{signature.method_name}` as #{pretty_mode(signature)}, but it doesn't match up with a corresponding abstract method.\n" \
100
- " Either check for typos and for missing includes or super classes to make the parent method shows up\n" \
101
- " ... or remove #{pretty_mode(signature)} here: #{method_loc_str(signature.method)}\n"
102
99
  else
103
100
  raise "Unexpected mode: #{signature.mode}. Please report to #dev-productivity."
104
101
  end
105
102
 
103
+ # Given a singleton class, we can check if it belongs to a
104
+ # module by looking at its superclass; given `module M`,
105
+ # `M.singleton_class.superclass == Module`, which is not true
106
+ # for any class.
106
107
  owner = signature.method.owner
107
108
  if (signature.mode == Modes.abstract || Modes::OVERRIDABLE_MODES.include?(signature.mode)) &&
108
- owner.singleton_class?
109
- # Given a singleton class, we can check if it belongs to a
110
- # module by looking at its superclass; given `module M`,
111
- # `M.singleton_class.superclass == Module`, which is not true
112
- # for any class.
113
- if owner.superclass == Module
114
- raise "Defining an overridable class method (via #{pretty_mode(signature)}) " \
115
- "on a module is not allowed. Class methods on " \
116
- "modules do not get inherited and thus cannot be overridden. For help, ask in " \
117
- "#dev-productivity."
118
- end
109
+ owner.singleton_class? && owner.superclass == Module
110
+ raise "Defining an overridable class method (via #{pretty_mode(signature)}) " \
111
+ "on a module is not allowed. Class methods on " \
112
+ "modules do not get inherited and thus cannot be overridden."
119
113
  end
120
114
  end
121
115
 
@@ -222,10 +216,10 @@ module T::Private::Methods::SignatureValidation
222
216
  end
223
217
 
224
218
  private_class_method def self.method_loc_str(method)
225
- if method.source_location
226
- loc = method.source_location.join(':')
219
+ loc = if method.source_location
220
+ method.source_location.join(':')
227
221
  else
228
- loc = "<unknown location>"
222
+ "<unknown location>"
229
223
  end
230
224
  "#{method.owner} at #{loc}"
231
225
  end
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+ # typed: true
3
+
4
+ module T::Private::Retry
5
+
6
+ # A special singleton used for static analysis of exceptions.
7
+ module RETRY
8
+ freeze
9
+ end
10
+ end
@@ -7,6 +7,11 @@ module T::Private::Sealed
7
7
  super
8
8
  this_line = Kernel.caller.find {|line| !line.match(/in `inherited'$/)}
9
9
  T::Private::Sealed.validate_inheritance(this_line, self, 'inherited')
10
+ @sorbet_sealed_module_all_subclasses << other
11
+ end
12
+
13
+ def sealed_subclasses
14
+ @sorbet_sealed_module_all_subclasses
10
15
  end
11
16
  end
12
17
 
@@ -15,12 +20,21 @@ module T::Private::Sealed
15
20
  super
16
21
  this_line = Kernel.caller.find {|line| !line.match(/in `included'$/)}
17
22
  T::Private::Sealed.validate_inheritance(this_line, self, 'included')
23
+ @sorbet_sealed_module_all_subclasses << other
18
24
  end
19
25
 
20
26
  def extended(other)
21
27
  super
22
28
  this_line = Kernel.caller.find {|line| !line.match(/in `extended'$/)}
23
29
  T::Private::Sealed.validate_inheritance(this_line, self, 'extended')
30
+ @sorbet_sealed_module_all_subclasses << other
31
+ end
32
+
33
+ def sealed_subclasses
34
+ # this will freeze the set so that you can never get into a
35
+ # state where you use the subclasses list and then something
36
+ # else will add to it
37
+ @sorbet_sealed_module_all_subclasses.freeze
24
38
  end
25
39
  end
26
40
 
@@ -39,6 +53,7 @@ module T::Private::Sealed
39
53
  raise "Couldn't determine declaration file for sealed class."
40
54
  end
41
55
  mod.instance_variable_set(:@sorbet_sealed_module_decl_file, decl_file)
56
+ mod.instance_variable_set(:@sorbet_sealed_module_all_subclasses, Set.new)
42
57
  end
43
58
 
44
59
  def self.sealed_module?(mod)
@@ -46,7 +61,7 @@ module T::Private::Sealed
46
61
  end
47
62
 
48
63
  def self.validate_inheritance(this_line, parent, verb)
49
- this_file = this_line&.split(':').first
64
+ this_file = this_line&.split(':')&.first
50
65
  decl_file = parent.instance_variable_get(:@sorbet_sealed_module_decl_file)
51
66
 
52
67
  if !this_file || !decl_file
@@ -54,6 +69,11 @@ module T::Private::Sealed
54
69
  end
55
70
 
56
71
  if !this_file.start_with?(decl_file)
72
+ whitelist = T::Configuration.sealed_violation_whitelist
73
+ if !whitelist.nil? && whitelist.any? {|pattern| this_file =~ pattern}
74
+ return
75
+ end
76
+
57
77
  raise "#{parent} was declared sealed and can only be #{verb} in #{decl_file}, not #{this_file}"
58
78
  end
59
79
  end