@markw65/monkeyc-optimizer 1.1.11 → 1.1.13

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.
@@ -6029,7 +6029,7 @@ function pragmaChecker(state, ast, diagnostics) {
6029
6029
  if (kind === "match") {
6030
6030
  const haystack = (0,external_api_cjs_namespaceObject.formatAst)(node)
6031
6031
  .replace(/([\r\n]|\s)+/g, " ")
6032
- .replace(/\b\w+\s\/\*>(\w+)<\*\//g, "$1");
6032
+ .replace(/\b\w+\s\/\*>([\w.]+)<\*\//g, "$1");
6033
6033
  if (!matcher(quote, needle, haystack)) {
6034
6034
  matcher(quote, needle, haystack);
6035
6035
  (0,external_api_cjs_namespaceObject.diagnostic)(state, comment, `Didn't find '${needle}' in '${haystack}'`, "ERROR");
@@ -10954,9 +10954,10 @@ function buildDataFlowGraph(state, func, wantsLiteral, trackInsertionPoints, wan
10954
10954
  decl,
10955
10955
  mayThrow,
10956
10956
  };
10957
- if (wantsAllRefs && node.operator === "=") {
10958
- if (node.right.type === "Identifier" ||
10959
- node.right.type === "MemberExpression") {
10957
+ if (wantsAllRefs) {
10958
+ if ((node.right.type === "Identifier" ||
10959
+ node.right.type === "MemberExpression") &&
10960
+ node.operator === "=") {
10960
10961
  const rhs = findDecl(node.right);
10961
10962
  if (rhs)
10962
10963
  def.rhs = rhs;
@@ -11182,19 +11183,20 @@ const external_node_assert_namespaceObject = require("node:assert");
11182
11183
 
11183
11184
 
11184
11185
 
11186
+
11185
11187
  function cloneAnt(antMap) {
11186
- const ant = new Map();
11187
- antMap.forEach((s, k) => ant.set(k, new Set(s)));
11188
- return ant;
11188
+ return new Map(antMap);
11189
11189
  }
11190
11190
  function addAnt(antMap, decl, node) {
11191
11191
  external_node_assert_namespaceObject(node.type === "Identifier");
11192
11192
  const ant = antMap.get(decl);
11193
- if (!ant) {
11194
- antMap.set(decl, new Set([node]));
11193
+ if (ant === false || ant === node)
11194
+ return;
11195
+ if (ant === undefined) {
11196
+ antMap.set(decl, node);
11195
11197
  }
11196
11198
  else {
11197
- ant.add(node);
11199
+ antMap.set(decl, false);
11198
11200
  }
11199
11201
  }
11200
11202
  function cloneState(blockState) {
@@ -11230,18 +11232,10 @@ function findDeadStores(func, graph, nodeEquivs, findCopyPropCandidates, logThis
11230
11232
  else {
11231
11233
  changed = Array.from(to.anticipated).reduce((changed, [decl, toant]) => {
11232
11234
  const fromant = from.anticipated.get(decl);
11233
- if (!fromant) {
11235
+ if (toant !== fromant) {
11234
11236
  to.anticipated.delete(decl);
11235
11237
  changed = true;
11236
11238
  }
11237
- else {
11238
- toant.forEach((node) => {
11239
- if (!fromant.has(node)) {
11240
- toant.delete(node);
11241
- changed = true;
11242
- }
11243
- });
11244
- }
11245
11239
  return changed;
11246
11240
  }, changed);
11247
11241
  }
@@ -11254,17 +11248,15 @@ function findDeadStores(func, graph, nodeEquivs, findCopyPropCandidates, logThis
11254
11248
  else {
11255
11249
  changed = Array.from(from.partiallyAnticipated).reduce((changed, [decl, fromant]) => {
11256
11250
  const toant = to.partiallyAnticipated.get(decl);
11257
- if (!toant) {
11251
+ if (toant === undefined) {
11258
11252
  to.partiallyAnticipated.set(decl, fromant);
11259
11253
  changed = true;
11260
11254
  }
11261
11255
  else {
11262
- fromant.forEach((node) => {
11263
- if (!toant.has(node)) {
11264
- changed = true;
11265
- toant.add(node);
11266
- }
11267
- });
11256
+ if (toant !== fromant) {
11257
+ changed = true;
11258
+ to.partiallyAnticipated.set(decl, false);
11259
+ }
11268
11260
  }
11269
11261
  return changed;
11270
11262
  }, changed);
@@ -11328,7 +11320,7 @@ function findDeadStores(func, graph, nodeEquivs, findCopyPropCandidates, logThis
11328
11320
  }
11329
11321
  addAnt(curState.partiallyAnticipated, event.decl, event.node);
11330
11322
  if (logThisRun) {
11331
- console.log(` antrefs: ${curState.partiallyAnticipated.get(event.decl)?.size ?? 0} ${curState.anticipated.get(event.decl)?.size ?? 0}`);
11323
+ console.log(` antrefs: ${curState.partiallyAnticipated.get(event.decl) !== false} ${curState.anticipated.get(event.decl) !== false}`);
11332
11324
  }
11333
11325
  }
11334
11326
  curState.dead.delete(event.decl);
@@ -11349,25 +11341,21 @@ function findDeadStores(func, graph, nodeEquivs, findCopyPropCandidates, logThis
11349
11341
  }
11350
11342
  else {
11351
11343
  deadStores.delete(event.node);
11352
- if (assignNode &&
11353
- declIsLocal(event.decl) &&
11354
- curState.partiallyAnticipated) {
11344
+ copyPropStores.delete(event.node);
11345
+ if (declIsLocal(event.decl) && curState.partiallyAnticipated) {
11355
11346
  const pant = curState.partiallyAnticipated.get(event.decl);
11356
- if (pant && pant.size === 1) {
11347
+ if (pant) {
11357
11348
  if (logThisRun) {
11358
- console.log(` is copy-prop-candidate ${curState.anticipated?.get(event.decl)?.size ?? 0}`);
11349
+ console.log(` is copy-prop-candidate ${curState.anticipated?.get(event.decl) === pant}`);
11359
11350
  }
11360
11351
  copyPropStores.set(event.node, {
11361
- ref: Array.from(pant)[0],
11362
- ant: curState.anticipated?.get(event.decl)?.size === 1,
11352
+ ref: pant,
11353
+ ant: curState.anticipated?.get(event.decl) === pant,
11363
11354
  });
11364
11355
  }
11365
11356
  curState.partiallyAnticipated.delete(event.decl);
11366
11357
  curState.anticipated?.delete(event.decl);
11367
11358
  }
11368
- else {
11369
- copyPropStores.delete(event.node);
11370
- }
11371
11359
  }
11372
11360
  if (nodeConflicts) {
11373
11361
  const conflicts = new Set(locals);
@@ -11456,7 +11444,10 @@ function eliminateDeadStores(state, func, graph, logThisRun) {
11456
11444
  console.log(`${(0,external_api_cjs_namespaceObject.formatAst)(dead)} (${sourceLocation(dead.loc)})`));
11457
11445
  }
11458
11446
  let changes = false;
11459
- (0,external_api_cjs_namespaceObject.traverseAst)(func.node.body, null, (node, parent) => {
11447
+ (0,external_api_cjs_namespaceObject.traverseAst)(func.node.body, null, (node) => {
11448
+ const cleaned = variableCleanup(node);
11449
+ if (cleaned !== null)
11450
+ return cleaned;
11460
11451
  if (node.type === "ExpressionStatement" &&
11461
11452
  node.expression.type === "AssignmentExpression" &&
11462
11453
  deadStores.has(node.expression)) {
@@ -11478,40 +11469,17 @@ function eliminateDeadStores(state, func, graph, logThisRun) {
11478
11469
  changes = true;
11479
11470
  return { type: "Literal", value: null, raw: "null" };
11480
11471
  }
11481
- if (node.type === "VariableDeclaration") {
11482
- const result = [];
11483
- for (let i = 0; i < node.declarations.length; i++) {
11484
- const decl = node.declarations[i];
11485
- if (decl.init && deadStores.has(decl)) {
11486
- const body = unused(state, decl.init);
11487
- if (body.length) {
11488
- if (!parent ||
11489
- (parent.type !== "BlockStatement" && parent.type !== "SwitchCase")) {
11490
- // Must be the init in a for statement. Fixing
11491
- // it would be complicated, so just punt for now.
11492
- break;
11493
- }
11494
- const newDeclaration = withLoc({ ...node }, node, decl.id);
11495
- if (i + 1 < node.declarations.length) {
11496
- newDeclaration.declarations = node.declarations.splice(0, i + 1);
11497
- result.push(newDeclaration);
11498
- withLoc(node, node.declarations[0], node);
11499
- i = -1;
11500
- }
11501
- else {
11502
- result.push(node);
11503
- }
11504
- result.push(...body);
11505
- }
11506
- changes = true;
11507
- delete decl.init;
11508
- }
11509
- }
11510
- if (result.length) {
11511
- if (!result.includes(node)) {
11512
- result.push(node);
11472
+ if (node.type === "VariableDeclarator") {
11473
+ const decl = node;
11474
+ if (decl.init && deadStores.has(decl)) {
11475
+ const body = unused(state, decl.init);
11476
+ delete decl.init;
11477
+ changes = true;
11478
+ if (!body.length) {
11479
+ return null;
11513
11480
  }
11514
- return result;
11481
+ body.unshift(decl);
11482
+ return body;
11515
11483
  }
11516
11484
  }
11517
11485
  return null;
@@ -11591,79 +11559,42 @@ function buildConflictGraph(state, func) {
11591
11559
  function addEquiv(ts, key, equiv) {
11592
11560
  if (key === equiv)
11593
11561
  return true;
11594
- let keyVal = ts.get(key);
11595
- let equivVal = ts.get(equiv);
11562
+ const keyVal = ts.get(key);
11563
+ const equivVal = ts.get(equiv);
11596
11564
  if (!keyVal || !equivVal)
11597
11565
  return false;
11598
11566
  if (equivVal.equivSet) {
11599
- if (keyVal.equivSet) {
11600
- // key is already a member of a set, see if
11601
- // equiv is part of it.
11602
- let s = keyVal.equivSet.next;
11603
- do {
11604
- if (s === equiv) {
11605
- // these two are already equivalent
11606
- return true;
11607
- }
11608
- const next = ts.get(s);
11609
- if (!next || !next.equivSet) {
11610
- throw new Error(`Inconsistent equivSet for ${tsKey(key)}: missing value for ${tsKey(s)}`);
11611
- }
11612
- s = next.equivSet.next;
11613
- } while (s !== key);
11567
+ if (equivVal.equivSet.has(key)) {
11568
+ return true;
11614
11569
  }
11615
11570
  // equiv is already a member of a set. remove it
11616
11571
  removeEquiv(ts, equiv);
11617
11572
  }
11618
11573
  // equiv is not (or no longer) part of an equivSet
11619
- keyVal = { ...keyVal };
11620
11574
  if (!keyVal.equivSet) {
11621
- keyVal.equivSet = { next: key };
11575
+ keyVal.equivSet = new Set([key, equiv]);
11576
+ }
11577
+ else {
11578
+ keyVal.equivSet.add(equiv);
11622
11579
  }
11623
- equivVal = { ...equivVal, equivSet: keyVal.equivSet };
11624
- keyVal.equivSet = { next: equiv };
11625
- ts.set(key, keyVal);
11626
- ts.set(equiv, equivVal);
11580
+ equivVal.equivSet = keyVal.equivSet;
11627
11581
  return false;
11628
11582
  }
11629
11583
  function removeEquiv(ts, equiv) {
11630
11584
  const equivVal = ts.get(equiv);
11631
11585
  if (!equivVal?.equivSet)
11632
11586
  return;
11633
- let s = equivVal.equivSet.next;
11634
- do {
11635
- const next = ts.get(s);
11636
- if (!next || !next.equivSet) {
11637
- throw new Error(`Inconsistent equivSet for ${tsKey(equiv)}: missing value for ${tsKey(s)}`);
11638
- }
11639
- if (next.equivSet.next === equiv) {
11640
- const { equivSet: _e, ...rest } = next;
11641
- if (equivVal.equivSet.next === s) {
11642
- // this is a pair. just kill both
11643
- ts.set(s, rest);
11644
- }
11645
- else {
11646
- ts.set(s, { ...rest, equivSet: equivVal.equivSet });
11647
- }
11648
- break;
11649
- }
11650
- s = next.equivSet.next;
11651
- } while (true);
11652
- const newVal = { ...equivVal };
11653
- delete newVal.equivSet;
11654
- ts.set(equiv, newVal);
11587
+ equivVal.equivSet.delete(equiv);
11588
+ if (equivVal.equivSet.size === 1) {
11589
+ const other = Array.from(equivVal.equivSet)[0];
11590
+ const otherVal = ts.get(other);
11591
+ delete otherVal.equivSet;
11592
+ }
11593
+ delete equivVal.equivSet;
11655
11594
  }
11656
11595
  function getEquivSet(ts, k) {
11657
- const keys = new Set();
11658
- let s = k;
11659
- do {
11660
- const next = ts.get(s);
11661
- if (!next || !next.equivSet) {
11662
- throw new Error(`Inconsistent equivSet for ${tsKey(k)}: missing value for ${tsKey(s)}`);
11663
- }
11664
- keys.add(s);
11665
- s = next.equivSet.next;
11666
- } while (s !== k);
11596
+ const keys = ts.get(k)?.equivSet;
11597
+ external_node_assert_namespaceObject(keys);
11667
11598
  return keys;
11668
11599
  }
11669
11600
  function intersectEquiv(ts1, ts2, k) {
@@ -11675,21 +11606,26 @@ function intersectEquiv(ts1, ts2, k) {
11675
11606
  removeEquiv(ts1, k);
11676
11607
  return true;
11677
11608
  }
11678
- const keys = getEquivSet(ts2, k);
11679
- let ret = false;
11680
- let s = eq1.equivSet.next;
11681
- do {
11682
- const next = ts1.get(s);
11683
- if (!next || !next.equivSet) {
11684
- throw new Error(`Inconsistent equivSet for ${tsKey(k)}: missing value for ${tsKey(s)}`);
11685
- }
11686
- if (!keys.has(s)) {
11687
- ret = true;
11688
- removeEquiv(ts1, s);
11609
+ let removed = null;
11610
+ eq1.equivSet.forEach((key) => {
11611
+ if (!eq2.equivSet.has(key)) {
11612
+ eq1.equivSet.delete(key);
11613
+ if (!removed) {
11614
+ removed = new Set();
11615
+ }
11616
+ removed.add(key);
11689
11617
  }
11690
- s = next.equivSet.next;
11691
- } while (s !== k);
11692
- return ret;
11618
+ });
11619
+ if (eq1.equivSet.size === 1) {
11620
+ external_node_assert_namespaceObject(eq1.equivSet.has(k));
11621
+ delete eq1.equivSet;
11622
+ }
11623
+ if (removed) {
11624
+ removed.forEach((k) => removed.size === 1
11625
+ ? delete ts1.get(k).equivSet
11626
+ : (ts1.get(k).equivSet = removed));
11627
+ }
11628
+ return false;
11693
11629
  }
11694
11630
  function clearAssocPaths(blockState, decl, v) {
11695
11631
  if (v.assocPaths?.size) {
@@ -11707,6 +11643,17 @@ function clearAssocPaths(blockState, decl, v) {
11707
11643
  function cloneTypeState(blockState) {
11708
11644
  const { map, trackedMemberDecls, liveCopyPropEvents, ...rest } = blockState;
11709
11645
  const clone = { map: new Map(map), ...rest };
11646
+ clone.map.forEach((value, key) => {
11647
+ if (value.equivSet) {
11648
+ if (key === Array.from(value.equivSet)[0]) {
11649
+ const equivSet = new Set(value.equivSet);
11650
+ equivSet.forEach((k) => clone.map.set(k, { ...clone.map.get(k), equivSet }));
11651
+ }
11652
+ }
11653
+ else {
11654
+ clone.map.set(key, { ...value });
11655
+ }
11656
+ });
11710
11657
  if (trackedMemberDecls) {
11711
11658
  clone.trackedMemberDecls = new Map();
11712
11659
  trackedMemberDecls.forEach((value, key) => {
@@ -11741,12 +11688,9 @@ function addCopyPropEvent(blockState, item) {
11741
11688
  const liveCopyPropEvents = blockState.liveCopyPropEvents;
11742
11689
  const decl = item.event.decl;
11743
11690
  external_node_assert_namespaceObject(declIsLocal(decl));
11744
- let tov = blockState.map.get(decl);
11691
+ const tov = blockState.map.get(decl);
11745
11692
  external_node_assert_namespaceObject(tov);
11746
- if (tov.copyPropItem !== item) {
11747
- tov = { ...tov, copyPropItem: item };
11748
- blockState.map.set(decl, tov);
11749
- }
11693
+ tov.copyPropItem = item;
11750
11694
  item.contained.forEach((value, key) => {
11751
11695
  const decls = liveCopyPropEvents.get(key);
11752
11696
  if (!decls) {
@@ -11779,15 +11723,13 @@ function clearRelatedCopyPropEvents(blockState, decl, nodeCopyProp) {
11779
11723
  blockState.liveCopyPropEvents
11780
11724
  ?.get(decl)
11781
11725
  ?.forEach((cpDecl) => {
11782
- let value = blockState.map.get(cpDecl);
11726
+ const value = blockState.map.get(cpDecl);
11783
11727
  external_node_assert_namespaceObject(value && value.copyPropItem);
11784
11728
  external_node_assert_namespaceObject(Array.from(value.copyPropItem.contained).some(([key]) => {
11785
11729
  return decl === key;
11786
11730
  }));
11787
11731
  copyPropFailed(blockState, value.copyPropItem, nodeCopyProp);
11788
- value = { ...value };
11789
11732
  delete value.copyPropItem;
11790
- blockState.map.set(cpDecl, value);
11791
11733
  });
11792
11734
  }
11793
11735
  function validateTypeState(curState) {
@@ -11830,11 +11772,9 @@ function mergeTypeState(blockStates, index, from, nodeCopyProp) {
11830
11772
  if (tov.equivSet) {
11831
11773
  if (intersectEquiv(to.map, from.map, k)) {
11832
11774
  changes = true;
11833
- tov = to.map.get(k);
11834
11775
  }
11835
11776
  }
11836
11777
  if (tov.assocPaths) {
11837
- tov = { ...tov };
11838
11778
  if (!fromv.assocPaths) {
11839
11779
  changes = true;
11840
11780
  delete tov.assocPaths;
@@ -11857,7 +11797,6 @@ function mergeTypeState(blockStates, index, from, nodeCopyProp) {
11857
11797
  delete tov.assocPaths;
11858
11798
  }
11859
11799
  }
11860
- to.map.set(k, tov);
11861
11800
  }
11862
11801
  // if both from and to have copyPropEvents, we can only
11863
11802
  // keep it if they're the same event.
@@ -11875,10 +11814,8 @@ function mergeTypeState(blockStates, index, from, nodeCopyProp) {
11875
11814
  }
11876
11815
  nodeCopyProp.set(fromv.copyPropItem.event.node, false);
11877
11816
  }
11878
- tov = { ...tov };
11879
11817
  delete tov.copyPropItem;
11880
11818
  changes = true;
11881
- to.map.set(k, tov);
11882
11819
  }
11883
11820
  else {
11884
11821
  external_node_assert_namespaceObject(k === tov.copyPropItem.event.decl);
@@ -11889,7 +11826,7 @@ function mergeTypeState(blockStates, index, from, nodeCopyProp) {
11889
11826
  if (subtypeOf(fromv.curType, tov.curType))
11890
11827
  return;
11891
11828
  if (subtypeOf(tov.curType, fromv.curType)) {
11892
- to.map.set(k, { ...tov, curType: fromv.curType });
11829
+ tov.curType = fromv.curType;
11893
11830
  changes = true;
11894
11831
  return;
11895
11832
  }
@@ -11902,22 +11839,11 @@ function mergeTypeState(blockStates, index, from, nodeCopyProp) {
11902
11839
  if (wide)
11903
11840
  result = wide;
11904
11841
  }
11905
- to.map.set(k, { ...tov, curType: result });
11842
+ tov.curType = result;
11906
11843
  changes = true;
11907
11844
  });
11908
11845
  return changes;
11909
11846
  }
11910
- function tsEquivs(state, key) {
11911
- const result = [];
11912
- let s = key;
11913
- do {
11914
- result.push(tsKey(s));
11915
- const next = state.get(s);
11916
- external_node_assert_namespaceObject(next && next.equivSet);
11917
- s = next.equivSet.next;
11918
- } while (s !== key);
11919
- return `[(${result.join(", ")})]`;
11920
- }
11921
11847
  function typeStateEntry(value, key) {
11922
11848
  return `${tsKey(key)} = ${display(value.curType)}`;
11923
11849
  }
@@ -11928,7 +11854,9 @@ function printBlockState(block, state, indent = "") {
11928
11854
  return;
11929
11855
  }
11930
11856
  state.map.forEach((value, key) => {
11931
- console.log(`${indent} - ${typeStateEntry(value, key)}${value.equivSet ? " " + tsEquivs(state.map, key) : ""}`);
11857
+ console.log(`${indent} - ${typeStateEntry(value, key)}${value.equivSet
11858
+ ? " " + `[(${Array.from(value.equivSet).map(tsKey).join(", ")})]`
11859
+ : ""}`);
11932
11860
  });
11933
11861
  }
11934
11862
  function updateAffected(blockState, objectType, baseDecl, assignedPath, affectedName, affected, assignedType) {
@@ -11936,7 +11864,6 @@ function updateAffected(blockState, objectType, baseDecl, assignedPath, affected
11936
11864
  let droppedComponents = null;
11937
11865
  const entry = blockState.map.get(key);
11938
11866
  external_node_assert_namespaceObject(entry && entry.assocPaths);
11939
- let newEntry = entry;
11940
11867
  entry.assocPaths.forEach((path) => {
11941
11868
  if (key === baseDecl && path === assignedPath) {
11942
11869
  return;
@@ -11955,12 +11882,9 @@ function updateAffected(blockState, objectType, baseDecl, assignedPath, affected
11955
11882
  });
11956
11883
  if (pathItem === affectedName && couldBeShallow(type, objectType)) {
11957
11884
  const newAssocKey = assocPath.map((av) => av.name ?? "*").join(".");
11958
- if (newEntry === entry) {
11959
- newEntry = { ...entry };
11960
- }
11961
11885
  if (newAssocKey !== path) {
11962
- newEntry.assocPaths = new Set(newEntry.assocPaths);
11963
- newEntry.assocPaths.delete(path);
11886
+ entry.assocPaths = new Set(entry.assocPaths);
11887
+ entry.assocPaths.delete(path);
11964
11888
  // the "extra" path components will also have entries
11965
11889
  // in blockState.trackedMemberDecls. Since they're gone
11966
11890
  // from here, we (may) need to remove them from there
@@ -11972,8 +11896,7 @@ function updateAffected(blockState, objectType, baseDecl, assignedPath, affected
11972
11896
  }
11973
11897
  break;
11974
11898
  }
11975
- const baseType = updateByAssocPath(assocPath, assignedType, true);
11976
- newEntry.curType = baseType;
11899
+ entry.curType = updateByAssocPath(assocPath, assignedType, true);
11977
11900
  break;
11978
11901
  }
11979
11902
  if (pathItem === "*") {
@@ -12003,14 +11926,11 @@ function updateAffected(blockState, objectType, baseDecl, assignedPath, affected
12003
11926
  }
12004
11927
  }
12005
11928
  });
12006
- if (newEntry !== entry) {
12007
- if (droppedComponents) {
12008
- newEntry.assocPaths.forEach((path) => path
12009
- .split(".")
12010
- .forEach((pathComponent) => droppedComponents.delete(pathComponent)));
12011
- droppedComponents.forEach((pathComponent) => blockState.trackedMemberDecls.get(pathComponent).delete(key));
12012
- }
12013
- blockState.map.set(key, newEntry);
11929
+ if (droppedComponents) {
11930
+ entry.assocPaths.forEach((path) => path
11931
+ .split(".")
11932
+ .forEach((pathComponent) => droppedComponents.delete(pathComponent)));
11933
+ droppedComponents.forEach((pathComponent) => blockState.trackedMemberDecls.get(pathComponent).delete(key));
12014
11934
  }
12015
11935
  });
12016
11936
  }
@@ -12117,10 +12037,9 @@ function propagateTypes(state, func, graph, optimizeEquivalencies, copyPropStore
12117
12037
  const assocKey = assocValue.map((av) => av.name ?? "*").join(".");
12118
12038
  const newType = updateByAssocPath(assocValue, next, false);
12119
12039
  setStateEvent(blockState, decl.base, newType, newValue ? 1 /* UpdateKind.Inner */ : 0 /* UpdateKind.None */);
12120
- const tsv = { ...blockState.map.get(decl.base) };
12040
+ const tsv = blockState.map.get(decl.base);
12121
12041
  tsv.assocPaths = new Set(tsv.assocPaths);
12122
12042
  tsv.assocPaths.add(assocKey);
12123
- blockState.map.set(decl.base, tsv);
12124
12043
  addTrackedMemberDecl(blockState, decl.base, assocKey);
12125
12044
  if (newValue) {
12126
12045
  const baseElem = assocValue[decl.path.length - 1];
@@ -12198,38 +12117,39 @@ function propagateTypes(state, func, graph, optimizeEquivalencies, copyPropStore
12198
12117
  // that foo is side-effect free, and accesses no globals.
12199
12118
  clearRelatedCopyPropEvents(blockState, decl, nodeCopyProp);
12200
12119
  }
12120
+ const v = blockState.map.get(decl);
12121
+ if (!v) {
12122
+ blockState.map.set(decl, { curType: value });
12123
+ return;
12124
+ }
12201
12125
  if (updateKind !== 2 /* UpdateKind.Reassign */) {
12202
12126
  /*
12203
12127
  * If we're not re-assigning, the equivalencies don't
12204
12128
  * change, so this update must be applied to every
12205
12129
  * element of the set
12206
12130
  */
12207
- const v = blockState.map.get(decl);
12208
- if (v?.equivSet) {
12209
- let s = decl;
12210
- do {
12131
+ if (v.equivSet) {
12132
+ v.equivSet.forEach((s) => {
12211
12133
  const next = blockState.map.get(s);
12212
- if (!next || !next.equivSet) {
12213
- throw new Error(`Inconsistent equivSet for ${tsKey(decl)}: missing value for ${tsKey(s)}`);
12214
- }
12215
- blockState.map.set(s, { ...next, curType: value });
12216
- s = next.equivSet.next;
12217
- } while (s !== decl);
12134
+ external_node_assert_namespaceObject(next && next.equivSet?.has(s));
12135
+ next.curType = value;
12136
+ });
12218
12137
  }
12219
12138
  else {
12220
- blockState.map.set(decl, { ...v, curType: value });
12139
+ v.curType = value;
12221
12140
  }
12222
12141
  }
12223
12142
  else {
12224
- const v = blockState.map.get(decl);
12225
12143
  removeEquiv(blockState.map, decl);
12226
- if (v?.assocPaths?.size) {
12144
+ if (v.assocPaths?.size) {
12227
12145
  clearAssocPaths(blockState, decl, v);
12146
+ delete v.assocPaths;
12228
12147
  }
12229
- if (v?.copyPropItem) {
12148
+ if (v.copyPropItem) {
12230
12149
  copyPropFailed(blockState, v.copyPropItem, nodeCopyProp);
12150
+ delete v.copyPropItem;
12231
12151
  }
12232
- blockState.map.set(decl, { curType: value });
12152
+ v.curType = value;
12233
12153
  }
12234
12154
  return;
12235
12155
  }
@@ -12563,7 +12483,7 @@ function propagateTypes(state, func, graph, optimizeEquivalencies, copyPropStore
12563
12483
  break;
12564
12484
  }
12565
12485
  case "ref": {
12566
- let curEntry = getStateEntry(curState, event.decl);
12486
+ const curEntry = getStateEntry(curState, event.decl);
12567
12487
  typeMap.set(event.node, curEntry.curType);
12568
12488
  nodeEquivs.delete(event.node);
12569
12489
  if (curEntry.equivSet) {
@@ -12587,9 +12507,7 @@ function propagateTypes(state, func, graph, optimizeEquivalencies, copyPropStore
12587
12507
  nodeCopyProp.set(curEntry.copyPropItem.event.node, event.node);
12588
12508
  }
12589
12509
  clearCopyProp(curState, curEntry.copyPropItem);
12590
- curEntry = { ...curEntry };
12591
12510
  delete curEntry.copyPropItem;
12592
- curState.map.set(event.decl, curEntry);
12593
12511
  }
12594
12512
  else if (declIsNonLocal(event.decl)) {
12595
12513
  clearRelatedCopyPropEvents(curState, null, nodeCopyProp);
@@ -12627,12 +12545,13 @@ function propagateTypes(state, func, graph, optimizeEquivalencies, copyPropStore
12627
12545
  }
12628
12546
  });
12629
12547
  }
12548
+ let calleeEffects;
12630
12549
  curState.map.forEach((tsv, decl) => {
12631
12550
  let type = tsv.curType;
12632
- if (!(0,external_util_cjs_namespaceObject.some)(decl, (d) => d.type === "VariableDeclarator" &&
12633
- (d.node.kind === "var" ||
12634
- // even a "const" could have its "inner" type altered
12635
- (type.value != null && (type.type & 32768 /* TypeTag.Object */) !== 0)))) {
12551
+ if ((type.value == null ||
12552
+ !(type.type &
12553
+ (32768 /* TypeTag.Object */ | 512 /* TypeTag.Array */ | 1024 /* TypeTag.Dictionary */))) &&
12554
+ !(0,external_util_cjs_namespaceObject.some)(decl, (d) => d.type === "VariableDeclarator" && !(0,external_api_cjs_namespaceObject.isLocal)(d))) {
12636
12555
  return;
12637
12556
  }
12638
12557
  if (modifiableDecl(decl, callees)) {
@@ -12648,9 +12567,14 @@ function propagateTypes(state, func, graph, optimizeEquivalencies, copyPropStore
12648
12567
  clearRelatedCopyPropEvents(curState, decl, nodeCopyProp);
12649
12568
  curState.map.set(decl, { curType: typeConstraint(decl) });
12650
12569
  }
12651
- else if (type.value != null &&
12652
- (!callees || !(0,external_util_cjs_namespaceObject.every)(callees, (callee) => callee.info === false))) {
12653
- if (type.type & 32768 /* TypeTag.Object */) {
12570
+ else if (type.type &
12571
+ (32768 /* TypeTag.Object */ | 512 /* TypeTag.Array */ | 1024 /* TypeTag.Dictionary */) &&
12572
+ (calleeEffects == null
12573
+ ? (calleeEffects =
12574
+ !callees ||
12575
+ !(0,external_util_cjs_namespaceObject.every)(callees, (callee) => callee.info === false))
12576
+ : calleeEffects)) {
12577
+ if (type.value != null && type.type & 32768 /* TypeTag.Object */) {
12654
12578
  const odata = getObjectValue(tsv.curType);
12655
12579
  if (odata?.obj) {
12656
12580
  type = cloneType(type);
@@ -12658,18 +12582,12 @@ function propagateTypes(state, func, graph, optimizeEquivalencies, copyPropStore
12658
12582
  setUnionComponent(type, 32768 /* TypeTag.Object */, newData);
12659
12583
  if (tsv.assocPaths) {
12660
12584
  clearAssocPaths(curState, decl, tsv);
12661
- tsv = { ...tsv };
12662
12585
  delete tsv.assocPaths;
12663
12586
  }
12664
- if (tsv.copyPropItem) {
12665
- copyPropFailed(curState, tsv.copyPropItem, nodeCopyProp);
12666
- tsv = { ...tsv };
12667
- delete tsv.copyPropItem;
12668
- }
12669
- clearRelatedCopyPropEvents(curState, decl, nodeCopyProp);
12670
- curState.map.set(decl, { ...tsv, curType: type });
12587
+ tsv.curType = type;
12671
12588
  }
12672
12589
  }
12590
+ clearRelatedCopyPropEvents(curState, decl, nodeCopyProp);
12673
12591
  }
12674
12592
  });
12675
12593
  return true;
@@ -12691,10 +12609,7 @@ function propagateTypes(state, func, graph, optimizeEquivalencies, copyPropStore
12691
12609
  (event.node.type !== "AssignmentExpression" ||
12692
12610
  event.node.operator !== "=")) {
12693
12611
  copyPropFailed(curState, before.copyPropItem, nodeCopyProp);
12694
- const v = { ...before };
12695
- delete v.copyPropItem;
12696
- external_node_assert_namespaceObject(isTypeStateKey(event.decl));
12697
- curState.map.set(event.decl, v);
12612
+ delete before.copyPropItem;
12698
12613
  }
12699
12614
  }
12700
12615
  const expr = event.node.type === "VariableDeclarator"
@@ -12788,22 +12703,41 @@ function propagateTypes(state, func, graph, optimizeEquivalencies, copyPropStore
12788
12703
  decl.type === "BinaryExpression" ||
12789
12704
  decl.type === "Identifier"))) {
12790
12705
  const key = event.decl ?? null;
12791
- if (key &&
12792
- declIsLocal(key) &&
12793
- nodeCopyProp.has(event.node)) {
12794
- // we might have
12795
- //
12796
- // var x = foo();
12797
- // var y = x + 1;
12798
- // bar();
12799
- // return y;
12800
- //
12801
- // In that case, its ok to drop "x = foo()" and rewrite as y = foo() + 1"
12802
- // OR its ok to drop "y = x + 1" and rewrite as "return x + 1".
12803
- // But we can't do both, and rewrite as "bar(); return foo() + 1;"
12804
- // So just disable copy prop for *this* node. We'll re-run and have a
12805
- // second chance later.
12806
- return false;
12706
+ if (key && declIsLocal(key)) {
12707
+ if (nodeCopyProp.has(event.node)) {
12708
+ // we might have
12709
+ //
12710
+ // var x = foo();
12711
+ // var y = x + 1;
12712
+ // bar();
12713
+ // return y;
12714
+ //
12715
+ // In that case, its ok to drop "x = foo()" and rewrite as y = foo() + 1"
12716
+ // OR its ok to drop "y = x + 1" and rewrite as "return x + 1".
12717
+ // But we can't do both, and rewrite as "bar(); return foo() + 1;"
12718
+ // So just disable copy prop for *this* node. We'll re-run and have a
12719
+ // second chance later.
12720
+ return false;
12721
+ }
12722
+ else if (event.node.type === "AssignmentExpression" &&
12723
+ event.node.operator !== "=" &&
12724
+ nodeCopyProp.has(event.node.left)) {
12725
+ // If we're copy proping into the lhs of an update
12726
+ // assignment, we're going to have to rewrite it.
12727
+ // similar to the above, don't also do forward copy
12728
+ // prop. eg
12729
+ //
12730
+ // var x = a + b;
12731
+ // x += c;
12732
+ // return x;
12733
+ //
12734
+ // becomes
12735
+ //
12736
+ // var x;
12737
+ // x = (a + b) + c;
12738
+ // return x; // <- dont propagate to here (yet), in case a+b has changed.
12739
+ return false;
12740
+ }
12807
12741
  }
12808
12742
  const item = contained.get(key);
12809
12743
  if (!item) {
@@ -12992,7 +12926,22 @@ function propagateTypes(state, func, graph, optimizeEquivalencies, copyPropStore
12992
12926
  }
12993
12927
  }
12994
12928
  }));
12995
- (0,external_api_cjs_namespaceObject.traverseAst)(func.node.body, null, (node) => {
12929
+ (0,external_api_cjs_namespaceObject.traverseAst)(func.node.body, (node) => {
12930
+ if (node.type === "AssignmentExpression" &&
12931
+ node.operator !== "=" &&
12932
+ nodeCopyProp.has(node.left)) {
12933
+ const left = cloneDeep(node.left);
12934
+ const right = withLoc({
12935
+ type: "BinaryExpression",
12936
+ operator: node.operator.slice(0, -1),
12937
+ left: withLocDeep(node.left, node.right, false, true),
12938
+ right: node.right,
12939
+ }, node.left, node.right);
12940
+ node.operator = "=";
12941
+ node.left = left;
12942
+ node.right = right;
12943
+ }
12944
+ }, (node) => {
12996
12945
  const copyNode = nodeCopyProp.get(node);
12997
12946
  if (copyNode) {
12998
12947
  if (node.type === "AssignmentExpression") {
@@ -13011,10 +12960,18 @@ function propagateTypes(state, func, graph, optimizeEquivalencies, copyPropStore
13011
12960
  return dup;
13012
12961
  }
13013
12962
  if (copyNode.type === "AssignmentExpression") {
12963
+ const replacement = copyNode.operator === "="
12964
+ ? copyNode.right
12965
+ : {
12966
+ type: "BinaryExpression",
12967
+ operator: copyNode.operator.slice(0, -1),
12968
+ left: copyNode.left,
12969
+ right: copyNode.right,
12970
+ };
13014
12971
  if (logThisRun) {
13015
- console.log(`copy-prop ${(0,external_api_cjs_namespaceObject.formatAstLongLines)(node)} => ${(0,external_api_cjs_namespaceObject.formatAstLongLines)(copyNode.right)}`);
12972
+ console.log(`copy-prop ${(0,external_api_cjs_namespaceObject.formatAstLongLines)(node)} => ${(0,external_api_cjs_namespaceObject.formatAstLongLines)(replacement)}`);
13016
12973
  }
13017
- return withLocDeep(copyNode.right, node, node, false);
12974
+ return withLocDeep(replacement, node, node, false);
13018
12975
  }
13019
12976
  else if (copyNode.type === "VariableDeclarator") {
13020
12977
  external_node_assert_namespaceObject(copyNode.init);
@@ -13321,11 +13278,6 @@ function minimizeLocals(state, func) {
13321
13278
  return null;
13322
13279
  }
13323
13280
  break;
13324
- case "ExpressionStatement":
13325
- if (node.expression.type === "Literal") {
13326
- return false;
13327
- }
13328
- break;
13329
13281
  case "UpdateExpression":
13330
13282
  if (info) {
13331
13283
  external_node_assert_namespaceObject(node.argument.type === "Identifier");
@@ -13346,7 +13298,7 @@ function minimizeLocals(state, func) {
13346
13298
  }
13347
13299
  // VariableDeclarations aren't allowed to have
13348
13300
  // AssignmentExpressions in them, but we'll fix that
13349
- // below
13301
+ // via variableCleanup
13350
13302
  return withLoc({
13351
13303
  type: "AssignmentExpression",
13352
13304
  operator: "=",
@@ -13359,79 +13311,92 @@ function minimizeLocals(state, func) {
13359
13311
  }, node, node);
13360
13312
  }
13361
13313
  break;
13362
- case "VariableDeclaration":
13363
- if (node.declarations.some((decl) => decl.type !== "VariableDeclarator")) {
13364
- const results = [];
13365
- node.declarations.forEach((decl) => {
13366
- if (isExpression(decl)) {
13367
- results.push(withLoc({ type: "ExpressionStatement", expression: decl }, decl, decl));
13368
- }
13369
- else if (decl.init) {
13370
- results.push(withLoc({
13371
- type: "ExpressionStatement",
13372
- expression: withLoc({
13373
- type: "AssignmentExpression",
13374
- operator: "=",
13375
- left: withLoc({
13376
- type: "Identifier",
13377
- name: (0,external_api_cjs_namespaceObject.variableDeclarationName)(decl.id),
13378
- }, decl.id, decl.id),
13379
- right: decl.init,
13380
- }, decl, decl),
13381
- }, decl, decl));
13382
- }
13383
- });
13384
- node.declarations = node.declarations.filter((decl) => {
13385
- if (decl.type === "VariableDeclarator") {
13386
- delete decl.init;
13387
- return true;
13388
- }
13389
- return false;
13390
- });
13391
- if (node.declarations.length) {
13392
- withLocDeep(node, node, false);
13393
- results.unshift(node);
13314
+ }
13315
+ external_node_assert_namespaceObject(!info);
13316
+ return variableCleanup(node);
13317
+ });
13318
+ return;
13319
+ }
13320
+ function variableCleanup(node) {
13321
+ switch (node.type) {
13322
+ case "ExpressionStatement":
13323
+ if (node.expression.type === "Literal") {
13324
+ return false;
13325
+ }
13326
+ break;
13327
+ case "VariableDeclaration":
13328
+ if (node.declarations.some((decl) => decl.type !== "VariableDeclarator")) {
13329
+ const results = [];
13330
+ node.declarations.forEach((decl) => {
13331
+ if (isStatement(decl)) {
13332
+ results.push(decl);
13394
13333
  }
13395
- // if this was the init of a ForStatement, this will
13396
- // replace its init with a BlockStatement, so we have to
13397
- // fix that below.
13398
- return results;
13399
- }
13400
- break;
13401
- case "ForStatement":
13402
- if (node.init) {
13403
- if (node.init.type === "BlockStatement") {
13404
- const result = node.init;
13405
- delete node.init;
13406
- result.body.push(node);
13407
- if (node.loc && result.loc) {
13408
- // result has the range of the original VariableDeclaration
13409
- // but now we're moving that ahead of the 'for', so to keep
13410
- // things straight, we need to set the for's start to be
13411
- // where result ended, and result's end to be where the for
13412
- // ends (since that block now encloses the for)
13413
- node.start = result.end;
13414
- node.loc.start = result.loc.end;
13415
- result.end = node.end;
13416
- result.loc.end = node.loc.end;
13417
- }
13418
- return result;
13334
+ else if (isExpression(decl)) {
13335
+ results.push(withLoc({ type: "ExpressionStatement", expression: decl }, decl, decl));
13336
+ }
13337
+ else if (decl.init) {
13338
+ results.push(withLoc({
13339
+ type: "ExpressionStatement",
13340
+ expression: withLoc({
13341
+ type: "AssignmentExpression",
13342
+ operator: "=",
13343
+ left: withLoc({
13344
+ type: "Identifier",
13345
+ name: (0,external_api_cjs_namespaceObject.variableDeclarationName)(decl.id),
13346
+ }, decl.id, decl.id),
13347
+ right: decl.init,
13348
+ }, decl, decl),
13349
+ }, decl, decl));
13419
13350
  }
13420
- if (node.init.type === "Literal") {
13421
- delete node.init;
13351
+ });
13352
+ node.declarations = node.declarations.filter((decl) => {
13353
+ if (decl.type === "VariableDeclarator") {
13354
+ delete decl.init;
13355
+ return true;
13422
13356
  }
13357
+ return false;
13358
+ });
13359
+ if (node.declarations.length) {
13360
+ withLocDeep(node, node, false);
13361
+ results.unshift(node);
13423
13362
  }
13424
- break;
13425
- case "SequenceExpression":
13426
- if (node.expressions.some((e) => e.type === "Literal")) {
13427
- node.expressions = node.expressions.filter((e) => e.type !== "Literal");
13363
+ // if this was the init of a ForStatement, this will
13364
+ // replace its init with a BlockStatement, so we have to
13365
+ // fix that below.
13366
+ return results;
13367
+ }
13368
+ break;
13369
+ case "ForStatement":
13370
+ if (node.init) {
13371
+ if (node.init.type === "BlockStatement") {
13372
+ const result = node.init;
13373
+ delete node.init;
13374
+ result.body.push(node);
13375
+ if (node.loc && result.loc) {
13376
+ // result has the range of the original VariableDeclaration
13377
+ // but now we're moving that ahead of the 'for', so to keep
13378
+ // things straight, we need to set the for's start to be
13379
+ // where result ended, and result's end to be where the for
13380
+ // ends (since that block now encloses the for)
13381
+ node.start = result.end;
13382
+ node.loc.start = result.loc.end;
13383
+ result.end = node.end;
13384
+ result.loc.end = node.loc.end;
13385
+ }
13386
+ return result;
13428
13387
  }
13429
- break;
13430
- }
13431
- external_node_assert_namespaceObject(!info);
13432
- return null;
13433
- });
13434
- return;
13388
+ if (node.init.type === "Literal") {
13389
+ delete node.init;
13390
+ }
13391
+ }
13392
+ break;
13393
+ case "SequenceExpression":
13394
+ if (node.expressions.some((e) => e.type === "Literal")) {
13395
+ node.expressions = node.expressions.filter((e) => e.type !== "Literal");
13396
+ }
13397
+ break;
13398
+ }
13399
+ return null;
13435
13400
  }
13436
13401
 
13437
13402
  ;// CONCATENATED MODULE: ./src/pre.ts
@@ -14184,6 +14149,199 @@ function applyReplacements(func, nodeMap, declMap) {
14184
14149
  });
14185
14150
  }
14186
14151
 
14152
+ ;// CONCATENATED MODULE: ./src/type-flow/minimize-modules.ts
14153
+
14154
+
14155
+
14156
+ function minimizeModules(ast, state) {
14157
+ const { pre, post } = state;
14158
+ try {
14159
+ const replacementMap = new Map();
14160
+ const conflictingNames = new Set();
14161
+ state.pre = (node) => {
14162
+ if (state.inType)
14163
+ return null;
14164
+ switch (node.type) {
14165
+ case "ModuleDeclaration":
14166
+ case "ClassDeclaration":
14167
+ case "FunctionDeclaration":
14168
+ return ["body"];
14169
+ case "Using":
14170
+ conflictingNames.add(node.as?.name ??
14171
+ (node.id.type === "Identifier"
14172
+ ? node.id.name
14173
+ : node.id.property.name));
14174
+ return [];
14175
+ case "ImportModule":
14176
+ conflictingNames.add(node.id.type === "Identifier" ? node.id.name : node.id.property.name);
14177
+ return [];
14178
+ case "Identifier":
14179
+ case "MemberExpression": {
14180
+ let current = node;
14181
+ const parts = [];
14182
+ while (current.type === "MemberExpression" && !current.computed) {
14183
+ parts.unshift(current);
14184
+ current = current.object;
14185
+ }
14186
+ if (current.type !== "Identifier" &&
14187
+ current.type !== "ThisExpression") {
14188
+ break;
14189
+ }
14190
+ let toReplace = null;
14191
+ let module = null;
14192
+ let addImport = false;
14193
+ let [, results] = state.lookupValue(current, null);
14194
+ let i = 0;
14195
+ for (; results &&
14196
+ results.length === 1 &&
14197
+ results[0].results.length === 1 &&
14198
+ (results[0].results[0].type === "Program" ||
14199
+ results[0].results[0].type === "ClassDeclaration" ||
14200
+ results[0].results[0].type === "ModuleDeclaration"); i++) {
14201
+ if (current.type === "Identifier" &&
14202
+ results[0].results[0].type === "ModuleDeclaration" &&
14203
+ isImportCandidate(results[0].results[0])) {
14204
+ const directResults = i
14205
+ ? state.lookupValue(current, null)
14206
+ : results;
14207
+ if (directResults &&
14208
+ directResults.length === 1 &&
14209
+ directResults[0].results.length === 1 &&
14210
+ directResults[0].results[0] === results[0].results[0]) {
14211
+ // we would find the same thing if we just looked up
14212
+ // current directly.
14213
+ toReplace = (i ? parts[i - 1] : current);
14214
+ module = results[0].results[0];
14215
+ if ((0,external_api_cjs_namespaceObject.findUsingForNode)(state, state.stack, state.stack.length - 1, current) === directResults[0].results[0]) {
14216
+ // we already find it via an import, so we don't need
14217
+ // a new import.
14218
+ addImport = false;
14219
+ }
14220
+ else {
14221
+ addImport = true;
14222
+ }
14223
+ }
14224
+ else {
14225
+ toReplace = parts[i - 1];
14226
+ module = results[0].results[0];
14227
+ addImport = true;
14228
+ }
14229
+ }
14230
+ if (i === parts.length)
14231
+ break;
14232
+ current = parts[i].property;
14233
+ results = (0,external_api_cjs_namespaceObject.lookupNext)(state, results, "decls", current);
14234
+ }
14235
+ if (toReplace) {
14236
+ external_node_assert_namespaceObject(module);
14237
+ replacementMap.set(toReplace, { module, addImport });
14238
+ }
14239
+ else if (parts.length === 0) {
14240
+ external_node_assert_namespaceObject(node.type === "Identifier");
14241
+ conflictingNames.add(node.name);
14242
+ }
14243
+ else if (parts[0].object.type === "Identifier") {
14244
+ conflictingNames.add(parts[0].object.name);
14245
+ }
14246
+ return [];
14247
+ }
14248
+ }
14249
+ return null;
14250
+ };
14251
+ (0,external_api_cjs_namespaceObject.collectNamespaces)(ast, state);
14252
+ const mappedNames = new Map();
14253
+ replacementMap.forEach((value, key) => {
14254
+ let name;
14255
+ if (value.addImport) {
14256
+ name = mappedNames.get(value.module);
14257
+ if (!name) {
14258
+ name = value.module.name;
14259
+ for (let i = 0; conflictingNames.has(name); i++) {
14260
+ name = `${value.module.name}_${i}`;
14261
+ }
14262
+ mappedNames.set(value.module, name);
14263
+ conflictingNames.add(name);
14264
+ }
14265
+ }
14266
+ else {
14267
+ name = key.type === "Identifier" ? key.name : key.property.name;
14268
+ }
14269
+ const original = (0,external_api_cjs_namespaceObject.formatAstLongLines)(key);
14270
+ const repl = key;
14271
+ repl.type = "Identifier";
14272
+ repl.name = name;
14273
+ if (name !== original) {
14274
+ repl.original = original;
14275
+ }
14276
+ delete repl.property;
14277
+ delete repl.object;
14278
+ delete repl.computed;
14279
+ });
14280
+ mappedNames.forEach((name, module) => {
14281
+ const id = makeScopedName(module.fullName.slice(2));
14282
+ const as = name !== (id.type === "Identifier" ? id : id.property).name &&
14283
+ makeIdentifier(name);
14284
+ const using = withLocDeep(as ? { type: "Using", id, as } : { type: "Using", id }, ast, false, true);
14285
+ ast.body.unshift(using);
14286
+ });
14287
+ }
14288
+ finally {
14289
+ state.pre = pre;
14290
+ state.post = post;
14291
+ }
14292
+ }
14293
+ /**
14294
+ * There's a bug in garmin's runtime (although the compiler could
14295
+ * work around it). See
14296
+ *
14297
+ * https://forums.garmin.com/developer/connect-iq/i/bug-reports/referencing-an-imported-module-doesn-t-run-its-parent-s-init
14298
+ *
14299
+ * What this means is that if a module's parent isn't `globals`
14300
+ * and it needs to be initialized, then we can't risk
14301
+ * importing it, because the parent module might not get initialized
14302
+ * in time.
14303
+ */
14304
+ function isImportCandidate(module) {
14305
+ if (module.fullName.startsWith("$.Toybox."))
14306
+ return true;
14307
+ if (module.fullName.startsWith("$.Rez."))
14308
+ return false;
14309
+ external_node_assert_namespaceObject(module.stack);
14310
+ if (module.stack.length === 1)
14311
+ return true;
14312
+ return module.stack.every((elem) => {
14313
+ if (!elem.sn.decls)
14314
+ return false;
14315
+ if (elem.sn.type === "Program")
14316
+ return true;
14317
+ if (elem.sn.type !== "ModuleDeclaration")
14318
+ return false;
14319
+ return Object.values(elem.sn.decls).every((decls) => decls.every((decl) => {
14320
+ if (decl.type !== "VariableDeclarator")
14321
+ return true;
14322
+ if (!decl.node.init)
14323
+ return true;
14324
+ if (decl.node.init.type === "UnaryExpression" &&
14325
+ decl.node.init.operator === ":") {
14326
+ return true;
14327
+ }
14328
+ if (decl.node.init.type !== "Literal")
14329
+ return false;
14330
+ switch (typeof decl.node.init.value) {
14331
+ case "boolean":
14332
+ return true;
14333
+ case "bigint":
14334
+ return false;
14335
+ case "number":
14336
+ return !/[dl]$/i.test(decl.node.init.raw);
14337
+ case "object":
14338
+ return decl.node.init.value === null;
14339
+ }
14340
+ return false;
14341
+ }));
14342
+ });
14343
+ }
14344
+
14187
14345
  ;// CONCATENATED MODULE: ./src/type-flow/optimize.ts
14188
14346
 
14189
14347
 
@@ -15034,6 +15192,7 @@ function cleanupUnusedVars(state, node) {
15034
15192
 
15035
15193
 
15036
15194
 
15195
+
15037
15196
  /*
15038
15197
  * Map each name to the list of StateNodes that declare that
15039
15198
  * name (excluding Functions, which are already in allFunctions)
@@ -15621,32 +15780,30 @@ async function optimizeMonkeyC(fnMap, resourcesMap, manifestXML, config) {
15621
15780
  break;
15622
15781
  case "Identifier": {
15623
15782
  const map = topLocals().map;
15624
- if (map) {
15625
- if ((0,external_api_cjs_namespaceObject.hasProperty)(map, node.name)) {
15626
- const name = map[node.name];
15627
- if (typeof name === "string") {
15628
- renameIdentifier(node, name);
15783
+ if ((0,external_api_cjs_namespaceObject.hasProperty)(map, node.name)) {
15784
+ const name = map[node.name];
15785
+ if (typeof name === "string") {
15786
+ renameIdentifier(node, name);
15787
+ }
15788
+ const [, results] = state.lookupValue(node);
15789
+ if (results) {
15790
+ if (results.length !== 1 || results[0].results.length !== 1) {
15791
+ throw new Error(`Local ${node.name} had multiple lookup results`);
15629
15792
  }
15630
- const [, results] = state.lookupValue(node);
15631
- if (results) {
15632
- if (results.length !== 1 || results[0].results.length !== 1) {
15633
- throw new Error(`Local ${node.name} had multiple lookup results`);
15634
- }
15635
- const parent = results[0].parent;
15636
- if (!parent) {
15637
- throw new Error(`Local ${node.name} had no parent`);
15638
- }
15639
- const decl = results[0].results[0];
15640
- if (parent.type === "FunctionDeclaration" ||
15641
- decl.type !== "VariableDeclarator") {
15642
- // we can't optimize away function or catch parameters
15643
- return [];
15644
- }
15645
- if (parent.type !== "BlockStatement") {
15646
- throw new Error(`Local ${node.name} was not declared at block scope(??)`);
15647
- }
15648
- decl.used = true;
15793
+ const parent = results[0].parent;
15794
+ if (!parent) {
15795
+ throw new Error(`Local ${node.name} had no parent`);
15796
+ }
15797
+ const decl = results[0].results[0];
15798
+ if (parent.type === "FunctionDeclaration" ||
15799
+ decl.type !== "VariableDeclarator") {
15800
+ // we can't optimize away function or catch parameters
15801
+ return [];
15649
15802
  }
15803
+ if (parent.type !== "BlockStatement") {
15804
+ throw new Error(`Local ${node.name} was not declared at block scope(??)`);
15805
+ }
15806
+ decl.used = true;
15650
15807
  }
15651
15808
  }
15652
15809
  return [];
@@ -15934,6 +16091,11 @@ async function optimizeMonkeyC(fnMap, resourcesMap, manifestXML, config) {
15934
16091
  state.nextExposed = {};
15935
16092
  delete state.pre;
15936
16093
  delete state.post;
16094
+ if (state.config?.minimizeModules ?? true) {
16095
+ Object.values(fnMap).forEach((f) => {
16096
+ minimizeModules(f.ast, state);
16097
+ });
16098
+ }
15937
16099
  Object.values(state.allFunctions).forEach((fns) => fns.forEach((fn) => sizeBasedPRE(state, fn)));
15938
16100
  const cleanup = (node) => {
15939
16101
  switch (node.type) {
@@ -16579,6 +16741,7 @@ const configOptionsToCheck = [
16579
16741
  "propagateTypes",
16580
16742
  "singleUseCopyProp",
16581
16743
  "minimizeLocals",
16744
+ "minimizeModules",
16582
16745
  "extensionVersion",
16583
16746
  "typeCheckLevel",
16584
16747
  "covarianceWarnings",
@@ -16640,7 +16803,7 @@ async function generateOneConfig(buildConfig, manifestXML, dependencyFiles, conf
16640
16803
  // the oldest optimized file, we don't need to regenerate
16641
16804
  const source_time = await (0,external_util_cjs_namespaceObject.last_modified)(Object.keys(fnMap).concat(dependencyFiles));
16642
16805
  const opt_time = await (0,external_util_cjs_namespaceObject.first_modified)(Object.values(fnMap).map((v) => v.output));
16643
- if (source_time < opt_time && 1676064117591 < opt_time) {
16806
+ if (source_time < opt_time && 1676335488374 < opt_time) {
16644
16807
  return { hasTests, diagnostics: prevDiagnostics };
16645
16808
  }
16646
16809
  }
@@ -16667,7 +16830,7 @@ async function generateOneConfig(buildConfig, manifestXML, dependencyFiles, conf
16667
16830
  return promises_namespaceObject.writeFile(external_path_.join(output, "build-info.json"), JSON.stringify({
16668
16831
  hasTests,
16669
16832
  diagnostics,
16670
- optimizerVersion: "1.1.11",
16833
+ optimizerVersion: "1.1.13",
16671
16834
  ...Object.fromEntries(configOptionsToCheck.map((option) => [option, config[option]])),
16672
16835
  }))
16673
16836
  .then(() => ({ hasTests, diagnostics }));