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
19k stars 4.03k forks source link

False nullability warnings for delegate conversions #72252

Open TessenR opened 8 months ago

TessenR commented 8 months ago

Version Used:

Microsoft Visual Studio Professional 2022
Version 17.10.0 Preview 1.0
VisualStudio.17.Preview/17.10.0-pre.1.0+34607.79
Microsoft .NET Framework
Version 4.8.09037

Steps to Reproduce:

Compile the following code:

#nullable enable
using System;
using System.Diagnostics.CodeAnalysis;

public class C<T>
{
  void M()
  {
    MyDel d1 = GetT;
    MyDel d2 = new MyDel(GetT);
    MyDel d3 = t => GetT(t); // false CS8621, CS8603
    MyDel d4 = new MyDel(t => GetT(t)); // false CS8621, CS8603
  }

  [return: MaybeNull] delegate T MyDel(T t); 
  [return: MaybeNull] T GetT(T t) => t;
}

sharplab.io

Diagnostic Id:

CS8621, CS8603

Expected Behavior: No warnings in the code above. All the delegate conversions are safe and equivalent to each other

Actual Behavior: False CS8603: Possible null reference return. and CS8621: Nullability of reference types in return type of 'lambda expression' doesn't match the target delegate 'C<T>.MyDel' (possibly because of nullability attributes). are reported for non-method group conversions

RikkiGibson commented 7 months ago

@jcouv I seem to recall a decision that nullability attributes didn't factor into constraint checking, or something like that. Is it possible that a similar decision was made here, for nullability attributes to not factor in to delegate compatibility?

jaredpar commented 7 months ago

@jcouv ?

jcouv commented 6 months ago

Nullability attributes do factor in delegate conversion. Below is an example with conversion of lambda to delegate type. So the example in OP seems a bug. FWIW, the logic lives in CheckValidNullableMethodOverride.

#nullable enable

using System.Diagnostics.CodeAnalysis;

public class C
{
  void M()
  {
    MyDel2<string> d5 = (t) => t; // warning CS8621: Nullability of reference types in return type of 'lambda expression' doesn't match the target delegate 'C<T>.MyDel2<string>' (possibly because of nullability attributes).
    MyDel2<string> d6 = [return: MaybeNull] string (string t) => t;
  }

  [return: MaybeNull] delegate T2 MyDel2<T2>(T2 t); 
}