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 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