error-messages icon indicating copy to clipboard operation
error-messages copied to clipboard

Better error message for out of scope data constructor if a type with the same name exists

Open noughtmare opened this issue 2 years ago • 2 comments

Inspired by this stackoverflow question,

I imagine a common mistake newcomers make when learning about pattern matching is that they use the name of the type instead of the name of constructors. I guess especially people coming from C-style languages are used to the prefix Typename x way of writing function arguments. I think we can detect this case and save them the trouble of turning to a book or the internet for help.

In particular, I'd propose to add a check for the not in scope error for data constructors. If the identifier does match a valid type, then we can suggest that perhaps the user meant to use a constructor of that type. We could list all possible constructors (limited to 5 if there are too many perhaps).

The problematic code in the stackoverflow question is this:

data Mood = Blah | Woot

instance Show Mood where
    show(Mood x) = "Mood: " ++ show(x)

Currently GHC produces the message:

T7.hs:4:10: error: Not in scope: data constructor ‘Mood’
  |
4 |     show(Mood x) = "Mood: " ++ show(x)
  |          ^^^^

I'd propose:

T7.hs:4:10: error: Not in scope: data constructor ‘Mood’
    Perhaps you intended to pattern match on the type ‘Mood’
    For that you can use its data constructors: ‘Blah’, ‘Woot’
  |
4 |     show(Mood x) = "Mood: " ++ show(x)
  |          ^^^^

noughtmare avatar Oct 31 '22 08:10 noughtmare

Actually, now I'm also thinking that we can suggest possible constructors if we know the type of the thing we're matching against. That would be similar to the valid hole fits suggestions.

In particular, here we know that this show has type show :: Mood -> String, so we can suggest the constructors of Mood as possible things to match against:

T7.hs:4:10: error: Not in scope: data constructor ‘Mood’
    Possible data constructors of the type ‘Mood’ are: ‘Blah’, ‘Woot’
  |
4 |     show(Mood x) = "Mood: " ++ show(x)
  |          ^^^^

noughtmare avatar Oct 31 '22 09:10 noughtmare

I like the idea of using types, but I prefer the wording of the original message, with "Perhaps you intended to pattern match" (but I'd finish with "against a value of type 'Mood'", but maybe that's too long?) or maybe "Perhaps you want to match against constructors from 'Mood'"? In any case, I like the gentle correction.

goldfirere avatar Nov 11 '22 19:11 goldfirere