From 8828a246ab9b754d78b5c25c885e79717ed7dc13 Mon Sep 17 00:00:00 2001 From: "g. nicholas d'andrea" Date: Thu, 16 Apr 2026 03:14:44 -0400 Subject: [PATCH] format: make return.data optional The data pointer on function return contexts was required, forcing compilers to emit placeholder pointers at instructions where no return value is observable. The common motivating case is a tail-call-optimized back-edge JUMP, where the intermediate return value is not materialized on the stack (it would have become the next iteration's argument, which the compiler has already folded into the new call's setup). A placeholder pointer at such an instruction would mislabel unrelated stack content as the return value. Make data optional, matching the revert context's precedent (reason and panic are both optional there for similar reasons). A bare `return: {}` is now permitted, analogous to bare `revert: {}`. This also accommodates void functions (no return value to point at) and lost-compiler-precision cases where the compiler knows a return occurred but has dropped the value's location. Updates: - return.schema.yaml: drop data from required, expand descriptions, add a no-data example. - context.ts: data?: Function.PointerRef and adjust guard. - return.mdx: rewrite Field optionality section covering void/TCO/lost-precision cases. - call-contexts.test.ts: use non-null assertion where the test asserts the compiler did emit data. --- .../bugc/src/evmgen/call-contexts.test.ts | 3 +- packages/format/src/types/program/context.ts | 5 +-- .../spec/program/context/function/return.mdx | 40 ++++++++++++++----- .../context/function/return.schema.yaml | 36 ++++++++++++++--- 4 files changed, 66 insertions(+), 18 deletions(-) diff --git a/packages/bugc/src/evmgen/call-contexts.test.ts b/packages/bugc/src/evmgen/call-contexts.test.ts index 43f1b76cb..c05f58708 100644 --- a/packages/bugc/src/evmgen/call-contexts.test.ts +++ b/packages/bugc/src/evmgen/call-contexts.test.ts @@ -126,7 +126,8 @@ code { // Should have data pointer to return value at // TOS (stack slot 0) - expect(ret.data.pointer).toEqual({ + expect(ret.data).toBeDefined(); + expect(ret.data!.pointer).toEqual({ location: "stack", slot: 0, }); diff --git a/packages/format/src/types/program/context.ts b/packages/format/src/types/program/context.ts index 9388fea7b..104f27196 100644 --- a/packages/format/src/types/program/context.ts +++ b/packages/format/src/types/program/context.ts @@ -239,7 +239,7 @@ export namespace Context { export namespace Return { export interface Info extends Function.Identity { - data: Function.PointerRef; + data?: Function.PointerRef; success?: Function.PointerRef; } @@ -247,8 +247,7 @@ export namespace Context { Function.isIdentity(value) && typeof value === "object" && !!value && - "data" in value && - Function.isPointerRef(value.data) && + (!("data" in value) || Function.isPointerRef(value.data)) && (!("success" in value) || Function.isPointerRef(value.success)); } diff --git a/packages/web/spec/program/context/function/return.mdx b/packages/web/spec/program/context/function/return.mdx index e03668a1b..47279cea3 100644 --- a/packages/web/spec/program/context/function/return.mdx +++ b/packages/web/spec/program/context/function/return.mdx @@ -9,8 +9,8 @@ import SchemaViewer from "@site/src/components/SchemaViewer"; A return context marks an instruction associated with a successful function return. It extends the [function identity](/spec/program/context/function) schema with -a pointer to the return data and, for external calls, the -success status. +an optional pointer to the return data and, for external calls, +the success status.