[ty] Bind typing.Self in class attributes and assignment#23108
[ty] Bind typing.Self in class attributes and assignment#23108
typing.Self in class attributes and assignment#23108Conversation
Typing conformance results improved 🎉The percentage of diagnostics emitted that were expected errors increased from 82.63% to 83.14%. The percentage of expected errors that received a diagnostic held steady at 74.24%. Summary
False positives removedDetails
|
|
Merging this PR will not alter performance
Comparing Footnotes
|
|
| Lint rule | Added | Removed | Changed |
|---|---|---|---|
unresolved-attribute |
934 | 16 | 7 |
invalid-argument-type |
15 | 70 | 19 |
possibly-missing-attribute |
58 | 13 | 0 |
invalid-return-type |
2 | 41 | 3 |
invalid-assignment |
2 | 22 | 10 |
invalid-type-form |
33 | 0 | 0 |
invalid-type-arguments |
0 | 18 | 0 |
unused-type-ignore-comment |
0 | 3 | 0 |
redundant-cast |
2 | 0 | 0 |
| Total | 1,046 | 183 | 39 |
1019f08 to
c086f6f
Compare
typing.Self in class attributes and assignmenttyping.Self in class attributes and assignment
|
Just adding a note that the 992 new false positives on zulip are due to missing django support. |
sharkdp
left a comment
There was a problem hiding this comment.
Finishing my first review here, as I would first like to understand if we really need the supports_self_binding filtering.
|
For completeness: I also had #22487 which was written by Claude and iterated-on over the course of a few days, but I found it hard to understand and this is my attempt to simplify the solution. |
e3d8129 to
2c9e780
Compare
sharkdp
left a comment
There was a problem hiding this comment.
I have some more questions, but the general direction definitely looks good — thank you for the updates.
| self_typevar_owner_class_literal(db, other), | ||
| ) { | ||
| return left == right && self.paramspec_attr(db) == other.paramspec_attr(db); | ||
| } |
There was a problem hiding this comment.
With this change, we will now also consider Self@method1 and Self@method2 the same typevar. Can this cause any problems?
There was a problem hiding this comment.
I think this is correct, e.g. given:
class Foo:
def method1(self) -> Self: ...
def method2(self) -> Self: ...
def combined(self) -> Self:
if condition:
return self.method1() # Self@method1
else:
return self.method2() # Self@method2You want Self@method1 | Self@method2 to simplify to Self.
There was a problem hiding this comment.
I don't think we generate the type Self@method1 | Self@method2 here. Inferring the type for self.method1() will already bind Self@method1 and return Foo. This code works fine on main.
Interested in @dcreager's opinion here.
There was a problem hiding this comment.
(Increasingly think you're right, and that this was introduced in a prior iteration but subsequently made redundant. Going to try removing.)
There was a problem hiding this comment.
Looks like it works, cool! In that case — no dcreager opinion needed 😄. Let's merge!
75c5ea3 to
58faf6f
Compare
Memory usage reportSummary
Significant changesClick to expand detailed breakdownprefect
sphinx
trio
flake8
|
f42072c to
4e48939
Compare
4e48939 to
4d8f4e0
Compare
| class Linkable(Protocol): | ||
| next_node: Self | ||
|
|
||
| def advance(self) -> Self: | ||
| return self.next_node |
There was a problem hiding this comment.
This passes on main as well. But if you try to access the attribute like this:
def _(linkable: Linkable):
reveal_type(linkable.next_node)we get @Todo(type[T] for protocols). We don't have to fix this TODO here, but I'm a bit surprised that other attributes can be accessed without problems (see below), so this might be worth investigating?
class Linkable(Protocol):
next_node: Self
other_attribute: int
def _(linkable: Linkable):
reveal_type(linkable.next_node) # revealed: @Todo(type[T] for protocols)
reveal_type(linkable.other_attribute) # revealed: intI think we should add a test like
| class Linkable(Protocol): | |
| next_node: Self | |
| def advance(self) -> Self: | |
| return self.next_node | |
| class Linkable(Protocol): | |
| next_node: Self | |
| def advance(self) -> Self: | |
| return self.next_node | |
| def _(l: Linkable) -> None: | |
| # TODO: Should be `Linkable` | |
| reveal_type(l.next_node) # revealed: @Todo(type[T] for protocols) |
| self_typevar_owner_class_literal(db, other), | ||
| ) { | ||
| return left == right && self.paramspec_attr(db) == other.paramspec_attr(db); | ||
| } |
There was a problem hiding this comment.
I don't think we generate the type Self@method1 | Self@method2 here. Inferring the type for self.method1() will already bind Self@method1 and return Foo. This code works fine on main.
Interested in @dcreager's opinion here.
4d8f4e0 to
d883f6b
Compare
Summary
Closes astral-sh/ty#1124.