From 442f6f90b7b362b4a6cc35ac386ecde77c83b2ad Mon Sep 17 00:00:00 2001 From: Siegfried Pammer Date: Sun, 16 Aug 2020 11:49:39 +0200 Subject: [PATCH] Implement deconstruction discards --- .../TestCases/Pretty/DeconstructionTests.cs | 57 +++++++++++++++++++ .../IL/Instructions/DeconstructInstruction.cs | 5 +- .../IL/Transforms/DeconstructionTransform.cs | 7 ++- 3 files changed, 66 insertions(+), 3 deletions(-) diff --git a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/DeconstructionTests.cs b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/DeconstructionTests.cs index b68aa524a..e86156723 100644 --- a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/DeconstructionTests.cs +++ b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/DeconstructionTests.cs @@ -51,6 +51,21 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty } } + private class DeconstructionSource + { + 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 return null; } + private DeconstructionSource GetSource() + { + return null; + } + private AssignmentTargets Get(int i) { return null; @@ -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(); + Console.WriteLine(x); + Console.WriteLine(value); + } + + public void LocalVariable_NoConversion_DiscardLast() + { + MyInt? myInt3; + MyInt x; + (myInt3, x, _) = GetSource(); + Console.WriteLine(myInt3); + Console.WriteLine(x); + } + + public void LocalVariable_NoConversion_DiscardSecond() + { + MyInt? myInt3; + int value; + (myInt3, _, value) = GetSource(); + Console.WriteLine(myInt3); + Console.WriteLine(value); + } + public void LocalVariable_NoConversion_ReferenceTypes() { string value; @@ -144,5 +191,15 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty { (Get(0).NMy, Get(1).My) = GetSource(); } + + public void Property_NoConversion_DiscardFirst() + { + (_, Get(1).My) = GetSource(); + } + + public void Property_NoConversion_DiscardLast() + { + (Get(0).NMy, _) = GetSource(); + } } } diff --git a/ICSharpCode.Decompiler/IL/Instructions/DeconstructInstruction.cs b/ICSharpCode.Decompiler/IL/Instructions/DeconstructInstruction.cs index ad1b511a6..2a0cbd165 100644 --- a/ICSharpCode.Decompiler/IL/Instructions/DeconstructInstruction.cs +++ b/ICSharpCode.Decompiler/IL/Instructions/DeconstructInstruction.cs @@ -273,8 +273,9 @@ namespace ICSharpCode.Decompiler.IL Debug.Assert(!inst.HasDesignator); foreach (var subPattern in inst.SubPatterns.Cast()) { 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); diff --git a/ICSharpCode.Decompiler/IL/Transforms/DeconstructionTransform.cs b/ICSharpCode.Decompiler/IL/Transforms/DeconstructionTransform.cs index 23f6ae238..ce6c736d4 100644 --- a/ICSharpCode.Decompiler/IL/Transforms/DeconstructionTransform.cs +++ b/ICSharpCode.Decompiler/IL/Transforms/DeconstructionTransform.cs @@ -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 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 bool MatchAssignment(ILInstruction inst, out IType targetType, out ILInstruction valueInst, out Action 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 _))