Skip to content

[compiler] Further improve new range inference #33411

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 14 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,14 @@ export class CompilerErrorDetail {
export class CompilerError extends Error {
details: Array<CompilerErrorDetail> = [];

static from(details: Array<CompilerErrorDetailOptions>): CompilerError {
const error = new CompilerError();
for (const detail of details) {
error.push(detail);
}
return error;
}

static invariant(
condition: unknown,
options: Omit<CompilerErrorDetailOptions, 'severity'>,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1003,6 +1003,12 @@ export function printAliasingEffect(effect: AliasingEffect): string {
case 'MutateTransitiveConditionally': {
return `${effect.kind} ${printPlaceForAliasEffect(effect.value)}`;
}
case 'MutateFrozen': {
return `MutateFrozen ${printPlaceForAliasEffect(effect.place)} reason=${JSON.stringify(effect.error.reason)}`;
}
case 'MutateGlobal': {
return `MutateGlobal ${printPlaceForAliasEffect(effect.place)} reason=${JSON.stringify(effect.error.reason)}`;
}
default: {
assertExhaustive(effect, `Unexpected kind '${(effect as any).kind}'`);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
Place,
isRefOrRefValue,
makeInstructionId,
printFunction,

Check failure on line 18 in compiler/packages/babel-plugin-react-compiler/src/Inference/AnalyseFunctions.ts

View workflow job for this annotation

GitHub Actions / Lint babel-plugin-react-compiler

'printFunction' is defined but never used. Allowed unused vars must match /^_/u
} from '../HIR';
import {deadCodeElimination} from '../Optimization';
import {inferReactiveScopeVariables} from '../ReactiveScopes';
Expand Down Expand Up @@ -72,7 +73,10 @@
value: fn,
});
const effects = inferMutationAliasingFunctionEffects(fn);
fn.aliasingEffects = effects;
if (effects != null) {
fn.aliasingEffects ??= [];
fn.aliasingEffects?.push(...effects);
}

const capturedOrMutated = new Set<IdentifierId>();
for (const effect of effects ?? []) {
Expand All @@ -97,6 +101,8 @@
capturedOrMutated.add(effect.value.identifier.id);
break;
}
case 'MutateFrozen':
case 'MutateGlobal':
case 'CreateFunction':
case 'Create':
case 'Freeze':
Expand All @@ -114,7 +120,10 @@
}

for (const operand of fn.context) {
if (capturedOrMutated.has(operand.identifier.id)) {
if (
capturedOrMutated.has(operand.identifier.id) ||
operand.effect === Effect.Capture
) {
operand.effect = Effect.Capture;
} else {
operand.effect = Effect.Read;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,13 @@
* LICENSE file in the root directory of this source tree.
*/

import {CompilerError, Effect, ValueKind} from '..';
import {
CompilerError,
CompilerErrorDetailOptions,
Effect,
ErrorSeverity,
ValueKind,
} from '..';
import {
BasicBlock,
BlockId,
Expand Down Expand Up @@ -214,11 +220,6 @@ function inferBlock(
instructionSignature = computeSignatureForInstruction(state.env, instr);
instructionSignatureCache.set(instr, instructionSignature);
}
/*
* console.log(
* printInstruction({...instr, effects: [...instructionSignature.effects]}),
* );
*/
const effects = applySignature(
state,
instructionSignature,
Expand All @@ -244,6 +245,7 @@ function applySignature(
instruction: Instruction,
effectInstructionValueCache: Map<AliasingEffect, InstructionValue>,
): Array<AliasingEffect> | null {
const effects: Array<AliasingEffect> = [];
/**
* For function instructions, eagerly validate that they aren't mutating
* a known-frozen value.
Expand All @@ -260,27 +262,33 @@ function applySignature(
for (const effect of aliasingEffects) {
if (effect.kind === 'Mutate' || effect.kind === 'MutateTransitive') {
const value = state.kind(effect.value);
if (value.kind === ValueKind.Frozen) {
if (DEBUG) {
console.log(printInstruction(instruction));
console.log(printAliasingEffect(effect));
console.log(prettyFormat(state.debugAbstractValue(value)));
switch (value.kind) {
case ValueKind.Global:
case ValueKind.Frozen: {
const reason = getWriteErrorReason({
kind: value.kind,
reason: value.reason,
context: new Set(),
});
effects.push({
kind:
value.kind === ValueKind.Frozen
? 'MutateFrozen'
: 'MutateGlobal',
place: effect.value,
error: {
severity: ErrorSeverity.InvalidReact,
reason,
description:
effect.value.identifier.name !== null &&
effect.value.identifier.name.kind === 'named'
? `Found mutation of \`${effect.value.identifier.name}\``
: null,
loc: effect.value.loc,
suggestions: null,
},
});
}
const reason = getWriteErrorReason({
kind: value.kind,
reason: value.reason,
context: new Set(),
});
CompilerError.throwInvalidReact({
reason,
description:
effect.value.identifier.name !== null &&
effect.value.identifier.name.kind === 'named'
? `Found mutation of \`${effect.value.identifier.name}\``
: null,
loc: effect.value.loc,
suggestions: null,
});
}
}
}
Expand All @@ -296,7 +304,6 @@ function applySignature(
console.log(printInstruction(instruction));
}

const effects: Array<AliasingEffect> = [];
for (const effect of signature.effects) {
applyEffect(
state,
Expand Down Expand Up @@ -429,6 +436,19 @@ function applyEffect(
}
}
});
for (const operand of effect.function.loweredFunc.func.context) {
if (operand.effect !== Effect.Capture) {
continue;
}
const kind = state.kind(operand).kind;
if (
kind === ValueKind.Primitive ||
kind == ValueKind.Frozen ||
kind == ValueKind.Global
) {
operand.effect = Effect.Read;
}
}
state.initialize(effect.function, {
kind: isMutable ? ValueKind.Mutable : ValueKind.Frozen,
reason: new Set([]),
Expand Down Expand Up @@ -742,24 +762,36 @@ function applyEffect(
console.log(printAliasingEffect(effect));
console.log(prettyFormat(state.debugAbstractValue(value)));
}

const reason = getWriteErrorReason({
kind: value.kind,
reason: value.reason,
context: new Set(),
});
CompilerError.throwInvalidReact({
reason,
description:
effect.value.identifier.name !== null &&
effect.value.identifier.name.kind === 'named'
? `Found mutation of \`${effect.value.identifier.name}\``
: null,
loc: effect.value.loc,
suggestions: null,
effects.push({
kind:
value.kind === ValueKind.Frozen ? 'MutateFrozen' : 'MutateGlobal',
place: effect.value,
error: {
severity: ErrorSeverity.InvalidReact,
reason,
description:
effect.value.identifier.name !== null &&
effect.value.identifier.name.kind === 'named'
? `Found mutation of \`${effect.value.identifier.name}\``
: null,
loc: effect.value.loc,
suggestions: null,
},
});
}
break;
}
case 'MutateFrozen':
case 'MutateGlobal': {
effects.push(effect);
break;
}
default: {
assertExhaustive(
effect,
Expand Down Expand Up @@ -933,7 +965,11 @@ class InferenceState {
kind: ValueKind.Frozen,
reason: new Set([reason]),
});
if (value.kind === 'FunctionExpression') {
if (
value.kind === 'FunctionExpression' &&
(this.env.config.enablePreserveExistingMemoizationGuarantees ||
this.env.config.enableTransitivelyFreezeFunctionExpressions)
) {
for (const place of value.loweredFunc.func.context) {
this.freeze(place, reason);
}
Expand Down Expand Up @@ -1552,15 +1588,31 @@ function computeSignatureForInstruction(
});
break;
}
case 'StartMemoize':
case 'FinishMemoize': {
if (env.config.enablePreserveExistingMemoizationGuarantees) {
for (const operand of eachInstructionValueOperand(value)) {
effects.push({
kind: 'Freeze',
value: operand,
reason: ValueReason.Other,
});
}
}
effects.push({
kind: 'Create',
into: lvalue,
value: ValueKind.Primitive,
});
break;
}
case 'TaggedTemplateExpression':
case 'BinaryExpression':
case 'Debugger':
case 'FinishMemoize':
case 'JSXText':
case 'MetaProperty':
case 'Primitive':
case 'RegExpLiteral':
case 'StartMemoize':
case 'TemplateLiteral':
case 'UnaryExpression':
case 'UnsupportedNode': {
Expand Down Expand Up @@ -1879,6 +1931,14 @@ function computeEffectsForSignature(
}
break;
}
case 'MutateFrozen':
case 'MutateGlobal': {
const values = substitutions.get(effect.place.identifier.id) ?? [];
for (const value of values) {
effects.push({kind: effect.kind, place: value, error: effect.error});
}
break;
}
case 'Mutate':
case 'MutateTransitive':
case 'MutateTransitiveConditionally':
Expand Down Expand Up @@ -2165,6 +2225,18 @@ export type AliasingEffect =
captures: Array<Place>;
function: FunctionExpression | ObjectMethod;
into: Place;
}
/**
* Mutation of a value known to be immutable
*/
| {kind: 'MutateFrozen'; place: Place; error: CompilerErrorDetailOptions}
/**
* Mutation of a global
*/
| {
kind: 'MutateGlobal';
place: Place;
error: CompilerErrorDetailOptions;
};

export type AliasingSignatureEffect = AliasingEffect;
Expand Down
Loading
Loading