Skip to content
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

False positive about self argument with union of namedtuple and Any #15600

Open
JukkaL opened this issue Jul 5, 2023 · 1 comment
Open

False positive about self argument with union of namedtuple and Any #15600

JukkaL opened this issue Jul 5, 2023 · 1 comment
Labels
bug mypy got something wrong topic-named-tuple

Comments

@JukkaL
Copy link
Collaborator

JukkaL commented Jul 5, 2023

The following code produces a false positive:

from collections import namedtuple
from typing import Any

T = namedtuple("T", ["x"])

class C(T):
    def f(self) -> bool:
        return True

c: C | Any
c.f()  # Error: Invalid self argument "C" to attribute function "f" with type "Callable[[C], bool]"

c2: C
c2.f()  # Ok

It looks like the self argument check fails when we have a union with a namedtuple type. It's okay if the base class is a regular class, or if there is no union.

@JukkaL JukkaL added the bug mypy got something wrong label Jul 5, 2023
@ilevkivskyi
Copy link
Member

Note that the bug is specific to a union with Any, union with another type (that has the attribute) doesn't cause the problem. This is happening because self argument check does something like is_subtype(meet_types(base_type, instance_type), erase_type_vars(declared_self_type)), and meet_types() is broken for Any. Namely, in this case meet_types(Union[tuple[Any, fallback=C], Any], C) returns C, because meet_types(Any, C) returns C. And then is_subtype(C, tuple[Any, fallback=C]) obviously returns False, causing the error.

But the problem is actually much wider, meet_types(C, Any) returning C is both wrong and inconsistent (with joins returning Any). Here is a more abstract example: imagine arbitrary pair of types C <: B, then if meet(X, Any) = X, and meet(X | Y, Z) = meet(X, Z) | meet(Y, Z), we get a contradiction meet(C | Any, B) = meet(C, B) | meet(Any, B) = C | B = B, while by definition meet must be a subtype of both arguments. Btw @JukkaL proposed to switch meet(X, Any) from X to Any a long time ago in #3194 (comment). This may be a good argument to actually do this.

Unfortunately, switching meet(X, Any) to return Any causes 22 test failures, most of them look like something that just needs to be updated, but also there are few tests that fail because if isinstance(x, list): ... behaves differently (since in such cases both meet and Any are present). So this is not a super-easy fix as I hoped.

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-named-tuple
Projects
None yet
Development

No branches or pull requests

3 participants