Skip to content

Commit cf8ea56

Browse files
committed
cow the tuplespec
1 parent cfb020d commit cf8ea56

File tree

3 files changed

+28
-22
lines changed

3 files changed

+28
-22
lines changed

crates/ty_python_semantic/src/types.rs

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ use infer::nearest_enclosing_class;
22
use itertools::{Either, Itertools};
33
use ruff_db::parsed::parsed_module;
44

5+
use std::borrow::Cow;
56
use std::slice::Iter;
67

78
use bitflags::bitflags;
@@ -4614,9 +4615,9 @@ impl<'db> Type<'db> {
46144615
///
46154616
/// This method should only be used outside of type checking because it omits any errors.
46164617
/// For type checking, use [`try_iterate`](Self::try_iterate) instead.
4617-
fn iterate(self, db: &'db dyn Db) -> TupleSpec<'db> {
4618+
fn iterate(self, db: &'db dyn Db) -> Cow<'db, TupleSpec<'db>> {
46184619
self.try_iterate(db)
4619-
.unwrap_or_else(|err| TupleSpec::homogeneous(err.fallback_element_type(db)))
4620+
.unwrap_or_else(|err| Cow::Owned(TupleSpec::homogeneous(err.fallback_element_type(db))))
46204621
}
46214622

46224623
/// Given the type of an object that is iterated over in some way,
@@ -4628,24 +4629,27 @@ impl<'db> Type<'db> {
46284629
/// ```python
46294630
/// y(*x)
46304631
/// ```
4631-
fn try_iterate(self, db: &'db dyn Db) -> Result<TupleSpec<'db>, IterationError<'db>> {
4632+
fn try_iterate(self, db: &'db dyn Db) -> Result<Cow<'db, TupleSpec<'db>>, IterationError<'db>> {
46324633
match self {
4633-
// XXX: Cow?
4634-
Type::Tuple(tuple_type) => return Ok(tuple_type.tuple(db).clone()),
4634+
Type::Tuple(tuple_type) => return Ok(Cow::Borrowed(tuple_type.tuple(db))),
46354635
Type::GenericAlias(alias) if alias.origin(db).is_known(db, KnownClass::Tuple) => {
4636-
return Ok(TupleSpec::homogeneous(todo_type!("*tuple[] annotations")));
4636+
return Ok(Cow::Owned(TupleSpec::homogeneous(todo_type!(
4637+
"*tuple[] annotations"
4638+
))));
46374639
}
46384640
Type::StringLiteral(string_literal_ty) => {
46394641
// We could go further and deconstruct to an array of `StringLiteral`
46404642
// with each individual character, instead of just an array of
46414643
// `LiteralString`, but there would be a cost and it's not clear that
46424644
// it's worth it.
4643-
return Ok(TupleSpec::from_elements(std::iter::repeat_n(
4645+
return Ok(Cow::Owned(TupleSpec::from_elements(std::iter::repeat_n(
46444646
Type::LiteralString,
46454647
string_literal_ty.python_len(db),
4646-
)));
4648+
))));
4649+
}
4650+
Type::LiteralString => {
4651+
return Ok(Cow::Owned(TupleSpec::homogeneous(Type::LiteralString)));
46474652
}
4648-
Type::LiteralString => return Ok(TupleSpec::homogeneous(Type::LiteralString)),
46494653
_ => {}
46504654
}
46514655

@@ -4673,7 +4677,7 @@ impl<'db> Type<'db> {
46734677
// `__iter__` is definitely bound and calling it succeeds.
46744678
// See what calling `__next__` on the object returned by `__iter__` gives us...
46754679
try_call_dunder_next_on_iterator(iterator)
4676-
.map(TupleSpec::homogeneous)
4680+
.map(|ty| Cow::Owned(TupleSpec::homogeneous(ty)))
46774681
.map_err(
46784682
|dunder_next_error| IterationError::IterReturnsInvalidIterator {
46794683
iterator,
@@ -4697,10 +4701,10 @@ impl<'db> Type<'db> {
46974701
// and the type returned by the `__getitem__` method.
46984702
//
46994703
// No diagnostic is emitted; iteration will always succeed!
4700-
TupleSpec::homogeneous(UnionType::from_elements(
4704+
Cow::Owned(TupleSpec::homogeneous(UnionType::from_elements(
47014705
db,
47024706
[dunder_next_return, dunder_getitem_return_type],
4703-
))
4707+
)))
47044708
})
47054709
.map_err(|dunder_getitem_error| {
47064710
IterationError::PossiblyUnboundIterAndGetitemError {
@@ -4724,7 +4728,7 @@ impl<'db> Type<'db> {
47244728

47254729
// There's no `__iter__` method. Try `__getitem__` instead...
47264730
Err(CallDunderError::MethodNotAvailable) => try_call_dunder_getitem()
4727-
.map(TupleSpec::homogeneous)
4731+
.map(|ty| Cow::Owned(TupleSpec::homogeneous(ty)))
47284732
.map_err(
47294733
|dunder_getitem_error| IterationError::UnboundIterAndGetitemError {
47304734
dunder_getitem_error,

crates/ty_python_semantic/src/types/call/bind.rs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ use crate::types::function::{
2424
};
2525
use crate::types::generics::{Specialization, SpecializationBuilder, SpecializationError};
2626
use crate::types::signatures::{Parameter, ParameterForm, Parameters};
27-
use crate::types::tuple::{TupleSpec, TupleType};
27+
use crate::types::tuple::TupleType;
2828
use crate::types::{
2929
BoundMethodType, ClassLiteral, DataclassParams, KnownClass, KnownInstanceType,
3030
MethodWrapperKind, PropertyInstanceType, SpecialFormType, TypeMapping, UnionType,
@@ -969,15 +969,15 @@ impl<'db> Bindings<'db> {
969969
// but `tuple[Never, ...]` eagerly simplifies to `tuple[()]`,
970970
// which will cause us to emit false positives if we index into the tuple.
971971
// Using `tuple[Unknown, ...]` avoids these false positives.
972-
let tuple_spec = if argument.is_never() {
973-
TupleSpec::homogeneous(Type::unknown())
972+
if argument.is_never() {
973+
TupleType::homogeneous(db, Type::unknown())
974974
} else {
975-
argument.try_iterate(db).expect(
975+
let tuple_spec = argument.try_iterate(db).expect(
976976
"try_iterate() should not fail on a type \
977977
assignable to `Iterable`",
978-
)
979-
};
980-
Type::tuple(TupleType::new(db, tuple_spec))
978+
);
979+
Type::tuple(TupleType::new(db, tuple_spec.as_ref()))
980+
}
981981
});
982982
overload.set_return_type(overridden_return);
983983
}

crates/ty_python_semantic/src/types/unpacker.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
use std::borrow::Cow;
2+
13
use ruff_db::parsed::ParsedModuleRef;
24
use rustc_hash::FxHashMap;
35

@@ -121,10 +123,10 @@ impl<'db, 'ast> Unpacker<'db, 'ast> {
121123
for ty in unpack_types.iter().copied() {
122124
let tuple = ty.try_iterate(self.db()).unwrap_or_else(|err| {
123125
err.report_diagnostic(&self.context, ty, value_expr);
124-
TupleSpec::homogeneous(err.fallback_element_type(self.db()))
126+
Cow::Owned(TupleSpec::homogeneous(err.fallback_element_type(self.db())))
125127
});
126128

127-
if let Err(err) = unpacker.unpack_tuple(&tuple) {
129+
if let Err(err) = unpacker.unpack_tuple(tuple.as_ref()) {
128130
unpacker
129131
.unpack_tuple(&Tuple::homogeneous(Type::unknown()))
130132
.expect("adding a homogeneous tuple should always succeed");

0 commit comments

Comments
 (0)