Skip to content

Commit

Permalink
Merge pull request #1134 from icsharpcode/tuple
Browse files Browse the repository at this point in the history
C# 7.0 tuples
  • Loading branch information
dgrunwald committed May 29, 2018
2 parents b3db473 + 5cdd5ec commit 5c0c492
Show file tree
Hide file tree
Showing 51 changed files with 2,737 additions and 324 deletions.
16 changes: 7 additions & 9 deletions ICSharpCode.Decompiler.Tests/Helpers/RemoveCompilerAttribute.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@

namespace ICSharpCode.Decompiler.Tests.Helpers
{
class RemoveCompilerAttribute : DepthFirstAstVisitor<object, object>, IAstTransform
class RemoveCompilerAttribute : DepthFirstAstVisitor, IAstTransform
{
public override object VisitAttribute(CSharp.Syntax.Attribute attribute, object data)
public override void VisitAttribute(CSharp.Syntax.Attribute attribute)
{
var section = (AttributeSection)attribute.Parent;
SimpleType type = attribute.Type as SimpleType;
Expand All @@ -25,38 +25,36 @@ public override object VisitAttribute(CSharp.Syntax.Attribute attribute, object
if (section.Attributes.Count == 0)
section.Remove();
}
return null;
}

public void Run(AstNode rootNode, TransformContext context)
{
rootNode.AcceptVisitor(this, null);
rootNode.AcceptVisitor(this);
}
}

public class RemoveEmbeddedAtttributes : DepthFirstAstVisitor<object, object>, IAstTransform
public class RemoveEmbeddedAtttributes : DepthFirstAstVisitor, IAstTransform
{
HashSet<string> attributeNames = new HashSet<string>() {
"System.Runtime.CompilerServices.IsReadOnlyAttribute",
"System.Runtime.CompilerServices.IsByRefLikeAttribute",
"Microsoft.CodeAnalysis.EmbeddedAttribute",
};

public override object VisitTypeDeclaration(TypeDeclaration typeDeclaration, object data)
public override void VisitTypeDeclaration(TypeDeclaration typeDeclaration)
{
var typeDefinition = typeDeclaration.GetSymbol() as ITypeDefinition;
if (typeDefinition == null || !attributeNames.Contains(typeDefinition.FullName))
return null;
return;
if (typeDeclaration.Parent is NamespaceDeclaration ns && ns.Members.Count == 1)
ns.Remove();
else
typeDeclaration.Remove();
return null;
}

public void Run(AstNode rootNode, TransformContext context)
{
rootNode.AcceptVisitor(this, null);
rootNode.AcceptVisitor(this);
}
}
}
3 changes: 2 additions & 1 deletion ICSharpCode.Decompiler.Tests/Helpers/Tester.cs
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,8 @@ private static string ReplacePrivImplDetails(string il)
MetadataReference.CreateFromFile(Path.Combine(refAsmPath, "mscorlib.dll")),
MetadataReference.CreateFromFile(Path.Combine(refAsmPath, "System.dll")),
MetadataReference.CreateFromFile(Path.Combine(refAsmPath, "System.Core.dll")),
MetadataReference.CreateFromFile(Path.Combine(refAsmPath, "System.Xml.dll"))
MetadataReference.CreateFromFile(Path.Combine(refAsmPath, "System.Xml.dll")),
MetadataReference.CreateFromFile(typeof(ValueTuple).Assembly.Location)
};
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@
<Compile Include="TestCases\Pretty\Issue1080.cs" />
<Compile Include="TestCases\Pretty\QualifierTests.cs" />
<Compile Include="TestCases\Pretty\RefLocalsAndReturns.cs" />
<Compile Include="TestCases\Pretty\TupleTests.cs" />
<Compile Include="TestCases\Pretty\WellKnownConstants.cs" />
<Compile Include="TypeSystem\TypeSystemHelper.cs" />
<Compile Include="TypeSystem\TypeSystemLoaderTests.cs" />
Expand Down
6 changes: 6 additions & 0 deletions ICSharpCode.Decompiler.Tests/PrettyTestRunner.cs
Original file line number Diff line number Diff line change
Expand Up @@ -279,6 +279,12 @@ public void QualifierTests([ValueSource("defaultOptions")] CSharpCompilerOptions
RunForLibrary(cscOptions: cscOptions);
}

[Test]
public void TupleTests([ValueSource("roslynOnlyOptions")] CSharpCompilerOptions cscOptions)
{
RunForLibrary(cscOptions: cscOptions);
}

[Test]
public void Issue1080([ValueSource(nameof(roslynOnlyOptions))] CSharpCompilerOptions cscOptions)
{
Expand Down
27 changes: 27 additions & 0 deletions ICSharpCode.Decompiler.Tests/Semantics/ConversionTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Immutable;
using ICSharpCode.Decompiler.CSharp.Resolver;
using ICSharpCode.Decompiler.Semantics;
using ICSharpCode.Decompiler.Tests.TypeSystem;
Expand Down Expand Up @@ -88,6 +89,32 @@ public void ComplexDynamicIdentityConversions()
Assert.AreEqual(C.None, ImplicitConversion(typeof(List<List<object>[,]>), typeof(List<List<dynamic>[]>)));
}

[Test]
public void TupleIdentityConversions()
{
var intType = compilation.FindType(typeof(int));
var stringType = compilation.FindType(typeof(string));
Assert.AreEqual(C.IdentityConversion, conversions.ImplicitConversion(
new TupleType(compilation, ImmutableArray.Create(intType, stringType), ImmutableArray.Create("a", "b")),
new TupleType(compilation, ImmutableArray.Create(intType, stringType), ImmutableArray.Create("a", "c"))));

Assert.AreEqual(C.None, conversions.ImplicitConversion(
new TupleType(compilation, ImmutableArray.Create(intType, stringType), ImmutableArray.Create("a", "b")),
new TupleType(compilation, ImmutableArray.Create(stringType, intType), ImmutableArray.Create("a", "b"))));
}

[Test]
public void TupleConversions()
{
Assert.AreEqual(
C.TupleConversion(ImmutableArray.Create(C.ImplicitNumericConversion, C.ImplicitReferenceConversion)),
ImplicitConversion(typeof((int, string)), typeof((long, object))));

Assert.AreEqual(
C.TupleConversion(ImmutableArray.Create(C.ImplicitNumericConversion)),
ImplicitConversion(typeof(ValueTuple<float>), typeof(ValueTuple<double>)));
}

[Test]
public void PrimitiveConversions()
{
Expand Down
100 changes: 100 additions & 0 deletions ICSharpCode.Decompiler.Tests/TestCases/Pretty/TupleTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
// Copyright (c) 2018 Daniel Grunwald
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.

using System;
using System.Collections.Generic;
using System.Linq;

namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
{
public class TupleTests
{
private abstract class OverloadResolution
{
public abstract void M1((long, long) a);
public abstract void M1(object a);

public void UseM1((int, int) a)
{
// M1(a); TODO: tuple conversion transform
// Cast is required to avoid the overload usable via tuple conversion:
M1((object)a);
}
}

public ValueTuple VT0;
public ValueTuple<int> VT1;
public ValueTuple<int, int, int, int, int, int, int, ValueTuple> VT7EmptyRest;

public (int, uint) Unnamed2;
public (int, int, int) Unnamed3;
public (int, int, int, int) Unnamed4;
public (int, int, int, int, int) Unnamed5;
public (int, int, int, int, int, int) Unnamed6;
public (int, int, int, int, int, int, int) Unnamed7;
public (int, int, int, int, int, int, int, int) Unnamed8;

public (int a, uint b) Named2;
public (int a, uint b)[] Named2Array;
public (int a, int b, int c, int d, int e, int f, int g, int h) Named8;

public (int, int a, int, int b, int) PartiallyNamed;

public ((int a, int b) x, (int, int) y, (int c, int d) z) Nested1;
public ((object a, dynamic b), dynamic, (dynamic c, object d)) Nested2;
public (ValueTuple a, (int x1, int x2), ValueTuple<int> b, (int y1, int y2), (int, int) c) Nested3;
public (int a, int b, int c, int d, int e, int f, int g, int h, (int i, int j)) Nested4;

public Dictionary<(int a, string b), (string c, int d)> TupleDict;

public int VT1Member => VT1.Item1;
public int AccessUnnamed8 => Unnamed8.Item8;
public int AccessNamed8 => Named8.h;
public int AccessPartiallyNamed => PartiallyNamed.a + PartiallyNamed.Item3;

public ValueTuple<int> NewTuple1 => new ValueTuple<int>(1);
public (int a, int b) NewTuple2 => (1, 2);
public object BoxedTuple10 => (1, 2, 3, 4, 5, 6, 7, 8, 9, 10);

public (uint, int) SwapUnnamed => (Unnamed2.Item2, Unnamed2.Item1);
public (uint, int) SwapNamed2 => (Named2.b, Named2.a);

public int TupleHash => (1, 2, 3).GetHashCode();
public int TupleHash2 => Named2.GetHashCode();

public (int, int) AccessRest => (1, 2, 3, 4, 5, 6, 7, 8, 9).Rest;

public (string, object, Action) TargetTyping => (null, 1, delegate {
});

public object NotTargetTyping => ((string)null, (object)1, (Action)delegate {
});

public void UseDict()
{
if (TupleDict.Count > 10) {
TupleDict.Clear();
}
// TODO: it would be nice if we could infer the name 'c' for the local
string item = TupleDict[(1, "abc")].c;
Console.WriteLine(item);
Console.WriteLine(item);
Console.WriteLine(TupleDict.Values.ToList().First().d);
}
}
}
Loading

0 comments on commit 5c0c492

Please sign in to comment.