mirror of
https://github.com/astral-sh/ruff.git
synced 2025-09-28 12:55:05 +00:00
[ty] Remove SliceLiteral
type variant (#17958)
@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
|
@ -520,8 +520,6 @@ pub enum Type<'db> {
|
|||
LiteralString,
|
||||
/// A bytes literal
|
||||
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.
|
||||
// TODO: Support variable length homogeneous tuple type like `tuple[int, ...]`.
|
||||
Tuple(TupleType<'db>),
|
||||
|
@ -607,7 +605,6 @@ impl<'db> Type<'db> {
|
|||
| Self::StringLiteral(_)
|
||||
| Self::IntLiteral(_)
|
||||
| Self::LiteralString
|
||||
| Self::SliceLiteral(_)
|
||||
| Self::Dynamic(DynamicType::Unknown | DynamicType::Any)
|
||||
| Self::BoundMethod(_)
|
||||
| Self::WrapperDescriptor(_)
|
||||
|
@ -905,7 +902,6 @@ impl<'db> Type<'db> {
|
|||
| Type::AlwaysFalsy
|
||||
| Type::AlwaysTruthy
|
||||
| Type::BooleanLiteral(_)
|
||||
| Type::SliceLiteral(_)
|
||||
| Type::BytesLiteral(_)
|
||||
| Type::StringLiteral(_)
|
||||
| Type::Dynamic(_)
|
||||
|
@ -1102,15 +1098,13 @@ impl<'db> Type<'db> {
|
|||
| Type::BytesLiteral(_)
|
||||
| Type::ClassLiteral(_)
|
||||
| Type::FunctionLiteral(_)
|
||||
| Type::ModuleLiteral(_)
|
||||
| Type::SliceLiteral(_),
|
||||
| Type::ModuleLiteral(_),
|
||||
Type::StringLiteral(_)
|
||||
| Type::IntLiteral(_)
|
||||
| Type::BytesLiteral(_)
|
||||
| Type::ClassLiteral(_)
|
||||
| Type::FunctionLiteral(_)
|
||||
| Type::ModuleLiteral(_)
|
||||
| Type::SliceLiteral(_),
|
||||
| Type::ModuleLiteral(_),
|
||||
) => false,
|
||||
|
||||
// All `StringLiteral` types are a subtype of `LiteralString`.
|
||||
|
@ -1132,9 +1126,6 @@ impl<'db> Type<'db> {
|
|||
(Type::ModuleLiteral(_), _) => KnownClass::ModuleType
|
||||
.to_instance(db)
|
||||
.is_subtype_of(db, target),
|
||||
(Type::SliceLiteral(_), _) => {
|
||||
KnownClass::Slice.to_instance(db).is_subtype_of(db, target)
|
||||
}
|
||||
|
||||
(Type::FunctionLiteral(self_function_literal), Type::Callable(_)) => {
|
||||
self_function_literal
|
||||
|
@ -1516,10 +1507,6 @@ impl<'db> Type<'db> {
|
|||
false
|
||||
}
|
||||
|
||||
(Type::SliceLiteral(_), _) => KnownClass::Slice
|
||||
.to_instance(db)
|
||||
.is_assignable_to(db, target),
|
||||
|
||||
(Type::FunctionLiteral(self_function_literal), Type::Callable(_)) => {
|
||||
self_function_literal
|
||||
.into_callable_type(db)
|
||||
|
@ -1711,7 +1698,6 @@ impl<'db> Type<'db> {
|
|||
| Type::IntLiteral(..)
|
||||
| Type::StringLiteral(..)
|
||||
| Type::BytesLiteral(..)
|
||||
| Type::SliceLiteral(..)
|
||||
| Type::FunctionLiteral(..)
|
||||
| Type::BoundMethod(..)
|
||||
| Type::MethodWrapper(..)
|
||||
|
@ -1724,7 +1710,6 @@ impl<'db> Type<'db> {
|
|||
| Type::IntLiteral(..)
|
||||
| Type::StringLiteral(..)
|
||||
| Type::BytesLiteral(..)
|
||||
| Type::SliceLiteral(..)
|
||||
| Type::FunctionLiteral(..)
|
||||
| Type::BoundMethod(..)
|
||||
| Type::MethodWrapper(..)
|
||||
|
@ -1751,7 +1736,6 @@ impl<'db> Type<'db> {
|
|||
| Type::DataclassDecorator(..)
|
||||
| Type::DataclassTransformer(..)
|
||||
| Type::IntLiteral(..)
|
||||
| Type::SliceLiteral(..)
|
||||
| Type::StringLiteral(..)
|
||||
| Type::LiteralString,
|
||||
)
|
||||
|
@ -1768,7 +1752,6 @@ impl<'db> Type<'db> {
|
|||
| Type::DataclassDecorator(..)
|
||||
| Type::DataclassTransformer(..)
|
||||
| Type::IntLiteral(..)
|
||||
| Type::SliceLiteral(..)
|
||||
| Type::StringLiteral(..)
|
||||
| Type::LiteralString,
|
||||
Type::Tuple(..),
|
||||
|
@ -1799,7 +1782,6 @@ impl<'db> Type<'db> {
|
|||
| Type::StringLiteral(..)
|
||||
| Type::LiteralString
|
||||
| Type::BytesLiteral(..)
|
||||
| Type::SliceLiteral(..)
|
||||
| Type::FunctionLiteral(..)
|
||||
| Type::BoundMethod(..)
|
||||
| Type::MethodWrapper(..)
|
||||
|
@ -1812,7 +1794,6 @@ impl<'db> Type<'db> {
|
|||
| Type::StringLiteral(..)
|
||||
| Type::LiteralString
|
||||
| Type::BytesLiteral(..)
|
||||
| Type::SliceLiteral(..)
|
||||
| Type::FunctionLiteral(..)
|
||||
| Type::BoundMethod(..)
|
||||
| Type::MethodWrapper(..)
|
||||
|
@ -1848,7 +1829,6 @@ impl<'db> Type<'db> {
|
|||
| Type::StringLiteral(..)
|
||||
| Type::BytesLiteral(..)
|
||||
| Type::BooleanLiteral(..)
|
||||
| Type::SliceLiteral(..)
|
||||
| Type::ClassLiteral(..)
|
||||
| Type::FunctionLiteral(..)
|
||||
| Type::ModuleLiteral(..)
|
||||
|
@ -1862,7 +1842,6 @@ impl<'db> Type<'db> {
|
|||
| Type::StringLiteral(..)
|
||||
| Type::BytesLiteral(..)
|
||||
| Type::BooleanLiteral(..)
|
||||
| Type::SliceLiteral(..)
|
||||
| Type::ClassLiteral(..)
|
||||
| Type::FunctionLiteral(..)
|
||||
| Type::ModuleLiteral(..)
|
||||
|
@ -1953,13 +1932,6 @@ impl<'db> Type<'db> {
|
|||
!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`,
|
||||
// unless the type expressing "all instances of `Z`" is a subtype of of `Y`,
|
||||
// where `Z` is `X`'s metaclass.
|
||||
|
@ -2005,14 +1977,8 @@ impl<'db> Type<'db> {
|
|||
false
|
||||
}
|
||||
|
||||
(
|
||||
Type::Callable(_),
|
||||
Type::StringLiteral(_) | Type::BytesLiteral(_) | Type::SliceLiteral(_),
|
||||
)
|
||||
| (
|
||||
Type::StringLiteral(_) | Type::BytesLiteral(_) | Type::SliceLiteral(_),
|
||||
Type::Callable(_),
|
||||
) => {
|
||||
(Type::Callable(_), Type::StringLiteral(_) | Type::BytesLiteral(_))
|
||||
| (Type::StringLiteral(_) | Type::BytesLiteral(_), Type::Callable(_)) => {
|
||||
// A callable type is disjoint from other literal types. For example,
|
||||
// `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.
|
||||
|
@ -2092,7 +2058,6 @@ impl<'db> Type<'db> {
|
|||
| Type::StringLiteral(_)
|
||||
| Type::LiteralString
|
||||
| Type::BytesLiteral(_)
|
||||
| Type::SliceLiteral(_)
|
||||
| Type::KnownInstance(_)
|
||||
| Type::AlwaysFalsy
|
||||
| Type::AlwaysTruthy
|
||||
|
@ -2157,7 +2122,6 @@ impl<'db> Type<'db> {
|
|||
| Type::IntLiteral(..)
|
||||
| Type::StringLiteral(..)
|
||||
| Type::BytesLiteral(..)
|
||||
| Type::SliceLiteral(..)
|
||||
| Type::LiteralString => {
|
||||
// Note: The literal types included in this pattern are not true singletons.
|
||||
// There can be multiple Python objects (at different memory locations) that
|
||||
|
@ -2284,7 +2248,6 @@ impl<'db> Type<'db> {
|
|||
| Type::BooleanLiteral(..)
|
||||
| Type::StringLiteral(..)
|
||||
| Type::BytesLiteral(..)
|
||||
| Type::SliceLiteral(..)
|
||||
| Type::KnownInstance(..) => true,
|
||||
|
||||
Type::ProtocolInstance(..) => {
|
||||
|
@ -2481,7 +2444,6 @@ impl<'db> Type<'db> {
|
|||
| Type::StringLiteral(_)
|
||||
| Type::LiteralString
|
||||
| Type::BytesLiteral(_)
|
||||
| Type::SliceLiteral(_)
|
||||
| Type::Tuple(_)
|
||||
| Type::TypeVar(_)
|
||||
| Type::NominalInstance(_)
|
||||
|
@ -2591,7 +2553,6 @@ impl<'db> Type<'db> {
|
|||
KnownClass::Str.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::AlwaysTruthy | Type::AlwaysFalsy => Type::object(db).instance_member(db, name),
|
||||
|
@ -3046,7 +3007,6 @@ impl<'db> Type<'db> {
|
|||
| Type::StringLiteral(..)
|
||||
| Type::BytesLiteral(..)
|
||||
| Type::LiteralString
|
||||
| Type::SliceLiteral(..)
|
||||
| Type::Tuple(..)
|
||||
| Type::TypeVar(..)
|
||||
| Type::KnownInstance(..)
|
||||
|
@ -3303,7 +3263,6 @@ impl<'db> Type<'db> {
|
|||
| Type::DataclassDecorator(_)
|
||||
| Type::DataclassTransformer(_)
|
||||
| Type::ModuleLiteral(_)
|
||||
| Type::SliceLiteral(_)
|
||||
| Type::AlwaysTruthy => Truthiness::AlwaysTrue,
|
||||
|
||||
Type::AlwaysFalsy => Truthiness::AlwaysFalse,
|
||||
|
@ -4210,7 +4169,6 @@ impl<'db> Type<'db> {
|
|||
| Type::BytesLiteral(_)
|
||||
| Type::BooleanLiteral(_)
|
||||
| Type::LiteralString
|
||||
| Type::SliceLiteral(_)
|
||||
| Type::Tuple(_)
|
||||
| Type::BoundSuper(_)
|
||||
| Type::TypeVar(_)
|
||||
|
@ -4660,7 +4618,6 @@ impl<'db> Type<'db> {
|
|||
| Type::ModuleLiteral(_)
|
||||
| Type::IntLiteral(_)
|
||||
| Type::StringLiteral(_)
|
||||
| Type::SliceLiteral(_)
|
||||
| Type::Tuple(_)
|
||||
| Type::TypeVar(_)
|
||||
| Type::LiteralString
|
||||
|
@ -4713,7 +4670,6 @@ impl<'db> Type<'db> {
|
|||
| Type::BytesLiteral(_)
|
||||
| Type::AlwaysTruthy
|
||||
| Type::AlwaysFalsy
|
||||
| Type::SliceLiteral(_)
|
||||
| Type::IntLiteral(_)
|
||||
| Type::LiteralString
|
||||
| Type::ModuleLiteral(_)
|
||||
|
@ -4972,7 +4928,6 @@ impl<'db> Type<'db> {
|
|||
Type::Union(union) => union.map(db, |ty| ty.to_meta_type(db)),
|
||||
Type::BooleanLiteral(_) => KnownClass::Bool.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::FunctionLiteral(_) => KnownClass::FunctionType.to_class_literal(db),
|
||||
Type::BoundMethod(_) => KnownClass::MethodType.to_class_literal(db),
|
||||
|
@ -5151,7 +5106,6 @@ impl<'db> Type<'db> {
|
|||
| Type::LiteralString
|
||||
| Type::StringLiteral(_)
|
||||
| Type::BytesLiteral(_)
|
||||
| Type::SliceLiteral(_)
|
||||
| Type::BoundSuper(_)
|
||||
// Same for `ProtocolInstance`
|
||||
| Type::ProtocolInstance(_)
|
||||
|
@ -5242,7 +5196,6 @@ impl<'db> Type<'db> {
|
|||
| Type::LiteralString
|
||||
| Type::StringLiteral(_)
|
||||
| Type::BytesLiteral(_)
|
||||
| Type::SliceLiteral(_)
|
||||
| Type::BoundSuper(_)
|
||||
| Type::NominalInstance(_)
|
||||
| Type::ProtocolInstance(_)
|
||||
|
@ -5334,7 +5287,6 @@ impl<'db> Type<'db> {
|
|||
| Self::LiteralString
|
||||
| Self::IntLiteral(_)
|
||||
| Self::BytesLiteral(_)
|
||||
| Self::SliceLiteral(_)
|
||||
| Self::MethodWrapper(_)
|
||||
| Self::WrapperDescriptor(_)
|
||||
| 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)]
|
||||
pub struct TupleType<'db> {
|
||||
#[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)]
|
||||
pub(super) struct MetaclassError<'db> {
|
||||
kind: MetaclassErrorKind<'db>,
|
||||
|
|
|
@ -125,7 +125,6 @@ impl<'db> ClassBase<'db> {
|
|||
| Type::StringLiteral(_)
|
||||
| Type::LiteralString
|
||||
| Type::Tuple(_)
|
||||
| Type::SliceLiteral(_)
|
||||
| Type::ModuleLiteral(_)
|
||||
| Type::SubclassOf(_)
|
||||
| Type::TypeVar(_)
|
||||
|
|
|
@ -228,28 +228,6 @@ impl Display for DisplayRepresentation<'_> {
|
|||
|
||||
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) => {
|
||||
f.write_str("tuple[")?;
|
||||
let elements = tuple.elements(self.db);
|
||||
|
@ -752,53 +730,9 @@ mod tests {
|
|||
|
||||
use crate::db::tests::setup_db;
|
||||
use crate::symbol::typing_extensions_symbol;
|
||||
use crate::types::{
|
||||
KnownClass, Parameter, Parameters, Signature, SliceLiteralType, StringLiteralType, Type,
|
||||
};
|
||||
use crate::types::{KnownClass, Parameter, Parameters, Signature, StringLiteralType, Type};
|
||||
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]
|
||||
fn string_literal_display() {
|
||||
let db = setup_db();
|
||||
|
|
|
@ -65,7 +65,7 @@ use crate::symbol::{
|
|||
typing_extensions_symbol, Boundness, LookupError,
|
||||
};
|
||||
use crate::types::call::{Argument, Bindings, CallArgumentTypes, CallArguments, CallError};
|
||||
use crate::types::class::MetaclassErrorKind;
|
||||
use crate::types::class::{MetaclassErrorKind, SliceLiteral};
|
||||
use crate::types::diagnostic::{
|
||||
report_implicit_return_type, report_invalid_arguments_to_annotated,
|
||||
report_invalid_arguments_to_callable, report_invalid_assignment,
|
||||
|
@ -87,10 +87,10 @@ use crate::types::{
|
|||
ClassType, DataclassParams, DynamicType, FunctionDecorators, FunctionType, GenericAlias,
|
||||
IntersectionBuilder, IntersectionType, KnownClass, KnownFunction, KnownInstanceType,
|
||||
MemberLookupPolicy, MetaclassCandidate, Parameter, ParameterForm, Parameters, Signature,
|
||||
Signatures, SliceLiteralType, StringLiteralType, SubclassOfType, Symbol, SymbolAndQualifiers,
|
||||
Truthiness, TupleType, Type, TypeAliasType, TypeAndQualifiers, TypeArrayDisplay,
|
||||
TypeQualifiers, TypeVarBoundOrConstraints, TypeVarInstance, TypeVarKind, TypeVarVariance,
|
||||
UnionBuilder, UnionType,
|
||||
Signatures, StringLiteralType, SubclassOfType, Symbol, SymbolAndQualifiers, Truthiness,
|
||||
TupleType, Type, TypeAliasType, TypeAndQualifiers, TypeArrayDisplay, TypeQualifiers,
|
||||
TypeVarBoundOrConstraints, TypeVarInstance, TypeVarKind, TypeVarVariance, UnionBuilder,
|
||||
UnionType,
|
||||
};
|
||||
use crate::unpack::{Unpack, UnpackPosition};
|
||||
use crate::util::subscript::{PyIndex, PySlice};
|
||||
|
@ -2911,7 +2911,6 @@ impl<'db> TypeInferenceBuilder<'db> {
|
|||
| Type::StringLiteral(..)
|
||||
| Type::BytesLiteral(..)
|
||||
| Type::LiteralString
|
||||
| Type::SliceLiteral(..)
|
||||
| Type::Tuple(..)
|
||||
| Type::KnownInstance(..)
|
||||
| Type::PropertyInstance(..)
|
||||
|
@ -5653,7 +5652,6 @@ impl<'db> TypeInferenceBuilder<'db> {
|
|||
| Type::StringLiteral(_)
|
||||
| Type::LiteralString
|
||||
| Type::BytesLiteral(_)
|
||||
| Type::SliceLiteral(_)
|
||||
| Type::Tuple(_)
|
||||
| Type::BoundSuper(_)
|
||||
| Type::TypeVar(_),
|
||||
|
@ -5952,7 +5950,6 @@ impl<'db> TypeInferenceBuilder<'db> {
|
|||
| Type::StringLiteral(_)
|
||||
| Type::LiteralString
|
||||
| Type::BytesLiteral(_)
|
||||
| Type::SliceLiteral(_)
|
||||
| Type::Tuple(_)
|
||||
| Type::BoundSuper(_)
|
||||
| Type::TypeVar(_),
|
||||
|
@ -5978,7 +5975,6 @@ impl<'db> TypeInferenceBuilder<'db> {
|
|||
| Type::StringLiteral(_)
|
||||
| Type::LiteralString
|
||||
| Type::BytesLiteral(_)
|
||||
| Type::SliceLiteral(_)
|
||||
| Type::Tuple(_)
|
||||
| Type::BoundSuper(_)
|
||||
| Type::TypeVar(_),
|
||||
|
@ -6931,13 +6927,11 @@ impl<'db> TypeInferenceBuilder<'db> {
|
|||
value_ty: Type<'db>,
|
||||
slice_ty: Type<'db>,
|
||||
) -> Type<'db> {
|
||||
match (value_ty, slice_ty) {
|
||||
(
|
||||
Type::NominalInstance(instance),
|
||||
Type::IntLiteral(_) | Type::BooleanLiteral(_) | Type::SliceLiteral(_),
|
||||
) if instance
|
||||
.class()
|
||||
.is_known(self.db(), KnownClass::VersionInfo) =>
|
||||
match (value_ty, slice_ty, slice_ty.slice_literal(self.db())) {
|
||||
(Type::NominalInstance(instance), _, _)
|
||||
if instance
|
||||
.class()
|
||||
.is_known(self.db(), KnownClass::VersionInfo) =>
|
||||
{
|
||||
self.infer_subscript_expression_types(
|
||||
value_node,
|
||||
|
@ -6947,7 +6941,7 @@ impl<'db> TypeInferenceBuilder<'db> {
|
|||
}
|
||||
|
||||
// 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());
|
||||
elements
|
||||
.iter()
|
||||
|
@ -6966,9 +6960,8 @@ impl<'db> TypeInferenceBuilder<'db> {
|
|||
})
|
||||
}
|
||||
// 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 (start, stop, step) = slice_ty.as_tuple(self.db());
|
||||
|
||||
if let Ok(new_elements) = elements.py_slice(start, stop, step) {
|
||||
TupleType::from_elements(self.db(), new_elements)
|
||||
|
@ -6978,7 +6971,7 @@ impl<'db> TypeInferenceBuilder<'db> {
|
|||
}
|
||||
}
|
||||
// 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() =>
|
||||
{
|
||||
let literal_value = literal_ty.value(self.db());
|
||||
|
@ -6999,9 +6992,8 @@ impl<'db> TypeInferenceBuilder<'db> {
|
|||
})
|
||||
}
|
||||
// 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 (start, stop, step) = slice_ty.as_tuple(self.db());
|
||||
|
||||
let chars: Vec<_> = literal_value.chars().collect();
|
||||
let result = if let Ok(new_chars) = chars.py_slice(start, stop, step) {
|
||||
|
@ -7014,7 +7006,7 @@ impl<'db> TypeInferenceBuilder<'db> {
|
|||
result
|
||||
}
|
||||
// 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() =>
|
||||
{
|
||||
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"`
|
||||
(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 (start, stop, step) = slice_ty.as_tuple(self.db());
|
||||
|
||||
if let Ok(new_bytes) = literal_value.py_slice(start, stop, step) {
|
||||
let new_bytes: Vec<u8> = new_bytes.copied().collect();
|
||||
|
@ -7051,29 +7042,30 @@ impl<'db> TypeInferenceBuilder<'db> {
|
|||
(
|
||||
Type::Tuple(_) | Type::StringLiteral(_) | Type::BytesLiteral(_),
|
||||
Type::BooleanLiteral(bool),
|
||||
_,
|
||||
) => self.infer_subscript_expression_types(
|
||||
value_node,
|
||||
value_ty,
|
||||
Type::IntLiteral(i64::from(bool)),
|
||||
),
|
||||
(Type::KnownInstance(KnownInstanceType::Protocol), _) => {
|
||||
(Type::KnownInstance(KnownInstanceType::Protocol), _, _) => {
|
||||
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()))
|
||||
}
|
||||
(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)),
|
||||
(Type::KnownInstance(KnownInstanceType::Generic(Some(_))), _) => {
|
||||
(Type::KnownInstance(KnownInstanceType::Generic(Some(_))), _, _) => {
|
||||
// TODO: emit a diagnostic
|
||||
todo_type!("doubly-specialized typing.Generic")
|
||||
}
|
||||
(Type::KnownInstance(known_instance), _)
|
||||
(Type::KnownInstance(known_instance), _, _)
|
||||
if known_instance.class().is_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.
|
||||
//
|
||||
// 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> {
|
||||
enum SliceArg {
|
||||
Arg(Option<i32>),
|
||||
enum SliceArg<'db> {
|
||||
Arg(Type<'db>),
|
||||
Unsupported,
|
||||
}
|
||||
|
||||
|
@ -7269,17 +7261,13 @@ impl<'db> TypeInferenceBuilder<'db> {
|
|||
let ty_step = self.infer_optional_expression(step.as_deref());
|
||||
|
||||
let type_to_slice_argument = |ty: Option<Type<'db>>| match ty {
|
||||
Some(Type::IntLiteral(n)) => match i32::try_from(n) {
|
||||
Ok(n) => SliceArg::Arg(Some(n)),
|
||||
Err(_) => SliceArg::Unsupported,
|
||||
},
|
||||
Some(Type::BooleanLiteral(b)) => SliceArg::Arg(Some(i32::from(b))),
|
||||
Some(Type::NominalInstance(instance))
|
||||
Some(ty @ (Type::IntLiteral(_) | Type::BooleanLiteral(_))) => SliceArg::Arg(ty),
|
||||
Some(ty @ Type::NominalInstance(instance))
|
||||
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,
|
||||
};
|
||||
|
||||
|
@ -7289,7 +7277,7 @@ impl<'db> TypeInferenceBuilder<'db> {
|
|||
type_to_slice_argument(ty_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()),
|
||||
}
|
||||
|
|
|
@ -64,10 +64,6 @@ pub(super) fn union_or_intersection_elements_ordering<'db>(
|
|||
(Type::BytesLiteral(_), _) => Ordering::Less,
|
||||
(_, 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(_), _) => Ordering::Less,
|
||||
(_, Type::FunctionLiteral(_)) => Ordering::Greater,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue