Skip to content

[mypyc] Fix super() method calls in class methods and generators - #22171

Merged
p-sawicki merged 2 commits into
python:masterfrom
rheard:fix-mypyc-1247
Oct 13, 2026
Merged

p-sawicki merged 2 commits into
python:masterfrom
rheard:fix-mypyc-1247

Conversation

@rheard

@rheard rheard commented Oct 10, 2026

Copy link
Copy Markdown
Contributor

Fixes mypyc/mypyc#1247.

super().f() in a class method called a class method of a native base class with type(cls), the metaclass, instead of cls:

class A:
    @classmethod
    def make(cls) -> str:
        return cls.__name__


class B(A):
    @classmethod
    def make(cls) -> str:
        return "B:" + super().make()


print(B.make())  # B:B, compiled: B:type

translate_super_method_call() binds methods of native base classes statically. It took the first argument of the function being compiled as the object, and type() of it for a class method.

The function now works with the variable that super() binds: the second argument of super(B, self), or the first argument of the enclosing function for the zero-argument form. It reads that variable through the symbol table, which gives the right value in generators and closures.

Comment thread mypyc/irbuild/expression.py Outdated
Comment on lines +665 to +669
arg_values = [builder.accept(arg) for arg in expr.args]
arg_kinds, arg_names = expr.arg_kinds.copy(), expr.arg_names.copy()

if decl.kind != FUNC_STATICMETHOD and decl.name != "__new__":
# Grab first argument
vself: Value = builder.self()
if decl.kind == FUNC_CLASSMETHOD:
if needs_self:
vself = builder.read(builder.lookup(self_var), expr.line)

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 think this lookup will have to be moved before argument evaluation, otherwise it's possible to reassign self in the argument expression and break evaluation order:

class A:
    label: str

    def __init__(self, label: str) -> None:
        self.label = label

    def method(self, unused: int) -> str:
        return self.label

class B(A):
    def method(self, unused: int) -> str:
        def change_receiver() -> int:
            nonlocal self
            self = B("replacement")
            return 0

        return super().method(change_receiver())

def result() -> str:
    return B("original").method(0)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Good catch, this has been addressed.

@p-sawicki p-sawicki left a comment

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.

thanks!

@p-sawicki
p-sawicki merged commit f32e78d into python:master Oct 13, 2026
18 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.

super().method() in a class method calls a native base class method with the metaclass as cls

2 participants