steep 0.21.0 → 0.27.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (45) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +38 -1
  3. data/Gemfile +7 -0
  4. data/bin/steep-prof +16 -0
  5. data/lib/steep/ast/types.rb +5 -3
  6. data/lib/steep/ast/types/any.rb +1 -3
  7. data/lib/steep/ast/types/boolean.rb +1 -3
  8. data/lib/steep/ast/types/bot.rb +1 -3
  9. data/lib/steep/ast/types/class.rb +2 -2
  10. data/lib/steep/ast/types/factory.rb +58 -16
  11. data/lib/steep/ast/types/helper.rb +6 -0
  12. data/lib/steep/ast/types/instance.rb +2 -2
  13. data/lib/steep/ast/types/intersection.rb +8 -4
  14. data/lib/steep/ast/types/literal.rb +5 -3
  15. data/lib/steep/ast/types/name.rb +13 -9
  16. data/lib/steep/ast/types/nil.rb +1 -3
  17. data/lib/steep/ast/types/proc.rb +5 -2
  18. data/lib/steep/ast/types/record.rb +9 -4
  19. data/lib/steep/ast/types/self.rb +1 -1
  20. data/lib/steep/ast/types/top.rb +1 -3
  21. data/lib/steep/ast/types/tuple.rb +5 -3
  22. data/lib/steep/ast/types/union.rb +11 -3
  23. data/lib/steep/ast/types/var.rb +2 -2
  24. data/lib/steep/ast/types/void.rb +1 -3
  25. data/lib/steep/drivers/check.rb +4 -0
  26. data/lib/steep/interface/method_type.rb +48 -18
  27. data/lib/steep/interface/substitution.rb +32 -2
  28. data/lib/steep/project/target.rb +17 -3
  29. data/lib/steep/server/base_worker.rb +4 -3
  30. data/lib/steep/server/master.rb +3 -1
  31. data/lib/steep/server/signature_worker.rb +3 -0
  32. data/lib/steep/signature/errors.rb +28 -0
  33. data/lib/steep/signature/validator.rb +11 -1
  34. data/lib/steep/source.rb +2 -1
  35. data/lib/steep/subtyping/check.rb +38 -21
  36. data/lib/steep/type_construction.rb +446 -181
  37. data/lib/steep/type_inference/constant_env.rb +1 -1
  38. data/lib/steep/type_inference/context.rb +8 -0
  39. data/lib/steep/type_inference/context_array.rb +4 -3
  40. data/lib/steep/type_inference/logic.rb +31 -0
  41. data/lib/steep/typing.rb +7 -0
  42. data/lib/steep/version.rb +1 -1
  43. data/smoke/hash/d.rb +1 -1
  44. data/steep.gemspec +1 -8
  45. metadata +5 -88
@@ -79,6 +79,7 @@ module Steep
79
79
  end
80
80
 
81
81
  mapping = {}
82
+
82
83
  construct_mapping(node: node, annotations: annotations, mapping: mapping)
83
84
 
84
85
  annotations.each do |annot|
@@ -185,7 +186,7 @@ module Steep
185
186
  construct_mapping(node: node.children[0], annotations: annotations, mapping: mapping, line_range: nil)
186
187
  end
187
188
 
188
- if node.loc.else
189
+ if node.children.last
189
190
  else_node = node.children.last
190
191
  else_start = node.loc.else.last_line
191
192
  else_end = node.loc.end.line
@@ -180,15 +180,6 @@ module Steep
180
180
  constraints: constraints
181
181
  )
182
182
 
183
- when relation.sub_type.is_a?(AST::Types::Literal)
184
- check(
185
- Relation.new(sub_type: relation.sub_type.back_type, super_type: relation.super_type),
186
- self_type: self_type,
187
- assumption: assumption,
188
- trace: trace,
189
- constraints: constraints
190
- )
191
-
192
183
  when relation.sub_type.is_a?(AST::Types::Union)
193
184
  results = relation.sub_type.types.map do |sub_type|
194
185
  check(Relation.new(sub_type: sub_type, super_type: relation.super_type),
@@ -311,10 +302,9 @@ module Steep
311
302
  when relation.sub_type.is_a?(AST::Types::Tuple) && relation.super_type.is_a?(AST::Types::Tuple)
312
303
  if relation.sub_type.types.size >= relation.super_type.types.size
313
304
  pairs = relation.sub_type.types.take(relation.super_type.types.size).zip(relation.super_type.types)
314
- results = pairs.flat_map do |t1, t2|
305
+ results = pairs.map do |t1, t2|
315
306
  relation = Relation.new(sub_type: t1, super_type: t2)
316
- [check(relation, self_type: self_type, assumption: assumption, trace: trace, constraints: constraints),
317
- check(relation.flip, self_type: self_type, assumption: assumption, trace: trace, constraints: constraints)]
307
+ check(relation, self_type: self_type, assumption: assumption, trace: trace, constraints: constraints)
318
308
  end
319
309
 
320
310
  if results.all?(&:success?)
@@ -327,16 +317,17 @@ module Steep
327
317
  trace: trace)
328
318
  end
329
319
 
