diff --git a/src/Compilers/CSharp/Portable/FlowAnalysis/NullableWalker.cs b/src/Compilers/CSharp/Portable/FlowAnalysis/NullableWalker.cs index 2ef8a8f7ad491..4643ad1cb71e0 100644 --- a/src/Compilers/CSharp/Portable/FlowAnalysis/NullableWalker.cs +++ b/src/Compilers/CSharp/Portable/FlowAnalysis/NullableWalker.cs @@ -3160,11 +3160,18 @@ void visitOperandConversion( ParameterSymbol parameter, TypeWithState operandType) { + TypeWithAnnotations targetTypeWithNullability = parameter.TypeWithAnnotations; + + if (isLifted && targetTypeWithNullability.Type.IsNonNullableValueType()) + { + targetTypeWithNullability = TypeWithAnnotations.Create(MakeNullableOf(targetTypeWithNullability)); + } + _ = VisitConversion( expr as BoundConversion, operand, conversion, - parameter.TypeWithAnnotations, + targetTypeWithNullability, operandType, checkConversion: true, fromExplicitCast: false, @@ -7581,7 +7588,8 @@ private void ReportNullabilityMismatchInArgument(SyntaxNode argument, TypeSymbol private void ReportNullabilityMismatchInArgument(Location argument, TypeSymbol argumentType, ParameterSymbol parameterOpt, TypeSymbol parameterType, bool forOutput) { ReportDiagnostic(forOutput ? ErrorCode.WRN_NullabilityMismatchInArgumentForOutput : ErrorCode.WRN_NullabilityMismatchInArgument, - argument, argumentType, parameterType, + argument, argumentType, + parameterOpt?.Type.IsNonNullableValueType() == true && parameterType.IsNullableType() ? parameterOpt.Type : parameterType, // Compensate for operator lifting GetParameterAsDiagnosticArgument(parameterOpt), GetContainingSymbolAsDiagnosticArgument(parameterOpt)); } diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/NullableReferenceTypesTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/NullableReferenceTypesTests.cs index f5ff53e45930f..3a2e7f4a19ae6 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/NullableReferenceTypesTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/NullableReferenceTypesTests.cs @@ -121902,6 +121902,92 @@ static void M( comp.VerifyDiagnostics(); } + [Fact] + [WorkItem(35057, "https://github.com/dotnet/roslyn/issues/39361")] + public void Operator_11() + { + var source = +@" +#nullable enable + +using System; + +struct S +{ + public static implicit operator DateTime?(S? value) => default; + + bool M1(S? x1, DateTime y1) + { + return x1 == y1; + } + + bool M2(DateTime? x2, DateTime y2) + { + return x2 == y2; + } + + bool M3(DateTime x3, DateTime? y3) + { + return x3 == y3; + } + + bool M4(DateTime x4, S? y4) + { + return x4 == y4; + } + + bool M5(DateTime? x5, DateTime? y5) + { + return x5 == y5; + } + + bool M6(S? x6, DateTime? y6) + { + return x6 == y6; + } + + bool M7(DateTime? x7, S? y7) + { + return x7 == y7; + } + + bool M8(DateTime x8, S y8) + { + return x8 == y8; + } + + bool M9(S x9, DateTime y9) + { + return x9 == y9; + } +} +"; + var comp = CreateCompilation(source); + comp.VerifyDiagnostics(); + } + + [Fact] + [WorkItem(35057, "https://github.com/dotnet/roslyn/issues/39361")] + public void Operator_12() + { + var source = +@" +#nullable enable + +struct S +{ + public static bool operator-(S value) => default; + + bool? M1(S? x1) + { + return -x1; + } +} +"; + var comp = CreateCompilation(source); + comp.VerifyDiagnostics(); + } + [Theory] [InlineData("object.Equals")] [InlineData("object.ReferenceEquals")]