Commits

Ronan Lamy committed 120b233

Make sure that locals dict creation doesn't prevent translation

* Copy some initialisation code down into FSFrame and simplify it.
* Add test.

Comments (0)

Files changed (3)

pypy/objspace/flow/flowcontext.py

 from pypy.interpreter.executioncontext import ExecutionContext
 from pypy.interpreter.error import OperationError
 from pypy.interpreter.pytraceback import PyTraceback
-from pypy.interpreter import pyframe, nestedscope
+from pypy.interpreter import pyframe
+from pypy.interpreter.nestedscope import Cell
+from pypy.interpreter.pycode import CO_OPTIMIZED, CO_NEWLOCALS
 from pypy.interpreter.argument import ArgumentsForTranslation
 from pypy.interpreter.pyopcode import (Return, Yield, SuspendedUnroller,
         SReturnValue, SApplicationException, BytecodeCorruption, Reraise,
         class outerfunc: pass # hack
         if func.func_closure is not None:
             cl = [c.cell_contents for c in func.func_closure]
-            outerfunc.closure = [nestedscope.Cell(Constant(value)) for value in cl]
+            outerfunc.closure = [Cell(Constant(value)) for value in cl]
         else:
-            outerfunc.closure = None
+            outerfunc.closure = []
         super(FlowSpaceFrame, self).__init__(space, code, w_globals, outerfunc)
         self.last_instr = 0
 
             arg_list[position] = Constant(value)
         self.setfastscope(arg_list)
 
+    def initialize_frame_scopes(self, outer_func, code):
+        # CO_NEWLOCALS: make a locals dict unless optimized is also set
+        # CO_OPTIMIZED: no locals dict needed at all
+        flags = code.co_flags
+        if flags & CO_OPTIMIZED:
+            pass
+        elif flags & CO_NEWLOCALS:
+            self.w_locals = SpaceOperation('newdict', (), Variable()).result
+        else:
+            assert self.w_globals is not None
+            self.w_locals = self.w_globals
+        ncellvars = len(code.co_cellvars)
+        nfreevars = len(code.co_freevars)
+        closure_size = len(outer_func.closure)
+        if closure_size != nfreevars:
+            raise ValueError("code object received a closure with "
+                                 "an unexpected number of free variables")
+        self.cells = [Cell() for i in range(ncellvars)] + outer_func.closure
+
     def _init_graph(self, func):
         # CallableFactory.pycall may add class_ to functions that are methods
         name = func.func_name

pypy/objspace/flow/objspace.py

     # ____________________________________________________________
     def do_operation(self, name, *args_w):
         spaceop = SpaceOperation(name, args_w, Variable())
-        if hasattr(self, 'executioncontext'):  # not here during bootstrapping
-            spaceop.offset = self.executioncontext.frame.last_instr
-            self.executioncontext.recorder.append(spaceop)
+        spaceop.offset = self.executioncontext.frame.last_instr
+        self.executioncontext.recorder.append(spaceop)
         return spaceop.result
 
     def do_operation_with_implicit_exceptions(self, name, *args_w):

pypy/objspace/flow/test/test_objspace.py

                 pass
         py.test.raises(error.FlowingError, "self.codetest(f)")
 
+    def test_locals_dict(self):
+        def f():
+            x = 5
+            return x
+            exec "None"
+        graph = self.codetest(f)
+        assert len(graph.startblock.exits) == 1
+        assert graph.startblock.exits[0].target == graph.returnblock
+
 
 class TestFlowObjSpaceDelay(Base):
     def setup_class(cls):