-
-
Notifications
You must be signed in to change notification settings - Fork 2.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix crash on TypeGuard plus "and" #10496
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks! This looks good to me (just one comment).
I wonder if we can "leak" type guard types more generally during type checking. This could plausibly trigger some of the other visitors that we don't currently support, resulting in a crash. Can you give a link to the code where the crash happened? Maybe it's clear from the context that we won't perform arbitrary type operations on type guard types.
mypy/subtypes.py
Outdated
@@ -1374,6 +1377,10 @@ def visit_overloaded(self, left: Overloaded) -> bool: | |||
def visit_union_type(self, left: UnionType) -> bool: | |||
return all([self._is_proper_subtype(item, self.orig_right) for item in left.items]) | |||
|
|||
def visit_type_guard_type(self, left: TypeGuardType) -> bool: | |||
# TODO: What's the right thing to do here? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess since we don't expect type guard types to be used for subtype checks, we can raise an error here as well?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for reviewing! I'll make this one throw an error.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oops, that actually causes it to crash again.
File "/Users/jelle/py/mypy/mypy/checker.py", line 5232, in or_conditional_maps
result[n1] = make_simplified_union([m1[n1], m2[n2]])
File "/Users/jelle/py/mypy/mypy/typeops.py", line 370, in make_simplified_union
if i != j and is_proper_subtype(tj, ti, keep_erased_types=keep_erased) and \
File "/Users/jelle/py/mypy/mypy/subtypes.py", line 1178, in is_proper_subtype
return _is_proper_subtype(left, right,
File "/Users/jelle/py/mypy/mypy/subtypes.py", line 1199, in _is_proper_subtype
return left.accept(ProperSubtypeVisitor(orig_right,
File "/Users/jelle/py/mypy/mypy/types.py", line 290, in accept
return visitor.visit_type_guard_type(self)
File "/Users/jelle/py/mypy/mypy/subtypes.py", line 1381, in visit_type_guard_type
raise RuntimeError("TypeGuard should not be used in subtype checks")
RuntimeError: TypeGuard should not be used in subtype checks
sphinx/ext/coverage.py:212: : note: use --pdb to drop into pdb
Going to write a proper implementation instead.
The first crash was:
I first tried fixing that one with a special case in
I think the current code shouldn't let TypeGuard through in too many places because it's almost exclusively used in the binder, but fixing #10489 properly will probably involve making TypeGuard more of a real type, so it will appear in more places. I'm not proposing to do that now, but this PR will help create a foundation for that change. |
Fixes #11007, fixes #10899, fixes #10647 Since the initial implementation of TypeGuard, there have been several fixes quickly applied to make mypy not crash on various TypeGuard things. This includes #10496, #10683 and #11015. We'll discuss how this PR relates to each of these three changes. In particular, #10496 seems incorrect. As A5rocks discusses in #10899 , it introduces confusion between a type guarded variable and a TypeGuard[T]. This PR basically walks back that change entirely and renames TypeGuardType to TypeGuardedType to reduce that possible confusion. Now, we still have the issue that TypeGuardedTypes are getting everywhere and causing unhappiness. I see two high level solutions to this: a) Make TypeGuardedType a proper type, then delegate to the wrapped type in a bunch of type visitors and arbitrary amounts of other places where multiple types interact, and hope that we got all of them, b) Make TypeGuardedType as an improper type (as it was in the original implementation)! Similar to TypeAliasType, it's just a wrapper for another type, so we unwrap it in get_proper_type. This is the approach this PR takes. This might feel controversial, but I think it could be the better option. It also means that if we type check we won't get type guard crashes. #10683 is basically "remove call that leads to crash from the stacktrace". I think the join here (that ends up being with the wrapped type of the TypeGuardedType) is actually fine: if it's different, it tells us that the type changed, which is what we want to know. So seems fine to remove the special casing. Finally, #11015. This is the other contentious part of this PR. I liked the idea of moving the core "type guard overrides narrowing" idea into meet.py, so I kept that. But my changes ended up regressing a reveal_type testTypeGuardNestedRestrictionAny test that was added. But it's not really clear to me how that worked or really, what it tested. I tried writing a simpler version of what I thought the test was meant to test (this is testTypeGuardMultipleCondition added in this PR), but that fails on master. Anyway, this should at least fix the type guard crashes that have been coming up.
In python/typeshed#5473, I tried to switch a number of
inspect
functions to use the newTypeGuard
functionality. Unfortunately, mypy-primer found a number of crashes in third-party libraries in places where a TypeGuard function was ANDed together with some other check. Examples:The problems trace back to the decision in #9865 to make TypeGuardType not inherit from ProperType: in various conditions that are more complicated than a simple
if
check, mypy wants everything to become a ProperType. Therefore, to fix the crashes I had to make TypeGuardType a ProperType and support it in various visitors.