mirror of
https://github.com/astral-sh/ruff.git
synced 2025-11-18 03:36:18 +00:00
[ty] support imported PEP 613 type aliases
This commit is contained in:
parent
fb5b8c3653
commit
df0c8e202d
20 changed files with 297 additions and 252 deletions
|
|
@ -143,7 +143,7 @@ static FREQTRADE: Benchmark = Benchmark::new(
|
||||||
max_dep_date: "2025-06-17",
|
max_dep_date: "2025-06-17",
|
||||||
python_version: PythonVersion::PY312,
|
python_version: PythonVersion::PY312,
|
||||||
},
|
},
|
||||||
525,
|
600,
|
||||||
);
|
);
|
||||||
|
|
||||||
static PANDAS: Benchmark = Benchmark::new(
|
static PANDAS: Benchmark = Benchmark::new(
|
||||||
|
|
@ -163,7 +163,7 @@ static PANDAS: Benchmark = Benchmark::new(
|
||||||
max_dep_date: "2025-06-17",
|
max_dep_date: "2025-06-17",
|
||||||
python_version: PythonVersion::PY312,
|
python_version: PythonVersion::PY312,
|
||||||
},
|
},
|
||||||
3000,
|
4000,
|
||||||
);
|
);
|
||||||
|
|
||||||
static PYDANTIC: Benchmark = Benchmark::new(
|
static PYDANTIC: Benchmark = Benchmark::new(
|
||||||
|
|
@ -181,7 +181,7 @@ static PYDANTIC: Benchmark = Benchmark::new(
|
||||||
max_dep_date: "2025-06-17",
|
max_dep_date: "2025-06-17",
|
||||||
python_version: PythonVersion::PY39,
|
python_version: PythonVersion::PY39,
|
||||||
},
|
},
|
||||||
5000,
|
7000,
|
||||||
);
|
);
|
||||||
|
|
||||||
static SYMPY: Benchmark = Benchmark::new(
|
static SYMPY: Benchmark = Benchmark::new(
|
||||||
|
|
|
||||||
|
|
@ -12,11 +12,8 @@ P = ParamSpec("P")
|
||||||
Ts = TypeVarTuple("Ts")
|
Ts = TypeVarTuple("Ts")
|
||||||
R_co = TypeVar("R_co", covariant=True)
|
R_co = TypeVar("R_co", covariant=True)
|
||||||
|
|
||||||
Alias: TypeAlias = int
|
|
||||||
|
|
||||||
def f(*args: Unpack[Ts]) -> tuple[Unpack[Ts]]:
|
def f(*args: Unpack[Ts]) -> tuple[Unpack[Ts]]:
|
||||||
reveal_type(args) # revealed: tuple[@Todo(`Unpack[]` special form), ...]
|
reveal_type(args) # revealed: tuple[@Todo(`Unpack[]` special form), ...]
|
||||||
reveal_type(Alias) # revealed: @Todo(Support for `typing.TypeAlias`)
|
|
||||||
return args
|
return args
|
||||||
|
|
||||||
def g() -> TypeGuard[int]: ...
|
def g() -> TypeGuard[int]: ...
|
||||||
|
|
|
||||||
|
|
@ -2208,9 +2208,9 @@ reveal_type(False.real) # revealed: Literal[0]
|
||||||
All attribute access on literal `bytes` types is currently delegated to `builtins.bytes`:
|
All attribute access on literal `bytes` types is currently delegated to `builtins.bytes`:
|
||||||
|
|
||||||
```py
|
```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)
|
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 = None, end: SupportsIndex | None = None, /) -> bool
|
# revealed: bound method Literal[b"foo"].endswith(suffix: Buffer | tuple[Buffer, ...], start: SupportsIndex | None = None, end: SupportsIndex | None = None, /) -> bool
|
||||||
reveal_type(b"foo".endswith)
|
reveal_type(b"foo".endswith)
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -313,8 +313,7 @@ reveal_type(A() + "foo") # revealed: A
|
||||||
reveal_type("foo" + A()) # revealed: A
|
reveal_type("foo" + A()) # revealed: A
|
||||||
|
|
||||||
reveal_type(A() + b"foo") # 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: A
|
||||||
reveal_type(b"foo" + A()) # revealed: bytes
|
|
||||||
|
|
||||||
reveal_type(A() + ()) # revealed: A
|
reveal_type(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):
|
def variable(x: int):
|
||||||
reveal_type(x**2) # revealed: int
|
reveal_type(x**2) # revealed: int
|
||||||
# TODO: should be `Any` (overload 5 on `__pow__`), requires correct overload matching
|
reveal_type(2**x) # revealed: Any
|
||||||
reveal_type(2**x) # revealed: int
|
reveal_type(x**x) # revealed: Any
|
||||||
# TODO: should be `Any` (overload 5 on `__pow__`), requires correct overload matching
|
|
||||||
reveal_type(x**x) # revealed: int
|
|
||||||
```
|
```
|
||||||
|
|
||||||
If the second argument is \<0, a `float` is returned at runtime. If the first argument is \<0 but
|
If the second argument is \<0, a `float` is returned at runtime. If the first argument is \<0 but
|
||||||
|
|
|
||||||
|
|
@ -598,9 +598,9 @@ from typing_extensions import Self
|
||||||
|
|
||||||
reveal_type(object.__new__) # revealed: def __new__(cls) -> Self@__new__
|
reveal_type(object.__new__) # revealed: def __new__(cls) -> Self@__new__
|
||||||
reveal_type(object().__new__) # revealed: def __new__(cls) -> Self@__new__
|
reveal_type(object().__new__) # revealed: def __new__(cls) -> Self@__new__
|
||||||
# revealed: Overload[(cls, x: @Todo(Support for `typing.TypeAlias`) = Literal[0], /) -> Self@__new__, (cls, x: str | bytes | bytearray, /, base: SupportsIndex) -> Self@__new__]
|
# revealed: Overload[(cls, x: str | Buffer | SupportsInt | SupportsIndex | SupportsTrunc = Literal[0], /) -> Self@__new__, (cls, x: str | bytes | bytearray, /, base: SupportsIndex) -> Self@__new__]
|
||||||
reveal_type(int.__new__)
|
reveal_type(int.__new__)
|
||||||
# revealed: Overload[(cls, x: @Todo(Support for `typing.TypeAlias`) = Literal[0], /) -> Self@__new__, (cls, x: str | bytes | bytearray, /, base: SupportsIndex) -> Self@__new__]
|
# revealed: Overload[(cls, x: str | Buffer | SupportsInt | SupportsIndex | SupportsTrunc = Literal[0], /) -> Self@__new__, (cls, x: str | bytes | bytearray, /, base: SupportsIndex) -> Self@__new__]
|
||||||
reveal_type((42).__new__)
|
reveal_type((42).__new__)
|
||||||
|
|
||||||
class X:
|
class X:
|
||||||
|
|
|
||||||
|
|
@ -10,13 +10,13 @@ import pickle
|
||||||
|
|
||||||
reveal_type(open("")) # revealed: TextIOWrapper[_WrappedBuffer]
|
reveal_type(open("")) # revealed: TextIOWrapper[_WrappedBuffer]
|
||||||
reveal_type(open("", "r")) # revealed: TextIOWrapper[_WrappedBuffer]
|
reveal_type(open("", "r")) # revealed: TextIOWrapper[_WrappedBuffer]
|
||||||
reveal_type(open("", "rb")) # revealed: @Todo(`builtins.open` return type)
|
reveal_type(open("", "rb")) # revealed: BufferedReader[_BufferedReaderStream]
|
||||||
|
|
||||||
with open("foo.pickle", "rb") as f:
|
with open("foo.pickle", "rb") as f:
|
||||||
x = pickle.load(f) # fine
|
x = pickle.load(f) # fine
|
||||||
|
|
||||||
def _(mode: str):
|
def _(mode: str):
|
||||||
reveal_type(open("", mode)) # revealed: @Todo(`builtins.open` return type)
|
reveal_type(open("", mode)) # revealed: IO[Any]
|
||||||
```
|
```
|
||||||
|
|
||||||
## `os.fdopen`
|
## `os.fdopen`
|
||||||
|
|
@ -29,7 +29,7 @@ import os
|
||||||
|
|
||||||
reveal_type(os.fdopen(0)) # revealed: TextIOWrapper[_WrappedBuffer]
|
reveal_type(os.fdopen(0)) # revealed: TextIOWrapper[_WrappedBuffer]
|
||||||
reveal_type(os.fdopen(0, "r")) # revealed: TextIOWrapper[_WrappedBuffer]
|
reveal_type(os.fdopen(0, "r")) # revealed: TextIOWrapper[_WrappedBuffer]
|
||||||
reveal_type(os.fdopen(0, "rb")) # revealed: @Todo(`os.fdopen` return type)
|
reveal_type(os.fdopen(0, "rb")) # revealed: BufferedReader[_BufferedReaderStream]
|
||||||
|
|
||||||
with os.fdopen(0, "rb") as f:
|
with os.fdopen(0, "rb") as f:
|
||||||
x = pickle.load(f) # fine
|
x = pickle.load(f) # fine
|
||||||
|
|
@ -43,9 +43,9 @@ And similarly for `Path.open()`:
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
import pickle
|
import pickle
|
||||||
|
|
||||||
reveal_type(Path("").open()) # revealed: @Todo(`Path.open` return type)
|
reveal_type(Path("").open()) # revealed: TextIOWrapper[_WrappedBuffer]
|
||||||
reveal_type(Path("").open("r")) # revealed: @Todo(`Path.open` return type)
|
reveal_type(Path("").open("r")) # revealed: TextIOWrapper[_WrappedBuffer]
|
||||||
reveal_type(Path("").open("rb")) # revealed: @Todo(`Path.open` return type)
|
reveal_type(Path("").open("rb")) # revealed: BufferedReader[_BufferedReaderStream]
|
||||||
|
|
||||||
with Path("foo.pickle").open("rb") as f:
|
with Path("foo.pickle").open("rb") as f:
|
||||||
x = pickle.load(f) # fine
|
x = pickle.load(f) # fine
|
||||||
|
|
@ -61,7 +61,7 @@ import pickle
|
||||||
|
|
||||||
reveal_type(NamedTemporaryFile()) # revealed: _TemporaryFileWrapper[bytes]
|
reveal_type(NamedTemporaryFile()) # revealed: _TemporaryFileWrapper[bytes]
|
||||||
reveal_type(NamedTemporaryFile("r")) # revealed: _TemporaryFileWrapper[str]
|
reveal_type(NamedTemporaryFile("r")) # revealed: _TemporaryFileWrapper[str]
|
||||||
reveal_type(NamedTemporaryFile("rb")) # revealed: @Todo(`tempfile.NamedTemporaryFile` return type)
|
reveal_type(NamedTemporaryFile("rb")) # revealed: _TemporaryFileWrapper[bytes]
|
||||||
|
|
||||||
with NamedTemporaryFile("rb") as f:
|
with NamedTemporaryFile("rb") as f:
|
||||||
x = pickle.load(f) # fine
|
x = pickle.load(f) # fine
|
||||||
|
|
|
||||||
|
|
@ -127,7 +127,7 @@ x = lambda y: y
|
||||||
reveal_type(x.__code__) # revealed: CodeType
|
reveal_type(x.__code__) # revealed: CodeType
|
||||||
reveal_type(x.__name__) # revealed: str
|
reveal_type(x.__name__) # revealed: str
|
||||||
reveal_type(x.__defaults__) # revealed: tuple[Any, ...] | None
|
reveal_type(x.__defaults__) # revealed: tuple[Any, ...] | None
|
||||||
reveal_type(x.__annotations__) # revealed: dict[str, @Todo(Support for `typing.TypeAlias`)]
|
reveal_type(x.__annotations__) # revealed: dict[str, Any]
|
||||||
reveal_type(x.__dict__) # revealed: dict[str, Any]
|
reveal_type(x.__dict__) # revealed: dict[str, Any]
|
||||||
reveal_type(x.__doc__) # revealed: str | None
|
reveal_type(x.__doc__) # revealed: str | None
|
||||||
reveal_type(x.__kwdefaults__) # revealed: dict[str, Any] | None
|
reveal_type(x.__kwdefaults__) # revealed: dict[str, Any] | None
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,82 @@
|
||||||
# PEP 613 type aliases
|
# PEP 613 type aliases
|
||||||
|
|
||||||
## No panics
|
PEP 613 type aliases are simple assignment statements, annotated with `typing.TypeAlias` to mark
|
||||||
|
them as a type alias. At runtime, they behave the same as implicit type aliases. Our support for
|
||||||
|
them is currently the same as for implicit type aliases, but we don't reproduce the full
|
||||||
|
implicit-type-alias test suite here, just some particularly interesting cases.
|
||||||
|
|
||||||
We do not fully support PEP 613 type aliases yet. For now, just make sure that we don't panic:
|
## Basic
|
||||||
|
|
||||||
|
### as `TypeAlias`
|
||||||
|
|
||||||
|
```py
|
||||||
|
from typing import TypeAlias
|
||||||
|
|
||||||
|
IntOrStr: TypeAlias = int | str
|
||||||
|
|
||||||
|
def _(x: IntOrStr):
|
||||||
|
reveal_type(x) # revealed: int | str
|
||||||
|
```
|
||||||
|
|
||||||
|
### as `typing.TypeAlias`
|
||||||
|
|
||||||
|
```py
|
||||||
|
import typing
|
||||||
|
|
||||||
|
IntOrStr: typing.TypeAlias = int | str
|
||||||
|
|
||||||
|
def _(x: IntOrStr):
|
||||||
|
reveal_type(x) # revealed: int | str
|
||||||
|
```
|
||||||
|
|
||||||
|
## Can be used as value
|
||||||
|
|
||||||
|
Because PEP 613 type aliases are just annotated assignments, they can be used as values, like a
|
||||||
|
legacy type expression (and unlike a PEP 695 type alias). We might prefer this wasn't allowed, but
|
||||||
|
people do use it.
|
||||||
|
|
||||||
|
```py
|
||||||
|
from typing import TypeAlias
|
||||||
|
|
||||||
|
MyExc: TypeAlias = Exception
|
||||||
|
|
||||||
|
try:
|
||||||
|
raise MyExc("error")
|
||||||
|
except MyExc as e:
|
||||||
|
reveal_type(e) # revealed: Exception
|
||||||
|
```
|
||||||
|
|
||||||
|
## Imported
|
||||||
|
|
||||||
|
`alias.py`:
|
||||||
|
|
||||||
|
```py
|
||||||
|
from typing import TypeAlias
|
||||||
|
|
||||||
|
MyAlias: TypeAlias = int | str
|
||||||
|
```
|
||||||
|
|
||||||
|
`main.py`:
|
||||||
|
|
||||||
|
```py
|
||||||
|
from alias import MyAlias
|
||||||
|
|
||||||
|
def _(x: MyAlias):
|
||||||
|
reveal_type(x) # revealed: int | str
|
||||||
|
```
|
||||||
|
|
||||||
|
## String literal in RHS
|
||||||
|
|
||||||
|
```py
|
||||||
|
from typing import TypeAlias
|
||||||
|
|
||||||
|
IntOrStr: TypeAlias = "int | str"
|
||||||
|
|
||||||
|
def _(x: IntOrStr):
|
||||||
|
reveal_type(x) # revealed: int | str
|
||||||
|
```
|
||||||
|
|
||||||
|
## Cyclic
|
||||||
|
|
||||||
```py
|
```py
|
||||||
from typing import TypeAlias
|
from typing import TypeAlias
|
||||||
|
|
@ -18,6 +92,26 @@ def _(rec: RecursiveHomogeneousTuple):
|
||||||
reveal_type(rec) # revealed: tuple[Divergent, ...]
|
reveal_type(rec) # revealed: tuple[Divergent, ...]
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Conditionally imported on Python < 3.10
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[environment]
|
||||||
|
python-version = "3.9"
|
||||||
|
```
|
||||||
|
|
||||||
|
```py
|
||||||
|
try:
|
||||||
|
# error: [unresolved-import]
|
||||||
|
from typing import TypeAlias
|
||||||
|
except ImportError:
|
||||||
|
from typing_extensions import TypeAlias
|
||||||
|
|
||||||
|
MyAlias: TypeAlias = int
|
||||||
|
|
||||||
|
def _(x: MyAlias):
|
||||||
|
reveal_type(x) # revealed: int
|
||||||
|
```
|
||||||
|
|
||||||
## PEP-613 aliases in stubs are deferred
|
## PEP-613 aliases in stubs are deferred
|
||||||
|
|
||||||
Although the right-hand side of a PEP-613 alias is a value expression, inference of this value is
|
Although the right-hand side of a PEP-613 alias is a value expression, inference of this value is
|
||||||
|
|
@ -46,7 +140,31 @@ f(stub.B())
|
||||||
|
|
||||||
class Unrelated: ...
|
class Unrelated: ...
|
||||||
|
|
||||||
# TODO: we should emit `[invalid-argument-type]` here
|
# error: [invalid-argument-type]
|
||||||
# (the alias is a `@Todo` because it's imported from another file)
|
|
||||||
f(Unrelated())
|
f(Unrelated())
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Invalid position
|
||||||
|
|
||||||
|
`typing.TypeAlias` must be used as the sole annotation in an annotated assignment. Use in any other
|
||||||
|
context is an error.
|
||||||
|
|
||||||
|
```py
|
||||||
|
from typing import TypeAlias
|
||||||
|
|
||||||
|
# error: [invalid-type-form]
|
||||||
|
def _(x: TypeAlias):
|
||||||
|
reveal_type(x) # revealed: Unknown
|
||||||
|
|
||||||
|
# error: [invalid-type-form]
|
||||||
|
y: list[TypeAlias] = []
|
||||||
|
```
|
||||||
|
|
||||||
|
## RHS is required
|
||||||
|
|
||||||
|
```py
|
||||||
|
from typing import TypeAlias
|
||||||
|
|
||||||
|
# error: [invalid-type-form]
|
||||||
|
Empty: TypeAlias
|
||||||
|
```
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,7 @@ def f() -> None:
|
||||||
```py
|
```py
|
||||||
type IntOrStr = int | str
|
type IntOrStr = int | str
|
||||||
|
|
||||||
reveal_type(IntOrStr.__value__) # revealed: @Todo(Support for `typing.TypeAlias`)
|
reveal_type(IntOrStr.__value__) # revealed: Any
|
||||||
```
|
```
|
||||||
|
|
||||||
## Invalid assignment
|
## Invalid assignment
|
||||||
|
|
|
||||||
|
|
@ -122,7 +122,7 @@ properties on instance types:
|
||||||
|
|
||||||
```py
|
```py
|
||||||
reveal_type(sys.version_info.micro) # revealed: int
|
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
|
reveal_type(sys.version_info.serial) # revealed: int
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4369,11 +4369,6 @@ impl<'db> Type<'db> {
|
||||||
Type::KnownBoundMethod(KnownBoundMethodType::StrStartswith(literal)),
|
Type::KnownBoundMethod(KnownBoundMethodType::StrStartswith(literal)),
|
||||||
)
|
)
|
||||||
.into(),
|
.into(),
|
||||||
Type::NominalInstance(instance)
|
|
||||||
if instance.has_known_class(db, KnownClass::Path) && name == "open" =>
|
|
||||||
{
|
|
||||||
Place::bound(Type::KnownBoundMethod(KnownBoundMethodType::PathOpen)).into()
|
|
||||||
}
|
|
||||||
|
|
||||||
Type::ClassLiteral(class)
|
Type::ClassLiteral(class)
|
||||||
if name == "range" && class.is_known(db, KnownClass::ConstraintSet) =>
|
if name == "range" && class.is_known(db, KnownClass::ConstraintSet) =>
|
||||||
|
|
@ -6737,6 +6732,7 @@ impl<'db> Type<'db> {
|
||||||
|
|
||||||
Ok(ty.inner(db).to_meta_type(db))
|
Ok(ty.inner(db).to_meta_type(db))
|
||||||
}
|
}
|
||||||
|
KnownInstanceType::LiteralStringAlias(ty) => Ok(ty.inner(db)),
|
||||||
},
|
},
|
||||||
|
|
||||||
Type::SpecialForm(special_form) => match special_form {
|
Type::SpecialForm(special_form) => match special_form {
|
||||||
|
|
@ -6791,7 +6787,15 @@ impl<'db> Type<'db> {
|
||||||
|
|
||||||
Ok(typing_self(db, scope_id, typevar_binding_context, class).unwrap_or(*self))
|
Ok(typing_self(db, scope_id, typevar_binding_context, class).unwrap_or(*self))
|
||||||
}
|
}
|
||||||
SpecialFormType::TypeAlias => Ok(Type::Dynamic(DynamicType::TodoTypeAlias)),
|
// We ensure that `typing.TypeAlias` used in the expected position (annotating an
|
||||||
|
// annotated assignment statement) doesn't reach here. Using it in any other type
|
||||||
|
// expression is an error.
|
||||||
|
SpecialFormType::TypeAlias => Err(InvalidTypeExpressionError {
|
||||||
|
invalid_expressions: smallvec::smallvec_inline![
|
||||||
|
InvalidTypeExpression::TypeAlias
|
||||||
|
],
|
||||||
|
fallback_type: Type::unknown(),
|
||||||
|
}),
|
||||||
SpecialFormType::TypedDict => Err(InvalidTypeExpressionError {
|
SpecialFormType::TypedDict => Err(InvalidTypeExpressionError {
|
||||||
invalid_expressions: smallvec::smallvec_inline![
|
invalid_expressions: smallvec::smallvec_inline![
|
||||||
InvalidTypeExpression::TypedDict
|
InvalidTypeExpression::TypedDict
|
||||||
|
|
@ -7269,7 +7273,6 @@ impl<'db> Type<'db> {
|
||||||
| Type::WrapperDescriptor(_)
|
| Type::WrapperDescriptor(_)
|
||||||
| Type::KnownBoundMethod(
|
| Type::KnownBoundMethod(
|
||||||
KnownBoundMethodType::StrStartswith(_)
|
KnownBoundMethodType::StrStartswith(_)
|
||||||
| KnownBoundMethodType::PathOpen
|
|
||||||
| KnownBoundMethodType::ConstraintSetRange
|
| KnownBoundMethodType::ConstraintSetRange
|
||||||
| KnownBoundMethodType::ConstraintSetAlways
|
| KnownBoundMethodType::ConstraintSetAlways
|
||||||
| KnownBoundMethodType::ConstraintSetNever
|
| KnownBoundMethodType::ConstraintSetNever
|
||||||
|
|
@ -7429,7 +7432,6 @@ impl<'db> Type<'db> {
|
||||||
| Type::WrapperDescriptor(_)
|
| Type::WrapperDescriptor(_)
|
||||||
| Type::KnownBoundMethod(
|
| Type::KnownBoundMethod(
|
||||||
KnownBoundMethodType::StrStartswith(_)
|
KnownBoundMethodType::StrStartswith(_)
|
||||||
| KnownBoundMethodType::PathOpen
|
|
||||||
| KnownBoundMethodType::ConstraintSetRange
|
| KnownBoundMethodType::ConstraintSetRange
|
||||||
| KnownBoundMethodType::ConstraintSetAlways
|
| KnownBoundMethodType::ConstraintSetAlways
|
||||||
| KnownBoundMethodType::ConstraintSetNever
|
| KnownBoundMethodType::ConstraintSetNever
|
||||||
|
|
@ -7980,6 +7982,9 @@ pub enum KnownInstanceType<'db> {
|
||||||
/// An instance of `typing.GenericAlias` representing a `type[...]` expression.
|
/// An instance of `typing.GenericAlias` representing a `type[...]` expression.
|
||||||
TypeGenericAlias(InternedType<'db>),
|
TypeGenericAlias(InternedType<'db>),
|
||||||
|
|
||||||
|
/// A literal string which is the right-hand side of a PEP 613 `TypeAlias`.
|
||||||
|
LiteralStringAlias(InternedType<'db>),
|
||||||
|
|
||||||
/// An identity callable created with `typing.NewType(name, base)`, which behaves like a
|
/// An identity callable created with `typing.NewType(name, base)`, which behaves like a
|
||||||
/// subtype of `base` in type expressions. See the `struct NewType` payload for an example.
|
/// subtype of `base` in type expressions. See the `struct NewType` payload for an example.
|
||||||
NewType(NewType<'db>),
|
NewType(NewType<'db>),
|
||||||
|
|
@ -8016,7 +8021,8 @@ fn walk_known_instance_type<'db, V: visitor::TypeVisitor<'db> + ?Sized>(
|
||||||
}
|
}
|
||||||
KnownInstanceType::Literal(ty)
|
KnownInstanceType::Literal(ty)
|
||||||
| KnownInstanceType::Annotated(ty)
|
| KnownInstanceType::Annotated(ty)
|
||||||
| KnownInstanceType::TypeGenericAlias(ty) => {
|
| KnownInstanceType::TypeGenericAlias(ty)
|
||||||
|
| KnownInstanceType::LiteralStringAlias(ty) => {
|
||||||
visitor.visit_type(db, ty.inner(db));
|
visitor.visit_type(db, ty.inner(db));
|
||||||
}
|
}
|
||||||
KnownInstanceType::NewType(newtype) => {
|
KnownInstanceType::NewType(newtype) => {
|
||||||
|
|
@ -8064,6 +8070,9 @@ impl<'db> KnownInstanceType<'db> {
|
||||||
Self::Literal(ty) => Self::Literal(ty.normalized_impl(db, visitor)),
|
Self::Literal(ty) => Self::Literal(ty.normalized_impl(db, visitor)),
|
||||||
Self::Annotated(ty) => Self::Annotated(ty.normalized_impl(db, visitor)),
|
Self::Annotated(ty) => Self::Annotated(ty.normalized_impl(db, visitor)),
|
||||||
Self::TypeGenericAlias(ty) => Self::TypeGenericAlias(ty.normalized_impl(db, visitor)),
|
Self::TypeGenericAlias(ty) => Self::TypeGenericAlias(ty.normalized_impl(db, visitor)),
|
||||||
|
Self::LiteralStringAlias(ty) => {
|
||||||
|
Self::LiteralStringAlias(ty.normalized_impl(db, visitor))
|
||||||
|
}
|
||||||
Self::NewType(newtype) => Self::NewType(
|
Self::NewType(newtype) => Self::NewType(
|
||||||
newtype
|
newtype
|
||||||
.map_base_class_type(db, |class_type| class_type.normalized_impl(db, visitor)),
|
.map_base_class_type(db, |class_type| class_type.normalized_impl(db, visitor)),
|
||||||
|
|
@ -8089,6 +8098,7 @@ impl<'db> KnownInstanceType<'db> {
|
||||||
Self::Literal(_) | Self::Annotated(_) | Self::TypeGenericAlias(_) => {
|
Self::Literal(_) | Self::Annotated(_) | Self::TypeGenericAlias(_) => {
|
||||||
KnownClass::GenericAlias
|
KnownClass::GenericAlias
|
||||||
}
|
}
|
||||||
|
Self::LiteralStringAlias(_) => KnownClass::Str,
|
||||||
Self::NewType(_) => KnownClass::NewType,
|
Self::NewType(_) => KnownClass::NewType,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -8175,6 +8185,7 @@ impl<'db> KnownInstanceType<'db> {
|
||||||
f.write_str("<typing.Annotated special form>")
|
f.write_str("<typing.Annotated special form>")
|
||||||
}
|
}
|
||||||
KnownInstanceType::TypeGenericAlias(_) => f.write_str("GenericAlias"),
|
KnownInstanceType::TypeGenericAlias(_) => f.write_str("GenericAlias"),
|
||||||
|
KnownInstanceType::LiteralStringAlias(_) => f.write_str("str"),
|
||||||
KnownInstanceType::NewType(declaration) => {
|
KnownInstanceType::NewType(declaration) => {
|
||||||
write!(f, "<NewType pseudo-class '{}'>", declaration.name(self.db))
|
write!(f, "<NewType pseudo-class '{}'>", declaration.name(self.db))
|
||||||
}
|
}
|
||||||
|
|
@ -8216,9 +8227,6 @@ pub enum DynamicType<'db> {
|
||||||
///
|
///
|
||||||
/// This variant should be created with the `todo_type!` macro.
|
/// This variant should be created with the `todo_type!` macro.
|
||||||
Todo(TodoType),
|
Todo(TodoType),
|
||||||
/// A special Todo-variant for type aliases declared using `typing.TypeAlias`.
|
|
||||||
/// A temporary variant to detect and special-case the handling of these aliases in autocomplete suggestions.
|
|
||||||
TodoTypeAlias,
|
|
||||||
/// A special Todo-variant for `Unpack[Ts]`, so that we can treat it specially in `Generic[Unpack[Ts]]`
|
/// A special Todo-variant for `Unpack[Ts]`, so that we can treat it specially in `Generic[Unpack[Ts]]`
|
||||||
TodoUnpack,
|
TodoUnpack,
|
||||||
/// A type that is determined to be divergent during type inference for a recursive function.
|
/// A type that is determined to be divergent during type inference for a recursive function.
|
||||||
|
|
@ -8250,13 +8258,6 @@ impl std::fmt::Display for DynamicType<'_> {
|
||||||
f.write_str("@Todo")
|
f.write_str("@Todo")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
DynamicType::TodoTypeAlias => {
|
|
||||||
if cfg!(debug_assertions) {
|
|
||||||
f.write_str("@Todo(Support for `typing.TypeAlias`)")
|
|
||||||
} else {
|
|
||||||
f.write_str("@Todo")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
DynamicType::Divergent(_) => f.write_str("Divergent"),
|
DynamicType::Divergent(_) => f.write_str("Divergent"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -8415,6 +8416,9 @@ enum InvalidTypeExpression<'db> {
|
||||||
ConstraintSet,
|
ConstraintSet,
|
||||||
/// Same for `typing.TypedDict`
|
/// Same for `typing.TypedDict`
|
||||||
TypedDict,
|
TypedDict,
|
||||||
|
/// Same for `typing.TypeAlias`, anywhere except for as the sole annotation on an annotated
|
||||||
|
/// assignment
|
||||||
|
TypeAlias,
|
||||||
/// Type qualifiers are always invalid in *type expressions*,
|
/// Type qualifiers are always invalid in *type expressions*,
|
||||||
/// but these ones are okay with 0 arguments in *annotation expressions*
|
/// but these ones are okay with 0 arguments in *annotation expressions*
|
||||||
TypeQualifier(SpecialFormType),
|
TypeQualifier(SpecialFormType),
|
||||||
|
|
@ -8470,6 +8474,11 @@ impl<'db> InvalidTypeExpression<'db> {
|
||||||
"The special form `typing.TypedDict` is not allowed in type expressions. \
|
"The special form `typing.TypedDict` is not allowed in type expressions. \
|
||||||
Did you mean to use a concrete TypedDict or `collections.abc.Mapping[str, object]` instead?")
|
Did you mean to use a concrete TypedDict or `collections.abc.Mapping[str, object]` instead?")
|
||||||
}
|
}
|
||||||
|
InvalidTypeExpression::TypeAlias => {
|
||||||
|
f.write_str(
|
||||||
|
"`typing.TypeAlias` is only allowed as the sole annotation on an annotated assignment",
|
||||||
|
)
|
||||||
|
}
|
||||||
InvalidTypeExpression::TypeQualifier(qualifier) => write!(
|
InvalidTypeExpression::TypeQualifier(qualifier) => write!(
|
||||||
f,
|
f,
|
||||||
"Type qualifier `{qualifier}` is not allowed in type expressions \
|
"Type qualifier `{qualifier}` is not allowed in type expressions \
|
||||||
|
|
@ -10910,8 +10919,6 @@ pub enum KnownBoundMethodType<'db> {
|
||||||
/// this allows us to understand statically known branches for common tests such as
|
/// this allows us to understand statically known branches for common tests such as
|
||||||
/// `if sys.platform.startswith("freebsd")`.
|
/// `if sys.platform.startswith("freebsd")`.
|
||||||
StrStartswith(StringLiteralType<'db>),
|
StrStartswith(StringLiteralType<'db>),
|
||||||
/// Method wrapper for `Path.open`,
|
|
||||||
PathOpen,
|
|
||||||
|
|
||||||
// ConstraintSet methods
|
// ConstraintSet methods
|
||||||
ConstraintSetRange,
|
ConstraintSetRange,
|
||||||
|
|
@ -10943,8 +10950,7 @@ pub(super) fn walk_method_wrapper_type<'db, V: visitor::TypeVisitor<'db> + ?Size
|
||||||
KnownBoundMethodType::StrStartswith(string_literal) => {
|
KnownBoundMethodType::StrStartswith(string_literal) => {
|
||||||
visitor.visit_type(db, Type::StringLiteral(string_literal));
|
visitor.visit_type(db, Type::StringLiteral(string_literal));
|
||||||
}
|
}
|
||||||
KnownBoundMethodType::PathOpen
|
KnownBoundMethodType::ConstraintSetRange
|
||||||
| KnownBoundMethodType::ConstraintSetRange
|
|
||||||
| KnownBoundMethodType::ConstraintSetAlways
|
| KnownBoundMethodType::ConstraintSetAlways
|
||||||
| KnownBoundMethodType::ConstraintSetNever
|
| KnownBoundMethodType::ConstraintSetNever
|
||||||
| KnownBoundMethodType::ConstraintSetImpliesSubtypeOf(_)
|
| KnownBoundMethodType::ConstraintSetImpliesSubtypeOf(_)
|
||||||
|
|
@ -11001,8 +11007,7 @@ impl<'db> KnownBoundMethodType<'db> {
|
||||||
ConstraintSet::from(self == other)
|
ConstraintSet::from(self == other)
|
||||||
}
|
}
|
||||||
|
|
||||||
(KnownBoundMethodType::PathOpen, KnownBoundMethodType::PathOpen)
|
(
|
||||||
| (
|
|
||||||
KnownBoundMethodType::ConstraintSetRange,
|
KnownBoundMethodType::ConstraintSetRange,
|
||||||
KnownBoundMethodType::ConstraintSetRange,
|
KnownBoundMethodType::ConstraintSetRange,
|
||||||
)
|
)
|
||||||
|
|
@ -11033,7 +11038,6 @@ impl<'db> KnownBoundMethodType<'db> {
|
||||||
| KnownBoundMethodType::PropertyDunderGet(_)
|
| KnownBoundMethodType::PropertyDunderGet(_)
|
||||||
| KnownBoundMethodType::PropertyDunderSet(_)
|
| KnownBoundMethodType::PropertyDunderSet(_)
|
||||||
| KnownBoundMethodType::StrStartswith(_)
|
| KnownBoundMethodType::StrStartswith(_)
|
||||||
| KnownBoundMethodType::PathOpen
|
|
||||||
| KnownBoundMethodType::ConstraintSetRange
|
| KnownBoundMethodType::ConstraintSetRange
|
||||||
| KnownBoundMethodType::ConstraintSetAlways
|
| KnownBoundMethodType::ConstraintSetAlways
|
||||||
| KnownBoundMethodType::ConstraintSetNever
|
| KnownBoundMethodType::ConstraintSetNever
|
||||||
|
|
@ -11045,7 +11049,6 @@ impl<'db> KnownBoundMethodType<'db> {
|
||||||
| KnownBoundMethodType::PropertyDunderGet(_)
|
| KnownBoundMethodType::PropertyDunderGet(_)
|
||||||
| KnownBoundMethodType::PropertyDunderSet(_)
|
| KnownBoundMethodType::PropertyDunderSet(_)
|
||||||
| KnownBoundMethodType::StrStartswith(_)
|
| KnownBoundMethodType::StrStartswith(_)
|
||||||
| KnownBoundMethodType::PathOpen
|
|
||||||
| KnownBoundMethodType::ConstraintSetRange
|
| KnownBoundMethodType::ConstraintSetRange
|
||||||
| KnownBoundMethodType::ConstraintSetAlways
|
| KnownBoundMethodType::ConstraintSetAlways
|
||||||
| KnownBoundMethodType::ConstraintSetNever
|
| KnownBoundMethodType::ConstraintSetNever
|
||||||
|
|
@ -11087,8 +11090,7 @@ impl<'db> KnownBoundMethodType<'db> {
|
||||||
ConstraintSet::from(self == other)
|
ConstraintSet::from(self == other)
|
||||||
}
|
}
|
||||||
|
|
||||||
(KnownBoundMethodType::PathOpen, KnownBoundMethodType::PathOpen)
|
(
|
||||||
| (
|
|
||||||
KnownBoundMethodType::ConstraintSetRange,
|
KnownBoundMethodType::ConstraintSetRange,
|
||||||
KnownBoundMethodType::ConstraintSetRange,
|
KnownBoundMethodType::ConstraintSetRange,
|
||||||
)
|
)
|
||||||
|
|
@ -11122,7 +11124,6 @@ impl<'db> KnownBoundMethodType<'db> {
|
||||||
| KnownBoundMethodType::PropertyDunderGet(_)
|
| KnownBoundMethodType::PropertyDunderGet(_)
|
||||||
| KnownBoundMethodType::PropertyDunderSet(_)
|
| KnownBoundMethodType::PropertyDunderSet(_)
|
||||||
| KnownBoundMethodType::StrStartswith(_)
|
| KnownBoundMethodType::StrStartswith(_)
|
||||||
| KnownBoundMethodType::PathOpen
|
|
||||||
| KnownBoundMethodType::ConstraintSetRange
|
| KnownBoundMethodType::ConstraintSetRange
|
||||||
| KnownBoundMethodType::ConstraintSetAlways
|
| KnownBoundMethodType::ConstraintSetAlways
|
||||||
| KnownBoundMethodType::ConstraintSetNever
|
| KnownBoundMethodType::ConstraintSetNever
|
||||||
|
|
@ -11134,7 +11135,6 @@ impl<'db> KnownBoundMethodType<'db> {
|
||||||
| KnownBoundMethodType::PropertyDunderGet(_)
|
| KnownBoundMethodType::PropertyDunderGet(_)
|
||||||
| KnownBoundMethodType::PropertyDunderSet(_)
|
| KnownBoundMethodType::PropertyDunderSet(_)
|
||||||
| KnownBoundMethodType::StrStartswith(_)
|
| KnownBoundMethodType::StrStartswith(_)
|
||||||
| KnownBoundMethodType::PathOpen
|
|
||||||
| KnownBoundMethodType::ConstraintSetRange
|
| KnownBoundMethodType::ConstraintSetRange
|
||||||
| KnownBoundMethodType::ConstraintSetAlways
|
| KnownBoundMethodType::ConstraintSetAlways
|
||||||
| KnownBoundMethodType::ConstraintSetNever
|
| KnownBoundMethodType::ConstraintSetNever
|
||||||
|
|
@ -11160,7 +11160,6 @@ impl<'db> KnownBoundMethodType<'db> {
|
||||||
KnownBoundMethodType::PropertyDunderSet(property.normalized_impl(db, visitor))
|
KnownBoundMethodType::PropertyDunderSet(property.normalized_impl(db, visitor))
|
||||||
}
|
}
|
||||||
KnownBoundMethodType::StrStartswith(_)
|
KnownBoundMethodType::StrStartswith(_)
|
||||||
| KnownBoundMethodType::PathOpen
|
|
||||||
| KnownBoundMethodType::ConstraintSetRange
|
| KnownBoundMethodType::ConstraintSetRange
|
||||||
| KnownBoundMethodType::ConstraintSetAlways
|
| KnownBoundMethodType::ConstraintSetAlways
|
||||||
| KnownBoundMethodType::ConstraintSetNever
|
| KnownBoundMethodType::ConstraintSetNever
|
||||||
|
|
@ -11178,7 +11177,6 @@ impl<'db> KnownBoundMethodType<'db> {
|
||||||
| KnownBoundMethodType::PropertyDunderGet(_)
|
| KnownBoundMethodType::PropertyDunderGet(_)
|
||||||
| KnownBoundMethodType::PropertyDunderSet(_) => KnownClass::MethodWrapperType,
|
| KnownBoundMethodType::PropertyDunderSet(_) => KnownClass::MethodWrapperType,
|
||||||
KnownBoundMethodType::StrStartswith(_) => KnownClass::BuiltinFunctionType,
|
KnownBoundMethodType::StrStartswith(_) => KnownClass::BuiltinFunctionType,
|
||||||
KnownBoundMethodType::PathOpen => KnownClass::MethodType,
|
|
||||||
KnownBoundMethodType::ConstraintSetRange
|
KnownBoundMethodType::ConstraintSetRange
|
||||||
| KnownBoundMethodType::ConstraintSetAlways
|
| KnownBoundMethodType::ConstraintSetAlways
|
||||||
| KnownBoundMethodType::ConstraintSetNever
|
| KnownBoundMethodType::ConstraintSetNever
|
||||||
|
|
@ -11283,9 +11281,6 @@ impl<'db> KnownBoundMethodType<'db> {
|
||||||
Some(KnownClass::Bool.to_instance(db)),
|
Some(KnownClass::Bool.to_instance(db)),
|
||||||
)))
|
)))
|
||||||
}
|
}
|
||||||
KnownBoundMethodType::PathOpen => {
|
|
||||||
Either::Right(std::iter::once(Signature::todo("`Path.open` return type")))
|
|
||||||
}
|
|
||||||
|
|
||||||
KnownBoundMethodType::ConstraintSetRange => {
|
KnownBoundMethodType::ConstraintSetRange => {
|
||||||
Either::Right(std::iter::once(Signature::new(
|
Either::Right(std::iter::once(Signature::new(
|
||||||
|
|
|
||||||
|
|
@ -48,9 +48,7 @@ impl<'db> ClassBase<'db> {
|
||||||
ClassBase::Class(class) => class.name(db),
|
ClassBase::Class(class) => class.name(db),
|
||||||
ClassBase::Dynamic(DynamicType::Any) => "Any",
|
ClassBase::Dynamic(DynamicType::Any) => "Any",
|
||||||
ClassBase::Dynamic(DynamicType::Unknown) => "Unknown",
|
ClassBase::Dynamic(DynamicType::Unknown) => "Unknown",
|
||||||
ClassBase::Dynamic(
|
ClassBase::Dynamic(DynamicType::Todo(_) | DynamicType::TodoUnpack) => "@Todo",
|
||||||
DynamicType::Todo(_) | DynamicType::TodoTypeAlias | DynamicType::TodoUnpack,
|
|
||||||
) => "@Todo",
|
|
||||||
ClassBase::Dynamic(DynamicType::Divergent(_)) => "Divergent",
|
ClassBase::Dynamic(DynamicType::Divergent(_)) => "Divergent",
|
||||||
ClassBase::Protocol => "Protocol",
|
ClassBase::Protocol => "Protocol",
|
||||||
ClassBase::Generic => "Generic",
|
ClassBase::Generic => "Generic",
|
||||||
|
|
@ -176,6 +174,7 @@ impl<'db> ClassBase<'db> {
|
||||||
| KnownInstanceType::ConstraintSet(_)
|
| KnownInstanceType::ConstraintSet(_)
|
||||||
| KnownInstanceType::UnionType(_)
|
| KnownInstanceType::UnionType(_)
|
||||||
| KnownInstanceType::Literal(_)
|
| KnownInstanceType::Literal(_)
|
||||||
|
| KnownInstanceType::LiteralStringAlias(_)
|
||||||
// A class inheriting from a newtype would make intuitive sense, but newtype
|
// A class inheriting from a newtype would make intuitive sense, but newtype
|
||||||
// wrappers are just identity callables at runtime, so this sort of inheritance
|
// wrappers are just identity callables at runtime, so this sort of inheritance
|
||||||
// doesn't work and isn't allowed.
|
// doesn't work and isn't allowed.
|
||||||
|
|
|
||||||
|
|
@ -520,9 +520,6 @@ impl Display for DisplayRepresentation<'_> {
|
||||||
Type::KnownBoundMethod(KnownBoundMethodType::StrStartswith(_)) => {
|
Type::KnownBoundMethod(KnownBoundMethodType::StrStartswith(_)) => {
|
||||||
f.write_str("<method-wrapper `startswith` of `str` object>")
|
f.write_str("<method-wrapper `startswith` of `str` object>")
|
||||||
}
|
}
|
||||||
Type::KnownBoundMethod(KnownBoundMethodType::PathOpen) => {
|
|
||||||
f.write_str("bound method `Path.open`")
|
|
||||||
}
|
|
||||||
Type::KnownBoundMethod(KnownBoundMethodType::ConstraintSetRange) => {
|
Type::KnownBoundMethod(KnownBoundMethodType::ConstraintSetRange) => {
|
||||||
f.write_str("bound method `ConstraintSet.range`")
|
f.write_str("bound method `ConstraintSet.range`")
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -83,7 +83,7 @@ use crate::types::{
|
||||||
ClassLiteral, ClassType, DeprecatedInstance, DynamicType, FindLegacyTypeVarsVisitor,
|
ClassLiteral, ClassType, DeprecatedInstance, DynamicType, FindLegacyTypeVarsVisitor,
|
||||||
HasRelationToVisitor, IsDisjointVisitor, IsEquivalentVisitor, KnownClass, KnownInstanceType,
|
HasRelationToVisitor, IsDisjointVisitor, IsEquivalentVisitor, KnownClass, KnownInstanceType,
|
||||||
NormalizedVisitor, SpecialFormType, Truthiness, Type, TypeContext, TypeMapping, TypeRelation,
|
NormalizedVisitor, SpecialFormType, Truthiness, Type, TypeContext, TypeMapping, TypeRelation,
|
||||||
UnionBuilder, binding_type, todo_type, walk_signature,
|
UnionBuilder, binding_type, walk_signature,
|
||||||
};
|
};
|
||||||
use crate::{Db, FxOrderSet, ModuleName, resolve_module};
|
use crate::{Db, FxOrderSet, ModuleName, resolve_module};
|
||||||
|
|
||||||
|
|
@ -1152,70 +1152,6 @@ fn is_instance_truthiness<'db>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return true, if the type passed as `mode` would require us to pick a non-trivial overload of
|
|
||||||
/// `builtins.open` / `os.fdopen` / `Path.open`.
|
|
||||||
fn is_mode_with_nontrivial_return_type<'db>(db: &'db dyn Db, mode: Type<'db>) -> bool {
|
|
||||||
// Return true for any mode that doesn't match typeshed's
|
|
||||||
// `OpenTextMode` type alias (<https://github.com/python/typeshed/blob/6937a9b193bfc2f0696452d58aad96d7627aa29a/stdlib/_typeshed/__init__.pyi#L220>).
|
|
||||||
mode.as_string_literal().is_none_or(|mode| {
|
|
||||||
!matches!(
|
|
||||||
mode.value(db),
|
|
||||||
"r+" | "+r"
|
|
||||||
| "rt+"
|
|
||||||
| "r+t"
|
|
||||||
| "+rt"
|
|
||||||
| "tr+"
|
|
||||||
| "t+r"
|
|
||||||
| "+tr"
|
|
||||||
| "w+"
|
|
||||||
| "+w"
|
|
||||||
| "wt+"
|
|
||||||
| "w+t"
|
|
||||||
| "+wt"
|
|
||||||
| "tw+"
|
|
||||||
| "t+w"
|
|
||||||
| "+tw"
|
|
||||||
| "a+"
|
|
||||||
| "+a"
|
|
||||||
| "at+"
|
|
||||||
| "a+t"
|
|
||||||
| "+at"
|
|
||||||
| "ta+"
|
|
||||||
| "t+a"
|
|
||||||
| "+ta"
|
|
||||||
| "x+"
|
|
||||||
| "+x"
|
|
||||||
| "xt+"
|
|
||||||
| "x+t"
|
|
||||||
| "+xt"
|
|
||||||
| "tx+"
|
|
||||||
| "t+x"
|
|
||||||
| "+tx"
|
|
||||||
| "w"
|
|
||||||
| "wt"
|
|
||||||
| "tw"
|
|
||||||
| "a"
|
|
||||||
| "at"
|
|
||||||
| "ta"
|
|
||||||
| "x"
|
|
||||||
| "xt"
|
|
||||||
| "tx"
|
|
||||||
| "r"
|
|
||||||
| "rt"
|
|
||||||
| "tr"
|
|
||||||
| "U"
|
|
||||||
| "rU"
|
|
||||||
| "Ur"
|
|
||||||
| "rtU"
|
|
||||||
| "rUt"
|
|
||||||
| "Urt"
|
|
||||||
| "trU"
|
|
||||||
| "tUr"
|
|
||||||
| "Utr"
|
|
||||||
)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
fn signature_cycle_initial<'db>(
|
fn signature_cycle_initial<'db>(
|
||||||
_db: &'db dyn Db,
|
_db: &'db dyn Db,
|
||||||
_id: salsa::Id,
|
_id: salsa::Id,
|
||||||
|
|
@ -1268,16 +1204,6 @@ pub enum KnownFunction {
|
||||||
DunderImport,
|
DunderImport,
|
||||||
/// `importlib.import_module`, which returns the submodule.
|
/// `importlib.import_module`, which returns the submodule.
|
||||||
ImportModule,
|
ImportModule,
|
||||||
/// `builtins.open`
|
|
||||||
Open,
|
|
||||||
|
|
||||||
/// `os.fdopen`
|
|
||||||
Fdopen,
|
|
||||||
|
|
||||||
/// `tempfile.NamedTemporaryFile`
|
|
||||||
#[strum(serialize = "NamedTemporaryFile")]
|
|
||||||
NamedTemporaryFile,
|
|
||||||
|
|
||||||
/// `typing(_extensions).final`
|
/// `typing(_extensions).final`
|
||||||
Final,
|
Final,
|
||||||
/// `typing(_extensions).disjoint_base`
|
/// `typing(_extensions).disjoint_base`
|
||||||
|
|
@ -1376,7 +1302,6 @@ impl KnownFunction {
|
||||||
| Self::HasAttr
|
| Self::HasAttr
|
||||||
| Self::Len
|
| Self::Len
|
||||||
| Self::Repr
|
| Self::Repr
|
||||||
| Self::Open
|
|
||||||
| Self::DunderImport => module.is_builtins(),
|
| Self::DunderImport => module.is_builtins(),
|
||||||
Self::AssertType
|
Self::AssertType
|
||||||
| Self::AssertNever
|
| Self::AssertNever
|
||||||
|
|
@ -1396,12 +1321,6 @@ impl KnownFunction {
|
||||||
Self::AbstractMethod => {
|
Self::AbstractMethod => {
|
||||||
matches!(module, KnownModule::Abc)
|
matches!(module, KnownModule::Abc)
|
||||||
}
|
}
|
||||||
Self::Fdopen => {
|
|
||||||
matches!(module, KnownModule::Os)
|
|
||||||
}
|
|
||||||
Self::NamedTemporaryFile => {
|
|
||||||
matches!(module, KnownModule::Tempfile)
|
|
||||||
}
|
|
||||||
Self::Dataclass | Self::Field => {
|
Self::Dataclass | Self::Field => {
|
||||||
matches!(module, KnownModule::Dataclasses)
|
matches!(module, KnownModule::Dataclasses)
|
||||||
}
|
}
|
||||||
|
|
@ -1871,38 +1790,6 @@ impl KnownFunction {
|
||||||
|
|
||||||
overload.set_return_type(Type::module_literal(db, file, module));
|
overload.set_return_type(Type::module_literal(db, file, module));
|
||||||
}
|
}
|
||||||
|
|
||||||
KnownFunction::Open => {
|
|
||||||
// TODO: Temporary special-casing for `builtins.open` to avoid an excessive number of
|
|
||||||
// false positives in lieu of proper support for PEP-613 type aliases.
|
|
||||||
if let [_, Some(mode), ..] = parameter_types
|
|
||||||
&& is_mode_with_nontrivial_return_type(db, *mode)
|
|
||||||
{
|
|
||||||
overload.set_return_type(todo_type!("`builtins.open` return type"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
KnownFunction::Fdopen => {
|
|
||||||
// TODO: Temporary special-casing for `os.fdopen` to avoid an excessive number of
|
|
||||||
// false positives in lieu of proper support for PEP-613 type aliases.
|
|
||||||
if let [_, Some(mode), ..] = parameter_types
|
|
||||||
&& is_mode_with_nontrivial_return_type(db, *mode)
|
|
||||||
{
|
|
||||||
overload.set_return_type(todo_type!("`os.fdopen` return type"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
KnownFunction::NamedTemporaryFile => {
|
|
||||||
// TODO: Temporary special-casing for `tempfile.NamedTemporaryFile` to avoid an excessive number of
|
|
||||||
// false positives in lieu of proper support for PEP-613 type aliases.
|
|
||||||
if let [Some(mode), ..] = parameter_types
|
|
||||||
&& is_mode_with_nontrivial_return_type(db, *mode)
|
|
||||||
{
|
|
||||||
overload
|
|
||||||
.set_return_type(todo_type!("`tempfile.NamedTemporaryFile` return type"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1929,15 +1816,10 @@ pub(crate) mod tests {
|
||||||
| KnownFunction::IsInstance
|
| KnownFunction::IsInstance
|
||||||
| KnownFunction::HasAttr
|
| KnownFunction::HasAttr
|
||||||
| KnownFunction::IsSubclass
|
| KnownFunction::IsSubclass
|
||||||
| KnownFunction::Open
|
|
||||||
| KnownFunction::DunderImport => KnownModule::Builtins,
|
| KnownFunction::DunderImport => KnownModule::Builtins,
|
||||||
|
|
||||||
KnownFunction::AbstractMethod => KnownModule::Abc,
|
KnownFunction::AbstractMethod => KnownModule::Abc,
|
||||||
|
|
||||||
KnownFunction::Fdopen => KnownModule::Os,
|
|
||||||
|
|
||||||
KnownFunction::NamedTemporaryFile => KnownModule::Tempfile,
|
|
||||||
|
|
||||||
KnownFunction::Dataclass | KnownFunction::Field => KnownModule::Dataclasses,
|
KnownFunction::Dataclass | KnownFunction::Field => KnownModule::Dataclasses,
|
||||||
|
|
||||||
KnownFunction::GetattrStatic => KnownModule::Inspect,
|
KnownFunction::GetattrStatic => KnownModule::Inspect,
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ use crate::types::generics::Specialization;
|
||||||
use crate::types::signatures::Signature;
|
use crate::types::signatures::Signature;
|
||||||
use crate::types::{CallDunderError, UnionType};
|
use crate::types::{CallDunderError, UnionType};
|
||||||
use crate::types::{
|
use crate::types::{
|
||||||
ClassBase, ClassLiteral, DynamicType, KnownClass, KnownInstanceType, Type, TypeContext,
|
ClassBase, ClassLiteral, KnownClass, KnownInstanceType, Type, TypeContext,
|
||||||
TypeVarBoundOrConstraints, class::CodeGeneratorKind,
|
TypeVarBoundOrConstraints, class::CodeGeneratorKind,
|
||||||
};
|
};
|
||||||
use crate::{Db, HasType, NameKind, SemanticModel};
|
use crate::{Db, HasType, NameKind, SemanticModel};
|
||||||
|
|
@ -299,9 +299,10 @@ impl<'db> AllMembers<'db> {
|
||||||
Type::KnownInstance(
|
Type::KnownInstance(
|
||||||
KnownInstanceType::TypeVar(_)
|
KnownInstanceType::TypeVar(_)
|
||||||
| KnownInstanceType::TypeAliasType(_)
|
| KnownInstanceType::TypeAliasType(_)
|
||||||
| KnownInstanceType::UnionType(_),
|
| KnownInstanceType::UnionType(_)
|
||||||
|
| KnownInstanceType::Literal(_)
|
||||||
|
| KnownInstanceType::Annotated(_),
|
||||||
) => continue,
|
) => continue,
|
||||||
Type::Dynamic(DynamicType::TodoTypeAlias) => continue,
|
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5390,7 +5390,7 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
|
||||||
let target = assignment.target(self.module());
|
let target = assignment.target(self.module());
|
||||||
let value = assignment.value(self.module());
|
let value = assignment.value(self.module());
|
||||||
|
|
||||||
let mut declared = self.infer_annotation_expression(
|
let mut declared = self.infer_annotation_expression_allow_pep_613(
|
||||||
annotation,
|
annotation,
|
||||||
DeferredExpressionState::from(self.defer_annotations()),
|
DeferredExpressionState::from(self.defer_annotations()),
|
||||||
);
|
);
|
||||||
|
|
@ -5442,6 +5442,13 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
|
||||||
declared.inner = Type::BooleanLiteral(true);
|
declared.inner = Type::BooleanLiteral(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check if this is a PEP 613 `TypeAlias`. (This must come below the SpecialForm handling
|
||||||
|
// immediately below, since that can overwrite the type to be `TypeAlias`.)
|
||||||
|
let is_pep_613_type_alias = matches!(
|
||||||
|
declared.inner_type(),
|
||||||
|
Type::SpecialForm(SpecialFormType::TypeAlias)
|
||||||
|
);
|
||||||
|
|
||||||
// Handle various singletons.
|
// Handle various singletons.
|
||||||
if let Some(name_expr) = target.as_name_expr() {
|
if let Some(name_expr) = target.as_name_expr() {
|
||||||
if let Some(special_form) =
|
if let Some(special_form) =
|
||||||
|
|
@ -5487,20 +5494,24 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
|
||||||
}
|
}
|
||||||
|
|
||||||
// We defer the r.h.s. of PEP-613 `TypeAlias` assignments in stub files.
|
// We defer the r.h.s. of PEP-613 `TypeAlias` assignments in stub files.
|
||||||
let declared_type = declared.inner_type();
|
|
||||||
let previous_deferred_state = self.deferred_state;
|
let previous_deferred_state = self.deferred_state;
|
||||||
|
|
||||||
if matches!(
|
if is_pep_613_type_alias && self.in_stub() {
|
||||||
declared_type,
|
|
||||||
Type::SpecialForm(SpecialFormType::TypeAlias)
|
|
||||||
| Type::Dynamic(DynamicType::TodoTypeAlias)
|
|
||||||
) && self.in_stub()
|
|
||||||
{
|
|
||||||
self.deferred_state = DeferredExpressionState::Deferred;
|
self.deferred_state = DeferredExpressionState::Deferred;
|
||||||
}
|
}
|
||||||
|
|
||||||
let inferred_ty = self
|
let inferred_ty = if is_pep_613_type_alias && value.is_string_literal_expr() {
|
||||||
.infer_maybe_standalone_expression(value, TypeContext::new(Some(declared_type)));
|
let aliased_type = self.infer_type_expression(value);
|
||||||
|
Type::KnownInstance(KnownInstanceType::LiteralStringAlias(InternedType::new(
|
||||||
|
self.db(),
|
||||||
|
aliased_type,
|
||||||
|
)))
|
||||||
|
} else {
|
||||||
|
self.infer_maybe_standalone_expression(
|
||||||
|
value,
|
||||||
|
TypeContext::new(Some(declared.inner_type())),
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
self.deferred_state = previous_deferred_state;
|
self.deferred_state = previous_deferred_state;
|
||||||
|
|
||||||
|
|
@ -5517,17 +5528,33 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
|
||||||
inferred_ty
|
inferred_ty
|
||||||
};
|
};
|
||||||
|
|
||||||
self.add_declaration_with_binding(
|
if is_pep_613_type_alias {
|
||||||
target.into(),
|
self.add_declaration_with_binding(
|
||||||
definition,
|
target.into(),
|
||||||
&DeclaredAndInferredType::MightBeDifferent {
|
definition,
|
||||||
declared_ty: declared,
|
&DeclaredAndInferredType::AreTheSame(TypeAndQualifiers::declared(inferred_ty)),
|
||||||
inferred_ty,
|
);
|
||||||
},
|
} else {
|
||||||
);
|
self.add_declaration_with_binding(
|
||||||
|
target.into(),
|
||||||
|
definition,
|
||||||
|
&DeclaredAndInferredType::MightBeDifferent {
|
||||||
|
declared_ty: declared,
|
||||||
|
inferred_ty,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
self.store_expression_type(target, inferred_ty);
|
self.store_expression_type(target, inferred_ty);
|
||||||
} else {
|
} else {
|
||||||
|
if is_pep_613_type_alias {
|
||||||
|
if let Some(builder) = self.context.report_lint(&INVALID_TYPE_FORM, annotation) {
|
||||||
|
builder.into_diagnostic(
|
||||||
|
"`TypeAlias` must be assigned a value in annotated assignments",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
declared.inner = Type::unknown();
|
||||||
|
}
|
||||||
if self.in_stub() {
|
if self.in_stub() {
|
||||||
self.add_declaration_with_binding(
|
self.add_declaration_with_binding(
|
||||||
target.into(),
|
target.into(),
|
||||||
|
|
@ -9286,20 +9313,10 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
|
||||||
(unknown @ Type::Dynamic(DynamicType::Unknown), _, _)
|
(unknown @ Type::Dynamic(DynamicType::Unknown), _, _)
|
||||||
| (_, unknown @ Type::Dynamic(DynamicType::Unknown), _) => Some(unknown),
|
| (_, unknown @ Type::Dynamic(DynamicType::Unknown), _) => Some(unknown),
|
||||||
|
|
||||||
(
|
(todo @ Type::Dynamic(DynamicType::Todo(_) | DynamicType::TodoUnpack), _, _)
|
||||||
todo @ Type::Dynamic(
|
| (_, todo @ Type::Dynamic(DynamicType::Todo(_) | DynamicType::TodoUnpack), _) => {
|
||||||
DynamicType::Todo(_) | DynamicType::TodoUnpack | DynamicType::TodoTypeAlias,
|
Some(todo)
|
||||||
),
|
}
|
||||||
_,
|
|
||||||
_,
|
|
||||||
)
|
|
||||||
| (
|
|
||||||
_,
|
|
||||||
todo @ Type::Dynamic(
|
|
||||||
DynamicType::Todo(_) | DynamicType::TodoUnpack | DynamicType::TodoTypeAlias,
|
|
||||||
),
|
|
||||||
_,
|
|
||||||
) => Some(todo),
|
|
||||||
|
|
||||||
(Type::Never, _, _) | (_, Type::Never, _) => Some(Type::Never),
|
(Type::Never, _, _) | (_, Type::Never, _) => Some(Type::Never),
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -18,21 +18,17 @@ impl<'db> TypeInferenceBuilder<'db, '_> {
|
||||||
annotation: &ast::Expr,
|
annotation: &ast::Expr,
|
||||||
deferred_state: DeferredExpressionState,
|
deferred_state: DeferredExpressionState,
|
||||||
) -> TypeAndQualifiers<'db> {
|
) -> TypeAndQualifiers<'db> {
|
||||||
// `DeferredExpressionState::InStringAnnotation` takes precedence over other deferred states.
|
self.infer_annotation_expression_inner(annotation, deferred_state, false)
|
||||||
// However, if it's not a stringified annotation, we must still ensure that annotation expressions
|
}
|
||||||
// are always deferred in stub files.
|
|
||||||
let state = if deferred_state.in_string_annotation() {
|
|
||||||
deferred_state
|
|
||||||
} else if self.in_stub() {
|
|
||||||
DeferredExpressionState::Deferred
|
|
||||||
} else {
|
|
||||||
deferred_state
|
|
||||||
};
|
|
||||||
|
|
||||||
let previous_deferred_state = std::mem::replace(&mut self.deferred_state, state);
|
/// Infer the type of an annotation expression with the given [`DeferredExpressionState`],
|
||||||
let annotation_ty = self.infer_annotation_expression_impl(annotation);
|
/// allowing a PEP 613 `typing.TypeAlias` annotation.
|
||||||
self.deferred_state = previous_deferred_state;
|
pub(super) fn infer_annotation_expression_allow_pep_613(
|
||||||
annotation_ty
|
&mut self,
|
||||||
|
annotation: &ast::Expr,
|
||||||
|
deferred_state: DeferredExpressionState,
|
||||||
|
) -> TypeAndQualifiers<'db> {
|
||||||
|
self.infer_annotation_expression_inner(annotation, deferred_state, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Similar to [`infer_annotation_expression`], but accepts an optional annotation expression
|
/// Similar to [`infer_annotation_expression`], but accepts an optional annotation expression
|
||||||
|
|
@ -47,17 +43,42 @@ impl<'db> TypeInferenceBuilder<'db, '_> {
|
||||||
annotation.map(|expr| self.infer_annotation_expression(expr, deferred_state))
|
annotation.map(|expr| self.infer_annotation_expression(expr, deferred_state))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn infer_annotation_expression_inner(
|
||||||
|
&mut self,
|
||||||
|
annotation: &ast::Expr,
|
||||||
|
deferred_state: DeferredExpressionState,
|
||||||
|
allow_pep_613: bool,
|
||||||
|
) -> TypeAndQualifiers<'db> {
|
||||||
|
// `DeferredExpressionState::InStringAnnotation` takes precedence over other deferred states.
|
||||||
|
// However, if it's not a stringified annotation, we must still ensure that annotation expressions
|
||||||
|
// are always deferred in stub files.
|
||||||
|
let state = if deferred_state.in_string_annotation() {
|
||||||
|
deferred_state
|
||||||
|
} else if self.in_stub() {
|
||||||
|
DeferredExpressionState::Deferred
|
||||||
|
} else {
|
||||||
|
deferred_state
|
||||||
|
};
|
||||||
|
|
||||||
|
let previous_deferred_state = std::mem::replace(&mut self.deferred_state, state);
|
||||||
|
let annotation_ty = self.infer_annotation_expression_impl(annotation, allow_pep_613);
|
||||||
|
self.deferred_state = previous_deferred_state;
|
||||||
|
annotation_ty
|
||||||
|
}
|
||||||
|
|
||||||
/// Implementation of [`infer_annotation_expression`].
|
/// Implementation of [`infer_annotation_expression`].
|
||||||
///
|
///
|
||||||
/// [`infer_annotation_expression`]: TypeInferenceBuilder::infer_annotation_expression
|
/// [`infer_annotation_expression`]: TypeInferenceBuilder::infer_annotation_expression
|
||||||
fn infer_annotation_expression_impl(
|
fn infer_annotation_expression_impl(
|
||||||
&mut self,
|
&mut self,
|
||||||
annotation: &ast::Expr,
|
annotation: &ast::Expr,
|
||||||
|
allow_pep_613: bool,
|
||||||
) -> TypeAndQualifiers<'db> {
|
) -> TypeAndQualifiers<'db> {
|
||||||
fn infer_name_or_attribute<'db>(
|
fn infer_name_or_attribute<'db>(
|
||||||
ty: Type<'db>,
|
ty: Type<'db>,
|
||||||
annotation: &ast::Expr,
|
annotation: &ast::Expr,
|
||||||
builder: &TypeInferenceBuilder<'db, '_>,
|
builder: &TypeInferenceBuilder<'db, '_>,
|
||||||
|
allow_pep_613: bool,
|
||||||
) -> TypeAndQualifiers<'db> {
|
) -> TypeAndQualifiers<'db> {
|
||||||
match ty {
|
match ty {
|
||||||
Type::SpecialForm(SpecialFormType::ClassVar) => TypeAndQualifiers::new(
|
Type::SpecialForm(SpecialFormType::ClassVar) => TypeAndQualifiers::new(
|
||||||
|
|
@ -85,6 +106,22 @@ impl<'db> TypeInferenceBuilder<'db, '_> {
|
||||||
TypeOrigin::Declared,
|
TypeOrigin::Declared,
|
||||||
TypeQualifiers::READ_ONLY,
|
TypeQualifiers::READ_ONLY,
|
||||||
),
|
),
|
||||||
|
Type::SpecialForm(SpecialFormType::TypeAlias) if allow_pep_613 => {
|
||||||
|
TypeAndQualifiers::declared(ty)
|
||||||
|
}
|
||||||
|
// Conditional import of `typing.TypeAlias` or `typing_extensions.TypeAlias` on a
|
||||||
|
// Python version where the former doesn't exist.
|
||||||
|
Type::Union(union)
|
||||||
|
if allow_pep_613
|
||||||
|
&& union.elements(builder.db()).iter().all(|ty| {
|
||||||
|
matches!(
|
||||||
|
ty,
|
||||||
|
Type::SpecialForm(SpecialFormType::TypeAlias) | Type::Dynamic(_)
|
||||||
|
)
|
||||||
|
}) =>
|
||||||
|
{
|
||||||
|
TypeAndQualifiers::declared(Type::SpecialForm(SpecialFormType::TypeAlias))
|
||||||
|
}
|
||||||
Type::ClassLiteral(class) if class.is_known(builder.db(), KnownClass::InitVar) => {
|
Type::ClassLiteral(class) if class.is_known(builder.db(), KnownClass::InitVar) => {
|
||||||
if let Some(builder) =
|
if let Some(builder) =
|
||||||
builder.context.report_lint(&INVALID_TYPE_FORM, annotation)
|
builder.context.report_lint(&INVALID_TYPE_FORM, annotation)
|
||||||
|
|
@ -148,6 +185,7 @@ impl<'db> TypeInferenceBuilder<'db, '_> {
|
||||||
self.infer_attribute_expression(attribute),
|
self.infer_attribute_expression(attribute),
|
||||||
annotation,
|
annotation,
|
||||||
self,
|
self,
|
||||||
|
allow_pep_613,
|
||||||
),
|
),
|
||||||
ast::ExprContext::Invalid => TypeAndQualifiers::declared(Type::unknown()),
|
ast::ExprContext::Invalid => TypeAndQualifiers::declared(Type::unknown()),
|
||||||
ast::ExprContext::Store | ast::ExprContext::Del => TypeAndQualifiers::declared(
|
ast::ExprContext::Store | ast::ExprContext::Del => TypeAndQualifiers::declared(
|
||||||
|
|
@ -156,9 +194,12 @@ impl<'db> TypeInferenceBuilder<'db, '_> {
|
||||||
},
|
},
|
||||||
|
|
||||||
ast::Expr::Name(name) => match name.ctx {
|
ast::Expr::Name(name) => match name.ctx {
|
||||||
ast::ExprContext::Load => {
|
ast::ExprContext::Load => infer_name_or_attribute(
|
||||||
infer_name_or_attribute(self.infer_name_expression(name), annotation, self)
|
self.infer_name_expression(name),
|
||||||
}
|
annotation,
|
||||||
|
self,
|
||||||
|
allow_pep_613,
|
||||||
|
),
|
||||||
ast::ExprContext::Invalid => TypeAndQualifiers::declared(Type::unknown()),
|
ast::ExprContext::Invalid => TypeAndQualifiers::declared(Type::unknown()),
|
||||||
ast::ExprContext::Store | ast::ExprContext::Del => TypeAndQualifiers::declared(
|
ast::ExprContext::Store | ast::ExprContext::Del => TypeAndQualifiers::declared(
|
||||||
todo_type!("Name expression annotation in Store/Del context"),
|
todo_type!("Name expression annotation in Store/Del context"),
|
||||||
|
|
@ -189,7 +230,7 @@ impl<'db> TypeInferenceBuilder<'db, '_> {
|
||||||
}
|
}
|
||||||
|
|
||||||
let inner_annotation_ty =
|
let inner_annotation_ty =
|
||||||
self.infer_annotation_expression_impl(inner_annotation);
|
self.infer_annotation_expression_impl(inner_annotation, false);
|
||||||
|
|
||||||
self.store_expression_type(slice, inner_annotation_ty.inner_type());
|
self.store_expression_type(slice, inner_annotation_ty.inner_type());
|
||||||
inner_annotation_ty
|
inner_annotation_ty
|
||||||
|
|
@ -202,7 +243,7 @@ impl<'db> TypeInferenceBuilder<'db, '_> {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
report_invalid_arguments_to_annotated(&self.context, subscript);
|
report_invalid_arguments_to_annotated(&self.context, subscript);
|
||||||
self.infer_annotation_expression_impl(slice)
|
self.infer_annotation_expression_impl(slice, false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Type::SpecialForm(
|
Type::SpecialForm(
|
||||||
|
|
@ -220,7 +261,7 @@ impl<'db> TypeInferenceBuilder<'db, '_> {
|
||||||
let num_arguments = arguments.len();
|
let num_arguments = arguments.len();
|
||||||
let type_and_qualifiers = if num_arguments == 1 {
|
let type_and_qualifiers = if num_arguments == 1 {
|
||||||
let mut type_and_qualifiers =
|
let mut type_and_qualifiers =
|
||||||
self.infer_annotation_expression_impl(slice);
|
self.infer_annotation_expression_impl(slice, false);
|
||||||
|
|
||||||
match type_qualifier {
|
match type_qualifier {
|
||||||
SpecialFormType::ClassVar => {
|
SpecialFormType::ClassVar => {
|
||||||
|
|
@ -243,7 +284,7 @@ impl<'db> TypeInferenceBuilder<'db, '_> {
|
||||||
type_and_qualifiers
|
type_and_qualifiers
|
||||||
} else {
|
} else {
|
||||||
for element in arguments {
|
for element in arguments {
|
||||||
self.infer_annotation_expression_impl(element);
|
self.infer_annotation_expression_impl(element, false);
|
||||||
}
|
}
|
||||||
if let Some(builder) =
|
if let Some(builder) =
|
||||||
self.context.report_lint(&INVALID_TYPE_FORM, subscript)
|
self.context.report_lint(&INVALID_TYPE_FORM, subscript)
|
||||||
|
|
@ -269,12 +310,12 @@ impl<'db> TypeInferenceBuilder<'db, '_> {
|
||||||
let num_arguments = arguments.len();
|
let num_arguments = arguments.len();
|
||||||
let type_and_qualifiers = if num_arguments == 1 {
|
let type_and_qualifiers = if num_arguments == 1 {
|
||||||
let mut type_and_qualifiers =
|
let mut type_and_qualifiers =
|
||||||
self.infer_annotation_expression_impl(slice);
|
self.infer_annotation_expression_impl(slice, false);
|
||||||
type_and_qualifiers.add_qualifier(TypeQualifiers::INIT_VAR);
|
type_and_qualifiers.add_qualifier(TypeQualifiers::INIT_VAR);
|
||||||
type_and_qualifiers
|
type_and_qualifiers
|
||||||
} else {
|
} else {
|
||||||
for element in arguments {
|
for element in arguments {
|
||||||
self.infer_annotation_expression_impl(element);
|
self.infer_annotation_expression_impl(element, false);
|
||||||
}
|
}
|
||||||
if let Some(builder) =
|
if let Some(builder) =
|
||||||
self.context.report_lint(&INVALID_TYPE_FORM, subscript)
|
self.context.report_lint(&INVALID_TYPE_FORM, subscript)
|
||||||
|
|
|
||||||
|
|
@ -825,6 +825,10 @@ impl<'db> TypeInferenceBuilder<'db, '_> {
|
||||||
self.infer_type_expression(slice);
|
self.infer_type_expression(slice);
|
||||||
todo_type!("Generic manual PEP-695 type alias")
|
todo_type!("Generic manual PEP-695 type alias")
|
||||||
}
|
}
|
||||||
|
KnownInstanceType::LiteralStringAlias(_) => {
|
||||||
|
self.infer_type_expression(slice);
|
||||||
|
todo_type!("Generic stringified PEP-613 type alias")
|
||||||
|
}
|
||||||
KnownInstanceType::UnionType(_) => {
|
KnownInstanceType::UnionType(_) => {
|
||||||
self.infer_type_expression(slice);
|
self.infer_type_expression(slice);
|
||||||
todo_type!("Generic specialization of types.UnionType")
|
todo_type!("Generic specialization of types.UnionType")
|
||||||
|
|
|
||||||
|
|
@ -269,9 +269,6 @@ fn dynamic_elements_ordering(left: DynamicType, right: DynamicType) -> Ordering
|
||||||
(DynamicType::TodoUnpack, _) => Ordering::Less,
|
(DynamicType::TodoUnpack, _) => Ordering::Less,
|
||||||
(_, DynamicType::TodoUnpack) => Ordering::Greater,
|
(_, DynamicType::TodoUnpack) => Ordering::Greater,
|
||||||
|
|
||||||
(DynamicType::TodoTypeAlias, _) => Ordering::Less,
|
|
||||||
(_, DynamicType::TodoTypeAlias) => Ordering::Greater,
|
|
||||||
|
|
||||||
(DynamicType::Divergent(left), DynamicType::Divergent(right)) => {
|
(DynamicType::Divergent(left), DynamicType::Divergent(right)) => {
|
||||||
left.scope.cmp(&right.scope)
|
left.scope.cmp(&right.scope)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue