Skip to content

super() is analyzed differently from super(C, self) in generic subclass context #13039

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
velsinki opened this issue Jun 29, 2022 · 3 comments
Labels
bug mypy got something wrong topic-inheritance Inheritance and incompatible overrides topic-type-variables

Comments

@velsinki
Copy link

velsinki commented Jun 29, 2022

Bug Report

Consider a minimal reproducing example, based on one from #7362

from typing import TypeVar

T = TypeVar('T', str, int)

class C(list[T]):
    def pop_item(self, key: int) -> T:
        reveal_type(super().pop(key))
        return super().pop(key)

(https://mypy-play.net/?mypy=0.961&python=3.10&gist=ab00ab8ee474443b979cb00ea4284946)

main.py:7: note: Revealed type is "T`1"
main.py:8: error: Incompatible return value type (got "T", expected "str")
main.py:8: error: Incompatible return value type (got "T", expected "int")

This is clearly unexpected, as this should work normally. However, if instead of writing super(), we write super(C, self), which is exactly equivalent syntactically in Python 3, we get

from typing import TypeVar

T = TypeVar('T', str, int)

class C(list[T]):
    def pop_item(self, key: int) -> T:
        reveal_type(super(C, self).pop(key))
        return super(C, self).pop(key)

(https://mypy-play.net/?mypy=0.961&python=3.10&gist=44206838005bf4acfa264a42eecb0eb5)

main.py:7: note: Revealed type is "builtins.str"
main.py:7: note: Revealed type is "builtins.int"

As expected.

Possible fix

Here, Mypy is analyzing super(), differently from super(C, self), which is syntactically incorrect. If super() would instead be (correctly) parsed as super(C, self) in this case, the problem disappears. Note that this also fixes #7362 and #10130.

I don't know enough about Mypy internals to understand why Mypy does not take super() to be equal to super(C, self) here, but perhaps this could be an easy fix?

2024 edit
This reproduces on 1.8.0 as well.

@velsinki velsinki added the bug mypy got something wrong label Jun 29, 2022
@AlexWaygood AlexWaygood added topic-type-variables topic-inheritance Inheritance and incompatible overrides labels Jun 29, 2022
@AlexWaygood
Copy link
Member

Strictly speaking this is a duplicate of the final snippet in #5416, but I think it's fine for this to have its own issue personally.

@velsinki
Copy link
Author

I agree, as that final snipped is also solved by changing super().__init__(t=t) to super(L, self).__init__(t=t).

I would say this is more specific though and should be kept on its own, since one gets that error precisely because super() works differently from super(L, self), and not due to another problem it seems.

Also #7362 and #10130 are similar, but this error will also pop up if you call any super method, not just __init__.

@velsinki
Copy link
Author

velsinki commented Jun 30, 2022

I did a little digging. The function

def _super_arg_types(self, e: SuperExpr) -> Union[Type, Tuple[Type, Type]]:
extracts the arguments to super calls and if it is called without arguments, inspects the top function to figure out the type of the first argument (self in this case).

I don't know how the type checker deals with generic instances though. In this constrained case, it seems to run itself two times, both with T as int and then as str? However, the top_function() does not know about this and so here

instance_type: Type = method.arguments[0].variable.type or current_type
method.arguments[0].variable.type is actually None.

If there is a different method in the type checker to retrieve the type of this argument in this context, perhaps that can be a start to fix this issue?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug mypy got something wrong topic-inheritance Inheritance and incompatible overrides topic-type-variables
Projects
None yet
Development

No branches or pull requests

2 participants