Skip to content

feat: typed function declarations and verified direct and indirect calls - #237

Merged
LunaStev merged 2 commits into
wavefnd:masterfrom
LunaStev:feat/typed-function-calls
Sep 27, 2026
Merged

LunaStev merged 2 commits into
wavefnd:masterfrom
LunaStev:feat/typed-function-calls

Conversation

@LunaStev

@LunaStev LunaStev commented Sep 27, 2026 •

Copy link
Copy Markdown
Member

Problem and result

AST programs could not express calls, and IR calls only carried a string symbol plus unchecked argument IDs. Call sites now resolve a typed function identity or a function-pointer SSA value and must match the complete signature, calling convention and result contract.

Closes #90
Closes #110
Closes #159

Implementation

  • Add FunctionId, a module declaration table, complete FunctionSignature, Whale/SysV64 calling conventions, and internal/external linkage. External functions require an explicit nonempty link_name; conflicting declarations, duplicate definitions, missing internal bodies and external-name collisions are rejected. Definitions refer to declaration IDs rather than their position in the table.
  • Add checked declaration/body/address/call builder APIs. Calls infer their result type from the callee, validate arguments before emitting an instruction, omit a result only for void, and preserve unused nonvoid results at O0. The existing begin_function convenience still creates an internal Whale definition.
  • Replace string callees with Direct(FunctionId) and Indirect(ValueId). Introduce FnPtr(signature), FunctionAddr and typed NullFunction. Function-pointer types survive storage, parameter/return passing, phi, select and tuple extraction; invalid extraction cannot manufacture a callable type. Casts involving function-pointer types are rejected.
  • Verify callee identity, parameter count/types, result type and destination presence, calling convention, function-address type and indirect-callee SSA dominance. Reject void parameters, variadic signatures and unsupported SysV64 aggregate signatures explicitly, including nested malformed function-pointer signatures.
  • Extend AST lowering with declarations, function references, typed nulls, direct calls and expression-based indirect calls. Register signatures before bodies for forward/recursive references. Evaluate the callee expression first and arguments left to right. Reject void calls used as values and calls/function references used as numeric constant expressions.
  • Add positive/negative IR and AST tests, an exact JSON-to-printed-IR fixture, and CLI output-preservation checks with --no-verify. Update the README, existing fixtures and empty-PATH smoke inputs.

Format migration

AST format and printed typed IR format each advance from 1 to 2; semantics remain 1. Format 1 input is rejected rather than interpreted under the changed schema.

AST producers must add program.declarations (an empty array when unused) and explicit convention/linkage on function definitions. Internal definitions normally use "Whale"/"Internal" and no link name. External declarations/definitions need an explicit link_name. Numeric string encodings are unchanged. The complete strict schema is ir/schema/ast-v2.schema.json.

Rust users must register callees and replace Callee::Symbol and caller-supplied return types with typed direct/indirect calls returning Result<Option<ValueId>, CallError>. Raw module producers must populate declaration IDs and keep definition types consistent with declarations. Printed IR exposes declarations, convention, linkage, link names and definition IDs.

Boundaries

A well-typed null or invalid indirect target has a required runtime trap before entering the callee. This PR represents and verifies the IR contract; it does not add an interpreter, machine ABI lowering, native call emission, foreign callback lifetime management or runtime shadow metadata. Those execution checks remain with #67 and the execution work.

Function identity/link names are preserved at the IR boundary only. #215 remains open for typed identity through object emission and final linking. Aggregate Whale signatures are representable IR, not a claim of native aggregate ABI support. Existing uninitialized-value work (#65), strong/weak policy and complete static linking are unchanged.

Validation

  • Final-commit offline workspace tests: default 140 passed; all features 175 passed; Rust 1.86.0 all features 175 passed.
  • Default/all-feature workspace Clippy with all targets and warnings denied; formatting and diff checks.
  • Both CLI feature modes built and passed standalone smoke tests with an empty PATH.
  • Python CI helper tests: 8 passed.
  • Pinned Wave bootstrap built from the existing CI revision; the selected Wave ELF path passed 177 all-feature workspace tests, all-target Clippy, build and empty-PATH CLI smoke.
  • Strict JSON Schema validation passed all three format-2 fixtures.
  • Official documentation: 14 Rust snippets compiled and ran; six complete JSON examples and their associated printed modules checked; document/handler Go tests passed. Documentation: docs: explain Whale typed calls and format 2 with runnable examples wave-platform#130 — merge it after this implementation.

The final additional regression covers function_addr rejecting malformed signatures produced through the legacy infallible convenience API.

Windows checkout correction

Both Windows all-feature jobs failed the exact printed-IR fixture assertion because Git converted calls-v2.wir to CRLF while the printer consistently emits LF. Add *.wir text eol=lf to preserve the canonical fixture bytes on every host; keep the exact assertion and printer output unchanged.

Reproduced the pre-fix conversion in an isolated checkout with core.autocrlf=true. With the attribute applied, fresh checkout of the fixture preserves identical LF bytes for core.autocrlf=true, false, and input, including core.eol=crlf. All five call-lowering tests and diff checks passed locally. On commit 4f14536c5fa419d8cd107f770888145d16d180ee, all 23 GitHub CI checks passed, including native Windows x64 and ARM64 with default and all features.

@LunaStev
LunaStev merged commit 4f45fdb into wavefnd:master Sep 27, 2026
23 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant