[compiler] Remove now-unused FunctionEffect type (#34029)

The new mutation/aliasing model significantly expands on the idea of
FunctionEffect. The type (and its usage in HIRFunction.effects) was only
necessary for the now-deleted old inference model so we can clean up
this code now.
This commit is contained in:
Joseph Savona 2025-08-15 15:27:30 -07:00 committed by GitHub
parent eaf6adb127
commit 5063b3283f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 11 additions and 64 deletions

View File

@ -7,7 +7,7 @@
import {BindingKind} from '@babel/traverse'; import {BindingKind} from '@babel/traverse';
import * as t from '@babel/types'; import * as t from '@babel/types';
import {CompilerError, CompilerErrorDetailOptions} from '../CompilerError'; import {CompilerError} from '../CompilerError';
import {assertExhaustive} from '../Utils/utils'; import {assertExhaustive} from '../Utils/utils';
import {Environment, ReactFunctionType} from './Environment'; import {Environment, ReactFunctionType} from './Environment';
import type {HookKind} from './ObjectShape'; import type {HookKind} from './ObjectShape';
@ -282,30 +282,13 @@ export type HIRFunction = {
returnTypeAnnotation: t.FlowType | t.TSType | null; returnTypeAnnotation: t.FlowType | t.TSType | null;
returns: Place; returns: Place;
context: Array<Place>; context: Array<Place>;
effects: Array<FunctionEffect> | null;
body: HIR; body: HIR;
generator: boolean; generator: boolean;
async: boolean; async: boolean;
directives: Array<string>; directives: Array<string>;
aliasingEffects?: Array<AliasingEffect> | null; aliasingEffects: Array<AliasingEffect> | null;
}; };
export type FunctionEffect =
| {
kind: 'GlobalMutation';
error: CompilerErrorDetailOptions;
}
| {
kind: 'ReactMutation';
error: CompilerErrorDetailOptions;
}
| {
kind: 'ContextMutation';
places: ReadonlySet<Place>;
effect: Effect;
loc: SourceLocation;
};
/* /*
* Each reactive scope may have its own control-flow, so the instructions form * Each reactive scope may have its own control-flow, so the instructions form
* a control-flow graph. The graph comprises a set of basic blocks which reference * a control-flow graph. The graph comprises a set of basic blocks which reference

View File

@ -554,23 +554,11 @@ export function printInstructionValue(instrValue: ReactiveValue): string {
const context = instrValue.loweredFunc.func.context const context = instrValue.loweredFunc.func.context
.map(dep => printPlace(dep)) .map(dep => printPlace(dep))
.join(','); .join(',');
const effects =
instrValue.loweredFunc.func.effects
?.map(effect => {
if (effect.kind === 'ContextMutation') {
return `ContextMutation places=[${[...effect.places]
.map(place => printPlace(place))
.join(', ')}] effect=${effect.effect}`;
} else {
return `GlobalMutation`;
}
})
.join(', ') ?? '';
const aliasingEffects = const aliasingEffects =
instrValue.loweredFunc.func.aliasingEffects instrValue.loweredFunc.func.aliasingEffects
?.map(printAliasingEffect) ?.map(printAliasingEffect)
?.join(', ') ?? ''; ?.join(', ') ?? '';
value = `${kind} ${name} @context[${context}] @effects[${effects}] @aliasingEffects=[${aliasingEffects}]\n${fn}`; value = `${kind} ${name} @context[${context}] @aliasingEffects=[${aliasingEffects}]\n${fn}`;
break; break;
} }
case 'TaggedTemplateExpression': { case 'TaggedTemplateExpression': {

View File

@ -255,7 +255,6 @@ function emitSelectorFn(env: Environment, keys: Array<string>): Instruction {
returnTypeAnnotation: null, returnTypeAnnotation: null,
returns: createTemporaryPlace(env, GeneratedSource), returns: createTemporaryPlace(env, GeneratedSource),
context: [], context: [],
effects: null,
body: { body: {
entry: block.id, entry: block.id,
blocks: new Map([[block.id, block]]), blocks: new Map([[block.id, block]]),
@ -263,6 +262,7 @@ function emitSelectorFn(env: Environment, keys: Array<string>): Instruction {
generator: false, generator: false,
async: false, async: false,
directives: [], directives: [],
aliasingEffects: [],
}; };
reversePostorderBlocks(fn.body); reversePostorderBlocks(fn.body);

View File

@ -370,7 +370,6 @@ function emitOutlinedFn(
returnTypeAnnotation: null, returnTypeAnnotation: null,
returns: createTemporaryPlace(env, GeneratedSource), returns: createTemporaryPlace(env, GeneratedSource),
context: [], context: [],
effects: null,
body: { body: {
entry: block.id, entry: block.id,
blocks: new Map([[block.id, block]]), blocks: new Map([[block.id, block]]),
@ -378,6 +377,7 @@ function emitOutlinedFn(
generator: false, generator: false,
async: false, async: false,
directives: [], directives: [],
aliasingEffects: [],
}; };
return fn; return fn;
} }

View File

@ -7,10 +7,8 @@
import {CompilerDiagnostic, CompilerError, Effect, ErrorSeverity} from '..'; import {CompilerDiagnostic, CompilerError, Effect, ErrorSeverity} from '..';
import { import {
FunctionEffect,
HIRFunction, HIRFunction,
IdentifierId, IdentifierId,
isMutableEffect,
isRefOrRefLikeMutableType, isRefOrRefLikeMutableType,
Place, Place,
} from '../HIR'; } from '../HIR';
@ -18,8 +16,8 @@ import {
eachInstructionValueOperand, eachInstructionValueOperand,
eachTerminalOperand, eachTerminalOperand,
} from '../HIR/visitors'; } from '../HIR/visitors';
import {AliasingEffect} from '../Inference/AliasingEffects';
import {Result} from '../Utils/Result'; import {Result} from '../Utils/Result';
import {Iterable_some} from '../Utils/utils';
/** /**
* Validates that functions with known mutations (ie due to types) cannot be passed * Validates that functions with known mutations (ie due to types) cannot be passed
@ -50,14 +48,14 @@ export function validateNoFreezingKnownMutableFunctions(
const errors = new CompilerError(); const errors = new CompilerError();
const contextMutationEffects: Map< const contextMutationEffects: Map<
IdentifierId, IdentifierId,
Extract<FunctionEffect, {kind: 'ContextMutation'}> Extract<AliasingEffect, {kind: 'Mutate'} | {kind: 'MutateTransitive'}>
> = new Map(); > = new Map();
function visitOperand(operand: Place): void { function visitOperand(operand: Place): void {
if (operand.effect === Effect.Freeze) { if (operand.effect === Effect.Freeze) {
const effect = contextMutationEffects.get(operand.identifier.id); const effect = contextMutationEffects.get(operand.identifier.id);
if (effect != null) { if (effect != null) {
const place = [...effect.places][0]; const place = effect.value;
const variable = const variable =
place != null && place != null &&
place.identifier.name != null && place.identifier.name != null &&
@ -77,7 +75,7 @@ export function validateNoFreezingKnownMutableFunctions(
}) })
.withDetail({ .withDetail({
kind: 'error', kind: 'error',
loc: effect.loc, loc: effect.value.loc,
message: `This modifies ${variable}`, message: `This modifies ${variable}`,
}), }),
); );
@ -108,24 +106,7 @@ export function validateNoFreezingKnownMutableFunctions(
break; break;
} }
case 'FunctionExpression': { case 'FunctionExpression': {
const knownMutation = (value.loweredFunc.func.effects ?? []).find( if (value.loweredFunc.func.aliasingEffects != null) {
effect => {
return (
effect.kind === 'ContextMutation' &&
(effect.effect === Effect.Store ||
effect.effect === Effect.Mutate) &&
Iterable_some(effect.places, place => {
return (
isMutableEffect(place.effect, place.loc) &&
!isRefOrRefLikeMutableType(place.identifier.type)
);
})
);
},
);
if (knownMutation && knownMutation.kind === 'ContextMutation') {
contextMutationEffects.set(lvalue.identifier.id, knownMutation);
} else if (value.loweredFunc.func.aliasingEffects != null) {
const context = new Set( const context = new Set(
value.loweredFunc.func.context.map(p => p.identifier.id), value.loweredFunc.func.context.map(p => p.identifier.id),
); );
@ -146,12 +127,7 @@ export function validateNoFreezingKnownMutableFunctions(
context.has(effect.value.identifier.id) && context.has(effect.value.identifier.id) &&
!isRefOrRefLikeMutableType(effect.value.identifier.type) !isRefOrRefLikeMutableType(effect.value.identifier.type)
) { ) {
contextMutationEffects.set(lvalue.identifier.id, { contextMutationEffects.set(lvalue.identifier.id, effect);
kind: 'ContextMutation',
effect: Effect.Mutate,
loc: effect.value.loc,
places: new Set([effect.value]),
});
break effects; break effects;
} }
break; break;