Unnecessary defensive copy on readonly struct
when performing a constrained call #76288
Open
Description
opened on Dec 5, 2024
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
{
}
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
Activity