Dispatch splice on arrays of unknown elements (#1935)

This commit is contained in:
Chris Tate
2026-10-22 22:57:55 -05:00
committed by GitHub
5 changed files with 37 additions and 0 deletions
@@ -361,6 +361,21 @@ export function lowerArrayMethodCall(
if (probe.type.kind === "array") {
receiverIr = probe.type;
probedUntyped = true;
} else if (
probe.type.kind === "dyn" &&
!isJsSourceFile(ts.getSourceFileOfNode(access)) &&
lowerer.isStdlibMember(access)
) {
// An `unknown[]` (or `any[]`) array stored checked-dynamic — a
// generic body instantiated at `unknown`, a spread of unknown
// elements: the method runs on the runtime array (dynInvoke, JS
// exact), and a typed result is checked like any member read.
const dispatched = lowerDynDispatchMethodCall(lowerer, call, access, probe, true);
if (!dispatched) return null;
const result = lowerer.mapTypeOf(lowerer.typeOf(call));
return result && result.kind !== "void" && result.kind !== "dyn"
? lowerer.coerceInto(call, dispatched, result)
: dispatched;
}
}
if (receiverIr?.kind === "union") {
@@ -4261,6 +4261,7 @@ const DYN_DISPATCH_METHODS = new Set([
"shift",
"unshift",
"slice",
"splice",
"at",
"indexOf",
"lastIndexOf",
@@ -0,0 +1,6 @@
{
"order": [
"<repo>/tests/corpus/7402-unknown-array-methods.ts"
],
"diags": []
}
@@ -0,0 +1,14 @@
// Methods on arrays of unknown elements, which are stored checked-dynamic:
// direct `unknown[]` bindings and generic bodies instantiated at `unknown`.
const values: unknown[] = [1, "two", 3, { four: 4 }];
const removed = values.splice(1, 2);
console.log(values, removed, removed.length);
values.splice(1, 0, "inserted", null);
console.log(values, values.indexOf(null), values.includes("inserted"));
console.log(values.slice(1).reverse(), values.join("|"));
function takeAt<T>(items: readonly T[], index: number): T[] {
const pool = [...items];
return pool.splice(index, 1);
}
console.log(takeAt([10, 20, 30], 1), takeAt<unknown>([true, "x", 7], 2));
@@ -0,0 +1 @@
{ "plain": 2600, "san": 20000 }