From 999d3b48fab106f33049e34d6df18270c50d108b Mon Sep 17 00:00:00 2001 From: DualFroz Date: Sat, 10 Oct 2026 12:50:07 +0200 Subject: [PATCH] Fix #4137: Keep nint in conditionals with mixed native int branches When the branches of a conditional have different types, its type falls back to the IL stack slot type, which is (U)IntPtr. IntroduceNativeIntTypeOnLocals only retypes variables, so with native integers enabled the branches got cast to IntPtr. Map (U)IntPtr to n(u)int the same way boxing does; pointer types are unaffected. --- .../TestCases/Pretty/NativeInts.cs | 5 ++++ .../CSharp/ExpressionBuilder.cs | 29 ++++++++++++------- 2 files changed, 24 insertions(+), 10 deletions(-) diff --git a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/NativeInts.cs b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/NativeInts.cs index 134131c..a65953c 100644 --- a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/NativeInts.cs +++ b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/NativeInts.cs @@ -254,5 +254,10 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty // Explicit `unchecked` is necessary when casting oversized constant to nuint return unchecked((nuint)9123123123123uL); } + + public nint ConditionalWithMixedBranchTypes(bool b, int i, nuint x, nint y) + { + return (b ? ((nint)i) : ((nint)x)) - y; + } } } diff --git a/ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs b/ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs index 8461e11..e2af27a 100644 --- a/ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs +++ b/ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs @@ -1825,6 +1825,22 @@ namespace ICSharpCode.Decompiler.CSharp } } + IType PreferNativeIntegerType(IType type) + { + if (settings.NativeIntegers) + { + if (type.IsKnownType(KnownTypeCode.IntPtr)) + { + return SpecialType.NInt; + } + else if (type.IsKnownType(KnownTypeCode.UIntPtr)) + { + return SpecialType.NUInt; + } + } + return type; + } + /// /// Gets a type used for performing arithmetic with the stack type and sign. /// @@ -3525,16 +3541,9 @@ namespace ICSharpCode.Decompiler.CSharp { IType targetType = inst.Type; var arg = Translate(inst.Argument, typeHint: targetType); - if (settings.NativeIntegers && !arg.Type.Equals(targetType)) + if (!arg.Type.Equals(targetType)) { - if (targetType.IsKnownType(KnownTypeCode.IntPtr)) - { - targetType = SpecialType.NInt; - } - else if (targetType.IsKnownType(KnownTypeCode.UIntPtr)) - { - targetType = SpecialType.NUInt; - } + targetType = PreferNativeIntegerType(targetType); } arg = arg.ConvertTo(targetType, this); var obj = compilation.FindType(KnownTypeCode.Object); @@ -4241,7 +4250,7 @@ namespace ICSharpCode.Decompiler.CSharp } else { - targetType = inst.InferType(compilation); + targetType = PreferNativeIntegerType(inst.InferType(compilation)); } } }