steep 0.1.0.pre2 → 0.1.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 (119) hide show
  1. checksums.yaml +5 -5
  2. data/.travis.yml +1 -1
  3. data/README.md +146 -33
  4. data/bin/smoke_runner.rb +43 -10
  5. data/lib/steep/ast/annotation/collection.rb +93 -0
  6. data/lib/steep/ast/annotation.rb +131 -0
  7. data/lib/steep/ast/buffer.rb +47 -0
  8. data/lib/steep/ast/location.rb +82 -0
  9. data/lib/steep/ast/method_type.rb +116 -0
  10. data/lib/steep/ast/signature/class.rb +33 -0
  11. data/lib/steep/ast/signature/const.rb +17 -0
  12. data/lib/steep/ast/signature/env.rb +123 -0
  13. data/lib/steep/ast/signature/extension.rb +21 -0
  14. data/lib/steep/ast/signature/gvar.rb +17 -0
  15. data/lib/steep/ast/signature/interface.rb +31 -0
  16. data/lib/steep/ast/signature/members.rb +71 -0
  17. data/lib/steep/ast/signature/module.rb +21 -0
  18. data/lib/steep/ast/type_params.rb +13 -0
  19. data/lib/steep/ast/types/any.rb +39 -0
  20. data/lib/steep/ast/types/bot.rb +39 -0
  21. data/lib/steep/ast/types/class.rb +35 -0
  22. data/lib/steep/ast/types/helper.rb +21 -0
  23. data/lib/steep/ast/types/instance.rb +39 -0
  24. data/lib/steep/ast/types/intersection.rb +74 -0
  25. data/lib/steep/ast/types/name.rb +124 -0
  26. data/lib/steep/ast/types/self.rb +39 -0
  27. data/lib/steep/ast/types/top.rb +39 -0
  28. data/lib/steep/ast/types/union.rb +74 -0
  29. data/lib/steep/ast/types/var.rb +57 -0
  30. data/lib/steep/ast/types/void.rb +35 -0
  31. data/lib/steep/cli.rb +28 -1
  32. data/lib/steep/drivers/annotations.rb +32 -0
  33. data/lib/steep/drivers/check.rb +53 -77
  34. data/lib/steep/drivers/scaffold.rb +303 -0
  35. data/lib/steep/drivers/utils/each_signature.rb +66 -0
  36. data/lib/steep/drivers/utils/validator.rb +115 -0
  37. data/lib/steep/drivers/validate.rb +39 -0
  38. data/lib/steep/errors.rb +291 -19
  39. data/lib/steep/interface/abstract.rb +44 -0
  40. data/lib/steep/interface/builder.rb +470 -0
  41. data/lib/steep/interface/instantiated.rb +126 -0
  42. data/lib/steep/interface/ivar_chain.rb +26 -0
  43. data/lib/steep/interface/method.rb +60 -0
  44. data/lib/steep/{interface.rb → interface/method_type.rb} +111 -100
  45. data/lib/steep/interface/substitution.rb +65 -0
  46. data/lib/steep/module_name.rb +116 -0
  47. data/lib/steep/parser.rb +1314 -814
  48. data/lib/steep/parser.y +536 -175
  49. data/lib/steep/source.rb +220 -25
  50. data/lib/steep/subtyping/check.rb +673 -0
  51. data/lib/steep/subtyping/constraints.rb +275 -0
  52. data/lib/steep/subtyping/relation.rb +41 -0
  53. data/lib/steep/subtyping/result.rb +126 -0
  54. data/lib/steep/subtyping/trace.rb +48 -0
  55. data/lib/steep/subtyping/variable_occurrence.rb +49 -0
  56. data/lib/steep/subtyping/variable_variance.rb +69 -0
  57. data/lib/steep/type_construction.rb +1630 -524
  58. data/lib/steep/type_inference/block_params.rb +100 -0
  59. data/lib/steep/type_inference/constant_env.rb +55 -0
  60. data/lib/steep/type_inference/send_args.rb +222 -0
  61. data/lib/steep/type_inference/type_env.rb +226 -0
  62. data/lib/steep/type_name.rb +27 -7
  63. data/lib/steep/typing.rb +4 -0
  64. data/lib/steep/version.rb +1 -1
  65. data/lib/steep.rb +71 -16
  66. data/smoke/and/a.rb +4 -2
  67. data/smoke/array/a.rb +4 -5
  68. data/smoke/array/b.rb +4 -4
  69. data/smoke/block/a.rb +2 -2
  70. data/smoke/block/a.rbi +2 -0
  71. data/smoke/block/b.rb +15 -0
  72. data/smoke/case/a.rb +3 -3
  73. data/smoke/class/a.rb +3 -3
  74. data/smoke/class/b.rb +0 -2
  75. data/smoke/class/d.rb +2 -2
  76. data/smoke/class/e.rb +1 -1
  77. data/smoke/class/f.rb +2 -2
  78. data/smoke/class/g.rb +8 -0
  79. data/smoke/const/a.rb +3 -3
  80. data/smoke/dstr/a.rb +1 -1
  81. data/smoke/ensure/a.rb +22 -0
  82. data/smoke/enumerator/a.rb +6 -6
  83. data/smoke/enumerator/b.rb +22 -0
  84. data/smoke/extension/a.rb +2 -2
  85. data/smoke/extension/b.rb +3 -3
  86. data/smoke/extension/c.rb +1 -1
  87. data/smoke/hello/hello.rb +2 -2
  88. data/smoke/if/a.rb +4 -2
  89. data/smoke/kwbegin/a.rb +8 -0
  90. data/smoke/literal/a.rb +5 -5
  91. data/smoke/method/a.rb +5 -5
  92. data/smoke/method/a.rbi +4 -0
  93. data/smoke/method/b.rb +29 -0
  94. data/smoke/module/a.rb +3 -3
  95. data/smoke/module/a.rbi +9 -0
  96. data/smoke/module/b.rb +2 -2
  97. data/smoke/module/c.rb +1 -1
  98. data/smoke/module/d.rb +5 -0
  99. data/smoke/module/e.rb +13 -0
  100. data/smoke/module/f.rb +13 -0
  101. data/smoke/rescue/a.rb +62 -0
  102. data/smoke/super/a.rb +2 -2
  103. data/smoke/type_case/a.rb +35 -0
  104. data/smoke/yield/a.rb +2 -2
  105. data/stdlib/builtin.rbi +463 -24
  106. data/steep.gemspec +3 -2
  107. metadata +91 -29
  108. data/lib/steep/annotation.rb +0 -223
  109. data/lib/steep/signature/class.rb +0 -450
  110. data/lib/steep/signature/extension.rb +0 -51
  111. data/lib/steep/signature/interface.rb +0 -49
  112. data/lib/steep/types/any.rb +0 -31
  113. data/lib/steep/types/class.rb +0 -27
  114. data/lib/steep/types/instance.rb +0 -27
  115. data/lib/steep/types/merge.rb +0 -32
  116. data/lib/steep/types/name.rb +0 -57
  117. data/lib/steep/types/union.rb +0 -42
  118. data/lib/steep/types/var.rb +0 -38
  119. data/lib/steep/types.rb +0 -4
