steep 0.47.1 → 0.48.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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.map{|x| "#{x}" }.join(", ")}] " : ""
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
- type_params = []
99
- s1 = Substitution.build(self.type_params)
100
- type_params.push(*s1.dictionary.values.map(&:name))
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
- self_type_params = Set.new(self.type_params)
138
- other_type_params = Set.new(other.type_params)
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
- type_params = (self_type_params + other_type_params).to_a
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
- self_type_params = Set.new(self.type_params)
186
- other_type_params = Set.new(other.type_params)
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
- type_params = (self_type_params + other_type_params).to_a
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
@@ -14,6 +14,7 @@ module Steep
14
14
  @writer = writer
15
15
  @skip_job = false
16
16
  @shutdown = false
17
+ @skip_jobs_after_shutdown = nil
17
18
  end
18
19
 
19
20
  def skip_jobs_after_shutdown!(flag = true)
@@ -338,7 +338,7 @@ HOVER
338
338
  else
339
339
  ps = params.each.map do |param|
340
340
  s = ""
341
- if param.skip_validation
341
+ if param.unchecked?
342
342
  s << "unchecked "
343
343
  end
344
344
  case param.variance
@@ -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::ErrorBase
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::ErrorBase => exn
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.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
@@ -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