Fixed a bug that caused internal errors if names where used as iteration
variable and regular variable *after* the loop if that variable was unused
*before* the loop.  (#331)

--HG--
branch : trunk
diff --git a/jinja2/compiler.py b/jinja2/compiler.py
index b6bf2eb..20ac03b 100644
--- a/jinja2/compiler.py
+++ b/jinja2/compiler.py
@@ -115,14 +115,6 @@
             return False
         return name in self.declared
 
-    def find_shadowed(self, extra=()):
-        """Find all the shadowed names.  extra is an iterable of variables
-        that may be defined with `add_special` which may occour scoped.
-        """
-        return (self.declared | self.outer_undeclared) & \
-               (self.declared_locally | self.declared_parameter) | \
-               set(x for x in extra if self.is_declared(x))
-
 
 class Frame(object):
     """Holds compile time information for us."""
@@ -151,15 +143,17 @@
         # the name of the block we're in, otherwise None.
         self.block = parent and parent.block or None
 
+        # a set of actually assigned names
+        self.assigned_names = set()
+
         # the parent of this frame
         self.parent = parent
 
         if parent is not None:
             self.identifiers.declared.update(
                 parent.identifiers.declared |
-                parent.identifiers.declared_locally |
                 parent.identifiers.declared_parameter |
-                parent.identifiers.undeclared
+                parent.assigned_names
             )
             self.identifiers.outer_undeclared.update(
                 parent.identifiers.undeclared -
@@ -184,6 +178,15 @@
         for node in nodes:
             visitor.visit(node)
 
+    def find_shadowed(self, extra=()):
+        """Find all the shadowed names.  extra is an iterable of variables
+        that may be defined with `add_special` which may occour scoped.
+        """
+        i = self.identifiers
+        return (i.declared | i.outer_undeclared) & \
+               (i.declared_locally | i.declared_parameter) | \
+               set(x for x in extra if i.is_declared(x))
+
     def inner(self):
         """Return an inner frame."""
         return Frame(self)
@@ -295,6 +298,9 @@
     def visit_FilterBlock(self, node):
         self.visit(node.filter)
 
+    def visit_Scope(self, node):
+        """Stop visiting at scopes."""
+
     def visit_Block(self, node):
         """Stop visiting at blocks."""
 
@@ -538,10 +544,10 @@
         This also predefines locally declared variables from the loop
         body because under some circumstances it may be the case that
 
-        `extra_vars` is passed to `Identifiers.find_shadowed`.
+        `extra_vars` is passed to `Frame.find_shadowed`.
         """
         aliases = {}
-        for name in frame.identifiers.find_shadowed(extra_vars):
+        for name in frame.find_shadowed(extra_vars):
             aliases[name] = ident = self.temporary_identifier()
             self.writeline('%s = l_%s' % (ident, name))
         to_declare = set()
@@ -878,6 +884,7 @@
             self.write('module')
         if frame.toplevel and not node.target.startswith('_'):
             self.writeline('context.exported_vars.discard(%r)' % node.target)
+        frame.assigned_names.add(node.target)
 
     def visit_FromImport(self, node, frame):
         """Visit named imports."""
@@ -914,6 +921,7 @@
                 var_names.append(alias)
                 if not alias.startswith('_'):
                     discarded_names.append(alias)
+            frame.assigned_names.add(alias)
 
         if var_names:
             if len(var_names) == 1:
@@ -1079,6 +1087,7 @@
             self.writeline('context.vars[%r] = ' % node.name)
         self.write('l_%s = ' % node.name)
         self.macro_def(node, macro_frame)
+        frame.assigned_names.add(node.name)
 
     def visit_CallBlock(self, node, frame):
         children = node.iter_child_nodes(exclude=('call',))
@@ -1228,7 +1237,7 @@
         # names here.
         if frame.toplevel:
             assignment_frame = frame.copy()
-            assignment_frame.assigned_names = set()
+            assignment_frame.toplevel_assignments = set()
         else:
             assignment_frame = frame
         self.visit(node.target, assignment_frame)
@@ -1237,14 +1246,14 @@
 
         # make sure toplevel assignments are added to the context.
         if frame.toplevel:
-            public_names = [x for x in assignment_frame.assigned_names
+            public_names = [x for x in assignment_frame.toplevel_assignments
                             if not x.startswith('_')]
-            if len(assignment_frame.assigned_names) == 1:
-                name = iter(assignment_frame.assigned_names).next()
+            if len(assignment_frame.toplevel_assignments) == 1:
+                name = iter(assignment_frame.toplevel_assignments).next()
                 self.writeline('context.vars[%r] = l_%s' % (name, name))
             else:
                 self.writeline('context.vars.update({')
-                for idx, name in enumerate(assignment_frame.assigned_names):
+                for idx, name in enumerate(assignment_frame.toplevel_assignments):
                     if idx:
                         self.write(', ')
                     self.write('%r: l_%s' % (name, name))
@@ -1261,8 +1270,9 @@
 
     def visit_Name(self, node, frame):
         if node.ctx == 'store' and frame.toplevel:
-            frame.assigned_names.add(node.name)
+            frame.toplevel_assignments.add(node.name)
         self.write('l_' + node.name)
+        frame.assigned_names.add(node.name)
 
     def visit_Const(self, node, frame):
         val = node.value
@@ -1472,3 +1482,11 @@
 
     def visit_Break(self, node, frame):
         self.writeline('break', node)
+
+    def visit_Scope(self, node, frame):
+        scope_frame = frame.inner()
+        scope_frame.inspect(node.iter_child_nodes())
+        aliases = self.push_scope(scope_frame)
+        self.pull_locals(scope_frame)
+        self.blockvisit(node.body, scope_frame)
+        self.pop_scope(aliases, scope_frame)