[compiler][be] Refactor similar CallExpression and MethodCall effect handling (#32696)
Simplify InferReferenceEffect function signature matching logic for next PRs in stack --- [//]: # (BEGIN SAPLING FOOTER) Stack created with [Sapling](https://sapling-scm.com). Best reviewed with [ReviewStack](https://reviewstack.dev/facebook/react/pull/32696). * #32698 * #32697 * __->__ #32696 * #32695
mofeiZ committed
Mar 23, 2025 at 23:07 UTC
45463ab3ac3ed0e65dfdbbfd5e53a50a8384e909
1 file changed
+113
-150
compiler/packages/babel-plugin-react-compiler/src/Inference/InferReferenceEffects.ts
+113
-150
@@ -23,6 +23,7 @@ import {
23
Phi,
24
Place,
25
SpreadPattern,
26
+ TInstruction,
27
Type,
28
ValueKind,
29
ValueReason,
@@ -1238,62 +1239,12 @@ function inferBlock(
1239
break;
1240
}
1241
case 'CallExpression': {
1241
- const signature = getFunctionCallSignature(
1242
- env,
1243
- instrValue.callee.identifier.type,
1242
+ inferCallEffects(
1243
+ state,
1244
+ instr as TInstruction<CallExpression>,
1245
+ freezeActions,
1246
+ getFunctionCallSignature(env, instrValue.callee.identifier.type),
1247
);
1245
-
1246
- const effects =
1247
- signature !== null ? getFunctionEffects(instrValue, signature) : null;
1248
- const returnValueKind: AbstractValue =
1249
- signature !== null
1250
- ? {
1251
- kind: signature.returnValueKind,
1252
- reason: new Set([
1253
- signature.returnValueReason ??
1254
- ValueReason.KnownReturnSignature,
1255
- ]),
1256
- context: new Set(),
1257
- }
1258
- : {
1259
- kind: ValueKind.Mutable,
1260
- reason: new Set([ValueReason.Other]),
1261
- context: new Set(),
1262
- };
1263
- let hasCaptureArgument = false;
1264
- for (let i = 0; i < instrValue.args.length; i++) {
1265
- const arg = instrValue.args[i];
1266
- const place = arg.kind === 'Identifier' ? arg : arg.place;
1267
- state.referenceAndRecordEffects(
1268
- freezeActions,
1269
- place,
1270
- getArgumentEffect(effects != null ? effects[i] : null, arg),
1271
- ValueReason.Other,
1272
- );
1273
- hasCaptureArgument ||= place.effect === Effect.Capture;
1274
- }
1275
- if (signature !== null) {
1276
- state.referenceAndRecordEffects(
1277
- freezeActions,
1278
- instrValue.callee,
1279
- signature.calleeEffect,
1280
- ValueReason.Other,
1281
- );
1282
- } else {
1283
- state.referenceAndRecordEffects(
1284
- freezeActions,
1285
- instrValue.callee,
1286
- Effect.ConditionallyMutate,
1287
- ValueReason.Other,
1288
- );
1289
- }
1290
- hasCaptureArgument ||= instrValue.callee.effect === Effect.Capture;
1291
-
1292
- state.initialize(instrValue, returnValueKind);
1293
- state.define(instr.lvalue, instrValue);
1294
- instr.lvalue.effect = hasCaptureArgument
1295
- ? Effect.Store
1296
- : Effect.ConditionallyMutate;
1248
continuation = {kind: 'funeffects'};
1249
break;
1250
}
@@ -1311,102 +1262,12 @@ function inferBlock(
1262
Effect.Read,
1263
ValueReason.Other,
1264
);
1314
-
1315
- const signature = getFunctionCallSignature(
1316
- env,
1317
- instrValue.property.identifier.type,
1265
+ inferCallEffects(
1266
+ state,
1267
+ instr as TInstruction<MethodCall>,
1268
+ freezeActions,
1269
+ getFunctionCallSignature(env, instrValue.property.identifier.type),
1270
);
1319
-
1320
- const returnValueKind: AbstractValue =
1321
- signature !== null
1322
- ? {
1323
- kind: signature.returnValueKind,
1324
- reason: new Set([
1325
- signature.returnValueReason ??
1326
- ValueReason.KnownReturnSignature,
1327
- ]),
1328
- context: new Set(),
1329
- }
1330
- : {
1331
- kind: ValueKind.Mutable,
1332
- reason: new Set([ValueReason.Other]),
1333
- context: new Set(),
1334
- };
1335
-
1336
- if (
1337
- signature !== null &&
1338
- signature.mutableOnlyIfOperandsAreMutable &&
1339
- areArgumentsImmutableAndNonMutating(state, instrValue.args)
1340
- ) {
1341
- /*
1342
- * None of the args are mutable or mutate their params, we can downgrade to
1343
- * treating as all reads (except that the receiver may be captured)
1344
- */
1345
- for (const arg of instrValue.args) {
1346
- const place = arg.kind === 'Identifier' ? arg : arg.place;
1347
- state.referenceAndRecordEffects(
1348
- freezeActions,
1349
- place,
1350
- Effect.Read,
1351
- ValueReason.Other,
1352
- );
1353
- }
1354
- state.referenceAndRecordEffects(
1355
- freezeActions,
1356
- instrValue.receiver,
1357
- Effect.Capture,
1358
- ValueReason.Other,
1359
- );
1360
- state.initialize(instrValue, returnValueKind);
1361
- state.define(instr.lvalue, instrValue);
1362
- instr.lvalue.effect =
1363
- instrValue.receiver.effect === Effect.Capture
1364
- ? Effect.Store
1365
- : Effect.ConditionallyMutate;
1366
- continuation = {kind: 'funeffects'};
1367
- break;
1368
- }
1369
-
1370
- const effects =
1371
- signature !== null ? getFunctionEffects(instrValue, signature) : null;
1372
- let hasCaptureArgument = false;
1373
- for (let i = 0; i < instrValue.args.length; i++) {
1374
- const arg = instrValue.args[i];
1375
- const place = arg.kind === 'Identifier' ? arg : arg.place;
1376
- /*
1377
- * If effects are inferred for an argument, we should fail invalid
1378
- * mutating effects
1379
- */
1380
- state.referenceAndRecordEffects(
1381
- freezeActions,
1382
- place,
1383
- getArgumentEffect(effects != null ? effects[i] : null, arg),
1384
- ValueReason.Other,
1385
- );
1386
- hasCaptureArgument ||= place.effect === Effect.Capture;
1387
- }
1388
- if (signature !== null) {
1389
- state.referenceAndRecordEffects(
1390
- freezeActions,
1391
- instrValue.receiver,
1392
- signature.calleeEffect,
1393
- ValueReason.Other,
1394
- );
1395
- } else {
1396
- state.referenceAndRecordEffects(
1397
- freezeActions,
1398
- instrValue.receiver,
1399
- Effect.ConditionallyMutate,
1400
- ValueReason.Other,
1401
- );
1402
- }
1403
- hasCaptureArgument ||= instrValue.receiver.effect === Effect.Capture;
1404
-
1405
- state.initialize(instrValue, returnValueKind);
1406
- state.define(instr.lvalue, instrValue);
1407
- instr.lvalue.effect = hasCaptureArgument
1408
- ? Effect.Store
1409
- : Effect.ConditionallyMutate;
1271
continuation = {kind: 'funeffects'};
1272
break;
1273
}
@@ -2125,3 +1986,105 @@ function getArgumentEffect(
1986
return Effect.ConditionallyMutate;
1987
}
1988
}
1989
+
1990
+function inferCallEffects(
1991
+ state: InferenceState,
1992
+ instr: TInstruction<CallExpression> | TInstruction<MethodCall>,
1993
+ freezeActions: Array<FreezeAction>,
1994
+ signature: FunctionSignature | null,
1995
+): void {
1996
+ const instrValue = instr.value;
1997
+ const returnValueKind: AbstractValue =
1998
+ signature !== null
1999
+ ? {
2000
+ kind: signature.returnValueKind,
2001
+ reason: new Set([
2002
+ signature.returnValueReason ?? ValueReason.KnownReturnSignature,
2003
+ ]),
2004
+ context: new Set(),
2005
+ }
2006
+ : {
2007
+ kind: ValueKind.Mutable,
2008
+ reason: new Set([ValueReason.Other]),
2009
+ context: new Set(),
2010
+ };
2011
+
2012
+ if (
2013
+ instrValue.kind === 'MethodCall' &&
2014
+ signature !== null &&
2015
+ signature.mutableOnlyIfOperandsAreMutable &&
2016
+ areArgumentsImmutableAndNonMutating(state, instrValue.args)
2017
+ ) {
2018
+ /*
2019
+ * None of the args are mutable or mutate their params, we can downgrade to
2020
+ * treating as all reads (except that the receiver may be captured)
2021
+ */
2022
+ for (const arg of instrValue.args) {
2023
+ const place = arg.kind === 'Identifier' ? arg : arg.place;
2024
+ state.referenceAndRecordEffects(
2025
+ freezeActions,
2026
+ place,
2027
+ Effect.Read,
2028
+ ValueReason.Other,
2029
+ );
2030
+ }
2031
+ state.referenceAndRecordEffects(
2032
+ freezeActions,
2033
+ instrValue.receiver,
2034
+ Effect.Capture,
2035
+ ValueReason.Other,
2036
+ );
2037
+ state.initialize(instrValue, returnValueKind);
2038
+ state.define(instr.lvalue, instrValue);
2039
+ instr.lvalue.effect =
2040
+ instrValue.receiver.effect === Effect.Capture
2041
+ ? Effect.Store
2042
+ : Effect.ConditionallyMutate;
2043
+ return;
2044
+ }
2045
+
2046
+ const effects =
2047
+ signature !== null ? getFunctionEffects(instrValue, signature) : null;
2048
+ let hasCaptureArgument = false;
2049
+ for (let i = 0; i < instrValue.args.length; i++) {
2050
+ const arg = instrValue.args[i];
2051
+ const place = arg.kind === 'Identifier' ? arg : arg.place;
2052
+ /*
2053
+ * If effects are inferred for an argument, we should fail invalid
2054
+ * mutating effects
2055
+ */
2056
+ state.referenceAndRecordEffects(
2057
+ freezeActions,
2058
+ place,
2059
+ getArgumentEffect(effects != null ? effects[i] : null, arg),
2060
+ ValueReason.Other,
2061
+ );
2062
+ hasCaptureArgument ||= place.effect === Effect.Capture;
2063
+ }
2064
+ const callee =
2065
+ instrValue.kind === 'CallExpression'
2066
+ ? instrValue.callee
2067
+ : instrValue.receiver;
2068
+ if (signature !== null) {
2069
+ state.referenceAndRecordEffects(
2070
+ freezeActions,
2071
+ callee,
2072
+ signature.calleeEffect,
2073
+ ValueReason.Other,
2074
+ );
2075
+ } else {
2076
+ state.referenceAndRecordEffects(
2077
+ freezeActions,
2078
+ callee,
2079
+ Effect.ConditionallyMutate,
2080
+ ValueReason.Other,
2081
+ );
2082
+ }
2083
+ hasCaptureArgument ||= callee.effect === Effect.Capture;
2084
+
2085
+ state.initialize(instrValue, returnValueKind);
2086
+ state.define(instr.lvalue, instrValue);
2087
+ instr.lvalue.effect = hasCaptureArgument
2088
+ ? Effect.Store
2089
+ : Effect.ConditionallyMutate;
2090
+}