Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

9. Errors and diagnostics

9.1 The diagnostic model

Every problem Korrin reports is a diagnostic: a stable error code, a one-line message, one or more labelled spans of source, and optional notes and a help line. Diagnostics are produced by four stages — lexer, parser, resolver, interpreter — and rendered the same way regardless of origin (ADR 0008).

9.2 Stability of codes

Once a code is assigned a meaning it keeps it forever. Wording may improve; the code–meaning mapping does not change. New codes are appended. The authoritative list is the ErrorCode enum in crates/korrin/src/diagnostics.rs; this section is its prose companion.

9.3 When does a program stop?

  • Lexer and parser errors are collected — one mistake does not hide the rest — and reported together. The program does not run.
  • Resolver errors are all reported in one pass. The program does not run.
  • A runtime fault raises an exception (§9.6). If a try catches it (§5.10), the program continues; otherwise it stops at that point, and output written before then has already been produced.

9.4 Codes

Lexical — E00xx

CodeMeaning
E0001A character that cannot begin any token (includes a lone !).
E0002A string literal with no closing " before the end of the line.
E0003A \ escape that Korrin does not define.
E0004A malformed number literal (1.2.3, 10abc).
E0005A number literal outside the range of its type.
E0006A tab character in a line's leading indentation.
E0007A dedent to a column that matches no enclosing block.
E0008An opening (, [, or { with no matching close.

Syntax — E01xx

CodeMeaning
E0101A token where the grammar does not allow it (includes a chained comparison).
E0102A required token (:, ), in, a name, end of line, …) was missing.
E0103An expression was required and none was found.
E0104The left side of = is not a name, attribute, or index.
E0105(reserved) An indented block with no statements.
E0106A for header not of the form for NAME in EXPR:.
E0107A try with neither except nor finally, or a dangling except / finally.

Static — E02xx

CodeMeaning
E0201return outside any function.
E0202break outside any loop.
E0203continue outside any loop.
E0204(reserved — self is an ordinary name)
E0205super outside any method.
E0206super in a class with no parent.
E0207Two parameters of one function share a name.
E0208A class names itself as its own parent.

Runtime — E03xx

CodeMeaning
E0301Read of a name with no binding in scope.
E0302Call of a value that is not a function or class.
E0303A call with the wrong number of arguments.
E0304An operator, builtin, or method got a value of the wrong type.
E0305Integer or float division/modulo by zero.
E0306An integer operation overflowed the 64-bit range.
E0307A list or string index outside its bounds (includes list.pop / list.remove_at / list.insert out of range).
E0308Indexing a value that does not support it.
E0309Access of an attribute a value does not have (an unknown instance field/method, or an unknown method on str / list / map).
E0310A map[key] lookup for an absent key.
E0311A value that is not hashable used as a map key.
E0312An exception (raised value or built-in fault) reached the top level uncaught.
E0313Function-call nesting exceeded the interpreter's recursion limit.

9.6 Exceptions

A runtime fault is an exception: it unwinds until a try (§5.10) catches it, or it reaches the top level as E0312.

Catching. except NAME: binds the exception to NAME. What NAME holds depends on how the exception arose:

  • A built-in fault (E0301E0313) is bound as an Error value with .message (the diagnostic's text) and .code (its "E03xx" string).
  • A raised value is bound as-israise 42 binds 42, raise "x" binds "x", raise Error("x") binds that Error.

The Error type. Error is a built-in name bound in every program. Error(message?) constructs an instance with:

  • .message — the argument's display form, or "error" if none was given;
  • .codenil (a program-created error has no diagnostic code).

type(Error("x")) is "Error".

e = Error("out of range")
print(e.message)
print(e.code)
print(type(e))
# => out of range
# => nil
# => Error

Uncaught. An exception with no enclosing try prints an E0312 diagnostic pointing at the raise (or the faulting expression) and the program exits non-zero. An uncaught Error shows its .message; any other value shows as uncaught: <repr>.

try:
    value = {"a": 1}["b"]
except err:
    print("{err.code}")
# => E0310

9.5 Examples

x = 1 + undefined_name
# error: E0301
fn f(a, a):
    return a
# error: E0207
print(10 % 0)
# error: E0305