diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/FunctionPointerTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/FunctionPointerTests.cs index cd444ddf08469..c283935f2e7b7 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/FunctionPointerTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/FunctionPointerTests.cs @@ -1665,6 +1665,181 @@ public void M2() "); } + [Fact, WorkItem(51037, "https://github.com/dotnet/roslyn/issues/51037")] + public void FunctionPointerGenericSubstitutionCustomModifiersTypesDefinedOnClass() + { + var il = @" +.class public auto ansi beforefieldinit A`1 + extends [mscorlib]System.Object +{ +} +.class public auto ansi beforefieldinit C`6 + extends [mscorlib]System.Object +{ + // Methods + .method public hidebysig static + void M1 ( + method class A`1 modopt(class A`1) & modopt(class A`1) *(class A`1 modopt(class A`1) & modopt(class A`1)) param + ) cil managed + { + ret + } + + .method public hidebysig specialname rtspecialname + instance void .ctor () cil managed + { + ldarg.0 + call instance void [mscorlib]System.Object::.ctor() + nop + ret + } +} +"; + + var source = @" +class Derived : C {} + +class D1 {} +class D2 {} +class D3 {} +class D4 {} +class D5 {} +class D6 {} +"; + + var comp = CreateCompilationWithIL(source, il, options: TestOptions.UnsafeReleaseDll); + comp.VerifyDiagnostics(); + + var derived = comp.GetTypeByMetadataName("Derived"); + var m1 = derived!.BaseTypeNoUseSiteDiagnostics.GetMethod("M1"); + + AssertEx.Equal("void C.M1(delegate*) A modopt(A), ref modopt(A) A modopt(A)> param)", + m1.ToTestDisplayString()); + } + + [Fact, WorkItem(51037, "https://github.com/dotnet/roslyn/issues/51037")] + public void FunctionPointerGenericSubstitutionCustomModifiersTypesDefinedOnMethod() + { + var il = @" +.class public auto ansi beforefieldinit A`1 + extends [mscorlib]System.Object +{ +} +.class public auto ansi beforefieldinit C + extends [mscorlib]System.Object +{ + // Methods + .method public hidebysig static + void M1 ( + method class A`1 modopt(class A`1) & modopt(class A`1) *(class A`1 modopt(class A`1) & modopt(class A`1)) param + ) cil managed + { + ret + } +} +"; + + var source = @" +unsafe +{ + C.M1(null); +} + +class D1 {} +class D2 {} +class D3 {} +class D4 {} +class D5 {} +class D6 {} +"; + + var comp = CreateCompilationWithIL(source, il, options: TestOptions.UnsafeReleaseExe); + comp.VerifyDiagnostics(); + + var tree = comp.SyntaxTrees[0]; + var model = comp.GetSemanticModel(tree); + var invocation = tree.GetRoot().DescendantNodes().OfType().Single(); + + var symbol = model.GetSymbolInfo(invocation); + + AssertEx.Equal("void C.M1(delegate*) A modopt(A), ref modopt(A) A modopt(A)> param)", + symbol.Symbol.ToTestDisplayString()); + } + + [Fact] + public void FunctionPointerGenericSubstitution_SubstitutionAddsCallConvModopts() + { + var il = @" +.class public auto ansi beforefieldinit C + extends [mscorlib]System.Object +{ + .field public static int32 modopt([mscorlib]System.Runtime.CompilerServices.CallConvCdecl) modopt([mscorlib]System.Runtime.CompilerServices.CallConvStdcall) Field +} +"; + + var code = @" +unsafe +{ + delegate* unmanaged ptr = M(C.Field); + + delegate* unmanaged M(T arg) => null; +} +"; + + var comp = CreateCompilationWithIL(code, il, targetFramework: TargetFramework.NetCoreApp, options: TestOptions.UnsafeReleaseExe); + comp.VerifyDiagnostics(); + + var tree = comp.SyntaxTrees[0]; + var model = comp.GetSemanticModel(tree); + + var localSyntax = tree.GetRoot().DescendantNodes().OfType().Single(); + AssertEx.Equal("ptr = M(C.Field)", localSyntax.ToString()); + var local = (ILocalSymbol)model.GetDeclaredSymbol(localSyntax)!; + + AssertEx.Equal("delegate* unmanaged", local.Type.ToTestDisplayString()); + + var typeInfo = model.GetTypeInfo(localSyntax.Initializer!.Value); + AssertEx.Equal("delegate* unmanaged", typeInfo.Type.ToTestDisplayString()); + } + + [Fact] + public void FunctionPointerGenericSubstitution_SubstitutionAddsCallConvModopts_InIL() + { + var cDefinition = @" +public class C +{ + public unsafe delegate* unmanaged M() => null; +} +"; + var cComp = CreateCompilation(cDefinition, assemblyName: "cLib"); + + var il = @" +.assembly extern cLib +{ + .ver 0:0:0:0 +} +.class public auto ansi beforefieldinit D + extends class [cLib]C`1 +{ +} +"; + + var comp = CreateCompilationWithIL("", il, references: new[] { cComp.ToMetadataReference() }, targetFramework: TargetFramework.NetCoreApp, options: TestOptions.UnsafeReleaseDll); + comp.VerifyDiagnostics(); + + var d = comp.GetTypeByMetadataName("D"); + var m = d!.BaseTypeNoUseSiteDiagnostics.GetMethod("M"); + + var funcPtrType = (FunctionPointerTypeSymbol)m.ReturnType; + AssertEx.Equal("delegate* unmanaged[Stdcall, Cdecl]", funcPtrType.ToTestDisplayString()); + AssertEx.SetEqual(new[] + { + "System.Runtime.CompilerServices.CallConvCdecl", + "System.Runtime.CompilerServices.CallConvStdcall" + }, + funcPtrType.Signature.GetCallingConventionModifiers().Select(c => ((CSharpCustomModifier)c).ModifierSymbol.ToTestDisplayString())); + } + [Fact] public void FunctionPointerAsConstraint() {