gh-129093: Fix f-string debug text sometimes getting cut off when expression contains !#129159
gh-129093: Fix f-string debug text sometimes getting cut off when expression contains !#129159pablogsal merged 2 commits intopython:mainfrom
!#129159Conversation
|
I have made some spelunking and I have chased this code to the original implementation in commit 1ef61cf. The code was protecting against a condition that is not true anymore and unfortunately never got removed |
|
Thanks @tomasr8 for the PR, and @pablogsal for merging it 🌮🎉.. I'm working now to backport this PR to: 3.12. |
|
Thanks @tomasr8 for the PR, and @pablogsal for merging it 🌮🎉.. I'm working now to backport this PR to: 3.13. |
|
Sorry, @tomasr8 and @pablogsal, I could not cleanly backport this to |
…en expression contains `!` (pythonGH-129159) (cherry picked from commit 767cf70) Co-authored-by: Tomas R. <tomas.roun8@gmail.com>
|
GH-129163 is a backport of this pull request to the 3.13 branch. |
|
|
@freakboy3742: This iOS failure has happened twice in the last 24 hours on each of the main and 3.13 branches, but with successful builds in between. |
|
Yeah is certainly unrelated to this PR |
|
Yeah - this specific failure is a weird race condition that I thought would be fairly rare, but I've now seen it a couple of times. Logged as #129200. |
Here's what I think is happening (though I may be wrong, the lexer code and especially the f-string code is really complex):
For an f-string replacement field such as
{1!=2=}we end up in this branch of the parser:cpython/Grammar/python.gram
Lines 916 to 918 in 29caec6
The original source (i.e.
debug_expr) is stored on therbrace'stoken->metadata:cpython/Parser/lexer/lexer.c
Line 171 in 29caec6
which is how the
_PyPegen_formatted_valuefunction injects it into the AST (asdebug_text):cpython/Parser/action_helpers.c
Lines 1492 to 1493 in 29caec6
The
token->metadataitself gets the debug text fromtok_mode->last_expr_bufferandtok_mode->last_expr_end.cpython/Parser/lexer/lexer.c
Lines 159 to 163 in 29caec6
If we go back to the example
{1!=2=}, to parse thefstring_replacement_fieldrule, the parser first tries to parse theannotated_rhswhich consumes1at first since it's a valid expression. It then skipsdebug_expr='='?and starts parsing the conversion specifier which matches the following!. Now that it hit!, it setstok_mode->last_expr_endin_PyLexer_update_fstring_expr:cpython/Parser/lexer/lexer.c
Lines 212 to 218 in 29caec6
The problem is that now the parser needs to backtrack. The second time it parses the full
1!=2asannotated_rhsbut becausetok_mode->last_expr_endis guarded withif(tok_mode->last_expr_end == -1){}it never gets updated which is what is causing this issue.Simply removing that if check seems to work, but I'm not 100% sure this is the best way to fix it. It'd be great if a parser expert could check this :)