15
HIRFunction,
16
Identifier,
17
IdentifierId,
18
- InstructionId,
18
+ InstructionValue,
19
ReactiveScopeDependency,
20
ScopeId,
21
} from './HIR';
209
}
210
}
211
212
-function addNonNullPropertyPath(
213
- source: Identifier,
214
- sourceNode: PropertyPathNode,
215
- instrId: InstructionId,
216
- knownImmutableIdentifiers: Set<IdentifierId>,
217
- result: Set<PropertyPathNode>,
218
-): void {
219
- /**
220
- * Since this runs *after* buildReactiveScopeTerminals, identifier mutable ranges
221
- * are not valid with respect to current instruction id numbering.
222
- * We use attached reactive scope ranges as a proxy for mutable range, but this
223
- * is an overestimate as (1) scope ranges merge and align to form valid program
224
- * blocks and (2) passes like MemoizeFbtAndMacroOperands may assign scopes to
225
- * non-mutable identifiers.
226
- *
227
- * See comment at top of function for why we track known immutable identifiers.
228
- */
229
- const isMutableAtInstr =
230
- source.mutableRange.end > source.mutableRange.start + 1 &&
231
- source.scope != null &&
232
- inRange({id: instrId}, source.scope.range);
233
- if (
234
- !isMutableAtInstr ||
235
- knownImmutableIdentifiers.has(sourceNode.fullPath.identifier.id)
236
- ) {
237
- result.add(sourceNode);
212
+function getMaybeNonNullInInstruction(
213
+ instr: InstructionValue,
214
+ temporaries: ReadonlyMap<IdentifierId, ReactiveScopeDependency>,
215
+ registry: PropertyPathRegistry,
216
+): PropertyPathNode | null {
217
+ let path = null;
218
+ if (instr.kind === 'PropertyLoad') {
219
+ path = temporaries.get(instr.object.identifier.id) ?? {
220
+ identifier: instr.object.identifier,
221
+ path: [],
222
+ };
223
+ } else if (instr.kind === 'Destructure') {
224
+ path = temporaries.get(instr.value.identifier.id) ?? null;
225
+ } else if (instr.kind === 'ComputedLoad') {
226
+ path = temporaries.get(instr.object.identifier.id) ?? null;
227
}
228
+ return path != null ? registry.getOrCreateProperty(path) : null;
229
}
230
231
function collectNonNullsInBlocks(
276
);
277
}
278
for (const instr of block.instructions) {
289
- if (instr.value.kind === 'PropertyLoad') {
290
- const source = temporaries.get(instr.value.object.identifier.id) ?? {
291
- identifier: instr.value.object.identifier,
292
- path: [],
293
- };
294
- addNonNullPropertyPath(
295
- instr.value.object.identifier,
296
- registry.getOrCreateProperty(source),
297
- instr.id,
298
- knownImmutableIdentifiers,
299
- assumedNonNullObjects,
300
- );
301
- } else if (instr.value.kind === 'Destructure') {
302
- const source = instr.value.value.identifier.id;
303
- const sourceNode = temporaries.get(source);
304
- if (sourceNode != null) {
305
- addNonNullPropertyPath(
306
- instr.value.value.identifier,
307
- registry.getOrCreateProperty(sourceNode),
308
- instr.id,
309
- knownImmutableIdentifiers,
310
- assumedNonNullObjects,
311
- );
312
- }
313
- } else if (instr.value.kind === 'ComputedLoad') {
314
- const source = instr.value.object.identifier.id;
315
- const sourceNode = temporaries.get(source);
316
- if (sourceNode != null) {
317
- addNonNullPropertyPath(
318
- instr.value.object.identifier,
319
- registry.getOrCreateProperty(sourceNode),
320
- instr.id,
321
- knownImmutableIdentifiers,
322
- assumedNonNullObjects,
279
+ const maybeNonNull = getMaybeNonNullInInstruction(
280
+ instr.value,
281
+ temporaries,
282
+ registry,
283
+ );
284
+ if (maybeNonNull != null) {
285
+ const baseIdentifier = maybeNonNull.fullPath.identifier;
286
+ /**
287
+ * Since this runs *after* buildReactiveScopeTerminals, identifier mutable ranges
288
+ * are not valid with respect to current instruction id numbering.
289
+ * We use attached reactive scope ranges as a proxy for mutable range, but this
290
+ * is an overestimate as (1) scope ranges merge and align to form valid program
291
+ * blocks and (2) passes like MemoizeFbtAndMacroOperands may assign scopes to
292
+ * non-mutable identifiers.
293
+ *
294
+ * See comment at top of function for why we track known immutable identifiers.
295
+ */
296
+ const isMutableAtInstr =
297
+ baseIdentifier.mutableRange.end >
298
+ baseIdentifier.mutableRange.start + 1 &&
299
+ baseIdentifier.scope != null &&
300
+ inRange(
301
+ {
302
+ id: instr.id,
303
+ },
304
+ baseIdentifier.scope.range,
305
);
306
+ if (
307
+ !isMutableAtInstr ||
308
+ knownImmutableIdentifiers.has(baseIdentifier.id)
309
+ ) {
310
+ assumedNonNullObjects.add(maybeNonNull);
311
}
312
}
313
}