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

Self type of ClassVar lost through TypeVar #17395

Closed
asottile-sentry opened this issue Jun 17, 2024 · 2 comments
Closed

Self type of ClassVar lost through TypeVar #17395

asottile-sentry opened this issue Jun 17, 2024 · 2 comments
Labels
bug mypy got something wrong

Comments

@asottile-sentry
Copy link

this is very similar to #16826 but appears to be slightly different

Bug Report

Self appears to be decaying to the TypeVar bound instead of the TypeVar itself. my specific example looks similar to django models construction but is isolated from django-stubs itself to make a minimal reproduction

it works great for the subclass (as demonstrated by the first reveal_type) -- just not for the TypeVar

To Reproduce

from typing import TypeVar, Generic, ClassVar, Self

M = TypeVar("M", bound="B", covariant=True)

class Related(Generic[M]):
    def get(self) -> M:
        raise NotImplementedError

class B:
    objects: ClassVar[Related[Self]] = Related()

class C(B):
    pass

reveal_type(C.objects)

def of_m(cls: type[M]) -> M:
    return cls.objects.get()

Expected Behavior

(no errors)

Actual Behavior

t.py:15: note: Revealed type is "t.Related[t.C]"
t.py:18: error: Incompatible return value type (got "B", expected "M")  [return-value]
Found 1 error in 1 file (checked 1 source file)

Your Environment

  • Mypy version used: 1.10.0
  • Mypy command-line flags: (none)
  • Mypy configuration options from mypy.ini (and other config files): (n/a)
  • Python version used: 3.12.2
@asottile-sentry asottile-sentry added the bug mypy got something wrong label Jun 17, 2024
@asottile-sentry
Copy link
Author

this seems to make this particular example work -- and passes the existing tests

diff --git a/mypy/checkmember.py b/mypy/checkmember.py
index 7525db2..2ed9af1 100644
--- a/mypy/checkmember.py
+++ b/mypy/checkmember.py
@@ -1064,7 +1064,13 @@ def analyze_class_attribute_access(
             # In the above example this means that we infer following types:
             #     C.x -> Any
             #     C[int].x -> int
-            t = get_proper_type(expand_self_type(node.node, t, itype))
+            if isinstance(mx.self_type, CallableType):
+                self_type = mx.self_type.ret_type
+            elif isinstance(mx.self_type, TypeType):
+                self_type = mx.self_type.item
+            else:
+                self_type = itype
+            t = get_proper_type(expand_self_type(node.node, t, self_type))
             t = erase_typevars(expand_type_by_instance(t, isuper), {tv.id for tv in def_vars})
 
         is_classmethod = (is_decorated and cast(Decorator, node.node).func.is_class) or (

@asottile
Copy link
Contributor

via ba5c279

asottile-sentry added a commit to getsentry/sentry that referenced this issue Jun 18, 2024
…72877)

fortunately there's enough plugin hooks that we can work around
python/mypy#17395

<!-- Describe your PR here. -->
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug mypy got something wrong
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants