From 03e7af9588442925ecdf6e166be50b71487765ad Mon Sep 17 00:00:00 2001 From: Jan Jones Date: Tue, 1 Sep 2026 10:06:39 +0200 Subject: [PATCH 1/2] Visit left operand conversion in a fast path of nullable analysis --- .../Portable/FlowAnalysis/NullableWalker.cs | 17 +++++++++++++++++ .../Semantics/NullableReferenceTypesTests.cs | 16 ++++++++++++++++ 2 files changed, 33 insertions(+) diff --git a/src/Compilers/CSharp/Portable/FlowAnalysis/NullableWalker.cs b/src/Compilers/CSharp/Portable/FlowAnalysis/NullableWalker.cs index ed81df1a5cee2..4cd27376935f2 100644 --- a/src/Compilers/CSharp/Portable/FlowAnalysis/NullableWalker.cs +++ b/src/Compilers/CSharp/Portable/FlowAnalysis/NullableWalker.cs @@ -5565,6 +5565,23 @@ bool learnFromConditionalAccessOrBoolConstant() else if (binary.Left.ConstantValueOpt is { IsBoolean: true } leftConstant) { Unsplit(); + + // The left operand was visited without its stripped conversion. + if (binary.Left is BoundConversion leftConversionNode && leftConversionNode != leftOperand) + { + Debug.Assert(leftConversionNode.Type is not null); + VisitConversion( + leftConversionNode, + leftOperand, + leftConversion, + TypeWithAnnotations.Create(leftConversionNode.Type), + leftResult, + checkConversion: true, + fromExplicitCast: false, + useLegacyWarnings: false, + AssignmentKind.Argument); + } + Visit(binary.Right); UseRvalueOnly(binary.Right); if (IsConditionalState && isEquals(binary) != leftConstant.BooleanValue) diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/NullableReferenceTypesTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/NullableReferenceTypesTests.cs index 96cf7f4132270..9793e26f4dc81 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/NullableReferenceTypesTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/NullableReferenceTypesTests.cs @@ -51746,6 +51746,22 @@ public void M4(C? c, string? x) ); } + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/84642")] + public void EqualsBoolConstant_DefaultLiteral() + { + var source = """ + class C + { + static bool M() + { + return default != true; + } + } + """; + + CreateNullableCompilation(source).VerifyEmitDiagnostics(); + } + [Fact] public void EqualsBoolConstant_UserDefinedOperator_BoolRight() { From f21e1e7e73093f9846d5e2ddd625f4da809efa46 Mon Sep 17 00:00:00 2001 From: Jan Jones Date: Thu, 3 Sep 2026 09:36:45 +0200 Subject: [PATCH 2/2] Remove unnecessary assert --- src/Compilers/CSharp/Portable/FlowAnalysis/NullableWalker.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Compilers/CSharp/Portable/FlowAnalysis/NullableWalker.cs b/src/Compilers/CSharp/Portable/FlowAnalysis/NullableWalker.cs index 4cd27376935f2..ec15414de3d2d 100644 --- a/src/Compilers/CSharp/Portable/FlowAnalysis/NullableWalker.cs +++ b/src/Compilers/CSharp/Portable/FlowAnalysis/NullableWalker.cs @@ -5569,7 +5569,6 @@ bool learnFromConditionalAccessOrBoolConstant() // The left operand was visited without its stripped conversion. if (binary.Left is BoundConversion leftConversionNode && leftConversionNode != leftOperand) { - Debug.Assert(leftConversionNode.Type is not null); VisitConversion( leftConversionNode, leftOperand,