steep 1.5.0.pre.4 → 1.5.0.pre.5
Sign up to get free protection for your applications and to get access to all the features.
- 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
|