Skip to content

Comments

Disallow implicit concatenation of t-strings and other string types#19485

Merged
dylwil3 merged 14 commits intoastral-sh:mainfrom
dylwil3:t-string-disallow-concat
Jul 27, 2025
Merged

Disallow implicit concatenation of t-strings and other string types#19485
dylwil3 merged 14 commits intoastral-sh:mainfrom
dylwil3:t-string-disallow-concat

Conversation

@dylwil3
Copy link
Collaborator

@dylwil3 dylwil3 commented Jul 22, 2025

As of this cpython PR, it is not allowed to concatenate t-strings with non-t-strings, implicitly or explicitly. Expressions such as "foo" t"{bar}" are now syntax errors.

This PR updates some AST nodes and parsing to reflect this change.

The structural change is that TStringPart is no longer needed, since, as in the case of BytesStringLiteral, the only possibilities are that we have a single TString or a vector of such (representing an implicit concatenation of t-strings). This removes a level of nesting from many AST expressions (which is what all the snapshot changes reflect), and simplifies some logic in the implementation of visitors, for example.

The other change of note is in the parser. When we meet an implicit concatenation of string-like literals, we now count the number of t-string literals. If these do not exhaust the total number of implicitly concatenated pieces, then we emit a syntax error. To recover from this syntax error, we encode any t-string pieces as invalid string literals (which means we flag them as invalid, record their range, and record the value as ""). Note that if at least one of the pieces is an f-string we prefer to parse the entire string as an f-string; otherwise we parse it as a string.

This logic is exactly the same as how we currently treat BytesStringLiteral parsing and error recovery - and carries with it the same pros and cons.

Finally, note that I have not implemented any changes in the implementation of the formatter. As far as I can tell, none are needed. I did change a few of the fixtures so that we are always concatenating t-strings with t-strings.

@dylwil3 dylwil3 added internal An internal refactor or improvement parser Related to the parser python314 Related to Python 3.14 labels Jul 22, 2025
@github-actions
Copy link
Contributor

github-actions bot commented Jul 22, 2025

mypy_primer results

No ecosystem changes detected ✅
No memory usage changes detected ✅

@github-actions
Copy link
Contributor

github-actions bot commented Jul 22, 2025

ruff-ecosystem results

Linter (stable)

✅ ecosystem check detected no linter changes.

Linter (preview)

✅ ecosystem check detected no linter changes.

Formatter (stable)

✅ ecosystem check detected no format changes.

Formatter (preview)

✅ ecosystem check detected no format changes.

InterpolatedStringLiteralElement {
range: 10..17,
node_index: AtomicNodeIndex(..),
value: "{foo}",
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is correct - the actual test has

        let source = r#"t"{a}{ b }{{foo}}""#;

so we are correctly reading the escaped braces.

Comment on lines 42 to 45
ExprNumberLiteral {
node_index: AtomicNodeIndex(..),
range: 3..5,
range: 9..11,
value: Int(
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is also correct - it's just one of those unfortunate diffs that makes it look like something changed when it was just moved.

@dylwil3 dylwil3 force-pushed the t-string-disallow-concat branch 2 times, most recently from 19a8667 to 1762483 Compare July 25, 2025 18:28
@dylwil3 dylwil3 marked this pull request as ready for review July 25, 2025 18:39
@dylwil3 dylwil3 force-pushed the t-string-disallow-concat branch from 1762483 to 34a9313 Compare July 27, 2025 12:37
@dylwil3 dylwil3 enabled auto-merge (squash) July 27, 2025 12:38
@dylwil3 dylwil3 merged commit 008bbfd into astral-sh:main Jul 27, 2025
36 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

internal An internal refactor or improvement parser Related to the parser python314 Related to Python 3.14

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants