Skip to content

Face transformers disagree on trailing-statement lowering — greet compiles to 2 wasm classes #601

@hyperpolymath

Description

@hyperpolymath

Summary

Grounding the "different faces, same cube" claim against a fresh build (the invariant-path faces profile + verify-same-cube.sh) shows the six faces do not produce byte-identical typed-wasm for the same program. They split into two classes because the face transformers disagree on how to lower a block's trailing statement (statement { println(x); } vs tail-expression { println(x) }).

Evidence

Corpus: one program (greet) written in every face — identical strings and structure (invariant-path/examples/same-cube/greet/). Built affinescript at HEAD (full suite 457 tests green; tools/run_face_transformer_tests.sh 6/6 green), compiled each face with compile --face <face>, sha256'd the wasm:

wasm class faces trailing call lowered as
56c454be… canonical, jaffa, cafe statement { println(x); }
2ff63dd1… rattle, pseudo, lucid tail-expression { println(x) }

preview-python (etc.) confirms it: it emits fn main() -{IO}-> () { println("…") } (no trailing ;), while the canonical reference has { println("…"); }.

Impact

  • For a unit-returning trailing call (e.g. println : … -> ()) the two lowerings are observationally identical (same effects, same unit return) — machine-checked in invariant-path/proofs/SameCube.agda (agda --safe, no postulates). So today's examples still behave the same.
  • For a value-returning trailing expression they genuinely diverge: the statement form discards the value and returns (), the tail-expression form returns the value. A face that lowers { …; lastExpr } as a statement would silently change the block's value/type — a real latent correctness gap, not a cosmetic wasm difference.

Suggested fix

Pick one trailing-statement convention and make all lib/<face>_face.ml transformers agree. Most faithful to AffineScript's expression-oriented blocks: preserve the tail expression (the rattle/pseudo/lucid behaviour), inserting ; only for genuine non-tail statements. Then the same-cube verifier collapses to one wasm class and byte-level same-cube holds.

Repro

# in invariant-path, with affinescript built at ../affinescript/_build:
just same-cube     # scripts/verify-same-cube.sh examples/same-cube/greet
just proofs        # agda --safe proofs/SameCube.agda

Found while grounding the faces work (invariant-path#33, affinescript#600).

🤖 Filed via Claude Codehttps://claude.ai/code/session_01KPG9mEQXFyA3k7NWAzMNMr

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions