steep 0.4.0 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
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