Browse Source

TransformExpressionTrees: compare operand stack types, not operand types

A conversion of a small integer type to Int32 returns its operand unchanged,
because such values already occupy an I4 stack slot. The two operands of
`(short a, int b) => a + b` are therefore Int16 and Int32, and requiring them
to be equal rejected the conversion; the whole expression tree was then left
untransformed, or worse, aborted the enclosing method. What
BinaryNumericInstruction requires of its operands is a common stack type.

TryConvertExpressionTree also has to cope with a builder that fails, rather
than dereferencing the lambda it did not get.

Assisted-by: Claude:claude-opus-5[1m]:Claude Code
pull/4091/head
Siegfried Pammer 2 weeks ago committed by Daniel Grunwald
parent
commit
9947ad528a
  1. 11
      ICSharpCode.Decompiler/IL/Transforms/TransformExpressionTrees.cs

11
ICSharpCode.Decompiler/IL/Transforms/TransformExpressionTrees.cs

@ -172,6 +172,8 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -172,6 +172,8 @@ namespace ICSharpCode.Decompiler.IL.Transforms
{
context.Step("Convert Expression Tree", instruction);
var newLambda = (ILFunction)lambda();
if (newLambda == null)
return false;
SetExpressionTreeFlag(newLambda, (CallInstruction)instruction);
instruction.ReplaceWith(newLambda);
context.EndStep(newLambda);
@ -642,8 +644,15 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -642,8 +644,15 @@ namespace ICSharpCode.Decompiler.IL.Transforms
}
else
{
if (!rightType.Equals(leftType))
// Compare the stack types rather than the types themselves: a conversion
// of a small integer type to Int32 leaves its operand unchanged, because
// such values already occupy an I4 stack slot, so the two sides of
// `(short a, int b) => a + b` are Int16 and Int32 at this point.
if (NullableType.GetUnderlyingType(rightType).GetStackType()
!= NullableType.GetUnderlyingType(leftType).GetStackType())
{
return null;
}
}
if (leftType.IsKnownType(KnownTypeCode.Decimal))
{

Loading…
Cancel
Save