Consider this example where we currently emit a false positive.
from typing import Self
from enum import Enum
class Answer(Enum):
YES = "yes"
NO = "no"
def is_yes(self: Self) -> bool: # ty: Function can implicitly return `None`, which is not assignable to return type `bool`
match self:
case Answer.YES:
return True
case Answer.NO:
return False
When the annotation is changed to self: Answer, everything works as expected. But we do not recognize that Self@is_yes with an upper bound of Answer can be narrowed down.
Similar problems certainly exist for other final types and other narrowing patterns.
It seems like we can generally simplify a non-inferable typevar T with a final upper bound F to that upper bound F? Or let T share more properties of F (like whether or not we consider it to be final).
Consider this example where we currently emit a false positive.
When the annotation is changed to
self: Answer, everything works as expected. But we do not recognize thatSelf@is_yeswith an upper bound ofAnswercan be narrowed down.Similar problems certainly exist for other final types and other narrowing patterns.
It seems like we can generally simplify a non-inferable typevar
Twith afinalupper boundFto that upper boundF? Or letTshare more properties ofF(like whether or not we consider it to befinal).