Skip to content

While applying lifting for operators involving ref structs, compiler can silently construct invalid Nullable types.  #56646

@AlekseyTs

Description

@AlekseyTs
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.

Metadata

Metadata

Assignees

Labels

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions