fromtypingimportLiteral, overrideclassFoo:
@overridedef__eq__(self, value: object, /) ->bool:
returnTruedeffun(a: Foo|Literal["a"]) ->None:
ifa=="a":
reveal_type(a) # Foo | Literal['a']else:
reveal_type(a) # Foo | Literal['a']
playground
in this case, it's safe to narrow to Foo in the else block, because the Literal["a"] cannot have a custom __eq__. this means if a == "a" returns False, there's no chance that a is a Literal["a"], but if it returns True then it's still possible for it to be a Foo because of the Foo.__eq__.
therefore, the narrowing should work like this:
deffun(a: Foo|Literal["a"]) ->None:
ifa=="a":
reveal_type(a) # Foo | Literal['a']else:
reveal_type(a) # Foo
this would also be consistent with pyright's behavior: playground
playground
in this case, it's safe to narrow to
Fooin theelseblock, because theLiteral["a"]cannot have a custom__eq__. this means ifa == "a"returnsFalse, there's no chance thatais aLiteral["a"], but if it returnsTruethen it's still possible for it to be aFoobecause of theFoo.__eq__.therefore, the narrowing should work like this:
this would also be consistent with pyright's behavior: playground