5
5
* LICENSE file in the root directory of this source tree.
6
6
*/
7
7
8
- import { CompilerError , Effect , ValueKind } from '..' ;
8
+ import {
9
+ CompilerError ,
10
+ CompilerErrorDetailOptions ,
11
+ Effect ,
12
+ ErrorSeverity ,
13
+ ValueKind ,
14
+ } from '..' ;
9
15
import {
10
16
BasicBlock ,
11
17
BlockId ,
@@ -214,11 +220,6 @@ function inferBlock(
214
220
instructionSignature = computeSignatureForInstruction ( state . env , instr ) ;
215
221
instructionSignatureCache . set ( instr , instructionSignature ) ;
216
222
}
217
- /*
218
- * console.log(
219
- * printInstruction({...instr, effects: [...instructionSignature.effects]}),
220
- * );
221
- */
222
223
const effects = applySignature (
223
224
state ,
224
225
instructionSignature ,
@@ -244,6 +245,7 @@ function applySignature(
244
245
instruction : Instruction ,
245
246
effectInstructionValueCache : Map < AliasingEffect , InstructionValue > ,
246
247
) : Array < AliasingEffect > | null {
248
+ const effects : Array < AliasingEffect > = [ ] ;
247
249
/**
248
250
* For function instructions, eagerly validate that they aren't mutating
249
251
* a known-frozen value.
@@ -260,27 +262,33 @@ function applySignature(
260
262
for ( const effect of aliasingEffects ) {
261
263
if ( effect . kind === 'Mutate' || effect . kind === 'MutateTransitive' ) {
262
264
const value = state . kind ( effect . value ) ;
263
- if ( value . kind === ValueKind . Frozen ) {
264
- if ( DEBUG ) {
265
- console . log ( printInstruction ( instruction ) ) ;
266
- console . log ( printAliasingEffect ( effect ) ) ;
267
- console . log ( prettyFormat ( state . debugAbstractValue ( value ) ) ) ;
265
+ switch ( value . kind ) {
266
+ case ValueKind . Global :
267
+ case ValueKind . Frozen : {
268
+ const reason = getWriteErrorReason ( {
269
+ kind : value . kind ,
270
+ reason : value . reason ,
271
+ context : new Set ( ) ,
272
+ } ) ;
273
+ effects . push ( {
274
+ kind :
275
+ value . kind === ValueKind . Frozen
276
+ ? 'MutateFrozen'
277
+ : 'MutateGlobal' ,
278
+ place : effect . value ,
279
+ error : {
280
+ severity : ErrorSeverity . InvalidReact ,
281
+ reason,
282
+ description :
283
+ effect . value . identifier . name !== null &&
284
+ effect . value . identifier . name . kind === 'named'
285
+ ? `Found mutation of \`${ effect . value . identifier . name } \``
286
+ : null ,
287
+ loc : effect . value . loc ,
288
+ suggestions : null ,
289
+ } ,
290
+ } ) ;
268
291
}
269
- const reason = getWriteErrorReason ( {
270
- kind : value . kind ,
271
- reason : value . reason ,
272
- context : new Set ( ) ,
273
- } ) ;
274
- CompilerError . throwInvalidReact ( {
275
- reason,
276
- description :
277
- effect . value . identifier . name !== null &&
278
- effect . value . identifier . name . kind === 'named'
279
- ? `Found mutation of \`${ effect . value . identifier . name } \``
280
- : null ,
281
- loc : effect . value . loc ,
282
- suggestions : null ,
283
- } ) ;
284
292
}
285
293
}
286
294
}
@@ -296,7 +304,6 @@ function applySignature(
296
304
console . log ( printInstruction ( instruction ) ) ;
297
305
}
298
306
299
- const effects : Array < AliasingEffect > = [ ] ;
300
307
for ( const effect of signature . effects ) {
301
308
applyEffect (
302
309
state ,
@@ -429,6 +436,19 @@ function applyEffect(
429
436
}
430
437
}
431
438
} ) ;
439
+ for ( const operand of effect . function . loweredFunc . func . context ) {
440
+ if ( operand . effect !== Effect . Capture ) {
441
+ continue ;
442
+ }
443
+ const kind = state . kind ( operand ) . kind ;
444
+ if (
445
+ kind === ValueKind . Primitive ||
446
+ kind == ValueKind . Frozen ||
447
+ kind == ValueKind . Global
448
+ ) {
449
+ operand . effect = Effect . Read ;
450
+ }
451
+ }
432
452
state . initialize ( effect . function , {
433
453
kind : isMutable ? ValueKind . Mutable : ValueKind . Frozen ,
434
454
reason : new Set ( [ ] ) ,
@@ -742,24 +762,36 @@ function applyEffect(
742
762
console . log ( printAliasingEffect ( effect ) ) ;
743
763
console . log ( prettyFormat ( state . debugAbstractValue ( value ) ) ) ;
744
764
}
765
+
745
766
const reason = getWriteErrorReason ( {
746
767
kind : value . kind ,
747
768
reason : value . reason ,
748
769
context : new Set ( ) ,
749
770
} ) ;
750
- CompilerError . throwInvalidReact ( {
751
- reason,
752
- description :
753
- effect . value . identifier . name !== null &&
754
- effect . value . identifier . name . kind === 'named'
755
- ? `Found mutation of \`${ effect . value . identifier . name } \``
756
- : null ,
757
- loc : effect . value . loc ,
758
- suggestions : null ,
771
+ effects . push ( {
772
+ kind :
773
+ value . kind === ValueKind . Frozen ? 'MutateFrozen' : 'MutateGlobal' ,
774
+ place : effect . value ,
775
+ error : {
776
+ severity : ErrorSeverity . InvalidReact ,
777
+ reason,
778
+ description :
779
+ effect . value . identifier . name !== null &&
780
+ effect . value . identifier . name . kind === 'named'
781
+ ? `Found mutation of \`${ effect . value . identifier . name } \``
782
+ : null ,
783
+ loc : effect . value . loc ,
784
+ suggestions : null ,
785
+ } ,
759
786
} ) ;
760
787
}
761
788
break ;
762
789
}
790
+ case 'MutateFrozen' :
791
+ case 'MutateGlobal' : {
792
+ effects . push ( effect ) ;
793
+ break ;
794
+ }
763
795
default : {
764
796
assertExhaustive (
765
797
effect ,
@@ -933,7 +965,11 @@ class InferenceState {
933
965
kind : ValueKind . Frozen ,
934
966
reason : new Set ( [ reason ] ) ,
935
967
} ) ;
936
- if ( value . kind === 'FunctionExpression' ) {
968
+ if (
969
+ value . kind === 'FunctionExpression' &&
970
+ ( this . env . config . enablePreserveExistingMemoizationGuarantees ||
971
+ this . env . config . enableTransitivelyFreezeFunctionExpressions )
972
+ ) {
937
973
for ( const place of value . loweredFunc . func . context ) {
938
974
this . freeze ( place , reason ) ;
939
975
}
@@ -1552,15 +1588,31 @@ function computeSignatureForInstruction(
1552
1588
} ) ;
1553
1589
break ;
1554
1590
}
1591
+ case 'StartMemoize' :
1592
+ case 'FinishMemoize' : {
1593
+ if ( env . config . enablePreserveExistingMemoizationGuarantees ) {
1594
+ for ( const operand of eachInstructionValueOperand ( value ) ) {
1595
+ effects . push ( {
1596
+ kind : 'Freeze' ,
1597
+ value : operand ,
1598
+ reason : ValueReason . Other ,
1599
+ } ) ;
1600
+ }
1601
+ }
1602
+ effects . push ( {
1603
+ kind : 'Create' ,
1604
+ into : lvalue ,
1605
+ value : ValueKind . Primitive ,
1606
+ } ) ;
1607
+ break ;
1608
+ }
1555
1609
case 'TaggedTemplateExpression' :
1556
1610
case 'BinaryExpression' :
1557
1611
case 'Debugger' :
1558
- case 'FinishMemoize' :
1559
1612
case 'JSXText' :
1560
1613
case 'MetaProperty' :
1561
1614
case 'Primitive' :
1562
1615
case 'RegExpLiteral' :
1563
- case 'StartMemoize' :
1564
1616
case 'TemplateLiteral' :
1565
1617
case 'UnaryExpression' :
1566
1618
case 'UnsupportedNode' : {
@@ -1879,6 +1931,14 @@ function computeEffectsForSignature(
1879
1931
}
1880
1932
break ;
1881
1933
}
1934
+ case 'MutateFrozen' :
1935
+ case 'MutateGlobal' : {
1936
+ const values = substitutions . get ( effect . place . identifier . id ) ?? [ ] ;
1937
+ for ( const value of values ) {
1938
+ effects . push ( { kind : effect . kind , place : value , error : effect . error } ) ;
1939
+ }
1940
+ break ;
1941
+ }
1882
1942
case 'Mutate' :
1883
1943
case 'MutateTransitive' :
1884
1944
case 'MutateTransitiveConditionally' :
@@ -2165,6 +2225,18 @@ export type AliasingEffect =
2165
2225
captures : Array < Place > ;
2166
2226
function : FunctionExpression | ObjectMethod ;
2167
2227
into : Place ;
2228
+ }
2229
+ /**
2230
+ * Mutation of a value known to be immutable
2231
+ */
2232
+ | { kind : 'MutateFrozen' ; place : Place ; error : CompilerErrorDetailOptions }
2233
+ /**
2234
+ * Mutation of a global
2235
+ */
2236
+ | {
2237
+ kind : 'MutateGlobal' ;
2238
+ place : Place ;
2239
+ error : CompilerErrorDetailOptions ;
2168
2240
} ;
2169
2241
2170
2242
export type AliasingSignatureEffect = AliasingEffect ;
0 commit comments