Skip to content

fix(js/ts/python): preserve JS/TS generic unit arguments and Python unit continuations - #5037

Merged
MangelMaxime merged 3 commits into
mainfrom
fix/python-unit-continuations
Oct 11, 2026
Merged

MangelMaxime merged 3 commits into
mainfrom
fix/python-unit-continuations

Conversation

@dbrattli

@dbrattli dbrattli commented Oct 3, 2026 •

Copy link
Copy Markdown
Collaborator

Why

The JavaScript and TypeScript compiler drops unit arguments when calling local generic functions, generating fromValue() instead of fromValue(undefined). Call-site types are specialized to unit, so using them to erase arguments loses the function's declared generic parameter. This affects the shared JS/TS code generator and causes TypeScript compilation to fail with TS2554. Generic functions must receive their unit value while ordinary unit -> unit callbacks retain their zero-argument convention.

Python has two related unit continuation failures. Async.FromContinuations(fun (ok, _, _) -> ok ()) invokes a runtime success continuation without its required value. A unit continuation inside a tail-recursive function can also put a captured callback in its first default parameter, which the runtime's None argument overwrites. Both failures reproduce by executing generated Python.

How

  • Retain declaration types for local bindings, recursive bindings, and function parameters in the shared JavaScript/TypeScript Babel transform.
  • Preserve unit arguments when a curried call's declared parameter requires a value, including generic aliases whose parameter type is erased to any. Generate fromValue(undefined) for a generic factory and keep callback() for an ordinary unit callback.
  • Add a dedicated Python unit FromContinuations runtime adapter and select it at the replacement boundary, preserving the existing generic API and ordinary unit call semantics.
  • Reserve a real unit argument before Python captured tail-call defaults so runtime arguments cannot overwrite captures. Give it a unique name, including when a captured F# variable is named __unit.
  • Add generated JS/TypeScript/Python/BEAM regressions for unit and non-unit computations, generic and explicitly unit-typed callbacks, recursive generic factories and aliases, and a Python capture-name collision.

Validation

  • Published compiler/library 5.19.0: both Python unit tests failed (on_success missing value, and a callback overwritten with None). They pass with the compiler/runtime fixes.
  • Before the JS/TS compiler fix: ./build.sh test typescript reproduces TS2554 at AsyncTests.ts(134,34) for fromValue(). After: ./build.sh test typescript --force-fable-library passes TypeScript compilation and all 2,884 generated tests using TypeScript 7.0.2. Generated code passes undefined to the factory and alias, and invokes ordinary unit callbacks without arguments.
  • Exact PR branch: ./build.sh test javascript --force-fable-library passes 2,937 .NET, 3,107 JS, 3,132 Temporal JS, React 26 tests/19 snapshots, and Adaptive 1 test.
  • Exact PR branch: ./build.sh test python --type-check --skip-fable-library-core passes 2,399 .NET and 2,489 Python tests. Generated Pyright matches the existing baseline of 34 errors/45 warnings; the async regression module and changed Python adapter have 0 errors/0 warnings. Existing abandoned-event-loop warnings remain observable with the published runtime as well.
  • ./build.sh test beam passes 2,712 .NET and 2,746 BEAM tests, plus entry-point checks. Repository-wide Fantomas and git diff --check pass.
  • This requires an updated compiler and Python runtime together; Fable.Actor adapters remain until publication and a passing four-target Actor suite without them.

@dbrattli
dbrattli marked this pull request as ready for review October 3, 2026 20:13
@github-actions

github-actions Bot commented Oct 3, 2026

Copy link
Copy Markdown
Contributor

Python Type Checking Results (Pyright)

Metric Value
Total errors 34
Files with errors 4
Excluded files 4
New errors ✅ No
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 changed the title fix(python): preserve unit continuations and captured callbacks fix(js/ts/python): preserve unit calls and continuation captures Oct 3, 2026
@dbrattli dbrattli changed the title fix(js/ts/python): preserve unit calls and continuation captures fix: preserve JS/TS generic unit arguments and Python unit continuations Oct 3, 2026
@dbrattli dbrattli changed the title fix: preserve JS/TS generic unit arguments and Python unit continuations fix(js/ts): preserve JS/TS generic unit arguments and Python unit continuations Oct 3, 2026
@dbrattli dbrattli changed the title fix(js/ts): preserve JS/TS generic unit arguments and Python unit continuations fix(js/ts/python): preserve JS/TS generic unit arguments and Python unit continuations Oct 3, 2026
@dbrattli
dbrattli requested a review from MangelMaxime October 7, 2026 21:43
@MangelMaxime
MangelMaxime force-pushed the fix/python-unit-continuations branch from 70d776b to 58597af Compare October 10, 2026 16:36
@MangelMaxime
MangelMaxime merged commit e05bc75 into main Oct 11, 2026
37 checks passed
@MangelMaxime
MangelMaxime deleted the fix/python-unit-continuations branch October 11, 2026 08:58
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