Skip to content

Conversation

@asukaminato0721
Copy link
Contributor

Summary

Fixes #1422

Adjusted constrained TypeVar handling so return checks accept any constraint and missing-return is suppressed when an isinstance chain covers all constraints, then added a regression test and updated expectations.

Updated constrained TypeVar subtyping to accept any matching constraint.

Added a conservative exhaustive-isinstance check for constrained TypeVar parameters to avoid false missing-return errors.

Test Plan

Added a new return regression test and removed the now-obsolete return-type error expectation.

@meta-cla meta-cla bot added the cla signed label Dec 30, 2025
@github-actions

This comment has been minimized.

@asukaminato0721 asukaminato0721 marked this pull request as ready for review December 30, 2025 20:39
Copilot AI review requested due to automatic review settings December 30, 2025 20:39
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR fixes issue #1422 by correctly handling constrained TypeVars in return type checking and missing-return analysis. The key change is recognizing that a constrained TypeVar T = TypeVar("T", int, str) can be satisfied by any of its constraints (not all), and that isinstance chains covering all constraints constitute exhaustive checking.

  • Updated subset checking to accept any matching constraint for constrained TypeVars
  • Added exhaustive isinstance chain detection to suppress false missing-return errors when all constraints are covered
  • Added regression test for constrained TypeVar with isinstance chain

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated no comments.

File Description
pyrefly/lib/solver/subset.rs Changed constrained TypeVar subtype checking from all to any to correctly handle constraint matching
pyrefly/lib/binding/function.rs Added isinstance chain analysis for constrained TypeVars to detect exhaustive type checking patterns
pyrefly/lib/test/returns.rs Added regression test for constrained TypeVar with exhaustive isinstance chain
pyrefly/lib/test/generic_restrictions.rs Removed now-incorrect return type error expectation due to fixed constraint checking

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@github-actions

This comment has been minimized.

1 similar comment
@github-actions

This comment has been minimized.

.
.
@github-actions
Copy link

Diff from mypy_primer, showing the effect of this PR on open source code:

prefect (https://github.com/PrefectHQ/prefect)
- ERROR src/prefect/utilities/templating.py:199:36-68: `str` is not assignable to variable `template` with type `T` [bad-assignment]
- ERROR src/prefect/utilities/templating.py:201:32-72: `str` is not assignable to variable `template` with type `T` [bad-assignment]
- ERROR src/prefect/utilities/templating.py:323:16-328:10: Returned type `list[dict[str, Any] | Unknown]` is not assignable to declared return type `dict[str, Any] | T` [bad-return]
- ERROR src/prefect/utilities/templating.py:423:24-26: Returned type `Literal['']` is not assignable to declared return type `T` [bad-return]
- ERROR src/prefect/utilities/templating.py:432:36-68: `str` is not assignable to variable `template` with type `T` [bad-assignment]
- ERROR src/prefect/utilities/templating.py:434:36-85: `str` is not assignable to variable `template` with type `T` [bad-assignment]
- ERROR src/prefect/utilities/templating.py:437:16-440:10: Returned type `dict[Unknown, Unknown]` is not assignable to declared return type `T` [bad-return]
- ERROR src/prefect/utilities/templating.py:442:16-83: Returned type `list[Unknown]` is not assignable to declared return type `T` [bad-return]
- ::error file=src/prefect/utilities/templating.py,line=199,col=36,endLine=199,endColumn=68,title=Pyrefly bad-assignment::`str` is not assignable to variable `template` with type `T`
- ::error file=src/prefect/utilities/templating.py,line=201,col=32,endLine=201,endColumn=72,title=Pyrefly bad-assignment::`str` is not assignable to variable `template` with type `T`
- ::error file=src/prefect/utilities/templating.py,line=323,col=16,endLine=328,endColumn=10,title=Pyrefly bad-return::Returned type `list[dict[str, Any] | Unknown]` is not assignable to declared return type `dict[str, Any] | T`
- ::error file=src/prefect/utilities/templating.py,line=423,col=24,endLine=423,endColumn=26,title=Pyrefly bad-return::Returned type `Literal['']` is not assignable to declared return type `T`
- ::error file=src/prefect/utilities/templating.py,line=432,col=36,endLine=432,endColumn=68,title=Pyrefly bad-assignment::`str` is not assignable to variable `template` with type `T`
- ::error file=src/prefect/utilities/templating.py,line=434,col=36,endLine=434,endColumn=85,title=Pyrefly bad-assignment::`str` is not assignable to variable `template` with type `T`
- ::error file=src/prefect/utilities/templating.py,line=437,col=16,endLine=440,endColumn=10,title=Pyrefly bad-return::Returned type `dict[Unknown, Unknown]` is not assignable to declared return type `T`
- ::error file=src/prefect/utilities/templating.py,line=442,col=16,endLine=442,endColumn=83,title=Pyrefly bad-return::Returned type `list[Unknown]` is not assignable to declared return type `T`

zulip (https://github.com/zulip/zulip)
- ERROR zerver/lib/queue.py:109:17-25: Argument `(ChannelT, Basic.Deliver, BasicProperties, bytes) -> None` is not assignable to parameter `on_message_callback` with type `(Channel, Basic.Deliver, BasicProperties, bytes) -> object` in function `pika.channel.Channel.basic_consume` [bad-argument-type]
- ::error file=zerver/lib/queue.py,line=109,col=17,endLine=109,endColumn=25,title=Pyrefly bad-argument-type::Argument `(ChannelT, Basic.Deliver, BasicProperties, bytes) -> None` is not assignable to parameter `on_message_callback` with type `(Channel, Basic.Deliver, BasicProperties, bytes) -> object` in function `pika.channel.Channel.basic_consume`

pyodide (https://github.com/pyodide/pyodide)
- ERROR src/tests/test_static_typing.py:56:20-25: Returned type `float | int | str` is not assignable to declared return type `T` [bad-return]
- ::error file=src/tests/test_static_typing.py,line=56,col=20,endLine=56,endColumn=25,title=Pyrefly bad-return::Returned type `float | int | str` is not assignable to declared return type `T`

pytest (https://github.com/pytest-dev/pytest)
- ERROR src/_pytest/capture.py:948:13-31: `bytes | Unknown` is not assignable to attribute `_captured_out` with type `AnyStr` [bad-assignment]
- ERROR src/_pytest/capture.py:949:13-31: `bytes | Unknown` is not assignable to attribute `_captured_err` with type `AnyStr` [bad-assignment]
- ERROR src/_pytest/capture.py:968:30-42: Argument `bytes | AnyStr | Unknown` is not assignable to parameter `out` with type `AnyStr` in function `CaptureResult.__new__` [bad-argument-type]
- ERROR src/_pytest/capture.py:968:44-56: Argument `bytes | AnyStr | Unknown` is not assignable to parameter `err` with type `AnyStr` in function `CaptureResult.__new__` [bad-argument-type]
- ::error file=src/_pytest/capture.py,line=948,col=13,endLine=948,endColumn=31,title=Pyrefly bad-assignment::`bytes | Unknown` is not assignable to attribute `_captured_out` with type `AnyStr`
- ::error file=src/_pytest/capture.py,line=949,col=13,endLine=949,endColumn=31,title=Pyrefly bad-assignment::`bytes | Unknown` is not assignable to attribute `_captured_err` with type `AnyStr`
- ::error file=src/_pytest/capture.py,line=968,col=30,endLine=968,endColumn=42,title=Pyrefly bad-argument-type::Argument `bytes | AnyStr | Unknown` is not assignable to parameter `out` with type `AnyStr` in function `CaptureResult.__new__`
- ::error file=src/_pytest/capture.py,line=968,col=44,endLine=968,endColumn=56,title=Pyrefly bad-argument-type::Argument `bytes | AnyStr | Unknown` is not assignable to parameter `err` with type `AnyStr` in function `CaptureResult.__new__`

dulwich (https://github.com/dulwich/dulwich)
- ERROR dulwich/objects.py:243:16-22: Returned type `str` is not assignable to declared return type `PathT` [bad-return]
- ERROR dulwich/objects.py:254:16-24: Returned type `bytes` is not assignable to declared return type `PathT` [bad-return]
- ERROR dulwich/refs.py:1992:12-20: Returned type `dict[Ref, ObjectID | None]` is not assignable to declared return type `T` [bad-return]
- ::error file=dulwich/objects.py,line=243,col=16,endLine=243,endColumn=22,title=Pyrefly bad-return::Returned type `str` is not assignable to declared return type `PathT`
- ::error file=dulwich/objects.py,line=254,col=16,endLine=254,endColumn=24,title=Pyrefly bad-return::Returned type `bytes` is not assignable to declared return type `PathT`
- ::error file=dulwich/refs.py,line=1992,col=12,endLine=1992,endColumn=20,title=Pyrefly bad-return::Returned type `dict[Ref, ObjectID | None]` is not assignable to declared return type `T`

xarray (https://github.com/pydata/xarray)
- ERROR xarray/computation/rolling.py:1216:20-55: Returned type `DataArray` is not assignable to declared return type `T_Xarray` [bad-return]
- ERROR xarray/computation/rolling.py:1218:20-26: Returned type `Dataset` is not assignable to declared return type `T_Xarray` [bad-return]
- ERROR xarray/core/dtypes.py:108:12-33: Returned type `tuple[dtype[Any], Unknown]` is not assignable to declared return type `tuple[T_dtype, Any]` [bad-return]
+ ERROR xarray/core/dtypes.py:107:33-43: Argument `complex | datetime64[None] | float | timedelta64[str]` is not assignable to parameter `value` with type `SupportsFloat | SupportsIndex | bytes | str | None` in function `numpy.floating.__new__` [bad-argument-type]
- ERROR xarray/core/groupby.py:1204:16-22: Returned type `Dataset` is not assignable to declared return type `T_Xarray` [bad-return]
- ::error file=xarray/computation/rolling.py,line=1216,col=20,endLine=1216,endColumn=55,title=Pyrefly bad-return::Returned type `DataArray` is not assignable to declared return type `T_Xarray`
- ::error file=xarray/computation/rolling.py,line=1218,col=20,endLine=1218,endColumn=26,title=Pyrefly bad-return::Returned type `Dataset` is not assignable to declared return type `T_Xarray`
- ::error file=xarray/core/dtypes.py,line=108,col=12,endLine=108,endColumn=33,title=Pyrefly bad-return::Returned type `tuple[dtype[Any], Unknown]` is not assignable to declared return type `tuple[T_dtype, Any]`
+ ::error file=xarray/core/dtypes.py,line=107,col=33,endLine=107,endColumn=43,title=Pyrefly bad-argument-type::Argument `complex | datetime64[None] | float | timedelta64[str]` is not assignable to parameter `value` with type `SupportsFloat | SupportsIndex | bytes | str | None` in function `numpy.floating.__new__`
- ::error file=xarray/core/groupby.py,line=1204,col=16,endLine=1204,endColumn=22,title=Pyrefly bad-return::Returned type `Dataset` is not assignable to declared return type `T_Xarray`

hydpy (https://github.com/hydpy-dev/hydpy)
- ERROR hydpy/core/devicetools.py:2541:20-79: Returned type `tuple[(int & t) | (str & t) | None, (int & t) | (str & t) | None] | tuple[t | None, t | None] | t` is not assignable to declared return type `tuple[t | None, t | None]` [bad-return]
+ ERROR hydpy/core/devicetools.py:2541:20-79: Returned type `tuple[int | str | None, int | str | None] | tuple[t | None, t | None] | t` is not assignable to declared return type `tuple[t | None, t | None]` [bad-return]
- ERROR hydpy/core/devicetools.py:2724:20-79: Returned type `tuple[(int & t) | (str & t) | None, (int & t) | (str & t) | None] | tuple[t | None, t | None] | t` is not assignable to declared return type `tuple[t | None, t | None]` [bad-return]
+ ERROR hydpy/core/devicetools.py:2724:20-79: Returned type `tuple[int | str | None, int | str | None] | tuple[t | None, t | None] | t` is not assignable to declared return type `tuple[t | None, t | None]` [bad-return]
+ ERROR hydpy/core/importtools.py:796:32-65: No matching overload found for function `SubmodelAdder.update` called with arguments: (TM_contra, TI_contra, refresh=Literal[False]) [no-matching-overload]
+ ERROR hydpy/core/importtools.py:799:32-84: No matching overload found for function `SubmodelAdder.update` called with arguments: (TM_contra, TI_contra, position=int, refresh=Literal[False]) [no-matching-overload]
+ ERROR hydpy/core/importtools.py:949:29-31: No matching overload found for function `SubmodelAdder.get_wrapped` called with arguments: () [no-matching-overload]
+ ERROR hydpy/core/importtools.py:952:29-31: No matching overload found for function `SubmodelAdder.get_wrapped` called with arguments: () [no-matching-overload]
- ERROR hydpy/core/parametertools.py:1540:20-49: Returned type `float | ndarray[tuple[Any, ...], dtype[float64]]` is not assignable to declared return type `ArrayFloat` [bad-return]
- ERROR hydpy/core/parametertools.py:1542:20-49: Returned type `float | ndarray[tuple[Any, ...], dtype[float64]]` is not assignable to declared return type `ArrayFloat` [bad-return]
- ERROR hydpy/core/parametertools.py:1569:20-49: Returned type `float | ndarray[tuple[Any, ...], dtype[float64]]` is not assignable to declared return type `ArrayFloat` [bad-return]
- ERROR hydpy/core/parametertools.py:1571:20-49: Returned type `float | ndarray[tuple[Any, ...], dtype[float64]]` is not assignable to declared return type `ArrayFloat` [bad-return]
- ERROR hydpy/core/selectiontools.py:715:20-43: Returned type `Node` is not assignable to declared return type `TypeNodeElement` [bad-return]
- ERROR hydpy/core/selectiontools.py:717:20-46: Returned type `Element` is not assignable to declared return type `TypeNodeElement` [bad-return]
- ERROR hydpy/exe/xmltools.py:1868:45-53: Expected class object, got `type[ChangeItem & _TypeGetOrChangeItem]` [invalid-argument]
- ERROR hydpy/exe/xmltools.py:1868:45-53: Expected class object, got `type[GetItem & _TypeGetOrChangeItem]` [invalid-argument]
- ERROR hydpy/exe/xmltools.py:1869:34-38: Argument `ExchangeItem` is not assignable to parameter `object` with type `_TypeGetOrChangeItem` in function `list.append` [bad-argument-type]
- ERROR hydpy/exe/xmltools.py:1873:49-57: Expected class object, got `type[ChangeItem & _TypeGetOrChangeItem]` [invalid-argument]
- ERROR hydpy/exe/xmltools.py:1873:49-57: Expected class object, got `type[GetItem & _TypeGetOrChangeItem]` [invalid-argument]
- ERROR hydpy/exe/xmltools.py:1874:38-42: Argument `ExchangeItem` is not assignable to parameter `object` with type `_TypeGetOrChangeItem` in function `list.append` [bad-argument-type]
- ERROR hydpy/exe/xmltools.py:2373:20-2379:14: `SetItem` is not assignable to variable `item` with type `_TypeSetOrAddOrMultiplyItem` [bad-assignment]
- ::error file=hydpy/core/devicetools.py,line=2541,col=20,endLine=2541,endColumn=79,title=Pyrefly bad-return::Returned type `tuple[(int & t) | (str & t) | None, (int & t) | (str & t) | None] | tuple[t | None, t | None] | t` is not assignable to declared return type `tuple[t | None, t | None]`
+ ::error file=hydpy/core/devicetools.py,line=2541,col=20,endLine=2541,endColumn=79,title=Pyrefly bad-return::Returned type `tuple[int | str | None, int | str | None] | tuple[t | None, t | None] | t` is not assignable to declared return type `tuple[t | None, t | None]`
- ::error file=hydpy/core/devicetools.py,line=2724,col=20,endLine=2724,endColumn=79,title=Pyrefly bad-return::Returned type `tuple[(int & t) | (str & t) | None, (int & t) | (str & t) | None] | tuple[t | None, t | None] | t` is not assignable to declared return type `tuple[t | None, t | None]`
+ ::error file=hydpy/core/devicetools.py,line=2724,col=20,endLine=2724,endColumn=79,title=Pyrefly bad-return::Returned type `tuple[int | str | None, int | str | None] | tuple[t | None, t | None] | t` is not assignable to declared return type `tuple[t | None, t | None]`
+ ::error file=hydpy/core/importtools.py,line=796,col=32,endLine=796,endColumn=65,title=Pyrefly no-matching-overload::No matching overload found for function `SubmodelAdder.update` called with arguments: (TM_contra, TI_contra, refresh=Literal[False])%0A  Possible overloads:%0A  (model: TM_contra, submodel: TI_contra, /, *, refresh: bool) -> None [closest match]%0A  (model: TM_contra, submodel: TI_contra, /, *, position: int, refresh: bool) -> None
+ ::error file=hydpy/core/importtools.py,line=799,col=32,endLine=799,endColumn=84,title=Pyrefly no-matching-overload::No matching overload found for function `SubmodelAdder.update` called with arguments: (TM_contra, TI_contra, position=int, refresh=Literal[False])%0A  Possible overloads:%0A  (model: TM_contra, submodel: TI_contra, /, *, refresh: bool) -> None%0A  (model: TM_contra, submodel: TI_contra, /, *, position: int, refresh: bool) -> None [closest match]
+ ::error file=hydpy/core/importtools.py,line=949,col=29,endLine=949,endColumn=31,title=Pyrefly no-matching-overload::No matching overload found for function `SubmodelAdder.get_wrapped` called with arguments: ()%0A  Possible overloads:%0A  () -> PrepSub0D[TM_contra, TI_contra] [closest match]%0A  () -> PrepSub1D[TM_contra, TI_contra]
+ ::error file=hydpy/core/importtools.py,line=952,col=29,endLine=952,endColumn=31,title=Pyrefly no-matching-overload::No matching overload found for function `SubmodelAdder.get_wrapped` called with arguments: ()%0A  Possible overloads:%0A  () -> PrepSub0D[TM_contra, TI_contra] [closest match]%0A  () -> PrepSub1D[TM_contra, TI_contra]
- ::error file=hydpy/core/parametertools.py,line=1540,col=20,endLine=1540,endColumn=49,title=Pyrefly bad-return::Returned type `float | ndarray[tuple[Any, ...], dtype[float64]]` is not assignable to declared return type `ArrayFloat`
- ::error file=hydpy/core/parametertools.py,line=1542,col=20,endLine=1542,endColumn=49,title=Pyrefly bad-return::Returned type `float | ndarray[tuple[Any, ...], dtype[float64]]` is not assignable to declared return type `ArrayFloat`
- ::error file=hydpy/core/parametertools.py,line=1569,col=20,endLine=1569,endColumn=49,title=Pyrefly bad-return::Returned type `float | ndarray[tuple[Any, ...], dtype[float64]]` is not assignable to declared return type `ArrayFloat`
- ::error file=hydpy/core/parametertools.py,line=1571,col=20,endLine=1571,endColumn=49,title=Pyrefly bad-return::Returned type `float | ndarray[tuple[Any, ...], dtype[float64]]` is not assignable to declared return type `ArrayFloat`
- ::error file=hydpy/core/selectiontools.py,line=715,col=20,endLine=715,endColumn=43,title=Pyrefly bad-return::Returned type `Node` is not assignable to declared return type `TypeNodeElement`
- ::error file=hydpy/core/selectiontools.py,line=717,col=20,endLine=717,endColumn=46,title=Pyrefly bad-return::Returned type `Element` is not assignable to declared return type `TypeNodeElement`
- ::error file=hydpy/exe/xmltools.py,line=1868,col=45,endLine=1868,endColumn=53,title=Pyrefly invalid-argument::Expected class object, got `type[ChangeItem & _TypeGetOrChangeItem]`
- ::error file=hydpy/exe/xmltools.py,line=1868,col=45,endLine=1868,endColumn=53,title=Pyrefly invalid-argument::Expected class object, got `type[GetItem & _TypeGetOrChangeItem]`
- ::error file=hydpy/exe/xmltools.py,line=1869,col=34,endLine=1869,endColumn=38,title=Pyrefly bad-argument-type::Argument `ExchangeItem` is not assignable to parameter `object` with type `_TypeGetOrChangeItem` in function `list.append`
- ::error file=hydpy/exe/xmltools.py,line=1873,col=49,endLine=1873,endColumn=57,title=Pyrefly invalid-argument::Expected class object, got `type[ChangeItem & _TypeGetOrChangeItem]`
- ::error file=hydpy/exe/xmltools.py,line=1873,col=49,endLine=1873,endColumn=57,title=Pyrefly invalid-argument::Expected class object, got `type[GetItem & _TypeGetOrChangeItem]`
- ::error file=hydpy/exe/xmltools.py,line=1874,col=38,endLine=1874,endColumn=42,title=Pyrefly bad-argument-type::Argument `ExchangeItem` is not assignable to parameter `object` with type `_TypeGetOrChangeItem` in function `list.append`
- ::error file=hydpy/exe/xmltools.py,line=2373,col=20,endLine=2379,endColumn=14,title=Pyrefly bad-assignment::`SetItem` is not assignable to variable `item` with type `_TypeSetOrAddOrMultiplyItem`

static-frame (https://github.com/static-frame/static-frame)
- ERROR static_frame/core/node_values.py:147:24-155:18: Returned type `Frame[Any, Any, *tuple[Any, ...]]` is not assignable to declared return type `TVContainer_co` [bad-return]
- ERROR static_frame/core/node_values.py:176:20-181:14: Returned type `Series[Any, Any]` is not assignable to declared return type `TVContainer_co` [bad-return]
- ERROR static_frame/core/node_values.py:275:20-284:14: Returned type `Frame[Any, Any, *tuple[Any, ...]] | Index[Any] | IndexHierarchy[*tuple[Any, ...]] | Series[Any, Any]` is not assignable to declared return type `TVContainer_co` [bad-return]
- ::error file=static_frame/core/node_values.py,line=147,col=24,endLine=155,endColumn=18,title=Pyrefly bad-return::Returned type `Frame[Any, Any, *tuple[Any, ...]]` is not assignable to declared return type `TVContainer_co`
- ::error file=static_frame/core/node_values.py,line=176,col=20,endLine=181,endColumn=14,title=Pyrefly bad-return::Returned type `Series[Any, Any]` is not assignable to declared return type `TVContainer_co`
- ::error file=static_frame/core/node_values.py,line=275,col=20,endLine=284,endColumn=14,title=Pyrefly bad-return::Returned type `Frame[Any, Any, *tuple[Any, ...]] | Index[Any] | IndexHierarchy[*tuple[Any, ...]] | Series[Any, Any]` is not assignable to declared return type `TVContainer_co`

koda-validate (https://github.com/keithasaurus/koda-validate)
- ERROR koda_validate/generic.py:321:16-27: Returned type `bytes | str` is not assignable to declared return type `StrOrBytes` [bad-return]
- ERROR koda_validate/generic.py:330:16-27: Returned type `bytes | str` is not assignable to declared return type `StrOrBytes` [bad-return]
- ERROR koda_validate/generic.py:336:16-27: Returned type `bytes | str` is not assignable to declared return type `StrOrBytes` [bad-return]
- ::error file=koda_validate/generic.py,line=321,col=16,endLine=321,endColumn=27,title=Pyrefly bad-return::Returned type `bytes | str` is not assignable to declared return type `StrOrBytes`
- ::error file=koda_validate/generic.py,line=330,col=16,endLine=330,endColumn=27,title=Pyrefly bad-return::Returned type `bytes | str` is not assignable to declared return type `StrOrBytes`
- ::error file=koda_validate/generic.py,line=336,col=16,endLine=336,endColumn=27,title=Pyrefly bad-return::Returned type `bytes | str` is not assignable to declared return type `StrOrBytes`

discord.py (https://github.com/Rapptz/discord.py)
- ERROR discord/backoff.py:63:56-61: Default `Literal[False]` is not assignable to parameter `integral` with type `T` [bad-function-definition]
- ::error file=discord/backoff.py,line=63,col=56,endLine=63,endColumn=61,title=Pyrefly bad-function-definition::Default `Literal[False]` is not assignable to parameter `integral` with type `T`

pandas (https://github.com/pandas-dev/pandas)
- ERROR pandas/core/dtypes/cast.py:408:16-36: Returned type `Index | ndarray[tuple[Any, ...], dtype[signedinteger[_64Bit]]] | NumpyIndexT` is not assignable to declared return type `NumpyIndexT` [bad-return]
- ERROR pandas/core/dtypes/cast.py:410:16-37: Returned type `Index | ndarray[tuple[Any, ...], dtype[unsignedinteger[_64Bit]]] | NumpyIndexT` is not assignable to declared return type `NumpyIndexT` [bad-return]
- ERROR pandas/core/dtypes/cast.py:412:16-38: Returned type `Index | ndarray[tuple[Any, ...], dtype[float64]] | NumpyIndexT` is not assignable to declared return type `NumpyIndexT` [bad-return]
- ERROR pandas/core/resample.py:3149:12-21: Returned type `DatetimeIndex | PeriodIndex | TimedeltaIndex` is not assignable to declared return type `FreqIndexT` [bad-return]
- ERROR pandas/io/stata.py:2253:16-53: Returned type `bytes` is not assignable to declared return type `AnyStr` [bad-return]
- ERROR pandas/io/stata.py:2254:12-48: Returned type `bytes | str` is not assignable to declared return type `AnyStr` [bad-return]
- ::error file=pandas/core/dtypes/cast.py,line=408,col=16,endLine=408,endColumn=36,title=Pyrefly bad-return::Returned type `Index | ndarray[tuple[Any, ...], dtype[signedinteger[_64Bit]]] | NumpyIndexT` is not assignable to declared return type `NumpyIndexT`
- ::error file=pandas/core/dtypes/cast.py,line=410,col=16,endLine=410,endColumn=37,title=Pyrefly bad-return::Returned type `Index | ndarray[tuple[Any, ...], dtype[unsignedinteger[_64Bit]]] | NumpyIndexT` is not assignable to declared return type `NumpyIndexT`
- ::error file=pandas/core/dtypes/cast.py,line=412,col=16,endLine=412,endColumn=38,title=Pyrefly bad-return::Returned type `Index | ndarray[tuple[Any, ...], dtype[float64]] | NumpyIndexT` is not assignable to declared return type `NumpyIndexT`
- ::error file=pandas/core/resample.py,line=3149,col=12,endLine=3149,endColumn=21,title=Pyrefly bad-return::Returned type `DatetimeIndex | PeriodIndex | TimedeltaIndex` is not assignable to declared return type `FreqIndexT`
- ::error file=pandas/io/stata.py,line=2253,col=16,endLine=2253,endColumn=53,title=Pyrefly bad-return::Returned type `bytes` is not assignable to declared return type `AnyStr`
- ::error file=pandas/io/stata.py,line=2254,col=12,endLine=2254,endColumn=48,title=Pyrefly bad-return::Returned type `bytes | str` is not assignable to declared return type `AnyStr`

scrapy (https://github.com/scrapy/scrapy)
- ERROR scrapy/utils/datatypes.py:76:16-27: Returned type `bytes | str` is not assignable to declared return type `AnyStr` [bad-return]
- ::error file=scrapy/utils/datatypes.py,line=76,col=16,endLine=76,endColumn=27,title=Pyrefly bad-return::Returned type `bytes | str` is not assignable to declared return type `AnyStr`

@meta-codesync
Copy link

meta-codesync bot commented Jan 15, 2026

@stroxler has imported this pull request. If you are a Meta employee, you can view this in D90690156.

Copy link
Contributor

@stroxler stroxler left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the PR. I think it works, but I actually think the implementation isn't the right direction, we fixed the reported bug but not the root cause, which is missing exhaustiveness checks.

In particular, this snippet has exactly the same bug:

def g(x: int | str) -> int | str:
    if isinstance(x, int):
        return x
    elif isinstance(x, str):
        return x

I have some related work in draft match exhaustiveness changes I have (which are blocked from landing right away because I have major features that depend on one another + on some internal constraints)

I think I may need to come back to this PR once that work is unblocked to better understand how it all fits together, but my instinct is that we need a much more general mechanism for handling whether a final statement with branching control flow "falls off the end" or not in function return logic.

(t1, Type::Quantified(q)) => match q.restriction() {
// This only works for constraints and not bounds, because a TypeVar must resolve to exactly one of its constraints.
Restriction::Constraints(constraints) => all(constraints.iter(), |constraint| {
Restriction::Constraints(constraints) => any(constraints.iter(), |constraint| {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this change is probably not closely related, and it looks like it's probably right to me.

Would you want to submit a PR with just this one change?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Support exhaustiveness checks for constrained quantified type vars

3 participants