25
* `identifier.path`, or `identifier?.path` is in this map, it is safe to
26
* evaluate (non-optional) PropertyLoads from.
27
*/
28
- #hoistableObjects: Map<Identifier, HoistableNode> = new Map();
29
- #deps: Map<Identifier, DependencyNode> = new Map();
28
+ #hoistableObjects: Map<Identifier, HoistableNode & {reactive: boolean}> =
29
+ new Map();
30
+ #deps: Map<Identifier, DependencyNode & {reactive: boolean}> = new Map();
31
32
/**
33
* @param hoistableObjects a set of paths from which we can safely evaluate
36
* duplicates when traversing the CFG.
37
*/
38
constructor(hoistableObjects: Iterable<ReactiveScopeDependency>) {
38
- for (const {path, identifier} of hoistableObjects) {
39
+ for (const {path, identifier, reactive} of hoistableObjects) {
40
let currNode = ReactiveScopeDependencyTreeHIR.#getOrCreateRoot(
41
identifier,
42
+ reactive,
43
this.#hoistableObjects,
44
path.length > 0 && path[0].optional ? 'Optional' : 'NonNull',
45
);
72
73
static #getOrCreateRoot<T extends string>(
74
identifier: Identifier,
73
- roots: Map<Identifier, TreeNode<T>>,
75
+ reactive: boolean,
76
+ roots: Map<Identifier, TreeNode<T> & {reactive: boolean}>,
77
defaultAccessType: T,
78
): TreeNode<T> {
79
// roots can always be accessed unconditionally in JS
82
if (rootNode === undefined) {
83
rootNode = {
84
properties: new Map(),
85
+ reactive,
86
accessType: defaultAccessType,
87
};
88
roots.set(identifier, rootNode);
89
+ } else {
90
+ CompilerError.invariant(reactive === rootNode.reactive, {
91
+ reason: '[DeriveMinimalDependenciesHIR] Conflicting reactive root flag',
92
+ description: `Identifier ${printIdentifier(identifier)}`,
93
+ loc: GeneratedSource,
94
+ });
95
}
96
return rootNode;
97
}
102
* safe-to-evaluate subpath
103
*/
104
addDependency(dep: ReactiveScopeDependency): void {
95
- const {identifier, path} = dep;
105
+ const {identifier, reactive, path} = dep;
106
let depCursor = ReactiveScopeDependencyTreeHIR.#getOrCreateRoot(
107
identifier,
108
+ reactive,
109
this.#deps,
110
PropertyAccessType.UnconditionalAccess,
111
);
183
deriveMinimalDependencies(): Set<ReactiveScopeDependency> {
184
const results = new Set<ReactiveScopeDependency>();
185
for (const [rootId, rootNode] of this.#deps.entries()) {
175
- collectMinimalDependenciesInSubtree(rootNode, rootId, [], results);
186
+ collectMinimalDependenciesInSubtree(
187
+ rootNode,
188
+ rootNode.reactive,
189
+ rootId,
190
+ [],
191
+ results,
192
+ );
193
}
194
195
return results;
311
type DependencyNode = TreeNode<PropertyAccessType>;
312
313
/**
297
- * TODO: this is directly pasted from DeriveMinimalDependencies. Since we no
298
- * longer have conditionally accessed nodes, we can simplify
299
- *
314
* Recursively calculates minimal dependencies in a subtree.
315
* @param node DependencyNode representing a dependency subtree.
316
* @returns a minimal list of dependencies in this subtree.
317
*/
318
function collectMinimalDependenciesInSubtree(
319
node: DependencyNode,
320
+ reactive: boolean,
321
rootIdentifier: Identifier,
322
path: Array<DependencyPathEntry>,
323
results: Set<ReactiveScopeDependency>,
324
): void {
325
if (isDependency(node.accessType)) {
311
- results.add({identifier: rootIdentifier, path});
326
+ results.add({identifier: rootIdentifier, reactive, path});
327
} else {
328
for (const [childName, childNode] of node.properties) {
329
collectMinimalDependenciesInSubtree(
330
childNode,
331
+ reactive,
332
rootIdentifier,
333
[
334
...path,