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
Allow returning AnyOf rather than Any for amiguous overloads. #2196
Currently, the typing spec for overloads, step 5, states that
Once this filtering process is applied for all arguments, examine the return types of the remaining overloads. If these return types include type variables, they should be replaced with their solved types. If the resulting return types for all remaining overloads are equivalent, proceed to step 6.
If the return types are not equivalent, overload matching is ambiguous. In this case, assume a return type of Any and stop.
However, couldn't this rule be relaxed to returning the union of the return type of all matching overloads? For instance, consider this example derived from a real world use case (numpy scalar ops)
According to the rule stated above, op(A[Any], A[Any]) should be inferred to as Any, because the overloads are ambious and A[Any] is not equivalent to A[None] as not all materializations of A[Any] can be assigned to A[None].
However inferring Any loses deducible information: we know that no matter what, the return type must be an A. So in principle the return type should be A[Any] | A[None], because if either the left argument or the right argument materializes to A[None], then we get A[None] and otherwise if they materialize to something else we get A[Any].
Addendum: Some discussion in astral-sh/ty#665 suggests allowing the intersection rather than the union, which would also be fine in my example, and I guess aligns better with the gradual guarantee, though it has the potential to lead to false negatives:
@overloaddeffoo(arg: str) ->str: ...
@overloaddeffoo(arg: int) ->int: ...
deftest(arg): # unannoted, so arg=Anyy=foo(arg)
y.isdigit() # <- false negative if we infer str & int rather than str | inttest(0) # error.
changed the title [-]Allow returning unions rather than `Any` for amiguous overloads.[/-][+]Allow returning unions/intersections rather than `Any` for amiguous overloads.[/+]on Feb 25, 2026
I think the fact that current type checkers found it necessary to implement the "fallback to Any" rule suggests that in practice the gradual guarantee is important here. Put in more intuitive terms, Any behaves in a maximally permissive way, so it is odd for an input Any type to translate into a maximally restrictive union output type.
Thinking about it, maybe @srittau 's AnyOf type may be the best solution here! This should give us the best of both worlds - gradual guarantee, but it stays union-like.
I can't quite tell whether this is what you meant by "allow", but it would be a step backwards to allow two different interpretations here in the spec. E.g., it makes it harder for library authors to know what the experience of their users will be. A non-default strictness option in a willing type checker could be interesting though.
Agree that if we get AnyOf then this is a good place to use it.
changed the title [-]Allow returning unions/intersections rather than `Any` for amiguous overloads.[/-][+]Allow returning `AnyOf` rather than `Any` for amiguous overloads.[/+]on Mar 28, 2026
Activity
randolf-scholz commentedon Feb 25, 2026
Addendum: Some discussion in astral-sh/ty#665 suggests allowing the intersection rather than the union, which would also be fine in my example, and I guess aligns better with the gradual guarantee, though it has the potential to lead to false negatives:
[-]Allow returning unions rather than `Any` for amiguous overloads.[/-][+]Allow returning unions/intersections rather than `Any` for amiguous overloads.[/+]carljm commentedon Feb 25, 2026
I think the fact that current type checkers found it necessary to implement the "fallback to Any" rule suggests that in practice the gradual guarantee is important here. Put in more intuitive terms,
Anybehaves in a maximally permissive way, so it is odd for an inputAnytype to translate into a maximally restrictive union output type.randolf-scholz commentedon Feb 25, 2026
Thinking about it, maybe @srittau 's
AnyOftype may be the best solution here! This should give us the best of both worlds - gradual guarantee, but it stays union-like.hauntsaninja commentedon Feb 25, 2026
I can't quite tell whether this is what you meant by "allow", but it would be a step backwards to allow two different interpretations here in the spec. E.g., it makes it harder for library authors to know what the experience of their users will be. A non-default strictness option in a willing type checker could be interesting though.
Agree that if we get AnyOf then this is a good place to use it.
[-]Allow returning unions/intersections rather than `Any` for amiguous overloads.[/-][+]Allow returning `AnyOf` rather than `Any` for amiguous overloads.[/+]