@@ -1,5 +1,5 @@
1
1
  module Steep
2
- class Interface
2
+ module Interface
3
3
  class Params
4
4
  attr_reader :required
5
5
  attr_reader :optional
@@ -17,17 +17,15 @@ module Steep
17
17
  @rest_keywords = rest_keywords
18
18
  end
19
19
 
20
- def with(required: nil, optional: nil, rest: nil, required_keywords: nil, optional_keywords: nil, rest_keywords: nil)
21
- self.class.new(required: required || self.required,
22
- optional: optional || self.optional,
23
- rest: rest || self.rest,
24
- required_keywords: required_keywords || self.required_keywords,
25
- optional_keywords: optional_keywords || self.optional_keywords,
26
- rest_keywords: rest_keywords || self.rest_keywords)
27
- end
28
-
29
20
  def self.empty
30
- new(required: [], optional: [], rest: nil, required_keywords: {}, optional_keywords: {}, rest_keywords: nil)
21
+ self.new(
22
+ required: [],
23
+ optional: [],
24
+ rest: nil,
25
+ required_keywords: {},
26
+ optional_keywords: {},
27
+ rest_keywords: nil
28
+ )
31
29
  end
32
30
 
33
31
  def ==(other)
@@ -138,150 +136,163 @@ module Steep
138
136
  end
