steep 1.5.0.pre.4 → 1.5.0.pre.5
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 +4 -4
- data/CHANGELOG.md +7 -0
- data/Gemfile.lock +1 -1
- data/lib/steep/ast/types/factory.rb +1 -1
- data/lib/steep/diagnostic/ruby.rb +17 -1
- data/lib/steep/type_construction.rb +78 -25
- data/lib/steep/type_inference/context.rb +3 -1
- data/lib/steep/version.rb +1 -1
- data/sig/shims/parser/nodes.rbs +5 -0
- data/sig/steep/diagnostic/ruby.rbs +25 -0
- data/smoke/diagnostics/test_expectations.yml +0 -12
- data/smoke/type_case/test_expectations.yml +6 -6
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ed79428764aa83fbd2e7f3c5a8e52ff863b4e65bef05aae43ba9ca4b7c9d2f4e
|
4
|
+
data.tar.gz: be79772ce19f152e3048ae565802640cae96f1bfca98adf60eab47a28ab3ccad
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: aa071be8eaf425a2a36ffed4c8d0a97446997f9cbf85c9dc4190b5bf26c9bf5f66c7106ab27b96378d05e246a6327689ef491dedbd16ad7cb9eb8d8079b3818d
|
7
|
+
data.tar.gz: d7f842d51c84a2f48bdfd79a07de3e6265dd746497aa9661871f12b062832c2a24f46b37ce1ddb614ac5ba1c65f4c408e9e1eafec27fd69d7158514fe77e0fec
|
data/CHANGELOG.md
CHANGED
@@ -2,6 +2,13 @@
|
|
2
2
|
|
3
3
|
## master
|
4
4
|
|
5
|
+
## 1.5.0.pre.5 (2023-07-07)
|
6
|
+
|
7
|
+
### Type checker core
|
8
|
+
|
9
|
+
* Unreachability improvements ([#845](https://github.com/soutaro/steep/pull/845))
|
10
|
+
* Fix type inference problem ([#843](https://github.com/soutaro/steep/pull/843))
|
11
|
+
|
5
12
|
## 1.5.0.pre.4 (2023-07-06)
|
6
13
|
|
7
14
|
### Type checker core
|
data/Gemfile.lock
CHANGED
@@ -767,6 +767,19 @@ module Steep
|
|
767
767
|
end
|
768
768
|
end
|
769
769
|
|
770
|
+
class UnreachableValueBranch < Base
|
771
|
+
attr_reader :type
|
772
|
+
|
773
|
+
def initialize(node:, type:, location: node.location.expression)
|
774
|
+
super(node: node, location: location)
|
775
|
+
@type = type
|
776
|
+
end
|
777
|
+
|
778
|
+
def header_line
|
779
|
+
"The branch may evaluate to a value of `#{type}` but unreachable"
|
780
|
+
end
|
781
|
+
end
|
782
|
+
|
770
783
|
class UnexpectedSplat < Base
|
771
784
|
attr_reader :type
|
772
785
|
|
@@ -968,7 +981,8 @@ module Steep
|
|
968
981
|
{
|
969
982
|
ImplicitBreakValueMismatch => :warning,
|
970
983
|
FallbackAny => :information,
|
971
|
-
|
984
|
+
UnreachableValueBranch => :warning,
|
985
|
+
UnreachableBranch => :information,
|
972
986
|
UnknownConstant => :warning,
|
973
987
|
MethodDefinitionMissing => :information,
|
974
988
|
FalseAssertion => :information,
|
@@ -989,6 +1003,7 @@ module Steep
|
|
989
1003
|
NoMethod => nil,
|
990
1004
|
ImplicitBreakValueMismatch => nil,
|
991
1005
|
FallbackAny => nil,
|
1006
|
+
UnreachableValueBranch => nil,
|
992
1007
|
UnreachableBranch => nil,
|
993
1008
|
UnknownConstant => nil,
|
994
1009
|
MethodDefinitionMissing => nil,
|
@@ -1006,6 +1021,7 @@ module Steep
|
|
1006
1021
|
NoMethod => nil,
|
1007
1022
|
ImplicitBreakValueMismatch => nil,
|
1008
1023
|
FallbackAny => nil,
|
1024
|
+
UnreachableValueBranch => nil,
|
1009
1025
|
UnreachableBranch => nil,
|
1010
1026
|
UnknownConstant => nil,
|
1011
1027
|
MethodDefinitionMissing => nil,
|
@@ -1883,9 +1883,25 @@ module Steep
|
|
1883
1883
|
|
1884
1884
|
if truthy.unreachable
|
1885
1885
|
if true_clause
|
1886
|
+
_, _, _, loc = deconstruct_if_node!(node)
|
1887
|
+
|
1888
|
+
if loc.respond_to?(:keyword)
|
1889
|
+
condition_loc = loc #: NodeHelper::condition_loc
|
1890
|
+
case condition_loc.keyword.source
|
1891
|
+
when "if"
|
1892
|
+
location = condition_loc.begin || condition_loc.keyword
|
1893
|
+
when "unless"
|
1894
|
+
# `else` token always exists
|
1895
|
+
location = condition_loc.else || raise
|
1896
|
+
end
|
1897
|
+
else
|
1898
|
+
location = true_clause.loc.expression
|
1899
|
+
end
|
1900
|
+
|
1886
1901
|
typing.add_error(
|
1887
1902
|
Diagnostic::Ruby::UnreachableBranch.new(
|
1888
|
-
node: true_clause
|
1903
|
+
node: true_clause,
|
1904
|
+
location: location || raise
|
1889
1905
|
)
|
1890
1906
|
)
|
1891
1907
|
end
|
@@ -1893,9 +1909,25 @@ module Steep
|
|
1893
1909
|
|
1894
1910
|
if falsy.unreachable
|
1895
1911
|
if false_clause
|
1912
|
+
_, _, _, loc = deconstruct_if_node!(node)
|
1913
|
+
|
1914
|
+
if loc.respond_to?(:keyword)
|
1915
|
+
condition_loc = loc #: NodeHelper::condition_loc
|
1916
|
+
case condition_loc.keyword.source
|
1917
|
+
when "if"
|
1918
|
+
# `else` token always exists
|
1919
|
+
location = condition_loc.else || raise
|
1920
|
+
when "unless"
|
1921
|
+
location = condition_loc.begin || condition_loc.keyword
|
1922
|
+
end
|
1923
|
+
else
|
1924
|
+
location = false_clause.loc.expression
|
1925
|
+
end
|
1926
|
+
|
1896
1927
|
typing.add_error(
|
1897
1928
|
Diagnostic::Ruby::UnreachableBranch.new(
|
1898
|
-
node: false_clause
|
1929
|
+
node: false_clause,
|
1930
|
+
location: location || raise
|
1899
1931
|
)
|
1900
1932
|
)
|
1901
1933
|
end
|
@@ -1961,19 +1993,25 @@ module Steep
|
|
1961
1993
|
next_branch_reachable &&= false_branch_reachable
|
1962
1994
|
body_constr = when_constr.update_type_env {|env| env.join(*test_envs) }
|
1963
1995
|
|
1964
|
-
|
1965
|
-
|
1996
|
+
branch_result =
|
1997
|
+
if body
|
1966
1998
|
body_constr
|
1967
1999
|
.for_branch(body)
|
1968
2000
|
.tap {|constr| typing.add_context_for_node(body, context: constr.context) }
|
1969
2001
|
.synthesize(body, hint: hint)
|
1970
|
-
|
1971
|
-
|
1972
|
-
|
2002
|
+
else
|
2003
|
+
Pair.new(type: AST::Builtin.nil_type, constr: body_constr)
|
2004
|
+
end
|
1973
2005
|
|
1974
|
-
|
2006
|
+
branch_results << branch_result
|
2007
|
+
|
2008
|
+
if !branch_reachable && !branch_result.type.is_a?(AST::Types::Bot)
|
1975
2009
|
typing.add_error(
|
1976
|
-
Diagnostic::Ruby::
|
2010
|
+
Diagnostic::Ruby::UnreachableValueBranch.new(
|
2011
|
+
node: clause,
|
2012
|
+
type: branch_result.type,
|
2013
|
+
location: clause.location.keyword
|
2014
|
+
)
|
1977
2015
|
)
|
1978
2016
|
end
|
1979
2017
|
|
@@ -2004,9 +2042,14 @@ module Steep
|
|
2004
2042
|
# `else` may present even if it's empty
|
2005
2043
|
if loc.else
|
2006
2044
|
if els
|
2007
|
-
|
2008
|
-
|
2009
|
-
|
2045
|
+
else_result or raise
|
2046
|
+
unless else_result.type.is_a?(AST::Types::Bot)
|
2047
|
+
typing.add_error Diagnostic::Ruby::UnreachableValueBranch.new(
|
2048
|
+
node: els,
|
2049
|
+
type: else_result.type,
|
2050
|
+
location: node.loc.else || raise
|
2051
|
+
)
|
2052
|
+
end
|
2010
2053
|
end
|
2011
2054
|
end
|
2012
2055
|
else
|
@@ -2042,21 +2085,29 @@ module Steep
|
|
2042
2085
|
branch_reachable ||= !truthy.unreachable
|
2043
2086
|
end
|
2044
2087
|
|
2045
|
-
|
2046
|
-
|
2088
|
+
branch_result =
|
2089
|
+
if body
|
2047
2090
|
when_clause_constr
|
2048
2091
|
.for_branch(body)
|
2049
2092
|
.update_type_env {|env| env.join(*body_envs) }
|
2050
2093
|
.tap {|constr| typing.add_context_for_node(body, context: constr.context) }
|
2051
2094
|
.synthesize(body, hint: hint)
|
2052
|
-
|
2053
|
-
|
2054
|
-
|
2095
|
+
else
|
2096
|
+
Pair.new(type: AST::Builtin.nil_type, constr: when_clause_constr)
|
2097
|
+
end
|
2098
|
+
|
2099
|
+
branch_results << branch_result
|
2055
2100
|
|
2056
2101
|
unless branch_reachable
|
2057
|
-
|
2058
|
-
|
2059
|
-
|
2102
|
+
unless branch_result.type.is_a?(AST::Types::Bot)
|
2103
|
+
typing.add_error(
|
2104
|
+
Diagnostic::Ruby::UnreachableValueBranch.new(
|
2105
|
+
node: when_clause,
|
2106
|
+
type: branch_result.type,
|
2107
|
+
location: when_clause.location.keyword || raise
|
2108
|
+
)
|
2109
|
+
)
|
2110
|
+
end
|
2060
2111
|
end
|
2061
2112
|
end
|
2062
2113
|
|
@@ -3913,13 +3964,15 @@ module Steep
|
|
3913
3964
|
end
|
3914
3965
|
|
3915
3966
|
if hint && !fvs.empty?
|
3916
|
-
if
|
3917
|
-
|
3918
|
-
|
3967
|
+
if hint.free_variables.subset?(self_type.free_variables)
|
3968
|
+
if check_relation(sub_type: method_type.type.return_type, super_type: hint, constraints: constraints).success?
|
3969
|
+
method_type, solved, s = apply_solution(errors, node: node, method_type: method_type) do
|
3970
|
+
constraints.solution(checker, variables: fvs, context: ccontext)
|
3971
|
+
end
|
3919
3972
|
end
|
3920
|
-
end
|
3921
3973
|
|
3922
|
-
|
3974
|
+
method_type.block or raise
|
3975
|
+
end
|
3923
3976
|
end
|
3924
3977
|
|
3925
3978
|
# Method accepts block
|
@@ -126,7 +126,9 @@ module Steep
|
|
126
126
|
|
127
127
|
def upper_bounds
|
128
128
|
table.each_value.with_object({}) do |type_param, bounds|
|
129
|
-
|
129
|
+
if type_param.upper_bound
|
130
|
+
bounds[type_param.name] = type_param.upper_bound
|
131
|
+
end
|
130
132
|
end
|
131
133
|
end
|
132
134
|
|
data/lib/steep/version.rb
CHANGED
data/sig/shims/parser/nodes.rbs
CHANGED
@@ -479,6 +479,31 @@ module Steep
|
|
479
479
|
def header_line: () -> String
|
480
480
|
end
|
481
481
|
|
482
|
+
# The branch is unreachable, but not `bot` type
|
483
|
+
#
|
484
|
+
# We often have `else` branch to make the code more defensive:
|
485
|
+
#
|
486
|
+
# ```ruby
|
487
|
+
# case value
|
488
|
+
# when Integer
|
489
|
+
# # ...
|
490
|
+
# when String
|
491
|
+
# # ...
|
492
|
+
# else
|
493
|
+
# raise "Cannot happen!"
|
494
|
+
# end
|
495
|
+
# ```
|
496
|
+
#
|
497
|
+
# This diagnostic allows writing `raise` or `return`, by checking the type of the branch body is `bot` or not.
|
498
|
+
#
|
499
|
+
class UnreachableValueBranch < Base
|
500
|
+
attr_reader type: AST::Types::t
|
501
|
+
|
502
|
+
def initialize: (node: Parser::AST::Node, type: AST::Types::t, ?location: location) -> void
|
503
|
+
|
504
|
+
def header_line: () -> String
|
505
|
+
end
|
506
|
+
|
482
507
|
class UnexpectedSplat < Base
|
483
508
|
attr_reader type: untyped
|
484
509
|
|
@@ -120,18 +120,6 @@
|
|
120
120
|
message: 'The method parameter has different kind from the declaration `(name:
|
121
121
|
::String, size: ::Integer) -> void`'
|
122
122
|
code: Ruby::DifferentMethodParameterKind
|
123
|
-
- file: else_on_exhaustive_case.rb
|
124
|
-
diagnostics:
|
125
|
-
- range:
|
126
|
-
start:
|
127
|
-
line: 11
|
128
|
-
character: 2
|
129
|
-
end:
|
130
|
-
line: 11
|
131
|
-
character: 26
|
132
|
-
severity: ERROR
|
133
|
-
message: The branch is unreachable
|
134
|
-
code: Ruby::UnreachableBranch
|
135
123
|
- file: incompatible_annotation.rb
|
136
124
|
diagnostics:
|
137
125
|
- range:
|
@@ -13,14 +13,14 @@
|
|
13
13
|
code: Ruby::NoMethod
|
14
14
|
- range:
|
15
15
|
start:
|
16
|
-
line:
|
17
|
-
character:
|
16
|
+
line: 11
|
17
|
+
character: 0
|
18
18
|
end:
|
19
|
-
line:
|
20
|
-
character:
|
19
|
+
line: 11
|
20
|
+
character: 4
|
21
21
|
severity: ERROR
|
22
|
-
message: The branch
|
23
|
-
code: Ruby::
|
22
|
+
message: The branch may evaluate to a value of `untyped` but unreachable
|
23
|
+
code: Ruby::UnreachableValueBranch
|
24
24
|
- range:
|
25
25
|
start:
|
26
26
|
line: 12
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: steep
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.5.0.pre.
|
4
|
+
version: 1.5.0.pre.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Soutaro Matsumoto
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-07-
|
11
|
+
date: 2023-07-07 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: parser
|