[red-knot] Attribute access on intersection types#16665
Conversation
| reveal_type(a_and_b.x) # revealed: int | ||
|
|
||
| # Same for class objects | ||
| def _(a_and_b: Intersection[type[A], type[B]]): |
There was a problem hiding this comment.
I wonder if we should allow type[Intersection[A, B]] in type expressions, as a shorthand for Intersection[type[A], type[B]]. We already allow (and it's mandated by the spec) type[A | B] and type[Union[A, B]] as shorthands for type[A] | type[B].
Obviously doesn't need to be done in this PR, though
|
| x: Q = Q() | ||
|
|
||
| def _(a_and_b: Intersection[A, B]): | ||
| reveal_type(a_and_b.x) # revealed: P & Q |
There was a problem hiding this comment.
Again, not something for this PR necessarily. But I think that this implies that we should infer the following case like so:
@final
class A: ...
class B: ...
class C:
x: A
class D:
x: B
def f(y: C):
if isinstance(y, D):
reveal_type(y) # revealed: NeverBecause we know that all instances of C have an x attribute, but the inferred type of the x attribute on the y variable would be A & B, which simplifies to Never, since A is @final. An inferred attribute type of Never for the x attribute is the same thing as saying that y cannot have an attribute x in this branch, but we already established that y must have an x attribute, since y is an instance of C. The only way to solve this contradiction is to say that this branch is in fact unreachable: C & D must simplify to Never due to the fact that A & B simplifies to Never.
This is perhaps quite a long-winded proof for something that is self-evident...! I think mypy and pyright might also infer unreachable code in cases like this
There was a problem hiding this comment.
We already (with this PR) correctly infer the type of y.x as Never in your example.
I think it is also correct to go from that to inferring C & D itself as Never, but this could be quite expensive to implement (since it would require checking every attribute of any pair of types that end up in an intersection together), and it's not clear to me how necessary/valuable it will be in practice.
There was a problem hiding this comment.
We already (with this PR) correctly infer the type of
y.xasNeverin your example.
I know; it was the further inference that I was attempting to discuss.
Anyway, I agree that we can defer this for now and see how expensive and/or useful it is later!
| x: Q = Q() | ||
|
|
||
| def _(a_and_b: Intersection[A, B]): | ||
| reveal_type(a_and_b.x) # revealed: P & Q |
There was a problem hiding this comment.
We already (with this PR) correctly infer the type of y.x as Never in your example.
I think it is also correct to go from that to inferring C & D itself as Never, but this could be quite expensive to implement (since it would require checking every attribute of any pair of types that end up in an intersection together), and it's not clear to me how necessary/valuable it will be in practice.
|
(mypy-primer changes look correct) |
Summary
Implements attribute access on intersection types, which didn't previously work. For example:
Refers to this comment.
Test Plan
New Markdown tests