@markw65/monkeyc-optimizer 1.0.45 → 1.1.0

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.
@@ -4723,8 +4723,6 @@ function mayThrow(node) {
4723
4723
  switch (node.type) {
4724
4724
  case "BinaryExpression":
4725
4725
  case "CallExpression":
4726
- case "ConditionalExpression":
4727
- case "LogicalExpression":
4728
4726
  case "NewExpression":
4729
4727
  case "ThrowStatement":
4730
4728
  case "UnaryExpression":
@@ -4869,6 +4867,28 @@ function makeScopedName(dotted, l) {
4869
4867
  throw new Error("Failed to make a ScopedName");
4870
4868
  return result;
4871
4869
  }
4870
+ function ast_getLiteralNode(node) {
4871
+ if (node == null)
4872
+ return null;
4873
+ if (node.type == "Literal")
4874
+ return node;
4875
+ if (node.type == "BinaryExpression" && node.operator == "as") {
4876
+ return ast_getLiteralNode(node.left) && node;
4877
+ }
4878
+ if (node.type == "UnaryExpression") {
4879
+ if (node.argument.type != "Literal")
4880
+ return null;
4881
+ switch (node.operator) {
4882
+ case "-": {
4883
+ const [arg, type] = getNodeValue(node.argument);
4884
+ if (type === "Number" || type === "Long") {
4885
+ return { ...arg, value: -arg.value, raw: `-${arg.raw}` };
4886
+ }
4887
+ }
4888
+ }
4889
+ }
4890
+ return null;
4891
+ }
4872
4892
 
4873
4893
  ;// CONCATENATED MODULE: ./src/function-info.ts
4874
4894
 
@@ -5602,31 +5622,9 @@ function unused(state, expression, top) {
5602
5622
  }
5603
5623
  return top ? null : [estmt(expression)];
5604
5624
  }
5605
- function diagnostic(state, loc, message, type = "INFO") {
5606
- if (!loc || !loc.source)
5607
- return;
5608
- const source = loc.source;
5609
- if (!state.diagnostics)
5610
- state.diagnostics = {};
5611
- if (!(0,external_api_cjs_namespaceObject.hasProperty)(state.diagnostics, source)) {
5612
- if (!message)
5613
- return;
5614
- state.diagnostics[source] = [];
5615
- }
5616
- const diags = state.diagnostics[source];
5617
- let index = diags.findIndex((item) => item.loc === loc);
5618
- if (message) {
5619
- if (index < 0)
5620
- index = diags.length;
5621
- diags[index] = { type, loc, message };
5622
- }
5623
- else if (index >= 0) {
5624
- diags.splice(index, 1);
5625
- }
5626
- }
5627
5625
  function inlineDiagnostic(state, func, call, message) {
5628
5626
  if (inlineRequested(state, func)) {
5629
- diagnostic(state, call.loc, message && `While inlining ${func.node.id.name}: ${message}`);
5627
+ (0,external_api_cjs_namespaceObject.diagnostic)(state, call.loc, message && `While inlining ${func.node.id.name}: ${message}`);
5630
5628
  }
5631
5629
  }
5632
5630
  function inlineWithArgs(state, func, call, context) {
@@ -5651,8 +5649,9 @@ function inlineWithArgs(state, func, call, context) {
5651
5649
  });
5652
5650
  if (retStmtCount > 1) {
5653
5651
  inlineDiagnostic(state, func, call, "Function had more than one return statement");
5652
+ return null;
5654
5653
  }
5655
- else if ((context.type === "AssignmentExpression" ||
5654
+ if ((context.type === "AssignmentExpression" ||
5656
5655
  context.type === "VariableDeclarator" ||
5657
5656
  context.type === "IfStatement") &&
5658
5657
  retStmtCount !== 1) {
@@ -5684,7 +5683,7 @@ function inlineWithArgs(state, func, call, context) {
5684
5683
  if (!processInlineBody(state, func, call, body, params)) {
5685
5684
  return null;
5686
5685
  }
5687
- diagnostic(state, call.loc, null);
5686
+ (0,external_api_cjs_namespaceObject.diagnostic)(state, call.loc, null);
5688
5687
  if (context.type !== "ReturnStatement" && retStmtCount) {
5689
5688
  const [last, block] = lastStmt(body);
5690
5689
  if (last.type != "ReturnStatement") {
@@ -5921,7 +5920,6 @@ function fixNodeScope(state, lookupNode, nodeStack) {
5921
5920
  ;// CONCATENATED MODULE: ./src/pragma-checker.ts
5922
5921
 
5923
5922
 
5924
-
5925
5923
  function pragmaChecker(state, ast, diagnostics) {
5926
5924
  const comments = ast.comments;
5927
5925
  if (!comments)
@@ -5963,7 +5961,7 @@ function pragmaChecker(state, ast, diagnostics) {
5963
5961
  break;
5964
5962
  }
5965
5963
  }
5966
- diagnostic(state, comment.loc, `Build pragma '${comment.value}' is invalid`, "ERROR");
5964
+ (0,external_api_cjs_namespaceObject.diagnostic)(state, comment.loc, `Build pragma '${comment.value}' is invalid`, "ERROR");
5967
5965
  }
5968
5966
  };
5969
5967
  const matcher = (quote, needle, haystack) => {
@@ -5987,7 +5985,7 @@ function pragmaChecker(state, ast, diagnostics) {
5987
5985
  const haystack = (0,external_api_cjs_namespaceObject.formatAst)(node).replace(/([\r\n]|\s)+/g, " ");
5988
5986
  if (!matcher(quote, needle, haystack)) {
5989
5987
  matcher(quote, needle, haystack);
5990
- diagnostic(state, comment.loc, `Didn't find '${needle}' in '${haystack}'`, "ERROR");
5988
+ (0,external_api_cjs_namespaceObject.diagnostic)(state, comment.loc, `Didn't find '${needle}' in '${haystack}'`, "ERROR");
5991
5989
  }
5992
5990
  }
5993
5991
  else if (kind === "expect") {
@@ -6029,7 +6027,7 @@ function pragmaChecker(state, ast, diagnostics) {
6029
6027
  }
6030
6028
  }
6031
6029
  if (!found) {
6032
- diagnostic(state, comment.loc, `Missing error message '${needle}`, "ERROR");
6030
+ (0,external_api_cjs_namespaceObject.diagnostic)(state, comment.loc, `Missing error message '${needle}`, "ERROR");
6033
6031
  }
6034
6032
  }
6035
6033
  if (matchers.length) {
@@ -6128,6 +6126,7 @@ function buildReducedGraph(state, func, notice) {
6128
6126
  const ret = localState.curBlock;
6129
6127
  state.stack = [...func.stack];
6130
6128
  const stmtStack = [func.node];
6129
+ const testStack = [{ node: func.node }];
6131
6130
  let tryActive = 0;
6132
6131
  state.pre = (node) => {
6133
6132
  if (state.inType || localState.unreachable) {
@@ -6137,6 +6136,10 @@ function buildReducedGraph(state, func, notice) {
6137
6136
  (isStatement(node) || isExpression(node))) {
6138
6137
  localState.curBlock.node = node;
6139
6138
  }
6139
+ let topTest = testStack[testStack.length - 1];
6140
+ if (topTest.node !== node && topTest.true) {
6141
+ testStack.push((topTest = { node }));
6142
+ }
6140
6143
  if (isStatement(node)) {
6141
6144
  stmtStack.push(node);
6142
6145
  }
@@ -6187,9 +6190,15 @@ function buildReducedGraph(state, func, notice) {
6187
6190
  let head;
6188
6191
  if (node.type === "WhileStatement") {
6189
6192
  head = localState.newBlock(top.continue);
6193
+ const body = {};
6194
+ testStack.push({
6195
+ node: node.test,
6196
+ true: body,
6197
+ false: top.break,
6198
+ });
6190
6199
  state.traverse(node.test);
6191
- localState.addEdge(localState.curBlock, top.break);
6192
- localState.newBlock();
6200
+ localState.unreachable = true;
6201
+ localState.newBlock(body);
6193
6202
  }
6194
6203
  else {
6195
6204
  head = localState.newBlock();
@@ -6197,11 +6206,18 @@ function buildReducedGraph(state, func, notice) {
6197
6206
  state.traverse(node.body);
6198
6207
  if (node.type === "DoWhileStatement") {
6199
6208
  localState.newBlock(top.continue);
6209
+ testStack.push({
6210
+ node: node.test,
6211
+ true: head,
6212
+ false: top.break,
6213
+ });
6200
6214
  state.traverse(node.test);
6201
- localState.addEdge(localState.curBlock, top.break);
6215
+ localState.unreachable = true;
6216
+ }
6217
+ else if (!localState.unreachable) {
6218
+ localState.addEdge(localState.curBlock, head);
6202
6219
  }
6203
- localState.addEdge(localState.curBlock, head);
6204
- localState.curBlock = top.break;
6220
+ localState.newBlock(top.break);
6205
6221
  return [];
6206
6222
  }
6207
6223
  case "TryStatement": {
@@ -6298,9 +6314,15 @@ function buildReducedGraph(state, func, notice) {
6298
6314
  top.break = {};
6299
6315
  top.continue = {};
6300
6316
  if (node.test) {
6317
+ const body = {};
6318
+ testStack.push({
6319
+ node: node.test,
6320
+ true: body,
6321
+ false: top.break,
6322
+ });
6301
6323
  state.traverse(node.test);
6302
- localState.addEdge(localState.curBlock, top.break);
6303
- localState.newBlock();
6324
+ localState.unreachable = true;
6325
+ localState.newBlock(body);
6304
6326
  }
6305
6327
  state.traverse(node.body);
6306
6328
  localState.newBlock(top.continue);
@@ -6322,39 +6344,91 @@ function buildReducedGraph(state, func, notice) {
6322
6344
  }
6323
6345
  case "IfStatement":
6324
6346
  case "ConditionalExpression": {
6325
- state.traverse(node.test);
6347
+ const consequent = {};
6326
6348
  const alternate = {};
6327
- localState.addEdge(localState.curBlock, alternate);
6328
- localState.newBlock();
6349
+ const next = node.alternate ? {} : alternate;
6350
+ testStack.push({
6351
+ node: node.test,
6352
+ true: consequent,
6353
+ false: alternate,
6354
+ });
6355
+ state.traverse(node.test);
6356
+ localState.unreachable = true;
6357
+ if (topTest.true) {
6358
+ testStack.push({ ...topTest, node: node.consequent });
6359
+ }
6360
+ else {
6361
+ testStack.push({ node: node.consequent, true: next, false: next });
6362
+ }
6363
+ localState.newBlock(consequent);
6329
6364
  state.traverse(node.consequent);
6330
- const consequent = localState.unreachable
6331
- ? null
6332
- : localState.curBlock;
6333
6365
  localState.unreachable = true;
6334
- localState.newBlock(alternate);
6335
6366
  if (node.alternate) {
6336
- state.traverse(node.alternate);
6337
- if (!localState.unreachable) {
6338
- localState.newBlock();
6367
+ if (topTest.true) {
6368
+ testStack.push({ ...topTest, node: node.alternate });
6339
6369
  }
6340
- }
6341
- if (consequent) {
6342
- if (localState.unreachable) {
6343
- localState.newBlock();
6370
+ else {
6371
+ testStack.push({ node: node.alternate, true: next, false: next });
6344
6372
  }
6345
- localState.addEdge(consequent, localState.curBlock);
6373
+ localState.newBlock(alternate);
6374
+ state.traverse(node.alternate);
6375
+ localState.unreachable = true;
6376
+ }
6377
+ if (next.preds) {
6378
+ /*
6379
+ * Given:
6380
+ * if (cond) {
6381
+ * } else if (cond2) {
6382
+ * } // no else
6383
+ *
6384
+ * cond2 will cause a branch to the second if's next block
6385
+ * But if topTest.true, we also need to ensure that next branches
6386
+ * to both true and false.
6387
+ *
6388
+ * So in *this* case, we have to skip the testStack.pop (or manually
6389
+ * add the edges here).
6390
+ */
6391
+ localState.newBlock(next);
6392
+ }
6393
+ else if (topTest.node === node) {
6394
+ testStack.pop();
6346
6395
  }
6347
6396
  return [];
6348
6397
  }
6349
6398
  case "LogicalExpression": {
6399
+ const isAnd = node.operator === "&&" || node.operator === "and";
6400
+ const right = {};
6401
+ const next = {};
6402
+ if (isAnd) {
6403
+ testStack.push({
6404
+ node: node.left,
6405
+ true: right,
6406
+ false: topTest.false || next,
6407
+ });
6408
+ }
6409
+ else {
6410
+ testStack.push({
6411
+ node: node.left,
6412
+ true: topTest.true || next,
6413
+ false: right,
6414
+ });
6415
+ }
6350
6416
  state.traverse(node.left);
6351
- if (localState.unreachable)
6352
- break;
6353
- const mid = localState.curBlock;
6354
- localState.newBlock();
6417
+ localState.unreachable = true;
6418
+ localState.newBlock(right);
6419
+ testStack.push({
6420
+ node: node.right,
6421
+ true: topTest.true || next,
6422
+ false: topTest.false || next,
6423
+ });
6355
6424
  state.traverse(node.right);
6356
- localState.newBlock();
6357
- localState.addEdge(mid, localState.curBlock);
6425
+ localState.unreachable = true;
6426
+ if (next.preds) {
6427
+ localState.newBlock(next);
6428
+ }
6429
+ if (topTest.node === node) {
6430
+ testStack.pop();
6431
+ }
6358
6432
  return [];
6359
6433
  }
6360
6434
  case "VariableDeclarator":
@@ -6415,6 +6489,7 @@ function buildReducedGraph(state, func, notice) {
6415
6489
  };
6416
6490
  state.post = (node) => {
6417
6491
  const curStmt = stmtStack[stmtStack.length - 1];
6492
+ const topTest = testStack[testStack.length - 1];
6418
6493
  if (!state.inType) {
6419
6494
  const throws = tryActive > 0 && mayThrow(node);
6420
6495
  const event = notice(node, curStmt, throws);
@@ -6452,11 +6527,34 @@ function buildReducedGraph(state, func, notice) {
6452
6527
  addEvent(localState.curBlock, event);
6453
6528
  }
6454
6529
  }
6530
+ if (localState.top().node === node) {
6531
+ localState.pop();
6532
+ }
6533
+ if (topTest.node === node) {
6534
+ testStack.pop();
6535
+ if (topTest.true && !localState.unreachable) {
6536
+ localState.addEdge(localState.curBlock, topTest.true);
6537
+ if (topTest.false !== topTest.true) {
6538
+ if (localState.curBlock.succs?.length !== 1) {
6539
+ throw new Error("Internal error: Unexpected successor edges");
6540
+ }
6541
+ localState.addEdge(localState.curBlock, topTest.false);
6542
+ const event = notice(node, curStmt, 1);
6543
+ if (event) {
6544
+ event.mayThrow = false;
6545
+ addEvent(localState.curBlock, event);
6546
+ localState.unreachable = true;
6547
+ }
6548
+ }
6549
+ }
6550
+ }
6455
6551
  if (curStmt === node) {
6456
6552
  stmtStack.pop();
6457
6553
  }
6458
- if (localState.top().node === node) {
6459
- localState.pop();
6554
+ else if (localState.unreachable &&
6555
+ curStmt.type === "BlockStatement" &&
6556
+ isStatement(node)) {
6557
+ return false;
6460
6558
  }
6461
6559
  return null;
6462
6560
  };
@@ -6580,6 +6678,8 @@ function declFullName(decl) {
6580
6678
  if ((0,external_api_cjs_namespaceObject.isStateNode)(decl))
6581
6679
  return decl.fullName;
6582
6680
  switch (decl.type) {
6681
+ case "Identifier":
6682
+ return decl.name;
6583
6683
  case "BinaryExpression":
6584
6684
  return decl.left.name;
6585
6685
  case "EnumStringMember":
@@ -6587,7 +6687,7 @@ function declFullName(decl) {
6587
6687
  ? `${decl.id.name}:${(0,external_api_cjs_namespaceObject.formatAst)(decl.init)}`
6588
6688
  : decl.id.name;
6589
6689
  default:
6590
- throw new Error(`Unexpected EventDecl type: ${decl.type}`);
6690
+ unhandledType(decl);
6591
6691
  }
6592
6692
  }
6593
6693
  function declName(decl) {
@@ -6608,7 +6708,7 @@ function declName(decl) {
6608
6708
  throw new Error(`Unexpected EventDecl type: ${decl.type}`);
6609
6709
  }
6610
6710
  }
6611
- function unhandledExpression(node) {
6711
+ function unhandledType(node) {
6612
6712
  throw new Error(`Unhandled expression type: ${node.type}`);
6613
6713
  }
6614
6714
  function buildDataFlowGraph(state, func, wantsLiteral, trackInsertionPoints, wantsAllRefs) {
@@ -6677,6 +6777,9 @@ function buildDataFlowGraph(state, func, wantsLiteral, trackInsertionPoints, wan
6677
6777
  return {
6678
6778
  identifiers,
6679
6779
  graph: buildReducedGraph(state, func, (node, stmt, mayThrow) => {
6780
+ if (mayThrow === 1) {
6781
+ return null;
6782
+ }
6680
6783
  const defs = liveStmts.get(node);
6681
6784
  if (defs) {
6682
6785
  liveStmts.delete(node);
@@ -6820,7 +6923,7 @@ function buildDataFlowGraph(state, func, wantsLiteral, trackInsertionPoints, wan
6820
6923
  default:
6821
6924
  if (!isExpression(node))
6822
6925
  break;
6823
- unhandledExpression(node);
6926
+ unhandledType(node);
6824
6927
  }
6825
6928
  if (mayThrow) {
6826
6929
  return { type: "exn", node, mayThrow };
@@ -6921,7 +7024,10 @@ function sizeBasedPRE(state, func) {
6921
7024
  }, func.node.body);
6922
7025
  variableDecl.end = variableDecl.start;
6923
7026
  variableDecl.loc.end = variableDecl.loc.start;
6924
- candidates.forEach((s, decl) => {
7027
+ Array.from(candidates.keys())
7028
+ .map((decl) => [declFullName(decl), decl])
7029
+ .sort()
7030
+ .forEach(([, decl]) => {
6925
7031
  let name;
6926
7032
  let i = 0;
6927
7033
  do {
@@ -6933,6 +7039,7 @@ function sizeBasedPRE(state, func) {
6933
7039
  i++;
6934
7040
  } while (true);
6935
7041
  declMap.set(decl, name);
7042
+ const s = candidates.get(decl);
6936
7043
  variableDecl.declarations.push(withLoc({
6937
7044
  type: "VariableDeclarator",
6938
7045
  id: withLoc({ type: "Identifier", name }, variableDecl),
@@ -6953,7 +7060,71 @@ function sizeBasedPRE(state, func) {
6953
7060
  }
6954
7061
  }
6955
7062
  function buildPREGraph(state, func) {
6956
- return buildDataFlowGraph(state, func, (literal) => refCost(literal) > LocalRefCost, true, false);
7063
+ const result = buildDataFlowGraph(state, func, (literal) => refCost(literal) > LocalRefCost, true, false);
7064
+ // Split blocks that contains refs and defs to the same thing,
7065
+ // to make it easier to pick and choose which refs are converted
7066
+ postOrderTraverse(result.graph, (block) => {
7067
+ if (!block.events) {
7068
+ return;
7069
+ }
7070
+ let modSeen = false;
7071
+ const refs = new Set();
7072
+ const defs = new Set();
7073
+ const splitBlock = (eventIndex) => {
7074
+ const newBlock = { ...block };
7075
+ delete newBlock.node;
7076
+ newBlock.events = block.events?.splice(eventIndex);
7077
+ newBlock.succs?.forEach((succ) => {
7078
+ const i = succ.preds.findIndex((b) => b === block);
7079
+ succ.preds[i] = newBlock;
7080
+ if (succ.expreds?.includes(block)) {
7081
+ succ.expreds.push(newBlock);
7082
+ }
7083
+ });
7084
+ block.succs = [newBlock];
7085
+ newBlock.preds = [block];
7086
+ delete newBlock.expreds;
7087
+ modSeen = false;
7088
+ refs.clear();
7089
+ defs.clear();
7090
+ };
7091
+ for (let i = block.events.length; i--;) {
7092
+ const event = block.events[i];
7093
+ switch (event.type) {
7094
+ case "ref":
7095
+ if ((0,external_util_cjs_namespaceObject.some)(event.decl, (decl) => decl.type === "Literal" ||
7096
+ (decl.type === "VariableDeclarator" &&
7097
+ decl.node.kind === "const"))) {
7098
+ break;
7099
+ }
7100
+ if (modSeen || defs.has(event.decl)) {
7101
+ splitBlock(i + 1);
7102
+ }
7103
+ refs.add(event.decl);
7104
+ break;
7105
+ case "def":
7106
+ if (refs.has(event.decl)) {
7107
+ splitBlock(i + 1);
7108
+ }
7109
+ defs.add(event.decl);
7110
+ break;
7111
+ case "mod":
7112
+ if (event.callees &&
7113
+ (0,external_util_cjs_namespaceObject.every)(event.callees, (callee) => callee.info === false)) {
7114
+ // calls known to have no side effects can be
7115
+ // dropped.
7116
+ block.events.splice(i, 1);
7117
+ break;
7118
+ }
7119
+ if (refs.size) {
7120
+ splitBlock(i + 1);
7121
+ }
7122
+ modSeen = true;
7123
+ break;
7124
+ }
7125
+ }
7126
+ });
7127
+ return result;
6957
7128
  }
6958
7129
  function anticipatedDecls() {
6959
7130
  return new Map();
@@ -7527,64 +7698,2874 @@ function applyReplacements(func, nodeMap, declMap) {
7527
7698
  });
7528
7699
  }
7529
7700
 
7530
- ;// CONCATENATED MODULE: ./src/unused-exprs.ts
7701
+ ;// CONCATENATED MODULE: ./src/type-flow/union-type.ts
7531
7702
 
7532
7703
 
7533
7704
 
7534
- function cleanupUnusedVars(state, node) {
7535
- const [parent] = state.stack.slice(-1);
7536
- if (parent.node !== node) {
7705
+ function unionInto(to, from) {
7706
+ if (from.type === 0 || to === from)
7707
+ return false;
7708
+ if (to.type === 0) {
7709
+ to.type = from.type;
7710
+ to.value = from.value;
7711
+ return true;
7712
+ }
7713
+ const newTags = to.type | from.type;
7714
+ if (!(from.type & ~SingleTonTypeTagsConst)) {
7715
+ // - Adding singletons never affects the data.
7716
+ if (newTags === to.type)
7717
+ return false;
7718
+ to.type = newTags;
7719
+ return true;
7720
+ }
7721
+ if (newTags === to.type) {
7722
+ if (to.value === from.value || to.value == null) {
7723
+ return false;
7724
+ }
7725
+ if (from.value == null) {
7726
+ clearValuesUnder(to, from.type);
7727
+ return true;
7728
+ }
7729
+ return mergeMultiple(to, from);
7730
+ }
7731
+ if (to.value != null) {
7732
+ if (from.value == null) {
7733
+ clearValuesUnder(to, from.type);
7734
+ return true;
7735
+ }
7736
+ return mergeMultiple(to, from);
7737
+ }
7738
+ if (from.value == null) {
7739
+ to.type = newTags;
7740
+ return true;
7741
+ }
7742
+ const tmp = cloneType(from);
7743
+ clearValuesUnder(tmp, to.type);
7744
+ to.type = tmp.type;
7745
+ to.value = tmp.value;
7746
+ return true;
7747
+ }
7748
+ function mergeMultiple(to, from) {
7749
+ const newTags = to.type | from.type;
7750
+ let anyChanged = newTags !== to.type;
7751
+ let mask = 0;
7752
+ const result = {};
7753
+ forEachUnionComponent(to, newTags, (tag, tov) => {
7754
+ const fromv = getUnionComponent(from, tag);
7755
+ if (tov != null) {
7756
+ if (fromv != null) {
7757
+ const [value, changed] = mergeSingle(tag, tov, fromv);
7758
+ if (changed)
7759
+ anyChanged = true;
7760
+ if (value) {
7761
+ mask |= tag;
7762
+ result[tag] = value;
7763
+ }
7764
+ }
7765
+ else if (!(from.type & tag)) {
7766
+ // from doesn't contribute to this tag,
7767
+ // so just keep it. No change.
7768
+ mask |= tag;
7769
+ result[tag] = tov;
7770
+ }
7771
+ else {
7772
+ // We dropped the data for this tag, so
7773
+ // things changed.
7774
+ anyChanged = true;
7775
+ }
7776
+ }
7777
+ else if (fromv && !(to.type & tag)) {
7778
+ // to doesn't contribute to this tag,
7779
+ // so just keep from's component.
7780
+ // this is new, so it changed.
7781
+ anyChanged = true;
7782
+ mask |= tag;
7783
+ result[tag] = fromv;
7784
+ }
7785
+ });
7786
+ if (!anyChanged)
7787
+ return false;
7788
+ to.type = newTags;
7789
+ if (!mask) {
7790
+ delete to.value;
7791
+ return true;
7792
+ }
7793
+ if (hasUnionData(newTags)) {
7794
+ to.value = result;
7795
+ to.value.mask = mask;
7796
+ return true;
7797
+ }
7798
+ if (mask & (mask - 1)) {
7799
+ throw new Error("Union incorrectly produced a UnionData");
7800
+ }
7801
+ to.value = result[mask];
7802
+ return true;
7803
+ }
7804
+ function tryUnion(to, from) {
7805
+ to = cloneType(to);
7806
+ if (unionInto(to, from))
7807
+ return to;
7808
+ return null;
7809
+ }
7810
+ function mergeSingle(type, to, from) {
7811
+ switch (type) {
7812
+ case TypeTag.Number:
7813
+ case TypeTag.Long:
7814
+ case TypeTag.Float:
7815
+ case TypeTag.Double:
7816
+ case TypeTag.Char:
7817
+ case TypeTag.String:
7818
+ case TypeTag.Symbol:
7819
+ if (to === from) {
7820
+ return [to, false];
7821
+ }
7822
+ return [null, true];
7823
+ case TypeTag.Array: {
7824
+ const merged = tryUnion(to, from);
7825
+ return [merged || to, merged != null];
7826
+ }
7827
+ case TypeTag.Dictionary: {
7828
+ const { key, value } = to;
7829
+ const keyChange = tryUnion(key, from.key);
7830
+ const valueChange = tryUnion(value, from.value);
7831
+ if (keyChange || valueChange) {
7832
+ return [{ key: keyChange || key, value: valueChange || value }, true];
7833
+ }
7834
+ return [to, false];
7835
+ }
7836
+ case TypeTag.Module:
7837
+ case TypeTag.Function:
7838
+ case TypeTag.Class:
7839
+ case TypeTag.Typedef:
7840
+ return mergeStateDecls(to, from);
7841
+ case TypeTag.Object: {
7842
+ const klass = to.klass;
7843
+ const [obj, objChanged] = mergeObjectValues(to.obj, from.obj);
7844
+ const klassChanged = tryUnion(klass, from.klass);
7845
+ if (klassChanged || objChanged) {
7846
+ if (obj) {
7847
+ return [{ klass: klassChanged, obj }, true];
7848
+ }
7849
+ return [{ klass: klassChanged }, true];
7850
+ }
7851
+ return [to, false];
7852
+ }
7853
+ case TypeTag.Enum: {
7854
+ const toE = to;
7855
+ const fromE = from;
7856
+ if (toE.enum !== fromE.enum) {
7857
+ return [null, true];
7858
+ }
7859
+ if (!toE.value) {
7860
+ return [toE, false];
7861
+ }
7862
+ if (!fromE.value) {
7863
+ delete toE.value;
7864
+ return [toE, true];
7865
+ }
7866
+ const toValue = tryUnion(toE.value, fromE.value);
7867
+ if (toValue) {
7868
+ return [{ enum: toE.enum, value: toValue }, true];
7869
+ }
7870
+ return [toE, false];
7871
+ }
7872
+ }
7873
+ throw new Error(`Unexpected type ${type}`);
7874
+ }
7875
+ function mergeObjectValues(to, from) {
7876
+ if (!to) {
7877
+ return [to, false];
7878
+ }
7879
+ if (!from) {
7880
+ return [from, true];
7881
+ }
7882
+ let empty = true;
7883
+ let result = to;
7884
+ Object.entries(to).forEach(([key, value]) => {
7885
+ if (!hasProperty(from, key)) {
7886
+ if (result === to)
7887
+ result = { ...result };
7888
+ delete result[key];
7889
+ return;
7890
+ }
7891
+ const rep = cloneType(value);
7892
+ if (unionInto(rep, from[key])) {
7893
+ if (result === to)
7894
+ result = { ...result };
7895
+ result[key] = rep;
7896
+ }
7897
+ empty = false;
7898
+ });
7899
+ if (empty) {
7900
+ return [undefined, true];
7901
+ }
7902
+ return [result, result !== to];
7903
+ }
7904
+ function mergeStateDecls(to, from) {
7905
+ let changed = false;
7906
+ let result = to;
7907
+ (0,external_util_cjs_namespaceObject.forEach)(from, (v) => {
7908
+ if ((0,external_util_cjs_namespaceObject.some)(to, (t) => t === v)) {
7909
+ return;
7910
+ }
7911
+ if (Array.isArray(result)) {
7912
+ if (result === to) {
7913
+ result = [...result, v];
7914
+ }
7915
+ else {
7916
+ result.push(v);
7917
+ }
7918
+ }
7919
+ else {
7920
+ result = [to, v];
7921
+ }
7922
+ changed = true;
7923
+ });
7924
+ return [result, changed];
7925
+ }
7926
+ // precondition: hasUnionData
7927
+ function nonUnionDataMask(tag) {
7928
+ if (tag & (tag - 1)) {
7929
+ // More than one bit set, but it doesn't have
7930
+ // UnionData, so it must either have a single bit
7931
+ // under UnionDataTypeTagsConst, or a single bit
7932
+ // under ValueTypeTagsConst.
7933
+ return tag & UnionDataTypeTagsConst || tag & ValueTypeTagsConst;
7934
+ }
7935
+ return tag;
7936
+ }
7937
+ /*
7938
+ * Remove any data associated with tag.
7939
+ * Add (or remove) tag to (or from) v.type, according
7940
+ * to clearTag.
7941
+ */
7942
+ function clearValuesUnder(v, tag, clearTag = false) {
7943
+ const newTag = clearTag ? v.type & ~tag : v.type | tag;
7944
+ // If the incoming type consists of singletons,
7945
+ // we can always merge it without affecting our data.
7946
+ tag &= ~SingleTonTypeTagsConst;
7947
+ if (!tag) {
7948
+ v.type = newTag;
7537
7949
  return;
7538
7950
  }
7539
- if (parent.type != "BlockStatement") {
7540
- throw new Error(`Unexpected parent type '${parent.type}' for local declaration`);
7951
+ // We only keep data for ValueTypeTags if there is
7952
+ // only one of them. If the type being merged has
7953
+ // no data for one of them, the resulting type has
7954
+ // no data for any of them.
7955
+ if (tag & ValueTypeTagsConst) {
7956
+ tag |= ValueTypeTagsConst;
7957
+ }
7958
+ if (!hasUnionData(v.type)) {
7959
+ // get the single bit corresponding to v's data
7960
+ const dataMask = nonUnionDataMask(v.type);
7961
+ if (dataMask & tag) {
7962
+ // the merging type has no data for our
7963
+ // exact type; so delete all our data.
7964
+ // eg Number<1> or String => Number or String
7965
+ v.type = newTag;
7966
+ delete v.value;
7967
+ return;
7968
+ }
7969
+ if (dataMask & ValueTypeTagsConst) {
7970
+ // assert(tag & UnionDataTypeTags)
7971
+ // v had data corresponding to one of the
7972
+ // ValueTypeTags. But tag adds at least
7973
+ // one new bit. So drop the data.
7974
+ // eg Number<1> or Array => Number or Array
7975
+ delete v.value;
7976
+ v.type = newTag;
7977
+ return;
7978
+ }
7979
+ if (hasUnionData(newTag)) {
7980
+ // v had data corresponding to one of the
7981
+ // UnionDataTypeTags, and tag adds at least
7982
+ // one new bit. Keep the data, but move it into
7983
+ // a UnionData.
7984
+ // eg Array<Number> or Dictionary remains as is.
7985
+ const mask = v.type & UnionDataTypeTagsConst;
7986
+ v.value = {
7987
+ [mask]: v.value,
7988
+ mask,
7989
+ };
7990
+ }
7991
+ v.type = newTag;
7992
+ return;
7541
7993
  }
7542
- if (parent.decls) {
7543
- let toRemove = null;
7544
- Object.values(parent.decls).forEach((decls) => {
7545
- if (decls.length === 1 &&
7546
- decls[0].type === "VariableDeclarator" &&
7547
- !decls[0].used) {
7548
- if (!toRemove)
7549
- toRemove = {};
7550
- toRemove[decls[0].name] = decls[0];
7994
+ v.type = newTag;
7995
+ const unionData = v.value;
7996
+ let remain = unionData.mask & ~tag;
7997
+ if (!remain) {
7998
+ delete v.value;
7999
+ return;
8000
+ }
8001
+ const newData = { mask: remain };
8002
+ while (remain) {
8003
+ const next = remain & (remain - 1);
8004
+ const bit = (remain - next);
8005
+ newData[bit] = unionData[bit];
8006
+ remain = next;
8007
+ }
8008
+ if (!hasUnionData(newTag)) {
8009
+ v.value = newData[(newTag & UnionDataTypeTagsConst)];
8010
+ }
8011
+ else {
8012
+ v.value = newData;
8013
+ }
8014
+ }
8015
+
8016
+ ;// CONCATENATED MODULE: ./src/type-flow/types.ts
8017
+
8018
+
8019
+
8020
+
8021
+
8022
+
8023
+ /**
8024
+ * TypeBit gives the position of the 1 bit in TypeTag
8025
+ */
8026
+ var TypeBit;
8027
+ (function (TypeBit) {
8028
+ TypeBit[TypeBit["Null"] = 0] = "Null";
8029
+ TypeBit[TypeBit["False"] = 1] = "False";
8030
+ TypeBit[TypeBit["True"] = 2] = "True";
8031
+ TypeBit[TypeBit["Number"] = 3] = "Number";
8032
+ TypeBit[TypeBit["Long"] = 4] = "Long";
8033
+ TypeBit[TypeBit["Float"] = 5] = "Float";
8034
+ TypeBit[TypeBit["Double"] = 6] = "Double";
8035
+ TypeBit[TypeBit["Char"] = 7] = "Char";
8036
+ TypeBit[TypeBit["String"] = 8] = "String";
8037
+ TypeBit[TypeBit["Array"] = 9] = "Array";
8038
+ TypeBit[TypeBit["Dictionary"] = 10] = "Dictionary";
8039
+ TypeBit[TypeBit["Module"] = 11] = "Module";
8040
+ TypeBit[TypeBit["Function"] = 12] = "Function";
8041
+ TypeBit[TypeBit["Class"] = 13] = "Class";
8042
+ TypeBit[TypeBit["Object"] = 14] = "Object";
8043
+ TypeBit[TypeBit["Enum"] = 15] = "Enum";
8044
+ TypeBit[TypeBit["Symbol"] = 16] = "Symbol";
8045
+ TypeBit[TypeBit["Typedef"] = 17] = "Typedef";
8046
+ })(TypeBit || (TypeBit = {}));
8047
+ var TypeTag;
8048
+ (function (TypeTag) {
8049
+ TypeTag[TypeTag["Never"] = 0] = "Never";
8050
+ TypeTag[TypeTag["Null"] = 1] = "Null";
8051
+ TypeTag[TypeTag["False"] = 2] = "False";
8052
+ TypeTag[TypeTag["True"] = 4] = "True";
8053
+ TypeTag[TypeTag["Boolean"] = 6] = "Boolean";
8054
+ TypeTag[TypeTag["Number"] = 8] = "Number";
8055
+ TypeTag[TypeTag["Long"] = 16] = "Long";
8056
+ TypeTag[TypeTag["Float"] = 32] = "Float";
8057
+ TypeTag[TypeTag["Double"] = 64] = "Double";
8058
+ TypeTag[TypeTag["Numeric"] = 120] = "Numeric";
8059
+ TypeTag[TypeTag["Char"] = 128] = "Char";
8060
+ TypeTag[TypeTag["String"] = 256] = "String";
8061
+ TypeTag[TypeTag["Array"] = 512] = "Array";
8062
+ TypeTag[TypeTag["Dictionary"] = 1024] = "Dictionary";
8063
+ TypeTag[TypeTag["Module"] = 2048] = "Module";
8064
+ TypeTag[TypeTag["Function"] = 4096] = "Function";
8065
+ TypeTag[TypeTag["Class"] = 8192] = "Class";
8066
+ TypeTag[TypeTag["Object"] = 16384] = "Object";
8067
+ TypeTag[TypeTag["Enum"] = 32768] = "Enum";
8068
+ TypeTag[TypeTag["Symbol"] = 65536] = "Symbol";
8069
+ TypeTag[TypeTag["Typedef"] = 131072] = "Typedef";
8070
+ TypeTag[TypeTag["Any"] = 262143] = "Any";
8071
+ })(TypeTag || (TypeTag = {}));
8072
+ const SingleTonTypeTagsConst = TypeTag.Null | TypeTag.False | TypeTag.True;
8073
+ const UnionDataTypeTagsConst = TypeTag.Array |
8074
+ TypeTag.Dictionary |
8075
+ TypeTag.Module |
8076
+ TypeTag.Function |
8077
+ TypeTag.Class |
8078
+ TypeTag.Object |
8079
+ TypeTag.Enum |
8080
+ TypeTag.Typedef;
8081
+ const ValueTypeTagsConst = TypeTag.Number |
8082
+ TypeTag.Long |
8083
+ TypeTag.Float |
8084
+ TypeTag.Double |
8085
+ TypeTag.Char |
8086
+ TypeTag.String |
8087
+ TypeTag.Symbol;
8088
+ const ObjectLikeTagsConst = TypeTag.Boolean |
8089
+ ValueTypeTagsConst |
8090
+ TypeTag.Array |
8091
+ TypeTag.Dictionary |
8092
+ TypeTag.Enum;
8093
+ function isExact(v) {
8094
+ // check that there is exactly one bit set
8095
+ return v.type !== 0 && !(v.type & (v.type - 1));
8096
+ }
8097
+ function isUnion(v) {
8098
+ return v.type !== 0 && !isExact(v);
8099
+ }
8100
+ function isSingleton(v) {
8101
+ return isExact(v) && (v.type & SingleTonTypeTagsConst) !== 0;
8102
+ }
8103
+ function hasValue(v) {
8104
+ return (isExact(v) &&
8105
+ ((v.type & SingleTonTypeTagsConst) !== 0 || v.value !== undefined));
8106
+ }
8107
+ function lookupByFullName(state, fullName) {
8108
+ return fullName.split(".").reduce((results, part) => {
8109
+ return results
8110
+ .flatMap((result) => (0,external_api_cjs_namespaceObject.isStateNode)(result)
8111
+ ? result.decls?.[part] || result.type_decls?.[part]
8112
+ : null)
8113
+ .filter((sn) => !!sn);
8114
+ }, [state.stack[0]]);
8115
+ }
8116
+ function getMethod(state) {
8117
+ const results = lookupByFullName(state, "Toybox.Lang.Method");
8118
+ if (results.length !== 1) {
8119
+ throw new Error("Internal error: Didn't find Toybox.Lang.Method");
8120
+ }
8121
+ if (results[0].type !== "ClassDeclaration") {
8122
+ throw new Error("Internal error: Toybox.Lang.Method was not a Class");
8123
+ }
8124
+ return results[0];
8125
+ }
8126
+ function cloneType(t) {
8127
+ return { ...t };
8128
+ }
8129
+ function typeFromTypeStateNode(state, sn, classVsObj) {
8130
+ switch (sn.type) {
8131
+ case "ClassDeclaration": {
8132
+ switch (sn.fullName) {
8133
+ case "$.Toybox.Lang.Boolean":
8134
+ return { type: TypeTag.Boolean };
8135
+ case "$.Toybox.Lang.Number":
8136
+ return { type: TypeTag.Number };
8137
+ case "$.Toybox.Lang.Long":
8138
+ return { type: TypeTag.Long };
8139
+ case "$.Toybox.Lang.Float":
8140
+ return { type: TypeTag.Float };
8141
+ case "$.Toybox.Lang.Double":
8142
+ return { type: TypeTag.Double };
8143
+ case "$.Toybox.Lang.Char":
8144
+ return { type: TypeTag.Char };
8145
+ case "$.Toybox.Lang.String":
8146
+ return { type: TypeTag.String };
8147
+ case "$.Toybox.Lang.Array":
8148
+ return { type: TypeTag.Array };
8149
+ case "$.Toybox.Lang.Dictionary":
8150
+ return { type: TypeTag.Dictionary };
8151
+ case "$.Toybox.Lang.Symbol":
8152
+ return { type: TypeTag.Symbol };
8153
+ case "$.Toybox.Lang.Object":
8154
+ return { type: TypeTag.Object };
8155
+ }
8156
+ const cls = { type: TypeTag.Class, value: sn };
8157
+ if (classVsObj)
8158
+ return cls;
8159
+ return { type: TypeTag.Object, value: { klass: cls } };
8160
+ }
8161
+ case "FunctionDeclaration":
8162
+ return { type: TypeTag.Function, value: sn };
8163
+ case "ModuleDeclaration":
8164
+ return { type: TypeTag.Module, value: sn };
8165
+ case "Program":
8166
+ return { type: TypeTag.Module };
8167
+ case "EnumDeclaration":
8168
+ return { type: TypeTag.Enum, value: { enum: sn } };
8169
+ case "EnumStringMember": {
8170
+ const e = state.enumMap?.get(sn);
8171
+ const value = sn.init?.type === "Literal"
8172
+ ? typeFromLiteral(sn.init)
8173
+ : { type: TypeTag.Numeric | TypeTag.String };
8174
+ if (e) {
8175
+ return { type: TypeTag.Enum, value: { enum: e, value } };
8176
+ }
8177
+ return value;
8178
+ }
8179
+ case "TypedefDeclaration": {
8180
+ if (sn.resolvedType) {
8181
+ return sn.resolvedType;
8182
+ }
8183
+ if (sn.isExpanding) {
8184
+ sn.isRecursive = true;
8185
+ return { type: TypeTag.Typedef, value: sn };
8186
+ }
8187
+ sn.isExpanding = true;
8188
+ const result = typeFromTypespec(state, sn.node.ts.argument, sn.stack);
8189
+ delete sn.isExpanding;
8190
+ if (sn.isRecursive) {
8191
+ // Something like
8192
+ // typedef Foo as Number or String or Foo;
8193
+ // is pointless. Its just the same as
8194
+ // typedef Foo as Number or String;
8195
+ // Recursive typedefs are only useful when the
8196
+ // recursion happens under a generic.
8197
+ // So check for that, and remove it.
8198
+ if (result.type & TypeTag.Typedef) {
8199
+ const value = getUnionComponent(result, TypeTag.Typedef);
8200
+ if (value) {
8201
+ const a = [];
8202
+ (0,external_util_cjs_namespaceObject.forEach)(value, (v) => {
8203
+ if (v !== sn)
8204
+ a.push(v);
8205
+ });
8206
+ clearValuesUnder(result, TypeTag.Typedef, true);
8207
+ if (a.length) {
8208
+ unionInto(result, {
8209
+ type: TypeTag.Typedef,
8210
+ value: a.length > 1 ? a : a[0],
8211
+ });
8212
+ }
8213
+ }
8214
+ }
7551
8215
  }
7552
- });
7553
- if (toRemove) {
7554
- const varDeclarations = new Map();
7555
- const stack = [];
7556
- traverseAst(node, (node) => {
7557
- switch (node.type) {
7558
- case "SwitchCase":
7559
- stack.push(node.consequent);
7560
- break;
7561
- case "BlockStatement":
7562
- stack.push(node.body);
7563
- break;
8216
+ sn.resolvedType = result;
8217
+ return result;
8218
+ }
8219
+ case "VariableDeclarator":
8220
+ if (sn.node.kind === "const" && sn.node.init) {
8221
+ if (sn.node.init.type === "Literal") {
8222
+ return typeFromLiteral(sn.node.init);
7564
8223
  }
7565
- }, (node) => {
7566
- switch (node.type) {
7567
- case "SwitchCase":
7568
- case "BlockStatement":
7569
- stack.pop();
7570
- break;
7571
- case "VariableDeclaration": {
7572
- node.declarations.forEach((decl, i) => {
7573
- const name = (0,external_api_cjs_namespaceObject.variableDeclarationName)(decl.id);
7574
- if (hasProperty(toRemove, name)) {
7575
- const info = varDeclarations.get(node);
7576
- if (info) {
7577
- info.indices.push(i);
7578
- }
7579
- else {
7580
- varDeclarations.set(node, {
7581
- parent: stack[stack.length - 1],
7582
- indices: [i],
7583
- });
7584
- }
7585
- }
7586
- });
7587
- break;
8224
+ const [value] = getNodeValue(sn.node.init);
8225
+ if (value) {
8226
+ return evaluateExpr(state, sn.node.init).value;
8227
+ }
8228
+ }
8229
+ if (sn.node.id.type === "BinaryExpression") {
8230
+ return typeFromTypespec(state, sn.node.id.right, sn.stack);
8231
+ }
8232
+ return { type: TypeTag.Any };
8233
+ }
8234
+ throw new Error(`Internal error: Unexpected StateNodeDecl.type: ${sn.type}`);
8235
+ }
8236
+ function typeFromTypeStateNodes(state, sns, classVsObj) {
8237
+ return sns.reduce((cur, sn) => {
8238
+ unionInto(cur, typeFromTypeStateNode(state, sn, classVsObj));
8239
+ return cur;
8240
+ }, { type: TypeTag.Never });
8241
+ }
8242
+ function typeFromSingleTypeSpec(state, type, stack) {
8243
+ if (typeof type === "string") {
8244
+ type = { type: "TypeSpecPart", name: type };
8245
+ }
8246
+ switch (type.type) {
8247
+ case "ObjectExpression":
8248
+ return { type: TypeTag.Dictionary };
8249
+ case "TypeSpecPart": {
8250
+ if (type.body) {
8251
+ // this is an interface declaration.
8252
+ // For now, make it an instance of an unknown class.
8253
+ return { type: TypeTag.Object };
8254
+ }
8255
+ if (type.callspec) {
8256
+ // only legal thing here is Method(<args>) as <result>
8257
+ // For now, make it an instance of an unknown class.
8258
+ return {
8259
+ type: TypeTag.Object,
8260
+ value: { klass: { type: TypeTag.Class, value: getMethod(state) } },
8261
+ };
8262
+ }
8263
+ const id = typeof type.name === "string" ? makeScopedName(type.name) : type.name;
8264
+ const [, results] = state.lookupType(id, null, stack);
8265
+ if (!results) {
8266
+ if (id.type === "Identifier") {
8267
+ switch (id.name) {
8268
+ case "Void":
8269
+ case "Null":
8270
+ return { type: TypeTag.Null };
8271
+ }
8272
+ }
8273
+ const level = state.config?.checkInvalidSymbols;
8274
+ if (level !== "OFF") {
8275
+ (0,external_api_cjs_namespaceObject.diagnostic)(state, id.loc, `Unable to resolve type ${(0,external_api_cjs_namespaceObject.formatAst)(id)}`, level || "WARNING");
8276
+ }
8277
+ return { type: TypeTag.Any };
8278
+ }
8279
+ const resultType = results.reduce((cur, lookupDefn) => {
8280
+ unionInto(cur, typeFromTypeStateNodes(state, lookupDefn.results));
8281
+ return cur;
8282
+ }, { type: TypeTag.Never });
8283
+ if (type.generics) {
8284
+ if (resultType.type === TypeTag.Array && type.generics.length === 1) {
8285
+ resultType.value = typeFromTypespec(state, type.generics[0], stack);
8286
+ }
8287
+ else if (resultType.type === TypeTag.Dictionary &&
8288
+ type.generics.length === 2) {
8289
+ resultType.value = {
8290
+ key: typeFromTypespec(state, type.generics[0], stack),
8291
+ value: typeFromTypespec(state, type.generics[1], stack),
8292
+ };
8293
+ }
8294
+ }
8295
+ return resultType;
8296
+ }
8297
+ }
8298
+ }
8299
+ function typeFromTypespec(state, ts, stack) {
8300
+ if (!state.config?.trustDeclaredTypes) {
8301
+ if (ts.ts.length === 1 && typeof ts.ts[0] === "string") {
8302
+ const e = lookupByFullName(state, ts.ts[0]);
8303
+ if (e && e.length === 1 && e[0].type === "EnumDeclaration") {
8304
+ return {
8305
+ type: TypeTag.Enum,
8306
+ value: { enum: e[0] },
8307
+ };
8308
+ }
8309
+ }
8310
+ return { type: TypeTag.Any };
8311
+ }
8312
+ return ts.ts.reduce((cur, type) => {
8313
+ unionInto(cur, typeFromSingleTypeSpec(state, type, stack));
8314
+ return cur;
8315
+ }, { type: TypeTag.Never });
8316
+ }
8317
+ function typeFromLiteral(literal) {
8318
+ const [value, type] = getNodeValue(literal);
8319
+ switch (type) {
8320
+ case "Null":
8321
+ return { type: TypeTag.Null };
8322
+ case "Boolean":
8323
+ return literal.value ? { type: TypeTag.True } : { type: TypeTag.False };
8324
+ case "Number":
8325
+ return { type: TypeTag.Number, value: value.value };
8326
+ case "Long":
8327
+ return { type: TypeTag.Long, value: BigInt(value.value) };
8328
+ case "Float":
8329
+ return { type: TypeTag.Float, value: value.value };
8330
+ case "Double":
8331
+ return { type: TypeTag.Double, value: value.value };
8332
+ case "Char":
8333
+ return { type: TypeTag.Char, value: value.value };
8334
+ case "String":
8335
+ return { type: TypeTag.String, value: value.value };
8336
+ default:
8337
+ throw new Error(`Unexpected literal type: ${type}:${literal.value}`);
8338
+ }
8339
+ }
8340
+ function mcExprFromType(type) {
8341
+ switch (type.type) {
8342
+ case TypeTag.Null:
8343
+ return { type: "Literal", value: null, raw: "null" };
8344
+ case TypeTag.False:
8345
+ return { type: "Literal", value: false, raw: "false" };
8346
+ case TypeTag.True:
8347
+ return { type: "Literal", value: true, raw: "true" };
8348
+ case TypeTag.Number:
8349
+ return { type: "Literal", value: type.value, raw: `${type.value}` };
8350
+ case TypeTag.Long:
8351
+ return { type: "Literal", value: type.value, raw: `${type.value}l` };
8352
+ case TypeTag.Float: {
8353
+ let raw = type.value.toString();
8354
+ if (prettier_plugin_monkeyc_namespaceObject.LiteralIntegerRe.test(raw)) {
8355
+ raw += "f";
8356
+ }
8357
+ else {
8358
+ const match = raw.match(/^(-)?(\d*)\.(\d+)(e\d+)?/);
8359
+ if (match && match[2].length + match[3].length > 9) {
8360
+ for (let l = 9 - match[2].length; l > 0; l--) {
8361
+ const s = `${match[1] || ""}${match[2]}.${match[3].substring(0, l)}${match[4] || ""}`;
8362
+ if (type.value !== roundToFloat(parseFloat(s)))
8363
+ break;
8364
+ raw = s;
8365
+ }
8366
+ }
8367
+ }
8368
+ return { type: "Literal", value: type.value, raw };
8369
+ }
8370
+ case TypeTag.Double:
8371
+ return { type: "Literal", value: type.value, raw: `${type.value}d` };
8372
+ case TypeTag.Char:
8373
+ return {
8374
+ type: "Literal",
8375
+ value: type.value,
8376
+ raw: `'${JSON.stringify(type.value).slice(1, -1)}'`,
8377
+ };
8378
+ case TypeTag.String:
8379
+ return {
8380
+ type: "Literal",
8381
+ value: type.value,
8382
+ raw: JSON.stringify(type.value),
8383
+ };
8384
+ case TypeTag.Enum:
8385
+ if (type.value.value && hasValue(type.value.value)) {
8386
+ const left = mcExprFromType(type.value.value);
8387
+ if (left) {
8388
+ return {
8389
+ type: "BinaryExpression",
8390
+ operator: "as",
8391
+ left,
8392
+ right: {
8393
+ type: "TypeSpecList",
8394
+ ts: [type.value.enum.fullName.slice(2)],
8395
+ },
8396
+ };
8397
+ }
8398
+ }
8399
+ }
8400
+ return null;
8401
+ }
8402
+ /*
8403
+ * Cast one type to another, as might happen during
8404
+ * operator coercion. If the source type has a value,
8405
+ * try to preserve it.
8406
+ * eg in 1.0 + 2, the 2 will be converted to 2.0 before adding.
8407
+ * Note that many possible conversions simply can't happen.
8408
+ * eg Number can be converted to Long, Float or Double, but
8409
+ * Long, Float and Double never get converted to Number.
8410
+ */
8411
+ function castType(type, target) {
8412
+ if (type.type === target)
8413
+ return cloneType(type);
8414
+ const result = { type: target };
8415
+ if (hasValue(type)) {
8416
+ if (isExact(result)) {
8417
+ switch (result.type) {
8418
+ case TypeTag.Null:
8419
+ case TypeTag.False:
8420
+ case TypeTag.True:
8421
+ case TypeTag.Number:
8422
+ break;
8423
+ case TypeTag.Long:
8424
+ if (type.type === TypeTag.Number) {
8425
+ result.value = BigInt(type.value);
8426
+ return result;
8427
+ }
8428
+ break;
8429
+ case TypeTag.Float:
8430
+ if (type.type === TypeTag.Number) {
8431
+ result.value = type.value;
8432
+ return result;
8433
+ }
8434
+ break;
8435
+ case TypeTag.Double:
8436
+ switch (type.type) {
8437
+ case TypeTag.Number:
8438
+ case TypeTag.Long:
8439
+ case TypeTag.Float:
8440
+ result.value = Number(type.value);
8441
+ return result;
8442
+ }
8443
+ break;
8444
+ case TypeTag.Char:
8445
+ switch (type.type) {
8446
+ case TypeTag.Number:
8447
+ case TypeTag.Long:
8448
+ result.value = String.fromCharCode(Number(type.value));
8449
+ return result;
8450
+ }
8451
+ break;
8452
+ case TypeTag.String:
8453
+ switch (type.type) {
8454
+ case TypeTag.Null:
8455
+ result.value = "null";
8456
+ return result;
8457
+ case TypeTag.False:
8458
+ result.value = "false";
8459
+ return result;
8460
+ case TypeTag.True:
8461
+ result.value = "true";
8462
+ return result;
8463
+ case TypeTag.Number:
8464
+ case TypeTag.Long:
8465
+ result.value = type.value.toString();
8466
+ return result;
8467
+ case TypeTag.Float:
8468
+ case TypeTag.Double:
8469
+ // Dont try to implement these, due to inconsistencies and bugs
8470
+ return result;
8471
+ case TypeTag.Char:
8472
+ result.value = type.value;
8473
+ return result;
8474
+ default:
8475
+ return result;
8476
+ }
8477
+ break;
8478
+ }
8479
+ throw new Error(`Trying to cast ${display(type)} to ${display(result)}`);
8480
+ }
8481
+ else if (result.type === TypeTag.Boolean) {
8482
+ // Number or Long operands to '&', '|', and '^' are coerced
8483
+ // to boolean if the other argument is boolean.
8484
+ if (type.type & (TypeTag.Number | TypeTag.Long)) {
8485
+ result.type = type.value == 0 ? TypeTag.False : TypeTag.True;
8486
+ return result;
8487
+ }
8488
+ }
8489
+ }
8490
+ return result;
8491
+ }
8492
+ /*
8493
+ * Anything consisting of solely these types is definitely true
8494
+ */
8495
+ const TruthyTypes = TypeTag.True |
8496
+ TypeTag.Object |
8497
+ TypeTag.Module |
8498
+ TypeTag.Class |
8499
+ TypeTag.Function;
8500
+ function mustBeTrue(arg) {
8501
+ return (((arg.type === TypeTag.Number || arg.type === TypeTag.Long) &&
8502
+ arg.value != null &&
8503
+ arg.value != 0) ||
8504
+ ((arg.type & TruthyTypes) != 0 && (arg.type & ~TruthyTypes) == 0));
8505
+ }
8506
+ function mustBeFalse(arg) {
8507
+ return (arg.type === TypeTag.Null ||
8508
+ arg.type === TypeTag.False ||
8509
+ ((arg.type === TypeTag.Number || arg.type === TypeTag.Long) &&
8510
+ arg.value != null &&
8511
+ arg.value == 0));
8512
+ }
8513
+ function display(type) {
8514
+ const names = (v, fn) => (0,external_util_cjs_namespaceObject.map)(v, fn)
8515
+ .sort()
8516
+ .filter((s, i, arr) => !i || s !== arr[i - 1])
8517
+ .join(" or ");
8518
+ const parts = [];
8519
+ const displayOne = (bit, value) => {
8520
+ switch (bit) {
8521
+ case TypeTag.Null:
8522
+ case TypeTag.False:
8523
+ case TypeTag.True:
8524
+ throw new Error("Unexpected value for SingletonTypeTag");
8525
+ case TypeTag.Number:
8526
+ case TypeTag.Long:
8527
+ case TypeTag.Float:
8528
+ case TypeTag.Double:
8529
+ return value.toString();
8530
+ case TypeTag.Char:
8531
+ return `'${JSON.stringify(value).slice(1, -1)}'`;
8532
+ case TypeTag.String:
8533
+ return JSON.stringify(type.value);
8534
+ case TypeTag.Array:
8535
+ return display(value);
8536
+ case TypeTag.Dictionary:
8537
+ return `${display(value.key)}, ${display(value.value)}`;
8538
+ case TypeTag.Module:
8539
+ case TypeTag.Function:
8540
+ case TypeTag.Class:
8541
+ case TypeTag.Typedef:
8542
+ return names(value, (v) => v.fullName.slice(2));
8543
+ case TypeTag.Object: {
8544
+ const klass = value.klass;
8545
+ if (!klass.value)
8546
+ return undefined;
8547
+ const obj = value.obj;
8548
+ const ret = displayOne(TypeTag.Class, klass.value);
8549
+ return obj
8550
+ ? `${ret}<{${Object.entries(obj)
8551
+ .map(([key, value]) => `${key}: ${display(value)}`)
8552
+ .join(", ")}}>`
8553
+ : ret;
8554
+ }
8555
+ case TypeTag.Enum: {
8556
+ const v = value;
8557
+ return v.value
8558
+ ? `${display(v.value)} as ${v.enum.fullName.slice(2)}`
8559
+ : v.enum.fullName.slice(2);
8560
+ }
8561
+ case TypeTag.Symbol:
8562
+ return `:${value}`;
8563
+ default:
8564
+ throw new Error(`Unexpected type tag '${bit}'`);
8565
+ }
8566
+ };
8567
+ let bits = type.type;
8568
+ if (!bits)
8569
+ return "Never";
8570
+ if (bits === TypeTag.Any && type.value == null) {
8571
+ return "Any";
8572
+ }
8573
+ while (bits) {
8574
+ const next = bits & (bits - 1);
8575
+ const bit = bits - next;
8576
+ if (bit === TypeTag.False && next & TypeTag.True) {
8577
+ parts.push("Boolean");
8578
+ bits = next - TypeTag.True;
8579
+ continue;
8580
+ }
8581
+ const name = TypeTag[bit];
8582
+ const value = getUnionComponent(type, bit);
8583
+ const valueStr = value != null && displayOne(bit, value);
8584
+ if (!valueStr) {
8585
+ parts.push(name);
8586
+ }
8587
+ else if (bit &
8588
+ (TypeTag.Object |
8589
+ TypeTag.Enum |
8590
+ TypeTag.Typedef |
8591
+ TypeTag.Symbol |
8592
+ TypeTag.String)) {
8593
+ parts.push(valueStr);
8594
+ }
8595
+ else {
8596
+ parts.push(`${name}<${valueStr}${valueStr.endsWith(">") ? " " : ""}>`);
8597
+ }
8598
+ bits = next;
8599
+ }
8600
+ return parts.join(" or ");
8601
+ }
8602
+ function hasUnionData(tag) {
8603
+ tag &= UnionDataTypeTagsConst;
8604
+ return (tag & (tag - 1)) != 0;
8605
+ }
8606
+ function getObjectValue(t) {
8607
+ if (!(t.type & TypeTag.Object) || t.value == null)
8608
+ return null;
8609
+ if (hasUnionData(t.type)) {
8610
+ return t.value[TypeTag.Object];
8611
+ }
8612
+ return t.value;
8613
+ }
8614
+ function forEachUnionComponent(v, bits, fn) {
8615
+ // never iterate the singleton bits, because they don't have data
8616
+ bits &= ~SingleTonTypeTagsConst;
8617
+ if (!bits)
8618
+ return;
8619
+ if (v.type & UnionDataTypeTagsConst) {
8620
+ // Don't iterate the value type bits if any union bit is set
8621
+ bits &= ~ValueTypeTagsConst;
8622
+ }
8623
+ else if (bits & (bits - 1)) {
8624
+ // More than one ValueTypeTagsConst bit set, so there's
8625
+ // no data.
8626
+ return;
8627
+ }
8628
+ const hasUnion = hasUnionData(v.type);
8629
+ const unionData = v.value;
8630
+ do {
8631
+ const next = bits & (bits - 1);
8632
+ const bit = bits - next;
8633
+ const data = hasUnion
8634
+ ? unionData[bit]
8635
+ : bit & v.type
8636
+ ? v.value
8637
+ : null;
8638
+ if (fn(bit, data) === false)
8639
+ break;
8640
+ bits = next;
8641
+ } while (bits);
8642
+ }
8643
+ function getUnionComponent(v, tag) {
8644
+ if (v.value == null)
8645
+ return null;
8646
+ let bits = v.type & ~SingleTonTypeTagsConst;
8647
+ if (!bits)
8648
+ return null;
8649
+ if (bits & (bits - 1)) {
8650
+ bits &= UnionDataTypeTagsConst;
8651
+ if (!bits) {
8652
+ throw new Error(`Non-exact type had no union bits set`);
8653
+ }
8654
+ }
8655
+ if (bits === tag) {
8656
+ return v.value;
8657
+ }
8658
+ else if (bits & tag) {
8659
+ const unionData = v.value;
8660
+ return unionData[tag] || null;
8661
+ }
8662
+ return null;
8663
+ }
8664
+
8665
+ ;// CONCATENATED MODULE: ./src/type-flow/interp-binary.ts
8666
+
8667
+
8668
+
8669
+ /*
8670
+ * Compute the possible type tags of the result of an arithmetic
8671
+ * operation on left and right.
8672
+ *
8673
+ * allowed gives the set of allowed input types.
8674
+ *
8675
+ * + => Number | Long | Float | Double | String | Char | Null
8676
+ * - => Number | Long | Float | Double
8677
+ */
8678
+ function common_types(left, right, allowed) {
8679
+ const types = left.type | right.type;
8680
+ let mask = TypeTag.True |
8681
+ TypeTag.False |
8682
+ TypeTag.Number |
8683
+ TypeTag.Long |
8684
+ TypeTag.Float |
8685
+ TypeTag.Double;
8686
+ if (types & allowed & TypeTag.String) {
8687
+ mask |=
8688
+ TypeTag.String |
8689
+ TypeTag.Char |
8690
+ TypeTag.Null |
8691
+ TypeTag.Dictionary |
8692
+ TypeTag.Array;
8693
+ }
8694
+ else if (types & allowed & TypeTag.Char) {
8695
+ mask |= TypeTag.Char;
8696
+ }
8697
+ mask &= allowed;
8698
+ const lt = left.type & mask;
8699
+ const rt = right.type & mask;
8700
+ let result = lt & TypeTag.String;
8701
+ if (lt & TypeTag.Null)
8702
+ result |= rt & TypeTag.String;
8703
+ if (lt & TypeTag.Boolean) {
8704
+ result |=
8705
+ (rt & TypeTag.Boolean) | TypeTag.Number | TypeTag.Long && TypeTag.Boolean;
8706
+ }
8707
+ if (lt & TypeTag.Number) {
8708
+ result |=
8709
+ rt & TypeTag.Boolean ? TypeTag.Boolean : rt & ~SingleTonTypeTagsConst;
8710
+ }
8711
+ if (lt & TypeTag.Long) {
8712
+ if (rt & TypeTag.Boolean) {
8713
+ result |= TypeTag.Boolean;
8714
+ }
8715
+ else {
8716
+ if (rt & (TypeTag.Number | TypeTag.Long))
8717
+ result |= TypeTag.Long;
8718
+ if (rt & (TypeTag.Float | TypeTag.Double))
8719
+ result |= TypeTag.Double;
8720
+ result |= rt & (TypeTag.String | TypeTag.Char);
8721
+ }
8722
+ }
8723
+ if (lt & TypeTag.Float) {
8724
+ if (rt & (TypeTag.Number | TypeTag.Float))
8725
+ result |= TypeTag.Float;
8726
+ if (rt & (TypeTag.Long | TypeTag.Double))
8727
+ result |= TypeTag.Double;
8728
+ result |= rt & TypeTag.String;
8729
+ }
8730
+ if (lt & TypeTag.Double) {
8731
+ if (rt & (TypeTag.Number | TypeTag.Long | TypeTag.Float | TypeTag.Double)) {
8732
+ result |= TypeTag.Double;
8733
+ }
8734
+ result |= rt & TypeTag.String;
8735
+ }
8736
+ if (lt & TypeTag.Char) {
8737
+ if (rt & (TypeTag.Number | TypeTag.Long)) {
8738
+ result |= TypeTag.Char;
8739
+ }
8740
+ if (rt & (TypeTag.Char | TypeTag.String)) {
8741
+ result |= TypeTag.String;
8742
+ }
8743
+ }
8744
+ return {
8745
+ tag: result,
8746
+ castArgs: !(result & TypeTag.Char) ? result : false,
8747
+ };
8748
+ }
8749
+ function compare_types(left, right) {
8750
+ const ret = common_types(left, right, TypeTag.Number | TypeTag.Long | TypeTag.Float | TypeTag.Double);
8751
+ return { tag: TypeTag.Boolean, castArgs: ret.castArgs };
8752
+ }
8753
+ function equalsCheck(left, right) {
8754
+ // compare numbers for equality without regard for type;
8755
+ // otherwise if its Number vs Char, compare the char-code with the number;
8756
+ // otherwise if its Number vs Boolean, 1/0 compare equal to true/false
8757
+ // otherwise if the types are different, the result is
8758
+ // - unknown if its Object vs any normal type (because eg Number is also Object)
8759
+ // - currently unknown if its Object vs Null (because we can't trust api.mir to
8760
+ // always include Null in the possible return types)
8761
+ // otherwise if its a singleton type (Null, True, False)
8762
+ // the result is true;
8763
+ // otherwise if its a Char or Symbol, compare for equality
8764
+ // otherwise its unknown (we don't track object identity).
8765
+ // Note that each type can only have a single bit set. This is important!
8766
+ return left.type & TypeTag.Numeric && right.type & TypeTag.Numeric
8767
+ ? left.value == right.value
8768
+ : (left.type | right.type) == (TypeTag.Number | TypeTag.Char)
8769
+ ? // Char vs Number is true iff the number is the char-code of the char
8770
+ left.type === TypeTag.Char
8771
+ ? left.value.charCodeAt(0) === right.value
8772
+ : left.value === right.value.charCodeAt(0)
8773
+ : left.type == TypeTag.Number && right.type & TypeTag.Boolean
8774
+ ? left.value == (right.value ? 1 : 0)
8775
+ : right.type == TypeTag.Number && left.type & TypeTag.Boolean
8776
+ ? right.value == (left.value ? 1 : 0)
8777
+ : left.type !== right.type
8778
+ ? ((left.type | right.type) &
8779
+ (TypeTag.Object |
8780
+ TypeTag.Module |
8781
+ TypeTag.Function |
8782
+ TypeTag.Class)) ===
8783
+ TypeTag.Object
8784
+ ? undefined
8785
+ : false
8786
+ : left.type === TypeTag.Char || left.type === TypeTag.Symbol
8787
+ ? left.value === right.value
8788
+ : isSingleton(left)
8789
+ ? true
8790
+ : undefined;
8791
+ }
8792
+ let operators = null;
8793
+ function evaluateBinaryTypes(op, left, right) {
8794
+ if (!operators) {
8795
+ operators = {
8796
+ "+": {
8797
+ allowed: TypeTag.Number |
8798
+ TypeTag.Long |
8799
+ TypeTag.Float |
8800
+ TypeTag.Double |
8801
+ TypeTag.String |
8802
+ TypeTag.Char |
8803
+ TypeTag.Array |
8804
+ TypeTag.Dictionary |
8805
+ TypeTag.Null,
8806
+ typeFn: common_types,
8807
+ valueFn: (left, right) => left.type === TypeTag.Char &&
8808
+ right.type & (TypeTag.Number | TypeTag.Long)
8809
+ ? {
8810
+ type: TypeTag.Char,
8811
+ value: String.fromCharCode(left.value.charCodeAt(0) + Number(right.value)),
8812
+ }
8813
+ : left.type & (TypeTag.Number | TypeTag.Long) &&
8814
+ right.type === TypeTag.Char
8815
+ ? {
8816
+ type: TypeTag.Char,
8817
+ value: String.fromCharCode(right.value.charCodeAt(0) + Number(left.value)),
8818
+ }
8819
+ : {
8820
+ type: left.type,
8821
+ value: left.value + right.value,
8822
+ },
8823
+ },
8824
+ "-": {
8825
+ allowed: TypeTag.Number | TypeTag.Long | TypeTag.Float | TypeTag.Double,
8826
+ typeFn: common_types,
8827
+ valueFn: (left, right) => ({
8828
+ type: left.type,
8829
+ value: left.value - right.value,
8830
+ }),
8831
+ },
8832
+ "*": {
8833
+ allowed: TypeTag.Number | TypeTag.Long | TypeTag.Float | TypeTag.Double,
8834
+ typeFn: common_types,
8835
+ valueFn: (left, right) => ({
8836
+ type: left.type,
8837
+ value: left.value * right.value,
8838
+ }),
8839
+ },
8840
+ "/": {
8841
+ allowed: TypeTag.Number | TypeTag.Long | TypeTag.Float | TypeTag.Double,
8842
+ typeFn: common_types,
8843
+ valueFn: (left, right) => right.value == 0 // "==" because it could be a bigint
8844
+ ? { type: left.type }
8845
+ : left.type === TypeTag.Number
8846
+ ? {
8847
+ type: left.type,
8848
+ value: Number(BigInt(left.value) / BigInt(right.value)),
8849
+ }
8850
+ : {
8851
+ type: left.type,
8852
+ value: left.value / right.value,
8853
+ },
8854
+ },
8855
+ "%": {
8856
+ allowed: TypeTag.Number | TypeTag.Long,
8857
+ typeFn: common_types,
8858
+ valueFn: (left, right) => right.value == 0 // "==" because it could be a bigint
8859
+ ? { type: left.type }
8860
+ : {
8861
+ type: left.type,
8862
+ value: left.value % right.value,
8863
+ },
8864
+ },
8865
+ "&": {
8866
+ allowed: TypeTag.Boolean | TypeTag.Number | TypeTag.Long,
8867
+ typeFn: common_types,
8868
+ valueFn: (left, right) => left.type & TypeTag.Boolean
8869
+ ? {
8870
+ type: left.type === TypeTag.True && right.type === TypeTag.True
8871
+ ? TypeTag.True
8872
+ : TypeTag.False,
8873
+ }
8874
+ : {
8875
+ type: left.type,
8876
+ value: left.value & right.value,
8877
+ },
8878
+ },
8879
+ "|": {
8880
+ allowed: TypeTag.Boolean | TypeTag.Number | TypeTag.Long,
8881
+ typeFn: common_types,
8882
+ valueFn: (left, right) => left.type & TypeTag.Boolean
8883
+ ? {
8884
+ type: left.type === TypeTag.True || right.type === TypeTag.True
8885
+ ? TypeTag.True
8886
+ : TypeTag.False,
8887
+ }
8888
+ : {
8889
+ type: left.type,
8890
+ value: left.value | right.value,
8891
+ },
8892
+ },
8893
+ "^": {
8894
+ allowed: TypeTag.Boolean | TypeTag.Number | TypeTag.Long,
8895
+ typeFn: common_types,
8896
+ valueFn: (left, right) => left.type & TypeTag.Boolean
8897
+ ? {
8898
+ type: (left.type === TypeTag.True) !== (right.type === TypeTag.True)
8899
+ ? TypeTag.True
8900
+ : TypeTag.False,
8901
+ }
8902
+ : {
8903
+ type: left.type,
8904
+ value: left.value ^ right.value,
8905
+ },
8906
+ },
8907
+ "<<": {
8908
+ allowed: TypeTag.Number | TypeTag.Long,
8909
+ typeFn: common_types,
8910
+ valueFn: (left, right) => left.type === TypeTag.Long
8911
+ ? {
8912
+ type: TypeTag.Long,
8913
+ value: left.value << right.value,
8914
+ }
8915
+ : {
8916
+ type: TypeTag.Number,
8917
+ value: left.value << (right.value & 63),
8918
+ },
8919
+ },
8920
+ ">>": {
8921
+ allowed: TypeTag.Number | TypeTag.Long,
8922
+ typeFn: common_types,
8923
+ valueFn: (left, right) => left.type === TypeTag.Long
8924
+ ? {
8925
+ type: TypeTag.Long,
8926
+ value: left.value >> right.value,
8927
+ }
8928
+ : {
8929
+ type: TypeTag.Number,
8930
+ value: left.value >> (right.value & 63),
8931
+ },
8932
+ },
8933
+ "==": {
8934
+ allowed: TypeTag.Any,
8935
+ typeFn: () => ({
8936
+ tag: TypeTag.Boolean,
8937
+ castArgs: false,
8938
+ }),
8939
+ valueFn: (left, right) => {
8940
+ const result = equalsCheck(left, right);
8941
+ return result === undefined
8942
+ ? result
8943
+ : { type: result ? TypeTag.True : TypeTag.False };
8944
+ },
8945
+ },
8946
+ "!=": {
8947
+ allowed: TypeTag.Any,
8948
+ typeFn: () => ({
8949
+ tag: TypeTag.Boolean,
8950
+ castArgs: false,
8951
+ }),
8952
+ valueFn: (left, right) => {
8953
+ const result = equalsCheck(left, right);
8954
+ return result === undefined
8955
+ ? result
8956
+ : { type: result ? TypeTag.False : TypeTag.True };
8957
+ },
8958
+ },
8959
+ "<=": {
8960
+ allowed: TypeTag.Any,
8961
+ typeFn: compare_types,
8962
+ valueFn: (left, right) => ({
8963
+ type: left.value <= right.value
8964
+ ? TypeTag.True
8965
+ : TypeTag.False,
8966
+ }),
8967
+ },
8968
+ ">=": {
8969
+ allowed: TypeTag.Any,
8970
+ typeFn: compare_types,
8971
+ valueFn: (left, right) => ({
8972
+ type: left.value >= right.value
8973
+ ? TypeTag.True
8974
+ : TypeTag.False,
8975
+ }),
8976
+ },
8977
+ "<": {
8978
+ allowed: TypeTag.Any,
8979
+ typeFn: compare_types,
8980
+ valueFn: (left, right) => ({
8981
+ type: left.value < right.value
8982
+ ? TypeTag.True
8983
+ : TypeTag.False,
8984
+ }),
8985
+ },
8986
+ ">": {
8987
+ allowed: TypeTag.Any,
8988
+ typeFn: compare_types,
8989
+ valueFn: (left, right) => ({
8990
+ type: left.value > right.value
8991
+ ? TypeTag.True
8992
+ : TypeTag.False,
8993
+ }),
8994
+ },
8995
+ instanceof: {
8996
+ allowed: TypeTag.Any,
8997
+ typeFn: () => ({
8998
+ tag: TypeTag.Boolean,
8999
+ castArgs: false,
9000
+ }),
9001
+ valueFn: (_left, _right) => undefined,
9002
+ },
9003
+ has: {
9004
+ allowed: TypeTag.Any,
9005
+ typeFn: () => ({
9006
+ tag: TypeTag.Boolean,
9007
+ castArgs: false,
9008
+ }),
9009
+ valueFn: (_left, _right) => undefined,
9010
+ },
9011
+ };
9012
+ }
9013
+ const info = operators[op];
9014
+ if (!info)
9015
+ return { type: TypeTag.Any };
9016
+ const { tag, castArgs } = info.typeFn(left, right, info.allowed);
9017
+ const result_type = { type: tag };
9018
+ if (isExact(result_type) && castArgs !== false) {
9019
+ left = castType(left, castArgs);
9020
+ right = castType(right, castArgs);
9021
+ }
9022
+ if (hasValue(left) && hasValue(right)) {
9023
+ const value = info.valueFn(left, right);
9024
+ if (value) {
9025
+ if (value.type === TypeTag.Float && value.value != null) {
9026
+ value.value = roundToFloat(value.value);
9027
+ }
9028
+ return value;
9029
+ }
9030
+ }
9031
+ return result_type;
9032
+ }
9033
+ function evaluateLogicalTypes(op, left, right) {
9034
+ switch (op) {
9035
+ case "&&":
9036
+ case "and":
9037
+ if (mustBeFalse(left)) {
9038
+ return left;
9039
+ }
9040
+ else {
9041
+ const result = evaluateBinaryTypes("&", left, right);
9042
+ if ((left.type & TypeTag.Null) !== 0) {
9043
+ unionInto(result, { type: TypeTag.Null });
9044
+ }
9045
+ return result;
9046
+ }
9047
+ case "||":
9048
+ case "or":
9049
+ if (mustBeTrue(left)) {
9050
+ return left;
9051
+ }
9052
+ else {
9053
+ const result = evaluateBinaryTypes("|", left, right);
9054
+ if ((left.type & TruthyTypes) !== 0) {
9055
+ unionInto(result, { type: left.type & TruthyTypes });
9056
+ }
9057
+ return result;
9058
+ }
9059
+ }
9060
+ }
9061
+
9062
+ ;// CONCATENATED MODULE: ./src/type-flow/interp-call.ts
9063
+
9064
+
9065
+
9066
+ function evaluateCall(state, node, callee, _args) {
9067
+ while (!hasValue(callee) || callee.type !== TypeTag.Function) {
9068
+ const name = node.callee.type === "Identifier"
9069
+ ? node.callee
9070
+ : node.callee.type === "MemberExpression" && !node.callee.computed
9071
+ ? node.callee.property
9072
+ : null;
9073
+ if (name) {
9074
+ const decls = state.allFunctions[name.name];
9075
+ if (decls) {
9076
+ callee = typeFromTypeStateNodes(state, decls);
9077
+ if (hasValue(callee) && callee.type === TypeTag.Function) {
9078
+ break;
9079
+ }
9080
+ }
9081
+ }
9082
+ return { type: TypeTag.Any };
9083
+ }
9084
+ return (0,external_util_cjs_namespaceObject.reduce)(callee.value, (result, cur) => {
9085
+ if (cur.node.returnType) {
9086
+ const returnType = typeFromTypespec(state, cur.node.returnType.argument, cur.stack);
9087
+ unionInto(result, returnType);
9088
+ }
9089
+ else {
9090
+ result.type = TypeTag.Any;
9091
+ delete result.value;
9092
+ }
9093
+ return result;
9094
+ }, { type: TypeTag.Never });
9095
+ }
9096
+
9097
+ ;// CONCATENATED MODULE: ./src/type-flow/interp.ts
9098
+
9099
+
9100
+
9101
+
9102
+
9103
+
9104
+
9105
+
9106
+ function popIstate(istate, node) {
9107
+ const item = istate.stack.pop();
9108
+ if (!item) {
9109
+ throw new Error("Unbalanced stack!");
9110
+ }
9111
+ if (item.node !== node) {
9112
+ throw new Error("Stack mismatch");
9113
+ }
9114
+ return item;
9115
+ }
9116
+ function evaluateExpr(state, expr, typeMap) {
9117
+ return interp_evaluate({ state, stack: [], typeMap }, expr);
9118
+ }
9119
+ function interp_evaluate(istate, node) {
9120
+ let skipNode = null;
9121
+ const post = (node) => {
9122
+ if (istate.pre && node !== skipNode) {
9123
+ const rep = istate.pre(node);
9124
+ if (rep)
9125
+ return rep;
9126
+ }
9127
+ evaluateNode(istate, node);
9128
+ if (skipNode === node) {
9129
+ skipNode = null;
9130
+ return null;
9131
+ }
9132
+ return istate.post ? istate.post(node) : null;
9133
+ };
9134
+ const pre = (node) => {
9135
+ switch (node.type) {
9136
+ case "MemberExpression":
9137
+ if ((0,external_api_cjs_namespaceObject.isLookupCandidate)(node)) {
9138
+ return ["object"];
9139
+ }
9140
+ break;
9141
+ case "BinaryExpression":
9142
+ if (node.operator === "as") {
9143
+ return ["left"];
9144
+ }
9145
+ break;
9146
+ case "UnaryExpression":
9147
+ if (node.operator === ":") {
9148
+ return [];
9149
+ }
9150
+ break;
9151
+ case "AttributeList":
9152
+ return [];
9153
+ case "AssignmentExpression":
9154
+ skipNode = node.left;
9155
+ break;
9156
+ case "UpdateExpression":
9157
+ skipNode = node.argument;
9158
+ break;
9159
+ case "SizedArrayExpression":
9160
+ return ["size"];
9161
+ case "VariableDeclarator":
9162
+ return ["init"];
9163
+ case "CatchClause":
9164
+ return ["body"];
9165
+ }
9166
+ return null;
9167
+ };
9168
+ traverseAst(node, pre, post);
9169
+ const ret = istate.stack.pop();
9170
+ if (isExpression(node)) {
9171
+ if (!ret || node !== ret.node) {
9172
+ throw new Error("evaluate failed to produce a value for an expression");
9173
+ }
9174
+ }
9175
+ return ret;
9176
+ }
9177
+ function evaluateUnaryTypes(op, argument) {
9178
+ switch (op) {
9179
+ case "+":
9180
+ return argument;
9181
+ case "-":
9182
+ return evaluateBinaryTypes("-", { type: TypeTag.Number, value: 0 }, argument);
9183
+ case "!":
9184
+ case "~":
9185
+ if (hasValue(argument)) {
9186
+ const left = argument.type & TypeTag.Boolean
9187
+ ? { type: TypeTag.True }
9188
+ : { type: TypeTag.Number, value: -1 };
9189
+ return evaluateBinaryTypes("^", left, argument);
9190
+ }
9191
+ return {
9192
+ type: argument.type & (TypeTag.Boolean | TypeTag.Number | TypeTag.Long),
9193
+ };
9194
+ }
9195
+ throw new Error(`Unexpected unary operator ${op}`);
9196
+ }
9197
+ /*
9198
+ * When an enumeration constant, or a constant cast to an
9199
+ * enum type is used in an arithmetic context, its converted
9200
+ * to its underlying type.
9201
+ */
9202
+ function deEnumerate(t) {
9203
+ if (hasValue(t) && t.type === TypeTag.Enum && t.value.value) {
9204
+ return t.value.value;
9205
+ }
9206
+ if (t.type & TypeTag.Enum) {
9207
+ return {
9208
+ type: (t.type & ~TypeTag.Enum) | TypeTag.Numeric | TypeTag.String,
9209
+ };
9210
+ }
9211
+ return t;
9212
+ }
9213
+ function pushScopedNameType(istate, node, embeddedEffects) {
9214
+ let result;
9215
+ if (istate.typeMap) {
9216
+ result = istate.typeMap?.get(node);
9217
+ }
9218
+ else {
9219
+ const [, results] = istate.state.lookup(node);
9220
+ result =
9221
+ results &&
9222
+ results.reduce((cur, lookupDefn) => lookupDefn.results.reduce((cur, result) => {
9223
+ if (result.type !== "BinaryExpression" &&
9224
+ result.type !== "Identifier") {
9225
+ const type = typeFromTypeStateNode(istate.state, result, true);
9226
+ if (!cur) {
9227
+ cur = cloneType(type);
9228
+ }
9229
+ else {
9230
+ unionInto(cur, type);
9231
+ }
9232
+ }
9233
+ return cur;
9234
+ }, cur), null);
9235
+ }
9236
+ istate.stack.push({
9237
+ value: result || { type: TypeTag.Any },
9238
+ embeddedEffects,
9239
+ node,
9240
+ });
9241
+ }
9242
+ function evaluateNode(istate, node) {
9243
+ const { state, stack } = istate;
9244
+ const push = (item) => {
9245
+ if (!item) {
9246
+ throw new Error("Pushing null");
9247
+ }
9248
+ istate.stack.push(item);
9249
+ };
9250
+ switch (node.type) {
9251
+ case "BinaryExpression": {
9252
+ if (node.operator === "as") {
9253
+ push({
9254
+ value: typeFromTypespec(istate.state, node.right),
9255
+ embeddedEffects: false,
9256
+ node: node.right,
9257
+ });
9258
+ }
9259
+ const right = popIstate(istate, node.right);
9260
+ const left = popIstate(istate, node.left);
9261
+ if (node.operator === "as") {
9262
+ if (hasValue(right.value) && right.value.type === TypeTag.Enum) {
9263
+ if ((left.value.type & (TypeTag.Numeric | TypeTag.String)) ==
9264
+ left.value.type) {
9265
+ right.value.value.value = left.value;
9266
+ stack.push({
9267
+ value: right.value,
9268
+ embeddedEffects: left.embeddedEffects,
9269
+ node,
9270
+ });
9271
+ return;
9272
+ }
9273
+ }
9274
+ push({
9275
+ value: right.value,
9276
+ embeddedEffects: left.embeddedEffects,
9277
+ node,
9278
+ });
9279
+ }
9280
+ else {
9281
+ push({
9282
+ value: evaluateBinaryTypes(node.operator, deEnumerate(left.value), deEnumerate(right.value)),
9283
+ embeddedEffects: left.embeddedEffects || right.embeddedEffects,
9284
+ node,
9285
+ });
9286
+ }
9287
+ break;
9288
+ }
9289
+ case "UnaryExpression":
9290
+ if (node.operator === ":") {
9291
+ push({
9292
+ value: { type: TypeTag.Symbol, value: node.argument.name },
9293
+ embeddedEffects: false,
9294
+ node,
9295
+ });
9296
+ }
9297
+ else if (node.operator !== " as") {
9298
+ const arg = popIstate(istate, node.argument);
9299
+ push({
9300
+ value: evaluateUnaryTypes(node.operator, deEnumerate(arg.value)),
9301
+ embeddedEffects: arg.embeddedEffects,
9302
+ node,
9303
+ });
9304
+ }
9305
+ break;
9306
+ case "SizedArrayExpression": {
9307
+ const arg = popIstate(istate, node.size);
9308
+ push({
9309
+ value: { type: TypeTag.Array },
9310
+ embeddedEffects: arg.embeddedEffects,
9311
+ node,
9312
+ });
9313
+ break;
9314
+ }
9315
+ case "ArrayExpression": {
9316
+ const args = node.elements.length
9317
+ ? stack.splice(-node.elements.length)
9318
+ : [];
9319
+ push({
9320
+ value: {
9321
+ type: TypeTag.Array,
9322
+ },
9323
+ embeddedEffects: args.some((arg) => arg.embeddedEffects),
9324
+ node,
9325
+ });
9326
+ break;
9327
+ }
9328
+ case "ObjectExpression": {
9329
+ const args = node.properties.length
9330
+ ? stack.splice(-node.properties.length * 2)
9331
+ : [];
9332
+ push({
9333
+ value: {
9334
+ type: TypeTag.Dictionary,
9335
+ },
9336
+ embeddedEffects: args.some((arg) => arg.embeddedEffects),
9337
+ node,
9338
+ });
9339
+ break;
9340
+ }
9341
+ case "ThisExpression": {
9342
+ const self = (() => {
9343
+ for (let i = state.stack.length; i--;) {
9344
+ const si = state.stack[i];
9345
+ if (si.type === "ClassDeclaration") {
9346
+ const klass = { type: TypeTag.Class, value: si };
9347
+ if ((istate.func?.attributes || 0) & StateNodeAttributes.STATIC) {
9348
+ return klass;
9349
+ }
9350
+ else {
9351
+ return { type: TypeTag.Object, value: { klass } };
9352
+ }
9353
+ }
9354
+ if (si.type === "ModuleDeclaration") {
9355
+ return { type: TypeTag.Module, value: si };
9356
+ }
9357
+ }
9358
+ return { type: TypeTag.Module };
9359
+ })();
9360
+ push({ value: self, embeddedEffects: false, node });
9361
+ break;
9362
+ }
9363
+ case "LogicalExpression": {
9364
+ const right = popIstate(istate, node.right);
9365
+ const left = popIstate(istate, node.left);
9366
+ push({
9367
+ value: evaluateLogicalTypes(node.operator, deEnumerate(left.value), deEnumerate(right.value)),
9368
+ embeddedEffects: left.embeddedEffects || right.embeddedEffects,
9369
+ node,
9370
+ });
9371
+ break;
9372
+ }
9373
+ case "ConditionalExpression": {
9374
+ const alternate = popIstate(istate, node.alternate);
9375
+ const consequent = popIstate(istate, node.consequent);
9376
+ const test = popIstate(istate, node.test);
9377
+ const testType = deEnumerate(test.value);
9378
+ if (mustBeTrue(testType)) {
9379
+ push({
9380
+ value: consequent.value,
9381
+ embeddedEffects: test.embeddedEffects || consequent.embeddedEffects,
9382
+ node,
9383
+ });
9384
+ }
9385
+ else if (mustBeFalse(testType)) {
9386
+ push({
9387
+ value: alternate.value,
9388
+ embeddedEffects: test.embeddedEffects || alternate.embeddedEffects,
9389
+ node,
9390
+ });
9391
+ }
9392
+ else {
9393
+ const value = cloneType(consequent.value);
9394
+ unionInto(value, alternate.value);
9395
+ push({
9396
+ value,
9397
+ embeddedEffects: test.embeddedEffects ||
9398
+ alternate.embeddedEffects ||
9399
+ consequent.embeddedEffects,
9400
+ node,
9401
+ });
9402
+ }
9403
+ break;
9404
+ }
9405
+ case "ParenthesizedExpression": {
9406
+ const { value, embeddedEffects } = popIstate(istate, node.expression);
9407
+ push({ value, embeddedEffects, node });
9408
+ break;
9409
+ }
9410
+ case "Literal":
9411
+ push({
9412
+ value: typeFromLiteral(node),
9413
+ embeddedEffects: false,
9414
+ node,
9415
+ });
9416
+ break;
9417
+ case "Identifier":
9418
+ pushScopedNameType(istate, node, false);
9419
+ break;
9420
+ case "MemberExpression":
9421
+ if (!(0,external_api_cjs_namespaceObject.isLookupCandidate)(node)) {
9422
+ const property = popIstate(istate, node.property);
9423
+ const object = popIstate(istate, node.object);
9424
+ if (hasValue(object.value) &&
9425
+ object.value.type === TypeTag.Array &&
9426
+ property.value.type & (TypeTag.Number | TypeTag.Long)) {
9427
+ push({
9428
+ value: object.value.value,
9429
+ embeddedEffects: object.embeddedEffects || property.embeddedEffects,
9430
+ node,
9431
+ });
9432
+ break;
9433
+ }
9434
+ if (hasValue(object.value) &&
9435
+ object.value.type === TypeTag.Dictionary &&
9436
+ property.value.type & object.value.value.key.type) {
9437
+ const value = { type: TypeTag.Null };
9438
+ unionInto(value, object.value.value.value);
9439
+ push({
9440
+ value,
9441
+ embeddedEffects: object.embeddedEffects || property.embeddedEffects,
9442
+ node,
9443
+ });
9444
+ break;
9445
+ }
9446
+ push({
9447
+ value: { type: TypeTag.Any },
9448
+ embeddedEffects: object.embeddedEffects || property.embeddedEffects,
9449
+ node,
9450
+ });
9451
+ }
9452
+ else {
9453
+ const object = popIstate(istate, node.object);
9454
+ pushScopedNameType(istate, node, object.embeddedEffects);
9455
+ }
9456
+ break;
9457
+ case "SequenceExpression": {
9458
+ if (stack.length < node.expressions.length) {
9459
+ throw new Error("Unbalanced stack");
9460
+ }
9461
+ if (node.expressions.length) {
9462
+ const right = popIstate(istate, node.expressions[node.expressions.length - 1]);
9463
+ if (node.expressions.length > 1) {
9464
+ right.embeddedEffects =
9465
+ stack
9466
+ .splice(1 - node.expressions.length)
9467
+ .some(({ embeddedEffects }) => embeddedEffects) ||
9468
+ right.embeddedEffects;
9469
+ }
9470
+ push({
9471
+ value: right.value,
9472
+ embeddedEffects: right.embeddedEffects,
9473
+ node,
9474
+ });
9475
+ }
9476
+ break;
9477
+ }
9478
+ case "AssignmentExpression": {
9479
+ const right = popIstate(istate, node.right);
9480
+ const left = popIstate(istate, node.left);
9481
+ if (node.operator === "=") {
9482
+ push({
9483
+ value: right.value,
9484
+ embeddedEffects: true,
9485
+ node,
9486
+ });
9487
+ }
9488
+ else {
9489
+ push({
9490
+ value: evaluateBinaryTypes(node.operator.slice(0, -1), left.value, right.value),
9491
+ embeddedEffects: true,
9492
+ node,
9493
+ });
9494
+ }
9495
+ break;
9496
+ }
9497
+ case "UpdateExpression": {
9498
+ const right = { type: TypeTag.Number, value: 1 };
9499
+ const left = popIstate(istate, node.argument);
9500
+ push({
9501
+ value: evaluateBinaryTypes(node.operator.slice(1), left.value, right),
9502
+ embeddedEffects: true,
9503
+ node,
9504
+ });
9505
+ break;
9506
+ }
9507
+ case "NewExpression": {
9508
+ const [klass, ..._args] = stack.splice(-1 - node.arguments.length);
9509
+ // we should check the arguments at some point...
9510
+ const obj = { type: TypeTag.Object };
9511
+ if (isExact(klass.value) && klass.value.type === TypeTag.Class) {
9512
+ obj.value = { klass: klass.value };
9513
+ }
9514
+ push({ value: obj, embeddedEffects: true, node });
9515
+ break;
9516
+ }
9517
+ case "CallExpression": {
9518
+ const [callee, ...args] = stack.splice(-1 - node.arguments.length);
9519
+ push({
9520
+ value: evaluateCall(state, node, callee.value, args.map(({ value }) => value)),
9521
+ embeddedEffects: true,
9522
+ node,
9523
+ });
9524
+ break;
9525
+ }
9526
+ // Statements, and other
9527
+ case "VariableDeclarator":
9528
+ case "EnumStringMember":
9529
+ if (node.init)
9530
+ popIstate(istate, node.init);
9531
+ break;
9532
+ case "ExpressionStatement":
9533
+ popIstate(istate, node.expression);
9534
+ break;
9535
+ case "ReturnStatement":
9536
+ if (node.argument) {
9537
+ popIstate(istate, node.argument);
9538
+ }
9539
+ break;
9540
+ case "IfStatement":
9541
+ case "WhileStatement":
9542
+ case "DoWhileStatement":
9543
+ popIstate(istate, node.test);
9544
+ break;
9545
+ case "SwitchStatement":
9546
+ popIstate(istate, node.discriminant);
9547
+ break;
9548
+ case "SwitchCase":
9549
+ if (node.test)
9550
+ popIstate(istate, node.test);
9551
+ break;
9552
+ case "InstanceOfCase": {
9553
+ const klass = popIstate(istate, node.id);
9554
+ push({
9555
+ value: { type: TypeTag.Boolean },
9556
+ embeddedEffects: klass.embeddedEffects,
9557
+ node,
9558
+ });
9559
+ break;
9560
+ }
9561
+ case "BlockStatement":
9562
+ case "BreakStatement":
9563
+ case "ContinueStatement":
9564
+ case "TryStatement":
9565
+ break;
9566
+ case "ThrowStatement":
9567
+ popIstate(istate, node.argument);
9568
+ break;
9569
+ case "ForStatement":
9570
+ if (node.update)
9571
+ popIstate(istate, node.update);
9572
+ if (node.test)
9573
+ popIstate(istate, node.test);
9574
+ if (node.init && node.init.type !== "VariableDeclaration") {
9575
+ popIstate(istate, node.init);
9576
+ }
9577
+ break;
9578
+ case "ImportModule":
9579
+ popIstate(istate, node.id);
9580
+ break;
9581
+ case "Using":
9582
+ if (node.as)
9583
+ popIstate(istate, node.as);
9584
+ popIstate(istate, node.id);
9585
+ break;
9586
+ case "ClassDeclaration":
9587
+ case "EnumDeclaration":
9588
+ case "FunctionDeclaration":
9589
+ case "ModuleDeclaration":
9590
+ case "TypedefDeclaration":
9591
+ case "VariableDeclaration":
9592
+ case "Program":
9593
+ case "TypeSpecList":
9594
+ case "CatchClause":
9595
+ case "CatchClauses":
9596
+ case "EnumStringBody":
9597
+ case "Property":
9598
+ case "AttributeList":
9599
+ case "Attributes":
9600
+ case "TypeSpecPart":
9601
+ case "ClassElement":
9602
+ case "ClassBody":
9603
+ case "MethodDefinition":
9604
+ case "Block":
9605
+ case "Line":
9606
+ case "MultiLine":
9607
+ break;
9608
+ default:
9609
+ unhandledType(node);
9610
+ }
9611
+ }
9612
+ function roundToFloat(value) {
9613
+ return new Float32Array([value])[0];
9614
+ }
9615
+
9616
+ ;// CONCATENATED MODULE: ./src/type-flow.ts
9617
+
9618
+
9619
+
9620
+
9621
+
9622
+
9623
+
9624
+
9625
+ const type_flow_logging = true;
9626
+ function type_flow_buildTypeInfo(state, func) {
9627
+ if (!func.node.body || !func.stack)
9628
+ return;
9629
+ const { graph } = buildDataFlowGraph(state, func, () => false, false, true);
9630
+ state = { ...state, stack: func.stack };
9631
+ return propagateTypes(state, func, graph);
9632
+ }
9633
+ function mergeTypeState(to, from) {
9634
+ let changes = false;
9635
+ from.forEach((v, k) => {
9636
+ const tov = to.get(k);
9637
+ let result;
9638
+ if (tov) {
9639
+ if (!unionInto((result = cloneType(tov)), v))
9640
+ return;
9641
+ }
9642
+ else {
9643
+ result = v;
9644
+ }
9645
+ to.set(k, result);
9646
+ changes = true;
9647
+ });
9648
+ return changes;
9649
+ }
9650
+ function printBlockHeader(block) {
9651
+ console.log(block.order, `(${block.node?.loc?.source || "??"}:${block.node?.loc?.start.line || "??"})`, `Preds: ${(block.preds || [])
9652
+ .map((block) => block.order)
9653
+ .join(", ")}`);
9654
+ }
9655
+ function printBlockEvents(block, typeMap) {
9656
+ (0,external_util_cjs_namespaceObject.forEach)(block.events, (event) => event.type !== "exn" &&
9657
+ console.log(` ${event.type}: ${event.decl ? declFullName(event.decl) : "??"} ${event.type === "ref" && typeMap && typeMap.has(event.node)
9658
+ ? display(typeMap.get(event.node))
9659
+ : ""}`));
9660
+ }
9661
+ function printBlockTrailer(block) {
9662
+ console.log(`Succs: ${(block.succs || [])
9663
+ .map((block) => block.order)
9664
+ .join(", ")} ExSucc: ${block.exsucc ? block.exsucc.order : ""}`);
9665
+ }
9666
+ function printBlockState(block, state) {
9667
+ state.forEach((value, key) => {
9668
+ console.log(`${(0,external_util_cjs_namespaceObject.map)(key, (k) => {
9669
+ if (k.type === "Literal") {
9670
+ return k.raw;
9671
+ }
9672
+ else if ((0,external_api_cjs_namespaceObject.isStateNode)(k)) {
9673
+ return k.fullName;
9674
+ }
9675
+ else if (k.type === "BinaryExpression") {
9676
+ return k.left.name;
9677
+ }
9678
+ else if (k.type === "Identifier") {
9679
+ return k.name;
9680
+ }
9681
+ else if (k.type === "EnumStringMember") {
9682
+ return k.id.name;
9683
+ }
9684
+ return "<unknown>";
9685
+ }).join("|")} = ${display(value)}`);
9686
+ });
9687
+ }
9688
+ function propagateTypes(state, func, graph) {
9689
+ // We want to traverse the blocks in reverse post order, in
9690
+ // order to propagate the "availability" of the types.
9691
+ const order = getPostOrder(graph).reverse();
9692
+ const queue = new DataflowQueue();
9693
+ const blockStates = order.map((block, i) => {
9694
+ block.order = i;
9695
+ queue.enqueue(block);
9696
+ return new Map();
9697
+ });
9698
+ if (type_flow_logging && process.env["TYPEFLOW_FUNC"] === func.fullName) {
9699
+ order.forEach((block) => {
9700
+ printBlockHeader(block);
9701
+ printBlockEvents(block);
9702
+ printBlockTrailer(block);
9703
+ });
9704
+ }
9705
+ const typeMap = new Map();
9706
+ const istate = {
9707
+ state,
9708
+ typeMap,
9709
+ stack: [],
9710
+ };
9711
+ const modifiableDecl = (decls, callees) => (0,external_util_cjs_namespaceObject.some)(decls, (decl) => decl.type === "VariableDeclarator" &&
9712
+ decl.node.kind === "var" &&
9713
+ !(0,external_api_cjs_namespaceObject.isLocal)(decl) &&
9714
+ (!callees ||
9715
+ callees.some((callee) => functionMayModify(state, callee, decl))));
9716
+ const declInitVal = (decls) => {
9717
+ return (0,external_util_cjs_namespaceObject.reduce)(decls, (result, decl) => {
9718
+ if (decl.type === "Identifier" || decl.type === "BinaryExpression") {
9719
+ // It looks like this can happen due to catch clauses
9720
+ // throw new Error(`Internal error: Unexpected function parameter`);
9721
+ unionInto(result, { type: TypeTag.Any });
9722
+ return result;
9723
+ }
9724
+ const declType = decl.type === "Literal"
9725
+ ? typeFromLiteral(decl)
9726
+ : typeFromTypeStateNode(state, decl, true);
9727
+ unionInto(result, declType);
9728
+ return result;
9729
+ }, { type: TypeTag.Never });
9730
+ };
9731
+ const head = blockStates[0];
9732
+ // set the parameters to their initial types
9733
+ func.node.params.forEach((param) => {
9734
+ head.set(param, param.type === "BinaryExpression"
9735
+ ? typeFromTypespec(state, param.right)
9736
+ : { type: TypeTag.Any });
9737
+ });
9738
+ // set every other modifiable (ie non-local variables that
9739
+ // could be affected by "mod" events) decl to its initial
9740
+ // value too.
9741
+ order.forEach((block) => {
9742
+ (0,external_util_cjs_namespaceObject.forEach)(block.events, (event) => {
9743
+ if (event.type === "ref" &&
9744
+ !head.has(event.decl) &&
9745
+ modifiableDecl(event.decl)) {
9746
+ head.set(event.decl, declInitVal(event.decl));
9747
+ }
9748
+ });
9749
+ });
9750
+ while (!queue.empty()) {
9751
+ const top = queue.dequeue();
9752
+ if (top.order === undefined) {
9753
+ throw new Error(`Unreachable block was visited!`);
9754
+ }
9755
+ const curState = new Map(blockStates[top.order]);
9756
+ if (top.events) {
9757
+ for (let i = 0; i < top.events.length; i++) {
9758
+ const event = top.events[i];
9759
+ if (event.mayThrow && top.exsucc) {
9760
+ const succState = blockStates[top.exsucc.order];
9761
+ if (succState) {
9762
+ if (mergeTypeState(succState, curState)) {
9763
+ queue.enqueue(top.exsucc);
9764
+ }
9765
+ }
9766
+ }
9767
+ switch (event.type) {
9768
+ case "ref": {
9769
+ let curType = curState.get(event.decl);
9770
+ if (!curType) {
9771
+ curState.set(event.decl, (curType = declInitVal(event.decl)));
9772
+ }
9773
+ typeMap.set(event.node, curType);
9774
+ break;
9775
+ }
9776
+ case "mod": {
9777
+ curState.forEach((_type, decls) => {
9778
+ if (modifiableDecl(decls, event.callees)) {
9779
+ curState.set(decls, declInitVal(decls));
9780
+ }
9781
+ });
9782
+ if (event.node.type === "CallExpression") {
9783
+ typeMap.set(event.node, interp_evaluate(istate, event.node).value);
9784
+ }
9785
+ break;
9786
+ }
9787
+ case "def": {
9788
+ const beforeType = curState.get(event.decl);
9789
+ const lval = event.node.type === "UpdateExpression"
9790
+ ? event.node.argument
9791
+ : event.node.type === "AssignmentExpression"
9792
+ ? event.node.left
9793
+ : null;
9794
+ if (beforeType && lval) {
9795
+ typeMap.set(lval, beforeType);
9796
+ }
9797
+ const expr = event.node.type === "VariableDeclarator"
9798
+ ? event.node.init || null
9799
+ : event.node;
9800
+ if (expr) {
9801
+ const type = interp_evaluate(istate, expr);
9802
+ curState.set(event.decl, type.value);
9803
+ }
9804
+ else {
9805
+ curState.set(event.decl, { type: TypeTag.Any });
9806
+ }
9807
+ break;
9808
+ }
9809
+ }
9810
+ }
9811
+ }
9812
+ top.succs?.forEach((succ) => {
9813
+ if (succ.order == null) {
9814
+ throw new Error("Unreachable block was visited");
9815
+ }
9816
+ if (mergeTypeState(blockStates[succ.order], curState)) {
9817
+ queue.enqueue(succ);
9818
+ }
9819
+ });
9820
+ }
9821
+ if (type_flow_logging && process.env["TYPEFLOW_FUNC"] === func.fullName) {
9822
+ order.forEach((block) => {
9823
+ printBlockHeader(block);
9824
+ printBlockState(block, blockStates[block.order]);
9825
+ printBlockEvents(block, typeMap);
9826
+ printBlockTrailer(block);
9827
+ });
9828
+ console.log("====== TypeMap =====");
9829
+ typeMap.forEach((value, key) => {
9830
+ console.log(`${(0,external_api_cjs_namespaceObject.formatAst)(key)} = ${display(value)}`);
9831
+ });
9832
+ }
9833
+ return istate;
9834
+ }
9835
+
9836
+ ;// CONCATENATED MODULE: ./src/type-flow/could-be.ts
9837
+
9838
+
9839
+
9840
+
9841
+ /*
9842
+ * Determine whether a value conforming to a's type could also
9843
+ * be a value conforming to b's type.
9844
+ *
9845
+ * This is symmetric, and a subtypeOf b, or b subtypeOf a implies
9846
+ * a couldBe b.
9847
+ */
9848
+ function couldBe(a, b) {
9849
+ const common = a.type & b.type & ~TypeTag.Typedef;
9850
+ if (common) {
9851
+ if (a.value == null)
9852
+ return true;
9853
+ if (b.value == null)
9854
+ return true;
9855
+ let result = false;
9856
+ forEachUnionComponent(a, common, (bit, avalue) => {
9857
+ if (avalue == null) {
9858
+ result = true;
9859
+ return false;
9860
+ }
9861
+ const bvalue = getUnionComponent(b, bit);
9862
+ if (bvalue == null || couldBeValue(bit, avalue, bvalue)) {
9863
+ result = true;
9864
+ return false;
9865
+ }
9866
+ return true;
9867
+ });
9868
+ if (result)
9869
+ return true;
9870
+ }
9871
+ if ((a.type & TypeTag.Enum && b.type & (TypeTag.Numeric | TypeTag.String)) ||
9872
+ (b.type & TypeTag.Enum && a.type & (TypeTag.Numeric | TypeTag.String))) {
9873
+ return true;
9874
+ }
9875
+ if (a.type & TypeTag.Object &&
9876
+ b.type & ObjectLikeTagsConst &&
9877
+ getObjectValue(a) == null) {
9878
+ /*
9879
+ * converting Number, String etc to and from Object is ok,
9880
+ * because they *are* subtypes of Object. But converting
9881
+ * them from `Object<something>` is not, because `something`
9882
+ * will never be Number, String, etc.
9883
+ *
9884
+ * So we only add Object when the other side has an unqualified
9885
+ * object type.
9886
+ */
9887
+ return true;
9888
+ }
9889
+ if (b.type & TypeTag.Object &&
9890
+ a.type & ObjectLikeTagsConst &&
9891
+ getObjectValue(b) == null) {
9892
+ return true;
9893
+ }
9894
+ const checkTypdef = (t, other) => {
9895
+ const typedef = getUnionComponent(t, TypeTag.Typedef);
9896
+ return (typedef &&
9897
+ (0,external_util_cjs_namespaceObject.some)(typedef, (td) => {
9898
+ if (!td.resolvedType) {
9899
+ throw new Error(`No resolved type for ${td.fullName} in 'couldBe'`);
9900
+ }
9901
+ return couldBe(td.resolvedType, other);
9902
+ }));
9903
+ };
9904
+ if (a.type & TypeTag.Typedef && checkTypdef(a, b)) {
9905
+ return true;
9906
+ }
9907
+ if (b.type & TypeTag.Typedef && checkTypdef(b, a)) {
9908
+ return true;
9909
+ }
9910
+ return false;
9911
+ }
9912
+ function couldBeValue(bit, avalue, bvalue) {
9913
+ switch (bit) {
9914
+ case TypeTag.Null:
9915
+ case TypeTag.False:
9916
+ case TypeTag.True:
9917
+ case TypeTag.Typedef:
9918
+ throw new Error(`Unexpected TypeTag '${TypeTag[bit]}'`);
9919
+ case TypeTag.Number:
9920
+ case TypeTag.Long:
9921
+ case TypeTag.Float:
9922
+ case TypeTag.Double:
9923
+ case TypeTag.String:
9924
+ case TypeTag.Char:
9925
+ case TypeTag.Symbol:
9926
+ return avalue === bvalue;
9927
+ case TypeTag.Array:
9928
+ return couldBe(avalue, bvalue);
9929
+ case TypeTag.Dictionary: {
9930
+ const adict = avalue;
9931
+ const bdict = bvalue;
9932
+ return couldBe(adict.key, bdict.key) && couldBe(adict.value, bdict.value);
9933
+ }
9934
+ case TypeTag.Module:
9935
+ case TypeTag.Function: {
9936
+ const asd = avalue;
9937
+ const bsd = bvalue;
9938
+ // quadratic :-(
9939
+ return (0,external_util_cjs_namespaceObject.some)(asd, (sna) => (0,external_util_cjs_namespaceObject.some)(bsd, (snb) => sna === snb));
9940
+ }
9941
+ case TypeTag.Class: {
9942
+ const asd = avalue;
9943
+ const bsd = bvalue;
9944
+ return (0,external_util_cjs_namespaceObject.some)(asd, (sna) => {
9945
+ const superA = (0,external_api_cjs_namespaceObject.getSuperClasses)(sna);
9946
+ return (0,external_util_cjs_namespaceObject.some)(bsd, (snb) => {
9947
+ if (sna === snb || (superA && superA.has(snb))) {
9948
+ return true;
9949
+ }
9950
+ const superB = (0,external_api_cjs_namespaceObject.getSuperClasses)(snb);
9951
+ return superB && superB.has(sna);
9952
+ });
9953
+ });
9954
+ }
9955
+ case TypeTag.Object: {
9956
+ const aobj = avalue;
9957
+ const bobj = bvalue;
9958
+ return couldBe(aobj.klass, bobj.klass) && couldBeObj(aobj.obj, bobj.obj);
9959
+ }
9960
+ case TypeTag.Enum: {
9961
+ const aenum = avalue;
9962
+ const benum = bvalue;
9963
+ return (aenum.enum === benum.enum &&
9964
+ (!aenum.value || !benum.value || couldBe(aenum.value, benum.value)));
9965
+ }
9966
+ default:
9967
+ unhandledType(bit);
9968
+ }
9969
+ }
9970
+ function couldBeObj(a, b) {
9971
+ if (!a || !b)
9972
+ return true;
9973
+ return Object.entries(a).every(([key, value]) => {
9974
+ if (!(0,external_api_cjs_namespaceObject.hasProperty)(b, key))
9975
+ return true;
9976
+ return couldBe(value, b[key]);
9977
+ });
9978
+ }
9979
+
9980
+ ;// CONCATENATED MODULE: ./src/type-flow/optimize.ts
9981
+
9982
+
9983
+
9984
+
9985
+
9986
+
9987
+
9988
+
9989
+ function optimizeFunction(state, func) {
9990
+ const istate = buildTypeInfo(state, func);
9991
+ if (!istate)
9992
+ return;
9993
+ evaluate({
9994
+ ...istate,
9995
+ pre(node) {
9996
+ return beforeEvaluate(this, node);
9997
+ },
9998
+ post(node) {
9999
+ return afterEvaluate(this, node);
10000
+ },
10001
+ }, func.node.body);
10002
+ }
10003
+ function beforeEvaluate(istate, node) {
10004
+ switch (node.type) {
10005
+ case "ConditionalExpression": {
10006
+ let alternate = popIstate(istate, node.alternate);
10007
+ let consequent = popIstate(istate, node.consequent);
10008
+ const test = popIstate(istate, node.test);
10009
+ const result = mustBeTrue(test.value)
10010
+ ? true
10011
+ : mustBeFalse(test.value)
10012
+ ? false
10013
+ : null;
10014
+ if (result !== null) {
10015
+ if (!test.embeddedEffects) {
10016
+ const arg = result ? consequent : alternate;
10017
+ istate.stack.push(arg);
10018
+ return result ? node.consequent : node.alternate;
10019
+ }
10020
+ }
10021
+ if (node.alternate &&
10022
+ node.test.type === "UnaryExpression" &&
10023
+ node.test.operator === "!" &&
10024
+ test.value.type === TypeTag.Boolean) {
10025
+ const alternateNode = node.alternate;
10026
+ node.alternate = node.consequent;
10027
+ node.consequent = alternateNode;
10028
+ const tmp = alternate;
10029
+ alternate = consequent;
10030
+ consequent = tmp;
10031
+ test.node = node.test = node.test.argument;
10032
+ }
10033
+ if (test.value.type === TypeTag.Boolean &&
10034
+ ((consequent.value.type === TypeTag.True &&
10035
+ alternate.value.type === TypeTag.False) ||
10036
+ (consequent.value.type === TypeTag.False &&
10037
+ alternate.value.type === TypeTag.True)) &&
10038
+ !consequent.embeddedEffects &&
10039
+ !alternate.embeddedEffects) {
10040
+ if (consequent.value.type === TypeTag.False) {
10041
+ test.node = wrap({
10042
+ type: "UnaryExpression",
10043
+ operator: "!",
10044
+ argument: node.test,
10045
+ prefix: true,
10046
+ }, test.node.loc);
10047
+ }
10048
+ istate.stack.push(test);
10049
+ return test.node;
10050
+ }
10051
+ istate.stack.push(test, consequent, alternate);
10052
+ break;
10053
+ }
10054
+ case "IfStatement": {
10055
+ const test = popIstate(istate, node.test);
10056
+ const result = mustBeTrue(test.value)
10057
+ ? true
10058
+ : mustBeFalse(test.value)
10059
+ ? false
10060
+ : null;
10061
+ if (result !== null) {
10062
+ const rep = result ? node.consequent : node.alternate || false;
10063
+ if (!test.embeddedEffects) {
10064
+ return rep;
10065
+ }
10066
+ const estmt = wrap({ type: "ExpressionStatement", expression: node.test }, node.loc);
10067
+ if (!rep) {
10068
+ return estmt;
10069
+ }
10070
+ if (rep.type === "BlockStatement") {
10071
+ rep.body.unshift(estmt);
10072
+ return rep;
10073
+ }
10074
+ }
10075
+ if (node.alternate &&
10076
+ node.test.type === "UnaryExpression" &&
10077
+ node.test.operator === "!" &&
10078
+ test.value.type === TypeTag.Boolean) {
10079
+ const alternate = node.alternate;
10080
+ node.alternate = node.consequent;
10081
+ node.consequent = alternate;
10082
+ test.node = node.test = node.test.argument;
10083
+ }
10084
+ istate.stack.push(test);
10085
+ break;
10086
+ }
10087
+ case "WhileStatement":
10088
+ case "DoWhileStatement": {
10089
+ const test = popIstate(istate, node.test);
10090
+ if (!test.embeddedEffects) {
10091
+ if (mustBeFalse(test.value)) {
10092
+ return node.type === "WhileStatement" ? false : node.body;
10093
+ }
10094
+ }
10095
+ istate.stack.push(test);
10096
+ break;
10097
+ }
10098
+ case "BinaryExpression":
10099
+ if (node.operator === "has" &&
10100
+ node.right.type === "UnaryExpression" &&
10101
+ node.right.operator === ":") {
10102
+ const [left, right] = istate.stack.slice(-2);
10103
+ if (left.embeddedEffects ||
10104
+ right.embeddedEffects ||
10105
+ !hasValue(left.value) ||
10106
+ !hasValue(right.value) ||
10107
+ !(left.value.type & (TypeTag.Module | TypeTag.Class))) {
10108
+ break;
10109
+ }
10110
+ const id = node.right.argument;
10111
+ if ((0,external_util_cjs_namespaceObject.every)(left.value.value, (m) => {
10112
+ if (hasProperty(m.decls, id.name))
10113
+ return false;
10114
+ // This is overkill, since we've already looked up
10115
+ // node.left, but the actual lookup rules are complicated,
10116
+ // and embedded within state.lookup; so just defer to that.
10117
+ return (istate.state.lookup({
10118
+ type: "MemberExpression",
10119
+ object: node.left,
10120
+ property: id,
10121
+ computed: false,
10122
+ })[1] == null);
10123
+ })) {
10124
+ popIstate(istate, node.right);
10125
+ popIstate(istate, node.left);
10126
+ const rep = wrap({ type: "Literal", value: false, raw: "false" }, node.loc);
10127
+ istate.stack.push({
10128
+ value: { type: TypeTag.False },
10129
+ embeddedEffects: false,
10130
+ node: rep,
10131
+ });
10132
+ return rep;
10133
+ }
10134
+ }
10135
+ else {
10136
+ const rep = tryCommuteAndAssociate(istate, node);
10137
+ if (rep)
10138
+ return rep;
10139
+ const level = istate.state.config?.checkTypes === "OFF"
10140
+ ? null
10141
+ : istate.state.config?.checkTypes || "WARNING";
10142
+ if (!level)
10143
+ break;
10144
+ if (node.operator === "==" || node.operator === "!=") {
10145
+ const [{ value: left }, { value: right }] = istate.stack.slice(-2);
10146
+ if ((left.type === TypeTag.Null && !(right.type & TypeTag.Null)) ||
10147
+ (right.type === TypeTag.Null && !(left.type & TypeTag.Null))) {
10148
+ (0,external_api_cjs_namespaceObject.diagnostic)(istate.state, node.loc, `This comparison seems redundant because ${(0,external_api_cjs_namespaceObject.formatAst)(left.type === TypeTag.Null ? node.right : node.left)} should never be null`, level);
10149
+ }
10150
+ }
10151
+ else if (node.operator === "as") {
10152
+ const [{ value: left }] = istate.stack.slice(-1);
10153
+ const right = typeFromTypespec(istate.state, node.right);
10154
+ if (!couldBe(left, right)) {
10155
+ (0,external_api_cjs_namespaceObject.diagnostic)(istate.state, node.loc, `The type ${display(left)} cannot be converted to ${display(right)} because they have nothing in common`, level);
10156
+ }
10157
+ }
10158
+ }
10159
+ break;
10160
+ case "LogicalExpression": {
10161
+ const [left, right] = istate.stack.slice(-2);
10162
+ const isAnd = node.operator === "&&" || node.operator === "and";
10163
+ if (isAnd ? mustBeFalse(left.value) : mustBeTrue(left.value)) {
10164
+ popIstate(istate, node.right);
10165
+ return node.left;
10166
+ }
10167
+ if (
10168
+ // bail if left could be anything other than bool/integer
10169
+ (left.value.type &
10170
+ (TypeTag.Boolean | TypeTag.Number | TypeTag.Long)) !==
10171
+ left.value.type ||
10172
+ // bail if left could be boolean AND it could be integer
10173
+ (left.value.type & TypeTag.Boolean &&
10174
+ left.value.type & (TypeTag.Number | TypeTag.Long)) ||
10175
+ // bail if right doesn't match left
10176
+ (right.value.type &
10177
+ (left.value.type & TypeTag.Boolean
10178
+ ? TypeTag.Boolean
10179
+ : TypeTag.Number | TypeTag.Long)) !==
10180
+ right.value.type) {
10181
+ break;
10182
+ }
10183
+ if (right.value.type === (isAnd ? TypeTag.True : TypeTag.False) &&
10184
+ !right.embeddedEffects &&
10185
+ (left.value.type & TypeTag.Boolean) === left.value.type) {
10186
+ popIstate(istate, node.right);
10187
+ return node.left;
10188
+ }
10189
+ if (isAnd ? !mustBeTrue(left.value) : !mustBeFalse(left.value)) {
10190
+ break;
10191
+ }
10192
+ if (!(left.value.type & ~TypeTag.Boolean)) {
10193
+ // the left type is boolean, so the
10194
+ // `&` or `|` would be a no-op. We
10195
+ // need to check that its side-effect
10196
+ // free. Just cheap checks for now.
10197
+ if (!left.embeddedEffects) {
10198
+ popIstate(istate, node.right);
10199
+ popIstate(istate, node.left);
10200
+ istate.stack.push(right);
10201
+ return node.right;
10202
+ }
10203
+ }
10204
+ const rep = node;
10205
+ rep.type = "BinaryExpression";
10206
+ rep.operator = isAnd ? "&" : "|";
10207
+ break;
10208
+ }
10209
+ }
10210
+ return null;
10211
+ }
10212
+ function afterEvaluate(istate, node) {
10213
+ switch (node.type) {
10214
+ case "IfStatement":
10215
+ if (node.alternate &&
10216
+ node.alternate.type === "BlockStatement" &&
10217
+ !node.alternate.body.length) {
10218
+ delete node.alternate;
10219
+ }
10220
+ break;
10221
+ }
10222
+ if (isExpression(node) && node.type !== "Literal") {
10223
+ const top = istate.stack[istate.stack.length - 1];
10224
+ if (!top.embeddedEffects && hasValue(top.value)) {
10225
+ const rep = mcExprFromType(top.value);
10226
+ if (rep) {
10227
+ top.node = rep;
10228
+ return withLoc(rep, node, node);
10229
+ }
10230
+ }
10231
+ }
10232
+ return null;
10233
+ }
10234
+ function identity(istate, node, left, right, allowedTypes, target) {
10235
+ if (hasValue(right.value) &&
10236
+ right.value.type & allowedTypes &&
10237
+ !(left.value.type & ~allowedTypes) &&
10238
+ Number(right.value.value) === target) {
10239
+ // a +/- 0 => a
10240
+ // but we still need to check that the type of the zero
10241
+ // doesn't change the type of the result.
10242
+ if (right.value.type === TypeTag.Number ||
10243
+ (right.value.type === TypeTag.Long &&
10244
+ !(left.value.type & ~(TypeTag.Long | TypeTag.Double))) ||
10245
+ (right.value.type === TypeTag.Float &&
10246
+ !(left.value.type & ~(TypeTag.Float | TypeTag.Double))) ||
10247
+ (right.value.type === TypeTag.Double &&
10248
+ left.value.type === TypeTag.Double)) {
10249
+ istate.stack.pop();
10250
+ return node.left;
10251
+ }
10252
+ }
10253
+ return null;
10254
+ }
10255
+ function zero(istate, node, left, right, allowedTypes, target) {
10256
+ if (hasValue(right.value) &&
10257
+ right.value.type & allowedTypes &&
10258
+ !(left.value.type & ~allowedTypes) &&
10259
+ Number(right.value.value) === target) {
10260
+ // a * 0 => 0
10261
+ // but we still need to check that the type of a
10262
+ // doesn't change the type of the zero.
10263
+ if ((right.value.type === TypeTag.Number &&
10264
+ left.value.type === TypeTag.Number) ||
10265
+ (right.value.type === TypeTag.Long &&
10266
+ !(left.value.type & ~(TypeTag.Long | TypeTag.Number))) ||
10267
+ (right.value.type === TypeTag.Float &&
10268
+ !(left.value.type & ~(TypeTag.Float | TypeTag.Number))) ||
10269
+ right.value.type === TypeTag.Double) {
10270
+ istate.stack.splice(-2, 1);
10271
+ return node.right;
10272
+ }
10273
+ }
10274
+ return null;
10275
+ }
10276
+ function tryIdentity(istate, node, left, right) {
10277
+ switch (node.operator) {
10278
+ case "+":
10279
+ case "-": {
10280
+ const rep = identity(istate, node, left, right, TypeTag.Numeric, 0);
10281
+ if (rep)
10282
+ return rep;
10283
+ if (node.right.type === "UnaryExpression" &&
10284
+ node.right.operator === "-") {
10285
+ // We can convert a +/- -b to a -/+ b, but we have to know
10286
+ // something about the types. eg if b is Number, with the
10287
+ // value -2^31, negating b will leave the value as -2^31.
10288
+ // This doesn't matter if the a is also Number, but if
10289
+ // a might be Long, Float or Double, we would change the
10290
+ // result. Similarly for Long and -2^63
10291
+ if (!((left.value.type | right.value.type) & ~TypeTag.Numeric) &&
10292
+ (right.value.type & TypeTag.Number // Negating -2^31 goes wrong if left is a wider type
10293
+ ? !(left.value.type &
10294
+ (TypeTag.Long | TypeTag.Float | TypeTag.Double))
10295
+ : right.value.type & TypeTag.Long // Negating -2^63 goes wrong if left is a float/double
10296
+ ? !(left.value.type & (TypeTag.Float | TypeTag.Double))
10297
+ : true)) {
10298
+ right.value = evaluateBinaryTypes("-", { type: TypeTag.Number, value: 0 }, right.value);
10299
+ right.node = node.right.argument;
10300
+ node.right = right.node;
10301
+ node.operator = node.operator === "+" ? "-" : "+";
10302
+ }
10303
+ }
10304
+ break;
10305
+ }
10306
+ case "*": {
10307
+ const rep = zero(istate, node, left, right, TypeTag.Numeric, 0);
10308
+ if (rep)
10309
+ return rep;
10310
+ // fall through
10311
+ }
10312
+ case "/": {
10313
+ const rep = identity(istate, node, left, right, TypeTag.Numeric, 1);
10314
+ if (rep)
10315
+ return rep;
10316
+ break;
10317
+ }
10318
+ case "|": {
10319
+ const rep = zero(istate, node, left, right, TypeTag.Number | TypeTag.Long, -1);
10320
+ if (rep)
10321
+ return rep;
10322
+ // fall through
10323
+ }
10324
+ case "^": {
10325
+ const rep = identity(istate, node, left, right, TypeTag.Number | TypeTag.Long, 0);
10326
+ if (rep)
10327
+ return rep;
10328
+ break;
10329
+ }
10330
+ case "&": {
10331
+ const rep = zero(istate, node, left, right, TypeTag.Number | TypeTag.Long, 0) ||
10332
+ identity(istate, node, left, right, TypeTag.Number | TypeTag.Long, -1);
10333
+ if (rep)
10334
+ return rep;
10335
+ break;
10336
+ }
10337
+ }
10338
+ return null;
10339
+ }
10340
+ function tryCommuteAndAssociate(istate, node) {
10341
+ let [left, right] = istate.stack.slice(-2);
10342
+ // no need to do anything if both sides are constants
10343
+ if (!right || (hasValue(left.value) && hasValue(right.value))) {
10344
+ return null;
10345
+ }
10346
+ switch (node.operator) {
10347
+ case "+":
10348
+ // Addition is only commutative/associative if both arguments
10349
+ // are numeric, or one argument is Number, and the other is Char
10350
+ if (left.value.type & ~(TypeTag.Numeric | TypeTag.Char) ||
10351
+ right.value.type & ~(TypeTag.Numeric | TypeTag.Char) ||
10352
+ left.value.type & right.value.type & TypeTag.Char) {
10353
+ break;
10354
+ }
10355
+ // fallthrough
10356
+ case "*":
10357
+ case "&":
10358
+ case "|":
10359
+ case "^":
10360
+ // flip the left argument to the right if the left has
10361
+ // a known value, but the right does not, or if the
10362
+ // top operator is additive, and the left operand is
10363
+ // negated, and the right operand is not.
10364
+ if (!left.embeddedEffects &&
10365
+ (hasValue(left.value) ||
10366
+ (!right.embeddedEffects &&
10367
+ node.operator === "+" &&
10368
+ node.left.type === "UnaryExpression" &&
10369
+ node.left.operator === "-" &&
10370
+ (node.right.type !== "UnaryExpression" ||
10371
+ node.right.operator !== "-")))) {
10372
+ const l = node.left;
10373
+ node.left = node.right;
10374
+ node.right = l;
10375
+ istate.stack.splice(-2, 2, right, left);
10376
+ const r = right;
10377
+ right = left;
10378
+ left = r;
10379
+ }
10380
+ // fallthrough
10381
+ case "-":
10382
+ if (tryReAssociate(istate, node, left, right)) {
10383
+ [left, right] = istate.stack.slice(-2);
10384
+ }
10385
+ }
10386
+ return tryIdentity(istate, node, left, right);
10387
+ }
10388
+ /*
10389
+ * Try to reorder (a op K1) op K2 => a op (K1 op K2),
10390
+ * and fold K1 op K2.
10391
+ *
10392
+ * Failing that,
10393
+ * Try to reorder (a op K1) op (b op K2) as
10394
+ * (a op b) op (K1 op K2), and fold K1 op K2.
10395
+ *
10396
+ * Failing that,
10397
+ * Try to reorder (a op K) op b => (a op b) op K
10398
+ * so that constants float up and to the right.
10399
+ * This helps because now ((a op K1) op b) op K2
10400
+ * becomes ((a op b) op K1) op K2, and we can
10401
+ * fold K1 op K2 by the first transformation.
10402
+ *
10403
+ * Floating point arithmetic isn't really associative
10404
+ * though, so we mostly suppress this when Floats
10405
+ * and Doubles may be involved; except that
10406
+ * (a + K1) + K2 can be safely converted to
10407
+ * a + (K1 + K2) if K1 and K2 have the same sign.
10408
+ */
10409
+ function tryReAssociate(istate, node, left, right) {
10410
+ if (node.left.type !== "BinaryExpression" ||
10411
+ (node.left.operator !== node.operator &&
10412
+ !(node.operator === "+" && node.left.operator === "-") &&
10413
+ !(node.operator === "-" && node.left.operator === "+"))) {
10414
+ return false;
10415
+ }
10416
+ const lr = ast_getLiteralNode(node.left.right);
10417
+ if (!lr)
10418
+ return false;
10419
+ const leftRight = interp_evaluate(istate, lr);
10420
+ if (!hasValue(leftRight.value))
10421
+ return false;
10422
+ if (hasValue(right.value)) {
10423
+ // (ll + lr) + r => ll + (r + lr)
10424
+ // (ll - lr) - r => ll - (r + lr)
10425
+ // (ll + lr) - r => ll + (r - lr)
10426
+ // (ll - lr) + r => ll - (r - lr)
10427
+ const tmpNode = {
10428
+ type: "BinaryExpression",
10429
+ operator: node.operator === "+" || node.operator === "-"
10430
+ ? node.operator === node.left.operator
10431
+ ? "+"
10432
+ : "-"
10433
+ : node.operator,
10434
+ left: node.right,
10435
+ right: node.left.right,
10436
+ };
10437
+ if (tmpNode.operator === "+" || tmpNode.operator === "-") {
10438
+ if (leftRight.value.type & (TypeTag.Float | TypeTag.Double) ||
10439
+ right.value.type & (TypeTag.Float | TypeTag.Double)) {
10440
+ // we don't want to fold "a + 1.0 - 1.0" because
10441
+ // it could be there for rounding purposes
10442
+ const lsign = right.value.value < 0;
10443
+ const rsign = leftRight.value.value < 0 === (tmpNode.operator === "+");
10444
+ if (lsign !== rsign)
10445
+ return false;
10446
+ }
10447
+ }
10448
+ const repType = interp_evaluate(istate, tmpNode);
10449
+ if (!hasValue(repType.value))
10450
+ return false;
10451
+ const repNode = mcExprFromType(repType.value);
10452
+ if (!repNode)
10453
+ return false;
10454
+ left.node = node.left = node.left.left;
10455
+ node.right = repNode;
10456
+ istate.stack.splice(-1, 1, repType);
10457
+ repType.node = repNode;
10458
+ return true;
10459
+ }
10460
+ if (leftRight.value.type !== left.value.type ||
10461
+ leftRight.value.type !== right.value.type ||
10462
+ leftRight.value.type & (TypeTag.Float | TypeTag.Double)) {
10463
+ return false;
10464
+ }
10465
+ if (node.right.type === "BinaryExpression" &&
10466
+ (node.right.operator === node.operator ||
10467
+ ((node.operator === "+" || node.operator === "-") &&
10468
+ (node.right.operator === "+" || node.right.operator === "-")))) {
10469
+ // (a + K1) + (b + K2) => (a + b) + (K1 + K2)
10470
+ const rr = ast_getLiteralNode(node.right.right);
10471
+ if (!rr)
10472
+ return false;
10473
+ const rightRight = interp_evaluate(istate, rr);
10474
+ if (!hasValue(rightRight.value))
10475
+ return false;
10476
+ const rightOp = node.operator === "+" || node.operator === "-"
10477
+ ? ((node.left.operator === "+") === (node.right.operator === "+")) ===
10478
+ (node.operator === "+")
10479
+ ? "+"
10480
+ : "-"
10481
+ : node.operator;
10482
+ const topOp = node.left.operator;
10483
+ const leftOp = node.operator;
10484
+ const rightType = evaluateBinaryTypes(rightOp, leftRight.value, rightRight.value);
10485
+ if (!hasValue(rightType))
10486
+ return false;
10487
+ const repNode = mcExprFromType(rightType);
10488
+ if (!repNode)
10489
+ return false;
10490
+ node.left.right = node.right.left;
10491
+ node.right = repNode;
10492
+ node.left.operator = leftOp;
10493
+ node.operator = topOp;
10494
+ istate.stack.splice(-1, 1, {
10495
+ value: rightType,
10496
+ node: repNode,
10497
+ embeddedEffects: false,
10498
+ });
10499
+ return true;
10500
+ }
10501
+ const op = node.operator;
10502
+ node.operator = node.left.operator;
10503
+ node.left.operator = op;
10504
+ leftRight.node = node.left.right;
10505
+ node.left.right = node.right;
10506
+ node.right = leftRight.node;
10507
+ istate.stack.splice(-1, 1, leftRight);
10508
+ return true;
10509
+ }
10510
+
10511
+ ;// CONCATENATED MODULE: ./src/unused-exprs.ts
10512
+
10513
+
10514
+
10515
+ function cleanupUnusedVars(state, node) {
10516
+ const [parent] = state.stack.slice(-1);
10517
+ if (parent.node !== node) {
10518
+ return;
10519
+ }
10520
+ if (parent.type != "BlockStatement") {
10521
+ throw new Error(`Unexpected parent type '${parent.type}' for local declaration`);
10522
+ }
10523
+ if (parent.decls) {
10524
+ let toRemove = null;
10525
+ Object.values(parent.decls).forEach((decls) => {
10526
+ if (decls.length === 1 &&
10527
+ decls[0].type === "VariableDeclarator" &&
10528
+ !decls[0].used) {
10529
+ if (!toRemove)
10530
+ toRemove = {};
10531
+ toRemove[decls[0].name] = decls[0];
10532
+ }
10533
+ });
10534
+ if (toRemove) {
10535
+ const varDeclarations = new Map();
10536
+ const stack = [];
10537
+ traverseAst(node, (node) => {
10538
+ switch (node.type) {
10539
+ case "SwitchCase":
10540
+ stack.push(node.consequent);
10541
+ break;
10542
+ case "BlockStatement":
10543
+ stack.push(node.body);
10544
+ break;
10545
+ }
10546
+ }, (node) => {
10547
+ switch (node.type) {
10548
+ case "SwitchCase":
10549
+ case "BlockStatement":
10550
+ stack.pop();
10551
+ break;
10552
+ case "VariableDeclaration": {
10553
+ node.declarations.forEach((decl, i) => {
10554
+ const name = (0,external_api_cjs_namespaceObject.variableDeclarationName)(decl.id);
10555
+ if (hasProperty(toRemove, name)) {
10556
+ const info = varDeclarations.get(node);
10557
+ if (info) {
10558
+ info.indices.push(i);
10559
+ }
10560
+ else {
10561
+ varDeclarations.set(node, {
10562
+ parent: stack[stack.length - 1],
10563
+ indices: [i],
10564
+ });
10565
+ }
10566
+ }
10567
+ });
10568
+ break;
7588
10569
  }
7589
10570
  case "ExpressionStatement":
7590
10571
  if (node.expression.type === "AssignmentExpression") {
@@ -7709,6 +10690,9 @@ function cleanupUnusedVars(state, node) {
7709
10690
 
7710
10691
 
7711
10692
 
10693
+
10694
+
10695
+
7712
10696
  function collectClassInfo(state) {
7713
10697
  const toybox = state.stack[0].decls["Toybox"][0];
7714
10698
  const lang = toybox.decls["Lang"][0];
@@ -7786,7 +10770,7 @@ function collectClassInfo(state) {
7786
10770
  funcs.forEach((f) => {
7787
10771
  if (f.type === "FunctionDeclaration" &&
7788
10772
  !(f.attributes & StateNodeAttributes.STATIC)) {
7789
- (0,external_api_cjs_namespaceObject.markInvokeClassMethod)(f);
10773
+ (0,external_api_cjs_namespaceObject.markInvokeClassMethod)(state, f);
7790
10774
  }
7791
10775
  });
7792
10776
  });
@@ -7866,7 +10850,7 @@ async function analyze(fnMap, resourcesMap, manifestXML, config) {
7866
10850
  if (scope.type == "FunctionDeclaration") {
7867
10851
  if (markApi) {
7868
10852
  node.body = null;
7869
- scope.info = (0,external_api_cjs_namespaceObject.getApiFunctionInfo)(scope);
10853
+ scope.info = (0,external_api_cjs_namespaceObject.getApiFunctionInfo)(state, scope);
7870
10854
  delete scope.stack;
7871
10855
  }
7872
10856
  const allFuncs = state.allFunctions;
@@ -7944,7 +10928,7 @@ function reportMissingSymbols(state, config) {
7944
10928
  return false;
7945
10929
  });
7946
10930
  })) {
7947
- diagnostic(state, node.loc, `The expression ${(0,external_api_cjs_namespaceObject.formatAst)(node)} will fail at runtime using sdk-4.1.6`, compiler2DiagnosticType);
10931
+ (0,external_api_cjs_namespaceObject.diagnostic)(state, node.loc, `The expression ${(0,external_api_cjs_namespaceObject.formatAst)(node)} will fail at runtime using sdk-4.1.6`, compiler2DiagnosticType);
7948
10932
  }
7949
10933
  return undefined;
7950
10934
  }
@@ -7954,7 +10938,7 @@ function reportMissingSymbols(state, config) {
7954
10938
  return undefined;
7955
10939
  }
7956
10940
  }
7957
- diagnostic(state, node.loc, `Undefined symbol ${nodeStr || (0,external_api_cjs_namespaceObject.formatAst)(node)}`, diagnosticType);
10941
+ (0,external_api_cjs_namespaceObject.diagnostic)(state, node.loc, `Undefined symbol ${nodeStr || (0,external_api_cjs_namespaceObject.formatAst)(node)}`, diagnosticType);
7958
10942
  return false;
7959
10943
  });
7960
10944
  };
@@ -7993,405 +10977,53 @@ function getLiteralFromDecls(lookupDefns) {
7993
10977
  }
7994
10978
  return null;
7995
10979
  }
7996
- function getLiteralNode(node) {
7997
- if (node == null)
7998
- return null;
7999
- if (node.type == "Literal")
8000
- return node;
8001
- if (node.type == "BinaryExpression" && node.operator == "as") {
8002
- return getLiteralNode(node.left) && node;
8003
- }
8004
- if (node.type == "UnaryExpression") {
8005
- if (node.argument.type != "Literal")
8006
- return null;
8007
- switch (node.operator) {
8008
- case "-": {
8009
- const [arg, type] = getNodeValue(node.argument);
8010
- if (type === "Number" || type === "Long") {
8011
- return replacementLiteral(node, -arg.value, type);
8012
- }
8013
- }
8014
- }
8015
- }
8016
- return null;
8017
- }
8018
- function fullTypeName(state, tsp) {
8019
- if (typeof tsp.name === "string") {
8020
- return tsp.name;
8021
- }
8022
- const [, results] = state.lookupType(tsp.name);
8023
- if (results && results.length === 1 && results[0].results.length === 1) {
8024
- const result = results[0].results[0];
8025
- if ((0,external_api_cjs_namespaceObject.isStateNode)(result)) {
8026
- return result.fullName;
8027
- }
8028
- }
8029
- return null;
8030
- }
8031
- function isBooleanExpression(state, node) {
8032
- switch (node.type) {
8033
- case "Literal":
8034
- return typeof node.value === "boolean";
8035
- case "BinaryExpression":
8036
- switch (node.operator) {
8037
- case "==":
8038
- case "!=":
8039
- case "<=":
8040
- case ">=":
8041
- case "<":
8042
- case ">":
8043
- return true;
8044
- case "as":
8045
- return node.right.ts.length === 1 &&
8046
- node.right.ts[0].type === "TypeSpecPart" &&
8047
- node.right.ts[0].name &&
8048
- fullTypeName(state, node.right.ts[0]) === "$.Toybox.Lang.Boolean"
8049
- ? true
8050
- : false;
8051
- }
8052
- return false;
8053
- case "LogicalExpression":
8054
- return (isBooleanExpression(state, node.left) &&
8055
- isBooleanExpression(state, node.right));
8056
- case "UnaryExpression":
8057
- return node.operator === "!" && isBooleanExpression(state, node.argument);
8058
- }
8059
- return false;
8060
- }
8061
- function roundToFloat(value) {
8062
- return new Float32Array([value])[0];
8063
- }
8064
- function replacementLiteral(arg, value, type) {
8065
- if (value === null) {
8066
- type = "Null";
8067
- }
8068
- else if (typeof value === "boolean") {
8069
- type = "Boolean";
8070
- }
8071
- else if (type === "Number") {
8072
- value = Number(BigInt.asIntN(32, BigInt(value)));
8073
- }
8074
- else if (type === "Long") {
8075
- value = BigInt.asIntN(64, BigInt(value));
8076
- }
8077
- else if (type === "Float") {
8078
- value = roundToFloat(Number(value));
8079
- }
8080
- let raw = type === "String"
8081
- ? JSON.stringify(value)
8082
- : type === "Char"
8083
- ? value === "'"
8084
- ? "'\\''"
8085
- : "'" + JSON.stringify(value).slice(1, -1) + "'"
8086
- : value == null
8087
- ? "null"
8088
- : value.toString();
8089
- if (type === "Long") {
8090
- raw += "l";
8091
- }
8092
- else if (type === "Double") {
8093
- raw += "d";
8094
- }
8095
- else if (type === "Float") {
8096
- if (prettier_plugin_monkeyc_namespaceObject.LiteralIntegerRe.test(raw)) {
8097
- raw += "f";
8098
- }
8099
- else {
8100
- const match = raw.match(/^(-)?(\d*)\.(\d+)(e\d+)?/);
8101
- if (match && match[2].length + match[3].length > 9) {
8102
- for (let l = 9 - match[2].length; l > 0; l--) {
8103
- const s = `${match[1] || ""}${match[2]}.${match[3].substring(0, l)}${match[4] || ""}`;
8104
- if (value !== roundToFloat(parseFloat(s)))
8105
- break;
8106
- raw = s;
8107
- }
8108
- }
8109
- }
8110
- }
8111
- const { start, end, loc } = arg;
8112
- return {
8113
- type: "Literal",
8114
- value,
8115
- raw,
8116
- start,
8117
- end,
8118
- loc,
8119
- };
8120
- }
8121
- function classify(arg) {
8122
- switch (arg) {
8123
- case "Number":
8124
- return { big: false, int: true };
8125
- case "Long":
8126
- return { big: true, int: true };
8127
- case "Float":
8128
- return { big: false, int: false };
8129
- case "Double":
8130
- return { big: true, int: false };
8131
- }
8132
- return null;
8133
- }
8134
- function common_arith_types(left, right) {
8135
- const l = classify(left);
8136
- if (!l)
8137
- return null;
8138
- const r = classify(right);
8139
- if (!r)
8140
- return null;
8141
- if (l.big || r.big) {
8142
- return l.int && r.int
8143
- ? ["Long", (v) => BigInt.asIntN(64, BigInt(v))]
8144
- : ["Double", (v) => Number(v)];
8145
- }
8146
- else {
8147
- return l.int && r.int
8148
- ? ["Number", (v) => BigInt.asIntN(32, BigInt(v))]
8149
- : ["Float", (v) => roundToFloat(Number(v))];
8150
- }
8151
- }
8152
- function common_bitwise_types(left, right) {
8153
- if (left === "Boolean" && right === "Boolean") {
8154
- return ["Boolean", (v) => (v ? true : false)];
8155
- }
8156
- const l = classify(left);
8157
- if (!l)
8158
- return null;
8159
- const r = classify(right);
8160
- if (!r)
10980
+ function optimizeNode(istate, node) {
10981
+ if (istate.state.inlining)
8161
10982
  return null;
8162
- if (!l.int || !r.int)
8163
- return null;
8164
- return l.big || r.big
8165
- ? ["Long", (v) => BigInt.asIntN(64, BigInt(v))]
8166
- : ["Number", (v) => Number(BigInt.asIntN(32, BigInt(v)))];
8167
- }
8168
- function plus_types(left, right) {
8169
- if (left === "String" || right === "String") {
8170
- // Boolean + String is an error, and
8171
- // Float/Double + String is legal, but its hard to predict
8172
- // the way the float will be formatted (and it won't match
8173
- // what javascript would do by default)
8174
- if (/Float|Double|Boolean/.test(left + right)) {
8175
- return null;
8176
- }
8177
- return ["String", String];
8178
- }
8179
- if (left === "Char" || right === "Char") {
8180
- if (left === right) {
8181
- // adding two chars produces a string
8182
- return ["String", String];
8183
- }
8184
- if (/Number|Long/.test(left + right)) {
8185
- return ["Char", (v) => v];
8186
- }
8187
- }
8188
- return common_arith_types(left, right);
8189
- }
8190
- function shift_mod_types(left, right) {
8191
- const result = common_bitwise_types(left, right);
8192
- if (result && result[0] === "Boolean") {
10983
+ if (istate.state.inType) {
8193
10984
  return null;
8194
10985
  }
8195
- return result;
8196
- }
8197
- function equalsFn(left, right) {
8198
- const lt = typeof left;
8199
- const rt = typeof right;
8200
- return lt === "string" || rt === "string"
8201
- ? // two string literals will compare unequal, becuase string
8202
- // equality is object equality.
8203
- false
8204
- : (lt === "number" || lt === "bigint") &&
8205
- (rt === "number" || rt === "bigint")
8206
- ? // numeric types are compared for value equality
8207
- left == right
8208
- : // otherwise types and values must match
8209
- left === right;
8210
- }
8211
- const operators = {
8212
- "+": {
8213
- typeFn: plus_types,
8214
- valueFn: (left, right) => typeof left === "string" && typeof right !== "string"
8215
- ? String.fromCharCode(left.charCodeAt(0) + Number(right))
8216
- : typeof left !== "string" && typeof right === "string"
8217
- ? String.fromCharCode(right.charCodeAt(0) + Number(left))
8218
- : left + right,
8219
- },
8220
- "-": {
8221
- typeFn: common_arith_types,
8222
- valueFn: (left, right) => left - right,
8223
- },
8224
- "*": {
8225
- typeFn: common_arith_types,
8226
- valueFn: (left, right) => left * right,
8227
- },
8228
- "/": {
8229
- typeFn: common_arith_types,
8230
- valueFn: (left, right) => left / right,
8231
- },
8232
- "%": {
8233
- typeFn: shift_mod_types,
8234
- valueFn: (left, right) => left % right,
8235
- },
8236
- "&": {
8237
- typeFn: common_bitwise_types,
8238
- valueFn: (left, right) => left & right,
8239
- },
8240
- "|": {
8241
- typeFn: common_bitwise_types,
8242
- valueFn: (left, right) => left | right,
8243
- },
8244
- "^": {
8245
- typeFn: common_bitwise_types,
8246
- valueFn: (left, right) => left ^ right,
8247
- },
8248
- "<<": {
8249
- typeFn: shift_mod_types,
8250
- valueFn: (left, right) => typeof right === "bigint"
8251
- ? left << right
8252
- : left << right,
8253
- },
8254
- ">>": {
8255
- typeFn: shift_mod_types,
8256
- valueFn: (left, right) => typeof right === "bigint"
8257
- ? left >> right
8258
- : left >> right,
8259
- },
8260
- "==": {
8261
- typeFn: () => ["Boolean", (v) => v],
8262
- valueFn: equalsFn,
8263
- },
8264
- "!=": {
8265
- typeFn: () => ["Boolean", (v) => v],
8266
- valueFn: (left, right) => !equalsFn(left, right),
8267
- },
8268
- "<=": {
8269
- typeFn: common_arith_types,
8270
- valueFn: (left, right) => left <= right,
8271
- },
8272
- ">=": {
8273
- typeFn: common_arith_types,
8274
- valueFn: (left, right) => left >= right,
8275
- },
8276
- "<": {
8277
- typeFn: common_arith_types,
8278
- valueFn: (left, right) => left < right,
8279
- },
8280
- ">": {
8281
- typeFn: common_arith_types,
8282
- valueFn: (left, right) => left > right,
8283
- },
8284
- as: null,
8285
- instanceof: null,
8286
- has: null,
8287
- };
8288
- function optimizeNode(state, node) {
8289
10986
  switch (node.type) {
8290
- case "UnaryExpression": {
8291
- const [arg, type] = getNodeValue(node.argument);
8292
- if (arg === null)
8293
- break;
8294
- switch (node.operator) {
8295
- case "+":
8296
- if (type === "Number" ||
8297
- type === "Long" ||
8298
- type === "Float" ||
8299
- type === "Double" ||
8300
- type === "Char" ||
8301
- type === "String") {
8302
- return arg;
8303
- }
8304
- break;
8305
- case "-":
8306
- if (type === "Number" ||
8307
- type === "Long" ||
8308
- type === "Float" ||
8309
- type === "Double") {
8310
- return replacementLiteral(node, -arg.value, type);
8311
- }
8312
- break;
8313
- case "!":
8314
- case "~":
8315
- {
8316
- if (type === "Number" || type === "Long") {
8317
- return replacementLiteral(node, ~BigInt(arg.value), type);
8318
- }
8319
- if (type === "Boolean" && node.operator == "!") {
8320
- return replacementLiteral(node, !arg.value, type);
8321
- }
8322
- }
8323
- break;
8324
- }
8325
- break;
8326
- }
8327
- case "BinaryExpression": {
8328
- const op = operators[node.operator];
8329
- if (op) {
8330
- const [left, left_type] = getNodeValue(node.left);
8331
- const [right, right_type] = getNodeValue(node.right);
8332
- if (!left || !right)
8333
- break;
8334
- const type = op.typeFn(left_type, right_type);
8335
- if (!type)
8336
- break;
8337
- const value = op.valueFn(type[1](left.value), type[1](right.value));
8338
- if (value === null)
8339
- break;
8340
- return replacementLiteral(node, value, type[0]);
8341
- }
10987
+ case "UpdateExpression":
10988
+ // we only evaluated any subexpressions of the argument.
10989
+ evaluateNode(istate, node.argument);
8342
10990
  break;
8343
- }
8344
- case "LogicalExpression": {
8345
- const [left, left_type] = getNodeValue(node.left);
8346
- if (!left)
8347
- break;
8348
- const falsy = left.value === false ||
8349
- left.value === null ||
8350
- ((left_type === "Number" || left_type === "Long") &&
8351
- (left.value === 0 || left.value === 0n));
8352
- if (falsy === (node.operator === "&&" || node.operator === "and")) {
8353
- return left;
8354
- }
8355
- if (left_type !== "Boolean" &&
8356
- left_type !== "Number" &&
8357
- left_type !== "Long") {
8358
- break;
8359
- }
8360
- const [right, right_type] = getNodeValue(node.right);
8361
- if (right && right_type === left_type) {
8362
- if (left_type === "Boolean" ||
8363
- node.operator === "||" ||
8364
- node.operator === "or") {
8365
- return right;
8366
- }
8367
- if (node.operator !== "&&" && node.operator !== "and") {
8368
- throw new Error(`Unexpected operator "${node.operator}"`);
8369
- }
8370
- return { ...node, type: "BinaryExpression", operator: "&" };
8371
- }
8372
- if (left_type === "Boolean") {
8373
- if (isBooleanExpression(state, node.right)) {
8374
- return node.right;
8375
- }
8376
- }
10991
+ case "AssignmentExpression": {
10992
+ // we only evaluated any subexpressions of the lhs.
10993
+ const right = istate.stack.pop();
10994
+ evaluateNode(istate, node.left);
10995
+ istate.stack.push(right);
8377
10996
  break;
8378
10997
  }
8379
- case "FunctionDeclaration":
8380
- if (node.body && evaluateFunction(state, node, null) !== false) {
8381
- node.optimizable = true;
10998
+ case "BinaryExpression":
10999
+ if (node.operator === "has" &&
11000
+ node.right.type === "UnaryExpression" &&
11001
+ node.right.operator === ":") {
11002
+ // we skipped this node, so evaluate it now...
11003
+ istate.stack.push(interp_evaluate(istate, node.right));
8382
11004
  }
8383
11005
  break;
8384
11006
  }
8385
- return null;
11007
+ const before = beforeEvaluate(istate, node);
11008
+ if (before != null)
11009
+ return before;
11010
+ evaluateNode(istate, node);
11011
+ return afterEvaluate(istate, node);
8386
11012
  }
8387
- function evaluateFunction(state, func, args) {
8388
- if (!func.body || (args && args.length != func.params.length)) {
11013
+ function evaluateFunction(istate, func, args) {
11014
+ if (!func.body ||
11015
+ istate.state.inlining ||
11016
+ (args && args.length != func.params.length)) {
8389
11017
  return false;
8390
11018
  }
8391
11019
  const paramValues = args &&
8392
- Object.fromEntries(func.params.map((p, i) => [(0,external_api_cjs_namespaceObject.variableDeclarationName)(p), args[i]]));
11020
+ Object.fromEntries(func.params.map((p, i) => [
11021
+ (0,external_api_cjs_namespaceObject.variableDeclarationName)(p),
11022
+ args[i],
11023
+ ]));
8393
11024
  let ret = null;
8394
11025
  const body = args ? cloneDeep(func.body) : func.body;
11026
+ const depth = istate.stack.length;
8395
11027
  try {
8396
11028
  traverseAst(body, (node) => {
8397
11029
  switch (node.type) {
@@ -8413,24 +11045,28 @@ function evaluateFunction(state, func, args) {
8413
11045
  ret = node.argument || null;
8414
11046
  return null;
8415
11047
  case "BlockStatement":
8416
- case "Literal":
8417
11048
  return null;
8418
11049
  case "Identifier":
8419
11050
  if ((0,external_api_cjs_namespaceObject.hasProperty)(paramValues, node.name)) {
8420
- return paramValues[node.name];
11051
+ istate.stack.push(interp_evaluate(istate, (node = paramValues[node.name])));
11052
+ return node;
8421
11053
  }
8422
11054
  // fall through;
8423
11055
  default: {
8424
- const repl = optimizeNode(state, node);
8425
- if (repl && repl.type === "Literal")
11056
+ const repl = optimizeNode(istate, node) || node;
11057
+ if (repl.type === "Literal")
8426
11058
  return repl;
8427
11059
  throw new Error("Didn't optimize");
8428
11060
  }
8429
11061
  }
8430
11062
  });
11063
+ delete istate.state.inlining;
11064
+ istate.stack.length = depth;
8431
11065
  return ret;
8432
11066
  }
8433
11067
  catch (e) {
11068
+ delete istate.state.inlining;
11069
+ istate.stack.length = depth;
8434
11070
  return false;
8435
11071
  }
8436
11072
  }
@@ -8449,51 +11085,22 @@ async function optimizeMonkeyC(fnMap, resourcesMap, manifestXML, config) {
8449
11085
  const replace = (node, old) => {
8450
11086
  if (node === false || node === null)
8451
11087
  return node;
11088
+ if (isExpression(node)) {
11089
+ popIstate(istate, old);
11090
+ }
8452
11091
  const rep = state.traverse(node);
8453
11092
  if (rep === false || Array.isArray(rep))
8454
11093
  return rep;
8455
- return { ...(rep || node), loc: old.loc, start: old.start, end: old.end };
8456
- };
8457
- const inPlaceReplacement = (node, obj) => {
8458
- const { start, end, loc } = node;
8459
- for (const k of Object.keys(node)) {
8460
- delete node[k];
8461
- }
8462
- if (obj.enumType) {
8463
- obj = {
8464
- type: "BinaryExpression",
8465
- operator: "as",
8466
- left: { ...obj, start, end, loc },
8467
- right: { type: "TypeSpecList", ts: [obj.enumType] },
8468
- };
8469
- }
8470
- for (const [k, v] of Object.entries(obj)) {
8471
- node[k] = v;
8472
- }
8473
- node.loc = loc;
8474
- node.start = start;
8475
- node.end = end;
8476
- };
8477
- const lookupAndReplace = (node) => {
8478
- const [, objects] = state.lookup(node);
8479
- if (!objects) {
8480
- return false;
8481
- }
8482
- let obj = getLiteralFromDecls(objects);
8483
- if (!obj) {
8484
- return false;
8485
- }
8486
- while (obj.type === "BinaryExpression") {
8487
- if (obj.left.type === "BinaryExpression" && obj.left.operator === "as") {
8488
- obj = { ...obj, left: obj.left.left };
8489
- }
8490
- else {
8491
- obj = { ...obj, left: { ...obj.left } };
8492
- break;
8493
- }
11094
+ const result = {
11095
+ ...(rep || node),
11096
+ loc: old.loc,
11097
+ start: old.start,
11098
+ end: old.end,
11099
+ };
11100
+ if (isExpression(result)) {
11101
+ istate.stack[istate.stack.length - 1].node = result;
8494
11102
  }
8495
- inPlaceReplacement(node, obj);
8496
- return true;
11103
+ return result;
8497
11104
  };
8498
11105
  const topLocals = () => state.localsStack[state.localsStack.length - 1];
8499
11106
  /*
@@ -8586,48 +11193,14 @@ async function optimizeMonkeyC(fnMap, resourcesMap, manifestXML, config) {
8586
11193
  }
8587
11194
  }
8588
11195
  };
11196
+ // use this when optimizing initializer expressions,
11197
+ // outside of any function.
11198
+ const gistate = { state, stack: [] };
11199
+ // use this when type inference is enabled, and we're
11200
+ // inside a function.
11201
+ let istate = gistate;
8589
11202
  state.pre = (node) => {
8590
11203
  switch (node.type) {
8591
- case "ConditionalExpression":
8592
- case "IfStatement":
8593
- case "DoWhileStatement":
8594
- case "WhileStatement": {
8595
- const test = (state.traverse(node.test) ||
8596
- node.test);
8597
- const [value, type] = getNodeValue(test);
8598
- if (value) {
8599
- let result = null;
8600
- if (type === "Null") {
8601
- result = false;
8602
- }
8603
- else if (type === "Boolean" ||
8604
- type === "Number" ||
8605
- type === "Long") {
8606
- result = !!value.value;
8607
- }
8608
- if (result !== null) {
8609
- node.test = {
8610
- type: "Literal",
8611
- value: result,
8612
- raw: result.toString(),
8613
- };
8614
- if (node.type === "IfStatement" ||
8615
- node.type === "ConditionalExpression") {
8616
- return [result ? "consequent" : "alternate"];
8617
- }
8618
- else if (node.type === "WhileStatement") {
8619
- return result === false ? [] : ["body"];
8620
- }
8621
- else if (node.type === "DoWhileStatement") {
8622
- return ["body"];
8623
- }
8624
- else {
8625
- throw new Error("Unexpected Node type");
8626
- }
8627
- }
8628
- }
8629
- return null;
8630
- }
8631
11204
  case "EnumDeclaration":
8632
11205
  return [];
8633
11206
  case "ForStatement": {
@@ -8649,13 +11222,14 @@ async function optimizeMonkeyC(fnMap, resourcesMap, manifestXML, config) {
8649
11222
  }
8650
11223
  break;
8651
11224
  case "BinaryExpression":
8652
- if (node.operator === "has") {
8653
- if (node.right.type === "UnaryExpression" &&
8654
- node.right.operator === ":") {
8655
- // Using `expr has :symbol` doesn't "expose"
8656
- // symbol. So skip the right operand.
8657
- return ["left"];
8658
- }
11225
+ if (node.operator === "has"
11226
+ ? node.right.type === "UnaryExpression" &&
11227
+ node.right.operator === ":"
11228
+ : node.operator === "as") {
11229
+ // Using `expr has :symbol` doesn't "expose"
11230
+ // symbol, and the rhs of an "as" isn't an
11231
+ // expression. In both cases, skip the rhs
11232
+ return ["left"];
8659
11233
  }
8660
11234
  break;
8661
11235
  case "UnaryExpression":
@@ -8695,29 +11269,8 @@ async function optimizeMonkeyC(fnMap, resourcesMap, manifestXML, config) {
8695
11269
  }
8696
11270
  }
8697
11271
  }
8698
- if ((0,external_api_cjs_namespaceObject.hasProperty)(state.index, node.name)) {
8699
- if (!lookupAndReplace(node)) {
8700
- state.usedByName[node.name] = true;
8701
- }
8702
- }
8703
11272
  return [];
8704
11273
  }
8705
- case "MemberExpression": {
8706
- const property = (0,external_api_cjs_namespaceObject.isLookupCandidate)(node);
8707
- if (property) {
8708
- if ((0,external_api_cjs_namespaceObject.hasProperty)(state.index, property.name)) {
8709
- if (lookupAndReplace(node)) {
8710
- return false;
8711
- }
8712
- else {
8713
- state.usedByName[property.name] = true;
8714
- }
8715
- }
8716
- // Don't optimize the property.
8717
- return ["object"];
8718
- }
8719
- break;
8720
- }
8721
11274
  case "AssignmentExpression":
8722
11275
  case "UpdateExpression": {
8723
11276
  const lhs = node.type === "AssignmentExpression" ? node.left : node.argument;
@@ -8733,9 +11286,15 @@ async function optimizeMonkeyC(fnMap, resourcesMap, manifestXML, config) {
8733
11286
  }
8734
11287
  }
8735
11288
  else if (lhs.type === "MemberExpression") {
8736
- state.traverse(lhs.object);
8737
- if (lhs.computed) {
8738
- state.traverse(lhs.property);
11289
+ const object = state.traverse(lhs.object);
11290
+ if (object) {
11291
+ lhs.object = object;
11292
+ }
11293
+ if (!(0,external_api_cjs_namespaceObject.isLookupCandidate)(lhs)) {
11294
+ const property = state.traverse(lhs.property);
11295
+ if (property) {
11296
+ lhs.property = property;
11297
+ }
8739
11298
  }
8740
11299
  }
8741
11300
  return node.type === "AssignmentExpression" ? ["right"] : [];
@@ -8760,6 +11319,23 @@ async function optimizeMonkeyC(fnMap, resourcesMap, manifestXML, config) {
8760
11319
  throw new Error(`Nested functions: ${self.fullName} was activated during processing of ${state.currentFunction.fullName}`);
8761
11320
  }
8762
11321
  state.currentFunction = self;
11322
+ const is = !state.config?.propagateTypes ||
11323
+ node.attrs?.attributes?.elements.find((attr) => attr.type == "UnaryExpression" &&
11324
+ attr.argument.name === "noConstProp")
11325
+ ? null
11326
+ : type_flow_buildTypeInfo(state, state.currentFunction);
11327
+ if (is) {
11328
+ /*
11329
+ * istate contains a copy of state, but we need the real
11330
+ * thing, because "state" is captured here.
11331
+ *
11332
+ * A better solution will be to separate out a
11333
+ * "lookup context", which will be a stack, plus a couple
11334
+ * of fields from state, and then pass that around.
11335
+ */
11336
+ is.state = state;
11337
+ istate = is;
11338
+ }
8763
11339
  if (parent.type == "ClassDeclaration" && !maybeCalled(node)) {
8764
11340
  let used = false;
8765
11341
  if (node.id.name == "initialize") {
@@ -8772,7 +11348,15 @@ async function optimizeMonkeyC(fnMap, resourcesMap, manifestXML, config) {
8772
11348
  markFunctionCalled(state, node);
8773
11349
  }
8774
11350
  }
11351
+ // We dont want to call evaluateNode on
11352
+ // id, args or returnType
11353
+ return ["body"];
8775
11354
  }
11355
+ case "ClassDeclaration":
11356
+ case "ModuleDeclaration":
11357
+ // We dont want to call evaluateNode on
11358
+ // id, or superClass
11359
+ return ["body"];
8776
11360
  }
8777
11361
  return null;
8778
11362
  };
@@ -8781,18 +11365,25 @@ async function optimizeMonkeyC(fnMap, resourcesMap, manifestXML, config) {
8781
11365
  if (locals.node === node) {
8782
11366
  state.localsStack.pop();
8783
11367
  }
8784
- const opt = optimizeNode(state, node);
8785
- if (opt) {
8786
- return replace(opt, node);
11368
+ const opt = optimizeNode(istate, node);
11369
+ if (opt != null) {
11370
+ return opt;
8787
11371
  }
8788
11372
  switch (node.type) {
8789
11373
  case "FunctionDeclaration":
11374
+ if (node.body && evaluateFunction(istate, node, null) !== false) {
11375
+ node.optimizable = true;
11376
+ }
8790
11377
  if (!state.currentFunction) {
8791
11378
  throw new Error(`Finished function ${state.stack.slice(-1)[0].fullName}, but it was not marked current`);
8792
11379
  }
8793
11380
  state.currentFunction.info = state.currentFunction.next_info || false;
8794
11381
  delete state.currentFunction.next_info;
8795
11382
  delete state.currentFunction;
11383
+ if (istate.stack.length) {
11384
+ throw new Error("Stack was not empty");
11385
+ }
11386
+ istate = gistate;
8796
11387
  break;
8797
11388
  case "BlockStatement":
8798
11389
  if (node.body.length === 1 && node.body[0].type === "BlockStatement") {
@@ -8804,74 +11395,32 @@ async function optimizeMonkeyC(fnMap, resourcesMap, manifestXML, config) {
8804
11395
  cleanupUnusedVars(state, node);
8805
11396
  }
8806
11397
  break;
8807
- case "ConditionalExpression":
8808
- case "IfStatement":
8809
- if (node.test.type === "Literal" &&
8810
- typeof node.test.value === "boolean") {
8811
- const rep = node.test.value ? node.consequent : node.alternate;
8812
- if (!rep)
8813
- return false;
8814
- return replace(rep, rep);
8815
- }
8816
- else if (node.type === "IfStatement") {
8817
- if (node.alternate &&
8818
- node.alternate.type === "BlockStatement" &&
8819
- !node.alternate.body.length) {
8820
- delete node.alternate;
8821
- }
8822
- else {
8823
- const call = inlinableSubExpression(node.test);
8824
- if (call) {
8825
- return replace(optimizeCall(state, call, node), node.test);
8826
- }
8827
- }
8828
- }
8829
- break;
8830
- case "WhileStatement":
8831
- if (node.test.type === "Literal" && node.test.value === false) {
8832
- return false;
8833
- }
8834
- break;
8835
- case "DoWhileStatement":
8836
- if (node.test.type === "Literal" && node.test.value === false) {
8837
- return node.body;
11398
+ case "IfStatement": {
11399
+ const call = inlinableSubExpression(node.test);
11400
+ if (call) {
11401
+ return replace(optimizeCall(istate, call, node), node.test);
8838
11402
  }
8839
11403
  break;
11404
+ }
8840
11405
  case "ReturnStatement":
8841
11406
  if (node.argument && node.argument.type === "CallExpression") {
8842
- return replace(optimizeCall(state, node.argument, node), node.argument);
11407
+ return replace(optimizeCall(istate, node.argument, node), node.argument);
8843
11408
  }
8844
11409
  break;
8845
- case "BinaryExpression":
8846
- if (node.operator === "has" &&
8847
- node.right.type === "UnaryExpression" &&
8848
- node.right.operator === ":") {
8849
- const [, results] = state.lookup(node.left);
8850
- if (results &&
8851
- results.length === 1 &&
8852
- results[0].results.length === 1) {
8853
- const obj = results[0].results[0];
8854
- if ((obj.type === "ModuleDeclaration" ||
8855
- obj.type === "Program" ||
8856
- obj.type === "ClassDeclaration") &&
8857
- obj.stack) {
8858
- const exists = (0,external_api_cjs_namespaceObject.hasProperty)(obj.decls, node.right.argument.name) ||
8859
- // This is overkill, since we've already looked up
8860
- // node.left, but the actual lookup rules are complicated,
8861
- // and embedded within state.lookup; so just defer to that.
8862
- state.lookup({
8863
- type: "MemberExpression",
8864
- object: node.left,
8865
- property: node.right.argument,
8866
- computed: false,
8867
- })[1];
8868
- if (!exists) {
8869
- return replace({ type: "Literal", value: false, raw: "false" }, node);
8870
- }
8871
- }
11410
+ case "Identifier":
11411
+ if ((0,external_api_cjs_namespaceObject.hasProperty)(state.index, node.name)) {
11412
+ state.usedByName[node.name] = true;
11413
+ }
11414
+ break;
11415
+ case "MemberExpression": {
11416
+ const property = (0,external_api_cjs_namespaceObject.isLookupCandidate)(node);
11417
+ if (property) {
11418
+ if ((0,external_api_cjs_namespaceObject.hasProperty)(state.index, property.name)) {
11419
+ state.usedByName[property.name] = true;
8872
11420
  }
8873
11421
  }
8874
11422
  break;
11423
+ }
8875
11424
  case "NewExpression":
8876
11425
  if (state.currentFunction) {
8877
11426
  const [, results] = state.lookup(node.callee);
@@ -8884,7 +11433,7 @@ async function optimizeMonkeyC(fnMap, resourcesMap, manifestXML, config) {
8884
11433
  }
8885
11434
  break;
8886
11435
  case "CallExpression": {
8887
- return replace(optimizeCall(state, node, null), node);
11436
+ return replace(optimizeCall(istate, node, null), node);
8888
11437
  }
8889
11438
  case "VariableDeclaration": {
8890
11439
  const locals = topLocals();
@@ -8901,7 +11450,7 @@ async function optimizeMonkeyC(fnMap, resourcesMap, manifestXML, config) {
8901
11450
  continue;
8902
11451
  const call = inlinableSubExpression(decl.init);
8903
11452
  if (call) {
8904
- const inlined = replace(optimizeCall(state, call, decl), decl.init);
11453
+ const inlined = replace(optimizeCall(istate, call, decl), decl.init);
8905
11454
  if (!inlined)
8906
11455
  continue;
8907
11456
  if (Array.isArray(inlined) || inlined.type != "BlockStatement") {
@@ -8933,7 +11482,7 @@ async function optimizeMonkeyC(fnMap, resourcesMap, manifestXML, config) {
8933
11482
  }
8934
11483
  case "ExpressionStatement":
8935
11484
  if (node.expression.type === "CallExpression") {
8936
- return replace(optimizeCall(state, node.expression, node), node.expression);
11485
+ return replace(optimizeCall(istate, node.expression, node), node.expression);
8937
11486
  }
8938
11487
  else if (node.expression.type === "AssignmentExpression") {
8939
11488
  const call = inlinableSubExpression(node.expression.right);
@@ -8949,7 +11498,7 @@ async function optimizeMonkeyC(fnMap, resourcesMap, manifestXML, config) {
8949
11498
  ok = !!result;
8950
11499
  }
8951
11500
  if (ok) {
8952
- return replace(optimizeCall(state, call, node.expression), node.expression.right);
11501
+ return replace(optimizeCall(istate, call, node.expression), node.expression.right);
8953
11502
  }
8954
11503
  }
8955
11504
  }
@@ -8968,7 +11517,7 @@ async function optimizeMonkeyC(fnMap, resourcesMap, manifestXML, config) {
8968
11517
  node.left.type === "Identifier" &&
8969
11518
  node.right.type === "Identifier" &&
8970
11519
  node.left.name === node.right.name) {
8971
- return { type: "Literal", value: null, raw: "null" };
11520
+ return replace({ type: "Literal", value: null, raw: "null" }, node);
8972
11521
  }
8973
11522
  // fall through;
8974
11523
  case "UpdateExpression":
@@ -9116,7 +11665,8 @@ async function optimizeMonkeyC(fnMap, resourcesMap, manifestXML, config) {
9116
11665
  });
9117
11666
  return state.diagnostics;
9118
11667
  }
9119
- function optimizeCall(state, node, context) {
11668
+ function optimizeCall(istate, node, context) {
11669
+ const state = istate.state;
9120
11670
  const [name, results] = state.lookupNonlocal(node.callee);
9121
11671
  const callees = results ? findCallees(results) : null;
9122
11672
  if (!callees || !callees.length) {
@@ -9151,7 +11701,7 @@ function optimizeCall(state, node, context) {
9151
11701
  callee.optimizable &&
9152
11702
  !callee.hasOverride &&
9153
11703
  node.arguments.every((n) => getNodeValue(n)[0] !== null)) {
9154
- const ret = evaluateFunction(state, callee, node.arguments);
11704
+ const ret = evaluateFunction(istate, callee, node.arguments);
9155
11705
  if (ret) {
9156
11706
  return ret;
9157
11707
  }
@@ -9620,7 +12170,10 @@ const configOptionsToCheck = [
9620
12170
  "ignoredSourcePaths",
9621
12171
  "checkInvalidSymbols",
9622
12172
  "checkCompilerLookupRules",
12173
+ "checkTypes",
9623
12174
  "sizeBasedPRE",
12175
+ "trustDeclaredTypes",
12176
+ "propagateTypes",
9624
12177
  "extensionVersion",
9625
12178
  ];
9626
12179
  /**
@@ -9680,7 +12233,7 @@ async function generateOneConfig(buildConfig, manifestXML, dependencyFiles, conf
9680
12233
  // the oldest optimized file, we don't need to regenerate
9681
12234
  const source_time = await (0,external_util_cjs_namespaceObject.last_modified)(Object.keys(fnMap).concat(dependencyFiles));
9682
12235
  const opt_time = await (0,external_util_cjs_namespaceObject.first_modified)(Object.values(fnMap).map((v) => v.output));
9683
- if (source_time < opt_time && 1672601827382 < opt_time) {
12236
+ if (source_time < opt_time && 1673220499844 < opt_time) {
9684
12237
  return { hasTests, diagnostics: prevDiagnostics };
9685
12238
  }
9686
12239
  }
@@ -9707,7 +12260,7 @@ async function generateOneConfig(buildConfig, manifestXML, dependencyFiles, conf
9707
12260
  return promises_namespaceObject.writeFile(external_path_.join(output, "build-info.json"), JSON.stringify({
9708
12261
  hasTests,
9709
12262
  diagnostics,
9710
- optimizerVersion: "1.0.45",
12263
+ optimizerVersion: "1.1.0",
9711
12264
  ...Object.fromEntries(configOptionsToCheck.map((option) => [option, config[option]])),
9712
12265
  }))
9713
12266
  .then(() => ({ hasTests, diagnostics }));