Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
@@ -0,0 +1,7 @@
# parse_options: {"target-version": "3.10"}
lst[*index] # simple index
class Array(Generic[DType, *Shape]): ... # motivating example from the PEP
lst[a, *b, c] # different positions
lst[a, b, *c] # different positions
lst[*a, *b] # multiple unpacks
array[3:5, *idxs] # mixed with slices
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
array[*start:*end]
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# parse_options: {"target-version": "3.11"}
lst[*index] # simple index
class Array(Generic[DType, *Shape]): ... # motivating example from the PEP
lst[a, *b, c] # different positions
lst[a, b, *c] # different positions
lst[*a, *b] # multiple unpacks
array[3:5, *idxs] # mixed with slices
34 changes: 34 additions & 0 deletions crates/ruff_python_parser/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -610,6 +610,34 @@ pub enum UnsupportedSyntaxErrorKind {
TypeParameterList,
TypeAliasStatement,
TypeParamDefault,

/// Represents the use of a [PEP 646] star expression in an index.
///
/// ## Examples
///
/// Before Python 3.11, star expressions were not allowed in index/subscript operations (within
/// square brackets). This restriction was lifted in [PEP 646] to allow for star-unpacking of
/// `typing.TypeVarTuple`s, also added in Python 3.11. As such, this is the primary motivating
/// example from the PEP:
///
/// ```python
/// from typing import TypeVar, TypeVarTuple
///
/// DType = TypeVar('DType')
/// Shape = TypeVarTuple('Shape')
///
/// class Array(Generic[DType, *Shape]): ...
/// ```
///
/// But it applies to simple indexing as well:
///
/// ```python
/// vector[*x]
/// array[a, *b]
/// ```
///
/// [PEP 646]: https://peps.python.org/pep-0646/#change-1-star-expressions-in-indexes
StarExpressionInIndex,
}

impl Display for UnsupportedSyntaxError {
Expand All @@ -636,6 +664,9 @@ impl Display for UnsupportedSyntaxError {
UnsupportedSyntaxErrorKind::TypeParamDefault => {
"Cannot set default type for a type parameter"
}
UnsupportedSyntaxErrorKind::StarExpressionInIndex => {
"Cannot use star expression in index"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: Maybe in index operations to align with the terminology used in the PEP

}
};

write!(
Expand Down Expand Up @@ -681,6 +712,9 @@ impl UnsupportedSyntaxErrorKind {
UnsupportedSyntaxErrorKind::TypeParameterList => Change::Added(PythonVersion::PY312),
UnsupportedSyntaxErrorKind::TypeAliasStatement => Change::Added(PythonVersion::PY312),
UnsupportedSyntaxErrorKind::TypeParamDefault => Change::Added(PythonVersion::PY313),
UnsupportedSyntaxErrorKind::StarExpressionInIndex => {
Change::Added(PythonVersion::PY311)
}
}
}

Expand Down
29 changes: 29 additions & 0 deletions crates/ruff_python_parser/src/parser/expression.rs
Original file line number Diff line number Diff line change
Expand Up @@ -853,6 +853,35 @@ impl<'src> Parser<'src> {

self.expect(TokenKind::Rsqb);

// test_ok star_index_py311
// # parse_options: {"target-version": "3.11"}
// lst[*index] # simple index
// class Array(Generic[DType, *Shape]): ... # motivating example from the PEP
// lst[a, *b, c] # different positions
// lst[a, b, *c] # different positions
// lst[*a, *b] # multiple unpacks
// array[3:5, *idxs] # mixed with slices

// test_err star_index_py310
// # parse_options: {"target-version": "3.10"}
// lst[*index] # simple index
// class Array(Generic[DType, *Shape]): ... # motivating example from the PEP
// lst[a, *b, c] # different positions
// lst[a, b, *c] # different positions
// lst[*a, *b] # multiple unpacks
// array[3:5, *idxs] # mixed with slices

// test_err star_slices
// array[*start:*end]
if let Expr::Tuple(ast::ExprTuple { elts, .. }) = &slice {
for elt in elts.iter().filter(|elt| elt.is_starred_expr()) {
self.add_unsupported_syntax_error(
UnsupportedSyntaxErrorKind::StarExpressionInIndex,
elt.range(),
);
}
};

ast::ExprSubscript {
value: Box::new(value),
slice: Box::new(slice),
Expand Down
Loading
Loading