@scriptc/compiler 0.0.36 → 0.1.2
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 +52 -22
- package/ambient/scriptc-overrides.d.ts +0 -7
- package/ambient/scriptc.d.ts +3 -2
- package/dist/backend/build-cache.js.map +1 -1
- package/dist/backend/c/async.js +24 -2
- package/dist/backend/c/async.js.map +1 -1
- package/dist/backend/c/c-emitter.d.ts +22 -10
- package/dist/backend/c/c-emitter.js +60 -15
- package/dist/backend/c/c-emitter.js.map +1 -1
- package/dist/backend/c/exprs.js +289 -55
- package/dist/backend/c/exprs.js.map +1 -1
- package/dist/backend/c/island.js.map +1 -1
- package/dist/backend/c/may-throw.js +3 -0
- package/dist/backend/c/may-throw.js.map +1 -1
- package/dist/backend/c/stmts.d.ts +3 -5
- package/dist/backend/c/stmts.js +76 -17
- package/dist/backend/c/stmts.js.map +1 -1
- package/dist/backend/c/types.js.map +1 -1
- package/dist/backend/c/walkers.js +36 -12
- package/dist/backend/c/walkers.js.map +1 -1
- package/dist/backend/external-c.d.ts +33 -0
- package/dist/backend/external-c.js +51 -0
- package/dist/backend/external-c.js.map +1 -0
- package/dist/backend/link-plan.d.ts +37 -0
- package/dist/backend/link-plan.js +26 -0
- package/dist/backend/link-plan.js.map +1 -0
- package/dist/backend/linker.d.ts +22 -0
- package/dist/backend/linker.js +236 -0
- package/dist/backend/linker.js.map +1 -0
- package/dist/backend/llvm/blocks.js.map +1 -1
- package/dist/backend/llvm/dyn.js +63 -3
- package/dist/backend/llvm/dyn.js.map +1 -1
- package/dist/backend/llvm/emitter.js +132 -26
- package/dist/backend/llvm/emitter.js.map +1 -1
- package/dist/backend/llvm/expr-async.js +85 -3
- package/dist/backend/llvm/expr-async.js.map +1 -1
- package/dist/backend/llvm/expr-bytes.js.map +1 -1
- package/dist/backend/llvm/expr-calls.js.map +1 -1
- package/dist/backend/llvm/expr-containers.js +68 -54
- package/dist/backend/llvm/expr-containers.js.map +1 -1
- package/dist/backend/llvm/expr-context.d.ts +2 -1
- package/dist/backend/llvm/expr-control.js.map +1 -1
- package/dist/backend/llvm/expr-dispatch.js +2 -0
- package/dist/backend/llvm/expr-dispatch.js.map +1 -1
- package/dist/backend/llvm/expr-dynamic.js +6 -3
- package/dist/backend/llvm/expr-dynamic.js.map +1 -1
- package/dist/backend/llvm/expr-island.js.map +1 -1
- package/dist/backend/llvm/expr-primitives.d.ts +1 -1
- package/dist/backend/llvm/expr-primitives.js +20 -0
- package/dist/backend/llvm/expr-primitives.js.map +1 -1
- package/dist/backend/llvm/expr-records.js.map +1 -1
- package/dist/backend/llvm/expr-stream-bridges.js +245 -10
- package/dist/backend/llvm/expr-stream-bridges.js.map +1 -1
- package/dist/backend/llvm/lib-dispatch.js +2 -0
- package/dist/backend/llvm/lib-dispatch.js.map +1 -1
- package/dist/backend/llvm/lib-shared.js +18 -0
- package/dist/backend/llvm/lib-shared.js.map +1 -1
- package/dist/backend/llvm/lib-stream.js +6 -3
- package/dist/backend/llvm/lib-stream.js.map +1 -1
- package/dist/backend/llvm/split.js.map +1 -1
- package/dist/backend/llvm/unsupported.js.map +1 -1
- package/dist/backend/llvm/walkers.js +31 -4
- package/dist/backend/llvm/walkers.js.map +1 -1
- package/dist/backend/native-codegen.d.ts +8 -1
- package/dist/backend/native-codegen.js +39 -25
- package/dist/backend/native-codegen.js.map +1 -1
- package/dist/backend/native-codegen.test.js +44 -4
- package/dist/backend/native-codegen.test.js.map +1 -1
- package/dist/backend/native-link-info.d.ts +1 -1
- package/dist/backend/native-link-info.js +42 -18
- package/dist/backend/native-link-info.js.map +1 -1
- package/dist/backend/native-toolchain.js.map +1 -1
- package/dist/backend/native-toolchain.test.js +5 -1
- package/dist/backend/native-toolchain.test.js.map +1 -1
- package/dist/backend/runtime-pack-targets.test.d.ts +1 -0
- package/dist/backend/runtime-pack-targets.test.js +54 -0
- package/dist/backend/runtime-pack-targets.test.js.map +1 -0
- package/dist/backend/runtime-pack.d.ts +5 -30
- package/dist/backend/runtime-pack.js +46 -141
- package/dist/backend/runtime-pack.js.map +1 -1
- package/dist/backend/runtime-pack.test.js +49 -14
- package/dist/backend/runtime-pack.test.js.map +1 -1
- package/dist/backend/targets.d.ts +63 -17
- package/dist/backend/targets.js +251 -35
- package/dist/backend/targets.js.map +1 -1
- package/dist/backend/targets.test.js +27 -5
- package/dist/backend/targets.test.js.map +1 -1
- package/dist/backend/vendor-archives.js.map +1 -1
- package/dist/compat/fetch-profile.js +4 -2
- package/dist/compat/fetch-profile.js.map +1 -1
- package/dist/coverage/report.js.map +1 -1
- package/dist/coverage/surface-manifest.js +22 -1
- package/dist/coverage/surface-manifest.js.map +1 -1
- package/dist/diagnostics/diagnostic.d.ts +6 -5
- package/dist/diagnostics/diagnostic.js +7 -6
- package/dist/diagnostics/diagnostic.js.map +1 -1
- package/dist/diagnostics/render.js.map +1 -1
- package/dist/ffi/ffi-manifest.js.map +1 -1
- package/dist/frontend/cjs-lexer.js.map +1 -1
- package/dist/frontend/dts-paths.js.map +1 -1
- package/dist/frontend/input-tracker.d.ts +10 -0
- package/dist/frontend/input-tracker.js +26 -3
- package/dist/frontend/input-tracker.js.map +1 -1
- package/dist/frontend/input-tracker.test.js +8 -1
- package/dist/frontend/input-tracker.test.js.map +1 -1
- package/dist/frontend/lib-contract.js.map +1 -1
- package/dist/frontend/lowering/array-values.d.ts +12 -0
- package/dist/frontend/lowering/array-values.js +76 -0
- package/dist/frontend/lowering/array-values.js.map +1 -0
- package/dist/frontend/lowering/callback-arg.js.map +1 -1
- package/dist/frontend/lowering/containers/bytes.d.ts +35 -0
- package/dist/frontend/lowering/containers/bytes.js +1021 -0
- package/dist/frontend/lowering/containers/bytes.js.map +1 -0
- package/dist/frontend/lowering/containers/string-and-regexp.d.ts +17 -0
- package/dist/frontend/lowering/containers/string-and-regexp.js +345 -0
- package/dist/frontend/lowering/containers/string-and-regexp.js.map +1 -0
- package/dist/frontend/lowering/expressions/evaluation-safety.d.ts +13 -0
- package/dist/frontend/lowering/expressions/evaluation-safety.js +76 -0
- package/dist/frontend/lowering/expressions/evaluation-safety.js.map +1 -0
- package/dist/frontend/lowering/expressions/object-literals.d.ts +44 -0
- package/dist/frontend/lowering/expressions/object-literals.js +1815 -0
- package/dist/frontend/lowering/expressions/object-literals.js.map +1 -0
- package/dist/frontend/lowering/expressions/optional-chains.d.ts +31 -0
- package/dist/frontend/lowering/expressions/optional-chains.js +382 -0
- package/dist/frontend/lowering/expressions/optional-chains.js.map +1 -0
- package/dist/frontend/lowering/expressions/try-lower-expression.d.ts +7 -0
- package/dist/frontend/lowering/expressions/try-lower-expression.js +26 -0
- package/dist/frontend/lowering/expressions/try-lower-expression.js.map +1 -0
- package/dist/frontend/lowering/lib-boundary.js +7 -2
- package/dist/frontend/lowering/lib-boundary.js.map +1 -1
- package/dist/frontend/lowering/lower-array-sort.d.ts +22 -0
- package/dist/frontend/lowering/lower-array-sort.js +619 -0
- package/dist/frontend/lowering/lower-array-sort.js.map +1 -0
- package/dist/frontend/lowering/lower-assert.js.map +1 -1
- package/dist/frontend/lowering/lower-async-iteration.d.ts +7 -0
- package/dist/frontend/lowering/lower-async-iteration.js +657 -0
- package/dist/frontend/lowering/lower-async-iteration.js.map +1 -0
- package/dist/frontend/lowering/lower-builtins.d.ts +18 -0
- package/dist/frontend/lowering/lower-builtins.js +379 -48
- package/dist/frontend/lowering/lower-builtins.js.map +1 -1
- package/dist/frontend/lowering/lower-calls.d.ts +16 -8
- package/dist/frontend/lowering/lower-calls.js +667 -91
- package/dist/frontend/lowering/lower-calls.js.map +1 -1
- package/dist/frontend/lowering/lower-classes.d.ts +7 -13
- package/dist/frontend/lowering/lower-classes.js +128 -35
- package/dist/frontend/lowering/lower-classes.js.map +1 -1
- package/dist/frontend/lowering/lower-comptime.js.map +1 -1
- package/dist/frontend/lowering/lower-containers.d.ts +1 -47
- package/dist/frontend/lowering/lower-containers.js +779 -2038
- package/dist/frontend/lowering/lower-containers.js.map +1 -1
- package/dist/frontend/lowering/lower-event-emitter.js +51 -5
- package/dist/frontend/lowering/lower-event-emitter.js.map +1 -1
- package/dist/frontend/lowering/lower-exprs.d.ts +4 -78
- package/dist/frontend/lowering/lower-exprs.js +1128 -2409
- package/dist/frontend/lowering/lower-exprs.js.map +1 -1
- package/dist/frontend/lowering/lower-generators.d.ts +18 -3
- package/dist/frontend/lowering/lower-generators.js +145 -9
- package/dist/frontend/lowering/lower-generators.js.map +1 -1
- package/dist/frontend/lowering/lower-inspect.js +50 -36
- package/dist/frontend/lowering/lower-inspect.js.map +1 -1
- package/dist/frontend/lowering/lower-island.d.ts +11 -4
- package/dist/frontend/lowering/lower-island.js +47 -10
- package/dist/frontend/lowering/lower-island.js.map +1 -1
- package/dist/frontend/lowering/lower-modules.js +52 -15
- package/dist/frontend/lowering/lower-modules.js.map +1 -1
- package/dist/frontend/lowering/lower-node-module.d.ts +18 -0
- package/dist/frontend/lowering/lower-node-module.js +302 -0
- package/dist/frontend/lowering/lower-node-module.js.map +1 -0
- package/dist/frontend/lowering/lower-server.js +11 -1
- package/dist/frontend/lowering/lower-server.js.map +1 -1
- package/dist/frontend/lowering/lower-stmts.d.ts +5 -24
- package/dist/frontend/lowering/lower-stmts.js +811 -314
- package/dist/frontend/lowering/lower-stmts.js.map +1 -1
- package/dist/frontend/lowering/lower-stream.js +4 -4
- package/dist/frontend/lowering/lower-stream.js.map +1 -1
- package/dist/frontend/lowering/lowerer.d.ts +109 -34
- package/dist/frontend/lowering/lowerer.js +1225 -62
- package/dist/frontend/lowering/lowerer.js.map +1 -1
- package/dist/frontend/lowering/optional-arguments.d.ts +9 -0
- package/dist/frontend/lowering/optional-arguments.js +57 -0
- package/dist/frontend/lowering/optional-arguments.js.map +1 -0
- package/dist/frontend/lowering/surfaces.d.ts +10 -2
- package/dist/frontend/lowering/surfaces.js +15 -3
- package/dist/frontend/lowering/surfaces.js.map +1 -1
- package/dist/frontend/npm-static-declarations.d.ts +35 -0
- package/dist/frontend/npm-static-declarations.js +506 -0
- package/dist/frontend/npm-static-declarations.js.map +1 -0
- package/dist/frontend/npm-static-declarations.test.d.ts +1 -0
- package/dist/frontend/npm-static-declarations.test.js +122 -0
- package/dist/frontend/npm-static-declarations.test.js.map +1 -0
- package/dist/frontend/npm-static.d.ts +2 -0
- package/dist/frontend/npm-static.js +26 -10
- package/dist/frontend/npm-static.js.map +1 -1
- package/dist/frontend/npm.d.ts +60 -0
- package/dist/frontend/npm.js +38 -4
- package/dist/frontend/npm.js.map +1 -1
- package/dist/frontend/npm.test.d.ts +1 -0
- package/dist/frontend/npm.test.js +50 -0
- package/dist/frontend/npm.test.js.map +1 -0
- package/dist/frontend/program.d.ts +3 -2
- package/dist/frontend/program.js +495 -68
- package/dist/frontend/program.js.map +1 -1
- package/dist/frontend/resolve.d.ts +10 -2
- package/dist/frontend/resolve.js +90 -14
- package/dist/frontend/resolve.js.map +1 -1
- package/dist/frontend/resolve.test.js +4 -1
- package/dist/frontend/resolve.test.js.map +1 -1
- package/dist/frontend/runtime-resolve.d.ts +22 -0
- package/dist/frontend/runtime-resolve.js +101 -0
- package/dist/frontend/runtime-resolve.js.map +1 -0
- package/dist/frontend/runtime-resolve.test.d.ts +1 -0
- package/dist/frontend/runtime-resolve.test.js +18 -0
- package/dist/frontend/runtime-resolve.test.js.map +1 -0
- package/dist/frontend/ts7/adapter.js +12 -13
- package/dist/frontend/ts7/adapter.js.map +1 -1
- package/dist/frontend/ts7/ast.js.map +1 -1
- package/dist/frontend/ts7/census-check.js +3 -3
- package/dist/frontend/ts7/census-check.js.map +1 -1
- package/dist/frontend/ts7/checker.d.ts +3 -0
- package/dist/frontend/ts7/checker.js +12 -3
- package/dist/frontend/ts7/checker.js.map +1 -1
- package/dist/frontend/ts7/enums.js.map +1 -1
- package/dist/frontend/ts7/program-adapter.js +42 -3
- package/dist/frontend/ts7/program-adapter.js.map +1 -1
- package/dist/frontend/type-mapper.js +120 -7
- package/dist/frontend/type-mapper.js.map +1 -1
- package/dist/index.d.ts +3 -3
- package/dist/index.js +50 -28
- package/dist/index.js.map +1 -1
- package/dist/ir/analysis.js.map +1 -1
- package/dist/ir/ir.d.ts +125 -41
- package/dist/ir/ir.js +82 -31
- package/dist/ir/ir.js.map +1 -1
- package/dist/ir/serialize.d.ts +1 -1
- package/dist/ir/serialize.js +1 -1
- package/dist/ir/validate.js +127 -95
- package/dist/ir/validate.js.map +1 -1
- package/dist/library/cache-primitives.js.map +1 -1
- package/dist/library/cache-reset.test.js.map +1 -1
- package/dist/library/compiler-self-identity.js.map +1 -1
- package/dist/library/fence-eval.js +3 -1
- package/dist/library/fence-eval.js.map +1 -1
- package/dist/library/int-infer.js +12 -1
- package/dist/library/int-infer.js.map +1 -1
- package/dist/library/int-infer.test.js +4 -4
- package/dist/library/int-infer.test.js.map +1 -1
- package/dist/library/library-cache.test.js +5 -5
- package/dist/library/library-profile.js.map +1 -1
- package/dist/library/sidecar-validate.js.map +1 -1
- package/dist/library/sidecar.js.map +1 -1
- package/dist/startup-cache.d.ts +9 -1
- package/dist/startup-cache.js +16 -1
- package/dist/startup-cache.js.map +1 -1
- package/dist/wasi-paths.js.map +1 -1
- package/package.json +18 -5
- package/surface-manifest.json +64 -8
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { InternalCompilerError } from "../../errors.js";
|
|
1
2
|
/* Call lowering: the lowerCall dispatch chain, parameter-shape analysis and
|
|
2
3
|
* argument completion (optional/default/rest, explicit-undefined ≡ omission),
|
|
3
4
|
* function/lambda lowering and signature collection, and monomorphizing
|
|
@@ -6,15 +7,19 @@ import * as ts from "../ts7/adapter.js";
|
|
|
6
7
|
import { lowerGenMethodCall } from "./lower-generators.js";
|
|
7
8
|
import { BOOL, CAUGHT, DYN, F64, JSVAL, STRING, SYMBOL_T, UNDEFINED_T, VOID, arrayOf, canBoxFuncIntoDyn, canConvertToDyn, canDynCheckTo, canMarshalTypedFuncIntoIsland, ffiClassType, ffiSourceParamTypes, funcOf, isFfiCallbackParam, isFfiContextParam, isFfiReleaseParam, isUnitType, shapeHasAccessorSlots, typeEquals } from "../../ir/ir.js";
|
|
8
9
|
import { isJsSourceFile, locOf } from "../program.js";
|
|
9
|
-
import { isGenericCallableMemberType, typeKey } from "../type-mapper.js";
|
|
10
|
+
import { genResultRecord, isGenericCallableMemberType, typeKey } from "../type-mapper.js";
|
|
10
11
|
import { PoisonError, dynFallbackType, dynUndefinedExpr, importCallHandleType, jsFuncNameOf, newFnCtx, nodeThrowExpr } from "./lowerer.js";
|
|
11
12
|
import { enforceLibBoundary } from "./lib-boundary.js";
|
|
12
13
|
import { NARROW_FIRST, builtinFenceHintOf, builtinModuleFnOf } from "./surfaces.js";
|
|
13
14
|
import { ffiBindingDiag, ffiSignatureDiag, libCallbackDiag, requiresDynamicDiag } from "../../diagnostics/diagnostic.js";
|
|
14
15
|
import { mixinFnShapeOf } from "./lower-mixins.js";
|
|
15
|
-
import {
|
|
16
|
-
import {
|
|
17
|
-
import {
|
|
16
|
+
import { dynStringReceiver, lowerArrayFromCall, lowerDynArrayFilterCall, lowerDynArrayFlatMapCall, lowerGroupByStaticCall, lowerIteratorHelperCall, lowerObjectAssignIndexShape, lowerObjectFromEntriesCall, lowerObjectIterOverIndexShape, lowerTupleReadMethodCall } from "./lower-containers.js";
|
|
17
|
+
import { bufEncoding } from "./containers/bytes.js";
|
|
18
|
+
import { lowerRegexMethodCall, lowerStringMethodCall } from "./containers/string-and-regexp.js";
|
|
19
|
+
import { lowerChildStreamMethodCall, lowerCreateRequireCall, lowerDirentMethodCall, lowerFileHandleMethodCall, lowerImportMetaResolveCall, lowerPerfHooksCall, lowerProcStreamMethodCall, lowerReflectApplyCall, lowerRequireResolveCall, lowerWatcherMethodCall } from "./lower-builtins.js";
|
|
20
|
+
import { lowerAbsenceProbe, lowerPromiseAllTupleCall, lowerPromiseRejectCall, templateRawTextOf } from "./lower-exprs.js";
|
|
21
|
+
import { isSafeToDiscard } from "./expressions/evaluation-safety.js";
|
|
22
|
+
import { tryLowerExpression } from "./expressions/try-lower-expression.js";
|
|
18
23
|
import { httpClientFnBindingOf, isStreamUndefCallExpr, lowerCompatReqStreamOptionalCall, lowerHttpClientFnCall } from "./lower-server.js";
|
|
19
24
|
import { EMITTER_API_MEMBERS, exactInstanceClassOf, findGenericMethodOn, lowerClassGenericMethodCall, lowerStaticMethodCall } from "./lower-classes.js";
|
|
20
25
|
import { emitterRooted, lowerEmitterMethodCall } from "./lower-event-emitter.js";
|
|
@@ -26,6 +31,14 @@ import { expandoMemberRead } from "./lower-expando.js";
|
|
|
26
31
|
import { npmStaticPackageOfPath } from "../npm-static.js";
|
|
27
32
|
import { countedFor, varRef } from "../../ir/build.js";
|
|
28
33
|
import { rejectStaticThis } from "./static-this.js";
|
|
34
|
+
import { fenceNodeModuleMutationCall, lowerRequireCacheKeys } from "./lower-node-module.js";
|
|
35
|
+
export function generatorMeta(lowerer, type) {
|
|
36
|
+
const resultType = genResultRecord(type.yieldT, type.retT, lowerer.shapes, lowerer.unions);
|
|
37
|
+
if (resultType === null) {
|
|
38
|
+
throw new InternalCompilerError("lowerer bug: mapped generator without an IteratorResult record");
|
|
39
|
+
}
|
|
40
|
+
return { yieldT: type.yieldT, nextT: type.nextT, resultType };
|
|
41
|
+
}
|
|
29
42
|
/** Instantiation cap per generic function: same-key recursion (`len<T>`
|
|
30
43
|
* calling itself) converges, but POLYMORPHIC recursion (`f<T>` calling
|
|
31
44
|
* `f<T[]>`) would request new instances forever — the cap turns that into a
|
|
@@ -101,7 +114,7 @@ export function paramShape(lowerer, param) {
|
|
|
101
114
|
}
|
|
102
115
|
return { type: abi, mode: "omittable", bodyType };
|
|
103
116
|
}
|
|
104
|
-
return { type: lowerer.irTypeOf(param.name), mode: "required" };
|
|
117
|
+
return { type: lowerer.runtimeOptionalBindingType(param.name, lowerer.irTypeOf(param.name)), mode: "required" };
|
|
105
118
|
}
|
|
106
119
|
if (param.dotDotDotToken) {
|
|
107
120
|
// A JS rest param with no static element type (`(...args)` — any[]):
|
|
@@ -124,7 +137,7 @@ export function paramShape(lowerer, param) {
|
|
|
124
137
|
return { type: DYN, mode: "dynRest" };
|
|
125
138
|
}
|
|
126
139
|
}
|
|
127
|
-
const type = lowerer.irTypeOf(param.name);
|
|
140
|
+
const type = lowerer.runtimeOptionalBindingType(param.name, lowerer.irTypeOf(param.name));
|
|
128
141
|
// Tuple-typed rest params don't map to an array; generic rest is the
|
|
129
142
|
// generic path's business. Anything non-array here is unmappable.
|
|
130
143
|
if (type.kind !== "array")
|
|
@@ -167,7 +180,7 @@ export function paramShape(lowerer, param) {
|
|
|
167
180
|
}
|
|
168
181
|
return { type: abi, mode: "omittable", bodyType };
|
|
169
182
|
}
|
|
170
|
-
const type = lowerer.irTypeOf(param.name);
|
|
183
|
+
const type = lowerer.runtimeOptionalBindingType(param.name, lowerer.irTypeOf(param.name));
|
|
171
184
|
if (param.questionToken && !lowerer.bareUndefinedArmedUnion(type) && type.kind !== "dyn" && type.kind !== "jsval") {
|
|
172
185
|
// `x?: unknown` where unknown came from an annotation: undefined is
|
|
173
186
|
// absorbed into the hole type, so no undefined ARM exists — but a
|
|
@@ -195,7 +208,7 @@ export function paramShapes(lowerer, params, signature, blameOf) {
|
|
|
195
208
|
return params.map((declParam, i) => {
|
|
196
209
|
const symbol = signature.getParameters()[i];
|
|
197
210
|
const tsType = symbol ? lowerer.checker.getTypeOfSymbol(symbol) : lowerer.typeOf(declParam.name);
|
|
198
|
-
const mapped = lowerer.mapTypeOf(tsType);
|
|
211
|
+
const mapped = lowerer.runtimeOptionalBindingType(declParam.name, lowerer.mapTypeOf(tsType) ?? lowerer.irTypeOf(declParam.name));
|
|
199
212
|
if (!mapped || mapped.kind === "void")
|
|
200
213
|
lowerer.badType(blameOf?.(declParam, i) ?? declParam.name, tsType);
|
|
201
214
|
if (declParam.dotDotDotToken) {
|
|
@@ -585,6 +598,16 @@ export function appendImplicitUndefinedReturn(lowerer, body, bodyReturn, loc) {
|
|
|
585
598
|
/** A declaration's checker-derived IR return type. The unmappable-type
|
|
586
599
|
* diagnostic points at `blame` (the name for top-level declarations, the
|
|
587
600
|
* whole node for lambda-likes — preserving each caller's historical loc). */
|
|
601
|
+
function hasExplicitJsDocReturn(decl) {
|
|
602
|
+
const sourceFile = decl.getSourceFile();
|
|
603
|
+
return /@returns?\b/.test(sourceFile.text.slice(decl.pos, decl.getStart(sourceFile)));
|
|
604
|
+
}
|
|
605
|
+
function promiseCarriesDyn(lowerer, type) {
|
|
606
|
+
if (type.kind === "promise")
|
|
607
|
+
return type.inner.kind === "dyn";
|
|
608
|
+
return type.kind === "union" &&
|
|
609
|
+
(lowerer.unions.get(type.unionId)?.arms.some((arm) => promiseCarriesDyn(lowerer, arm)) ?? false);
|
|
610
|
+
}
|
|
588
611
|
export function declaredReturnType(lowerer, decl, blame) {
|
|
589
612
|
const sig = lowerer.checker.getSignatureFromDeclaration(decl);
|
|
590
613
|
if (!sig)
|
|
@@ -596,6 +619,17 @@ export function declaredReturnType(lowerer, decl, blame) {
|
|
|
596
619
|
// (`.action(() => { throw ... })`). `never` VALUES stay unmapped.
|
|
597
620
|
if (retTsType.flags & ts.TypeFlags.Never)
|
|
598
621
|
return VOID;
|
|
622
|
+
const mappedReturn = lowerer.mapTypeOf(retTsType);
|
|
623
|
+
if (isJsSourceFile(decl.getSourceFile()) &&
|
|
624
|
+
!hasExplicitJsDocReturn(decl) &&
|
|
625
|
+
mappedReturn !== null &&
|
|
626
|
+
promiseCarriesDyn(lowerer, mappedReturn) &&
|
|
627
|
+
decl.parameters.some((param) => {
|
|
628
|
+
const mapped = lowerer.mapTypeOf(lowerer.typeOf(param.name));
|
|
629
|
+
return mapped === null || mapped.kind === "dyn";
|
|
630
|
+
})) {
|
|
631
|
+
return DYN;
|
|
632
|
+
}
|
|
599
633
|
// A JS function whose UNANNOTATED return infers a FUNCTION type
|
|
600
634
|
// (test/common's mustCall — tsc infers `() => any` from the wrapper
|
|
601
635
|
// it returns): the inferred arity is the wrapper's spelling, not a
|
|
@@ -691,9 +725,6 @@ export function collectSignatureInner(lowerer, decl) {
|
|
|
691
725
|
return;
|
|
692
726
|
const isAsync = decl.modifiers?.some((m) => m.kind === ts.SyntaxKind.AsyncKeyword) === true;
|
|
693
727
|
const isGenerator = decl.asteriskToken !== undefined;
|
|
694
|
-
if (isGenerator && isAsync) {
|
|
695
|
-
lowerer.unsupported("SC1071", decl, "async generators (async function*)");
|
|
696
|
-
}
|
|
697
728
|
if (decl.typeParameters) {
|
|
698
729
|
// Generic async composes: each monomorphized instance is an async
|
|
699
730
|
// IrFunction like any other — its own spawn wrapper, its body
|
|
@@ -742,10 +773,11 @@ export function collectSignatureInner(lowerer, decl) {
|
|
|
742
773
|
}
|
|
743
774
|
const nameBlame = decl.name ?? decl;
|
|
744
775
|
const returnType = lowerer.declaredReturnType(decl, nameBlame);
|
|
745
|
-
if (isAsync && returnType.kind !== "promise") {
|
|
776
|
+
if (isAsync && !isGenerator && returnType.kind !== "promise") {
|
|
746
777
|
lowerer.badType(nameBlame, lowerer.typeOf(nameBlame));
|
|
747
778
|
}
|
|
748
|
-
if (isGenerator &&
|
|
779
|
+
if (isGenerator &&
|
|
780
|
+
(returnType.kind !== "generator" || (returnType.async === true) !== isAsync)) {
|
|
749
781
|
lowerer.badType(nameBlame, lowerer.typeOf(nameBlame));
|
|
750
782
|
}
|
|
751
783
|
const symbol = declSymbolOf(lowerer, decl);
|
|
@@ -761,7 +793,7 @@ export function collectSignatureInner(lowerer, decl) {
|
|
|
761
793
|
returnType,
|
|
762
794
|
isAsync,
|
|
763
795
|
...(isGenerator && returnType.kind === "generator"
|
|
764
|
-
? { generator:
|
|
796
|
+
? { generator: generatorMeta(lowerer, returnType) }
|
|
765
797
|
: {}),
|
|
766
798
|
});
|
|
767
799
|
}
|
|
@@ -1172,17 +1204,15 @@ export function lowerGenericInstance(lowerer, info, inst) {
|
|
|
1172
1204
|
// and awaits park this instance's fibers.
|
|
1173
1205
|
const isAsync = decl.modifiers?.some((m) => m.kind === ts.SyntaxKind.AsyncKeyword) === true;
|
|
1174
1206
|
const nameBlame = (ts.isArrowFunction(decl) ? undefined : decl.name) ?? decl;
|
|
1175
|
-
|
|
1207
|
+
const isGenerator = decl.asteriskToken !== undefined;
|
|
1208
|
+
if (isAsync && !isGenerator && inst.returnType.kind !== "promise") {
|
|
1176
1209
|
lowerer.badType(nameBlame, lowerer.checker.getTypeAtLocation(nameBlame));
|
|
1177
1210
|
}
|
|
1178
1211
|
// A generic GENERATOR instance mirrors async: the body returns the
|
|
1179
1212
|
// resolved TReturn channel, calls enter through the instance's own
|
|
1180
1213
|
// gen-spawn wrapper (the emitter routes by fn.generator).
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
lowerer.unsupported("SC1071", decl, "async generators (async function*)");
|
|
1184
|
-
}
|
|
1185
|
-
if (isGenerator && inst.returnType.kind !== "generator") {
|
|
1214
|
+
if (isGenerator &&
|
|
1215
|
+
(inst.returnType.kind !== "generator" || (inst.returnType.async === true) !== isAsync)) {
|
|
1186
1216
|
lowerer.badType(nameBlame, lowerer.checker.getTypeAtLocation(nameBlame));
|
|
1187
1217
|
}
|
|
1188
1218
|
let bodyReturn = isGenerator
|
|
@@ -1198,7 +1228,7 @@ export function lowerGenericInstance(lowerer, info, inst) {
|
|
|
1198
1228
|
if (cls && info.member.kind === "method")
|
|
1199
1229
|
lowerer.currentClass = cls;
|
|
1200
1230
|
if (isGenerator && inst.returnType.kind === "generator") {
|
|
1201
|
-
fnCtx.generator =
|
|
1231
|
+
fnCtx.generator = generatorMeta(lowerer, inst.returnType);
|
|
1202
1232
|
}
|
|
1203
1233
|
lowerer.fnStack.push(fnCtx);
|
|
1204
1234
|
try {
|
|
@@ -1437,6 +1467,9 @@ export function lowerGenericFnValue(lowerer, ref, info) {
|
|
|
1437
1467
|
fenceUnpinned();
|
|
1438
1468
|
const bindings = new Map();
|
|
1439
1469
|
unifySignatureBindings(lowerer, info, target, bindings);
|
|
1470
|
+
const hofBinding = runtimeOptionalHofGenericBinding(lowerer, ref, info);
|
|
1471
|
+
if (hofBinding)
|
|
1472
|
+
bindings.set(hofBinding.typeParam, hofBinding.type);
|
|
1440
1473
|
bindDefaultTypeParams(lowerer, info.typeParams, info.decl.typeParameters, bindings);
|
|
1441
1474
|
// A pinning signature that itself keeps type parameters (`let g: <T>(x:
|
|
1442
1475
|
// T) => T = identity` — storing the generic signature as such) binds
|
|
@@ -1457,6 +1490,31 @@ export function lowerGenericFnValue(lowerer, ref, info) {
|
|
|
1457
1490
|
lowerer.noteEdge(inst.name);
|
|
1458
1491
|
return { kind: "closure", fnName: inst.name, captures: [], type: funcType, loc };
|
|
1459
1492
|
}
|
|
1493
|
+
function runtimeOptionalHofGenericBinding(lowerer, ref, info) {
|
|
1494
|
+
let argument = ref;
|
|
1495
|
+
while (argument.parent && ts.isParenthesizedExpression(argument.parent))
|
|
1496
|
+
argument = argument.parent;
|
|
1497
|
+
const call = argument.parent;
|
|
1498
|
+
if (!ts.isCallExpression(call) || call.arguments[0] !== argument)
|
|
1499
|
+
return null;
|
|
1500
|
+
if (!ts.isPropertyAccessExpression(call.expression) || call.expression.name.text !== "map")
|
|
1501
|
+
return null;
|
|
1502
|
+
if (!lowerer.isStdlibMember(call.expression))
|
|
1503
|
+
return null;
|
|
1504
|
+
const receiver = lowerer.mapTypeOf(lowerer.typeOf(call.expression.expression));
|
|
1505
|
+
if (receiver?.kind !== "array")
|
|
1506
|
+
return null;
|
|
1507
|
+
const parameter = info.decl.parameters[0];
|
|
1508
|
+
if (!parameter || !ts.isIdentifier(parameter.name))
|
|
1509
|
+
return null;
|
|
1510
|
+
const parameterType = lowerer.typeOf(parameter.name);
|
|
1511
|
+
if ((parameterType.flags & ts.TypeFlags.TypeParameter) === 0)
|
|
1512
|
+
return null;
|
|
1513
|
+
const typeParam = parameterType.getSymbol();
|
|
1514
|
+
if (!typeParam || !info.typeParams.includes(typeParam))
|
|
1515
|
+
return null;
|
|
1516
|
+
return { typeParam, type: lowerer.runtimeOptionalType(receiver.elem) };
|
|
1517
|
+
}
|
|
1460
1518
|
/** The instance a pinned VALUE reference names: the declaration's modes
|
|
1461
1519
|
* over the DECLARED types mapped under the bindings (mapType's resolver
|
|
1462
1520
|
* substitutes — the instance-body trick), which is the same result the
|
|
@@ -1595,6 +1653,15 @@ function paramWrittenInBody(lowerer, body, sym, name) {
|
|
|
1595
1653
|
walk(body);
|
|
1596
1654
|
return written;
|
|
1597
1655
|
}
|
|
1656
|
+
function broadPromiseParam(lowerer, type) {
|
|
1657
|
+
const mapped = lowerer.mapTypeOf(type);
|
|
1658
|
+
const arms = mapped?.kind === "union"
|
|
1659
|
+
? lowerer.unions.get(mapped.unionId)?.arms
|
|
1660
|
+
: mapped === null ? undefined : [mapped];
|
|
1661
|
+
return !!arms &&
|
|
1662
|
+
arms.some((arm) => arm.kind === "promise" && arm.inner.kind === "dyn") &&
|
|
1663
|
+
arms.every((arm) => isUnitType(arm) || (arm.kind === "promise" && arm.inner.kind === "dyn"));
|
|
1664
|
+
}
|
|
1598
1665
|
/** The implicit-type-parameter slots of a JS function-like: parallel to
|
|
1599
1666
|
* decl.parameters, the param SYMBOL where the slot is a bindable
|
|
1600
1667
|
* implicit-any param (identifier-named, no annotation/JSDoc type, not
|
|
@@ -1623,7 +1690,10 @@ export function implicitAnyParamSymbolsOf(lowerer, decl) {
|
|
|
1623
1690
|
if (param.name.text === "this")
|
|
1624
1691
|
return null;
|
|
1625
1692
|
const t = lowerer.typeOf(param.name);
|
|
1626
|
-
|
|
1693
|
+
const broadFunction = lowerer.checker.typeToString(t) === "Function";
|
|
1694
|
+
const broadArray = lowerer.checkerAnyArrayType(t);
|
|
1695
|
+
const broadPromise = broadPromiseParam(lowerer, t);
|
|
1696
|
+
if ((t.flags & ts.TypeFlags.Any) === 0 && !broadFunction && !broadArray && !broadPromise)
|
|
1627
1697
|
return null;
|
|
1628
1698
|
const sym = lowerer.checker.getSymbolAtLocation(param.name);
|
|
1629
1699
|
if (!sym)
|
|
@@ -1642,13 +1712,54 @@ export function implicitAnyParamSymbolsOf(lowerer, decl) {
|
|
|
1642
1712
|
* selects return INFERENCE with DYN as the recursion pin. */
|
|
1643
1713
|
function implicitDeclaredReturn(lowerer, info) {
|
|
1644
1714
|
try {
|
|
1715
|
+
const broadCallbackSymbols = new Set(info.decl.parameters.flatMap((param, index) => {
|
|
1716
|
+
const symbol = info.implicitParams?.[index];
|
|
1717
|
+
return symbol !== null && symbol !== undefined &&
|
|
1718
|
+
lowerer.checker.typeToString(lowerer.typeOf(param.name)) === "Function"
|
|
1719
|
+
? [symbol]
|
|
1720
|
+
: [];
|
|
1721
|
+
}));
|
|
1722
|
+
let returnsBroadCallback = false;
|
|
1723
|
+
if (broadCallbackSymbols.size > 0 && info.decl.body !== undefined) {
|
|
1724
|
+
ts.walkPreorder(info.decl.body, (node) => {
|
|
1725
|
+
if (node !== info.decl.body && ts.isFunctionLike(node))
|
|
1726
|
+
return "skip";
|
|
1727
|
+
if (!ts.isReturnStatement(node) || node.expression === undefined)
|
|
1728
|
+
return undefined;
|
|
1729
|
+
let expression = node.expression;
|
|
1730
|
+
while (ts.isParenthesizedExpression(expression))
|
|
1731
|
+
expression = expression.expression;
|
|
1732
|
+
if (ts.isCallExpression(expression) &&
|
|
1733
|
+
ts.isIdentifier(expression.expression) &&
|
|
1734
|
+
broadCallbackSymbols.has(lowerer.checker.getSymbolAtLocation(expression.expression) ?? {})) {
|
|
1735
|
+
returnsBroadCallback = true;
|
|
1736
|
+
return "stop";
|
|
1737
|
+
}
|
|
1738
|
+
return undefined;
|
|
1739
|
+
});
|
|
1740
|
+
}
|
|
1741
|
+
if (returnsBroadCallback)
|
|
1742
|
+
return null;
|
|
1645
1743
|
const declSig = lowerer.checker.getSignatureFromDeclaration(info.decl);
|
|
1646
1744
|
if (!declSig)
|
|
1647
1745
|
return null;
|
|
1648
1746
|
const retTs = lowerer.checker.getReturnTypeOfSignature(declSig);
|
|
1649
1747
|
if (retTs.flags & ts.TypeFlags.Any)
|
|
1650
1748
|
return null;
|
|
1651
|
-
|
|
1749
|
+
if (lowerer.checker.isArrayType(retTs)) {
|
|
1750
|
+
const elem = lowerer.checker.getTypeArguments(retTs)[0];
|
|
1751
|
+
// An implicit-any parameter poisons an inferred array result to
|
|
1752
|
+
// any[] even when this instance's body produces one concrete
|
|
1753
|
+
// element type (`knownBy(cmd)` in commander). Let the existing
|
|
1754
|
+
// lowered-return unifier recover that type. Explicit unknown[]
|
|
1755
|
+
// remains a declared checked-dynamic contract and stays pinned.
|
|
1756
|
+
if (elem && (elem.flags & ts.TypeFlags.Any) !== 0)
|
|
1757
|
+
return null;
|
|
1758
|
+
}
|
|
1759
|
+
const mapped = lowerer.mapTypeOf(retTs);
|
|
1760
|
+
if (mapped !== null && promiseCarriesDyn(lowerer, mapped) && !hasExplicitJsDocReturn(info.decl))
|
|
1761
|
+
return null;
|
|
1762
|
+
return mapped;
|
|
1652
1763
|
}
|
|
1653
1764
|
catch (e) {
|
|
1654
1765
|
if (!(e instanceof PoisonError))
|
|
@@ -1656,6 +1767,19 @@ function implicitDeclaredReturn(lowerer, info) {
|
|
|
1656
1767
|
return null;
|
|
1657
1768
|
}
|
|
1658
1769
|
}
|
|
1770
|
+
/** True when a `this.method(...)` call targets an implicit npm-static
|
|
1771
|
+
* method whose result is settled from its lowered body rather than the
|
|
1772
|
+
* checker declaration. Uninitialized-local inference uses this to avoid
|
|
1773
|
+
* freezing an evolving `any` slot to stale JSDoc. */
|
|
1774
|
+
export function implicitMethodCallInfersReturn(lowerer, call) {
|
|
1775
|
+
if (!ts.isPropertyAccessExpression(call.expression) ||
|
|
1776
|
+
call.expression.expression.kind !== ts.SyntaxKind.ThisKeyword ||
|
|
1777
|
+
lowerer.currentClass === null) {
|
|
1778
|
+
return false;
|
|
1779
|
+
}
|
|
1780
|
+
const found = findGenericMethodOn(lowerer, lowerer.currentClass, call.expression.name.text);
|
|
1781
|
+
return found?.info.implicitParams !== undefined && implicitDeclaredReturn(lowerer, found.info) === null;
|
|
1782
|
+
}
|
|
1659
1783
|
/** True when an IR type may BIND an implicit param (a concrete static
|
|
1660
1784
|
* type — the checked-dynamic kinds keep the dyn slot, units have no
|
|
1661
1785
|
* standalone representation). */
|
|
@@ -1681,15 +1805,37 @@ export function implicitCallInstance(lowerer, call, info) {
|
|
|
1681
1805
|
return;
|
|
1682
1806
|
}
|
|
1683
1807
|
let bound = DYN;
|
|
1808
|
+
const declared = lowerer.paramShape(param);
|
|
1809
|
+
if ((lowerer.typeOf(param.name).flags & ts.TypeFlags.Any) === 0)
|
|
1810
|
+
bound = declared.type;
|
|
1684
1811
|
const arg = call.arguments[i];
|
|
1685
1812
|
if (arg && !ts.isSpreadElement(arg)) {
|
|
1813
|
+
const runtimeLocal = ts.isIdentifier(arg) ? lowerer.peekLocal(arg) : null;
|
|
1814
|
+
if (runtimeLocal?.type.kind === "dyn") {
|
|
1815
|
+
bound = DYN;
|
|
1816
|
+
argTypes.set(sym, lowerer.checker.getUnknownType());
|
|
1817
|
+
shapes.push({ type: bound, mode: "required" });
|
|
1818
|
+
return;
|
|
1819
|
+
}
|
|
1686
1820
|
// The argument's own checker type, literal-widened ('add' binds
|
|
1687
1821
|
// string) — typeOf consults the ACTIVE instance's bindings, so a
|
|
1688
1822
|
// bound param forwarded into another implicit call transitively
|
|
1689
1823
|
// instantiates it (this._initCommandGroup(command)).
|
|
1690
1824
|
const t = lowerer.checker.getBaseTypeOfLiteralType(lowerer.typeOf(arg));
|
|
1691
|
-
const mapped = lowerer.mapTypeOf(t);
|
|
1692
|
-
if (
|
|
1825
|
+
const mapped = lowerer.mapTypeOf(t) ?? dynFallbackType(lowerer, arg, t);
|
|
1826
|
+
if (ts.isArrowFunction(arg) &&
|
|
1827
|
+
arg.type === undefined &&
|
|
1828
|
+
mapped?.kind === "func" &&
|
|
1829
|
+
promiseCarriesDyn(lowerer, mapped.ret)) {
|
|
1830
|
+
bound = { ...mapped, ret: DYN };
|
|
1831
|
+
lowerer.runtimeOptionalFunctionReturns.set(arg, DYN);
|
|
1832
|
+
argTypes.set(sym, t);
|
|
1833
|
+
}
|
|
1834
|
+
else if (mapped?.kind === "dyn") {
|
|
1835
|
+
bound = DYN;
|
|
1836
|
+
argTypes.set(sym, t);
|
|
1837
|
+
}
|
|
1838
|
+
else if (bindableImplicitIr(mapped)) {
|
|
1693
1839
|
bound = mapped;
|
|
1694
1840
|
argTypes.set(sym, t);
|
|
1695
1841
|
}
|
|
@@ -1715,7 +1861,11 @@ function internImplicitInstance(lowerer, blame, info, shapes, argTypes) {
|
|
|
1715
1861
|
`${MAX_GENERIC_INSTANCES} instances — polymorphic recursion?)`);
|
|
1716
1862
|
}
|
|
1717
1863
|
const rendered = shapes.map((s) => lowerer.fmt(s.type)).join(", ");
|
|
1718
|
-
const
|
|
1864
|
+
const dynamicBroadPromise = info.decl.parameters.some((param, index) => info.implicitParams?.[index] !== null &&
|
|
1865
|
+
info.implicitParams?.[index] !== undefined &&
|
|
1866
|
+
shapes[index]?.type.kind === "dyn" &&
|
|
1867
|
+
broadPromiseParam(lowerer, lowerer.typeOf(param.name)));
|
|
1868
|
+
const declared = dynamicBroadPromise ? null : implicitDeclaredReturn(lowerer, info);
|
|
1719
1869
|
inst = {
|
|
1720
1870
|
name: `${info.qualifiedName}%${info.instances.size}`,
|
|
1721
1871
|
ordinal: info.instances.size,
|
|
@@ -2684,6 +2834,11 @@ export function lowerCall(lowerer, expr) {
|
|
|
2684
2834
|
if (crServed)
|
|
2685
2835
|
return crServed;
|
|
2686
2836
|
}
|
|
2837
|
+
{
|
|
2838
|
+
const resolved = lowerImportMetaResolveCall(lowerer, expr) ?? lowerRequireResolveCall(lowerer, expr);
|
|
2839
|
+
if (resolved)
|
|
2840
|
+
return resolved;
|
|
2841
|
+
}
|
|
2687
2842
|
// `process.getuid?.()` — intercepted BEFORE the optional-chain
|
|
2688
2843
|
// machinery (the member always exists on a POSIX target, so the
|
|
2689
2844
|
// optional call IS the call; `process.getuid` itself has no value
|
|
@@ -3044,6 +3199,9 @@ export function lowerCall(lowerer, expr) {
|
|
|
3044
3199
|
if (arg.type.kind === "string") {
|
|
3045
3200
|
return { kind: "libCall", fn: "num.fromString", args: [arg], type: F64, loc };
|
|
3046
3201
|
}
|
|
3202
|
+
const optionalNumber = lowerOptionalStringNumber(lowerer, arg, loc);
|
|
3203
|
+
if (optionalNumber)
|
|
3204
|
+
return optionalNumber;
|
|
3047
3205
|
lowerer.noLowering(`Number of ${lowerer.fmt(arg.type)} values`, argNode, arg.type.kind === "union"
|
|
3048
3206
|
? "numbers, booleans, and strings lower (the full ToNumber string grammar included) — narrow the union first"
|
|
3049
3207
|
: undefined);
|
|
@@ -3110,7 +3268,7 @@ export function lowerCall(lowerer, expr) {
|
|
|
3110
3268
|
!expr.expression.questionDotToken &&
|
|
3111
3269
|
!expr.questionDotToken &&
|
|
3112
3270
|
!expr.arguments.some((a) => ts.isSpreadElement(a))) {
|
|
3113
|
-
const recvProbe =
|
|
3271
|
+
const recvProbe = tryLowerExpression(lowerer, expr.expression.expression);
|
|
3114
3272
|
if (recvProbe?.type.kind === "dyn") {
|
|
3115
3273
|
const args = expr.arguments.map((a) => lowerer.lowerExprExpecting(a, DYN));
|
|
3116
3274
|
return {
|
|
@@ -3256,6 +3414,9 @@ export function lowerCall(lowerer, expr) {
|
|
|
3256
3414
|
const cryptoServed = lowerer.lowerCryptoModuleCall(expr, bi, loc);
|
|
3257
3415
|
if (cryptoServed)
|
|
3258
3416
|
return cryptoServed;
|
|
3417
|
+
const timersInterval = lowerer.lowerTimersPromisesSetInterval(expr, bi, loc);
|
|
3418
|
+
if (timersInterval)
|
|
3419
|
+
return timersInterval;
|
|
3259
3420
|
const builtinFn = builtinModuleFnOf(lowerer, bi.module, bi.member);
|
|
3260
3421
|
if (!builtinFn) {
|
|
3261
3422
|
// Typed by @types/node (the fallback declarations only declare
|
|
@@ -3335,7 +3496,7 @@ export function lowerCall(lowerer, expr) {
|
|
|
3335
3496
|
const radix = expr.arguments[1]
|
|
3336
3497
|
? lowerer.lowerExprExpecting(expr.arguments[1], F64)
|
|
3337
3498
|
: { kind: "numLit", value: 0, type: F64, loc };
|
|
3338
|
-
const optional =
|
|
3499
|
+
const optional = optionalCallValue(lowerer, expr.arguments[0]);
|
|
3339
3500
|
if (optional?.type.kind === "union") {
|
|
3340
3501
|
const def = lowerer.unions.get(optional.type.unionId);
|
|
3341
3502
|
const stringTag = def?.arms.findIndex((arm) => arm.kind === "string") ?? -1;
|
|
@@ -3403,7 +3564,15 @@ export function lowerCall(lowerer, expr) {
|
|
|
3403
3564
|
expr.arguments.length === 1 &&
|
|
3404
3565
|
lowerer.isStdlibSymbol(lowerer.resolveValueSymbol(expr.expression) ?? undefined)) {
|
|
3405
3566
|
const name = expr.expression.text;
|
|
3406
|
-
|
|
3567
|
+
if (name === "parseFloat") {
|
|
3568
|
+
const optional = optionalCallValue(lowerer, expr.arguments[0]);
|
|
3569
|
+
if (optional) {
|
|
3570
|
+
const parsed = lowerOptionalStringNumber(lowerer, optional, loc, "num.parseFloat", "parseFloat");
|
|
3571
|
+
if (parsed)
|
|
3572
|
+
return parsed;
|
|
3573
|
+
}
|
|
3574
|
+
}
|
|
3575
|
+
const probed = tryLowerExpression(lowerer, expr.arguments[0]);
|
|
3407
3576
|
if (name === "parseFloat" && probed?.type.kind === "string") {
|
|
3408
3577
|
return { kind: "libCall", fn: "num.parseFloat", args: [probed], type: F64, loc };
|
|
3409
3578
|
}
|
|
@@ -3433,13 +3602,12 @@ export function lowerCall(lowerer, expr) {
|
|
|
3433
3602
|
const loc = locOf(expr);
|
|
3434
3603
|
const argNode = expr.arguments[0];
|
|
3435
3604
|
if (name === "decodeURIComponent") {
|
|
3436
|
-
const d = lowerer.lowerExpr(argNode);
|
|
3437
|
-
|
|
3438
|
-
|
|
3439
|
-
}
|
|
3440
|
-
return { kind: "libCall", fn: "str.decodeUriComponent", args: [d], type: STRING, loc };
|
|
3605
|
+
const d = optionalCallValue(lowerer, argNode) ?? lowerer.lowerExpr(argNode);
|
|
3606
|
+
const s = lowerer.ensureString(d, argNode);
|
|
3607
|
+
return { kind: "libCall", fn: "str.decodeUriComponent", args: [s], type: STRING, loc };
|
|
3441
3608
|
}
|
|
3442
|
-
const
|
|
3609
|
+
const value = optionalCallValue(lowerer, argNode) ?? lowerer.lowerExpr(argNode);
|
|
3610
|
+
const s = lowerer.ensureString(value, argNode);
|
|
3443
3611
|
return {
|
|
3444
3612
|
kind: "libCall",
|
|
3445
3613
|
fn: name === "encodeURIComponent" ? "str.encodeUriComponent" : "str.encodeUri",
|
|
@@ -3718,12 +3886,12 @@ export function lowerCall(lowerer, expr) {
|
|
|
3718
3886
|
return { kind: "callValue", callee, args, type: callee.type.ret, loc };
|
|
3719
3887
|
}
|
|
3720
3888
|
if (ts.isPropertyAccessExpression(expr.expression)) {
|
|
3721
|
-
const intrinsic =
|
|
3722
|
-
|
|
3723
|
-
|
|
3724
|
-
|
|
3725
|
-
|
|
3726
|
-
|
|
3889
|
+
const intrinsic = fenceNodeModuleMutationCall(lowerer, expr, expr.expression) ??
|
|
3890
|
+
// Builtin namespace imports first (`fs.readFileSync(...)` where fs
|
|
3891
|
+
// is `import * as fs from "node:fs"`): the same tables and fences
|
|
3892
|
+
// as named builtin imports — before anything below tries to lower
|
|
3893
|
+
// the namespace object itself as a receiver.
|
|
3894
|
+
lowerer.lowerNamespaceBuiltinCall(expr, expr.expression) ??
|
|
3727
3895
|
// The node:perf_hooks spoke: performance.now() and its
|
|
3728
3896
|
// .bind(performance) function value over the runtime's
|
|
3729
3897
|
// process-start-anchored monotonic clock.
|
|
@@ -3750,7 +3918,7 @@ export function lowerCall(lowerer, expr) {
|
|
|
3750
3918
|
lowerPromiseRejectCall(lowerer, expr, expr.expression) ??
|
|
3751
3919
|
// Before the island path: regex-argument replace/replaceAll/split
|
|
3752
3920
|
// lower STATICALLY; only the string-pattern overloads are island.
|
|
3753
|
-
lowerer
|
|
3921
|
+
lowerRegexMethodCallWithOptionalArg(lowerer, expr, expr.expression) ??
|
|
3754
3922
|
lowerer.lowerUrlMethodCall(expr, expr.expression) ??
|
|
3755
3923
|
lowerer.lowerSearchParamsMethodCall(expr, expr.expression) ??
|
|
3756
3924
|
lowerer.lowerStatsMethodCall(expr, expr.expression) ??
|
|
@@ -3789,11 +3957,11 @@ export function lowerCall(lowerer, expr) {
|
|
|
3789
3957
|
// TestContext surface (t.test/t.skip/t.diagnostic), t.assert.*.
|
|
3790
3958
|
lowerer.lowerTestMethodCall(expr, expr.expression) ??
|
|
3791
3959
|
lowerer.lowerTimeoutMethodCall(expr, expr.expression) ??
|
|
3792
|
-
lowerer
|
|
3960
|
+
lowerStringMethodCallWithOptionalArgs(lowerer, expr, expr.expression) ??
|
|
3793
3961
|
// Typed-array/Buffer receivers and the Buffer statics — before the
|
|
3794
3962
|
// island path (bytes never cross the boundary).
|
|
3795
3963
|
lowerer.lowerBytesMethodCall(expr, expr.expression) ??
|
|
3796
|
-
lowerer
|
|
3964
|
+
lowerBufferStaticCallWithOptionalArg(lowerer, expr, expr.expression) ??
|
|
3797
3965
|
// URL.revokeObjectURL's zero-argument contract (the one-argument
|
|
3798
3966
|
// form keeps the fence — createObjectURL does too).
|
|
3799
3967
|
lowerUrlStaticCall(lowerer, expr, expr.expression) ??
|
|
@@ -4057,6 +4225,160 @@ export function lowerCall(lowerer, expr) {
|
|
|
4057
4225
|
}
|
|
4058
4226
|
return { kind: "callValue", callee, args, type: callee.type.ret, loc };
|
|
4059
4227
|
}
|
|
4228
|
+
function lowerRegexMethodCallWithOptionalArg(lowerer, call, access) {
|
|
4229
|
+
const lowered = lowerer.lowerRegexMethodCall(call, access);
|
|
4230
|
+
if (lowered?.kind !== "regexIntrinsic" || lowered.method !== "test" || call.arguments.length !== 1)
|
|
4231
|
+
return lowered;
|
|
4232
|
+
const subject = lowered.args[0];
|
|
4233
|
+
if (subject?.type.kind !== "union" || lowerer.armTag(subject.type.unionId, UNDEFINED_T) < 0)
|
|
4234
|
+
return lowered;
|
|
4235
|
+
if (lowerer.mapTypeOf(lowerer.typeOf(call.arguments[0]))?.kind !== "string")
|
|
4236
|
+
return lowered;
|
|
4237
|
+
const present = lowerer.stripUndefinedArm(subject.type);
|
|
4238
|
+
if (present.kind !== "string")
|
|
4239
|
+
return lowered;
|
|
4240
|
+
return {
|
|
4241
|
+
...lowered,
|
|
4242
|
+
args: [lowerer.ensureString(subject, call.arguments[0])],
|
|
4243
|
+
};
|
|
4244
|
+
}
|
|
4245
|
+
function optionalCallValue(lowerer, node) {
|
|
4246
|
+
return lowerer.runtimeOptionalIdentifierValue(node)?.value ?? lowerAbsenceProbe(lowerer, node);
|
|
4247
|
+
}
|
|
4248
|
+
function lowerBufferStaticCallWithOptionalArg(lowerer, call, access) {
|
|
4249
|
+
const lowered = lowerer.lowerBufferStaticCall(call, access);
|
|
4250
|
+
if (lowered?.kind !== "bytesNew" || !lowered.source || lowered.source.type.kind !== "union")
|
|
4251
|
+
return lowered;
|
|
4252
|
+
const present = lowerer.stripUndefinedArm(lowered.source.type);
|
|
4253
|
+
const validSource = (present.kind === "array" && present.elem.kind === "f64") ||
|
|
4254
|
+
(present.kind === "bytes" && present.elem === "u8");
|
|
4255
|
+
if (!validSource)
|
|
4256
|
+
return lowered;
|
|
4257
|
+
const helper = lowerer.narrowedArmHelper(lowered.source.type.unionId, present, lowered.source.loc);
|
|
4258
|
+
return helper
|
|
4259
|
+
? {
|
|
4260
|
+
...lowered,
|
|
4261
|
+
source: { kind: "call", callee: helper, args: [lowered.source], type: present, loc: lowered.source.loc },
|
|
4262
|
+
}
|
|
4263
|
+
: lowered;
|
|
4264
|
+
}
|
|
4265
|
+
function lowerOptionalNumberDefault(lowerer, value, dflt, loc) {
|
|
4266
|
+
const widened = lowerer.runtimeOptionalWidening(value.type, F64);
|
|
4267
|
+
if (!widened || widened.kind !== "union")
|
|
4268
|
+
return null;
|
|
4269
|
+
const numberTag = lowerer.armTag(widened.unionId, F64);
|
|
4270
|
+
const undefinedTag = lowerer.armTag(widened.unionId, UNDEFINED_T);
|
|
4271
|
+
if (numberTag < 0 || undefinedTag < 0)
|
|
4272
|
+
return null;
|
|
4273
|
+
const key = `number.optionalDefault:${widened.unionId}:${dflt}`;
|
|
4274
|
+
let helper = lowerer.widthHelpers.get(key);
|
|
4275
|
+
if (!helper) {
|
|
4276
|
+
helper = `%number.optionalDefault.${lowerer.widthHelpers.size}`;
|
|
4277
|
+
lowerer.widthHelpers.set(key, helper);
|
|
4278
|
+
const input = varRef("value.0", widened, loc);
|
|
4279
|
+
lowerer.liftedFns.push({
|
|
4280
|
+
name: helper,
|
|
4281
|
+
params: [{ localId: "value.0", name: "value", type: widened }],
|
|
4282
|
+
returnType: F64,
|
|
4283
|
+
locals: [{ id: "value.0", name: "value", type: widened, mutable: false }],
|
|
4284
|
+
body: [
|
|
4285
|
+
{
|
|
4286
|
+
kind: "if",
|
|
4287
|
+
cond: { kind: "unionIsTag", unionId: widened.unionId, tag: undefinedTag, negated: false, value: input, type: BOOL, loc },
|
|
4288
|
+
then: [{ kind: "return", value: { kind: "numLit", value: dflt, type: F64, loc }, loc }],
|
|
4289
|
+
else_: null,
|
|
4290
|
+
loc,
|
|
4291
|
+
},
|
|
4292
|
+
{
|
|
4293
|
+
kind: "return",
|
|
4294
|
+
value: { kind: "unionNarrow", unionId: widened.unionId, tag: numberTag, value: input, type: F64, loc },
|
|
4295
|
+
loc,
|
|
4296
|
+
},
|
|
4297
|
+
],
|
|
4298
|
+
loc,
|
|
4299
|
+
});
|
|
4300
|
+
}
|
|
4301
|
+
return { kind: "call", callee: helper, args: [value], type: F64, loc };
|
|
4302
|
+
}
|
|
4303
|
+
function lowerStringMethodCallWithOptionalArgs(lowerer, call, access) {
|
|
4304
|
+
const lowered = lowerer.lowerStringMethodCall(call, access);
|
|
4305
|
+
if (lowered?.kind !== "strIntrinsic")
|
|
4306
|
+
return lowered;
|
|
4307
|
+
const args = [...lowered.args];
|
|
4308
|
+
let changed = false;
|
|
4309
|
+
const zeroDefaultArgs = lowered.method === "charCodeAt" || lowered.method === "charAt" ||
|
|
4310
|
+
lowered.method === "repeat" || lowered.method === "padStart" || lowered.method === "padEnd"
|
|
4311
|
+
? [0]
|
|
4312
|
+
: lowered.method === "slice" || lowered.method === "substring"
|
|
4313
|
+
? [0]
|
|
4314
|
+
: lowered.method === "indexOf" || lowered.method === "includes"
|
|
4315
|
+
? [1]
|
|
4316
|
+
: [];
|
|
4317
|
+
for (const index of zeroDefaultArgs) {
|
|
4318
|
+
const value = args[index];
|
|
4319
|
+
if (!value)
|
|
4320
|
+
continue;
|
|
4321
|
+
const coerced = lowerOptionalNumberDefault(lowerer, value, 0, value.loc);
|
|
4322
|
+
if (coerced) {
|
|
4323
|
+
args[index] = coerced;
|
|
4324
|
+
changed = true;
|
|
4325
|
+
}
|
|
4326
|
+
}
|
|
4327
|
+
if ((lowered.method === "indexOf" || lowered.method === "includes" ||
|
|
4328
|
+
lowered.method === "startsWith" || lowered.method === "endsWith") &&
|
|
4329
|
+
args[0]?.type.kind === "union" &&
|
|
4330
|
+
lowerer.runtimeOptionalWidening(args[0].type, STRING) !== null) {
|
|
4331
|
+
args[0] = lowerer.ensureString(args[0], call.arguments[0]);
|
|
4332
|
+
changed = true;
|
|
4333
|
+
}
|
|
4334
|
+
return changed ? { ...lowered, args } : lowered;
|
|
4335
|
+
}
|
|
4336
|
+
function lowerOptionalStringNumber(lowerer, arg, loc, fn = "num.fromString", label = "number") {
|
|
4337
|
+
if (arg.type.kind !== "union")
|
|
4338
|
+
return null;
|
|
4339
|
+
const def = lowerer.unions.get(arg.type.unionId);
|
|
4340
|
+
if (!def || def.arms.length !== 2)
|
|
4341
|
+
return null;
|
|
4342
|
+
const stringTag = lowerer.armTag(arg.type.unionId, STRING);
|
|
4343
|
+
const undefinedTag = lowerer.armTag(arg.type.unionId, UNDEFINED_T);
|
|
4344
|
+
if (stringTag < 0 || undefinedTag < 0)
|
|
4345
|
+
return null;
|
|
4346
|
+
const key = `${label}.optionalString:${arg.type.unionId}`;
|
|
4347
|
+
let helper = lowerer.widthHelpers.get(key);
|
|
4348
|
+
if (!helper) {
|
|
4349
|
+
helper = `%${label}.optionalString.${lowerer.widthHelpers.size}`;
|
|
4350
|
+
lowerer.widthHelpers.set(key, helper);
|
|
4351
|
+
const value = varRef("value.0", arg.type, loc);
|
|
4352
|
+
lowerer.liftedFns.push({
|
|
4353
|
+
name: helper,
|
|
4354
|
+
params: [{ localId: "value.0", name: "value", type: arg.type }],
|
|
4355
|
+
returnType: F64,
|
|
4356
|
+
locals: [{ id: "value.0", name: "value", type: arg.type, mutable: false }],
|
|
4357
|
+
body: [
|
|
4358
|
+
{
|
|
4359
|
+
kind: "if",
|
|
4360
|
+
cond: { kind: "unionIsTag", unionId: arg.type.unionId, tag: undefinedTag, negated: false, value, type: BOOL, loc },
|
|
4361
|
+
then: [{ kind: "return", value: { kind: "bin", op: "/", left: { kind: "numLit", value: 0, type: F64, loc }, right: { kind: "numLit", value: 0, type: F64, loc }, type: F64, loc }, loc }],
|
|
4362
|
+
else_: null,
|
|
4363
|
+
loc,
|
|
4364
|
+
},
|
|
4365
|
+
{
|
|
4366
|
+
kind: "return",
|
|
4367
|
+
value: {
|
|
4368
|
+
kind: "libCall",
|
|
4369
|
+
fn,
|
|
4370
|
+
args: [{ kind: "unionNarrow", unionId: arg.type.unionId, tag: stringTag, value, type: STRING, loc }],
|
|
4371
|
+
type: F64,
|
|
4372
|
+
loc,
|
|
4373
|
+
},
|
|
4374
|
+
loc,
|
|
4375
|
+
},
|
|
4376
|
+
],
|
|
4377
|
+
loc,
|
|
4378
|
+
});
|
|
4379
|
+
}
|
|
4380
|
+
return { kind: "call", callee: helper, args: [arg], type: F64, loc };
|
|
4381
|
+
}
|
|
4060
4382
|
/** The RUNTIME-ARITY spread call — `f(...args)`, the rest-forwarding idiom
|
|
4061
4383
|
* (`const f = (...args) => from(...args)`): a spread whose length is a
|
|
4062
4384
|
* runtime fact has no home in the compile-time completion, so the call
|
|
@@ -4187,7 +4509,7 @@ function lowerDynReceiverMethodCall(lowerer, call, access) {
|
|
|
4187
4509
|
// evolving `let h = {}` object flowing back out of a JS helper —
|
|
4188
4510
|
// tsc types the return by the evolved shape, the binding lowered
|
|
4189
4511
|
// dyn): probe the lowering and claim exactly the dyn results.
|
|
4190
|
-
const probed =
|
|
4512
|
+
const probed = tryLowerExpression(lowerer, access.expression);
|
|
4191
4513
|
if (probed?.type.kind !== "dyn")
|
|
4192
4514
|
return null;
|
|
4193
4515
|
recv = probed;
|
|
@@ -4380,6 +4702,71 @@ export function lowerDynDispatchMethodCall(lowerer, call, access, recv, arrayRec
|
|
|
4380
4702
|
if (arrayReceiver && predicate?.type.kind === "func" && predicate.type.ret.kind === "void") {
|
|
4381
4703
|
lowerer.unsupported("SC1090", call.arguments[0], "'.filter()' with a void-returning predicate (the callback return value is erased before its truthiness can be tested)");
|
|
4382
4704
|
}
|
|
4705
|
+
// A dynamic argument array consumed immediately by the fixed-arity arrow
|
|
4706
|
+
// apply lowering below never exposes its surplus tail. Keep a pushed
|
|
4707
|
+
// static-only value's evaluation and the array length mutation, but store
|
|
4708
|
+
// undefined in that unobserved slot so no impossible dyn conversion is
|
|
4709
|
+
// invented. If the slot falls inside the typed prefix, its dynCheck fails
|
|
4710
|
+
// at the callback boundary; valid callers preserve the original prefix.
|
|
4711
|
+
if (method === "push" &&
|
|
4712
|
+
call.arguments.length === 1 &&
|
|
4713
|
+
ts.isIdentifier(access.expression) &&
|
|
4714
|
+
ts.isExpressionStatement(call.parent) &&
|
|
4715
|
+
ts.isBlock(call.parent.parent)) {
|
|
4716
|
+
const receiverSymbol = lowerer.checker.getSymbolAtLocation(access.expression);
|
|
4717
|
+
const block = call.parent.parent;
|
|
4718
|
+
const statementIndex = block.statements.indexOf(call.parent);
|
|
4719
|
+
const next = statementIndex >= 0 ? block.statements[statementIndex + 1] : undefined;
|
|
4720
|
+
let returned = next && ts.isReturnStatement(next) ? next.expression : undefined;
|
|
4721
|
+
while (returned && ts.isParenthesizedExpression(returned))
|
|
4722
|
+
returned = returned.expression;
|
|
4723
|
+
const apply = returned && ts.isCallExpression(returned) &&
|
|
4724
|
+
ts.isPropertyAccessExpression(returned.expression) &&
|
|
4725
|
+
returned.expression.name.text === "apply"
|
|
4726
|
+
? returned
|
|
4727
|
+
: null;
|
|
4728
|
+
const argsNode = apply?.arguments[1];
|
|
4729
|
+
const sameArgs = receiverSymbol !== undefined &&
|
|
4730
|
+
argsNode !== undefined &&
|
|
4731
|
+
ts.isIdentifier(argsNode) &&
|
|
4732
|
+
lowerer.checker.getSymbolAtLocation(argsNode) === receiverSymbol;
|
|
4733
|
+
const applyAccess = apply && ts.isPropertyAccessExpression(apply.expression)
|
|
4734
|
+
? apply.expression
|
|
4735
|
+
: null;
|
|
4736
|
+
const applyTarget = applyAccess?.expression;
|
|
4737
|
+
const arrow = applyTarget ? arrowSignatureOf(lowerer, applyTarget) : null;
|
|
4738
|
+
const target = applyTarget && ts.isIdentifier(applyTarget)
|
|
4739
|
+
? lowerer.peekLocal(applyTarget)
|
|
4740
|
+
: null;
|
|
4741
|
+
const targetParams = target?.type.kind === "func" && target.type.rest !== true
|
|
4742
|
+
? target.type.params
|
|
4743
|
+
: null;
|
|
4744
|
+
if (sameArgs && arrow !== null && targetParams !== null &&
|
|
4745
|
+
targetParams.every((param) => canDynCheckTo(param, (id) => lowerer.shapes.get(id), (id) => lowerer.unions.get(id)))) {
|
|
4746
|
+
const value = lowerer.lowerExpr(call.arguments[0]);
|
|
4747
|
+
if (value.type.kind !== "dyn" && !lowerer.dynConvertible(value.type)) {
|
|
4748
|
+
const saved = lowerer.declareHiddenLocal("%applyTail", DYN);
|
|
4749
|
+
return {
|
|
4750
|
+
kind: "seqExpr",
|
|
4751
|
+
stmts: [
|
|
4752
|
+
{ kind: "varDecl", localId: saved.id, init: recv, loc: locOf(access.expression) },
|
|
4753
|
+
{ kind: "exprStmt", expr: value, loc: value.loc },
|
|
4754
|
+
],
|
|
4755
|
+
result: {
|
|
4756
|
+
kind: "dynInvoke",
|
|
4757
|
+
recv: { kind: "varRef", localId: saved.id, type: DYN, loc: locOf(access.expression) },
|
|
4758
|
+
method,
|
|
4759
|
+
calleeName: access.getText(),
|
|
4760
|
+
args: [dynUndefinedExpr(locOf(call.arguments[0]))],
|
|
4761
|
+
type: DYN,
|
|
4762
|
+
loc: locOf(call),
|
|
4763
|
+
},
|
|
4764
|
+
type: DYN,
|
|
4765
|
+
loc: locOf(call),
|
|
4766
|
+
};
|
|
4767
|
+
}
|
|
4768
|
+
}
|
|
4769
|
+
}
|
|
4383
4770
|
const args = call.arguments.map((arg, i) => i === 0 && predicate ? lowerer.coerceInto(arg, predicate, DYN) : lowerer.lowerExprExpecting(arg, DYN));
|
|
4384
4771
|
return {
|
|
4385
4772
|
kind: "dynInvoke",
|
|
@@ -4732,7 +5119,7 @@ function lowerPrimitiveProtoCall(lowerer, call, recv, name, memberSym) {
|
|
|
4732
5119
|
// optional number selects 0 at runtime through the same narrowed
|
|
4733
5120
|
// nullish IR used by `digits ?? 0`.
|
|
4734
5121
|
const zero = { kind: "numLit", value: 0, type: F64, loc: digits.loc };
|
|
4735
|
-
const defaultUnitDigits = (value) =>
|
|
5122
|
+
const defaultUnitDigits = (value) => isSafeToDiscard(value)
|
|
4736
5123
|
? zero
|
|
4737
5124
|
: {
|
|
4738
5125
|
kind: "seqExpr",
|
|
@@ -4818,6 +5205,46 @@ function lowerPrimitiveProtoCall(lowerer, call, recv, name, memberSym) {
|
|
|
4818
5205
|
return null;
|
|
4819
5206
|
return { kind: "boolLit", value: false, type: BOOL, loc };
|
|
4820
5207
|
}
|
|
5208
|
+
/** The uniquely arity-selected overload on an implicit-any receiver whose
|
|
5209
|
+
* active monomorphization supplies a concrete type. The checker resolved
|
|
5210
|
+
* the original call through `any`, so getResolvedSignature cannot name
|
|
5211
|
+
* the declaration-authored overload; typeOf carries the instance's real
|
|
5212
|
+
* receiver type. Restricting the fallback to exactly one bodyless
|
|
5213
|
+
* signature at this arity avoids recreating TypeScript's overload
|
|
5214
|
+
* resolution for same-arity type distinctions. */
|
|
5215
|
+
function implicitReceiverOverloadReturn(lowerer, expr) {
|
|
5216
|
+
if (!ts.isCallExpression(expr) ||
|
|
5217
|
+
!ts.isPropertyAccessExpression(expr.expression) ||
|
|
5218
|
+
expr.arguments.some(ts.isSpreadElement)) {
|
|
5219
|
+
return null;
|
|
5220
|
+
}
|
|
5221
|
+
const access = expr.expression;
|
|
5222
|
+
const original = lowerer.checker.getTypeAtLocation(access.expression);
|
|
5223
|
+
if ((original.flags & ts.TypeFlags.Any) === 0)
|
|
5224
|
+
return null;
|
|
5225
|
+
const effective = lowerer.typeOf(access.expression);
|
|
5226
|
+
if ((effective.flags & ts.TypeFlags.Any) !== 0)
|
|
5227
|
+
return null;
|
|
5228
|
+
const member = lowerer.checker.getPropertyOfType(effective, access.name.text);
|
|
5229
|
+
if (!member)
|
|
5230
|
+
return null;
|
|
5231
|
+
const signatures = lowerer.checker.getCallSignatures(lowerer.checker.getTypeOfSymbol(member));
|
|
5232
|
+
const matches = signatures.filter((signature) => {
|
|
5233
|
+
const decl = lowerer.checker.signatureDeclaration(signature);
|
|
5234
|
+
if (!decl ||
|
|
5235
|
+
!(ts.isFunctionDeclaration(decl) || ts.isMethodDeclaration(decl)) ||
|
|
5236
|
+
decl.body) {
|
|
5237
|
+
return false;
|
|
5238
|
+
}
|
|
5239
|
+
const params = decl.parameters.filter((param) => !isThisParameter(param));
|
|
5240
|
+
const required = params.filter((param) => !param.questionToken && !param.initializer && !param.dotDotDotToken).length;
|
|
5241
|
+
const maximum = params.some((param) => param.dotDotDotToken) ? Infinity : params.length;
|
|
5242
|
+
return expr.arguments.length >= required && expr.arguments.length <= maximum;
|
|
5243
|
+
});
|
|
5244
|
+
if (matches.length !== 1)
|
|
5245
|
+
return null;
|
|
5246
|
+
return lowerer.mapTypeOf(lowerer.checker.getReturnTypeOfSignature(matches[0]));
|
|
5247
|
+
}
|
|
4821
5248
|
/** Reconciles a direct call's recorded type with the checker's answer at
|
|
4822
5249
|
* the site when the callee is OVERLOADED: tsc resolved the call against
|
|
4823
5250
|
* one overload SIGNATURE, so every downstream lowering sees that
|
|
@@ -4837,10 +5264,12 @@ function lowerPrimitiveProtoCall(lowerer, call, recv, name, memberSym) {
|
|
|
4837
5264
|
function reconcileOverloadReturn(lowerer, expr, call) {
|
|
4838
5265
|
const rsig = lowerer.checker.getResolvedSignature(expr);
|
|
4839
5266
|
const rdecl = rsig ? lowerer.checker.signatureDeclaration(rsig) : undefined;
|
|
4840
|
-
|
|
4841
|
-
|
|
4842
|
-
|
|
4843
|
-
|
|
5267
|
+
const resolvedOverload = rsig && rdecl &&
|
|
5268
|
+
(ts.isFunctionDeclaration(rdecl) || ts.isMethodDeclaration(rdecl)) &&
|
|
5269
|
+
!rdecl.body
|
|
5270
|
+
? lowerer.mapTypeOf(lowerer.checker.getReturnTypeOfSignature(rsig))
|
|
5271
|
+
: null;
|
|
5272
|
+
const rt = resolvedOverload ?? implicitReceiverOverloadReturn(lowerer, expr);
|
|
4844
5273
|
// Unmappable, void, or unit resolved returns keep the implementation's
|
|
4845
5274
|
// type: a discarded result never looks, a USED one meets its use
|
|
4846
5275
|
// site's own mapping (and that site's honest fences). Unit narrowing
|
|
@@ -4920,10 +5349,9 @@ function templateEscapesValid(raw) {
|
|
|
4920
5349
|
return true;
|
|
4921
5350
|
}
|
|
4922
5351
|
/** Tagged templates `tag\`a${x}b\`` — ES's call: tag(strings, ...values).
|
|
4923
|
-
* The strings object is
|
|
4924
|
-
*
|
|
4925
|
-
*
|
|
4926
|
-
* the tag the SAME array; two sites never share). TemplateStringsArray
|
|
5352
|
+
* The strings object is a per-SITE lazily initialized hidden array global,
|
|
5353
|
+
* so the spec's identity contract holds — the same site evaluated twice
|
|
5354
|
+
* hands the tag the SAME array; two sites never share. TemplateStringsArray
|
|
4927
5355
|
* maps to string[] (type-mapper.ts), so the array rides the ordinary
|
|
4928
5356
|
* slot-directed coercion into whatever the tag's first parameter wants
|
|
4929
5357
|
* — string[] exactly, an `any` slot through the dyn boundary, a rest
|
|
@@ -4949,13 +5377,7 @@ export function lowerTaggedTemplate(lowerer, expr) {
|
|
|
4949
5377
|
lowerer.unsupported("SC1090", p, "tagged templates with invalid escape sequences (the span cooks to undefined, which the strings array cannot carry)");
|
|
4950
5378
|
}
|
|
4951
5379
|
}
|
|
4952
|
-
const strings =
|
|
4953
|
-
kind: "templateStrings",
|
|
4954
|
-
key: `${loc.file}:${expr.template.getStart()}`,
|
|
4955
|
-
cooked: pieces.map((p) => p.text),
|
|
4956
|
-
type: arrayOf(STRING),
|
|
4957
|
-
loc,
|
|
4958
|
-
};
|
|
5380
|
+
const strings = () => loweredTemplateStrings(lowerer, expr, pieces.map((piece) => piece.text), loc);
|
|
4959
5381
|
const values = ts.isNoSubstitutionTemplateLiteral(expr.template)
|
|
4960
5382
|
? []
|
|
4961
5383
|
: expr.template.templateSpans.map((s) => s.expression);
|
|
@@ -5007,7 +5429,7 @@ export function lowerTaggedTemplate(lowerer, expr) {
|
|
|
5007
5429
|
const sig = lowerer.fnSigOf(expr.tag);
|
|
5008
5430
|
if (sig) {
|
|
5009
5431
|
lowerer.noteEdge(sig.name);
|
|
5010
|
-
const args = completeArgs(lowerer, values, sig.params, loc, expr, [strings]);
|
|
5432
|
+
const args = completeArgs(lowerer, values, sig.params, loc, expr, [strings()]);
|
|
5011
5433
|
return reconcileOverloadReturn(lowerer, expr, { kind: "call", callee: sig.name, args, type: sig.returnType, loc });
|
|
5012
5434
|
}
|
|
5013
5435
|
// An ambient `declare function` nothing defines: Node throws
|
|
@@ -5034,7 +5456,7 @@ export function lowerTaggedTemplate(lowerer, expr) {
|
|
|
5034
5456
|
const callee = lowerer.lowerExpr(expr.tag);
|
|
5035
5457
|
if (callee.type.kind === "dyn") {
|
|
5036
5458
|
const args = [
|
|
5037
|
-
lowerer.coerceInto(expr.template, strings, DYN),
|
|
5459
|
+
lowerer.coerceInto(expr.template, strings(), DYN),
|
|
5038
5460
|
...values.map((a) => lowerer.lowerExprExpecting(a, DYN)),
|
|
5039
5461
|
];
|
|
5040
5462
|
const calleeName = ts.isPropertyAccessExpression(expr.tag) || ts.isElementAccessExpression(expr.tag)
|
|
@@ -5046,6 +5468,53 @@ export function lowerTaggedTemplate(lowerer, expr) {
|
|
|
5046
5468
|
}
|
|
5047
5469
|
lowerer.unsupported("SC1090", expr, "tagged templates with this tag form (top-level functions and dynamic values tag; call the function directly otherwise)");
|
|
5048
5470
|
}
|
|
5471
|
+
function loweredTemplateStrings(lowerer, expr, cooked, loc) {
|
|
5472
|
+
// Normal runtime construction keeps this array aligned with the current
|
|
5473
|
+
// ScrArr layout in both backends. The old static-header IR node encoded the
|
|
5474
|
+
// pre-sparse layout in LLVM and crashed as soon as a tag read its strings.
|
|
5475
|
+
const type = arrayOf(STRING);
|
|
5476
|
+
const key = `templateStringsGlobal:${loc.file}:${expr.template.getStart()}`;
|
|
5477
|
+
let getter = lowerer.widthHelpers.get(key);
|
|
5478
|
+
if (!getter) {
|
|
5479
|
+
const site = lowerer.globalsList.length;
|
|
5480
|
+
const globalId = `%g.templateStrings.${site}`;
|
|
5481
|
+
const readyId = `%g.templateStringsReady.${site}`;
|
|
5482
|
+
getter = `%templateStrings.get.${lowerer.widthHelpers.size}`;
|
|
5483
|
+
lowerer.widthHelpers.set(key, getter);
|
|
5484
|
+
lowerer.globalsList.push({ id: globalId, name: "%templateStrings", type, mutable: true }, { id: readyId, name: "%templateStringsReady", type: BOOL, mutable: true });
|
|
5485
|
+
lowerer.liftedFns.push({
|
|
5486
|
+
name: getter,
|
|
5487
|
+
params: [],
|
|
5488
|
+
returnType: type,
|
|
5489
|
+
locals: [],
|
|
5490
|
+
body: [
|
|
5491
|
+
{
|
|
5492
|
+
kind: "if",
|
|
5493
|
+
cond: { kind: "unary", op: "!", operand: varRef(readyId, BOOL, loc), type: BOOL, loc },
|
|
5494
|
+
then: [
|
|
5495
|
+
{
|
|
5496
|
+
kind: "assign",
|
|
5497
|
+
localId: globalId,
|
|
5498
|
+
value: {
|
|
5499
|
+
kind: "arrayLit",
|
|
5500
|
+
elems: cooked.map((value) => ({ kind: "strLit", value, type: STRING, loc })),
|
|
5501
|
+
type,
|
|
5502
|
+
loc,
|
|
5503
|
+
},
|
|
5504
|
+
loc,
|
|
5505
|
+
},
|
|
5506
|
+
{ kind: "assign", localId: readyId, value: { kind: "boolLit", value: true, type: BOOL, loc }, loc },
|
|
5507
|
+
],
|
|
5508
|
+
else_: null,
|
|
5509
|
+
loc,
|
|
5510
|
+
},
|
|
5511
|
+
{ kind: "return", value: varRef(globalId, type, loc), loc },
|
|
5512
|
+
],
|
|
5513
|
+
loc,
|
|
5514
|
+
});
|
|
5515
|
+
}
|
|
5516
|
+
return { kind: "call", callee: getter, args: [], type, loc };
|
|
5517
|
+
}
|
|
5049
5518
|
/** True when the identifier resolves (through import aliases) to a
|
|
5050
5519
|
* top-level function declaration of ANY program file (not merely a
|
|
5051
5520
|
* same-named local shadowing one). Functions declared directly in a
|
|
@@ -5080,10 +5549,6 @@ export function lowerNestedFunctionDecl(lowerer, stmt) {
|
|
|
5080
5549
|
export function lambdaSignature(lowerer, node) {
|
|
5081
5550
|
if (!node.body)
|
|
5082
5551
|
lowerer.unsupported("SC1090", node, "function overload signatures");
|
|
5083
|
-
if (node.asteriskToken &&
|
|
5084
|
-
node.modifiers?.some((m) => m.kind === ts.SyntaxKind.AsyncKeyword)) {
|
|
5085
|
-
lowerer.unsupported("SC1071", node, "async generators (async function*)");
|
|
5086
|
-
}
|
|
5087
5552
|
if (node.typeParameters) {
|
|
5088
5553
|
// Generic function-like forms monomorphize only where a static home
|
|
5089
5554
|
// exists: top-level generic function declarations, generic methods
|
|
@@ -5107,6 +5572,7 @@ export function lambdaSignature(lowerer, node) {
|
|
|
5107
5572
|
let ret = ts.isArrowFunction(node) && !ts.isBlock(node.body) && isStreamUndefCallExpr(lowerer, node.body)
|
|
5108
5573
|
? VOID
|
|
5109
5574
|
: lowerer.declaredReturnType(node, node);
|
|
5575
|
+
ret = lowerer.runtimeOptionalFunctionReturnType(node, ret);
|
|
5110
5576
|
// A contextually-typed arrow/function EXPRESSION whose slot signature
|
|
5111
5577
|
// returns a UNION the inferred return doesn't spell adopts the slot's
|
|
5112
5578
|
// return as its ABI: `(n) => work()` (inferring Promise<void>) against
|
|
@@ -5253,13 +5719,14 @@ export function lowerLambda(lowerer, node) {
|
|
|
5253
5719
|
// the lifted body returns the inner T (a `return v` fulfills with v).
|
|
5254
5720
|
const isAsync = !ts.isAccessor(node) &&
|
|
5255
5721
|
node.modifiers?.some((m) => m.kind === ts.SyntaxKind.AsyncKeyword) === true;
|
|
5256
|
-
|
|
5722
|
+
const isGenerator = node.asteriskToken !== undefined;
|
|
5723
|
+
if (isAsync && !isGenerator && funcType.ret.kind !== "promise")
|
|
5257
5724
|
lowerer.badType(node, lowerer.typeOf(node));
|
|
5258
5725
|
// Generator lambdas (function* expressions and object-literal
|
|
5259
5726
|
// *methods): the VALUE's type returns the generator; the lifted body
|
|
5260
5727
|
// returns the TReturn channel (a `return v` is the done-value).
|
|
5261
|
-
|
|
5262
|
-
|
|
5728
|
+
if (isGenerator &&
|
|
5729
|
+
(funcType.ret.kind !== "generator" || (funcType.ret.async === true) !== isAsync))
|
|
5263
5730
|
lowerer.badType(node, lowerer.typeOf(node));
|
|
5264
5731
|
const bodyReturn = isGenerator
|
|
5265
5732
|
? lowerer.genBodyReturnType(funcType.ret)
|
|
@@ -5267,7 +5734,7 @@ export function lowerLambda(lowerer, node) {
|
|
|
5267
5734
|
const fnCtx = newFnCtx(true, selfSymbol, funcType, bodyReturn);
|
|
5268
5735
|
fnCtx.isAsync = isAsync;
|
|
5269
5736
|
if (isGenerator && funcType.ret.kind === "generator") {
|
|
5270
|
-
fnCtx.generator =
|
|
5737
|
+
fnCtx.generator = generatorMeta(lowerer, funcType.ret);
|
|
5271
5738
|
}
|
|
5272
5739
|
const diagsBefore = lowerer.diags.length;
|
|
5273
5740
|
lowerer.fnStack.push(fnCtx);
|
|
@@ -6609,7 +7076,7 @@ function lowerIntlNumberFormatCall(lowerer, call, access) {
|
|
|
6609
7076
|
function objectIsDisjointFalse(left, right, loc) {
|
|
6610
7077
|
const stmts = [];
|
|
6611
7078
|
for (const e of [left, right]) {
|
|
6612
|
-
if (!
|
|
7079
|
+
if (!isSafeToDiscard(e))
|
|
6613
7080
|
stmts.push({ kind: "exprStmt", expr: e, loc });
|
|
6614
7081
|
}
|
|
6615
7082
|
const answer = { kind: "boolLit", value: false, type: BOOL, loc };
|
|
@@ -6623,6 +7090,9 @@ function lowerObjectStaticCall(lowerer, call, access) {
|
|
|
6623
7090
|
if (!lowerer.isStdlibGlobal(access.expression, "Object"))
|
|
6624
7091
|
return null;
|
|
6625
7092
|
const member = access.name.text;
|
|
7093
|
+
const cacheKeys = lowerRequireCacheKeys(lowerer, call, member);
|
|
7094
|
+
if (cacheKeys)
|
|
7095
|
+
return cacheKeys;
|
|
6626
7096
|
// Object.is — the spec's SameValue over the static kinds. Number
|
|
6627
7097
|
// pairs take the runtime SameValue (NaN equals NaN, +0 differs from
|
|
6628
7098
|
// -0 — the two divergences from ===); every other supported pair
|
|
@@ -6813,8 +7283,8 @@ function lowerObjectStaticCall(lowerer, call, access) {
|
|
|
6813
7283
|
// the explicit-undefined-is-absent stance). Everything else keeps
|
|
6814
7284
|
// the spread hint.
|
|
6815
7285
|
if (call.arguments.length === 2 && !call.arguments.some((a) => ts.isSpreadElement(a))) {
|
|
6816
|
-
const tProbe =
|
|
6817
|
-
const sProbe =
|
|
7286
|
+
const tProbe = tryLowerExpression(lowerer, call.arguments[0]);
|
|
7287
|
+
const sProbe = tryLowerExpression(lowerer, call.arguments[1]);
|
|
6818
7288
|
// CHECKED-DYNAMIC target and source (the JS file-scope
|
|
6819
7289
|
// object-literal identity story): the runtime dyn copy — own
|
|
6820
7290
|
// members of the source land on the target, which returns.
|
|
@@ -6872,7 +7342,7 @@ function lowerObjectStaticCall(lowerer, call, access) {
|
|
|
6872
7342
|
while (ts.isParenthesizedExpression(targetNode))
|
|
6873
7343
|
targetNode = targetNode.expression;
|
|
6874
7344
|
const freshLiteralTarget = ts.isObjectLiteralExpression(targetNode);
|
|
6875
|
-
const tProbe = freshLiteralTarget ? null :
|
|
7345
|
+
const tProbe = freshLiteralTarget ? null : tryLowerExpression(lowerer, call.arguments[0]);
|
|
6876
7346
|
const tKind = tProbe?.type.kind;
|
|
6877
7347
|
if (freshLiteralTarget || tKind === "dyn" || tKind === "nullT" || tKind === "undefinedT") {
|
|
6878
7348
|
const loc = locOf(call);
|
|
@@ -6944,7 +7414,7 @@ function lowerObjectStaticCall(lowerer, call, access) {
|
|
|
6944
7414
|
// static shapes have no property table to extend.
|
|
6945
7415
|
if (member === "defineProperties" && call.arguments.length === 2 &&
|
|
6946
7416
|
!call.arguments.some((a) => ts.isSpreadElement(a))) {
|
|
6947
|
-
let target =
|
|
7417
|
+
let target = tryLowerExpression(lowerer, call.arguments[0]);
|
|
6948
7418
|
// A FUNCTION-typed target boxes through the dyn boundary: the
|
|
6949
7419
|
// property table lives on the CLOSURE (shared by every box of this
|
|
6950
7420
|
// function value), so defining through a fresh box sticks — the
|
|
@@ -6999,7 +7469,7 @@ function lowerObjectStaticCall(lowerer, call, access) {
|
|
|
6999
7469
|
if (member === "hasOwn" && call.arguments.length === 2 && !call.arguments.some((a) => ts.isSpreadElement(a))) {
|
|
7000
7470
|
const recvNode = call.arguments[0];
|
|
7001
7471
|
const keyNode = call.arguments[1];
|
|
7002
|
-
const probed =
|
|
7472
|
+
const probed = tryLowerExpression(lowerer, recvNode);
|
|
7003
7473
|
// A CHECKED-DYNAMIC receiver (the JS file-scope object-literal
|
|
7004
7474
|
// identity story): the runtime dyn probe — OBJ member presence, ARR
|
|
7005
7475
|
// index bounds, Node's ToObject TypeError on nullish.
|
|
@@ -7045,7 +7515,7 @@ function lowerObjectStaticCall(lowerer, call, access) {
|
|
|
7045
7515
|
// runtime walks the dyn node's own keys (integer-like keys first,
|
|
7046
7516
|
// JS's own-key order) and answers a dyn array.
|
|
7047
7517
|
{
|
|
7048
|
-
const probed =
|
|
7518
|
+
const probed = tryLowerExpression(lowerer, argNode);
|
|
7049
7519
|
const isDyn = probed?.type.kind === "dyn";
|
|
7050
7520
|
// Unit-typed arguments (Object.keys(null)) ride the same runtime
|
|
7051
7521
|
// walk: it throws Node's catchable TypeError.
|
|
@@ -7063,7 +7533,7 @@ function lowerObjectStaticCall(lowerer, call, access) {
|
|
|
7063
7533
|
// record (the narrowed export-table literal) — the lowered value's
|
|
7064
7534
|
// shape is the honest dispatch key, exactly the identity-Set stance.
|
|
7065
7535
|
if (argIr === null && isJsSourceFile(argNode.getSourceFile())) {
|
|
7066
|
-
const probed =
|
|
7536
|
+
const probed = tryLowerExpression(lowerer, argNode);
|
|
7067
7537
|
if (probed?.type.kind === "record")
|
|
7068
7538
|
argIr = probed.type;
|
|
7069
7539
|
}
|
|
@@ -8104,6 +8574,69 @@ const SP_BRAND_METHODS = new Set([
|
|
|
8104
8574
|
"append", "delete", "get", "getAll", "has", "set", "sort",
|
|
8105
8575
|
"forEach", "keys", "values", "entries", "toString",
|
|
8106
8576
|
]);
|
|
8577
|
+
function arrowSignatureOf(lowerer, node) {
|
|
8578
|
+
const signatures = lowerer.checker.getCallSignatures(lowerer.typeOf(node));
|
|
8579
|
+
if (signatures.length !== 1)
|
|
8580
|
+
return null;
|
|
8581
|
+
const declaration = lowerer.checker.signatureDeclaration(signatures[0]);
|
|
8582
|
+
return declaration !== undefined && ts.isArrowFunction(declaration) ? signatures[0] : null;
|
|
8583
|
+
}
|
|
8584
|
+
/** `arrow.apply(thisArg, dynArgs)` for a fixed-arity compiled arrow. Arrows
|
|
8585
|
+
* ignore `thisArg` and surplus arguments by language definition; declared
|
|
8586
|
+
* parameters validate from the dynamic array in order. */
|
|
8587
|
+
function lowerArrowFunctionApply(lowerer, call, access) {
|
|
8588
|
+
if (access.name.text !== "apply" ||
|
|
8589
|
+
call.arguments.length !== 2 ||
|
|
8590
|
+
call.arguments.some(ts.isSpreadElement) ||
|
|
8591
|
+
arrowSignatureOf(lowerer, access.expression) === null) {
|
|
8592
|
+
return null;
|
|
8593
|
+
}
|
|
8594
|
+
const callee = lowerer.lowerExpr(access.expression);
|
|
8595
|
+
if (callee.type.kind !== "func" || callee.type.rest === true)
|
|
8596
|
+
return null;
|
|
8597
|
+
if (!callee.type.params.every((param) => canDynCheckTo(param, (id) => lowerer.shapes.get(id), (id) => lowerer.unions.get(id)))) {
|
|
8598
|
+
return null;
|
|
8599
|
+
}
|
|
8600
|
+
const argsList = lowerer.lowerExpr(call.arguments[1]);
|
|
8601
|
+
if (argsList.type.kind !== "dyn")
|
|
8602
|
+
return null;
|
|
8603
|
+
const loc = locOf(call);
|
|
8604
|
+
const savedCallee = lowerer.declareHiddenLocal("%applyFn", callee.type);
|
|
8605
|
+
const savedArgs = lowerer.declareHiddenLocal("%applyArgs", DYN);
|
|
8606
|
+
const stmts = [
|
|
8607
|
+
{ kind: "varDecl", localId: savedCallee.id, init: callee, loc },
|
|
8608
|
+
{ kind: "exprStmt", expr: lowerer.lowerExpr(call.arguments[0]), loc },
|
|
8609
|
+
{ kind: "varDecl", localId: savedArgs.id, init: argsList, loc },
|
|
8610
|
+
];
|
|
8611
|
+
const args = callee.type.params.map((param, index) => {
|
|
8612
|
+
const read = {
|
|
8613
|
+
kind: "dynKeyGet",
|
|
8614
|
+
key: { kind: "strLit", value: String(index), type: STRING, loc },
|
|
8615
|
+
value: { kind: "varRef", localId: savedArgs.id, type: DYN, loc },
|
|
8616
|
+
type: DYN,
|
|
8617
|
+
loc,
|
|
8618
|
+
};
|
|
8619
|
+
return lowerer.coerceInto(call.arguments[1], read, param);
|
|
8620
|
+
});
|
|
8621
|
+
const invoked = {
|
|
8622
|
+
kind: "callValue",
|
|
8623
|
+
callee: { kind: "varRef", localId: savedCallee.id, type: callee.type, loc },
|
|
8624
|
+
args,
|
|
8625
|
+
type: callee.type.ret,
|
|
8626
|
+
loc,
|
|
8627
|
+
};
|
|
8628
|
+
let result;
|
|
8629
|
+
if (invoked.type.kind === "void") {
|
|
8630
|
+
stmts.push({ kind: "exprStmt", expr: invoked, loc });
|
|
8631
|
+
result = dynUndefinedExpr(loc);
|
|
8632
|
+
}
|
|
8633
|
+
else {
|
|
8634
|
+
result = lowerer.coerceInto(call, invoked, DYN);
|
|
8635
|
+
if (result.type.kind !== "dyn")
|
|
8636
|
+
return null;
|
|
8637
|
+
}
|
|
8638
|
+
return { kind: "seqExpr", stmts, result, type: DYN, loc };
|
|
8639
|
+
}
|
|
8107
8640
|
function lowerObjLitGenericMethodCall(lowerer, call, access) {
|
|
8108
8641
|
if (lowerer.chainBlocked(access, call))
|
|
8109
8642
|
return null;
|
|
@@ -8165,6 +8698,9 @@ function lowerObjLitGenericMethodCall(lowerer, call, access) {
|
|
|
8165
8698
|
}
|
|
8166
8699
|
const found = objLitGenericFnNodeOf(lowerer, propSym);
|
|
8167
8700
|
if (!found) {
|
|
8701
|
+
const arrowApply = lowerArrowFunctionApply(lowerer, call, access);
|
|
8702
|
+
if (arrowApply !== null)
|
|
8703
|
+
return arrowApply;
|
|
8168
8704
|
// Function.prototype.apply/call/bind spelled through a FUNCTION
|
|
8169
8705
|
// receiver: compiled functions are direct calls with no runtime
|
|
8170
8706
|
// `this`/arguments object to re-route — name the working spelling
|
|
@@ -8211,9 +8747,32 @@ function lowerObjLitGenericMethodCall(lowerer, call, access) {
|
|
|
8211
8747
|
export function lowerObjectMethodCall(lowerer, call, access) {
|
|
8212
8748
|
if (lowerer.chainBlocked(access, call))
|
|
8213
8749
|
return null;
|
|
8214
|
-
const
|
|
8215
|
-
|
|
8750
|
+
const mappedReceiver = lowerer.mapTypeOf(lowerer.typeOf(access.expression));
|
|
8751
|
+
const receiverIr = mappedReceiver?.kind === "object"
|
|
8752
|
+
? mappedReceiver
|
|
8753
|
+
: mappedReceiver?.kind === "union"
|
|
8754
|
+
? (() => {
|
|
8755
|
+
const arms = lowerer.unions.get(mappedReceiver.unionId)?.arms ?? [];
|
|
8756
|
+
const objects = arms.filter((arm) => arm.kind === "object");
|
|
8757
|
+
return objects.length === 1 && arms.every((arm) => arm.kind === "object" || isUnitType(arm))
|
|
8758
|
+
? objects[0]
|
|
8759
|
+
: null;
|
|
8760
|
+
})()
|
|
8761
|
+
: null;
|
|
8762
|
+
if (receiverIr === null)
|
|
8216
8763
|
return null;
|
|
8764
|
+
const lowerReceiver = () => {
|
|
8765
|
+
const receiver = lowerer.lowerExpr(access.expression);
|
|
8766
|
+
const optional = lowerer.runtimeOptionalPropertyReceiver(access.expression, receiver, receiverIr, access.name.text);
|
|
8767
|
+
if (optional !== null)
|
|
8768
|
+
return optional;
|
|
8769
|
+
if (receiver.type.kind === "union") {
|
|
8770
|
+
const helper = lowerer.narrowedArmHelper(receiver.type.unionId, receiverIr, locOf(access.expression));
|
|
8771
|
+
if (helper !== null)
|
|
8772
|
+
return { kind: "call", callee: helper, args: [receiver], type: receiverIr, loc: locOf(access.expression) };
|
|
8773
|
+
}
|
|
8774
|
+
return receiver;
|
|
8775
|
+
};
|
|
8217
8776
|
const info = lowerer.classes.get(receiverIr.className);
|
|
8218
8777
|
if (!info)
|
|
8219
8778
|
lowerer.flushDeferredClass(receiverIr.className);
|
|
@@ -8241,17 +8800,34 @@ export function lowerObjectMethodCall(lowerer, call, access) {
|
|
|
8241
8800
|
if (gfound)
|
|
8242
8801
|
return lowerClassGenericMethodCall(lowerer, call, access, info, gfound);
|
|
8243
8802
|
}
|
|
8244
|
-
// A FUNC- or DYN-typed FIELD in call position:
|
|
8245
|
-
// ctor-assigned callback field (countdown.js's
|
|
8246
|
-
// ordinary call through the field's VALUE —
|
|
8247
|
-
//
|
|
8248
|
-
//
|
|
8249
|
-
//
|
|
8803
|
+
// A FUNC-, nullable-FUNC-, or DYN-typed FIELD in call position:
|
|
8804
|
+
// `this.cb()` — the ctor-assigned callback field (countdown.js's
|
|
8805
|
+
// shape). The call is an ordinary call through the field's VALUE —
|
|
8806
|
+
// read and, when necessary, check-narrow the callable arm, then
|
|
8807
|
+
// callValue; checked-dynamic fields use the dynCall boundary. Every
|
|
8808
|
+
// other field type falls through to the fences.
|
|
8250
8809
|
if (info && !found) {
|
|
8251
8810
|
const fieldType = info.fields.get(access.name.text);
|
|
8252
|
-
|
|
8811
|
+
const callableType = fieldType?.kind === "func"
|
|
8812
|
+
? fieldType
|
|
8813
|
+
: fieldType?.kind === "union"
|
|
8814
|
+
? (() => {
|
|
8815
|
+
const arms = lowerer.unions.get(fieldType.unionId)?.arms ?? [];
|
|
8816
|
+
const funcs = arms.filter((arm) => arm.kind === "func");
|
|
8817
|
+
return funcs.length === 1 && arms.every((arm) => arm.kind === "func" || isUnitType(arm))
|
|
8818
|
+
? funcs[0]
|
|
8819
|
+
: null;
|
|
8820
|
+
})()
|
|
8821
|
+
: null;
|
|
8822
|
+
if (fieldType && (callableType !== null || fieldType.kind === "dyn")) {
|
|
8253
8823
|
const target = lowerer.fieldTarget(access);
|
|
8254
|
-
|
|
8824
|
+
let callee = target ? lowerer.fieldGetExpr(target, locOf(access), access) : null;
|
|
8825
|
+
if (callee?.type.kind === "union" && callableType !== null) {
|
|
8826
|
+
const helper = lowerer.narrowedArmHelper(callee.type.unionId, callableType, locOf(access));
|
|
8827
|
+
if (helper !== null) {
|
|
8828
|
+
callee = { kind: "call", callee: helper, args: [callee], type: callableType, loc: locOf(access) };
|
|
8829
|
+
}
|
|
8830
|
+
}
|
|
8255
8831
|
if (callee?.type.kind === "func") {
|
|
8256
8832
|
const params = callee.type.params;
|
|
8257
8833
|
const args = call.arguments.map((a, i) => lowerer.lowerExprExpecting(a, params[i]));
|
|
@@ -8281,7 +8857,7 @@ export function lowerObjectMethodCall(lowerer, call, access) {
|
|
|
8281
8857
|
// The one builtin method: Error.prototype.toString, a runtime
|
|
8282
8858
|
// implementation called directly (overriding it is fenced, so no
|
|
8283
8859
|
// dispatch can ever be needed). Receiver BORROWED by the libCall.
|
|
8284
|
-
const receiver =
|
|
8860
|
+
const receiver = lowerReceiver();
|
|
8285
8861
|
return {
|
|
8286
8862
|
kind: "libCall",
|
|
8287
8863
|
fn: "error.toString",
|
|
@@ -8303,7 +8879,7 @@ export function lowerObjectMethodCall(lowerer, call, access) {
|
|
|
8303
8879
|
lowerer.noteVirtualEdge(info, method);
|
|
8304
8880
|
else
|
|
8305
8881
|
lowerer.noteEdge(`%${found.declarer.def.name}.${method}`);
|
|
8306
|
-
const receiver =
|
|
8882
|
+
const receiver = lowerReceiver();
|
|
8307
8883
|
const args = lowerer.completeArgs(call.arguments, found.sig.params, locOf(call), call);
|
|
8308
8884
|
if (lowerer.overrideBelow(info, method)) {
|
|
8309
8885
|
return reconcileOverloadReturn(lowerer, call, {
|