Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -52,13 +52,11 @@ reveal_type(b) # revealed: tuple[int]
reveal_type(c) # revealed: tuple[str, int]
reveal_type(d) # revealed: tuple[tuple[str, str], tuple[int, int]]

# TODO: homogeneous tuples, PEP-646 tuples
# TODO: homogeneous tuples, PEP-646 tuples, generics
reveal_type(e) # revealed: @Todo(full tuple[...] support)
reveal_type(f) # revealed: @Todo(full tuple[...] support)
reveal_type(g) # revealed: @Todo(full tuple[...] support)

# TODO: support more kinds of type expressions in annotations
reveal_type(h) # revealed: @Todo(full tuple[...] support)
reveal_type(h) # revealed: tuple[@Todo(generics), @Todo(generics)]

reveal_type(i) # revealed: tuple[str | int, str | int]
reveal_type(j) # revealed: tuple[str | int]
Expand Down
33 changes: 23 additions & 10 deletions crates/red_knot_python_semantic/src/types/infer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6451,14 +6451,25 @@ impl<'db> TypeInferenceBuilder<'db> {
/// homogeneous tuple and a partly homogeneous tuple (respectively) due to the `...`
/// and the starred expression (respectively), Neither is supported by us right now,
/// so we should infer `Todo` for the *entire* tuple if we encounter one of those elements.
/// Even a subscript subelement could alter the type of the entire tuple
/// if the subscript is `Unpack[]` (which again, we don't yet support).
fn element_could_alter_type_of_whole_tuple(element: &ast::Expr, element_ty: Type) -> bool {
element_ty.is_todo()
&& matches!(
element,
ast::Expr::EllipsisLiteral(_) | ast::Expr::Starred(_) | ast::Expr::Subscript(_)
)
fn element_could_alter_type_of_whole_tuple(
element: &ast::Expr,
element_ty: Type,
builder: &TypeInferenceBuilder,
) -> bool {
if !element_ty.is_todo() {
return false;
}

match element {
ast::Expr::EllipsisLiteral(_) | ast::Expr::Starred(_) => true,
ast::Expr::Subscript(ast::ExprSubscript { value, .. }) => {
matches!(
builder.expression_type(value),
Type::KnownInstance(KnownInstanceType::Unpack)
)
}
_ => false,
}
}

// TODO:
Expand All @@ -6474,7 +6485,8 @@ impl<'db> TypeInferenceBuilder<'db> {

for element in elements {
let element_ty = self.infer_type_expression(element);
return_todo |= element_could_alter_type_of_whole_tuple(element, element_ty);
return_todo |=
element_could_alter_type_of_whole_tuple(element, element_ty, self);
element_types.push(element_ty);
}

Expand All @@ -6493,7 +6505,8 @@ impl<'db> TypeInferenceBuilder<'db> {
}
single_element => {
let single_element_ty = self.infer_type_expression(single_element);
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, self)
{
todo_type!("full tuple[...] support")
} else {
TupleType::from_elements(self.db(), std::iter::once(single_element_ty))
Expand Down
Loading