[pypy-commit] pypy py3.5: More hacks to make the cell '__class__' in class bodies work

arigo pypy.commits at gmail.com
Wed Dec 7 08:44:46 EST 2016


Author: Armin Rigo <arigo at tunes.org>
Branch: py3.5
Changeset: r88937:061607b3f6ed
Date: 2016-12-07 14:44 +0100
http://bitbucket.org/pypy/pypy/changeset/061607b3f6ed/

Log:	More hacks to make the cell '__class__' in class bodies work

diff --git a/pypy/interpreter/astcompiler/assemble.py b/pypy/interpreter/astcompiler/assemble.py
--- a/pypy/interpreter/astcompiler/assemble.py
+++ b/pypy/interpreter/astcompiler/assemble.py
@@ -137,11 +137,11 @@
         return ''.join(code)
 
 
-def _make_index_dict_filter(syms, flag):
+def _make_index_dict_filter(syms, flag1, flag2):
     i = 0
     result = {}
     for name, scope in syms.iteritems():
-        if scope == flag:
+        if scope in (flag1, flag2):
             result[name] = i
             i += 1
     return result
@@ -170,7 +170,8 @@
         self.names = {}
         self.var_names = _iter_to_dict(scope.varnames)
         self.cell_vars = _make_index_dict_filter(scope.symbols,
-                                                 symtable.SCOPE_CELL)
+                                                 symtable.SCOPE_CELL,
+                                                 symtable.SCOPE_CELL_CLASS)
         self.free_vars = _iter_to_dict(scope.free_vars, len(self.cell_vars))
         self.w_consts = space.newdict()
         self.argcount = 0
diff --git a/pypy/interpreter/astcompiler/codegen.py b/pypy/interpreter/astcompiler/codegen.py
--- a/pypy/interpreter/astcompiler/codegen.py
+++ b/pypy/interpreter/astcompiler/codegen.py
@@ -317,7 +317,8 @@
             # Load cell and free vars to pass on.
             for free in code.co_freevars:
                 free_scope = self.scope.lookup(free)
-                if free_scope == symtable.SCOPE_CELL:
+                if free_scope in (symtable.SCOPE_CELL,
+                                  symtable.SCOPE_CELL_CLASS):
                     index = self.cell_vars[free]
                 else:
                     index = self.free_vars[free]
@@ -1626,7 +1627,7 @@
         self._handle_body(cls.body)
         # return the (empty) __class__ cell
         scope = self.scope.lookup("__class__")
-        if scope == symtable.SCOPE_CELL:
+        if scope == symtable.SCOPE_CELL_CLASS:
             # Return the cell where to store __class__
             self.emit_op_arg(ops.LOAD_CLOSURE, self.cell_vars["__class__"])
         else:
diff --git a/pypy/interpreter/astcompiler/symtable.py b/pypy/interpreter/astcompiler/symtable.py
--- a/pypy/interpreter/astcompiler/symtable.py
+++ b/pypy/interpreter/astcompiler/symtable.py
@@ -21,6 +21,7 @@
 SCOPE_LOCAL = 3
 SCOPE_FREE = 4
 SCOPE_CELL = 5
+SCOPE_CELL_CLASS = 6     # for "__class__" inside class bodies only
 
 
 class Scope(object):
@@ -336,7 +337,7 @@
     def _finalize_cells(self, free):
         for name, role in self.symbols.iteritems():
             if role == SCOPE_LOCAL and name in free and name == '__class__':
-                self.symbols[name] = SCOPE_CELL
+                self.symbols[name] = SCOPE_CELL_CLASS
                 del free[name]
 
 
diff --git a/pypy/interpreter/test/test_compiler.py b/pypy/interpreter/test/test_compiler.py
--- a/pypy/interpreter/test/test_compiler.py
+++ b/pypy/interpreter/test/test_compiler.py
@@ -398,6 +398,13 @@
     # in CPython 3.5.2.  Looks like a bug to me
 def testing():
     return 42
+''', '''
+class Y:
+    def f():
+        __class__
+    __class__ = 42
+def testing():
+    return Y.__dict__['__class__']
 '''
         ]:
             space.call_args(w_filterwarnings, filter_arg)


More information about the pypy-commit mailing list