mirror of
https://github.com/astral-sh/ruff.git
synced 2025-09-29 13:25:17 +00:00
Remove Type::tuple
in favor of TupleType::from_elements
(#15218)
## Summary Remove `Type::tuple` in favor of `TupleType::from_elements`, avoid a few intermediate `Vec`tors. Resolves an old [review comment](https://github.com/astral-sh/ruff/pull/14744#discussion_r1867493706). ## Test Plan New regression test for something I ran into while implementing this.
This commit is contained in:
parent
11e873eb45
commit
7671a3bbc7
4 changed files with 39 additions and 27 deletions
|
@ -705,13 +705,6 @@ impl<'db> Type<'db> {
|
||||||
Self::BytesLiteral(BytesLiteralType::new(db, bytes))
|
Self::BytesLiteral(BytesLiteralType::new(db, bytes))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn tuple<T: Into<Type<'db>>>(
|
|
||||||
db: &'db dyn Db,
|
|
||||||
elements: impl IntoIterator<Item = T>,
|
|
||||||
) -> Self {
|
|
||||||
TupleType::from_elements(db, elements)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn negate(&self, db: &'db dyn Db) -> Type<'db> {
|
pub fn negate(&self, db: &'db dyn Db) -> Type<'db> {
|
||||||
IntersectionBuilder::new(db).add_negative(*self).build()
|
IntersectionBuilder::new(db).add_negative(*self).build()
|
||||||
|
@ -2118,15 +2111,16 @@ impl<'db> Type<'db> {
|
||||||
Type::Union(UnionType::new(db, elements))
|
Type::Union(UnionType::new(db, elements))
|
||||||
};
|
};
|
||||||
|
|
||||||
let version_info_elements = &[
|
TupleType::from_elements(
|
||||||
Type::IntLiteral(python_version.major.into()),
|
db,
|
||||||
Type::IntLiteral(python_version.minor.into()),
|
[
|
||||||
int_instance_ty,
|
Type::IntLiteral(python_version.major.into()),
|
||||||
release_level_ty,
|
Type::IntLiteral(python_version.minor.into()),
|
||||||
int_instance_ty,
|
int_instance_ty,
|
||||||
];
|
release_level_ty,
|
||||||
|
int_instance_ty,
|
||||||
Self::tuple(db, version_info_elements)
|
],
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Given a type that is assumed to represent an instance of a class,
|
/// Given a type that is assumed to represent an instance of a class,
|
||||||
|
@ -3435,8 +3429,8 @@ impl<'db> Class<'db> {
|
||||||
/// The member resolves to a member on the class itself or any of its proper superclasses.
|
/// The member resolves to a member on the class itself or any of its proper superclasses.
|
||||||
pub(crate) fn class_member(self, db: &'db dyn Db, name: &str) -> Symbol<'db> {
|
pub(crate) fn class_member(self, db: &'db dyn Db, name: &str) -> Symbol<'db> {
|
||||||
if name == "__mro__" {
|
if name == "__mro__" {
|
||||||
let tuple_elements: Vec<Type<'db>> = self.iter_mro(db).map(Type::from).collect();
|
let tuple_elements = self.iter_mro(db).map(Type::from);
|
||||||
return Type::tuple(db, &tuple_elements).into();
|
return TupleType::from_elements(db, tuple_elements).into();
|
||||||
}
|
}
|
||||||
|
|
||||||
for superclass in self.iter_mro(db) {
|
for superclass in self.iter_mro(db) {
|
||||||
|
@ -3846,7 +3840,7 @@ pub(crate) mod tests {
|
||||||
}
|
}
|
||||||
Ty::Tuple(tys) => {
|
Ty::Tuple(tys) => {
|
||||||
let elements = tys.into_iter().map(|ty| ty.into_type(db));
|
let elements = tys.into_iter().map(|ty| ty.into_type(db));
|
||||||
Type::tuple(db, elements)
|
TupleType::from_elements(db, elements)
|
||||||
}
|
}
|
||||||
Ty::SubclassOfAny => Type::subclass_of_base(ClassBase::Any),
|
Ty::SubclassOfAny => Type::subclass_of_base(ClassBase::Any),
|
||||||
Ty::SubclassOfUnknown => Type::subclass_of_base(ClassBase::Unknown),
|
Ty::SubclassOfUnknown => Type::subclass_of_base(ClassBase::Unknown),
|
||||||
|
|
|
@ -2672,10 +2672,12 @@ impl<'db> TypeInferenceBuilder<'db> {
|
||||||
parenthesized: _,
|
parenthesized: _,
|
||||||
} = tuple;
|
} = tuple;
|
||||||
|
|
||||||
let element_types: Vec<Type<'db>> =
|
// Collecting all elements is necessary to infer all sub-expressions even if some
|
||||||
elts.iter().map(|elt| self.infer_expression(elt)).collect();
|
// element types are `Never` (which leads `from_elements` to return early without
|
||||||
|
// consuming the whole iterator).
|
||||||
|
let element_types: Vec<_> = elts.iter().map(|elt| self.infer_expression(elt)).collect();
|
||||||
|
|
||||||
Type::tuple(self.db(), &element_types)
|
TupleType::from_elements(self.db(), element_types)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn infer_list_expression(&mut self, list: &ast::ExprList) -> Type<'db> {
|
fn infer_list_expression(&mut self, list: &ast::ExprList) -> Type<'db> {
|
||||||
|
@ -4239,8 +4241,7 @@ impl<'db> TypeInferenceBuilder<'db> {
|
||||||
let (start, stop, step) = slice_ty.as_tuple(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) {
|
||||||
let new_elements: Vec<_> = new_elements.copied().collect();
|
TupleType::from_elements(self.db(), new_elements)
|
||||||
Type::tuple(self.db(), &new_elements)
|
|
||||||
} else {
|
} else {
|
||||||
report_slice_step_size_zero(&self.context, value_node.into());
|
report_slice_step_size_zero(&self.context, value_node.into());
|
||||||
Type::Unknown
|
Type::Unknown
|
||||||
|
@ -4842,7 +4843,7 @@ impl<'db> TypeInferenceBuilder<'db> {
|
||||||
let ty = if return_todo {
|
let ty = if return_todo {
|
||||||
todo_type!("full tuple[...] support")
|
todo_type!("full tuple[...] support")
|
||||||
} else {
|
} else {
|
||||||
Type::tuple(self.db(), &element_types)
|
TupleType::from_elements(self.db(), element_types)
|
||||||
};
|
};
|
||||||
|
|
||||||
// Here, we store the type for the inner `int, str` tuple-expression,
|
// Here, we store the type for the inner `int, str` tuple-expression,
|
||||||
|
@ -4857,7 +4858,7 @@ impl<'db> TypeInferenceBuilder<'db> {
|
||||||
if element_could_alter_type_of_whole_tuple(single_element, single_element_ty) {
|
if element_could_alter_type_of_whole_tuple(single_element, single_element_ty) {
|
||||||
todo_type!("full tuple[...] support")
|
todo_type!("full tuple[...] support")
|
||||||
} else {
|
} else {
|
||||||
Type::tuple(self.db(), [single_element_ty])
|
TupleType::from_elements(self.db(), std::iter::once(single_element_ty))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -96,7 +96,7 @@ impl<'db> Unpacker<'db> {
|
||||||
// with each individual character, instead of just an array of
|
// with each individual character, instead of just an array of
|
||||||
// `LiteralString`, but there would be a cost and it's not clear that
|
// `LiteralString`, but there would be a cost and it's not clear that
|
||||||
// it's worth it.
|
// it's worth it.
|
||||||
Type::tuple(
|
TupleType::from_elements(
|
||||||
self.db(),
|
self.db(),
|
||||||
std::iter::repeat(Type::LiteralString)
|
std::iter::repeat(Type::LiteralString)
|
||||||
.take(string_literal_ty.python_len(self.db())),
|
.take(string_literal_ty.python_len(self.db())),
|
||||||
|
|
|
@ -0,0 +1,17 @@
|
||||||
|
"""
|
||||||
|
Regression test that makes sure we do not short-circuit here after
|
||||||
|
determining that the overall type will be `Never` and still infer
|
||||||
|
a type for the second tuple element `2`.
|
||||||
|
|
||||||
|
Relevant discussion:
|
||||||
|
https://github.com/astral-sh/ruff/pull/15218#discussion_r1900811073
|
||||||
|
"""
|
||||||
|
|
||||||
|
from typing_extensions import Never
|
||||||
|
|
||||||
|
|
||||||
|
def never() -> Never:
|
||||||
|
return never()
|
||||||
|
|
||||||
|
|
||||||
|
(never(), 2)
|
Loading…
Add table
Add a link
Reference in a new issue