mirror of
https://github.com/facebook/react.git
synced 2026-02-21 19:31:52 +00:00
[compiler] Remove local CompilerError accumulators, emit directly to env.recordError()
Removes unnecessary indirection in 17 compiler passes that previously accumulated errors in a local `CompilerError` instance before flushing them to `env.recordErrors()` at the end of each pass. Errors are now emitted directly via `env.recordError()` as they're discovered. For passes with recursive error-detection patterns (ValidateNoRefAccessInRender, ValidateNoSetStateInRender), the internal accumulator is kept but flushed via individual `recordError()` calls. For InferMutationAliasingRanges, a `shouldRecordErrors` flag preserves the conditional suppression logic. For TransformFire, the throw-based error propagation is replaced with direct recording plus an early-exit check in Pipeline.ts.
This commit is contained in:
@@ -220,6 +220,9 @@ function runWithEnvironment(
|
|||||||
if (env.config.enableFire) {
|
if (env.config.enableFire) {
|
||||||
transformFire(hir);
|
transformFire(hir);
|
||||||
log({kind: 'hir', name: 'TransformFire', value: hir});
|
log({kind: 'hir', name: 'TransformFire', value: hir});
|
||||||
|
if (env.hasErrors()) {
|
||||||
|
return Err(env.aggregateErrors());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (env.config.lowerContextAccess) {
|
if (env.config.lowerContextAccess) {
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -7,7 +7,12 @@
|
|||||||
|
|
||||||
import {Binding, NodePath} from '@babel/traverse';
|
import {Binding, NodePath} from '@babel/traverse';
|
||||||
import * as t from '@babel/types';
|
import * as t from '@babel/types';
|
||||||
import {CompilerError, ErrorCategory} from '../CompilerError';
|
import {
|
||||||
|
CompilerError,
|
||||||
|
CompilerDiagnostic,
|
||||||
|
CompilerErrorDetail,
|
||||||
|
ErrorCategory,
|
||||||
|
} from '../CompilerError';
|
||||||
import {Environment} from './Environment';
|
import {Environment} from './Environment';
|
||||||
import {
|
import {
|
||||||
BasicBlock,
|
BasicBlock,
|
||||||
@@ -110,7 +115,6 @@ export default class HIRBuilder {
|
|||||||
#bindings: Bindings;
|
#bindings: Bindings;
|
||||||
#env: Environment;
|
#env: Environment;
|
||||||
#exceptionHandlerStack: Array<BlockId> = [];
|
#exceptionHandlerStack: Array<BlockId> = [];
|
||||||
errors: CompilerError = new CompilerError();
|
|
||||||
/**
|
/**
|
||||||
* Traversal context: counts the number of `fbt` tag parents
|
* Traversal context: counts the number of `fbt` tag parents
|
||||||
* of the current babel node.
|
* of the current babel node.
|
||||||
@@ -148,6 +152,10 @@ export default class HIRBuilder {
|
|||||||
this.#current = newBlock(this.#entry, options?.entryBlockKind ?? 'block');
|
this.#current = newBlock(this.#entry, options?.entryBlockKind ?? 'block');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
recordError(error: CompilerDiagnostic | CompilerErrorDetail): void {
|
||||||
|
this.#env.recordError(error);
|
||||||
|
}
|
||||||
|
|
||||||
currentBlockKind(): BlockKind {
|
currentBlockKind(): BlockKind {
|
||||||
return this.#current.kind;
|
return this.#current.kind;
|
||||||
}
|
}
|
||||||
@@ -308,24 +316,28 @@ export default class HIRBuilder {
|
|||||||
|
|
||||||
resolveBinding(node: t.Identifier): Identifier {
|
resolveBinding(node: t.Identifier): Identifier {
|
||||||
if (node.name === 'fbt') {
|
if (node.name === 'fbt') {
|
||||||
this.errors.push({
|
this.recordError(
|
||||||
category: ErrorCategory.Todo,
|
new CompilerErrorDetail({
|
||||||
reason: 'Support local variables named `fbt`',
|
category: ErrorCategory.Todo,
|
||||||
description:
|
reason: 'Support local variables named `fbt`',
|
||||||
'Local variables named `fbt` may conflict with the fbt plugin and are not yet supported',
|
description:
|
||||||
loc: node.loc ?? GeneratedSource,
|
'Local variables named `fbt` may conflict with the fbt plugin and are not yet supported',
|
||||||
suggestions: null,
|
loc: node.loc ?? GeneratedSource,
|
||||||
});
|
suggestions: null,
|
||||||
|
}),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
if (node.name === 'this') {
|
if (node.name === 'this') {
|
||||||
this.errors.push({
|
this.recordError(
|
||||||
category: ErrorCategory.UnsupportedSyntax,
|
new CompilerErrorDetail({
|
||||||
reason: '`this` is not supported syntax',
|
category: ErrorCategory.UnsupportedSyntax,
|
||||||
description:
|
reason: '`this` is not supported syntax',
|
||||||
'React Compiler does not support compiling functions that use `this`',
|
description:
|
||||||
loc: node.loc ?? GeneratedSource,
|
'React Compiler does not support compiling functions that use `this`',
|
||||||
suggestions: null,
|
loc: node.loc ?? GeneratedSource,
|
||||||
});
|
suggestions: null,
|
||||||
|
}),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
const originalName = node.name;
|
const originalName = node.name;
|
||||||
let name = originalName;
|
let name = originalName;
|
||||||
@@ -371,13 +383,15 @@ export default class HIRBuilder {
|
|||||||
instr => instr.value.kind === 'FunctionExpression',
|
instr => instr.value.kind === 'FunctionExpression',
|
||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
this.errors.push({
|
this.recordError(
|
||||||
reason: `Support functions with unreachable code that may contain hoisted declarations`,
|
new CompilerErrorDetail({
|
||||||
loc: block.instructions[0]?.loc ?? block.terminal.loc,
|
reason: `Support functions with unreachable code that may contain hoisted declarations`,
|
||||||
description: null,
|
loc: block.instructions[0]?.loc ?? block.terminal.loc,
|
||||||
suggestions: null,
|
description: null,
|
||||||
category: ErrorCategory.Todo,
|
suggestions: null,
|
||||||
});
|
category: ErrorCategory.Todo,
|
||||||
|
}),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ir.blocks = rpoBlocks;
|
ir.blocks = rpoBlocks;
|
||||||
|
|||||||
@@ -293,7 +293,7 @@ function extractManualMemoizationArgs(
|
|||||||
instr: TInstruction<CallExpression> | TInstruction<MethodCall>,
|
instr: TInstruction<CallExpression> | TInstruction<MethodCall>,
|
||||||
kind: 'useCallback' | 'useMemo',
|
kind: 'useCallback' | 'useMemo',
|
||||||
sidemap: IdentifierSidemap,
|
sidemap: IdentifierSidemap,
|
||||||
errors: CompilerError,
|
env: Environment,
|
||||||
): {
|
): {
|
||||||
fnPlace: Place;
|
fnPlace: Place;
|
||||||
depsList: Array<ManualMemoDependency> | null;
|
depsList: Array<ManualMemoDependency> | null;
|
||||||
@@ -303,7 +303,7 @@ function extractManualMemoizationArgs(
|
|||||||
Place | SpreadPattern | undefined
|
Place | SpreadPattern | undefined
|
||||||
>;
|
>;
|
||||||
if (fnPlace == null || fnPlace.kind !== 'Identifier') {
|
if (fnPlace == null || fnPlace.kind !== 'Identifier') {
|
||||||
errors.pushDiagnostic(
|
env.recordError(
|
||||||
CompilerDiagnostic.create({
|
CompilerDiagnostic.create({
|
||||||
category: ErrorCategory.UseMemo,
|
category: ErrorCategory.UseMemo,
|
||||||
reason: `Expected a callback function to be passed to ${kind}`,
|
reason: `Expected a callback function to be passed to ${kind}`,
|
||||||
@@ -335,7 +335,7 @@ function extractManualMemoizationArgs(
|
|||||||
? sidemap.maybeDepsLists.get(depsListPlace.identifier.id)
|
? sidemap.maybeDepsLists.get(depsListPlace.identifier.id)
|
||||||
: null;
|
: null;
|
||||||
if (maybeDepsList == null) {
|
if (maybeDepsList == null) {
|
||||||
errors.pushDiagnostic(
|
env.recordError(
|
||||||
CompilerDiagnostic.create({
|
CompilerDiagnostic.create({
|
||||||
category: ErrorCategory.UseMemo,
|
category: ErrorCategory.UseMemo,
|
||||||
reason: `Expected the dependency list for ${kind} to be an array literal`,
|
reason: `Expected the dependency list for ${kind} to be an array literal`,
|
||||||
@@ -354,7 +354,7 @@ function extractManualMemoizationArgs(
|
|||||||
for (const dep of maybeDepsList.deps) {
|
for (const dep of maybeDepsList.deps) {
|
||||||
const maybeDep = sidemap.maybeDeps.get(dep.identifier.id);
|
const maybeDep = sidemap.maybeDeps.get(dep.identifier.id);
|
||||||
if (maybeDep == null) {
|
if (maybeDep == null) {
|
||||||
errors.pushDiagnostic(
|
env.recordError(
|
||||||
CompilerDiagnostic.create({
|
CompilerDiagnostic.create({
|
||||||
category: ErrorCategory.UseMemo,
|
category: ErrorCategory.UseMemo,
|
||||||
reason: `Expected the dependency list to be an array of simple expressions (e.g. \`x\`, \`x.y.z\`, \`x?.y?.z\`)`,
|
reason: `Expected the dependency list to be an array of simple expressions (e.g. \`x\`, \`x.y.z\`, \`x?.y?.z\`)`,
|
||||||
@@ -389,7 +389,6 @@ function extractManualMemoizationArgs(
|
|||||||
* is only used for memoizing values and not for running arbitrary side effects.
|
* is only used for memoizing values and not for running arbitrary side effects.
|
||||||
*/
|
*/
|
||||||
export function dropManualMemoization(func: HIRFunction): void {
|
export function dropManualMemoization(func: HIRFunction): void {
|
||||||
const errors = new CompilerError();
|
|
||||||
const isValidationEnabled =
|
const isValidationEnabled =
|
||||||
func.env.config.validatePreserveExistingMemoizationGuarantees ||
|
func.env.config.validatePreserveExistingMemoizationGuarantees ||
|
||||||
func.env.config.validateNoSetStateInRender ||
|
func.env.config.validateNoSetStateInRender ||
|
||||||
@@ -436,7 +435,7 @@ export function dropManualMemoization(func: HIRFunction): void {
|
|||||||
instr as TInstruction<CallExpression> | TInstruction<MethodCall>,
|
instr as TInstruction<CallExpression> | TInstruction<MethodCall>,
|
||||||
manualMemo.kind,
|
manualMemo.kind,
|
||||||
sidemap,
|
sidemap,
|
||||||
errors,
|
func.env,
|
||||||
);
|
);
|
||||||
|
|
||||||
if (memoDetails == null) {
|
if (memoDetails == null) {
|
||||||
@@ -464,7 +463,7 @@ export function dropManualMemoization(func: HIRFunction): void {
|
|||||||
* is rare and likely sketchy.
|
* is rare and likely sketchy.
|
||||||
*/
|
*/
|
||||||
if (!sidemap.functions.has(fnPlace.identifier.id)) {
|
if (!sidemap.functions.has(fnPlace.identifier.id)) {
|
||||||
errors.pushDiagnostic(
|
func.env.recordError(
|
||||||
CompilerDiagnostic.create({
|
CompilerDiagnostic.create({
|
||||||
category: ErrorCategory.UseMemo,
|
category: ErrorCategory.UseMemo,
|
||||||
reason: `Expected the first argument to be an inline function expression`,
|
reason: `Expected the first argument to be an inline function expression`,
|
||||||
@@ -549,10 +548,6 @@ export function dropManualMemoization(func: HIRFunction): void {
|
|||||||
markInstructionIds(func.body);
|
markInstructionIds(func.body);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (errors.hasAnyErrors()) {
|
|
||||||
func.env.recordErrors(errors);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function findOptionalPlaces(fn: HIRFunction): Set<IdentifierId> {
|
function findOptionalPlaces(fn: HIRFunction): Set<IdentifierId> {
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ import {
|
|||||||
Place,
|
Place,
|
||||||
isPrimitiveType,
|
isPrimitiveType,
|
||||||
} from '../HIR/HIR';
|
} from '../HIR/HIR';
|
||||||
|
import {Environment} from '../HIR/Environment';
|
||||||
import {
|
import {
|
||||||
eachInstructionLValue,
|
eachInstructionLValue,
|
||||||
eachInstructionValueOperand,
|
eachInstructionValueOperand,
|
||||||
@@ -107,7 +108,7 @@ export function inferMutationAliasingRanges(
|
|||||||
|
|
||||||
let index = 0;
|
let index = 0;
|
||||||
|
|
||||||
const errors = new CompilerError();
|
const shouldRecordErrors = !isFunctionExpression && fn.env.enableValidations;
|
||||||
|
|
||||||
for (const param of [...fn.params, ...fn.context, fn.returns]) {
|
for (const param of [...fn.params, ...fn.context, fn.returns]) {
|
||||||
const place = param.kind === 'Identifier' ? param : param.place;
|
const place = param.kind === 'Identifier' ? param : param.place;
|
||||||
@@ -200,7 +201,9 @@ export function inferMutationAliasingRanges(
|
|||||||
effect.kind === 'MutateGlobal' ||
|
effect.kind === 'MutateGlobal' ||
|
||||||
effect.kind === 'Impure'
|
effect.kind === 'Impure'
|
||||||
) {
|
) {
|
||||||
errors.pushDiagnostic(effect.error);
|
if (shouldRecordErrors) {
|
||||||
|
fn.env.recordError(effect.error);
|
||||||
|
}
|
||||||
functionEffects.push(effect);
|
functionEffects.push(effect);
|
||||||
} else if (effect.kind === 'Render') {
|
} else if (effect.kind === 'Render') {
|
||||||
renders.push({index: index++, place: effect.place});
|
renders.push({index: index++, place: effect.place});
|
||||||
@@ -245,11 +248,15 @@ export function inferMutationAliasingRanges(
|
|||||||
mutation.kind,
|
mutation.kind,
|
||||||
mutation.place.loc,
|
mutation.place.loc,
|
||||||
mutation.reason,
|
mutation.reason,
|
||||||
errors,
|
shouldRecordErrors ? fn.env : null,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
for (const render of renders) {
|
for (const render of renders) {
|
||||||
state.render(render.index, render.place.identifier, errors);
|
state.render(
|
||||||
|
render.index,
|
||||||
|
render.place.identifier,
|
||||||
|
shouldRecordErrors ? fn.env : null,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
for (const param of [...fn.context, ...fn.params]) {
|
for (const param of [...fn.context, ...fn.params]) {
|
||||||
const place = param.kind === 'Identifier' ? param : param.place;
|
const place = param.kind === 'Identifier' ? param : param.place;
|
||||||
@@ -498,7 +505,6 @@ export function inferMutationAliasingRanges(
|
|||||||
* would be transitively mutated needs a capture relationship.
|
* would be transitively mutated needs a capture relationship.
|
||||||
*/
|
*/
|
||||||
const tracked: Array<Place> = [];
|
const tracked: Array<Place> = [];
|
||||||
const ignoredErrors = new CompilerError();
|
|
||||||
for (const param of [...fn.params, ...fn.context, fn.returns]) {
|
for (const param of [...fn.params, ...fn.context, fn.returns]) {
|
||||||
const place = param.kind === 'Identifier' ? param : param.place;
|
const place = param.kind === 'Identifier' ? param : param.place;
|
||||||
tracked.push(place);
|
tracked.push(place);
|
||||||
@@ -513,7 +519,7 @@ export function inferMutationAliasingRanges(
|
|||||||
MutationKind.Conditional,
|
MutationKind.Conditional,
|
||||||
into.loc,
|
into.loc,
|
||||||
null,
|
null,
|
||||||
ignoredErrors,
|
null,
|
||||||
);
|
);
|
||||||
for (const from of tracked) {
|
for (const from of tracked) {
|
||||||
if (
|
if (
|
||||||
@@ -547,23 +553,17 @@ export function inferMutationAliasingRanges(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (
|
|
||||||
errors.hasAnyErrors() &&
|
|
||||||
!isFunctionExpression &&
|
|
||||||
fn.env.enableValidations
|
|
||||||
) {
|
|
||||||
fn.env.recordErrors(errors);
|
|
||||||
}
|
|
||||||
return functionEffects;
|
return functionEffects;
|
||||||
}
|
}
|
||||||
|
|
||||||
function appendFunctionErrors(errors: CompilerError, fn: HIRFunction): void {
|
function appendFunctionErrors(env: Environment | null, fn: HIRFunction): void {
|
||||||
|
if (env == null) return;
|
||||||
for (const effect of fn.aliasingEffects ?? []) {
|
for (const effect of fn.aliasingEffects ?? []) {
|
||||||
switch (effect.kind) {
|
switch (effect.kind) {
|
||||||
case 'Impure':
|
case 'Impure':
|
||||||
case 'MutateFrozen':
|
case 'MutateFrozen':
|
||||||
case 'MutateGlobal': {
|
case 'MutateGlobal': {
|
||||||
errors.pushDiagnostic(effect.error);
|
env.recordError(effect.error);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -664,7 +664,7 @@ class AliasingState {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
render(index: number, start: Identifier, errors: CompilerError): void {
|
render(index: number, start: Identifier, env: Environment | null): void {
|
||||||
const seen = new Set<Identifier>();
|
const seen = new Set<Identifier>();
|
||||||
const queue: Array<Identifier> = [start];
|
const queue: Array<Identifier> = [start];
|
||||||
while (queue.length !== 0) {
|
while (queue.length !== 0) {
|
||||||
@@ -678,7 +678,7 @@ class AliasingState {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (node.value.kind === 'Function') {
|
if (node.value.kind === 'Function') {
|
||||||
appendFunctionErrors(errors, node.value.function);
|
appendFunctionErrors(env, node.value.function);
|
||||||
}
|
}
|
||||||
for (const [alias, when] of node.createdFrom) {
|
for (const [alias, when] of node.createdFrom) {
|
||||||
if (when >= index) {
|
if (when >= index) {
|
||||||
@@ -710,7 +710,7 @@ class AliasingState {
|
|||||||
startKind: MutationKind,
|
startKind: MutationKind,
|
||||||
loc: SourceLocation,
|
loc: SourceLocation,
|
||||||
reason: MutationReason | null,
|
reason: MutationReason | null,
|
||||||
errors: CompilerError,
|
env: Environment | null,
|
||||||
): void {
|
): void {
|
||||||
const seen = new Map<Identifier, MutationKind>();
|
const seen = new Map<Identifier, MutationKind>();
|
||||||
const queue: Array<{
|
const queue: Array<{
|
||||||
@@ -742,7 +742,7 @@ class AliasingState {
|
|||||||
node.transitive == null &&
|
node.transitive == null &&
|
||||||
node.local == null
|
node.local == null
|
||||||
) {
|
) {
|
||||||
appendFunctionErrors(errors, node.value.function);
|
appendFunctionErrors(env, node.value.function);
|
||||||
}
|
}
|
||||||
if (transitive) {
|
if (transitive) {
|
||||||
if (node.transitive == null || node.transitive.kind < kind) {
|
if (node.transitive == null || node.transitive.kind < kind) {
|
||||||
|
|||||||
@@ -13,7 +13,11 @@ import {
|
|||||||
pruneUnusedLabels,
|
pruneUnusedLabels,
|
||||||
renameVariables,
|
renameVariables,
|
||||||
} from '.';
|
} from '.';
|
||||||
import {CompilerError, ErrorCategory} from '../CompilerError';
|
import {
|
||||||
|
CompilerError,
|
||||||
|
CompilerErrorDetail,
|
||||||
|
ErrorCategory,
|
||||||
|
} from '../CompilerError';
|
||||||
import {Environment, ExternalFunction} from '../HIR';
|
import {Environment, ExternalFunction} from '../HIR';
|
||||||
import {
|
import {
|
||||||
ArrayPattern,
|
ArrayPattern,
|
||||||
@@ -358,10 +362,6 @@ function codegenReactiveFunction(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cx.errors.hasAnyErrors()) {
|
|
||||||
fn.env.recordErrors(cx.errors);
|
|
||||||
}
|
|
||||||
|
|
||||||
const countMemoBlockVisitor = new CountMemoBlockVisitor(fn.env);
|
const countMemoBlockVisitor = new CountMemoBlockVisitor(fn.env);
|
||||||
visitReactiveFunction(fn, countMemoBlockVisitor, undefined);
|
visitReactiveFunction(fn, countMemoBlockVisitor, undefined);
|
||||||
|
|
||||||
@@ -434,7 +434,6 @@ class Context {
|
|||||||
*/
|
*/
|
||||||
#declarations: Set<DeclarationId> = new Set();
|
#declarations: Set<DeclarationId> = new Set();
|
||||||
temp: Temporaries;
|
temp: Temporaries;
|
||||||
errors: CompilerError = new CompilerError();
|
|
||||||
objectMethods: Map<IdentifierId, ObjectMethod> = new Map();
|
objectMethods: Map<IdentifierId, ObjectMethod> = new Map();
|
||||||
uniqueIdentifiers: Set<string>;
|
uniqueIdentifiers: Set<string>;
|
||||||
fbtOperands: Set<IdentifierId>;
|
fbtOperands: Set<IdentifierId>;
|
||||||
@@ -453,6 +452,10 @@ class Context {
|
|||||||
this.fbtOperands = fbtOperands;
|
this.fbtOperands = fbtOperands;
|
||||||
this.temp = temporaries !== null ? new Map(temporaries) : new Map();
|
this.temp = temporaries !== null ? new Map(temporaries) : new Map();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
recordError(error: CompilerErrorDetail): void {
|
||||||
|
this.env.recordError(error);
|
||||||
|
}
|
||||||
get nextCacheIndex(): number {
|
get nextCacheIndex(): number {
|
||||||
return this.#nextCacheIndex++;
|
return this.#nextCacheIndex++;
|
||||||
}
|
}
|
||||||
@@ -972,12 +975,14 @@ function codegenTerminal(
|
|||||||
loc: terminal.init.loc,
|
loc: terminal.init.loc,
|
||||||
});
|
});
|
||||||
if (terminal.init.instructions.length !== 2) {
|
if (terminal.init.instructions.length !== 2) {
|
||||||
cx.errors.push({
|
cx.recordError(
|
||||||
reason: 'Support non-trivial for..in inits',
|
new CompilerErrorDetail({
|
||||||
category: ErrorCategory.Todo,
|
reason: 'Support non-trivial for..in inits',
|
||||||
loc: terminal.init.loc,
|
category: ErrorCategory.Todo,
|
||||||
suggestions: null,
|
loc: terminal.init.loc,
|
||||||
});
|
suggestions: null,
|
||||||
|
}),
|
||||||
|
);
|
||||||
return t.emptyStatement();
|
return t.emptyStatement();
|
||||||
}
|
}
|
||||||
const iterableCollection = terminal.init.instructions[0];
|
const iterableCollection = terminal.init.instructions[0];
|
||||||
@@ -993,12 +998,14 @@ function codegenTerminal(
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'StoreContext': {
|
case 'StoreContext': {
|
||||||
cx.errors.push({
|
cx.recordError(
|
||||||
reason: 'Support non-trivial for..in inits',
|
new CompilerErrorDetail({
|
||||||
category: ErrorCategory.Todo,
|
reason: 'Support non-trivial for..in inits',
|
||||||
loc: terminal.init.loc,
|
category: ErrorCategory.Todo,
|
||||||
suggestions: null,
|
loc: terminal.init.loc,
|
||||||
});
|
suggestions: null,
|
||||||
|
}),
|
||||||
|
);
|
||||||
return t.emptyStatement();
|
return t.emptyStatement();
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
@@ -1069,12 +1076,14 @@ function codegenTerminal(
|
|||||||
loc: terminal.test.loc,
|
loc: terminal.test.loc,
|
||||||
});
|
});
|
||||||
if (terminal.test.instructions.length !== 2) {
|
if (terminal.test.instructions.length !== 2) {
|
||||||
cx.errors.push({
|
cx.recordError(
|
||||||
reason: 'Support non-trivial for..of inits',
|
new CompilerErrorDetail({
|
||||||
category: ErrorCategory.Todo,
|
reason: 'Support non-trivial for..of inits',
|
||||||
loc: terminal.init.loc,
|
category: ErrorCategory.Todo,
|
||||||
suggestions: null,
|
loc: terminal.init.loc,
|
||||||
});
|
suggestions: null,
|
||||||
|
}),
|
||||||
|
);
|
||||||
return t.emptyStatement();
|
return t.emptyStatement();
|
||||||
}
|
}
|
||||||
const iterableItem = terminal.test.instructions[1];
|
const iterableItem = terminal.test.instructions[1];
|
||||||
@@ -1089,12 +1098,14 @@ function codegenTerminal(
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'StoreContext': {
|
case 'StoreContext': {
|
||||||
cx.errors.push({
|
cx.recordError(
|
||||||
reason: 'Support non-trivial for..of inits',
|
new CompilerErrorDetail({
|
||||||
category: ErrorCategory.Todo,
|
reason: 'Support non-trivial for..of inits',
|
||||||
loc: terminal.init.loc,
|
category: ErrorCategory.Todo,
|
||||||
suggestions: null,
|
loc: terminal.init.loc,
|
||||||
});
|
suggestions: null,
|
||||||
|
}),
|
||||||
|
);
|
||||||
return t.emptyStatement();
|
return t.emptyStatement();
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
@@ -2189,22 +2200,26 @@ function codegenInstructionValue(
|
|||||||
} else {
|
} else {
|
||||||
if (t.isVariableDeclaration(stmt)) {
|
if (t.isVariableDeclaration(stmt)) {
|
||||||
const declarator = stmt.declarations[0];
|
const declarator = stmt.declarations[0];
|
||||||
cx.errors.push({
|
cx.recordError(
|
||||||
reason: `(CodegenReactiveFunction::codegenInstructionValue) Cannot declare variables in a value block, tried to declare '${
|
new CompilerErrorDetail({
|
||||||
(declarator.id as t.Identifier).name
|
reason: `(CodegenReactiveFunction::codegenInstructionValue) Cannot declare variables in a value block, tried to declare '${
|
||||||
}'`,
|
(declarator.id as t.Identifier).name
|
||||||
category: ErrorCategory.Todo,
|
}'`,
|
||||||
loc: declarator.loc ?? null,
|
category: ErrorCategory.Todo,
|
||||||
suggestions: null,
|
loc: declarator.loc ?? null,
|
||||||
});
|
suggestions: null,
|
||||||
|
}),
|
||||||
|
);
|
||||||
return t.stringLiteral(`TODO handle ${declarator.id}`);
|
return t.stringLiteral(`TODO handle ${declarator.id}`);
|
||||||
} else {
|
} else {
|
||||||
cx.errors.push({
|
cx.recordError(
|
||||||
reason: `(CodegenReactiveFunction::codegenInstructionValue) Handle conversion of ${stmt.type} to expression`,
|
new CompilerErrorDetail({
|
||||||
category: ErrorCategory.Todo,
|
reason: `(CodegenReactiveFunction::codegenInstructionValue) Handle conversion of ${stmt.type} to expression`,
|
||||||
loc: stmt.loc ?? null,
|
category: ErrorCategory.Todo,
|
||||||
suggestions: null,
|
loc: stmt.loc ?? null,
|
||||||
});
|
suggestions: null,
|
||||||
|
}),
|
||||||
|
);
|
||||||
return t.stringLiteral(`TODO handle ${stmt.type}`);
|
return t.stringLiteral(`TODO handle ${stmt.type}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,11 @@
|
|||||||
* LICENSE file in the root directory of this source tree.
|
* LICENSE file in the root directory of this source tree.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {CompilerError, CompilerErrorDetailOptions, SourceLocation} from '..';
|
import {
|
||||||
|
CompilerErrorDetail,
|
||||||
|
CompilerErrorDetailOptions,
|
||||||
|
SourceLocation,
|
||||||
|
} from '..';
|
||||||
import {
|
import {
|
||||||
ArrayExpression,
|
ArrayExpression,
|
||||||
CallExpression,
|
CallExpression,
|
||||||
@@ -54,7 +58,6 @@ export function transformFire(fn: HIRFunction): void {
|
|||||||
if (!context.hasErrors()) {
|
if (!context.hasErrors()) {
|
||||||
ensureNoMoreFireUses(fn, context);
|
ensureNoMoreFireUses(fn, context);
|
||||||
}
|
}
|
||||||
context.throwIfErrorsFound();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function replaceFireFunctions(fn: HIRFunction, context: Context): void {
|
function replaceFireFunctions(fn: HIRFunction, context: Context): void {
|
||||||
@@ -526,7 +529,7 @@ type FireCalleesToFireFunctionBinding = Map<
|
|||||||
class Context {
|
class Context {
|
||||||
#env: Environment;
|
#env: Environment;
|
||||||
|
|
||||||
#errors: CompilerError = new CompilerError();
|
#hasErrors: boolean = false;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Used to look up the call expression passed to a `fire(callExpr())`. Gives back
|
* Used to look up the call expression passed to a `fire(callExpr())`. Gives back
|
||||||
@@ -589,7 +592,8 @@ class Context {
|
|||||||
#arrayExpressions = new Map<IdentifierId, ArrayExpression>();
|
#arrayExpressions = new Map<IdentifierId, ArrayExpression>();
|
||||||
|
|
||||||
pushError(error: CompilerErrorDetailOptions): void {
|
pushError(error: CompilerErrorDetailOptions): void {
|
||||||
this.#errors.push(error);
|
this.#hasErrors = true;
|
||||||
|
this.#env.recordError(new CompilerErrorDetail(error));
|
||||||
}
|
}
|
||||||
|
|
||||||
withFunctionScope(fn: () => void): FireCalleesToFireFunctionBinding {
|
withFunctionScope(fn: () => void): FireCalleesToFireFunctionBinding {
|
||||||
@@ -698,11 +702,7 @@ class Context {
|
|||||||
}
|
}
|
||||||
|
|
||||||
hasErrors(): boolean {
|
hasErrors(): boolean {
|
||||||
return this.#errors.hasAnyErrors();
|
return this.#hasErrors;
|
||||||
}
|
|
||||||
|
|
||||||
throwIfErrorsFound(): void {
|
|
||||||
if (this.hasErrors()) throw this.#errors;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -100,7 +100,6 @@ export function validateExhaustiveDependencies(fn: HIRFunction): void {
|
|||||||
loc: place.loc,
|
loc: place.loc,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
const error = new CompilerError();
|
|
||||||
let startMemo: StartMemoize | null = null;
|
let startMemo: StartMemoize | null = null;
|
||||||
|
|
||||||
function onStartMemoize(
|
function onStartMemoize(
|
||||||
@@ -141,7 +140,7 @@ export function validateExhaustiveDependencies(fn: HIRFunction): void {
|
|||||||
'all',
|
'all',
|
||||||
);
|
);
|
||||||
if (diagnostic != null) {
|
if (diagnostic != null) {
|
||||||
error.pushDiagnostic(diagnostic);
|
fn.env.recordError(diagnostic);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -206,15 +205,12 @@ export function validateExhaustiveDependencies(fn: HIRFunction): void {
|
|||||||
effectReportMode,
|
effectReportMode,
|
||||||
);
|
);
|
||||||
if (diagnostic != null) {
|
if (diagnostic != null) {
|
||||||
error.pushDiagnostic(diagnostic);
|
fn.env.recordError(diagnostic);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
false, // isFunctionExpression
|
false, // isFunctionExpression
|
||||||
);
|
);
|
||||||
if (error.hasAnyErrors()) {
|
|
||||||
fn.env.recordErrors(error);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function validateDependencies(
|
function validateDependencies(
|
||||||
|
|||||||
@@ -6,13 +6,9 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import * as t from '@babel/types';
|
import * as t from '@babel/types';
|
||||||
import {
|
import {CompilerErrorDetail, ErrorCategory} from '../CompilerError';
|
||||||
CompilerError,
|
|
||||||
CompilerErrorDetail,
|
|
||||||
ErrorCategory,
|
|
||||||
} from '../CompilerError';
|
|
||||||
import {computeUnconditionalBlocks} from '../HIR/ComputeUnconditionalBlocks';
|
import {computeUnconditionalBlocks} from '../HIR/ComputeUnconditionalBlocks';
|
||||||
import {isHookName} from '../HIR/Environment';
|
import {Environment, isHookName} from '../HIR/Environment';
|
||||||
import {
|
import {
|
||||||
HIRFunction,
|
HIRFunction,
|
||||||
IdentifierId,
|
IdentifierId,
|
||||||
@@ -90,15 +86,14 @@ function joinKinds(a: Kind, b: Kind): Kind {
|
|||||||
export function validateHooksUsage(fn: HIRFunction): void {
|
export function validateHooksUsage(fn: HIRFunction): void {
|
||||||
const unconditionalBlocks = computeUnconditionalBlocks(fn);
|
const unconditionalBlocks = computeUnconditionalBlocks(fn);
|
||||||
|
|
||||||
const errors = new CompilerError();
|
|
||||||
const errorsByPlace = new Map<t.SourceLocation, CompilerErrorDetail>();
|
const errorsByPlace = new Map<t.SourceLocation, CompilerErrorDetail>();
|
||||||
|
|
||||||
function recordError(
|
function trackError(
|
||||||
loc: SourceLocation,
|
loc: SourceLocation,
|
||||||
errorDetail: CompilerErrorDetail,
|
errorDetail: CompilerErrorDetail,
|
||||||
): void {
|
): void {
|
||||||
if (typeof loc === 'symbol') {
|
if (typeof loc === 'symbol') {
|
||||||
errors.pushErrorDetail(errorDetail);
|
fn.env.recordError(errorDetail);
|
||||||
} else {
|
} else {
|
||||||
errorsByPlace.set(loc, errorDetail);
|
errorsByPlace.set(loc, errorDetail);
|
||||||
}
|
}
|
||||||
@@ -118,7 +113,7 @@ export function validateHooksUsage(fn: HIRFunction): void {
|
|||||||
* If that same place is also used as a conditional call, upgrade the error to a conditonal hook error
|
* If that same place is also used as a conditional call, upgrade the error to a conditonal hook error
|
||||||
*/
|
*/
|
||||||
if (previousError === undefined || previousError.reason !== reason) {
|
if (previousError === undefined || previousError.reason !== reason) {
|
||||||
recordError(
|
trackError(
|
||||||
place.loc,
|
place.loc,
|
||||||
new CompilerErrorDetail({
|
new CompilerErrorDetail({
|
||||||
category: ErrorCategory.Hooks,
|
category: ErrorCategory.Hooks,
|
||||||
@@ -134,7 +129,7 @@ export function validateHooksUsage(fn: HIRFunction): void {
|
|||||||
const previousError =
|
const previousError =
|
||||||
typeof place.loc !== 'symbol' ? errorsByPlace.get(place.loc) : undefined;
|
typeof place.loc !== 'symbol' ? errorsByPlace.get(place.loc) : undefined;
|
||||||
if (previousError === undefined) {
|
if (previousError === undefined) {
|
||||||
recordError(
|
trackError(
|
||||||
place.loc,
|
place.loc,
|
||||||
new CompilerErrorDetail({
|
new CompilerErrorDetail({
|
||||||
category: ErrorCategory.Hooks,
|
category: ErrorCategory.Hooks,
|
||||||
@@ -151,7 +146,7 @@ export function validateHooksUsage(fn: HIRFunction): void {
|
|||||||
const previousError =
|
const previousError =
|
||||||
typeof place.loc !== 'symbol' ? errorsByPlace.get(place.loc) : undefined;
|
typeof place.loc !== 'symbol' ? errorsByPlace.get(place.loc) : undefined;
|
||||||
if (previousError === undefined) {
|
if (previousError === undefined) {
|
||||||
recordError(
|
trackError(
|
||||||
place.loc,
|
place.loc,
|
||||||
new CompilerErrorDetail({
|
new CompilerErrorDetail({
|
||||||
category: ErrorCategory.Hooks,
|
category: ErrorCategory.Hooks,
|
||||||
@@ -396,7 +391,7 @@ export function validateHooksUsage(fn: HIRFunction): void {
|
|||||||
}
|
}
|
||||||
case 'ObjectMethod':
|
case 'ObjectMethod':
|
||||||
case 'FunctionExpression': {
|
case 'FunctionExpression': {
|
||||||
visitFunctionExpression(errors, instr.value.loweredFunc.func);
|
visitFunctionExpression(fn.env, instr.value.loweredFunc.func);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default: {
|
default: {
|
||||||
@@ -421,20 +416,17 @@ export function validateHooksUsage(fn: HIRFunction): void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (const [, error] of errorsByPlace) {
|
for (const [, error] of errorsByPlace) {
|
||||||
errors.pushErrorDetail(error);
|
fn.env.recordError(error);
|
||||||
}
|
|
||||||
if (errors.hasAnyErrors()) {
|
|
||||||
fn.env.recordErrors(errors);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function visitFunctionExpression(errors: CompilerError, fn: HIRFunction): void {
|
function visitFunctionExpression(env: Environment, fn: HIRFunction): void {
|
||||||
for (const [, block] of fn.body.blocks) {
|
for (const [, block] of fn.body.blocks) {
|
||||||
for (const instr of block.instructions) {
|
for (const instr of block.instructions) {
|
||||||
switch (instr.value.kind) {
|
switch (instr.value.kind) {
|
||||||
case 'ObjectMethod':
|
case 'ObjectMethod':
|
||||||
case 'FunctionExpression': {
|
case 'FunctionExpression': {
|
||||||
visitFunctionExpression(errors, instr.value.loweredFunc.func);
|
visitFunctionExpression(env, instr.value.loweredFunc.func);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'MethodCall':
|
case 'MethodCall':
|
||||||
@@ -445,7 +437,7 @@ function visitFunctionExpression(errors: CompilerError, fn: HIRFunction): void {
|
|||||||
: instr.value.property;
|
: instr.value.property;
|
||||||
const hookKind = getHookKind(fn.env, callee.identifier);
|
const hookKind = getHookKind(fn.env, callee.identifier);
|
||||||
if (hookKind != null) {
|
if (hookKind != null) {
|
||||||
errors.pushErrorDetail(
|
env.recordError(
|
||||||
new CompilerErrorDetail({
|
new CompilerErrorDetail({
|
||||||
category: ErrorCategory.Hooks,
|
category: ErrorCategory.Hooks,
|
||||||
reason:
|
reason:
|
||||||
|
|||||||
@@ -5,8 +5,7 @@
|
|||||||
* LICENSE file in the root directory of this source tree.
|
* LICENSE file in the root directory of this source tree.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {CompilerError} from '..';
|
import {CompilerErrorDetail, ErrorCategory} from '../CompilerError';
|
||||||
import {ErrorCategory} from '../CompilerError';
|
|
||||||
import {
|
import {
|
||||||
Identifier,
|
Identifier,
|
||||||
Instruction,
|
Instruction,
|
||||||
@@ -18,6 +17,7 @@ import {
|
|||||||
isUseInsertionEffectHookType,
|
isUseInsertionEffectHookType,
|
||||||
isUseLayoutEffectHookType,
|
isUseLayoutEffectHookType,
|
||||||
} from '../HIR';
|
} from '../HIR';
|
||||||
|
import {Environment} from '../HIR/Environment';
|
||||||
import {isMutable} from '../ReactiveScopes/InferReactiveScopeVariables';
|
import {isMutable} from '../ReactiveScopes/InferReactiveScopeVariables';
|
||||||
import {
|
import {
|
||||||
ReactiveFunctionVisitor,
|
ReactiveFunctionVisitor,
|
||||||
@@ -49,17 +49,15 @@ import {
|
|||||||
* ```
|
* ```
|
||||||
*/
|
*/
|
||||||
export function validateMemoizedEffectDependencies(fn: ReactiveFunction): void {
|
export function validateMemoizedEffectDependencies(fn: ReactiveFunction): void {
|
||||||
const errors = new CompilerError();
|
visitReactiveFunction(fn, new Visitor(), fn.env);
|
||||||
visitReactiveFunction(fn, new Visitor(), errors);
|
|
||||||
fn.env.recordErrors(errors);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class Visitor extends ReactiveFunctionVisitor<CompilerError> {
|
class Visitor extends ReactiveFunctionVisitor<Environment> {
|
||||||
scopes: Set<ScopeId> = new Set();
|
scopes: Set<ScopeId> = new Set();
|
||||||
|
|
||||||
override visitScope(
|
override visitScope(
|
||||||
scopeBlock: ReactiveScopeBlock,
|
scopeBlock: ReactiveScopeBlock,
|
||||||
state: CompilerError,
|
state: Environment,
|
||||||
): void {
|
): void {
|
||||||
this.traverseScope(scopeBlock, state);
|
this.traverseScope(scopeBlock, state);
|
||||||
|
|
||||||
@@ -87,7 +85,7 @@ class Visitor extends ReactiveFunctionVisitor<CompilerError> {
|
|||||||
|
|
||||||
override visitInstruction(
|
override visitInstruction(
|
||||||
instruction: ReactiveInstruction,
|
instruction: ReactiveInstruction,
|
||||||
state: CompilerError,
|
state: Environment,
|
||||||
): void {
|
): void {
|
||||||
this.traverseInstruction(instruction, state);
|
this.traverseInstruction(instruction, state);
|
||||||
if (
|
if (
|
||||||
@@ -105,14 +103,16 @@ class Visitor extends ReactiveFunctionVisitor<CompilerError> {
|
|||||||
(isMutable(instruction as Instruction, deps) ||
|
(isMutable(instruction as Instruction, deps) ||
|
||||||
isUnmemoized(deps.identifier, this.scopes))
|
isUnmemoized(deps.identifier, this.scopes))
|
||||||
) {
|
) {
|
||||||
state.push({
|
state.recordError(
|
||||||
category: ErrorCategory.EffectDependencies,
|
new CompilerErrorDetail({
|
||||||
reason:
|
category: ErrorCategory.EffectDependencies,
|
||||||
'React Compiler has skipped optimizing this component because the effect dependencies could not be memoized. Unmemoized effect dependencies can trigger an infinite loop or other unexpected behavior',
|
reason:
|
||||||
description: null,
|
'React Compiler has skipped optimizing this component because the effect dependencies could not be memoized. Unmemoized effect dependencies can trigger an infinite loop or other unexpected behavior',
|
||||||
loc: typeof instruction.loc !== 'symbol' ? instruction.loc : null,
|
description: null,
|
||||||
suggestions: null,
|
loc: typeof instruction.loc !== 'symbol' ? instruction.loc : null,
|
||||||
});
|
suggestions: null,
|
||||||
|
}),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
* LICENSE file in the root directory of this source tree.
|
* LICENSE file in the root directory of this source tree.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {CompilerError, CompilerErrorDetail, EnvironmentConfig} from '..';
|
import {CompilerErrorDetail, EnvironmentConfig} from '..';
|
||||||
import {ErrorCategory} from '../CompilerError';
|
import {ErrorCategory} from '../CompilerError';
|
||||||
import {HIRFunction, IdentifierId} from '../HIR';
|
import {HIRFunction, IdentifierId} from '../HIR';
|
||||||
import {DEFAULT_GLOBALS} from '../HIR/Globals';
|
import {DEFAULT_GLOBALS} from '../HIR/Globals';
|
||||||
@@ -28,7 +28,6 @@ export function validateNoCapitalizedCalls(fn: HIRFunction): void {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const errors = new CompilerError();
|
|
||||||
const capitalLoadGlobals = new Map<IdentifierId, string>();
|
const capitalLoadGlobals = new Map<IdentifierId, string>();
|
||||||
const capitalizedProperties = new Map<IdentifierId, string>();
|
const capitalizedProperties = new Map<IdentifierId, string>();
|
||||||
const reason =
|
const reason =
|
||||||
@@ -80,20 +79,19 @@ export function validateNoCapitalizedCalls(fn: HIRFunction): void {
|
|||||||
const propertyIdentifier = value.property.identifier.id;
|
const propertyIdentifier = value.property.identifier.id;
|
||||||
const propertyName = capitalizedProperties.get(propertyIdentifier);
|
const propertyName = capitalizedProperties.get(propertyIdentifier);
|
||||||
if (propertyName != null) {
|
if (propertyName != null) {
|
||||||
errors.push({
|
fn.env.recordError(
|
||||||
category: ErrorCategory.CapitalizedCalls,
|
new CompilerErrorDetail({
|
||||||
reason,
|
category: ErrorCategory.CapitalizedCalls,
|
||||||
description: `${propertyName} may be a component`,
|
reason,
|
||||||
loc: value.loc,
|
description: `${propertyName} may be a component`,
|
||||||
suggestions: null,
|
loc: value.loc,
|
||||||
});
|
suggestions: null,
|
||||||
|
}),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (errors.hasAnyErrors()) {
|
|
||||||
fn.env.recordErrors(errors);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import {CompilerError, SourceLocation} from '..';
|
import {CompilerError, SourceLocation} from '..';
|
||||||
import {ErrorCategory} from '../CompilerError';
|
import {CompilerErrorDetail, ErrorCategory} from '../CompilerError';
|
||||||
import {
|
import {
|
||||||
ArrayExpression,
|
ArrayExpression,
|
||||||
BlockId,
|
BlockId,
|
||||||
@@ -20,6 +20,7 @@ import {
|
|||||||
eachInstructionValueOperand,
|
eachInstructionValueOperand,
|
||||||
eachTerminalOperand,
|
eachTerminalOperand,
|
||||||
} from '../HIR/visitors';
|
} from '../HIR/visitors';
|
||||||
|
import {Environment} from '../HIR/Environment';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Validates that useEffect is not used for derived computations which could/should
|
* Validates that useEffect is not used for derived computations which could/should
|
||||||
@@ -49,8 +50,6 @@ export function validateNoDerivedComputationsInEffects(fn: HIRFunction): void {
|
|||||||
const functions: Map<IdentifierId, FunctionExpression> = new Map();
|
const functions: Map<IdentifierId, FunctionExpression> = new Map();
|
||||||
const locals: Map<IdentifierId, IdentifierId> = new Map();
|
const locals: Map<IdentifierId, IdentifierId> = new Map();
|
||||||
|
|
||||||
const errors = new CompilerError();
|
|
||||||
|
|
||||||
for (const block of fn.body.blocks.values()) {
|
for (const block of fn.body.blocks.values()) {
|
||||||
for (const instr of block.instructions) {
|
for (const instr of block.instructions) {
|
||||||
const {lvalue, value} = instr;
|
const {lvalue, value} = instr;
|
||||||
@@ -90,20 +89,19 @@ export function validateNoDerivedComputationsInEffects(fn: HIRFunction): void {
|
|||||||
validateEffect(
|
validateEffect(
|
||||||
effectFunction.loweredFunc.func,
|
effectFunction.loweredFunc.func,
|
||||||
dependencies,
|
dependencies,
|
||||||
errors,
|
fn.env,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn.env.recordErrors(errors);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function validateEffect(
|
function validateEffect(
|
||||||
effectFunction: HIRFunction,
|
effectFunction: HIRFunction,
|
||||||
effectDeps: Array<IdentifierId>,
|
effectDeps: Array<IdentifierId>,
|
||||||
errors: CompilerError,
|
env: Environment,
|
||||||
): void {
|
): void {
|
||||||
for (const operand of effectFunction.context) {
|
for (const operand of effectFunction.context) {
|
||||||
if (isSetStateType(operand.identifier)) {
|
if (isSetStateType(operand.identifier)) {
|
||||||
@@ -217,13 +215,15 @@ function validateEffect(
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (const loc of setStateLocations) {
|
for (const loc of setStateLocations) {
|
||||||
errors.push({
|
env.recordError(
|
||||||
category: ErrorCategory.EffectDerivationsOfState,
|
new CompilerErrorDetail({
|
||||||
reason:
|
category: ErrorCategory.EffectDerivationsOfState,
|
||||||
'Values derived from props and state should be calculated during render, not in an effect. (https://react.dev/learn/you-might-not-need-an-effect#updating-state-based-on-props-or-state)',
|
reason:
|
||||||
description: null,
|
'Values derived from props and state should be calculated during render, not in an effect. (https://react.dev/learn/you-might-not-need-an-effect#updating-state-based-on-props-or-state)',
|
||||||
loc,
|
description: null,
|
||||||
suggestions: null,
|
loc,
|
||||||
});
|
suggestions: null,
|
||||||
|
}),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
* LICENSE file in the root directory of this source tree.
|
* LICENSE file in the root directory of this source tree.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {CompilerDiagnostic, CompilerError, Effect} from '..';
|
import {CompilerDiagnostic, Effect} from '..';
|
||||||
import {ErrorCategory} from '../CompilerError';
|
import {ErrorCategory} from '../CompilerError';
|
||||||
import {
|
import {
|
||||||
HIRFunction,
|
HIRFunction,
|
||||||
@@ -43,7 +43,6 @@ import {AliasingEffect} from '../Inference/AliasingEffects';
|
|||||||
* that are passed where a frozen value is expected and rejects them.
|
* that are passed where a frozen value is expected and rejects them.
|
||||||
*/
|
*/
|
||||||
export function validateNoFreezingKnownMutableFunctions(fn: HIRFunction): void {
|
export function validateNoFreezingKnownMutableFunctions(fn: HIRFunction): void {
|
||||||
const errors = new CompilerError();
|
|
||||||
const contextMutationEffects: Map<
|
const contextMutationEffects: Map<
|
||||||
IdentifierId,
|
IdentifierId,
|
||||||
Extract<AliasingEffect, {kind: 'Mutate'} | {kind: 'MutateTransitive'}>
|
Extract<AliasingEffect, {kind: 'Mutate'} | {kind: 'MutateTransitive'}>
|
||||||
@@ -60,7 +59,7 @@ export function validateNoFreezingKnownMutableFunctions(fn: HIRFunction): void {
|
|||||||
place.identifier.name.kind === 'named'
|
place.identifier.name.kind === 'named'
|
||||||
? `\`${place.identifier.name.value}\``
|
? `\`${place.identifier.name.value}\``
|
||||||
: 'a local variable';
|
: 'a local variable';
|
||||||
errors.pushDiagnostic(
|
fn.env.recordError(
|
||||||
CompilerDiagnostic.create({
|
CompilerDiagnostic.create({
|
||||||
category: ErrorCategory.Immutability,
|
category: ErrorCategory.Immutability,
|
||||||
reason: 'Cannot modify local variables after render completes',
|
reason: 'Cannot modify local variables after render completes',
|
||||||
@@ -159,7 +158,4 @@ export function validateNoFreezingKnownMutableFunctions(fn: HIRFunction): void {
|
|||||||
visitOperand(operand);
|
visitOperand(operand);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (errors.hasAnyErrors()) {
|
|
||||||
fn.env.recordErrors(errors);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
* LICENSE file in the root directory of this source tree.
|
* LICENSE file in the root directory of this source tree.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {CompilerDiagnostic, CompilerError} from '..';
|
import {CompilerDiagnostic} from '..';
|
||||||
import {ErrorCategory} from '../CompilerError';
|
import {ErrorCategory} from '../CompilerError';
|
||||||
import {HIRFunction} from '../HIR';
|
import {HIRFunction} from '../HIR';
|
||||||
import {getFunctionCallSignature} from '../Inference/InferMutationAliasingEffects';
|
import {getFunctionCallSignature} from '../Inference/InferMutationAliasingEffects';
|
||||||
@@ -20,7 +20,6 @@ import {getFunctionCallSignature} from '../Inference/InferMutationAliasingEffect
|
|||||||
* and use it here.
|
* and use it here.
|
||||||
*/
|
*/
|
||||||
export function validateNoImpureFunctionsInRender(fn: HIRFunction): void {
|
export function validateNoImpureFunctionsInRender(fn: HIRFunction): void {
|
||||||
const errors = new CompilerError();
|
|
||||||
for (const [, block] of fn.body.blocks) {
|
for (const [, block] of fn.body.blocks) {
|
||||||
for (const instr of block.instructions) {
|
for (const instr of block.instructions) {
|
||||||
const value = instr.value;
|
const value = instr.value;
|
||||||
@@ -32,7 +31,7 @@ export function validateNoImpureFunctionsInRender(fn: HIRFunction): void {
|
|||||||
callee.identifier.type,
|
callee.identifier.type,
|
||||||
);
|
);
|
||||||
if (signature != null && signature.impure === true) {
|
if (signature != null && signature.impure === true) {
|
||||||
errors.pushDiagnostic(
|
fn.env.recordError(
|
||||||
CompilerDiagnostic.create({
|
CompilerDiagnostic.create({
|
||||||
category: ErrorCategory.Purity,
|
category: ErrorCategory.Purity,
|
||||||
reason: 'Cannot call impure function during render',
|
reason: 'Cannot call impure function during render',
|
||||||
@@ -52,7 +51,4 @@ export function validateNoImpureFunctionsInRender(fn: HIRFunction): void {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (errors.hasAnyErrors()) {
|
|
||||||
fn.env.recordErrors(errors);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -126,8 +126,8 @@ export function validateNoRefAccessInRender(fn: HIRFunction): void {
|
|||||||
collectTemporariesSidemap(fn, env);
|
collectTemporariesSidemap(fn, env);
|
||||||
const errors = new CompilerError();
|
const errors = new CompilerError();
|
||||||
validateNoRefAccessInRenderImpl(fn, env, errors);
|
validateNoRefAccessInRenderImpl(fn, env, errors);
|
||||||
if (errors.hasAnyErrors()) {
|
for (const detail of errors.details) {
|
||||||
fn.env.recordErrors(errors);
|
fn.env.recordError(detail);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -48,8 +48,8 @@ export function validateNoSetStateInRender(fn: HIRFunction): void {
|
|||||||
fn,
|
fn,
|
||||||
unconditionalSetStateFunctions,
|
unconditionalSetStateFunctions,
|
||||||
);
|
);
|
||||||
if (errors.hasAnyErrors()) {
|
for (const detail of errors.details) {
|
||||||
fn.env.recordErrors(errors);
|
fn.env.recordError(detail);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ import {
|
|||||||
ScopeId,
|
ScopeId,
|
||||||
SourceLocation,
|
SourceLocation,
|
||||||
} from '../HIR';
|
} from '../HIR';
|
||||||
|
import {Environment} from '../HIR/Environment';
|
||||||
import {printIdentifier, printManualMemoDependency} from '../HIR/PrintHIR';
|
import {printIdentifier, printManualMemoDependency} from '../HIR/PrintHIR';
|
||||||
import {
|
import {
|
||||||
eachInstructionValueLValue,
|
eachInstructionValueLValue,
|
||||||
@@ -48,11 +49,10 @@ import {getOrInsertDefault} from '../Utils/utils';
|
|||||||
*/
|
*/
|
||||||
export function validatePreservedManualMemoization(fn: ReactiveFunction): void {
|
export function validatePreservedManualMemoization(fn: ReactiveFunction): void {
|
||||||
const state = {
|
const state = {
|
||||||
errors: new CompilerError(),
|
env: fn.env,
|
||||||
manualMemoState: null,
|
manualMemoState: null,
|
||||||
};
|
};
|
||||||
visitReactiveFunction(fn, new Visitor(), state);
|
visitReactiveFunction(fn, new Visitor(), state);
|
||||||
fn.env.recordErrors(state.errors);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const DEBUG = false;
|
const DEBUG = false;
|
||||||
@@ -110,7 +110,7 @@ type ManualMemoBlockState = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
type VisitorState = {
|
type VisitorState = {
|
||||||
errors: CompilerError;
|
env: Environment;
|
||||||
manualMemoState: ManualMemoBlockState | null;
|
manualMemoState: ManualMemoBlockState | null;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -230,7 +230,7 @@ function validateInferredDep(
|
|||||||
temporaries: Map<IdentifierId, ManualMemoDependency>,
|
temporaries: Map<IdentifierId, ManualMemoDependency>,
|
||||||
declsWithinMemoBlock: Set<DeclarationId>,
|
declsWithinMemoBlock: Set<DeclarationId>,
|
||||||
validDepsInMemoBlock: Array<ManualMemoDependency>,
|
validDepsInMemoBlock: Array<ManualMemoDependency>,
|
||||||
errorState: CompilerError,
|
errorState: Environment,
|
||||||
memoLocation: SourceLocation,
|
memoLocation: SourceLocation,
|
||||||
): void {
|
): void {
|
||||||
let normalizedDep: ManualMemoDependency;
|
let normalizedDep: ManualMemoDependency;
|
||||||
@@ -280,7 +280,7 @@ function validateInferredDep(
|
|||||||
errorDiagnostic = merge(errorDiagnostic ?? compareResult, compareResult);
|
errorDiagnostic = merge(errorDiagnostic ?? compareResult, compareResult);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
errorState.pushDiagnostic(
|
errorState.recordError(
|
||||||
CompilerDiagnostic.create({
|
CompilerDiagnostic.create({
|
||||||
category: ErrorCategory.PreserveManualMemo,
|
category: ErrorCategory.PreserveManualMemo,
|
||||||
reason: 'Existing memoization could not be preserved',
|
reason: 'Existing memoization could not be preserved',
|
||||||
@@ -426,7 +426,7 @@ class Visitor extends ReactiveFunctionVisitor<VisitorState> {
|
|||||||
this.temporaries,
|
this.temporaries,
|
||||||
state.manualMemoState.decls,
|
state.manualMemoState.decls,
|
||||||
state.manualMemoState.depsFromSource,
|
state.manualMemoState.depsFromSource,
|
||||||
state.errors,
|
state.env,
|
||||||
state.manualMemoState.loc,
|
state.manualMemoState.loc,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -529,7 +529,7 @@ class Visitor extends ReactiveFunctionVisitor<VisitorState> {
|
|||||||
!this.scopes.has(identifier.scope.id) &&
|
!this.scopes.has(identifier.scope.id) &&
|
||||||
!this.prunedScopes.has(identifier.scope.id)
|
!this.prunedScopes.has(identifier.scope.id)
|
||||||
) {
|
) {
|
||||||
state.errors.pushDiagnostic(
|
state.env.recordError(
|
||||||
CompilerDiagnostic.create({
|
CompilerDiagnostic.create({
|
||||||
category: ErrorCategory.PreserveManualMemo,
|
category: ErrorCategory.PreserveManualMemo,
|
||||||
reason: 'Existing memoization could not be preserved',
|
reason: 'Existing memoization could not be preserved',
|
||||||
@@ -575,7 +575,7 @@ class Visitor extends ReactiveFunctionVisitor<VisitorState> {
|
|||||||
|
|
||||||
for (const identifier of decls) {
|
for (const identifier of decls) {
|
||||||
if (isUnmemoized(identifier, this.scopes)) {
|
if (isUnmemoized(identifier, this.scopes)) {
|
||||||
state.errors.pushDiagnostic(
|
state.env.recordError(
|
||||||
CompilerDiagnostic.create({
|
CompilerDiagnostic.create({
|
||||||
category: ErrorCategory.PreserveManualMemo,
|
category: ErrorCategory.PreserveManualMemo,
|
||||||
reason: 'Existing memoization could not be preserved',
|
reason: 'Existing memoization could not be preserved',
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
|
|
||||||
import {NodePath} from '@babel/traverse';
|
import {NodePath} from '@babel/traverse';
|
||||||
import * as t from '@babel/types';
|
import * as t from '@babel/types';
|
||||||
import {CompilerDiagnostic, CompilerError, ErrorCategory} from '..';
|
import {CompilerDiagnostic, ErrorCategory} from '..';
|
||||||
import {CodegenFunction} from '../ReactiveScopes';
|
import {CodegenFunction} from '../ReactiveScopes';
|
||||||
import {Environment} from '../HIR/Environment';
|
import {Environment} from '../HIR/Environment';
|
||||||
|
|
||||||
@@ -125,8 +125,6 @@ export function validateSourceLocations(
|
|||||||
generatedAst: CodegenFunction,
|
generatedAst: CodegenFunction,
|
||||||
env: Environment,
|
env: Environment,
|
||||||
): void {
|
): void {
|
||||||
const errors = new CompilerError();
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Step 1: Collect important locations from the original source
|
* Step 1: Collect important locations from the original source
|
||||||
* Note: Multiple node types can share the same location (e.g. VariableDeclarator and Identifier)
|
* Note: Multiple node types can share the same location (e.g. VariableDeclarator and Identifier)
|
||||||
@@ -241,7 +239,7 @@ export function validateSourceLocations(
|
|||||||
loc: t.SourceLocation,
|
loc: t.SourceLocation,
|
||||||
nodeType: string,
|
nodeType: string,
|
||||||
): void => {
|
): void => {
|
||||||
errors.pushDiagnostic(
|
env.recordError(
|
||||||
CompilerDiagnostic.create({
|
CompilerDiagnostic.create({
|
||||||
category: ErrorCategory.Todo,
|
category: ErrorCategory.Todo,
|
||||||
reason: 'Important source location missing in generated code',
|
reason: 'Important source location missing in generated code',
|
||||||
@@ -261,7 +259,7 @@ export function validateSourceLocations(
|
|||||||
expectedType: string,
|
expectedType: string,
|
||||||
actualTypes: Set<string>,
|
actualTypes: Set<string>,
|
||||||
): void => {
|
): void => {
|
||||||
errors.pushDiagnostic(
|
env.recordError(
|
||||||
CompilerDiagnostic.create({
|
CompilerDiagnostic.create({
|
||||||
category: ErrorCategory.Todo,
|
category: ErrorCategory.Todo,
|
||||||
reason:
|
reason:
|
||||||
@@ -309,6 +307,4 @@ export function validateSourceLocations(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
env.recordErrors(errors);
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,13 +16,13 @@ import {
|
|||||||
IdentifierId,
|
IdentifierId,
|
||||||
SourceLocation,
|
SourceLocation,
|
||||||
} from '../HIR';
|
} from '../HIR';
|
||||||
|
import {Environment} from '../HIR/Environment';
|
||||||
import {
|
import {
|
||||||
eachInstructionValueOperand,
|
eachInstructionValueOperand,
|
||||||
eachTerminalOperand,
|
eachTerminalOperand,
|
||||||
} from '../HIR/visitors';
|
} from '../HIR/visitors';
|
||||||
|
|
||||||
export function validateUseMemo(fn: HIRFunction): void {
|
export function validateUseMemo(fn: HIRFunction): void {
|
||||||
const errors = new CompilerError();
|
|
||||||
const voidMemoErrors = new CompilerError();
|
const voidMemoErrors = new CompilerError();
|
||||||
const useMemos = new Set<IdentifierId>();
|
const useMemos = new Set<IdentifierId>();
|
||||||
const react = new Set<IdentifierId>();
|
const react = new Set<IdentifierId>();
|
||||||
@@ -90,7 +90,7 @@ export function validateUseMemo(fn: HIRFunction): void {
|
|||||||
firstParam.kind === 'Identifier'
|
firstParam.kind === 'Identifier'
|
||||||
? firstParam.loc
|
? firstParam.loc
|
||||||
: firstParam.place.loc;
|
: firstParam.place.loc;
|
||||||
errors.pushDiagnostic(
|
fn.env.recordError(
|
||||||
CompilerDiagnostic.create({
|
CompilerDiagnostic.create({
|
||||||
category: ErrorCategory.UseMemo,
|
category: ErrorCategory.UseMemo,
|
||||||
reason: 'useMemo() callbacks may not accept parameters',
|
reason: 'useMemo() callbacks may not accept parameters',
|
||||||
@@ -106,7 +106,7 @@ export function validateUseMemo(fn: HIRFunction): void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (body.loweredFunc.func.async || body.loweredFunc.func.generator) {
|
if (body.loweredFunc.func.async || body.loweredFunc.func.generator) {
|
||||||
errors.pushDiagnostic(
|
fn.env.recordError(
|
||||||
CompilerDiagnostic.create({
|
CompilerDiagnostic.create({
|
||||||
category: ErrorCategory.UseMemo,
|
category: ErrorCategory.UseMemo,
|
||||||
reason:
|
reason:
|
||||||
@@ -122,7 +122,7 @@ export function validateUseMemo(fn: HIRFunction): void {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
validateNoContextVariableAssignment(body.loweredFunc.func, errors);
|
validateNoContextVariableAssignment(body.loweredFunc.func, fn.env);
|
||||||
|
|
||||||
if (fn.env.config.validateNoVoidUseMemo) {
|
if (fn.env.config.validateNoVoidUseMemo) {
|
||||||
if (!hasNonVoidReturn(body.loweredFunc.func)) {
|
if (!hasNonVoidReturn(body.loweredFunc.func)) {
|
||||||
@@ -176,14 +176,11 @@ export function validateUseMemo(fn: HIRFunction): void {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn.env.logErrors(voidMemoErrors.asResult());
|
fn.env.logErrors(voidMemoErrors.asResult());
|
||||||
if (errors.hasAnyErrors()) {
|
|
||||||
fn.env.recordErrors(errors);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function validateNoContextVariableAssignment(
|
function validateNoContextVariableAssignment(
|
||||||
fn: HIRFunction,
|
fn: HIRFunction,
|
||||||
errors: CompilerError,
|
env: Environment,
|
||||||
): void {
|
): void {
|
||||||
const context = new Set(fn.context.map(place => place.identifier.id));
|
const context = new Set(fn.context.map(place => place.identifier.id));
|
||||||
for (const block of fn.body.blocks.values()) {
|
for (const block of fn.body.blocks.values()) {
|
||||||
@@ -192,7 +189,7 @@ function validateNoContextVariableAssignment(
|
|||||||
switch (value.kind) {
|
switch (value.kind) {
|
||||||
case 'StoreContext': {
|
case 'StoreContext': {
|
||||||
if (context.has(value.lvalue.place.identifier.id)) {
|
if (context.has(value.lvalue.place.identifier.id)) {
|
||||||
errors.pushDiagnostic(
|
env.recordError(
|
||||||
CompilerDiagnostic.create({
|
CompilerDiagnostic.create({
|
||||||
category: ErrorCategory.UseMemo,
|
category: ErrorCategory.UseMemo,
|
||||||
reason:
|
reason:
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ function Component({prop1, bar}) {
|
|||||||
## Code
|
## Code
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
import { c as _c, useFire } from "react/compiler-runtime"; // @validateNoCapitalizedCalls @enableFire @panicThreshold:"none"
|
import { useFire } from "react/compiler-runtime"; // @validateNoCapitalizedCalls @enableFire @panicThreshold:"none"
|
||||||
import { fire } from "react";
|
import { fire } from "react";
|
||||||
const CapitalizedCall = require("shared-runtime").sum;
|
const CapitalizedCall = require("shared-runtime").sum;
|
||||||
|
|
||||||
|
|||||||
@@ -68,7 +68,7 @@ function NonFireComponent({ prop1 }) {
|
|||||||
function FireComponent(props) {
|
function FireComponent(props) {
|
||||||
const $ = _c(3);
|
const $ = _c(3);
|
||||||
|
|
||||||
const foo = _temp3;
|
const foo = _temp;
|
||||||
const t0 = useFire(foo);
|
const t0 = useFire(foo);
|
||||||
let t1;
|
let t1;
|
||||||
if ($[0] !== props || $[1] !== t0) {
|
if ($[0] !== props || $[1] !== t0) {
|
||||||
@@ -85,7 +85,7 @@ function FireComponent(props) {
|
|||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
function _temp3(props_0) {
|
function _temp(props_0) {
|
||||||
console.log(props_0);
|
console.log(props_0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ function Component(props) {
|
|||||||
## Code
|
## Code
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
import { c as _c, useFire } from "react/compiler-runtime"; // @enableFire @panicThreshold:"none"
|
import { useFire } from "react/compiler-runtime"; // @enableFire @panicThreshold:"none"
|
||||||
import { fire, useEffect } from "react";
|
import { fire, useEffect } from "react";
|
||||||
import { Stringify } from "shared-runtime";
|
import { Stringify } from "shared-runtime";
|
||||||
|
|
||||||
@@ -38,7 +38,7 @@ import { Stringify } from "shared-runtime";
|
|||||||
* hook usage) disabled
|
* hook usage) disabled
|
||||||
*/
|
*/
|
||||||
function Component(props) {
|
function Component(props) {
|
||||||
const foo = _temp2;
|
const foo = _temp;
|
||||||
|
|
||||||
if (props.cond) {
|
if (props.cond) {
|
||||||
const t0 = useFire(foo);
|
const t0 = useFire(foo);
|
||||||
@@ -49,7 +49,7 @@ function Component(props) {
|
|||||||
|
|
||||||
return <Stringify />;
|
return <Stringify />;
|
||||||
}
|
}
|
||||||
function _temp2(props_0) {
|
function _temp(props_0) {
|
||||||
console.log(props_0);
|
console.log(props_0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -23,15 +23,14 @@ function Component(props, useDynamicHook) {
|
|||||||
## Code
|
## Code
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
import { $dispatcherGuard } from "react-compiler-runtime";
|
import { useFire } from "react/compiler-runtime";
|
||||||
import { c as _c, useFire } from "react/compiler-runtime";
|
|
||||||
import { useEffect, fire } from "react";
|
import { useEffect, fire } from "react";
|
||||||
|
|
||||||
function Component(props, useDynamicHook) {
|
function Component(props, useDynamicHook) {
|
||||||
"use memo";
|
"use memo";
|
||||||
|
|
||||||
useDynamicHook();
|
useDynamicHook();
|
||||||
const foo = _temp2;
|
const foo = _temp;
|
||||||
const t0 = useFire(foo);
|
const t0 = useFire(foo);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -40,7 +39,7 @@ function Component(props, useDynamicHook) {
|
|||||||
|
|
||||||
return <div>hello world</div>;
|
return <div>hello world</div>;
|
||||||
}
|
}
|
||||||
function _temp2(props_0) {
|
function _temp(props_0) {
|
||||||
console.log(props_0);
|
console.log(props_0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user