mirror of
https://github.com/vercel-labs/scriptc.git
synced 2026-10-22 05:59:31 +08:00
- The ratified rename rider (world-unification §7 lane 5): "DOM" collided with the browser DOM and, post-lane-1, the structure is no longer a document tree. Comments and doc prose now say "the checked-dynamic tree" for the noun and "dyn" adjectivally; runtime symbol names (scr_dyn_*), the error.domClone libCall, and the real web DOMException family are unchanged. - The few user-facing strings carrying the nickname move with it (the structuredClone cyclic message, the dc subscriber/publish fences, two emitter ICE texts); diagnostics snapshots regenerated (96 pass). One private compiler constant (DOM_PROTO_METHOD_NAMES -> DYN_PROTO_METHOD_NAMES) rides along. - Mechanical sweep, 142 files, comments/prose only — no behavior change.
95 lines
2.7 KiB
TypeScript
95 lines
2.7 KiB
TypeScript
// #private-member FENCES: the shapes the private-members lowering refuses,
|
|
// each with the diagnostic naming the honest reason. Everything here is
|
|
// legal TypeScript that Node runs — the fences are representation limits,
|
|
// not type errors.
|
|
|
|
// A subclass redeclaring an inherited private NAME: JS gives each class its
|
|
// own distinct '#x' slot under one spelling; these layouts have one slot
|
|
// per name.
|
|
class RedeclareBase {
|
|
#x = 1;
|
|
read(): number {
|
|
return this.#x;
|
|
}
|
|
}
|
|
class RedeclareSub extends RedeclareBase {
|
|
#x = 2;
|
|
own(): number {
|
|
return this.#x;
|
|
}
|
|
}
|
|
const rs = new RedeclareSub();
|
|
console.log(rs.read());
|
|
|
|
// Extracted private methods are NOT auto-bound in JS (`f()` runs with
|
|
// `this` undefined) — the unbound value has no static story, the
|
|
// bound-method fence names it.
|
|
class Unbound {
|
|
#m(): number {
|
|
return 1;
|
|
}
|
|
grab(): () => number {
|
|
const f = this.#m;
|
|
return f;
|
|
}
|
|
}
|
|
console.log(new Unbound().grab()());
|
|
|
|
// Brand checks need a receiver whose representation can HOLD a branded
|
|
// instance: 'unknown' values live in the checked-dynamic tree, which never carries class
|
|
// instances — the fence points at narrowing.
|
|
class BrandUnknown {
|
|
#v = 3;
|
|
static probe(o: unknown): boolean {
|
|
return typeof o === "object" && o !== null && #v in o;
|
|
}
|
|
}
|
|
console.log(BrandUnknown.probe(null));
|
|
|
|
// A private STATIC's brand lives on the declaring class OBJECT, not on
|
|
// instances — the instance-shaped test fences.
|
|
class StaticBrand {
|
|
static #s(): number {
|
|
return 1;
|
|
}
|
|
check(o: StaticBrand): boolean {
|
|
return #s in o;
|
|
}
|
|
}
|
|
console.log(new StaticBrand().check(new StaticBrand()));
|
|
|
|
// Private statics through class VALUES that may hold a DESCENDANT: with a
|
|
// subclass in the program, the slot can hold it at runtime and JS brands
|
|
// the declaring class object alone (exact receivers — the name, a const
|
|
// alias, a leaf class's values — compile).
|
|
class ViaValue {
|
|
static #origin = 7;
|
|
static read(k: typeof ViaValue): number {
|
|
return k.#origin;
|
|
}
|
|
}
|
|
class ViaValueSub extends ViaValue {}
|
|
console.log(ViaValue.read(ViaValueSub));
|
|
|
|
// Generic classes share ONE brand across every instantiation in JS; these
|
|
// layouts mint one class per instantiation, so private-in fences there.
|
|
class GenBrand<T> {
|
|
#tag = 1;
|
|
same(o: GenBrand<number>): boolean {
|
|
return #tag in o;
|
|
}
|
|
}
|
|
console.log(new GenBrand<number>().same(new GenBrand<number>()));
|
|
|
|
// Async private generators are still async generators — the blanket fence.
|
|
class AsyncGen {
|
|
async *#pump(): AsyncGenerator<number, void, undefined> {
|
|
yield 1;
|
|
}
|
|
async drain(): Promise<void> {
|
|
for await (const v of this.#pump()) console.log(v);
|
|
}
|
|
}
|
|
const ag = new AsyncGen();
|
|
void ag.drain();
|