crystal
crystal copied to clipboard
Add detail to errors involving automatic casting of symbols
cc @straight-shoota
When a user calls a function which autocasts a symbol literal as an enum and the symbol name doesn't exist:
enum Foo
Bar
Baz
Quux
end
def foo(arg : Foo)
end
foo(:far) # :far doesn't exist in Foo
The error message is unhelpful, and while it does address the fact that foo()
doesn't work with Symbol
, it doesn't detect the automatic casting:
Error in line 10: no overload matches 'foo' with type Symbol
Overloads are:
- foo(arg : Foo)
An extra portion could be added onto the end of this error, listing possible typos that the user may have entered:
Do you mean:
- :bar (Foo::Bar)
- :gar (FooAgain::Gar)
@asterite I saw the source code of autocasting and I assume it could be easy to raise proper error in this case? Also please consider def foo(arg : Foo | String)
case (i.e. with union argument where Enum is a part of this union). Usecase: https://carc.in/#/r/6er7 (need better error here)
This is actually a bit hard to implement. The above only considers a method with a single argument. What happens if you have multiple arguments? For example:
enum Foo
Bar
Baz
Quux
end
def foo(x : String, arg : Foo)
end
foo(1, :far)
Right now you get:
Error in foo.cr:10: no overload matches 'foo' with types Int32, Symbol
Overloads are:
- foo(x : String, arg : Foo)
foo(1, :far)
^~~
But what, should it also say that the symbol won't match, and list all possible values? What happens if there are multiple arguments that need to be autocast? Should this be shown below the Overloads list?
Removing symbols and using :foo
notation only as symbol shorthand would allow this, I think the correct discussion of that is #6736.
But what, should it also say that the symbol won't match, and list all possible values?
If the argument to be autocast is the first one that fails an overload match, yes, otherwise some other error will be shown as part of #11106. Say:
enum Foo
Bar
end
def foo(x : Int32, y : Foo); end
# Error: no overload matches
# Note: failed to match argument #2 against parameter `y : Foo`
# Did you mean `:bar`?
foo(1, :bat)
# Error: no overload matches
# Note: failed to match argument #1 against parameter `x : Int32`
foo("", :bat)