Crystal: Variable defined in all branches of exhaustive case is still nil-able

Created on 3 Aug 2020  Â·  1Comment  Â·  Source: crystal-lang/crystal

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`

https://carc.in/#/r/9hqa


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

https://carc.in/#/r/9hqo

Most helpful comment

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

>All comments

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
Was this page helpful?
0 / 5 - 0 ratings

Related issues

nabeelomer picture nabeelomer  Â·  3Comments

asterite picture asterite  Â·  3Comments

grosser picture grosser  Â·  3Comments

cjgajard picture cjgajard  Â·  3Comments

asterite picture asterite  Â·  3Comments