@@ -51116,20 +51116,84 @@ function validateNoSetStateInEffects(fn, env) {
5111651116 return errors.asResult();
5111751117}
5111851118function getSetStateCall(fn, setStateFunctions, env) {
51119+ const enableAllowSetStateFromRefsInEffects = env.config.enableAllowSetStateFromRefsInEffects;
5111951120 const refDerivedValues = new Set();
5112051121 const isDerivedFromRef = (place) => {
5112151122 return (refDerivedValues.has(place.identifier.id) ||
5112251123 isUseRefType(place.identifier) ||
5112351124 isRefValueType(place.identifier));
5112451125 };
51126+ const isRefControlledBlock = enableAllowSetStateFromRefsInEffects
51127+ ? createControlDominators(fn, place => isDerivedFromRef(place))
51128+ : () => false;
5112551129 for (const [, block] of fn.body.blocks) {
51130+ if (enableAllowSetStateFromRefsInEffects) {
51131+ for (const phi of block.phis) {
51132+ if (isDerivedFromRef(phi.place)) {
51133+ continue;
51134+ }
51135+ let isPhiDerivedFromRef = false;
51136+ for (const [, operand] of phi.operands) {
51137+ if (isDerivedFromRef(operand)) {
51138+ isPhiDerivedFromRef = true;
51139+ break;
51140+ }
51141+ }
51142+ if (isPhiDerivedFromRef) {
51143+ refDerivedValues.add(phi.place.identifier.id);
51144+ }
51145+ else {
51146+ for (const [pred] of phi.operands) {
51147+ if (isRefControlledBlock(pred)) {
51148+ refDerivedValues.add(phi.place.identifier.id);
51149+ break;
51150+ }
51151+ }
51152+ }
51153+ }
51154+ }
5112651155 for (const instr of block.instructions) {
51127- if (env.config. enableAllowSetStateFromRefsInEffects) {
51156+ if (enableAllowSetStateFromRefsInEffects) {
5112851157 const hasRefOperand = Iterable_some(eachInstructionValueOperand(instr.value), isDerivedFromRef);
5112951158 if (hasRefOperand) {
5113051159 for (const lvalue of eachInstructionLValue(instr)) {
5113151160 refDerivedValues.add(lvalue.identifier.id);
5113251161 }
51162+ for (const operand of eachInstructionValueOperand(instr.value)) {
51163+ switch (operand.effect) {
51164+ case Effect.Capture:
51165+ case Effect.Store:
51166+ case Effect.ConditionallyMutate:
51167+ case Effect.ConditionallyMutateIterator:
51168+ case Effect.Mutate: {
51169+ if (isMutable(instr, operand)) {
51170+ refDerivedValues.add(operand.identifier.id);
51171+ }
51172+ break;
51173+ }
51174+ case Effect.Freeze:
51175+ case Effect.Read: {
51176+ break;
51177+ }
51178+ case Effect.Unknown: {
51179+ CompilerError.invariant(false, {
51180+ reason: 'Unexpected unknown effect',
51181+ description: null,
51182+ details: [
51183+ {
51184+ kind: 'error',
51185+ loc: operand.loc,
51186+ message: null,
51187+ },
51188+ ],
51189+ suggestions: null,
51190+ });
51191+ }
51192+ default: {
51193+ assertExhaustive$1(operand.effect, `Unexpected effect kind \`${operand.effect}\``);
51194+ }
51195+ }
51196+ }
5113351197 }
5113451198 if (instr.value.kind === 'PropertyLoad' &&
5113551199 instr.value.property === 'current' &&
@@ -51156,13 +51220,16 @@ function getSetStateCall(fn, setStateFunctions, env) {
5115651220 const callee = instr.value.callee;
5115751221 if (isSetStateType(callee.identifier) ||
5115851222 setStateFunctions.has(callee.identifier.id)) {
51159- if (env.config. enableAllowSetStateFromRefsInEffects) {
51223+ if (enableAllowSetStateFromRefsInEffects) {
5116051224 const arg = instr.value.args.at(0);
5116151225 if (arg !== undefined &&
5116251226 arg.kind === 'Identifier' &&
5116351227 refDerivedValues.has(arg.identifier.id)) {
5116451228 return null;
5116551229 }
51230+ else if (isRefControlledBlock(block.id)) {
51231+ continue;
51232+ }
5116651233 }
5116751234 return callee;
5116851235 }
0 commit comments