139
137
  end
140
138
 
139
+ def free_variables
140
+ Set.new.tap do |fvs|
141
+ each_type do |type|
142
+ fvs.merge type.free_variables
143
+ end
144
+ end
145
+ end
146
+
141
147
  def closed?
142
148
  required.all?(&:closed?) && optional.all?(&:closed?) && (!rest || rest.closed?) && required_keywords.values.all?(&:closed?) && optional_keywords.values.all?(&:closed?) && (!rest_keywords || rest_keywords.closed?)
143
149
  end
144
150
 
145
- def substitute(klass:, instance:, params:)
146
- self.class.new(required: required.map {|t| t.substitute(klass: klass, instance: instance, params: params) },
147
- optional: optional.map {|t| t.substitute(klass: klass, instance: instance, params: params) },
148
- rest: rest&.substitute(klass: klass, instance: instance, params: params),
149
- required_keywords: required_keywords.transform_values {|t| t.substitute(klass: klass, instance: instance, params: params) },
150
- optional_keywords: optional_keywords.transform_values {|t| t.substitute(klass: klass, instance: instance, params: params) },
151
- rest_keywords: rest_keywords&.substitute(klass: klass, instance: instance, params: params) )
151
+ def has_keyword?
152
+ required_keywords.any? || optional_keywords.any? || rest_keywords
153
+ end
154
+
155
+ def subst(s)
156
+ self.class.new(
157
+ required: required.map {|t| t.subst(s) },
158
+ optional: optional.map {|t| t.subst(s) },
159
+ rest: rest&.subst(s),
160
+ required_keywords: required_keywords.transform_values {|t| t.subst(s) },
161
+ optional_keywords: optional_keywords.transform_values {|t| t.subst(s) },
162
+ rest_keywords: rest_keywords&.subst(s)
163
+ )
152
164
  end
153
165
 
154
166
  def size
155
167
  required.size + optional.size + (rest ? 1 : 0) + required_keywords.size + optional_keywords.size + (rest_keywords ? 1 : 0)
156
168
  end
169
+
170
+ def to_s
171
+ required = self.required.map {|ty| ty.to_s }
172
+ optional = self.optional.map {|ty| "?#{ty}" }
173
+ rest = self.rest ? ["*#{self.rest}"] : []
174
+ required_keywords = self.required_keywords.map {|name, type| "#{name}: #{type}" }
175
+ optional_keywords = self.optional_keywords.map {|name, type| "?#{name}: #{type}"}
176
+ rest_keywords = self.rest_keywords ? ["**#{self.rest_keywords}"] : []
177
+ "(#{(required + optional + rest + required_keywords + optional_keywords + rest_keywords).join(", ")})"
178
+ end
157
179
  end
158
180
 
159
- class MethodType
160
- attr_reader :type_params
181
+ class Block
161
182
  attr_reader :params
162
- attr_reader :block
163
183
  attr_reader :return_type
164
184
 
165
- NONE = Object.new
166
-
167
- def initialize(type_params:, params:, block:, return_type:)
168
- @type_params = type_params
185
+ def initialize(params:, return_type:)
169
186
  @params = params
170
- @block = block
171
187
  @return_type = return_type
172
188
  end
173
189
 
