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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: cfb1de89ec50042cf06306ab17717671e8b6a8451ea2885b4af8085226f7994e
4
- data.tar.gz: 1b67eb25821061afe42c8c4dd644b30370e866ac9ef8066cb77031799c981145
3
+ metadata.gz: ed79428764aa83fbd2e7f3c5a8e52ff863b4e65bef05aae43ba9ca4b7c9d2f4e
4
+ data.tar.gz: be79772ce19f152e3048ae565802640cae96f1bfca98adf60eab47a28ab3ccad
5
5
  SHA512:
6
- metadata.gz: 1f0b3400822be747c45ed1d5c2cdfbddf8c0fdf70963061b66308464a18a95e493cc94ad406bbc444f618f562e0f95f276600c27e3ec2269f01504727b0528c7
7
- data.tar.gz: 45b2a32802ea5ab504a8c3ee04f714a87b27227ffa66282d64243e3161aa0628001f1925e3ad7aaf09fcd0fbddc4def36e9b9940c76a87b195c2f51b19006bf9
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
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- steep (1.5.0.pre.4)
4
+ steep (1.5.0.pre.5)
5
5
  activesupport (>= 5.1)
6
6
  concurrent-ruby (>= 1.1.10)
7
7
  csv (>= 3.0.9)
@@ -204,7 +204,7 @@ module Steep
204
204
  when Logic::Base
205
205
  RBS::Types::Bases::Bool.new(location: type.location)
206
206
  else
207
- __skip__ = raise "Unexpected type given: #{type} (#{type.class})"
207
+ raise "Unexpected type given: #{type} (#{type.class})"
208
208
  end
209
209
  end
210
210
 
@@ -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
- UnreachableBranch => :warning,
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 || node
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 || node
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
- if body
1965
- branch_results <<
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
- else
1971
- branch_results << Pair.new(type: AST::Builtin.nil_type, constr: body_constr)
1972
- end
2002
+ else
2003
+ Pair.new(type: AST::Builtin.nil_type, constr: body_constr)
2004
+ end
1973
2005
 
1974
- unless branch_reachable
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::UnreachableBranch.new(node: body || clause)
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
- typing.add_error Diagnostic::Ruby::UnreachableBranch.new(node: els)
2008
- else
2009
- typing.add_error Diagnostic::Ruby::UnreachableBranch.new(node: node, location: loc.else)
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
- if body
2046
- branch_results <<
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
- else
2053
- branch_results << Pair.new(type: AST::Builtin.nil_type, constr: when_clause_constr)
2054
- end
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
- typing.add_error(
2058
- Diagnostic::Ruby::UnreachableBranch.new(node: body || when_clause)
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 check_relation(sub_type: method_type.type.return_type, super_type: hint, constraints: constraints).success?
3917
- method_type, solved, s = apply_solution(errors, node: node, method_type: method_type) do
3918
- constraints.solution(checker, variables: fvs, context: ccontext)
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
- method_type.block or raise
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
- bounds[type_param.name] = type_param.upper_bound
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
@@ -1,3 +1,3 @@
1
1
  module Steep
2
- VERSION = "1.5.0.pre.4"
2
+ VERSION = "1.5.0.pre.5"
3
3
  end
@@ -62,6 +62,11 @@ module Parser
62
62
  %a{pure} def end: () -> Source::Range?
63
63
  end
64
64
 
65
+ # ```ruby
66
+ # foo ? bar : baz
67
+ # # ^ question
68
+ # # ^ colon
69
+ # ```
65
70
  interface _Ternary
66
71
  %a{pure} def question: () -> Source::Range
67
72
 
@@ -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: 12
17
- character: 2
16
+ line: 11
17
+ character: 0
18
18
  end:
19
- line: 12
20
- character: 10
19
+ line: 11
20
+ character: 4
21
21
  severity: ERROR
22
- message: The branch is unreachable
23
- code: Ruby::UnreachableBranch
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
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-06 00:00:00.000000000 Z
11
+ date: 2023-07-07 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: parser