mirror of
https://github.com/vercel-labs/scriptc.git
synced 2026-10-27 06:43:19 +08:00
Revert "Read error constructors as values and destructure workerData in JavaScript"
This reverts #1776, which made main CI fail.
This commit is contained in:
@@ -36,7 +36,6 @@ import { tryLowerExpression } from "./try-lower-expression.js";
|
||||
import { fenceSymbolFieldCopy } from "../symbol-fields.js";
|
||||
import { planUnionRetag } from "../union-retag.js";
|
||||
import { jsHoldsDynObject, runtimeOptionalStorageOperand } from "../lower-exprs.js";
|
||||
import { builtinGlobalValue } from "./property-access.js";
|
||||
|
||||
/** `{ a: 1, b: "x" }` → recordLit. The record type comes from the
|
||||
* contextual type when tsc has one (annotated declarations, arguments,
|
||||
@@ -395,11 +394,9 @@ export function lowerDynObjectLiteral(
|
||||
const lowerValue = (): IrExpr =>
|
||||
ts.isMethodDeclaration(prop)
|
||||
? lowerer.lowerLambda(prop, true)
|
||||
: ts.isShorthandPropertyAssignment(prop) && shorthandBuiltinValue(lowerer, prop)
|
||||
? shorthandBuiltinValue(lowerer, prop)!
|
||||
: !boxValue && ts.isObjectLiteralExpression(valueExpr)
|
||||
? lowerer.lowerExprExpecting(valueExpr, DYN)
|
||||
: lowerer.lowerExpr(valueExpr as ts.Expression);
|
||||
: !boxValue && ts.isObjectLiteralExpression(valueExpr)
|
||||
? lowerer.lowerExprExpecting(valueExpr, DYN)
|
||||
: lowerer.lowerExpr(valueExpr as ts.Expression);
|
||||
raw = fenceClosureProbe(lowerer, valueExpr, undefined, lowerValue) ?? lowerValue();
|
||||
} catch (err) {
|
||||
// A PURE member read a JS file cannot lower (a namespace object
|
||||
@@ -3157,20 +3154,6 @@ function lowerDeclaredSpreadMerge(
|
||||
/** The value of a shorthand property (`{ x }`): the binding `x` refers to.
|
||||
* The property name's own symbol is the PROPERTY, so resolution goes
|
||||
* through getShorthandAssignmentValueSymbol. */
|
||||
/** `{ TypeError }`: a stdlib global in shorthand position reads as the value
|
||||
* its name reads as elsewhere (the interned constructor or function value),
|
||||
* or null when the global has no such value. The shorthand's name carries
|
||||
* the property's symbol, so the identifier path cannot resolve it. */
|
||||
function shorthandBuiltinValue(
|
||||
lowerer: Lowerer,
|
||||
prop: ts.ShorthandPropertyAssignment,
|
||||
): IrExpr | null {
|
||||
const symbol = lowerer.checker.getShorthandAssignmentValueSymbol(prop);
|
||||
if (!symbol || !lowerer.isStdlibSymbol(symbol)) return null;
|
||||
const js = isJsSourceFile(ts.getSourceFileOfNode(prop));
|
||||
return builtinGlobalValue(ts.symbolName(symbol), locOf(prop.name), js);
|
||||
}
|
||||
|
||||
export function lowerShorthandValue(
|
||||
lowerer: Lowerer,
|
||||
prop: ts.ShorthandPropertyAssignment,
|
||||
@@ -3187,8 +3170,6 @@ export function lowerShorthandValue(
|
||||
const callable = lowerer.lowerBuiltinCallableValue(builtin, loc);
|
||||
if (callable) return callable;
|
||||
}
|
||||
const builtinValue = shorthandBuiltinValue(lowerer, prop);
|
||||
if (builtinValue) return builtinValue;
|
||||
if (symbol) {
|
||||
if (lowerer.ctx.selfSymbol === symbol) {
|
||||
return { kind: "selfRef", type: lowerer.ctx.selfType!, loc };
|
||||
|
||||
@@ -4024,26 +4024,10 @@ function lowerStreamObjectProperty(
|
||||
return lowerStreamProperty(lowerer, expr, info);
|
||||
}
|
||||
|
||||
/** The error constructors among GLOBAL_CONSTRUCTOR_VALUES. Their statics
|
||||
* (`Error.stackTraceLimit`, `Error.captureStackTrace`) keep their own
|
||||
* lowerings, so fenceBuiltinConstructorStaticRead leaves them alone. */
|
||||
const ERROR_CONSTRUCTOR_VALUES: ReadonlySet<string> = new Set([
|
||||
"Error",
|
||||
"TypeError",
|
||||
"RangeError",
|
||||
"SyntaxError",
|
||||
"ReferenceError",
|
||||
"EvalError",
|
||||
"URIError",
|
||||
"AggregateError",
|
||||
]);
|
||||
|
||||
/** The builtin constructors JavaScript sources read as real function
|
||||
* values rather than identity tokens: the runtime interns one function per
|
||||
* constructor, and dynamic values answer `.constructor` with the same one,
|
||||
* so `o.constructor === Object` and `err.constructor === TypeError` are
|
||||
* exact identity tests, and `err.constructor.name` is the constructor's
|
||||
* name. */
|
||||
* so `o.constructor === Object` is an exact identity test. */
|
||||
const GLOBAL_CONSTRUCTOR_VALUES: ReadonlySet<string> = new Set([
|
||||
"Object",
|
||||
"Function",
|
||||
@@ -4054,7 +4038,6 @@ const GLOBAL_CONSTRUCTOR_VALUES: ReadonlySet<string> = new Set([
|
||||
"Promise",
|
||||
"WeakMap",
|
||||
"WeakSet",
|
||||
...ERROR_CONSTRUCTOR_VALUES,
|
||||
]);
|
||||
|
||||
/** The builtin global functions JavaScript sources read as interned
|
||||
@@ -4197,7 +4180,6 @@ function fenceBuiltinConstructorStaticRead(
|
||||
symbol !== undefined &&
|
||||
ts.symbolName(symbol).endsWith("Constructor") &&
|
||||
GLOBAL_CONSTRUCTOR_VALUES.has(ts.symbolName(symbol).slice(0, -"Constructor".length)) &&
|
||||
!ERROR_CONSTRUCTOR_VALUES.has(ts.symbolName(symbol).slice(0, -"Constructor".length)) &&
|
||||
lowerer.isStdlibSymbol(symbol)
|
||||
)
|
||||
lowerer.stdlibMemberFence(access);
|
||||
|
||||
@@ -3889,9 +3889,6 @@ function stdlibGlobalTokenDestructure(
|
||||
if (decl.initializer === undefined || !isJsSourceFile(ts.getSourceFileOfNode(decl))) return null;
|
||||
const globalName = stdlibGlobalNameOf(lowerer, decl.initializer);
|
||||
if (globalName === null) return null;
|
||||
// `workerData` is a value (the data the worker was started with), not an
|
||||
// API surface: its members destructure as any untyped value's do.
|
||||
if (globalName === "workerData") return null;
|
||||
if (!ts.isObjectBindingPattern(decl.name)) {
|
||||
lowerer.unsupported(
|
||||
"SC1031",
|
||||
|
||||
-6
@@ -1,6 +0,0 @@
|
||||
{
|
||||
"order": [
|
||||
"<repo>/tests/corpus/6870-error-constructor-values.js"
|
||||
],
|
||||
"diags": []
|
||||
}
|
||||
-6
@@ -1,6 +0,0 @@
|
||||
{
|
||||
"order": [
|
||||
"<repo>/tests/corpus/6871-worker-data-destructuring.cjs"
|
||||
],
|
||||
"diags": []
|
||||
}
|
||||
@@ -725,9 +725,6 @@ ScrDyn *scr_dyn_array_constructor(void);
|
||||
/* The interned builtin constructor `name` (Object, Date, RegExp, Map, Set,
|
||||
* Promise, WeakMap, WeakSet) as a dynamic function value: +1. */
|
||||
ScrDyn *scr_dyn_global_constructor(const ScrStr *name);
|
||||
/* The interned function value of an error constructor ("TypeError"), or
|
||||
* NULL for other names. */
|
||||
ScrDyn *scr_dyn_error_constructor(const char *name);
|
||||
/* A builtin global function (setTimeout, setImmediate, process.nextTick, ...)
|
||||
* as an interned dynamic function value: +1. */
|
||||
ScrDyn *scr_dyn_builtin_function(const ScrStr *name);
|
||||
|
||||
@@ -1913,8 +1913,6 @@ static ScrDyn *dyn_function_constructor(void) {
|
||||
|
||||
ScrDyn *scr_dyn_global_constructor(const ScrStr *name) {
|
||||
if (strcmp(name->data, dyn_s20) == 0) return dyn_function_constructor();
|
||||
ScrDyn *error = scr_dyn_error_constructor(name->data);
|
||||
if (error) return error;
|
||||
ScrDyn *ctor = dyn_global_ctor(name->data);
|
||||
if (!ctor) scr_trap(dyn_s3);
|
||||
return ctor;
|
||||
|
||||
@@ -1801,55 +1801,6 @@ static void scr_builtin_object_prototype_cleanup(void) {
|
||||
scr_dyn_release(prototype);
|
||||
}
|
||||
|
||||
/* The error constructors as values (an error's `constructor`, and the
|
||||
* globals in JavaScript): one interned function per constructor and thread,
|
||||
* indexed like scr_error_vts, with the constructor's name and length.
|
||||
* Calling one through the value is not supported yet, as for the other
|
||||
* interned constructors (scr_dyn_global_constructor). */
|
||||
static const char *const scr_error_ctor_names[] = {
|
||||
"Error", "TypeError", "RangeError", "SyntaxError", NULL,
|
||||
"ReferenceError", "EvalError", "URIError", "AggregateError",
|
||||
};
|
||||
#define SCR_ERROR_CTORS (sizeof scr_error_ctor_names / sizeof scr_error_ctor_names[0])
|
||||
static SCR_TL ScrDyn *scr_error_ctor_values[SCR_ERROR_CTORS];
|
||||
static SCR_TL bool scr_error_ctors_registered;
|
||||
|
||||
static void scr_error_ctors_cleanup(void) {
|
||||
for (size_t i = 0; i < SCR_ERROR_CTORS; i++) {
|
||||
scr_dyn_release(scr_error_ctor_values[i]);
|
||||
scr_error_ctor_values[i] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static ScrDyn *scr_error_ctor_call(ScrClosure *closure, ScrDyn *const *args, size_t argc) {
|
||||
(void)args;
|
||||
(void)argc;
|
||||
char message[128];
|
||||
int length = snprintf(message, sizeof message,
|
||||
"calling the %s constructor through a stored value is not supported yet",
|
||||
(const char *)closure->fn);
|
||||
scr_throw_error_msg_code(SCR_ERR_ERROR, message, (size_t)length, "SC2020");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ScrDyn *scr_dyn_error_constructor(const char *name) {
|
||||
for (size_t i = 0; i < SCR_ERROR_CTORS; i++) {
|
||||
if (!scr_error_ctor_names[i] || strcmp(scr_error_ctor_names[i], name) != 0) continue;
|
||||
if (!scr_error_ctors_registered) {
|
||||
scr_error_ctors_registered = true;
|
||||
scr_atexit(scr_error_ctors_cleanup);
|
||||
}
|
||||
if (!scr_error_ctor_values[i]) {
|
||||
uint32_t length = strcmp(name, "AggregateError") == 0 ? 2 : 1;
|
||||
scr_error_ctor_values[i] =
|
||||
scr_dyn_new_func(scr_closure_new((void *)scr_error_ctor_names[i], 0), scr_error_ctor_call, length,
|
||||
"native:constructor", scr_error_ctor_names[i]);
|
||||
}
|
||||
return scr_dyn_retain(scr_error_ctor_values[i]);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ScrDyn *scr_dyn_object_prototype(void) {
|
||||
if (!scr_builtin_object_prototype) {
|
||||
scr_builtin_object_prototype = scr_dyn_alloc(SCR_DYN_OBJ);
|
||||
@@ -7756,17 +7707,6 @@ ScrStr *scr_dyn_to_string(const ScrDyn *d, const ScrStr *enc) {
|
||||
return out;
|
||||
}
|
||||
case SCR_DYN_FUNC: {
|
||||
/* The interned builtin constructors print with their names, as in Node
|
||||
* (function Map() { [native code] }); other functions without a source
|
||||
* text print the anonymous native form. */
|
||||
if (d->v.fn.sig && strcmp(d->v.fn.sig, "native:constructor") == 0 && d->v.fn.name) {
|
||||
ScrJsonBuf b;
|
||||
scr_jb_init(&b);
|
||||
scr_jb_puts(&b, "function ");
|
||||
scr_jb_puts(&b, d->v.fn.name);
|
||||
scr_jb_puts(&b, "() { [native code] }");
|
||||
return scr_jb_finish(&b);
|
||||
}
|
||||
static const char f[] = "function () { [native code] }";
|
||||
return scr_str_new(f, sizeof f - 1);
|
||||
}
|
||||
@@ -11720,18 +11660,21 @@ static ScrDyn *scr_dyn_obj_read_receiver(const ScrDyn *d, const char *key, size_
|
||||
ScrDyn *own = scr_dyn_obj_get(d, key, key_len);
|
||||
if (own) return scr_dyn_retain(own);
|
||||
if (key_len == 11 && memcmp(key, "constructor", 11) == 0) {
|
||||
/* An error's constructor: the interned function value its global
|
||||
* reads as (scr_dyn_error_constructor). */
|
||||
static const char *const names[] = {
|
||||
"Error", "TypeError", "RangeError", "SyntaxError", NULL,
|
||||
"ReferenceError", "EvalError", "URIError", "AggregateError",
|
||||
static const char *const tokens[] = {
|
||||
"[builtin Error]", "[builtin TypeError]",
|
||||
"[builtin RangeError]", "[builtin SyntaxError]",
|
||||
NULL, "[builtin ReferenceError]", "[builtin EvalError]", "[builtin URIError]",
|
||||
"[builtin AggregateError]",
|
||||
};
|
||||
size_t hit = scr_errdyn_find(d, false);
|
||||
const ScrVt *vt = hit == SIZE_MAX ? NULL : scr_errdyn_cache[hit].err->vt;
|
||||
for (size_t kind = 0; vt && kind < sizeof names / sizeof names[0]; kind++) {
|
||||
if (!names[kind]) continue;
|
||||
for (size_t kind = 0; vt && kind < sizeof tokens / sizeof tokens[0]; kind++) {
|
||||
if (!tokens[kind]) continue;
|
||||
if (vt != &scr_error_vts[kind]) continue;
|
||||
return scr_dyn_error_constructor(names[kind]);
|
||||
ScrStr *token = scr_str_new(tokens[kind], strlen(tokens[kind]));
|
||||
ScrDyn *result = scr_dyn_new_str(token);
|
||||
scr_str_release(token);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
return scr_dyn_retain(scr_dyn_undefined());
|
||||
|
||||
@@ -1,55 +0,0 @@
|
||||
// The error constructors as values in JavaScript: an error's `constructor`
|
||||
// is the same function the global names, whose name, length, typeof and
|
||||
// String() are Node's, for errors the program throws, errors the runtime
|
||||
// throws, and errors read back from catch bindings and containers.
|
||||
function describe(label, error) {
|
||||
const ctor = error.constructor;
|
||||
console.log(label, error.name, error.constructor.name, typeof ctor, ctor.length, String(ctor));
|
||||
}
|
||||
|
||||
describe('Error', new Error('e'));
|
||||
describe('TypeError', new TypeError('t'));
|
||||
describe('RangeError', new RangeError('r'));
|
||||
describe('SyntaxError', new SyntaxError('s'));
|
||||
describe('ReferenceError', new ReferenceError('f'));
|
||||
describe('EvalError', new EvalError('v'));
|
||||
describe('URIError', new URIError('u'));
|
||||
describe('AggregateError', new AggregateError([], 'a'));
|
||||
|
||||
const thrown = [
|
||||
() => JSON.parse('{'),
|
||||
() => {
|
||||
const holder = JSON.parse('{"value":null}');
|
||||
return holder.value.missing;
|
||||
},
|
||||
() => new Array(-1),
|
||||
() => decodeURIComponent('%'),
|
||||
() => {
|
||||
throw new TypeError('own');
|
||||
},
|
||||
];
|
||||
const constructors = { SyntaxError, TypeError, RangeError, URIError };
|
||||
const caught = [];
|
||||
for (const run of thrown) {
|
||||
try {
|
||||
run();
|
||||
} catch (error) {
|
||||
caught.push(error);
|
||||
console.log('caught', error.constructor.name, error.constructor === constructors[error.name]);
|
||||
}
|
||||
}
|
||||
|
||||
const byName = new Map();
|
||||
for (const error of caught) byName.set(error.constructor.name, (byName.get(error.constructor.name) ?? 0) + 1);
|
||||
console.log('kinds', JSON.stringify([...byName]));
|
||||
|
||||
console.log('identity', new TypeError('x').constructor === TypeError, new RangeError('x').constructor === TypeError);
|
||||
console.log('globals', Error.name, TypeError.length, AggregateError.length, typeof RangeError, String(SyntaxError));
|
||||
|
||||
const renamed = new TypeError('x');
|
||||
renamed.name = 'Custom';
|
||||
console.log('renamed', renamed.name, renamed.constructor.name);
|
||||
|
||||
class ParseFailure extends SyntaxError {}
|
||||
const failure = new ParseFailure('p');
|
||||
console.log('subclass', failure.name, failure.constructor.name, failure instanceof SyntaxError);
|
||||
@@ -1,30 +0,0 @@
|
||||
// Destructuring the members of a worker's workerData in JavaScript: plain,
|
||||
// renamed, defaulted, nested and rest bindings read the data the worker was
|
||||
// started with, as reading `workerData.<member>` does.
|
||||
'use strict';
|
||||
const { Worker, isMainThread, parentPort, workerData } = require('node:worker_threads');
|
||||
|
||||
if (isMainThread) {
|
||||
const sab = new SharedArrayBuffer(8);
|
||||
const data = { name: 'job-7', size: 3, options: { verbose: true, tags: ['a', 'b'] }, counters: new Int32Array(sab), extra: 1, more: 'x' };
|
||||
const worker = new Worker(__filename, { workerData: data });
|
||||
worker.on('message', (lines) => {
|
||||
for (const line of lines) console.log(line);
|
||||
console.log('main sees', new Int32Array(sab)[0]);
|
||||
});
|
||||
} else {
|
||||
const lines = [];
|
||||
const { name, size } = workerData;
|
||||
lines.push(`plain ${name} ${size}`);
|
||||
const { name: jobName, missing = 'fallback', size: count = 10 } = workerData;
|
||||
lines.push(`renamed ${jobName} ${missing} ${count}`);
|
||||
const {
|
||||
options: { verbose, tags: [firstTag, ...otherTags] },
|
||||
} = workerData;
|
||||
lines.push(`nested ${verbose} ${firstTag} ${JSON.stringify(otherTags)}`);
|
||||
const { name: ignored, size: alsoIgnored, options, counters, ...rest } = workerData;
|
||||
lines.push(`rest ${JSON.stringify(rest)} ${typeof options} ${ignored === name && alsoIgnored === size}`);
|
||||
counters[0] = 41;
|
||||
counters[0] += 1;
|
||||
parentPort.postMessage(lines);
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
{ "plain": 1200, "san": 3400 }
|
||||
@@ -1 +0,0 @@
|
||||
{ "plain": 1300, "san": 3490 }
|
||||
Reference in New Issue
Block a user