Repository: psf/black

Issue:
Black changes f-string into string even though there is a substitution in it.
**Describe the bug**:
Black changes f-string into string even though there is a substitution in it.

**To Reproduce**:
1. Put this into a file:
```py
temp_msg = (
    f"{f'{humanize_number(pos)}.': <{pound_len+2}} "
    f"{balance: <{bal_len + 5}} "
    f"<<{author.display_name}>>\n"
)
```
2. Run _Black_ on it with no arguments:
3. See error
```
error: cannot format test.py: INTERNAL ERROR: Black produced code that is not equivalent to the source.  Please report a bug on https://github.com/psf/black/issues. This diff might be helpful: C:\Users\Jakub\AppData\Local\Temp\blk_08urbts5.log
```
Contents of the log file:
```diff
--- src
+++ dst
@@ -85,60 +85,11 @@
                     )  # /Constant
                 )  # /JoinedStr
             )  # /FormattedValue
             Constant(
               value=
-                '',  # str
-            )  # /Constant
-            FormattedValue(
-              conversion=
-                -1,  # int
-              format_spec=
-                JoinedStr(
-                  values=
-                    Constant(
-                      value=
-                        '<',  # str
-                    )  # /Constant
-                    FormattedValue(
-                      conversion=
-                        -1,  # int
-                      format_spec=
-                        None,  # NoneType
-                      value=
-                        BinOp(
-                          left=
-                            Name(
-                              ctx=
-                                Load(
-                                )  # /Load
-                              id=
-                                'bal_len',  # str
-                            )  # /Name
-                          op=
-                            Add(
-                            )  # /Add
-                          right=
-                            Constant(
-                              value=
-                                5,  # int
-                            )  # /Constant
-                        )  # /BinOp
-                    )  # /FormattedValue
-                )  # /JoinedStr
-              value=
-                Name(
-                  ctx=
-                    Load(
-                    )  # /Load
-                  id=
-                    'balance',  # str
-                )  # /Name
-            )  # /FormattedValue
-            Constant(
-              value=
-                '<<',  # str
+                '{balance: <{bal_len + 5} <<',  # str
             )  # /Constant
             FormattedValue(
               conversion=
                 -1,  # int
               format_spec=
```

**Expected behavior**:
I would expect _Black_ to not touch that f-string.

**Environment:**
- Version: master (commit cd3a93a14689f046468ece2a5b1f78863c3c4cd2, with `--experimental-string-processing` flag)
- OS and Python version: Windows/Python 3.8.3

**Does this bug also happen on master?**
It *only* happens on master, it doesn't happen on current release as there's no string reformatting in it yet. Online formatter doesn't error, but it does produce this output which is obviously not equivalent to the original:
```py
temp_msg = (
    f"{f'{humanize_number(pos)}.': <{pound_len+2}} "
    "{balance: <{bal_len + 5} "
    f"<<{author.display_name}>>\n"
)
```

**Additional context**:
None

I'm sorry for the amount of issues but I tried to run Black's master on Cog-Creators/Red-DiscordBot's code base which resulted in quite a few of errors and also some undesired (by me) changes which I wanted to at least report even if they're not gonna be changed.



Discussion:
Can confirm this still fails on main (519f807f879350704449e424c5c5b7e049e582b3).
cc @bbugyi200 if you're interested. This crash happens only with `--experimental-string-processing`.

Resolving patch:
diff --git a/src/black/trans.py b/src/black/trans.py
--- a/src/black/trans.py
+++ b/src/black/trans.py
@@ -971,8 +971,8 @@ class StringSplitter(CustomSplitMapMixin, BaseStringSplitter):
             | \{\{
             | \}\}
             | (?R)
-        )+?
-    (?<!\}) \} (?:\}\})* (?!\})
+        )+
+    \}
     """
 
     def do_splitter_match(self, line: Line) -> TMatchResult:


Test patch:
diff --git a/tests/data/long_strings__regression.py b/tests/data/long_strings__regression.py
--- a/tests/data/long_strings__regression.py
+++ b/tests/data/long_strings__regression.py
@@ -407,6 +407,12 @@ def _legacy_listen_examples():
     )
 
 
+temp_msg = (
+    f"{f'{humanize_number(pos)}.': <{pound_len+2}} "
+    f"{balance: <{bal_len + 5}} "
+    f"<<{author.display_name}>>\n"
+)
+
 assert str(suffix_arr) == (
     "['$', 'angaroo$', 'angrykangaroo$', 'aroo$', 'garoo$', "
     "'grykangaroo$', 'kangaroo$', 'ngaroo$', 'ngrykangaroo$', "
@@ -942,6 +948,12 @@ def _legacy_listen_examples():
     )
 
 
+temp_msg = (
+    f"{f'{humanize_number(pos)}.': <{pound_len+2}} "
+    f"{balance: <{bal_len + 5}} "
+    f"<<{author.display_name}>>\n"
+)
+
 assert (
     str(suffix_arr)
     == "['$', 'angaroo$', 'angrykangaroo$', 'aroo$', 'garoo$', "