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.
Files changed (49) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ruby.yml +0 -1
  3. data/CHANGELOG.md +23 -0
  4. data/Gemfile +1 -2
  5. data/Gemfile.lock +18 -22
  6. data/README.md +2 -1
  7. data/lib/steep/annotation_parser.rb +1 -1
  8. data/lib/steep/ast/types/factory.rb +161 -137
  9. data/lib/steep/ast/types/var.rb +14 -3
  10. data/lib/steep/diagnostic/ruby.rb +23 -11
  11. data/lib/steep/diagnostic/signature.rb +60 -15
  12. data/lib/steep/interface/method_type.rb +14 -26
  13. data/lib/steep/interface/type_param.rb +103 -0
  14. data/lib/steep/project/dsl.rb +32 -5
  15. data/lib/steep/project/options.rb +1 -0
  16. data/lib/steep/project/target.rb +1 -0
  17. data/lib/steep/server/base_worker.rb +1 -0
  18. data/lib/steep/server/interaction_worker.rb +9 -9
  19. data/lib/steep/server/type_check_worker.rb +2 -2
  20. data/lib/steep/services/hover_content.rb +3 -0
  21. data/lib/steep/services/signature_service.rb +2 -2
  22. data/lib/steep/services/type_check_service.rb +2 -1
  23. data/lib/steep/signature/validator.rb +221 -49
  24. data/lib/steep/source.rb +5 -1
  25. data/lib/steep/subtyping/cache.rb +30 -0
  26. data/lib/steep/subtyping/check.rb +582 -708
  27. data/lib/steep/subtyping/constraints.rb +66 -30
  28. data/lib/steep/subtyping/relation.rb +60 -0
  29. data/lib/steep/subtyping/result.rb +190 -16
  30. data/lib/steep/type_construction.rb +493 -372
  31. data/lib/steep/type_inference/block_params.rb +1 -1
  32. data/lib/steep/type_inference/context.rb +37 -3
  33. data/lib/steep/type_inference/send_args.rb +1 -12
  34. data/lib/steep/version.rb +1 -1
  35. data/lib/steep.rb +5 -5
  36. data/sample/lib/length.rb +35 -0
  37. data/sample/sig/length.rbs +34 -0
  38. data/smoke/diagnostics/test_expectations.yml +4 -4
  39. data/smoke/diagnostics-rbs/nonregular-type-alias.rbs +3 -0
  40. data/smoke/diagnostics-rbs/recursive-type-alias.rbs +3 -0
  41. data/smoke/diagnostics-rbs/test_expectations.yml +57 -12
  42. data/smoke/extension/e.rbs +1 -1
  43. data/steep.gemspec +1 -1
  44. metadata +11 -10
  45. data/lib/steep/drivers/trace_printer.rb +0 -29
  46. data/lib/steep/interface/method.rb +0 -78
  47. data/lib/steep/subtyping/trace.rb +0 -71
  48. data/sig/project.rbi +0 -109
  49. 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.instance_variables.each do |name, var|
119
- if parent = var.parent_variable
120
- var_type = checker.factory.type(var.type)
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
- relation = Subtyping::Relation.new(sub_type: var_type, super_type: parent_type)
124
- result1 = checker.check(
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
- result2 = checker.check(
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: var.type.location,
143
- var_type: var_type,
144
- parent_type: parent_type
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
- ancestors = builder.ancestor_builder.one_instance_ancestors(name)
151
- mixin_constraints(definition, ancestors.included_modules, immediate_self_types: ancestors.self_types).each do |relation, ancestor|
152
- checker.check(
153
- relation,
154
- self_type: AST::Types::Self.new,
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
- definition.each_type do |type|
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
- definition.each_type do |type|
225
- validate_type type
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).each_type do |type|
237
- validate_type type
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
- builder.expand_alias(name).tap do |type|
284
- validate_type(type)
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::ErrorBase => exn
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
- construct_mapping(node: node, annotations: annotations, mapping: mapping)
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