sorbet-runtime 0.5.5841
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 +7 -0
- data/lib/sorbet-runtime.rb +116 -0
- data/lib/types/_types.rb +285 -0
- data/lib/types/abstract_utils.rb +50 -0
- data/lib/types/boolean.rb +8 -0
- data/lib/types/compatibility_patches.rb +95 -0
- data/lib/types/configuration.rb +428 -0
- data/lib/types/enum.rb +349 -0
- data/lib/types/generic.rb +23 -0
- data/lib/types/helpers.rb +39 -0
- data/lib/types/interface_wrapper.rb +158 -0
- data/lib/types/non_forcing_constants.rb +51 -0
- data/lib/types/private/abstract/data.rb +36 -0
- data/lib/types/private/abstract/declare.rb +48 -0
- data/lib/types/private/abstract/hooks.rb +43 -0
- data/lib/types/private/abstract/validate.rb +128 -0
- data/lib/types/private/casts.rb +22 -0
- data/lib/types/private/class_utils.rb +111 -0
- data/lib/types/private/decl_state.rb +30 -0
- data/lib/types/private/final.rb +51 -0
- data/lib/types/private/methods/_methods.rb +460 -0
- data/lib/types/private/methods/call_validation.rb +1149 -0
- data/lib/types/private/methods/decl_builder.rb +228 -0
- data/lib/types/private/methods/modes.rb +16 -0
- data/lib/types/private/methods/signature.rb +196 -0
- data/lib/types/private/methods/signature_validation.rb +229 -0
- data/lib/types/private/mixins/mixins.rb +27 -0
- data/lib/types/private/retry.rb +10 -0
- data/lib/types/private/runtime_levels.rb +56 -0
- data/lib/types/private/sealed.rb +65 -0
- data/lib/types/private/types/not_typed.rb +23 -0
- data/lib/types/private/types/string_holder.rb +26 -0
- data/lib/types/private/types/type_alias.rb +26 -0
- data/lib/types/private/types/void.rb +34 -0
- data/lib/types/profile.rb +31 -0
- data/lib/types/props/_props.rb +161 -0
- data/lib/types/props/constructor.rb +40 -0
- data/lib/types/props/custom_type.rb +108 -0
- data/lib/types/props/decorator.rb +672 -0
- data/lib/types/props/errors.rb +8 -0
- data/lib/types/props/generated_code_validation.rb +268 -0
- data/lib/types/props/has_lazily_specialized_methods.rb +92 -0
- data/lib/types/props/optional.rb +81 -0
- data/lib/types/props/plugin.rb +37 -0
- data/lib/types/props/pretty_printable.rb +107 -0
- data/lib/types/props/private/apply_default.rb +170 -0
- data/lib/types/props/private/deserializer_generator.rb +165 -0
- data/lib/types/props/private/parser.rb +32 -0
- data/lib/types/props/private/serde_transform.rb +192 -0
- data/lib/types/props/private/serializer_generator.rb +77 -0
- data/lib/types/props/private/setter_factory.rb +134 -0
- data/lib/types/props/serializable.rb +330 -0
- data/lib/types/props/type_validation.rb +111 -0
- data/lib/types/props/utils.rb +59 -0
- data/lib/types/props/weak_constructor.rb +67 -0
- data/lib/types/runtime_profiled.rb +24 -0
- data/lib/types/sig.rb +30 -0
- data/lib/types/struct.rb +18 -0
- data/lib/types/types/attached_class.rb +37 -0
- data/lib/types/types/base.rb +151 -0
- data/lib/types/types/class_of.rb +38 -0
- data/lib/types/types/enum.rb +42 -0
- data/lib/types/types/fixed_array.rb +60 -0
- data/lib/types/types/fixed_hash.rb +59 -0
- data/lib/types/types/intersection.rb +37 -0
- data/lib/types/types/noreturn.rb +29 -0
- data/lib/types/types/proc.rb +51 -0
- data/lib/types/types/self_type.rb +35 -0
- data/lib/types/types/simple.rb +33 -0
- data/lib/types/types/t_enum.rb +38 -0
- data/lib/types/types/type_member.rb +7 -0
- data/lib/types/types/type_parameter.rb +23 -0
- data/lib/types/types/type_template.rb +7 -0
- data/lib/types/types/type_variable.rb +31 -0
- data/lib/types/types/typed_array.rb +34 -0
- data/lib/types/types/typed_enumerable.rb +161 -0
- data/lib/types/types/typed_enumerator.rb +36 -0
- data/lib/types/types/typed_hash.rb +43 -0
- data/lib/types/types/typed_range.rb +26 -0
- data/lib/types/types/typed_set.rb +36 -0
- data/lib/types/types/union.rb +56 -0
- data/lib/types/types/untyped.rb +29 -0
- data/lib/types/utils.rb +217 -0
- metadata +223 -0
@@ -0,0 +1,228 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
# typed: true
|
3
|
+
|
4
|
+
module T::Private::Methods
|
5
|
+
Declaration = Struct.new(:mod, :params, :returns, :bind, :mode, :checked, :finalized, :on_failure, :override_allow_incompatible, :type_parameters)
|
6
|
+
|
7
|
+
class DeclBuilder
|
8
|
+
attr_reader :decl
|
9
|
+
|
10
|
+
class BuilderError < StandardError; end
|
11
|
+
|
12
|
+
private def check_live!
|
13
|
+
if decl.finalized
|
14
|
+
raise BuilderError.new("You can't modify a signature declaration after it has been used.")
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def initialize(mod)
|
19
|
+
# TODO RUBYPLAT-1278 - with ruby 2.5, use kwargs here
|
20
|
+
@decl = Declaration.new(
|
21
|
+
mod,
|
22
|
+
ARG_NOT_PROVIDED, # params
|
23
|
+
ARG_NOT_PROVIDED, # returns
|
24
|
+
ARG_NOT_PROVIDED, # bind
|
25
|
+
Modes.standard, # mode
|
26
|
+
ARG_NOT_PROVIDED, # checked
|
27
|
+
false, # finalized
|
28
|
+
ARG_NOT_PROVIDED, # on_failure
|
29
|
+
nil, # override_allow_incompatible
|
30
|
+
ARG_NOT_PROVIDED, # type_parameters
|
31
|
+
)
|
32
|
+
end
|
33
|
+
|
34
|
+
def params(params)
|
35
|
+
check_live!
|
36
|
+
if !decl.params.equal?(ARG_NOT_PROVIDED)
|
37
|
+
raise BuilderError.new("You can't call .params twice")
|
38
|
+
end
|
39
|
+
|
40
|
+
decl.params = params
|
41
|
+
|
42
|
+
self
|
43
|
+
end
|
44
|
+
|
45
|
+
def returns(type)
|
46
|
+
check_live!
|
47
|
+
if decl.returns.is_a?(T::Private::Types::Void)
|
48
|
+
raise BuilderError.new("You can't call .returns after calling .void.")
|
49
|
+
end
|
50
|
+
if !decl.returns.equal?(ARG_NOT_PROVIDED)
|
51
|
+
raise BuilderError.new("You can't call .returns multiple times in a signature.")
|
52
|
+
end
|
53
|
+
|
54
|
+
decl.returns = type
|
55
|
+
|
56
|
+
self
|
57
|
+
end
|
58
|
+
|
59
|
+
def void
|
60
|
+
check_live!
|
61
|
+
if !decl.returns.equal?(ARG_NOT_PROVIDED)
|
62
|
+
raise BuilderError.new("You can't call .void after calling .returns.")
|
63
|
+
end
|
64
|
+
|
65
|
+
decl.returns = T::Private::Types::Void.new
|
66
|
+
|
67
|
+
self
|
68
|
+
end
|
69
|
+
|
70
|
+
def bind(type)
|
71
|
+
check_live!
|
72
|
+
if !decl.bind.equal?(ARG_NOT_PROVIDED)
|
73
|
+
raise BuilderError.new("You can't call .bind multiple times in a signature.")
|
74
|
+
end
|
75
|
+
|
76
|
+
decl.bind = type
|
77
|
+
|
78
|
+
self
|
79
|
+
end
|
80
|
+
|
81
|
+
def checked(level)
|
82
|
+
check_live!
|
83
|
+
|
84
|
+
if !decl.checked.equal?(ARG_NOT_PROVIDED)
|
85
|
+
raise BuilderError.new("You can't call .checked multiple times in a signature.")
|
86
|
+
end
|
87
|
+
if level == :never && !decl.on_failure.equal?(ARG_NOT_PROVIDED)
|
88
|
+
raise BuilderError.new("You can't use .checked(:never) with .on_failure because .on_failure will have no effect.")
|
89
|
+
end
|
90
|
+
if !T::Private::RuntimeLevels::LEVELS.include?(level)
|
91
|
+
raise BuilderError.new("Invalid `checked` level '#{level}'. Use one of: #{T::Private::RuntimeLevels::LEVELS}.")
|
92
|
+
end
|
93
|
+
|
94
|
+
decl.checked = level
|
95
|
+
|
96
|
+
self
|
97
|
+
end
|
98
|
+
|
99
|
+
def on_failure(*args)
|
100
|
+
check_live!
|
101
|
+
|
102
|
+
if !decl.on_failure.equal?(ARG_NOT_PROVIDED)
|
103
|
+
raise BuilderError.new("You can't call .on_failure multiple times in a signature.")
|
104
|
+
end
|
105
|
+
if decl.checked == :never
|
106
|
+
raise BuilderError.new("You can't use .on_failure with .checked(:never) because .on_failure will have no effect.")
|
107
|
+
end
|
108
|
+
|
109
|
+
decl.on_failure = args
|
110
|
+
|
111
|
+
self
|
112
|
+
end
|
113
|
+
|
114
|
+
def abstract
|
115
|
+
check_live!
|
116
|
+
|
117
|
+
case decl.mode
|
118
|
+
when Modes.standard
|
119
|
+
decl.mode = Modes.abstract
|
120
|
+
when Modes.abstract
|
121
|
+
raise BuilderError.new(".abstract cannot be repeated in a single signature")
|
122
|
+
else
|
123
|
+
raise BuilderError.new("`.abstract` cannot be combined with `.override` or `.overridable`.")
|
124
|
+
end
|
125
|
+
|
126
|
+
self
|
127
|
+
end
|
128
|
+
|
129
|
+
def final
|
130
|
+
check_live!
|
131
|
+
raise BuilderError.new("The syntax for declaring a method final is `sig(:final) {...}`, not `sig {final. ...}`")
|
132
|
+
end
|
133
|
+
|
134
|
+
def override(allow_incompatible: false)
|
135
|
+
check_live!
|
136
|
+
|
137
|
+
case decl.mode
|
138
|
+
when Modes.standard
|
139
|
+
decl.mode = Modes.override
|
140
|
+
decl.override_allow_incompatible = allow_incompatible
|
141
|
+
when Modes.override, Modes.overridable_override
|
142
|
+
raise BuilderError.new(".override cannot be repeated in a single signature")
|
143
|
+
when Modes.overridable
|
144
|
+
decl.mode = Modes.overridable_override
|
145
|
+
else
|
146
|
+
raise BuilderError.new("`.override` cannot be combined with `.abstract`.")
|
147
|
+
end
|
148
|
+
|
149
|
+
self
|
150
|
+
end
|
151
|
+
|
152
|
+
def overridable
|
153
|
+
check_live!
|
154
|
+
|
155
|
+
case decl.mode
|
156
|
+
when Modes.abstract
|
157
|
+
raise BuilderError.new("`.overridable` cannot be combined with `.#{decl.mode}`")
|
158
|
+
when Modes.override
|
159
|
+
decl.mode = Modes.overridable_override
|
160
|
+
when Modes.standard
|
161
|
+
decl.mode = Modes.overridable
|
162
|
+
when Modes.overridable, Modes.overridable_override
|
163
|
+
raise BuilderError.new(".overridable cannot be repeated in a single signature")
|
164
|
+
end
|
165
|
+
|
166
|
+
self
|
167
|
+
end
|
168
|
+
|
169
|
+
# Declares valid type paramaters which can be used with `T.type_parameter` in
|
170
|
+
# this `sig`.
|
171
|
+
#
|
172
|
+
# This is used for generic methods. Example usage:
|
173
|
+
#
|
174
|
+
# sig do
|
175
|
+
# type_parameters(:U)
|
176
|
+
# .params(blk: T.proc.params(arg0: Elem).returns(T.type_parameter(:U)))
|
177
|
+
# .returns(T::Array[T.type_parameter(:U)])
|
178
|
+
# end
|
179
|
+
# def map(&blk); end
|
180
|
+
def type_parameters(*names)
|
181
|
+
check_live!
|
182
|
+
|
183
|
+
names.each do |name|
|
184
|
+
raise BuilderError.new("not a symbol: #{name}") unless name.is_a?(Symbol)
|
185
|
+
end
|
186
|
+
|
187
|
+
if !decl.type_parameters.equal?(ARG_NOT_PROVIDED)
|
188
|
+
raise BuilderError.new("You can't call .type_parameters multiple times in a signature.")
|
189
|
+
end
|
190
|
+
|
191
|
+
decl.type_parameters = names
|
192
|
+
|
193
|
+
self
|
194
|
+
end
|
195
|
+
|
196
|
+
def finalize!
|
197
|
+
check_live!
|
198
|
+
|
199
|
+
if decl.returns.equal?(ARG_NOT_PROVIDED)
|
200
|
+
raise BuilderError.new("You must provide a return type; use the `.returns` or `.void` builder methods.")
|
201
|
+
end
|
202
|
+
|
203
|
+
if decl.bind.equal?(ARG_NOT_PROVIDED)
|
204
|
+
decl.bind = nil
|
205
|
+
end
|
206
|
+
if decl.checked.equal?(ARG_NOT_PROVIDED)
|
207
|
+
default_checked_level = T::Private::RuntimeLevels.default_checked_level
|
208
|
+
if default_checked_level == :never && !decl.on_failure.equal?(ARG_NOT_PROVIDED)
|
209
|
+
raise BuilderError.new("To use .on_failure you must additionally call .checked(:tests) or .checked(:always), otherwise, the .on_failure has no effect.")
|
210
|
+
end
|
211
|
+
decl.checked = default_checked_level
|
212
|
+
end
|
213
|
+
if decl.on_failure.equal?(ARG_NOT_PROVIDED)
|
214
|
+
decl.on_failure = nil
|
215
|
+
end
|
216
|
+
if decl.params.equal?(ARG_NOT_PROVIDED)
|
217
|
+
decl.params = {}
|
218
|
+
end
|
219
|
+
if decl.type_parameters.equal?(ARG_NOT_PROVIDED)
|
220
|
+
decl.type_parameters = {}
|
221
|
+
end
|
222
|
+
|
223
|
+
decl.finalized = true
|
224
|
+
|
225
|
+
self
|
226
|
+
end
|
227
|
+
end
|
228
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
# typed: true
|
3
|
+
|
4
|
+
module T::Private::Methods::Modes
|
5
|
+
def self.standard; 'standard'; end
|
6
|
+
def self.abstract; 'abstract'; end
|
7
|
+
def self.overridable; 'overridable'; end
|
8
|
+
def self.override; 'override'; end
|
9
|
+
def self.overridable_override; 'overridable_override'; end
|
10
|
+
def self.untyped; 'untyped'; end
|
11
|
+
MODES = [self.standard, self.abstract, self.overridable, self.override, self.overridable_override, self.untyped]
|
12
|
+
|
13
|
+
OVERRIDABLE_MODES = [self.override, self.overridable, self.overridable_override, self.untyped, self.abstract]
|
14
|
+
OVERRIDE_MODES = [self.override, self.overridable_override]
|
15
|
+
NON_OVERRIDE_MODES = MODES - OVERRIDE_MODES
|
16
|
+
end
|
@@ -0,0 +1,196 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
# typed: true
|
3
|
+
|
4
|
+
class T::Private::Methods::Signature
|
5
|
+
attr_reader :method, :method_name, :arg_types, :kwarg_types, :block_type, :block_name,
|
6
|
+
:rest_type, :rest_name, :keyrest_type, :keyrest_name, :bind,
|
7
|
+
:return_type, :mode, :req_arg_count, :req_kwarg_names, :has_rest, :has_keyrest,
|
8
|
+
:check_level, :parameters, :on_failure, :override_allow_incompatible
|
9
|
+
|
10
|
+
def self.new_untyped(method:, mode: T::Private::Methods::Modes.untyped, parameters: method.parameters)
|
11
|
+
# Using `Untyped` ensures we'll get an error if we ever try validation on these.
|
12
|
+
not_typed = T::Private::Types::NotTyped.new
|
13
|
+
raw_return_type = not_typed
|
14
|
+
raw_arg_types = parameters.map do |_param_kind, param_name|
|
15
|
+
[param_name, not_typed]
|
16
|
+
end.to_h
|
17
|
+
|
18
|
+
self.new(
|
19
|
+
method: method,
|
20
|
+
method_name: method.name,
|
21
|
+
raw_arg_types: raw_arg_types,
|
22
|
+
raw_return_type: raw_return_type,
|
23
|
+
bind: nil,
|
24
|
+
mode: mode,
|
25
|
+
check_level: :never,
|
26
|
+
parameters: parameters,
|
27
|
+
on_failure: nil,
|
28
|
+
)
|
29
|
+
end
|
30
|
+
|
31
|
+
def initialize(method:, method_name:, raw_arg_types:, raw_return_type:, bind:, mode:, check_level:, parameters: method.parameters, on_failure:, override_allow_incompatible: false)
|
32
|
+
@method = method
|
33
|
+
@method_name = method_name
|
34
|
+
@arg_types = []
|
35
|
+
@kwarg_types = {}
|
36
|
+
@block_type = nil
|
37
|
+
@block_name = nil
|
38
|
+
@rest_type = nil
|
39
|
+
@rest_name = nil
|
40
|
+
@keyrest_type = nil
|
41
|
+
@keyrest_name = nil
|
42
|
+
@return_type = T::Utils.coerce(raw_return_type)
|
43
|
+
@bind = bind ? T::Utils.coerce(bind) : bind
|
44
|
+
@mode = mode
|
45
|
+
@check_level = check_level
|
46
|
+
@req_arg_count = 0
|
47
|
+
@req_kwarg_names = []
|
48
|
+
@has_rest = false
|
49
|
+
@has_keyrest = false
|
50
|
+
@parameters = parameters
|
51
|
+
@on_failure = on_failure
|
52
|
+
@override_allow_incompatible = override_allow_incompatible
|
53
|
+
|
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
|
+
missing_names = param_names - declared_param_names
|
63
|
+
extra_names = declared_param_names - param_names
|
64
|
+
if !missing_names.empty?
|
65
|
+
raise "The declaration for `#{method.name}` is missing parameter(s): #{missing_names.join(', ')}"
|
66
|
+
end
|
67
|
+
if !extra_names.empty?
|
68
|
+
raise "The declaration for `#{method.name}` has extra parameter(s): #{extra_names.join(', ')}"
|
69
|
+
end
|
70
|
+
|
71
|
+
parameters.zip(raw_arg_types) do |(param_kind, param_name), (type_name, raw_type)|
|
72
|
+
if type_name != param_name
|
73
|
+
hint = ""
|
74
|
+
# Ruby reorders params so that required keyword arguments
|
75
|
+
# always precede optional keyword arguments. We can't tell
|
76
|
+
# whether the culprit is the Ruby reordering or user error, so
|
77
|
+
# we error but include a note
|
78
|
+
if param_kind == :keyreq && parameters.any? {|k, _| k == :key}
|
79
|
+
hint = "\n\nNote: Any required keyword arguments must precede any optional keyword " \
|
80
|
+
"arguments. If your method declaration matches your `def`, try reordering any " \
|
81
|
+
"optional keyword parameters to the end of the method list."
|
82
|
+
end
|
83
|
+
|
84
|
+
raise "Parameter `#{type_name}` is declared out of order (declared as arg number " \
|
85
|
+
"#{declared_param_names.index(type_name) + 1}, defined in the method as arg number " \
|
86
|
+
"#{param_names.index(type_name) + 1}).#{hint}\nMethod: #{method_desc}"
|
87
|
+
end
|
88
|
+
|
89
|
+
type = T::Utils.coerce(raw_type)
|
90
|
+
|
91
|
+
case param_kind
|
92
|
+
when :req
|
93
|
+
if @arg_types.length > @req_arg_count
|
94
|
+
# Note that this is actually is supported by Ruby, but it would add complexity to
|
95
|
+
# support it here, and I'm happy to discourage its use anyway.
|
96
|
+
raise "Required params after optional params are not supported in method declarations. Method: #{method_desc}"
|
97
|
+
end
|
98
|
+
@arg_types << [param_name, type]
|
99
|
+
@req_arg_count += 1
|
100
|
+
when :opt
|
101
|
+
@arg_types << [param_name, type]
|
102
|
+
when :key, :keyreq
|
103
|
+
@kwarg_types[param_name] = type
|
104
|
+
if param_kind == :keyreq
|
105
|
+
@req_kwarg_names << param_name
|
106
|
+
end
|
107
|
+
when :block
|
108
|
+
@block_name = param_name
|
109
|
+
@block_type = type
|
110
|
+
when :rest
|
111
|
+
@has_rest = true
|
112
|
+
@rest_name = param_name
|
113
|
+
@rest_type = type
|
114
|
+
when :keyrest
|
115
|
+
@has_keyrest = true
|
116
|
+
@keyrest_name = param_name
|
117
|
+
@keyrest_type = type
|
118
|
+
else
|
119
|
+
raise "Unexpected param_kind: `#{param_kind}`. Method: #{method_desc}"
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
def arg_count
|
125
|
+
@arg_types.length
|
126
|
+
end
|
127
|
+
|
128
|
+
def kwarg_names
|
129
|
+
@kwarg_types.keys
|
130
|
+
end
|
131
|
+
|
132
|
+
def owner
|
133
|
+
@method.owner
|
134
|
+
end
|
135
|
+
|
136
|
+
def dsl_method
|
137
|
+
"#{@mode}_method"
|
138
|
+
end
|
139
|
+
|
140
|
+
# @return [Hash] a mapping like {arg_name: [val, type], ...}, for only those args actually present.
|
141
|
+
def each_args_value_type(args)
|
142
|
+
# Manually split out args and kwargs based on ruby's behavior. Do not try to implement this by
|
143
|
+
# getting ruby to determine the kwargs for you (e.g., by defining this method to take *args and
|
144
|
+
# **kwargs). That won't work, because ruby's behavior for determining kwargs is dependent on the
|
145
|
+
# the other parameters in the method definition, and our method definition here doesn't (and
|
146
|
+
# can't) match the definition of the method we're validating. In addition, Ruby has a bug that
|
147
|
+
# causes forwarding **kwargs to do the wrong thing: see https://bugs.ruby-lang.org/issues/10708
|
148
|
+
# 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)
|
150
|
+
kwargs = args[-1]
|
151
|
+
args = args[0...-1]
|
152
|
+
else
|
153
|
+
kwargs = EMPTY_HASH
|
154
|
+
end
|
155
|
+
|
156
|
+
arg_types = @arg_types
|
157
|
+
|
158
|
+
if @has_rest
|
159
|
+
arg_types += [[@rest_name, @rest_type]] * (args.length - @arg_types.length)
|
160
|
+
|
161
|
+
elsif (args.length < @req_arg_count) || (args.length > @arg_types.length)
|
162
|
+
expected_str = @req_arg_count.to_s
|
163
|
+
if @arg_types.length != @req_arg_count
|
164
|
+
expected_str += "..#{@arg_types.length}"
|
165
|
+
end
|
166
|
+
raise ArgumentError.new("wrong number of arguments (given #{args.length}, expected #{expected_str})")
|
167
|
+
end
|
168
|
+
|
169
|
+
begin
|
170
|
+
it = 0
|
171
|
+
while it < args.length
|
172
|
+
yield arg_types[it][0], args[it], arg_types[it][1]
|
173
|
+
it += 1
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
kwargs.each do |name, val|
|
178
|
+
type = @kwarg_types[name]
|
179
|
+
if !type && @has_keyrest
|
180
|
+
type = @keyrest_type
|
181
|
+
end
|
182
|
+
yield name, val, type if type
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
def method_desc
|
187
|
+
if @method.source_location
|
188
|
+
loc = @method.source_location.join(':')
|
189
|
+
else
|
190
|
+
loc = "<unknown location>"
|
191
|
+
end
|
192
|
+
"#{@method} at #{loc}"
|
193
|
+
end
|
194
|
+
|
195
|
+
EMPTY_HASH = {}.freeze
|
196
|
+
end
|
@@ -0,0 +1,229 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
# typed: true
|
3
|
+
|
4
|
+
module T::Private::Methods::SignatureValidation
|
5
|
+
Methods = T::Private::Methods
|
6
|
+
Modes = Methods::Modes
|
7
|
+
|
8
|
+
def self.validate(signature)
|
9
|
+
if signature.method_name == :initialize && signature.method.owner.is_a?(Class)
|
10
|
+
# Constructors are special. They look like overrides in terms of a super_method existing,
|
11
|
+
# but in practice, you never call them polymorphically. Conceptually, they're standard
|
12
|
+
# methods (this is consistent with how they're treated in other languages, e.g. Java)
|
13
|
+
if signature.mode != Modes.standard
|
14
|
+
raise "`initialize` should not use `.abstract` or `.implementation` or any other inheritance modifiers."
|
15
|
+
end
|
16
|
+
return
|
17
|
+
end
|
18
|
+
|
19
|
+
super_method = signature.method.super_method
|
20
|
+
|
21
|
+
if super_method && super_method.owner != signature.method.owner
|
22
|
+
Methods.maybe_run_sig_block_for_method(super_method)
|
23
|
+
super_signature = Methods.signature_for_method(super_method)
|
24
|
+
|
25
|
+
# If the super_method has any kwargs we can't build a
|
26
|
+
# Signature for it, so we'll just skip validation in that case.
|
27
|
+
if !super_signature && !super_method.parameters.select {|kind, _| kind == :rest || kind == :kwrest}.empty?
|
28
|
+
nil
|
29
|
+
else
|
30
|
+
# super_signature can be nil when we're overriding a method (perhaps a builtin) that didn't use
|
31
|
+
# one of the method signature helpers. Use an untyped signature so we can still validate
|
32
|
+
# everything but types.
|
33
|
+
#
|
34
|
+
# We treat these signatures as overridable, that way people can use `.override` with
|
35
|
+
# overrides of builtins. In the future we could try to distinguish when the method is a
|
36
|
+
# builtin and treat non-builtins as non-overridable (so you'd be forced to declare them with
|
37
|
+
# `.overridable`).
|
38
|
+
#
|
39
|
+
super_signature ||= Methods::Signature.new_untyped(method: super_method)
|
40
|
+
|
41
|
+
validate_override_mode(signature, super_signature)
|
42
|
+
validate_override_shape(signature, super_signature)
|
43
|
+
validate_override_types(signature, super_signature)
|
44
|
+
end
|
45
|
+
else
|
46
|
+
validate_non_override_mode(signature)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
private_class_method def self.pretty_mode(signature)
|
51
|
+
if signature.mode == Modes.overridable_override
|
52
|
+
'.overridable.override'
|
53
|
+
else
|
54
|
+
".#{signature.mode}"
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def self.validate_override_mode(signature, super_signature)
|
59
|
+
case signature.mode
|
60
|
+
when *Modes::OVERRIDE_MODES
|
61
|
+
# Peaceful
|
62
|
+
when *Modes::NON_OVERRIDE_MODES
|
63
|
+
if super_signature.mode == Modes.standard
|
64
|
+
# Peaceful
|
65
|
+
elsif super_signature.mode == Modes.abstract
|
66
|
+
raise "You must use `.override` when overriding the abstract method `#{signature.method_name}`.\n" \
|
67
|
+
" Abstract definition: #{method_loc_str(super_signature.method)}\n" \
|
68
|
+
" Implementation definition: #{method_loc_str(signature.method)}\n"
|
69
|
+
elsif super_signature.mode != Modes.untyped
|
70
|
+
raise "You must use `.override` when overriding the existing method `#{signature.method_name}`.\n" \
|
71
|
+
" Parent definition: #{method_loc_str(super_signature.method)}\n" \
|
72
|
+
" Child definition: #{method_loc_str(signature.method)}\n"
|
73
|
+
end
|
74
|
+
else
|
75
|
+
raise "Unexpected mode: #{signature.mode}. Please report to #dev-productivity."
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def self.validate_non_override_mode(signature)
|
80
|
+
case signature.mode
|
81
|
+
when Modes.override
|
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
|
96
|
+
when Modes.standard, *Modes::NON_OVERRIDE_MODES
|
97
|
+
# Peaceful
|
98
|
+
nil
|
99
|
+
else
|
100
|
+
raise "Unexpected mode: #{signature.mode}. Please report to #dev-productivity."
|
101
|
+
end
|
102
|
+
|
103
|
+
owner = signature.method.owner
|
104
|
+
if (signature.mode == Modes.abstract || Modes::OVERRIDABLE_MODES.include?(signature.mode)) &&
|
105
|
+
owner.singleton_class?
|
106
|
+
# Given a singleton class, we can check if it belongs to a
|
107
|
+
# module by looking at its superclass; given `module M`,
|
108
|
+
# `M.singleton_class.superclass == Module`, which is not true
|
109
|
+
# for any class.
|
110
|
+
if owner.superclass == Module
|
111
|
+
raise "Defining an overridable class method (via #{pretty_mode(signature)}) " \
|
112
|
+
"on a module is not allowed. Class methods on " \
|
113
|
+
"modules do not get inherited and thus cannot be overridden. For help, ask in " \
|
114
|
+
"#dev-productivity."
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
def self.validate_override_shape(signature, super_signature)
|
120
|
+
return if signature.override_allow_incompatible
|
121
|
+
return if super_signature.mode == Modes.untyped
|
122
|
+
|
123
|
+
method_name = signature.method_name
|
124
|
+
mode_verb = super_signature.mode == Modes.abstract ? 'implements' : 'overrides'
|
125
|
+
|
126
|
+
if !signature.has_rest && signature.arg_count < super_signature.arg_count
|
127
|
+
raise "Your definition of `#{method_name}` must accept at least #{super_signature.arg_count} " \
|
128
|
+
"positional arguments to be compatible with the method it #{mode_verb}: " \
|
129
|
+
"#{base_override_loc_str(signature, super_signature)}"
|
130
|
+
end
|
131
|
+
|
132
|
+
if !signature.has_rest && super_signature.has_rest
|
133
|
+
raise "Your definition of `#{method_name}` must have `*#{super_signature.rest_name}` " \
|
134
|
+
"to be compatible with the method it #{mode_verb}: " \
|
135
|
+
"#{base_override_loc_str(signature, super_signature)}"
|
136
|
+
end
|
137
|
+
|
138
|
+
if signature.req_arg_count > super_signature.req_arg_count
|
139
|
+
raise "Your definition of `#{method_name}` must have no more than #{super_signature.req_arg_count} " \
|
140
|
+
"required argument(s) to be compatible with the method it #{mode_verb}: " \
|
141
|
+
"#{base_override_loc_str(signature, super_signature)}"
|
142
|
+
end
|
143
|
+
|
144
|
+
if !signature.has_keyrest
|
145
|
+
# O(nm), but n and m are tiny here
|
146
|
+
missing_kwargs = super_signature.kwarg_names - signature.kwarg_names
|
147
|
+
if !missing_kwargs.empty?
|
148
|
+
raise "Your definition of `#{method_name}` is missing these keyword arg(s): #{missing_kwargs} " \
|
149
|
+
"which are defined in the method it #{mode_verb}: " \
|
150
|
+
"#{base_override_loc_str(signature, super_signature)}"
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
if !signature.has_keyrest && super_signature.has_keyrest
|
155
|
+
raise "Your definition of `#{method_name}` must have `**#{super_signature.keyrest_name}` " \
|
156
|
+
"to be compatible with the method it #{mode_verb}: " \
|
157
|
+
"#{base_override_loc_str(signature, super_signature)}"
|
158
|
+
end
|
159
|
+
|
160
|
+
|
161
|
+
# O(nm), but n and m are tiny here
|
162
|
+
extra_req_kwargs = signature.req_kwarg_names - super_signature.req_kwarg_names
|
163
|
+
if !extra_req_kwargs.empty?
|
164
|
+
raise "Your definition of `#{method_name}` has extra required keyword arg(s) " \
|
165
|
+
"#{extra_req_kwargs} relative to the method it #{mode_verb}, making it incompatible: " \
|
166
|
+
"#{base_override_loc_str(signature, super_signature)}"
|
167
|
+
end
|
168
|
+
|
169
|
+
if super_signature.block_name && !signature.block_name
|
170
|
+
raise "Your definition of `#{method_name}` must accept a block parameter to be compatible " \
|
171
|
+
"with the method it #{mode_verb}: " \
|
172
|
+
"#{base_override_loc_str(signature, super_signature)}"
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
def self.validate_override_types(signature, super_signature)
|
177
|
+
return if signature.override_allow_incompatible
|
178
|
+
return if super_signature.mode == Modes.untyped
|
179
|
+
return unless [signature, super_signature].all? do |sig|
|
180
|
+
sig.check_level == :always || (sig.check_level == :tests && T::Private::RuntimeLevels.check_tests?)
|
181
|
+
end
|
182
|
+
mode_noun = super_signature.mode == Modes.abstract ? 'implementation' : 'override'
|
183
|
+
|
184
|
+
# arg types must be contravariant
|
185
|
+
super_signature.arg_types.zip(signature.arg_types).each_with_index do |((_super_name, super_type), (name, type)), index|
|
186
|
+
if !super_type.subtype_of?(type)
|
187
|
+
raise "Incompatible type for arg ##{index + 1} (`#{name}`) in #{mode_noun} of method " \
|
188
|
+
"`#{signature.method_name}`:\n" \
|
189
|
+
"* Base: `#{super_type}` (in #{method_loc_str(super_signature.method)})\n" \
|
190
|
+
"* #{mode_noun.capitalize}: `#{type}` (in #{method_loc_str(signature.method)})\n" \
|
191
|
+
"(The types must be contravariant.)"
|
192
|
+
end
|
193
|
+
end
|
194
|
+
|
195
|
+
# kwarg types must be contravariant
|
196
|
+
super_signature.kwarg_types.each do |name, super_type|
|
197
|
+
type = signature.kwarg_types[name]
|
198
|
+
if !super_type.subtype_of?(type)
|
199
|
+
raise "Incompatible type for arg `#{name}` in #{mode_noun} of method `#{signature.method_name}`:\n" \
|
200
|
+
"* Base: `#{super_type}` (in #{method_loc_str(super_signature.method)})\n" \
|
201
|
+
"* #{mode_noun.capitalize}: `#{type}` (in #{method_loc_str(signature.method)})\n" \
|
202
|
+
"(The types must be contravariant.)"
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
206
|
+
# return types must be covariant
|
207
|
+
if !signature.return_type.subtype_of?(super_signature.return_type)
|
208
|
+
raise "Incompatible return type in #{mode_noun} of method `#{signature.method_name}`:\n" \
|
209
|
+
"* Base: `#{super_signature.return_type}` (in #{method_loc_str(super_signature.method)})\n" \
|
210
|
+
"* #{mode_noun.capitalize}: `#{signature.return_type}` (in #{method_loc_str(signature.method)})\n" \
|
211
|
+
"(The types must be covariant.)"
|
212
|
+
end
|
213
|
+
end
|
214
|
+
|
215
|
+
private_class_method def self.base_override_loc_str(signature, super_signature)
|
216
|
+
mode_noun = super_signature.mode == Modes.abstract ? 'Implementation' : 'Override'
|
217
|
+
"\n * Base definition: in #{method_loc_str(super_signature.method)}" \
|
218
|
+
"\n * #{mode_noun}: in #{method_loc_str(signature.method)}"
|
219
|
+
end
|
220
|
+
|
221
|
+
private_class_method def self.method_loc_str(method)
|
222
|
+
if method.source_location
|
223
|
+
loc = method.source_location.join(':')
|
224
|
+
else
|
225
|
+
loc = "<unknown location>"
|
226
|
+
end
|
227
|
+
"#{method.owner} at #{loc}"
|
228
|
+
end
|
229
|
+
end
|