dotnet / dotnet/roslyn

Possible issue with collection-expression-builders and `MemberNotNull` attribute.

Open
#82,029 2 comments 0 reactions 1 assignee Claimed by @RikkiGibson View on GitHub
Area-Compilers Feature - Collection Expressions Feature - Nullable Reference Types
Dominant language
C#
Stars
20.7k
Forks
4.3k
PR merge metrics
PR metrics pending

Description

Repro case:

```c#
#nullable enable
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices;

[CollectionBuilder(typeof(MyBuilder), "Create")]
class MyCollection : List
{
}

static class MyBuilder
{
public static string? Singleton;

[MemberNotNull(nameof(Singleton))]
public static MyCollection Create(bool b, ReadOnlySpan items) => throw null!;
}

static class Other
{
public static string? Singleton;

[MemberNotNull(nameof(Singleton))]
public static void EnsureNotNull() => throw null!;
}

class C
{
static void Main()
{
Other.EnsureNotNull();
Goo(Other.Singleton);

MyCollection list = [with(true)];
Goo(MyBuilder.Singleton);
}

static void Goo(string s) { }
}
```

Warnings:

```
// (14,27): warning CS0649: Field 'MyBuilder.Singleton' is never assigned to, and will always have its default value null
// public static string? Singleton;
// (22,27): warning CS0649: Field 'Other.Singleton' is never assigned to, and will always have its default value null
// public static string? Singleton;
// (36,13): warning CS8604: Possible null reference argument for parameter 's' in 'void C.Goo(string s)'.
// Goo(MyBuilder.Singleton);
```

In this case, despite calling into `MyBuilder.Create` (through the `with(true)` with element) the compiler does not track that MyBuilder.Singleton is now non-null (like it does above with Other.EnsureNotNull/Singleton.

First, this is EXTREMELY esoteric. It is highly unlikely for anyone to ever even hit this case. Second, it may be the case that this is NOT a bug. It really depends on how nullable member tracking is supposed to work these attributes. For example, it may be expected that nullable-tracking only works through some `X.Y.Z.SomeMethod()` call and then access of `X.Y.Z.Member`. In other words, the `X.Y.Z` has to be the same *in the user's written code* for this to count.

In this example, because there's no explicit call to MyBuilder.Create by the user, it may just be the expectation that this is not tracked.

However, if it is deemed to be an actual bug, it is again highly unlikely this need be fixed. This issue simply tracks potential issue in case someone wants to look into it.

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.