Browse Source

Support short-circuiting operators with dynamic. (e.g. "if (x.A && x.B)" where "x" is dynamic)

pull/1236/head
Daniel Grunwald 7 years ago
parent
commit
dd5845e83d
  1. 37
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/CustomShortCircuitOperators.cs
  2. 1206
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/CustomShortCircuitOperators.il
  3. 1103
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/CustomShortCircuitOperators.opt.il
  4. 1043
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/CustomShortCircuitOperators.opt.roslyn.il
  5. 1157
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/CustomShortCircuitOperators.roslyn.il
  6. 69
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/DynamicTests.cs
  7. 2485
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/DynamicTests.il
  8. 2337
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/DynamicTests.opt.il
  9. 2165
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/DynamicTests.opt.roslyn.il
  10. 2357
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/DynamicTests.roslyn.il
  11. 17
      ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs
  12. 4
      ICSharpCode.Decompiler/CSharp/StatementBuilder.cs
  13. 105
      ICSharpCode.Decompiler/IL/Instructions.cs
  14. 10
      ICSharpCode.Decompiler/IL/Instructions.tt
  15. 49
      ICSharpCode.Decompiler/IL/Instructions/DynamicInstructions.cs
  16. 3
      ICSharpCode.Decompiler/IL/Transforms/ExpressionTransforms.cs
  17. 1
      ICSharpCode.Decompiler/IL/Transforms/ILInlining.cs
  18. 106
      ICSharpCode.Decompiler/IL/Transforms/UserDefinedLogicTransform.cs
  19. 31
      ICSharpCode.Decompiler/TypeSystem/NormalizeTypeVisitor.cs

37
ICSharpCode.Decompiler.Tests/TestCases/Pretty/CustomShortCircuitOperators.cs

@ -82,13 +82,14 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty.CustomShortCircuitOperat @@ -82,13 +82,14 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty.CustomShortCircuitOperat
private static void Test2()
{
C c = new C();
if (c && c) {
Console.WriteLine(c.ToString());
if (GetC(1) && GetC(2)) {
Console.WriteLine(GetC(3));
}
if (!(c && c)) {
Console.WriteLine(c.ToString());
if (GetC(1) || GetC(2)) {
Console.WriteLine(GetC(3));
}
if (!(GetC(1) && GetC(2))) {
Console.WriteLine(GetC(3));
}
}
@ -102,6 +103,18 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty.CustomShortCircuitOperat @@ -102,6 +103,18 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty.CustomShortCircuitOperat
Console.WriteLine(c.ToString());
}
}
public void WithDynamic(dynamic d)
{
Console.WriteLine(GetC(1) && d.P);
Console.WriteLine(GetC(2) || d.P);
if (GetC(3) && d.P) {
Console.WriteLine(GetC(4));
}
if (GetC(5) || d.P) {
Console.WriteLine(GetC(6));
}
}
}
internal struct S
@ -167,5 +180,17 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty.CustomShortCircuitOperat @@ -167,5 +180,17 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty.CustomShortCircuitOperat
Console.WriteLine("e");
}
}
public void WithDynamic(dynamic d)
{
Console.WriteLine(Get(1) && d.P);
Console.WriteLine(Get(2) || d.P);
if (Get(3) && d.P) {
Console.WriteLine(Get(4));
}
if (Get(5) || d.P) {
Console.WriteLine(Get(6));
}
}
}
}

1206
ICSharpCode.Decompiler.Tests/TestCases/Pretty/CustomShortCircuitOperators.il

File diff suppressed because it is too large Load Diff

1103
ICSharpCode.Decompiler.Tests/TestCases/Pretty/CustomShortCircuitOperators.opt.il

File diff suppressed because it is too large Load Diff

1043
ICSharpCode.Decompiler.Tests/TestCases/Pretty/CustomShortCircuitOperators.opt.roslyn.il

File diff suppressed because it is too large Load Diff

1157
ICSharpCode.Decompiler.Tests/TestCases/Pretty/CustomShortCircuitOperators.roslyn.il

File diff suppressed because it is too large Load Diff

69
ICSharpCode.Decompiler.Tests/TestCases/Pretty/DynamicTests.cs

@ -369,10 +369,71 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty @@ -369,10 +369,71 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
private static void If2(dynamic a, dynamic b)
{
// TODO : beautify complex conditions
//if (a == null || b == null) {
// Console.WriteLine("Equal");
//}
if (a == null || b == null) {
Console.WriteLine("One is null");
}
}
private static void If3(dynamic a, dynamic b)
{
if (a == null && b == null) {
Console.WriteLine("Both are null");
}
}
private static void If4(dynamic a, dynamic b)
{
if ((a == null || b == null) && GetDynamic(1) && !(GetDynamic(2) && GetDynamic(3))) {
Console.WriteLine("then");
} else {
Console.WriteLine("else");
}
}
private static dynamic GetDynamic(int i)
{
return null;
}
private static bool GetBool(int i)
{
return false;
}
private static dynamic LogicAnd()
{
return GetDynamic(1) && GetDynamic(2);
}
private static dynamic LogicAnd(dynamic a, dynamic b)
{
return a && b;
}
private static void LogicAndExtended(int i, dynamic d)
{
Console.WriteLine(GetDynamic(1) && GetDynamic(2));
Console.WriteLine(GetDynamic(1) && GetBool(2));
Console.WriteLine(GetBool(1) && GetDynamic(2));
Console.WriteLine(i == 1 && d == null);
}
private static dynamic LogicOr()
{
return GetDynamic(1) || GetDynamic(2);
}
private static dynamic LogicOr(dynamic a, dynamic b)
{
return a || b;
}
private static void LogicOrExtended(int i, dynamic d)
{
Console.WriteLine(GetDynamic(1) || GetDynamic(2));
Console.WriteLine(GetDynamic(1) || GetBool(2));
Console.WriteLine(GetBool(1) || GetDynamic(2));
Console.WriteLine(i == 1 || d == null);
}
}
}

2485
ICSharpCode.Decompiler.Tests/TestCases/Pretty/DynamicTests.il

File diff suppressed because it is too large Load Diff

2337
ICSharpCode.Decompiler.Tests/TestCases/Pretty/DynamicTests.opt.il

File diff suppressed because it is too large Load Diff

2165
ICSharpCode.Decompiler.Tests/TestCases/Pretty/DynamicTests.opt.roslyn.il

File diff suppressed because it is too large Load Diff

2357
ICSharpCode.Decompiler.Tests/TestCases/Pretty/DynamicTests.roslyn.il

File diff suppressed because it is too large Load Diff

17
ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs

@ -2581,6 +2581,23 @@ namespace ICSharpCode.Decompiler.CSharp @@ -2581,6 +2581,23 @@ namespace ICSharpCode.Decompiler.CSharp
}
}
protected internal override TranslatedExpression VisitDynamicLogicOperatorInstruction(DynamicLogicOperatorInstruction inst, TranslationContext context)
{
BinaryOperatorType operatorType;
if (inst.Operation == ExpressionType.AndAlso) {
operatorType = BinaryOperatorType.ConditionalAnd;
} else if (inst.Operation == ExpressionType.OrElse) {
operatorType = BinaryOperatorType.ConditionalOr;
} else {
Debug.Fail("Unknown operation for DynamicLogicOperatorInstruction");
return base.VisitDynamicLogicOperatorInstruction(inst, context);
}
var left = TranslateDynamicArgument(inst.Left, inst.LeftArgumentInfo);
var right = TranslateDynamicArgument(inst.Right, inst.RightArgumentInfo);
var boe = new BinaryOperatorExpression(left.Expression, operatorType, right.Expression);
return boe.WithILInstruction(inst).WithRR(new ResolveResult(SpecialType.Dynamic));
}
protected internal override TranslatedExpression VisitDynamicUnaryOperatorInstruction(DynamicUnaryOperatorInstruction inst, TranslationContext context)
{
switch (inst.Operation) {

4
ICSharpCode.Decompiler/CSharp/StatementBuilder.cs

@ -566,9 +566,7 @@ namespace ICSharpCode.Decompiler.CSharp @@ -566,9 +566,7 @@ namespace ICSharpCode.Decompiler.CSharp
static bool EqualErasedType(IType a, IType b)
{
a = a.AcceptVisitor(NormalizeTypeVisitor.TypeErasure);
b = b.AcceptVisitor(NormalizeTypeVisitor.TypeErasure);
return a.Equals(b);
return NormalizeTypeVisitor.TypeErasure.EquivalentTypes(a, b);
}
private bool IsDynamicCastToIEnumerable(Expression expr, out Expression dynamicExpr)

105
ICSharpCode.Decompiler/IL/Instructions.cs

@ -189,6 +189,8 @@ namespace ICSharpCode.Decompiler.IL @@ -189,6 +189,8 @@ namespace ICSharpCode.Decompiler.IL
ExpressionTreeCast,
/// <summary>Use of user-defined && or || operator.</summary>
UserDefinedLogicOperator,
/// <summary>ILAst representation of a short-circuiting binary operator inside a dynamic expression.</summary>
DynamicLogicOperatorInstruction,
/// <summary>ILAst representation of a binary operator inside a dynamic expression (maps to Binder.BinaryOperation).</summary>
DynamicBinaryOperatorInstruction,
/// <summary>ILAst representation of a unary operator inside a dynamic expression (maps to Binder.UnaryOperation).</summary>
@ -4952,6 +4954,94 @@ namespace ICSharpCode.Decompiler.IL @@ -4952,6 +4954,94 @@ namespace ICSharpCode.Decompiler.IL
}
}
namespace ICSharpCode.Decompiler.IL
{
/// <summary>ILAst representation of a short-circuiting binary operator inside a dynamic expression.</summary>
public sealed partial class DynamicLogicOperatorInstruction : DynamicInstruction
{
public static readonly SlotInfo LeftSlot = new SlotInfo("Left", canInlineInto: true);
ILInstruction left;
public ILInstruction Left {
get { return this.left; }
set {
ValidateChild(value);
SetChildInstruction(ref this.left, value, 0);
}
}
public static readonly SlotInfo RightSlot = new SlotInfo("Right");
ILInstruction right;
public ILInstruction Right {
get { return this.right; }
set {
ValidateChild(value);
SetChildInstruction(ref this.right, value, 1);
}
}
protected sealed override int GetChildCount()
{
return 2;
}
protected sealed override ILInstruction GetChild(int index)
{
switch (index) {
case 0:
return this.left;
case 1:
return this.right;
default:
throw new IndexOutOfRangeException();
}
}
protected sealed override void SetChild(int index, ILInstruction value)
{
switch (index) {
case 0:
this.Left = value;
break;
case 1:
this.Right = value;
break;
default:
throw new IndexOutOfRangeException();
}
}
protected sealed override SlotInfo GetChildSlot(int index)
{
switch (index) {
case 0:
return LeftSlot;
case 1:
return RightSlot;
default:
throw new IndexOutOfRangeException();
}
}
public sealed override ILInstruction Clone()
{
var clone = (DynamicLogicOperatorInstruction)ShallowClone();
clone.Left = this.left.Clone();
clone.Right = this.right.Clone();
return clone;
}
public override void AcceptVisitor(ILVisitor visitor)
{
visitor.VisitDynamicLogicOperatorInstruction(this);
}
public override T AcceptVisitor<T>(ILVisitor<T> visitor)
{
return visitor.VisitDynamicLogicOperatorInstruction(this);
}
public override T AcceptVisitor<C, T>(ILVisitor<C, T> visitor, C context)
{
return visitor.VisitDynamicLogicOperatorInstruction(this, context);
}
protected internal override bool PerformMatch(ILInstruction other, ref Patterns.Match match)
{
var o = other as DynamicLogicOperatorInstruction;
return o != null && this.left.PerformMatch(o.left, ref match) && this.right.PerformMatch(o.right, ref match);
}
}
}
namespace ICSharpCode.Decompiler.IL
{
/// <summary>ILAst representation of a binary operator inside a dynamic expression (maps to Binder.BinaryOperation).</summary>
public sealed partial class DynamicBinaryOperatorInstruction : DynamicInstruction
@ -6499,6 +6589,10 @@ namespace ICSharpCode.Decompiler.IL @@ -6499,6 +6589,10 @@ namespace ICSharpCode.Decompiler.IL
{
Default(inst);
}
protected internal virtual void VisitDynamicLogicOperatorInstruction(DynamicLogicOperatorInstruction inst)
{
Default(inst);
}
protected internal virtual void VisitDynamicBinaryOperatorInstruction(DynamicBinaryOperatorInstruction inst)
{
Default(inst);
@ -6873,6 +6967,10 @@ namespace ICSharpCode.Decompiler.IL @@ -6873,6 +6967,10 @@ namespace ICSharpCode.Decompiler.IL
{
return Default(inst);
}
protected internal virtual T VisitDynamicLogicOperatorInstruction(DynamicLogicOperatorInstruction inst)
{
return Default(inst);
}
protected internal virtual T VisitDynamicBinaryOperatorInstruction(DynamicBinaryOperatorInstruction inst)
{
return Default(inst);
@ -7247,6 +7345,10 @@ namespace ICSharpCode.Decompiler.IL @@ -7247,6 +7345,10 @@ namespace ICSharpCode.Decompiler.IL
{
return Default(inst, context);
}
protected internal virtual T VisitDynamicLogicOperatorInstruction(DynamicLogicOperatorInstruction inst, C context)
{
return Default(inst, context);
}
protected internal virtual T VisitDynamicBinaryOperatorInstruction(DynamicBinaryOperatorInstruction inst, C context)
{
return Default(inst, context);
@ -7390,7 +7492,8 @@ namespace ICSharpCode.Decompiler.IL @@ -7390,7 +7492,8 @@ namespace ICSharpCode.Decompiler.IL
"array.to.pointer",
"string.to.int",
"expression.tree.cast",
"user.logic.op",
"user.logic.operator",
"dynamic.logic.operator",
"dynamic.binary.operator",
"dynamic.unary.operator",
"dynamic.convert",

10
ICSharpCode.Decompiler/IL/Instructions.tt

@ -279,7 +279,7 @@ @@ -279,7 +279,7 @@
CustomClassName("ExpressionTreeCast"), Unary, HasTypeOperand, MayThrow, CustomConstructor, CustomWriteTo, ResultType("type.GetStackType()"),
MatchCondition("this.IsChecked == o.IsChecked")),
new OpCode("user.logic.op", "Use of user-defined && or || operator.",
new OpCode("user.logic.operator", "Use of user-defined && or || operator.",
CustomClassName("UserDefinedLogicOperator"),
HasMethodOperand, ResultType("O"),
CustomChildren(new []{
@ -288,6 +288,14 @@ @@ -288,6 +288,14 @@
}),
CustomComputeFlags // MayThrow, SideEffect, ControlFlow
),
new OpCode("dynamic.logic.operator", "ILAst representation of a short-circuiting binary operator inside a dynamic expression.",
CustomClassName("DynamicLogicOperatorInstruction"), Dynamic, CustomComputeFlags,
CustomChildren(new []{
new ChildInfo("left") { CanInlineInto = true },
new ChildInfo("right") { CanInlineInto = false } // only executed depending on value of left
}), CustomWriteTo
),
new OpCode("dynamic.binary.operator", "ILAst representation of a binary operator inside a dynamic expression (maps to Binder.BinaryOperation).",
CustomClassName("DynamicBinaryOperatorInstruction"), Dynamic, CustomArguments(("left", null), ("right", null)), CustomWriteTo),

49
ICSharpCode.Decompiler/IL/Instructions/DynamicInstructions.cs

@ -420,6 +420,55 @@ namespace ICSharpCode.Decompiler.IL @@ -420,6 +420,55 @@ namespace ICSharpCode.Decompiler.IL
}
}
partial class DynamicLogicOperatorInstruction
{
public CSharpArgumentInfo LeftArgumentInfo { get; }
public CSharpArgumentInfo RightArgumentInfo { get; }
public ExpressionType Operation { get; }
public DynamicLogicOperatorInstruction(CSharpBinderFlags binderFlags, ExpressionType operation, IType context, CSharpArgumentInfo leftArgumentInfo, ILInstruction left, CSharpArgumentInfo rightArgumentInfo, ILInstruction right)
: base(OpCode.DynamicLogicOperatorInstruction, binderFlags, context)
{
Operation = operation;
LeftArgumentInfo = leftArgumentInfo;
Left = left;
RightArgumentInfo = rightArgumentInfo;
Right = right;
}
public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
{
ILRange.WriteTo(output, options);
output.Write(OpCode);
WriteBinderFlags(output, options);
output.Write(' ');
output.Write(Operation.ToString());
WriteArgumentList(output, options, (Left, LeftArgumentInfo), (Right, RightArgumentInfo));
}
public override StackType ResultType => StackType.O;
protected override InstructionFlags ComputeFlags()
{
return DirectFlags | Left.Flags
| SemanticHelper.CombineBranches(Right.Flags, InstructionFlags.None);
}
public override InstructionFlags DirectFlags => InstructionFlags.MayThrow | InstructionFlags.SideEffect | InstructionFlags.ControlFlow;
public override CSharpArgumentInfo GetArgumentInfoOfChild(int index)
{
switch (index) {
case 0:
return LeftArgumentInfo;
case 1:
return RightArgumentInfo;
default:
throw new ArgumentOutOfRangeException(nameof(index));
}
}
}
partial class DynamicUnaryOperatorInstruction
{
public CSharpArgumentInfo OperandArgumentInfo { get; }

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

@ -335,6 +335,9 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -335,6 +335,9 @@ namespace ICSharpCode.Decompiler.IL.Transforms
return;
if (inst.MatchIfInstructionPositiveCondition(out var condition, out var trueInst, out var falseInst)) {
ILInstruction transformed = UserDefinedLogicTransform.Transform(condition, trueInst, falseInst);
if (transformed == null) {
transformed = UserDefinedLogicTransform.TransformDynamic(condition, trueInst, falseInst);
}
if (transformed != null) {
context.Step("User-defined short-circuiting logic operator (roslyn pattern)", condition);
transformed.AddILRange(inst.ILRange);

1
ICSharpCode.Decompiler/IL/Transforms/ILInlining.cs

@ -351,6 +351,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -351,6 +351,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
case OpCode.NullableUnwrap:
return true; // inline into ?. operator
case OpCode.UserDefinedLogicOperator:
case OpCode.DynamicLogicOperatorInstruction:
return true; // inline into (left slot of) user-defined && or || operator
case OpCode.DynamicGetMemberInstruction:
case OpCode.DynamicGetIndexInstruction:

106
ICSharpCode.Decompiler/IL/Transforms/UserDefinedLogicTransform.cs

@ -18,7 +18,11 @@ @@ -18,7 +18,11 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using ICSharpCode.Decompiler.TypeSystem;
using ICSharpCode.Decompiler.Util;
namespace ICSharpCode.Decompiler.IL.Transforms
{
@ -50,6 +54,9 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -50,6 +54,9 @@ namespace ICSharpCode.Decompiler.IL.Transforms
}
if (trueInst.MatchReturn(out var trueValue) && falseInst.MatchReturn(out var falseValue)) {
var transformed = Transform(condition, trueValue, falseValue);
if (transformed == null) {
transformed = TransformDynamic(condition, trueValue, falseValue);
}
if (transformed != null) {
context.Step("User-defined short-circuiting logic operator (optimized return)", condition);
((Leave)block.Instructions[pos + 1]).Value = transformed;
@ -146,5 +153,104 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -146,5 +153,104 @@ namespace ICSharpCode.Decompiler.IL.Transforms
result.AddILRange(call.ILRange);
return result;
}
public static ILInstruction TransformDynamic(ILInstruction condition, ILInstruction trueInst, ILInstruction falseInst)
{
// Check condition:
System.Linq.Expressions.ExpressionType unaryOp;
if (condition.MatchLdLoc(out var lhsVar)) {
// if (ldloc lhsVar) box bool(ldloc lhsVar) else dynamic.binary.operator.logic Or(ldloc lhsVar, rhsInst)
// -> dynamic.logic.operator OrElse(ldloc lhsVar, rhsInst)
if (trueInst is Box box && box.Type.IsKnownType(KnownTypeCode.Boolean)) {
unaryOp = System.Linq.Expressions.ExpressionType.IsTrue;
trueInst = box.Argument;
} else if (falseInst is Box box2 && box2.Type.IsKnownType(KnownTypeCode.Boolean)) {
// negate condition and swap true/false
unaryOp = System.Linq.Expressions.ExpressionType.IsFalse;
falseInst = trueInst;
trueInst = box2.Argument;
} else {
return null;
}
} else if (condition is DynamicUnaryOperatorInstruction unary) {
// if (dynamic.unary.operator IsFalse(ldloc lhsVar)) ldloc lhsVar else dynamic.binary.operator.logic And(ldloc lhsVar, rhsInst)
// -> dynamic.logic.operator AndAlso(ldloc lhsVar, rhsInst)
unaryOp = unary.Operation;
if (!unary.Operand.MatchLdLoc(out lhsVar))
return null;
} else if (MatchCondition(condition, out lhsVar, out string operatorMethodName)) {
// if (call op_False(ldloc s)) box S(ldloc s) else dynamic.binary.operator.logic And(ldloc s, rhsInst))
if (operatorMethodName == "op_True") {
unaryOp = System.Linq.Expressions.ExpressionType.IsTrue;
} else {
Debug.Assert(operatorMethodName == "op_False");
unaryOp = System.Linq.Expressions.ExpressionType.IsFalse;
}
var callParamType = ((Call)condition).Method.Parameters.Single().Type.SkipModifiers();
if (callParamType.IsReferenceType == false) {
// If lhs is a value type, eliminate the boxing instruction.
if (trueInst is Box box && NormalizeTypeVisitor.TypeErasure.EquivalentTypes(box.Type, callParamType)) {
trueInst = box.Argument;
} else if (trueInst.OpCode == OpCode.LdcI4) {
// special case, handled below in 'check trueInst'
} else {
return null;
}
}
} else {
return null;
}
// Check trueInst:
DynamicUnaryOperatorInstruction rhsUnary;
if (trueInst.MatchLdLoc(lhsVar)) {
// OK, typical pattern where the expression evaluates to 'dynamic'
rhsUnary = null;
} else if (trueInst.MatchLdcI4(1) && unaryOp == System.Linq.Expressions.ExpressionType.IsTrue) {
// logic.or(IsTrue(lhsVar), IsTrue(lhsVar | rhsInst))
// => IsTrue(lhsVar || rhsInst)
rhsUnary = falseInst as DynamicUnaryOperatorInstruction;
if (rhsUnary != null) {
if (rhsUnary.Operation != System.Linq.Expressions.ExpressionType.IsTrue)
return null;
falseInst = rhsUnary.Operand;
} else {
return null;
}
} else {
return null;
}
System.Linq.Expressions.ExpressionType expectedBitop;
System.Linq.Expressions.ExpressionType logicOp;
if (unaryOp == System.Linq.Expressions.ExpressionType.IsFalse) {
expectedBitop = System.Linq.Expressions.ExpressionType.And;
logicOp = System.Linq.Expressions.ExpressionType.AndAlso;
} else if (unaryOp == System.Linq.Expressions.ExpressionType.IsTrue) {
expectedBitop = System.Linq.Expressions.ExpressionType.Or;
logicOp = System.Linq.Expressions.ExpressionType.OrElse;
} else {
return null;
}
// Check falseInst:
if (!(falseInst is DynamicBinaryOperatorInstruction binary))
return null;
if (binary.Operation != expectedBitop)
return null;
if (!binary.Left.MatchLdLoc(lhsVar))
return null;
var logicInst = new DynamicLogicOperatorInstruction(binary.BinderFlags, logicOp, binary.CallingContext,
binary.LeftArgumentInfo, binary.Left, binary.RightArgumentInfo, binary.Right)
{
ILRange = binary.ILRange
};
if (rhsUnary != null) {
rhsUnary.Operand = logicInst;
return rhsUnary;
} else {
return logicInst;
}
}
}
}

31
ICSharpCode.Decompiler/TypeSystem/NormalizeTypeVisitor.cs

@ -15,9 +15,20 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -15,9 +15,20 @@ namespace ICSharpCode.Decompiler.TypeSystem
ReplaceClassTypeParametersWithDummy = false,
ReplaceMethodTypeParametersWithDummy = false,
DynamicAndObject = true,
TupleToUnderlyingType = true
TupleToUnderlyingType = true,
RemoveModOpt = true,
RemoveModReq = true,
};
public bool EquivalentTypes(IType a, IType b)
{
a = a.AcceptVisitor(this);
b = b.AcceptVisitor(this);
return a.Equals(b);
}
public bool RemoveModOpt = true;
public bool RemoveModReq = true;
public bool ReplaceClassTypeParametersWithDummy = true;
public bool ReplaceMethodTypeParametersWithDummy = true;
public bool DynamicAndObject = true;
@ -52,5 +63,23 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -52,5 +63,23 @@ namespace ICSharpCode.Decompiler.TypeSystem
return base.VisitTupleType(type);
}
}
public override IType VisitModOpt(ModifiedType type)
{
if (RemoveModOpt) {
return type.ElementType.AcceptVisitor(this);
} else {
return base.VisitModOpt(type);
}
}
public override IType VisitModReq(ModifiedType type)
{
if (RemoveModReq) {
return type.ElementType.AcceptVisitor(this);
} else {
return base.VisitModReq(type);
}
}
}
}

Loading…
Cancel
Save