@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.
package/build/api.cjs CHANGED
@@ -1507,9 +1507,10 @@ function buildDataFlowGraph(state, func, wantsLiteral, trackInsertionPoints, wan
1507
1507
  decl,
1508
1508
  mayThrow,
1509
1509
  };
1510
- if (wantsAllRefs && node.operator === "=") {
1511
- if (node.right.type === "Identifier" ||
1512
- node.right.type === "MemberExpression") {
1510
+ if (wantsAllRefs) {
1511
+ if ((node.right.type === "Identifier" ||
1512
+ node.right.type === "MemberExpression") &&
1513
+ node.operator === "=") {
1513
1514
  const rhs = findDecl(node.right);
1514
1515
  if (rhs)
1515
1516
  def.rhs = rhs;
@@ -2757,13 +2758,15 @@ function fixNodeScope(state, lookupNode, nodeStack) {
2757
2758
  /* harmony import */ var _type_flow__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(4859);
2758
2759
  /* harmony import */ var _type_flow_could_be__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(4055);
2759
2760
  /* harmony import */ var _type_flow_interp__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(7161);
2760
- /* harmony import */ var _type_flow_optimize__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(3687);
2761
- /* harmony import */ var _type_flow_sub_type__WEBPACK_IMPORTED_MODULE_13__ = __webpack_require__(9234);
2762
- /* harmony import */ var _type_flow_types__WEBPACK_IMPORTED_MODULE_14__ = __webpack_require__(7255);
2763
- /* harmony import */ var _unused_exprs__WEBPACK_IMPORTED_MODULE_15__ = __webpack_require__(424);
2764
- /* harmony import */ var _util__WEBPACK_IMPORTED_MODULE_16__ = __webpack_require__(6906);
2765
- /* harmony import */ var _util__WEBPACK_IMPORTED_MODULE_16___default = /*#__PURE__*/__webpack_require__.n(_util__WEBPACK_IMPORTED_MODULE_16__);
2766
- /* harmony import */ var _variable_renamer__WEBPACK_IMPORTED_MODULE_17__ = __webpack_require__(4405);
2761
+ /* harmony import */ var _type_flow_minimize_modules__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(4416);
2762
+ /* harmony import */ var _type_flow_optimize__WEBPACK_IMPORTED_MODULE_13__ = __webpack_require__(3687);
2763
+ /* harmony import */ var _type_flow_sub_type__WEBPACK_IMPORTED_MODULE_14__ = __webpack_require__(9234);
2764
+ /* harmony import */ var _type_flow_types__WEBPACK_IMPORTED_MODULE_15__ = __webpack_require__(7255);
2765
+ /* harmony import */ var _unused_exprs__WEBPACK_IMPORTED_MODULE_16__ = __webpack_require__(424);
2766
+ /* harmony import */ var _util__WEBPACK_IMPORTED_MODULE_17__ = __webpack_require__(6906);
2767
+ /* harmony import */ var _util__WEBPACK_IMPORTED_MODULE_17___default = /*#__PURE__*/__webpack_require__.n(_util__WEBPACK_IMPORTED_MODULE_17__);
2768
+ /* harmony import */ var _variable_renamer__WEBPACK_IMPORTED_MODULE_18__ = __webpack_require__(4405);
2769
+
2767
2770
 
2768
2771
 
2769
2772
 
@@ -3369,32 +3372,30 @@ async function optimizeMonkeyC(fnMap, resourcesMap, manifestXML, config) {
3369
3372
  break;
3370
3373
  case "Identifier": {
3371
3374
  const map = topLocals().map;
3372
- if (map) {
3373
- if (hasProperty(map, node.name)) {
3374
- const name = map[node.name];
3375
- if (typeof name === "string") {
3376
- renameIdentifier(node, name);
3377
- }
3378
- const [, results] = state.lookupValue(node);
3379
- if (results) {
3380
- if (results.length !== 1 || results[0].results.length !== 1) {
3381
- throw new Error(`Local ${node.name} had multiple lookup results`);
3382
- }
3383
- const parent = results[0].parent;
3384
- if (!parent) {
3385
- throw new Error(`Local ${node.name} had no parent`);
3386
- }
3387
- const decl = results[0].results[0];
3388
- if (parent.type === "FunctionDeclaration" ||
3389
- decl.type !== "VariableDeclarator") {
3390
- // we can't optimize away function or catch parameters
3391
- return [];
3392
- }
3393
- if (parent.type !== "BlockStatement") {
3394
- throw new Error(`Local ${node.name} was not declared at block scope(??)`);
3395
- }
3396
- decl.used = true;
3375
+ if (hasProperty(map, node.name)) {
3376
+ const name = map[node.name];
3377
+ if (typeof name === "string") {
3378
+ renameIdentifier(node, name);
3379
+ }
3380
+ const [, results] = state.lookupValue(node);
3381
+ if (results) {
3382
+ if (results.length !== 1 || results[0].results.length !== 1) {
3383
+ throw new Error(`Local ${node.name} had multiple lookup results`);
3384
+ }
3385
+ const parent = results[0].parent;
3386
+ if (!parent) {
3387
+ throw new Error(`Local ${node.name} had no parent`);
3388
+ }
3389
+ const decl = results[0].results[0];
3390
+ if (parent.type === "FunctionDeclaration" ||
3391
+ decl.type !== "VariableDeclarator") {
3392
+ // we can't optimize away function or catch parameters
3393
+ return [];
3397
3394
  }
3395
+ if (parent.type !== "BlockStatement") {
3396
+ throw new Error(`Local ${node.name} was not declared at block scope(??)`);
3397
+ }
3398
+ decl.used = true;
3398
3399
  }
3399
3400
  }
3400
3401
  return [];
@@ -3682,6 +3683,11 @@ async function optimizeMonkeyC(fnMap, resourcesMap, manifestXML, config) {
3682
3683
  state.nextExposed = {};
3683
3684
  delete state.pre;
3684
3685
  delete state.post;
3686
+ if (state.config?.minimizeModules ?? true) {
3687
+ Object.values(fnMap).forEach((f) => {
3688
+ minimizeModules(f.ast, state);
3689
+ });
3690
+ }
3685
3691
  Object.values(state.allFunctions).forEach((fns) => fns.forEach((fn) => sizeBasedPRE(state, fn)));
3686
3692
  const cleanup = (node) => {
3687
3693
  switch (node.type) {
@@ -4025,7 +4031,7 @@ function pragmaChecker(state, ast, diagnostics) {
4025
4031
  if (kind === "match") {
4026
4032
  const haystack = formatAst(node)
4027
4033
  .replace(/([\r\n]|\s)+/g, " ")
4028
- .replace(/\b\w+\s\/\*>(\w+)<\*\//g, "$1");
4034
+ .replace(/\b\w+\s\/\*>([\w.]+)<\*\//g, "$1");
4029
4035
  if (!matcher(quote, needle, haystack)) {
4030
4036
  matcher(quote, needle, haystack);
4031
4037
  diagnostic(state, comment, `Didn't find '${needle}' in '${haystack}'`, "ERROR");
@@ -4950,79 +4956,42 @@ function buildConflictGraph(state, func) {
4950
4956
  function addEquiv(ts, key, equiv) {
4951
4957
  if (key === equiv)
4952
4958
  return true;
4953
- let keyVal = ts.get(key);
4954
- let equivVal = ts.get(equiv);
4959
+ const keyVal = ts.get(key);
4960
+ const equivVal = ts.get(equiv);
4955
4961
  if (!keyVal || !equivVal)
4956
4962
  return false;
4957
4963
  if (equivVal.equivSet) {
4958
- if (keyVal.equivSet) {
4959
- // key is already a member of a set, see if
4960
- // equiv is part of it.
4961
- let s = keyVal.equivSet.next;
4962
- do {
4963
- if (s === equiv) {
4964
- // these two are already equivalent
4965
- return true;
4966
- }
4967
- const next = ts.get(s);
4968
- if (!next || !next.equivSet) {
4969
- throw new Error(`Inconsistent equivSet for ${tsKey(key)}: missing value for ${tsKey(s)}`);
4970
- }
4971
- s = next.equivSet.next;
4972
- } while (s !== key);
4964
+ if (equivVal.equivSet.has(key)) {
4965
+ return true;
4973
4966
  }
4974
4967
  // equiv is already a member of a set. remove it
4975
4968
  removeEquiv(ts, equiv);
4976
4969
  }
4977
4970
  // equiv is not (or no longer) part of an equivSet
4978
- keyVal = { ...keyVal };
4979
4971
  if (!keyVal.equivSet) {
4980
- keyVal.equivSet = { next: key };
4972
+ keyVal.equivSet = new Set([key, equiv]);
4973
+ }
4974
+ else {
4975
+ keyVal.equivSet.add(equiv);
4981
4976
  }
4982
- equivVal = { ...equivVal, equivSet: keyVal.equivSet };
4983
- keyVal.equivSet = { next: equiv };
4984
- ts.set(key, keyVal);
4985
- ts.set(equiv, equivVal);
4977
+ equivVal.equivSet = keyVal.equivSet;
4986
4978
  return false;
4987
4979
  }
4988
4980
  function removeEquiv(ts, equiv) {
4989
4981
  const equivVal = ts.get(equiv);
4990
4982
  if (!equivVal?.equivSet)
4991
4983
  return;
4992
- let s = equivVal.equivSet.next;
4993
- do {
4994
- const next = ts.get(s);
4995
- if (!next || !next.equivSet) {
4996
- throw new Error(`Inconsistent equivSet for ${tsKey(equiv)}: missing value for ${tsKey(s)}`);
4997
- }
4998
- if (next.equivSet.next === equiv) {
4999
- const { equivSet: _e, ...rest } = next;
5000
- if (equivVal.equivSet.next === s) {
5001
- // this is a pair. just kill both
5002
- ts.set(s, rest);
5003
- }
5004
- else {
5005
- ts.set(s, { ...rest, equivSet: equivVal.equivSet });
5006
- }
5007
- break;
5008
- }
5009
- s = next.equivSet.next;
5010
- } while (true);
5011
- const newVal = { ...equivVal };
5012
- delete newVal.equivSet;
5013
- ts.set(equiv, newVal);
4984
+ equivVal.equivSet.delete(equiv);
4985
+ if (equivVal.equivSet.size === 1) {
4986
+ const other = Array.from(equivVal.equivSet)[0];
4987
+ const otherVal = ts.get(other);
4988
+ delete otherVal.equivSet;
4989
+ }
4990
+ delete equivVal.equivSet;
5014
4991
  }
5015
4992
  function getEquivSet(ts, k) {
5016
- const keys = new Set();
5017
- let s = k;
5018
- do {
5019
- const next = ts.get(s);
5020
- if (!next || !next.equivSet) {
5021
- throw new Error(`Inconsistent equivSet for ${tsKey(k)}: missing value for ${tsKey(s)}`);
5022
- }
5023
- keys.add(s);
5024
- s = next.equivSet.next;
5025
- } while (s !== k);
4993
+ const keys = ts.get(k)?.equivSet;
4994
+ assert(keys);
5026
4995
  return keys;
5027
4996
  }
5028
4997
  function intersectEquiv(ts1, ts2, k) {
@@ -5034,21 +5003,26 @@ function intersectEquiv(ts1, ts2, k) {
5034
5003
  removeEquiv(ts1, k);
5035
5004
  return true;
5036
5005
  }
5037
- const keys = getEquivSet(ts2, k);
5038
- let ret = false;
5039
- let s = eq1.equivSet.next;
5040
- do {
5041
- const next = ts1.get(s);
5042
- if (!next || !next.equivSet) {
5043
- throw new Error(`Inconsistent equivSet for ${tsKey(k)}: missing value for ${tsKey(s)}`);
5044
- }
5045
- if (!keys.has(s)) {
5046
- ret = true;
5047
- removeEquiv(ts1, s);
5006
+ let removed = null;
5007
+ eq1.equivSet.forEach((key) => {
5008
+ if (!eq2.equivSet.has(key)) {
5009
+ eq1.equivSet.delete(key);
5010
+ if (!removed) {
5011
+ removed = new Set();
5012
+ }
5013
+ removed.add(key);
5048
5014
  }
5049
- s = next.equivSet.next;
5050
- } while (s !== k);
5051
- return ret;
5015
+ });
5016
+ if (eq1.equivSet.size === 1) {
5017
+ assert(eq1.equivSet.has(k));
5018
+ delete eq1.equivSet;
5019
+ }
5020
+ if (removed) {
5021
+ removed.forEach((k) => removed.size === 1
5022
+ ? delete ts1.get(k).equivSet
5023
+ : (ts1.get(k).equivSet = removed));
5024
+ }
5025
+ return false;
5052
5026
  }
5053
5027
  function clearAssocPaths(blockState, decl, v) {
5054
5028
  if (v.assocPaths?.size) {
@@ -5066,6 +5040,17 @@ function clearAssocPaths(blockState, decl, v) {
5066
5040
  function cloneTypeState(blockState) {
5067
5041
  const { map, trackedMemberDecls, liveCopyPropEvents, ...rest } = blockState;
5068
5042
  const clone = { map: new Map(map), ...rest };
5043
+ clone.map.forEach((value, key) => {
5044
+ if (value.equivSet) {
5045
+ if (key === Array.from(value.equivSet)[0]) {
5046
+ const equivSet = new Set(value.equivSet);
5047
+ equivSet.forEach((k) => clone.map.set(k, { ...clone.map.get(k), equivSet }));
5048
+ }
5049
+ }
5050
+ else {
5051
+ clone.map.set(key, { ...value });
5052
+ }
5053
+ });
5069
5054
  if (trackedMemberDecls) {
5070
5055
  clone.trackedMemberDecls = new Map();
5071
5056
  trackedMemberDecls.forEach((value, key) => {
@@ -5100,12 +5085,9 @@ function addCopyPropEvent(blockState, item) {
5100
5085
  const liveCopyPropEvents = blockState.liveCopyPropEvents;
5101
5086
  const decl = item.event.decl;
5102
5087
  assert(declIsLocal(decl));
5103
- let tov = blockState.map.get(decl);
5088
+ const tov = blockState.map.get(decl);
5104
5089
  assert(tov);
5105
- if (tov.copyPropItem !== item) {
5106
- tov = { ...tov, copyPropItem: item };
5107
- blockState.map.set(decl, tov);
5108
- }
5090
+ tov.copyPropItem = item;
5109
5091
  item.contained.forEach((value, key) => {
5110
5092
  const decls = liveCopyPropEvents.get(key);
5111
5093
  if (!decls) {
@@ -5138,15 +5120,13 @@ function clearRelatedCopyPropEvents(blockState, decl, nodeCopyProp) {
5138
5120
  blockState.liveCopyPropEvents
5139
5121
  ?.get(decl)
5140
5122
  ?.forEach((cpDecl) => {
5141
- let value = blockState.map.get(cpDecl);
5123
+ const value = blockState.map.get(cpDecl);
5142
5124
  assert(value && value.copyPropItem);
5143
5125
  assert(Array.from(value.copyPropItem.contained).some(([key]) => {
5144
5126
  return decl === key;
5145
5127
  }));
5146
5128
  copyPropFailed(blockState, value.copyPropItem, nodeCopyProp);
5147
- value = { ...value };
5148
5129
  delete value.copyPropItem;
5149
- blockState.map.set(cpDecl, value);
5150
5130
  });
5151
5131
  }
5152
5132
  function validateTypeState(curState) {
@@ -5189,11 +5169,9 @@ function mergeTypeState(blockStates, index, from, nodeCopyProp) {
5189
5169
  if (tov.equivSet) {
5190
5170
  if (intersectEquiv(to.map, from.map, k)) {
5191
5171
  changes = true;
5192
- tov = to.map.get(k);
5193
5172
  }
5194
5173
  }
5195
5174
  if (tov.assocPaths) {
5196
- tov = { ...tov };
5197
5175
  if (!fromv.assocPaths) {
5198
5176
  changes = true;
5199
5177
  delete tov.assocPaths;
@@ -5216,7 +5194,6 @@ function mergeTypeState(blockStates, index, from, nodeCopyProp) {
5216
5194
  delete tov.assocPaths;
5217
5195
  }
5218
5196
  }
5219
- to.map.set(k, tov);
5220
5197
  }
5221
5198
  // if both from and to have copyPropEvents, we can only
5222
5199
  // keep it if they're the same event.
@@ -5234,10 +5211,8 @@ function mergeTypeState(blockStates, index, from, nodeCopyProp) {
5234
5211
  }
5235
5212
  nodeCopyProp.set(fromv.copyPropItem.event.node, false);
5236
5213
  }
5237
- tov = { ...tov };
5238
5214
  delete tov.copyPropItem;
5239
5215
  changes = true;
5240
- to.map.set(k, tov);
5241
5216
  }
5242
5217
  else {
5243
5218
  assert(k === tov.copyPropItem.event.decl);
@@ -5248,7 +5223,7 @@ function mergeTypeState(blockStates, index, from, nodeCopyProp) {
5248
5223
  if (subtypeOf(fromv.curType, tov.curType))
5249
5224
  return;
5250
5225
  if (subtypeOf(tov.curType, fromv.curType)) {
5251
- to.map.set(k, { ...tov, curType: fromv.curType });
5226
+ tov.curType = fromv.curType;
5252
5227
  changes = true;
5253
5228
  return;
5254
5229
  }
@@ -5261,22 +5236,11 @@ function mergeTypeState(blockStates, index, from, nodeCopyProp) {
5261
5236
  if (wide)
5262
5237
  result = wide;
5263
5238
  }
5264
- to.map.set(k, { ...tov, curType: result });
5239
+ tov.curType = result;
5265
5240
  changes = true;
5266
5241
  });
5267
5242
  return changes;
5268
5243
  }
5269
- function tsEquivs(state, key) {
5270
- const result = [];
5271
- let s = key;
5272
- do {
5273
- result.push(tsKey(s));
5274
- const next = state.get(s);
5275
- assert(next && next.equivSet);
5276
- s = next.equivSet.next;
5277
- } while (s !== key);
5278
- return `[(${result.join(", ")})]`;
5279
- }
5280
5244
  function typeStateEntry(value, key) {
5281
5245
  return `${tsKey(key)} = ${display(value.curType)}`;
5282
5246
  }
@@ -5287,7 +5251,9 @@ function printBlockState(block, state, indent = "") {
5287
5251
  return;
5288
5252
  }
5289
5253
  state.map.forEach((value, key) => {
5290
- console.log(`${indent} - ${typeStateEntry(value, key)}${value.equivSet ? " " + tsEquivs(state.map, key) : ""}`);
5254
+ console.log(`${indent} - ${typeStateEntry(value, key)}${value.equivSet
5255
+ ? " " + `[(${Array.from(value.equivSet).map(tsKey).join(", ")})]`
5256
+ : ""}`);
5291
5257
  });
5292
5258
  }
5293
5259
  function updateAffected(blockState, objectType, baseDecl, assignedPath, affectedName, affected, assignedType) {
@@ -5295,7 +5261,6 @@ function updateAffected(blockState, objectType, baseDecl, assignedPath, affected
5295
5261
  let droppedComponents = null;
5296
5262
  const entry = blockState.map.get(key);
5297
5263
  assert(entry && entry.assocPaths);
5298
- let newEntry = entry;
5299
5264
  entry.assocPaths.forEach((path) => {
5300
5265
  if (key === baseDecl && path === assignedPath) {
5301
5266
  return;
@@ -5314,12 +5279,9 @@ function updateAffected(blockState, objectType, baseDecl, assignedPath, affected
5314
5279
  });
5315
5280
  if (pathItem === affectedName && couldBeShallow(type, objectType)) {
5316
5281
  const newAssocKey = assocPath.map((av) => av.name ?? "*").join(".");
5317
- if (newEntry === entry) {
5318
- newEntry = { ...entry };
5319
- }
5320
5282
  if (newAssocKey !== path) {
5321
- newEntry.assocPaths = new Set(newEntry.assocPaths);
5322
- newEntry.assocPaths.delete(path);
5283
+ entry.assocPaths = new Set(entry.assocPaths);
5284
+ entry.assocPaths.delete(path);
5323
5285
  // the "extra" path components will also have entries
5324
5286
  // in blockState.trackedMemberDecls. Since they're gone
5325
5287
  // from here, we (may) need to remove them from there
@@ -5331,8 +5293,7 @@ function updateAffected(blockState, objectType, baseDecl, assignedPath, affected
5331
5293
  }
5332
5294
  break;
5333
5295
  }
5334
- const baseType = updateByAssocPath(assocPath, assignedType, true);
5335
- newEntry.curType = baseType;
5296
+ entry.curType = updateByAssocPath(assocPath, assignedType, true);
5336
5297
  break;
5337
5298
  }
5338
5299
  if (pathItem === "*") {
@@ -5362,14 +5323,11 @@ function updateAffected(blockState, objectType, baseDecl, assignedPath, affected
5362
5323
  }
5363
5324
  }
5364
5325
  });
5365
- if (newEntry !== entry) {
5366
- if (droppedComponents) {
5367
- newEntry.assocPaths.forEach((path) => path
5368
- .split(".")
5369
- .forEach((pathComponent) => droppedComponents.delete(pathComponent)));
5370
- droppedComponents.forEach((pathComponent) => blockState.trackedMemberDecls.get(pathComponent).delete(key));
5371
- }
5372
- blockState.map.set(key, newEntry);
5326
+ if (droppedComponents) {
5327
+ entry.assocPaths.forEach((path) => path
5328
+ .split(".")
5329
+ .forEach((pathComponent) => droppedComponents.delete(pathComponent)));
5330
+ droppedComponents.forEach((pathComponent) => blockState.trackedMemberDecls.get(pathComponent).delete(key));
5373
5331
  }
5374
5332
  });
5375
5333
  }
@@ -5476,10 +5434,9 @@ function propagateTypes(state, func, graph, optimizeEquivalencies, copyPropStore
5476
5434
  const assocKey = assocValue.map((av) => av.name ?? "*").join(".");
5477
5435
  const newType = updateByAssocPath(assocValue, next, false);
5478
5436
  setStateEvent(blockState, decl.base, newType, newValue ? 1 /* UpdateKind.Inner */ : 0 /* UpdateKind.None */);
5479
- const tsv = { ...blockState.map.get(decl.base) };
5437
+ const tsv = blockState.map.get(decl.base);
5480
5438
  tsv.assocPaths = new Set(tsv.assocPaths);
5481
5439
  tsv.assocPaths.add(assocKey);
5482
- blockState.map.set(decl.base, tsv);
5483
5440
  addTrackedMemberDecl(blockState, decl.base, assocKey);
5484
5441
  if (newValue) {
5485
5442
  const baseElem = assocValue[decl.path.length - 1];
@@ -5557,38 +5514,39 @@ function propagateTypes(state, func, graph, optimizeEquivalencies, copyPropStore
5557
5514
  // that foo is side-effect free, and accesses no globals.
5558
5515
  clearRelatedCopyPropEvents(blockState, decl, nodeCopyProp);
5559
5516
  }
5517
+ const v = blockState.map.get(decl);
5518
+ if (!v) {
5519
+ blockState.map.set(decl, { curType: value });
5520
+ return;
5521
+ }
5560
5522
  if (updateKind !== 2 /* UpdateKind.Reassign */) {
5561
5523
  /*
5562
5524
  * If we're not re-assigning, the equivalencies don't
5563
5525
  * change, so this update must be applied to every
5564
5526
  * element of the set
5565
5527
  */
5566
- const v = blockState.map.get(decl);
5567
- if (v?.equivSet) {
5568
- let s = decl;
5569
- do {
5528
+ if (v.equivSet) {
5529
+ v.equivSet.forEach((s) => {
5570
5530
  const next = blockState.map.get(s);
5571
- if (!next || !next.equivSet) {
5572
- throw new Error(`Inconsistent equivSet for ${tsKey(decl)}: missing value for ${tsKey(s)}`);
5573
- }
5574
- blockState.map.set(s, { ...next, curType: value });
5575
- s = next.equivSet.next;
5576
- } while (s !== decl);
5531
+ assert(next && next.equivSet?.has(s));
5532
+ next.curType = value;
5533
+ });
5577
5534
  }
5578
5535
  else {
5579
- blockState.map.set(decl, { ...v, curType: value });
5536
+ v.curType = value;
5580
5537
  }
5581
5538
  }
5582
5539
  else {
5583
- const v = blockState.map.get(decl);
5584
5540
  removeEquiv(blockState.map, decl);
5585
- if (v?.assocPaths?.size) {
5541
+ if (v.assocPaths?.size) {
5586
5542
  clearAssocPaths(blockState, decl, v);
5543
+ delete v.assocPaths;
5587
5544
  }
5588
- if (v?.copyPropItem) {
5545
+ if (v.copyPropItem) {
5589
5546
  copyPropFailed(blockState, v.copyPropItem, nodeCopyProp);
5547
+ delete v.copyPropItem;
5590
5548
  }
5591
- blockState.map.set(decl, { curType: value });
5549
+ v.curType = value;
5592
5550
  }
5593
5551
  return;
5594
5552
  }
@@ -5922,7 +5880,7 @@ function propagateTypes(state, func, graph, optimizeEquivalencies, copyPropStore
5922
5880
  break;
5923
5881
  }
5924
5882
  case "ref": {
5925
- let curEntry = getStateEntry(curState, event.decl);
5883
+ const curEntry = getStateEntry(curState, event.decl);
5926
5884
  typeMap.set(event.node, curEntry.curType);
5927
5885
  nodeEquivs.delete(event.node);
5928
5886
  if (curEntry.equivSet) {
@@ -5946,9 +5904,7 @@ function propagateTypes(state, func, graph, optimizeEquivalencies, copyPropStore
5946
5904
  nodeCopyProp.set(curEntry.copyPropItem.event.node, event.node);
5947
5905
  }
5948
5906
  clearCopyProp(curState, curEntry.copyPropItem);
5949
- curEntry = { ...curEntry };
5950
5907
  delete curEntry.copyPropItem;
5951
- curState.map.set(event.decl, curEntry);
5952
5908
  }
5953
5909
  else if (declIsNonLocal(event.decl)) {
5954
5910
  clearRelatedCopyPropEvents(curState, null, nodeCopyProp);
@@ -5986,12 +5942,13 @@ function propagateTypes(state, func, graph, optimizeEquivalencies, copyPropStore
5986
5942
  }
5987
5943
  });
5988
5944
  }
5945
+ let calleeEffects;
5989
5946
  curState.map.forEach((tsv, decl) => {
5990
5947
  let type = tsv.curType;
5991
- if (!some(decl, (d) => d.type === "VariableDeclarator" &&
5992
- (d.node.kind === "var" ||
5993
- // even a "const" could have its "inner" type altered
5994
- (type.value != null && (type.type & 32768 /* TypeTag.Object */) !== 0)))) {
5948
+ if ((type.value == null ||
5949
+ !(type.type &
5950
+ (32768 /* TypeTag.Object */ | 512 /* TypeTag.Array */ | 1024 /* TypeTag.Dictionary */))) &&
5951
+ !some(decl, (d) => d.type === "VariableDeclarator" && !isLocal(d))) {
5995
5952
  return;
5996
5953
  }
5997
5954
  if (modifiableDecl(decl, callees)) {
@@ -6007,9 +5964,14 @@ function propagateTypes(state, func, graph, optimizeEquivalencies, copyPropStore
6007
5964
  clearRelatedCopyPropEvents(curState, decl, nodeCopyProp);
6008
5965
  curState.map.set(decl, { curType: typeConstraint(decl) });
6009
5966
  }
6010
- else if (type.value != null &&
6011
- (!callees || !every(callees, (callee) => callee.info === false))) {
6012
- if (type.type & 32768 /* TypeTag.Object */) {
5967
+ else if (type.type &
5968
+ (32768 /* TypeTag.Object */ | 512 /* TypeTag.Array */ | 1024 /* TypeTag.Dictionary */) &&
5969
+ (calleeEffects == null
5970
+ ? (calleeEffects =
5971
+ !callees ||
5972
+ !every(callees, (callee) => callee.info === false))
5973
+ : calleeEffects)) {
5974
+ if (type.value != null && type.type & 32768 /* TypeTag.Object */) {
6013
5975
  const odata = getObjectValue(tsv.curType);
6014
5976
  if (odata?.obj) {
6015
5977
  type = cloneType(type);
@@ -6017,18 +5979,12 @@ function propagateTypes(state, func, graph, optimizeEquivalencies, copyPropStore
6017
5979
  setUnionComponent(type, 32768 /* TypeTag.Object */, newData);
6018
5980
  if (tsv.assocPaths) {
6019
5981
  clearAssocPaths(curState, decl, tsv);
6020
- tsv = { ...tsv };
6021
5982
  delete tsv.assocPaths;
6022
5983
  }
6023
- if (tsv.copyPropItem) {
6024
- copyPropFailed(curState, tsv.copyPropItem, nodeCopyProp);
6025
- tsv = { ...tsv };
6026
- delete tsv.copyPropItem;
6027
- }
6028
- clearRelatedCopyPropEvents(curState, decl, nodeCopyProp);
6029
- curState.map.set(decl, { ...tsv, curType: type });
5984
+ tsv.curType = type;
6030
5985
  }
6031
5986
  }
5987
+ clearRelatedCopyPropEvents(curState, decl, nodeCopyProp);
6032
5988
  }
6033
5989
  });
6034
5990
  return true;
@@ -6050,10 +6006,7 @@ function propagateTypes(state, func, graph, optimizeEquivalencies, copyPropStore
6050
6006
  (event.node.type !== "AssignmentExpression" ||
6051
6007
  event.node.operator !== "=")) {
6052
6008
  copyPropFailed(curState, before.copyPropItem, nodeCopyProp);
6053
- const v = { ...before };
6054
- delete v.copyPropItem;
6055
- assert(isTypeStateKey(event.decl));
6056
- curState.map.set(event.decl, v);
6009
+ delete before.copyPropItem;
6057
6010
  }
6058
6011
  }
6059
6012
  const expr = event.node.type === "VariableDeclarator"
@@ -6147,22 +6100,41 @@ function propagateTypes(state, func, graph, optimizeEquivalencies, copyPropStore
6147
6100
  decl.type === "BinaryExpression" ||
6148
6101
  decl.type === "Identifier"))) {
6149
6102
  const key = event.decl ?? null;
6150
- if (key &&
6151
- declIsLocal(key) &&
6152
- nodeCopyProp.has(event.node)) {
6153
- // we might have
6154
- //
6155
- // var x = foo();
6156
- // var y = x + 1;
6157
- // bar();
6158
- // return y;
6159
- //
6160
- // In that case, its ok to drop "x = foo()" and rewrite as y = foo() + 1"
6161
- // OR its ok to drop "y = x + 1" and rewrite as "return x + 1".
6162
- // But we can't do both, and rewrite as "bar(); return foo() + 1;"
6163
- // So just disable copy prop for *this* node. We'll re-run and have a
6164
- // second chance later.
6165
- return false;
6103
+ if (key && declIsLocal(key)) {
6104
+ if (nodeCopyProp.has(event.node)) {
6105
+ // we might have
6106
+ //
6107
+ // var x = foo();
6108
+ // var y = x + 1;
6109
+ // bar();
6110
+ // return y;
6111
+ //
6112
+ // In that case, its ok to drop "x = foo()" and rewrite as y = foo() + 1"
6113
+ // OR its ok to drop "y = x + 1" and rewrite as "return x + 1".
6114
+ // But we can't do both, and rewrite as "bar(); return foo() + 1;"
6115
+ // So just disable copy prop for *this* node. We'll re-run and have a
6116
+ // second chance later.
6117
+ return false;
6118
+ }
6119
+ else if (event.node.type === "AssignmentExpression" &&
6120
+ event.node.operator !== "=" &&
6121
+ nodeCopyProp.has(event.node.left)) {
6122
+ // If we're copy proping into the lhs of an update
6123
+ // assignment, we're going to have to rewrite it.
6124
+ // similar to the above, don't also do forward copy
6125
+ // prop. eg
6126
+ //
6127
+ // var x = a + b;
6128
+ // x += c;
6129
+ // return x;
6130
+ //
6131
+ // becomes
6132
+ //
6133
+ // var x;
6134
+ // x = (a + b) + c;
6135
+ // return x; // <- dont propagate to here (yet), in case a+b has changed.
6136
+ return false;
6137
+ }
6166
6138
  }
6167
6139
  const item = contained.get(key);
6168
6140
  if (!item) {
@@ -6351,7 +6323,22 @@ function propagateTypes(state, func, graph, optimizeEquivalencies, copyPropStore
6351
6323
  }
6352
6324
  }
6353
6325
  }));
6354
- traverseAst(func.node.body, null, (node) => {
6326
+ traverseAst(func.node.body, (node) => {
6327
+ if (node.type === "AssignmentExpression" &&
6328
+ node.operator !== "=" &&
6329
+ nodeCopyProp.has(node.left)) {
6330
+ const left = cloneDeep(node.left);
6331
+ const right = withLoc({
6332
+ type: "BinaryExpression",
6333
+ operator: node.operator.slice(0, -1),
6334
+ left: withLocDeep(node.left, node.right, false, true),
6335
+ right: node.right,
6336
+ }, node.left, node.right);
6337
+ node.operator = "=";
6338
+ node.left = left;
6339
+ node.right = right;
6340
+ }
6341
+ }, (node) => {
6355
6342
  const copyNode = nodeCopyProp.get(node);
6356
6343
  if (copyNode) {
6357
6344
  if (node.type === "AssignmentExpression") {
@@ -6370,10 +6357,18 @@ function propagateTypes(state, func, graph, optimizeEquivalencies, copyPropStore
6370
6357
  return dup;
6371
6358
  }
6372
6359
  if (copyNode.type === "AssignmentExpression") {
6360
+ const replacement = copyNode.operator === "="
6361
+ ? copyNode.right
6362
+ : {
6363
+ type: "BinaryExpression",
6364
+ operator: copyNode.operator.slice(0, -1),
6365
+ left: copyNode.left,
6366
+ right: copyNode.right,
6367
+ };
6373
6368
  if (logThisRun) {
6374
- console.log(`copy-prop ${formatAstLongLines(node)} => ${formatAstLongLines(copyNode.right)}`);
6369
+ console.log(`copy-prop ${formatAstLongLines(node)} => ${formatAstLongLines(replacement)}`);
6375
6370
  }
6376
- return withLocDeep(copyNode.right, node, node, false);
6371
+ return withLocDeep(replacement, node, node, false);
6377
6372
  }
6378
6373
  else if (copyNode.type === "VariableDeclarator") {
6379
6374
  assert(copyNode.init);
@@ -6706,7 +6701,9 @@ function couldBeObj(a, b) {
6706
6701
  /* harmony import */ var _control_flow__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(5101);
6707
6702
  /* harmony import */ var _data_flow__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(8180);
6708
6703
  /* harmony import */ var _inliner__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(333);
6709
- /* harmony import */ var _type_flow_util__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(1638);
6704
+ /* harmony import */ var _minimize_locals__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(736);
6705
+ /* harmony import */ var _type_flow_util__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(1638);
6706
+
6710
6707
 
6711
6708
 
6712
6709
 
@@ -6715,18 +6712,18 @@ function couldBeObj(a, b) {
6715
6712
 
6716
6713
 
6717
6714
  function cloneAnt(antMap) {
6718
- const ant = new Map();
6719
- antMap.forEach((s, k) => ant.set(k, new Set(s)));
6720
- return ant;
6715
+ return new Map(antMap);
6721
6716
  }
6722
6717
  function addAnt(antMap, decl, node) {
6723
6718
  assert(node.type === "Identifier");
6724
6719
  const ant = antMap.get(decl);
6725
- if (!ant) {
6726
- antMap.set(decl, new Set([node]));
6720
+ if (ant === false || ant === node)
6721
+ return;
6722
+ if (ant === undefined) {
6723
+ antMap.set(decl, node);
6727
6724
  }
6728
6725
  else {
6729
- ant.add(node);
6726
+ antMap.set(decl, false);
6730
6727
  }
6731
6728
  }
6732
6729
  function cloneState(blockState) {
@@ -6762,18 +6759,10 @@ function findDeadStores(func, graph, nodeEquivs, findCopyPropCandidates, logThis
6762
6759
  else {
6763
6760
  changed = Array.from(to.anticipated).reduce((changed, [decl, toant]) => {
6764
6761
  const fromant = from.anticipated.get(decl);
6765
- if (!fromant) {
6762
+ if (toant !== fromant) {
6766
6763
  to.anticipated.delete(decl);
6767
6764
  changed = true;
6768
6765
  }
6769
- else {
6770
- toant.forEach((node) => {
6771
- if (!fromant.has(node)) {
6772
- toant.delete(node);
6773
- changed = true;
6774
- }
6775
- });
6776
- }
6777
6766
  return changed;
6778
6767
  }, changed);
6779
6768
  }
@@ -6786,17 +6775,15 @@ function findDeadStores(func, graph, nodeEquivs, findCopyPropCandidates, logThis
6786
6775
  else {
6787
6776
  changed = Array.from(from.partiallyAnticipated).reduce((changed, [decl, fromant]) => {
6788
6777
  const toant = to.partiallyAnticipated.get(decl);
6789
- if (!toant) {
6778
+ if (toant === undefined) {
6790
6779
  to.partiallyAnticipated.set(decl, fromant);
6791
6780
  changed = true;
6792
6781
  }
6793
6782
  else {
6794
- fromant.forEach((node) => {
6795
- if (!toant.has(node)) {
6796
- changed = true;
6797
- toant.add(node);
6798
- }
6799
- });
6783
+ if (toant !== fromant) {
6784
+ changed = true;
6785
+ to.partiallyAnticipated.set(decl, false);
6786
+ }
6800
6787
  }
6801
6788
  return changed;
6802
6789
  }, changed);
@@ -6860,7 +6847,7 @@ function findDeadStores(func, graph, nodeEquivs, findCopyPropCandidates, logThis
6860
6847
  }
6861
6848
  addAnt(curState.partiallyAnticipated, event.decl, event.node);
6862
6849
  if (logThisRun) {
6863
- console.log(` antrefs: ${curState.partiallyAnticipated.get(event.decl)?.size ?? 0} ${curState.anticipated.get(event.decl)?.size ?? 0}`);
6850
+ console.log(` antrefs: ${curState.partiallyAnticipated.get(event.decl) !== false} ${curState.anticipated.get(event.decl) !== false}`);
6864
6851
  }
6865
6852
  }
6866
6853
  curState.dead.delete(event.decl);
@@ -6881,25 +6868,21 @@ function findDeadStores(func, graph, nodeEquivs, findCopyPropCandidates, logThis
6881
6868
  }
6882
6869
  else {
6883
6870
  deadStores.delete(event.node);
6884
- if (assignNode &&
6885
- declIsLocal(event.decl) &&
6886
- curState.partiallyAnticipated) {
6871
+ copyPropStores.delete(event.node);
6872
+ if (declIsLocal(event.decl) && curState.partiallyAnticipated) {
6887
6873
  const pant = curState.partiallyAnticipated.get(event.decl);
6888
- if (pant && pant.size === 1) {
6874
+ if (pant) {
6889
6875
  if (logThisRun) {
6890
- console.log(` is copy-prop-candidate ${curState.anticipated?.get(event.decl)?.size ?? 0}`);
6876
+ console.log(` is copy-prop-candidate ${curState.anticipated?.get(event.decl) === pant}`);
6891
6877
  }
6892
6878
  copyPropStores.set(event.node, {
6893
- ref: Array.from(pant)[0],
6894
- ant: curState.anticipated?.get(event.decl)?.size === 1,
6879
+ ref: pant,
6880
+ ant: curState.anticipated?.get(event.decl) === pant,
6895
6881
  });
6896
6882
  }
6897
6883
  curState.partiallyAnticipated.delete(event.decl);
6898
6884
  curState.anticipated?.delete(event.decl);
6899
6885
  }
6900
- else {
6901
- copyPropStores.delete(event.node);
6902
- }
6903
6886
  }
6904
6887
  if (nodeConflicts) {
6905
6888
  const conflicts = new Set(locals);
@@ -6988,7 +6971,10 @@ function eliminateDeadStores(state, func, graph, logThisRun) {
6988
6971
  console.log(`${formatAst(dead)} (${sourceLocation(dead.loc)})`));
6989
6972
  }
6990
6973
  let changes = false;
6991
- traverseAst(func.node.body, null, (node, parent) => {
6974
+ traverseAst(func.node.body, null, (node) => {
6975
+ const cleaned = variableCleanup(node);
6976
+ if (cleaned !== null)
6977
+ return cleaned;
6992
6978
  if (node.type === "ExpressionStatement" &&
6993
6979
  node.expression.type === "AssignmentExpression" &&
6994
6980
  deadStores.has(node.expression)) {
@@ -7010,40 +6996,17 @@ function eliminateDeadStores(state, func, graph, logThisRun) {
7010
6996
  changes = true;
7011
6997
  return { type: "Literal", value: null, raw: "null" };
7012
6998
  }
7013
- if (node.type === "VariableDeclaration") {
7014
- const result = [];
7015
- for (let i = 0; i < node.declarations.length; i++) {
7016
- const decl = node.declarations[i];
7017
- if (decl.init && deadStores.has(decl)) {
7018
- const body = unused(state, decl.init);
7019
- if (body.length) {
7020
- if (!parent ||
7021
- (parent.type !== "BlockStatement" && parent.type !== "SwitchCase")) {
7022
- // Must be the init in a for statement. Fixing
7023
- // it would be complicated, so just punt for now.
7024
- break;
7025
- }
7026
- const newDeclaration = withLoc({ ...node }, node, decl.id);
7027
- if (i + 1 < node.declarations.length) {
7028
- newDeclaration.declarations = node.declarations.splice(0, i + 1);
7029
- result.push(newDeclaration);
7030
- withLoc(node, node.declarations[0], node);
7031
- i = -1;
7032
- }
7033
- else {
7034
- result.push(node);
7035
- }
7036
- result.push(...body);
7037
- }
7038
- changes = true;
7039
- delete decl.init;
7040
- }
7041
- }
7042
- if (result.length) {
7043
- if (!result.includes(node)) {
7044
- result.push(node);
6999
+ if (node.type === "VariableDeclarator") {
7000
+ const decl = node;
7001
+ if (decl.init && deadStores.has(decl)) {
7002
+ const body = unused(state, decl.init);
7003
+ delete decl.init;
7004
+ changes = true;
7005
+ if (!body.length) {
7006
+ return null;
7045
7007
  }
7046
- return result;
7008
+ body.unshift(decl);
7009
+ return body;
7047
7010
  }
7048
7011
  }
7049
7012
  return null;
@@ -9342,7 +9305,7 @@ function restrictByEquality(a, b) {
9342
9305
  /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
9343
9306
 
9344
9307
  "use strict";
9345
- /* unused harmony export minimizeLocals */
9308
+ /* unused harmony exports minimizeLocals, variableCleanup */
9346
9309
  /* harmony import */ var node_assert__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(4143);
9347
9310
  /* harmony import */ var node_assert__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(node_assert__WEBPACK_IMPORTED_MODULE_0__);
9348
9311
  /* harmony import */ var _api__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(6817);
@@ -9516,11 +9479,6 @@ function minimizeLocals(state, func) {
9516
9479
  return null;
9517
9480
  }
9518
9481
  break;
9519
- case "ExpressionStatement":
9520
- if (node.expression.type === "Literal") {
9521
- return false;
9522
- }
9523
- break;
9524
9482
  case "UpdateExpression":
9525
9483
  if (info) {
9526
9484
  assert(node.argument.type === "Identifier");
@@ -9541,7 +9499,7 @@ function minimizeLocals(state, func) {
9541
9499
  }
9542
9500
  // VariableDeclarations aren't allowed to have
9543
9501
  // AssignmentExpressions in them, but we'll fix that
9544
- // below
9502
+ // via variableCleanup
9545
9503
  return withLoc({
9546
9504
  type: "AssignmentExpression",
9547
9505
  operator: "=",
@@ -9554,79 +9512,297 @@ function minimizeLocals(state, func) {
9554
9512
  }, node, node);
9555
9513
  }
9556
9514
  break;
9557
- case "VariableDeclaration":
9558
- if (node.declarations.some((decl) => decl.type !== "VariableDeclarator")) {
9559
- const results = [];
9560
- node.declarations.forEach((decl) => {
9561
- if (isExpression(decl)) {
9562
- results.push(withLoc({ type: "ExpressionStatement", expression: decl }, decl, decl));
9563
- }
9564
- else if (decl.init) {
9565
- results.push(withLoc({
9566
- type: "ExpressionStatement",
9567
- expression: withLoc({
9568
- type: "AssignmentExpression",
9569
- operator: "=",
9570
- left: withLoc({
9571
- type: "Identifier",
9572
- name: variableDeclarationName(decl.id),
9573
- }, decl.id, decl.id),
9574
- right: decl.init,
9575
- }, decl, decl),
9576
- }, decl, decl));
9577
- }
9578
- });
9579
- node.declarations = node.declarations.filter((decl) => {
9580
- if (decl.type === "VariableDeclarator") {
9581
- delete decl.init;
9582
- return true;
9583
- }
9584
- return false;
9585
- });
9586
- if (node.declarations.length) {
9587
- withLocDeep(node, node, false);
9588
- results.unshift(node);
9515
+ }
9516
+ assert(!info);
9517
+ return variableCleanup(node);
9518
+ });
9519
+ return;
9520
+ }
9521
+ function variableCleanup(node) {
9522
+ switch (node.type) {
9523
+ case "ExpressionStatement":
9524
+ if (node.expression.type === "Literal") {
9525
+ return false;
9526
+ }
9527
+ break;
9528
+ case "VariableDeclaration":
9529
+ if (node.declarations.some((decl) => decl.type !== "VariableDeclarator")) {
9530
+ const results = [];
9531
+ node.declarations.forEach((decl) => {
9532
+ if (isStatement(decl)) {
9533
+ results.push(decl);
9534
+ }
9535
+ else if (isExpression(decl)) {
9536
+ results.push(withLoc({ type: "ExpressionStatement", expression: decl }, decl, decl));
9537
+ }
9538
+ else if (decl.init) {
9539
+ results.push(withLoc({
9540
+ type: "ExpressionStatement",
9541
+ expression: withLoc({
9542
+ type: "AssignmentExpression",
9543
+ operator: "=",
9544
+ left: withLoc({
9545
+ type: "Identifier",
9546
+ name: variableDeclarationName(decl.id),
9547
+ }, decl.id, decl.id),
9548
+ right: decl.init,
9549
+ }, decl, decl),
9550
+ }, decl, decl));
9589
9551
  }
9590
- // if this was the init of a ForStatement, this will
9591
- // replace its init with a BlockStatement, so we have to
9592
- // fix that below.
9593
- return results;
9552
+ });
9553
+ node.declarations = node.declarations.filter((decl) => {
9554
+ if (decl.type === "VariableDeclarator") {
9555
+ delete decl.init;
9556
+ return true;
9557
+ }
9558
+ return false;
9559
+ });
9560
+ if (node.declarations.length) {
9561
+ withLocDeep(node, node, false);
9562
+ results.unshift(node);
9594
9563
  }
9595
- break;
9596
- case "ForStatement":
9597
- if (node.init) {
9598
- if (node.init.type === "BlockStatement") {
9599
- const result = node.init;
9600
- delete node.init;
9601
- result.body.push(node);
9602
- if (node.loc && result.loc) {
9603
- // result has the range of the original VariableDeclaration
9604
- // but now we're moving that ahead of the 'for', so to keep
9605
- // things straight, we need to set the for's start to be
9606
- // where result ended, and result's end to be where the for
9607
- // ends (since that block now encloses the for)
9608
- node.start = result.end;
9609
- node.loc.start = result.loc.end;
9610
- result.end = node.end;
9611
- result.loc.end = node.loc.end;
9564
+ // if this was the init of a ForStatement, this will
9565
+ // replace its init with a BlockStatement, so we have to
9566
+ // fix that below.
9567
+ return results;
9568
+ }
9569
+ break;
9570
+ case "ForStatement":
9571
+ if (node.init) {
9572
+ if (node.init.type === "BlockStatement") {
9573
+ const result = node.init;
9574
+ delete node.init;
9575
+ result.body.push(node);
9576
+ if (node.loc && result.loc) {
9577
+ // result has the range of the original VariableDeclaration
9578
+ // but now we're moving that ahead of the 'for', so to keep
9579
+ // things straight, we need to set the for's start to be
9580
+ // where result ended, and result's end to be where the for
9581
+ // ends (since that block now encloses the for)
9582
+ node.start = result.end;
9583
+ node.loc.start = result.loc.end;
9584
+ result.end = node.end;
9585
+ result.loc.end = node.loc.end;
9586
+ }
9587
+ return result;
9588
+ }
9589
+ if (node.init.type === "Literal") {
9590
+ delete node.init;
9591
+ }
9592
+ }
9593
+ break;
9594
+ case "SequenceExpression":
9595
+ if (node.expressions.some((e) => e.type === "Literal")) {
9596
+ node.expressions = node.expressions.filter((e) => e.type !== "Literal");
9597
+ }
9598
+ break;
9599
+ }
9600
+ return null;
9601
+ }
9602
+
9603
+
9604
+ /***/ }),
9605
+
9606
+ /***/ 4416:
9607
+ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
9608
+
9609
+ "use strict";
9610
+ /* unused harmony export minimizeModules */
9611
+ /* harmony import */ var node_assert__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(4143);
9612
+ /* harmony import */ var node_assert__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(node_assert__WEBPACK_IMPORTED_MODULE_0__);
9613
+ /* harmony import */ var _ast__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(6652);
9614
+ /* harmony import */ var _api__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(6817);
9615
+ /* harmony import */ var _api__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(_api__WEBPACK_IMPORTED_MODULE_2__);
9616
+
9617
+
9618
+
9619
+ function minimizeModules(ast, state) {
9620
+ const { pre, post } = state;
9621
+ try {
9622
+ const replacementMap = new Map();
9623
+ const conflictingNames = new Set();
9624
+ state.pre = (node) => {
9625
+ if (state.inType)
9626
+ return null;
9627
+ switch (node.type) {
9628
+ case "ModuleDeclaration":
9629
+ case "ClassDeclaration":
9630
+ case "FunctionDeclaration":
9631
+ return ["body"];
9632
+ case "Using":
9633
+ conflictingNames.add(node.as?.name ??
9634
+ (node.id.type === "Identifier"
9635
+ ? node.id.name
9636
+ : node.id.property.name));
9637
+ return [];
9638
+ case "ImportModule":
9639
+ conflictingNames.add(node.id.type === "Identifier" ? node.id.name : node.id.property.name);
9640
+ return [];
9641
+ case "Identifier":
9642
+ case "MemberExpression": {
9643
+ let current = node;
9644
+ const parts = [];
9645
+ while (current.type === "MemberExpression" && !current.computed) {
9646
+ parts.unshift(current);
9647
+ current = current.object;
9648
+ }
9649
+ if (current.type !== "Identifier" &&
9650
+ current.type !== "ThisExpression") {
9651
+ break;
9652
+ }
9653
+ let toReplace = null;
9654
+ let module = null;
9655
+ let addImport = false;
9656
+ let [, results] = state.lookupValue(current, null);
9657
+ let i = 0;
9658
+ for (; results &&
9659
+ results.length === 1 &&
9660
+ results[0].results.length === 1 &&
9661
+ (results[0].results[0].type === "Program" ||
9662
+ results[0].results[0].type === "ClassDeclaration" ||
9663
+ results[0].results[0].type === "ModuleDeclaration"); i++) {
9664
+ if (current.type === "Identifier" &&
9665
+ results[0].results[0].type === "ModuleDeclaration" &&
9666
+ isImportCandidate(results[0].results[0])) {
9667
+ const directResults = i
9668
+ ? state.lookupValue(current, null)
9669
+ : results;
9670
+ if (directResults &&
9671
+ directResults.length === 1 &&
9672
+ directResults[0].results.length === 1 &&
9673
+ directResults[0].results[0] === results[0].results[0]) {
9674
+ // we would find the same thing if we just looked up
9675
+ // current directly.
9676
+ toReplace = (i ? parts[i - 1] : current);
9677
+ module = results[0].results[0];
9678
+ if (findUsingForNode(state, state.stack, state.stack.length - 1, current) === directResults[0].results[0]) {
9679
+ // we already find it via an import, so we don't need
9680
+ // a new import.
9681
+ addImport = false;
9682
+ }
9683
+ else {
9684
+ addImport = true;
9685
+ }
9686
+ }
9687
+ else {
9688
+ toReplace = parts[i - 1];
9689
+ module = results[0].results[0];
9690
+ addImport = true;
9691
+ }
9612
9692
  }
9613
- return result;
9693
+ if (i === parts.length)
9694
+ break;
9695
+ current = parts[i].property;
9696
+ results = lookupNext(state, results, "decls", current);
9614
9697
  }
9615
- if (node.init.type === "Literal") {
9616
- delete node.init;
9698
+ if (toReplace) {
9699
+ assert(module);
9700
+ replacementMap.set(toReplace, { module, addImport });
9617
9701
  }
9702
+ else if (parts.length === 0) {
9703
+ assert(node.type === "Identifier");
9704
+ conflictingNames.add(node.name);
9705
+ }
9706
+ else if (parts[0].object.type === "Identifier") {
9707
+ conflictingNames.add(parts[0].object.name);
9708
+ }
9709
+ return [];
9618
9710
  }
9619
- break;
9620
- case "SequenceExpression":
9621
- if (node.expressions.some((e) => e.type === "Literal")) {
9622
- node.expressions = node.expressions.filter((e) => e.type !== "Literal");
9711
+ }
9712
+ return null;
9713
+ };
9714
+ collectNamespaces(ast, state);
9715
+ const mappedNames = new Map();
9716
+ replacementMap.forEach((value, key) => {
9717
+ let name;
9718
+ if (value.addImport) {
9719
+ name = mappedNames.get(value.module);
9720
+ if (!name) {
9721
+ name = value.module.name;
9722
+ for (let i = 0; conflictingNames.has(name); i++) {
9723
+ name = `${value.module.name}_${i}`;
9724
+ }
9725
+ mappedNames.set(value.module, name);
9726
+ conflictingNames.add(name);
9623
9727
  }
9624
- break;
9625
- }
9626
- assert(!info);
9627
- return null;
9728
+ }
9729
+ else {
9730
+ name = key.type === "Identifier" ? key.name : key.property.name;
9731
+ }
9732
+ const original = formatAstLongLines(key);
9733
+ const repl = key;
9734
+ repl.type = "Identifier";
9735
+ repl.name = name;
9736
+ if (name !== original) {
9737
+ repl.original = original;
9738
+ }
9739
+ delete repl.property;
9740
+ delete repl.object;
9741
+ delete repl.computed;
9742
+ });
9743
+ mappedNames.forEach((name, module) => {
9744
+ const id = makeScopedName(module.fullName.slice(2));
9745
+ const as = name !== (id.type === "Identifier" ? id : id.property).name &&
9746
+ makeIdentifier(name);
9747
+ const using = withLocDeep(as ? { type: "Using", id, as } : { type: "Using", id }, ast, false, true);
9748
+ ast.body.unshift(using);
9749
+ });
9750
+ }
9751
+ finally {
9752
+ state.pre = pre;
9753
+ state.post = post;
9754
+ }
9755
+ }
9756
+ /**
9757
+ * There's a bug in garmin's runtime (although the compiler could
9758
+ * work around it). See
9759
+ *
9760
+ * https://forums.garmin.com/developer/connect-iq/i/bug-reports/referencing-an-imported-module-doesn-t-run-its-parent-s-init
9761
+ *
9762
+ * What this means is that if a module's parent isn't `globals`
9763
+ * and it needs to be initialized, then we can't risk
9764
+ * importing it, because the parent module might not get initialized
9765
+ * in time.
9766
+ */
9767
+ function isImportCandidate(module) {
9768
+ if (module.fullName.startsWith("$.Toybox."))
9769
+ return true;
9770
+ if (module.fullName.startsWith("$.Rez."))
9771
+ return false;
9772
+ assert(module.stack);
9773
+ if (module.stack.length === 1)
9774
+ return true;
9775
+ return module.stack.every((elem) => {
9776
+ if (!elem.sn.decls)
9777
+ return false;
9778
+ if (elem.sn.type === "Program")
9779
+ return true;
9780
+ if (elem.sn.type !== "ModuleDeclaration")
9781
+ return false;
9782
+ return Object.values(elem.sn.decls).every((decls) => decls.every((decl) => {
9783
+ if (decl.type !== "VariableDeclarator")
9784
+ return true;
9785
+ if (!decl.node.init)
9786
+ return true;
9787
+ if (decl.node.init.type === "UnaryExpression" &&
9788
+ decl.node.init.operator === ":") {
9789
+ return true;
9790
+ }
9791
+ if (decl.node.init.type !== "Literal")
9792
+ return false;
9793
+ switch (typeof decl.node.init.value) {
9794
+ case "boolean":
9795
+ return true;
9796
+ case "bigint":
9797
+ return false;
9798
+ case "number":
9799
+ return !/[dl]$/i.test(decl.node.init.raw);
9800
+ case "object":
9801
+ return decl.node.init.value === null;
9802
+ }
9803
+ return false;
9804
+ }));
9628
9805
  });
9629
- return;
9630
9806
  }
9631
9807
 
9632
9808