Browse Source

Fix Deconstruction for Deconstruct instance methods of value-types.

pull/2642/head
Siegfried Pammer 4 years ago
parent
commit
5f73bfbb01
  1. 13
      ICSharpCode.Decompiler/CSharp/StatementBuilder.cs
  2. 3
      ICSharpCode.Decompiler/IL/Instructions/MatchInstruction.cs
  3. 10
      ICSharpCode.Decompiler/IL/Transforms/DeconstructionTransform.cs
  4. 3
      ICSharpCode.Decompiler/IL/Transforms/ILInlining.cs

13
ICSharpCode.Decompiler/CSharp/StatementBuilder.cs

@ -962,8 +962,7 @@ namespace ICSharpCode.Decompiler.CSharp
return RequiredGetCurrentTransformation.NoForeach; return RequiredGetCurrentTransformation.NoForeach;
} }
if (loopBody.Instructions[0] is DeconstructInstruction deconstruction if (loopBody.Instructions[0] is DeconstructInstruction deconstruction
&& singleGetter == deconstruction.Pattern.TestedOperand && CanBeDeconstructedInForeach(deconstruction, singleGetter, usingContainer, loopContainer))
&& CanBeDeconstructedInForeach(deconstruction, usingContainer, loopContainer))
{ {
return RequiredGetCurrentTransformation.Deconstruction; return RequiredGetCurrentTransformation.Deconstruction;
} }
@ -992,13 +991,19 @@ namespace ICSharpCode.Decompiler.CSharp
return RequiredGetCurrentTransformation.IntroduceNewVariable; return RequiredGetCurrentTransformation.IntroduceNewVariable;
} }
bool CanBeDeconstructedInForeach(DeconstructInstruction deconstruction, BlockContainer usingContainer, BlockContainer loopContainer) bool CanBeDeconstructedInForeach(DeconstructInstruction deconstruction, ILInstruction singleGetter, BlockContainer usingContainer, BlockContainer loopContainer)
{ {
ILInstruction testedOperand = deconstruction.Pattern.TestedOperand;
if (testedOperand != singleGetter)
{
if (!(testedOperand is AddressOf addressOf && addressOf.Value == singleGetter))
return false;
}
if (deconstruction.Init.Count > 0) if (deconstruction.Init.Count > 0)
return false; return false;
if (deconstruction.Conversions.Instructions.Count > 0) if (deconstruction.Conversions.Instructions.Count > 0)
return false; return false;
var operandType = deconstruction.Pattern.TestedOperand.InferType(this.typeSystem); var operandType = singleGetter.InferType(this.typeSystem);
var expectedType = deconstruction.Pattern.Variable.Type; var expectedType = deconstruction.Pattern.Variable.Type;
if (!NormalizeTypeVisitor.TypeErasure.EquivalentTypes(operandType, expectedType)) if (!NormalizeTypeVisitor.TypeErasure.EquivalentTypes(operandType, expectedType))
return false; return false;

3
ICSharpCode.Decompiler/IL/Instructions/MatchInstruction.cs

@ -218,8 +218,7 @@ namespace ICSharpCode.Decompiler.IL
internal static bool IsDeconstructMethod(IMethod? method) internal static bool IsDeconstructMethod(IMethod? method)
{ {
if (method == null if (method == null)
)
return false; return false;
if (method.Name != "Deconstruct") if (method.Name != "Deconstruct")
return false; return false;

10
ICSharpCode.Decompiler/IL/Transforms/DeconstructionTransform.cs

@ -272,8 +272,16 @@ namespace ICSharpCode.Decompiler.IL.Transforms
return false; return false;
if (!MatchInstruction.IsDeconstructMethod(call.Method)) if (!MatchInstruction.IsDeconstructMethod(call.Method))
return false; return false;
if (call.Method.IsStatic == call is CallVirt) if (call.Method.IsStatic || call.Method.DeclaringType.IsReferenceType == false)
{
if (!(call is Call))
return false;
}
else
{
if (!(call is CallVirt))
return false; return false;
}
if (call.Arguments.Count < 3) if (call.Arguments.Count < 3)
return false; return false;
deconstructionResults = new ILVariable[call.Arguments.Count - 1]; deconstructionResults = new ILVariable[call.Arguments.Count - 1];

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

@ -377,6 +377,9 @@ namespace ICSharpCode.Decompiler.IL.Transforms
return true; return true;
case OpCode.NullableUnwrap: case OpCode.NullableUnwrap:
return ((NullableUnwrap)inst.Parent).RefInput; return ((NullableUnwrap)inst.Parent).RefInput;
case OpCode.MatchInstruction:
method = ((MatchInstruction)inst.Parent).Method;
return true;
default: default:
return false; return false;
} }

Loading…
Cancel
Save