You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Incorrect handling of overloads with defaultdict and MutableMapping #19525
What should ??? be? In my mind it should be Any as "idk, have your any" fallback. There is no way I could expect B[int] there. I can also understand inferring union (A[str] | B[int]), join (A[int | str]) or A[Any] (the latter with a bit of a stretch), but picking the first overload in such case (where it's Any what decides which overload to pick) is unreasonable IMO.
I don't have enough time to dig the overloads spec now (and I still remember how controversial that page was), but I prefer mypy behavior (Any) over pyright behavior (B[int]) even if that means nonconformance.
Any in the last reproducer by @brianschubert "causes overload ambiguity", we look for such conditions explicitly:
I think mypy is working correctly here and is in compliance with the overload call evaluation algorithm defined in the typing spec. Pyright is nonconformant in this case. This is a known issue in pyright.
I think mypy is working correctly here and is in compliance with the overload call evaluation algorithm defined in the typing spec. Pyright is nonconformant in this case. This is a known issue in pyright.
@erictraut which example are you referring to? The original one I posted, or the second example: #19525 (comment)
Any should be seen as a standin for some unknown static type (a "materialization"; see the spec: https://typing.python.org/en/latest/spec/concepts.html#materialization ). This example uses a number of distinct Anys, and in general we have to infer a type that works for all possible materializations. In this case, there are many possible materializations that would make it so the call with B[Any] as an argument hits the second overload. For example, the Any in the argument and in the parameter type of the second overload could materialize to one type (e.g., int), while the Any in the parameter type of the first overload could materialize to another type (e.g., str).
This means that we hit step 5 of the overload evaluation spec and there are multiple matching overloads with distinct return types. Therefore, we return Any.
Any should be seen as a standin for some unknown static type (a "materialization"; see the spec: https://typing.python.org/en/latest/spec/concepts.html#materialization ). This example uses a number of distinct Anys, and in general we have to infer a type that works for all possible materializations. In this case, there are many possible materializations that would make it so the call with B[Any] as an argument hits the second overload. For example, the Any in the argument and in the parameter type of the second overload could materialize to one type (e.g., int), while the Any in the parameter type of the first overload could materialize to another type (e.g., str).
This means that we hit step 5 of the overload evaluation spec and there are multiple matching overloads with distinct return types. Therefore, we return Any.
Can you make the same analysis with my original example involving defaultdict and MutableMapping, because I'm having a hard time seeing how your analysis applies in that case.
Your original example had defaultdict (which means defaultdict[Any, Any]) and MutableMapping (i.e., MutableMapping[Any, Any]), so it's closely analogous. Unfortunately the type system doesn't contain a type that represents all kinds of defaultdicts, which is perhaps what you'd want here.
Since we have identified the root cause and realized that this behavior is intended and even spec-compliant, I'm closing this ticket as "not planned" - there's no bug on the mypy side.
Activity
brianschubert commentedon Jul 28, 2025
Smaller reproducer:
edit: only the Any at the callsite appears to be relevant:
brianschubert commentedon Jul 28, 2025
(nevermind about the crash - that was due to an unrelated issue caused by a typo in the reproducer. I'll open a separate issue for it. edit: #19526)
sterliakov commentedon Jul 29, 2025
Is this really a bug? While this specific example seems unambiguous, consider the following:
What should
???be? In my mind it should beAnyas "idk, have your any" fallback. There is no way I could expectB[int]there. I can also understand inferring union (A[str] | B[int]), join (A[int | str]) orA[Any](the latter with a bit of a stretch), but picking the first overload in such case (where it'sAnywhat decides which overload to pick) is unreasonable IMO.I don't have enough time to dig the overloads spec now (and I still remember how controversial that page was), but I prefer
mypybehavior (Any) overpyrightbehavior (B[int]) even if that means nonconformance.Anyin the last reproducer by @brianschubert "causes overload ambiguity", we look for such conditions explicitly:mypy/mypy/checkexpr.py
Lines 6598 to 6653 in af92439
erictraut commentedon Jul 29, 2025
I think mypy is working correctly here and is in compliance with the overload call evaluation algorithm defined in the typing spec. Pyright is nonconformant in this case. This is a known issue in pyright.
Dr-Irv commentedon Jul 29, 2025
@erictraut which example are you referring to? The original one I posted, or the second example: #19525 (comment)
erictraut commentedon Jul 30, 2025
Both. The second example is a simplified version of the first.
cmp0xff commentedon Jul 30, 2025
Could you elaborate why the first example is correct? In my opinion, inserting
b: B[Any]intofooshould be evaluated by the first overloadand should give the type
B[Any].JelleZijlstra commentedon Jul 30, 2025
Any should be seen as a standin for some unknown static type (a "materialization"; see the spec: https://typing.python.org/en/latest/spec/concepts.html#materialization ). This example uses a number of distinct Anys, and in general we have to infer a type that works for all possible materializations. In this case, there are many possible materializations that would make it so the call with
B[Any]as an argument hits the second overload. For example, the Any in the argument and in the parameter type of the second overload could materialize to one type (e.g.,int), while the Any in the parameter type of the first overload could materialize to another type (e.g.,str).This means that we hit step 5 of the overload evaluation spec and there are multiple matching overloads with distinct return types. Therefore, we return Any.
fix: constraint instead of bound to get rid of Any python/mypy#19525 …
Dr-Irv commentedon Jul 30, 2025
Can you make the same analysis with my original example involving
defaultdictandMutableMapping, because I'm having a hard time seeing how your analysis applies in that case.feat(index): append (#1282)
JelleZijlstra commentedon Aug 1, 2025
Your original example had
defaultdict(which meansdefaultdict[Any, Any]) andMutableMapping(i.e.,MutableMapping[Any, Any]), so it's closely analogous. Unfortunately the type system doesn't contain a type that represents all kinds of defaultdicts, which is perhaps what you'd want here.sterliakov commentedon Aug 8, 2025
Since we have identified the root cause and realized that this behavior is intended and even spec-compliant, I'm closing this ticket as "not planned" - there's no bug on the mypy side.
feat(index): append (pandas-dev#1282)