partial class Test
{
static void Main(){}
void Test1()
{
var x = new S1();
int? y = 1;
((x + y) + new S2())?.M();
}
}
public readonly ref struct S1
{
public static S1 operator+ (S1 x, int y) => throw null;
}
struct S2
{
public static S2 operator+ (S1 x, S2 y) => default;
public void M() {}
}
Observed: Instances of Nullable<S1> are created:
.method private hidebysig
instance void Test1 () cil managed
{
// Method begins at RVA 0x2054
// Code size 141 (0x8d)
.maxstack 2
.locals init (
[0] valuetype S1 x,
[1] valuetype [System.Private.CoreLib]System.Nullable`1<int32> y,
[2] valuetype [System.Private.CoreLib]System.Nullable`1<valuetype S1>,
[3] valuetype S1,
[4] valuetype [System.Private.CoreLib]System.Nullable`1<int32>,
[5] valuetype [System.Private.CoreLib]System.Nullable`1<valuetype S1>,
[6] valuetype [System.Private.CoreLib]System.Nullable`1<valuetype S2>,
[7] valuetype S2
)
IL_0000: nop
IL_0001: ldloca.s 0
IL_0003: initobj S1
IL_0009: ldloca.s 1
IL_000b: ldc.i4.1
IL_000c: call instance void valuetype [System.Private.CoreLib]System.Nullable`1<int32>::.ctor(!0)
IL_0011: ldloc.0
IL_0012: stloc.3
IL_0013: ldloc.1
IL_0014: stloc.s 4
IL_0016: ldloca.s 4
IL_0018: call instance bool valuetype [System.Private.CoreLib]System.Nullable`1<int32>::get_HasValue()
IL_001d: brtrue.s IL_002b
IL_001f: ldloca.s 5
IL_0021: initobj valuetype [System.Private.CoreLib]System.Nullable`1<valuetype S1>
IL_0027: ldloc.s 5
IL_0029: br.s IL_003d
IL_002b: ldloc.3
IL_002c: ldloca.s 4
IL_002e: call instance !0 valuetype [System.Private.CoreLib]System.Nullable`1<int32>::GetValueOrDefault()
IL_0033: call valuetype S1 S1::op_Addition(valuetype S1, int32)
IL_0038: newobj instance void valuetype [System.Private.CoreLib]System.Nullable`1<valuetype S1>::.ctor(!0)
IL_003d: stloc.2
IL_003e: ldloca.s 2
IL_0040: call instance bool valuetype [System.Private.CoreLib]System.Nullable`1<valuetype S1>::get_HasValue()
IL_0045: brtrue.s IL_0053
IL_0047: ldloca.s 6
IL_0049: initobj valuetype [System.Private.CoreLib]System.Nullable`1<valuetype S2>
IL_004f: ldloc.s 6
IL_0051: br.s IL_006e
IL_0053: ldloca.s 2
IL_0055: call instance !0 valuetype [System.Private.CoreLib]System.Nullable`1<valuetype S1>::GetValueOrDefault()
IL_005a: ldloca.s 7
IL_005c: initobj S2
IL_0062: ldloc.s 7
IL_0064: call valuetype S2 S2::op_Addition(valuetype S1, valuetype S2)
IL_0069: newobj instance void valuetype [System.Private.CoreLib]System.Nullable`1<valuetype S2>::.ctor(!0)
IL_006e: stloc.s 6
IL_0070: ldloca.s 6
IL_0072: dup
IL_0073: call instance bool valuetype [System.Private.CoreLib]System.Nullable`1<valuetype S2>::get_HasValue()
IL_0078: brtrue.s IL_007d
IL_007a: pop
IL_007b: br.s IL_008c
IL_007d: call instance !0 valuetype [System.Private.CoreLib]System.Nullable`1<valuetype S2>::GetValueOrDefault()
IL_0082: stloc.s 7
IL_0084: ldloca.s 7
IL_0086: call instance void S2::M()
IL_008b: nop
IL_008c: ret
} // end of method Test::Test1
Expected:
A compilation error because ref structs cannot be used as type arguments.
Even if compiler manages to optimize away nullable instances in emitted code at the end, presence of conversions to Nullable in the bound tree after initial binding is likely to "disable" ref safety checks.
Observed: Instances of
Nullable<S1>are created:Expected:
A compilation error because ref structs cannot be used as type arguments.
Even if compiler manages to optimize away nullable instances in emitted code at the end, presence of conversions to Nullable in the bound tree after initial binding is likely to "disable" ref safety checks.