Documentation

Core.ComputableTLAPlus.Coercion

Coercion.applyComputable is the second of Core/TypedTLAPlus/Coercion.lean's two structural recursions over TypedTLAPlus.Coercion, discharging against ComputableTLAPlus.Expression instead of TypedTLAPlus.Expression. Needed because a receive's channel/reference coercion is stored unapplied and survives past Typed2Computable's type change: Guarded2Network is the first pass with a concrete ComputableTLAPlus.Expression (the built Head(inbox)/Tail(inbox) expression) to discharge it against, so it can't reuse Coercion.apply (fixed at TypedTLAPlus.Expr).

Mirrors Coercion.apply case-for-case, except choose's domain here is a required Expression α rather than Option (Expression α) — see Core/ComputableTLAPlus/Syntax.lean's module doc.

@[reducible, inline]

Checked TLA⁺ expressions at ComputableTLAPlus's output type — what Coercion.applyComputable transforms.

Equations
Instances For
    @[irreducible]

    Applies a coercion to an already-built ComputableTLAPlus.Expression — see the module doc above for why this can't reuse Coercion.apply. Registers every synthesized node at the coerced expression's own span, for the reason spelled out on Coercion.apply.

    Equations
    Instances For

      Coercion.applyComputable and free variables #

      freeVars_applyComputable_subset — a coercion adds no free variable — lives here rather than next to the semantics: it needs Coercion.applyComputable's induction principle, generated only in this module. The small mem_freeVars_* unfoldings it uses are re-exported for the semantics to reuse.

      TODO(locally-nameless): re-derive freeVars_applyComputable_subset against the de Bruijn applyComputable/liftBound; parked with the semantics port.

      theorem ComputableTLAPlus.mem_freeVars_fn {z y : String} {a co : Typ} {dom body : Expression Typ} :
      z (Expression.fn y a co dom body).freeVars z dom.freeVars z body.freeVars
      theorem ComputableTLAPlus.mem_freeVars_map' {z y : String} {a co : Typ} {dom body : Expression Typ} :
      z (body.map' y a co dom).freeVars z dom.freeVars z body.freeVars

      A .fnCall at a .nat index reads only its head.

      Field access reads only its subject.

      A coercion adds no free variable: every binder applyComputable introduces refers to itself by a .bound index, liftBound never touches a .free name, and every splice of e sits under an operator (Len/DOMAIN/.fnCall/.recordAccess) that carries e's free variables through unchanged. ExprSemantics.evalCoerce needs this to shrink a Coercion.FreshFor hypothesis onto a sub-expression (.comp, .function).

      Coercion.applyComputable and openVar #

      applyComputable commutes with an openVar traversal: every binder it introduces refers to itself by .bound, every splice of e under a binder carries a liftBound 1 that openVar at the raised depth cancels (Expression.openVar_liftBound_one_comm), and every other node passes the traversal through. ExprSemantics.evalCoerce's .set/.function cases need this: the built .fn/ .map' body opens with the binder's hint, and the opened term must read as applyComputable of the opened argument so the coercion recursion applies.

      mapVars (openVarLam x) k pushes through applyComputable: the depth-generalised statement, proved by recursion on the coercion. openVar_applyComputable is the k = 0 reading.

      Applying a coercion and then opening the enclosing binder is opening it inside the argument first: openVar slides through applyComputable.

      A coercion preserves local closedness. applyComputable introduces binders but every splice of e under one carries a liftBound 1, so opening the enclosing binder slides through (openVar_applyComputable) and lands on e, which a locally-closed e is fixed by — so the whole term is fixed by openVar, hence locally closed (Expression.LC.of_openVar_eq).