Skip to content

Nested arrows with same-named untyped parameters can be instantiated - #542

Merged
ASDAlexander77 merged 1 commit into
mainfrom
fix-nested-implicit-generic-names
Oct 11, 2026
Merged

ASDAlexander77 merged 1 commit into
mainfrom
fix-nested-implicit-generic-names

Conversation

@ASDAlexander77

Copy link
Copy Markdown
Owner

Problem

docs/bugs/generic_in_generic.ts failed to compile:

function render(screenWidth, screenHeight) {
    const getPoint = (x, y) => {
        const recenterX = x => (x - (screenWidth / 2.0)) / 2.0 / screenWidth;
        const recenterY = y => -(y - (screenHeight / 2.0)) / 2.0 / screenHeight;
        return recenterX(x) + recenterY(y);
    }
    const v = getPoint(512, 384);   // error: can't instantiate function. '...afL2C22...' not all generic types can be identified

It needs all three of these: an untyped outer arrow, an untyped inner arrow whose parameter has the same name as one of the outer's, and a variable captured from the enclosing function. Renaming the inner x to z made it compile.

Cause

An untyped parameter makes its function generic in an implicit type parameter named TGenParam_<parameter name> (processTypeParametersFromFunctionParameters). The inner x therefore got the same type-parameter name as the outer x. When getPoint was instantiated with TGenParam_x = si32, that binding was in scope while the inner arrow was generated, so the inner arrow was named and registered as already specialized (...afL3C20...<si32>, with its captured screenWidth) while its type stayed (x: TGenParam_x) => .... resolveFunctionWithCapture then found the captures under that name and built a bound function with the still-generic type, and nothing instantiates a bound function, so the call failed. (Traced with -debug-only=mlir on the debug build.)

Fix

getParameterGenericTypeName also includes the function's source position in the name (TGenParam_x_<pos>), so nested functions' implicit type parameters can't collide. Both places that build the name (processTypeParametersFromFunctionParameters and processTypeArgumentsFromFunctionParameters) use the same signature, so they still agree.

Testing

  • New 00nested_implicit_generics.ts (compile + JIT + rc/none corpus): the original render/getPoint case, an untyped outer function with a capturing same-named inner arrow, and a same-named pair without capture. The current release fails with the error above.
  • docs/bugs/generic_in_generic.ts now prints 0, 0, 0.016276, done.
  • Full ctest: 3919/3919 pass.

🤖 Generated with Claude Code

An untyped parameter makes its function generic in a type named
TGenParam_<parameter>. In

    const getPoint = (x, y) => {
        const recenterX = x => (x - screenWidth / 2.0) / screenWidth;
        return recenterX(x) + ...;
    };

the inner `x`'s type had the same name as the outer `x`'s, so
instantiating getPoint bound the inner arrow's type as well. With a
captured variable (screenWidth) the inner arrow then resolved as a
closure over a function whose type was still generic, and the call
failed: "can't instantiate function ... not all generic types can be
identified". The type is now also named after the function's position.

Found by docs/bugs/generic_in_generic.ts.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@ASDAlexander77
ASDAlexander77 merged commit 3780091 into main Oct 11, 2026
2 checks passed
@ASDAlexander77
ASDAlexander77 deleted the fix-nested-implicit-generic-names branch October 11, 2026 12:47
ASDAlexander77 added a commit that referenced this pull request Oct 12, 2026
…558)

Every repro in docs/bugs passes on main, or fails as TypeScript does:
the native_ts_graphics findings were fixed by #535-#544 and #549 (the
`let s = 0` one by design, with a warning since #544), testFallThrough,
generic_in_generic and array_of_ifaces_cast by #538, #542 and #543, and
bug14 and bug21 aren't valid TypeScript. Each fix has its regression
test in tslang/test/tester, and the findings document is in the history
and in those PRs, so the folder goes.

Its interop notes stay, in docs/c-cpp-header-import.md: a `string`
returned by a C function is its `char*`, not a copy; `number` is a
`double`; and a nullable `Ref<T>` field is spelled `Ref<T> | null`.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
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.

1 participant