Skip to content

Unnecessary defensive copy on readonly struct when performing a constrained call #76288

@hamarb123

Description

@hamarb123

Version Used: sharplab.io

Steps to Reproduce:

Here we go again with another unnessary defensive copy 😆

struct X
{
    private Y a;
    public readonly string W() => a.ToString(); //defensive copy for call to ToString
}

readonly struct Y
{
}

https://sharplab.io/#v2:EYLgtghglgdgNAFxFANgHwM4IE4FcDGCABABoCwAUAN6VF1EAO2UAbhAgKZECaREA3LXoABAMxFsHCABMA9jBQBPIsICMABiIB1ABQBKIgF4AfHwB0AFVkBlHLADm+wRQC+lSpJnylRLHkI8lDSulEA=

Diagnostic Id:

N/A

Expected Behavior:

No defensive copy is emitted for the call to .ToString(), since Y is readonly, and the default implementation provided by valuetype base classes also does not mutate (since they box & run on that, and also just don't mutate anyway, which is guaranteed by III.2.1) & any future overriding ToString implementation would have to be readonly since Y is readonly.

Actual Behavior:

A defensive copy of a is made (see below).

W marked readonly:

    .method public hidebysig 
        instance string W () cil managed 
    {
        .custom instance void [System.Runtime]System.Runtime.CompilerServices.IsReadOnlyAttribute::.ctor() = (
            01 00 00 00
        )
        .custom instance void [System.Runtime]System.Runtime.CompilerServices.NullableContextAttribute::.ctor(uint8) = (
            01 00 01 00 00
        )
        // Method begins at RVA 0x2050
        // Code size 21 (0x15)
        .maxstack 1
        .locals init (
            [0] valuetype Y
        )

        IL_0000: ldarg.0
        IL_0001: ldfld valuetype Y X::a
        IL_0006: stloc.0
        IL_0007: ldloca.s 0
        IL_0009: constrained. Y
        IL_000f: callvirt instance string [System.Runtime]System.Object::ToString()
        IL_0014: ret
    } // end of method X::W

W not marked readonly:

    .method public hidebysig 
        instance string W () cil managed 
    {
        .custom instance void [System.Runtime]System.Runtime.CompilerServices.NullableContextAttribute::.ctor(uint8) = (
            01 00 01 00 00
        )
        // Method begins at RVA 0x2050
        // Code size 18 (0x12)
        .maxstack 8

        IL_0000: ldarg.0
        IL_0001: ldflda valuetype Y X::a
        IL_0006: constrained. Y
        IL_000c: callvirt instance string [System.Runtime]System.Object::ToString()
        IL_0011: ret
    } // end of method X::W

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions