Are there plans for exhaustiveness checks on case with enums?

Given the following code:

enum BasicColor
    Red,
    Green,
    Blue
end

def max_out(color : BasicColor) : String
    case color
    when BasicColor::Red then "#ff0000"
    when BasicColor::Green then "#00ff00"
    when BasicColor::Blue then "#0000ff"
    end
end

puts max_out(BasicColor::Red)

Currently, you get this error:

Error: method must return String but it is returning (String | Nil)

This of course makes no sense, because you annotated the method param as exactly BasicColor (not BasicColor?), and you handled all the cases, returning a non-nilable String in every case. But because there’s no else case that returns a String (even though such a case would be unreachable), the compiler complains.

In short, the compiler is not aware that our case statement is exhaustive.

Is this something that’s on the roadmap for Crystal, or is it deemed out of scope for the compiler itself?

1 Like

I think I have seen a few PRs on this. Have you tried this code in 0.32.1?

The PR is still open https://github.com/crystal-lang/crystal/pull/8424.

For now you can just do like

def max_out(color : BasicColor) : String
    case color
    when BasicColor::Red then "#ff0000"
    when BasicColor::Green then "#00ff00"
    when BasicColor::Blue then "#0000ff"
    end.not_nil!
end
1 Like

Yes, this feature is definitely planned to come, see #8001, but not yet available.

As a workaround for the time being, it is recommended to add an else raise "unreachable" branch to the case.

1 Like

Ah, that’s exciting to hear! Thanks for the quick responses, too!