未验证 提交 760f4fd2 编写于 作者: C Charles Stoner 提交者: GitHub

Find explicitly implemented method on base type using CLR comparison (#47251)

上级 412f9a04
...@@ -3,7 +3,6 @@ ...@@ -3,7 +3,6 @@
// See the LICENSE file in the project root for more information. // See the LICENSE file in the project root for more information.
using System; using System;
using System.Collections.Generic;
using System.Collections.Immutable; using System.Collections.Immutable;
using System.Diagnostics; using System.Diagnostics;
using System.Reflection.Metadata; using System.Reflection.Metadata;
...@@ -181,7 +180,7 @@ private static FieldSymbol FindFieldBySignature(TypeSymbol targetTypeSymbol, str ...@@ -181,7 +180,7 @@ private static FieldSymbol FindFieldBySignature(TypeSymbol targetTypeSymbol, str
TypeWithAnnotations fieldType; TypeWithAnnotations fieldType;
if ((object)field != null && if ((object)field != null &&
TypeSymbol.Equals((fieldType = field.TypeWithAnnotations).Type, type, TypeCompareKind.ConsiderEverything2) && TypeSymbol.Equals((fieldType = field.TypeWithAnnotations).Type, type, TypeCompareKind.CLRSignatureCompareOptions) &&
CustomModifiersMatch(fieldType.CustomModifiers, customModifiers)) CustomModifiersMatch(fieldType.CustomModifiers, customModifiers))
{ {
// Behavior in the face of multiple matching signatures is // Behavior in the face of multiple matching signatures is
...@@ -257,7 +256,7 @@ private static bool ParametersMatch(ParameterSymbol candidateParam, TypeMap cand ...@@ -257,7 +256,7 @@ private static bool ParametersMatch(ParameterSymbol candidateParam, TypeMap cand
// CONSIDER: Do we want to add special handling for error types? Right now, we expect they'll just fail to match. // CONSIDER: Do we want to add special handling for error types? Right now, we expect they'll just fail to match.
var substituted = candidateParam.TypeWithAnnotations.SubstituteType(candidateMethodTypeMap); var substituted = candidateParam.TypeWithAnnotations.SubstituteType(candidateMethodTypeMap);
if (!TypeSymbol.Equals(substituted.Type, targetParam.Type, TypeCompareKind.ConsiderEverything2)) if (!TypeSymbol.Equals(substituted.Type, targetParam.Type, TypeCompareKind.CLRSignatureCompareOptions))
{ {
return false; return false;
} }
...@@ -285,7 +284,7 @@ private static bool ReturnTypesMatch(MethodSymbol candidateMethod, TypeMap candi ...@@ -285,7 +284,7 @@ private static bool ReturnTypesMatch(MethodSymbol candidateMethod, TypeMap candi
// CONSIDER: Do we want to add special handling for error types? Right now, we expect they'll just fail to match. // CONSIDER: Do we want to add special handling for error types? Right now, we expect they'll just fail to match.
var substituted = candidateMethodType.SubstituteType(candidateMethodTypeMap); var substituted = candidateMethodType.SubstituteType(candidateMethodTypeMap);
if (!TypeSymbol.Equals(substituted.Type, targetReturnType, TypeCompareKind.ConsiderEverything2)) if (!TypeSymbol.Equals(substituted.Type, targetReturnType, TypeCompareKind.CLRSignatureCompareOptions))
{ {
return false; return false;
} }
......
...@@ -61,7 +61,6 @@ public class CodeGen_DynamicTests : CSharpTestBase ...@@ -61,7 +61,6 @@ public class CodeGen_DynamicTests : CSharpTestBase
#endregion #endregion
#region C# Runtime and System.Core sources #region C# Runtime and System.Core sources
private const string CSharpBinderTemplate = @" private const string CSharpBinderTemplate = @"
...@@ -1068,7 +1067,7 @@ .maxstack 9 ...@@ -1068,7 +1067,7 @@ .maxstack 9
IL_0069: ldarg.0 IL_0069: ldarg.0
IL_006a: ldfld ""T C.<>c__DisplayClass0_0<T>.a"" IL_006a: ldfld ""T C.<>c__DisplayClass0_0<T>.a""
IL_006f: ldarg.0 IL_006f: ldarg.0
IL_0070: ldfld """" IL_0070: ldfld ""dynamic C.<>c__DisplayClass0_0<T>.b""
IL_0075: callvirt ""void System.Action<System.Runtime.CompilerServices.CallSite, System.Type, T, object>.Invoke(System.Runtime.CompilerServices.CallSite, System.Type, T, object)"" IL_0075: callvirt ""void System.Action<System.Runtime.CompilerServices.CallSite, System.Type, T, object>.Invoke(System.Runtime.CompilerServices.CallSite, System.Type, T, object)""
IL_007a: ret IL_007a: ret
} }
......
...@@ -6,7 +6,6 @@ ...@@ -6,7 +6,6 @@
using System.Linq; using System.Linq;
using System.Threading; using System.Threading;
using Microsoft.CodeAnalysis.CSharp.Symbols; using Microsoft.CodeAnalysis.CSharp.Symbols;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.CSharp.Test.Utilities; using Microsoft.CodeAnalysis.CSharp.Test.Utilities;
using Microsoft.CodeAnalysis.Test.Utilities; using Microsoft.CodeAnalysis.Test.Utilities;
using Roslyn.Test.Utilities; using Roslyn.Test.Utilities;
...@@ -2498,5 +2497,218 @@ class OneToOneUnicodeComparer : StringComparer ...@@ -2498,5 +2497,218 @@ class OneToOneUnicodeComparer : StringComparer
Assert.Equal("System.Int32 StringComparer.GetHashCode(System.String obj)", implementation.ToTestDisplayString()); Assert.Equal("System.Int32 StringComparer.GetHashCode(System.String obj)", implementation.ToTestDisplayString());
} }
[Theory]
[CombinatorialData]
[WorkItem(46494, "https://github.com/dotnet/roslyn/issues/46494")]
public void ExplicitImplementationInBaseType_01(bool useCompilationReference)
{
var source0 =
@"#nullable enable
public struct S<T>
{
}
public interface I
{
S<object?> F();
}";
var source1 =
@"#nullable enable
public class A<T> : I where T : class
{
public S<T?> F() => throw null;
S<object?> I.F() => default;
}";
var source2A =
@"#nullable enable
class B<T> : A<T>, I where T : class
{
}";
var source2B =
@"#nullable disable
class B<T> : A<T>, I where T : class
{
}";
var source3 =
@"class Program
{
static void Main()
{
object o = ((I)new B<string>()).F();
System.Console.WriteLine(o);
}
}";
ExplicitImplementationInBaseType(useCompilationReference, source0, source1, source2A, source3, "B", "I.F", "S`1[System.Object]", "S<System.Object?> A<T>.I.F()");
ExplicitImplementationInBaseType(useCompilationReference, source0, source1, source2B, source3, "B", "I.F", "S`1[System.Object]", "S<System.Object?> A<T>.I.F()");
}
[WorkItem(46494, "https://github.com/dotnet/roslyn/issues/46494")]
[Theory]
[InlineData("dynamic", "dynamic", "dynamic", "System.Object", true)]
[InlineData("dynamic", "dynamic", "dynamic", "System.Object", false)]
[InlineData("dynamic", "object", "System.Object", "System.Object", true)]
[InlineData("dynamic", "object", "System.Object", "System.Object", false)]
[InlineData("object", "dynamic", "dynamic", "System.Object", true)]
[InlineData("object", "dynamic", "dynamic", "System.Object", false)]
[InlineData("(int X, int Y)", "(int X, int Y)", "(System.Int32 X, System.Int32 Y)", "System.ValueTuple`2[System.Int32,System.Int32]", true)]
[InlineData("(int X, int Y)", "(int X, int Y)", "(System.Int32 X, System.Int32 Y)", "System.ValueTuple`2[System.Int32,System.Int32]", false)]
[InlineData("nint", "nint", "nint", "System.IntPtr", true)]
[InlineData("nint", "nint", "nint", "System.IntPtr", false)]
// https://github.com/dotnet/roslyn/issues/42500: CopyTypeCustomModifiers() should copy NativeIntegerAttribute
//[InlineData("nint", "System.IntPtr", "System.IntPtr", "System.IntPtr", true)]
//[InlineData("nint", "System.IntPtr", "System.IntPtr", "System.IntPtr", false)]
//[InlineData("System.IntPtr", "nint", "nint", "System.IntPtr", true)]
//[InlineData("System.IntPtr", "nint", "nint", "System.IntPtr", false)]
public void ExplicitImplementationInBaseType_02(string interfaceTypeArg, string baseTypeArg, string expectedTypeArg, string expectedOutput, bool useCompilationReference)
{
var source0 =
$@"public struct S<T>
{{
}}
public interface I
{{
S<{interfaceTypeArg}> F();
}}";
var source1 =
$@"public class A<T> : I
{{
public S<T> F() => throw null;
S<{baseTypeArg}> I.F() => default;
}}";
var source2 =
@"class B<T> : A<T>, I
{
}";
var source3 =
@"class Program
{
static void Main()
{
object o = ((I)new B<string>()).F();
System.Console.WriteLine(o);
}
}";
ExplicitImplementationInBaseType(useCompilationReference, source0, source1, source2, source3, "B", "I.F", $"S`1[{expectedOutput}]", $"S<{expectedTypeArg}> A<T>.I.F()");
}
[Theory]
[CombinatorialData]
[WorkItem(46494, "https://github.com/dotnet/roslyn/issues/46494")]
public void ExplicitImplementationInBaseType_03(bool useCompilationReference)
{
var source0 =
@"#nullable enable
public struct S<T>
{
}
public interface I
{
void F(S<object?> s);
}";
var source1 =
@"#nullable enable
public class A<T> : I
{
public void F(S<T> s) => throw null;
void I.F(S<object?> s) { }
}";
var source2A =
@"#nullable enable
class B<T> : A<T>, I
{
}";
var source2B =
@"#nullable disable
class B<T> : A<T>, I
{
}";
var source3 =
@"class Program
{
static void Main()
{
((I)new B<string>()).F(default);
System.Console.WriteLine(1);
}
}";
ExplicitImplementationInBaseType(useCompilationReference, source0, source1, source2A, source3, "B", "I.F", "1", "void A<T>.I.F(S<System.Object?> s)");
ExplicitImplementationInBaseType(useCompilationReference, source0, source1, source2B, source3, "B", "I.F", "1", "void A<T>.I.F(S<System.Object?> s)");
}
[WorkItem(46494, "https://github.com/dotnet/roslyn/issues/46494")]
[Theory]
[InlineData("dynamic", "dynamic", "dynamic", true)]
[InlineData("dynamic", "dynamic", "dynamic", false)]
[InlineData("dynamic", "object", "System.Object", true)]
[InlineData("dynamic", "object", "System.Object", false)]
[InlineData("object", "dynamic", "dynamic", true)]
[InlineData("object", "dynamic", "dynamic", false)]
[InlineData("(int X, int Y)", "(int X, int Y)", "(System.Int32 X, System.Int32 Y)", true)]
[InlineData("(int X, int Y)", "(int X, int Y)", "(System.Int32 X, System.Int32 Y)", false)]
[InlineData("nint", "nint", "nint", true)]
[InlineData("nint", "nint", "nint", false)]
[InlineData("nint", "System.IntPtr", "System.IntPtr", true)]
[InlineData("nint", "System.IntPtr", "System.IntPtr", false)]
[InlineData("System.IntPtr", "nint", "nint", true)]
[InlineData("System.IntPtr", "nint", "nint", false)]
public void ExplicitImplementationInBaseType_04(string interfaceTypeArg, string baseTypeArg, string expectedTypeArg, bool useCompilationReference)
{
var source0 =
$@"public struct S<T>
{{
}}
public interface I
{{
void F(S<{interfaceTypeArg}> s);
}}";
var source1 =
$@"public class A<T> : I
{{
public void F(S<T> s) => throw null;
void I.F(S<{baseTypeArg}> s) {{ }}
}}";
var source2 =
@"class B<T> : A<T>, I
{
}";
var source3 =
@"class Program
{
static void Main()
{
((I)new B<string>()).F(default);
System.Console.WriteLine(1);
}
}";
ExplicitImplementationInBaseType(useCompilationReference, source0, source1, source2, source3, "B", "I.F", "1", $"void A<T>.I.F(S<{expectedTypeArg}> s)");
}
private void ExplicitImplementationInBaseType(
bool useCompilationReference,
string source0,
string source1,
string source2,
string source3,
string derivedTypeName,
string interfaceMemberName,
string expectedOutput,
string expectedImplementingMember)
{
var comp = CreateCompilation(source0);
var ref0 = AsReference(comp, useCompilationReference);
comp = CreateCompilation(source1, references: new[] { ref0 });
var ref1 = AsReference(comp, useCompilationReference);
comp = CreateCompilation(new[] { source2, source3 }, references: new[] { ref0, ref1 }, options: TestOptions.ReleaseExe);
CompileAndVerify(comp, expectedOutput: expectedOutput);
var derivedType = comp.GetMember<SourceNamedTypeSymbol>(derivedTypeName);
Assert.True(derivedType.GetSynthesizedExplicitImplementations(cancellationToken: default).IsEmpty);
var interfaceMember = comp.GetMember<MethodSymbol>(interfaceMemberName);
var implementingMember = derivedType.FindImplementationForInterfaceMember(interfaceMember);
Assert.Equal(expectedImplementingMember, implementingMember.ToTestDisplayString());
}
} }
} }
...@@ -149,7 +149,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols.Metadata.PE ...@@ -149,7 +149,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols.Metadata.PE
For Each member In targetTypeSymbol.GetMembers(targetMemberName) For Each member In targetTypeSymbol.GetMembers(targetMemberName)
Dim field = TryCast(member, FieldSymbol) Dim field = TryCast(member, FieldSymbol)
If field IsNot Nothing AndAlso If field IsNot Nothing AndAlso
TypeSymbol.Equals(field.Type, type, TypeCompareKind.ConsiderEverything) AndAlso TypeSymbol.Equals(field.Type, type, TypeCompareKind.AllIgnoreOptionsForVB) AndAlso
CustomModifiersMatch(field.CustomModifiers, customModifiers) Then CustomModifiersMatch(field.CustomModifiers, customModifiers) Then
' Behavior in the face of multiple matching signatures is ' Behavior in the face of multiple matching signatures is
...@@ -215,7 +215,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols.Metadata.PE ...@@ -215,7 +215,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols.Metadata.PE
End If End If
'CONSIDER: Do we want to add special handling for error types? Right now, we expect they'll just fail to match. 'CONSIDER: Do we want to add special handling for error types? Right now, we expect they'll just fail to match.
If Not TypeSymbol.Equals(candidateParam.Type, targetParam.Type, TypeCompareKind.ConsiderEverything) Then If Not TypeSymbol.Equals(candidateParam.Type, targetParam.Type, TypeCompareKind.AllIgnoreOptionsForVB) Then
Return False Return False
End If End If
...@@ -232,7 +232,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols.Metadata.PE ...@@ -232,7 +232,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols.Metadata.PE
Dim targetReturnType As TypeSymbol = targetReturnParam.Type Dim targetReturnType As TypeSymbol = targetReturnParam.Type
' No special handling for error types. Right now, we expect they'll just fail to match. ' No special handling for error types. Right now, we expect they'll just fail to match.
If Not TypeSymbol.Equals(candidateReturnType, targetReturnType, TypeCompareKind.ConsiderEverything) OrElse candidateMethod.ReturnsByRef <> targetReturnParam.IsByRef Then If Not TypeSymbol.Equals(candidateReturnType, targetReturnType, TypeCompareKind.AllIgnoreOptionsForVB) OrElse candidateMethod.ReturnsByRef <> targetReturnParam.IsByRef Then
Return False Return False
End If End If
......
' Licensed to the .NET Foundation under one or more agreements.
' The .NET Foundation licenses this file to you under the MIT license.
' See the LICENSE file in the project root for more information.
Imports Microsoft.CodeAnalysis.Test.Extensions
Imports Microsoft.CodeAnalysis.VisualBasic.Symbols
Imports Roslyn.Test.Utilities
Namespace Microsoft.CodeAnalysis.VisualBasic.UnitTests
Public Class InterfaceImplementationTests
Inherits BasicTestBase
<Theory>
<CombinatorialData>
<WorkItem(46494, "https://github.com/dotnet/roslyn/issues/46494")>
Public Sub ExplicitImplementationInBaseType_01(useCompilationReference As Boolean)
Dim source0 =
"Public Structure S(Of T)
End Structure
Public Interface I
Function F() As S(Of (X As Integer, Y As Integer))
End Interface"
Dim source1 =
"Public Class A(Of T)
Implements I
Public Function F() As S(Of T)
Return Nothing
End Function
Private Function I_F() As S(Of (X As Integer, Y As Integer)) Implements I.F
Return Nothing
End Function
End Class"
Dim source2 =
"Class B(Of T)
Inherits A(Of T)
Implements I
End Class"
Dim source3 =
"Class Program
Shared Sub Main()
Dim i As I = New B(Of String)()
Dim o = i.F()
System.Console.WriteLine(o)
End Sub
End Class"
ExplicitImplementationInBaseType(useCompilationReference, source0, source1, source2, source3, "B", "I.F", "S`1[System.ValueTuple`2[System.Int32,System.Int32]]", "Function A(Of T).I_F() As S(Of (X As System.Int32, Y As System.Int32))")
End Sub
<Theory>
<CombinatorialData>
<WorkItem(46494, "https://github.com/dotnet/roslyn/issues/46494")>
Public Sub ExplicitImplementationInBaseType_02(useCompilationReference As Boolean)
Dim source0 =
"Public Structure S(Of T)
End Structure
Public Interface I
Sub F(s As S(Of (X As Integer, Y As Integer)))
End Interface"
Dim source1 =
"Public Class A(Of T)
Implements I
Public Sub F(s As S(Of T))
End Sub
Private Sub I_F(s As S(Of (X As Integer, Y As Integer))) Implements I.F
End Sub
End Class"
Dim source2 =
"Class B(Of T)
Inherits A(Of T)
Implements I
End Class"
Dim source3 =
"Class Program
Shared Sub Main()
Dim i As I = New B(Of String)()
i.F(Nothing)
System.Console.WriteLine(1)
End Sub
End Class"
ExplicitImplementationInBaseType(useCompilationReference, source0, source1, source2, source3, "B", "I.F", "1", "Sub A(Of T).I_F(s As S(Of (X As System.Int32, Y As System.Int32)))")
End Sub
Private Sub ExplicitImplementationInBaseType(
useCompilationReference As Boolean,
source0 As String,
source1 As String,
source2 As String,
source3 As String,
derivedTypeName As String,
interfaceMemberName As String,
expectedOutput As String,
expectedImplementingMember As String)
Dim comp = CreateCompilation(source0)
Dim ref0 = AsReference(comp, useCompilationReference)
comp = CreateCompilation(source1, references:={ref0})
Dim ref1 = AsReference(comp, useCompilationReference)
comp = CreateCompilation({source2, source3}, references:={ref0, ref1}, options:=TestOptions.ReleaseExe)
CompileAndVerify(comp, expectedOutput:=expectedOutput)
Dim derivedType = comp.GetMember(Of SourceNamedTypeSymbol)(derivedTypeName)
Dim interfaceMember = comp.GetMember(Of MethodSymbol)(interfaceMemberName)
Dim implementingMember = derivedType.FindImplementationForInterfaceMember(interfaceMember)
Assert.Equal(expectedImplementingMember, implementingMember.ToTestDisplayString())
End Sub
End Class
End Namespace
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册