steep 0.4.0 → 0.5.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 (65) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +12 -0
  3. data/LICENSE +21 -0
  4. data/bin/smoke_runner.rb +3 -0
  5. data/lib/steep/ast/annotation/collection.rb +120 -43
  6. data/lib/steep/ast/annotation.rb +5 -10
  7. data/lib/steep/ast/location.rb +1 -1
  8. data/lib/steep/ast/method_type.rb +3 -1
  9. data/lib/steep/ast/signature/alias.rb +19 -0
  10. data/lib/steep/ast/signature/env.rb +9 -0
  11. data/lib/steep/ast/signature/members.rb +4 -0
  12. data/lib/steep/ast/types/proc.rb +79 -0
  13. data/lib/steep/ast/types/void.rb +4 -0
  14. data/lib/steep/cli.rb +2 -1
  15. data/lib/steep/drivers/check.rb +4 -1
  16. data/lib/steep/errors.rb +13 -0
  17. data/lib/steep/interface/builder.rb +90 -47
  18. data/lib/steep/interface/instantiated.rb +1 -1
  19. data/lib/steep/interface/method.rb +8 -0
  20. data/lib/steep/interface/method_type.rb +40 -13
  21. data/lib/steep/parser.rb +1098 -1043
  22. data/lib/steep/parser.y +94 -36
  23. data/lib/steep/source.rb +5 -6
  24. data/lib/steep/subtyping/check.rb +162 -47
  25. data/lib/steep/subtyping/variable_occurrence.rb +2 -2
  26. data/lib/steep/subtyping/variable_variance.rb +3 -3
  27. data/lib/steep/type_construction.rb +630 -300
  28. data/lib/steep/type_inference/block_params.rb +186 -35
  29. data/lib/steep/type_inference/send_args.rb +12 -3
  30. data/lib/steep/type_inference/type_env.rb +10 -4
  31. data/lib/steep/type_name.rb +6 -0
  32. data/lib/steep/typing.rb +21 -2
  33. data/lib/steep/version.rb +1 -1
  34. data/lib/steep.rb +2 -0
  35. data/smoke/alias/a.rb +19 -0
  36. data/smoke/alias/a.rbi +10 -0
  37. data/smoke/alias/b.rb +7 -0
  38. data/smoke/alias/c.rb +10 -0
  39. data/smoke/array/c.rb +7 -0
  40. data/smoke/block/c.rb +10 -0
  41. data/smoke/block/c.rbi +3 -0
  42. data/smoke/block/d.rb +15 -0
  43. data/smoke/class/c.rb +1 -1
  44. data/smoke/class/e.rb +1 -1
  45. data/smoke/class/h.rb +15 -0
  46. data/smoke/class/h.rbi +7 -0
  47. data/smoke/class/i.rb +17 -0
  48. data/smoke/class/i.rbi +9 -0
  49. data/smoke/extension/a.rbi +4 -0
  50. data/smoke/extension/d.rb +2 -0
  51. data/smoke/hash/a.rb +17 -0
  52. data/smoke/hash/b.rb +7 -0
  53. data/smoke/implements/a.rb +2 -2
  54. data/smoke/initialize/a.rb +1 -1
  55. data/smoke/lambda/a.rb +11 -0
  56. data/smoke/literal/b.rb +9 -0
  57. data/smoke/literal/literal_methods.rbi +4 -0
  58. data/smoke/method/c.rb +5 -0
  59. data/smoke/regression/array.rb +7 -0
  60. data/smoke/regression/hash.rb +7 -0
  61. data/smoke/regression/set_divide.rb +16 -0
  62. data/smoke/self/a.rb +2 -2
  63. data/stdlib/builtin.rbi +151 -1
  64. data/steep.gemspec +1 -0
  65. metadata +30 -4
@@ -73,6 +73,12 @@ module Steep
73
73
  types: type.types.map {|ty| absolute_type(ty, current:current) },
74
74
  location: type.location
75
75
  )
76
+ when AST::Types::Proc
77
+ AST::Types::Proc.new(
78
+ params: type.params.map_type {|ty| absolute_type(ty, current: current) },
79
+ return_type: absolute_type(type.return_type, current: current),
80
+ location: type.location
81
+ )
76
82
  else
77
83
  type
78
84
  end
@@ -137,7 +143,7 @@ module Steep
137
143
  merge_ivars ivars, instantiated.ivars
138
144
  end
139
145
 
140
- def add_method(type_name, method, methods:)
146
+ def add_method(type_name, method, methods:, extra_attributes: [])
141
147
  super_method = methods[method.name]
142
148
  new_method = Method.new(
143
149
  type_name: type_name,
@@ -146,7 +152,7 @@ module Steep
146
152
  method_type_to_method_type(method_type, current: type_name.name)
147
153
  end,
148
154
  super_method: super_method,
149
- attributes: method.attributes
155
+ attributes: method.attributes + extra_attributes
150
156
  )
151
157
 
152
158
  methods[method.name] = if super_method&.include_in_chain?(new_method)
@@ -243,6 +249,17 @@ module Steep
243
249
  end
244
250
  end
245
251
 
252
+ signatures.find_extensions(sig.name).each do |ext|
253
+ ext.members.each do |member|
254
+ case member
255
+ when AST::Signature::Members::Method
256
+ if member.module_method?
257
+ add_method(type_name, member, methods: methods)
258
+ end
259
+ end
260
+ end
261
+ end
262
+
246
263
  unless constructor
247
264
  methods.delete(:new)
248
265
  end
@@ -261,6 +278,7 @@ module Steep
261
278
 
262
279
  supers = [sig.self_type].compact.map {|type| absolute_type(type, current: nil) }
263
280
  methods = {}
281
+ ivar_chains = {}
264
282
 
265
283
  module_instance = build(TypeName::Instance.new(name: ModuleName.parse("::Module")))
266
284
  instantiated = module_instance.instantiate(
@@ -277,14 +295,14 @@ module Steep
277
295
  merge_mixin(TypeName::Module.new(name: member.name),
278
296
  member.args.map {|type| absolute_type(type, current: sig.name) },
279
297
  methods: methods,
280
- ivars: {},
298
+ ivars: ivar_chains,
281
299
  supers: supers,
282
300
  current: sig.name)
283
301
  when AST::Signature::Members::Extend
284
302
  merge_mixin(TypeName::Instance.new(name: member.name),
285
303
  member.args.map {|type| absolute_type(type, current: sig.name) },
286
304
  methods: methods,
287
- ivars: {},
305
+ ivars: ivar_chains,
288
306
  supers: supers,
289
307
  current: sig.name)
290
308
  end
@@ -296,6 +314,22 @@ module Steep
296
314
  if member.module_method?
297
315
  add_method(type_name, member, methods: methods)
298
316
  end
317
+ when AST::Signature::Members::Ivar
318
+ merge_ivars(ivar_chains,
319
+ { member.name => absolute_type(member.type, current: sig.name) })
320
+ when AST::Signature::Members::Attr
321
+ merge_attribute(sig, ivar_chains, methods, type_name, member)
322
+ end
323
+ end
324
+
325
+ signatures.find_extensions(sig.name).each do |ext|
326
+ ext.members.each do |member|
327
+ case member
328
+ when AST::Signature::Members::Method
329
+ if member.module_method?
330
+ add_method(type_name, member, methods: methods)
331
+ end
332
+ end
299
333
  end
300
334
  end
301
335
 
@@ -304,7 +338,7 @@ module Steep
304
338
  params: [],
305
339
  methods: methods,
306
340
  supers: supers,
307
- ivar_chains: {}
341
+ ivar_chains: ivar_chains
308
342
  )
309
343
  end
310
344
 
@@ -319,7 +353,7 @@ module Steep
319
353
  if sig.is_a?(AST::Signature::Class)
320
354
  unless sig.name == ModuleName.parse("::BasicObject")
321
355
  super_class_name = sig.super_class&.name || ModuleName.parse("::Object")
322
- super_class_interface = build(TypeName::Instance.new(name: super_class_name), current: nil)
356
+ super_class_interface = build(TypeName::Instance.new(name: super_class_name), current: nil, with_initialize: with_initialize)
323
357
 
324
358
  supers.push(*super_class_interface.supers)
325
359
  instantiated = super_class_interface.instantiate(
@@ -357,51 +391,15 @@ module Steep
357
391
  when AST::Signature::Members::Method
358
392
  if member.instance_method?
359
393
  if with_initialize || member.name != :initialize
360
- add_method(type_name, member, methods: methods)
394
+ extra_attrs = member.name == :initialize ? [:incompatible] : []
395
+ add_method(type_name, member, methods: methods, extra_attributes: extra_attrs)
361
396
  end
362
397
  end
363
398
  when AST::Signature::Members::Ivar
364
399
  merge_ivars(ivar_chains,
365
400
  { member.name => absolute_type(member.type, current: sig.name) })
366
401
  when AST::Signature::Members::Attr
367
- if member.ivar != false
368
- ivar_name = member.ivar || "@#{member.name}".to_sym
369
- merge_ivars(ivar_chains,
370
- { ivar_name => absolute_type(member.type, current: sig.name) })
371
- end
372
-
373
- reader_method = AST::Signature::Members::Method.new(
374
- location: member.location,
375
- name: member.name,
376
- kind: :instance,
377
- types: [
378
- AST::MethodType.new(location: member.type.location,
379
- type_params: nil,
380
- params: nil,
381
- block: nil,
382
- return_type: member.type)
383
- ],
384
- attributes: []
385
- )
386
- add_method(type_name, reader_method, methods: methods)
387
-
388
- if member.accessor?
389
- writer_method = AST::Signature::Members::Method.new(
390
- location: member.location,
391
- name: "#{member.name}=".to_sym,
392
- kind: :instance,
393
- types: [
394
- AST::MethodType.new(location: member.type.location,
395
- type_params: nil,
396
- params: AST::MethodType::Params::Required.new(location: member.type.location,
397
- type: member.type),
398
- block: nil,
399
- return_type: member.type)
400
- ],
401
- attributes: []
402
- )
403
- add_method(type_name, writer_method, methods: methods)
404
- end
402
+ merge_attribute(sig, ivar_chains, methods, type_name, member)
405
403
  end
406
404
  end
407
405
 
@@ -425,6 +423,47 @@ module Steep
425
423
  )
426
424
  end
427
425
 
426
+ def merge_attribute(sig, ivar_chains, methods, type_name, member)
427
+ if member.ivar != false
428
+ ivar_name = member.ivar || "@#{member.name}".to_sym
429
+ merge_ivars(ivar_chains,
430
+ { ivar_name => absolute_type(member.type, current: sig.name) })
431
+ end
432
+
433
+ reader_method = AST::Signature::Members::Method.new(
434
+ location: member.location,
435
+ name: member.name,
436
+ kind: :instance,
437
+ types: [
438
+ AST::MethodType.new(location: member.type.location,
439
+ type_params: nil,
440
+ params: nil,
441
+ block: nil,
442
+ return_type: member.type)
443
+ ],
444
+ attributes: []
445
+ )
446
+ add_method(type_name, reader_method, methods: methods)
447
+
448
+ if member.accessor?
449
+ writer_method = AST::Signature::Members::Method.new(
450
+ location: member.location,
451
+ name: "#{member.name}=".to_sym,
452
+ kind: :instance,
453
+ types: [
454
+ AST::MethodType.new(location: member.type.location,
455
+ type_params: nil,
456
+ params: AST::MethodType::Params::Required.new(location: member.type.location,
457
+ type: member.type),
458
+ block: nil,
459
+ return_type: member.type)
460
+ ],
461
+ attributes: []
462
+ )
463
+ add_method(type_name, writer_method, methods: methods)
464
+ end
465
+ end
466
+
428
467
  def merge_ivars(dest, new_vars)
429
468
  new_vars.each do |name, new_type|
430
469
  dest[name] = IvarChain.new(type: new_type, parent: dest[name])
@@ -460,8 +499,12 @@ module Steep
460
499
  type_params = method_type.type_params&.variables || []
461
500
  params = params_to_params(method_type.params, current: current)
462
501
  block = method_type.block && Block.new(
463
- params: params_to_params(method_type.block.params, current: current),
464
- return_type: absolute_type(method_type.block.return_type, current: current)
502
+ type: AST::Types::Proc.new(
503
+ params: params_to_params(method_type.block.params, current: current),
504
+ return_type: absolute_type(method_type.block.return_type, current: current),
505
+ location: method_type.block.location,
506
+ ),
507
+ optional: method_type.block.optional
465
508
  )
466
509
 
467
510
  MethodType.new(
@@ -85,7 +85,7 @@ module Steep
85
85
  end
86
86
 
87
87
  def validate_method(check, method)
88
- if method.super_method
88
+ if method.super_method && !method.incompatible?
89
89
  result = check.check_method(method.name,
90
90
  method,
91
91
  method.super_method,
@@ -24,6 +24,10 @@ module Steep
24
24
  other.attributes == attributes
25
25
  end
26
26
 
27
+ def incompatible?
28
+ attributes.include?(:incompatible)
29
+ end
30
+
27
31
  def closed?
28
32
  types.all?(&:closed?)
29
33
  end
@@ -58,6 +62,10 @@ module Steep
58
62
  )
59
63
  end
60
64
 
65
+ def map_types
66
+ with_types(types.map {|type| yield type })
67
+ end
68
+
61
69
  def include_in_chain?(method)
62
70
  (method.type_name == type_name &&
63
71
  method.name == name &&
@@ -17,6 +17,18 @@ module Steep
17
17
  @rest_keywords = rest_keywords
18
18
  end
19
19
 
20
+ NONE = Object.new
21
+ def update(required: NONE, optional: NONE, rest: NONE, required_keywords: NONE, optional_keywords: NONE, rest_keywords: NONE)
22
+ self.class.new(
23
+ required: required.equal?(NONE) ? self.required : required,
24
+ optional: optional.equal?(NONE) ? self.optional : optional,
25
+ rest: rest.equal?(NONE) ? self.rest : rest,
26
+ required_keywords: required_keywords.equal?(NONE) ? self.required_keywords : required_keywords,
27
+ optional_keywords: optional_keywords.equal?(NONE) ? self.optional_keywords : optional_keywords,
28
+ rest_keywords: rest_keywords.equal?(NONE) ? self.rest_keywords : rest_keywords
29
+ )
30
+ end
31
+
20
32
  def self.empty
21
33
  self.new(
22
34
  required: [],
@@ -176,38 +188,53 @@ module Steep
176
188
  rest_keywords = self.rest_keywords ? ["**#{self.rest_keywords}"] : []
177
189
  "(#{(required + optional + rest + required_keywords + optional_keywords + rest_keywords).join(", ")})"
178
190
  end
191
+
192
+ def map_type(&block)
193
+ self.class.new(
194
+ required: required.map(&block),
195
+ optional: optional.map(&block),
196
+ rest: rest && yield(rest),
197
+ required_keywords: required_keywords.transform_values(&block),
198
+ optional_keywords: optional_keywords.transform_values(&block),
199
+ rest_keywords: rest_keywords && yield(rest_keywords)
200
+ )
201
+ end
179
202
  end
180
203
 
181
204
  class Block
182
- attr_reader :params
183
- attr_reader :return_type
205
+ attr_reader :type
206
+ attr_reader :optional
184
207
 
185
- def initialize(params:, return_type:)
186
- @params = params
187
- @return_type = return_type
208
+ def initialize(type:, optional:)
209
+ @type = type
210
+ @optional = optional
211
+ end
212
+
213
+ def optional?
214
+ @optional
188
215
  end
189
216
 
190
217
  def ==(other)
191
- other.is_a?(self.class) && other.params == params && other.return_type == return_type
218
+ other.is_a?(self.class) && other.type == type && other.optional == optional
192
219
  end
193
220
 
194
221
  def closed?
195
- params.closed? && return_type.closed?
222
+ type.closed?
196
223
  end
197
224
 
198
225
  def subst(s)
199
226
  self.class.new(
200
- params: params.subst(s),
201
- return_type: return_type.subst(s)
227
+ type: type.subst(s),
228
+ optional: optional
202
229
  )
203
230
  end
204
231
 
205
232
  def free_variables
206
- params.free_variables + return_type.free_variables
233
+ type.free_variables
207
234
  end
208
235
 
209
236
  def to_s
210
- "{ #{params} -> #{return_type} }"
237
+ "#{optional? ? "?" : ""}{ #{type.params} -> #{type.return_type} }"
211
238
  end
212
239
  end
213
240
 
@@ -257,8 +284,8 @@ module Steep
257
284
  if block_given?
258
285
  params.each_type(&block)
259
286
  self.block&.tap do
260
- self.block.params.each_type(&block)
261
- yield(self.block.return_type)
287
+ self.block.type.params.each_type(&block)
288
+ yield(self.block.type.return_type)
262
289
  end
263
290
  yield(return_type)
264
291
  else