steep 0.24.0 → 0.25.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3fc0de639f659b9b59f83ca0f8968550e7230ee1dbb6ae8e0d005325267ab46e
4
- data.tar.gz: a1f73b521a222fa1313c2f58b1e0d3fb2a07149aba42c17e91c8df495e3319de
3
+ metadata.gz: c290301da65ed473b092cd6c2ea39eebe02f566124a1fa32e0f420d290513cbf
4
+ data.tar.gz: ca4fca20e9f3f0b19c57b98d6cdfce0023aeeff8cd0fcd2ee0fc91346e5e0816
5
5
  SHA512:
6
- metadata.gz: bcedd630c3b51bc4d3a24549c6bcde88156af410be2b64ec51d813c238f3cb5d5f9f85b980302cae3cacd007e478ae51f99019ed10f3b6a31df84723bd43f35b
7
- data.tar.gz: da09a3c3e7f762ec48b378533b6c624c1b9590a0cfd58ffc7aed87212fde2c67897bc1aa745eaa8f4baeaa19b1e6c7b0a4826e7fb6e582a6ef6798ee3b4a47a4
6
+ metadata.gz: 76c3b0c76e303bcc558bf20efeebe3ddaa3caef432f5d325261261f6d8431f5bbd36bc44af9a4a4dd6a90f2db30ac35ca044181b25063890c0e68c5499d7792c
7
+ data.tar.gz: a5fa8fba718f599806d9d0ad62a66c138261469d41694bb39ebafe1b8736ad255e890c55f0e3b4f180f4e0212f0b65b31b5957b5c337cba42d1129b9e935e577
@@ -2,6 +2,14 @@
2
2
 
3
3
  ## master
4
4
 
