Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added test for custom modifier substitution in function pointer types. #51038

Merged
merged 3 commits into from
Feb 18, 2021
Merged
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
172 changes: 172 additions & 0 deletions src/Compilers/CSharp/Test/Semantic/Semantics/FunctionPointerTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1665,6 +1665,178 @@ public void M2<T>()
");
}

[Fact, WorkItem(51037, "https://github.com/dotnet/roslyn/issues/51037")]
public void FunctionPointerGenericSubstitutionCustomModifiersTypesDefinedOnClass()
{
var il = @"
.class public auto ansi beforefieldinit A`1<T>
extends [mscorlib]System.Object
{
}
.class public auto ansi beforefieldinit C`6<T1, T2, T3, T4, T5, T6>
extends [mscorlib]System.Object
{
// Methods
.method public hidebysig static
void M1 (
method class A`1<!T1> modopt(class A`1<!T2>) & modopt(class A`1<!T3>) *(class A`1<!T4> modopt(class A`1<!T5>) & modopt(class A`1<!T6>)) param
) cil managed
{
ret
}
}
";

var source = @"
unsafe
{
C<D1, D2, D3, D4, D5, D6>.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);
333fred marked this conversation as resolved.
Show resolved Hide resolved
var invocation = tree.GetRoot().DescendantNodes().OfType<InvocationExpressionSyntax>().Single();

var symbol = model.GetSymbolInfo(invocation);

AssertEx.Equal("void C<D1, D2, D3, D4, D5, D6>.M1(delegate*<ref modopt(A<D6>) A<D4> modopt(A<D5>), ref modopt(A<T3>) A<D1> modopt(A<D2>)> param)",
symbol.Symbol.ToTestDisplayString());
}

[Fact, WorkItem(51037, "https://github.com/dotnet/roslyn/issues/51037")]
public void FunctionPointerGenericSubstitutionCustomModifiersTypesDefinedOnMethod()
{
var il = @"
.class public auto ansi beforefieldinit A`1<T>
extends [mscorlib]System.Object
{
}
.class public auto ansi beforefieldinit C
extends [mscorlib]System.Object
{
// Methods
.method public hidebysig static
void M1<T1, T2, T3, T4, T5, T6> (
method class A`1<!!T1> modopt(class A`1<!!T2>) & modopt(class A`1<!!T3>) *(class A`1<!!T4> modopt(class A`1<!!T5>) & modopt(class A`1<!!T6>)) param
) cil managed
{
ret
}
}
";

var source = @"
unsafe
{
C.M1<D1, D2, D3, D4, D5, D6>(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<InvocationExpressionSyntax>().Single();

var symbol = model.GetSymbolInfo(invocation);

AssertEx.Equal("void C.M1<D1, D2, D3, D4, D5, D6>(delegate*<ref modopt(A<D6>) A<D4> modopt(A<D5>), ref modopt(A<T3>) A<D1> modopt(A<D2>)> 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<int> ptr = M(C.Field);

delegate* unmanaged<T> M<T>(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<VariableDeclaratorSyntax>().Single();
AssertEx.Equal("ptr = M(C.Field)", localSyntax.ToString());
var local = (ILocalSymbol)model.GetDeclaredSymbol(localSyntax)!;

AssertEx.Equal("delegate* unmanaged<System.Int32>", local.Type.ToTestDisplayString());

var typeInfo = model.GetTypeInfo(localSyntax.Initializer!.Value);
AssertEx.Equal("delegate* unmanaged<System.Int32>", typeInfo.Type.ToTestDisplayString());
}

[Fact]
public void FunctionPointerGenericSubstitution_SubstitutionAddsCallConvModopts_InIL()
{
var cDefinition = @"
public class C<T>
{
public unsafe delegate* unmanaged<T> 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<int32 modopt([mscorlib]System.Runtime.CompilerServices.CallConvCdecl) modopt([mscorlib]System.Runtime.CompilerServices.CallConvStdcall)>
{
}
";

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]<System.Int32 modopt(System.Runtime.CompilerServices.CallConvStdcall) modopt(System.Runtime.CompilerServices.CallConvCdecl)>", 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()
{
Expand Down