diff --git a/pytype/blocks/blocks.py b/pytype/blocks/blocks.py index 9282c0b63..5a2e71614 100644 --- a/pytype/blocks/blocks.py +++ b/pytype/blocks/blocks.py @@ -78,6 +78,12 @@ def __getitem__(self, index_or_slice): def __iter__(self): return self.code.__iter__() + def __lt__(self, other: Self) -> bool: + return (self.code[0].line, self.id) < (other.code[0].line, other.id) + + def __gt__(self, other: Self) -> bool: + return (self.code[0].line, self.id) > (other.code[0].line, other.id) + class OrderedCode: """Code object which knows about instruction ordering. diff --git a/pytype/tests/test_flow2.py b/pytype/tests/test_flow2.py index 018c7b871..29aed9be7 100644 --- a/pytype/tests/test_flow2.py +++ b/pytype/tests/test_flow2.py @@ -95,6 +95,20 @@ def f() -> int: f() """) + def test_try_in_loop(self): + self.Check(""" + def may_fail(): + pass + + while True: + err = None + try: + may_fail() + except ValueError as e: + err = str(e) + assert_type(err, str|None) + """) + if __name__ == "__main__": test_base.main() diff --git a/pytype/typegraph/cfg_utils.py b/pytype/typegraph/cfg_utils.py index 1a33ec0c4..03562c398 100644 --- a/pytype/typegraph/cfg_utils.py +++ b/pytype/typegraph/cfg_utils.py @@ -272,7 +272,12 @@ def compute_predecessors( class OrderableNode(PredecessorNode, Protocol): - id: int + + def __lt__(self, other: "OrderableNode", /) -> bool: + ... + + def __gt__(self, other: "OrderableNode", /) -> bool: + ... _OrderableNode = TypeVar("_OrderableNode", bound=OrderableNode) @@ -287,8 +292,9 @@ def order_nodes(nodes: Sequence[_OrderableNode]) -> list[_OrderableNode]: process both the branches before that node). Args: - nodes: A list of nodes or blocks. They have two attributes: "id" (an int to - enable deterministic sorting) and "outgoing" (a list of nodes). + nodes: A list of nodes or blocks. They have an attribute `outgoing` (a list + of nodes) and define rich comparisons method `__lt__` and `__gt__` to + enable deterministic sorting. Returns: A list of nodes in the proper order. @@ -308,9 +314,8 @@ def order_nodes(nodes: Sequence[_OrderableNode]) -> list[_OrderableNode]: while queue: # Find node with minimum amount of predecessors that's connected to a node # we already processed. - _, _, node = min( - (len(predecessors), node.id, node) - for node, predecessors in queue.items() + _, node = min( + (len(predecessors), node) for node, predecessors in queue.items() ) del queue[node] if node in seen: