Skip to content

Commit 24d8b88

Browse files
JelleZijlstracdce8perictrautlarryhastingsAlexWaygood
authored
gh-103763: Implement PEP 695 (#103764)
This implements PEP 695, Type Parameter Syntax. It adds support for: - Generic functions (def func[T](): ...) - Generic classes (class X[T](): ...) - Type aliases (type X = ...) - New scoping when the new syntax is used within a class body - Compiler and interpreter changes to support the new syntax and scoping rules Co-authored-by: Marc Mueller <30130371+cdce8p@users.noreply.github.com> Co-authored-by: Eric Traut <eric@traut.com> Co-authored-by: Larry Hastings <larry@hastings.org> Co-authored-by: Alex Waygood <Alex.Waygood@Gmail.com>
1 parent fdafdc2 commit 24d8b88

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

56 files changed

+9217
-3281
lines changed

Doc/library/ast.rst

+3
Original file line numberDiff line numberDiff line change
@@ -1724,6 +1724,7 @@ Function and class definitions
17241724
body=[
17251725
FunctionDef(
17261726
name='f',
1727+
typeparams=[],
17271728
args=arguments(
17281729
posonlyargs=[],
17291730
args=[
@@ -1847,6 +1848,7 @@ Function and class definitions
18471848
body=[
18481849
ClassDef(
18491850
name='Foo',
1851+
typeparams=[],
18501852
bases=[
18511853
Name(id='base1', ctx=Load()),
18521854
Name(id='base2', ctx=Load())],
@@ -1885,6 +1887,7 @@ Async and await
18851887
body=[
18861888
AsyncFunctionDef(
18871889
name='f',
1890+
typeparams=[],
18881891
args=arguments(
18891892
posonlyargs=[],
18901893
args=[],

Grammar/python.gram

+40-6
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,7 @@ simple_stmts[asdl_stmt_seq*]:
112112
# will throw a SyntaxError.
113113
simple_stmt[stmt_ty] (memo):
114114
| assignment
115+
| &"type" type_alias
115116
| e=star_expressions { _PyAST_Expr(e, EXTRA) }
116117
| &'return' return_stmt
117118
| &('import' | 'from') import_stmt
@@ -252,8 +253,8 @@ class_def[stmt_ty]:
252253

253254
class_def_raw[stmt_ty]:
254255
| invalid_class_def_raw
255-
| 'class' a=NAME b=['(' z=[arguments] ')' { z }] ':' c=block {
256-
_PyAST_ClassDef(a->v.Name.id,
256+
| 'class' a=NAME t=[type_params] b=['(' z=[arguments] ')' { z }] ':' c=block {
257+
_PyAST_ClassDef(a->v.Name.id, t,
257258
(b) ? ((expr_ty) b)->v.Call.args : NULL,
258259
(b) ? ((expr_ty) b)->v.Call.keywords : NULL,
259260
c, NULL, EXTRA) }
@@ -267,16 +268,16 @@ function_def[stmt_ty]:
267268

268269
function_def_raw[stmt_ty]:
269270
| invalid_def_raw
270-
| 'def' n=NAME &&'(' params=[params] ')' a=['->' z=expression { z }] &&':' tc=[func_type_comment] b=block {
271-
_PyAST_FunctionDef(n->v.Name.id,
271+
| 'def' n=NAME t=[type_params] &&'(' params=[params] ')' a=['->' z=expression { z }] &&':' tc=[func_type_comment] b=block {
272+
_PyAST_FunctionDef(n->v.Name.id, t,
272273
(params) ? params : CHECK(arguments_ty, _PyPegen_empty_arguments(p)),
273274
b, NULL, a, NEW_TYPE_COMMENT(p, tc), EXTRA) }
274-
| ASYNC 'def' n=NAME &&'(' params=[params] ')' a=['->' z=expression { z }] &&':' tc=[func_type_comment] b=block {
275+
| ASYNC 'def' n=NAME t=[type_params] &&'(' params=[params] ')' a=['->' z=expression { z }] &&':' tc=[func_type_comment] b=block {
275276
CHECK_VERSION(
276277
stmt_ty,
277278
5,
278279
"Async functions are",
279-
_PyAST_AsyncFunctionDef(n->v.Name.id,
280+
_PyAST_AsyncFunctionDef(n->v.Name.id, t,
280281
(params) ? params : CHECK(arguments_ty, _PyPegen_empty_arguments(p)),
281282
b, NULL, a, NEW_TYPE_COMMENT(p, tc), EXTRA)
282283
) }
@@ -628,6 +629,39 @@ keyword_patterns[asdl_seq*]:
628629
keyword_pattern[KeyPatternPair*]:
629630
| arg=NAME '=' value=pattern { _PyPegen_key_pattern_pair(p, arg, value) }
630631

632+
# Type statement
633+
# ---------------
634+
635+
type_alias[stmt_ty]:
636+
| "type" n=NAME t=[type_params] '=' b=expression {
637+
CHECK_VERSION(stmt_ty, 12, "Type statement is",
638+
_PyAST_TypeAlias(CHECK(expr_ty, _PyPegen_set_expr_context(p, n, Store)), t, b, EXTRA)) }
639+
640+
# Type parameter declaration
641+
# --------------------------
642+
643+
type_params[asdl_typeparam_seq*]: '[' t=type_param_seq ']' {
644+
CHECK_VERSION(asdl_typeparam_seq *, 12, "Type parameter lists are", t) }
645+
646+
type_param_seq[asdl_typeparam_seq*]: a[asdl_typeparam_seq*]=','.type_param+ [','] { a }
647+
648+
type_param[typeparam_ty] (memo):
649+
| a=NAME b=[type_param_bound] { _PyAST_TypeVar(a->v.Name.id, b, EXTRA) }
650+
| '*' a=NAME colon=":" e=expression {
651+
RAISE_SYNTAX_ERROR_STARTING_FROM(colon, e->kind == Tuple_kind
652+
? "cannot use constraints with TypeVarTuple"
653+
: "cannot use bound with TypeVarTuple")
654+
}
655+
| '*' a=NAME { _PyAST_TypeVarTuple(a->v.Name.id, EXTRA) }
656+
| '**' a=NAME colon=":" e=expression {
657+
RAISE_SYNTAX_ERROR_STARTING_FROM(colon, e->kind == Tuple_kind
658+
? "cannot use constraints with ParamSpec"
659+
: "cannot use bound with ParamSpec")
660+
}
661+
| '**' a=NAME { _PyAST_ParamSpec(a->v.Name.id, EXTRA) }
662+
663+
type_param_bound[expr_ty]: ":" e=expression { e }
664+
631665
# EXPRESSIONS
632666
# -----------
633667

Include/cpython/funcobject.h

+1
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ typedef struct {
4141
PyObject *func_weakreflist; /* List of weak references */
4242
PyObject *func_module; /* The __module__ attribute, can be anything */
4343
PyObject *func_annotations; /* Annotations, a dict or NULL */
44+
PyObject *func_typeparams; /* Tuple of active type variables or NULL */
4445
vectorcallfunc vectorcall;
4546
/* Version number for use by specializer.
4647
* Can set to non-zero when we want to specialize.

Include/internal/pycore_ast.h

+76-21
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Include/internal/pycore_ast_state.h

+7
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Include/internal/pycore_function.h

+2
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ struct _py_func_state {
1717
extern PyFunctionObject* _PyFunction_FromConstructor(PyFrameConstructor *constr);
1818

1919
extern uint32_t _PyFunction_GetVersionForCurrentState(PyFunctionObject *func);
20+
extern PyObject *_Py_set_function_type_params(
21+
PyThreadState* unused, PyObject *func, PyObject *type_params);
2022

2123
#ifdef __cplusplus
2224
}

Include/internal/pycore_global_objects.h

+8
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,14 @@ struct _Py_interp_cached_objects {
6868
PyObject *type_slots_pname;
6969
pytype_slotdef *type_slots_ptrs[MAX_EQUIV];
7070

71+
/* TypeVar and related types */
72+
PyTypeObject *generic_type;
73+
PyTypeObject *typevar_type;
74+
PyTypeObject *typevartuple_type;
75+
PyTypeObject *paramspec_type;
76+
PyTypeObject *paramspecargs_type;
77+
PyTypeObject *paramspeckwargs_type;
78+
PyTypeObject *typealias_type;
7179
};
7280

7381
#define _Py_INTERP_STATIC_OBJECT(interp, NAME) \

0 commit comments

Comments
 (0)