From 54ff546221064311c9ee32cf00a301386fb3612f Mon Sep 17 00:00:00 2001 From: Siegfried Pammer Date: Sun, 17 Feb 2019 23:01:30 +0100 Subject: [PATCH] Fix deactivated Generics pretty tests: remove redundant boxing conversion from is-expressions. --- .../TestCases/Pretty/Generics.cs | 8 +-- .../TestCases/Pretty/Generics.il | 54 +++++++++++++++++++ .../TestCases/Pretty/Generics.opt.il | 36 +++++++++++++ .../TestCases/Pretty/Generics.opt.roslyn.il | 36 +++++++++++++ .../TestCases/Pretty/Generics.roslyn.il | 54 +++++++++++++++++++ .../CSharp/ExpressionBuilder.cs | 5 +- .../CSharp/StatementBuilder.cs | 4 +- 7 files changed, 188 insertions(+), 9 deletions(-) diff --git a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/Generics.cs b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/Generics.cs index 29d6ef568..baefb56dc 100644 --- a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/Generics.cs +++ b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/Generics.cs @@ -198,12 +198,10 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty return d.Keys.GetEnumerator(); } -#if false public static bool IsString(T input) { return input is string; } -#endif public static string AsString(T input) { @@ -220,12 +218,10 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty return (T)(object)input; } -#if false public static bool IsInt(T input) { return input is int; } -#endif public static int CastToInt(T input) { @@ -236,12 +232,12 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty { return (T)(object)input; } -#if false + public static bool IsNullableInt(T input) { return input is int?; } -#endif + public static int? AsNullableInt(T input) { return input as int?; diff --git a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/Generics.il b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/Generics.il index 3ebf3eea9..f1ff82129 100644 --- a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/Generics.il +++ b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/Generics.il @@ -581,6 +581,24 @@ IL_0010: ret } // end of method Generics::GetEnumerator + .method public hidebysig static bool IsString(!!T input) cil managed + { + // Code size 20 (0x14) + .maxstack 2 + .locals init (bool V_0) + IL_0000: nop + IL_0001: ldarg.0 + IL_0002: box !!T + IL_0007: isinst [mscorlib]System.String + IL_000c: ldnull + IL_000d: cgt.un + IL_000f: stloc.0 + IL_0010: br.s IL_0012 + + IL_0012: ldloc.0 + IL_0013: ret + } // end of method Generics::IsString + .method public hidebysig static string AsString(!!T input) cil managed { @@ -630,6 +648,24 @@ IL_000b: ret } // end of method Generics::CastFromString + .method public hidebysig static bool IsInt(!!T input) cil managed + { + // Code size 20 (0x14) + .maxstack 2 + .locals init (bool V_0) + IL_0000: nop + IL_0001: ldarg.0 + IL_0002: box !!T + IL_0007: isinst [mscorlib]System.Int32 + IL_000c: ldnull + IL_000d: cgt.un + IL_000f: stloc.0 + IL_0010: br.s IL_0012 + + IL_0012: ldloc.0 + IL_0013: ret + } // end of method Generics::IsInt + .method public hidebysig static int32 CastToInt(!!T input) cil managed { // Code size 17 (0x11) @@ -662,6 +698,24 @@ IL_0010: ret } // end of method Generics::CastFromInt + .method public hidebysig static bool IsNullableInt(!!T input) cil managed + { + // Code size 20 (0x14) + .maxstack 2 + .locals init (bool V_0) + IL_0000: nop + IL_0001: ldarg.0 + IL_0002: box !!T + IL_0007: isinst valuetype [mscorlib]System.Nullable`1 + IL_000c: ldnull + IL_000d: cgt.un + IL_000f: stloc.0 + IL_0010: br.s IL_0012 + + IL_0012: ldloc.0 + IL_0013: ret + } // end of method Generics::IsNullableInt + .method public hidebysig static valuetype [mscorlib]System.Nullable`1 AsNullableInt(!!T input) cil managed { diff --git a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/Generics.opt.il b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/Generics.opt.il index d9ff5de8d..b22031fa9 100644 --- a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/Generics.opt.il +++ b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/Generics.opt.il @@ -478,6 +478,18 @@ IL_000b: ret } // end of method Generics::GetEnumerator + .method public hidebysig static bool IsString(!!T input) cil managed + { + // Code size 15 (0xf) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: box !!T + IL_0006: isinst [mscorlib]System.String + IL_000b: ldnull + IL_000c: cgt.un + IL_000e: ret + } // end of method Generics::IsString + .method public hidebysig static string AsString(!!T input) cil managed { @@ -509,6 +521,18 @@ IL_0006: ret } // end of method Generics::CastFromString + .method public hidebysig static bool IsInt(!!T input) cil managed + { + // Code size 15 (0xf) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: box !!T + IL_0006: isinst [mscorlib]System.Int32 + IL_000b: ldnull + IL_000c: cgt.un + IL_000e: ret + } // end of method Generics::IsInt + .method public hidebysig static int32 CastToInt(!!T input) cil managed { // Code size 12 (0xc) @@ -529,6 +553,18 @@ IL_000b: ret } // end of method Generics::CastFromInt + .method public hidebysig static bool IsNullableInt(!!T input) cil managed + { + // Code size 15 (0xf) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: box !!T + IL_0006: isinst valuetype [mscorlib]System.Nullable`1 + IL_000b: ldnull + IL_000c: cgt.un + IL_000e: ret + } // end of method Generics::IsNullableInt + .method public hidebysig static valuetype [mscorlib]System.Nullable`1 AsNullableInt(!!T input) cil managed { diff --git a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/Generics.opt.roslyn.il b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/Generics.opt.roslyn.il index 7fbf4f592..bf048290c 100644 --- a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/Generics.opt.roslyn.il +++ b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/Generics.opt.roslyn.il @@ -466,6 +466,18 @@ IL_000b: ret } // end of method Generics::GetEnumerator + .method public hidebysig static bool IsString(!!T input) cil managed + { + // Code size 15 (0xf) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: box !!T + IL_0006: isinst [mscorlib]System.String + IL_000b: ldnull + IL_000c: cgt.un + IL_000e: ret + } // end of method Generics::IsString + .method public hidebysig static string AsString(!!T input) cil managed { @@ -497,6 +509,18 @@ IL_0006: ret } // end of method Generics::CastFromString + .method public hidebysig static bool IsInt(!!T input) cil managed + { + // Code size 15 (0xf) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: box !!T + IL_0006: isinst [mscorlib]System.Int32 + IL_000b: ldnull + IL_000c: cgt.un + IL_000e: ret + } // end of method Generics::IsInt + .method public hidebysig static int32 CastToInt(!!T input) cil managed { // Code size 12 (0xc) @@ -517,6 +541,18 @@ IL_000b: ret } // end of method Generics::CastFromInt + .method public hidebysig static bool IsNullableInt(!!T input) cil managed + { + // Code size 15 (0xf) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: box !!T + IL_0006: isinst valuetype [mscorlib]System.Nullable`1 + IL_000b: ldnull + IL_000c: cgt.un + IL_000e: ret + } // end of method Generics::IsNullableInt + .method public hidebysig static valuetype [mscorlib]System.Nullable`1 AsNullableInt(!!T input) cil managed { diff --git a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/Generics.roslyn.il b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/Generics.roslyn.il index 65850a038..4b9989d1f 100644 --- a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/Generics.roslyn.il +++ b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/Generics.roslyn.il @@ -576,6 +576,24 @@ IL_0010: ret } // end of method Generics::GetEnumerator + .method public hidebysig static bool IsString(!!T input) cil managed + { + // Code size 20 (0x14) + .maxstack 2 + .locals init (bool V_0) + IL_0000: nop + IL_0001: ldarg.0 + IL_0002: box !!T + IL_0007: isinst [mscorlib]System.String + IL_000c: ldnull + IL_000d: cgt.un + IL_000f: stloc.0 + IL_0010: br.s IL_0012 + + IL_0012: ldloc.0 + IL_0013: ret + } // end of method Generics::IsString + .method public hidebysig static string AsString(!!T input) cil managed { @@ -625,6 +643,24 @@ IL_000b: ret } // end of method Generics::CastFromString + .method public hidebysig static bool IsInt(!!T input) cil managed + { + // Code size 20 (0x14) + .maxstack 2 + .locals init (bool V_0) + IL_0000: nop + IL_0001: ldarg.0 + IL_0002: box !!T + IL_0007: isinst [mscorlib]System.Int32 + IL_000c: ldnull + IL_000d: cgt.un + IL_000f: stloc.0 + IL_0010: br.s IL_0012 + + IL_0012: ldloc.0 + IL_0013: ret + } // end of method Generics::IsInt + .method public hidebysig static int32 CastToInt(!!T input) cil managed { // Code size 17 (0x11) @@ -657,6 +693,24 @@ IL_0010: ret } // end of method Generics::CastFromInt + .method public hidebysig static bool IsNullableInt(!!T input) cil managed + { + // Code size 20 (0x14) + .maxstack 2 + .locals init (bool V_0) + IL_0000: nop + IL_0001: ldarg.0 + IL_0002: box !!T + IL_0007: isinst valuetype [mscorlib]System.Nullable`1 + IL_000c: ldnull + IL_000d: cgt.un + IL_000f: stloc.0 + IL_0010: br.s IL_0012 + + IL_0012: ldloc.0 + IL_0013: ret + } // end of method Generics::IsNullableInt + .method public hidebysig static valuetype [mscorlib]System.Nullable`1 AsNullableInt(!!T input) cil managed { diff --git a/ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs b/ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs index 2bd7f9ec8..1d3e3cc1b 100644 --- a/ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs +++ b/ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs @@ -257,6 +257,7 @@ namespace ICSharpCode.Decompiler.CSharp TranslatedExpression IsType(IsInst inst) { var arg = Translate(inst.Argument); + arg = UnwrapBoxingConversion(arg); return new IsExpression(arg.Expression, ConvertType(inst.Type)) .WithILInstruction(inst) .WithRR(new TypeIsResolveResult(arg.ResolveResult, inst.Type, compilation.FindType(TypeCode.Boolean))); @@ -265,6 +266,7 @@ namespace ICSharpCode.Decompiler.CSharp protected internal override TranslatedExpression VisitIsInst(IsInst inst, TranslationContext context) { var arg = Translate(inst.Argument); + arg = UnwrapBoxingConversion(arg); if (inst.Type.IsReferenceType == false) { // isinst with a value type results in an expression of "boxed value type", // which is not supported in C#. @@ -284,7 +286,6 @@ namespace ICSharpCode.Decompiler.CSharp return ErrorExpression("isinst with value type is only supported in some contexts"); } } - arg = UnwrapBoxingConversion(arg); return new AsExpression(arg.Expression, ConvertType(inst.Type)) .WithILInstruction(inst) .WithRR(new ConversionResolveResult(inst.Type, arg.ResolveResult, Conversion.TryCast)); @@ -296,7 +297,7 @@ namespace ICSharpCode.Decompiler.CSharp && arg.Type.IsKnownType(KnownTypeCode.Object) && arg.ResolveResult is ConversionResolveResult crr && crr.Conversion.IsBoxingConversion) { - // When 'as' used with value type or type parameter, + // When 'is' or 'as' is used with a value type or type parameter, // the C# compiler implicitly boxes the input. arg = arg.UnwrapChild(cast.Expression); } diff --git a/ICSharpCode.Decompiler/CSharp/StatementBuilder.cs b/ICSharpCode.Decompiler/CSharp/StatementBuilder.cs index f19d52420..a230461eb 100644 --- a/ICSharpCode.Decompiler/CSharp/StatementBuilder.cs +++ b/ICSharpCode.Decompiler/CSharp/StatementBuilder.cs @@ -72,9 +72,11 @@ namespace ICSharpCode.Decompiler.CSharp // (even for value types) by using "is" instead of "as" // This can happen when the result of "expr is T" is unused // and the C# compiler optimizes away the null check portion of the "is" operator. + var arg = exprBuilder.Translate(inst.Argument); + arg = ExpressionBuilder.UnwrapBoxingConversion(arg); return new ExpressionStatement( new IsExpression( - exprBuilder.Translate(inst.Argument), + arg, exprBuilder.ConvertType(inst.Type) ) .WithRR(new ResolveResult(exprBuilder.compilation.FindType(KnownTypeCode.Boolean)))