Skip to content

fix(repeat): declare repeat()'s closure signature as ANY, not VOID - #897

Merged
martin-henz merged 1 commit into
masterfrom
fix/repeat-closure-any-type
Aug 8, 2026
Merged

fix(repeat): declare repeat()'s closure signature as ANY, not VOID#897
martin-henz merged 1 commit into
masterfrom
fix/repeat-closure-any-type

Conversation

@martin-henz

Copy link
Copy Markdown
Member

Summary

  • repeat() built its composed closure with args: [DataType.VOID], returnType: DataType.VOID. DataType.VOID means "the associated JS value is undefined" (Python None), so Py2JS's type checker rejected any real argument passed to a repeat-composed closure:
    from repeat import repeat
    plusTen = repeat(lambda x: x + 2, 5)
    plusTen(0)
    # TypeError: Expected argument 0 to have type 'NoneType', got 'int' or 'float'
  • The closure is generic over its argument's type (works for numbers, points, anything), so it should declare DataType.ANY, matching the existing pattern already used for repl's identity-like closures (src/bundles/repl/src/index.ts:156,205).
  • twice/thrice are thin wrappers over repeat and are fixed the same way.

Fixes #896

Why the existing tests didn't catch this

TestDataHandler.closure_call_unchecked (used by the bundle's JS-side test suite) calls the underlying JS function directly and never validates arguments against the closure's declared signature - only the real Py2JS evaluator enforces it. So this class of bug is invisible to the current unit tests; a signature-inspection helper in the shared test plugin would be needed to catch it there, which is out of scope for this fix.

Test plan

  • yarn test (repeat bundle) — 5/5 existing tests pass
  • yarn tsc — no errors
  • yarn lint — clean

DataType.VOID means "the associated JS value is undefined" (Python
None), so Py2JS's type checker rejected any actual argument passed to
a repeat()-composed closure - e.g. repeat(f, 5)(0) failed with
"Expected argument 0 to have type 'NoneType', got 'int'". The closure
is generic over its argument's type, so it should declare
DataType.ANY, matching the existing pattern used for repl's identity-
like closures.

The bundle's own test suite didn't catch this because
TestDataHandler.closure_call_unchecked calls the underlying JS
function directly without validating declared argument types - only
the real Py2JS evaluator enforces the signature.

Fixes #896
@martin-henz
martin-henz merged commit ad23578 into master Aug 8, 2026
12 checks passed
@martin-henz
martin-henz deleted the fix/repeat-closure-any-type branch August 8, 2026 00:17
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.

repeat: repeat function broken

1 participant