-
-
Notifications
You must be signed in to change notification settings - Fork 2.9k
Internal error with TypeGuard and Literal-based union narrowing using StrEnum #18895
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
Comments
master traceback:
|
This minimal patch should prevent crashing due to
Note that |
Hmm, I notice that if both typeguards use literals (instead of one using a union of literals), then we don't even put a union of Is having a union-of- |
Hm, transposing a union-of-guards into guard-of-union sounds reasonable too. In the linked PR I settled on a slightly different approach, not as in the patch above: I propose to keep narrowing union members even for enum/literal-union overlap - why should cf. playground from enum import Enum
from typing_extensions import TypeIs, Literal
class Model(str, Enum):
A = 'a'
B = 'a'
def is_model_a(model: str) -> TypeIs[Literal[Model.A, "foo"]]:
return True
def handle(model: Model) -> None:
if is_model_a(model):
reveal_type(model) # N: Revealed type is "Union[Literal[__main__.Model.A], Literal['foo']]"
def is_int_or_list(model: object) -> TypeIs[int | list[int]]:
return True
def compare(x: int | str) -> None:
if is_int_or_list(x):
reveal_type(x) # N: Revealed type is "builtins.int" (yes, I can't invent a simpler test to show On my PR |
…apping with enum (#18897) Fixes #18895. The original implementation of that block was introduced as a performance optimization in #12032. It's in fact incorrect: it produces overly optimistic meets, assuming that *any* match among union items makes them *all* relevant. As discussed in #18895, this actually results in unexpected `meet` behaviour, as demonstrated by ```python from enum import Enum from typing_extensions import TypeIs, Literal class Model(str, Enum): A = 'a' B = 'a' def is_model_a(model: str) -> TypeIs[Literal[Model.A, "foo"]]: return True def handle(model: Model) -> None: if is_model_a(model): reveal_type(model) # N: Revealed type is "Union[Literal[__main__.Model.A], Literal['foo']]" def is_int_or_list(model: object) -> TypeIs[int | list[int]]: return True def compare(x: int | str) -> None: if is_int_or_list(x): reveal_type(x) # N: Revealed type is "builtins.int" ``` This patch restores filtering of union members, but keeps it running before the expensive `is_overlapping_types` check involving expansion.
Crash Report
When using TypeGuard to narrow a Literal-based union from a StrEnum, mypy raises an internal error.
I found a workaround, but I prefer my first implementation as it is more concise.
Traceback
To Reproduce
Your Environment
mypy.ini
(and other config files):The text was updated successfully, but these errors were encountered: