Skip to content

Better optimizations around combining string concatenation and string interpolation #73736

@stephentoub

Description

@stephentoub

I've recently seen a fair amount of code that involves expressions like:

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:

public class C
{
    public string M1(string s1, string s2, string s3)
    {
        s1 += $"{s2} {s3}";
        return s1;
    }
}

generates the equivalent of:

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.

public class C
{
    public string M2(string s1, string s2, string s3)
    {
        s1 += $"{s2} {s3} {42}";
        return s1;
    }
}

generates the equivalent of:

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:

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:

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();
    }
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    Area-CompilersBugCode Gen QualityRoom for improvement in the quality of the compiler's generated code

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions