Skip to content

Implement interpolated strings via String.Concat - #1

Closed
charlesroddie wants to merge 2 commits into
mainfrom
InterpolatedStringCollector
Closed

Implement interpolated strings via String.Concat#1
charlesroddie wants to merge 2 commits into
mainfrom
InterpolatedStringCollector

Conversation

@charlesroddie

@charlesroddie charlesroddie commented Jun 17, 2026

Copy link
Copy Markdown
Owner

PR ready so moved to main FSharp repo

@github-actions

Copy link
Copy Markdown

Caution

Repository is on lockdown for maintenance, all merges are on hold.

@github-actions

github-actions Bot commented Jun 17, 2026

Copy link
Copy Markdown

❗ Release notes required

@charlesroddie,

Caution

No release notes found for the changed paths (see table below).

Please make sure to add an entry with an informative description of the change as well as link to this pull request, issue and language suggestion if applicable. Release notes for this repository are based on Keep A Changelog format.

The following format is recommended for this repository:

* <Informative description>. ([PR #XXXXX](https://github.com/dotnet/fsharp/pull/XXXXX))

See examples in the files, listed in the table below or in th full documentation at https://fsharp.github.io/fsharp-compiler-docs/release-notes/About.html.

If you believe that release notes are not necessary for this PR, please add NO_RELEASE_NOTES label to the pull request.

You can open this PR in browser to add release notes: open in github.dev

Change path Release notes path Description
src/Compiler docs/release-notes/.FSharp.Compiler.Service/11.0.101.md No release notes found or release notes format is not correct

@charlesroddie charlesroddie changed the title Lower plain-hole string interpolation to StringBuilder Lower string-typed interpolation via StringBuilder Jun 18, 2026
Comment thread src/Compiler/SyntaxTree/ParseHelpers.fs Outdated
Comment thread src/Compiler/SyntaxTree/SyntaxTree.fsi Outdated
Comment thread tests/FSharp.Compiler.ComponentTests/Language/InterpolatedStringsTests.fs Outdated
Comment thread src/Compiler/Checking/CheckExpressions.fs Outdated
@charlesroddie charlesroddie changed the title Lower string-typed interpolation via StringBuilder Implement interpolated strings via StringBuilder Jun 18, 2026
@charlesroddie
charlesroddie force-pushed the InterpolatedStringCollector branch from 9c8c9b4 to 1e9ae9b Compare June 18, 2026 19:10
@charlesroddie charlesroddie changed the title Implement interpolated strings via StringBuilder Lower string-typed interpolation to String.Concat (reflection-free) Jun 18, 2026
@charlesroddie charlesroddie changed the title Lower string-typed interpolation to String.Concat (reflection-free) Implement interpolated strings via String.Concat Jun 18, 2026
@charlesroddie charlesroddie reopened this Jun 18, 2026
A string-typed interpolated string is lowered to System.String.Concat of its
parts rather than the reflection-based printf engine: a string-typed hole is
passed through directly, any other plain hole is converted with `string x`, an
aligned/formatted hole with `String.Format(InvariantCulture, ...)`, and a
printf-specifier hole with `sprintf`. This removes the reflection dependency on
the common path, so these interpolations become trim- and NativeAOT-compatible.

This generalizes and replaces the language-version-gated String.Concat
optimization (dotnet#16556), which only handled all-string holes: the lowering now
applies to every string-typed interpolation, ungated. The reflection path is
used only for PrintfFormat/FormattableString-typed interpolation.

The syntax tree now carries each hole's formatting explicitly, so a printf
specifier no longer leaks into an adjacent literal and alignment is no longer a
fake tuple:

    type SynInterpolatedStringPart =
        | String of value: string * range: range
        | FillExpr of fillExpr: SynExpr * formatting: SynInterpolationFormatting

    type SynInterpolationFormatting =
        | DotNet of alignment: SynExpr option * format: Ident option
        | Printf of specifier: string * range: range

Behavioural change: plain `{x}` holes now render with invariant culture (the F#
`string` operator) rather than the current thread culture, matching `string`.

Adds a NativeAOT regression test under tests/AheadOfTime/NativeAOT.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@charlesroddie
charlesroddie force-pushed the InterpolatedStringCollector branch 2 times, most recently from e2debcd to f571df9 Compare June 18, 2026 21:51
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant