Skip to content

[compiler] Fix gating export misplaced on _unoptimized variant with TypeScript overload signatures#36020

Open
sleitor wants to merge 2 commits intofacebook:mainfrom
sleitor:fix-35991
Open

[compiler] Fix gating export misplaced on _unoptimized variant with TypeScript overload signatures#36020
sleitor wants to merge 2 commits intofacebook:mainfrom
sleitor:fix-35991

Conversation

@sleitor
Copy link
Contributor

@sleitor sleitor commented Mar 12, 2026

Summary

When a function has TypeScript overload signatures (TSDeclareFunction nodes), the overload identifier names were treated as runtime references by Babel's isReferencedIdentifier(). This caused getFunctionReferencedBeforeDeclarationAtTopLevel to incorrectly mark the implementation as referenced before declaration, triggering the insertAdditionalFunctionDeclaration path in insertGatedFunctionDeclaration.

In that path, the original function is renamed to <fn>_unoptimized in-place, keeping any parent ExportNamedDeclaration wrapper — so the export ended up on the wrong (unoptimized) function. The new dispatcher function was inserted without export, breaking the exported binding at runtime.

Before:

// Wrong: export lands on unoptimized variant
export function useSession_unoptimized<T>(...) { ... }
// Wrong: dispatcher has no export
function useSession(arg0) { if (gate()) ... }

After:

// Correct: export is on the dispatcher
export const useSession = isForgetEnabled_Fixtures()
  ? function useSession(selector) { /* optimized */ }
  : function useSession(selector) { /* original */ };

Fix

Skip TSDeclareFunction nodes in the top-level reference traversal (the same way TSTypeAliasDeclaration is already skipped). Overload signatures are not runtime references and should not influence the reference-before-declaration detection.

Fixes #35991

Test Plan

Added compiler fixture gating-ts-overload-export.tsx covering the exported function with TypeScript overload signatures + gating + annotation mode.

…ypeScript overload signatures

When a function has TypeScript overload signatures (TSDeclareFunction nodes),
the overload identifiers were treated as runtime references by Babel's
isReferencedIdentifier(). This caused getFunctionReferencedBeforeDeclarationAtTopLevel
to incorrectly mark the implementation as 'referenced before declaration', triggering
the insertAdditionalFunctionDeclaration path in insertGatedFunctionDeclaration.

In that path, the original function is renamed to <fn>_unoptimized in-place,
keeping any parent ExportNamedDeclaration wrapper — so the export ended up on
the wrong (unoptimized) function. The new dispatcher function was inserted
without export, making the exported name wrong at runtime.

Fix: skip TSDeclareFunction nodes in the top-level reference traversal, so
overload signatures are not treated as runtime references, and the standard
(non-referencedBeforeDeclaration) gating path is used instead, which correctly
replaces the entire export with `export const useSession = gating() ? ... : ...`.

Fixes facebook#35991

Test plan: added compiler fixture gating-ts-overload-export.tsx
@meta-cla meta-cla bot added the CLA Signed label Mar 12, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Compiler Bug]: Overloads cause wrong function to be exported with gating

1 participant