Browse Source

Make NullableLiftingTransform handle the case where ExpressionTransforms.VisitComp already lifted a nullable comparison with constant.

pull/3243/head
Siegfried Pammer 10 months ago
parent
commit
28aa88bfb8
  1. 5
      ICSharpCode.Decompiler/IL/Transforms/ExpressionTransforms.cs
  2. 31
      ICSharpCode.Decompiler/IL/Transforms/NullableLiftingTransform.cs

5
ICSharpCode.Decompiler/IL/Transforms/ExpressionTransforms.cs

@ -106,7 +106,10 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -106,7 +106,10 @@ namespace ICSharpCode.Decompiler.IL.Transforms
inst.Left.AcceptVisitor(this);
return;
}
new NullableLiftingTransform(context).Run(inst);
if (context.Settings.LiftNullables)
{
new NullableLiftingTransform(context).Run(inst);
}
base.VisitComp(inst);
if (inst.IsLifted)

31
ICSharpCode.Decompiler/IL/Transforms/NullableLiftingTransform.cs

@ -225,14 +225,14 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -225,14 +225,14 @@ namespace ICSharpCode.Decompiler.IL.Transforms
return LiftCSharpEqualityComparison(comp, ComparisonKind.Inequality, trueInst)
?? LiftCSharpUserEqualityComparison(comp, ComparisonKind.Inequality, trueInst);
}
else if (IsGenericNewPattern(comp.Left, comp.Right, trueInst, falseInst))
else if (!comp.IsLifted && IsGenericNewPattern(comp.Left, comp.Right, trueInst, falseInst))
{
// (default(T) == null) ? Activator.CreateInstance<T>() : default(T)
// => Activator.CreateInstance<T>()
return trueInst;
}
}
else
else if (!comp.IsLifted)
{
// Not (in)equality, but one of < <= > >=.
// Returns false unless all HasValue bits are true.
@ -401,11 +401,12 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -401,11 +401,12 @@ namespace ICSharpCode.Decompiler.IL.Transforms
{
result = default(CompOrDecimal);
result.Instruction = inst;
if (inst is Comp comp && !comp.IsLifted)
if (inst is Comp comp)
{
result.Kind = comp.Kind;
result.Left = comp.Left;
result.Right = comp.Right;
result.IsLifted = comp.IsLifted;
return true;
}
else if (inst is Call call && call.Method.IsOperator && call.Arguments.Count == 2 && !call.IsLifted)
@ -449,6 +450,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -449,6 +450,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
public ComparisonKind Kind;
public ILInstruction Left;
public ILInstruction Right;
public bool IsLifted;
public IType LeftExpectedType {
get {
@ -528,6 +530,8 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -528,6 +530,8 @@ namespace ICSharpCode.Decompiler.IL.Transforms
// The HasValue comparison must be the same operator as the Value comparison.
if (hasValueTest is Comp hasValueComp)
{
if (valueComp.IsLifted || hasValueComp.IsLifted)
return null;
// Comparing two nullables: HasValue comparison must be the same operator as the Value comparison
if ((hasValueTestNegated ? hasValueComp.Kind.Negate() : hasValueComp.Kind) != newComparisonKind)
return null;
@ -576,6 +580,24 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -576,6 +580,24 @@ namespace ICSharpCode.Decompiler.IL.Transforms
/// </summary>
ILInstruction LiftCSharpComparison(CompOrDecimal comp, ComparisonKind newComparisonKind)
{
if (comp.IsLifted)
{
// Happens when legacy csc generates 'num.GetValueOrDefault() == const && num.HasValue',
// checking HasValue is redundant here, modern Roslyn versions optimize it and our
// NullableLifting transform on Comp will already lift the lhs of the logic.and.
// Treat this case as if the transform had not undone the optimization yet.
if (nullableVars.Count != 1)
{
return null;
}
if (comp.Left.MatchLdLoc(nullableVars[0]) || comp.Right.MatchLdLoc(nullableVars[0]))
{
return comp.MakeLifted(newComparisonKind, comp.Left.Clone(), comp.Right.Clone());
}
return null;
}
var (left, right, bits) = DoLiftBinary(comp.Left, comp.Right, comp.LeftExpectedType, comp.RightExpectedType);
// due to the restrictions on side effects, we only allow instructions that are pure after lifting.
// (we can't check this before lifting due to the calls to GetValueOrDefault())
@ -611,7 +633,8 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -611,7 +633,8 @@ namespace ICSharpCode.Decompiler.IL.Transforms
// call op_Inequality(call GetValueOrDefault(ldloca nullable1), call GetValueOrDefault(ldloca nullable2))
// else
// ldc.i4 0
if (hasValueComp.IsLifted)
return null;
if (!MatchHasValueCall(hasValueComp.Left, out ILVariable nullable1))
return null;
if (!MatchHasValueCall(hasValueComp.Right, out ILVariable nullable2))

Loading…
Cancel
Save