diff --git a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/InlineAssignmentTest.cs b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/InlineAssignmentTest.cs
index cc0887987..f32d2fb6b 100644
--- a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/InlineAssignmentTest.cs
+++ b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/InlineAssignmentTest.cs
@@ -51,12 +51,16 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
Console.WriteLine(InlineAssignmentTest.field2 = new InlineAssignmentTest());
Console.WriteLine(InlineAssignmentTest.field2);
this.UseShort(this.field4 = 6);
+ this.UseShort(this.field4 = -10000);
+ this.UseShort(this.field4 = (short)this.field1);
+ this.UseShort(this.field4 = this.UseShort(0));
Console.WriteLine(this.field4);
}
- public void UseShort(short s)
+ public short UseShort(short s)
{
Console.WriteLine(s);
+ return s;
}
public void ReadLoop1(TextReader r)
diff --git a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/InlineAssignmentTest.il b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/InlineAssignmentTest.il
index ec2d0ea7e..9a1797896 100644
--- a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/InlineAssignmentTest.il
+++ b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/InlineAssignmentTest.il
@@ -10,7 +10,7 @@
.publickeytoken = (B7 7A 5C 56 19 34 E0 89 ) // .z\V.4..
.ver 4:0:0:0
}
-.assembly uq03kalt
+.assembly w1xqybg1
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.CompilationRelaxationsAttribute::.ctor(int32) = ( 01 00 08 00 00 00 00 00 )
.custom instance void [mscorlib]System.Runtime.CompilerServices.RuntimeCompatibilityAttribute::.ctor() = ( 01 00 01 00 54 02 16 57 72 61 70 4E 6F 6E 45 78 // ....T..WrapNonEx
@@ -20,15 +20,15 @@
.hash algorithm 0x00008004
.ver 0:0:0:0
}
-.module uq03kalt.dll
-// MVID: {D636DE2E-D2CD-4EDF-B87B-0B0985C6C0B8}
+.module w1xqybg1.dll
+// MVID: {1BE5829A-0D5E-43DC-8C02-E3012B1780A2}
.custom instance void [mscorlib]System.Security.UnverifiableCodeAttribute::.ctor() = ( 01 00 00 00 )
.imagebase 0x10000000
.file alignment 0x00000200
.stackreserve 0x00100000
.subsystem 0x0003 // WINDOWS_CUI
.corflags 0x00000001 // ILONLY
-// Image base: 0x018D0000
+// Image base: 0x033B0000
// =============== CLASS MEMBERS DECLARATION ===================
@@ -93,7 +93,7 @@
.method public hidebysig instance void
SimpleInlineWithFields2() cil managed
{
- // Code size 87 (0x57)
+ // Code size 154 (0x9a)
.maxstack 4
.locals init (int32 V_0,
int16 V_1)
@@ -125,25 +125,62 @@
IL_003d: stloc.1
IL_003e: stfld int16 ICSharpCode.Decompiler.Tests.TestCases.Pretty.InlineAssignmentTest::field4
IL_0043: ldloc.1
- IL_0044: call instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.InlineAssignmentTest::UseShort(int16)
- IL_0049: nop
+ IL_0044: call instance int16 ICSharpCode.Decompiler.Tests.TestCases.Pretty.InlineAssignmentTest::UseShort(int16)
+ IL_0049: pop
IL_004a: ldarg.0
- IL_004b: ldfld int16 ICSharpCode.Decompiler.Tests.TestCases.Pretty.InlineAssignmentTest::field4
- IL_0050: call void [mscorlib]System.Console::WriteLine(int32)
- IL_0055: nop
- IL_0056: ret
+ IL_004b: ldarg.0
+ IL_004c: ldc.i4 0xffffd8f0
+ IL_0051: dup
+ IL_0052: stloc.1
+ IL_0053: stfld int16 ICSharpCode.Decompiler.Tests.TestCases.Pretty.InlineAssignmentTest::field4
+ IL_0058: ldloc.1
+ IL_0059: call instance int16 ICSharpCode.Decompiler.Tests.TestCases.Pretty.InlineAssignmentTest::UseShort(int16)
+ IL_005e: pop
+ IL_005f: ldarg.0
+ IL_0060: ldarg.0
+ IL_0061: ldarg.0
+ IL_0062: ldfld int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.InlineAssignmentTest::field1
+ IL_0067: conv.i2
+ IL_0068: dup
+ IL_0069: stloc.1
+ IL_006a: stfld int16 ICSharpCode.Decompiler.Tests.TestCases.Pretty.InlineAssignmentTest::field4
+ IL_006f: ldloc.1
+ IL_0070: call instance int16 ICSharpCode.Decompiler.Tests.TestCases.Pretty.InlineAssignmentTest::UseShort(int16)
+ IL_0075: pop
+ IL_0076: ldarg.0
+ IL_0077: ldarg.0
+ IL_0078: ldarg.0
+ IL_0079: ldc.i4.0
+ IL_007a: call instance int16 ICSharpCode.Decompiler.Tests.TestCases.Pretty.InlineAssignmentTest::UseShort(int16)
+ IL_007f: dup
+ IL_0080: stloc.1
+ IL_0081: stfld int16 ICSharpCode.Decompiler.Tests.TestCases.Pretty.InlineAssignmentTest::field4
+ IL_0086: ldloc.1
+ IL_0087: call instance int16 ICSharpCode.Decompiler.Tests.TestCases.Pretty.InlineAssignmentTest::UseShort(int16)
+ IL_008c: pop
+ IL_008d: ldarg.0
+ IL_008e: ldfld int16 ICSharpCode.Decompiler.Tests.TestCases.Pretty.InlineAssignmentTest::field4
+ IL_0093: call void [mscorlib]System.Console::WriteLine(int32)
+ IL_0098: nop
+ IL_0099: ret
} // end of method InlineAssignmentTest::SimpleInlineWithFields2
- .method public hidebysig instance void
+ .method public hidebysig instance int16
UseShort(int16 s) cil managed
{
- // Code size 9 (0x9)
- .maxstack 8
+ // Code size 14 (0xe)
+ .maxstack 1
+ .locals init (int16 V_0)
IL_0000: nop
IL_0001: ldarg.1
IL_0002: call void [mscorlib]System.Console::WriteLine(int32)
IL_0007: nop
- IL_0008: ret
+ IL_0008: ldarg.1
+ IL_0009: stloc.0
+ IL_000a: br.s IL_000c
+
+ IL_000c: ldloc.0
+ IL_000d: ret
} // end of method InlineAssignmentTest::UseShort
.method public hidebysig instance void
diff --git a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/InlineAssignmentTest.opt.il b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/InlineAssignmentTest.opt.il
index f98d18c87..2f944dee2 100644
--- a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/InlineAssignmentTest.opt.il
+++ b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/InlineAssignmentTest.opt.il
@@ -10,7 +10,7 @@
.publickeytoken = (B7 7A 5C 56 19 34 E0 89 ) // .z\V.4..
.ver 4:0:0:0
}
-.assembly zztqnmi4
+.assembly f1ibwsev
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.CompilationRelaxationsAttribute::.ctor(int32) = ( 01 00 08 00 00 00 00 00 )
.custom instance void [mscorlib]System.Runtime.CompilerServices.RuntimeCompatibilityAttribute::.ctor() = ( 01 00 01 00 54 02 16 57 72 61 70 4E 6F 6E 45 78 // ....T..WrapNonEx
@@ -20,15 +20,15 @@
.hash algorithm 0x00008004
.ver 0:0:0:0
}
-.module zztqnmi4.dll
-// MVID: {038F2DF5-AE7B-4B0A-B846-AC254CE46038}
+.module f1ibwsev.dll
+// MVID: {8DB4E6AA-A0C2-49F3-8E9C-A28CE30F145A}
.custom instance void [mscorlib]System.Security.UnverifiableCodeAttribute::.ctor() = ( 01 00 00 00 )
.imagebase 0x10000000
.file alignment 0x00000200
.stackreserve 0x00100000
.subsystem 0x0003 // WINDOWS_CUI
.corflags 0x00000001 // ILONLY
-// Image base: 0x006A0000
+// Image base: 0x01400000
// =============== CLASS MEMBERS DECLARATION ===================
@@ -85,10 +85,13 @@
.method public hidebysig instance void
SimpleInlineWithFields2() cil managed
{
- // Code size 80 (0x50)
+ // Code size 150 (0x96)
.maxstack 4
.locals init (int32 V_0,
- int16 V_1)
+ int16 V_1,
+ int16 V_2,
+ int16 V_3,
+ int16 V_4)
IL_0000: ldarg.0
IL_0001: ldc.i4.5
IL_0002: dup
@@ -112,21 +115,54 @@
IL_0038: stloc.1
IL_0039: stfld int16 ICSharpCode.Decompiler.Tests.TestCases.Pretty.InlineAssignmentTest::field4
IL_003e: ldloc.1
- IL_003f: call instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.InlineAssignmentTest::UseShort(int16)
- IL_0044: ldarg.0
- IL_0045: ldfld int16 ICSharpCode.Decompiler.Tests.TestCases.Pretty.InlineAssignmentTest::field4
- IL_004a: call void [mscorlib]System.Console::WriteLine(int32)
- IL_004f: ret
+ IL_003f: call instance int16 ICSharpCode.Decompiler.Tests.TestCases.Pretty.InlineAssignmentTest::UseShort(int16)
+ IL_0044: pop
+ IL_0045: ldarg.0
+ IL_0046: ldarg.0
+ IL_0047: ldc.i4 0xffffd8f0
+ IL_004c: dup
+ IL_004d: stloc.2
+ IL_004e: stfld int16 ICSharpCode.Decompiler.Tests.TestCases.Pretty.InlineAssignmentTest::field4
+ IL_0053: ldloc.2
+ IL_0054: call instance int16 ICSharpCode.Decompiler.Tests.TestCases.Pretty.InlineAssignmentTest::UseShort(int16)
+ IL_0059: pop
+ IL_005a: ldarg.0
+ IL_005b: ldarg.0
+ IL_005c: ldarg.0
+ IL_005d: ldfld int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.InlineAssignmentTest::field1
+ IL_0062: conv.i2
+ IL_0063: dup
+ IL_0064: stloc.3
+ IL_0065: stfld int16 ICSharpCode.Decompiler.Tests.TestCases.Pretty.InlineAssignmentTest::field4
+ IL_006a: ldloc.3
+ IL_006b: call instance int16 ICSharpCode.Decompiler.Tests.TestCases.Pretty.InlineAssignmentTest::UseShort(int16)
+ IL_0070: pop
+ IL_0071: ldarg.0
+ IL_0072: ldarg.0
+ IL_0073: ldarg.0
+ IL_0074: ldc.i4.0
+ IL_0075: call instance int16 ICSharpCode.Decompiler.Tests.TestCases.Pretty.InlineAssignmentTest::UseShort(int16)
+ IL_007a: dup
+ IL_007b: stloc.s V_4
+ IL_007d: stfld int16 ICSharpCode.Decompiler.Tests.TestCases.Pretty.InlineAssignmentTest::field4
+ IL_0082: ldloc.s V_4
+ IL_0084: call instance int16 ICSharpCode.Decompiler.Tests.TestCases.Pretty.InlineAssignmentTest::UseShort(int16)
+ IL_0089: pop
+ IL_008a: ldarg.0
+ IL_008b: ldfld int16 ICSharpCode.Decompiler.Tests.TestCases.Pretty.InlineAssignmentTest::field4
+ IL_0090: call void [mscorlib]System.Console::WriteLine(int32)
+ IL_0095: ret
} // end of method InlineAssignmentTest::SimpleInlineWithFields2
- .method public hidebysig instance void
+ .method public hidebysig instance int16
UseShort(int16 s) cil managed
{
- // Code size 7 (0x7)
+ // Code size 8 (0x8)
.maxstack 8
IL_0000: ldarg.1
IL_0001: call void [mscorlib]System.Console::WriteLine(int32)
- IL_0006: ret
+ IL_0006: ldarg.1
+ IL_0007: ret
} // end of method InlineAssignmentTest::UseShort
.method public hidebysig instance void
diff --git a/ICSharpCode.Decompiler/IL/Transforms/TransformAssignment.cs b/ICSharpCode.Decompiler/IL/Transforms/TransformAssignment.cs
index f631b5312..00542ee18 100644
--- a/ICSharpCode.Decompiler/IL/Transforms/TransformAssignment.cs
+++ b/ICSharpCode.Decompiler/IL/Transforms/TransformAssignment.cs
@@ -268,9 +268,55 @@ namespace ICSharpCode.Decompiler.IL.Transforms
return true;
}
+ ///
+ /// Gets whether 'stobj type(..., value)' would evaluate to a different value than 'value'
+ /// due to implicit truncation.
+ ///
bool IsImplicitTruncation(ILInstruction value, IType type)
{
- return type.IsSmallIntegerType();
+ if (!type.IsSmallIntegerType()) {
+ // Implicit truncation in ILAst only happens for small integer types;
+ // other types of implicit truncation in IL cause the ILReader to insert
+ // conv instructions.
+ return false;
+ }
+ // With small integer types, test whether the value being stored
+ // is being truncated:
+ if (value.MatchLdcI4(out int val)) {
+ switch (type.GetEnumUnderlyingType().GetDefinition()?.KnownTypeCode) {
+ case KnownTypeCode.Boolean:
+ return !(val == 0 || val == 1);
+ case KnownTypeCode.Byte:
+ return !(val >= byte.MinValue && val <= byte.MaxValue);
+ case KnownTypeCode.SByte:
+ return !(val >= sbyte.MinValue && val <= sbyte.MaxValue);
+ case KnownTypeCode.Int16:
+ return !(val >= short.MinValue && val <= short.MaxValue);
+ case KnownTypeCode.UInt16:
+ case KnownTypeCode.Char:
+ return !(val >= ushort.MinValue && val <= ushort.MaxValue);
+ }
+ } else if (value is LdObj ldobj) {
+ return IsImplicitTruncation(ldobj.Type, type);
+ } else if (value is StObj stobj) {
+ return IsImplicitTruncation(stobj.Type, type);
+ } else if (value is LdLoc ldloc) {
+ return IsImplicitTruncation(ldloc.Variable.Type, type);
+ } else if (value is StLoc stloc) {
+ return IsImplicitTruncation(stloc.Variable.Type, type);
+ } else if (value is CallInstruction call) {
+ return IsImplicitTruncation(call.Method.ReturnType, type);
+ } else if (value is Conv conv) {
+ return conv.TargetType != type.ToPrimitiveType();
+ } else if (value is Comp) {
+ return false; // comp returns 0 or 1, which always fits
+ }
+ return true;
+ }
+
+ bool IsImplicitTruncation(IType fromType, IType toType)
+ {
+ return !(fromType.GetSize() <= toType.GetSize() && fromType.GetSign() == toType.GetSign());
}
///