# 1.cr
require "option_parser"
module Translater
enum Browser
Firefox
end
browser = Browser::Firefox
OptionParser.parse do |parser|
parser.on(
"-b BROWSER",
"--browser=BROWSER",
"Specify browser used for scrap, only support firefox for now, default is firefox.
") do |b|
browser = Browser.parse?(b)
if browser.nil?
STDERR.puts "Supported options: #{Browser.names.map(&.downcase).join ", "}"
exit 1
end
end
end
case browser # Translater::Browser | Nil
in Browser::Firefox
puts "Firefox"
end
end
In src/1.cr:25:3
25 | case browser # Translater::Browser | Nil
^
Error: case is not exhaustive.
Missing cases:
- Nil
the browser in line 25 case statement is never be nil, right?
Maybe have double check, because if it never execute this block, probably it’s possible you value is Nil without know it.
I never use option_parser personnaly.
I think as well about something else: the error say it’s not exhaustive. Actually the enum you made only enum one type. Maybe it’s the main problem here. Can you try to add an another value to your enum ?
The compiler is unable to proof that due to complications with the closure context. browser = Browser.parse?(b) assigns a nilable value. Even if that nilable value afterwards leads to a different code path that never reaches the case statement, it requires the closured variable browser to be nilable.
What you can do to avoid this is not assign the nilable return value from Browser.parse?(b) directly to browser. Instead, use a non-closured local variable and only assign it to the closured browser when the Nil type is eliminated.
If never execute this block, browser value is enum Browser::Firefox, in fact, this issue not involve with OptionParser, add a new enum value, result is same.
No, it’s definitely nilable because you assign a value that’s Browser | Nil. And it can actually have the value nil when Browser.parse? does not find a match. Between the assignment of browser = Browser.parse?(b) and exit 1, it’s nil. Since the assignment happens in a captured block (of parser.on), it’s not easy to disprove that at the point case browser runs, the proc might be exactly in this spot where browser is nil in a different fiber.
Theoretically, the compiler could maybe become sophisticated enough to figure this out. But I’m not sure if it’s feasible. Definitely not an easy feature to implement.
This is certainly not a bug, though.
What if the block actually runs inside a spawn and between it gets assigned nil and exiting the block fiber switch happens? Then outside the block it will be nil.