Skip to content

ty thinks Generator[None, None, A] and Generator[None, None, B] are equivalent types on Python <3.13 #2426

@carljm

Description

@carljm
from ty_extensions import is_equivalent_to, is_subtype_of, static_assert
from typing import Generator

class A: ...
class B: ...

static_assert(not is_equivalent_to(Generator[None, None, A], Generator[None, None, B]))
static_assert(not is_subtype_of(Generator[None, None, A], Generator[None, None, B]))
static_assert(not is_subtype_of(Generator[None, None, B], Generator[None, None, A]))

https://play.ty.dev/0cd14b68-645f-461b-896a-31f78cc10b6c

The assertions here should pass. They do pass on Python 3.13+, but fail on Python 3.12 or older.

The reason is that Generator is a protocol, and its third type parameter (ReturnT_co) is unused in its interface (as defined in typeshed) in Python earlier than 3.13.

As far as the definition given in typeshed, I think ty's conclusion here is correct. But generators are rather special, specifically in that their "return" value also gets wrapped into the StopIteration exception that ends their iteration (even on 3.12 and earlier), but this is not visible in their type system interface. Thus their ReturnT_co always matters (quite a lot -- this is the key mechanism by which async/await works), but typeshed's definition doesn't make that explicit.

I think we will probably need to special-case this type somehow to understand that its ReturnT_co always matters, even on older Python versions.

Metadata

Metadata

Assignees

Labels

ProtocolsasyncIssues related to checking code using async/awaitbugSomething isn't workinggenericsBugs or features relating to ty's generics implementation

Type

No type

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions