Skip to content

feat(vm): reflect proxy boxes multi-return funcs as vectors - #776

Merged
nooga merged 1 commit into
nooga:mainfrom
abogoyavlensky:interop/p3-reflect-multireturn
Sep 6, 2026
Merged

nooga merged 1 commit into
nooga:mainfrom
abogoyavlensky:interop/p3-reflect-multireturn

Conversation

@abogoyavlensky

@abogoyavlensky abogoyavlensky commented Aug 23, 2026

Copy link
Copy Markdown
Contributor

Resolves: #775

Same goal as #773: letting lgx projects depend on Go libraries. That only pays off if calling those libraries works, and the reflect proxy assumed at most two results, silently dropping the rest. Any (a, b, ok) or (a, b, err) function came back wrong, and strings.Cut returns three. The values were dropped on the Go side before boxing, so no .lg wrapper could recover them.

Independent of #773 and can land in any order.

@nooga nooga left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. Small, correct, tested (strings.Cut-style 3-return). Build/vet/tests/check-generated pass locally. Merging.

@nnunley nnunley added the review-priority/medium Review after bases land / once rebased label Sep 2, 2026
@nnunley

nnunley commented Sep 2, 2026

Copy link
Copy Markdown
Collaborator

Queue update: #758 has merged and advanced main. GitHub now reports this approved PR as conflicting at fd23603cd713. Please update it onto current main; once the refreshed head is green, it is next in the integration order.

The proxy assumed at most two results and silently dropped the rest. The
drop happened on the Go side, before boxing, so a .lg veneer could never
recover the lost values and a wrapper library has no Go of its own to
shim with — nothing downstream could work around it. (a, b, ok) and
(a, b, err) are ordinary modern Go; strings.Cut returns three.

Peel a trailing error, then box what remains as nil, a single value, or a
vector.

One judgment call, because the plan for this change contradicted itself:
its design said a trailing error is peeled as a throw, its task steps said
existing 0/1/2-shape behavior is unchanged, and those disagree about
func() error — which today returns the error as a VALUE and never throws.
Every reflect-boxed Close/Write/Flush has that shape, so peeling there
would quietly turn (if (.Close f) ...) into a throw across a lot of
working interop. The peel therefore applies only when a non-error result
remains: from (T, error) upward, exactly where it already did. func()
error is pinned by its own test.

The only intended behavior change is the one the design asked for:
func() (A, B) now yields [a b] instead of a alone.

The type test stays on the DECLARED result type, so a function returning
a concrete *MyError returns a value rather than signalling failure, and
an error anywhere but last is an ordinary value. The TinyGo stub is a
separate build-tagged file and is untouched.

Known limitation, pinned by a test rather than fixed: BoxValue does not
support Go arrays. Its slice/array case calls IsNil, invalid for arrays,
and the branches under it assume []int64 or Bytes(). This predates
multi-return — func() [1]int panics identically and always has — and
multi-return only makes the existing hole reachable through one more
shape, turning a silent wrong answer into a visible error. Fixing
BoxValue is out of scope here.

docs/guide/go-interop.md gains the full result-mapping table; there was
no written rule for this before.

Baseline: main a665761. Independent of the other interop branches.
@nooga
nooga force-pushed the interop/p3-reflect-multireturn branch from aed5ea0 to 16a9776 Compare September 6, 2026 22:14
@nooga
nooga merged commit c8b2a3a into nooga:main Sep 6, 2026
21 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

review-priority/medium Review after bases land / once rebased

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Reflect proxy silently drops Go return values past the second

3 participants