330
- when relation.sub_type.is_a?(AST::Types::Tuple) && relation.super_type.is_a?(AST::Types::Name::Base)
331
- tuple_interface = factory.interface(relation.sub_type, private: false)
332
- type_interface = factory.interface(relation.super_type, private: false)
320
+ when relation.sub_type.is_a?(AST::Types::Tuple) && AST::Builtin::Array.instance_type?(relation.super_type)
321
+ tuple_element_type = AST::Types::Union.build(
322
+ types: relation.sub_type.types,
323
+ location: relation.sub_type.location
324
+ )
333
325
 
334
- check_interface(tuple_interface,
335
- type_interface,
336
- self_type: self_type,
337
- assumption: assumption,
338
- trace: trace,
339
- constraints: constraints)
326
+ check(Relation.new(sub_type: tuple_element_type, super_type: relation.super_type.args[0]),
327
+ self_type: self_type,
328
+ assumption: assumption,
329
+ trace: trace,
330
+ constraints: constraints)
340
331
 
341
332
  when relation.sub_type.is_a?(AST::Types::Record) && relation.super_type.is_a?(AST::Types::Record)
342
333
  if Set.new(relation.sub_type.elements.keys).superset?(Set.new(relation.super_type.elements.keys))
@@ -369,6 +360,32 @@ module Steep
369
360
  trace: trace,
370
361
  constraints: constraints)
371
362
 
363
+ when relation.super_type.is_a?(AST::Types::Literal)
364
+ case
365
+ when relation.super_type.value == true && AST::Builtin::TrueClass.instance_type?(relation.sub_type)
366
+ success(constraints: constraints)
367
+ when relation.super_type.value == false && AST::Builtin::FalseClass.instance_type?(relation.sub_type)
368
+ success(constraints: constraints)
369
+ else
370
+ failure(error: Result::Failure::UnknownPairError.new(relation: relation),
371
+ trace: trace)
372
+ end
373
+
374
+ when relation.super_type.is_a?(AST::Types::Nil) && AST::Builtin::NilClass.instance_type?(relation.sub_type)
375
+ success(constraints: constraints)
376
+
377
+ when relation.sub_type.is_a?(AST::Types::Nil) && AST::Builtin::NilClass.instance_type?(relation.super_type)
378
+ success(constraints: constraints)
379
+
380
+ when relation.sub_type.is_a?(AST::Types::Literal)
381
+ check(
382
+ Relation.new(sub_type: relation.sub_type.back_type, super_type: relation.super_type),
383
+ self_type: self_type,
384
+ assumption: assumption,
385
+ trace: trace,
386
+ constraints: constraints
387
+ )
388
+
372
389
  else
373
390
  failure(error: Result::Failure::UnknownPairError.new(relation: relation),
374
391
  trace: trace)
@@ -638,7 +638,8 @@ module Steep
638
638
  when :__skip__
639
639
  add_typing(node, type: AST::Builtin.any_type)
640
640
  else
641
- rhs_result = synthesize(rhs, hint: hint || context.lvar_env.declared_types[name]&.type)
641
+ hint ||= context.lvar_env.declared_types[name]&.type
642
+ rhs_result = synthesize(rhs, hint: hint)
642
643
 
643
644
  constr = rhs_result.constr.update_lvar_env do |lvar_env|
644
645
  lvar_env.assign(name, node: node, type: rhs_result.type) do |declared_type, actual_type, result|
@@ -743,6 +744,23 @@ module Steep
743
744
 
744
745
  constr.add_typing(node, type: type)
745
746
 
747
+ when :cvasgn
748
+ var_node = lhs.updated(:cvar)
749
+ send_node = rhs.updated(:send, [var_node, op, rhs])
750
+ new_node = node.updated(:cvasgn, [lhs.children[0], send_node])
751
+
752
+ type, constr = synthesize(new_node, hint: hint)
753
+
754
+ constr.add_typing(node, type: type)
755
+
756
+ when :send
757
+ new_rhs = rhs.updated(:send, [lhs, node.children[1], node.children[2]])
758
+ new_node = lhs.updated(:send, [lhs.children[0], :"#{lhs.children[1]}=", *lhs.children.drop(2), new_rhs])
759
+
760
+ type, constr = synthesize(new_node, hint: hint)
761
+
762
+ constr.add_typing(node, type: type)
763
+
746
764
  else
747
765
  Steep.logger.error("Unexpected op_asgn lhs: #{lhs.type}")
748
766
 
@@ -810,7 +828,7 @@ module Steep
810
828
  new.typing.add_context_for_body(node, context: new.context)
811
829
 
812
830
  each_child_node(args_node) do |arg|
813
- new.synthesize(arg)
831
+ _, new = new.synthesize(arg)
814
832
  end
815
833
 
816
834
  body_pair = if body_node
@@ -998,11 +1016,17 @@ module Steep
998
1016
  yield_self do
999
1017
  var = node.children[0]
1000
1018
  type = context.lvar_env[var.name]
1001
- unless type
1019
+
1020
+ if type
1021
+ add_typing(node, type: type)
1022
+ else
1002
1023
  type = AST::Builtin.any_type
1003
- Steep.logger.error { "Unknown arg type: #{node}" }
1024
+ if context&.method_context&.method_type
1025
+ Steep.logger.error { "Unknown arg type: #{node}" }
1026
+ end
1027
+
1028
+ lvasgn(node, type)
1004
1029
  end
1005
- add_typing(node, type: type)
1006
1030
  end
1007
1031
 
1008
1032
  when :optarg, :kwoptarg
@@ -1033,7 +1057,9 @@ module Steep
1033
1057
  var = node.children[0]
1034
1058
  type = context.lvar_env[var.name]
1035
1059
  unless type
1036
- Steep.logger.error { "Unknown variable: #{node}" }
1060
+ if context&.method_context&.method_type
1061
+ Steep.logger.error { "Unknown variable: #{node}" }
1062
+ end
1037
1063
  typing.add_error Errors::FallbackAny.new(node: node)
1038
1064
  type = AST::Builtin::Array.instance_type(AST::Builtin.any_type)
1039
1065
  end
@@ -1046,7 +1072,9 @@ module Steep
1046
1072
  var = node.children[0]
1047
1073
  type = context.lvar_env[var.name]
1048
1074
  unless type
1049
- Steep.logger.error { "Unknown variable: #{node}" }
1075
+ if context&.method_context&.method_type
1076
+ Steep.logger.error { "Unknown variable: #{node}" }
1077
+ end
1050
1078
  typing.add_error Errors::FallbackAny.new(node: node)
1051
1079
  type = AST::Builtin::Hash.instance_type(AST::Builtin::Symbol.instance_type, AST::Builtin.any_type)
1052
1080
  end
@@ -1062,7 +1090,7 @@ module Steep
1062
1090
 
1063
1091
  when :int
1064
1092
  yield_self do
1065
- literal_type = expand_alias(hint) {|hint_| test_literal_type(node.children[0], hint_) }
1093
+ literal_type = test_literal_type(node.children[0], hint)
1066
1094
 
1067
1095
  if literal_type
1068
1096
  add_typing(node, type: literal_type)
@@ -1073,7 +1101,7 @@ module Steep
1073
1101
 
1074
1102
  when :sym
1075
1103
  yield_self do
1076
- literal_type = expand_alias(hint) {|hint| test_literal_type(node.children[0], hint) }
1104
+ literal_type = test_literal_type(node.children[0], hint)
1077
1105
 
1078
1106
  if literal_type
1079
1107
  add_typing(node, type: literal_type)
@@ -1084,7 +1112,7 @@ module Steep
1084
1112
 
1085
1113
  when :str
1086
1114
  yield_self do
1087
- literal_type = expand_alias(hint) {|hint_| test_literal_type(node.children[0], hint_)}
1115
+ literal_type = test_literal_type(node.children[0], hint)
1088
1116
 
1089
1117
  if literal_type
1090
1118
  add_typing(node, type: literal_type)
@@ -1094,7 +1122,13 @@ module Steep
1094
1122
  end
1095
1123
 
1096
1124
  when :true, :false
1097
- add_typing(node, type: AST::Types::Boolean.new)
1125
+ ty = node.type == :true ? AST::Types::Literal.new(value: true) : AST::Types::Literal.new(value: false)
1126
+
1127
+ if hint && check_relation(sub_type: ty, super_type: hint).success?
1128
+ add_typing(node, type: hint)
1129
+ else
1130
+ add_typing(node, type: AST::Types::Boolean.new)
1131
+ end
1098
1132
 
1099
1133
  when :hash
1100
1134
  yield_self do
@@ -1294,69 +1328,45 @@ module Steep
1294
1328
  when :array
1295
1329
  yield_self do
1296
1330
  if node.children.empty?
1297
- typing.add_error Errors::FallbackAny.new(node: node) unless hint
1298
-
1299
- array_type = if hint
1300
- if check_relation(sub_type: AST::Builtin::Array.instance_type(AST::Builtin.any_type),
1301
- super_type: hint).success?
1302
- hint
1303
- end
1304
- end
1305
-
1306
- add_typing(node, type: array_type || AST::Builtin::Array.instance_type(AST::Builtin.any_type))
1307
- else
1308
- is_tuple = nil
1309
-
1310
- expand_alias(hint) do |hint|
1311
- is_tuple = hint.is_a?(AST::Types::Tuple)
1312
- is_tuple &&= node.children.all? {|child| child.type != :splat}
1313
- is_tuple &&= node.children.size >= hint.types.size
1314
- is_tuple &&= hint.types.map.with_index do |child_type, index|
1315
- child_node = node.children[index]
1316
- [synthesize(child_node, hint: child_type).type, child_type]
1317
- end.all? do |node_type, hint_type|
1318
- result = check_relation(sub_type: node_type, super_type: hint_type)
1319
- result.success?
1331
+ if hint
1332
+ array = AST::Builtin::Array.instance_type(AST::Builtin.any_type)
1333
+ if check_relation(sub_type: array, super_type: hint).success?
1334
+ add_typing node, type: hint
1335
+ else
1336
+ add_typing node, type: array
1320
1337
  end
1321
- end
1322
-
1323
- if is_tuple
1324
- array_type = hint
1325
1338
  else
1326
- element_hint = expand_alias(hint) do |hint|
1327
- AST::Builtin::Array.instance_type?(hint) && hint.args[0]
1339
+ typing.add_error Errors::FallbackAny.new(node: node)
1340
+ add_typing node, type: AST::Builtin::Array.instance_type(AST::Builtin.any_type)
1341
+ end
1342
+ else
1343
+ node_range = node.loc.expression.yield_self {|l| l.begin_pos..l.end_pos }
1344
+
1345
+ if hint && !(tuples = select_flatten_types(hint) {|type| type.is_a?(AST::Types::Tuple) }).empty?
1346
+ tuples.each do |tuple|
1347
+ typing.new_child(node_range) do |child_typing|
1348
+ pair = with_new_typing(child_typing).try_tuple_type(node, tuple)
1349
+ if pair && pair.constr.check_relation(sub_type: pair.type, super_type: hint).success?
1350
+ child_typing.save!
1351
+ return pair.with(constr: pair.constr.with_new_typing(typing))
1352
+ end
1353
+ end
1328
1354
  end
1355
+ end
1329
1356
 
1330
- element_types = node.children.flat_map do |e|
1331
- if e.type == :splat
1332
- Steep.logger.info "Typing of splat in array is incompatible with Ruby; it does not use #to_a method"
1333
- synthesize(e.children.first).type.yield_self do |type|
1334
- expand_alias(type) do |ty|
1335
- case ty
1336
- when AST::Types::Union
1337
- ty.types
1338
- else
1339
- [ty]
1340
- end
1341
- end
1342
- end.map do |type|
1343
- case
1344
- when AST::Builtin::Array.instance_type?(type)
1345
- type.args.first
1346
- when AST::Builtin::Range.instance_type?(type)
1347
- type.args.first
1348
- else
1349
- type
1350
- end
1357
+ if hint && !(arrays = select_flatten_types(hint) {|type| AST::Builtin::Array.instance_type?(type) }).empty?
1358
+ arrays.each do |array|
1359
+ typing.new_child(node_range) do |child_typing|
1360
+ pair = with_new_typing(child_typing).try_array_type(node, array)
1361
+ if pair.constr.check_relation(sub_type: pair.type, super_type: hint).success?
1362
+ child_typing.save!
1363
+ return pair.with(constr: pair.constr.with_new_typing(typing))
1351
1364
  end
1352
- else
1353
- [select_super_type(synthesize(e, hint: element_hint).type, element_hint)]
1354
1365
  end
1355
1366
  end
1356
- array_type = AST::Builtin::Array.instance_type(AST::Types::Union.build(types: element_types))
1357
1367
  end
1358
1368
 
1359
- add_typing(node, type: array_type)
1369
+ try_array_type(node, nil)
1360
1370
  end
1361
1371
  end
1362
1372
 
@@ -1665,6 +1675,49 @@ module Steep
1665
1675
  when :masgn
1666
1676
  type_masgn(node)
1667
1677
 
1678
+ when :for
1679
+ yield_self do
1680
+ asgn, collection, body = node.children
1681
+
1682
+ collection_type, constr = synthesize(collection)
1683
+ collection_type = expand_self(collection_type)
1684
+
1685
+ var_type = case collection_type
1686
+ when AST::Types::Any
1687
+ AST::Types::Any.new
1688
+ else
1689
+ each = checker.factory.interface(collection_type, private: true).methods[:each]
1690
+ method_type = (each&.types || []).find {|type| type.block && type.block.type.params.first_param }
1691
+ method_type&.yield_self do |method_type|
1692
+ method_type.block.type.params.first_param&.type
1693
+ end
1694
+ end
1695
+
1696
+ if var_type
1697
+ if body
1698
+ body_constr = constr.with_updated_context(
1699
+ lvar_env: constr.context.lvar_env.assign(asgn.children[0].name, node: asgn, type: var_type)
1700
+ )
1701
+
1702
+ typing.add_context_for_body(node, context: body_constr.context)
1703
+ _, _, body_context = body_constr.synthesize(body)
1704
+
1705
+ constr = constr.update_lvar_env {|env| env.join(constr.context.lvar_env, body_context.lvar_env) }
1706
+ else
1707
+ constr = self
1708
+ end
1709
+
1710
+ add_typing(node, type: collection_type, constr: constr)
1711
+ else
1712
+ fallback_to_any(node) do
1713
+ Errors::NoMethod.new(
1714
+ node: node,
1715
+ method: :each,
1716
+ type: collection_type
1717
+ )
1718
+ end
1719
+ end
1720
+ end
1668
1721
  when :while, :until
1669
1722
  yield_self do
1670
1723
  cond, body = node.children
@@ -1746,9 +1799,36 @@ module Steep
1746
1799
 
1747
1800
  when :or_asgn, :and_asgn
1748
1801
  yield_self do
1749
- _, rhs = node.children
1750
- rhs_type = synthesize(rhs).type
1751
- add_typing(node, type: rhs_type)
1802
+ asgn, rhs = node.children
1803
+
1804
+ case asgn.type
1805
+ when :lvasgn
1806
+ type, constr = synthesize(rhs, hint: hint)
1807
+ constr.lvasgn(asgn, type)
1808
+ when :ivasgn
1809
+ type, constr = synthesize(rhs, hint: hint)
1810
+ constr.ivasgn(asgn, type)
1811
+ when :send
1812
+ rhs_ = node.updated(:send,
1813
+ [
1814
+ asgn.children[0],
1815
+ :"#{asgn.children[1]}=",
1816
+ asgn.children[2],
1817
+ rhs
1818
+ ])
1819
+ node_type = case node.type
1820
+ when :or_asgn
1821
+ :or
1822
+ when :and_asgn
1823
+ :and
1824
+ end
1825
+ node_ = node.updated(node_type, [asgn, rhs_])
1826
+
1827
+ synthesize(node_, hint: hint)
1828
+ else
1829
+ Steep.logger.error { "#{node.type} with #{asgn.type} lhs is not supported"}
1830
+ fallback_to_any(node)
1831
+ end
1752
1832
  end
1753
1833
 
1754
1834
  when :defined?
@@ -1824,9 +1904,50 @@ module Steep
1824
1904
  add_typing node, type: AST::Builtin.any_type
1825
1905
  end
1826
1906
 
1827
- when :splat, :sclass, :alias
1907
+ when :cvasgn
1908
+ name, rhs = node.children
1909
+
1910
+ type, constr = synthesize(rhs, hint: hint)
1911
+
1912
+ var_type = if module_context&.class_variables
1913
+ module_context.class_variables[name]&.yield_self {|ty| checker.factory.type(ty) }
1914
+ end
1915
+
1916
+ if var_type
1917
+ result = constr.check_relation(sub_type: type, super_type: var_type)
1918
+
1919
+ if result.success?
1920
+ add_typing node, type: type, constr: constr
1921
+ else
1922
+ fallback_to_any node do
1923
+ Errors::IncompatibleAssignment.new(node: node,
1924
+ lhs_type: var_type,
1925
+ rhs_type: type,
1926
+ result: result)
1927
+ end
1928
+ end
1929
+ else
1930
+ fallback_to_any(node)
1931
+ end
1932
+
1933
+ when :cvar
1934
+ name = node.children[0]
1935
+ var_type = if module_context&.class_variables
1936
+ module_context.class_variables[name]&.yield_self {|ty| checker.factory.type(ty) }
1937
+ end
1938
+
1939
+ if var_type
1940
+ add_typing node, type: var_type
1941
+ else
1942
+ fallback_to_any node
1943
+ end
1944
+
1945
+ when :alias
1946
+ add_typing node, type: AST::Builtin.nil_type
1947
+
1948
+ when :splat
1828
1949
  yield_self do
1829
- Steep.logger.error "Unsupported node #{node.type} (#{node.location.expression.source_buffer.name}:#{node.location.expression.line})"
1950
+ Steep.logger.warn { "Unsupported node #{node.type} (#{node.location.expression.source_buffer.name}:#{node.location.expression.line})" }
1830
1951
 
1831
1952
  each_child_node node do |child|
1832
1953
  synthesize(child)
@@ -1876,136 +1997,202 @@ module Steep
1876
1997
  add_typing(node, type: ivar_type)
1877
1998
  end
1878
1999
 
2000
+ def masgn_lhs?(lhs)
2001
+ lhs.children.all? do |a|
2002
+ asgn_type = if a.type == :splat
2003
+ a.children[0].type
2004
+ else
2005
+ a.type
2006
+ end
2007
+ asgn_type == :lvasgn || asgn_type == :ivasgn
2008
+ end
2009
+ end
2010
+
2011
+ def lvasgn(node, type)
2012
+ name = node.children[0].name
2013
+ env = context.lvar_env.assign(name, node: node, type: type) do |declared_type, type, result|
2014
+ typing.add_error(
2015
+ Errors::IncompatibleAssignment.new(node: node,
2016
+ lhs_type: declared_type,
2017
+ rhs_type: type,
2018
+ result: result)
2019
+ )
2020
+ end
2021
+
2022
+ add_typing(node, type: type, constr: with_updated_context(lvar_env: env))
2023
+ end
2024
+
2025
+ def ivasgn(node, type)
2026
+ ivar = node.children[0]
2027
+
2028
+ type_env.assign(ivar: ivar, type: type, self_type: self_type) do |error|
2029
+ case error
2030
+ when Subtyping::Result::Failure
2031
+ var_type = type_env.get(ivar: ivar)
2032
+ typing.add_error(Errors::IncompatibleAssignment.new(node: node,
2033
+ lhs_type: var_type,
2034
+ rhs_type: type,
2035
+ result: error))
2036
+ when nil
2037
+ fallback_to_any node
2038
+ end
2039
+ end
2040
+
2041
+ add_typing(node, type: type)
2042
+ end
2043
+
1879
2044
  def type_masgn(node)
1880
2045
  lhs, rhs = node.children
1881
2046
  rhs_pair = synthesize(rhs)
1882
- rhs_type = expand_alias(rhs_pair.type)
2047
+ rhs_type = deep_expand_alias(rhs_pair.type)
1883
2048
 
1884
2049
  constr = rhs_pair.constr
1885
2050
 
1886
- if lhs.children.all? {|a| a.type == :lvasgn || a.type == :ivasgn}
1887
- case
1888
- when rhs.type == :array && lhs.children.size == rhs.children.size
1889
- # a, @b = x, y
2051
+ unless masgn_lhs?(lhs)
2052
+ Steep.logger.error("Unsupported masgn lhs node: only lvasgn, ivasgn, and splat are supported")
2053
+ _, constr = constr.fallback_to_any(lhs)
2054
+ return add_typing(node, type: rhs_type, constr: constr)
2055
+ end
1890
2056
 
1891
- constr = lhs.children.zip(rhs.children).inject(constr) do |ctr, (lhs, rhs)|
1892
- case lhs.type
1893
- when :lvasgn
1894
- name = lhs.children[0].name
1895
- type = typing.type_of(node: rhs)
1896
- env = ctr.context.lvar_env.assign(name, node: node, type: type) do |declared_type, type, result|
1897
- typing.add_error(
1898
- Errors::IncompatibleAssignment.new(node: lhs,
1899
- lhs_type: declared_type,
1900
- rhs_type: type,
1901
- result: result)
1902
- )
1903
- end
1904
- add_typing(lhs,
1905
- type: type,
1906
- constr: ctr.with_updated_context(lvar_env: env))
1907
- when :ivasgn
1908
- type_ivasgn(lhs.children.first, rhs, lhs)
1909
- constr
1910
- end
2057
+ falseys, truthys = partition_flatten_types(rhs_type) do |type|
2058
+ type.is_a?(AST::Types::Nil) || (type.is_a?(AST::Types::Literal) && type.value == false)
2059
+ end
2060
+
2061
+ unwrap_rhs_type = AST::Types::Union.build(types: truthys)
2062
+
2063
+ case
2064
+ when unwrap_rhs_type.is_a?(AST::Types::Tuple) || (rhs.type == :array && rhs.children.none? {|n| n.type == :splat })
2065
+ tuple_types = if unwrap_rhs_type.is_a?(AST::Types::Tuple)
2066
+ unwrap_rhs_type.types.dup
2067
+ else
2068
+ rhs.children.map do |node|
2069
+ typing.type_of(node: node)
2070
+ end
2071
+ end
2072
+
2073
+ assignment_nodes = lhs.children.dup
2074
+ leading_assignments = []
2075
+ trailing_assignments = []
2076
+
2077
+ until assignment_nodes.empty?
2078
+ cursor = assignment_nodes.first
2079
+
2080
+ if cursor.type == :splat
2081
+ break
2082
+ else
2083
+ leading_assignments << assignment_nodes.shift
1911
2084
  end
2085
+ end
1912
2086
 
1913
- add_typing(node, type: rhs_type, constr: constr)
2087
+ until assignment_nodes.empty?
2088
+ cursor = assignment_nodes.last
1914
2089
 
1915
- when rhs_type.is_a?(AST::Types::Tuple)
1916
- # a, @b = tuple
2090
+ if cursor.type == :splat
2091
+ break
2092
+ else
2093
+ trailing_assignments.unshift assignment_nodes.pop
2094
+ end
2095
+ end
1917
2096
 
1918
- constr = lhs.children.zip(rhs_type.types).inject(constr) do |ctr, (lhs, type)|
1919
- ty = type || AST::Builtin.nil_type
2097
+ leading_assignments.each do |asgn|
2098
+ type = tuple_types.first
1920
2099
 
1921
- case lhs.type
1922
- when :lvasgn
1923
- name = lhs.children[0].name
1924
- env = ctr.context.lvar_env.assign(name, node: node, type: ty) do |declared_type, type, result|
1925
- typing.add_error(
1926
- Errors::IncompatibleAssignment.new(node: lhs,
1927
- lhs_type: declared_type,
1928
- rhs_type: type,
1929
- result: result)
1930
- )
1931
- end
1932
- add_typing(lhs,
1933
- type: ty,
1934
- constr: ctr.with_updated_context(lvar_env: env)).constr
1935
- when :ivasgn
1936
- ivar = lhs.children[0]
2100
+ if type
2101
+ tuple_types.shift
2102
+ else
2103
+ type = AST::Builtin.nil_type
2104
+ end
1937
2105
 
1938
- type_env.assign(ivar: ivar, type: ty, self_type: self_type) do |error|
1939
- case error
1940
- when Subtyping::Result::Failure
1941
- ivar_type = type_env.get(ivar: ivar)
1942
- typing.add_error(Errors::IncompatibleAssignment.new(node: lhs,
1943
- lhs_type: ivar_type,
1944
- rhs_type: ty,
1945
- result: error))
1946
- when nil
1947
- fallback_to_any node
1948
- end
1949
- end
2106
+ case asgn.type
2107
+ when :lvasgn
2108
+ _, constr = constr.lvasgn(asgn, type)
2109
+ when :ivasgn
2110
+ _, constr = constr.ivasgn(asgn, type)
2111
+ end
2112
+ end
1950
2113
 
1951
- ctr
1952
- end
2114
+ trailing_assignments.reverse_each do |asgn|
2115
+ type = tuple_types.last
2116
+
2117
+ if type
2118
+ tuple_types.pop
2119
+ else
2120
+ type = AST::Builtin.nil_type
1953
2121
  end
1954
2122
 
1955
- add_typing(node, type: rhs_type, constr: constr)
2123
+ case asgn.type
2124
+ when :lvasgn
2125
+ _, constr = constr.lvasgn(asgn, type)
2126
+ when :ivasgn
2127
+ _, constr = constr.ivasgn(asgn, type)
2128
+ end
2129
+ end
1956
2130
 
1957
- when AST::Builtin::Array.instance_type?(rhs_type)
1958
- element_type = AST::Types::Union.build(types: [rhs_type.args.first, AST::Builtin.nil_type])
2131
+ element_type = if tuple_types.empty?
2132
+ AST::Builtin.nil_type
2133
+ else
2134
+ AST::Types::Union.build(types: tuple_types)
2135
+ end
2136
+ array_type = AST::Builtin::Array.instance_type(element_type)
1959
2137
 
1960
- constr = lhs.children.inject(constr) do |ctr, assignment|
1961
- case assignment.type
2138
+ assignment_nodes.each do |asgn|
2139
+ case asgn.type
2140
+ when :splat
2141
+ case asgn.children[0].type
1962
2142
  when :lvasgn
1963
- name = assignment.children[0].name
1964
- env = ctr.context.lvar_env.assign(name, node: node, type: element_type) do |declared_type, type, result|
1965
- typing.add_error(
1966
- Errors::IncompatibleAssignment.new(node: assignment,
1967
- lhs_type: declared_type,
1968
- rhs_type: type,
1969
- result: result)
1970
- )
1971
- end
2143
+ _, constr = constr.lvasgn(asgn.children[0], array_type)
2144
+ when :ivasgn
2145
+ _, constr = constr.ivasgn(asgn.children[0], array_type)
2146
+ end
2147
+ when :lvasgn
2148
+ _, constr = constr.lvasgn(asgn, element_type)
2149
+ when :ivasgn
2150
+ _,constr = constr.ivasgn(asgn, element_type)
2151
+ end
2152
+ end
1972
2153
 
1973
- add_typing(assignment,
1974
- type: element_type,
1975
- constr: ctr.with_updated_context(lvar_env: env)).constr
2154
+ unless falseys.empty?
2155
+ constr = constr.update_lvar_env {|lvar_env| self.context.lvar_env.join(lvar_env, self.context.lvar_env)}
2156
+ end
1976
2157
 
1977
- when :ivasgn
1978
- ivar = assignment.children[0]
2158
+ add_typing(node, type: rhs_type, constr: constr)
1979
2159
 
1980
- type_env.assign(ivar: ivar, type: element_type, self_type: self_type) do |error|
1981
- case error
1982
- when Subtyping::Result::Failure
1983
- type = type_env.get(ivar: ivar)
1984
- typing.add_error(Errors::IncompatibleAssignment.new(node: assignment,
1985
- lhs_type: type,
1986
- rhs_type: element_type,
1987
- result: error))
1988
- when nil
1989
- fallback_to_any node
1990
- end
1991
- end
2160
+ when flatten_union(unwrap_rhs_type).all? {|type| AST::Builtin::Array.instance_type?(type) }
2161
+ array_elements = flatten_union(unwrap_rhs_type).map {|type| type.args[0] }
2162
+ element_type = AST::Types::Union.build(types: array_elements + [AST::Builtin.nil_type])
2163
+
2164
+ constr = lhs.children.inject(constr) do |constr, assignment|
2165
+ case assignment.type
2166
+ when :lvasgn
2167
+ _, constr = constr.lvasgn(assignment, element_type)
1992
2168
 
1993
- ctr
2169
+ when :ivasgn
2170
+ _, constr = constr.ivasgn(assignment, element_type)
2171
+ when :splat
2172
+ case assignment.children[0].type
2173
+ when :lvasgn
2174
+ _, constr = constr.lvasgn(assignment.children[0], unwrap_rhs_type)
2175
+ when :ivasgn
2176
+ _, constr = constr.ivasgn(assignment.children[0], unwrap_rhs_type)
2177
+ else
2178
+ raise
1994
2179
  end
1995
2180
  end
1996
2181
 
1997
- add_typing node, type: rhs_type, constr: constr
1998
-
1999
- when rhs_type.is_a?(AST::Types::Any)
2000
- fallback_to_any(node)
2182
+ constr
2183
+ end
2001
2184
 
2002
- else
2003
- Steep.logger.error("Unsupported masgn: #{rhs.type} (#{rhs_type})")
2004
- fallback_to_any(node)
2185
+ unless falseys.empty?
2186
+ constr = constr.update_lvar_env {|lvar_env| self.context.lvar_env.join(lvar_env, self.context.lvar_env)}
2005
2187
  end
2188
+
2189
+ add_typing(node, type: rhs_type, constr: constr)
2006
2190
  else
2007
- Steep.logger.error("Unsupported masgn left hand side")
2008
- fallback_to_any(node)
2191
+ unless rhs_type.is_a?(AST::Types::Any)
2192
+ Steep.logger.error("Unsupported masgn rhs type: array or tuple is supported (#{rhs_type})")
2193
+ end
2194
+ _, constr = constr.fallback_to_any(lhs)
2195
+ add_typing(node, type: rhs_type, constr: constr)
2009
2196
  end
2010
2197
  end
2011
2198
 
@@ -2056,7 +2243,7 @@ module Steep
2056
2243
  else
2057
2244
  case expanded_receiver_type = expand_self(receiver_type)
2058
2245
  when AST::Types::Self
2059
- Steep.logger.error "`self` type cannot be resolved to concrete type"
2246
+ Steep.logger.debug { "`self` type cannot be resolved to concrete type" }
2060
2247
  fallback_to_any node do
2061
2248
  Errors::NoMethod.new(node: node, method: method_name, type: receiver_type)
2062
2249
  end
@@ -2999,7 +3186,12 @@ module Steep
2999
3186
 
3000
3187
  ty = case type
3001
3188
  when AST::Types::Name::Alias
3002
- deep_expand_alias(expand_alias(type), recursive: recursive << type)
3189
+ deep_expand_alias(expand_alias(type), recursive: recursive.union([type]))
3190
+ when AST::Types::Union
3191
+ AST::Types::Union.build(
3192
+ types: type.types.map {|ty| deep_expand_alias(ty, recursive: recursive, &block) },
3193
+ location: type.location
3194
+ )
3003
3195
  else
3004
3196
  type
3005
3197
  end
@@ -3011,19 +3203,51 @@ module Steep
3011
3203
  end
3012
3204
  end
3013
3205
 
3206
+ def flatten_union(type, acc = [])
3207
+ case type
3208
+ when AST::Types::Union
3209
+ type.types.each {|ty| flatten_union(ty, acc) }
3210
+ else
3211
+ acc << type
3212
+ end
3213
+
3214
+ acc
3215
+ end
3216
+
3217
+ def select_flatten_types(type, &block)
3218
+ types = flatten_union(deep_expand_alias(type))
3219
+ types.select(&block)
3220
+ end
3221
+
3222
+ def partition_flatten_types(type, &block)
3223
+ types = flatten_union(deep_expand_alias(type))
3224
+ types.partition(&block)
3225
+ end
3226
+
3227
+ def flatten_array_elements(type)
3228
+ flatten_union(deep_expand_alias(type)).flat_map do |type|
3229
+ if AST::Builtin::Array.instance_type?(type)
3230
+ type.args
3231
+ else
3232
+ [type]
3233
+ end
3234
+ end
3235
+ end
3236
+
3014
3237
  def expand_alias(type, &block)
3015
3238
  checker.factory.expand_alias(type, &block)
3016
3239
  end
3017
3240
 
3018
3241
  def test_literal_type(literal, hint)
3019
- case hint
3020
- when AST::Types::Literal
3021
- if hint.value == literal
3022
- hint
3023
- end
3024
- when AST::Types::Union
3025
- if hint.types.any? {|ty| ty.is_a?(AST::Types::Literal) && ty.value == literal}
3026
- hint
3242
+ if hint
3243
+ case hint
3244
+ when AST::Types::Any
3245
+ nil
3246
+ else
3247
+ literal_type = AST::Types::Literal.new(value: literal, location: nil)
3248
+ if check_relation(sub_type: literal_type, super_type: hint).success?
3249
+ hint
3250
+ end
3027
3251
  end
3028
3252
  end
3029
3253
  end
@@ -3057,6 +3281,47 @@ module Steep
3057
3281
  AST::Types::Name::Instance.new(name: type.name, args: args)
3058
3282
  end
3059
3283
 
3284
+ def try_tuple_type(node, hint)
3285
+ if node.children.size != hint.types.size
3286
+ return
3287
+ end
3288
+
3289
+ constr = self
3290
+ element_types = []
3291
+
3292
+ each_child_node(node).with_index do |child, index|
3293
+ type, constr = constr.synthesize(child, hint: hint.types[index])
3294
+ element_types << type
3295
+ end
3296
+
3297
+ constr.add_typing(node, type: AST::Types::Tuple.new(types: element_types))
3298
+ end
3299
+
3300
+ def try_array_type(node, hint)
3301
+ element_hint = hint ? hint.args[0] : nil
3302
+
3303
+ constr = self
3304
+ element_types = []
3305
+
3306
+ each_child_node(node) do |child|
3307
+ case child.type
3308
+ when :splat
3309
+ type, constr = constr.synthesize(child.children[0], hint: hint)
3310
+ if AST::Builtin::Array.instance_type?(type)
3311
+ element_types << type.args[0]
3312
+ else
3313
+ element_types.push(*flatten_array_elements(type))
3314
+ end
3315
+ else
3316
+ type, constr = constr.synthesize(child, hint: element_hint)
3317
+ element_types << type
3318
+ end
3319
+ end
3320
+
3321
+ element_type = AST::Types::Union.build(types: element_types)
3322
+ constr.add_typing(node, type: AST::Builtin::Array.instance_type(element_type))
3323
+ end
3324
+
3060
3325
  def try_hash_type(node, hint)
3061
3326
  case hint
3062
3327
  when AST::Types::Record