dotnet / dotnet/roslyn

Better optimizations around combining string concatenation and string interpolation

Open
#73,736 0 comments 2 reactions 0 assignees View on GitHub
Area-Compilers Bug Code Gen Quality
Dominant language
C#
Stars
20.7k
Forks
4.3k
PR merge metrics
PR metrics pending

Description

I've recently seen a fair amount of code that involves expressions like:
```C#
string s1 = ..., s2 = ..., s3 = ...;
...
s1 += $"{s2} {s3} {somethingElse}";
```
When the string interpolation can be lowered to just usage of string.Concat, downstream optimizations combine the concat from the interpolation with the explicit concat:
```C#
public class C
{
public string M1(string s1, string s2, string s3)
{
s1 += $"{s2} {s3}";
return s1;
}
}
```
generates the equivalent of:
```C#
public class C
{
public string M1(string s1, string s2, string s3)
{
s1 = string.Concat(s1, s2, " ", s3);
return s1;
}
}
```
But, when the interpolation doesn't lower to a concat, the resulting code has both the string generated by the interpolation and then separately the concatenation, e.g.
```C#
public class C
{
public string M2(string s1, string s2, string s3)
{
s1 += $"{s2} {s3} {42}";
return s1;
}
}
```
generates the equivalent of:
```C#
public class C
{
public string M2(string s1, string s2, string s3)
{
string text = s1;
DefaultInterpolatedStringHandler defaultInterpolatedStringHandler = new DefaultInterpolatedStringHandler(2, 3);
defaultInterpolatedStringHandler.AppendFormatted(s2);
defaultInterpolatedStringHandler.AppendLiteral(" ");
defaultInterpolatedStringHandler.AppendFormatted(s3);
defaultInterpolatedStringHandler.AppendLiteral(" ");
defaultInterpolatedStringHandler.AppendFormatted(42);
s1 = string.Concat(text, defaultInterpolatedStringHandler.ToStringAndClear());
return s1;
}
}
```
While a developer could rewrite the code to better handle this, it'd be helpful if the compiler could instead optimize it to the equivalent of if the developer had written:
```C#
public class C
{
public string M2(string s1, string s2, string s3)
{
s1 = $"{s1}{s2} {s3} {42}";
return s1;
}
}
```
such that it would generate the equivalent of:
```C#
public class C
{
public string M2(string s1, string s2, string s3)
{
DefaultInterpolatedStringHandler defaultInterpolatedStringHandler = new DefaultInterpolatedStringHandler(2, 4);
defaultInterpolatedStringHandler.AppendLiteral(s1);
defaultInterpolatedStringHandler.AppendFormatted(s2);
defaultInterpolatedStringHandler.AppendLiteral(" ");
defaultInterpolatedStringHandler.AppendFormatted(s3);
defaultInterpolatedStringHandler.AppendLiteral(" ");
defaultInterpolatedStringHandler.AppendFormatted(42);
return defaultInterpolatedStringHandler.ToStringAndClear();
}
}
```

Contributor guide

Open the contributing guide

Research direction

The issue names no source files, tests, or entry points. Start by locating the C# lowering and optimization coverage for interpolated strings, then compare the M1 and M2 examples; done means combining the explicit concatenation with the interpolated-string handler so the generated code matches the single-handler equivalent shown.

Written by the indexing model from the issue text.

Assessment

Tech stack
csharp
Domain
compilers, performance
Issue type
Feature
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.