diff --git a/src/Compilers/CSharp/Portable/Symbols/MemberSignatureComparer.cs b/src/Compilers/CSharp/Portable/Symbols/MemberSignatureComparer.cs index 7d6646049238..f7034dd3d1c8 100644 --- a/src/Compilers/CSharp/Portable/Symbols/MemberSignatureComparer.cs +++ b/src/Compilers/CSharp/Portable/Symbols/MemberSignatureComparer.cs @@ -312,7 +312,7 @@ internal sealed class MemberSignatureComparer : IEqualityComparer considerReturnType: true, considerTypeConstraints: false, considerCallingConvention: true, - refKindCompareMode: RefKindCompareMode.ConsiderDifferences, + refKindCompareMode: RefKindCompareMode.ConsiderDifferences | RefKindCompareMode.AllowRefReadonlyVsInMismatch, typeComparison: TypeCompareKind.IgnoreDynamicAndTupleNames | TypeCompareKind.IgnoreNullableModifiersForReferenceTypes | TypeCompareKind.IgnoreNativeIntegers); //if it was a true explicit impl, we expect it to remain so after retargeting /// diff --git a/src/Compilers/CSharp/Test/Emit2/Semantics/RefReadonlyParameterTests.cs b/src/Compilers/CSharp/Test/Emit2/Semantics/RefReadonlyParameterTests.cs index 2190adc3934f..38010575c15a 100644 --- a/src/Compilers/CSharp/Test/Emit2/Semantics/RefReadonlyParameterTests.cs +++ b/src/Compilers/CSharp/Test/Emit2/Semantics/RefReadonlyParameterTests.cs @@ -5,6 +5,7 @@ using System; using System.Linq; using Microsoft.CodeAnalysis.CSharp.Symbols; +using Microsoft.CodeAnalysis.CSharp.Symbols.Retargeting; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.CSharp.Test.Utilities; using Microsoft.CodeAnalysis.Test.Utilities; @@ -4606,6 +4607,51 @@ static void Main() Diagnostic(ErrorCode.WRN_OverridingDifferentRefness, "M2").WithArguments("in int x", "ref readonly int x").WithLocation(9, 12)); } + [Theory, CombinatorialData] + public void Implementation_RefReadonly_In_Explicit_Retargeting(bool emit) + { + var source1v1 = """ + public interface I + { + void M(in int x); + } + """; + var comp1v1 = CreateCompilation(source1v1, assemblyName: "Assembly1"); + var comp1v1Ref = emit ? comp1v1.EmitToImageReference() : comp1v1.ToMetadataReference(); + + var source1v2 = """ + public interface I + { + void M(ref readonly int x); + } + """; + var comp1v2 = CreateCompilation(source1v2, assemblyName: "Assembly1"); + var comp1v2Ref = emit ? comp1v2.EmitToImageReference() : comp1v2.ToMetadataReference(); + + var source2 = """ + public class C : I + { + void I.M(in int x) { } + } + """; + var comp2 = CreateCompilation(source2, new[] { comp1v1Ref }, assemblyName: "Assembly2"); + var comp2Ref = emit ? comp2.EmitToImageReference() : comp2.ToMetadataReference(); + + var comp3v1 = CreateCompilation("", new[] { comp2Ref, comp1v1Ref }, assemblyName: "Assembly3"); + + var c1 = comp3v1.GetMember("C"); + var m1 = c1.GetMember("I.M"); + Assert.True(m1 is not RetargetingMethodSymbol); + Assert.Equal("I.M(in int)", m1.ExplicitInterfaceImplementations.Single().ToDisplayString()); + + var comp3v2 = CreateCompilation("", new[] { comp2Ref, comp1v2Ref }, assemblyName: "Assembly3"); + + var c2 = comp3v2.GetMember("C"); + var m2 = c2.GetMember("I.M"); + Assert.Equal(!emit, m2 is RetargetingMethodSymbol); + Assert.Equal("I.M(ref readonly int)", m2.ExplicitInterfaceImplementations.Single().ToDisplayString()); + } + [Fact] public void Implementation_RefReadonly_In_Indexer() {