steep 0.1.0.pre2 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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
@@ -0,0 +1,275 @@
1
+ module Steep
2
+ module Subtyping
3
+ class Constraints
4
+ class UnsatisfiedInvariantError < StandardError
5
+ attr_reader :constraints
6
+ attr_reader :reason
7
+
8
+ def initialize(reason:, constraints:)
9
+ @reason = reason
10
+ @constraints = constraints
11
+ super "Invalid constraint: reason=#{reason.message}, constraints=#{constraints.to_s}"
12
+ end
13
+
14
+ class VariablesUnknownsNotDisjoint
15
+ attr_reader :vars
16
+
17
+ def initialize(vars:)
18
+ @vars = vars
19
+ end
20
+
21
+ def message
22
+ "Variables and unknowns should be disjoint (#{vars})"
23
+ end
24
+ end
25
+
26
+ class VariablesFreeVariablesNotDisjoint
27
+ attr_reader :var
28
+ attr_reader :lower_bound
29
+ attr_reader :upper_bound
30
+
31
+ def initialize(var: nil, lower_bound: nil, upper_bound: nil)
32
+ @var = var
33
+ @lower_bound = lower_bound
34
+ @upper_bound = upper_bound
35
+ end
36
+
37
+ def message
38
+ "Variables and FV(constraints) should be disjoint (#{var}, #{lower_bound}, #{upper_bound})"
39
+ end
40
+ end
41
+
42
+ class UnknownsFreeVariableNotDisjoint
43
+ attr_reader :var
44
+ attr_reader :upper_bound
45
+ attr_reader :lower_bound
46
+
47
+ def initialize(var:, lower_bound:, upper_bound:)
48
+ @var = var
49
+ @lower_bound = lower_bound
50
+ @upper_bound = upper_bound
51
+ end
52
+
53
+ def message
54
+ "Unknowns and FV(constraints) should be disjoint (#{var}, #{lower_bound}, #{upper_bound})"
55
+ end
56
+ end
57
+ end
58
+
59
+ class UnsatisfiableConstraint < StandardError
60
+ attr_reader :var
61
+ attr_reader :sub_type
62
+ attr_reader :super_type
63
+ attr_reader :result
64
+
65
+ def initialize(var:, sub_type:, super_type:, result:)
66
+ @var = var
67
+ @sub_type = sub_type
68
+ @super_type = super_type
69
+ @result = result
70
+
71
+ super "Unsatisfiable constraint on #{var}: #{sub_type} <: #{super_type}"
72
+ end
73
+ end
74
+
75
+ attr_reader :dictionary
76
+ attr_reader :vars
77
+
78
+ def initialize(unknowns:)
79
+ @dictionary = {}
80
+ @vars = Set.new
81
+
82
+ unknowns.each do |var|
83
+ dictionary[var] = [Set.new, Set.new]
84
+ end
85
+ end
86
+
87
+ def self.empty
88
+ new(unknowns: [])
89
+ end
90
+
91
+ def add_var(*vars)
92
+ vars.each do |var|
93
+ self.vars << var
94
+ end
95
+
96
+ unless Set.new(vars).disjoint?(unknowns)
97
+ raise UnsatisfiedInvariantError.new(
98
+ reason: UnsatisfiedInvariantError::VariablesUnknownsNotDisjoint.new(vars: vars),
99
+ constraints: constraints
100
+ )
101
+ end
102
+ end
103
+
104
+ def add(var, sub_type: nil, super_type: nil)
105
+ subs, supers = dictionary[var]
106
+
107
+ if super_type && !super_type.is_a?(AST::Types::Top)
108
+ supers << eliminate_variable(super_type, to: AST::Types::Top.new)
109
+ end
110
+
111
+ if sub_type && !sub_type.is_a?(AST::Types::Bot)
112
+ subs << eliminate_variable(sub_type, to: AST::Types::Bot.new)
113
+ end
114
+
115
+ super_fvs = supers.each.with_object(Set.new) do |type, fvs|
116
+ fvs.merge(type.free_variables)
117
+ end
118
+ sub_fvs = subs.each.with_object(Set.new) do |type, fvs|
119
+ fvs.merge(type.free_variables)
120
+ end
121
+
122
+ unless super_fvs.disjoint?(unknowns) || sub_fvs.disjoint?(unknowns)
123
+ raise UnsatisfiedInvariantError.new(
124
+ reason: UnsatisfiedInvariantError::UnknownsFreeVariableNotDisjoint.new(
125
+ var: var,
126
+ lower_bound: sub_type,
127
+ upper_bound: super_type
128
+ ),
129
+ constraints: self
130
+ )
131
+ end
132
+ end
133
+
134
+ def eliminate_variable(type, to:)
135
+ case type
136
+ when AST::Types::Name
137
+ type.args.map do |ty|
138
+ eliminate_variable(ty, to: AST::Types::Any.new)
139
+ end.yield_self do |args|
140
+ AST::Types::Name.new(
141
+ name: type.name,
142
+ args: args
143
+ )
144
+ end
145
+ when AST::Types::Union
146
+ type.types.map do |ty|
147
+ eliminate_variable(ty, to: AST::Types::Any.new)
148
+ end.yield_self do |types|
149
+ AST::Types::Union.build(types: types)
150
+ end
151
+ when AST::Types::Intersection
152
+ type.types.map do |ty|
153
+ eliminate_variable(ty, to: AST::Types::Any.new)
154
+ end.yield_self do |types|
155
+ AST::Types::Intersection.build(types: types)
156
+ end
157
+ when AST::Types::Var
158
+ if vars.member?(type.name)
159
+ to
160
+ else
161
+ type
162
+ end
163
+ else
164
+ type
165
+ end
166
+ end
167
+
168
+ def unknown?(var)
169
+ dictionary.key?(var)
170
+ end
171
+
172
+ def unknowns
173
+ Set.new(dictionary.keys)
174
+ end
175
+
176
+ def empty?
177
+ dictionary.keys.empty?
178
+ end
179
+
180
+ def upper_bound(var)
181
+ _, upper_bound = dictionary[var]
182
+ case upper_bound.size
183
+ when 0
184
+ AST::Types::Top.new
185
+ when 1
186
+ upper_bound.first
187
+ else
188
+ AST::Types::Union.build(types: upper_bound.to_a)
189
+ end
190
+ end
191
+
192
+ def lower_bound(var)
193
+ lower_bound, _ = dictionary[var]
194
+
195
+ case lower_bound.size
196
+ when 0
197
+ AST::Types::Bot.new
198
+ when 1
199
+ lower_bound.first
200
+ else
201
+ AST::Types::Intersection.build(types: lower_bound.to_a)
202
+ end
203
+ end
204
+
205
+ def solution(checker, variance:, variables:)
206
+ vars = []
207
+ types = []
208
+
209
+ dictionary.each_key do |var|
210
+ if variables.include?(var)
211
+ if has_constraint?(var)
212
+ upper_bound = upper_bound(var)
213
+ lower_bound = lower_bound(var)
214
+ relation = Relation.new(sub_type: lower_bound, super_type: upper_bound)
215
+
216
+ checker.check(relation, constraints: self.class.empty).yield_self do |result|
217
+ if result.success?
218
+ vars << var
219
+
220
+ type = case
221
+ when variance.contravariant?(var)
222
+ upper_bound
223
+ when variance.covariant?(var)
224
+ lower_bound
225
+ else
226
+ if lower_bound.level.join > upper_bound.level.join
227
+ upper_bound
228
+ else
229
+ lower_bound
230
+ end
231
+ end
232
+
233
+ types << type
234
+ else
235
+ raise UnsatisfiableConstraint.new(var: var,
236
+ sub_type: lower_bound,
237
+ super_type: upper_bound,
238
+ result: result)
239
+ end
240
+ end
241
+ else
242
+ vars << var
243
+ types << AST::Types::Any.new
244
+ end
245
+ end
246
+ end
247
+
248
+ Interface::Substitution.build(vars, types)
249
+ end
250
+
251
+ def has_constraint?(var)
252
+ lower, upper = dictionary[var]
253
+ !lower.empty? || !upper.empty?
254
+ end
255
+
256
+ def each
257
+ if block_given?
258
+ dictionary.each_key do |var|
259
+ yield var, lower_bound(var), upper_bound(var)
260
+ end
261
+ else
262
+ enum_for :each
263
+ end
264
+ end
265
+
266
+ def to_s
267
+ strings = each.map do |var, lower_bound, upper_bound|
268
+ "#{lower_bound} <: #{var} <: #{upper_bound}"
269
+ end
270
+
271
+ "#{unknowns.to_a.join(",")}/#{vars.to_a.join(",")} |- { #{strings.join(", ")} }"
272
+ end
273
+ end
274
+ end
275
+ end
@@ -0,0 +1,41 @@
1
+ module Steep
2
+ module Subtyping
3
+ class Relation
4
+ attr_reader :sub_type
5
+ attr_reader :super_type
6
+
7
+ def initialize(sub_type:, super_type:)
8
+ @sub_type = sub_type
9
+ @super_type = super_type
10
+ end
11
+
12
+ def hash
13
+ self.class.hash ^ sub_type.hash ^ super_type.hash
14
+ end
15
+
16
+ def ==(other)
17
+ other.is_a?(self.class) && other.sub_type == sub_type && other.super_type == super_type
18
+ end
19
+
20
+ alias eql? ==
21
+
22
+ def to_s
23
+ "#{sub_type} <: #{super_type}"
24
+ end
25
+
26
+ def map
27
+ self.class.new(
28
+ sub_type: yield(sub_type),
29
+ super_type: yield(super_type)
30
+ )
31
+ end
32
+
33
+ def flip
34
+ self.class.new(
35
+ sub_type: super_type,
36
+ super_type: sub_type
37
+ )
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,126 @@
1
+ module Steep
2
+ module Subtyping
3
+ module Result
4
+ class Base
5
+ def failure?
6
+ !success?
7
+ end
8
+
9
+ def then
10
+ if success?
11
+ yield self
12
+ else
13
+ self
14
+ end
15
+ end
16
+
17
+ def else
18
+ if failure?
19
+ yield self
20
+ else
21
+ self
22
+ end
23
+ end
24
+ end
25
+
26
+ class Success < Base
27
+ attr_reader :constraints
28
+
29
+ def initialize(constraints:)
30
+ @constraints = constraints
31
+ end
32
+
33
+ def success?
34
+ true
35
+ end
36
+ end
37
+
38
+ class Failure < Base
39
+ class MethodMissingError
40
+ attr_reader :name
41
+
42
+ def initialize(name:)
43
+ @name = name
44
+ end
45
+
46
+ def message
47
+ "Method #{name} is missing"
48
+ end
49
+ end
50
+
51
+ class BlockMismatchError
52
+ attr_reader :name
53
+
54
+ def initialize(name:)
55
+ @name = name
56
+ end
57
+
58
+ def message
59
+ "Method #{name} is incompatible for block"
60
+ end
61
+ end
62
+
63
+ class ParameterMismatchError
64
+ attr_reader :name
65
+
66
+ def initialize(name:)
67
+ @name = name
68
+ end
69
+
70
+ def message
71
+ "Method #{name} or its block has incompatible parameters"
72
+ end
73
+ end
74
+
75
+ class UnknownPairError
76
+ attr_reader :relation
77
+
78
+ def initialize(relation:)
79
+ @relation = relation
80
+ end
81
+
82
+ def message
83
+ "#{relation} does not hold"
84
+ end
85
+ end
86
+
87
+ class PolyMethodSubtyping
88
+ attr_reader :name
89
+
90
+ def initialize(name:)
91
+ @name = name
92
+ end
93
+
94
+ def message
95
+ "Method #{name} requires uncheckable polymorphic subtyping"
96
+ end
97
+ end
98
+
99
+ attr_reader :error
100
+ attr_reader :trace
101
+
102
+ def initialize(error:, trace:)
103
+ @error = error
104
+ @trace = trace.dup
105
+ end
106
+
107
+ def success?
108
+ false
109
+ end
110
+
111
+ def merge_trace(trace)
112
+ if trace.empty?
113
+ self
114
+ else
115
+ self.class.new(error: error,
116
+ trace: trace + self.trace)
117
+ end
118
+ end
119
+
120
+ def drop(n)
121
+ self.class.new(error: error, trace: trace.drop(n))
122
+ end
123
+ end
124
+ end
125
+ end
126
+ end
@@ -0,0 +1,48 @@
1
+ module Steep
2
+ module Subtyping
3
+ class Trace
4
+ attr_reader :array
5
+
6
+ def initialize(array: [])
7
+ @array = array
8
+ end
9
+
10
+ def add(sup, sub)
11
+ array << [sup, sub]
12
+ yield
13
+ ensure
14
+ array.pop
15
+ end
16
+
17
+ def empty?
18
+ array.empty?
19
+ end
20
+
21
+ def drop(n)
22
+ self.class.new(array: array.drop(n))
23
+ end
24
+
25
+ def size
26
+ array.size
27
+ end
28
+
29
+ def +(other)
30
+ self.class.new(array: array + other.array)
31
+ end
32
+
33
+ def initialize_copy(source)
34
+ @array = source.array.dup
35
+ end
36
+
37
+ def each
38
+ if block_given?
39
+ array.each do |pair|
40
+ yield *pair
41
+ end
42
+ else
43
+ enum_for :each
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,49 @@
1
+ module Steep
2
+ module Subtyping
3
+ class VariableOccurence
4
+ attr_reader :params
5
+ attr_reader :returns
6
+
7
+ def initialize
8
+ @params = Set.new
9
+ @returns = Set.new
10
+ end
11
+
12
+ def add_method_type(method_type)
13
+ method_type.params.each_type do |type|
14
+ each_var(type) do |var|
15
+ params << var
16
+ end
17
+ end
18
+ each_var(method_type.return_type) do |var|
19
+ returns << var
20
+ end
21
+
22
+ method_type.block&.yield_self do |block|
23
+ block.params.each_type do |type|
24
+ each_var(type) do |var|
25
+ params << var
26
+ end
27
+ end
28
+ each_var(block.return_type) do |var|
29
+ returns << var
30
+ end
31
+ end
32
+ end
33
+
34
+ def each_var(type, &block)
35
+ type.free_variables.each(&block)
36
+ end
37
+
38
+ def strictly_return?(var)
39
+ !params.member?(var) && returns.member?(var)
40
+ end
41
+
42
+ def self.from_method_type(method_type)
43
+ self.new.tap do |occurence|
44
+ occurence.add_method_type(method_type)
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,69 @@
1
+ module Steep
2
+ module Subtyping
3
+ class VariableVariance
4
+ attr_reader :covariants
5
+ attr_reader :contravariants
6
+
7
+ def initialize(covariants:, contravariants:)
8
+ @covariants = covariants
9
+ @contravariants = contravariants
10
+ end
11
+
12
+ def covariant?(var)
13
+ covariants.member?(var) && !contravariants.member?(var)
14
+ end
15
+
16
+ def contravariant?(var)
17
+ contravariants.member?(var) && !covariants.member?(var)
18
+ end
19
+
20
+ def invariant?(var)
21
+ covariants.member?(var) && contravariants.member?(var)
22
+ end
23
+
24
+ def self.from_method_type(method_type)
25
+ covariants = Set.new
26
+ contravariants = Set.new
27
+
28
+ add_params(method_type.params, block: false, contravariants: contravariants, covariants: covariants)
29
+ add_type(method_type.return_type, variance: :covariant, covariants: covariants, contravariants: contravariants)
30
+
31
+ method_type.block&.yield_self do |block|
32
+ add_params(block.params, block: true, contravariants: contravariants, covariants: covariants)
33
+ add_type(block.return_type, variance: :contravariant, covariants: covariants, contravariants: contravariants)
34
+ end
35
+
36
+ new(covariants: covariants, contravariants: contravariants)
37
+ end
38
+
39
+ def self.add_params(params, block:, covariants:, contravariants:)
40
+ params.each_type do |type|
41
+ add_type(type, variance: block ? :contravariant : :covariant, covariants: covariants, contravariants: contravariants)
42
+ end
43
+ end
44
+
45
+ def self.add_type(type, variance:, covariants:, contravariants:)
46
+ case type
47
+ when AST::Types::Var
48
+ case variance
49
+ when :covariant
50
+ covariants << type.name
51
+ when :contravariant
52
+ contravariants << type.name
53
+ when :invariant
54
+ covariants << type.name
55
+ contravariants << type.name
56
+ end
57
+ when AST::Types::Union, AST::Types::Intersection
58
+ type.types.each do |ty|
59
+ add_type(ty, variance: variance, covariants: covariants, contravariants: contravariants)
60
+ end
61
+ when AST::Types::Name
62
+ type.args.each do |arg|
63
+ add_type(arg, variance: :invariant, covariants: covariants, contravariants: contravariants)
64
+ end
65
+ end
66
+ end
67
+ end
68
+ end
69
+ end