@@ -23,6 +23,7 @@ import {
23
23
Phi ,
24
24
Place ,
25
25
SpreadPattern ,
26
+ TInstruction ,
26
27
Type ,
27
28
ValueKind ,
28
29
ValueReason ,
@@ -1238,62 +1239,12 @@ function inferBlock(
1238
1239
break ;
1239
1240
}
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 ) ,
1244
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 ;
1297
1248
continuation = { kind : 'funeffects' } ;
1298
1249
break ;
1299
1250
}
@@ -1311,102 +1262,12 @@ function inferBlock(
1311
1262
Effect . Read ,
1312
1263
ValueReason . Other ,
1313
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 ) ,
1318
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 ;
1410
1271
continuation = { kind : 'funeffects' } ;
1411
1272
break ;
1412
1273
}
@@ -2125,3 +1986,105 @@ function getArgumentEffect(
2125
1986
return Effect . ConditionallyMutate ;
2126
1987
}
2127
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
+ }
0 commit comments