Skip to content

Commit

Permalink
Fix #1479: Unable to cast object of type 'System.Int32' to type 'Syst…
Browse files Browse the repository at this point in the history
…em.Single'
  • Loading branch information
siegfriedpammer committed Apr 7, 2019
1 parent b31d922 commit 3abb548
Show file tree
Hide file tree
Showing 5 changed files with 89 additions and 23 deletions.
Expand Up @@ -59,6 +59,7 @@
<None Include="TestCases\Correctness\StackTests.il" />
<None Include="TestCases\Correctness\StackTypes.il" />
<None Include="TestCases\Correctness\Uninit.vb" />
<None Include="TestCases\ILPretty\ConstantBlobs.il" />
<None Include="TestCases\ILPretty\FSharpLoops.fs" />
<None Include="TestCases\ILPretty\FSharpLoops_Debug.il" />
<None Include="TestCases\ILPretty\FSharpLoops_Release.il" />
Expand All @@ -71,6 +72,7 @@

<ItemGroup>
<Compile Include="DisassemblerPrettyTestRunner.cs" />
<Compile Include="TestCases\ILPretty\ConstantBlobs.cs" />
<Compile Include="TestCases\ILPretty\Issue1389.cs" />
<Compile Include="TestCases\ILPretty\Issue1454.cs" />
<Compile Include="TestCases\Pretty\Discards.cs" />
Expand Down
6 changes: 6 additions & 0 deletions ICSharpCode.Decompiler.Tests/ILPrettyTestRunner.cs
Expand Up @@ -148,6 +148,12 @@ public void Issue1454()
Run();
}

[Test]
public void ConstantBlobs()
{
Run();
}

[Test]
public void SequenceOfNestedIfs()
{
Expand Down
@@ -0,0 +1,9 @@
namespace ICSharpCode.Decompiler.Tests.TestCases.ILPretty
{
internal class ConstantBlobs
{
public static void Float_Int32(float f1 = 0f, float f2 = -1f, float f3 = int.MaxValue, float f4 = int.MinValue)
{
}
}
}
39 changes: 39 additions & 0 deletions ICSharpCode.Decompiler.Tests/TestCases/ILPretty/ConstantBlobs.il
@@ -0,0 +1,39 @@
// Metadata version: v4.0.30319
.assembly extern mscorlib
{
.publickeytoken = (B7 7A 5C 56 19 34 E0 89 ) // .z\V.4..
.ver 4:0:0:0
}
.assembly ConstantBlobs
{
.ver 1:0:0:0
}
.module ConstantBlobs.exe
// MVID: {B973FCD6-A9C4-48A9-8291-26DDC248E208}
.imagebase 0x00400000
.file alignment 0x00000200
.stackreserve 0x00100000
.subsystem 0x0003 // WINDOWS_CUI
.corflags 0x00020003 // ILONLY 32BITPREFERRED
// Image base: 0x000001C4B6C90000

.class private auto ansi beforefieldinit ICSharpCode.Decompiler.Tests.TestCases.ILPretty.ConstantBlobs
extends [mscorlib]System.Object
{
.method public hidebysig static void Float_Int32(
[opt] float32 f1,
[opt] float32 f2,
[opt] float32 f3,
[opt] float32 f4
) cil managed
{
.param [1] = int32(0)
.param [2] = int32(-1)
.param [3] = int32(2147483647)
.param [4] = int32(-2147483648)

// Code size 1 (0x1)
.maxstack 8
IL_0000: ret
} // end of method Program::Float_Int32
}
56 changes: 33 additions & 23 deletions ICSharpCode.Decompiler/CSharp/Syntax/TypeSystemAstBuilder.cs
Expand Up @@ -795,72 +795,78 @@ public Expression ConvertConstantValue(IType expectedType, IType type, object co
}
}