5
+ ## 0.25.0 (2020-08-18)
6
+
7
+ * Improve `op_send` typing ([#186](https://github.com/soutaro/steep/pull/186))
8
+ * Improve `op_asgn` typing ([#189](https://github.com/soutaro/steep/pull/189))
9
+ * Better multi-assignment support ([#183](https://github.com/soutaro/steep/pull/183), [#184](https://github.com/soutaro/steep/pull/184))
10
+ * Support for loop and class variables ([#182](https://github.com/soutaro/steep/pull/182))
11
+ * Fix tuple typing ([#181](https://github.com/soutaro/steep/pull/181))
12
+
5
13
  ## 0.24.0 (2020-08-11)
6
14
 
7
15
  * Update RBS to 0.10 ([#180](https://github.com/soutaro/steep/pull/180))
@@ -29,7 +29,10 @@ module Steep
29
29
  type
30
30
  end
31
31
  end.compact.uniq.yield_self do |tys|
32
- if tys.length == 1
32
+ case tys.length
33
+ when 0
34
+ AST::Types::Bot.new
35
+ when 1
33
36
  tys.first
34
37
  else
35
38
  new(types: tys.sort_by(&:hash), location: location)
@@ -60,6 +60,10 @@ module Steep
60
60
  Steep.log_error source_file.status.error
61
61
  end
62
62
  end
63
+ when Project::Target::SignatureOtherErrorStatus
64
+ Steep.log_error status.error
65
+ else
66
+ Steep.logger.error { "Unexpected status: #{status.class}" }
63
67
  end
64
68
  end
65
69
  end
@@ -172,6 +172,7 @@ module Steep
172
172
  timestamp: Time.now
173
173
  )
174
174
  rescue => exn
175
+ Steep.log_error exn
175
176
  @status = SignatureOtherErrorStatus.new(error: exn, timestamp: Time.now)
176
177
  end
177
178
  end
@@ -194,8 +195,10 @@ module Steep
194
195
  type_check_sources = []
195
196
 
196
197
  target_sources.each do |file|
197
- if file.type_check(check, timestamp)
198
- type_check_sources << file
198
+ Steep.logger.tagged("path=#{file.path}") do
199
+ if file.type_check(check, timestamp)
200
+ type_check_sources << file
201
+ end
199
202
  end
200
203
  end
201
204
 
@@ -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
@@ -318,16 +318,17 @@ module Steep
318
318
  trace: trace)
319
319
  end
320
320
 
321
- when relation.sub_type.is_a?(AST::Types::Tuple) && relation.super_type.is_a?(AST::Types::Name::Base)
322
- tuple_interface = factory.interface(relation.sub_type, private: false)
323
- type_interface = factory.interface(relation.super_type, private: false)
321
+ when relation.sub_type.is_a?(AST::Types::Tuple) && AST::Builtin::Array.instance_type?(relation.super_type)
322
+ tuple_element_type = AST::Types::Union.build(
323
+ types: relation.sub_type.types,
324
+ location: relation.sub_type.location
325
+ )
324
326
 
325
- check_interface(tuple_interface,
326
- type_interface,
327
- self_type: self_type,
328
- assumption: assumption,
329
- trace: trace,
330
- constraints: constraints)
327
+ check(Relation.new(sub_type: tuple_element_type, super_type: relation.super_type.args[0]),
328
+ self_type: self_type,
329
+ assumption: assumption,
330
+ trace: trace,
331
+ constraints: constraints)
331
332
 
332
333
  when relation.sub_type.is_a?(AST::Types::Record) && relation.super_type.is_a?(AST::Types::Record)
333
334
  if Set.new(relation.sub_type.elements.keys).superset?(Set.new(relation.super_type.elements.keys))
@@ -744,6 +744,23 @@ module Steep
744
744
 
745
745
  constr.add_typing(node, type: type)
746
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
+
747
764
  else
748
765
  Steep.logger.error("Unexpected op_asgn lhs: #{lhs.type}")
749
766
 
@@ -811,7 +828,7 @@ module Steep
811
828
  new.typing.add_context_for_body(node, context: new.context)
812
829
 
813
830
  each_child_node(args_node) do |arg|
814
- new.synthesize(arg)
831
+ _, new = new.synthesize(arg)
815
832
  end
816
833
 
817
834
  body_pair = if body_node
@@ -999,11 +1016,17 @@ module Steep
999
1016
  yield_self do
1000
1017
  var = node.children[0]
1001
1018
  type = context.lvar_env[var.name]
1002
- unless type
1019
+
1020
+ if type
1021
+ add_typing(node, type: type)
1022
+ else
1003
1023
  type = AST::Builtin.any_type
1004
- 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)
1005
1029
  end
1006
- add_typing(node, type: type)
1007
1030
  end
1008
1031
 
1009
1032
  when :optarg, :kwoptarg
@@ -1034,7 +1057,9 @@ module Steep
1034
1057
  var = node.children[0]
1035
1058
  type = context.lvar_env[var.name]
1036
1059
  unless type
1037
- Steep.logger.error { "Unknown variable: #{node}" }
1060
+ if context&.method_context&.method_type
1061
+ Steep.logger.error { "Unknown variable: #{node}" }
1062
+ end
1038
1063
  typing.add_error Errors::FallbackAny.new(node: node)
1039
1064
  type = AST::Builtin::Array.instance_type(AST::Builtin.any_type)
1040
1065
  end
@@ -1047,7 +1072,9 @@ module Steep
1047
1072
  var = node.children[0]
1048
1073
  type = context.lvar_env[var.name]
1049
1074
  unless type
1050
- Steep.logger.error { "Unknown variable: #{node}" }
1075
+ if context&.method_context&.method_type
1076
+ Steep.logger.error { "Unknown variable: #{node}" }
1077
+ end
1051
1078
  typing.add_error Errors::FallbackAny.new(node: node)
1052
1079
  type = AST::Builtin::Hash.instance_type(AST::Builtin::Symbol.instance_type, AST::Builtin.any_type)
1053
1080
  end
@@ -1301,69 +1328,45 @@ module Steep
1301
1328
  when :array
1302
1329
  yield_self do
1303
1330
  if node.children.empty?
1304
- typing.add_error Errors::FallbackAny.new(node: node) unless hint
1305
-
1306
- array_type = if hint
1307
- if check_relation(sub_type: AST::Builtin::Array.instance_type(AST::Builtin.any_type),
1308
- super_type: hint).success?
1309
- hint
1310
- end
1311
- end
1312
-
1313
- add_typing(node, type: array_type || AST::Builtin::Array.instance_type(AST::Builtin.any_type))
1314
- else
1315
- is_tuple = nil
1316
-
1317
- expand_alias(hint) do |hint|
1318
- is_tuple = hint.is_a?(AST::Types::Tuple)
1319
- is_tuple &&= node.children.all? {|child| child.type != :splat}
1320
- is_tuple &&= node.children.size >= hint.types.size
1321
- is_tuple &&= hint.types.map.with_index do |child_type, index|
1322
- child_node = node.children[index]
1323
- [synthesize(child_node, hint: child_type).type, child_type]
1324
- end.all? do |node_type, hint_type|
1325
- result = check_relation(sub_type: node_type, super_type: hint_type)
1326
- 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
1327
1337
  end
1328
- end
1329
-
1330
- if is_tuple
1331
- array_type = hint
1332
1338
  else
1333
- element_hint = expand_alias(hint) do |hint|
1334
- 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
1335
1354
  end
1355
+ end
1336
1356
 
1337
- element_types = node.children.flat_map do |e|
1338
- if e.type == :splat
1339
- Steep.logger.info "Typing of splat in array is incompatible with Ruby; it does not use #to_a method"
1340
- synthesize(e.children.first).type.yield_self do |type|
1341
- expand_alias(type) do |ty|
1342
- case ty
1343
- when AST::Types::Union
1344
- ty.types
1345
- else
1346
- [ty]
1347
- end
1348
- end
1349
- end.map do |type|
1350
- case
1351
- when AST::Builtin::Array.instance_type?(type)
1352
- type.args.first
1353
- when AST::Builtin::Range.instance_type?(type)
1354
- type.args.first
1355
- else
1356
- type
1357
- 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))
1358
1364
  end
1359
- else
1360
- [select_super_type(synthesize(e, hint: element_hint).type, element_hint)]
1361
1365
  end
1362
1366
  end
1363
- array_type = AST::Builtin::Array.instance_type(AST::Types::Union.build(types: element_types))
1364
1367
  end
1365
1368
 
1366
- add_typing(node, type: array_type)
1369
+ try_array_type(node, nil)
1367
1370
  end
1368
1371
  end
1369
1372
 
@@ -1672,6 +1675,49 @@ module Steep
1672
1675
  when :masgn
1673
1676
  type_masgn(node)
1674
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
1675
1721
  when :while, :until
1676
1722
  yield_self do
1677
1723
  cond, body = node.children
@@ -1753,9 +1799,15 @@ module Steep
1753
1799
 
1754
1800
  when :or_asgn, :and_asgn
1755
1801
  yield_self do
1756
- _, rhs = node.children
1757
- rhs_type = synthesize(rhs).type
1758
- add_typing(node, type: rhs_type)
1802
+ asgn, rhs = node.children
1803
+ type, constr = synthesize(rhs, hint: hint)
1804
+
1805
+ case asgn.type
1806
+ when :lvasgn
1807
+ constr.lvasgn(asgn, type)
1808
+ when :ivasgn
1809
+ constr.ivasgn(asgn, type)
1810
+ end
1759
1811
  end
1760
1812
 
1761
1813
  when :defined?
@@ -1831,9 +1883,50 @@ module Steep
1831
1883
  add_typing node, type: AST::Builtin.any_type
1832
1884
  end
1833
1885
 
1834
- when :splat, :sclass, :alias
1886
+ when :cvasgn
1887
+ name, rhs = node.children
1888
+
1889
+ type, constr = synthesize(rhs, hint: hint)
1890
+
1891
+ var_type = if module_context&.class_variables
1892
+ module_context.class_variables[name]&.yield_self {|ty| checker.factory.type(ty) }
1893
+ end
1894
+
1895
+ if var_type
1896
+ result = constr.check_relation(sub_type: type, super_type: var_type)
1897
+
1898
+ if result.success?
1899
+ add_typing node, type: type, constr: constr
1900
+ else
1901
+ fallback_to_any node do
1902
+ Errors::IncompatibleAssignment.new(node: node,
1903
+ lhs_type: var_type,
1904
+ rhs_type: type,
1905
+ result: result)
1906
+ end
1907
+ end
1908
+ else
1909
+ fallback_to_any(node)
1910
+ end
1911
+
1912
+ when :cvar
1913
+ name = node.children[0]
1914
+ var_type = if module_context&.class_variables
1915
+ module_context.class_variables[name]&.yield_self {|ty| checker.factory.type(ty) }
1916
+ end
1917
+
1918
+ if var_type
1919
+ add_typing node, type: var_type
1920
+ else
1921
+ fallback_to_any node
1922
+ end
1923
+
1924
+ when :alias
1925
+ add_typing node, type: AST::Builtin.nil_type
1926
+
1927
+ when :splat
1835
1928
  yield_self do
1836
- Steep.logger.error "Unsupported node #{node.type} (#{node.location.expression.source_buffer.name}:#{node.location.expression.line})"
1929
+ Steep.logger.warn { "Unsupported node #{node.type} (#{node.location.expression.source_buffer.name}:#{node.location.expression.line})" }
1837
1930
 
1838
1931
  each_child_node node do |child|
1839
1932
  synthesize(child)
@@ -1883,136 +1976,202 @@ module Steep
1883
1976
  add_typing(node, type: ivar_type)
1884
1977
  end
1885
1978
 
1979
+ def masgn_lhs?(lhs)
1980
+ lhs.children.all? do |a|
1981
+ asgn_type = if a.type == :splat
1982
+ a.children[0].type
1983
+ else
1984
+ a.type
1985
+ end
1986
+ asgn_type == :lvasgn || asgn_type == :ivasgn
1987
+ end
1988
+ end
1989
+
1990
+ def lvasgn(node, type)
1991
+ name = node.children[0].name
1992
+ env = context.lvar_env.assign(name, node: node, type: type) do |declared_type, type, result|
1993
+ typing.add_error(
1994
+ Errors::IncompatibleAssignment.new(node: node,
1995
+ lhs_type: declared_type,
1996
+ rhs_type: type,
1997
+ result: result)
1998
+ )
1999
+ end
2000
+
2001
+ add_typing(node, type: type, constr: with_updated_context(lvar_env: env))
2002
+ end
2003
+
2004
+ def ivasgn(node, type)
2005
+ ivar = node.children[0]
2006
+
2007
+ type_env.assign(ivar: ivar, type: type, self_type: self_type) do |error|
2008
+ case error
2009
+ when Subtyping::Result::Failure
2010
+ var_type = type_env.get(ivar: ivar)
2011
+ typing.add_error(Errors::IncompatibleAssignment.new(node: node,
2012
+ lhs_type: var_type,
2013
+ rhs_type: type,
2014
+ result: error))
2015
+ when nil
2016
+ fallback_to_any node
2017
+ end
2018
+ end
2019
+
2020
+ add_typing(node, type: type)
2021
+ end
2022
+
1886
2023
  def type_masgn(node)
1887
2024
  lhs, rhs = node.children
1888
2025
  rhs_pair = synthesize(rhs)
1889
- rhs_type = expand_alias(rhs_pair.type)
2026
+ rhs_type = deep_expand_alias(rhs_pair.type)
1890
2027
 
1891
2028
  constr = rhs_pair.constr
1892
2029
 
1893
- if lhs.children.all? {|a| a.type == :lvasgn || a.type == :ivasgn}
1894
- case
1895
- when rhs.type == :array && lhs.children.size == rhs.children.size
1896
- # a, @b = x, y
2030
+ unless masgn_lhs?(lhs)
2031
+ Steep.logger.error("Unsupported masgn lhs node: only lvasgn, ivasgn, and splat are supported")
2032
+ _, constr = constr.fallback_to_any(lhs)
2033
+ return add_typing(node, type: rhs_type, constr: constr)
2034
+ end
1897
2035
 
1898
- constr = lhs.children.zip(rhs.children).inject(constr) do |ctr, (lhs, rhs)|
1899
- case lhs.type
1900
- when :lvasgn
1901
- name = lhs.children[0].name
1902
- type = typing.type_of(node: rhs)
1903
- env = ctr.context.lvar_env.assign(name, node: node, type: type) do |declared_type, type, result|
1904
- typing.add_error(
1905
- Errors::IncompatibleAssignment.new(node: lhs,
1906
- lhs_type: declared_type,
1907
- rhs_type: type,
1908
- result: result)
1909
- )
1910
- end
1911
- add_typing(lhs,
1912
- type: type,
1913
- constr: ctr.with_updated_context(lvar_env: env))
1914
- when :ivasgn
1915
- type_ivasgn(lhs.children.first, rhs, lhs)
1916
- constr
1917
- end
2036
+ falseys, truthys = partition_flatten_types(rhs_type) do |type|
2037
+ type.is_a?(AST::Types::Nil) || (type.is_a?(AST::Types::Literal) && type.value == false)
2038
+ end
2039
+
2040
+ unwrap_rhs_type = AST::Types::Union.build(types: truthys)
2041
+
2042
+ case
2043
+ when unwrap_rhs_type.is_a?(AST::Types::Tuple) || (rhs.type == :array && rhs.children.none? {|n| n.type == :splat })
2044
+ tuple_types = if unwrap_rhs_type.is_a?(AST::Types::Tuple)
2045
+ unwrap_rhs_type.types.dup
2046
+ else
2047
+ rhs.children.map do |node|
2048
+ typing.type_of(node: node)
2049
+ end
2050
+ end
2051
+
2052
+ assignment_nodes = lhs.children.dup
2053
+ leading_assignments = []
2054
+ trailing_assignments = []
2055
+
2056
+ until assignment_nodes.empty?
2057
+ cursor = assignment_nodes.first
2058
+
2059
+ if cursor.type == :splat
2060
+ break
2061
+ else
2062
+ leading_assignments << assignment_nodes.shift
1918
2063
  end
2064
+ end
1919
2065
 
1920
- add_typing(node, type: rhs_type, constr: constr)
2066
+ until assignment_nodes.empty?
2067
+ cursor = assignment_nodes.last
1921
2068
 
1922
- when rhs_type.is_a?(AST::Types::Tuple)
1923
- # a, @b = tuple
2069
+ if cursor.type == :splat
2070
+ break
2071
+ else
2072
+ trailing_assignments.unshift assignment_nodes.pop
2073
+ end
2074
+ end
1924
2075
 
1925
- constr = lhs.children.zip(rhs_type.types).inject(constr) do |ctr, (lhs, type)|
1926
- ty = type || AST::Builtin.nil_type
2076
+ leading_assignments.each do |asgn|
2077
+ type = tuple_types.first
1927
2078
 
1928
- case lhs.type
1929
- when :lvasgn
1930
- name = lhs.children[0].name
1931
- env = ctr.context.lvar_env.assign(name, node: node, type: ty) do |declared_type, type, result|
1932
- typing.add_error(
1933
- Errors::IncompatibleAssignment.new(node: lhs,
1934
- lhs_type: declared_type,
1935
- rhs_type: type,
1936
- result: result)
1937
- )
1938
- end
1939
- add_typing(lhs,
1940
- type: ty,
1941
- constr: ctr.with_updated_context(lvar_env: env)).constr
1942
- when :ivasgn
1943
- ivar = lhs.children[0]
2079
+ if type
2080
+ tuple_types.shift
2081
+ else
2082
+ type = AST::Builtin.nil_type
2083
+ end
1944
2084
 
1945
- type_env.assign(ivar: ivar, type: ty, self_type: self_type) do |error|
1946
- case error
1947
- when Subtyping::Result::Failure
1948
- ivar_type = type_env.get(ivar: ivar)
1949
- typing.add_error(Errors::IncompatibleAssignment.new(node: lhs,
1950
- lhs_type: ivar_type,
1951
- rhs_type: ty,
1952
- result: error))
1953
- when nil
1954
- fallback_to_any node
1955
- end
1956
- end
2085
+ case asgn.type
2086
+ when :lvasgn
2087
+ _, constr = constr.lvasgn(asgn, type)
2088
+ when :ivasgn
2089
+ _, constr = constr.ivasgn(asgn, type)
2090
+ end
2091
+ end
1957
2092
 
1958
- ctr
1959
- end
2093
+ trailing_assignments.reverse_each do |asgn|
2094
+ type = tuple_types.last
2095
+
2096
+ if type
2097
+ tuple_types.pop
2098
+ else
2099
+ type = AST::Builtin.nil_type
1960
2100
  end
1961
2101
 
1962
- add_typing(node, type: rhs_type, constr: constr)
2102
+ case asgn.type
2103
+ when :lvasgn
2104
+ _, constr = constr.lvasgn(asgn, type)
2105
+ when :ivasgn
2106
+ _, constr = constr.ivasgn(asgn, type)
2107
+ end
2108
+ end
1963
2109
 
1964
- when AST::Builtin::Array.instance_type?(rhs_type)
1965
- element_type = AST::Types::Union.build(types: [rhs_type.args.first, AST::Builtin.nil_type])
2110
+ element_type = if tuple_types.empty?
2111
+ AST::Builtin.nil_type
2112
+ else
2113
+ AST::Types::Union.build(types: tuple_types)
2114
+ end
2115
+ array_type = AST::Builtin::Array.instance_type(element_type)
1966
2116
 
1967
- constr = lhs.children.inject(constr) do |ctr, assignment|
1968
- case assignment.type
2117
+ assignment_nodes.each do |asgn|
2118
+ case asgn.type
2119
+ when :splat
2120
+ case asgn.children[0].type
1969
2121
  when :lvasgn
1970
- name = assignment.children[0].name
1971
- env = ctr.context.lvar_env.assign(name, node: node, type: element_type) do |declared_type, type, result|
1972
- typing.add_error(
1973
- Errors::IncompatibleAssignment.new(node: assignment,
1974
- lhs_type: declared_type,
1975
- rhs_type: type,
1976
- result: result)
1977
- )
1978
- end
2122
+ _, constr = constr.lvasgn(asgn.children[0], array_type)
2123
+ when :ivasgn
2124
+ _, constr = constr.ivasgn(asgn.children[0], array_type)
2125
+ end
2126
+ when :lvasgn
2127
+ _, constr = constr.lvasgn(asgn, element_type)
2128
+ when :ivasgn
2129
+ _,constr = constr.ivasgn(asgn, element_type)
2130
+ end
2131
+ end
1979
2132
 
1980
- add_typing(assignment,
1981
- type: element_type,
1982
- constr: ctr.with_updated_context(lvar_env: env)).constr
2133
+ unless falseys.empty?
2134
+ constr = constr.update_lvar_env {|lvar_env| self.context.lvar_env.join(lvar_env, self.context.lvar_env)}
2135
+ end
1983
2136
 
1984
- when :ivasgn
1985
- ivar = assignment.children[0]
2137
+ add_typing(node, type: rhs_type, constr: constr)
1986
2138
 
1987
- type_env.assign(ivar: ivar, type: element_type, self_type: self_type) do |error|
1988
- case error
1989
- when Subtyping::Result::Failure
1990
- type = type_env.get(ivar: ivar)
1991
- typing.add_error(Errors::IncompatibleAssignment.new(node: assignment,
1992
- lhs_type: type,
1993
- rhs_type: element_type,
1994
- result: error))
1995
- when nil
1996
- fallback_to_any node
1997
- end
1998
- end
2139
+ when flatten_union(unwrap_rhs_type).all? {|type| AST::Builtin::Array.instance_type?(type) }
2140
+ array_elements = flatten_union(unwrap_rhs_type).map {|type| type.args[0] }
2141
+ element_type = AST::Types::Union.build(types: array_elements + [AST::Builtin.nil_type])
2142
+
2143
+ constr = lhs.children.inject(constr) do |constr, assignment|
2144
+ case assignment.type
2145
+ when :lvasgn
2146
+ _, constr = constr.lvasgn(assignment, element_type)
1999
2147
 
2000
- ctr
2148
+ when :ivasgn
2149
+ _, constr = constr.ivasgn(assignment, element_type)
2150
+ when :splat
2151
+ case assignment.children[0].type
2152
+ when :lvasgn
2153
+ _, constr = constr.lvasgn(assignment.children[0], unwrap_rhs_type)
2154
+ when :ivasgn
2155
+ _, constr = constr.ivasgn(assignment.children[0], unwrap_rhs_type)
2156
+ else
2157
+ raise
2001
2158
  end
2002
2159
  end
2003
2160
 
2004
- add_typing node, type: rhs_type, constr: constr
2005
-
2006
- when rhs_type.is_a?(AST::Types::Any)
2007
- fallback_to_any(node)
2161
+ constr
2162
+ end
2008
2163
 
2009
- else
2010
- Steep.logger.error("Unsupported masgn: #{rhs.type} (#{rhs_type})")
2011
- fallback_to_any(node)
2164
+ unless falseys.empty?
2165
+ constr = constr.update_lvar_env {|lvar_env| self.context.lvar_env.join(lvar_env, self.context.lvar_env)}
2012
2166
  end
2167
+
2168
+ add_typing(node, type: rhs_type, constr: constr)
2013
2169
  else
2014
- Steep.logger.error("Unsupported masgn left hand side")
2015
- fallback_to_any(node)
2170
+ unless rhs_type.is_a?(AST::Types::Any)
2171
+ Steep.logger.error("Unsupported masgn rhs type: array or tuple is supported (#{rhs_type})")
2172
+ end
2173
+ _, constr = constr.fallback_to_any(lhs)
2174
+ add_typing(node, type: rhs_type, constr: constr)
2016
2175
  end
2017
2176
  end
2018
2177
 
@@ -2063,7 +2222,7 @@ module Steep
2063
2222
  else
2064
2223
  case expanded_receiver_type = expand_self(receiver_type)
2065
2224
  when AST::Types::Self
2066
- Steep.logger.error "`self` type cannot be resolved to concrete type"
2225
+ Steep.logger.debug { "`self` type cannot be resolved to concrete type" }
2067
2226
  fallback_to_any node do
2068
2227
  Errors::NoMethod.new(node: node, method: method_name, type: receiver_type)
2069
2228
  end
@@ -3006,7 +3165,12 @@ module Steep
3006
3165
 
3007
3166
  ty = case type
3008
3167
  when AST::Types::Name::Alias
3009
- deep_expand_alias(expand_alias(type), recursive: recursive << type)
3168
+ deep_expand_alias(expand_alias(type), recursive: recursive.union([type]))
3169
+ when AST::Types::Union
3170
+ AST::Types::Union.build(
3171
+ types: type.types.map {|ty| deep_expand_alias(ty, recursive: recursive, &block) },
3172
+ location: type.location
3173
+ )
3010
3174
  else
3011
3175
  type
3012
3176
  end
@@ -3018,6 +3182,37 @@ module Steep
3018
3182
  end
3019
3183
  end
3020
3184
 
3185
+ def flatten_union(type, acc = [])
3186
+ case type
3187
+ when AST::Types::Union
3188
+ type.types.each {|ty| flatten_union(ty, acc) }
3189
+ else
3190
+ acc << type
3191
+ end
3192
+
3193
+ acc
3194
+ end
3195
+
3196
+ def select_flatten_types(type, &block)
3197
+ types = flatten_union(deep_expand_alias(type))
3198
+ types.select(&block)
3199
+ end
3200
+
3201
+ def partition_flatten_types(type, &block)
3202
+ types = flatten_union(deep_expand_alias(type))
3203
+ types.partition(&block)
3204
+ end
3205
+
3206
+ def flatten_array_elements(type)
3207
+ flatten_union(deep_expand_alias(type)).flat_map do |type|
3208
+ if AST::Builtin::Array.instance_type?(type)
3209
+ type.args
3210
+ else
3211
+ [type]
3212
+ end
3213
+ end
3214
+ end
3215
+
3021
3216
  def expand_alias(type, &block)
3022
3217
  checker.factory.expand_alias(type, &block)
3023
3218
  end
@@ -3065,6 +3260,47 @@ module Steep
3065
3260
  AST::Types::Name::Instance.new(name: type.name, args: args)
3066
3261
  end
3067
3262
 
3263
+ def try_tuple_type(node, hint)
3264
+ if node.children.size != hint.types.size
3265
+ return
3266
+ end
3267
+
3268
+ constr = self
3269
+ element_types = []
3270
+
3271
+ each_child_node(node).with_index do |child, index|
3272
+ type, constr = constr.synthesize(child, hint: hint.types[index])
3273
+ element_types << type
3274
+ end
3275
+
3276
+ constr.add_typing(node, type: AST::Types::Tuple.new(types: element_types))
3277
+ end
3278
+
3279
+ def try_array_type(node, hint)
3280
+ element_hint = hint ? hint.args[0] : nil
3281
+
3282
+ constr = self
3283
+ element_types = []
3284
+
3285
+ each_child_node(node) do |child|
3286
+ case child.type
3287
+ when :splat
3288
+ type, constr = constr.synthesize(child.children[0], hint: hint)
3289
+ if AST::Builtin::Array.instance_type?(type)
3290
+ element_types << type.args[0]
3291
+ else
3292
+ element_types.push(*flatten_array_elements(type))
3293
+ end
3294
+ else
3295
+ type, constr = constr.synthesize(child, hint: element_hint)
3296
+ element_types << type
3297
+ end
3298
+ end
3299
+
3300
+ element_type = AST::Types::Union.build(types: element_types)
3301
+ constr.add_typing(node, type: AST::Builtin::Array.instance_type(element_type))
3302
+ end
3303
+
3068
3304
  def try_hash_type(node, hint)
3069
3305
  case hint
3070
3306
  when AST::Types::Record
@@ -26,7 +26,7 @@ module Steep
26
26
  factory.type(constant.type)
27
27
  end
28
28
  rescue => exn
29
- Steep.logger.error "Looking up a constant failed: name=#{name}, context=[#{context.join(", ")}], error=#{exn.inspect}"
29
+ Steep.logger.debug "Looking up a constant failed: name=#{name}, context=[#{context.join(", ")}], error=#{exn.inspect}"
30
30
  nil
31
31
  end
32
32
  end
@@ -70,6 +70,14 @@ module Steep
70
70
  def const_context
71
71
  const_env.context
72
72
  end
73
+
74
+ def class_variables
75
+ if module_definition
76
+ @class_variables ||= module_definition.class_variables.transform_values do |var_def|
77
+ var_def.type
78
+ end
79
+ end
80
+ end
73
81
  end
74
82
 
75
83
  attr_reader :method_context
@@ -35,12 +35,13 @@ module Steep
35
35
 
36
36
  def insert_context(range, context:, entry: self.root)
37
37
  entry.sub_entries.each do |sub|
38
- next if sub.range.begin < range.begin && range.end <= sub.range.end
39
- next if range.begin < sub.range.begin && sub.range.end <= range.end
38
+ next if sub.range.begin <= range.begin && range.end <= sub.range.end
39
+ next if range.begin <= sub.range.begin && sub.range.end <= range.end
40
40
  next if range.end <= sub.range.begin
41
41
  next if sub.range.end <= range.begin
42
42
 
43
- raise "Range crossing: sub range=#{sub.range}, new range=#{range}"
43
+ Steep.logger.error { "Range crossing: sub range=#{sub.range}, new range=#{range}" }
44
+ raise
44
45
  end
45
46
 
46
47
  sup = entry.sub_entries.find do |sub|
@@ -47,6 +47,37 @@ module Steep
47
47
  f.merge([node])
48
48
  ]
49
49
 
50
+ when :masgn
51
+ lhs, rhs = node.children
52
+
53
+ lt, lf = nodes(node: lhs)
54
+ rt, rf = nodes(node: rhs)
55
+
56
+ [
57
+ (lt + rt).merge([node]),
58
+ (lf + rf).merge([node])
59
+ ]
60
+
61
+ when :mlhs
62
+ nodes = [node]
63
+
64
+ node.children.each do |child|
65
+ case child.type
66
+ when :lvasgn
67
+ nodes << child
68
+ when :splat
69
+ if node.children[0].type == :lvasgn
70
+ nodes << child
71
+ nodes << child.children[0]
72
+ end
73
+ end
74
+ end
75
+
76
+ [
77
+ Result.new(nodes),
78
+ Result.new(nodes)
79
+ ]
80
+
50
81
  when :and
51
82
  lhs, rhs = node.children
52
83
 
@@ -126,6 +126,13 @@ module Steep
126
126
  end_pos = node.loc.end.begin_pos
127
127
  add_context(begin_pos..end_pos, context: context)
128
128
 
129
+ when :for
130
+ _, collection, _ = node.children
131
+
132
+ begin_pos = collection.loc.expression.end_pos
133
+ end_pos = node.loc.end.begin_pos
134
+
135
+ add_context(begin_pos..end_pos, context: context)
129
136
  else
130
137
  raise "Unexpected node for insert_context: #{node.type}"
131
138
  end
@@ -1,3 +1,3 @@
1
1
  module Steep
2
- VERSION = "0.24.0"
2
+ VERSION = "0.25.0"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: steep
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.24.0
4
+ version: 0.25.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Soutaro Matsumoto
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2020-08-10 00:00:00.000000000 Z
11
+ date: 2020-08-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: parser