@scriptc/compiler 0.2.0 → 0.2.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 +84 -19
- 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 +8 -0
- package/dist/backend/llvm/dyn.js +247 -108
- package/dist/backend/llvm/dyn.js.map +1 -1
- package/dist/backend/llvm/emitter.d.ts +6 -3
- package/dist/backend/llvm/emitter.js +99 -25
- package/dist/backend/llvm/emitter.js.map +1 -1
- package/dist/backend/llvm/emitter.test.js +9 -1
- package/dist/backend/llvm/emitter.test.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-containers.js +5 -0
- package/dist/backend/llvm/expr-containers.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 +47 -13
- 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 +187 -18
- package/dist/backend/llvm/expr-stream-bridges.js.map +1 -1
- package/dist/backend/llvm/expr-stream-callbacks.d.ts +2 -2
- package/dist/backend/llvm/expr-stream-callbacks.js +7 -57
- package/dist/backend/llvm/expr-stream-callbacks.js.map +1 -1
- package/dist/backend/llvm/lib-dispatch.js +41 -3
- package/dist/backend/llvm/lib-dispatch.js.map +1 -1
- package/dist/backend/llvm/lib-filesystem.js +12 -9
- package/dist/backend/llvm/lib-filesystem.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 +80 -3
- 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/may-throw.js +4 -0
- package/dist/backend/may-throw.js.map +1 -1
- package/dist/backend/native-codegen.d.ts +1 -1
- package/dist/backend/native-codegen.js +4 -3
- package/dist/backend/native-codegen.js.map +1 -1
- package/dist/backend/native-codegen.test.js +11 -0
- package/dist/backend/native-codegen.test.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/target-diagnostics.d.ts +5 -0
- package/dist/backend/target-diagnostics.js +72 -1
- package/dist/backend/target-diagnostics.js.map +1 -1
- package/dist/backend/target-diagnostics.test.d.ts +1 -0
- package/dist/backend/target-diagnostics.test.js +68 -0
- package/dist/backend/target-diagnostics.test.js.map +1 -0
- 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/coverage/surface-manifest.js +5 -3
- package/dist/coverage/surface-manifest.js.map +1 -1
- package/dist/diagnostics/diagnostic.js +2 -7
- package/dist/diagnostics/diagnostic.js.map +1 -1
- package/dist/executable/executable-cache.d.ts +7 -3
- package/dist/executable/executable-cache.js +47 -11
- package/dist/executable/executable-cache.js.map +1 -1
- package/dist/executable/executable-cache.test.js +109 -2
- package/dist/executable/executable-cache.test.js.map +1 -1
- package/dist/executable/prepare.js +2 -1
- package/dist/executable/prepare.js.map +1 -1
- package/dist/frontend/builtin-modules.d.ts +1 -1
- package/dist/frontend/builtin-modules.js +1 -1
- package/dist/frontend/builtin-modules.js.map +1 -1
- package/dist/frontend/function-completion.d.ts +6 -0
- package/dist/frontend/function-completion.js +50 -0
- package/dist/frontend/function-completion.js.map +1 -0
- package/dist/frontend/lowering/abstract-equality.js +5 -1
- package/dist/frontend/lowering/abstract-equality.js.map +1 -1
- package/dist/frontend/lowering/checked-iterable-spread.d.ts +4 -0
- package/dist/frontend/lowering/checked-iterable-spread.js +30 -0
- package/dist/frontend/lowering/checked-iterable-spread.js.map +1 -0
- package/dist/frontend/lowering/checked-promise-all.d.ts +5 -0
- package/dist/frontend/lowering/checked-promise-all.js +31 -0
- package/dist/frontend/lowering/checked-promise-all.js.map +1 -0
- package/dist/frontend/lowering/class-callbacks.d.ts +4 -4
- package/dist/frontend/lowering/class-callbacks.js +29 -17
- package/dist/frontend/lowering/class-callbacks.js.map +1 -1
- package/dist/frontend/lowering/class-construction.d.ts +14 -0
- package/dist/frontend/lowering/class-construction.js +185 -0
- package/dist/frontend/lowering/class-construction.js.map +1 -0
- package/dist/frontend/lowering/class-descriptors.d.ts +2 -1
- package/dist/frontend/lowering/class-descriptors.js +58 -10
- package/dist/frontend/lowering/class-descriptors.js.map +1 -1
- package/dist/frontend/lowering/class-dynamic-dispatch.d.ts +36 -1
- package/dist/frontend/lowering/class-dynamic-dispatch.js +965 -91
- package/dist/frontend/lowering/class-dynamic-dispatch.js.map +1 -1
- package/dist/frontend/lowering/class-dynamic-dispatch.test.js +66 -3
- package/dist/frontend/lowering/class-dynamic-dispatch.test.js.map +1 -1
- package/dist/frontend/lowering/class-instance-constructor.d.ts +1 -1
- package/dist/frontend/lowering/class-instance-constructor.js +15 -42
- package/dist/frontend/lowering/class-instance-constructor.js.map +1 -1
- package/dist/frontend/lowering/class-method-values.d.ts +20 -1
- package/dist/frontend/lowering/class-method-values.js +120 -24
- package/dist/frontend/lowering/class-method-values.js.map +1 -1
- package/dist/frontend/lowering/class-prototypes.d.ts +10 -3
- package/dist/frontend/lowering/class-prototypes.js +188 -21
- 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 +84 -0
- package/dist/frontend/lowering/class-runtime-statics.js.map +1 -0
- package/dist/frontend/lowering/class-static-data.d.ts +1 -0
- package/dist/frontend/lowering/class-static-data.js +6 -4
- package/dist/frontend/lowering/class-static-data.js.map +1 -1
- package/dist/frontend/lowering/containers/bytes.js +66 -17
- package/dist/frontend/lowering/containers/bytes.js.map +1 -1
- package/dist/frontend/lowering/containers/string-and-regexp.js +24 -47
- package/dist/frontend/lowering/containers/string-and-regexp.js.map +1 -1
- package/dist/frontend/lowering/deferred-module-initializers.d.ts +13 -0
- package/dist/frontend/lowering/deferred-module-initializers.js +410 -0
- package/dist/frontend/lowering/deferred-module-initializers.js.map +1 -0
- package/dist/frontend/lowering/deferred-module-initializers.test.d.ts +1 -0
- package/dist/frontend/lowering/deferred-module-initializers.test.js +92 -0
- package/dist/frontend/lowering/deferred-module-initializers.test.js.map +1 -0
- 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 +68 -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 +72 -20
- 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 +10 -14
- package/dist/frontend/lowering/lower-builtins.js +443 -88
- 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 +717 -142
- package/dist/frontend/lowering/lower-calls.js.map +1 -1
- package/dist/frontend/lowering/lower-classes.d.ts +18 -13
- package/dist/frontend/lowering/lower-classes.js +1076 -188
- 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 +172 -51
- 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 +12 -8
- package/dist/frontend/lowering/lower-exprs.js +802 -232
- package/dist/frontend/lowering/lower-exprs.js.map +1 -1
- package/dist/frontend/lowering/lower-generators.js +17 -2
- package/dist/frontend/lowering/lower-generators.js.map +1 -1
- package/dist/frontend/lowering/lower-inspect.js +15 -1
- package/dist/frontend/lowering/lower-inspect.js.map +1 -1
- package/dist/frontend/lowering/lower-island.d.ts +2 -0
- package/dist/frontend/lowering/lower-island.js +36 -10
- package/dist/frontend/lowering/lower-island.js.map +1 -1
- package/dist/frontend/lowering/lower-island.test.d.ts +1 -0
- package/dist/frontend/lowering/lower-island.test.js +51 -0
- package/dist/frontend/lowering/lower-island.test.js.map +1 -0
- package/dist/frontend/lowering/lower-modules.d.ts +1 -3
- package/dist/frontend/lowering/lower-modules.js +380 -73
- 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 +107 -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 +221 -47
- package/dist/frontend/lowering/lower-stmts.js.map +1 -1
- package/dist/frontend/lowering/lower-stmts.test.d.ts +1 -0
- package/dist/frontend/lowering/lower-stmts.test.js +77 -0
- package/dist/frontend/lowering/lower-stmts.test.js.map +1 -0
- package/dist/frontend/lowering/lower-stream.js +3 -1
- package/dist/frontend/lowering/lower-stream.js.map +1 -1
- package/dist/frontend/lowering/lower-url.d.ts +2 -1
- package/dist/frontend/lowering/lower-url.js +32 -9
- package/dist/frontend/lowering/lower-url.js.map +1 -1
- package/dist/frontend/lowering/lowerer.d.ts +53 -10
- package/dist/frontend/lowering/lowerer.js +390 -77
- package/dist/frontend/lowering/lowerer.js.map +1 -1
- package/dist/frontend/lowering/lowerer.test.js +187 -3
- package/dist/frontend/lowering/lowerer.test.js.map +1 -1
- package/dist/frontend/lowering/module-namespace-elements.d.ts +7 -0
- package/dist/frontend/lowering/module-namespace-elements.js +54 -0
- package/dist/frontend/lowering/module-namespace-elements.js.map +1 -0
- package/dist/frontend/lowering/object-factory-new.d.ts +4 -3
- package/dist/frontend/lowering/object-factory-new.js +27 -14
- package/dist/frontend/lowering/object-factory-new.js.map +1 -1
- package/dist/frontend/lowering/surfaces.d.ts +3 -0
- package/dist/frontend/lowering/surfaces.js +48 -19
- 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 +8 -0
- package/dist/frontend/lowering/text-decoder-encoding.js.map +1 -1
- package/dist/frontend/lowering/text-decoder-encoding.test.js +2 -1
- package/dist/frontend/lowering/text-decoder-encoding.test.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 +57 -26
- 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 +169 -23
- 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 +24 -9
- package/dist/frontend/union-discriminants.js.map +1 -1
- package/dist/index.js +16 -10
- package/dist/index.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 +74 -41
- package/dist/ir/ir.js +167 -43
- 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 +35 -3
- package/dist/ir/serialize.js.map +1 -1
- package/dist/ir/serialize.test.js +26 -1
- package/dist/ir/serialize.test.js.map +1 -1
- package/dist/ir/traverse.d.ts +0 -3
- package/dist/ir/traverse.js +33 -20
- package/dist/ir/traverse.js.map +1 -1
- package/dist/ir/validate.js +136 -16
- package/dist/ir/validate.js.map +1 -1
- package/dist/ir/validate.test.js +77 -1
- package/dist/ir/validate.test.js.map +1 -1
- package/dist/library/compiler-self-identity.js +1 -1
- package/dist/library/compiler-self-identity.test.js +2 -2
- package/dist/library/compiler-self-identity.test.js.map +1 -1
- package/dist/library/int-infer.d.ts +2 -2
- package/dist/library/int-infer.js +10 -7
- package/dist/library/int-infer.js.map +1 -1
- package/dist/library/int-infer.test.js +44 -0
- package/dist/library/int-infer.test.js.map +1 -1
- package/dist/library/prepare.js +2 -1
- package/dist/library/prepare.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 +170 -93
|
@@ -10,24 +10,25 @@ import { bodyReadsArguments } from "../arguments-usage.js";
|
|
|
10
10
|
import { lowerGenMethodCall } from "./lower-generators.js";
|
|
11
11
|
import { lowerClassSymbolMethodCall } from "./symbol-methods.js";
|
|
12
12
|
import { errorToStringCall } from "./error-methods.js";
|
|
13
|
-
import { lowerClassPrototypeAssign } from "./class-prototypes.js";
|
|
13
|
+
import { lowerClassPrototypeAssign, lowerClassPrototypeDescriptors } 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,10 @@ 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";
|
|
48
|
+
import { functionCanReturnUndefined } from "../function-completion.js";
|
|
49
|
+
import { checkedIterableSpread } from "./checked-iterable-spread.js";
|
|
50
|
+
import { lowerUrlFactory } from "./lower-url.js";
|
|
46
51
|
export { bodyReadsArguments };
|
|
47
52
|
/** The one func-type projection of completed parameter shapes. Typed rest
|
|
48
53
|
* parameters keep their packed array as the trailing native ABI slot and
|
|
@@ -123,7 +128,38 @@ export const MAX_GENERIC_INSTANCES = 100;
|
|
|
123
128
|
* - `...xs: T[]`: the ABI type is the array; call sites pack the surplus.
|
|
124
129
|
*/
|
|
125
130
|
export function paramShape(lowerer, param) {
|
|
131
|
+
if (isJsSourceFile(param.getSourceFile()) && ts.isSetAccessorDeclaration(param.parent))
|
|
132
|
+
return { type: DYN, mode: "required" };
|
|
133
|
+
if (isJsSourceFile(param.getSourceFile()) && ts.isConstructorDeclaration(param.parent) && !param.dotDotDotToken) {
|
|
134
|
+
// Reflective JavaScript construction can supply values outside the
|
|
135
|
+
// constructor's documented usual types. Retain the actual arguments
|
|
136
|
+
// and apply checked conversions only at operations that need them.
|
|
137
|
+
return param.initializer ? { type: DYN, mode: "omittable", bodyType: DYN }
|
|
138
|
+
: { type: DYN, mode: param.questionToken ? "omittable" : "required" };
|
|
139
|
+
}
|
|
140
|
+
const executor = param.parent;
|
|
141
|
+
const construction = executor?.parent;
|
|
142
|
+
const nativeExecutor = executor && (ts.isArrowFunction(executor) || ts.isFunctionExpression(executor)) && ts.isNewExpression(construction) &&
|
|
143
|
+
construction.arguments?.[0] === executor && lowerer.isStdlibGlobal(construction.expression, "Promise");
|
|
144
|
+
if (!nativeExecutor && isJsSourceFile(param.getSourceFile()) && !param.type && !param.dotDotDotToken && !ts.isSetAccessorDeclaration(param.parent) &&
|
|
145
|
+
!/@(?:param|type)\b/.test(param.getSourceFile().text.slice(param.parent?.pos ?? param.pos, param.getStart()))) {
|
|
146
|
+
return param.initializer ? { type: DYN, mode: "omittable", bodyType: DYN } : { type: DYN, mode: "required" };
|
|
147
|
+
}
|
|
148
|
+
if (param.initializer && isJsSourceFile(param.getSourceFile()) && !param.type &&
|
|
149
|
+
!/@(?:param|type)\b/.test(param.getSourceFile().text.slice(param.parent?.pos ?? param.pos, param.getStart()))) {
|
|
150
|
+
return { type: DYN, mode: "omittable", bodyType: DYN };
|
|
151
|
+
}
|
|
152
|
+
// Inferred JS array patterns describe the bindings, not an exact tuple
|
|
153
|
+
// contract. Consume the actual iterable, including surplus elements.
|
|
154
|
+
if (ts.isArrayBindingPattern(param.name) && isJsSourceFile(param.getSourceFile()) && !param.type &&
|
|
155
|
+
!/@(?:param|type)\b/.test(param.getSourceFile().text.slice(param.parent?.pos ?? param.pos, param.getStart()))) {
|
|
156
|
+
if (param.dotDotDotToken)
|
|
157
|
+
return { type: DYN, mode: "dynRest" };
|
|
158
|
+
return param.initializer ? { type: DYN, mode: "omittable", bodyType: DYN } : { type: DYN, mode: "required" };
|
|
159
|
+
}
|
|
126
160
|
if (lowerer.checkedCallbackParams.has(param)) {
|
|
161
|
+
if (param.dotDotDotToken)
|
|
162
|
+
return { type: DYN, mode: "dynRest" };
|
|
127
163
|
return param.initializer
|
|
128
164
|
? { type: DYN, mode: "omittable", bodyType: DYN }
|
|
129
165
|
: { type: DYN, mode: "required" };
|
|
@@ -203,11 +239,41 @@ export function paramShape(lowerer, param) {
|
|
|
203
239
|
}
|
|
204
240
|
if (param.initializer) {
|
|
205
241
|
const raw = lowerer.irTypeOf(param.name);
|
|
242
|
+
// An optional JS array parameter is a live caller-owned buffer,
|
|
243
|
+
// including typed arrays passed through checked callbacks. Extracting
|
|
244
|
+
// a native array here would copy it and discard element writes.
|
|
245
|
+
if (isJsSourceFile(param.getSourceFile()) && !param.type &&
|
|
246
|
+
(raw.kind === "array" || raw.kind === "union" && lowerer.unions.get(raw.unionId)?.arms.some((arm) => arm.kind === "array"))) {
|
|
247
|
+
return { type: DYN, mode: "omittable", bodyType: DYN };
|
|
248
|
+
}
|
|
206
249
|
return defaultParameterShape(lowerer, param, raw);
|
|
207
250
|
}
|
|
208
|
-
|
|
251
|
+
let type = lowerer.runtimeOptionalBindingType(param.name, lowerer.irTypeOf(param.name));
|
|
252
|
+
const body = param.parent?.body;
|
|
253
|
+
if (isJsSourceFile(param.getSourceFile()) && body &&
|
|
254
|
+
type.kind !== "dyn" && type.kind !== "jsval") {
|
|
255
|
+
const symbol = lowerer.checker.getSymbolAtLocation(param.name);
|
|
256
|
+
let acceptsUndefined = false;
|
|
257
|
+
ts.walkPreorder(body, (node) => {
|
|
258
|
+
if (acceptsUndefined || !ts.isBinaryExpression(node))
|
|
259
|
+
return;
|
|
260
|
+
const op = node.operatorToken.kind;
|
|
261
|
+
if (op !== ts.SyntaxKind.EqualsEqualsEqualsToken && op !== ts.SyntaxKind.ExclamationEqualsEqualsToken &&
|
|
262
|
+
op !== ts.SyntaxKind.EqualsEqualsToken && op !== ts.SyntaxKind.ExclamationEqualsToken)
|
|
263
|
+
return;
|
|
264
|
+
const checks = (value, absent) => ts.isIdentifier(value) && ts.isIdentifier(absent) && absent.text === "undefined" &&
|
|
265
|
+
(lowerer.typeOf(absent).flags & ts.TypeFlags.Undefined) !== 0 &&
|
|
266
|
+
lowerer.checker.getSymbolAtLocation(value) === symbol;
|
|
267
|
+
acceptsUndefined = checks(node.left, node.right) || checks(node.right, node.left);
|
|
268
|
+
});
|
|
269
|
+
// A JavaScript body that handles an absent argument defines a wider
|
|
270
|
+
// contract than its JSDoc's usual value. Checked callers must deliver
|
|
271
|
+
// undefined to that branch rather than reject it at the ABI boundary.
|
|
272
|
+
if (acceptsUndefined)
|
|
273
|
+
type = lowerer.promoteRuntimeOptionalParameter(param.name, type);
|
|
274
|
+
}
|
|
209
275
|
if (type.kind === "void") {
|
|
210
|
-
|
|
276
|
+
return { type: DYN, mode: param.questionToken ? "omittable" : "required" };
|
|
211
277
|
}
|
|
212
278
|
if (param.questionToken && !lowerer.bareUndefinedArmedUnion(type) && type.kind !== "dyn" && type.kind !== "jsval") {
|
|
213
279
|
// `x?: unknown` where unknown came from an annotation: undefined is
|
|
@@ -352,7 +418,7 @@ leading) {
|
|
|
352
418
|
// before conversion to the dense checked-dynamic argument pack.
|
|
353
419
|
value = { kind: "arrayLit", elems: [value], spreads: [0], type: value.type, loc: value.loc };
|
|
354
420
|
}
|
|
355
|
-
value = lowerer
|
|
421
|
+
value = checkedIterableSpread(lowerer, value, arg.expression.getText(), loc);
|
|
356
422
|
if (spreads === 1 && index === argNodes.length - 1) {
|
|
357
423
|
stmts.push({ kind: "exprStmt", expr: {
|
|
358
424
|
kind: "libCall", fn: "dyn.packPushSpread", args: [ref(), value, { kind: "strLit", value: arg.expression.getText(), type: STRING, loc }], type: VOID, loc,
|
|
@@ -624,8 +690,7 @@ leading) {
|
|
|
624
690
|
lowerer.unsupported("SC1090", a, "spread arguments into fixed parameter positions (a spread can only fill a rest parameter)");
|
|
625
691
|
}
|
|
626
692
|
const v = lowerer.lowerExpr(a);
|
|
627
|
-
if (v
|
|
628
|
-
v.kind !== "boolLit" && v.kind !== "varRef" && v.kind !== "closure") {
|
|
693
|
+
if (!isSafeToDiscard(v)) {
|
|
629
694
|
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
695
|
}
|
|
631
696
|
}
|
|
@@ -856,7 +921,7 @@ export function appendImplicitUndefinedReturn(lowerer, body, bodyReturn, loc) {
|
|
|
856
921
|
/** A declaration's checker-derived IR return type. The unmappable-type
|
|
857
922
|
* diagnostic points at `blame` (the name for top-level declarations, the
|
|
858
923
|
* whole node for lambda-likes — preserving each caller's historical loc). */
|
|
859
|
-
function hasExplicitJsDocReturn(decl) {
|
|
924
|
+
export function hasExplicitJsDocReturn(decl) {
|
|
860
925
|
const sourceFile = decl.getSourceFile();
|
|
861
926
|
return /@returns?\b/.test(sourceFile.text.slice(decl.pos, decl.getStart(sourceFile)));
|
|
862
927
|
}
|
|
@@ -866,7 +931,19 @@ function promiseCarriesDyn(lowerer, type) {
|
|
|
866
931
|
return type.kind === "union" &&
|
|
867
932
|
(lowerer.unions.get(type.unionId)?.arms.some((arm) => promiseCarriesDyn(lowerer, arm)) ?? false);
|
|
868
933
|
}
|
|
934
|
+
function producesConstructor(lowerer, type) {
|
|
935
|
+
let result = type;
|
|
936
|
+
for (let depth = 0; result && depth < 8; depth++) {
|
|
937
|
+
if (lowerer.checker.getConstructSignatures(result).length > 0)
|
|
938
|
+
return true;
|
|
939
|
+
const signatures = lowerer.checker.getCallSignatures(result);
|
|
940
|
+
result = signatures.length === 1 ? lowerer.checker.getReturnTypeOfSignature(signatures[0]) : undefined;
|
|
941
|
+
}
|
|
942
|
+
return false;
|
|
943
|
+
}
|
|
869
944
|
export function declaredReturnType(lowerer, decl, blame) {
|
|
945
|
+
if (isJsSourceFile(decl.getSourceFile()) && ts.isGetAccessorDeclaration(decl))
|
|
946
|
+
return DYN;
|
|
870
947
|
const sig = lowerer.checker.getSignatureFromDeclaration(decl);
|
|
871
948
|
if (!sig)
|
|
872
949
|
lowerer.unsupported("SC1090", decl, "this function form");
|
|
@@ -881,9 +958,36 @@ export function declaredReturnType(lowerer, decl, blame) {
|
|
|
881
958
|
// (`.action(() => { throw ... })`). `never` VALUES stay unmapped.
|
|
882
959
|
if (retTsType.flags & ts.TypeFlags.Never)
|
|
883
960
|
return VOID;
|
|
884
|
-
|
|
961
|
+
let mappedReturn = lowerer.mapTypeOf(retTsType);
|
|
962
|
+
if (isJsSourceFile(decl.getSourceFile()) && decl.modifiers?.some((modifier) => modifier.kind === ts.SyntaxKind.AsyncKeyword) &&
|
|
963
|
+
!decl.asteriskToken && mappedReturn?.kind !== "promise") {
|
|
964
|
+
const fallback = dynFallbackType(lowerer, decl, retTsType);
|
|
965
|
+
return fallback?.kind === "promise" ? fallback : { kind: "promise", inner: DYN };
|
|
966
|
+
}
|
|
967
|
+
if (mappedReturn && isJsSourceFile(decl.getSourceFile()) && functionCanReturnUndefined(decl))
|
|
968
|
+
mappedReturn = lowerer.withUndefinedArmOf(mappedReturn) ?? mappedReturn;
|
|
969
|
+
if (isJsSourceFile(decl.getSourceFile()) && mappedReturn?.kind === "void") {
|
|
970
|
+
let returnsValue = false;
|
|
971
|
+
const scan = (node) => {
|
|
972
|
+
if (node !== decl && ts.isFunctionLike(node))
|
|
973
|
+
return;
|
|
974
|
+
if (ts.isReturnStatement(node) && node.expression)
|
|
975
|
+
returnsValue = true;
|
|
976
|
+
node.forEachChild(scan);
|
|
977
|
+
};
|
|
978
|
+
scan(decl);
|
|
979
|
+
if (returnsValue)
|
|
980
|
+
return DYN;
|
|
981
|
+
}
|
|
982
|
+
if (isJsSourceFile(decl.getSourceFile()) && mappedReturn?.kind === "array")
|
|
983
|
+
return DYN;
|
|
984
|
+
if (isJsSourceFile(decl.getSourceFile()) && !decl.type && !hasExplicitJsDocReturn(decl) && mappedReturn?.kind === "record")
|
|
985
|
+
return DYN;
|
|
885
986
|
if (isJsSourceFile(decl.getSourceFile()) && !decl.type && !hasExplicitJsDocReturn(decl) && mappedReturn?.kind === "date")
|
|
886
987
|
return DYN;
|
|
988
|
+
if (isJsSourceFile(decl.getSourceFile()) && !decl.type && !hasExplicitJsDocReturn(decl) &&
|
|
989
|
+
mappedReturn?.kind === "union" && lowerer.unions.get(mappedReturn.unionId)?.arms.some((arm) => arm.kind === "func"))
|
|
990
|
+
return DYN;
|
|
887
991
|
// JS inference assigns Number to arithmetic over any, although the
|
|
888
992
|
// runtime operands can both be BigInts. Preserve that native result.
|
|
889
993
|
if (isJsSourceFile(decl.getSourceFile()) && !decl.type && !hasExplicitJsDocReturn(decl) &&
|
|
@@ -944,10 +1048,13 @@ export function declaredReturnType(lowerer, decl, blame) {
|
|
|
944
1048
|
// Native-only members (such as Int32Array layout offsets) cannot cross
|
|
945
1049
|
// that boundary; their factories keep the native record ABI.
|
|
946
1050
|
const asyncReturn = decl.modifiers?.some((modifier) => modifier.kind === ts.SyntaxKind.AsyncKeyword) && mappedReturn?.kind === "promise";
|
|
947
|
-
const recordReturn = asyncReturn ? mappedReturn.inner : mappedReturn;
|
|
1051
|
+
const recordReturn = asyncReturn && mappedReturn?.kind === "promise" ? mappedReturn.inner : mappedReturn;
|
|
1052
|
+
const recordArms = recordReturn?.kind === "union" ? lowerer.unions.get(recordReturn.unionId)?.arms : recordReturn ? [recordReturn] : undefined;
|
|
1053
|
+
const inferredRecordReturn = recordArms?.some((arm) => arm.kind === "record" || arm.kind === "object") &&
|
|
1054
|
+
recordArms.every((arm) => isUnitType(arm) || arm.kind === "record" || arm.kind === "object" && !hasExplicitJsDocReturn(decl));
|
|
948
1055
|
if (isJsSourceFile(decl.getSourceFile()) &&
|
|
949
1056
|
decl.type === undefined &&
|
|
950
|
-
recordReturn
|
|
1057
|
+
recordReturn !== null && recordReturn !== undefined && inferredRecordReturn &&
|
|
951
1058
|
lowerer.dynConvertible(recordReturn) &&
|
|
952
1059
|
decl.parameters.every((p) => {
|
|
953
1060
|
const mt = lowerer.mapTypeOf(lowerer.typeOf(p));
|
|
@@ -955,7 +1062,7 @@ export function declaredReturnType(lowerer, decl, blame) {
|
|
|
955
1062
|
})) {
|
|
956
1063
|
return asyncReturn ? { kind: "promise", inner: DYN } : DYN;
|
|
957
1064
|
}
|
|
958
|
-
const returnType =
|
|
1065
|
+
const returnType = mappedReturn;
|
|
959
1066
|
if (!returnType) {
|
|
960
1067
|
// JS inference residue (an `any` return, an unmappable union): the
|
|
961
1068
|
// checked-dynamic fallback, exactly the declaration story in
|
|
@@ -1565,6 +1672,7 @@ export function lowerGenericInstance(lowerer, info, inst) {
|
|
|
1565
1672
|
body.push(...lowerer.lowerStmts(bodyBlock.statements));
|
|
1566
1673
|
if (fnCtx.inferReturn) {
|
|
1567
1674
|
bodyReturn = resolveInferredReturn(lowerer, inst, fnCtx.inferReturn, body, decl);
|
|
1675
|
+
inst.returnType = bodyReturn;
|
|
1568
1676
|
}
|
|
1569
1677
|
appendImplicitUndefinedReturn(lowerer, body, bodyReturn, locOf(decl));
|
|
1570
1678
|
}
|
|
@@ -1578,6 +1686,7 @@ export function lowerGenericInstance(lowerer, info, inst) {
|
|
|
1578
1686
|
if (value.type.kind === "void") {
|
|
1579
1687
|
body.push({ kind: "exprStmt", expr: value, loc: locOf(decl.body) });
|
|
1580
1688
|
bodyReturn = resolveInferredReturn(lowerer, inst, fnCtx.inferReturn, body, decl);
|
|
1689
|
+
inst.returnType = bodyReturn;
|
|
1581
1690
|
appendImplicitUndefinedReturn(lowerer, body, bodyReturn, locOf(decl));
|
|
1582
1691
|
}
|
|
1583
1692
|
else {
|
|
@@ -1585,6 +1694,7 @@ export function lowerGenericInstance(lowerer, info, inst) {
|
|
|
1585
1694
|
fnCtx.inferReturn.entries.push({ stmt, node: decl.body });
|
|
1586
1695
|
body.push(stmt);
|
|
1587
1696
|
bodyReturn = resolveInferredReturn(lowerer, inst, fnCtx.inferReturn, body, decl);
|
|
1697
|
+
inst.returnType = bodyReturn;
|
|
1588
1698
|
}
|
|
1589
1699
|
}
|
|
1590
1700
|
else {
|
|
@@ -1639,7 +1749,9 @@ export function lowerGenericInstance(lowerer, info, inst) {
|
|
|
1639
1749
|
* adds JS's undefined; DYN when returns disagree (the checked-dynamic
|
|
1640
1750
|
* result slot — today's shape). Same-key recursion PINNED the fallback
|
|
1641
1751
|
* type mid-lowering (callers already hold it), so a pinned instance
|
|
1642
|
-
* keeps it and the wrap pass coerces every return to the pin.
|
|
1752
|
+
* keeps it and the wrap pass coerces every return to the pin. Callers
|
|
1753
|
+
* store the settled type on their full instance; this narrower view
|
|
1754
|
+
* can be a structural copy in native builds. */
|
|
1643
1755
|
function resolveInferredReturn(lowerer, inst, infer, body, decl) {
|
|
1644
1756
|
// The conservative completion test appendImplicitUndefinedReturn uses:
|
|
1645
1757
|
// a body whose last statement isn't a terminator may complete without
|
|
@@ -1670,14 +1782,13 @@ function resolveInferredReturn(lowerer, inst, infer, body, decl) {
|
|
|
1670
1782
|
else {
|
|
1671
1783
|
final = DYN; // disagreeing returns: the checked-dynamic join
|
|
1672
1784
|
}
|
|
1673
|
-
inst.returnType = final;
|
|
1674
1785
|
}
|
|
1675
1786
|
// The wrap pass: settle every recorded return onto `final`, in place.
|
|
1787
|
+
// Write through the stored union arm: optional-field widening on a
|
|
1788
|
+
// local alias can otherwise introduce a record copy in native builds.
|
|
1676
1789
|
for (const e of infer.entries) {
|
|
1677
1790
|
if (e.stmt.kind !== "return")
|
|
1678
1791
|
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
1792
|
const diagsBefore = lowerer.diags.length;
|
|
1682
1793
|
try {
|
|
1683
1794
|
if (e.stmt.value === null || e.stmt.value === undefined) {
|
|
@@ -2063,6 +2174,12 @@ function implicitDeclaredReturn(lowerer, info) {
|
|
|
2063
2174
|
if (retTs.flags & (ts.TypeFlags.Null | ts.TypeFlags.Undefined))
|
|
2064
2175
|
return DYN;
|
|
2065
2176
|
if (lowerer.checker.isArrayType(retTs)) {
|
|
2177
|
+
// Inferred JavaScript arrays can hold values selected through a
|
|
2178
|
+
// mutable constructor registry. The checker may retain only one
|
|
2179
|
+
// constructor's element type; settle the result from the lowered
|
|
2180
|
+
// container instead of checking every element against that guess.
|
|
2181
|
+
if (!hasExplicitJsDocReturn(info.decl))
|
|
2182
|
+
return null;
|
|
2066
2183
|
if (info.decl.parameters.some((param, index) => info.implicitParams?.[index] &&
|
|
2067
2184
|
lowerer.mapTypeOf(lowerer.typeOf(param.name))?.kind === "array"))
|
|
2068
2185
|
return null;
|
|
@@ -2076,6 +2193,39 @@ function implicitDeclaredReturn(lowerer, info) {
|
|
|
2076
2193
|
return null;
|
|
2077
2194
|
}
|
|
2078
2195
|
const mapped = lowerer.mapTypeOf(retTs);
|
|
2196
|
+
// Mixed inferred results can select a closure or a class instance.
|
|
2197
|
+
// Their callable ABI is settled by the lowered body, including native
|
|
2198
|
+
// classes whose reflected calls return checked values.
|
|
2199
|
+
if (mapped?.kind === "union" && !hasExplicitJsDocReturn(info.decl) &&
|
|
2200
|
+
lowerer.unions.get(mapped.unionId)?.arms.some((arm) => arm.kind === "func"))
|
|
2201
|
+
return null;
|
|
2202
|
+
if (mapped?.kind === "symbol" && !hasExplicitJsDocReturn(info.decl))
|
|
2203
|
+
return null;
|
|
2204
|
+
if (mapped?.kind === "date" && !hasExplicitJsDocReturn(info.decl))
|
|
2205
|
+
return DYN;
|
|
2206
|
+
if (!hasExplicitJsDocReturn(info.decl) && info.decl.body) {
|
|
2207
|
+
let openReturn = false;
|
|
2208
|
+
ts.walkPreorder(info.decl.body, (node) => {
|
|
2209
|
+
if (node !== info.decl.body && ts.isFunctionLike(node))
|
|
2210
|
+
return "skip";
|
|
2211
|
+
if (!ts.isReturnStatement(node) || !node.expression || !ts.isIdentifier(node.expression))
|
|
2212
|
+
return undefined;
|
|
2213
|
+
const symbol = lowerer.resolveValueSymbol(node.expression);
|
|
2214
|
+
if (symbol && lowerer.checker.declarationsOf(symbol).some((decl) => ts.isVariableDeclaration(decl) && jsBindingHasOpenWrites(lowerer, decl)))
|
|
2215
|
+
openReturn = true;
|
|
2216
|
+
return undefined;
|
|
2217
|
+
});
|
|
2218
|
+
if (openReturn)
|
|
2219
|
+
return null;
|
|
2220
|
+
}
|
|
2221
|
+
// A JavaScript result inferred from an initial record can later
|
|
2222
|
+
// carry additional fields. Settle its representation from the
|
|
2223
|
+
// lowered returns instead of copying it back into that initial shape.
|
|
2224
|
+
const resultArms = mapped?.kind === "union" ? lowerer.unions.get(mapped.unionId)?.arms : mapped ? [mapped] : [];
|
|
2225
|
+
if (resultArms?.some((arm) => arm.kind === "record" || arm.kind === "object" || arm.kind === "classval") &&
|
|
2226
|
+
resultArms.every((arm) => isUnitType(arm) || arm.kind === "record" || arm.kind === "object" || arm.kind === "classval") &&
|
|
2227
|
+
!hasExplicitJsDocReturn(info.decl))
|
|
2228
|
+
return null;
|
|
2079
2229
|
// Inferred variadic results carry runtime argument packs. Their
|
|
2080
2230
|
// factory must retain the lowered callable rather than extracting a
|
|
2081
2231
|
// fixed native signature from a checked value.
|
|
@@ -2117,15 +2267,52 @@ function bindableImplicitIr(t) {
|
|
|
2117
2267
|
function storedImplicitArgumentType(lowerer, arg) {
|
|
2118
2268
|
while (ts.isParenthesizedExpression(arg))
|
|
2119
2269
|
arg = arg.expression;
|
|
2270
|
+
if (isJsSourceFile(arg.getSourceFile()) && (ts.isArrowFunction(arg) || ts.isFunctionExpression(arg))) {
|
|
2271
|
+
const saved = lowerer.diagSink;
|
|
2272
|
+
const diagnostics = [];
|
|
2273
|
+
lowerer.diagSink = diagnostics;
|
|
2274
|
+
let value;
|
|
2275
|
+
try {
|
|
2276
|
+
value = tryLowerExpression(lowerer, arg);
|
|
2277
|
+
}
|
|
2278
|
+
finally {
|
|
2279
|
+
lowerer.diagSink = saved;
|
|
2280
|
+
}
|
|
2281
|
+
// Direct inferred helpers can receive native callbacks even when their
|
|
2282
|
+
// result is an opaque handle that cannot cross checked storage.
|
|
2283
|
+
if (diagnostics.length === 0 && value?.type.kind === "func")
|
|
2284
|
+
return value.type;
|
|
2285
|
+
}
|
|
2286
|
+
if (arg.kind === ts.SyntaxKind.ThisKeyword)
|
|
2287
|
+
return lowerer.resolveThis()?.type ?? null;
|
|
2120
2288
|
if (ts.isAwaitExpression(arg)) {
|
|
2121
2289
|
const awaited = storedImplicitArgumentType(lowerer, arg.expression);
|
|
2122
2290
|
return awaited?.kind === "promise" ? awaited.inner : awaited;
|
|
2123
2291
|
}
|
|
2124
|
-
if (ts.isObjectLiteralExpression(arg) && isJsSourceFile(arg.getSourceFile()) &&
|
|
2125
|
-
|
|
2292
|
+
if (ts.isObjectLiteralExpression(arg) && isJsSourceFile(arg.getSourceFile()) &&
|
|
2293
|
+
(arg.properties.length === 0 || arg.properties.some((property) => ts.isMethodDeclaration(property) || ts.isAccessor(property) ||
|
|
2294
|
+
!ts.isSpreadAssignment(property) && property.name !== undefined && ts.isComputedPropertyName(property.name))))
|
|
2126
2295
|
return DYN;
|
|
2127
2296
|
if (ts.isIdentifier(arg))
|
|
2128
2297
|
return lowerer.peekLocal(arg)?.type ?? lowerer.globalOf(arg)?.type ?? null;
|
|
2298
|
+
if (isJsSourceFile(arg.getSourceFile()) &&
|
|
2299
|
+
(ts.isPropertyAccessExpression(arg) || ts.isElementAccessExpression(arg))) {
|
|
2300
|
+
// Mutable JS members can retain an initializer-only checker type (for
|
|
2301
|
+
// example a linked-list slot initially null). Specialize to the value
|
|
2302
|
+
// we actually represent, rather than checking it back into that type.
|
|
2303
|
+
const represented = tryLowerExpression(lowerer, arg);
|
|
2304
|
+
if (represented)
|
|
2305
|
+
return represented.type;
|
|
2306
|
+
}
|
|
2307
|
+
if (isJsSourceFile(arg.getSourceFile()) && (ts.isCallExpression(arg) || ts.isConditionalExpression(arg) ||
|
|
2308
|
+
ts.isBinaryExpression(arg) && (arg.operatorToken.kind === ts.SyntaxKind.BarBarToken ||
|
|
2309
|
+
arg.operatorToken.kind === ts.SyntaxKind.AmpersandAmpersandToken || arg.operatorToken.kind === ts.SyntaxKind.QuestionQuestionToken))) {
|
|
2310
|
+
// Calls and fallback expressions can retain checked storage wider than
|
|
2311
|
+
// the checker's inference (for example Object.assign on a JS instance).
|
|
2312
|
+
const represented = tryLowerExpression(lowerer, arg);
|
|
2313
|
+
if (represented?.type.kind === "dyn" || represented?.type.kind === "func")
|
|
2314
|
+
return represented.type;
|
|
2315
|
+
}
|
|
2129
2316
|
if (ts.isCallExpression(arg) && ts.isIdentifier(arg.expression)) {
|
|
2130
2317
|
const callee = storedImplicitArgumentType(lowerer, arg.expression);
|
|
2131
2318
|
if (callee?.kind === "dyn")
|
|
@@ -2173,12 +2360,29 @@ export function implicitCallInstance(lowerer, call, info) {
|
|
|
2173
2360
|
shapes.push({ type: stored, mode: "required" });
|
|
2174
2361
|
return;
|
|
2175
2362
|
}
|
|
2363
|
+
if (stored?.kind === "func") {
|
|
2364
|
+
// The lowered closure may have an inferred JS destructuring
|
|
2365
|
+
// parameter widened from the checker's exact tuple to dyn.
|
|
2366
|
+
// Preserve that signature throughout the specialization.
|
|
2367
|
+
const checkerType = lowerer.mapTypeOf(lowerer.typeOf(arg));
|
|
2368
|
+
argTypes.set(sym, checkerType && typeEquals(checkerType, stored)
|
|
2369
|
+
? lowerer.typeOf(arg) : lowerer.checker.getUnknownType());
|
|
2370
|
+
shapes.push({ type: stored, mode: "required" });
|
|
2371
|
+
return;
|
|
2372
|
+
}
|
|
2176
2373
|
// The argument's own checker type, literal-widened ('add' binds
|
|
2177
2374
|
// string) — typeOf consults the ACTIVE instance's bindings, so a
|
|
2178
2375
|
// bound param forwarded into another implicit call transitively
|
|
2179
2376
|
// instantiates it (this._initCommandGroup(command)).
|
|
2180
2377
|
const t = lowerer.checker.getBaseTypeOfLiteralType(lowerer.typeOf(arg));
|
|
2181
|
-
const mapped = lowerer.mapTypeOf(t) ?? dynFallbackType(lowerer, arg, t);
|
|
2378
|
+
const mapped = (neverTaintedJsType(lowerer, arg, t) ? null : lowerer.mapTypeOf(t)) ?? dynFallbackType(lowerer, arg, t);
|
|
2379
|
+
if (isJsSourceFile(arg.getSourceFile()) && ts.isArrayLiteralExpression(arg) && mapped?.kind === "array" &&
|
|
2380
|
+
(mapped.elem.kind === "classval" || mapped.elem.kind === "union" &&
|
|
2381
|
+
lowerer.unions.get(mapped.elem.unionId)?.arms.every((arm) => arm.kind === "classval"))) {
|
|
2382
|
+
argTypes.set(sym, lowerer.checker.getUnknownType());
|
|
2383
|
+
shapes.push({ type: DYN, mode: "required" });
|
|
2384
|
+
return;
|
|
2385
|
+
}
|
|
2182
2386
|
// JavaScript arguments-based callables travel as checked functions.
|
|
2183
2387
|
// Specializing a parameter to the inferred rest signature would
|
|
2184
2388
|
// require extracting a native variadic ABI that the value does not
|
|
@@ -2192,6 +2396,11 @@ export function implicitCallInstance(lowerer, call, info) {
|
|
|
2192
2396
|
// That checker supertype is not an empty-record runtime layout:
|
|
2193
2397
|
// preserve represented arms through the checked boundary instead
|
|
2194
2398
|
// of specializing a call to a union that would discard them.
|
|
2399
|
+
if (isJsSourceFile(arg.getSourceFile()) && mapped?.kind === "func" && !lowerer.dynConvertible(mapped)) {
|
|
2400
|
+
argTypes.set(sym, lowerer.checker.getUnknownType());
|
|
2401
|
+
shapes.push({ type: DYN, mode: "required" });
|
|
2402
|
+
return;
|
|
2403
|
+
}
|
|
2195
2404
|
const mappedArms = mapped?.kind === "union" ? lowerer.unions.get(mapped.unionId)?.arms ?? [] : mapped ? [mapped] : [];
|
|
2196
2405
|
const hasTopObject = mappedArms.some((arm) => {
|
|
2197
2406
|
const shape = arm.kind === "record" ? lowerer.shapes.get(arm.shapeId) : undefined;
|
|
@@ -2737,7 +2946,15 @@ export function lowerTimersMemberCall(lowerer, expr, member, loc) {
|
|
|
2737
2946
|
if (expr.arguments.length !== 1) {
|
|
2738
2947
|
lowerer.noLowering(`clearTimeout with ${expr.arguments.length} arguments`, expr);
|
|
2739
2948
|
}
|
|
2740
|
-
|
|
2949
|
+
let handle = lowerer.lowerExpr(expr.arguments[0]);
|
|
2950
|
+
if (handle.type.kind === "dyn" && isJsSourceFile(expr.getSourceFile())) {
|
|
2951
|
+
const stored = lowerer.declareHiddenLocal("%timer.clear", DYN);
|
|
2952
|
+
const ref = varRef(stored.id, DYN, loc);
|
|
2953
|
+
handle = { kind: "seqExpr", stmts: [{ kind: "varDecl", localId: stored.id, init: handle, loc }], result: {
|
|
2954
|
+
kind: "ternary", cond: { kind: "dynTest", test: "number", value: ref, type: BOOL, loc },
|
|
2955
|
+
then: lowerer.coerceInto(expr.arguments[0], ref, F64), else_: numLit(0, loc), type: F64, loc,
|
|
2956
|
+
}, type: F64, loc };
|
|
2957
|
+
}
|
|
2741
2958
|
if (handle.type.kind !== "f64") {
|
|
2742
2959
|
lowerer.noLowering(`clearTimeout of '${lowerer.fmt(handle.type)}' handles`, expr.arguments[0], "the handle is the Timeout setTimeout returned (narrow 'Timeout | null' first)");
|
|
2743
2960
|
}
|
|
@@ -3264,6 +3481,14 @@ function lowerProjectedBuiltinCall(lowerer, expr, bi, loc) {
|
|
|
3264
3481
|
}
|
|
3265
3482
|
export function lowerCall(lowerer, expr) {
|
|
3266
3483
|
const loc = locOf(expr);
|
|
3484
|
+
// Object's checker return type is `any`. Claim known object inputs
|
|
3485
|
+
// before generic checked-dynamic dispatch tries to load the constructor.
|
|
3486
|
+
if (ts.isIdentifier(expr.expression) && expr.expression.text === "Object" &&
|
|
3487
|
+
lowerer.isStdlibGlobal(expr.expression, "Object")) {
|
|
3488
|
+
const object = lowerObjectConstructor(lowerer, expr.arguments, loc);
|
|
3489
|
+
if (object)
|
|
3490
|
+
return object;
|
|
3491
|
+
}
|
|
3267
3492
|
// A call whose chain ROOTS at an ambient-undefined name (`declare
|
|
3268
3493
|
// const value: Y | undefined; value?.foo("a")`, `declare function
|
|
3269
3494
|
// chain...; chain(o).mapValues(f).value()`, a trap binding's read):
|
|
@@ -3373,7 +3598,7 @@ export function lowerCall(lowerer, expr) {
|
|
|
3373
3598
|
// `a?.m()` (the token on the member access). The handled markers keep
|
|
3374
3599
|
// the chain lowering's re-entrant dispatch from looping.
|
|
3375
3600
|
if ((expr.questionDotToken && !lowerer.chainHandled.has(expr)) ||
|
|
3376
|
-
(ts.isPropertyAccessExpression(expr.expression) &&
|
|
3601
|
+
((ts.isPropertyAccessExpression(expr.expression) || ts.isElementAccessExpression(expr.expression)) &&
|
|
3377
3602
|
expr.expression.questionDotToken &&
|
|
3378
3603
|
!lowerer.chainHandled.has(expr.expression))) {
|
|
3379
3604
|
return lowerer.lowerOptionalChain(expr);
|
|
@@ -3382,6 +3607,9 @@ export function lowerCall(lowerer, expr) {
|
|
|
3382
3607
|
// top-level statement (its field-initializer ordering lives there);
|
|
3383
3608
|
// any other position would misorder initialization — rejected.
|
|
3384
3609
|
if (expr.expression.kind === ts.SyntaxKind.SuperKeyword) {
|
|
3610
|
+
const superCall = lowerer.ctx.superCall;
|
|
3611
|
+
if (superCall)
|
|
3612
|
+
return superCall(expr);
|
|
3385
3613
|
lowerer.unsupported("SC1090", expr, "super() calls anywhere but as a top-level constructor statement");
|
|
3386
3614
|
}
|
|
3387
3615
|
// super.method(...): a DIRECT (never virtual) call of the base chain's
|
|
@@ -3500,6 +3728,13 @@ export function lowerCall(lowerer, expr) {
|
|
|
3500
3728
|
loc,
|
|
3501
3729
|
});
|
|
3502
3730
|
}
|
|
3731
|
+
if (ts.isPropertyAccessExpression(expr.expression) &&
|
|
3732
|
+
TIMER_MODULE_MEMBERS.has(expr.expression.name.text) &&
|
|
3733
|
+
lowerer.stdlibGlobalMember(expr.expression, "globalThis") === expr.expression.name.text) {
|
|
3734
|
+
const served = lowerTimersMemberCall(lowerer, expr, expr.expression.name.text, loc);
|
|
3735
|
+
if (served)
|
|
3736
|
+
return served;
|
|
3737
|
+
}
|
|
3503
3738
|
// The timer globals — setTimeout/clearTimeout, setInterval/
|
|
3504
3739
|
// clearInterval, setImmediate/clearImmediate. Provenance-checked (a
|
|
3505
3740
|
// user function shadowing the name has a different, non-ambient
|
|
@@ -3642,9 +3877,7 @@ export function lowerCall(lowerer, expr) {
|
|
|
3642
3877
|
// Provenance-checked like setTimeout; zero-arg forms are the JS
|
|
3643
3878
|
// constants ("", false, 0). Wrapper objects stay fenced except where
|
|
3644
3879
|
// 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)) {
|
|
3880
|
+
if (lowerer.isStdlibGlobal(expr.expression, "BigInt")) {
|
|
3648
3881
|
if (expr.arguments.length !== 1) {
|
|
3649
3882
|
lowerer.noLowering(`BigInt with ${expr.arguments.length} arguments`, expr);
|
|
3650
3883
|
}
|
|
@@ -3657,12 +3890,11 @@ export function lowerCall(lowerer, expr) {
|
|
|
3657
3890
|
return converted;
|
|
3658
3891
|
lowerer.noLowering(`BigInt of ${lowerer.fmt(arg.type)} values`, argNode, "string, number, boolean, and bigint arguments are supported");
|
|
3659
3892
|
}
|
|
3660
|
-
if (
|
|
3661
|
-
(expr.expression
|
|
3662
|
-
|
|
3663
|
-
|
|
3664
|
-
|
|
3665
|
-
const name = expr.expression.text;
|
|
3893
|
+
if (lowerer.isStdlibGlobal(expr.expression, "String") ||
|
|
3894
|
+
lowerer.isStdlibGlobal(expr.expression, "Boolean") ||
|
|
3895
|
+
lowerer.isStdlibGlobal(expr.expression, "Number")) {
|
|
3896
|
+
const name = lowerer.isStdlibGlobal(expr.expression, "String") ? "String" :
|
|
3897
|
+
lowerer.isStdlibGlobal(expr.expression, "Boolean") ? "Boolean" : "Number";
|
|
3666
3898
|
if (expr.arguments.length > 1) {
|
|
3667
3899
|
lowerer.noLowering(`${name} with ${expr.arguments.length} arguments`, expr);
|
|
3668
3900
|
}
|
|
@@ -3692,8 +3924,9 @@ export function lowerCall(lowerer, expr) {
|
|
|
3692
3924
|
if (name === "Number")
|
|
3693
3925
|
return lowerNumberConstructorValue(lowerer, argNode, loc);
|
|
3694
3926
|
const arg = lowerer.lowerExpr(argNode);
|
|
3695
|
-
if (name === "String" && arg.type.kind === "dyn"
|
|
3696
|
-
|
|
3927
|
+
if (name === "String" && (arg.type.kind === "dyn" || arg.type.kind === "union" &&
|
|
3928
|
+
lowerer.unions.get(arg.type.unionId)?.arms.some((arm) => arm.kind === "symbol") && lowerer.dynConvertible(arg.type))) {
|
|
3929
|
+
return { kind: "libCall", fn: "dyn.stringConstructor", args: [lowerer.coerceToExpected(arg, DYN)], type: STRING, loc };
|
|
3697
3930
|
}
|
|
3698
3931
|
if (name === "String")
|
|
3699
3932
|
return lowerer.ensureString(arg, argNode);
|
|
@@ -3720,7 +3953,9 @@ export function lowerCall(lowerer, expr) {
|
|
|
3720
3953
|
lowerer.fenceStaticHeadersMember(access, "call");
|
|
3721
3954
|
lowerer.fenceStaticReadableStreamMember(access, "call");
|
|
3722
3955
|
const source = tryLowerExpression(lowerer, access.expression);
|
|
3723
|
-
if (source && (source.type.kind === "dyn" ||
|
|
3956
|
+
if (source && (source.type.kind === "dyn" || source.type.kind === "func" ||
|
|
3957
|
+
source.type.kind === "union" && isJsSourceFile(expr.getSourceFile()) && lowerer.dynConvertible(source.type) ||
|
|
3958
|
+
(source.type.kind === "map" || source.type.kind === "set") && lowerer.dynConvertible(source.type) || isDynTypedRefType(source.type) &&
|
|
3724
3959
|
lowerer.foldedStringKeyOf(access.argumentExpression) === null &&
|
|
3725
3960
|
lowerer.mapTypeOf(lowerer.typeOf(access.argumentExpression))?.kind !== "symbol")) {
|
|
3726
3961
|
const local = lowerer.declareHiddenLocal("%computedReceiver", DYN);
|
|
@@ -4106,6 +4341,9 @@ export function lowerCall(lowerer, expr) {
|
|
|
4106
4341
|
if (name === "parseFloat" && probed?.type.kind === "string") {
|
|
4107
4342
|
return { kind: "libCall", fn: "num.parseFloat", args: [probed], type: F64, loc };
|
|
4108
4343
|
}
|
|
4344
|
+
if (name === "parseFloat" && probed?.type.kind === "dyn") {
|
|
4345
|
+
return { kind: "libCall", fn: "num.parseFloat", args: [{ kind: "libCall", fn: "dyn.toStringCoerce", args: [probed], type: STRING, loc }], type: F64, loc };
|
|
4346
|
+
}
|
|
4109
4347
|
if (name === "isFinite" && probed?.type.kind === "f64") {
|
|
4110
4348
|
return { kind: "libCall", fn: "number.isFinite", args: [probed], type: BOOL, loc };
|
|
4111
4349
|
}
|
|
@@ -4123,6 +4361,7 @@ export function lowerCall(lowerer, expr) {
|
|
|
4123
4361
|
// string-only argument rule.
|
|
4124
4362
|
if ((expr.expression.text === "encodeURIComponent" ||
|
|
4125
4363
|
expr.expression.text === "encodeURI" ||
|
|
4364
|
+
expr.expression.text === "decodeURI" ||
|
|
4126
4365
|
expr.expression.text === "decodeURIComponent") &&
|
|
4127
4366
|
lowerer.isStdlibSymbol(lowerer.resolveValueSymbol(expr.expression) ?? undefined)) {
|
|
4128
4367
|
const name = expr.expression.text;
|
|
@@ -4131,10 +4370,10 @@ export function lowerCall(lowerer, expr) {
|
|
|
4131
4370
|
}
|
|
4132
4371
|
const loc = locOf(expr);
|
|
4133
4372
|
const argNode = expr.arguments[0];
|
|
4134
|
-
if (name === "decodeURIComponent") {
|
|
4373
|
+
if (name === "decodeURIComponent" || name === "decodeURI") {
|
|
4135
4374
|
const d = optionalCallValue(lowerer, argNode) ?? lowerer.lowerExpr(argNode);
|
|
4136
4375
|
const s = lowerer.ensureString(d, argNode);
|
|
4137
|
-
return { kind: "libCall", fn: "str.decodeUriComponent", args: [s], type: STRING, loc };
|
|
4376
|
+
return { kind: "libCall", fn: name === "decodeURI" ? "str.decodeUri" : "str.decodeUriComponent", args: [s], type: STRING, loc };
|
|
4138
4377
|
}
|
|
4139
4378
|
const value = optionalCallValue(lowerer, argNode) ?? lowerer.lowerExpr(argNode);
|
|
4140
4379
|
const s = lowerer.ensureString(value, argNode);
|
|
@@ -4415,7 +4654,8 @@ export function lowerCall(lowerer, expr) {
|
|
|
4415
4654
|
lowerer.lowerJsonMethodCall(expr, expr.expression) ??
|
|
4416
4655
|
// Reflect.apply of a builtin rest-parameter fn (fixtures.js's
|
|
4417
4656
|
// fixturesPath idiom) — before the stdlib member fence claims it.
|
|
4418
|
-
|
|
4657
|
+
lowerReflectCall(lowerer, expr, expr.expression) ??
|
|
4658
|
+
lowerBigIntStaticCall(lowerer, expr, expr.expression) ??
|
|
4419
4659
|
lowerer.lowerNumberStaticCall(expr, expr.expression) ??
|
|
4420
4660
|
lowerer.lowerDateCall(expr, expr.expression) ??
|
|
4421
4661
|
lowerer.lowerTextCodecCall(expr, expr.expression) ??
|
|
@@ -4431,6 +4671,7 @@ export function lowerCall(lowerer, expr) {
|
|
|
4431
4671
|
// Before the island path: regex-argument replace/replaceAll/split
|
|
4432
4672
|
// lower STATICALLY; only the string-pattern overloads are island.
|
|
4433
4673
|
lowerRegexMethodCallWithOptionalArg(lowerer, expr, expr.expression) ??
|
|
4674
|
+
lowerUrlStaticCall(lowerer, expr, expr.expression) ??
|
|
4434
4675
|
lowerer.lowerUrlMethodCall(expr, expr.expression) ??
|
|
4435
4676
|
lowerer.lowerSearchParamsMethodCall(expr, expr.expression) ??
|
|
4436
4677
|
lowerer.lowerStatsMethodCall(expr, expr.expression) ??
|
|
@@ -4481,14 +4722,11 @@ export function lowerCall(lowerer, expr) {
|
|
|
4481
4722
|
lowerer.lowerBytesMethodCall(expr, expr.expression) ??
|
|
4482
4723
|
lowerBytesStaticCall(lowerer, expr, expr.expression) ??
|
|
4483
4724
|
lowerBufferStaticCallWithNarrowedArg(lowerer, expr, expr.expression) ??
|
|
4484
|
-
// URL.revokeObjectURL's zero-argument contract (the one-argument
|
|
4485
|
-
// form keeps the fence — createObjectURL does too).
|
|
4486
|
-
lowerUrlStaticCall(lowerer, expr, expr.expression) ??
|
|
4487
4725
|
// Readable.from — the stream classes' one static (before the
|
|
4488
4726
|
// stdlib chokepoint claims the member).
|
|
4489
4727
|
lowerStreamStaticCall(lowerer, expr, expr.expression) ??
|
|
4490
|
-
//
|
|
4491
|
-
//
|
|
4728
|
+
// Primitive toString calls, including numeric radices, use the
|
|
4729
|
+
// native formatters before the island method path.
|
|
4492
4730
|
lowerNumberToStringCall(lowerer, expr, expr.expression) ??
|
|
4493
4731
|
// Union receivers whose every arm has a text — the ngrok
|
|
4494
4732
|
// `(chunk: Buffer | string) => chunk.toString()` idiom.
|
|
@@ -4528,7 +4766,6 @@ export function lowerCall(lowerer, expr) {
|
|
|
4528
4766
|
// by the receiver's own element.
|
|
4529
4767
|
lowerer.lowerFilterNarrowCall(expr, expr.expression) ??
|
|
4530
4768
|
lowerArrayIsArrayCall(lowerer, expr, expr.expression) ??
|
|
4531
|
-
lowerBigIntStaticCall(lowerer, expr, expr.expression) ??
|
|
4532
4769
|
lowerBigIntMethodCall(lowerer, expr, expr.expression) ??
|
|
4533
4770
|
lowerSymbolStaticCall(lowerer, expr, expr.expression) ??
|
|
4534
4771
|
lowerSymbolMethodCall(lowerer, expr, expr.expression) ??
|
|
@@ -4563,6 +4800,13 @@ export function lowerCall(lowerer, expr) {
|
|
|
4563
4800
|
lowerObjLitGenericMethodCall(lowerer, expr, expr.expression);
|
|
4564
4801
|
if (intrinsic)
|
|
4565
4802
|
return intrinsic;
|
|
4803
|
+
if (isJsSourceFile(expr.getSourceFile())) {
|
|
4804
|
+
const staticField = lowerStaticFieldRead(lowerer, expr.expression);
|
|
4805
|
+
if (staticField?.type.kind === "dyn" && !expr.arguments.some(ts.isSpreadElement)) {
|
|
4806
|
+
return { kind: "dynCall", callee: staticField, receiver: lowerer.lowerExprExpecting(expr.expression.expression, DYN), calleeName: expr.expression.getText(),
|
|
4807
|
+
args: expr.arguments.map((arg) => lowerer.lowerExprExpecting(arg, DYN)), type: DYN, loc: locOf(expr) };
|
|
4808
|
+
}
|
|
4809
|
+
}
|
|
4566
4810
|
const accessorTarget = lowerer.fieldTarget(expr.expression);
|
|
4567
4811
|
if (accessorTarget?.container === "accessor") {
|
|
4568
4812
|
const callee = lowerer.fieldGetExpr(accessorTarget, locOf(expr.expression), expr.expression);
|
|
@@ -4635,6 +4879,30 @@ export function lowerCall(lowerer, expr) {
|
|
|
4635
4879
|
lowerer.fenceStaticHeadersMember(expr.expression, "call");
|
|
4636
4880
|
lowerer.fenceStaticReadableStreamMember(expr.expression, "call");
|
|
4637
4881
|
}
|
|
4882
|
+
// Computed native members retain their original receiver and resolve
|
|
4883
|
+
// the function before argument effects, just like dotted calls.
|
|
4884
|
+
if (ts.isElementAccessExpression(expr.expression) && !expr.expression.questionDotToken && !expr.questionDotToken &&
|
|
4885
|
+
!symbolFieldInfo(lowerer, expr.expression)) {
|
|
4886
|
+
const access = expr.expression;
|
|
4887
|
+
const value = tryLowerExpression(lowerer, access.expression);
|
|
4888
|
+
if (value?.type.kind === "dyn" || value?.type.kind === "generator" ||
|
|
4889
|
+
value && ["array", "bytes", "map", "set"].includes(value.type.kind) && lowerer.dynConvertible(value.type) ||
|
|
4890
|
+
value?.type.kind === "string" && !ts.isStringLiteralLike(access.argumentExpression) && lowerer.dynConvertible(value.type) ||
|
|
4891
|
+
value?.type.kind === "object" && !lowerer.classes.get(value.type.className)?.def.runtime) {
|
|
4892
|
+
const local = lowerer.declareHiddenLocal("%computedReceiver", value.type);
|
|
4893
|
+
const reference = { kind: "varRef", localId: local.id, type: value.type, loc };
|
|
4894
|
+
const receiver = lowerer.coerceToExpected(reference, DYN);
|
|
4895
|
+
const raw = lowerer.lowerExpr(access.argumentExpression);
|
|
4896
|
+
const key = raw.type.kind === "string" ? raw : lowerer.coerceInto(access.argumentExpression, raw, DYN);
|
|
4897
|
+
const callee = { kind: "dynKeyGet", value: receiver, key, type: DYN, loc };
|
|
4898
|
+
const spread = expr.arguments.some(ts.isSpreadElement) ? lowerSpreadArgsCall(lowerer, expr, callee, loc) : null;
|
|
4899
|
+
if (spread && spread.kind !== "dynCall")
|
|
4900
|
+
lowerer.unsupported("SC1090", expr, "computed native method spread arguments");
|
|
4901
|
+
const result = spread !== null ? { ...spread, receiver } : { kind: "dynCall", callee, receiver,
|
|
4902
|
+
calleeName: access.getText(), args: expr.arguments.map((arg) => lowerer.lowerExprExpecting(arg, DYN)), type: DYN, loc };
|
|
4903
|
+
return { kind: "seqExpr", stmts: [{ kind: "varDecl", localId: local.id, init: value, loc }], result, type: DYN, loc };
|
|
4904
|
+
}
|
|
4905
|
+
}
|
|
4638
4906
|
// The ELEMENT spelling of a primitive method call — `x['toString']()`,
|
|
4639
4907
|
// `s['charAt'](0)`: JS resolves it exactly like the dot form, so the
|
|
4640
4908
|
// literal-keyed shapes with a static lowering route there before the
|
|
@@ -4720,6 +4988,11 @@ export function lowerCall(lowerer, expr) {
|
|
|
4720
4988
|
: "value";
|
|
4721
4989
|
return { kind: "dynCall", callee, calleeName, args, type: DYN, loc };
|
|
4722
4990
|
}
|
|
4991
|
+
if (callee.type.kind === "union" && lowerer.dynConvertible(callee.type) &&
|
|
4992
|
+
lowerer.unions.get(callee.type.unionId)?.arms.some((arm) => arm.kind === "func")) {
|
|
4993
|
+
return { kind: "dynCall", callee: lowerer.coerceToExpected(callee, DYN), calleeName: expr.expression.getText(),
|
|
4994
|
+
args: expr.arguments.map((arg) => lowerer.lowerExprExpecting(arg, DYN)), type: DYN, loc };
|
|
4995
|
+
}
|
|
4723
4996
|
if (callee.type.kind !== "func") {
|
|
4724
4997
|
lowerer.badType(expr.expression, lowerer.typeOf(expr.expression));
|
|
4725
4998
|
}
|
|
@@ -4959,6 +5232,10 @@ function lowerNumberConstructorValue(lowerer, argNode, loc) {
|
|
|
4959
5232
|
return { kind: "libCall", fn: "num.fromString", args: [arg], type: F64, loc };
|
|
4960
5233
|
if (arg.type.kind === "dyn")
|
|
4961
5234
|
return { kind: "libCall", fn: "dyn.numberConstructor", args: [arg], type: F64, loc };
|
|
5235
|
+
if (arg.type.kind === "union" && lowerer.dynConvertible(arg.type))
|
|
5236
|
+
return {
|
|
5237
|
+
kind: "libCall", fn: "dyn.numberConstructor", args: [lowerer.coerceToExpected(arg, DYN)], type: F64, loc,
|
|
5238
|
+
};
|
|
4962
5239
|
const optionalNumber = lowerOptionalStringNumber(lowerer, arg, loc);
|
|
4963
5240
|
if (optionalNumber)
|
|
4964
5241
|
return optionalNumber;
|
|
@@ -4973,6 +5250,8 @@ function lowerNumberConstructorValue(lowerer, argNode, loc) {
|
|
|
4973
5250
|
* checker guard. Dispatch BigInt by the actual value, including nullish
|
|
4974
5251
|
* TypeErrors, rather than interpreting that storage as the narrowed arm. */
|
|
4975
5252
|
function lowerBigIntConstructorValue(lowerer, arg, loc) {
|
|
5253
|
+
if (arg.type.kind === "dyn")
|
|
5254
|
+
return { kind: "libCall", fn: "dyn.bigintConstructor", args: [arg], type: BIGINT_T, loc };
|
|
4976
5255
|
if (arg.type.kind === "bigint")
|
|
4977
5256
|
return arg;
|
|
4978
5257
|
if (arg.type.kind === "string")
|
|
@@ -5244,8 +5523,9 @@ function lowerObjectOwnCall(lowerer, call, receiverNode, keyNode, extraNodes, me
|
|
|
5244
5523
|
stmts.push({ kind: "exprStmt", expr: effect, loc: locOf(extra) });
|
|
5245
5524
|
}
|
|
5246
5525
|
let key = keyRef;
|
|
5247
|
-
if (receiverRef.type.kind === "
|
|
5248
|
-
|
|
5526
|
+
if (lowerer.dynConvertible(receiverRef.type) && keyRef && (receiverRef.type.kind === "object" || keyRef.type.kind === "symbol" || keyRef.type.kind === "dyn" ||
|
|
5527
|
+
keyRef.type.kind === "union" && lowerer.dynConvertible(keyRef.type))) {
|
|
5528
|
+
const result = { kind: "libCall", fn: enumerable ? "dyn.propertyIsEnumerableComputed" : "dyn.hasOwnComputed", args: [lowerer.coerceToExpected(receiverRef, DYN), lowerer.coerceToExpected(keyRef, DYN)], type: BOOL, loc };
|
|
5249
5529
|
return { kind: "seqExpr", stmts, result, type: BOOL, loc };
|
|
5250
5530
|
}
|
|
5251
5531
|
if (!keyNode || rawKey?.type.kind === "undefinedT" || rawKey?.type.kind === "void") {
|
|
@@ -5441,6 +5721,9 @@ function lowerStringPrototypeCall(lowerer, call, access) {
|
|
|
5441
5721
|
// padding uses a helper that delays conversion until every argument is ready.
|
|
5442
5722
|
const objectWithoutMethodArgs = entry?.maxArgs === 0 && call.arguments.length === 1 &&
|
|
5443
5723
|
(receiverType.kind === "record" || receiverType.kind === "array" || receiverType.kind === "object");
|
|
5724
|
+
if (padding && !scalar && lowerer.dynConvertible(receiverType)) {
|
|
5725
|
+
return lowerStringPaddingCall(lowerer, call, entry.method, lowerer.coerceToExpected(receiverValue, DYN), receiverNode, call.arguments.slice(1));
|
|
5726
|
+
}
|
|
5444
5727
|
if (!scalar && !objectWithoutMethodArgs) {
|
|
5445
5728
|
lowerer.noLowering(`String.prototype.${methodAccess.name.text}.call with ${lowerer.fmt(receiverType)} receivers`, call);
|
|
5446
5729
|
}
|
|
@@ -5581,7 +5864,7 @@ function lowerSpreadArgsCall(lowerer, expr, callee, loc) {
|
|
|
5581
5864
|
// The spelling rides along for V8's nullish spread-call
|
|
5582
5865
|
// TypeError ("v is not iterable (cannot read property ...)").
|
|
5583
5866
|
spreads.push({ arg: args.length, what: p.spreadOf.getText() });
|
|
5584
|
-
args.push(lowerer
|
|
5867
|
+
args.push(checkedIterableSpread(lowerer, p.v, p.spreadOf.getText(), loc));
|
|
5585
5868
|
}
|
|
5586
5869
|
else {
|
|
5587
5870
|
args.push(lowerer.coerceInto(p.node, p.v, DYN));
|
|
@@ -5591,7 +5874,7 @@ function lowerSpreadArgsCall(lowerer, expr, callee, loc) {
|
|
|
5591
5874
|
return { kind: "dynCall", callee: boxed, calleeName, args, spreads, type: DYN, loc };
|
|
5592
5875
|
}
|
|
5593
5876
|
if (spreadParts.length > 0 &&
|
|
5594
|
-
spreadParts.every((p) => p.v.type.kind === "jsval") &&
|
|
5877
|
+
(spreadParts.every((p) => p.v.type.kind === "jsval") || callee.type.kind === "func" && callee.type.restAbi === "jsval") &&
|
|
5595
5878
|
(callee.type.kind === "jsval" || callee.type.kind === "func")) {
|
|
5596
5879
|
if (spreadParts.length !== 1 || parts[parts.length - 1].spreadOf === null) {
|
|
5597
5880
|
lowerer.unsupported("SC1090", expr, "spread arguments before positional arguments in island calls (one trailing spread after the fixed arguments is the supported form)");
|
|
@@ -5604,7 +5887,7 @@ function lowerSpreadArgsCall(lowerer, expr, callee, loc) {
|
|
|
5604
5887
|
const last = parts[parts.length - 1];
|
|
5605
5888
|
// The spelling rides in `name` for V8's nullish spread-call
|
|
5606
5889
|
// TypeError ("v is not iterable (cannot read property ...)").
|
|
5607
|
-
return { kind: "jsOp", op: "callSpread", name: last.spreadOf.getText(), args: [f, preArr, last.v], type: JSVAL, loc };
|
|
5890
|
+
return { kind: "jsOp", op: "callSpread", name: last.spreadOf.getText(), args: [f, preArr, lowerer.coerceInto(last.spreadOf, last.v, JSVAL)], type: JSVAL, loc };
|
|
5608
5891
|
}
|
|
5609
5892
|
// No lane fits (a spread source outside both tiers, a callee neither
|
|
5610
5893
|
// boxable nor marshalable, mixed dyn/jsval spreads): fence HERE — the
|
|
@@ -5656,12 +5939,21 @@ function canCompleteRuntimeSpread(lowerer, shapes) {
|
|
|
5656
5939
|
function lowerDynReceiverMethodCall(lowerer, call, access) {
|
|
5657
5940
|
if (lowerer.chainBlocked(call, access))
|
|
5658
5941
|
return null;
|
|
5942
|
+
if (stdlibGlobalNameOf(lowerer, access.expression) !== null)
|
|
5943
|
+
return null;
|
|
5659
5944
|
// Only checker-untyped receivers: `any`/`unknown`, or the `any[]` an
|
|
5660
5945
|
// Array.isArray guard narrows them to (the value is STILL the checked-dynamic tree
|
|
5661
5946
|
// array — scalar narrowings bridge through maybeNarrow's dynCheck and
|
|
5662
5947
|
// take the ordinary typed paths, but there is no static home for an
|
|
5663
5948
|
// any-elemented array). Typed receivers keep their own lowerings.
|
|
5664
5949
|
const recvTs = lowerer.typeOf(access.expression);
|
|
5950
|
+
const recvSymbol = recvTs.getSymbol();
|
|
5951
|
+
if (recvSymbol && ["MapIterator", "SetIterator"].includes(recvSymbol.name) &&
|
|
5952
|
+
lowerer.isStdlibSymbol(recvSymbol) &&
|
|
5953
|
+
["map", "filter", "take", "drop", "flatMap", "toArray", "forEach", "reduce", "some", "every", "find"].includes(access.name.text) &&
|
|
5954
|
+
lowerer.isStdlibMember(access)) {
|
|
5955
|
+
lowerer.noLowering(`collection iterator .${access.name.text}()`, call, "stored Map/Set iterators support .next() and iteration; iterator helper methods have no lowering");
|
|
5956
|
+
}
|
|
5665
5957
|
const arrayReceiver = lowerer.checker.isArrayType(recvTs);
|
|
5666
5958
|
const anyArray = arrayReceiver &&
|
|
5667
5959
|
((lowerer.checker.getTypeArguments(recvTs)[0]?.flags ?? 0) &
|
|
@@ -5677,11 +5969,11 @@ function lowerDynReceiverMethodCall(lowerer, call, access) {
|
|
|
5677
5969
|
// tsc types the return by the evolved shape, the binding lowered
|
|
5678
5970
|
// dyn): probe the lowering and claim exactly the dyn results.
|
|
5679
5971
|
const probed = tryLowerExpression(lowerer, access.expression);
|
|
5680
|
-
if (
|
|
5972
|
+
if (probed?.type.kind === "func" && stdlibGlobalNameOf(lowerer, access.expression) === null &&
|
|
5681
5973
|
!["call", "apply", "bind", "toString", "valueOf", "constructor"].includes(access.name.text) &&
|
|
5682
5974
|
canBoxFuncIntoDyn(probed.type, (id) => lowerer.shapes.get(id), (id) => lowerer.unions.get(id))) {
|
|
5683
5975
|
const loc = locOf(call);
|
|
5684
|
-
const fnName = jsFuncNameOf(access.expression);
|
|
5976
|
+
const fnName = jsFuncNameOf(access.expression, lowerer);
|
|
5685
5977
|
const boxed = { kind: "dynFrom", value: probed, type: DYN, loc, ...(fnName !== null ? { fnName } : {}) };
|
|
5686
5978
|
const local = lowerer.declareHiddenLocal("%callableReceiver", DYN);
|
|
5687
5979
|
const receiver = { kind: "varRef", localId: local.id, type: DYN, loc };
|
|
@@ -5698,9 +5990,27 @@ function lowerDynReceiverMethodCall(lowerer, call, access) {
|
|
|
5698
5990
|
args: call.arguments.map((arg) => lowerer.lowerExprExpecting(arg, DYN)), type: DYN, loc }, type: DYN, loc,
|
|
5699
5991
|
};
|
|
5700
5992
|
}
|
|
5701
|
-
if (probed?.type.kind
|
|
5702
|
-
|
|
5703
|
-
|
|
5993
|
+
if (probed?.type.kind === "classval") {
|
|
5994
|
+
const info = lowerer.classes.get(probed.type.className);
|
|
5995
|
+
if (info)
|
|
5996
|
+
return lowerStaticMethodCall(lowerer, call, access);
|
|
5997
|
+
}
|
|
5998
|
+
if (probed?.type.kind === "union" && isJsSourceFile(call.getSourceFile()) &&
|
|
5999
|
+
lowerer.unions.get(probed.type.unionId)?.arms.every((arm) => isUnitType(arm) || arm.kind === "object" || arm.kind === "record" || arm.kind === "func") && lowerer.dynConvertible(probed.type)) {
|
|
6000
|
+
recv = lowerer.coerceToExpected(probed, DYN);
|
|
6001
|
+
}
|
|
6002
|
+
else {
|
|
6003
|
+
if (probed?.type.kind !== "dyn")
|
|
6004
|
+
return null;
|
|
6005
|
+
recv = probed;
|
|
6006
|
+
}
|
|
6007
|
+
}
|
|
6008
|
+
// A factory may return a constructor more precise than its inferred
|
|
6009
|
+
// checker result. Runtime static members live on that constructor.
|
|
6010
|
+
if (recv.type.kind === "classval") {
|
|
6011
|
+
const info = lowerer.classes.get(recv.type.className);
|
|
6012
|
+
if (info)
|
|
6013
|
+
return lowerStaticMethodCall(lowerer, call, access);
|
|
5704
6014
|
}
|
|
5705
6015
|
// A checker-`any` receiver that already lowered to a real STRING (the
|
|
5706
6016
|
// chained form — `cfg.host.trim().toLowerCase()`, where the first step
|
|
@@ -5715,6 +6025,25 @@ function lowerDynReceiverMethodCall(lowerer, call, access) {
|
|
|
5715
6025
|
}
|
|
5716
6026
|
if (recv.type.kind !== "dyn")
|
|
5717
6027
|
return null;
|
|
6028
|
+
if (access.name.text === "normalize" && call.arguments.length <= 1 && !call.arguments.some(ts.isSpreadElement)) {
|
|
6029
|
+
const loc = locOf(call);
|
|
6030
|
+
const hasArgument = call.arguments.length === 1;
|
|
6031
|
+
const name = `%dyn.string.normalize:${hasArgument ? 1 : 0}`;
|
|
6032
|
+
if (!lowerer.liftedFns.some((fn) => fn.name === name)) {
|
|
6033
|
+
const value = varRef("receiver", DYN, loc);
|
|
6034
|
+
const argument = varRef("form", DYN, loc);
|
|
6035
|
+
const form = { kind: "ternary", cond: { kind: "dynTest", value: argument, test: "undefined", type: BOOL, loc },
|
|
6036
|
+
then: { kind: "strLit", value: "NFC", type: STRING, loc },
|
|
6037
|
+
else_: { kind: "libCall", fn: "dyn.toStringCoerce", args: [argument], type: STRING, loc }, type: STRING, loc };
|
|
6038
|
+
const result = { kind: "strIntrinsic", method: "normalize", receiver: { kind: "dynCheck", value, type: STRING, loc }, args: [form], type: STRING, loc };
|
|
6039
|
+
lowerer.liftedFns.push({ name, params: [{ localId: "receiver", name: "receiver", type: DYN }, { localId: "form", name: "form", type: DYN }],
|
|
6040
|
+
locals: [{ id: "receiver", name: "receiver", type: DYN, mutable: false }, { id: "form", name: "form", type: DYN, mutable: false }], returnType: DYN, loc,
|
|
6041
|
+
body: [{ kind: "if", cond: { kind: "dynTest", value, test: "string", type: BOOL, loc }, then: [
|
|
6042
|
+
{ kind: "return", value: { kind: "dynFrom", value: result, type: DYN, loc }, loc },
|
|
6043
|
+
], else_: null, loc }, { kind: "return", value: { kind: "dynInvoke", recv: value, method: "normalize", calleeName: access.getText(), args: hasArgument ? [argument] : [], type: DYN, loc }, loc }] });
|
|
6044
|
+
}
|
|
6045
|
+
return { kind: "call", callee: name, args: [recv, call.arguments[0] ? lowerer.lowerExprExpecting(call.arguments[0], DYN) : dynUndefinedExpr(loc)], type: DYN, loc };
|
|
6046
|
+
}
|
|
5718
6047
|
if (lowerer.mapTypeOf(recvTs)?.kind === "classval") {
|
|
5719
6048
|
return lowerStaticMethodCall(lowerer, call, access);
|
|
5720
6049
|
}
|
|
@@ -5770,7 +6099,16 @@ function lowerDynReceiverMethodCall(lowerer, call, access) {
|
|
|
5770
6099
|
// unimplemented methods throw a LOUD not-supported Error; names the
|
|
5771
6100
|
// kind's prototype lacks throw Node's "x.y is not a function"; OBJ
|
|
5772
6101
|
// receivers call the own member.
|
|
5773
|
-
|
|
6102
|
+
// A stored callback must be read before argument effects, and called
|
|
6103
|
+
// with the original receiver rather than a materialized property view.
|
|
6104
|
+
const callbackProperty = (() => {
|
|
6105
|
+
const prop = lowerer.checker.getPropertyOfType(recvTs, access.name.text);
|
|
6106
|
+
const mapped = lowerer.mapTypeOf(recvTs);
|
|
6107
|
+
if (mapped?.kind === "union" && lowerer.unions.get(mapped.unionId)?.arms.every((arm) => arm.kind === "object" && lowerer.classes.get(arm.className)?.fields.has(access.name.text)))
|
|
6108
|
+
return true;
|
|
6109
|
+
return prop !== undefined && lowerer.checker.declarationsOf(prop).some((decl) => ts.isPropertyDeclaration(decl) || ts.isPropertySignature(decl));
|
|
6110
|
+
})();
|
|
6111
|
+
const dispatched = callbackProperty ? null : lowerDynDispatchMethodCall(lowerer, call, access, recv, arrayReceiver);
|
|
5774
6112
|
if (dispatched)
|
|
5775
6113
|
return dispatched;
|
|
5776
6114
|
// Names NO dyn-representable prototype declares: the member can only
|
|
@@ -5796,9 +6134,6 @@ function lowerDynReceiverMethodCall(lowerer, call, access) {
|
|
|
5796
6134
|
if (call.questionDotToken || access.questionDotToken)
|
|
5797
6135
|
return null;
|
|
5798
6136
|
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
6137
|
const receiverLocal = lowerer.declareHiddenLocal("%dynCallReceiver", DYN);
|
|
5803
6138
|
const receiver = { kind: "varRef", localId: receiverLocal.id, type: DYN, loc };
|
|
5804
6139
|
const member = {
|
|
@@ -5808,10 +6143,24 @@ function lowerDynReceiverMethodCall(lowerer, call, access) {
|
|
|
5808
6143
|
type: DYN,
|
|
5809
6144
|
loc: locOf(access),
|
|
5810
6145
|
};
|
|
6146
|
+
const calleeLocal = lowerer.declareHiddenLocal("%dynCallCallee", DYN);
|
|
6147
|
+
const callee = varRef(calleeLocal.id, DYN, loc);
|
|
6148
|
+
const stmts = [
|
|
6149
|
+
{ kind: "varDecl", localId: receiverLocal.id, init: recv, loc },
|
|
6150
|
+
{ kind: "varDecl", localId: calleeLocal.id, init: member, loc },
|
|
6151
|
+
];
|
|
6152
|
+
if (call.arguments.some(ts.isSpreadElement)) {
|
|
6153
|
+
const spread = lowerSpreadArgsCall(lowerer, call, callee, loc);
|
|
6154
|
+
if (spread?.kind === "dynCall")
|
|
6155
|
+
return { kind: "seqExpr",
|
|
6156
|
+
stmts,
|
|
6157
|
+
result: { ...spread, receiver }, type: DYN, loc };
|
|
6158
|
+
lowerer.unsupported("SC1090", call, "spread arguments in calls through 'unknown' values");
|
|
6159
|
+
}
|
|
5811
6160
|
const args = call.arguments.map((a) => lowerer.lowerExprExpecting(a, DYN));
|
|
5812
6161
|
return {
|
|
5813
|
-
kind: "seqExpr", stmts
|
|
5814
|
-
result: { kind: "dynCall", callee
|
|
6162
|
+
kind: "seqExpr", stmts,
|
|
6163
|
+
result: { kind: "dynCall", callee, receiver, calleeName: access.getText(), args, type: DYN, loc }, type: DYN, loc,
|
|
5815
6164
|
};
|
|
5816
6165
|
}
|
|
5817
6166
|
/** Prototype method names of the checked-dynamic tree-representable kinds (String, Array,
|
|
@@ -5839,6 +6188,7 @@ const DYN_PROTO_METHOD_NAMES = new Set([
|
|
|
5839
6188
|
* is-not-a-function where the kind's prototype lacks the name, and
|
|
5840
6189
|
* fences LOUDLY on real-but-unimplemented pairs. */
|
|
5841
6190
|
const DYN_DISPATCH_METHODS = new Set([
|
|
6191
|
+
"toFixed", "toExponential",
|
|
5842
6192
|
"segment", "containing", "resolvedOptions", "test", "exec",
|
|
5843
6193
|
"apply", "bind", "call",
|
|
5844
6194
|
"push", "pop", "shift", "unshift", "slice", "at",
|
|
@@ -5858,7 +6208,7 @@ const DYN_DISPATCH_METHODS = new Set([
|
|
|
5858
6208
|
"setEncoding", "setDefaultEncoding", "setTimeout", "read", "isPaused",
|
|
5859
6209
|
"writeHead", "setHeader", "getHeader", "hasHeader", "removeHeader",
|
|
5860
6210
|
"getHeaders", "getHeaderNames", "appendHeader", "flushHeaders",
|
|
5861
|
-
"add", "append", "delete", "get", "getSetCookie", "has", "set",
|
|
6211
|
+
"add", "append", "delete", "get", "getSetCookie", "has", "set", "clear", "keys", "values", "entries", "next",
|
|
5862
6212
|
"writeContinue", "writeEarlyHints", "cork", "uncork", "addTrailers",
|
|
5863
6213
|
"ref", "unref", "address", "setNoDelay", "setKeepAlive", "connect",
|
|
5864
6214
|
"resetAndDestroy", "destroySoon",
|
|
@@ -5879,7 +6229,7 @@ const DYN_DISPATCH_METHODS = new Set([
|
|
|
5879
6229
|
"dispatchEvent",
|
|
5880
6230
|
"preventDefault", "stopPropagation", "stopImmediatePropagation",
|
|
5881
6231
|
"composedPath",
|
|
5882
|
-
"json", "text", "bytes",
|
|
6232
|
+
"json", "text", "bytes", "arrayBuffer",
|
|
5883
6233
|
// Promise.prototype (SCR_DYN_PROMISE receivers): the reaction trio
|
|
5884
6234
|
// rides the fiber machinery (scr_dyn_promise_then); on every other dyn
|
|
5885
6235
|
// kind then/catch/finally answer the stored-member path (OBJ own
|
|
@@ -5899,6 +6249,17 @@ export function lowerDynDispatchMethodCall(lowerer, call, access, recv, arrayRec
|
|
|
5899
6249
|
if ((!DYN_DISPATCH_METHODS.has(method) && !isJsSourceFile(call.getSourceFile())) || lowerer.chainBlocked(call, access))
|
|
5900
6250
|
return null;
|
|
5901
6251
|
if (call.arguments.some((arg) => ts.isSpreadElement(arg))) {
|
|
6252
|
+
const loc = locOf(call);
|
|
6253
|
+
const local = lowerer.declareHiddenLocal("%spreadReceiver", DYN);
|
|
6254
|
+
const receiver = varRef(local.id, DYN, loc);
|
|
6255
|
+
const callee = { kind: "dynKeyGet", value: receiver,
|
|
6256
|
+
key: { kind: "strLit", value: method, type: STRING, loc }, type: DYN, loc };
|
|
6257
|
+
const spread = lowerSpreadArgsCall(lowerer, call, callee, loc);
|
|
6258
|
+
if (spread?.kind === "dynCall")
|
|
6259
|
+
return { kind: "seqExpr",
|
|
6260
|
+
stmts: [{ kind: "varDecl", localId: local.id, init: recv, loc },
|
|
6261
|
+
{ kind: "exprStmt", expr: { kind: "libCall", fn: "dyn.arrayPrototype", args: [], type: DYN, loc }, loc }],
|
|
6262
|
+
result: { ...spread, receiver }, type: DYN, loc };
|
|
5902
6263
|
lowerer.unsupported("SC1090", call, "spread arguments in calls through 'unknown' values");
|
|
5903
6264
|
}
|
|
5904
6265
|
const predicate = method === "filter" && call.arguments[0]
|
|
@@ -5972,7 +6333,12 @@ export function lowerDynDispatchMethodCall(lowerer, call, access, recv, arrayRec
|
|
|
5972
6333
|
}
|
|
5973
6334
|
}
|
|
5974
6335
|
}
|
|
5975
|
-
const args = call.arguments.map((arg, i) =>
|
|
6336
|
+
const args = call.arguments.map((arg, i) => {
|
|
6337
|
+
if (i === 0 && predicate)
|
|
6338
|
+
return lowerer.coerceInto(arg, predicate, DYN);
|
|
6339
|
+
const undefinedArg = lowerStaticallyUndefinedArgument(lowerer, arg);
|
|
6340
|
+
return undefinedArg ? defaultAfterUndefined(undefinedArg, dynUndefinedExpr(locOf(arg))) : lowerer.lowerExprExpecting(arg, DYN);
|
|
6341
|
+
});
|
|
5976
6342
|
return {
|
|
5977
6343
|
kind: "dynInvoke",
|
|
5978
6344
|
recv,
|
|
@@ -6098,13 +6464,13 @@ function lowerCaughtPredicateCall(lowerer, call, caughtLocal) {
|
|
|
6098
6464
|
* and String(n) lower to (Number::toString with radix 10 IS that
|
|
6099
6465
|
* conversion, per spec) — booleans the "true"/"false" texts, and strings
|
|
6100
6466
|
* the identity read (String.prototype.toString returns `this`). The
|
|
6101
|
-
* explicit-radix number form
|
|
6467
|
+
* explicit-radix number form uses the native radix formatter;
|
|
6102
6468
|
* null for other receivers, argument shapes, or non-lib members (a
|
|
6103
6469
|
* user's own `.toString` takes the ordinary paths). */
|
|
6104
6470
|
function lowerNumberToStringCall(lowerer, call, access) {
|
|
6105
6471
|
if (lowerer.chainBlocked(call, access))
|
|
6106
6472
|
return null;
|
|
6107
|
-
if (access.name.text !== "toString" || call.arguments.length
|
|
6473
|
+
if (access.name.text !== "toString" || call.arguments.length > 1 || call.arguments.some(ts.isSpreadElement))
|
|
6108
6474
|
return null;
|
|
6109
6475
|
const recvKind = lowerer.mapTypeOf(lowerer.typeOf(access.expression))?.kind;
|
|
6110
6476
|
if (recvKind !== "f64" && recvKind !== "bool" && recvKind !== "string")
|
|
@@ -6112,6 +6478,22 @@ function lowerNumberToStringCall(lowerer, call, access) {
|
|
|
6112
6478
|
if (!lowerer.isStdlibMember(access))
|
|
6113
6479
|
return null;
|
|
6114
6480
|
const operand = lowerer.lowerExpr(access.expression);
|
|
6481
|
+
// JavaScript array and typed-array reads can still be undefined even
|
|
6482
|
+
// when the checker declares a number. Preserve that runtime value and
|
|
6483
|
+
// let native method dispatch format numbers or throw for missing data.
|
|
6484
|
+
if (operand.type.kind === "dyn") {
|
|
6485
|
+
return {
|
|
6486
|
+
kind: "libCall", fn: "dyn.toString", args: [operand,
|
|
6487
|
+
call.arguments[0] ? lowerer.lowerExprExpecting(call.arguments[0], DYN) : dynUndefinedExpr(locOf(call)),
|
|
6488
|
+
{ kind: "strLit", value: access.getText(), type: STRING, loc: locOf(call) },
|
|
6489
|
+
], type: STRING, loc: locOf(call),
|
|
6490
|
+
};
|
|
6491
|
+
}
|
|
6492
|
+
if (call.arguments.length === 1) {
|
|
6493
|
+
if (operand.type.kind !== "f64")
|
|
6494
|
+
return null;
|
|
6495
|
+
return { kind: "libCall", fn: "num.toStringRadix", args: [operand, lowerer.lowerExprExpecting(call.arguments[0], DYN)], type: STRING, loc: locOf(call) };
|
|
6496
|
+
}
|
|
6115
6497
|
if (operand.type.kind === "string")
|
|
6116
6498
|
return operand; // identity, receiver evaluated
|
|
6117
6499
|
if (operand.type.kind !== "f64" && operand.type.kind !== "bool")
|
|
@@ -6305,6 +6687,15 @@ function lowerPrimitiveProtoCall(lowerer, call, recv, name, memberSym) {
|
|
|
6305
6687
|
if (!lowerer.isStdlibSymbol(memberSym))
|
|
6306
6688
|
return null;
|
|
6307
6689
|
const recvKind = lowerer.mapTypeOf(lowerer.typeOf(recv))?.kind;
|
|
6690
|
+
if ((name === "toFixed" || name === "toExponential") && call.arguments.length <= 1 &&
|
|
6691
|
+
!call.arguments.some(ts.isSpreadElement) && isJsSourceFile(call.getSourceFile())) {
|
|
6692
|
+
const operand = lowerer.lowerExpr(recv);
|
|
6693
|
+
if (operand.type.kind === "dyn" || operand.type.kind === "union" && lowerer.dynConvertible(operand.type))
|
|
6694
|
+
return {
|
|
6695
|
+
kind: "dynInvoke", recv: lowerer.coerceToExpected(operand, DYN), method: name, calleeName: `${recv.getText()}.${name}`,
|
|
6696
|
+
args: call.arguments.map((argument) => lowerer.lowerExprExpecting(argument, DYN)), type: DYN, loc: locOf(call),
|
|
6697
|
+
};
|
|
6698
|
+
}
|
|
6308
6699
|
if (recvKind !== "f64" && recvKind !== "bool" && recvKind !== "string")
|
|
6309
6700
|
return null;
|
|
6310
6701
|
const loc = locOf(call);
|
|
@@ -6574,15 +6965,14 @@ function templateEscapesValid(raw) {
|
|
|
6574
6965
|
* maps to string[] (type-mapper.ts), so the array rides the ordinary
|
|
6575
6966
|
* slot-directed coercion into whatever the tag's first parameter wants
|
|
6576
6967
|
* — string[] exactly, an `any` slot through the dyn boundary, a rest
|
|
6577
|
-
* pack's first element.
|
|
6578
|
-
*
|
|
6579
|
-
*
|
|
6968
|
+
* pack's first element. Checked tags receive frozen cooked and raw
|
|
6969
|
+
* arrays with the standard nonenumerable `.raw` descriptor. Typed direct
|
|
6970
|
+
* tags retain the string-array representation.
|
|
6580
6971
|
*
|
|
6581
6972
|
* Tag forms: a top-level declared function (the direct-call fast path —
|
|
6582
6973
|
* overload sets reconcile through the resolved signature exactly like
|
|
6583
6974
|
* plain calls), an island value under --dynamic (engine method/function
|
|
6584
|
-
* call
|
|
6585
|
-
* `.raw` there answers undefined where Node carries the raw spans), and
|
|
6975
|
+
* call with the engine's cooked/raw template object), and
|
|
6586
6976
|
* a checked-dynamic value (the dynCall boundary — a non-function tag
|
|
6587
6977
|
* throws Node's catchable TypeError). Everything else — generic tags,
|
|
6588
6978
|
* method tags, function-value bindings — fences by name. */
|
|
@@ -6642,10 +7032,11 @@ export function lowerTaggedTemplate(lowerer, expr) {
|
|
|
6642
7032
|
if (ts.isIdentifier(expr.tag) && !lowerer.isSelfReference(expr.tag)) {
|
|
6643
7033
|
if (lowerer.isTopLevelFnSymbol(expr.tag) && !lowerer.peekLocal(expr.tag)) {
|
|
6644
7034
|
fenceEarlyAliasUse(lowerer, expr.tag, expr);
|
|
6645
|
-
|
|
7035
|
+
const genericTag = lowerer.genericFnOf(expr.tag);
|
|
7036
|
+
if (genericTag && !genericTag.implicitParams) {
|
|
6646
7037
|
lowerer.unsupported("SC1090", expr, "tagged templates with generic tag functions");
|
|
6647
7038
|
}
|
|
6648
|
-
const sig = lowerer.fnSigOf(expr.tag);
|
|
7039
|
+
const sig = genericTag ? null : lowerer.fnSigOf(expr.tag);
|
|
6649
7040
|
if (sig) {
|
|
6650
7041
|
lowerer.noteEdge(sig.name);
|
|
6651
7042
|
const args = completeArgs(lowerer, values, sig.params, loc, expr, [strings()]);
|
|
@@ -6672,10 +7063,13 @@ export function lowerTaggedTemplate(lowerer, expr) {
|
|
|
6672
7063
|
// Checked-dynamic tags (`var f: any; f\`abc\``, dyn property chains):
|
|
6673
7064
|
// the dynCall boundary — arguments convert into dyn, a non-function
|
|
6674
7065
|
// tag throws Node's catchable "<name> is not a function" TypeError.
|
|
6675
|
-
|
|
7066
|
+
let callee = lowerer.lowerExpr(expr.tag);
|
|
7067
|
+
if (callee.type.kind === "func" && isJsSourceFile(expr.getSourceFile()) && lowerer.dynConvertible(callee.type)) {
|
|
7068
|
+
callee = { kind: "dynFrom", value: callee, type: DYN, loc };
|
|
7069
|
+
}
|
|
6676
7070
|
if (callee.type.kind === "dyn") {
|
|
6677
7071
|
const args = [
|
|
6678
|
-
lowerer
|
|
7072
|
+
loweredTemplateStrings(lowerer, expr, pieces.map((piece) => piece.text), loc, pieces.map(templateRawTextOf)),
|
|
6679
7073
|
...values.map((a) => lowerer.lowerExprExpecting(a, DYN)),
|
|
6680
7074
|
];
|
|
6681
7075
|
const calleeName = ts.isPropertyAccessExpression(expr.tag) || ts.isElementAccessExpression(expr.tag)
|
|
@@ -6687,12 +7081,15 @@ export function lowerTaggedTemplate(lowerer, expr) {
|
|
|
6687
7081
|
}
|
|
6688
7082
|
lowerer.unsupported("SC1090", expr, "tagged templates with this tag form (top-level functions and dynamic values tag; call the function directly otherwise)");
|
|
6689
7083
|
}
|
|
6690
|
-
function loweredTemplateStrings(lowerer, expr, cooked, loc) {
|
|
7084
|
+
function loweredTemplateStrings(lowerer, expr, cooked, loc, raw) {
|
|
6691
7085
|
// Normal runtime construction keeps this array aligned with the current
|
|
6692
7086
|
// ScrArr layout in the backend. The old static-header IR node encoded the
|
|
6693
7087
|
// pre-sparse layout in LLVM and crashed as soon as a tag read its strings.
|
|
6694
|
-
const type = arrayOf(STRING);
|
|
6695
|
-
const
|
|
7088
|
+
const type = raw ? DYN : arrayOf(STRING);
|
|
7089
|
+
const array = (values) => ({ kind: "dynArrLit", elems: values.map((value) => ({ kind: "dynFrom", value: { kind: "strLit", value, type: STRING, loc }, type: DYN, loc })), type: DYN, loc });
|
|
7090
|
+
const freeze = (value) => ({ kind: "libCall", fn: "dyn.freeze", args: [value], type: DYN, loc });
|
|
7091
|
+
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;
|
|
7092
|
+
const key = `templateStringsGlobal:${loc.file}:${expr.template.getStart()}:${raw ? "checked" : "typed"}`;
|
|
6696
7093
|
let getter = lowerer.widthHelpers.get(key);
|
|
6697
7094
|
if (!getter) {
|
|
6698
7095
|
const site = lowerer.globalsList.length;
|
|
@@ -6714,7 +7111,7 @@ function loweredTemplateStrings(lowerer, expr, cooked, loc) {
|
|
|
6714
7111
|
{
|
|
6715
7112
|
kind: "assign",
|
|
6716
7113
|
localId: globalId,
|
|
6717
|
-
value: {
|
|
7114
|
+
value: checked ?? {
|
|
6718
7115
|
kind: "arrayLit",
|
|
6719
7116
|
elems: cooked.map((value) => ({ kind: "strLit", value, type: STRING, loc })),
|
|
6720
7117
|
type,
|
|
@@ -6779,6 +7176,17 @@ export function lowerNestedFunctionDecl(lowerer, stmt) {
|
|
|
6779
7176
|
throw new InternalCompilerError("lowerer bug: nested function declaration has no active statement list");
|
|
6780
7177
|
}
|
|
6781
7178
|
const init = lowerer.lowerLambda(stmt);
|
|
7179
|
+
// Body inference may settle a JS return differently from the initial
|
|
7180
|
+
// checker signature. Publish that same ABI on the hoisted binding and
|
|
7181
|
+
// every mutable capture of it before callers are lowered.
|
|
7182
|
+
if (init.type.kind === "func" && !typeEquals(local.type, init.type)) {
|
|
7183
|
+
local.type = init.type;
|
|
7184
|
+
for (const fn of lowerer.liftedFns)
|
|
7185
|
+
for (const capture of fn.captures ?? []) {
|
|
7186
|
+
if (capture.localId === local.id)
|
|
7187
|
+
capture.type = init.type;
|
|
7188
|
+
}
|
|
7189
|
+
}
|
|
6782
7190
|
return { kind: "assign", localId: local.id, value: init, loc: locOf(stmt) };
|
|
6783
7191
|
}
|
|
6784
7192
|
/** Signature checks + param shapes + IR func type for any lambda-like
|
|
@@ -6819,6 +7227,23 @@ export function lambdaSignature(lowerer, node) {
|
|
|
6819
7227
|
: "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
7228
|
}
|
|
6821
7229
|
const shapes = lowerer.paramShapes(node.parameters);
|
|
7230
|
+
// Error-first callbacks captured by native filesystem adapters receive
|
|
7231
|
+
// the selected runtime overload. Ambient contextual inference can pick
|
|
7232
|
+
// the string overload even when options request a Buffer.
|
|
7233
|
+
if ((ts.isArrowFunction(node) || ts.isFunctionExpression(node)) && ts.isCallExpression(node.parent) &&
|
|
7234
|
+
node.parent.arguments.at(-1) === node) {
|
|
7235
|
+
const builtin = ts.isPropertyAccessExpression(node.parent.expression) ? lowerer.builtinMemberOf(node.parent.expression)
|
|
7236
|
+
: ts.isIdentifier(node.parent.expression) ? lowerer.builtinImportOf(node.parent.expression) : null;
|
|
7237
|
+
if (builtin?.module === "fs" && builtin.member !== "rename" && builtinModuleFnOf(lowerer, builtin.module, builtin.member)?.fn === "fs.callbackCall") {
|
|
7238
|
+
for (let index = 0; index < shapes.length; index++) {
|
|
7239
|
+
if (!node.parameters[index]?.type) {
|
|
7240
|
+
shapes[index].type = DYN;
|
|
7241
|
+
if (shapes[index].bodyType)
|
|
7242
|
+
shapes[index].bodyType = DYN;
|
|
7243
|
+
}
|
|
7244
|
+
}
|
|
7245
|
+
}
|
|
7246
|
+
}
|
|
6822
7247
|
// A concise arrow over an h2-only stream/session call (`() =>
|
|
6823
7248
|
// req.stream.destroy()`): the call ALWAYS throws on this lowering
|
|
6824
7249
|
// (stream is undefined — the streamUndefCall precedent), so the body
|
|
@@ -6919,14 +7344,28 @@ export function lambdaSignature(lowerer, node) {
|
|
|
6919
7344
|
* object-literal shorthand method to a module-level function and yields
|
|
6920
7345
|
* the `closure` expression creating it. */
|
|
6921
7346
|
export function lowerLambda(lowerer, node) {
|
|
7347
|
+
const prepared = (ts.isArrowFunction(node) || ts.isFunctionExpression(node)) ? lowerer.preparedClassFactories.get(node) : undefined;
|
|
7348
|
+
if (prepared)
|
|
7349
|
+
return prepared;
|
|
6922
7350
|
const loc = locOf(node);
|
|
6923
|
-
const
|
|
7351
|
+
const signature = lowerer.lambdaSignature(node);
|
|
7352
|
+
const { shapes } = signature;
|
|
7353
|
+
let { funcType } = signature;
|
|
7354
|
+
// Reflected JS methods receive the caller's actual `this`, which may
|
|
7355
|
+
// be a Proxy or a descriptor-created object rather than the class.
|
|
7356
|
+
// Fluent methods must return that receiver without a class cast.
|
|
7357
|
+
if (ts.isMethodDeclaration(node) && isJsSourceFile(node.getSourceFile()) &&
|
|
7358
|
+
!node.type && !node.asteriskToken && !hasExplicitJsDocReturn(node) && returnsOnlyThis(node)) {
|
|
7359
|
+
funcType = { ...funcType, ret: funcType.ret.kind === "promise" ? { ...funcType.ret, inner: DYN } : DYN };
|
|
7360
|
+
}
|
|
6924
7361
|
// A lambda IS a value: the completed-ABI rule applies at birth. The
|
|
6925
7362
|
// contextual (target) type decides — `(x?: number) => void` may flow
|
|
6926
7363
|
// into a slot annotated `(x: number | undefined) => void` (same ABI
|
|
6927
7364
|
// signature), anything else is fenced. Nested function declarations and
|
|
6928
7365
|
// object-literal shorthand methods aren't expressions — always fenced.
|
|
6929
|
-
|
|
7366
|
+
if (!(ts.isMethodDeclaration(node) && isJsSourceFile(node.getSourceFile()) &&
|
|
7367
|
+
canBoxFuncIntoDyn(funcType, (id) => lowerer.shapes.get(id), (id) => lowerer.unions.get(id))))
|
|
7368
|
+
lowerer.requireExactArityValue(node, ts.isArrowFunction(node) || ts.isFunctionExpression(node) ? node : null, shapes, funcType);
|
|
6930
7369
|
const nameIdent = !ts.isArrowFunction(node) && node.name && ts.isIdentifier(node.name) ? node.name : null;
|
|
6931
7370
|
const baseName = nameIdent ? nameIdent.text : "";
|
|
6932
7371
|
const fnName = `%fn${lowerer.lambdaCounter++}${baseName ? `_${baseName}` : ""}`;
|
|
@@ -6950,10 +7389,18 @@ export function lowerLambda(lowerer, node) {
|
|
|
6950
7389
|
if (isGenerator &&
|
|
6951
7390
|
(funcType.ret.kind !== "generator" || (funcType.ret.async === true) !== isAsync))
|
|
6952
7391
|
lowerer.badType(node, lowerer.typeOf(node));
|
|
6953
|
-
|
|
7392
|
+
let bodyReturn = isGenerator
|
|
6954
7393
|
? lowerer.genBodyReturnType(funcType.ret)
|
|
6955
7394
|
: lowerer.bodyReturnType(isAsync, funcType.ret);
|
|
6956
7395
|
const fnCtx = newFnCtx(true, selfSymbol, funcType, bodyReturn);
|
|
7396
|
+
const inferredSignature = isJsSourceFile(node.getSourceFile()) && !node.type ? lowerer.checker.getSignatureFromDeclaration(node) : undefined;
|
|
7397
|
+
const returnsConstructor = inferredSignature && producesConstructor(lowerer, lowerer.checker.getReturnTypeOfSignature(inferredSignature));
|
|
7398
|
+
if (isJsSourceFile(node.getSourceFile()) && !node.type && !isAsync && !isGenerator &&
|
|
7399
|
+
(bodyReturn.kind === "classval" || bodyReturn.kind === "date" || bodyReturn.kind === "symbol" || bodyReturn.kind === "record" ||
|
|
7400
|
+
(bodyReturn.kind === "dyn" || bodyReturn.kind === "func") && returnsConstructor)) {
|
|
7401
|
+
fnCtx.inferReturn = { entries: [] };
|
|
7402
|
+
}
|
|
7403
|
+
fnCtx.inheritsArguments = ts.isArrowFunction(node);
|
|
6957
7404
|
fnCtx.isAsync = isAsync;
|
|
6958
7405
|
if (isGenerator && funcType.ret.kind === "generator") {
|
|
6959
7406
|
fnCtx.generator = generatorMeta(lowerer, funcType.ret);
|
|
@@ -6967,7 +7414,7 @@ export function lowerLambda(lowerer, node) {
|
|
|
6967
7414
|
// and a method nested inside another method never captures its owner.
|
|
6968
7415
|
if (isJsSourceFile(node.getSourceFile()) && !ts.isArrowFunction(node)) {
|
|
6969
7416
|
const receiver = lowerer.declareThis(DYN);
|
|
6970
|
-
prologue.unshift({ kind: "varDecl", localId: receiver.id, init: { kind: "libCall", fn: "dyn.this", args: [], type: DYN, loc }, loc });
|
|
7417
|
+
prologue.unshift({ kind: "varDecl", localId: receiver.id, init: { kind: "libCall", fn: isGenerator ? "dyn.generatorThis" : "dyn.this", args: [], type: DYN, loc }, loc });
|
|
6971
7418
|
}
|
|
6972
7419
|
// The synthetic trailing dyn-array param carries `arguments`.
|
|
6973
7420
|
// Parameterized functions receive all actual arguments; zero-param
|
|
@@ -6977,6 +7424,15 @@ export function lowerLambda(lowerer, node) {
|
|
|
6977
7424
|
params.push({ localId: argsLocal.id, name: "%arguments", type: DYN });
|
|
6978
7425
|
fnCtx.argumentsLocal = argsLocal;
|
|
6979
7426
|
}
|
|
7427
|
+
if (isJsSourceFile(node.getSourceFile()) && !ts.isArrowFunction(node) &&
|
|
7428
|
+
shapes.length === 1 && shapes[0]?.mode === "dynRest" && bodyReadsArguments(node)) {
|
|
7429
|
+
const argsLocal = lowerer.declareHiddenLocal("%arguments", DYN);
|
|
7430
|
+
prologue.push({ kind: "varDecl", localId: argsLocal.id, init: {
|
|
7431
|
+
kind: "dynInvoke", recv: varRef(params[0].localId, DYN, loc), method: "slice",
|
|
7432
|
+
calleeName: "Array.prototype.slice", args: [], type: DYN, loc,
|
|
7433
|
+
}, loc });
|
|
7434
|
+
fnCtx.argumentsLocal = argsLocal;
|
|
7435
|
+
}
|
|
6980
7436
|
let body;
|
|
6981
7437
|
if (ts.isBlock(node.body)) {
|
|
6982
7438
|
body = lowerer.lowerStmts(node.body.statements);
|
|
@@ -7011,7 +7467,7 @@ export function lowerLambda(lowerer, node) {
|
|
|
7011
7467
|
else {
|
|
7012
7468
|
// Concise and block bodies use the same destination layout for
|
|
7013
7469
|
// fresh literals. Async bodies must inspect promises first.
|
|
7014
|
-
let value = isAsync ? lowerer.lowerExpr(bodyExpr) : lowerer.lowerExprExpecting(bodyExpr, bodyReturn);
|
|
7470
|
+
let value = isAsync || fnCtx.inferReturn ? lowerer.lowerExpr(bodyExpr) : lowerer.lowerExprExpecting(bodyExpr, bodyReturn);
|
|
7015
7471
|
// An async concise body whose value is itself a promise
|
|
7016
7472
|
// (`async () => p`): the async machinery RESOLVES the returned
|
|
7017
7473
|
// thenable into the function's own promise — lowerReturnValue's
|
|
@@ -7025,17 +7481,25 @@ export function lowerLambda(lowerer, node) {
|
|
|
7025
7481
|
: [
|
|
7026
7482
|
{
|
|
7027
7483
|
kind: "return",
|
|
7028
|
-
value: lowerer.coerceInto(bodyExpr, value, bodyReturn),
|
|
7484
|
+
value: fnCtx.inferReturn ? value : lowerer.coerceInto(bodyExpr, value, bodyReturn),
|
|
7029
7485
|
loc: locOf(node.body),
|
|
7030
7486
|
},
|
|
7031
7487
|
];
|
|
7488
|
+
if (fnCtx.inferReturn && body[0]?.kind === "return")
|
|
7489
|
+
fnCtx.inferReturn.entries.push({ stmt: body[0], node: bodyExpr });
|
|
7032
7490
|
}
|
|
7033
7491
|
}
|
|
7492
|
+
if (fnCtx.inferReturn) {
|
|
7493
|
+
bodyReturn = resolveInferredReturn(lowerer, { returnType: bodyReturn }, fnCtx.inferReturn, body, node);
|
|
7494
|
+
funcType = { ...funcType, ret: bodyReturn };
|
|
7495
|
+
fnCtx.returnType = bodyReturn;
|
|
7496
|
+
}
|
|
7034
7497
|
body = [...prologue, ...body];
|
|
7035
7498
|
// Bare-expression bodies never pass through lowerStmts, so the
|
|
7036
7499
|
// lib-boundary chokepoint runs here (idempotent for block bodies,
|
|
7037
7500
|
// whose statements were already walked). A fence poisons the
|
|
7038
7501
|
// enclosing statement — the lambda IS part of it.
|
|
7502
|
+
body = lowerSurplusCalls(lowerer, body);
|
|
7039
7503
|
enforceLibBoundary(lowerer, body);
|
|
7040
7504
|
appendImplicitUndefinedReturn(lowerer, body, bodyReturn, loc);
|
|
7041
7505
|
const ctx = lowerer.ctx;
|
|
@@ -7189,7 +7653,7 @@ export function lowerPromiseMethodCall(lowerer, call, access) {
|
|
|
7189
7653
|
const member = access.name.text;
|
|
7190
7654
|
if (member !== "then" && member !== "catch" && member !== "finally")
|
|
7191
7655
|
return null;
|
|
7192
|
-
let recvT = lowerer.mapTypeOf(lowerer.typeOf(access.expression));
|
|
7656
|
+
let recvT = lowerer.mapTypeOf(lowerer.typeOf(access.expression)) ?? dynFallbackType(lowerer, access.expression, lowerer.typeOf(access.expression));
|
|
7193
7657
|
// A dynamic-import promise under an unmappable checker type
|
|
7194
7658
|
// (`Promise<typeof import("./m")>` — module-namespace types have no
|
|
7195
7659
|
// static mapping): the BINDING holds the island promise
|
|
@@ -7242,6 +7706,8 @@ export function lowerPromiseMethodCall(lowerer, call, access) {
|
|
|
7242
7706
|
loc,
|
|
7243
7707
|
};
|
|
7244
7708
|
}
|
|
7709
|
+
if (receiver.type.kind === "dyn" && lowerer.dynConvertible(recvT))
|
|
7710
|
+
receiver = lowerer.coerceInto(access.expression, receiver, recvT);
|
|
7245
7711
|
if (receiver.type.kind !== "promise") {
|
|
7246
7712
|
// mapTypeOf said promise but the value lowered as something else —
|
|
7247
7713
|
// a lowering gap, named rather than ICEd on.
|
|
@@ -7501,7 +7967,7 @@ export function lowerPromiseMethodCall(lowerer, call, access) {
|
|
|
7501
7967
|
value: {
|
|
7502
7968
|
kind: "dynCall",
|
|
7503
7969
|
callee: { kind: "varRef", localId: cbLocal.id, type: DYN, loc },
|
|
7504
|
-
calleeName: jsFuncNameOf(call.arguments[0]) ?? "onFulfilled",
|
|
7970
|
+
calleeName: jsFuncNameOf(call.arguments[0], lowerer) ?? "onFulfilled",
|
|
7505
7971
|
args: handlerArgs,
|
|
7506
7972
|
type: DYN,
|
|
7507
7973
|
loc,
|
|
@@ -7534,7 +8000,8 @@ export function lowerPromiseMethodCall(lowerer, call, access) {
|
|
|
7534
8000
|
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
8001
|
}
|
|
7536
8002
|
const param = cb.type.params[0];
|
|
7537
|
-
if (param !== undefined && !typeEquals(param, inner)
|
|
8003
|
+
if (param !== undefined && !typeEquals(param, inner) &&
|
|
8004
|
+
!(param.kind === "dyn" && (inner.kind === "void" || lowerer.dynConvertible(inner)))) {
|
|
7538
8005
|
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
8006
|
}
|
|
7540
8007
|
const resultT = lowerer.mapTypeOf(lowerer.typeOf(call));
|
|
@@ -7564,10 +8031,12 @@ export function lowerPromiseMethodCall(lowerer, call, access) {
|
|
|
7564
8031
|
if (param !== undefined && inner.kind !== "void") {
|
|
7565
8032
|
const vLocal = lowerer.declareHiddenLocal("v", inner);
|
|
7566
8033
|
body.push({ kind: "varDecl", localId: vLocal.id, init: awaitE, loc });
|
|
7567
|
-
handlerArgs = [{ kind: "varRef", localId: vLocal.id, type: inner, loc }];
|
|
8034
|
+
handlerArgs = [lowerer.coerceToExpected({ kind: "varRef", localId: vLocal.id, type: inner, loc }, param)];
|
|
7568
8035
|
}
|
|
7569
8036
|
else {
|
|
7570
8037
|
body.push({ kind: "exprStmt", expr: awaitE, loc });
|
|
8038
|
+
if (param !== undefined)
|
|
8039
|
+
handlerArgs = [dynUndefinedExpr(loc)];
|
|
7571
8040
|
}
|
|
7572
8041
|
const handlerCall = {
|
|
7573
8042
|
kind: "callValue",
|
|
@@ -7623,6 +8092,14 @@ export function lowerPromiseMethodCall(lowerer, call, access) {
|
|
|
7623
8092
|
}
|
|
7624
8093
|
if (member === "finally") {
|
|
7625
8094
|
const cb = lowerer.lowerExpr(call.arguments[0]);
|
|
8095
|
+
if (lowerer.dynConvertible(promT) && lowerer.dynConvertible(cb.type)) {
|
|
8096
|
+
const result = {
|
|
8097
|
+
kind: "dynInvoke", recv: lowerer.coerceToExpected(receiver, DYN),
|
|
8098
|
+
method: "finally", calleeName: access.getText(),
|
|
8099
|
+
args: [lowerer.coerceToExpected(cb, DYN)], type: DYN, loc,
|
|
8100
|
+
};
|
|
8101
|
+
return lowerer.coerceToExpected(result, promT);
|
|
8102
|
+
}
|
|
7626
8103
|
if (cb.type.kind !== "func" || cb.type.params.length !== 0 || cb.type.ret.kind !== "void") {
|
|
7627
8104
|
lowerer.unsupported("SC1090", call.arguments[0], "finally callbacks with parameters or a return value (use () => { ... })");
|
|
7628
8105
|
}
|
|
@@ -7699,7 +8176,8 @@ export function lowerPromiseMethodCall(lowerer, call, access) {
|
|
|
7699
8176
|
// receiver, passes fulfillments through as dyn, and on rejection
|
|
7700
8177
|
// calls the boxed handler with caughtToDyn's identity-preserving
|
|
7701
8178
|
// snapshot (the dyn-then desugar's catch twin).
|
|
7702
|
-
if (member === "catch" && inner.kind === "dyn")
|
|
8179
|
+
if (member === "catch" && (inner.kind === "dyn" || isJsSourceFile(call.getSourceFile()) &&
|
|
8180
|
+
(inner.kind === "void" || lowerer.dynConvertible(inner)))) {
|
|
7703
8181
|
let cb = lowerer.lowerExpr(call.arguments[0]);
|
|
7704
8182
|
if (cb.type.kind === "func" &&
|
|
7705
8183
|
canBoxFuncIntoDyn(cb.type, (id) => lowerer.shapes.get(id), (id) => lowerer.unions.get(id))) {
|
|
@@ -7716,20 +8194,11 @@ export function lowerPromiseMethodCall(lowerer, call, access) {
|
|
|
7716
8194
|
const pLocal = lowerer.declareHiddenLocal("p", promT);
|
|
7717
8195
|
const cbLocal = lowerer.declareHiddenLocal("cb", DYN);
|
|
7718
8196
|
const eLocal = lowerer.declareHiddenLocal("e", CAUGHT);
|
|
7719
|
-
const vLocal = lowerer.declareHiddenLocal("v",
|
|
8197
|
+
const vLocal = inner.kind === "void" ? null : lowerer.declareHiddenLocal("v", inner);
|
|
8198
|
+
const awaited = { kind: "awaitExpr", value: { kind: "varRef", localId: pLocal.id, type: promT, loc }, type: inner, loc };
|
|
7720
8199
|
const tryBody = [
|
|
7721
|
-
{
|
|
7722
|
-
|
|
7723
|
-
localId: vLocal.id,
|
|
7724
|
-
init: {
|
|
7725
|
-
kind: "awaitExpr",
|
|
7726
|
-
value: { kind: "varRef", localId: pLocal.id, type: promT, loc },
|
|
7727
|
-
type: DYN,
|
|
7728
|
-
loc,
|
|
7729
|
-
},
|
|
7730
|
-
loc,
|
|
7731
|
-
},
|
|
7732
|
-
{ kind: "return", value: { kind: "varRef", localId: vLocal.id, type: DYN, loc }, loc },
|
|
8200
|
+
vLocal ? { kind: "varDecl", localId: vLocal.id, init: awaited, loc } : { kind: "exprStmt", expr: awaited, loc },
|
|
8201
|
+
{ kind: "return", value: vLocal ? lowerer.coerceToExpected(varRef(vLocal.id, inner, loc), DYN) : dynUndefinedExpr(loc), loc },
|
|
7733
8202
|
];
|
|
7734
8203
|
const catchBody = [
|
|
7735
8204
|
{
|
|
@@ -7737,7 +8206,7 @@ export function lowerPromiseMethodCall(lowerer, call, access) {
|
|
|
7737
8206
|
value: {
|
|
7738
8207
|
kind: "dynCall",
|
|
7739
8208
|
callee: { kind: "varRef", localId: cbLocal.id, type: DYN, loc },
|
|
7740
|
-
calleeName: jsFuncNameOf(call.arguments[0]) ?? "onRejected",
|
|
8209
|
+
calleeName: jsFuncNameOf(call.arguments[0], lowerer) ?? "onRejected",
|
|
7741
8210
|
args: [
|
|
7742
8211
|
{
|
|
7743
8212
|
kind: "caughtToDyn",
|
|
@@ -8540,14 +9009,23 @@ function lowerObjectStaticCall(lowerer, call, access) {
|
|
|
8540
9009
|
!call.arguments.some(ts.isSpreadElement) && !lowerer.dynamic) {
|
|
8541
9010
|
let object = lowerer.lowerExpr(call.arguments[0]);
|
|
8542
9011
|
if (object.type.kind === "func") {
|
|
8543
|
-
const fnName = jsFuncNameOf(call.arguments[0]);
|
|
9012
|
+
const fnName = jsFuncNameOf(call.arguments[0], lowerer);
|
|
8544
9013
|
object = { kind: "dynFrom", value: object, type: DYN, loc: locOf(call),
|
|
8545
9014
|
...(fnName !== null ? { fnName } : {}) };
|
|
8546
9015
|
}
|
|
9016
|
+
if (object.type.kind !== "dyn" && canConvertToDyn(object.type, (id) => lowerer.shapes.get(id), (id) => lowerer.unions.get(id)))
|
|
9017
|
+
object = lowerer.coerceInto(call.arguments[0], object, DYN);
|
|
8547
9018
|
if (object.type.kind === "dyn") {
|
|
8548
9019
|
const loc = locOf(call);
|
|
8549
|
-
if (member === "getPrototypeOf")
|
|
8550
|
-
|
|
9020
|
+
if (member === "getPrototypeOf") {
|
|
9021
|
+
let parent = call.parent;
|
|
9022
|
+
while (parent && ts.isParenthesizedExpression(parent))
|
|
9023
|
+
parent = parent.parent;
|
|
9024
|
+
const identityOnly = !!parent && ts.isBinaryExpression(parent) &&
|
|
9025
|
+
[ts.SyntaxKind.EqualsEqualsEqualsToken, ts.SyntaxKind.ExclamationEqualsEqualsToken].includes(parent.operatorToken.kind);
|
|
9026
|
+
return { kind: "libCall", fn: "dyn.getPrototype", args: [object], type: DYN, loc,
|
|
9027
|
+
...(identityOnly ? { prototypeIdentityOnly: true } : {}) };
|
|
9028
|
+
}
|
|
8551
9029
|
const prototype = lowerer.lowerExprExpecting(call.arguments[1], DYN);
|
|
8552
9030
|
if (prototype.type.kind === "dyn")
|
|
8553
9031
|
return { kind: "libCall", fn: "dyn.setPrototype", args: [object, prototype], type: DYN, loc };
|
|
@@ -8600,7 +9078,7 @@ function lowerObjectStaticCall(lowerer, call, access) {
|
|
|
8600
9078
|
if (unitTest)
|
|
8601
9079
|
return unitTest;
|
|
8602
9080
|
if (lk === "dyn" || rk === "dyn" || lk === "jsval" || rk === "jsval") {
|
|
8603
|
-
|
|
9081
|
+
return { kind: "libCall", fn: "dyn.sameValue", args: [lowerer.coerceInto(leftNode, left, DYN), lowerer.coerceInto(rightNode, right, DYN)], type: BOOL, loc };
|
|
8604
9082
|
}
|
|
8605
9083
|
if (left.type.kind === "union" || right.type.kind === "union") {
|
|
8606
9084
|
const ut = left.type.kind === "union" ? left.type : right.type;
|
|
@@ -8728,7 +9206,8 @@ function lowerObjectStaticCall(lowerer, call, access) {
|
|
|
8728
9206
|
return prototype;
|
|
8729
9207
|
if (isJsSourceFile(call.getSourceFile()) && call.arguments.length > 0 && !call.arguments.some(ts.isSpreadElement)) {
|
|
8730
9208
|
const target = tryLowerExpression(lowerer, call.arguments[0]);
|
|
8731
|
-
if (target
|
|
9209
|
+
if (target && ((target.type.kind === "func" && lowerer.dynConvertible(target.type)) ||
|
|
9210
|
+
(target.type.kind === "object" && lowerer.dynConvertible(target.type)))) {
|
|
8732
9211
|
const loc = locOf(call);
|
|
8733
9212
|
return { kind: "libCall", fn: "dyn.assignAll", args: [lowerer.coerceToExpected(target, DYN),
|
|
8734
9213
|
{ kind: "dynArrLit", elems: call.arguments.slice(1).map((arg) => lowerer.lowerExprExpecting(arg, DYN)), type: DYN, loc },
|
|
@@ -8904,6 +9383,14 @@ function lowerObjectStaticCall(lowerer, call, access) {
|
|
|
8904
9383
|
if (call.arguments.some((a) => ts.isSpreadElement(a)))
|
|
8905
9384
|
return null;
|
|
8906
9385
|
let target = tryLowerExpression(lowerer, call.arguments[0]);
|
|
9386
|
+
const targetNode = call.arguments[0];
|
|
9387
|
+
// The checker gives C.prototype the instance type, but its lowered
|
|
9388
|
+
// value is the shared prototype table, not an instance to unbox.
|
|
9389
|
+
const prototypeTarget = ts.isPropertyAccessExpression(targetNode) && targetNode.name.text === "prototype" &&
|
|
9390
|
+
(exactClassOfReceiver(lowerer, targetNode.expression) !== null || storedClassValueType(lowerer, targetNode.expression)?.kind === "classval");
|
|
9391
|
+
const declaredTarget = target?.type.kind === "dyn" && !prototypeTarget && !isJsSourceFile(targetNode.getSourceFile()) ? lowerer.mapTypeOf(lowerer.typeOf(targetNode)) : null;
|
|
9392
|
+
if (target && declaredTarget && isDynTypedRefType(declaredTarget))
|
|
9393
|
+
target = lowerer.coerceToExpected(target, declaredTarget);
|
|
8907
9394
|
if (target && member === "defineProperty") {
|
|
8908
9395
|
const native = lowerClassDataDescriptor(lowerer, call, member, target);
|
|
8909
9396
|
if (native)
|
|
@@ -8915,15 +9402,14 @@ function lowerObjectStaticCall(lowerer, call, access) {
|
|
|
8915
9402
|
return descriptor;
|
|
8916
9403
|
target = lowerer.coerceToExpected(target, DYN);
|
|
8917
9404
|
}
|
|
8918
|
-
// Error
|
|
8919
|
-
// view. Other native fields do not yet synchronize descriptor edits.
|
|
9405
|
+
// Error instances share a live property table with their checked view.
|
|
8920
9406
|
const keyNode = call.arguments[1];
|
|
8921
9407
|
if (target?.type.kind === "object" && target.type.className !== "%DOMException" && lowerer.errorHierarchyClassOf(target.type.className) &&
|
|
8922
|
-
ts.isStringLiteral(keyNode) && keyNode.text === "cause") {
|
|
9408
|
+
((ts.isStringLiteral(keyNode) && (keyNode.text === "cause" || keyNode.text === "message")) || lowerer.mapTypeOf(lowerer.typeOf(keyNode))?.kind === "symbol")) {
|
|
8923
9409
|
target = lowerer.coerceToExpected(target, DYN);
|
|
8924
9410
|
}
|
|
8925
9411
|
if (target?.type.kind === "func" && lowerer.dynConvertible(target.type)) {
|
|
8926
|
-
const fnName = jsFuncNameOf(call.arguments[0]);
|
|
9412
|
+
const fnName = jsFuncNameOf(call.arguments[0], lowerer);
|
|
8927
9413
|
target = { kind: "dynFrom", value: target, type: DYN, loc: locOf(call.arguments[0]), ...(fnName !== null ? { fnName } : {}) };
|
|
8928
9414
|
}
|
|
8929
9415
|
const descriptorPrimitive = member === "getOwnPropertyDescriptor" && target &&
|
|
@@ -8952,6 +9438,9 @@ function lowerObjectStaticCall(lowerer, call, access) {
|
|
|
8952
9438
|
// static shapes have no property table to extend.
|
|
8953
9439
|
if (member === "defineProperties" && call.arguments.length === 2 &&
|
|
8954
9440
|
!call.arguments.some((a) => ts.isSpreadElement(a))) {
|
|
9441
|
+
const prototype = lowerClassPrototypeDescriptors(lowerer, call, member);
|
|
9442
|
+
if (prototype)
|
|
9443
|
+
return prototype;
|
|
8955
9444
|
let target = tryLowerExpression(lowerer, call.arguments[0]);
|
|
8956
9445
|
if (target) {
|
|
8957
9446
|
const native = lowerClassDataDescriptor(lowerer, call, member, target);
|
|
@@ -8964,7 +9453,7 @@ function lowerObjectStaticCall(lowerer, call, access) {
|
|
|
8964
9453
|
// wrapper returned later reads the same table.
|
|
8965
9454
|
if (target && target.type.kind === "func" &&
|
|
8966
9455
|
canBoxFuncIntoDyn(target.type, (id) => lowerer.shapes.get(id), (id) => lowerer.unions.get(id))) {
|
|
8967
|
-
const fnName = jsFuncNameOf(call.arguments[0]);
|
|
9456
|
+
const fnName = jsFuncNameOf(call.arguments[0], lowerer);
|
|
8968
9457
|
target = { kind: "dynFrom", value: target, type: DYN, loc: locOf(call.arguments[0]), ...(fnName !== null ? { fnName } : {}) };
|
|
8969
9458
|
}
|
|
8970
9459
|
if (target && isUnitType(target.type)) {
|
|
@@ -9019,7 +9508,8 @@ function lowerObjectStaticCall(lowerer, call, access) {
|
|
|
9019
9508
|
let inner = argNode;
|
|
9020
9509
|
while (ts.isParenthesizedExpression(inner) || ts.isAsExpression(inner))
|
|
9021
9510
|
inner = inner.expression;
|
|
9022
|
-
const value =
|
|
9511
|
+
const value = isJsSourceFile(call.getSourceFile()) && (ts.isObjectLiteralExpression(inner) || ts.isArrayLiteralExpression(inner))
|
|
9512
|
+
? lowerer.lowerExprExpecting(argNode, DYN) : lowerer.lowerExpr(argNode);
|
|
9023
9513
|
if (value.type.kind === "dyn")
|
|
9024
9514
|
return { kind: "libCall", fn: "dyn.freeze", args: [value], type: DYN, loc: locOf(call) };
|
|
9025
9515
|
if (ts.isObjectLiteralExpression(inner) || ts.isArrayLiteralExpression(inner)) {
|
|
@@ -9048,14 +9538,19 @@ function lowerObjectStaticCall(lowerer, call, access) {
|
|
|
9048
9538
|
const recvNode = call.arguments[0];
|
|
9049
9539
|
const keyNode = call.arguments[1];
|
|
9050
9540
|
const probed = tryLowerExpression(lowerer, recvNode);
|
|
9541
|
+
const constructor = probed?.type.kind === "classval" ? lowerer.classes.get(probed.type.className) : undefined;
|
|
9051
9542
|
// A CHECKED-DYNAMIC receiver (the JS file-scope object-literal
|
|
9052
9543
|
// identity story): the runtime dyn probe — OBJ member presence, ARR
|
|
9053
9544
|
// index bounds, Node's ToObject TypeError on nullish.
|
|
9054
|
-
if (probed?.type.kind === "dyn" || (probed && isDynTypedRefType(probed.type)) ||
|
|
9545
|
+
if (probed?.type.kind === "dyn" || (probed && isDynTypedRefType(probed.type)) ||
|
|
9546
|
+
(probed?.type.kind === "object" && lowerer.errorHierarchyClassOf(probed.type.className)) ||
|
|
9547
|
+
(probed && constructor && (constructor.callableBase || hasRuntimeStatics(constructor))) ||
|
|
9548
|
+
(probed?.type.kind === "func" && lowerer.dynConvertible(probed.type))) {
|
|
9055
9549
|
const loc = locOf(call);
|
|
9056
9550
|
const receiver = lowerer.coerceToExpected(probed, DYN);
|
|
9057
9551
|
const rawKey = lowerer.lowerExpr(keyNode);
|
|
9058
|
-
if (rawKey.type.kind === "dyn" || rawKey.type.kind === "symbol"
|
|
9552
|
+
if (rawKey.type.kind === "dyn" || rawKey.type.kind === "symbol" ||
|
|
9553
|
+
rawKey.type.kind === "union" && lowerer.dynConvertible(rawKey.type))
|
|
9059
9554
|
return {
|
|
9060
9555
|
kind: "libCall", fn: "dyn.hasOwnComputed", args: [receiver, lowerer.coerceToExpected(rawKey, DYN)], type: BOOL, loc,
|
|
9061
9556
|
};
|
|
@@ -9140,7 +9635,8 @@ function lowerObjectStaticCall(lowerer, call, access) {
|
|
|
9140
9635
|
const isPrimitive = probed !== null && probed !== undefined &&
|
|
9141
9636
|
(isUnitType(probed.type) || probed.type.kind === "string" ||
|
|
9142
9637
|
probed.type.kind === "f64" || probed.type.kind === "bool");
|
|
9143
|
-
|
|
9638
|
+
const isJsUnion = probed?.type.kind === "union" && isJsSourceFile(call.getSourceFile()) && lowerer.dynConvertible(probed.type);
|
|
9639
|
+
if (isDyn || isPrimitive || isFunction || isJsUnion || (probed && isDynTypedRefType(probed.type))) {
|
|
9144
9640
|
const fn = member === "keys" ? "dyn.objKeys" : member === "values" ? "dyn.objValues" : "dyn.objEntries";
|
|
9145
9641
|
let v = lowerer.lowerExpr(argNode);
|
|
9146
9642
|
if (v.type.kind !== "dyn")
|
|
@@ -9149,14 +9645,11 @@ function lowerObjectStaticCall(lowerer, call, access) {
|
|
|
9149
9645
|
}
|
|
9150
9646
|
}
|
|
9151
9647
|
let argIr = lowerer.mapTypeOf(lowerer.typeOf(argNode));
|
|
9152
|
-
//
|
|
9153
|
-
//
|
|
9154
|
-
|
|
9155
|
-
if (
|
|
9156
|
-
|
|
9157
|
-
if (probed?.type.kind === "record")
|
|
9158
|
-
argIr = probed.type;
|
|
9159
|
-
}
|
|
9648
|
+
// Inferred records can carry runtime-optional index values that the
|
|
9649
|
+
// checker omits (named regex captures). Enumerate the represented shape.
|
|
9650
|
+
const represented = tryLowerExpression(lowerer, argNode);
|
|
9651
|
+
if (represented?.type.kind === "record")
|
|
9652
|
+
argIr = represented.type;
|
|
9160
9653
|
if (argIr?.kind !== "record")
|
|
9161
9654
|
return null; // Maps, classes, arrays → the SC2020 fence
|
|
9162
9655
|
const shape = lowerer.shapes.get(argIr.shapeId);
|
|
@@ -9221,7 +9714,6 @@ function lowerObjectStaticCall(lowerer, call, access) {
|
|
|
9221
9714
|
const recT = argIr;
|
|
9222
9715
|
const ref = { kind: "varRef", localId: "r.0", type: recT, loc };
|
|
9223
9716
|
const outRef = { kind: "varRef", localId: "out.0", type: resultT, loc };
|
|
9224
|
-
lowerer.arrHofHelpers.set(key, helper);
|
|
9225
9717
|
const fn = {
|
|
9226
9718
|
name: helper,
|
|
9227
9719
|
params: [{ localId: "r.0", name: "r", type: recT }],
|
|
@@ -9250,6 +9742,8 @@ function lowerObjectStaticCall(lowerer, call, access) {
|
|
|
9250
9742
|
return null;
|
|
9251
9743
|
if (typeEquals(vt, valueT))
|
|
9252
9744
|
return value;
|
|
9745
|
+
if (valueT.kind === "dyn" && lowerer.dynConvertible(vt))
|
|
9746
|
+
return lowerer.coerceToExpected(value, DYN);
|
|
9253
9747
|
if (valueT.kind === "union" && vt.kind !== "union") {
|
|
9254
9748
|
const tag = lowerer.armTag(valueT.unionId, vt);
|
|
9255
9749
|
if (tag >= 0) {
|
|
@@ -9269,7 +9763,7 @@ function lowerObjectStaticCall(lowerer, call, access) {
|
|
|
9269
9763
|
guardUndefTag = undefTag;
|
|
9270
9764
|
const arms = lowerer.unions.get(f.type.unionId)?.arms ?? [];
|
|
9271
9765
|
const others = arms.filter((a) => a.kind !== "undefinedT");
|
|
9272
|
-
if (typeEquals(f.type, valueT ?? f.type)) {
|
|
9766
|
+
if (valueT?.kind === "dyn" || typeEquals(f.type, valueT ?? f.type)) {
|
|
9273
9767
|
// The field union IS the result union (single-field shapes):
|
|
9274
9768
|
// push the raw box — but then the undefined skip must NOT
|
|
9275
9769
|
// narrow. Handled below via vt === valueT.
|
|
@@ -9293,7 +9787,7 @@ function lowerObjectStaticCall(lowerer, call, access) {
|
|
|
9293
9787
|
"cannot re-tag into the result element type — read the fields directly)");
|
|
9294
9788
|
}
|
|
9295
9789
|
}
|
|
9296
|
-
else if (!typeEquals(f.type, valueT ?? f.type)) {
|
|
9790
|
+
else if (valueT?.kind !== "dyn" && !typeEquals(f.type, valueT ?? f.type)) {
|
|
9297
9791
|
lowerer.unsupported("SC1090", call, `Object.${member} over '${lowerer.fmt(argIr)}' (field '${f.name}' is a union that cannot ` +
|
|
9298
9792
|
"re-tag into the result element type — read the fields directly)");
|
|
9299
9793
|
}
|
|
@@ -9333,6 +9827,7 @@ function lowerObjectStaticCall(lowerer, call, access) {
|
|
|
9333
9827
|
fn.body = body;
|
|
9334
9828
|
};
|
|
9335
9829
|
finalize();
|
|
9830
|
+
lowerer.arrHofHelpers.set(key, helper);
|
|
9336
9831
|
lowerer.shapeOrderHelperFinalizers.push(finalize);
|
|
9337
9832
|
lowerer.liftedFns.push(fn);
|
|
9338
9833
|
}
|
|
@@ -9381,6 +9876,15 @@ export function lowerFunction(lowerer, decl) {
|
|
|
9381
9876
|
params.push({ localId: argsLocal.id, name: "%arguments", type: DYN });
|
|
9382
9877
|
ctx.argumentsLocal = argsLocal;
|
|
9383
9878
|
}
|
|
9879
|
+
if (isJsSourceFile(decl.getSourceFile()) && sig.params.length === 1 &&
|
|
9880
|
+
sig.params[0]?.mode === "dynRest" && bodyReadsArguments(decl)) {
|
|
9881
|
+
const argsLocal = lowerer.declareHiddenLocal("%arguments", DYN);
|
|
9882
|
+
prologue.push({ kind: "varDecl", localId: argsLocal.id, init: {
|
|
9883
|
+
kind: "dynInvoke", recv: varRef(params[0].localId, DYN, locOf(decl)), method: "slice",
|
|
9884
|
+
calleeName: "Array.prototype.slice", args: [], type: DYN, loc: locOf(decl),
|
|
9885
|
+
}, loc: locOf(decl) });
|
|
9886
|
+
ctx.argumentsLocal = argsLocal;
|
|
9887
|
+
}
|
|
9384
9888
|
const bodyBlock = blockBodyOf(decl);
|
|
9385
9889
|
if (!bodyBlock) {
|
|
9386
9890
|
lowerer.unsupported("SC1090", decl, "function declarations whose block body the frontend cannot locate");
|
|
@@ -9537,6 +10041,13 @@ export function lowerRecordFieldCall(lowerer, call, access) {
|
|
|
9537
10041
|
return { kind: "callValue", callee, args, type: callee.type.ret, loc: locOf(call) };
|
|
9538
10042
|
}
|
|
9539
10043
|
const target = lowerer.fieldTarget(access);
|
|
10044
|
+
const loc = locOf(call);
|
|
10045
|
+
const receiverLocal = target && isJsSourceFile(call.getSourceFile())
|
|
10046
|
+
? lowerer.declareHiddenLocal("%callReceiver", target.obj.type) : null;
|
|
10047
|
+
const init = target && receiverLocal
|
|
10048
|
+
? { kind: "varDecl", localId: receiverLocal.id, init: target.obj, loc } : null;
|
|
10049
|
+
if (target && receiverLocal)
|
|
10050
|
+
target.obj = varRef(receiverLocal.id, receiverLocal.type, loc);
|
|
9540
10051
|
let callee = target ? lowerer.fieldGetExpr(target, locOf(access), access) : null;
|
|
9541
10052
|
if (!callee)
|
|
9542
10053
|
return null;
|
|
@@ -9545,10 +10056,24 @@ export function lowerRecordFieldCall(lowerer, call, access) {
|
|
|
9545
10056
|
// `.bold` (the chalk shape).
|
|
9546
10057
|
if (callee.type.kind === "record")
|
|
9547
10058
|
callee = lowerer.hybridCallUnwrap(callee);
|
|
10059
|
+
// Inferred JavaScript option records can retain checked callables in
|
|
10060
|
+
// fields even when the checker only describes those members as any.
|
|
10061
|
+
if (callee.type.kind === "dyn" && isJsSourceFile(call.getSourceFile())) {
|
|
10062
|
+
const receiver = target && receiverLocal ? lowerer.coerceToExpected(target.obj, DYN) : undefined;
|
|
10063
|
+
const spread = call.arguments.some(ts.isSpreadElement) ? lowerSpreadArgsCall(lowerer, call, callee, loc) : null;
|
|
10064
|
+
if (spread && spread.kind !== "dynCall")
|
|
10065
|
+
lowerer.unsupported("SC1090", call, "checked record property call spread arguments");
|
|
10066
|
+
const result = spread ? (receiver ? { ...spread, receiver } : spread) : {
|
|
10067
|
+
kind: "dynCall", callee, ...(receiver ? { receiver } : {}), calleeName: access.getText(),
|
|
10068
|
+
args: call.arguments.map((arg) => lowerer.lowerExprExpecting(arg, DYN)), type: DYN, loc,
|
|
10069
|
+
};
|
|
10070
|
+
return init ? { kind: "seqExpr", stmts: [init], result, type: result.type, loc } : result;
|
|
10071
|
+
}
|
|
9548
10072
|
if (callee.type.kind !== "func")
|
|
9549
10073
|
lowerer.badType(access, lowerer.typeOf(access));
|
|
9550
10074
|
const args = completeFuncValueArgs(lowerer, call, callee.type, locOf(call));
|
|
9551
|
-
|
|
10075
|
+
const result = { kind: "callValue", callee, ...(target && receiverLocal ? { receiver: lowerer.coerceToExpected(target.obj, DYN) } : {}), args, type: callee.type.ret, loc };
|
|
10076
|
+
return init ? { kind: "seqExpr", stmts: [init], result, type: result.type, loc } : result;
|
|
9552
10077
|
}
|
|
9553
10078
|
/** The function-like node behind an object-literal generic-method member:
|
|
9554
10079
|
* the MethodDeclaration itself (`{ m<T>(x: T) {...} }`) or a generic
|
|
@@ -10206,7 +10731,8 @@ export function requireObjLitGenericReceiver(lowerer, blame, recvExpr, literal,
|
|
|
10206
10731
|
* direct `call` of the instance with the receiver unevaluated. Claims
|
|
10207
10732
|
* every call whose member is generic-callable — lowering it or fencing
|
|
10208
10733
|
* with a named message. */
|
|
10209
|
-
/** URL
|
|
10734
|
+
/** The URL factories use the constructor's conversion order and parser.
|
|
10735
|
+
* URL.revokeObjectURL() with NO argument: Node's ERR_MISSING_ARGS
|
|
10210
10736
|
* throws before the registry lookup, so the zero-argument contract is
|
|
10211
10737
|
* exact without any blob machinery. The one-argument form (Node's
|
|
10212
10738
|
* silent no-op for unregistered ids) and createObjectURL keep their
|
|
@@ -10214,12 +10740,15 @@ export function requireObjLitGenericReceiver(lowerer, blame, recvExpr, literal,
|
|
|
10214
10740
|
function lowerUrlStaticCall(lowerer, call, callee) {
|
|
10215
10741
|
if (!ts.isPropertyAccessExpression(callee) || callee.questionDotToken !== undefined)
|
|
10216
10742
|
return null;
|
|
10217
|
-
if (!ts.isIdentifier(callee.expression)
|
|
10218
|
-
return null;
|
|
10219
|
-
if (callee.name.text !== "revokeObjectURL" || call.arguments.length !== 0)
|
|
10743
|
+
if (!ts.isIdentifier(callee.expression))
|
|
10220
10744
|
return null;
|
|
10221
10745
|
const sym = lowerer.resolveValueSymbol(callee.expression);
|
|
10222
|
-
if (!sym || !lowerer.isStdlibSymbol(sym))
|
|
10746
|
+
if (!sym || !lowerer.isStdlibSymbol(sym) || sym.name !== "URL")
|
|
10747
|
+
return null;
|
|
10748
|
+
if (callee.name.text === "canParse" || callee.name.text === "parse") {
|
|
10749
|
+
return lowerUrlFactory(lowerer, call, callee.name.text);
|
|
10750
|
+
}
|
|
10751
|
+
if (callee.name.text !== "revokeObjectURL" || call.arguments.length !== 0)
|
|
10223
10752
|
return null;
|
|
10224
10753
|
return nodeThrowExpr(1, "ERR_MISSING_ARGS", 'The "url" argument must be specified', VOID, locOf(call));
|
|
10225
10754
|
}
|
|
@@ -10404,6 +10933,14 @@ function lowerObjLitGenericMethodCall(lowerer, call, access) {
|
|
|
10404
10933
|
const propSym = lowerer.checker.getPropertyOfType(recvT, name);
|
|
10405
10934
|
if (!propSym)
|
|
10406
10935
|
return null;
|
|
10936
|
+
const propertyDecl = lowerer.checker.valueDeclarationOf(propSym);
|
|
10937
|
+
if (propertyDecl && ts.isShorthandPropertyAssignment(propertyDecl) && ts.isIdentifier(propertyDecl.name) && ts.isObjectLiteralExpression(propertyDecl.parent)) {
|
|
10938
|
+
requireObjLitGenericReceiver(lowerer, call, access.expression, propertyDecl.parent, name);
|
|
10939
|
+
const targetSymbol = lowerer.checker.getShorthandAssignmentValueSymbol(propertyDecl);
|
|
10940
|
+
const target = targetSymbol ? lowerer.genericFnsBySymbol.get((targetSymbol.flags & ts.SymbolFlags.Alias ? lowerer.checker.getAliasedSymbol(targetSymbol) : targetSymbol)) : undefined;
|
|
10941
|
+
if (target)
|
|
10942
|
+
return lowerer.lowerGenericCall(call, target);
|
|
10943
|
+
}
|
|
10407
10944
|
if (!isGenericCallableMemberType(lowerer.checker.getTypeOfSymbol(propSym), lowerer.checker))
|
|
10408
10945
|
return null;
|
|
10409
10946
|
// CLASS members belong to the class path (lowerClassGenericMethodCall
|
|
@@ -10492,9 +11029,11 @@ export function lowerObjectMethodCall(lowerer, call, access) {
|
|
|
10492
11029
|
// type still belongs to the unspecialized body (plane.normal.dot()).
|
|
10493
11030
|
// Use the lowered receiver's representation and retain its evaluation.
|
|
10494
11031
|
const probe = mappedReceiver?.kind !== "object" && (lowerer.implicitParamTypes !== null || ts.isNewExpression(access.expression) ||
|
|
10495
|
-
isJsSourceFile(call.getSourceFile())
|
|
10496
|
-
? tryLowerExpression(lowerer, access.expression)
|
|
10497
|
-
|
|
11032
|
+
isJsSourceFile(call.getSourceFile()))
|
|
11033
|
+
? ts.isNewExpression(access.expression) ? lowerer.lowerExpr(access.expression) : tryLowerExpression(lowerer, access.expression)
|
|
11034
|
+
: null;
|
|
11035
|
+
const specializedReceiver = probe?.type.kind === "object" || probe?.type.kind === "union" &&
|
|
11036
|
+
lowerer.unions.get(probe.type.unionId)?.arms.some((arm) => arm.kind === "object") ? probe : null;
|
|
10498
11037
|
if (specializedReceiver)
|
|
10499
11038
|
mappedReceiver = specializedReceiver.type;
|
|
10500
11039
|
if (mappedReceiver?.kind === "union") {
|
|
@@ -10502,6 +11041,11 @@ export function lowerObjectMethodCall(lowerer, call, access) {
|
|
|
10502
11041
|
lowerUnionObjectDynFieldCall(lowerer, call, access, mappedReceiver);
|
|
10503
11042
|
if (dispatched)
|
|
10504
11043
|
return dispatched;
|
|
11044
|
+
const arms = lowerer.unions.get(mappedReceiver.unionId)?.arms;
|
|
11045
|
+
if (isJsSourceFile(call.getSourceFile()) && arms?.every((arm) => arm.kind === "object" &&
|
|
11046
|
+
!lowerer.classes.get(arm.className)?.def.runtime) && lowerer.dynConvertible(mappedReceiver)) {
|
|
11047
|
+
return lowerDynReceiverMethodCall(lowerer, call, access);
|
|
11048
|
+
}
|
|
10505
11049
|
}
|
|
10506
11050
|
const receiverIr = mappedReceiver?.kind === "object"
|
|
10507
11051
|
? mappedReceiver
|
|
@@ -10614,6 +11158,21 @@ export function lowerObjectMethodCall(lowerer, call, access) {
|
|
|
10614
11158
|
return finish({ kind: "dynCall", callee, receiver, calleeName: access.getText(), args, type: DYN, loc });
|
|
10615
11159
|
}
|
|
10616
11160
|
}
|
|
11161
|
+
if (!fieldType && isJsSourceFile(call.getSourceFile()) && !info.def.runtime && !info.builtinError && !info.builtinEmitter && !info.builtinStream) {
|
|
11162
|
+
const loc = locOf(call);
|
|
11163
|
+
const value = lowerReceiver();
|
|
11164
|
+
const local = lowerer.declareHiddenLocal("%callReceiver", value.type);
|
|
11165
|
+
const reference = { kind: "varRef", localId: local.id, type: value.type, loc };
|
|
11166
|
+
const receiver = lowerer.coerceToExpected(reference, DYN);
|
|
11167
|
+
const callee = { kind: "dynKeyGet", value: receiver,
|
|
11168
|
+
key: { kind: "strLit", value: access.name.text, type: STRING, loc }, type: DYN, loc };
|
|
11169
|
+
const spread = call.arguments.some(ts.isSpreadElement) ? lowerSpreadArgsCall(lowerer, call, callee, loc) : null;
|
|
11170
|
+
if (spread && spread.kind !== "dynCall")
|
|
11171
|
+
lowerer.unsupported("SC1090", call, "native property call spread arguments");
|
|
11172
|
+
const result = spread !== null ? { ...spread, receiver } : { kind: "dynCall", callee, receiver,
|
|
11173
|
+
calleeName: access.getText(), args: call.arguments.map((arg) => lowerer.lowerExprExpecting(arg, DYN)), type: DYN, loc };
|
|
11174
|
+
return { kind: "seqExpr", stmts: [{ kind: "varDecl", localId: local.id, init: value, loc }], result, type: DYN, loc };
|
|
11175
|
+
}
|
|
10617
11176
|
return null;
|
|
10618
11177
|
}
|
|
10619
11178
|
if (!info || !found)
|
|
@@ -10633,7 +11192,7 @@ export function lowerObjectMethodCall(lowerer, call, access) {
|
|
|
10633
11192
|
const fallback = virtual
|
|
10634
11193
|
? { kind: "virtualCall", className: info.def.name, method, args: [lowerer.upcastTo(value, info.def.name), ...args], type: found.sig.ret, loc }
|
|
10635
11194
|
: { kind: "call", callee: `%${found.declarer.def.name}.${method}`, args: [lowerer.upcastTo(value, found.declarer.def.name), ...args], type: found.sig.ret, loc };
|
|
10636
|
-
const result = classCallbackCall(lowerer, value, method, call.arguments.map((arg) => lowerer.lowerExprExpecting(arg, DYN)), fallback, loc);
|
|
11195
|
+
const result = classCallbackCall(lowerer, value, method, call.arguments.map((arg) => lowerer.lowerExprExpecting(arg, DYN)), fallback, loc, access.getText());
|
|
10637
11196
|
return { kind: "seqExpr", stmts: [{ kind: "varDecl", localId: local.id, init: receiver, loc }], result, type: result.type, loc };
|
|
10638
11197
|
}
|
|
10639
11198
|
if (found.declarer.builtinError) {
|
|
@@ -10696,6 +11255,22 @@ function lowerUnionObjectMethodCall(lowerer, call, access, receiverT) {
|
|
|
10696
11255
|
plans.push({ arm, info, found });
|
|
10697
11256
|
}
|
|
10698
11257
|
const shapes = plans[0].found.sig.params;
|
|
11258
|
+
if (plans.some((plan) => isClassCallback(lowerer, plan.info, method))) {
|
|
11259
|
+
const loc = locOf(call);
|
|
11260
|
+
const local = lowerer.declareHiddenLocal("%unionMethodReceiver", DYN);
|
|
11261
|
+
const receiver = varRef(local.id, DYN, loc);
|
|
11262
|
+
const callee = { kind: "dynKeyGet", value: receiver,
|
|
11263
|
+
key: { kind: "strLit", value: method, type: STRING, loc }, type: DYN, loc };
|
|
11264
|
+
const spread = call.arguments.some(ts.isSpreadElement) ? lowerSpreadArgsCall(lowerer, call, callee, loc) : null;
|
|
11265
|
+
if (spread && spread.kind !== "dynCall")
|
|
11266
|
+
lowerer.unsupported("SC1090", call, "union method spread arguments");
|
|
11267
|
+
const value = spread !== null ? { ...spread, receiver } : { kind: "dynCall", callee, receiver,
|
|
11268
|
+
calleeName: access.getText(), args: call.arguments.map((arg) => lowerer.lowerExprExpecting(arg, DYN)), type: DYN, loc };
|
|
11269
|
+
const resultT = lowerer.mapTypeOf(lowerer.typeOf(call));
|
|
11270
|
+
const result = resultT && !isUnitType(resultT) ? lowerer.coerceToExpected(value, resultT) : value;
|
|
11271
|
+
return { kind: "seqExpr", stmts: [{ kind: "varDecl", localId: local.id,
|
|
11272
|
+
init: lowerer.coerceInto(access.expression, lowerer.lowerExpr(access.expression), DYN), loc }], result, type: result.type, loc };
|
|
11273
|
+
}
|
|
10699
11274
|
if (!plans.every((plan) => paramAbisEqual(shapes, plan.found.sig.params)))
|
|
10700
11275
|
return null;
|
|
10701
11276
|
const resultT = lowerer.mapTypeOf(lowerer.typeOf(call));
|