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
} }
} }
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 private class AssignmentTargets
{ {
public int IntField; public int IntField;
@ -97,6 +112,11 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
return null; return null;
} }
private DeconstructionSource<T, T2, T3> GetSource<T, T2, T3>()
{
return null;
}
private AssignmentTargets Get(int i) private AssignmentTargets Get(int i)
{ {
return null; return null;
@ -111,6 +131,33 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
Console.WriteLine(x); 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() public void LocalVariable_NoConversion_ReferenceTypes()
{ {
string value; string value;
@ -144,5 +191,15 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
{ {
(Get(0).NMy, Get(1).My) = GetSource<MyInt?, MyInt>(); (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
Debug.Assert(!inst.HasDesignator); Debug.Assert(!inst.HasDesignator);
foreach (var subPattern in inst.SubPatterns.Cast<MatchInstruction>()) { foreach (var subPattern in inst.SubPatterns.Cast<MatchInstruction>()) {
if (subPattern.IsVar) { if (subPattern.IsVar) {
Debug.Assert(subPattern.Variable.IsSingleDefinition && subPattern.Variable.LoadCount == 1); Debug.Assert(subPattern.Variable.IsSingleDefinition && subPattern.Variable.LoadCount <= 1);
Debug.Assert(subPattern.Variable.LoadInstructions[0].IsDescendantOf(this)); if (subPattern.Variable.LoadCount == 1)
Debug.Assert(subPattern.Variable.LoadInstructions[0].IsDescendantOf(this));
patternVariables.Add(subPattern.Variable); patternVariables.Add(subPattern.Variable);
} else { } else {
ValidatePattern(subPattern); ValidatePattern(subPattern);

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

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

Loading…
Cancel
Save