[syntax-errors] Type parameter defaults before Python 3.13 (#16447)

Summary
--

Detects the presence of a [PEP 696] type parameter default before Python
3.13.

Test Plan
--

New inline parser tests for type aliases, generic functions and generic
classes.

[PEP 696]: https://peps.python.org/pep-0696/#grammar-changes
This commit is contained in:
Brent Westbrook 2025-03-04 11:53:38 -05:00 committed by GitHub
parent c8a06a9be8
commit e7b93f93ef
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 514 additions and 4 deletions

View file

@ -449,18 +449,22 @@ pub enum UnsupportedSyntaxErrorKind {
Match,
Walrus,
ExceptStar,
TypeParamDefault,
}
impl Display for UnsupportedSyntaxError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let kind = match self.kind {
UnsupportedSyntaxErrorKind::Match => "`match` statement",
UnsupportedSyntaxErrorKind::Walrus => "named assignment expression (`:=`)",
UnsupportedSyntaxErrorKind::ExceptStar => "`except*`",
UnsupportedSyntaxErrorKind::Match => "Cannot use `match` statement",
UnsupportedSyntaxErrorKind::Walrus => "Cannot use named assignment expression (`:=`)",
UnsupportedSyntaxErrorKind::ExceptStar => "Cannot use `except*`",
UnsupportedSyntaxErrorKind::TypeParamDefault => {
"Cannot set default type for a type parameter"
}
};
write!(
f,
"Cannot use {kind} on Python {} (syntax was added in Python {})",
"{kind} on Python {} (syntax was added in Python {})",
self.target_version,
self.kind.minimum_version(),
)
@ -474,6 +478,7 @@ impl UnsupportedSyntaxErrorKind {
UnsupportedSyntaxErrorKind::Match => PythonVersion::PY310,
UnsupportedSyntaxErrorKind::Walrus => PythonVersion::PY38,
UnsupportedSyntaxErrorKind::ExceptStar => PythonVersion::PY311,
UnsupportedSyntaxErrorKind::TypeParamDefault => PythonVersion::PY313,
}
}
}

View file

@ -3243,6 +3243,7 @@ impl<'src> Parser<'src> {
None
};
let equal_token_start = self.node_start();
let default = if self.eat(TokenKind::Equal) {
if self.at_expr() {
// test_err type_param_type_var_invalid_default_expr
@ -3268,6 +3269,26 @@ impl<'src> Parser<'src> {
None
};
// test_ok type_param_default_py313
// # parse_options: {"target-version": "3.13"}
// type X[T = int] = int
// def f[T = int](): ...
// class C[T = int](): ...
// test_err type_param_default_py312
// # parse_options: {"target-version": "3.12"}
// type X[T = int] = int
// def f[T = int](): ...
// class C[T = int](): ...
// class D[S, T = int, U = uint](): ...
if default.is_some() {
self.add_unsupported_syntax_error(
UnsupportedSyntaxErrorKind::TypeParamDefault,
self.node_range(equal_token_start),
);
}
ast::TypeParam::TypeVar(ast::TypeParamTypeVar {
range: self.node_range(start),
name,