Merge e88b05e387 into sapling-pr-archive-mofeiZ

This commit is contained in:
mofeiZ
2024-11-05 15:15:46 -05:00
committed by GitHub
10 changed files with 88 additions and 101 deletions
@@ -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
@@ -239,7 +239,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.
@@ -330,9 +330,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
@@ -416,7 +416,7 @@ const EnvironmentConfigSchema = z.object({
* }
*
*/
enableEmitInstrumentForget: InstrumentationSchema.nullish(),
enableEmitInstrumentForget: InstrumentationSchema.nullable().default(null),
// Enable validation of mutable ranges
assertValidMutableRanges: z.boolean().default(false),
@@ -455,8 +455,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
@@ -494,7 +492,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
@@ -534,7 +533,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
@@ -556,11 +555,56 @@ 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>;
/**
* 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 testConfigValues: 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 parseConfigPragma(pragma: string): EnvironmentConfig {
const maybeConfig: any = {};
// Get the defaults to programmatically check for boolean properties
@@ -571,21 +615,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 testConfigValues) {
maybeConfig[key] =
testConfigValues[key as keyof PartialEnvironmentConfig];
continue;
}
@@ -600,7 +635,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;
@@ -611,11 +645,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);
@@ -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';
@@ -2,7 +2,7 @@
## Input
```javascript
// @enableInlineJsxTransform
// @inlineJsxTransform
function Parent({children, a: _a, b: _b, c: _c, ref}) {
return <div ref={ref}>{children}</div>;
@@ -76,7 +76,7 @@ export const FIXTURE_ENTRYPOINT = {
## Code
```javascript
import { c as _c2 } from "react/compiler-runtime"; // @enableInlineJsxTransform
import { c as _c2 } from "react/compiler-runtime"; // @inlineJsxTransform
function Parent(t0) {
const $ = _c2(2);
@@ -1,4 +1,4 @@
// @enableInlineJsxTransform
// @inlineJsxTransform
function Parent({children, a: _a, b: _b, c: _c, ref}) {
return <div ref={ref}>{children}</div>;
+13 -59
View File
@@ -21,7 +21,6 @@ import type {
} from 'babel-plugin-react-compiler/src/Entrypoint';
import type {Effect, ValueKind} from 'babel-plugin-react-compiler/src/HIR';
import type {
EnvironmentConfig,
Macro,
MacroMethod,
parseConfigPragma as ParseConfigPragma,
@@ -37,6 +36,11 @@ export function parseLanguage(source: string): 'flow' | 'typescript' {
return source.indexOf('@flow') !== -1 ? 'flow' : 'typescript';
}
/**
* Parse react compiler plugin + environment options from test fixture. Note
* that although this primarily uses `Environment:parseConfigPragma`, it also
* has test fixture specific (i.e. not applicable to playground) parsing logic.
*/
function makePluginOptions(
firstLine: string,
parseConfigPragmaFn: typeof ParseConfigPragma,
@@ -44,15 +48,11 @@ function makePluginOptions(
ValueKindEnum: typeof ValueKind,
): [PluginOptions, Array<{filename: string | null; event: LoggerEvent}>] {
let gating = null;
let enableEmitInstrumentForget = null;
let enableEmitFreeze = null;
let enableEmitHookGuards = null;
let compilationMode: CompilationMode = 'all';
let panicThreshold: PanicThresholdOptions = 'all_errors';
let hookPattern: string | null = null;
// TODO(@mofeiZ) rewrite snap fixtures to @validatePreserveExistingMemo:false
let validatePreserveExistingMemoizationGuarantees = false;
let enableChangeDetectionForDebugging = null;
let customMacros: null | Array<Macro> = null;
let validateBlocklistedImports = null;
let target = '19' as const;
@@ -78,31 +78,6 @@ function makePluginOptions(
importSpecifierName: 'isForgetEnabled_Fixtures',
};
}
if (firstLine.includes('@instrumentForget')) {
enableEmitInstrumentForget = {
fn: {
source: 'react-compiler-runtime',
importSpecifierName: 'useRenderCounter',
},
gating: {
source: 'react-compiler-runtime',
importSpecifierName: 'shouldInstrument',
},
globalGating: '__DEV__',
};
}
if (firstLine.includes('@enableEmitFreeze')) {
enableEmitFreeze = {
source: 'react-compiler-runtime',
importSpecifierName: 'makeReadOnly',
};
}
if (firstLine.includes('@enableEmitHookGuards')) {
enableEmitHookGuards = {
source: 'react-compiler-runtime',
importSpecifierName: '$dispatcherGuard',
};
}
const targetMatch = /@target="([^"]+)"/.exec(firstLine);
if (targetMatch) {
@@ -132,16 +107,18 @@ function makePluginOptions(
ignoreUseNoForget = true;
}
/**
* Snap currently runs all fixtures without `validatePreserveExistingMemo` as
* most fixtures are interested in compilation output, not whether the
* compiler was able to preserve existing memo.
*
* TODO: flip the default. `useMemo` is rare in test fixtures -- fixtures that
* use useMemo should be explicit about whether this flag is enabled
*/
if (firstLine.includes('@validatePreserveExistingMemoizationGuarantees')) {
validatePreserveExistingMemoizationGuarantees = true;
}
if (firstLine.includes('@enableChangeDetectionForDebugging')) {
enableChangeDetectionForDebugging = {
source: 'react-compiler-runtime',
importSpecifierName: '$structuralCheck',
};
}
const hookPatternMatch = /@hookPattern:"([^"]+)"/.exec(firstLine);
if (
hookPatternMatch &&
@@ -197,22 +174,6 @@ function makePluginOptions(
.filter(s => s.length > 0);
}
let lowerContextAccess = null;
if (firstLine.includes('@lowerContextAccess')) {
lowerContextAccess = {
source: 'react-compiler-runtime',
importSpecifierName: 'useContext_withSelector',
};
}
let inlineJsxTransform: EnvironmentConfig['inlineJsxTransform'] = null;
if (firstLine.includes('@enableInlineJsxTransform')) {
inlineJsxTransform = {
elementSymbol: 'react.transitional.element',
globalDevVar: 'DEV',
};
}
let logs: Array<{filename: string | null; event: LoggerEvent}> = [];
let logger: Logger | null = null;
if (firstLine.includes('@logger')) {
@@ -232,17 +193,10 @@ function makePluginOptions(
ValueKindEnum,
}),
customMacros,
enableEmitFreeze,
enableEmitInstrumentForget,
enableEmitHookGuards,
assertValidMutableRanges: true,
enableSharedRuntime__testonly: true,
hookPattern,
validatePreserveExistingMemoizationGuarantees,
enableChangeDetectionForDebugging,
lowerContextAccess,
validateBlocklistedImports,
inlineJsxTransform,
},
compilationMode,
logger,