8
import {CompilerError, Effect} from '..';
9
import {HIRFunction, IdentifierId, Place} from '../HIR';
10
import {
11
+ eachInstructionLValue,
12
eachInstructionValueOperand,
13
eachTerminalOperand,
14
} from '../HIR/visitors';
15
+import {getFunctionCallSignature} from '../Inference/InferReferenceEffects';
16
17
/**
18
* Validates that local variables cannot be reassigned after render.
133
break;
134
}
135
default: {
134
- for (const operand of eachInstructionValueOperand(value)) {
136
+ let operands = eachInstructionValueOperand(value);
137
+ // If we're calling a function that doesn't let its arguments escape, only test the callee
138
+ if (value.kind === 'CallExpression') {
139
+ const signature = getFunctionCallSignature(
140
+ fn.env,
141
+ value.callee.identifier.type,
142
+ );
143
+ if (signature?.noAlias) {
144
+ operands = [value.callee];
145
+ }
146
+ } else if (value.kind === 'MethodCall') {
147
+ const signature = getFunctionCallSignature(
148
+ fn.env,
149
+ value.property.identifier.type,
150
+ );
151
+ if (signature?.noAlias) {
152
+ operands = [value.receiver, value.property];
153
+ }
154
+ }
155
+ for (const operand of operands) {
156
CompilerError.invariant(operand.effect !== Effect.Unknown, {
157
reason: `Expected effects to be inferred prior to ValidateLocalsNotReassignedAfterRender`,
158
loc: operand.loc,
160
const reassignment = reassigningFunctions.get(
161
operand.identifier.id,
162
);
142
- if (
143
- reassignment !== undefined &&
144
- operand.effect === Effect.Freeze
145
- ) {
163
+ if (reassignment !== undefined) {
164
/*
165
* Functions that reassign local variables are inherently mutable and are unsafe to pass
166
* to a place that expects a frozen value. Propagate the reassignment upward.
167
*/
150
- return reassignment;
168
+ if (operand.effect === Effect.Freeze) {
169
+ return reassignment;
170
+ } else {
171
+ /*
172
+ * If the operand is not frozen but it does reassign, then the lvalues
173
+ * of the instruction could also be reassigning
174
+ */
175
+ for (const lval of eachInstructionLValue(instr)) {
176
+ reassigningFunctions.set(lval.identifier.id, reassignment);
177
+ }
178
+ }
179
}
180
}
181
break;