174
- def updated(type_params: NONE, params: NONE, block: NONE, return_type: NONE)
175
- self.class.new(type_params: type_params.equal?(NONE) ? self.type_params : type_params,
176
- params: params.equal?(NONE) ? self.params : params,
177
- block: block.equal?(NONE) ? self.block : block,
178
- return_type: return_type.equal?(NONE) ? self.return_type : return_type)
179
- end
180
-
181
190
  def ==(other)
182
- other.is_a?(self.class) &&
183
- other.params == params &&
184
- other.block == block &&
185
- other.return_type == return_type
191
+ other.is_a?(self.class) && other.params == params && other.return_type == return_type
186
192
  end
187
193
 
188
194
  def closed?
189
- params.closed? && (!block || block.closed?) && return_type.closed?
195
+ params.closed? && return_type.closed?
190
196
  end
191
197
 
192
- def substitute(klass:, instance:, params:)
193
- self.class.new(type_params: type_params,
194
- params: self.params.substitute(klass: klass, instance: instance, params: params),
195
- block: block&.substitute(klass: klass, instance: instance, params: params),
196
- return_type: return_type.substitute(klass: klass, instance: instance, params: params))
198
+ def subst(s)
199
+ self.class.new(
200
+ params: params.subst(s),
201
+ return_type: return_type.subst(s)
202
+ )
197
203
  end
198
204
 
199
- def instantiate(subst:)
200
- raise "Open method type cannot be instantiated" unless closed?
205
+ def free_variables
206
+ params.free_variables + return_type.free_variables
207
+ end
201
208
 
202
- self.class.new(type_params: type_params.reject {|param| subst.key?(param) },
203
- params: self.params.substitute(klass: nil, instance: nil, params: subst),
204
- block: block&.substitute(klass: nil, instance: nil, params: subst),
205
- return_type: return_type.substitute(klass: nil, instance: nil, params: subst))
209
+ def to_s
210
+ "{ #{params} -> #{return_type} }"
206
211
  end
207
212
  end
208
213
 
209
- class Block
214
+ class MethodType
215
+ attr_reader :type_params
210
216
  attr_reader :params
217
+ attr_reader :block
211
218
  attr_reader :return_type
219
+ attr_reader :location
212
220
 
213
- def initialize(params:, return_type:)
221
+ NONE = Object.new
222
+
223
+ def initialize(type_params:, params:, block:, return_type:, location:)
224
+ @type_params = type_params
214
225
  @params = params
226
+ @block = block
215
227
  @return_type = return_type
228
+ @location = location
216
229
  end
217
230
 
218
231
  def ==(other)
219
- other.is_a?(self.class) && other.params == params && other.return_type == return_type
220
- end
221
-
222
- def closed?
223
- params.closed? && return_type.closed?
232
+ other.is_a?(self.class) &&
233
+ other.type_params == type_params &&
234
+ other.params == params &&
235
+ other.block == block &&
236
+ other.return_type == return_type &&
237
+ (!other.location || !location || other.location == location)
224
238
  end
225
239
 
226
- def substitute(klass:, instance:, params:)
227
- self.class.new(params: self.params.substitute(klass: klass, instance: instance, params: params),
228
- return_type: return_type.substitute(klass: klass, instance: instance, params: params))
240
+ def free_variables
241
+ (params.free_variables + (block&.free_variables || Set.new) + return_type.free_variables) - Set.new(type_params)
229
242
  end
230
- end
231
-
232
- class Method
233
- attr_reader :super_method
234
- attr_reader :types
235
- attr_reader :attributes
236
243
 
237
- def initialize(types:, super_method:, attributes:)
238
- @types = types
239
- @super_method = super_method
240
- @attributes = attributes
241
- end
244
+ def subst(s)
245
+ s_ = s.except(type_params)
242
246
 
243
- def ==(other)
244
- other.is_a?(Method) &&
245
- other.types == types &&
246
- other.super_method == super_method &&
247
- other.attributes == attributes
247
+ self.class.new(
248
+ type_params: type_params,
249
+ params: params.subst(s_),
250
+ block: block&.subst(s_),
251
+ return_type: return_type.subst(s_),
252
+ location: location
253
+ )
248
254
  end
249
255
 
250
- def closed?
251
- types.all?(&:closed?)
256
+ def each_type(&block)
257
+ if block_given?
258
+ params.each_type(&block)
259
+ self.block&.tap do
260
+ self.block.params.each_type(&block)
261
+ yield(self.block.return_type)
262
+ end
263
+ yield(return_type)
264
+ else
265
+ enum_for :each_type
266
+ end
252
267
  end
253
268
 
254
- def substitute(klass:, instance:, params:)
269
+ def instantiate(s)
255
270
  self.class.new(
256
- types: types.map {|type| type.substitute(klass: klass, instance: instance, params: params) },
257
- super_method: super_method&.substitute(klass: klass, instance: instance, params: params)
258
- )
271
+ type_params: [],
272
+ params: params.subst(s),
273
+ block: block&.subst(s),
274
+ return_type: return_type.subst(s),
275
+ location: location,
276
+ )
259
277
  end
260
278
 
261
- def map_types()
279
+ def with(type_params: NONE, params: NONE, block: NONE, return_type: NONE, location: NONE)
262
280
  self.class.new(
263
- types: types.map {|type| yield(type) },
264
- super_method: super_method
281
+ type_params: type_params.equal?(NONE) ? self.type_params : type_params,
282
+ params: params.equal?(NONE) ? self.params : params,
283
+ block: block.equal?(NONE) ? self.block : block,
284
+ return_type: return_type.equal?(NONE) ? self.return_type : return_type,
285
+ location: location.equal?(NONE) ? self.location : location
265
286
  )
266
287
  end
267
- end
268
-
269
- attr_reader :name
270
- attr_reader :params
271
- attr_reader :methods
272
288
 
273
- def initialize(name:, params:, methods:)
274
- @name = name
275
- @params = params
276
- @methods = methods
277
- end
278
-
279
- def closed?
280
- methods.values.all?(&:closed?)
281
- end
289
+ def to_s
290
+ type_params = !self.type_params.empty? ? "<#{self.type_params.map{|x| "'#{x}" }.join(", ")}> " : ""
291
+ params = self.params.to_s
292
+ block = self.block ? " #{self.block}" : ""
282
293
 
283
- def ==(other)
284
- other.is_a?(self.class) && other.name == name && other.params == params && other.methods == methods
294
+ "#{type_params}#{params}#{block} -> #{return_type}"
295
+ end
285
296
  end
286
297
  end
287
298
  end
@@ -0,0 +1,65 @@
1
+ module Steep
2
+ module Interface
3
+ class Substitution
4
+ attr_reader :dictionary
5
+ attr_reader :instance_type
6
+ attr_reader :module_type
7
+ attr_reader :self_type
8
+
9
+ def initialize(dictionary:, instance_type:, module_type:, self_type:)
10
+ @dictionary = dictionary
11
+ @instance_type = instance_type
12
+ @module_type = module_type
13
+ @self_type = self_type
14
+ end
15
+
16
+ def self.empty
17
+ new(dictionary: {}, instance_type: AST::Types::Instance.new, module_type: AST::Types::Class.new, self_type: AST::Types::Self.new)
18
+ end
19
+
20
+ def [](key)
21
+ dictionary[key] or raise "Unknown variable: #{key}"
22
+ end
23
+
24
+ def key?(var)
25
+ dictionary.key?(var)
26
+ end
27
+
28
+ def self.build(vars, types = nil, instance_type: AST::Types::Instance.new, module_type: AST::Types::Class.new, self_type: AST::Types::Self.new)
29
+ types ||= vars.map {|var| AST::Types::Var.fresh(var) }
30
+
31
+ raise "Invalid substitution: vars.size=#{vars.size}, types.size=#{types.size}" unless vars.size == types.size
32
+
33
+ dic = vars.zip(types).each.with_object({}) do |(var, type), d|
34
+ d[var] = type
35
+ end
36
+
37
+ new(dictionary: dic, instance_type: instance_type, module_type: module_type, self_type: self_type)
38
+ end
39
+
40
+ def except(vars)
41
+ self.class.new(
42
+ dictionary: dictionary.reject {|k, _| vars.include?(k) },
43
+ instance_type: instance_type,
44
+ module_type: module_type,
45
+ self_type: self_type
46
+ )
47
+ end
48
+
49
+ def merge!(s)
50
+ dictionary.transform_values! {|ty| ty.subst(s) }
51
+ dictionary.merge!(s.dictionary) do |key, a, b|
52
+ if a == b
53
+ a
54
+ else
55
+ raise "Duplicated key on merge!: #{key}, #{a}, #{b}"
56
+ end
57
+ end
58
+ end
59
+
60
+ def add!(v, ty)
61
+ merge!(Substitution.new(dictionary: { v => ty }, instance_type: nil, module_type: nil, self_type: nil))
62
+ end
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,116 @@
1
+ module Steep
2
+ class ModuleName
3
+ attr_reader :name
4
+
5
+ def initialize(name:, absolute:)
6
+ @name = name
7
+ @absolute = absolute
8
+ end
9
+
10
+ def self.parse(name)
11
+ name = name.to_s
12
+ new(name: name.gsub(/\A::/, ""), absolute: name.start_with?("::"))
13
+ end
14
+
15
+ def self.from_node(node)
16
+ case node.type
17
+ when :const
18
+ relative_node = new(name: node.children.last.to_s, absolute: false)
19
+ parent_node = node.children.first
20
+
21
+ case parent_node&.type
22
+ when :cbase
23
+ relative_node.absolute!
24
+ when nil
25
+ relative_node
26
+ else
27
+ from_node(parent_node)&.yield_self do |parent|
28
+ parent + relative_node
29
+ end
30
+ end
31
+ when :casgn
32
+ relative_node = new(name: node.children[1].to_s, absolute: false)
33
+ parent_node = node.children.first
34
+
35
+ case parent_node&.type
36
+ when :cbase
37
+ relative_node.absolute!
38
+ when nil
39
+ relative_node
40
+ else
41
+ from_node(parent_node)&.yield_self do |parent|
42
+ parent + relative_node
43
+ end
44
+ end
45
+ else
46
+ nil
47
+ end
48
+ end
49
+
50
+ def ==(other)
51
+ other.is_a?(self.class) && other.name == name && other.absolute? == absolute?
52
+ end
53
+
54
+ def hash
55
+ self.class.hash ^ name.hash ^ @absolute.hash
56
+ end
57
+
58
+ alias eql? ==
59
+
60
+ def absolute!
61
+ self.class.new(name: name, absolute: true)
62
+ end
63
+
64
+ def absolute?
65
+ !!@absolute
66
+ end
67
+
68
+ def relative?
69
+ !absolute?
70
+ end
71
+
72
+ def to_s
73
+ if absolute?
74
+ "::#{name}"
75
+ else
76
+ name
77
+ end
78
+ end
79
+
80
+ def +(other)
81
+ case other
82
+ when self.class
83
+ if other.absolute?
84
+ other
85
+ else
86
+ self.class.new(name: "#{name}::#{other.name}", absolute: absolute?)
87
+ end
88
+ else
89
+ self + self.class.parse(other)
90
+ end
91
+ end
92
+
93
+ def components
94
+ name.split(/::/).map.with_index {|s, index|
95
+ if index == 0 && absolute?
96
+ self.class.parse(s).absolute!
97
+ else
98
+ self.class.parse(s)
99
+ end
100
+ }
101
+ end
102
+
103
+ def parent
104
+ components = components()
105
+ components.pop
106
+
107
+ unless components.empty?
108
+ self.class.parse(components.join("::"))
109
+ end
110
+ end
111
+
112
+ def simple?
113
+ components.size == 1
114
+ end
115
+ end
116
+ end