Skip to content

TSLANG_ISSUES 5: @cpp C++ overloads under one name, picked by the arguments - #576

Merged
ASDAlexander77 merged 1 commit into
mainfrom
cpp-overloads
Oct 13, 2026
Merged

ASDAlexander77 merged 1 commit into
mainfrom
cpp-overloads

Conversation

@ASDAlexander77

Copy link
Copy Markdown
Owner

TSLANG_ISSUES.md 5: C++ overloads in @cpp classes.

A @cpp class can now declare a C++ overload set under its C++ name. Each method has its own @slot (or @linkname for a non-virtual one), and a call picks the overload from its arguments at compile time, as C++ does:

@cpp
class Methods {
    @slot(8) over(x: s32): s32;          // MSVC groups overloads in reverse declaration order
    @slot(7) over(x: f64): s32;
    @slot(6) over(a: s32, b: s32): s32;
    @linkname("?scaled@Methods@@QEAAHH@Z") scaled(x: s32): s32;
    @linkname("?scaled@Methods@@QEAAHN@Z") scaled(x: f64): s32;
}
methods.over(5); methods.over(2.5); methods.over(6, 7); methods.scaled(0.5);

Before, a second declaration of a name was a redefinition of symbol error. tsbindgen wrote scale_2, scale_3, so a binding regenerated after the header gained an overload silently called a different method.

How:

  • mlirGenClassCppOverloadNames renames each overload after the first to name#N in the AST, so every name derived from it stays consistent; # can't appear in a TypeScript identifier. It runs once the base classes are known. A method in the slot of a base class's overload takes that overload's name, which is how it overrides it. It is idempotent across discovery and import passes.
  • resolveCppOverload runs in mlirGenCallExpression once the arguments exist. It collects the overloads from the object's class and its bases, deduplicating overrides by name and slot. It scores each argument: 3 for its own type (number ≡ f64), 2 for integer→integer or float→float, 1 for any other conversion. It rebuilds the callee with ClassMethodAccess. No fit, or two equal best fits, is an error that lists the overloads.
  • New errors:
    • an override of an overloaded base method without @slot;
    • a @slot overload with the same parameters as a base method in another slot. That keeps the existing slot_override error: it is the same method overridden in the wrong slot.
  • DeclarationPrinter prints the declared name, and the importer renames again. @cpp diagnostics print declared names.
  • tsbindgen keeps the C++ name for overloads; a method named like a field still gets _2. Docs updated: README, docs/cpp-classes.md, TSLANG_ISSUES.md item 5.

Tests:

  • cppvtable/abi_host.cpp (real C++, built by the host compiler) gains:

    • virtual over(int), over(double), over(int, int);
    • non-virtual scaled(double);
    • pure-virtual Callback::pick(int) / pick(double) implemented in tslang and called from C++.

    test-jit-cppvtable-abi passes with MSVC locally. The Itanium slots (7/8/9, 5/6) and _ZN7Methods6scaledEd follow declaration order and the mangling rules, and Linux CI runs them. The Itanium compile tests check Counter's vtable, including pick and pick#1.

  • 00cpp_overloads.ts: hand-made vtable, base and derived overloads, an override by slot, integer/float/u8/number/string arguments.

  • Error tests: overload_no_match, overload_ambiguous, overload_override.

  • export/import_cppvtable_class: overloads cross __decls, and the exporting module picks the same overload.

  • TsClangImporterTests and the bindgen C++ test now use one name.

  • Full Release suite: all passed, after updating the two tests that expected the old behavior (TsClangImporterTests, and the ownership verifier, which now skips 00cpp_overloads.ts like the other @cpp tests).

🤖 Generated with Claude Code

A @cpp class can declare a C++ overload set under the C++ name, each
method with its own @slot (or @Linkname for a non-virtual one). Before,
a second declaration of a name was "redefinition of symbol", and
tsbindgen wrote `scale_2`, `scale_3`, which quietly changed meaning when
a header added an overload above them.

- mlirGenClassCppOverloadNames renames an overload after the first to
  `name#N` (`#` is in no identifier), once the base classes are known: a
  method in the slot of a base class's overload takes that overload's
  name, which is how it overrides it.
- resolveCppOverload: at the call, after the arguments are generated,
  the overload the arguments fit best is picked from the class and its
  bases, as C++ does: the argument's own type, then an integer for an
  integer or a float for a float (`number` is f64), then any other
  conversion. No fit, or two equal fits, is an error listing them.
- An override of an overloaded base method without @slot is an error,
  and so is a @slot overload with the parameters of a base method in
  another slot (that method, overridden in the wrong slot).
- DeclarationPrinter prints the declared name; the importer renames
  again. Diagnostics print the declared name too.
- tsbindgen keeps the C++ name for overloads (a field of the name still
  gives `_2`).

Tested against real C++ (cppvtable/abi_host.cpp): virtual overloads in
MSVC's reversed order, non-virtual ones by symbol, and C++ calling
overloads implemented in tslang.

TSLANG_ISSUES.md 5.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@ASDAlexander77
ASDAlexander77 merged commit 5eec3b2 into main Oct 13, 2026
2 checks passed
@ASDAlexander77
ASDAlexander77 deleted the cpp-overloads branch October 13, 2026 20:08
ASDAlexander77 added a commit that referenced this pull request Oct 17, 2026
All 19 issues are fixed on main; the section of fixes after pre-alpha97
is no longer headed "Open".

Co-authored-by: Claude Opus 5.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