Skip to content

More informative error reporting from QuasiQuoters

Motivation

When a QuasiQuoter fails (calling fail), there are (essentially) two potential reasons:

  1. There is something wrong with part or all of the string it is asked to interpret.
  2. There is something wrong with the context it occurs in.

GHC's error highlighter assumes the first reason. For example, suppose

defaultQuasiQuoter :: QuasiQuoter
defaultQuasiQuoter = QuasiQuoter
  { quoteExp = f "use in expression contexts."
  , quotePat = f "use in pattern contexts."
  , quoteType = f "use in types."
  , quoteDec = f "creating declarations."
  }
  where
    f m _ = fail $ "This quasiquoter is not for " ++ m

If I write

f [defaultQuasiQuoter| whatever |] = 3

I get the error

Vest.hs:6:12: error:
    • This quasiquoter is not for use in pattern contexts.
    • In the quasi-quotation: [myPatQQ| Whatever |]
  |
6 | f [myPatQQ| Whatever |] = 3
  |            ^^^^^^^^^^^^

The error highlighting suggests that the problem is in Whatever, but in fact it is not.

Proposal

It would be nice to have a mechanism by which the QuasiQuoter can signal whether it's reporting an error with its argument or with its context. Where it's reporting an error with its argument, it would also be great if it could (optionally) indicate where in its argument string it encountered a problem. These argument strings can be extremely long, so just telling the user that the problem is "somewhere out that way" isn't very helpful. The options I can think of:

  1. Add appropriate methods to Quasi. This seems cleanest.
  2. Use the fact that Quasi is a subclass of MonadIO, letting particular thrown exception types represent these situations. This is pretty hideous, and doesn't deal nicely with recoverable errors.
To upload designs, you'll need to enable LFS and have an admin enable hashed storage. More information