Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Fix inconsistent type resolution with unused type variables #20541

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
leonace924 wants to merge 2 commits into python:master
base: master
Choose a base branch
Loading
from leonace924:fix/issue-20442

Conversation

@leonace924
Copy link

@leonace924 leonace924 commented Jan 7, 2026
edited
Loading

Fixes #20442

Problem

When a generic class has an unused type parameter, mypy incorrectly returns Any when resolving overloads involving functions that reference that class.

Reproduction

from typing import Any, Generic, overload
from collections.abc import Callable, Hashable, Iterable
from typing_extensions import TypeVar, Self
IndexT0 = TypeVar("IndexT0") # Unused type variable
T = TypeVar("T")
class Series:
 pass
class _LocIndexerFrame(Generic[T]):
 @overload
 def __getitem__(self, idx: tuple[Callable[[DataFrame], int], str]) -> int: ...
 @overload
 def __getitem__(self, idx: tuple[Callable[[DataFrame], list[Hashable]], str]) -> Series: ...
 @overload
 def __getitem__(self, idx: tuple[Callable[[DataFrame], Any], Iterable[Hashable]]) -> T: ...
 def __getitem__(self, idx: object) -> object:
 return idx
class DataFrame(Generic[IndexT0]):
 @property
 def loc(self) -> _LocIndexerFrame[Self]:
 return _LocIndexerFrame()
def select2(df: DataFrame) -> list[Hashable]:
 return []
def select3(_: DataFrame) -> int:
 return 1
reveal_type(DataFrame().loc[select2, "x"]) # Was: Any, Expected: Series
reveal_type(DataFrame().loc[select3, "x"]) # Was: Any, Expected: int

Root Cause

When DataFrame has an unused type parameter IndexT0, mypy treats bare DataFrame as DataFrame[Any]. This Any propagates into callable types like Callable[[DataFrame[Any]], list[Hashable]].

The any_causes_overload_ambiguity() function in checkexpr.py was too aggressive - it saw the nested Any in the argument and concluded there was ambiguity, even though the Any was in a position that was identical across all overload formals (the callable's argument type), not in the position that differentiated the overloads (the callable's return type).

Solution

Added _any_in_unrelated_position() function that checks whether Any in an argument is in a position that doesn't affect overload differentiation:

Changes

  • mypy/checkexpr.py: Added _any_in_unrelated_position() helper function and integrated it into any_causes_overload_ambiguity()
  • test-data/unit/check-overloading.test: Added two regression test cases

Test Plan

  • Added testOverloadWithNestedAnyInCallableDoesNotCauseAmbiguity - tests direct callable arguments
  • Added testOverloadWithNestedAnyInTupleCallableDoesNotCauseAmbiguity - tests tuple containing callable arguments (matches the original issue)
  • All existing overload tests pass (271 passed, 1 skipped)
  • Full test suite passes (7769 passed, 36 skipped, 7 xfailed)

Contribution by Gittensor, see my contribution statistics at https://gittensor.io/miners/details?githubId=42954461

Copy link
Author

@A5rocks @hauntsaninja would you review my PR? glad to contribute on this project!

Copy link
Contributor

github-actions bot commented Jan 7, 2026

According to mypy_primer, this change doesn't affect type check results on a corpus of open source code. ✅

Copy link
Collaborator

@A5rocks A5rocks left a comment

Choose a reason for hiding this comment

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

I don't really get what _any_in_unrelated_position is doing and I'm not convinced I should spend the hour it would take to do so :P

What's the logic for it?

# So it's safe to just append everything to the same list.
for formal in formals:
matching_formals.append(matched_callable.arg_types[formal])
if not all_same_types(matching_formals) and not all_same_types(matching_returns):
Copy link
Collaborator

@A5rocks A5rocks Jan 7, 2026
edited
Loading

Choose a reason for hiding this comment

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

Ack, I did in fact misunderstand.

But I feel like this is probably wrong, rather than having a complicated addition to patch things.

Copy link
Author

@leonace924 leonace924 Jan 7, 2026

Choose a reason for hiding this comment

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

What is your suggestion? we should have complicated addition? @A5rocks

Copy link
Author

@leonace924 leonace924 Jan 7, 2026

Choose a reason for hiding this comment

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

It'd be great if you give me the advice in case my direction is wrong.. 😉
Thank you for your time

Copy link
Collaborator

@A5rocks A5rocks Jan 7, 2026

Choose a reason for hiding this comment

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

Sorry, I'm not sure! I'm a bit confused about what this code is supposed to do, because I don't think the formals being the same type is necessary.

Copy link
Author

@leonace924 leonace924 Jan 7, 2026

Choose a reason for hiding this comment

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

#20442

{E9BE3B76-9A6C-4B67-896E-DA9B58C1FE1F}

can you check the issue and this screenshot? I misunderstood the requirement from issue?

A5rocks reacted with confused emoji
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Reviewers

1 more reviewer

@A5rocks A5rocks A5rocks left review comments

Reviewers whose approvals may not affect merge requirements

Assignees

No one assigned

Labels

None yet

Projects

None yet

Milestone

No milestone

Development

Successfully merging this pull request may close these issues.

Inconsistent behaviour with / without a dummy type variable

AltStyle によって変換されたページ (->オリジナル) /