Repository navigation
fix(hir): self-named native member base no longer OOM-loops codegen (#4908) - #4955
Merged
Merged
Conversation
…4908) `class Agent extends http.Agent` resolved the member base by its trailing property only (`extract_member_class_name` -> "Agent"), which equals the subclass's own name. The subclass registers its name before heritage resolution, so `lookup_class("Agent")` returned the class itself and both `extends` and `extends_name` self-referenced. Every codegen parent-chain walk then looped forever, OOM-killing the process during "Generating code..." — the four node:http `class Agent extends http.Agent` abort/error tests all crashed this way. Guard both member-heritage arms (class decl + class expr): when the member's trailing name equals the subclass name, leave the class parentless instead of self-linking. This matches how a non-colliding native member base (`class Foo extends http.Agent`) already behaves and, unlike routing through the dynamic extends_expr path, constructs cleanly (no spurious "Must call super constructor"). Cross-module member-extends resolution (drizzle/ethers) is unchanged — the else branch is identical. Adds a regression test covering the empty and method+super+captured-let shapes.
This was referenced Jun 11, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #4908.
Root cause
class Agent extends http.Agent { ... }OOM-crashed codegen during "Generating code...".The class-heritage lowering resolves a member-expression base (
http.Agent) by its trailing property only —extract_member_class_namereturns"Agent". The subclass registers its own name (Agent) before heritage resolution, solookup_class("Agent")returns the class itself and bothextendsandextends_nameend up self-referencing. Every codegen parent-chain walk (extends_name→ctx.classesby name → same class) then loops forever until the process is OOM-killed.Confirmed by bisection: an empty
class Agent extends http.Agent {}— no method, nosuper, no capturedlet— is already enough to crash. Thesuper.createConnection()call and the captured-let++cited in the issue are not the trigger (both compile fine on their own; a CPU sample showed a tight recursive cycle in the parent-chain walk).Fix
Guard both member-heritage arms (class declaration + class expression): when the member's trailing name equals the subclass's own name, leave the class parentless (
extends/extends_name/native_extends/extends_exprallNone) instead of self-linking.This matches how a non-colliding native member base (
class Foo extends http.Agent) already behaves —extends_namethere resolves to no known class, so the class is effectively parentless and constructs cleanly. Routing through the dynamicextends_exprpath was tried and rejected: it makes the class derived and demands a runtimesuper()into the native base, which fails (Class extends value is not a constructor/Must call super constructor).Cross-module member-extends resolution (drizzle
import_mid.SQLiteColumnBuilder, ethersethers.JsonRpcProvider) is unchanged — theelsebranch is byte-identical; the new guard only fires on the name-collision case.Native member-base inheritance (real
instanceof/super.methoddispatch into the base) remains unimplemented for the member-expression case generally; this PR scopes to the codegen crash per the issue's acceptance ("the four tests compile").Validation
class Agent extends http.Agentnode:http tests now compile (-abort-keep-alive-destroy-res,-abort-keep-alive-queued-tcp-socket,-abort-unix-socket,-read-in-error).crates/perry/tests/issue_4908_subclass_native_member_base.rs(2 cases: empty subclass; method +super.createConnection+ capturedlet++) — both compile and construct/run cleanly.cargo test -p perry-hirgreen.Metadata (version bump + CHANGELOG) intentionally omitted for the maintainer to fold at merge.