steep 1.1.0 → 1.1.1
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 +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
|