Documentation

Elaborator.Expressions

Bidirectional expression checking: checkExpr (Γ ⊢ e ⇓ τ) and inferExpr (Γ ⊢ e ⇑ τ), turning a CoreTLAPlus.Expression (Option TypedTLAPlus.Typ) (binder annotations still the optional, user-written ones) into a TypedTLAPlus.Expression TypedTLAPlus.Typ (every binder now a resolved type). Each case carries the rule it implements as a comment: premises over a bar over the conclusion, tagged [Rule Name].

A few constructs synthesize only in certain cases:

Out of scope, with no CoreTLAPlus.Expression constructor to match on: LAMBDA, LET-IN, weak/strong fairness (WF_/SF_), non-stuttering ⟨A⟩_e, and temporal operators generally. UNCHANGED/ENABLED/prime '/~>/-+>/[]/<> desugar to plain operator calls, covered by the generic OPERATOR CALL rule once the builtin table gives each one a Γ entry. Only stutter ([A]_e) is a real constructor with its own case.

EXCEPT supports an arbitrary-length path of record-field/index steps per update ([f EXCEPT ![1].x[2] = v]), implemented as one general recursive walk (stepInto/checkExceptPath below) rather than one case per path length.

Polymorphism instantiation happens once, at [Var] below, not at OPERATOR CALL: a reference to a scheme Γ binding (Elaborator/Monad.lean's Binding.isScheme — a top-level operator/function definition, not an ordinary binder) freshens every distinct Typ.var in its type into its own metavariable (specializeType, Elaborator/TypeUtils.lean) right there, whether or not that reference is later called. OPERATOR CALL just checks arguments against the callee's already-specialized type, resolving those metavariables incrementally through Elaborator/Subtyping.lean's direction-aware solving.

@[reducible, inline]
abbrev SrcExpr :

The checker's actual input: CoreTLAPlus.Expression at α := Option Typ, every binder's annotation still the optional, user-written one rather than a resolved type.

Equations
Instances For

    Indexing e[e'] where e's own type τ is already known — the shared core of function call/sequence access/tuple access. CoreTLAPlus.Expression.fnCall is a single constructor covering all three, so which rule applies is a runtime dispatch on τ's own shape.

    One EXCEPT path step (a path is a List (String ⊕ SrcExpr): .inl a record field, .inr an index) applied to an already-known type τ.

    The general EXCEPT path walk — recurses on the path, threading the type through each step via stepInto, and returns the type the final new value must be checked against alongside the elaborated (unchanged-shape) path.

    Γ ⊢ e ⇓ τ — see the module doc for exactly which constructs get a dedicated checking rule here versus falling to the generic [Subtype] fallback (everything else, including checking-mode use of every purely-synthesis rule inferExpr implements).

    Γ ⊢ e ⇑ τ — see the module doc for the precise checking/synthesis split.