Browse Source

Fix interaction of C# 11 nint==IntPtr with overload resolution.

In C# 11+.NET 7 mode, we now always use type nint, never IntPtr, so that overload resolution works as expected.
pull/2873/head
Daniel Grunwald 2 years ago
parent
commit
9abc2b90da
  1. 12
      ICSharpCode.Decompiler.Tests/PrettyTestRunner.cs
  2. 31
      ICSharpCode.Decompiler.Tests/TestCases/Correctness/OverloadResolution.cs
  3. 8
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/PInvoke.cs
  4. 15
      ICSharpCode.Decompiler/CSharp/CallBuilder.cs
  5. 5
      ICSharpCode.Decompiler/TypeSystem/MetadataModule.cs
  6. 2
      ICSharpCode.Decompiler/TypeSystem/TypeSystemExtensions.cs

12
ICSharpCode.Decompiler.Tests/PrettyTestRunner.cs

@ -321,13 +321,11 @@ namespace ICSharpCode.Decompiler.Tests
[Test] [Test]
public async Task Loops([ValueSource(nameof(defaultOptionsWithMcs))] CompilerOptions cscOptions) public async Task Loops([ValueSource(nameof(defaultOptionsWithMcs))] CompilerOptions cscOptions)
{ {
await RunForLibrary(cscOptions: cscOptions, decompilerSettings: new DecompilerSettings { DecompilerSettings settings = Tester.GetSettings(cscOptions);
// legacy csc generates a dead store in debug builds // legacy csc generates a dead store in debug builds
RemoveDeadStores = (cscOptions == CompilerOptions.None), settings.RemoveDeadStores = (cscOptions == CompilerOptions.None);
UseExpressionBodyForCalculatedGetterOnlyProperties = false, settings.UseExpressionBodyForCalculatedGetterOnlyProperties = false;
FileScopedNamespaces = false, await RunForLibrary(cscOptions: cscOptions, decompilerSettings: settings);
NumericIntPtr = false,
});
} }
[Test] [Test]

31
ICSharpCode.Decompiler.Tests/TestCases/Correctness/OverloadResolution.cs

@ -36,6 +36,9 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Correctness
Issue1747(); Issue1747();
CallAmbiguousOutParam(); CallAmbiguousOutParam();
CallWithInParam(); CallWithInParam();
#if CS90
NativeIntTests(new IntPtr(1), 2);
#endif
Issue2444.M2(); Issue2444.M2();
Issue2741.B.Test(new Issue2741.C()); Issue2741.B.Test(new Issue2741.C());
} }
@ -337,6 +340,34 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Correctness
#endif #endif
#endregion #endregion
#if CS90
static void NativeIntTests(IntPtr i1, nint i2)
{
Console.WriteLine("NativeIntTests(i1):");
ObjectOrLong((object)i1);
ObjectOrLong((long)i1);
Console.WriteLine("NativeIntTests(i2):");
ObjectOrLong((object)i2);
ObjectOrLong((long)i2);
Console.WriteLine("NativeIntTests(new IntPtr):");
ObjectOrLong((object)new IntPtr(3));
ObjectOrLong((long)new IntPtr(3));
Console.WriteLine("NativeIntTests(IntPtr.Zero):");
ObjectOrLong((object)IntPtr.Zero);
ObjectOrLong((long)IntPtr.Zero);
}
static void ObjectOrLong(object o)
{
Console.WriteLine("object " + o);
}
static void ObjectOrLong(long l)
{
Console.WriteLine("long " + l);
}
#endif
#region #2444 #region #2444
public struct Issue2444 public struct Issue2444
{ {

8
ICSharpCode.Decompiler.Tests/TestCases/Pretty/PInvoke.cs

@ -93,20 +93,14 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
[DllImport("ws2_32.dll", SetLastError = true)] [DllImport("ws2_32.dll", SetLastError = true)]
internal static extern nint ioctlsocket([In] nint socketHandle, [In] int cmd, [In][Out] ref int argp); internal static extern nint ioctlsocket([In] nint socketHandle, [In] int cmd, [In][Out] ref int argp);
public void CallMethodWithInOutParameter()
{
int argp = 0;
ioctlsocket(nint.Zero, 0, ref argp);
}
#else #else
[DllImport("ws2_32.dll", SetLastError = true)] [DllImport("ws2_32.dll", SetLastError = true)]
internal static extern IntPtr ioctlsocket([In] IntPtr socketHandle, [In] int cmd, [In][Out] ref int argp); internal static extern IntPtr ioctlsocket([In] IntPtr socketHandle, [In] int cmd, [In][Out] ref int argp);
#endif
public void CallMethodWithInOutParameter() public void CallMethodWithInOutParameter()
{ {
int argp = 0; int argp = 0;
ioctlsocket(IntPtr.Zero, 0, ref argp); ioctlsocket(IntPtr.Zero, 0, ref argp);
} }
#endif
} }
} }

