mirror of
https://github.com/astral-sh/ruff.git
synced 2025-10-01 06:11:21 +00:00
[ty] Remove SliceLiteral
type variant (#17958)
Some checks are pending
CI / Fuzz for new ty panics (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 (linux) (push) Blocked by required conditions
CI / cargo test (linux, release) (push) Blocked by required conditions
CI / cargo test (windows) (push) Blocked by required conditions
CI / cargo test (wasm) (push) Blocked by required conditions
CI / cargo build (release) (push) Waiting to run
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 / cargo shear (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 (push) Blocked by required conditions
[ty Playground] Release / publish (push) Waiting to run
Some checks are pending
CI / Fuzz for new ty panics (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 (linux) (push) Blocked by required conditions
CI / cargo test (linux, release) (push) Blocked by required conditions
CI / cargo test (windows) (push) Blocked by required conditions
CI / cargo test (wasm) (push) Blocked by required conditions
CI / cargo build (release) (push) Waiting to run
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 / cargo shear (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 (push) Blocked by required conditions
[ty Playground] Release / publish (push) Waiting to run
@AlexWaygood pointed out that the `SliceLiteral` type variant was originally created to handle slices before we had generics. https://github.com/astral-sh/ruff/pull/17927#discussion_r2078115787 Now that we _do_ have generics, we can use a specialization of the `slice` builtin type for slice literals. This depends on https://github.com/astral-sh/ruff/pull/17956, since we need to make sure that all typevar defaults are fully substituted when specializing `slice`.
This commit is contained in:
parent
b705664d49
commit
f78367979e
8 changed files with 89 additions and 185 deletions
|
@ -125,6 +125,17 @@ static_assert(not is_assignable_to(Literal[b"foo"], Literal["foo"]))
|
||||||
static_assert(not is_assignable_to(Literal["foo"], Literal[b"foo"]))
|
static_assert(not is_assignable_to(Literal["foo"], Literal[b"foo"]))
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Slice literals
|
||||||
|
|
||||||
|
The type of a slice literal is currently inferred as a specialization of `slice`.
|
||||||
|
|
||||||
|
```py
|
||||||
|
from ty_extensions import TypeOf, is_assignable_to, static_assert
|
||||||
|
|
||||||
|
static_assert(is_assignable_to(TypeOf[1:2:3], slice))
|
||||||
|
static_assert(is_assignable_to(TypeOf[1:2:3], slice[int]))
|
||||||
|
```
|
||||||
|
|
||||||
## `type[…]` and class literals
|
## `type[…]` and class literals
|
||||||
|
|
||||||
In the following tests, `TypeOf[str]` is a singleton type with a single inhabitant, the class `str`.
|
In the following tests, `TypeOf[str]` is a singleton type with a single inhabitant, the class `str`.
|
||||||
|
|
|
@ -334,18 +334,13 @@ static_assert(is_subtype_of(TypeOf[typing], ModuleType))
|
||||||
|
|
||||||
### Slice literals
|
### Slice literals
|
||||||
|
|
||||||
The type of a slice literal is currently inferred as `slice`, which is a generic type whose default
|
The type of a slice literal is currently inferred as a specialization of `slice`.
|
||||||
specialization includes `Any`. Slice literals therefore do not participate in the subtyping
|
|
||||||
relationship.
|
|
||||||
|
|
||||||
TODO: Infer a specialized type for the slice literal
|
|
||||||
|
|
||||||
```py
|
```py
|
||||||
from ty_extensions import TypeOf, is_subtype_of, static_assert
|
from ty_extensions import TypeOf, is_subtype_of, static_assert
|
||||||
|
|
||||||
|
# slice's default specialization is slice[Any, Any, Any], which does not participate in subtyping.
|
||||||
static_assert(not is_subtype_of(TypeOf[1:2:3], slice))
|
static_assert(not is_subtype_of(TypeOf[1:2:3], slice))
|
||||||
# TODO: no error
|
|
||||||
# error: [static-assert-error]
|
|
||||||
static_assert(is_subtype_of(TypeOf[1:2:3], slice[int]))
|
static_assert(is_subtype_of(TypeOf[1:2:3], slice[int]))
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
@ -520,8 +520,6 @@ pub enum Type<'db> {
|
||||||
LiteralString,
|
LiteralString,
|
||||||
/// A bytes literal
|
/// A bytes literal
|
||||||
BytesLiteral(BytesLiteralType<'db>),
|
BytesLiteral(BytesLiteralType<'db>),
|
||||||
/// A slice literal, e.g. `1:5`, `10:0:-1` or `:`
|
|
||||||
SliceLiteral(SliceLiteralType<'db>),
|
|
||||||
/// A heterogeneous tuple type, with elements of the given types in source order.
|
/// A heterogeneous tuple type, with elements of the given types in source order.
|
||||||
// TODO: Support variable length homogeneous tuple type like `tuple[int, ...]`.
|
// TODO: Support variable length homogeneous tuple type like `tuple[int, ...]`.
|
||||||
Tuple(TupleType<'db>),
|
Tuple(TupleType<'db>),
|
||||||
|
@ -607,7 +605,6 @@ impl<'db> Type<'db> {
|
||||||
| Self::StringLiteral(_)
|
| Self::StringLiteral(_)
|
||||||
| Self::IntLiteral(_)
|
| Self::IntLiteral(_)
|
||||||
| Self::LiteralString
|
| Self::LiteralString
|
||||||
| Self::SliceLiteral(_)
|
|
||||||
| Self::Dynamic(DynamicType::Unknown | DynamicType::Any)
|
| Self::Dynamic(DynamicType::Unknown | DynamicType::Any)
|
||||||
| Self::BoundMethod(_)
|
| Self::BoundMethod(_)
|
||||||
| Self::WrapperDescriptor(_)
|
| Self::WrapperDescriptor(_)
|
||||||
|
@ -905,7 +902,6 @@ impl<'db> Type<'db> {
|
||||||
| Type::AlwaysFalsy
|
| Type::AlwaysFalsy
|
||||||
| Type::AlwaysTruthy
|
| Type::AlwaysTruthy
|
||||||
| Type::BooleanLiteral(_)
|
| Type::BooleanLiteral(_)
|
||||||
| Type::SliceLiteral(_)
|
|
||||||
| Type::BytesLiteral(_)
|
| Type::BytesLiteral(_)
|
||||||
| Type::StringLiteral(_)
|
| Type::StringLiteral(_)
|
||||||
| Type::Dynamic(_)
|
| Type::Dynamic(_)
|
||||||
|
@ -1102,15 +1098,13 @@ impl<'db> Type<'db> {
|
||||||
| Type::BytesLiteral(_)
|
| Type::BytesLiteral(_)
|
||||||
| Type::ClassLiteral(_)
|
| Type::ClassLiteral(_)
|
||||||
| Type::FunctionLiteral(_)
|
| Type::FunctionLiteral(_)
|
||||||
| Type::ModuleLiteral(_)
|
| Type::ModuleLiteral(_),
|
||||||
| Type::SliceLiteral(_),
|
|
||||||
Type::StringLiteral(_)
|
Type::StringLiteral(_)
|
||||||
| Type::IntLiteral(_)
|
| Type::IntLiteral(_)
|
||||||
| Type::BytesLiteral(_)
|
| Type::BytesLiteral(_)
|
||||||
| Type::ClassLiteral(_)
|
| Type::ClassLiteral(_)
|
||||||
| Type::FunctionLiteral(_)
|
| Type::FunctionLiteral(_)
|
||||||
| Type::ModuleLiteral(_)
|
| Type::ModuleLiteral(_),
|
||||||
| Type::SliceLiteral(_),
|
|
||||||
) => false,
|
) => false,
|
||||||
|
|
||||||
// All `StringLiteral` types are a subtype of `LiteralString`.
|
// All `StringLiteral` types are a subtype of `LiteralString`.
|
||||||
|
@ -1132,9 +1126,6 @@ impl<'db> Type<'db> {
|
||||||
(Type::ModuleLiteral(_), _) => KnownClass::ModuleType
|
(Type::ModuleLiteral(_), _) => KnownClass::ModuleType
|
||||||
.to_instance(db)
|
.to_instance(db)
|
||||||
.is_subtype_of(db, target),
|
.is_subtype_of(db, target),
|
||||||
(Type::SliceLiteral(_), _) => {
|
|
||||||
KnownClass::Slice.to_instance(db).is_subtype_of(db, target)
|
|
||||||
}
|
|
||||||
|
|
||||||
(Type::FunctionLiteral(self_function_literal), Type::Callable(_)) => {
|
(Type::FunctionLiteral(self_function_literal), Type::Callable(_)) => {
|
||||||
self_function_literal
|
self_function_literal
|
||||||
|
@ -1516,10 +1507,6 @@ impl<'db> Type<'db> {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
(Type::SliceLiteral(_), _) => KnownClass::Slice
|
|
||||||
.to_instance(db)
|
|
||||||
.is_assignable_to(db, target),
|
|
||||||
|
|
||||||
(Type::FunctionLiteral(self_function_literal), Type::Callable(_)) => {
|
(Type::FunctionLiteral(self_function_literal), Type::Callable(_)) => {
|
||||||
self_function_literal
|
self_function_literal
|
||||||
.into_callable_type(db)
|
.into_callable_type(db)
|
||||||
|
@ -1711,7 +1698,6 @@ impl<'db> Type<'db> {
|
||||||
| Type::IntLiteral(..)
|
| Type::IntLiteral(..)
|
||||||
| Type::StringLiteral(..)
|
| Type::StringLiteral(..)
|
||||||
| Type::BytesLiteral(..)
|
| Type::BytesLiteral(..)
|
||||||
| Type::SliceLiteral(..)
|
|
||||||
| Type::FunctionLiteral(..)
|
| Type::FunctionLiteral(..)
|
||||||
| Type::BoundMethod(..)
|
| Type::BoundMethod(..)
|
||||||
| Type::MethodWrapper(..)
|
| Type::MethodWrapper(..)
|
||||||
|
@ -1724,7 +1710,6 @@ impl<'db> Type<'db> {
|
||||||
| Type::IntLiteral(..)
|
| Type::IntLiteral(..)
|
||||||
| Type::StringLiteral(..)
|
| Type::StringLiteral(..)
|
||||||
| Type::BytesLiteral(..)
|
| Type::BytesLiteral(..)
|
||||||
| Type::SliceLiteral(..)
|
|
||||||
| Type::FunctionLiteral(..)
|
| Type::FunctionLiteral(..)
|
||||||
| Type::BoundMethod(..)
|
| Type::BoundMethod(..)
|
||||||
| Type::MethodWrapper(..)
|
| Type::MethodWrapper(..)
|
||||||
|
@ -1751,7 +1736,6 @@ impl<'db> Type<'db> {
|
||||||
| Type::DataclassDecorator(..)
|
| Type::DataclassDecorator(..)
|
||||||
| Type::DataclassTransformer(..)
|
| Type::DataclassTransformer(..)
|
||||||
| Type::IntLiteral(..)
|
| Type::IntLiteral(..)
|
||||||
| Type::SliceLiteral(..)
|
|
||||||
| Type::StringLiteral(..)
|
| Type::StringLiteral(..)
|
||||||
| Type::LiteralString,
|
| Type::LiteralString,
|
||||||
)
|
)
|
||||||
|
@ -1768,7 +1752,6 @@ impl<'db> Type<'db> {
|
||||||
| Type::DataclassDecorator(..)
|
| Type::DataclassDecorator(..)
|
||||||
| Type::DataclassTransformer(..)
|
| Type::DataclassTransformer(..)
|
||||||
| Type::IntLiteral(..)
|
| Type::IntLiteral(..)
|
||||||
| Type::SliceLiteral(..)
|
|
||||||
| Type::StringLiteral(..)
|
| Type::StringLiteral(..)
|
||||||
| Type::LiteralString,
|
| Type::LiteralString,
|
||||||
Type::Tuple(..),
|
Type::Tuple(..),
|
||||||
|
@ -1799,7 +1782,6 @@ impl<'db> Type<'db> {
|
||||||
| Type::StringLiteral(..)
|
| Type::StringLiteral(..)
|
||||||
| Type::LiteralString
|
| Type::LiteralString
|
||||||
| Type::BytesLiteral(..)
|
| Type::BytesLiteral(..)
|
||||||
| Type::SliceLiteral(..)
|
|
||||||
| Type::FunctionLiteral(..)
|
| Type::FunctionLiteral(..)
|
||||||
| Type::BoundMethod(..)
|
| Type::BoundMethod(..)
|
||||||
| Type::MethodWrapper(..)
|
| Type::MethodWrapper(..)
|
||||||
|
@ -1812,7 +1794,6 @@ impl<'db> Type<'db> {
|
||||||
| Type::StringLiteral(..)
|
| Type::StringLiteral(..)
|
||||||
| Type::LiteralString
|
| Type::LiteralString
|
||||||
| Type::BytesLiteral(..)
|
| Type::BytesLiteral(..)
|
||||||
| Type::SliceLiteral(..)
|
|
||||||
| Type::FunctionLiteral(..)
|
| Type::FunctionLiteral(..)
|
||||||
| Type::BoundMethod(..)
|
| Type::BoundMethod(..)
|
||||||
| Type::MethodWrapper(..)
|
| Type::MethodWrapper(..)
|
||||||
|
@ -1848,7 +1829,6 @@ impl<'db> Type<'db> {
|
||||||
| Type::StringLiteral(..)
|
| Type::StringLiteral(..)
|
||||||
| Type::BytesLiteral(..)
|
| Type::BytesLiteral(..)
|
||||||
| Type::BooleanLiteral(..)
|
| Type::BooleanLiteral(..)
|
||||||
| Type::SliceLiteral(..)
|
|
||||||
| Type::ClassLiteral(..)
|
| Type::ClassLiteral(..)
|
||||||
| Type::FunctionLiteral(..)
|
| Type::FunctionLiteral(..)
|
||||||
| Type::ModuleLiteral(..)
|
| Type::ModuleLiteral(..)
|
||||||
|
@ -1862,7 +1842,6 @@ impl<'db> Type<'db> {
|
||||||
| Type::StringLiteral(..)
|
| Type::StringLiteral(..)
|
||||||
| Type::BytesLiteral(..)
|
| Type::BytesLiteral(..)
|
||||||
| Type::BooleanLiteral(..)
|
| Type::BooleanLiteral(..)
|
||||||
| Type::SliceLiteral(..)
|
|
||||||
| Type::ClassLiteral(..)
|
| Type::ClassLiteral(..)
|
||||||
| Type::FunctionLiteral(..)
|
| Type::FunctionLiteral(..)
|
||||||
| Type::ModuleLiteral(..)
|
| Type::ModuleLiteral(..)
|
||||||
|
@ -1953,13 +1932,6 @@ impl<'db> Type<'db> {
|
||||||
!KnownClass::Bytes.is_subclass_of(db, instance.class())
|
!KnownClass::Bytes.is_subclass_of(db, instance.class())
|
||||||
}
|
}
|
||||||
|
|
||||||
(Type::SliceLiteral(..), Type::NominalInstance(instance))
|
|
||||||
| (Type::NominalInstance(instance), Type::SliceLiteral(..)) => {
|
|
||||||
// A `Type::SliceLiteral` must be an instance of exactly `slice`
|
|
||||||
// (it cannot be an instance of a `slice` subclass)
|
|
||||||
!KnownClass::Slice.is_subclass_of(db, instance.class())
|
|
||||||
}
|
|
||||||
|
|
||||||
// A class-literal type `X` is always disjoint from an instance type `Y`,
|
// A class-literal type `X` is always disjoint from an instance type `Y`,
|
||||||
// unless the type expressing "all instances of `Z`" is a subtype of of `Y`,
|
// unless the type expressing "all instances of `Z`" is a subtype of of `Y`,
|
||||||
// where `Z` is `X`'s metaclass.
|
// where `Z` is `X`'s metaclass.
|
||||||
|
@ -2005,14 +1977,8 @@ impl<'db> Type<'db> {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
(
|
(Type::Callable(_), Type::StringLiteral(_) | Type::BytesLiteral(_))
|
||||||
Type::Callable(_),
|
| (Type::StringLiteral(_) | Type::BytesLiteral(_), Type::Callable(_)) => {
|
||||||
Type::StringLiteral(_) | Type::BytesLiteral(_) | Type::SliceLiteral(_),
|
|
||||||
)
|
|
||||||
| (
|
|
||||||
Type::StringLiteral(_) | Type::BytesLiteral(_) | Type::SliceLiteral(_),
|
|
||||||
Type::Callable(_),
|
|
||||||
) => {
|
|
||||||
// A callable type is disjoint from other literal types. For example,
|
// A callable type is disjoint from other literal types. For example,
|
||||||
// `Type::StringLiteral` must be an instance of exactly `str`, not a subclass
|
// `Type::StringLiteral` must be an instance of exactly `str`, not a subclass
|
||||||
// of `str`, and `str` is not callable. The same applies to other literal types.
|
// of `str`, and `str` is not callable. The same applies to other literal types.
|
||||||
|
@ -2092,7 +2058,6 @@ impl<'db> Type<'db> {
|
||||||
| Type::StringLiteral(_)
|
| Type::StringLiteral(_)
|
||||||
| Type::LiteralString
|
| Type::LiteralString
|
||||||
| Type::BytesLiteral(_)
|
| Type::BytesLiteral(_)
|
||||||
| Type::SliceLiteral(_)
|
|
||||||
| Type::KnownInstance(_)
|
| Type::KnownInstance(_)
|
||||||
| Type::AlwaysFalsy
|
| Type::AlwaysFalsy
|
||||||
| Type::AlwaysTruthy
|
| Type::AlwaysTruthy
|
||||||
|
@ -2157,7 +2122,6 @@ impl<'db> Type<'db> {
|
||||||
| Type::IntLiteral(..)
|
| Type::IntLiteral(..)
|
||||||
| Type::StringLiteral(..)
|
| Type::StringLiteral(..)
|
||||||
| Type::BytesLiteral(..)
|
| Type::BytesLiteral(..)
|
||||||
| Type::SliceLiteral(..)
|
|
||||||
| Type::LiteralString => {
|
| Type::LiteralString => {
|
||||||
// Note: The literal types included in this pattern are not true singletons.
|
// Note: The literal types included in this pattern are not true singletons.
|
||||||
// There can be multiple Python objects (at different memory locations) that
|
// There can be multiple Python objects (at different memory locations) that
|
||||||
|
@ -2284,7 +2248,6 @@ impl<'db> Type<'db> {
|
||||||
| Type::BooleanLiteral(..)
|
| Type::BooleanLiteral(..)
|
||||||
| Type::StringLiteral(..)
|
| Type::StringLiteral(..)
|
||||||
| Type::BytesLiteral(..)
|
| Type::BytesLiteral(..)
|
||||||
| Type::SliceLiteral(..)
|
|
||||||
| Type::KnownInstance(..) => true,
|
| Type::KnownInstance(..) => true,
|
||||||
|
|
||||||
Type::ProtocolInstance(..) => {
|
Type::ProtocolInstance(..) => {
|
||||||
|
@ -2481,7 +2444,6 @@ impl<'db> Type<'db> {
|
||||||
| Type::StringLiteral(_)
|
| Type::StringLiteral(_)
|
||||||
| Type::LiteralString
|
| Type::LiteralString
|
||||||
| Type::BytesLiteral(_)
|
| Type::BytesLiteral(_)
|
||||||
| Type::SliceLiteral(_)
|
|
||||||
| Type::Tuple(_)
|
| Type::Tuple(_)
|
||||||
| Type::TypeVar(_)
|
| Type::TypeVar(_)
|
||||||
| Type::NominalInstance(_)
|
| Type::NominalInstance(_)
|
||||||
|
@ -2591,7 +2553,6 @@ impl<'db> Type<'db> {
|
||||||
KnownClass::Str.to_instance(db).instance_member(db, name)
|
KnownClass::Str.to_instance(db).instance_member(db, name)
|
||||||
}
|
}
|
||||||
Type::BytesLiteral(_) => KnownClass::Bytes.to_instance(db).instance_member(db, name),
|
Type::BytesLiteral(_) => KnownClass::Bytes.to_instance(db).instance_member(db, name),
|
||||||
Type::SliceLiteral(_) => KnownClass::Slice.to_instance(db).instance_member(db, name),
|
|
||||||
Type::Tuple(_) => KnownClass::Tuple.to_instance(db).instance_member(db, name),
|
Type::Tuple(_) => KnownClass::Tuple.to_instance(db).instance_member(db, name),
|
||||||
|
|
||||||
Type::AlwaysTruthy | Type::AlwaysFalsy => Type::object(db).instance_member(db, name),
|
Type::AlwaysTruthy | Type::AlwaysFalsy => Type::object(db).instance_member(db, name),
|
||||||
|
@ -3046,7 +3007,6 @@ impl<'db> Type<'db> {
|
||||||
| Type::StringLiteral(..)
|
| Type::StringLiteral(..)
|
||||||
| Type::BytesLiteral(..)
|
| Type::BytesLiteral(..)
|
||||||
| Type::LiteralString
|
| Type::LiteralString
|
||||||
| Type::SliceLiteral(..)
|
|
||||||
| Type::Tuple(..)
|
| Type::Tuple(..)
|
||||||
| Type::TypeVar(..)
|
| Type::TypeVar(..)
|
||||||
| Type::KnownInstance(..)
|
| Type::KnownInstance(..)
|
||||||
|
@ -3303,7 +3263,6 @@ impl<'db> Type<'db> {
|
||||||
| Type::DataclassDecorator(_)
|
| Type::DataclassDecorator(_)
|
||||||
| Type::DataclassTransformer(_)
|
| Type::DataclassTransformer(_)
|
||||||
| Type::ModuleLiteral(_)
|
| Type::ModuleLiteral(_)
|
||||||
| Type::SliceLiteral(_)
|
|
||||||
| Type::AlwaysTruthy => Truthiness::AlwaysTrue,
|
| Type::AlwaysTruthy => Truthiness::AlwaysTrue,
|
||||||
|
|
||||||
Type::AlwaysFalsy => Truthiness::AlwaysFalse,
|
Type::AlwaysFalsy => Truthiness::AlwaysFalse,
|
||||||
|
@ -4210,7 +4169,6 @@ impl<'db> Type<'db> {
|
||||||
| Type::BytesLiteral(_)
|
| Type::BytesLiteral(_)
|
||||||
| Type::BooleanLiteral(_)
|
| Type::BooleanLiteral(_)
|
||||||
| Type::LiteralString
|
| Type::LiteralString
|
||||||
| Type::SliceLiteral(_)
|
|
||||||
| Type::Tuple(_)
|
| Type::Tuple(_)
|
||||||
| Type::BoundSuper(_)
|
| Type::BoundSuper(_)
|
||||||
| Type::TypeVar(_)
|
| Type::TypeVar(_)
|
||||||
|
@ -4660,7 +4618,6 @@ impl<'db> Type<'db> {
|
||||||
| Type::ModuleLiteral(_)
|
| Type::ModuleLiteral(_)
|
||||||
| Type::IntLiteral(_)
|
| Type::IntLiteral(_)
|
||||||
| Type::StringLiteral(_)
|
| Type::StringLiteral(_)
|
||||||
| Type::SliceLiteral(_)
|
|
||||||
| Type::Tuple(_)
|
| Type::Tuple(_)
|
||||||
| Type::TypeVar(_)
|
| Type::TypeVar(_)
|
||||||
| Type::LiteralString
|
| Type::LiteralString
|
||||||
|
@ -4713,7 +4670,6 @@ impl<'db> Type<'db> {
|
||||||
| Type::BytesLiteral(_)
|
| Type::BytesLiteral(_)
|
||||||
| Type::AlwaysTruthy
|
| Type::AlwaysTruthy
|
||||||
| Type::AlwaysFalsy
|
| Type::AlwaysFalsy
|
||||||
| Type::SliceLiteral(_)
|
|
||||||
| Type::IntLiteral(_)
|
| Type::IntLiteral(_)
|
||||||
| Type::LiteralString
|
| Type::LiteralString
|
||||||
| Type::ModuleLiteral(_)
|
| Type::ModuleLiteral(_)
|
||||||
|
@ -4972,7 +4928,6 @@ impl<'db> Type<'db> {
|
||||||
Type::Union(union) => union.map(db, |ty| ty.to_meta_type(db)),
|
Type::Union(union) => union.map(db, |ty| ty.to_meta_type(db)),
|
||||||
Type::BooleanLiteral(_) => KnownClass::Bool.to_class_literal(db),
|
Type::BooleanLiteral(_) => KnownClass::Bool.to_class_literal(db),
|
||||||
Type::BytesLiteral(_) => KnownClass::Bytes.to_class_literal(db),
|
Type::BytesLiteral(_) => KnownClass::Bytes.to_class_literal(db),
|
||||||
Type::SliceLiteral(_) => KnownClass::Slice.to_class_literal(db),
|
|
||||||
Type::IntLiteral(_) => KnownClass::Int.to_class_literal(db),
|
Type::IntLiteral(_) => KnownClass::Int.to_class_literal(db),
|
||||||
Type::FunctionLiteral(_) => KnownClass::FunctionType.to_class_literal(db),
|
Type::FunctionLiteral(_) => KnownClass::FunctionType.to_class_literal(db),
|
||||||
Type::BoundMethod(_) => KnownClass::MethodType.to_class_literal(db),
|
Type::BoundMethod(_) => KnownClass::MethodType.to_class_literal(db),
|
||||||
|
@ -5151,7 +5106,6 @@ impl<'db> Type<'db> {
|
||||||
| Type::LiteralString
|
| Type::LiteralString
|
||||||
| Type::StringLiteral(_)
|
| Type::StringLiteral(_)
|
||||||
| Type::BytesLiteral(_)
|
| Type::BytesLiteral(_)
|
||||||
| Type::SliceLiteral(_)
|
|
||||||
| Type::BoundSuper(_)
|
| Type::BoundSuper(_)
|
||||||
// Same for `ProtocolInstance`
|
// Same for `ProtocolInstance`
|
||||||
| Type::ProtocolInstance(_)
|
| Type::ProtocolInstance(_)
|
||||||
|
@ -5242,7 +5196,6 @@ impl<'db> Type<'db> {
|
||||||
| Type::LiteralString
|
| Type::LiteralString
|
||||||
| Type::StringLiteral(_)
|
| Type::StringLiteral(_)
|
||||||
| Type::BytesLiteral(_)
|
| Type::BytesLiteral(_)
|
||||||
| Type::SliceLiteral(_)
|
|
||||||
| Type::BoundSuper(_)
|
| Type::BoundSuper(_)
|
||||||
| Type::NominalInstance(_)
|
| Type::NominalInstance(_)
|
||||||
| Type::ProtocolInstance(_)
|
| Type::ProtocolInstance(_)
|
||||||
|
@ -5334,7 +5287,6 @@ impl<'db> Type<'db> {
|
||||||
| Self::LiteralString
|
| Self::LiteralString
|
||||||
| Self::IntLiteral(_)
|
| Self::IntLiteral(_)
|
||||||
| Self::BytesLiteral(_)
|
| Self::BytesLiteral(_)
|
||||||
| Self::SliceLiteral(_)
|
|
||||||
| Self::MethodWrapper(_)
|
| Self::MethodWrapper(_)
|
||||||
| Self::WrapperDescriptor(_)
|
| Self::WrapperDescriptor(_)
|
||||||
| Self::DataclassDecorator(_)
|
| Self::DataclassDecorator(_)
|
||||||
|
@ -7947,18 +7899,6 @@ impl<'db> BytesLiteralType<'db> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[salsa::interned(debug)]
|
|
||||||
pub struct SliceLiteralType<'db> {
|
|
||||||
start: Option<i32>,
|
|
||||||
stop: Option<i32>,
|
|
||||||
step: Option<i32>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl SliceLiteralType<'_> {
|
|
||||||
fn as_tuple(self, db: &dyn Db) -> (Option<i32>, Option<i32>, Option<i32>) {
|
|
||||||
(self.start(db), self.stop(db), self.step(db))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#[salsa::interned(debug)]
|
#[salsa::interned(debug)]
|
||||||
pub struct TupleType<'db> {
|
pub struct TupleType<'db> {
|
||||||
#[return_ref]
|
#[return_ref]
|
||||||
|
|
|
@ -2662,6 +2662,47 @@ impl<'db> KnownClassLookupError<'db> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) struct SliceLiteral {
|
||||||
|
pub(crate) start: Option<i32>,
|
||||||
|
pub(crate) stop: Option<i32>,
|
||||||
|
pub(crate) step: Option<i32>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'db> Type<'db> {
|
||||||
|
/// If this type represents a valid slice literal, returns a [`SliceLiteral`] describing it.
|
||||||
|
/// Otherwise returns `None`.
|
||||||
|
///
|
||||||
|
/// The type must be a specialization of the `slice` builtin type, where the specialized
|
||||||
|
/// typevars are statically known integers or `None`.
|
||||||
|
pub(crate) fn slice_literal(self, db: &'db dyn Db) -> Option<SliceLiteral> {
|
||||||
|
let ClassType::Generic(alias) = self.into_nominal_instance()?.class() else {
|
||||||
|
return None;
|
||||||
|
};
|
||||||
|
if !alias.origin(db).is_known(db, KnownClass::Slice) {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
let [start, stop, step] = alias.specialization(db).types(db).as_ref() else {
|
||||||
|
return None;
|
||||||
|
};
|
||||||
|
|
||||||
|
let to_u32 = |ty: &Type<'db>| match ty {
|
||||||
|
Type::IntLiteral(n) => i32::try_from(*n).map(Some).ok(),
|
||||||
|
Type::BooleanLiteral(b) => Some(Some(i32::from(*b))),
|
||||||
|
Type::NominalInstance(instance)
|
||||||
|
if instance.class().is_known(db, KnownClass::NoneType) =>
|
||||||
|
{
|
||||||
|
Some(None)
|
||||||
|
}
|
||||||
|
_ => None,
|
||||||
|
};
|
||||||
|
Some(SliceLiteral {
|
||||||
|
start: to_u32(start)?,
|
||||||
|
stop: to_u32(stop)?,
|
||||||
|
step: to_u32(step)?,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, salsa::Update)]
|
#[derive(Debug, Clone, PartialEq, Eq, salsa::Update)]
|
||||||
pub(super) struct MetaclassError<'db> {
|
pub(super) struct MetaclassError<'db> {
|
||||||
kind: MetaclassErrorKind<'db>,
|
kind: MetaclassErrorKind<'db>,
|
||||||
|
|
|
@ -125,7 +125,6 @@ impl<'db> ClassBase<'db> {
|
||||||
| Type::StringLiteral(_)
|
| Type::StringLiteral(_)
|
||||||
| Type::LiteralString
|
| Type::LiteralString
|
||||||
| Type::Tuple(_)
|
| Type::Tuple(_)
|
||||||
| Type::SliceLiteral(_)
|
|
||||||
| Type::ModuleLiteral(_)
|
| Type::ModuleLiteral(_)
|
||||||
| Type::SubclassOf(_)
|
| Type::SubclassOf(_)
|
||||||
| Type::TypeVar(_)
|
| Type::TypeVar(_)
|
||||||
|
|
|
@ -228,28 +228,6 @@ impl Display for DisplayRepresentation<'_> {
|
||||||
|
|
||||||
escape.bytes_repr(TripleQuotes::No).write(f)
|
escape.bytes_repr(TripleQuotes::No).write(f)
|
||||||
}
|
}
|
||||||
Type::SliceLiteral(slice) => {
|
|
||||||
f.write_str("slice[")?;
|
|
||||||
if let Some(start) = slice.start(self.db) {
|
|
||||||
write!(f, "Literal[{start}]")?;
|
|
||||||
} else {
|
|
||||||
f.write_str("None")?;
|
|
||||||
}
|
|
||||||
|
|
||||||
f.write_str(", ")?;
|
|
||||||
|
|
||||||
if let Some(stop) = slice.stop(self.db) {
|
|
||||||
write!(f, "Literal[{stop}]")?;
|
|
||||||
} else {
|
|
||||||
f.write_str("None")?;
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(step) = slice.step(self.db) {
|
|
||||||
write!(f, ", Literal[{step}]")?;
|
|
||||||
}
|
|
||||||
|
|
||||||
f.write_str("]")
|
|
||||||
}
|
|
||||||
Type::Tuple(tuple) => {
|
Type::Tuple(tuple) => {
|
||||||
f.write_str("tuple[")?;
|
f.write_str("tuple[")?;
|
||||||
let elements = tuple.elements(self.db);
|
let elements = tuple.elements(self.db);
|
||||||
|
@ -752,53 +730,9 @@ mod tests {
|
||||||
|
|
||||||
use crate::db::tests::setup_db;
|
use crate::db::tests::setup_db;
|
||||||
use crate::symbol::typing_extensions_symbol;
|
use crate::symbol::typing_extensions_symbol;
|
||||||
use crate::types::{
|
use crate::types::{KnownClass, Parameter, Parameters, Signature, StringLiteralType, Type};
|
||||||
KnownClass, Parameter, Parameters, Signature, SliceLiteralType, StringLiteralType, Type,
|
|
||||||
};
|
|
||||||
use crate::Db;
|
use crate::Db;
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_slice_literal_display() {
|
|
||||||
let db = setup_db();
|
|
||||||
|
|
||||||
assert_eq!(
|
|
||||||
Type::SliceLiteral(SliceLiteralType::new(&db, None, None, None))
|
|
||||||
.display(&db)
|
|
||||||
.to_string(),
|
|
||||||
"slice[None, None]"
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
Type::SliceLiteral(SliceLiteralType::new(&db, Some(1), None, None))
|
|
||||||
.display(&db)
|
|
||||||
.to_string(),
|
|
||||||
"slice[Literal[1], None]"
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
Type::SliceLiteral(SliceLiteralType::new(&db, None, Some(2), None))
|
|
||||||
.display(&db)
|
|
||||||
.to_string(),
|
|
||||||
"slice[None, Literal[2]]"
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
Type::SliceLiteral(SliceLiteralType::new(&db, Some(1), Some(5), None))
|
|
||||||
.display(&db)
|
|
||||||
.to_string(),
|
|
||||||
"slice[Literal[1], Literal[5]]"
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
Type::SliceLiteral(SliceLiteralType::new(&db, Some(1), Some(5), Some(2)))
|
|
||||||
.display(&db)
|
|
||||||
.to_string(),
|
|
||||||
"slice[Literal[1], Literal[5], Literal[2]]"
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
Type::SliceLiteral(SliceLiteralType::new(&db, None, None, Some(2)))
|
|
||||||
.display(&db)
|
|
||||||
.to_string(),
|
|
||||||
"slice[None, None, Literal[2]]"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn string_literal_display() {
|
fn string_literal_display() {
|
||||||
let db = setup_db();
|
let db = setup_db();
|
||||||
|
|
|
@ -65,7 +65,7 @@ use crate::symbol::{
|
||||||
typing_extensions_symbol, Boundness, LookupError,
|
typing_extensions_symbol, Boundness, LookupError,
|
||||||
};
|
};
|
||||||
use crate::types::call::{Argument, Bindings, CallArgumentTypes, CallArguments, CallError};
|
use crate::types::call::{Argument, Bindings, CallArgumentTypes, CallArguments, CallError};
|
||||||
use crate::types::class::MetaclassErrorKind;
|
use crate::types::class::{MetaclassErrorKind, SliceLiteral};
|
||||||
use crate::types::diagnostic::{
|
use crate::types::diagnostic::{
|
||||||
report_implicit_return_type, report_invalid_arguments_to_annotated,
|
report_implicit_return_type, report_invalid_arguments_to_annotated,
|
||||||
report_invalid_arguments_to_callable, report_invalid_assignment,
|
report_invalid_arguments_to_callable, report_invalid_assignment,
|
||||||
|
@ -87,10 +87,10 @@ use crate::types::{
|
||||||
ClassType, DataclassParams, DynamicType, FunctionDecorators, FunctionType, GenericAlias,
|
ClassType, DataclassParams, DynamicType, FunctionDecorators, FunctionType, GenericAlias,
|
||||||
IntersectionBuilder, IntersectionType, KnownClass, KnownFunction, KnownInstanceType,
|
IntersectionBuilder, IntersectionType, KnownClass, KnownFunction, KnownInstanceType,
|
||||||
MemberLookupPolicy, MetaclassCandidate, Parameter, ParameterForm, Parameters, Signature,
|
MemberLookupPolicy, MetaclassCandidate, Parameter, ParameterForm, Parameters, Signature,
|
||||||
Signatures, SliceLiteralType, StringLiteralType, SubclassOfType, Symbol, SymbolAndQualifiers,
|
Signatures, StringLiteralType, SubclassOfType, Symbol, SymbolAndQualifiers, Truthiness,
|
||||||
Truthiness, TupleType, Type, TypeAliasType, TypeAndQualifiers, TypeArrayDisplay,
|
TupleType, Type, TypeAliasType, TypeAndQualifiers, TypeArrayDisplay, TypeQualifiers,
|
||||||
TypeQualifiers, TypeVarBoundOrConstraints, TypeVarInstance, TypeVarKind, TypeVarVariance,
|
TypeVarBoundOrConstraints, TypeVarInstance, TypeVarKind, TypeVarVariance, UnionBuilder,
|
||||||
UnionBuilder, UnionType,
|
UnionType,
|
||||||
};
|
};
|
||||||
use crate::unpack::{Unpack, UnpackPosition};
|
use crate::unpack::{Unpack, UnpackPosition};
|
||||||
use crate::util::subscript::{PyIndex, PySlice};
|
use crate::util::subscript::{PyIndex, PySlice};
|
||||||
|
@ -2911,7 +2911,6 @@ impl<'db> TypeInferenceBuilder<'db> {
|
||||||
| Type::StringLiteral(..)
|
| Type::StringLiteral(..)
|
||||||
| Type::BytesLiteral(..)
|
| Type::BytesLiteral(..)
|
||||||
| Type::LiteralString
|
| Type::LiteralString
|
||||||
| Type::SliceLiteral(..)
|
|
||||||
| Type::Tuple(..)
|
| Type::Tuple(..)
|
||||||
| Type::KnownInstance(..)
|
| Type::KnownInstance(..)
|
||||||
| Type::PropertyInstance(..)
|
| Type::PropertyInstance(..)
|
||||||
|
@ -5653,7 +5652,6 @@ impl<'db> TypeInferenceBuilder<'db> {
|
||||||
| Type::StringLiteral(_)
|
| Type::StringLiteral(_)
|
||||||
| Type::LiteralString
|
| Type::LiteralString
|
||||||
| Type::BytesLiteral(_)
|
| Type::BytesLiteral(_)
|
||||||
| Type::SliceLiteral(_)
|
|
||||||
| Type::Tuple(_)
|
| Type::Tuple(_)
|
||||||
| Type::BoundSuper(_)
|
| Type::BoundSuper(_)
|
||||||
| Type::TypeVar(_),
|
| Type::TypeVar(_),
|
||||||
|
@ -5952,7 +5950,6 @@ impl<'db> TypeInferenceBuilder<'db> {
|
||||||
| Type::StringLiteral(_)
|
| Type::StringLiteral(_)
|
||||||
| Type::LiteralString
|
| Type::LiteralString
|
||||||
| Type::BytesLiteral(_)
|
| Type::BytesLiteral(_)
|
||||||
| Type::SliceLiteral(_)
|
|
||||||
| Type::Tuple(_)
|
| Type::Tuple(_)
|
||||||
| Type::BoundSuper(_)
|
| Type::BoundSuper(_)
|
||||||
| Type::TypeVar(_),
|
| Type::TypeVar(_),
|
||||||
|
@ -5978,7 +5975,6 @@ impl<'db> TypeInferenceBuilder<'db> {
|
||||||
| Type::StringLiteral(_)
|
| Type::StringLiteral(_)
|
||||||
| Type::LiteralString
|
| Type::LiteralString
|
||||||
| Type::BytesLiteral(_)
|
| Type::BytesLiteral(_)
|
||||||
| Type::SliceLiteral(_)
|
|
||||||
| Type::Tuple(_)
|
| Type::Tuple(_)
|
||||||
| Type::BoundSuper(_)
|
| Type::BoundSuper(_)
|
||||||
| Type::TypeVar(_),
|
| Type::TypeVar(_),
|
||||||
|
@ -6931,11 +6927,9 @@ impl<'db> TypeInferenceBuilder<'db> {
|
||||||
value_ty: Type<'db>,
|
value_ty: Type<'db>,
|
||||||
slice_ty: Type<'db>,
|
slice_ty: Type<'db>,
|
||||||
) -> Type<'db> {
|
) -> Type<'db> {
|
||||||
match (value_ty, slice_ty) {
|
match (value_ty, slice_ty, slice_ty.slice_literal(self.db())) {
|
||||||
(
|
(Type::NominalInstance(instance), _, _)
|
||||||
Type::NominalInstance(instance),
|
if instance
|
||||||
Type::IntLiteral(_) | Type::BooleanLiteral(_) | Type::SliceLiteral(_),
|
|
||||||
) if instance
|
|
||||||
.class()
|
.class()
|
||||||
.is_known(self.db(), KnownClass::VersionInfo) =>
|
.is_known(self.db(), KnownClass::VersionInfo) =>
|
||||||
{
|
{
|
||||||
|
@ -6947,7 +6941,7 @@ impl<'db> TypeInferenceBuilder<'db> {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ex) Given `("a", "b", "c", "d")[1]`, return `"b"`
|
// Ex) Given `("a", "b", "c", "d")[1]`, return `"b"`
|
||||||
(Type::Tuple(tuple_ty), Type::IntLiteral(int)) if i32::try_from(int).is_ok() => {
|
(Type::Tuple(tuple_ty), Type::IntLiteral(int), _) if i32::try_from(int).is_ok() => {
|
||||||
let elements = tuple_ty.elements(self.db());
|
let elements = tuple_ty.elements(self.db());
|
||||||
elements
|
elements
|
||||||
.iter()
|
.iter()
|
||||||
|
@ -6966,9 +6960,8 @@ impl<'db> TypeInferenceBuilder<'db> {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
// Ex) Given `("a", 1, Null)[0:2]`, return `("a", 1)`
|
// Ex) Given `("a", 1, Null)[0:2]`, return `("a", 1)`
|
||||||
(Type::Tuple(tuple_ty), Type::SliceLiteral(slice_ty)) => {
|
(Type::Tuple(tuple_ty), _, Some(SliceLiteral { start, stop, step })) => {
|
||||||
let elements = tuple_ty.elements(self.db());
|
let elements = tuple_ty.elements(self.db());
|
||||||
let (start, stop, step) = slice_ty.as_tuple(self.db());
|
|
||||||
|
|
||||||
if let Ok(new_elements) = elements.py_slice(start, stop, step) {
|
if let Ok(new_elements) = elements.py_slice(start, stop, step) {
|
||||||
TupleType::from_elements(self.db(), new_elements)
|
TupleType::from_elements(self.db(), new_elements)
|
||||||
|
@ -6978,7 +6971,7 @@ impl<'db> TypeInferenceBuilder<'db> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Ex) Given `"value"[1]`, return `"a"`
|
// Ex) Given `"value"[1]`, return `"a"`
|
||||||
(Type::StringLiteral(literal_ty), Type::IntLiteral(int))
|
(Type::StringLiteral(literal_ty), Type::IntLiteral(int), _)
|
||||||
if i32::try_from(int).is_ok() =>
|
if i32::try_from(int).is_ok() =>
|
||||||
{
|
{
|
||||||
let literal_value = literal_ty.value(self.db());
|
let literal_value = literal_ty.value(self.db());
|
||||||
|
@ -6999,9 +6992,8 @@ impl<'db> TypeInferenceBuilder<'db> {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
// Ex) Given `"value"[1:3]`, return `"al"`
|
// Ex) Given `"value"[1:3]`, return `"al"`
|
||||||
(Type::StringLiteral(literal_ty), Type::SliceLiteral(slice_ty)) => {
|
(Type::StringLiteral(literal_ty), _, Some(SliceLiteral { start, stop, step })) => {
|
||||||
let literal_value = literal_ty.value(self.db());
|
let literal_value = literal_ty.value(self.db());
|
||||||
let (start, stop, step) = slice_ty.as_tuple(self.db());
|
|
||||||
|
|
||||||
let chars: Vec<_> = literal_value.chars().collect();
|
let chars: Vec<_> = literal_value.chars().collect();
|
||||||
let result = if let Ok(new_chars) = chars.py_slice(start, stop, step) {
|
let result = if let Ok(new_chars) = chars.py_slice(start, stop, step) {
|
||||||
|
@ -7014,7 +7006,7 @@ impl<'db> TypeInferenceBuilder<'db> {
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
// Ex) Given `b"value"[1]`, return `b"a"`
|
// Ex) Given `b"value"[1]`, return `b"a"`
|
||||||
(Type::BytesLiteral(literal_ty), Type::IntLiteral(int))
|
(Type::BytesLiteral(literal_ty), Type::IntLiteral(int), _)
|
||||||
if i32::try_from(int).is_ok() =>
|
if i32::try_from(int).is_ok() =>
|
||||||
{
|
{
|
||||||
let literal_value = literal_ty.value(self.db());
|
let literal_value = literal_ty.value(self.db());
|
||||||
|
@ -7035,9 +7027,8 @@ impl<'db> TypeInferenceBuilder<'db> {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
// Ex) Given `b"value"[1:3]`, return `b"al"`
|
// Ex) Given `b"value"[1:3]`, return `b"al"`
|
||||||
(Type::BytesLiteral(literal_ty), Type::SliceLiteral(slice_ty)) => {
|
(Type::BytesLiteral(literal_ty), _, Some(SliceLiteral { start, stop, step })) => {
|
||||||
let literal_value = literal_ty.value(self.db());
|
let literal_value = literal_ty.value(self.db());
|
||||||
let (start, stop, step) = slice_ty.as_tuple(self.db());
|
|
||||||
|
|
||||||
if let Ok(new_bytes) = literal_value.py_slice(start, stop, step) {
|
if let Ok(new_bytes) = literal_value.py_slice(start, stop, step) {
|
||||||
let new_bytes: Vec<u8> = new_bytes.copied().collect();
|
let new_bytes: Vec<u8> = new_bytes.copied().collect();
|
||||||
|
@ -7051,29 +7042,30 @@ impl<'db> TypeInferenceBuilder<'db> {
|
||||||
(
|
(
|
||||||
Type::Tuple(_) | Type::StringLiteral(_) | Type::BytesLiteral(_),
|
Type::Tuple(_) | Type::StringLiteral(_) | Type::BytesLiteral(_),
|
||||||
Type::BooleanLiteral(bool),
|
Type::BooleanLiteral(bool),
|
||||||
|
_,
|
||||||
) => self.infer_subscript_expression_types(
|
) => self.infer_subscript_expression_types(
|
||||||
value_node,
|
value_node,
|
||||||
value_ty,
|
value_ty,
|
||||||
Type::IntLiteral(i64::from(bool)),
|
Type::IntLiteral(i64::from(bool)),
|
||||||
),
|
),
|
||||||
(Type::KnownInstance(KnownInstanceType::Protocol), _) => {
|
(Type::KnownInstance(KnownInstanceType::Protocol), _, _) => {
|
||||||
Type::Dynamic(DynamicType::SubscriptedProtocol)
|
Type::Dynamic(DynamicType::SubscriptedProtocol)
|
||||||
}
|
}
|
||||||
(Type::KnownInstance(KnownInstanceType::Generic(None)), Type::Tuple(typevars)) => {
|
(Type::KnownInstance(KnownInstanceType::Generic(None)), Type::Tuple(typevars), _) => {
|
||||||
self.infer_subscript_legacy_generic_class(value_node, typevars.elements(self.db()))
|
self.infer_subscript_legacy_generic_class(value_node, typevars.elements(self.db()))
|
||||||
}
|
}
|
||||||
(Type::KnownInstance(KnownInstanceType::Generic(None)), typevar) => self
|
(Type::KnownInstance(KnownInstanceType::Generic(None)), typevar, _) => self
|
||||||
.infer_subscript_legacy_generic_class(value_node, std::slice::from_ref(&typevar)),
|
.infer_subscript_legacy_generic_class(value_node, std::slice::from_ref(&typevar)),
|
||||||
(Type::KnownInstance(KnownInstanceType::Generic(Some(_))), _) => {
|
(Type::KnownInstance(KnownInstanceType::Generic(Some(_))), _, _) => {
|
||||||
// TODO: emit a diagnostic
|
// TODO: emit a diagnostic
|
||||||
todo_type!("doubly-specialized typing.Generic")
|
todo_type!("doubly-specialized typing.Generic")
|
||||||
}
|
}
|
||||||
(Type::KnownInstance(known_instance), _)
|
(Type::KnownInstance(known_instance), _, _)
|
||||||
if known_instance.class().is_special_form() =>
|
if known_instance.class().is_special_form() =>
|
||||||
{
|
{
|
||||||
todo_type!("Inference of subscript on special form")
|
todo_type!("Inference of subscript on special form")
|
||||||
}
|
}
|
||||||
(value_ty, slice_ty) => {
|
(value_ty, slice_ty, _) => {
|
||||||
// If the class defines `__getitem__`, return its return type.
|
// If the class defines `__getitem__`, return its return type.
|
||||||
//
|
//
|
||||||
// See: https://docs.python.org/3/reference/datamodel.html#class-getitem-versus-getitem
|
// See: https://docs.python.org/3/reference/datamodel.html#class-getitem-versus-getitem
|
||||||
|
@ -7252,8 +7244,8 @@ impl<'db> TypeInferenceBuilder<'db> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn infer_slice_expression(&mut self, slice: &ast::ExprSlice) -> Type<'db> {
|
fn infer_slice_expression(&mut self, slice: &ast::ExprSlice) -> Type<'db> {
|
||||||
enum SliceArg {
|
enum SliceArg<'db> {
|
||||||
Arg(Option<i32>),
|
Arg(Type<'db>),
|
||||||
Unsupported,
|
Unsupported,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7269,17 +7261,13 @@ impl<'db> TypeInferenceBuilder<'db> {
|
||||||
let ty_step = self.infer_optional_expression(step.as_deref());
|
let ty_step = self.infer_optional_expression(step.as_deref());
|
||||||
|
|
||||||
let type_to_slice_argument = |ty: Option<Type<'db>>| match ty {
|
let type_to_slice_argument = |ty: Option<Type<'db>>| match ty {
|
||||||
Some(Type::IntLiteral(n)) => match i32::try_from(n) {
|
Some(ty @ (Type::IntLiteral(_) | Type::BooleanLiteral(_))) => SliceArg::Arg(ty),
|
||||||
Ok(n) => SliceArg::Arg(Some(n)),
|
Some(ty @ Type::NominalInstance(instance))
|
||||||
Err(_) => SliceArg::Unsupported,
|
|
||||||
},
|
|
||||||
Some(Type::BooleanLiteral(b)) => SliceArg::Arg(Some(i32::from(b))),
|
|
||||||
Some(Type::NominalInstance(instance))
|
|
||||||
if instance.class().is_known(self.db(), KnownClass::NoneType) =>
|
if instance.class().is_known(self.db(), KnownClass::NoneType) =>
|
||||||
{
|
{
|
||||||
SliceArg::Arg(None)
|
SliceArg::Arg(ty)
|
||||||
}
|
}
|
||||||
None => SliceArg::Arg(None),
|
None => SliceArg::Arg(Type::none(self.db())),
|
||||||
_ => SliceArg::Unsupported,
|
_ => SliceArg::Unsupported,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -7289,7 +7277,7 @@ impl<'db> TypeInferenceBuilder<'db> {
|
||||||
type_to_slice_argument(ty_step),
|
type_to_slice_argument(ty_step),
|
||||||
) {
|
) {
|
||||||
(SliceArg::Arg(lower), SliceArg::Arg(upper), SliceArg::Arg(step)) => {
|
(SliceArg::Arg(lower), SliceArg::Arg(upper), SliceArg::Arg(step)) => {
|
||||||
Type::SliceLiteral(SliceLiteralType::new(self.db(), lower, upper, step))
|
KnownClass::Slice.to_specialized_instance(self.db(), [lower, upper, step])
|
||||||
}
|
}
|
||||||
_ => KnownClass::Slice.to_instance(self.db()),
|
_ => KnownClass::Slice.to_instance(self.db()),
|
||||||
}
|
}
|
||||||
|
|
|
@ -64,10 +64,6 @@ pub(super) fn union_or_intersection_elements_ordering<'db>(
|
||||||
(Type::BytesLiteral(_), _) => Ordering::Less,
|
(Type::BytesLiteral(_), _) => Ordering::Less,
|
||||||
(_, Type::BytesLiteral(_)) => Ordering::Greater,
|
(_, Type::BytesLiteral(_)) => Ordering::Greater,
|
||||||
|
|
||||||
(Type::SliceLiteral(left), Type::SliceLiteral(right)) => left.cmp(right),
|
|
||||||
(Type::SliceLiteral(_), _) => Ordering::Less,
|
|
||||||
(_, Type::SliceLiteral(_)) => Ordering::Greater,
|
|
||||||
|
|
||||||
(Type::FunctionLiteral(left), Type::FunctionLiteral(right)) => left.cmp(right),
|
(Type::FunctionLiteral(left), Type::FunctionLiteral(right)) => left.cmp(right),
|
||||||
(Type::FunctionLiteral(_), _) => Ordering::Less,
|
(Type::FunctionLiteral(_), _) => Ordering::Less,
|
||||||
(_, Type::FunctionLiteral(_)) => Ordering::Greater,
|
(_, Type::FunctionLiteral(_)) => Ordering::Greater,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue