steep 0.46.0 → 0.48.0
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 +4 -4
- data/.github/workflows/ruby.yml +0 -1
- data/CHANGELOG.md +23 -0
- data/Gemfile +1 -2
- data/Gemfile.lock +18 -22
- data/README.md +2 -1
- data/lib/steep/annotation_parser.rb +1 -1
- 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 +60 -15
- data/lib/steep/interface/method_type.rb +14 -26
- data/lib/steep/interface/type_param.rb +103 -0
- data/lib/steep/project/dsl.rb +32 -5
- data/lib/steep/project/options.rb +1 -0
- data/lib/steep/project/target.rb +1 -0
- data/lib/steep/server/base_worker.rb +1 -0
- data/lib/steep/server/interaction_worker.rb +9 -9
- data/lib/steep/server/type_check_worker.rb +2 -2
- data/lib/steep/services/hover_content.rb +3 -0
- 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/source.rb +5 -1
- 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 +493 -372
- data/lib/steep/type_inference/block_params.rb +1 -1
- data/lib/steep/type_inference/context.rb +37 -3
- data/lib/steep/type_inference/send_args.rb +1 -12
- data/lib/steep/version.rb +1 -1
- data/lib/steep.rb +5 -5
- data/sample/lib/length.rb +35 -0
- data/sample/sig/length.rbs +34 -0
- data/smoke/diagnostics/test_expectations.yml +4 -4
- 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/smoke/extension/e.rbs +1 -1
- data/steep.gemspec +1 -1
- metadata +11 -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
- data/sig/project.rbi +0 -109
- data/sig/steep/type_inference/send_args.rbs +0 -42
@@ -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
|
data/lib/steep/source.rb
CHANGED
@@ -71,7 +71,11 @@ module Steep
|
|
71
71
|
|
72
72
|
mapping = {}.compare_by_identity
|
73
73
|
|
74
|
-
|
74
|
+
if node
|
75
|
+
construct_mapping(node: node, annotations: annotations, mapping: mapping)
|
76
|
+
else
|
77
|
+
Steep.logger.fatal { "#{path} is empty source code" }
|
78
|
+
end
|
75
79
|
|
76
80
|
annotations.each do |annot|
|
77
81
|
mapping[node] ||= []
|
@@ -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
|