@scriptc/compiler 0.1.3 → 0.1.5
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 +275 -62
- package/dist/backend/c/async.d.ts +25 -0
- package/dist/backend/c/async.js +167 -0
- package/dist/backend/c/async.js.map +1 -1
- package/dist/backend/c/c-emitter.d.ts +15 -1
- package/dist/backend/c/c-emitter.js +36 -11
- package/dist/backend/c/c-emitter.js.map +1 -1
- package/dist/backend/c/exprs.d.ts +2 -2
- package/dist/backend/c/exprs.js +556 -71
- package/dist/backend/c/exprs.js.map +1 -1
- package/dist/backend/c/stmts.js +5 -3
- package/dist/backend/c/stmts.js.map +1 -1
- package/dist/backend/c/types.d.ts +2 -3
- package/dist/backend/c/types.js +10 -1
- package/dist/backend/c/types.js.map +1 -1
- package/dist/backend/c/walkers.js +1 -1
- package/dist/backend/c/walkers.js.map +1 -1
- package/dist/backend/link-plan.d.ts +3 -1
- package/dist/backend/link-plan.js +3 -1
- package/dist/backend/link-plan.js.map +1 -1
- package/dist/backend/llvm/dyn.js +1 -1
- package/dist/backend/llvm/dyn.js.map +1 -1
- package/dist/backend/llvm/emitter.js +42 -12
- package/dist/backend/llvm/emitter.js.map +1 -1
- package/dist/backend/llvm/expr-bytes.d.ts +1 -2
- package/dist/backend/llvm/expr-bytes.js +28 -23
- package/dist/backend/llvm/expr-bytes.js.map +1 -1
- package/dist/backend/llvm/expr-callbacks.d.ts +9 -0
- package/dist/backend/llvm/expr-callbacks.js +125 -0
- package/dist/backend/llvm/expr-callbacks.js.map +1 -1
- package/dist/backend/llvm/expr-containers.d.ts +1 -0
- package/dist/backend/llvm/expr-containers.js +32 -4
- package/dist/backend/llvm/expr-containers.js.map +1 -1
- package/dist/backend/llvm/expr-context.d.ts +19 -3
- package/dist/backend/llvm/expr-dispatch.js +1 -0
- package/dist/backend/llvm/expr-dispatch.js.map +1 -1
- package/dist/backend/llvm/expr-primitives.d.ts +1 -1
- package/dist/backend/llvm/expr-primitives.js +49 -13
- package/dist/backend/llvm/expr-primitives.js.map +1 -1
- package/dist/backend/llvm/expr-primitives.test.d.ts +1 -0
- package/dist/backend/llvm/expr-primitives.test.js +38 -0
- package/dist/backend/llvm/expr-primitives.test.js.map +1 -0
- package/dist/backend/llvm/expr-stream-callbacks.d.ts +3 -0
- package/dist/backend/llvm/expr-stream-callbacks.js +69 -0
- package/dist/backend/llvm/expr-stream-callbacks.js.map +1 -1
- package/dist/backend/llvm/lib-filesystem.js +80 -10
- package/dist/backend/llvm/lib-filesystem.js.map +1 -1
- package/dist/backend/llvm/lib-network.js +69 -10
- package/dist/backend/llvm/lib-network.js.map +1 -1
- package/dist/backend/llvm/lib-process.js +156 -6
- package/dist/backend/llvm/lib-process.js.map +1 -1
- package/dist/backend/llvm/lib-shared.js +100 -0
- package/dist/backend/llvm/lib-shared.js.map +1 -1
- package/dist/backend/llvm/lib-stream.js +23 -0
- package/dist/backend/llvm/lib-stream.js.map +1 -1
- package/dist/backend/native-toolchain.d.ts +5 -0
- package/dist/backend/native-toolchain.js +4 -1
- package/dist/backend/native-toolchain.js.map +1 -1
- package/dist/backend/runtime-pack.test.js +28 -10
- package/dist/backend/runtime-pack.test.js.map +1 -1
- package/dist/backend/targets.d.ts +7 -0
- package/dist/backend/targets.js +26 -0
- package/dist/backend/targets.js.map +1 -1
- package/dist/backend/targets.test.js +8 -1
- package/dist/backend/targets.test.js.map +1 -1
- package/dist/coverage/surface-manifest.js +14 -4
- package/dist/coverage/surface-manifest.js.map +1 -1
- package/dist/diagnostics/diagnostic.js +1 -1
- package/dist/diagnostics/diagnostic.js.map +1 -1
- package/dist/executable/executable-cache.d.ts +4 -0
- package/dist/executable/executable-cache.js +6 -1
- package/dist/executable/executable-cache.js.map +1 -1
- package/dist/executable/executable-cache.test.js +3 -3
- package/dist/executable/executable-cache.test.js.map +1 -1
- package/dist/frontend/fork-target.d.ts +17 -0
- package/dist/frontend/fork-target.js +256 -0
- package/dist/frontend/fork-target.js.map +1 -0
- package/dist/frontend/lowering/abstract-equality.d.ts +6 -0
- package/dist/frontend/lowering/abstract-equality.js +250 -0
- package/dist/frontend/lowering/abstract-equality.js.map +1 -0
- package/dist/frontend/lowering/containers/bytes.d.ts +1 -1
- package/dist/frontend/lowering/containers/bytes.js +6 -5
- package/dist/frontend/lowering/containers/bytes.js.map +1 -1
- package/dist/frontend/lowering/containers/string-and-regexp.d.ts +7 -6
- package/dist/frontend/lowering/containers/string-and-regexp.js +237 -28
- package/dist/frontend/lowering/containers/string-and-regexp.js.map +1 -1
- package/dist/frontend/lowering/expressions/object-literals.js +8 -0
- package/dist/frontend/lowering/expressions/object-literals.js.map +1 -1
- package/dist/frontend/lowering/lower-assert.js +71 -2
- package/dist/frontend/lowering/lower-assert.js.map +1 -1
- package/dist/frontend/lowering/lower-builtins.d.ts +54 -28
- package/dist/frontend/lowering/lower-builtins.js +957 -116
- package/dist/frontend/lowering/lower-builtins.js.map +1 -1
- package/dist/frontend/lowering/lower-calls.d.ts +32 -23
- package/dist/frontend/lowering/lower-calls.js +835 -206
- package/dist/frontend/lowering/lower-calls.js.map +1 -1
- package/dist/frontend/lowering/lower-classes.js +41 -10
- package/dist/frontend/lowering/lower-classes.js.map +1 -1
- package/dist/frontend/lowering/lower-containers.d.ts +7 -9
- package/dist/frontend/lowering/lower-containers.js +293 -51
- package/dist/frontend/lowering/lower-containers.js.map +1 -1
- package/dist/frontend/lowering/lower-event-emitter.js +212 -21
- package/dist/frontend/lowering/lower-event-emitter.js.map +1 -1
- package/dist/frontend/lowering/lower-exprs.d.ts +12 -0
- package/dist/frontend/lowering/lower-exprs.js +263 -93
- package/dist/frontend/lowering/lower-exprs.js.map +1 -1
- package/dist/frontend/lowering/lower-inspect.d.ts +4 -0
- package/dist/frontend/lowering/lower-inspect.js +1 -1
- package/dist/frontend/lowering/lower-inspect.js.map +1 -1
- package/dist/frontend/lowering/lower-island.d.ts +6 -3
- package/dist/frontend/lowering/lower-island.js +182 -12
- package/dist/frontend/lowering/lower-island.js.map +1 -1
- package/dist/frontend/lowering/lower-modules.d.ts +6 -0
- package/dist/frontend/lowering/lower-modules.js +184 -38
- package/dist/frontend/lowering/lower-modules.js.map +1 -1
- package/dist/frontend/lowering/lower-namespaces.js +7 -0
- package/dist/frontend/lowering/lower-namespaces.js.map +1 -1
- package/dist/frontend/lowering/lower-server.d.ts +3 -5
- package/dist/frontend/lowering/lower-server.js +413 -54
- package/dist/frontend/lowering/lower-server.js.map +1 -1
- package/dist/frontend/lowering/lower-stmts.js +122 -19
- package/dist/frontend/lowering/lower-stmts.js.map +1 -1
- package/dist/frontend/lowering/lower-stream.d.ts +3 -0
- package/dist/frontend/lowering/lower-stream.js +7 -0
- package/dist/frontend/lowering/lower-stream.js.map +1 -1
- package/dist/frontend/lowering/lowerer.d.ts +86 -9
- package/dist/frontend/lowering/lowerer.js +449 -74
- package/dist/frontend/lowering/lowerer.js.map +1 -1
- package/dist/frontend/lowering/optional-arguments.d.ts +9 -1
- package/dist/frontend/lowering/optional-arguments.js +67 -1
- package/dist/frontend/lowering/optional-arguments.js.map +1 -1
- package/dist/frontend/lowering/pairs-snapshot.d.ts +3 -1
- package/dist/frontend/lowering/pairs-snapshot.js +12 -4
- package/dist/frontend/lowering/pairs-snapshot.js.map +1 -1
- package/dist/frontend/lowering/surfaces.d.ts +34 -14
- package/dist/frontend/lowering/surfaces.js +177 -104
- package/dist/frontend/lowering/surfaces.js.map +1 -1
- package/dist/frontend/npm-static-declarations.d.ts +4 -0
- package/dist/frontend/npm-static-declarations.js +56 -0
- package/dist/frontend/npm-static-declarations.js.map +1 -1
- package/dist/frontend/npm-static-declarations.test.js +23 -2
- package/dist/frontend/npm-static-declarations.test.js.map +1 -1
- package/dist/frontend/npm-static-prune.d.ts +6 -0
- package/dist/frontend/npm-static-prune.js +203 -0
- package/dist/frontend/npm-static-prune.js.map +1 -0
- package/dist/frontend/npm-static-prune.test.d.ts +1 -0
- package/dist/frontend/npm-static-prune.test.js +48 -0
- package/dist/frontend/npm-static-prune.test.js.map +1 -0
- package/dist/frontend/npm-static.js +6 -5
- package/dist/frontend/npm-static.js.map +1 -1
- package/dist/frontend/npm.d.ts +15 -3
- package/dist/frontend/npm.js +87 -14
- package/dist/frontend/npm.js.map +1 -1
- package/dist/frontend/npm.test.js +76 -9
- package/dist/frontend/npm.test.js.map +1 -1
- package/dist/frontend/program.js +107 -14
- package/dist/frontend/program.js.map +1 -1
- package/dist/frontend/provenance.js +8 -3
- package/dist/frontend/provenance.js.map +1 -1
- package/dist/frontend/resolve.d.ts +6 -0
- package/dist/frontend/resolve.js +7 -4
- package/dist/frontend/resolve.js.map +1 -1
- package/dist/frontend/type-mapper.d.ts +5 -0
- package/dist/frontend/type-mapper.js +80 -29
- package/dist/frontend/type-mapper.js.map +1 -1
- package/dist/index.d.ts +8 -3
- package/dist/index.js +34 -41
- package/dist/index.js.map +1 -1
- package/dist/ir/analysis.d.ts +5 -3
- package/dist/ir/analysis.js +25 -11
- package/dist/ir/analysis.js.map +1 -1
- package/dist/ir/analysis.test.js +50 -2
- package/dist/ir/analysis.test.js.map +1 -1
- package/dist/ir/constant-tables.d.ts +17 -0
- package/dist/ir/constant-tables.js +99 -0
- package/dist/ir/constant-tables.js.map +1 -0
- package/dist/ir/constant-tables.test.d.ts +1 -0
- package/dist/ir/constant-tables.test.js +78 -0
- package/dist/ir/constant-tables.test.js.map +1 -0
- package/dist/ir/integer-ranges.d.ts +13 -0
- package/dist/ir/integer-ranges.js +122 -0
- package/dist/ir/integer-ranges.js.map +1 -0
- package/dist/ir/integer-ranges.test.d.ts +1 -0
- package/dist/ir/integer-ranges.test.js +63 -0
- package/dist/ir/integer-ranges.test.js.map +1 -0
- package/dist/ir/ir.d.ts +130 -76
- package/dist/ir/ir.js +69 -4
- package/dist/ir/ir.js.map +1 -1
- package/dist/ir/ir.test.js +20 -1
- package/dist/ir/ir.test.js.map +1 -1
- package/dist/ir/scalar-records.d.ts +8 -0
- package/dist/ir/scalar-records.js +216 -0
- package/dist/ir/scalar-records.js.map +1 -0
- package/dist/ir/scalar-records.test.d.ts +1 -0
- package/dist/ir/scalar-records.test.js +142 -0
- package/dist/ir/scalar-records.test.js.map +1 -0
- package/dist/ir/serialize.d.ts +1 -1
- package/dist/ir/serialize.js +1 -1
- package/dist/ir/serialize.js.map +1 -1
- package/dist/ir/validate.js +256 -20
- package/dist/ir/validate.js.map +1 -1
- package/dist/ir/validate.test.d.ts +1 -0
- package/dist/ir/validate.test.js +31 -0
- package/dist/ir/validate.test.js.map +1 -0
- package/dist/library/cache-primitives.d.ts +1 -1
- package/dist/library/cache-primitives.js +3 -3
- package/dist/library/cache-primitives.js.map +1 -1
- package/dist/library/fence-eval.js +11 -4
- package/dist/library/fence-eval.js.map +1 -1
- package/dist/library/int-infer.test.js +4 -4
- package/dist/library/int-infer.test.js.map +1 -1
- package/dist/library/library-cache.js +0 -1
- package/dist/library/library-cache.js.map +1 -1
- package/dist/library/library-cache.test.js +8 -8
- package/dist/library/library-cache.test.js.map +1 -1
- package/package.json +17 -17
- package/surface-manifest.json +186 -79
|
@@ -11,11 +11,11 @@ import { pathToFileURL } from "node:url";
|
|
|
11
11
|
import { wasiGuestPath } from "../../wasi-paths.js";
|
|
12
12
|
import { BIGINT_T, 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, canBoxFuncIntoDyn, funcOf, isDynTypedRefType, isJsonSafeType, isSupportedArrayElem, isUnitType, jsOpResultKind, shapeHasAccessorSlots, typeEquals, typeKey, unionFuncSetArmsOk } from "../../ir/ir.js";
|
|
13
13
|
import { cjsClassExprWholeExportOf, cjsExportAssignmentOf, cjsExportDiscardReason, isCjsExportTableLiteral, isCjsJsFile, isJsSourceFile, isModuleExportsAccess, isNodeEsmFile, locOf } from "../program.js";
|
|
14
|
-
import { ARRAY_METHODS, builtinConstLit, builtinFenceHintOf, builtinModuleConstOf, builtinModulesArrayLit, builtinModuleFnOf, ISLAND_SURFACE, isChildSurfaceMember, MAP_METHODS, NARROW_FIRST, SET_METHODS, STR_METHODS, UNSUPPORTED_EXPR, sideEffectFreeOptionValue, stdlibGlobalNameOf } from "./surfaces.js";
|
|
14
|
+
import { ARRAY_METHODS, builtinConstLit, builtinFenceHintOf, builtinModuleConstOf, builtinModulesArrayLit, builtinModuleFnOf, COMPOUND_ASSIGN_OPS, ISLAND_SURFACE, isChildSurfaceMember, MAP_METHODS, NARROW_FIRST, SET_METHODS, STR_METHODS, UNSUPPORTED_EXPR, sideEffectFreeOptionValue, stdlibGlobalNameOf } from "./surfaces.js";
|
|
15
15
|
import { blockedBindingUseDiag, requiresDynamicPackageDiag, unsupportedDiag } from "../../diagnostics/diagnostic.js";
|
|
16
16
|
import { PoisonError, dynUndefinedExpr, jsFuncNameOf, neverTaintedJsType, nodeThrowExpr, own } from "./lowerer.js";
|
|
17
|
-
import { lowerNpmStaticSafeIndexRead, lowerSafeIndexRead, strCharsCall } from "./lower-containers.js";
|
|
18
|
-
import { arrayValueStore } from "./array-values.js";
|
|
17
|
+
import { lowerNpmStaticSafeIndexRead, lowerSafeIndexRead, strCharsCall, tryLowerNumericIndexRead } from "./lower-containers.js";
|
|
18
|
+
import { arrayValueRead, arrayValueStore } from "./array-values.js";
|
|
19
19
|
import { npmStaticPackageOfPath } from "../npm-static.js";
|
|
20
20
|
import { unsupportedModuleFeatureOf } from "../builtin-modules.js";
|
|
21
21
|
import { fenceEnumObjectValue, lowerEnumAccess } from "./lower-enums.js";
|
|
@@ -23,7 +23,7 @@ import { ambientNsRootOf, ambientUndefReadType, ambientUndefVarRootOf, ambientUn
|
|
|
23
23
|
import { expandoMemberRead, expandoWritableTarget } from "./lower-expando.js";
|
|
24
24
|
import { lowerSocketInstanceOf, lowerTlsRootCertificates } from "./lower-server.js";
|
|
25
25
|
import { findGenericMethodOn, lowerStaticFieldRead } from "./lower-classes.js";
|
|
26
|
-
import { bindingNeverReassigned, implicitMonoFile, lowerTaggedTemplate, nullishGenericBindingUnitOf, objLitGenericFnInfoOf, objLitGenericFnNodeOf, requireObjLitGenericReceiver } from "./lower-calls.js";
|
|
26
|
+
import { bindingNeverReassigned, funcTypeFromParamShapes, implicitMonoFile, lowerTaggedTemplate, nullishGenericBindingUnitOf, objLitGenericFnInfoOf, objLitGenericFnNodeOf, requireObjLitGenericReceiver } from "./lower-calls.js";
|
|
27
27
|
import { mixinFnOfCallee } from "./lower-mixins.js";
|
|
28
28
|
import { isConstAssertionTypeNode, isGenericCallableMemberType, isParseArgsDynTypeName, underConstAssertion, unitOnlyUnion } from "../type-mapper.js";
|
|
29
29
|
import { lowerYield } from "./lower-generators.js";
|
|
@@ -34,6 +34,8 @@ import { hasOptionalChainGuard, isOptionalChainTail, isRequireMainFilename } fro
|
|
|
34
34
|
import { conditionalSpreadOf, foldedStringKeyOf } from "./expressions/object-literals.js";
|
|
35
35
|
import { tryLowerExpression } from "./expressions/try-lower-expression.js";
|
|
36
36
|
import { fenceNodeModuleMutation, isNodeModuleValue, lowerNodeModuleIdentifier, lowerNodeModuleProperty, lowerRequireCacheElement, lowerRequireCacheHas, lowerRequireMainProperty } from "./lower-node-module.js";
|
|
37
|
+
import { lowerAbstractEquality } from "./abstract-equality.js";
|
|
38
|
+
import { coerceStringSearchValue, defaultAfterUndefined, lowerStaticallyUndefinedArgument } from "./optional-arguments.js";
|
|
37
39
|
/** A template piece's RAW text (String.raw's contract: escapes stay
|
|
38
40
|
* characters). 7's client AST ships no rawText at runtime (the typing
|
|
39
41
|
* declares it; the serialized node data omits it), so the raw span comes
|
|
@@ -598,6 +600,7 @@ function lowerExprInner(lowerer, expr) {
|
|
|
598
600
|
symbol: "symbol",
|
|
599
601
|
map: "object", set: "object", promise: "object", bytes: "object",
|
|
600
602
|
regexp: "object", generator: "object", classval: "function",
|
|
603
|
+
moduleNs: "object",
|
|
601
604
|
undefinedT: "undefined", nullT: "object",
|
|
602
605
|
};
|
|
603
606
|
const folded = FOLD[operand.type.kind];
|
|
@@ -649,13 +652,22 @@ function lowerExprInner(lowerer, expr) {
|
|
|
649
652
|
if (expr.text === "arguments" && lowerer.ctx.argumentsLocal) {
|
|
650
653
|
return { kind: "varRef", localId: lowerer.ctx.argumentsLocal.id, type: DYN, loc };
|
|
651
654
|
}
|
|
652
|
-
// A
|
|
653
|
-
//
|
|
654
|
-
//
|
|
655
|
+
// A compiler-projected adapter as a VALUE: the adapter has no
|
|
656
|
+
// runtime function object (its calls rewrite directly) — call it
|
|
657
|
+
// through its immutable binding instead.
|
|
655
658
|
{
|
|
656
659
|
const sym = lowerer.resolveValueSymbol(expr);
|
|
657
|
-
|
|
658
|
-
|
|
660
|
+
const projection = sym ? lowerer.staticCallables.get(sym) : undefined;
|
|
661
|
+
if (projection?.kind === "promisified-exec-file" || projection?.kind === "promisified-builtin") {
|
|
662
|
+
lowerer.unsupported("SC1090", expr, `a promisified builtin as a value (call '${expr.text}' directly)`);
|
|
663
|
+
}
|
|
664
|
+
if (projection?.kind === "builtin-function") {
|
|
665
|
+
if (!isJsSourceFile(expr.getSourceFile())) {
|
|
666
|
+
const callable = lowerer.lowerBuiltinCallableValue(projection, loc);
|
|
667
|
+
if (callable)
|
|
668
|
+
return callable;
|
|
669
|
+
}
|
|
670
|
+
lowerer.unsupported("SC1090", expr, `a builtin function alias as an escaping value (call '${expr.text}' directly)`);
|
|
659
671
|
}
|
|
660
672
|
}
|
|
661
673
|
// Union-typed bindings read through tsc's control-flow narrowing:
|
|
@@ -809,17 +821,12 @@ function lowerExprInner(lowerer, expr) {
|
|
|
809
821
|
if (sig && lowerer.isTopLevelFnSymbol(expr)) {
|
|
810
822
|
// A declared function used as a value: a zero-capture closure. The
|
|
811
823
|
// backend interns one per function so `f === f` holds (JS identity).
|
|
812
|
-
// The value's type is the completed ABI signature
|
|
813
|
-
//
|
|
824
|
+
// The value's type is the completed ABI signature; optional/default
|
|
825
|
+
// slots and typed rest arrays pass the value fence first.
|
|
814
826
|
lowerer.noteEdge(sig.name);
|
|
815
827
|
// dynRest slots stay out of the VALUE type's param list (fn.length
|
|
816
828
|
// semantics); the rest marker carries the trailing dyn-array ABI.
|
|
817
|
-
const funcType =
|
|
818
|
-
kind: "func",
|
|
819
|
-
params: sig.params.filter((p) => p.mode !== "dynRest").map((p) => p.type),
|
|
820
|
-
ret: sig.returnType,
|
|
821
|
-
...(sig.params.some((p) => p.mode === "dynRest") ? { rest: true } : {}),
|
|
822
|
-
};
|
|
829
|
+
const funcType = funcTypeFromParamShapes(sig.params, sig.returnType);
|
|
823
830
|
lowerer.requireExactArityValue(expr, expr, sig.params, funcType);
|
|
824
831
|
return { kind: "closure", fnName: sig.name, captures: [], type: funcType, loc };
|
|
825
832
|
}
|
|
@@ -865,6 +872,12 @@ function lowerExprInner(lowerer, expr) {
|
|
|
865
872
|
if (bi.module === "module" && bi.member === "builtinModules") {
|
|
866
873
|
return builtinModulesArrayLit(loc);
|
|
867
874
|
}
|
|
875
|
+
if (bi.module === "http" && bi.member === "METHODS") {
|
|
876
|
+
return { kind: "libCall", fn: "http.methods", args: [], type: arrayOf(STRING), loc };
|
|
877
|
+
}
|
|
878
|
+
if (bi.module === "http" && bi.member === "STATUS_CODES") {
|
|
879
|
+
return { kind: "libCall", fn: "http.statusCodes", args: [], type: DYN, loc };
|
|
880
|
+
}
|
|
868
881
|
// tls.rootCertificates: a runtime-valued module constant (the
|
|
869
882
|
// cached bundled-CA array) — the one member read that lowers
|
|
870
883
|
// to a libCall instead of a baked literal.
|
|
@@ -879,6 +892,11 @@ function lowerExprInner(lowerer, expr) {
|
|
|
879
892
|
if (isJsSourceFile(expr.getSourceFile())) {
|
|
880
893
|
return { kind: "strLit", value: `[builtin ${bi.module}.${bi.member}]`, type: STRING, loc };
|
|
881
894
|
}
|
|
895
|
+
{
|
|
896
|
+
const callable = lowerer.lowerBuiltinCallableValue(bi, loc);
|
|
897
|
+
if (callable)
|
|
898
|
+
return callable;
|
|
899
|
+
}
|
|
882
900
|
if (builtinModuleFnOf(lowerer, bi.module, bi.member)) {
|
|
883
901
|
lowerer.unsupported("SC1090", expr, `library functions as values (call '${expr.text}' directly)`);
|
|
884
902
|
}
|
|
@@ -889,7 +907,12 @@ function lowerExprInner(lowerer, expr) {
|
|
|
889
907
|
// the namespace object has no representation — members lower at
|
|
890
908
|
// their access sites only. The CommonJS namespace binding
|
|
891
909
|
// (`const lib = require("./lib.js")`) gets the same fence.
|
|
892
|
-
|
|
910
|
+
const builtinNamespace = lowerer.builtinNamespaceModuleOf(expr);
|
|
911
|
+
if (builtinNamespace !== null) {
|
|
912
|
+
const type = { kind: "moduleNs", moduleId: `builtin:${builtinNamespace}` };
|
|
913
|
+
return { kind: "moduleNsRef", moduleId: type.moduleId, type, loc };
|
|
914
|
+
}
|
|
915
|
+
if (lowerer.cjsLocalModuleBindingOf(expr)) {
|
|
893
916
|
lowerer.unsupported("SC1090", expr, `module namespace objects as values (access '${expr.text}' members directly)`);
|
|
894
917
|
}
|
|
895
918
|
if (lowerer.islandGlobalFnOf(expr)) {
|
|
@@ -941,11 +964,14 @@ function lowerExprInner(lowerer, expr) {
|
|
|
941
964
|
// type-mapper.ts pins the one concrete signature `(value: string) =>
|
|
942
965
|
// primitive`; direct calls `String(x)` never reach here — the call
|
|
943
966
|
// lowering intercepts them with the wider static coercions).
|
|
944
|
-
|
|
967
|
+
const jsPrimitiveCtorSelector = isJsSourceFile(expr.getSourceFile()) &&
|
|
968
|
+
expr.parent !== undefined &&
|
|
969
|
+
ts.isArrowFunction(expr.parent) &&
|
|
970
|
+
expr.parent.body === expr;
|
|
945
971
|
if ((expr.text === "String" || expr.text === "Number" || expr.text === "Boolean") &&
|
|
946
|
-
!isJsSourceFile(expr.getSourceFile()) &&
|
|
972
|
+
(!isJsSourceFile(expr.getSourceFile()) || jsPrimitiveCtorSelector) &&
|
|
947
973
|
lowerer.isStdlibSymbol(lowerer.checker.getSymbolAtLocation(expr))) {
|
|
948
|
-
return primitiveCtorClosure(lowerer, expr.text, loc);
|
|
974
|
+
return primitiveCtorClosure(lowerer, expr.text, loc, jsPrimitiveCtorSelector);
|
|
949
975
|
}
|
|
950
976
|
// The lib fence's IDENTIFIER chokepoint: the real standard library
|
|
951
977
|
// resolves names the old minimal ambient world never declared
|
|
@@ -1081,6 +1107,15 @@ function lowerExprInner(lowerer, expr) {
|
|
|
1081
1107
|
// representation (ambient namespaces compile to Node's
|
|
1082
1108
|
// ReferenceError instead — the object never exists at runtime).
|
|
1083
1109
|
{
|
|
1110
|
+
const moduleNs = lowerer.mapTypeOf(lowerer.typeOf(expr));
|
|
1111
|
+
if (moduleNs?.kind === "moduleNs") {
|
|
1112
|
+
return { kind: "moduleNsRef", moduleId: moduleNs.moduleId, type: moduleNs, loc };
|
|
1113
|
+
}
|
|
1114
|
+
const builtinNs = lowerer.builtinNamespaceModuleOf(expr);
|
|
1115
|
+
if (builtinNs !== null) {
|
|
1116
|
+
const type = { kind: "moduleNs", moduleId: `builtin:${builtinNs}` };
|
|
1117
|
+
return { kind: "moduleNsRef", moduleId: type.moduleId, type, loc };
|
|
1118
|
+
}
|
|
1084
1119
|
const ns = lowerNsIdentifierValue(lowerer, expr);
|
|
1085
1120
|
if (ns)
|
|
1086
1121
|
return ns;
|
|
@@ -3084,10 +3119,10 @@ export function lowerIntrinsicProperty(lowerer, expr) {
|
|
|
3084
3119
|
const receiver = lowerer.lowerExpr(expr.expression);
|
|
3085
3120
|
return { kind: "libCall", fn: "child.killed", args: [receiver], type: BOOL, loc };
|
|
3086
3121
|
}
|
|
3087
|
-
if (name === "on" || name === "kill" || name === "unref") {
|
|
3122
|
+
if (name === "on" || name === "once" || name === "kill" || name === "unref") {
|
|
3088
3123
|
lowerer.unsupported("SC1090", expr, `child methods as values (call '${name}' directly)`);
|
|
3089
3124
|
}
|
|
3090
|
-
lowerer.noLowering(`ChildProcess.${name}`, expr, "on(\"exit\" | \"error\", cb), pid, exitCode, killed, kill(signal?), and unref() are the supported ChildProcess members", lowerer.checker.getSymbolAtLocation(expr.name));
|
|
3125
|
+
lowerer.noLowering(`ChildProcess.${name}`, expr, "on/once(\"exit\" | \"close\" | \"error\", cb), pid, exitCode, killed, kill(signal?), and unref() are the supported ChildProcess members", lowerer.checker.getSymbolAtLocation(expr.name));
|
|
3091
3126
|
}
|
|
3092
3127
|
if (kind === "spawnRes") {
|
|
3093
3128
|
// The spawnSync-result reads. status is the interned `number | null`
|
|
@@ -3137,7 +3172,7 @@ export function lowerIntrinsicProperty(lowerer, expr) {
|
|
|
3137
3172
|
if (name === "isFile" || name === "isDirectory") {
|
|
3138
3173
|
lowerer.unsupported("SC1090", expr, `Stats methods as values (call '${name}' directly)`);
|
|
3139
3174
|
}
|
|
3140
|
-
lowerer.noLowering(`Stats.${name}`, expr, "isFile(), isDirectory(), isSymbolicLink(), size, blocks, nlink, atimeMs, and
|
|
3175
|
+
lowerer.noLowering(`Stats.${name}`, expr, "isFile(), isDirectory(), isSymbolicLink(), dev, ino, size, blocks, nlink, atimeMs, mtimeMs, and ctimeMs are the supported Stats members", lowerer.checker.getSymbolAtLocation(expr.name));
|
|
3141
3176
|
}
|
|
3142
3177
|
if (kind === "date") {
|
|
3143
3178
|
const methods = new Set([
|
|
@@ -3178,22 +3213,30 @@ export function lowerIntrinsicProperty(lowerer, expr) {
|
|
|
3178
3213
|
// serialization: lowercased hostname, `:port` appended exactly when
|
|
3179
3214
|
// a non-default port is present (scr_url_host — Node-exact,
|
|
3180
3215
|
// opaque-path URLs answer ""); `hostname` is the stored port-less
|
|
3181
|
-
// host field verbatim
|
|
3182
|
-
|
|
3183
|
-
// never sees one).
|
|
3184
|
-
if (name === "protocol" || name === "pathname" || name === "href" || name === "host" || name === "hostname" || name === "search") {
|
|
3216
|
+
// host field verbatim, including IPv6 brackets.
|
|
3217
|
+
if (name === "protocol" || name === "origin" || name === "username" || name === "password" || name === "pathname" || name === "href" || name === "host" || name === "hostname" || name === "port" || name === "search" || name === "hash") {
|
|
3185
3218
|
const receiver = lowerer.lowerExpr(expr.expression);
|
|
3186
3219
|
const fn = name === "protocol"
|
|
3187
3220
|
? "url.protocol"
|
|
3188
|
-
: name === "
|
|
3189
|
-
? "url.
|
|
3190
|
-
: name === "
|
|
3191
|
-
? "url.
|
|
3192
|
-
: name === "
|
|
3193
|
-
? "url.
|
|
3194
|
-
: name === "
|
|
3195
|
-
? "url.
|
|
3196
|
-
: "
|
|
3221
|
+
: name === "origin"
|
|
3222
|
+
? "url.origin"
|
|
3223
|
+
: name === "username"
|
|
3224
|
+
? "url.username"
|
|
3225
|
+
: name === "password"
|
|
3226
|
+
? "url.password"
|
|
3227
|
+
: name === "pathname"
|
|
3228
|
+
? "url.pathname"
|
|
3229
|
+
: name === "host"
|
|
3230
|
+
? "url.host"
|
|
3231
|
+
: name === "hostname"
|
|
3232
|
+
? "url.hostname"
|
|
3233
|
+
: name === "port"
|
|
3234
|
+
? "url.port"
|
|
3235
|
+
: name === "search"
|
|
3236
|
+
? "url.search"
|
|
3237
|
+
: name === "hash"
|
|
3238
|
+
? "url.hash"
|
|
3239
|
+
: "url.href";
|
|
3197
3240
|
return { kind: "libCall", fn, args: [receiver], type: STRING, loc: locOf(expr) };
|
|
3198
3241
|
}
|
|
3199
3242
|
// `u.searchParams`: the LIVE cached view (one identity per URL —
|
|
@@ -3206,7 +3249,7 @@ export function lowerIntrinsicProperty(lowerer, expr) {
|
|
|
3206
3249
|
if (name === "toString" || name === "toJSON") {
|
|
3207
3250
|
lowerer.unsupported("SC1090", expr, `URL methods as values (call '${name}' directly)`);
|
|
3208
3251
|
}
|
|
3209
|
-
lowerer.noLowering(`URL.${name}`, expr, "protocol, pathname, href, host, hostname, search, searchParams, and toString() are the supported URL members", lowerer.checker.getSymbolAtLocation(expr.name));
|
|
3252
|
+
lowerer.noLowering(`URL.${name}`, expr, "protocol, origin, username, password, pathname, href, host, hostname, port, search, hash, searchParams, and toString() are the supported URL members", lowerer.checker.getSymbolAtLocation(expr.name));
|
|
3210
3253
|
}
|
|
3211
3254
|
if (kind === "searchParams") {
|
|
3212
3255
|
const SEARCH_PARAMS_METHODS = new Set(["get", "getAll", "set", "append", "delete", "has", "sort", "toString", "forEach", "keys", "values", "entries"]);
|
|
@@ -3768,6 +3811,11 @@ export function lowerOptionalNumber(lowerer, operand, loc, narrowedNode) {
|
|
|
3768
3811
|
if (operand.type.kind !== "union" || lowerer.armTag(operand.type.unionId, UNDEFINED_T) < 0)
|
|
3769
3812
|
return operand;
|
|
3770
3813
|
const directNumber = lowerer.stripUndefinedArm(operand.type).kind === "f64";
|
|
3814
|
+
if (directNumber) {
|
|
3815
|
+
const scalarRead = tryLowerNumericIndexRead(lowerer, operand, loc);
|
|
3816
|
+
if (scalarRead)
|
|
3817
|
+
return scalarRead;
|
|
3818
|
+
}
|
|
3771
3819
|
const checkerNumber = narrowedNode !== undefined && lowerer.mapTypeOf(lowerer.typeOf(narrowedNode))?.kind === "f64";
|
|
3772
3820
|
if (!directNumber && (!checkerNumber || lowerer.armTag(operand.type.unionId, F64) < 0))
|
|
3773
3821
|
return operand;
|
|
@@ -4546,6 +4594,78 @@ function tupleLiteralIndex(node) {
|
|
|
4546
4594
|
const n = Number(e.text);
|
|
4547
4595
|
return Number.isInteger(n) && n >= 0 ? n : null;
|
|
4548
4596
|
}
|
|
4597
|
+
/** `a[i] op= rhs` over native arrays and byte views. A compound assignment
|
|
4598
|
+
* evaluates the receiver and index, reads the old element, evaluates rhs,
|
|
4599
|
+
* then writes. Capture each stage so a call in the index or rhs cannot
|
|
4600
|
+
* change the target or the value used by the operator. The expression yields
|
|
4601
|
+
* the computed value before a typed array or Buffer coerces it for storage. */
|
|
4602
|
+
export function lowerElementCompound(lowerer, expr, op) {
|
|
4603
|
+
const target = expr.left;
|
|
4604
|
+
fenceNodeModuleMutation(lowerer, target, "assignment");
|
|
4605
|
+
const loc = locOf(expr);
|
|
4606
|
+
const receiverType = lowerer.mapTypeOf(lowerer.typeOf(target.expression));
|
|
4607
|
+
if (receiverType?.kind !== "array" && receiverType?.kind !== "bytes") {
|
|
4608
|
+
lowerer.unsupported("SC1090", target, "compound assignment to non-array elements");
|
|
4609
|
+
}
|
|
4610
|
+
let receiver = lowerer.lowerExpr(target.expression);
|
|
4611
|
+
if (receiver.type.kind === "union" && lowerer.armTag(receiver.type.unionId, UNDEFINED_T) >= 0) {
|
|
4612
|
+
const present = lowerer.stripUndefinedArm(receiver.type);
|
|
4613
|
+
const helper = present.kind === receiverType.kind
|
|
4614
|
+
? lowerer.narrowedArmHelper(receiver.type.unionId, present, locOf(target.expression))
|
|
4615
|
+
: null;
|
|
4616
|
+
if (helper)
|
|
4617
|
+
receiver = { kind: "call", callee: helper, args: [receiver], type: present, loc: locOf(target.expression) };
|
|
4618
|
+
}
|
|
4619
|
+
if (receiver.type.kind !== receiverType.kind) {
|
|
4620
|
+
lowerer.unsupported("SC1090", target.expression, "compound assignment through a non-native array or byte view");
|
|
4621
|
+
}
|
|
4622
|
+
const index = lowerer.lowerExpr(target.argumentExpression);
|
|
4623
|
+
if (index.type.kind !== "f64")
|
|
4624
|
+
lowerer.unsupported("SC1090", target.argumentExpression, "indexing with non-number keys");
|
|
4625
|
+
const receiverLocal = lowerer.declareHiddenLocal("%compoundArray", receiver.type);
|
|
4626
|
+
const indexLocal = lowerer.declareHiddenLocal("%compoundIndex", F64);
|
|
4627
|
+
const receiverRef = () => varRef(receiverLocal.id, receiver.type, loc);
|
|
4628
|
+
const indexRef = () => varRef(indexLocal.id, F64, loc);
|
|
4629
|
+
const oldValue = receiver.type.kind === "array"
|
|
4630
|
+
? arrayValueRead(lowerer, receiverRef(), indexRef(), receiver.type.elem, locOf(target))
|
|
4631
|
+
: { kind: "bytesIntrinsic", method: "get", receiver: receiverRef(), args: [indexRef()], type: F64, loc: locOf(target) };
|
|
4632
|
+
const oldLocal = lowerer.declareHiddenLocal("%compoundOld", oldValue.type);
|
|
4633
|
+
const oldRef = () => varRef(oldLocal.id, oldValue.type, loc);
|
|
4634
|
+
const rhs = lowerer.lowerExpr(expr.right);
|
|
4635
|
+
const numericRhs = lowerOptionalNumber(lowerer, rhs, loc);
|
|
4636
|
+
const elementType = receiver.type.kind === "array" ? receiver.type.elem : F64;
|
|
4637
|
+
const valueType = elementType.kind === "union" && lowerer.armTag(elementType.unionId, UNDEFINED_T) >= 0
|
|
4638
|
+
? lowerer.stripUndefinedArm(elementType)
|
|
4639
|
+
: elementType;
|
|
4640
|
+
let computed;
|
|
4641
|
+
if (op === "+" && valueType.kind === "string") {
|
|
4642
|
+
computed = { kind: "strConcat", left: lowerer.ensureString(oldRef(), target), right: lowerer.ensureString(rhs, expr.right), type: STRING, loc };
|
|
4643
|
+
}
|
|
4644
|
+
else if (valueType.kind === "f64" && numericRhs.type.kind === "f64") {
|
|
4645
|
+
computed = { kind: "bin", op, left: lowerOptionalNumber(lowerer, oldRef(), loc), right: numericRhs, type: F64, loc };
|
|
4646
|
+
}
|
|
4647
|
+
else {
|
|
4648
|
+
lowerer.unsupported("SC1043", expr);
|
|
4649
|
+
}
|
|
4650
|
+
const resultLocal = lowerer.declareHiddenLocal("%compoundResult", computed.type);
|
|
4651
|
+
const resultRef = () => varRef(resultLocal.id, computed.type, loc);
|
|
4652
|
+
const write = receiver.type.kind === "array"
|
|
4653
|
+
? arrayValueStore(lowerer, receiverRef(), indexRef(), resultRef(), receiver.type.elem, loc)
|
|
4654
|
+
: { kind: "bytesSet", arr: receiverRef(), index: indexRef(), value: resultRef(), loc };
|
|
4655
|
+
return {
|
|
4656
|
+
kind: "seqExpr",
|
|
4657
|
+
stmts: [
|
|
4658
|
+
{ kind: "varDecl", localId: receiverLocal.id, init: receiver, loc },
|
|
4659
|
+
{ kind: "varDecl", localId: indexLocal.id, init: index, loc },
|
|
4660
|
+
{ kind: "varDecl", localId: oldLocal.id, init: oldValue, loc },
|
|
4661
|
+
{ kind: "varDecl", localId: resultLocal.id, init: computed, loc },
|
|
4662
|
+
write,
|
|
4663
|
+
],
|
|
4664
|
+
result: resultRef(),
|
|
4665
|
+
type: computed.type,
|
|
4666
|
+
loc,
|
|
4667
|
+
};
|
|
4668
|
+
}
|
|
4549
4669
|
/** `a[i] = v` in statement position → arraySet (element writes, like local
|
|
4550
4670
|
* assignment, produce no value in our subset). */
|
|
4551
4671
|
export function lowerElementWrite(lowerer, expr) {
|
|
@@ -4917,6 +5037,18 @@ export function ensureString(lowerer, e, node) {
|
|
|
4917
5037
|
if (stringable) {
|
|
4918
5038
|
return { kind: "toString", operand: e, type: STRING, loc: e.loc };
|
|
4919
5039
|
}
|
|
5040
|
+
// Runtime-optional locals can retain their stored union after the
|
|
5041
|
+
// checker has narrowed this use to a primitive arm. Validate that
|
|
5042
|
+
// arm before converting it; an unguarded object arm stays fenced.
|
|
5043
|
+
const narrowed = lowerer.mapTypeOf(lowerer.typeOf(node));
|
|
5044
|
+
if (narrowed &&
|
|
5045
|
+
(narrowed.kind === "string" || narrowed.kind === "f64" ||
|
|
5046
|
+
narrowed.kind === "bool" || narrowed.kind === "bigint")) {
|
|
5047
|
+
const helper = lowerer.narrowedArmHelper(e.type.unionId, narrowed, e.loc);
|
|
5048
|
+
if (helper) {
|
|
5049
|
+
return ensureString(lowerer, { kind: "call", callee: helper, args: [e], type: narrowed, loc: e.loc }, node);
|
|
5050
|
+
}
|
|
5051
|
+
}
|
|
4920
5052
|
lowerer.unsupported("SC1090", node, `string conversions of unions with object arms (${NARROW_FIRST})`);
|
|
4921
5053
|
}
|
|
4922
5054
|
if (e.type.kind === "symbol") {
|
|
@@ -4968,7 +5100,7 @@ export function ensureString(lowerer, e, node) {
|
|
|
4968
5100
|
* neither is observable where the value immediately stringifies — so the
|
|
4969
5101
|
* span lowers as the argument's own ToString (`new String()` is "").
|
|
4970
5102
|
* Every other position keeps the wrapper-object constructor fence. */
|
|
4971
|
-
function stringWrapperToString(lowerer, node) {
|
|
5103
|
+
export function stringWrapperToString(lowerer, node) {
|
|
4972
5104
|
let e = node;
|
|
4973
5105
|
while (ts.isParenthesizedExpression(e))
|
|
4974
5106
|
e = e.expression;
|
|
@@ -4982,7 +5114,11 @@ function stringWrapperToString(lowerer, node) {
|
|
|
4982
5114
|
return null;
|
|
4983
5115
|
if (args.length === 0)
|
|
4984
5116
|
return { kind: "strLit", value: "", type: STRING, loc: locOf(e) };
|
|
4985
|
-
|
|
5117
|
+
const undefinedArg = lowerStaticallyUndefinedArgument(lowerer, args[0]);
|
|
5118
|
+
if (undefinedArg)
|
|
5119
|
+
return defaultAfterUndefined(undefinedArg, { kind: "strLit", value: "undefined", type: STRING, loc: locOf(e) });
|
|
5120
|
+
return lowerer.caughtToString(args[0]) ??
|
|
5121
|
+
coerceStringSearchValue(lowerer, lowerer.lowerExpr(args[0]), args[0], locOf(e));
|
|
4986
5122
|
}
|
|
4987
5123
|
export function lowerTemplate(lowerer, expr) {
|
|
4988
5124
|
const loc = locOf(expr);
|
|
@@ -5229,7 +5365,14 @@ export function lowerPrefixUnary(lowerer, expr) {
|
|
|
5229
5365
|
if (raw.type.kind === "bigint") {
|
|
5230
5366
|
return { kind: "libCall", fn: "bigint.not", args: [raw], type: BIGINT_T, loc };
|
|
5231
5367
|
}
|
|
5232
|
-
|
|
5368
|
+
// A checked-dynamic value retains enough JavaScript structure to
|
|
5369
|
+
// run exact ToNumber, including the object valueOf/toString
|
|
5370
|
+
// protocol. This is the static `any`/JS-lane answer for idioms
|
|
5371
|
+
// such as `while (~index)`, where inference may have widened an
|
|
5372
|
+
// otherwise numeric slot to the checked-dynamic tree.
|
|
5373
|
+
const operand = raw.type.kind === "dyn"
|
|
5374
|
+
? { kind: "libCall", fn: "dyn.toNumberCoerce", args: [raw], type: F64, loc }
|
|
5375
|
+
: lowerOptionalNumber(lowerer, raw, loc, expr.operand);
|
|
5233
5376
|
if (operand.type.kind !== "f64")
|
|
5234
5377
|
lowerer.unsupported("SC1043", expr);
|
|
5235
5378
|
return { kind: "unary", op: "~", operand, type: F64, loc };
|
|
@@ -5367,8 +5510,9 @@ export function lowerBinary(lowerer, expr) {
|
|
|
5367
5510
|
// globals, captured/boxed included); the RHS coerces into the binding's
|
|
5368
5511
|
// type exactly like statement position, and the expression's value is
|
|
5369
5512
|
// the coerced binding-typed value (representation change only — never
|
|
5370
|
-
// observably different from JS's raw-RHS yield).
|
|
5371
|
-
//
|
|
5513
|
+
// observably different from JS's raw-RHS yield). Indexed compounds
|
|
5514
|
+
// use a sequenced read/modify/write; other member targets and
|
|
5515
|
+
// destructuring targets stay fenced.
|
|
5372
5516
|
if (op === ts.SyntaxKind.EqualsToken && ts.isIdentifier(expr.left)) {
|
|
5373
5517
|
const target = lowerer.resolveWritable(expr.left);
|
|
5374
5518
|
if (!target) {
|
|
@@ -5380,6 +5524,10 @@ export function lowerBinary(lowerer, expr) {
|
|
|
5380
5524
|
lowerer.runtimeOptionalLocals.add(runtimeOptionalRoot);
|
|
5381
5525
|
return { kind: "assignExpr", localId: target.id, value, type: target.type, loc };
|
|
5382
5526
|
}
|
|
5527
|
+
const indexedCompound = COMPOUND_ASSIGN_OPS[op];
|
|
5528
|
+
if (indexedCompound !== undefined && ts.isElementAccessExpression(expr.left)) {
|
|
5529
|
+
return lowerElementCompound(lowerer, expr, indexedCompound);
|
|
5530
|
+
}
|
|
5383
5531
|
// `events.defaultMaxListeners = v` — the module-property write
|
|
5384
5532
|
// Node validates (validateNumber(n, 'defaultMaxListeners', 0)):
|
|
5385
5533
|
// the value crosses into the checked-dynamic tree and the runtime ladder throws
|
|
@@ -5518,23 +5666,10 @@ export function lowerBinary(lowerer, expr) {
|
|
|
5518
5666
|
const nullTest = lowerLooseNullCompare(lowerer, expr, loc);
|
|
5519
5667
|
if (nullTest)
|
|
5520
5668
|
return nullTest;
|
|
5521
|
-
|
|
5522
|
-
|
|
5523
|
-
|
|
5524
|
-
|
|
5525
|
-
{
|
|
5526
|
-
const negated = op === ts.SyntaxKind.ExclamationEqualsToken;
|
|
5527
|
-
const left = lowerer.lowerExpr(expr.left);
|
|
5528
|
-
const right = lowerer.lowerExpr(expr.right);
|
|
5529
|
-
if (left.type.kind === "string" && right.type.kind === "string") {
|
|
5530
|
-
return { kind: "strEq", negated, left, right, type: BOOL, loc };
|
|
5531
|
-
}
|
|
5532
|
-
if ((left.type.kind === "f64" && right.type.kind === "f64") ||
|
|
5533
|
-
(left.type.kind === "bool" && right.type.kind === "bool")) {
|
|
5534
|
-
return { kind: "bin", op: negated ? "!==" : "===", left, right, type: BOOL, loc };
|
|
5535
|
-
}
|
|
5536
|
-
}
|
|
5537
|
-
lowerer.unsupported("SC1040", expr);
|
|
5669
|
+
const loose = lowerAbstractEquality(lowerer, lowerer.lowerExpr(expr.left), lowerer.lowerExpr(expr.right), op === ts.SyntaxKind.ExclamationEqualsToken, loc);
|
|
5670
|
+
if (loose)
|
|
5671
|
+
return loose;
|
|
5672
|
+
lowerer.unsupported("SC1040", expr, undefined, "object-to-primitive loose equality can call user-defined valueOf/toString methods — compare explicit primitive conversions instead");
|
|
5538
5673
|
}
|
|
5539
5674
|
if (op === ts.SyntaxKind.AmpersandAmpersandToken || op === ts.SyntaxKind.BarBarToken) {
|
|
5540
5675
|
if (op === ts.SyntaxKind.BarBarToken) {
|
|
@@ -5558,6 +5693,15 @@ export function lowerBinary(lowerer, expr) {
|
|
|
5558
5693
|
if (left.kind === "unitLit") {
|
|
5559
5694
|
return op === ts.SyntaxKind.BarBarToken ? right : left;
|
|
5560
5695
|
}
|
|
5696
|
+
// JS objects and symbols are always truthy. In `ref || fallback`
|
|
5697
|
+
// the fallback is therefore unreachable and the result is the
|
|
5698
|
+
// already-evaluated left value — the browser-fallback idiom used by
|
|
5699
|
+
// packages for `process.argv || []` and `process.env || {}`. The
|
|
5700
|
+
// operand itself remains in the IR, preserving reads/calls that
|
|
5701
|
+
// produce the reference; only the unreachable right lowering drops.
|
|
5702
|
+
if (op === ts.SyntaxKind.BarBarToken && REF_TRUTHY_KINDS.has(left.type.kind)) {
|
|
5703
|
+
return left;
|
|
5704
|
+
}
|
|
5561
5705
|
if (left.type.kind === "dyn" || right.type.kind === "dyn") {
|
|
5562
5706
|
// A checked-dynamic operand (`fn.name || '<anonymous>'` —
|
|
5563
5707
|
// test/common's _mustCallInner): both sides live in the checked-dynamic tree and
|
|
@@ -6253,6 +6397,9 @@ export function lowerBinary(lowerer, expr) {
|
|
|
6253
6397
|
if (idLeft.type.kind === "classval" && idRight.type.kind === "classval") {
|
|
6254
6398
|
return { kind: "bin", op: negated ? "!==" : "===", left: idLeft, right: idRight, type: BOOL, loc };
|
|
6255
6399
|
}
|
|
6400
|
+
if (idLeft.type.kind === "moduleNs" && idRight.type.kind === "moduleNs") {
|
|
6401
|
+
return { kind: "bin", op: negated ? "!==" : "===", left: idLeft, right: idRight, type: BOOL, loc };
|
|
6402
|
+
}
|
|
6256
6403
|
if ((idLeft.type.kind === "array" ||
|
|
6257
6404
|
idLeft.type.kind === "map" ||
|
|
6258
6405
|
idLeft.type.kind === "set" ||
|
|
@@ -7359,10 +7506,10 @@ function lowerInExpression(lowerer, expr, loc) {
|
|
|
7359
7506
|
// Compile-time-known STRING keys fold — literals, and the same
|
|
7360
7507
|
// const/enum-literal and template folding computed property keys get
|
|
7361
7508
|
// (foldedStringKeyOf); runtime-valued keys keep the fence.
|
|
7362
|
-
// NUMERIC literal keys answer on ARRAY receivers
|
|
7363
|
-
//
|
|
7364
|
-
//
|
|
7365
|
-
//
|
|
7509
|
+
// NUMERIC literal keys answer on ARRAY receivers through the shared
|
|
7510
|
+
// presence query. Arrays retain holes independently from length, and
|
|
7511
|
+
// noncanonical numeric keys live in their ordinary-property table, so
|
|
7512
|
+
// a length comparison is not an honest `in` answer.
|
|
7366
7513
|
{
|
|
7367
7514
|
let kNode = expr.left;
|
|
7368
7515
|
while (ts.isParenthesizedExpression(kNode))
|
|
@@ -7370,12 +7517,14 @@ function lowerInExpression(lowerer, expr, loc) {
|
|
|
7370
7517
|
if (ts.isNumericLiteral(kNode) && lowerer.mapTypeOf(lowerer.typeOf(expr.right))?.kind === "array") {
|
|
7371
7518
|
const recvArr = lowerer.lowerExpr(expr.right);
|
|
7372
7519
|
if (recvArr.type.kind === "array") {
|
|
7373
|
-
const len = { kind: "arrIntrinsic", method: "length", receiver: recvArr, args: [], type: F64, loc };
|
|
7374
7520
|
const n = Number(kNode.text);
|
|
7375
|
-
|
|
7376
|
-
|
|
7377
|
-
|
|
7378
|
-
|
|
7521
|
+
return {
|
|
7522
|
+
kind: "arrayHas",
|
|
7523
|
+
arr: recvArr,
|
|
7524
|
+
index: { kind: "numLit", value: n, type: F64, loc },
|
|
7525
|
+
type: BOOL,
|
|
7526
|
+
loc,
|
|
7527
|
+
};
|
|
7379
7528
|
}
|
|
7380
7529
|
}
|
|
7381
7530
|
}
|
|
@@ -8695,7 +8844,20 @@ export function fieldGetExpr(lowerer, target, loc, blame) {
|
|
|
8695
8844
|
// construction), typed as the index value armed with undefined under
|
|
8696
8845
|
// noUncheckedIndexedAccess (mirroring lowerRecordKeyRead).
|
|
8697
8846
|
if (target.container === "recordOvf") {
|
|
8698
|
-
let
|
|
8847
|
+
let obj = target.obj;
|
|
8848
|
+
if (obj.type.kind === "union" && ts.isPropertyAccessExpression(blame)) {
|
|
8849
|
+
const present = lowerer.stripUndefinedArm(obj.type);
|
|
8850
|
+
if (present.kind === "record") {
|
|
8851
|
+
obj = lowerer.runtimeOptionalPropertyReceiver(blame.expression, obj, present, target.field) ?? obj;
|
|
8852
|
+
}
|
|
8853
|
+
}
|
|
8854
|
+
if (obj.type.kind !== "record") {
|
|
8855
|
+
lowerer.unsupported("SC1090", blame, `reading '${target.field}' on a non-record receiver (narrow first)`);
|
|
8856
|
+
}
|
|
8857
|
+
const shape = lowerer.shapes.get(obj.type.shapeId);
|
|
8858
|
+
if (!shape?.indexValue)
|
|
8859
|
+
lowerer.unsupported("SC1090", blame, `reading '${target.field}' on a record without an index signature`);
|
|
8860
|
+
let t = shape.indexValue;
|
|
8699
8861
|
if (lowerer.program.getCompilerOptions().noUncheckedIndexedAccess) {
|
|
8700
8862
|
const armed = lowerer.withUndefinedArmOf(t);
|
|
8701
8863
|
if (!armed)
|
|
@@ -8704,8 +8866,8 @@ export function fieldGetExpr(lowerer, target, loc, blame) {
|
|
|
8704
8866
|
}
|
|
8705
8867
|
return {
|
|
8706
8868
|
kind: "recordKeyGet",
|
|
8707
|
-
obj
|
|
8708
|
-
shapeId:
|
|
8869
|
+
obj,
|
|
8870
|
+
shapeId: obj.type.shapeId,
|
|
8709
8871
|
key: { kind: "strLit", value: target.field, type: STRING, loc },
|
|
8710
8872
|
overflowOnly: true,
|
|
8711
8873
|
type: t,
|
|
@@ -9011,32 +9173,40 @@ function lowerStreamObjectProperty(lowerer, expr) {
|
|
|
9011
9173
|
return lowerStreamProperty(lowerer, expr, info);
|
|
9012
9174
|
}
|
|
9013
9175
|
/** The primitive-constructor closure (`String`/`Number`/`Boolean` as a
|
|
9014
|
-
* VALUE): interns one synthesized module function per constructor
|
|
9015
|
-
*
|
|
9016
|
-
*
|
|
9017
|
-
* (`(
|
|
9018
|
-
*
|
|
9019
|
-
*
|
|
9020
|
-
* every reference the SAME immortal closure,
|
|
9021
|
-
* compares like JS function identity. */
|
|
9022
|
-
function primitiveCtorClosure(lowerer, name, loc) {
|
|
9176
|
+
* VALUE): interns one synthesized module function per constructor/ABI and
|
|
9177
|
+
* returns the zero-capture closure over it. Typed sources use the mapped
|
|
9178
|
+
* `(value: string) => primitive` signature; a recognized JavaScript
|
|
9179
|
+
* concise-arrow selector (`() => String`, the picocolors fallback) takes
|
|
9180
|
+
* dyn so its ordinary coercion signature survives inference residue. The
|
|
9181
|
+
* dyn bodies run exact ToString/ToNumber/ToBoolean, including object hooks.
|
|
9182
|
+
* Interning makes every reference under one ABI the SAME immortal closure,
|
|
9183
|
+
* so `opt.type === String` compares like JS function identity. */
|
|
9184
|
+
function primitiveCtorClosure(lowerer, name, loc, dynamicInput) {
|
|
9023
9185
|
const ret = name === "String" ? STRING : name === "Number" ? F64 : BOOL;
|
|
9024
|
-
const
|
|
9025
|
-
|
|
9186
|
+
const input = dynamicInput ? DYN : STRING;
|
|
9187
|
+
const fnT = funcOf([input], ret);
|
|
9188
|
+
const key = `${name}:${dynamicInput ? "dyn" : "string"}`;
|
|
9189
|
+
let fnName = lowerer.primitiveCtorFns.get(key);
|
|
9026
9190
|
if (!fnName) {
|
|
9027
|
-
fnName = `%builtin.${name}`;
|
|
9028
|
-
lowerer.primitiveCtorFns.set(
|
|
9029
|
-
const
|
|
9030
|
-
const value =
|
|
9031
|
-
?
|
|
9032
|
-
|
|
9033
|
-
|
|
9034
|
-
|
|
9191
|
+
fnName = `%builtin.${name}${dynamicInput ? ".dyn" : ""}`;
|
|
9192
|
+
lowerer.primitiveCtorFns.set(key, fnName);
|
|
9193
|
+
const v = { kind: "varRef", localId: "v.0", type: input, loc };
|
|
9194
|
+
const value = dynamicInput
|
|
9195
|
+
? name === "String"
|
|
9196
|
+
? { kind: "libCall", fn: "dyn.toStringCoerce", args: [v], type: STRING, loc }
|
|
9197
|
+
: name === "Number"
|
|
9198
|
+
? { kind: "libCall", fn: "dyn.toNumberCoerce", args: [v], type: F64, loc }
|
|
9199
|
+
: { kind: "dynTest", test: "truthy", value: v, type: BOOL, loc }
|
|
9200
|
+
: name === "String"
|
|
9201
|
+
? v
|
|
9202
|
+
: name === "Number"
|
|
9203
|
+
? { kind: "libCall", fn: "num.fromString", args: [v], type: F64, loc }
|
|
9204
|
+
: { kind: "strEq", negated: true, left: v, right: { kind: "strLit", value: "", type: STRING, loc }, type: BOOL, loc };
|
|
9035
9205
|
const fn = {
|
|
9036
9206
|
name: fnName,
|
|
9037
|
-
params: [{ localId: "v.0", name: "value", type:
|
|
9207
|
+
params: [{ localId: "v.0", name: "value", type: input }],
|
|
9038
9208
|
returnType: ret,
|
|
9039
|
-
locals: [{ id: "v.0", name: "value", type:
|
|
9209
|
+
locals: [{ id: "v.0", name: "value", type: input, mutable: false }],
|
|
9040
9210
|
body: [{ kind: "return", value, loc }],
|
|
9041
9211
|
loc,
|
|
9042
9212
|
};
|