Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CS8602: Incorrect nullable flow analysis for indirect null check #49653

Closed
tom-englert opened this issue Nov 29, 2020 · 17 comments
Closed

CS8602: Incorrect nullable flow analysis for indirect null check #49653

tom-englert opened this issue Nov 29, 2020 · 17 comments
Labels
Area-Compilers Resolution-By Design The behavior reported in the issue matches the current design untriaged Issues and PRs which have not yet been triaged by a lead

Comments

@tom-englert
Copy link

Microsoft Visual Studio Professional 2019
Version 16.8.2

Steps to Reproduce:

public void Method(object? a) 
{
    var b = a?.ToString();

    if (b == null)
        return;

    // If b is not null, a can't be null here, but a CS8602 is shown:
    var c = a.ToString();
}

Expected Behavior:
No warning in var c = a.ToString();

Actual Behavior:
CS8602

@Dotnet-GitSync-Bot Dotnet-GitSync-Bot added Area-Compilers untriaged Issues and PRs which have not yet been triaged by a lead labels Nov 29, 2020
@Youssef1313
Copy link
Member

Duplicate of #48354, which was closed as by-design.

@tom-englert
Copy link
Author

@Youssef1313 no, this one is different. Compiler can know that a has been checked already in the first line.
It was working fine with https://github.com/microsoft/CodeContracts and R# nullability annotations, but stopped after migrating to Roslyn.

@Youssef1313
Copy link
Member

Then adding @jcouv to have a look.

@RikkiGibson
Copy link
Contributor

This is by design. When you null check a variable, we don't attempt to infer what other variables could have their flow state modified based on that null check.

@RikkiGibson RikkiGibson added the Resolution-By Design The behavior reported in the issue matches the current design label Nov 30, 2020
@tom-englert
Copy link
Author

tom-englert commented Nov 30, 2020

But there IS a null check on a in the first line: a?.ToString(). It's just the flow analysis that goes wrong.
See these variants:

  1. This works: (same as original sample, just not using ?. but explicit if/else.
    string? b;
    if (a == null || (b = a.ToString()) == null) return;
  1. This works:
    if ((a?.ToString()) == null) return;
  1. This does NOT work, despite it's merely the same as 2.:
    string? b;
    if ((b = a?.ToString()) == null) return;

Also as already stated above, any other analyzer claiming to be state of the art and industrial standard (CodeContracts, ReSharper, SonarCube) can do this right.

@jaredpar
Copy link
Member

jaredpar commented Dec 1, 2020

@RikkiGibson and @Youssef1313 are correct that this is behaving as designed. The flow checking engine used by the compiler does not handle cases where the result of a null check is stored in a bool and that bool is used later on in a conditional construct. There have been discussions about changing that in future versions of the language but for now it's not included in the flow analysis.

This works: (same as original sample, just not using ?. but explicit if/else.

This works because it includes a direct check of a in the if and hence is included in our flow analysis checking.

This works:

Same as above.

This does NOT work, despite it's merely the same as 2.:

This is not the same as it involves extra constructs, notably the assignment, that the compiler must include in its flow analysis. Sure it's a case we could add into the analysis but at the moment it's not part of the included set.

@jaredpar jaredpar closed this as completed Dec 1, 2020
@tom-englert
Copy link
Author

@jaredpar I raised this issue because this is not part of the included set.
If we argue like this we can close any issue, just because any issue is a known limitation.
Shouldn't this rather be turned into a feature request?

@jaredpar
Copy link
Member

jaredpar commented Dec 1, 2020

The roslyn repository holds the compiler code base which is the implementation of the language design. At this point the compiler is correctly implementing the language design which does not include this level of requests.

I agree this could be a feature request but it should be a feature request on the language in dotnet/csharplang.

@tom-englert
Copy link
Author

I see, this was the missing information. I'll create a request in that repo.

@tom-englert
Copy link
Author

@jaredpar dotnet/csharplang is only about the language spec - but this is not about a new spec.

@jaredpar
Copy link
Member

jaredpar commented Dec 4, 2020

dotnet/csharplang is about the language spec, features and design alterations to existing features.

@jaredpar
Copy link
Member

jaredpar commented Dec 7, 2020

That is the C# 8 version of the spec, probably want to refer to the 9.0 one

https://github.com/dotnet/csharplang/blob/master/proposals/csharp-9.0/nullable-reference-types-specification.md

@tom-englert
Copy link
Author

OK, only found this related to the problem:

https://github.com/dotnet/csharplang/blob/master/proposals/csharp-9.0/nullable-reference-types-specification.md#member-access

var person = new Person();

// The receiver is a tracked expression hence the member_access of the property 
// is tracked as well 
if (person.FirstName is not null)
{
    Use(person.FirstName);
}

So doesn't this mean it should work?

@tom-englert
Copy link
Author

Or where in this document is written that the flow analysis should not work in that case?

@jaredpar
Copy link
Member

jaredpar commented Dec 8, 2020

Or where in this document is written that the flow analysis should not work in that case?

Specs of this nature are generally focused on discussing the places in which the behavior takes place. Specifically cases in which we will track the null state. The set of cases where we don't are generally not listed because that list is basically infinite. There are a few cases where we have called it out, like array element access, because it's a common misconception by users.

@tom-englert
Copy link
Author

@jaredpar I've created the proposal in issues, but it has been moved to discussions: dotnet/csharplang#4208

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Area-Compilers Resolution-By Design The behavior reported in the issue matches the current design untriaged Issues and PRs which have not yet been triaged by a lead
Projects
None yet
Development

No branches or pull requests

5 participants