Skip to content

Fix cross-module super-accessor crash and add class coverage#278

Merged
ASDAlexander77 merged 1 commit into
mainfrom
fix/cross-module-class-accessor-super-crash
Jul 22, 2026
Merged

Fix cross-module super-accessor crash and add class coverage#278
ASDAlexander77 merged 1 commit into
mainfrom
fix/cross-module-class-accessor-super-crash

Conversation

@ASDAlexander77

Copy link
Copy Markdown
Owner

Summary

  • Fixes a real crash: super.<accessor> (get or set) triggered an MLIR verification error ('llvm.call' op operand type mismatch for operand 0) because ClassAccessorAccess never repaired the this operand via getThisRefOfClass, unlike ClassMethodAccess/ClassGenericMethodAccess. Fixed by threading isSuperClass through ClassAccessorAccess and calling getThisRefOfClass for the non-static branch. Not cross-module-specific - reproduces in a single file too.
  • Adds cross-module (export/import) test coverage for class areas that had none before: abstract classes, static members, and accessors (all 3 link tiers: plain compile, -shared DLL, -jit -shared). Abstract classes and static members pass cleanly.
  • Adds a same-file regression test (00class_accessor_super.ts) for the crash fix, since the bug wasn't cross-module-specific.
  • Cross-module generic classes (export_class_generic.ts/import_class_generic.ts) and the -shared tiers of the accessor test are added but currently commented out in CMakeLists.txt - they found two additional, separate, pre-existing bugs in the cross-module declaration-reconstruction path (generic specializations wrongly get dllexport linkage with a comma that breaks the linker's /EXPORT: directive; accessors aren't resolvable at all through the -shared dynamic-import path). These are documented in code comments and left disabled pending a dedicated fix.

Test plan

  • ctest -C Debug -R accessor - all 7 accessor tests pass (including new same-file and cross-module tests)
  • ctest -C Debug -R "class-abstract|class-static" - all 20 tests pass across all 3 tiers
  • Full suite: ctest -C Debug -j8 - 776/776 passed, no regressions

super.<accessor> (get or set) crashed MLIR verification because
ClassAccessorAccess never repaired the `this` operand via
getThisRefOfClass the way ClassMethodAccess does, leaving a raw
by-value ClassStorageType struct where a pointer was expected. Not
cross-module-specific - fixed by threading isSuperClass through
ClassAccessorAccess, with a same-file regression test added alongside
the cross-module one that surfaced it.

Also adds cross-module (export/import) test coverage for abstract
classes and static members, both passing cleanly with no changes
needed.
@ASDAlexander77
ASDAlexander77 merged commit 188e734 into main Jul 22, 2026
2 checks passed
@ASDAlexander77
ASDAlexander77 deleted the fix/cross-module-class-accessor-super-crash branch July 22, 2026 16:13
ASDAlexander77 added a commit that referenced this pull request Jul 22, 2026
…ss) (#282)

super[i] hit llvm_unreachable: the ElementAccessExpression codegen's
super-specific branch only handled a constant string index, with no
fallback to route a real (non-constant) index into ClassIndexAccess the
way ordinary t[i] access already does. Fixing that exposed the second,
originally-suspected bug: ClassIndexAccess never took isSuperClass, so
`super[i]`'s thisValue was never repaired via getThisRefOfClass the way
ClassMethodAccess/ClassAccessorAccess already do (same class of bug PR
#278 fixed for super.<accessor>).

Adds a same-file regression test (00class_indexer_super.ts) covering an
overridden indexer calling back into the base via super[i]/super[i] = v.

Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
ASDAlexander77 added a commit that referenced this pull request Jul 23, 2026
Closes the "much bigger gap" flagged alongside super-accessor-crash-fix
(PR #278): overriding a get/set accessor pair in a subclass and
accessing it through a BASE-TYPED reference (an ordinary upcast, not
`super`) always resolved statically to the base's own accessor instead
of dispatching virtually to the override - a real correctness gap
(this is standard OOP virtual dispatch, not an edge case), unlike
ordinary methods which already dispatch through the vtable correctly.

Root cause: an accessor's backing get/set functions are ALREADY
registered as ordinary MethodInfo entries in ClassInfo::methods (same
list ordinary methods use) with a real vtable slot assigned via
registerClassMethodMember/getVirtualTable - accessors are virtual by
default exactly like methods. But ClassAccessorAccess never checked
isVirtual at all: it unconditionally built ThisAccessorOp with a
hardcoded FlatSymbolRefAttr naming THIS class's own get/set symbol,
completely bypassing the vtable that was already being correctly
built.

Fix: mirror ClassMethodAccess's own isVirtual/isStorageType check
(isStorageType is true for `super.<accessor>`'s raw-struct thisValue,
so super access is naturally excluded from virtual dispatch, same as
methods) and route through the vtable via VirtualSymbolRefOp (the same
op static virtual method access already uses) feeding into the
existing "indirect" (function-value) ThisIndirectAccessorOp, instead
of the hardcoded-symbol ThisAccessorOp. Checked before the
isDynamicImport branch, matching ClassMethodAccess's ordering - the
vtable's own construction already resolves dynamic-import-owned slots,
so virtual dispatch through it is correct regardless of module
boundaries.

One regression found and fixed during verification: getThisRefOfClass
only narrows `thisValue` for the isSuperClass case, so an ordinary
access whose static type is still a wider union (e.g. `T | null`
narrowed only at the type-info level, never cast at the value level -
hit by 00iterator_bug.ts's spread-operator-generated `.length` access)
reached the new vtable lookup with an un-narrowed union type, which
mlirGenPropertyAccessExpression's PropertyRefOp rejects (unlike the
old AnyType-typed ThisAccessorOp it replaces). Fixed by explicitly
casting to classInfo->classType before the vtable lookup.

New same-file regression test 00class_accessor_virtual.ts (compile +
jit tiers). Also closed the historical NOTE in
import_class_accessor.ts documenting this exact gap as deliberately
untested - now asserts virtual dispatch through a base-typed reference
works, cross-module, across all 3 tiers (plain, -shared compile,
-jit -shared). Full suite: 810/810 green.

Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
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