Skip to content

Fixes #35770#508

Closed
everettbu wants to merge 1 commit into
mainfrom
fix-compiler-runtime-exports
Closed

Fixes #35770#508
everettbu wants to merge 1 commit into
mainfrom
fix-compiler-runtime-exports

Conversation

@everettbu

Copy link
Copy Markdown

Mirror of facebook/react#35773
Original author: itsnothuy


Summary

This PR resolves a compiler/runtime contract mismatch where react-compiler-runtime was missing exports that the React Compiler emits in compiled code when certain features are enabled.

Problem: The compiler's test/playground configuration (testComplexConfigDefaults in TestUtils.ts) enables three features that generate imports from react-compiler-runtime:

  • enableEmitFreeze → imports makeReadOnly
  • enableEmitInstrumentForget.gating → imports shouldInstrument
  • lowerContextAccess → imports useContext_withSelector

However, the runtime package did not export these helpers. The existing $makeReadOnly threw a TODO error, causing compiled code to crash at runtime.

Solution: This PR implements and exports the three missing helpers with correct semantics:

  1. makeReadOnly(val, source) — Mutation-tracking proxy for dev-mode debugging. Implementation inlined from the existing make-read-only-util package (to avoid adding dependencies). Logs console.error when values the compiler treats as immutable are mutated. Also aliases $makeReadOnly to this implementation.

  2. shouldInstrument — Exported as const shouldInstrument: boolean = true. The compiler emits this as a bare identifier in if (DEV && shouldInstrument), not as a function call. Value is true since the DEV global already provides the dev/prod gate.

  3. useContext_withSelector(context, selector) — Correctness-first fallback that delegates to React.useContext(context) (ignoring the selector). The selector enables future optimizations; this implementation is semantically correct for React 17/18/19.

This PR also adds Jest test infrastructure and comprehensive export surface tests to prevent future drift.

How did you test this change?

1. New Unit Tests

cd /Users/huy/Desktop/react/compiler
yarn workspace react-compiler-runtime test

Result: [x] All 14 tests passed

Test Coverage:

  • All required exports are present with correct types
  • makeReadOnly handles primitives, objects, and logs mutations
  • shouldInstrument is a boolean (not a function)
  • $makeReadOnly no longer throws TODO error
  • useContext_withSelector is callable

Output:

PASS src/__tests__/exports.test.ts
  react-compiler-runtime export surface
    ✓ exports c (memo cache polyfill) (1 ms)
    ✓ exports $dispatcherGuard (hook guards) (1 ms)
    ✓ exports $structuralCheck (change detection)
    ✓ exports useRenderCounter (instrumentation)
    ✓ exports $reset
    ✓ exports makeReadOnly (enableEmitFreeze)
    ✓ exports $makeReadOnly as alias for makeReadOnly
    ✓ $makeReadOnly does not throw TODO
    ✓ exports shouldInstrument (enableEmitInstrumentForget gating)
    ✓ exports useContext_withSelector (lowerContextAccess)
  makeReadOnly
    ✓ returns primitive values unchanged (1 ms)
    ✓ returns same object reference
    ✓ logs error on mutation of frozen property
    ✓ source parameter is optional (1 ms)

Test Suites: 1 passed, 1 total
Tests:       14 passed, 14 total

2. Lint Checks

cd /Users/huy/Desktop/react
yarn linc

Result: [x] Lint passed for changed files

3. Manual Verification

Verify exports are present:

yarn workspace react-compiler-runtime build
node -e "const r=require('./compiler/packages/react-compiler-runtime/dist/index.js'); \
  console.log({ \
    makeReadOnly: typeof r.makeReadOnly, \
    shouldInstrument: typeof r.shouldInstrument, \
    useContext_withSelector: typeof r.useContext_withSelector, \
    \$makeReadOnly: typeof r.\$makeReadOnly \
  })"

Output:

{
  makeReadOnly: 'function',
  shouldInstrument: 'boolean',
  useContext_withSelector: 'function',
  $makeReadOnly: 'function'
}

Verify $makeReadOnly no longer throws:

node -e "require('./compiler/packages/react-compiler-runtime/dist/index.js').\$makeReadOnly('test', 'source')"

Result: [x] No error (previously threw: "TODO: implement $makeReadOnly")

4. Before/After Comparison

Before this PR:

  • makeReadOnly was undefined
  • shouldInstrument was undefined
  • useContext_withSelector was undefined
  • $makeReadOnly() threw error: "TODO: implement $makeReadOnly in react-compiler-runtime"
  • Compiled code with these features enabled would crash at runtime

After this PR:

  • All three helpers are properly exported
  • $makeReadOnly is now a working alias for makeReadOnly
  • Compiled code executes successfully
  • Mutation tracking works in dev mode (logs to console)

5. Files Changed

compiler/packages/react-compiler-runtime/jest.config.js              (new file)
compiler/packages/react-compiler-runtime/package.json               (modified)
compiler/packages/react-compiler-runtime/src/__tests__/exports.test.ts  (new file)
compiler/packages/react-compiler-runtime/src/index.ts               (modified)

Total changes: 4 files changed, 275 insertions(+), 3 deletions(-)

Miscellaneous

No breaking changes: No existing public API behavior is modified (except $makeReadOnly which was non-functional and threw an error)

Backward compatible: Works with React 17/18/19 (the full peer dependency range: ^17.0.0 || ^18.0.0 || ^19.0.0)

Consistent semantics: The makeReadOnly implementation is inlined from the repo's existing make-read-only-util package, ensuring consistency

Safe fallback: useContext_withSelector returns semantically correct values (full context object). Future optimizations can be added without breaking the contract

Zero new dependencies: Implementation is self-contained, no new packages added to react-compiler-runtime

Test coverage: Comprehensive tests prevent future regression

@greptile-apps

greptile-apps Bot commented Feb 12, 2026

Copy link
Copy Markdown

Greptile Overview

Greptile Summary

This PR fixes a critical compiler/runtime contract mismatch where the React Compiler's test configuration enabled three features that import helpers from react-compiler-runtime, but the runtime package was missing those exports.

Changes Made:

  • makeReadOnly(val, source) - Implemented mutation-tracking proxy for dev-mode debugging. The implementation is correctly inlined from the existing make-read-only-util package with simplified logging (direct console.error instead of callback-based logging). Returns primitives unchanged and wraps objects with property descriptors to detect mutations.

  • shouldInstrument - Exported as const shouldInstrument: boolean = true. Correctly implemented as a boolean constant (not a function) since the compiler emits it as a bare identifier in conditional expressions.

  • useContext_withSelector(context, selector) - Implemented as a fallback that delegates to React.useContext(context) while ignoring the selector parameter. This is semantically correct for all React versions and provides a foundation for future optimization.

  • $makeReadOnly - Changed from throwing a TODO error to being an alias for makeReadOnly, maintaining backwards compatibility.

  • Test Infrastructure - Added comprehensive Jest tests that verify all exports exist and function correctly, preventing future contract drift.

The implementation is well-documented, follows existing patterns in the codebase, and includes no breaking changes.

Confidence Score: 5/5

  • This PR is safe to merge with no issues found.
  • The implementation correctly addresses the stated problem with well-tested, production-ready code. The makeReadOnly implementation is faithfully adapted from the existing make-read-only-util package, shouldInstrument is correctly exported as a boolean constant, and useContext_withSelector provides a semantically correct fallback. Comprehensive tests verify all exports and prevent regression. No breaking changes, security issues, or logical errors were found.
  • No files require special attention

Important Files Changed

Filename Overview
compiler/packages/react-compiler-runtime/src/index.ts Implements three missing runtime helpers (makeReadOnly, shouldInstrument, useContext_withSelector) that fix compiler/runtime contract mismatch. Implementation is correct and well-documented.
compiler/packages/react-compiler-runtime/src/tests/exports.test.ts Comprehensive regression tests verify all required exports exist and function correctly. Tests prevent future contract drift between compiler and runtime.

Last reviewed commit: a01afd0

@greptile-apps greptile-apps Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

4 files reviewed, no comments

Edit Code Review Agent Settings | Greptile

@everettbu

Copy link
Copy Markdown
Author

Upstream PR was closed or merged. Code is synced via branch mirror.

@everettbu everettbu closed this Feb 12, 2026
@everettbu
everettbu deleted the fix-compiler-runtime-exports branch February 12, 2026 22:22
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.

2 participants