mirror of
https://github.com/astral-sh/ruff.git
synced 2025-09-29 21:34:57 +00:00
[ty] Reduce memory usage of TupleSpec
and TupleType
(#19872)
This commit is contained in:
parent
f34b65b7a0
commit
498a04804d
2 changed files with 136 additions and 79 deletions
|
@ -114,7 +114,7 @@ use crate::types::generics::{GenericContext, bind_typevar};
|
||||||
use crate::types::instance::SliceLiteral;
|
use crate::types::instance::SliceLiteral;
|
||||||
use crate::types::mro::MroErrorKind;
|
use crate::types::mro::MroErrorKind;
|
||||||
use crate::types::signatures::{CallableSignature, Signature};
|
use crate::types::signatures::{CallableSignature, Signature};
|
||||||
use crate::types::tuple::{Tuple, TupleSpec, TupleType};
|
use crate::types::tuple::{Tuple, TupleSpec, TupleSpecBuilder, TupleType};
|
||||||
use crate::types::unpacker::{UnpackResult, Unpacker};
|
use crate::types::unpacker::{UnpackResult, Unpacker};
|
||||||
use crate::types::{
|
use crate::types::{
|
||||||
CallDunderError, CallableType, ClassLiteral, ClassType, DataclassParams, DynamicType,
|
CallDunderError, CallableType, ClassLiteral, ClassType, DataclassParams, DynamicType,
|
||||||
|
@ -10042,7 +10042,7 @@ impl<'db> TypeInferenceBuilder<'db, '_> {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut element_types = TupleSpec::with_capacity(elements.len());
|
let mut element_types = TupleSpecBuilder::with_capacity(elements.len());
|
||||||
|
|
||||||
// Whether to infer `Todo` for the whole tuple
|
// Whether to infer `Todo` for the whole tuple
|
||||||
// (see docstring for `element_could_alter_type_of_whole_tuple`)
|
// (see docstring for `element_could_alter_type_of_whole_tuple`)
|
||||||
|
@ -10067,7 +10067,7 @@ impl<'db> TypeInferenceBuilder<'db, '_> {
|
||||||
let ty = if return_todo {
|
let ty = if return_todo {
|
||||||
TupleType::homogeneous(self.db(), todo_type!("PEP 646"))
|
TupleType::homogeneous(self.db(), todo_type!("PEP 646"))
|
||||||
} else {
|
} else {
|
||||||
TupleType::new(self.db(), element_types)
|
TupleType::new(self.db(), element_types.build())
|
||||||
};
|
};
|
||||||
|
|
||||||
// Here, we store the type for the inner `int, str` tuple-expression,
|
// Here, we store the type for the inner `int, str` tuple-expression,
|
||||||
|
|
|
@ -303,15 +303,11 @@ pub(crate) type TupleSpec<'db> = Tuple<Type<'db>>;
|
||||||
/// Our tuple representation can hold instances of any Rust type. For tuples containing Python
|
/// Our tuple representation can hold instances of any Rust type. For tuples containing Python
|
||||||
/// types, use [`TupleSpec`], which defines some additional type-specific methods.
|
/// types, use [`TupleSpec`], which defines some additional type-specific methods.
|
||||||
#[derive(Clone, Debug, Eq, Hash, PartialEq, get_size2::GetSize)]
|
#[derive(Clone, Debug, Eq, Hash, PartialEq, get_size2::GetSize)]
|
||||||
pub struct FixedLengthTuple<T>(Vec<T>);
|
pub struct FixedLengthTuple<T>(Box<[T]>);
|
||||||
|
|
||||||
impl<T> FixedLengthTuple<T> {
|
impl<T> FixedLengthTuple<T> {
|
||||||
fn empty() -> Self {
|
fn empty() -> Self {
|
||||||
Self(Vec::new())
|
Self(Box::default())
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn with_capacity(capacity: usize) -> Self {
|
|
||||||
Self(Vec::with_capacity(capacity))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn from_elements(elements: impl IntoIterator<Item = T>) -> Self {
|
fn from_elements(elements: impl IntoIterator<Item = T>) -> Self {
|
||||||
|
@ -338,27 +334,9 @@ impl<T> FixedLengthTuple<T> {
|
||||||
pub(crate) fn len(&self) -> usize {
|
pub(crate) fn len(&self) -> usize {
|
||||||
self.0.len()
|
self.0.len()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn push(&mut self, element: T) {
|
|
||||||
self.0.push(element);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'db> FixedLengthTuple<Type<'db>> {
|
impl<'db> FixedLengthTuple<Type<'db>> {
|
||||||
fn concat(&self, other: &Tuple<Type<'db>>) -> Tuple<Type<'db>> {
|
|
||||||
match other {
|
|
||||||
TupleSpec::Fixed(other) => TupleSpec::Fixed(FixedLengthTuple::from_elements(
|
|
||||||
self.elements().chain(other.elements()).copied(),
|
|
||||||
)),
|
|
||||||
|
|
||||||
TupleSpec::Variable(other) => VariableLengthTuple::mixed(
|
|
||||||
self.elements().chain(other.prefix_elements()).copied(),
|
|
||||||
other.variable,
|
|
||||||
other.suffix_elements().copied(),
|
|
||||||
),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn resize(
|
fn resize(
|
||||||
&self,
|
&self,
|
||||||
db: &'db dyn Db,
|
db: &'db dyn Db,
|
||||||
|
@ -482,7 +460,7 @@ where
|
||||||
unsafe fn maybe_update(old_pointer: *mut Self, new_value: Self) -> bool {
|
unsafe fn maybe_update(old_pointer: *mut Self, new_value: Self) -> bool {
|
||||||
unsafe {
|
unsafe {
|
||||||
let old_value = &mut *old_pointer;
|
let old_value = &mut *old_pointer;
|
||||||
Vec::maybe_update(&raw mut old_value.0, new_value.0)
|
Box::maybe_update(&raw mut old_value.0, new_value.0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -491,7 +469,7 @@ impl<'db> PyIndex<'db> for &FixedLengthTuple<Type<'db>> {
|
||||||
type Item = Type<'db>;
|
type Item = Type<'db>;
|
||||||
|
|
||||||
fn py_index(self, db: &'db dyn Db, index: i32) -> Result<Self::Item, OutOfBoundsError> {
|
fn py_index(self, db: &'db dyn Db, index: i32) -> Result<Self::Item, OutOfBoundsError> {
|
||||||
self.0.as_slice().py_index(db, index).copied()
|
self.0.py_index(db, index).copied()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -518,9 +496,9 @@ impl<'db> PySlice<'db> for FixedLengthTuple<Type<'db>> {
|
||||||
/// types, use [`TupleSpec`], which defines some additional type-specific methods.
|
/// types, use [`TupleSpec`], which defines some additional type-specific methods.
|
||||||
#[derive(Clone, Debug, Eq, Hash, PartialEq, get_size2::GetSize)]
|
#[derive(Clone, Debug, Eq, Hash, PartialEq, get_size2::GetSize)]
|
||||||
pub struct VariableLengthTuple<T> {
|
pub struct VariableLengthTuple<T> {
|
||||||
pub(crate) prefix: Vec<T>,
|
pub(crate) prefix: Box<[T]>,
|
||||||
pub(crate) variable: T,
|
pub(crate) variable: T,
|
||||||
pub(crate) suffix: Vec<T>,
|
pub(crate) suffix: Box<[T]>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> VariableLengthTuple<T> {
|
impl<T> VariableLengthTuple<T> {
|
||||||
|
@ -569,10 +547,6 @@ impl<T> VariableLengthTuple<T> {
|
||||||
fn len(&self) -> TupleLength {
|
fn len(&self) -> TupleLength {
|
||||||
TupleLength::Variable(self.prefix.len(), self.suffix.len())
|
TupleLength::Variable(self.prefix.len(), self.suffix.len())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn push(&mut self, element: T) {
|
|
||||||
self.suffix.push(element);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'db> VariableLengthTuple<Type<'db>> {
|
impl<'db> VariableLengthTuple<Type<'db>> {
|
||||||
|
@ -639,30 +613,6 @@ impl<'db> VariableLengthTuple<Type<'db>> {
|
||||||
.copied()
|
.copied()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn concat(&self, db: &'db dyn Db, other: &Tuple<Type<'db>>) -> Tuple<Type<'db>> {
|
|
||||||
match other {
|
|
||||||
TupleSpec::Fixed(other) => VariableLengthTuple::mixed(
|
|
||||||
self.prefix_elements().copied(),
|
|
||||||
self.variable,
|
|
||||||
self.suffix_elements().chain(other.elements()).copied(),
|
|
||||||
),
|
|
||||||
|
|
||||||
Tuple::Variable(other) => {
|
|
||||||
let variable = UnionType::from_elements(
|
|
||||||
db,
|
|
||||||
(self.suffix_elements().copied())
|
|
||||||
.chain([self.variable, other.variable])
|
|
||||||
.chain(other.prefix_elements().copied()),
|
|
||||||
);
|
|
||||||
VariableLengthTuple::mixed(
|
|
||||||
self.prefix_elements().copied(),
|
|
||||||
variable,
|
|
||||||
other.suffix_elements().copied(),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn resize(
|
fn resize(
|
||||||
&self,
|
&self,
|
||||||
db: &'db dyn Db,
|
db: &'db dyn Db,
|
||||||
|
@ -711,13 +661,17 @@ impl<'db> VariableLengthTuple<Type<'db>> {
|
||||||
let prefix = self
|
let prefix = self
|
||||||
.prenormalized_prefix_elements(db, None)
|
.prenormalized_prefix_elements(db, None)
|
||||||
.map(|ty| ty.normalized_impl(db, visitor))
|
.map(|ty| ty.normalized_impl(db, visitor))
|
||||||
.collect::<Vec<_>>();
|
.collect::<Box<_>>();
|
||||||
let suffix = self
|
let suffix = self
|
||||||
.prenormalized_suffix_elements(db, None)
|
.prenormalized_suffix_elements(db, None)
|
||||||
.map(|ty| ty.normalized_impl(db, visitor))
|
.map(|ty| ty.normalized_impl(db, visitor))
|
||||||
.collect::<Vec<_>>();
|
.collect::<Box<_>>();
|
||||||
let variable = self.variable.normalized_impl(db, visitor);
|
let variable = self.variable.normalized_impl(db, visitor);
|
||||||
Self::mixed(prefix, variable, suffix)
|
TupleSpec::Variable(Self {
|
||||||
|
prefix,
|
||||||
|
variable,
|
||||||
|
suffix,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn materialize(&self, db: &'db dyn Db, variance: TypeVarVariance) -> TupleSpec<'db> {
|
fn materialize(&self, db: &'db dyn Db, variance: TypeVarVariance) -> TupleSpec<'db> {
|
||||||
|
@ -901,9 +855,9 @@ where
|
||||||
unsafe fn maybe_update(old_pointer: *mut Self, new_value: Self) -> bool {
|
unsafe fn maybe_update(old_pointer: *mut Self, new_value: Self) -> bool {
|
||||||
let old_value = unsafe { &mut *old_pointer };
|
let old_value = unsafe { &mut *old_pointer };
|
||||||
let mut changed = false;
|
let mut changed = false;
|
||||||
changed |= unsafe { Vec::maybe_update(&raw mut old_value.prefix, new_value.prefix) };
|
changed |= unsafe { Box::maybe_update(&raw mut old_value.prefix, new_value.prefix) };
|
||||||
changed |= unsafe { T::maybe_update(&raw mut old_value.variable, new_value.variable) };
|
changed |= unsafe { T::maybe_update(&raw mut old_value.variable, new_value.variable) };
|
||||||
changed |= unsafe { Vec::maybe_update(&raw mut old_value.suffix, new_value.suffix) };
|
changed |= unsafe { Box::maybe_update(&raw mut old_value.suffix, new_value.suffix) };
|
||||||
changed
|
changed
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -971,10 +925,6 @@ impl<T> Tuple<T> {
|
||||||
FixedLengthTuple::from_elements(elements).into()
|
FixedLengthTuple::from_elements(elements).into()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn with_capacity(capacity: usize) -> Self {
|
|
||||||
Tuple::Fixed(FixedLengthTuple::with_capacity(capacity))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns an iterator of all of the fixed-length element types of this tuple.
|
/// Returns an iterator of all of the fixed-length element types of this tuple.
|
||||||
pub(crate) fn fixed_elements(&self) -> impl Iterator<Item = &T> + '_ {
|
pub(crate) fn fixed_elements(&self) -> impl Iterator<Item = &T> + '_ {
|
||||||
match self {
|
match self {
|
||||||
|
@ -1017,13 +967,6 @@ impl<T> Tuple<T> {
|
||||||
_ => Truthiness::Ambiguous,
|
_ => Truthiness::Ambiguous,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn push(&mut self, element: T) {
|
|
||||||
match self {
|
|
||||||
Tuple::Fixed(tuple) => tuple.push(element),
|
|
||||||
Tuple::Variable(tuple) => tuple.push(element),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'db> Tuple<Type<'db>> {
|
impl<'db> Tuple<Type<'db>> {
|
||||||
|
@ -1033,10 +976,7 @@ impl<'db> Tuple<Type<'db>> {
|
||||||
|
|
||||||
/// Concatenates another tuple to the end of this tuple, returning a new tuple.
|
/// Concatenates another tuple to the end of this tuple, returning a new tuple.
|
||||||
pub(crate) fn concat(&self, db: &'db dyn Db, other: &Self) -> Self {
|
pub(crate) fn concat(&self, db: &'db dyn Db, other: &Self) -> Self {
|
||||||
match self {
|
TupleSpecBuilder::from(self).concat(db, other).build()
|
||||||
Tuple::Fixed(tuple) => tuple.concat(other),
|
|
||||||
Tuple::Variable(tuple) => tuple.concat(db, other),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Resizes this tuple to a different length, if possible. If this tuple cannot satisfy the
|
/// Resizes this tuple to a different length, if possible. If this tuple cannot satisfy the
|
||||||
|
@ -1349,3 +1289,120 @@ pub(crate) enum ResizeTupleError {
|
||||||
TooFewValues,
|
TooFewValues,
|
||||||
TooManyValues,
|
TooManyValues,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A builder for creating a new [`TupleSpec`]
|
||||||
|
pub(crate) enum TupleSpecBuilder<'db> {
|
||||||
|
Fixed(Vec<Type<'db>>),
|
||||||
|
Variable {
|
||||||
|
prefix: Vec<Type<'db>>,
|
||||||
|
variable: Type<'db>,
|
||||||
|
suffix: Vec<Type<'db>>,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'db> TupleSpecBuilder<'db> {
|
||||||
|
pub(crate) fn with_capacity(capacity: usize) -> Self {
|
||||||
|
TupleSpecBuilder::Fixed(Vec::with_capacity(capacity))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn push(&mut self, element: Type<'db>) {
|
||||||
|
match self {
|
||||||
|
TupleSpecBuilder::Fixed(elements) => elements.push(element),
|
||||||
|
TupleSpecBuilder::Variable { suffix, .. } => suffix.push(element),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Concatenates another tuple to the end of this tuple, returning a new tuple.
|
||||||
|
pub(crate) fn concat(mut self, db: &'db dyn Db, other: &TupleSpec<'db>) -> Self {
|
||||||
|
match (&mut self, other) {
|
||||||
|
(TupleSpecBuilder::Fixed(left_tuple), TupleSpec::Fixed(right_tuple)) => {
|
||||||
|
left_tuple.extend_from_slice(&right_tuple.0);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
(
|
||||||
|
TupleSpecBuilder::Fixed(left_tuple),
|
||||||
|
TupleSpec::Variable(VariableLengthTuple {
|
||||||
|
prefix,
|
||||||
|
variable,
|
||||||
|
suffix,
|
||||||
|
}),
|
||||||
|
) => {
|
||||||
|
left_tuple.extend_from_slice(prefix);
|
||||||
|
TupleSpecBuilder::Variable {
|
||||||
|
prefix: std::mem::take(left_tuple),
|
||||||
|
variable: *variable,
|
||||||
|
suffix: suffix.to_vec(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
(
|
||||||
|
TupleSpecBuilder::Variable {
|
||||||
|
prefix: _,
|
||||||
|
variable: _,
|
||||||
|
suffix,
|
||||||
|
},
|
||||||
|
TupleSpec::Fixed(right),
|
||||||
|
) => {
|
||||||
|
suffix.extend_from_slice(&right.0);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
(
|
||||||
|
TupleSpecBuilder::Variable {
|
||||||
|
prefix: left_prefix,
|
||||||
|
variable: left_variable,
|
||||||
|
suffix: left_suffix,
|
||||||
|
},
|
||||||
|
TupleSpec::Variable(VariableLengthTuple {
|
||||||
|
prefix: right_prefix,
|
||||||
|
variable: right_variable,
|
||||||
|
suffix: right_suffix,
|
||||||
|
}),
|
||||||
|
) => {
|
||||||
|
let variable = UnionType::from_elements(
|
||||||
|
db,
|
||||||
|
left_suffix
|
||||||
|
.iter()
|
||||||
|
.chain([left_variable, right_variable])
|
||||||
|
.chain(right_prefix),
|
||||||
|
);
|
||||||
|
TupleSpecBuilder::Variable {
|
||||||
|
prefix: std::mem::take(left_prefix),
|
||||||
|
variable,
|
||||||
|
suffix: right_suffix.to_vec(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) fn build(self) -> TupleSpec<'db> {
|
||||||
|
match self {
|
||||||
|
TupleSpecBuilder::Fixed(elements) => {
|
||||||
|
TupleSpec::Fixed(FixedLengthTuple(elements.into_boxed_slice()))
|
||||||
|
}
|
||||||
|
TupleSpecBuilder::Variable {
|
||||||
|
prefix,
|
||||||
|
variable,
|
||||||
|
suffix,
|
||||||
|
} => TupleSpec::Variable(VariableLengthTuple {
|
||||||
|
prefix: prefix.into_boxed_slice(),
|
||||||
|
variable,
|
||||||
|
suffix: suffix.into_boxed_slice(),
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'db> From<&TupleSpec<'db>> for TupleSpecBuilder<'db> {
|
||||||
|
fn from(tuple: &TupleSpec<'db>) -> Self {
|
||||||
|
match tuple {
|
||||||
|
TupleSpec::Fixed(fixed) => TupleSpecBuilder::Fixed(fixed.0.to_vec()),
|
||||||
|
TupleSpec::Variable(variable) => TupleSpecBuilder::Variable {
|
||||||
|
prefix: variable.prefix.to_vec(),
|
||||||
|
variable: variable.variable,
|
||||||
|
suffix: variable.suffix.to_vec(),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue