Skip to content

Return promises when async functions and generators fall off the end - #77

Open
schloerke wants to merge 2 commits into
r-lib:mainfrom
schloerke:issue-33
Open

schloerke wants to merge 2 commits into
r-lib:mainfrom
schloerke:issue-33

Conversation

@schloerke

Copy link
Copy Markdown

Fixes #33. An async function that ended with a loop or an if without else returned the exhaustion sentinel instead of a promise, so promises::then(async(function() while (FALSE) NULL)(), ~ NULL) failed. With an await() before the loop, the promise resolved to the sentinel instead of NULL. The cause was the fall-through return at the end of the state machine in walk_states(), which always returned exhausted(). A new fallthrough_value() helper now returns as_promise(NULL) for async functions and as_promise(exhausted()) for async generators.

Async generators had a second gap: calling one again after it was done returned the raw sentinel, while the docs say it always returns a promise. The exhausted check in the generator instance now wraps the sentinel in a promise for async generators, except on close = TRUE, which is only used for cleanup. Plain generators are unchanged.

Tests were written first and failed before the fix. The parser and async snapshots change only the final fall-through line. devtools::test() passes locally (317 pass, 2 skipped for reticulate).

@schloerke
schloerke marked this pull request as ready for review October 21, 2026 20:52

This branch has not been deployed

No deployments
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.

Loops and missing else branches in async() functions should return promises to NULL

1 participant