steep 0.47.1 → 0.48.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +9 -0
- data/Gemfile.lock +6 -6
- data/lib/steep/ast/types/factory.rb +161 -137
- data/lib/steep/ast/types/var.rb +14 -3
- data/lib/steep/diagnostic/ruby.rb +23 -11
- data/lib/steep/diagnostic/signature.rb +56 -0
- data/lib/steep/interface/method_type.rb +14 -26
- data/lib/steep/interface/type_param.rb +103 -0
- data/lib/steep/server/base_worker.rb +1 -0
- data/lib/steep/server/interaction_worker.rb +1 -1
- data/lib/steep/server/type_check_worker.rb +2 -2
- data/lib/steep/services/signature_service.rb +2 -2
- data/lib/steep/services/type_check_service.rb +2 -1
- data/lib/steep/signature/validator.rb +221 -49
- data/lib/steep/subtyping/cache.rb +30 -0
- data/lib/steep/subtyping/check.rb +582 -708
- data/lib/steep/subtyping/constraints.rb +66 -30
- data/lib/steep/subtyping/relation.rb +60 -0
- data/lib/steep/subtyping/result.rb +190 -16
- data/lib/steep/type_construction.rb +492 -371
- data/lib/steep/type_inference/context.rb +37 -3
- data/lib/steep/version.rb +1 -1
- data/lib/steep.rb +3 -3
- data/sample/lib/length.rb +35 -0
- data/sample/sig/length.rbs +34 -0
- data/smoke/diagnostics-rbs/nonregular-type-alias.rbs +3 -0
- data/smoke/diagnostics-rbs/recursive-type-alias.rbs +3 -0
- data/smoke/diagnostics-rbs/test_expectations.yml +57 -12
- data/steep.gemspec +1 -1
- metadata +13 -10
- data/lib/steep/drivers/trace_printer.rb +0 -29
- data/lib/steep/interface/method.rb +0 -78
- data/lib/steep/subtyping/trace.rb +0 -71
@@ -80,7 +80,7 @@ module Steep
|
|
80
80
|
@vars = Set.new
|
81
81
|
|
82
82
|
unknowns.each do |var|
|
83
|
-
dictionary[var] = [Set.new, Set.new]
|
83
|
+
dictionary[var] = [Set.new, Set.new, Set.new]
|
84
84
|
end
|
85
85
|
end
|
86
86
|
|
@@ -101,8 +101,8 @@ module Steep
|
|
101
101
|
end
|
102
102
|
end
|
103
103
|
|
104
|
-
def add(var, sub_type: nil, super_type: nil)
|
105
|
-
subs, supers = dictionary[var]
|
104
|
+
def add(var, sub_type: nil, super_type: nil, skip: false)
|
105
|
+
subs, supers, skips = dictionary[var]
|
106
106
|
|
107
107
|
if sub_type.is_a?(AST::Types::Logic::Base)
|
108
108
|
sub_type = AST::Builtin.bool_type
|
@@ -113,11 +113,15 @@ module Steep
|
|
113
113
|
end
|
114
114
|
|
115
115
|
if super_type && !super_type.is_a?(AST::Types::Top)
|
116
|
-
|
116
|
+
type = eliminate_variable(super_type, to: AST::Types::Top.new)
|
117
|
+
supers << type
|
118
|
+
skips << type if skip
|
117
119
|
end
|
118
120
|
|
119
121
|
if sub_type && !sub_type.is_a?(AST::Types::Bot)
|
120
|
-
|
122
|
+
type = eliminate_variable(sub_type, to: AST::Types::Bot.new)
|
123
|
+
subs << type
|
124
|
+
skips << type if skip
|
121
125
|
end
|
122
126
|
|
123
127
|
super_fvs = supers.each.with_object(Set.new) do |type, fvs|
|
@@ -178,12 +182,20 @@ module Steep
|
|
178
182
|
Set.new(dictionary.keys)
|
179
183
|
end
|
180
184
|
|
185
|
+
def unknown!(var)
|
186
|
+
unless unknown?(var)
|
187
|
+
dictionary[var] = [Set.new, Set.new, Set.new]
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
181
191
|
def empty?
|
182
192
|
dictionary.keys.empty?
|
183
193
|
end
|
184
194
|
|
185
|
-
def upper_bound(var)
|
186
|
-
_, upper_bound = dictionary[var]
|
195
|
+
def upper_bound(var, skip: false)
|
196
|
+
_, upper_bound, skips = dictionary[var]
|
197
|
+
upper_bound -= skips if skip
|
198
|
+
|
187
199
|
case upper_bound.size
|
188
200
|
when 0
|
189
201
|
AST::Types::Top.new
|
@@ -194,8 +206,9 @@ module Steep
|
|
194
206
|
end
|
195
207
|
end
|
196
208
|
|
197
|
-
def lower_bound(var)
|
198
|
-
lower_bound, _ = dictionary[var]
|
209
|
+
def lower_bound(var, skip: false)
|
210
|
+
lower_bound, _, skips = dictionary[var]
|
211
|
+
lower_bound -= skips if skip
|
199
212
|
|
200
213
|
case lower_bound.size
|
201
214
|
when 0
|
@@ -207,40 +220,61 @@ module Steep
|
|
207
220
|
end
|
208
221
|
end
|
209
222
|
|
210
|
-
|
223
|
+
Context = Struct.new(:variance, :self_type, :instance_type, :class_type, keyword_init: true)
|
224
|
+
|
225
|
+
def solution(checker, variance: nil, variables:, self_type: nil, instance_type: nil, class_type: nil, context: nil)
|
226
|
+
if context
|
227
|
+
raise if variance
|
228
|
+
raise if self_type
|
229
|
+
raise if instance_type
|
230
|
+
raise if class_type
|
231
|
+
|
232
|
+
variance = context.variance
|
233
|
+
self_type = context.self_type
|
234
|
+
instance_type = context.instance_type
|
235
|
+
class_type = context.class_type
|
236
|
+
end
|
237
|
+
|
211
238
|
vars = []
|
212
239
|
types = []
|
213
240
|
|
214
241
|
dictionary.each_key do |var|
|
215
242
|
if variables.include?(var)
|
216
243
|
if has_constraint?(var)
|
217
|
-
|
218
|
-
|
219
|
-
|
244
|
+
relation = Relation.new(
|
245
|
+
sub_type: lower_bound(var, skip: false),
|
246
|
+
super_type: upper_bound(var, skip: false)
|
247
|
+
)
|
220
248
|
|
221
249
|
checker.check(relation, self_type: self_type, instance_type: instance_type, class_type: class_type, constraints: self.class.empty).yield_self do |result|
|
222
250
|
if result.success?
|
223
251
|
vars << var
|
224
252
|
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
253
|
+
upper_bound = upper_bound(var, skip: true)
|
254
|
+
lower_bound = lower_bound(var, skip: true)
|
255
|
+
|
256
|
+
type =
|
257
|
+
case
|
258
|
+
when variance.contravariant?(var)
|
259
|
+
upper_bound
|
260
|
+
when variance.covariant?(var)
|
261
|
+
lower_bound
|
262
|
+
else
|
263
|
+
if lower_bound.level.join > upper_bound.level.join
|
264
|
+
upper_bound
|
265
|
+
else
|
266
|
+
lower_bound
|
267
|
+
end
|
268
|
+
end
|
237
269
|
|
238
270
|
types << type
|
239
271
|
else
|
240
|
-
raise UnsatisfiableConstraint.new(
|
241
|
-
|
242
|
-
|
243
|
-
|
272
|
+
raise UnsatisfiableConstraint.new(
|
273
|
+
var: var,
|
274
|
+
sub_type: result.relation.sub_type,
|
275
|
+
super_type: result.relation.super_type,
|
276
|
+
result: result
|
277
|
+
)
|
244
278
|
end
|
245
279
|
end
|
246
280
|
else
|
@@ -254,7 +288,9 @@ module Steep
|
|
254
288
|
end
|
255
289
|
|
256
290
|
def has_constraint?(var)
|
257
|
-
lower, upper = dictionary[var]
|
291
|
+
lower, upper, skips = dictionary[var]
|
292
|
+
lower -= skips
|
293
|
+
upper -= skips
|
258
294
|
!lower.empty? || !upper.empty?
|
259
295
|
end
|
260
296
|
|
@@ -23,6 +23,66 @@ module Steep
|
|
23
23
|
"#{sub_type} <: #{super_type}"
|
24
24
|
end
|
25
25
|
|
26
|
+
def to_ary
|
27
|
+
[sub_type, super_type]
|
28
|
+
end
|
29
|
+
|
30
|
+
def type?
|
31
|
+
!interface? && !method? && !function? && !params? && !block?
|
32
|
+
end
|
33
|
+
|
34
|
+
def interface?
|
35
|
+
sub_type.is_a?(Interface::Interface) && super_type.is_a?(Interface::Interface)
|
36
|
+
end
|
37
|
+
|
38
|
+
def method?
|
39
|
+
(sub_type.is_a?(Interface::Interface::Entry) || sub_type.is_a?(Interface::MethodType)) &&
|
40
|
+
(super_type.is_a?(Interface::Interface::Entry) || super_type.is_a?(Interface::MethodType))
|
41
|
+
end
|
42
|
+
|
43
|
+
def function?
|
44
|
+
sub_type.is_a?(Interface::Function) && super_type.is_a?(Interface::Function)
|
45
|
+
end
|
46
|
+
|
47
|
+
def params?
|
48
|
+
sub_type.is_a?(Interface::Function::Params) && super_type.is_a?(Interface::Function::Params)
|
49
|
+
end
|
50
|
+
|
51
|
+
def block?
|
52
|
+
(sub_type.is_a?(Interface::Block) || !sub_type) &&
|
53
|
+
(!super_type || super_type.is_a?(Interface::Block))
|
54
|
+
end
|
55
|
+
|
56
|
+
def assert_type(type)
|
57
|
+
unless __send__(:"#{type}?")
|
58
|
+
raise "#{type}? is expected but: sub_type=#{sub_type.class}, super_type=#{super_type.class}"
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def type!
|
63
|
+
assert_type(:type)
|
64
|
+
end
|
65
|
+
|
66
|
+
def interface!
|
67
|
+
assert_type(:interface)
|
68
|
+
end
|
69
|
+
|
70
|
+
def method!
|
71
|
+
assert_type(:method)
|
72
|
+
end
|
73
|
+
|
74
|
+
def function!
|
75
|
+
assert_type(:function)
|
76
|
+
end
|
77
|
+
|
78
|
+
def params!
|
79
|
+
assert_type(:params)
|
80
|
+
end
|
81
|
+
|
82
|
+
def block!
|
83
|
+
assert_type(:block)
|
84
|
+
end
|
85
|
+
|
26
86
|
def map
|
27
87
|
self.class.new(
|
28
88
|
sub_type: yield(sub_type),
|
@@ -2,6 +2,12 @@ module Steep
|
|
2
2
|
module Subtyping
|
3
3
|
module Result
|
4
4
|
class Base
|
5
|
+
attr_reader :relation
|
6
|
+
|
7
|
+
def initialize(relation)
|
8
|
+
@relation = relation
|
9
|
+
end
|
10
|
+
|
5
11
|
def failure?
|
6
12
|
!success?
|
7
13
|
end
|
@@ -21,18 +27,139 @@ module Steep
|
|
21
27
|
self
|
22
28
|
end
|
23
29
|
end
|
30
|
+
|
31
|
+
def failure_path(path = [])
|
32
|
+
raise
|
33
|
+
end
|
24
34
|
end
|
25
35
|
|
26
|
-
class
|
27
|
-
|
36
|
+
class Skip < Base
|
37
|
+
def success?
|
38
|
+
false
|
39
|
+
end
|
40
|
+
|
41
|
+
def failure?
|
42
|
+
false
|
43
|
+
end
|
44
|
+
|
45
|
+
def failure_path(path = [])
|
46
|
+
raise
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
class Expand < Base
|
51
|
+
attr_reader :child
|
52
|
+
|
53
|
+
def initialize(relation, &block)
|
54
|
+
super relation
|
55
|
+
@child = yield relation
|
56
|
+
|
57
|
+
raise if @child == true
|
58
|
+
end
|
59
|
+
|
60
|
+
def success?
|
61
|
+
child.success?
|
62
|
+
end
|
28
63
|
|
29
|
-
def
|
30
|
-
|
64
|
+
def failure_path(path = [])
|
65
|
+
if child.failure?
|
66
|
+
path.unshift(self)
|
67
|
+
child.failure_path(path)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
class All < Base
|
73
|
+
attr_reader :branches
|
74
|
+
|
75
|
+
def initialize(relation)
|
76
|
+
super relation
|
77
|
+
@branches = []
|
78
|
+
@failure = false
|
79
|
+
end
|
80
|
+
|
81
|
+
# Returns `false` if no future `#add` changes the result.
|
82
|
+
def add(*relations, &block)
|
83
|
+
relations.each do |relation|
|
84
|
+
if success?
|
85
|
+
result = yield(relation)
|
86
|
+
branches << result
|
87
|
+
else
|
88
|
+
# Already failed.
|
89
|
+
branches << Skip.new(relation)
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
# No need to test more branches if already failed.
|
94
|
+
success?
|
31
95
|
end
|
32
96
|
|
97
|
+
def success?
|
98
|
+
!failure?
|
99
|
+
end
|
100
|
+
|
101
|
+
def failure?
|
102
|
+
@failure ||= branches.any?(&:failure?)
|
103
|
+
end
|
104
|
+
|
105
|
+
def failure_path(path = [])
|
106
|
+
if failure?
|
107
|
+
r = branches.find(&:failure?)
|
108
|
+
path.unshift(self)
|
109
|
+
r.failure_path(path)
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
class Any < Base
|
115
|
+
attr_reader :branches
|
116
|
+
|
117
|
+
def initialize(relation)
|
118
|
+
super relation
|
119
|
+
@branches = []
|
120
|
+
@success = false
|
121
|
+
end
|
122
|
+
|
123
|
+
# Returns `false` if no future `#add` changes the result.
|
124
|
+
def add(*relations, &block)
|
125
|
+
relations.each do |relation|
|
126
|
+
if failure?
|
127
|
+
result = yield(relation)
|
128
|
+
branches << result
|
129
|
+
else
|
130
|
+
# Already succeeded.
|
131
|
+
branches << Skip.new(relation)
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
# No need to test more branches if already succeeded.
|
136
|
+
failure?
|
137
|
+
end
|
138
|
+
|
139
|
+
def success?
|
140
|
+
@success ||= branches.any?(&:success?)
|
141
|
+
end
|
142
|
+
|
143
|
+
def failure_path(path = [])
|
144
|
+
if failure?
|
145
|
+
path.unshift(self)
|
146
|
+
if r = branches.find(&:failure?)
|
147
|
+
r.failure_path(path)
|
148
|
+
else
|
149
|
+
path
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
class Success < Base
|
33
156
|
def success?
|
34
157
|
true
|
35
158
|
end
|
159
|
+
|
160
|
+
def failure_path(path = [])
|
161
|
+
nil
|
162
|
+
end
|
36
163
|
end
|
37
164
|
|
38
165
|
class Failure < Base
|
@@ -96,29 +223,76 @@ module Steep
|
|
96
223
|
end
|
97
224
|
end
|
98
225
|
|
226
|
+
class UnsatisfiedConstraints
|
227
|
+
attr_reader :error
|
228
|
+
|
229
|
+
def initialize(error)
|
230
|
+
@error = error
|
231
|
+
end
|
232
|
+
|
233
|
+
def var
|
234
|
+
error.var
|
235
|
+
end
|
236
|
+
|
237
|
+
def sub_type
|
238
|
+
error.sub_type
|
239
|
+
end
|
240
|
+
|
241
|
+
def super_type
|
242
|
+
error.super_type
|
243
|
+
end
|
244
|
+
|
245
|
+
def result
|
246
|
+
error.result
|
247
|
+
end
|
248
|
+
|
249
|
+
def message
|
250
|
+
"A constraint on #{var} cannot be solved: #{sub_type} <: #{super_type}"
|
251
|
+
end
|
252
|
+
end
|
253
|
+
|
99
254
|
attr_reader :error
|
100
|
-
attr_reader :trace
|
101
255
|
|
102
|
-
def initialize(error
|
256
|
+
def initialize(relation, error)
|
257
|
+
super relation
|
103
258
|
@error = error
|
104
|
-
@trace = trace.dup
|
105
259
|
end
|
106
260
|
|
107
261
|
def success?
|
108
262
|
false
|
109
263
|
end
|
110
264
|
|
111
|
-
def
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
265
|
+
def failure_path(path = [])
|
266
|
+
path.unshift(self)
|
267
|
+
path
|
268
|
+
end
|
269
|
+
end
|
270
|
+
|
271
|
+
module Helper
|
272
|
+
def Skip(relation)
|
273
|
+
Skip.new(relation)
|
274
|
+
end
|
275
|
+
|
276
|
+
def Expand(relation, &block)
|
277
|
+
Expand.new(relation, &block)
|
278
|
+
end
|
279
|
+
|
280
|
+
def All(relation, &block)
|
281
|
+
All.new(relation).tap(&block)
|
118
282
|
end
|
119
283
|
|
120
|
-
def
|
121
|
-
|
284
|
+
def Any(relation, &block)
|
285
|
+
Any.new(relation).tap(&block)
|
286
|
+
end
|
287
|
+
|
288
|
+
def Success(relation)
|
289
|
+
Success.new(relation)
|
290
|
+
end
|
291
|
+
|
292
|
+
alias success Success
|
293
|
+
|
294
|
+
def Failure(relation, error = nil)
|
295
|
+
Failure.new(relation, error || yield)
|
122
296
|
end
|
123
297
|
end
|
124
298
|
end
|