Skip to content

T | None <= int | None constraint wrongly solves T to int | None, should be int #3596

@carljm

Description

@carljm
from typing import Protocol

class Expected(Protocol):
    def value(self) -> int | None: ...

class Actual[T]:
    def value(self) -> T | None:
        return None

def make[T](_: list[T]) -> Actual[T]:
    return Actual()

def preserve[T: Expected](value: T) -> T:
    return value

def test() -> Actual[int]:
    return preserve(make([]))  # error: expected `Actual[int]`, found `Actual[int | None]`

This originally showed up with stdlib async-related types in #3583 (Generator.close() returns _ReturnTCo | None, which triggers this issue). We can easily work around it for that particular case by special-casing Generator, but the general bug in constraint solving remains.

Metadata

Metadata

Assignees

No one assigned

    Labels

    genericsBugs or features relating to ty's generics implementation

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions