Skip to content

fix(js/ts/python): preserve cancelled cleanup and generic unit callbacks - #5062

Merged
dbrattli merged 4 commits into
mainfrom
fix/async-cleanup-generic-continuations
Oct 15, 2026
Merged

dbrattli merged 4 commits into
mainfrom
fix/async-cleanup-generic-continuations

Conversation

@dbrattli

@dbrattli dbrattli commented Oct 13, 2026 •

Copy link
Copy Markdown
Collaborator

Why

JS/TypeScript and Python Async.TryFinally can skip cleanup with an already-cancelled token. Eager Using binders can also enter a cancelled resource body before disposal is protected.

Python generic Async.FromContinuations exposes a success callback requiring a value even when unit specialization emits ok().

Relationship to earlier fixes

  • fix(js/ts/python): synchronize cancellation registrations #5036 fixed cancellation registration disposal, ordering, races, and callback failures. Its registration tests did not cover resource ownership through Using and TryFinally; correct listener lifecycle alone does not ensure cleanup is installed before cancellation can terminate a computation.
  • fix(js/ts/python): preserve JS/TS generic unit arguments and Python unit continuations #5037 added a Python unit adapter selected when FromContinuations has a statically known Async<unit> result. Its generic fromValue () regression passes a value and preserves an argument. A helper returning Async<'T> can instead receive a callback that invokes ok () with no argument: the helper still selects the generic runtime path, leaving both runtime arity and callable annotations mismatched.
  • fix(js/ts/python): settle cancelled delays and finalizers once #5038 fixed cancelled-delay settlement and finalizer exception precedence. Its finalizer tests exercised cancellation after cleanup handlers were installed; its pre-cancellation test asserted that work did not start without asserting cleanup. The outer TryFinally cancellation check could still bypass handler installation, and Using still evaluated its binder before disposal was protected. Downstream continuation exceptions could also re-enter finalization; preventing duplicate timer settlement did not guard finalization itself.

This PR adds coverage for those composition boundaries: pre-cancelled finalization, nested finalization, cancellation during resource acquisition, downstream continuation failures, and generic callbacks specialized to unit.

How

  • Install cleanup before cancellation checks and defer resource binders in the existing runtimes. For nested TryFinally with an already-cancelled token, run only the outer cleanup without entering the inner computation, matching .NET.
  • Accept erased unit in Python's generic success callback, guard single completion, and adapt callable annotations while preserving callback identity and return types.
  • Preserve the shared trampoline, downstream continuation exceptions, and .NET's terminal cancellation when compensation throws.
  • Add F# and native Python regressions for cancellation, disposal, unit/non-unit results, stack growth, and duplicate/concurrent completion.

@dbrattli dbrattli changed the title fix(async): preserve cancelled cleanup and Python generic unit callbacks fix(js/ts/python): preserve cancelled cleanup and generic unit callbacks Oct 13, 2026
@github-actions

github-actions Bot commented Oct 13, 2026 •

Copy link
Copy Markdown
Contributor

Python Type Checking Results (Pyright)

Metric Value
Total errors 36
Files with errors 5
Excluded files 4
New errors ❌ Yes

⚠️ New Files with Errors

These files are NOT in the exclude list and must be fixed or added to pyrightconfig.ci.json:

File Errors Status
temp/tests/Python/fable_modules/thoth_json_core/codec.py 2 ⚠️ NEW
Excluded files with errors (4 files)

These files have known type errors and are excluded from CI. Remove from pyrightconfig.ci.json as errors are fixed.

File Errors Status
temp/tests/Python/test_hash_set.py 18 Excluded
temp/tests/Python/test_applicative.py 12 Excluded
temp/tests/Python/test_nested_and_recursive_pattern.py 2 Excluded
temp/tests/Python/fable_modules/thoth_json_python/encode.py 2 Excluded

@dbrattli
dbrattli force-pushed the fix/async-cleanup-generic-continuations branch 2 times, most recently from 3ac4b9f to e82b304 Compare October 13, 2026 22:16
@dbrattli
dbrattli marked this pull request as ready for review October 13, 2026 23:00
@dbrattli
dbrattli requested a review from MangelMaxime October 14, 2026 22:18
@dbrattli
dbrattli force-pushed the fix/async-cleanup-generic-continuations branch from 18ce662 to efe486d Compare October 15, 2026 19:11
@dbrattli
dbrattli merged commit 5dd6b49 into main Oct 15, 2026
37 of 38 checks passed
@dbrattli
dbrattli deleted the fix/async-cleanup-generic-continuations branch October 15, 2026 20:23
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.

2 participants