Skip to content

Codegen.UnboundVariable for top-level const bindings (typecheck OK, compile fails) #73

@hyperpolymath

Description

@hyperpolymath

Surfaced by: IDApTIK Mode A pilot of shared/src/PortNames.res → migration/shared/PortNames.affine (after PR #67's parser fix lands).

Affected version: v0.1.0 (affinescript HEAD with PR #67 [T] parser fix applied).
Severity: Blocks compile (codegen) on any module with top-level const bindings used by other top-level fns or consts. check (typechecker) handles them correctly.

Reproducer

const inputSuffix: String = ":in";

fn withInput(port: String) -> String { port ++ inputSuffix }
$ affinescript check pn.affine
Type checking passed

$ affinescript compile pn.affine
Code generation error: (Codegen.UnboundVariable "inputSuffix")
affinescript: Code generation error

Diagnosis

The typechecker resolves inputSuffix correctly (check passes), so the AST has the right cross-reference. The codegen phase has its own name resolution and fails to look up inputSuffix when generating code for withInput's body — top-level consts aren't being threaded into the codegen environment alongside fn bindings.

bin/main.ml and lib/codegen.ml (or wherever the codegen lives) likely walk fn_decl declarations only, skipping const_decl. Adding consts to the codegen environment is the likely fix.

Why this matters now

Real idaptik translation hits this immediately. Modules like PortNames (well-known string constants used across the codebase), AssetPaths (resource locations), PortBindings (configuration), and many more, are precisely the shape of "a few module-level constants + a few helper fns that reference them". They typecheck cleanly but cannot be compiled to wasm.

Cross-reference

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