Skip to content

Instantly share code, notes, and snippets.

@julien-h
Last active December 19, 2016 20:16
Show Gist options
  • Save julien-h/2fc52e8cf702ad0b53ad5e9d6ec38560 to your computer and use it in GitHub Desktop.
Save julien-h/2fc52e8cf702ad0b53ad5e9d6ec38560 to your computer and use it in GitHub Desktop.
Some thoughts about designing a clean error signaling process that will lead to useful error messages.

I thought a lot about compilers these past few days. One challenge that arises in the front-end is to provide the user with useful error messages: where the error was detected, where it occured, how to fix it, etc.

Don't put it in the middle of the source code

The common pratice in compilers that I know is to use a reporter to signal the error. The reporter is provider with an error string and is expected to display it to the user. So we have user-facing formatted strings in the source code :-(

For instance, this snippet is from llvm's lexer:

if (NumBits < IntegerType::MIN_INT_BITS ||
        NumBits > IntegerType::MAX_INT_BITS) {
      Error("bitwidth for integer type out of range!");
      return lltok::Error;
}

[source] lexer: https://github.com/llvm-mirror/llvm/blob/master/lib/AsmParser/LLLexer.cpp

and this snippet was found in the scala compiler:

if (settings.warnUnsoundMatch && unsoundAssumptionUsed)
    reporter.warning(pat.pos,
    sm"""The value matched by $pat is bound to ${binder.name}, which may be used under the
      |unsound assumption that it has type ${pat.tpe}, whereas we can only safely
      |count on it having type $pt, as the pattern is matched using `==` (see SI-1503).""")

    pat.tpe
}

[source] match analysis: https://github.com/scala/scala/blob/2.12.x/src/compiler/scala/tools/nsc/transform/patmat/MatchAnalysis.scala

Use objects

Now, another approach would be to have an object for each possible error. By localizing the objects in the same file or directory, we would have a list of existing errors, and it would be easy to modify them all at once. This also keeps the code clean, and, more importantly we can provide as much information as needed while creating the object, even if it's not displayed (for now) to the user.

For instance:

if (settings.warnUnsoundMatch && unsoundAssumptionUsed)
    reporter.signal(new SI1503(pat, binder, pt))
    pat.tpe
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment