mirror of
https://github.com/vercel-labs/scriptc.git
synced 2026-10-26 06:34:20 +08:00
Throw for every object on the right of an arrow instanceof, and give blocked bodies their this
- An arrow function or method on the right of an untyped `instanceof` has no prototype. Node throws "Function has non-object prototype 'undefined' in instanceof check" for any object, but the runtime threw only for plain objects, arrays and functions, and answered false for typed arrays, native handles, promises and typed references. It now answers false only for primitives. - Coverage lowers the body of a signature-blocked function for its diagnostics. A declared `this` parameter now gives that body its receiver, as lowerFunction does, so `this.label` reports nothing. Before, each use reported SC1080.
This commit is contained in:
@@ -893,6 +893,9 @@ export function blockedBodyDiagnostics(
|
||||
lowerer.fnStack.push(ctx);
|
||||
let internal = false;
|
||||
try {
|
||||
// A declared `this` parameter gives the body its receiver, as
|
||||
// lowerFunction declares it.
|
||||
if (decl.parameters.nodes.some(isThisParameter)) declareCallReceiver(lowerer, decl, false);
|
||||
for (const param of decl.parameters.nodes) {
|
||||
if (isThisParameter(param)) continue;
|
||||
const declaredParam = lowersCleanly(lowerer, () => {
|
||||
|
||||
@@ -3968,10 +3968,14 @@ bool scr_bytes_instanceof_at(const ScrDyn *value, const ScrDyn *callee, const Sc
|
||||
bool undefined_prototype = prototype->kind == SCR_DYN_UNDEF;
|
||||
scr_dyn_release(prototype);
|
||||
/* A function the program compiled with no prototype (an arrow function
|
||||
* or a method): Node's TypeError for an object, false for a primitive.
|
||||
* The runtime's own constructors carry "native:" signatures. */
|
||||
* or a method): false for a primitive, and Node's TypeError for every
|
||||
* object, typed arrays, native handles, promises and typed references
|
||||
* included. The runtime's own constructors carry "native:" signatures. */
|
||||
if (undefined_prototype && (!callee->v.fn.sig || strncmp(callee->v.fn.sig, "native:", 7) != 0)) {
|
||||
if (value->kind != SCR_DYN_OBJ && value->kind != SCR_DYN_ARR && value->kind != SCR_DYN_FUNC) return false;
|
||||
if (value->kind == SCR_DYN_UNDEF || value->kind == SCR_DYN_NULL || value->kind == SCR_DYN_BOOL ||
|
||||
value->kind == SCR_DYN_NUM || value->kind == SCR_DYN_STR || value->kind == SCR_DYN_BIGINT ||
|
||||
value->kind == SCR_DYN_SYMBOL)
|
||||
return false;
|
||||
static const char message[] = "Function has non-object prototype 'undefined' in instanceof check";
|
||||
scr_throw_error_msg(SCR_ERR_TYPE, message, sizeof message - 1);
|
||||
return false;
|
||||
|
||||
@@ -3,9 +3,10 @@
|
||||
// an ES5 constructor's prototype, at module load and in calls, and throws a
|
||||
// TypeError for an arrow function, which has no prototype, when the value
|
||||
// is an object.
|
||||
import { arrowCheck, describe, rejects, tags } from "tag-types";
|
||||
import { arrowCheck, arrowObjects, describe, rejects, tags } from "tag-types";
|
||||
|
||||
console.log(tags());
|
||||
console.log(describe("{}"), describe("[1]"), describe("null"), describe('"s"'));
|
||||
console.log(rejects('{"tag":"!x"}'));
|
||||
console.log(arrowCheck("{}"), arrowCheck("1"));
|
||||
console.log(arrowObjects());
|
||||
|
||||
+1
@@ -2,3 +2,4 @@ export declare function describe(json: string): string;
|
||||
export declare function tags(): string;
|
||||
export declare function rejects(json: string): string;
|
||||
export declare function arrowCheck(json: string): string;
|
||||
export declare function arrowObjects(): string;
|
||||
|
||||
+10
@@ -59,3 +59,13 @@ module.exports.arrowCheck = function (json) {
|
||||
return error.name + ": " + error.message;
|
||||
}
|
||||
};
|
||||
// Every object reaches the TypeError, typed arrays, promises and Maps too.
|
||||
module.exports.arrowObjects = function () {
|
||||
return [new Uint8Array(2), Promise.resolve(1), new Map(), [1]].map(function (value) {
|
||||
try {
|
||||
return String(value instanceof make);
|
||||
} catch (error) {
|
||||
return error.name;
|
||||
}
|
||||
}).join(",");
|
||||
};
|
||||
|
||||
@@ -13,3 +13,7 @@ function unused(target: WeakRef<object>): number {
|
||||
return extra === undefined ? 0 : 1;
|
||||
}
|
||||
console.log(measure(new WeakRef({}), "abc"));
|
||||
// A declared `this` parameter gives the body its receiver.
|
||||
function described(this: { label: string }, target: WeakRef<object>): string {
|
||||
return this.label + String(target);
|
||||
}
|
||||
|
||||
@@ -194,17 +194,21 @@ test("the body of a signature-blocked function reports its diagnostics", () => {
|
||||
"SC2020 'WeakRef<object>' is part of the standard library types but has no scriptc lowering yet",
|
||||
"SC2020 'new WeakRef' is part of the standard library types but has no scriptc lowering yet",
|
||||
]);
|
||||
// Nothing calls unused: its signature and body report as unreached.
|
||||
// Nothing calls unused or described: their signatures and bodies report
|
||||
// as unreached. described's declared `this` is its receiver, so
|
||||
// `this.label` reports nothing.
|
||||
expect(sites(coverage.unreached?.diagnostics ?? [])).toEqual([
|
||||
"SC2004 uses of 'extra' inherit the blocker on its declaration",
|
||||
"SC2004 uses of 'target' inherit the blocker on its declaration",
|
||||
"SC2020 'WeakRef<object>' is part of the standard library types but has no scriptc lowering yet",
|
||||
"SC2020 'WeakRef<object>' is part of the standard library types but has no scriptc lowering yet",
|
||||
"SC2020 'new WeakRef' is part of the standard library types but has no scriptc lowering yet",
|
||||
]);
|
||||
// The bodies' statements still count once each, as not static.
|
||||
const un = coverage.unreached?.stats;
|
||||
expect(coverage.stats.functionsSkipped + (un?.functionsSkipped ?? 0)).toBe(2);
|
||||
expect(coverage.stats.statementsTotal + (un?.statementsTotal ?? 0)).toBe(6);
|
||||
expect(coverage.stats.statementsFailed + (un?.statementsFailed ?? 0)).toBe(6);
|
||||
expect(coverage.stats.functionsSkipped + (un?.functionsSkipped ?? 0)).toBe(3);
|
||||
expect(coverage.stats.statementsTotal + (un?.statementsTotal ?? 0)).toBe(7);
|
||||
expect(coverage.stats.statementsFailed + (un?.statementsFailed ?? 0)).toBe(7);
|
||||
});
|
||||
|
||||
test("deferred fences in a module's top-level code report as running at startup", () => {
|
||||
|
||||
Reference in New Issue
Block a user