steep 1.4.0 → 1.5.0.pre.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (112) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +2 -0
  3. data/.vscode/steep-shared.code-snippets +41 -0
  4. data/CHANGELOG.md +37 -0
  5. data/Gemfile +2 -5
  6. data/Gemfile.lock +20 -17
  7. data/Gemfile.steep +1 -1
  8. data/Gemfile.steep.lock +6 -6
  9. data/Rakefile +198 -0
  10. data/Steepfile +3 -1
  11. data/lib/steep/ast/builtin.rb +9 -7
  12. data/lib/steep/ast/node/type_application.rb +13 -5
  13. data/lib/steep/ast/node/type_assertion.rb +28 -9
  14. data/lib/steep/ast/types/factory.rb +39 -7
  15. data/lib/steep/cli.rb +2 -1
  16. data/lib/steep/diagnostic/deprecated/else_on_exhaustive_case.rb +20 -0
  17. data/lib/steep/diagnostic/lsp_formatter.rb +3 -3
  18. data/lib/steep/diagnostic/ruby.rb +73 -12
  19. data/lib/steep/drivers/annotations.rb +1 -0
  20. data/lib/steep/drivers/check.rb +18 -13
  21. data/lib/steep/drivers/checkfile.rb +1 -1
  22. data/lib/steep/drivers/diagnostic_printer.rb +6 -4
  23. data/lib/steep/drivers/init.rb +2 -1
  24. data/lib/steep/drivers/print_project.rb +3 -1
  25. data/lib/steep/drivers/stats.rb +1 -1
  26. data/lib/steep/drivers/utils/driver_helper.rb +10 -8
  27. data/lib/steep/drivers/utils/jobs_option.rb +6 -1
  28. data/lib/steep/drivers/validate.rb +9 -5
  29. data/lib/steep/drivers/watch.rb +8 -3
  30. data/lib/steep/expectations.rb +144 -75
  31. data/lib/steep/index/signature_symbol_provider.rb +22 -13
  32. data/lib/steep/node_helper.rb +172 -0
  33. data/lib/steep/server/base_worker.rb +2 -1
  34. data/lib/steep/server/change_buffer.rb +17 -15
  35. data/lib/steep/server/interaction_worker.rb +20 -0
  36. data/lib/steep/server/lsp_formatter.rb +20 -1
  37. data/lib/steep/server/master.rb +51 -36
  38. data/lib/steep/server/type_check_worker.rb +18 -2
  39. data/lib/steep/server/worker_process.rb +19 -2
  40. data/lib/steep/services/completion_provider.rb +189 -3
  41. data/lib/steep/services/file_loader.rb +1 -1
  42. data/lib/steep/services/goto_service.rb +123 -27
  43. data/lib/steep/services/signature_help_provider.rb +1 -6
  44. data/lib/steep/signature/validator.rb +6 -1
  45. data/lib/steep/source.rb +165 -108
  46. data/lib/steep/subtyping/check.rb +5 -3
  47. data/lib/steep/subtyping/variable_variance.rb +11 -0
  48. data/lib/steep/thread_waiter.rb +35 -0
  49. data/lib/steep/type_construction.rb +416 -171
  50. data/lib/steep/type_inference/block_params.rb +50 -9
  51. data/lib/steep/type_inference/context.rb +4 -0
  52. data/lib/steep/type_inference/context_array.rb +6 -6
  53. data/lib/steep/type_inference/logic_type_interpreter.rb +202 -68
  54. data/lib/steep/typing.rb +5 -4
  55. data/lib/steep/version.rb +1 -1
  56. data/lib/steep.rb +21 -14
  57. data/sample/Steepfile +1 -0
  58. data/sig/shims/bundler.rbs +3 -0
  59. data/sig/shims/language-server_protocol.rbs +151 -10
  60. data/sig/shims/parser/nodes.rbs +210 -0
  61. data/sig/shims/parser.rbs +10 -0
  62. data/sig/steep/ast/builtin.rbs +2 -2
  63. data/sig/steep/ast/node/type_application.rbs +2 -2
  64. data/sig/steep/ast/node/type_assertion.rbs +8 -2
  65. data/sig/steep/ast/types/factory.rbs +28 -1
  66. data/sig/steep/diagnostic/deprecated/else_on_exhaustive_case.rbs +13 -0
  67. data/sig/steep/diagnostic/lsp_formatter.rbs +5 -2
  68. data/sig/steep/diagnostic/ruby.rbs +76 -6
  69. data/sig/steep/drivers/annotations.rbs +5 -5
  70. data/sig/steep/drivers/check.rbs +11 -11
  71. data/sig/steep/drivers/diagnostic_printer.rbs +9 -9
  72. data/sig/steep/drivers/init.rbs +6 -6
  73. data/sig/steep/drivers/print_project.rbs +4 -4
  74. data/sig/steep/drivers/utils/driver_helper.rbs +8 -6
  75. data/sig/steep/drivers/validate.rbs +4 -4
  76. data/sig/steep/drivers/watch.rbs +1 -1
  77. data/sig/steep/expectations.rbs +72 -0
  78. data/sig/steep/index/signature_symbol_provider.rbs +22 -10
  79. data/sig/steep/interface/block.rbs +2 -0
  80. data/sig/steep/interface/function.rbs +2 -2
  81. data/sig/steep/node_helper.rbs +56 -0
  82. data/sig/steep/path_helper.rbs +1 -1
  83. data/sig/steep/project/options.rbs +1 -1
  84. data/sig/steep/range_extension.rbs +2 -2
  85. data/sig/steep/server/master.rbs +16 -2
  86. data/sig/steep/server/type_check_worker.rbs +5 -1
  87. data/sig/steep/server/worker_process.rbs +5 -1
  88. data/sig/steep/services/completion_provider.rbs +31 -1
  89. data/sig/steep/services/goto_service.rbs +80 -19
  90. data/sig/steep/source.rbs +27 -4
  91. data/sig/steep/subtyping/variable_variance.rbs +9 -9
  92. data/sig/steep/thread_waiter.rbs +13 -0
  93. data/sig/steep/type_construction.rbs +26 -9
  94. data/sig/steep/type_inference/block_params.rbs +13 -1
  95. data/sig/steep/type_inference/context.rbs +5 -1
  96. data/sig/steep/type_inference/context_array.rbs +16 -15
  97. data/sig/steep/type_inference/logic_type_interpreter.rbs +36 -6
  98. data/sig/steep/type_inference/type_env_builder.rbs +4 -0
  99. data/sig/steep/typing.rbs +22 -20
  100. data/sig/steep.rbs +14 -13
  101. data/smoke/and/a.rb +1 -1
  102. data/smoke/and/test_expectations.yml +5 -7
  103. data/smoke/diagnostics/incompatible_annotation.rb +1 -1
  104. data/smoke/diagnostics/test_expectations.yml +2 -2
  105. data/smoke/enumerator/a.rb +0 -7
  106. data/smoke/enumerator/b.rb +0 -2
  107. data/smoke/enumerator/test_expectations.yml +17 -105
  108. data/smoke/lambda/a.rb +0 -5
  109. data/smoke/lambda/test_expectations.yml +0 -22
  110. data/smoke/type_case/test_expectations.yml +10 -0
  111. data/steep.gemspec +2 -2
  112. metadata +16 -9
@@ -877,10 +877,6 @@ module Steep
877
877
  yield_self do
878
878
  if self_type && method_context!.method
879
879
  if super_def = method_context!.super_method
880
- each_child_node(node) do |child|
881
- synthesize(child)
882
- end
883
-
884
880
  super_method = Interface::Shape::Entry.new(
885
881
  method_types: super_def.defs.map {|type_def|
886
882
  decl = TypeInference::MethodCall::MethodDecl.new(
@@ -902,7 +898,8 @@ module Steep
902
898
  arguments: node.children,
903
899
  block_params: nil,
904
900
  block_body: nil,
905
- tapp: nil
901
+ tapp: nil,
902
+ hint: hint
906
903
  )
907
904
 
908
905
  if call && constr
@@ -927,12 +924,12 @@ module Steep
927
924
  fallback_to_any(node) { error }
928
925
  end
929
926
  else
930
- fallback_to_any node do
927
+ type_check_untyped_args(node.children).fallback_to_any(node) do
931
928
  Diagnostic::Ruby::UnexpectedSuper.new(node: node, method: method_context!.name)
932
929
  end
933
930
  end
934
931
  else
935
- fallback_to_any node
932
+ type_check_untyped_args(node.children).fallback_to_any(node)
936
933
  end
937
934
  end
938
935
 
@@ -949,47 +946,75 @@ module Steep
949
946
  self_type: module_context&.instance_type,
950
947
  definition: module_context&.instance_definition
951
948
  ) do |new|
949
+ # @type var new: TypeConstruction
950
+
952
951
  new.typing.add_context_for_node(node, context: new.context)
953
952
  new.typing.add_context_for_body(node, context: new.context)
954
953
 
955
- new.method_context.tap do |method_context|
954
+ new.method_context!.tap do |method_context|
956
955
  if method_context.method
957
- method_name = InstanceMethodName.new(type_name: method_context.method.implemented_in, method_name: name)
958
- new.typing.source_index.add_definition(method: method_name, definition: node)
956
+ if owner = method_context.method.implemented_in || method_context.method.defined_in
957
+ method_name = InstanceMethodName.new(type_name: owner, method_name: name)
958
+ new.typing.source_index.add_definition(method: method_name, definition: node)
959
+ end
959
960
  end
960
961
  end
961
962
 
962
963
  new = new.synthesize_children(args_node)
963
964
 
964
965
  body_pair = if body_node
965
- return_type = expand_alias(new.method_context&.return_type)
966
- if return_type && !return_type.is_a?(AST::Types::Void)
966
+ return_type = expand_alias(new.method_context!.return_type)
967
+ if !return_type.is_a?(AST::Types::Void)
967
968
  new.check(body_node, return_type) do |_, actual_type, result|
968
- typing.add_error(
969
- Diagnostic::Ruby::MethodBodyTypeMismatch.new(
970
- node: node,
971
- expected: new.method_context&.return_type,
972
- actual: actual_type,
973
- result: result
969
+ if new.method_context!.attribute_setter?
970
+ typing.add_error(
971
+ Diagnostic::Ruby::SetterBodyTypeMismatch.new(
972
+ node: node,
973
+ expected: new.method_context!.return_type,
974
+ actual: actual_type,
975
+ result: result,
976
+ method_name: new.method_context!.name
977
+ )
974
978
  )
975
- )
979
+ else
980
+ typing.add_error(
981
+ Diagnostic::Ruby::MethodBodyTypeMismatch.new(
982
+ node: node,
983
+ expected: new.method_context!.return_type,
984
+ actual: actual_type,
985
+ result: result
986
+ )
987
+ )
988
+ end
976
989
  end
977
990
  else
978
991
  new.synthesize(body_node)
979
992
  end
980
993
  else
981
- return_type = expand_alias(new.method_context&.return_type)
982
- if return_type && !return_type.is_a?(AST::Types::Void)
994
+ return_type = expand_alias(new.method_context!.return_type)
995
+ if !return_type.is_a?(AST::Types::Void)
983
996
  result = check_relation(sub_type: AST::Builtin.nil_type, super_type: return_type)
984
997
  if result.failure?
985
- typing.add_error(
986
- Diagnostic::Ruby::MethodBodyTypeMismatch.new(
987
- node: node,
988
- expected: new.method_context&.return_type,
989
- actual: AST::Builtin.nil_type,
990
- result: result
998
+ if new.method_context!.attribute_setter?
999
+ typing.add_error(
1000
+ Diagnostic::Ruby::SetterBodyTypeMismatch.new(
1001
+ node: node,
1002
+ expected: new.method_context!.return_type,
1003
+ actual: AST::Builtin.nil_type,
1004
+ result: result,
1005
+ method_name: new.method_context!.name
1006
+ )
1007
+ )
1008
+ else
1009
+ typing.add_error(
1010
+ Diagnostic::Ruby::MethodBodyTypeMismatch.new(
1011
+ node: node,
1012
+ expected: new.method_context!.return_type,
1013
+ actual: AST::Builtin.nil_type,
1014
+ result: result
1015
+ )
991
1016
  )
992
- )
1017
+ end
993
1018
  end
994
1019
  end
995
1020
 
@@ -1100,12 +1125,9 @@ module Steep
1100
1125
  return_value_node = node.children[0]
1101
1126
  value_type, constr = synthesize(return_value_node, hint: method_return_type)
1102
1127
  else
1103
- constr = synthesize_children(node)
1104
- return_types = node.children.map do |value|
1105
- constr.typing.type_of(node: value)
1106
- end
1107
-
1108
- value_type = AST::Builtin::Array.instance_type(union_type(*return_types))
1128
+ # It returns an array
1129
+ array = node.updated(:array)
1130
+ value_type, constr = synthesize(array, hint: method_return_type)
1109
1131
  end
1110
1132
 
1111
1133
  if method_return_type
@@ -1113,14 +1135,26 @@ module Steep
1113
1135
  result = constr.check_relation(sub_type: value_type, super_type: method_return_type)
1114
1136
 
1115
1137
  if result.failure?
1116
- typing.add_error(
1117
- Diagnostic::Ruby::ReturnTypeMismatch.new(
1118
- node: node,
1119
- expected: method_return_type,
1120
- actual: value_type,
1121
- result: result
1138
+ if method_context.attribute_setter?
1139
+ typing.add_error(
1140
+ Diagnostic::Ruby::SetterReturnTypeMismatch.new(
1141
+ node: node,
1142
+ method_name: method_context.name,
1143
+ expected: method_return_type,
1144
+ actual: value_type,
1145
+ result: result
1146
+ )
1122
1147
  )
1123
- )
1148
+ else
1149
+ typing.add_error(
1150
+ Diagnostic::Ruby::ReturnTypeMismatch.new(
1151
+ node: node,
1152
+ expected: method_return_type,
1153
+ actual: value_type,
1154
+ result: result
1155
+ )
1156
+ )
1157
+ end
1124
1158
  end
1125
1159
  end
1126
1160
  end
@@ -1408,11 +1442,17 @@ module Steep
1408
1442
  # @type var super_node: Parser::AST::Node?
1409
1443
 
1410
1444
  name_node, super_node, _ = node.children
1411
- _, constr, class_name = synthesize_constant_decl(name_node, name_node.children[0], name_node.children[1]) do
1412
- typing.add_error(
1413
- Diagnostic::Ruby::UnknownConstant.new(node: name_node, name: name_node.children[1]).class!
1414
- )
1445
+
1446
+ if name_node.type == :const
1447
+ _, constr, class_name = synthesize_constant_decl(name_node, name_node.children[0], name_node.children[1]) do
1448
+ typing.add_error(
1449
+ Diagnostic::Ruby::UnknownConstant.new(node: name_node, name: name_node.children[1]).class!
1450
+ )
1451
+ end
1452
+ else
1453
+ _, constr = synthesize(name_node)
1415
1454
  end
1455
+
1416
1456
  if class_name
1417
1457
  typing.source_index.add_definition(constant: class_name, definition: name_node)
1418
1458
  end
@@ -1459,8 +1499,13 @@ module Steep
1459
1499
 
1460
1500
  # @type var name_node: Parser::AST::Node
1461
1501
  name_node, _ = node.children
1462
- _, constr, module_name = synthesize_constant_decl(name_node, name_node.children[0], name_node.children[1]) do
1463
- typing.add_error Diagnostic::Ruby::UnknownConstant.new(node: name_node, name: name_node.children[1]).module!
1502
+
1503
+ if name_node.type == :const
1504
+ _, constr, module_name = synthesize_constant_decl(name_node, name_node.children[0], name_node.children[1]) do
1505
+ typing.add_error Diagnostic::Ruby::UnknownConstant.new(node: name_node, name: name_node.children[1]).module!
1506
+ end
1507
+ else
1508
+ _, constr = synthesize(name_node)
1464
1509
  end
1465
1510
 
1466
1511
  if module_name
@@ -1677,7 +1722,7 @@ module Steep
1677
1722
  left_type, constr, left_context = synthesize(left_node, hint: hint, condition: true).to_ary
1678
1723
 
1679
1724
  interpreter = TypeInference::LogicTypeInterpreter.new(subtyping: checker, typing: typing, config: builder_config)
1680
- left_truthy_env, left_falsy_env = interpreter.eval(env: left_context.type_env, node: left_node)
1725
+ left_truthy, left_falsy = interpreter.eval(env: left_context.type_env, node: left_node)
1681
1726
 
1682
1727
  if left_type.is_a?(AST::Types::Logic::Env)
1683
1728
  left_type = left_type.type
@@ -1685,32 +1730,40 @@ module Steep
1685
1730
 
1686
1731
  right_type, constr, right_context =
1687
1732
  constr
1688
- .update_type_env { left_truthy_env }
1733
+ .update_type_env { left_truthy.env }
1689
1734
  .tap {|constr| typing.add_context_for_node(right_node, context: constr.context) }
1690
1735
  .for_branch(right_node)
1691
1736
  .synthesize(right_node, hint: hint, condition: true).to_ary
1692
1737
 
1693
- right_truthy_env, right_falsy_env = interpreter.eval(env: right_context.type_env, node: right_node)
1738
+ right_truthy, right_falsy = interpreter.eval(env: right_context.type_env, node: right_node)
1694
1739
 
1695
- env =
1696
- if right_type.is_a?(AST::Types::Bot)
1697
- left_falsy_env
1698
- else
1699
- context.type_env.join(left_falsy_env, right_context.type_env)
1700
- end
1740
+ case
1741
+ when left_truthy.unreachable
1742
+ # Always left_falsy
1743
+ env = left_falsy.env
1744
+ type = left_falsy.type
1745
+ when left_falsy.unreachable
1746
+ # Always left_truthy ==> right
1747
+ env = right_context.type_env
1748
+ type = right_type
1749
+ when right_truthy.unreachable && right_falsy.unreachable
1750
+ env = left_falsy.env
1751
+ type = left_falsy.type
1752
+ else
1753
+ env = context.type_env.join(left_falsy.env, right_context.type_env)
1754
+ type = union_type(left_falsy.type, right_type)
1701
1755
 
1702
- type =
1703
- case
1704
- when check_relation(sub_type: left_type, super_type: AST::Types::Boolean.new).success?
1705
- union_type(left_type, right_type)
1706
- else
1707
- union_type(right_type, AST::Builtin.nil_type)
1756
+ unless type.is_a?(AST::Types::Any)
1757
+ if check_relation(sub_type: type, super_type: AST::Types::Boolean.new).success?
1758
+ type = AST::Types::Boolean.new
1759
+ end
1708
1760
  end
1761
+ end
1709
1762
 
1710
1763
  if condition
1711
1764
  type = AST::Types::Logic::Env.new(
1712
- truthy: right_truthy_env,
1713
- falsy: context.type_env.join(left_falsy_env, right_falsy_env),
1765
+ truthy: right_truthy.env,
1766
+ falsy: context.type_env.join(left_falsy.env, right_falsy.env),
1714
1767
  type: type
1715
1768
  )
1716
1769
  end
@@ -1725,40 +1778,47 @@ module Steep
1725
1778
  left_type, constr, left_context = synthesize(left_node, hint: hint, condition: true).to_ary
1726
1779
 
1727
1780
  interpreter = TypeInference::LogicTypeInterpreter.new(subtyping: checker, typing: typing, config: builder_config)
1728
- left_truthy_env, left_falsy_env = interpreter.eval(env: left_context.type_env, node: left_node)
1781
+ left_truthy, left_falsy = interpreter.eval(env: left_context.type_env, node: left_node)
1729
1782
 
1730
1783
  if left_type.is_a?(AST::Types::Logic::Env)
1731
1784
  left_type = left_type.type
1732
1785
  end
1733
- left_type, _ = checker.factory.unwrap_optional(left_type)
1734
1786
 
1735
1787
  right_type, constr, right_context =
1736
1788
  constr
1737
- .update_type_env { left_falsy_env }
1789
+ .update_type_env { left_falsy.env }
1738
1790
  .tap {|constr| typing.add_context_for_node(right_node, context: constr.context) }
1739
1791
  .for_branch(right_node)
1740
- .synthesize(right_node, hint: left_type, condition: true).to_ary
1792
+ .synthesize(right_node, hint: left_truthy.type, condition: true).to_ary
1741
1793
 
1742
- right_truthy_env, right_falsy_env = interpreter.eval(env: left_falsy_env, node: right_node)
1794
+ right_truthy, right_falsy = interpreter.eval(env: left_falsy.env, node: right_node)
1743
1795
 
1744
- env = if right_type.is_a?(AST::Types::Bot)
1745
- left_truthy_env
1746
- else
1747
- context.type_env.join(left_truthy_env, right_context.type_env)
1748
- end
1796
+ case
1797
+ when left_falsy.unreachable
1798
+ env = left_truthy.env
1799
+ type = left_truthy.type
1800
+ when left_truthy.unreachable
1801
+ # Always left_falsy ==> right
1802
+ env = right_context.type_env
1803
+ type = right_type
1804
+ when right_truthy.unreachable && right_falsy.unreachable
1805
+ env = left_truthy.env
1806
+ type = left_truthy.type
1807
+ else
1808
+ env = context.type_env.join(left_truthy.env, right_context.type_env)
1809
+ type = union_type(left_truthy.type, right_type)
1749
1810
 
1750
- type =
1751
- case
1752
- when check_relation(sub_type: left_type, super_type: AST::Builtin.bool_type).success? && !left_type.is_a?(AST::Types::Any)
1753
- AST::Builtin.bool_type
1754
- else
1755
- union_type(left_type, right_type)
1811
+ unless type.is_a?(AST::Types::Any)
1812
+ if check_relation(sub_type: type, super_type: AST::Types::Boolean.new).success?
1813
+ type = AST::Types::Boolean.new
1814
+ end
1756
1815
  end
1816
+ end
1757
1817
 
1758
1818
  if condition
1759
1819
  type = AST::Types::Logic::Env.new(
1760
- truthy: context.type_env.join(left_truthy_env, right_truthy_env),
1761
- falsy: right_falsy_env,
1820
+ truthy: context.type_env.join(left_truthy.env, right_truthy.env),
1821
+ falsy: right_falsy.env,
1762
1822
  type: type
1763
1823
  )
1764
1824
  end
@@ -1772,12 +1832,12 @@ module Steep
1772
1832
 
1773
1833
  cond_type, constr = synthesize(cond, condition: true).to_ary
1774
1834
  interpreter = TypeInference::LogicTypeInterpreter.new(subtyping: checker, typing: constr.typing, config: builder_config)
1775
- truthy_env, falsy_env = interpreter.eval(env: constr.context.type_env, node: cond)
1835
+ truthy, falsy = interpreter.eval(env: constr.context.type_env, node: cond)
1776
1836
 
1777
1837
  if true_clause
1778
1838
  true_pair =
1779
1839
  constr
1780
- .update_type_env { truthy_env }
1840
+ .update_type_env { truthy.env }
1781
1841
  .for_branch(true_clause)
1782
1842
  .tap {|constr| typing.add_context_for_node(true_clause, context: constr.context) }
1783
1843
  .synthesize(true_clause, hint: hint)
@@ -1786,7 +1846,7 @@ module Steep
1786
1846
  if false_clause
1787
1847
  false_pair =
1788
1848
  constr
1789
- .update_type_env { falsy_env }
1849
+ .update_type_env { falsy.env }
1790
1850
  .for_branch(false_clause)
1791
1851
  .tap {|constr| typing.add_context_for_node(false_clause, context: constr.context) }
1792
1852
  .synthesize(false_clause, hint: hint)
@@ -1795,25 +1855,49 @@ module Steep
1795
1855
  constr = constr.update_type_env do |env|
1796
1856
  envs = [] #: Array[TypeInference::TypeEnv]
1797
1857
 
1798
- if true_pair
1799
- unless true_pair.type.is_a?(AST::Types::Bot)
1800
- envs << true_pair.context.type_env
1858
+ unless truthy.unreachable
1859
+ if true_pair
1860
+ unless true_pair.type.is_a?(AST::Types::Bot)
1861
+ envs << true_pair.context.type_env
1862
+ end
1863
+ else
1864
+ envs << truthy.env
1801
1865
  end
1802
- else
1803
- envs << truthy_env
1804
1866
  end
1805
1867
 
1806
1868
  if false_pair
1807
- unless false_pair.type.is_a?(AST::Types::Bot)
1808
- envs << false_pair.context.type_env
1869
+ unless falsy.unreachable
1870
+ unless false_pair.type.is_a?(AST::Types::Bot)
1871
+ envs << false_pair.context.type_env
1872
+ end
1809
1873
  end
1810
1874
  else
1811
- envs << falsy_env
1875
+ envs << falsy.env
1812
1876
  end
1813
1877
 
1814
1878
  env.join(*envs)
1815
1879
  end
1816
1880
 
1881
+ if truthy.unreachable
1882
+ if true_clause
1883
+ typing.add_error(
1884
+ Diagnostic::Ruby::UnreachableBranch.new(
1885
+ node: true_clause || node
1886
+ )
1887
+ )
1888
+ end
1889
+ end
1890
+
1891
+ if falsy.unreachable
1892
+ if false_clause
1893
+ typing.add_error(
1894
+ Diagnostic::Ruby::UnreachableBranch.new(
1895
+ node: false_clause || node
1896
+ )
1897
+ )
1898
+ end
1899
+ end
1900
+
1817
1901
  node_type = union_type_unify(true_pair&.type || AST::Builtin.nil_type, false_pair&.type || AST::Builtin.nil_type)
1818
1902
  add_typing(node, type: node_type, constr: constr)
1819
1903
  end
@@ -1832,8 +1916,11 @@ module Steep
1832
1916
 
1833
1917
  cond_type, constr = constr.synthesize(cond)
1834
1918
  _, cond_vars = interpreter.decompose_value(cond)
1919
+ SPECIAL_LVAR_NAMES.each do |name|
1920
+ cond_vars.delete(name)
1921
+ end
1835
1922
 
1836
- var_name = :"_a#{SecureRandom.base64(4)}"
1923
+ var_name = :"_a#{SecureRandom.alphanumeric(4)}"
1837
1924
  var_cond, value_node = extract_outermost_call(cond, var_name)
1838
1925
  if value_node
1839
1926
  unless constr.context.type_env[value_node]
@@ -1846,6 +1933,8 @@ module Steep
1846
1933
  end
1847
1934
  end
1848
1935
 
1936
+ next_branch_reachable = true
1937
+
1849
1938
  when_constr = constr
1850
1939
  whens.each do |clause|
1851
1940
  # @type var tests: Array[Parser::AST::Node]
@@ -1856,16 +1945,26 @@ module Steep
1856
1945
  # @type var test_envs: Array[TypeInference::TypeEnv]
1857
1946
  test_envs = []
1858
1947
 
1948
+ branch_reachable = false
1949
+ false_branch_reachable = false
1950
+
1859
1951
  tests.each do |test|
1860
1952
  test_node = test.updated(:send, [test, :===, cond])
1861
1953
  test_type, test_constr = test_constr.synthesize(test_node, condition: true).to_ary
1862
- truthy_env, falsy_env = interpreter.eval(node: test_node, env: test_constr.context.type_env)
1954
+ truthy, falsy = interpreter.eval(node: test_node, env: test_constr.context.type_env)
1955
+
1956
+ truthy_env = truthy.env
1957
+ falsy_env = falsy.env
1863
1958
 
1864
1959
  test_envs << truthy_env
1865
1960
 
1866
1961
  test_constr = test_constr.update_type_env { falsy_env }
1962
+
1963
+ branch_reachable ||= next_branch_reachable && !truthy.unreachable
1964
+ false_branch_reachable = !falsy.unreachable
1867
1965
  end
1868
1966
 
1967
+ next_branch_reachable &&= false_branch_reachable
1869
1968
  body_constr = when_constr.update_type_env {|env| env.join(*test_envs) }
1870
1969
 
1871
1970
  if body
@@ -1878,6 +1977,12 @@ module Steep
1878
1977
  branch_results << Pair.new(type: AST::Builtin.nil_type, constr: body_constr)
1879
1978
  end
1880
1979
 
1980
+ unless branch_reachable
1981
+ typing.add_error(
1982
+ Diagnostic::Ruby::UnreachableBranch.new(node: body || clause)
1983
+ )
1984
+ end
1985
+
1881
1986
  when_constr = test_constr
1882
1987
  end
1883
1988
 
@@ -1888,7 +1993,11 @@ module Steep
1888
1993
  end_pos = node.loc.end.begin_pos
1889
1994
  typing.add_context(begin_pos..end_pos, context: when_constr.context)
1890
1995
 
1891
- branch_results << when_constr.synthesize(els, hint: hint)
1996
+ else_result = when_constr.synthesize(els, hint: hint)
1997
+
1998
+ if next_branch_reachable
1999
+ branch_results << else_result
2000
+ end
1892
2001
  end
1893
2002
 
1894
2003
  types = branch_results.map(&:type)
@@ -1899,10 +2008,17 @@ module Steep
1899
2008
  cond_type ||= when_constr.context.type_env[value_node] if value_node
1900
2009
  cond_type ||= typing.type_of(node: node.children[0])
1901
2010
 
1902
- if cond_type.is_a?(AST::Types::Bot)
2011
+ if !next_branch_reachable
1903
2012
  # Exhaustive
1904
- if els
1905
- typing.add_error Diagnostic::Ruby::ElseOnExhaustiveCase.new(node: els, type: cond_type)
2013
+ _, _, _, loc = deconstruct_case_node!(node)
2014
+
2015
+ # `else` may present even if it's empty
2016
+ if loc.else
2017
+ if els
2018
+ typing.add_error Diagnostic::Ruby::UnreachableBranch.new(node: els)
2019
+ else
2020
+ typing.add_error Diagnostic::Ruby::UnreachableBranch.new(node: node, location: loc.else)
2021
+ end
1906
2022
  end
1907
2023
  else
1908
2024
  unless els
@@ -1916,6 +2032,8 @@ module Steep
1916
2032
  condition_constr = constr
1917
2033
  clause_constr = constr
1918
2034
 
2035
+ next_branch_reachable = true
2036
+
1919
2037
  whens.each do |when_clause|
1920
2038
  when_clause_constr = condition_constr
1921
2039
  body_envs = [] #: Array[TypeInference::TypeEnv]
@@ -1924,14 +2042,24 @@ module Steep
1924
2042
  # @type var body: Parser::AST::Node?
1925
2043
  *tests, body = when_clause.children
1926
2044
 
2045
+ branch_reachable = false
2046
+ false_branch_reachable = false
2047
+
1927
2048
  tests.each do |test|
1928
2049
  test_type, condition_constr = condition_constr.synthesize(test, condition: true)
1929
- truthy_env, falsy_env = interpreter.eval(env: condition_constr.context.type_env, node: test)
2050
+ truthy, falsy = interpreter.eval(env: condition_constr.context.type_env, node: test)
2051
+ truthy_env = truthy.env
2052
+ falsy_env = falsy.env
1930
2053
 
1931
2054
  condition_constr = condition_constr.update_type_env { falsy_env }
1932
2055
  body_envs << truthy_env
2056
+
2057
+ branch_reachable ||= next_branch_reachable && !truthy.unreachable
2058
+ false_branch_reachable ||= !falsy.unreachable
1933
2059
  end
1934
2060
 
2061
+ next_branch_reachable &&= false_branch_reachable
2062
+
1935
2063
  if body
1936
2064
  branch_results <<
1937
2065
  when_clause_constr
@@ -1942,6 +2070,12 @@ module Steep
1942
2070
  else
1943
2071
  branch_results << Pair.new(type: AST::Builtin.nil_type, constr: when_clause_constr)
1944
2072
  end
2073
+
2074
+ unless branch_reachable
2075
+ typing.add_error(
2076
+ Diagnostic::Ruby::UnreachableBranch.new(node: body || when_clause)
2077
+ )
2078
+ end
1945
2079
  end
1946
2080
 
1947
2081
  if els
@@ -2135,7 +2269,9 @@ module Steep
2135
2269
  cond_type, constr = synthesize(cond, condition: true).to_ary
2136
2270
 
2137
2271
  interpreter = TypeInference::LogicTypeInterpreter.new(subtyping: checker, typing: typing, config: builder_config)
2138
- truthy_env, falsy_env = interpreter.eval(env: constr.context.type_env, node: cond)
2272
+ truthy, falsy = interpreter.eval(env: constr.context.type_env, node: cond)
2273
+ truthy_env = truthy.env
2274
+ falsy_env = falsy.env
2139
2275
 
2140
2276
  case node.type
2141
2277
  when :while
@@ -2221,8 +2357,11 @@ module Steep
2221
2357
  # ignore
2222
2358
  add_typing(node, type: AST::Builtin.any_type)
2223
2359
 
2224
- when :nth_ref, :back_ref
2225
- add_typing(node, type: AST::Builtin::String.instance_type)
2360
+ when :nth_ref
2361
+ add_typing(node, type: union_type(AST::Builtin::String.instance_type, AST::Builtin.nil_type))
2362
+
2363
+ when :back_ref
2364
+ synthesize(node.updated(:gvar), hint: hint)
2226
2365
 
2227
2366
  when :or_asgn, :and_asgn
2228
2367
  yield_self do
@@ -2290,43 +2429,58 @@ module Steep
2290
2429
 
2291
2430
  when :block_pass
2292
2431
  yield_self do
2293
- value = node.children[0]
2432
+ value_node = node.children[0]
2294
2433
 
2295
- case
2296
- when hint.is_a?(AST::Types::Proc) && value && value.type == :sym
2297
- if hint.one_arg?
2298
- # Assumes Symbol#to_proc implementation
2299
- param_type = hint.type.params.required[0]
2300
- case param_type
2301
- when AST::Types::Any
2302
- type = AST::Types::Any.new
2303
- else
2304
- if method = calculate_interface(param_type, private: true)&.methods&.[](value.children[0])
2305
- return_types = method.method_types.filter_map do |method_type|
2306
- if method_type.type.params.optional?
2307
- method_type.type.return_type
2434
+ constr = self #: TypeConstruction
2435
+
2436
+ if value_node
2437
+ type, constr = synthesize(value_node, hint: hint)
2438
+
2439
+ if hint.is_a?(AST::Types::Proc) && value_node.type == :sym
2440
+ if hint.one_arg?
2441
+ # Assumes Symbol#to_proc implementation
2442
+ param_type = hint.type.params.required[0]
2443
+ case param_type
2444
+ when AST::Types::Any
2445
+ type = AST::Types::Any.new
2446
+ else
2447
+ if method = calculate_interface(param_type, private: true)&.methods&.[](value_node.children[0])
2448
+ return_types = method.method_types.filter_map do |method_type|
2449
+ if method_type.type.params.optional?
2450
+ method_type.type.return_type
2451
+ end
2308
2452
  end
2309
- end
2310
2453
 
2311
- unless return_types.empty?
2312
- type = AST::Types::Proc.new(
2313
- type: Interface::Function.new(
2314
- params: Interface::Function::Params.empty.with_first_param(
2315
- Interface::Function::Params::PositionalParams::Required.new(param_type)
2454
+ unless return_types.empty?
2455
+ type = AST::Types::Proc.new(
2456
+ type: Interface::Function.new(
2457
+ params: Interface::Function::Params.empty.with_first_param(
2458
+ Interface::Function::Params::PositionalParams::Required.new(param_type)
2459
+ ),
2460
+ return_type: return_types[0],
2461
+ location: nil
2316
2462
  ),
2317
- return_type: return_types[0],
2318
- location: nil
2319
- ),
2320
- block: nil,
2321
- self_type: nil
2322
- )
2463
+ block: nil,
2464
+ self_type: nil
2465
+ )
2466
+ end
2323
2467
  end
2324
2468
  end
2469
+ else
2470
+ Steep.logger.error "Passing multiple args through Symbol#to_proc is not supported yet"
2325
2471
  end
2472
+ end
2473
+
2474
+ case
2475
+ when type.is_a?(AST::Types::Proc)
2476
+ # nop
2477
+ when AST::Builtin::Proc.instance_type?(type)
2478
+ # nop
2326
2479
  else
2327
- Steep.logger.error "Passing multiple args through Symbol#to_proc is not supported yet"
2480
+ type = try_convert(type, :to_proc) || type
2328
2481
  end
2329
- when value == nil
2482
+ else
2483
+ # Anonymous block_pass only happens inside method definition
2330
2484
  if block_type = method_context!.block_type
2331
2485
  type = AST::Types::Proc.new(
2332
2486
  type: block_type.type,
@@ -2334,16 +2488,15 @@ module Steep
2334
2488
  block: nil,
2335
2489
  self_type: block_type.self_type
2336
2490
  )
2491
+
2337
2492
  if block_type.optional?
2338
- type = AST::Types::Union.build(types: [type, AST::Builtin.nil_type])
2493
+ type = union_type(type, AST::Builtin.nil_type)
2339
2494
  end
2340
2495
  else
2341
2496
  type = AST::Builtin.nil_type
2342
2497
  end
2343
2498
  end
2344
2499
 
2345
- type ||= synthesize(value, hint: hint).type
2346
-
2347
2500
  add_typing node, type: type
2348
2501
  end
2349
2502
 
@@ -2435,7 +2588,7 @@ module Steep
2435
2588
  # @type var as_type: AST::Node::TypeAssertion
2436
2589
  asserted_node, as_type = node.children
2437
2590
 
2438
- if type = as_type.type?(module_context.nesting, checker.factory, [])
2591
+ if type = as_type.type?(module_context.nesting, checker, [])
2439
2592
  actual_type, constr = synthesize(asserted_node, hint: type)
2440
2593
 
2441
2594
  if no_subtyping?(sub_type: type, super_type: actual_type) && no_subtyping?(sub_type: actual_type, super_type: type)
@@ -2517,7 +2670,7 @@ module Steep
2517
2670
 
2518
2671
  add_typing(node, type: type)
2519
2672
  else
2520
- type_send(node, send_node: node, block_params: nil, block_body: nil, tapp: tapp)
2673
+ type_send(node, send_node: node, block_params: nil, block_body: nil, tapp: tapp, hint: hint)
2521
2674
  end
2522
2675
  end
2523
2676
  when :csend
@@ -2532,7 +2685,7 @@ module Steep
2532
2685
  end
2533
2686
  add_typing(node, type: type).to_ary
2534
2687
  else
2535
- type_send(node, send_node: node, block_params: nil, block_body: nil, unwrap: true, tapp: tapp).to_ary
2688
+ type_send(node, send_node: node, block_params: nil, block_body: nil, unwrap: true, tapp: tapp, hint: hint).to_ary
2536
2689
  end
2537
2690
 
2538
2691
  constr
@@ -2546,7 +2699,7 @@ module Steep
2546
2699
  # @type var node: Parser::AST::Node & Parser::AST::_BlockNode
2547
2700
  type_lambda(node, params_node: params, body_node: body, type_hint: hint)
2548
2701
  else
2549
- type_send(node, send_node: send_node, block_params: params, block_body: body, unwrap: send_node.type == :csend, tapp: tapp)
2702
+ type_send(node, send_node: send_node, block_params: params, block_body: body, unwrap: send_node.type == :csend, tapp: tapp, hint: hint)
2550
2703
  end
2551
2704
  end
2552
2705
  when :numblock
@@ -2565,7 +2718,7 @@ module Steep
2565
2718
  # @type var node: Parser::AST::Node & Parser::AST::_BlockNode
2566
2719
  type_lambda(node, params_node: params, body_node: body, type_hint: hint)
2567
2720
  else
2568
- type_send(node, send_node: send_node, block_params: params, block_body: body, unwrap: send_node.type == :csend, tapp: tapp)
2721
+ type_send(node, send_node: send_node, block_params: params, block_body: body, unwrap: send_node.type == :csend, tapp: tapp, hint: hint)
2569
2722
  end
2570
2723
  end
2571
2724
  else
@@ -2874,7 +3027,7 @@ module Steep
2874
3027
  if type.types.size == 2
2875
3028
  if type.types.find {|t| t.is_a?(AST::Types::Nil) }
2876
3029
  if proc_type = type.types.find {|t| t.is_a?(AST::Types::Proc) }
2877
- proc_type
3030
+ proc_type #: AST::Types::Proc
2878
3031
  end
2879
3032
  end
2880
3033
  end
@@ -2885,14 +3038,32 @@ module Steep
2885
3038
  block_annotations = source.annotations(block: node, factory: checker.factory, context: nesting)
2886
3039
  params = TypeInference::BlockParams.from_node(params_node, annotations: block_annotations)
2887
3040
 
2888
- type_hint = deep_expand_alias(type_hint) if type_hint
3041
+ if type_hint
3042
+ original_hint = type_hint
2889
3043
 
2890
- case type_hint
2891
- when AST::Types::Proc
2892
- params_hint = type_hint.type.params
2893
- return_hint = type_hint.type.return_type
2894
- block_hint = type_hint.block
2895
- self_hint = type_hint.self_type
3044
+ type_hint = deep_expand_alias(type_hint) || type_hint
3045
+
3046
+ procs = flatten_union(type_hint).select do |type|
3047
+ check_relation(sub_type: type, super_type: AST::Builtin::Proc.instance_type).success?
3048
+ end
3049
+
3050
+ proc_instances, proc_types = procs.partition {|type| AST::Builtin::Proc.instance_type?(type) }
3051
+
3052
+ case
3053
+ when !proc_instances.empty? && proc_types.empty?
3054
+ # `::Proc` is given as a hint
3055
+ when proc_types.size == 1
3056
+ # Proc type is given as a hint
3057
+ hint_proc = proc_types[0] #: AST::Types::Proc
3058
+ params_hint = hint_proc.type.params
3059
+ return_hint = hint_proc.type.return_type
3060
+ block_hint = hint_proc.block
3061
+ self_hint = hint_proc.self_type
3062
+ else
3063
+ typing.add_error(
3064
+ Diagnostic::Ruby::ProcHintIgnored.new(hint_type: original_hint, node: node)
3065
+ )
3066
+ end
2896
3067
  end
2897
3068
 
2898
3069
  block_constr = for_block(
@@ -3028,7 +3199,7 @@ module Steep
3028
3199
  end
3029
3200
  end
3030
3201
 
3031
- def type_send_interface(node, interface:, receiver:, receiver_type:, method_name:, arguments:, block_params:, block_body:, tapp:)
3202
+ def type_send_interface(node, interface:, receiver:, receiver_type:, method_name:, arguments:, block_params:, block_body:, tapp:, hint:)
3032
3203
  method = interface&.methods&.[](method_name)
3033
3204
 
3034
3205
  if method
@@ -3040,7 +3211,8 @@ module Steep
3040
3211
  block_params: block_params,
3041
3212
  block_body: block_body,
3042
3213
  receiver_type: receiver_type,
3043
- tapp: tapp
3214
+ tapp: tapp,
3215
+ hint: hint
3044
3216
  )
3045
3217
 
3046
3218
  if call && constr
@@ -3159,17 +3331,17 @@ module Steep
3159
3331
  end
3160
3332
  end
3161
3333
 
3162
- def type_send(node, send_node:, block_params:, block_body:, unwrap: false, tapp:)
3334
+ def type_send(node, send_node:, block_params:, block_body:, unwrap: false, tapp:, hint:)
3163
3335
  # @type var constr: TypeConstruction
3164
3336
  # @type var receiver: Parser::AST::Node?
3165
3337
 
3166
3338
  case send_node.type
3167
3339
  when :super, :zsuper
3168
3340
  receiver = nil
3169
- method_name = method_context&.name
3341
+ method_name = method_context!.name
3170
3342
  arguments = send_node.children
3171
3343
 
3172
- if method_name.nil? || method_context&.super_method.nil?
3344
+ if method_name.nil? || method_context!.super_method.nil?
3173
3345
  return fallback_to_any(send_node) do
3174
3346
  Diagnostic::Ruby::UnexpectedSuper.new(
3175
3347
  node: send_node,
@@ -3241,7 +3413,8 @@ module Steep
3241
3413
  arguments: arguments,
3242
3414
  block_params: block_params,
3243
3415
  block_body: block_body,
3244
- tapp: tapp
3416
+ tapp: tapp,
3417
+ hint: hint
3245
3418
  )
3246
3419
  else
3247
3420
  constr = constr.synthesize_children(node, skips: [receiver])
@@ -3300,10 +3473,14 @@ module Steep
3300
3473
  ],
3301
3474
  hash_compact: Set[
3302
3475
  MethodName("::Hash#compact")
3476
+ ],
3477
+ lambda: Set[
3478
+ MethodName("::Kernel#lambda"),
3479
+ MethodName("::Kernel.lambda")
3303
3480
  ]
3304
3481
  }
3305
3482
 
3306
- def try_special_method(node, receiver_type:, method_name:, method_type:, arguments:, block_params:, block_body:)
3483
+ def try_special_method(node, receiver_type:, method_name:, method_type:, arguments:, block_params:, block_body:, hint:)
3307
3484
  decls = method_type.method_decls
3308
3485
 
3309
3486
  case
@@ -3354,12 +3531,29 @@ module Steep
3354
3531
  return [call, constr]
3355
3532
  end
3356
3533
  end
3534
+ when decl = decls.find {|decl| SPECIAL_METHOD_NAMES[:lambda].include?(decl.method_name) }
3535
+ if block_params
3536
+ # @type var node: Parser::AST::Node & Parser::AST::_BlockNode
3537
+ type, constr = type_lambda(node, params_node: block_params, body_node: block_body, type_hint: hint)
3538
+
3539
+ call = TypeInference::MethodCall::Special.new(
3540
+ node: node,
3541
+ context: context.call_context,
3542
+ method_name: decl.method_name.method_name,
3543
+ receiver_type: receiver_type,
3544
+ actual_method_type: method_type.with(type: method_type.type.with(return_type: type)),
3545
+ return_type: type,
3546
+ method_decls: decls
3547
+ )
3548
+
3549
+ return [call, constr]
3550
+ end
3357
3551
  end
3358
3552
 
3359
3553
  nil
3360
3554
  end
3361
3555
 
3362
- def type_method_call(node, method_name:, receiver_type:, method:, arguments:, block_params:, block_body:, tapp:)
3556
+ def type_method_call(node, method_name:, receiver_type:, method:, arguments:, block_params:, block_body:, tapp:, hint:)
3363
3557
  node_range = node.loc.expression.to_range
3364
3558
 
3365
3559
  # @type var fails: Array[[TypeInference::MethodCall::t, TypeConstruction]]
@@ -3377,7 +3571,8 @@ module Steep
3377
3571
  method_type: method_type,
3378
3572
  arguments: arguments,
3379
3573
  block_params: block_params,
3380
- block_body: block_body
3574
+ block_body: block_body,
3575
+ hint: hint
3381
3576
  ) || constr.try_method_type(
3382
3577
  node,
3383
3578
  receiver_type: receiver_type,
@@ -3386,7 +3581,8 @@ module Steep
3386
3581
  arguments: arguments,
3387
3582
  block_params: block_params,
3388
3583
  block_body: block_body,
3389
- tapp: tapp
3584
+ tapp: tapp,
3585
+ hint: hint
3390
3586
  )
3391
3587
 
3392
3588
  if call.is_a?(TypeInference::MethodCall::Typed)
@@ -3473,6 +3669,24 @@ module Steep
3473
3669
  end
3474
3670
  end
3475
3671
 
3672
+ def type_check_untyped_args(arguments)
3673
+ constr = self #: TypeConstruction
3674
+
3675
+ arguments.each do |arg|
3676
+ case arg.type
3677
+ when :splat
3678
+ type, constr = constr.synthesize(arg.children[0])
3679
+ _, constr = constr.add_typing(arg, type: type)
3680
+ when :kwargs
3681
+ _, constr = constr.type_hash_record(arg, nil) || constr.type_hash(arg, hint: nil)
3682
+ else
3683
+ _, constr = constr.synthesize(arg)
3684
+ end
3685
+ end
3686
+
3687
+ constr
3688
+ end
3689
+
3476
3690
  def type_check_args(method_name, args, constraints, errors)
3477
3691
  # @type var constr: TypeConstruction
3478
3692
  constr = self
@@ -3588,10 +3802,10 @@ module Steep
3588
3802
  constr
3589
3803
  end
3590
3804
 
3591
- def try_method_type(node, receiver_type:, method_name:, method_type:, arguments:, block_params:, block_body:, tapp:)
3805
+ def try_method_type(node, receiver_type:, method_name:, method_type:, arguments:, block_params:, block_body:, tapp:, hint:)
3592
3806
  constr = self
3593
3807
 
3594
- if tapp && type_args = tapp.types?(module_context.nesting, checker.factory, [])
3808
+ if tapp && type_args = tapp.types?(module_context.nesting, checker, [])
3595
3809
  type_arity = method_type.type_params.size
3596
3810
  type_param_names = method_type.type_params.map(&:name)
3597
3811
 
@@ -3703,12 +3917,29 @@ module Steep
3703
3917
 
3704
3918
  if block_params
3705
3919
  # block is given
3920
+
3706
3921
  # @type var node: Parser::AST::Node & Parser::AST::_BlockNode
3707
3922
 
3708
3923
  block_annotations = source.annotations(block: node, factory: checker.factory, context: nesting)
3709
3924
  block_params_ = TypeInference::BlockParams.from_node(block_params, annotations: block_annotations)
3710
3925
 
3711
3926
  if method_type.block
3927
+ fvs = method_type.type.return_type.free_variables.each.with_object(Set[]) do |var, fvs| #$ Set[Symbol]
3928
+ if var.is_a?(Symbol)
3929
+ fvs << var
3930
+ end
3931
+ end
3932
+
3933
+ if hint && !fvs.empty?
3934
+ if check_relation(sub_type: method_type.type.return_type, super_type: hint, constraints: constraints).success?
3935
+ method_type, solved, s = apply_solution(errors, node: node, method_type: method_type) do
3936
+ constraints.solution(checker, variables: fvs, context: ccontext)
3937
+ end
3938
+ end
3939
+
3940
+ method_type.block or raise
3941
+ end
3942
+
3712
3943
  # Method accepts block
3713
3944
  pairs = block_params_&.zip(method_type.block.type.params, nil, factory: checker.factory)
3714
3945
 
@@ -3724,6 +3955,7 @@ module Steep
3724
3955
  block_self_hint: method_type.block.self_type,
3725
3956
  node_type_hint: method_type.type.return_type
3726
3957
  )
3958
+
3727
3959
  block_constr = block_constr.with_new_typing(
3728
3960
  block_constr.typing.new_child(block_constr.typing.block_range(node))
3729
3961
  )
@@ -3733,7 +3965,7 @@ module Steep
3733
3965
  pairs.each do |param, type|
3734
3966
  case param
3735
3967
  when TypeInference::BlockParams::Param
3736
- _, block_constr = block_constr.synthesize(param.node, hint: param.type || type).to_ary
3968
+ _, block_constr = block_constr.synthesize(param.node, hint: param.type || type)
3737
3969
 
3738
3970
  if param.type
3739
3971
  check_relation(sub_type: type, super_type: param.type, constraints: constraints).else do |result|
@@ -3748,7 +3980,7 @@ module Steep
3748
3980
  end
3749
3981
  when TypeInference::BlockParams::MultipleParam
3750
3982
  param.each_param do |p|
3751
- _, block_constr = block_constr.synthesize(p.node, hint: p.type || type).to_ary
3983
+ _, block_constr = block_constr.synthesize(p.node, hint: p.type || type)
3752
3984
 
3753
3985
  if p.type
3754
3986
  check_relation(sub_type: type, super_type: p.type, constraints: constraints).else do |result|
@@ -4154,6 +4386,7 @@ module Steep
4154
4386
  pins = context.type_env.pin_local_variables(nil)
4155
4387
 
4156
4388
  type_env = context.type_env
4389
+ type_env = type_env.invalidate_pure_node(Parser::AST::Node.new(:self)) if block_self_hint || block_annotations.self_type
4157
4390
  type_env = type_env.merge(local_variable_types: pins)
4158
4391
  type_env = type_env.merge(local_variable_types: param_types)
4159
4392
  type_env = TypeInference::TypeEnvBuilder.new(
@@ -4419,8 +4652,7 @@ module Steep
4419
4652
  end
4420
4653
 
4421
4654
  def unwrap(type)
4422
- truthy, _ = checker.factory.unwrap_optional(type)
4423
- truthy
4655
+ checker.factory.unwrap_optional(type) || AST::Types::Bot.new
4424
4656
  end
4425
4657
 
4426
4658
  def deep_expand_alias(type)
@@ -4490,7 +4722,7 @@ module Steep
4490
4722
  def try_tuple_type!(node, hint: nil)
4491
4723
  if node.type == :array
4492
4724
  if hint.nil? || hint.is_a?(AST::Types::Tuple)
4493
- node_range = node.loc.expression.yield_self {|l| l.begin_pos..l.end_pos }
4725
+ node_range = node.loc.expression.to_range
4494
4726
 
4495
4727
  typing.new_child(node_range) do |child_typing|
4496
4728
  if pair = with_new_typing(child_typing).try_tuple_type(node, hint)
@@ -4510,15 +4742,28 @@ module Steep
4510
4742
  element_types = [] #: Array[AST::Types::t]
4511
4743
 
4512
4744
  array_node.children.each_with_index do |child, index|
4513
- return if child.type == :splat
4514
-
4515
- child_hint =
4516
- if hint
4517
- hint.types[index]
4745
+ if child.type == :splat
4746
+ type, constr = constr.synthesize(child.children[0])
4747
+ typing.add_typing(child, type, nil)
4748
+ if converted_type = try_convert(type, :to_a)
4749
+ if converted_type.is_a?(AST::Types::Tuple)
4750
+ element_types.push(*converted_type.types)
4751
+ else
4752
+ # The converted_type may be an array, which cannot be used to construct a tuple type
4753
+ return
4754
+ end
4755
+ else
4756
+ element_types << type
4518
4757
  end
4758
+ else
4759
+ child_hint =
4760
+ if hint
4761
+ hint.types[index]
4762
+ end
4519
4763
 
4520
- type, constr = constr.synthesize(child, hint: child_hint)
4521
- element_types << type
4764
+ type, constr = constr.synthesize(child, hint: child_hint)
4765
+ element_types << type
4766
+ end
4522
4767
  end
4523
4768
 
4524
4769
  constr.add_typing(array_node, type: AST::Types::Tuple.new(types: element_types))