Repository navigation
Ensures overloads are ordered from narrow to broad - #2138
Conversation
This commit reorders any overloads where the first overload was
"shadowing" the second, preventing it from ever being matched by type
checkers that work by selecting the first matching overload alternative.
For example, the first overload alternative below is strictly broader
then the second, preventing it from ever being selected:
class Parent: pass
class Child(Parent): pass
@overload
def foo(x: *int) -> Parent: ...
@overload
def foo(x: int, y: int) -> Child: ...
The correct thing to do is to either delete the second overload or
rearrange them to look like this:
@overload
def foo(x: int, y: int) -> Child: ...
@overload
def foo(x: *int) -> Parent: ...
Rationale: I'm currently [working on a proposal][0] that would amend
PEP 484 to (a) mandate type checkers check overloads in order and
(b) prohibit overloads where an earlier alternative completely shadows
a later one.
[0]: python/typing#253 (comment)
This would prohibit overloads that look like the example below, where
the first alternative completely shadows the second.
I figured it would be a good idea to make these changes ahead of time:
if my proposal is accepted, it'd make the transition smoother. If not,
this is hopefully a relatively harmless change.
Note: I think some of these overloads could be simplified (e.g.
`reversed(...)`), but I mostly stuck with rearranging them in case I was
wrong. The only overload I actually changed was `hmac.compare_digest` --
I believe the Python 2 version actually accepts unicode.
|
I assume you mean "overloads", not "commits" :) |
| @overload | ||
| def stat_float_times() -> bool: ... | ||
| @overload | ||
| def stat_float_times(newvalue: bool = ...) -> None: ... |
There was a problem hiding this comment.
Shouldn't we just remove the = ... here?
|
lol, good point -- fixed the title |
This pull request relaxes the overlapping overload checks so that if the
parameter types of an alternative are a proper subtype of another, the
return type needs to only be a regular subtype, not a proper subtype.
The net effect is that the return type of the first alternative is
allowed to be 'Any'.
This *does* make overloads slightly less safe, but 'Any' was always
meant to be an escape hatch, so I'm figuring this is fine.
**Rationale**: My [proposed changes on overhauling overloads][0] require
a few changes to typeshed -- [relevant pull request here][1]. Rather then
trying to change both at the same time, I want to get typeshed working
first.
This was pretty easy to do, apart from the attrs stubs. The issue
basically boils down to this:
# Alternative 1
@overload
def attrib(x: Optional[T]) -> T: ...
# Alternative 2
@overload
def attrib(x: None = None) -> Any: ...
This code typechecks under the current system because alternative 1
completely shadows alternative 2. It fails to typecheck under the new
system for the exact same reason.
If we swap the two alternatives, it fails under the current system
because 'Any' is not a proper subtype of 'T'.
It *is*, however, regular subtype of 'T' -- hence this change.
[0]: python/typing#253 (comment)
[1]: python/typeshed#2138
|
I reverted the changes to the attrs stubs for now -- it looks like the attrs stubs are currently impossible to type in a way that's compatible with both the current and proposed overload semantics. I submitted a pull request to slightly relax mypy's current overload semantics so that this change can go through. Once my other pull request is accepted, I'll unrevert my revert (unless you decide to accept this pull request as-is -- if so, I can just make another pull request for attrs). |
…5064) This pull request relaxes the overlapping overload checks so that if the parameter types of an alternative are a proper subtype of another, the return type needs to only be a regular subtype, not a proper subtype. The net effect is that the return type of the first alternative is allowed to be 'Any'. This *does* make overloads slightly less safe, but 'Any' was always meant to be an escape hatch, so I'm figuring this is fine. **Rationale**: My [proposed changes on overhauling overloads][0] require a few changes to typeshed -- [relevant pull request here][1]. Rather then trying to change both at the same time, I want to get typeshed working first. This was pretty easy to do, apart from the attrs stubs. The issue basically boils down to this: # Alternative 1 @overload def attrib(x: Optional[T]) -> T: ... # Alternative 2 @overload def attrib(x: None = None) -> Any: ... This code typechecks under the current system because alternative 1 completely shadows alternative 2. It fails to typecheck under the new system for the exact same reason. If we swap the two alternatives, it fails under the current system because 'Any' is not a proper subtype of 'T'. It *is*, however, regular subtype of 'T' -- hence this change. [0]: python/typing#253 (comment) [1]: python/typeshed#2138
|
@JelleZijlstra -- Ok, looks like third time was the charm. I think this is ready for a second look whenever you have time. |
Syncs typeshed, mostly to pull in some [tweaks I made][0] that makes typeshed compatible with both the current and [proposed][1] overload semantics. [0]: python/typeshed#2138 [1]: python/typing#253 (comment)
Syncs typeshed, mostly to pull in some [tweaks I made][0] that makes typeshed compatible with both the current and [proposed][1] overload semantics. [0]: python/typeshed#2138 [1]: python/typing#253 (comment)
Basically, the same thing as [my previous pull request][0], except the fixes are now focusing on functions with overlapping argument counts. [0]: python#2138
Basically, the same thing as [my previous pull request][0], except the fixes are now focusing on functions with overlapping argument counts. [0]: #2138
This commit reorders any overloads where the first overload was
"shadowing" the second, preventing it from ever being matched by type
checkers that work by selecting the first matching overload alternative.
For example, the first overload alternative below is strictly broader
then the second, preventing it from ever being selected:
class Parent: pass
class Child(Parent): pass
@overload
def foo(x: *int) -> Parent: ...
@overload
def foo(x: int, y: int) -> Child: ...
The correct thing to do is to either delete the second overload or
rearrange them to look like this:
@overload
def foo(x: int, y: int) -> Child: ...
@overload
def foo(x: *int) -> Parent: ...
Rationale: I'm currently [working on a proposal][0] that would amend
PEP 484 to (a) mandate type checkers check overloads in order and
(b) prohibit overloads where an earlier alternative completely shadows
a later one.
[0]: python/typing#253 (comment)
This would prohibit overloads that look like the example below, where
the first alternative completely shadows the second.
I figured it would be a good idea to make these changes ahead of time:
if my proposal is accepted, it'd make the transition smoother. If not,
this is hopefully a relatively harmless change.
Note: I think some of these overloads could be simplified (e.g.
`reversed(...)`), but I mostly stuck with rearranging them in case I was
wrong. The only overload I actually changed was `hmac.compare_digest` --
I believe the Python 2 version actually accepts unicode.
Basically, the same thing as [my previous pull request][0], except the fixes are now focusing on functions with overlapping argument counts. [0]: python#2138
This commit reorders any overloads where the first overload was
"shadowing" the second, preventing it from ever being matched by type
checkers that work by selecting the first matching overload alternative.
For example, the first overload alternative below is strictly broader
then the second, preventing it from ever being selected:
class Parent: pass
class Child(Parent): pass
@overload
def foo(x: *int) -> Parent: ...
@overload
def foo(x: int, y: int) -> Child: ...
The correct thing to do is to either delete the second overload or
rearrange them to look like this:
@overload
def foo(x: int, y: int) -> Child: ...
@overload
def foo(x: *int) -> Parent: ...
Rationale: I'm currently [working on a proposal][0] that would amend
PEP 484 to (a) mandate type checkers check overloads in order and
(b) prohibit overloads where an earlier alternative completely shadows
a later one.
[0]: python/typing#253 (comment)
This would prohibit overloads that look like the example below, where
the first alternative completely shadows the second.
I figured it would be a good idea to make these changes ahead of time:
if my proposal is accepted, it'd make the transition smoother. If not,
this is hopefully a relatively harmless change.
Note: I think some of these overloads could be simplified (e.g.
`reversed(...)`), but I mostly stuck with rearranging them in case I was
wrong. The only overload I actually changed was `hmac.compare_digest` --
I believe the Python 2 version actually accepts unicode.
Basically, the same thing as [my previous pull request][0], except the fixes are now focusing on functions with overlapping argument counts. [0]: python#2138
This commit reorders any overloads where the first overload was "shadowing" the second, preventing it from ever being matched by type checkers that work by selecting the first matching overload alternative.
For example, the first overload alternative below is strictly broader then the second, preventing it from ever being selected:
The correct thing to do is to either delete the second overload or rearrange them to look like this:
Rationale: I'm currently working on a proposal that would amend PEP 484 to (a) mandate type checkers check overloads in order and (b) prohibit overloads where an earlier alternative completely shadows a later one.
This would prohibit overloads that look like the example below, where the first alternative completely shadows the second.
I figured it would be a good idea to make these changes ahead of time: if my proposal is accepted, it'd make the transition smoother. If not, this is hopefully a relatively harmless change.
Note: I think some of these overloads could be simplified (e.g.
reversed(...)), but I mostly stuck with rearranging them in case I was wrong. The only overload I actually changed washmac.compare_digest-- I believe the Python 2 version actually accepts unicode.