Skip to content

Union type incorrectly satisfies TypeVar bound to Protocol with Self in contravariant position #11374

@DanShaders

Description

@DanShaders

Describe the bug

When a TypeVar is bound to a Protocol that uses Self as a parameter type (contravariant position), pyright incorrectly accepts a union type as satisfying the bound.

Code or Screenshots

from typing import Protocol, Self, final


class SelfSerializable(Protocol):
    @classmethod
    def serialize(cls, value: Self) -> bytes: ...


@final
class Foo:
    def __init__(self, x: int) -> None:
        self.x = x

    @classmethod
    def serialize(cls, value: Self) -> bytes:
        return value.x.to_bytes(4)


@final
class Bar:
    def __init__(self, name: str) -> None:
        self.name = name

    @classmethod
    def serialize(cls, value: Self) -> bytes:
        return value.name.encode()


def serialize_other[T: SelfSerializable](template: T, value: T) -> bytes:
    return type(template).serialize(value)


_ = serialize_other(Bar("name"), Foo(42))

0 diagnostics, runtime crash.

Writing def serialize[T](cls: type[T], value: T) -> bytes: ... in SelfSerializable makes no difference.

VS Code extension or command-line

1.1.408, through cmdline.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions