steep 0.47.1 → 0.48.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +9 -0
- data/Gemfile.lock +6 -6
- data/lib/steep/ast/types/factory.rb +161 -137
- data/lib/steep/ast/types/var.rb +14 -3
- data/lib/steep/diagnostic/ruby.rb +23 -11
- data/lib/steep/diagnostic/signature.rb +56 -0
- data/lib/steep/interface/method_type.rb +14 -26
- data/lib/steep/interface/type_param.rb +103 -0
- data/lib/steep/server/base_worker.rb +1 -0
- data/lib/steep/server/interaction_worker.rb +1 -1
- data/lib/steep/server/type_check_worker.rb +2 -2
- data/lib/steep/services/signature_service.rb +2 -2
- data/lib/steep/services/type_check_service.rb +2 -1
- data/lib/steep/signature/validator.rb +221 -49
- data/lib/steep/subtyping/cache.rb +30 -0
- data/lib/steep/subtyping/check.rb +582 -708
- data/lib/steep/subtyping/constraints.rb +66 -30
- data/lib/steep/subtyping/relation.rb +60 -0
- data/lib/steep/subtyping/result.rb +190 -16
- data/lib/steep/type_construction.rb +492 -371
- data/lib/steep/type_inference/context.rb +37 -3
- data/lib/steep/version.rb +1 -1
- data/lib/steep.rb +3 -3
- data/sample/lib/length.rb +35 -0
- data/sample/sig/length.rbs +34 -0
- data/smoke/diagnostics-rbs/nonregular-type-alias.rbs +3 -0
- data/smoke/diagnostics-rbs/recursive-type-alias.rbs +3 -0
- data/smoke/diagnostics-rbs/test_expectations.yml +57 -12
- data/steep.gemspec +1 -1
- metadata +13 -10
- data/lib/steep/drivers/trace_printer.rb +0 -29
- data/lib/steep/interface/method.rb +0 -78
- data/lib/steep/subtyping/trace.rb +0 -71
@@ -77,7 +77,7 @@ module Steep
|
|
77
77
|
end
|
78
78
|
|
79
79
|
def to_s
|
80
|
-
type_params = !self.type_params.empty? ? "[#{self.type_params.
|
80
|
+
type_params = !self.type_params.empty? ? "[#{self.type_params.join(", ")}] " : ""
|
81
81
|
params = type.params.to_s
|
82
82
|
return_type = type.return_type
|
83
83
|
block = self.block ? " #{self.block}" : ""
|
@@ -95,11 +95,9 @@ module Steep
|
|
95
95
|
# Returns a new method type which can be used for the method implementation type of both `self` and `other`.
|
96
96
|
#
|
97
97
|
def unify_overload(other)
|
98
|
-
|
99
|
-
|
100
|
-
type_params
|
101
|
-
s2 = Substitution.build(other.type_params)
|
102
|
-
type_params.push(*s2.dictionary.values.map(&:name))
|
98
|
+
type_params_1, s1 = TypeParam.rename(self.type_params)
|
99
|
+
type_params_2, s2 = TypeParam.rename(other.type_params)
|
100
|
+
type_params = type_params_1 + type_params_2
|
103
101
|
|
104
102
|
block = case
|
105
103
|
when self.block && other.block
|
@@ -134,17 +132,12 @@ module Steep
|
|
134
132
|
# Returns nil if self and other are incompatible.
|
135
133
|
#
|
136
134
|
def |(other)
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
unless (common_type_params = (self_type_params & other_type_params).to_a).empty?
|
141
|
-
fresh_types = common_type_params.map {|name| AST::Types::Var.fresh(name) }
|
142
|
-
fresh_names = fresh_types.map(&:name)
|
143
|
-
subst = Substitution.build(common_type_params, fresh_types)
|
144
|
-
other = other.instantiate(subst)
|
145
|
-
type_params = (self_type_params + (other_type_params - common_type_params + Set.new(fresh_names))).to_a
|
135
|
+
if other.type_params.empty?
|
136
|
+
type_params = self.type_params
|
146
137
|
else
|
147
|
-
|
138
|
+
other_params, s2 = TypeParam.rename(other.type_params)
|
139
|
+
other = other.instantiate(s2)
|
140
|
+
type_params = self.type_params + other_params
|
148
141
|
end
|
149
142
|
|
150
143
|
params = self.type.params & other.type.params or return
|
@@ -182,17 +175,12 @@ module Steep
|
|
182
175
|
# Returns nil if self and other are incompatible.
|
183
176
|
#
|
184
177
|
def &(other)
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
unless (common_type_params = (self_type_params & other_type_params).to_a).empty?
|
189
|
-
fresh_types = common_type_params.map {|name| AST::Types::Var.fresh(name) }
|
190
|
-
fresh_names = fresh_types.map(&:name)
|
191
|
-
subst = Substitution.build(common_type_params, fresh_types)
|
192
|
-
other = other.subst(subst)
|
193
|
-
type_params = (self_type_params + (other_type_params - common_type_params + Set.new(fresh_names))).to_a
|
178
|
+
if other.type_params.empty?
|
179
|
+
type_params = self.type_params
|
194
180
|
else
|
195
|
-
|
181
|
+
other_params, s2 = TypeParam.rename(other.type_params)
|
182
|
+
other = other.instantiate(s2)
|
183
|
+
type_params = self.type_params + other_params
|
196
184
|
end
|
197
185
|
|
198
186
|
params = self.type.params | other.type.params
|
@@ -0,0 +1,103 @@
|
|
1
|
+
module Steep
|
2
|
+
module Interface
|
3
|
+
class TypeParam
|
4
|
+
attr_reader :name
|
5
|
+
attr_reader :upper_bound
|
6
|
+
attr_reader :variance
|
7
|
+
attr_reader :unchecked
|
8
|
+
attr_reader :location
|
9
|
+
|
10
|
+
def initialize(name:, upper_bound:, variance:, unchecked:, location: nil)
|
11
|
+
@name = name
|
12
|
+
@upper_bound = upper_bound
|
13
|
+
@variance = variance
|
14
|
+
@unchecked = unchecked
|
15
|
+
@location = location
|
16
|
+
end
|
17
|
+
|
18
|
+
def ==(other)
|
19
|
+
other.is_a?(TypeParam) &&
|
20
|
+
other.name == name &&
|
21
|
+
other.upper_bound == upper_bound &&
|
22
|
+
other.variance == variance &&
|
23
|
+
other.unchecked == unchecked
|
24
|
+
end
|
25
|
+
|
26
|
+
alias eql? ==
|
27
|
+
|
28
|
+
def hash
|
29
|
+
name.hash ^ upper_bound.hash ^ variance.hash ^ unchecked.hash
|
30
|
+
end
|
31
|
+
|
32
|
+
def self.rename(params, conflicting_names = params.map(&:name))
|
33
|
+
unless conflicting_names.empty?
|
34
|
+
new_names = conflicting_names.map {|n| AST::Types::Var.fresh_name(n) }
|
35
|
+
hash = conflicting_names.zip(new_names).to_h
|
36
|
+
new_types = new_names.map {|n| AST::Types::Var.new(name: n) }
|
37
|
+
|
38
|
+
subst = Substitution.build(conflicting_names, new_types)
|
39
|
+
|
40
|
+
[
|
41
|
+
params.map do |param|
|
42
|
+
if hash.key?(param.name) || param.upper_bound
|
43
|
+
TypeParam.new(
|
44
|
+
name: hash[param.name] || param.name,
|
45
|
+
upper_bound: param.upper_bound&.subst(subst),
|
46
|
+
variance: param.variance,
|
47
|
+
unchecked: param.unchecked,
|
48
|
+
location: param.location
|
49
|
+
)
|
50
|
+
else
|
51
|
+
param
|
52
|
+
end
|
53
|
+
end,
|
54
|
+
subst
|
55
|
+
]
|
56
|
+
else
|
57
|
+
[params, Substitution.empty]
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def to_s
|
62
|
+
buf = ""
|
63
|
+
|
64
|
+
if unchecked
|
65
|
+
buf << "unchecked "
|
66
|
+
end
|
67
|
+
|
68
|
+
case variance
|
69
|
+
when :covariant
|
70
|
+
buf << "out "
|
71
|
+
when :contravariant
|
72
|
+
buf << "in "
|
73
|
+
end
|
74
|
+
|
75
|
+
buf << name.to_s
|
76
|
+
|
77
|
+
if upper_bound
|
78
|
+
buf << " < #{upper_bound}"
|
79
|
+
end
|
80
|
+
|
81
|
+
buf
|
82
|
+
end
|
83
|
+
|
84
|
+
def update(name: self.name, upper_bound: self.upper_bound, variance: self.variance, unchecked: self.unchecked, location: self.location)
|
85
|
+
TypeParam.new(
|
86
|
+
name: name,
|
87
|
+
upper_bound: upper_bound,
|
88
|
+
variance: variance,
|
89
|
+
unchecked: unchecked,
|
90
|
+
location: location
|
91
|
+
)
|
92
|
+
end
|
93
|
+
|
94
|
+
def subst(s)
|
95
|
+
if u = upper_bound
|
96
|
+
update(upper_bound: u.subst(s))
|
97
|
+
else
|
98
|
+
self
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
@@ -144,7 +144,7 @@ module Steep
|
|
144
144
|
if job.guid == current_type_check_guid
|
145
145
|
Steep.logger.info { "Processing ValidateAppSignature for guid=#{job.guid}, path=#{job.path}" }
|
146
146
|
service.validate_signature(path: project.relative_path(job.path)) do |path, diagnostics|
|
147
|
-
formatter = Diagnostic::LSPFormatter.new({})
|
147
|
+
formatter = Diagnostic::LSPFormatter.new({}, **{})
|
148
148
|
|
149
149
|
writer.write(
|
150
150
|
method: :"textDocument/publishDiagnostics",
|
@@ -162,7 +162,7 @@ module Steep
|
|
162
162
|
if job.guid == current_type_check_guid
|
163
163
|
Steep.logger.info { "Processing ValidateLibrarySignature for guid=#{job.guid}, path=#{job.path}" }
|
164
164
|
service.validate_signature(path: job.path) do |path, diagnostics|
|
165
|
-
formatter = Diagnostic::LSPFormatter.new({})
|
165
|
+
formatter = Diagnostic::LSPFormatter.new({}, **{})
|
166
166
|
|
167
167
|
writer.write(
|
168
168
|
method: :"textDocument/publishDiagnostics",
|
@@ -224,7 +224,7 @@ module Steep
|
|
224
224
|
Steep.measure "Loading new decls" do
|
225
225
|
updated_files.each_value do |content|
|
226
226
|
case decls = content.decls
|
227
|
-
when RBS::
|
227
|
+
when RBS::BaseError
|
228
228
|
errors << content.decls
|
229
229
|
else
|
230
230
|
begin
|
@@ -283,7 +283,7 @@ module Steep
|
|
283
283
|
def rescue_rbs_error(errors)
|
284
284
|
begin
|
285
285
|
yield
|
286
|
-
rescue RBS::
|
286
|
+
rescue RBS::BaseError => exn
|
287
287
|
errors << exn
|
288
288
|
end
|
289
289
|
end
|
@@ -366,7 +366,8 @@ module Steep
|
|
366
366
|
self_type: AST::Builtin::Object.instance_type,
|
367
367
|
type_env: type_env,
|
368
368
|
lvar_env: lvar_env,
|
369
|
-
call_context: TypeInference::MethodCall::TopLevelContext.new
|
369
|
+
call_context: TypeInference::MethodCall::TopLevelContext.new,
|
370
|
+
variable_context: TypeInference::Context::TypeVariableContext.empty
|
370
371
|
)
|
371
372
|
|
372
373
|
typing = Typing.new(source: source, root_context: context)
|
@@ -56,9 +56,73 @@ module Steep
|
|
56
56
|
validate_alias
|
57
57
|
end
|
58
58
|
|
59
|
+
def validate_type_application_constraints(type_name, type_params, type_args, location:)
|
60
|
+
if type_params.size == type_args.size
|
61
|
+
type_params.zip(type_args).each do |param, arg|
|
62
|
+
if param.upper_bound
|
63
|
+
upper_bound_type = factory.type(param.upper_bound)
|
64
|
+
arg_type = factory.type(arg)
|
65
|
+
|
66
|
+
constraints = Subtyping::Constraints.empty
|
67
|
+
|
68
|
+
checker.check(
|
69
|
+
Subtyping::Relation.new(sub_type: arg_type, super_type: upper_bound_type),
|
70
|
+
self_type: nil,
|
71
|
+
class_type: nil,
|
72
|
+
instance_type: nil,
|
73
|
+
constraints: constraints
|
74
|
+
).else do |result|
|
75
|
+
@errors << Diagnostic::Signature::UnsatisfiableTypeApplication.new(
|
76
|
+
type_name: type_name,
|
77
|
+
type_arg: arg_type,
|
78
|
+
type_param: Interface::TypeParam.new(
|
79
|
+
name: param.name,
|
80
|
+
upper_bound: upper_bound_type,
|
81
|
+
variance: param.variance,
|
82
|
+
unchecked: param.unchecked?
|
83
|
+
),
|
84
|
+
location: location
|
85
|
+
)
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
59
92
|
def validate_type(type)
|
60
93
|
Steep.logger.debug "#{Location.to_string type.location}: Validating #{type}..."
|
94
|
+
|
61
95
|
validator.validate_type type, context: [RBS::Namespace.root]
|
96
|
+
|
97
|
+
name, type_params, type_args =
|
98
|
+
case type
|
99
|
+
when RBS::Types::ClassInstance
|
100
|
+
[
|
101
|
+
type.name,
|
102
|
+
builder.build_instance(type.name).type_params_decl,
|
103
|
+
type.args
|
104
|
+
]
|
105
|
+
when RBS::Types::Interface
|
106
|
+
[
|
107
|
+
type.name,
|
108
|
+
builder.build_interface(type.name).type_params_decl,
|
109
|
+
type.args
|
110
|
+
]
|
111
|
+
when RBS::Types::Alias
|
112
|
+
entry = env.alias_decls[type.name]
|
113
|
+
|
114
|
+
[
|
115
|
+
type.name,
|
116
|
+
entry.decl.type_params,
|
117
|
+
type.args
|
118
|
+
]
|
119
|
+
end
|
120
|
+
|
121
|
+
if name && type_params && type_args
|
122
|
+
if !type_params.empty? && !type_args.empty?
|
123
|
+
validate_type_application_constraints(type.name, type_params, type_args, location: type.location)
|
124
|
+
end
|
125
|
+
end
|
62
126
|
end
|
63
127
|
|
64
128
|
def ancestor_to_type(ancestor)
|
@@ -109,64 +173,109 @@ module Steep
|
|
109
173
|
relations
|
110
174
|
end
|
111
175
|
|
176
|
+
def each_method_type(definition)
|
177
|
+
type_name = definition.type_name
|
178
|
+
|
179
|
+
definition.methods.each_value do |method|
|
180
|
+
if method.defined_in == type_name
|
181
|
+
method.method_types.each do |method_type|
|
182
|
+
yield method_type
|
183
|
+
end
|
184
|
+
end
|
185
|
+
end
|
186
|
+
end
|
187
|
+
|
188
|
+
def each_variable_type(definition)
|
189
|
+
type_name = definition.type_name
|
190
|
+
|
191
|
+
definition.instance_variables.each_value do |var|
|
192
|
+
if var.declared_in == type_name
|
193
|
+
yield var.type
|
194
|
+
end
|
195
|
+
end
|
196
|
+
|
197
|
+
definition.class_variables.each_value do |var|
|
198
|
+
if var.declared_in == type_name
|
199
|
+
yield var.type
|
200
|
+
end
|
201
|
+
end
|
202
|
+
end
|
203
|
+
|
204
|
+
def validate_definition_type(definition)
|
205
|
+
each_method_type(definition) do |method_type|
|
206
|
+
upper_bounds = method_type.type_params.each.with_object({}) do |param, hash|
|
207
|
+
hash[param.name] = factory.type_opt(param.upper_bound)
|
208
|
+
end
|
209
|
+
|
210
|
+
checker.push_variable_bounds(upper_bounds) do
|
211
|
+
method_type.each_type do |type|
|
212
|
+
validate_type(type)
|
213
|
+
end
|
214
|
+
end
|
215
|
+
end
|
216
|
+
|
217
|
+
each_variable_type(definition) do |type|
|
218
|
+
validate_type(type)
|
219
|
+
end
|
220
|
+
end
|
221
|
+
|
112
222
|
def validate_one_class(name)
|
113
223
|
rescue_validation_errors(name) do
|
114
224
|
Steep.logger.debug { "Validating class definition `#{name}`..." }
|
115
225
|
|
116
226
|
Steep.logger.tagged "#{name}" do
|
117
227
|
builder.build_instance(name).tap do |definition|
|
118
|
-
definition.
|
119
|
-
|
120
|
-
|
121
|
-
parent_type = checker.factory.type(parent.type)
|
228
|
+
upper_bounds = definition.type_params_decl.each.with_object({}) do |param, bounds|
|
229
|
+
bounds[param.name] = factory.type_opt(param.upper_bound)
|
230
|
+
end
|
122
231
|
|
123
|
-
|
124
|
-
|
232
|
+
checker.push_variable_bounds(upper_bounds) do
|
233
|
+
definition.instance_variables.each do |name, var|
|
234
|
+
if parent = var.parent_variable
|
235
|
+
var_type = checker.factory.type(var.type)
|
236
|
+
parent_type = checker.factory.type(parent.type)
|
237
|
+
|
238
|
+
relation = Subtyping::Relation.new(sub_type: var_type, super_type: parent_type)
|
239
|
+
result1 = checker.check(relation, self_type: nil, instance_type: nil, class_type: nil, constraints: Subtyping::Constraints.empty)
|
240
|
+
result2 = checker.check(relation.flip, self_type: nil, instance_type: nil, class_type: nil, constraints: Subtyping::Constraints.empty)
|
241
|
+
|
242
|
+
unless result1.success? and result2.success?
|
243
|
+
@errors << Diagnostic::Signature::InstanceVariableTypeError.new(
|
244
|
+
name: name,
|
245
|
+
location: var.type.location,
|
246
|
+
var_type: var_type,
|
247
|
+
parent_type: parent_type
|
248
|
+
)
|
249
|
+
end
|
250
|
+
end
|
251
|
+
end
|
252
|
+
|
253
|
+
ancestors = builder.ancestor_builder.one_instance_ancestors(name)
|
254
|
+
mixin_constraints(definition, ancestors.included_modules, immediate_self_types: ancestors.self_types).each do |relation, ancestor|
|
255
|
+
checker.check(
|
125
256
|
relation,
|
126
257
|
self_type: AST::Types::Self.new,
|
127
258
|
instance_type: AST::Types::Instance.new,
|
128
259
|
class_type: AST::Types::Class.new,
|
129
260
|
constraints: Subtyping::Constraints.empty
|
130
|
-
)
|
131
|
-
|
132
|
-
relation.flip,
|
133
|
-
self_type: AST::Types::Self.new,
|
134
|
-
instance_type: AST::Types::Instance.new,
|
135
|
-
class_type: AST::Types::Class.new,
|
136
|
-
constraints: Subtyping::Constraints.empty
|
137
|
-
)
|
138
|
-
|
139
|
-
unless result1.success? and result2.success?
|
140
|
-
@errors << Diagnostic::Signature::InstanceVariableTypeError.new(
|
261
|
+
).else do
|
262
|
+
@errors << Diagnostic::Signature::ModuleSelfTypeError.new(
|
141
263
|
name: name,
|
142
|
-
location:
|
143
|
-
|
144
|
-
|
264
|
+
location: ancestor.source&.location || raise,
|
265
|
+
ancestor: ancestor,
|
266
|
+
relation: relation
|
145
267
|
)
|
146
268
|
end
|
147
269
|
end
|
148
|
-
end
|
149
270
|
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
instance_type: AST::Types::Instance.new,
|
156
|
-
class_type: AST::Types::Class.new,
|
157
|
-
constraints: Subtyping::Constraints.empty
|
158
|
-
).else do
|
159
|
-
@errors << Diagnostic::Signature::ModuleSelfTypeError.new(
|
160
|
-
name: name,
|
161
|
-
location: ancestor.source&.location || raise,
|
162
|
-
ancestor: ancestor,
|
163
|
-
relation: relation
|
164
|
-
)
|
271
|
+
ancestors.each_ancestor do |ancestor|
|
272
|
+
case ancestor
|
273
|
+
when RBS::Definition::Ancestor::Instance
|
274
|
+
validate_ancestor_application(name, ancestor)
|
275
|
+
end
|
165
276
|
end
|
166
|
-
end
|
167
277
|
|
168
|
-
|
169
|
-
validate_type type
|
278
|
+
validate_definition_type(definition)
|
170
279
|
end
|
171
280
|
end
|
172
281
|
|
@@ -220,21 +329,78 @@ module Steep
|
|
220
329
|
)
|
221
330
|
end
|
222
331
|
end
|
223
|
-
|
224
|
-
|
225
|
-
|
332
|
+
ancestors.each_ancestor do |ancestor|
|
333
|
+
case ancestor
|
334
|
+
when RBS::Definition::Ancestor::Instance
|
335
|
+
validate_ancestor_application(name, ancestor)
|
336
|
+
end
|
226
337
|
end
|
338
|
+
|
339
|
+
validate_definition_type(definition)
|
227
340
|
end
|
228
341
|
end
|
229
342
|
end
|
230
343
|
end
|
231
344
|
|
345
|
+
def validate_ancestor_application(name, ancestor)
|
346
|
+
unless ancestor.args.empty?
|
347
|
+
definition =
|
348
|
+
case
|
349
|
+
when ancestor.name.class?
|
350
|
+
builder.build_instance(ancestor.name)
|
351
|
+
when ancestor.name.interface?
|
352
|
+
builder.build_interface(ancestor.name)
|
353
|
+
end
|
354
|
+
|
355
|
+
location =
|
356
|
+
if ancestor.source == :super
|
357
|
+
primary_decl = env.class_decls[name].primary.decl
|
358
|
+
if super_class = primary_decl.super_class
|
359
|
+
super_class.location
|
360
|
+
else
|
361
|
+
# Implicit super class (Object): this can be skipped in fact...
|
362
|
+
primary_decl.location[:name]
|
363
|
+
end
|
364
|
+
else
|
365
|
+
ancestor.source.location
|
366
|
+
end
|
367
|
+
|
368
|
+
validate_type_application_constraints(
|
369
|
+
ancestor.name,
|
370
|
+
definition.type_params_decl,
|
371
|
+
ancestor.args,
|
372
|
+
location: location
|
373
|
+
)
|
374
|
+
end
|
375
|
+
end
|
376
|
+
|
232
377
|
def validate_one_interface(name)
|
233
378
|
rescue_validation_errors(name) do
|
234
379
|
Steep.logger.debug "Validating interface `#{name}`..."
|
235
380
|
Steep.logger.tagged "#{name}" do
|
236
|
-
builder.build_interface(name)
|
237
|
-
|
381
|
+
definition = builder.build_interface(name)
|
382
|
+
|
383
|
+
upper_bounds = definition.type_params_decl.each.with_object({}) do |param, bounds|
|
384
|
+
bounds[param.name] = factory.type_opt(param.upper_bound)
|
385
|
+
end
|
386
|
+
|
387
|
+
checker.push_variable_bounds(upper_bounds) do
|
388
|
+
validate_definition_type(definition)
|
389
|
+
|
390
|
+
ancestors = builder.ancestor_builder.one_interface_ancestors(name)
|
391
|
+
ancestors.each_ancestor do |ancestor|
|
392
|
+
case ancestor
|
393
|
+
when RBS::Definition::Ancestor::Instance
|
394
|
+
# Interface ancestor cannot be other than Interface
|
395
|
+
defn = builder.build_interface(ancestor.name)
|
396
|
+
validate_type_application_constraints(
|
397
|
+
ancestor.name,
|
398
|
+
defn.type_params_decl,
|
399
|
+
ancestor.args,
|
400
|
+
location: ancestor.source.location || raise
|
401
|
+
)
|
402
|
+
end
|
403
|
+
end
|
238
404
|
end
|
239
405
|
end
|
240
406
|
end
|
@@ -277,24 +443,30 @@ module Steep
|
|
277
443
|
end
|
278
444
|
end
|
279
445
|
|
280
|
-
def validate_one_alias(name)
|
446
|
+
def validate_one_alias(name, entry = env.alias_decls[name])
|
281
447
|
rescue_validation_errors(name) do
|
282
448
|
Steep.logger.debug "Validating alias `#{name}`..."
|
283
|
-
|
284
|
-
|
449
|
+
upper_bounds = entry.decl.type_params.each.with_object({}) do |param, bounds|
|
450
|
+
bounds[param.name] = factory.type_opt(param.upper_bound)
|
451
|
+
end
|
452
|
+
|
453
|
+
validator.validate_type_alias(entry: entry) do |type|
|
454
|
+
checker.push_variable_bounds(upper_bounds) do
|
455
|
+
validate_type(entry.decl.type)
|
456
|
+
end
|
285
457
|
end
|
286
458
|
end
|
287
459
|
end
|
288
460
|
|
289
461
|
def validate_alias
|
290
462
|
env.alias_decls.each do |name, entry|
|
291
|
-
validate_one_alias(name)
|
463
|
+
validate_one_alias(name, entry)
|
292
464
|
end
|
293
465
|
end
|
294
466
|
|
295
467
|
def rescue_validation_errors(type_name = nil)
|
296
468
|
yield
|
297
|
-
rescue RBS::
|
469
|
+
rescue RBS::BaseError => exn
|
298
470
|
@errors << Diagnostic::Signature.from_rbs_error(exn, factory: factory)
|
299
471
|
end
|
300
472
|
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module Steep
|
2
|
+
module Subtyping
|
3
|
+
class Cache
|
4
|
+
attr_reader :subtypes
|
5
|
+
|
6
|
+
def initialize
|
7
|
+
@subtypes = {}
|
8
|
+
end
|
9
|
+
|
10
|
+
def subtype(relation, self_type, instance_type, class_type, bounds)
|
11
|
+
key = [relation, self_type, instance_type, class_type, bounds]
|
12
|
+
subtypes[key]
|
13
|
+
end
|
14
|
+
|
15
|
+
def [](relation, self_type, instance_type, class_type, bounds)
|
16
|
+
key = [relation, self_type, instance_type, class_type, bounds]
|
17
|
+
subtypes[key]
|
18
|
+
end
|
19
|
+
|
20
|
+
def []=(relation, self_type, instance_type, class_type, bounds, value)
|
21
|
+
key = [relation, self_type, instance_type, class_type, bounds]
|
22
|
+
subtypes[key] = value
|
23
|
+
end
|
24
|
+
|
25
|
+
def no_subtype_cache?
|
26
|
+
@subtypes.empty?
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|