mirror of
https://github.com/vercel-labs/scriptc.git
synced 2026-10-26 06:34:20 +08:00
Read the class base after the callable-base case in super calls (#1281)
This commit is contained in:
@@ -3,3 +3,5 @@ Casts from values whose type is only known at runtime validate the value. For ex
|
|||||||
Casts between program classes are checked too: casting an instance to a class it does not extend throws a `TypeError`, where Node.js reads the members structurally. `SC6004` reports calls that pass such an instance to a function that casts it.
|
Casts between program classes are checked too: casting an instance to a class it does not extend throws a `TypeError`, where Node.js reads the members structurally. `SC6004` reports calls that pass such an instance to a function that casts it.
|
||||||
|
|
||||||
A Promise converted from `unknown` to a typed result validates its fulfilled value. A mismatch rejects with a `TypeError`. Rejection reasons and reference equality are preserved across conversions.
|
A Promise converted from `unknown` to a typed result validates its fulfilled value. A mismatch rejects with a `TypeError`. Rejection reasons and reference equality are preserved across conversions.
|
||||||
|
|
||||||
|
A non-null assertion (`value!`) checks the value when it extracts an object, array or other non-nullable member from a union. If the value holds `null` or `undefined`, the assertion throws a `TypeError`, even when the result is never used; Node.js continues until a property of the value is read.
|
||||||
|
|||||||
@@ -2,6 +2,6 @@
|
|||||||
"schemaVersion": 3,
|
"schemaVersion": 3,
|
||||||
"nodeVersion": "24.22.0",
|
"nodeVersion": "24.22.0",
|
||||||
"nodeCommit": "f14cd3aa7bf9ca8df2cc5b8bb14beb0f335b1d93",
|
"nodeCommit": "f14cd3aa7bf9ca8df2cc5b8bb14beb0f335b1d93",
|
||||||
"artifactVersion": "56f660f5e2eb7391a048",
|
"artifactVersion": "cade1b8e6e0c5c42fcc9",
|
||||||
"rowCount": 3880
|
"rowCount": 3880
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -569,9 +569,9 @@
|
|||||||
"apiEntries": 120,
|
"apiEntries": 120,
|
||||||
"static": {
|
"static": {
|
||||||
"supported": 0,
|
"supported": 0,
|
||||||
"partial": 50,
|
"partial": 51,
|
||||||
"refused": 0,
|
"refused": 0,
|
||||||
"not-implemented": 70,
|
"not-implemented": 69,
|
||||||
"by-design": 0,
|
"by-design": 0,
|
||||||
"unreviewed": 0,
|
"unreviewed": 0,
|
||||||
"not-applicable": 0
|
"not-applicable": 0
|
||||||
@@ -57593,9 +57593,9 @@
|
|||||||
"anchor": "",
|
"anchor": "",
|
||||||
"nodeStability": null,
|
"nodeStability": null,
|
||||||
"static": {
|
"static": {
|
||||||
"status": "not-implemented",
|
"status": "partial",
|
||||||
"detail": "No static compiler lowering is registered for this API yet.",
|
"detail": "Implemented for the call shapes accepted by the compiler lowering.",
|
||||||
"verification": "registry-gap"
|
"verification": "test-backed"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -7,8 +7,8 @@
|
|||||||
"tierItemCount": 3456,
|
"tierItemCount": 3456,
|
||||||
"tiers": {
|
"tiers": {
|
||||||
"static": {
|
"static": {
|
||||||
"audit-partial": 1142,
|
"audit-partial": 1143,
|
||||||
"verify-gap": 2187,
|
"verify-gap": 2186,
|
||||||
"replace-refusal": 40,
|
"replace-refusal": 40,
|
||||||
"classify": 2,
|
"classify": 2,
|
||||||
"implement": 85
|
"implement": 85
|
||||||
@@ -57507,12 +57507,15 @@
|
|||||||
"priority": "normal",
|
"priority": "normal",
|
||||||
"tiers": {
|
"tiers": {
|
||||||
"static": {
|
"static": {
|
||||||
"status": "not-implemented",
|
"status": "partial",
|
||||||
"action": "verify-gap",
|
"action": "audit-partial",
|
||||||
"verification": "registry-gap",
|
"verification": "test-backed",
|
||||||
"confidence": "low",
|
"confidence": "high",
|
||||||
"source": "compiler-unmatched:process",
|
"source": "surface-manifest:node-builtin.process.execArgv",
|
||||||
"tests": []
|
"tests": [
|
||||||
|
"tests/corpus/990-process-basics.ts",
|
||||||
|
"tests/corpus/2314-process-introspection.ts"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -596,9 +596,9 @@
|
|||||||
"apiEntries": 120,
|
"apiEntries": 120,
|
||||||
"static": {
|
"static": {
|
||||||
"supported": 0,
|
"supported": 0,
|
||||||
"partial": 50,
|
"partial": 51,
|
||||||
"refused": 0,
|
"refused": 0,
|
||||||
"not-implemented": 70,
|
"not-implemented": 69,
|
||||||
"by-design": 0,
|
"by-design": 0,
|
||||||
"unreviewed": 0,
|
"unreviewed": 0,
|
||||||
"not-applicable": 0
|
"not-applicable": 0
|
||||||
@@ -80949,8 +80949,12 @@
|
|||||||
"anchor": "",
|
"anchor": "",
|
||||||
"nodeStability": null,
|
"nodeStability": null,
|
||||||
"static": {
|
"static": {
|
||||||
"status": "not-implemented",
|
"status": "partial",
|
||||||
"evidence": "compiler-unmatched:process"
|
"evidence": "surface-manifest:node-builtin.process.execArgv",
|
||||||
|
"tests": [
|
||||||
|
"tests/corpus/990-process-basics.ts",
|
||||||
|
"tests/corpus/2314-process-introspection.ts"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"anchorSource": "chapter"
|
"anchorSource": "chapter"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -7861,7 +7861,6 @@ export function superCallStmt(
|
|||||||
args: IrExpr[],
|
args: IrExpr[],
|
||||||
loc: SrcLoc,
|
loc: SrcLoc,
|
||||||
): IrStmt {
|
): IrStmt {
|
||||||
const base = superBaseOf(info)!;
|
|
||||||
const thisRef: IrExpr = {
|
const thisRef: IrExpr = {
|
||||||
kind: "varRef",
|
kind: "varRef",
|
||||||
localId: thisLocal.id,
|
localId: thisLocal.id,
|
||||||
@@ -7906,6 +7905,8 @@ export function superCallStmt(
|
|||||||
},
|
},
|
||||||
loc,
|
loc,
|
||||||
};
|
};
|
||||||
|
// A callable base has no class info, so the base is read after that case.
|
||||||
|
const base = superBaseOf(info)!;
|
||||||
if (base.builtinError) {
|
if (base.builtinError) {
|
||||||
// super(message) into the runtime-provided Error constructor: stamps
|
// super(message) into the runtime-provided Error constructor: stamps
|
||||||
// name/message on the (already-allocated) object. Receiver + message
|
// name/message on the (already-allocated) object. Receiver + message
|
||||||
|
|||||||
+6
@@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"order": [
|
||||||
|
"<repo>/tests/corpus/6020-class-extends-function-constructor.js"
|
||||||
|
],
|
||||||
|
"diags": []
|
||||||
|
}
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
// Classes whose base is an ordinary function constructor, with a declared
|
||||||
|
// constructor calling super and with the implicit derived constructor.
|
||||||
|
function Shape(name, sides) {
|
||||||
|
this.name = name;
|
||||||
|
this.sides = sides;
|
||||||
|
}
|
||||||
|
Shape.prototype.describe = function () {
|
||||||
|
return `${this.name} with ${this.sides} sides`;
|
||||||
|
};
|
||||||
|
|
||||||
|
class Polygon extends Shape {
|
||||||
|
constructor(name, sides, length) {
|
||||||
|
super(name, sides);
|
||||||
|
this.length = length;
|
||||||
|
}
|
||||||
|
perimeter() {
|
||||||
|
return this.sides * this.length;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Unnamed extends Shape {}
|
||||||
|
|
||||||
|
const square = new Polygon("square", 4, 3);
|
||||||
|
console.log(square.describe(), square.perimeter());
|
||||||
|
console.log(square instanceof Polygon);
|
||||||
|
const shape = new Unnamed("triangle", 3);
|
||||||
|
console.log(shape.describe(), Object.keys(shape).join(","));
|
||||||
@@ -1915,6 +1915,7 @@
|
|||||||
"600-closures-basic.ts": 2349,
|
"600-closures-basic.ts": 2349,
|
||||||
"601-closures-loops.ts": 1788,
|
"601-closures-loops.ts": 1788,
|
||||||
"602-closures-identity-recursion.ts": 2372,
|
"602-closures-identity-recursion.ts": 2372,
|
||||||
|
"6020-class-extends-function-constructor.js": 4300,
|
||||||
"603-closures-rc-stress.ts": 1832,
|
"603-closures-rc-stress.ts": 1832,
|
||||||
"604-closures-for-of.ts": 2639,
|
"604-closures-for-of.ts": 2639,
|
||||||
"605-closures-forward-capture-tdz.ts": 3277,
|
"605-closures-forward-capture-tdz.ts": 3277,
|
||||||
@@ -4611,6 +4612,7 @@
|
|||||||
"600-closures-basic.ts": 2534,
|
"600-closures-basic.ts": 2534,
|
||||||
"601-closures-loops.ts": 2297,
|
"601-closures-loops.ts": 2297,
|
||||||
"602-closures-identity-recursion.ts": 2427,
|
"602-closures-identity-recursion.ts": 2427,
|
||||||
|
"6020-class-extends-function-constructor.js": 7500,
|
||||||
"603-closures-rc-stress.ts": 2589,
|
"603-closures-rc-stress.ts": 2589,
|
||||||
"604-closures-for-of.ts": 3514,
|
"604-closures-for-of.ts": 3514,
|
||||||
"605-closures-forward-capture-tdz.ts": 4638,
|
"605-closures-forward-capture-tdz.ts": 4638,
|
||||||
|
|||||||
@@ -764,6 +764,38 @@ console.log("recovered");
|
|||||||
expect(r.stdout).toBe("TypeError true\narray: TypeError\nfunc: TypeError\nrecovered\n");
|
expect(r.stdout).toBe("TypeError true\narray: TypeError\nfunc: TypeError\nrecovered\n");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("a non-null assertion on a null object result throws at the assertion, even when the binding is never read", async () => {
|
||||||
|
// Node lets the null ride until a member read; the compiled program
|
||||||
|
// throws the stranded TypeError where `!` extracts the object.
|
||||||
|
const r = await compileAndRun(
|
||||||
|
"asserted-null-object-result",
|
||||||
|
`interface Info {
|
||||||
|
name: string;
|
||||||
|
base: Info | null;
|
||||||
|
callable: boolean;
|
||||||
|
}
|
||||||
|
function baseOf(info: Info): Info | null {
|
||||||
|
return info.base;
|
||||||
|
}
|
||||||
|
function describe(info: Info): string {
|
||||||
|
const base = baseOf(info)!;
|
||||||
|
if (info.callable) return info.name + ": callable base";
|
||||||
|
return info.name + " extends " + base.name;
|
||||||
|
}
|
||||||
|
const root: Info = { name: "Root", base: null, callable: false };
|
||||||
|
console.log(describe({ name: "Child", base: root, callable: false }));
|
||||||
|
try {
|
||||||
|
console.log("unreachable", describe({ name: "Wrapped", base: null, callable: true }));
|
||||||
|
} catch (e) {
|
||||||
|
console.log((e as Error).name, (e as Error).message.includes("not representable in the target union"));
|
||||||
|
}
|
||||||
|
console.log("recovered");
|
||||||
|
`,
|
||||||
|
);
|
||||||
|
expect(r.exitCode).toBe(0);
|
||||||
|
expect(r.stdout).toBe("Child extends Root\nTypeError true\nrecovered\n");
|
||||||
|
});
|
||||||
|
|
||||||
test("a checker-approved function mismatch strands per piece: mismatched params compile at the flow, void results trap after the call", async () => {
|
test("a checker-approved function mismatch strands per piece: mismatched params compile at the flow, void results trap after the call", async () => {
|
||||||
// funcCoerceAdapter's stranded dispositions. Param strand: an array
|
// funcCoerceAdapter's stranded dispositions. Param strand: an array
|
||||||
// literal of arrows collapses to one element signature — the
|
// literal of arrows collapses to one element signature — the
|
||||||
|
|||||||
@@ -65,6 +65,7 @@ export const programs = [
|
|||||||
"nullish-long-chain.ts",
|
"nullish-long-chain.ts",
|
||||||
"class-array-optional-return.ts",
|
"class-array-optional-return.ts",
|
||||||
"contextual-array-union-write.ts",
|
"contextual-array-union-write.ts",
|
||||||
|
"6020-class-extends-function-constructor.js",
|
||||||
];
|
];
|
||||||
|
|
||||||
interface LowerRequest {
|
interface LowerRequest {
|
||||||
|
|||||||
Reference in New Issue
Block a user