You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
generic is incorrectly inferred as invariant if class uses Self type on an attribute #18334
fromtypingimportSelfclassFoo[T]:
instance: Self# commenting out this line makes the error go awaydeffoo(self) ->T: ... # type:ignore[empty-body]classBar(Foo[int]): ...
# Incompatible types in assignment (expression has type "Bar", variable has type "Foo[object]") [assignment]foo: Foo[object] =Bar()
changed the title [-]generic is incorrectly inferred as invariant if class uess `Self` type on an attribute[/-][+]generic is incorrectly inferred as invariant if class uses `Self` type on an attribute[/+]on Dec 24, 2024
This is a well known unsafety of self-types. In fact, essentially same problem existed long before Self notation was even introduced, for example this is unsafe:
Most (if not all) false negatives with self types boil down to this hole in type system. However, the current consensus is that it is impossible to fix it without making self-types a pain to work with.
i've found that there is no downside to adding new diagnostic rules for stuff like this, because users who want the additional safety can benefit from them, but users who think it would make self-types a pain to work with can just keep those rules disabled.
Yeah, adding a new flag (or if possible an error code) may be a solution. This still however requires some discussions on exact semantics. Also to give correct expectations: since this hole causes (surprisingly) few problems in real-world code, fixing this is not high priority.
If you are interested in this, I guess #15619 may be a better place to continue discussion.
Mypy seems to assume that Self is class-scoped. It isn't; Self is method- or property-scoped. So Self cannot influence the (variance of) class-scoped type parameters.
Mypy seems to assume that Self is class-scoped. It isn't; Self is method- or property-scoped. So Self cannot influence the (variance of) class-scoped type parameters.
Wouldn't this mean that ClassVar[Self] is illegal? This is actually part of the test-suite. Your comment also gave me the idea to try the following, since mypy sometimes treat an annotation inside __init__ differently than an annotation inside the class-body.1 This led to an odd result playground
fromtypingimportSelfclassFoo:
def__init__(self) ->None:
self.instance: Self=self# main.py:5: error: Incompatible types in assignment (expression has type "Foo", variable has type "Self") [assignment]
Footnotes
as an annotated attribute inside the class body can be a class- or instance-attribute whereas a self.attr annotated inside __init__ is always treated as an instance-only attribute. Though I sometimes wish that were the default for everything that's not explicitly marked as ClassVar. ↩
Wouldn't this mean that ClassVar[Self] is illegal?
Although not explicitly stated in the typing spec, it would be legal if you think of class-attributes as a "classproperty", i.e. a @property + @classmethod, analogous to instance attributes -> @property
Activity
[-]generic is incorrectly inferred as invariant if class uess `Self` type on an attribute[/-][+]generic is incorrectly inferred as invariant if class uses `Self` type on an attribute[/+]ilevkivskyi commentedon Oct 15, 2025
is invariant for the same reason
is invariant:
instsanceis a settable attribute. So this is actually true positive.DetachHead commentedon Oct 16, 2025
hmm interesting. here's a simplified example that mypy doesn't catch:
playground
ilevkivskyi commentedon Oct 16, 2025
This is a well known unsafety of self-types. In fact, essentially same problem existed long before
Selfnotation was even introduced, for example this is unsafe:Most (if not all) false negatives with self types boil down to this hole in type system. However, the current consensus is that it is impossible to fix it without making self-types a pain to work with.
DetachHead commentedon Oct 16, 2025
my proposed solution is to add new rules to:
Selffrom being used in a contravariant position (except for theselfparameter on instance methods) (Selfshould not be allowed in a contravariant position DetachHead/basedpyright#1586)i've found that there is no downside to adding new diagnostic rules for stuff like this, because users who want the additional safety can benefit from them, but users who think it would make self-types a pain to work with can just keep those rules disabled.
ilevkivskyi commentedon Oct 16, 2025
Yeah, adding a new flag (or if possible an error code) may be a solution. This still however requires some discussions on exact semantics. Also to give correct expectations: since this hole causes (surprisingly) few problems in real-world code, fixing this is not high priority.
If you are interested in this, I guess #15619 may be a better place to continue discussion.
KotlinIsland commentedon Oct 16, 2025
KotlinIsland commentedon Oct 16, 2025
why is there no error here then?
what exactly does this help with? making it invariant because of
Selfusage doesn't prevent any invalid usagesjorenham commentedon Oct 17, 2025
From the typing spec:
The code above is semantically equivalent to treating each attribute containing a
Selftype as apropertythat returns that type:So the example in the OP is specified to be equivalent to:
Mypy seems to assume that
Selfis class-scoped. It isn't;Selfis method- or property-scoped. SoSelfcannot influence the (variance of) class-scoped type parameters.randolf-scholz commentedon Oct 27, 2025
Wouldn't this mean that
ClassVar[Self]is illegal? This is actually part of the test-suite. Your comment also gave me the idea to try the following, sincemypysometimes treat an annotation inside__init__differently than an annotation inside the class-body.1 This led to an odd result playgroundFootnotes
as an annotated attribute inside the class body can be a class- or instance-attribute whereas a
self.attrannotated inside__init__is always treated as an instance-only attribute. Though I sometimes wish that were the default for everything that's not explicitly marked asClassVar. ↩jorenham commentedon Oct 27, 2025
Although not explicitly stated in the typing spec, it would be legal if you think of class-attributes as a "classproperty", i.e. a
@property+@classmethod, analogous to instance attributes ->@property