steep 1.1.0 → 1.1.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +7 -0
- data/Gemfile.lock +1 -1
- data/Gemfile.steep +1 -1
- data/Gemfile.steep.lock +2 -2
- data/lib/steep/type_construction.rb +102 -31
- data/lib/steep/type_inference/logic_type_interpreter.rb +27 -12
- data/lib/steep/type_inference/multiple_assignment.rb +6 -1
- data/lib/steep/type_inference/type_env.rb +13 -1
- data/lib/steep/version.rb +1 -1
- data/sig/steep/node_helper.rbs +2 -0
- data/sig/steep/type_construction.rbs +15 -0
- data/sig/steep/type_inference/type_env.rbs +2 -0
- data/sig/version.rbs +3 -0
- metadata +4 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a82e5deea68aec9ddc24d1ff5c4872ea0c2fd1d00a6098056e144bc932fba5bf
|
4
|
+
data.tar.gz: 2e55a0e505ab5ff267c911b53828f7de2159ae1ac443401a962c1d77c8cda294
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3d572d7d6f4908286a5714cfe029930a749a0437d5f88663b3c85f86bf14a60f2de0f53320177b6749d235ed384576cfbfc21f6954873fa4fcc29d4132a24880
|
7
|
+
data.tar.gz: 7319b4110d5f5ad465f0a84a4052c7c542ed5c0f2da5bd8e378247a75883ecc62fecfb16d3da215f9e017ade5045cffa56cff3d5eaaaeeb59c602035113af370
|
data/CHANGELOG.md
CHANGED
@@ -2,6 +2,13 @@
|
|
2
2
|
|
3
3
|
## master
|
4
4
|
|
5
|
+
## 1.1.1 (2022-07-31)
|
6
|
+
|
7
|
+
### Type checker core
|
8
|
+
|
9
|
+
* Ignore special local variables -- `_`, `__any__` and `__skip__` ([#617](https://github.com/soutaro/steep/pull/617), [#627](https://github.com/soutaro/steep/pull/627))
|
10
|
+
* Fix type narrowing on assignments ([#622](https://github.com/soutaro/steep/pull/622))
|
11
|
+
|
5
12
|
## 1.1.0 (2022-07-27)
|
6
13
|
|
7
14
|
### Type checker core
|
data/Gemfile.lock
CHANGED
data/Gemfile.steep
CHANGED
data/Gemfile.steep.lock
CHANGED
@@ -24,7 +24,7 @@ GEM
|
|
24
24
|
rb-inotify (0.10.1)
|
25
25
|
ffi (~> 1.0)
|
26
26
|
rbs (2.5.1)
|
27
|
-
steep (1.1.0
|
27
|
+
steep (1.1.0)
|
28
28
|
activesupport (>= 5.1)
|
29
29
|
language_server-protocol (>= 3.15, < 4.0)
|
30
30
|
listen (~> 3.0)
|
@@ -44,7 +44,7 @@ PLATFORMS
|
|
44
44
|
|
45
45
|
DEPENDENCIES
|
46
46
|
rbs (~> 2.5.0)
|
47
|
-
steep (~> 1.1.
|
47
|
+
steep (~> 1.1.0)
|
48
48
|
|
49
49
|
BUNDLED WITH
|
50
50
|
2.3.15
|
@@ -37,6 +37,8 @@ module Steep
|
|
37
37
|
s + ">"
|
38
38
|
end
|
39
39
|
|
40
|
+
SPECIAL_LVAR_NAMES = Set[:_, :__any__, :__skip__]
|
41
|
+
|
40
42
|
include ModuleHelper
|
41
43
|
|
42
44
|
attr_reader :checker
|
@@ -202,7 +204,9 @@ module Steep
|
|
202
204
|
|
203
205
|
local_variable_types = method_params.each_param.with_object({}) do |param, hash|
|
204
206
|
if param.name
|
205
|
-
|
207
|
+
unless SPECIAL_LVAR_NAMES.include?(param.name)
|
208
|
+
hash[param.name] = param.var_type
|
209
|
+
end
|
206
210
|
end
|
207
211
|
end
|
208
212
|
type_env = context.type_env.assign_local_variables(local_variable_types)
|
@@ -752,10 +756,15 @@ module Steep
|
|
752
756
|
when :lvar
|
753
757
|
yield_self do
|
754
758
|
var = node.children[0]
|
755
|
-
|
756
|
-
|
759
|
+
|
760
|
+
if SPECIAL_LVAR_NAMES.include?(var)
|
761
|
+
add_typing node, type: AST::Builtin.any_type
|
757
762
|
else
|
758
|
-
|
763
|
+
if (type = context.type_env[var])
|
764
|
+
add_typing node, type: type
|
765
|
+
else
|
766
|
+
fallback_to_any(node)
|
767
|
+
end
|
759
768
|
end
|
760
769
|
end
|
761
770
|
|
@@ -1240,13 +1249,17 @@ module Steep
|
|
1240
1249
|
|
1241
1250
|
node.children.each do |arg|
|
1242
1251
|
if arg.is_a?(Symbol)
|
1243
|
-
|
1244
|
-
|
1245
|
-
if type
|
1246
|
-
_, constr = add_typing(node, type: type)
|
1252
|
+
if SPECIAL_LVAR_NAMES === arg
|
1253
|
+
_, constr = add_typing(node, type: AST::Builtin.any_type)
|
1247
1254
|
else
|
1248
|
-
type =
|
1249
|
-
|
1255
|
+
type = context.type_env[arg]
|
1256
|
+
|
1257
|
+
if type
|
1258
|
+
_, constr = add_typing(node, type: type)
|
1259
|
+
else
|
1260
|
+
type = AST::Builtin.any_type
|
1261
|
+
_, constr = lvasgn(node, type)
|
1262
|
+
end
|
1250
1263
|
end
|
1251
1264
|
else
|
1252
1265
|
_, constr = constr.synthesize(arg)
|
@@ -1270,13 +1283,18 @@ module Steep
|
|
1270
1283
|
when :arg, :kwarg
|
1271
1284
|
yield_self do
|
1272
1285
|
var = node.children[0]
|
1273
|
-
type = context.type_env[var]
|
1274
1286
|
|
1275
|
-
if
|
1276
|
-
add_typing(node, type:
|
1287
|
+
if SPECIAL_LVAR_NAMES.include?(var)
|
1288
|
+
add_typing(node, type: AST::Builtin.any_type)
|
1277
1289
|
else
|
1278
|
-
type =
|
1279
|
-
|
1290
|
+
type = context.type_env[var]
|
1291
|
+
|
1292
|
+
if type
|
1293
|
+
add_typing(node, type: type)
|
1294
|
+
else
|
1295
|
+
type = AST::Builtin.any_type
|
1296
|
+
lvasgn(node, type)
|
1297
|
+
end
|
1280
1298
|
end
|
1281
1299
|
end
|
1282
1300
|
|
@@ -1826,8 +1844,21 @@ module Steep
|
|
1826
1844
|
if cond
|
1827
1845
|
branch_results = []
|
1828
1846
|
|
1829
|
-
cond_type, constr = constr.synthesize(cond)
|
1830
|
-
|
1847
|
+
cond_type, constr = constr.synthesize(cond)
|
1848
|
+
_, cond_vars = interpreter.decompose_value(cond)
|
1849
|
+
|
1850
|
+
var_name = :"_a#{SecureRandom.base64(4)}"
|
1851
|
+
var_cond, value_node = extract_outermost_call(cond, var_name)
|
1852
|
+
if value_node
|
1853
|
+
unless constr.context.type_env[value_node]
|
1854
|
+
constr = constr.update_type_env do |env|
|
1855
|
+
env.assign_local_variable(var_name, cond_type, nil)
|
1856
|
+
end
|
1857
|
+
cond = var_cond
|
1858
|
+
else
|
1859
|
+
value_node = nil
|
1860
|
+
end
|
1861
|
+
end
|
1831
1862
|
|
1832
1863
|
when_constr = constr
|
1833
1864
|
whens.each do |clause|
|
@@ -1875,7 +1906,11 @@ module Steep
|
|
1875
1906
|
types = branch_results.map(&:type)
|
1876
1907
|
constrs = branch_results.map(&:constr)
|
1877
1908
|
|
1878
|
-
cond_type = when_constr.context.type_env[
|
1909
|
+
cond_type = when_constr.context.type_env[var_name]
|
1910
|
+
cond_type ||= when_constr.context.type_env[cond_vars.first || raise] unless cond_vars.empty?
|
1911
|
+
cond_type ||= when_constr.context.type_env[value_node] if value_node
|
1912
|
+
cond_type ||= typing.type_of(node: node.children[0])
|
1913
|
+
|
1879
1914
|
if cond_type.is_a?(AST::Types::Bot)
|
1880
1915
|
# Exhaustive
|
1881
1916
|
if els
|
@@ -2440,23 +2475,27 @@ module Steep
|
|
2440
2475
|
def lvasgn(node, type)
|
2441
2476
|
name = node.children[0]
|
2442
2477
|
|
2443
|
-
if
|
2444
|
-
|
2445
|
-
|
2446
|
-
|
2447
|
-
|
2448
|
-
|
2449
|
-
|
2450
|
-
|
2478
|
+
if SPECIAL_LVAR_NAMES.include?(name)
|
2479
|
+
add_typing(node, type: AST::Builtin.any_type)
|
2480
|
+
else
|
2481
|
+
if enforced_type = context.type_env.enforced_type(name)
|
2482
|
+
if result = no_subtyping?(sub_type: type, super_type: enforced_type)
|
2483
|
+
typing.add_error(
|
2484
|
+
Diagnostic::Ruby::IncompatibleAssignment.new(
|
2485
|
+
node: node,
|
2486
|
+
lhs_type: enforced_type,
|
2487
|
+
rhs_type: type,
|
2488
|
+
result: result
|
2489
|
+
)
|
2451
2490
|
)
|
2452
|
-
)
|
2453
2491
|
|
2454
|
-
|
2492
|
+
type = enforced_type
|
2493
|
+
end
|
2455
2494
|
end
|
2456
|
-
end
|
2457
2495
|
|
2458
|
-
|
2459
|
-
|
2496
|
+
update_type_env {|env| env.assign_local_variable(name, type, enforced_type) }
|
2497
|
+
.add_typing(node, type: type)
|
2498
|
+
end
|
2460
2499
|
end
|
2461
2500
|
|
2462
2501
|
def ivasgn(node, rhs_type)
|
@@ -3689,6 +3728,8 @@ module Steep
|
|
3689
3728
|
end
|
3690
3729
|
end
|
3691
3730
|
|
3731
|
+
param_types_hash.delete_if {|name, _| SPECIAL_LVAR_NAMES.include?(name) }
|
3732
|
+
|
3692
3733
|
param_types = param_types_hash.each.with_object({}) do |pair, hash|
|
3693
3734
|
# @type var hash: Hash[Symbol, [AST::Types::t, AST::Types::t?]]
|
3694
3735
|
name, type = pair
|
@@ -4213,5 +4254,35 @@ module Steep
|
|
4213
4254
|
typing.save!
|
4214
4255
|
with_new_typing(typing.parent)
|
4215
4256
|
end
|
4257
|
+
|
4258
|
+
def extract_outermost_call(node, var_name)
|
4259
|
+
case node.type
|
4260
|
+
when :lvasgn
|
4261
|
+
name, rhs = node.children
|
4262
|
+
rhs, value_node = extract_outermost_call(rhs, var_name)
|
4263
|
+
if value_node
|
4264
|
+
[node.updated(nil, [name, rhs]), value_node]
|
4265
|
+
else
|
4266
|
+
[node, value_node]
|
4267
|
+
end
|
4268
|
+
when :begin
|
4269
|
+
*children, last = node.children
|
4270
|
+
last, value_node = extract_outermost_call(last, var_name)
|
4271
|
+
if value_node
|
4272
|
+
[node.updated(nil, children.push(last)), value_node]
|
4273
|
+
else
|
4274
|
+
[node, value_node]
|
4275
|
+
end
|
4276
|
+
when :lvar
|
4277
|
+
[node, nil]
|
4278
|
+
else
|
4279
|
+
if value_node?(node)
|
4280
|
+
[node, nil]
|
4281
|
+
else
|
4282
|
+
var_node = node.updated(:lvar, [var_name])
|
4283
|
+
[var_node, node]
|
4284
|
+
end
|
4285
|
+
end
|
4286
|
+
end
|
4216
4287
|
end
|
4217
4288
|
end
|
@@ -114,8 +114,12 @@ module Steep
|
|
114
114
|
case assignment_node.type
|
115
115
|
when :lvasgn
|
116
116
|
name, _ = assignment_node.children
|
117
|
-
|
118
|
-
|
117
|
+
if TypeConstruction::SPECIAL_LVAR_NAMES.include?(name)
|
118
|
+
env
|
119
|
+
else
|
120
|
+
refined_objects << name
|
121
|
+
env.refine_types(local_variable_types: { name => rhs_type })
|
122
|
+
end
|
119
123
|
when :masgn
|
120
124
|
lhs, _ = assignment_node.children
|
121
125
|
|
@@ -146,20 +150,31 @@ module Steep
|
|
146
150
|
when :lvar
|
147
151
|
name = node.children[0]
|
148
152
|
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
153
|
+
if TypeConstruction::SPECIAL_LVAR_NAMES.include?(name)
|
154
|
+
[env, env]
|
155
|
+
else
|
156
|
+
refined_objects << name
|
157
|
+
[
|
158
|
+
env.refine_types(local_variable_types: { name => truthy_type }),
|
159
|
+
env.refine_types(local_variable_types: { name => falsy_type })
|
160
|
+
]
|
161
|
+
end
|
162
|
+
|
154
163
|
when :lvasgn
|
155
164
|
name, rhs = node.children
|
156
165
|
|
157
166
|
truthy_env, falsy_env = refine_node_type(env: env, node: rhs, truthy_type: truthy_type, falsy_type: falsy_type, refined_objects: refined_objects)
|
158
|
-
|
159
|
-
|
160
|
-
truthy_env
|
161
|
-
|
162
|
-
|
167
|
+
|
168
|
+
if TypeConstruction::SPECIAL_LVAR_NAMES.include?(name)
|
169
|
+
[truthy_env, falsy_env]
|
170
|
+
else
|
171
|
+
refined_objects << name
|
172
|
+
[
|
173
|
+
truthy_env.refine_types(local_variable_types: { name => truthy_type }),
|
174
|
+
falsy_env.refine_types(local_variable_types: { name => falsy_type })
|
175
|
+
]
|
176
|
+
end
|
177
|
+
|
163
178
|
when :send
|
164
179
|
if env[node]
|
165
180
|
refined_objects << node
|
@@ -177,7 +177,12 @@ module Steep
|
|
177
177
|
AST::Types::Tuple.new(types: types)
|
178
178
|
when :lvasgn, :ivasgn, :gvasgn
|
179
179
|
name = mlhs.children[0]
|
180
|
-
|
180
|
+
|
181
|
+
unless TypeConstruction::SPECIAL_LVAR_NAMES.include?(name)
|
182
|
+
env[name] || AST::Builtin.any_type
|
183
|
+
else
|
184
|
+
AST::Builtin.any_type
|
185
|
+
end
|
181
186
|
when :splat
|
182
187
|
return
|
183
188
|
else
|
@@ -112,6 +112,8 @@ module Steep
|
|
112
112
|
invalidated_nodes = Set[]
|
113
113
|
|
114
114
|
assignments.each do |name, new_type|
|
115
|
+
local_variable_name!(name)
|
116
|
+
|
115
117
|
local_variable_types[name] = [new_type, enforced_type(name)]
|
116
118
|
invalidated_nodes.merge(invalidated_pure_nodes(::Parser::AST::Node.new(:lvar, [name])))
|
117
119
|
end
|
@@ -125,6 +127,7 @@ module Steep
|
|
125
127
|
end
|
126
128
|
|
127
129
|
def assign_local_variable(name, var_type, enforced_type)
|
130
|
+
local_variable_name!(name)
|
128
131
|
merge(
|
129
132
|
local_variable_types: { name => [enforced_type || var_type, enforced_type] },
|
130
133
|
pure_method_calls: pure_node_invalidation(invalidated_pure_nodes(::Parser::AST::Node.new(:lvar, [name])))
|
@@ -135,6 +138,7 @@ module Steep
|
|
135
138
|
local_variable_updates = {}
|
136
139
|
|
137
140
|
local_variable_types.each do |name, type|
|
141
|
+
local_variable_name!(name)
|
138
142
|
local_variable_updates[name] = [type, enforced_type(name)]
|
139
143
|
end
|
140
144
|
|
@@ -175,6 +179,8 @@ module Steep
|
|
175
179
|
local_variable_types.each.with_object({}) do |pair, hash|
|
176
180
|
name, entry = pair
|
177
181
|
|
182
|
+
local_variable_name!(name)
|
183
|
+
|
178
184
|
if names.nil? || names.include?(name)
|
179
185
|
type, enforced_type = entry
|
180
186
|
unless enforced_type
|
@@ -190,6 +196,8 @@ module Steep
|
|
190
196
|
local_var_types = local_variable_types.each.with_object({}) do |pair, hash|
|
191
197
|
name, entry = pair
|
192
198
|
|
199
|
+
local_variable_name!(name)
|
200
|
+
|
193
201
|
if names.nil? || names.include?(name)
|
194
202
|
type, _ = entry
|
195
203
|
hash[name] = [type, nil]
|
@@ -300,7 +308,11 @@ module Steep
|
|
300
308
|
end
|
301
309
|
|
302
310
|
def local_variable_name?(name)
|
303
|
-
name.start_with?(/[a-z_]/)
|
311
|
+
name.start_with?(/[a-z_]/) && name != :_ && name != :__skip__ && name != :__any__
|
312
|
+
end
|
313
|
+
|
314
|
+
def local_variable_name!(name)
|
315
|
+
local_variable_name?(name) || raise("#{name} is not a local variable")
|
304
316
|
end
|
305
317
|
|
306
318
|
def instance_variable_name?(name)
|
data/lib/steep/version.rb
CHANGED
data/sig/steep/node_helper.rbs
CHANGED
@@ -6,6 +6,8 @@ module Steep
|
|
6
6
|
def each_descendant_node: (Parser::AST::Node) -> Enumerator[Parser::AST::Node, void]
|
7
7
|
| (Parser::AST::Node) { (Parser::AST::Node) -> void } -> void
|
8
8
|
|
9
|
+
# Returns true if given node is a syntactic-value node
|
10
|
+
#
|
9
11
|
def value_node?: (Parser::AST::Node) -> bool
|
10
12
|
end
|
11
13
|
end
|
@@ -16,6 +16,8 @@ module Steep
|
|
16
16
|
def to_ary: () -> [AST::Types::t, TypeConstruction, TypeInference::Context]
|
17
17
|
end
|
18
18
|
|
19
|
+
SPECIAL_LVAR_NAMES: Set[Symbol]
|
20
|
+
|
19
21
|
include NodeHelper
|
20
22
|
|
21
23
|
attr_reader checker: Subtyping::Check
|
@@ -281,5 +283,18 @@ module Steep
|
|
281
283
|
# * All of the arguments are _pure_
|
282
284
|
#
|
283
285
|
def pure_send?: (TypeInference::MethodCall::Typed call, Parser::AST::Node receiver, Array[Parser::AST::Node] arguments) -> bool
|
286
|
+
|
287
|
+
# Transform given `node` to a node that has a local variable instead of the outer most call/non-value node
|
288
|
+
#
|
289
|
+
# Returns a pair of transformed node and the outer most call/non-value node if present.
|
290
|
+
#
|
291
|
+
# ```rb
|
292
|
+
# x = y = foo() # Call `#transform_value_node` with the node and var_name `:__foo__`
|
293
|
+
# # => Returns [x = y = __foo__, foo()]
|
294
|
+
# ```
|
295
|
+
#
|
296
|
+
# This is typically used for transforming assginment node for case condition.
|
297
|
+
#
|
298
|
+
def extract_outermost_call: (Parser::AST::Node node, Symbol) -> [Parser::AST::Node, Parser::AST::Node?]
|
284
299
|
end
|
285
300
|
end
|
data/sig/version.rbs
ADDED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: steep
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.1.
|
4
|
+
version: 1.1.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Soutaro Matsumoto
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-07-
|
11
|
+
date: 2022-07-31 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: parser
|
@@ -363,6 +363,7 @@ files:
|
|
363
363
|
- sig/steep/type_inference/type_env.rbs
|
364
364
|
- sig/steep/type_inference/type_env_builder.rbs
|
365
365
|
- sig/steep/typing.rbs
|
366
|
+
- sig/version.rbs
|
366
367
|
- smoke/alias/Steepfile
|
367
368
|
- smoke/alias/a.rb
|
368
369
|
- smoke/alias/a.rbs
|
@@ -633,7 +634,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
633
634
|
- !ruby/object:Gem::Version
|
634
635
|
version: '0'
|
635
636
|
requirements: []
|
636
|
-
rubygems_version: 3.3.
|
637
|
+
rubygems_version: 3.3.3
|
637
638
|
signing_key:
|
638
639
|
specification_version: 4
|
639
640
|
summary: Gradual Typing for Ruby
|