Error and Warning Messages practical migration guidelines

Alfredo Di Napoli alfredo.dinapoli at gmail.com
Sat Apr 3 07:17:23 UTC 2021


*TL;DR If you recently had merge conflicts related to error and
messages in GHC, here I give migration guidelines. Otherwise,
feel free to ignore this email.*


Good morning all,

If you had some work-in-progress branch that was emitting errors or
warnings (either adding new ones or modifying existing
ones), chances are you noticed that now the API and types changed
slightly and you had to deal with the conflicts. What
you noticed was the initial chunk of work for [#18516]. See the [Wiki]
for more info.

Our work is not done yet, but the API changed enough to warrant me
writing this little email to help folks out
with their rebasing (because we are *all* rebasing at least daily,
aren't we? :) ).

First of all, sorry for all the churning! I am trying to stabilise the
external interfaces (i.e the type signatures
of the GHC API functions) so things will become a bit more stable in the future.

In the meantime, I wanted to give you some practical guidelines on how
to migrate your code:

* Rather than "errors" or "warnings", we are trying to shift our
vocabulary to talk about "diagnostics". In
  GHC this distinction is not so "strict", in the sense warnings can
become errors and errors can become warnings
  if deferred. Rather we talk about diagnostics, i.e. facts about the
compiled program, that can be, at the very end,
  classified as errors or warnings based on their `Severity`;

* *If you skip this whole email, read just this:* the key insight is
that there is a clear separation between the *reason*
  this diagnostic was created and the final `Severity`! Example: we
emit a diagnostic because `Opt_WarnMonomorphism` is
  on. That's the raison d'ĂȘtre of this diagnostic. Therefore, we would
create a new message (more on this later) with
  reason `WarningWithFlag Opt_WarnMonomorphism`;

* A `Severity` of a diagnostic is computed using the `DynFlags`,
because that's the only way to correctly classify
  a diagnostic. Back to our little example above, if
`Opt_WarnMonomorphism` was set as fatal (or -Werror enabled), now
  the final `Severity` of the diagnostic above would be `SevError`.
That's why it's important to keep them separate;

* We separated out the logging messages with the diagnostics proper,
this is why we now have a new [MessageClass]
  type which can be used to log all sort of messages (debug ones,
informational etc) *and* diagnostics, which has
  a dedicated type constructor;

* If you want to emit something which is not an error or a warning,
use [putLogMsg].
  Here is an example:
https://gitlab.haskell.org/ghc/ghc/-/blob/master/compiler/GHC/Core/Lint.hs#L402
(we could
  argue if the example shouldn't be a diagnostic, but we didn't go
that far in the refactoring yet, this is just
  to give you an idea of the usage);

* The most general function which can be used to produce a diagnostic
is [mkMsgEnvelope], which takes as
  input the `DynFlags` to compute the `Severity` under the hood.

* You can't just pass a random `DynFlags` to `mkMsgEnvelope`, but the
former should be acquired as close as possible
  to the construction/emission site of the diagnostics. This is
because `DynFlags` evolves and are mangled all the time
  inside GHC, and we want to produce the `Severity` using the most
faithful "snapshot" of the state of the world at the
  time the diagnostic was produced.

* Most of the times you don't have to worry about all of this; if you
know for sure a diagnostic is an error and is
  not recoverable, then you can use `mkMsgErrorEnvelope` that doesn't
need the `DynFlags` and always produces a diagnostic
  with `SevError` and `ErrorWithoutFlags`.

* Once #18516 will be completed, this will require a bit less
cognitive overhead. We will have proper types (not SDocs
  or generic `DecoratedMessage`s), and all the working GHC hacker will
have to worry about would be to create a brand new
  Haskell type for the diagnostic, give it a `Diagnostic` instance (or
extend the instance declaration if that's an
  existing type) and then just call whichever high-level API we will
have available.


Hope this helps!


Alfredo


[#18516]: https://gitlab.haskell.org/ghc/ghc/-/issues/18516
[Wiki]: https://gitlab.haskell.org/ghc/ghc/-/wikis/Errors-as-(structured)-values
[MessageClass]:
https://gitlab.haskell.org/ghc/ghc/-/blob/master/compiler/GHC/Types/Error.hs#L209
[putLogMsg]: https://gitlab.haskell.org/ghc/ghc/-/blob/master/compiler/GHC/Utils/Logger.hs#L128
[mkMsgEnvelope]:
https://gitlab.haskell.org/ghc/ghc/-/blob/master/compiler/GHC/Utils/Error.hs#L116
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.haskell.org/pipermail/ghc-devs/attachments/20210403/1e848535/attachment.html>


More information about the ghc-devs mailing list