Skip to content

runtime: indirect subclass of a native base inherits nothing (class D extends B, class B extends EventEmitter) #6326

Description

@proggeramlug

Summary

An indirect subclass of a native base inherits nothing. The base's method surface is only installed when the class literally names the base in its extends clause, so one level of indirection loses it entirely.

Confirmed on clean origin/main.

Repro

import { EventEmitter } from "node:events";
class B extends EventEmitter {}
class D extends B {}          // one hop away from the native base
const d = new D();
console.log("typeof d.on:", typeof d.on, "typeof d.emit:", typeof d.emit);
output
node 26 typeof d.on: function typeof d.emit: function
perry main typeof d.on: undefined typeof d.emit: undefined

new D() is a usable EventEmitter in Node; in perry it has no emitter surface at all. No override is involved — plain two-level inheritance.

Root cause

js_event_emitter_subclass_init only fires when extends_name is literally EventEmitter. A class whose parent is itself an EventEmitter subclass never runs the init, so the method surface is never installed.

Fix direction

This is the EventEmitter mirror of the class-chain walk that PR #6311 added for EventTarget (which reserved CLASS_ID_EVENT_TARGET and wired the registry parent edge so inheritance resolves at any depth). The init needs to trigger on "the class chain reaches EventEmitter", not on a literal extends name match.

Surfaced while fixing #6316 (PR #6322), which deliberately documents this exclusion in its fixture rather than silently passing it. Two-level subclassing of EventEmitter is a very common Node pattern.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions