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

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

上级 412f9a04
......@@ -3,7 +3,6 @@
// See the LICENSE file in the project root for more information.
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics;
using System.Reflection.Metadata;
......@@ -181,7 +180,7 @@ private static FieldSymbol FindFieldBySignature(TypeSymbol targetTypeSymbol, str
TypeWithAnnotations fieldType;
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))
{
// Behavior in the face of multiple matching signatures is
......@@ -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.
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;
}
......@@ -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.
var substituted = candidateMethodType.SubstituteType(candidateMethodTypeMap);
if (!TypeSymbol.Equals(substituted.Type, targetReturnType, TypeCompareKind.ConsiderEverything2))
if (!TypeSymbol.Equals(substituted.Type, targetReturnType, TypeCompareKind.CLRSignatureCompareOptions))
{
return false;
}
......
......@@ -61,7 +61,6 @@ public class CodeGen_DynamicTests : CSharpTestBase
#endregion
#region C# Runtime and System.Core sources
private const string CSharpBinderTemplate = @"
......@@ -1068,7 +1067,7 @@ .maxstack 9
IL_0069: ldarg.0
IL_006a: ldfld ""T C.<>c__DisplayClass0_0<T>.a""
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_007a: ret
}
......
......@@ -6,7 +6,6 @@
using System.Linq;
using System.Threading;
using Microsoft.CodeAnalysis.CSharp.Symbols;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.CSharp.Test.Utilities;
using Microsoft.CodeAnalysis.Test.Utilities;
using Roslyn.Test.Utilities;
......@@ -2498,5 +2497,218 @@ class OneToOneUnicodeComparer : StringComparer
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
For Each member In targetTypeSymbol.GetMembers(targetMemberName)
Dim field = TryCast(member, FieldSymbol)
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
' Behavior in the face of multiple matching signatures is
......@@ -215,7 +215,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols.Metadata.PE
End If
'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
End If
......@@ -232,7 +232,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols.Metadata.PE
Dim targetReturnType As TypeSymbol = targetReturnParam.Type
' 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
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.
先完成此消息的编辑!
想要评论请 注册