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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7c8da530ec2506030583be78aaaecc04f977ce86bef6c69a5025806c29f32a73
4
- data.tar.gz: 507b2fc612005b9893ae02ec840114b428654d039dd6e0c3cf3c719fc03916ab
3
+ metadata.gz: a82e5deea68aec9ddc24d1ff5c4872ea0c2fd1d00a6098056e144bc932fba5bf
4
+ data.tar.gz: 2e55a0e505ab5ff267c911b53828f7de2159ae1ac443401a962c1d77c8cda294
5
5
  SHA512:
6
- metadata.gz: 03444250fd89df0edcb58884081dee7c21f5a2b26d1c2b012371ee5b7046355b426dec781b7a9551d336190f306850721ac66d525128518a7c2324fb8b63f4f1
7
- data.tar.gz: c4f35528752c20c8d2b494e8bb60546ca65cf0317134343202679b865e7afd92d58bcfe49dc315f58ea2f29c93906ba65ebacb1a53741f94f2f47870961e23ff
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
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- steep (1.1.0)
4
+ steep (1.1.1)
5
5
  activesupport (>= 5.1)
6
6
  language_server-protocol (>= 3.15, < 4.0)
7
7
  listen (~> 3.0)
data/Gemfile.steep CHANGED
@@ -1,4 +1,4 @@
1
1
  source "https://rubygems.org"
2
2
 
3
- gem 'steep', '~> 1.1.pre'
3
+ gem 'steep', '~> 1.1.0'
4
4
  gem "rbs", "~> 2.5.0"
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.pre.1)
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.pre)
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
- hash[param.name] = param.var_type
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
- if (type = context.type_env[var])
756
- add_typing node, type: type
759
+
760
+ if SPECIAL_LVAR_NAMES.include?(var)
761
+ add_typing node, type: AST::Builtin.any_type
757
762
  else
758
- fallback_to_any(node)
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
- type = context.type_env[arg]
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 = AST::Builtin.any_type
1249
- _, constr = lvasgn(node, type)
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 type
1276
- add_typing(node, type: type)
1287
+ if SPECIAL_LVAR_NAMES.include?(var)
1288
+ add_typing(node, type: AST::Builtin.any_type)
1277
1289
  else
1278
- type = AST::Builtin.any_type
1279
- lvasgn(node, type)
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).to_ary
1830
- cond_value_node, cond_vars = interpreter.decompose_value(cond)
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[cond_value_node]
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 enforced_type = context.type_env.enforced_type(name)
2444
- if result = no_subtyping?(sub_type: type, super_type: enforced_type)
2445
- typing.add_error(
2446
- Diagnostic::Ruby::IncompatibleAssignment.new(
2447
- node: node,
2448
- lhs_type: enforced_type,
2449
- rhs_type: type,
2450
- result: result
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
- type = enforced_type
2492
+ type = enforced_type
2493
+ end
2455
2494
  end
2456
- end
2457
2495
 
2458
- update_type_env {|env| env.assign_local_variable(name, type, enforced_type) }
2459
- .add_typing(node, type: type)
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
- refined_objects << name
118
- env.refine_types(local_variable_types: { name => rhs_type })
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
- refined_objects << name
150
- [
151
- env.refine_types(local_variable_types: { name => truthy_type }),
152
- env.refine_types(local_variable_types: { name => falsy_type })
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
- refined_objects << name
159
- [
160
- truthy_env.refine_types(local_variable_types: { name => truthy_type }),
161
- falsy_env.refine_types(local_variable_types: { name => falsy_type })
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
- env[name] || AST::Builtin.any_type
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
@@ -1,3 +1,3 @@
1
1
  module Steep
2
- VERSION = "1.1.0"
2
+ VERSION = "1.1.1"
3
3
  end
@@ -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
@@ -150,6 +150,8 @@ module Steep
150
150
 
151
151
  def local_variable_name?: (Symbol) -> bool
152
152
 
153
+ def local_variable_name!: (Symbol) -> void
154
+
153
155
  def instance_variable_name?: (Symbol) -> bool
154
156
 
155
157
  def global_name?: (Symbol) -> bool
data/sig/version.rbs ADDED
@@ -0,0 +1,3 @@
1
+ module Steep
2
+ VERSION: String
3
+ end
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.0
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-27 00:00:00.000000000 Z
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.7
637
+ rubygems_version: 3.3.3
637
638
  signing_key:
638
639
  specification_version: 4
639
640
  summary: Gradual Typing for Ruby