Skip to content

Commit efbefd0

Browse files
Fix #3361: switch-value conversion was losing its target type.
1 parent 6215747 commit efbefd0

File tree

3 files changed

+102
-28
lines changed

3 files changed

+102
-28
lines changed

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

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,36 @@ public static explicit operator string(ExplicitString v)
6767
}
6868
}
6969

70+
public class ImplicitInt
71+
{
72+
private readonly int s;
73+
74+
public ImplicitInt(int s)
75+
{
76+
this.s = s;
77+
}
78+
79+
public static implicit operator int(ImplicitInt v)
80+
{
81+
return v.s;
82+
}
83+
}
84+
85+
public class ExplicitInt
86+
{
87+
private readonly int s;
88+
89+
public ExplicitInt(int s)
90+
{
91+
this.s = s;
92+
}
93+
94+
public static explicit operator int(ExplicitInt v)
95+
{
96+
return v.s;
97+
}
98+
}
99+
70100
public enum State
71101
{
72102
False,
@@ -310,6 +340,62 @@ public static void SwitchOverInt(int i)
310340
}
311341
}
312342

343+
public static void SwitchOverExplicitInt(ExplicitInt i)
344+
{
345+
switch ((int)i)
346+
{
347+
case 0:
348+
Console.WriteLine("zero");
349+
break;
350+
case 5:
351+
Console.WriteLine("five");
352+
break;
353+
case 10:
354+
Console.WriteLine("ten");
355+
break;
356+
case 15:
357+
Console.WriteLine("fifteen");
358+
break;
359+
case 20:
360+
Console.WriteLine("twenty");
361+
break;
362+
case 25:
363+
Console.WriteLine("twenty-five");
364+
break;
365+
case 30:
366+
Console.WriteLine("thirty");
367+
break;
368+
}
369+
}
370+
371+
public static void SwitchOverImplicitInt(ImplicitInt i)
372+
{
373+
switch (i)
374+
{
375+
case 0:
376+
Console.WriteLine("zero");
377+
break;
378+
case 5:
379+
Console.WriteLine("five");
380+
break;
381+
case 10:
382+
Console.WriteLine("ten");
383+
break;
384+
case 15:
385+
Console.WriteLine("fifteen");
386+
break;
387+
case 20:
388+
Console.WriteLine("twenty");
389+
break;
390+
case 25:
391+
Console.WriteLine("twenty-five");
392+
break;
393+
case 30:
394+
Console.WriteLine("thirty");
395+
break;
396+
}
397+
}
398+
313399
// SwitchDetection.UseCSharpSwitch requires more complex heuristic to identify this when compiled with Roslyn
314400
public static void CompactSwitchOverInt(int i)
315401
{

ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3900,30 +3900,41 @@ protected internal override TranslatedExpression VisitIfInstruction(IfInstructio
39003900
}
39013901
}
39023902

3903-
protected internal override TranslatedExpression VisitSwitchInstruction(SwitchInstruction inst, TranslationContext context)
3903+
internal (TranslatedExpression, IType) TranslateSwitchValue(SwitchInstruction inst, bool allowImplicitConversion)
39043904
{
39053905
TranslatedExpression value;
39063906
IType type;
39073907
if (inst.Value is StringToInt strToInt)
39083908
{
3909+
// switch-expression does not support implicit conversions at all,
3910+
// switch-statement does support implicit conversions in general, however, the rules are
3911+
// not very intuitive and in order to prevent bugs, we emit an explicit cast.
39093912
value = Translate(strToInt.Argument)
39103913
.ConvertTo(
39113914
strToInt.ExpectedType,
39123915
this,
3913-
allowImplicitConversion: false // switch-expression does not support implicit conversions
3916+
allowImplicitConversion: false
39143917
);
39153918
type = compilation.FindType(KnownTypeCode.String);
39163919
}
39173920
else
39183921
{
39193922
strToInt = null;
39203923
value = Translate(inst.Value);
3924+
type = value.Type;
39213925
if (inst.Type != null)
39223926
{
3923-
value = value.ConvertTo(inst.Type, this, allowImplicitConversion: true);
3927+
value = value.ConvertTo(inst.Type, this, allowImplicitConversion: allowImplicitConversion);
3928+
type = inst.Type;
39243929
}
3925-
type = value.Type;
39263930
}
3931+
return (value, type);
3932+
}
3933+
3934+
protected internal override TranslatedExpression VisitSwitchInstruction(SwitchInstruction inst, TranslationContext context)
3935+
{
3936+
// switch-expression does not support implicit conversions
3937+
var (value, type) = TranslateSwitchValue(inst, allowImplicitConversion: false);
39273938

39283939
IL.SwitchSection defaultSection = inst.GetDefaultSection();
39293940
SwitchExpression switchExpr = new SwitchExpression();

ICSharpCode.Decompiler/CSharp/StatementBuilder.cs

Lines changed: 1 addition & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -210,30 +210,7 @@ SwitchStatement TranslateSwitch(BlockContainer switchContainer, SwitchInstructio
210210
var oldCaseLabelMapping = caseLabelMapping;
211211
caseLabelMapping = new Dictionary<Block, ConstantResolveResult>();
212212

213-
TranslatedExpression value;
214-
IType type;
215-
if (inst.Value is StringToInt strToInt)
216-
{
217-
value = exprBuilder.Translate(strToInt.Argument)
218-
.ConvertTo(
219-
strToInt.ExpectedType,
220-
exprBuilder,
221-
// switch statement does support implicit conversions in general, however, the rules are
222-
// not very intuitive and in order to prevent bugs, we emit an explicit cast.
223-
allowImplicitConversion: false
224-
);
225-
type = exprBuilder.compilation.FindType(KnownTypeCode.String);
226-
}
227-
else
228-
{
229-
strToInt = null;
230-
value = exprBuilder.Translate(inst.Value);
231-
if (inst.Type != null)
232-
{
233-
value = value.ConvertTo(inst.Type, exprBuilder, allowImplicitConversion: true);
234-
}
235-
type = value.Type;
236-
}
213+
var (value, type) = exprBuilder.TranslateSwitchValue(inst, allowImplicitConversion: true);
237214

238215
IL.SwitchSection defaultSection = inst.GetDefaultSection();
239216

0 commit comments

Comments
 (0)