Skip to content

[Repo Assist] feat: implement dynamic resumable code for taskSeq / taskSeqDynamic, fixes #246#380

Merged
dsyme merged 1 commit intomainfrom
repo-assist/feat-dynamic-246-2026-04-07-c0100b55ab8efbcf
Apr 7, 2026
Merged

[Repo Assist] feat: implement dynamic resumable code for taskSeq / taskSeqDynamic, fixes #246#380
dsyme merged 1 commit intomainfrom
repo-assist/feat-dynamic-246-2026-04-07-c0100b55ab8efbcf

Conversation

@github-actions
Copy link
Copy Markdown
Contributor

@github-actions github-actions bot commented Apr 7, 2026

🤖 This is an automated pull request from Repo Assist, an AI assistant.

Closes #246

Summary

This PR implements the dynamic (FSI-compatible) resumable code path for taskSeq computation expressions, fixing the NotImplementedException that was raised whenever taskSeq was used in F# Interactive or any context where the F# compiler cannot emit static resumable code.

Root Cause

The TaskSeqBuilder.Run method has two branches controlled by __useResumableCode:

  • True (compiled code): uses __stateMachine to generate a static state machine struct
  • False (FSI / dynamic): previously raised NotImplementedException

Fix

New types added

Type Role
TaskSeqDynamicInfo<'T> Concrete ResumptionDynamicInfo subclass. Overrides MoveNext to drive the resumption function and handle yield/await/completion—same logic as the static MoveNextMethodImpl.
TaskSeqDynamic<'T> Reference-type IAsyncEnumerable<'T> implementation for the dynamic path. Stores _initialResumptionFunc instead of a compiler-generated machine struct, with correct cloning for re-enumeration.

Builder changes

  • TaskSeqBuilder.Run else branch now creates a TaskSeqDynamic<'T> instead of raising.
  • New TaskSeqDynamicBuilder type (inherits TaskSeqBuilder with no overrides—the base Run already handles both paths).
  • New taskSeqDynamic CE value exported from TaskSeqDynamicBuilder module.

Suppression

#nowarn "3513" added to TaskSeqBuilder.fs—the ResumableCode.Invoke call in the dynamic else branch is an intentional use of resumable code as a regular delegate.

Trade-offs

  • The dynamic path allocates a heap object (TaskSeqDynamic<'T>) vs. the static path's struct. This is acceptable since the dynamic path is only used in FSI.
  • taskSeqDynamic is functionally identical to taskSeq in compiled code (uses the same static path). Its only advantage over taskSeq is that it documents intent for code meant to run in FSI.

Test Status

Build: 0 warnings, 0 errors (Release)
Fantomas: formatting check passes
Tests: 5093 passed (24 new + 5069 existing), 2 skipped, 0 failed

New tests cover: empty sequence, single/multi yield, for/while loops, Task/Async bind, yield! from seq/taskSeq/taskSeqDynamic, tryWith, tryFinally, use, cancellation, re-enumeration, large sequences, nested loops.

Generated by 🌈 Repo Assist, see workflow run. Learn more.

To install this agentic workflow, run

gh aw add githubnext/agentics/workflows/repo-assist.md@7ee2b60744abf71b985bead4599640f165edcd93

 #246

Adds TaskSeqDynamicInfo<'T> and TaskSeqDynamic<'T> types that implement the
dynamic (ResumptionDynamicInfo-based) execution path for taskSeq computation
expressions. This fixes the NotImplementedException raised when taskSeq is used
in contexts where the F# compiler cannot emit static resumable code, such as
F# Interactive (FSI) or top-level functions.

Key changes:
- TaskSeqDynamicInfo<'T>: concrete ResumptionDynamicInfo subclass that handles
  MoveNext transitions (same logic as the static MoveNextMethodImpl)
- TaskSeqDynamic<'T>: reference-type IAsyncEnumerable implementation using the
  dynamic path, with proper cloning support for re-enumeration
- TaskSeqBuilder.Run: else-branch now creates TaskSeqDynamic instead of raising
- taskSeqDynamic: new CE builder (inherits TaskSeqBuilder) and module value;
  identical to taskSeq in compiled code, uses dynamic path in FSI
- 24 new tests covering: empty, single/multi yield, for/while loops, async bind,

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@dsyme dsyme marked this pull request as ready for review April 7, 2026 16:47
@dsyme dsyme closed this Apr 7, 2026
@dsyme dsyme reopened this Apr 7, 2026
@dsyme dsyme merged commit 4873e88 into main Apr 7, 2026
11 checks passed
@dsyme dsyme deleted the repo-assist/feat-dynamic-246-2026-04-07-c0100b55ab8efbcf branch April 7, 2026 16:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Implement dynamic versions of the resumable code

1 participant