mirror of
https://github.com/vercel-labs/scriptc.git
synced 2026-10-28 06:53:42 +08:00
A reflected JavaScript class method lowers its lambda the first time its value is read, and caches the closure only after the body lowered. A method whose own body reads the method as a value, like i18next's `instance.createInstance = I18n.createInstance`, reentered the lowering for the same method until the compiler overflowed its stack. Record the method while its lambda lowers; lowerLambda names the closure it will produce, and a read of the method inside its own body takes that closure, so every read sees the same function. When the body later changes the closure (its type is settled by an inferred return, or it captures), the self read is refused with a named diagnostic instead. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
29 lines
804 B
JavaScript
29 lines
804 B
JavaScript
// JavaScript class methods that read themselves as a value inside their
|
|
// own body: i18next's `instance.createInstance = I18n.createInstance`.
|
|
// The value is the same function every other read of the method sees.
|
|
|
|
class Registry {
|
|
/** @param {string} name */
|
|
constructor(name) {
|
|
this.name = name;
|
|
/** @type {((name: string) => Registry) | undefined} */
|
|
this.create = undefined;
|
|
}
|
|
|
|
/** @param {string} name */
|
|
static create(name) {
|
|
const registry = new Registry(name);
|
|
registry.create = Registry.create;
|
|
return registry;
|
|
}
|
|
|
|
describe() {
|
|
return `${this.name} ${typeof this.create}`;
|
|
}
|
|
}
|
|
|
|
const a = Registry.create('a');
|
|
const b = a.create?.('b') ?? a;
|
|
console.log(a.describe(), b.describe());
|
|
console.log(a.create === Registry.create, b.create === a.create);
|