55
66from __future__ import annotations
77
8+ import collections
89import dis
910
1011from types import CodeType
@@ -98,7 +99,9 @@ def walk(
9899
99100
100101TBranchTrail = tuple [set [TOffset ], Optional [TArc ]]
101- TBranchTrails = dict [TOffset , list [TBranchTrail ]]
102+ #TBranchTrails = dict[TOffset, list[TBranchTrail]]
103+
104+ TBranchTrails = dict [TOffset , dict [Optional [TArc ], set [TOffset ]]]
102105
103106
104107def branch_trails (code : CodeType ) -> TBranchTrails :
@@ -117,7 +120,7 @@ def branch_trails(code: CodeType) -> TBranchTrails:
117120 arc from the original instruction's line to the new source line.
118121
119122 """
120- the_trails : TBranchTrails = {}
123+ the_trails : TBranchTrails = collections . defaultdict ( lambda : collections . defaultdict ( set ))
121124 iwalker = InstructionWalker (code )
122125 for inst in iwalker .walk (follow_jumps = False ):
123126 if not inst .jump_target :
@@ -131,7 +134,7 @@ def branch_trails(code: CodeType) -> TBranchTrails:
131134 if from_line is None :
132135 continue
133136
134- def walk_one_branch (start_at : TOffset ) -> TBranchTrail :
137+ def walk_one_branch (start_at : TOffset ) -> tuple [ Optional [ TArc ], set [ TOffset ]] :
135138 # pylint: disable=cell-var-from-loop
136139 inst_offsets : set [TOffset ] = set ()
137140 to_line = None
@@ -146,27 +149,26 @@ def walk_one_branch(start_at: TOffset) -> TBranchTrail:
146149 to_line = - code .co_firstlineno
147150 break
148151 if to_line is not None :
149- return inst_offsets , (from_line , to_line )
152+ return (from_line , to_line ), inst_offsets
150153 else :
151- return set (), None
154+ return None , set ()
152155
153156 # Calculate two trails: one from the next instruction, and one from the
154157 # jump_target instruction.
155- trails = [
156- walk_one_branch (start_at = inst .offset + 2 ),
157- walk_one_branch (start_at = inst .jump_target ),
158- ]
158+ trails = collections .defaultdict (set )
159+ arc , offsets = walk_one_branch (start_at = inst .offset + 2 )
160+ trails [arc ].update (offsets )
161+ arc , offsets = walk_one_branch (start_at = inst .jump_target )
162+ trails [arc ].update (offsets )
159163 the_trails [inst .offset ] = trails
160164
161165 # Sometimes we get BRANCH_RIGHT or BRANCH_LEFT events from instructions
162166 # other than the original jump possibility instruction. Register each
163167 # trail under all of their offsets so we can pick up in the middle of a
164168 # trail if need be.
165- for trail in trails :
166- for offset in trail [0 ]:
167- if offset not in the_trails :
168- the_trails [offset ] = []
169- the_trails [offset ].append (trail )
169+ for arc , offsets in trails .items ():
170+ for offset in offsets :
171+ the_trails [offset ][arc ].update (offsets )
170172
171173 return the_trails
172174
0 commit comments