Skip to content

Consider special-casing Interlocked.Exchange and friends for nullable inference #51191

@stephentoub

Description

@stephentoub

Version Used:
2d3ffe0

Description
One semi-common pattern when using Interlocked.Exchange and friends when using it to rent some shared object is to first check whether the field is null to avoid the overhead of the interlocked operation if it's unlikely to succeed:

if (field is not null)
    ... = Interlocked.Exchange(ref field, null);

Because of that upfront null check, however, the C# compiler's nullable inference then infers the type of the field as being non-nullable rather than nullable, and thus warns that the null being used in the Exchange can't be converted to a non-null value. This is easily worked around by specifying the type parameter to Exchange explicitly, but it seems like we may want to special-case threading-focused APIs like Exchange to opt-out of this inference.

It's of course possible that'll lead to other warts, though, so if this is too niche, feel free to close.

Steps to Reproduce:

#nullable enable

using System;
using System.Threading;

public class C {
    private C? _obj;
    
    public void Rent()
    {
        if (_obj is not null)
        {
            C? o = Interlocked.Exchange(ref _obj, null);
            if (o is not null)
            {
                Use(o);
            }
        }
    }
    
    private void Use(C o) {}
}

https://sharplab.io/#v2:EYLgtghgzgLgpgJwD4GIB2BXANliwtwAEcaeBAsAFBUACATAIy0AMhNDAdACoAWCcEACYBLNAHMA3FVoBmNnUIBhQgG8qhDYQAOCYQDcI8JQH5CAfQD2wAFZTKmwus005NACyEASiRgAKAJROGmr2DprCAGaEvpY2hMJQhGgWMEnYWIGhYapB2ZqKphaEALyEAJJo8AhYFgDGANZwghwAogAetTwQ4nC+/FGx1gA0aTj+dnlhkdFFCUkpoxm5kyGTkwCqUL0W48t5AL57GodZhCcOuTr6hkTuhJu9yjuqJ/tAA==

Expected Behavior:
No warnings

Actual Behavior:
warning CS8625: Cannot convert null literal to non-nullable reference type.

cc: @jcouv

Metadata

Metadata

Assignees

Type

No type
No fields configured for issues without a type.

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions