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
@@ -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