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.

@github-actions
Copy link

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

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]

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]

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]

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]

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]

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]

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]

pandas (https://github.com/pandas-dev/pandas)
- ERROR pandas/core/dtypes/cast.py:409: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:411: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:413: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:3143: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]

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]

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]

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

1 participant