steep 0.21.0 → 0.27.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +38 -1
- data/Gemfile +7 -0
- data/bin/steep-prof +16 -0
- data/lib/steep/ast/types.rb +5 -3
- data/lib/steep/ast/types/any.rb +1 -3
- data/lib/steep/ast/types/boolean.rb +1 -3
- data/lib/steep/ast/types/bot.rb +1 -3
- data/lib/steep/ast/types/class.rb +2 -2
- data/lib/steep/ast/types/factory.rb +58 -16
- data/lib/steep/ast/types/helper.rb +6 -0
- data/lib/steep/ast/types/instance.rb +2 -2
- data/lib/steep/ast/types/intersection.rb +8 -4
- data/lib/steep/ast/types/literal.rb +5 -3
- data/lib/steep/ast/types/name.rb +13 -9
- data/lib/steep/ast/types/nil.rb +1 -3
- data/lib/steep/ast/types/proc.rb +5 -2
- data/lib/steep/ast/types/record.rb +9 -4
- data/lib/steep/ast/types/self.rb +1 -1
- data/lib/steep/ast/types/top.rb +1 -3
- data/lib/steep/ast/types/tuple.rb +5 -3
- data/lib/steep/ast/types/union.rb +11 -3
- data/lib/steep/ast/types/var.rb +2 -2
- data/lib/steep/ast/types/void.rb +1 -3
- data/lib/steep/drivers/check.rb +4 -0
- data/lib/steep/interface/method_type.rb +48 -18
- data/lib/steep/interface/substitution.rb +32 -2
- data/lib/steep/project/target.rb +17 -3
- data/lib/steep/server/base_worker.rb +4 -3
- data/lib/steep/server/master.rb +3 -1
- data/lib/steep/server/signature_worker.rb +3 -0
- data/lib/steep/signature/errors.rb +28 -0
- data/lib/steep/signature/validator.rb +11 -1
- data/lib/steep/source.rb +2 -1
- data/lib/steep/subtyping/check.rb +38 -21
- data/lib/steep/type_construction.rb +446 -181
- data/lib/steep/type_inference/constant_env.rb +1 -1
- data/lib/steep/type_inference/context.rb +8 -0
- data/lib/steep/type_inference/context_array.rb +4 -3
- data/lib/steep/type_inference/logic.rb +31 -0
- data/lib/steep/typing.rb +7 -0
- data/lib/steep/version.rb +1 -1
- data/smoke/hash/d.rb +1 -1
- data/steep.gemspec +1 -8
- metadata +5 -88
data/lib/steep/ast/types/self.rb
CHANGED
data/lib/steep/ast/types/top.rb
CHANGED
@@ -30,9 +30,11 @@ module Steep
|
|
30
30
|
"[#{types.join(", ")}]"
|
31
31
|
end
|
32
32
|
|
33
|
-
def free_variables
|
34
|
-
|
35
|
-
|
33
|
+
def free_variables()
|
34
|
+
@fvs ||= Set.new.tap do |set|
|
35
|
+
types.each do |type|
|
36
|
+
set.merge(type.free_variables)
|
37
|
+
end
|
36
38
|
end
|
37
39
|
end
|
38
40
|
|
@@ -11,6 +11,9 @@ module Steep
|
|
11
11
|
end
|
12
12
|
|
13
13
|
def self.build(types:, location: nil)
|
14
|
+
return AST::Types::Bot.new if types.empty?
|
15
|
+
return types.first if types.size == 1
|
16
|
+
|
14
17
|
types.flat_map do |type|
|
15
18
|
if type.is_a?(Union)
|
16
19
|
type.types
|
@@ -29,7 +32,10 @@ module Steep
|
|
29
32
|
type
|
30
33
|
end
|
31
34
|
end.compact.uniq.yield_self do |tys|
|
32
|
-
|
35
|
+
case tys.size
|
36
|
+
when 0
|
37
|
+
AST::Types::Bot.new
|
38
|
+
when 1
|
33
39
|
tys.first
|
34
40
|
else
|
35
41
|
new(types: tys.sort_by(&:hash), location: location)
|
@@ -58,8 +64,10 @@ module Steep
|
|
58
64
|
end
|
59
65
|
|
60
66
|
def free_variables
|
61
|
-
|
62
|
-
|
67
|
+
@fvs ||= Set.new.tap do |set|
|
68
|
+
types.each do |type|
|
69
|
+
set.merge(type.free_variables)
|
70
|
+
end
|
63
71
|
end
|
64
72
|
end
|
65
73
|
|
data/lib/steep/ast/types/var.rb
CHANGED
data/lib/steep/ast/types/void.rb
CHANGED
data/lib/steep/drivers/check.rb
CHANGED
@@ -211,10 +211,10 @@ module Steep
|
|
211
211
|
end
|
212
212
|
end
|
213
213
|
|
214
|
-
def free_variables
|
215
|
-
Set.new.tap do |
|
214
|
+
def free_variables()
|
215
|
+
@fvs ||= Set.new.tap do |set|
|
216
216
|
each_type do |type|
|
217
|
-
|
217
|
+
set.merge(type.free_variables)
|
218
218
|
end
|
219
219
|
end
|
220
220
|
end
|
@@ -224,14 +224,29 @@ module Steep
|
|
224
224
|
end
|
225
225
|
|
226
226
|
def subst(s)
|
227
|
-
self.
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
)
|
227
|
+
return self if s.empty?
|
228
|
+
return self if empty?
|
229
|
+
return self if free_variables.disjoint?(s.domain)
|
230
|
+
|
231
|
+
rs = required.map {|t| t.subst(s) }
|
232
|
+
os = optional.map {|t| t.subst(s) }
|
233
|
+
r = rest&.subst(s)
|
234
|
+
rk = required_keywords.transform_values {|t| t.subst(s) }
|
235
|
+
ok = optional_keywords.transform_values {|t| t.subst(s) }
|
236
|
+
k = rest_keywords&.subst(s)
|
237
|
+
|
238
|
+
if rs == required && os == optional && r == rest && rk == required_keywords && ok == optional_keywords && k == rest_keywords
|
239
|
+
self
|
240
|
+
else
|
241
|
+
self.class.new(
|
242
|
+
required: required.map {|t| t.subst(s) },
|
243
|
+
optional: optional.map {|t| t.subst(s) },
|
244
|
+
rest: rest&.subst(s),
|
245
|
+
required_keywords: required_keywords.transform_values {|t| t.subst(s) },
|
246
|
+
optional_keywords: optional_keywords.transform_values {|t| t.subst(s) },
|
247
|
+
rest_keywords: rest_keywords&.subst(s)
|
248
|
+
)
|
249
|
+
end
|
235
250
|
end
|
236
251
|
|
237
252
|
def size
|
@@ -557,14 +572,19 @@ module Steep
|
|
557
572
|
end
|
558
573
|
|
559
574
|
def subst(s)
|
560
|
-
|
561
|
-
|
562
|
-
|
563
|
-
|
575
|
+
ty = type.subst(s)
|
576
|
+
if ty == type
|
577
|
+
self
|
578
|
+
else
|
579
|
+
self.class.new(
|
580
|
+
type: ty,
|
581
|
+
optional: optional
|
582
|
+
)
|
583
|
+
end
|
564
584
|
end
|
565
585
|
|
566
|
-
def free_variables
|
567
|
-
type.free_variables
|
586
|
+
def free_variables()
|
587
|
+
@fvs ||= type.free_variables
|
568
588
|
end
|
569
589
|
|
570
590
|
def to_s
|
@@ -617,10 +637,20 @@ module Steep
|
|
617
637
|
end
|
618
638
|
|
619
639
|
def free_variables
|
620
|
-
|
640
|
+
@fvs ||= Set.new.tap do |set|
|
641
|
+
set.merge(params.free_variables)
|
642
|
+
if block
|
643
|
+
set.merge(block.free_variables)
|
644
|
+
end
|
645
|
+
set.merge(return_type.free_variables)
|
646
|
+
set.subtract(type_params)
|
647
|
+
end
|
621
648
|
end
|
622
649
|
|
623
650
|
def subst(s)
|
651
|
+
return self if s.empty?
|
652
|
+
return self if free_variables.disjoint?(s.domain)
|
653
|
+
|
624
654
|
s_ = s.except(type_params)
|
625
655
|
|
626
656
|
self.class.new(
|
@@ -26,7 +26,32 @@ module Steep
|
|
26
26
|
end
|
27
27
|
|
28
28
|
def self.empty
|
29
|
-
new(dictionary: {},
|
29
|
+
new(dictionary: {},
|
30
|
+
instance_type: INSTANCE_TYPE,
|
31
|
+
module_type: CLASS_TYPE,
|
32
|
+
self_type: SELF_TYPE)
|
33
|
+
end
|
34
|
+
|
35
|
+
def empty?
|
36
|
+
dictionary.empty? &&
|
37
|
+
instance_type.is_a?(AST::Types::Instance) &&
|
38
|
+
module_type.is_a?(AST::Types::Class) &&
|
39
|
+
self_type.is_a?(AST::Types::Self)
|
40
|
+
end
|
41
|
+
|
42
|
+
INSTANCE_TYPE = AST::Types::Instance.new
|
43
|
+
CLASS_TYPE = AST::Types::Class.new
|
44
|
+
SELF_TYPE = AST::Types::Self.new
|
45
|
+
|
46
|
+
def domain
|
47
|
+
set = Set.new
|
48
|
+
|
49
|
+
set.merge(dictionary.keys)
|
50
|
+
set << INSTANCE_TYPE unless instance_type.is_a?(AST::Types::Instance)
|
51
|
+
set << CLASS_TYPE unless instance_type.is_a?(AST::Types::Class)
|
52
|
+
set << SELF_TYPE unless instance_type.is_a?(AST::Types::Self)
|
53
|
+
|
54
|
+
set
|
30
55
|
end
|
31
56
|
|
32
57
|
def to_s
|
@@ -81,6 +106,11 @@ module Steep
|
|
81
106
|
raise "Duplicated key on merge!: #{key}, #{a}, #{b}"
|
82
107
|
end
|
83
108
|
end
|
109
|
+
|
110
|
+
@instance_type = instance_type.subst(s)
|
111
|
+
@module_type = module_type.subst(s)
|
112
|
+
@self_type = self_type.subst(s)
|
113
|
+
|
84
114
|
self
|
85
115
|
end
|
86
116
|
|
@@ -92,7 +122,7 @@ module Steep
|
|
92
122
|
end
|
93
123
|
|
94
124
|
def add!(v, ty)
|
95
|
-
merge!(Substitution.new(dictionary: { v => ty }, instance_type:
|
125
|
+
merge!(Substitution.new(dictionary: { v => ty }, instance_type: instance_type, module_type: module_type, self_type: self_type))
|
96
126
|
end
|
97
127
|
end
|
98
128
|
end
|
data/lib/steep/project/target.rb
CHANGED
@@ -79,6 +79,7 @@ module Steep
|
|
79
79
|
def self.test_pattern(patterns, path, ext:)
|
80
80
|
patterns.any? do |pattern|
|
81
81
|
p = pattern.end_with?(File::Separator) ? pattern : pattern + File::Separator
|
82
|
+
p.delete_prefix!('./')
|
82
83
|
(path.to_s.start_with?(p) && path.extname == ext) || File.fnmatch(pattern, path.to_s)
|
83
84
|
end
|
84
85
|
end
|
@@ -160,7 +161,18 @@ module Steep
|
|
160
161
|
else
|
161
162
|
yield env, check, Time.now
|
162
163
|
end
|
164
|
+
rescue RBS::DuplicatedDeclarationError => exn
|
165
|
+
@status = SignatureValidationErrorStatus.new(
|
166
|
+
errors: [
|
167
|
+
Signature::Errors::DuplicatedDefinitionError.new(
|
168
|
+
name: exn.name,
|
169
|
+
location: exn.decls[0].location
|
170
|
+
)
|
171
|
+
],
|
172
|
+
timestamp: Time.now
|
173
|
+
)
|
163
174
|
rescue => exn
|
175
|
+
Steep.log_error exn
|
164
176
|
@status = SignatureOtherErrorStatus.new(error: exn, timestamp: Time.now)
|
165
177
|
end
|
166
178
|
end
|
@@ -183,8 +195,10 @@ module Steep
|
|
183
195
|
type_check_sources = []
|
184
196
|
|
185
197
|
target_sources.each do |file|
|
186
|
-
|
187
|
-
|
198
|
+
Steep.logger.tagged("path=#{file.path}") do
|
199
|
+
if file.type_check(check, timestamp)
|
200
|
+
type_check_sources << file
|
201
|
+
end
|
188
202
|
end
|
189
203
|
end
|
190
204
|
|
@@ -205,7 +219,7 @@ module Steep
|
|
205
219
|
def errors
|
206
220
|
case status
|
207
221
|
when TypeCheckStatus
|
208
|
-
source_files.each_value.flat_map(&:errors)
|
222
|
+
source_files.each_value.flat_map(&:errors).select { |error | options.error_to_report?(error) }
|
209
223
|
else
|
210
224
|
[]
|
211
225
|
end
|
@@ -12,6 +12,7 @@ module Steep
|
|
12
12
|
@project = project
|
13
13
|
@reader = reader
|
14
14
|
@writer = writer
|
15
|
+
@shutdown = false
|
15
16
|
end
|
16
17
|
|
17
18
|
def handle_request(request)
|
@@ -28,7 +29,7 @@ module Steep
|
|
28
29
|
Steep.logger.formatter.push_tags(*tags)
|
29
30
|
Steep.logger.tagged "background" do
|
30
31
|
while job = queue.pop
|
31
|
-
handle_job(job)
|
32
|
+
handle_job(job) unless @shutdown
|
32
33
|
end
|
33
34
|
end
|
34
35
|
end
|
@@ -38,11 +39,11 @@ module Steep
|
|
38
39
|
reader.read do |request|
|
39
40
|
case request[:method]
|
40
41
|
when "shutdown"
|
41
|
-
|
42
|
+
@shutdown = true
|
42
43
|
when "exit"
|
43
44
|
break
|
44
45
|
else
|
45
|
-
handle_request(request)
|
46
|
+
handle_request(request) unless @shutdown
|
46
47
|
end
|
47
48
|
end
|
48
49
|
ensure
|
data/lib/steep/server/master.rb
CHANGED
@@ -23,6 +23,7 @@ module Steep
|
|
23
23
|
@signature_worker = signature_worker
|
24
24
|
@code_workers = code_workers
|
25
25
|
@worker_to_paths = {}
|
26
|
+
@shutdown = false
|
26
27
|
end
|
27
28
|
|
28
29
|
def start
|
@@ -59,7 +60,7 @@ module Steep
|
|
59
60
|
end
|
60
61
|
|
61
62
|
while job = queue.pop
|
62
|
-
writer.write(job)
|
63
|
+
writer.write(job) unless @shutdown
|
63
64
|
end
|
64
65
|
|
65
66
|
writer.io.close
|
@@ -154,6 +155,7 @@ module Steep
|
|
154
155
|
|
155
156
|
when "shutdown"
|
156
157
|
queue << { id: id, result: nil }
|
158
|
+
@shutdown = true
|
157
159
|
|
158
160
|
when "exit"
|
159
161
|
queue << nil
|
@@ -112,6 +112,9 @@ module Steep
|
|
112
112
|
target.signature_files.each_key.with_object({}) do |path, hash|
|
113
113
|
hash[path] = []
|
114
114
|
end
|
115
|
+
when Project::Target::SignatureOtherErrorStatus
|
116
|
+
Steep.log_error status.error
|
117
|
+
{}
|
115
118
|
else
|
116
119
|
Steep.logger.info "Unexpected target status: #{status.class}"
|
117
120
|
{}
|
@@ -19,6 +19,19 @@ module Steep
|
|
19
19
|
end
|
20
20
|
end
|
21
21
|
|
22
|
+
class DuplicatedDefinitionError < Base
|
23
|
+
attr_reader :name
|
24
|
+
|
25
|
+
def initialize(name:, location:)
|
26
|
+
@name = name
|
27
|
+
@location = location
|
28
|
+
end
|
29
|
+
|
30
|
+
def puts(io)
|
31
|
+
io.puts "#{loc_to_s}\sDuplicatedDefinitionError: name=#{name}"
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
22
35
|
class UnknownTypeNameError < Base
|
23
36
|
attr_reader :name
|
24
37
|
|
@@ -48,6 +61,21 @@ module Steep
|
|
48
61
|
io.puts "#{loc_to_s}\tInvalidTypeApplicationError: name=#{name}, expected=[#{params.join(", ")}], actual=[#{args.join(", ")}]"
|
49
62
|
end
|
50
63
|
end
|
64
|
+
|
65
|
+
class InvalidMethodOverloadError < Base
|
66
|
+
attr_reader :class_name
|
67
|
+
attr_reader :method_name
|
68
|
+
|
69
|
+
def initialize(class_name:, method_name:, location:)
|
70
|
+
@class_name = class_name
|
71
|
+
@method_name = method_name
|
72
|
+
@location = location
|
73
|
+
end
|
74
|
+
|
75
|
+
def puts(io)
|
76
|
+
io.puts "#{loc_to_s}\tInvalidMethodOverloadError: class_name=#{class_name}, method_name=#{method_name}"
|
77
|
+
end
|
78
|
+
end
|
51
79
|
end
|
52
80
|
end
|
53
81
|
end
|
@@ -53,6 +53,7 @@ module Steep
|
|
53
53
|
validate_decl
|
54
54
|
validate_const
|
55
55
|
validate_global
|
56
|
+
validate_alias
|
56
57
|
end
|
57
58
|
|
58
59
|
def validate_type(type)
|
@@ -99,6 +100,7 @@ module Steep
|
|
99
100
|
env.constant_decls.each do |name, entry|
|
100
101
|
rescue_validation_errors do
|
101
102
|
Steep.logger.debug "Validating constant `#{name}`..."
|
103
|
+
builder.ensure_namespace!(name.namespace, location: entry.decl.location)
|
102
104
|
validate_type entry.decl.type
|
103
105
|
end
|
104
106
|
end
|
@@ -117,7 +119,9 @@ module Steep
|
|
117
119
|
env.alias_decls.each do |name, entry|
|
118
120
|
rescue_validation_errors do
|
119
121
|
Steep.logger.debug "Validating alias `#{name}`..."
|
120
|
-
|
122
|
+
builder.expand_alias(name).tap do |type|
|
123
|
+
validate_type(type)
|
124
|
+
end
|
121
125
|
end
|
122
126
|
end
|
123
127
|
end
|
@@ -136,6 +140,12 @@ module Steep
|
|
136
140
|
name: factory.type_name(exn.type_name),
|
137
141
|
location: exn.location
|
138
142
|
)
|
143
|
+
rescue RBS::InvalidOverloadMethodError => exn
|
144
|
+
@errors << Errors::InvalidMethodOverloadError.new(
|
145
|
+
class_name: factory.type_name(exn.type_name),
|
146
|
+
method_name: exn.method_name,
|
147
|
+
location: exn.members[0].location
|
148
|
+
)
|
139
149
|
end
|
140
150
|
end
|
141
151
|
end
|