[ty] Ensure annotation/type expressions in stub files are always deferred (#21401)
Some checks are pending
CI / cargo test (linux) (push) Blocked by required conditions
CI / cargo test (linux, release) (push) Blocked by required conditions
CI / Determine changes (push) Waiting to run
CI / cargo fmt (push) Waiting to run
CI / cargo clippy (push) Blocked by required conditions
CI / cargo test (${{ github.repository == 'astral-sh/ruff' && 'depot-windows-2022-16' || 'windows-latest' }}) (push) Blocked by required conditions
CI / cargo test (macos-latest) (push) Blocked by required conditions
CI / cargo test (wasm) (push) Blocked by required conditions
CI / cargo build (msrv) (push) Blocked by required conditions
CI / cargo fuzz build (push) Blocked by required conditions
CI / fuzz parser (push) Blocked by required conditions
CI / test scripts (push) Blocked by required conditions
CI / ecosystem (push) Blocked by required conditions
CI / benchmarks instrumented (ty) (push) Blocked by required conditions
CI / Fuzz for new ty panics (push) Blocked by required conditions
CI / cargo shear (push) Blocked by required conditions
CI / ty completion evaluation (push) Blocked by required conditions
CI / python package (push) Waiting to run
CI / pre-commit (push) Waiting to run
CI / mkdocs (push) Waiting to run
CI / formatter instabilities and black similarity (push) Blocked by required conditions
CI / test ruff-lsp (push) Blocked by required conditions
CI / check playground (push) Blocked by required conditions
CI / benchmarks instrumented (ruff) (push) Blocked by required conditions
CI / benchmarks walltime (medium|multithreaded) (push) Blocked by required conditions
CI / benchmarks walltime (small|large) (push) Blocked by required conditions
[ty Playground] Release / publish (push) Waiting to run

This commit is contained in:
Alex Waygood 2025-11-13 17:14:54 +00:00 committed by GitHub
parent 99694b6e4a
commit 90b32f3b3b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 115 additions and 5 deletions

View file

@ -396,3 +396,34 @@ B = NewType("B", list[Any])
T = TypeVar("T")
C = NewType("C", list[T]) # TODO: should be "error: [invalid-newtype]"
```
## Forward references in stub files
Stubs natively support forward references, so patterns that would raise `NameError` at runtime are
allowed in stub files:
`stub.pyi`:
```pyi
from typing import NewType
N = NewType("N", A)
class A: ...
```
`main.py`:
```py
from stub import N, A
n = N(A()) # fine
def f(x: A): ...
f(n) # fine
class Invalid: ...
bad = N(Invalid()) # error: [invalid-argument-type]
```

View file

@ -266,7 +266,48 @@ from typing import TypeVar
# error: [invalid-legacy-type-variable]
T = TypeVar("T", invalid_keyword=True)
```
### Forward references in stubs
Stubs natively support forward references, so patterns that would raise `NameError` at runtime are
allowed in stub files:
`stub.pyi`:
```pyi
from typing import TypeVar
T = TypeVar("T", bound=A, default=B)
U = TypeVar("U", C, D)
class A: ...
class B(A): ...
class C: ...
class D: ...
def f(x: T) -> T: ...
def g(x: U) -> U: ...
```
`main.py`:
```py
from stub import f, g, A, B, C, D
reveal_type(f(A())) # revealed: A
reveal_type(f(B())) # revealed: B
reveal_type(g(C())) # revealed: C
reveal_type(g(D())) # revealed: D
# TODO: one diagnostic would probably be sufficient here...?
#
# error: [invalid-argument-type] "Argument type `C` does not satisfy upper bound `A` of type variable `T`"
# error: [invalid-argument-type] "Argument to function `f` is incorrect: Expected `B`, found `C`"
reveal_type(f(C())) # revealed: B
# error: [invalid-argument-type]
reveal_type(g(A())) # revealed: Unknown
```
### Constructor signature versioning

View file

@ -82,7 +82,7 @@ def _(x: int | str | bytes | memoryview | range):
if isinstance(x, int | str):
reveal_type(x) # revealed: int | str
elif isinstance(x, bytes | memoryview):
reveal_type(x) # revealed: bytes | memoryview[Unknown]
reveal_type(x) # revealed: bytes | memoryview[int]
else:
reveal_type(x) # revealed: range
```
@ -242,11 +242,11 @@ def _(flag: bool):
def _(flag: bool):
x = 1 if flag else "a"
# error: [invalid-argument-type] "Argument to function `isinstance` is incorrect: Expected `type | UnionType | tuple[Unknown, ...]`, found `Literal["a"]"
# error: [invalid-argument-type] "Argument to function `isinstance` is incorrect: Expected `type | UnionType | tuple[Divergent, ...]`, found `Literal["a"]"
if isinstance(x, "a"):
reveal_type(x) # revealed: Literal[1, "a"]
# error: [invalid-argument-type] "Argument to function `isinstance` is incorrect: Expected `type | UnionType | tuple[Unknown, ...]`, found `Literal["int"]"
# error: [invalid-argument-type] "Argument to function `isinstance` is incorrect: Expected `type | UnionType | tuple[Divergent, ...]`, found `Literal["int"]"
if isinstance(x, "int"):
reveal_type(x) # revealed: Literal[1, "a"]
```

View file

@ -283,7 +283,7 @@ def flag() -> bool:
t = int if flag() else str
# error: [invalid-argument-type] "Argument to function `issubclass` is incorrect: Expected `type | UnionType | tuple[Unknown, ...]`, found `Literal["str"]"
# error: [invalid-argument-type] "Argument to function `issubclass` is incorrect: Expected `type | UnionType | tuple[Divergent, ...]`, found `Literal["str"]"
if issubclass(t, "str"):
reveal_type(t) # revealed: <class 'int'> | <class 'str'>

View file

@ -102,6 +102,20 @@ Other values are invalid.
P4 = ParamSpec("P4", default=int)
```
### Forward references in stub files
Stubs natively support forward references, so patterns that would raise `NameError` at runtime are
allowed in stub files:
```pyi
from typing_extensions import ParamSpec
P = ParamSpec("P", default=[A, B])
class A: ...
class B: ...
```
### PEP 695
```toml