Compare commits
45 Commits
pr32593
...
repro-bug-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7b90545420 | ||
|
|
86d5ac0882 | ||
|
|
476f53879e | ||
|
|
c69a5fc53a | ||
|
|
a35aaf704c | ||
|
|
3c3696d554 | ||
|
|
90b511ec7a | ||
|
|
02372952e4 | ||
|
|
9fde224a53 | ||
|
|
ca02c4bb40 | ||
|
|
c37d89827e | ||
|
|
6c6699f3d2 | ||
|
|
9320a0139d | ||
|
|
fbcda19a23 | ||
|
|
cd28a946d5 | ||
|
|
8243f3f063 | ||
|
|
df31952275 | ||
|
|
1a191701fe | ||
|
|
99563e9173 | ||
|
|
17d274dc12 | ||
|
|
6b5d9fd316 | ||
|
|
2c560374d6 | ||
|
|
2e385738a4 | ||
|
|
c4a3b92e09 | ||
|
|
6daef4e7c8 | ||
|
|
3e956805e8 | ||
|
|
1b6e3dd985 | ||
|
|
5398b71158 | ||
|
|
f3c956006a | ||
|
|
4eba294c69 | ||
|
|
5200721e5c | ||
|
|
e9d80d939e | ||
|
|
ef1103d3e9 | ||
|
|
67338703aa | ||
|
|
7939d92fcc | ||
|
|
d92e5713be | ||
|
|
93b61fc4ec | ||
|
|
77987e5ee3 | ||
|
|
0df46f01a9 | ||
|
|
f457d0b4c6 | ||
|
|
1c79cb82ab | ||
|
|
89a46a57df | ||
|
|
eb53139ee5 | ||
|
|
38a7600920 | ||
|
|
ed1264f077 |
@@ -19,7 +19,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Discord Webhook Action
|
||||
uses: tsickert/discord-webhook@v6.0.0
|
||||
uses: tsickert/discord-webhook@86dc739f3f165f16dadc5666051c367efa1692f4
|
||||
with:
|
||||
webhook-url: ${{ secrets.COMPILER_DISCORD_WEBHOOK_URL }}
|
||||
embed-author-name: ${{ github.event.pull_request.user.login }}
|
||||
|
||||
5
.github/workflows/compiler_playground.yml
vendored
5
.github/workflows/compiler_playground.yml
vendored
@@ -36,8 +36,9 @@ jobs:
|
||||
uses: actions/cache@v4
|
||||
id: node_modules
|
||||
with:
|
||||
path: "**/node_modules"
|
||||
key: compiler-node_modules-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('compiler/**/yarn.lock') }}
|
||||
path: |
|
||||
**/node_modules
|
||||
key: compiler-node_modules-v5-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('compiler/**/yarn.lock') }}
|
||||
- run: yarn install --frozen-lockfile
|
||||
- run: npx playwright install --with-deps chromium
|
||||
- run: CI=true yarn test
|
||||
|
||||
5
.github/workflows/compiler_prereleases.yml
vendored
5
.github/workflows/compiler_prereleases.yml
vendored
@@ -46,8 +46,9 @@ jobs:
|
||||
uses: actions/cache@v4
|
||||
id: node_modules
|
||||
with:
|
||||
path: "**/node_modules"
|
||||
key: compiler-node_modules-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('compiler/**/yarn.lock') }}
|
||||
path: |
|
||||
**/node_modules
|
||||
key: compiler-node_modules-v5-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('compiler/**/yarn.lock') }}
|
||||
- run: yarn install --frozen-lockfile
|
||||
- name: Publish packages to npm
|
||||
run: |
|
||||
|
||||
15
.github/workflows/compiler_typescript.yml
vendored
15
.github/workflows/compiler_typescript.yml
vendored
@@ -46,8 +46,9 @@ jobs:
|
||||
- name: Restore cached node_modules
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: "**/node_modules"
|
||||
key: compiler-node_modules-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('compiler/**/yarn.lock') }}
|
||||
path: |
|
||||
**/node_modules
|
||||
key: compiler-node_modules-v5-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('compiler/**/yarn.lock') }}
|
||||
- run: yarn install --frozen-lockfile
|
||||
- run: yarn workspace babel-plugin-react-compiler lint
|
||||
|
||||
@@ -66,8 +67,9 @@ jobs:
|
||||
uses: actions/cache@v4
|
||||
id: node_modules
|
||||
with:
|
||||
path: "**/node_modules"
|
||||
key: compiler-node_modules-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('compiler/**/yarn.lock') }}
|
||||
path: |
|
||||
**/node_modules
|
||||
key: compiler-node_modules-v5-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('compiler/**/yarn.lock') }}
|
||||
- run: yarn install --frozen-lockfile
|
||||
- run: yarn workspace babel-plugin-react-compiler jest
|
||||
|
||||
@@ -90,8 +92,9 @@ jobs:
|
||||
uses: actions/cache@v4
|
||||
id: node_modules
|
||||
with:
|
||||
path: "**/node_modules"
|
||||
key: compiler-node_modules-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('compiler/**/yarn.lock') }}
|
||||
path: |
|
||||
**/node_modules
|
||||
key: compiler-node_modules-v5-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('compiler/**/yarn.lock') }}
|
||||
- run: yarn install --frozen-lockfile
|
||||
- run: xvfb-run -a yarn workspace ${{ matrix.workspace_name }} test
|
||||
if: runner.os == 'Linux' && matrix.workspace_name == 'react-forgive'
|
||||
|
||||
23
.github/workflows/devtools_regression_tests.yml
vendored
23
.github/workflows/devtools_regression_tests.yml
vendored
@@ -29,13 +29,13 @@ jobs:
|
||||
uses: actions/cache@v4
|
||||
id: node_modules
|
||||
with:
|
||||
path: "**/node_modules"
|
||||
key: runtime-release-node_modules-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock', 'scripts/release/yarn.lock') }}
|
||||
path: |
|
||||
**/node_modules
|
||||
key: runtime-release-node_modules-v5-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock', 'scripts/release/yarn.lock') }}
|
||||
- name: Ensure clean build directory
|
||||
run: rm -rf build
|
||||
- run: yarn install --frozen-lockfile
|
||||
- run: yarn install --frozen-lockfile
|
||||
working-directory: scripts/release
|
||||
- run: yarn --cwd scripts/release install --frozen-lockfile
|
||||
- name: Download react-devtools artifacts for base revision
|
||||
run: |
|
||||
git fetch origin main
|
||||
@@ -63,8 +63,9 @@ jobs:
|
||||
uses: actions/cache@v4
|
||||
id: node_modules
|
||||
with:
|
||||
path: "**/node_modules"
|
||||
key: runtime-node_modules-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock') }}
|
||||
path: |
|
||||
**/node_modules
|
||||
key: runtime-node_modules-v5-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock') }}
|
||||
- name: Ensure clean build directory
|
||||
run: rm -rf build
|
||||
- run: yarn install --frozen-lockfile
|
||||
@@ -120,8 +121,9 @@ jobs:
|
||||
uses: actions/cache@v4
|
||||
id: node_modules
|
||||
with:
|
||||
path: "**/node_modules"
|
||||
key: runtime-node_modules-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock') }}
|
||||
path: |
|
||||
**/node_modules
|
||||
key: runtime-node_modules-v5-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock') }}
|
||||
- run: yarn install --frozen-lockfile
|
||||
- name: Restore all archived build artifacts
|
||||
uses: actions/download-artifact@v4
|
||||
@@ -154,8 +156,9 @@ jobs:
|
||||
uses: actions/cache@v4
|
||||
id: node_modules
|
||||
with:
|
||||
path: "**/node_modules"
|
||||
key: runtime-node_modules-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock') }}
|
||||
path: |
|
||||
**/node_modules
|
||||
key: runtime-node_modules-v5-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock') }}
|
||||
- run: yarn install --frozen-lockfile
|
||||
- name: Restore all archived build artifacts
|
||||
uses: actions/download-artifact@v4
|
||||
|
||||
95
.github/workflows/runtime_build_and_test.yml
vendored
95
.github/workflows/runtime_build_and_test.yml
vendored
@@ -55,8 +55,9 @@ jobs:
|
||||
uses: actions/cache@v4
|
||||
id: node_modules
|
||||
with:
|
||||
path: "**/node_modules"
|
||||
key: runtime-node_modules-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock') }}
|
||||
path: |
|
||||
**/node_modules
|
||||
key: runtime-node_modules-v5-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock') }}
|
||||
- name: Ensure clean build directory
|
||||
run: rm -rf build
|
||||
- run: yarn install --frozen-lockfile
|
||||
@@ -79,8 +80,9 @@ jobs:
|
||||
uses: actions/cache@v4
|
||||
id: node_modules
|
||||
with:
|
||||
path: "**/node_modules"
|
||||
key: runtime-node_modules-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock') }}
|
||||
path: |
|
||||
**/node_modules
|
||||
key: runtime-node_modules-v5-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock') }}
|
||||
- name: Ensure clean build directory
|
||||
run: rm -rf build
|
||||
- run: yarn install --frozen-lockfile
|
||||
@@ -105,8 +107,9 @@ jobs:
|
||||
uses: actions/cache@v4
|
||||
id: node_modules
|
||||
with:
|
||||
path: "**/node_modules"
|
||||
key: runtime-node_modules-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock') }}
|
||||
path: |
|
||||
**/node_modules
|
||||
key: runtime-node_modules-v5-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock') }}
|
||||
- name: Ensure clean build directory
|
||||
run: rm -rf build
|
||||
- run: yarn install --frozen-lockfile
|
||||
@@ -153,16 +156,20 @@ jobs:
|
||||
with:
|
||||
node-version-file: '.nvmrc'
|
||||
cache: yarn
|
||||
cache-dependency-path: yarn.lock
|
||||
cache-dependency-path: |
|
||||
yarn.lock
|
||||
compiler/yarn.lock
|
||||
- name: Restore cached node_modules
|
||||
uses: actions/cache@v4
|
||||
id: node_modules
|
||||
with:
|
||||
path: "**/node_modules"
|
||||
key: runtime-node_modules-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock') }}
|
||||
path: |
|
||||
**/node_modules
|
||||
key: runtime-and-compiler-node_modules-v5-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock', 'compiler/yarn.lock') }}
|
||||
- name: Ensure clean build directory
|
||||
run: rm -rf build
|
||||
- run: yarn install --frozen-lockfile
|
||||
- run: yarn --cwd compiler install --frozen-lockfile
|
||||
- run: yarn test ${{ matrix.params }} --ci --shard=${{ matrix.shard }}
|
||||
|
||||
# ----- BUILD -----
|
||||
@@ -183,7 +190,9 @@ jobs:
|
||||
with:
|
||||
node-version-file: '.nvmrc'
|
||||
cache: yarn
|
||||
cache-dependency-path: yarn.lock
|
||||
cache-dependency-path: |
|
||||
yarn.lock
|
||||
compiler/yarn.lock
|
||||
- uses: actions/setup-java@v4
|
||||
with:
|
||||
distribution: temurin
|
||||
@@ -192,11 +201,13 @@ jobs:
|
||||
uses: actions/cache@v4
|
||||
id: node_modules
|
||||
with:
|
||||
path: "**/node_modules"
|
||||
key: runtime-node_modules-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock') }}
|
||||
path: |
|
||||
**/node_modules
|
||||
key: runtime-and-compiler-node_modules-v5-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock', 'compiler/yarn.lock') }}
|
||||
- name: Ensure clean build directory
|
||||
run: rm -rf build
|
||||
- run: yarn install --frozen-lockfile
|
||||
- run: yarn --cwd compiler install --frozen-lockfile
|
||||
- run: yarn build --index=${{ matrix.worker_id }} --total=20 --r=${{ matrix.release_channel }} --ci
|
||||
env:
|
||||
CI: github
|
||||
@@ -261,16 +272,20 @@ jobs:
|
||||
with:
|
||||
node-version-file: '.nvmrc'
|
||||
cache: yarn
|
||||
cache-dependency-path: yarn.lock
|
||||
cache-dependency-path: |
|
||||
yarn.lock
|
||||
compiler/yarn.lock
|
||||
- name: Restore cached node_modules
|
||||
uses: actions/cache@v4
|
||||
id: node_modules
|
||||
with:
|
||||
path: "**/node_modules"
|
||||
key: runtime-node_modules-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock') }}
|
||||
path: |
|
||||
**/node_modules
|
||||
key: runtime-and-compiler-node_modules-v5-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock', 'compiler/yarn.lock') }}
|
||||
- name: Ensure clean build directory
|
||||
run: rm -rf build
|
||||
- run: yarn install --frozen-lockfile
|
||||
- run: yarn --cwd compiler install --frozen-lockfile
|
||||
- name: Restore archived build
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
@@ -298,8 +313,9 @@ jobs:
|
||||
uses: actions/cache@v4
|
||||
id: node_modules
|
||||
with:
|
||||
path: "**/node_modules"
|
||||
key: runtime-node_modules-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock') }}
|
||||
path: |
|
||||
**/node_modules
|
||||
key: runtime-node_modules-v5-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock') }}
|
||||
- name: Ensure clean build directory
|
||||
run: rm -rf build
|
||||
- run: yarn install --frozen-lockfile
|
||||
@@ -311,7 +327,7 @@ jobs:
|
||||
merge-multiple: true
|
||||
- name: Display structure of build
|
||||
run: ls -R build
|
||||
- run: echo ${{ github.sha }} >> build/COMMIT_SHA
|
||||
- run: echo ${{ github.event.pull_request.head.sha || github.sha }} >> build/COMMIT_SHA
|
||||
- name: Scrape warning messages
|
||||
run: |
|
||||
mkdir -p ./build/__test_utils__
|
||||
@@ -345,8 +361,9 @@ jobs:
|
||||
uses: actions/cache@v4
|
||||
id: node_modules
|
||||
with:
|
||||
path: "**/node_modules"
|
||||
key: runtime-node_modules-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock') }}
|
||||
path: |
|
||||
**/node_modules
|
||||
key: runtime-node_modules-v5-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock') }}
|
||||
- name: Ensure clean build directory
|
||||
run: rm -rf build
|
||||
- run: yarn install --frozen-lockfile
|
||||
@@ -380,8 +397,9 @@ jobs:
|
||||
uses: actions/cache@v4
|
||||
id: node_modules
|
||||
with:
|
||||
path: "**/node_modules"
|
||||
key: runtime-node_modules-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock') }}
|
||||
path: |
|
||||
**/node_modules
|
||||
key: runtime-node_modules-v5-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock') }}
|
||||
- name: Ensure clean build directory
|
||||
run: rm -rf build
|
||||
- run: yarn install --frozen-lockfile
|
||||
@@ -412,12 +430,12 @@ jobs:
|
||||
uses: actions/cache@v4
|
||||
id: node_modules
|
||||
with:
|
||||
path: "**/node_modules"
|
||||
key: fixtures_dom-node_modules-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock') }}
|
||||
path: |
|
||||
**/node_modules
|
||||
key: fixtures_dom-node_modules-v5-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock') }}
|
||||
- name: Ensure clean build directory
|
||||
run: rm -rf build
|
||||
- run: yarn install --frozen-lockfile
|
||||
working-directory: fixtures/dom
|
||||
- run: yarn --cwd fixtures/dom install --frozen-lockfile
|
||||
- name: Restore archived build
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
@@ -455,8 +473,9 @@ jobs:
|
||||
uses: actions/cache@v4
|
||||
id: node_modules
|
||||
with:
|
||||
path: "**/node_modules"
|
||||
key: fixtures_flight-node_modules-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock') }}
|
||||
path: |
|
||||
**/node_modules
|
||||
key: fixtures_flight-node_modules-v5-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock') }}
|
||||
- name: Ensure clean build directory
|
||||
run: rm -rf build
|
||||
- run: yarn install --frozen-lockfile
|
||||
@@ -517,8 +536,9 @@ jobs:
|
||||
uses: actions/cache@v4
|
||||
id: node_modules
|
||||
with:
|
||||
path: "**/node_modules"
|
||||
key: runtime-node_modules-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock') }}
|
||||
path: |
|
||||
**/node_modules
|
||||
key: runtime-node_modules-v5-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock') }}
|
||||
- name: Ensure clean build directory
|
||||
run: rm -rf build
|
||||
- run: yarn install --frozen-lockfile
|
||||
@@ -568,8 +588,9 @@ jobs:
|
||||
uses: actions/cache@v4
|
||||
id: node_modules
|
||||
with:
|
||||
path: "**/node_modules"
|
||||
key: runtime-node_modules-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock') }}
|
||||
path: |
|
||||
**/node_modules
|
||||
key: runtime-node_modules-v5-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock') }}
|
||||
- name: Ensure clean build directory
|
||||
run: rm -rf build
|
||||
- run: yarn install --frozen-lockfile
|
||||
@@ -605,12 +626,12 @@ jobs:
|
||||
uses: actions/cache@v4
|
||||
id: node_modules
|
||||
with:
|
||||
path: "**/node_modules"
|
||||
key: runtime-node_modules-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock') }}
|
||||
path: |
|
||||
**/node_modules
|
||||
key: runtime-node_modules-v5-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock') }}
|
||||
- name: Ensure clean build directory
|
||||
run: rm -rf build
|
||||
- run: yarn install --frozen-lockfile
|
||||
working-directory: scripts/release
|
||||
- run: yarn --cwd scripts/release install --frozen-lockfile
|
||||
- name: Download artifacts for base revision
|
||||
run: |
|
||||
GH_TOKEN=${{ github.token }} scripts/release/download-experimental-build.js --commit=$(git rev-parse ${{ github.event.pull_request.base.sha }})
|
||||
@@ -638,7 +659,7 @@ jobs:
|
||||
node ./scripts/print-warnings/print-warnings.js > build/__test_utils__/ReactAllWarnings.js
|
||||
- name: Display structure of build for PR
|
||||
run: ls -R build
|
||||
- run: echo ${{ github.sha }} >> build/COMMIT_SHA
|
||||
- run: echo ${{ github.event.pull_request.head.sha || github.sha }} >> build/COMMIT_SHA
|
||||
- run: node ./scripts/tasks/danger
|
||||
- name: Archive sizebot results
|
||||
uses: actions/upload-artifact@v4
|
||||
|
||||
56
.github/workflows/runtime_commit_artifacts.yml
vendored
56
.github/workflows/runtime_commit_artifacts.yml
vendored
@@ -16,6 +16,11 @@ on:
|
||||
required: true
|
||||
default: false
|
||||
type: boolean
|
||||
dry_run:
|
||||
description: Perform a dry run (run everything except push)
|
||||
required: true
|
||||
default: false
|
||||
type: boolean
|
||||
|
||||
env:
|
||||
TZ: /usr/share/zoneinfo/America/Los_Angeles
|
||||
@@ -73,15 +78,13 @@ jobs:
|
||||
uses: actions/cache@v4
|
||||
id: node_modules
|
||||
with:
|
||||
path: "**/node_modules"
|
||||
key: runtime-release-node_modules-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock', 'scripts/release/yarn.lock') }}
|
||||
path: |
|
||||
**/node_modules
|
||||
key: runtime-release-node_modules-v5-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock', 'scripts/release/yarn.lock') }}
|
||||
- name: Ensure clean build directory
|
||||
run: rm -rf build
|
||||
- run: yarn install --frozen-lockfile
|
||||
name: yarn install (react)
|
||||
- run: yarn install --frozen-lockfile
|
||||
name: yarn install (scripts/release)
|
||||
working-directory: scripts/release
|
||||
- run: yarn --cwd scripts/release install --frozen-lockfile
|
||||
- name: Download artifacts for base revision
|
||||
run: |
|
||||
GH_TOKEN=${{ github.token }} scripts/release/download-experimental-build.js --commit=${{ inputs.commit_sha || github.event.workflow_run.head_sha || github.sha }}
|
||||
@@ -107,9 +110,10 @@ jobs:
|
||||
mkdir ./compiled/facebook-www/__test_utils__
|
||||
mv build/__test_utils__/ReactAllWarnings.js ./compiled/facebook-www/__test_utils__/ReactAllWarnings.js
|
||||
|
||||
# Move eslint-plugin-react-hooks into facebook-www
|
||||
# Move eslint-plugin-react-hooks into eslint-plugin-react-hooks
|
||||
mkdir ./compiled/eslint-plugin-react-hooks
|
||||
mv build/oss-experimental/eslint-plugin-react-hooks/cjs/eslint-plugin-react-hooks.development.js \
|
||||
./compiled/facebook-www/eslint-plugin-react-hooks.js
|
||||
./compiled/eslint-plugin-react-hooks/index.js
|
||||
|
||||
# Move unstable_server-external-runtime.js into facebook-www
|
||||
mv build/oss-experimental/react-dom/unstable_server-external-runtime.js \
|
||||
@@ -244,16 +248,16 @@ jobs:
|
||||
git status -u
|
||||
- name: Commit changes to branch
|
||||
if: inputs.force == true || steps.check_should_commit.outputs.should_commit == 'true'
|
||||
uses: stefanzweifel/git-auto-commit-action@v5
|
||||
with:
|
||||
commit_message: |
|
||||
${{ github.event.workflow_run.head_commit.message || format('Manual build of {0}', github.event.workflow_run.head_sha || github.sha) }}
|
||||
run: |
|
||||
git config --global user.email "${{ format('{0}@users.noreply.github.com', github.triggering_actor) }}"
|
||||
git config --global user.name "${{ github.triggering_actor }}"
|
||||
|
||||
DiffTrain build for [${{ github.event.workflow_run.head_sha || github.sha }}](https://github.com/facebook/react/commit/${{ github.event.workflow_run.head_sha || github.sha }})
|
||||
branch: builds/facebook-www
|
||||
commit_user_name: ${{ github.triggering_actor }}
|
||||
commit_user_email: ${{ format('{0}@users.noreply.github.com', github.triggering_actor) }}
|
||||
create_branch: true
|
||||
git commit -m "${{ github.event.workflow_run.head_commit.message || format('Manual build of {0}', github.event.workflow_run.head_sha || github.sha) }}
|
||||
|
||||
DiffTrain build for [${{ github.event.workflow_run.head_sha || github.sha }}](https://github.com/facebook/react/commit/${{ github.event.workflow_run.head_sha || github.sha }})" || echo "No changes to commit"
|
||||
- name: Push changes to branch
|
||||
if: inputs.dry_run == false && (inputs.force == true || steps.check_should_commit.outputs.should_commit == 'true')
|
||||
run: git push
|
||||
|
||||
commit_fbsource_artifacts:
|
||||
needs: download_artifacts
|
||||
@@ -411,13 +415,13 @@ jobs:
|
||||
git status
|
||||
- name: Commit changes to branch
|
||||
if: inputs.force == true || steps.check_should_commit.outputs.should_commit == 'true'
|
||||
uses: stefanzweifel/git-auto-commit-action@v5
|
||||
with:
|
||||
commit_message: |
|
||||
${{ github.event.workflow_run.head_commit.message || format('Manual build of {0}', github.event.workflow_run.head_sha || github.sha) }}
|
||||
run: |
|
||||
git config --global user.email "${{ format('{0}@users.noreply.github.com', github.triggering_actor) }}"
|
||||
git config --global user.name "${{ github.triggering_actor }}"
|
||||
|
||||
DiffTrain build for [${{ github.event.workflow_run.head_sha || github.sha }}](https://github.com/facebook/react/commit/${{ github.event.workflow_run.head_sha || github.sha }})
|
||||
branch: builds/facebook-fbsource
|
||||
commit_user_name: ${{ github.triggering_actor }}
|
||||
commit_user_email: ${{ format('{0}@users.noreply.github.com', github.triggering_actor) }}
|
||||
create_branch: true
|
||||
git commit -m "${{ github.event.workflow_run.head_commit.message || format('Manual build of {0}', github.event.workflow_run.head_sha || github.sha) }}
|
||||
|
||||
DiffTrain build for [${{ github.event.workflow_run.head_sha || github.sha }}](https://github.com/facebook/react/commit/${{ github.event.workflow_run.head_sha || github.sha }})" || echo "No changes to commit"
|
||||
- name: Push changes to branch
|
||||
if: inputs.dry_run == false && (inputs.force == true || steps.check_should_commit.outputs.should_commit == 'true')
|
||||
run: git push
|
||||
|
||||
2
.github/workflows/runtime_discord_notify.yml
vendored
2
.github/workflows/runtime_discord_notify.yml
vendored
@@ -19,7 +19,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Discord Webhook Action
|
||||
uses: tsickert/discord-webhook@v6.0.0
|
||||
uses: tsickert/discord-webhook@86dc739f3f165f16dadc5666051c367efa1692f4
|
||||
with:
|
||||
webhook-url: ${{ secrets.DISCORD_WEBHOOK_URL }}
|
||||
embed-author-name: ${{ github.event.pull_request.user.login }}
|
||||
|
||||
10
.github/workflows/runtime_eslint_plugin_e2e.yml
vendored
10
.github/workflows/runtime_eslint_plugin_e2e.yml
vendored
@@ -35,16 +35,20 @@ jobs:
|
||||
with:
|
||||
node-version-file: '.nvmrc'
|
||||
cache: yarn
|
||||
cache-dependency-path: yarn.lock
|
||||
cache-dependency-path: |
|
||||
yarn.lock
|
||||
compiler/yarn.lock
|
||||
- name: Restore cached node_modules
|
||||
uses: actions/cache@v4
|
||||
id: node_modules
|
||||
with:
|
||||
path: "node_modules"
|
||||
key: runtime-eslint_e2e-node_modules-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock') }}
|
||||
path: |
|
||||
**/node_modules
|
||||
key: runtime-and-compiler-eslint_e2e-node_modules-v5-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock', 'compiler/yarn.lock') }}
|
||||
- name: Ensure clean build directory
|
||||
run: rm -rf build
|
||||
- run: yarn install --frozen-lockfile
|
||||
- run: yarn --cwd compiler install --frozen-lockfile
|
||||
- name: Build plugin
|
||||
working-directory: fixtures/eslint-v${{ matrix.eslint_major }}
|
||||
run: node build.mjs
|
||||
|
||||
8
.github/workflows/runtime_prereleases.yml
vendored
8
.github/workflows/runtime_prereleases.yml
vendored
@@ -39,13 +39,13 @@ jobs:
|
||||
uses: actions/cache@v4
|
||||
id: node_modules
|
||||
with:
|
||||
path: "**/node_modules"
|
||||
key: runtime-release-node_modules-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock', 'scripts/release/yarn.lock') }}
|
||||
path: |
|
||||
**/node_modules
|
||||
key: runtime-release-node_modules-v5-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock', 'scripts/release/yarn.lock') }}
|
||||
- name: Ensure clean build directory
|
||||
run: rm -rf build
|
||||
- run: yarn install --frozen-lockfile
|
||||
- run: yarn install --frozen-lockfile
|
||||
working-directory: scripts/release
|
||||
- run: yarn --cwd scripts/release install --frozen-lockfile
|
||||
- run: |
|
||||
scripts/release/prepare-release-from-ci.js --skipTests -r ${{ inputs.release_channel }} --commit=${{ inputs.commit_sha }}
|
||||
cp ./scripts/release/ci-npmrc ~/.npmrc
|
||||
|
||||
@@ -44,7 +44,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Discord Webhook Action
|
||||
uses: tsickert/discord-webhook@v6.0.0
|
||||
uses: tsickert/discord-webhook@86dc739f3f165f16dadc5666051c367efa1692f4
|
||||
with:
|
||||
webhook-url: ${{ secrets.DISCORD_WEBHOOK_URL }}
|
||||
embed-author-name: ${{ github.event.sender.login }}
|
||||
@@ -71,13 +71,13 @@ jobs:
|
||||
uses: actions/cache@v4
|
||||
id: node_modules
|
||||
with:
|
||||
path: "**/node_modules"
|
||||
key: runtime-release-node_modules-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock', 'scripts/release/yarn.lock') }}
|
||||
path: |
|
||||
**/node_modules
|
||||
key: runtime-release-node_modules-v5-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock', 'scripts/release/yarn.lock') }}
|
||||
- name: Ensure clean build directory
|
||||
run: rm -rf build
|
||||
- run: yarn install --frozen-lockfile
|
||||
- run: yarn install --frozen-lockfile
|
||||
working-directory: scripts/release
|
||||
- run: yarn --cwd scripts/release install --frozen-lockfile
|
||||
- run: cp ./scripts/release/ci-npmrc ~/.npmrc
|
||||
- if: '${{ inputs.only_packages }}'
|
||||
name: 'Prepare ${{ inputs.only_packages }} from NPM'
|
||||
|
||||
20
.github/workflows/shared_lint.yml
vendored
20
.github/workflows/shared_lint.yml
vendored
@@ -28,8 +28,9 @@ jobs:
|
||||
- name: Restore cached node_modules
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: "**/node_modules"
|
||||
key: shared-lint-node_modules-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('**/yarn.lock') }}
|
||||
path: |
|
||||
**/node_modules
|
||||
key: shared-lint-node_modules-v5-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('**/yarn.lock') }}
|
||||
- name: Ensure clean build directory
|
||||
run: rm -rf build
|
||||
- run: yarn install --frozen-lockfile
|
||||
@@ -48,8 +49,9 @@ jobs:
|
||||
- name: Restore cached node_modules
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: "**/node_modules"
|
||||
key: shared-lint-node_modules-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('**/yarn.lock') }}
|
||||
path: |
|
||||
**/node_modules
|
||||
key: shared-lint-node_modules-v5-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('**/yarn.lock') }}
|
||||
- name: Ensure clean build directory
|
||||
run: rm -rf build
|
||||
- run: yarn install --frozen-lockfile
|
||||
@@ -68,8 +70,9 @@ jobs:
|
||||
- name: Restore cached node_modules
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: "**/node_modules"
|
||||
key: shared-lint-node_modules-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('**/yarn.lock') }}
|
||||
path: |
|
||||
**/node_modules
|
||||
key: shared-lint-node_modules-v5-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('**/yarn.lock') }}
|
||||
- name: Ensure clean build directory
|
||||
run: rm -rf build
|
||||
- run: yarn install --frozen-lockfile
|
||||
@@ -88,8 +91,9 @@ jobs:
|
||||
- name: Restore cached node_modules
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: "**/node_modules"
|
||||
key: shared-lint-node_modules-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('**/yarn.lock') }}
|
||||
path: |
|
||||
**/node_modules
|
||||
key: shared-lint-node_modules-v5-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('**/yarn.lock') }}
|
||||
- name: Ensure clean build directory
|
||||
run: rm -rf build
|
||||
- run: yarn install --frozen-lockfile
|
||||
|
||||
@@ -4,8 +4,7 @@ module.exports = {
|
||||
plugins: [
|
||||
'@babel/plugin-syntax-jsx',
|
||||
'@babel/plugin-transform-flow-strip-types',
|
||||
['@babel/plugin-transform-class-properties', {loose: true}],
|
||||
'@babel/plugin-transform-classes',
|
||||
['@babel/plugin-proposal-class-properties', {loose: true}],
|
||||
'syntax-trailing-function-commas',
|
||||
[
|
||||
'@babel/plugin-proposal-object-rest-spread',
|
||||
|
||||
@@ -181,6 +181,7 @@ function ReactForgetFunctionTransform() {
|
||||
fn,
|
||||
forgetOptions,
|
||||
'Other',
|
||||
'all_features',
|
||||
'_c',
|
||||
null,
|
||||
null,
|
||||
|
||||
@@ -11,6 +11,7 @@ import {
|
||||
injectReanimatedFlag,
|
||||
pipelineUsesReanimatedPlugin,
|
||||
} from '../Entrypoint/Reanimated';
|
||||
import validateNoUntransformedReferences from '../Entrypoint/ValidateNoUntransformedReferences';
|
||||
|
||||
const ENABLE_REACT_COMPILER_TIMINGS =
|
||||
process.env['ENABLE_REACT_COMPILER_TIMINGS'] === '1';
|
||||
@@ -61,12 +62,19 @@ export default function BabelPluginReactCompiler(
|
||||
},
|
||||
};
|
||||
}
|
||||
compileProgram(prog, {
|
||||
const result = compileProgram(prog, {
|
||||
opts,
|
||||
filename: pass.filename ?? null,
|
||||
comments: pass.file.ast.comments ?? [],
|
||||
code: pass.file.code,
|
||||
});
|
||||
validateNoUntransformedReferences(
|
||||
prog,
|
||||
pass.filename ?? null,
|
||||
opts.logger,
|
||||
opts.environment,
|
||||
result?.retryErrors ?? [],
|
||||
);
|
||||
if (ENABLE_REACT_COMPILER_TIMINGS === true) {
|
||||
performance.mark(`${filename}:end`, {
|
||||
detail: 'BabelPlugin:Program:end',
|
||||
|
||||
@@ -8,7 +8,119 @@
|
||||
import {NodePath} from '@babel/core';
|
||||
import * as t from '@babel/types';
|
||||
import {PluginOptions} from './Options';
|
||||
import {CompilerError} from '../CompilerError';
|
||||
|
||||
/**
|
||||
* Gating rewrite for function declarations which are referenced before their
|
||||
* declaration site.
|
||||
*
|
||||
* ```js
|
||||
* // original
|
||||
* export default React.memo(Foo);
|
||||
* function Foo() { ... }
|
||||
*
|
||||
* // React compiler optimized + gated
|
||||
* import {gating} from 'myGating';
|
||||
* export default React.memo(Foo);
|
||||
* const gating_result = gating(); <- inserted
|
||||
* function Foo_optimized() {} <- inserted
|
||||
* function Foo_unoptimized() {} <- renamed from Foo
|
||||
* function Foo() { <- inserted function, which can be hoisted by JS engines
|
||||
* if (gating_result) return Foo_optimized();
|
||||
* else return Foo_unoptimized();
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
function insertAdditionalFunctionDeclaration(
|
||||
fnPath: NodePath<t.FunctionDeclaration>,
|
||||
compiled: t.FunctionDeclaration,
|
||||
gating: NonNullable<PluginOptions['gating']>,
|
||||
): void {
|
||||
const originalFnName = fnPath.node.id;
|
||||
const originalFnParams = fnPath.node.params;
|
||||
const compiledParams = fnPath.node.params;
|
||||
/**
|
||||
* Note that other than `export default function() {}`, all other function
|
||||
* declarations must have a binding identifier. Since default exports cannot
|
||||
* be referenced, it's safe to assume that all function declarations passed
|
||||
* here will have an identifier.
|
||||
* https://tc39.es/ecma262/multipage/ecmascript-language-functions-and-classes.html#sec-function-definitions
|
||||
*/
|
||||
CompilerError.invariant(originalFnName != null && compiled.id != null, {
|
||||
reason:
|
||||
'Expected function declarations that are referenced elsewhere to have a named identifier',
|
||||
loc: fnPath.node.loc ?? null,
|
||||
});
|
||||
CompilerError.invariant(originalFnParams.length === compiledParams.length, {
|
||||
reason:
|
||||
'Expected React Compiler optimized function declarations to have the same number of parameters as source',
|
||||
loc: fnPath.node.loc ?? null,
|
||||
});
|
||||
|
||||
const gatingCondition = fnPath.scope.generateUidIdentifier(
|
||||
`${gating.importSpecifierName}_result`,
|
||||
);
|
||||
const unoptimizedFnName = fnPath.scope.generateUidIdentifier(
|
||||
`${originalFnName.name}_unoptimized`,
|
||||
);
|
||||
const optimizedFnName = fnPath.scope.generateUidIdentifier(
|
||||
`${originalFnName.name}_optimized`,
|
||||
);
|
||||
/**
|
||||
* Step 1: rename existing functions
|
||||
*/
|
||||
compiled.id.name = optimizedFnName.name;
|
||||
fnPath.get('id').replaceInline(unoptimizedFnName);
|
||||
|
||||
/**
|
||||
* Step 2: insert new function declaration
|
||||
*/
|
||||
const newParams: Array<t.Identifier | t.RestElement> = [];
|
||||
const genNewArgs: Array<() => t.Identifier | t.SpreadElement> = [];
|
||||
for (let i = 0; i < originalFnParams.length; i++) {
|
||||
const argName = `arg${i}`;
|
||||
if (originalFnParams[i].type === 'RestElement') {
|
||||
newParams.push(t.restElement(t.identifier(argName)));
|
||||
genNewArgs.push(() => t.spreadElement(t.identifier(argName)));
|
||||
} else {
|
||||
newParams.push(t.identifier(argName));
|
||||
genNewArgs.push(() => t.identifier(argName));
|
||||
}
|
||||
}
|
||||
// insertAfter called in reverse order of how nodes should appear in program
|
||||
fnPath.insertAfter(
|
||||
t.functionDeclaration(
|
||||
originalFnName,
|
||||
newParams,
|
||||
t.blockStatement([
|
||||
t.ifStatement(
|
||||
gatingCondition,
|
||||
t.returnStatement(
|
||||
t.callExpression(
|
||||
compiled.id,
|
||||
genNewArgs.map(fn => fn()),
|
||||
),
|
||||
),
|
||||
t.returnStatement(
|
||||
t.callExpression(
|
||||
unoptimizedFnName,
|
||||
genNewArgs.map(fn => fn()),
|
||||
),
|
||||
),
|
||||
),
|
||||
]),
|
||||
),
|
||||
);
|
||||
fnPath.insertBefore(
|
||||
t.variableDeclaration('const', [
|
||||
t.variableDeclarator(
|
||||
gatingCondition,
|
||||
t.callExpression(t.identifier(gating.importSpecifierName), []),
|
||||
),
|
||||
]),
|
||||
);
|
||||
fnPath.insertBefore(compiled);
|
||||
}
|
||||
export function insertGatedFunctionDeclaration(
|
||||
fnPath: NodePath<
|
||||
t.FunctionDeclaration | t.ArrowFunctionExpression | t.FunctionExpression
|
||||
@@ -18,47 +130,57 @@ export function insertGatedFunctionDeclaration(
|
||||
| t.ArrowFunctionExpression
|
||||
| t.FunctionExpression,
|
||||
gating: NonNullable<PluginOptions['gating']>,
|
||||
referencedBeforeDeclaration: boolean,
|
||||
): void {
|
||||
const gatingExpression = t.conditionalExpression(
|
||||
t.callExpression(t.identifier(gating.importSpecifierName), []),
|
||||
buildFunctionExpression(compiled),
|
||||
buildFunctionExpression(fnPath.node),
|
||||
);
|
||||
|
||||
/*
|
||||
* Convert function declarations to named variables *unless* this is an
|
||||
* `export default function ...` since `export default const ...` is
|
||||
* not supported. For that case we fall through to replacing w the raw
|
||||
* conditional expression
|
||||
*/
|
||||
if (
|
||||
fnPath.parentPath.node.type !== 'ExportDefaultDeclaration' &&
|
||||
fnPath.node.type === 'FunctionDeclaration' &&
|
||||
fnPath.node.id != null
|
||||
) {
|
||||
fnPath.replaceWith(
|
||||
t.variableDeclaration('const', [
|
||||
t.variableDeclarator(fnPath.node.id, gatingExpression),
|
||||
]),
|
||||
);
|
||||
} else if (
|
||||
fnPath.parentPath.node.type === 'ExportDefaultDeclaration' &&
|
||||
fnPath.node.type !== 'ArrowFunctionExpression' &&
|
||||
fnPath.node.id != null
|
||||
) {
|
||||
fnPath.insertAfter(
|
||||
t.exportDefaultDeclaration(t.identifier(fnPath.node.id.name)),
|
||||
);
|
||||
fnPath.parentPath.replaceWith(
|
||||
t.variableDeclaration('const', [
|
||||
t.variableDeclarator(
|
||||
t.identifier(fnPath.node.id.name),
|
||||
gatingExpression,
|
||||
),
|
||||
]),
|
||||
);
|
||||
if (referencedBeforeDeclaration && fnPath.isFunctionDeclaration()) {
|
||||
CompilerError.invariant(compiled.type === 'FunctionDeclaration', {
|
||||
reason: 'Expected compiled node type to match input type',
|
||||
description: `Got ${compiled.type} but expected FunctionDeclaration`,
|
||||
loc: fnPath.node.loc ?? null,
|
||||
});
|
||||
insertAdditionalFunctionDeclaration(fnPath, compiled, gating);
|
||||
} else {
|
||||
fnPath.replaceWith(gatingExpression);
|
||||
const gatingExpression = t.conditionalExpression(
|
||||
t.callExpression(t.identifier(gating.importSpecifierName), []),
|
||||
buildFunctionExpression(compiled),
|
||||
buildFunctionExpression(fnPath.node),
|
||||
);
|
||||
|
||||
/*
|
||||
* Convert function declarations to named variables *unless* this is an
|
||||
* `export default function ...` since `export default const ...` is
|
||||
* not supported. For that case we fall through to replacing w the raw
|
||||
* conditional expression
|
||||
*/
|
||||
if (
|
||||
fnPath.parentPath.node.type !== 'ExportDefaultDeclaration' &&
|
||||
fnPath.node.type === 'FunctionDeclaration' &&
|
||||
fnPath.node.id != null
|
||||
) {
|
||||
fnPath.replaceWith(
|
||||
t.variableDeclaration('const', [
|
||||
t.variableDeclarator(fnPath.node.id, gatingExpression),
|
||||
]),
|
||||
);
|
||||
} else if (
|
||||
fnPath.parentPath.node.type === 'ExportDefaultDeclaration' &&
|
||||
fnPath.node.type !== 'ArrowFunctionExpression' &&
|
||||
fnPath.node.id != null
|
||||
) {
|
||||
fnPath.insertAfter(
|
||||
t.exportDefaultDeclaration(t.identifier(fnPath.node.id.name)),
|
||||
);
|
||||
fnPath.parentPath.replaceWith(
|
||||
t.variableDeclaration('const', [
|
||||
t.variableDeclarator(
|
||||
t.identifier(fnPath.node.id.name),
|
||||
gatingExpression,
|
||||
),
|
||||
]),
|
||||
);
|
||||
} else {
|
||||
fnPath.replaceWith(gatingExpression);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@ import {
|
||||
EnvironmentConfig,
|
||||
ExternalFunction,
|
||||
parseEnvironmentConfig,
|
||||
tryParseExternalFunction,
|
||||
} from '../HIR/Environment';
|
||||
import {hasOwnProperty} from '../Utils/utils';
|
||||
import {fromZodError} from 'zod-validation-error';
|
||||
@@ -271,6 +272,14 @@ export function parsePluginOptions(obj: unknown): PluginOptions {
|
||||
parsedOptions[key] = parseTargetConfig(value);
|
||||
break;
|
||||
}
|
||||
case 'gating': {
|
||||
if (value == null) {
|
||||
parsedOptions[key] = null;
|
||||
} else {
|
||||
parsedOptions[key] = tryParseExternalFunction(value);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
parsedOptions[key] = value;
|
||||
}
|
||||
|
||||
@@ -24,6 +24,7 @@ import {
|
||||
pruneUnusedLabelsHIR,
|
||||
} from '../HIR';
|
||||
import {
|
||||
CompilerMode,
|
||||
Environment,
|
||||
EnvironmentConfig,
|
||||
ReactFunctionType,
|
||||
@@ -100,6 +101,7 @@ import {outlineJSX} from '../Optimization/OutlineJsx';
|
||||
import {optimizePropsMethodCalls} from '../Optimization/OptimizePropsMethodCalls';
|
||||
import {transformFire} from '../Transform';
|
||||
import {validateNoImpureFunctionsInRender} from '../Validation/ValiateNoImpureFunctionsInRender';
|
||||
import {CompilerError} from '..';
|
||||
|
||||
export type CompilerPipelineValue =
|
||||
| {kind: 'ast'; name: string; value: CodegenFunction}
|
||||
@@ -113,6 +115,7 @@ function run(
|
||||
>,
|
||||
config: EnvironmentConfig,
|
||||
fnType: ReactFunctionType,
|
||||
mode: CompilerMode,
|
||||
useMemoCacheIdentifier: string,
|
||||
logger: Logger | null,
|
||||
filename: string | null,
|
||||
@@ -122,6 +125,7 @@ function run(
|
||||
const env = new Environment(
|
||||
func.scope,
|
||||
fnType,
|
||||
mode,
|
||||
config,
|
||||
contextIdentifiers,
|
||||
logger,
|
||||
@@ -160,10 +164,10 @@ function runWithEnvironment(
|
||||
validateUseMemo(hir);
|
||||
|
||||
if (
|
||||
env.isInferredMemoEnabled &&
|
||||
!env.config.enablePreserveExistingManualUseMemo &&
|
||||
!env.config.disableMemoizationForDebugging &&
|
||||
!env.config.enableChangeDetectionForDebugging &&
|
||||
!env.config.enableMinimalTransformsForRetry
|
||||
!env.config.enableChangeDetectionForDebugging
|
||||
) {
|
||||
dropManualMemoization(hir);
|
||||
log({kind: 'hir', name: 'DropManualMemoization', value: hir});
|
||||
@@ -196,8 +200,13 @@ function runWithEnvironment(
|
||||
inferTypes(hir);
|
||||
log({kind: 'hir', name: 'InferTypes', value: hir});
|
||||
|
||||
if (env.config.validateHooksUsage) {
|
||||
validateHooksUsage(hir);
|
||||
if (env.isInferredMemoEnabled) {
|
||||
if (env.config.validateHooksUsage) {
|
||||
validateHooksUsage(hir);
|
||||
}
|
||||
if (env.config.validateNoCapitalizedCalls) {
|
||||
validateNoCapitalizedCalls(hir);
|
||||
}
|
||||
}
|
||||
|
||||
if (env.config.enableFire) {
|
||||
@@ -205,10 +214,6 @@ function runWithEnvironment(
|
||||
log({kind: 'hir', name: 'TransformFire', value: hir});
|
||||
}
|
||||
|
||||
if (env.config.validateNoCapitalizedCalls) {
|
||||
validateNoCapitalizedCalls(hir);
|
||||
}
|
||||
|
||||
if (env.config.lowerContextAccess) {
|
||||
lowerContextAccess(hir, env.config.lowerContextAccess);
|
||||
}
|
||||
@@ -219,7 +224,12 @@ function runWithEnvironment(
|
||||
analyseFunctions(hir);
|
||||
log({kind: 'hir', name: 'AnalyseFunctions', value: hir});
|
||||
|
||||
inferReferenceEffects(hir);
|
||||
const fnEffectErrors = inferReferenceEffects(hir);
|
||||
if (env.isInferredMemoEnabled) {
|
||||
if (fnEffectErrors.length > 0) {
|
||||
CompilerError.throw(fnEffectErrors[0]);
|
||||
}
|
||||
}
|
||||
log({kind: 'hir', name: 'InferReferenceEffects', value: hir});
|
||||
|
||||
validateLocalsNotReassignedAfterRender(hir);
|
||||
@@ -239,28 +249,30 @@ function runWithEnvironment(
|
||||
inferMutableRanges(hir);
|
||||
log({kind: 'hir', name: 'InferMutableRanges', value: hir});
|
||||
|
||||
if (env.config.assertValidMutableRanges) {
|
||||
assertValidMutableRanges(hir);
|
||||
}
|
||||
if (env.isInferredMemoEnabled) {
|
||||
if (env.config.assertValidMutableRanges) {
|
||||
assertValidMutableRanges(hir);
|
||||
}
|
||||
|
||||
if (env.config.validateRefAccessDuringRender) {
|
||||
validateNoRefAccessInRender(hir);
|
||||
}
|
||||
if (env.config.validateRefAccessDuringRender) {
|
||||
validateNoRefAccessInRender(hir);
|
||||
}
|
||||
|
||||
if (env.config.validateNoSetStateInRender) {
|
||||
validateNoSetStateInRender(hir);
|
||||
}
|
||||
if (env.config.validateNoSetStateInRender) {
|
||||
validateNoSetStateInRender(hir);
|
||||
}
|
||||
|
||||
if (env.config.validateNoSetStateInPassiveEffects) {
|
||||
validateNoSetStateInPassiveEffects(hir);
|
||||
}
|
||||
if (env.config.validateNoSetStateInPassiveEffects) {
|
||||
validateNoSetStateInPassiveEffects(hir);
|
||||
}
|
||||
|
||||
if (env.config.validateNoJSXInTryStatements) {
|
||||
validateNoJSXInTryStatement(hir);
|
||||
}
|
||||
if (env.config.validateNoJSXInTryStatements) {
|
||||
validateNoJSXInTryStatement(hir);
|
||||
}
|
||||
|
||||
if (env.config.validateNoImpureFunctionsInRender) {
|
||||
validateNoImpureFunctionsInRender(hir);
|
||||
if (env.config.validateNoImpureFunctionsInRender) {
|
||||
validateNoImpureFunctionsInRender(hir);
|
||||
}
|
||||
}
|
||||
|
||||
inferReactivePlaces(hir);
|
||||
@@ -280,7 +292,12 @@ function runWithEnvironment(
|
||||
value: hir,
|
||||
});
|
||||
|
||||
if (!env.config.enableMinimalTransformsForRetry) {
|
||||
if (env.isInferredMemoEnabled) {
|
||||
/**
|
||||
* Only create reactive scopes (which directly map to generated memo blocks)
|
||||
* if inferred memoization is enabled. This makes all later passes which
|
||||
* transform reactive-scope labeled instructions no-ops.
|
||||
*/
|
||||
inferReactiveScopeVariables(hir);
|
||||
log({kind: 'hir', name: 'InferReactiveScopeVariables', value: hir});
|
||||
}
|
||||
@@ -529,6 +546,7 @@ export function compileFn(
|
||||
>,
|
||||
config: EnvironmentConfig,
|
||||
fnType: ReactFunctionType,
|
||||
mode: CompilerMode,
|
||||
useMemoCacheIdentifier: string,
|
||||
logger: Logger | null,
|
||||
filename: string | null,
|
||||
@@ -538,6 +556,7 @@ export function compileFn(
|
||||
func,
|
||||
config,
|
||||
fnType,
|
||||
mode,
|
||||
useMemoCacheIdentifier,
|
||||
logger,
|
||||
filename,
|
||||
|
||||
@@ -16,8 +16,6 @@ import {
|
||||
EnvironmentConfig,
|
||||
ExternalFunction,
|
||||
ReactFunctionType,
|
||||
MINIMAL_RETRY_CONFIG,
|
||||
tryParseExternalFunction,
|
||||
} from '../HIR/Environment';
|
||||
import {CodegenFunction} from '../ReactiveScopes';
|
||||
import {isComponentDeclaration} from '../Utils/ComponentDeclaration';
|
||||
@@ -273,6 +271,9 @@ function isFilePartOfSources(
|
||||
return false;
|
||||
}
|
||||
|
||||
type CompileProgramResult = {
|
||||
retryErrors: Array<{fn: BabelFn; error: CompilerError}>;
|
||||
};
|
||||
/**
|
||||
* `compileProgram` is directly invoked by the react-compiler babel plugin, so
|
||||
* exceptions thrown by this function will fail the babel build.
|
||||
@@ -287,16 +288,16 @@ function isFilePartOfSources(
|
||||
export function compileProgram(
|
||||
program: NodePath<t.Program>,
|
||||
pass: CompilerPass,
|
||||
): void {
|
||||
): CompileProgramResult | null {
|
||||
if (shouldSkipCompilation(program, pass)) {
|
||||
return;
|
||||
return null;
|
||||
}
|
||||
|
||||
const environment = pass.opts.environment;
|
||||
const restrictedImportsErr = validateRestrictedImports(program, environment);
|
||||
if (restrictedImportsErr) {
|
||||
handleError(restrictedImportsErr, pass, null);
|
||||
return;
|
||||
return null;
|
||||
}
|
||||
const useMemoCacheIdentifier = program.scope.generateUidIdentifier('c');
|
||||
|
||||
@@ -367,7 +368,7 @@ export function compileProgram(
|
||||
filename: pass.filename ?? null,
|
||||
},
|
||||
);
|
||||
|
||||
const retryErrors: Array<{fn: BabelFn; error: CompilerError}> = [];
|
||||
const processFn = (
|
||||
fn: BabelFn,
|
||||
fnType: ReactFunctionType,
|
||||
@@ -408,6 +409,7 @@ export function compileProgram(
|
||||
fn,
|
||||
environment,
|
||||
fnType,
|
||||
'all_features',
|
||||
useMemoCacheIdentifier.name,
|
||||
pass.opts.logger,
|
||||
pass.filename,
|
||||
@@ -418,28 +420,7 @@ export function compileProgram(
|
||||
compileResult = {kind: 'error', error: err};
|
||||
}
|
||||
}
|
||||
// If non-memoization features are enabled, retry regardless of error kind
|
||||
if (compileResult.kind === 'error' && environment.enableFire) {
|
||||
try {
|
||||
compileResult = {
|
||||
kind: 'compile',
|
||||
compiledFn: compileFn(
|
||||
fn,
|
||||
{
|
||||
...environment,
|
||||
...MINIMAL_RETRY_CONFIG,
|
||||
},
|
||||
fnType,
|
||||
useMemoCacheIdentifier.name,
|
||||
pass.opts.logger,
|
||||
pass.filename,
|
||||
pass.code,
|
||||
),
|
||||
};
|
||||
} catch (err) {
|
||||
compileResult = {kind: 'error', error: err};
|
||||
}
|
||||
}
|
||||
|
||||
if (compileResult.kind === 'error') {
|
||||
/**
|
||||
* If an opt out directive is present, log only instead of throwing and don't mark as
|
||||
@@ -450,7 +431,33 @@ export function compileProgram(
|
||||
} else {
|
||||
handleError(compileResult.error, pass, fn.node.loc ?? null);
|
||||
}
|
||||
return null;
|
||||
// If non-memoization features are enabled, retry regardless of error kind
|
||||
if (
|
||||
!(environment.enableFire || environment.inferEffectDependencies != null)
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
compileResult = {
|
||||
kind: 'compile',
|
||||
compiledFn: compileFn(
|
||||
fn,
|
||||
environment,
|
||||
fnType,
|
||||
'no_inferred_memo',
|
||||
useMemoCacheIdentifier.name,
|
||||
pass.opts.logger,
|
||||
pass.filename,
|
||||
pass.code,
|
||||
),
|
||||
};
|
||||
} catch (err) {
|
||||
// TODO: we might want to log error here, but this will also result in duplicate logging
|
||||
if (err instanceof CompilerError) {
|
||||
retryErrors.push({fn, error: err});
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
pass.opts.logger?.logEvent(pass.filename, {
|
||||
@@ -539,32 +546,28 @@ export function compileProgram(
|
||||
program.node.directives,
|
||||
);
|
||||
if (moduleScopeOptOutDirectives.length > 0) {
|
||||
return;
|
||||
return null;
|
||||
}
|
||||
|
||||
let gating: null | {
|
||||
gatingFn: ExternalFunction;
|
||||
referencedBeforeDeclared: Set<CompileResult>;
|
||||
} = null;
|
||||
if (pass.opts.gating != null) {
|
||||
const error = checkFunctionReferencedBeforeDeclarationAtTopLevel(
|
||||
program,
|
||||
compiledFns.map(result => {
|
||||
return result.originalFn;
|
||||
}),
|
||||
);
|
||||
if (error) {
|
||||
handleError(error, pass, null);
|
||||
return;
|
||||
}
|
||||
gating = {
|
||||
gatingFn: pass.opts.gating,
|
||||
referencedBeforeDeclared:
|
||||
getFunctionReferencedBeforeDeclarationAtTopLevel(program, compiledFns),
|
||||
};
|
||||
}
|
||||
|
||||
const hasLoweredContextAccess = compiledFns.some(
|
||||
c => c.compiledFn.hasLoweredContextAccess,
|
||||
);
|
||||
const externalFunctions: Array<ExternalFunction> = [];
|
||||
let gating: null | ExternalFunction = null;
|
||||
try {
|
||||
// TODO: check for duplicate import specifiers
|
||||
if (pass.opts.gating != null) {
|
||||
gating = tryParseExternalFunction(pass.opts.gating);
|
||||
externalFunctions.push(gating);
|
||||
if (gating != null) {
|
||||
externalFunctions.push(gating.gatingFn);
|
||||
}
|
||||
|
||||
const lowerContextAccess = environment.lowerContextAccess;
|
||||
@@ -601,7 +604,7 @@ export function compileProgram(
|
||||
}
|
||||
} catch (err) {
|
||||
handleError(err, pass, null);
|
||||
return;
|
||||
return null;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -613,7 +616,12 @@ export function compileProgram(
|
||||
const transformedFn = createNewFunctionNode(originalFn, compiledFn);
|
||||
|
||||
if (gating != null && kind === 'original') {
|
||||
insertGatedFunctionDeclaration(originalFn, transformedFn, gating);
|
||||
insertGatedFunctionDeclaration(
|
||||
originalFn,
|
||||
transformedFn,
|
||||
gating.gatingFn,
|
||||
gating.referencedBeforeDeclared.has(result),
|
||||
);
|
||||
} else {
|
||||
originalFn.replaceWith(transformedFn);
|
||||
}
|
||||
@@ -638,6 +646,7 @@ export function compileProgram(
|
||||
}
|
||||
addImportsToProgram(program, externalFunctions);
|
||||
}
|
||||
return {retryErrors};
|
||||
}
|
||||
|
||||
function shouldSkipCompilation(
|
||||
@@ -1093,20 +1102,23 @@ function getFunctionName(
|
||||
}
|
||||
}
|
||||
|
||||
function checkFunctionReferencedBeforeDeclarationAtTopLevel(
|
||||
function getFunctionReferencedBeforeDeclarationAtTopLevel(
|
||||
program: NodePath<t.Program>,
|
||||
fns: Array<BabelFn>,
|
||||
): CompilerError | null {
|
||||
const fnIds = new Set(
|
||||
fns: Array<CompileResult>,
|
||||
): Set<CompileResult> {
|
||||
const fnNames = new Map<string, {id: t.Identifier; fn: CompileResult}>(
|
||||
fns
|
||||
.map(fn => getFunctionName(fn))
|
||||
.map<[NodePath<t.Expression> | null, CompileResult]>(fn => [
|
||||
getFunctionName(fn.originalFn),
|
||||
fn,
|
||||
])
|
||||
.filter(
|
||||
(name): name is NodePath<t.Identifier> => !!name && name.isIdentifier(),
|
||||
(entry): entry is [NodePath<t.Identifier>, CompileResult] =>
|
||||
!!entry[0] && entry[0].isIdentifier(),
|
||||
)
|
||||
.map(name => name.node),
|
||||
.map(entry => [entry[0].node.name, {id: entry[0].node, fn: entry[1]}]),
|
||||
);
|
||||
const fnNames = new Map([...fnIds].map(id => [id.name, id]));
|
||||
const errors = new CompilerError();
|
||||
const referencedBeforeDeclaration = new Set<CompileResult>();
|
||||
|
||||
program.traverse({
|
||||
TypeAnnotation(path) {
|
||||
@@ -1132,8 +1144,7 @@ function checkFunctionReferencedBeforeDeclarationAtTopLevel(
|
||||
* We've reached the declaration, hoisting is no longer possible, stop
|
||||
* checking for this component name.
|
||||
*/
|
||||
if (fnIds.has(id.node)) {
|
||||
fnIds.delete(id.node);
|
||||
if (id.node === fn.id) {
|
||||
fnNames.delete(id.node.name);
|
||||
return;
|
||||
}
|
||||
@@ -1143,21 +1154,13 @@ function checkFunctionReferencedBeforeDeclarationAtTopLevel(
|
||||
* A null scope means there's no function scope, which means we're at the
|
||||
* top level scope.
|
||||
*/
|
||||
if (scope === null) {
|
||||
errors.pushErrorDetail(
|
||||
new CompilerErrorDetail({
|
||||
reason: `Encountered a function used before its declaration, which breaks Forget's gating codegen due to hoisting`,
|
||||
description: `Rewrite the reference to ${fn.name} to not rely on hoisting to fix this issue`,
|
||||
loc: fn.loc ?? null,
|
||||
suggestions: null,
|
||||
severity: ErrorSeverity.Invariant,
|
||||
}),
|
||||
);
|
||||
if (scope === null && id.isReferencedIdentifier()) {
|
||||
referencedBeforeDeclaration.add(fn.fn);
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
return errors.details.length > 0 ? errors : null;
|
||||
return referencedBeforeDeclaration;
|
||||
}
|
||||
|
||||
function getReactCompilerRuntimeModule(opts: PluginOptions): string {
|
||||
|
||||
@@ -0,0 +1,275 @@
|
||||
import {NodePath} from '@babel/core';
|
||||
import * as t from '@babel/types';
|
||||
|
||||
import {
|
||||
CompilerError,
|
||||
CompilerErrorDetailOptions,
|
||||
EnvironmentConfig,
|
||||
ErrorSeverity,
|
||||
Logger,
|
||||
} from '..';
|
||||
import {getOrInsertWith} from '../Utils/utils';
|
||||
import {Environment} from '../HIR';
|
||||
import {DEFAULT_EXPORT} from '../HIR/Environment';
|
||||
|
||||
function throwInvalidReact(
|
||||
options: Omit<CompilerErrorDetailOptions, 'severity'>,
|
||||
{logger, filename}: TraversalState,
|
||||
): never {
|
||||
const detail: CompilerErrorDetailOptions = {
|
||||
...options,
|
||||
severity: ErrorSeverity.InvalidReact,
|
||||
};
|
||||
logger?.logEvent(filename, {
|
||||
kind: 'CompileError',
|
||||
fnLoc: null,
|
||||
detail,
|
||||
});
|
||||
CompilerError.throw(detail);
|
||||
}
|
||||
function assertValidEffectImportReference(
|
||||
numArgs: number,
|
||||
paths: Array<NodePath<t.Node>>,
|
||||
context: TraversalState,
|
||||
): void {
|
||||
for (const path of paths) {
|
||||
const parent = path.parentPath;
|
||||
if (parent != null && parent.isCallExpression()) {
|
||||
const args = parent.get('arguments');
|
||||
/**
|
||||
* Only error on untransformed references of the form `useMyEffect(...)`
|
||||
* or `moduleNamespace.useMyEffect(...)`, with matching argument counts.
|
||||
* TODO: do we also want a mode to also hard error on non-call references?
|
||||
*/
|
||||
if (args.length === numArgs) {
|
||||
const maybeErrorDiagnostic = matchCompilerDiagnostic(
|
||||
path,
|
||||
context.transformErrors,
|
||||
);
|
||||
/**
|
||||
* Note that we cannot easily check the type of the first argument here,
|
||||
* as it may have already been transformed by the compiler (and not
|
||||
* memoized).
|
||||
*/
|
||||
throwInvalidReact(
|
||||
{
|
||||
reason:
|
||||
'[InferEffectDependencies] React Compiler is unable to infer dependencies of this effect. ' +
|
||||
'This will break your build! ' +
|
||||
'To resolve, either pass your own dependency array or fix reported compiler bailout diagnostics.',
|
||||
description: maybeErrorDiagnostic
|
||||
? `(Bailout reason: ${maybeErrorDiagnostic})`
|
||||
: null,
|
||||
loc: parent.node.loc ?? null,
|
||||
},
|
||||
context,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function assertValidFireImportReference(
|
||||
paths: Array<NodePath<t.Node>>,
|
||||
context: TraversalState,
|
||||
): void {
|
||||
if (paths.length > 0) {
|
||||
const maybeErrorDiagnostic = matchCompilerDiagnostic(
|
||||
paths[0],
|
||||
context.transformErrors,
|
||||
);
|
||||
throwInvalidReact(
|
||||
{
|
||||
reason:
|
||||
'[Fire] Untransformed reference to compiler-required feature. ' +
|
||||
'Either remove this `fire` call or ensure it is successfully transformed by the compiler',
|
||||
description: maybeErrorDiagnostic
|
||||
? `(Bailout reason: ${maybeErrorDiagnostic})`
|
||||
: null,
|
||||
loc: paths[0].node.loc ?? null,
|
||||
},
|
||||
context,
|
||||
);
|
||||
}
|
||||
}
|
||||
export default function validateNoUntransformedReferences(
|
||||
path: NodePath<t.Program>,
|
||||
filename: string | null,
|
||||
logger: Logger | null,
|
||||
env: EnvironmentConfig,
|
||||
transformErrors: Array<{fn: NodePath<t.Node>; error: CompilerError}>,
|
||||
): void {
|
||||
const moduleLoadChecks = new Map<
|
||||
string,
|
||||
Map<string, CheckInvalidReferenceFn>
|
||||
>();
|
||||
if (env.enableFire) {
|
||||
/**
|
||||
* Error on any untransformed references to `fire` (e.g. including non-call
|
||||
* expressions)
|
||||
*/
|
||||
for (const module of Environment.knownReactModules) {
|
||||
const react = getOrInsertWith(moduleLoadChecks, module, () => new Map());
|
||||
react.set('fire', assertValidFireImportReference);
|
||||
}
|
||||
}
|
||||
if (env.inferEffectDependencies) {
|
||||
for (const {
|
||||
function: {source, importSpecifierName},
|
||||
numRequiredArgs,
|
||||
} of env.inferEffectDependencies) {
|
||||
const module = getOrInsertWith(moduleLoadChecks, source, () => new Map());
|
||||
module.set(
|
||||
importSpecifierName,
|
||||
assertValidEffectImportReference.bind(null, numRequiredArgs),
|
||||
);
|
||||
}
|
||||
}
|
||||
if (moduleLoadChecks.size > 0) {
|
||||
transformProgram(path, moduleLoadChecks, filename, logger, transformErrors);
|
||||
}
|
||||
}
|
||||
|
||||
type TraversalState = {
|
||||
shouldInvalidateScopes: boolean;
|
||||
program: NodePath<t.Program>;
|
||||
logger: Logger | null;
|
||||
filename: string | null;
|
||||
transformErrors: Array<{fn: NodePath<t.Node>; error: CompilerError}>;
|
||||
};
|
||||
type CheckInvalidReferenceFn = (
|
||||
paths: Array<NodePath<t.Node>>,
|
||||
context: TraversalState,
|
||||
) => void;
|
||||
|
||||
function validateImportSpecifier(
|
||||
specifier: NodePath<t.ImportSpecifier>,
|
||||
importSpecifierChecks: Map<string, CheckInvalidReferenceFn>,
|
||||
state: TraversalState,
|
||||
): void {
|
||||
const imported = specifier.get('imported');
|
||||
const specifierName: string =
|
||||
imported.node.type === 'Identifier'
|
||||
? imported.node.name
|
||||
: imported.node.value;
|
||||
const checkFn = importSpecifierChecks.get(specifierName);
|
||||
if (checkFn == null) {
|
||||
return;
|
||||
}
|
||||
if (state.shouldInvalidateScopes) {
|
||||
state.shouldInvalidateScopes = false;
|
||||
state.program.scope.crawl();
|
||||
}
|
||||
|
||||
const local = specifier.get('local');
|
||||
const binding = local.scope.getBinding(local.node.name);
|
||||
CompilerError.invariant(binding != null, {
|
||||
reason: 'Expected binding to be found for import specifier',
|
||||
loc: local.node.loc ?? null,
|
||||
});
|
||||
checkFn(binding.referencePaths, state);
|
||||
}
|
||||
|
||||
function validateNamespacedImport(
|
||||
specifier: NodePath<t.ImportNamespaceSpecifier | t.ImportDefaultSpecifier>,
|
||||
importSpecifierChecks: Map<string, CheckInvalidReferenceFn>,
|
||||
state: TraversalState,
|
||||
): void {
|
||||
if (state.shouldInvalidateScopes) {
|
||||
state.shouldInvalidateScopes = false;
|
||||
state.program.scope.crawl();
|
||||
}
|
||||
const local = specifier.get('local');
|
||||
const binding = local.scope.getBinding(local.node.name);
|
||||
const defaultCheckFn = importSpecifierChecks.get(DEFAULT_EXPORT);
|
||||
|
||||
CompilerError.invariant(binding != null, {
|
||||
reason: 'Expected binding to be found for import specifier',
|
||||
loc: local.node.loc ?? null,
|
||||
});
|
||||
const filteredReferences = new Map<
|
||||
CheckInvalidReferenceFn,
|
||||
Array<NodePath<t.Node>>
|
||||
>();
|
||||
for (const reference of binding.referencePaths) {
|
||||
if (defaultCheckFn != null) {
|
||||
getOrInsertWith(filteredReferences, defaultCheckFn, () => []).push(
|
||||
reference,
|
||||
);
|
||||
}
|
||||
const parent = reference.parentPath;
|
||||
if (
|
||||
parent != null &&
|
||||
parent.isMemberExpression() &&
|
||||
parent.get('object') === reference
|
||||
) {
|
||||
if (parent.node.computed || parent.node.property.type !== 'Identifier') {
|
||||
continue;
|
||||
}
|
||||
const checkFn = importSpecifierChecks.get(parent.node.property.name);
|
||||
if (checkFn != null) {
|
||||
getOrInsertWith(filteredReferences, checkFn, () => []).push(parent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (const [checkFn, references] of filteredReferences) {
|
||||
checkFn(references, state);
|
||||
}
|
||||
}
|
||||
function transformProgram(
|
||||
path: NodePath<t.Program>,
|
||||
|
||||
moduleLoadChecks: Map<string, Map<string, CheckInvalidReferenceFn>>,
|
||||
filename: string | null,
|
||||
logger: Logger | null,
|
||||
transformErrors: Array<{fn: NodePath<t.Node>; error: CompilerError}>,
|
||||
): void {
|
||||
const traversalState: TraversalState = {
|
||||
shouldInvalidateScopes: true,
|
||||
program: path,
|
||||
filename,
|
||||
logger,
|
||||
transformErrors,
|
||||
};
|
||||
path.traverse({
|
||||
ImportDeclaration(path: NodePath<t.ImportDeclaration>) {
|
||||
const importSpecifierChecks = moduleLoadChecks.get(
|
||||
path.node.source.value,
|
||||
);
|
||||
if (importSpecifierChecks == null) {
|
||||
return;
|
||||
}
|
||||
const specifiers = path.get('specifiers');
|
||||
for (const specifier of specifiers) {
|
||||
if (specifier.isImportSpecifier()) {
|
||||
validateImportSpecifier(
|
||||
specifier,
|
||||
importSpecifierChecks,
|
||||
traversalState,
|
||||
);
|
||||
} else {
|
||||
validateNamespacedImport(
|
||||
specifier as NodePath<
|
||||
t.ImportNamespaceSpecifier | t.ImportDefaultSpecifier
|
||||
>,
|
||||
importSpecifierChecks,
|
||||
traversalState,
|
||||
);
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
function matchCompilerDiagnostic(
|
||||
badReference: NodePath<t.Node>,
|
||||
transformErrors: Array<{fn: NodePath<t.Node>; error: CompilerError}>,
|
||||
): string | null {
|
||||
for (const {fn, error} of transformErrors) {
|
||||
if (fn.isAncestor(badReference)) {
|
||||
return error.toString();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@@ -1455,6 +1455,11 @@ function lowerObjectPropertyKey(
|
||||
kind: 'identifier',
|
||||
name: key.node.name,
|
||||
};
|
||||
} else if (key.isNumericLiteral()) {
|
||||
return {
|
||||
kind: 'identifier',
|
||||
name: String(key.node.value),
|
||||
};
|
||||
}
|
||||
|
||||
builder.errors.push({
|
||||
|
||||
@@ -96,6 +96,8 @@ export const MacroSchema = z.union([
|
||||
z.tuple([z.string(), z.array(MacroMethodSchema)]),
|
||||
]);
|
||||
|
||||
export type CompilerMode = 'all_features' | 'no_inferred_memo';
|
||||
|
||||
export type Macro = z.infer<typeof MacroSchema>;
|
||||
export type MacroMethod = z.infer<typeof MacroMethodSchema>;
|
||||
|
||||
@@ -550,8 +552,6 @@ const EnvironmentConfigSchema = z.object({
|
||||
*/
|
||||
disableMemoizationForDebugging: z.boolean().default(false),
|
||||
|
||||
enableMinimalTransformsForRetry: z.boolean().default(false),
|
||||
|
||||
/**
|
||||
* When true, rather using memoized values, the compiler will always re-compute
|
||||
* values, and then use a heuristic to compare the memoized value to the newly
|
||||
@@ -626,17 +626,6 @@ const EnvironmentConfigSchema = z.object({
|
||||
|
||||
export type EnvironmentConfig = z.infer<typeof EnvironmentConfigSchema>;
|
||||
|
||||
export const MINIMAL_RETRY_CONFIG: PartialEnvironmentConfig = {
|
||||
validateHooksUsage: false,
|
||||
validateRefAccessDuringRender: false,
|
||||
validateNoSetStateInRender: false,
|
||||
validateNoSetStateInPassiveEffects: false,
|
||||
validateNoJSXInTryStatements: false,
|
||||
validateMemoizedEffectDependencies: false,
|
||||
validateNoCapitalizedCalls: null,
|
||||
validateBlocklistedImports: null,
|
||||
enableMinimalTransformsForRetry: true,
|
||||
};
|
||||
/**
|
||||
* For test fixtures and playground only.
|
||||
*
|
||||
@@ -663,7 +652,7 @@ const testComplexConfigDefaults: PartialEnvironmentConfig = {
|
||||
source: 'react-compiler-runtime',
|
||||
importSpecifierName: 'shouldInstrument',
|
||||
},
|
||||
globalGating: '__DEV__',
|
||||
globalGating: 'DEV',
|
||||
},
|
||||
enableEmitHookGuards: {
|
||||
source: 'react-compiler-runtime',
|
||||
@@ -851,6 +840,7 @@ export class Environment {
|
||||
code: string | null;
|
||||
config: EnvironmentConfig;
|
||||
fnType: ReactFunctionType;
|
||||
compilerMode: CompilerMode;
|
||||
useMemoCacheIdentifier: string;
|
||||
hasLoweredContextAccess: boolean;
|
||||
hasFireRewrite: boolean;
|
||||
@@ -861,6 +851,7 @@ export class Environment {
|
||||
constructor(
|
||||
scope: BabelScope,
|
||||
fnType: ReactFunctionType,
|
||||
compilerMode: CompilerMode,
|
||||
config: EnvironmentConfig,
|
||||
contextIdentifiers: Set<t.Identifier>,
|
||||
logger: Logger | null,
|
||||
@@ -870,6 +861,7 @@ export class Environment {
|
||||
) {
|
||||
this.#scope = scope;
|
||||
this.fnType = fnType;
|
||||
this.compilerMode = compilerMode;
|
||||
this.config = config;
|
||||
this.filename = filename;
|
||||
this.code = code;
|
||||
@@ -924,6 +916,10 @@ export class Environment {
|
||||
this.#hoistedIdentifiers = new Set();
|
||||
}
|
||||
|
||||
get isInferredMemoEnabled(): boolean {
|
||||
return this.compilerMode !== 'no_inferred_memo';
|
||||
}
|
||||
|
||||
get nextIdentifierId(): IdentifierId {
|
||||
return makeIdentifierId(this.#nextIdentifer++);
|
||||
}
|
||||
@@ -1125,6 +1121,7 @@ export class Environment {
|
||||
moduleName.toLowerCase() === 'react-dom'
|
||||
);
|
||||
}
|
||||
static knownReactModules: ReadonlyArray<string> = ['react', 'react-dom'];
|
||||
|
||||
getFallthroughPropertyType(
|
||||
receiver: Type,
|
||||
|
||||
@@ -703,6 +703,10 @@ export type ObjectPropertyKey =
|
||||
| {
|
||||
kind: 'computed';
|
||||
name: Place;
|
||||
}
|
||||
| {
|
||||
kind: 'number';
|
||||
name: number;
|
||||
};
|
||||
|
||||
export type ObjectProperty = {
|
||||
|
||||
@@ -535,6 +535,30 @@ addObject(BUILTIN_SHAPES, BuiltInRefValueId, [
|
||||
['*', {kind: 'Object', shapeId: BuiltInRefValueId}],
|
||||
]);
|
||||
|
||||
/**
|
||||
* MixedReadOnly =
|
||||
* | primitive
|
||||
* | simple objects (Record<string, MixedReadOnly>)
|
||||
* | Array<MixedReadOnly>
|
||||
*
|
||||
* APIs such as Relay — but also Flux and other data stores — often return a
|
||||
* union of types with some interesting properties in terms of analysis.
|
||||
*
|
||||
* Given this constraint, if data came from Relay, then we should be able to
|
||||
* infer things like `data.items.map(): Array`. That may seem like a leap at
|
||||
* first but remember, we assume you're not patching builtins. Thus the only way
|
||||
* data.items.map can exist and be a function, given the above set of data types
|
||||
* and builtin JS methods, is if `data.items` was an Array, and `data.items.map`
|
||||
* is therefore calling Array.prototype.map. Then we know that function returns
|
||||
* an Array as well. This relies on the fact that map() is being called, so if
|
||||
* data.items was some other type it would error at runtime - so it's sound.
|
||||
*
|
||||
* Note that this shape is currently only used for hook return values, which
|
||||
* means that it's safe to type aliasing method-call return kinds as `Frozen`.
|
||||
*
|
||||
* Also note that all newly created arrays from method-calls (e.g. `.map`)
|
||||
* have the appropriate mutable `BuiltInArray` shape
|
||||
*/
|
||||
addObject(BUILTIN_SHAPES, BuiltInMixedReadonlyId, [
|
||||
[
|
||||
'toString',
|
||||
@@ -546,6 +570,36 @@ addObject(BUILTIN_SHAPES, BuiltInMixedReadonlyId, [
|
||||
returnValueKind: ValueKind.Primitive,
|
||||
}),
|
||||
],
|
||||
[
|
||||
'indexOf',
|
||||
addFunction(BUILTIN_SHAPES, [], {
|
||||
positionalParams: [],
|
||||
restParam: Effect.Read,
|
||||
returnType: {kind: 'Primitive'},
|
||||
calleeEffect: Effect.Read,
|
||||
returnValueKind: ValueKind.Primitive,
|
||||
}),
|
||||
],
|
||||
[
|
||||
'includes',
|
||||
addFunction(BUILTIN_SHAPES, [], {
|
||||
positionalParams: [],
|
||||
restParam: Effect.Read,
|
||||
returnType: {kind: 'Primitive'},
|
||||
calleeEffect: Effect.Read,
|
||||
returnValueKind: ValueKind.Primitive,
|
||||
}),
|
||||
],
|
||||
[
|
||||
'at',
|
||||
addFunction(BUILTIN_SHAPES, [], {
|
||||
positionalParams: [Effect.Read],
|
||||
restParam: null,
|
||||
returnType: {kind: 'Object', shapeId: BuiltInMixedReadonlyId},
|
||||
calleeEffect: Effect.Capture,
|
||||
returnValueKind: ValueKind.Frozen,
|
||||
}),
|
||||
],
|
||||
[
|
||||
'map',
|
||||
addFunction(BUILTIN_SHAPES, [], {
|
||||
@@ -642,9 +696,9 @@ addObject(BUILTIN_SHAPES, BuiltInMixedReadonlyId, [
|
||||
addFunction(BUILTIN_SHAPES, [], {
|
||||
positionalParams: [],
|
||||
restParam: Effect.ConditionallyMutate,
|
||||
returnType: {kind: 'Poly'},
|
||||
returnType: {kind: 'Object', shapeId: BuiltInMixedReadonlyId},
|
||||
calleeEffect: Effect.ConditionallyMutate,
|
||||
returnValueKind: ValueKind.Mutable,
|
||||
returnValueKind: ValueKind.Frozen,
|
||||
noAlias: true,
|
||||
mutableOnlyIfOperandsAreMutable: true,
|
||||
}),
|
||||
|
||||
@@ -330,6 +330,9 @@ function printObjectPropertyKey(key: ObjectPropertyKey): string {
|
||||
case 'computed': {
|
||||
return `[${printPlace(key.name)}]`;
|
||||
}
|
||||
case 'number': {
|
||||
return String(key.name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -5,7 +5,12 @@
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
import {CompilerError, ErrorSeverity, ValueKind} from '..';
|
||||
import {
|
||||
CompilerError,
|
||||
CompilerErrorDetailOptions,
|
||||
ErrorSeverity,
|
||||
ValueKind,
|
||||
} from '..';
|
||||
import {
|
||||
AbstractValue,
|
||||
BasicBlock,
|
||||
@@ -290,21 +295,21 @@ export function inferTerminalFunctionEffects(
|
||||
return functionEffects;
|
||||
}
|
||||
|
||||
export function raiseFunctionEffectErrors(
|
||||
export function transformFunctionEffectErrors(
|
||||
functionEffects: Array<FunctionEffect>,
|
||||
): void {
|
||||
functionEffects.forEach(eff => {
|
||||
): Array<CompilerErrorDetailOptions> {
|
||||
return functionEffects.map(eff => {
|
||||
switch (eff.kind) {
|
||||
case 'ReactMutation':
|
||||
case 'GlobalMutation': {
|
||||
CompilerError.throw(eff.error);
|
||||
return eff.error;
|
||||
}
|
||||
case 'ContextMutation': {
|
||||
CompilerError.throw({
|
||||
return {
|
||||
severity: ErrorSeverity.Invariant,
|
||||
reason: `Unexpected ContextMutation in top-level function effects`,
|
||||
loc: eff.loc,
|
||||
});
|
||||
};
|
||||
}
|
||||
default:
|
||||
assertExhaustive(
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
import {CompilerError} from '../CompilerError';
|
||||
import {CompilerError, CompilerErrorDetailOptions} from '../CompilerError';
|
||||
import {Environment} from '../HIR';
|
||||
import {
|
||||
AbstractValue,
|
||||
@@ -49,7 +49,7 @@ import {assertExhaustive} from '../Utils/utils';
|
||||
import {
|
||||
inferTerminalFunctionEffects,
|
||||
inferInstructionFunctionEffects,
|
||||
raiseFunctionEffectErrors,
|
||||
transformFunctionEffectErrors,
|
||||
} from './InferFunctionEffects';
|
||||
|
||||
const UndefinedValue: InstructionValue = {
|
||||
@@ -103,7 +103,7 @@ const UndefinedValue: InstructionValue = {
|
||||
export default function inferReferenceEffects(
|
||||
fn: HIRFunction,
|
||||
options: {isFunctionExpression: boolean} = {isFunctionExpression: false},
|
||||
): void {
|
||||
): Array<CompilerErrorDetailOptions> {
|
||||
/*
|
||||
* Initial state contains function params
|
||||
* TODO: include module declarations here as well
|
||||
@@ -241,8 +241,9 @@ export default function inferReferenceEffects(
|
||||
|
||||
if (options.isFunctionExpression) {
|
||||
fn.effects = functionEffects;
|
||||
} else if (!fn.env.config.enableMinimalTransformsForRetry) {
|
||||
raiseFunctionEffectErrors(functionEffects);
|
||||
return [];
|
||||
} else {
|
||||
return transformFunctionEffectErrors(functionEffects);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2429,6 +2429,9 @@ function codegenObjectPropertyKey(
|
||||
});
|
||||
return expr;
|
||||
}
|
||||
case 'number': {
|
||||
return t.numericLiteral(key.name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,35 +0,0 @@
|
||||
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
// @gating
|
||||
const ErrorView = (error, _retry) => <MessageBox error={error}></MessageBox>;
|
||||
|
||||
export default ErrorView;
|
||||
|
||||
```
|
||||
|
||||
## Code
|
||||
|
||||
```javascript
|
||||
import { isForgetEnabled_Fixtures } from "ReactForgetFeatureFlag";
|
||||
import { c as _c } from "react/compiler-runtime"; // @gating
|
||||
const ErrorView = isForgetEnabled_Fixtures()
|
||||
? (error, _retry) => {
|
||||
const $ = _c(2);
|
||||
let t0;
|
||||
if ($[0] !== error) {
|
||||
t0 = <MessageBox error={error} />;
|
||||
$[0] = error;
|
||||
$[1] = t0;
|
||||
} else {
|
||||
t0 = $[1];
|
||||
}
|
||||
return t0;
|
||||
}
|
||||
: (error, _retry) => <MessageBox error={error}></MessageBox>;
|
||||
|
||||
export default ErrorView;
|
||||
|
||||
```
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
// @gating
|
||||
const ErrorView = (error, _retry) => <MessageBox error={error}></MessageBox>;
|
||||
|
||||
export default ErrorView;
|
||||
@@ -21,7 +21,7 @@ import {
|
||||
import { c as _c } from "react/compiler-runtime"; // @enableEmitFreeze @enableEmitInstrumentForget
|
||||
|
||||
function useFoo(props) {
|
||||
if (__DEV__ && shouldInstrument)
|
||||
if (DEV && shouldInstrument)
|
||||
useRenderCounter("useFoo", "/codegen-emit-imports-same-source.ts");
|
||||
const $ = _c(2);
|
||||
let t0;
|
||||
|
||||
@@ -28,7 +28,7 @@ import { c as _c } from "react/compiler-runtime"; // @enableEmitInstrumentForget
|
||||
|
||||
function Bar(props) {
|
||||
"use forget";
|
||||
if (__DEV__ && shouldInstrument)
|
||||
if (DEV && shouldInstrument)
|
||||
useRenderCounter("Bar", "/codegen-instrument-forget-test.ts");
|
||||
const $ = _c(2);
|
||||
let t0;
|
||||
@@ -48,7 +48,7 @@ function NoForget(props) {
|
||||
|
||||
function Foo(props) {
|
||||
"use forget";
|
||||
if (__DEV__ && shouldInstrument)
|
||||
if (DEV && shouldInstrument)
|
||||
useRenderCounter("Foo", "/codegen-instrument-forget-test.ts");
|
||||
const $ = _c(2);
|
||||
let t0;
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
// @flow @gating
|
||||
component Foo(ref: React.RefSetter<Controls>) {
|
||||
return <Bar ref={ref} />;
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
## Error
|
||||
|
||||
```
|
||||
1 | // @flow @gating
|
||||
> 2 | component Foo(ref: React.RefSetter<Controls>) {
|
||||
| ^^^ Invariant: Encountered a function used before its declaration, which breaks Forget's gating codegen due to hoisting. Rewrite the reference to Foo_withRef to not rely on hoisting to fix this issue (2:2)
|
||||
3 | return <Bar ref={ref} />;
|
||||
4 | }
|
||||
5 |
|
||||
```
|
||||
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
// @flow @gating
|
||||
component Foo(ref: React.RefSetter<Controls>) {
|
||||
return <Bar ref={ref} />;
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
// @gating
|
||||
const Foo = React.forwardRef(Foo_withRef);
|
||||
function Foo_withRef(props, ref) {
|
||||
return <Bar ref={ref} {...props}></Bar>;
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
## Error
|
||||
|
||||
```
|
||||
1 | // @gating
|
||||
2 | const Foo = React.forwardRef(Foo_withRef);
|
||||
> 3 | function Foo_withRef(props, ref) {
|
||||
| ^^^^^^^^^^^ Invariant: Encountered a function used before its declaration, which breaks Forget's gating codegen due to hoisting. Rewrite the reference to Foo_withRef to not rely on hoisting to fix this issue (3:3)
|
||||
4 | return <Bar ref={ref} {...props}></Bar>;
|
||||
5 | }
|
||||
6 |
|
||||
```
|
||||
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
// @gating
|
||||
const Foo = React.forwardRef(Foo_withRef);
|
||||
function Foo_withRef(props, ref) {
|
||||
return <Bar ref={ref} {...props}></Bar>;
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
// @gating
|
||||
import {memo} from 'react';
|
||||
|
||||
export default memo(Foo);
|
||||
function Foo() {}
|
||||
|
||||
```
|
||||
|
||||
|
||||
## Error
|
||||
|
||||
```
|
||||
3 |
|
||||
4 | export default memo(Foo);
|
||||
> 5 | function Foo() {}
|
||||
| ^^^ Invariant: Encountered a function used before its declaration, which breaks Forget's gating codegen due to hoisting. Rewrite the reference to Foo to not rely on hoisting to fix this issue (5:5)
|
||||
6 |
|
||||
```
|
||||
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
// @gating
|
||||
import {memo} from 'react';
|
||||
|
||||
export default memo(Foo);
|
||||
function Foo() {}
|
||||
@@ -1,14 +0,0 @@
|
||||
// @gating @compilationMode(annotation)
|
||||
export default function Bar(props) {
|
||||
'use forget';
|
||||
return <div>{props.bar}</div>;
|
||||
}
|
||||
|
||||
function NoForget(props) {
|
||||
return <Bar>{props.noForget}</Bar>;
|
||||
}
|
||||
|
||||
export function Foo(props) {
|
||||
'use forget';
|
||||
return <Foo>{props.bar}</Foo>;
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
// @gating
|
||||
import {Stringify} from 'shared-runtime';
|
||||
const ErrorView = ({error, _retry}) => <Stringify error={error}></Stringify>;
|
||||
|
||||
export default ErrorView;
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: eval('ErrorView'),
|
||||
params: [{}],
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
## Code
|
||||
|
||||
```javascript
|
||||
import { isForgetEnabled_Fixtures } from "ReactForgetFeatureFlag";
|
||||
import { c as _c } from "react/compiler-runtime"; // @gating
|
||||
import { Stringify } from "shared-runtime";
|
||||
const ErrorView = isForgetEnabled_Fixtures()
|
||||
? (t0) => {
|
||||
const $ = _c(2);
|
||||
const { error } = t0;
|
||||
let t1;
|
||||
if ($[0] !== error) {
|
||||
t1 = <Stringify error={error} />;
|
||||
$[0] = error;
|
||||
$[1] = t1;
|
||||
} else {
|
||||
t1 = $[1];
|
||||
}
|
||||
return t1;
|
||||
}
|
||||
: ({ error, _retry }) => <Stringify error={error}></Stringify>;
|
||||
|
||||
export default ErrorView;
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: eval("ErrorView"),
|
||||
params: [{}],
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
### Eval output
|
||||
(kind: ok) <div>{}</div>
|
||||
@@ -0,0 +1,10 @@
|
||||
// @gating
|
||||
import {Stringify} from 'shared-runtime';
|
||||
const ErrorView = ({error, _retry}) => <Stringify error={error}></Stringify>;
|
||||
|
||||
export default ErrorView;
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: eval('ErrorView'),
|
||||
params: [{}],
|
||||
};
|
||||
@@ -15,9 +15,22 @@ function NoForget(props) {
|
||||
|
||||
function Foo(props) {
|
||||
'use forget';
|
||||
return <Foo>{props.bar}</Foo>;
|
||||
if (props.bar < 0) {
|
||||
return props.children;
|
||||
}
|
||||
return (
|
||||
<Foo bar={props.bar - 1}>
|
||||
<NoForget />
|
||||
</Foo>
|
||||
);
|
||||
}
|
||||
|
||||
global.DEV = true;
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: eval('Foo'),
|
||||
params: [{bar: 2}],
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
## Code
|
||||
@@ -29,7 +42,7 @@ import { c as _c } from "react/compiler-runtime"; // @enableEmitInstrumentForget
|
||||
const Bar = isForgetEnabled_Fixtures()
|
||||
? function Bar(props) {
|
||||
"use forget";
|
||||
if (__DEV__ && shouldInstrument)
|
||||
if (DEV && shouldInstrument)
|
||||
useRenderCounter("Bar", "/codegen-instrument-forget-gating-test.ts");
|
||||
const $ = _c(2);
|
||||
let t0;
|
||||
@@ -53,23 +66,50 @@ function NoForget(props) {
|
||||
const Foo = isForgetEnabled_Fixtures()
|
||||
? function Foo(props) {
|
||||
"use forget";
|
||||
if (__DEV__ && shouldInstrument)
|
||||
if (DEV && shouldInstrument)
|
||||
useRenderCounter("Foo", "/codegen-instrument-forget-gating-test.ts");
|
||||
const $ = _c(2);
|
||||
let t0;
|
||||
if ($[0] !== props.bar) {
|
||||
t0 = <Foo>{props.bar}</Foo>;
|
||||
$[0] = props.bar;
|
||||
$[1] = t0;
|
||||
} else {
|
||||
t0 = $[1];
|
||||
const $ = _c(3);
|
||||
if (props.bar < 0) {
|
||||
return props.children;
|
||||
}
|
||||
return t0;
|
||||
|
||||
const t0 = props.bar - 1;
|
||||
let t1;
|
||||
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
|
||||
t1 = <NoForget />;
|
||||
$[0] = t1;
|
||||
} else {
|
||||
t1 = $[0];
|
||||
}
|
||||
let t2;
|
||||
if ($[1] !== t0) {
|
||||
t2 = <Foo bar={t0}>{t1}</Foo>;
|
||||
$[1] = t0;
|
||||
$[2] = t2;
|
||||
} else {
|
||||
t2 = $[2];
|
||||
}
|
||||
return t2;
|
||||
}
|
||||
: function Foo(props) {
|
||||
"use forget";
|
||||
return <Foo>{props.bar}</Foo>;
|
||||
if (props.bar < 0) {
|
||||
return props.children;
|
||||
}
|
||||
return (
|
||||
<Foo bar={props.bar - 1}>
|
||||
<NoForget />
|
||||
</Foo>
|
||||
);
|
||||
};
|
||||
|
||||
global.DEV = true;
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: eval("Foo"),
|
||||
params: [{ bar: 2 }],
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
|
||||
### Eval output
|
||||
(kind: ok) <div></div>
|
||||
@@ -11,5 +11,18 @@ function NoForget(props) {
|
||||
|
||||
function Foo(props) {
|
||||
'use forget';
|
||||
return <Foo>{props.bar}</Foo>;
|
||||
if (props.bar < 0) {
|
||||
return props.children;
|
||||
}
|
||||
return (
|
||||
<Foo bar={props.bar - 1}>
|
||||
<NoForget />
|
||||
</Foo>
|
||||
);
|
||||
}
|
||||
|
||||
global.DEV = true;
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: eval('Foo'),
|
||||
params: [{bar: 2}],
|
||||
};
|
||||
@@ -0,0 +1,62 @@
|
||||
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
// @flow @gating
|
||||
import {Stringify} from 'shared-runtime';
|
||||
import * as React from 'react';
|
||||
|
||||
component Foo(ref: React.RefSetter<Controls>) {
|
||||
return <Stringify ref={ref} />;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: eval('(...args) => React.createElement(Foo, args)'),
|
||||
params: [{ref: React.createRef()}],
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
## Code
|
||||
|
||||
```javascript
|
||||
import { isForgetEnabled_Fixtures } from "ReactForgetFeatureFlag";
|
||||
import { c as _c } from "react/compiler-runtime";
|
||||
import { Stringify } from "shared-runtime";
|
||||
import * as React from "react";
|
||||
|
||||
const Foo = React.forwardRef(Foo_withRef);
|
||||
const _isForgetEnabled_Fixtures_result = isForgetEnabled_Fixtures();
|
||||
function _Foo_withRef_optimized(_$$empty_props_placeholder$$, ref) {
|
||||
const $ = _c(2);
|
||||
let t0;
|
||||
if ($[0] !== ref) {
|
||||
t0 = <Stringify ref={ref} />;
|
||||
$[0] = ref;
|
||||
$[1] = t0;
|
||||
} else {
|
||||
t0 = $[1];
|
||||
}
|
||||
return t0;
|
||||
}
|
||||
function _Foo_withRef_unoptimized(
|
||||
_$$empty_props_placeholder$$: $ReadOnly<{}>,
|
||||
ref: React.RefSetter<Controls>,
|
||||
): React.Node {
|
||||
return <Stringify ref={ref} />;
|
||||
}
|
||||
function Foo_withRef(arg0, arg1) {
|
||||
if (_isForgetEnabled_Fixtures_result)
|
||||
return _Foo_withRef_optimized(arg0, arg1);
|
||||
else return _Foo_withRef_unoptimized(arg0, arg1);
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: eval("(...args) => React.createElement(Foo, args)"),
|
||||
params: [{ ref: React.createRef() }],
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
### Eval output
|
||||
(kind: ok) <div>{"ref":null}</div>
|
||||
@@ -0,0 +1,12 @@
|
||||
// @flow @gating
|
||||
import {Stringify} from 'shared-runtime';
|
||||
import * as React from 'react';
|
||||
|
||||
component Foo(ref: React.RefSetter<Controls>) {
|
||||
return <Stringify ref={ref} />;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: eval('(...args) => React.createElement(Foo, args)'),
|
||||
params: [{ref: React.createRef()}],
|
||||
};
|
||||
@@ -0,0 +1,60 @@
|
||||
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
// @gating
|
||||
import {identity, useHook as useRenamed} from 'shared-runtime';
|
||||
const _ = {
|
||||
useHook: () => {},
|
||||
};
|
||||
identity(_.useHook);
|
||||
|
||||
function useHook() {
|
||||
useRenamed();
|
||||
return <div>hello world!</div>;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: useHook,
|
||||
params: [{}],
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
## Code
|
||||
|
||||
```javascript
|
||||
import { isForgetEnabled_Fixtures } from "ReactForgetFeatureFlag";
|
||||
import { c as _c } from "react/compiler-runtime"; // @gating
|
||||
import { identity, useHook as useRenamed } from "shared-runtime";
|
||||
const _ = {
|
||||
useHook: isForgetEnabled_Fixtures() ? () => {} : () => {},
|
||||
};
|
||||
identity(_.useHook);
|
||||
const useHook = isForgetEnabled_Fixtures()
|
||||
? function useHook() {
|
||||
const $ = _c(1);
|
||||
useRenamed();
|
||||
let t0;
|
||||
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
|
||||
t0 = <div>hello world!</div>;
|
||||
$[0] = t0;
|
||||
} else {
|
||||
t0 = $[0];
|
||||
}
|
||||
return t0;
|
||||
}
|
||||
: function useHook() {
|
||||
useRenamed();
|
||||
return <div>hello world!</div>;
|
||||
};
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: useHook,
|
||||
params: [{}],
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
### Eval output
|
||||
(kind: ok) <div>hello world!</div>
|
||||
@@ -0,0 +1,16 @@
|
||||
// @gating
|
||||
import {identity, useHook as useRenamed} from 'shared-runtime';
|
||||
const _ = {
|
||||
useHook: () => {},
|
||||
};
|
||||
identity(_.useHook);
|
||||
|
||||
function useHook() {
|
||||
useRenamed();
|
||||
return <div>hello world!</div>;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: useHook,
|
||||
params: [{}],
|
||||
};
|
||||
@@ -17,6 +17,11 @@ function Foo(props) {
|
||||
return <Foo>{props.bar}</Foo>;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: eval('Bar'),
|
||||
params: [{bar: 2}],
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
## Code
|
||||
@@ -66,5 +71,12 @@ const Foo = isForgetEnabled_Fixtures()
|
||||
return <Foo>{props.bar}</Foo>;
|
||||
};
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: eval("Bar"),
|
||||
params: [{ bar: 2 }],
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
|
||||
### Eval output
|
||||
(kind: ok) <div>2</div>
|
||||
@@ -12,3 +12,8 @@ function Foo(props) {
|
||||
'use forget';
|
||||
return <Foo>{props.bar}</Foo>;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: eval('Bar'),
|
||||
params: [{bar: 2}],
|
||||
};
|
||||
@@ -12,11 +12,23 @@ function NoForget(props) {
|
||||
return <Bar>{props.noForget}</Bar>;
|
||||
}
|
||||
|
||||
export function Foo(props) {
|
||||
function Foo(props) {
|
||||
'use forget';
|
||||
return <Foo>{props.bar}</Foo>;
|
||||
if (props.bar < 0) {
|
||||
return props.children;
|
||||
}
|
||||
return (
|
||||
<Foo bar={props.bar - 1}>
|
||||
<NoForget />
|
||||
</Foo>
|
||||
);
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: eval('Bar'),
|
||||
params: [{bar: 2}],
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
## Code
|
||||
@@ -47,25 +59,50 @@ export default Bar;
|
||||
function NoForget(props) {
|
||||
return <Bar>{props.noForget}</Bar>;
|
||||
}
|
||||
|
||||
export const Foo = isForgetEnabled_Fixtures()
|
||||
const Foo = isForgetEnabled_Fixtures()
|
||||
? function Foo(props) {
|
||||
"use forget";
|
||||
const $ = _c(2);
|
||||
let t0;
|
||||
if ($[0] !== props.bar) {
|
||||
t0 = <Foo>{props.bar}</Foo>;
|
||||
$[0] = props.bar;
|
||||
$[1] = t0;
|
||||
} else {
|
||||
t0 = $[1];
|
||||
const $ = _c(3);
|
||||
if (props.bar < 0) {
|
||||
return props.children;
|
||||
}
|
||||
return t0;
|
||||
|
||||
const t0 = props.bar - 1;
|
||||
let t1;
|
||||
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
|
||||
t1 = <NoForget />;
|
||||
$[0] = t1;
|
||||
} else {
|
||||
t1 = $[0];
|
||||
}
|
||||
let t2;
|
||||
if ($[1] !== t0) {
|
||||
t2 = <Foo bar={t0}>{t1}</Foo>;
|
||||
$[1] = t0;
|
||||
$[2] = t2;
|
||||
} else {
|
||||
t2 = $[2];
|
||||
}
|
||||
return t2;
|
||||
}
|
||||
: function Foo(props) {
|
||||
"use forget";
|
||||
return <Foo>{props.bar}</Foo>;
|
||||
if (props.bar < 0) {
|
||||
return props.children;
|
||||
}
|
||||
return (
|
||||
<Foo bar={props.bar - 1}>
|
||||
<NoForget />
|
||||
</Foo>
|
||||
);
|
||||
};
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: eval("Bar"),
|
||||
params: [{ bar: 2 }],
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
|
||||
### Eval output
|
||||
(kind: ok) <div>2</div>
|
||||
@@ -0,0 +1,26 @@
|
||||
// @gating @compilationMode(annotation)
|
||||
export default function Bar(props) {
|
||||
'use forget';
|
||||
return <div>{props.bar}</div>;
|
||||
}
|
||||
|
||||
function NoForget(props) {
|
||||
return <Bar>{props.noForget}</Bar>;
|
||||
}
|
||||
|
||||
function Foo(props) {
|
||||
'use forget';
|
||||
if (props.bar < 0) {
|
||||
return props.children;
|
||||
}
|
||||
return (
|
||||
<Foo bar={props.bar - 1}>
|
||||
<NoForget />
|
||||
</Foo>
|
||||
);
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: eval('Bar'),
|
||||
params: [{bar: 2}],
|
||||
};
|
||||
@@ -17,6 +17,11 @@ export function Foo(props) {
|
||||
return <Foo>{props.bar}</Foo>;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: eval('Bar'),
|
||||
params: [{bar: 2}],
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
## Code
|
||||
@@ -66,5 +71,12 @@ export const Foo = isForgetEnabled_Fixtures()
|
||||
return <Foo>{props.bar}</Foo>;
|
||||
};
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: eval("Bar"),
|
||||
params: [{ bar: 2 }],
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
|
||||
### Eval output
|
||||
(kind: ok) <div>2</div>
|
||||
@@ -12,3 +12,8 @@ export function Foo(props) {
|
||||
'use forget';
|
||||
return <Foo>{props.bar}</Foo>;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: eval('Bar'),
|
||||
params: [{bar: 2}],
|
||||
};
|
||||
@@ -17,6 +17,11 @@ function Foo(props) {
|
||||
return <Foo>{props.bar}</Foo>;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: eval('Bar'),
|
||||
params: [{bar: 2}],
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
## Code
|
||||
@@ -65,5 +70,12 @@ const Foo = isForgetEnabled_Fixtures()
|
||||
return <Foo>{props.bar}</Foo>;
|
||||
};
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: eval("Bar"),
|
||||
params: [{ bar: 2 }],
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
|
||||
### Eval output
|
||||
(kind: ok) <div>2</div>
|
||||
@@ -12,3 +12,8 @@ function Foo(props) {
|
||||
'use forget';
|
||||
return <Foo>{props.bar}</Foo>;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: eval('Bar'),
|
||||
params: [{bar: 2}],
|
||||
};
|
||||
@@ -0,0 +1,61 @@
|
||||
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
// @gating
|
||||
import {createRef, forwardRef} from 'react';
|
||||
import {Stringify} from 'shared-runtime';
|
||||
|
||||
const Foo = forwardRef(Foo_withRef);
|
||||
function Foo_withRef(props, ref) {
|
||||
return <Stringify ref={ref} {...props} />;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: eval('(...args) => React.createElement(Foo, args)'),
|
||||
params: [{prop1: 1, prop2: 2, ref: createRef()}],
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
## Code
|
||||
|
||||
```javascript
|
||||
import { isForgetEnabled_Fixtures } from "ReactForgetFeatureFlag";
|
||||
import { c as _c } from "react/compiler-runtime"; // @gating
|
||||
import { createRef, forwardRef } from "react";
|
||||
import { Stringify } from "shared-runtime";
|
||||
|
||||
const Foo = forwardRef(Foo_withRef);
|
||||
const _isForgetEnabled_Fixtures_result = isForgetEnabled_Fixtures();
|
||||
function _Foo_withRef_optimized(props, ref) {
|
||||
const $ = _c(3);
|
||||
let t0;
|
||||
if ($[0] !== props || $[1] !== ref) {
|
||||
t0 = <Stringify ref={ref} {...props} />;
|
||||
$[0] = props;
|
||||
$[1] = ref;
|
||||
$[2] = t0;
|
||||
} else {
|
||||
t0 = $[2];
|
||||
}
|
||||
return t0;
|
||||
}
|
||||
function _Foo_withRef_unoptimized(props, ref) {
|
||||
return <Stringify ref={ref} {...props} />;
|
||||
}
|
||||
function Foo_withRef(arg0, arg1) {
|
||||
if (_isForgetEnabled_Fixtures_result)
|
||||
return _Foo_withRef_optimized(arg0, arg1);
|
||||
else return _Foo_withRef_unoptimized(arg0, arg1);
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: eval("(...args) => React.createElement(Foo, args)"),
|
||||
params: [{ prop1: 1, prop2: 2, ref: createRef() }],
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
### Eval output
|
||||
(kind: ok) <div>{"0":{"prop1":1,"prop2":2,"ref":{"current":null}},"ref":"[[ cyclic ref *3 ]]"}</div>
|
||||
@@ -0,0 +1,13 @@
|
||||
// @gating
|
||||
import {createRef, forwardRef} from 'react';
|
||||
import {Stringify} from 'shared-runtime';
|
||||
|
||||
const Foo = forwardRef(Foo_withRef);
|
||||
function Foo_withRef(props, ref) {
|
||||
return <Stringify ref={ref} {...props} />;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: eval('(...args) => React.createElement(Foo, args)'),
|
||||
params: [{prop1: 1, prop2: 2, ref: createRef()}],
|
||||
};
|
||||
@@ -0,0 +1,64 @@
|
||||
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
// @gating
|
||||
import {memo} from 'react';
|
||||
import {Stringify} from 'shared-runtime';
|
||||
|
||||
export default memo(Foo);
|
||||
function Foo({prop1, prop2}) {
|
||||
'use memo';
|
||||
return <Stringify prop1={prop1} prop2={prop2} />;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: eval('Foo'),
|
||||
params: [{prop1: 1, prop2: 2}],
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
## Code
|
||||
|
||||
```javascript
|
||||
import { isForgetEnabled_Fixtures } from "ReactForgetFeatureFlag";
|
||||
import { c as _c } from "react/compiler-runtime"; // @gating
|
||||
import { memo } from "react";
|
||||
import { Stringify } from "shared-runtime";
|
||||
|
||||
export default memo(Foo);
|
||||
const _isForgetEnabled_Fixtures_result = isForgetEnabled_Fixtures();
|
||||
function _Foo_optimized(t0) {
|
||||
"use memo";
|
||||
const $ = _c(3);
|
||||
const { prop1, prop2 } = t0;
|
||||
let t1;
|
||||
if ($[0] !== prop1 || $[1] !== prop2) {
|
||||
t1 = <Stringify prop1={prop1} prop2={prop2} />;
|
||||
$[0] = prop1;
|
||||
$[1] = prop2;
|
||||
$[2] = t1;
|
||||
} else {
|
||||
t1 = $[2];
|
||||
}
|
||||
return t1;
|
||||
}
|
||||
function _Foo_unoptimized({ prop1, prop2 }) {
|
||||
"use memo";
|
||||
return <Stringify prop1={prop1} prop2={prop2} />;
|
||||
}
|
||||
function Foo(arg0) {
|
||||
if (_isForgetEnabled_Fixtures_result) return _Foo_optimized(arg0);
|
||||
else return _Foo_unoptimized(arg0);
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: eval("Foo"),
|
||||
params: [{ prop1: 1, prop2: 2 }],
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
### Eval output
|
||||
(kind: ok) <div>{"prop1":1,"prop2":2}</div>
|
||||
@@ -0,0 +1,14 @@
|
||||
// @gating
|
||||
import {memo} from 'react';
|
||||
import {Stringify} from 'shared-runtime';
|
||||
|
||||
export default memo(Foo);
|
||||
function Foo({prop1, prop2}) {
|
||||
'use memo';
|
||||
return <Stringify prop1={prop1} prop2={prop2} />;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: eval('Foo'),
|
||||
params: [{prop1: 1, prop2: 2}],
|
||||
};
|
||||
@@ -13,6 +13,11 @@ component Component(value: string) {
|
||||
|
||||
export default memo<Props>(Component);
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: eval('Component'),
|
||||
params: [{value: 'foo'}],
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
## Code
|
||||
@@ -43,5 +48,12 @@ const Component = isForgetEnabled_Fixtures()
|
||||
|
||||
export default memo<Props>(Component);
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: eval("Component"),
|
||||
params: [{ value: "foo" }],
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
|
||||
### Eval output
|
||||
(kind: ok) <div>foo</div>
|
||||
@@ -8,3 +8,8 @@ component Component(value: string) {
|
||||
}
|
||||
|
||||
export default memo<Props>(Component);
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: eval('Component'),
|
||||
params: [{value: 'foo'}],
|
||||
};
|
||||
@@ -35,4 +35,7 @@ export default React.forwardRef(
|
||||
);
|
||||
|
||||
```
|
||||
|
||||
|
||||
### Eval output
|
||||
(kind: exception) Fixture not implemented
|
||||
logs: ['forwardRef render functions accept exactly two parameters: props and ref. %s','Did you forget to use the ref parameter?']
|
||||
@@ -0,0 +1,59 @@
|
||||
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
// @gating
|
||||
import * as React from 'react';
|
||||
|
||||
let Foo;
|
||||
const MemoFoo = React.memo(Foo);
|
||||
Foo = () => <div>hello world!</div>;
|
||||
|
||||
/**
|
||||
* Evaluate this fixture module to assert that compiler + original have the same
|
||||
* runtime error message.
|
||||
*/
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: () => {},
|
||||
params: [],
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
## Code
|
||||
|
||||
```javascript
|
||||
import { isForgetEnabled_Fixtures } from "ReactForgetFeatureFlag";
|
||||
import { c as _c } from "react/compiler-runtime"; // @gating
|
||||
import * as React from "react";
|
||||
|
||||
let Foo;
|
||||
const MemoFoo = React.memo(Foo);
|
||||
Foo = isForgetEnabled_Fixtures()
|
||||
? () => {
|
||||
const $ = _c(1);
|
||||
let t0;
|
||||
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
|
||||
t0 = <div>hello world!</div>;
|
||||
$[0] = t0;
|
||||
} else {
|
||||
t0 = $[0];
|
||||
}
|
||||
return t0;
|
||||
}
|
||||
: () => <div>hello world!</div>;
|
||||
|
||||
/**
|
||||
* Evaluate this fixture module to assert that compiler + original have the same
|
||||
* runtime error message.
|
||||
*/
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: isForgetEnabled_Fixtures() ? () => {} : () => {},
|
||||
params: [],
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
### Eval output
|
||||
(kind: ok)
|
||||
logs: ['memo: The first argument must be a component. Instead received: %s','undefined']
|
||||
@@ -0,0 +1,15 @@
|
||||
// @gating
|
||||
import * as React from 'react';
|
||||
|
||||
let Foo;
|
||||
const MemoFoo = React.memo(Foo);
|
||||
Foo = () => <div>hello world!</div>;
|
||||
|
||||
/**
|
||||
* Evaluate this fixture module to assert that compiler + original have the same
|
||||
* runtime error message.
|
||||
*/
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: () => {},
|
||||
params: [],
|
||||
};
|
||||
@@ -3,17 +3,17 @@
|
||||
|
||||
```javascript
|
||||
// @gating
|
||||
const ErrorView = (error, _retry) => <MessageBox error={error}></MessageBox>;
|
||||
import {Stringify} from 'shared-runtime';
|
||||
|
||||
const Renderer = props => (
|
||||
const ErrorView = (error, _retry) => <Stringify error={error}></Stringify>;
|
||||
|
||||
export default props => (
|
||||
<Foo>
|
||||
<Bar></Bar>
|
||||
<ErrorView></ErrorView>
|
||||
</Foo>
|
||||
);
|
||||
|
||||
export default Renderer;
|
||||
|
||||
```
|
||||
|
||||
## Code
|
||||
@@ -21,12 +21,14 @@ export default Renderer;
|
||||
```javascript
|
||||
import { isForgetEnabled_Fixtures } from "ReactForgetFeatureFlag";
|
||||
import { c as _c } from "react/compiler-runtime"; // @gating
|
||||
import { Stringify } from "shared-runtime";
|
||||
|
||||
const ErrorView = isForgetEnabled_Fixtures()
|
||||
? (error, _retry) => {
|
||||
const $ = _c(2);
|
||||
let t0;
|
||||
if ($[0] !== error) {
|
||||
t0 = <MessageBox error={error} />;
|
||||
t0 = <Stringify error={error} />;
|
||||
$[0] = error;
|
||||
$[1] = t0;
|
||||
} else {
|
||||
@@ -34,9 +36,9 @@ const ErrorView = isForgetEnabled_Fixtures()
|
||||
}
|
||||
return t0;
|
||||
}
|
||||
: (error, _retry) => <MessageBox error={error}></MessageBox>;
|
||||
: (error, _retry) => <Stringify error={error}></Stringify>;
|
||||
|
||||
const Renderer = isForgetEnabled_Fixtures()
|
||||
export default isForgetEnabled_Fixtures()
|
||||
? (props) => {
|
||||
const $ = _c(1);
|
||||
let t0;
|
||||
@@ -59,7 +61,8 @@ const Renderer = isForgetEnabled_Fixtures()
|
||||
<ErrorView></ErrorView>
|
||||
</Foo>
|
||||
);
|
||||
export default Renderer;
|
||||
|
||||
```
|
||||
|
||||
|
||||
### Eval output
|
||||
(kind: exception) Fixture not implemented
|
||||
@@ -0,0 +1,11 @@
|
||||
// @gating
|
||||
import {Stringify} from 'shared-runtime';
|
||||
|
||||
const ErrorView = (error, _retry) => <Stringify error={error}></Stringify>;
|
||||
|
||||
export default props => (
|
||||
<Foo>
|
||||
<Bar></Bar>
|
||||
<ErrorView></ErrorView>
|
||||
</Foo>
|
||||
);
|
||||
@@ -3,15 +3,22 @@
|
||||
|
||||
```javascript
|
||||
// @gating
|
||||
const ErrorView = (error, _retry) => <MessageBox error={error}></MessageBox>;
|
||||
import {Stringify} from 'shared-runtime';
|
||||
|
||||
const ErrorView = (error, _retry) => <Stringify error={error}></Stringify>;
|
||||
|
||||
export const Renderer = props => (
|
||||
<Foo>
|
||||
<Bar></Bar>
|
||||
<div>
|
||||
<span></span>
|
||||
<ErrorView></ErrorView>
|
||||
</Foo>
|
||||
</div>
|
||||
);
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: eval('Renderer'),
|
||||
params: [{}],
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
## Code
|
||||
@@ -19,12 +26,14 @@ export const Renderer = props => (
|
||||
```javascript
|
||||
import { isForgetEnabled_Fixtures } from "ReactForgetFeatureFlag";
|
||||
import { c as _c } from "react/compiler-runtime"; // @gating
|
||||
import { Stringify } from "shared-runtime";
|
||||
|
||||
const ErrorView = isForgetEnabled_Fixtures()
|
||||
? (error, _retry) => {
|
||||
const $ = _c(2);
|
||||
let t0;
|
||||
if ($[0] !== error) {
|
||||
t0 = <MessageBox error={error} />;
|
||||
t0 = <Stringify error={error} />;
|
||||
$[0] = error;
|
||||
$[1] = t0;
|
||||
} else {
|
||||
@@ -32,7 +41,7 @@ const ErrorView = isForgetEnabled_Fixtures()
|
||||
}
|
||||
return t0;
|
||||
}
|
||||
: (error, _retry) => <MessageBox error={error}></MessageBox>;
|
||||
: (error, _retry) => <Stringify error={error}></Stringify>;
|
||||
|
||||
export const Renderer = isForgetEnabled_Fixtures()
|
||||
? (props) => {
|
||||
@@ -40,10 +49,10 @@ export const Renderer = isForgetEnabled_Fixtures()
|
||||
let t0;
|
||||
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
|
||||
t0 = (
|
||||
<Foo>
|
||||
<Bar />
|
||||
<div>
|
||||
<span />
|
||||
<ErrorView />
|
||||
</Foo>
|
||||
</div>
|
||||
);
|
||||
$[0] = t0;
|
||||
} else {
|
||||
@@ -52,11 +61,17 @@ export const Renderer = isForgetEnabled_Fixtures()
|
||||
return t0;
|
||||
}
|
||||
: (props) => (
|
||||
<Foo>
|
||||
<Bar></Bar>
|
||||
<div>
|
||||
<span></span>
|
||||
<ErrorView></ErrorView>
|
||||
</Foo>
|
||||
</div>
|
||||
);
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: eval("Renderer"),
|
||||
params: [{}],
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
|
||||
### Eval output
|
||||
(kind: ok) <div><span></span><div>{"error":{}}</div></div>
|
||||
@@ -0,0 +1,16 @@
|
||||
// @gating
|
||||
import {Stringify} from 'shared-runtime';
|
||||
|
||||
const ErrorView = (error, _retry) => <Stringify error={error}></Stringify>;
|
||||
|
||||
export const Renderer = props => (
|
||||
<div>
|
||||
<span></span>
|
||||
<ErrorView></ErrorView>
|
||||
</div>
|
||||
);
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: eval('Renderer'),
|
||||
params: [{}],
|
||||
};
|
||||
@@ -3,15 +3,24 @@
|
||||
|
||||
```javascript
|
||||
// @gating
|
||||
const ErrorView = (error, _retry) => <MessageBox error={error}></MessageBox>;
|
||||
import {Stringify} from 'shared-runtime';
|
||||
|
||||
export default Renderer = props => (
|
||||
<Foo>
|
||||
<Bar></Bar>
|
||||
const ErrorView = (error, _retry) => <Stringify error={error}></Stringify>;
|
||||
|
||||
const Renderer = props => (
|
||||
<div>
|
||||
<span></span>
|
||||
<ErrorView></ErrorView>
|
||||
</Foo>
|
||||
</div>
|
||||
);
|
||||
|
||||
export default Renderer;
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: eval('Renderer'),
|
||||
params: [{}],
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
## Code
|
||||
@@ -19,12 +28,14 @@ export default Renderer = props => (
|
||||
```javascript
|
||||
import { isForgetEnabled_Fixtures } from "ReactForgetFeatureFlag";
|
||||
import { c as _c } from "react/compiler-runtime"; // @gating
|
||||
import { Stringify } from "shared-runtime";
|
||||
|
||||
const ErrorView = isForgetEnabled_Fixtures()
|
||||
? (error, _retry) => {
|
||||
const $ = _c(2);
|
||||
let t0;
|
||||
if ($[0] !== error) {
|
||||
t0 = <MessageBox error={error} />;
|
||||
t0 = <Stringify error={error} />;
|
||||
$[0] = error;
|
||||
$[1] = t0;
|
||||
} else {
|
||||
@@ -32,18 +43,18 @@ const ErrorView = isForgetEnabled_Fixtures()
|
||||
}
|
||||
return t0;
|
||||
}
|
||||
: (error, _retry) => <MessageBox error={error}></MessageBox>;
|
||||
: (error, _retry) => <Stringify error={error}></Stringify>;
|
||||
|
||||
export default Renderer = isForgetEnabled_Fixtures()
|
||||
const Renderer = isForgetEnabled_Fixtures()
|
||||
? (props) => {
|
||||
const $ = _c(1);
|
||||
let t0;
|
||||
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
|
||||
t0 = (
|
||||
<Foo>
|
||||
<Bar />
|
||||
<div>
|
||||
<span />
|
||||
<ErrorView />
|
||||
</Foo>
|
||||
</div>
|
||||
);
|
||||
$[0] = t0;
|
||||
} else {
|
||||
@@ -52,11 +63,19 @@ export default Renderer = isForgetEnabled_Fixtures()
|
||||
return t0;
|
||||
}
|
||||
: (props) => (
|
||||
<Foo>
|
||||
<Bar></Bar>
|
||||
<div>
|
||||
<span></span>
|
||||
<ErrorView></ErrorView>
|
||||
</Foo>
|
||||
</div>
|
||||
);
|
||||
export default Renderer;
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: eval("Renderer"),
|
||||
params: [{}],
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
|
||||
### Eval output
|
||||
(kind: ok) <div><span></span><div>{"error":{}}</div></div>
|
||||
@@ -0,0 +1,18 @@
|
||||
// @gating
|
||||
import {Stringify} from 'shared-runtime';
|
||||
|
||||
const ErrorView = (error, _retry) => <Stringify error={error}></Stringify>;
|
||||
|
||||
const Renderer = props => (
|
||||
<div>
|
||||
<span></span>
|
||||
<ErrorView></ErrorView>
|
||||
</div>
|
||||
);
|
||||
|
||||
export default Renderer;
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: eval('Renderer'),
|
||||
params: [{}],
|
||||
};
|
||||
@@ -0,0 +1,86 @@
|
||||
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
// @gating
|
||||
import * as React from 'react';
|
||||
|
||||
/**
|
||||
* Test that the correct `Foo` is printed
|
||||
*/
|
||||
let Foo = () => <div>hello world 1!</div>;
|
||||
const MemoOne = React.memo(Foo);
|
||||
Foo = () => <div>hello world 2!</div>;
|
||||
const MemoTwo = React.memo(Foo);
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: () => {
|
||||
'use no memo';
|
||||
return (
|
||||
<>
|
||||
<MemoOne />
|
||||
<MemoTwo />
|
||||
</>
|
||||
);
|
||||
},
|
||||
params: [],
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
## Code
|
||||
|
||||
```javascript
|
||||
import { isForgetEnabled_Fixtures } from "ReactForgetFeatureFlag";
|
||||
import { c as _c } from "react/compiler-runtime"; // @gating
|
||||
import * as React from "react";
|
||||
|
||||
/**
|
||||
* Test that the correct `Foo` is printed
|
||||
*/
|
||||
let Foo = isForgetEnabled_Fixtures()
|
||||
? () => {
|
||||
const $ = _c(1);
|
||||
let t0;
|
||||
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
|
||||
t0 = <div>hello world 1!</div>;
|
||||
$[0] = t0;
|
||||
} else {
|
||||
t0 = $[0];
|
||||
}
|
||||
return t0;
|
||||
}
|
||||
: () => <div>hello world 1!</div>;
|
||||
const MemoOne = React.memo(Foo);
|
||||
Foo = isForgetEnabled_Fixtures()
|
||||
? () => {
|
||||
const $ = _c(1);
|
||||
let t0;
|
||||
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
|
||||
t0 = <div>hello world 2!</div>;
|
||||
$[0] = t0;
|
||||
} else {
|
||||
t0 = $[0];
|
||||
}
|
||||
return t0;
|
||||
}
|
||||
: () => <div>hello world 2!</div>;
|
||||
const MemoTwo = React.memo(Foo);
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: () => {
|
||||
"use no memo";
|
||||
return (
|
||||
<>
|
||||
<MemoOne />
|
||||
<MemoTwo />
|
||||
</>
|
||||
);
|
||||
},
|
||||
params: [],
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
### Eval output
|
||||
(kind: ok) <div>hello world 1!</div><div>hello world 2!</div>
|
||||
@@ -0,0 +1,23 @@
|
||||
// @gating
|
||||
import * as React from 'react';
|
||||
|
||||
/**
|
||||
* Test that the correct `Foo` is printed
|
||||
*/
|
||||
let Foo = () => <div>hello world 1!</div>;
|
||||
const MemoOne = React.memo(Foo);
|
||||
Foo = () => <div>hello world 2!</div>;
|
||||
const MemoTwo = React.memo(Foo);
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: () => {
|
||||
'use no memo';
|
||||
return (
|
||||
<>
|
||||
<MemoOne />
|
||||
<MemoTwo />
|
||||
</>
|
||||
);
|
||||
},
|
||||
params: [],
|
||||
};
|
||||
@@ -0,0 +1,26 @@
|
||||
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
// @inferEffectDependencies @compilationMode(infer) @panicThreshold(none)
|
||||
import useMyEffect from 'useEffectWrapper';
|
||||
|
||||
function nonReactFn(arg) {
|
||||
useMyEffect(() => [1, 2, arg]);
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
## Error
|
||||
|
||||
```
|
||||
3 |
|
||||
4 | function nonReactFn(arg) {
|
||||
> 5 | useMyEffect(() => [1, 2, arg]);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ InvalidReact: [InferEffectDependencies] React Compiler is unable to infer dependencies of this effect. This will break your build! To resolve, either pass your own dependency array or fix reported compiler bailout diagnostics. (5:5)
|
||||
6 | }
|
||||
7 |
|
||||
```
|
||||
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
// @inferEffectDependencies @compilationMode(infer) @panicThreshold(none)
|
||||
import useMyEffect from 'useEffectWrapper';
|
||||
|
||||
function nonReactFn(arg) {
|
||||
useMyEffect(() => [1, 2, arg]);
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
// @inferEffectDependencies @compilationMode(infer) @panicThreshold(none)
|
||||
import {useEffect} from 'react';
|
||||
|
||||
function nonReactFn(arg) {
|
||||
useEffect(() => [1, 2, arg]);
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
## Error
|
||||
|
||||
```
|
||||
3 |
|
||||
4 | function nonReactFn(arg) {
|
||||
> 5 | useEffect(() => [1, 2, arg]);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ InvalidReact: [InferEffectDependencies] React Compiler is unable to infer dependencies of this effect. This will break your build! To resolve, either pass your own dependency array or fix reported compiler bailout diagnostics. (5:5)
|
||||
6 | }
|
||||
7 |
|
||||
```
|
||||
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
// @inferEffectDependencies @compilationMode(infer) @panicThreshold(none)
|
||||
import {useEffect} from 'react';
|
||||
|
||||
function nonReactFn(arg) {
|
||||
useEffect(() => [1, 2, arg]);
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
// @inferEffectDependencies @panicThreshold(none)
|
||||
import {useEffect} from 'react';
|
||||
|
||||
/**
|
||||
* Error on non-inlined effect functions:
|
||||
* 1. From the effect hook callee's perspective, it only makes sense
|
||||
* to either
|
||||
* (a) never hard error (i.e. failing to infer deps is acceptable) or
|
||||
* (b) always hard error,
|
||||
* regardless of whether the callback function is an inline fn.
|
||||
* 2. (Technical detail) it's harder to support detecting cases in which
|
||||
* function (pre-Forget transform) was inline but becomes memoized
|
||||
*/
|
||||
function Component({foo}) {
|
||||
function f() {
|
||||
console.log(foo);
|
||||
}
|
||||
|
||||
// No inferred dep array, the argument is not a lambda
|
||||
useEffect(f);
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
## Error
|
||||
|
||||
```
|
||||
18 |
|
||||
19 | // No inferred dep array, the argument is not a lambda
|
||||
> 20 | useEffect(f);
|
||||
| ^^^^^^^^^^^^ InvalidReact: [InferEffectDependencies] React Compiler is unable to infer dependencies of this effect. This will break your build! To resolve, either pass your own dependency array or fix reported compiler bailout diagnostics. (20:20)
|
||||
21 | }
|
||||
22 |
|
||||
```
|
||||
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
// @inferEffectDependencies @panicThreshold(none)
|
||||
import {useEffect} from 'react';
|
||||
|
||||
/**
|
||||
* Error on non-inlined effect functions:
|
||||
* 1. From the effect hook callee's perspective, it only makes sense
|
||||
* to either
|
||||
* (a) never hard error (i.e. failing to infer deps is acceptable) or
|
||||
* (b) always hard error,
|
||||
* regardless of whether the callback function is an inline fn.
|
||||
* 2. (Technical detail) it's harder to support detecting cases in which
|
||||
* function (pre-Forget transform) was inline but becomes memoized
|
||||
*/
|
||||
function Component({foo}) {
|
||||
function f() {
|
||||
console.log(foo);
|
||||
}
|
||||
|
||||
// No inferred dep array, the argument is not a lambda
|
||||
useEffect(f);
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
// @inferEffectDependencies @panicThreshold(none)
|
||||
import React from 'react';
|
||||
|
||||
function NonReactiveDepInEffect() {
|
||||
const obj = makeObject_Primitives();
|
||||
React.useEffect(() => print(obj));
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
## Error
|
||||
|
||||
```
|
||||
4 | function NonReactiveDepInEffect() {
|
||||
5 | const obj = makeObject_Primitives();
|
||||
> 6 | React.useEffect(() => print(obj));
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ InvalidReact: [InferEffectDependencies] React Compiler is unable to infer dependencies of this effect. This will break your build! To resolve, either pass your own dependency array or fix reported compiler bailout diagnostics. (6:6)
|
||||
7 | }
|
||||
8 |
|
||||
```
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// @inferEffectDependencies
|
||||
// @inferEffectDependencies @panicThreshold(none)
|
||||
import React from 'react';
|
||||
|
||||
function NonReactiveDepInEffect() {
|
||||
@@ -0,0 +1,51 @@
|
||||
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
// @inferEffectDependencies @panicThreshold(none)
|
||||
import {useSpecialEffect} from 'shared-runtime';
|
||||
|
||||
/**
|
||||
* Note that a react compiler-based transform still has limitations on JS syntax.
|
||||
* We should surface these as actionable lint / build errors to devs.
|
||||
*/
|
||||
function Component({prop1}) {
|
||||
'use memo';
|
||||
useSpecialEffect(() => {
|
||||
try {
|
||||
console.log(prop1);
|
||||
} finally {
|
||||
console.log('exiting');
|
||||
}
|
||||
}, [prop1]);
|
||||
return <div>{prop1}</div>;
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
## Error
|
||||
|
||||
```
|
||||
8 | function Component({prop1}) {
|
||||
9 | 'use memo';
|
||||
> 10 | useSpecialEffect(() => {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
> 11 | try {
|
||||
| ^^^^^^^^^
|
||||
> 12 | console.log(prop1);
|
||||
| ^^^^^^^^^
|
||||
> 13 | } finally {
|
||||
| ^^^^^^^^^
|
||||
> 14 | console.log('exiting');
|
||||
| ^^^^^^^^^
|
||||
> 15 | }
|
||||
| ^^^^^^^^^
|
||||
> 16 | }, [prop1]);
|
||||
| ^^^^^^^^^^^^^^ InvalidReact: [InferEffectDependencies] React Compiler is unable to infer dependencies of this effect. This will break your build! To resolve, either pass your own dependency array or fix reported compiler bailout diagnostics.. (Bailout reason: Todo: (BuildHIR::lowerStatement) Handle TryStatement without a catch clause (11:15)) (10:16)
|
||||
17 | return <div>{prop1}</div>;
|
||||
18 | }
|
||||
19 |
|
||||
```
|
||||
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
// @inferEffectDependencies @panicThreshold(none)
|
||||
import {useSpecialEffect} from 'shared-runtime';
|
||||
|
||||
/**
|
||||
* Note that a react compiler-based transform still has limitations on JS syntax.
|
||||
* We should surface these as actionable lint / build errors to devs.
|
||||
*/
|
||||
function Component({prop1}) {
|
||||
'use memo';
|
||||
useSpecialEffect(() => {
|
||||
try {
|
||||
console.log(prop1);
|
||||
} finally {
|
||||
console.log('exiting');
|
||||
}
|
||||
}, [prop1]);
|
||||
return <div>{prop1}</div>;
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
// @inferEffectDependencies @panicThreshold(none)
|
||||
import {useEffect} from 'react';
|
||||
|
||||
function Component({propVal}) {
|
||||
'use no memo';
|
||||
useEffect(() => [propVal]);
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
## Error
|
||||
|
||||
```
|
||||
4 | function Component({propVal}) {
|
||||
5 | 'use no memo';
|
||||
> 6 | useEffect(() => [propVal]);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ InvalidReact: [InferEffectDependencies] React Compiler is unable to infer dependencies of this effect. This will break your build! To resolve, either pass your own dependency array or fix reported compiler bailout diagnostics. (6:6)
|
||||
7 | }
|
||||
8 |
|
||||
```
|
||||
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
// @inferEffectDependencies @panicThreshold(none)
|
||||
import {useEffect} from 'react';
|
||||
|
||||
function Component({propVal}) {
|
||||
'use no memo';
|
||||
useEffect(() => [propVal]);
|
||||
}
|
||||
@@ -34,13 +34,6 @@ function Component({foo, bar}) {
|
||||
console.log(bar.qux);
|
||||
});
|
||||
|
||||
function f() {
|
||||
console.log(foo);
|
||||
}
|
||||
|
||||
// No inferred dep array, the argument is not a lambda
|
||||
useEffect(f);
|
||||
|
||||
useEffectWrapper(() => {
|
||||
console.log(foo);
|
||||
});
|
||||
@@ -58,7 +51,7 @@ import useEffectWrapper from "useEffectWrapper";
|
||||
const moduleNonReactive = 0;
|
||||
|
||||
function Component(t0) {
|
||||
const $ = _c(14);
|
||||
const $ = _c(12);
|
||||
const { foo, bar } = t0;
|
||||
|
||||
const ref = useRef(0);
|
||||
@@ -119,7 +112,7 @@ function Component(t0) {
|
||||
useEffect(t4, [bar.baz, bar.qux]);
|
||||
let t5;
|
||||
if ($[10] !== foo) {
|
||||
t5 = function f() {
|
||||
t5 = () => {
|
||||
console.log(foo);
|
||||
};
|
||||
$[10] = foo;
|
||||
@@ -127,20 +120,7 @@ function Component(t0) {
|
||||
} else {
|
||||
t5 = $[11];
|
||||
}
|
||||
const f = t5;
|
||||
|
||||
useEffect(f);
|
||||
let t6;
|
||||
if ($[12] !== foo) {
|
||||
t6 = () => {
|
||||
console.log(foo);
|
||||
};
|
||||
$[12] = foo;
|
||||
$[13] = t6;
|
||||
} else {
|
||||
t6 = $[13];
|
||||
}
|
||||
useEffectWrapper(t6, [foo]);
|
||||
useEffectWrapper(t5, [foo]);
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
@@ -30,13 +30,6 @@ function Component({foo, bar}) {
|
||||
console.log(bar.qux);
|
||||
});
|
||||
|
||||
function f() {
|
||||
console.log(foo);
|
||||
}
|
||||
|
||||
// No inferred dep array, the argument is not a lambda
|
||||
useEffect(f);
|
||||
|
||||
useEffectWrapper(() => {
|
||||
console.log(foo);
|
||||
});
|
||||
|
||||
@@ -1,44 +0,0 @@
|
||||
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
// @inferEffectDependencies
|
||||
import React from 'react';
|
||||
|
||||
function NonReactiveDepInEffect() {
|
||||
const obj = makeObject_Primitives();
|
||||
React.useEffect(() => print(obj));
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
## Code
|
||||
|
||||
```javascript
|
||||
import { c as _c } from "react/compiler-runtime"; // @inferEffectDependencies
|
||||
import React from "react";
|
||||
|
||||
function NonReactiveDepInEffect() {
|
||||
const $ = _c(2);
|
||||
let t0;
|
||||
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
|
||||
t0 = makeObject_Primitives();
|
||||
$[0] = t0;
|
||||
} else {
|
||||
t0 = $[0];
|
||||
}
|
||||
const obj = t0;
|
||||
let t1;
|
||||
if ($[1] === Symbol.for("react.memo_cache_sentinel")) {
|
||||
t1 = () => print(obj);
|
||||
$[1] = t1;
|
||||
} else {
|
||||
t1 = $[1];
|
||||
}
|
||||
React.useEffect(t1);
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
### Eval output
|
||||
(kind: exception) Fixture not implemented
|
||||
@@ -1,9 +0,0 @@
|
||||
// @gating
|
||||
const ErrorView = (error, _retry) => <MessageBox error={error}></MessageBox>;
|
||||
|
||||
export default Renderer = props => (
|
||||
<Foo>
|
||||
<Bar></Bar>
|
||||
<ErrorView></ErrorView>
|
||||
</Foo>
|
||||
);
|
||||
@@ -1,9 +0,0 @@
|
||||
// @gating
|
||||
const ErrorView = (error, _retry) => <MessageBox error={error}></MessageBox>;
|
||||
|
||||
export const Renderer = props => (
|
||||
<Foo>
|
||||
<Bar></Bar>
|
||||
<ErrorView></ErrorView>
|
||||
</Foo>
|
||||
);
|
||||
@@ -1,11 +0,0 @@
|
||||
// @gating
|
||||
const ErrorView = (error, _retry) => <MessageBox error={error}></MessageBox>;
|
||||
|
||||
const Renderer = props => (
|
||||
<Foo>
|
||||
<Bar></Bar>
|
||||
<ErrorView></ErrorView>
|
||||
</Foo>
|
||||
);
|
||||
|
||||
export default Renderer;
|
||||
@@ -0,0 +1,65 @@
|
||||
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
function Test() {
|
||||
const obj = {
|
||||
21: 'dimaMachina',
|
||||
};
|
||||
// Destructuring assignment
|
||||
const {21: myVar} = obj;
|
||||
return (
|
||||
<div>
|
||||
{obj[21]}
|
||||
{myVar}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: Test,
|
||||
params: [{}],
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
## Code
|
||||
|
||||
```javascript
|
||||
import { c as _c } from "react/compiler-runtime";
|
||||
function Test() {
|
||||
const $ = _c(2);
|
||||
let t0;
|
||||
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
|
||||
t0 = { 21: "dimaMachina" };
|
||||
$[0] = t0;
|
||||
} else {
|
||||
t0 = $[0];
|
||||
}
|
||||
const obj = t0;
|
||||
|
||||
const { 21: myVar } = obj;
|
||||
let t1;
|
||||
if ($[1] === Symbol.for("react.memo_cache_sentinel")) {
|
||||
t1 = (
|
||||
<div>
|
||||
{obj[21]}
|
||||
{myVar}
|
||||
</div>
|
||||
);
|
||||
$[1] = t1;
|
||||
} else {
|
||||
t1 = $[1];
|
||||
}
|
||||
return t1;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: Test,
|
||||
params: [{}],
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
### Eval output
|
||||
(kind: ok) <div>dimaMachinadimaMachina</div>
|
||||
@@ -0,0 +1,18 @@
|
||||
function Test() {
|
||||
const obj = {
|
||||
21: 'dimaMachina',
|
||||
};
|
||||
// Destructuring assignment
|
||||
const {21: myVar} = obj;
|
||||
return (
|
||||
<div>
|
||||
{obj[21]}
|
||||
{myVar}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: Test,
|
||||
params: [{}],
|
||||
};
|
||||
@@ -2,7 +2,7 @@
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
// @validateNoCapitalizedCalls @enableFire
|
||||
// @validateNoCapitalizedCalls @enableFire @panicThreshold(none)
|
||||
import {fire} from 'react';
|
||||
const CapitalizedCall = require('shared-runtime').sum;
|
||||
|
||||
@@ -24,7 +24,7 @@ function Component({prop1, bar}) {
|
||||
## Code
|
||||
|
||||
```javascript
|
||||
import { useFire } from "react/compiler-runtime"; // @validateNoCapitalizedCalls @enableFire
|
||||
import { useFire } from "react/compiler-runtime"; // @validateNoCapitalizedCalls @enableFire @panicThreshold(none)
|
||||
import { fire } from "react";
|
||||
const CapitalizedCall = require("shared-runtime").sum;
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user