# HG changeset patch # User Paul Boddie # Date 1559510007 -7200 # Node ID 709a26b533187c861e22dee9bf9e16ed563ab2e4 # Parent e42488d172c53746d264c031eca47c2f2e5b89b4# Parent 938887b82033d33ceaf9e9a462f1aabf5b7c8df2 Merged changes from the default branch. diff -r e42488d172c5 -r 709a26b53318 common.py --- a/common.py Mon May 27 11:58:58 2019 +0200 +++ b/common.py Sun Jun 02 23:13:27 2019 +0200 @@ -563,6 +563,8 @@ self.next_temporary() t2 = self.get_temporary_name() self.next_temporary() + t3 = self.get_temporary_name() + self.next_temporary() node = compiler.ast.Stmt([ @@ -583,9 +585,10 @@ # try: # while True: # try: - # ... = () + # = () # except StopIteration: # raise LoopExit + # ... = # {n.body} # except LoopExit: # {n.else_} @@ -601,13 +604,16 @@ compiler.ast.Stmt([ compiler.ast.TryExcept( compiler.ast.Assign( - [n.assign], + [compiler.ast.AssName(t3, "OP_ASSIGN")], compiler.ast.CallFunc( compiler.ast.Name(t2), [])), [(compiler.ast.Name("StopIteration"), None, compiler.ast.Raise(compiler.ast.Name("LoopExit")))], None), + compiler.ast.Assign( + [n.assign], + compiler.ast.Name(t3)), n.body]), None), [(compiler.ast.Name("LoopExit"), None, n.else_ or compiler.ast.Pass())], diff -r e42488d172c5 -r 709a26b53318 internal_tests/branches.py --- a/internal_tests/branches.py Mon May 27 11:58:58 2019 +0200 +++ b/internal_tests/branches.py Sun Jun 02 23:13:27 2019 +0200 @@ -687,4 +687,77 @@ bt.get_assignment_positions_for_branches("a", ar) names.append(bt.assignments["a"]) +# This demonstrates why the assignment in a "for" loop construct must appear +# outside the inner "try" body: null usage escapes the loop via the exception +# handler and the raise statement, even though the assignment would only be +# valid otherwise. + +# Equivalent to... +# +# try: +# while ...: +# try: +# a = ... +# except: +# raise ... +# a.p +# except: +# pass + +bt = branching.BranchTracker() +bt.new_branchpoint() # begin (try) +bt.new_branchpoint(True) # begin (while) +bt.new_branch(True) # while ... +bt.new_branchpoint() # begin (try) +a = bt.assign_names(["a"]) +bt.resume_abandoned_branches() # except +bt.abandon_branch() # raise +bt.shelve_branch() +bt.new_branch() # (null) +bt.shelve_branch() +bt.merge_branches() # end (try) +ap = bt.use_attribute("a", "p") +bt.resume_continuing_branches() +bt.shelve_branch(True) +bt.new_branch() # (null) +bt.shelve_branch() +bt.merge_branches() # end (while) +bt.resume_broken_branches() +bt.resume_abandoned_branches() # except +bt.shelve_branch() +bt.new_branch() # (null) +bt.shelve_branch() +bt.merge_branches() # end (try) + +print simple_usage(a) == \ + {'a' : set([('p',), ()])}, simple_usage(a) +print bt.get_assignment_positions_for_branches("a", ap) == [0], \ + bt.get_assignment_positions_for_branches("a", ap) +names.append(bt.assignments["a"]) + +# Equivalent to... +# +# b = ... +# while ...: +# a = ... +# a.p + +bt = branching.BranchTracker() +bt.new_branchpoint(True) # begin +b = bt.assign_names(["b"]) +bt.new_branch(True) # while ... +a = bt.assign_names(["a"]) +ap = bt.use_attribute("a", "p") +bt.resume_continuing_branches() +bt.shelve_branch(True) +bt.new_branch() # (null) +bt.shelve_branch() +bt.merge_branches() # end + +print simple_usage(a) == \ + {'a' : set([('p',)])}, simple_usage(a) +print bt.get_assignment_positions_for_branches("a", ap) == [0], \ + bt.get_assignment_positions_for_branches("a", ap) +names.append(bt.assignments["a"]) + # vim: tabstop=4 expandtab shiftwidth=4