dotnet / roslyn

The Roslyn .NET compiler provides C# and Visual Basic languages with rich code analysis APIs.
https://docs.microsoft.com/dotnet/csharp/roslyn-sdk/
MIT License
19.06k stars 4.04k forks source link

! on nullable argument should suppress subsequent CS8602 #37071

Closed drewnoakes closed 5 years ago

drewnoakes commented 5 years ago

Version Used: 3.3.0-beta1-19327-04

Steps to Reproduce:

bool _initialised;

void M()
{
    _initialised = true;

    object? service = GetService();

    EnsuresNotNull(service!); // ! should indicate 'service' is not null below

    service.ToString();
//  ^^^^^^^ CS8602
}

object? GetService() => _initialised ? "" : null;

void EnsuresNotNull<T>(T t) where T : class
{
    if (t is null)
        throw new ArgumentNullException();
}

It seems we don't have a way of annotating EnsuresNotNull to say that it throws if its argument is null (DoesNotReturnIf in #36810 gets close).

In the absence of that, I'd be happy to ! arguments to such guard methods. It feels consistent and local. It'll also be easy to regex out of code later if I'm able to annotate the guard function in future.

jcouv commented 5 years ago

The recommended way of doing this is Debug.Assert(service != null);. The current behavior is by-design: the suppression (service!) returns a value with a non-null state, but does not change the known state of the variable service.

RikkiGibson commented 5 years ago

Ideally the method EnsuresNotNull could be annotated EnsuresNotNull([NotNull] object? param) to tell the compiler that "if the method returns, the argument is not-null".

jcouv commented 5 years ago

I'll go ahead and close this issue as by-design. Here's the relevant section of the spec. It's probably captured in the LDM notes for nullability as well, but I couldn't find which one from a quick look.