From 647542e6cbcd965c046c8657f217d276c4d54ab4 Mon Sep 17 00:00:00 2001 From: hauntsaninja <> Date: Fri, 28 Jan 2022 02:34:39 -0800 Subject: [PATCH] Fix arithmetic stability issue It turns out "simple_stmt" isn't that simple: it can contain multiple statements separated by semicolons. Invisible parenthesis logic for arithmetic expressions only looked at the first child of simple_stmt. This causes instability in the presence of semicolons, since the next run through the statement following the semicolon will be the first child of another simple_stmt. I believe this along with #2572 fix the known stability issues. --- src/black/linegen.py | 10 +++++++--- src/black/nodes.py | 7 +++---- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/src/black/linegen.py b/src/black/linegen.py index ac60ed1986..ca121ada3e 100644 --- a/src/black/linegen.py +++ b/src/black/linegen.py @@ -7,7 +7,7 @@ from black.nodes import WHITESPACE, RARROW, STATEMENT, STANDALONE_COMMENT from black.nodes import ASSIGNMENTS, OPENING_BRACKETS, CLOSING_BRACKETS -from black.nodes import Visitor, syms, first_child_is_arith, ensure_visible +from black.nodes import Visitor, syms, is_arith_like, ensure_visible from black.nodes import is_docstring, is_empty_tuple, is_one_tuple, is_one_tuple_between from black.nodes import is_name_token, is_lpar_token, is_rpar_token from black.nodes import is_walrus_assignment, is_yield, is_vararg, is_multiline_string @@ -156,8 +156,12 @@ def visit_suite(self, node: Node) -> Iterator[Line]: def visit_simple_stmt(self, node: Node) -> Iterator[Line]: """Visit a statement without nested statements.""" - if first_child_is_arith(node): - wrap_in_parentheses(node, node.children[0], visible=False) + prev_type = None + for child in node.children: + if (prev_type is None or prev_type == token.SEMI) and is_arith_like(child): + wrap_in_parentheses(node, child, visible=False) + prev_type = child.type + is_suite_like = node.parent and node.parent.type in STATEMENT if is_suite_like: if self.mode.is_pyi and is_stub_body(node): diff --git a/src/black/nodes.py b/src/black/nodes.py index 74dfa89629..aff0419fa7 100644 --- a/src/black/nodes.py +++ b/src/black/nodes.py @@ -536,15 +536,14 @@ def first_leaf_column(node: Node) -> Optional[int]: return None -def first_child_is_arith(node: Node) -> bool: - """Whether first child is an arithmetic or a binary arithmetic expression""" - expr_types = { +def is_arith_like(node: Node) -> bool: + """Whether node is an arithmetic or a binary arithmetic expression""" + return node.type in { syms.arith_expr, syms.shift_expr, syms.xor_expr, syms.and_expr, } - return bool(node.children and node.children[0].type in expr_types) def is_docstring(leaf: Leaf) -> bool: