Skip to content

Override inherited overloads a direct base implements only in part - #153

Open
guitargeek wants to merge 1 commit into
compiler-research:mainfrom
guitargeek:fix-dispatcher-inherited-overloads
Open

guitargeek wants to merge 1 commit into
compiler-research:mainfrom
guitargeek:fix-dispatcher-inherited-overloads

Conversation

@guitargeek

@guitargeek guitargeek commented Oct 14, 2026 •

Copy link
Copy Markdown
Collaborator

The dispatcher matched the methods a Python class overrides against the methods its direct C++ base declares itself, and only looked further up the hierarchy for names the base does not declare at all. A base that implements some overloads of a method and inherits others as pure virtual thus had only its own overloads overridden, and the dispatcher class remained abstract.

Walk the whole hierarchy for every overridden name and override each virtual overload not already covered by a more derived class, keyed by canonical argument types and constness. The same key also prevents a signature from being defined twice when two bases declare it.

Operators are matched by their Python name, so that e.g. defining call overrides a virtual operator().

Fixes #146

Comment thread test/test_crossinheritance.py Outdated
Comment on lines +1948 to +1955
PyStandalone = type(
"PyStandalone",
(ns.Standalone,),
{
"operator()": lambda self, *args: 100 + len(args),
"run": lambda self, *args: 200 + len(args),
},
)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe we should be matching the __call__ in Python to operator() in C++.
And not this weird thing.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're right. It's one indirection more though, but worth it because the test becomes more readable.

Comment thread src/cpyrt/Dispatcher.cxx Outdated
// signatures of the methods already overridden, per method name
typedef std::map<std::string, std::set<std::string>> Overridden_t;

static inline std::string MethodKey(TCppMethod_t method) {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
static inline std::string MethodKey(TCppMethod_t method) {
static inline std::string GetMethodSignature(TCppMethod_t method) {

?
Or something like that...

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We already have interop::GetMethodSignature in interop_wrapper.cxx to get the signature of a method.

@guitargeek guitargeek Oct 14, 2026 •

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Renamed to GetOverrideSignature. interop::GetMethodSignature can't be reused here because it prints the types as written (no canonicalization, top-level cv-qualifiers kept) and leaves out constness, so the same signature declared slightly differently in two classes would be injected twice.

The dispatcher matched the methods a Python class overrides against the
methods its direct C++ base declares itself, and only looked further up
the hierarchy for names the base does not declare at all. A base that
implements some overloads of a method and inherits others as pure virtual
thus had only its own overloads overridden, and the dispatcher class
remained abstract.

Walk the whole hierarchy for every overridden name and override each
virtual overload not already covered by a more derived class, keyed by
canonical argument types and constness. The same key also prevents a
signature from being defined twice when two bases declare it.

Operators are matched by their Python name, so that e.g. defining
__call__ overrides a virtual operator().

Fixes compiler-research#146
@guitargeek
guitargeek force-pushed the fix-dispatcher-inherited-overloads branch from 358fcf8 to 817bfe5 Compare October 14, 2026 08:55

This branch has not been deployed

No deployments
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.

Python override of an inherited pure virtual operator() is not generated

2 participants