mirror of
https://github.com/astral-sh/ruff.git
synced 2025-08-04 18:58:04 +00:00
[ty] Experiment: half-baked typing.TypeAlias support
This commit is contained in:
parent
f9ca6eb63e
commit
9220598fc8
13 changed files with 48 additions and 28 deletions
|
@ -16,7 +16,8 @@ Alias: TypeAlias = int
|
|||
|
||||
def f(*args: Unpack[Ts]) -> tuple[Unpack[Ts]]:
|
||||
reveal_type(args) # revealed: tuple[@Todo(`Unpack[]` special form), ...]
|
||||
reveal_type(Alias) # revealed: @Todo(Support for `typing.TypeAlias`)
|
||||
# TODO: this is not correct. At runtime, this is `type` (`Alias` is just `<class 'int'>`).
|
||||
reveal_type(Alias) # revealed: typing.TypeAliasType
|
||||
|
||||
def g() -> TypeGuard[int]: ...
|
||||
def h() -> TypeIs[int]: ...
|
||||
|
|
|
@ -1736,9 +1736,9 @@ reveal_type(False.real) # revealed: Literal[0]
|
|||
All attribute access on literal `bytes` types is currently delegated to `builtins.bytes`:
|
||||
|
||||
```py
|
||||
# revealed: bound method Literal[b"foo"].join(iterable_of_bytes: Iterable[@Todo(Support for `typing.TypeAlias`)], /) -> bytes
|
||||
# revealed: bound method Literal[b"foo"].join(iterable_of_bytes: Iterable[Buffer], /) -> bytes
|
||||
reveal_type(b"foo".join)
|
||||
# revealed: bound method Literal[b"foo"].endswith(suffix: @Todo(Support for `typing.TypeAlias`) | tuple[@Todo(Support for `typing.TypeAlias`), ...], start: SupportsIndex | None = ellipsis, end: SupportsIndex | None = ellipsis, /) -> bool
|
||||
# revealed: bound method Literal[b"foo"].endswith(suffix: Buffer | tuple[Buffer, ...], start: SupportsIndex | None = ellipsis, end: SupportsIndex | None = ellipsis, /) -> bool
|
||||
reveal_type(b"foo".endswith)
|
||||
```
|
||||
|
||||
|
|
|
@ -313,8 +313,7 @@ reveal_type(A() + "foo") # revealed: A
|
|||
reveal_type("foo" + A()) # revealed: A
|
||||
|
||||
reveal_type(A() + b"foo") # revealed: A
|
||||
# TODO should be `A` since `bytes.__add__` doesn't support `A` instances
|
||||
reveal_type(b"foo" + A()) # revealed: bytes
|
||||
reveal_type(b"foo" + A()) # revealed: A
|
||||
|
||||
reveal_type(A() + ()) # revealed: A
|
||||
reveal_type(() + A()) # revealed: A
|
||||
|
|
|
@ -54,10 +54,8 @@ reveal_type(2**largest_u32) # revealed: int
|
|||
|
||||
def variable(x: int):
|
||||
reveal_type(x**2) # revealed: int
|
||||
# TODO: should be `Any` (overload 5 on `__pow__`), requires correct overload matching
|
||||
reveal_type(2**x) # revealed: int
|
||||
# TODO: should be `Any` (overload 5 on `__pow__`), requires correct overload matching
|
||||
reveal_type(x**x) # revealed: int
|
||||
reveal_type(2**x) # revealed: Any
|
||||
reveal_type(x**x) # revealed: Any
|
||||
```
|
||||
|
||||
If the second argument is \<0, a `float` is returned at runtime. If the first argument is \<0 but
|
||||
|
|
|
@ -146,13 +146,11 @@ def _(flag: bool):
|
|||
def _(flag: bool):
|
||||
x = 1 if flag else "a"
|
||||
|
||||
# TODO: this should cause us to emit a diagnostic during
|
||||
# type checking
|
||||
# error: [invalid-argument-type]
|
||||
if isinstance(x, "a"):
|
||||
reveal_type(x) # revealed: Literal[1, "a"]
|
||||
|
||||
# TODO: this should cause us to emit a diagnostic during
|
||||
# type checking
|
||||
# error: [invalid-argument-type]
|
||||
if isinstance(x, "int"):
|
||||
reveal_type(x) # revealed: Literal[1, "a"]
|
||||
```
|
||||
|
|
|
@ -214,8 +214,7 @@ def flag() -> bool:
|
|||
|
||||
t = int if flag() else str
|
||||
|
||||
# TODO: this should cause us to emit a diagnostic during
|
||||
# type checking
|
||||
# error: [invalid-argument-type]
|
||||
if issubclass(t, "str"):
|
||||
reveal_type(t) # revealed: <class 'int'> | <class 'str'>
|
||||
|
||||
|
|
|
@ -28,7 +28,7 @@ def f() -> None:
|
|||
```py
|
||||
type IntOrStr = int | str
|
||||
|
||||
reveal_type(IntOrStr.__value__) # revealed: @Todo(Support for `typing.TypeAlias`)
|
||||
reveal_type(IntOrStr.__value__) # revealed: Any
|
||||
```
|
||||
|
||||
## Invalid assignment
|
||||
|
|
|
@ -243,7 +243,8 @@ def f(
|
|||
Nonetheless, `Protocol` can still be used as the second argument to `issubclass()` at runtime:
|
||||
|
||||
```py
|
||||
# Could also be `Literal[True]`, but `bool` is fine:
|
||||
# TODO: Should be `Literal[True]`, but `bool` is also fine
|
||||
# error: [invalid-argument-type]
|
||||
reveal_type(issubclass(MyProtocol, Protocol)) # revealed: bool
|
||||
```
|
||||
|
||||
|
|
|
@ -122,7 +122,7 @@ properties on instance types:
|
|||
|
||||
```py
|
||||
reveal_type(sys.version_info.micro) # revealed: int
|
||||
reveal_type(sys.version_info.releaselevel) # revealed: @Todo(Support for `typing.TypeAlias`)
|
||||
reveal_type(sys.version_info.releaselevel) # revealed: Literal["alpha", "beta", "candidate", "final"]
|
||||
reveal_type(sys.version_info.serial) # revealed: int
|
||||
```
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
Tanjun # hangs
|
||||
alerta # too many iterations
|
||||
antidote # hangs / slow
|
||||
artigraph # cycle panics (value_type_)
|
||||
core # cycle panics (value_type_)
|
||||
|
@ -6,21 +7,29 @@ cpython # access to field whilst being initialized, too many cycle iterations
|
|||
discord.py # some kind of hang, only when multi-threaded?
|
||||
freqtrade # hangs
|
||||
hydpy # too many iterations
|
||||
hydra-zen # too many iterations
|
||||
ibis # too many iterations
|
||||
isort # too many iterations
|
||||
jax # too many iterations
|
||||
meson # too many iterations
|
||||
mypy # too many iterations
|
||||
packaging # too many iterations
|
||||
pandas # slow
|
||||
pandas-stubs # hangs/slow, or else https://github.com/salsa-rs/salsa/issues/831
|
||||
pandera # stack overflow
|
||||
pip # vendors packaging, see above
|
||||
prefect # slow
|
||||
psycopg2 # too many iterations
|
||||
pydantic # too many iterations
|
||||
pylint # cycle panics (self-recursive type alias)
|
||||
pyodide # too many cycle iterations
|
||||
pywin32 # bad use-def map (binding with definitely-visible unbound)
|
||||
schemathesis # https://github.com/salsa-rs/salsa/issues/831
|
||||
scikit-learn # success, but mypy-primer hangs processing the output
|
||||
scipy # slow / hangs
|
||||
setuptools # vendors packaging, see above
|
||||
spack # success, but mypy-primer hangs processing the output
|
||||
spark # too many iterations
|
||||
steam.py # hangs
|
||||
strawberry # too many iterations
|
||||
xarray # too many iterations
|
||||
|
|
|
@ -8,7 +8,6 @@ aiohttp-devtools
|
|||
aioredis
|
||||
aiortc
|
||||
alectryon
|
||||
alerta
|
||||
altair
|
||||
anyio
|
||||
apprise
|
||||
|
@ -41,10 +40,8 @@ flake8-pyi
|
|||
git-revise
|
||||
graphql-core
|
||||
httpx-caching
|
||||
hydra-zen
|
||||
ignite
|
||||
imagehash
|
||||
isort
|
||||
itsdangerous
|
||||
janus
|
||||
jinja
|
||||
|
@ -53,13 +50,11 @@ kopf
|
|||
kornia
|
||||
manticore
|
||||
materialize
|
||||
meson
|
||||
mitmproxy
|
||||
mkdocs
|
||||
mkosi
|
||||
mongo-python-driver
|
||||
more-itertools
|
||||
mypy
|
||||
mypy-protobuf
|
||||
mypy_primer
|
||||
nionutils
|
||||
|
@ -74,11 +69,9 @@ pegen
|
|||
poetry
|
||||
porcupine
|
||||
ppb-vector
|
||||
psycopg
|
||||
pwndbg
|
||||
pybind11
|
||||
pycryptodome
|
||||
pydantic
|
||||
pyinstrument
|
||||
pyjwt
|
||||
pylox
|
||||
|
@ -93,7 +86,6 @@ rclip
|
|||
rich
|
||||
rotki
|
||||
schema_salad
|
||||
scipy
|
||||
scrapy
|
||||
sockeye
|
||||
speedrun.com_global_scoreboard_webapp
|
||||
|
@ -101,7 +93,6 @@ sphinx
|
|||
starlette
|
||||
static-frame
|
||||
stone
|
||||
strawberry
|
||||
streamlit
|
||||
sympy
|
||||
tornado
|
||||
|
|
|
@ -4922,7 +4922,9 @@ impl<'db> Type<'db> {
|
|||
TypeVarKind::Legacy,
|
||||
)))
|
||||
}
|
||||
KnownInstanceType::TypeAlias => Ok(todo_type!("Support for `typing.TypeAlias`")),
|
||||
KnownInstanceType::TypeAlias => {
|
||||
Ok(Type::KnownInstance(KnownInstanceType::TypeAlias))
|
||||
}
|
||||
KnownInstanceType::TypedDict => Ok(todo_type!("Support for `typing.TypedDict`")),
|
||||
|
||||
KnownInstanceType::Protocol(_) => Err(InvalidTypeExpressionError {
|
||||
|
|
|
@ -3575,7 +3575,29 @@ impl<'db> TypeInferenceBuilder<'db> {
|
|||
debug_assert!(target.is_name_expr());
|
||||
|
||||
if let Some(value) = value {
|
||||
if declared_ty.inner_type() == Type::KnownInstance(KnownInstanceType::TypeAlias) {
|
||||
let value_ty = self.infer_type_expression(value);
|
||||
|
||||
let type_alias_ty = Type::KnownInstance(KnownInstanceType::TypeAliasType(
|
||||
TypeAliasType::Bare(BareTypeAliasType::new(
|
||||
self.db(),
|
||||
ast::name::Name::new("dummy"),
|
||||
Some(definition),
|
||||
value_ty,
|
||||
)),
|
||||
));
|
||||
|
||||
self.add_declaration_with_binding(
|
||||
target.into(),
|
||||
definition,
|
||||
&DeclaredAndInferredType::AreTheSame(type_alias_ty),
|
||||
);
|
||||
self.store_expression_type(target, type_alias_ty);
|
||||
return;
|
||||
}
|
||||
|
||||
let inferred_ty = self.infer_expression(value);
|
||||
|
||||
let inferred_ty = if target
|
||||
.as_name_expr()
|
||||
.is_some_and(|name| &name.id == "TYPE_CHECKING")
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue