diff --git a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/FunctionPointers.cs b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/FunctionPointers.cs index c3f05a953..16eee5f60 100644 --- a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/FunctionPointers.cs +++ b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/FunctionPointers.cs @@ -1,4 +1,5 @@ using System; +using System.Text; namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty { @@ -25,6 +26,28 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty { return (delegate*)(&Overloaded); } + + public static string VarianceTest(object o) + { + return null; + } + + public unsafe delegate* Variance() + { + return (delegate*)(&VarianceTest); + } + +#if TODO + public unsafe delegate* AddressOfLocalFunction() + { + return &LocalFunction; + + static void LocalFunction() + { + + } + } +#endif } internal class FunctionPointersWithDynamicTypes @@ -94,4 +117,24 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty // public delegate* unmanaged[Cdecl] cdecl; //} + internal class FunctionPointerTypeInference + { + private static char Test(int i) + { + return (char)i; + } + + public unsafe R GenericMethod(delegate* f, T arg) + { + return f(arg); + } + + public unsafe void Call() + { + delegate* f = &Test; + GenericMethod(f, 0); + GenericMethod((delegate*)(&Test), 1); + GenericMethod(null, 2); + } + } } diff --git a/ICSharpCode.Decompiler/CSharp/RequiredNamespaceCollector.cs b/ICSharpCode.Decompiler/CSharp/RequiredNamespaceCollector.cs index b8428fa7f..6c4aa4acd 100644 --- a/ICSharpCode.Decompiler/CSharp/RequiredNamespaceCollector.cs +++ b/ICSharpCode.Decompiler/CSharp/RequiredNamespaceCollector.cs @@ -180,6 +180,13 @@ namespace ICSharpCode.Decompiler.CSharp CollectNamespacesForTypeReference(elementType); } break; + case FunctionPointerType fnPtrType: + CollectNamespacesForTypeReference(fnPtrType.ReturnType); + foreach (var paramType in fnPtrType.ParameterTypes) + { + CollectNamespacesForTypeReference(paramType); + } + break; default: namespaces.Add(type.Namespace); break; diff --git a/ICSharpCode.Decompiler/CSharp/Resolver/CSharpConversions.cs b/ICSharpCode.Decompiler/CSharp/Resolver/CSharpConversions.cs index 403fb08e7..fd099d0e2 100644 --- a/ICSharpCode.Decompiler/CSharp/Resolver/CSharpConversions.cs +++ b/ICSharpCode.Decompiler/CSharp/Resolver/CSharpConversions.cs @@ -874,6 +874,27 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver return true; if (fromType.Kind == TypeKind.Null && toType.Kind.IsAnyPointer()) return true; + if (fromType is FunctionPointerType fromFnPtr && toType is FunctionPointerType toFnPtr + && fromFnPtr.CallingConvention == toFnPtr.CallingConvention + && fromFnPtr.ParameterTypes.Length == toFnPtr.ParameterTypes.Length) + { + // Variance applies to function pointer types + const int nestingDepth = 0; + if (!(IdentityConversion(fromFnPtr.ReturnType, toFnPtr.ReturnType) + || ImplicitReferenceConversion(fromFnPtr.ReturnType, toFnPtr.ReturnType, nestingDepth))) + { + return false; + } + foreach (var (fromPT, toPT) in fromFnPtr.ParameterTypes.Zip(toFnPtr.ParameterTypes)) + { + if (!(IdentityConversion(toPT, fromPT) + || ImplicitReferenceConversion(toPT, fromPT, nestingDepth))) + { + return false; + } + } + return true; + } return false; } diff --git a/ICSharpCode.Decompiler/CSharp/Resolver/TypeInference.cs b/ICSharpCode.Decompiler/CSharp/Resolver/TypeInference.cs index 28afb46a5..5af195db5 100644 --- a/ICSharpCode.Decompiler/CSharp/Resolver/TypeInference.cs +++ b/ICSharpCode.Decompiler/CSharp/Resolver/TypeInference.cs @@ -676,6 +676,22 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver MakeExactInference(pU.GetTypeArgument(i), pV.GetTypeArgument(i)); } Log.Unindent(); + return; + } + // Handle pointer types: + if (U is PointerType ptrU && V is PointerType ptrV) + { + MakeExactInference(ptrU.ElementType, ptrV.ElementType); + return; + } + if (U is FunctionPointerType fnPtrU && V is FunctionPointerType fnPtrV) + { + MakeExactInference(fnPtrU.ReturnType, fnPtrV.ReturnType); + foreach (var (ptU, ptV) in fnPtrU.ParameterTypes.Zip(fnPtrV.ParameterTypes)) + { + MakeExactInference(ptU, ptV); + } + return; } } @@ -792,6 +808,22 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver } } Log.Unindent(); + return; + } + // Handle pointer types: + if (U is PointerType ptrU && V is PointerType ptrV) + { + MakeExactInference(ptrU.ElementType, ptrV.ElementType); + return; + } + if (U is FunctionPointerType fnPtrU && V is FunctionPointerType fnPtrV) + { + MakeLowerBoundInference(fnPtrU.ReturnType, fnPtrV.ReturnType); + foreach (var (ptU, ptV) in fnPtrU.ParameterTypes.Zip(fnPtrV.ParameterTypes)) + { + MakeUpperBoundInference(ptU, ptV); + } + return; } } @@ -897,6 +929,22 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver } } Log.Unindent(); + return; + } + // Handle pointer types: + if (U is PointerType ptrU && V is PointerType ptrV) + { + MakeExactInference(ptrU.ElementType, ptrV.ElementType); + return; + } + if (U is FunctionPointerType fnPtrU && V is FunctionPointerType fnPtrV) + { + MakeUpperBoundInference(fnPtrU.ReturnType, fnPtrV.ReturnType); + foreach (var (ptU, ptV) in fnPtrU.ParameterTypes.Zip(fnPtrV.ParameterTypes)) + { + MakeLowerBoundInference(ptU, ptV); + } + return; } } #endregion diff --git a/ICSharpCode.Decompiler/CSharp/TranslatedExpression.cs b/ICSharpCode.Decompiler/CSharp/TranslatedExpression.cs index 6413eeb0b..24c7f2bcd 100644 --- a/ICSharpCode.Decompiler/CSharp/TranslatedExpression.cs +++ b/ICSharpCode.Decompiler/CSharp/TranslatedExpression.cs @@ -535,11 +535,11 @@ namespace ICSharpCode.Decompiler.CSharp { return new NullReferenceExpression() .WithILInstruction(this.ILInstructions) - .WithRR(new ConstantResolveResult(targetType, null)); + .WithRR(new ConstantResolveResult(SpecialType.NullType, null)); } return new CastExpression(expressionBuilder.ConvertType(targetType), new NullReferenceExpression()) .WithILInstruction(this.ILInstructions) - .WithRR(new ConstantResolveResult(targetType, null)); + .WithRR(new ConstantResolveResult(SpecialType.NullType, null)); } if (allowImplicitConversion) {