Repository: psf/black

Issue:
bug formatting await (a**b)
<!--
Please make sure that the bug is not already fixed either in newer versions or the
current development version. To confirm this, you have three options:

1. Update Black's version if a newer release exists: `pip install -U black`
2. Use the online formatter at <https://black.vercel.app/?version=main>, which will use
   the latest main branch.
3. Or run _Black_ on your machine:
   - create a new virtualenv (make sure it's the same Python version);
   - clone this repository;
   - run `pip install -e .[d]`;
   - run `pip install -r test_requirements.txt`
   - make sure it's sane by running `python -m pytest`; and
   - run `black` like you did last time.
-->

**Describe the bug**

black converts `await (a**b)` into `await a ** b` (if run with --fast) 

**To Reproduce**


```python
async def name_5():
    await (name_1 ** name_4)
```

And run it with these arguments:

```sh
$ black file.py
```

The resulting error is:

> cannot format file.py: INTERNAL ERROR: ...

**Expected behavior**

black should preserve the braces and be able to format the file

**Environment**

<!-- Please complete the following information: -->

python -m black, 23.3.1.dev10+geb32729 (compiled: no)
Python (CPython) 3.11.3

**Additional context**

error log:
``` diff
--- src
+++ dst
@@ -14,34 +14,34 @@
             None,  # NoneType
         )  # /arguments
       body=
         Expr(
           value=
-            Await(
-              value=
-                BinOp(
-                  left=
+            BinOp(
+              left=
+                Await(
+                  value=
                     Name(
                       ctx=
                         Load(
                         )  # /Load
                       id=
                         'name_1',  # str
                     )  # /Name
-                  op=
-                    Pow(
-                    )  # /Pow
-                  right=
-                    Name(
-                      ctx=
-                        Load(
-                        )  # /Load
-                      id=
-                        'name_4',  # str
-                    )  # /Name
-                )  # /BinOp
-            )  # /Await
+                )  # /Await
+              op=
+                Pow(
+                )  # /Pow
+              right=
+                Name(
+                  ctx=
+                    Load(
+                    )  # /Load
+                  id=
+                    'name_4',  # str
+                )  # /Name
+            )  # /BinOp
         )  # /Expr
       decorator_list=
       name=
         'name_5',  # str
       returns=


```

For context:
I currently write a generator wich generates random python code. This is still work in progress, but finding bugs in black shows me that I am on the right track.
I will provide a script similar to `scripts/fuzz.py` as soon as it is ready.





Discussion:
Thanks! I suppose we get the precedence wrong and incorrectly remove the parentheses. Let us know if you find additional crashes while fuzzing.
I found two other issues while fuzzing, #3678 and #3677. I will stop searching for now because it seems that I find always the same issues. 

Resolving patch:
diff --git a/src/black/linegen.py b/src/black/linegen.py
--- a/src/black/linegen.py
+++ b/src/black/linegen.py
@@ -1350,18 +1350,16 @@ def remove_await_parens(node: Node) -> None:
             opening_bracket = cast(Leaf, node.children[1].children[0])
             closing_bracket = cast(Leaf, node.children[1].children[-1])
             bracket_contents = node.children[1].children[1]
-            if isinstance(bracket_contents, Node):
-                if bracket_contents.type != syms.power:
-                    ensure_visible(opening_bracket)
-                    ensure_visible(closing_bracket)
-                elif (
-                    bracket_contents.type == syms.power
-                    and bracket_contents.children[0].type == token.AWAIT
-                ):
-                    ensure_visible(opening_bracket)
-                    ensure_visible(closing_bracket)
-                    # If we are in a nested await then recurse down.
-                    remove_await_parens(bracket_contents)
+            if isinstance(bracket_contents, Node) and (
+                bracket_contents.type != syms.power
+                or bracket_contents.children[0].type == token.AWAIT
+                or any(
+                    isinstance(child, Leaf) and child.type == token.DOUBLESTAR
+                    for child in bracket_contents.children
+                )
+            ):
+                ensure_visible(opening_bracket)
+                ensure_visible(closing_bracket)
 
 
 def _maybe_wrap_cms_in_parens(


Test patch:
diff --git a/tests/data/cases/remove_await_parens.py b/tests/data/cases/remove_await_parens.py
--- a/tests/data/cases/remove_await_parens.py
+++ b/tests/data/cases/remove_await_parens.py
@@ -80,6 +80,15 @@ async def main():
 async def main():
     await (yield)
 
+async def main():
+    await (a ** b)
+    await (a[b] ** c)
+    await (a ** b[c])
+    await ((a + b) ** (c + d))
+    await (a + b)
+    await (a[b])
+    await (a[b ** c])
+
 # output
 import asyncio
 
@@ -174,3 +183,13 @@ async def main():
 
 async def main():
     await (yield)
+
+
+async def main():
+    await (a**b)
+    await (a[b] ** c)
+    await (a ** b[c])
+    await ((a + b) ** (c + d))
+    await (a + b)
+    await a[b]
+    await a[b**c]