roslyn: IDE0045 produced code causes compiler to flag a nullable dereference that won't happen

Version Used: 4.3.0-3.22401.3+41ae77386c335929113f61d6f51f2663d2780443

Steps to Reproduce:

public static void TestMethod(Test? test)
    {
        if (test != null && test.Field == null)
        {
            test.Field = string.Empty;
        }
        else
        {
            throw new InvalidOperationException();
        }
    }

    public class Test
    {
        public string? Field;
    }

Expected Behavior:

No IDE0045 suggestion

Actual Behavior:

public static void TestMethod(Test? test)
    {
        // CS8602 Dereference of a possibly null reference
        test.Field = test != null && test.Field == null ? string.Empty : throw new InvalidOperationException();
    }

    public class Test
    {
        public string? Field;
    }

About this issue

  • Original URL
  • State: open
  • Created 2 years ago
  • Comments: 33 (32 by maintainers)

Most upvoted comments

@MadsTorgersen

We should note this, live with it and move on.

This sounds good to me.

it isn’t clear that the compiler’s behavior is consistent

I am not sure I agree with that. I think the behavior is consistent. If the target of an assignment is a field reference, its receiver is evaluated before the right hand side is evaluated, but is not dereferenced until we execute the store command. It is the store command that actually dereferences the receiver, we are not doing that explicitly.

The current implementation is a bug

In my opinion, this is a small deviation from the spec, rather than a bug. It is really not obvious what does it mean to evaluate a field reference when it is a target of an assignment. I also think that it should be relatively easy to adjust the spec to clarify the behavior - receivers of the target are dereferenced in the process of the store operation. This affects properties and probably array elements too.

@AlekseyTs sure. I just wanted to report incorrect behavior, didn’t expected it to escalate to this level 😄

Shouldn’t there be a check that Nested is not null too?

The NRE is not on Nested, it’s on test.

Agreed. This looks like a flow problem. Either we go into the true-branch (in which case we should have learned that test is not-null, or we go into the false-branch, in which case the end point is not reachable.