Throw checked-dynamic primitives as primitives so catch typeof tests see them (#1510)

This commit is contained in:
Chris Tate
2026-10-20 04:19:32 -05:00
committed by GitHub
3 changed files with 68 additions and 0 deletions
@@ -0,0 +1,6 @@
{
"order": [
"<repo>/tests/corpus/6480-catch-typeof-untyped-throws.ts"
],
"diags": []
}
+22
View File
@@ -6421,6 +6421,28 @@ void scr_dyn_throw(ScrDyn *d) {
scr_dyn_release(d);
return;
}
/* A checked-dynamic primitive throws as the primitive itself, as a
* statically typed `throw 5` does: catch bindings test and extract the
* same snapshot kinds (`typeof e === "number"`), and a primitive has no
* identity to keep. */
if (d->kind == SCR_DYN_NUM) {
double value = d->v.num;
scr_dyn_release(d);
scr_throw_f64(value);
return;
}
if (d->kind == SCR_DYN_BOOL) {
bool value = d->v.b;
scr_dyn_release(d);
scr_throw_bool(value);
return;
}
if (d->kind == SCR_DYN_STR) {
ScrStr *value = scr_str_retain(d->v.str);
scr_dyn_release(d);
scr_throw_str(value);
return;
}
scr_throw_ref_classified(d, scr_dyn_retain_v, scr_dyn_release_v,
scr_dyn_trace_v, scr_dyn_is_object(d));
}
@@ -0,0 +1,40 @@
// Values thrown from `unknown` storage read back through typeof tests on
// the catch binding, like the same values thrown with static types.
const thrown: unknown[] = [5, 0, -1.5, "text", "", true, false, null, undefined, { kind: "box" }];
function describe(value: unknown): string {
try {
throw value;
} catch (e) {
const same = e === value;
if (typeof e === "number") return `${same} number ${e + 1}`;
if (typeof e === "string") return `${same} string ${e.length}`;
if (typeof e === "boolean") return `${same} boolean ${!e}`;
if (typeof e === "object") return `${same} object ${e === null ? "null" : "value"}`;
return `${same} ${typeof e}`;
}
}
for (const value of thrown) console.log(describe(value));
function rethrow(value: unknown): void {
try {
throw value;
} catch (e) {
if (typeof e !== "string") throw e;
console.log("kept string", e);
}
}
for (const value of ["s", 7, false]) {
try {
rethrow(value);
} catch (e) {
console.log("rethrown", typeof e, String(e));
}
}
let count = 0;
for (const value of thrown) {
try {
throw value;
} catch (e) {
if (typeof e === "number" && e > 0) count += e;
}
}
console.log(count);