Compare commits
41 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bbed0b0ee6 | ||
|
|
f3e3f6fbac | ||
|
|
154f4b15e2 | ||
|
|
7aa5dda3b3 | ||
|
|
988e217670 | ||
|
|
380f5d675d | ||
|
|
7ac8e61211 | ||
|
|
3770c11011 | ||
|
|
d9b3841ca6 | ||
|
|
2ec26bc432 | ||
|
|
b836de613d | ||
|
|
ed15d5007c | ||
|
|
6e29479bff | ||
|
|
ff595de29a | ||
|
|
989af12f72 | ||
|
|
5c56b873ef | ||
|
|
682a103cde | ||
|
|
e1378902bb | ||
|
|
a88b9e5f68 | ||
|
|
09197bb786 | ||
|
|
2df8f61885 | ||
|
|
a7b83e7ceb | ||
|
|
66855b9637 | ||
|
|
314968561b | ||
|
|
d1f04722d6 | ||
|
|
3dc1e4820e | ||
|
|
c3570b158d | ||
|
|
fd018af617 | ||
|
|
f2f002c7c1 | ||
|
|
792fa065ca | ||
|
|
33195602ea | ||
|
|
5ca2bc6d63 | ||
|
|
bddb7c9b5c | ||
|
|
f8f6e1a21a | ||
|
|
6c0f37f94b | ||
|
|
527bcaa83d | ||
|
|
e7e269b726 | ||
|
|
dd1a021bad | ||
|
|
156eab2f7b | ||
|
|
b81e6dd2da | ||
|
|
33c7bd9ae3 |
@@ -8,11 +8,9 @@ indent_size = 2
|
||||
indent_style = space
|
||||
insert_final_newline = true
|
||||
max_line_length = 80
|
||||
trim_trailing_whitespace = true
|
||||
|
||||
[*.md]
|
||||
max_line_length = 0
|
||||
trim_trailing_whitespace = false
|
||||
|
||||
[COMMIT_EDITMSG]
|
||||
max_line_length = 0
|
||||
|
||||
@@ -31,6 +31,8 @@ jobs:
|
||||
with:
|
||||
path: "**/node_modules"
|
||||
key: runtime-release-node_modules-${{ 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
|
||||
@@ -63,6 +65,8 @@ jobs:
|
||||
with:
|
||||
path: "**/node_modules"
|
||||
key: runtime-node_modules-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock') }}
|
||||
- name: Ensure clean build directory
|
||||
run: rm -rf build
|
||||
- run: yarn install --frozen-lockfile
|
||||
- name: Restore archived build
|
||||
uses: actions/download-artifact@v4
|
||||
|
||||
30
.github/workflows/runtime_build_and_test.yml
vendored
30
.github/workflows/runtime_build_and_test.yml
vendored
@@ -53,6 +53,8 @@ jobs:
|
||||
with:
|
||||
path: "**/node_modules"
|
||||
key: runtime-node_modules-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock') }}
|
||||
- name: Ensure clean build directory
|
||||
run: rm -rf build
|
||||
- run: yarn install --frozen-lockfile
|
||||
- run: node ./scripts/tasks/flow-ci ${{ matrix.flow_inline_config_shortname }}
|
||||
|
||||
@@ -73,6 +75,8 @@ jobs:
|
||||
with:
|
||||
path: "**/node_modules"
|
||||
key: runtime-node_modules-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock') }}
|
||||
- name: Ensure clean build directory
|
||||
run: rm -rf build
|
||||
- run: yarn install --frozen-lockfile
|
||||
- run: |
|
||||
yarn generate-inline-fizz-runtime
|
||||
@@ -95,6 +99,8 @@ jobs:
|
||||
with:
|
||||
path: "**/node_modules"
|
||||
key: runtime-node_modules-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock') }}
|
||||
- name: Ensure clean build directory
|
||||
run: rm -rf build
|
||||
- run: yarn install --frozen-lockfile
|
||||
- run: yarn flags
|
||||
|
||||
@@ -144,6 +150,8 @@ jobs:
|
||||
with:
|
||||
path: "**/node_modules"
|
||||
key: runtime-node_modules-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock') }}
|
||||
- name: Ensure clean build directory
|
||||
run: rm -rf build
|
||||
- run: yarn install --frozen-lockfile
|
||||
- run: yarn test ${{ matrix.params }} --ci --shard=${{ matrix.shard }}
|
||||
|
||||
@@ -173,6 +181,8 @@ jobs:
|
||||
with:
|
||||
path: "**/node_modules"
|
||||
key: runtime-node_modules-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock') }}
|
||||
- name: Ensure clean build directory
|
||||
run: rm -rf build
|
||||
- run: yarn install --frozen-lockfile
|
||||
- run: yarn build --index=${{ matrix.worker_id }} --total=20 --r=${{ matrix.release_channel }} --ci
|
||||
env:
|
||||
@@ -243,6 +253,8 @@ jobs:
|
||||
with:
|
||||
path: "**/node_modules"
|
||||
key: runtime-node_modules-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock') }}
|
||||
- name: Ensure clean build directory
|
||||
run: rm -rf build
|
||||
- run: yarn install --frozen-lockfile
|
||||
- name: Restore archived build
|
||||
uses: actions/download-artifact@v4
|
||||
@@ -271,6 +283,8 @@ jobs:
|
||||
with:
|
||||
path: "**/node_modules"
|
||||
key: runtime-node_modules-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock') }}
|
||||
- name: Ensure clean build directory
|
||||
run: rm -rf build
|
||||
- run: yarn install --frozen-lockfile
|
||||
- name: Restore archived build
|
||||
uses: actions/download-artifact@v4
|
||||
@@ -314,6 +328,8 @@ jobs:
|
||||
with:
|
||||
path: "**/node_modules"
|
||||
key: runtime-node_modules-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock') }}
|
||||
- name: Ensure clean build directory
|
||||
run: rm -rf build
|
||||
- run: yarn install --frozen-lockfile
|
||||
- name: Restore archived build
|
||||
uses: actions/download-artifact@v4
|
||||
@@ -345,6 +361,8 @@ jobs:
|
||||
with:
|
||||
path: "**/node_modules"
|
||||
key: runtime-node_modules-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock') }}
|
||||
- name: Ensure clean build directory
|
||||
run: rm -rf build
|
||||
- run: yarn install --frozen-lockfile
|
||||
- name: Restore archived build
|
||||
uses: actions/download-artifact@v4
|
||||
@@ -373,6 +391,8 @@ jobs:
|
||||
with:
|
||||
path: "**/node_modules"
|
||||
key: fixtures_dom-node_modules-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock') }}
|
||||
- name: Ensure clean build directory
|
||||
run: rm -rf build
|
||||
- run: yarn install --frozen-lockfile
|
||||
- run: yarn install --frozen-lockfile --cache-folder ~/.cache/yarn
|
||||
working-directory: fixtures/dom
|
||||
@@ -413,6 +433,8 @@ jobs:
|
||||
with:
|
||||
path: "**/node_modules"
|
||||
key: fixtures_flight-node_modules-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock') }}
|
||||
- name: Ensure clean build directory
|
||||
run: rm -rf build
|
||||
- run: yarn install --frozen-lockfile
|
||||
- name: Restore archived build
|
||||
uses: actions/download-artifact@v4
|
||||
@@ -469,6 +491,8 @@ jobs:
|
||||
with:
|
||||
path: "**/node_modules"
|
||||
key: runtime-node_modules-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock') }}
|
||||
- name: Ensure clean build directory
|
||||
run: rm -rf build
|
||||
- run: yarn install --frozen-lockfile
|
||||
- name: Restore archived build
|
||||
uses: actions/download-artifact@v4
|
||||
@@ -515,6 +539,8 @@ jobs:
|
||||
with:
|
||||
path: "**/node_modules"
|
||||
key: runtime-node_modules-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock') }}
|
||||
- name: Ensure clean build directory
|
||||
run: rm -rf build
|
||||
- run: yarn install --frozen-lockfile
|
||||
- name: Restore archived build
|
||||
uses: actions/download-artifact@v4
|
||||
@@ -547,6 +573,8 @@ jobs:
|
||||
with:
|
||||
path: "**/node_modules"
|
||||
key: ${{ runner.arch }}-${{ runner.os }}-modules-${{ 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
|
||||
@@ -586,6 +614,8 @@ jobs:
|
||||
with:
|
||||
path: "**/node_modules"
|
||||
key: runtime-node_modules-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock') }}
|
||||
- name: Ensure clean build directory
|
||||
run: rm -rf build
|
||||
- run: yarn install --frozen-lockfile
|
||||
- name: Restore archived build for PR
|
||||
uses: actions/download-artifact@v4
|
||||
|
||||
@@ -75,6 +75,8 @@ jobs:
|
||||
with:
|
||||
path: "**/node_modules"
|
||||
key: runtime-release-node_modules-${{ 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
|
||||
|
||||
2
.github/workflows/runtime_prereleases.yml
vendored
2
.github/workflows/runtime_prereleases.yml
vendored
@@ -41,6 +41,8 @@ jobs:
|
||||
with:
|
||||
path: "**/node_modules"
|
||||
key: runtime-release-node_modules-${{ 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
|
||||
|
||||
8
.github/workflows/shared_lint.yml
vendored
8
.github/workflows/shared_lint.yml
vendored
@@ -30,6 +30,8 @@ jobs:
|
||||
with:
|
||||
path: "**/node_modules"
|
||||
key: shared-lint-node_modules-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('**/yarn.lock') }}
|
||||
- name: Ensure clean build directory
|
||||
run: rm -rf build
|
||||
- run: yarn install --frozen-lockfile
|
||||
- run: yarn prettier-check
|
||||
|
||||
@@ -48,6 +50,8 @@ jobs:
|
||||
with:
|
||||
path: "**/node_modules"
|
||||
key: shared-lint-node_modules-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('**/yarn.lock') }}
|
||||
- name: Ensure clean build directory
|
||||
run: rm -rf build
|
||||
- run: yarn install --frozen-lockfile
|
||||
- run: node ./scripts/tasks/eslint
|
||||
|
||||
@@ -66,6 +70,8 @@ jobs:
|
||||
with:
|
||||
path: "**/node_modules"
|
||||
key: shared-lint-node_modules-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('**/yarn.lock') }}
|
||||
- name: Ensure clean build directory
|
||||
run: rm -rf build
|
||||
- run: yarn install --frozen-lockfile
|
||||
- run: ./scripts/ci/check_license.sh
|
||||
|
||||
@@ -84,5 +90,7 @@ jobs:
|
||||
with:
|
||||
path: "**/node_modules"
|
||||
key: shared-lint-node_modules-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('**/yarn.lock') }}
|
||||
- name: Ensure clean build directory
|
||||
run: rm -rf build
|
||||
- run: yarn install --frozen-lockfile
|
||||
- run: ./scripts/ci/test_print_warnings.sh
|
||||
|
||||
@@ -7,18 +7,18 @@
|
||||
//
|
||||
// The @latest channel uses the version as-is, e.g.:
|
||||
//
|
||||
// 19.0.0
|
||||
// 19.0.1
|
||||
//
|
||||
// The @canary channel appends additional information, with the scheme
|
||||
// <version>-<label>-<commit_sha>, e.g.:
|
||||
//
|
||||
// 19.0.0-canary-a1c2d3e4
|
||||
// 19.0.1-canary-a1c2d3e4
|
||||
//
|
||||
// The @experimental channel doesn't include a version, only a date and a sha, e.g.:
|
||||
//
|
||||
// 0.0.0-experimental-241c4467e-20200129
|
||||
|
||||
const ReactVersion = '19.0.0';
|
||||
const ReactVersion = '19.0.1';
|
||||
|
||||
// The label used by the @canary channel. Represents the upcoming release's
|
||||
// stability. Most of the time, this will be "canary", but we may temporarily
|
||||
@@ -30,7 +30,7 @@ const canaryChannelLabel = 'rc';
|
||||
|
||||
// If the canaryChannelLabel is "rc", the build pipeline will use this to build
|
||||
// an RC version of the packages.
|
||||
const rcNumber = 0;
|
||||
const rcNumber = 1;
|
||||
|
||||
const stablePackages = {
|
||||
'eslint-plugin-react-hooks': '5.1.0',
|
||||
|
||||
@@ -14,7 +14,7 @@ import {
|
||||
CompilerErrorDetail,
|
||||
Effect,
|
||||
ErrorSeverity,
|
||||
parseConfigPragma,
|
||||
parseConfigPragmaForTests,
|
||||
ValueKind,
|
||||
runPlayground,
|
||||
type Hook,
|
||||
@@ -208,7 +208,7 @@ function compile(source: string): [CompilerOutput, 'flow' | 'typescript'] {
|
||||
try {
|
||||
// Extract the first line to quickly check for custom test directives
|
||||
const pragma = source.substring(0, source.indexOf('\n'));
|
||||
const config = parseConfigPragma(pragma);
|
||||
const config = parseConfigPragmaForTests(pragma);
|
||||
|
||||
for (const fn of parseFunctions(source, language)) {
|
||||
const id = withIdentifier(getFunctionIdentifier(fn));
|
||||
|
||||
0
compiler/fixtures/.gitkeep
Normal file
0
compiler/fixtures/.gitkeep
Normal file
@@ -1 +0,0 @@
|
||||
Reference library compiled with React Compiler.
|
||||
@@ -1,24 +0,0 @@
|
||||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
pnpm-debug.log*
|
||||
lerna-debug.log*
|
||||
|
||||
node_modules
|
||||
dist
|
||||
dist-ssr
|
||||
*.local
|
||||
|
||||
# Editor directories and files
|
||||
.vscode/*
|
||||
!.vscode/extensions.json
|
||||
.idea
|
||||
.DS_Store
|
||||
*.suo
|
||||
*.ntvs*
|
||||
*.njsproj
|
||||
*.sln
|
||||
*.sw?
|
||||
@@ -1,50 +0,0 @@
|
||||
# React + TypeScript + Vite
|
||||
|
||||
This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules.
|
||||
|
||||
Currently, two official plugins are available:
|
||||
|
||||
- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react/README.md) uses [Babel](https://babeljs.io/) for Fast Refresh
|
||||
- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh
|
||||
|
||||
## Expanding the ESLint configuration
|
||||
|
||||
If you are developing a production application, we recommend updating the configuration to enable type aware lint rules:
|
||||
|
||||
- Configure the top-level `parserOptions` property like this:
|
||||
|
||||
```js
|
||||
export default tseslint.config({
|
||||
languageOptions: {
|
||||
// other options...
|
||||
parserOptions: {
|
||||
project: ['./tsconfig.node.json', './tsconfig.app.json'],
|
||||
tsconfigRootDir: import.meta.dirname,
|
||||
},
|
||||
},
|
||||
})
|
||||
```
|
||||
|
||||
- Replace `tseslint.configs.recommended` to `tseslint.configs.recommendedTypeChecked` or `tseslint.configs.strictTypeChecked`
|
||||
- Optionally add `...tseslint.configs.stylisticTypeChecked`
|
||||
- Install [eslint-plugin-react](https://github.com/jsx-eslint/eslint-plugin-react) and update the config:
|
||||
|
||||
```js
|
||||
// eslint.config.js
|
||||
import react from 'eslint-plugin-react'
|
||||
|
||||
export default tseslint.config({
|
||||
// Set the react version
|
||||
settings: { react: { version: '18.3' } },
|
||||
plugins: {
|
||||
// Add the react plugin
|
||||
react,
|
||||
},
|
||||
rules: {
|
||||
// other rules...
|
||||
// Enable its recommended rules
|
||||
...react.configs.recommended.rules,
|
||||
...react.configs['jsx-runtime'].rules,
|
||||
},
|
||||
})
|
||||
```
|
||||
@@ -1,28 +0,0 @@
|
||||
import js from '@eslint/js';
|
||||
import globals from 'globals';
|
||||
import reactHooks from 'eslint-plugin-react-hooks';
|
||||
import reactRefresh from 'eslint-plugin-react-refresh';
|
||||
import tseslint from 'typescript-eslint';
|
||||
|
||||
export default tseslint.config(
|
||||
{ignores: ['dist']},
|
||||
{
|
||||
extends: [js.configs.recommended, ...tseslint.configs.recommended],
|
||||
files: ['**/*.{ts,tsx}'],
|
||||
languageOptions: {
|
||||
ecmaVersion: 2020,
|
||||
globals: globals.browser,
|
||||
},
|
||||
plugins: {
|
||||
'react-hooks': reactHooks,
|
||||
'react-refresh': reactRefresh,
|
||||
},
|
||||
rules: {
|
||||
...reactHooks.configs.recommended.rules,
|
||||
'react-refresh/only-export-components': [
|
||||
'warn',
|
||||
{allowConstantExport: true},
|
||||
],
|
||||
},
|
||||
}
|
||||
);
|
||||
@@ -1,13 +0,0 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Vite + React + TS</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
<script type="module" src="/src/main.tsx"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,32 +0,0 @@
|
||||
{
|
||||
"name": "app-18",
|
||||
"private": true,
|
||||
"version": "0.0.0",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"build": "tsc -b && vite build",
|
||||
"lint": "eslint .",
|
||||
"preview": "vite preview"
|
||||
},
|
||||
"dependencies": {
|
||||
"react": "^18.3.1",
|
||||
"react-compiler-runtime": "19.0.0-beta-9ee70a1-20241017",
|
||||
"react-dom": "^18.3.1",
|
||||
"runtime-compat-lib": "file:../lib"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@eslint/js": "^9.11.1",
|
||||
"@types/react": "^18.3.10",
|
||||
"@types/react-dom": "^18.3.0",
|
||||
"@vitejs/plugin-react": "^4.3.2",
|
||||
"babel-plugin-react-compiler": "19.0.0-beta-9ee70a1-20241017",
|
||||
"eslint": "^9.11.1",
|
||||
"eslint-plugin-react-hooks": "^5.1.0-rc.0",
|
||||
"eslint-plugin-react-refresh": "^0.4.12",
|
||||
"globals": "^15.9.0",
|
||||
"typescript": "^5.5.3",
|
||||
"typescript-eslint": "^8.7.0",
|
||||
"vite": "^5.4.8"
|
||||
}
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg>
|
||||
|
Before Width: | Height: | Size: 1.5 KiB |
@@ -1,42 +0,0 @@
|
||||
#root {
|
||||
max-width: 1280px;
|
||||
margin: 0 auto;
|
||||
padding: 2rem;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.logo {
|
||||
height: 6em;
|
||||
padding: 1.5em;
|
||||
will-change: filter;
|
||||
transition: filter 300ms;
|
||||
}
|
||||
.logo:hover {
|
||||
filter: drop-shadow(0 0 2em #646cffaa);
|
||||
}
|
||||
.logo.react:hover {
|
||||
filter: drop-shadow(0 0 2em #61dafbaa);
|
||||
}
|
||||
|
||||
@keyframes logo-spin {
|
||||
from {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
to {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
|
||||
@media (prefers-reduced-motion: no-preference) {
|
||||
a:nth-of-type(2) .logo {
|
||||
animation: logo-spin infinite 20s linear;
|
||||
}
|
||||
}
|
||||
|
||||
.card {
|
||||
padding: 2em;
|
||||
}
|
||||
|
||||
.read-the-docs {
|
||||
color: #888;
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
import 'react';
|
||||
import './App.css';
|
||||
// @ts-expect-error no types
|
||||
import {useTime} from 'runtime-compat-lib';
|
||||
|
||||
function App() {
|
||||
const time = useTime();
|
||||
return (
|
||||
<>
|
||||
<h1>React 18</h1>
|
||||
<span>Current time: {time.toLocaleString()}</span>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export default App;
|
||||
@@ -1 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="35.93" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 228"><path fill="#00D8FF" d="M210.483 73.824a171.49 171.49 0 0 0-8.24-2.597c.465-1.9.893-3.777 1.273-5.621c6.238-30.281 2.16-54.676-11.769-62.708c-13.355-7.7-35.196.329-57.254 19.526a171.23 171.23 0 0 0-6.375 5.848a155.866 155.866 0 0 0-4.241-3.917C100.759 3.829 77.587-4.822 63.673 3.233C50.33 10.957 46.379 33.89 51.995 62.588a170.974 170.974 0 0 0 1.892 8.48c-3.28.932-6.445 1.924-9.474 2.98C17.309 83.498 0 98.307 0 113.668c0 15.865 18.582 31.778 46.812 41.427a145.52 145.52 0 0 0 6.921 2.165a167.467 167.467 0 0 0-2.01 9.138c-5.354 28.2-1.173 50.591 12.134 58.266c13.744 7.926 36.812-.22 59.273-19.855a145.567 145.567 0 0 0 5.342-4.923a168.064 168.064 0 0 0 6.92 6.314c21.758 18.722 43.246 26.282 56.54 18.586c13.731-7.949 18.194-32.003 12.4-61.268a145.016 145.016 0 0 0-1.535-6.842c1.62-.48 3.21-.974 4.76-1.488c29.348-9.723 48.443-25.443 48.443-41.52c0-15.417-17.868-30.326-45.517-39.844Zm-6.365 70.984c-1.4.463-2.836.91-4.3 1.345c-3.24-10.257-7.612-21.163-12.963-32.432c5.106-11 9.31-21.767 12.459-31.957c2.619.758 5.16 1.557 7.61 2.4c23.69 8.156 38.14 20.213 38.14 29.504c0 9.896-15.606 22.743-40.946 31.14Zm-10.514 20.834c2.562 12.94 2.927 24.64 1.23 33.787c-1.524 8.219-4.59 13.698-8.382 15.893c-8.067 4.67-25.32-1.4-43.927-17.412a156.726 156.726 0 0 1-6.437-5.87c7.214-7.889 14.423-17.06 21.459-27.246c12.376-1.098 24.068-2.894 34.671-5.345a134.17 134.17 0 0 1 1.386 6.193ZM87.276 214.515c-7.882 2.783-14.16 2.863-17.955.675c-8.075-4.657-11.432-22.636-6.853-46.752a156.923 156.923 0 0 1 1.869-8.499c10.486 2.32 22.093 3.988 34.498 4.994c7.084 9.967 14.501 19.128 21.976 27.15a134.668 134.668 0 0 1-4.877 4.492c-9.933 8.682-19.886 14.842-28.658 17.94ZM50.35 144.747c-12.483-4.267-22.792-9.812-29.858-15.863c-6.35-5.437-9.555-10.836-9.555-15.216c0-9.322 13.897-21.212 37.076-29.293c2.813-.98 5.757-1.905 8.812-2.773c3.204 10.42 7.406 21.315 12.477 32.332c-5.137 11.18-9.399 22.249-12.634 32.792a134.718 134.718 0 0 1-6.318-1.979Zm12.378-84.26c-4.811-24.587-1.616-43.134 6.425-47.789c8.564-4.958 27.502 2.111 47.463 19.835a144.318 144.318 0 0 1 3.841 3.545c-7.438 7.987-14.787 17.08-21.808 26.988c-12.04 1.116-23.565 2.908-34.161 5.309a160.342 160.342 0 0 1-1.76-7.887Zm110.427 27.268a347.8 347.8 0 0 0-7.785-12.803c8.168 1.033 15.994 2.404 23.343 4.08c-2.206 7.072-4.956 14.465-8.193 22.045a381.151 381.151 0 0 0-7.365-13.322Zm-45.032-43.861c5.044 5.465 10.096 11.566 15.065 18.186a322.04 322.04 0 0 0-30.257-.006c4.974-6.559 10.069-12.652 15.192-18.18ZM82.802 87.83a323.167 323.167 0 0 0-7.227 13.238c-3.184-7.553-5.909-14.98-8.134-22.152c7.304-1.634 15.093-2.97 23.209-3.984a321.524 321.524 0 0 0-7.848 12.897Zm8.081 65.352c-8.385-.936-16.291-2.203-23.593-3.793c2.26-7.3 5.045-14.885 8.298-22.6a321.187 321.187 0 0 0 7.257 13.246c2.594 4.48 5.28 8.868 8.038 13.147Zm37.542 31.03c-5.184-5.592-10.354-11.779-15.403-18.433c4.902.192 9.899.29 14.978.29c5.218 0 10.376-.117 15.453-.343c-4.985 6.774-10.018 12.97-15.028 18.486Zm52.198-57.817c3.422 7.8 6.306 15.345 8.596 22.52c-7.422 1.694-15.436 3.058-23.88 4.071a382.417 382.417 0 0 0 7.859-13.026a347.403 347.403 0 0 0 7.425-13.565Zm-16.898 8.101a358.557 358.557 0 0 1-12.281 19.815a329.4 329.4 0 0 1-23.444.823c-7.967 0-15.716-.248-23.178-.732a310.202 310.202 0 0 1-12.513-19.846h.001a307.41 307.41 0 0 1-10.923-20.627a310.278 310.278 0 0 1 10.89-20.637l-.001.001a307.318 307.318 0 0 1 12.413-19.761c7.613-.576 15.42-.876 23.31-.876H128c7.926 0 15.743.303 23.354.883a329.357 329.357 0 0 1 12.335 19.695a358.489 358.489 0 0 1 11.036 20.54a329.472 329.472 0 0 1-11 20.722Zm22.56-122.124c8.572 4.944 11.906 24.881 6.52 51.026c-.344 1.668-.73 3.367-1.15 5.09c-10.622-2.452-22.155-4.275-34.23-5.408c-7.034-10.017-14.323-19.124-21.64-27.008a160.789 160.789 0 0 1 5.888-5.4c18.9-16.447 36.564-22.941 44.612-18.3ZM128 90.808c12.625 0 22.86 10.235 22.86 22.86s-10.235 22.86-22.86 22.86s-22.86-10.235-22.86-22.86s10.235-22.86 22.86-22.86Z"></path></svg>
|
||||
|
Before Width: | Height: | Size: 4.0 KiB |
@@ -1,68 +0,0 @@
|
||||
:root {
|
||||
font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif;
|
||||
line-height: 1.5;
|
||||
font-weight: 400;
|
||||
|
||||
color-scheme: light dark;
|
||||
color: rgba(255, 255, 255, 0.87);
|
||||
background-color: #242424;
|
||||
|
||||
font-synthesis: none;
|
||||
text-rendering: optimizeLegibility;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
a {
|
||||
font-weight: 500;
|
||||
color: #646cff;
|
||||
text-decoration: inherit;
|
||||
}
|
||||
a:hover {
|
||||
color: #535bf2;
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
display: flex;
|
||||
place-items: center;
|
||||
min-width: 320px;
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 3.2em;
|
||||
line-height: 1.1;
|
||||
}
|
||||
|
||||
button {
|
||||
border-radius: 8px;
|
||||
border: 1px solid transparent;
|
||||
padding: 0.6em 1.2em;
|
||||
font-size: 1em;
|
||||
font-weight: 500;
|
||||
font-family: inherit;
|
||||
background-color: #1a1a1a;
|
||||
cursor: pointer;
|
||||
transition: border-color 0.25s;
|
||||
}
|
||||
button:hover {
|
||||
border-color: #646cff;
|
||||
}
|
||||
button:focus,
|
||||
button:focus-visible {
|
||||
outline: 4px auto -webkit-focus-ring-color;
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: light) {
|
||||
:root {
|
||||
color: #213547;
|
||||
background-color: #ffffff;
|
||||
}
|
||||
a:hover {
|
||||
color: #747bff;
|
||||
}
|
||||
button {
|
||||
background-color: #f9f9f9;
|
||||
}
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
import {StrictMode} from 'react';
|
||||
import {createRoot} from 'react-dom/client';
|
||||
import App from './App.tsx';
|
||||
import './index.css';
|
||||
|
||||
createRoot(document.getElementById('root')!).render(
|
||||
<StrictMode>
|
||||
<App />
|
||||
</StrictMode>,
|
||||
);
|
||||
@@ -1 +0,0 @@
|
||||
/// <reference types="vite/client" />
|
||||
@@ -1,24 +0,0 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "ES2020",
|
||||
"useDefineForClassFields": true,
|
||||
"lib": ["ES2020", "DOM", "DOM.Iterable"],
|
||||
"module": "ESNext",
|
||||
"skipLibCheck": true,
|
||||
|
||||
/* Bundler mode */
|
||||
"moduleResolution": "bundler",
|
||||
"allowImportingTsExtensions": true,
|
||||
"isolatedModules": true,
|
||||
"moduleDetection": "force",
|
||||
"noEmit": true,
|
||||
"jsx": "react-jsx",
|
||||
|
||||
/* Linting */
|
||||
"strict": true,
|
||||
"noUnusedLocals": true,
|
||||
"noUnusedParameters": true,
|
||||
"noFallthroughCasesInSwitch": true
|
||||
},
|
||||
"include": ["src"]
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
{"root":["./src/app.tsx","./src/main.tsx","./src/vite-env.d.ts"],"version":"5.6.3"}
|
||||
@@ -1,7 +0,0 @@
|
||||
{
|
||||
"files": [],
|
||||
"references": [
|
||||
{ "path": "./tsconfig.app.json" },
|
||||
{ "path": "./tsconfig.node.json" }
|
||||
]
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "ES2022",
|
||||
"lib": ["ES2023"],
|
||||
"module": "ESNext",
|
||||
"skipLibCheck": true,
|
||||
|
||||
/* Bundler mode */
|
||||
"moduleResolution": "bundler",
|
||||
"allowImportingTsExtensions": true,
|
||||
"isolatedModules": true,
|
||||
"moduleDetection": "force",
|
||||
"noEmit": true,
|
||||
|
||||
/* Linting */
|
||||
"strict": true,
|
||||
"noUnusedLocals": true,
|
||||
"noUnusedParameters": true,
|
||||
"noFallthroughCasesInSwitch": true
|
||||
},
|
||||
"include": ["vite.config.ts"]
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
{"root":["./vite.config.ts"],"version":"5.6.3"}
|
||||
@@ -1,11 +0,0 @@
|
||||
import {defineConfig} from 'vite';
|
||||
import react from '@vitejs/plugin-react';
|
||||
|
||||
// https://vitejs.dev/config/
|
||||
export default defineConfig({
|
||||
plugins: [
|
||||
react({
|
||||
babel: {plugins: [['babel-plugin-react-compiler', {target: '18'}]]},
|
||||
}),
|
||||
],
|
||||
});
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,24 +0,0 @@
|
||||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
pnpm-debug.log*
|
||||
lerna-debug.log*
|
||||
|
||||
node_modules
|
||||
dist
|
||||
dist-ssr
|
||||
*.local
|
||||
|
||||
# Editor directories and files
|
||||
.vscode/*
|
||||
!.vscode/extensions.json
|
||||
.idea
|
||||
.DS_Store
|
||||
*.suo
|
||||
*.ntvs*
|
||||
*.njsproj
|
||||
*.sln
|
||||
*.sw?
|
||||
@@ -1,50 +0,0 @@
|
||||
# React + TypeScript + Vite
|
||||
|
||||
This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules.
|
||||
|
||||
Currently, two official plugins are available:
|
||||
|
||||
- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react/README.md) uses [Babel](https://babeljs.io/) for Fast Refresh
|
||||
- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh
|
||||
|
||||
## Expanding the ESLint configuration
|
||||
|
||||
If you are developing a production application, we recommend updating the configuration to enable type aware lint rules:
|
||||
|
||||
- Configure the top-level `parserOptions` property like this:
|
||||
|
||||
```js
|
||||
export default tseslint.config({
|
||||
languageOptions: {
|
||||
// other options...
|
||||
parserOptions: {
|
||||
project: ['./tsconfig.node.json', './tsconfig.app.json'],
|
||||
tsconfigRootDir: import.meta.dirname,
|
||||
},
|
||||
},
|
||||
})
|
||||
```
|
||||
|
||||
- Replace `tseslint.configs.recommended` to `tseslint.configs.recommendedTypeChecked` or `tseslint.configs.strictTypeChecked`
|
||||
- Optionally add `...tseslint.configs.stylisticTypeChecked`
|
||||
- Install [eslint-plugin-react](https://github.com/jsx-eslint/eslint-plugin-react) and update the config:
|
||||
|
||||
```js
|
||||
// eslint.config.js
|
||||
import react from 'eslint-plugin-react'
|
||||
|
||||
export default tseslint.config({
|
||||
// Set the react version
|
||||
settings: { react: { version: '18.3' } },
|
||||
plugins: {
|
||||
// Add the react plugin
|
||||
react,
|
||||
},
|
||||
rules: {
|
||||
// other rules...
|
||||
// Enable its recommended rules
|
||||
...react.configs.recommended.rules,
|
||||
...react.configs['jsx-runtime'].rules,
|
||||
},
|
||||
})
|
||||
```
|
||||
@@ -1,28 +0,0 @@
|
||||
import js from '@eslint/js';
|
||||
import globals from 'globals';
|
||||
import reactHooks from 'eslint-plugin-react-hooks';
|
||||
import reactRefresh from 'eslint-plugin-react-refresh';
|
||||
import tseslint from 'typescript-eslint';
|
||||
|
||||
export default tseslint.config(
|
||||
{ignores: ['dist']},
|
||||
{
|
||||
extends: [js.configs.recommended, ...tseslint.configs.recommended],
|
||||
files: ['**/*.{ts,tsx}'],
|
||||
languageOptions: {
|
||||
ecmaVersion: 2020,
|
||||
globals: globals.browser,
|
||||
},
|
||||
plugins: {
|
||||
'react-hooks': reactHooks,
|
||||
'react-refresh': reactRefresh,
|
||||
},
|
||||
rules: {
|
||||
...reactHooks.configs.recommended.rules,
|
||||
'react-refresh/only-export-components': [
|
||||
'warn',
|
||||
{allowConstantExport: true},
|
||||
],
|
||||
},
|
||||
}
|
||||
);
|
||||
@@ -1,13 +0,0 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Vite + React + TS</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
<script type="module" src="/src/main.tsx"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,31 +0,0 @@
|
||||
{
|
||||
"name": "app-19",
|
||||
"private": true,
|
||||
"version": "0.0.0",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"build": "tsc -b && vite build",
|
||||
"lint": "eslint .",
|
||||
"preview": "vite preview"
|
||||
},
|
||||
"dependencies": {
|
||||
"react": "19.0.0-beta-26f2496093-20240514",
|
||||
"react-dom": "19.0.0-beta-26f2496093-20240514",
|
||||
"runtime-compat-lib": "file:../lib"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@eslint/js": "^9.11.1",
|
||||
"@types/react": "^18.3.10",
|
||||
"@types/react-dom": "^18.3.0",
|
||||
"@vitejs/plugin-react": "^4.3.2",
|
||||
"babel-plugin-react-compiler": "19.0.0-beta-9ee70a1-20241017",
|
||||
"eslint": "^9.11.1",
|
||||
"eslint-plugin-react-hooks": "^5.1.0-rc.0",
|
||||
"eslint-plugin-react-refresh": "^0.4.12",
|
||||
"globals": "^15.9.0",
|
||||
"typescript": "^5.5.3",
|
||||
"typescript-eslint": "^8.7.0",
|
||||
"vite": "^5.4.8"
|
||||
}
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg>
|
||||
|
Before Width: | Height: | Size: 1.5 KiB |
@@ -1,42 +0,0 @@
|
||||
#root {
|
||||
max-width: 1280px;
|
||||
margin: 0 auto;
|
||||
padding: 2rem;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.logo {
|
||||
height: 6em;
|
||||
padding: 1.5em;
|
||||
will-change: filter;
|
||||
transition: filter 300ms;
|
||||
}
|
||||
.logo:hover {
|
||||
filter: drop-shadow(0 0 2em #646cffaa);
|
||||
}
|
||||
.logo.react:hover {
|
||||
filter: drop-shadow(0 0 2em #61dafbaa);
|
||||
}
|
||||
|
||||
@keyframes logo-spin {
|
||||
from {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
to {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
|
||||
@media (prefers-reduced-motion: no-preference) {
|
||||
a:nth-of-type(2) .logo {
|
||||
animation: logo-spin infinite 20s linear;
|
||||
}
|
||||
}
|
||||
|
||||
.card {
|
||||
padding: 2em;
|
||||
}
|
||||
|
||||
.read-the-docs {
|
||||
color: #888;
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
import 'react';
|
||||
import './App.css';
|
||||
// @ts-expect-error no types
|
||||
import {useTime} from 'runtime-compat-lib';
|
||||
|
||||
function App() {
|
||||
const time = useTime();
|
||||
return (
|
||||
<>
|
||||
<h1>React 19</h1>
|
||||
<span>Current time: {time.toLocaleString()}</span>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export default App;
|
||||
@@ -1 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="35.93" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 228"><path fill="#00D8FF" d="M210.483 73.824a171.49 171.49 0 0 0-8.24-2.597c.465-1.9.893-3.777 1.273-5.621c6.238-30.281 2.16-54.676-11.769-62.708c-13.355-7.7-35.196.329-57.254 19.526a171.23 171.23 0 0 0-6.375 5.848a155.866 155.866 0 0 0-4.241-3.917C100.759 3.829 77.587-4.822 63.673 3.233C50.33 10.957 46.379 33.89 51.995 62.588a170.974 170.974 0 0 0 1.892 8.48c-3.28.932-6.445 1.924-9.474 2.98C17.309 83.498 0 98.307 0 113.668c0 15.865 18.582 31.778 46.812 41.427a145.52 145.52 0 0 0 6.921 2.165a167.467 167.467 0 0 0-2.01 9.138c-5.354 28.2-1.173 50.591 12.134 58.266c13.744 7.926 36.812-.22 59.273-19.855a145.567 145.567 0 0 0 5.342-4.923a168.064 168.064 0 0 0 6.92 6.314c21.758 18.722 43.246 26.282 56.54 18.586c13.731-7.949 18.194-32.003 12.4-61.268a145.016 145.016 0 0 0-1.535-6.842c1.62-.48 3.21-.974 4.76-1.488c29.348-9.723 48.443-25.443 48.443-41.52c0-15.417-17.868-30.326-45.517-39.844Zm-6.365 70.984c-1.4.463-2.836.91-4.3 1.345c-3.24-10.257-7.612-21.163-12.963-32.432c5.106-11 9.31-21.767 12.459-31.957c2.619.758 5.16 1.557 7.61 2.4c23.69 8.156 38.14 20.213 38.14 29.504c0 9.896-15.606 22.743-40.946 31.14Zm-10.514 20.834c2.562 12.94 2.927 24.64 1.23 33.787c-1.524 8.219-4.59 13.698-8.382 15.893c-8.067 4.67-25.32-1.4-43.927-17.412a156.726 156.726 0 0 1-6.437-5.87c7.214-7.889 14.423-17.06 21.459-27.246c12.376-1.098 24.068-2.894 34.671-5.345a134.17 134.17 0 0 1 1.386 6.193ZM87.276 214.515c-7.882 2.783-14.16 2.863-17.955.675c-8.075-4.657-11.432-22.636-6.853-46.752a156.923 156.923 0 0 1 1.869-8.499c10.486 2.32 22.093 3.988 34.498 4.994c7.084 9.967 14.501 19.128 21.976 27.15a134.668 134.668 0 0 1-4.877 4.492c-9.933 8.682-19.886 14.842-28.658 17.94ZM50.35 144.747c-12.483-4.267-22.792-9.812-29.858-15.863c-6.35-5.437-9.555-10.836-9.555-15.216c0-9.322 13.897-21.212 37.076-29.293c2.813-.98 5.757-1.905 8.812-2.773c3.204 10.42 7.406 21.315 12.477 32.332c-5.137 11.18-9.399 22.249-12.634 32.792a134.718 134.718 0 0 1-6.318-1.979Zm12.378-84.26c-4.811-24.587-1.616-43.134 6.425-47.789c8.564-4.958 27.502 2.111 47.463 19.835a144.318 144.318 0 0 1 3.841 3.545c-7.438 7.987-14.787 17.08-21.808 26.988c-12.04 1.116-23.565 2.908-34.161 5.309a160.342 160.342 0 0 1-1.76-7.887Zm110.427 27.268a347.8 347.8 0 0 0-7.785-12.803c8.168 1.033 15.994 2.404 23.343 4.08c-2.206 7.072-4.956 14.465-8.193 22.045a381.151 381.151 0 0 0-7.365-13.322Zm-45.032-43.861c5.044 5.465 10.096 11.566 15.065 18.186a322.04 322.04 0 0 0-30.257-.006c4.974-6.559 10.069-12.652 15.192-18.18ZM82.802 87.83a323.167 323.167 0 0 0-7.227 13.238c-3.184-7.553-5.909-14.98-8.134-22.152c7.304-1.634 15.093-2.97 23.209-3.984a321.524 321.524 0 0 0-7.848 12.897Zm8.081 65.352c-8.385-.936-16.291-2.203-23.593-3.793c2.26-7.3 5.045-14.885 8.298-22.6a321.187 321.187 0 0 0 7.257 13.246c2.594 4.48 5.28 8.868 8.038 13.147Zm37.542 31.03c-5.184-5.592-10.354-11.779-15.403-18.433c4.902.192 9.899.29 14.978.29c5.218 0 10.376-.117 15.453-.343c-4.985 6.774-10.018 12.97-15.028 18.486Zm52.198-57.817c3.422 7.8 6.306 15.345 8.596 22.52c-7.422 1.694-15.436 3.058-23.88 4.071a382.417 382.417 0 0 0 7.859-13.026a347.403 347.403 0 0 0 7.425-13.565Zm-16.898 8.101a358.557 358.557 0 0 1-12.281 19.815a329.4 329.4 0 0 1-23.444.823c-7.967 0-15.716-.248-23.178-.732a310.202 310.202 0 0 1-12.513-19.846h.001a307.41 307.41 0 0 1-10.923-20.627a310.278 310.278 0 0 1 10.89-20.637l-.001.001a307.318 307.318 0 0 1 12.413-19.761c7.613-.576 15.42-.876 23.31-.876H128c7.926 0 15.743.303 23.354.883a329.357 329.357 0 0 1 12.335 19.695a358.489 358.489 0 0 1 11.036 20.54a329.472 329.472 0 0 1-11 20.722Zm22.56-122.124c8.572 4.944 11.906 24.881 6.52 51.026c-.344 1.668-.73 3.367-1.15 5.09c-10.622-2.452-22.155-4.275-34.23-5.408c-7.034-10.017-14.323-19.124-21.64-27.008a160.789 160.789 0 0 1 5.888-5.4c18.9-16.447 36.564-22.941 44.612-18.3ZM128 90.808c12.625 0 22.86 10.235 22.86 22.86s-10.235 22.86-22.86 22.86s-22.86-10.235-22.86-22.86s10.235-22.86 22.86-22.86Z"></path></svg>
|
||||
|
Before Width: | Height: | Size: 4.0 KiB |
@@ -1,68 +0,0 @@
|
||||
:root {
|
||||
font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif;
|
||||
line-height: 1.5;
|
||||
font-weight: 400;
|
||||
|
||||
color-scheme: light dark;
|
||||
color: rgba(255, 255, 255, 0.87);
|
||||
background-color: #242424;
|
||||
|
||||
font-synthesis: none;
|
||||
text-rendering: optimizeLegibility;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
a {
|
||||
font-weight: 500;
|
||||
color: #646cff;
|
||||
text-decoration: inherit;
|
||||
}
|
||||
a:hover {
|
||||
color: #535bf2;
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
display: flex;
|
||||
place-items: center;
|
||||
min-width: 320px;
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 3.2em;
|
||||
line-height: 1.1;
|
||||
}
|
||||
|
||||
button {
|
||||
border-radius: 8px;
|
||||
border: 1px solid transparent;
|
||||
padding: 0.6em 1.2em;
|
||||
font-size: 1em;
|
||||
font-weight: 500;
|
||||
font-family: inherit;
|
||||
background-color: #1a1a1a;
|
||||
cursor: pointer;
|
||||
transition: border-color 0.25s;
|
||||
}
|
||||
button:hover {
|
||||
border-color: #646cff;
|
||||
}
|
||||
button:focus,
|
||||
button:focus-visible {
|
||||
outline: 4px auto -webkit-focus-ring-color;
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: light) {
|
||||
:root {
|
||||
color: #213547;
|
||||
background-color: #ffffff;
|
||||
}
|
||||
a:hover {
|
||||
color: #747bff;
|
||||
}
|
||||
button {
|
||||
background-color: #f9f9f9;
|
||||
}
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
import {StrictMode} from 'react';
|
||||
import {createRoot} from 'react-dom/client';
|
||||
import App from './App.tsx';
|
||||
import './index.css';
|
||||
|
||||
createRoot(document.getElementById('root')!).render(
|
||||
<StrictMode>
|
||||
<App />
|
||||
</StrictMode>,
|
||||
);
|
||||
@@ -1 +0,0 @@
|
||||
/// <reference types="vite/client" />
|
||||
@@ -1,24 +0,0 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "ES2020",
|
||||
"useDefineForClassFields": true,
|
||||
"lib": ["ES2020", "DOM", "DOM.Iterable"],
|
||||
"module": "ESNext",
|
||||
"skipLibCheck": true,
|
||||
|
||||
/* Bundler mode */
|
||||
"moduleResolution": "bundler",
|
||||
"allowImportingTsExtensions": true,
|
||||
"isolatedModules": true,
|
||||
"moduleDetection": "force",
|
||||
"noEmit": true,
|
||||
"jsx": "react-jsx",
|
||||
|
||||
/* Linting */
|
||||
"strict": true,
|
||||
"noUnusedLocals": true,
|
||||
"noUnusedParameters": true,
|
||||
"noFallthroughCasesInSwitch": true
|
||||
},
|
||||
"include": ["src"]
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
{"root":["./src/app.tsx","./src/main.tsx","./src/vite-env.d.ts"],"version":"5.6.3"}
|
||||
@@ -1,7 +0,0 @@
|
||||
{
|
||||
"files": [],
|
||||
"references": [
|
||||
{ "path": "./tsconfig.app.json" },
|
||||
{ "path": "./tsconfig.node.json" }
|
||||
]
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "ES2022",
|
||||
"lib": ["ES2023"],
|
||||
"module": "ESNext",
|
||||
"skipLibCheck": true,
|
||||
|
||||
/* Bundler mode */
|
||||
"moduleResolution": "bundler",
|
||||
"allowImportingTsExtensions": true,
|
||||
"isolatedModules": true,
|
||||
"moduleDetection": "force",
|
||||
"noEmit": true,
|
||||
|
||||
/* Linting */
|
||||
"strict": true,
|
||||
"noUnusedLocals": true,
|
||||
"noUnusedParameters": true,
|
||||
"noFallthroughCasesInSwitch": true
|
||||
},
|
||||
"include": ["vite.config.ts"]
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
{"root":["./vite.config.ts"],"version":"5.6.3"}
|
||||
@@ -1,11 +0,0 @@
|
||||
import {defineConfig} from 'vite';
|
||||
import react from '@vitejs/plugin-react';
|
||||
|
||||
// https://vitejs.dev/config/
|
||||
export default defineConfig({
|
||||
plugins: [
|
||||
react({
|
||||
babel: {plugins: [['babel-plugin-react-compiler', {target: '19'}]]},
|
||||
}),
|
||||
],
|
||||
});
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,10 +0,0 @@
|
||||
const plugins = [
|
||||
[
|
||||
'babel-plugin-react-compiler',
|
||||
{
|
||||
target: '18',
|
||||
},
|
||||
],
|
||||
];
|
||||
|
||||
module.exports = {plugins};
|
||||
@@ -1,13 +0,0 @@
|
||||
import {useState, useEffect} from 'react';
|
||||
|
||||
export function useTime() {
|
||||
const [time, setTime] = useState(() => new Date());
|
||||
useEffect(() => {
|
||||
const id = setInterval(() => {
|
||||
setTime(new Date());
|
||||
}, 1000);
|
||||
return () => clearInterval(id);
|
||||
}, []);
|
||||
|
||||
return time;
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
{
|
||||
"name": "runtime-compat-lib",
|
||||
"version": "0.0.0",
|
||||
"description": "Testing ground for libraries compiled with React Compiler",
|
||||
"main": "dist/index.js",
|
||||
"scripts": {
|
||||
"build": "rimraf dist && rollup --config --bundleConfigAsCjs",
|
||||
"test": "echo 'no tests'"
|
||||
},
|
||||
"license": "MIT",
|
||||
"devDependencies": {
|
||||
"@babel/cli": "^7.25.7",
|
||||
"@babel/core": "^7.25.7",
|
||||
"@babel/preset-env": "^7.25.7",
|
||||
"@rollup/plugin-babel": "^6.0.4",
|
||||
"@rollup/plugin-json": "^6.1.0",
|
||||
"babel-plugin-react-compiler": "19.0.0-beta-9ee70a1-20241017",
|
||||
"@rollup/plugin-terser": "^0.4.4",
|
||||
"react": "19.0.0-beta-26f2496093-20240514",
|
||||
"react-dom": "19.0.0-beta-26f2496093-20240514",
|
||||
"rimraf": "5",
|
||||
"rollup": "^4.22.4",
|
||||
"rollup-plugin-banner2": "^1.2.3",
|
||||
"rollup-plugin-prettier": "^4.1.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"react-compiler-runtime": "19.0.0-beta-9ee70a1-20241017"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "^18 || ^19"
|
||||
}
|
||||
}
|
||||
@@ -1,51 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
import json from '@rollup/plugin-json';
|
||||
import terser from '@rollup/plugin-terser';
|
||||
import prettier from 'rollup-plugin-prettier';
|
||||
import banner2 from 'rollup-plugin-banner2';
|
||||
import babel from '@rollup/plugin-babel';
|
||||
|
||||
const ROLLUP_CONFIG = {
|
||||
input: 'index.js',
|
||||
output: {
|
||||
file: 'dist/index.js',
|
||||
format: 'esm',
|
||||
sourcemap: false,
|
||||
exports: 'named',
|
||||
},
|
||||
plugins: [
|
||||
json(),
|
||||
babel({babelHelpers: 'bundled'}),
|
||||
terser({
|
||||
format: {
|
||||
comments: false,
|
||||
},
|
||||
compress: false,
|
||||
mangle: false,
|
||||
}),
|
||||
prettier(),
|
||||
banner2(
|
||||
() => `/**
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @lightSyntaxTransform
|
||||
* @noflow
|
||||
* @nolint
|
||||
* @preventMunge
|
||||
* @preserve-invariant-messages
|
||||
*/
|
||||
`
|
||||
),
|
||||
],
|
||||
};
|
||||
|
||||
export default ROLLUP_CONFIG;
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,13 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
# Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
#
|
||||
# This source code is licensed under the MIT license found in the
|
||||
# LICENSE file in the root directory of this source tree.
|
||||
|
||||
set -eo pipefail
|
||||
|
||||
HERE=$(pwd)
|
||||
|
||||
cd lib && yarn --silent link
|
||||
cd $HERE/app-18 && yarn --silent link runtime-compat-lib
|
||||
cd $HERE/app-19 && yarn --silent link runtime-compat-lib
|
||||
@@ -57,7 +57,6 @@ import {
|
||||
mergeReactiveScopesThatInvalidateTogether,
|
||||
promoteUsedTemporaries,
|
||||
propagateEarlyReturns,
|
||||
propagateScopeDependencies,
|
||||
pruneHoistedContexts,
|
||||
pruneNonEscapingScopes,
|
||||
pruneNonReactiveDependencies,
|
||||
@@ -348,14 +347,12 @@ function* runWithEnvironment(
|
||||
});
|
||||
assertTerminalSuccessorsExist(hir);
|
||||
assertTerminalPredsExist(hir);
|
||||
if (env.config.enablePropagateDepsInHIR) {
|
||||
propagateScopeDependenciesHIR(hir);
|
||||
yield log({
|
||||
kind: 'hir',
|
||||
name: 'PropagateScopeDependenciesHIR',
|
||||
value: hir,
|
||||
});
|
||||
}
|
||||
propagateScopeDependenciesHIR(hir);
|
||||
yield log({
|
||||
kind: 'hir',
|
||||
name: 'PropagateScopeDependenciesHIR',
|
||||
value: hir,
|
||||
});
|
||||
|
||||
if (env.config.inlineJsxTransform) {
|
||||
inlineJsxTransform(hir, env.config.inlineJsxTransform);
|
||||
@@ -383,15 +380,6 @@ function* runWithEnvironment(
|
||||
});
|
||||
assertScopeInstructionsWithinScopes(reactiveFunction);
|
||||
|
||||
if (!env.config.enablePropagateDepsInHIR) {
|
||||
propagateScopeDependencies(reactiveFunction);
|
||||
yield log({
|
||||
kind: 'reactive',
|
||||
name: 'PropagateScopeDependencies',
|
||||
value: reactiveFunction,
|
||||
});
|
||||
}
|
||||
|
||||
pruneNonEscapingScopes(reactiveFunction);
|
||||
yield log({
|
||||
kind: 'reactive',
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import {CompilerError} from '../CompilerError';
|
||||
import {inRange} from '../ReactiveScopes/InferReactiveScopeVariables';
|
||||
import {printDependency} from '../ReactiveScopes/PrintReactiveFunction';
|
||||
import {
|
||||
Set_equal,
|
||||
Set_filter,
|
||||
@@ -7,7 +8,6 @@ import {
|
||||
Set_union,
|
||||
getOrInsertDefault,
|
||||
} from '../Utils/utils';
|
||||
import {collectOptionalChainSidemap} from './CollectOptionalChainDependencies';
|
||||
import {
|
||||
BasicBlock,
|
||||
BlockId,
|
||||
@@ -21,7 +21,8 @@ import {
|
||||
ReactiveScopeDependency,
|
||||
ScopeId,
|
||||
} from './HIR';
|
||||
import {collectTemporariesSidemap} from './PropagateScopeDependenciesHIR';
|
||||
|
||||
const DEBUG_PRINT = false;
|
||||
|
||||
/**
|
||||
* Helper function for `PropagateScopeDependencies`. Uses control flow graph
|
||||
@@ -86,15 +87,8 @@ export function collectHoistablePropertyLoads(
|
||||
fn: HIRFunction,
|
||||
temporaries: ReadonlyMap<IdentifierId, ReactiveScopeDependency>,
|
||||
hoistableFromOptionals: ReadonlyMap<BlockId, ReactiveScopeDependency>,
|
||||
nestedFnImmutableContext: ReadonlySet<IdentifierId> | null,
|
||||
): ReadonlyMap<BlockId, BlockInfo> {
|
||||
const registry = new PropertyPathRegistry();
|
||||
|
||||
const functionExpressionLoads = collectFunctionExpressionFakeLoads(fn);
|
||||
const actuallyEvaluatedTemporaries = new Map(
|
||||
[...temporaries].filter(([id]) => !functionExpressionLoads.has(id)),
|
||||
);
|
||||
|
||||
/**
|
||||
* Due to current limitations of mutable range inference, there are edge cases in
|
||||
* which we infer known-immutable values (e.g. props or hook params) to have a
|
||||
@@ -111,14 +105,51 @@ export function collectHoistablePropertyLoads(
|
||||
}
|
||||
}
|
||||
}
|
||||
const nodes = collectNonNullsInBlocks(fn, {
|
||||
temporaries: actuallyEvaluatedTemporaries,
|
||||
return collectHoistablePropertyLoadsImpl(fn, {
|
||||
temporaries,
|
||||
knownImmutableIdentifiers,
|
||||
hoistableFromOptionals,
|
||||
registry,
|
||||
nestedFnImmutableContext,
|
||||
nestedFnImmutableContext: null,
|
||||
});
|
||||
propagateNonNull(fn, nodes, registry);
|
||||
}
|
||||
|
||||
type CollectHoistablePropertyLoadsContext = {
|
||||
temporaries: ReadonlyMap<IdentifierId, ReactiveScopeDependency>;
|
||||
knownImmutableIdentifiers: ReadonlySet<IdentifierId>;
|
||||
hoistableFromOptionals: ReadonlyMap<BlockId, ReactiveScopeDependency>;
|
||||
registry: PropertyPathRegistry;
|
||||
/**
|
||||
* (For nested / inner function declarations)
|
||||
* Context variables (i.e. captured from an outer scope) that are immutable.
|
||||
* Note that this technically could be merged into `knownImmutableIdentifiers`,
|
||||
* but are currently kept separate for readability.
|
||||
*/
|
||||
nestedFnImmutableContext: ReadonlySet<IdentifierId> | null;
|
||||
};
|
||||
function collectHoistablePropertyLoadsImpl(
|
||||
fn: HIRFunction,
|
||||
context: CollectHoistablePropertyLoadsContext,
|
||||
): ReadonlyMap<BlockId, BlockInfo> {
|
||||
const functionExpressionLoads = collectFunctionExpressionFakeLoads(fn);
|
||||
const actuallyEvaluatedTemporaries = new Map(
|
||||
[...context.temporaries].filter(([id]) => !functionExpressionLoads.has(id)),
|
||||
);
|
||||
|
||||
const nodes = collectNonNullsInBlocks(fn, {
|
||||
...context,
|
||||
temporaries: actuallyEvaluatedTemporaries,
|
||||
});
|
||||
propagateNonNull(fn, nodes, context.registry);
|
||||
|
||||
if (DEBUG_PRINT) {
|
||||
console.log('(printing hoistable nodes in blocks)');
|
||||
for (const [blockId, node] of nodes) {
|
||||
console.log(
|
||||
`bb${blockId}: ${[...node.assumedNonNullObjects].map(n => printDependency(n.fullPath)).join(' ')}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return nodes;
|
||||
}
|
||||
@@ -243,7 +274,7 @@ class PropertyPathRegistry {
|
||||
|
||||
function getMaybeNonNullInInstruction(
|
||||
instr: InstructionValue,
|
||||
context: CollectNonNullsInBlocksContext,
|
||||
context: CollectHoistablePropertyLoadsContext,
|
||||
): PropertyPathNode | null {
|
||||
let path = null;
|
||||
if (instr.kind === 'PropertyLoad') {
|
||||
@@ -262,7 +293,7 @@ function getMaybeNonNullInInstruction(
|
||||
function isImmutableAtInstr(
|
||||
identifier: Identifier,
|
||||
instr: InstructionId,
|
||||
context: CollectNonNullsInBlocksContext,
|
||||
context: CollectHoistablePropertyLoadsContext,
|
||||
): boolean {
|
||||
if (context.nestedFnImmutableContext != null) {
|
||||
/**
|
||||
@@ -295,22 +326,9 @@ function isImmutableAtInstr(
|
||||
}
|
||||
}
|
||||
|
||||
type CollectNonNullsInBlocksContext = {
|
||||
temporaries: ReadonlyMap<IdentifierId, ReactiveScopeDependency>;
|
||||
knownImmutableIdentifiers: ReadonlySet<IdentifierId>;
|
||||
hoistableFromOptionals: ReadonlyMap<BlockId, ReactiveScopeDependency>;
|
||||
registry: PropertyPathRegistry;
|
||||
/**
|
||||
* (For nested / inner function declarations)
|
||||
* Context variables (i.e. captured from an outer scope) that are immutable.
|
||||
* Note that this technically could be merged into `knownImmutableIdentifiers`,
|
||||
* but are currently kept separate for readability.
|
||||
*/
|
||||
nestedFnImmutableContext: ReadonlySet<IdentifierId> | null;
|
||||
};
|
||||
function collectNonNullsInBlocks(
|
||||
fn: HIRFunction,
|
||||
context: CollectNonNullsInBlocksContext,
|
||||
context: CollectHoistablePropertyLoadsContext,
|
||||
): ReadonlyMap<BlockId, BlockInfo> {
|
||||
/**
|
||||
* Known non-null objects such as functional component props can be safely
|
||||
@@ -348,27 +366,25 @@ function collectNonNullsInBlocks(
|
||||
assumedNonNullObjects.add(maybeNonNull);
|
||||
}
|
||||
if (
|
||||
instr.value.kind === 'FunctionExpression' &&
|
||||
(instr.value.kind === 'FunctionExpression' ||
|
||||
instr.value.kind === 'ObjectMethod') &&
|
||||
!fn.env.config.enableTreatFunctionDepsAsConditional
|
||||
) {
|
||||
const innerFn = instr.value.loweredFunc;
|
||||
const innerTemporaries = collectTemporariesSidemap(
|
||||
const innerHoistableMap = collectHoistablePropertyLoadsImpl(
|
||||
innerFn.func,
|
||||
new Set(),
|
||||
);
|
||||
const innerOptionals = collectOptionalChainSidemap(innerFn.func);
|
||||
const innerHoistableMap = collectHoistablePropertyLoads(
|
||||
innerFn.func,
|
||||
innerTemporaries,
|
||||
innerOptionals.hoistableObjects,
|
||||
context.nestedFnImmutableContext ??
|
||||
new Set(
|
||||
innerFn.func.context
|
||||
.filter(place =>
|
||||
isImmutableAtInstr(place.identifier, instr.id, context),
|
||||
)
|
||||
.map(place => place.identifier.id),
|
||||
),
|
||||
{
|
||||
...context,
|
||||
nestedFnImmutableContext:
|
||||
context.nestedFnImmutableContext ??
|
||||
new Set(
|
||||
innerFn.func.context
|
||||
.filter(place =>
|
||||
isImmutableAtInstr(place.identifier, instr.id, context),
|
||||
)
|
||||
.map(place => place.identifier.id),
|
||||
),
|
||||
},
|
||||
);
|
||||
const innerHoistables = assertNonNull(
|
||||
innerHoistableMap.get(innerFn.func.body.entry),
|
||||
@@ -591,7 +607,10 @@ function collectFunctionExpressionFakeLoads(
|
||||
|
||||
for (const [_, block] of fn.body.blocks) {
|
||||
for (const {lvalue, value} of block.instructions) {
|
||||
if (value.kind === 'FunctionExpression') {
|
||||
if (
|
||||
value.kind === 'FunctionExpression' ||
|
||||
value.kind === 'ObjectMethod'
|
||||
) {
|
||||
for (const reference of value.loweredFunc.dependencies) {
|
||||
let curr: IdentifierId | undefined = reference.identifier.id;
|
||||
while (curr != null) {
|
||||
|
||||
@@ -3,7 +3,6 @@ import {assertNonNull} from './CollectHoistablePropertyLoads';
|
||||
import {
|
||||
BlockId,
|
||||
BasicBlock,
|
||||
InstructionId,
|
||||
IdentifierId,
|
||||
ReactiveScopeDependency,
|
||||
BranchTerminal,
|
||||
@@ -15,6 +14,8 @@ import {
|
||||
OptionalTerminal,
|
||||
HIRFunction,
|
||||
DependencyPathEntry,
|
||||
Instruction,
|
||||
Terminal,
|
||||
} from './HIR';
|
||||
import {printIdentifier} from './PrintHIR';
|
||||
|
||||
@@ -22,25 +23,14 @@ export function collectOptionalChainSidemap(
|
||||
fn: HIRFunction,
|
||||
): OptionalChainSidemap {
|
||||
const context: OptionalTraversalContext = {
|
||||
currFn: fn,
|
||||
blocks: fn.body.blocks,
|
||||
seenOptionals: new Set(),
|
||||
processedInstrsInOptional: new Set(),
|
||||
temporariesReadInOptional: new Map(),
|
||||
hoistableObjects: new Map(),
|
||||
};
|
||||
for (const [_, block] of fn.body.blocks) {
|
||||
if (
|
||||
block.terminal.kind === 'optional' &&
|
||||
!context.seenOptionals.has(block.id)
|
||||
) {
|
||||
traverseOptionalBlock(
|
||||
block as TBasicBlock<OptionalTerminal>,
|
||||
context,
|
||||
null,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
traverseFunction(fn, context);
|
||||
return {
|
||||
temporariesReadInOptional: context.temporariesReadInOptional,
|
||||
processedInstrsInOptional: context.processedInstrsInOptional,
|
||||
@@ -96,8 +86,10 @@ export type OptionalChainSidemap = {
|
||||
* bb5:
|
||||
* $5 = MethodCall $2.$4() <--- here, we want to take a dep on $2 and $4!
|
||||
* ```
|
||||
*
|
||||
* Also note that InstructionIds are not unique across inner functions.
|
||||
*/
|
||||
processedInstrsInOptional: ReadonlySet<InstructionId>;
|
||||
processedInstrsInOptional: ReadonlySet<Instruction | Terminal>;
|
||||
/**
|
||||
* Records optional chains for which we can safely evaluate non-optional
|
||||
* PropertyLoads. e.g. given `a?.b.c`, we can evaluate any load from `a?.b` at
|
||||
@@ -115,16 +107,46 @@ export type OptionalChainSidemap = {
|
||||
};
|
||||
|
||||
type OptionalTraversalContext = {
|
||||
currFn: HIRFunction;
|
||||
blocks: ReadonlyMap<BlockId, BasicBlock>;
|
||||
|
||||
// Track optional blocks to avoid outer calls into nested optionals
|
||||
seenOptionals: Set<BlockId>;
|
||||
|
||||
processedInstrsInOptional: Set<InstructionId>;
|
||||
processedInstrsInOptional: Set<Instruction | Terminal>;
|
||||
temporariesReadInOptional: Map<IdentifierId, ReactiveScopeDependency>;
|
||||
hoistableObjects: Map<BlockId, ReactiveScopeDependency>;
|
||||
};
|
||||
|
||||
function traverseFunction(
|
||||
fn: HIRFunction,
|
||||
context: OptionalTraversalContext,
|
||||
): void {
|
||||
for (const [_, block] of fn.body.blocks) {
|
||||
for (const instr of block.instructions) {
|
||||
if (
|
||||
instr.value.kind === 'FunctionExpression' ||
|
||||
instr.value.kind === 'ObjectMethod'
|
||||
) {
|
||||
traverseFunction(instr.value.loweredFunc.func, {
|
||||
...context,
|
||||
currFn: instr.value.loweredFunc.func,
|
||||
blocks: instr.value.loweredFunc.func.body.blocks,
|
||||
});
|
||||
}
|
||||
}
|
||||
if (
|
||||
block.terminal.kind === 'optional' &&
|
||||
!context.seenOptionals.has(block.id)
|
||||
) {
|
||||
traverseOptionalBlock(
|
||||
block as TBasicBlock<OptionalTerminal>,
|
||||
context,
|
||||
null,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Match the consequent and alternate blocks of an optional.
|
||||
* @returns propertyload computed by the consequent block, or null if the
|
||||
@@ -137,7 +159,7 @@ function matchOptionalTestBlock(
|
||||
consequentId: IdentifierId;
|
||||
property: string;
|
||||
propertyId: IdentifierId;
|
||||
storeLocalInstrId: InstructionId;
|
||||
storeLocalInstr: Instruction;
|
||||
consequentGoto: BlockId;
|
||||
} | null {
|
||||
const consequentBlock = assertNonNull(blocks.get(terminal.consequent));
|
||||
@@ -149,7 +171,7 @@ function matchOptionalTestBlock(
|
||||
const propertyLoad: TInstruction<PropertyLoad> = consequentBlock
|
||||
.instructions[0] as TInstruction<PropertyLoad>;
|
||||
const storeLocal: StoreLocal = consequentBlock.instructions[1].value;
|
||||
const storeLocalInstrId = consequentBlock.instructions[1].id;
|
||||
const storeLocalInstr = consequentBlock.instructions[1];
|
||||
CompilerError.invariant(
|
||||
propertyLoad.value.object.identifier.id === terminal.test.identifier.id,
|
||||
{
|
||||
@@ -189,7 +211,7 @@ function matchOptionalTestBlock(
|
||||
consequentId: storeLocal.lvalue.place.identifier.id,
|
||||
property: propertyLoad.value.property,
|
||||
propertyId: propertyLoad.lvalue.identifier.id,
|
||||
storeLocalInstrId,
|
||||
storeLocalInstr,
|
||||
consequentGoto: consequentBlock.terminal.block,
|
||||
};
|
||||
}
|
||||
@@ -369,10 +391,8 @@ function traverseOptionalBlock(
|
||||
},
|
||||
],
|
||||
};
|
||||
context.processedInstrsInOptional.add(
|
||||
matchConsequentResult.storeLocalInstrId,
|
||||
);
|
||||
context.processedInstrsInOptional.add(test.id);
|
||||
context.processedInstrsInOptional.add(matchConsequentResult.storeLocalInstr);
|
||||
context.processedInstrsInOptional.add(test);
|
||||
context.temporariesReadInOptional.set(
|
||||
matchConsequentResult.consequentId,
|
||||
load,
|
||||
|
||||
@@ -69,8 +69,8 @@ export const ExternalFunctionSchema = z.object({
|
||||
export const InstrumentationSchema = z
|
||||
.object({
|
||||
fn: ExternalFunctionSchema,
|
||||
gating: ExternalFunctionSchema.nullish(),
|
||||
globalGating: z.string().nullish(),
|
||||
gating: ExternalFunctionSchema.nullable(),
|
||||
globalGating: z.string().nullable(),
|
||||
})
|
||||
.refine(
|
||||
opts => opts.gating != null || opts.globalGating != null,
|
||||
@@ -147,7 +147,7 @@ export type Hook = z.infer<typeof HookSchema>;
|
||||
*/
|
||||
|
||||
const EnvironmentConfigSchema = z.object({
|
||||
customHooks: z.map(z.string(), HookSchema).optional().default(new Map()),
|
||||
customHooks: z.map(z.string(), HookSchema).default(new Map()),
|
||||
|
||||
/**
|
||||
* A function that, given the name of a module, can optionally return a description
|
||||
@@ -231,16 +231,6 @@ const EnvironmentConfigSchema = z.object({
|
||||
*/
|
||||
enableUseTypeAnnotations: z.boolean().default(false),
|
||||
|
||||
enablePropagateDepsInHIR: z.boolean().default(false),
|
||||
|
||||
/**
|
||||
* Enables inference of optional dependency chains. Without this flag
|
||||
* a property chain such as `props?.items?.foo` will infer as a dep on
|
||||
* just `props`. With this flag enabled, we'll infer that full path as
|
||||
* the dependency.
|
||||
*/
|
||||
enableOptionalDependencies: z.boolean().default(true),
|
||||
|
||||
/**
|
||||
* Enables inlining ReactElement object literals in place of JSX
|
||||
* An alternative to the standard JSX transform which replaces JSX with React's jsxProd() runtime
|
||||
@@ -248,7 +238,7 @@ const EnvironmentConfigSchema = z.object({
|
||||
*
|
||||
* The symbol configuration is set for backwards compatability with pre-React 19 transforms
|
||||
*/
|
||||
inlineJsxTransform: ReactElementSymbolSchema.nullish(),
|
||||
inlineJsxTransform: ReactElementSymbolSchema.nullable().default(null),
|
||||
|
||||
/*
|
||||
* Enable validation of hooks to partially check that the component honors the rules of hooks.
|
||||
@@ -339,9 +329,9 @@ const EnvironmentConfigSchema = z.object({
|
||||
* }
|
||||
* }
|
||||
*/
|
||||
enableEmitFreeze: ExternalFunctionSchema.nullish(),
|
||||
enableEmitFreeze: ExternalFunctionSchema.nullable().default(null),
|
||||
|
||||
enableEmitHookGuards: ExternalFunctionSchema.nullish(),
|
||||
enableEmitHookGuards: ExternalFunctionSchema.nullable().default(null),
|
||||
|
||||
/**
|
||||
* Enable instruction reordering. See InstructionReordering.ts for the details
|
||||
@@ -425,7 +415,7 @@ const EnvironmentConfigSchema = z.object({
|
||||
* }
|
||||
*
|
||||
*/
|
||||
enableEmitInstrumentForget: InstrumentationSchema.nullish(),
|
||||
enableEmitInstrumentForget: InstrumentationSchema.nullable().default(null),
|
||||
|
||||
// Enable validation of mutable ranges
|
||||
assertValidMutableRanges: z.boolean().default(false),
|
||||
@@ -464,8 +454,6 @@ const EnvironmentConfigSchema = z.object({
|
||||
*/
|
||||
throwUnknownException__testonly: z.boolean().default(false),
|
||||
|
||||
enableSharedRuntime__testonly: z.boolean().default(false),
|
||||
|
||||
/**
|
||||
* Enables deps of a function epxression to be treated as conditional. This
|
||||
* makes sure we don't load a dep when it's a property (to check if it has
|
||||
@@ -503,7 +491,8 @@ const EnvironmentConfigSchema = z.object({
|
||||
* computed one. This detects cases where rules of react violations may cause the
|
||||
* compiled code to behave differently than the original.
|
||||
*/
|
||||
enableChangeDetectionForDebugging: ExternalFunctionSchema.nullish(),
|
||||
enableChangeDetectionForDebugging:
|
||||
ExternalFunctionSchema.nullable().default(null),
|
||||
|
||||
/**
|
||||
* The react native re-animated library uses custom Babel transforms that
|
||||
@@ -543,7 +532,7 @@ const EnvironmentConfigSchema = z.object({
|
||||
*
|
||||
* Here the variables `ref` and `myRef` will be typed as Refs.
|
||||
*/
|
||||
enableTreatRefLikeIdentifiersAsRefs: z.boolean().nullable().default(false),
|
||||
enableTreatRefLikeIdentifiersAsRefs: z.boolean().default(false),
|
||||
|
||||
/*
|
||||
* If specified a value, the compiler lowers any calls to `useContext` to use
|
||||
@@ -565,12 +554,57 @@ const EnvironmentConfigSchema = z.object({
|
||||
* const {foo, bar} = useCompiledContext(MyContext, (c) => [c.foo, c.bar]);
|
||||
* ```
|
||||
*/
|
||||
lowerContextAccess: ExternalFunctionSchema.nullish(),
|
||||
lowerContextAccess: ExternalFunctionSchema.nullable().default(null),
|
||||
});
|
||||
|
||||
export type EnvironmentConfig = z.infer<typeof EnvironmentConfigSchema>;
|
||||
|
||||
export function parseConfigPragma(pragma: string): EnvironmentConfig {
|
||||
/**
|
||||
* For test fixtures and playground only.
|
||||
*
|
||||
* Pragmas are straightforward to parse for boolean options (`:true` and
|
||||
* `:false`). These are 'enabled' config values for non-boolean configs (i.e.
|
||||
* what is used when parsing `:true`).
|
||||
*/
|
||||
const testComplexConfigDefaults: PartialEnvironmentConfig = {
|
||||
validateNoCapitalizedCalls: [],
|
||||
enableChangeDetectionForDebugging: {
|
||||
source: 'react-compiler-runtime',
|
||||
importSpecifierName: '$structuralCheck',
|
||||
},
|
||||
enableEmitFreeze: {
|
||||
source: 'react-compiler-runtime',
|
||||
importSpecifierName: 'makeReadOnly',
|
||||
},
|
||||
enableEmitInstrumentForget: {
|
||||
fn: {
|
||||
source: 'react-compiler-runtime',
|
||||
importSpecifierName: 'useRenderCounter',
|
||||
},
|
||||
gating: {
|
||||
source: 'react-compiler-runtime',
|
||||
importSpecifierName: 'shouldInstrument',
|
||||
},
|
||||
globalGating: '__DEV__',
|
||||
},
|
||||
enableEmitHookGuards: {
|
||||
source: 'react-compiler-runtime',
|
||||
importSpecifierName: '$dispatcherGuard',
|
||||
},
|
||||
inlineJsxTransform: {
|
||||
elementSymbol: 'react.transitional.element',
|
||||
globalDevVar: 'DEV',
|
||||
},
|
||||
lowerContextAccess: {
|
||||
source: 'react-compiler-runtime',
|
||||
importSpecifierName: 'useContext_withSelector',
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* For snap test fixtures and playground only.
|
||||
*/
|
||||
export function parseConfigPragmaForTests(pragma: string): EnvironmentConfig {
|
||||
const maybeConfig: any = {};
|
||||
// Get the defaults to programmatically check for boolean properties
|
||||
const defaultConfig = EnvironmentConfigSchema.parse({});
|
||||
@@ -580,21 +614,12 @@ export function parseConfigPragma(pragma: string): EnvironmentConfig {
|
||||
continue;
|
||||
}
|
||||
const keyVal = token.slice(1);
|
||||
let [key, val]: any = keyVal.split(':');
|
||||
let [key, val = undefined] = keyVal.split(':');
|
||||
const isSet = val === undefined || val === 'true';
|
||||
|
||||
if (key === 'validateNoCapitalizedCalls') {
|
||||
maybeConfig[key] = [];
|
||||
continue;
|
||||
}
|
||||
|
||||
if (
|
||||
key === 'enableChangeDetectionForDebugging' &&
|
||||
(val === undefined || val === 'true')
|
||||
) {
|
||||
maybeConfig[key] = {
|
||||
source: 'react-compiler-runtime',
|
||||
importSpecifierName: '$structuralCheck',
|
||||
};
|
||||
if (isSet && key in testComplexConfigDefaults) {
|
||||
maybeConfig[key] =
|
||||
testComplexConfigDefaults[key as keyof PartialEnvironmentConfig];
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -609,7 +634,6 @@ export function parseConfigPragma(pragma: string): EnvironmentConfig {
|
||||
props.push({type: 'name', name: elt});
|
||||
}
|
||||
}
|
||||
console.log([valSplit[0], props.map(x => x.name ?? '*').join('.')]);
|
||||
maybeConfig[key] = [[valSplit[0], props]];
|
||||
}
|
||||
continue;
|
||||
@@ -620,11 +644,10 @@ export function parseConfigPragma(pragma: string): EnvironmentConfig {
|
||||
continue;
|
||||
}
|
||||
if (val === undefined || val === 'true') {
|
||||
val = true;
|
||||
maybeConfig[key] = true;
|
||||
} else {
|
||||
val = false;
|
||||
maybeConfig[key] = false;
|
||||
}
|
||||
maybeConfig[key] = val;
|
||||
}
|
||||
|
||||
const config = EnvironmentConfigSchema.safeParse(maybeConfig);
|
||||
|
||||
@@ -16,6 +16,7 @@ import {
|
||||
DeclarationId,
|
||||
areEqualPaths,
|
||||
IdentifierId,
|
||||
Terminal,
|
||||
} from './HIR';
|
||||
import {
|
||||
collectHoistablePropertyLoads,
|
||||
@@ -46,7 +47,7 @@ export function propagateScopeDependenciesHIR(fn: HIRFunction): void {
|
||||
|
||||
const hoistablePropertyLoads = keyByScopeId(
|
||||
fn,
|
||||
collectHoistablePropertyLoads(fn, temporaries, hoistableObjects, null),
|
||||
collectHoistablePropertyLoads(fn, temporaries, hoistableObjects),
|
||||
);
|
||||
|
||||
const scopeDeps = collectDependencies(
|
||||
@@ -176,8 +177,10 @@ function findTemporariesUsedOutsideDeclaringScope(
|
||||
* $2 = LoadLocal 'foo'
|
||||
* $3 = CallExpression $2($1)
|
||||
* ```
|
||||
* Only map LoadLocal and PropertyLoad lvalues to their source if we know that
|
||||
* reordering the read (from the time-of-load to time-of-use) is valid.
|
||||
* @param usedOutsideDeclaringScope is used to check the correctness of
|
||||
* reordering LoadLocal / PropertyLoad calls. We only track a LoadLocal /
|
||||
* PropertyLoad in the returned temporaries map if reordering the read (from the
|
||||
* time-of-load to time-of-use) is valid.
|
||||
*
|
||||
* If a LoadLocal or PropertyLoad instruction is within the reactive scope range
|
||||
* (a proxy for mutable range) of the load source, later instructions may
|
||||
@@ -215,7 +218,29 @@ export function collectTemporariesSidemap(
|
||||
fn: HIRFunction,
|
||||
usedOutsideDeclaringScope: ReadonlySet<DeclarationId>,
|
||||
): ReadonlyMap<IdentifierId, ReactiveScopeDependency> {
|
||||
const temporaries = new Map<IdentifierId, ReactiveScopeDependency>();
|
||||
const temporaries = new Map();
|
||||
collectTemporariesSidemapImpl(
|
||||
fn,
|
||||
usedOutsideDeclaringScope,
|
||||
temporaries,
|
||||
false,
|
||||
);
|
||||
return temporaries;
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursive collect a sidemap of all `LoadLocal` and `PropertyLoads` with a
|
||||
* function and all nested functions.
|
||||
*
|
||||
* Note that IdentifierIds are currently unique, so we can use a single
|
||||
* Map<IdentifierId, ...> across all nested functions.
|
||||
*/
|
||||
function collectTemporariesSidemapImpl(
|
||||
fn: HIRFunction,
|
||||
usedOutsideDeclaringScope: ReadonlySet<DeclarationId>,
|
||||
temporaries: Map<IdentifierId, ReactiveScopeDependency>,
|
||||
isInnerFn: boolean,
|
||||
): void {
|
||||
for (const [_, block] of fn.body.blocks) {
|
||||
for (const instr of block.instructions) {
|
||||
const {value, lvalue} = instr;
|
||||
@@ -224,27 +249,51 @@ export function collectTemporariesSidemap(
|
||||
);
|
||||
|
||||
if (value.kind === 'PropertyLoad' && !usedOutside) {
|
||||
const property = getProperty(
|
||||
value.object,
|
||||
value.property,
|
||||
false,
|
||||
temporaries,
|
||||
);
|
||||
temporaries.set(lvalue.identifier.id, property);
|
||||
if (!isInnerFn || temporaries.has(value.object.identifier.id)) {
|
||||
/**
|
||||
* All dependencies of a inner / nested function must have a base
|
||||
* identifier from the outermost component / hook. This is because the
|
||||
* compiler cannot break an inner function into multiple granular
|
||||
* scopes.
|
||||
*/
|
||||
const property = getProperty(
|
||||
value.object,
|
||||
value.property,
|
||||
false,
|
||||
temporaries,
|
||||
);
|
||||
temporaries.set(lvalue.identifier.id, property);
|
||||
}
|
||||
} else if (
|
||||
value.kind === 'LoadLocal' &&
|
||||
lvalue.identifier.name == null &&
|
||||
value.place.identifier.name !== null &&
|
||||
!usedOutside
|
||||
) {
|
||||
temporaries.set(lvalue.identifier.id, {
|
||||
identifier: value.place.identifier,
|
||||
path: [],
|
||||
});
|
||||
if (
|
||||
!isInnerFn ||
|
||||
fn.context.some(
|
||||
context => context.identifier.id === value.place.identifier.id,
|
||||
)
|
||||
) {
|
||||
temporaries.set(lvalue.identifier.id, {
|
||||
identifier: value.place.identifier,
|
||||
path: [],
|
||||
});
|
||||
}
|
||||
} else if (
|
||||
value.kind === 'FunctionExpression' ||
|
||||
value.kind === 'ObjectMethod'
|
||||
) {
|
||||
collectTemporariesSidemapImpl(
|
||||
value.loweredFunc.func,
|
||||
usedOutsideDeclaringScope,
|
||||
temporaries,
|
||||
true,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
return temporaries;
|
||||
}
|
||||
|
||||
function getProperty(
|
||||
@@ -310,6 +359,12 @@ class Context {
|
||||
#temporaries: ReadonlyMap<IdentifierId, ReactiveScopeDependency>;
|
||||
#temporariesUsedOutsideScope: ReadonlySet<DeclarationId>;
|
||||
|
||||
/**
|
||||
* Tracks the traversal state. See Context.declare for explanation of why this
|
||||
* is needed.
|
||||
*/
|
||||
inInnerFn: boolean = false;
|
||||
|
||||
constructor(
|
||||
temporariesUsedOutsideScope: ReadonlySet<DeclarationId>,
|
||||
temporaries: ReadonlyMap<IdentifierId, ReactiveScopeDependency>,
|
||||
@@ -360,12 +415,23 @@ class Context {
|
||||
}
|
||||
|
||||
/*
|
||||
* Records where a value was declared, and optionally, the scope where the value originated from.
|
||||
* This is later used to determine if a dependency should be added to a scope; if the current
|
||||
* scope we are visiting is the same scope where the value originates, it can't be a dependency
|
||||
* on itself.
|
||||
* Records where a value was declared, and optionally, the scope where the
|
||||
* value originated from. This is later used to determine if a dependency
|
||||
* should be added to a scope; if the current scope we are visiting is the
|
||||
* same scope where the value originates, it can't be a dependency on itself.
|
||||
*
|
||||
* Note that we do not track declarations or reassignments within inner
|
||||
* functions for the following reasons:
|
||||
* - inner functions cannot be split by scope boundaries and are guaranteed
|
||||
* to consume their own declarations
|
||||
* - reassignments within inner functions are tracked as context variables,
|
||||
* which already have extended mutable ranges to account for reassignments
|
||||
* - *most importantly* it's currently simply incorrect to compare inner
|
||||
* function instruction ids (tracked by `decl`) with outer ones (as stored
|
||||
* by root identifier mutable ranges).
|
||||
*/
|
||||
declare(identifier: Identifier, decl: Decl): void {
|
||||
if (this.inInnerFn) return;
|
||||
if (!this.#declarations.has(identifier.declarationId)) {
|
||||
this.#declarations.set(identifier.declarationId, decl);
|
||||
}
|
||||
@@ -575,7 +641,7 @@ function collectDependencies(
|
||||
fn: HIRFunction,
|
||||
usedOutsideDeclaringScope: ReadonlySet<DeclarationId>,
|
||||
temporaries: ReadonlyMap<IdentifierId, ReactiveScopeDependency>,
|
||||
processedInstrsInOptional: ReadonlySet<InstructionId>,
|
||||
processedInstrsInOptional: ReadonlySet<Instruction | Terminal>,
|
||||
): Map<ReactiveScope, Array<ReactiveScopeDependency>> {
|
||||
const context = new Context(usedOutsideDeclaringScope, temporaries);
|
||||
|
||||
@@ -614,12 +680,12 @@ function collectDependencies(
|
||||
}
|
||||
}
|
||||
for (const instr of block.instructions) {
|
||||
if (!processedInstrsInOptional.has(instr.id)) {
|
||||
if (!processedInstrsInOptional.has(instr)) {
|
||||
handleInstruction(instr, context);
|
||||
}
|
||||
}
|
||||
|
||||
if (!processedInstrsInOptional.has(block.terminal.id)) {
|
||||
if (!processedInstrsInOptional.has(block.terminal)) {
|
||||
for (const place of eachTerminalOperand(block.terminal)) {
|
||||
context.visitOperand(place);
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@ export {buildReactiveScopeTerminalsHIR} from './BuildReactiveScopeTerminalsHIR';
|
||||
export {computeDominatorTree, computePostDominatorTree} from './Dominator';
|
||||
export {
|
||||
Environment,
|
||||
parseConfigPragma,
|
||||
parseConfigPragmaForTests,
|
||||
validateEnvironmentConfig,
|
||||
type EnvironmentConfig,
|
||||
type ExternalFunction,
|
||||
|
||||
@@ -1215,9 +1215,17 @@ export class ScopeBlockTraversal {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns if the given scope is currently 'active', i.e. if the scope start
|
||||
* block but not the scope fallthrough has been recorded.
|
||||
*/
|
||||
isScopeActive(scopeId: ScopeId): boolean {
|
||||
return this.#activeScopes.indexOf(scopeId) !== -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* The current, innermost active scope.
|
||||
*/
|
||||
get currentScope(): ScopeId | null {
|
||||
return this.#activeScopes.at(-1) ?? null;
|
||||
}
|
||||
|
||||
@@ -383,6 +383,30 @@ export function inlineJsxTransform(
|
||||
mapTerminalOperands(block.terminal, place =>
|
||||
handlePlace(place, blockId, inlinedJsxDeclarations),
|
||||
);
|
||||
|
||||
if (block.terminal.kind === 'scope') {
|
||||
const scope = block.terminal.scope;
|
||||
for (const dep of scope.dependencies) {
|
||||
dep.identifier = handleIdentifier(
|
||||
dep.identifier,
|
||||
inlinedJsxDeclarations,
|
||||
);
|
||||
}
|
||||
|
||||
for (const [origId, decl] of [...scope.declarations]) {
|
||||
const newDecl = handleIdentifier(
|
||||
decl.identifier,
|
||||
inlinedJsxDeclarations,
|
||||
);
|
||||
if (newDecl.id !== origId) {
|
||||
scope.declarations.delete(origId);
|
||||
scope.declarations.set(decl.identifier.id, {
|
||||
identifier: newDecl,
|
||||
scope: decl.scope,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -697,10 +721,10 @@ function handlePlace(
|
||||
inlinedJsxDeclaration == null ||
|
||||
inlinedJsxDeclaration.blockIdsToIgnore.has(blockId)
|
||||
) {
|
||||
return {...place};
|
||||
return place;
|
||||
}
|
||||
|
||||
return {...place, identifier: {...inlinedJsxDeclaration.identifier}};
|
||||
return {...place, identifier: inlinedJsxDeclaration.identifier};
|
||||
}
|
||||
|
||||
function handlelValue(
|
||||
@@ -715,8 +739,20 @@ function handlelValue(
|
||||
inlinedJsxDeclaration == null ||
|
||||
inlinedJsxDeclaration.blockIdsToIgnore.has(blockId)
|
||||
) {
|
||||
return {...lvalue};
|
||||
return lvalue;
|
||||
}
|
||||
|
||||
return {...lvalue, identifier: {...inlinedJsxDeclaration.identifier}};
|
||||
return {...lvalue, identifier: inlinedJsxDeclaration.identifier};
|
||||
}
|
||||
|
||||
function handleIdentifier(
|
||||
identifier: Identifier,
|
||||
inlinedJsxDeclarations: InlinedJsxDeclarationMap,
|
||||
): Identifier {
|
||||
const inlinedJsxDeclaration = inlinedJsxDeclarations.get(
|
||||
identifier.declarationId,
|
||||
);
|
||||
return inlinedJsxDeclaration == null
|
||||
? identifier
|
||||
: inlinedJsxDeclaration.identifier;
|
||||
}
|
||||
|
||||
@@ -210,12 +210,30 @@ function process(
|
||||
return {instrs: newInstrs, fn: outlinedFn};
|
||||
}
|
||||
|
||||
type OutlinedJsxAttribute = {
|
||||
originalName: string;
|
||||
newName: string;
|
||||
place: Place;
|
||||
};
|
||||
|
||||
function collectProps(
|
||||
instructions: Array<JsxInstruction>,
|
||||
): Array<JsxAttribute> | null {
|
||||
const attributes: Array<JsxAttribute> = [];
|
||||
): Array<OutlinedJsxAttribute> | null {
|
||||
let id = 1;
|
||||
|
||||
function generateName(oldName: string): string {
|
||||
let newName = oldName;
|
||||
while (seen.has(newName)) {
|
||||
newName = `${oldName}${id++}`;
|
||||
}
|
||||
seen.add(newName);
|
||||
return newName;
|
||||
}
|
||||
|
||||
const attributes: Array<OutlinedJsxAttribute> = [];
|
||||
const jsxIds = new Set(instructions.map(i => i.lvalue.identifier.id));
|
||||
const seen: Set<string> = new Set();
|
||||
|
||||
for (const instr of instructions) {
|
||||
const {value} = instr;
|
||||
|
||||
@@ -224,26 +242,30 @@ function collectProps(
|
||||
return null;
|
||||
}
|
||||
|
||||
/*
|
||||
* TODO(gsn): Handle attributes that have same value across
|
||||
* the outlined jsx instructions.
|
||||
*/
|
||||
if (seen.has(at.name)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (at.kind === 'JsxAttribute') {
|
||||
seen.add(at.name);
|
||||
attributes.push(at);
|
||||
const newName = generateName(at.name);
|
||||
attributes.push({
|
||||
originalName: at.name,
|
||||
newName,
|
||||
place: at.place,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(gsn): Add support for children that are not jsx expressions
|
||||
if (
|
||||
value.children &&
|
||||
value.children.some(child => !jsxIds.has(child.identifier.id))
|
||||
) {
|
||||
return null;
|
||||
if (value.children) {
|
||||
for (const child of value.children) {
|
||||
if (jsxIds.has(child.identifier.id)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
promoteTemporary(child.identifier);
|
||||
const newName = generateName('t');
|
||||
attributes.push({
|
||||
originalName: child.identifier.name!.value,
|
||||
newName: newName,
|
||||
place: child,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
return attributes;
|
||||
@@ -252,9 +274,15 @@ function collectProps(
|
||||
function emitOutlinedJsx(
|
||||
env: Environment,
|
||||
instructions: Array<Instruction>,
|
||||
props: Array<JsxAttribute>,
|
||||
outlinedProps: Array<OutlinedJsxAttribute>,
|
||||
outlinedTag: string,
|
||||
): Array<Instruction> {
|
||||
const props: Array<JsxAttribute> = outlinedProps.map(p => ({
|
||||
kind: 'JsxAttribute',
|
||||
name: p.newName,
|
||||
place: p.place,
|
||||
}));
|
||||
|
||||
const loadJsx: Instruction = {
|
||||
id: makeInstructionId(0),
|
||||
loc: GeneratedSource,
|
||||
@@ -290,7 +318,7 @@ function emitOutlinedJsx(
|
||||
function emitOutlinedFn(
|
||||
env: Environment,
|
||||
jsx: Array<JsxInstruction>,
|
||||
oldProps: Array<JsxAttribute>,
|
||||
oldProps: Array<OutlinedJsxAttribute>,
|
||||
globals: LoadGlobalMap,
|
||||
): HIRFunction | null {
|
||||
const instructions: Array<Instruction> = [];
|
||||
@@ -299,9 +327,11 @@ function emitOutlinedFn(
|
||||
const propsObj: Place = createTemporaryPlace(env, GeneratedSource);
|
||||
promoteTemporary(propsObj.identifier);
|
||||
|
||||
const destructurePropsInstr = emitDestructureProps(env, propsObj, [
|
||||
...oldToNewProps.values(),
|
||||
]);
|
||||
const destructurePropsInstr = emitDestructureProps(
|
||||
env,
|
||||
propsObj,
|
||||
oldToNewProps,
|
||||
);
|
||||
instructions.push(destructurePropsInstr);
|
||||
|
||||
const updatedJsxInstructions = emitUpdatedJsx(jsx, oldToNewProps);
|
||||
@@ -368,9 +398,10 @@ function emitLoadGlobals(
|
||||
|
||||
function emitUpdatedJsx(
|
||||
jsx: Array<JsxInstruction>,
|
||||
oldToNewProps: Map<IdentifierId, ObjectProperty>,
|
||||
oldToNewProps: Map<IdentifierId, OutlinedJsxAttribute>,
|
||||
): Array<JsxInstruction> {
|
||||
const newInstrs: Array<JsxInstruction> = [];
|
||||
const jsxIds = new Set(jsx.map(i => i.lvalue.identifier.id));
|
||||
|
||||
for (const instr of jsx) {
|
||||
const {value} = instr;
|
||||
@@ -390,16 +421,36 @@ function emitUpdatedJsx(
|
||||
`Expected a new property for ${printIdentifier(prop.place.identifier)}`,
|
||||
);
|
||||
newProps.push({
|
||||
...prop,
|
||||
kind: 'JsxAttribute',
|
||||
name: newProp.originalName,
|
||||
place: newProp.place,
|
||||
});
|
||||
}
|
||||
|
||||
let newChildren: Array<Place> | null = null;
|
||||
if (value.children) {
|
||||
newChildren = [];
|
||||
for (const child of value.children) {
|
||||
if (jsxIds.has(child.identifier.id)) {
|
||||
newChildren.push({...child});
|
||||
continue;
|
||||
}
|
||||
|
||||
const newChild = oldToNewProps.get(child.identifier.id);
|
||||
invariant(
|
||||
newChild !== undefined,
|
||||
`Expected a new prop for ${printIdentifier(child.identifier)}`,
|
||||
);
|
||||
newChildren.push({...newChild.place});
|
||||
}
|
||||
}
|
||||
|
||||
newInstrs.push({
|
||||
...instr,
|
||||
value: {
|
||||
...value,
|
||||
props: newProps,
|
||||
children: newChildren,
|
||||
},
|
||||
});
|
||||
}
|
||||
@@ -409,31 +460,21 @@ function emitUpdatedJsx(
|
||||
|
||||
function createOldToNewPropsMapping(
|
||||
env: Environment,
|
||||
oldProps: Array<JsxAttribute>,
|
||||
): Map<IdentifierId, ObjectProperty> {
|
||||
oldProps: Array<OutlinedJsxAttribute>,
|
||||
): Map<IdentifierId, OutlinedJsxAttribute> {
|
||||
const oldToNewProps = new Map();
|
||||
|
||||
for (const oldProp of oldProps) {
|
||||
invariant(
|
||||
oldProp.kind === 'JsxAttribute',
|
||||
`Expected only attributes but found ${oldProp.kind}`,
|
||||
);
|
||||
|
||||
// Do not read key prop in the outlined component
|
||||
if (oldProp.name === 'key') {
|
||||
if (oldProp.originalName === 'key') {
|
||||
continue;
|
||||
}
|
||||
|
||||
const newProp: ObjectProperty = {
|
||||
kind: 'ObjectProperty',
|
||||
key: {
|
||||
kind: 'string',
|
||||
name: oldProp.name,
|
||||
},
|
||||
type: 'property',
|
||||
const newProp: OutlinedJsxAttribute = {
|
||||
...oldProp,
|
||||
place: createTemporaryPlace(env, GeneratedSource),
|
||||
};
|
||||
newProp.place.identifier.name = makeIdentifierName(oldProp.name);
|
||||
newProp.place.identifier.name = makeIdentifierName(oldProp.newName);
|
||||
oldToNewProps.set(oldProp.place.identifier.id, newProp);
|
||||
}
|
||||
|
||||
@@ -443,8 +484,21 @@ function createOldToNewPropsMapping(
|
||||
function emitDestructureProps(
|
||||
env: Environment,
|
||||
propsObj: Place,
|
||||
properties: Array<ObjectProperty>,
|
||||
oldToNewProps: Map<IdentifierId, OutlinedJsxAttribute>,
|
||||
): Instruction {
|
||||
const properties: Array<ObjectProperty> = [];
|
||||
for (const [_, prop] of oldToNewProps) {
|
||||
properties.push({
|
||||
kind: 'ObjectProperty',
|
||||
key: {
|
||||
kind: 'string',
|
||||
name: prop.newName,
|
||||
},
|
||||
type: 'property',
|
||||
place: prop.place,
|
||||
});
|
||||
}
|
||||
|
||||
const destructurePropsInstr: Instruction = {
|
||||
id: makeInstructionId(0),
|
||||
lvalue: createTemporaryPlace(env, GeneratedSource),
|
||||
|
||||
@@ -34,6 +34,7 @@ import {
|
||||
ReactiveInstruction,
|
||||
ReactiveScope,
|
||||
ReactiveScopeBlock,
|
||||
ReactiveScopeDeclaration,
|
||||
ReactiveScopeDependency,
|
||||
ReactiveTerminal,
|
||||
ReactiveValue,
|
||||
@@ -572,7 +573,8 @@ function codegenReactiveScope(
|
||||
const changeExpressions: Array<t.Expression> = [];
|
||||
const changeExpressionComments: Array<string> = [];
|
||||
const outputComments: Array<string> = [];
|
||||
for (const dep of scope.dependencies) {
|
||||
|
||||
for (const dep of [...scope.dependencies].sort(compareScopeDependency)) {
|
||||
const index = cx.nextCacheIndex;
|
||||
changeExpressionComments.push(printDependencyComment(dep));
|
||||
const comparison = t.binaryExpression(
|
||||
@@ -615,7 +617,10 @@ function codegenReactiveScope(
|
||||
);
|
||||
}
|
||||
let firstOutputIndex: number | null = null;
|
||||
for (const [, {identifier}] of scope.declarations) {
|
||||
|
||||
for (const [, {identifier}] of [...scope.declarations].sort(([, a], [, b]) =>
|
||||
compareScopeDeclaration(a, b),
|
||||
)) {
|
||||
const index = cx.nextCacheIndex;
|
||||
if (firstOutputIndex === null) {
|
||||
firstOutputIndex = index;
|
||||
@@ -2566,3 +2571,45 @@ function convertIdentifier(identifier: Identifier): t.Identifier {
|
||||
);
|
||||
return t.identifier(identifier.name.value);
|
||||
}
|
||||
|
||||
function compareScopeDependency(
|
||||
a: ReactiveScopeDependency,
|
||||
b: ReactiveScopeDependency,
|
||||
): number {
|
||||
CompilerError.invariant(
|
||||
a.identifier.name?.kind === 'named' && b.identifier.name?.kind === 'named',
|
||||
{
|
||||
reason: '[Codegen] Expected named identifier for dependency',
|
||||
loc: a.identifier.loc,
|
||||
},
|
||||
);
|
||||
const aName = [
|
||||
a.identifier.name.value,
|
||||
...a.path.map(entry => `${entry.optional ? '?' : ''}${entry.property}`),
|
||||
].join('.');
|
||||
const bName = [
|
||||
b.identifier.name.value,
|
||||
...b.path.map(entry => `${entry.optional ? '?' : ''}${entry.property}`),
|
||||
].join('.');
|
||||
if (aName < bName) return -1;
|
||||
else if (aName > bName) return 1;
|
||||
else return 0;
|
||||
}
|
||||
|
||||
function compareScopeDeclaration(
|
||||
a: ReactiveScopeDeclaration,
|
||||
b: ReactiveScopeDeclaration,
|
||||
): number {
|
||||
CompilerError.invariant(
|
||||
a.identifier.name?.kind === 'named' && b.identifier.name?.kind === 'named',
|
||||
{
|
||||
reason: '[Codegen] Expected named identifier for declaration',
|
||||
loc: a.identifier.loc,
|
||||
},
|
||||
);
|
||||
const aName = a.identifier.name.value;
|
||||
const bName = b.identifier.name.value;
|
||||
if (aName < bName) return -1;
|
||||
else if (aName > bName) return 1;
|
||||
else return 0;
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -17,7 +17,6 @@ export {mergeReactiveScopesThatInvalidateTogether} from './MergeReactiveScopesTh
|
||||
export {printReactiveFunction} from './PrintReactiveFunction';
|
||||
export {promoteUsedTemporaries} from './PromoteUsedTemporaries';
|
||||
export {propagateEarlyReturns} from './PropagateEarlyReturns';
|
||||
export {propagateScopeDependencies} from './PropagateScopeDependencies';
|
||||
export {pruneAllReactiveScopes} from './PruneAllReactiveScopes';
|
||||
export {pruneHoistedContexts} from './PruneHoistedContexts';
|
||||
export {pruneNonEscapingScopes} from './PruneNonEscapingScopes';
|
||||
|
||||
@@ -47,7 +47,7 @@ import { identity, mutate, setProperty } from "shared-runtime";
|
||||
function AllocatingPrimitiveAsDepNested(props) {
|
||||
const $ = _c(5);
|
||||
let t0;
|
||||
if ($[0] !== props.b || $[1] !== props.a) {
|
||||
if ($[0] !== props.a || $[1] !== props.b) {
|
||||
const x = {};
|
||||
mutate(x);
|
||||
const t1 = identity(props.b) + 1;
|
||||
@@ -62,8 +62,8 @@ function AllocatingPrimitiveAsDepNested(props) {
|
||||
const y = t2;
|
||||
setProperty(x, props.a);
|
||||
t0 = [x, y];
|
||||
$[0] = props.b;
|
||||
$[1] = props.a;
|
||||
$[0] = props.a;
|
||||
$[1] = props.b;
|
||||
$[2] = t0;
|
||||
} else {
|
||||
t0 = $[2];
|
||||
|
||||
@@ -41,7 +41,7 @@ function ArrayAtTest(props) {
|
||||
}
|
||||
const arr = t1;
|
||||
let t2;
|
||||
if ($[4] !== props.y || $[5] !== arr) {
|
||||
if ($[4] !== arr || $[5] !== props.y) {
|
||||
let t3;
|
||||
if ($[7] !== props.y) {
|
||||
t3 = bar(props.y);
|
||||
@@ -51,8 +51,8 @@ function ArrayAtTest(props) {
|
||||
t3 = $[8];
|
||||
}
|
||||
t2 = arr.at(t3);
|
||||
$[4] = props.y;
|
||||
$[5] = arr;
|
||||
$[4] = arr;
|
||||
$[5] = props.y;
|
||||
$[6] = t2;
|
||||
} else {
|
||||
t2 = $[6];
|
||||
|
||||
@@ -22,10 +22,10 @@ import { c as _c } from "react/compiler-runtime";
|
||||
function Component(props) {
|
||||
const $ = _c(3);
|
||||
let t0;
|
||||
if ($[0] !== props.foo || $[1] !== props.bar) {
|
||||
if ($[0] !== props.bar || $[1] !== props.foo) {
|
||||
t0 = [0, ...props.foo, null, ...props.bar, "z"];
|
||||
$[0] = props.foo;
|
||||
$[1] = props.bar;
|
||||
$[0] = props.bar;
|
||||
$[1] = props.foo;
|
||||
$[2] = t0;
|
||||
} else {
|
||||
t0 = $[2];
|
||||
|
||||
@@ -24,18 +24,18 @@ export const FIXTURE_ENTRYPOINT = {
|
||||
import { c as _c } from "react/compiler-runtime";
|
||||
function Component(props) {
|
||||
const $ = _c(11);
|
||||
let t0;
|
||||
let a;
|
||||
let t0;
|
||||
if ($[0] !== props.a || $[1] !== props.b) {
|
||||
a = [props.a, props.b, "hello"];
|
||||
t0 = a.push(42);
|
||||
$[0] = props.a;
|
||||
$[1] = props.b;
|
||||
$[2] = t0;
|
||||
$[3] = a;
|
||||
$[2] = a;
|
||||
$[3] = t0;
|
||||
} else {
|
||||
t0 = $[2];
|
||||
a = $[3];
|
||||
a = $[2];
|
||||
t0 = $[3];
|
||||
}
|
||||
const x = t0;
|
||||
let t1;
|
||||
|
||||
@@ -0,0 +1,107 @@
|
||||
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
// @flow @enableTransitivelyFreezeFunctionExpressions:false
|
||||
import {arrayPush, setPropertyByKey, Stringify} from 'shared-runtime';
|
||||
|
||||
/**
|
||||
* 1. `InferMutableRanges` derives the mutable range of identifiers and their
|
||||
* aliases from `LoadLocal`, `PropertyLoad`, etc
|
||||
* - After this pass, y's mutable range only extends to `arrayPush(x, y)`
|
||||
* - We avoid assigning mutable ranges to loads after y's mutable range, as
|
||||
* these are working with an immutable value. As a result, `LoadLocal y` and
|
||||
* `PropertyLoad y` do not get mutable ranges
|
||||
* 2. `InferReactiveScopeVariables` extends mutable ranges and creates scopes,
|
||||
* as according to the 'co-mutation' of different values
|
||||
* - Here, we infer that
|
||||
* - `arrayPush(y, x)` might alias `x` and `y` to each other
|
||||
* - `setPropertyKey(x, ...)` may mutate both `x` and `y`
|
||||
* - This pass correctly extends the mutable range of `y`
|
||||
* - Since we didn't run `InferMutableRange` logic again, the LoadLocal /
|
||||
* PropertyLoads still don't have a mutable range
|
||||
*
|
||||
* Note that the this bug is an edge case. Compiler output is only invalid for:
|
||||
* - function expressions with
|
||||
* `enableTransitivelyFreezeFunctionExpressions:false`
|
||||
* - functions that throw and get retried without clearing the memocache
|
||||
*
|
||||
* Found differences in evaluator results
|
||||
* Non-forget (expected):
|
||||
* (kind: ok)
|
||||
* <div>{"cb":{"kind":"Function","result":10},"shouldInvokeFns":true}</div>
|
||||
* <div>{"cb":{"kind":"Function","result":11},"shouldInvokeFns":true}</div>
|
||||
* Forget:
|
||||
* (kind: ok)
|
||||
* <div>{"cb":{"kind":"Function","result":10},"shouldInvokeFns":true}</div>
|
||||
* <div>{"cb":{"kind":"Function","result":10},"shouldInvokeFns":true}</div>
|
||||
*/
|
||||
function useFoo({a, b}: {a: number, b: number}) {
|
||||
const x = [];
|
||||
const y = {value: a};
|
||||
|
||||
arrayPush(x, y); // x and y co-mutate
|
||||
const y_alias = y;
|
||||
const cb = () => y_alias.value;
|
||||
setPropertyByKey(x[0], 'value', b); // might overwrite y.value
|
||||
return <Stringify cb={cb} shouldInvokeFns={true} />;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: useFoo,
|
||||
params: [{a: 2, b: 10}],
|
||||
sequentialRenders: [
|
||||
{a: 2, b: 10},
|
||||
{a: 2, b: 11},
|
||||
],
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
## Code
|
||||
|
||||
```javascript
|
||||
import { c as _c } from "react/compiler-runtime";
|
||||
import { arrayPush, setPropertyByKey, Stringify } from "shared-runtime";
|
||||
|
||||
function useFoo(t0) {
|
||||
const $ = _c(5);
|
||||
const { a, b } = t0;
|
||||
let t1;
|
||||
if ($[0] !== a || $[1] !== b) {
|
||||
const x = [];
|
||||
const y = { value: a };
|
||||
|
||||
arrayPush(x, y);
|
||||
const y_alias = y;
|
||||
let t2;
|
||||
if ($[3] !== y_alias.value) {
|
||||
t2 = () => y_alias.value;
|
||||
$[3] = y_alias.value;
|
||||
$[4] = t2;
|
||||
} else {
|
||||
t2 = $[4];
|
||||
}
|
||||
const cb = t2;
|
||||
setPropertyByKey(x[0], "value", b);
|
||||
t1 = <Stringify cb={cb} shouldInvokeFns={true} />;
|
||||
$[0] = a;
|
||||
$[1] = b;
|
||||
$[2] = t1;
|
||||
} else {
|
||||
t1 = $[2];
|
||||
}
|
||||
return t1;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: useFoo,
|
||||
params: [{ a: 2, b: 10 }],
|
||||
sequentialRenders: [
|
||||
{ a: 2, b: 10 },
|
||||
{ a: 2, b: 11 },
|
||||
],
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
// @flow @enableTransitivelyFreezeFunctionExpressions:false
|
||||
import {arrayPush, setPropertyByKey, Stringify} from 'shared-runtime';
|
||||
|
||||
/**
|
||||
* 1. `InferMutableRanges` derives the mutable range of identifiers and their
|
||||
* aliases from `LoadLocal`, `PropertyLoad`, etc
|
||||
* - After this pass, y's mutable range only extends to `arrayPush(x, y)`
|
||||
* - We avoid assigning mutable ranges to loads after y's mutable range, as
|
||||
* these are working with an immutable value. As a result, `LoadLocal y` and
|
||||
* `PropertyLoad y` do not get mutable ranges
|
||||
* 2. `InferReactiveScopeVariables` extends mutable ranges and creates scopes,
|
||||
* as according to the 'co-mutation' of different values
|
||||
* - Here, we infer that
|
||||
* - `arrayPush(y, x)` might alias `x` and `y` to each other
|
||||
* - `setPropertyKey(x, ...)` may mutate both `x` and `y`
|
||||
* - This pass correctly extends the mutable range of `y`
|
||||
* - Since we didn't run `InferMutableRange` logic again, the LoadLocal /
|
||||
* PropertyLoads still don't have a mutable range
|
||||
*
|
||||
* Note that the this bug is an edge case. Compiler output is only invalid for:
|
||||
* - function expressions with
|
||||
* `enableTransitivelyFreezeFunctionExpressions:false`
|
||||
* - functions that throw and get retried without clearing the memocache
|
||||
*
|
||||
* Found differences in evaluator results
|
||||
* Non-forget (expected):
|
||||
* (kind: ok)
|
||||
* <div>{"cb":{"kind":"Function","result":10},"shouldInvokeFns":true}</div>
|
||||
* <div>{"cb":{"kind":"Function","result":11},"shouldInvokeFns":true}</div>
|
||||
* Forget:
|
||||
* (kind: ok)
|
||||
* <div>{"cb":{"kind":"Function","result":10},"shouldInvokeFns":true}</div>
|
||||
* <div>{"cb":{"kind":"Function","result":10},"shouldInvokeFns":true}</div>
|
||||
*/
|
||||
function useFoo({a, b}: {a: number, b: number}) {
|
||||
const x = [];
|
||||
const y = {value: a};
|
||||
|
||||
arrayPush(x, y); // x and y co-mutate
|
||||
const y_alias = y;
|
||||
const cb = () => y_alias.value;
|
||||
setPropertyByKey(x[0], 'value', b); // might overwrite y.value
|
||||
return <Stringify cb={cb} shouldInvokeFns={true} />;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: useFoo,
|
||||
params: [{a: 2, b: 10}],
|
||||
sequentialRenders: [
|
||||
{a: 2, b: 10},
|
||||
{a: 2, b: 11},
|
||||
],
|
||||
};
|
||||
@@ -0,0 +1,87 @@
|
||||
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
// @flow @enableTransitivelyFreezeFunctionExpressions:false
|
||||
import {setPropertyByKey, Stringify} from 'shared-runtime';
|
||||
|
||||
/**
|
||||
* Variation of bug in `bug-aliased-capture-aliased-mutate`
|
||||
* Found differences in evaluator results
|
||||
* Non-forget (expected):
|
||||
* (kind: ok)
|
||||
* <div>{"cb":{"kind":"Function","result":2},"shouldInvokeFns":true}</div>
|
||||
* <div>{"cb":{"kind":"Function","result":3},"shouldInvokeFns":true}</div>
|
||||
* Forget:
|
||||
* (kind: ok)
|
||||
* <div>{"cb":{"kind":"Function","result":2},"shouldInvokeFns":true}</div>
|
||||
* <div>{"cb":{"kind":"Function","result":2},"shouldInvokeFns":true}</div>
|
||||
*/
|
||||
|
||||
function useFoo({a}: {a: number, b: number}) {
|
||||
const arr = [];
|
||||
const obj = {value: a};
|
||||
|
||||
setPropertyByKey(obj, 'arr', arr);
|
||||
const obj_alias = obj;
|
||||
const cb = () => obj_alias.arr.length;
|
||||
for (let i = 0; i < a; i++) {
|
||||
arr.push(i);
|
||||
}
|
||||
return <Stringify cb={cb} shouldInvokeFns={true} />;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: useFoo,
|
||||
params: [{a: 2}],
|
||||
sequentialRenders: [{a: 2}, {a: 3}],
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
## Code
|
||||
|
||||
```javascript
|
||||
import { c as _c } from "react/compiler-runtime";
|
||||
import { setPropertyByKey, Stringify } from "shared-runtime";
|
||||
|
||||
function useFoo(t0) {
|
||||
const $ = _c(4);
|
||||
const { a } = t0;
|
||||
let t1;
|
||||
if ($[0] !== a) {
|
||||
const arr = [];
|
||||
const obj = { value: a };
|
||||
|
||||
setPropertyByKey(obj, "arr", arr);
|
||||
const obj_alias = obj;
|
||||
let t2;
|
||||
if ($[2] !== obj_alias.arr.length) {
|
||||
t2 = () => obj_alias.arr.length;
|
||||
$[2] = obj_alias.arr.length;
|
||||
$[3] = t2;
|
||||
} else {
|
||||
t2 = $[3];
|
||||
}
|
||||
const cb = t2;
|
||||
for (let i = 0; i < a; i++) {
|
||||
arr.push(i);
|
||||
}
|
||||
|
||||
t1 = <Stringify cb={cb} shouldInvokeFns={true} />;
|
||||
$[0] = a;
|
||||
$[1] = t1;
|
||||
} else {
|
||||
t1 = $[1];
|
||||
}
|
||||
return t1;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: useFoo,
|
||||
params: [{ a: 2 }],
|
||||
sequentialRenders: [{ a: 2 }, { a: 3 }],
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
// @flow @enableTransitivelyFreezeFunctionExpressions:false
|
||||
import {setPropertyByKey, Stringify} from 'shared-runtime';
|
||||
|
||||
/**
|
||||
* Variation of bug in `bug-aliased-capture-aliased-mutate`
|
||||
* Found differences in evaluator results
|
||||
* Non-forget (expected):
|
||||
* (kind: ok)
|
||||
* <div>{"cb":{"kind":"Function","result":2},"shouldInvokeFns":true}</div>
|
||||
* <div>{"cb":{"kind":"Function","result":3},"shouldInvokeFns":true}</div>
|
||||
* Forget:
|
||||
* (kind: ok)
|
||||
* <div>{"cb":{"kind":"Function","result":2},"shouldInvokeFns":true}</div>
|
||||
* <div>{"cb":{"kind":"Function","result":2},"shouldInvokeFns":true}</div>
|
||||
*/
|
||||
|
||||
function useFoo({a}: {a: number, b: number}) {
|
||||
const arr = [];
|
||||
const obj = {value: a};
|
||||
|
||||
setPropertyByKey(obj, 'arr', arr);
|
||||
const obj_alias = obj;
|
||||
const cb = () => obj_alias.arr.length;
|
||||
for (let i = 0; i < a; i++) {
|
||||
arr.push(i);
|
||||
}
|
||||
return <Stringify cb={cb} shouldInvokeFns={true} />;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: useFoo,
|
||||
params: [{a: 2}],
|
||||
sequentialRenders: [{a: 2}, {a: 3}],
|
||||
};
|
||||
@@ -0,0 +1,81 @@
|
||||
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
import {Stringify} from 'shared-runtime';
|
||||
|
||||
/**
|
||||
* Fixture currently fails with
|
||||
* Found differences in evaluator results
|
||||
* Non-forget (expected):
|
||||
* (kind: ok) <div>{"result":{"value":2},"fn":{"kind":"Function","result":{"value":2}},"shouldInvokeFns":true}</div>
|
||||
* Forget:
|
||||
* (kind: exception) bar is not a function
|
||||
*/
|
||||
function Foo({value}) {
|
||||
const result = bar();
|
||||
function bar() {
|
||||
return {value};
|
||||
}
|
||||
return <Stringify result={result} fn={bar} shouldInvokeFns={true} />;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: Foo,
|
||||
params: [{value: 2}],
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
## Code
|
||||
|
||||
```javascript
|
||||
import { c as _c } from "react/compiler-runtime";
|
||||
import { Stringify } from "shared-runtime";
|
||||
|
||||
/**
|
||||
* Fixture currently fails with
|
||||
* Found differences in evaluator results
|
||||
* Non-forget (expected):
|
||||
* (kind: ok) <div>{"result":{"value":2},"fn":{"kind":"Function","result":{"value":2}},"shouldInvokeFns":true}</div>
|
||||
* Forget:
|
||||
* (kind: exception) bar is not a function
|
||||
*/
|
||||
function Foo(t0) {
|
||||
const $ = _c(6);
|
||||
const { value } = t0;
|
||||
let bar;
|
||||
let result;
|
||||
if ($[0] !== value) {
|
||||
result = bar();
|
||||
bar = function bar() {
|
||||
return { value };
|
||||
};
|
||||
$[0] = value;
|
||||
$[1] = bar;
|
||||
$[2] = result;
|
||||
} else {
|
||||
bar = $[1];
|
||||
result = $[2];
|
||||
}
|
||||
|
||||
const t1 = bar;
|
||||
let t2;
|
||||
if ($[3] !== result || $[4] !== t1) {
|
||||
t2 = <Stringify result={result} fn={t1} shouldInvokeFns={true} />;
|
||||
$[3] = result;
|
||||
$[4] = t1;
|
||||
$[5] = t2;
|
||||
} else {
|
||||
t2 = $[5];
|
||||
}
|
||||
return t2;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: Foo,
|
||||
params: [{ value: 2 }],
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
import {Stringify} from 'shared-runtime';
|
||||
|
||||
/**
|
||||
* Fixture currently fails with
|
||||
* Found differences in evaluator results
|
||||
* Non-forget (expected):
|
||||
* (kind: ok) <div>{"result":{"value":2},"fn":{"kind":"Function","result":{"value":2}},"shouldInvokeFns":true}</div>
|
||||
* Forget:
|
||||
* (kind: exception) bar is not a function
|
||||
*/
|
||||
function Foo({value}) {
|
||||
const result = bar();
|
||||
function bar() {
|
||||
return {value};
|
||||
}
|
||||
return <Stringify result={result} fn={bar} shouldInvokeFns={true} />;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: Foo,
|
||||
params: [{value: 2}],
|
||||
};
|
||||
@@ -58,7 +58,7 @@ function Component(t0) {
|
||||
const $ = _c(5);
|
||||
const { obj, isObjNull } = t0;
|
||||
let t1;
|
||||
if ($[0] !== isObjNull || $[1] !== obj.prop) {
|
||||
if ($[0] !== isObjNull || $[1] !== obj) {
|
||||
t1 = () => {
|
||||
if (!isObjNull) {
|
||||
return obj.prop;
|
||||
@@ -67,7 +67,7 @@ function Component(t0) {
|
||||
}
|
||||
};
|
||||
$[0] = isObjNull;
|
||||
$[1] = obj.prop;
|
||||
$[1] = obj;
|
||||
$[2] = t1;
|
||||
} else {
|
||||
t1 = $[2];
|
||||
|
||||
@@ -70,10 +70,10 @@ function Component() {
|
||||
throw new Error("invariant broken");
|
||||
}
|
||||
let t1;
|
||||
if ($[1] !== obj || $[2] !== boxedInner) {
|
||||
if ($[1] !== boxedInner || $[2] !== obj) {
|
||||
t1 = <Stringify obj={obj} inner={boxedInner} />;
|
||||
$[1] = obj;
|
||||
$[2] = boxedInner;
|
||||
$[1] = boxedInner;
|
||||
$[2] = obj;
|
||||
$[3] = t1;
|
||||
} else {
|
||||
t1 = $[3];
|
||||
|
||||
@@ -0,0 +1,89 @@
|
||||
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
import {useRef} from 'react';
|
||||
import {Stringify} from 'shared-runtime';
|
||||
|
||||
/**
|
||||
* Bug: we're currently filtering out `ref.current` dependencies in
|
||||
* `propagateScopeDependencies:checkValidDependency`. This is incorrect.
|
||||
* Instead, we should always take a dependency on ref values (the outer box) as
|
||||
* they may be reactive. Pruning should be done in
|
||||
* `pruneNonReactiveDependencies`
|
||||
*
|
||||
* Found differences in evaluator results
|
||||
* Non-forget (expected):
|
||||
* (kind: ok)
|
||||
* <div>{"cb":{"kind":"Function","result":1},"shouldInvokeFns":true}</div>
|
||||
* <div>{"cb":{"kind":"Function","result":2},"shouldInvokeFns":true}</div>
|
||||
* Forget:
|
||||
* (kind: ok)
|
||||
* <div>{"cb":{"kind":"Function","result":1},"shouldInvokeFns":true}</div>
|
||||
* <div>{"cb":{"kind":"Function","result":1},"shouldInvokeFns":true}</div>
|
||||
*/
|
||||
function Component({cond}) {
|
||||
const ref1 = useRef(1);
|
||||
const ref2 = useRef(2);
|
||||
const ref = cond ? ref1 : ref2;
|
||||
const cb = () => ref.current;
|
||||
return <Stringify cb={cb} shouldInvokeFns={true} />;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: Component,
|
||||
params: [{cond: true}],
|
||||
sequentialRenders: [{cond: true}, {cond: false}],
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
## Code
|
||||
|
||||
```javascript
|
||||
import { c as _c } from "react/compiler-runtime";
|
||||
import { useRef } from "react";
|
||||
import { Stringify } from "shared-runtime";
|
||||
|
||||
/**
|
||||
* Bug: we're currently filtering out `ref.current` dependencies in
|
||||
* `propagateScopeDependencies:checkValidDependency`. This is incorrect.
|
||||
* Instead, we should always take a dependency on ref values (the outer box) as
|
||||
* they may be reactive. Pruning should be done in
|
||||
* `pruneNonReactiveDependencies`
|
||||
*
|
||||
* Found differences in evaluator results
|
||||
* Non-forget (expected):
|
||||
* (kind: ok)
|
||||
* <div>{"cb":{"kind":"Function","result":1},"shouldInvokeFns":true}</div>
|
||||
* <div>{"cb":{"kind":"Function","result":2},"shouldInvokeFns":true}</div>
|
||||
* Forget:
|
||||
* (kind: ok)
|
||||
* <div>{"cb":{"kind":"Function","result":1},"shouldInvokeFns":true}</div>
|
||||
* <div>{"cb":{"kind":"Function","result":1},"shouldInvokeFns":true}</div>
|
||||
*/
|
||||
function Component(t0) {
|
||||
const $ = _c(1);
|
||||
const { cond } = t0;
|
||||
const ref1 = useRef(1);
|
||||
const ref2 = useRef(2);
|
||||
const ref = cond ? ref1 : ref2;
|
||||
let t1;
|
||||
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
|
||||
const cb = () => ref.current;
|
||||
t1 = <Stringify cb={cb} shouldInvokeFns={true} />;
|
||||
$[0] = t1;
|
||||
} else {
|
||||
t1 = $[0];
|
||||
}
|
||||
return t1;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: Component,
|
||||
params: [{ cond: true }],
|
||||
sequentialRenders: [{ cond: true }, { cond: false }],
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
import {useRef} from 'react';
|
||||
import {Stringify} from 'shared-runtime';
|
||||
|
||||
/**
|
||||
* Bug: we're currently filtering out `ref.current` dependencies in
|
||||
* `propagateScopeDependencies:checkValidDependency`. This is incorrect.
|
||||
* Instead, we should always take a dependency on ref values (the outer box) as
|
||||
* they may be reactive. Pruning should be done in
|
||||
* `pruneNonReactiveDependencies`
|
||||
*
|
||||
* Found differences in evaluator results
|
||||
* Non-forget (expected):
|
||||
* (kind: ok)
|
||||
* <div>{"cb":{"kind":"Function","result":1},"shouldInvokeFns":true}</div>
|
||||
* <div>{"cb":{"kind":"Function","result":2},"shouldInvokeFns":true}</div>
|
||||
* Forget:
|
||||
* (kind: ok)
|
||||
* <div>{"cb":{"kind":"Function","result":1},"shouldInvokeFns":true}</div>
|
||||
* <div>{"cb":{"kind":"Function","result":1},"shouldInvokeFns":true}</div>
|
||||
*/
|
||||
function Component({cond}) {
|
||||
const ref1 = useRef(1);
|
||||
const ref2 = useRef(2);
|
||||
const ref = cond ? ref1 : ref2;
|
||||
const cb = () => ref.current;
|
||||
return <Stringify cb={cb} shouldInvokeFns={true} />;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: Component,
|
||||
params: [{cond: true}],
|
||||
sequentialRenders: [{cond: true}, {cond: false}],
|
||||
};
|
||||
@@ -0,0 +1,109 @@
|
||||
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
import {identity, mutate} from 'shared-runtime';
|
||||
|
||||
/**
|
||||
* Bug: copy of error.todo-object-expression-computed-key-modified-during-after-construction-sequence-expr
|
||||
* with the mutation hoisted to a named variable instead of being directly
|
||||
* inlined into the Object key.
|
||||
*
|
||||
* Found differences in evaluator results
|
||||
* Non-forget (expected):
|
||||
* (kind: ok) [{"[object Object]":[42]},{"wat0":"joe","wat1":"joe"}]
|
||||
* [{"[object Object]":[42]},{"wat0":"joe","wat1":"joe"}]
|
||||
* Forget:
|
||||
* (kind: ok) [{"[object Object]":[42]},{"wat0":"joe","wat1":"joe"}]
|
||||
* [{"[object Object]":[42]},{"wat0":"joe","wat1":"joe","wat2":"joe"}]
|
||||
*/
|
||||
function Component(props) {
|
||||
const key = {};
|
||||
const tmp = (mutate(key), key);
|
||||
const context = {
|
||||
// Here, `tmp` is frozen (as it's inferred to be a primitive/string)
|
||||
[tmp]: identity([props.value]),
|
||||
};
|
||||
mutate(key);
|
||||
return [context, key];
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: Component,
|
||||
params: [{value: 42}],
|
||||
sequentialRenders: [{value: 42}, {value: 42}],
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
## Code
|
||||
|
||||
```javascript
|
||||
import { c as _c } from "react/compiler-runtime";
|
||||
import { identity, mutate } from "shared-runtime";
|
||||
|
||||
/**
|
||||
* Bug: copy of error.todo-object-expression-computed-key-modified-during-after-construction-sequence-expr
|
||||
* with the mutation hoisted to a named variable instead of being directly
|
||||
* inlined into the Object key.
|
||||
*
|
||||
* Found differences in evaluator results
|
||||
* Non-forget (expected):
|
||||
* (kind: ok) [{"[object Object]":[42]},{"wat0":"joe","wat1":"joe"}]
|
||||
* [{"[object Object]":[42]},{"wat0":"joe","wat1":"joe"}]
|
||||
* Forget:
|
||||
* (kind: ok) [{"[object Object]":[42]},{"wat0":"joe","wat1":"joe"}]
|
||||
* [{"[object Object]":[42]},{"wat0":"joe","wat1":"joe","wat2":"joe"}]
|
||||
*/
|
||||
function Component(props) {
|
||||
const $ = _c(8);
|
||||
let key;
|
||||
let t0;
|
||||
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
|
||||
key = {};
|
||||
t0 = (mutate(key), key);
|
||||
$[0] = key;
|
||||
$[1] = t0;
|
||||
} else {
|
||||
key = $[0];
|
||||
t0 = $[1];
|
||||
}
|
||||
const tmp = t0;
|
||||
let t1;
|
||||
if ($[2] !== props.value) {
|
||||
t1 = identity([props.value]);
|
||||
$[2] = props.value;
|
||||
$[3] = t1;
|
||||
} else {
|
||||
t1 = $[3];
|
||||
}
|
||||
let t2;
|
||||
if ($[4] !== t1) {
|
||||
t2 = { [tmp]: t1 };
|
||||
$[4] = t1;
|
||||
$[5] = t2;
|
||||
} else {
|
||||
t2 = $[5];
|
||||
}
|
||||
const context = t2;
|
||||
|
||||
mutate(key);
|
||||
let t3;
|
||||
if ($[6] !== context) {
|
||||
t3 = [context, key];
|
||||
$[6] = context;
|
||||
$[7] = t3;
|
||||
} else {
|
||||
t3 = $[7];
|
||||
}
|
||||
return t3;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: Component,
|
||||
params: [{ value: 42 }],
|
||||
sequentialRenders: [{ value: 42 }, { value: 42 }],
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
import {identity, mutate} from 'shared-runtime';
|
||||
|
||||
/**
|
||||
* Bug: copy of error.todo-object-expression-computed-key-modified-during-after-construction-sequence-expr
|
||||
* with the mutation hoisted to a named variable instead of being directly
|
||||
* inlined into the Object key.
|
||||
*
|
||||
* Found differences in evaluator results
|
||||
* Non-forget (expected):
|
||||
* (kind: ok) [{"[object Object]":[42]},{"wat0":"joe","wat1":"joe"}]
|
||||
* [{"[object Object]":[42]},{"wat0":"joe","wat1":"joe"}]
|
||||
* Forget:
|
||||
* (kind: ok) [{"[object Object]":[42]},{"wat0":"joe","wat1":"joe"}]
|
||||
* [{"[object Object]":[42]},{"wat0":"joe","wat1":"joe","wat2":"joe"}]
|
||||
*/
|
||||
function Component(props) {
|
||||
const key = {};
|
||||
const tmp = (mutate(key), key);
|
||||
const context = {
|
||||
// Here, `tmp` is frozen (as it's inferred to be a primitive/string)
|
||||
[tmp]: identity([props.value]),
|
||||
};
|
||||
mutate(key);
|
||||
return [context, key];
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: Component,
|
||||
params: [{value: 42}],
|
||||
sequentialRenders: [{value: 42}, {value: 42}],
|
||||
};
|
||||
@@ -38,16 +38,24 @@ import { identity } from "shared-runtime";
|
||||
* try-catch block, as that might throw
|
||||
*/
|
||||
function useFoo(maybeNullObject) {
|
||||
const $ = _c(2);
|
||||
const $ = _c(4);
|
||||
let y;
|
||||
if ($[0] !== maybeNullObject.value.inner) {
|
||||
if ($[0] !== maybeNullObject) {
|
||||
y = [];
|
||||
try {
|
||||
y.push(identity(maybeNullObject.value.inner));
|
||||
let t0;
|
||||
if ($[2] !== maybeNullObject.value.inner) {
|
||||
t0 = identity(maybeNullObject.value.inner);
|
||||
$[2] = maybeNullObject.value.inner;
|
||||
$[3] = t0;
|
||||
} else {
|
||||
t0 = $[3];
|
||||
}
|
||||
y.push(t0);
|
||||
} catch {
|
||||
y.push("null");
|
||||
}
|
||||
$[0] = maybeNullObject.value.inner;
|
||||
$[0] = maybeNullObject;
|
||||
$[1] = y;
|
||||
} else {
|
||||
y = $[1];
|
||||
|
||||
@@ -32,7 +32,7 @@ import { mutate } from "shared-runtime";
|
||||
function component(foo, bar) {
|
||||
const $ = _c(3);
|
||||
let x;
|
||||
if ($[0] !== foo || $[1] !== bar) {
|
||||
if ($[0] !== bar || $[1] !== foo) {
|
||||
x = { foo };
|
||||
const y = { bar };
|
||||
|
||||
@@ -41,8 +41,8 @@ function component(foo, bar) {
|
||||
a.x = b;
|
||||
|
||||
mutate(y);
|
||||
$[0] = foo;
|
||||
$[1] = bar;
|
||||
$[0] = bar;
|
||||
$[1] = foo;
|
||||
$[2] = x;
|
||||
} else {
|
||||
x = $[2];
|
||||
|
||||
@@ -24,7 +24,7 @@ import { c as _c } from "react/compiler-runtime";
|
||||
function component(foo, bar) {
|
||||
const $ = _c(3);
|
||||
let x;
|
||||
if ($[0] !== foo || $[1] !== bar) {
|
||||
if ($[0] !== bar || $[1] !== foo) {
|
||||
x = { foo };
|
||||
const y = { bar };
|
||||
const f0 = function () {
|
||||
@@ -35,8 +35,8 @@ function component(foo, bar) {
|
||||
|
||||
f0();
|
||||
mutate(y);
|
||||
$[0] = foo;
|
||||
$[1] = bar;
|
||||
$[0] = bar;
|
||||
$[1] = foo;
|
||||
$[2] = x;
|
||||
} else {
|
||||
x = $[2];
|
||||
|
||||
@@ -32,7 +32,7 @@ const { mutate } = require("shared-runtime");
|
||||
function component(foo, bar) {
|
||||
const $ = _c(3);
|
||||
let x;
|
||||
if ($[0] !== foo || $[1] !== bar) {
|
||||
if ($[0] !== bar || $[1] !== foo) {
|
||||
x = { foo };
|
||||
const y = { bar };
|
||||
|
||||
@@ -41,8 +41,8 @@ function component(foo, bar) {
|
||||
a.x = b;
|
||||
|
||||
mutate(y);
|
||||
$[0] = foo;
|
||||
$[1] = bar;
|
||||
$[0] = bar;
|
||||
$[1] = foo;
|
||||
$[2] = x;
|
||||
} else {
|
||||
x = $[2];
|
||||
|
||||
@@ -24,7 +24,7 @@ import { c as _c } from "react/compiler-runtime";
|
||||
function component(foo, bar) {
|
||||
const $ = _c(3);
|
||||
let x;
|
||||
if ($[0] !== foo || $[1] !== bar) {
|
||||
if ($[0] !== bar || $[1] !== foo) {
|
||||
x = { foo };
|
||||
const y = { bar };
|
||||
const f0 = function () {
|
||||
@@ -35,8 +35,8 @@ function component(foo, bar) {
|
||||
|
||||
f0();
|
||||
mutate(y);
|
||||
$[0] = foo;
|
||||
$[1] = bar;
|
||||
$[0] = bar;
|
||||
$[1] = foo;
|
||||
$[2] = x;
|
||||
} else {
|
||||
x = $[2];
|
||||
|
||||
@@ -32,7 +32,7 @@ const { mutate } = require("shared-runtime");
|
||||
function component(foo, bar) {
|
||||
const $ = _c(3);
|
||||
let y;
|
||||
if ($[0] !== foo || $[1] !== bar) {
|
||||
if ($[0] !== bar || $[1] !== foo) {
|
||||
const x = { foo };
|
||||
y = { bar };
|
||||
|
||||
@@ -41,8 +41,8 @@ function component(foo, bar) {
|
||||
a.x = b;
|
||||
|
||||
mutate(y);
|
||||
$[0] = foo;
|
||||
$[1] = bar;
|
||||
$[0] = bar;
|
||||
$[1] = foo;
|
||||
$[2] = y;
|
||||
} else {
|
||||
y = $[2];
|
||||
|
||||
@@ -24,7 +24,7 @@ import { c as _c } from "react/compiler-runtime";
|
||||
function component(foo, bar) {
|
||||
const $ = _c(3);
|
||||
let y;
|
||||
if ($[0] !== foo || $[1] !== bar) {
|
||||
if ($[0] !== bar || $[1] !== foo) {
|
||||
const x = { foo };
|
||||
y = { bar };
|
||||
const f0 = function () {
|
||||
@@ -35,8 +35,8 @@ function component(foo, bar) {
|
||||
|
||||
f0();
|
||||
mutate(y);
|
||||
$[0] = foo;
|
||||
$[1] = bar;
|
||||
$[0] = bar;
|
||||
$[1] = foo;
|
||||
$[2] = y;
|
||||
} else {
|
||||
y = $[2];
|
||||
|
||||
@@ -32,7 +32,7 @@ const { mutate } = require("shared-runtime");
|
||||
function component(foo, bar) {
|
||||
const $ = _c(3);
|
||||
let y;
|
||||
if ($[0] !== foo || $[1] !== bar) {
|
||||
if ($[0] !== bar || $[1] !== foo) {
|
||||
const x = { foo };
|
||||
y = { bar };
|
||||
|
||||
@@ -41,8 +41,8 @@ function component(foo, bar) {
|
||||
a.x = b;
|
||||
|
||||
mutate(y);
|
||||
$[0] = foo;
|
||||
$[1] = bar;
|
||||
$[0] = bar;
|
||||
$[1] = foo;
|
||||
$[2] = y;
|
||||
} else {
|
||||
y = $[2];
|
||||
|
||||
@@ -24,7 +24,7 @@ import { c as _c } from "react/compiler-runtime";
|
||||
function component(foo, bar) {
|
||||
const $ = _c(3);
|
||||
let y;
|
||||
if ($[0] !== foo || $[1] !== bar) {
|
||||
if ($[0] !== bar || $[1] !== foo) {
|
||||
const x = { foo };
|
||||
y = { bar };
|
||||
const f0 = function () {
|
||||
@@ -35,8 +35,8 @@ function component(foo, bar) {
|
||||
|
||||
f0();
|
||||
mutate(y);
|
||||
$[0] = foo;
|
||||
$[1] = bar;
|
||||
$[0] = bar;
|
||||
$[1] = foo;
|
||||
$[2] = y;
|
||||
} else {
|
||||
y = $[2];
|
||||
|
||||
@@ -37,7 +37,7 @@ function component(a, b) {
|
||||
}
|
||||
const y = t0;
|
||||
let z;
|
||||
if ($[2] !== a || $[3] !== y.b) {
|
||||
if ($[2] !== a || $[3] !== y) {
|
||||
z = { a };
|
||||
const x = function () {
|
||||
z.a = 2;
|
||||
@@ -45,7 +45,7 @@ function component(a, b) {
|
||||
|
||||
x();
|
||||
$[2] = a;
|
||||
$[3] = y.b;
|
||||
$[3] = y;
|
||||
$[4] = z;
|
||||
} else {
|
||||
z = $[4];
|
||||
|
||||
@@ -46,10 +46,10 @@ function component(t0) {
|
||||
}
|
||||
const hide = t2;
|
||||
let t3;
|
||||
if ($[4] !== poke || $[5] !== hide) {
|
||||
if ($[4] !== hide || $[5] !== poke) {
|
||||
t3 = <Foo poke={poke} hide={hide} />;
|
||||
$[4] = poke;
|
||||
$[5] = hide;
|
||||
$[4] = hide;
|
||||
$[5] = poke;
|
||||
$[6] = t3;
|
||||
} else {
|
||||
t3 = $[6];
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
// @enableEmitFreeze @instrumentForget
|
||||
// @enableEmitFreeze @enableEmitInstrumentForget
|
||||
|
||||
function useFoo(props) {
|
||||
return foo(props.x);
|
||||
@@ -18,7 +18,7 @@ import {
|
||||
shouldInstrument,
|
||||
makeReadOnly,
|
||||
} from "react-compiler-runtime";
|
||||
import { c as _c } from "react/compiler-runtime"; // @enableEmitFreeze @instrumentForget
|
||||
import { c as _c } from "react/compiler-runtime"; // @enableEmitFreeze @enableEmitInstrumentForget
|
||||
|
||||
function useFoo(props) {
|
||||
if (__DEV__ && shouldInstrument)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// @enableEmitFreeze @instrumentForget
|
||||
// @enableEmitFreeze @enableEmitInstrumentForget
|
||||
|
||||
function useFoo(props) {
|
||||
return foo(props.x);
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
// @instrumentForget @compilationMode(annotation) @gating
|
||||
// @enableEmitInstrumentForget @compilationMode(annotation) @gating
|
||||
|
||||
function Bar(props) {
|
||||
'use forget';
|
||||
@@ -25,7 +25,7 @@ function Foo(props) {
|
||||
```javascript
|
||||
import { isForgetEnabled_Fixtures } from "ReactForgetFeatureFlag";
|
||||
import { useRenderCounter, shouldInstrument } from "react-compiler-runtime";
|
||||
import { c as _c } from "react/compiler-runtime"; // @instrumentForget @compilationMode(annotation) @gating
|
||||
import { c as _c } from "react/compiler-runtime"; // @enableEmitInstrumentForget @compilationMode(annotation) @gating
|
||||
const Bar = isForgetEnabled_Fixtures()
|
||||
? function Bar(props) {
|
||||
"use forget";
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// @instrumentForget @compilationMode(annotation) @gating
|
||||
// @enableEmitInstrumentForget @compilationMode(annotation) @gating
|
||||
|
||||
function Bar(props) {
|
||||
'use forget';
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
// @instrumentForget @compilationMode(annotation)
|
||||
// @enableEmitInstrumentForget @compilationMode(annotation)
|
||||
|
||||
function Bar(props) {
|
||||
'use forget';
|
||||
@@ -24,7 +24,7 @@ function Foo(props) {
|
||||
|
||||
```javascript
|
||||
import { useRenderCounter, shouldInstrument } from "react-compiler-runtime";
|
||||
import { c as _c } from "react/compiler-runtime"; // @instrumentForget @compilationMode(annotation)
|
||||
import { c as _c } from "react/compiler-runtime"; // @enableEmitInstrumentForget @compilationMode(annotation)
|
||||
|
||||
function Bar(props) {
|
||||
"use forget";
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// @instrumentForget @compilationMode(annotation)
|
||||
// @enableEmitInstrumentForget @compilationMode(annotation)
|
||||
|
||||
function Bar(props) {
|
||||
'use forget';
|
||||
|
||||
@@ -46,7 +46,7 @@ function Component(props) {
|
||||
const items = props.items;
|
||||
const maxItems = props.maxItems;
|
||||
let renderedItems;
|
||||
if ($[0] !== maxItems || $[1] !== items) {
|
||||
if ($[0] !== items || $[1] !== maxItems) {
|
||||
renderedItems = [];
|
||||
const seen = new Set();
|
||||
const max = Math.max(0, maxItems);
|
||||
@@ -62,8 +62,8 @@ function Component(props) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
$[0] = maxItems;
|
||||
$[1] = items;
|
||||
$[0] = items;
|
||||
$[1] = maxItems;
|
||||
$[2] = renderedItems;
|
||||
} else {
|
||||
renderedItems = $[2];
|
||||
@@ -79,15 +79,15 @@ function Component(props) {
|
||||
t0 = $[4];
|
||||
}
|
||||
let t1;
|
||||
if ($[5] !== t0 || $[6] !== renderedItems) {
|
||||
if ($[5] !== renderedItems || $[6] !== t0) {
|
||||
t1 = (
|
||||
<div>
|
||||
{t0}
|
||||
{renderedItems}
|
||||
</div>
|
||||
);
|
||||
$[5] = t0;
|
||||
$[6] = renderedItems;
|
||||
$[5] = renderedItems;
|
||||
$[6] = t0;
|
||||
$[7] = t1;
|
||||
} else {
|
||||
t1 = $[7];
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user