bool IsSpecialConstant(IType type, object constant, out Expression expression)
bool IsSpecialConstant(IType expectedType, object constant, out Expression expression)
{
expression = null;
if (!specialConstants.TryGetValue(constant, out var info))
return false;
// find IType of constant in compilation.
var constantType = expectedType;
if (!expectedType.IsKnownType(info.Type)) {
var compilation = expectedType.GetDefinition().Compilation;
constantType = compilation.FindType(info.Type);
}
// if the field definition cannot be found, do not generate a reference to the field.
var field = type.GetFields(p => p.Name == info.Member).SingleOrDefault();
var field = constantType.GetFields(p => p.Name == info.Member).SingleOrDefault();
if (!UseSpecialConstants || field == null) {
// +Infty, -Infty and NaN, cannot be represented in their encoded form.
// Use an equivalent arithmetic expression instead.
if (info.Type == KnownTypeCode.Double) {
switch ((double)constant) {
case double.NegativeInfinity: // (-1.0 / 0.0)
var left = new PrimitiveExpression(-1.0).WithoutILInstruction().WithRR(new ConstantResolveResult(type, -1.0));
var right = new PrimitiveExpression(0.0).WithoutILInstruction().WithRR(new ConstantResolveResult(type, 0.0));
var left = new PrimitiveExpression(-1.0).WithoutILInstruction().WithRR(new ConstantResolveResult(constantType, -1.0));
var right = new PrimitiveExpression(0.0).WithoutILInstruction().WithRR(new ConstantResolveResult(constantType, 0.0));
expression = new BinaryOperatorExpression(left, BinaryOperatorType.Divide, right).WithoutILInstruction()
.WithRR(new ConstantResolveResult(type, double.NegativeInfinity));
.WithRR(new ConstantResolveResult(constantType, double.NegativeInfinity));
return true;
case double.PositiveInfinity: // (1.0 / 0.0)
left = new PrimitiveExpression(1.0).WithoutILInstruction().WithRR(new ConstantResolveResult(type, 1.0));
right = new PrimitiveExpression(0.0).WithoutILInstruction().WithRR(new ConstantResolveResult(type, 0.0));
left = new PrimitiveExpression(1.0).WithoutILInstruction().WithRR(new ConstantResolveResult(constantType, 1.0));
right = new PrimitiveExpression(0.0).WithoutILInstruction().WithRR(new ConstantResolveResult(constantType, 0.0));
expression = new BinaryOperatorExpression(left, BinaryOperatorType.Divide, right).WithoutILInstruction()
.WithRR(new ConstantResolveResult(type, double.PositiveInfinity));
.WithRR(new ConstantResolveResult(constantType, double.PositiveInfinity));
return true;
case double.NaN: // (0.0 / 0.0)
left = new PrimitiveExpression(0.0).WithoutILInstruction().WithRR(new ConstantResolveResult(type, 0.0));
right = new PrimitiveExpression(0.0).WithoutILInstruction().WithRR(new ConstantResolveResult(type, 0.0));
left = new PrimitiveExpression(0.0).WithoutILInstruction().WithRR(new ConstantResolveResult(constantType, 0.0));
right = new PrimitiveExpression(0.0).WithoutILInstruction().WithRR(new ConstantResolveResult(constantType, 0.0));
expression = new BinaryOperatorExpression(left, BinaryOperatorType.Divide, right).WithoutILInstruction()
.WithRR(new ConstantResolveResult(type, double.NaN));
.WithRR(new ConstantResolveResult(constantType, double.NaN));
return true;
}
}
if (info.Type == KnownTypeCode.Single) {
switch ((float)constant) {
case float.NegativeInfinity: // (-1.0f / 0.0f)
var left = new PrimitiveExpression(-1.0f).WithoutILInstruction().WithRR(new ConstantResolveResult(type, -1.0f));
var right = new PrimitiveExpression(0.0f).WithoutILInstruction().WithRR(new ConstantResolveResult(type, 0.0f));
var left = new PrimitiveExpression(-1.0f).WithoutILInstruction().WithRR(new ConstantResolveResult(constantType, -1.0f));
var right = new PrimitiveExpression(0.0f).WithoutILInstruction().WithRR(new ConstantResolveResult(constantType, 0.0f));
expression = new BinaryOperatorExpression(left, BinaryOperatorType.Divide, right).WithoutILInstruction()
.WithRR(new ConstantResolveResult(type, float.NegativeInfinity));
.WithRR(new ConstantResolveResult(constantType, float.NegativeInfinity));
return true;
case float.PositiveInfinity: // (1.0f / 0.0f)
left = new PrimitiveExpression(1.0f).WithoutILInstruction().WithRR(new ConstantResolveResult(type, 1.0f));
right = new PrimitiveExpression(0.0f).WithoutILInstruction().WithRR(new ConstantResolveResult(type, 0.0f));
left = new PrimitiveExpression(1.0f).WithoutILInstruction().WithRR(new ConstantResolveResult(constantType, 1.0f));
right = new PrimitiveExpression(0.0f).WithoutILInstruction().WithRR(new ConstantResolveResult(constantType, 0.0f));
expression = new BinaryOperatorExpression(left, BinaryOperatorType.Divide, right).WithoutILInstruction()
.WithRR(new ConstantResolveResult(type, float.PositiveInfinity));
.WithRR(new ConstantResolveResult(constantType, float.PositiveInfinity));
return true;
case float.NaN: // (0.0f / 0.0f)
left = new PrimitiveExpression(0.0f).WithoutILInstruction().WithRR(new ConstantResolveResult(type, 0.0f));
right = new PrimitiveExpression(0.0f).WithoutILInstruction().WithRR(new ConstantResolveResult(type, 0.0f));
left = new PrimitiveExpression(0.0f).WithoutILInstruction().WithRR(new ConstantResolveResult(constantType, 0.0f));
right = new PrimitiveExpression(0.0f).WithoutILInstruction().WithRR(new ConstantResolveResult(constantType, 0.0f));
expression = new BinaryOperatorExpression(left, BinaryOperatorType.Divide, right).WithoutILInstruction()
.WithRR(new ConstantResolveResult(type, float.NaN));
.WithRR(new ConstantResolveResult(constantType, float.NaN));
return true;
}
}
return false;
}

expression = new TypeReferenceExpression(ConvertType(type));
expression = new TypeReferenceExpression(ConvertType(constantType));

if (AddResolveResultAnnotations)
expression.AddAnnotation(new TypeResolveResult(type));
expression.AddAnnotation(new TypeResolveResult(constantType));

expression = new MemberReferenceExpression(expression, info.Member);

if (AddResolveResultAnnotations)
expression.AddAnnotation(new MemberResolveResult(new TypeResolveResult(type), field));
expression.AddAnnotation(new MemberResolveResult(new TypeResolveResult(constantType), field));

return true;
}
Expand Down Expand Up @@ -1005,6 +1011,10 @@ static bool IsEqual(long num, long den, object constantValue, bool isDouble)

Expression ConvertFloatingPointLiteral(IType type, object constantValue)
{
// Coerce constantValue to either float or double:
// There are compilers that embed 0 (and possible other values) as int into constant value signatures,
// even if the expected type is float or double.
constantValue = CSharpPrimitiveCast.Cast(type.GetTypeCode(), constantValue, false);
bool isDouble = type.IsKnownType(KnownTypeCode.Double);
ICompilation compilation = type.GetDefinition().Compilation;
Expression expr = null;
Expand Down

0 comments on commit 3abb548

Please sign in to comment.