15
ICSharpCode.Decompiler/CSharp/CallBuilder.cs

@ -1553,12 +1553,25 @@ namespace ICSharpCode.Decompiler.CSharp
CastArguments(argumentList.Arguments, argumentList.ExpectedParameters); CastArguments(argumentList.Arguments, argumentList.ExpectedParameters);
break; // make sure that we don't not end up in an infinite loop break; // make sure that we don't not end up in an infinite loop
} }
IType returnTypeOverride = null;
if (typeSystem.MainModule.TypeSystemOptions.HasFlag(TypeSystemOptions.NativeIntegersWithoutAttribute))
{
// For DeclaringType, we don't use nint/nuint (so that DeclaringType.GetConstructors etc. works),
// but in NativeIntegersWithoutAttribute mode we must use nint/nuint for expression types,
// so that the appropriate set of conversions is used for further overload resolution.
if (method.DeclaringType.IsKnownType(KnownTypeCode.IntPtr))
returnTypeOverride = SpecialType.NInt;
else if (method.DeclaringType.IsKnownType(KnownTypeCode.UIntPtr))
returnTypeOverride = SpecialType.NUInt;
}
return new ObjectCreateExpression( return new ObjectCreateExpression(
expressionBuilder.ConvertType(method.DeclaringType), expressionBuilder.ConvertType(method.DeclaringType),
argumentList.GetArgumentExpressions() argumentList.GetArgumentExpressions()
).WithRR(new CSharpInvocationResolveResult( ).WithRR(new CSharpInvocationResolveResult(
target, method, argumentList.GetArgumentResolveResults().ToArray(), target, method, argumentList.GetArgumentResolveResults().ToArray(),
isExpandedForm: argumentList.IsExpandedForm, argumentToParameterMap: argumentList.ArgumentToParameterMap isExpandedForm: argumentList.IsExpandedForm,
argumentToParameterMap: argumentList.ArgumentToParameterMap,
returnTypeOverride: returnTypeOverride
)); ));
} }
} }

5
ICSharpCode.Decompiler/TypeSystem/MetadataModule.cs

@ -402,8 +402,9 @@ namespace ICSharpCode.Decompiler.TypeSystem
IType ResolveDeclaringType(EntityHandle declaringTypeReference, GenericContext context) IType ResolveDeclaringType(EntityHandle declaringTypeReference, GenericContext context)
{ {
// resolve without substituting dynamic/tuple types // resolve without substituting dynamic/tuple types
var ty = ResolveType(declaringTypeReference, context, const TypeSystemOptions removedOptions = TypeSystemOptions.Dynamic | TypeSystemOptions.Tuple
options & ~(TypeSystemOptions.Dynamic | TypeSystemOptions.Tuple | TypeSystemOptions.NullabilityAnnotations)); | TypeSystemOptions.NullabilityAnnotations | TypeSystemOptions.NativeIntegers | TypeSystemOptions.NativeIntegersWithoutAttribute;
var ty = ResolveType(declaringTypeReference, context, options & ~removedOptions);
// but substitute tuple types in type arguments: // but substitute tuple types in type arguments:
ty = ApplyAttributeTypeVisitor.ApplyAttributesToType(ty, Compilation, null, metadata, options, Nullability.Oblivious, typeChildrenOnly: true); ty = ApplyAttributeTypeVisitor.ApplyAttributesToType(ty, Compilation, null, metadata, options, Nullability.Oblivious, typeChildrenOnly: true);
return ty; return ty;

2
ICSharpCode.Decompiler/TypeSystem/TypeSystemExtensions.cs

@ -239,7 +239,7 @@ namespace ICSharpCode.Decompiler.TypeSystem
bool IsUnmanagedTypeInternal(IType type) bool IsUnmanagedTypeInternal(IType type)
{ {
if (type.Kind is TypeKind.Enum or TypeKind.Pointer or TypeKind.FunctionPointer) if (type.Kind is TypeKind.Enum or TypeKind.Pointer or TypeKind.FunctionPointer or TypeKind.NInt or TypeKind.NUInt)
{ {
return true; return true;
} }

Loading…
Cancel
Save