From 8263533494c4b22d102227f590c8b4e5b1ba7163 Mon Sep 17 00:00:00 2001 From: Alex Zaytsev Date: Wed, 19 Nov 2025 19:18:15 +1000 Subject: [PATCH] Fix support for prefix opcodes Fixes #303 --- src/DelegateDecompiler.Tests/Issue298.cs | 36 ++++++++++++++----- src/DelegateDecompiler/Processor.cs | 3 +- .../Processors/ConvertTypeProcessor.cs | 12 +++---- 3 files changed, 33 insertions(+), 18 deletions(-) diff --git a/src/DelegateDecompiler.Tests/Issue298.cs b/src/DelegateDecompiler.Tests/Issue298.cs index ec7b676c..9c5ad1c8 100644 --- a/src/DelegateDecompiler.Tests/Issue298.cs +++ b/src/DelegateDecompiler.Tests/Issue298.cs @@ -10,28 +10,46 @@ public class Issue298 : DecompilerTestsBase [Test] public void TestNotConstrained() { - static int NotConstrained(T value) where T : ITestInterface => ((ITestInterface)value).Value; - - Expression> expected = value => value.Value; - Test(NotConstrained, expected); + static int Actual(T value) where T : ITestInterface => ((ITestInterface)value).Field; + + Test(Actual, + value => value.Field, + value => ((ITestInterface)value).Field + ); } [Test] public void TestConstrained() { - static int Constrained(T value) where T : ITestInterface => value.Value; + static int Actual(T value) where T : ITestInterface => value.Field; - Expression> expected = value => value.Value; - Test(Constrained, expected); + Test(Actual, value => value.Field); + Test(Actual, value => value.Field); } +#if NET6_0_OR_GREATER + [Test] + public void TestConstrainedDefaultImplementation() + { + static int Actual(T value, int i) where T : ITestInterface => value.Method(i); + static Expression> Expected() where T : ITestInterface => (value, i) => value.Method(i); + + Test(Actual, Expected()); + Test(Actual, Expected()); + } +#endif + interface ITestInterface { - public int Value { get; } + public int Field { get; } + +#if NET6_0_OR_GREATER + public int Method(int i) => i; +#endif } class TestClass : ITestInterface { - public int Value { get; set; } + public int Field { get; set; } } } diff --git a/src/DelegateDecompiler/Processor.cs b/src/DelegateDecompiler/Processor.cs index c1c8b8b1..aa5271ca 100644 --- a/src/DelegateDecompiler/Processor.cs +++ b/src/DelegateDecompiler/Processor.cs @@ -145,9 +145,10 @@ static int ProcessInstruction(ProcessorState state, Instruction instruction) { Debug.WriteLine(instruction); - if (instruction.OpCode == OpCodes.Nop || + if (instruction.OpCode == OpCodes.Nop || instruction.OpCode == OpCodes.Break || instruction.OpCode == OpCodes.Ret || + instruction.OpCode.OpCodeType == OpCodeType.Prefix || instruction.OpCode.FlowControl == FlowControl.Branch) { // Do nothing diff --git a/src/DelegateDecompiler/Processors/ConvertTypeProcessor.cs b/src/DelegateDecompiler/Processors/ConvertTypeProcessor.cs index 39144fa4..043907ca 100644 --- a/src/DelegateDecompiler/Processors/ConvertTypeProcessor.cs +++ b/src/DelegateDecompiler/Processors/ConvertTypeProcessor.cs @@ -10,20 +10,16 @@ internal class ConvertTypeProcessor : IProcessor { public static void Register(Dictionary processors) { - processors.Register(new ConvertTypeProcessor(), - OpCodes.Castclass, + processors.Register(new ConvertTypeProcessor(), + OpCodes.Castclass, OpCodes.Unbox, - OpCodes.Unbox_Any, - OpCodes.Constrained); + OpCodes.Unbox_Any); } public void Process(ProcessorState state, Instruction instruction) { var expression = state.Stack.Pop(); - var targetType = (Type)instruction.Operand; - state.Stack.Push(expression.Type != targetType - ? Expression.Convert(expression, targetType) - : expression); + state.Stack.Push(Expression.Convert(expression, (Type)instruction.Operand)); } } }