Describe the Bug
Pyrefly rejects a dispatch-on-concrete-subclass pattern that pyright (1.1.408) accepts. When a function is parameterised over a TypeVar bound to a union, narrowing the value with type(x) is C or isinstance(x, C) and returning the result of a function that takes the concrete class is reported as bad-return.
I tried findinding pre-existing issues on this, but couldn't. This is technically different from issue #2530 (which was about narrowing of plain unions, now fixed) — here the value is bound by a TypeVar.
from typing import TypeVar
class A:
pass
class B:
pass
T = TypeVar("T", bound=A | B)
def func_a(a: A) -> A:
return a
def func_b(b: B) -> B:
return b
def dispatch_with_type_is(x: T) -> T:
if type(x) is A:
return func_a(x) # pyrefly: bad-return (`A` is not assignable to `T`)
elif type(x) is B:
return func_b(x) # pyrefly: bad-return (`B` is not assignable to `T`)
raise NotImplementedError
def dispatch_with_isinstance(x: T) -> T:
if isinstance(x, A):
return func_a(x) # pyrefly: bad-return
elif isinstance(x, B):
return func_b(x) # pyrefly: bad-return
raise NotImplementedError
Pyrefly output (1.0.0)
ERROR Returned type `A` is not assignable to declared return type `T` [bad-return]
ERROR Returned type `B` is not assignable to declared return type `T` [bad-return]
ERROR Returned type `A` is not assignable to declared return type `T` [bad-return]
ERROR Returned type `B` is not assignable to declared return type `T` [bad-return]
Pyright output (1.1.408)
0 errors, 0 warnings, 0 informations
Environment
- pyrefly 1.0.0
- Python 3.12
Sandbox Link
https://pyrefly.org/sandbox/?project=N4IgZglgNgpgziAXKOBDAdgEwEYHsAeAdAA4CeSIAOumAE64C2ABAC6nEToDmTEDxuWiyYAVdjABqqWtWoBjKKjhwmAQUTUmWpsSVxZ6BXqYAhDem069BkUwC8o8VNoAKSiBHuANEzwBXLDtVJgAfUwBKA0wYMCYwALkAfVQXVEQ1cKYAWgA%2BNXNLWhgWP1oLVCiYuITE7BdsdJNM3NMC7SKSst9K2MwIOF0WOQALRIB3CBZRtmIYRP6XfHSRZryRNq0IWJmYRcz%2B-M1LduLSi3jDZL2tAGIdUiKwKFJ07FRMLI6zphcAA1VfrwVOhcMI9BAuOhUNhYKxcExfiJfpELNoYFAtqxxNcDmYjscmF8uhcknV8JkmHcyI9nq93p9Tl0-iZAQcQWDlBCoTCYHCEUiUYVUP1eQA5UEASX4sAYMHQLBgmAAorR6DJ0D0mH0BqghqMJlN5nBOHAWBg5LslqJVqINrxYv0TWbDJafKpwnbCozzjUUuTbvcaS9fPSiRrUVp0ZjHehTebXRFPSdOj7LmSKVSHjFaSGPmH8YThXAxZLpTBZfLFSq1SAvCBqdnSIQWIwoBQ7gAFLNPUhMNBYPD4JhyXA0CGlXUQUeEah3ADKMF5wxYLGIcEQAHoNw2e4RBFwN3KN5hcHI4BuR2OuBOWFP0Bu4oImKgAG7CxQ84ejyDX2iT0dMLgxC3qOcAzugZBTKOWQvjAtDGgBDjuAAzIQACMABM7jUAA2nBapwAAutQAR8AIQiKlkfRFHIt6wfYTAAORcoIMCMdQ7IMgAjn4EBFB8ADWMCkFkqByBaygMYxYzSOg7HoCAAC%2BdZiXRMAAGLQDAFD9jgBAkOQilAA
(Only applicable for extension issues) IDE Information
No response
Describe the Bug
Pyrefly rejects a dispatch-on-concrete-subclass pattern that pyright (1.1.408) accepts. When a function is parameterised over a
TypeVarbound to a union, narrowing the value withtype(x) is Corisinstance(x, C)and returning the result of a function that takes the concrete class is reported asbad-return.I tried findinding pre-existing issues on this, but couldn't. This is technically different from issue #2530 (which was about narrowing of plain unions, now fixed) — here the value is bound by a
TypeVar.Pyrefly output (1.0.0)
Pyright output (1.1.408)
Environment
Sandbox Link
https://pyrefly.org/sandbox/?project=N4IgZglgNgpgziAXKOBDAdgEwEYHsAeAdAA4CeSIAOumAE64C2ABAC6nEToDmTEDxuWiyYAVdjABqqWtWoBjKKjhwmAQUTUmWpsSVxZ6BXqYAhDem069BkUwC8o8VNoAKSiBHuANEzwBXLDtVJgAfUwBKA0wYMCYwALkAfVQXVEQ1cKYAWgA%2BNXNLWhgWP1oLVCiYuITE7BdsdJNM3NMC7SKSst9K2MwIOF0WOQALRIB3CBZRtmIYRP6XfHSRZryRNq0IWJmYRcz%2B-M1LduLSi3jDZL2tAGIdUiKwKFJ07FRMLI6zphcAA1VfrwVOhcMI9BAuOhUNhYKxcExfiJfpELNoYFAtqxxNcDmYjscmF8uhcknV8JkmHcyI9nq93p9Tl0-iZAQcQWDlBCoTCYHCEUiUYVUP1eQA5UEASX4sAYMHQLBgmAAorR6DJ0D0mH0BqghqMJlN5nBOHAWBg5LslqJVqINrxYv0TWbDJafKpwnbCozzjUUuTbvcaS9fPSiRrUVp0ZjHehTebXRFPSdOj7LmSKVSHjFaSGPmH8YThXAxZLpTBZfLFSq1SAvCBqdnSIQWIwoBQ7gAFLNPUhMNBYPD4JhyXA0CGlXUQUeEah3ADKMF5wxYLGIcEQAHoNw2e4RBFwN3KN5hcHI4BuR2OuBOWFP0Bu4oImKgAG7CxQ84ejyDX2iT0dMLgxC3qOcAzugZBTKOWQvjAtDGgBDjuAAzIQACMABM7jUAA2nBapwAAutQAR8AIQiKlkfRFHIt6wfYTAAORcoIMCMdQ7IMgAjn4EBFB8ADWMCkFkqByBaygMYxYzSOg7HoCAAC%2BdZiXRMAAGLQDAFD9jgBAkOQilAA
(Only applicable for extension issues) IDE Information
No response