diff --git a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/Switch.cs b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/Switch.cs index 856c02028..e6e7e7ae4 100644 --- a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/Switch.cs +++ b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/Switch.cs @@ -67,6 +67,36 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty } } + public class ImplicitInt + { + private readonly int s; + + public ImplicitInt(int s) + { + this.s = s; + } + + public static implicit operator int(ImplicitInt v) + { + return v.s; + } + } + + public class ExplicitInt + { + private readonly int s; + + public ExplicitInt(int s) + { + this.s = s; + } + + public static explicit operator int(ExplicitInt v) + { + return v.s; + } + } + public enum State { False, @@ -310,6 +340,62 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty } } + public static void SwitchOverExplicitInt(ExplicitInt i) + { + switch ((int)i) + { + case 0: + Console.WriteLine("zero"); + break; + case 5: + Console.WriteLine("five"); + break; + case 10: + Console.WriteLine("ten"); + break; + case 15: + Console.WriteLine("fifteen"); + break; + case 20: + Console.WriteLine("twenty"); + break; + case 25: + Console.WriteLine("twenty-five"); + break; + case 30: + Console.WriteLine("thirty"); + break; + } + } + + public static void SwitchOverImplicitInt(ImplicitInt i) + { + switch (i) + { + case 0: + Console.WriteLine("zero"); + break; + case 5: + Console.WriteLine("five"); + break; + case 10: + Console.WriteLine("ten"); + break; + case 15: + Console.WriteLine("fifteen"); + break; + case 20: + Console.WriteLine("twenty"); + break; + case 25: + Console.WriteLine("twenty-five"); + break; + case 30: + Console.WriteLine("thirty"); + break; + } + } + // SwitchDetection.UseCSharpSwitch requires more complex heuristic to identify this when compiled with Roslyn public static void CompactSwitchOverInt(int i) { diff --git a/ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs b/ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs index 635d32871..dfec27d8d 100644 --- a/ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs +++ b/ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs @@ -3900,17 +3900,20 @@ namespace ICSharpCode.Decompiler.CSharp } } - protected internal override TranslatedExpression VisitSwitchInstruction(SwitchInstruction inst, TranslationContext context) + internal (TranslatedExpression, IType) TranslateSwitchValue(SwitchInstruction inst, bool allowImplicitConversion) { TranslatedExpression value; IType type; if (inst.Value is StringToInt strToInt) { + // switch-expression does not support implicit conversions at all, + // switch-statement does support implicit conversions in general, however, the rules are + // not very intuitive and in order to prevent bugs, we emit an explicit cast. value = Translate(strToInt.Argument) .ConvertTo( strToInt.ExpectedType, this, - allowImplicitConversion: false // switch-expression does not support implicit conversions + allowImplicitConversion: false ); type = compilation.FindType(KnownTypeCode.String); } @@ -3918,12 +3921,20 @@ namespace ICSharpCode.Decompiler.CSharp { strToInt = null; value = Translate(inst.Value); + type = value.Type; if (inst.Type != null) { - value = value.ConvertTo(inst.Type, this, allowImplicitConversion: true); + value = value.ConvertTo(inst.Type, this, allowImplicitConversion: allowImplicitConversion); + type = inst.Type; } - type = value.Type; } + return (value, type); + } + + protected internal override TranslatedExpression VisitSwitchInstruction(SwitchInstruction inst, TranslationContext context) + { + // switch-expression does not support implicit conversions + var (value, type) = TranslateSwitchValue(inst, allowImplicitConversion: false); IL.SwitchSection defaultSection = inst.GetDefaultSection(); SwitchExpression switchExpr = new SwitchExpression(); diff --git a/ICSharpCode.Decompiler/CSharp/StatementBuilder.cs b/ICSharpCode.Decompiler/CSharp/StatementBuilder.cs index 4dfc5f658..52fcb2302 100644 --- a/ICSharpCode.Decompiler/CSharp/StatementBuilder.cs +++ b/ICSharpCode.Decompiler/CSharp/StatementBuilder.cs @@ -210,30 +210,7 @@ namespace ICSharpCode.Decompiler.CSharp var oldCaseLabelMapping = caseLabelMapping; caseLabelMapping = new Dictionary(); - TranslatedExpression value; - IType type; - if (inst.Value is StringToInt strToInt) - { - value = exprBuilder.Translate(strToInt.Argument) - .ConvertTo( - strToInt.ExpectedType, - exprBuilder, - // switch statement does support implicit conversions in general, however, the rules are - // not very intuitive and in order to prevent bugs, we emit an explicit cast. - allowImplicitConversion: false - ); - type = exprBuilder.compilation.FindType(KnownTypeCode.String); - } - else - { - strToInt = null; - value = exprBuilder.Translate(inst.Value); - if (inst.Type != null) - { - value = value.ConvertTo(inst.Type, exprBuilder, allowImplicitConversion: true); - } - type = value.Type; - } + var (value, type) = exprBuilder.TranslateSwitchValue(inst, allowImplicitConversion: true); IL.SwitchSection defaultSection = inst.GetDefaultSection();