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
Let's say I have a generic Protocol and a class that implements that protocol multiple times (for different arguments) via overloads:
classProto[T](Protocol):
@type_check_onlydefproto(self, _: T, /) ->None: ...
type One=Literal[1]
type Two=Literal[2]
@finalclassImpl[N: int]:
# ensure `N` is invariantdef__init__(self, n: N, /) ->None: ...
@type_check_onlydefget_n(self, /) ->N: ...
# implement Proto[N] for Impl[N] and Proto[M] for Impl[One] (for all integers N, M)@overloaddefproto(self, _: "Impl[N]", /) ->None: ...
@overloaddefproto[M: int](self: "Impl[One]", _: "Impl[M]", /) ->None: ...
I can easily verify that Impl really does implement Proto the way I intended:
classcheck1[T]:
def__init__(self, x: Proto[T], /) ->None: ...
# Here it all works as expectedimpl1=Impl[One](1)
impl2=Impl[Two](2)
impl_=Impl[int](3)
_=check1[Impl[One]](impl1) # ok (first overload applies)_=check1[Impl[Two]](impl1) # ok (second overload applies)_=check1[Impl[One]](impl2) # error (second overload doesn't apply because One != Two)_=check1[Impl[Two]](impl2) # ok (first overload applies)_=check1[Impl[One]](impl_) # error (second overload doesn't apply because N is invariant)_=check1[Impl[Two]](impl_) # error (second overload doesn't apply because N is invariant)_=check1[Impl[int]](impl_) # ok (first overload applies)
Now, let's say we wanted to write a function func that takes T and Proto[T], in any order, and just applies .proto(...) on them. Here, I'll model it as a generic class:
The error message says I cannot assign impl2: Impl[Two] to y: T, because Impl[Two] is not assignable to Impl[One]: it looks like Pyright has chosen the first overload in Impl's implementation of Proto and has resolved T to be One because impl1: Impl[One] indeed implements Proto[One]. However, since this leads to an error, why has Pyright not tried the other implementation?
Side note
If I don't manually enforce the type parameter of check1, Pyright infers Impl[One]:
reveal_type(check1(impl1)) # type is `check1[Impl[One]]` # first overload applies
Is this:
a hard limitation of Pyright (and type checker implementations in general),
a hole (unspecified behaviour) in the typing spec,
or the expected behaviour (and I just don't understand what's going on)?
If it is indeed a hard limitation, can I type func in a different way (without changing Impl and Proto)?
Thank you for your time and dedication to improve the soundness and expressiveness of the Python type system (and to answer all these questions from the community).
reacted with thumbs up emoji reacted with thumbs down emoji reacted with laugh emoji reacted with hooray emoji reacted with confused emoji reacted with heart emoji reacted with rocket emoji reacted with eyes emoji
Uh oh!
There was an error while loading. Please reload this page.
-
Let's say I have a generic
Protocol
and a class that implements that protocol multiple times (for different arguments) viaoverload
s:I can easily verify that
Impl
really does implementProto
the way I intended:Now, let's say we wanted to write a function
func
that takesT
andProto[T]
, in any order, and just applies.proto(...)
on them. Here, I'll model it as a generic class:If I don't specify
T
manually, sometimes Pyright complains:Code sample in pyright playground
The error message says I cannot assign
impl2: Impl[Two]
toy: T
, becauseImpl[Two]
is not assignable toImpl[One]
: it looks like Pyright has chosen the firstoverload
inImpl
's implementation ofProto
and has resolvedT
to beOne
becauseimpl1: Impl[One]
indeed implementsProto[One]
. However, since this leads to an error, why has Pyright not tried the other implementation?Side note
If I don't manually enforce the type parameter of
check1
, Pyright infersImpl[One]
:Is this:
If it is indeed a hard limitation, can I type
func
in a different way (without changingImpl
andProto
)?Thank you for your time and dedication to improve the soundness and expressiveness of the Python type system (and to answer all these questions from the community).
Best regards,
Riccardo Bergamaschi.
Beta Was this translation helpful? Give feedback.
All reactions