Skip to content

fix(beam): implement Async.AwaitTask#4819

Merged
dbrattli merged 1 commit into
mainfrom
fix/beam-async-runtime-gaps
Jul 18, 2026
Merged

fix(beam): implement Async.AwaitTask#4819
dbrattli merged 1 commit into
mainfrom
fix/beam-async-runtime-gaps

Conversation

@dbrattli

Copy link
Copy Markdown
Collaborator

Problem

Async.AwaitTask compiled to fable_async:await_task/1, which does not exist in the Beam runtime library. The call built cleanly and failed at runtime with undef:

{undef,[{fable_async,await_task,[#Fun<fable_async_builder.1.93784029>],[]}, ...

This comes from the catch-all at the end of asyncs in src/Fable.Transforms/Beam/Replacements.fs, which passes any unmapped Async member through to fable_async under its derived name, assuming a matching function exists.

Fix

Implemented await_task/1 as the identity. On the Beam a Task and an Async share one representation — the task CE is compiled onto the async builder — so there is nothing to convert. The crash dump above confirms it: the argument is already a fable_async_builder fun.

Added two tests in tests/Beam/TaskTests.fs: direct, and inside an async CE with let!.

Scope

Other Async members reachable through the same catch-all (Choice, OnCancel, TryCancelled, CancelDefaultToken, DefaultCancellationToken, SwitchToThreadPool) are not Beam-specific gaps — src/fable-library-ts/Async.ts and fable_library/async_.py don't implement them either, and all three targets use the same catch-all shape. AwaitTask was the one member where Beam was genuinely behind: JS maps it explicitly to awaitPromise and Python has await_task in its runtime.

Deliberately left out of this PR:

  • A compile-time error for unsupported members. A Beam-only error for calls that JS and Python also emit as broken would be a divergence rather than a fix; if wanted, it belongs in the shared layer across all targets.
  • A build-time check diffing emitted fable_async:* calls against the runtime's exports. Good idea and cheap, but it has its own design questions (which targets, where in the build, how to handle the intentional gaps that would immediately light up red) — worth doing deliberately rather than bundling here.

Verification

Full Beam suite green: 2635 Erlang tests pass / 0 fail; .NET side 2616/2616. Both new tests pass.

🤖 Generated with Claude Code

`Async.AwaitTask` compiled to `fable_async:await_task/1`, which did not
exist — the call built cleanly and failed at runtime with `undef`.

On the Beam a Task and an Async share one representation (the `task` CE
is compiled onto the async builder), so the conversion is the identity.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@dbrattli
dbrattli merged commit 17cc3b6 into main Jul 18, 2026
31 checks passed
@dbrattli
dbrattli deleted the fix/beam-async-runtime-gaps branch July 18, 2026 14:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant