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

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

@ -588,18 +588,33 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -588,18 +588,33 @@ namespace ICSharpCode.Decompiler.IL.Transforms
IfInstruction HandleConditionalOperator(IfInstruction inst)
{
// if (cond) stloc A(V1) else stloc A(V2) --> stloc A(if (cond) V1 else V2)
Block trueInst = inst.TrueInst as Block;
if (trueInst == null || trueInst.Instructions.Count != 1)
if (inst.TrueInst is not Block trueInst || trueInst.Instructions.Count != 1)
return inst;
Block falseInst = inst.FalseInst as Block;
if (falseInst == null || falseInst.Instructions.Count != 1)
if (inst.FalseInst is not Block falseInst || falseInst.Instructions.Count != 1)
return inst;
ILVariable v;
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);
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);
var stLoc = new StLoc(v, newIf);
inst.ReplaceWith(stLoc);

Loading…
Cancel
Save