@@ -701,20 +701,22 @@ _PyCompile_EnterScope(compiler *c, identifier name, int scope_type,
701701 return ERROR ;
702702 }
703703 if (u -> u_ste -> ste_needs_class_closure ) {
704- /* Cook up an implicit __class__ cell. */
704+ /* Private cellvar name so it cannot clash with a class-body
705+ * LOCAL/FREE named __class__. Methods still expose freevar
706+ * __class__; _PyCompile_LookupArg maps that free to this cell. */
705707 Py_ssize_t res ;
706708 assert (u -> u_scope_type == COMPILE_SCOPE_CLASS );
707- res = _PyCompile_DictAddObj (u -> u_metadata .u_cellvars , & _Py_ID (__class__ ));
709+ res = _PyCompile_DictAddObj (u -> u_metadata .u_cellvars , & _Py_ID (__classcell__ ));
708710 if (res < 0 ) {
709711 compiler_unit_free (u );
710712 return ERROR ;
711713 }
712714 }
713715 if (u -> u_ste -> ste_needs_classdict ) {
714- /* Cook up an implicit __classdict__ cell . */
716+ /* Private cellvar name; see ste_needs_class_closure above . */
715717 Py_ssize_t res ;
716718 assert (u -> u_scope_type == COMPILE_SCOPE_CLASS );
717- res = _PyCompile_DictAddObj (u -> u_metadata .u_cellvars , & _Py_ID (__classdict__ ));
719+ res = _PyCompile_DictAddObj (u -> u_metadata .u_cellvars , & _Py_ID (__classdictcell__ ));
718720 if (res < 0 ) {
719721 compiler_unit_free (u );
720722 return ERROR ;
@@ -1010,11 +1012,35 @@ compiler_resolve_inlined_free(PySTEntryObject **ste, PyObject *name)
10101012 return scope ;
10111013}
10121014
1015+ /* Class-closure cells use private cellvar names that do not collide with
1016+ * class-body locals/frees of the same spelling. Method freevars keep the
1017+ * public names (__class__, ...); map those to the private cellvar. */
1018+ static PyObject *
1019+ compiler_class_closure_cellvar (PyObject * name )
1020+ {
1021+ if (name == & _Py_ID (__class__ )) {
1022+ return & _Py_ID (__classcell__ );
1023+ }
1024+ if (name == & _Py_ID (__classdict__ )) {
1025+ return & _Py_ID (__classdictcell__ );
1026+ }
1027+ if (name == & _Py_ID (__conditional_annotations__ )) {
1028+ return & _Py_ID (__conditional_annotations__ );
1029+ }
1030+ return NULL ;
1031+ }
1032+
10131033int
10141034_PyCompile_GetRefType (compiler * c , PyObject * name )
10151035{
1016- if (c -> u -> u_scope_type == COMPILE_SCOPE_CLASS && _PyST_IsClassClosureName (name )) {
1017- return CELL ;
1036+ /* Synthetic cells cooked into u_cellvars under their public spelling
1037+ * (today only __conditional_annotations__) are not always in ste_symbols. */
1038+ if (c -> u -> u_scope_type == COMPILE_SCOPE_CLASS ||
1039+ c -> u -> u_scope_type == COMPILE_SCOPE_MODULE ) {
1040+ PyObject * cell_name = compiler_class_closure_cellvar (name );
1041+ if (cell_name != NULL && cell_name == name ) {
1042+ return CELL ;
1043+ }
10181044 }
10191045 PySTEntryObject * ste = c -> u -> u_ste ;
10201046 int scope = compiler_resolve_inlined_free (& ste , name );
@@ -1054,6 +1080,61 @@ _PyCompile_LookupCellvar(compiler *c, PyObject *name)
10541080int
10551081_PyCompile_LookupArg (compiler * c , PyCodeObject * co , PyObject * name )
10561082{
1083+ /* Class units store the synthetic class-closure cell under a private
1084+ * name (__classcell__, ...). Inside an inlined comprehension, a nested
1085+ * free of the public name usually captures that comprehension's CELL;
1086+ * elsewhere (methods, class-body lambdas) it is the private cell. */
1087+ if (c -> u -> u_scope_type == COMPILE_SCOPE_CLASS ) {
1088+ PyObject * cell_name = compiler_class_closure_cellvar (name );
1089+ if (cell_name != NULL ) {
1090+ int arg ;
1091+ int in_inlined = (c -> u -> u_ste -> ste_type == InlinedComprehensionBlock );
1092+ if (in_inlined ) {
1093+ arg = dict_lookup_arg (c -> u -> u_metadata .u_cellvars , name );
1094+ if (arg != -1 ) {
1095+ return arg ;
1096+ }
1097+ if (PyErr_Occurred ()) {
1098+ return ERROR ;
1099+ }
1100+ }
1101+ if (cell_name != name ) {
1102+ arg = dict_lookup_arg (c -> u -> u_metadata .u_cellvars , cell_name );
1103+ if (arg != -1 ) {
1104+ return arg ;
1105+ }
1106+ if (PyErr_Occurred ()) {
1107+ return ERROR ;
1108+ }
1109+ }
1110+ if (!in_inlined ) {
1111+ arg = dict_lookup_arg (c -> u -> u_metadata .u_cellvars , name );
1112+ if (arg != -1 ) {
1113+ return arg ;
1114+ }
1115+ if (PyErr_Occurred ()) {
1116+ return ERROR ;
1117+ }
1118+ }
1119+ arg = dict_lookup_arg (c -> u -> u_metadata .u_freevars , name );
1120+ if (arg != -1 || PyErr_Occurred ()) {
1121+ return arg ;
1122+ }
1123+ PyObject * freevars = _PyCode_GetFreevars (co );
1124+ if (freevars == NULL ) {
1125+ PyErr_Clear ();
1126+ }
1127+ PyErr_Format (PyExc_SystemError ,
1128+ "compiler_lookup_arg(name=%R) failed in class %S; "
1129+ "freevars of code %S: %R" ,
1130+ name ,
1131+ c -> u -> u_metadata .u_name ,
1132+ co -> co_name ,
1133+ freevars );
1134+ Py_XDECREF (freevars );
1135+ return ERROR ;
1136+ }
1137+ }
10571138 /* Special case: If a class contains a method with a
10581139 * free variable that has the same name as a method,
10591140 * the name will be considered free *and* local in the
0 commit comments