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. 10
      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

10
ICSharpCode.Decompiler.Tests/PrettyTestRunner.cs

@ -321,13 +321,11 @@ namespace ICSharpCode.Decompiler.Tests @@ -321,13 +321,11 @@ namespace ICSharpCode.Decompiler.Tests
[Test]
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
RemoveDeadStores = (cscOptions == CompilerOptions.None),
UseExpressionBodyForCalculatedGetterOnlyProperties = false,
FileScopedNamespaces = false,
NumericIntPtr = false,
});
settings.RemoveDeadStores = (cscOptions == CompilerOptions.None);
settings.UseExpressionBodyForCalculatedGetterOnlyProperties = false;
await RunForLibrary(cscOptions: cscOptions, decompilerSettings: settings);
}
[Test]

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

@ -36,6 +36,9 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Correctness @@ -36,6 +36,9 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Correctness
Issue1747();
CallAmbiguousOutParam();
CallWithInParam();
#if CS90
NativeIntTests(new IntPtr(1), 2);
#endif
Issue2444.M2();
Issue2741.B.Test(new Issue2741.C());
}
@ -337,6 +340,34 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Correctness @@ -337,6 +340,34 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Correctness
#endif
#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
public struct Issue2444
{

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

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

15
ICSharpCode.Decompiler/CSharp/CallBuilder.cs

@ -1553,12 +1553,25 @@ namespace ICSharpCode.Decompiler.CSharp @@ -1553,12 +1553,25 @@ namespace ICSharpCode.Decompiler.CSharp
CastArguments(argumentList.Arguments, argumentList.ExpectedParameters);
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(
expressionBuilder.ConvertType(method.DeclaringType),
argumentList.GetArgumentExpressions()
).WithRR(new CSharpInvocationResolveResult(
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 @@ -402,8 +402,9 @@ namespace ICSharpCode.Decompiler.TypeSystem
IType ResolveDeclaringType(EntityHandle declaringTypeReference, GenericContext context)
{
// resolve without substituting dynamic/tuple types
var ty = ResolveType(declaringTypeReference, context,
options & ~(TypeSystemOptions.Dynamic | TypeSystemOptions.Tuple | TypeSystemOptions.NullabilityAnnotations));
const TypeSystemOptions removedOptions = TypeSystemOptions.Dynamic | TypeSystemOptions.Tuple
| TypeSystemOptions.NullabilityAnnotations | TypeSystemOptions.NativeIntegers | TypeSystemOptions.NativeIntegersWithoutAttribute;
var ty = ResolveType(declaringTypeReference, context, options & ~removedOptions);
// but substitute tuple types in type arguments:
ty = ApplyAttributeTypeVisitor.ApplyAttributesToType(ty, Compilation, null, metadata, options, Nullability.Oblivious, typeChildrenOnly: true);
return ty;

2
ICSharpCode.Decompiler/TypeSystem/TypeSystemExtensions.cs

@ -239,7 +239,7 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -239,7 +239,7 @@ namespace ICSharpCode.Decompiler.TypeSystem
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;
}

Loading…
Cancel
Save