@scriptc/compiler 0.2.1 → 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 +59 -4
- package/dist/backend/llvm/dyn.d.ts +3 -0
- package/dist/backend/llvm/dyn.js +84 -12
- package/dist/backend/llvm/dyn.js.map +1 -1
- package/dist/backend/llvm/emitter.d.ts +4 -1
- package/dist/backend/llvm/emitter.js +20 -5
- 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-containers.js +5 -0
- package/dist/backend/llvm/expr-containers.js.map +1 -1
- package/dist/backend/llvm/expr-dynamic.js +30 -5
- package/dist/backend/llvm/expr-dynamic.js.map +1 -1
- package/dist/backend/llvm/expr-stream-bridges.js +70 -9
- 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-shared.js +35 -1
- package/dist/backend/llvm/lib-shared.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/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/coverage/surface-manifest.js +5 -3
- package/dist/coverage/surface-manifest.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 +1 -1
- package/dist/frontend/lowering/class-callbacks.js +7 -6
- package/dist/frontend/lowering/class-callbacks.js.map +1 -1
- package/dist/frontend/lowering/class-construction.d.ts +2 -0
- package/dist/frontend/lowering/class-construction.js +34 -5
- package/dist/frontend/lowering/class-construction.js.map +1 -1
- package/dist/frontend/lowering/class-descriptors.d.ts +1 -1
- package/dist/frontend/lowering/class-descriptors.js +12 -5
- package/dist/frontend/lowering/class-descriptors.js.map +1 -1
- package/dist/frontend/lowering/class-dynamic-dispatch.d.ts +25 -0
- package/dist/frontend/lowering/class-dynamic-dispatch.js +597 -78
- package/dist/frontend/lowering/class-dynamic-dispatch.js.map +1 -1
- package/dist/frontend/lowering/class-dynamic-dispatch.test.js +64 -2
- 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 +11 -41
- package/dist/frontend/lowering/class-instance-constructor.js.map +1 -1
- package/dist/frontend/lowering/class-method-values.d.ts +16 -0
- package/dist/frontend/lowering/class-method-values.js +60 -29
- package/dist/frontend/lowering/class-method-values.js.map +1 -1
- package/dist/frontend/lowering/class-prototypes.d.ts +5 -1
- package/dist/frontend/lowering/class-prototypes.js +69 -10
- package/dist/frontend/lowering/class-prototypes.js.map +1 -1
- package/dist/frontend/lowering/class-runtime-statics.d.ts +4 -4
- package/dist/frontend/lowering/class-runtime-statics.js +26 -8
- package/dist/frontend/lowering/class-runtime-statics.js.map +1 -1
- package/dist/frontend/lowering/class-static-data.d.ts +1 -0
- package/dist/frontend/lowering/class-static-data.js +4 -2
- package/dist/frontend/lowering/class-static-data.js.map +1 -1
- package/dist/frontend/lowering/containers/bytes.js +17 -4
- package/dist/frontend/lowering/containers/bytes.js.map +1 -1
- package/dist/frontend/lowering/containers/string-and-regexp.js +6 -1
- 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/expressions/object-literals.js +31 -1
- package/dist/frontend/lowering/expressions/object-literals.js.map +1 -1
- package/dist/frontend/lowering/expressions/optional-chains.js +3 -3
- package/dist/frontend/lowering/expressions/optional-chains.js.map +1 -1
- package/dist/frontend/lowering/lower-builtins.d.ts +4 -9
- package/dist/frontend/lowering/lower-builtins.js +291 -51
- package/dist/frontend/lowering/lower-builtins.js.map +1 -1
- package/dist/frontend/lowering/lower-calls.js +283 -73
- package/dist/frontend/lowering/lower-calls.js.map +1 -1
- package/dist/frontend/lowering/lower-classes.d.ts +5 -0
- package/dist/frontend/lowering/lower-classes.js +439 -25
- package/dist/frontend/lowering/lower-classes.js.map +1 -1
- package/dist/frontend/lowering/lower-containers.d.ts +1 -1
- package/dist/frontend/lowering/lower-containers.js +39 -17
- package/dist/frontend/lowering/lower-containers.js.map +1 -1
- package/dist/frontend/lowering/lower-exprs.d.ts +10 -6
- package/dist/frontend/lowering/lower-exprs.js +294 -129
- package/dist/frontend/lowering/lower-exprs.js.map +1 -1
- package/dist/frontend/lowering/lower-generators.js +5 -1
- 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.js +4 -0
- 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 +186 -82
- package/dist/frontend/lowering/lower-modules.js.map +1 -1
- package/dist/frontend/lowering/lower-modules.test.js +69 -1
- package/dist/frontend/lowering/lower-modules.test.js.map +1 -1
- package/dist/frontend/lowering/lower-stmts.js +100 -35
- 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 +2 -0
- 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 +26 -9
- package/dist/frontend/lowering/lowerer.js +218 -27
- package/dist/frontend/lowering/lowerer.js.map +1 -1
- package/dist/frontend/lowering/lowerer.test.js +38 -0
- 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 +1 -0
- package/dist/frontend/lowering/surfaces.js +24 -12
- package/dist/frontend/lowering/surfaces.js.map +1 -1
- package/dist/frontend/lowering/text-decoder-encoding.js +3 -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/program.js +4 -2
- package/dist/frontend/program.js.map +1 -1
- package/dist/frontend/type-mapper.js +83 -14
- package/dist/frontend/type-mapper.js.map +1 -1
- package/dist/frontend/union-discriminants.js +22 -7
- 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/ir.d.ts +27 -13
- package/dist/ir/ir.js +26 -2
- package/dist/ir/ir.js.map +1 -1
- package/dist/ir/serialize.js +21 -1
- package/dist/ir/serialize.js.map +1 -1
- package/dist/ir/serialize.test.js +21 -0
- 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 +56 -5
- package/dist/ir/validate.js.map +1 -1
- package/dist/ir/validate.test.js +17 -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/package.json +20 -20
- package/surface-manifest.json +115 -13
|
@@ -10,7 +10,7 @@ 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";
|
|
@@ -45,6 +45,9 @@ import { fenceSymbolFieldCopy } from "./symbol-fields.js";
|
|
|
45
45
|
import { lowerClassDataDescriptor, lowerClassDescriptorRead } from "./class-descriptors.js";
|
|
46
46
|
import { classStaticDataFor } from "./class-static-data.js";
|
|
47
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";
|
|
48
51
|
export { bodyReadsArguments };
|
|
49
52
|
/** The one func-type projection of completed parameter shapes. Typed rest
|
|
50
53
|
* parameters keep their packed array as the trailing native ABI slot and
|
|
@@ -125,6 +128,23 @@ export const MAX_GENERIC_INSTANCES = 100;
|
|
|
125
128
|
* - `...xs: T[]`: the ABI type is the array; call sites pack the surplus.
|
|
126
129
|
*/
|
|
127
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
|
+
}
|
|
128
148
|
if (param.initializer && isJsSourceFile(param.getSourceFile()) && !param.type &&
|
|
129
149
|
!/@(?:param|type)\b/.test(param.getSourceFile().text.slice(param.parent?.pos ?? param.pos, param.getStart()))) {
|
|
130
150
|
return { type: DYN, mode: "omittable", bodyType: DYN };
|
|
@@ -219,9 +239,39 @@ export function paramShape(lowerer, param) {
|
|
|
219
239
|
}
|
|
220
240
|
if (param.initializer) {
|
|
221
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
|
+
}
|
|
222
249
|
return defaultParameterShape(lowerer, param, raw);
|
|
223
250
|
}
|
|
224
|
-
|
|
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
|
+
}
|
|
225
275
|
if (type.kind === "void") {
|
|
226
276
|
return { type: DYN, mode: param.questionToken ? "omittable" : "required" };
|
|
227
277
|
}
|
|
@@ -368,7 +418,7 @@ leading) {
|
|
|
368
418
|
// before conversion to the dense checked-dynamic argument pack.
|
|
369
419
|
value = { kind: "arrayLit", elems: [value], spreads: [0], type: value.type, loc: value.loc };
|
|
370
420
|
}
|
|
371
|
-
value = lowerer
|
|
421
|
+
value = checkedIterableSpread(lowerer, value, arg.expression.getText(), loc);
|
|
372
422
|
if (spreads === 1 && index === argNodes.length - 1) {
|
|
373
423
|
stmts.push({ kind: "exprStmt", expr: {
|
|
374
424
|
kind: "libCall", fn: "dyn.packPushSpread", args: [ref(), value, { kind: "strLit", value: arg.expression.getText(), type: STRING, loc }], type: VOID, loc,
|
|
@@ -892,6 +942,8 @@ function producesConstructor(lowerer, type) {
|
|
|
892
942
|
return false;
|
|
893
943
|
}
|
|
894
944
|
export function declaredReturnType(lowerer, decl, blame) {
|
|
945
|
+
if (isJsSourceFile(decl.getSourceFile()) && ts.isGetAccessorDeclaration(decl))
|
|
946
|
+
return DYN;
|
|
895
947
|
const sig = lowerer.checker.getSignatureFromDeclaration(decl);
|
|
896
948
|
if (!sig)
|
|
897
949
|
lowerer.unsupported("SC1090", decl, "this function form");
|
|
@@ -906,11 +958,36 @@ export function declaredReturnType(lowerer, decl, blame) {
|
|
|
906
958
|
// (`.action(() => { throw ... })`). `never` VALUES stay unmapped.
|
|
907
959
|
if (retTsType.flags & ts.TypeFlags.Never)
|
|
908
960
|
return VOID;
|
|
909
|
-
|
|
910
|
-
if (isJsSourceFile(decl.getSourceFile()) &&
|
|
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")
|
|
911
985
|
return DYN;
|
|
912
986
|
if (isJsSourceFile(decl.getSourceFile()) && !decl.type && !hasExplicitJsDocReturn(decl) && mappedReturn?.kind === "date")
|
|
913
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;
|
|
914
991
|
// JS inference assigns Number to arithmetic over any, although the
|
|
915
992
|
// runtime operands can both be BigInts. Preserve that native result.
|
|
916
993
|
if (isJsSourceFile(decl.getSourceFile()) && !decl.type && !hasExplicitJsDocReturn(decl) &&
|
|
@@ -971,7 +1048,7 @@ export function declaredReturnType(lowerer, decl, blame) {
|
|
|
971
1048
|
// Native-only members (such as Int32Array layout offsets) cannot cross
|
|
972
1049
|
// that boundary; their factories keep the native record ABI.
|
|
973
1050
|
const asyncReturn = decl.modifiers?.some((modifier) => modifier.kind === ts.SyntaxKind.AsyncKeyword) && mappedReturn?.kind === "promise";
|
|
974
|
-
const recordReturn = asyncReturn ? mappedReturn.inner : mappedReturn;
|
|
1051
|
+
const recordReturn = asyncReturn && mappedReturn?.kind === "promise" ? mappedReturn.inner : mappedReturn;
|
|
975
1052
|
const recordArms = recordReturn?.kind === "union" ? lowerer.unions.get(recordReturn.unionId)?.arms : recordReturn ? [recordReturn] : undefined;
|
|
976
1053
|
const inferredRecordReturn = recordArms?.some((arm) => arm.kind === "record" || arm.kind === "object") &&
|
|
977
1054
|
recordArms.every((arm) => isUnitType(arm) || arm.kind === "record" || arm.kind === "object" && !hasExplicitJsDocReturn(decl));
|
|
@@ -985,7 +1062,7 @@ export function declaredReturnType(lowerer, decl, blame) {
|
|
|
985
1062
|
})) {
|
|
986
1063
|
return asyncReturn ? { kind: "promise", inner: DYN } : DYN;
|
|
987
1064
|
}
|
|
988
|
-
const returnType =
|
|
1065
|
+
const returnType = mappedReturn;
|
|
989
1066
|
if (!returnType) {
|
|
990
1067
|
// JS inference residue (an `any` return, an unmappable union): the
|
|
991
1068
|
// checked-dynamic fallback, exactly the declaration story in
|
|
@@ -2097,6 +2174,12 @@ function implicitDeclaredReturn(lowerer, info) {
|
|
|
2097
2174
|
if (retTs.flags & (ts.TypeFlags.Null | ts.TypeFlags.Undefined))
|
|
2098
2175
|
return DYN;
|
|
2099
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;
|
|
2100
2183
|
if (info.decl.parameters.some((param, index) => info.implicitParams?.[index] &&
|
|
2101
2184
|
lowerer.mapTypeOf(lowerer.typeOf(param.name))?.kind === "array"))
|
|
2102
2185
|
return null;
|
|
@@ -2110,6 +2193,12 @@ function implicitDeclaredReturn(lowerer, info) {
|
|
|
2110
2193
|
return null;
|
|
2111
2194
|
}
|
|
2112
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;
|
|
2113
2202
|
if (mapped?.kind === "symbol" && !hasExplicitJsDocReturn(info.decl))
|
|
2114
2203
|
return null;
|
|
2115
2204
|
if (mapped?.kind === "date" && !hasExplicitJsDocReturn(info.decl))
|
|
@@ -2206,12 +2295,25 @@ function storedImplicitArgumentType(lowerer, arg) {
|
|
|
2206
2295
|
return DYN;
|
|
2207
2296
|
if (ts.isIdentifier(arg))
|
|
2208
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
|
+
}
|
|
2209
2316
|
if (ts.isCallExpression(arg) && ts.isIdentifier(arg.expression)) {
|
|
2210
|
-
if (isJsSourceFile(arg.getSourceFile())) {
|
|
2211
|
-
const represented = tryLowerExpression(lowerer, arg);
|
|
2212
|
-
if (represented?.type.kind === "dyn" || represented?.type.kind === "func")
|
|
2213
|
-
return represented.type;
|
|
2214
|
-
}
|
|
2215
2317
|
const callee = storedImplicitArgumentType(lowerer, arg.expression);
|
|
2216
2318
|
if (callee?.kind === "dyn")
|
|
2217
2319
|
return DYN;
|
|
@@ -3852,6 +3954,7 @@ export function lowerCall(lowerer, expr) {
|
|
|
3852
3954
|
lowerer.fenceStaticReadableStreamMember(access, "call");
|
|
3853
3955
|
const source = tryLowerExpression(lowerer, access.expression);
|
|
3854
3956
|
if (source && (source.type.kind === "dyn" || source.type.kind === "func" ||
|
|
3957
|
+
source.type.kind === "union" && isJsSourceFile(expr.getSourceFile()) && lowerer.dynConvertible(source.type) ||
|
|
3855
3958
|
(source.type.kind === "map" || source.type.kind === "set") && lowerer.dynConvertible(source.type) || isDynTypedRefType(source.type) &&
|
|
3856
3959
|
lowerer.foldedStringKeyOf(access.argumentExpression) === null &&
|
|
3857
3960
|
lowerer.mapTypeOf(lowerer.typeOf(access.argumentExpression))?.kind !== "symbol")) {
|
|
@@ -4238,6 +4341,9 @@ export function lowerCall(lowerer, expr) {
|
|
|
4238
4341
|
if (name === "parseFloat" && probed?.type.kind === "string") {
|
|
4239
4342
|
return { kind: "libCall", fn: "num.parseFloat", args: [probed], type: F64, loc };
|
|
4240
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
|
+
}
|
|
4241
4347
|
if (name === "isFinite" && probed?.type.kind === "f64") {
|
|
4242
4348
|
return { kind: "libCall", fn: "number.isFinite", args: [probed], type: BOOL, loc };
|
|
4243
4349
|
}
|
|
@@ -4565,6 +4671,7 @@ export function lowerCall(lowerer, expr) {
|
|
|
4565
4671
|
// Before the island path: regex-argument replace/replaceAll/split
|
|
4566
4672
|
// lower STATICALLY; only the string-pattern overloads are island.
|
|
4567
4673
|
lowerRegexMethodCallWithOptionalArg(lowerer, expr, expr.expression) ??
|
|
4674
|
+
lowerUrlStaticCall(lowerer, expr, expr.expression) ??
|
|
4568
4675
|
lowerer.lowerUrlMethodCall(expr, expr.expression) ??
|
|
4569
4676
|
lowerer.lowerSearchParamsMethodCall(expr, expr.expression) ??
|
|
4570
4677
|
lowerer.lowerStatsMethodCall(expr, expr.expression) ??
|
|
@@ -4615,9 +4722,6 @@ export function lowerCall(lowerer, expr) {
|
|
|
4615
4722
|
lowerer.lowerBytesMethodCall(expr, expr.expression) ??
|
|
4616
4723
|
lowerBytesStaticCall(lowerer, expr, expr.expression) ??
|
|
4617
4724
|
lowerBufferStaticCallWithNarrowedArg(lowerer, expr, expr.expression) ??
|
|
4618
|
-
// URL.revokeObjectURL's zero-argument contract (the one-argument
|
|
4619
|
-
// form keeps the fence — createObjectURL does too).
|
|
4620
|
-
lowerUrlStaticCall(lowerer, expr, expr.expression) ??
|
|
4621
4725
|
// Readable.from — the stream classes' one static (before the
|
|
4622
4726
|
// stdlib chokepoint claims the member).
|
|
4623
4727
|
lowerStreamStaticCall(lowerer, expr, expr.expression) ??
|
|
@@ -5760,7 +5864,7 @@ function lowerSpreadArgsCall(lowerer, expr, callee, loc) {
|
|
|
5760
5864
|
// The spelling rides along for V8's nullish spread-call
|
|
5761
5865
|
// TypeError ("v is not iterable (cannot read property ...)").
|
|
5762
5866
|
spreads.push({ arg: args.length, what: p.spreadOf.getText() });
|
|
5763
|
-
args.push(lowerer
|
|
5867
|
+
args.push(checkedIterableSpread(lowerer, p.v, p.spreadOf.getText(), loc));
|
|
5764
5868
|
}
|
|
5765
5869
|
else {
|
|
5766
5870
|
args.push(lowerer.coerceInto(p.node, p.v, DYN));
|
|
@@ -5770,7 +5874,7 @@ function lowerSpreadArgsCall(lowerer, expr, callee, loc) {
|
|
|
5770
5874
|
return { kind: "dynCall", callee: boxed, calleeName, args, spreads, type: DYN, loc };
|
|
5771
5875
|
}
|
|
5772
5876
|
if (spreadParts.length > 0 &&
|
|
5773
|
-
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") &&
|
|
5774
5878
|
(callee.type.kind === "jsval" || callee.type.kind === "func")) {
|
|
5775
5879
|
if (spreadParts.length !== 1 || parts[parts.length - 1].spreadOf === null) {
|
|
5776
5880
|
lowerer.unsupported("SC1090", expr, "spread arguments before positional arguments in island calls (one trailing spread after the fixed arguments is the supported form)");
|
|
@@ -5783,7 +5887,7 @@ function lowerSpreadArgsCall(lowerer, expr, callee, loc) {
|
|
|
5783
5887
|
const last = parts[parts.length - 1];
|
|
5784
5888
|
// The spelling rides in `name` for V8's nullish spread-call
|
|
5785
5889
|
// TypeError ("v is not iterable (cannot read property ...)").
|
|
5786
|
-
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 };
|
|
5787
5891
|
}
|
|
5788
5892
|
// No lane fits (a spread source outside both tiers, a callee neither
|
|
5789
5893
|
// boxable nor marshalable, mixed dyn/jsval spreads): fence HERE — the
|
|
@@ -5835,12 +5939,21 @@ function canCompleteRuntimeSpread(lowerer, shapes) {
|
|
|
5835
5939
|
function lowerDynReceiverMethodCall(lowerer, call, access) {
|
|
5836
5940
|
if (lowerer.chainBlocked(call, access))
|
|
5837
5941
|
return null;
|
|
5942
|
+
if (stdlibGlobalNameOf(lowerer, access.expression) !== null)
|
|
5943
|
+
return null;
|
|
5838
5944
|
// Only checker-untyped receivers: `any`/`unknown`, or the `any[]` an
|
|
5839
5945
|
// Array.isArray guard narrows them to (the value is STILL the checked-dynamic tree
|
|
5840
5946
|
// array — scalar narrowings bridge through maybeNarrow's dynCheck and
|
|
5841
5947
|
// take the ordinary typed paths, but there is no static home for an
|
|
5842
5948
|
// any-elemented array). Typed receivers keep their own lowerings.
|
|
5843
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
|
+
}
|
|
5844
5957
|
const arrayReceiver = lowerer.checker.isArrayType(recvTs);
|
|
5845
5958
|
const anyArray = arrayReceiver &&
|
|
5846
5959
|
((lowerer.checker.getTypeArguments(recvTs)[0]?.flags ?? 0) &
|
|
@@ -5860,7 +5973,7 @@ function lowerDynReceiverMethodCall(lowerer, call, access) {
|
|
|
5860
5973
|
!["call", "apply", "bind", "toString", "valueOf", "constructor"].includes(access.name.text) &&
|
|
5861
5974
|
canBoxFuncIntoDyn(probed.type, (id) => lowerer.shapes.get(id), (id) => lowerer.unions.get(id))) {
|
|
5862
5975
|
const loc = locOf(call);
|
|
5863
|
-
const fnName = jsFuncNameOf(access.expression);
|
|
5976
|
+
const fnName = jsFuncNameOf(access.expression, lowerer);
|
|
5864
5977
|
const boxed = { kind: "dynFrom", value: probed, type: DYN, loc, ...(fnName !== null ? { fnName } : {}) };
|
|
5865
5978
|
const local = lowerer.declareHiddenLocal("%callableReceiver", DYN);
|
|
5866
5979
|
const receiver = { kind: "varRef", localId: local.id, type: DYN, loc };
|
|
@@ -5879,18 +5992,24 @@ function lowerDynReceiverMethodCall(lowerer, call, access) {
|
|
|
5879
5992
|
}
|
|
5880
5993
|
if (probed?.type.kind === "classval") {
|
|
5881
5994
|
const info = lowerer.classes.get(probed.type.className);
|
|
5882
|
-
if (info
|
|
5995
|
+
if (info)
|
|
5883
5996
|
return lowerStaticMethodCall(lowerer, call, access);
|
|
5884
5997
|
}
|
|
5885
|
-
if (probed?.type.kind
|
|
5886
|
-
|
|
5887
|
-
|
|
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
|
+
}
|
|
5888
6007
|
}
|
|
5889
6008
|
// A factory may return a constructor more precise than its inferred
|
|
5890
6009
|
// checker result. Runtime static members live on that constructor.
|
|
5891
6010
|
if (recv.type.kind === "classval") {
|
|
5892
6011
|
const info = lowerer.classes.get(recv.type.className);
|
|
5893
|
-
if (info
|
|
6012
|
+
if (info)
|
|
5894
6013
|
return lowerStaticMethodCall(lowerer, call, access);
|
|
5895
6014
|
}
|
|
5896
6015
|
// A checker-`any` receiver that already lowered to a real STRING (the
|
|
@@ -5906,6 +6025,25 @@ function lowerDynReceiverMethodCall(lowerer, call, access) {
|
|
|
5906
6025
|
}
|
|
5907
6026
|
if (recv.type.kind !== "dyn")
|
|
5908
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
|
+
}
|
|
5909
6047
|
if (lowerer.mapTypeOf(recvTs)?.kind === "classval") {
|
|
5910
6048
|
return lowerStaticMethodCall(lowerer, call, access);
|
|
5911
6049
|
}
|
|
@@ -5965,6 +6103,9 @@ function lowerDynReceiverMethodCall(lowerer, call, access) {
|
|
|
5965
6103
|
// with the original receiver rather than a materialized property view.
|
|
5966
6104
|
const callbackProperty = (() => {
|
|
5967
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;
|
|
5968
6109
|
return prop !== undefined && lowerer.checker.declarationsOf(prop).some((decl) => ts.isPropertyDeclaration(decl) || ts.isPropertySignature(decl));
|
|
5969
6110
|
})();
|
|
5970
6111
|
const dispatched = callbackProperty ? null : lowerDynDispatchMethodCall(lowerer, call, access, recv, arrayReceiver);
|
|
@@ -6002,18 +6143,24 @@ function lowerDynReceiverMethodCall(lowerer, call, access) {
|
|
|
6002
6143
|
type: DYN,
|
|
6003
6144
|
loc: locOf(access),
|
|
6004
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
|
+
];
|
|
6005
6152
|
if (call.arguments.some(ts.isSpreadElement)) {
|
|
6006
|
-
const spread = lowerSpreadArgsCall(lowerer, call,
|
|
6153
|
+
const spread = lowerSpreadArgsCall(lowerer, call, callee, loc);
|
|
6007
6154
|
if (spread?.kind === "dynCall")
|
|
6008
6155
|
return { kind: "seqExpr",
|
|
6009
|
-
stmts
|
|
6156
|
+
stmts,
|
|
6010
6157
|
result: { ...spread, receiver }, type: DYN, loc };
|
|
6011
6158
|
lowerer.unsupported("SC1090", call, "spread arguments in calls through 'unknown' values");
|
|
6012
6159
|
}
|
|
6013
6160
|
const args = call.arguments.map((a) => lowerer.lowerExprExpecting(a, DYN));
|
|
6014
6161
|
return {
|
|
6015
|
-
kind: "seqExpr", stmts
|
|
6016
|
-
result: { kind: "dynCall", callee
|
|
6162
|
+
kind: "seqExpr", stmts,
|
|
6163
|
+
result: { kind: "dynCall", callee, receiver, calleeName: access.getText(), args, type: DYN, loc }, type: DYN, loc,
|
|
6017
6164
|
};
|
|
6018
6165
|
}
|
|
6019
6166
|
/** Prototype method names of the checked-dynamic tree-representable kinds (String, Array,
|
|
@@ -6041,6 +6188,7 @@ const DYN_PROTO_METHOD_NAMES = new Set([
|
|
|
6041
6188
|
* is-not-a-function where the kind's prototype lacks the name, and
|
|
6042
6189
|
* fences LOUDLY on real-but-unimplemented pairs. */
|
|
6043
6190
|
const DYN_DISPATCH_METHODS = new Set([
|
|
6191
|
+
"toFixed", "toExponential",
|
|
6044
6192
|
"segment", "containing", "resolvedOptions", "test", "exec",
|
|
6045
6193
|
"apply", "bind", "call",
|
|
6046
6194
|
"push", "pop", "shift", "unshift", "slice", "at",
|
|
@@ -6539,6 +6687,15 @@ function lowerPrimitiveProtoCall(lowerer, call, recv, name, memberSym) {
|
|
|
6539
6687
|
if (!lowerer.isStdlibSymbol(memberSym))
|
|
6540
6688
|
return null;
|
|
6541
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
|
+
}
|
|
6542
6699
|
if (recvKind !== "f64" && recvKind !== "bool" && recvKind !== "string")
|
|
6543
6700
|
return null;
|
|
6544
6701
|
const loc = locOf(call);
|
|
@@ -7019,6 +7176,17 @@ export function lowerNestedFunctionDecl(lowerer, stmt) {
|
|
|
7019
7176
|
throw new InternalCompilerError("lowerer bug: nested function declaration has no active statement list");
|
|
7020
7177
|
}
|
|
7021
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
|
+
}
|
|
7022
7190
|
return { kind: "assign", localId: local.id, value: init, loc: locOf(stmt) };
|
|
7023
7191
|
}
|
|
7024
7192
|
/** Signature checks + param shapes + IR func type for any lambda-like
|
|
@@ -7183,6 +7351,13 @@ export function lowerLambda(lowerer, node) {
|
|
|
7183
7351
|
const signature = lowerer.lambdaSignature(node);
|
|
7184
7352
|
const { shapes } = signature;
|
|
7185
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
|
+
}
|
|
7186
7361
|
// A lambda IS a value: the completed-ABI rule applies at birth. The
|
|
7187
7362
|
// contextual (target) type decides — `(x?: number) => void` may flow
|
|
7188
7363
|
// into a slot annotated `(x: number | undefined) => void` (same ABI
|
|
@@ -7792,7 +7967,7 @@ export function lowerPromiseMethodCall(lowerer, call, access) {
|
|
|
7792
7967
|
value: {
|
|
7793
7968
|
kind: "dynCall",
|
|
7794
7969
|
callee: { kind: "varRef", localId: cbLocal.id, type: DYN, loc },
|
|
7795
|
-
calleeName: jsFuncNameOf(call.arguments[0]) ?? "onFulfilled",
|
|
7970
|
+
calleeName: jsFuncNameOf(call.arguments[0], lowerer) ?? "onFulfilled",
|
|
7796
7971
|
args: handlerArgs,
|
|
7797
7972
|
type: DYN,
|
|
7798
7973
|
loc,
|
|
@@ -7825,7 +8000,8 @@ export function lowerPromiseMethodCall(lowerer, call, access) {
|
|
|
7825
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)");
|
|
7826
8001
|
}
|
|
7827
8002
|
const param = cb.type.params[0];
|
|
7828
|
-
if (param !== undefined && !typeEquals(param, inner) &&
|
|
8003
|
+
if (param !== undefined && !typeEquals(param, inner) &&
|
|
8004
|
+
!(param.kind === "dyn" && (inner.kind === "void" || lowerer.dynConvertible(inner)))) {
|
|
7829
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)}')`);
|
|
7830
8006
|
}
|
|
7831
8007
|
const resultT = lowerer.mapTypeOf(lowerer.typeOf(call));
|
|
@@ -7855,7 +8031,7 @@ export function lowerPromiseMethodCall(lowerer, call, access) {
|
|
|
7855
8031
|
if (param !== undefined && inner.kind !== "void") {
|
|
7856
8032
|
const vLocal = lowerer.declareHiddenLocal("v", inner);
|
|
7857
8033
|
body.push({ kind: "varDecl", localId: vLocal.id, init: awaitE, loc });
|
|
7858
|
-
handlerArgs = [{ kind: "varRef", localId: vLocal.id, type: inner, loc }];
|
|
8034
|
+
handlerArgs = [lowerer.coerceToExpected({ kind: "varRef", localId: vLocal.id, type: inner, loc }, param)];
|
|
7859
8035
|
}
|
|
7860
8036
|
else {
|
|
7861
8037
|
body.push({ kind: "exprStmt", expr: awaitE, loc });
|
|
@@ -7916,6 +8092,14 @@ export function lowerPromiseMethodCall(lowerer, call, access) {
|
|
|
7916
8092
|
}
|
|
7917
8093
|
if (member === "finally") {
|
|
7918
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
|
+
}
|
|
7919
8103
|
if (cb.type.kind !== "func" || cb.type.params.length !== 0 || cb.type.ret.kind !== "void") {
|
|
7920
8104
|
lowerer.unsupported("SC1090", call.arguments[0], "finally callbacks with parameters or a return value (use () => { ... })");
|
|
7921
8105
|
}
|
|
@@ -7992,7 +8176,8 @@ export function lowerPromiseMethodCall(lowerer, call, access) {
|
|
|
7992
8176
|
// receiver, passes fulfillments through as dyn, and on rejection
|
|
7993
8177
|
// calls the boxed handler with caughtToDyn's identity-preserving
|
|
7994
8178
|
// snapshot (the dyn-then desugar's catch twin).
|
|
7995
|
-
if (member === "catch" && inner.kind === "dyn")
|
|
8179
|
+
if (member === "catch" && (inner.kind === "dyn" || isJsSourceFile(call.getSourceFile()) &&
|
|
8180
|
+
(inner.kind === "void" || lowerer.dynConvertible(inner)))) {
|
|
7996
8181
|
let cb = lowerer.lowerExpr(call.arguments[0]);
|
|
7997
8182
|
if (cb.type.kind === "func" &&
|
|
7998
8183
|
canBoxFuncIntoDyn(cb.type, (id) => lowerer.shapes.get(id), (id) => lowerer.unions.get(id))) {
|
|
@@ -8009,20 +8194,11 @@ export function lowerPromiseMethodCall(lowerer, call, access) {
|
|
|
8009
8194
|
const pLocal = lowerer.declareHiddenLocal("p", promT);
|
|
8010
8195
|
const cbLocal = lowerer.declareHiddenLocal("cb", DYN);
|
|
8011
8196
|
const eLocal = lowerer.declareHiddenLocal("e", CAUGHT);
|
|
8012
|
-
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 };
|
|
8013
8199
|
const tryBody = [
|
|
8014
|
-
{
|
|
8015
|
-
|
|
8016
|
-
localId: vLocal.id,
|
|
8017
|
-
init: {
|
|
8018
|
-
kind: "awaitExpr",
|
|
8019
|
-
value: { kind: "varRef", localId: pLocal.id, type: promT, loc },
|
|
8020
|
-
type: DYN,
|
|
8021
|
-
loc,
|
|
8022
|
-
},
|
|
8023
|
-
loc,
|
|
8024
|
-
},
|
|
8025
|
-
{ 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 },
|
|
8026
8202
|
];
|
|
8027
8203
|
const catchBody = [
|
|
8028
8204
|
{
|
|
@@ -8030,7 +8206,7 @@ export function lowerPromiseMethodCall(lowerer, call, access) {
|
|
|
8030
8206
|
value: {
|
|
8031
8207
|
kind: "dynCall",
|
|
8032
8208
|
callee: { kind: "varRef", localId: cbLocal.id, type: DYN, loc },
|
|
8033
|
-
calleeName: jsFuncNameOf(call.arguments[0]) ?? "onRejected",
|
|
8209
|
+
calleeName: jsFuncNameOf(call.arguments[0], lowerer) ?? "onRejected",
|
|
8034
8210
|
args: [
|
|
8035
8211
|
{
|
|
8036
8212
|
kind: "caughtToDyn",
|
|
@@ -8833,7 +9009,7 @@ function lowerObjectStaticCall(lowerer, call, access) {
|
|
|
8833
9009
|
!call.arguments.some(ts.isSpreadElement) && !lowerer.dynamic) {
|
|
8834
9010
|
let object = lowerer.lowerExpr(call.arguments[0]);
|
|
8835
9011
|
if (object.type.kind === "func") {
|
|
8836
|
-
const fnName = jsFuncNameOf(call.arguments[0]);
|
|
9012
|
+
const fnName = jsFuncNameOf(call.arguments[0], lowerer);
|
|
8837
9013
|
object = { kind: "dynFrom", value: object, type: DYN, loc: locOf(call),
|
|
8838
9014
|
...(fnName !== null ? { fnName } : {}) };
|
|
8839
9015
|
}
|
|
@@ -8841,8 +9017,15 @@ function lowerObjectStaticCall(lowerer, call, access) {
|
|
|
8841
9017
|
object = lowerer.coerceInto(call.arguments[0], object, DYN);
|
|
8842
9018
|
if (object.type.kind === "dyn") {
|
|
8843
9019
|
const loc = locOf(call);
|
|
8844
|
-
if (member === "getPrototypeOf")
|
|
8845
|
-
|
|
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
|
+
}
|
|
8846
9029
|
const prototype = lowerer.lowerExprExpecting(call.arguments[1], DYN);
|
|
8847
9030
|
if (prototype.type.kind === "dyn")
|
|
8848
9031
|
return { kind: "libCall", fn: "dyn.setPrototype", args: [object, prototype], type: DYN, loc };
|
|
@@ -9024,7 +9207,7 @@ function lowerObjectStaticCall(lowerer, call, access) {
|
|
|
9024
9207
|
if (isJsSourceFile(call.getSourceFile()) && call.arguments.length > 0 && !call.arguments.some(ts.isSpreadElement)) {
|
|
9025
9208
|
const target = tryLowerExpression(lowerer, call.arguments[0]);
|
|
9026
9209
|
if (target && ((target.type.kind === "func" && lowerer.dynConvertible(target.type)) ||
|
|
9027
|
-
(target.type.kind === "object" && lowerer.
|
|
9210
|
+
(target.type.kind === "object" && lowerer.dynConvertible(target.type)))) {
|
|
9028
9211
|
const loc = locOf(call);
|
|
9029
9212
|
return { kind: "libCall", fn: "dyn.assignAll", args: [lowerer.coerceToExpected(target, DYN),
|
|
9030
9213
|
{ kind: "dynArrLit", elems: call.arguments.slice(1).map((arg) => lowerer.lowerExprExpecting(arg, DYN)), type: DYN, loc },
|
|
@@ -9226,7 +9409,7 @@ function lowerObjectStaticCall(lowerer, call, access) {
|
|
|
9226
9409
|
target = lowerer.coerceToExpected(target, DYN);
|
|
9227
9410
|
}
|
|
9228
9411
|
if (target?.type.kind === "func" && lowerer.dynConvertible(target.type)) {
|
|
9229
|
-
const fnName = jsFuncNameOf(call.arguments[0]);
|
|
9412
|
+
const fnName = jsFuncNameOf(call.arguments[0], lowerer);
|
|
9230
9413
|
target = { kind: "dynFrom", value: target, type: DYN, loc: locOf(call.arguments[0]), ...(fnName !== null ? { fnName } : {}) };
|
|
9231
9414
|
}
|
|
9232
9415
|
const descriptorPrimitive = member === "getOwnPropertyDescriptor" && target &&
|
|
@@ -9255,6 +9438,9 @@ function lowerObjectStaticCall(lowerer, call, access) {
|
|
|
9255
9438
|
// static shapes have no property table to extend.
|
|
9256
9439
|
if (member === "defineProperties" && call.arguments.length === 2 &&
|
|
9257
9440
|
!call.arguments.some((a) => ts.isSpreadElement(a))) {
|
|
9441
|
+
const prototype = lowerClassPrototypeDescriptors(lowerer, call, member);
|
|
9442
|
+
if (prototype)
|
|
9443
|
+
return prototype;
|
|
9258
9444
|
let target = tryLowerExpression(lowerer, call.arguments[0]);
|
|
9259
9445
|
if (target) {
|
|
9260
9446
|
const native = lowerClassDataDescriptor(lowerer, call, member, target);
|
|
@@ -9267,7 +9453,7 @@ function lowerObjectStaticCall(lowerer, call, access) {
|
|
|
9267
9453
|
// wrapper returned later reads the same table.
|
|
9268
9454
|
if (target && target.type.kind === "func" &&
|
|
9269
9455
|
canBoxFuncIntoDyn(target.type, (id) => lowerer.shapes.get(id), (id) => lowerer.unions.get(id))) {
|
|
9270
|
-
const fnName = jsFuncNameOf(call.arguments[0]);
|
|
9456
|
+
const fnName = jsFuncNameOf(call.arguments[0], lowerer);
|
|
9271
9457
|
target = { kind: "dynFrom", value: target, type: DYN, loc: locOf(call.arguments[0]), ...(fnName !== null ? { fnName } : {}) };
|
|
9272
9458
|
}
|
|
9273
9459
|
if (target && isUnitType(target.type)) {
|
|
@@ -9322,7 +9508,8 @@ function lowerObjectStaticCall(lowerer, call, access) {
|
|
|
9322
9508
|
let inner = argNode;
|
|
9323
9509
|
while (ts.isParenthesizedExpression(inner) || ts.isAsExpression(inner))
|
|
9324
9510
|
inner = inner.expression;
|
|
9325
|
-
const value =
|
|
9511
|
+
const value = isJsSourceFile(call.getSourceFile()) && (ts.isObjectLiteralExpression(inner) || ts.isArrayLiteralExpression(inner))
|
|
9512
|
+
? lowerer.lowerExprExpecting(argNode, DYN) : lowerer.lowerExpr(argNode);
|
|
9326
9513
|
if (value.type.kind === "dyn")
|
|
9327
9514
|
return { kind: "libCall", fn: "dyn.freeze", args: [value], type: DYN, loc: locOf(call) };
|
|
9328
9515
|
if (ts.isObjectLiteralExpression(inner) || ts.isArrayLiteralExpression(inner)) {
|
|
@@ -9458,14 +9645,11 @@ function lowerObjectStaticCall(lowerer, call, access) {
|
|
|
9458
9645
|
}
|
|
9459
9646
|
}
|
|
9460
9647
|
let argIr = lowerer.mapTypeOf(lowerer.typeOf(argNode));
|
|
9461
|
-
//
|
|
9462
|
-
//
|
|
9463
|
-
|
|
9464
|
-
if (
|
|
9465
|
-
|
|
9466
|
-
if (probed?.type.kind === "record")
|
|
9467
|
-
argIr = probed.type;
|
|
9468
|
-
}
|
|
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;
|
|
9469
9653
|
if (argIr?.kind !== "record")
|
|
9470
9654
|
return null; // Maps, classes, arrays → the SC2020 fence
|
|
9471
9655
|
const shape = lowerer.shapes.get(argIr.shapeId);
|
|
@@ -9857,6 +10041,13 @@ export function lowerRecordFieldCall(lowerer, call, access) {
|
|
|
9857
10041
|
return { kind: "callValue", callee, args, type: callee.type.ret, loc: locOf(call) };
|
|
9858
10042
|
}
|
|
9859
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);
|
|
9860
10051
|
let callee = target ? lowerer.fieldGetExpr(target, locOf(access), access) : null;
|
|
9861
10052
|
if (!callee)
|
|
9862
10053
|
return null;
|
|
@@ -9865,10 +10056,24 @@ export function lowerRecordFieldCall(lowerer, call, access) {
|
|
|
9865
10056
|
// `.bold` (the chalk shape).
|
|
9866
10057
|
if (callee.type.kind === "record")
|
|
9867
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
|
+
}
|
|
9868
10072
|
if (callee.type.kind !== "func")
|
|
9869
10073
|
lowerer.badType(access, lowerer.typeOf(access));
|
|
9870
10074
|
const args = completeFuncValueArgs(lowerer, call, callee.type, locOf(call));
|
|
9871
|
-
|
|
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;
|
|
9872
10077
|
}
|
|
9873
10078
|
/** The function-like node behind an object-literal generic-method member:
|
|
9874
10079
|
* the MethodDeclaration itself (`{ m<T>(x: T) {...} }`) or a generic
|
|
@@ -10526,7 +10731,8 @@ export function requireObjLitGenericReceiver(lowerer, blame, recvExpr, literal,
|
|
|
10526
10731
|
* direct `call` of the instance with the receiver unevaluated. Claims
|
|
10527
10732
|
* every call whose member is generic-callable — lowering it or fencing
|
|
10528
10733
|
* with a named message. */
|
|
10529
|
-
/** URL
|
|
10734
|
+
/** The URL factories use the constructor's conversion order and parser.
|
|
10735
|
+
* URL.revokeObjectURL() with NO argument: Node's ERR_MISSING_ARGS
|
|
10530
10736
|
* throws before the registry lookup, so the zero-argument contract is
|
|
10531
10737
|
* exact without any blob machinery. The one-argument form (Node's
|
|
10532
10738
|
* silent no-op for unregistered ids) and createObjectURL keep their
|
|
@@ -10534,12 +10740,15 @@ export function requireObjLitGenericReceiver(lowerer, blame, recvExpr, literal,
|
|
|
10534
10740
|
function lowerUrlStaticCall(lowerer, call, callee) {
|
|
10535
10741
|
if (!ts.isPropertyAccessExpression(callee) || callee.questionDotToken !== undefined)
|
|
10536
10742
|
return null;
|
|
10537
|
-
if (!ts.isIdentifier(callee.expression)
|
|
10538
|
-
return null;
|
|
10539
|
-
if (callee.name.text !== "revokeObjectURL" || call.arguments.length !== 0)
|
|
10743
|
+
if (!ts.isIdentifier(callee.expression))
|
|
10540
10744
|
return null;
|
|
10541
10745
|
const sym = lowerer.resolveValueSymbol(callee.expression);
|
|
10542
|
-
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)
|
|
10543
10752
|
return null;
|
|
10544
10753
|
return nodeThrowExpr(1, "ERR_MISSING_ARGS", 'The "url" argument must be specified', VOID, locOf(call));
|
|
10545
10754
|
}
|
|
@@ -10820,9 +11029,11 @@ export function lowerObjectMethodCall(lowerer, call, access) {
|
|
|
10820
11029
|
// type still belongs to the unspecialized body (plane.normal.dot()).
|
|
10821
11030
|
// Use the lowered receiver's representation and retain its evaluation.
|
|
10822
11031
|
const probe = mappedReceiver?.kind !== "object" && (lowerer.implicitParamTypes !== null || ts.isNewExpression(access.expression) ||
|
|
10823
|
-
isJsSourceFile(call.getSourceFile())
|
|
10824
|
-
? tryLowerExpression(lowerer, access.expression)
|
|
10825
|
-
|
|
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;
|
|
10826
11037
|
if (specializedReceiver)
|
|
10827
11038
|
mappedReceiver = specializedReceiver.type;
|
|
10828
11039
|
if (mappedReceiver?.kind === "union") {
|
|
@@ -10833,8 +11044,7 @@ export function lowerObjectMethodCall(lowerer, call, access) {
|
|
|
10833
11044
|
const arms = lowerer.unions.get(mappedReceiver.unionId)?.arms;
|
|
10834
11045
|
if (isJsSourceFile(call.getSourceFile()) && arms?.every((arm) => arm.kind === "object" &&
|
|
10835
11046
|
!lowerer.classes.get(arm.className)?.def.runtime) && lowerer.dynConvertible(mappedReceiver)) {
|
|
10836
|
-
|
|
10837
|
-
return lowerDynDispatchMethodCall(lowerer, call, access, receiver, false);
|
|
11047
|
+
return lowerDynReceiverMethodCall(lowerer, call, access);
|
|
10838
11048
|
}
|
|
10839
11049
|
}
|
|
10840
11050
|
const receiverIr = mappedReceiver?.kind === "object"
|
|
@@ -10982,7 +11192,7 @@ export function lowerObjectMethodCall(lowerer, call, access) {
|
|
|
10982
11192
|
const fallback = virtual
|
|
10983
11193
|
? { kind: "virtualCall", className: info.def.name, method, args: [lowerer.upcastTo(value, info.def.name), ...args], type: found.sig.ret, loc }
|
|
10984
11194
|
: { kind: "call", callee: `%${found.declarer.def.name}.${method}`, args: [lowerer.upcastTo(value, found.declarer.def.name), ...args], type: found.sig.ret, loc };
|
|
10985
|
-
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());
|
|
10986
11196
|
return { kind: "seqExpr", stmts: [{ kind: "varDecl", localId: local.id, init: receiver, loc }], result, type: result.type, loc };
|
|
10987
11197
|
}
|
|
10988
11198
|
if (found.declarer.builtinError) {
|