babel-plugin-react-compiler 0.0.0-experimental-b4db8c3-20241001 → 0.0.0-experimental-27e0f40-20241002

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -119602,6 +119602,17 @@ function getOrInsertDefault(m, key, defaultValue) {
119602
119602
  return defaultValue;
119603
119603
  }
119604
119604
  }
119605
+ function Set_equal(a, b) {
119606
+ if (a.size !== b.size) {
119607
+ return false;
119608
+ }
119609
+ for (const item of a) {
119610
+ if (!b.has(item)) {
119611
+ return false;
119612
+ }
119613
+ }
119614
+ return true;
119615
+ }
119605
119616
  function Set_union(a, b) {
119606
119617
  const union = new Set(a);
119607
119618
  for (const item of b) {
@@ -119635,6 +119646,15 @@ function Iterable_some(iter, pred) {
119635
119646
  }
119636
119647
  return false;
119637
119648
  }
119649
+ function Set_filter(source, fn) {
119650
+ const result = new Set();
119651
+ for (const entry of source) {
119652
+ if (fn(entry)) {
119653
+ result.add(entry);
119654
+ }
119655
+ }
119656
+ return result;
119657
+ }
119638
119658
  function hasNode(input) {
119639
119659
  return input.node != null;
119640
119660
  }
@@ -144922,7 +144942,7 @@ class ReactiveScopeDependencyTree {
144922
144942
  }
144923
144943
  const depType = inConditional
144924
144944
  ? PropertyAccessType$1.ConditionalDependency
144925
- : isOptional(currNode.accessType)
144945
+ : isOptional$1(currNode.accessType)
144926
144946
  ? PropertyAccessType$1.OptionalDependency
144927
144947
  : PropertyAccessType$1.UnconditionalDependency;
144928
144948
  currNode.accessType = merge$1(currNode.accessType, depType);
@@ -144934,7 +144954,7 @@ class ReactiveScopeDependencyTree {
144934
144954
  _ReactiveScopeDependencyTree_roots,
144935
144955
  'f'
144936
144956
  ).entries()) {
144937
- const deps = deriveMinimalDependenciesInSubtree$1(rootNode, null);
144957
+ const deps = deriveMinimalDependenciesInSubtree(rootNode, null);
144938
144958
  CompilerError.invariant(
144939
144959
  deps.every(
144940
144960
  dep =>
@@ -145092,7 +145112,7 @@ var PropertyAccessType$1;
145092
145112
  PropertyAccessType['OptionalDependency'] = 'OptionalDependency';
145093
145113
  PropertyAccessType['UnconditionalDependency'] = 'UnconditionalDependency';
145094
145114
  })(PropertyAccessType$1 || (PropertyAccessType$1 = {}));
145095
- const MIN_ACCESS_TYPE$1 = PropertyAccessType$1.ConditionalAccess;
145115
+ const MIN_ACCESS_TYPE = PropertyAccessType$1.ConditionalAccess;
145096
145116
  function isUnconditional(access) {
145097
145117
  return (
145098
145118
  access === PropertyAccessType$1.UnconditionalAccess ||
@@ -145106,7 +145126,7 @@ function isDependency$1(access) {
145106
145126
  access === PropertyAccessType$1.UnconditionalDependency
145107
145127
  );
145108
145128
  }
145109
- function isOptional(access) {
145129
+ function isOptional$1(access) {
145110
145130
  return (
145111
145131
  access === PropertyAccessType$1.OptionalAccess ||
145112
145132
  access === PropertyAccessType$1.OptionalDependency
@@ -145116,7 +145136,7 @@ function merge$1(access1, access2) {
145116
145136
  const resultIsUnconditional =
145117
145137
  isUnconditional(access1) || isUnconditional(access2);
145118
145138
  const resultIsDependency = isDependency$1(access1) || isDependency$1(access2);
145119
- const resultIsOptional = isOptional(access1) || isOptional(access2);
145139
+ const resultIsOptional = isOptional$1(access1) || isOptional$1(access2);
145120
145140
  if (resultIsUnconditional) {
145121
145141
  if (resultIsDependency) {
145122
145142
  return PropertyAccessType$1.UnconditionalDependency;
@@ -145153,10 +145173,10 @@ function prependPath(results, path) {
145153
145173
  relativePath: [path, ...result.relativePath],
145154
145174
  }));
145155
145175
  }
145156
- function deriveMinimalDependenciesInSubtree$1(dep, property) {
145176
+ function deriveMinimalDependenciesInSubtree(dep, property) {
145157
145177
  const results = [];
145158
145178
  for (const [childName, childNode] of dep.properties) {
145159
- const childResult = deriveMinimalDependenciesInSubtree$1(
145179
+ const childResult = deriveMinimalDependenciesInSubtree(
145160
145180
  childNode,
145161
145181
  childName
145162
145182
  );
@@ -145322,7 +145342,7 @@ function printSubtree$1(node, includeAccesses) {
145322
145342
  function getOrMakeProperty(node, property) {
145323
145343
  let child = node.properties.get(property);
145324
145344
  if (child == null) {
145325
- child = {properties: new Map(), accessType: MIN_ACCESS_TYPE$1};
145345
+ child = {properties: new Map(), accessType: MIN_ACCESS_TYPE};
145326
145346
  node.properties.set(property, child);
145327
145347
  }
145328
145348
  return child;
@@ -154219,10 +154239,19 @@ function validateNoJSXInTryStatement(fn) {
154219
154239
  throw errors;
154220
154240
  }
154221
154241
  }
154222
- function collectHoistablePropertyLoads(fn, temporaries) {
154242
+ function collectHoistablePropertyLoads(
154243
+ fn,
154244
+ temporaries,
154245
+ hoistableFromOptionals
154246
+ ) {
154223
154247
  const registry = new PropertyPathRegistry();
154224
- const nodes = collectNonNullsInBlocks(fn, temporaries, registry);
154225
- propagateNonNull(fn, nodes);
154248
+ const nodes = collectNonNullsInBlocks(
154249
+ fn,
154250
+ temporaries,
154251
+ hoistableFromOptionals,
154252
+ registry
154253
+ );
154254
+ propagateNonNull(fn, nodes, registry);
154226
154255
  const nodesKeyedByScopeId = new Map();
154227
154256
  for (const [_, block] of fn.body.blocks) {
154228
154257
  if (block.terminal.kind === 'scope') {
@@ -154244,7 +154273,9 @@ class PropertyPathRegistry {
154244
154273
  rootNode = {
154245
154274
  root: identifier.id,
154246
154275
  properties: new Map(),
154276
+ optionalProperties: new Map(),
154247
154277
  fullPath: {identifier: identifier, path: []},
154278
+ hasOptional: false,
154248
154279
  parent: null,
154249
154280
  };
154250
154281
  this.roots.set(identifier.id, rootNode);
@@ -154252,23 +154283,20 @@ class PropertyPathRegistry {
154252
154283
  return rootNode;
154253
154284
  }
154254
154285
  static getOrCreatePropertyEntry(parent, entry) {
154255
- if (entry.optional) {
154256
- CompilerError.throwTodo({
154257
- reason: 'handle optional nodes',
154258
- loc: GeneratedSource,
154259
- });
154260
- }
154261
- let child = parent.properties.get(entry.property);
154286
+ const map = entry.optional ? parent.optionalProperties : parent.properties;
154287
+ let child = map.get(entry.property);
154262
154288
  if (child == null) {
154263
154289
  child = {
154264
154290
  properties: new Map(),
154291
+ optionalProperties: new Map(),
154265
154292
  parent: parent,
154266
154293
  fullPath: {
154267
154294
  identifier: parent.fullPath.identifier,
154268
154295
  path: parent.fullPath.path.concat(entry),
154269
154296
  },
154297
+ hasOptional: parent.hasOptional || entry.optional,
154270
154298
  };
154271
- parent.properties.set(entry.property, child);
154299
+ map.set(entry.property, child);
154272
154300
  }
154273
154301
  return child;
154274
154302
  }
@@ -154307,7 +154335,12 @@ function addNonNullPropertyPath(
154307
154335
  result.add(sourceNode);
154308
154336
  }
154309
154337
  }
154310
- function collectNonNullsInBlocks(fn, temporaries, registry) {
154338
+ function collectNonNullsInBlocks(
154339
+ fn,
154340
+ temporaries,
154341
+ hoistableFromOptionals,
154342
+ registry
154343
+ ) {
154311
154344
  var _a;
154312
154345
  const knownImmutableIdentifiers = new Set();
154313
154346
  if (fn.fnType === 'Component' || fn.fnType === 'Hook') {
@@ -154329,6 +154362,12 @@ function collectNonNullsInBlocks(fn, temporaries, registry) {
154329
154362
  const nodes = new Map();
154330
154363
  for (const [_, block] of fn.body.blocks) {
154331
154364
  const assumedNonNullObjects = new Set(knownNonNullIdentifiers);
154365
+ const maybeOptionalChain = hoistableFromOptionals.get(block.id);
154366
+ if (maybeOptionalChain != null) {
154367
+ assumedNonNullObjects.add(
154368
+ registry.getOrCreateProperty(maybeOptionalChain)
154369
+ );
154370
+ }
154332
154371
  for (const instr of block.instructions) {
154333
154372
  if (instr.value.kind === 'PropertyLoad') {
154334
154373
  const source =
@@ -154376,7 +154415,7 @@ function collectNonNullsInBlocks(fn, temporaries, registry) {
154376
154415
  }
154377
154416
  return nodes;
154378
154417
  }
154379
- function propagateNonNull(fn, nodes) {
154418
+ function propagateNonNull(fn, nodes, registry) {
154380
154419
  const blockSuccessors = new Map();
154381
154420
  const terminalPreds = new Set();
154382
154421
  for (const [blockId, block] of fn.body.blocks) {
@@ -154425,9 +154464,10 @@ function propagateNonNull(fn, nodes) {
154425
154464
  );
154426
154465
  const prevObjects = assertNonNull(nodes.get(nodeId)).assumedNonNullObjects;
154427
154466
  const mergedObjects = Set_union(prevObjects, neighborAccesses);
154467
+ reduceMaybeOptionalChains(mergedObjects, registry);
154428
154468
  assertNonNull(nodes.get(nodeId)).assumedNonNullObjects = mergedObjects;
154429
154469
  traversalState.set(nodeId, 'done');
154430
- changed || (changed = prevObjects.size !== mergedObjects.size);
154470
+ changed || (changed = !Set_equal(prevObjects, mergedObjects));
154431
154471
  return changed;
154432
154472
  }
154433
154473
  const traversalState = new Map();
@@ -154470,70 +154510,156 @@ function assertNonNull(value, source) {
154470
154510
  });
154471
154511
  return value;
154472
154512
  }
154473
- var _ReactiveScopeDependencyTreeHIR_instances,
154474
- _ReactiveScopeDependencyTreeHIR_roots,
154475
- _ReactiveScopeDependencyTreeHIR_getOrCreateRoot;
154513
+ function reduceMaybeOptionalChains(nodes, registry) {
154514
+ let optionalChainNodes = Set_filter(nodes, n => n.hasOptional);
154515
+ if (optionalChainNodes.size === 0) {
154516
+ return;
154517
+ }
154518
+ let changed;
154519
+ do {
154520
+ changed = false;
154521
+ for (const original of optionalChainNodes) {
154522
+ let {identifier: identifier, path: origPath} = original.fullPath;
154523
+ let currNode = registry.getOrCreateIdentifier(identifier);
154524
+ for (let i = 0; i < origPath.length; i++) {
154525
+ const entry = origPath[i];
154526
+ const nextEntry =
154527
+ entry.optional && nodes.has(currNode)
154528
+ ? {property: entry.property, optional: false}
154529
+ : entry;
154530
+ currNode = PropertyPathRegistry.getOrCreatePropertyEntry(
154531
+ currNode,
154532
+ nextEntry
154533
+ );
154534
+ }
154535
+ if (currNode !== original) {
154536
+ changed = true;
154537
+ optionalChainNodes.delete(original);
154538
+ optionalChainNodes.add(currNode);
154539
+ nodes.delete(original);
154540
+ nodes.add(currNode);
154541
+ }
154542
+ }
154543
+ } while (changed);
154544
+ }
154545
+ var _a,
154546
+ _ReactiveScopeDependencyTreeHIR_hoistableObjects,
154547
+ _ReactiveScopeDependencyTreeHIR_deps,
154548
+ _ReactiveScopeDependencyTreeHIR_getOrCreateRoot,
154549
+ _ReactiveScopeDependencyTreeHIR_debugImpl;
154476
154550
  class ReactiveScopeDependencyTreeHIR {
154477
- constructor() {
154478
- _ReactiveScopeDependencyTreeHIR_instances.add(this);
154479
- _ReactiveScopeDependencyTreeHIR_roots.set(this, new Map());
154551
+ constructor(hoistableObjects) {
154552
+ var _b;
154553
+ _ReactiveScopeDependencyTreeHIR_hoistableObjects.set(this, new Map());
154554
+ _ReactiveScopeDependencyTreeHIR_deps.set(this, new Map());
154555
+ for (const {path: path, identifier: identifier} of hoistableObjects) {
154556
+ let currNode = __classPrivateFieldGet(
154557
+ _a,
154558
+ _a,
154559
+ 'm',
154560
+ _ReactiveScopeDependencyTreeHIR_getOrCreateRoot
154561
+ ).call(
154562
+ _a,
154563
+ identifier,
154564
+ __classPrivateFieldGet(
154565
+ this,
154566
+ _ReactiveScopeDependencyTreeHIR_hoistableObjects,
154567
+ 'f'
154568
+ ),
154569
+ path.length > 0 && path[0].optional ? 'Optional' : 'NonNull'
154570
+ );
154571
+ for (let i = 0; i < path.length; i++) {
154572
+ const prevAccessType =
154573
+ (_b = currNode.properties.get(path[i].property)) === null ||
154574
+ _b === void 0
154575
+ ? void 0
154576
+ : _b.accessType;
154577
+ const accessType =
154578
+ i + 1 < path.length && path[i + 1].optional ? 'Optional' : 'NonNull';
154579
+ CompilerError.invariant(
154580
+ prevAccessType == null || prevAccessType === accessType,
154581
+ {reason: 'Conflicting access types', loc: GeneratedSource}
154582
+ );
154583
+ let nextNode = currNode.properties.get(path[i].property);
154584
+ if (nextNode == null) {
154585
+ nextNode = {properties: new Map(), accessType: accessType};
154586
+ currNode.properties.set(path[i].property, nextNode);
154587
+ }
154588
+ currNode = nextNode;
154589
+ }
154590
+ }
154480
154591
  }
154481
154592
  addDependency(dep) {
154482
- const {path: path} = dep;
154483
- let currNode = __classPrivateFieldGet(
154484
- this,
154485
- _ReactiveScopeDependencyTreeHIR_instances,
154593
+ const {identifier: identifier, path: path} = dep;
154594
+ let depCursor = __classPrivateFieldGet(
154595
+ _a,
154596
+ _a,
154486
154597
  'm',
154487
154598
  _ReactiveScopeDependencyTreeHIR_getOrCreateRoot
154488
- ).call(this, dep.identifier, MIN_ACCESS_TYPE);
154489
- const accessType = PropertyAccessType.Access;
154490
- currNode.accessType = merge(currNode.accessType, accessType);
154491
- for (const property of path) {
154492
- let currChild = makeOrMergeProperty(
154493
- currNode,
154494
- property.property,
154495
- accessType
154496
- );
154497
- currNode = currChild;
154498
- }
154499
- currNode.accessType = merge(
154500
- currNode.accessType,
154501
- PropertyAccessType.Dependency
154599
+ ).call(
154600
+ _a,
154601
+ identifier,
154602
+ __classPrivateFieldGet(this, _ReactiveScopeDependencyTreeHIR_deps, 'f'),
154603
+ PropertyAccessType.UnconditionalAccess
154502
154604
  );
154503
- }
154504
- markNodesNonNull(dep) {
154505
- const accessType = PropertyAccessType.NonNullAccess;
154506
- let currNode = __classPrivateFieldGet(
154605
+ let hoistableCursor = __classPrivateFieldGet(
154507
154606
  this,
154508
- _ReactiveScopeDependencyTreeHIR_roots,
154607
+ _ReactiveScopeDependencyTreeHIR_hoistableObjects,
154509
154608
  'f'
154510
- ).get(dep.identifier);
154511
- let cursor = 0;
154512
- while (currNode != null && cursor < dep.path.length) {
154513
- currNode.accessType = merge(currNode.accessType, accessType);
154514
- currNode = currNode.properties.get(dep.path[cursor++].property);
154515
- }
154516
- if (currNode != null) {
154517
- currNode.accessType = merge(currNode.accessType, accessType);
154609
+ ).get(identifier);
154610
+ for (const entry of path) {
154611
+ let nextHoistableCursor;
154612
+ let nextDepCursor;
154613
+ if (entry.optional) {
154614
+ if (hoistableCursor != null) {
154615
+ nextHoistableCursor =
154616
+ hoistableCursor === null || hoistableCursor === void 0
154617
+ ? void 0
154618
+ : hoistableCursor.properties.get(entry.property);
154619
+ }
154620
+ let accessType;
154621
+ if (
154622
+ hoistableCursor != null &&
154623
+ hoistableCursor.accessType === 'NonNull'
154624
+ ) {
154625
+ accessType = PropertyAccessType.UnconditionalAccess;
154626
+ } else {
154627
+ accessType = PropertyAccessType.OptionalAccess;
154628
+ }
154629
+ nextDepCursor = makeOrMergeProperty(
154630
+ depCursor,
154631
+ entry.property,
154632
+ accessType
154633
+ );
154634
+ } else if (
154635
+ hoistableCursor != null &&
154636
+ hoistableCursor.accessType === 'NonNull'
154637
+ ) {
154638
+ nextHoistableCursor = hoistableCursor.properties.get(entry.property);
154639
+ nextDepCursor = makeOrMergeProperty(
154640
+ depCursor,
154641
+ entry.property,
154642
+ PropertyAccessType.UnconditionalAccess
154643
+ );
154644
+ } else {
154645
+ break;
154646
+ }
154647
+ depCursor = nextDepCursor;
154648
+ hoistableCursor = nextHoistableCursor;
154518
154649
  }
154650
+ depCursor.accessType = merge(
154651
+ depCursor.accessType,
154652
+ PropertyAccessType.OptionalDependency
154653
+ );
154519
154654
  }
154520
154655
  deriveMinimalDependencies() {
154521
154656
  const results = new Set();
154522
154657
  for (const [rootId, rootNode] of __classPrivateFieldGet(
154523
154658
  this,
154524
- _ReactiveScopeDependencyTreeHIR_roots,
154659
+ _ReactiveScopeDependencyTreeHIR_deps,
154525
154660
  'f'
154526
154661
  ).entries()) {
154527
- {
154528
- assertWellFormedTree(rootNode);
154529
- }
154530
- const deps = deriveMinimalDependenciesInSubtree(rootNode, []);
154531
- for (const dep of deps) {
154532
- results.add({
154533
- identifier: rootId,
154534
- path: dep.path.map(s => ({property: s, optional: false})),
154535
- });
154536
- }
154662
+ collectMinimalDependenciesInSubtree(rootNode, rootId, [], results);
154537
154663
  }
154538
154664
  return results;
154539
154665
  }
@@ -154541,7 +154667,7 @@ class ReactiveScopeDependencyTreeHIR {
154541
154667
  let res = [];
154542
154668
  for (const [rootId, rootNode] of __classPrivateFieldGet(
154543
154669
  this,
154544
- _ReactiveScopeDependencyTreeHIR_roots,
154670
+ _ReactiveScopeDependencyTreeHIR_deps,
154545
154671
  'f'
154546
154672
  ).entries()) {
154547
154673
  const rootResults = printSubtree(rootNode, includeAccesses).map(
@@ -154551,95 +154677,106 @@ class ReactiveScopeDependencyTreeHIR {
154551
154677
  }
154552
154678
  return res.flat().join('\n');
154553
154679
  }
154680
+ static debug(roots) {
154681
+ const buf = [`tree() [`];
154682
+ for (const [rootId, rootNode] of roots) {
154683
+ buf.push(`${printIdentifier(rootId)} (${rootNode.accessType}):`);
154684
+ __classPrivateFieldGet(
154685
+ this,
154686
+ _a,
154687
+ 'm',
154688
+ _ReactiveScopeDependencyTreeHIR_debugImpl
154689
+ ).call(this, buf, rootNode, 1);
154690
+ }
154691
+ buf.push(']');
154692
+ return buf.length > 2 ? buf.join('\n') : buf.join('');
154693
+ }
154554
154694
  }
154555
- (_ReactiveScopeDependencyTreeHIR_roots = new WeakMap()),
154556
- (_ReactiveScopeDependencyTreeHIR_instances = new WeakSet()),
154695
+ (_a = ReactiveScopeDependencyTreeHIR),
154696
+ (_ReactiveScopeDependencyTreeHIR_hoistableObjects = new WeakMap()),
154697
+ (_ReactiveScopeDependencyTreeHIR_deps = new WeakMap()),
154557
154698
  (_ReactiveScopeDependencyTreeHIR_getOrCreateRoot =
154558
154699
  function _ReactiveScopeDependencyTreeHIR_getOrCreateRoot(
154559
154700
  identifier,
154560
- accessType
154701
+ roots,
154702
+ defaultAccessType
154561
154703
  ) {
154562
- let rootNode = __classPrivateFieldGet(
154563
- this,
154564
- _ReactiveScopeDependencyTreeHIR_roots,
154565
- 'f'
154566
- ).get(identifier);
154704
+ let rootNode = roots.get(identifier);
154567
154705
  if (rootNode === undefined) {
154568
- rootNode = {properties: new Map(), accessType: accessType};
154706
+ rootNode = {properties: new Map(), accessType: defaultAccessType};
154707
+ roots.set(identifier, rootNode);
154708
+ }
154709
+ return rootNode;
154710
+ }),
154711
+ (_ReactiveScopeDependencyTreeHIR_debugImpl =
154712
+ function _ReactiveScopeDependencyTreeHIR_debugImpl(buf, node, depth = 0) {
154713
+ for (const [property, childNode] of node.properties) {
154714
+ buf.push(
154715
+ `${' '.repeat(depth)}.${property} (${childNode.accessType}):`
154716
+ );
154569
154717
  __classPrivateFieldGet(
154570
154718
  this,
154571
- _ReactiveScopeDependencyTreeHIR_roots,
154572
- 'f'
154573
- ).set(identifier, rootNode);
154719
+ _a,
154720
+ 'm',
154721
+ _ReactiveScopeDependencyTreeHIR_debugImpl
154722
+ ).call(this, buf, childNode, depth + 1);
154574
154723
  }
154575
- return rootNode;
154576
154724
  });
154577
154725
  var PropertyAccessType;
154578
154726
  (function (PropertyAccessType) {
154579
- PropertyAccessType['Access'] = 'Access';
154580
- PropertyAccessType['NonNullAccess'] = 'NonNullAccess';
154581
- PropertyAccessType['Dependency'] = 'Dependency';
154582
- PropertyAccessType['NonNullDependency'] = 'NonNullDependency';
154727
+ PropertyAccessType['OptionalAccess'] = 'OptionalAccess';
154728
+ PropertyAccessType['UnconditionalAccess'] = 'UnconditionalAccess';
154729
+ PropertyAccessType['OptionalDependency'] = 'OptionalDependency';
154730
+ PropertyAccessType['UnconditionalDependency'] = 'UnconditionalDependency';
154583
154731
  })(PropertyAccessType || (PropertyAccessType = {}));
154584
- const MIN_ACCESS_TYPE = PropertyAccessType.Access;
154585
- function isNonNull(access) {
154732
+ function isOptional(access) {
154586
154733
  return (
154587
- access === PropertyAccessType.NonNullAccess ||
154588
- access === PropertyAccessType.NonNullDependency
154734
+ access === PropertyAccessType.OptionalAccess ||
154735
+ access === PropertyAccessType.OptionalDependency
154589
154736
  );
154590
154737
  }
154591
154738
  function isDependency(access) {
154592
154739
  return (
154593
- access === PropertyAccessType.Dependency ||
154594
- access === PropertyAccessType.NonNullDependency
154740
+ access === PropertyAccessType.OptionalDependency ||
154741
+ access === PropertyAccessType.UnconditionalDependency
154595
154742
  );
154596
154743
  }
154597
154744
  function merge(access1, access2) {
154598
- const resultisNonNull = isNonNull(access1) || isNonNull(access2);
154745
+ const resultIsUnconditional = !(isOptional(access1) && isOptional(access2));
154599
154746
  const resultIsDependency = isDependency(access1) || isDependency(access2);
154600
- if (resultisNonNull) {
154747
+ if (resultIsUnconditional) {
154601
154748
  if (resultIsDependency) {
154602
- return PropertyAccessType.NonNullDependency;
154749
+ return PropertyAccessType.UnconditionalDependency;
154603
154750
  } else {
154604
- return PropertyAccessType.NonNullAccess;
154751
+ return PropertyAccessType.UnconditionalAccess;
154605
154752
  }
154606
154753
  } else {
154607
154754
  if (resultIsDependency) {
154608
- return PropertyAccessType.Dependency;
154755
+ return PropertyAccessType.OptionalDependency;
154609
154756
  } else {
154610
- return PropertyAccessType.Access;
154757
+ return PropertyAccessType.OptionalAccess;
154611
154758
  }
154612
154759
  }
154613
154760
  }
154614
- function assertWellFormedTree(node) {
154615
- let nonNullInChildren = false;
154616
- for (const childNode of node.properties.values()) {
154617
- assertWellFormedTree(childNode);
154618
- nonNullInChildren || (nonNullInChildren = isNonNull(childNode.accessType));
154619
- }
154620
- if (nonNullInChildren) {
154621
- CompilerError.invariant(isNonNull(node.accessType), {
154622
- reason:
154623
- '[DeriveMinimialDependencies] Not well formed tree, unexpected non-null node',
154624
- description: node.accessType,
154625
- loc: GeneratedSource,
154626
- });
154627
- }
154628
- }
154629
- function deriveMinimalDependenciesInSubtree(node, path) {
154761
+ function collectMinimalDependenciesInSubtree(
154762
+ node,
154763
+ rootIdentifier,
154764
+ path,
154765
+ results
154766
+ ) {
154630
154767
  if (isDependency(node.accessType)) {
154631
- return [{path: path}];
154768
+ results.add({identifier: rootIdentifier, path: path});
154632
154769
  } else {
154633
- if (isNonNull(node.accessType)) {
154634
- const result = [];
154635
- for (const [childName, childNode] of node.properties) {
154636
- result.push(
154637
- ...deriveMinimalDependenciesInSubtree(childNode, [...path, childName])
154638
- );
154639
- }
154640
- return result;
154641
- } else {
154642
- return [{path: path}];
154770
+ for (const [childName, childNode] of node.properties) {
154771
+ collectMinimalDependenciesInSubtree(
154772
+ childNode,
154773
+ rootIdentifier,
154774
+ [
154775
+ ...path,
154776
+ {property: childName, optional: isOptional(childNode.accessType)},
154777
+ ],
154778
+ results
154779
+ );
154643
154780
  }
154644
154781
  }
154645
154782
  }
@@ -154664,6 +154801,192 @@ function makeOrMergeProperty(node, property, accessType) {
154664
154801
  }
154665
154802
  return child;
154666
154803
  }
154804
+ function collectOptionalChainSidemap(fn) {
154805
+ const context = {
154806
+ blocks: fn.body.blocks,
154807
+ seenOptionals: new Set(),
154808
+ processedInstrsInOptional: new Set(),
154809
+ temporariesReadInOptional: new Map(),
154810
+ hoistableObjects: new Map(),
154811
+ };
154812
+ for (const [_, block] of fn.body.blocks) {
154813
+ if (
154814
+ block.terminal.kind === 'optional' &&
154815
+ !context.seenOptionals.has(block.id)
154816
+ ) {
154817
+ traverseOptionalBlock(block, context, null);
154818
+ }
154819
+ }
154820
+ return {
154821
+ temporariesReadInOptional: context.temporariesReadInOptional,
154822
+ processedInstrsInOptional: context.processedInstrsInOptional,
154823
+ hoistableObjects: context.hoistableObjects,
154824
+ };
154825
+ }
154826
+ function matchOptionalTestBlock(terminal, blocks) {
154827
+ const consequentBlock = assertNonNull(blocks.get(terminal.consequent));
154828
+ if (
154829
+ consequentBlock.instructions.length === 2 &&
154830
+ consequentBlock.instructions[0].value.kind === 'PropertyLoad' &&
154831
+ consequentBlock.instructions[1].value.kind === 'StoreLocal'
154832
+ ) {
154833
+ const propertyLoad = consequentBlock.instructions[0];
154834
+ const storeLocal = consequentBlock.instructions[1].value;
154835
+ const storeLocalInstrId = consequentBlock.instructions[1].id;
154836
+ CompilerError.invariant(
154837
+ propertyLoad.value.object.identifier.id === terminal.test.identifier.id,
154838
+ {
154839
+ reason:
154840
+ '[OptionalChainDeps] Inconsistent optional chaining property load',
154841
+ description: `Test=${printIdentifier(terminal.test.identifier)} PropertyLoad base=${printIdentifier(propertyLoad.value.object.identifier)}`,
154842
+ loc: propertyLoad.loc,
154843
+ }
154844
+ );
154845
+ CompilerError.invariant(
154846
+ storeLocal.value.identifier.id === propertyLoad.lvalue.identifier.id,
154847
+ {
154848
+ reason: '[OptionalChainDeps] Unexpected storeLocal',
154849
+ loc: propertyLoad.loc,
154850
+ }
154851
+ );
154852
+ if (
154853
+ consequentBlock.terminal.kind !== 'goto' ||
154854
+ consequentBlock.terminal.variant !== GotoVariant.Break
154855
+ ) {
154856
+ return null;
154857
+ }
154858
+ const alternate = assertNonNull(blocks.get(terminal.alternate));
154859
+ CompilerError.invariant(
154860
+ alternate.instructions.length === 2 &&
154861
+ alternate.instructions[0].value.kind === 'Primitive' &&
154862
+ alternate.instructions[1].value.kind === 'StoreLocal',
154863
+ {reason: 'Unexpected alternate structure', loc: terminal.loc}
154864
+ );
154865
+ return {
154866
+ consequentId: storeLocal.lvalue.place.identifier.id,
154867
+ property: propertyLoad.value.property,
154868
+ propertyId: propertyLoad.lvalue.identifier.id,
154869
+ storeLocalInstrId: storeLocalInstrId,
154870
+ consequentGoto: consequentBlock.terminal.block,
154871
+ };
154872
+ }
154873
+ return null;
154874
+ }
154875
+ function traverseOptionalBlock(optional, context, outerAlternate) {
154876
+ context.seenOptionals.add(optional.id);
154877
+ const maybeTest = context.blocks.get(optional.terminal.test);
154878
+ let test;
154879
+ let baseObject;
154880
+ if (maybeTest.terminal.kind === 'branch') {
154881
+ CompilerError.invariant(optional.terminal.optional, {
154882
+ reason: '[OptionalChainDeps] Expect base case to be always optional',
154883
+ loc: optional.terminal.loc,
154884
+ });
154885
+ if (
154886
+ maybeTest.instructions.length === 0 ||
154887
+ maybeTest.instructions[0].value.kind !== 'LoadLocal'
154888
+ ) {
154889
+ return null;
154890
+ }
154891
+ const path = [];
154892
+ for (let i = 1; i < maybeTest.instructions.length; i++) {
154893
+ const instrVal = maybeTest.instructions[i].value;
154894
+ const prevInstr = maybeTest.instructions[i - 1];
154895
+ if (
154896
+ instrVal.kind === 'PropertyLoad' &&
154897
+ instrVal.object.identifier.id === prevInstr.lvalue.identifier.id
154898
+ ) {
154899
+ path.push({property: instrVal.property, optional: false});
154900
+ } else {
154901
+ return null;
154902
+ }
154903
+ }
154904
+ CompilerError.invariant(
154905
+ maybeTest.terminal.test.identifier.id ===
154906
+ maybeTest.instructions.at(-1).lvalue.identifier.id,
154907
+ {
154908
+ reason: '[OptionalChainDeps] Unexpected test expression',
154909
+ loc: maybeTest.terminal.loc,
154910
+ }
154911
+ );
154912
+ baseObject = {
154913
+ identifier: maybeTest.instructions[0].value.place.identifier,
154914
+ path: path,
154915
+ };
154916
+ test = maybeTest.terminal;
154917
+ } else if (maybeTest.terminal.kind === 'optional') {
154918
+ const testBlock = context.blocks.get(maybeTest.terminal.fallthrough);
154919
+ if (testBlock.terminal.kind !== 'branch') {
154920
+ CompilerError.throwTodo({
154921
+ reason: `Unexpected terminal kind \`${testBlock.terminal.kind}\` for optional fallthrough block`,
154922
+ loc: maybeTest.terminal.loc,
154923
+ });
154924
+ }
154925
+ const innerOptional = traverseOptionalBlock(
154926
+ maybeTest,
154927
+ context,
154928
+ testBlock.terminal.alternate
154929
+ );
154930
+ if (innerOptional == null) {
154931
+ return null;
154932
+ }
154933
+ if (testBlock.terminal.test.identifier.id !== innerOptional) {
154934
+ return null;
154935
+ }
154936
+ if (!optional.terminal.optional) {
154937
+ context.hoistableObjects.set(
154938
+ optional.id,
154939
+ assertNonNull(context.temporariesReadInOptional.get(innerOptional))
154940
+ );
154941
+ }
154942
+ baseObject = assertNonNull(
154943
+ context.temporariesReadInOptional.get(innerOptional)
154944
+ );
154945
+ test = testBlock.terminal;
154946
+ } else {
154947
+ return null;
154948
+ }
154949
+ if (test.alternate === outerAlternate) {
154950
+ CompilerError.invariant(optional.instructions.length === 0, {
154951
+ reason:
154952
+ '[OptionalChainDeps] Unexpected instructions an inner optional block. ' +
154953
+ 'This indicates that the compiler may be incorrectly concatenating two unrelated optional chains',
154954
+ loc: optional.terminal.loc,
154955
+ });
154956
+ }
154957
+ const matchConsequentResult = matchOptionalTestBlock(test, context.blocks);
154958
+ if (!matchConsequentResult) {
154959
+ return null;
154960
+ }
154961
+ CompilerError.invariant(
154962
+ matchConsequentResult.consequentGoto === optional.terminal.fallthrough,
154963
+ {
154964
+ reason: '[OptionalChainDeps] Unexpected optional goto-fallthrough',
154965
+ description: `${matchConsequentResult.consequentGoto} != ${optional.terminal.fallthrough}`,
154966
+ loc: optional.terminal.loc,
154967
+ }
154968
+ );
154969
+ const load = {
154970
+ identifier: baseObject.identifier,
154971
+ path: [
154972
+ ...baseObject.path,
154973
+ {
154974
+ property: matchConsequentResult.property,
154975
+ optional: optional.terminal.optional,
154976
+ },
154977
+ ],
154978
+ };
154979
+ context.processedInstrsInOptional.add(
154980
+ matchConsequentResult.storeLocalInstrId
154981
+ );
154982
+ context.processedInstrsInOptional.add(test.id);
154983
+ context.temporariesReadInOptional.set(
154984
+ matchConsequentResult.consequentId,
154985
+ load
154986
+ );
154987
+ context.temporariesReadInOptional.set(matchConsequentResult.propertyId, load);
154988
+ return matchConsequentResult.consequentId;
154989
+ }
154667
154990
  var _Context_instances,
154668
154991
  _Context_declarations,
154669
154992
  _Context_reassignments,
@@ -154677,18 +155000,37 @@ function propagateScopeDependenciesHIR(fn) {
154677
155000
  const usedOutsideDeclaringScope =
154678
155001
  findTemporariesUsedOutsideDeclaringScope(fn);
154679
155002
  const temporaries = collectTemporariesSidemap(fn, usedOutsideDeclaringScope);
154680
- const hoistablePropertyLoads = collectHoistablePropertyLoads(fn, temporaries);
155003
+ const {
155004
+ temporariesReadInOptional: temporariesReadInOptional,
155005
+ processedInstrsInOptional: processedInstrsInOptional,
155006
+ hoistableObjects: hoistableObjects,
155007
+ } = collectOptionalChainSidemap(fn);
155008
+ const hoistablePropertyLoads = collectHoistablePropertyLoads(
155009
+ fn,
155010
+ temporaries,
155011
+ hoistableObjects
155012
+ );
154681
155013
  const scopeDeps = collectDependencies(
154682
155014
  fn,
154683
155015
  usedOutsideDeclaringScope,
154684
- temporaries
155016
+ new Map([...temporaries, ...temporariesReadInOptional]),
155017
+ processedInstrsInOptional
154685
155018
  );
154686
155019
  for (const [scope, deps] of scopeDeps) {
154687
- const tree = new ReactiveScopeDependencyTreeHIR();
155020
+ if (deps.length === 0) {
155021
+ continue;
155022
+ }
155023
+ const hoistables = hoistablePropertyLoads.get(scope.id);
155024
+ CompilerError.invariant(hoistables != null, {
155025
+ reason: '[PropagateScopeDependencies] Scope not found in tracked blocks',
155026
+ loc: GeneratedSource,
155027
+ });
155028
+ const tree = new ReactiveScopeDependencyTreeHIR(
155029
+ [...hoistables.assumedNonNullObjects].map(o => o.fullPath)
155030
+ );
154688
155031
  for (const dep of deps) {
154689
155032
  tree.addDependency(Object.assign({}, dep));
154690
155033
  }
154691
- recordHoistablePropertyReads(hoistablePropertyLoads, scope.id, tree);
154692
155034
  const candidates = tree.deriveMinimalDependencies();
154693
155035
  for (const candidateDep of candidates) {
154694
155036
  if (
@@ -154765,7 +155107,12 @@ function collectTemporariesSidemap(fn, usedOutsideDeclaringScope) {
154765
155107
  lvalue.identifier.declarationId
154766
155108
  );
154767
155109
  if (value.kind === 'PropertyLoad' && !usedOutside) {
154768
- const property = getProperty(value.object, value.property, temporaries);
155110
+ const property = getProperty(
155111
+ value.object,
155112
+ value.property,
155113
+ false,
155114
+ temporaries
155115
+ );
154769
155116
  temporaries.set(lvalue.identifier.id, property);
154770
155117
  } else if (
154771
155118
  value.kind === 'LoadLocal' &&
@@ -154782,20 +155129,20 @@ function collectTemporariesSidemap(fn, usedOutsideDeclaringScope) {
154782
155129
  }
154783
155130
  return temporaries;
154784
155131
  }
154785
- function getProperty(object, propertyName, temporaries) {
155132
+ function getProperty(object, propertyName, optional, temporaries) {
154786
155133
  const resolvedDependency = temporaries.get(object.identifier.id);
154787
155134
  let property;
154788
155135
  if (resolvedDependency == null) {
154789
155136
  property = {
154790
155137
  identifier: object.identifier,
154791
- path: [{property: propertyName, optional: false}],
155138
+ path: [{property: propertyName, optional: optional}],
154792
155139
  };
154793
155140
  } else {
154794
155141
  property = {
154795
155142
  identifier: resolvedDependency.identifier,
154796
155143
  path: [
154797
155144
  ...resolvedDependency.path,
154798
- {property: propertyName, optional: false},
155145
+ {property: propertyName, optional: optional},
154799
155146
  ],
154800
155147
  };
154801
155148
  }
@@ -154914,10 +155261,11 @@ class Context {
154914
155261
  : {identifier: place.identifier, path: []}
154915
155262
  );
154916
155263
  }
154917
- visitProperty(object, property) {
155264
+ visitProperty(object, property, optional) {
154918
155265
  const nextDependency = getProperty(
154919
155266
  object,
154920
155267
  property,
155268
+ optional,
154921
155269
  __classPrivateFieldGet(this, _Context_temporaries, 'f')
154922
155270
  );
154923
155271
  this.visitDependency(nextDependency);
@@ -155048,7 +155396,7 @@ function handleInstruction(instr, context) {
155048
155396
  }
155049
155397
  } else if (value.kind === 'PropertyLoad') {
155050
155398
  if (context.isUsedOutsideDeclaringScope(lvalue)) {
155051
- context.visitProperty(value.object, value.property);
155399
+ context.visitProperty(value.object, value.property, false);
155052
155400
  }
155053
155401
  } else if (value.kind === 'StoreLocal') {
155054
155402
  context.visitOperand(value.value);
@@ -155079,7 +155427,12 @@ function handleInstruction(instr, context) {
155079
155427
  }
155080
155428
  context.declare(lvalue.identifier, {id: id, scope: context.currentScope});
155081
155429
  }
155082
- function collectDependencies(fn, usedOutsideDeclaringScope, temporaries) {
155430
+ function collectDependencies(
155431
+ fn,
155432
+ usedOutsideDeclaringScope,
155433
+ temporaries,
155434
+ processedInstrsInOptional
155435
+ ) {
155083
155436
  const context = new Context(usedOutsideDeclaringScope, temporaries);
155084
155437
  for (const param of fn.params) {
155085
155438
  if (param.kind === 'Identifier') {
@@ -155116,25 +155469,27 @@ function collectDependencies(fn, usedOutsideDeclaringScope, temporaries) {
155116
155469
  : scopeBlockInfo.pruned
155117
155470
  );
155118
155471
  }
155472
+ for (const phi of block.phis) {
155473
+ for (const operand of phi.operands) {
155474
+ const maybeOptionalChain = temporaries.get(operand[1].id);
155475
+ if (maybeOptionalChain) {
155476
+ context.visitDependency(maybeOptionalChain);
155477
+ }
155478
+ }
155479
+ }
155119
155480
  for (const instr of block.instructions) {
155120
- handleInstruction(instr, context);
155481
+ if (!processedInstrsInOptional.has(instr.id)) {
155482
+ handleInstruction(instr, context);
155483
+ }
155121
155484
  }
155122
- for (const place of eachTerminalOperand(block.terminal)) {
155123
- context.visitOperand(place);
155485
+ if (!processedInstrsInOptional.has(block.terminal.id)) {
155486
+ for (const place of eachTerminalOperand(block.terminal)) {
155487
+ context.visitOperand(place);
155488
+ }
155124
155489
  }
155125
155490
  }
155126
155491
  return context.deps;
155127
155492
  }
155128
- function recordHoistablePropertyReads(nodes, scopeId, tree) {
155129
- const node = nodes.get(scopeId);
155130
- CompilerError.invariant(node != null, {
155131
- reason: '[PropagateScopeDependencies] Scope not found in tracked blocks',
155132
- loc: GeneratedSource,
155133
- });
155134
- for (const item of node.assumedNonNullObjects) {
155135
- tree.markNodesNonNull(Object.assign({}, item.fullPath));
155136
- }
155137
- }
155138
155493
  function* run(
155139
155494
  func,
155140
155495
  config,