Description
Bug Report
Okay so, let's say for a second you have this code:
from typing_extensions import TypeGuard
def type_guard_function(a: object) -> TypeGuard[int]:
return isinstance(a, int)
reveal_type(type_guard_function)
n: object = 5
reveal_type(n)
if type_guard_function(n):
reveal_type(n)
else:
reveal_type(n)
Now then, it turns out that in this bit:
if type_guard_function(n):
reveal_type(n)
mypy actually says n
is a TypeGuard
! If you look at ConditionalTypeBinder#frames
during the reveal_type
, you'll note a: {('Var', <mypy.nodes.Var object at 0x7f7a76e32580>): TypeGuard(builtins.int)}
.
ConditionalTypeBinder
stores types. To prove this to yourself, add a n = '5'
after n: object = 5
. You'll see a frame now looks like: {('Var', <mypy.nodes.Var object at 0x7f7a76e32580>): builtins.str}
(note that since it's the same variable, it's the same memory address :P)...
Anyways, this seems completely off, because in types.py
's TypeStrVisitor
, you have this:
def visit_type_guard_type(self, t: TypeGuardType) -> str:
return 'TypeGuard[{}]'.format(t.type_guard.accept(self))
Here are the relevant lines to the above:
- Type narrowing working around
TypeGuardType
:
Lines 4188 to 4190 in 7edcead
This is what causes reveal_type(n)
in the if statement to be int
.
- The implementation that adds
TypeGuardType
to the value in the first place:
Line 4147 in 7edcead
TypeStrVisitor#visit_type_guard_type
Lines 2197 to 2198 in 7edcead
Expected Behavior
This doesn't happen. TypeGuardType
is only for TypeGuard[T]
. Instead, there's another way to signal to type narrowing that a value became the way it is because of a type guard (necessary because of differences in behavior).
Actual Behavior
This does happen. Chaos ensues, causing things like #10647 and #10665. (confirmed this by removing relevant line number 2 and testing both -- no crashes. However, I did this as described in #10671 (comment) and well, the tests show the problem themselves.)
Your Environment
The source code.
I was redirected here by the contributing document, as this is a moderate (I think?) effort change, and I have no clue what exactly should change. Like, should type guarded values use their own ProperType? Should there be a bool flag somewhere? No clue.
Full disclaimer that I probably messed a few things up in my explanation, and that I may have misspoken a few terms. Hopefully I'm wrong and this isn't actually an issue 😰 .