@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
|
@@ -14,20 +14,21 @@ import { lowerClassPrototypeAssign } from "./class-prototypes.js";
|
|
|
14
14
|
import { BYTES_ELEMENT_NAME, BIGINT_T, BOOL, CAUGHT, DYN, F64, JSVAL, NULL_T, STRING, SYMBOL_T, UNDEFINED_T, VOID, arrayOf, canBoxFuncIntoDyn, canConvertToDyn, canDynCheckTo, canMarshalTypedFuncIntoIsland, ffiClassType, ffiSourceParamTypes, funcOf, isDynTypedRefType, isFfiCallbackParam, isFfiContextParam, isFfiReleaseParam, isUnitType, shapeHasAccessorSlots, typeEquals } from "../../ir/ir.js";
|
|
15
15
|
import { isJsSourceFile, isNodeEsmFile, locOf, requireSpecOf } from "../program.js";
|
|
16
16
|
import { genResultRecord, isGenericCallableMemberType, jsOpenObjectType, typeKey } from "../type-mapper.js";
|
|
17
|
-
import { PoisonError, dynFallbackType, dynUndefinedExpr, importCallHandleType, jsFuncNameOf, newFnCtx, nodeThrowExpr, staticImportNamespaceType } from "./lowerer.js";
|
|
18
|
-
import { enforceLibBoundary } from "./lib-boundary.js";
|
|
19
|
-
import { NARROW_FIRST, STRING_INDEX_METHODS, STR_METHODS, builtinFenceHintOf, builtinModuleFnOf } from "./surfaces.js";
|
|
17
|
+
import { PoisonError, dynFallbackType, dynUndefinedExpr, importCallHandleType, jsFuncNameOf, neverTaintedJsType, newFnCtx, nodeThrowExpr, staticImportNamespaceType } from "./lowerer.js";
|
|
18
|
+
import { enforceLibBoundary, lowerSurplusCalls } from "./lib-boundary.js";
|
|
19
|
+
import { NARROW_FIRST, STRING_INDEX_METHODS, STR_METHODS, builtinFenceHintOf, builtinModuleFnOf, stdlibGlobalNameOf } from "./surfaces.js";
|
|
20
20
|
import { ffiBindingDiag, ffiSignatureDiag, libCallbackDiag, requiresDynamicDiag } from "../../diagnostics/diagnostic.js";
|
|
21
21
|
import { mixinFnShapeOf } from "./lower-mixins.js";
|
|
22
|
-
import { dynStringReceiver, lowerArrayConstructor, lowerArrayFromCall, lowerArrayOfCall, lowerDynArrayFilterCall, lowerDynArrayFlatMapCall, lowerGroupByStaticCall, lowerIteratorHelperCall, lowerObjectAssignIndexShape, lowerObjectFromEntriesCall, lowerObjectIterOverIndexShape, lowerTupleReadMethodCall } from "./lower-containers.js";
|
|
22
|
+
import { dynStringReceiver, lowerArrayConstructor, lowerArrayFromCall, lowerArrayOfCall, lowerDynArrayFilterCall, lowerDynArrayFlatMapCall, lowerGroupByStaticCall, lowerIteratorHelperCall, lowerObjectAssignIndexShape, lowerObjectConstructor, lowerObjectFromEntriesCall, lowerObjectIterOverIndexShape, lowerTupleReadMethodCall } from "./lower-containers.js";
|
|
23
23
|
import { lowerBytesStaticCall } from "./containers/bytes.js";
|
|
24
24
|
import { lowerRegexMethodCall, lowerStringIndexCall, lowerStringMethodCall, lowerStringPaddingCall, lowerStringSplitCall } from "./containers/string-and-regexp.js";
|
|
25
|
-
import { createRequireSpecOf, lowerChildStreamMethodCall, lowerChildWriterMethodCall, lowerCreateRequireCall, lowerCryptoHashMethodCall, lowerDirentMethodCall, lowerFileHandleMethodCall, lowerImportMetaResolveCall, lowerNodeModuleCall, lowerPerfHooksCall, lowerProcStreamMethodCall,
|
|
26
|
-
import { lowerAbsenceProbe, lowerPromiseAllTupleCall, lowerPromiseRejectCall, stringWrapperToString, templateRawTextOf } from "./lower-exprs.js";
|
|
25
|
+
import { createRequireSpecOf, lowerChildStreamMethodCall, lowerChildWriterMethodCall, lowerCreateRequireCall, lowerCryptoHashMethodCall, lowerDirentMethodCall, lowerFileHandleMethodCall, lowerImportMetaResolveCall, lowerNodeModuleCall, lowerPerfHooksCall, lowerProcStreamMethodCall, lowerReflectCall, lowerRequireResolveCall, lowerWatcherMethodCall } from "./lower-builtins.js";
|
|
26
|
+
import { lowerAbsenceProbe, lowerPromiseAllTupleCall, lowerPromiseRejectCall, stringWrapperToString, symbolFieldInfo, templateRawTextOf } from "./lower-exprs.js";
|
|
27
27
|
import { isSafeToDiscard } from "./expressions/evaluation-safety.js";
|
|
28
28
|
import { tryLowerExpression } from "./expressions/try-lower-expression.js";
|
|
29
|
+
import { hasRuntimeStatics } from "./class-runtime-statics.js";
|
|
29
30
|
import { httpClientFnBindingOf, isStreamUndefCallExpr, lowerCompatReqStreamOptionalCall, lowerHttpClientFnCall } from "./lower-server.js";
|
|
30
|
-
import { EMITTER_API_MEMBERS, exactInstanceClassOf, findGenericMethodOn, lowerClassGenericMethodCall, lowerStaticMethodCall, returnsOnlyThis } from "./lower-classes.js";
|
|
31
|
+
import { EMITTER_API_MEMBERS, exactClassOfReceiver, exactInstanceClassOf, findGenericMethodOn, lowerClassGenericMethodCall, lowerStaticMethodCall, lowerStaticFieldRead, returnsOnlyThis, storedClassValueType } from "./lower-classes.js";
|
|
31
32
|
import { classCallbackCall, isClassCallback } from "./class-callbacks.js";
|
|
32
33
|
import { emitterRooted, lowerEmitterMethodCall } from "./lower-event-emitter.js";
|
|
33
34
|
import { lowerConsoleInspectArg, lowerFormatCall } from "./lower-inspect.js";
|
|
@@ -43,6 +44,7 @@ import { defaultAfterUndefined, lowerOptionalArgument, lowerStaticallyUndefinedA
|
|
|
43
44
|
import { fenceSymbolFieldCopy } from "./symbol-fields.js";
|
|
44
45
|
import { lowerClassDataDescriptor, lowerClassDescriptorRead } from "./class-descriptors.js";
|
|
45
46
|
import { classStaticDataFor } from "./class-static-data.js";
|
|
47
|
+
import { jsBindingHasOpenWrites } from "./lower-stmts.js";
|
|
46
48
|
export { bodyReadsArguments };
|
|
47
49
|
/** The one func-type projection of completed parameter shapes. Typed rest
|
|
48
50
|
* parameters keep their packed array as the trailing native ABI slot and
|
|
@@ -123,7 +125,21 @@ export const MAX_GENERIC_INSTANCES = 100;
|
|
|
123
125
|
* - `...xs: T[]`: the ABI type is the array; call sites pack the surplus.
|
|
124
126
|
*/
|
|
125
127
|
export function paramShape(lowerer, param) {
|
|
128
|
+
if (param.initializer && isJsSourceFile(param.getSourceFile()) && !param.type &&
|
|
129
|
+
!/@(?:param|type)\b/.test(param.getSourceFile().text.slice(param.parent?.pos ?? param.pos, param.getStart()))) {
|
|
130
|
+
return { type: DYN, mode: "omittable", bodyType: DYN };
|
|
131
|
+
}
|
|
132
|
+
// Inferred JS array patterns describe the bindings, not an exact tuple
|
|
133
|
+
// contract. Consume the actual iterable, including surplus elements.
|
|
134
|
+
if (ts.isArrayBindingPattern(param.name) && isJsSourceFile(param.getSourceFile()) && !param.type &&
|
|
135
|
+
!/@(?:param|type)\b/.test(param.getSourceFile().text.slice(param.parent?.pos ?? param.pos, param.getStart()))) {
|
|
136
|
+
if (param.dotDotDotToken)
|
|
137
|
+
return { type: DYN, mode: "dynRest" };
|
|
138
|
+
return param.initializer ? { type: DYN, mode: "omittable", bodyType: DYN } : { type: DYN, mode: "required" };
|
|
139
|
+
}
|
|
126
140
|
if (lowerer.checkedCallbackParams.has(param)) {
|
|
141
|
+
if (param.dotDotDotToken)
|
|
142
|
+
return { type: DYN, mode: "dynRest" };
|
|
127
143
|
return param.initializer
|
|
128
144
|
? { type: DYN, mode: "omittable", bodyType: DYN }
|
|
129
145
|
: { type: DYN, mode: "required" };
|
|
@@ -207,7 +223,7 @@ export function paramShape(lowerer, param) {
|
|
|
207
223
|
}
|
|
208
224
|
const type = lowerer.runtimeOptionalBindingType(param.name, lowerer.irTypeOf(param.name));
|
|
209
225
|
if (type.kind === "void") {
|
|
210
|
-
|
|
226
|
+
return { type: DYN, mode: param.questionToken ? "omittable" : "required" };
|
|
211
227
|
}
|
|
212
228
|
if (param.questionToken && !lowerer.bareUndefinedArmedUnion(type) && type.kind !== "dyn" && type.kind !== "jsval") {
|
|
213
229
|
// `x?: unknown` where unknown came from an annotation: undefined is
|
|
@@ -624,8 +640,7 @@ leading) {
|
|
|
624
640
|
lowerer.unsupported("SC1090", a, "spread arguments into fixed parameter positions (a spread can only fill a rest parameter)");
|
|
625
641
|
}
|
|
626
642
|
const v = lowerer.lowerExpr(a);
|
|
627
|
-
if (v
|
|
628
|
-
v.kind !== "boolLit" && v.kind !== "varRef" && v.kind !== "closure") {
|
|
643
|
+
if (!isSafeToDiscard(v)) {
|
|
629
644
|
lowerer.unsupported("SC1090", a, "surplus arguments with side effects (JS evaluates surplus arguments to a function without a rest parameter, then drops them; only effect-free surplus arguments compile)");
|
|
630
645
|
}
|
|
631
646
|
}
|
|
@@ -856,7 +871,7 @@ export function appendImplicitUndefinedReturn(lowerer, body, bodyReturn, loc) {
|
|
|
856
871
|
/** A declaration's checker-derived IR return type. The unmappable-type
|
|
857
872
|
* diagnostic points at `blame` (the name for top-level declarations, the
|
|
858
873
|
* whole node for lambda-likes — preserving each caller's historical loc). */
|
|
859
|
-
function hasExplicitJsDocReturn(decl) {
|
|
874
|
+
export function hasExplicitJsDocReturn(decl) {
|
|
860
875
|
const sourceFile = decl.getSourceFile();
|
|
861
876
|
return /@returns?\b/.test(sourceFile.text.slice(decl.pos, decl.getStart(sourceFile)));
|
|
862
877
|
}
|
|
@@ -866,6 +881,16 @@ function promiseCarriesDyn(lowerer, type) {
|
|
|
866
881
|
return type.kind === "union" &&
|
|
867
882
|
(lowerer.unions.get(type.unionId)?.arms.some((arm) => promiseCarriesDyn(lowerer, arm)) ?? false);
|
|
868
883
|
}
|
|
884
|
+
function producesConstructor(lowerer, type) {
|
|
885
|
+
let result = type;
|
|
886
|
+
for (let depth = 0; result && depth < 8; depth++) {
|
|
887
|
+
if (lowerer.checker.getConstructSignatures(result).length > 0)
|
|
888
|
+
return true;
|
|
889
|
+
const signatures = lowerer.checker.getCallSignatures(result);
|
|
890
|
+
result = signatures.length === 1 ? lowerer.checker.getReturnTypeOfSignature(signatures[0]) : undefined;
|
|
891
|
+
}
|
|
892
|
+
return false;
|
|
893
|
+
}
|
|
869
894
|
export function declaredReturnType(lowerer, decl, blame) {
|
|
870
895
|
const sig = lowerer.checker.getSignatureFromDeclaration(decl);
|
|
871
896
|
if (!sig)
|
|
@@ -882,6 +907,8 @@ export function declaredReturnType(lowerer, decl, blame) {
|
|
|
882
907
|
if (retTsType.flags & ts.TypeFlags.Never)
|
|
883
908
|
return VOID;
|
|
884
909
|
const mappedReturn = lowerer.mapTypeOf(retTsType);
|
|
910
|
+
if (isJsSourceFile(decl.getSourceFile()) && mappedReturn?.kind === "array" && mappedReturn.elem.kind === "f64")
|
|
911
|
+
return DYN;
|
|
885
912
|
if (isJsSourceFile(decl.getSourceFile()) && !decl.type && !hasExplicitJsDocReturn(decl) && mappedReturn?.kind === "date")
|
|
886
913
|
return DYN;
|
|
887
914
|
// JS inference assigns Number to arithmetic over any, although the
|
|
@@ -945,9 +972,12 @@ export function declaredReturnType(lowerer, decl, blame) {
|
|
|
945
972
|
// that boundary; their factories keep the native record ABI.
|
|
946
973
|
const asyncReturn = decl.modifiers?.some((modifier) => modifier.kind === ts.SyntaxKind.AsyncKeyword) && mappedReturn?.kind === "promise";
|
|
947
974
|
const recordReturn = asyncReturn ? mappedReturn.inner : mappedReturn;
|
|
975
|
+
const recordArms = recordReturn?.kind === "union" ? lowerer.unions.get(recordReturn.unionId)?.arms : recordReturn ? [recordReturn] : undefined;
|
|
976
|
+
const inferredRecordReturn = recordArms?.some((arm) => arm.kind === "record" || arm.kind === "object") &&
|
|
977
|
+
recordArms.every((arm) => isUnitType(arm) || arm.kind === "record" || arm.kind === "object" && !hasExplicitJsDocReturn(decl));
|
|
948
978
|
if (isJsSourceFile(decl.getSourceFile()) &&
|
|
949
979
|
decl.type === undefined &&
|
|
950
|
-
recordReturn
|
|
980
|
+
recordReturn !== null && recordReturn !== undefined && inferredRecordReturn &&
|
|
951
981
|
lowerer.dynConvertible(recordReturn) &&
|
|
952
982
|
decl.parameters.every((p) => {
|
|
953
983
|
const mt = lowerer.mapTypeOf(lowerer.typeOf(p));
|
|
@@ -1565,6 +1595,7 @@ export function lowerGenericInstance(lowerer, info, inst) {
|
|
|
1565
1595
|
body.push(...lowerer.lowerStmts(bodyBlock.statements));
|
|
1566
1596
|
if (fnCtx.inferReturn) {
|
|
1567
1597
|
bodyReturn = resolveInferredReturn(lowerer, inst, fnCtx.inferReturn, body, decl);
|
|
1598
|
+
inst.returnType = bodyReturn;
|
|
1568
1599
|
}
|
|
1569
1600
|
appendImplicitUndefinedReturn(lowerer, body, bodyReturn, locOf(decl));
|
|
1570
1601
|
}
|
|
@@ -1578,6 +1609,7 @@ export function lowerGenericInstance(lowerer, info, inst) {
|
|
|
1578
1609
|
if (value.type.kind === "void") {
|
|
1579
1610
|
body.push({ kind: "exprStmt", expr: value, loc: locOf(decl.body) });
|
|
1580
1611
|
bodyReturn = resolveInferredReturn(lowerer, inst, fnCtx.inferReturn, body, decl);
|
|
1612
|
+
inst.returnType = bodyReturn;
|
|
1581
1613
|
appendImplicitUndefinedReturn(lowerer, body, bodyReturn, locOf(decl));
|
|
1582
1614
|
}
|
|
1583
1615
|
else {
|
|
@@ -1585,6 +1617,7 @@ export function lowerGenericInstance(lowerer, info, inst) {
|
|
|
1585
1617
|
fnCtx.inferReturn.entries.push({ stmt, node: decl.body });
|
|
1586
1618
|
body.push(stmt);
|
|
1587
1619
|
bodyReturn = resolveInferredReturn(lowerer, inst, fnCtx.inferReturn, body, decl);
|
|
1620
|
+
inst.returnType = bodyReturn;
|
|
1588
1621
|
}
|
|
1589
1622
|
}
|
|
1590
1623
|
else {
|
|
@@ -1639,7 +1672,9 @@ export function lowerGenericInstance(lowerer, info, inst) {
|
|
|
1639
1672
|
* adds JS's undefined; DYN when returns disagree (the checked-dynamic
|
|
1640
1673
|
* result slot — today's shape). Same-key recursion PINNED the fallback
|
|
1641
1674
|
* type mid-lowering (callers already hold it), so a pinned instance
|
|
1642
|
-
* keeps it and the wrap pass coerces every return to the pin.
|
|
1675
|
+
* keeps it and the wrap pass coerces every return to the pin. Callers
|
|
1676
|
+
* store the settled type on their full instance; this narrower view
|
|
1677
|
+
* can be a structural copy in native builds. */
|
|
1643
1678
|
function resolveInferredReturn(lowerer, inst, infer, body, decl) {
|
|
1644
1679
|
// The conservative completion test appendImplicitUndefinedReturn uses:
|
|
1645
1680
|
// a body whose last statement isn't a terminator may complete without
|
|
@@ -1670,14 +1705,13 @@ function resolveInferredReturn(lowerer, inst, infer, body, decl) {
|
|
|
1670
1705
|
else {
|
|
1671
1706
|
final = DYN; // disagreeing returns: the checked-dynamic join
|
|
1672
1707
|
}
|
|
1673
|
-
inst.returnType = final;
|
|
1674
1708
|
}
|
|
1675
1709
|
// The wrap pass: settle every recorded return onto `final`, in place.
|
|
1710
|
+
// Write through the stored union arm: optional-field widening on a
|
|
1711
|
+
// local alias can otherwise introduce a record copy in native builds.
|
|
1676
1712
|
for (const e of infer.entries) {
|
|
1677
1713
|
if (e.stmt.kind !== "return")
|
|
1678
1714
|
continue;
|
|
1679
|
-
// Write through the recorded statement. A narrowed local can acquire a
|
|
1680
|
-
// different record layout and copy it in the native compiler.
|
|
1681
1715
|
const diagsBefore = lowerer.diags.length;
|
|
1682
1716
|
try {
|
|
1683
1717
|
if (e.stmt.value === null || e.stmt.value === undefined) {
|
|
@@ -2076,6 +2110,33 @@ function implicitDeclaredReturn(lowerer, info) {
|
|
|
2076
2110
|
return null;
|
|
2077
2111
|
}
|
|
2078
2112
|
const mapped = lowerer.mapTypeOf(retTs);
|
|
2113
|
+
if (mapped?.kind === "symbol" && !hasExplicitJsDocReturn(info.decl))
|
|
2114
|
+
return null;
|
|
2115
|
+
if (mapped?.kind === "date" && !hasExplicitJsDocReturn(info.decl))
|
|
2116
|
+
return DYN;
|
|
2117
|
+
if (!hasExplicitJsDocReturn(info.decl) && info.decl.body) {
|
|
2118
|
+
let openReturn = false;
|
|
2119
|
+
ts.walkPreorder(info.decl.body, (node) => {
|
|
2120
|
+
if (node !== info.decl.body && ts.isFunctionLike(node))
|
|
2121
|
+
return "skip";
|
|
2122
|
+
if (!ts.isReturnStatement(node) || !node.expression || !ts.isIdentifier(node.expression))
|
|
2123
|
+
return undefined;
|
|
2124
|
+
const symbol = lowerer.resolveValueSymbol(node.expression);
|
|
2125
|
+
if (symbol && lowerer.checker.declarationsOf(symbol).some((decl) => ts.isVariableDeclaration(decl) && jsBindingHasOpenWrites(lowerer, decl)))
|
|
2126
|
+
openReturn = true;
|
|
2127
|
+
return undefined;
|
|
2128
|
+
});
|
|
2129
|
+
if (openReturn)
|
|
2130
|
+
return null;
|
|
2131
|
+
}
|
|
2132
|
+
// A JavaScript result inferred from an initial record can later
|
|
2133
|
+
// carry additional fields. Settle its representation from the
|
|
2134
|
+
// lowered returns instead of copying it back into that initial shape.
|
|
2135
|
+
const resultArms = mapped?.kind === "union" ? lowerer.unions.get(mapped.unionId)?.arms : mapped ? [mapped] : [];
|
|
2136
|
+
if (resultArms?.some((arm) => arm.kind === "record" || arm.kind === "object" || arm.kind === "classval") &&
|
|
2137
|
+
resultArms.every((arm) => isUnitType(arm) || arm.kind === "record" || arm.kind === "object" || arm.kind === "classval") &&
|
|
2138
|
+
!hasExplicitJsDocReturn(info.decl))
|
|
2139
|
+
return null;
|
|
2079
2140
|
// Inferred variadic results carry runtime argument packs. Their
|
|
2080
2141
|
// factory must retain the lowered callable rather than extracting a
|
|
2081
2142
|
// fixed native signature from a checked value.
|
|
@@ -2117,16 +2178,40 @@ function bindableImplicitIr(t) {
|
|
|
2117
2178
|
function storedImplicitArgumentType(lowerer, arg) {
|
|
2118
2179
|
while (ts.isParenthesizedExpression(arg))
|
|
2119
2180
|
arg = arg.expression;
|
|
2181
|
+
if (isJsSourceFile(arg.getSourceFile()) && (ts.isArrowFunction(arg) || ts.isFunctionExpression(arg))) {
|
|
2182
|
+
const saved = lowerer.diagSink;
|
|
2183
|
+
const diagnostics = [];
|
|
2184
|
+
lowerer.diagSink = diagnostics;
|
|
2185
|
+
let value;
|
|
2186
|
+
try {
|
|
2187
|
+
value = tryLowerExpression(lowerer, arg);
|
|
2188
|
+
}
|
|
2189
|
+
finally {
|
|
2190
|
+
lowerer.diagSink = saved;
|
|
2191
|
+
}
|
|
2192
|
+
// Direct inferred helpers can receive native callbacks even when their
|
|
2193
|
+
// result is an opaque handle that cannot cross checked storage.
|
|
2194
|
+
if (diagnostics.length === 0 && value?.type.kind === "func")
|
|
2195
|
+
return value.type;
|
|
2196
|
+
}
|
|
2197
|
+
if (arg.kind === ts.SyntaxKind.ThisKeyword)
|
|
2198
|
+
return lowerer.resolveThis()?.type ?? null;
|
|
2120
2199
|
if (ts.isAwaitExpression(arg)) {
|
|
2121
2200
|
const awaited = storedImplicitArgumentType(lowerer, arg.expression);
|
|
2122
2201
|
return awaited?.kind === "promise" ? awaited.inner : awaited;
|
|
2123
2202
|
}
|
|
2124
|
-
if (ts.isObjectLiteralExpression(arg) && isJsSourceFile(arg.getSourceFile()) &&
|
|
2125
|
-
|
|
2203
|
+
if (ts.isObjectLiteralExpression(arg) && isJsSourceFile(arg.getSourceFile()) &&
|
|
2204
|
+
(arg.properties.length === 0 || arg.properties.some((property) => ts.isMethodDeclaration(property) || ts.isAccessor(property) ||
|
|
2205
|
+
!ts.isSpreadAssignment(property) && property.name !== undefined && ts.isComputedPropertyName(property.name))))
|
|
2126
2206
|
return DYN;
|
|
2127
2207
|
if (ts.isIdentifier(arg))
|
|
2128
2208
|
return lowerer.peekLocal(arg)?.type ?? lowerer.globalOf(arg)?.type ?? null;
|
|
2129
2209
|
if (ts.isCallExpression(arg) && ts.isIdentifier(arg.expression)) {
|
|
2210
|
+
if (isJsSourceFile(arg.getSourceFile())) {
|
|
2211
|
+
const represented = tryLowerExpression(lowerer, arg);
|
|
2212
|
+
if (represented?.type.kind === "dyn" || represented?.type.kind === "func")
|
|
2213
|
+
return represented.type;
|
|
2214
|
+
}
|
|
2130
2215
|
const callee = storedImplicitArgumentType(lowerer, arg.expression);
|
|
2131
2216
|
if (callee?.kind === "dyn")
|
|
2132
2217
|
return DYN;
|
|
@@ -2173,12 +2258,29 @@ export function implicitCallInstance(lowerer, call, info) {
|
|
|
2173
2258
|
shapes.push({ type: stored, mode: "required" });
|
|
2174
2259
|
return;
|
|
2175
2260
|
}
|
|
2261
|
+
if (stored?.kind === "func") {
|
|
2262
|
+
// The lowered closure may have an inferred JS destructuring
|
|
2263
|
+
// parameter widened from the checker's exact tuple to dyn.
|
|
2264
|
+
// Preserve that signature throughout the specialization.
|
|
2265
|
+
const checkerType = lowerer.mapTypeOf(lowerer.typeOf(arg));
|
|
2266
|
+
argTypes.set(sym, checkerType && typeEquals(checkerType, stored)
|
|
2267
|
+
? lowerer.typeOf(arg) : lowerer.checker.getUnknownType());
|
|
2268
|
+
shapes.push({ type: stored, mode: "required" });
|
|
2269
|
+
return;
|
|
2270
|
+
}
|
|
2176
2271
|
// The argument's own checker type, literal-widened ('add' binds
|
|
2177
2272
|
// string) — typeOf consults the ACTIVE instance's bindings, so a
|
|
2178
2273
|
// bound param forwarded into another implicit call transitively
|
|
2179
2274
|
// instantiates it (this._initCommandGroup(command)).
|
|
2180
2275
|
const t = lowerer.checker.getBaseTypeOfLiteralType(lowerer.typeOf(arg));
|
|
2181
|
-
const mapped = lowerer.mapTypeOf(t) ?? dynFallbackType(lowerer, arg, t);
|
|
2276
|
+
const mapped = (neverTaintedJsType(lowerer, arg, t) ? null : lowerer.mapTypeOf(t)) ?? dynFallbackType(lowerer, arg, t);
|
|
2277
|
+
if (isJsSourceFile(arg.getSourceFile()) && ts.isArrayLiteralExpression(arg) && mapped?.kind === "array" &&
|
|
2278
|
+
(mapped.elem.kind === "classval" || mapped.elem.kind === "union" &&
|
|
2279
|
+
lowerer.unions.get(mapped.elem.unionId)?.arms.every((arm) => arm.kind === "classval"))) {
|
|
2280
|
+
argTypes.set(sym, lowerer.checker.getUnknownType());
|
|
2281
|
+
shapes.push({ type: DYN, mode: "required" });
|
|
2282
|
+
return;
|
|
2283
|
+
}
|
|
2182
2284
|
// JavaScript arguments-based callables travel as checked functions.
|
|
2183
2285
|
// Specializing a parameter to the inferred rest signature would
|
|
2184
2286
|
// require extracting a native variadic ABI that the value does not
|
|
@@ -2192,6 +2294,11 @@ export function implicitCallInstance(lowerer, call, info) {
|
|
|
2192
2294
|
// That checker supertype is not an empty-record runtime layout:
|
|
2193
2295
|
// preserve represented arms through the checked boundary instead
|
|
2194
2296
|
// of specializing a call to a union that would discard them.
|
|
2297
|
+
if (isJsSourceFile(arg.getSourceFile()) && mapped?.kind === "func" && !lowerer.dynConvertible(mapped)) {
|
|
2298
|
+
argTypes.set(sym, lowerer.checker.getUnknownType());
|
|
2299
|
+
shapes.push({ type: DYN, mode: "required" });
|
|
2300
|
+
return;
|
|
2301
|
+
}
|
|
2195
2302
|
const mappedArms = mapped?.kind === "union" ? lowerer.unions.get(mapped.unionId)?.arms ?? [] : mapped ? [mapped] : [];
|
|
2196
2303
|
const hasTopObject = mappedArms.some((arm) => {
|
|
2197
2304
|
const shape = arm.kind === "record" ? lowerer.shapes.get(arm.shapeId) : undefined;
|
|
@@ -2737,7 +2844,15 @@ export function lowerTimersMemberCall(lowerer, expr, member, loc) {
|
|
|
2737
2844
|
if (expr.arguments.length !== 1) {
|
|
2738
2845
|
lowerer.noLowering(`clearTimeout with ${expr.arguments.length} arguments`, expr);
|
|
2739
2846
|
}
|
|
2740
|
-
|
|
2847
|
+
let handle = lowerer.lowerExpr(expr.arguments[0]);
|
|
2848
|
+
if (handle.type.kind === "dyn" && isJsSourceFile(expr.getSourceFile())) {
|
|
2849
|
+
const stored = lowerer.declareHiddenLocal("%timer.clear", DYN);
|
|
2850
|
+
const ref = varRef(stored.id, DYN, loc);
|
|
2851
|
+
handle = { kind: "seqExpr", stmts: [{ kind: "varDecl", localId: stored.id, init: handle, loc }], result: {
|
|
2852
|
+
kind: "ternary", cond: { kind: "dynTest", test: "number", value: ref, type: BOOL, loc },
|
|
2853
|
+
then: lowerer.coerceInto(expr.arguments[0], ref, F64), else_: numLit(0, loc), type: F64, loc,
|
|
2854
|
+
}, type: F64, loc };
|
|
2855
|
+
}
|
|
2741
2856
|
if (handle.type.kind !== "f64") {
|
|
2742
2857
|
lowerer.noLowering(`clearTimeout of '${lowerer.fmt(handle.type)}' handles`, expr.arguments[0], "the handle is the Timeout setTimeout returned (narrow 'Timeout | null' first)");
|
|
2743
2858
|
}
|
|
@@ -3264,6 +3379,14 @@ function lowerProjectedBuiltinCall(lowerer, expr, bi, loc) {
|
|
|
3264
3379
|
}
|
|
3265
3380
|
export function lowerCall(lowerer, expr) {
|
|
3266
3381
|
const loc = locOf(expr);
|
|
3382
|
+
// Object's checker return type is `any`. Claim known object inputs
|
|
3383
|
+
// before generic checked-dynamic dispatch tries to load the constructor.
|
|
3384
|
+
if (ts.isIdentifier(expr.expression) && expr.expression.text === "Object" &&
|
|
3385
|
+
lowerer.isStdlibGlobal(expr.expression, "Object")) {
|
|
3386
|
+
const object = lowerObjectConstructor(lowerer, expr.arguments, loc);
|
|
3387
|
+
if (object)
|
|
3388
|
+
return object;
|
|
3389
|
+
}
|
|
3267
3390
|
// A call whose chain ROOTS at an ambient-undefined name (`declare
|
|
3268
3391
|
// const value: Y | undefined; value?.foo("a")`, `declare function
|
|
3269
3392
|
// chain...; chain(o).mapValues(f).value()`, a trap binding's read):
|
|
@@ -3373,7 +3496,7 @@ export function lowerCall(lowerer, expr) {
|
|
|
3373
3496
|
// `a?.m()` (the token on the member access). The handled markers keep
|
|
3374
3497
|
// the chain lowering's re-entrant dispatch from looping.
|
|
3375
3498
|
if ((expr.questionDotToken && !lowerer.chainHandled.has(expr)) ||
|
|
3376
|
-
(ts.isPropertyAccessExpression(expr.expression) &&
|
|
3499
|
+
((ts.isPropertyAccessExpression(expr.expression) || ts.isElementAccessExpression(expr.expression)) &&
|
|
3377
3500
|
expr.expression.questionDotToken &&
|
|
3378
3501
|
!lowerer.chainHandled.has(expr.expression))) {
|
|
3379
3502
|
return lowerer.lowerOptionalChain(expr);
|
|
@@ -3382,6 +3505,9 @@ export function lowerCall(lowerer, expr) {
|
|
|
3382
3505
|
// top-level statement (its field-initializer ordering lives there);
|
|
3383
3506
|
// any other position would misorder initialization — rejected.
|
|
3384
3507
|
if (expr.expression.kind === ts.SyntaxKind.SuperKeyword) {
|
|
3508
|
+
const superCall = lowerer.ctx.superCall;
|
|
3509
|
+
if (superCall)
|
|
3510
|
+
return superCall(expr);
|
|
3385
3511
|
lowerer.unsupported("SC1090", expr, "super() calls anywhere but as a top-level constructor statement");
|
|
3386
3512
|
}
|
|
3387
3513
|
// super.method(...): a DIRECT (never virtual) call of the base chain's
|
|
@@ -3500,6 +3626,13 @@ export function lowerCall(lowerer, expr) {
|
|
|
3500
3626
|
loc,
|
|
3501
3627
|
});
|
|
3502
3628
|
}
|
|
3629
|
+
if (ts.isPropertyAccessExpression(expr.expression) &&
|
|
3630
|
+
TIMER_MODULE_MEMBERS.has(expr.expression.name.text) &&
|
|
3631
|
+
lowerer.stdlibGlobalMember(expr.expression, "globalThis") === expr.expression.name.text) {
|
|
3632
|
+
const served = lowerTimersMemberCall(lowerer, expr, expr.expression.name.text, loc);
|
|
3633
|
+
if (served)
|
|
3634
|
+
return served;
|
|
3635
|
+
}
|
|
3503
3636
|
// The timer globals — setTimeout/clearTimeout, setInterval/
|
|
3504
3637
|
// clearInterval, setImmediate/clearImmediate. Provenance-checked (a
|
|
3505
3638
|
// user function shadowing the name has a different, non-ambient
|
|
@@ -3642,9 +3775,7 @@ export function lowerCall(lowerer, expr) {
|
|
|
3642
3775
|
// Provenance-checked like setTimeout; zero-arg forms are the JS
|
|
3643
3776
|
// constants ("", false, 0). Wrapper objects stay fenced except where
|
|
3644
3777
|
// the receiver is immediately converted by a direct String method call.
|
|
3645
|
-
if (
|
|
3646
|
-
expr.expression.text === "BigInt" &&
|
|
3647
|
-
lowerer.isStdlibSymbol(lowerer.resolveValueSymbol(expr.expression) ?? undefined)) {
|
|
3778
|
+
if (lowerer.isStdlibGlobal(expr.expression, "BigInt")) {
|
|
3648
3779
|
if (expr.arguments.length !== 1) {
|
|
3649
3780
|
lowerer.noLowering(`BigInt with ${expr.arguments.length} arguments`, expr);
|
|
3650
3781
|
}
|
|
@@ -3657,12 +3788,11 @@ export function lowerCall(lowerer, expr) {
|
|
|
3657
3788
|
return converted;
|
|
3658
3789
|
lowerer.noLowering(`BigInt of ${lowerer.fmt(arg.type)} values`, argNode, "string, number, boolean, and bigint arguments are supported");
|
|
3659
3790
|
}
|
|
3660
|
-
if (
|
|
3661
|
-
(expr.expression
|
|
3662
|
-
|
|
3663
|
-
|
|
3664
|
-
|
|
3665
|
-
const name = expr.expression.text;
|
|
3791
|
+
if (lowerer.isStdlibGlobal(expr.expression, "String") ||
|
|
3792
|
+
lowerer.isStdlibGlobal(expr.expression, "Boolean") ||
|
|
3793
|
+
lowerer.isStdlibGlobal(expr.expression, "Number")) {
|
|
3794
|
+
const name = lowerer.isStdlibGlobal(expr.expression, "String") ? "String" :
|
|
3795
|
+
lowerer.isStdlibGlobal(expr.expression, "Boolean") ? "Boolean" : "Number";
|
|
3666
3796
|
if (expr.arguments.length > 1) {
|
|
3667
3797
|
lowerer.noLowering(`${name} with ${expr.arguments.length} arguments`, expr);
|
|
3668
3798
|
}
|
|
@@ -3692,8 +3822,9 @@ export function lowerCall(lowerer, expr) {
|
|
|
3692
3822
|
if (name === "Number")
|
|
3693
3823
|
return lowerNumberConstructorValue(lowerer, argNode, loc);
|
|
3694
3824
|
const arg = lowerer.lowerExpr(argNode);
|
|
3695
|
-
if (name === "String" && arg.type.kind === "dyn"
|
|
3696
|
-
|
|
3825
|
+
if (name === "String" && (arg.type.kind === "dyn" || arg.type.kind === "union" &&
|
|
3826
|
+
lowerer.unions.get(arg.type.unionId)?.arms.some((arm) => arm.kind === "symbol") && lowerer.dynConvertible(arg.type))) {
|
|
3827
|
+
return { kind: "libCall", fn: "dyn.stringConstructor", args: [lowerer.coerceToExpected(arg, DYN)], type: STRING, loc };
|
|
3697
3828
|
}
|
|
3698
3829
|
if (name === "String")
|
|
3699
3830
|
return lowerer.ensureString(arg, argNode);
|
|
@@ -3720,7 +3851,8 @@ export function lowerCall(lowerer, expr) {
|
|
|
3720
3851
|
lowerer.fenceStaticHeadersMember(access, "call");
|
|
3721
3852
|
lowerer.fenceStaticReadableStreamMember(access, "call");
|
|
3722
3853
|
const source = tryLowerExpression(lowerer, access.expression);
|
|
3723
|
-
if (source && (source.type.kind === "dyn" ||
|
|
3854
|
+
if (source && (source.type.kind === "dyn" || source.type.kind === "func" ||
|
|
3855
|
+
(source.type.kind === "map" || source.type.kind === "set") && lowerer.dynConvertible(source.type) || isDynTypedRefType(source.type) &&
|
|
3724
3856
|
lowerer.foldedStringKeyOf(access.argumentExpression) === null &&
|
|
3725
3857
|
lowerer.mapTypeOf(lowerer.typeOf(access.argumentExpression))?.kind !== "symbol")) {
|
|
3726
3858
|
const local = lowerer.declareHiddenLocal("%computedReceiver", DYN);
|
|
@@ -4123,6 +4255,7 @@ export function lowerCall(lowerer, expr) {
|
|
|
4123
4255
|
// string-only argument rule.
|
|
4124
4256
|
if ((expr.expression.text === "encodeURIComponent" ||
|
|
4125
4257
|
expr.expression.text === "encodeURI" ||
|
|
4258
|
+
expr.expression.text === "decodeURI" ||
|
|
4126
4259
|
expr.expression.text === "decodeURIComponent") &&
|
|
4127
4260
|
lowerer.isStdlibSymbol(lowerer.resolveValueSymbol(expr.expression) ?? undefined)) {
|
|
4128
4261
|
const name = expr.expression.text;
|
|
@@ -4131,10 +4264,10 @@ export function lowerCall(lowerer, expr) {
|
|
|
4131
4264
|
}
|
|
4132
4265
|
const loc = locOf(expr);
|
|
4133
4266
|
const argNode = expr.arguments[0];
|
|
4134
|
-
if (name === "decodeURIComponent") {
|
|
4267
|
+
if (name === "decodeURIComponent" || name === "decodeURI") {
|
|
4135
4268
|
const d = optionalCallValue(lowerer, argNode) ?? lowerer.lowerExpr(argNode);
|
|
4136
4269
|
const s = lowerer.ensureString(d, argNode);
|
|
4137
|
-
return { kind: "libCall", fn: "str.decodeUriComponent", args: [s], type: STRING, loc };
|
|
4270
|
+
return { kind: "libCall", fn: name === "decodeURI" ? "str.decodeUri" : "str.decodeUriComponent", args: [s], type: STRING, loc };
|
|
4138
4271
|
}
|
|
4139
4272
|
const value = optionalCallValue(lowerer, argNode) ?? lowerer.lowerExpr(argNode);
|
|
4140
4273
|
const s = lowerer.ensureString(value, argNode);
|
|
@@ -4415,7 +4548,8 @@ export function lowerCall(lowerer, expr) {
|
|
|
4415
4548
|
lowerer.lowerJsonMethodCall(expr, expr.expression) ??
|
|
4416
4549
|
// Reflect.apply of a builtin rest-parameter fn (fixtures.js's
|
|
4417
4550
|
// fixturesPath idiom) — before the stdlib member fence claims it.
|
|
4418
|
-
|
|
4551
|
+
lowerReflectCall(lowerer, expr, expr.expression) ??
|
|
4552
|
+
lowerBigIntStaticCall(lowerer, expr, expr.expression) ??
|
|
4419
4553
|
lowerer.lowerNumberStaticCall(expr, expr.expression) ??
|
|
4420
4554
|
lowerer.lowerDateCall(expr, expr.expression) ??
|
|
4421
4555
|
lowerer.lowerTextCodecCall(expr, expr.expression) ??
|
|
@@ -4487,8 +4621,8 @@ export function lowerCall(lowerer, expr) {
|
|
|
4487
4621
|
// Readable.from — the stream classes' one static (before the
|
|
4488
4622
|
// stdlib chokepoint claims the member).
|
|
4489
4623
|
lowerStreamStaticCall(lowerer, expr, expr.expression) ??
|
|
4490
|
-
//
|
|
4491
|
-
//
|
|
4624
|
+
// Primitive toString calls, including numeric radices, use the
|
|
4625
|
+
// native formatters before the island method path.
|
|
4492
4626
|
lowerNumberToStringCall(lowerer, expr, expr.expression) ??
|
|
4493
4627
|
// Union receivers whose every arm has a text — the ngrok
|
|
4494
4628
|
// `(chunk: Buffer | string) => chunk.toString()` idiom.
|
|
@@ -4528,7 +4662,6 @@ export function lowerCall(lowerer, expr) {
|
|
|
4528
4662
|
// by the receiver's own element.
|
|
4529
4663
|
lowerer.lowerFilterNarrowCall(expr, expr.expression) ??
|
|
4530
4664
|
lowerArrayIsArrayCall(lowerer, expr, expr.expression) ??
|
|
4531
|
-
lowerBigIntStaticCall(lowerer, expr, expr.expression) ??
|
|
4532
4665
|
lowerBigIntMethodCall(lowerer, expr, expr.expression) ??
|
|
4533
4666
|
lowerSymbolStaticCall(lowerer, expr, expr.expression) ??
|
|
4534
4667
|
lowerSymbolMethodCall(lowerer, expr, expr.expression) ??
|
|
@@ -4563,6 +4696,13 @@ export function lowerCall(lowerer, expr) {
|
|
|
4563
4696
|
lowerObjLitGenericMethodCall(lowerer, expr, expr.expression);
|
|
4564
4697
|
if (intrinsic)
|
|
4565
4698
|
return intrinsic;
|
|
4699
|
+
if (isJsSourceFile(expr.getSourceFile())) {
|
|
4700
|
+
const staticField = lowerStaticFieldRead(lowerer, expr.expression);
|
|
4701
|
+
if (staticField?.type.kind === "dyn" && !expr.arguments.some(ts.isSpreadElement)) {
|
|
4702
|
+
return { kind: "dynCall", callee: staticField, receiver: lowerer.lowerExprExpecting(expr.expression.expression, DYN), calleeName: expr.expression.getText(),
|
|
4703
|
+
args: expr.arguments.map((arg) => lowerer.lowerExprExpecting(arg, DYN)), type: DYN, loc: locOf(expr) };
|
|
4704
|
+
}
|
|
4705
|
+
}
|
|
4566
4706
|
const accessorTarget = lowerer.fieldTarget(expr.expression);
|
|
4567
4707
|
if (accessorTarget?.container === "accessor") {
|
|
4568
4708
|
const callee = lowerer.fieldGetExpr(accessorTarget, locOf(expr.expression), expr.expression);
|
|
@@ -4635,6 +4775,30 @@ export function lowerCall(lowerer, expr) {
|
|
|
4635
4775
|
lowerer.fenceStaticHeadersMember(expr.expression, "call");
|
|
4636
4776
|
lowerer.fenceStaticReadableStreamMember(expr.expression, "call");
|
|
4637
4777
|
}
|
|
4778
|
+
// Computed native members retain their original receiver and resolve
|
|
4779
|
+
// the function before argument effects, just like dotted calls.
|
|
4780
|
+
if (ts.isElementAccessExpression(expr.expression) && !expr.expression.questionDotToken && !expr.questionDotToken &&
|
|
4781
|
+
!symbolFieldInfo(lowerer, expr.expression)) {
|
|
4782
|
+
const access = expr.expression;
|
|
4783
|
+
const value = tryLowerExpression(lowerer, access.expression);
|
|
4784
|
+
if (value?.type.kind === "dyn" || value?.type.kind === "generator" ||
|
|
4785
|
+
value && ["array", "bytes", "map", "set"].includes(value.type.kind) && lowerer.dynConvertible(value.type) ||
|
|
4786
|
+
value?.type.kind === "string" && !ts.isStringLiteralLike(access.argumentExpression) && lowerer.dynConvertible(value.type) ||
|
|
4787
|
+
value?.type.kind === "object" && !lowerer.classes.get(value.type.className)?.def.runtime) {
|
|
4788
|
+
const local = lowerer.declareHiddenLocal("%computedReceiver", value.type);
|
|
4789
|
+
const reference = { kind: "varRef", localId: local.id, type: value.type, loc };
|
|
4790
|
+
const receiver = lowerer.coerceToExpected(reference, DYN);
|
|
4791
|
+
const raw = lowerer.lowerExpr(access.argumentExpression);
|
|
4792
|
+
const key = raw.type.kind === "string" ? raw : lowerer.coerceInto(access.argumentExpression, raw, DYN);
|
|
4793
|
+
const callee = { kind: "dynKeyGet", value: receiver, key, type: DYN, loc };
|
|
4794
|
+
const spread = expr.arguments.some(ts.isSpreadElement) ? lowerSpreadArgsCall(lowerer, expr, callee, loc) : null;
|
|
4795
|
+
if (spread && spread.kind !== "dynCall")
|
|
4796
|
+
lowerer.unsupported("SC1090", expr, "computed native method spread arguments");
|
|
4797
|
+
const result = spread !== null ? { ...spread, receiver } : { kind: "dynCall", callee, receiver,
|
|
4798
|
+
calleeName: access.getText(), args: expr.arguments.map((arg) => lowerer.lowerExprExpecting(arg, DYN)), type: DYN, loc };
|
|
4799
|
+
return { kind: "seqExpr", stmts: [{ kind: "varDecl", localId: local.id, init: value, loc }], result, type: DYN, loc };
|
|
4800
|
+
}
|
|
4801
|
+
}
|
|
4638
4802
|
// The ELEMENT spelling of a primitive method call — `x['toString']()`,
|
|
4639
4803
|
// `s['charAt'](0)`: JS resolves it exactly like the dot form, so the
|
|
4640
4804
|
// literal-keyed shapes with a static lowering route there before the
|
|
@@ -4720,6 +4884,11 @@ export function lowerCall(lowerer, expr) {
|
|
|
4720
4884
|
: "value";
|
|
4721
4885
|
return { kind: "dynCall", callee, calleeName, args, type: DYN, loc };
|
|
4722
4886
|
}
|
|
4887
|
+
if (callee.type.kind === "union" && lowerer.dynConvertible(callee.type) &&
|
|
4888
|
+
lowerer.unions.get(callee.type.unionId)?.arms.some((arm) => arm.kind === "func")) {
|
|
4889
|
+
return { kind: "dynCall", callee: lowerer.coerceToExpected(callee, DYN), calleeName: expr.expression.getText(),
|
|
4890
|
+
args: expr.arguments.map((arg) => lowerer.lowerExprExpecting(arg, DYN)), type: DYN, loc };
|
|
4891
|
+
}
|
|
4723
4892
|
if (callee.type.kind !== "func") {
|
|
4724
4893
|
lowerer.badType(expr.expression, lowerer.typeOf(expr.expression));
|
|
4725
4894
|
}
|
|
@@ -4959,6 +5128,10 @@ function lowerNumberConstructorValue(lowerer, argNode, loc) {
|
|
|
4959
5128
|
return { kind: "libCall", fn: "num.fromString", args: [arg], type: F64, loc };
|
|
4960
5129
|
if (arg.type.kind === "dyn")
|
|
4961
5130
|
return { kind: "libCall", fn: "dyn.numberConstructor", args: [arg], type: F64, loc };
|
|
5131
|
+
if (arg.type.kind === "union" && lowerer.dynConvertible(arg.type))
|
|
5132
|
+
return {
|
|
5133
|
+
kind: "libCall", fn: "dyn.numberConstructor", args: [lowerer.coerceToExpected(arg, DYN)], type: F64, loc,
|
|
5134
|
+
};
|
|
4962
5135
|
const optionalNumber = lowerOptionalStringNumber(lowerer, arg, loc);
|
|
4963
5136
|
if (optionalNumber)
|
|
4964
5137
|
return optionalNumber;
|
|
@@ -4973,6 +5146,8 @@ function lowerNumberConstructorValue(lowerer, argNode, loc) {
|
|
|
4973
5146
|
* checker guard. Dispatch BigInt by the actual value, including nullish
|
|
4974
5147
|
* TypeErrors, rather than interpreting that storage as the narrowed arm. */
|
|
4975
5148
|
function lowerBigIntConstructorValue(lowerer, arg, loc) {
|
|
5149
|
+
if (arg.type.kind === "dyn")
|
|
5150
|
+
return { kind: "libCall", fn: "dyn.bigintConstructor", args: [arg], type: BIGINT_T, loc };
|
|
4976
5151
|
if (arg.type.kind === "bigint")
|
|
4977
5152
|
return arg;
|
|
4978
5153
|
if (arg.type.kind === "string")
|
|
@@ -5244,8 +5419,9 @@ function lowerObjectOwnCall(lowerer, call, receiverNode, keyNode, extraNodes, me
|
|
|
5244
5419
|
stmts.push({ kind: "exprStmt", expr: effect, loc: locOf(extra) });
|
|
5245
5420
|
}
|
|
5246
5421
|
let key = keyRef;
|
|
5247
|
-
if (receiverRef.type.kind === "
|
|
5248
|
-
|
|
5422
|
+
if (lowerer.dynConvertible(receiverRef.type) && keyRef && (receiverRef.type.kind === "object" || keyRef.type.kind === "symbol" || keyRef.type.kind === "dyn" ||
|
|
5423
|
+
keyRef.type.kind === "union" && lowerer.dynConvertible(keyRef.type))) {
|
|
5424
|
+
const result = { kind: "libCall", fn: enumerable ? "dyn.propertyIsEnumerableComputed" : "dyn.hasOwnComputed", args: [lowerer.coerceToExpected(receiverRef, DYN), lowerer.coerceToExpected(keyRef, DYN)], type: BOOL, loc };
|
|
5249
5425
|
return { kind: "seqExpr", stmts, result, type: BOOL, loc };
|
|
5250
5426
|
}
|
|
5251
5427
|
if (!keyNode || rawKey?.type.kind === "undefinedT" || rawKey?.type.kind === "void") {
|
|
@@ -5441,6 +5617,9 @@ function lowerStringPrototypeCall(lowerer, call, access) {
|
|
|
5441
5617
|
// padding uses a helper that delays conversion until every argument is ready.
|
|
5442
5618
|
const objectWithoutMethodArgs = entry?.maxArgs === 0 && call.arguments.length === 1 &&
|
|
5443
5619
|
(receiverType.kind === "record" || receiverType.kind === "array" || receiverType.kind === "object");
|
|
5620
|
+
if (padding && !scalar && lowerer.dynConvertible(receiverType)) {
|
|
5621
|
+
return lowerStringPaddingCall(lowerer, call, entry.method, lowerer.coerceToExpected(receiverValue, DYN), receiverNode, call.arguments.slice(1));
|
|
5622
|
+
}
|
|
5444
5623
|
if (!scalar && !objectWithoutMethodArgs) {
|
|
5445
5624
|
lowerer.noLowering(`String.prototype.${methodAccess.name.text}.call with ${lowerer.fmt(receiverType)} receivers`, call);
|
|
5446
5625
|
}
|
|
@@ -5677,7 +5856,7 @@ function lowerDynReceiverMethodCall(lowerer, call, access) {
|
|
|
5677
5856
|
// tsc types the return by the evolved shape, the binding lowered
|
|
5678
5857
|
// dyn): probe the lowering and claim exactly the dyn results.
|
|
5679
5858
|
const probed = tryLowerExpression(lowerer, access.expression);
|
|
5680
|
-
if (
|
|
5859
|
+
if (probed?.type.kind === "func" && stdlibGlobalNameOf(lowerer, access.expression) === null &&
|
|
5681
5860
|
!["call", "apply", "bind", "toString", "valueOf", "constructor"].includes(access.name.text) &&
|
|
5682
5861
|
canBoxFuncIntoDyn(probed.type, (id) => lowerer.shapes.get(id), (id) => lowerer.unions.get(id))) {
|
|
5683
5862
|
const loc = locOf(call);
|
|
@@ -5698,10 +5877,22 @@ function lowerDynReceiverMethodCall(lowerer, call, access) {
|
|
|
5698
5877
|
args: call.arguments.map((arg) => lowerer.lowerExprExpecting(arg, DYN)), type: DYN, loc }, type: DYN, loc,
|
|
5699
5878
|
};
|
|
5700
5879
|
}
|
|
5880
|
+
if (probed?.type.kind === "classval") {
|
|
5881
|
+
const info = lowerer.classes.get(probed.type.className);
|
|
5882
|
+
if (info && (info.callableBase || hasRuntimeStatics(info)))
|
|
5883
|
+
return lowerStaticMethodCall(lowerer, call, access);
|
|
5884
|
+
}
|
|
5701
5885
|
if (probed?.type.kind !== "dyn")
|
|
5702
5886
|
return null;
|
|
5703
5887
|
recv = probed;
|
|
5704
5888
|
}
|
|
5889
|
+
// A factory may return a constructor more precise than its inferred
|
|
5890
|
+
// checker result. Runtime static members live on that constructor.
|
|
5891
|
+
if (recv.type.kind === "classval") {
|
|
5892
|
+
const info = lowerer.classes.get(recv.type.className);
|
|
5893
|
+
if (info && (info.callableBase || hasRuntimeStatics(info)))
|
|
5894
|
+
return lowerStaticMethodCall(lowerer, call, access);
|
|
5895
|
+
}
|
|
5705
5896
|
// A checker-`any` receiver that already lowered to a real STRING (the
|
|
5706
5897
|
// chained form — `cfg.host.trim().toLowerCase()`, where the first step
|
|
5707
5898
|
// extracted): no validation needed, ride the string tables directly.
|
|
@@ -5770,7 +5961,13 @@ function lowerDynReceiverMethodCall(lowerer, call, access) {
|
|
|
5770
5961
|
// unimplemented methods throw a LOUD not-supported Error; names the
|
|
5771
5962
|
// kind's prototype lacks throw Node's "x.y is not a function"; OBJ
|
|
5772
5963
|
// receivers call the own member.
|
|
5773
|
-
|
|
5964
|
+
// A stored callback must be read before argument effects, and called
|
|
5965
|
+
// with the original receiver rather than a materialized property view.
|
|
5966
|
+
const callbackProperty = (() => {
|
|
5967
|
+
const prop = lowerer.checker.getPropertyOfType(recvTs, access.name.text);
|
|
5968
|
+
return prop !== undefined && lowerer.checker.declarationsOf(prop).some((decl) => ts.isPropertyDeclaration(decl) || ts.isPropertySignature(decl));
|
|
5969
|
+
})();
|
|
5970
|
+
const dispatched = callbackProperty ? null : lowerDynDispatchMethodCall(lowerer, call, access, recv, arrayReceiver);
|
|
5774
5971
|
if (dispatched)
|
|
5775
5972
|
return dispatched;
|
|
5776
5973
|
// Names NO dyn-representable prototype declares: the member can only
|
|
@@ -5796,9 +5993,6 @@ function lowerDynReceiverMethodCall(lowerer, call, access) {
|
|
|
5796
5993
|
if (call.questionDotToken || access.questionDotToken)
|
|
5797
5994
|
return null;
|
|
5798
5995
|
const loc = locOf(call);
|
|
5799
|
-
if (call.arguments.some((a) => ts.isSpreadElement(a))) {
|
|
5800
|
-
lowerer.unsupported("SC1090", call, "spread arguments in calls through 'unknown' values");
|
|
5801
|
-
}
|
|
5802
5996
|
const receiverLocal = lowerer.declareHiddenLocal("%dynCallReceiver", DYN);
|
|
5803
5997
|
const receiver = { kind: "varRef", localId: receiverLocal.id, type: DYN, loc };
|
|
5804
5998
|
const member = {
|
|
@@ -5808,6 +6002,14 @@ function lowerDynReceiverMethodCall(lowerer, call, access) {
|
|
|
5808
6002
|
type: DYN,
|
|
5809
6003
|
loc: locOf(access),
|
|
5810
6004
|
};
|
|
6005
|
+
if (call.arguments.some(ts.isSpreadElement)) {
|
|
6006
|
+
const spread = lowerSpreadArgsCall(lowerer, call, member, loc);
|
|
6007
|
+
if (spread?.kind === "dynCall")
|
|
6008
|
+
return { kind: "seqExpr",
|
|
6009
|
+
stmts: [{ kind: "varDecl", localId: receiverLocal.id, init: recv, loc }],
|
|
6010
|
+
result: { ...spread, receiver }, type: DYN, loc };
|
|
6011
|
+
lowerer.unsupported("SC1090", call, "spread arguments in calls through 'unknown' values");
|
|
6012
|
+
}
|
|
5811
6013
|
const args = call.arguments.map((a) => lowerer.lowerExprExpecting(a, DYN));
|
|
5812
6014
|
return {
|
|
5813
6015
|
kind: "seqExpr", stmts: [{ kind: "varDecl", localId: receiverLocal.id, init: recv, loc }],
|
|
@@ -5858,7 +6060,7 @@ const DYN_DISPATCH_METHODS = new Set([
|
|
|
5858
6060
|
"setEncoding", "setDefaultEncoding", "setTimeout", "read", "isPaused",
|
|
5859
6061
|
"writeHead", "setHeader", "getHeader", "hasHeader", "removeHeader",
|
|
5860
6062
|
"getHeaders", "getHeaderNames", "appendHeader", "flushHeaders",
|
|
5861
|
-
"add", "append", "delete", "get", "getSetCookie", "has", "set",
|
|
6063
|
+
"add", "append", "delete", "get", "getSetCookie", "has", "set", "clear", "keys", "values", "entries", "next",
|
|
5862
6064
|
"writeContinue", "writeEarlyHints", "cork", "uncork", "addTrailers",
|
|
5863
6065
|
"ref", "unref", "address", "setNoDelay", "setKeepAlive", "connect",
|
|
5864
6066
|
"resetAndDestroy", "destroySoon",
|
|
@@ -5879,7 +6081,7 @@ const DYN_DISPATCH_METHODS = new Set([
|
|
|
5879
6081
|
"dispatchEvent",
|
|
5880
6082
|
"preventDefault", "stopPropagation", "stopImmediatePropagation",
|
|
5881
6083
|
"composedPath",
|
|
5882
|
-
"json", "text", "bytes",
|
|
6084
|
+
"json", "text", "bytes", "arrayBuffer",
|
|
5883
6085
|
// Promise.prototype (SCR_DYN_PROMISE receivers): the reaction trio
|
|
5884
6086
|
// rides the fiber machinery (scr_dyn_promise_then); on every other dyn
|
|
5885
6087
|
// kind then/catch/finally answer the stored-member path (OBJ own
|
|
@@ -5899,6 +6101,17 @@ export function lowerDynDispatchMethodCall(lowerer, call, access, recv, arrayRec
|
|
|
5899
6101
|
if ((!DYN_DISPATCH_METHODS.has(method) && !isJsSourceFile(call.getSourceFile())) || lowerer.chainBlocked(call, access))
|
|
5900
6102
|
return null;
|
|
5901
6103
|
if (call.arguments.some((arg) => ts.isSpreadElement(arg))) {
|
|
6104
|
+
const loc = locOf(call);
|
|
6105
|
+
const local = lowerer.declareHiddenLocal("%spreadReceiver", DYN);
|
|
6106
|
+
const receiver = varRef(local.id, DYN, loc);
|
|
6107
|
+
const callee = { kind: "dynKeyGet", value: receiver,
|
|
6108
|
+
key: { kind: "strLit", value: method, type: STRING, loc }, type: DYN, loc };
|
|
6109
|
+
const spread = lowerSpreadArgsCall(lowerer, call, callee, loc);
|
|
6110
|
+
if (spread?.kind === "dynCall")
|
|
6111
|
+
return { kind: "seqExpr",
|
|
6112
|
+
stmts: [{ kind: "varDecl", localId: local.id, init: recv, loc },
|
|
6113
|
+
{ kind: "exprStmt", expr: { kind: "libCall", fn: "dyn.arrayPrototype", args: [], type: DYN, loc }, loc }],
|
|
6114
|
+
result: { ...spread, receiver }, type: DYN, loc };
|
|
5902
6115
|
lowerer.unsupported("SC1090", call, "spread arguments in calls through 'unknown' values");
|
|
5903
6116
|
}
|
|
5904
6117
|
const predicate = method === "filter" && call.arguments[0]
|
|
@@ -5972,7 +6185,12 @@ export function lowerDynDispatchMethodCall(lowerer, call, access, recv, arrayRec
|
|
|
5972
6185
|
}
|
|
5973
6186
|
}
|
|
5974
6187
|
}
|
|
5975
|
-
const args = call.arguments.map((arg, i) =>
|
|
6188
|
+
const args = call.arguments.map((arg, i) => {
|
|
6189
|
+
if (i === 0 && predicate)
|
|
6190
|
+
return lowerer.coerceInto(arg, predicate, DYN);
|
|
6191
|
+
const undefinedArg = lowerStaticallyUndefinedArgument(lowerer, arg);
|
|
6192
|
+
return undefinedArg ? defaultAfterUndefined(undefinedArg, dynUndefinedExpr(locOf(arg))) : lowerer.lowerExprExpecting(arg, DYN);
|
|
6193
|
+
});
|
|
5976
6194
|
return {
|
|
5977
6195
|
kind: "dynInvoke",
|
|
5978
6196
|
recv,
|
|
@@ -6098,13 +6316,13 @@ function lowerCaughtPredicateCall(lowerer, call, caughtLocal) {
|
|
|
6098
6316
|
* and String(n) lower to (Number::toString with radix 10 IS that
|
|
6099
6317
|
* conversion, per spec) — booleans the "true"/"false" texts, and strings
|
|
6100
6318
|
* the identity read (String.prototype.toString returns `this`). The
|
|
6101
|
-
* explicit-radix number form
|
|
6319
|
+
* explicit-radix number form uses the native radix formatter;
|
|
6102
6320
|
* null for other receivers, argument shapes, or non-lib members (a
|
|
6103
6321
|
* user's own `.toString` takes the ordinary paths). */
|
|
6104
6322
|
function lowerNumberToStringCall(lowerer, call, access) {
|
|
6105
6323
|
if (lowerer.chainBlocked(call, access))
|
|
6106
6324
|
return null;
|
|
6107
|
-
if (access.name.text !== "toString" || call.arguments.length
|
|
6325
|
+
if (access.name.text !== "toString" || call.arguments.length > 1 || call.arguments.some(ts.isSpreadElement))
|
|
6108
6326
|
return null;
|
|
6109
6327
|
const recvKind = lowerer.mapTypeOf(lowerer.typeOf(access.expression))?.kind;
|
|
6110
6328
|
if (recvKind !== "f64" && recvKind !== "bool" && recvKind !== "string")
|
|
@@ -6112,6 +6330,22 @@ function lowerNumberToStringCall(lowerer, call, access) {
|
|
|
6112
6330
|
if (!lowerer.isStdlibMember(access))
|
|
6113
6331
|
return null;
|
|
6114
6332
|
const operand = lowerer.lowerExpr(access.expression);
|
|
6333
|
+
// JavaScript array and typed-array reads can still be undefined even
|
|
6334
|
+
// when the checker declares a number. Preserve that runtime value and
|
|
6335
|
+
// let native method dispatch format numbers or throw for missing data.
|
|
6336
|
+
if (operand.type.kind === "dyn") {
|
|
6337
|
+
return {
|
|
6338
|
+
kind: "libCall", fn: "dyn.toString", args: [operand,
|
|
6339
|
+
call.arguments[0] ? lowerer.lowerExprExpecting(call.arguments[0], DYN) : dynUndefinedExpr(locOf(call)),
|
|
6340
|
+
{ kind: "strLit", value: access.getText(), type: STRING, loc: locOf(call) },
|
|
6341
|
+
], type: STRING, loc: locOf(call),
|
|
6342
|
+
};
|
|
6343
|
+
}
|
|
6344
|
+
if (call.arguments.length === 1) {
|
|
6345
|
+
if (operand.type.kind !== "f64")
|
|
6346
|
+
return null;
|
|
6347
|
+
return { kind: "libCall", fn: "num.toStringRadix", args: [operand, lowerer.lowerExprExpecting(call.arguments[0], DYN)], type: STRING, loc: locOf(call) };
|
|
6348
|
+
}
|
|
6115
6349
|
if (operand.type.kind === "string")
|
|
6116
6350
|
return operand; // identity, receiver evaluated
|
|
6117
6351
|
if (operand.type.kind !== "f64" && operand.type.kind !== "bool")
|
|
@@ -6574,15 +6808,14 @@ function templateEscapesValid(raw) {
|
|
|
6574
6808
|
* maps to string[] (type-mapper.ts), so the array rides the ordinary
|
|
6575
6809
|
* slot-directed coercion into whatever the tag's first parameter wants
|
|
6576
6810
|
* — string[] exactly, an `any` slot through the dyn boundary, a rest
|
|
6577
|
-
* pack's first element.
|
|
6578
|
-
*
|
|
6579
|
-
*
|
|
6811
|
+
* pack's first element. Checked tags receive frozen cooked and raw
|
|
6812
|
+
* arrays with the standard nonenumerable `.raw` descriptor. Typed direct
|
|
6813
|
+
* tags retain the string-array representation.
|
|
6580
6814
|
*
|
|
6581
6815
|
* Tag forms: a top-level declared function (the direct-call fast path —
|
|
6582
6816
|
* overload sets reconcile through the resolved signature exactly like
|
|
6583
6817
|
* plain calls), an island value under --dynamic (engine method/function
|
|
6584
|
-
* call
|
|
6585
|
-
* `.raw` there answers undefined where Node carries the raw spans), and
|
|
6818
|
+
* call with the engine's cooked/raw template object), and
|
|
6586
6819
|
* a checked-dynamic value (the dynCall boundary — a non-function tag
|
|
6587
6820
|
* throws Node's catchable TypeError). Everything else — generic tags,
|
|
6588
6821
|
* method tags, function-value bindings — fences by name. */
|
|
@@ -6642,10 +6875,11 @@ export function lowerTaggedTemplate(lowerer, expr) {
|
|
|
6642
6875
|
if (ts.isIdentifier(expr.tag) && !lowerer.isSelfReference(expr.tag)) {
|
|
6643
6876
|
if (lowerer.isTopLevelFnSymbol(expr.tag) && !lowerer.peekLocal(expr.tag)) {
|
|
6644
6877
|
fenceEarlyAliasUse(lowerer, expr.tag, expr);
|
|
6645
|
-
|
|
6878
|
+
const genericTag = lowerer.genericFnOf(expr.tag);
|
|
6879
|
+
if (genericTag && !genericTag.implicitParams) {
|
|
6646
6880
|
lowerer.unsupported("SC1090", expr, "tagged templates with generic tag functions");
|
|
6647
6881
|
}
|
|
6648
|
-
const sig = lowerer.fnSigOf(expr.tag);
|
|
6882
|
+
const sig = genericTag ? null : lowerer.fnSigOf(expr.tag);
|
|
6649
6883
|
if (sig) {
|
|
6650
6884
|
lowerer.noteEdge(sig.name);
|
|
6651
6885
|
const args = completeArgs(lowerer, values, sig.params, loc, expr, [strings()]);
|
|
@@ -6672,10 +6906,13 @@ export function lowerTaggedTemplate(lowerer, expr) {
|
|
|
6672
6906
|
// Checked-dynamic tags (`var f: any; f\`abc\``, dyn property chains):
|
|
6673
6907
|
// the dynCall boundary — arguments convert into dyn, a non-function
|
|
6674
6908
|
// tag throws Node's catchable "<name> is not a function" TypeError.
|
|
6675
|
-
|
|
6909
|
+
let callee = lowerer.lowerExpr(expr.tag);
|
|
6910
|
+
if (callee.type.kind === "func" && isJsSourceFile(expr.getSourceFile()) && lowerer.dynConvertible(callee.type)) {
|
|
6911
|
+
callee = { kind: "dynFrom", value: callee, type: DYN, loc };
|
|
6912
|
+
}
|
|
6676
6913
|
if (callee.type.kind === "dyn") {
|
|
6677
6914
|
const args = [
|
|
6678
|
-
lowerer
|
|
6915
|
+
loweredTemplateStrings(lowerer, expr, pieces.map((piece) => piece.text), loc, pieces.map(templateRawTextOf)),
|
|
6679
6916
|
...values.map((a) => lowerer.lowerExprExpecting(a, DYN)),
|
|
6680
6917
|
];
|
|
6681
6918
|
const calleeName = ts.isPropertyAccessExpression(expr.tag) || ts.isElementAccessExpression(expr.tag)
|
|
@@ -6687,12 +6924,15 @@ export function lowerTaggedTemplate(lowerer, expr) {
|
|
|
6687
6924
|
}
|
|
6688
6925
|
lowerer.unsupported("SC1090", expr, "tagged templates with this tag form (top-level functions and dynamic values tag; call the function directly otherwise)");
|
|
6689
6926
|
}
|
|
6690
|
-
function loweredTemplateStrings(lowerer, expr, cooked, loc) {
|
|
6927
|
+
function loweredTemplateStrings(lowerer, expr, cooked, loc, raw) {
|
|
6691
6928
|
// Normal runtime construction keeps this array aligned with the current
|
|
6692
6929
|
// ScrArr layout in the backend. The old static-header IR node encoded the
|
|
6693
6930
|
// pre-sparse layout in LLVM and crashed as soon as a tag read its strings.
|
|
6694
|
-
const type = arrayOf(STRING);
|
|
6695
|
-
const
|
|
6931
|
+
const type = raw ? DYN : arrayOf(STRING);
|
|
6932
|
+
const array = (values) => ({ kind: "dynArrLit", elems: values.map((value) => ({ kind: "dynFrom", value: { kind: "strLit", value, type: STRING, loc }, type: DYN, loc })), type: DYN, loc });
|
|
6933
|
+
const freeze = (value) => ({ kind: "libCall", fn: "dyn.freeze", args: [value], type: DYN, loc });
|
|
6934
|
+
const checked = raw ? freeze({ kind: "libCall", fn: "dyn.defineProperty", args: [array(cooked), { kind: "dynFrom", value: { kind: "strLit", value: "raw", type: STRING, loc }, type: DYN, loc }, { kind: "dynObjLit", fields: [{ key: { kind: "strLit", value: "value", type: STRING, loc }, value: freeze(array(raw)) }], type: DYN, loc }], type: DYN, loc }) : null;
|
|
6935
|
+
const key = `templateStringsGlobal:${loc.file}:${expr.template.getStart()}:${raw ? "checked" : "typed"}`;
|
|
6696
6936
|
let getter = lowerer.widthHelpers.get(key);
|
|
6697
6937
|
if (!getter) {
|
|
6698
6938
|
const site = lowerer.globalsList.length;
|
|
@@ -6714,7 +6954,7 @@ function loweredTemplateStrings(lowerer, expr, cooked, loc) {
|
|
|
6714
6954
|
{
|
|
6715
6955
|
kind: "assign",
|
|
6716
6956
|
localId: globalId,
|
|
6717
|
-
value: {
|
|
6957
|
+
value: checked ?? {
|
|
6718
6958
|
kind: "arrayLit",
|
|
6719
6959
|
elems: cooked.map((value) => ({ kind: "strLit", value, type: STRING, loc })),
|
|
6720
6960
|
type,
|
|
@@ -6819,6 +7059,23 @@ export function lambdaSignature(lowerer, node) {
|
|
|
6819
7059
|
: "generic arrow/function expressions outside a never-reassigned module-scope binding (only `const f = <T>(x: T) => ...` bindings and top-level generic function declarations monomorphize)");
|
|
6820
7060
|
}
|
|
6821
7061
|
const shapes = lowerer.paramShapes(node.parameters);
|
|
7062
|
+
// Error-first callbacks captured by native filesystem adapters receive
|
|
7063
|
+
// the selected runtime overload. Ambient contextual inference can pick
|
|
7064
|
+
// the string overload even when options request a Buffer.
|
|
7065
|
+
if ((ts.isArrowFunction(node) || ts.isFunctionExpression(node)) && ts.isCallExpression(node.parent) &&
|
|
7066
|
+
node.parent.arguments.at(-1) === node) {
|
|
7067
|
+
const builtin = ts.isPropertyAccessExpression(node.parent.expression) ? lowerer.builtinMemberOf(node.parent.expression)
|
|
7068
|
+
: ts.isIdentifier(node.parent.expression) ? lowerer.builtinImportOf(node.parent.expression) : null;
|
|
7069
|
+
if (builtin?.module === "fs" && builtin.member !== "rename" && builtinModuleFnOf(lowerer, builtin.module, builtin.member)?.fn === "fs.callbackCall") {
|
|
7070
|
+
for (let index = 0; index < shapes.length; index++) {
|
|
7071
|
+
if (!node.parameters[index]?.type) {
|
|
7072
|
+
shapes[index].type = DYN;
|
|
7073
|
+
if (shapes[index].bodyType)
|
|
7074
|
+
shapes[index].bodyType = DYN;
|
|
7075
|
+
}
|
|
7076
|
+
}
|
|
7077
|
+
}
|
|
7078
|
+
}
|
|
6822
7079
|
// A concise arrow over an h2-only stream/session call (`() =>
|
|
6823
7080
|
// req.stream.destroy()`): the call ALWAYS throws on this lowering
|
|
6824
7081
|
// (stream is undefined — the streamUndefCall precedent), so the body
|
|
@@ -6919,14 +7176,21 @@ export function lambdaSignature(lowerer, node) {
|
|
|
6919
7176
|
* object-literal shorthand method to a module-level function and yields
|
|
6920
7177
|
* the `closure` expression creating it. */
|
|
6921
7178
|
export function lowerLambda(lowerer, node) {
|
|
7179
|
+
const prepared = (ts.isArrowFunction(node) || ts.isFunctionExpression(node)) ? lowerer.preparedClassFactories.get(node) : undefined;
|
|
7180
|
+
if (prepared)
|
|
7181
|
+
return prepared;
|
|
6922
7182
|
const loc = locOf(node);
|
|
6923
|
-
const
|
|
7183
|
+
const signature = lowerer.lambdaSignature(node);
|
|
7184
|
+
const { shapes } = signature;
|
|
7185
|
+
let { funcType } = signature;
|
|
6924
7186
|
// A lambda IS a value: the completed-ABI rule applies at birth. The
|
|
6925
7187
|
// contextual (target) type decides — `(x?: number) => void` may flow
|
|
6926
7188
|
// into a slot annotated `(x: number | undefined) => void` (same ABI
|
|
6927
7189
|
// signature), anything else is fenced. Nested function declarations and
|
|
6928
7190
|
// object-literal shorthand methods aren't expressions — always fenced.
|
|
6929
|
-
|
|
7191
|
+
if (!(ts.isMethodDeclaration(node) && isJsSourceFile(node.getSourceFile()) &&
|
|
7192
|
+
canBoxFuncIntoDyn(funcType, (id) => lowerer.shapes.get(id), (id) => lowerer.unions.get(id))))
|
|
7193
|
+
lowerer.requireExactArityValue(node, ts.isArrowFunction(node) || ts.isFunctionExpression(node) ? node : null, shapes, funcType);
|
|
6930
7194
|
const nameIdent = !ts.isArrowFunction(node) && node.name && ts.isIdentifier(node.name) ? node.name : null;
|
|
6931
7195
|
const baseName = nameIdent ? nameIdent.text : "";
|
|
6932
7196
|
const fnName = `%fn${lowerer.lambdaCounter++}${baseName ? `_${baseName}` : ""}`;
|
|
@@ -6950,10 +7214,18 @@ export function lowerLambda(lowerer, node) {
|
|
|
6950
7214
|
if (isGenerator &&
|
|
6951
7215
|
(funcType.ret.kind !== "generator" || (funcType.ret.async === true) !== isAsync))
|
|
6952
7216
|
lowerer.badType(node, lowerer.typeOf(node));
|
|
6953
|
-
|
|
7217
|
+
let bodyReturn = isGenerator
|
|
6954
7218
|
? lowerer.genBodyReturnType(funcType.ret)
|
|
6955
7219
|
: lowerer.bodyReturnType(isAsync, funcType.ret);
|
|
6956
7220
|
const fnCtx = newFnCtx(true, selfSymbol, funcType, bodyReturn);
|
|
7221
|
+
const inferredSignature = isJsSourceFile(node.getSourceFile()) && !node.type ? lowerer.checker.getSignatureFromDeclaration(node) : undefined;
|
|
7222
|
+
const returnsConstructor = inferredSignature && producesConstructor(lowerer, lowerer.checker.getReturnTypeOfSignature(inferredSignature));
|
|
7223
|
+
if (isJsSourceFile(node.getSourceFile()) && !node.type && !isAsync && !isGenerator &&
|
|
7224
|
+
(bodyReturn.kind === "classval" || bodyReturn.kind === "date" || bodyReturn.kind === "symbol" || bodyReturn.kind === "record" ||
|
|
7225
|
+
(bodyReturn.kind === "dyn" || bodyReturn.kind === "func") && returnsConstructor)) {
|
|
7226
|
+
fnCtx.inferReturn = { entries: [] };
|
|
7227
|
+
}
|
|
7228
|
+
fnCtx.inheritsArguments = ts.isArrowFunction(node);
|
|
6957
7229
|
fnCtx.isAsync = isAsync;
|
|
6958
7230
|
if (isGenerator && funcType.ret.kind === "generator") {
|
|
6959
7231
|
fnCtx.generator = generatorMeta(lowerer, funcType.ret);
|
|
@@ -6967,7 +7239,7 @@ export function lowerLambda(lowerer, node) {
|
|
|
6967
7239
|
// and a method nested inside another method never captures its owner.
|
|
6968
7240
|
if (isJsSourceFile(node.getSourceFile()) && !ts.isArrowFunction(node)) {
|
|
6969
7241
|
const receiver = lowerer.declareThis(DYN);
|
|
6970
|
-
prologue.unshift({ kind: "varDecl", localId: receiver.id, init: { kind: "libCall", fn: "dyn.this", args: [], type: DYN, loc }, loc });
|
|
7242
|
+
prologue.unshift({ kind: "varDecl", localId: receiver.id, init: { kind: "libCall", fn: isGenerator ? "dyn.generatorThis" : "dyn.this", args: [], type: DYN, loc }, loc });
|
|
6971
7243
|
}
|
|
6972
7244
|
// The synthetic trailing dyn-array param carries `arguments`.
|
|
6973
7245
|
// Parameterized functions receive all actual arguments; zero-param
|
|
@@ -6977,6 +7249,15 @@ export function lowerLambda(lowerer, node) {
|
|
|
6977
7249
|
params.push({ localId: argsLocal.id, name: "%arguments", type: DYN });
|
|
6978
7250
|
fnCtx.argumentsLocal = argsLocal;
|
|
6979
7251
|
}
|
|
7252
|
+
if (isJsSourceFile(node.getSourceFile()) && !ts.isArrowFunction(node) &&
|
|
7253
|
+
shapes.length === 1 && shapes[0]?.mode === "dynRest" && bodyReadsArguments(node)) {
|
|
7254
|
+
const argsLocal = lowerer.declareHiddenLocal("%arguments", DYN);
|
|
7255
|
+
prologue.push({ kind: "varDecl", localId: argsLocal.id, init: {
|
|
7256
|
+
kind: "dynInvoke", recv: varRef(params[0].localId, DYN, loc), method: "slice",
|
|
7257
|
+
calleeName: "Array.prototype.slice", args: [], type: DYN, loc,
|
|
7258
|
+
}, loc });
|
|
7259
|
+
fnCtx.argumentsLocal = argsLocal;
|
|
7260
|
+
}
|
|
6980
7261
|
let body;
|
|
6981
7262
|
if (ts.isBlock(node.body)) {
|
|
6982
7263
|
body = lowerer.lowerStmts(node.body.statements);
|
|
@@ -7011,7 +7292,7 @@ export function lowerLambda(lowerer, node) {
|
|
|
7011
7292
|
else {
|
|
7012
7293
|
// Concise and block bodies use the same destination layout for
|
|
7013
7294
|
// fresh literals. Async bodies must inspect promises first.
|
|
7014
|
-
let value = isAsync ? lowerer.lowerExpr(bodyExpr) : lowerer.lowerExprExpecting(bodyExpr, bodyReturn);
|
|
7295
|
+
let value = isAsync || fnCtx.inferReturn ? lowerer.lowerExpr(bodyExpr) : lowerer.lowerExprExpecting(bodyExpr, bodyReturn);
|
|
7015
7296
|
// An async concise body whose value is itself a promise
|
|
7016
7297
|
// (`async () => p`): the async machinery RESOLVES the returned
|
|
7017
7298
|
// thenable into the function's own promise — lowerReturnValue's
|
|
@@ -7025,17 +7306,25 @@ export function lowerLambda(lowerer, node) {
|
|
|
7025
7306
|
: [
|
|
7026
7307
|
{
|
|
7027
7308
|
kind: "return",
|
|
7028
|
-
value: lowerer.coerceInto(bodyExpr, value, bodyReturn),
|
|
7309
|
+
value: fnCtx.inferReturn ? value : lowerer.coerceInto(bodyExpr, value, bodyReturn),
|
|
7029
7310
|
loc: locOf(node.body),
|
|
7030
7311
|
},
|
|
7031
7312
|
];
|
|
7313
|
+
if (fnCtx.inferReturn && body[0]?.kind === "return")
|
|
7314
|
+
fnCtx.inferReturn.entries.push({ stmt: body[0], node: bodyExpr });
|
|
7032
7315
|
}
|
|
7033
7316
|
}
|
|
7317
|
+
if (fnCtx.inferReturn) {
|
|
7318
|
+
bodyReturn = resolveInferredReturn(lowerer, { returnType: bodyReturn }, fnCtx.inferReturn, body, node);
|
|
7319
|
+
funcType = { ...funcType, ret: bodyReturn };
|
|
7320
|
+
fnCtx.returnType = bodyReturn;
|
|
7321
|
+
}
|
|
7034
7322
|
body = [...prologue, ...body];
|
|
7035
7323
|
// Bare-expression bodies never pass through lowerStmts, so the
|
|
7036
7324
|
// lib-boundary chokepoint runs here (idempotent for block bodies,
|
|
7037
7325
|
// whose statements were already walked). A fence poisons the
|
|
7038
7326
|
// enclosing statement — the lambda IS part of it.
|
|
7327
|
+
body = lowerSurplusCalls(lowerer, body);
|
|
7039
7328
|
enforceLibBoundary(lowerer, body);
|
|
7040
7329
|
appendImplicitUndefinedReturn(lowerer, body, bodyReturn, loc);
|
|
7041
7330
|
const ctx = lowerer.ctx;
|
|
@@ -7189,7 +7478,7 @@ export function lowerPromiseMethodCall(lowerer, call, access) {
|
|
|
7189
7478
|
const member = access.name.text;
|
|
7190
7479
|
if (member !== "then" && member !== "catch" && member !== "finally")
|
|
7191
7480
|
return null;
|
|
7192
|
-
let recvT = lowerer.mapTypeOf(lowerer.typeOf(access.expression));
|
|
7481
|
+
let recvT = lowerer.mapTypeOf(lowerer.typeOf(access.expression)) ?? dynFallbackType(lowerer, access.expression, lowerer.typeOf(access.expression));
|
|
7193
7482
|
// A dynamic-import promise under an unmappable checker type
|
|
7194
7483
|
// (`Promise<typeof import("./m")>` — module-namespace types have no
|
|
7195
7484
|
// static mapping): the BINDING holds the island promise
|
|
@@ -7242,6 +7531,8 @@ export function lowerPromiseMethodCall(lowerer, call, access) {
|
|
|
7242
7531
|
loc,
|
|
7243
7532
|
};
|
|
7244
7533
|
}
|
|
7534
|
+
if (receiver.type.kind === "dyn" && lowerer.dynConvertible(recvT))
|
|
7535
|
+
receiver = lowerer.coerceInto(access.expression, receiver, recvT);
|
|
7245
7536
|
if (receiver.type.kind !== "promise") {
|
|
7246
7537
|
// mapTypeOf said promise but the value lowered as something else —
|
|
7247
7538
|
// a lowering gap, named rather than ICEd on.
|
|
@@ -7534,7 +7825,7 @@ export function lowerPromiseMethodCall(lowerer, call, access) {
|
|
|
7534
7825
|
lowerer.unsupported("SC1090", call.arguments[0], "then handlers with more than one parameter (the two-argument onRejected form has no lowering — chain .catch(...) instead)");
|
|
7535
7826
|
}
|
|
7536
7827
|
const param = cb.type.params[0];
|
|
7537
|
-
if (param !== undefined && !typeEquals(param, inner)) {
|
|
7828
|
+
if (param !== undefined && !typeEquals(param, inner) && !(inner.kind === "void" && param.kind === "dyn")) {
|
|
7538
7829
|
lowerer.unsupported("SC1090", call.arguments[0], `then handlers whose parameter is not the settled value's type (expected '${lowerer.fmt(inner)}', got '${lowerer.fmt(param)}')`);
|
|
7539
7830
|
}
|
|
7540
7831
|
const resultT = lowerer.mapTypeOf(lowerer.typeOf(call));
|
|
@@ -7568,6 +7859,8 @@ export function lowerPromiseMethodCall(lowerer, call, access) {
|
|
|
7568
7859
|
}
|
|
7569
7860
|
else {
|
|
7570
7861
|
body.push({ kind: "exprStmt", expr: awaitE, loc });
|
|
7862
|
+
if (param !== undefined)
|
|
7863
|
+
handlerArgs = [dynUndefinedExpr(loc)];
|
|
7571
7864
|
}
|
|
7572
7865
|
const handlerCall = {
|
|
7573
7866
|
kind: "callValue",
|
|
@@ -8544,6 +8837,8 @@ function lowerObjectStaticCall(lowerer, call, access) {
|
|
|
8544
8837
|
object = { kind: "dynFrom", value: object, type: DYN, loc: locOf(call),
|
|
8545
8838
|
...(fnName !== null ? { fnName } : {}) };
|
|
8546
8839
|
}
|
|
8840
|
+
if (object.type.kind !== "dyn" && canConvertToDyn(object.type, (id) => lowerer.shapes.get(id), (id) => lowerer.unions.get(id)))
|
|
8841
|
+
object = lowerer.coerceInto(call.arguments[0], object, DYN);
|
|
8547
8842
|
if (object.type.kind === "dyn") {
|
|
8548
8843
|
const loc = locOf(call);
|
|
8549
8844
|
if (member === "getPrototypeOf")
|
|
@@ -8600,7 +8895,7 @@ function lowerObjectStaticCall(lowerer, call, access) {
|
|
|
8600
8895
|
if (unitTest)
|
|
8601
8896
|
return unitTest;
|
|
8602
8897
|
if (lk === "dyn" || rk === "dyn" || lk === "jsval" || rk === "jsval") {
|
|
8603
|
-
|
|
8898
|
+
return { kind: "libCall", fn: "dyn.sameValue", args: [lowerer.coerceInto(leftNode, left, DYN), lowerer.coerceInto(rightNode, right, DYN)], type: BOOL, loc };
|
|
8604
8899
|
}
|
|
8605
8900
|
if (left.type.kind === "union" || right.type.kind === "union") {
|
|
8606
8901
|
const ut = left.type.kind === "union" ? left.type : right.type;
|
|
@@ -8728,7 +9023,8 @@ function lowerObjectStaticCall(lowerer, call, access) {
|
|
|
8728
9023
|
return prototype;
|
|
8729
9024
|
if (isJsSourceFile(call.getSourceFile()) && call.arguments.length > 0 && !call.arguments.some(ts.isSpreadElement)) {
|
|
8730
9025
|
const target = tryLowerExpression(lowerer, call.arguments[0]);
|
|
8731
|
-
if (target
|
|
9026
|
+
if (target && ((target.type.kind === "func" && lowerer.dynConvertible(target.type)) ||
|
|
9027
|
+
(target.type.kind === "object" && lowerer.errorHierarchyClassOf(target.type.className)))) {
|
|
8732
9028
|
const loc = locOf(call);
|
|
8733
9029
|
return { kind: "libCall", fn: "dyn.assignAll", args: [lowerer.coerceToExpected(target, DYN),
|
|
8734
9030
|
{ kind: "dynArrLit", elems: call.arguments.slice(1).map((arg) => lowerer.lowerExprExpecting(arg, DYN)), type: DYN, loc },
|
|
@@ -8904,6 +9200,14 @@ function lowerObjectStaticCall(lowerer, call, access) {
|
|
|
8904
9200
|
if (call.arguments.some((a) => ts.isSpreadElement(a)))
|
|
8905
9201
|
return null;
|
|
8906
9202
|
let target = tryLowerExpression(lowerer, call.arguments[0]);
|
|
9203
|
+
const targetNode = call.arguments[0];
|
|
9204
|
+
// The checker gives C.prototype the instance type, but its lowered
|
|
9205
|
+
// value is the shared prototype table, not an instance to unbox.
|
|
9206
|
+
const prototypeTarget = ts.isPropertyAccessExpression(targetNode) && targetNode.name.text === "prototype" &&
|
|
9207
|
+
(exactClassOfReceiver(lowerer, targetNode.expression) !== null || storedClassValueType(lowerer, targetNode.expression)?.kind === "classval");
|
|
9208
|
+
const declaredTarget = target?.type.kind === "dyn" && !prototypeTarget && !isJsSourceFile(targetNode.getSourceFile()) ? lowerer.mapTypeOf(lowerer.typeOf(targetNode)) : null;
|
|
9209
|
+
if (target && declaredTarget && isDynTypedRefType(declaredTarget))
|
|
9210
|
+
target = lowerer.coerceToExpected(target, declaredTarget);
|
|
8907
9211
|
if (target && member === "defineProperty") {
|
|
8908
9212
|
const native = lowerClassDataDescriptor(lowerer, call, member, target);
|
|
8909
9213
|
if (native)
|
|
@@ -8915,11 +9219,10 @@ function lowerObjectStaticCall(lowerer, call, access) {
|
|
|
8915
9219
|
return descriptor;
|
|
8916
9220
|
target = lowerer.coerceToExpected(target, DYN);
|
|
8917
9221
|
}
|
|
8918
|
-
// Error
|
|
8919
|
-
// view. Other native fields do not yet synchronize descriptor edits.
|
|
9222
|
+
// Error instances share a live property table with their checked view.
|
|
8920
9223
|
const keyNode = call.arguments[1];
|
|
8921
9224
|
if (target?.type.kind === "object" && target.type.className !== "%DOMException" && lowerer.errorHierarchyClassOf(target.type.className) &&
|
|
8922
|
-
ts.isStringLiteral(keyNode) && keyNode.text === "cause") {
|
|
9225
|
+
((ts.isStringLiteral(keyNode) && (keyNode.text === "cause" || keyNode.text === "message")) || lowerer.mapTypeOf(lowerer.typeOf(keyNode))?.kind === "symbol")) {
|
|
8923
9226
|
target = lowerer.coerceToExpected(target, DYN);
|
|
8924
9227
|
}
|
|
8925
9228
|
if (target?.type.kind === "func" && lowerer.dynConvertible(target.type)) {
|
|
@@ -9048,14 +9351,19 @@ function lowerObjectStaticCall(lowerer, call, access) {
|
|
|
9048
9351
|
const recvNode = call.arguments[0];
|
|
9049
9352
|
const keyNode = call.arguments[1];
|
|
9050
9353
|
const probed = tryLowerExpression(lowerer, recvNode);
|
|
9354
|
+
const constructor = probed?.type.kind === "classval" ? lowerer.classes.get(probed.type.className) : undefined;
|
|
9051
9355
|
// A CHECKED-DYNAMIC receiver (the JS file-scope object-literal
|
|
9052
9356
|
// identity story): the runtime dyn probe — OBJ member presence, ARR
|
|
9053
9357
|
// index bounds, Node's ToObject TypeError on nullish.
|
|
9054
|
-
if (probed?.type.kind === "dyn" || (probed && isDynTypedRefType(probed.type)) ||
|
|
9358
|
+
if (probed?.type.kind === "dyn" || (probed && isDynTypedRefType(probed.type)) ||
|
|
9359
|
+
(probed?.type.kind === "object" && lowerer.errorHierarchyClassOf(probed.type.className)) ||
|
|
9360
|
+
(probed && constructor && (constructor.callableBase || hasRuntimeStatics(constructor))) ||
|
|
9361
|
+
(probed?.type.kind === "func" && lowerer.dynConvertible(probed.type))) {
|
|
9055
9362
|
const loc = locOf(call);
|
|
9056
9363
|
const receiver = lowerer.coerceToExpected(probed, DYN);
|
|
9057
9364
|
const rawKey = lowerer.lowerExpr(keyNode);
|
|
9058
|
-
if (rawKey.type.kind === "dyn" || rawKey.type.kind === "symbol"
|
|
9365
|
+
if (rawKey.type.kind === "dyn" || rawKey.type.kind === "symbol" ||
|
|
9366
|
+
rawKey.type.kind === "union" && lowerer.dynConvertible(rawKey.type))
|
|
9059
9367
|
return {
|
|
9060
9368
|
kind: "libCall", fn: "dyn.hasOwnComputed", args: [receiver, lowerer.coerceToExpected(rawKey, DYN)], type: BOOL, loc,
|
|
9061
9369
|
};
|
|
@@ -9140,7 +9448,8 @@ function lowerObjectStaticCall(lowerer, call, access) {
|
|
|
9140
9448
|
const isPrimitive = probed !== null && probed !== undefined &&
|
|
9141
9449
|
(isUnitType(probed.type) || probed.type.kind === "string" ||
|
|
9142
9450
|
probed.type.kind === "f64" || probed.type.kind === "bool");
|
|
9143
|
-
|
|
9451
|
+
const isJsUnion = probed?.type.kind === "union" && isJsSourceFile(call.getSourceFile()) && lowerer.dynConvertible(probed.type);
|
|
9452
|
+
if (isDyn || isPrimitive || isFunction || isJsUnion || (probed && isDynTypedRefType(probed.type))) {
|
|
9144
9453
|
const fn = member === "keys" ? "dyn.objKeys" : member === "values" ? "dyn.objValues" : "dyn.objEntries";
|
|
9145
9454
|
let v = lowerer.lowerExpr(argNode);
|
|
9146
9455
|
if (v.type.kind !== "dyn")
|
|
@@ -9221,7 +9530,6 @@ function lowerObjectStaticCall(lowerer, call, access) {
|
|
|
9221
9530
|
const recT = argIr;
|
|
9222
9531
|
const ref = { kind: "varRef", localId: "r.0", type: recT, loc };
|
|
9223
9532
|
const outRef = { kind: "varRef", localId: "out.0", type: resultT, loc };
|
|
9224
|
-
lowerer.arrHofHelpers.set(key, helper);
|
|
9225
9533
|
const fn = {
|
|
9226
9534
|
name: helper,
|
|
9227
9535
|
params: [{ localId: "r.0", name: "r", type: recT }],
|
|
@@ -9250,6 +9558,8 @@ function lowerObjectStaticCall(lowerer, call, access) {
|
|
|
9250
9558
|
return null;
|
|
9251
9559
|
if (typeEquals(vt, valueT))
|
|
9252
9560
|
return value;
|
|
9561
|
+
if (valueT.kind === "dyn" && lowerer.dynConvertible(vt))
|
|
9562
|
+
return lowerer.coerceToExpected(value, DYN);
|
|
9253
9563
|
if (valueT.kind === "union" && vt.kind !== "union") {
|
|
9254
9564
|
const tag = lowerer.armTag(valueT.unionId, vt);
|
|
9255
9565
|
if (tag >= 0) {
|
|
@@ -9269,7 +9579,7 @@ function lowerObjectStaticCall(lowerer, call, access) {
|
|
|
9269
9579
|
guardUndefTag = undefTag;
|
|
9270
9580
|
const arms = lowerer.unions.get(f.type.unionId)?.arms ?? [];
|
|
9271
9581
|
const others = arms.filter((a) => a.kind !== "undefinedT");
|
|
9272
|
-
if (typeEquals(f.type, valueT ?? f.type)) {
|
|
9582
|
+
if (valueT?.kind === "dyn" || typeEquals(f.type, valueT ?? f.type)) {
|
|
9273
9583
|
// The field union IS the result union (single-field shapes):
|
|
9274
9584
|
// push the raw box — but then the undefined skip must NOT
|
|
9275
9585
|
// narrow. Handled below via vt === valueT.
|
|
@@ -9293,7 +9603,7 @@ function lowerObjectStaticCall(lowerer, call, access) {
|
|
|
9293
9603
|
"cannot re-tag into the result element type — read the fields directly)");
|
|
9294
9604
|
}
|
|
9295
9605
|
}
|
|
9296
|
-
else if (!typeEquals(f.type, valueT ?? f.type)) {
|
|
9606
|
+
else if (valueT?.kind !== "dyn" && !typeEquals(f.type, valueT ?? f.type)) {
|
|
9297
9607
|
lowerer.unsupported("SC1090", call, `Object.${member} over '${lowerer.fmt(argIr)}' (field '${f.name}' is a union that cannot ` +
|
|
9298
9608
|
"re-tag into the result element type — read the fields directly)");
|
|
9299
9609
|
}
|
|
@@ -9333,6 +9643,7 @@ function lowerObjectStaticCall(lowerer, call, access) {
|
|
|
9333
9643
|
fn.body = body;
|
|
9334
9644
|
};
|
|
9335
9645
|
finalize();
|
|
9646
|
+
lowerer.arrHofHelpers.set(key, helper);
|
|
9336
9647
|
lowerer.shapeOrderHelperFinalizers.push(finalize);
|
|
9337
9648
|
lowerer.liftedFns.push(fn);
|
|
9338
9649
|
}
|
|
@@ -9381,6 +9692,15 @@ export function lowerFunction(lowerer, decl) {
|
|
|
9381
9692
|
params.push({ localId: argsLocal.id, name: "%arguments", type: DYN });
|
|
9382
9693
|
ctx.argumentsLocal = argsLocal;
|
|
9383
9694
|
}
|
|
9695
|
+
if (isJsSourceFile(decl.getSourceFile()) && sig.params.length === 1 &&
|
|
9696
|
+
sig.params[0]?.mode === "dynRest" && bodyReadsArguments(decl)) {
|
|
9697
|
+
const argsLocal = lowerer.declareHiddenLocal("%arguments", DYN);
|
|
9698
|
+
prologue.push({ kind: "varDecl", localId: argsLocal.id, init: {
|
|
9699
|
+
kind: "dynInvoke", recv: varRef(params[0].localId, DYN, locOf(decl)), method: "slice",
|
|
9700
|
+
calleeName: "Array.prototype.slice", args: [], type: DYN, loc: locOf(decl),
|
|
9701
|
+
}, loc: locOf(decl) });
|
|
9702
|
+
ctx.argumentsLocal = argsLocal;
|
|
9703
|
+
}
|
|
9384
9704
|
const bodyBlock = blockBodyOf(decl);
|
|
9385
9705
|
if (!bodyBlock) {
|
|
9386
9706
|
lowerer.unsupported("SC1090", decl, "function declarations whose block body the frontend cannot locate");
|
|
@@ -10404,6 +10724,14 @@ function lowerObjLitGenericMethodCall(lowerer, call, access) {
|
|
|
10404
10724
|
const propSym = lowerer.checker.getPropertyOfType(recvT, name);
|
|
10405
10725
|
if (!propSym)
|
|
10406
10726
|
return null;
|
|
10727
|
+
const propertyDecl = lowerer.checker.valueDeclarationOf(propSym);
|
|
10728
|
+
if (propertyDecl && ts.isShorthandPropertyAssignment(propertyDecl) && ts.isIdentifier(propertyDecl.name) && ts.isObjectLiteralExpression(propertyDecl.parent)) {
|
|
10729
|
+
requireObjLitGenericReceiver(lowerer, call, access.expression, propertyDecl.parent, name);
|
|
10730
|
+
const targetSymbol = lowerer.checker.getShorthandAssignmentValueSymbol(propertyDecl);
|
|
10731
|
+
const target = targetSymbol ? lowerer.genericFnsBySymbol.get((targetSymbol.flags & ts.SymbolFlags.Alias ? lowerer.checker.getAliasedSymbol(targetSymbol) : targetSymbol)) : undefined;
|
|
10732
|
+
if (target)
|
|
10733
|
+
return lowerer.lowerGenericCall(call, target);
|
|
10734
|
+
}
|
|
10407
10735
|
if (!isGenericCallableMemberType(lowerer.checker.getTypeOfSymbol(propSym), lowerer.checker))
|
|
10408
10736
|
return null;
|
|
10409
10737
|
// CLASS members belong to the class path (lowerClassGenericMethodCall
|
|
@@ -10502,6 +10830,12 @@ export function lowerObjectMethodCall(lowerer, call, access) {
|
|
|
10502
10830
|
lowerUnionObjectDynFieldCall(lowerer, call, access, mappedReceiver);
|
|
10503
10831
|
if (dispatched)
|
|
10504
10832
|
return dispatched;
|
|
10833
|
+
const arms = lowerer.unions.get(mappedReceiver.unionId)?.arms;
|
|
10834
|
+
if (isJsSourceFile(call.getSourceFile()) && arms?.every((arm) => arm.kind === "object" &&
|
|
10835
|
+
!lowerer.classes.get(arm.className)?.def.runtime) && lowerer.dynConvertible(mappedReceiver)) {
|
|
10836
|
+
const receiver = lowerer.coerceInto(access.expression, lowerer.lowerExpr(access.expression), DYN);
|
|
10837
|
+
return lowerDynDispatchMethodCall(lowerer, call, access, receiver, false);
|
|
10838
|
+
}
|
|
10505
10839
|
}
|
|
10506
10840
|
const receiverIr = mappedReceiver?.kind === "object"
|
|
10507
10841
|
? mappedReceiver
|
|
@@ -10614,6 +10948,21 @@ export function lowerObjectMethodCall(lowerer, call, access) {
|
|
|
10614
10948
|
return finish({ kind: "dynCall", callee, receiver, calleeName: access.getText(), args, type: DYN, loc });
|
|
10615
10949
|
}
|
|
10616
10950
|
}
|
|
10951
|
+
if (!fieldType && isJsSourceFile(call.getSourceFile()) && !info.def.runtime && !info.builtinError && !info.builtinEmitter && !info.builtinStream) {
|
|
10952
|
+
const loc = locOf(call);
|
|
10953
|
+
const value = lowerReceiver();
|
|
10954
|
+
const local = lowerer.declareHiddenLocal("%callReceiver", value.type);
|
|
10955
|
+
const reference = { kind: "varRef", localId: local.id, type: value.type, loc };
|
|
10956
|
+
const receiver = lowerer.coerceToExpected(reference, DYN);
|
|
10957
|
+
const callee = { kind: "dynKeyGet", value: receiver,
|
|
10958
|
+
key: { kind: "strLit", value: access.name.text, type: STRING, loc }, type: DYN, loc };
|
|
10959
|
+
const spread = call.arguments.some(ts.isSpreadElement) ? lowerSpreadArgsCall(lowerer, call, callee, loc) : null;
|
|
10960
|
+
if (spread && spread.kind !== "dynCall")
|
|
10961
|
+
lowerer.unsupported("SC1090", call, "native property call spread arguments");
|
|
10962
|
+
const result = spread !== null ? { ...spread, receiver } : { kind: "dynCall", callee, receiver,
|
|
10963
|
+
calleeName: access.getText(), args: call.arguments.map((arg) => lowerer.lowerExprExpecting(arg, DYN)), type: DYN, loc };
|
|
10964
|
+
return { kind: "seqExpr", stmts: [{ kind: "varDecl", localId: local.id, init: value, loc }], result, type: DYN, loc };
|
|
10965
|
+
}
|
|
10617
10966
|
return null;
|
|
10618
10967
|
}
|
|
10619
10968
|
if (!info || !found)
|
|
@@ -10696,6 +11045,22 @@ function lowerUnionObjectMethodCall(lowerer, call, access, receiverT) {
|
|
|
10696
11045
|
plans.push({ arm, info, found });
|
|
10697
11046
|
}
|
|
10698
11047
|
const shapes = plans[0].found.sig.params;
|
|
11048
|
+
if (plans.some((plan) => isClassCallback(lowerer, plan.info, method))) {
|
|
11049
|
+
const loc = locOf(call);
|
|
11050
|
+
const local = lowerer.declareHiddenLocal("%unionMethodReceiver", DYN);
|
|
11051
|
+
const receiver = varRef(local.id, DYN, loc);
|
|
11052
|
+
const callee = { kind: "dynKeyGet", value: receiver,
|
|
11053
|
+
key: { kind: "strLit", value: method, type: STRING, loc }, type: DYN, loc };
|
|
11054
|
+
const spread = call.arguments.some(ts.isSpreadElement) ? lowerSpreadArgsCall(lowerer, call, callee, loc) : null;
|
|
11055
|
+
if (spread && spread.kind !== "dynCall")
|
|
11056
|
+
lowerer.unsupported("SC1090", call, "union method spread arguments");
|
|
11057
|
+
const value = spread !== null ? { ...spread, receiver } : { kind: "dynCall", callee, receiver,
|
|
11058
|
+
calleeName: access.getText(), args: call.arguments.map((arg) => lowerer.lowerExprExpecting(arg, DYN)), type: DYN, loc };
|
|
11059
|
+
const resultT = lowerer.mapTypeOf(lowerer.typeOf(call));
|
|
11060
|
+
const result = resultT && !isUnitType(resultT) ? lowerer.coerceToExpected(value, resultT) : value;
|
|
11061
|
+
return { kind: "seqExpr", stmts: [{ kind: "varDecl", localId: local.id,
|
|
11062
|
+
init: lowerer.coerceInto(access.expression, lowerer.lowerExpr(access.expression), DYN), loc }], result, type: result.type, loc };
|
|
11063
|
+
}
|
|
10699
11064
|
if (!plans.every((plan) => paramAbisEqual(shapes, plan.found.sig.params)))
|
|
10700
11065
|
return null;
|
|
10701
11066
|
const resultT = lowerer.mapTypeOf(lowerer.typeOf(call));
|