Missing nullability warning for lambda with multiple ref-returns in `var` local declaration
- Dominant language
- C#
- Stars
- 20.7k
- Forks
- 4.3k
- PR merge metrics
- PR metrics pending
Description
1. The first scenario produces no warning, but there should be a warning on `o2` and one of the `ref` assignments to result of calling `x`. From quick debugging of `NullableWalker.VisitLocalDeclaration`, the problem seems to be that we analyze the lambda using the anonymous delegate from initial binding and so try to convert the return values against the lambda's return type inferred during initial binding (ie. `object~`) instead of a return type accounting for nullability (ie. `object!`).
2. Once the first issue is fixed, we should make sure that we determine the best common type from multiple `ref` returns the same way that we determine it for `ref` ternaries and method type inference with `ref` parameters. We may have a bug there, as `NullableWalker.BestTypeForLambdaReturns` shows that we're using `Join` (in `BestTypeInferrer.GetNullableAnnotation`) even in `ref` return scenarios. This likely should be `EnsureCompatible` (which we use for [merging exact bounds](https://github.com/dotnet/roslyn/blob/main/src/Compilers/CSharp/Portable/Binder/Semantics/OverloadResolution/MethodTypeInference.cs#L2787) in method type inference and for [`ref` ternaries](https://github.com/dotnet/roslyn/pull/74498)).
3. The second scenario produces no warning, but there should be a warning on the dereference of `x`. This seems caused by the same issue (we're not using a nullability-aware inferred type for the local).
Scenario 1:
```
#nullable enable
var x = (bool b, ref object o1, ref object? o2) =>
{
if (b)
{
return ref o1;
}
return ref o2; // bug: missing warning
};
object x1 = new object();
object? x2 = new object();
bool b = true;
x(b, ref x1, ref x2) = null; // bug: missing warning (inferred delegate should return `ref string!` but actually returns `ref string~`)
ref object? y1 = ref x(b, ref x1, ref x2); // bug: missing warning (inferred delegate should return `ref string!` but actually returns `ref string~`)
ref object y2 = ref x(b, ref x1, ref x2);
```
Scenario 2:
```
#nullable enable
var x = (ref object? o) =>
{
return ref o;
};
object? x1 = new object();
x(ref x1).ToString(); // bug: missing warning
```

Contributor guide
Assessment
This issue has not been assessed yet.