@scriptc/compiler 0.2.0 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/ambient/scriptc-node-fallback.d.ts +25 -15
- package/dist/backend/cycle-analysis.js +1 -0
- package/dist/backend/cycle-analysis.js.map +1 -1
- package/dist/backend/llvm/classes.js +21 -5
- package/dist/backend/llvm/classes.js.map +1 -1
- package/dist/backend/llvm/dyn.d.ts +5 -0
- package/dist/backend/llvm/dyn.js +166 -99
- package/dist/backend/llvm/dyn.js.map +1 -1
- package/dist/backend/llvm/emitter.d.ts +2 -2
- package/dist/backend/llvm/emitter.js +79 -20
- package/dist/backend/llvm/emitter.js.map +1 -1
- package/dist/backend/llvm/expr-bytes.d.ts +1 -1
- package/dist/backend/llvm/expr-bytes.js +28 -17
- package/dist/backend/llvm/expr-bytes.js.map +1 -1
- package/dist/backend/llvm/expr-control.js +1 -1
- package/dist/backend/llvm/expr-control.js.map +1 -1
- package/dist/backend/llvm/expr-dynamic.js +18 -9
- package/dist/backend/llvm/expr-dynamic.js.map +1 -1
- package/dist/backend/llvm/expr-primitives.js +11 -1
- package/dist/backend/llvm/expr-primitives.js.map +1 -1
- package/dist/backend/llvm/expr-records.js +11 -3
- package/dist/backend/llvm/expr-records.js.map +1 -1
- package/dist/backend/llvm/expr-stream-bridges.js +125 -17
- package/dist/backend/llvm/expr-stream-bridges.js.map +1 -1
- package/dist/backend/llvm/lib-process.js +23 -3
- package/dist/backend/llvm/lib-process.js.map +1 -1
- package/dist/backend/llvm/lib-shared.js +45 -2
- package/dist/backend/llvm/lib-shared.js.map +1 -1
- package/dist/backend/llvm/shapes.js +8 -2
- package/dist/backend/llvm/shapes.js.map +1 -1
- package/dist/backend/native-toolchain.d.ts +3 -6
- package/dist/backend/native-toolchain.js +53 -23
- package/dist/backend/native-toolchain.js.map +1 -1
- package/dist/backend/native-toolchain.test.js +72 -0
- package/dist/backend/native-toolchain.test.js.map +1 -1
- package/dist/backend/runtime-abi.d.ts +2 -2
- package/dist/backend/runtime-abi.js +2 -2
- package/dist/backend/runtime-pack-native.js +4 -1
- package/dist/backend/runtime-pack-native.js.map +1 -1
- package/dist/backend/runtime-pack-targets.test.js +1 -1
- package/dist/backend/runtime-pack.test.js +1 -1
- package/dist/backend/targets.js +10 -6
- package/dist/backend/targets.js.map +1 -1
- package/dist/backend/targets.test.js +7 -0
- package/dist/backend/targets.test.js.map +1 -1
- package/dist/compat/fetch-profile.js +34 -4
- package/dist/compat/fetch-profile.js.map +1 -1
- package/dist/diagnostics/diagnostic.js +2 -7
- package/dist/diagnostics/diagnostic.js.map +1 -1
- package/dist/frontend/lowering/class-callbacks.d.ts +3 -3
- package/dist/frontend/lowering/class-callbacks.js +26 -15
- package/dist/frontend/lowering/class-callbacks.js.map +1 -1
- package/dist/frontend/lowering/class-construction.d.ts +12 -0
- package/dist/frontend/lowering/class-construction.js +156 -0
- package/dist/frontend/lowering/class-construction.js.map +1 -0
- package/dist/frontend/lowering/class-descriptors.d.ts +1 -0
- package/dist/frontend/lowering/class-descriptors.js +46 -5
- package/dist/frontend/lowering/class-descriptors.js.map +1 -1
- package/dist/frontend/lowering/class-dynamic-dispatch.d.ts +11 -1
- package/dist/frontend/lowering/class-dynamic-dispatch.js +403 -48
- package/dist/frontend/lowering/class-dynamic-dispatch.js.map +1 -1
- package/dist/frontend/lowering/class-dynamic-dispatch.test.js +2 -1
- package/dist/frontend/lowering/class-dynamic-dispatch.test.js.map +1 -1
- package/dist/frontend/lowering/class-instance-constructor.js +4 -1
- package/dist/frontend/lowering/class-instance-constructor.js.map +1 -1
- package/dist/frontend/lowering/class-method-values.d.ts +4 -1
- package/dist/frontend/lowering/class-method-values.js +72 -7
- package/dist/frontend/lowering/class-method-values.js.map +1 -1
- package/dist/frontend/lowering/class-prototypes.d.ts +5 -2
- package/dist/frontend/lowering/class-prototypes.js +121 -13
- package/dist/frontend/lowering/class-prototypes.js.map +1 -1
- package/dist/frontend/lowering/class-runtime-statics.d.ts +8 -0
- package/dist/frontend/lowering/class-runtime-statics.js +66 -0
- package/dist/frontend/lowering/class-runtime-statics.js.map +1 -0
- package/dist/frontend/lowering/class-static-data.js +2 -2
- package/dist/frontend/lowering/class-static-data.js.map +1 -1
- package/dist/frontend/lowering/containers/bytes.js +49 -13
- package/dist/frontend/lowering/containers/bytes.js.map +1 -1
- package/dist/frontend/lowering/containers/string-and-regexp.js +19 -47
- package/dist/frontend/lowering/containers/string-and-regexp.js.map +1 -1
- package/dist/frontend/lowering/error-methods.d.ts +4 -1
- package/dist/frontend/lowering/error-methods.js +100 -1
- package/dist/frontend/lowering/error-methods.js.map +1 -1
- package/dist/frontend/lowering/expressions/native-proxy.js +3 -1
- package/dist/frontend/lowering/expressions/native-proxy.js.map +1 -1
- package/dist/frontend/lowering/expressions/nullish-assignment.js +19 -11
- package/dist/frontend/lowering/expressions/nullish-assignment.js.map +1 -1
- package/dist/frontend/lowering/expressions/object-literals.js +38 -7
- package/dist/frontend/lowering/expressions/object-literals.js.map +1 -1
- package/dist/frontend/lowering/expressions/optional-chains.d.ts +3 -4
- package/dist/frontend/lowering/expressions/optional-chains.js +69 -17
- package/dist/frontend/lowering/expressions/optional-chains.js.map +1 -1
- package/dist/frontend/lowering/function-context.d.ts +11 -3
- package/dist/frontend/lowering/function-context.js +11 -5
- package/dist/frontend/lowering/function-context.js.map +1 -1
- package/dist/frontend/lowering/generator-dynamic-dispatch.d.ts +1 -0
- package/dist/frontend/lowering/generator-dynamic-dispatch.js +39 -1
- package/dist/frontend/lowering/generator-dynamic-dispatch.js.map +1 -1
- package/dist/frontend/lowering/lib-boundary.d.ts +2 -0
- package/dist/frontend/lowering/lib-boundary.js +54 -1
- package/dist/frontend/lowering/lib-boundary.js.map +1 -1
- package/dist/frontend/lowering/lower-builtin-values.d.ts +7 -1
- package/dist/frontend/lowering/lower-builtin-values.js +113 -3
- package/dist/frontend/lowering/lower-builtin-values.js.map +1 -1
- package/dist/frontend/lowering/lower-builtins.d.ts +6 -5
- package/dist/frontend/lowering/lower-builtins.js +156 -41
- package/dist/frontend/lowering/lower-builtins.js.map +1 -1
- package/dist/frontend/lowering/lower-calls.d.ts +8 -5
- package/dist/frontend/lowering/lower-calls.js +448 -83
- package/dist/frontend/lowering/lower-calls.js.map +1 -1
- package/dist/frontend/lowering/lower-classes.d.ts +13 -13
- package/dist/frontend/lowering/lower-classes.js +650 -176
- package/dist/frontend/lowering/lower-classes.js.map +1 -1
- package/dist/frontend/lowering/lower-containers.d.ts +9 -0
- package/dist/frontend/lowering/lower-containers.js +135 -36
- package/dist/frontend/lowering/lower-containers.js.map +1 -1
- package/dist/frontend/lowering/lower-dgram.js +3 -2
- package/dist/frontend/lowering/lower-dgram.js.map +1 -1
- package/dist/frontend/lowering/lower-exprs.d.ts +2 -2
- package/dist/frontend/lowering/lower-exprs.js +531 -126
- package/dist/frontend/lowering/lower-exprs.js.map +1 -1
- package/dist/frontend/lowering/lower-generators.js +12 -1
- package/dist/frontend/lowering/lower-generators.js.map +1 -1
- package/dist/frontend/lowering/lower-island.d.ts +2 -0
- package/dist/frontend/lowering/lower-island.js +32 -10
- package/dist/frontend/lowering/lower-island.js.map +1 -1
- package/dist/frontend/lowering/lower-modules.js +220 -17
- package/dist/frontend/lowering/lower-modules.js.map +1 -1
- package/dist/frontend/lowering/lower-modules.test.d.ts +1 -0
- package/dist/frontend/lowering/lower-modules.test.js +39 -0
- package/dist/frontend/lowering/lower-modules.test.js.map +1 -0
- package/dist/frontend/lowering/lower-stmts.d.ts +7 -3
- package/dist/frontend/lowering/lower-stmts.js +135 -26
- package/dist/frontend/lowering/lower-stmts.js.map +1 -1
- package/dist/frontend/lowering/lower-stream.js +1 -1
- package/dist/frontend/lowering/lower-stream.js.map +1 -1
- package/dist/frontend/lowering/lowerer.d.ts +27 -1
- package/dist/frontend/lowering/lowerer.js +172 -50
- package/dist/frontend/lowering/lowerer.js.map +1 -1
- package/dist/frontend/lowering/lowerer.test.js +149 -3
- package/dist/frontend/lowering/lowerer.test.js.map +1 -1
- package/dist/frontend/lowering/surfaces.d.ts +2 -0
- package/dist/frontend/lowering/surfaces.js +25 -8
- package/dist/frontend/lowering/surfaces.js.map +1 -1
- package/dist/frontend/lowering/text-decoder-encoding.d.ts +2 -0
- package/dist/frontend/lowering/text-decoder-encoding.js +5 -0
- package/dist/frontend/lowering/text-decoder-encoding.js.map +1 -1
- package/dist/frontend/lowering/unregistered-class-types.test.js +3 -3
- package/dist/frontend/lowering/unregistered-class-types.test.js.map +1 -1
- package/dist/frontend/npm-static-prune.js +116 -34
- package/dist/frontend/npm-static-prune.js.map +1 -1
- package/dist/frontend/npm-static-prune.test.js +8 -0
- package/dist/frontend/npm-static-prune.test.js.map +1 -1
- package/dist/frontend/program.d.ts +1 -1
- package/dist/frontend/program.js +53 -24
- package/dist/frontend/program.js.map +1 -1
- package/dist/frontend/program.test.js +18 -0
- package/dist/frontend/program.test.js.map +1 -1
- package/dist/frontend/ts7/ast.js +4 -3
- package/dist/frontend/ts7/ast.js.map +1 -1
- package/dist/frontend/ts7/semantic-json.js +5 -10
- package/dist/frontend/ts7/semantic-json.js.map +1 -1
- package/dist/frontend/type-mapper.d.ts +9 -1
- package/dist/frontend/type-mapper.js +90 -13
- package/dist/frontend/type-mapper.js.map +1 -1
- package/dist/frontend/type-mapper.test.js +23 -0
- package/dist/frontend/type-mapper.test.js.map +1 -1
- package/dist/frontend/union-discriminants.d.ts +1 -1
- package/dist/frontend/union-discriminants.js +2 -2
- package/dist/frontend/union-discriminants.js.map +1 -1
- package/dist/ir/analysis.js +2 -0
- package/dist/ir/analysis.js.map +1 -1
- package/dist/ir/ir.d.ts +52 -33
- package/dist/ir/ir.js +142 -42
- package/dist/ir/ir.js.map +1 -1
- package/dist/ir/ir.test.js +35 -0
- package/dist/ir/ir.test.js.map +1 -1
- package/dist/ir/serialize.js +15 -3
- package/dist/ir/serialize.js.map +1 -1
- package/dist/ir/serialize.test.js +5 -1
- package/dist/ir/serialize.test.js.map +1 -1
- package/dist/ir/validate.js +80 -11
- package/dist/ir/validate.js.map +1 -1
- package/dist/ir/validate.test.js +61 -1
- package/dist/ir/validate.test.js.map +1 -1
- package/dist/native/sanitizer.js +3 -1
- package/dist/native/sanitizer.js.map +1 -1
- package/dist/native/toolchain.d.ts +1 -1
- package/dist/native/toolchain.js +26 -6
- package/dist/native/toolchain.js.map +1 -1
- package/dist/native/toolchain.test.js +53 -1
- package/dist/native/toolchain.test.js.map +1 -1
- package/package.json +20 -20
- package/surface-manifest.json +56 -81
|
@@ -11,13 +11,14 @@ import * as ts from "../ts7/adapter.js";
|
|
|
11
11
|
import { dirname } from "node:path";
|
|
12
12
|
import * as posix from "node:path/posix";
|
|
13
13
|
import { pathToFileURL } from "node:url";
|
|
14
|
+
import { captureContextArguments } from "./function-context.js";
|
|
14
15
|
import { OBJECT_CALLABLE_VALUES } from "./surfaces.js";
|
|
15
16
|
import { wasiGuestPath } from "../../wasi-paths.js";
|
|
16
17
|
import { BIGINT_T, BYTES_ELEMENT_NAME, BOOL, CAUGHT, DYN, DYN_HANDLE_KINDS, F64, JSVAL, NULL_T, REF_TRUTHY_KINDS, REGEX, RUNTIME_ERROR_CLASSES, SEARCH_PARAMS_T, STRING, UNDEFINED_T, VOID, arrayOf, canAdaptDynFuncTo, canDynCheckTo, canBoxFuncIntoDyn, funcOf, isDynTypedRefType, isSupportedArrayElem, isUnitType, jsOpResultKind, shapeHasAccessorSlots, typeEquals, typeKey, unionContainerArmsOk } from "../../ir/ir.js";
|
|
17
18
|
import { cjsClassExprWholeExportOf, cjsExportAssignmentOf, cjsExportDiscardReason, isCjsExportTableLiteral, isCjsJsFile, isJsSourceFile, isModuleExportsAccess, isNodeEsmFile, locOf } from "../program.js";
|
|
18
19
|
import { ARRAY_METHODS, builtinConstLit, builtinFenceHintOf, builtinModuleConstOf, builtinModulesArrayLit, builtinModuleFnOf, COMPOUND_ASSIGN_OPS, ISLAND_SURFACE, isChildSurfaceMember, MAP_METHODS, NARROW_FIRST, SET_METHODS, STRING_INDEX_METHODS, STR_METHODS, UNSUPPORTED_EXPR, sideEffectFreeOptionValue, stdlibGlobalNameOf } from "./surfaces.js";
|
|
19
20
|
import { UNSUPPORTED, blockedBindingUseDiag, requiresDynamicPackageDiag, unsupportedDiag } from "../../diagnostics/diagnostic.js";
|
|
20
|
-
import { PoisonError, dynUndefinedExpr, jsFuncNameOf, neverTaintedJsType, nodeThrowExpr, own } from "./lowerer.js";
|
|
21
|
+
import { PoisonError, dynFallbackType, dynUndefinedExpr, jsFuncNameOf, neverTaintedJsType, nodeThrowExpr, own } from "./lowerer.js";
|
|
21
22
|
import { lowerCollectionSpread, lowerNpmStaticSafeIndexRead, lowerSafeIndexRead, strCharsCall, tryLowerNumericIndexRead } from "./lower-containers.js";
|
|
22
23
|
import { arrayValueRead, arrayValueStore, arrayValueType } from "./array-values.js";
|
|
23
24
|
import { lowerOptionalStringIndex } from "./string-index.js";
|
|
@@ -29,13 +30,14 @@ import { ambientNsRootOf, ambientUndefReadType, ambientUndefVarRootOf, ambientUn
|
|
|
29
30
|
import { expandoMemberRead, expandoWritableTarget } from "./lower-expando.js";
|
|
30
31
|
import { lowerSocketInstanceOf, lowerTlsRootCertificates } from "./lower-server.js";
|
|
31
32
|
import { findGenericMethodOn, lowerStaticFieldRead, staticFieldWriteTarget, storedClassValueType } from "./lower-classes.js";
|
|
33
|
+
import { hasRuntimeStatics } from "./class-runtime-statics.js";
|
|
32
34
|
import { bindingNeverReassigned, funcTypeFromParamShapes, implicitMonoFile, lowerTaggedTemplate, nullishGenericBindingUnitOf, objLitGenericFnInfoOf, objLitGenericFnNodeOf, requireObjLitGenericReceiver } from "./lower-calls.js";
|
|
33
35
|
import { mixinFnOfCallee } from "./lower-mixins.js";
|
|
34
36
|
import { isConstAssertionTypeNode, isGenericCallableMemberType, isParseArgsDynTypeName, underConstAssertion, unitOnlyUnion, withUnitArm } from "../type-mapper.js";
|
|
35
37
|
import { lowerYield } from "./lower-generators.js";
|
|
36
|
-
import { errorToStringCall } from "./error-methods.js";
|
|
38
|
+
import { errorPropertyRead, errorPropertyWrite, errorToStringCall } from "./error-methods.js";
|
|
37
39
|
import { lowerStreamProperty, lowerStreamStateProperty, streamSidesOf } from "./lower-stream.js";
|
|
38
|
-
import { countedFor, numLit, varRef } from "../../ir/build.js";
|
|
40
|
+
import { countedFor, numLit, strLit, varRef } from "../../ir/build.js";
|
|
39
41
|
import { unionWideningTags } from "../../ir/analysis.js";
|
|
40
42
|
import { isSafeToDiscard, isSafeToMoveConditionEarlier, isSafeToRepeat } from "./expressions/evaluation-safety.js";
|
|
41
43
|
import { globalSymbolKey } from "./expressions/global-symbols.js";
|
|
@@ -52,8 +54,12 @@ import { lowerClassMethodValue } from "./class-method-values.js";
|
|
|
52
54
|
import { classInstanceOf } from "./class-dynamic-dispatch.js";
|
|
53
55
|
import { lowerGlobalValue } from "./lower-global-value.js";
|
|
54
56
|
import { lowerClassPrototypeData } from "./class-prototypes.js";
|
|
55
|
-
import {
|
|
57
|
+
import { isClassCallback } from "./class-callbacks.js";
|
|
58
|
+
import { builtinPrototypeMethod, lowerArrayIsArrayValue, lowerCheckedPredicateValue, lowerNumberParserValue, lowerObjectAssignValue, lowerStringCodesValue } from "./lower-builtin-values.js";
|
|
59
|
+
import { lowerArrayFromValue } from "./lower-containers.js";
|
|
56
60
|
import { lowerPerfHooksTypeof } from "./lower-builtins.js";
|
|
61
|
+
import { jsBindingHasOpenWrites } from "./lower-stmts.js";
|
|
62
|
+
import { checkedClassInstanceOf } from "./class-construction.js";
|
|
57
63
|
/** A template piece's RAW text (String.raw's contract: escapes stay
|
|
58
64
|
* characters). 7's client AST ships no rawText at runtime (the typing
|
|
59
65
|
* declares it; the serialized node data omits it), so the raw span comes
|
|
@@ -704,8 +710,10 @@ function lowerExprInner(lowerer, expr) {
|
|
|
704
710
|
// `arguments` in a variadic JS function (the rest-marked form): the
|
|
705
711
|
// synthetic trailing dyn-array param — lambdaSignature marked the
|
|
706
712
|
// type and lowerLambda declared the local.
|
|
707
|
-
if (expr.text === "arguments"
|
|
708
|
-
|
|
713
|
+
if (expr.text === "arguments") {
|
|
714
|
+
const binding = captureContextArguments(lowerer.fnStack);
|
|
715
|
+
if (binding)
|
|
716
|
+
return { kind: "varRef", localId: binding.id, type: DYN, loc };
|
|
709
717
|
}
|
|
710
718
|
// A compiler-projected adapter as a VALUE: the adapter has no
|
|
711
719
|
// runtime function object (its calls rewrite directly) — call it
|
|
@@ -1052,14 +1060,36 @@ function lowerExprInner(lowerer, expr) {
|
|
|
1052
1060
|
// type-mapper.ts pins the one concrete signature `(value: string) =>
|
|
1053
1061
|
// primitive`; direct calls `String(x)` never reach here — the call
|
|
1054
1062
|
// lowering intercepts them with the wider static coercions).
|
|
1055
|
-
const jsPrimitiveCtorSelector = isJsSourceFile(expr.getSourceFile())
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
+
const jsPrimitiveCtorSelector = isJsSourceFile(expr.getSourceFile());
|
|
1064
|
+
const primitiveName = stdlibGlobalNameOf(lowerer, expr);
|
|
1065
|
+
if (primitiveName === "String" || primitiveName === "Number" || primitiveName === "Boolean" || primitiveName === "BigInt") {
|
|
1066
|
+
return primitiveCtorClosure(lowerer, primitiveName, loc, jsPrimitiveCtorSelector);
|
|
1067
|
+
}
|
|
1068
|
+
if (lowerer.isStdlibGlobal(expr, "ArrayBuffer"))
|
|
1069
|
+
return { kind: "libCall", fn: "arrayBuffer.constructor", args: [], type: DYN, loc };
|
|
1070
|
+
if (Object.values(BYTES_ELEMENT_NAME).includes(expr.text) && lowerer.isStdlibSymbol(lowerer.checker.getSymbolAtLocation(expr))) {
|
|
1071
|
+
return { kind: "libCall", fn: "bytes.constructor", args: [{ kind: "strLit", value: expr.text, type: STRING, loc }], type: DYN, loc };
|
|
1072
|
+
}
|
|
1073
|
+
if ((expr.text === "encodeURIComponent" || expr.text === "encodeURI" || expr.text === "decodeURIComponent" || expr.text === "decodeURI") && lowerer.isStdlibGlobal(expr, expr.text)) {
|
|
1074
|
+
const name = `%builtin.${expr.text}`;
|
|
1075
|
+
const type = funcOf([DYN], STRING);
|
|
1076
|
+
if (!lowerer.liftedFns.some((fn) => fn.name === name)) {
|
|
1077
|
+
const value = { kind: "libCall", fn: "dyn.toStringCoerce", args: [varRef("value", DYN, loc)], type: STRING, loc };
|
|
1078
|
+
const fn = expr.text === "encodeURIComponent" ? "str.encodeUriComponent" : expr.text === "encodeURI" ? "str.encodeUri" : expr.text === "decodeURI" ? "str.decodeUri" : "str.decodeUriComponent";
|
|
1079
|
+
lowerer.liftedFns.push({ name, params: [{ localId: "value", name: "value", type: DYN }],
|
|
1080
|
+
locals: [{ id: "value", name: "value", type: DYN, mutable: false }], returnType: STRING,
|
|
1081
|
+
body: [{ kind: "return", value: { kind: "libCall", fn, args: [value], type: STRING, loc }, loc }], loc });
|
|
1082
|
+
}
|
|
1083
|
+
return { kind: "closure", fnName: name, captures: [], type, loc };
|
|
1084
|
+
}
|
|
1085
|
+
if (!lowerer.dynamic && lowerer.isStdlibGlobal(expr, "crypto"))
|
|
1086
|
+
return { kind: "libCall", fn: "crypto.native", args: [], type: DYN, loc };
|
|
1087
|
+
const nativeAlias = stdlibGlobalNameOf(lowerer, expr);
|
|
1088
|
+
if (nativeAlias === "Buffer" && expr.text !== "Buffer") {
|
|
1089
|
+
return { kind: "strLit", value: "[builtin Buffer]", type: STRING, loc };
|
|
1090
|
+
}
|
|
1091
|
+
if (!lowerer.dynamic && lowerer.isStdlibGlobal(expr, "fetch")) {
|
|
1092
|
+
return { kind: "libCall", fn: "fetch.function", args: [], type: DYN, loc };
|
|
1063
1093
|
}
|
|
1064
1094
|
// The lib fence's IDENTIFIER chokepoint: the real standard library
|
|
1065
1095
|
// resolves names the old minimal ambient world never declared
|
|
@@ -1260,8 +1290,13 @@ function lowerExprInner(lowerer, expr) {
|
|
|
1260
1290
|
// `this` in plain nested functions is already a tsc error under
|
|
1261
1291
|
// noImplicitThis, so the generic scope walk here is preflight-safe.
|
|
1262
1292
|
const local = lowerer.resolveThis();
|
|
1263
|
-
if (local)
|
|
1264
|
-
|
|
1293
|
+
if (local) {
|
|
1294
|
+
const value = { kind: "varRef", localId: local.id, type: local.type, loc };
|
|
1295
|
+
const initialized = lowerer.ctx.superInitialized;
|
|
1296
|
+
if (initialized)
|
|
1297
|
+
return { kind: "seqExpr", stmts: [{ kind: "if", cond: { kind: "unary", op: "!", operand: { kind: "varRef", localId: initialized.id, type: BOOL, loc }, type: BOOL, loc }, then: [{ kind: "exprStmt", expr: nodeThrowExpr(5, "", "Must call super constructor in derived class before accessing 'this' or returning from derived constructor", DYN, loc), loc }], else_: null, loc }], result: value, type: value.type, loc };
|
|
1298
|
+
return value;
|
|
1299
|
+
}
|
|
1265
1300
|
// `this` in a plain JS FUNCTION (not a method): the AMBIENT
|
|
1266
1301
|
// RECEIVER (libCall dyn.this — scr_dyn_this_get). Firing sites bind
|
|
1267
1302
|
// the emitting handle around each listener call (Node calls
|
|
@@ -1456,6 +1491,12 @@ function lowerExprInner(lowerer, expr) {
|
|
|
1456
1491
|
const prototypeData = lowerClassPrototypeData(lowerer, expr);
|
|
1457
1492
|
if (prototypeData)
|
|
1458
1493
|
return prototypeData;
|
|
1494
|
+
if (ts.isPropertyAccessExpression(expr.expression) && expr.expression.name.text === "prototype") {
|
|
1495
|
+
const prototype = lowerClassPrototypeData(lowerer, expr.expression);
|
|
1496
|
+
if (prototype)
|
|
1497
|
+
return { kind: "dynKeyGet", value: prototype,
|
|
1498
|
+
key: { kind: "strLit", value: expr.name.text, type: STRING, loc }, type: DYN, loc };
|
|
1499
|
+
}
|
|
1459
1500
|
// `super.x`: the base chain's GETTER, called directly (super
|
|
1460
1501
|
// dispatch is static in JS — never through the dynamic class).
|
|
1461
1502
|
// super.method() calls are routed at the call site; a bare super
|
|
@@ -1501,6 +1542,14 @@ function lowerExprInner(lowerer, expr) {
|
|
|
1501
1542
|
["iterator", "asyncIterator", "toStringTag", "toPrimitive", "hasInstance", "isConcatSpreadable", "match", "matchAll", "replace", "search", "split", "species", "unscopables", "dispose", "asyncDispose"].includes(expr.name.text)) {
|
|
1502
1543
|
return { kind: "libCall", fn: "sym.wellKnown", args: [{ kind: "strLit", value: expr.name.text, type: STRING, loc }], type: { kind: "symbol" }, loc };
|
|
1503
1544
|
}
|
|
1545
|
+
if (!lowerer.dynamic && lowerer.stdlibGlobalMember(expr, "Object") === "freeze") {
|
|
1546
|
+
const name = "%builtin.Object.freeze";
|
|
1547
|
+
if (!lowerer.liftedFns.some((fn) => fn.name === name))
|
|
1548
|
+
lowerer.liftedFns.push({ name,
|
|
1549
|
+
params: [{ localId: "value", name: "value", type: DYN }], locals: [{ id: "value", name: "value", type: DYN, mutable: false }], returnType: DYN,
|
|
1550
|
+
body: [{ kind: "return", value: { kind: "libCall", fn: "dyn.freeze", args: [varRef("value", DYN, loc)], type: DYN, loc }, loc }], loc });
|
|
1551
|
+
return { kind: "closure", fnName: name, captures: [], type: funcOf([DYN], DYN), loc };
|
|
1552
|
+
}
|
|
1504
1553
|
if (lowerer.stdlibGlobalMember(expr, "globalThis") === "console") {
|
|
1505
1554
|
return { kind: "libCall", fn: "console.native", args: [], type: DYN, loc };
|
|
1506
1555
|
}
|
|
@@ -1586,15 +1635,6 @@ function lowerExprInner(lowerer, expr) {
|
|
|
1586
1635
|
}
|
|
1587
1636
|
return read;
|
|
1588
1637
|
}
|
|
1589
|
-
// `m.groups` on a match result whose regex is statically known:
|
|
1590
|
-
// the compile-time record projection over the honest slice (or
|
|
1591
|
-
// Node's undefined when the pattern has no named groups) — see
|
|
1592
|
-
// lowerMatchGroupsRead.
|
|
1593
|
-
{
|
|
1594
|
-
const g = lowerMatchGroupsRead(lowerer, expr);
|
|
1595
|
-
if (g !== null)
|
|
1596
|
-
return g;
|
|
1597
|
-
}
|
|
1598
1638
|
// `m.index` on a for-of-over-matchAll binding reads the companion-
|
|
1599
1639
|
// index array at this iteration's cursor — always a number: every
|
|
1600
1640
|
// drained row matched, so the lib's `.index` is never undefined
|
|
@@ -1612,6 +1652,25 @@ function lowerExprInner(lowerer, expr) {
|
|
|
1612
1652
|
};
|
|
1613
1653
|
}
|
|
1614
1654
|
}
|
|
1655
|
+
if ((expr.name.text === "index" || expr.name.text === "input") && !expr.questionDotToken) {
|
|
1656
|
+
const represented = tryLowerExpression(lowerer, expr.expression);
|
|
1657
|
+
if (represented && isMatchSliceType(lowerer, represented.type) &&
|
|
1658
|
+
(lowerer.isStdlibMember(expr) || isJsSourceFile(expr.getSourceFile()))) {
|
|
1659
|
+
const recv = represented;
|
|
1660
|
+
const read = { kind: "dynKeyGet", value: lowerer.coerceToExpected(recv, DYN),
|
|
1661
|
+
key: { kind: "strLit", value: expr.name.text, type: STRING, loc }, type: DYN, loc };
|
|
1662
|
+
return lowerer.maybeNarrow(read, expr);
|
|
1663
|
+
}
|
|
1664
|
+
}
|
|
1665
|
+
// `m.groups` on a match result whose regex is statically known:
|
|
1666
|
+
// the compile-time record projection over the honest slice (or
|
|
1667
|
+
// Node's undefined when the pattern has no named groups) — see
|
|
1668
|
+
// lowerMatchGroupsRead.
|
|
1669
|
+
{
|
|
1670
|
+
const g = lowerMatchGroupsRead(lowerer, expr);
|
|
1671
|
+
if (g !== null)
|
|
1672
|
+
return g;
|
|
1673
|
+
}
|
|
1615
1674
|
// `arguments.length` in a TYPED function whose signature is
|
|
1616
1675
|
// FIXED-ARITY (no optional/default/rest parameters): tsc enforces
|
|
1617
1676
|
// exact arity at every call site and call/apply/bind indirection is
|
|
@@ -1833,6 +1892,12 @@ function lowerExprInner(lowerer, expr) {
|
|
|
1833
1892
|
if (canonical !== null) {
|
|
1834
1893
|
if (!lowerer.dynamic && canonical === "globalThis")
|
|
1835
1894
|
return lowerGlobalValue(lowerer, expr);
|
|
1895
|
+
if (!lowerer.dynamic && canonical === "ArrayBuffer")
|
|
1896
|
+
return { kind: "libCall", fn: "arrayBuffer.constructor", args: [], type: DYN, loc };
|
|
1897
|
+
if (!lowerer.dynamic && canonical === "fetch")
|
|
1898
|
+
return { kind: "libCall", fn: "fetch.function", args: [], type: DYN, loc };
|
|
1899
|
+
if (!lowerer.dynamic && Object.values(BYTES_ELEMENT_NAME).includes(canonical))
|
|
1900
|
+
return { kind: "libCall", fn: "bytes.constructor", args: [{ kind: "strLit", value: canonical, type: STRING, loc }], type: DYN, loc };
|
|
1836
1901
|
return { kind: "strLit", value: `[builtin ${canonical}]`, type: STRING, loc };
|
|
1837
1902
|
}
|
|
1838
1903
|
}
|
|
@@ -1921,10 +1986,14 @@ function lowerExprInner(lowerer, expr) {
|
|
|
1921
1986
|
// is an ordinary recordGet — maybeNarrow then bridges the union slot
|
|
1922
1987
|
// to the checker's narrowed arm, exactly like a union field read.
|
|
1923
1988
|
if (expr.name.text === "done" || expr.name.text === "value") {
|
|
1924
|
-
const
|
|
1925
|
-
|
|
1926
|
-
|
|
1989
|
+
const receiverType = lowerer.typeOf(expr.expression);
|
|
1990
|
+
const recvSym = receiverType.getAliasSymbol()?.name === "IteratorResult" ? receiverType.getAliasSymbol() : receiverType.getSymbol();
|
|
1991
|
+
if ((recvSym?.name === "IteratorResult" || recvSym?.name === "IteratorYieldResult" || recvSym?.name === "IteratorReturnResult") &&
|
|
1992
|
+
lowerer.checker.declarationsOf(recvSym).some((d) => (ts.isInterfaceDeclaration(d) || ts.isTypeAliasDeclaration(d)) && lowerer.isStdlibFile(d.getSourceFile()))) {
|
|
1927
1993
|
const recv = lowerer.lowerExpr(expr.expression);
|
|
1994
|
+
if (recv.type.kind === "dyn")
|
|
1995
|
+
return lowerer.maybeNarrow({ kind: "dynKeyGet", value: recv,
|
|
1996
|
+
key: { kind: "strLit", value: expr.name.text, type: STRING, loc }, type: DYN, loc }, expr);
|
|
1928
1997
|
if (recv.type.kind === "record") {
|
|
1929
1998
|
const shape = lowerer.shapes.get(recv.type.shapeId);
|
|
1930
1999
|
const field = shape?.fields.find((f) => f.name === expr.name.text);
|
|
@@ -2021,10 +2090,11 @@ function lowerExprInner(lowerer, expr) {
|
|
|
2021
2090
|
// on undefined/null receivers unless an earlier `?.` guards the
|
|
2022
2091
|
// chain. Scalar-narrowed occurrences bridge via maybeNarrow's
|
|
2023
2092
|
// validated dynCheck as usual.
|
|
2024
|
-
if (recvLowered.type.kind === "dyn")
|
|
2093
|
+
if (recvLowered.type.kind === "dyn" || isJsSourceFile(expr.getSourceFile()) &&
|
|
2094
|
+
["f64", "bool", "bigint", "string", "symbol"].includes(recvLowered.type.kind)) {
|
|
2025
2095
|
const key = { kind: "strLit", value: expr.name.text, type: STRING, loc: locOf(expr.name) };
|
|
2026
2096
|
const opt = hasOptionalChainGuard(expr.expression);
|
|
2027
|
-
return lowerer.maybeNarrow({ kind: "dynKeyGet", key, ...(opt ? { optional: true } : {}), value: recvLowered, type: DYN, loc }, expr);
|
|
2097
|
+
return lowerer.maybeNarrow({ kind: "dynKeyGet", key, ...(opt ? { optional: true } : {}), value: lowerer.coerceToExpected(recvLowered, DYN), type: DYN, loc }, expr);
|
|
2028
2098
|
}
|
|
2029
2099
|
// The lowered receiver is a RECORD the checker spelled wider —
|
|
2030
2100
|
// `s.match(re).groups.key` in a JS file: the checker says
|
|
@@ -2074,6 +2144,16 @@ function lowerExprInner(lowerer, expr) {
|
|
|
2074
2144
|
// reports a class. Its property bag must remain reachable, while
|
|
2075
2145
|
// an absent element takes the normal checked-value TypeError.
|
|
2076
2146
|
const nativeReceiver = lowerer.stripUndefinedArm(recvLowered.type);
|
|
2147
|
+
if (ts.isPrivateIdentifier(expr.name) && recvLowered.type.kind === "object") {
|
|
2148
|
+
const field = lowerer.classes.get(recvLowered.type.className)?.fields.get(expr.name.text);
|
|
2149
|
+
if (field)
|
|
2150
|
+
return { kind: "fieldGet", obj: recvLowered, className: recvLowered.type.className,
|
|
2151
|
+
field: expr.name.text, type: field, loc };
|
|
2152
|
+
}
|
|
2153
|
+
if (nativeReceiver.kind === "object" && nativeReceiver.className === "%Error") {
|
|
2154
|
+
return lowerer.maybeNarrow({ kind: "dynKeyGet", value: lowerer.coerceToExpected(recvLowered, DYN),
|
|
2155
|
+
key: { kind: "strLit", value: expr.name.text, type: STRING, loc }, type: DYN, loc }, expr);
|
|
2156
|
+
}
|
|
2077
2157
|
if (isDynTypedRefType(nativeReceiver)) {
|
|
2078
2158
|
const info = lowerer.classes.get(nativeReceiver.className);
|
|
2079
2159
|
if (info && !info.def.runtime && !info.builtinError && !info.builtinEmitter && !info.builtinStream) {
|
|
@@ -2107,7 +2187,7 @@ function moduleFileName(lowerer, sf) {
|
|
|
2107
2187
|
: sf.fileName;
|
|
2108
2188
|
}
|
|
2109
2189
|
function importMetaProperty(lowerer, expr) {
|
|
2110
|
-
if (
|
|
2190
|
+
if (!ts.isMetaProperty(expr.expression))
|
|
2111
2191
|
return null;
|
|
2112
2192
|
const meta = expr.expression;
|
|
2113
2193
|
if (meta.keywordToken !== ts.SyntaxKind.ImportKeyword || meta.name.text !== "meta")
|
|
@@ -2115,6 +2195,8 @@ function importMetaProperty(lowerer, expr) {
|
|
|
2115
2195
|
const sf = expr.getSourceFile();
|
|
2116
2196
|
const fileName = moduleFileName(lowerer, sf);
|
|
2117
2197
|
switch (expr.name.text) {
|
|
2198
|
+
case "env":
|
|
2199
|
+
return dynUndefinedExpr(locOf(expr));
|
|
2118
2200
|
case "url":
|
|
2119
2201
|
return {
|
|
2120
2202
|
kind: "strLit",
|
|
@@ -2398,7 +2480,13 @@ export function lowerTernary(lowerer, expr, expected) {
|
|
|
2398
2480
|
thenRaw.type.kind === "func" && elseRaw.type.kind === "func" &&
|
|
2399
2481
|
!typeEquals(thenRaw.type, elseRaw.type) &&
|
|
2400
2482
|
lowerer.dynConvertible(thenRaw.type) && lowerer.dynConvertible(elseRaw.type);
|
|
2401
|
-
|
|
2483
|
+
// JavaScript inference can discard an initially-undefined field from
|
|
2484
|
+
// a conditional's type even after that field acquired other values.
|
|
2485
|
+
// A checked arm must retain its actual representation at the join.
|
|
2486
|
+
const checkedJsJoin = isJsSourceFile(expr.getSourceFile()) &&
|
|
2487
|
+
(thenRaw.type.kind === "dyn" || elseRaw.type.kind === "dyn") &&
|
|
2488
|
+
lowerer.dynConvertible(thenRaw.type) && lowerer.dynConvertible(elseRaw.type);
|
|
2489
|
+
const type = callableJoin || checkedJsJoin ? DYN :
|
|
2402
2490
|
thenRaw.type.kind === "array" && typeEquals(thenRaw.type, elseRaw.type)
|
|
2403
2491
|
? thenRaw.type
|
|
2404
2492
|
: dynJoin
|
|
@@ -2454,6 +2542,11 @@ export function maybeNarrow(lowerer, expr, node) {
|
|
|
2454
2542
|
if (expr.type.kind === "dyn") {
|
|
2455
2543
|
if (isJsSourceFile(node.getSourceFile()) && ts.isIdentifier(node)) {
|
|
2456
2544
|
const symbol = lowerer.resolveValueSymbol(node);
|
|
2545
|
+
if (symbol && lowerer.checker.declarationsOf(symbol).some((decl) => ts.isVariableDeclaration(decl) && jsBindingHasOpenWrites(lowerer, decl)))
|
|
2546
|
+
return expr;
|
|
2547
|
+
if (symbol && lowerer.checker.declarationsOf(symbol).some((decl) => ts.isParameter(decl) && decl.initializer && !decl.type &&
|
|
2548
|
+
!/@(?:param|type)\b/.test(decl.getSourceFile().text.slice(decl.parent?.pos ?? decl.pos, decl.getStart()))))
|
|
2549
|
+
return expr;
|
|
2457
2550
|
if (symbol && lowerer.checker.declarationsOf(symbol).some((decl) => {
|
|
2458
2551
|
if (!ts.isParameter(decl) || decl.type)
|
|
2459
2552
|
return false;
|
|
@@ -3003,6 +3096,10 @@ function lowerNullishPair(lowerer, expr, loc, left) {
|
|
|
3003
3096
|
if (fresh)
|
|
3004
3097
|
return { kind: "nullish", left, right: fresh, type: fresh.type, loc };
|
|
3005
3098
|
const type = lowerer.irTypeOf(expr);
|
|
3099
|
+
if (type.kind === "dyn" && lowerer.dynConvertible(left.type)) {
|
|
3100
|
+
return { kind: "nullish", left: lowerer.coerceToExpected(left, DYN),
|
|
3101
|
+
right: lowerer.lowerExprExpecting(expr.right, DYN), type: DYN, loc };
|
|
3102
|
+
}
|
|
3006
3103
|
if (typeEquals(type, left.type) || (rest.length === 1 && typeEquals(type, rest[0]))) {
|
|
3007
3104
|
const right = lowerer.lowerExprExpecting(expr.right, type);
|
|
3008
3105
|
return { kind: "nullish", left, right, type, loc };
|
|
@@ -3073,6 +3170,8 @@ export function lowerCondition(lowerer, expr) {
|
|
|
3073
3170
|
if (op === ts.SyntaxKind.AmpersandAmpersandToken || op === ts.SyntaxKind.BarBarToken) {
|
|
3074
3171
|
const isAnd = op === ts.SyntaxKind.AmpersandAmpersandToken;
|
|
3075
3172
|
const left = lowerer.lowerCondition(e.left);
|
|
3173
|
+
if (left.kind === "boolLit" && left.value !== isAnd)
|
|
3174
|
+
return left;
|
|
3076
3175
|
// The right operand evaluates only when the left already answered
|
|
3077
3176
|
// (true for &&, false for ||) — aliased-typeof narrows the left
|
|
3078
3177
|
// PROVES under that polarity hold while it lowers (`type ===
|
|
@@ -3089,6 +3188,8 @@ export function lowerCondition(lowerer, expr) {
|
|
|
3089
3188
|
lowerer.runtimeOptionalLocals.add(lowerer.runtimeOptionalRootOf(runtimeOptionalLocal));
|
|
3090
3189
|
}
|
|
3091
3190
|
});
|
|
3191
|
+
if (left.kind === "boolLit")
|
|
3192
|
+
return right;
|
|
3092
3193
|
return {
|
|
3093
3194
|
kind: "logical",
|
|
3094
3195
|
op: isAnd ? "&&" : "||",
|
|
@@ -3366,13 +3467,56 @@ export function eqComparableUnion(lowerer, unionId) {
|
|
|
3366
3467
|
* the receiver type AND the ambient-file provenance of the member are
|
|
3367
3468
|
* verified — the name alone proves nothing. */
|
|
3368
3469
|
export function lowerIntrinsicProperty(lowerer, expr) {
|
|
3470
|
+
for (const name of ["String", "Number", "Boolean", "BigInt"]) {
|
|
3471
|
+
if (!lowerer.chainBlocked(expr) && lowerer.isStdlibGlobal(expr, name)) {
|
|
3472
|
+
return primitiveCtorClosure(lowerer, name, locOf(expr), isJsSourceFile(expr.getSourceFile()));
|
|
3473
|
+
}
|
|
3474
|
+
}
|
|
3475
|
+
if (lowerer.stdlibGlobalMember(expr, "Reflect") === "ownKeys") {
|
|
3476
|
+
const value = lowerer.lowerNativeCallableValue({
|
|
3477
|
+
fn: "dyn.ownKeys", params: [DYN], result: DYN, valueParams: [{ mode: "required", type: DYN }],
|
|
3478
|
+
}, "Reflect.ownKeys", locOf(expr));
|
|
3479
|
+
return { kind: "dynFrom", value, fnName: "ownKeys", type: DYN, loc: locOf(expr) };
|
|
3480
|
+
}
|
|
3369
3481
|
if (lowerer.chainBlocked(expr))
|
|
3370
3482
|
return null;
|
|
3483
|
+
const builtinPrototype = builtinPrototypeMethod(lowerer, expr);
|
|
3484
|
+
if (builtinPrototype)
|
|
3485
|
+
return { kind: "libCall", fn: "dyn.builtinMethod", args: [
|
|
3486
|
+
{ kind: "strLit", value: builtinPrototype, type: STRING, loc: locOf(expr) },
|
|
3487
|
+
{ kind: "strLit", value: expr.name.text, type: STRING, loc: locOf(expr.name) },
|
|
3488
|
+
], type: DYN, loc: locOf(expr) };
|
|
3489
|
+
if (ts.isPropertyAccessExpression(expr.expression) &&
|
|
3490
|
+
lowerer.stdlibGlobalMember(expr.expression, "Array") === "prototype") {
|
|
3491
|
+
return { kind: "dynKeyGet", value: { kind: "libCall", fn: "dyn.arrayPrototype", args: [], type: DYN, loc: locOf(expr.expression) },
|
|
3492
|
+
key: { kind: "strLit", value: expr.name.text, type: STRING, loc: locOf(expr.name) }, type: DYN, loc: locOf(expr) };
|
|
3493
|
+
}
|
|
3494
|
+
if (expr.name.text === "apply" && ts.isPropertyAccessExpression(expr.expression) &&
|
|
3495
|
+
lowerer.stdlibGlobalMember(expr.expression, "Function") === "prototype")
|
|
3496
|
+
return { kind: "libCall", fn: "dyn.functionApply", args: [], type: DYN, loc: locOf(expr) };
|
|
3371
3497
|
if (lowerer.stdlibGlobalMember(expr, "Array") === "prototype")
|
|
3372
3498
|
return { kind: "libCall", fn: "dyn.arrayPrototype", args: [], type: DYN, loc: locOf(expr) };
|
|
3499
|
+
if (lowerer.stdlibGlobalMember(expr, "Object") === "prototype")
|
|
3500
|
+
return { kind: "libCall", fn: "dyn.objectPrototype", args: [], type: DYN, loc: locOf(expr) };
|
|
3373
3501
|
if (lowerer.stdlibGlobalMember(expr, "Array") === "isArray")
|
|
3374
3502
|
return lowerArrayIsArrayValue(lowerer, locOf(expr));
|
|
3503
|
+
if (lowerer.stdlibGlobalMember(expr, "Array") === "from")
|
|
3504
|
+
return lowerArrayFromValue(lowerer, locOf(expr));
|
|
3505
|
+
const stringMember = lowerer.stdlibGlobalMember(expr, "String");
|
|
3506
|
+
if (stringMember === "fromCharCode" || stringMember === "fromCodePoint")
|
|
3507
|
+
return lowerStringCodesValue(lowerer, stringMember, locOf(expr));
|
|
3508
|
+
const numberMember = lowerer.stdlibGlobalMember(expr, "Number");
|
|
3509
|
+
if (numberMember === "parseInt" || numberMember === "parseFloat")
|
|
3510
|
+
return lowerNumberParserValue(lowerer, numberMember, locOf(expr));
|
|
3511
|
+
if (lowerer.stdlibGlobalMember(expr, "Buffer") === "isBuffer")
|
|
3512
|
+
return lowerCheckedPredicateValue(lowerer, "Buffer.isBuffer", "buffer", locOf(expr));
|
|
3513
|
+
if (lowerer.stdlibGlobalMember(expr, "Date") === "now")
|
|
3514
|
+
return lowerer.lowerNativeCallableValue({
|
|
3515
|
+
fn: "date.now", params: [], result: F64, valueParams: [],
|
|
3516
|
+
}, "Date.now", locOf(expr));
|
|
3375
3517
|
if (stdlibGlobalNameOf(lowerer, expr.expression) === "Object") {
|
|
3518
|
+
if (expr.name.text === "assign")
|
|
3519
|
+
return lowerObjectAssignValue(lowerer, locOf(expr));
|
|
3376
3520
|
const fn = own(OBJECT_CALLABLE_VALUES, expr.name.text);
|
|
3377
3521
|
if (fn)
|
|
3378
3522
|
return lowerer.lowerNativeCallableValue(fn, `Object.${expr.name.text}`, locOf(expr));
|
|
@@ -3410,6 +3554,15 @@ export function lowerIntrinsicProperty(lowerer, expr) {
|
|
|
3410
3554
|
if (kind === "child" ? !isChildSurfaceMember(lowerer, expr) : !tupleLengthOnArray && !lowerer.isStdlibMember(expr))
|
|
3411
3555
|
return null;
|
|
3412
3556
|
const name = expr.name.text;
|
|
3557
|
+
if (kind === "array" && name === "constructor" && isJsSourceFile(expr.getSourceFile())) {
|
|
3558
|
+
const receiver = lowerer.lowerExpr(expr.expression);
|
|
3559
|
+
if (receiver.type.kind === "dyn")
|
|
3560
|
+
return { kind: "dynKeyGet", value: receiver,
|
|
3561
|
+
key: { kind: "strLit", value: name, type: STRING, loc: locOf(expr) }, type: DYN, loc: locOf(expr) };
|
|
3562
|
+
// Ordinary arrays keep the existing Array builtin identity token.
|
|
3563
|
+
const result = { kind: "strLit", value: "[builtin Array]", type: STRING, loc: locOf(expr) };
|
|
3564
|
+
return { kind: "seqExpr", stmts: [{ kind: "exprStmt", expr: receiver, loc: locOf(expr) }], result, type: STRING, loc: locOf(expr) };
|
|
3565
|
+
}
|
|
3413
3566
|
const strictReceiver = (expected) => {
|
|
3414
3567
|
const value = lowerer.lowerExpr(expr.expression);
|
|
3415
3568
|
if (value.type.kind === "dyn")
|
|
@@ -3585,6 +3738,9 @@ export function lowerIntrinsicProperty(lowerer, expr) {
|
|
|
3585
3738
|
lowerer.noLowering(`URLSearchParams.${name}`, expr, "get, getAll, set, append, delete, has, sort, size, toString(), forEach, and for-of iteration are the supported URLSearchParams members", lowerer.checker.getSymbolAtLocation(expr.name));
|
|
3586
3739
|
}
|
|
3587
3740
|
if (kind === "regex") {
|
|
3741
|
+
if (name === "lastIndex") {
|
|
3742
|
+
return { kind: "regexIntrinsic", method: "lastIndex", receiver: strictReceiver({ kind: "regex" }), args: [], type: F64, loc: locOf(expr) };
|
|
3743
|
+
}
|
|
3588
3744
|
if (name === "source" || name === "flags") {
|
|
3589
3745
|
const receiver = strictReceiver({ kind: "regex" });
|
|
3590
3746
|
return { kind: "regexIntrinsic", method: name, receiver, args: [], type: STRING, loc: locOf(expr) };
|
|
@@ -3604,6 +3760,12 @@ export function lowerIntrinsicProperty(lowerer, expr) {
|
|
|
3604
3760
|
}
|
|
3605
3761
|
if (kind === "bytes") {
|
|
3606
3762
|
const loc = locOf(expr);
|
|
3763
|
+
if (name === "constructor") {
|
|
3764
|
+
const expected = lowerer.mapTypeOf(lowerer.typeOf(expr.expression));
|
|
3765
|
+
const receiver = expected?.kind === "bytes" ? strictReceiver(expected) : lowerer.lowerExpr(expr.expression);
|
|
3766
|
+
return { kind: "dynKeyGet", value: lowerer.coerceInto(expr.expression, receiver, DYN),
|
|
3767
|
+
key: { kind: "strLit", value: name, type: STRING, loc }, type: DYN, loc };
|
|
3768
|
+
}
|
|
3607
3769
|
if (name === "length" || name === "byteLength") {
|
|
3608
3770
|
const expected = lowerer.mapTypeOf(lowerer.typeOf(expr.expression));
|
|
3609
3771
|
let receiver = expected?.kind === "bytes"
|
|
@@ -3674,9 +3836,10 @@ export function lowerIntrinsicProperty(lowerer, expr) {
|
|
|
3674
3836
|
const expected = kind === "string"
|
|
3675
3837
|
? STRING
|
|
3676
3838
|
: lowerer.mapTypeOf(lowerer.typeOf(expr.expression));
|
|
3677
|
-
let receiver =
|
|
3678
|
-
|
|
3679
|
-
|
|
3839
|
+
let receiver = lowerer.lowerExpr(expr.expression);
|
|
3840
|
+
if (receiver.type.kind !== "dyn" && expected && (expected.kind === "string" || expected.kind === "array")) {
|
|
3841
|
+
receiver = lowerer.runtimeOptionalPropertyReceiver(expr.expression, receiver, expected, name) ?? receiver;
|
|
3842
|
+
}
|
|
3680
3843
|
if (receiver.type.kind === "union" && lowerer.armTag(receiver.type.unionId, UNDEFINED_T) >= 0 && kind === "array") {
|
|
3681
3844
|
const present = lowerer.stripUndefinedArm(receiver.type);
|
|
3682
3845
|
const helper = present.kind === "array"
|
|
@@ -3742,6 +3905,19 @@ export function lowerArrayLiteral(lowerer, expr, expected) {
|
|
|
3742
3905
|
// destination can use the ordinary tuple-to-array coercion afterward.
|
|
3743
3906
|
const tsType = underConstAssertion(expr) ? lowerer.typeOf(expr) : ctxType ?? lowerer.typeOf(expr);
|
|
3744
3907
|
let mapped = expected ?? lowerer.mapTypeOf(tsType);
|
|
3908
|
+
// Inferred JavaScript arrays can contain unrelated constructors with
|
|
3909
|
+
// structurally equal checker types. Their native class ABIs still differ.
|
|
3910
|
+
if (!expected && isJsSourceFile(expr.getSourceFile()) && mapped?.kind === "array" && mapped.elem.kind === "classval")
|
|
3911
|
+
mapped = DYN;
|
|
3912
|
+
// An inferred destructuring pattern supplies a contextual [any, ...]
|
|
3913
|
+
// tuple. Its positions do not erase the literal's inferred element
|
|
3914
|
+
// types; explicit destinations already arrive through expected.
|
|
3915
|
+
if (expected === undefined && ctxType && lowerer.checker.isTupleType(ctxType) &&
|
|
3916
|
+
lowerer.checker.getTypeArguments(ctxType).some((type) => (type.flags & ts.TypeFlags.Any) !== 0)) {
|
|
3917
|
+
const inferred = lowerer.mapTypeOf(lowerer.typeOf(expr));
|
|
3918
|
+
if (inferred?.kind === "array" || inferred?.kind === "record" && lowerer.shapes.get(inferred.shapeId)?.tuple)
|
|
3919
|
+
mapped = inferred;
|
|
3920
|
+
}
|
|
3745
3921
|
// A JS literal whose OWN inferred type is never-tainted
|
|
3746
3922
|
// (neverTaintedJsType — the evolving `const gb = []`, the mixed
|
|
3747
3923
|
// command tuple `['pwd', []]`) carries no element information: route
|
|
@@ -3838,6 +4014,12 @@ export function lowerArrayLiteral(lowerer, expr, expected) {
|
|
|
3838
4014
|
mapped = arrayOf(first.type);
|
|
3839
4015
|
}
|
|
3840
4016
|
}
|
|
4017
|
+
if (!expected && isJsSourceFile(expr.getSourceFile()) && mapped?.kind === "array") {
|
|
4018
|
+
const elem = mapped.elem;
|
|
4019
|
+
const arms = elem.kind === "union" ? lowerer.unions.get(elem.unionId)?.arms : [elem];
|
|
4020
|
+
if (arms?.length && arms.every((arm) => arm.kind === "classval"))
|
|
4021
|
+
mapped = DYN;
|
|
4022
|
+
}
|
|
3841
4023
|
// An EMPTY literal under a CONST ASSERTION whose type queries panicked
|
|
3842
4024
|
// (tsgo's readonly-[] TupleType conversion — the facade answers `any`,
|
|
3843
4025
|
// which maps to nothing statically and to an island value under
|
|
@@ -3849,6 +4031,11 @@ export function lowerArrayLiteral(lowerer, expr, expected) {
|
|
|
3849
4031
|
underConstAssertion(expr)) {
|
|
3850
4032
|
mapped = arrayOf(unitOnlyUnion(lowerer.unions));
|
|
3851
4033
|
}
|
|
4034
|
+
// Heterogeneous JavaScript object arrays must retain each literal's
|
|
4035
|
+
// real keys. A structural union can otherwise drop descriptor fields.
|
|
4036
|
+
if (!expected && isJsSourceFile(expr.getSourceFile()) && mapped?.kind === "array" && mapped.elem.kind === "union" &&
|
|
4037
|
+
expr.elements.some(ts.isObjectLiteralExpression))
|
|
4038
|
+
mapped = DYN;
|
|
3852
4039
|
// A TUPLE-typed slot (`const t: [string, number] = ["a", 1]`): the
|
|
3853
4040
|
// literal constructs the tuple's record shape — one positional field
|
|
3854
4041
|
// per element, source order (which IS index order, so evaluation order
|
|
@@ -3904,7 +4091,7 @@ export function lowerArrayLiteral(lowerer, expr, expected) {
|
|
|
3904
4091
|
// `unknown[]` annotation or a collapsed `(string | object)[]` maps
|
|
3905
4092
|
// to DYN wholesale now (mapType's dyn-element array rule), so the
|
|
3906
4093
|
// literal IS the dyn array.
|
|
3907
|
-
if (isJsSourceFile(expr.getSourceFile()) || mapped?.kind === "dyn") {
|
|
4094
|
+
if (isJsSourceFile(expr.getSourceFile()) || mapped?.kind === "dyn" || lowerer.checkerAnyArray(expr)) {
|
|
3908
4095
|
if (expr.elements.some(ts.isSpreadElement)) {
|
|
3909
4096
|
// Native collection drains return vectors of retained dyn
|
|
3910
4097
|
// elements. Reuse the ordinary spread builder, then expose the
|
|
@@ -3998,11 +4185,7 @@ export function lowerArrayLiteral(lowerer, expr, expected) {
|
|
|
3998
4185
|
// the checker inferred a typed array from its producer. Drain once
|
|
3999
4186
|
// and validate the elements before the ordinary spread copy.
|
|
4000
4187
|
if (src.type.kind === "dyn" && (type.elem.kind === "dyn" || type.elem.kind === "f64" || type.elem.kind === "string" || type.elem.kind === "bool")) {
|
|
4001
|
-
src = lowerer.coerceInto(el.expression,
|
|
4002
|
-
kind: "libCall", fn: "dyn.iterPack", args: [src,
|
|
4003
|
-
{ kind: "strLit", value: el.expression.getText(), type: STRING, loc: locOf(el) }],
|
|
4004
|
-
type: DYN, loc: locOf(el),
|
|
4005
|
-
}, type);
|
|
4188
|
+
src = lowerer.coerceInto(el.expression, checkedIteratorPack(lowerer, src, locOf(el)), type);
|
|
4006
4189
|
}
|
|
4007
4190
|
// A same-family array whose ELEMENT lifts (string[] into a
|
|
4008
4191
|
// (string | symbol)[] literal — per-element wrap/width copy):
|
|
@@ -4320,7 +4503,11 @@ export function lowerElementAccess(lowerer, expr) {
|
|
|
4320
4503
|
if (target)
|
|
4321
4504
|
return lowerer.maybeNarrow(lowerer.fieldGetExpr(target, locOf(expr), expr), expr);
|
|
4322
4505
|
let receiver = lowerer.lowerExpr(expr.expression);
|
|
4323
|
-
|
|
4506
|
+
const classInfo = receiver.type.kind === "classval" ? lowerer.classes.get(receiver.type.className) : undefined;
|
|
4507
|
+
if (receiver.type.kind === "func" || receiver.type.kind === "generator" ||
|
|
4508
|
+
((receiver.type.kind === "array" || receiver.type.kind === "string" || receiver.type.kind === "bytes") && lowerer.dynConvertible(receiver.type)) ||
|
|
4509
|
+
(receiver.type.kind === "object" && lowerer.dynConvertible(receiver.type)) || isDynTypedRefType(receiver.type) ||
|
|
4510
|
+
(classInfo && (classInfo.callableBase || hasRuntimeStatics(classInfo))) || ((receiver.type.kind === "map" || receiver.type.kind === "set") && lowerer.dynConvertible(receiver.type))) {
|
|
4324
4511
|
const fnName = jsFuncNameOf(expr.expression);
|
|
4325
4512
|
receiver = { kind: "dynFrom", value: receiver, type: DYN, loc: locOf(expr),
|
|
4326
4513
|
...(fnName !== null ? { fnName } : {}) };
|
|
@@ -4340,11 +4527,17 @@ export function lowerElementAccess(lowerer, expr) {
|
|
|
4340
4527
|
: lowerer.mapTypeOf(lowerer.typeOf(expr.expression));
|
|
4341
4528
|
if (isJsSourceFile(expr.getSourceFile())) {
|
|
4342
4529
|
const receiver = tryLowerExpression(lowerer, expr.expression);
|
|
4530
|
+
if (receiver?.type.kind === "dyn") {
|
|
4531
|
+
const key = lowerer.lowerExprExpecting(expr.argumentExpression, DYN);
|
|
4532
|
+
const optional = hasOptionalChainGuard(expr.expression);
|
|
4533
|
+
return lowerer.maybeNarrow({ kind: "dynKeyGet", value: receiver, key,
|
|
4534
|
+
...(optional ? { optional: true } : {}), type: DYN, loc: locOf(expr) }, expr);
|
|
4535
|
+
}
|
|
4343
4536
|
if (receiver?.type.kind === "func" && lowerer.dynConvertible(receiver.type)) {
|
|
4344
4537
|
const loc = locOf(expr);
|
|
4345
4538
|
const fnName = jsFuncNameOf(expr.expression);
|
|
4346
4539
|
const boxed = { kind: "dynFrom", value: receiver, type: DYN, loc, ...(fnName !== null ? { fnName } : {}) };
|
|
4347
|
-
const key =
|
|
4540
|
+
const key = lowerer.lowerExprExpecting(expr.argumentExpression, DYN);
|
|
4348
4541
|
return lowerer.maybeNarrow({ kind: "dynKeyGet", key, value: boxed, type: DYN, loc }, expr);
|
|
4349
4542
|
}
|
|
4350
4543
|
}
|
|
@@ -4363,7 +4556,7 @@ export function lowerElementAccess(lowerer, expr) {
|
|
|
4363
4556
|
if (target)
|
|
4364
4557
|
return lowerer.maybeNarrow(lowerer.fieldGetExpr(target, locOf(expr), expr), expr);
|
|
4365
4558
|
}
|
|
4366
|
-
if (isDynTypedRefType(receiverIr)) {
|
|
4559
|
+
if (receiverIr.className === "%Error" || isDynTypedRefType(receiverIr)) {
|
|
4367
4560
|
const receiver = lowerer.coerceToExpected(lowerer.lowerExpr(expr.expression), DYN);
|
|
4368
4561
|
const key = lowerer.lowerExprExpecting(expr.argumentExpression, DYN);
|
|
4369
4562
|
return lowerer.maybeNarrow({ kind: "dynKeyGet", value: receiver, key, type: DYN, loc: locOf(expr) }, expr);
|
|
@@ -4412,6 +4605,11 @@ export function lowerElementAccess(lowerer, expr) {
|
|
|
4412
4605
|
if (recv.type.kind === "jsval")
|
|
4413
4606
|
return islandElementRead(lowerer, expr, recv);
|
|
4414
4607
|
const index = lowerer.lowerExpr(expr.argumentExpression);
|
|
4608
|
+
if (isJsSourceFile(expr.getSourceFile()) && recv.type.kind === "bytes") {
|
|
4609
|
+
return { kind: "dynKeyGet", value: lowerer.coerceInto(expr.expression, recv, DYN),
|
|
4610
|
+
key: index.type.kind === "f64" ? { kind: "toString", operand: index, type: STRING, loc: locOf(expr) } : index,
|
|
4611
|
+
type: DYN, loc: locOf(expr) };
|
|
4612
|
+
}
|
|
4415
4613
|
if (index.type.kind === "dyn" && recv.type.kind === "bytes") {
|
|
4416
4614
|
return { kind: "dynKeyGet", value: lowerer.coerceInto(expr.expression, recv, DYN), key: index, type: DYN, loc: locOf(expr) };
|
|
4417
4615
|
}
|
|
@@ -4509,16 +4707,21 @@ export function lowerElementAccess(lowerer, expr) {
|
|
|
4509
4707
|
// Dispatch from that stored shape, as the array fallback below does.
|
|
4510
4708
|
if (receiverIr === null && obj.type.kind === "record") {
|
|
4511
4709
|
const shape = lowerer.shapes.get(obj.type.shapeId);
|
|
4710
|
+
const index = tupleLiteralIndex(expr.argumentExpression);
|
|
4711
|
+
const field = shape?.tuple && index !== null ? shape.fields.find((field) => field.name === String(index)) : null;
|
|
4712
|
+
if (field)
|
|
4713
|
+
return lowerer.maybeNarrow({ kind: "recordGet", obj, shapeId: obj.type.shapeId, field: field.name, type: field.type, loc: locOf(expr) }, expr);
|
|
4512
4714
|
if (shape && !shape.tuple) {
|
|
4513
4715
|
return lowerer.lowerRecordKeyRead(expr, obj.type.shapeId, shape);
|
|
4514
4716
|
}
|
|
4515
4717
|
}
|
|
4516
|
-
if (obj.type.kind === "dyn" || isDynTypedRefType(obj.type)) {
|
|
4718
|
+
if (obj.type.kind === "dyn" || obj.type.kind === "object" && obj.type.className === "%Error" || isDynTypedRefType(obj.type)) {
|
|
4517
4719
|
const rawKey = lowerer.lowerExpr(expr.argumentExpression);
|
|
4518
4720
|
// Number, bool, and DYN keys stringify (ToPropertyKey) — the
|
|
4519
4721
|
// dyn-keyed read `catchWarning[warning.name]` where the property
|
|
4520
4722
|
// chain itself lowered dyn.
|
|
4521
|
-
const key = rawKey.type.kind === "dyn" || rawKey.type.kind === "symbol"
|
|
4723
|
+
const key = rawKey.type.kind === "dyn" || rawKey.type.kind === "symbol" ||
|
|
4724
|
+
rawKey.type.kind === "union" && lowerer.dynConvertible(rawKey.type)
|
|
4522
4725
|
? lowerer.coerceToExpected(rawKey, DYN)
|
|
4523
4726
|
: lowerRecordPropertyKey(lowerer, rawKey, expr.argumentExpression);
|
|
4524
4727
|
if (key.type.kind === "string" || key.type.kind === "dyn") {
|
|
@@ -4692,6 +4895,11 @@ export function lowerElementAccess(lowerer, expr) {
|
|
|
4692
4895
|
// is undefined, whose property lookup misses just like NaN; keep that
|
|
4693
4896
|
// value instead of rejecting a checker-number index with optional IR.
|
|
4694
4897
|
const index = lowerOptionalNumber(lowerer, lowerer.lowerExpr(expr.argumentExpression), locOf(expr.argumentExpression), expr.argumentExpression);
|
|
4898
|
+
if (arr.type.kind === "array" && (index.type.kind === "dyn" ||
|
|
4899
|
+
isJsSourceFile(expr.getSourceFile()) && index.type.kind !== "f64" && lowerer.dynConvertible(index.type))) {
|
|
4900
|
+
return { kind: "dynKeyGet", value: lowerer.coerceToExpected(arr, DYN),
|
|
4901
|
+
key: index, type: DYN, loc: locOf(expr) };
|
|
4902
|
+
}
|
|
4695
4903
|
if (index.type.kind !== "f64") {
|
|
4696
4904
|
lowerer.unsupported("SC1090", expr.argumentExpression, "indexing with non-number keys");
|
|
4697
4905
|
}
|
|
@@ -4802,8 +5010,11 @@ export function lowerRecordKeyRead(lowerer, expr, shapeId, shape, includeUndefin
|
|
|
4802
5010
|
// Number AND checked-dynamic keys ride the JS-exact formatter —
|
|
4803
5011
|
// property keys ARE strings (o[k] is o[String(k)] in JS), and a dyn
|
|
4804
5012
|
// key (agent.sockets[agent.getName(...)]) stringifies the same way.
|
|
4805
|
-
dk
|
|
4806
|
-
|
|
5013
|
+
if (dk.type.kind === "union" && lowerer.dynConvertible(dk.type))
|
|
5014
|
+
dk = lowerer.coerceToExpected(dk, DYN);
|
|
5015
|
+
if (dk.type.kind !== "symbol" && dk.type.kind !== "dyn")
|
|
5016
|
+
dk = lowerRecordPropertyKey(lowerer, dk, keyNode);
|
|
5017
|
+
if (dk.type.kind !== "string" && dk.type.kind !== "symbol" && dk.type.kind !== "dyn") {
|
|
4807
5018
|
lowerer.unsupported("SC1090", keyNode, "indexing records with non-string or non-number keys");
|
|
4808
5019
|
}
|
|
4809
5020
|
const read = { kind: "dynKeyGet", key: dk, value: obj, type: DYN, loc };
|
|
@@ -4850,6 +5061,19 @@ export function lowerRecordKeyRead(lowerer, expr, shapeId, shape, includeUndefin
|
|
|
4850
5061
|
let key = litKey !== null
|
|
4851
5062
|
? { kind: "strLit", value: litKey, type: STRING, loc: locOf(keyNode) }
|
|
4852
5063
|
: lowerer.lowerExpr(keyNode);
|
|
5064
|
+
// Optional string/number keys need ToPropertyKey, not a boxed copy of
|
|
5065
|
+
// the receiver. Keep record reads on their native storage so nested
|
|
5066
|
+
// references retain identity across index-signature reads.
|
|
5067
|
+
if (key.type.kind === "union" &&
|
|
5068
|
+
!lowerer.unions.get(key.type.unionId)?.arms.some((arm) => arm.kind === "symbol" || arm.kind === "dyn")) {
|
|
5069
|
+
key = lowerRecordPropertyKey(lowerer, key, keyNode);
|
|
5070
|
+
}
|
|
5071
|
+
if ((key.type.kind === "symbol" || key.type.kind === "dyn" || key.type.kind === "union") &&
|
|
5072
|
+
lowerer.dynConvertible(key.type) && lowerer.dynConvertible(obj.type)) {
|
|
5073
|
+
const read = { kind: "dynKeyGet", value: lowerer.coerceToExpected(obj, DYN),
|
|
5074
|
+
key: lowerer.coerceToExpected(key, DYN), type: DYN, loc };
|
|
5075
|
+
return includeUndefined ? read : lowerer.maybeNarrow(read, expr);
|
|
5076
|
+
}
|
|
4853
5077
|
// Runtime NUMBER keys ride the JS-exact formatter (o[n] is o[String(n)]
|
|
4854
5078
|
// in JS — the number-keyed-signature access path).
|
|
4855
5079
|
key = lowerRecordPropertyKey(lowerer, key, keyNode);
|
|
@@ -4914,6 +5138,9 @@ export function lowerRecordKeyRead(lowerer, expr, shapeId, shape, includeUndefin
|
|
|
4914
5138
|
* values remain real undefined values, whose JavaScript property spelling
|
|
4915
5139
|
* is the string "undefined". */
|
|
4916
5140
|
function lowerRecordPropertyKey(lowerer, key, node) {
|
|
5141
|
+
if (key.type.kind === "union" && lowerer.dynConvertible(key.type)) {
|
|
5142
|
+
return { kind: "libCall", fn: "dyn.toStringCoerce", args: [lowerer.coerceInto(node, key, DYN)], type: STRING, loc: key.loc };
|
|
5143
|
+
}
|
|
4917
5144
|
if (key.type.kind === "f64" || key.type.kind === "bool" || key.type.kind === "dyn" ||
|
|
4918
5145
|
lowerer.runtimeOptionalWidening(key.type, STRING) !== null) {
|
|
4919
5146
|
return lowerer.ensureString(key, node);
|
|
@@ -5079,11 +5306,29 @@ export function lowerElementCompound(lowerer, expr, op) {
|
|
|
5079
5306
|
const target = expr.left;
|
|
5080
5307
|
fenceNodeModuleMutation(lowerer, target, "assignment");
|
|
5081
5308
|
const loc = locOf(expr);
|
|
5082
|
-
const
|
|
5309
|
+
const checked = lowerer.lowerExpr(target.expression);
|
|
5310
|
+
if (checked?.type.kind === "dyn" && isJsSourceFile(expr.getSourceFile())) {
|
|
5311
|
+
const stmts = [];
|
|
5312
|
+
const save = (value, name) => {
|
|
5313
|
+
const local = lowerer.declareHiddenLocal(name, value.type);
|
|
5314
|
+
stmts.push({ kind: "varDecl", localId: local.id, init: value, loc });
|
|
5315
|
+
return varRef(local.id, value.type, loc);
|
|
5316
|
+
};
|
|
5317
|
+
const receiver = save(checked, "%compoundReceiver");
|
|
5318
|
+
const key = save(lowerer.lowerExprExpecting(target.argumentExpression, DYN), "%compoundKey");
|
|
5319
|
+
const old = save({ kind: "dynKeyGet", value: receiver, key, type: DYN, loc }, "%compoundOld");
|
|
5320
|
+
const rhs = lowerer.lowerExprExpecting(expr.right, DYN);
|
|
5321
|
+
const numeric = ["-", "*", "/", "%", "**"].includes(op);
|
|
5322
|
+
const value = save({ kind: "libCall", fn: op === "+" ? "dyn.add" : numeric ? "dyn.arithmetic" : "dyn.bitwise",
|
|
5323
|
+
args: op === "+" ? [old, rhs] : [old, rhs, strLit(op, loc)], type: DYN, loc }, "%compoundResult");
|
|
5324
|
+
stmts.push({ kind: "exprStmt", expr: { kind: "libCall", fn: "dyn.keySetComputed", args: [receiver, key, value], type: VOID, loc }, loc });
|
|
5325
|
+
return { kind: "seqExpr", stmts, result: value, type: DYN, loc };
|
|
5326
|
+
}
|
|
5327
|
+
const receiverType = checked.type.kind === "array" || checked.type.kind === "bytes" ? checked.type : lowerer.mapTypeOf(lowerer.typeOf(target.expression));
|
|
5083
5328
|
if (receiverType?.kind !== "array" && receiverType?.kind !== "bytes") {
|
|
5084
5329
|
lowerer.unsupported("SC1090", target, "compound assignment to non-array elements");
|
|
5085
5330
|
}
|
|
5086
|
-
let receiver =
|
|
5331
|
+
let receiver = checked;
|
|
5087
5332
|
if (receiver.type.kind === "union" && lowerer.armTag(receiver.type.unionId, UNDEFINED_T) >= 0) {
|
|
5088
5333
|
const present = lowerer.stripUndefinedArm(receiver.type);
|
|
5089
5334
|
const helper = present.kind === receiverType.kind
|
|
@@ -5120,6 +5365,12 @@ export function lowerElementCompound(lowerer, expr, op) {
|
|
|
5120
5365
|
else if (valueType.kind === "f64" && numericRhs.type.kind === "f64") {
|
|
5121
5366
|
computed = { kind: "bin", op, left: lowerOptionalNumber(lowerer, oldRef(), loc), right: numericRhs, type: F64, loc };
|
|
5122
5367
|
}
|
|
5368
|
+
else if (valueType.kind === "dyn" && isJsSourceFile(expr.getSourceFile())) {
|
|
5369
|
+
const left = lowerer.coerceToExpected(oldRef(), DYN), right = lowerer.coerceToExpected(rhs, DYN);
|
|
5370
|
+
const numeric = ["-", "*", "/", "%", "**"].includes(op);
|
|
5371
|
+
computed = { kind: "libCall", fn: op === "+" ? "dyn.add" : numeric ? "dyn.arithmetic" : "dyn.bitwise",
|
|
5372
|
+
args: op === "+" ? [left, right] : [left, right, strLit(op, loc)], type: DYN, loc };
|
|
5373
|
+
}
|
|
5123
5374
|
else {
|
|
5124
5375
|
lowerer.unsupported("SC1043", expr);
|
|
5125
5376
|
}
|
|
@@ -5233,12 +5484,23 @@ export function lowerElementWrite(lowerer, expr) {
|
|
|
5233
5484
|
const receiver = lowerer.lowerExpr(target.expression);
|
|
5234
5485
|
if (receiver.type.kind === "dyn")
|
|
5235
5486
|
return { kind: "exprStmt", expr: lowerDynMemberAssignment(lowerer, expr, receiver), loc: locOf(expr) };
|
|
5487
|
+
if (isJsSourceFile(expr.getSourceFile()) && receiver.type.kind === "object" && lowerer.dynConvertible(receiver.type)) {
|
|
5488
|
+
return { kind: "exprStmt", expr: lowerDynMemberAssignment(lowerer, expr, lowerer.coerceToExpected(receiver, DYN)), loc: locOf(expr) };
|
|
5489
|
+
}
|
|
5236
5490
|
lowerer.unsupported("SC1090", target, "symbol-keyed property writes outside class fields keyed by a stable module-level literal Symbol()/Symbol.for() (other static shapes have no symbol-keyed storage)");
|
|
5237
5491
|
}
|
|
5238
5492
|
const checkedReceiver = tryLowerExpression(lowerer, target.expression);
|
|
5239
5493
|
if (checkedReceiver?.type.kind === "dyn") {
|
|
5240
5494
|
return { kind: "exprStmt", expr: lowerDynMemberAssignment(lowerer, expr, checkedReceiver), loc: locOf(expr) };
|
|
5241
5495
|
}
|
|
5496
|
+
if (checkedReceiver?.type.kind === "object" && isJsSourceFile(expr.getSourceFile())) {
|
|
5497
|
+
const info = lowerer.classes.get(checkedReceiver.type.className);
|
|
5498
|
+
const key = recordKeyLiteralText(target.argumentExpression) ?? recordKeyTypeLiteralText(lowerer, target.argumentExpression);
|
|
5499
|
+
if (info && key !== null && isClassCallback(lowerer, info, key)) {
|
|
5500
|
+
const receiver = lowerer.coerceInto(target.expression, checkedReceiver, DYN);
|
|
5501
|
+
return { kind: "exprStmt", expr: lowerDynMemberAssignment(lowerer, expr, receiver), loc: locOf(expr) };
|
|
5502
|
+
}
|
|
5503
|
+
}
|
|
5242
5504
|
let receiverIr = lowerer.mapTypeOf(lowerer.typeOf(target.expression));
|
|
5243
5505
|
if (receiverIr === null || receiverIr.kind === "dyn") {
|
|
5244
5506
|
const receiver = tryLowerExpression(lowerer, target.expression);
|
|
@@ -5307,13 +5569,15 @@ export function lowerElementWrite(lowerer, expr) {
|
|
|
5307
5569
|
return lowerer.fieldSetStmt(field, value, locOf(expr), target);
|
|
5308
5570
|
}
|
|
5309
5571
|
if (hasClassPayload(lowerer, receiver.type)) {
|
|
5572
|
+
if (receiver.type.kind === "object" && receiver.type.className === "%Error") {
|
|
5573
|
+
return { kind: "exprStmt", expr: lowerDynMemberAssignment(lowerer, expr, lowerer.coerceInto(target.expression, receiver, DYN)), loc: locOf(expr) };
|
|
5574
|
+
}
|
|
5310
5575
|
lowerer.unsupported("SC1090", target, "writing undeclared properties through structural views of class instances");
|
|
5311
5576
|
}
|
|
5312
5577
|
}
|
|
5313
5578
|
}
|
|
5314
5579
|
// Typed-array element write `b[i] = v` — bytesSet: the value is an f64
|
|
5315
|
-
// the runtime coerces JS-exactly; invalid indices
|
|
5316
|
-
// typed arrays are fixed-length; JS would ignore the write).
|
|
5580
|
+
// the runtime coerces JS-exactly; invalid indices are ignored.
|
|
5317
5581
|
if (receiverIr?.kind === "bytes") {
|
|
5318
5582
|
const recv = lowerer.lowerExpr(target.expression);
|
|
5319
5583
|
// The write twin: a typed-array .d.ts surface whose VALUE is a
|
|
@@ -5499,7 +5763,7 @@ export function lowerElementWrite(lowerer, expr) {
|
|
|
5499
5763
|
// write, anything else falls through to the fences.
|
|
5500
5764
|
if (receiverIr?.kind === "dyn" || receiverIr?.kind === "object" || receiverIr === null) {
|
|
5501
5765
|
const obj = receiverIr !== null ? lowerer.lowerExpr(target.expression) : tryLowerExpression(lowerer, target.expression);
|
|
5502
|
-
if (obj !== null && (obj.type.kind === "dyn" || isDynTypedRefType(obj.type))) {
|
|
5766
|
+
if (obj !== null && (obj.type.kind === "dyn" || obj.type.kind === "object" && obj.type.className === "%Error" || isDynTypedRefType(obj.type))) {
|
|
5503
5767
|
const loc = locOf(expr);
|
|
5504
5768
|
const litKey = recordKeyLiteralText(target.argumentExpression);
|
|
5505
5769
|
let key = litKey !== null
|
|
@@ -5544,6 +5808,9 @@ export function lowerElementWrite(lowerer, expr) {
|
|
|
5544
5808
|
lowerer.unsupported("SC1090", target.expression, "assignment through a possibly missing nested array receiver");
|
|
5545
5809
|
}
|
|
5546
5810
|
const index = lowerOptionalNumber(lowerer, lowerer.lowerExpr(target.argumentExpression), locOf(target.argumentExpression), target.argumentExpression);
|
|
5811
|
+
if (index.type.kind === "dyn" && lowerer.dynConvertible(arr.type)) {
|
|
5812
|
+
return { kind: "exprStmt", expr: lowerDynMemberAssignment(lowerer, expr, lowerer.coerceInto(target.expression, arr, DYN)), loc: locOf(expr) };
|
|
5813
|
+
}
|
|
5547
5814
|
if (index.type.kind !== "f64") {
|
|
5548
5815
|
lowerer.unsupported("SC1090", target.argumentExpression, "indexing with non-number keys");
|
|
5549
5816
|
}
|
|
@@ -5878,7 +6145,7 @@ export function lowerAsExpression(lowerer, expr) {
|
|
|
5878
6145
|
return { kind: "jsExit", value: inner, type: target, loc: locOf(expr) };
|
|
5879
6146
|
}
|
|
5880
6147
|
const targetTs = lowerer.checker.getTypeFromTypeNode(expr.type);
|
|
5881
|
-
const target = lowerer.mapTypeOf(targetTs);
|
|
6148
|
+
const target = lowerer.mapTypeOf(targetTs) ?? dynFallbackType(lowerer, expr.type, targetTs);
|
|
5882
6149
|
if (!target)
|
|
5883
6150
|
lowerer.badType(expr.type, targetTs);
|
|
5884
6151
|
if (target.kind === "dyn")
|
|
@@ -6040,6 +6307,25 @@ function lowerIncDec(lowerer, expr, prefix) {
|
|
|
6040
6307
|
// accessor-backed names keep the fence.
|
|
6041
6308
|
if ((ts.isPropertyAccessExpression(expr.operand) || ts.isElementAccessExpression(expr.operand)) &&
|
|
6042
6309
|
!expr.operand.questionDotToken) {
|
|
6310
|
+
if (ts.isPropertyAccessExpression(expr.operand) && isJsSourceFile(expr.getSourceFile())) {
|
|
6311
|
+
const receiver = lowerer.lowerExpr(expr.operand.expression);
|
|
6312
|
+
if (receiver.type.kind === "dyn") {
|
|
6313
|
+
const local = lowerer.declareHiddenLocal("%incrementReceiver", DYN);
|
|
6314
|
+
const old = lowerer.declareHiddenLocal("%incrementOld", DYN);
|
|
6315
|
+
const next = lowerer.declareHiddenLocal("%incrementNext", DYN);
|
|
6316
|
+
const value = varRef(local.id, DYN, loc);
|
|
6317
|
+
const key = { kind: "strLit", value: expr.operand.name.text, type: STRING, loc };
|
|
6318
|
+
return { kind: "seqExpr", stmts: [
|
|
6319
|
+
{ kind: "varDecl", localId: local.id, init: receiver, loc },
|
|
6320
|
+
{ kind: "varDecl", localId: old.id, init: { kind: "libCall", fn: "dyn.toNumeric", args: [
|
|
6321
|
+
{ kind: "dynKeyGet", value, key, type: DYN, loc },
|
|
6322
|
+
], type: DYN, loc }, loc },
|
|
6323
|
+
{ kind: "varDecl", localId: next.id, init: { kind: "libCall", fn: "dyn.increment", args: [varRef(old.id, DYN, loc),
|
|
6324
|
+
{ kind: "boolLit", value: op === "+", type: BOOL, loc }], type: DYN, loc }, loc },
|
|
6325
|
+
{ kind: "exprStmt", expr: { kind: "libCall", fn: "dyn.keySet", args: [value, key, varRef(next.id, DYN, loc)], type: VOID, loc }, loc },
|
|
6326
|
+
], result: varRef(prefix ? next.id : old.id, DYN, loc), type: DYN, loc };
|
|
6327
|
+
}
|
|
6328
|
+
}
|
|
6043
6329
|
const target = ts.isPropertyAccessExpression(expr.operand)
|
|
6044
6330
|
? lowerer.fieldTarget(expr.operand)
|
|
6045
6331
|
: symbolFieldTarget(lowerer, expr.operand);
|
|
@@ -6163,12 +6449,13 @@ export function lowerCompoundValueToTarget(lowerer, expr, compound, target) {
|
|
|
6163
6449
|
return { kind: "bin", op: compound, left: read, right: numericRhs, type: F64, loc };
|
|
6164
6450
|
}
|
|
6165
6451
|
if ((target.type.kind === "dyn" || rhs.type.kind === "dyn") &&
|
|
6166
|
-
(target.type.kind === "dyn" || target.type.kind === "f64") &&
|
|
6167
|
-
(rhs.type.kind === "dyn" || rhs.type.kind === "f64") &&
|
|
6168
6452
|
isJsSourceFile(expr.getSourceFile())) {
|
|
6169
|
-
const
|
|
6170
|
-
const
|
|
6171
|
-
|
|
6453
|
+
const left = lowerer.coerceInto(expr.left, read, DYN);
|
|
6454
|
+
const right = lowerer.coerceInto(expr.right, rhs, DYN);
|
|
6455
|
+
const numeric = ["-", "*", "/", "%", "**"].includes(compound);
|
|
6456
|
+
const computed = { kind: "libCall", fn: compound === "+" ? "dyn.add" : numeric ? "dyn.arithmetic" : "dyn.bitwise",
|
|
6457
|
+
args: compound === "+" ? [left, right] : [left, right, { kind: "strLit", value: compound, type: STRING, loc }], type: DYN, loc };
|
|
6458
|
+
return lowerer.coerceInto(expr, computed, target.type);
|
|
6172
6459
|
}
|
|
6173
6460
|
lowerer.unsupported("SC1043", expr);
|
|
6174
6461
|
}
|
|
@@ -6293,8 +6580,30 @@ export function lowerBinary(lowerer, expr) {
|
|
|
6293
6580
|
// key afterward, then yields the RHS without rereading the property.
|
|
6294
6581
|
if (ts.isElementAccessExpression(expr.left) && !expr.left.questionDotToken) {
|
|
6295
6582
|
const recv = tryLowerExpression(lowerer, expr.left.expression);
|
|
6296
|
-
if (recv
|
|
6297
|
-
|
|
6583
|
+
if (recv && (recv.type.kind === "dyn" ||
|
|
6584
|
+
recv.type.kind === "array" && isJsSourceFile(expr.getSourceFile()) && lowerer.dynConvertible(recv.type))) {
|
|
6585
|
+
return lowerDynMemberAssignment(lowerer, expr, lowerer.coerceInto(expr.left.expression, recv, DYN));
|
|
6586
|
+
}
|
|
6587
|
+
if (recv?.type.kind === "array" || recv?.type.kind === "bytes") {
|
|
6588
|
+
const receiver = lowerer.declareHiddenLocal("%setArray", recv.type);
|
|
6589
|
+
const index = lowerer.lowerExpr(expr.left.argumentExpression);
|
|
6590
|
+
if (index.type.kind !== "f64")
|
|
6591
|
+
lowerer.unsupported("SC1090", expr.left.argumentExpression, "indexing with non-number keys");
|
|
6592
|
+
const key = lowerer.declareHiddenLocal("%setIndex", F64);
|
|
6593
|
+
const raw = lowerer.lowerExpr(expr.right);
|
|
6594
|
+
const value = lowerer.declareHiddenLocal("%setValue", raw.type);
|
|
6595
|
+
const result = varRef(value.id, raw.type, loc);
|
|
6596
|
+
const arr = varRef(receiver.id, recv.type, loc);
|
|
6597
|
+
const idx = varRef(key.id, F64, loc);
|
|
6598
|
+
const write = recv.type.kind === "array"
|
|
6599
|
+
? arrayValueStore(lowerer, arr, idx, result, recv.type.elem, loc)
|
|
6600
|
+
: { kind: "bytesSet", arr, index: idx, value: lowerer.coerceInto(expr.right, result, F64), loc };
|
|
6601
|
+
return { kind: "seqExpr", stmts: [
|
|
6602
|
+
{ kind: "varDecl", localId: receiver.id, init: recv, loc },
|
|
6603
|
+
{ kind: "varDecl", localId: key.id, init: index, loc },
|
|
6604
|
+
{ kind: "varDecl", localId: value.id, init: raw, loc },
|
|
6605
|
+
write,
|
|
6606
|
+
], result, type: result.type, loc };
|
|
6298
6607
|
}
|
|
6299
6608
|
}
|
|
6300
6609
|
// `h.k = v` on an ISLAND receiver in VALUE position: the engine
|
|
@@ -6337,32 +6646,8 @@ export function lowerBinary(lowerer, expr) {
|
|
|
6337
6646
|
// consumer sees exactly what the checker typed.
|
|
6338
6647
|
if (ts.isPropertyAccessExpression(expr.left) && !expr.left.questionDotToken) {
|
|
6339
6648
|
const recv = tryLowerExpression(lowerer, expr.left.expression);
|
|
6340
|
-
if (recv && recv.type.kind === "dyn")
|
|
6341
|
-
|
|
6342
|
-
const rhsVal = lowerer.lowerExpr(expr.right);
|
|
6343
|
-
const valTmp = lowerer.declareHiddenLocal("%setVal", rhsVal.type);
|
|
6344
|
-
const valRef = () => ({ kind: "varRef", localId: valTmp.id, type: rhsVal.type, loc });
|
|
6345
|
-
const stored = lowerer.coerceToExpected(valRef(), DYN);
|
|
6346
|
-
if (stored.type.kind !== "dyn") {
|
|
6347
|
-
lowerer.unsupported("SC1101", expr.right, `assigning '${lowerer.fmt(rhsVal.type)}' values into a checked-dynamic member`);
|
|
6348
|
-
}
|
|
6349
|
-
const key = { kind: "strLit", value: expr.left.name.text, type: STRING, loc: locOf(expr.left.name) };
|
|
6350
|
-
return {
|
|
6351
|
-
kind: "seqExpr",
|
|
6352
|
-
stmts: [
|
|
6353
|
-
{ kind: "varDecl", localId: recvTmp.id, init: recv, loc },
|
|
6354
|
-
{ kind: "varDecl", localId: valTmp.id, init: rhsVal, loc },
|
|
6355
|
-
{
|
|
6356
|
-
kind: "exprStmt",
|
|
6357
|
-
expr: { kind: "libCall", fn: "dyn.keySet", args: [{ kind: "varRef", localId: recvTmp.id, type: DYN, loc }, key, stored], type: VOID, loc },
|
|
6358
|
-
loc,
|
|
6359
|
-
},
|
|
6360
|
-
],
|
|
6361
|
-
result: valRef(),
|
|
6362
|
-
type: rhsVal.type,
|
|
6363
|
-
loc,
|
|
6364
|
-
};
|
|
6365
|
-
}
|
|
6649
|
+
if (recv && recv.type.kind === "dyn")
|
|
6650
|
+
return lowerDynMemberAssignment(lowerer, expr, recv);
|
|
6366
6651
|
const field = lowerer.fieldTarget(expr.left);
|
|
6367
6652
|
if (field) {
|
|
6368
6653
|
const recvTmp = lowerer.declareHiddenLocal("%setReceiver", field.obj.type);
|
|
@@ -6476,8 +6761,8 @@ export function lowerBinary(lowerer, expr) {
|
|
|
6476
6761
|
const scalarSide = dynSide === left ? right : left;
|
|
6477
6762
|
const reference = scalarSide.type;
|
|
6478
6763
|
if ((isDynTypedRefType(reference) || reference.kind === "record" || reference.kind === "array" ||
|
|
6479
|
-
reference.kind === "bytes" || reference.kind === "func" || reference.kind === "regex" || reference.kind === "url" ||
|
|
6480
|
-
reference.kind === "bigint" || reference.kind === "symbol" || reference.kind === "set" || reference.kind === "union" || DYN_HANDLE_KINDS.has(reference.kind)) &&
|
|
6764
|
+
reference.kind === "bytes" || reference.kind === "func" || reference.kind === "classval" || reference.kind === "regex" || reference.kind === "url" ||
|
|
6765
|
+
reference.kind === "bigint" || reference.kind === "symbol" || reference.kind === "map" || reference.kind === "set" || reference.kind === "union" || DYN_HANDLE_KINDS.has(reference.kind)) &&
|
|
6481
6766
|
lowerer.dynConvertible(reference)) {
|
|
6482
6767
|
const boxed = {
|
|
6483
6768
|
kind: "dynFrom", value: scalarSide, type: DYN, loc: scalarSide.loc,
|
|
@@ -6524,8 +6809,11 @@ export function lowerBinary(lowerer, expr) {
|
|
|
6524
6809
|
}
|
|
6525
6810
|
// Numeric operators dispatch on ToNumeric's actual Number/BigInt
|
|
6526
6811
|
// result, including values flowing through native callable properties.
|
|
6527
|
-
if (isJsSourceFile(expr.getSourceFile()) || op === ts.SyntaxKind.PlusToken
|
|
6528
|
-
|
|
6812
|
+
if (isJsSourceFile(expr.getSourceFile()) || op === ts.SyntaxKind.PlusToken ||
|
|
6813
|
+
[ts.SyntaxKind.LessThanToken, ts.SyntaxKind.LessThanEqualsToken,
|
|
6814
|
+
ts.SyntaxKind.GreaterThanToken, ts.SyntaxKind.GreaterThanEqualsToken].includes(op) ||
|
|
6815
|
+
[ts.SyntaxKind.MinusToken, ts.SyntaxKind.AsteriskToken, ts.SyntaxKind.SlashToken,
|
|
6816
|
+
ts.SyntaxKind.PercentToken, ts.SyntaxKind.AsteriskAsteriskToken].includes(op)) {
|
|
6529
6817
|
const other = left.type.kind === "dyn" ? right : left;
|
|
6530
6818
|
const NUM_BIN = {
|
|
6531
6819
|
[ts.SyntaxKind.MinusToken]: "-",
|
|
@@ -6553,8 +6841,9 @@ export function lowerBinary(lowerer, expr) {
|
|
|
6553
6841
|
return numeric ? { kind: "dynCheck", value, type: numeric, loc } : value;
|
|
6554
6842
|
}
|
|
6555
6843
|
}
|
|
6556
|
-
if (cmp && (
|
|
6557
|
-
return { kind: "
|
|
6844
|
+
if (cmp && lowerer.dynConvertible(left.type) && lowerer.dynConvertible(right.type)) {
|
|
6845
|
+
return { kind: "libCall", fn: "dyn.compare", args: [lowerer.coerceToExpected(left, DYN),
|
|
6846
|
+
lowerer.coerceToExpected(right, DYN), { kind: "strLit", value: cmp, type: STRING, loc }], type: BOOL, loc };
|
|
6558
6847
|
}
|
|
6559
6848
|
// Untyped addition chooses concatenation or numeric addition only
|
|
6560
6849
|
// after both operands have undergone ToPrimitive at runtime.
|
|
@@ -6986,6 +7275,10 @@ export function lowerBinary(lowerer, expr) {
|
|
|
6986
7275
|
if (DYN_HANDLE_KINDS.has(idLeft.type.kind) && typeEquals(idLeft.type, idRight.type)) {
|
|
6987
7276
|
return { kind: "bin", op: negated ? "!==" : "===", left: idLeft, right: idRight, type: BOOL, loc };
|
|
6988
7277
|
}
|
|
7278
|
+
if (lowerer.dynConvertible(idLeft.type) && lowerer.dynConvertible(idRight.type)) {
|
|
7279
|
+
return { kind: "dynScalarEq", left: lowerer.coerceToExpected(idLeft, DYN),
|
|
7280
|
+
right: lowerer.coerceToExpected(idRight, DYN), ...(negated ? { negated: true } : {}), type: BOOL, loc };
|
|
7281
|
+
}
|
|
6989
7282
|
lowerer.unsupported("SC1043", expr);
|
|
6990
7283
|
break;
|
|
6991
7284
|
}
|
|
@@ -7000,6 +7293,10 @@ export function lowerBinary(lowerer, expr) {
|
|
|
7000
7293
|
return { kind: "bin", op: cmpOp, left: arithmeticLeft, right: arithmeticRight, type: BOOL, loc };
|
|
7001
7294
|
if (bothStr)
|
|
7002
7295
|
return { kind: "strCmp", op: cmpOp, left, right, type: BOOL, loc };
|
|
7296
|
+
if (lowerer.dynConvertible(left.type) && lowerer.dynConvertible(right.type)) {
|
|
7297
|
+
return { kind: "libCall", fn: "dyn.compare", args: [lowerer.coerceToExpected(left, DYN),
|
|
7298
|
+
lowerer.coerceToExpected(right, DYN), { kind: "strLit", value: cmpOp, type: STRING, loc }], type: BOOL, loc };
|
|
7299
|
+
}
|
|
7003
7300
|
lowerer.unsupported("SC1043", expr);
|
|
7004
7301
|
break;
|
|
7005
7302
|
}
|
|
@@ -7042,6 +7339,16 @@ function lowerLogicalChain(lowerer, expr) {
|
|
|
7042
7339
|
function lowerLogicalPair(lowerer, expr, left) {
|
|
7043
7340
|
const op = expr.operatorToken.kind;
|
|
7044
7341
|
const loc = locOf(expr);
|
|
7342
|
+
// Preserve short-circuiting during lowering too: an unreachable member
|
|
7343
|
+
// on a specialized value must not poison the surrounding JS statement.
|
|
7344
|
+
if (left.kind === "boolLit") {
|
|
7345
|
+
const takeRight = op === ts.SyntaxKind.AmpersandAmpersandToken ? left.value : !left.value;
|
|
7346
|
+
return takeRight ? lowerer.lowerExpr(expr.right) : left;
|
|
7347
|
+
}
|
|
7348
|
+
if (left.kind === "unitLit" && op === ts.SyntaxKind.AmpersandAmpersandToken)
|
|
7349
|
+
return left;
|
|
7350
|
+
if (op === ts.SyntaxKind.BarBarToken && REF_TRUTHY_KINDS.has(left.type.kind))
|
|
7351
|
+
return left;
|
|
7045
7352
|
const right = lowerer.lowerExpr(expr.right);
|
|
7046
7353
|
// A LITERAL-unit left operand (a compile-time undefined/null — the
|
|
7047
7354
|
// capability-probe members: `process.features.inspector ||
|
|
@@ -7091,6 +7398,11 @@ function lowerLogicalPair(lowerer, expr, left) {
|
|
|
7091
7398
|
type: JSVAL, loc,
|
|
7092
7399
|
};
|
|
7093
7400
|
}
|
|
7401
|
+
if (isJsSourceFile(expr.getSourceFile()) && op === ts.SyntaxKind.AmpersandAmpersandToken &&
|
|
7402
|
+
left.type.kind === "union" && (lowerer.unions.get(left.type.unionId)?.arms.some((arm) => arm.kind === "bool")) &&
|
|
7403
|
+
!typeEquals(left.type, right.type) && lowerer.dynConvertible(left.type) && lowerer.dynConvertible(right.type)) {
|
|
7404
|
+
return { kind: "logical", op: "&&", left: lowerer.coerceToExpected(left, DYN), right: lowerer.coerceToExpected(right, DYN), type: DYN, loc };
|
|
7405
|
+
}
|
|
7094
7406
|
if (left.type.kind === "union" || right.type.kind === "union") {
|
|
7095
7407
|
// Test the deciding operand in its own representation. The result
|
|
7096
7408
|
// contains only the values that can survive short-circuit evaluation.
|
|
@@ -7970,6 +8282,8 @@ export function lowerInstanceOf(lowerer, expr, loc) {
|
|
|
7970
8282
|
if (value.type.kind === collection)
|
|
7971
8283
|
return { kind: "seqExpr", stmts: [{ kind: "exprStmt", expr: value, loc }],
|
|
7972
8284
|
result: { kind: "boolLit", value: true, type: BOOL, loc }, type: BOOL, loc };
|
|
8285
|
+
return { kind: "libCall", fn: collection === "map" ? "dyn.nativeMapIs" : "dyn.nativeSetIs",
|
|
8286
|
+
args: [lowerer.coerceInto(expr.left, value, DYN)], type: BOOL, loc };
|
|
7973
8287
|
}
|
|
7974
8288
|
if (lowerer.isStdlibGlobal(expr.right, "WeakMap") || lowerer.isStdlibGlobal(expr.right, "WeakSet")) {
|
|
7975
8289
|
if (lowerer.dynamic) {
|
|
@@ -7986,6 +8300,10 @@ export function lowerInstanceOf(lowerer, expr, loc) {
|
|
|
7986
8300
|
const value = lowerer.coerceInto(expr.left, lowerer.lowerExpr(expr.left), DYN);
|
|
7987
8301
|
return { kind: "libCall", fn: "dyn.nativeUrlIs", args: [value], type: BOOL, loc };
|
|
7988
8302
|
}
|
|
8303
|
+
if (lowerer.isStdlibGlobal(expr.right, "DataView")) {
|
|
8304
|
+
const value = lowerer.coerceInto(expr.left, lowerer.lowerExpr(expr.left), DYN);
|
|
8305
|
+
return { kind: "libCall", fn: "dyn.dataViewIs", args: [value], type: BOOL, loc };
|
|
8306
|
+
}
|
|
7989
8307
|
if (lowerer.isStdlibGlobal(expr.right, "ArrayBuffer")) {
|
|
7990
8308
|
const value = lowerer.coerceInto(expr.left, lowerer.lowerExpr(expr.left), DYN);
|
|
7991
8309
|
return { kind: "libCall", fn: "arrayBuffer.is", args: [value], type: BOOL, loc };
|
|
@@ -8040,24 +8358,29 @@ export function lowerInstanceOf(lowerer, expr, loc) {
|
|
|
8040
8358
|
if (value.type.kind === "dyn")
|
|
8041
8359
|
return { kind: "libCall", fn: date ? "dyn.nativeDateIs" : "dyn.nativeUrlIs", args: [value], type: BOOL, loc };
|
|
8042
8360
|
if (value.type.kind === "union")
|
|
8043
|
-
|
|
8361
|
+
return { kind: "libCall", fn: date ? "dyn.nativeDateIs" : "dyn.nativeUrlIs",
|
|
8362
|
+
args: [lowerer.coerceInto(expr.left, value, DYN)], type: BOOL, loc };
|
|
8044
8363
|
return { kind: "seqExpr", stmts: [{ kind: "exprStmt", expr: value, loc }],
|
|
8045
8364
|
result: { kind: "boolLit", value: value.type.kind === (date ? "date" : "url"), type: BOOL, loc }, type: BOOL, loc };
|
|
8046
8365
|
}
|
|
8366
|
+
const webBrand = ["Request", "Response", "Headers"].find((name) => lowerer.isStdlibGlobal(expr.right, name));
|
|
8367
|
+
if (webBrand)
|
|
8368
|
+
return { kind: "libCall", fn: "fetch.webIs", args: [lowerer.lowerExprExpecting(expr.left, DYN),
|
|
8369
|
+
{ kind: "strLit", value: webBrand, type: STRING, loc }], type: BOOL, loc };
|
|
8370
|
+
if (lowerer.isStdlibGlobal(expr.right, "ReadableStream")) {
|
|
8371
|
+
const value = lowerer.lowerExprExpecting(expr.left, DYN);
|
|
8372
|
+
return { kind: "libCall", fn: "fetch.streamIs", args: [value], type: BOOL, loc };
|
|
8373
|
+
}
|
|
8047
8374
|
// Unknown storage retains each numeric typed array's exact native brand.
|
|
8048
|
-
if (
|
|
8375
|
+
if (!lowerer.caughtLocalOf(expr.left)) {
|
|
8049
8376
|
const elem = Object.keys(BYTES_ELEMENT_NAME).find((kind) => lowerer.isStdlibGlobal(expr.right, BYTES_ELEMENT_NAME[kind]));
|
|
8050
8377
|
if (elem !== undefined) {
|
|
8051
8378
|
const left = lowerer.lowerExpr(expr.left);
|
|
8052
8379
|
if (left.type.kind === "dyn") {
|
|
8053
8380
|
return { kind: "dynTest", test: "bytes", bytesElem: elem, value: left, type: BOOL, loc };
|
|
8054
8381
|
}
|
|
8055
|
-
|
|
8056
|
-
|
|
8057
|
-
kind: "seqExpr", stmts: [{ kind: "exprStmt", expr: left, loc }],
|
|
8058
|
-
result: { kind: "boolLit", value: left.type.elem === elem, type: BOOL, loc }, type: BOOL, loc,
|
|
8059
|
-
};
|
|
8060
|
-
}
|
|
8382
|
+
return { kind: "dynTest", test: "bytes", bytesElem: elem,
|
|
8383
|
+
value: lowerer.coerceInto(expr.left, left, DYN), type: BOOL, loc };
|
|
8061
8384
|
}
|
|
8062
8385
|
}
|
|
8063
8386
|
// `x instanceof RegExp` over a union with a regex arm (the
|
|
@@ -8079,9 +8402,7 @@ export function lowerInstanceOf(lowerer, expr, loc) {
|
|
|
8079
8402
|
return { kind: "unionIsTag", unionId: left.type.unionId, tag, negated: false, value: left, type: BOOL, loc };
|
|
8080
8403
|
}
|
|
8081
8404
|
}
|
|
8082
|
-
|
|
8083
|
-
return { kind: "boolLit", value: true, type: BOOL, loc };
|
|
8084
|
-
}
|
|
8405
|
+
return { kind: "libCall", fn: "dyn.nativeRegexIs", args: [lowerer.coerceInto(expr.left, left, DYN)], type: BOOL, loc };
|
|
8085
8406
|
}
|
|
8086
8407
|
// `x instanceof X` where X is a class VALUE (a classval-typed
|
|
8087
8408
|
// binding): the target is DYNAMIC — a hierarchy target reads its
|
|
@@ -8100,6 +8421,10 @@ export function lowerInstanceOf(lowerer, expr, loc) {
|
|
|
8100
8421
|
lowerer.unsupported("SC1090", expr, "'instanceof' against a class value whose class has no lowering (the class declaration itself was rejected — see its own diagnostic)");
|
|
8101
8422
|
}
|
|
8102
8423
|
const left = lowerer.lowerExpr(expr.left);
|
|
8424
|
+
if (left.type.kind === "dyn") {
|
|
8425
|
+
const classValue = lowerer.lowerExpr(expr.right);
|
|
8426
|
+
return classInstanceOf(lowerer, left, targetInfo, loc, classValue);
|
|
8427
|
+
}
|
|
8103
8428
|
if (left.type.kind !== "object") {
|
|
8104
8429
|
lowerer.unsupported("SC1090", expr, "'instanceof' on values other than class instances (narrow union-typed values first)");
|
|
8105
8430
|
}
|
|
@@ -8124,6 +8449,11 @@ export function lowerInstanceOf(lowerer, expr, loc) {
|
|
|
8124
8449
|
}
|
|
8125
8450
|
lowerer.unsupported("SC1090", expr, "statically-decided 'instanceof' on computed operands (bind the values to variables first)");
|
|
8126
8451
|
}
|
|
8452
|
+
const constructor = tryLowerExpression(lowerer, expr.right);
|
|
8453
|
+
if (constructor?.type.kind === "dyn" && isJsSourceFile(expr.getSourceFile())) {
|
|
8454
|
+
const value = lowerer.coerceInto(expr.left, lowerer.lowerExpr(expr.left), DYN);
|
|
8455
|
+
return checkedClassInstanceOf(lowerer, value, constructor, loc);
|
|
8456
|
+
}
|
|
8127
8457
|
lowerer.unsupported("SC1090", expr.right, "'instanceof' right-hand sides other than classes declared in the program");
|
|
8128
8458
|
}
|
|
8129
8459
|
// A catch binding on the left: the runtime test against the class's
|
|
@@ -8218,7 +8548,8 @@ export function lowerInstanceOf(lowerer, expr, loc) {
|
|
|
8218
8548
|
}
|
|
8219
8549
|
}
|
|
8220
8550
|
if (left.type.kind !== "object") {
|
|
8221
|
-
|
|
8551
|
+
return { kind: "seqExpr", stmts: [{ kind: "exprStmt", expr: left, loc }],
|
|
8552
|
+
result: { kind: "boolLit", value: false, type: BOOL, loc }, type: BOOL, loc };
|
|
8222
8553
|
}
|
|
8223
8554
|
const lhsInfo = lowerer.classes.get(left.type.className);
|
|
8224
8555
|
if (!lhsInfo)
|
|
@@ -8446,9 +8777,9 @@ function lowerInExpression(lowerer, expr, loc) {
|
|
|
8446
8777
|
// `in` shares the coercion).
|
|
8447
8778
|
{
|
|
8448
8779
|
const probed = tryLowerExpression(lowerer, expr.right);
|
|
8449
|
-
if (probed &&
|
|
8780
|
+
if (probed && lowerer.dynConvertible(probed.type)) {
|
|
8450
8781
|
const k = lowerer.lowerExpr(expr.left); // JS order: the key evaluates first
|
|
8451
|
-
if (
|
|
8782
|
+
if (lowerer.dynConvertible(k.type)) {
|
|
8452
8783
|
const boxed = lowerer.coerceToExpected(k, DYN);
|
|
8453
8784
|
const keyLocal = lowerer.declareHiddenLocal("%inKey", DYN);
|
|
8454
8785
|
return { kind: "seqExpr", stmts: [{ kind: "varDecl", localId: keyLocal.id, init: boxed, loc }],
|
|
@@ -8479,7 +8810,9 @@ function lowerInExpression(lowerer, expr, loc) {
|
|
|
8479
8810
|
return { kind: "unionIsTag", unionId: envType.unionId, tag: undefTag, negated: true, value: read, type: BOOL, loc };
|
|
8480
8811
|
}
|
|
8481
8812
|
let recv = lowerer.lowerExpr(expr.right);
|
|
8482
|
-
|
|
8813
|
+
const classInfo = recv.type.kind === "classval" ? lowerer.classes.get(recv.type.className) : undefined;
|
|
8814
|
+
if ((classInfo && (classInfo.callableBase || hasRuntimeStatics(classInfo))) ||
|
|
8815
|
+
(isJsSourceFile(expr.getSourceFile()) && recv.type.kind === "func" && lowerer.dynConvertible(recv.type))) {
|
|
8483
8816
|
recv = lowerer.coerceToExpected(recv, DYN);
|
|
8484
8817
|
}
|
|
8485
8818
|
const siteType = lowerer.mapTypeOf(lowerer.typeOf(expr.right));
|
|
@@ -8728,8 +9061,8 @@ function lowerRuntimeKeyIn(lowerer, expr, loc) {
|
|
|
8728
9061
|
}
|
|
8729
9062
|
return { kind: "call", callee: helper, args: [keyIr, recv], type: BOOL, loc };
|
|
8730
9063
|
}
|
|
8731
|
-
/** A regex literal `/ab+c/gi` → regexLit (
|
|
8732
|
-
*
|
|
9064
|
+
/** A regex literal `/ab+c/gi` → regexLit (fresh state per evaluation,
|
|
9065
|
+
* shared bytecode per (pattern, flags) pair). The TS parser has already syntax-checked the literal;
|
|
8733
9066
|
* what remains here is the flag-alphabet fence (d and v are
|
|
8734
9067
|
* declared-valid TS flags outside this slice). Named capture groups
|
|
8735
9068
|
* `(?<name>...)` and `\k<name>` backreferences compile — libregexp
|
|
@@ -8870,14 +9203,52 @@ function constInitializerOf(lowerer, ident) {
|
|
|
8870
9203
|
* caller keeps its fence), or the groups list (possibly empty — a
|
|
8871
9204
|
* traced regex WITHOUT named groups is the Node-undefined case). */
|
|
8872
9205
|
export function matchResultNamedGroupsOf(lowerer, e) {
|
|
9206
|
+
let producer = e;
|
|
9207
|
+
while (ts.isParenthesizedExpression(producer) || ts.isNonNullExpression(producer))
|
|
9208
|
+
producer = producer.expression;
|
|
9209
|
+
if (ts.isIdentifier(producer)) {
|
|
9210
|
+
const init = constInitializerOf(lowerer, producer);
|
|
9211
|
+
if (init !== null)
|
|
9212
|
+
return matchResultNamedGroupsOf(lowerer, init);
|
|
9213
|
+
}
|
|
8873
9214
|
const reExpr = matchProducerRegexOf(lowerer, e);
|
|
8874
9215
|
if (reExpr === null)
|
|
8875
9216
|
return null;
|
|
9217
|
+
if (ts.isCallExpression(producer) && ts.isPropertyAccessExpression(producer.expression) &&
|
|
9218
|
+
producer.expression.name.text === "match") {
|
|
9219
|
+
const flags = staticRegexFlagsOf(lowerer, reExpr);
|
|
9220
|
+
if (flags === null)
|
|
9221
|
+
return null;
|
|
9222
|
+
// Global String.match returns whole matches without a groups
|
|
9223
|
+
// property, even when the pattern contains named captures.
|
|
9224
|
+
if (flags.includes("g"))
|
|
9225
|
+
return [];
|
|
9226
|
+
}
|
|
8876
9227
|
const pattern = staticRegexPatternOf(lowerer, reExpr);
|
|
8877
9228
|
if (pattern === null)
|
|
8878
9229
|
return null;
|
|
8879
9230
|
return namedCaptureGroupsOfPattern(pattern);
|
|
8880
9231
|
}
|
|
9232
|
+
function staticRegexFlagsOf(lowerer, node) {
|
|
9233
|
+
let expr = node;
|
|
9234
|
+
while (ts.isParenthesizedExpression(expr) || ts.isNonNullExpression(expr))
|
|
9235
|
+
expr = expr.expression;
|
|
9236
|
+
if (ts.isRegularExpressionLiteral(expr))
|
|
9237
|
+
return expr.text.slice(expr.text.lastIndexOf("/") + 1);
|
|
9238
|
+
if (ts.isIdentifier(expr)) {
|
|
9239
|
+
const init = constInitializerOf(lowerer, expr);
|
|
9240
|
+
return init !== null ? staticRegexFlagsOf(lowerer, init) : null;
|
|
9241
|
+
}
|
|
9242
|
+
if (ts.isNewExpression(expr) && ts.isIdentifier(expr.expression) &&
|
|
9243
|
+
lowerer.isStdlibGlobal(expr.expression, "RegExp")) {
|
|
9244
|
+
const flags = expr.arguments?.[1];
|
|
9245
|
+
if (!flags)
|
|
9246
|
+
return "";
|
|
9247
|
+
if (ts.isStringLiteral(flags) || ts.isNoSubstitutionTemplateLiteral(flags))
|
|
9248
|
+
return flags.text;
|
|
9249
|
+
}
|
|
9250
|
+
return null;
|
|
9251
|
+
}
|
|
8881
9252
|
/** The regex EXPRESSION whose match produced `e` (see
|
|
8882
9253
|
* matchResultNamedGroupsOf for the traced shapes). */
|
|
8883
9254
|
function matchProducerRegexOf(lowerer, e) {
|
|
@@ -9370,7 +9741,7 @@ export function lowerUnionProperty(lowerer, expr) {
|
|
|
9370
9741
|
// instance argument (e.g. Matrix4.makeTranslation). Preserve primitive
|
|
9371
9742
|
// missing-property semantics and dispatch class data through its native
|
|
9372
9743
|
// capsule instead of demanding a field shared by every union arm.
|
|
9373
|
-
if (isJsSourceFile(expr.getSourceFile()) &&
|
|
9744
|
+
if (isJsSourceFile(expr.getSourceFile()) && lowerer.dynConvertible(value.type)) {
|
|
9374
9745
|
return { kind: "dynKeyGet", value: lowerer.coerceToExpected(value, DYN), key,
|
|
9375
9746
|
...(hasOptionalChainGuard(expr.expression) ? { optional: true } : {}), type: DYN, loc: locOf(expr) };
|
|
9376
9747
|
}
|
|
@@ -9581,7 +9952,7 @@ export function fieldTarget(lowerer, access) {
|
|
|
9581
9952
|
}
|
|
9582
9953
|
const stored = ts.isIdentifier(access.expression)
|
|
9583
9954
|
? lowerer.peekLocal(access.expression)?.type ?? lowerer.globalOf(access.expression)?.type : undefined;
|
|
9584
|
-
const receiverIr = stored?.kind === "record" ? stored : lowerer.mapTypeOf(lowerer.typeOf(access.expression));
|
|
9955
|
+
const receiverIr = stored?.kind === "record" || stored?.kind === "object" ? stored : lowerer.mapTypeOf(lowerer.typeOf(access.expression));
|
|
9585
9956
|
if (receiverIr?.kind === "object") {
|
|
9586
9957
|
return classFieldTarget(lowerer, access.expression, receiverIr, access.name.text);
|
|
9587
9958
|
}
|
|
@@ -9787,6 +10158,8 @@ function symbolFieldTarget(lowerer, expr) {
|
|
|
9787
10158
|
* tsc-clean (the property types as the setter's param), but Node yields
|
|
9788
10159
|
* undefined, which these property types cannot represent. */
|
|
9789
10160
|
export function fieldGetExpr(lowerer, target, loc, blame) {
|
|
10161
|
+
if (target.container === "class" && (target.field === "message" || target.field === "name") && (target.className === "%Error" || lowerer.isSubclassOf(target.className, "%Error")))
|
|
10162
|
+
return errorPropertyRead(lowerer, target.obj, target.field);
|
|
9790
10163
|
if (target.container === "errorStackLimit") {
|
|
9791
10164
|
return { kind: "libCall", fn: "error.stackLimitGet", args: [], type: F64, loc };
|
|
9792
10165
|
}
|
|
@@ -9812,6 +10185,11 @@ export function fieldGetExpr(lowerer, target, loc, blame) {
|
|
|
9812
10185
|
if (!getF) {
|
|
9813
10186
|
lowerer.unsupported("SC1090", blame, `reading a property that has only a setter ('${target.field}' — Node would yield undefined)`);
|
|
9814
10187
|
}
|
|
10188
|
+
if (!target.field.startsWith("#") && isJsSourceFile(blame.getSourceFile()) && lowerer.dynConvertible(getF.sig.ret)) {
|
|
10189
|
+
const value = { kind: "dynKeyGet", value: lowerer.coerceToExpected(target.obj, DYN),
|
|
10190
|
+
key: { kind: "strLit", value: target.field, type: STRING, loc }, type: DYN, loc };
|
|
10191
|
+
return lowerer.coerceToExpected(value, getF.sig.ret);
|
|
10192
|
+
}
|
|
9815
10193
|
return lowerer.accessorCall(target.className, `get:${target.field}`, target.obj, [], getF.sig.ret, loc);
|
|
9816
10194
|
}
|
|
9817
10195
|
// Record accessor properties: the read IS a call of the %get: closure
|
|
@@ -9889,6 +10267,8 @@ export function fieldGetExpr(lowerer, target, loc, blame) {
|
|
|
9889
10267
|
* call). A write to a getter-only property never gets here in a clean
|
|
9890
10268
|
* program (tsc's TS2540 is the fence); the rejection is the backstop. */
|
|
9891
10269
|
export function fieldSetStmt(lowerer, target, value, loc, blame) {
|
|
10270
|
+
if (target.container === "class" && (target.field === "message" || target.field === "name") && (target.className === "%Error" || lowerer.isSubclassOf(target.className, "%Error")))
|
|
10271
|
+
return errorPropertyWrite(lowerer, target.obj, value, target.field);
|
|
9892
10272
|
if (target.container === "errorStackLimit") {
|
|
9893
10273
|
return { kind: "exprStmt", expr: { kind: "libCall", fn: "error.stackLimitSet", args: [value], type: VOID, loc }, loc };
|
|
9894
10274
|
}
|
|
@@ -9996,13 +10376,13 @@ export function lowerPromiseRejectCall(lowerer, call, access) {
|
|
|
9996
10376
|
// identity survives to catch/unhandledRejection observers), and the
|
|
9997
10377
|
// result is promise<dyn> when no context names a concrete one.
|
|
9998
10378
|
const reason = lowerer.lowerExpr(reasonNode);
|
|
9999
|
-
if (reason.type.kind === "dyn") {
|
|
10379
|
+
if (reason.type.kind === "dyn" || lowerer.dynConvertible(reason.type) && reason.type.kind !== "object") {
|
|
10000
10380
|
// The result only ever REJECTS, so the inner type is unobservable:
|
|
10001
10381
|
// adopt the context's promise type when one names it, else the
|
|
10002
10382
|
// checker's own Promise<never> reading (promise<void> — exactly the
|
|
10003
10383
|
// Error-reason form below).
|
|
10004
10384
|
const resultT = type?.kind === "promise" ? type : { kind: "promise", inner: VOID };
|
|
10005
|
-
return { kind: "intrinsic", name: "promise.reject", args: [reason], type: resultT, loc };
|
|
10385
|
+
return { kind: "intrinsic", name: "promise.reject", args: [lowerer.coerceInto(reasonNode, reason, DYN)], type: resultT, loc };
|
|
10006
10386
|
}
|
|
10007
10387
|
// An Error reason with NO context-named promise type (a bare
|
|
10008
10388
|
// top-level `Promise.reject(new Error())` — the unhandled-rejection
|
|
@@ -10193,8 +10573,8 @@ function lowerStreamObjectProperty(lowerer, expr) {
|
|
|
10193
10573
|
* Interning makes every reference under one ABI the SAME immortal closure,
|
|
10194
10574
|
* so `opt.type === String` compares like JS function identity. */
|
|
10195
10575
|
function primitiveCtorClosure(lowerer, name, loc, dynamicInput) {
|
|
10196
|
-
const ret = name === "String" ? STRING : name === "Number" ? F64 : BOOL;
|
|
10197
|
-
const input = dynamicInput ? DYN : STRING;
|
|
10576
|
+
const ret = name === "String" ? STRING : name === "Number" ? F64 : name === "BigInt" ? BIGINT_T : BOOL;
|
|
10577
|
+
const input = dynamicInput || name === "BigInt" ? DYN : STRING;
|
|
10198
10578
|
const fnT = funcOf([input], ret);
|
|
10199
10579
|
const key = `${name}:${dynamicInput ? "dyn" : "string"}`;
|
|
10200
10580
|
let fnName = lowerer.primitiveCtorFns.get(key);
|
|
@@ -10203,16 +10583,20 @@ function primitiveCtorClosure(lowerer, name, loc, dynamicInput) {
|
|
|
10203
10583
|
lowerer.primitiveCtorFns.set(key, fnName);
|
|
10204
10584
|
const v = { kind: "varRef", localId: "v.0", type: input, loc };
|
|
10205
10585
|
const value = dynamicInput
|
|
10206
|
-
? name === "
|
|
10207
|
-
? { kind: "libCall", fn: "dyn.
|
|
10208
|
-
: name === "
|
|
10209
|
-
? { kind: "libCall", fn: "dyn.
|
|
10210
|
-
:
|
|
10211
|
-
|
|
10212
|
-
|
|
10213
|
-
|
|
10214
|
-
|
|
10215
|
-
|
|
10586
|
+
? name === "BigInt"
|
|
10587
|
+
? { kind: "libCall", fn: "dyn.bigintConstructor", args: [v], type: BIGINT_T, loc }
|
|
10588
|
+
: name === "String"
|
|
10589
|
+
? { kind: "libCall", fn: "dyn.toStringCoerce", args: [v], type: STRING, loc }
|
|
10590
|
+
: name === "Number"
|
|
10591
|
+
? { kind: "libCall", fn: "dyn.numberConstructor", args: [v], type: F64, loc }
|
|
10592
|
+
: { kind: "dynTest", test: "truthy", value: v, type: BOOL, loc }
|
|
10593
|
+
: name === "BigInt"
|
|
10594
|
+
? { kind: "libCall", fn: "dyn.bigintConstructor", args: [v], type: BIGINT_T, loc }
|
|
10595
|
+
: name === "String"
|
|
10596
|
+
? v
|
|
10597
|
+
: name === "Number"
|
|
10598
|
+
? { kind: "libCall", fn: "num.fromString", args: [v], type: F64, loc }
|
|
10599
|
+
: { kind: "strEq", negated: true, left: v, right: { kind: "strLit", value: "", type: STRING, loc }, type: BOOL, loc };
|
|
10216
10600
|
const fn = {
|
|
10217
10601
|
name: fnName,
|
|
10218
10602
|
params: [{ localId: "v.0", name: "value", type: input }],
|
|
@@ -10225,4 +10609,25 @@ function primitiveCtorClosure(lowerer, name, loc, dynamicInput) {
|
|
|
10225
10609
|
}
|
|
10226
10610
|
return { kind: "closure", fnName, captures: [], type: fnT, loc };
|
|
10227
10611
|
}
|
|
10612
|
+
/** Drain using checked dispatch so native class and generator iterators keep their methods. */
|
|
10613
|
+
function checkedIteratorPack(lowerer, source, loc) {
|
|
10614
|
+
const name = "%iterator.pack.checked";
|
|
10615
|
+
if (!lowerer.liftedFns.some((fn) => fn.name === name)) {
|
|
10616
|
+
const ref = (id) => ({ kind: "varRef", localId: id, type: DYN, loc });
|
|
10617
|
+
const property = (key) => ({ kind: "dynKeyGet", value: ref("step"), key: { kind: "strLit", value: key, type: STRING, loc }, type: DYN, loc });
|
|
10618
|
+
lowerer.liftedFns.push({ name, params: [{ localId: "source", name: "source", type: DYN }], returnType: DYN,
|
|
10619
|
+
locals: ["source", "iterator", "step", "result"].map((id) => ({ id, name: id, type: DYN, mutable: id !== "source" })),
|
|
10620
|
+
body: [
|
|
10621
|
+
{ kind: "varDecl", localId: "iterator", init: { kind: "libCall", fn: "dyn.iterator", args: [ref("source"), { kind: "strLit", value: "value", type: STRING, loc }], type: DYN, loc }, loc },
|
|
10622
|
+
{ kind: "varDecl", localId: "result", init: { kind: "dynArrLit", elems: [], type: DYN, loc }, loc },
|
|
10623
|
+
{ kind: "while", cond: { kind: "boolLit", value: true, type: BOOL, loc }, body: [
|
|
10624
|
+
{ kind: "varDecl", localId: "step", init: { kind: "dynInvoke", recv: ref("iterator"), method: "next", calleeName: "iterator.next", args: [], type: DYN, loc }, loc },
|
|
10625
|
+
{ kind: "if", cond: { kind: "dynTest", test: "truthy", value: property("done"), type: BOOL, loc }, then: [{ kind: "return", value: ref("result"), loc }], else_: null, loc },
|
|
10626
|
+
{ kind: "exprStmt", expr: { kind: "libCall", fn: "dyn.packPush", args: [ref("result"), property("value")], type: VOID, loc }, loc },
|
|
10627
|
+
], loc },
|
|
10628
|
+
{ kind: "return", value: ref("result"), loc },
|
|
10629
|
+
], loc });
|
|
10630
|
+
}
|
|
10631
|
+
return { kind: "call", callee: name, args: [source], type: DYN, loc };
|
|
10632
|
+
}
|
|
10228
10633
|
//# sourceMappingURL=lower-exprs.js.map
|