Laurel User Guide

3.1. Resolution in practice🔗

The rest of this section states the typing rules precisely. In everyday use they come down to a short list, and a front end that respects these will rarely be surprised:

  • literals synthesize their primitive type; a local synthesizes its declared type;

  • a field synthesizes its declared type after looking the receiver up by its static type;

  • an assignment checks its right-hand side against the target's type, and yields that type;

  • a declaration extends only the enclosing block's scope;

  • a call checks arguments against the declared inputs and synthesizes the output type;

  • a multi-output call has an internal multi-value type and must be unpacked with assign;

  • an if checks both branches against the expected type when there is one, and otherwise joins the two synthesized branch types;

  • a block's last item carries the block's value;

  • loop conditions, invariants, and contract clauses check against bool;

  • arithmetic needs operands of one compatible numeric type — there are no implicit numeric promotions;

  • equality needs consistent operand types; is and as need related types;

  • return e checks e against the sole declared output;

  • names and types are pre-registered, so declaration order does not matter.

When a rule fails, resolution substitutes an internal unresolved or Unknown node so that one mistake does not cascade into a list of derived errors. Compilation stops before any analysis runs if a real diagnostic remains.