steep 0.21.0 → 0.27.0

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