Skip to content

New generics: specialise a subclass's superclasses without rewriting the list in place - #1422

Merged
Frotty merged 1 commit into
masterfrom
generics-override-crash
Oct 9, 2026
Merged

Frotty merged 1 commit into
masterfrom
generics-override-crash

Conversation

@Frotty

@Frotty Frotty commented Oct 9, 2026

Copy link
Copy Markdown
Member

Problem

The compiler crashed with a ConcurrentModificationException in EliminateGenerics.adaptSubmethods on Jass, the interpreter and Lua. It happened when a method of a generic class was overridden again in a plain subclass and called through a non-generic base:

class Base
    function m() returns int
        return 1
class C<T:> extends Base
    override function m() returns int
        return 2
class D extends C<int>
    override function m() returns int
        return 4
function viaBase(Base b) returns int
    return b.m()

adaptSubmethods rewrote D's superclass list in place with replaceAll(specializeType). Specialising C<int> runs the trigger registered on C. That trigger specialises C.m and adapts its submethods, D.m among them, so it rewrites D's list again inside the outer replaceAll.

The same in-place rewrite existed in two other places:

  • specializeClass, for a generic class's own superclasses.
  • rewriteRuntimeTypeSuperEdges, which rewrites every class's list in place.

Change

A new helper, specializeSuperClasses, reads a class's superclass list from a copy and replaces the list rather than rewriting it in place. All three callers now use it:

  • adaptSubmethods
  • specializeClass
  • the use queued for each non-generic class, which already built a new list but iterated the live one

The InterfaceTranslator note named this crash as one reason the bridge skips generic classes. I removed that clause; the other reason still stands.

Checks

  • Two new tests in GenericsWithTypeclassesTests: the plain subclass, and a subclass that also implements an interface. Both run on Jass, the interpreter and Lua. Both failed with the exception before this change and pass after it.
  • These 12 test classes pass (972 tests): GenericsWithTypeclassesTests, GenericsTests, ClassesTests, InterfaceTests, LuaBackendAuditTests, DeterministicChecks, FieldIterationTests, LuaKeyedMapTests, TreeShakerTests, LuaTranslationTests, BugTests, NewFeatureTests.
  • Castle fight and zombie defense, built with -lua -inline -localOptimizations, produce Lua byte-identical to master. Zombie defense differs only in its embedded build minute.

Not in this PR

The interface bridge from #1421 is still limited to non-generic classes. Extending it to generic classes is a separate change.

…the list in place

A method of a generic class overridden again in a plain subclass and called through
a non-generic base (class C<T:> extends Base, class D extends C<int>, Base.m() called)
crashed the compiler with a ConcurrentModificationException on every target.

adaptSubmethods rewrote D's superclass list in place with replaceAll(specializeType).
Specialising C<int> runs the trigger registered on C, which specialises C.m and adapts
its submethods, D.m among them, and so rewrites D's list again inside the outer
replaceAll. The specialisation of a generic class's own superclasses had the same
shape, and rewriteRuntimeTypeSuperEdges rewrites every class's list in place too.

One helper now specialises a class's superclasses into a new list from a copy and
replaces the old one; adaptSubmethods, specializeClass and the use queued for each
non-generic class all call it. The InterfaceTranslator note which named this crash
as a reason to skip generic classes is updated.
@Frotty

Frotty commented Oct 9, 2026

Copy link
Copy Markdown
Member Author

@codex review

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 9, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-09T19:26:08.422725Z af5f4a1 Manual request
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Another round soon, please!

Reviewed commit: af5f4a1cc1

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@Frotty
Frotty merged commit a88cdce into master Oct 9, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant