InferReferenceEffects uses function types for CallExpression

Updates the InferReferenceEffects logic for CallExpression to work similarly to 
MethodCall, where we take into account the function signature (if present) when 
inferring the effects and return kind.
This commit is contained in:
Joe Savona
2023-05-18 15:52:11 -07:00
parent c0a5d86902
commit 0322e4dbd4
5 changed files with 90 additions and 43 deletions
+8 -6
View File
@@ -538,6 +538,13 @@ export type MethodCall = {
loc: SourceLocation;
};
export type CallExpression = {
kind: "CallExpression";
callee: Place;
args: Array<Place | SpreadPattern>;
loc: SourceLocation;
};
/**
* The value of a given instruction. Note that values are not recursive: complex
* values such as objects or arrays are always defined by instructions to define
@@ -605,12 +612,7 @@ export type InstructionValue =
args: Array<Place | SpreadPattern>;
loc: SourceLocation;
}
| {
kind: "CallExpression";
callee: Place;
args: Array<Place | SpreadPattern>;
loc: SourceLocation;
}
| CallExpression
| MethodCall
| {
kind: "UnaryExpression";
@@ -11,6 +11,7 @@ import { Environment } from "../HIR";
import {
BasicBlock,
BlockId,
CallExpression,
Effect,
HIRFunction,
IdentifierId,
@@ -707,8 +708,6 @@ function inferBlock(
continue;
}
case "CallExpression": {
valueKind = ValueKind.Mutable;
effectKind = Effect.Mutate;
const hook =
instrValue.callee.identifier.type.kind === "Hook"
? instrValue.callee.identifier.type.definition
@@ -716,8 +715,42 @@ function inferBlock(
if (hook !== null) {
effectKind = hook.effectKind;
valueKind = hook.valueKind;
break;
}
break;
const signature = getFunctionCallSignature(
env,
instrValue.callee.identifier.type
);
const effects =
signature !== null
? getMethodCallEffects(instrValue, signature)
: null;
for (let i = 0; i < instrValue.args.length; i++) {
const arg = instrValue.args[i];
const place = arg.kind === "Identifier" ? arg : arg.place;
if (effects !== null) {
// If effects are inferred for an argument, we should fail invalid
// mutating effects
state.referenceAndCheckError(place, effects[i]);
} else {
state.reference(place, Effect.Mutate);
}
}
if (signature !== null) {
state.referenceAndCheckError(
instrValue.callee,
signature.calleeEffect
);
} else {
state.reference(instrValue.callee, Effect.Mutate);
}
state.initialize(instrValue, ValueKind.Mutable);
state.define(instr.lvalue, instrValue);
instr.lvalue.effect = Effect.Mutate;
continue;
}
case "MethodCall": {
invariant(
@@ -1003,7 +1036,7 @@ function getFunctionCallSignature(
* @returns Inferred effects of function arguments, or null if inference fails.
*/
function getMethodCallEffects(
fn: MethodCall,
fn: MethodCall | CallExpression,
sig: FunctionSignature
): Array<Effect> | null {
const results = [];
@@ -17,25 +17,29 @@ import { unstable_useMemoCache as useMemoCache } from "react";
function Component(props) {
const $ = useMemoCache(3);
let t0;
let x;
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
x = {};
t0 = Boolean(x);
t0 = {};
$[0] = t0;
$[1] = x;
} else {
t0 = $[0];
x = $[1];
}
const y = t0;
const x = t0;
let t1;
if ($[2] === Symbol.for("react.memo_cache_sentinel")) {
t1 = [x, y];
$[2] = t1;
if ($[1] === Symbol.for("react.memo_cache_sentinel")) {
t1 = Boolean(x);
$[1] = t1;
} else {
t1 = $[2];
t1 = $[1];
}
return t1;
const y = t1;
let t2;
if ($[2] === Symbol.for("react.memo_cache_sentinel")) {
t2 = [x, y];
$[2] = t2;
} else {
t2 = $[2];
}
return t2;
}
```
@@ -17,25 +17,29 @@ import { unstable_useMemoCache as useMemoCache } from "react";
function Component(props) {
const $ = useMemoCache(3);
let t0;
let x;
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
x = {};
t0 = Number(x);
t0 = {};
$[0] = t0;
$[1] = x;
} else {
t0 = $[0];
x = $[1];
}
const y = t0;
const x = t0;
let t1;
if ($[2] === Symbol.for("react.memo_cache_sentinel")) {
t1 = [x, y];
$[2] = t1;
if ($[1] === Symbol.for("react.memo_cache_sentinel")) {
t1 = Number(x);
$[1] = t1;
} else {
t1 = $[2];
t1 = $[1];
}
return t1;
const y = t1;
let t2;
if ($[2] === Symbol.for("react.memo_cache_sentinel")) {
t2 = [x, y];
$[2] = t2;
} else {
t2 = $[2];
}
return t2;
}
```
@@ -17,25 +17,29 @@ import { unstable_useMemoCache as useMemoCache } from "react";
function Component(props) {
const $ = useMemoCache(3);
let t0;
let x;
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
x = {};
t0 = String(x);
t0 = {};
$[0] = t0;
$[1] = x;
} else {
t0 = $[0];
x = $[1];
}
const y = t0;
const x = t0;
let t1;
if ($[2] === Symbol.for("react.memo_cache_sentinel")) {
t1 = [x, y];
$[2] = t1;
if ($[1] === Symbol.for("react.memo_cache_sentinel")) {
t1 = String(x);
$[1] = t1;
} else {
t1 = $[2];
t1 = $[1];
}
return t1;
const y = t1;
let t2;
if ($[2] === Symbol.for("react.memo_cache_sentinel")) {
t2 = [x, y];
$[2] = t2;
} else {
t2 = $[2];
}
return t2;
}
```