Browse Source

Use type `bool` for `logic.and`/`logic.or`.

pull/4091/head
Daniel Grunwald 3 days ago
parent
commit
cea8ff2dbb
  1. 27
      ICSharpCode.Decompiler/IL/Instructions/IfInstruction.cs
  2. 27
      ICSharpCode.Decompiler/IL/Transforms/ExpressionTransforms.cs

27
ICSharpCode.Decompiler/IL/Instructions/IfInstruction.cs

@ -39,7 +39,15 @@ namespace ICSharpCode.Decompiler.IL
partial class IfInstruction : ILInstruction partial class IfInstruction : ILInstruction
{ {
// null means void // null means void
readonly IType? resultType; IType? csharpType;
public IType? CSharpType {
get => csharpType;
set {
Debug.Assert(this.ResultType == (value?.GetStackType() ?? StackType.Void));
csharpType = value;
}
}
public IfInstruction(ILInstruction condition, ILInstruction trueInst, public IfInstruction(ILInstruction condition, ILInstruction trueInst,
ILInstruction? falseInst = null, IType? resultType = null) : base(OpCode.IfInstruction) ILInstruction? falseInst = null, IType? resultType = null) : base(OpCode.IfInstruction)
@ -48,7 +56,7 @@ namespace ICSharpCode.Decompiler.IL
this.TrueInst = trueInst; this.TrueInst = trueInst;
falseInst ??= new Nop(); falseInst ??= new Nop();
this.FalseInst = falseInst; this.FalseInst = falseInst;
this.resultType = resultType; this.csharpType = resultType;
Debug.Assert(condition.ResultType == StackType.I4); Debug.Assert(condition.ResultType == StackType.I4);
Debug.Assert(trueInst.ResultType == this.ResultType Debug.Assert(trueInst.ResultType == this.ResultType
|| trueInst.HasDirectFlag(InstructionFlags.EndPointUnreachable)); || trueInst.HasDirectFlag(InstructionFlags.EndPointUnreachable));
@ -80,15 +88,15 @@ namespace ICSharpCode.Decompiler.IL
public override StackType ResultType { public override StackType ResultType {
get { get {
if (resultType != null) if (csharpType != null)
return resultType.GetStackType(); return csharpType.GetStackType();
return StackType.Void; return StackType.Void;
} }
} }
public override IType InferType(ICompilation compilation) public override IType InferType(ICompilation compilation)
{ {
if (resultType != null) if (csharpType != null)
return resultType; return csharpType;
return compilation.FindType(KnownTypeCode.Void); return compilation.FindType(KnownTypeCode.Void);
} }
public override InstructionFlags DirectFlags => InstructionFlags.ControlFlow; public override InstructionFlags DirectFlags => InstructionFlags.ControlFlow;
@ -101,7 +109,8 @@ namespace ICSharpCode.Decompiler.IL
protected override void WriteToCore(ITextOutput output, ILAstWritingOptions options) protected override void WriteToCore(ITextOutput output, ILAstWritingOptions options)
{ {
WriteILRange(output, options); WriteILRange(output, options);
if (options.UseLogicOperationSugar) if (options.UseLogicOperationSugar
&& csharpType != null && csharpType.IsKnownType(KnownTypeCode.Boolean))
{ {
if (MatchLogicAnd(out var lhs, out var rhs)) if (MatchLogicAnd(out var lhs, out var rhs))
{ {
@ -123,10 +132,10 @@ namespace ICSharpCode.Decompiler.IL
} }
} }
output.Write(OpCode); output.Write(OpCode);
if (resultType != null) if (csharpType != null)
{ {
output.Write(" ["); output.Write(" [");
output.Write(resultType.ReflectionName); output.Write(csharpType.ReflectionName);
output.Write(']'); output.Write(']');
} }
output.Write(" ("); output.Write(" (");

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

@ -588,18 +588,33 @@ namespace ICSharpCode.Decompiler.IL.Transforms
IfInstruction HandleConditionalOperator(IfInstruction inst) IfInstruction HandleConditionalOperator(IfInstruction inst)
{ {
// if (cond) stloc A(V1) else stloc A(V2) --> stloc A(if (cond) V1 else V2) // if (cond) stloc A(V1) else stloc A(V2) --> stloc A(if (cond) V1 else V2)
Block trueInst = inst.TrueInst as Block; if (inst.TrueInst is not Block trueInst || trueInst.Instructions.Count != 1)
if (trueInst == null || trueInst.Instructions.Count != 1)
return inst; return inst;
Block falseInst = inst.FalseInst as Block; if (inst.FalseInst is not Block falseInst || falseInst.Instructions.Count != 1)
if (falseInst == null || falseInst.Instructions.Count != 1)
return inst; return inst;
ILVariable v; ILVariable v;
ILInstruction value1, value2; ILInstruction value1, value2;
if (trueInst.Instructions[0].MatchStLoc(out v, out value1) && falseInst.Instructions[0].MatchStLoc(v, out value2)) if (trueInst.Instructions[0].MatchStLoc(out v, out value1)
&& falseInst.Instructions[0].MatchStLoc(v, out value2))
{ {
context.Step("conditional operator", inst); context.Step("conditional operator", inst);
var newIf = new IfInstruction(Comp.LogicNot(inst.Condition), value2, value1, v.Type); IType type = v.Type;
// Try to tighten the type; this matters esp. for logic.and/logic.or:
IType type1 = value1.InferType(context.TypeSystem);
IType type2 = value2.InferType(context.TypeSystem);
if (type1.IsKnownType(KnownTypeCode.Boolean) && (
type2.IsKnownType(KnownTypeCode.Boolean)
|| value2 is LdcI4 { Value: 0 or 1 }
))
{
type = type1;
}
else if (type2.IsKnownType(KnownTypeCode.Boolean)
&& value1 is LdcI4 { Value: 0 or 1 })
{
type = type2;
}
var newIf = new IfInstruction(Comp.LogicNot(inst.Condition), value2, value1, type);
newIf.AddILRange(inst); newIf.AddILRange(inst);
var stLoc = new StLoc(v, newIf); var stLoc = new StLoc(v, newIf);
inst.ReplaceWith(stLoc); inst.ReplaceWith(stLoc);

Loading…
Cancel
Save