Browse Source

Implement deconstruction discards

pull/2119/head
Siegfried Pammer 5 years ago
parent
commit
442f6f90b7
  1. 57
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/DeconstructionTests.cs
  2. 5
      ICSharpCode.Decompiler/IL/Instructions/DeconstructInstruction.cs
  3. 7
      ICSharpCode.Decompiler/IL/Transforms/DeconstructionTransform.cs

57
ICSharpCode.Decompiler.Tests/TestCases/Pretty/DeconstructionTests.cs

@ -51,6 +51,21 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty @@ -51,6 +51,21 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
}
}
private class DeconstructionSource<T, T2, T3>
{
public int Dummy {
get;
set;
}
public void Deconstruct(out T a, out T2 b, out T3 c)
{
a = default(T);
b = default(T2);
c = default(T3);
}
}
private class AssignmentTargets
{
public int IntField;
@ -97,6 +112,11 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty @@ -97,6 +112,11 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
return null;
}
private DeconstructionSource<T, T2, T3> GetSource<T, T2, T3>()
{
return null;
}
private AssignmentTargets Get(int i)
{
return null;
@ -111,6 +131,33 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty @@ -111,6 +131,33 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
Console.WriteLine(x);
}
public void LocalVariable_NoConversion_DiscardFirst()
{
MyInt x;
int value;
(_, x, value) = GetSource<MyInt?, MyInt, int>();
Console.WriteLine(x);
Console.WriteLine(value);
}
public void LocalVariable_NoConversion_DiscardLast()
{
MyInt? myInt3;
MyInt x;
(myInt3, x, _) = GetSource<MyInt?, MyInt, int>();
Console.WriteLine(myInt3);
Console.WriteLine(x);
}
public void LocalVariable_NoConversion_DiscardSecond()
{
MyInt? myInt3;
int value;
(myInt3, _, value) = GetSource<MyInt?, MyInt, int>();
Console.WriteLine(myInt3);
Console.WriteLine(value);
}
public void LocalVariable_NoConversion_ReferenceTypes()
{
string value;
@ -144,5 +191,15 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty @@ -144,5 +191,15 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
{
(Get(0).NMy, Get(1).My) = GetSource<MyInt?, MyInt>();
}
public void Property_NoConversion_DiscardFirst()
{
(_, Get(1).My) = GetSource<MyInt?, MyInt>();
}
public void Property_NoConversion_DiscardLast()
{
(Get(0).NMy, _) = GetSource<MyInt?, MyInt>();
}
}
}

5
ICSharpCode.Decompiler/IL/Instructions/DeconstructInstruction.cs

@ -273,8 +273,9 @@ namespace ICSharpCode.Decompiler.IL @@ -273,8 +273,9 @@ namespace ICSharpCode.Decompiler.IL
Debug.Assert(!inst.HasDesignator);
foreach (var subPattern in inst.SubPatterns.Cast<MatchInstruction>()) {
if (subPattern.IsVar) {
Debug.Assert(subPattern.Variable.IsSingleDefinition && subPattern.Variable.LoadCount == 1);
Debug.Assert(subPattern.Variable.LoadInstructions[0].IsDescendantOf(this));
Debug.Assert(subPattern.Variable.IsSingleDefinition && subPattern.Variable.LoadCount <= 1);
if (subPattern.Variable.LoadCount == 1)
Debug.Assert(subPattern.Variable.LoadInstructions[0].IsDescendantOf(this));
patternVariables.Add(subPattern.Variable);
} else {
ValidatePattern(subPattern);

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

@ -19,6 +19,7 @@ @@ -19,6 +19,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Resources;
using ICSharpCode.Decompiler.CSharp.Resolver;
using ICSharpCode.Decompiler.TypeSystem;
@ -188,7 +189,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -188,7 +189,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
return false;
// TODO v.LoadCount may be 2 if the deconstruction is assigned to a tuple variable
// or 0? because of discards
if (!(v.StoreCount == 0 && v.AddressCount == 1 && v.LoadCount == 1))
if (!(v.StoreCount == 0 && v.AddressCount == 1 && v.LoadCount <= 1))
return false;
deconstructionResultsLookup.Add(v, i - 1);
deconstructionResults.Add(v);
@ -311,7 +312,11 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -311,7 +312,11 @@ namespace ICSharpCode.Decompiler.IL.Transforms
bool MatchAssignment(ILInstruction inst, out IType targetType, out ILInstruction valueInst, out Action<DeconstructInstruction> addAssignment)
{
targetType = null;
valueInst = null;
addAssignment = null;
if (inst == null)
return false;
if (inst.MatchStLoc(out var v, out var value)
&& value is Block block && block.MatchInlineAssignBlock(out var call, out valueInst)) {
if (!DeconstructInstruction.IsAssignment(call, out targetType, out _))

Loading…
Cancel
Save