@markw65/monkeyc-optimizer 1.1.9 → 1.1.11

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
@@ -1,4 +1,4 @@
1
- 0 && (module.exports = {checkCompilerVersion,collectNamespaces,createDocumentationMap,diagnostic,diagnosticHelper,findNamesInScope,findUsingForNode,formatAst,formatAstLongLines,getApiFunctionInfo,getApiMapping,getSuperClasses,hasProperty,isLocal,isLookupCandidate,isStateNode,lookupByFullName,lookupNext,lookupResultContains,lookupWithType,makeToyboxLink,mapVarDeclsByType,markInvokeClassMethod,parseSdkVersion,sameLookupResult,traverseAst,variableDeclarationName,visitReferences,visit_resources,visitorNode});
1
+ 0 && (module.exports = {checkCompilerVersion,collectNamespaces,createDocumentationMap,diagnostic,diagnosticHelper,findNamesInScope,findUsingForNode,formatAst,formatAstLongLines,getApiFunctionInfo,getApiMapping,getSuperClasses,hasProperty,isClassVariable,isLocal,isLookupCandidate,isStateNode,lookupByFullName,lookupNext,lookupResultContains,lookupWithType,makeToyboxLink,mapVarDeclsByType,markInvokeClassMethod,parseSdkVersion,sameLookupResult,traverseAst,variableDeclarationName,visitReferences,visit_resources,visitorNode});
2
2
  /******/ (() => { // webpackBootstrap
3
3
  /******/ var __webpack_modules__ = ({
4
4
 
@@ -619,7 +619,7 @@ class LocalState {
619
619
  this.unreachable = true;
620
620
  }
621
621
  }
622
- function buildReducedGraph(state, func, notice) {
622
+ function buildReducedGraph(state, func, refsForUpdate, notice) {
623
623
  const { stack, pre, post } = state;
624
624
  try {
625
625
  const localState = new LocalState(func.node);
@@ -627,8 +627,11 @@ function buildReducedGraph(state, func, notice) {
627
627
  state.stack = [...func.stack];
628
628
  const stmtStack = [func.node];
629
629
  const testStack = [{ node: func.node }];
630
+ const allEvents = [];
631
+ const eventsStack = [];
630
632
  let tryActive = 0;
631
633
  state.pre = (node) => {
634
+ eventsStack.push(allEvents.length);
632
635
  if (state.inType || localState.unreachable) {
633
636
  return [];
634
637
  }
@@ -954,6 +957,12 @@ function buildReducedGraph(state, func, notice) {
954
957
  }
955
958
  return [];
956
959
  case "AssignmentExpression":
960
+ if (refsForUpdate && node.operator !== "=") {
961
+ // if its an update, we need to see a "ref"
962
+ // of the lhs, then whatever happens on the rhs,
963
+ // and then the assignment itself
964
+ return null;
965
+ }
957
966
  if (node.left.type === "MemberExpression") {
958
967
  state.traverse(node.left.object);
959
968
  if (node.left.computed) {
@@ -983,6 +992,7 @@ function buildReducedGraph(state, func, notice) {
983
992
  return null;
984
993
  };
985
994
  const addEvent = (block, event) => {
995
+ allEvents.push(event);
986
996
  if (!block.events) {
987
997
  block.events = [event];
988
998
  }
@@ -991,11 +1001,13 @@ function buildReducedGraph(state, func, notice) {
991
1001
  }
992
1002
  };
993
1003
  state.post = (node) => {
1004
+ const eventIndex = eventsStack.pop();
1005
+ const getContainedEvents = () => allEvents.slice(eventIndex);
994
1006
  const curStmt = stmtStack[stmtStack.length - 1];
995
1007
  const topTest = testStack[testStack.length - 1];
996
1008
  if (!state.inType) {
997
1009
  const throws = tryActive > 0 && mayThrow(node);
998
- const events = notice(node, curStmt, throws);
1010
+ const events = notice(node, curStmt, throws, getContainedEvents);
999
1011
  if (throws) {
1000
1012
  if (!events) {
1001
1013
  throw new Error("mayThrow expression in try/catch must generate an event");
@@ -1042,7 +1054,7 @@ function buildReducedGraph(state, func, notice) {
1042
1054
  throw new Error("Internal error: Unexpected successor edges");
1043
1055
  }
1044
1056
  localState.addEdge(localState.curBlock, topTest.false);
1045
- const event = notice(node, curStmt, 1);
1057
+ const event = notice(node, curStmt, 1, getContainedEvents);
1046
1058
  if (event) {
1047
1059
  if (Array.isArray(event)) {
1048
1060
  throw new Error(`Unexpected array of flw events`);
@@ -1183,8 +1195,10 @@ function getPreOrder(head) {
1183
1195
  /* harmony import */ var _ast__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(6652);
1184
1196
  /* harmony import */ var _control_flow__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(5101);
1185
1197
  /* harmony import */ var _function_info__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(819);
1186
- /* harmony import */ var _util__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(6906);
1187
- /* harmony import */ var _util__WEBPACK_IMPORTED_MODULE_5___default = /*#__PURE__*/__webpack_require__.n(_util__WEBPACK_IMPORTED_MODULE_5__);
1198
+ /* harmony import */ var _type_flow_type_flow_util__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(1638);
1199
+ /* harmony import */ var _util__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(6906);
1200
+ /* harmony import */ var _util__WEBPACK_IMPORTED_MODULE_6___default = /*#__PURE__*/__webpack_require__.n(_util__WEBPACK_IMPORTED_MODULE_6__);
1201
+
1188
1202
 
1189
1203
 
1190
1204
 
@@ -1349,7 +1363,7 @@ function buildDataFlowGraph(state, func, wantsLiteral, trackInsertionPoints, wan
1349
1363
  };
1350
1364
  return {
1351
1365
  identifiers,
1352
- graph: buildReducedGraph(state, func, (node, stmt, mayThrow) => {
1366
+ graph: buildReducedGraph(state, func, wantsAllRefs, (node, stmt, mayThrow, getContainedEvents) => {
1353
1367
  if (mayThrow === 1) {
1354
1368
  return wantsAllRefs ? getFlowEvent(node, stmt, findDecl) : null;
1355
1369
  }
@@ -1473,6 +1487,12 @@ function buildDataFlowGraph(state, func, wantsLiteral, trackInsertionPoints, wan
1473
1487
  if (rhs)
1474
1488
  def.rhs = rhs;
1475
1489
  }
1490
+ if (declIsLocal(decl)) {
1491
+ const contained = getContainedEvents().filter((e) => e.type === "ref" || e.type === "mod");
1492
+ if (contained.length) {
1493
+ def.containedEvents = contained;
1494
+ }
1495
+ }
1476
1496
  return def;
1477
1497
  }
1478
1498
  break;
@@ -1487,13 +1507,19 @@ function buildDataFlowGraph(state, func, wantsLiteral, trackInsertionPoints, wan
1487
1507
  decl,
1488
1508
  mayThrow,
1489
1509
  };
1490
- if (wantsAllRefs &&
1491
- node.operator === "=" &&
1492
- (node.right.type === "Identifier" ||
1493
- node.right.type === "MemberExpression")) {
1494
- const rhs = findDecl(node.right);
1495
- if (rhs)
1496
- def.rhs = rhs;
1510
+ if (wantsAllRefs && node.operator === "=") {
1511
+ if (node.right.type === "Identifier" ||
1512
+ node.right.type === "MemberExpression") {
1513
+ const rhs = findDecl(node.right);
1514
+ if (rhs)
1515
+ def.rhs = rhs;
1516
+ }
1517
+ if (declIsLocal(decl)) {
1518
+ const contained = getContainedEvents().filter((e) => e.type === "ref" || e.type === "mod");
1519
+ if (contained.length) {
1520
+ def.containedEvents = contained;
1521
+ }
1522
+ }
1497
1523
  }
1498
1524
  return def;
1499
1525
  }
@@ -1546,6 +1572,12 @@ function buildDataFlowGraph(state, func, wantsLiteral, trackInsertionPoints, wan
1546
1572
  mod.calleeObj = calleeDecl.base;
1547
1573
  }
1548
1574
  }
1575
+ else if (node.callee.type === "MemberExpression") {
1576
+ const calleeObj = findDecl(node.callee.object);
1577
+ if (calleeObj) {
1578
+ mod.calleeObj = calleeObj;
1579
+ }
1580
+ }
1549
1581
  return mod;
1550
1582
  }
1551
1583
  }
@@ -1846,7 +1878,7 @@ function findCalleesByNode(state, callee) {
1846
1878
  /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
1847
1879
 
1848
1880
  "use strict";
1849
- /* unused harmony exports inlinableSubExpression, shouldInline, unused, inlineFunction, applyTypeIfNeeded */
1881
+ /* unused harmony exports inlinableSubExpression, inlineRequested, shouldInline, unused, inlineDiagnostic, inlineFunction, applyTypeIfNeeded */
1850
1882
  /* harmony import */ var _api__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(6817);
1851
1883
  /* harmony import */ var _api__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_api__WEBPACK_IMPORTED_MODULE_0__);
1852
1884
  /* harmony import */ var _ast__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(6652);
@@ -2533,16 +2565,18 @@ function updateLocationForInline(node, original, context, func) {
2533
2565
  throw new Error("Internal error: Inlined call had no location info");
2534
2566
  }
2535
2567
  traverseAst(node, (node) => {
2536
- if (node.loc &&
2537
- (node.loc.source !== loc.source ||
2538
- node.loc.start.offset > loc.end.offset ||
2539
- node.loc.end.offset <= loc.start.offset)) {
2540
- if (!node.origins) {
2541
- node.origins = [];
2568
+ if (!node.loc ||
2569
+ node.loc.source !== loc.source ||
2570
+ node.loc.start.offset > loc.end.offset ||
2571
+ node.loc.end.offset <= loc.start.offset) {
2572
+ if (node.loc) {
2573
+ if (!node.origins) {
2574
+ node.origins = [];
2575
+ }
2576
+ node.origins.unshift({ loc: node.loc, func: func.fullName });
2542
2577
  }
2543
- node.origins.unshift({ loc: node.loc, func: func.fullName });
2578
+ withLoc(node, context, context === original ? context : false);
2544
2579
  }
2545
- withLoc(node, context, context === original ? context : false);
2546
2580
  });
2547
2581
  return node;
2548
2582
  }
@@ -2570,8 +2604,8 @@ function inlineFunction(state, func, call, context) {
2570
2604
  const ret = inlineFunctionHelper(state, func, call, context);
2571
2605
  if (!ret)
2572
2606
  return ret;
2573
- const typecheckFalse = func.node.attrs?.attributes?.elements.find((attr) => isTypecheckArg(attr, false));
2574
- if (!typecheckFalse) {
2607
+ const typecheckAttrs = func.node.attrs?.attributes?.elements.filter((attr) => isTypecheckArg(attr, null));
2608
+ if (!typecheckAttrs || !typecheckAttrs.length) {
2575
2609
  return ret;
2576
2610
  }
2577
2611
  const callerElem = state.stack.find((elem) => elem.sn.type === "FunctionDeclaration");
@@ -2580,6 +2614,9 @@ function inlineFunction(state, func, call, context) {
2580
2614
  }
2581
2615
  const callerSn = callerElem.sn;
2582
2616
  const caller = callerSn.node;
2617
+ if (caller.attrs?.attributes?.elements.find((attr) => isTypecheckArg(attr, null))) {
2618
+ return ret;
2619
+ }
2583
2620
  if (!caller.attrs) {
2584
2621
  caller.attrs = withLoc({
2585
2622
  type: "AttributeList",
@@ -2588,10 +2625,7 @@ function inlineFunction(state, func, call, context) {
2588
2625
  if (!caller.attrs.attributes) {
2589
2626
  caller.attrs.attributes = withLoc({ type: "Attributes", elements: [] }, caller.attrs, false);
2590
2627
  }
2591
- if (caller.attrs.attributes.elements.find((attr) => isTypecheckArg(attr, null))) {
2592
- return ret;
2593
- }
2594
- caller.attrs.attributes.elements.unshift(withLocDeep({ ...typecheckFalse }, caller.attrs, false));
2628
+ caller.attrs.attributes.elements.unshift(...typecheckAttrs.map((typecheck) => withLocDeep({ ...typecheck }, caller.attrs, false)));
2595
2629
  return ret;
2596
2630
  }
2597
2631
  function applyTypeIfNeeded(node) {
@@ -2725,10 +2759,12 @@ function fixNodeScope(state, lookupNode, nodeStack) {
2725
2759
  /* harmony import */ var _type_flow_interp__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(7161);
2726
2760
  /* harmony import */ var _type_flow_optimize__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(3687);
2727
2761
  /* harmony import */ var _type_flow_sub_type__WEBPACK_IMPORTED_MODULE_13__ = __webpack_require__(9234);
2728
- /* harmony import */ var _unused_exprs__WEBPACK_IMPORTED_MODULE_14__ = __webpack_require__(424);
2729
- /* harmony import */ var _util__WEBPACK_IMPORTED_MODULE_15__ = __webpack_require__(6906);
2730
- /* harmony import */ var _util__WEBPACK_IMPORTED_MODULE_15___default = /*#__PURE__*/__webpack_require__.n(_util__WEBPACK_IMPORTED_MODULE_15__);
2731
- /* harmony import */ var _variable_renamer__WEBPACK_IMPORTED_MODULE_16__ = __webpack_require__(4405);
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);
2767
+
2732
2768
 
2733
2769
 
2734
2770
 
@@ -3175,12 +3211,19 @@ async function optimizeMonkeyC(fnMap, resourcesMap, manifestXML, config) {
3175
3211
  state.localsStack = [{}];
3176
3212
  state.calledFunctions = {};
3177
3213
  state.usedByName = {};
3214
+ const checkLookupRules = config.checkCompilerLookupRules;
3215
+ config.checkCompilerLookupRules = "OFF";
3178
3216
  let again = false;
3179
3217
  const optimizeCallHelper = (istate, call, node) => {
3180
3218
  const result = optimizeCall(istate, call, node);
3181
3219
  if (result) {
3182
3220
  if (isExpression(result)) {
3183
- istate.stack[istate.stack.length - 1].node = result;
3221
+ const elem = istate.stack[istate.stack.length - 1];
3222
+ elem.node = result;
3223
+ if (result.type === "Literal") {
3224
+ elem.value = typeFromLiteral(result);
3225
+ elem.embeddedEffects = false;
3226
+ }
3184
3227
  }
3185
3228
  again = true;
3186
3229
  }
@@ -3270,7 +3313,7 @@ async function optimizeMonkeyC(fnMap, resourcesMap, manifestXML, config) {
3270
3313
  throw new Error(`While renaming ${declName} to ${name}: Didn't find original declaration`);
3271
3314
  }
3272
3315
  }
3273
- ident.name = name;
3316
+ renameIdentifier(ident, name);
3274
3317
  }
3275
3318
  else {
3276
3319
  map[declName] = true;
@@ -3330,7 +3373,7 @@ async function optimizeMonkeyC(fnMap, resourcesMap, manifestXML, config) {
3330
3373
  if (hasProperty(map, node.name)) {
3331
3374
  const name = map[node.name];
3332
3375
  if (typeof name === "string") {
3333
- node.name = name;
3376
+ renameIdentifier(node, name);
3334
3377
  }
3335
3378
  const [, results] = state.lookupValue(node);
3336
3379
  if (results) {
@@ -3365,7 +3408,7 @@ async function optimizeMonkeyC(fnMap, resourcesMap, manifestXML, config) {
3365
3408
  if (hasProperty(map, lhs.name)) {
3366
3409
  const name = map[lhs.name];
3367
3410
  if (typeof name === "string") {
3368
- lhs.name = name;
3411
+ renameIdentifier(lhs, name);
3369
3412
  }
3370
3413
  }
3371
3414
  }
@@ -3529,9 +3572,14 @@ async function optimizeMonkeyC(fnMap, resourcesMap, manifestXML, config) {
3529
3572
  }
3530
3573
  case "VariableDeclaration": {
3531
3574
  const locals = topLocals();
3532
- if (locals.map &&
3533
- locals.node &&
3534
- locals.node.type === "BlockStatement") {
3575
+ if (!locals.map) {
3576
+ if (again) {
3577
+ again = false;
3578
+ state.traverse(node);
3579
+ }
3580
+ break;
3581
+ }
3582
+ if (locals.node && locals.node.type === "BlockStatement") {
3535
3583
  let results;
3536
3584
  const declarations = node.declarations;
3537
3585
  let i = 0;
@@ -3737,6 +3785,7 @@ async function optimizeMonkeyC(fnMap, resourcesMap, manifestXML, config) {
3737
3785
  return ret;
3738
3786
  });
3739
3787
  });
3788
+ config.checkCompilerLookupRules = checkLookupRules;
3740
3789
  reportMissingSymbols(state, config);
3741
3790
  if (state.inlineDiagnostics) {
3742
3791
  if (!state.diagnostics) {
@@ -3799,6 +3848,7 @@ function optimizeCall(istate, node, context) {
3799
3848
  node.arguments.every((n) => getNodeValue(n)[0] !== null)) {
3800
3849
  const ret = evaluateFunction(istate, callee, node.arguments);
3801
3850
  if (ret) {
3851
+ inlineDiagnostic(state, callees[0], node, null);
3802
3852
  return withLoc(ret, node, node);
3803
3853
  }
3804
3854
  }
@@ -3957,7 +4007,9 @@ function pragmaChecker(state, ast, diagnostics) {
3957
4007
  if (quote === '"') {
3958
4008
  return haystack.includes(needle);
3959
4009
  }
3960
- const re = new RegExp(needle.replace(/@([-\d.\w]+|"[^"]*")/g, (_match, pat) => `(?:${pat}|pre_${pat.replace(/\W/g, "_")}(?:_\\d+)?)`));
4010
+ const re = new RegExp(needle.replace(/@([-\d.\w]+|"[^"]*")/g, (_match, pat) => `(?:${pat}|pre_${pat
4011
+ .replace(/^([a-zA-Z_]+\.)*/, "")
4012
+ .replace(/\W/g, "_")}(?:_\\d+)?)`));
3961
4013
  return re.test(haystack);
3962
4014
  };
3963
4015
  next();
@@ -4154,7 +4206,9 @@ function sizeBasedPRE(state, func) {
4154
4206
  applyReplacements(func.node, nodeMap, declMap);
4155
4207
  func.node.body.body.unshift(variableDecl);
4156
4208
  }
4157
- minimizeLocals(state, func);
4209
+ if (state.config?.minimizeLocals ?? true) {
4210
+ minimizeLocals(state, func);
4211
+ }
4158
4212
  }
4159
4213
  function buildPREGraph(state, func) {
4160
4214
  const result = buildDataFlowGraph(state, func, (literal) => refCost(literal) > LocalRefCost, true, false);
@@ -4302,11 +4356,12 @@ const LocalRefCost = 2;
4302
4356
  function refCost(node) {
4303
4357
  if (node.type === "Literal") {
4304
4358
  switch (typeof node.value) {
4359
+ case "bigint":
4360
+ return 9;
4305
4361
  case "string":
4306
4362
  return 5;
4307
- case "bigint":
4308
4363
  case "number":
4309
- return 5;
4364
+ return node.raw.match(/d/i) ? 9 : 5;
4310
4365
  case "boolean":
4311
4366
  return 2;
4312
4367
  default:
@@ -4802,26 +4857,32 @@ function applyReplacements(func, nodeMap, declMap) {
4802
4857
  /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
4803
4858
 
4804
4859
  "use strict";
4805
- /* harmony export */ __webpack_require__.d(__webpack_exports__, {
4806
- /* harmony export */ "nK": () => (/* binding */ findObjectDeclsByProperty)
4807
- /* harmony export */ });
4808
- /* unused harmony exports missingNullWorkaround, buildTypeInfo, buildConflictGraph, resolveDottedMember */
4809
- /* harmony import */ var _api__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(6817);
4810
- /* harmony import */ var _api__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_api__WEBPACK_IMPORTED_MODULE_0__);
4811
- /* harmony import */ var _ast__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(6652);
4812
- /* harmony import */ var _control_flow__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(5101);
4813
- /* harmony import */ var _data_flow__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(8180);
4814
- /* harmony import */ var _function_info__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(819);
4815
- /* harmony import */ var _type_flow_dead_store__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(8486);
4816
- /* harmony import */ var _type_flow_interp__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(7161);
4817
- /* harmony import */ var _type_flow_interp_call__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(2222);
4818
- /* harmony import */ var _type_flow_intersection_type__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(6973);
4819
- /* harmony import */ var _type_flow_sub_type__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(9234);
4820
- /* harmony import */ var _type_flow_type_flow_util__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(1638);
4821
- /* harmony import */ var _type_flow_types__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(7255);
4822
- /* harmony import */ var _type_flow_union_type__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(757);
4823
- /* harmony import */ var _util__WEBPACK_IMPORTED_MODULE_13__ = __webpack_require__(6906);
4824
- /* harmony import */ var _util__WEBPACK_IMPORTED_MODULE_13___default = /*#__PURE__*/__webpack_require__.n(_util__WEBPACK_IMPORTED_MODULE_13__);
4860
+ /* unused harmony exports missingNullWorkaround, buildTypeInfo, buildConflictGraph */
4861
+ /* harmony import */ var node_assert__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(4143);
4862
+ /* harmony import */ var node_assert__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(node_assert__WEBPACK_IMPORTED_MODULE_0__);
4863
+ /* harmony import */ var _api__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(6817);
4864
+ /* harmony import */ var _api__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(_api__WEBPACK_IMPORTED_MODULE_1__);
4865
+ /* harmony import */ var _ast__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(6652);
4866
+ /* harmony import */ var _control_flow__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(5101);
4867
+ /* harmony import */ var _data_flow__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(8180);
4868
+ /* harmony import */ var _function_info__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(819);
4869
+ /* harmony import */ var _inliner__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(333);
4870
+ /* harmony import */ var _optimizer_types__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(9697);
4871
+ /* harmony import */ var _type_flow_could_be__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(4055);
4872
+ /* harmony import */ var _type_flow_dead_store__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(8486);
4873
+ /* harmony import */ var _type_flow_interp__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(7161);
4874
+ /* harmony import */ var _type_flow_interp_call__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(2222);
4875
+ /* harmony import */ var _type_flow_intersection_type__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(6973);
4876
+ /* harmony import */ var _type_flow_sub_type__WEBPACK_IMPORTED_MODULE_13__ = __webpack_require__(9234);
4877
+ /* harmony import */ var _type_flow_type_flow_util__WEBPACK_IMPORTED_MODULE_14__ = __webpack_require__(1638);
4878
+ /* harmony import */ var _type_flow_types__WEBPACK_IMPORTED_MODULE_15__ = __webpack_require__(7255);
4879
+ /* harmony import */ var _type_flow_union_type__WEBPACK_IMPORTED_MODULE_16__ = __webpack_require__(757);
4880
+ /* harmony import */ var _util__WEBPACK_IMPORTED_MODULE_17__ = __webpack_require__(6906);
4881
+ /* harmony import */ var _util__WEBPACK_IMPORTED_MODULE_17___default = /*#__PURE__*/__webpack_require__.n(_util__WEBPACK_IMPORTED_MODULE_17__);
4882
+
4883
+
4884
+
4885
+
4825
4886
 
4826
4887
 
4827
4888
 
@@ -4857,15 +4918,24 @@ function buildTypeInfo(state, func, optimizeEquivalencies) {
4857
4918
  const logThisRun = logging && loggingEnabledFor("TYPEFLOW_FUNC", func);
4858
4919
  while (true) {
4859
4920
  const { graph } = buildDataFlowGraph(state, func, () => false, false, true);
4860
- if (optimizeEquivalencies &&
4861
- eliminateDeadStores(state, func, graph, logThisRun)) {
4862
- /*
4863
- * eliminateDeadStores can change the control flow graph,
4864
- * so we need to recompute it if it did anything.
4865
- */
4866
- continue;
4921
+ let copyPropStores;
4922
+ if (optimizeEquivalencies) {
4923
+ const result = eliminateDeadStores(state, func, graph, logThisRun);
4924
+ if (result.changes) {
4925
+ /*
4926
+ * eliminateDeadStores can change the control flow graph,
4927
+ * so we need to recompute it if it did anything.
4928
+ */
4929
+ continue;
4930
+ }
4931
+ if (result.copyPropStores.size) {
4932
+ copyPropStores = result.copyPropStores;
4933
+ }
4934
+ }
4935
+ const result = propagateTypes({ ...state, stack: func.stack }, func, graph, optimizeEquivalencies, copyPropStores, logThisRun);
4936
+ if (!result.redo) {
4937
+ return result.istate;
4867
4938
  }
4868
- return propagateTypes({ ...state, stack: func.stack }, func, graph, optimizeEquivalencies, logThisRun).istate;
4869
4939
  }
4870
4940
  }
4871
4941
  function buildConflictGraph(state, func) {
@@ -4873,8 +4943,8 @@ function buildConflictGraph(state, func) {
4873
4943
  return;
4874
4944
  const logThisRun = logging && loggingEnabledFor("CONFLICT_FUNC", func);
4875
4945
  const { graph, identifiers } = buildDataFlowGraph(state, func, () => false, false, true);
4876
- const { nodeEquivs } = propagateTypes({ ...state, stack: func.stack }, func, graph, false, false);
4877
- const { locals, localConflicts } = findDeadStores(func, graph, nodeEquivs, logThisRun);
4946
+ const { nodeEquivs } = propagateTypes({ ...state, stack: func.stack }, func, graph, false, undefined, logThisRun);
4947
+ const { locals, localConflicts } = findDeadStores(func, graph, nodeEquivs, false, logThisRun);
4878
4948
  return { graph, localConflicts, locals, identifiers, logThisRun };
4879
4949
  }
4880
4950
  function addEquiv(ts, key, equiv) {
@@ -4980,36 +5050,205 @@ function intersectEquiv(ts1, ts2, k) {
4980
5050
  } while (s !== k);
4981
5051
  return ret;
4982
5052
  }
4983
- function mergeTypeState(blockStates, blockVisits, index, from) {
5053
+ function clearAssocPaths(blockState, decl, v) {
5054
+ if (v.assocPaths?.size) {
5055
+ assert(blockState.trackedMemberDecls);
5056
+ v.assocPaths.forEach((assocPath) => {
5057
+ assocPath.split(".").forEach((pathItem) => {
5058
+ const tmd = blockState.trackedMemberDecls?.get(pathItem);
5059
+ if (tmd) {
5060
+ tmd.delete(decl);
5061
+ }
5062
+ });
5063
+ });
5064
+ }
5065
+ }
5066
+ function cloneTypeState(blockState) {
5067
+ const { map, trackedMemberDecls, liveCopyPropEvents, ...rest } = blockState;
5068
+ const clone = { map: new Map(map), ...rest };
5069
+ if (trackedMemberDecls) {
5070
+ clone.trackedMemberDecls = new Map();
5071
+ trackedMemberDecls.forEach((value, key) => {
5072
+ clone.trackedMemberDecls.set(key, new Set(value));
5073
+ });
5074
+ }
5075
+ if (liveCopyPropEvents) {
5076
+ clone.liveCopyPropEvents = new Map();
5077
+ liveCopyPropEvents.forEach((value, key) => {
5078
+ clone.liveCopyPropEvents?.set(key, new Set(value));
5079
+ });
5080
+ }
5081
+ return clone;
5082
+ }
5083
+ function addTrackedMemberDecl(blockState, key, assocKey) {
5084
+ if (!blockState.trackedMemberDecls) {
5085
+ blockState.trackedMemberDecls = new Map();
5086
+ }
5087
+ assocKey.split(".").forEach((pathItem) => {
5088
+ const entries = blockState.trackedMemberDecls.get(pathItem);
5089
+ if (!entries) {
5090
+ blockState.trackedMemberDecls.set(pathItem, new Set([key]));
5091
+ return;
5092
+ }
5093
+ entries.add(key);
5094
+ });
5095
+ }
5096
+ function addCopyPropEvent(blockState, item) {
5097
+ if (!blockState.liveCopyPropEvents) {
5098
+ blockState.liveCopyPropEvents = new Map();
5099
+ }
5100
+ const liveCopyPropEvents = blockState.liveCopyPropEvents;
5101
+ const decl = item.event.decl;
5102
+ assert(declIsLocal(decl));
5103
+ let tov = blockState.map.get(decl);
5104
+ assert(tov);
5105
+ if (tov.copyPropItem !== item) {
5106
+ tov = { ...tov, copyPropItem: item };
5107
+ blockState.map.set(decl, tov);
5108
+ }
5109
+ item.contained.forEach((value, key) => {
5110
+ const decls = liveCopyPropEvents.get(key);
5111
+ if (!decls) {
5112
+ liveCopyPropEvents.set(key, new Set([decl]));
5113
+ }
5114
+ else {
5115
+ decls.add(decl);
5116
+ }
5117
+ });
5118
+ }
5119
+ function clearCopyProp(blockState, item) {
5120
+ const liveCopyPropEvents = blockState.liveCopyPropEvents;
5121
+ assert(liveCopyPropEvents);
5122
+ const itemDecl = item.event.decl;
5123
+ item.contained.forEach((event, decl) => {
5124
+ const decls = liveCopyPropEvents.get(decl);
5125
+ assert(decls && decls.has(itemDecl));
5126
+ decls.delete(itemDecl);
5127
+ });
5128
+ }
5129
+ function copyPropFailed(blockState, item, nodeCopyProp) {
5130
+ clearCopyProp(blockState, item);
5131
+ const ref = nodeCopyProp.get(item.event.node);
5132
+ if (ref) {
5133
+ nodeCopyProp.delete(ref);
5134
+ }
5135
+ nodeCopyProp.set(item.event.node, false);
5136
+ }
5137
+ function clearRelatedCopyPropEvents(blockState, decl, nodeCopyProp) {
5138
+ blockState.liveCopyPropEvents
5139
+ ?.get(decl)
5140
+ ?.forEach((cpDecl) => {
5141
+ let value = blockState.map.get(cpDecl);
5142
+ assert(value && value.copyPropItem);
5143
+ assert(Array.from(value.copyPropItem.contained).some(([key]) => {
5144
+ return decl === key;
5145
+ }));
5146
+ copyPropFailed(blockState, value.copyPropItem, nodeCopyProp);
5147
+ value = { ...value };
5148
+ delete value.copyPropItem;
5149
+ blockState.map.set(cpDecl, value);
5150
+ });
5151
+ }
5152
+ function validateTypeState(curState) {
5153
+ curState.liveCopyPropEvents?.forEach((decls) => decls.forEach((cpDecl) => {
5154
+ const value = curState.map.get(cpDecl);
5155
+ assert(value && value.copyPropItem);
5156
+ }));
5157
+ curState.trackedMemberDecls?.forEach((affected, key) => {
5158
+ affected.forEach((decl) => {
5159
+ const value = curState.map.get(decl);
5160
+ assert(value && value.assocPaths);
5161
+ if (!Array.from(value.assocPaths).some((path) => `.${path}.`.includes(`.${key}.`))) {
5162
+ throw new Error("What");
5163
+ }
5164
+ });
5165
+ });
5166
+ }
5167
+ function mergeTypeState(blockStates, index, from, nodeCopyProp) {
4984
5168
  const to = blockStates[index];
4985
5169
  if (!to) {
4986
- blockStates[index] = new Map(from);
4987
- blockVisits[index] = 1;
5170
+ blockStates[index] = cloneTypeState(from);
5171
+ blockStates[index].visits = 1;
4988
5172
  return true;
4989
5173
  }
4990
- const widen = ++blockVisits[index] > 10;
5174
+ const widen = ++to.visits > 10;
5175
+ // we'll rebuild these from scratch
5176
+ delete to.trackedMemberDecls;
5177
+ delete to.liveCopyPropEvents;
4991
5178
  let changes = false;
4992
- to.forEach((tov, k) => {
4993
- const fromv = from.get(k);
5179
+ to.map.forEach((tov, k) => {
5180
+ const fromv = from.map.get(k);
4994
5181
  if (!fromv) {
4995
5182
  changes = true;
4996
5183
  if (tov.equivSet) {
4997
- removeEquiv(to, k);
5184
+ removeEquiv(to.map, k);
4998
5185
  }
4999
- to.delete(k);
5186
+ to.map.delete(k);
5000
5187
  return;
5001
5188
  }
5002
5189
  if (tov.equivSet) {
5003
- if (intersectEquiv(to, from, k)) {
5190
+ if (intersectEquiv(to.map, from.map, k)) {
5191
+ changes = true;
5192
+ tov = to.map.get(k);
5193
+ }
5194
+ }
5195
+ if (tov.assocPaths) {
5196
+ tov = { ...tov };
5197
+ if (!fromv.assocPaths) {
5198
+ changes = true;
5199
+ delete tov.assocPaths;
5200
+ }
5201
+ else {
5202
+ const assocPaths = new Set(tov.assocPaths);
5203
+ assocPaths.forEach((key) => {
5204
+ if (!fromv.assocPaths.has(key)) {
5205
+ assocPaths.delete(key);
5206
+ changes = true;
5207
+ }
5208
+ else {
5209
+ addTrackedMemberDecl(to, k, key);
5210
+ }
5211
+ });
5212
+ if (assocPaths.size) {
5213
+ tov.assocPaths = assocPaths;
5214
+ }
5215
+ else {
5216
+ delete tov.assocPaths;
5217
+ }
5218
+ }
5219
+ to.map.set(k, tov);
5220
+ }
5221
+ // if both from and to have copyPropEvents, we can only
5222
+ // keep it if they're the same event.
5223
+ if (tov.copyPropItem) {
5224
+ if (tov.copyPropItem.event !== fromv.copyPropItem?.event) {
5225
+ const toProp = nodeCopyProp.get(tov.copyPropItem.event.node);
5226
+ if (toProp) {
5227
+ nodeCopyProp.delete(toProp);
5228
+ }
5229
+ nodeCopyProp.set(tov.copyPropItem.event.node, false);
5230
+ if (fromv.copyPropItem) {
5231
+ const fromProp = nodeCopyProp.get(fromv.copyPropItem.event.node);
5232
+ if (fromProp) {
5233
+ nodeCopyProp.delete(fromProp);
5234
+ }
5235
+ nodeCopyProp.set(fromv.copyPropItem.event.node, false);
5236
+ }
5237
+ tov = { ...tov };
5238
+ delete tov.copyPropItem;
5004
5239
  changes = true;
5005
- tov = to.get(k);
5240
+ to.map.set(k, tov);
5241
+ }
5242
+ else {
5243
+ assert(k === tov.copyPropItem.event.decl);
5244
+ addCopyPropEvent(to, tov.copyPropItem);
5006
5245
  }
5007
5246
  }
5008
5247
  if (widen) {
5009
5248
  if (subtypeOf(fromv.curType, tov.curType))
5010
5249
  return;
5011
5250
  if (subtypeOf(tov.curType, fromv.curType)) {
5012
- to.set(k, { ...tov, curType: fromv.curType });
5251
+ to.map.set(k, { ...tov, curType: fromv.curType });
5013
5252
  changes = true;
5014
5253
  return;
5015
5254
  }
@@ -5022,7 +5261,7 @@ function mergeTypeState(blockStates, blockVisits, index, from) {
5022
5261
  if (wide)
5023
5262
  result = wide;
5024
5263
  }
5025
- to.set(k, { ...tov, curType: result });
5264
+ to.map.set(k, { ...tov, curType: result });
5026
5265
  changes = true;
5027
5266
  });
5028
5267
  return changes;
@@ -5033,9 +5272,7 @@ function tsEquivs(state, key) {
5033
5272
  do {
5034
5273
  result.push(tsKey(s));
5035
5274
  const next = state.get(s);
5036
- if (!next || !next.equivSet) {
5037
- throw new Error(`Inconsistent equivSet for ${tsKey(key)}: missing value for ${tsKey(s)}`);
5038
- }
5275
+ assert(next && next.equivSet);
5039
5276
  s = next.equivSet.next;
5040
5277
  } while (s !== key);
5041
5278
  return `[(${result.join(", ")})]`;
@@ -5049,149 +5286,105 @@ function printBlockState(block, state, indent = "") {
5049
5286
  console.log(indent + "Not visited!");
5050
5287
  return;
5051
5288
  }
5052
- state.forEach((value, key) => {
5053
- console.log(`${indent} - ${typeStateEntry(value, key)}${value.equivSet ? " " + tsEquivs(state, key) : ""}`);
5289
+ state.map.forEach((value, key) => {
5290
+ console.log(`${indent} - ${typeStateEntry(value, key)}${value.equivSet ? " " + tsEquivs(state.map, key) : ""}`);
5054
5291
  });
5055
5292
  }
5056
- /*
5057
- * We have an object, and a MemberExpression object.<name>
5058
- * - decls are the StateNodes associated with the known type
5059
- * of object.
5060
- * - possible are all the StateNodes that declare <name>
5061
- *
5062
- * We want to find all the elements of possible which are
5063
- * "compatible" with decls, which tells us the set of things
5064
- * that object.<name> could correspond to, and also what that
5065
- * tells us about object.
5066
- *
5067
- * The return value is two arrays of StateNode. The first
5068
- * gives the refined type of object, and the second is the
5069
- * array of StateNodes that could declare <name>
5070
- */
5071
- function filterDecls(decls, possible, name) {
5072
- if (!possible)
5073
- return [null, null];
5074
- const result = decls.reduce((cur, decl) => {
5075
- const found = possible.reduce((flag, poss) => {
5076
- if (decl === poss ||
5077
- (poss.type === "ClassDeclaration" && (0,_api__WEBPACK_IMPORTED_MODULE_0__.getSuperClasses)(poss)?.has(decl))) {
5078
- // poss extends decl, so decl must actually be a poss
5079
- // eg we know obj is an Object, and we call obj.toNumber
5080
- // so possible includes all the classes that declare toNumber
5081
- // so we can refine obj's type to the union of those types
5082
- if (!cur[0]) {
5083
- cur = [new Set(), new Set()];
5084
- }
5085
- cur[0].add(poss);
5086
- cur[1].add(poss);
5087
- return true;
5293
+ function updateAffected(blockState, objectType, baseDecl, assignedPath, affectedName, affected, assignedType) {
5294
+ affected.forEach((key) => {
5295
+ let droppedComponents = null;
5296
+ const entry = blockState.map.get(key);
5297
+ assert(entry && entry.assocPaths);
5298
+ let newEntry = entry;
5299
+ entry.assocPaths.forEach((path) => {
5300
+ if (key === baseDecl && path === assignedPath) {
5301
+ return;
5088
5302
  }
5089
- else if (decl.type === "ClassDeclaration" &&
5090
- (0,_api__WEBPACK_IMPORTED_MODULE_0__.getSuperClasses)(decl)?.has(poss)) {
5091
- // decl extends poss, so decl remains unchanged
5092
- // eg we know obj is Menu2, we call obj.toString
5093
- // Menu2 doesn't define toString, but Object does
5094
- // so poss is Object. But we still know that
5095
- // obj is Menu2
5096
- if (!cur[0]) {
5097
- cur = [new Set(), new Set()];
5098
- }
5099
- cur[0].add(decl);
5100
- cur[1].add(poss);
5101
- return true;
5303
+ const pathSegments = path.split(".");
5304
+ if (!pathSegments.includes(affectedName)) {
5305
+ return;
5102
5306
  }
5103
- return flag;
5104
- }, false);
5105
- if (!found) {
5106
- // If we didn't find the property in any of the
5107
- // standard places, the runtime might still find
5108
- // it by searching up the Module stack (and up
5109
- // the module stack from any super classes)
5110
- //
5111
- // eg
5112
- //
5113
- // obj = Application.getApp();
5114
- // obj.Properties.whatever
5115
- //
5116
- // Properties doesn't exist on AppBase, but AppBase
5117
- // is declared in Application, and Application
5118
- // does declare Properties. So Application.Properties
5119
- // is (one of) the declarations we should find; but we
5120
- // must not refine obj's type to include Application.
5121
- let d = [decl];
5122
- do {
5123
- d.forEach((d) => {
5124
- const stack = d.stack;
5125
- possible.forEach((poss) => {
5126
- for (let i = stack.length; i--;) {
5127
- const sn = stack[i].sn;
5128
- if (sn.decls === poss.decls) {
5129
- if (!cur[0]) {
5130
- cur = [new Set(), new Set()];
5131
- }
5132
- cur[0].add(decl);
5133
- cur[1].add(poss);
5134
- break;
5135
- }
5136
- if ((0,_api__WEBPACK_IMPORTED_MODULE_0__.hasProperty)(sn.decls, name)) {
5137
- break;
5138
- }
5139
- }
5140
- });
5307
+ const assocPath = [];
5308
+ let type = entry.curType;
5309
+ for (let i = 0; i < pathSegments.length; i++) {
5310
+ const pathItem = pathSegments[i];
5311
+ assocPath.push({
5312
+ name: pathItem === "*" ? null : pathItem,
5313
+ type,
5141
5314
  });
5142
- d = d.flatMap((d) => {
5143
- if (d.type !== "ClassDeclaration" ||
5144
- !d.superClass ||
5145
- d.superClass === true) {
5146
- return [];
5315
+ if (pathItem === affectedName && couldBeShallow(type, objectType)) {
5316
+ const newAssocKey = assocPath.map((av) => av.name ?? "*").join(".");
5317
+ if (newEntry === entry) {
5318
+ newEntry = { ...entry };
5319
+ }
5320
+ if (newAssocKey !== path) {
5321
+ newEntry.assocPaths = new Set(newEntry.assocPaths);
5322
+ newEntry.assocPaths.delete(path);
5323
+ // the "extra" path components will also have entries
5324
+ // in blockState.trackedMemberDecls. Since they're gone
5325
+ // from here, we (may) need to remove them from there
5326
+ if (!droppedComponents) {
5327
+ droppedComponents = new Set();
5328
+ }
5329
+ while (++i < pathSegments.length) {
5330
+ droppedComponents.add(pathSegments[i]);
5331
+ }
5332
+ break;
5147
5333
  }
5148
- return d.superClass;
5149
- });
5150
- } while (d.length);
5334
+ const baseType = updateByAssocPath(assocPath, assignedType, true);
5335
+ newEntry.curType = baseType;
5336
+ break;
5337
+ }
5338
+ if (pathItem === "*") {
5339
+ const newType = { type: 0 /* TypeTag.Never */ };
5340
+ if (type.type & 512 /* TypeTag.Array */) {
5341
+ const atype = getUnionComponent(type, 512 /* TypeTag.Array */);
5342
+ if (atype) {
5343
+ unionInto(newType, atype);
5344
+ }
5345
+ }
5346
+ if (type.type & 1024 /* TypeTag.Dictionary */) {
5347
+ const dtype = getUnionComponent(type, 1024 /* TypeTag.Dictionary */);
5348
+ if (dtype) {
5349
+ unionInto(newType, dtype.value);
5350
+ }
5351
+ }
5352
+ if (newType.type === 0 /* TypeTag.Never */)
5353
+ break;
5354
+ type = newType;
5355
+ }
5356
+ else {
5357
+ const objValue = getObjectValue(type);
5358
+ if (!objValue || !hasProperty(objValue.obj, pathItem)) {
5359
+ break;
5360
+ }
5361
+ type = objValue.obj[pathItem];
5362
+ }
5363
+ }
5364
+ });
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);
5151
5373
  }
5152
- return cur;
5153
- }, [null, null]);
5154
- if (!result[0])
5155
- return [null, null];
5156
- return [Array.from(result[0]), Array.from(result[1])];
5157
- }
5158
- function findObjectDeclsByProperty(state, object, next) {
5159
- const decls = (0,_type_flow_types__WEBPACK_IMPORTED_MODULE_11__/* .getStateNodeDeclsFromType */ .iX)(state, object);
5160
- if (!decls)
5161
- return [null, null];
5162
- const possibleDecls = (0,_api__WEBPACK_IMPORTED_MODULE_0__.hasProperty)(state.allDeclarations, next.property.name) &&
5163
- state.allDeclarations[next.property.name];
5164
- return filterDecls(decls, possibleDecls, next.property.name);
5165
- }
5166
- function refineObjectTypeByDecls(istate, object, trueDecls) {
5167
- const refinedType = typeFromTypeStateNodes(istate.state, trueDecls);
5168
- return intersection(object, refinedType);
5169
- }
5170
- function findNextObjectType(istate, trueDecls, next) {
5171
- const results = lookupNext(istate.state, [{ parent: null, results: trueDecls }], "decls", next.property);
5172
- if (!results)
5173
- return null;
5174
- return results.reduce((cur, lookupDefn) => {
5175
- unionInto(cur, typeFromTypeStateNodes(istate.state, lookupDefn.results));
5176
- return cur;
5177
- }, { type: 0 /* TypeTag.Never */ });
5178
- }
5179
- function resolveDottedMember(istate, object, next) {
5180
- const [objDecls, trueDecls] = findObjectDeclsByProperty(istate.state, object, next);
5181
- if (!objDecls)
5182
- return null;
5183
- const property = findNextObjectType(istate, trueDecls, next);
5184
- if (!property)
5185
- return null;
5186
- const type = refineObjectTypeByDecls(istate, object, objDecls);
5187
- const mayThrow = !subtypeOf(object, type);
5188
- return { mayThrow, object: type, property };
5374
+ });
5189
5375
  }
5190
- function propagateTypes(state, func, graph, optimizeEquivalencies, logThisRun) {
5376
+ function propagateTypes(state, func, graph, optimizeEquivalencies, copyPropStores, logThisRun) {
5191
5377
  // We want to traverse the blocks in reverse post order, in
5192
5378
  // order to propagate the "availability" of the types.
5193
5379
  const order = getPostOrder(graph).reverse();
5194
5380
  const queue = new DataflowQueue();
5381
+ let selfClassDecl = null;
5382
+ if (!(func.attributes & StateNodeAttributes.STATIC)) {
5383
+ const klass = func.stack?.[func.stack?.length - 1].sn;
5384
+ if (klass && klass.type === "ClassDeclaration") {
5385
+ selfClassDecl = klass;
5386
+ }
5387
+ }
5195
5388
  order.forEach((block, i) => {
5196
5389
  block.order = i;
5197
5390
  });
@@ -5202,10 +5395,10 @@ function propagateTypes(state, func, graph, optimizeEquivalencies, logThisRun) {
5202
5395
  printBlockTrailer(block);
5203
5396
  });
5204
5397
  }
5205
- function memberDeclInfo(blockState, decl, clearEquiv, newValue) {
5398
+ function memberDeclInfo(blockState, decl, newValue) {
5206
5399
  const baseType = getStateType(blockState, decl.base);
5207
5400
  const typePath = [baseType];
5208
- let next;
5401
+ let next = null;
5209
5402
  let updateAny = false;
5210
5403
  for (let i = 0, l = decl.path.length - 1; i <= l; i++) {
5211
5404
  let cur = typePath.pop();
@@ -5276,55 +5469,62 @@ function propagateTypes(state, func, graph, optimizeEquivalencies, logThisRun) {
5276
5469
  typePath.push(cur);
5277
5470
  typePath.push(next);
5278
5471
  }
5279
- for (let i = decl.path.length; i--;) {
5280
- const me = decl.path[i];
5281
- const property = typePath.pop();
5282
- let object = typePath.pop();
5283
- if (!me.computed) {
5284
- const value = getObjectValue(object);
5285
- if (value) {
5286
- if (value.obj && hasProperty(value.obj, me.property.name)) {
5287
- const prevProp = value.obj[me.property.name];
5288
- if (!subtypeOf(prevProp, property)) {
5289
- object = cloneType(object);
5290
- const newValue = { klass: value.klass, obj: { ...value.obj } };
5291
- newValue.obj[me.property.name] = intersection(prevProp, property);
5292
- setUnionComponent(object, 32768 /* TypeTag.Object */, newValue);
5472
+ const assocValue = decl.path.map((me, i) => ({
5473
+ name: me.computed ? null : me.property.name,
5474
+ type: typePath[i],
5475
+ }));
5476
+ const assocKey = assocValue.map((av) => av.name ?? "*").join(".");
5477
+ const newType = updateByAssocPath(assocValue, next, false);
5478
+ setStateEvent(blockState, decl.base, newType, newValue ? 1 /* UpdateKind.Inner */ : 0 /* UpdateKind.None */);
5479
+ const tsv = { ...blockState.map.get(decl.base) };
5480
+ tsv.assocPaths = new Set(tsv.assocPaths);
5481
+ tsv.assocPaths.add(assocKey);
5482
+ blockState.map.set(decl.base, tsv);
5483
+ addTrackedMemberDecl(blockState, decl.base, assocKey);
5484
+ if (newValue) {
5485
+ const baseElem = assocValue[decl.path.length - 1];
5486
+ if (baseElem.name) {
5487
+ const affected = blockState.trackedMemberDecls?.get(baseElem.name);
5488
+ if (affected) {
5489
+ updateAffected(blockState, baseElem.type, decl.base, assocKey, baseElem.name, affected, next);
5490
+ }
5491
+ }
5492
+ if (selfClassDecl) {
5493
+ // Handle interference between the MemberDecl store
5494
+ // and the "self" object.
5495
+ const baseObj = getObjectValue(baseElem.type);
5496
+ if (baseObj &&
5497
+ baseObj.klass.type === 16384 /* TypeTag.Class */ &&
5498
+ some(baseObj.klass.value, (cls) => cls === selfClassDecl ||
5499
+ getSuperClasses(cls)?.has(selfClassDecl) ||
5500
+ getSuperClasses(selfClassDecl)?.has(cls) ||
5501
+ false)) {
5502
+ const last = decl.path[decl.path.length - 1];
5503
+ if (!last.computed) {
5504
+ const result = lookupNext(state, [{ parent: null, results: [selfClassDecl] }], "decls", last.property);
5505
+ if (result) {
5506
+ const decls = result.flatMap((lookupDef) => lookupDef.results);
5507
+ const doUpdate = (key, cur) => {
5508
+ const update = cloneType(cur.curType);
5509
+ unionInto(update, next);
5510
+ setStateEvent(blockState, key, update, 0 /* UpdateKind.None */);
5511
+ };
5512
+ if (decls.length === 1) {
5513
+ const cur = blockState.map.get(decls[0]);
5514
+ cur && doUpdate(decls[0], cur);
5515
+ }
5516
+ else {
5517
+ blockState.map.forEach((cur, key) => {
5518
+ if (Array.isArray(key) && key[0] === decls[0]) {
5519
+ doUpdate(key, cur);
5520
+ }
5521
+ });
5522
+ }
5293
5523
  }
5294
5524
  }
5295
- else {
5296
- const obj = value.obj ? { ...value.obj } : {};
5297
- obj[me.property.name] = property;
5298
- object = cloneType(object);
5299
- setUnionComponent(object, 32768 /* TypeTag.Object */, {
5300
- klass: value.klass,
5301
- obj,
5302
- });
5303
- }
5304
- }
5305
- }
5306
- else {
5307
- if (object.type & 512 /* TypeTag.Array */) {
5308
- const avalue = getUnionComponent(object, 512 /* TypeTag.Array */);
5309
- if (!avalue || !subtypeOf(property, avalue)) {
5310
- object = cloneType(object);
5311
- setUnionComponent(object, 512 /* TypeTag.Array */, property);
5312
- }
5313
- }
5314
- if (object.type & 1024 /* TypeTag.Dictionary */) {
5315
- const dvalue = getUnionComponent(object, 1024 /* TypeTag.Dictionary */);
5316
- if (!dvalue || !subtypeOf(property, dvalue.value)) {
5317
- object = cloneType(object);
5318
- setUnionComponent(object, 1024 /* TypeTag.Dictionary */, {
5319
- key: dvalue?.key || { type: 524287 /* TypeTag.Any */ },
5320
- value: property,
5321
- });
5322
- }
5323
5525
  }
5324
5526
  }
5325
- typePath.push(object);
5326
5527
  }
5327
- setStateEvent(blockState, decl.base, typePath[0], false);
5328
5528
  return [next, updateAny];
5329
5529
  }
5330
5530
  function typeConstraint(decls) {
@@ -5341,38 +5541,61 @@ function propagateTypes(state, func, graph, optimizeEquivalencies, logThisRun) {
5341
5541
  return cur;
5342
5542
  }, { type: 0 /* TypeTag.Never */ });
5343
5543
  }
5344
- function setStateEvent(blockState, decl, value, clearEquiv) {
5544
+ function setStateEvent(blockState, decl, value, updateKind) {
5345
5545
  if (Array.isArray(decl) ||
5346
5546
  (decl.type !== "MemberDecl" && decl.type !== "Unknown")) {
5347
- if (!clearEquiv) {
5547
+ if (updateKind !== 0 /* UpdateKind.None */) {
5548
+ // even if we're only modifying an Object, rather
5549
+ // than reassigning it, we need to clear the
5550
+ // related copy prop events, because although
5551
+ // we may only see the object itself, the expression
5552
+ // could access its fields. eg if x is the decl, then
5553
+ //
5554
+ // foo(x);
5555
+ //
5556
+ // might change when x.a.b.c is changed, even if we know
5557
+ // that foo is side-effect free, and accesses no globals.
5558
+ clearRelatedCopyPropEvents(blockState, decl, nodeCopyProp);
5559
+ }
5560
+ if (updateKind !== 2 /* UpdateKind.Reassign */) {
5348
5561
  /*
5349
- * If we're not clearing the equivalencies then this update
5350
- * must be applied to every element of the set
5562
+ * If we're not re-assigning, the equivalencies don't
5563
+ * change, so this update must be applied to every
5564
+ * element of the set
5351
5565
  */
5352
- const v = blockState.get(decl);
5566
+ const v = blockState.map.get(decl);
5353
5567
  if (v?.equivSet) {
5354
5568
  let s = decl;
5355
5569
  do {
5356
- const next = blockState.get(s);
5570
+ const next = blockState.map.get(s);
5357
5571
  if (!next || !next.equivSet) {
5358
5572
  throw new Error(`Inconsistent equivSet for ${tsKey(decl)}: missing value for ${tsKey(s)}`);
5359
5573
  }
5360
- blockState.set(s, { ...next, curType: value });
5574
+ blockState.map.set(s, { ...next, curType: value });
5361
5575
  s = next.equivSet.next;
5362
5576
  } while (s !== decl);
5363
- return;
5577
+ }
5578
+ else {
5579
+ blockState.map.set(decl, { ...v, curType: value });
5364
5580
  }
5365
5581
  }
5366
5582
  else {
5367
- removeEquiv(blockState, decl);
5583
+ const v = blockState.map.get(decl);
5584
+ removeEquiv(blockState.map, decl);
5585
+ if (v?.assocPaths?.size) {
5586
+ clearAssocPaths(blockState, decl, v);
5587
+ }
5588
+ if (v?.copyPropItem) {
5589
+ copyPropFailed(blockState, v.copyPropItem, nodeCopyProp);
5590
+ }
5591
+ blockState.map.set(decl, { curType: value });
5368
5592
  }
5369
- blockState.set(decl, { curType: value });
5370
5593
  return;
5371
5594
  }
5372
5595
  if (decl.type === "Unknown") {
5373
5596
  return;
5374
5597
  }
5375
- return memberDeclInfo(blockState, decl, clearEquiv, value)?.[1];
5598
+ return memberDeclInfo(blockState, decl, value)?.[1];
5376
5599
  }
5377
5600
  function getStateType(blockState, decl) {
5378
5601
  return getStateEntry(blockState, decl).curType;
@@ -5380,21 +5603,20 @@ function propagateTypes(state, func, graph, optimizeEquivalencies, logThisRun) {
5380
5603
  function getStateEntry(blockState, decl) {
5381
5604
  if (Array.isArray(decl) ||
5382
5605
  (decl.type !== "MemberDecl" && decl.type !== "Unknown")) {
5383
- let tsVal = blockState.get(decl);
5606
+ let tsVal = blockState.map.get(decl);
5384
5607
  if (!tsVal) {
5385
5608
  tsVal = { curType: typeConstraint(decl) };
5386
- blockState.set(decl, tsVal);
5609
+ blockState.map.set(decl, tsVal);
5387
5610
  }
5388
5611
  return tsVal;
5389
5612
  }
5390
5613
  if (decl.type === "Unknown") {
5391
5614
  return { curType: { type: 0 /* TypeTag.Never */ } };
5392
5615
  }
5393
- const info = memberDeclInfo(blockState, decl, false);
5616
+ const info = memberDeclInfo(blockState, decl);
5394
5617
  return { curType: info ? info[0] : { type: 524287 /* TypeTag.Any */ } };
5395
5618
  }
5396
5619
  const blockStates = [];
5397
- const blockVisits = [];
5398
5620
  const typeMap = new Map();
5399
5621
  const istate = {
5400
5622
  state,
@@ -5412,23 +5634,58 @@ function propagateTypes(state, func, graph, optimizeEquivalencies, logThisRun) {
5412
5634
  if (succ.order == null) {
5413
5635
  throw new Error("Unreachable block was visited");
5414
5636
  }
5415
- if (mergeTypeState(blockStates, blockVisits, succ.order, curState)) {
5637
+ if (mergeTypeState(blockStates, succ.order, curState, nodeCopyProp)) {
5638
+ if (logThisRun) {
5639
+ console.log(`re-merge: ${top.order} -> ${succ.order}`);
5640
+ }
5416
5641
  queue.enqueue(succ);
5417
5642
  }
5418
5643
  });
5419
5644
  };
5420
- function handleMod(curState, calleeObjDecl, callees, node) {
5645
+ function checkModResults(curState, calleeObjDecl, callees, node) {
5421
5646
  const calleeObj = getStateType(curState, calleeObjDecl);
5422
- return every(callees, (callee) => {
5423
- const info = sysCallInfo(callee);
5647
+ const calleeResult = { type: 0 /* TypeTag.Never */ };
5648
+ const result = every(callees, (callee) => {
5649
+ const info = sysCallInfo(istate.state, callee);
5424
5650
  if (!info)
5425
5651
  return false;
5426
5652
  const result = info(istate.state, callee, calleeObj, () => node.arguments.map((arg) => evaluateExpr(state, arg, typeMap).value));
5653
+ if (!result.effectFree) {
5654
+ return false;
5655
+ }
5427
5656
  if (result.calleeObj) {
5428
- setStateEvent(curState, calleeObjDecl, result.calleeObj, false);
5657
+ unionInto(calleeResult, result.calleeObj);
5429
5658
  }
5430
5659
  return true;
5431
5660
  });
5661
+ return result ? calleeResult : null;
5662
+ }
5663
+ function modInterference(blockState, event, doUpdate, callback) {
5664
+ let callees = undefined;
5665
+ if (event.calleeDecl) {
5666
+ const calleeType = getStateType(blockState, event.calleeDecl);
5667
+ if (hasValue(calleeType) && calleeType.type === 8192 /* TypeTag.Function */) {
5668
+ callees = calleeType.value;
5669
+ }
5670
+ else {
5671
+ callees = findCalleesByNode(state, event.node);
5672
+ }
5673
+ }
5674
+ if (callees === undefined && event.callees !== undefined) {
5675
+ callees = event.callees;
5676
+ }
5677
+ if (event.calleeObj) {
5678
+ const calleeObjResult = checkModResults(blockState, event.calleeObj, callees, event.node);
5679
+ if (calleeObjResult) {
5680
+ if (calleeObjResult.type !== 0 /* TypeTag.Never */) {
5681
+ if (doUpdate) {
5682
+ setStateEvent(blockState, event.calleeObj, calleeObjResult, 0 /* UpdateKind.None */);
5683
+ }
5684
+ }
5685
+ return true;
5686
+ }
5687
+ }
5688
+ return callback(callees, event.calleeObj);
5432
5689
  }
5433
5690
  function handleFlowEvent(event, top, curState) {
5434
5691
  const fixTypes = (equal, left, right, leftDecl, rightDecl) => {
@@ -5447,8 +5704,8 @@ function propagateTypes(state, func, graph, optimizeEquivalencies, logThisRun) {
5447
5704
  return false;
5448
5705
  }
5449
5706
  }
5450
- const tmpState = new Map(curState);
5451
- setStateEvent(tmpState, leftDecl, leftr, false);
5707
+ const tmpState = cloneTypeState(curState);
5708
+ setStateEvent(tmpState, leftDecl, leftr, 0 /* UpdateKind.None */);
5452
5709
  if (rightDecl) {
5453
5710
  let rightr = restrictByEquality(left, right);
5454
5711
  if (rightr.type === 0 /* TypeTag.Never */) {
@@ -5460,7 +5717,7 @@ function propagateTypes(state, func, graph, optimizeEquivalencies, logThisRun) {
5460
5717
  return false;
5461
5718
  }
5462
5719
  }
5463
- setStateEvent(tmpState, rightDecl, rightr, false);
5720
+ setStateEvent(tmpState, rightDecl, rightr, 0 /* UpdateKind.None */);
5464
5721
  }
5465
5722
  return tmpState;
5466
5723
  }
@@ -5473,8 +5730,8 @@ function propagateTypes(state, func, graph, optimizeEquivalencies, logThisRun) {
5473
5730
  singletonRemoved.type -= right.type;
5474
5731
  if (singletonRemoved.type === 0 /* TypeTag.Never */)
5475
5732
  return false;
5476
- const tmpState = new Map(curState);
5477
- setStateEvent(tmpState, leftDecl, singletonRemoved, false);
5733
+ const tmpState = cloneTypeState(curState);
5734
+ setStateEvent(tmpState, leftDecl, singletonRemoved, 0 /* UpdateKind.None */);
5478
5735
  return tmpState;
5479
5736
  }
5480
5737
  return null;
@@ -5505,8 +5762,8 @@ function propagateTypes(state, func, graph, optimizeEquivalencies, logThisRun) {
5505
5762
  singletonRemoved.type &= ~(1 /* TypeTag.Null */ | 2 /* TypeTag.False */);
5506
5763
  if (singletonRemoved.type === 0 /* TypeTag.Never */)
5507
5764
  return false;
5508
- const tmpState = new Map(curState);
5509
- setStateEvent(tmpState, event.left, singletonRemoved, false);
5765
+ const tmpState = cloneTypeState(curState);
5766
+ setStateEvent(tmpState, event.left, singletonRemoved, 0 /* UpdateKind.None */);
5510
5767
  return tmpState;
5511
5768
  }
5512
5769
  }
@@ -5520,8 +5777,8 @@ function propagateTypes(state, func, graph, optimizeEquivalencies, logThisRun) {
5520
5777
  });
5521
5778
  if (nonNullRemoved.type === 0 /* TypeTag.Never */)
5522
5779
  return false;
5523
- const tmpState = new Map(curState);
5524
- setStateEvent(tmpState, event.left, nonNullRemoved, false);
5780
+ const tmpState = cloneTypeState(curState);
5781
+ setStateEvent(tmpState, event.left, nonNullRemoved, 0 /* UpdateKind.None */);
5525
5782
  return tmpState;
5526
5783
  }
5527
5784
  break;
@@ -5578,8 +5835,8 @@ function propagateTypes(state, func, graph, optimizeEquivalencies, logThisRun) {
5578
5835
  }
5579
5836
  }
5580
5837
  if (result) {
5581
- const tmpState = new Map(curState);
5582
- setStateEvent(tmpState, event.left, result, false);
5838
+ const tmpState = cloneTypeState(curState);
5839
+ setStateEvent(tmpState, event.left, result, 0 /* UpdateKind.None */);
5583
5840
  return tmpState;
5584
5841
  }
5585
5842
  }
@@ -5606,7 +5863,10 @@ function propagateTypes(state, func, graph, optimizeEquivalencies, logThisRun) {
5606
5863
  console.log(` Flow (true): merge to ${trueSucc.order || -1}`);
5607
5864
  printBlockState(top, sTrue || curState, " >true ");
5608
5865
  }
5609
- if (mergeTypeState(blockStates, blockVisits, trueSucc.order, sTrue || curState)) {
5866
+ if (mergeTypeState(blockStates, trueSucc.order, sTrue || curState, nodeCopyProp)) {
5867
+ if (logThisRun) {
5868
+ console.log(`re-merge: ${top.order} -> ${trueSucc.order}`);
5869
+ }
5610
5870
  queue.enqueue(trueSucc);
5611
5871
  }
5612
5872
  }
@@ -5618,37 +5878,55 @@ function propagateTypes(state, func, graph, optimizeEquivalencies, logThisRun) {
5618
5878
  console.log(` Flow (false): merge to: ${falseSucc.order || -1}`);
5619
5879
  printBlockState(top, sFalse || curState, " >false ");
5620
5880
  }
5621
- if (mergeTypeState(blockStates, blockVisits, falseSucc.order, sFalse || curState)) {
5881
+ if (mergeTypeState(blockStates, falseSucc.order, sFalse || curState, nodeCopyProp)) {
5882
+ if (logThisRun) {
5883
+ console.log(`re-merge: ${top.order} -> ${falseSucc.order}`);
5884
+ }
5622
5885
  queue.enqueue(falseSucc);
5623
5886
  }
5624
5887
  }
5625
5888
  return true;
5626
5889
  }
5890
+ /*
5891
+ * nodeCopyProp contains two related maps. It maps ref nodes
5892
+ * to the def node that should be copy propagated. It also maps
5893
+ * def nodes to false, to indicate a previous failure to find
5894
+ * a copy prop candidate.
5895
+ */
5896
+ const nodeCopyProp = new Map();
5627
5897
  const nodeEquivs = new Map();
5628
5898
  const localDecls = new Map();
5629
5899
  const localConflicts = new Set();
5630
5900
  const selfAssignments = new Set();
5631
5901
  const processEvent = (top, curState, event, skipMerge) => {
5632
5902
  if (!skipMerge && event.mayThrow && top.exsucc) {
5633
- if (mergeTypeState(blockStates, blockVisits, top.exsucc.order, curState)) {
5903
+ if (mergeTypeState(blockStates, top.exsucc.order, curState, nodeCopyProp)) {
5634
5904
  queue.enqueue(top.exsucc);
5635
5905
  }
5636
5906
  }
5907
+ validateTypeState(curState);
5637
5908
  switch (event.type) {
5638
5909
  case "kil": {
5639
5910
  const curEntry = getStateEntry(curState, event.decl);
5640
5911
  if (curEntry.equivSet) {
5641
- removeEquiv(curState, event.decl);
5912
+ removeEquiv(curState.map, event.decl);
5642
5913
  }
5643
- curState.delete(event.decl);
5914
+ if (curEntry.assocPaths) {
5915
+ clearAssocPaths(curState, event.decl, curEntry);
5916
+ }
5917
+ if (curEntry.copyPropItem) {
5918
+ copyPropFailed(curState, curEntry.copyPropItem, nodeCopyProp);
5919
+ }
5920
+ clearRelatedCopyPropEvents(curState, event.decl, nodeCopyProp);
5921
+ curState.map.delete(event.decl);
5644
5922
  break;
5645
5923
  }
5646
5924
  case "ref": {
5647
- const curEntry = getStateEntry(curState, event.decl);
5925
+ let curEntry = getStateEntry(curState, event.decl);
5648
5926
  typeMap.set(event.node, curEntry.curType);
5649
5927
  nodeEquivs.delete(event.node);
5650
5928
  if (curEntry.equivSet) {
5651
- const equiv = Array.from(getEquivSet(curState, event.decl)).filter((decl) => decl !== event.decl && declIsLocal(decl));
5929
+ const equiv = Array.from(getEquivSet(curState.map, event.decl)).filter((decl) => decl !== event.decl && declIsLocal(decl));
5652
5930
  if (equiv.length) {
5653
5931
  nodeEquivs.set(event.node, {
5654
5932
  decl: event.decl,
@@ -5656,6 +5934,26 @@ function propagateTypes(state, func, graph, optimizeEquivalencies, logThisRun) {
5656
5934
  });
5657
5935
  }
5658
5936
  }
5937
+ if (copyPropStores) {
5938
+ nodeCopyProp.delete(event.node);
5939
+ if (curEntry.copyPropItem) {
5940
+ const copyPropInfo = copyPropStores.get(curEntry.copyPropItem.event.node);
5941
+ assert(copyPropInfo && copyPropInfo.ref === event.node);
5942
+ const defNode = nodeCopyProp.get(curEntry.copyPropItem.event.node);
5943
+ assert(!defNode || defNode === event.node);
5944
+ if (defNode !== false) {
5945
+ nodeCopyProp.set(event.node, curEntry.copyPropItem.event.node);
5946
+ nodeCopyProp.set(curEntry.copyPropItem.event.node, event.node);
5947
+ }
5948
+ clearCopyProp(curState, curEntry.copyPropItem);
5949
+ curEntry = { ...curEntry };
5950
+ delete curEntry.copyPropItem;
5951
+ curState.map.set(event.decl, curEntry);
5952
+ }
5953
+ else if (declIsNonLocal(event.decl)) {
5954
+ clearRelatedCopyPropEvents(curState, null, nodeCopyProp);
5955
+ }
5956
+ }
5659
5957
  if (logThisRun) {
5660
5958
  console.log(` ${describeEvent(event)} == ${display(curEntry.curType)}`);
5661
5959
  }
@@ -5665,44 +5963,75 @@ function propagateTypes(state, func, graph, optimizeEquivalencies, logThisRun) {
5665
5963
  if (logThisRun) {
5666
5964
  console.log(` ${describeEvent(event)}`);
5667
5965
  }
5668
- let callees = undefined;
5669
- if (event.calleeDecl) {
5670
- const calleeType = getStateType(curState, event.calleeDecl);
5671
- if (hasValue(calleeType) && calleeType.type === 8192 /* TypeTag.Function */) {
5672
- callees = calleeType.value;
5673
- }
5674
- else {
5675
- callees = findCalleesByNode(state, event.node);
5966
+ modInterference(curState, event, true, (callees, calleeObj) => {
5967
+ clearRelatedCopyPropEvents(curState, null, nodeCopyProp);
5968
+ if (calleeObj) {
5969
+ const objType = getStateType(curState, calleeObj);
5970
+ if (objType.type &
5971
+ (32768 /* TypeTag.Object */ | 512 /* TypeTag.Array */ | 1024 /* TypeTag.Dictionary */)) {
5972
+ setStateEvent(curState, calleeObj, objType, 1 /* UpdateKind.Inner */);
5973
+ }
5676
5974
  }
5677
- }
5678
- if (callees === undefined && event.callees !== undefined) {
5679
- callees = event.callees;
5680
- }
5681
- if (event.calleeObj) {
5682
- if (handleMod(curState, event.calleeObj, callees, event.node)) {
5683
- break;
5975
+ if (nodeCopyProp.size &&
5976
+ event.node.type === "CallExpression" &&
5977
+ some(callees, (callee) => inlineRequested(state, callee))) {
5978
+ // we don't want to copy-prop to the argument of
5979
+ // an inline function, because that could prevent
5980
+ // inlining.
5981
+ event.node.arguments.forEach((arg) => {
5982
+ const def = nodeCopyProp.get(arg);
5983
+ if (def && nodeCopyProp.get(def) !== false) {
5984
+ nodeCopyProp.set(def, false);
5985
+ nodeCopyProp.delete(arg);
5986
+ }
5987
+ });
5684
5988
  }
5685
- }
5686
- curState.forEach((tsv, decl) => {
5687
- let type = tsv.curType;
5688
- if (callees === undefined || modifiableDecl(decl, callees)) {
5689
- if (tsv.equivSet) {
5690
- removeEquiv(curState, decl);
5989
+ curState.map.forEach((tsv, decl) => {
5990
+ 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)))) {
5995
+ return;
5691
5996
  }
5692
- curState.set(decl, { curType: typeConstraint(decl) });
5693
- }
5694
- else if (type.value != null &&
5695
- !every(callees, (callee) => callee.info === false)) {
5696
- if (type.type & 32768 /* TypeTag.Object */) {
5697
- const odata = getObjectValue(tsv.curType);
5698
- if (odata?.obj) {
5699
- type = cloneType(type);
5700
- const newData = { klass: odata.klass };
5701
- setUnionComponent(type, 32768 /* TypeTag.Object */, newData);
5702
- curState.set(decl, { ...tsv, curType: type });
5997
+ if (modifiableDecl(decl, callees)) {
5998
+ if (tsv.equivSet) {
5999
+ removeEquiv(curState.map, decl);
6000
+ }
6001
+ if (tsv.assocPaths) {
6002
+ clearAssocPaths(curState, decl, tsv);
5703
6003
  }
6004
+ // we only attach copyPropItems to locals,
6005
+ // which can't be modified by a call.
6006
+ assert(!tsv.copyPropItem);
6007
+ clearRelatedCopyPropEvents(curState, decl, nodeCopyProp);
6008
+ curState.map.set(decl, { curType: typeConstraint(decl) });
5704
6009
  }
5705
- }
6010
+ else if (type.value != null &&
6011
+ (!callees || !every(callees, (callee) => callee.info === false))) {
6012
+ if (type.type & 32768 /* TypeTag.Object */) {
6013
+ const odata = getObjectValue(tsv.curType);
6014
+ if (odata?.obj) {
6015
+ type = cloneType(type);
6016
+ const newData = { klass: odata.klass };
6017
+ setUnionComponent(type, 32768 /* TypeTag.Object */, newData);
6018
+ if (tsv.assocPaths) {
6019
+ clearAssocPaths(curState, decl, tsv);
6020
+ tsv = { ...tsv };
6021
+ delete tsv.assocPaths;
6022
+ }
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 });
6030
+ }
6031
+ }
6032
+ }
6033
+ });
6034
+ return true;
5706
6035
  });
5707
6036
  break;
5708
6037
  }
@@ -5713,9 +6042,18 @@ function propagateTypes(state, func, graph, optimizeEquivalencies, logThisRun) {
5713
6042
  ? event.node.left
5714
6043
  : null;
5715
6044
  if (lval) {
5716
- const beforeType = getStateType(curState, event.decl);
5717
- if (beforeType) {
5718
- typeMap.set(lval, beforeType);
6045
+ const before = getStateEntry(curState, event.decl);
6046
+ if (before.curType) {
6047
+ typeMap.set(lval, before.curType);
6048
+ }
6049
+ if (before.copyPropItem &&
6050
+ (event.node.type !== "AssignmentExpression" ||
6051
+ event.node.operator !== "=")) {
6052
+ 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);
5719
6057
  }
5720
6058
  }
5721
6059
  const expr = event.node.type === "VariableDeclarator"
@@ -5724,24 +6062,47 @@ function propagateTypes(state, func, graph, optimizeEquivalencies, logThisRun) {
5724
6062
  const type = expr
5725
6063
  ? evaluate(istate, expr).value
5726
6064
  : { type: 524287 /* TypeTag.Any */ };
5727
- if (setStateEvent(curState, event.decl, type, true)) {
5728
- // we wrote through a computed member expression
5729
- // which might have been a Class, Module or Object.
5730
- // That could have affected anything...
5731
- curState.forEach((value, decls) => {
6065
+ const wasComputedDecl = setStateEvent(curState, event.decl, type, 2 /* UpdateKind.Reassign */);
6066
+ some(event.decl, (decl) => {
6067
+ if (decl.type !== "VariableDeclarator" ||
6068
+ decl.node.kind !== "var" ||
6069
+ !isClassVariable(decl)) {
6070
+ return false;
6071
+ }
6072
+ // A write to a class variable could interfere with
6073
+ // a MemberDecl
6074
+ const affected = curState.trackedMemberDecls?.get(decl.name);
6075
+ if (affected) {
6076
+ const objType = typeFromTypeStateNodes(istate.state, map(event.decl, (decl) => decl.type === "VariableDeclarator" &&
6077
+ decl.stack[decl.stack.length - 1].sn).filter((decl) => decl && decl.type === "ClassDeclaration"));
6078
+ updateAffected(curState, objType, event.decl, decl.name, decl.name, affected, type);
6079
+ }
6080
+ return true;
6081
+ });
6082
+ if (wasComputedDecl) {
6083
+ curState.map.forEach((value, decls) => {
6084
+ // we wrote through a computed member expression
6085
+ // which might have been a Class, Module or Object.
6086
+ // That could have affected any non-local...
5732
6087
  if (some(decls, (decl) => decl.type === "VariableDeclarator" &&
5733
6088
  decl.node.kind === "var" &&
5734
6089
  !isLocal(decl))) {
5735
6090
  if (value.equivSet) {
5736
- removeEquiv(curState, decls);
6091
+ removeEquiv(curState.map, decls);
5737
6092
  }
5738
- curState.set(decls, { curType: typeConstraint(decls) });
6093
+ if (value.assocPaths) {
6094
+ clearAssocPaths(curState, decls, value);
6095
+ }
6096
+ assert(!value.copyPropItem);
6097
+ curState.map.set(decls, { curType: typeConstraint(decls) });
6098
+ clearRelatedCopyPropEvents(curState, decls, nodeCopyProp);
5739
6099
  }
5740
6100
  });
5741
6101
  }
5742
6102
  if (event.rhs) {
5743
- const selfAssign = addEquiv(curState, event.rhs, event.decl);
5744
- if (event.node.type === "AssignmentExpression") {
6103
+ const selfAssign = addEquiv(curState.map, event.rhs, event.decl);
6104
+ if (event.node.type === "AssignmentExpression" &&
6105
+ event.node.operator === "=") {
5745
6106
  if (selfAssign) {
5746
6107
  // rhs and lhs are identical
5747
6108
  selfAssignments.add(event.node);
@@ -5751,7 +6112,72 @@ function propagateTypes(state, func, graph, optimizeEquivalencies, logThisRun) {
5751
6112
  }
5752
6113
  }
5753
6114
  }
5754
- if (declIsLocal(event.decl)) {
6115
+ if (!declIsLocal(event.decl)) {
6116
+ clearRelatedCopyPropEvents(curState, null, nodeCopyProp);
6117
+ }
6118
+ else {
6119
+ if (event.containedEvents &&
6120
+ copyPropStores &&
6121
+ nodeCopyProp.get(event.node) !== false &&
6122
+ (!event.rhs || !declIsLocal(event.rhs))) {
6123
+ const copyPropCandidate = copyPropStores.get(event.node);
6124
+ if (copyPropCandidate) {
6125
+ const contained = new Map();
6126
+ if (event.containedEvents.every((event) => {
6127
+ if (event.type === "mod") {
6128
+ if (modInterference(curState, event, false, () => false)) {
6129
+ return true;
6130
+ }
6131
+ if (!copyPropCandidate.ant ||
6132
+ // If the ref isn't anticipated, we can't propagate it
6133
+ // in case it has side effects.
6134
+ some(event.calleeDecl, (callee) => callee.type === "FunctionDeclaration" &&
6135
+ inlineRequested(state, callee))) {
6136
+ // Don't copy prop if the rhs is marked for
6137
+ // inline, because we might move it out of
6138
+ // assignment context, to somewhere it can't be
6139
+ // inlined.
6140
+ return false;
6141
+ }
6142
+ }
6143
+ if (!event.decl ||
6144
+ (isTypeStateKey(event.decl) &&
6145
+ some(event.decl, (decl) => (decl.type === "VariableDeclarator" &&
6146
+ decl.node.kind === "var") ||
6147
+ decl.type === "BinaryExpression" ||
6148
+ decl.type === "Identifier"))) {
6149
+ 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;
6166
+ }
6167
+ const item = contained.get(key);
6168
+ if (!item) {
6169
+ contained.set(key, [event]);
6170
+ }
6171
+ else {
6172
+ item.push(event);
6173
+ }
6174
+ }
6175
+ return true;
6176
+ })) {
6177
+ addCopyPropEvent(curState, { event, contained });
6178
+ }
6179
+ }
6180
+ }
5755
6181
  const name = localDeclName(event.decl);
5756
6182
  const locals = localDecls.get(name);
5757
6183
  if (!locals) {
@@ -5759,7 +6185,8 @@ function propagateTypes(state, func, graph, optimizeEquivalencies, logThisRun) {
5759
6185
  }
5760
6186
  else {
5761
6187
  locals.forEach((local) => {
5762
- if (local !== event.decl && curState.has(local)) {
6188
+ if (local !== event.decl &&
6189
+ curState.map.has(local)) {
5763
6190
  localConflicts.add(local);
5764
6191
  }
5765
6192
  });
@@ -5780,7 +6207,7 @@ function propagateTypes(state, func, graph, optimizeEquivalencies, logThisRun) {
5780
6207
  }
5781
6208
  if (logThisRun) {
5782
6209
  console.log(` ${describeEvent(event)} : ${!Array.isArray(event.left) && event.left.type === "MemberDecl"
5783
- ? `${display(curState.get(event.left.base)?.curType || {
6210
+ ? `${display(curState.map.get(event.left.base)?.curType || {
5784
6211
  type: 524287 /* TypeTag.Any */,
5785
6212
  })} :: `
5786
6213
  : ""}${display(getStateType(curState, event.left))}`);
@@ -5792,13 +6219,13 @@ function propagateTypes(state, func, graph, optimizeEquivalencies, logThisRun) {
5792
6219
  }
5793
6220
  return false;
5794
6221
  };
5795
- blockStates[0] = new Map();
6222
+ blockStates[0] = { map: new Map(), visits: 0 };
5796
6223
  const head = blockStates[0];
5797
6224
  // set the parameters to their initial types
5798
6225
  func.node.params.forEach((param) => {
5799
6226
  setStateEvent(head, param, param.type === "BinaryExpression"
5800
6227
  ? typeFromTypespec(state, param.right)
5801
- : { type: 524287 /* TypeTag.Any */ }, false);
6228
+ : { type: 524287 /* TypeTag.Any */ }, 0 /* UpdateKind.None */);
5802
6229
  });
5803
6230
  queue.enqueue(order[0]);
5804
6231
  while (!queue.empty()) {
@@ -5808,7 +6235,7 @@ function propagateTypes(state, func, graph, optimizeEquivalencies, logThisRun) {
5808
6235
  }
5809
6236
  if (!blockStates[top.order])
5810
6237
  continue;
5811
- const curState = new Map(blockStates[top.order]);
6238
+ const curState = cloneTypeState(blockStates[top.order]);
5812
6239
  if (logThisRun) {
5813
6240
  printBlockHeader(top);
5814
6241
  printBlockState(top, curState);
@@ -5832,6 +6259,16 @@ function propagateTypes(state, func, graph, optimizeEquivalencies, logThisRun) {
5832
6259
  printBlockTrailer(top);
5833
6260
  }
5834
6261
  }
6262
+ nodeCopyProp.forEach((value, key) => {
6263
+ if (key.type === "VariableDeclarator" ||
6264
+ key.type === "AssignmentExpression") {
6265
+ if (value === false) {
6266
+ nodeCopyProp.delete(key);
6267
+ return;
6268
+ }
6269
+ assert(nodeCopyProp.get(value) === key);
6270
+ }
6271
+ });
5835
6272
  if (logThisRun) {
5836
6273
  order.forEach((block) => {
5837
6274
  printBlockHeader(block);
@@ -5849,9 +6286,29 @@ function propagateTypes(state, func, graph, optimizeEquivalencies, logThisRun) {
5849
6286
  nodeEquivs.forEach((value, key) => {
5850
6287
  console.log(`${formatAst(key)} = [${value.equiv.map((equiv) => tsKey(equiv))}] ${key.loc && key.loc.source ? ` (${sourceLocation(key.loc)})` : ""}`);
5851
6288
  });
6289
+ console.log("====== Copy Prop =====");
6290
+ nodeCopyProp.forEach((value, key) => {
6291
+ assert(value !== false);
6292
+ if (key.type === "VariableDeclarator" ||
6293
+ key.type === "AssignmentExpression") {
6294
+ return;
6295
+ }
6296
+ assert((value.type === "VariableDeclarator" && value.init) ||
6297
+ value.type === "AssignmentExpression");
6298
+ const node = value.type === "VariableDeclarator" ? value.init : value.right;
6299
+ console.log(`${formatAst(key)} = [${formatAstLongLines(node)}] ${key.loc && key.loc.source ? ` (${sourceLocation(key.loc)})` : ""}`);
6300
+ });
6301
+ }
6302
+ if (logThisRun) {
6303
+ console.log(formatAstLongLines(func.node));
6304
+ if (copyPropStores) {
6305
+ copyPropStores.forEach(({ ref, ant }, node) => {
6306
+ console.log(`copy-prop-store: ${formatAstLongLines(node)}${ant ? "!" : ""} => ${nodeCopyProp.get(node) !== ref ? "Failed" : "Success"}`);
6307
+ });
6308
+ }
5852
6309
  }
5853
6310
  if (optimizeEquivalencies) {
5854
- if (!nodeEquivs.size && !selfAssignments.size) {
6311
+ if (!nodeEquivs.size && !selfAssignments.size && !nodeCopyProp.size) {
5855
6312
  return { istate, nodeEquivs };
5856
6313
  }
5857
6314
  if (logThisRun) {
@@ -5895,12 +6352,60 @@ function propagateTypes(state, func, graph, optimizeEquivalencies, logThisRun) {
5895
6352
  }
5896
6353
  }));
5897
6354
  traverseAst(func.node.body, null, (node) => {
6355
+ const copyNode = nodeCopyProp.get(node);
6356
+ if (copyNode) {
6357
+ if (node.type === "AssignmentExpression") {
6358
+ if (logThisRun) {
6359
+ console.log(`Killing copy-prop assignment ${formatAstLongLines(node)}`);
6360
+ }
6361
+ return withLoc({ type: "Literal", value: null, raw: "null" }, node, node);
6362
+ }
6363
+ if (node.type === "VariableDeclarator") {
6364
+ assert(node.init);
6365
+ if (logThisRun) {
6366
+ console.log(`Killing copy-prop variable initialization ${formatAstLongLines(node)}`);
6367
+ }
6368
+ const dup = { ...node };
6369
+ delete dup.init;
6370
+ return dup;
6371
+ }
6372
+ if (copyNode.type === "AssignmentExpression") {
6373
+ if (logThisRun) {
6374
+ console.log(`copy-prop ${formatAstLongLines(node)} => ${formatAstLongLines(copyNode.right)}`);
6375
+ }
6376
+ return withLocDeep(copyNode.right, node, node, false);
6377
+ }
6378
+ else if (copyNode.type === "VariableDeclarator") {
6379
+ assert(copyNode.init);
6380
+ if (logThisRun) {
6381
+ console.log(`copy-prop ${formatAstLongLines(node)} => ${formatAstLongLines(copyNode.init)}`);
6382
+ }
6383
+ return withLocDeep(copyNode.init, node, node, false);
6384
+ }
6385
+ assert(false);
6386
+ }
5898
6387
  if (selfAssignments.has(node)) {
5899
6388
  if (logThisRun) {
5900
6389
  console.log(`Deleting self assignment: ${formatAst(node)} (${sourceLocation(node.loc)})`);
5901
6390
  }
5902
6391
  return withLoc({ type: "Literal", value: null, raw: "null" }, node, node);
5903
6392
  }
6393
+ if (nodeCopyProp.size) {
6394
+ /*
6395
+ * Copy prop and equiv can interfere with each other:
6396
+ *
6397
+ * var c = g; // copy prop kills this
6398
+ * ...
6399
+ * var x = g + 2; // node equiv replaces g with c
6400
+ * ...
6401
+ * return c; // copy prop changes this to g
6402
+ *
6403
+ * So ignore equivalencies if copy prop is active.
6404
+ * Note that we have to re-run propagation anyway
6405
+ * if copy prop did anything.
6406
+ */
6407
+ return null;
6408
+ }
5904
6409
  const equiv = nodeEquivs.get(node);
5905
6410
  if (!equiv || localConflicts.has(equiv.decl))
5906
6411
  return null;
@@ -5952,7 +6457,62 @@ function propagateTypes(state, func, graph, optimizeEquivalencies, logThisRun) {
5952
6457
  return replacement;
5953
6458
  });
5954
6459
  }
5955
- return { istate, nodeEquivs };
6460
+ return {
6461
+ istate,
6462
+ nodeEquivs,
6463
+ redo: optimizeEquivalencies && nodeCopyProp.size,
6464
+ };
6465
+ }
6466
+ function updateByAssocPath(path, property, union) {
6467
+ const valueToStore = (base) => {
6468
+ const clone = cloneType(base);
6469
+ unionInto(clone, property);
6470
+ return clone;
6471
+ };
6472
+ for (let i = path.length; i--;) {
6473
+ const pathElem = path[i];
6474
+ let object = pathElem.type;
6475
+ if (pathElem.name) {
6476
+ const value = getObjectValue(object);
6477
+ if (value) {
6478
+ const obj = value.obj ? { ...value.obj } : {};
6479
+ obj[pathElem.name] = union
6480
+ ? valueToStore(obj[pathElem.name] || { type: 524287 /* TypeTag.Any */ })
6481
+ : property;
6482
+ object = cloneType(object);
6483
+ setUnionComponent(object, 32768 /* TypeTag.Object */, {
6484
+ klass: value.klass,
6485
+ obj,
6486
+ });
6487
+ }
6488
+ }
6489
+ else {
6490
+ if (object.type & 512 /* TypeTag.Array */) {
6491
+ object = cloneType(object);
6492
+ setUnionComponent(object, 512 /* TypeTag.Array */, union
6493
+ ? valueToStore(getUnionComponent(object, 512 /* TypeTag.Array */) || {
6494
+ type: 524287 /* TypeTag.Any */,
6495
+ })
6496
+ : property);
6497
+ }
6498
+ if (object.type & 1024 /* TypeTag.Dictionary */) {
6499
+ const dvalue = getUnionComponent(object, 1024 /* TypeTag.Dictionary */);
6500
+ object = cloneType(object);
6501
+ setUnionComponent(object, 1024 /* TypeTag.Dictionary */, {
6502
+ key: dvalue?.key || { type: 524287 /* TypeTag.Any */ },
6503
+ value: union
6504
+ ? valueToStore(getUnionComponent(object, 1024 /* TypeTag.Dictionary */)?.value || {
6505
+ type: 524287 /* TypeTag.Any */,
6506
+ })
6507
+ : property,
6508
+ });
6509
+ }
6510
+ }
6511
+ path[i].type = object;
6512
+ property = object;
6513
+ union = false;
6514
+ }
6515
+ return property;
5956
6516
  }
5957
6517
 
5958
6518
 
@@ -5962,7 +6522,7 @@ function propagateTypes(state, func, graph, optimizeEquivalencies, logThisRun) {
5962
6522
  /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
5963
6523
 
5964
6524
  "use strict";
5965
- /* unused harmony exports couldBe, couldBeWeak */
6525
+ /* unused harmony exports couldBeHelper, couldBe, couldBeWeak, couldBeShallow */
5966
6526
  /* harmony import */ var _api__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(6817);
5967
6527
  /* harmony import */ var _api__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_api__WEBPACK_IMPORTED_MODULE_0__);
5968
6528
  /* harmony import */ var _data_flow__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(8180);
@@ -5980,7 +6540,7 @@ function propagateTypes(state, func, graph, optimizeEquivalencies, logThisRun) {
5980
6540
  * This is symmetric, and a subtypeOf b, or b subtypeOf a implies
5981
6541
  * a couldBe b.
5982
6542
  */
5983
- function couldBe(a, b) {
6543
+ function couldBeHelper(a, b, shallow) {
5984
6544
  const common = a.type & b.type & ~262144 /* TypeTag.Typedef */;
5985
6545
  if (common) {
5986
6546
  if (a.value == null || b.value == null || a.value === b.value) {
@@ -6000,7 +6560,7 @@ function couldBe(a, b) {
6000
6560
  const bvalue = getUnionComponent(b, ac.type);
6001
6561
  if (bvalue == null ||
6002
6562
  ac.value === bvalue ||
6003
- couldBeValue({ type: ac.type, avalue: ac.value, bvalue })) {
6563
+ couldBeValue({ type: ac.type, avalue: ac.value, bvalue }, shallow)) {
6004
6564
  result = true;
6005
6565
  return false;
6006
6566
  }
@@ -6050,12 +6610,19 @@ function couldBe(a, b) {
6050
6610
  }
6051
6611
  return false;
6052
6612
  }
6613
+ function couldBe(a, b) {
6614
+ return couldBeHelper(a, b, false);
6615
+ }
6053
6616
  function couldBeWeak(a, b) {
6054
6617
  if (a.type === 0 /* TypeTag.Never */ || b.type === 0 /* TypeTag.Never */)
6055
6618
  return true;
6056
6619
  return couldBe(a, b);
6057
6620
  }
6058
- function couldBeValue(pair) {
6621
+ //
6622
+ function couldBeShallow(a, b) {
6623
+ return couldBeHelper(a, b, true);
6624
+ }
6625
+ function couldBeValue(pair, shallow) {
6059
6626
  switch (pair.type) {
6060
6627
  case 1 /* TypeTag.Null */:
6061
6628
  case 2 /* TypeTag.False */:
@@ -6071,10 +6638,11 @@ function couldBeValue(pair) {
6071
6638
  case 131072 /* TypeTag.Symbol */:
6072
6639
  return pair.avalue === pair.bvalue;
6073
6640
  case 512 /* TypeTag.Array */:
6074
- return couldBe(pair.avalue, pair.bvalue);
6641
+ return shallow || couldBe(pair.avalue, pair.bvalue);
6075
6642
  case 1024 /* TypeTag.Dictionary */: {
6076
- return (couldBe(pair.avalue.key, pair.bvalue.key) &&
6077
- couldBe(pair.avalue.value, pair.bvalue.value));
6643
+ return (shallow ||
6644
+ (couldBe(pair.avalue.key, pair.bvalue.key) &&
6645
+ couldBe(pair.avalue.value, pair.bvalue.value)));
6078
6646
  }
6079
6647
  case 2048 /* TypeTag.Method */: {
6080
6648
  return (pair.avalue.args.length === pair.bvalue.args.length &&
@@ -6100,7 +6668,7 @@ function couldBeValue(pair) {
6100
6668
  }
6101
6669
  case 32768 /* TypeTag.Object */: {
6102
6670
  return (couldBe(pair.avalue.klass, pair.bvalue.klass) &&
6103
- couldBeObj(pair.avalue.obj, pair.bvalue.obj));
6671
+ (shallow || couldBeObj(pair.avalue.obj, pair.bvalue.obj)));
6104
6672
  }
6105
6673
  case 65536 /* TypeTag.Enum */: {
6106
6674
  return (pair.avalue.enum === pair.bvalue.enum &&
@@ -6130,20 +6698,48 @@ function couldBeObj(a, b) {
6130
6698
 
6131
6699
  "use strict";
6132
6700
  /* unused harmony exports findDeadStores, eliminateDeadStores */
6133
- /* harmony import */ var _api__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(6817);
6134
- /* harmony import */ var _api__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_api__WEBPACK_IMPORTED_MODULE_0__);
6135
- /* harmony import */ var _ast__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(6652);
6136
- /* harmony import */ var _control_flow__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(5101);
6137
- /* harmony import */ var _data_flow__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(8180);
6138
- /* harmony import */ var _inliner__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(333);
6139
- /* harmony import */ var _type_flow_util__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(1638);
6701
+ /* harmony import */ var node_assert__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(4143);
6702
+ /* harmony import */ var node_assert__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(node_assert__WEBPACK_IMPORTED_MODULE_0__);
6703
+ /* harmony import */ var _api__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(6817);
6704
+ /* harmony import */ var _api__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(_api__WEBPACK_IMPORTED_MODULE_1__);
6705
+ /* harmony import */ var _ast__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(6652);
6706
+ /* harmony import */ var _control_flow__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(5101);
6707
+ /* harmony import */ var _data_flow__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(8180);
6708
+ /* 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);
6140
6710
 
6141
6711
 
6142
6712
 
6143
6713
 
6144
6714
 
6145
6715
 
6146
- function findDeadStores(func, graph, nodeEquivs, logThisRun) {
6716
+
6717
+ function cloneAnt(antMap) {
6718
+ const ant = new Map();
6719
+ antMap.forEach((s, k) => ant.set(k, new Set(s)));
6720
+ return ant;
6721
+ }
6722
+ function addAnt(antMap, decl, node) {
6723
+ assert(node.type === "Identifier");
6724
+ const ant = antMap.get(decl);
6725
+ if (!ant) {
6726
+ antMap.set(decl, new Set([node]));
6727
+ }
6728
+ else {
6729
+ ant.add(node);
6730
+ }
6731
+ }
6732
+ function cloneState(blockState) {
6733
+ const clone = { dead: new Set(blockState.dead) };
6734
+ if (blockState.anticipated) {
6735
+ clone.anticipated = cloneAnt(blockState.anticipated);
6736
+ }
6737
+ if (blockState.partiallyAnticipated) {
6738
+ clone.partiallyAnticipated = cloneAnt(blockState.partiallyAnticipated);
6739
+ }
6740
+ return clone;
6741
+ }
6742
+ function findDeadStores(func, graph, nodeEquivs, findCopyPropCandidates, logThisRun) {
6147
6743
  const order = getPostOrder(graph);
6148
6744
  order.forEach((block, i) => {
6149
6745
  block.order = i;
@@ -6151,13 +6747,62 @@ function findDeadStores(func, graph, nodeEquivs, logThisRun) {
6151
6747
  const blockStates = [];
6152
6748
  const nodeConflicts = nodeEquivs && new Map();
6153
6749
  const mergeStates = (to, from) => {
6154
- return Array.from(to).reduce((changed, decl) => {
6155
- if (!from.has(decl)) {
6156
- to.delete(decl);
6750
+ let changed = Array.from(to.dead).reduce((changed, decl) => {
6751
+ if (!from.dead.has(decl)) {
6752
+ to.dead.delete(decl);
6157
6753
  changed = true;
6158
6754
  }
6159
6755
  return changed;
6160
6756
  }, false);
6757
+ if (to.anticipated) {
6758
+ if (!from.anticipated) {
6759
+ delete to.anticipated;
6760
+ changed = true;
6761
+ }
6762
+ else {
6763
+ changed = Array.from(to.anticipated).reduce((changed, [decl, toant]) => {
6764
+ const fromant = from.anticipated.get(decl);
6765
+ if (!fromant) {
6766
+ to.anticipated.delete(decl);
6767
+ changed = true;
6768
+ }
6769
+ else {
6770
+ toant.forEach((node) => {
6771
+ if (!fromant.has(node)) {
6772
+ toant.delete(node);
6773
+ changed = true;
6774
+ }
6775
+ });
6776
+ }
6777
+ return changed;
6778
+ }, changed);
6779
+ }
6780
+ }
6781
+ if (from.partiallyAnticipated) {
6782
+ if (!to.partiallyAnticipated) {
6783
+ to.partiallyAnticipated = cloneAnt(from.partiallyAnticipated);
6784
+ changed = true;
6785
+ }
6786
+ else {
6787
+ changed = Array.from(from.partiallyAnticipated).reduce((changed, [decl, fromant]) => {
6788
+ const toant = to.partiallyAnticipated.get(decl);
6789
+ if (!toant) {
6790
+ to.partiallyAnticipated.set(decl, fromant);
6791
+ changed = true;
6792
+ }
6793
+ else {
6794
+ fromant.forEach((node) => {
6795
+ if (!toant.has(node)) {
6796
+ changed = true;
6797
+ toant.add(node);
6798
+ }
6799
+ });
6800
+ }
6801
+ return changed;
6802
+ }, changed);
6803
+ }
6804
+ }
6805
+ return changed;
6161
6806
  };
6162
6807
  const queue = new DataflowQueue();
6163
6808
  const locals = new Set(order
@@ -6168,10 +6813,11 @@ function findDeadStores(func, graph, nodeEquivs, logThisRun) {
6168
6813
  : [])
6169
6814
  .concat(func.node.params));
6170
6815
  const deadStores = new Set();
6816
+ const copyPropStores = new Map();
6171
6817
  order.forEach((block) => {
6172
6818
  if (!block.succs) {
6173
6819
  queue.enqueue(block);
6174
- blockStates[block.order] = new Set(locals);
6820
+ blockStates[block.order] = { dead: new Set(locals) };
6175
6821
  }
6176
6822
  });
6177
6823
  while (!queue.empty()) {
@@ -6182,10 +6828,10 @@ function findDeadStores(func, graph, nodeEquivs, logThisRun) {
6182
6828
  if (!blockStates[top.order]) {
6183
6829
  throw new Error(`Block ${top.order || 0} had no state!`);
6184
6830
  }
6185
- const curState = new Set(blockStates[top.order]);
6831
+ const curState = cloneState(blockStates[top.order]);
6186
6832
  if (logThisRun) {
6187
6833
  printBlockHeader(top);
6188
- curState.forEach((decl) => console.log(` - anticipated: ${tsKey(decl)}`));
6834
+ curState.dead.forEach((decl) => console.log(` - anticipated: ${tsKey(decl)}`));
6189
6835
  }
6190
6836
  if (top.events) {
6191
6837
  for (let i = top.events.length; i--;) {
@@ -6200,33 +6846,67 @@ function findDeadStores(func, graph, nodeEquivs, logThisRun) {
6200
6846
  switch (event.type) {
6201
6847
  case "ref":
6202
6848
  if (isTypeStateKey(event.decl)) {
6203
- curState.delete(event.decl);
6204
6849
  if (logThisRun) {
6850
+ console.log(describeEvent(event));
6205
6851
  console.log(` kill => ${tsKey(event.decl)}`);
6206
6852
  }
6853
+ if (findCopyPropCandidates && declIsLocal(event.decl)) {
6854
+ if (!curState.anticipated) {
6855
+ curState.anticipated = new Map();
6856
+ }
6857
+ addAnt(curState.anticipated, event.decl, event.node);
6858
+ if (!curState.partiallyAnticipated) {
6859
+ curState.partiallyAnticipated = new Map();
6860
+ }
6861
+ addAnt(curState.partiallyAnticipated, event.decl, event.node);
6862
+ if (logThisRun) {
6863
+ console.log(` antrefs: ${curState.partiallyAnticipated.get(event.decl)?.size ?? 0} ${curState.anticipated.get(event.decl)?.size ?? 0}`);
6864
+ }
6865
+ }
6866
+ curState.dead.delete(event.decl);
6207
6867
  }
6208
6868
  break;
6209
6869
  case "def":
6210
6870
  if (isTypeStateKey(event.decl) &&
6211
6871
  (event.node.type !== "VariableDeclarator" || event.node.init)) {
6212
- if (curState.has(event.decl)) {
6872
+ if (logThisRun) {
6873
+ console.log(describeEvent(event));
6874
+ }
6875
+ const assignNode = (event.node.type === "AssignmentExpression" &&
6876
+ event.node.operator === "=" &&
6877
+ event.node.right) ||
6878
+ (event.node.type === "VariableDeclarator" && event.node.init);
6879
+ if (curState.dead.has(event.decl)) {
6213
6880
  deadStores.add(event.node);
6214
6881
  }
6215
6882
  else {
6216
6883
  deadStores.delete(event.node);
6884
+ if (assignNode &&
6885
+ declIsLocal(event.decl) &&
6886
+ curState.partiallyAnticipated) {
6887
+ const pant = curState.partiallyAnticipated.get(event.decl);
6888
+ if (pant && pant.size === 1) {
6889
+ if (logThisRun) {
6890
+ console.log(` is copy-prop-candidate ${curState.anticipated?.get(event.decl)?.size ?? 0}`);
6891
+ }
6892
+ copyPropStores.set(event.node, {
6893
+ ref: Array.from(pant)[0],
6894
+ ant: curState.anticipated?.get(event.decl)?.size === 1,
6895
+ });
6896
+ }
6897
+ curState.partiallyAnticipated.delete(event.decl);
6898
+ curState.anticipated?.delete(event.decl);
6899
+ }
6900
+ else {
6901
+ copyPropStores.delete(event.node);
6902
+ }
6217
6903
  }
6218
6904
  if (nodeConflicts) {
6219
6905
  const conflicts = new Set(locals);
6220
- curState.forEach((dead) => conflicts.delete(dead));
6906
+ curState.dead.forEach((dead) => conflicts.delete(dead));
6221
6907
  if (event.rhs) {
6222
6908
  conflicts.delete(event.rhs);
6223
- const equiv = event.node.type === "AssignmentExpression" &&
6224
- event.node.operator === "="
6225
- ? nodeEquivs.get(event.node.right)
6226
- : event.node.type === "VariableDeclarator" &&
6227
- event.node.init
6228
- ? nodeEquivs.get(event.node.init)
6229
- : null;
6909
+ const equiv = assignNode && nodeEquivs.get(assignNode);
6230
6910
  if (equiv) {
6231
6911
  equiv.equiv.forEach((e) => isTypeStateKey(e) && conflicts.delete(e));
6232
6912
  isTypeStateKey(equiv.decl) && conflicts.delete(equiv.decl);
@@ -6235,10 +6915,8 @@ function findDeadStores(func, graph, nodeEquivs, logThisRun) {
6235
6915
  conflicts.add(event.decl);
6236
6916
  nodeConflicts.set(event.node, conflicts);
6237
6917
  }
6238
- if ((event.node.type === "AssignmentExpression" &&
6239
- event.node.operator === "=") ||
6240
- (event.node.type === "VariableDeclarator" && event.node.init)) {
6241
- curState.add(event.decl);
6918
+ if (assignNode) {
6919
+ curState.dead.add(event.decl);
6242
6920
  if (logThisRun) {
6243
6921
  console.log(` anticipated => ${tsKey(event.decl)}`);
6244
6922
  }
@@ -6247,14 +6925,14 @@ function findDeadStores(func, graph, nodeEquivs, logThisRun) {
6247
6925
  break;
6248
6926
  case "kil":
6249
6927
  if (isTypeStateKey(event.decl)) {
6250
- curState.add(event.decl);
6928
+ curState.dead.add(event.decl);
6251
6929
  if (logThisRun) {
6252
6930
  console.log(` anticipated => ${tsKey(event.decl)}`);
6253
6931
  }
6254
6932
  }
6255
6933
  break;
6256
6934
  case "mod":
6257
- curState.forEach((decl) => declIsLocal(decl) || curState.delete(decl));
6935
+ curState.dead.forEach((decl) => declIsLocal(decl) || curState.dead.delete(decl));
6258
6936
  break;
6259
6937
  case "flw":
6260
6938
  break;
@@ -6264,7 +6942,7 @@ function findDeadStores(func, graph, nodeEquivs, logThisRun) {
6264
6942
  const doMerge = (pred) => {
6265
6943
  const pi = pred.order || 0;
6266
6944
  if (!blockStates[pi]) {
6267
- blockStates[pi] = new Set(curState);
6945
+ blockStates[pi] = cloneState(curState);
6268
6946
  queue.enqueue(pred);
6269
6947
  }
6270
6948
  else if (mergeStates(blockStates[pi], curState)) {
@@ -6296,15 +6974,18 @@ function findDeadStores(func, graph, nodeEquivs, logThisRun) {
6296
6974
  nodeConflicts.forEach((conflicts) => conflicts.forEach((conflict) => addConflicts(conflict, conflicts)));
6297
6975
  func.node.params.forEach((param, index, arr) => addConflicts(param, arr));
6298
6976
  }
6299
- return { deadStores, locals, localConflicts };
6977
+ return { deadStores, locals, localConflicts, copyPropStores };
6300
6978
  }
6301
6979
  function eliminateDeadStores(state, func, graph, logThisRun) {
6302
- const { deadStores } = findDeadStores(func, graph, null, logThisRun);
6980
+ const { deadStores, copyPropStores } = findDeadStores(func, graph, null, state.config?.singleUseCopyProp ?? true, logThisRun);
6303
6981
  if (!deadStores.size)
6304
- return false;
6982
+ return { changes: false, copyPropStores };
6305
6983
  if (logThisRun) {
6306
6984
  console.log("====== Dead Stores =====");
6307
- deadStores.forEach((dead) => console.log(`${formatAst(dead)} (${sourceLocation(dead.loc)})`));
6985
+ deadStores.forEach((dead) => (dead.type === "AssignmentExpression" ||
6986
+ dead.type === "UpdateExpression" ||
6987
+ dead.type === "VariableDeclarator") &&
6988
+ console.log(`${formatAst(dead)} (${sourceLocation(dead.loc)})`));
6308
6989
  }
6309
6990
  let changes = false;
6310
6991
  traverseAst(func.node.body, null, (node, parent) => {
@@ -6367,7 +7048,7 @@ function eliminateDeadStores(state, func, graph, logThisRun) {
6367
7048
  }
6368
7049
  return null;
6369
7050
  });
6370
- return changes;
7051
+ return { copyPropStores, changes };
6371
7052
  }
6372
7053
 
6373
7054
 
@@ -6378,9 +7059,13 @@ function eliminateDeadStores(state, func, graph, logThisRun) {
6378
7059
 
6379
7060
  "use strict";
6380
7061
  /* unused harmony exports evaluateBinaryTypes, evaluateLogicalTypes */
6381
- /* harmony import */ var _interp__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(7161);
6382
- /* harmony import */ var _types__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(7255);
6383
- /* harmony import */ var _union_type__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(757);
7062
+ /* harmony import */ var _could_be__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(4055);
7063
+ /* harmony import */ var _interp__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(7161);
7064
+ /* harmony import */ var _sub_type__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(9234);
7065
+ /* harmony import */ var _types__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(7255);
7066
+ /* harmony import */ var _union_type__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(757);
7067
+
7068
+
6384
7069
 
6385
7070
 
6386
7071
 
@@ -6711,14 +7396,6 @@ function evaluateBinaryTypes(op, left, right) {
6711
7396
  : 2 /* TypeTag.False */,
6712
7397
  }),
6713
7398
  },
6714
- instanceof: {
6715
- allowed: 524287 /* TypeTag.Any */,
6716
- typeFn: () => ({
6717
- tag: 6 /* TypeTag.Boolean */,
6718
- castArgs: false,
6719
- }),
6720
- valueFn: (_left, _right) => undefined,
6721
- },
6722
7399
  has: {
6723
7400
  allowed: 524287 /* TypeTag.Any */,
6724
7401
  typeFn: () => ({
@@ -6729,6 +7406,21 @@ function evaluateBinaryTypes(op, left, right) {
6729
7406
  },
6730
7407
  };
6731
7408
  }
7409
+ if (op === "instanceof") {
7410
+ if (right.type & 16384 /* TypeTag.Class */) {
7411
+ if (!isExact(right)) {
7412
+ return { type: 6 /* TypeTag.Boolean */ };
7413
+ }
7414
+ right = { type: 32768 /* TypeTag.Object */, value: { klass: right } };
7415
+ }
7416
+ return {
7417
+ type: subtypeOf(left, right)
7418
+ ? 4 /* TypeTag.True */
7419
+ : !couldBeWeak(left, right)
7420
+ ? 2 /* TypeTag.False */
7421
+ : 6 /* TypeTag.Boolean */,
7422
+ };
7423
+ }
6732
7424
  const info = operators[op];
6733
7425
  if (!info)
6734
7426
  return { type: 524287 /* TypeTag.Any */ };
@@ -6787,15 +7479,15 @@ function evaluateLogicalTypes(op, left, right) {
6787
7479
  "use strict";
6788
7480
  /* unused harmony exports evaluateCall, checkCallArgs, sysCallInfo */
6789
7481
  /* harmony import */ var _optimizer_types__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(9697);
6790
- /* harmony import */ var _type_flow__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(4859);
6791
- /* harmony import */ var _api__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(6817);
6792
- /* harmony import */ var _api__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(_api__WEBPACK_IMPORTED_MODULE_2__);
6793
- /* harmony import */ var _util__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(6906);
6794
- /* harmony import */ var _util__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__webpack_require__.n(_util__WEBPACK_IMPORTED_MODULE_3__);
6795
- /* harmony import */ var _interp__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(7161);
6796
- /* harmony import */ var _sub_type__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(9234);
6797
- /* harmony import */ var _types__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(7255);
6798
- /* harmony import */ var _union_type__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(757);
7482
+ /* harmony import */ var _api__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(6817);
7483
+ /* harmony import */ var _api__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(_api__WEBPACK_IMPORTED_MODULE_1__);
7484
+ /* harmony import */ var _util__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(6906);
7485
+ /* harmony import */ var _util__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(_util__WEBPACK_IMPORTED_MODULE_2__);
7486
+ /* harmony import */ var _interp__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(7161);
7487
+ /* harmony import */ var _sub_type__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(9234);
7488
+ /* harmony import */ var _types__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(7255);
7489
+ /* harmony import */ var _union_type__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(757);
7490
+ /* harmony import */ var _type_flow_util__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(1638);
6799
7491
 
6800
7492
 
6801
7493
 
@@ -6851,7 +7543,7 @@ function checkCallArgs(istate, node, callees, args) {
6851
7543
  let argEffects = true;
6852
7544
  const object = calleeObjectType(istate, node.callee);
6853
7545
  if (object) {
6854
- const info = sysCallInfo(cur);
7546
+ const info = sysCallInfo(istate.state, cur);
6855
7547
  if (info) {
6856
7548
  const result = info(istate.state, cur, object, () => args);
6857
7549
  if (result.argTypes)
@@ -6982,16 +7674,18 @@ function isOverride(cur, funcs) {
6982
7674
  return false;
6983
7675
  }
6984
7676
  let systemCallInfo = null;
6985
- function sysCallInfo(func) {
6986
- const info = getSystemCallTable();
7677
+ let systemCallVersion;
7678
+ function sysCallInfo(state, func) {
7679
+ const info = getSystemCallTable(state);
6987
7680
  if (hasProperty(info, func.fullName)) {
6988
7681
  return info[func.fullName];
6989
7682
  }
6990
7683
  return null;
6991
7684
  }
6992
- function getSystemCallTable() {
6993
- if (systemCallInfo)
7685
+ function getSystemCallTable(state) {
7686
+ if (systemCallInfo && systemCallVersion === state.sdk) {
6994
7687
  return systemCallInfo;
7688
+ }
6995
7689
  const arrayAdd = (state, callee, calleeObj, getArgs) => {
6996
7690
  const ret = {};
6997
7691
  if (calleeObj.type & 512 /* TypeTag.Array */) {
@@ -7211,7 +7905,8 @@ function getSystemCallTable() {
7211
7905
  }
7212
7906
  return results;
7213
7907
  };
7214
- return (systemCallInfo = {
7908
+ systemCallVersion = state.sdk;
7909
+ return (systemCallInfo = expandKeys(state, {
7215
7910
  "$.Toybox.Lang.Array.add": arrayAdd,
7216
7911
  "$.Toybox.Lang.Array.addAll": arrayAdd,
7217
7912
  "$.Toybox.Lang.Array.remove": mod,
@@ -7254,7 +7949,47 @@ function getSystemCallTable() {
7254
7949
  "$.Toybox.Math.variance": nop,
7255
7950
  "$.Toybox.Math.srand": mod,
7256
7951
  "$.Toybox.Math.rand": mod,
7952
+ "$.Toybox.Lang.*.(to*|equals|abs)": nop,
7953
+ "$.Toybox.Time.Gregorian.(duration|info|localMoment|moment|utcInfo)": nop,
7954
+ "$.Toybox.Time.(Duration|LocalMoment|Moment).(?!initialize)*": nop,
7955
+ "$.Toybox.Graphics.Dc.get*": nop,
7956
+ }));
7957
+ }
7958
+ function expandKeys(state, table) {
7959
+ const result = {};
7960
+ const pattern = /[*()|]/;
7961
+ Object.entries(table).forEach(([key, value]) => {
7962
+ if (!pattern.test(key)) {
7963
+ result[key] = value;
7964
+ return;
7965
+ }
7966
+ if (state.stack) {
7967
+ const decls = key
7968
+ .split(".")
7969
+ .slice(1)
7970
+ .reduce((decls, decl) => {
7971
+ if (pattern.test(decl)) {
7972
+ const re = new RegExp(`^${decl.replace(/\*/g, ".*")}$`);
7973
+ return decls.flatMap((sn) => isStateNode(sn) && sn.decls
7974
+ ? Object.keys(sn.decls)
7975
+ .filter((m) => re.test(m))
7976
+ .flatMap((m) => sn.decls[m])
7977
+ : []);
7978
+ }
7979
+ else {
7980
+ return decls.flatMap((sn) => (isStateNode(sn) && sn.decls?.[decl]) || []);
7981
+ }
7982
+ }, [state.stack[0].sn]);
7983
+ decls.forEach((decl) => {
7984
+ if (decl.type === "FunctionDeclaration") {
7985
+ if (!hasProperty(result, decl.fullName)) {
7986
+ result[decl.fullName] = value;
7987
+ }
7988
+ }
7989
+ });
7990
+ }
7257
7991
  });
7992
+ return result;
7258
7993
  }
7259
7994
 
7260
7995
 
@@ -7270,11 +8005,11 @@ function getSystemCallTable() {
7270
8005
  /* harmony import */ var _ast__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(6652);
7271
8006
  /* harmony import */ var _data_flow__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(8180);
7272
8007
  /* harmony import */ var _optimizer_types__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(9697);
7273
- /* harmony import */ var _type_flow__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(4859);
7274
- /* harmony import */ var _could_be__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(4055);
7275
- /* harmony import */ var _interp_binary__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(4706);
7276
- /* harmony import */ var _interp_call__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(2222);
7277
- /* harmony import */ var _sub_type__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(9234);
8008
+ /* harmony import */ var _could_be__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(4055);
8009
+ /* harmony import */ var _interp_binary__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(4706);
8010
+ /* harmony import */ var _interp_call__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(2222);
8011
+ /* harmony import */ var _sub_type__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(9234);
8012
+ /* harmony import */ var _type_flow_util__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(1638);
7278
8013
  /* harmony import */ var _types__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(7255);
7279
8014
  /* harmony import */ var _union_type__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(757);
7280
8015
 
@@ -8610,12 +9345,14 @@ function restrictByEquality(a, b) {
8610
9345
  /* unused harmony export minimizeLocals */
8611
9346
  /* harmony import */ var node_assert__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(4143);
8612
9347
  /* harmony import */ var node_assert__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(node_assert__WEBPACK_IMPORTED_MODULE_0__);
8613
- /* harmony import */ var _control_flow__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(5101);
8614
- /* harmony import */ var _api__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(6817);
8615
- /* harmony import */ var _api__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(_api__WEBPACK_IMPORTED_MODULE_2__);
8616
- /* harmony import */ var _ast__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(6652);
9348
+ /* harmony import */ var _api__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(6817);
9349
+ /* harmony import */ var _api__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(_api__WEBPACK_IMPORTED_MODULE_1__);
9350
+ /* harmony import */ var _ast__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(6652);
9351
+ /* harmony import */ var _control_flow__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(5101);
8617
9352
  /* harmony import */ var _type_flow__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(4859);
8618
- /* harmony import */ var _type_flow_util__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(1638);
9353
+ /* harmony import */ var _variable_renamer__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(4405);
9354
+ /* harmony import */ var _type_flow_util__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(1638);
9355
+
8619
9356
 
8620
9357
 
8621
9358
 
@@ -8763,8 +9500,7 @@ function minimizeLocals(state, func) {
8763
9500
  switch (node.type) {
8764
9501
  case "Identifier":
8765
9502
  if (info && info.name !== node.name) {
8766
- node.original = node.name;
8767
- node.name = info.name;
9503
+ renameIdentifier(node, info.name);
8768
9504
  }
8769
9505
  return null;
8770
9506
  case "AssignmentExpression":
@@ -8775,8 +9511,7 @@ function minimizeLocals(state, func) {
8775
9511
  return withLoc({ type: "Literal", value: null, raw: "null" }, node, node);
8776
9512
  }
8777
9513
  if (node.left.name !== info.name) {
8778
- node.left.original = node.left.name;
8779
- node.left.name = info.name;
9514
+ renameIdentifier(node.left, info.name);
8780
9515
  }
8781
9516
  return null;
8782
9517
  }
@@ -8790,8 +9525,7 @@ function minimizeLocals(state, func) {
8790
9525
  if (info) {
8791
9526
  assert(node.argument.type === "Identifier");
8792
9527
  if (node.argument.name !== info.name) {
8793
- node.argument.original = node.argument.name;
8794
- node.argument.name = info.name;
9528
+ renameIdentifier(node.argument, info.name);
8795
9529
  }
8796
9530
  return null;
8797
9531
  }
@@ -8934,6 +9668,24 @@ function optimizeFunction(state, func) {
8934
9668
  }
8935
9669
  function beforeEvaluate(istate, node) {
8936
9670
  switch (node.type) {
9671
+ case "ExpressionStatement": {
9672
+ if (node.expression.type !== "Literal") {
9673
+ const expression = popIstate(istate, node.expression);
9674
+ if (expression.embeddedEffects) {
9675
+ istate.stack.push(expression);
9676
+ }
9677
+ else {
9678
+ const rep = withLoc({ type: "Literal", value: null, raw: "null" }, node, node);
9679
+ istate.stack.push({
9680
+ value: { type: 1 /* TypeTag.Null */ },
9681
+ embeddedEffects: false,
9682
+ node: rep,
9683
+ });
9684
+ node.expression = rep;
9685
+ }
9686
+ }
9687
+ break;
9688
+ }
8937
9689
  case "ConditionalExpression": {
8938
9690
  let alternate = tryPop(istate, node.alternate);
8939
9691
  let consequent = tryPop(istate, node.consequent);
@@ -9679,12 +10431,23 @@ function subtypeOfObj(a, b) {
9679
10431
  /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
9680
10432
 
9681
10433
  "use strict";
9682
- /* unused harmony exports isTypeStateKey, declIsLocal, localDeclName, tsKey, sourceLocation, printBlockHeader, describeEvent, printBlockEvents, printBlockTrailer */
10434
+ /* harmony export */ __webpack_require__.d(__webpack_exports__, {
10435
+ /* harmony export */ "nK": () => (/* binding */ findObjectDeclsByProperty)
10436
+ /* harmony export */ });
10437
+ /* unused harmony exports isTypeStateKey, declIsLocal, declIsNonLocal, localDeclName, tsKey, sourceLocation, printBlockHeader, describeEvent, printBlockEvents, printBlockTrailer, refineObjectTypeByDecls, findNextObjectType, resolveDottedMember */
9683
10438
  /* harmony import */ var _api__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(6817);
9684
10439
  /* harmony import */ var _api__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_api__WEBPACK_IMPORTED_MODULE_0__);
9685
10440
  /* harmony import */ var _data_flow__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(8180);
9686
10441
  /* harmony import */ var _util__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(6906);
9687
10442
  /* harmony import */ var _util__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(_util__WEBPACK_IMPORTED_MODULE_2__);
10443
+ /* harmony import */ var _intersection_type__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(6973);
10444
+ /* harmony import */ var _sub_type__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(9234);
10445
+ /* harmony import */ var _types__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(7255);
10446
+ /* harmony import */ var _union_type__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(757);
10447
+
10448
+
10449
+
10450
+
9688
10451
 
9689
10452
 
9690
10453
 
@@ -9697,6 +10460,9 @@ function declIsLocal(decl) {
9697
10460
  d.type === "Identifier" ||
9698
10461
  (d.type === "VariableDeclarator" && isLocal(d)));
9699
10462
  }
10463
+ function declIsNonLocal(decl) {
10464
+ return some(decl, (d) => d.type === "VariableDeclarator" && !isLocal(d));
10465
+ }
9700
10466
  function localDeclName(decl) {
9701
10467
  if (Array.isArray(decl))
9702
10468
  decl = decl[0];
@@ -9761,6 +10527,140 @@ function printBlockTrailer(block) {
9761
10527
  .map((block) => block.order)
9762
10528
  .join(", ")} ExSucc: ${block.exsucc ? block.exsucc.order : ""}`);
9763
10529
  }
10530
+ /*
10531
+ * We have an object, and a MemberExpression object.<name>
10532
+ * - decls are the StateNodes associated with the known type
10533
+ * of object.
10534
+ * - possible are all the StateNodes that declare <name>
10535
+ *
10536
+ * We want to find all the elements of possible which are
10537
+ * "compatible" with decls, which tells us the set of things
10538
+ * that object.<name> could correspond to, and also what that
10539
+ * tells us about object.
10540
+ *
10541
+ * The return value is two arrays of StateNode. The first
10542
+ * gives the refined type of object, and the second is the
10543
+ * array of StateNodes that could declare <name>
10544
+ */
10545
+ function filterDecls(decls, possible, name) {
10546
+ if (!possible)
10547
+ return [null, null];
10548
+ const result = decls.reduce((cur, decl) => {
10549
+ const found = possible.reduce((flag, poss) => {
10550
+ if (decl === poss ||
10551
+ (poss.type === "ClassDeclaration" && (0,_api__WEBPACK_IMPORTED_MODULE_0__.getSuperClasses)(poss)?.has(decl))) {
10552
+ // poss extends decl, so decl must actually be a poss
10553
+ // eg we know obj is an Object, and we call obj.toNumber
10554
+ // so possible includes all the classes that declare toNumber
10555
+ // so we can refine obj's type to the union of those types
10556
+ if (!cur[0]) {
10557
+ cur = [new Set(), new Set()];
10558
+ }
10559
+ cur[0].add(poss);
10560
+ cur[1].add(poss);
10561
+ return true;
10562
+ }
10563
+ else if (decl.type === "ClassDeclaration" &&
10564
+ (0,_api__WEBPACK_IMPORTED_MODULE_0__.getSuperClasses)(decl)?.has(poss)) {
10565
+ // decl extends poss, so decl remains unchanged
10566
+ // eg we know obj is Menu2, we call obj.toString
10567
+ // Menu2 doesn't define toString, but Object does
10568
+ // so poss is Object. But we still know that
10569
+ // obj is Menu2
10570
+ if (!cur[0]) {
10571
+ cur = [new Set(), new Set()];
10572
+ }
10573
+ cur[0].add(decl);
10574
+ cur[1].add(poss);
10575
+ return true;
10576
+ }
10577
+ return flag;
10578
+ }, false);
10579
+ if (!found) {
10580
+ // If we didn't find the property in any of the
10581
+ // standard places, the runtime might still find
10582
+ // it by searching up the Module stack (and up
10583
+ // the module stack from any super classes)
10584
+ //
10585
+ // eg
10586
+ //
10587
+ // obj = Application.getApp();
10588
+ // obj.Properties.whatever
10589
+ //
10590
+ // Properties doesn't exist on AppBase, but AppBase
10591
+ // is declared in Application, and Application
10592
+ // does declare Properties. So Application.Properties
10593
+ // is (one of) the declarations we should find; but we
10594
+ // must not refine obj's type to include Application.
10595
+ let d = [decl];
10596
+ do {
10597
+ d.forEach((d) => {
10598
+ const stack = d.stack;
10599
+ possible.forEach((poss) => {
10600
+ for (let i = stack.length; i--;) {
10601
+ const sn = stack[i].sn;
10602
+ if (sn.decls === poss.decls) {
10603
+ if (!cur[0]) {
10604
+ cur = [new Set(), new Set()];
10605
+ }
10606
+ cur[0].add(decl);
10607
+ cur[1].add(poss);
10608
+ break;
10609
+ }
10610
+ if ((0,_api__WEBPACK_IMPORTED_MODULE_0__.hasProperty)(sn.decls, name)) {
10611
+ break;
10612
+ }
10613
+ }
10614
+ });
10615
+ });
10616
+ d = d.flatMap((d) => {
10617
+ if (d.type !== "ClassDeclaration" ||
10618
+ !d.superClass ||
10619
+ d.superClass === true) {
10620
+ return [];
10621
+ }
10622
+ return d.superClass;
10623
+ });
10624
+ } while (d.length);
10625
+ }
10626
+ return cur;
10627
+ }, [null, null]);
10628
+ if (!result[0])
10629
+ return [null, null];
10630
+ return [Array.from(result[0]), Array.from(result[1])];
10631
+ }
10632
+ function findObjectDeclsByProperty(state, object, next) {
10633
+ const decls = (0,_types__WEBPACK_IMPORTED_MODULE_5__/* .getStateNodeDeclsFromType */ .iX)(state, object);
10634
+ if (!decls)
10635
+ return [null, null];
10636
+ const possibleDecls = (0,_api__WEBPACK_IMPORTED_MODULE_0__.hasProperty)(state.allDeclarations, next.property.name) &&
10637
+ state.allDeclarations[next.property.name];
10638
+ return filterDecls(decls, possibleDecls, next.property.name);
10639
+ }
10640
+ function refineObjectTypeByDecls(istate, object, trueDecls) {
10641
+ const refinedType = typeFromTypeStateNodes(istate.state, trueDecls);
10642
+ return intersection(object, refinedType);
10643
+ }
10644
+ function findNextObjectType(istate, trueDecls, next) {
10645
+ const results = lookupNext(istate.state, [{ parent: null, results: trueDecls }], "decls", next.property);
10646
+ if (!results)
10647
+ return null;
10648
+ return results.reduce((cur, lookupDefn) => {
10649
+ unionInto(cur, typeFromTypeStateNodes(istate.state, lookupDefn.results));
10650
+ return cur;
10651
+ }, { type: 0 /* TypeTag.Never */ });
10652
+ }
10653
+ function resolveDottedMember(istate, object, next) {
10654
+ const [objDecls, trueDecls] = findObjectDeclsByProperty(istate.state, object, next);
10655
+ if (!objDecls)
10656
+ return null;
10657
+ const property = findNextObjectType(istate, trueDecls, next);
10658
+ if (!property)
10659
+ return null;
10660
+ const type = refineObjectTypeByDecls(istate, object, objDecls);
10661
+ const mayThrow = !subtypeOf(object, type);
10662
+ return { mayThrow, object: type, property };
10663
+ }
9764
10664
 
9765
10665
 
9766
10666
  /***/ }),
@@ -11025,6 +11925,23 @@ function cleanupUnusedVars(state, node) {
11025
11925
  return false;
11026
11926
  const varDeclarations = new Map();
11027
11927
  const stack = [];
11928
+ /*
11929
+ * Every local mentioned in toRemove can be removed, but
11930
+ * occurances of the identifier prior to its declaration
11931
+ * must be non-local. So reconstruct the toRemove record
11932
+ * as we go. This is to prevent issues with something like
11933
+ *
11934
+ * var g = 0;
11935
+ * function foo(var h) {
11936
+ * // if we just consult toRemove, we'll remove this assignment
11937
+ * g = h * 2;
11938
+ * var x = g;
11939
+ * ...
11940
+ * // *This* g is unused, and "g" gets added to activeRemove here.
11941
+ * var g = 42;
11942
+ * }
11943
+ */
11944
+ const activeRemove = {};
11028
11945
  let changes = false;
11029
11946
  traverseAst(node, (node) => {
11030
11947
  switch (node.type) {
@@ -11045,6 +11962,7 @@ function cleanupUnusedVars(state, node) {
11045
11962
  node.declarations.forEach((decl, i) => {
11046
11963
  const name = variableDeclarationName(decl.id);
11047
11964
  if (hasProperty(toRemove, name)) {
11965
+ activeRemove[name] = toRemove[name];
11048
11966
  const info = varDeclarations.get(node);
11049
11967
  if (info) {
11050
11968
  info.indices.push(i);
@@ -11062,14 +11980,14 @@ function cleanupUnusedVars(state, node) {
11062
11980
  case "ExpressionStatement":
11063
11981
  if (node.expression.type === "AssignmentExpression") {
11064
11982
  if (node.expression.left.type === "Identifier" &&
11065
- hasProperty(toRemove, node.expression.left.name)) {
11983
+ hasProperty(activeRemove, node.expression.left.name)) {
11066
11984
  changes = true;
11067
11985
  return unused(state, node.expression.right);
11068
11986
  }
11069
11987
  }
11070
11988
  else if (node.expression.type === "UpdateExpression" &&
11071
11989
  node.expression.argument.type === "Identifier" &&
11072
- hasProperty(toRemove, node.expression.argument.name)) {
11990
+ hasProperty(activeRemove, node.expression.argument.name)) {
11073
11991
  return false;
11074
11992
  }
11075
11993
  break;
@@ -11078,7 +11996,7 @@ function cleanupUnusedVars(state, node) {
11078
11996
  const expr = node.expressions[i];
11079
11997
  if (expr.type === "AssignmentExpression") {
11080
11998
  if (expr.left.type === "Identifier" &&
11081
- hasProperty(toRemove, expr.left.name)) {
11999
+ hasProperty(activeRemove, expr.left.name)) {
11082
12000
  const rep = unused(state, expr.right);
11083
12001
  if (!rep.length) {
11084
12002
  changes = true;
@@ -11087,14 +12005,14 @@ function cleanupUnusedVars(state, node) {
11087
12005
  else {
11088
12006
  // Sequence expressions can only be assignments
11089
12007
  // or update expressions. Even calls aren't allowed
11090
- toRemove[expr.left.name] = null;
12008
+ activeRemove[expr.left.name] = null;
11091
12009
  expr.operator = "=";
11092
12010
  }
11093
12011
  }
11094
12012
  }
11095
12013
  else if (expr.type === "UpdateExpression" &&
11096
12014
  expr.argument.type === "Identifier" &&
11097
- hasProperty(toRemove, expr.argument.name)) {
12015
+ hasProperty(activeRemove, expr.argument.name)) {
11098
12016
  changes = true;
11099
12017
  node.expressions.splice(i, 1);
11100
12018
  }
@@ -11110,7 +12028,7 @@ function cleanupUnusedVars(state, node) {
11110
12028
  const i = info.indices[ii];
11111
12029
  const vdecl = decl.declarations[i];
11112
12030
  const name = variableDeclarationName(vdecl.id);
11113
- if (hasProperty(toRemove, name)) {
12031
+ if (hasProperty(activeRemove, name)) {
11114
12032
  const rep = vdecl.init ? unused(state, vdecl.init) : [];
11115
12033
  if (rep.length) {
11116
12034
  if ((state.sdkVersion || 0) < 4001007 &&
@@ -11155,7 +12073,7 @@ function cleanupUnusedVars(state, node) {
11155
12073
  j = i;
11156
12074
  continue;
11157
12075
  }
11158
- if (toRemove[name]) {
12076
+ if (activeRemove[name]) {
11159
12077
  changes = true;
11160
12078
  j--;
11161
12079
  decl.declarations.splice(i, 1);
@@ -11180,12 +12098,18 @@ function cleanupUnusedVars(state, node) {
11180
12098
  /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
11181
12099
 
11182
12100
  "use strict";
11183
- /* unused harmony export renameVariable */
12101
+ /* unused harmony exports renameIdentifier, renameVariable */
11184
12102
  /* harmony import */ var _api__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(6817);
11185
12103
  /* harmony import */ var _api__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_api__WEBPACK_IMPORTED_MODULE_0__);
11186
12104
  /* harmony import */ var _ast__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(6652);
11187
12105
 
11188
12106
 
12107
+ function renameIdentifier(ident, newName) {
12108
+ if (!ident.original) {
12109
+ ident.original = ident.name;
12110
+ }
12111
+ ident.name = newName;
12112
+ }
11189
12113
  function renameVariable(state, locals, declName) {
11190
12114
  const map = locals.map;
11191
12115
  if (declName) {
@@ -11377,6 +12301,7 @@ __webpack_require__.d(__webpack_exports__, {
11377
12301
  "getApiMapping": () => (/* binding */ getApiMapping),
11378
12302
  "getSuperClasses": () => (/* binding */ getSuperClasses),
11379
12303
  "hasProperty": () => (/* reexport */ src_ast/* hasProperty */.l$),
12304
+ "isClassVariable": () => (/* binding */ isClassVariable),
11380
12305
  "isLocal": () => (/* binding */ isLocal),
11381
12306
  "isLookupCandidate": () => (/* binding */ isLookupCandidate),
11382
12307
  "isStateNode": () => (/* binding */ isStateNode),
@@ -11778,7 +12703,7 @@ function visit_resource_refs(state, doc, e) {
11778
12703
  function add_one_resource(state, doc, module, e) {
11779
12704
  let id;
11780
12705
  let func;
11781
- const varDecl = () => {
12706
+ const makeVarDecl = (id, outer) => {
11782
12707
  const loc = id && (0,src_ast/* adjustLoc */.b5)(id.value.loc);
11783
12708
  return (0,src_ast/* wrap */.re)({
11784
12709
  type: "VariableDeclaration",
@@ -11801,17 +12726,24 @@ function add_one_resource(state, doc, module, e) {
11801
12726
  },
11802
12727
  },
11803
12728
  init,
11804
- }, e.loc),
12729
+ }, outer),
11805
12730
  ],
11806
12731
  kind: "var",
11807
- }, e.loc);
12732
+ }, outer);
11808
12733
  };
12734
+ const varDecl = () => makeVarDecl(id, e.loc);
11809
12735
  const classDecl = (parent) => {
11810
12736
  if (!id)
11811
12737
  return null;
11812
12738
  const loc = id.value.loc;
11813
12739
  const items = init
11814
- ? [{ type: "ClassElement", item: varDecl(), loc: e.loc }]
12740
+ ? [
12741
+ {
12742
+ type: "ClassElement",
12743
+ item: makeVarDecl(undefined, init.loc),
12744
+ loc: e.loc,
12745
+ },
12746
+ ]
11815
12747
  : [];
11816
12748
  return {
11817
12749
  type: "ClassDeclaration",
@@ -11825,7 +12757,9 @@ function add_one_resource(state, doc, module, e) {
11825
12757
  if (!id)
11826
12758
  return null;
11827
12759
  const loc = id.value.loc;
11828
- const items = init ? [varDecl()] : [];
12760
+ const items = init
12761
+ ? [makeVarDecl(undefined, init.loc)]
12762
+ : [];
11829
12763
  return {
11830
12764
  type: "FunctionDeclaration",
11831
12765
  body: { type: "BlockStatement", body: items, loc: e.loc },
@@ -11917,8 +12851,10 @@ function add_one_resource(state, doc, module, e) {
11917
12851
  if (!func)
11918
12852
  return;
11919
12853
  const elements = visit_resource_refs(state, doc, e);
12854
+ const startLoc = elements[0]?.loc;
12855
+ const endLoc = elements[elements.length - 1]?.loc;
11920
12856
  const init = elements.length
11921
- ? { type: "ArrayExpression", elements }
12857
+ ? (0,src_ast/* wrap */.re)({ type: "ArrayExpression", elements }, startLoc && endLoc && (0,src_ast/* locRange */.ht)(startLoc, endLoc))
11922
12858
  : undefined;
11923
12859
  if (!id) {
11924
12860
  if (!init)
@@ -11930,8 +12866,8 @@ function add_one_resource(state, doc, module, e) {
11930
12866
  }
11931
12867
  }
11932
12868
 
11933
- // EXTERNAL MODULE: ./src/type-flow.ts
11934
- var type_flow = __webpack_require__(4859);
12869
+ // EXTERNAL MODULE: ./src/type-flow/type-flow-util.ts
12870
+ var type_flow_util = __webpack_require__(1638);
11935
12871
  // EXTERNAL MODULE: ./src/type-flow/types.ts
11936
12872
  var types = __webpack_require__(7255);
11937
12873
  // EXTERNAL MODULE: external "./util.cjs"
@@ -12564,7 +13500,7 @@ function lookupWithType(state, node, typeMap, nonLocal = false, stack = null) {
12564
13500
  const objectType = typeMap.get(node.object);
12565
13501
  if (!objectType)
12566
13502
  return results;
12567
- const [, decls] = (0,type_flow/* findObjectDeclsByProperty */.nK)(state, objectType, node);
13503
+ const [, decls] = (0,type_flow_util/* findObjectDeclsByProperty */.nK)(state, objectType, node);
12568
13504
  if (decls) {
12569
13505
  const next = lookupNext(state, [{ parent: null, results: decls }], "decls", node.property);
12570
13506
  if (next) {
@@ -13099,13 +14035,14 @@ async function createDocumentationMap(functionDocumentation) {
13099
14035
  state.allFunctions[info.name]?.forEach((decl) => decl.node?.loc?.source === "api.mir" &&
13100
14036
  decl.fullName.endsWith(`.${info.parent}.${info.name}`) &&
13101
14037
  docMap.set(decl.fullName, info.doc
14038
+ .replace(/@example\s*(.*?)<br\/>(.*?)(@|$)/g, (match, title, m1, m2) => `\n#### Example: ${title}\n\`\`\`${m1.replace(/<br\/>/g, "\n")}\`\`\`${m2}`)
13102
14039
  .replace(/(\*.*?)\s*<br\/>\s*(?!\s*\*)/g, "$1\n\n")
13103
- .replace(/@example(.*?)(@|$)/g, (match, m1, m2) => `\n#### Example\n\`\`\`${m1.replace(/<br\/>/g, "\n")}\`\`\`${m2}`)
13104
14040
  .replace(/@note/g, "\n#### Note\n")
13105
14041
  .replace(/@see/, "\n#### See Also:\n$&")
13106
14042
  .replace(/@see\s+(.*?)(?=<br\/>)/g, "\n * {$1}")
13107
14043
  .replace(/@throws/, "\n#### Throws:\n$&")
13108
14044
  .replace(/@throws\s+(.*?)(?=<br\/>)/g, "\n * $1")
14045
+ .replace(/@option\s+\w+\s+(.*?)(?=<br\/>)/g, "\n - $1")
13109
14046
  .replace(/@since\s+(.*?)(?=<br\/>)/, "\n#### Since:\nAPI Level $1\n")
13110
14047
  .replace(/<div class="description">/, "### Description\n")
13111
14048
  .replace(/<div class="param">/, "\n#### Parameters\n$&")
@@ -13304,6 +14241,9 @@ function markInvokeClassMethod(state, func) {
13304
14241
  function isLocal(v) {
13305
14242
  return v.stack[v.stack.length - 1]?.sn.type === "BlockStatement";
13306
14243
  }
14244
+ function isClassVariable(v) {
14245
+ return v.stack[v.stack.length - 1]?.sn.type === "ClassDeclaration";
14246
+ }
13307
14247
  function diagnostic(state, node, message, type = "INFO", extra) {
13308
14248
  if (!state.diagnostics)
13309
14249
  state.diagnostics = {};