Skip to content

Commit e8567ea

Browse files
committed
Learn from comparisons to non-constant, non-null values
1 parent 946a943 commit e8567ea

2 files changed

Lines changed: 33 additions & 7 deletions

File tree

src/Compilers/CSharp/Portable/FlowAnalysis/NullableWalker.cs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2043,11 +2043,11 @@ protected override void AfterLeftChildHasBeenVisited(BoundBinaryOperator binary)
20432043

20442044
// learn from non-null constant
20452045
BoundExpression operandComparedToNonNull = null;
2046-
if (isNonNullConstant(binary.Left))
2046+
if (leftType.IsNotNull && rightType.MayBeNull && binary.Right.ConstantValue?.IsNull != true)
20472047
{
20482048
operandComparedToNonNull = binary.Right;
20492049
}
2050-
else if (isNonNullConstant(binary.Right))
2050+
else if (leftType.MayBeNull && binary.Left.ConstantValue?.IsNull != true && rightType.IsNotNull)
20512051
{
20522052
operandComparedToNonNull = binary.Left;
20532053
}
@@ -2249,6 +2249,12 @@ private void LearnFromNonNullTest(int slot, ref LocalState state)
22492249

22502250
private int LearnFromNullTest(BoundExpression expression, ref LocalState state)
22512251
{
2252+
// nothing to learn about a constant
2253+
if (expression.ConstantValue != null)
2254+
{
2255+
return -1;
2256+
}
2257+
22522258
var expressionWithoutConversion = RemoveConversion(expression, includeExplicitConversions: true).expression;
22532259
var slot = MakeSlot(expressionWithoutConversion);
22542260
return LearnFromNullTest(slot, expressionWithoutConversion.Type, ref state);

src/Compilers/CSharp/Test/Semantic/Semantics/NullableReferenceTypesTests.cs

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21867,18 +21867,15 @@ void M(Delegate d, string? s)
2186721867
{
2186821868
if (s != string.Empty) s.ToString(); // warn
2186921869
d.BeginInvoke(s, null, null);
21870-
s.ToString(); // warn 2
21870+
s.ToString();
2187121871
}
2187221872
}
2187321873
", NotNullAttributeDefinition }, options: WithNonNullTypesTrue());
2187421874

2187521875
c.VerifyDiagnostics(
2187621876
// (8,32): warning CS8602: Dereference of a possibly null reference.
2187721877
// if (s != string.Empty) s.ToString(); // warn
21878-
Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "s").WithLocation(8, 32),
21879-
// (10,9): warning CS8602: Dereference of a possibly null reference.
21880-
// s.ToString(); // warn 2
21881-
Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "s").WithLocation(10, 9)
21878+
Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "s").WithLocation(8, 32)
2188221879
);
2188321880
}
2188421881

@@ -95651,6 +95648,29 @@ public Box(T value) { }
9565195648
Diagnostic(ErrorCode.ERR_BadBinaryOps, "x == null").WithArguments("==", "T", "<null>").WithLocation(53, 13));
9565295649
}
9565395650

95651+
[Fact, WorkItem(34942, "https://github.com/dotnet/roslyn/issues/34942")]
95652+
public void ConditionalExpression_InferredNullability()
95653+
{
95654+
var source =
95655+
@"#nullable enable
95656+
using System;
95657+
95658+
public class Program
95659+
{
95660+
static void Main()
95661+
{
95662+
string? value = ""42"";
95663+
int count = 84;
95664+
if (value?.Length == count)
95665+
{
95666+
Console.WriteLine(value.Length);
95667+
}
95668+
}
95669+
}";
95670+
var comp = CreateCompilation(source);
95671+
comp.VerifyDiagnostics();
95672+
}
95673+
9565495674
[Fact, WorkItem(35075, "https://github.com/dotnet/roslyn/issues/35075")]
9565595675
public void ConditionalExpression_TypeParameterConstrainedToNullableValueType()
9565695676
{

0 commit comments

Comments
 (0)