Code below illustrates the problem:
enum E
Foo
Bar
Baz
end
case E::Foo
in .foo? then v = :foo
in .bar? then v = :bar
in .baz? then v = :baz
end
typeof(v) # => (Symbol | Nil) — Should be `Symbol`
Workaround (hat tip to @Blacksmoke16):
enum E
Foo
Bar
Baz
end
v = case E::Foo
in .foo? then :foo
in .bar? then :bar
in .baz? then :baz
end
typeof(v) # => Symbol
Her's the fix:
diff --git a/spec/compiler/semantic/cast_spec.cr b/spec/compiler/semantic/cast_spec.cr
index d9568c705..881d042ee 100644
--- a/spec/compiler/semantic/cast_spec.cr
+++ b/spec/compiler/semantic/cast_spec.cr
@@ -359,4 +359,14 @@ describe "Semantic: cast" do
x.foo if x
)) { nil_type }
end
+
+ it "considers else to be unreachable (#9658)" do
+ assert_type(%(
+ case 1
+ in Int32
+ v = 1
+ end
+ v
+ )) { int32 }
+ end
end
diff --git a/src/compiler/crystal/semantic/main_visitor.cr b/src/compiler/crystal/semantic/main_visitor.cr
index bf5ddb6bf..db8fb8d85 100644
--- a/src/compiler/crystal/semantic/main_visitor.cr
+++ b/src/compiler/crystal/semantic/main_visitor.cr
@@ -3165,6 +3165,7 @@ module Crystal
def visit(node : Unreachable)
node.type = @program.no_return
+ @unreachable = true
end
# # Helpers
Most helpful comment
Her's the fix: