Skip to content

Commit 9abc2b9

Browse files
committed
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.
1 parent efeaf13 commit 9abc2b9

File tree

6 files changed

+55
-18
lines changed

6 files changed

+55
-18
lines changed

ICSharpCode.Decompiler.Tests/PrettyTestRunner.cs

+5-7
Original file line numberDiff line numberDiff line change
@@ -321,13 +321,11 @@ public async Task Generics([ValueSource(nameof(defaultOptions))] CompilerOptions
321321
[Test]
322322
public async Task Loops([ValueSource(nameof(defaultOptionsWithMcs))] CompilerOptions cscOptions)
323323
{
324-
await RunForLibrary(cscOptions: cscOptions, decompilerSettings: new DecompilerSettings {
325-
// legacy csc generates a dead store in debug builds
326-
RemoveDeadStores = (cscOptions == CompilerOptions.None),
327-
UseExpressionBodyForCalculatedGetterOnlyProperties = false,
328-
FileScopedNamespaces = false,
329-
NumericIntPtr = false,
330-
});
324+
DecompilerSettings settings = Tester.GetSettings(cscOptions);
325+
// legacy csc generates a dead store in debug builds
326+
settings.RemoveDeadStores = (cscOptions == CompilerOptions.None);
327+
settings.UseExpressionBodyForCalculatedGetterOnlyProperties = false;
328+
await RunForLibrary(cscOptions: cscOptions, decompilerSettings: settings);
331329
}
332330

333331
[Test]

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

+31
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,9 @@ static void Main()
3636
Issue1747();
3737
CallAmbiguousOutParam();
3838
CallWithInParam();
39+
#if CS90
40+
NativeIntTests(new IntPtr(1), 2);
41+
#endif
3942
Issue2444.M2();
4043
Issue2741.B.Test(new Issue2741.C());
4144
}
@@ -337,6 +340,34 @@ static void InVsRegularParam(int i)
337340
#endif
338341
#endregion
339342

343+
#if CS90
344+
static void NativeIntTests(IntPtr i1, nint i2)
345+
{
346+
Console.WriteLine("NativeIntTests(i1):");
347+
ObjectOrLong((object)i1);
348+
ObjectOrLong((long)i1);
349+
Console.WriteLine("NativeIntTests(i2):");
350+
ObjectOrLong((object)i2);
351+
ObjectOrLong((long)i2);
352+
Console.WriteLine("NativeIntTests(new IntPtr):");
353+
ObjectOrLong((object)new IntPtr(3));
354+
ObjectOrLong((long)new IntPtr(3));
355+
Console.WriteLine("NativeIntTests(IntPtr.Zero):");
356+
ObjectOrLong((object)IntPtr.Zero);
357+
ObjectOrLong((long)IntPtr.Zero);
358+
}
359+
360+
static void ObjectOrLong(object o)
361+
{
362+
Console.WriteLine("object " + o);
363+
}
364+
365+
static void ObjectOrLong(long l)
366+
{
367+
Console.WriteLine("long " + l);
368+
}
369+
#endif
370+
340371
#region #2444
341372
public struct Issue2444
342373
{

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

+1-7
Original file line numberDiff line numberDiff line change
@@ -93,20 +93,14 @@ public void CustomMarshal2([MarshalAs(UnmanagedType.CustomMarshaler, MarshalType
9393
[DllImport("ws2_32.dll", SetLastError = true)]
9494
internal static extern nint ioctlsocket([In] nint socketHandle, [In] int cmd, [In][Out] ref int argp);
9595

96-
public void CallMethodWithInOutParameter()
97-
{
98-
int argp = 0;
99-
ioctlsocket(nint.Zero, 0, ref argp);
100-
}
10196
#else
10297
[DllImport("ws2_32.dll", SetLastError = true)]
10398
internal static extern IntPtr ioctlsocket([In] IntPtr socketHandle, [In] int cmd, [In][Out] ref int argp);
104-
99+
#endif
105100
public void CallMethodWithInOutParameter()
106101
{
107102
int argp = 0;
108103
ioctlsocket(IntPtr.Zero, 0, ref argp);
109104
}
110-
#endif
111105
}
112106
}

ICSharpCode.Decompiler/CSharp/CallBuilder.cs

+14-1
Original file line numberDiff line numberDiff line change
@@ -1553,12 +1553,25 @@ ExpressionWithResolveResult HandleConstructorCall(ExpectedTargetDetails expected
15531553
CastArguments(argumentList.Arguments, argumentList.ExpectedParameters);
15541554
break; // make sure that we don't not end up in an infinite loop
15551555
}
1556+
IType returnTypeOverride = null;
1557+
if (typeSystem.MainModule.TypeSystemOptions.HasFlag(TypeSystemOptions.NativeIntegersWithoutAttribute))
1558+
{
1559+
// For DeclaringType, we don't use nint/nuint (so that DeclaringType.GetConstructors etc. works),
1560+
// but in NativeIntegersWithoutAttribute mode we must use nint/nuint for expression types,
1561+
// so that the appropriate set of conversions is used for further overload resolution.
1562+
if (method.DeclaringType.IsKnownType(KnownTypeCode.IntPtr))
1563+
returnTypeOverride = SpecialType.NInt;
1564+
else if (method.DeclaringType.IsKnownType(KnownTypeCode.UIntPtr))
1565+
returnTypeOverride = SpecialType.NUInt;
1566+
}
15561567
return new ObjectCreateExpression(
15571568
expressionBuilder.ConvertType(method.DeclaringType),
15581569
argumentList.GetArgumentExpressions()
15591570
).WithRR(new CSharpInvocationResolveResult(
15601571
target, method, argumentList.GetArgumentResolveResults().ToArray(),
1561-
isExpandedForm: argumentList.IsExpandedForm, argumentToParameterMap: argumentList.ArgumentToParameterMap
1572+
isExpandedForm: argumentList.IsExpandedForm,
1573+
argumentToParameterMap: argumentList.ArgumentToParameterMap,
1574+
returnTypeOverride: returnTypeOverride
15621575
));
15631576
}
15641577
}

ICSharpCode.Decompiler/TypeSystem/MetadataModule.cs

+3-2
Original file line numberDiff line numberDiff line change
@@ -402,8 +402,9 @@ public IType ResolveType(EntityHandle typeRefDefSpec, GenericContext context, Ty
402402
IType ResolveDeclaringType(EntityHandle declaringTypeReference, GenericContext context)
403403
{
404404
// resolve without substituting dynamic/tuple types
405-
var ty = ResolveType(declaringTypeReference, context,
406-
options & ~(TypeSystemOptions.Dynamic | TypeSystemOptions.Tuple | TypeSystemOptions.NullabilityAnnotations));
405+
const TypeSystemOptions removedOptions = TypeSystemOptions.Dynamic | TypeSystemOptions.Tuple
406+
| TypeSystemOptions.NullabilityAnnotations | TypeSystemOptions.NativeIntegers | TypeSystemOptions.NativeIntegersWithoutAttribute;
407+
var ty = ResolveType(declaringTypeReference, context, options & ~removedOptions);
407408
// but substitute tuple types in type arguments:
408409
ty = ApplyAttributeTypeVisitor.ApplyAttributesToType(ty, Compilation, null, metadata, options, Nullability.Oblivious, typeChildrenOnly: true);
409410
return ty;

ICSharpCode.Decompiler/TypeSystem/TypeSystemExtensions.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -239,7 +239,7 @@ public static bool IsUnmanagedType(this IType type, bool allowGenerics)
239239

240240
bool IsUnmanagedTypeInternal(IType type)
241241
{
242-
if (type.Kind is TypeKind.Enum or TypeKind.Pointer or TypeKind.FunctionPointer)
242+
if (type.Kind is TypeKind.Enum or TypeKind.Pointer or TypeKind.FunctionPointer or TypeKind.NInt or TypeKind.NUInt)
243243
{
244244
return true;
245245
}

0 commit comments

Comments
 (0)