mirror of
https://github.com/facebook/react.git
synced 2025-11-01 09:12:30 +00:00
[be] Improve feature flags setup
Updates `Environment` to store all feature flags on a single `config` object. We now also define an object with all the default config values, and use this to populate defaults for any missing values in the user-provided config.
This commit is contained in:
@@ -7,7 +7,7 @@
|
||||
|
||||
import * as t from "@babel/types";
|
||||
import { CompilerErrorDetailOptions } from "../CompilerError";
|
||||
import { EnvironmentConfig } from "../HIR/Environment";
|
||||
import { PartialEnvironmentConfig } from "../HIR/Environment";
|
||||
|
||||
export type ExternalFunction = {
|
||||
/**
|
||||
@@ -39,7 +39,7 @@ export type PanicThresholdOptions =
|
||||
| "NONE";
|
||||
|
||||
export type PluginOptions = {
|
||||
environment: EnvironmentConfig | null;
|
||||
environment: PartialEnvironmentConfig | null;
|
||||
|
||||
logger: Logger | null;
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ import {
|
||||
lower,
|
||||
mergeConsecutiveBlocks,
|
||||
} from "../HIR";
|
||||
import { Environment, EnvironmentConfig } from "../HIR/Environment";
|
||||
import { Environment, PartialEnvironmentConfig } from "../HIR/Environment";
|
||||
import { findContextIdentifiers } from "../HIR/FindContextIdentifiers";
|
||||
import {
|
||||
analyseFunctions,
|
||||
@@ -82,7 +82,7 @@ export function* run(
|
||||
func: NodePath<
|
||||
t.FunctionDeclaration | t.ArrowFunctionExpression | t.FunctionExpression
|
||||
>,
|
||||
config?: EnvironmentConfig | null
|
||||
config?: PartialEnvironmentConfig | null
|
||||
): Generator<CompilerPipelineValue, CodegenFunction> {
|
||||
const contextIdentifiers = findContextIdentifiers(func);
|
||||
const env = new Environment(config ?? null, contextIdentifiers);
|
||||
@@ -106,7 +106,7 @@ function* runWithEnvironment(
|
||||
pruneMaybeThrows(hir);
|
||||
yield log({ kind: "hir", name: "PruneMaybeThrows", value: hir });
|
||||
|
||||
if (env.inlineUseMemo) {
|
||||
if (env.config.inlineUseMemo) {
|
||||
inlineUseMemo(hir);
|
||||
yield log({ kind: "hir", name: "RewriteUseMemo", value: hir });
|
||||
}
|
||||
@@ -131,7 +131,7 @@ function* runWithEnvironment(
|
||||
inferTypes(hir);
|
||||
yield log({ kind: "hir", name: "InferTypes", value: hir });
|
||||
|
||||
if (env.validateHooksUsage) {
|
||||
if (env.config.validateHooksUsage) {
|
||||
validateHooksUsage(hir);
|
||||
const conditionalHooksResult = validateUnconditionalHooks(hir).unwrap();
|
||||
yield log({
|
||||
@@ -150,7 +150,7 @@ function* runWithEnvironment(
|
||||
inferReferenceEffects(hir);
|
||||
yield log({ kind: "hir", name: "InferReferenceEffects", value: hir });
|
||||
|
||||
if (env.validateFrozenLambdas) {
|
||||
if (env.config.validateFrozenLambdas) {
|
||||
validateFrozenLambdas(hir);
|
||||
}
|
||||
|
||||
@@ -164,15 +164,15 @@ function* runWithEnvironment(
|
||||
inferMutableRanges(hir);
|
||||
yield log({ kind: "hir", name: "InferMutableRanges", value: hir });
|
||||
|
||||
if (env.assertValidMutableRanges) {
|
||||
if (env.config.assertValidMutableRanges) {
|
||||
assertValidMutableRanges(hir);
|
||||
}
|
||||
|
||||
if (env.validateRefAccessDuringRender) {
|
||||
if (env.config.validateRefAccessDuringRender) {
|
||||
validateNoRefAccessInRender(hir);
|
||||
}
|
||||
|
||||
if (env.validateNoSetStateInRender) {
|
||||
if (env.config.validateNoSetStateInRender) {
|
||||
const noSetStateInRenderResult = validateNoSetStateInRender(hir).unwrap();
|
||||
yield log({
|
||||
kind: "debug",
|
||||
@@ -222,7 +222,7 @@ function* runWithEnvironment(
|
||||
value: reactiveFunction,
|
||||
});
|
||||
|
||||
if (env.disableAllMemoization) {
|
||||
if (env.config.disableAllMemoization) {
|
||||
pruneAllReactiveScopes(reactiveFunction);
|
||||
yield log({
|
||||
kind: "reactive",
|
||||
@@ -259,8 +259,8 @@ function* runWithEnvironment(
|
||||
value: reactiveFunction,
|
||||
});
|
||||
|
||||
let memoizeJsxElements = env.memoizeJsxElements;
|
||||
if (env.enableForest) {
|
||||
let memoizeJsxElements = env.config.memoizeJsxElements;
|
||||
if (env.config.enableForest) {
|
||||
memoizeJsxElements = false;
|
||||
}
|
||||
pruneNonEscapingScopes(reactiveFunction, { memoizeJsxElements });
|
||||
@@ -284,7 +284,7 @@ function* runWithEnvironment(
|
||||
value: reactiveFunction,
|
||||
});
|
||||
|
||||
if (env.enableMergeConsecutiveScopes) {
|
||||
if (env.config.enableMergeConsecutiveScopes) {
|
||||
mergeConsecutiveScopes(reactiveFunction);
|
||||
yield log({
|
||||
kind: "reactive",
|
||||
@@ -293,7 +293,7 @@ function* runWithEnvironment(
|
||||
});
|
||||
}
|
||||
|
||||
if (env.enableForest) {
|
||||
if (env.config.enableForest) {
|
||||
yield* lowerToForest(reactiveFunction);
|
||||
}
|
||||
|
||||
@@ -349,7 +349,7 @@ export function compileFn(
|
||||
func: NodePath<
|
||||
t.FunctionDeclaration | t.ArrowFunctionExpression | t.FunctionExpression
|
||||
>,
|
||||
options?: Partial<EnvironmentConfig> | null
|
||||
options?: Partial<PartialEnvironmentConfig> | null
|
||||
): CodegenFunction {
|
||||
let generator = run(func, options);
|
||||
while (true) {
|
||||
|
||||
@@ -1436,7 +1436,7 @@ function lowerExpression(
|
||||
elements.push({
|
||||
kind: "Hole",
|
||||
});
|
||||
if (builder.environment.bailoutOnHoleyArrays) {
|
||||
if (builder.environment.config.bailoutOnHoleyArrays) {
|
||||
builder.errors.push({
|
||||
reason: `(BuildHIR::lower) Fix babel holey array backward compatibility.`,
|
||||
severity: ErrorSeverity.Todo,
|
||||
|
||||
@@ -84,8 +84,9 @@ export type Hook = {
|
||||
// i.e.
|
||||
// missing required shapes (BuiltInArray for [] and BuiltInObject for {})
|
||||
// missing some recursive Object / Function shapeIds
|
||||
export type EnvironmentConfig = Partial<{
|
||||
customHooks: Map<string, Hook>;
|
||||
|
||||
export type CompleteEnvironmentConfig = {
|
||||
customHooks: Map<string, Hook> | null;
|
||||
|
||||
// 🌲
|
||||
enableForest: boolean;
|
||||
@@ -243,42 +244,59 @@ export type EnvironmentConfig = Partial<{
|
||||
* https://github.com/babel/babel/pull/10917/files#diff-19b555d2f3904c206af406540d9df200b1e16befedb83ff39ebfcbd876f7fa8aL52-R56
|
||||
*/
|
||||
bailoutOnHoleyArrays: boolean;
|
||||
}>;
|
||||
};
|
||||
|
||||
const DEFAULT_ENVIRONMENT_CONFIG: CompleteEnvironmentConfig = {
|
||||
customHooks: null,
|
||||
|
||||
enableTreatHooksAsFunctions: true,
|
||||
memoizeJsxElements: true,
|
||||
|
||||
assertValidMutableRanges: false,
|
||||
bailoutOnHoleyArrays: false,
|
||||
disableAllMemoization: false,
|
||||
enableAssumeHooksFollowRulesOfReact: false,
|
||||
enableEmitFreeze: null,
|
||||
enableForest: false,
|
||||
enableFunctionCallSignatureOptimizations: false,
|
||||
enableMergeConsecutiveScopes: false,
|
||||
enableNoAliasOptimizations: false,
|
||||
inlineUseMemo: false,
|
||||
|
||||
validateFrozenLambdas: false,
|
||||
validateHooksUsage: false,
|
||||
validateNoSetStateInRender: false,
|
||||
validateRefAccessDuringRender: false,
|
||||
};
|
||||
|
||||
export type PartialEnvironmentConfig = Partial<CompleteEnvironmentConfig>;
|
||||
|
||||
export class Environment {
|
||||
#globals: GlobalRegistry;
|
||||
#shapes: ShapeRegistry;
|
||||
#nextIdentifer: number = 0;
|
||||
#nextBlock: number = 0;
|
||||
validateHooksUsage: boolean;
|
||||
validateRefAccessDuringRender: boolean;
|
||||
validateFrozenLambdas: boolean;
|
||||
validateNoSetStateInRender: boolean;
|
||||
enableFunctionCallSignatureOptimizations: boolean;
|
||||
enableAssumeHooksFollowRulesOfReact: boolean;
|
||||
enableTreatHooksAsFunctions: boolean;
|
||||
enableNoAliasOptimizations: boolean;
|
||||
inlineUseMemo: boolean;
|
||||
memoizeJsxElements: boolean;
|
||||
disableAllMemoization: boolean;
|
||||
enableEmitFreeze: ExternalFunction | null;
|
||||
enableMergeConsecutiveScopes: boolean;
|
||||
assertValidMutableRanges: boolean;
|
||||
bailoutOnHoleyArrays: boolean;
|
||||
enableForest: boolean;
|
||||
config: CompleteEnvironmentConfig;
|
||||
|
||||
#contextIdentifiers: Set<t.Identifier>;
|
||||
#hoistedIdentifiers: Set<t.Identifier>;
|
||||
|
||||
constructor(
|
||||
config: EnvironmentConfig | null,
|
||||
partialConfig: PartialEnvironmentConfig | null,
|
||||
contextIdentifiers: Set<t.Identifier>
|
||||
) {
|
||||
this.#shapes = new Map(DEFAULT_SHAPES);
|
||||
const config: CompleteEnvironmentConfig = { ...DEFAULT_ENVIRONMENT_CONFIG };
|
||||
for (const rawKey in DEFAULT_ENVIRONMENT_CONFIG) {
|
||||
const key = rawKey as keyof CompleteEnvironmentConfig;
|
||||
const value = partialConfig?.[key] ?? DEFAULT_ENVIRONMENT_CONFIG[key];
|
||||
config[key] = value as any;
|
||||
}
|
||||
this.config = config;
|
||||
|
||||
if (config?.customHooks) {
|
||||
if (this.config.customHooks != null && this.config.customHooks.size > 0) {
|
||||
this.#globals = new Map(DEFAULT_GLOBALS);
|
||||
for (const [hookName, hook] of config.customHooks) {
|
||||
for (const [hookName, hook] of this.config.customHooks) {
|
||||
CompilerError.invariant(!this.#globals.has(hookName), {
|
||||
reason: `[Globals] Found existing definition in global registry for custom hook ${hookName}`,
|
||||
description: null,
|
||||
@@ -303,29 +321,6 @@ export class Environment {
|
||||
} else {
|
||||
this.#globals = DEFAULT_GLOBALS;
|
||||
}
|
||||
this.validateHooksUsage = config?.validateHooksUsage ?? false;
|
||||
this.validateRefAccessDuringRender =
|
||||
config?.validateRefAccessDuringRender ?? false;
|
||||
this.validateFrozenLambdas = config?.validateFrozenLambdas ?? false;
|
||||
this.enableFunctionCallSignatureOptimizations =
|
||||
config?.enableFunctionCallSignatureOptimizations ?? false;
|
||||
this.enableNoAliasOptimizations =
|
||||
config?.enableNoAliasOptimizations ?? false;
|
||||
this.enableAssumeHooksFollowRulesOfReact =
|
||||
config?.enableAssumeHooksFollowRulesOfReact ?? false;
|
||||
this.enableTreatHooksAsFunctions =
|
||||
config?.enableTreatHooksAsFunctions ?? true;
|
||||
this.disableAllMemoization = config?.disableAllMemoization ?? false;
|
||||
this.enableEmitFreeze = config?.enableEmitFreeze ?? null;
|
||||
this.enableMergeConsecutiveScopes =
|
||||
config?.enableMergeConsecutiveScopes ?? false;
|
||||
this.assertValidMutableRanges = config?.assertValidMutableRanges ?? false;
|
||||
this.validateNoSetStateInRender =
|
||||
config?.validateNoSetStateInRender ?? false;
|
||||
this.inlineUseMemo = config?.inlineUseMemo ?? false;
|
||||
this.memoizeJsxElements = config?.memoizeJsxElements ?? true;
|
||||
this.bailoutOnHoleyArrays = config?.bailoutOnHoleyArrays ?? false;
|
||||
this.enableForest = config?.enableForest ?? false;
|
||||
|
||||
this.#contextIdentifiers = contextIdentifiers;
|
||||
this.#hoistedIdentifiers = new Set();
|
||||
@@ -412,7 +407,7 @@ export class Environment {
|
||||
}
|
||||
|
||||
#getCustomHookType(): Global {
|
||||
if (this.enableAssumeHooksFollowRulesOfReact) {
|
||||
if (this.config.enableAssumeHooksFollowRulesOfReact) {
|
||||
return DefaultNonmutatingHook;
|
||||
} else {
|
||||
return DefaultMutatingHook;
|
||||
|
||||
@@ -747,7 +747,7 @@ function inferBlock(
|
||||
instrValue.callee.identifier.type
|
||||
);
|
||||
signature =
|
||||
env.enableFunctionCallSignatureOptimizations ||
|
||||
env.config.enableFunctionCallSignatureOptimizations ||
|
||||
signature?.hookKind != null
|
||||
? signature
|
||||
: null;
|
||||
@@ -755,7 +755,7 @@ function inferBlock(
|
||||
if (
|
||||
signature &&
|
||||
signature.hookKind != null &&
|
||||
!env.enableTreatHooksAsFunctions
|
||||
!env.config.enableTreatHooksAsFunctions
|
||||
) {
|
||||
effectKind = signature.restParam;
|
||||
valueKind = signature.returnValueKind;
|
||||
|
||||
+3
-3
@@ -184,12 +184,12 @@ function codegenBlock(cx: Context, block: ReactiveBlock): t.BlockStatement {
|
||||
}
|
||||
|
||||
function wrapCacheDep(cx: Context, value: t.Expression): t.Expression {
|
||||
if (cx.env.enableEmitFreeze != null) {
|
||||
if (cx.env.config.enableEmitFreeze != null) {
|
||||
// The import declaration for emitFreeze is inserted in the Babel plugin
|
||||
return t.conditionalExpression(
|
||||
t.identifier("__DEV__"),
|
||||
t.callExpression(
|
||||
t.identifier(cx.env.enableEmitFreeze.importSpecifierName),
|
||||
t.identifier(cx.env.config.enableEmitFreeze.importSpecifierName),
|
||||
[value, t.stringLiteral(cx.fnName)]
|
||||
),
|
||||
value
|
||||
@@ -383,7 +383,7 @@ function codegenReactiveScope(
|
||||
scope: ReactiveScope,
|
||||
block: ReactiveBlock
|
||||
): void {
|
||||
if (cx.env.enableForest) {
|
||||
if (cx.env.config.enableForest) {
|
||||
codegenSignalBlockForReactiveScope(cx, statements, scope, block);
|
||||
} else {
|
||||
codegenMemoBlockForReactiveScope(cx, statements, scope, block);
|
||||
|
||||
+1
-1
@@ -250,7 +250,7 @@ function mayAllocate(env: Environment, instruction: Instruction): boolean {
|
||||
}
|
||||
case "CallExpression":
|
||||
case "MethodCall": {
|
||||
if (env.enableFunctionCallSignatureOptimizations) {
|
||||
if (env.config.enableFunctionCallSignatureOptimizations) {
|
||||
return instruction.lvalue.identifier.type.kind !== "Primitive";
|
||||
}
|
||||
return true;
|
||||
|
||||
+3
-3
@@ -611,7 +611,7 @@ function computeMemoizationInputs(
|
||||
};
|
||||
}
|
||||
case "CallExpression": {
|
||||
const signature = env.enableNoAliasOptimizations
|
||||
const signature = env.config.enableNoAliasOptimizations
|
||||
? getFunctionCallSignature(env, value.callee.identifier.type)
|
||||
: null;
|
||||
const operands = [...eachReactiveValueOperand(value)];
|
||||
@@ -636,7 +636,7 @@ function computeMemoizationInputs(
|
||||
};
|
||||
}
|
||||
case "MethodCall": {
|
||||
const signature = env.enableNoAliasOptimizations
|
||||
const signature = env.config.enableNoAliasOptimizations
|
||||
? getFunctionCallSignature(env, value.property.identifier.type)
|
||||
: null;
|
||||
const operands = [...eachReactiveValueOperand(value)];
|
||||
@@ -808,7 +808,7 @@ class CollectDependenciesVisitor extends ReactiveFunctionVisitor<State> {
|
||||
} else if (instruction.value.kind === "CallExpression") {
|
||||
const callee = instruction.value.callee;
|
||||
if (getHookKind(state.env, callee.identifier) != null) {
|
||||
const signature = this.env.enableNoAliasOptimizations
|
||||
const signature = this.env.config.enableNoAliasOptimizations
|
||||
? getFunctionCallSignature(
|
||||
this.env,
|
||||
instruction.value.callee.identifier.type
|
||||
|
||||
Reference in New Issue
Block a user