fix Overloaded function is not assignable to Callable #2273#2277
fix Overloaded function is not assignable to Callable #2273#2277asukaminato0721 wants to merge 1 commit intofacebook:mainfrom
Conversation
There was a problem hiding this comment.
Pull request overview
This pull request fixes issue #2273 by enabling overloaded functions with single-parameter signatures to be assignable to Callable types that accept a union of those parameter types. The fix allows Overload[(x: int) -> str, (x: str) -> str] to be treated as compatible with Callable[[int | str], str].
Changes:
- Added logic to merge single-parameter overload signatures into a unified callable when matching against a callable with union parameters
- Added a test case verifying the fix for the reported issue
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
| pyrefly/lib/solver/subset.rs | Implements overload-to-Callable subtyping by detecting single-parameter overloads that can be merged into a union-parameter callable, with fallback to existing behavior |
| pyrefly/lib/test/overload.rs | Adds regression test for overload assignability to Callable with union parameters |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| && u.callable_signatures() | ||
| .first() | ||
| .is_some_and(|sig| match &sig.params { | ||
| Params::List(params) if params.len() == 1 => { | ||
| matches!(params.items()[0].as_type(), Type::Union(_)) | ||
| } | ||
| _ => false, | ||
| }) |
There was a problem hiding this comment.
The check at line 1127 using .first() only verifies the first signature when the target type could potentially be an Overload with multiple signatures. While correctness is preserved by the subsequent is_subset_eq check and fallback logic, consider adding a length check to ensure u.callable_signatures().len() == 1 before attempting this optimization. This would avoid unnecessary work when the target is an Overload with multiple signatures where only the first matches the pattern.
|
Diff from mypy_primer, showing the effect of this PR on open source code: pywin32 (https://github.com/mhammond/pywin32)
- ERROR win32/Lib/win32timezone.py:672:9-15: Class member `TimeZoneInfo.tzname` overrides parent class `tzinfo` in an inconsistent manner [bad-override]
- ERROR win32/Lib/win32timezone.py:727:9-18: Class member `TimeZoneInfo.utcoffset` overrides parent class `tzinfo` in an inconsistent manner [bad-override]
- ERROR win32/Lib/win32timezone.py:738:9-12: Class member `TimeZoneInfo.dst` overrides parent class `tzinfo` in an inconsistent manner [bad-override]
- ::error file=win32/Lib/win32timezone.py,line=672,col=9,endLine=672,endColumn=15,title=Pyrefly bad-override::Class member `TimeZoneInfo.tzname` overrides parent class `tzinfo` in an inconsistent manner%0A `TimeZoneInfo.tzname` has type `BoundMethod[TimeZoneInfo, Overload[%0A (self: TimeZoneInfo, dt: datetime) -> str%0A (self: TimeZoneInfo, dt: None) -> None%0A]]`, which is not assignable to `BoundMethod[TimeZoneInfo, (self: TimeZoneInfo, dt: datetime | None, /) -> str | None]`, the type of `tzinfo.tzname`
- ::error file=win32/Lib/win32timezone.py,line=727,col=9,endLine=727,endColumn=18,title=Pyrefly bad-override::Class member `TimeZoneInfo.utcoffset` overrides parent class `tzinfo` in an inconsistent manner%0A `TimeZoneInfo.utcoffset` has type `BoundMethod[TimeZoneInfo, Overload[%0A (self: TimeZoneInfo, dt: None) -> None%0A (self: TimeZoneInfo, dt: datetime) -> timedelta%0A]]`, which is not assignable to `BoundMethod[TimeZoneInfo, (self: TimeZoneInfo, dt: datetime | None, /) -> timedelta | None]`, the type of `tzinfo.utcoffset`
- ::error file=win32/Lib/win32timezone.py,line=738,col=9,endLine=738,endColumn=12,title=Pyrefly bad-override::Class member `TimeZoneInfo.dst` overrides parent class `tzinfo` in an inconsistent manner%0A `TimeZoneInfo.dst` has type `BoundMethod[TimeZoneInfo, Overload[%0A (self: TimeZoneInfo, dt: None) -> None%0A (self: TimeZoneInfo, dt: datetime) -> timedelta%0A]]`, which is not assignable to `BoundMethod[TimeZoneInfo, (self: TimeZoneInfo, dt: datetime | None, /) -> timedelta | None]`, the type of `tzinfo.dst`
|
Summary
Fixes #2273
Adjusted overload-to-Callable subtyping so single-parameter overloads can satisfy a union-parameter Callable (the case in issue 2273), while keeping the existing per‑signature fallback.
Test Plan
Added a regression test.