Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions mypy/semanal.py
Original file line number Diff line number Diff line change
Expand Up @@ -5094,6 +5094,7 @@ def check_classvar(self, s: AssignmentStmt) -> None:
return
if not s.type or not self.is_classvar(s.type):
return
assert isinstance(s.type, UnboundType)
if self.is_class_scope() and isinstance(lvalue, NameExpr):
node = lvalue.node
if isinstance(node, Var):
Expand All @@ -5110,6 +5111,12 @@ def check_classvar(self, s: AssignmentStmt) -> None:
# In case of member access, report error only when assigning to self
# Other kinds of member assignments should be already reported
self.fail_invalid_classvar(lvalue)
if not s.type.args:
if isinstance(s.rvalue, TempNode) and s.rvalue.no_rhs:
if self.options.disallow_any_generics:
self.fail("ClassVar without type argument becomes Any", s, code=codes.TYPE_ARG)
return
s.type = None

def is_classvar(self, typ: Type) -> bool:
if not isinstance(typ, UnboundType):
Expand Down
20 changes: 20 additions & 0 deletions test-data/unit/check-classvar.test
Original file line number Diff line number Diff line change
Expand Up @@ -360,3 +360,23 @@ reveal_type(C.x) # E: Access to generic instance variables via class is ambiguo
# N: Revealed type is "Any"
reveal_type(C.y) # E: Access to generic class variables is ambiguous \
# N: Revealed type is "Any"

[case testClassVarBareAnnotation]
from typing import ClassVar

class C:
x: ClassVar = 1
y: ClassVar
Copy link
Collaborator

Choose a reason for hiding this comment

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

Okay, can we reject at least this in --disallow-any-generics fashion? Doesn't look like something I want to see in typed code silently...

Copy link
Member Author

Choose a reason for hiding this comment

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

Yeah, good point. We should reject this with --disallow-any-generics.


reveal_type(C.x) # N: Revealed type is "builtins.int"
reveal_type(C().x) # N: Revealed type is "builtins.int"
reveal_type(C.y) # N: Revealed type is "Any"
reveal_type(C().y) # N: Revealed type is "Any"

[case testClassVarBareAnnotationDisabled]
# flags: --disallow-any-generics
from typing import ClassVar

class C:
x: ClassVar = 1
y: ClassVar # E: ClassVar without type argument becomes Any
2 changes: 1 addition & 1 deletion test-data/unit/check-incremental.test
Original file line number Diff line number Diff line change
Expand Up @@ -2051,7 +2051,7 @@ warn_no_return = True
[case testIncrementalClassVar]
from typing import ClassVar
class A:
x = None # type: ClassVar
x: ClassVar
A().x = 0
[out1]
main:4: error: Cannot assign to class variable "x" via instance
Expand Down
2 changes: 1 addition & 1 deletion test-data/unit/semanal-classvar.test
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ MypyFile:1(
AssignmentStmt:3(
NameExpr(x [m])
IntExpr(1)
Any)))
builtins.int)))

[case testClassVarWithTypeVar]

Expand Down
Loading