@scriptc/compiler 0.4.3 → 0.4.4

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.
Files changed (232) hide show
  1. package/ambient/scriptc-node-fallback.d.ts +73 -29
  2. package/dist/backend/llvm/bytes-loop-versions.js +6 -0
  3. package/dist/backend/llvm/bytes-loop-versions.js.map +1 -1
  4. package/dist/backend/llvm/bytes-loop-versions.test.js +7 -2
  5. package/dist/backend/llvm/bytes-loop-versions.test.js.map +1 -1
  6. package/dist/backend/llvm/debug-info.js +2 -5
  7. package/dist/backend/llvm/debug-info.js.map +1 -1
  8. package/dist/backend/llvm/dyn.d.ts +4 -0
  9. package/dist/backend/llvm/dyn.js +21 -9
  10. package/dist/backend/llvm/dyn.js.map +1 -1
  11. package/dist/backend/llvm/emit-function.js +2 -8
  12. package/dist/backend/llvm/emit-function.js.map +1 -1
  13. package/dist/backend/llvm/emit-module.js +16 -6
  14. package/dist/backend/llvm/emit-module.js.map +1 -1
  15. package/dist/backend/llvm/emitter.d.ts +10 -0
  16. package/dist/backend/llvm/emitter.js +9 -5
  17. package/dist/backend/llvm/emitter.js.map +1 -1
  18. package/dist/backend/llvm/emitter.test.js +11 -2
  19. package/dist/backend/llvm/emitter.test.js.map +1 -1
  20. package/dist/backend/llvm/expr-async.js +11 -13
  21. package/dist/backend/llvm/expr-async.js.map +1 -1
  22. package/dist/backend/llvm/expr-bytes.js +14 -8
  23. package/dist/backend/llvm/expr-bytes.js.map +1 -1
  24. package/dist/backend/llvm/expr-containers.js +14 -0
  25. package/dist/backend/llvm/expr-containers.js.map +1 -1
  26. package/dist/backend/llvm/expr-primitives.js +20 -11
  27. package/dist/backend/llvm/expr-primitives.js.map +1 -1
  28. package/dist/backend/llvm/expr-stream-bridges.js +16 -4
  29. package/dist/backend/llvm/expr-stream-bridges.js.map +1 -1
  30. package/dist/backend/llvm/integer-values.d.ts +5 -0
  31. package/dist/backend/llvm/integer-values.js +27 -3
  32. package/dist/backend/llvm/integer-values.js.map +1 -1
  33. package/dist/backend/llvm/lib-dispatch.js +133 -3
  34. package/dist/backend/llvm/lib-dispatch.js.map +1 -1
  35. package/dist/backend/llvm/lib-process.js +37 -1
  36. package/dist/backend/llvm/lib-process.js.map +1 -1
  37. package/dist/backend/llvm/lib-shared.js +21 -0
  38. package/dist/backend/llvm/lib-shared.js.map +1 -1
  39. package/dist/backend/llvm/publish.js +3 -3
  40. package/dist/backend/llvm/publish.js.map +1 -1
  41. package/dist/backend/llvm/reference-effects.js +3 -0
  42. package/dist/backend/llvm/reference-effects.js.map +1 -1
  43. package/dist/backend/llvm/shapes.js +2 -7
  44. package/dist/backend/llvm/shapes.js.map +1 -1
  45. package/dist/backend/llvm/stack-captures.js +1 -5
  46. package/dist/backend/llvm/stack-captures.js.map +1 -1
  47. package/dist/backend/llvm/union-repr.d.ts +4 -3
  48. package/dist/backend/llvm/union-repr.js +6 -5
  49. package/dist/backend/llvm/union-repr.js.map +1 -1
  50. package/dist/backend/llvm/walkers.js +13 -0
  51. package/dist/backend/llvm/walkers.js.map +1 -1
  52. package/dist/backend/native-codegen-core.d.ts +5 -3
  53. package/dist/backend/native-codegen-core.js +13 -6
  54. package/dist/backend/native-codegen-core.js.map +1 -1
  55. package/dist/backend/native-codegen.test.js +6 -4
  56. package/dist/backend/native-codegen.test.js.map +1 -1
  57. package/dist/backend/target-cpu.d.ts +26 -0
  58. package/dist/backend/target-cpu.js +98 -0
  59. package/dist/backend/target-cpu.js.map +1 -0
  60. package/dist/backend/target-cpu.test.d.ts +1 -0
  61. package/dist/backend/target-cpu.test.js +38 -0
  62. package/dist/backend/target-cpu.test.js.map +1 -0
  63. package/dist/cli/command.js +20 -1
  64. package/dist/cli/command.js.map +1 -1
  65. package/dist/cli/usage.d.ts +4 -1
  66. package/dist/cli/usage.js +7 -0
  67. package/dist/cli/usage.js.map +1 -1
  68. package/dist/compile-types.d.ts +7 -0
  69. package/dist/diagnostics/diagnostic.js +1 -1
  70. package/dist/diagnostics/diagnostic.js.map +1 -1
  71. package/dist/executable/executable-cache.d.ts +3 -0
  72. package/dist/executable/executable-cache.js +4 -0
  73. package/dist/executable/executable-cache.js.map +1 -1
  74. package/dist/executable/executable-cache.test.js +2 -0
  75. package/dist/executable/executable-cache.test.js.map +1 -1
  76. package/dist/frontend/decl-projection.js +105 -10
  77. package/dist/frontend/decl-projection.js.map +1 -1
  78. package/dist/frontend/lowering/builtins/async-context.d.ts +8 -2
  79. package/dist/frontend/lowering/builtins/async-context.js +62 -3
  80. package/dist/frontend/lowering/builtins/async-context.js.map +1 -1
  81. package/dist/frontend/lowering/builtins/crypto.js +3 -1
  82. package/dist/frontend/lowering/builtins/crypto.js.map +1 -1
  83. package/dist/frontend/lowering/builtins/dates.js +4 -1
  84. package/dist/frontend/lowering/builtins/dates.js.map +1 -1
  85. package/dist/frontend/lowering/builtins/filesystem-calls.js +3 -3
  86. package/dist/frontend/lowering/builtins/filesystem-calls.js.map +1 -1
  87. package/dist/frontend/lowering/builtins/fs-glob.js +6 -3
  88. package/dist/frontend/lowering/builtins/fs-glob.js.map +1 -1
  89. package/dist/frontend/lowering/builtins/fs-paths.d.ts +43 -5
  90. package/dist/frontend/lowering/builtins/fs-paths.js +245 -93
  91. package/dist/frontend/lowering/builtins/fs-paths.js.map +1 -1
  92. package/dist/frontend/lowering/builtins/module-calls.js +6 -3
  93. package/dist/frontend/lowering/builtins/module-calls.js.map +1 -1
  94. package/dist/frontend/lowering/builtins/promises.d.ts +1 -1
  95. package/dist/frontend/lowering/builtins/promises.js +149 -138
  96. package/dist/frontend/lowering/builtins/promises.js.map +1 -1
  97. package/dist/frontend/lowering/call-signatures.js +0 -1
  98. package/dist/frontend/lowering/call-signatures.js.map +1 -1
  99. package/dist/frontend/lowering/cjs-exports-object.js +1 -1
  100. package/dist/frontend/lowering/cjs-exports-object.js.map +1 -1
  101. package/dist/frontend/lowering/cjs-inline-require.d.ts +32 -0
  102. package/dist/frontend/lowering/cjs-inline-require.js +307 -4
  103. package/dist/frontend/lowering/cjs-inline-require.js.map +1 -1
  104. package/dist/frontend/lowering/class-dynamic-dispatch.d.ts +10 -0
  105. package/dist/frontend/lowering/class-dynamic-dispatch.js +114 -0
  106. package/dist/frontend/lowering/class-dynamic-dispatch.js.map +1 -1
  107. package/dist/frontend/lowering/class-method-mutations.js +54 -18
  108. package/dist/frontend/lowering/class-method-mutations.js.map +1 -1
  109. package/dist/frontend/lowering/class-protocols.d.ts +25 -0
  110. package/dist/frontend/lowering/class-protocols.js +183 -1
  111. package/dist/frontend/lowering/class-protocols.js.map +1 -1
  112. package/dist/frontend/lowering/completion-callbacks.d.ts +4 -0
  113. package/dist/frontend/lowering/completion-callbacks.js +146 -0
  114. package/dist/frontend/lowering/completion-callbacks.js.map +1 -0
  115. package/dist/frontend/lowering/containers/array-callbacks.d.ts +5 -4
  116. package/dist/frontend/lowering/containers/array-callbacks.js +7 -6
  117. package/dist/frontend/lowering/containers/array-callbacks.js.map +1 -1
  118. package/dist/frontend/lowering/containers/array-construction.js +5 -0
  119. package/dist/frontend/lowering/containers/array-construction.js.map +1 -1
  120. package/dist/frontend/lowering/containers/array-methods.js +11 -3
  121. package/dist/frontend/lowering/containers/array-methods.js.map +1 -1
  122. package/dist/frontend/lowering/containers/bytes.d.ts +25 -17
  123. package/dist/frontend/lowering/containers/bytes.js +453 -45
  124. package/dist/frontend/lowering/containers/bytes.js.map +1 -1
  125. package/dist/frontend/lowering/date-values.d.ts +11 -0
  126. package/dist/frontend/lowering/date-values.js +207 -0
  127. package/dist/frontend/lowering/date-values.js.map +1 -0
  128. package/dist/frontend/lowering/expressions/array-literals.js +6 -0
  129. package/dist/frontend/lowering/expressions/array-literals.js.map +1 -1
  130. package/dist/frontend/lowering/expressions/binary.js +64 -26
  131. package/dist/frontend/lowering/expressions/binary.js.map +1 -1
  132. package/dist/frontend/lowering/expressions/element-access.js +79 -0
  133. package/dist/frontend/lowering/expressions/element-access.js.map +1 -1
  134. package/dist/frontend/lowering/expressions/identifiers.js +31 -1
  135. package/dist/frontend/lowering/expressions/identifiers.js.map +1 -1
  136. package/dist/frontend/lowering/expressions/property-access.js +56 -0
  137. package/dist/frontend/lowering/expressions/property-access.js.map +1 -1
  138. package/dist/frontend/lowering/expressions/typeof.js +6 -0
  139. package/dist/frontend/lowering/expressions/typeof.js.map +1 -1
  140. package/dist/frontend/lowering/expressions/updates.js +17 -0
  141. package/dist/frontend/lowering/expressions/updates.js.map +1 -1
  142. package/dist/frontend/lowering/function-returns.js +15 -0
  143. package/dist/frontend/lowering/function-returns.js.map +1 -1
  144. package/dist/frontend/lowering/indexed-unions.d.ts +54 -0
  145. package/dist/frontend/lowering/indexed-unions.js +401 -0
  146. package/dist/frontend/lowering/indexed-unions.js.map +1 -0
  147. package/dist/frontend/lowering/key-order-witness.js +210 -32
  148. package/dist/frontend/lowering/key-order-witness.js.map +1 -1
  149. package/dist/frontend/lowering/key-order-witness.test.js +104 -4
  150. package/dist/frontend/lowering/key-order-witness.test.js.map +1 -1
  151. package/dist/frontend/lowering/lower-assert.js +15 -3
  152. package/dist/frontend/lowering/lower-assert.js.map +1 -1
  153. package/dist/frontend/lowering/lower-calls.js +19 -3
  154. package/dist/frontend/lowering/lower-calls.js.map +1 -1
  155. package/dist/frontend/lowering/lower-classes.js +22 -47
  156. package/dist/frontend/lowering/lower-classes.js.map +1 -1
  157. package/dist/frontend/lowering/lower-exprs.js +205 -1
  158. package/dist/frontend/lowering/lower-exprs.js.map +1 -1
  159. package/dist/frontend/lowering/lower-generators.js +1 -1
  160. package/dist/frontend/lowering/lower-generators.js.map +1 -1
  161. package/dist/frontend/lowering/lower-inspect.d.ts +1 -1
  162. package/dist/frontend/lowering/lower-inspect.js +35 -11
  163. package/dist/frontend/lowering/lower-inspect.js.map +1 -1
  164. package/dist/frontend/lowering/lower-modules.js +21 -5
  165. package/dist/frontend/lowering/lower-modules.js.map +1 -1
  166. package/dist/frontend/lowering/lower-stmts.js +100 -34
  167. package/dist/frontend/lowering/lower-stmts.js.map +1 -1
  168. package/dist/frontend/lowering/lowerer.d.ts +30 -2
  169. package/dist/frontend/lowering/lowerer.js +68 -7
  170. package/dist/frontend/lowering/lowerer.js.map +1 -1
  171. package/dist/frontend/lowering/object-factory-new.d.ts +5 -0
  172. package/dist/frontend/lowering/object-factory-new.js +20 -6
  173. package/dist/frontend/lowering/object-factory-new.js.map +1 -1
  174. package/dist/frontend/lowering/overload-choice.d.ts +33 -0
  175. package/dist/frontend/lowering/overload-choice.js +190 -0
  176. package/dist/frontend/lowering/overload-choice.js.map +1 -0
  177. package/dist/frontend/lowering/surfaces.js +55 -2
  178. package/dist/frontend/lowering/surfaces.js.map +1 -1
  179. package/dist/frontend/pipeline.js +1 -1
  180. package/dist/frontend/pipeline.js.map +1 -1
  181. package/dist/frontend/program-analysis.d.ts +5 -1
  182. package/dist/frontend/program-analysis.js +5 -0
  183. package/dist/frontend/program-analysis.js.map +1 -1
  184. package/dist/frontend/program.d.ts +13 -5
  185. package/dist/frontend/program.js +197 -14
  186. package/dist/frontend/program.js.map +1 -1
  187. package/dist/frontend/ts7/semantic-model.d.ts +3 -0
  188. package/dist/frontend/ts7/semantic-model.js +5 -0
  189. package/dist/frontend/ts7/semantic-model.js.map +1 -1
  190. package/dist/frontend/ts7/semantic-model.test.js +6 -1
  191. package/dist/frontend/ts7/semantic-model.test.js.map +1 -1
  192. package/dist/frontend/ts7/semantic-types.d.ts +1 -1
  193. package/dist/frontend/ts7/semantic-types.js +1 -1
  194. package/dist/frontend/ts7/semantic-types.js.map +1 -1
  195. package/dist/frontend/type-mapper.js +45 -16
  196. package/dist/frontend/type-mapper.js.map +1 -1
  197. package/dist/index.js +12 -0
  198. package/dist/index.js.map +1 -1
  199. package/dist/ir/builtin-effects.js +8 -0
  200. package/dist/ir/builtin-effects.js.map +1 -1
  201. package/dist/ir/builtin-signatures.d.ts +1 -1
  202. package/dist/ir/builtin-signatures.js +56 -0
  203. package/dist/ir/builtin-signatures.js.map +1 -1
  204. package/dist/ir/int32-slots.js +7 -0
  205. package/dist/ir/int32-slots.js.map +1 -1
  206. package/dist/ir/int32-slots.test.js +33 -0
  207. package/dist/ir/int32-slots.test.js.map +1 -1
  208. package/dist/ir/integer-loops.js +14 -4
  209. package/dist/ir/integer-loops.js.map +1 -1
  210. package/dist/ir/ir.d.ts +13 -3
  211. package/dist/ir/ir.js +19 -5
  212. package/dist/ir/ir.js.map +1 -1
  213. package/dist/ir/ir.test.js +2 -1
  214. package/dist/ir/ir.test.js.map +1 -1
  215. package/dist/ir/js-ic.d.ts +2 -15
  216. package/dist/ir/js-ic.js +11 -79
  217. package/dist/ir/js-ic.js.map +1 -1
  218. package/dist/ir/js-ic.test.js +0 -142
  219. package/dist/ir/js-ic.test.js.map +1 -1
  220. package/dist/ir/runtime-features.js +25 -1
  221. package/dist/ir/runtime-features.js.map +1 -1
  222. package/dist/ir/validate.js +46 -5
  223. package/dist/ir/validate.js.map +1 -1
  224. package/dist/library/ir-policy.js +1 -0
  225. package/dist/library/ir-policy.js.map +1 -1
  226. package/dist/native/prepare.d.ts +1 -1
  227. package/dist/native/prepare.js +11 -1
  228. package/dist/native/prepare.js.map +1 -1
  229. package/dist/native/prepare.test.js +18 -2
  230. package/dist/native/prepare.test.js.map +1 -1
  231. package/package.json +20 -20
  232. package/surface-manifest.json +2 -4
@@ -26,7 +26,7 @@ import { lowerSafeIndexRead, tryLowerIndexTruthiness, tryLowerNumericIndexRead,
26
26
  import { nsMemberIdentOf } from "./lower-namespaces.js";
27
27
  import { bindingNeverReassigned } from "./binding-analysis.js";
28
28
  import { implicitMonoFile } from "./generic-functions.js";
29
- import { lowerTaggedTemplate } from "./lower-calls.js";
29
+ import { lowerPrimitiveUnionNumber, lowerTaggedTemplate } from "./lower-calls.js";
30
30
  import { unitOnlyUnion } from "../type-mapper.js";
31
31
  import { lowerYield } from "./lower-generators.js";
32
32
  import { unionWideningTags } from "../../ir/analysis.js";
@@ -272,6 +272,14 @@ function lowerExprInner(lowerer, expr) {
272
272
  const use = runtimeOptionalUseOf(expr);
273
273
  if (runtimeOptionalAssertionErases(lowerer, expr, inner, use))
274
274
  return inner;
275
+ // A destination that holds null or undefined keeps the value, as `!`
276
+ // does in JavaScript (`return cache.get(key)!` from a function that
277
+ // returns `T | null`); the destination's own coercion re-tags it.
278
+ if (assertionDestinationHoldsNullish(lowerer, expr, inner.type))
279
+ return inner;
280
+ const operand = assertionOperand(lowerer, expr, inner, target ?? null, loc);
281
+ if (operand)
282
+ return operand;
275
283
  if (target && target.kind !== "union" && !typeEquals(target, inner.type)) {
276
284
  const helper = lowerer.narrowedArmHelper(inner.type.unionId, target, loc);
277
285
  if (helper) {
@@ -723,6 +731,198 @@ export function assertedElementKeepsUndefined(lowerer, node) {
723
731
  return (admits(contextual) ||
724
732
  ((contextual.flags & ts.TypeFlags.Union) !== 0 && constituentTypes(contextual).some(admits)));
725
733
  }
734
+ /** Whether `node!` is a returned value, an arrow function's body or a call
735
+ * argument whose destination type (the return or parameter type) is `any`
736
+ * or `unknown` (as for `String(x!)` and `Number(x!)`) or holds null or
737
+ * undefined that the union `inner` holds and the assertion would remove.
738
+ * Bindings and assignments are left out: the checker narrows them to the
739
+ * asserted type for later reads. */
740
+ function assertionDestinationHoldsNullish(lowerer, node, inner) {
741
+ const holdsNull = lowerer.armTag(inner.unionId, NULL_T) >= 0;
742
+ const holdsUndefined = lowerer.armTag(inner.unionId, UNDEFINED_T) >= 0;
743
+ if (!holdsNull && !holdsUndefined)
744
+ return false;
745
+ let outer = node;
746
+ while (ts.isParenthesizedExpression(outer.parent))
747
+ outer = outer.parent;
748
+ const parent = outer.parent;
749
+ const destination = (ts.isReturnStatement(parent) && parent.expression === outer) ||
750
+ (ts.isArrowFunction(parent) && parent.body === outer) ||
751
+ ((ts.isCallExpression(parent) || ts.isNewExpression(parent)) &&
752
+ parent.arguments?.nodes.includes(outer) === true);
753
+ if (!destination)
754
+ return false;
755
+ const contextual = lowerer.checker.getContextualType(outer);
756
+ if (!contextual)
757
+ return false;
758
+ const nullish = ts.TypeFlags.Any |
759
+ ts.TypeFlags.Unknown |
760
+ (holdsNull ? ts.TypeFlags.Null : 0) |
761
+ (holdsUndefined && !optionalStdlibParameter(lowerer, parent, outer)
762
+ ? ts.TypeFlags.Undefined
763
+ : 0);
764
+ if ((contextual.flags & ts.TypeFlags.Union) === 0)
765
+ return (contextual.flags & nullish) !== 0;
766
+ return constituentTypes(contextual).some((type) => (type.flags & nullish) !== 0);
767
+ }
768
+ /** Whether `argument` of `call` binds an optional parameter of a standard
769
+ * library declaration (`decoder.decode(input?)`). The undefined such a
770
+ * parameter's type holds comes from its optionality, and the builtin
771
+ * lowerings read the argument as the declared type, so `x!` keeps the
772
+ * checked narrowing there. */
773
+ function optionalStdlibParameter(lowerer, call, argument) {
774
+ if (!ts.isCallExpression(call) && !ts.isNewExpression(call))
775
+ return false;
776
+ const declaration = lowerer.checker.getResolvedSignature(call)?.declaration;
777
+ if (declaration === undefined || !lowerer.isStdlibFile(ts.getSourceFileOfNode(declaration)))
778
+ return false;
779
+ const index = call.arguments?.nodes.indexOf(argument) ?? -1;
780
+ const parameter = declaration.parameters?.nodes[index];
781
+ return (parameter !== undefined &&
782
+ parameter.dotDotDotToken === undefined &&
783
+ (parameter.questionToken !== undefined || parameter.initializer !== undefined));
784
+ }
785
+ /** `x!` as the operand of an operator that converts its operands: an
786
+ * arithmetic, bitwise, relational or equality operator, `+`, a compound
787
+ * assignment, a unary `-`, `+`, `~` or `!`, a template span, or an argument
788
+ * of a Math function. `!` performs no runtime check,
789
+ * so a value that still holds undefined or null reaches the operator, which
790
+ * converts it as JavaScript does: NaN or 0 in arithmetic, false in a
791
+ * comparison, "undefined" or "null" in a string. Returns the operand to
792
+ * use, or null where the assertion narrows as usual. A numeric use gets the
793
+ * value converted with ToNumber; other uses get the union itself. */
794
+ function assertionOperand(lowerer, expr, inner, target, loc) {
795
+ if (inner.type.kind !== "union" || target === null || target.kind === "union")
796
+ return null;
797
+ const arms = lowerer.unions.get(inner.type.unionId)?.arms;
798
+ if (!arms?.some(isUnitType) ||
799
+ !arms.every((arm) => arm.kind === "f64" || arm.kind === "string" || arm.kind === "bool" || isUnitType(arm)))
800
+ return null;
801
+ // Array and typed-array element reads keep their own handling of a
802
+ // missing element.
803
+ let operand = expr.expression;
804
+ while (ts.isParenthesizedExpression(operand))
805
+ operand = operand.expression;
806
+ if (ts.isElementAccessExpression(operand)) {
807
+ const kind = lowerer.mapTypeOf(lowerer.typeOf(operand.expression))?.kind;
808
+ if (kind === "array" || kind === "bytes")
809
+ return null;
810
+ }
811
+ const use = convertingUseOf(lowerer, expr);
812
+ if (use === null)
813
+ return null;
814
+ if (use === "value")
815
+ return inner;
816
+ return lowerPrimitiveUnionNumber(lowerer, inner, expr, loc);
817
+ }
818
+ /** How the converting use of `x!` (see assertionOperand) reads it:
819
+ * "number" where the use applies ToNumber, "value" where the consumer
820
+ * lowers the union itself (strings, equality, truthiness), null for other
821
+ * uses. */
822
+ function convertingUseOf(lowerer, expr) {
823
+ let outer = expr;
824
+ while (ts.isParenthesizedExpression(outer.parent))
825
+ outer = outer.parent;
826
+ const parent = outer.parent;
827
+ if (ts.isTemplateSpan(parent))
828
+ return parent.expression === outer ? "value" : null;
829
+ if (ts.isPrefixUnaryExpression(parent)) {
830
+ if (parent.operator === ts.SyntaxKind.ExclamationToken)
831
+ return "value";
832
+ return parent.operator === ts.SyntaxKind.MinusToken ||
833
+ parent.operator === ts.SyntaxKind.PlusToken ||
834
+ parent.operator === ts.SyntaxKind.TildeToken
835
+ ? "number"
836
+ : null;
837
+ }
838
+ if (ts.isCallExpression(parent) && parent.arguments.nodes.includes(outer)) {
839
+ const callee = parent.expression;
840
+ return ts.isPropertyAccessExpression(callee) &&
841
+ stdlibGlobalNameOf(lowerer, callee.expression) === "Math"
842
+ ? "number"
843
+ : null;
844
+ }
845
+ if (!ts.isBinaryExpression(parent))
846
+ return null;
847
+ const op = parent.operatorToken.kind;
848
+ if (EQUALITY_OPERATORS.has(op))
849
+ return "value";
850
+ const other = parent.left === outer ? parent.right : parent.left;
851
+ const isString = (node) => (lowerer.typeOf(node).flags & ts.TypeFlags.StringLike) !== 0;
852
+ // With a string on either side, `+` concatenates and a comparison
853
+ // compares strings. `undefined + 1` and `undefined + undefined` are NaN,
854
+ // which a string-typed result cannot hold, so `+` takes the union only
855
+ // with a string partner that is not itself asserted. A partner that may
856
+ // hold a string or a number at run time (`any`, `unknown`) also gets the
857
+ // union, and `+` decides between concatenation and addition when it runs.
858
+ if (op === ts.SyntaxKind.PlusToken || op === ts.SyntaxKind.PlusEqualsToken) {
859
+ if (op === ts.SyntaxKind.PlusEqualsToken && parent.right !== outer)
860
+ return null;
861
+ let partner = other;
862
+ while (ts.isParenthesizedExpression(partner))
863
+ partner = partner.expression;
864
+ if (isString(other))
865
+ return ts.isNonNullExpression(partner) ? null : "value";
866
+ if (!numericPartner(lowerer.typeOf(other)))
867
+ return "value";
868
+ return isString(expr) ? null : "number";
869
+ }
870
+ if (RELATIONAL_OPERATORS.has(op))
871
+ return isString(other) || isString(expr) ? "value" : "number";
872
+ if (NUMERIC_OPERATORS.has(op))
873
+ return "number";
874
+ return NUMERIC_COMPOUNDS.has(op) && parent.right === outer ? "number" : null;
875
+ }
876
+ /** A `+` partner whose every value is a number, a boolean, null or
877
+ * undefined: `+` adds with it. */
878
+ function numericPartner(type) {
879
+ const numeric = ts.TypeFlags.NumberLike |
880
+ ts.TypeFlags.BooleanLike |
881
+ ts.TypeFlags.Null |
882
+ ts.TypeFlags.Undefined |
883
+ ts.TypeFlags.Void;
884
+ return (type.flags & ts.TypeFlags.Union) !== 0
885
+ ? constituentTypes(type).every((part) => (part.flags & numeric) !== 0)
886
+ : (type.flags & numeric) !== 0;
887
+ }
888
+ const EQUALITY_OPERATORS = new Set([
889
+ ts.SyntaxKind.EqualsEqualsEqualsToken,
890
+ ts.SyntaxKind.ExclamationEqualsEqualsToken,
891
+ ts.SyntaxKind.EqualsEqualsToken,
892
+ ts.SyntaxKind.ExclamationEqualsToken,
893
+ ]);
894
+ const RELATIONAL_OPERATORS = new Set([
895
+ ts.SyntaxKind.LessThanToken,
896
+ ts.SyntaxKind.GreaterThanToken,
897
+ ts.SyntaxKind.LessThanEqualsToken,
898
+ ts.SyntaxKind.GreaterThanEqualsToken,
899
+ ]);
900
+ const NUMERIC_OPERATORS = new Set([
901
+ ts.SyntaxKind.MinusToken,
902
+ ts.SyntaxKind.AsteriskToken,
903
+ ts.SyntaxKind.SlashToken,
904
+ ts.SyntaxKind.PercentToken,
905
+ ts.SyntaxKind.AsteriskAsteriskToken,
906
+ ts.SyntaxKind.AmpersandToken,
907
+ ts.SyntaxKind.BarToken,
908
+ ts.SyntaxKind.CaretToken,
909
+ ts.SyntaxKind.LessThanLessThanToken,
910
+ ts.SyntaxKind.GreaterThanGreaterThanToken,
911
+ ts.SyntaxKind.GreaterThanGreaterThanGreaterThanToken,
912
+ ]);
913
+ const NUMERIC_COMPOUNDS = new Set([
914
+ ts.SyntaxKind.MinusEqualsToken,
915
+ ts.SyntaxKind.AsteriskEqualsToken,
916
+ ts.SyntaxKind.SlashEqualsToken,
917
+ ts.SyntaxKind.PercentEqualsToken,
918
+ ts.SyntaxKind.AsteriskAsteriskEqualsToken,
919
+ ts.SyntaxKind.AmpersandEqualsToken,
920
+ ts.SyntaxKind.BarEqualsToken,
921
+ ts.SyntaxKind.CaretEqualsToken,
922
+ ts.SyntaxKind.LessThanLessThanEqualsToken,
923
+ ts.SyntaxKind.GreaterThanGreaterThanEqualsToken,
924
+ ts.SyntaxKind.GreaterThanGreaterThanGreaterThanEqualsToken,
925
+ ]);
726
926
  export function runtimeOptionalAssertionErases(lowerer, expr, inner, use) {
727
927
  if (inner.type.kind !== "union" ||
728
928
  !use?.optional ||
@@ -847,6 +1047,10 @@ export function lowerCondition(lowerer, expr) {
847
1047
  e.name.text === "setPrototypeOf" &&
848
1048
  lowerer.isStdlibGlobal(e.expression, "Object"))
849
1049
  return { kind: "boolLit", value: true, type: BOOL, loc: locOf(e) };
1050
+ // `if (runtimeBuffer)` over an alias of the Buffer global (a
1051
+ // capability probe): Node always defines Buffer.
1052
+ if (lowerer.isStdlibGlobal(e, "Buffer"))
1053
+ return { kind: "boolLit", value: true, type: BOOL, loc: locOf(e) };
850
1054
  if (ts.isPropertyAccessExpression(e)) {
851
1055
  const presence = lowerPromiseThenPresence(lowerer, e, {
852
1056
  kind: "boolLit",