Browse Source

Fix Deconstruction for Deconstruct instance methods of value-types.

pull/2642/head
Siegfried Pammer 3 years ago
parent
commit
5f73bfbb01
  1. 13
      ICSharpCode.Decompiler/CSharp/StatementBuilder.cs
  2. 3
      ICSharpCode.Decompiler/IL/Instructions/MatchInstruction.cs
  3. 12
      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 @@ -962,8 +962,7 @@ namespace ICSharpCode.Decompiler.CSharp
return RequiredGetCurrentTransformation.NoForeach;
}
if (loopBody.Instructions[0] is DeconstructInstruction deconstruction
&& singleGetter == deconstruction.Pattern.TestedOperand
&& CanBeDeconstructedInForeach(deconstruction, usingContainer, loopContainer))
&& CanBeDeconstructedInForeach(deconstruction, singleGetter, usingContainer, loopContainer))
{
return RequiredGetCurrentTransformation.Deconstruction;
}
@ -992,13 +991,19 @@ namespace ICSharpCode.Decompiler.CSharp @@ -992,13 +991,19 @@ namespace ICSharpCode.Decompiler.CSharp
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)
return false;
if (deconstruction.Conversions.Instructions.Count > 0)
return false;
var operandType = deconstruction.Pattern.TestedOperand.InferType(this.typeSystem);
var operandType = singleGetter.InferType(this.typeSystem);
var expectedType = deconstruction.Pattern.Variable.Type;
if (!NormalizeTypeVisitor.TypeErasure.EquivalentTypes(operandType, expectedType))
return false;

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

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

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

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

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

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

Loading…
Cancel
Save