1
1
import { CompilerError } from '../CompilerError' ;
2
2
import { inRange } from '../ReactiveScopes/InferReactiveScopeVariables' ;
3
+ import { printDependency } from '../ReactiveScopes/PrintReactiveFunction' ;
3
4
import {
4
5
Set_equal ,
5
6
Set_filter ,
@@ -23,6 +24,8 @@ import {
23
24
} from './HIR' ;
24
25
import { collectTemporariesSidemap } from './PropagateScopeDependenciesHIR' ;
25
26
27
+ const DEBUG_PRINT = false ;
28
+
26
29
/**
27
30
* Helper function for `PropagateScopeDependencies`. Uses control flow graph
28
31
* analysis to determine which `Identifier`s can be assumed to be non-null
@@ -86,15 +89,8 @@ export function collectHoistablePropertyLoads(
86
89
fn : HIRFunction ,
87
90
temporaries : ReadonlyMap < IdentifierId , ReactiveScopeDependency > ,
88
91
hoistableFromOptionals : ReadonlyMap < BlockId , ReactiveScopeDependency > ,
89
- nestedFnImmutableContext : ReadonlySet < IdentifierId > | null ,
90
92
) : ReadonlyMap < BlockId , BlockInfo > {
91
93
const registry = new PropertyPathRegistry ( ) ;
92
-
93
- const functionExpressionLoads = collectFunctionExpressionFakeLoads ( fn ) ;
94
- const actuallyEvaluatedTemporaries = new Map (
95
- [ ...temporaries ] . filter ( ( [ id ] ) => ! functionExpressionLoads . has ( id ) ) ,
96
- ) ;
97
-
98
94
/**
99
95
* Due to current limitations of mutable range inference, there are edge cases in
100
96
* which we infer known-immutable values (e.g. props or hook params) to have a
@@ -111,14 +107,51 @@ export function collectHoistablePropertyLoads(
111
107
}
112
108
}
113
109
}
114
- const nodes = collectNonNullsInBlocks ( fn , {
115
- temporaries : actuallyEvaluatedTemporaries ,
110
+ return collectHoistablePropertyLoadsImpl ( fn , {
111
+ temporaries,
116
112
knownImmutableIdentifiers,
117
113
hoistableFromOptionals,
118
114
registry,
119
- nestedFnImmutableContext,
115
+ nestedFnImmutableContext : null ,
120
116
} ) ;
121
- propagateNonNull ( fn , nodes , registry ) ;
117
+ }
118
+
119
+ type CollectHoistablePropertyLoadsContext = {
120
+ temporaries : ReadonlyMap < IdentifierId , ReactiveScopeDependency > ;
121
+ knownImmutableIdentifiers : ReadonlySet < IdentifierId > ;
122
+ hoistableFromOptionals : ReadonlyMap < BlockId , ReactiveScopeDependency > ;
123
+ registry : PropertyPathRegistry ;
124
+ /**
125
+ * (For nested / inner function declarations)
126
+ * Context variables (i.e. captured from an outer scope) that are immutable.
127
+ * Note that this technically could be merged into `knownImmutableIdentifiers`,
128
+ * but are currently kept separate for readability.
129
+ */
130
+ nestedFnImmutableContext : ReadonlySet < IdentifierId > | null ;
131
+ } ;
132
+ function collectHoistablePropertyLoadsImpl (
133
+ fn : HIRFunction ,
134
+ context : CollectHoistablePropertyLoadsContext ,
135
+ ) : ReadonlyMap < BlockId , BlockInfo > {
136
+ const functionExpressionLoads = collectFunctionExpressionFakeLoads ( fn ) ;
137
+ const actuallyEvaluatedTemporaries = new Map (
138
+ [ ...context . temporaries ] . filter ( ( [ id ] ) => ! functionExpressionLoads . has ( id ) ) ,
139
+ ) ;
140
+
141
+ const nodes = collectNonNullsInBlocks ( fn , {
142
+ ...context ,
143
+ temporaries : actuallyEvaluatedTemporaries ,
144
+ } ) ;
145
+ propagateNonNull ( fn , nodes , context . registry ) ;
146
+
147
+ if ( DEBUG_PRINT ) {
148
+ console . log ( '(printing hoistable nodes in blocks)' ) ;
149
+ for ( const [ blockId , node ] of nodes ) {
150
+ console . log (
151
+ `bb${ blockId } : ${ [ ...node . assumedNonNullObjects ] . map ( n => printDependency ( n . fullPath ) ) . join ( ' ' ) } ` ,
152
+ ) ;
153
+ }
154
+ }
122
155
123
156
return nodes ;
124
157
}
@@ -243,7 +276,7 @@ class PropertyPathRegistry {
243
276
244
277
function getMaybeNonNullInInstruction (
245
278
instr : InstructionValue ,
246
- context : CollectNonNullsInBlocksContext ,
279
+ context : CollectHoistablePropertyLoadsContext ,
247
280
) : PropertyPathNode | null {
248
281
let path = null ;
249
282
if ( instr . kind === 'PropertyLoad' ) {
@@ -262,7 +295,7 @@ function getMaybeNonNullInInstruction(
262
295
function isImmutableAtInstr (
263
296
identifier : Identifier ,
264
297
instr : InstructionId ,
265
- context : CollectNonNullsInBlocksContext ,
298
+ context : CollectHoistablePropertyLoadsContext ,
266
299
) : boolean {
267
300
if ( context . nestedFnImmutableContext != null ) {
268
301
/**
@@ -295,22 +328,9 @@ function isImmutableAtInstr(
295
328
}
296
329
}
297
330
298
- type CollectNonNullsInBlocksContext = {
299
- temporaries : ReadonlyMap < IdentifierId , ReactiveScopeDependency > ;
300
- knownImmutableIdentifiers : ReadonlySet < IdentifierId > ;
301
- hoistableFromOptionals : ReadonlyMap < BlockId , ReactiveScopeDependency > ;
302
- registry : PropertyPathRegistry ;
303
- /**
304
- * (For nested / inner function declarations)
305
- * Context variables (i.e. captured from an outer scope) that are immutable.
306
- * Note that this technically could be merged into `knownImmutableIdentifiers`,
307
- * but are currently kept separate for readability.
308
- */
309
- nestedFnImmutableContext : ReadonlySet < IdentifierId > | null ;
310
- } ;
311
331
function collectNonNullsInBlocks (
312
332
fn : HIRFunction ,
313
- context : CollectNonNullsInBlocksContext ,
333
+ context : CollectHoistablePropertyLoadsContext ,
314
334
) : ReadonlyMap < BlockId , BlockInfo > {
315
335
/**
316
336
* Known non-null objects such as functional component props can be safely
@@ -358,18 +378,22 @@ function collectNonNullsInBlocks(
358
378
new Set ( ) ,
359
379
) ;
360
380
const innerOptionals = collectOptionalChainSidemap ( innerFn . func ) ;
361
- const innerHoistableMap = collectHoistablePropertyLoads (
381
+ const innerHoistableMap = collectHoistablePropertyLoadsImpl (
362
382
innerFn . func ,
363
- innerTemporaries ,
364
- innerOptionals . hoistableObjects ,
365
- context . nestedFnImmutableContext ??
366
- new Set (
367
- innerFn . func . context
368
- . filter ( place =>
369
- isImmutableAtInstr ( place . identifier , instr . id , context ) ,
370
- )
371
- . map ( place => place . identifier . id ) ,
372
- ) ,
383
+ {
384
+ ...context ,
385
+ temporaries : innerTemporaries , // TODO: remove in later PR
386
+ hoistableFromOptionals : innerOptionals . hoistableObjects , // TODO: remove in later PR
387
+ nestedFnImmutableContext :
388
+ context . nestedFnImmutableContext ??
389
+ new Set (
390
+ innerFn . func . context
391
+ . filter ( place =>
392
+ isImmutableAtInstr ( place . identifier , instr . id , context ) ,
393
+ )
394
+ . map ( place => place . identifier . id ) ,
395
+ ) ,
396
+ } ,
373
397
) ;
374
398
const innerHoistables = assertNonNull (
375
399
innerHoistableMap . get ( innerFn . func . body . entry ) ,
0 commit comments