@@ -23,6 +23,7 @@ import {
2323 Phi ,
2424 Place ,
2525 SpreadPattern ,
26+ TInstruction ,
2627 Type ,
2728 ValueKind ,
2829 ValueReason ,
@@ -1238,62 +1239,12 @@ function inferBlock(
12381239 break ;
12391240 }
12401241 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 ) ,
12441247 ) ;
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 ;
12971248 continuation = { kind : 'funeffects' } ;
12981249 break ;
12991250 }
@@ -1311,102 +1262,12 @@ function inferBlock(
13111262 Effect . Read ,
13121263 ValueReason . Other ,
13131264 ) ;
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 ) ,
13181270 ) ;
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 ;
14101271 continuation = { kind : 'funeffects' } ;
14111272 break ;
14121273 }
@@ -2125,3 +1986,105 @@ function getArgumentEffect(
21251986 return Effect . ConditionallyMutate ;
21261987 }
21271988}
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