Browse Source

Merge pull request #1134 from icsharpcode/tuple

C# 7.0 tuples
pull/1600/head
Daniel Grunwald 7 years ago committed by GitHub
parent
commit
5c0c492c1f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 16
      ICSharpCode.Decompiler.Tests/Helpers/RemoveCompilerAttribute.cs
  2. 3
      ICSharpCode.Decompiler.Tests/Helpers/Tester.cs
  3. 1
      ICSharpCode.Decompiler.Tests/ICSharpCode.Decompiler.Tests.csproj
  4. 6
      ICSharpCode.Decompiler.Tests/PrettyTestRunner.cs
  5. 27
      ICSharpCode.Decompiler.Tests/Semantics/ConversionTests.cs
  6. 100
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/TupleTests.cs
  7. 519
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/TupleTests.opt.roslyn.il
  8. 540
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/TupleTests.roslyn.il
  9. 12
      ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs
  10. 95
      ICSharpCode.Decompiler/CSharp/CallBuilder.cs
  11. 51
      ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs
  12. 37
      ICSharpCode.Decompiler/CSharp/OutputVisitor/CSharpOutputVisitor.cs
  13. 130
      ICSharpCode.Decompiler/CSharp/Resolver/CSharpConversions.cs
  14. 45
      ICSharpCode.Decompiler/CSharp/Resolver/CSharpOperators.cs
  15. 4
      ICSharpCode.Decompiler/CSharp/Resolver/CSharpResolver.cs
  16. 2
      ICSharpCode.Decompiler/CSharp/Resolver/LambdaResolveResult.cs
  17. 2
      ICSharpCode.Decompiler/CSharp/Resolver/MethodGroupResolveResult.cs
  18. 8
      ICSharpCode.Decompiler/CSharp/Resolver/ReducedExtensionMethod.cs
  19. 16
      ICSharpCode.Decompiler/CSharp/Resolver/TypeInference.cs
  20. 51
      ICSharpCode.Decompiler/CSharp/Syntax/DepthFirstAstVisitor.cs
  21. 51
      ICSharpCode.Decompiler/CSharp/Syntax/Expressions/TupleExpression.cs
  22. 9
      ICSharpCode.Decompiler/CSharp/Syntax/IAstVisitor.cs
  23. 139
      ICSharpCode.Decompiler/CSharp/Syntax/TupleAstType.cs
  24. 16
      ICSharpCode.Decompiler/CSharp/Syntax/TypeSystemAstBuilder.cs
  25. 21
      ICSharpCode.Decompiler/CSharp/TranslatedExpression.cs
  26. 2
      ICSharpCode.Decompiler/CSharp/TypeSystem/AliasNamespaceReference.cs
  27. 68
      ICSharpCode.Decompiler/DecompilerSettings.cs
  28. 6
      ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj
  29. 18
      ICSharpCode.Decompiler/IL/Transforms/TransformArrayInitializers.cs
  30. 93
      ICSharpCode.Decompiler/IL/Transforms/TupleTransform.cs
  31. 58
      ICSharpCode.Decompiler/Semantics/Conversion.cs
  32. 2
      ICSharpCode.Decompiler/Semantics/NamespaceResolveResult.cs
  33. 57
      ICSharpCode.Decompiler/Semantics/TupleResolveResult.cs
  34. 182
      ICSharpCode.Decompiler/TypeSystem/CecilLoader.cs
  35. 36
      ICSharpCode.Decompiler/TypeSystem/DecompilerTypeSystem.cs
  36. 5
      ICSharpCode.Decompiler/TypeSystem/IMember.cs
  37. 5
      ICSharpCode.Decompiler/TypeSystem/Implementation/AbstractResolvedMember.cs
  38. 8
      ICSharpCode.Decompiler/TypeSystem/Implementation/DefaultMemberReference.cs
  39. 56
      ICSharpCode.Decompiler/TypeSystem/Implementation/DummyTypeParameter.cs
  40. 15
      ICSharpCode.Decompiler/TypeSystem/Implementation/SpecializedMember.cs
  41. 11
      ICSharpCode.Decompiler/TypeSystem/Implementation/SpecializedMethod.cs
  42. 56
      ICSharpCode.Decompiler/TypeSystem/NormalizeTypeVisitor.cs
  43. 28
      ICSharpCode.Decompiler/TypeSystem/ParameterListComparer.cs
  44. 2
      ICSharpCode.Decompiler/TypeSystem/ParameterizedType.cs
  45. 7
      ICSharpCode.Decompiler/TypeSystem/SpecialType.cs
  46. 369
      ICSharpCode.Decompiler/TypeSystem/TupleType.cs
  47. 12
      ICSharpCode.Decompiler/TypeSystem/TypeKind.cs
  48. 29
      ICSharpCode.Decompiler/TypeSystem/TypeParameterSubstitution.cs
  49. 7
      ICSharpCode.Decompiler/TypeSystem/TypeVisitor.cs
  50. 8
      ICSharpCode.Decompiler/TypeSystem/VarArgInstanceMethod.cs
  51. 20
      ICSharpCode.Decompiler/Util/CollectionExtensions.cs

16
ICSharpCode.Decompiler.Tests/Helpers/RemoveCompilerAttribute.cs

@ -6,9 +6,9 @@ using ICSharpCode.Decompiler.TypeSystem; @@ -6,9 +6,9 @@ using ICSharpCode.Decompiler.TypeSystem;
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;
@ -25,16 +25,15 @@ namespace ICSharpCode.Decompiler.Tests.Helpers @@ -25,16 +25,15 @@ namespace ICSharpCode.Decompiler.Tests.Helpers
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",
@ -42,21 +41,20 @@ namespace ICSharpCode.Decompiler.Tests.Helpers @@ -42,21 +41,20 @@ namespace ICSharpCode.Decompiler.Tests.Helpers
"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
ICSharpCode.Decompiler.Tests/Helpers/Tester.cs

@ -178,7 +178,8 @@ namespace ICSharpCode.Decompiler.Tests.Helpers @@ -178,7 +178,8 @@ namespace ICSharpCode.Decompiler.Tests.Helpers
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)
};
});

1
ICSharpCode.Decompiler.Tests/ICSharpCode.Decompiler.Tests.csproj

@ -70,6 +70,7 @@ @@ -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" />

6
ICSharpCode.Decompiler.Tests/PrettyTestRunner.cs

@ -279,6 +279,12 @@ namespace ICSharpCode.Decompiler.Tests @@ -279,6 +279,12 @@ namespace ICSharpCode.Decompiler.Tests
RunForLibrary(cscOptions: cscOptions);
}
[Test]
public void TupleTests([ValueSource("roslynOnlyOptions")] CSharpCompilerOptions cscOptions)
{
RunForLibrary(cscOptions: cscOptions);
}
[Test]
public void Issue1080([ValueSource(nameof(roslynOnlyOptions))] CSharpCompilerOptions cscOptions)
{

27
ICSharpCode.Decompiler.Tests/Semantics/ConversionTests.cs

@ -19,6 +19,7 @@ @@ -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;
@ -88,6 +89,32 @@ namespace ICSharpCode.Decompiler.Tests.Semantics @@ -88,6 +89,32 @@ namespace ICSharpCode.Decompiler.Tests.Semantics
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()
{

100
ICSharpCode.Decompiler.Tests/TestCases/Pretty/TupleTests.cs

@ -0,0 +1,100 @@ @@ -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);
}
}
}

519
ICSharpCode.Decompiler.Tests/TestCases/Pretty/TupleTests.opt.roslyn.il

@ -0,0 +1,519 @@ @@ -0,0 +1,519 @@
// Metadata version: v4.0.30319
.assembly extern mscorlib
{
.publickeytoken = (B7 7A 5C 56 19 34 E0 89 ) // .z\V.4..
.ver 4:0:0:0
}
.assembly extern System.Core
{
.publickeytoken = (B7 7A 5C 56 19 34 E0 89 ) // .z\V.4..
.ver 4:0:0:0
}
.assembly TupleTests
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.CompilationRelaxationsAttribute::.ctor(int32) = ( 01 00 08 00 00 00 00 00 )
.custom instance void [mscorlib]System.Runtime.CompilerServices.RuntimeCompatibilityAttribute::.ctor() = ( 01 00 01 00 54 02 16 57 72 61 70 4E 6F 6E 45 78 // ....T..WrapNonEx
63 65 70 74 69 6F 6E 54 68 72 6F 77 73 01 ) // ceptionThrows.
// --- The following custom attribute is added automatically, do not uncomment -------
// .custom instance void [mscorlib]System.Diagnostics.DebuggableAttribute::.ctor(valuetype [mscorlib]System.Diagnostics.DebuggableAttribute/DebuggingModes) = ( 01 00 02 00 00 00 00 00 )
.permissionset reqmin
= {[mscorlib]System.Security.Permissions.SecurityPermissionAttribute = {property bool 'SkipVerification' = bool(true)}}
.hash algorithm 0x00008004
.ver 0:0:0:0
}
.module TupleTests.dll
.custom instance void [mscorlib]System.Security.UnverifiableCodeAttribute::.ctor() = ( 01 00 00 00 )
.imagebase 0x10000000
.file alignment 0x00000200
.stackreserve 0x00100000
.subsystem 0x0003 // WINDOWS_CUI
.corflags 0x00000001 // ILONLY
// =============== CLASS MEMBERS DECLARATION ===================
.class public auto ansi beforefieldinit ICSharpCode.Decompiler.Tests.TestCases.Pretty.TupleTests
extends [mscorlib]System.Object
{
.class abstract auto ansi nested private beforefieldinit OverloadResolution
extends [mscorlib]System.Object
{
.method public hidebysig newslot abstract virtual
instance void M1(valuetype [mscorlib]System.ValueTuple`2<int64,int64> a) cil managed
{
} // end of method OverloadResolution::M1
.method public hidebysig newslot abstract virtual
instance void M1(object a) cil managed
{
} // end of method OverloadResolution::M1
.method public hidebysig instance void
UseM1(valuetype [mscorlib]System.ValueTuple`2<int32,int32> a) cil managed
{
// Code size 13 (0xd)
.maxstack 8
IL_0000: ldarg.0
IL_0001: ldarg.1
IL_0002: box valuetype [mscorlib]System.ValueTuple`2<int32,int32>
IL_0007: callvirt instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.TupleTests/OverloadResolution::M1(object)
IL_000c: ret
} // end of method OverloadResolution::UseM1
.method family hidebysig specialname rtspecialname
instance void .ctor() cil managed
{
// Code size 7 (0x7)
.maxstack 8
IL_0000: ldarg.0
IL_0001: call instance void [mscorlib]System.Object::.ctor()
IL_0006: ret
} // end of method OverloadResolution::.ctor
} // end of class OverloadResolution
.class auto ansi serializable sealed nested private beforefieldinit '<>c'
extends [mscorlib]System.Object
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 )
.field public static initonly class ICSharpCode.Decompiler.Tests.TestCases.Pretty.TupleTests/'<>c' '<>9'
.field public static class [mscorlib]System.Action '<>9__45_0'
.field public static class [mscorlib]System.Action '<>9__47_0'
.method private hidebysig specialname rtspecialname static
void .cctor() cil managed
{
// Code size 11 (0xb)
.maxstack 8
IL_0000: newobj instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.TupleTests/'<>c'::.ctor()
IL_0005: stsfld class ICSharpCode.Decompiler.Tests.TestCases.Pretty.TupleTests/'<>c' ICSharpCode.Decompiler.Tests.TestCases.Pretty.TupleTests/'<>c'::'<>9'
IL_000a: ret
} // end of method '<>c'::.cctor
.method public hidebysig specialname rtspecialname
instance void .ctor() cil managed
{
// Code size 7 (0x7)
.maxstack 8
IL_0000: ldarg.0
IL_0001: call instance void [mscorlib]System.Object::.ctor()
IL_0006: ret
} // end of method '<>c'::.ctor
.method assembly hidebysig instance void
'<get_TargetTyping>b__45_0'() cil managed
{
// Code size 1 (0x1)
.maxstack 8
IL_0000: ret
} // end of method '<>c'::'<get_TargetTyping>b__45_0'
.method assembly hidebysig instance void
'<get_NotTargetTyping>b__47_0'() cil managed
{
// Code size 1 (0x1)
.maxstack 8
IL_0000: ret
} // end of method '<>c'::'<get_NotTargetTyping>b__47_0'
} // end of class '<>c'
.field public valuetype [mscorlib]System.ValueTuple VT0
.field public valuetype [mscorlib]System.ValueTuple`1<int32> VT1
.field public valuetype [mscorlib]System.ValueTuple`8<int32,int32,int32,int32,int32,int32,int32,valuetype [mscorlib]System.ValueTuple> VT7EmptyRest
.field public valuetype [mscorlib]System.ValueTuple`2<int32,uint32> Unnamed2
.field public valuetype [mscorlib]System.ValueTuple`3<int32,int32,int32> Unnamed3
.field public valuetype [mscorlib]System.ValueTuple`4<int32,int32,int32,int32> Unnamed4
.field public valuetype [mscorlib]System.ValueTuple`5<int32,int32,int32,int32,int32> Unnamed5
.field public valuetype [mscorlib]System.ValueTuple`6<int32,int32,int32,int32,int32,int32> Unnamed6
.field public valuetype [mscorlib]System.ValueTuple`7<int32,int32,int32,int32,int32,int32,int32> Unnamed7
.field public valuetype [mscorlib]System.ValueTuple`8<int32,int32,int32,int32,int32,int32,int32,valuetype [mscorlib]System.ValueTuple`1<int32>> Unnamed8
.field public valuetype [mscorlib]System.ValueTuple`2<int32,uint32> Named2
.custom instance void [mscorlib]System.Runtime.CompilerServices.TupleElementNamesAttribute::.ctor(string[]) = ( 01 00 02 00 00 00 01 61 01 62 00 00 ) // .......a.b..
.field public valuetype [mscorlib]System.ValueTuple`2<int32,uint32>[] Named2Array
.custom instance void [mscorlib]System.Runtime.CompilerServices.TupleElementNamesAttribute::.ctor(string[]) = ( 01 00 02 00 00 00 01 61 01 62 00 00 ) // .......a.b..
.field public valuetype [mscorlib]System.ValueTuple`8<int32,int32,int32,int32,int32,int32,int32,valuetype [mscorlib]System.ValueTuple`1<int32>> Named8
.custom instance void [mscorlib]System.Runtime.CompilerServices.TupleElementNamesAttribute::.ctor(string[]) = ( 01 00 09 00 00 00 01 61 01 62 01 63 01 64 01 65 // .......a.b.c.d.e
01 66 01 67 01 68 FF 00 00 ) // .f.g.h...
.field public valuetype [mscorlib]System.ValueTuple`5<int32,int32,int32,int32,int32> PartiallyNamed
.custom instance void [mscorlib]System.Runtime.CompilerServices.TupleElementNamesAttribute::.ctor(string[]) = ( 01 00 05 00 00 00 FF 01 61 FF 01 62 FF 00 00 ) // ........a..b...
.field public valuetype [mscorlib]System.ValueTuple`3<valuetype [mscorlib]System.ValueTuple`2<int32,int32>,valuetype [mscorlib]System.ValueTuple`2<int32,int32>,valuetype [mscorlib]System.ValueTuple`2<int32,int32>> Nested1
.custom instance void [mscorlib]System.Runtime.CompilerServices.TupleElementNamesAttribute::.ctor(string[]) = ( 01 00 09 00 00 00 01 78 01 79 01 7A 01 61 01 62 // .......x.y.z.a.b
FF FF 01 63 01 64 00 00 ) // ...c.d..
.field public valuetype [mscorlib]System.ValueTuple`3<valuetype [mscorlib]System.ValueTuple`2<object,object>,object,valuetype [mscorlib]System.ValueTuple`2<object,object>> Nested2
.custom instance void [System.Core]System.Runtime.CompilerServices.DynamicAttribute::.ctor(bool[]) = ( 01 00 08 00 00 00 00 00 00 01 01 00 01 00 00 00 )
.custom instance void [mscorlib]System.Runtime.CompilerServices.TupleElementNamesAttribute::.ctor(string[]) = ( 01 00 07 00 00 00 FF FF FF 01 61 01 62 01 63 01 // ..........a.b.c.
64 00 00 ) // d..
.field public valuetype [mscorlib]System.ValueTuple`5<valuetype [mscorlib]System.ValueTuple,valuetype [mscorlib]System.ValueTuple`2<int32,int32>,valuetype [mscorlib]System.ValueTuple`1<int32>,valuetype [mscorlib]System.ValueTuple`2<int32,int32>,valuetype [mscorlib]System.ValueTuple`2<int32,int32>> Nested3
.custom instance void [mscorlib]System.Runtime.CompilerServices.TupleElementNamesAttribute::.ctor(string[]) = ( 01 00 0C 00 00 00 01 61 FF 01 62 FF 01 63 02 78 // .......a..b..c.x
31 02 78 32 FF 02 79 31 02 79 32 FF FF 00 00 ) // 1.x2..y1.y2....
.field public valuetype [mscorlib]System.ValueTuple`8<int32,int32,int32,int32,int32,int32,int32,valuetype [mscorlib]System.ValueTuple`2<int32,valuetype [mscorlib]System.ValueTuple`2<int32,int32>>> Nested4
.custom instance void [mscorlib]System.Runtime.CompilerServices.TupleElementNamesAttribute::.ctor(string[]) = ( 01 00 0D 00 00 00 01 61 01 62 01 63 01 64 01 65 // .......a.b.c.d.e
01 66 01 67 01 68 FF FF FF 01 69 01 6A 00 00 ) // .f.g.h....i.j..
.field public class [mscorlib]System.Collections.Generic.Dictionary`2<valuetype [mscorlib]System.ValueTuple`2<int32,string>,valuetype [mscorlib]System.ValueTuple`2<string,int32>> TupleDict
.custom instance void [mscorlib]System.Runtime.CompilerServices.TupleElementNamesAttribute::.ctor(string[]) = ( 01 00 04 00 00 00 01 61 01 62 01 63 01 64 00 00 ) // .......a.b.c.d..
.method public hidebysig specialname instance int32
get_VT1Member() cil managed
{
// Code size 12 (0xc)
.maxstack 8
IL_0000: ldarg.0
IL_0001: ldflda valuetype [mscorlib]System.ValueTuple`1<int32> ICSharpCode.Decompiler.Tests.TestCases.Pretty.TupleTests::VT1
IL_0006: ldfld !0 valuetype [mscorlib]System.ValueTuple`1<int32>::Item1
IL_000b: ret
} // end of method TupleTests::get_VT1Member
.method public hidebysig specialname instance int32
get_AccessUnnamed8() cil managed
{
// Code size 17 (0x11)
.maxstack 8
IL_0000: ldarg.0
IL_0001: ldflda valuetype [mscorlib]System.ValueTuple`8<int32,int32,int32,int32,int32,int32,int32,valuetype [mscorlib]System.ValueTuple`1<int32>> ICSharpCode.Decompiler.Tests.TestCases.Pretty.TupleTests::Unnamed8
IL_0006: ldflda !7 valuetype [mscorlib]System.ValueTuple`8<int32,int32,int32,int32,int32,int32,int32,valuetype [mscorlib]System.ValueTuple`1<int32>>::Rest
IL_000b: ldfld !0 valuetype [mscorlib]System.ValueTuple`1<int32>::Item1
IL_0010: ret
} // end of method TupleTests::get_AccessUnnamed8
.method public hidebysig specialname instance int32
get_AccessNamed8() cil managed
{
// Code size 17 (0x11)
.maxstack 8
IL_0000: ldarg.0
IL_0001: ldflda valuetype [mscorlib]System.ValueTuple`8<int32,int32,int32,int32,int32,int32,int32,valuetype [mscorlib]System.ValueTuple`1<int32>> ICSharpCode.Decompiler.Tests.TestCases.Pretty.TupleTests::Named8
IL_0006: ldflda !7 valuetype [mscorlib]System.ValueTuple`8<int32,int32,int32,int32,int32,int32,int32,valuetype [mscorlib]System.ValueTuple`1<int32>>::Rest
IL_000b: ldfld !0 valuetype [mscorlib]System.ValueTuple`1<int32>::Item1
IL_0010: ret
} // end of method TupleTests::get_AccessNamed8
.method public hidebysig specialname instance int32
get_AccessPartiallyNamed() cil managed
{
// Code size 24 (0x18)
.maxstack 8
IL_0000: ldarg.0
IL_0001: ldflda valuetype [mscorlib]System.ValueTuple`5<int32,int32,int32,int32,int32> ICSharpCode.Decompiler.Tests.TestCases.Pretty.TupleTests::PartiallyNamed
IL_0006: ldfld !1 valuetype [mscorlib]System.ValueTuple`5<int32,int32,int32,int32,int32>::Item2
IL_000b: ldarg.0
IL_000c: ldflda valuetype [mscorlib]System.ValueTuple`5<int32,int32,int32,int32,int32> ICSharpCode.Decompiler.Tests.TestCases.Pretty.TupleTests::PartiallyNamed
IL_0011: ldfld !2 valuetype [mscorlib]System.ValueTuple`5<int32,int32,int32,int32,int32>::Item3
IL_0016: add
IL_0017: ret
} // end of method TupleTests::get_AccessPartiallyNamed
.method public hidebysig specialname instance valuetype [mscorlib]System.ValueTuple`1<int32>
get_NewTuple1() cil managed
{
// Code size 7 (0x7)
.maxstack 8
IL_0000: ldc.i4.1
IL_0001: newobj instance void valuetype [mscorlib]System.ValueTuple`1<int32>::.ctor(!0)
IL_0006: ret
} // end of method TupleTests::get_NewTuple1
.method public hidebysig specialname instance valuetype [mscorlib]System.ValueTuple`2<int32,int32>
get_NewTuple2() cil managed
{
.param [0]
.custom instance void [mscorlib]System.Runtime.CompilerServices.TupleElementNamesAttribute::.ctor(string[]) = ( 01 00 02 00 00 00 01 61 01 62 00 00 ) // .......a.b..
// Code size 8 (0x8)
.maxstack 8
IL_0000: ldc.i4.1
IL_0001: ldc.i4.2
IL_0002: newobj instance void valuetype [mscorlib]System.ValueTuple`2<int32,int32>::.ctor(!0,
!1)
IL_0007: ret
} // end of method TupleTests::get_NewTuple2
.method public hidebysig specialname instance object
get_BoxedTuple10() cil managed
{
// Code size 28 (0x1c)
.maxstack 10
IL_0000: ldc.i4.1
IL_0001: ldc.i4.2
IL_0002: ldc.i4.3
IL_0003: ldc.i4.4
IL_0004: ldc.i4.5
IL_0005: ldc.i4.6
IL_0006: ldc.i4.7
IL_0007: ldc.i4.8
IL_0008: ldc.i4.s 9
IL_000a: ldc.i4.s 10
IL_000c: newobj instance void valuetype [mscorlib]System.ValueTuple`3<int32,int32,int32>::.ctor(!0,
!1,
!2)
IL_0011: newobj instance void valuetype [mscorlib]System.ValueTuple`8<int32,int32,int32,int32,int32,int32,int32,valuetype [mscorlib]System.ValueTuple`3<int32,int32,int32>>::.ctor(!0,
!1,
!2,
!3,
!4,
!5,
!6,
!7)
IL_0016: box valuetype [mscorlib]System.ValueTuple`8<int32,int32,int32,int32,int32,int32,int32,valuetype [mscorlib]System.ValueTuple`3<int32,int32,int32>>
IL_001b: ret
} // end of method TupleTests::get_BoxedTuple10
.method public hidebysig specialname instance valuetype [mscorlib]System.ValueTuple`2<uint32,int32>
get_SwapUnnamed() cil managed
{
// Code size 28 (0x1c)
.maxstack 8
IL_0000: ldarg.0
IL_0001: ldflda valuetype [mscorlib]System.ValueTuple`2<int32,uint32> ICSharpCode.Decompiler.Tests.TestCases.Pretty.TupleTests::Unnamed2
IL_0006: ldfld !1 valuetype [mscorlib]System.ValueTuple`2<int32,uint32>::Item2
IL_000b: ldarg.0
IL_000c: ldflda valuetype [mscorlib]System.ValueTuple`2<int32,uint32> ICSharpCode.Decompiler.Tests.TestCases.Pretty.TupleTests::Unnamed2
IL_0011: ldfld !0 valuetype [mscorlib]System.ValueTuple`2<int32,uint32>::Item1
IL_0016: newobj instance void valuetype [mscorlib]System.ValueTuple`2<uint32,int32>::.ctor(!0,
!1)
IL_001b: ret
} // end of method TupleTests::get_SwapUnnamed
.method public hidebysig specialname instance valuetype [mscorlib]System.ValueTuple`2<uint32,int32>
get_SwapNamed2() cil managed
{
// Code size 28 (0x1c)
.maxstack 8
IL_0000: ldarg.0
IL_0001: ldflda valuetype [mscorlib]System.ValueTuple`2<int32,uint32> ICSharpCode.Decompiler.Tests.TestCases.Pretty.TupleTests::Named2
IL_0006: ldfld !1 valuetype [mscorlib]System.ValueTuple`2<int32,uint32>::Item2
IL_000b: ldarg.0
IL_000c: ldflda valuetype [mscorlib]System.ValueTuple`2<int32,uint32> ICSharpCode.Decompiler.Tests.TestCases.Pretty.TupleTests::Named2
IL_0011: ldfld !0 valuetype [mscorlib]System.ValueTuple`2<int32,uint32>::Item1
IL_0016: newobj instance void valuetype [mscorlib]System.ValueTuple`2<uint32,int32>::.ctor(!0,
!1)
IL_001b: ret
} // end of method TupleTests::get_SwapNamed2
.method public hidebysig specialname instance int32
get_TupleHash() cil managed
{
// Code size 23 (0x17)
.maxstack 3
.locals init (valuetype [mscorlib]System.ValueTuple`3<int32,int32,int32> V_0)
IL_0000: ldc.i4.1
IL_0001: ldc.i4.2
IL_0002: ldc.i4.3
IL_0003: newobj instance void valuetype [mscorlib]System.ValueTuple`3<int32,int32,int32>::.ctor(!0,
!1,
!2)
IL_0008: stloc.0
IL_0009: ldloca.s V_0
IL_000b: constrained. valuetype [mscorlib]System.ValueTuple`3<int32,int32,int32>
IL_0011: callvirt instance int32 [mscorlib]System.Object::GetHashCode()
IL_0016: ret
} // end of method TupleTests::get_TupleHash
.method public hidebysig specialname instance int32
get_TupleHash2() cil managed
{
// Code size 18 (0x12)
.maxstack 8
IL_0000: ldarg.0
IL_0001: ldflda valuetype [mscorlib]System.ValueTuple`2<int32,uint32> ICSharpCode.Decompiler.Tests.TestCases.Pretty.TupleTests::Named2
IL_0006: constrained. valuetype [mscorlib]System.ValueTuple`2<int32,uint32>
IL_000c: callvirt instance int32 [mscorlib]System.Object::GetHashCode()
IL_0011: ret
} // end of method TupleTests::get_TupleHash2
.method public hidebysig specialname instance valuetype [mscorlib]System.ValueTuple`2<int32,int32>
get_AccessRest() cil managed
{
// Code size 26 (0x1a)
.maxstack 9
IL_0000: ldc.i4.1
IL_0001: ldc.i4.2
IL_0002: ldc.i4.3
IL_0003: ldc.i4.4
IL_0004: ldc.i4.5
IL_0005: ldc.i4.6
IL_0006: ldc.i4.7
IL_0007: ldc.i4.8
IL_0008: ldc.i4.s 9
IL_000a: newobj instance void valuetype [mscorlib]System.ValueTuple`2<int32,int32>::.ctor(!0,
!1)
IL_000f: newobj instance void valuetype [mscorlib]System.ValueTuple`8<int32,int32,int32,int32,int32,int32,int32,valuetype [mscorlib]System.ValueTuple`2<int32,int32>>::.ctor(!0,
!1,
!2,
!3,
!4,
!5,
!6,
!7)
IL_0014: ldfld !7 valuetype [mscorlib]System.ValueTuple`8<int32,int32,int32,int32,int32,int32,int32,valuetype [mscorlib]System.ValueTuple`2<int32,int32>>::Rest
IL_0019: ret
} // end of method TupleTests::get_AccessRest
.method public hidebysig specialname instance valuetype [mscorlib]System.ValueTuple`3<string,object,class [mscorlib]System.Action>
get_TargetTyping() cil managed
{
// Code size 44 (0x2c)
.maxstack 8
IL_0000: ldnull
IL_0001: ldc.i4.1
IL_0002: box [mscorlib]System.Int32
IL_0007: ldsfld class [mscorlib]System.Action ICSharpCode.Decompiler.Tests.TestCases.Pretty.TupleTests/'<>c'::'<>9__45_0'
IL_000c: dup
IL_000d: brtrue.s IL_0026
IL_000f: pop
IL_0010: ldsfld class ICSharpCode.Decompiler.Tests.TestCases.Pretty.TupleTests/'<>c' ICSharpCode.Decompiler.Tests.TestCases.Pretty.TupleTests/'<>c'::'<>9'
IL_0015: ldftn instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.TupleTests/'<>c'::'<get_TargetTyping>b__45_0'()
IL_001b: newobj instance void [mscorlib]System.Action::.ctor(object,
native int)
IL_0020: dup
IL_0021: stsfld class [mscorlib]System.Action ICSharpCode.Decompiler.Tests.TestCases.Pretty.TupleTests/'<>c'::'<>9__45_0'
IL_0026: newobj instance void valuetype [mscorlib]System.ValueTuple`3<string,object,class [mscorlib]System.Action>::.ctor(!0,
!1,
!2)
IL_002b: ret
} // end of method TupleTests::get_TargetTyping
.method public hidebysig specialname instance object
get_NotTargetTyping() cil managed
{
// Code size 49 (0x31)
.maxstack 8
IL_0000: ldnull
IL_0001: ldc.i4.1
IL_0002: box [mscorlib]System.Int32
IL_0007: ldsfld class [mscorlib]System.Action ICSharpCode.Decompiler.Tests.TestCases.Pretty.TupleTests/'<>c'::'<>9__47_0'
IL_000c: dup
IL_000d: brtrue.s IL_0026
IL_000f: pop
IL_0010: ldsfld class ICSharpCode.Decompiler.Tests.TestCases.Pretty.TupleTests/'<>c' ICSharpCode.Decompiler.Tests.TestCases.Pretty.TupleTests/'<>c'::'<>9'
IL_0015: ldftn instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.TupleTests/'<>c'::'<get_NotTargetTyping>b__47_0'()
IL_001b: newobj instance void [mscorlib]System.Action::.ctor(object,
native int)
IL_0020: dup
IL_0021: stsfld class [mscorlib]System.Action ICSharpCode.Decompiler.Tests.TestCases.Pretty.TupleTests/'<>c'::'<>9__47_0'
IL_0026: newobj instance void valuetype [mscorlib]System.ValueTuple`3<string,object,class [mscorlib]System.Action>::.ctor(!0,
!1,
!2)
IL_002b: box valuetype [mscorlib]System.ValueTuple`3<string,object,class [mscorlib]System.Action>
IL_0030: ret
} // end of method TupleTests::get_NotTargetTyping
.method public hidebysig instance void
UseDict() cil managed
{
// Code size 96 (0x60)
.maxstack 3
IL_0000: ldarg.0
IL_0001: ldfld class [mscorlib]System.Collections.Generic.Dictionary`2<valuetype [mscorlib]System.ValueTuple`2<int32,string>,valuetype [mscorlib]System.ValueTuple`2<string,int32>> ICSharpCode.Decompiler.Tests.TestCases.Pretty.TupleTests::TupleDict
IL_0006: callvirt instance int32 class [mscorlib]System.Collections.Generic.Dictionary`2<valuetype [mscorlib]System.ValueTuple`2<int32,string>,valuetype [mscorlib]System.ValueTuple`2<string,int32>>::get_Count()
IL_000b: ldc.i4.s 10
IL_000d: ble.s IL_001a
IL_000f: ldarg.0
IL_0010: ldfld class [mscorlib]System.Collections.Generic.Dictionary`2<valuetype [mscorlib]System.ValueTuple`2<int32,string>,valuetype [mscorlib]System.ValueTuple`2<string,int32>> ICSharpCode.Decompiler.Tests.TestCases.Pretty.TupleTests::TupleDict
IL_0015: callvirt instance void class [mscorlib]System.Collections.Generic.Dictionary`2<valuetype [mscorlib]System.ValueTuple`2<int32,string>,valuetype [mscorlib]System.ValueTuple`2<string,int32>>::Clear()
IL_001a: ldarg.0
IL_001b: ldfld class [mscorlib]System.Collections.Generic.Dictionary`2<valuetype [mscorlib]System.ValueTuple`2<int32,string>,valuetype [mscorlib]System.ValueTuple`2<string,int32>> ICSharpCode.Decompiler.Tests.TestCases.Pretty.TupleTests::TupleDict
IL_0020: ldc.i4.1
IL_0021: ldstr "abc"
IL_0026: newobj instance void valuetype [mscorlib]System.ValueTuple`2<int32,string>::.ctor(!0,
!1)
IL_002b: callvirt instance !1 class [mscorlib]System.Collections.Generic.Dictionary`2<valuetype [mscorlib]System.ValueTuple`2<int32,string>,valuetype [mscorlib]System.ValueTuple`2<string,int32>>::get_Item(!0)
IL_0030: ldfld !0 valuetype [mscorlib]System.ValueTuple`2<string,int32>::Item1
IL_0035: dup
IL_0036: call void [mscorlib]System.Console::WriteLine(string)
IL_003b: call void [mscorlib]System.Console::WriteLine(string)
IL_0040: ldarg.0
IL_0041: ldfld class [mscorlib]System.Collections.Generic.Dictionary`2<valuetype [mscorlib]System.ValueTuple`2<int32,string>,valuetype [mscorlib]System.ValueTuple`2<string,int32>> ICSharpCode.Decompiler.Tests.TestCases.Pretty.TupleTests::TupleDict
IL_0046: callvirt instance class [mscorlib]System.Collections.Generic.Dictionary`2/ValueCollection<!0,!1> class [mscorlib]System.Collections.Generic.Dictionary`2<valuetype [mscorlib]System.ValueTuple`2<int32,string>,valuetype [mscorlib]System.ValueTuple`2<string,int32>>::get_Values()
IL_004b: call class [mscorlib]System.Collections.Generic.List`1<!!0> [System.Core]System.Linq.Enumerable::ToList<valuetype [mscorlib]System.ValueTuple`2<string,int32>>(class [mscorlib]System.Collections.Generic.IEnumerable`1<!!0>)
IL_0050: call !!0 [System.Core]System.Linq.Enumerable::First<valuetype [mscorlib]System.ValueTuple`2<string,int32>>(class [mscorlib]System.Collections.Generic.IEnumerable`1<!!0>)
IL_0055: ldfld !1 valuetype [mscorlib]System.ValueTuple`2<string,int32>::Item2
IL_005a: call void [mscorlib]System.Console::WriteLine(int32)
IL_005f: ret
} // end of method TupleTests::UseDict
.method public hidebysig specialname rtspecialname
instance void .ctor() cil managed
{
// Code size 7 (0x7)
.maxstack 8
IL_0000: ldarg.0
IL_0001: call instance void [mscorlib]System.Object::.ctor()
IL_0006: ret
} // end of method TupleTests::.ctor
.property instance int32 VT1Member()
{
.get instance int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.TupleTests::get_VT1Member()
} // end of property TupleTests::VT1Member
.property instance int32 AccessUnnamed8()
{
.get instance int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.TupleTests::get_AccessUnnamed8()
} // end of property TupleTests::AccessUnnamed8
.property instance int32 AccessNamed8()
{
.get instance int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.TupleTests::get_AccessNamed8()
} // end of property TupleTests::AccessNamed8
.property instance int32 AccessPartiallyNamed()
{
.get instance int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.TupleTests::get_AccessPartiallyNamed()
} // end of property TupleTests::AccessPartiallyNamed
.property instance valuetype [mscorlib]System.ValueTuple`1<int32>
NewTuple1()
{
.get instance valuetype [mscorlib]System.ValueTuple`1<int32> ICSharpCode.Decompiler.Tests.TestCases.Pretty.TupleTests::get_NewTuple1()
} // end of property TupleTests::NewTuple1
.property instance valuetype [mscorlib]System.ValueTuple`2<int32,int32>
NewTuple2()
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.TupleElementNamesAttribute::.ctor(string[]) = ( 01 00 02 00 00 00 01 61 01 62 00 00 ) // .......a.b..
.get instance valuetype [mscorlib]System.ValueTuple`2<int32,int32> ICSharpCode.Decompiler.Tests.TestCases.Pretty.TupleTests::get_NewTuple2()
} // end of property TupleTests::NewTuple2
.property instance object BoxedTuple10()
{
.get instance object ICSharpCode.Decompiler.Tests.TestCases.Pretty.TupleTests::get_BoxedTuple10()
} // end of property TupleTests::BoxedTuple10
.property instance valuetype [mscorlib]System.ValueTuple`2<uint32,int32>
SwapUnnamed()
{
.get instance valuetype [mscorlib]System.ValueTuple`2<uint32,int32> ICSharpCode.Decompiler.Tests.TestCases.Pretty.TupleTests::get_SwapUnnamed()
} // end of property TupleTests::SwapUnnamed
.property instance valuetype [mscorlib]System.ValueTuple`2<uint32,int32>
SwapNamed2()
{
.get instance valuetype [mscorlib]System.ValueTuple`2<uint32,int32> ICSharpCode.Decompiler.Tests.TestCases.Pretty.TupleTests::get_SwapNamed2()
} // end of property TupleTests::SwapNamed2
.property instance int32 TupleHash()
{
.get instance int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.TupleTests::get_TupleHash()
} // end of property TupleTests::TupleHash
.property instance int32 TupleHash2()
{
.get instance int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.TupleTests::get_TupleHash2()
} // end of property TupleTests::TupleHash2
.property instance valuetype [mscorlib]System.ValueTuple`2<int32,int32>
AccessRest()
{
.get instance valuetype [mscorlib]System.ValueTuple`2<int32,int32> ICSharpCode.Decompiler.Tests.TestCases.Pretty.TupleTests::get_AccessRest()
} // end of property TupleTests::AccessRest
.property instance valuetype [mscorlib]System.ValueTuple`3<string,object,class [mscorlib]System.Action>
TargetTyping()
{
.get instance valuetype [mscorlib]System.ValueTuple`3<string,object,class [mscorlib]System.Action> ICSharpCode.Decompiler.Tests.TestCases.Pretty.TupleTests::get_TargetTyping()
} // end of property TupleTests::TargetTyping
.property instance object NotTargetTyping()
{
.get instance object ICSharpCode.Decompiler.Tests.TestCases.Pretty.TupleTests::get_NotTargetTyping()
} // end of property TupleTests::NotTargetTyping
} // end of class ICSharpCode.Decompiler.Tests.TestCases.Pretty.TupleTests
// =============================================================
// *********** DISASSEMBLY COMPLETE ***********************

540
ICSharpCode.Decompiler.Tests/TestCases/Pretty/TupleTests.roslyn.il

@ -0,0 +1,540 @@ @@ -0,0 +1,540 @@
// Metadata version: v4.0.30319
.assembly extern mscorlib
{
.publickeytoken = (B7 7A 5C 56 19 34 E0 89 ) // .z\V.4..
.ver 4:0:0:0
}
.assembly extern System.Core
{
.publickeytoken = (B7 7A 5C 56 19 34 E0 89 ) // .z\V.4..
.ver 4:0:0:0
}
.assembly TupleTests
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.CompilationRelaxationsAttribute::.ctor(int32) = ( 01 00 08 00 00 00 00 00 )
.custom instance void [mscorlib]System.Runtime.CompilerServices.RuntimeCompatibilityAttribute::.ctor() = ( 01 00 01 00 54 02 16 57 72 61 70 4E 6F 6E 45 78 // ....T..WrapNonEx
63 65 70 74 69 6F 6E 54 68 72 6F 77 73 01 ) // ceptionThrows.
// --- The following custom attribute is added automatically, do not uncomment -------
// .custom instance void [mscorlib]System.Diagnostics.DebuggableAttribute::.ctor(valuetype [mscorlib]System.Diagnostics.DebuggableAttribute/DebuggingModes) = ( 01 00 07 01 00 00 00 00 )
.permissionset reqmin
= {[mscorlib]System.Security.Permissions.SecurityPermissionAttribute = {property bool 'SkipVerification' = bool(true)}}
.hash algorithm 0x00008004
.ver 0:0:0:0
}
.module TupleTests.dll
.custom instance void [mscorlib]System.Security.UnverifiableCodeAttribute::.ctor() = ( 01 00 00 00 )
.imagebase 0x10000000
.file alignment 0x00000200
.stackreserve 0x00100000
.subsystem 0x0003 // WINDOWS_CUI
.corflags 0x00000001 // ILONLY
// =============== CLASS MEMBERS DECLARATION ===================
.class public auto ansi beforefieldinit ICSharpCode.Decompiler.Tests.TestCases.Pretty.TupleTests
extends [mscorlib]System.Object
{
.class abstract auto ansi nested private beforefieldinit OverloadResolution
extends [mscorlib]System.Object
{
.method public hidebysig newslot abstract virtual
instance void M1(valuetype [mscorlib]System.ValueTuple`2<int64,int64> a) cil managed
{
} // end of method OverloadResolution::M1
.method public hidebysig newslot abstract virtual
instance void M1(object a) cil managed
{
} // end of method OverloadResolution::M1
.method public hidebysig instance void
UseM1(valuetype [mscorlib]System.ValueTuple`2<int32,int32> a) cil managed
{
// Code size 15 (0xf)
.maxstack 8
IL_0000: nop
IL_0001: ldarg.0
IL_0002: ldarg.1
IL_0003: box valuetype [mscorlib]System.ValueTuple`2<int32,int32>
IL_0008: callvirt instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.TupleTests/OverloadResolution::M1(object)
IL_000d: nop
IL_000e: ret
} // end of method OverloadResolution::UseM1
.method family hidebysig specialname rtspecialname
instance void .ctor() cil managed
{
// Code size 8 (0x8)
.maxstack 8
IL_0000: ldarg.0
IL_0001: call instance void [mscorlib]System.Object::.ctor()
IL_0006: nop
IL_0007: ret
} // end of method OverloadResolution::.ctor
} // end of class OverloadResolution
.class auto ansi serializable sealed nested private beforefieldinit '<>c'
extends [mscorlib]System.Object
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 )
.field public static initonly class ICSharpCode.Decompiler.Tests.TestCases.Pretty.TupleTests/'<>c' '<>9'
.field public static class [mscorlib]System.Action '<>9__45_0'
.field public static class [mscorlib]System.Action '<>9__47_0'
.method private hidebysig specialname rtspecialname static
void .cctor() cil managed
{
// Code size 11 (0xb)
.maxstack 8
IL_0000: newobj instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.TupleTests/'<>c'::.ctor()
IL_0005: stsfld class ICSharpCode.Decompiler.Tests.TestCases.Pretty.TupleTests/'<>c' ICSharpCode.Decompiler.Tests.TestCases.Pretty.TupleTests/'<>c'::'<>9'
IL_000a: ret
} // end of method '<>c'::.cctor
.method public hidebysig specialname rtspecialname
instance void .ctor() cil managed
{
// Code size 8 (0x8)
.maxstack 8
IL_0000: ldarg.0
IL_0001: call instance void [mscorlib]System.Object::.ctor()
IL_0006: nop
IL_0007: ret
} // end of method '<>c'::.ctor
.method assembly hidebysig instance void
'<get_TargetTyping>b__45_0'() cil managed
{
// Code size 2 (0x2)
.maxstack 8
IL_0000: nop
IL_0001: ret
} // end of method '<>c'::'<get_TargetTyping>b__45_0'
.method assembly hidebysig instance void
'<get_NotTargetTyping>b__47_0'() cil managed
{
// Code size 2 (0x2)
.maxstack 8
IL_0000: nop
IL_0001: ret
} // end of method '<>c'::'<get_NotTargetTyping>b__47_0'
} // end of class '<>c'
.field public valuetype [mscorlib]System.ValueTuple VT0
.field public valuetype [mscorlib]System.ValueTuple`1<int32> VT1
.field public valuetype [mscorlib]System.ValueTuple`8<int32,int32,int32,int32,int32,int32,int32,valuetype [mscorlib]System.ValueTuple> VT7EmptyRest
.field public valuetype [mscorlib]System.ValueTuple`2<int32,uint32> Unnamed2
.field public valuetype [mscorlib]System.ValueTuple`3<int32,int32,int32> Unnamed3
.field public valuetype [mscorlib]System.ValueTuple`4<int32,int32,int32,int32> Unnamed4
.field public valuetype [mscorlib]System.ValueTuple`5<int32,int32,int32,int32,int32> Unnamed5
.field public valuetype [mscorlib]System.ValueTuple`6<int32,int32,int32,int32,int32,int32> Unnamed6
.field public valuetype [mscorlib]System.ValueTuple`7<int32,int32,int32,int32,int32,int32,int32> Unnamed7
.field public valuetype [mscorlib]System.ValueTuple`8<int32,int32,int32,int32,int32,int32,int32,valuetype [mscorlib]System.ValueTuple`1<int32>> Unnamed8
.field public valuetype [mscorlib]System.ValueTuple`2<int32,uint32> Named2
.custom instance void [mscorlib]System.Runtime.CompilerServices.TupleElementNamesAttribute::.ctor(string[]) = ( 01 00 02 00 00 00 01 61 01 62 00 00 ) // .......a.b..
.field public valuetype [mscorlib]System.ValueTuple`2<int32,uint32>[] Named2Array
.custom instance void [mscorlib]System.Runtime.CompilerServices.TupleElementNamesAttribute::.ctor(string[]) = ( 01 00 02 00 00 00 01 61 01 62 00 00 ) // .......a.b..
.field public valuetype [mscorlib]System.ValueTuple`8<int32,int32,int32,int32,int32,int32,int32,valuetype [mscorlib]System.ValueTuple`1<int32>> Named8
.custom instance void [mscorlib]System.Runtime.CompilerServices.TupleElementNamesAttribute::.ctor(string[]) = ( 01 00 09 00 00 00 01 61 01 62 01 63 01 64 01 65 // .......a.b.c.d.e
01 66 01 67 01 68 FF 00 00 ) // .f.g.h...
.field public valuetype [mscorlib]System.ValueTuple`5<int32,int32,int32,int32,int32> PartiallyNamed
.custom instance void [mscorlib]System.Runtime.CompilerServices.TupleElementNamesAttribute::.ctor(string[]) = ( 01 00 05 00 00 00 FF 01 61 FF 01 62 FF 00 00 ) // ........a..b...
.field public valuetype [mscorlib]System.ValueTuple`3<valuetype [mscorlib]System.ValueTuple`2<int32,int32>,valuetype [mscorlib]System.ValueTuple`2<int32,int32>,valuetype [mscorlib]System.ValueTuple`2<int32,int32>> Nested1
.custom instance void [mscorlib]System.Runtime.CompilerServices.TupleElementNamesAttribute::.ctor(string[]) = ( 01 00 09 00 00 00 01 78 01 79 01 7A 01 61 01 62 // .......x.y.z.a.b
FF FF 01 63 01 64 00 00 ) // ...c.d..
.field public valuetype [mscorlib]System.ValueTuple`3<valuetype [mscorlib]System.ValueTuple`2<object,object>,object,valuetype [mscorlib]System.ValueTuple`2<object,object>> Nested2
.custom instance void [System.Core]System.Runtime.CompilerServices.DynamicAttribute::.ctor(bool[]) = ( 01 00 08 00 00 00 00 00 00 01 01 00 01 00 00 00 )
.custom instance void [mscorlib]System.Runtime.CompilerServices.TupleElementNamesAttribute::.ctor(string[]) = ( 01 00 07 00 00 00 FF FF FF 01 61 01 62 01 63 01 // ..........a.b.c.
64 00 00 ) // d..
.field public valuetype [mscorlib]System.ValueTuple`5<valuetype [mscorlib]System.ValueTuple,valuetype [mscorlib]System.ValueTuple`2<int32,int32>,valuetype [mscorlib]System.ValueTuple`1<int32>,valuetype [mscorlib]System.ValueTuple`2<int32,int32>,valuetype [mscorlib]System.ValueTuple`2<int32,int32>> Nested3
.custom instance void [mscorlib]System.Runtime.CompilerServices.TupleElementNamesAttribute::.ctor(string[]) = ( 01 00 0C 00 00 00 01 61 FF 01 62 FF 01 63 02 78 // .......a..b..c.x
31 02 78 32 FF 02 79 31 02 79 32 FF FF 00 00 ) // 1.x2..y1.y2....
.field public valuetype [mscorlib]System.ValueTuple`8<int32,int32,int32,int32,int32,int32,int32,valuetype [mscorlib]System.ValueTuple`2<int32,valuetype [mscorlib]System.ValueTuple`2<int32,int32>>> Nested4
.custom instance void [mscorlib]System.Runtime.CompilerServices.TupleElementNamesAttribute::.ctor(string[]) = ( 01 00 0D 00 00 00 01 61 01 62 01 63 01 64 01 65 // .......a.b.c.d.e
01 66 01 67 01 68 FF FF FF 01 69 01 6A 00 00 ) // .f.g.h....i.j..
.field public class [mscorlib]System.Collections.Generic.Dictionary`2<valuetype [mscorlib]System.ValueTuple`2<int32,string>,valuetype [mscorlib]System.ValueTuple`2<string,int32>> TupleDict
.custom instance void [mscorlib]System.Runtime.CompilerServices.TupleElementNamesAttribute::.ctor(string[]) = ( 01 00 04 00 00 00 01 61 01 62 01 63 01 64 00 00 ) // .......a.b.c.d..
.method public hidebysig specialname instance int32
get_VT1Member() cil managed
{
// Code size 12 (0xc)
.maxstack 8
IL_0000: ldarg.0
IL_0001: ldflda valuetype [mscorlib]System.ValueTuple`1<int32> ICSharpCode.Decompiler.Tests.TestCases.Pretty.TupleTests::VT1
IL_0006: ldfld !0 valuetype [mscorlib]System.ValueTuple`1<int32>::Item1
IL_000b: ret
} // end of method TupleTests::get_VT1Member
.method public hidebysig specialname instance int32
get_AccessUnnamed8() cil managed
{
// Code size 17 (0x11)
.maxstack 8
IL_0000: ldarg.0
IL_0001: ldflda valuetype [mscorlib]System.ValueTuple`8<int32,int32,int32,int32,int32,int32,int32,valuetype [mscorlib]System.ValueTuple`1<int32>> ICSharpCode.Decompiler.Tests.TestCases.Pretty.TupleTests::Unnamed8
IL_0006: ldflda !7 valuetype [mscorlib]System.ValueTuple`8<int32,int32,int32,int32,int32,int32,int32,valuetype [mscorlib]System.ValueTuple`1<int32>>::Rest
IL_000b: ldfld !0 valuetype [mscorlib]System.ValueTuple`1<int32>::Item1
IL_0010: ret
} // end of method TupleTests::get_AccessUnnamed8
.method public hidebysig specialname instance int32
get_AccessNamed8() cil managed
{
// Code size 17 (0x11)
.maxstack 8
IL_0000: ldarg.0
IL_0001: ldflda valuetype [mscorlib]System.ValueTuple`8<int32,int32,int32,int32,int32,int32,int32,valuetype [mscorlib]System.ValueTuple`1<int32>> ICSharpCode.Decompiler.Tests.TestCases.Pretty.TupleTests::Named8
IL_0006: ldflda !7 valuetype [mscorlib]System.ValueTuple`8<int32,int32,int32,int32,int32,int32,int32,valuetype [mscorlib]System.ValueTuple`1<int32>>::Rest
IL_000b: ldfld !0 valuetype [mscorlib]System.ValueTuple`1<int32>::Item1
IL_0010: ret
} // end of method TupleTests::get_AccessNamed8
.method public hidebysig specialname instance int32
get_AccessPartiallyNamed() cil managed
{
// Code size 24 (0x18)
.maxstack 8
IL_0000: ldarg.0
IL_0001: ldflda valuetype [mscorlib]System.ValueTuple`5<int32,int32,int32,int32,int32> ICSharpCode.Decompiler.Tests.TestCases.Pretty.TupleTests::PartiallyNamed
IL_0006: ldfld !1 valuetype [mscorlib]System.ValueTuple`5<int32,int32,int32,int32,int32>::Item2
IL_000b: ldarg.0
IL_000c: ldflda valuetype [mscorlib]System.ValueTuple`5<int32,int32,int32,int32,int32> ICSharpCode.Decompiler.Tests.TestCases.Pretty.TupleTests::PartiallyNamed
IL_0011: ldfld !2 valuetype [mscorlib]System.ValueTuple`5<int32,int32,int32,int32,int32>::Item3
IL_0016: add
IL_0017: ret
} // end of method TupleTests::get_AccessPartiallyNamed
.method public hidebysig specialname instance valuetype [mscorlib]System.ValueTuple`1<int32>
get_NewTuple1() cil managed
{
// Code size 7 (0x7)
.maxstack 8
IL_0000: ldc.i4.1
IL_0001: newobj instance void valuetype [mscorlib]System.ValueTuple`1<int32>::.ctor(!0)
IL_0006: ret
} // end of method TupleTests::get_NewTuple1
.method public hidebysig specialname instance valuetype [mscorlib]System.ValueTuple`2<int32,int32>
get_NewTuple2() cil managed
{
.param [0]
.custom instance void [mscorlib]System.Runtime.CompilerServices.TupleElementNamesAttribute::.ctor(string[]) = ( 01 00 02 00 00 00 01 61 01 62 00 00 ) // .......a.b..
// Code size 8 (0x8)
.maxstack 8
IL_0000: ldc.i4.1
IL_0001: ldc.i4.2
IL_0002: newobj instance void valuetype [mscorlib]System.ValueTuple`2<int32,int32>::.ctor(!0,
!1)
IL_0007: ret
} // end of method TupleTests::get_NewTuple2
.method public hidebysig specialname instance object
get_BoxedTuple10() cil managed
{
// Code size 28 (0x1c)
.maxstack 10
IL_0000: ldc.i4.1
IL_0001: ldc.i4.2
IL_0002: ldc.i4.3
IL_0003: ldc.i4.4
IL_0004: ldc.i4.5
IL_0005: ldc.i4.6
IL_0006: ldc.i4.7
IL_0007: ldc.i4.8
IL_0008: ldc.i4.s 9
IL_000a: ldc.i4.s 10
IL_000c: newobj instance void valuetype [mscorlib]System.ValueTuple`3<int32,int32,int32>::.ctor(!0,
!1,
!2)
IL_0011: newobj instance void valuetype [mscorlib]System.ValueTuple`8<int32,int32,int32,int32,int32,int32,int32,valuetype [mscorlib]System.ValueTuple`3<int32,int32,int32>>::.ctor(!0,
!1,
!2,
!3,
!4,
!5,
!6,
!7)
IL_0016: box valuetype [mscorlib]System.ValueTuple`8<int32,int32,int32,int32,int32,int32,int32,valuetype [mscorlib]System.ValueTuple`3<int32,int32,int32>>
IL_001b: ret
} // end of method TupleTests::get_BoxedTuple10
.method public hidebysig specialname instance valuetype [mscorlib]System.ValueTuple`2<uint32,int32>
get_SwapUnnamed() cil managed
{
// Code size 28 (0x1c)
.maxstack 8
IL_0000: ldarg.0
IL_0001: ldflda valuetype [mscorlib]System.ValueTuple`2<int32,uint32> ICSharpCode.Decompiler.Tests.TestCases.Pretty.TupleTests::Unnamed2
IL_0006: ldfld !1 valuetype [mscorlib]System.ValueTuple`2<int32,uint32>::Item2
IL_000b: ldarg.0
IL_000c: ldflda valuetype [mscorlib]System.ValueTuple`2<int32,uint32> ICSharpCode.Decompiler.Tests.TestCases.Pretty.TupleTests::Unnamed2
IL_0011: ldfld !0 valuetype [mscorlib]System.ValueTuple`2<int32,uint32>::Item1
IL_0016: newobj instance void valuetype [mscorlib]System.ValueTuple`2<uint32,int32>::.ctor(!0,
!1)
IL_001b: ret
} // end of method TupleTests::get_SwapUnnamed
.method public hidebysig specialname instance valuetype [mscorlib]System.ValueTuple`2<uint32,int32>
get_SwapNamed2() cil managed
{
// Code size 28 (0x1c)
.maxstack 8
IL_0000: ldarg.0
IL_0001: ldflda valuetype [mscorlib]System.ValueTuple`2<int32,uint32> ICSharpCode.Decompiler.Tests.TestCases.Pretty.TupleTests::Named2
IL_0006: ldfld !1 valuetype [mscorlib]System.ValueTuple`2<int32,uint32>::Item2
IL_000b: ldarg.0
IL_000c: ldflda valuetype [mscorlib]System.ValueTuple`2<int32,uint32> ICSharpCode.Decompiler.Tests.TestCases.Pretty.TupleTests::Named2
IL_0011: ldfld !0 valuetype [mscorlib]System.ValueTuple`2<int32,uint32>::Item1
IL_0016: newobj instance void valuetype [mscorlib]System.ValueTuple`2<uint32,int32>::.ctor(!0,
!1)
IL_001b: ret
} // end of method TupleTests::get_SwapNamed2
.method public hidebysig specialname instance int32
get_TupleHash() cil managed
{
// Code size 23 (0x17)
.maxstack 3
.locals init (valuetype [mscorlib]System.ValueTuple`3<int32,int32,int32> V_0)
IL_0000: ldc.i4.1
IL_0001: ldc.i4.2
IL_0002: ldc.i4.3
IL_0003: newobj instance void valuetype [mscorlib]System.ValueTuple`3<int32,int32,int32>::.ctor(!0,
!1,
!2)
IL_0008: stloc.0
IL_0009: ldloca.s V_0
IL_000b: constrained. valuetype [mscorlib]System.ValueTuple`3<int32,int32,int32>
IL_0011: callvirt instance int32 [mscorlib]System.Object::GetHashCode()
IL_0016: ret
} // end of method TupleTests::get_TupleHash
.method public hidebysig specialname instance int32
get_TupleHash2() cil managed
{
// Code size 18 (0x12)
.maxstack 8
IL_0000: ldarg.0
IL_0001: ldflda valuetype [mscorlib]System.ValueTuple`2<int32,uint32> ICSharpCode.Decompiler.Tests.TestCases.Pretty.TupleTests::Named2
IL_0006: constrained. valuetype [mscorlib]System.ValueTuple`2<int32,uint32>
IL_000c: callvirt instance int32 [mscorlib]System.Object::GetHashCode()
IL_0011: ret
} // end of method TupleTests::get_TupleHash2
.method public hidebysig specialname instance valuetype [mscorlib]System.ValueTuple`2<int32,int32>
get_AccessRest() cil managed
{
// Code size 26 (0x1a)
.maxstack 9
IL_0000: ldc.i4.1
IL_0001: ldc.i4.2
IL_0002: ldc.i4.3
IL_0003: ldc.i4.4
IL_0004: ldc.i4.5
IL_0005: ldc.i4.6
IL_0006: ldc.i4.7
IL_0007: ldc.i4.8
IL_0008: ldc.i4.s 9
IL_000a: newobj instance void valuetype [mscorlib]System.ValueTuple`2<int32,int32>::.ctor(!0,
!1)
IL_000f: newobj instance void valuetype [mscorlib]System.ValueTuple`8<int32,int32,int32,int32,int32,int32,int32,valuetype [mscorlib]System.ValueTuple`2<int32,int32>>::.ctor(!0,
!1,
!2,
!3,
!4,
!5,
!6,
!7)
IL_0014: ldfld !7 valuetype [mscorlib]System.ValueTuple`8<int32,int32,int32,int32,int32,int32,int32,valuetype [mscorlib]System.ValueTuple`2<int32,int32>>::Rest
IL_0019: ret
} // end of method TupleTests::get_AccessRest
.method public hidebysig specialname instance valuetype [mscorlib]System.ValueTuple`3<string,object,class [mscorlib]System.Action>
get_TargetTyping() cil managed
{
// Code size 44 (0x2c)
.maxstack 8
IL_0000: ldnull
IL_0001: ldc.i4.1
IL_0002: box [mscorlib]System.Int32
IL_0007: ldsfld class [mscorlib]System.Action ICSharpCode.Decompiler.Tests.TestCases.Pretty.TupleTests/'<>c'::'<>9__45_0'
IL_000c: dup
IL_000d: brtrue.s IL_0026
IL_000f: pop
IL_0010: ldsfld class ICSharpCode.Decompiler.Tests.TestCases.Pretty.TupleTests/'<>c' ICSharpCode.Decompiler.Tests.TestCases.Pretty.TupleTests/'<>c'::'<>9'
IL_0015: ldftn instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.TupleTests/'<>c'::'<get_TargetTyping>b__45_0'()
IL_001b: newobj instance void [mscorlib]System.Action::.ctor(object,
native int)
IL_0020: dup
IL_0021: stsfld class [mscorlib]System.Action ICSharpCode.Decompiler.Tests.TestCases.Pretty.TupleTests/'<>c'::'<>9__45_0'
IL_0026: newobj instance void valuetype [mscorlib]System.ValueTuple`3<string,object,class [mscorlib]System.Action>::.ctor(!0,
!1,
!2)
IL_002b: ret
} // end of method TupleTests::get_TargetTyping
.method public hidebysig specialname instance object
get_NotTargetTyping() cil managed
{
// Code size 49 (0x31)
.maxstack 8
IL_0000: ldnull
IL_0001: ldc.i4.1
IL_0002: box [mscorlib]System.Int32
IL_0007: ldsfld class [mscorlib]System.Action ICSharpCode.Decompiler.Tests.TestCases.Pretty.TupleTests/'<>c'::'<>9__47_0'
IL_000c: dup
IL_000d: brtrue.s IL_0026
IL_000f: pop
IL_0010: ldsfld class ICSharpCode.Decompiler.Tests.TestCases.Pretty.TupleTests/'<>c' ICSharpCode.Decompiler.Tests.TestCases.Pretty.TupleTests/'<>c'::'<>9'
IL_0015: ldftn instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.TupleTests/'<>c'::'<get_NotTargetTyping>b__47_0'()
IL_001b: newobj instance void [mscorlib]System.Action::.ctor(object,
native int)
IL_0020: dup
IL_0021: stsfld class [mscorlib]System.Action ICSharpCode.Decompiler.Tests.TestCases.Pretty.TupleTests/'<>c'::'<>9__47_0'
IL_0026: newobj instance void valuetype [mscorlib]System.ValueTuple`3<string,object,class [mscorlib]System.Action>::.ctor(!0,
!1,
!2)
IL_002b: box valuetype [mscorlib]System.ValueTuple`3<string,object,class [mscorlib]System.Action>
IL_0030: ret
} // end of method TupleTests::get_NotTargetTyping
.method public hidebysig instance void
UseDict() cil managed
{
// Code size 109 (0x6d)
.maxstack 3
.locals init (string V_0,
bool V_1)
IL_0000: nop
IL_0001: ldarg.0
IL_0002: ldfld class [mscorlib]System.Collections.Generic.Dictionary`2<valuetype [mscorlib]System.ValueTuple`2<int32,string>,valuetype [mscorlib]System.ValueTuple`2<string,int32>> ICSharpCode.Decompiler.Tests.TestCases.Pretty.TupleTests::TupleDict
IL_0007: callvirt instance int32 class [mscorlib]System.Collections.Generic.Dictionary`2<valuetype [mscorlib]System.ValueTuple`2<int32,string>,valuetype [mscorlib]System.ValueTuple`2<string,int32>>::get_Count()
IL_000c: ldc.i4.s 10
IL_000e: cgt
IL_0010: stloc.1
IL_0011: ldloc.1
IL_0012: brfalse.s IL_0022
IL_0014: nop
IL_0015: ldarg.0
IL_0016: ldfld class [mscorlib]System.Collections.Generic.Dictionary`2<valuetype [mscorlib]System.ValueTuple`2<int32,string>,valuetype [mscorlib]System.ValueTuple`2<string,int32>> ICSharpCode.Decompiler.Tests.TestCases.Pretty.TupleTests::TupleDict
IL_001b: callvirt instance void class [mscorlib]System.Collections.Generic.Dictionary`2<valuetype [mscorlib]System.ValueTuple`2<int32,string>,valuetype [mscorlib]System.ValueTuple`2<string,int32>>::Clear()
IL_0020: nop
IL_0021: nop
IL_0022: ldarg.0
IL_0023: ldfld class [mscorlib]System.Collections.Generic.Dictionary`2<valuetype [mscorlib]System.ValueTuple`2<int32,string>,valuetype [mscorlib]System.ValueTuple`2<string,int32>> ICSharpCode.Decompiler.Tests.TestCases.Pretty.TupleTests::TupleDict
IL_0028: ldc.i4.1
IL_0029: ldstr "abc"
IL_002e: newobj instance void valuetype [mscorlib]System.ValueTuple`2<int32,string>::.ctor(!0,
!1)
IL_0033: callvirt instance !1 class [mscorlib]System.Collections.Generic.Dictionary`2<valuetype [mscorlib]System.ValueTuple`2<int32,string>,valuetype [mscorlib]System.ValueTuple`2<string,int32>>::get_Item(!0)
IL_0038: ldfld !0 valuetype [mscorlib]System.ValueTuple`2<string,int32>::Item1
IL_003d: stloc.0
IL_003e: ldloc.0
IL_003f: call void [mscorlib]System.Console::WriteLine(string)
IL_0044: nop
IL_0045: ldloc.0
IL_0046: call void [mscorlib]System.Console::WriteLine(string)
IL_004b: nop
IL_004c: ldarg.0
IL_004d: ldfld class [mscorlib]System.Collections.Generic.Dictionary`2<valuetype [mscorlib]System.ValueTuple`2<int32,string>,valuetype [mscorlib]System.ValueTuple`2<string,int32>> ICSharpCode.Decompiler.Tests.TestCases.Pretty.TupleTests::TupleDict
IL_0052: callvirt instance class [mscorlib]System.Collections.Generic.Dictionary`2/ValueCollection<!0,!1> class [mscorlib]System.Collections.Generic.Dictionary`2<valuetype [mscorlib]System.ValueTuple`2<int32,string>,valuetype [mscorlib]System.ValueTuple`2<string,int32>>::get_Values()
IL_0057: call class [mscorlib]System.Collections.Generic.List`1<!!0> [System.Core]System.Linq.Enumerable::ToList<valuetype [mscorlib]System.ValueTuple`2<string,int32>>(class [mscorlib]System.Collections.Generic.IEnumerable`1<!!0>)
IL_005c: call !!0 [System.Core]System.Linq.Enumerable::First<valuetype [mscorlib]System.ValueTuple`2<string,int32>>(class [mscorlib]System.Collections.Generic.IEnumerable`1<!!0>)
IL_0061: ldfld !1 valuetype [mscorlib]System.ValueTuple`2<string,int32>::Item2
IL_0066: call void [mscorlib]System.Console::WriteLine(int32)
IL_006b: nop
IL_006c: ret
} // end of method TupleTests::UseDict
.method public hidebysig specialname rtspecialname
instance void .ctor() cil managed
{
// Code size 8 (0x8)
.maxstack 8
IL_0000: ldarg.0
IL_0001: call instance void [mscorlib]System.Object::.ctor()
IL_0006: nop
IL_0007: ret
} // end of method TupleTests::.ctor
.property instance int32 VT1Member()
{
.get instance int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.TupleTests::get_VT1Member()
} // end of property TupleTests::VT1Member
.property instance int32 AccessUnnamed8()
{
.get instance int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.TupleTests::get_AccessUnnamed8()
} // end of property TupleTests::AccessUnnamed8
.property instance int32 AccessNamed8()
{
.get instance int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.TupleTests::get_AccessNamed8()
} // end of property TupleTests::AccessNamed8
.property instance int32 AccessPartiallyNamed()
{
.get instance int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.TupleTests::get_AccessPartiallyNamed()
} // end of property TupleTests::AccessPartiallyNamed
.property instance valuetype [mscorlib]System.ValueTuple`1<int32>
NewTuple1()
{
.get instance valuetype [mscorlib]System.ValueTuple`1<int32> ICSharpCode.Decompiler.Tests.TestCases.Pretty.TupleTests::get_NewTuple1()
} // end of property TupleTests::NewTuple1
.property instance valuetype [mscorlib]System.ValueTuple`2<int32,int32>
NewTuple2()
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.TupleElementNamesAttribute::.ctor(string[]) = ( 01 00 02 00 00 00 01 61 01 62 00 00 ) // .......a.b..
.get instance valuetype [mscorlib]System.ValueTuple`2<int32,int32> ICSharpCode.Decompiler.Tests.TestCases.Pretty.TupleTests::get_NewTuple2()
} // end of property TupleTests::NewTuple2
.property instance object BoxedTuple10()
{
.get instance object ICSharpCode.Decompiler.Tests.TestCases.Pretty.TupleTests::get_BoxedTuple10()
} // end of property TupleTests::BoxedTuple10
.property instance valuetype [mscorlib]System.ValueTuple`2<uint32,int32>
SwapUnnamed()
{
.get instance valuetype [mscorlib]System.ValueTuple`2<uint32,int32> ICSharpCode.Decompiler.Tests.TestCases.Pretty.TupleTests::get_SwapUnnamed()
} // end of property TupleTests::SwapUnnamed
.property instance valuetype [mscorlib]System.ValueTuple`2<uint32,int32>
SwapNamed2()
{
.get instance valuetype [mscorlib]System.ValueTuple`2<uint32,int32> ICSharpCode.Decompiler.Tests.TestCases.Pretty.TupleTests::get_SwapNamed2()
} // end of property TupleTests::SwapNamed2
.property instance int32 TupleHash()
{
.get instance int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.TupleTests::get_TupleHash()
} // end of property TupleTests::TupleHash
.property instance int32 TupleHash2()
{
.get instance int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.TupleTests::get_TupleHash2()
} // end of property TupleTests::TupleHash2
.property instance valuetype [mscorlib]System.ValueTuple`2<int32,int32>
AccessRest()
{
.get instance valuetype [mscorlib]System.ValueTuple`2<int32,int32> ICSharpCode.Decompiler.Tests.TestCases.Pretty.TupleTests::get_AccessRest()
} // end of property TupleTests::AccessRest
.property instance valuetype [mscorlib]System.ValueTuple`3<string,object,class [mscorlib]System.Action>
TargetTyping()
{
.get instance valuetype [mscorlib]System.ValueTuple`3<string,object,class [mscorlib]System.Action> ICSharpCode.Decompiler.Tests.TestCases.Pretty.TupleTests::get_TargetTyping()
} // end of property TupleTests::TargetTyping
.property instance object NotTargetTyping()
{
.get instance object ICSharpCode.Decompiler.Tests.TestCases.Pretty.TupleTests::get_NotTargetTyping()
} // end of property TupleTests::NotTargetTyping
} // end of class ICSharpCode.Decompiler.Tests.TestCases.Pretty.TupleTests
// =============================================================
// *********** DISASSEMBLY COMPLETE ***********************

12
ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs

@ -187,7 +187,7 @@ namespace ICSharpCode.Decompiler.CSharp @@ -187,7 +187,7 @@ namespace ICSharpCode.Decompiler.CSharp
}
public CSharpDecompiler(ModuleDefinition module, DecompilerSettings settings)
: this(new DecompilerTypeSystem(module), settings)
: this(new DecompilerTypeSystem(module, settings), settings)
{
}
@ -1374,6 +1374,16 @@ namespace ICSharpCode.Decompiler.CSharp @@ -1374,6 +1374,16 @@ namespace ICSharpCode.Decompiler.CSharp
HasNullableSpecifier = true
};
}
if (CecilLoader.IsValueTuple(gType, out int tupleCardinality) && tupleCardinality > 1 && tupleCardinality < TupleType.RestPosition) {
var tupleType = new TupleAstType();
foreach (var typeArgument in gType.GenericArguments) {
typeIndex++;
tupleType.Elements.Add(new TupleTypeElement {
Type = ConvertType(typeArgument, typeAttributes, ref typeIndex, options)
});
}
return tupleType;
}
AstType baseType = ConvertType(gType.ElementType, typeAttributes, ref typeIndex, options & ~ConvertTypeOptions.IncludeTypeParameterDefinitions);
List<AstType> typeArguments = new List<AstType>();
foreach (var typeArgument in gType.GenericArguments) {

95
ICSharpCode.Decompiler/CSharp/CallBuilder.cs

@ -18,6 +18,7 @@ @@ -18,6 +18,7 @@
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics;
using System.Linq;
using ICSharpCode.Decompiler.CSharp.Resolver;
@ -56,6 +57,23 @@ namespace ICSharpCode.Decompiler.CSharp @@ -56,6 +57,23 @@ namespace ICSharpCode.Decompiler.CSharp
if (inst is NewObj newobj && IL.Transforms.DelegateConstruction.IsDelegateConstruction(newobj, true)) {
return HandleDelegateConstruction(newobj);
}
if (settings.TupleTypes && TupleTransform.MatchTupleConstruction(inst as NewObj, out var tupleElements) && tupleElements.Length >= 2) {
var elementTypes = TupleType.GetTupleElementTypes(inst.Method.DeclaringType);
Debug.Assert(!elementTypes.IsDefault, "MatchTupleConstruction should not success unless we got a valid tuple type.");
Debug.Assert(elementTypes.Length == tupleElements.Length);
var tuple = new TupleExpression();
var elementRRs = new List<ResolveResult>();
foreach (var (element, elementType) in tupleElements.Zip(elementTypes)) {
var translatedElement = expressionBuilder.Translate(element, elementType)
.ConvertTo(elementType, expressionBuilder, allowImplicitConversion: true);
tuple.Elements.Add(translatedElement.Expression);
elementRRs.Add(translatedElement.ResolveResult);
}
return tuple.WithRR(new TupleResolveResult(
expressionBuilder.compilation,
elementRRs.ToImmutableArray()
)).WithILInstruction(inst);
}
return Build(inst.OpCode, inst.Method, inst.Arguments, inst.ConstrainedTo).WithILInstruction(inst);
}
@ -70,7 +88,11 @@ namespace ICSharpCode.Decompiler.CSharp @@ -70,7 +88,11 @@ namespace ICSharpCode.Decompiler.CSharp
if (callOpCode == OpCode.NewObj) {
target = default(TranslatedExpression); // no target
} else {
target = expressionBuilder.TranslateTarget(method, callArguments.FirstOrDefault(), callOpCode == OpCode.Call, constrainedTo);
target = expressionBuilder.TranslateTarget(
callArguments.FirstOrDefault(),
nonVirtualInvocation: callOpCode == OpCode.Call,
memberStatic: method.IsStatic,
memberDeclaringType: constrainedTo ?? method.DeclaringType);
if (constrainedTo == null
&& target.Expression is CastExpression cast
&& target.ResolveResult is ConversionResolveResult conversion
@ -116,7 +138,7 @@ namespace ICSharpCode.Decompiler.CSharp @@ -116,7 +138,7 @@ namespace ICSharpCode.Decompiler.CSharp
expandedArguments.Add(expressionBuilder.GetDefaultValueExpression(elementType).WithoutILInstruction());
}
}
if (IsUnambiguousCall(expectedTargetDetails, method, target.ResolveResult, Empty<IType>.Array, expandedArguments) == OverloadResolutionErrors.None) {
if (IsUnambiguousCall(expectedTargetDetails, method, target.ResolveResult, Empty<IType>.Array, expandedArguments, out _) == OverloadResolutionErrors.None) {
isExpandedForm = true;
expectedParameters = expandedParameters;
arguments = expandedArguments.SelectList(a => new TranslatedExpression(a.Expression.Detach()));
@ -155,9 +177,8 @@ namespace ICSharpCode.Decompiler.CSharp @@ -155,9 +177,8 @@ namespace ICSharpCode.Decompiler.CSharp
var argumentResolveResults = arguments.Select(arg => arg.ResolveResult).ToList();
ResolveResult rr = new CSharpInvocationResolveResult(target.ResolveResult, method, argumentResolveResults, isExpandedForm: isExpandedForm);
if (callOpCode == OpCode.NewObj) {
ResolveResult rr = new CSharpInvocationResolveResult(target.ResolveResult, method, argumentResolveResults, isExpandedForm: isExpandedForm);
if (settings.AnonymousTypes && method.DeclaringType.IsAnonymousType()) {
var argumentExpressions = arguments.SelectArray(arg => arg.Expression);
AnonymousTypeCreateExpression atce = new AnonymousTypeCreateExpression();
@ -175,7 +196,7 @@ namespace ICSharpCode.Decompiler.CSharp @@ -175,7 +196,7 @@ namespace ICSharpCode.Decompiler.CSharp
return atce
.WithRR(rr);
} else {
if (IsUnambiguousCall(expectedTargetDetails, method, null, Empty<IType>.Array, arguments) != OverloadResolutionErrors.None) {
if (IsUnambiguousCall(expectedTargetDetails, method, null, Empty<IType>.Array, arguments, out _) != OverloadResolutionErrors.None) {
for (int i = 0; i < arguments.Count; i++) {
if (settings.AnonymousTypes && expectedParameters[i].Type.ContainsAnonymousType()) {
if (arguments[i].Expression is LambdaExpression lambda) {
@ -194,10 +215,11 @@ namespace ICSharpCode.Decompiler.CSharp @@ -194,10 +215,11 @@ namespace ICSharpCode.Decompiler.CSharp
if (method.IsAccessor && (method.AccessorOwner.SymbolKind == SymbolKind.Indexer || expectedParameters.Count == allowedParamCount)) {
return HandleAccessorCall(expectedTargetDetails, method, target, arguments.ToList());
} else if (method.Name == "Invoke" && method.DeclaringType.Kind == TypeKind.Delegate && !IsNullConditional(target)) {
return new InvocationExpression(target, arguments.Select(arg => arg.Expression)).WithRR(rr);
return new InvocationExpression(target, arguments.Select(arg => arg.Expression))
.WithRR(new CSharpInvocationResolveResult(target.ResolveResult, method, argumentResolveResults, isExpandedForm: isExpandedForm));
} else if (IsDelegateEqualityComparison(method, arguments)) {
return HandleDelegateEqualityComparison(method, arguments)
.WithRR(rr);
.WithRR(new CSharpInvocationResolveResult(target.ResolveResult, method, argumentResolveResults, isExpandedForm: isExpandedForm));
} else if (method.IsOperator && method.Name == "op_Implicit" && arguments.Count == 1) {
return HandleImplicitConversion(method, arguments[0]);
} else {
@ -219,8 +241,9 @@ namespace ICSharpCode.Decompiler.CSharp @@ -219,8 +241,9 @@ namespace ICSharpCode.Decompiler.CSharp
bool argumentsCasted = false;
IType[] typeArguments = Empty<IType>.Array;
var targetResolveResult = requireTarget ? target.ResolveResult : null;
IParameterizedMember foundMethod;
OverloadResolutionErrors errors;
while ((errors = IsUnambiguousCall(expectedTargetDetails, method, targetResolveResult, typeArguments, arguments)) != OverloadResolutionErrors.None) {
while ((errors = IsUnambiguousCall(expectedTargetDetails, method, targetResolveResult, typeArguments, arguments, out foundMethod)) != OverloadResolutionErrors.None) {
switch (errors) {
case OverloadResolutionErrors.TypeInferenceFailed:
case OverloadResolutionErrors.WrongNumberOfTypeArguments:
@ -257,8 +280,12 @@ namespace ICSharpCode.Decompiler.CSharp @@ -257,8 +280,12 @@ namespace ICSharpCode.Decompiler.CSharp
}
continue;
}
// We've given up.
foundMethod = method;
break;
}
// Note: after this loop, 'method' and 'foundMethod' may differ,
// but as far as allowed by IsAppropriateCallTarget().
Expression targetExpr;
string methodName = method.Name;
@ -282,7 +309,8 @@ namespace ICSharpCode.Decompiler.CSharp @@ -282,7 +309,8 @@ namespace ICSharpCode.Decompiler.CSharp
if (requireTypeArguments && (!settings.AnonymousTypes || !method.TypeArguments.Any(a => a.ContainsAnonymousType())))
typeArgumentList.AddRange(method.TypeArguments.Select(expressionBuilder.ConvertType));
var argumentExpressions = arguments.Select(arg => arg.Expression);
return new InvocationExpression(targetExpr, argumentExpressions).WithRR(rr);
return new InvocationExpression(targetExpr, argumentExpressions)
.WithRR(new CSharpInvocationResolveResult(target.ResolveResult, foundMethod, argumentResolveResults, isExpandedForm: isExpandedForm));
}
}
}
@ -352,8 +380,10 @@ namespace ICSharpCode.Decompiler.CSharp @@ -352,8 +380,10 @@ namespace ICSharpCode.Decompiler.CSharp
}
OverloadResolutionErrors IsUnambiguousCall(ExpectedTargetDetails expectedTargetDetails, IMethod method,
ResolveResult target, IType[] typeArguments, IList<TranslatedExpression> arguments)
ResolveResult target, IType[] typeArguments, IList<TranslatedExpression> arguments,
out IParameterizedMember foundMember)
{
foundMember = null;
var lookup = new MemberLookup(resolver.CurrentTypeDefinition, resolver.CurrentTypeDefinition.ParentAssembly);
var or = new OverloadResolution(resolver.Compilation, arguments.SelectArray(a => a.ResolveResult), typeArguments: typeArguments);
if (expectedTargetDetails.CallOpCode == OpCode.NewObj) {
@ -375,7 +405,10 @@ namespace ICSharpCode.Decompiler.CSharp @@ -375,7 +405,10 @@ namespace ICSharpCode.Decompiler.CSharp
}
if (or.BestCandidateErrors != OverloadResolutionErrors.None)
return or.BestCandidateErrors;
if (!IsAppropriateCallTarget(expectedTargetDetails, method, or.GetBestCandidateWithSubstitutedTypeArguments()))
if (or.IsAmbiguous)
return OverloadResolutionErrors.AmbiguousMatch;
foundMember = or.GetBestCandidateWithSubstitutedTypeArguments();
if (!IsAppropriateCallTarget(expectedTargetDetails, method, foundMember))
return OverloadResolutionErrors.AmbiguousMatch;
return OverloadResolutionErrors.None;
}
@ -398,16 +431,31 @@ namespace ICSharpCode.Decompiler.CSharp @@ -398,16 +431,31 @@ namespace ICSharpCode.Decompiler.CSharp
return true;
}
bool IsUnambiguousAccess(ExpectedTargetDetails expectedTargetDetails, ResolveResult target, IMethod method)
bool IsUnambiguousAccess(ExpectedTargetDetails expectedTargetDetails, ResolveResult target, IMethod method, out IMember foundMember)
{
foundMember = null;
MemberResolveResult result;
if (target == null) {
var result = resolver.ResolveSimpleName(method.AccessorOwner.Name, EmptyList<IType>.Instance, isInvocationTarget: false) as MemberResolveResult;
return !(result == null || result.IsError || !IsAppropriateCallTarget(expectedTargetDetails, method.AccessorOwner, result.Member));
result = resolver.ResolveSimpleName(method.AccessorOwner.Name, EmptyList<IType>.Instance, isInvocationTarget: false) as MemberResolveResult;
} else {
var lookup = new MemberLookup(resolver.CurrentTypeDefinition, resolver.CurrentTypeDefinition.ParentAssembly);
var result = lookup.Lookup(target, method.AccessorOwner.Name, EmptyList<IType>.Instance, isInvocation: false) as MemberResolveResult;
return !(result == null || result.IsError || !IsAppropriateCallTarget(expectedTargetDetails, method.AccessorOwner, result.Member));
if (method.AccessorOwner.SymbolKind == SymbolKind.Indexer) {
// TODO: use OR here, etc.
result = null;
foreach (var methodList in lookup.LookupIndexers(target)) {
foreach (var indexer in methodList) {
if (IsAppropriateCallTarget(expectedTargetDetails, method.AccessorOwner, indexer)) {
foundMember = indexer;
return true;
}
}
}
} else {
result = lookup.Lookup(target, method.AccessorOwner.Name, EmptyList<IType>.Instance, isInvocation: false) as MemberResolveResult;
}
}
foundMember = result?.Member;
return !(result == null || result.IsError || !IsAppropriateCallTarget(expectedTargetDetails, method.AccessorOwner, result.Member));
}
ExpressionWithResolveResult HandleAccessorCall(ExpectedTargetDetails expectedTargetDetails, IMethod method, TranslatedExpression target, IList<TranslatedExpression> arguments)
@ -417,7 +465,8 @@ namespace ICSharpCode.Decompiler.CSharp @@ -417,7 +465,8 @@ namespace ICSharpCode.Decompiler.CSharp
bool targetCasted = false;
var targetResolveResult = requireTarget ? target.ResolveResult : null;
while (!IsUnambiguousAccess(expectedTargetDetails, targetResolveResult, method)) {
IMember foundMember;
while (!IsUnambiguousAccess(expectedTargetDetails, targetResolveResult, method, out foundMember)) {
if (!requireTarget) {
requireTarget = true;
targetResolveResult = target.ResolveResult;
@ -426,11 +475,12 @@ namespace ICSharpCode.Decompiler.CSharp @@ -426,11 +475,12 @@ namespace ICSharpCode.Decompiler.CSharp
target = target.ConvertTo(method.AccessorOwner.DeclaringType, expressionBuilder);
targetResolveResult = target.ResolveResult;
} else {
foundMember = method.AccessorOwner;
break;
}
}
var rr = new MemberResolveResult(target.ResolveResult, method.AccessorOwner);
var rr = new MemberResolveResult(target.ResolveResult, foundMember);
if (method.ReturnType.IsKnownType(KnownTypeCode.Void)) {
var value = arguments.Last();
@ -475,14 +525,14 @@ namespace ICSharpCode.Decompiler.CSharp @@ -475,14 +525,14 @@ namespace ICSharpCode.Decompiler.CSharp
bool IsAppropriateCallTarget(ExpectedTargetDetails expectedTargetDetails, IMember expectedTarget, IMember actualTarget)
{
if (expectedTarget.Equals(actualTarget))
if (expectedTarget.Equals(actualTarget, NormalizeTypeVisitor.TypeErasure))
return true;
if (expectedTargetDetails.CallOpCode == OpCode.CallVirt && actualTarget.IsOverride) {
if (expectedTargetDetails.NeedsBoxingConversion && actualTarget.DeclaringType.IsReferenceType != true)
return false;
foreach (var possibleTarget in InheritanceHelper.GetBaseMembers(actualTarget, false)) {
if (expectedTarget.Equals(possibleTarget))
if (expectedTarget.Equals(possibleTarget, NormalizeTypeVisitor.TypeErasure))
return true;
if (!possibleTarget.IsOverride)
break;
@ -516,7 +566,10 @@ namespace ICSharpCode.Decompiler.CSharp @@ -516,7 +566,10 @@ namespace ICSharpCode.Decompiler.CSharp
requireTarget = true;
} else {
targetType = method.DeclaringType;
target = expressionBuilder.TranslateTarget(method, inst.Arguments[0], func.OpCode == OpCode.LdFtn);
target = expressionBuilder.TranslateTarget(inst.Arguments[0],
nonVirtualInvocation: func.OpCode == OpCode.LdFtn,
memberStatic: method.IsStatic,
memberDeclaringType: method.DeclaringType);
target = ExpressionBuilder.UnwrapBoxingConversion(target);
requireTarget = expressionBuilder.HidesVariableWithName(method.Name)
|| (method.IsStatic ? !expressionBuilder.IsCurrentOrContainingType(method.DeclaringTypeDefinition) : !(target.Expression is ThisReferenceExpression));

51
ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs

@ -194,7 +194,10 @@ namespace ICSharpCode.Decompiler.CSharp @@ -194,7 +194,10 @@ namespace ICSharpCode.Decompiler.CSharp
ExpressionWithResolveResult ConvertField(IField field, ILInstruction targetInstruction = null)
{
var target = TranslateTarget(field, targetInstruction, true);
var target = TranslateTarget(targetInstruction,
nonVirtualInvocation: true,
memberStatic: field.IsStatic,
memberDeclaringType: field.DeclaringType);
bool requireTarget = HidesVariableWithName(field.Name)
|| (field.IsStatic ? !IsCurrentOrContainingType(field.DeclaringTypeDefinition) : !(target.Expression is ThisReferenceExpression || target.Expression is BaseReferenceExpression));
bool targetCasted = false;
@ -204,11 +207,11 @@ namespace ICSharpCode.Decompiler.CSharp @@ -204,11 +207,11 @@ namespace ICSharpCode.Decompiler.CSharp
{
if (targetResolveResult == null) {
var result = resolver.ResolveSimpleName(field.Name, EmptyList<IType>.Instance, isInvocationTarget: false) as MemberResolveResult;
return !(result == null || result.IsError || !result.Member.Equals(field));
return !(result == null || result.IsError || !result.Member.Equals(field, NormalizeTypeVisitor.TypeErasure));
} else {
var lookup = new MemberLookup(resolver.CurrentTypeDefinition, resolver.CurrentTypeDefinition.ParentAssembly);
var result = lookup.Lookup(target.ResolveResult, field.Name, EmptyList<IType>.Instance, false) as MemberResolveResult;
return !(result == null || result.IsError || !result.Member.Equals(field));
return !(result == null || result.IsError || !result.Member.Equals(field, NormalizeTypeVisitor.TypeErasure));
}
}
@ -1610,20 +1613,21 @@ namespace ICSharpCode.Decompiler.CSharp @@ -1610,20 +1613,21 @@ namespace ICSharpCode.Decompiler.CSharp
}
}
internal TranslatedExpression TranslateTarget(IMember member, ILInstruction target, bool nonVirtualInvocation, IType constrainedTo = null)
internal TranslatedExpression TranslateTarget(ILInstruction target, bool nonVirtualInvocation,
bool memberStatic, IType memberDeclaringType)
{
// If references are missing member.IsStatic might not be set correctly.
// Additionally check target for null, in order to avoid a crash.
if (!member.IsStatic && target != null) {
if (nonVirtualInvocation && target.MatchLdThis() && member.DeclaringTypeDefinition != resolver.CurrentTypeDefinition) {
if (!memberStatic && target != null) {
if (nonVirtualInvocation && target.MatchLdThis() && memberDeclaringType.GetDefinition() != resolver.CurrentTypeDefinition) {
return new BaseReferenceExpression()
.WithILInstruction(target)
.WithRR(new ThisResolveResult(member.DeclaringType, nonVirtualInvocation));
.WithRR(new ThisResolveResult(memberDeclaringType, nonVirtualInvocation));
} else {
var translatedTarget = Translate(target, constrainedTo ?? member.DeclaringType);
if (CallInstruction.ExpectedTypeForThisPointer(constrainedTo ?? member.DeclaringType) == StackType.Ref && translatedTarget.Type.GetStackType().IsIntegerType()) {
var translatedTarget = Translate(target, memberDeclaringType);
if (CallInstruction.ExpectedTypeForThisPointer(memberDeclaringType) == StackType.Ref && translatedTarget.Type.GetStackType().IsIntegerType()) {
// when accessing members on value types, ensure we use a reference and not a pointer
translatedTarget = translatedTarget.ConvertTo(new ByReferenceType(constrainedTo ?? member.DeclaringType), this);
translatedTarget = translatedTarget.ConvertTo(new ByReferenceType(memberDeclaringType), this);
}
if (translatedTarget.Expression is DirectionExpression) {
// (ref x).member => x.member
@ -1642,9 +1646,9 @@ namespace ICSharpCode.Decompiler.CSharp @@ -1642,9 +1646,9 @@ namespace ICSharpCode.Decompiler.CSharp
return translatedTarget;
}
} else {
return new TypeReferenceExpression(ConvertType(member.DeclaringType))
return new TypeReferenceExpression(ConvertType(memberDeclaringType))
.WithoutILInstruction()
.WithRR(new TypeResolveResult(member.DeclaringType));
.WithRR(new TypeResolveResult(memberDeclaringType));
}
}
@ -1752,7 +1756,26 @@ namespace ICSharpCode.Decompiler.CSharp @@ -1752,7 +1756,26 @@ namespace ICSharpCode.Decompiler.CSharp
return result;
}
}
var expr = ConvertField(inst.Field, inst.Target).WithILInstruction(inst);
TranslatedExpression expr;
if (TupleTransform.MatchTupleFieldAccess(inst, out IType underlyingTupleType, out var target, out int position)) {
var translatedTarget = TranslateTarget(target,
nonVirtualInvocation: true,
memberStatic: false,
memberDeclaringType: underlyingTupleType);
if (translatedTarget.Type is TupleType tupleType && tupleType.UnderlyingType.Equals(underlyingTupleType) && position <= tupleType.ElementNames.Length) {
string elementName = tupleType.ElementNames[position - 1];
if (elementName == null) {
elementName = "Item" + position;
}
expr = new MemberReferenceExpression(translatedTarget, elementName)
.WithRR(new MemberResolveResult(translatedTarget.ResolveResult, inst.Field))
.WithILInstruction(inst);
} else {
expr = ConvertField(inst.Field, inst.Target).WithILInstruction(inst);
}
} else {
expr = ConvertField(inst.Field, inst.Target).WithILInstruction(inst);
}
if (inst.ResultType == StackType.I) {
// ldflda producing native pointer
return new UnaryOperatorExpression(UnaryOperatorType.AddressOf, expr)
@ -1760,7 +1783,7 @@ namespace ICSharpCode.Decompiler.CSharp @@ -1760,7 +1783,7 @@ namespace ICSharpCode.Decompiler.CSharp
} else {
// ldflda producing managed pointer
return new DirectionExpression(FieldDirection.Ref, expr)
.WithoutILInstruction().WithRR(new ByReferenceResolveResult(expr.Type, isOut: false));
.WithoutILInstruction().WithRR(new ByReferenceResolveResult(expr.ResolveResult, isOut: false));
}
}

37
ICSharpCode.Decompiler/CSharp/OutputVisitor/CSharpOutputVisitor.cs

@ -24,6 +24,7 @@ using System.Linq; @@ -24,6 +24,7 @@ using System.Linq;
using ICSharpCode.Decompiler.CSharp.Syntax;
using ICSharpCode.Decompiler.CSharp.Syntax.PatternMatching;
using ICSharpCode.Decompiler.TypeSystem;
using ICSharpCode.Decompiler.Util;
using Attribute = ICSharpCode.Decompiler.CSharp.Syntax.Attribute;
namespace ICSharpCode.Decompiler.CSharp.OutputVisitor
@ -444,6 +445,7 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor @@ -444,6 +445,7 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor
{
foreach (CSharpModifierToken modifier in modifierTokens) {
modifier.AcceptVisitor(this);
Space();
}
}
@ -1061,7 +1063,17 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor @@ -1061,7 +1063,17 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor
throwExpression.Expression.AcceptVisitor(this);
EndNode(throwExpression);
}
public virtual void VisitTupleExpression(TupleExpression tupleExpression)
{
Debug.Assert(tupleExpression.Elements.Count >= 2);
StartNode(tupleExpression);
LPar();
WriteCommaSeparatedList(tupleExpression.Elements);
RPar();
EndNode(tupleExpression);
}
public virtual void VisitTypeOfExpression(TypeOfExpression typeOfExpression)
{
StartNode(typeOfExpression);
@ -2269,7 +2281,28 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor @@ -2269,7 +2281,28 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor
WriteTypeArguments(memberType.TypeArguments);
EndNode(memberType);
}
public virtual void VisitTupleType(TupleAstType tupleType)
{
Debug.Assert(tupleType.Elements.Count >= 2);
StartNode(tupleType);
LPar();
WriteCommaSeparatedList(tupleType.Elements);
RPar();
EndNode(tupleType);
}
public virtual void VisitTupleTypeElement(TupleTypeElement tupleTypeElement)
{
StartNode(tupleTypeElement);
tupleTypeElement.Type.AcceptVisitor(this);
if (!tupleTypeElement.NameToken.IsNull) {
Space();
tupleTypeElement.NameToken.AcceptVisitor(this);
}
EndNode(tupleTypeElement);
}
public virtual void VisitComposedType(ComposedType composedType)
{
StartNode(composedType);

130
ICSharpCode.Decompiler/CSharp/Resolver/CSharpConversions.cs

@ -19,6 +19,7 @@ @@ -19,6 +19,7 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics;
using System.Linq;
using ICSharpCode.Decompiler.Semantics;
@ -37,15 +38,12 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -37,15 +38,12 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
{
readonly ConcurrentDictionary<TypePair, Conversion> implicitConversionCache = new ConcurrentDictionary<TypePair, Conversion>();
readonly ICompilation compilation;
readonly IType objectType;
public CSharpConversions(ICompilation compilation)
{
if (compilation == null)
throw new ArgumentNullException("compilation");
this.compilation = compilation;
this.objectType = compilation.FindType(KnownTypeCode.Object);
this.dynamicErasure = new DynamicErasure(this);
}
/// <summary>
@ -97,7 +95,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -97,7 +95,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
#endregion
#region ImplicitConversion
private Conversion ImplicitConversion(ResolveResult resolveResult, IType toType, bool allowUserDefined)
private Conversion ImplicitConversion(ResolveResult resolveResult, IType toType, bool allowUserDefined, bool allowTuple)
{
Conversion c;
if (resolveResult.IsCompileTimeConstant) {
@ -105,18 +103,23 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -105,18 +103,23 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
if (c.IsValid) return c;
if (ImplicitConstantExpressionConversion(resolveResult, toType))
return Conversion.ImplicitConstantExpressionConversion;
c = StandardImplicitConversion(resolveResult.Type, toType);
c = StandardImplicitConversion(resolveResult.Type, toType, allowTuple);
if (c != Conversion.None) return c;
if (allowUserDefined) {
c = UserDefinedImplicitConversion(resolveResult, resolveResult.Type, toType);
if (c != Conversion.None) return c;
}
} else {
if (allowUserDefined) {
// if allowUserDefined is true, we might as well use the cache
if (allowTuple && resolveResult is TupleResolveResult tupleRR) {
c = TupleConversion(tupleRR, toType, isExplicit: false);
if (c != Conversion.None)
return c;
}
if (allowUserDefined && allowTuple) {
// if allowUserDefined and allowTuple are true, we might as well use the cache
c = ImplicitConversion(resolveResult.Type, toType);
} else {
c = ImplicitConversion(resolveResult.Type, toType, allowUserDefined);
c = ImplicitConversion(resolveResult.Type, toType, allowUserDefined, allowTuple);
}
if (c != Conversion.None) return c;
}
@ -128,10 +131,10 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -128,10 +131,10 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
return c;
}
private Conversion ImplicitConversion(IType fromType, IType toType, bool allowUserDefined)
private Conversion ImplicitConversion(IType fromType, IType toType, bool allowUserDefined, bool allowTuple)
{
// C# 4.0 spec: §6.1
var c = StandardImplicitConversion(fromType, toType);
var c = StandardImplicitConversion(fromType, toType, allowTuple);
if (c == Conversion.None && allowUserDefined) {
c = UserDefinedImplicitConversion(null, fromType, toType);
}
@ -142,7 +145,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -142,7 +145,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
{
if (resolveResult == null)
throw new ArgumentNullException("resolveResult");
return ImplicitConversion(resolveResult, toType, allowUserDefined: true);
return ImplicitConversion(resolveResult, toType, allowUserDefined: true, allowTuple: true);
}
public Conversion ImplicitConversion(IType fromType, IType toType)
@ -157,18 +160,23 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -157,18 +160,23 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
if (implicitConversionCache.TryGetValue(pair, out c))
return c;
c = ImplicitConversion(fromType, toType, allowUserDefined: true);
c = ImplicitConversion(fromType, toType, allowUserDefined: true, allowTuple: true);
implicitConversionCache[pair] = c;
return c;
}
public Conversion StandardImplicitConversion(IType fromType, IType toType)
{
if (fromType == null)
throw new ArgumentNullException("fromType");
if (toType == null)
throw new ArgumentNullException("toType");
return StandardImplicitConversion(fromType, toType, allowTupleConversion: true);
}
Conversion StandardImplicitConversion(IType fromType, IType toType, bool allowTupleConversion)
{
// C# 4.0 spec: §6.3.1
if (IdentityConversion(fromType, toType))
return Conversion.IdentityConversion;
@ -190,9 +198,14 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -190,9 +198,14 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
}
if (ImplicitPointerConversion(fromType, toType))
return Conversion.ImplicitPointerConversion;
if (allowTupleConversion) {
c = TupleConversion(fromType, toType, isExplicit: false);
if (c != Conversion.None)
return c;
}
return Conversion.None;
}
/// <summary>
/// Gets whether the type 'fromType' is convertible to 'toType'
/// using one of the conversions allowed when satisying constraints (§4.4.4)
@ -233,9 +246,14 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -233,9 +246,14 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
if (resolveResult.Type.Kind == TypeKind.Dynamic)
return Conversion.ExplicitDynamicConversion;
Conversion c = ImplicitConversion(resolveResult, toType, allowUserDefined: false);
Conversion c = ImplicitConversion(resolveResult, toType, allowUserDefined: false, allowTuple: false);
if (c != Conversion.None)
return c;
if (resolveResult is TupleResolveResult tupleRR) {
c = TupleConversion(tupleRR, toType, isExplicit: true);
if (c != Conversion.None)
return c;
}
c = ExplicitConversionImpl(resolveResult.Type, toType);
if (c != Conversion.None)
return c;
@ -249,7 +267,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -249,7 +267,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
if (toType == null)
throw new ArgumentNullException("toType");
Conversion c = ImplicitConversion(fromType, toType, allowUserDefined: false);
Conversion c = ImplicitConversion(fromType, toType, allowUserDefined: false, allowTuple: false);
if (c != Conversion.None)
return c;
c = ExplicitConversionImpl(fromType, toType);
@ -278,10 +296,10 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -278,10 +296,10 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
return c;
if (ExplicitPointerConversion(fromType, toType))
return Conversion.ExplicitPointerConversion;
return Conversion.None;
return TupleConversion(fromType, toType, isExplicit: true);
}
#endregion
#region Identity Conversion
/// <summary>
/// Gets whether there is an identity conversion from <paramref name="fromType"/> to <paramref name="toType"/>
@ -289,27 +307,9 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -289,27 +307,9 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
public bool IdentityConversion(IType fromType, IType toType)
{
// C# 4.0 spec: §6.1.1
return fromType.AcceptVisitor(dynamicErasure).Equals(toType.AcceptVisitor(dynamicErasure));
}
readonly DynamicErasure dynamicErasure;
sealed class DynamicErasure : TypeVisitor
{
readonly IType objectType;
public DynamicErasure(CSharpConversions conversions)
{
this.objectType = conversions.objectType;
}
public override IType VisitOtherType(IType type)
{
if (type.Kind == TypeKind.Dynamic)
return objectType;
else
return base.VisitOtherType(type);
}
fromType = fromType.AcceptVisitor(NormalizeTypeVisitor.TypeErasure);
toType = toType.AcceptVisitor(NormalizeTypeVisitor.TypeErasure);
return fromType.Equals(toType);
}
#endregion
@ -494,7 +494,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -494,7 +494,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
bool IsSubtypeOf(IType s, IType t, int subtypeCheckNestingDepth)
{
// conversion to dynamic + object are always possible
if (t.Kind == TypeKind.Dynamic || t.Equals(objectType))
if (t.Kind == TypeKind.Dynamic || t.IsKnownType(KnownTypeCode.Object))
return true;
if (subtypeCheckNestingDepth > 10) {
// Subtyping in C# is undecidable
@ -856,7 +856,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -856,7 +856,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
Conversion UserDefinedExplicitConversion(ResolveResult fromResult, IType fromType, IType toType)
{
// C# 4.0 spec §6.4.5 User-defined implicit conversions
// C# 4.0 spec §6.4.5 User-defined explicit conversions
var operators = GetApplicableConversionOperators(fromResult, fromType, toType, true);
if (operators.Count > 0) {
IType mostSpecificSource;
@ -1135,7 +1135,53 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -1135,7 +1135,53 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
|| IsImplicitReferenceConversion(m.ReturnType, invoke.ReturnType);
}
#endregion
#region Tuple Conversion
Conversion TupleConversion(TupleResolveResult fromRR, IType toType, bool isExplicit)
{
var fromElements = fromRR.Elements;
var toElements = TupleType.GetTupleElementTypes(toType);
if (toElements.IsDefault || fromElements.Length != toElements.Length)
return Conversion.None;
Conversion[] elementConversions = new Conversion[fromElements.Length];
for (int i = 0; i < elementConversions.Length; i++) {
Conversion c;
if (isExplicit) {
c = ExplicitConversion(fromElements[i], toElements[i]);
} else {
c = ImplicitConversion(fromElements[i], toElements[i]);
}
if (!c.IsValid)
return Conversion.None;
elementConversions[i] = c;
}
return Conversion.TupleConversion(elementConversions.ToImmutableArray());
}
Conversion TupleConversion(IType fromType, IType toType, bool isExplicit)
{
var fromElements = TupleType.GetTupleElementTypes(fromType);
if (fromElements.IsDefaultOrEmpty)
return Conversion.None;
var toElements = TupleType.GetTupleElementTypes(toType);
if (toElements.IsDefault || fromElements.Length != toElements.Length)
return Conversion.None;
Conversion[] elementConversions = new Conversion[fromElements.Length];
for (int i = 0; i < elementConversions.Length; i++) {
Conversion c;
if (isExplicit) {
c = ExplicitConversion(fromElements[i], toElements[i]);
} else {
c = ImplicitConversion(fromElements[i], toElements[i]);
}
if (!c.IsValid)
return Conversion.None;
elementConversions[i] = c;
}
return Conversion.TupleConversion(elementConversions.ToImmutableArray());
}
#endregion
#region BetterConversion
/// <summary>
/// Gets the better conversion (C# 4.0 spec, §7.5.3.3)

45
ICSharpCode.Decompiler/CSharp/Resolver/CSharpOperators.cs

@ -255,6 +255,11 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -255,6 +255,11 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
b.Append(')');
return b.ToString();
}
bool IMember.Equals(IMember obj, TypeVisitor typeNormalization)
{
return this == obj;
}
}
#endregion
@ -1055,13 +1060,15 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -1055,13 +1060,15 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
: base((IMethod)nonLiftedMethod.MemberDefinition, nonLiftedMethod.Substitution)
{
this.nonLiftedOperator = nonLiftedMethod;
var substitution = new MakeNullableVisitor(nonLiftedMethod.Compilation, nonLiftedMethod.Substitution);
this.Parameters = base.CreateParameters(substitution);
var compilation = nonLiftedMethod.Compilation;
var substitution = nonLiftedMethod.Substitution;
this.Parameters = base.CreateParameters(
type => NullableType.Create(compilation, type.AcceptVisitor(substitution)));
// Comparison operators keep the 'bool' return type even when lifted.
if (IsComparisonOperator(nonLiftedMethod))
this.ReturnType = nonLiftedMethod.ReturnType;
else
this.ReturnType = nonLiftedMethod.ReturnType.AcceptVisitor(substitution);
this.ReturnType = NullableType.Create(compilation, nonLiftedMethod.ReturnType.AcceptVisitor(substitution));
}
public IReadOnlyList<IParameter> NonLiftedParameters => nonLiftedOperator.Parameters;
@ -1078,38 +1085,6 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -1078,38 +1085,6 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
return nonLiftedOperator.GetHashCode() ^ 0x7191254;
}
}
sealed class MakeNullableVisitor : TypeVisitor
{
readonly ICompilation compilation;
readonly TypeParameterSubstitution typeParameterSubstitution;
public MakeNullableVisitor(ICompilation compilation, TypeParameterSubstitution typeParameterSubstitution)
{
this.compilation = compilation;
this.typeParameterSubstitution = typeParameterSubstitution;
}
public override IType VisitTypeDefinition(ITypeDefinition type)
{
return NullableType.Create(compilation, type.AcceptVisitor(typeParameterSubstitution));
}
public override IType VisitTypeParameter(ITypeParameter type)
{
return NullableType.Create(compilation, type.AcceptVisitor(typeParameterSubstitution));
}
public override IType VisitParameterizedType(ParameterizedType type)
{
return NullableType.Create(compilation, type.AcceptVisitor(typeParameterSubstitution));
}
public override IType VisitOtherType(IType type)
{
return NullableType.Create(compilation, type.AcceptVisitor(typeParameterSubstitution));
}
}
#endregion
}

4
ICSharpCode.Decompiler/CSharp/Resolver/CSharpResolver.cs

@ -1996,7 +1996,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -1996,7 +1996,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
} else {
// argument might be a lambda or delegate type, so we have to try to guess the delegate type
IType type = arguments[i].Type;
if (type.Kind == TypeKind.Null || type.Kind == TypeKind.Unknown) {
if (type.Kind == TypeKind.Null || type.Kind == TypeKind.None) {
list.Add(new DefaultParameter(compilation.FindType(KnownTypeCode.Object), argumentNames[i]));
} else {
list.Add(new DefaultParameter(type, argumentNames[i]));
@ -2353,7 +2353,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -2353,7 +2353,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
bool HasType(ResolveResult r)
{
return r.Type.Kind != TypeKind.Unknown && r.Type.Kind != TypeKind.Null;
return r.Type.Kind != TypeKind.None && r.Type.Kind != TypeKind.Null;
}
#endregion

2
ICSharpCode.Decompiler/CSharp/Resolver/LambdaResolveResult.cs

@ -30,7 +30,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -30,7 +30,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
/// </summary>
public abstract class LambdaResolveResult : ResolveResult
{
protected LambdaResolveResult() : base(SpecialType.UnknownType)
protected LambdaResolveResult() : base(SpecialType.NoType)
{
}

2
ICSharpCode.Decompiler/CSharp/Resolver/MethodGroupResolveResult.cs

@ -83,7 +83,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -83,7 +83,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
public MethodGroupResolveResult(ResolveResult targetResult, string methodName,
IReadOnlyList<MethodListWithDeclaringType> methods, IReadOnlyList<IType> typeArguments)
: base(SpecialType.UnknownType)
: base(SpecialType.NoType)
{
if (methods == null)
throw new ArgumentNullException("methods");

8
ICSharpCode.Decompiler/CSharp/Resolver/ReducedExtensionMethod.cs

@ -45,6 +45,14 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -45,6 +45,14 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
this.baseMethod = baseMethod;
}
public bool Equals(IMember obj, TypeVisitor typeNormalization)
{
var other = obj as ReducedExtensionMethod;
if (other == null)
return false;
return baseMethod.Equals(other.baseMethod, typeNormalization);
}
public override bool Equals(object obj)
{
var other = obj as ReducedExtensionMethod;

16
ICSharpCode.Decompiler/CSharp/Resolver/TypeInference.cs

@ -295,7 +295,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -295,7 +295,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
static bool IsValidType(IType type)
{
return type.Kind != TypeKind.Unknown && type.Kind != TypeKind.Null;
return type.Kind != TypeKind.Unknown && type.Kind != TypeKind.Null && type.Kind != TypeKind.None;
}
bool PhaseTwo()
@ -593,8 +593,8 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -593,8 +593,8 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
return;
}
// Handle parameterized type:
ParameterizedType pU = U as ParameterizedType;
ParameterizedType pV = V as ParameterizedType;
ParameterizedType pU = U.TupleUnderlyingTypeOrSelf() as ParameterizedType;
ParameterizedType pV = V.TupleUnderlyingTypeOrSelf() as ParameterizedType;
if (pU != null && pV != null
&& object.Equals(pU.GenericType, pV.GenericType)
&& pU.TypeParameterCount == pV.TypeParameterCount)
@ -644,7 +644,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -644,7 +644,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
// Handle array types:
ArrayType arrU = U as ArrayType;
ArrayType arrV = V as ArrayType;
ParameterizedType pV = V as ParameterizedType;
ParameterizedType pV = V.TupleUnderlyingTypeOrSelf() as ParameterizedType;
if (arrU != null && arrV != null && arrU.Dimensions == arrV.Dimensions) {
MakeLowerBoundInference(arrU.ElementType, arrV.ElementType);
return;
@ -656,7 +656,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -656,7 +656,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
if (pV != null) {
ParameterizedType uniqueBaseType = null;
foreach (IType baseU in U.GetAllBaseTypes()) {
ParameterizedType pU = baseU as ParameterizedType;
ParameterizedType pU = baseU.TupleUnderlyingTypeOrSelf() as ParameterizedType;
if (pU != null && object.Equals(pU.GenericType, pV.GenericType) && pU.TypeParameterCount == pV.TypeParameterCount) {
if (uniqueBaseType == null)
uniqueBaseType = pU;
@ -730,7 +730,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -730,7 +730,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
// Handle array types:
ArrayType arrU = U as ArrayType;
ArrayType arrV = V as ArrayType;
ParameterizedType pU = U as ParameterizedType;
ParameterizedType pU = U.TupleUnderlyingTypeOrSelf() as ParameterizedType;
if (arrV != null && arrU != null && arrU.Dimensions == arrV.Dimensions) {
MakeUpperBoundInference(arrU.ElementType, arrV.ElementType);
return;
@ -742,7 +742,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -742,7 +742,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
if (pU != null) {
ParameterizedType uniqueBaseType = null;
foreach (IType baseV in V.GetAllBaseTypes()) {
ParameterizedType pV = baseV as ParameterizedType;
ParameterizedType pV = baseV.TupleUnderlyingTypeOrSelf() as ParameterizedType;
if (pV != null && object.Equals(pU.GenericType, pV.GenericType) && pU.TypeParameterCount == pV.TypeParameterCount) {
if (uniqueBaseType == null)
uniqueBaseType = pV;
@ -818,7 +818,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -818,7 +818,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
if (expressions == null)
throw new ArgumentNullException("expressions");
if (expressions.Count == 1) {
success = (expressions[0].Type.Kind != TypeKind.Unknown);
success = IsValidType(expressions[0].Type);
return expressions[0].Type;
}
Log.WriteCollection("GetBestCommonType() for ", expressions);

51
ICSharpCode.Decompiler/CSharp/Syntax/DepthFirstAstVisitor.cs

@ -115,7 +115,17 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -115,7 +115,17 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
{
VisitChildren (memberType);
}
public virtual void VisitTupleType(TupleAstType tupleType)
{
VisitChildren(tupleType);
}
public virtual void VisitTupleTypeElement(TupleTypeElement tupleTypeElement)
{
VisitChildren (tupleTypeElement);
}
public virtual void VisitAttribute (Attribute attribute)
{
VisitChildren (attribute);
@ -536,6 +546,11 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -536,6 +546,11 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
VisitChildren (throwExpression);
}
public virtual void VisitTupleExpression(TupleExpression tupleExpression)
{
VisitChildren (tupleExpression);
}
public virtual void VisitTypeOfExpression (TypeOfExpression typeOfExpression)
{
VisitChildren (typeOfExpression);
@ -747,7 +762,17 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -747,7 +762,17 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
{
return VisitChildren (memberType);
}
public virtual T VisitTupleType(TupleAstType tupleType)
{
return VisitChildren (tupleType);
}
public virtual T VisitTupleTypeElement(TupleTypeElement tupleTypeElement)
{
return VisitChildren (tupleTypeElement);
}
public virtual T VisitAttribute (Attribute attribute)
{
return VisitChildren (attribute);
@ -1168,6 +1193,11 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -1168,6 +1193,11 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
return VisitChildren (throwExpression);
}
public virtual T VisitTupleExpression (TupleExpression tupleExpression)
{
return VisitChildren (tupleExpression);
}
public virtual T VisitTypeOfExpression (TypeOfExpression typeOfExpression)
{
return VisitChildren (typeOfExpression);
@ -1379,7 +1409,17 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -1379,7 +1409,17 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
{
return VisitChildren (memberType, data);
}
public virtual S VisitTupleType(TupleAstType tupleType, T data)
{
return VisitChildren (tupleType, data);
}
public virtual S VisitTupleTypeElement(TupleTypeElement tupleTypeElement, T data)
{
return VisitChildren (tupleTypeElement, data);
}
public virtual S VisitAttribute (Attribute attribute, T data)
{
return VisitChildren (attribute, data);
@ -1800,6 +1840,11 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -1800,6 +1840,11 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
return VisitChildren (throwExpression, data);
}
public virtual S VisitTupleExpression (TupleExpression tupleExpression, T data)
{
return VisitChildren (tupleExpression, data);
}
public virtual S VisitTypeOfExpression (TypeOfExpression typeOfExpression, T data)
{
return VisitChildren (typeOfExpression, data);

51
ICSharpCode.Decompiler/CSharp/Syntax/Expressions/TupleExpression.cs

@ -0,0 +1,51 @@ @@ -0,0 +1,51 @@
// 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 ICSharpCode.Decompiler.CSharp.Syntax.PatternMatching;
namespace ICSharpCode.Decompiler.CSharp.Syntax
{
public class TupleExpression : Expression
{
public AstNodeCollection<Expression> Elements {
get { return GetChildrenByRole(Roles.Expression); }
}
public override void AcceptVisitor(IAstVisitor visitor)
{
visitor.VisitTupleExpression(this);
}
public override T AcceptVisitor<T>(IAstVisitor<T> visitor)
{
return visitor.VisitTupleExpression(this);
}
public override S AcceptVisitor<T, S>(IAstVisitor<T, S> visitor, T data)
{
return visitor.VisitTupleExpression(this, data);
}
protected internal override bool DoMatch(AstNode other, Match match)
{
return other is TupleExpression tuple
&& Elements.DoMatch(tuple.Elements, match);
}
}
}

9
ICSharpCode.Decompiler/CSharp/Syntax/IAstVisitor.cs

@ -56,6 +56,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -56,6 +56,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
void VisitStackAllocExpression(StackAllocExpression stackAllocExpression);
void VisitThisReferenceExpression(ThisReferenceExpression thisReferenceExpression);
void VisitThrowExpression(ThrowExpression throwExpression);
void VisitTupleExpression(TupleExpression tupleExpression);
void VisitTypeOfExpression(TypeOfExpression typeOfExpression);
void VisitTypeReferenceExpression(TypeReferenceExpression typeReferenceExpression);
void VisitUnaryOperatorExpression(UnaryOperatorExpression unaryOperatorExpression);
@ -133,6 +134,8 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -133,6 +134,8 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
void VisitSyntaxTree(SyntaxTree syntaxTree);
void VisitSimpleType(SimpleType simpleType);
void VisitMemberType(MemberType memberType);
void VisitTupleType(TupleAstType tupleType);
void VisitTupleTypeElement(TupleTypeElement tupleTypeElement);
void VisitComposedType(ComposedType composedType);
void VisitArraySpecifier(ArraySpecifier arraySpecifier);
void VisitPrimitiveType(PrimitiveType primitiveType);
@ -194,6 +197,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -194,6 +197,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
S VisitStackAllocExpression(StackAllocExpression stackAllocExpression);
S VisitThisReferenceExpression(ThisReferenceExpression thisReferenceExpression);
S VisitThrowExpression(ThrowExpression throwExpression);
S VisitTupleExpression(TupleExpression tupleExpression);
S VisitTypeOfExpression(TypeOfExpression typeOfExpression);
S VisitTypeReferenceExpression(TypeReferenceExpression typeReferenceExpression);
S VisitUnaryOperatorExpression(UnaryOperatorExpression unaryOperatorExpression);
@ -271,6 +275,8 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -271,6 +275,8 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
S VisitSyntaxTree(SyntaxTree syntaxTree);
S VisitSimpleType(SimpleType simpleType);
S VisitMemberType(MemberType memberType);
S VisitTupleType(TupleAstType tupleType);
S VisitTupleTypeElement(TupleTypeElement tupleTypeElement);
S VisitComposedType(ComposedType composedType);
S VisitArraySpecifier(ArraySpecifier arraySpecifier);
S VisitPrimitiveType(PrimitiveType primitiveType);
@ -332,6 +338,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -332,6 +338,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
S VisitStackAllocExpression(StackAllocExpression stackAllocExpression, T data);
S VisitThisReferenceExpression(ThisReferenceExpression thisReferenceExpression, T data);
S VisitThrowExpression(ThrowExpression throwExpression, T data);
S VisitTupleExpression(TupleExpression tupleExpression, T data);
S VisitTypeOfExpression(TypeOfExpression typeOfExpression, T data);
S VisitTypeReferenceExpression(TypeReferenceExpression typeReferenceExpression, T data);
S VisitUnaryOperatorExpression(UnaryOperatorExpression unaryOperatorExpression, T data);
@ -409,6 +416,8 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -409,6 +416,8 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
S VisitSyntaxTree(SyntaxTree syntaxTree, T data);
S VisitSimpleType(SimpleType simpleType, T data);
S VisitMemberType(MemberType memberType, T data);
S VisitTupleType(TupleAstType tupleType, T data);
S VisitTupleTypeElement(TupleTypeElement tupleTypeElement, T data);
S VisitComposedType(ComposedType composedType, T data);
S VisitArraySpecifier(ArraySpecifier arraySpecifier, T data);
S VisitPrimitiveType(PrimitiveType primitiveType, T data);

139
ICSharpCode.Decompiler/CSharp/Syntax/TupleAstType.cs

@ -0,0 +1,139 @@ @@ -0,0 +1,139 @@
// 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.Immutable;
using System.Linq;
using ICSharpCode.Decompiler.CSharp.Resolver;
using ICSharpCode.Decompiler.CSharp.Syntax.PatternMatching;
using ICSharpCode.Decompiler.TypeSystem;
namespace ICSharpCode.Decompiler.CSharp.Syntax
{
public class TupleAstType : AstType
{
public static readonly Role<TupleTypeElement> ElementRole = new Role<TupleTypeElement>("Element", TupleTypeElement.Null);
public AstNodeCollection<TupleTypeElement> Elements {
get { return GetChildrenByRole(ElementRole); }
}
public override void AcceptVisitor(IAstVisitor visitor)
{
visitor.VisitTupleType(this);
}
public override T AcceptVisitor<T>(IAstVisitor<T> visitor)
{
return visitor.VisitTupleType(this);
}
public override S AcceptVisitor<T, S>(IAstVisitor<T, S> visitor, T data)
{
return visitor.VisitTupleType(this, data);
}
public override ITypeReference ToTypeReference(NameLookupMode lookupMode, InterningProvider interningProvider = null)
{
return new TupleTypeReference(
this.Elements.Select(e => e.Type.ToTypeReference(lookupMode, interningProvider)).ToImmutableArray(),
this.Elements.Select(e => e.Name).ToImmutableArray()
);
}
protected internal override bool DoMatch(AstNode other, Match match)
{
return other is TupleAstType o && Elements.DoMatch(o.Elements, match);
}
}
public class TupleTypeElement : AstNode
{
#region Null
public new static readonly TupleTypeElement Null = new TupleTypeElement();
sealed class NullTupleTypeElement : TupleTypeElement
{
public override bool IsNull {
get {
return true;
}
}
public override void AcceptVisitor(IAstVisitor visitor)
{
visitor.VisitNullNode(this);
}
public override T AcceptVisitor<T>(IAstVisitor<T> visitor)
{
return visitor.VisitNullNode(this);
}
public override S AcceptVisitor<T, S>(IAstVisitor<T, S> visitor, T data)
{
return visitor.VisitNullNode(this, data);
}
protected internal override bool DoMatch(AstNode other, PatternMatching.Match match)
{
return other == null || other.IsNull;
}
}
#endregion
public AstType Type {
get { return GetChildByRole(Roles.Type); }
set { SetChildByRole(Roles.Type, value); }
}
public string Name {
get { return GetChildByRole(Roles.Identifier).Name; }
set { SetChildByRole(Roles.Identifier, Identifier.Create(value)); }
}
public Identifier NameToken {
get { return GetChildByRole(Roles.Identifier); }
set { SetChildByRole(Roles.Identifier, value); }
}
public override NodeType NodeType => NodeType.Unknown;
public override void AcceptVisitor(IAstVisitor visitor)
{
visitor.VisitTupleTypeElement(this);
}
public override T AcceptVisitor<T>(IAstVisitor<T> visitor)
{
return visitor.VisitTupleTypeElement(this);
}
public override S AcceptVisitor<T, S>(IAstVisitor<T, S> visitor, T data)
{
return visitor.VisitTupleTypeElement(this, data);
}
protected internal override bool DoMatch(AstNode other, Match match)
{
return other is TupleTypeElement o
&& Type.DoMatch(o.Type, match)
&& MatchString(Name, o.Name);
}
}
}

16
ICSharpCode.Decompiler/CSharp/Syntax/TypeSystemAstBuilder.cs

@ -231,15 +231,23 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -231,15 +231,23 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
return ConvertType(typeWithElementType.ElementType);
}
}
ParameterizedType pt = type as ParameterizedType;
if (pt != null) {
if (type is ParameterizedType pt) {
if (pt.IsKnownType(KnownTypeCode.NullableOfT)) {
return ConvertType(pt.TypeArguments[0]).MakeNullableType();
}
return ConvertTypeHelper(pt.GenericType, pt.TypeArguments);
}
ITypeDefinition typeDef = type as ITypeDefinition;
if (typeDef != null) {
if (type is TupleType tuple) {
var astType = new TupleAstType();
foreach (var (etype, ename) in tuple.ElementTypes.Zip(tuple.ElementNames)) {
astType.Elements.Add(new TupleTypeElement {
Type = ConvertType(etype),
Name = ename
});
}
return astType;
}
if (type is ITypeDefinition typeDef) {
if (typeDef.TypeParameterCount > 0) {
// Unbound type
IType[] typeArguments = new IType[typeDef.TypeParameterCount];

21
ICSharpCode.Decompiler/CSharp/TranslatedExpression.cs

@ -18,6 +18,7 @@ @@ -18,6 +18,7 @@
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics;
using System.Linq;
using ICSharpCode.Decompiler.CSharp.Syntax;
@ -25,6 +26,7 @@ using ICSharpCode.Decompiler.CSharp.Transforms; @@ -25,6 +26,7 @@ using ICSharpCode.Decompiler.CSharp.Transforms;
using ICSharpCode.Decompiler.IL;
using ICSharpCode.Decompiler.Semantics;
using ICSharpCode.Decompiler.TypeSystem;
using ICSharpCode.Decompiler.Util;
namespace ICSharpCode.Decompiler.CSharp
{
@ -198,9 +200,24 @@ namespace ICSharpCode.Decompiler.CSharp @@ -198,9 +200,24 @@ namespace ICSharpCode.Decompiler.CSharp
}
return this;
}
if (targetType.Kind == TypeKind.Unknown || targetType.Kind == TypeKind.Void) {
if (targetType.Kind == TypeKind.Unknown || targetType.Kind == TypeKind.Void || targetType.Kind == TypeKind.None) {
return this; // don't attempt to insert cast to '?' or 'void' as these are not valid.
}
if (Expression is TupleExpression tupleExpr && targetType is TupleType targetTupleType
&& tupleExpr.Elements.Count == targetTupleType.ElementTypes.Length)
{
// Conversion of a tuple literal: convert element-wise
var newTupleExpr = new TupleExpression();
var newElementRRs = new List<ResolveResult>();
foreach (var (elementExpr, elementTargetType) in tupleExpr.Elements.Zip(targetTupleType.ElementTypes)) {
var newElementExpr = new TranslatedExpression(elementExpr.Detach())
.ConvertTo(elementTargetType, expressionBuilder, checkForOverflow, allowImplicitConversion);
newTupleExpr.Elements.Add(newElementExpr.Expression);
newElementRRs.Add(newElementExpr.ResolveResult);
}
return newTupleExpr.WithILInstruction(this.ILInstructions)
.WithRR(new TupleResolveResult(expressionBuilder.compilation, newElementRRs.ToImmutableArray()));
}
var compilation = expressionBuilder.compilation;
var conversions = Resolver.CSharpConversions.Get(compilation);
if (ResolveResult is ConversionResolveResult conv && Expression is CastExpression cast2 && conv.Conversion.IsBoxingConversion && conversions.IsBoxingConversion(conv.Input.Type, targetType)) {
@ -357,7 +374,7 @@ namespace ICSharpCode.Decompiler.CSharp @@ -357,7 +374,7 @@ namespace ICSharpCode.Decompiler.CSharp
.WithILInstruction(this.ILInstructions)
.WithRR(new ConstantResolveResult(targetType, null));
}
if (allowImplicitConversion && conversions.ImplicitConversion(type, targetType).IsValid) {
if (allowImplicitConversion && conversions.ImplicitConversion(ResolveResult, targetType).IsValid) {
return this;
}
var castExpr = new CastExpression(expressionBuilder.ConvertType(targetType), Expression);

2
ICSharpCode.Decompiler/CSharp/TypeSystem/AliasNamespaceReference.cs

@ -54,7 +54,7 @@ namespace ICSharpCode.Decompiler.CSharp.TypeSystem @@ -54,7 +54,7 @@ namespace ICSharpCode.Decompiler.CSharp.TypeSystem
public override IType ResolveType(CSharpResolver resolver)
{
// alias cannot refer to types
return SpecialType.UnknownType;
return SpecialType.NoType;
}
public override string ToString()

68
ICSharpCode.Decompiler/DecompilerSettings.cs

@ -59,7 +59,7 @@ namespace ICSharpCode.Decompiler @@ -59,7 +59,7 @@ namespace ICSharpCode.Decompiler
expressionTrees = false;
}
if (languageVersion < CSharp.LanguageVersion.CSharp4) {
// * dynamic (not supported yet)
dynamic = false;
// * named and optional arguments (not supported yet)
}
if (languageVersion < CSharp.LanguageVersion.CSharp5) {
@ -74,6 +74,8 @@ namespace ICSharpCode.Decompiler @@ -74,6 +74,8 @@ namespace ICSharpCode.Decompiler
}
if (languageVersion < CSharp.LanguageVersion.CSharp7) {
outVariables = false;
tupleTypes = false;
tupleConversions = false;
discards = false;
}
if (languageVersion < CSharp.LanguageVersion.CSharp7_2) {
@ -81,7 +83,7 @@ namespace ICSharpCode.Decompiler @@ -81,7 +83,7 @@ namespace ICSharpCode.Decompiler
}
if (languageVersion < CSharp.LanguageVersion.CSharp7_3) {
//introduceUnmanagedTypeConstraint = false;
//...
tupleComparisons = false;
}
}
@ -145,6 +147,21 @@ namespace ICSharpCode.Decompiler @@ -145,6 +147,21 @@ namespace ICSharpCode.Decompiler
}
}
bool dynamic = true;
/// <summary>
/// Decompile use of the 'dynamic' type.
/// </summary>
public bool Dynamic {
get { return dynamic; }
set {
if (dynamic != value) {
dynamic = value;
OnPropertyChanged();
}
}
}
bool asyncAwait = true;
/// <summary>
@ -571,6 +588,53 @@ namespace ICSharpCode.Decompiler @@ -571,6 +588,53 @@ namespace ICSharpCode.Decompiler
}
}
bool tupleTypes = true;
/// <summary>
/// Gets/Sets whether tuple type syntax <c>(int, string)</c>
/// should be used for <c>System.ValueTuple</c>.
/// </summary>
public bool TupleTypes {
get { return tupleTypes; }
set {
if (tupleTypes != value) {
tupleTypes = value;
OnPropertyChanged();
}
}
}
bool tupleConversions = true;
/// <summary>
/// Gets/Sets whether implicit conversions between tuples
/// should be used in the decompiled output.
/// </summary>
public bool TupleConversions {
get { return tupleConversions; }
set {
if (tupleConversions != value) {
tupleConversions = value;
OnPropertyChanged();
}
}
}
bool tupleComparisons = true;
/// <summary>
/// Gets/Sets whether tuple comparisons should be detected.
/// </summary>
public bool TupleComparisons {
get { return tupleComparisons; }
set {
if (tupleComparisons != value) {
tupleComparisons = value;
OnPropertyChanged();
}
}
}
#region Options to aid VB decompilation
bool assumeArrayLengthFitsIntoInt32 = true;

6
ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj

@ -107,6 +107,7 @@ @@ -107,6 +107,7 @@
<Compile Include="CSharp\Syntax\Expressions\StackAllocExpression.cs" />
<Compile Include="CSharp\Syntax\Expressions\ThisReferenceExpression.cs" />
<Compile Include="CSharp\Syntax\Expressions\ThrowExpression.cs" />
<Compile Include="CSharp\Syntax\Expressions\TupleExpression.cs" />
<Compile Include="CSharp\Syntax\Expressions\TypeOfExpression.cs" />
<Compile Include="CSharp\Syntax\Expressions\TypeReferenceExpression.cs" />
<Compile Include="CSharp\Syntax\Expressions\UnaryOperatorExpression.cs" />
@ -178,6 +179,7 @@ @@ -178,6 +179,7 @@
<Compile Include="CSharp\Syntax\SyntaxTree.cs" />
<Compile Include="CSharp\Syntax\TextLocation.cs" />
<Compile Include="CSharp\Syntax\TokenRole.cs" />
<Compile Include="CSharp\Syntax\TupleAstType.cs" />
<Compile Include="CSharp\Syntax\TypeMembers\Accessor.cs" />
<Compile Include="CSharp\Syntax\TypeMembers\ConstructorDeclaration.cs" />
<Compile Include="CSharp\Syntax\TypeMembers\DestructorDeclaration.cs" />
@ -303,6 +305,7 @@ @@ -303,6 +305,7 @@
<Compile Include="IL\Transforms\SwitchOnNullableTransform.cs" />
<Compile Include="IL\Transforms\SwitchOnStringTransform.cs" />
<Compile Include="IL\Transforms\TransformExpressionTrees.cs" />
<Compile Include="IL\Transforms\TupleTransform.cs" />
<Compile Include="IL\Transforms\UsingTransform.cs" />
<Compile Include="IL\ControlFlow\AsyncAwaitDecompiler.cs" />
<Compile Include="IL\ControlFlow\ControlFlowGraph.cs" />
@ -323,6 +326,9 @@ @@ -323,6 +326,9 @@
<Compile Include="IL\Transforms\StatementTransform.cs" />
<Compile Include="IL\Transforms\TransformCollectionAndObjectInitializers.cs" />
<Compile Include="Output\TextTokenWriter.cs" />
<Compile Include="Semantics\TupleResolveResult.cs" />
<Compile Include="TypeSystem\NormalizeTypeVisitor.cs" />
<Compile Include="TypeSystem\TupleType.cs" />
<Compile Include="Util\GraphVizGraph.cs" />
<Compile Include="Util\KeyComparer.cs" />
<Compile Include="Util\LongDict.cs" />

18
ICSharpCode.Decompiler/IL/Transforms/TransformArrayInitializers.cs

@ -290,24 +290,6 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -290,24 +290,6 @@ namespace ICSharpCode.Decompiler.IL.Transforms
return block;
}
static bool CompareTypes(IType a, IType b)
{
IType type1 = DummyTypeParameter.NormalizeAllTypeParameters(a);
IType type2 = DummyTypeParameter.NormalizeAllTypeParameters(b);
return type1.Equals(type2);
}
static bool CompareSignatures(IList<IParameter> parameters, IList<IParameter> otherParameters)
{
if (otherParameters.Count != parameters.Count)
return false;
for (int i = 0; i < otherParameters.Count; i++) {
if (!CompareTypes(otherParameters[i].Type, parameters[i].Type))
return false;
}
return true;
}
internal static bool MatchNewArr(ILInstruction instruction, out IType arrayType, out int[] length)
{
NewArr newArr = instruction as NewArr;

93
ICSharpCode.Decompiler/IL/Transforms/TupleTransform.cs

@ -0,0 +1,93 @@ @@ -0,0 +1,93 @@
// 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.Diagnostics;
using System.Text;
using ICSharpCode.Decompiler.TypeSystem;
namespace ICSharpCode.Decompiler.IL
{
class TupleTransform
{
/// <summary>
/// Matches an 'ldflda' instruction accessing a tuple element.
///
/// E.g. matches:
/// <c>ldflda Item1(ldflda Rest(target))</c>
/// </summary>
public static bool MatchTupleFieldAccess(LdFlda inst, out IType tupleType, out ILInstruction target, out int position)
{
tupleType = inst.Field.DeclaringType;
target = inst.Target;
if (!inst.Field.Name.StartsWith("Item", StringComparison.Ordinal)) {
position = 0;
return false;
}
if (!int.TryParse(inst.Field.Name.Substring(4), out position))
return false;
if (!TupleType.IsTupleCompatible(tupleType, out _))
return false;
while (target is LdFlda ldflda && ldflda.Field.Name == "Rest" && TupleType.IsTupleCompatible(ldflda.Field.DeclaringType, out _)) {
tupleType = ldflda.Field.DeclaringType;
target = ldflda.Target;
position += TupleType.RestPosition - 1;
}
return true;
}
/// <summary>
/// Matches 'newobj TupleType(...)'.
/// Takes care of flattening long tuples.
/// </summary>
public static bool MatchTupleConstruction(NewObj newobj, out ILInstruction[] arguments)
{
arguments = null;
if (newobj == null)
return false;
if (!TupleType.IsTupleCompatible(newobj.Method.DeclaringType, out int elementCount))
return false;
arguments = new ILInstruction[elementCount];
int outIndex = 0;
while (elementCount >= TupleType.RestPosition) {
if (newobj.Arguments.Count != TupleType.RestPosition)
return false;
for (int pos = 1; pos < TupleType.RestPosition; pos++) {
arguments[outIndex++] = newobj.Arguments[pos-1];
}
elementCount -= TupleType.RestPosition - 1;
Debug.Assert(outIndex + elementCount == arguments.Length);
newobj = newobj.Arguments.Last() as NewObj;
if (newobj == null)
return false;
if (!TupleType.IsTupleCompatible(newobj.Method.DeclaringType, out int restElementCount))
return false;
if (restElementCount != elementCount)
return false;
}
Debug.Assert(outIndex + elementCount == arguments.Length);
if (newobj.Arguments.Count != elementCount)
return false;
for (int i = 0; i < elementCount; i++) {
arguments[outIndex++] = newobj.Arguments[i];
}
return true;
}
}
}

58
ICSharpCode.Decompiler/Semantics/Conversion.cs

@ -17,6 +17,8 @@ @@ -17,6 +17,8 @@
// DEALINGS IN THE SOFTWARE.
using System;
using System.Collections.Immutable;
using System.Linq;
using ICSharpCode.Decompiler.TypeSystem;
namespace ICSharpCode.Decompiler.Semantics
@ -94,6 +96,11 @@ namespace ICSharpCode.Decompiler.Semantics @@ -94,6 +96,11 @@ namespace ICSharpCode.Decompiler.Semantics
throw new ArgumentNullException("chosenMethod");
return new MethodGroupConv(chosenMethod, isVirtualMethodLookup, delegateCapturesFirstArgument, isValid: false);
}
public static Conversion TupleConversion(ImmutableArray<Conversion> conversions)
{
return new TupleConv(conversions);
}
#endregion
#region Inner classes
@ -376,6 +383,43 @@ namespace ICSharpCode.Decompiler.Semantics @@ -376,6 +383,43 @@ namespace ICSharpCode.Decompiler.Semantics
return method.GetHashCode();
}
}
sealed class TupleConv : Conversion
{
public override bool IsImplicit { get; }
public override bool IsExplicit => !IsImplicit;
public override ImmutableArray<Conversion> ElementConversions { get; }
public override bool IsTupleConversion => true;
public TupleConv(ImmutableArray<Conversion> elementConversions)
{
this.ElementConversions = elementConversions;
this.IsImplicit = elementConversions.All(c => c.IsImplicit);
}
public override bool Equals(Conversion other)
{
return other is TupleConv o
&& ElementConversions.SequenceEqual(o.ElementConversions);
}
public override int GetHashCode()
{
unchecked {
int hash = 0;
foreach (var conv in ElementConversions) {
hash *= 31;
hash += conv.GetHashCode();
}
return hash;
}
}
public override string ToString()
{
return (IsImplicit ? "implicit " : "explicit ") + " tuple conversion";
}
}
#endregion
/// <summary>
@ -451,7 +495,7 @@ namespace ICSharpCode.Decompiler.Semantics @@ -451,7 +495,7 @@ namespace ICSharpCode.Decompiler.Semantics
public virtual bool IsNullableConversion {
get { return false; }
}
/// <summary>
/// Gets whether this conversion is user-defined (op_Implicit or op_Explicit).
/// </summary>
@ -533,7 +577,17 @@ namespace ICSharpCode.Decompiler.Semantics @@ -533,7 +577,17 @@ namespace ICSharpCode.Decompiler.Semantics
public virtual IMethod Method {
get { return null; }
}
/// <summary>
/// Gets whether this conversion is a tuple conversion.
/// </summary>
public virtual bool IsTupleConversion => false;
/// <summary>
/// For a tuple conversion, gets the individual tuple element conversions.
/// </summary>
public virtual ImmutableArray<Conversion> ElementConversions => default(ImmutableArray<Conversion>);
public override sealed bool Equals(object obj)
{
return Equals(obj as Conversion);

2
ICSharpCode.Decompiler/Semantics/NamespaceResolveResult.cs

@ -28,7 +28,7 @@ namespace ICSharpCode.Decompiler.Semantics @@ -28,7 +28,7 @@ namespace ICSharpCode.Decompiler.Semantics
{
readonly INamespace ns;
public NamespaceResolveResult(INamespace ns) : base(SpecialType.UnknownType)
public NamespaceResolveResult(INamespace ns) : base(SpecialType.NoType)
{
this.ns = ns;
}

57
ICSharpCode.Decompiler/Semantics/TupleResolveResult.cs

@ -0,0 +1,57 @@ @@ -0,0 +1,57 @@
// 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.Collections.Immutable;
using System.Linq;
using System.Text;
using ICSharpCode.Decompiler.TypeSystem;
using ICSharpCode.Decompiler.Util;
namespace ICSharpCode.Decompiler.Semantics
{
/// <summary>
/// Resolve result for a C# 7 tuple literal.
/// </summary>
public class TupleResolveResult : ResolveResult
{
public ImmutableArray<ResolveResult> Elements { get; }
public TupleResolveResult(ICompilation compilation,
ImmutableArray<ResolveResult> elements,
ImmutableArray<string> elementNames = default(ImmutableArray<string>))
: base(GetTupleType(compilation, elements, elementNames))
{
this.Elements = elements;
}
public override IEnumerable<ResolveResult> GetChildResults()
{
return Elements;
}
static IType GetTupleType(ICompilation compilation, ImmutableArray<ResolveResult> elements, ImmutableArray<string> elementNames)
{
if (elements.Any(e => e.Type.Kind == TypeKind.None || e.Type.Kind == TypeKind.Null))
return SpecialType.NoType;
else
return new TupleType(compilation, elements.Select(e => e.Type).ToImmutableArray(), elementNames);
}
}
}

182
ICSharpCode.Decompiler/TypeSystem/CecilLoader.cs

@ -18,6 +18,7 @@ @@ -18,6 +18,7 @@
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics;
using System.Linq;
using System.Runtime.CompilerServices;
@ -38,13 +39,6 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -38,13 +39,6 @@ namespace ICSharpCode.Decompiler.TypeSystem
/// if you want to load multiple project contents in parallel.</remarks>
public sealed class CecilLoader : AssemblyLoader
{
/// <summary>
/// Version number of the cecil loader.
/// Should be incremented when fixing bugs in the cecil loader so that project contents cached on disk
/// (which might be incorrect due to the bug) are re-created.
/// </summary>
const int cecilLoaderVersion = 1;
#region Options
// Most options are defined in the AssemblyLoader base class
@ -64,6 +58,16 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -64,6 +58,16 @@ namespace ICSharpCode.Decompiler.TypeSystem
/// </remarks>
public bool LazyLoad { get; set; }
/// <summary>
/// Gets/Sets whether to use the <c>dynamic</c> type.
/// </summary>
public bool UseDynamicType { get; set; } = true;
/// <summary>
/// Gets/Sets whether to use the tuple types.
/// </summary>
public bool UseTupleTypes { get; set; } = true;
/// <summary>
/// This delegate gets executed whenever an entity was loaded.
/// </summary>
@ -75,20 +79,11 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -75,20 +79,11 @@ namespace ICSharpCode.Decompiler.TypeSystem
/// </remarks>
public Action<IUnresolvedEntity, MemberReference> OnEntityLoaded { get; set; }
bool shortenInterfaceImplNames = true;
/// <summary>
/// Specifies whether method names of explicit interface-implementations should be shortened.
/// </summary>
/// <remarks>This is important when working with parser-initialized type-systems in order to be consistent.</remarks>
public bool ShortenInterfaceImplNames {
get {
return shortenInterfaceImplNames;
}
set {
shortenInterfaceImplNames = value;
}
}
public bool ShortenInterfaceImplNames { get; set; } = true;
#endregion
ModuleDefinition currentModule;
@ -108,6 +103,8 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -108,6 +103,8 @@ namespace ICSharpCode.Decompiler.TypeSystem
{
// use a shared typeSystemTranslationTable
this.IncludeInternalMembers = loader.IncludeInternalMembers;
this.UseDynamicType = loader.UseDynamicType;
this.UseTupleTypes = loader.UseTupleTypes;
this.LazyLoad = loader.LazyLoad;
this.OnEntityLoaded = loader.OnEntityLoaded;
this.ShortenInterfaceImplNames = loader.ShortenInterfaceImplNames;
@ -295,11 +292,12 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -295,11 +292,12 @@ namespace ICSharpCode.Decompiler.TypeSystem
/// IsValueType is set correctly.</param>
public ITypeReference ReadTypeReference(TypeReference type, ICustomAttributeProvider typeAttributes = null, bool isFromSignature = false)
{
int typeIndex = 0;
return CreateType(type, typeAttributes, ref typeIndex, isFromSignature);
int dynamicTypeIndex = 0;
int tupleTypeIndex = 0;
return CreateType(type, typeAttributes, ref dynamicTypeIndex, ref tupleTypeIndex, isFromSignature);
}
ITypeReference CreateType(TypeReference type, ICustomAttributeProvider typeAttributes, ref int typeIndex, bool isFromSignature)
ITypeReference CreateType(TypeReference type, ICustomAttributeProvider typeAttributes, ref int dynamicTypeIndex, ref int tupleTypeIndex, bool isFromSignature)
{
if (type == null) {
return SpecialType.UnknownType;
@ -307,90 +305,123 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -307,90 +305,123 @@ namespace ICSharpCode.Decompiler.TypeSystem
switch (type.MetadataType) {
case MetadataType.Void:
return KnownTypeReference.Get(KnownTypeCode.Void);
return KnownTypeReference.Void;
case MetadataType.Boolean:
return KnownTypeReference.Get(KnownTypeCode.Boolean);
return KnownTypeReference.Boolean;
case MetadataType.Char:
return KnownTypeReference.Get(KnownTypeCode.Char);
return KnownTypeReference.Char;
case MetadataType.SByte:
return KnownTypeReference.Get(KnownTypeCode.SByte);
return KnownTypeReference.SByte;
case MetadataType.Byte:
return KnownTypeReference.Get(KnownTypeCode.Byte);
return KnownTypeReference.Byte;
case MetadataType.Int16:
return KnownTypeReference.Get(KnownTypeCode.Int16);
return KnownTypeReference.Int16;
case MetadataType.UInt16:
return KnownTypeReference.Get(KnownTypeCode.UInt16);
return KnownTypeReference.UInt16;
case MetadataType.Int32:
return KnownTypeReference.Get(KnownTypeCode.Int32);
return KnownTypeReference.Int32;
case MetadataType.UInt32:
return KnownTypeReference.Get(KnownTypeCode.UInt32);
return KnownTypeReference.UInt32;
case MetadataType.Int64:
return KnownTypeReference.Get(KnownTypeCode.Int64);
return KnownTypeReference.Int64;
case MetadataType.UInt64:
return KnownTypeReference.Get(KnownTypeCode.UInt64);
return KnownTypeReference.UInt64;
case MetadataType.Single:
return KnownTypeReference.Get(KnownTypeCode.Single);
return KnownTypeReference.Single;
case MetadataType.Double:
return KnownTypeReference.Get(KnownTypeCode.Double);
return KnownTypeReference.Double;
case MetadataType.String:
return KnownTypeReference.Get(KnownTypeCode.String);
return KnownTypeReference.String;
case MetadataType.Pointer:
typeIndex++;
dynamicTypeIndex++;
return interningProvider.Intern(
new PointerTypeReference(
CreateType(
(type as Mono.Cecil.PointerType).ElementType,
typeAttributes, ref typeIndex, isFromSignature: true)));
typeAttributes, ref dynamicTypeIndex, ref tupleTypeIndex, isFromSignature: true)));
case MetadataType.ByReference:
typeIndex++;
dynamicTypeIndex++;
return interningProvider.Intern(
new ByReferenceTypeReference(
CreateType(
(type as Mono.Cecil.ByReferenceType).ElementType,
typeAttributes, ref typeIndex, isFromSignature: true)));
typeAttributes, ref dynamicTypeIndex, ref tupleTypeIndex, isFromSignature: true)));
case MetadataType.Var:
return TypeParameterReference.Create(SymbolKind.TypeDefinition, ((GenericParameter)type).Position);
case MetadataType.MVar:
return TypeParameterReference.Create(SymbolKind.Method, ((GenericParameter)type).Position);
case MetadataType.Array:
typeIndex++;
dynamicTypeIndex++;
return interningProvider.Intern(
new ArrayTypeReference(
CreateType(
(type as Mono.Cecil.ArrayType).ElementType,
typeAttributes, ref typeIndex, isFromSignature: true),
typeAttributes, ref dynamicTypeIndex, ref tupleTypeIndex, isFromSignature: true),
(type as Mono.Cecil.ArrayType).Rank));
case MetadataType.GenericInstance:
GenericInstanceType gType = (GenericInstanceType)type;
ITypeReference baseType = CreateType(gType.ElementType, typeAttributes, ref typeIndex, isFromSignature: true);
ITypeReference baseType = CreateType(gType.ElementType, typeAttributes, ref dynamicTypeIndex, ref tupleTypeIndex, isFromSignature: true);
if (UseTupleTypes && IsValueTuple(gType, out int tupleCardinality)) {
if (tupleCardinality > 1) {
var assemblyRef = GetAssemblyReference(gType.ElementType.Scope);
var elementNames = GetTupleElementNames(typeAttributes, tupleTypeIndex, tupleCardinality);
tupleTypeIndex += tupleCardinality;
ITypeReference[] elementTypeRefs = new ITypeReference[tupleCardinality];
int outPos = 0;
do {
int normalArgCount = Math.Min(gType.GenericArguments.Count, TupleType.RestPosition - 1);
for (int i = 0; i < normalArgCount; i++) {
dynamicTypeIndex++;
elementTypeRefs[outPos++] = CreateType(gType.GenericArguments[i], typeAttributes, ref dynamicTypeIndex, ref tupleTypeIndex, isFromSignature: true);
}
if (gType.GenericArguments.Count == TupleType.RestPosition) {
gType = (GenericInstanceType)gType.GenericArguments.Last();
dynamicTypeIndex++;
if (IsValueTuple(gType, out int nestedCardinality)) {
tupleTypeIndex += nestedCardinality;
} else {
Debug.Fail("TRest should be another value tuple");
}
} else {
gType = null;
}
} while (gType != null);
return new TupleTypeReference(
elementTypeRefs.ToImmutableArray(), elementNames,
assemblyRef);
} else {
// C# doesn't have syntax for tuples of cardinality <= 1
tupleTypeIndex += tupleCardinality;
}
}
ITypeReference[] para = new ITypeReference[gType.GenericArguments.Count];
for (int i = 0; i < para.Length; ++i) {
typeIndex++;
para[i] = CreateType(gType.GenericArguments[i], typeAttributes, ref typeIndex, isFromSignature: true);
dynamicTypeIndex++;
para[i] = CreateType(gType.GenericArguments[i], typeAttributes, ref dynamicTypeIndex, ref tupleTypeIndex, isFromSignature: true);
}
return interningProvider.Intern(new ParameterizedTypeReference(baseType, para));
case MetadataType.IntPtr:
return KnownTypeReference.Get(KnownTypeCode.IntPtr);
return KnownTypeReference.IntPtr;
case MetadataType.UIntPtr:
return KnownTypeReference.Get(KnownTypeCode.UIntPtr);
return KnownTypeReference.UIntPtr;
case MetadataType.FunctionPointer:
// C# and the NR typesystem don't support function pointer types.
// Function pointer types map to StackType.I, so we'll use IntPtr instead.
return KnownTypeReference.Get(KnownTypeCode.IntPtr);
return KnownTypeReference.IntPtr;
case MetadataType.Object:
if (HasDynamicAttribute(typeAttributes, typeIndex)) {
if (UseDynamicType && HasDynamicAttribute(typeAttributes, dynamicTypeIndex)) {
return SpecialType.Dynamic;
} else {
return KnownTypeReference.Get(KnownTypeCode.Object);
return KnownTypeReference.Object;
}
case MetadataType.RequiredModifier:
case MetadataType.OptionalModifier:
// we don't store modopts/modreqs in the NR type system
return CreateType(((TypeSpecification)type).ElementType, typeAttributes, ref typeIndex, isFromSignature: true);
return CreateType(((TypeSpecification)type).ElementType, typeAttributes, ref dynamicTypeIndex, ref tupleTypeIndex, isFromSignature: true);
case MetadataType.Sentinel:
return SpecialType.ArgList;
case MetadataType.Pinned:
return CreateType(((PinnedType)type).ElementType, typeAttributes, ref typeIndex, isFromSignature: true);
return CreateType(((PinnedType)type).ElementType, typeAttributes, ref dynamicTypeIndex, ref tupleTypeIndex, isFromSignature: true);
}
// valuetype/class/typedbyreference
if (type is TypeDefinition) {
@ -400,7 +431,7 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -400,7 +431,7 @@ namespace ICSharpCode.Decompiler.TypeSystem
// or if it's a TypeSpecification.
bool? isReferenceType = isFromSignature ? (bool?)!type.IsValueType : null;
if (type.IsNested) {
ITypeReference typeRef = CreateType(type.DeclaringType, typeAttributes, ref typeIndex, isFromSignature);
ITypeReference typeRef = CreateType(type.DeclaringType, typeAttributes, ref dynamicTypeIndex, ref tupleTypeIndex, isFromSignature);
int partTypeParameterCount;
string namepart = ReflectionHelper.SplitTypeParameterCountFromReflectionName(type.Name, out partTypeParameterCount);
namepart = interningProvider.Intern(namepart);
@ -411,7 +442,7 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -411,7 +442,7 @@ namespace ICSharpCode.Decompiler.TypeSystem
if (name == null)
throw new InvalidOperationException("type.Name returned null. Type: " + type.ToString());
if (name == "Object" && ns == "System" && HasDynamicAttribute(typeAttributes, typeIndex)) {
if (UseDynamicType && name == "Object" && ns == "System" && HasDynamicAttribute(typeAttributes, dynamicTypeIndex)) {
return SpecialType.Dynamic;
}
int typeParameterCount;
@ -422,7 +453,46 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -422,7 +453,46 @@ namespace ICSharpCode.Decompiler.TypeSystem
isReferenceType));
}
}
static internal bool IsValueTuple(GenericInstanceType gType, out int tupleCardinality)
{
tupleCardinality = 0;
if (gType == null || gType.DeclaringType != null || !gType.Name.StartsWith("ValueTuple`", StringComparison.Ordinal) || gType.Namespace != "System")
return false;
if (gType.GenericArguments.Count == TupleType.RestPosition) {
if (IsValueTuple(gType.GenericArguments.Last() as GenericInstanceType, out tupleCardinality)) {
tupleCardinality += TupleType.RestPosition - 1;
return true;
}
}
tupleCardinality = gType.GenericArguments.Count;
return tupleCardinality > 0 && tupleCardinality < TupleType.RestPosition;
}
static ImmutableArray<string> GetTupleElementNames(ICustomAttributeProvider attributeProvider, int tupleTypeIndex, int tupleCardinality)
{
if (attributeProvider == null || !attributeProvider.HasCustomAttributes)
return default(ImmutableArray<string>);
foreach (CustomAttribute a in attributeProvider.CustomAttributes) {
TypeReference type = a.AttributeType;
if (type.Name == "TupleElementNamesAttribute" && type.Namespace == "System.Runtime.CompilerServices") {
if (a.ConstructorArguments.Count == 1) {
CustomAttributeArgument[] values = a.ConstructorArguments[0].Value as CustomAttributeArgument[];
if (values != null) {
string[] extractedValues = new string[tupleCardinality];
for (int i = 0; i < tupleCardinality; i++) {
if (tupleTypeIndex + i < values.Length) {
extractedValues[i] = values[tupleTypeIndex + i].Value as string;
}
}
return extractedValues.ToImmutableArray();
}
}
}
}
return default(ImmutableArray<string>);
}
IAssemblyReference GetAssemblyReference(IMetadataScope scope)
{
if (scope == null || scope == currentModule)
@ -827,7 +897,11 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -827,7 +897,11 @@ namespace ICSharpCode.Decompiler.TypeSystem
foreach (var cecilAttribute in attributes) {
TypeReference type = cecilAttribute.AttributeType;
if (type.Namespace == "System.Runtime.CompilerServices") {
if (type.Name == "DynamicAttribute" || type.Name == "ExtensionAttribute" || type.Name == "DecimalConstantAttribute")
if (type.Name == "ExtensionAttribute" || type.Name == "DecimalConstantAttribute")
continue;
if (UseDynamicType && type.Name == "DynamicAttribute")
continue;
if (UseTupleTypes && type.Name == "TupleElementNamesAttribute")
continue;
} else if (type.Name == "ParamArrayAttribute" && type.Namespace == "System") {
continue;

36
ICSharpCode.Decompiler/TypeSystem/DecompilerTypeSystem.cs

@ -23,7 +23,7 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -23,7 +23,7 @@ namespace ICSharpCode.Decompiler.TypeSystem
/// CecilLoader used for converting cecil type references to ITypeReference.
/// May only be accessed within lock(typeReferenceCecilLoader).
/// </summary>
readonly CecilLoader typeReferenceCecilLoader = new CecilLoader();
readonly CecilLoader typeReferenceCecilLoader;
/// <summary>
/// Dictionary for NRefactory->Cecil lookup.
@ -35,13 +35,30 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -35,13 +35,30 @@ namespace ICSharpCode.Decompiler.TypeSystem
Dictionary<PropertyReference, IProperty> propertyLookupCache = new Dictionary<PropertyReference, IProperty>();
Dictionary<MethodReference, IMethod> methodLookupCache = new Dictionary<MethodReference, IMethod>();
Dictionary<EventReference, IEvent> eventLookupCache = new Dictionary<EventReference, IEvent>();
public DecompilerTypeSystem(ModuleDefinition moduleDefinition)
public DecompilerTypeSystem(ModuleDefinition moduleDefinition) : this(moduleDefinition, new DecompilerSettings())
{
}
public DecompilerTypeSystem(ModuleDefinition moduleDefinition, DecompilerSettings settings)
{
if (moduleDefinition == null)
throw new ArgumentNullException(nameof(moduleDefinition));
if (settings == null)
throw new ArgumentNullException(nameof(settings));
this.moduleDefinition = moduleDefinition;
CecilLoader cecilLoader = new CecilLoader { IncludeInternalMembers = true, LazyLoad = true, OnEntityLoaded = StoreMemberReference, ShortenInterfaceImplNames = false };
typeReferenceCecilLoader = new CecilLoader {
UseDynamicType = settings.Dynamic,
UseTupleTypes = settings.TupleTypes,
};
CecilLoader cecilLoader = new CecilLoader {
IncludeInternalMembers = true,
LazyLoad = true,
OnEntityLoaded = StoreMemberReference,
ShortenInterfaceImplNames = false,
UseDynamicType = settings.Dynamic,
UseTupleTypes = settings.TupleTypes,
};
typeReferenceCecilLoader.SetCurrentModule(moduleDefinition);
IUnresolvedAssembly mainAssembly = cecilLoader.LoadModule(moduleDefinition);
// Load referenced assemblies and type-forwarder references.
@ -294,11 +311,16 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -294,11 +311,16 @@ namespace ICSharpCode.Decompiler.TypeSystem
}
return CreateFakeMethod(methodReference);
}
static readonly NormalizeTypeVisitor normalizeTypeVisitor = new NormalizeTypeVisitor {
ReplaceClassTypeParametersWithDummy = true,
ReplaceMethodTypeParametersWithDummy = true,
};
static bool CompareTypes(IType a, IType b)
{
IType type1 = DummyTypeParameter.NormalizeAllTypeParameters(a);
IType type2 = DummyTypeParameter.NormalizeAllTypeParameters(b);
IType type1 = a.AcceptVisitor(normalizeTypeVisitor);
IType type2 = b.AcceptVisitor(normalizeTypeVisitor);
return type1.Equals(type2);
}

5
ICSharpCode.Decompiler/TypeSystem/IMember.cs

@ -172,5 +172,10 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -172,5 +172,10 @@ namespace ICSharpCode.Decompiler.TypeSystem
/// If this member is already specialized, the new substitution is composed with the existing substition.
/// </summary>
IMember Specialize(TypeParameterSubstitution substitution);
/// <summary>
/// Gets whether the members are considered equal when applying the specified type normalization.
/// </summary>
bool Equals(IMember obj, TypeVisitor typeNormalization);
}
}

5
ICSharpCode.Decompiler/TypeSystem/Implementation/AbstractResolvedMember.cs

@ -111,6 +111,11 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation @@ -111,6 +111,11 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation
get { return TypeParameterSubstitution.Identity; }
}
public virtual bool Equals(IMember obj, TypeVisitor typeNormalization)
{
return Equals(obj);
}
public abstract IMember Specialize(TypeParameterSubstitution substitution);
internal IMethod GetAccessor(ref IMethod accessorField, IUnresolvedMethod unresolvedAccessor)

8
ICSharpCode.Decompiler/TypeSystem/Implementation/DefaultMemberReference.cs

@ -57,7 +57,9 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation @@ -57,7 +57,9 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation
public ITypeReference DeclaringTypeReference {
get { return typeReference; }
}
static readonly NormalizeTypeVisitor normalizeTypeVisitor = new NormalizeTypeVisitor();
public IMember Resolve(ITypeResolveContext context)
{
IType type = typeReference.Resolve(context);
@ -85,8 +87,8 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation @@ -85,8 +87,8 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation
} else if (parameterTypes.Count == parameterizedMember.Parameters.Count) {
bool signatureMatches = true;
for (int i = 0; i < parameterTypes.Count; i++) {
IType type1 = DummyTypeParameter.NormalizeAllTypeParameters(resolvedParameterTypes[i]);
IType type2 = DummyTypeParameter.NormalizeAllTypeParameters(parameterizedMember.Parameters[i].Type);
IType type1 = resolvedParameterTypes[i].AcceptVisitor(normalizeTypeVisitor);
IType type2 = parameterizedMember.Parameters[i].Type.AcceptVisitor(normalizeTypeVisitor);
if (!type1.Equals(type2)) {
signatureMatches = false;
break;

56
ICSharpCode.Decompiler/TypeSystem/Implementation/DummyTypeParameter.cs

@ -93,62 +93,6 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation @@ -93,62 +93,6 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation
}
return tps[length];
}
sealed class NormalizeMethodTypeParametersVisitor : TypeVisitor
{
public override IType VisitTypeParameter(ITypeParameter type)
{
if (type.OwnerType == SymbolKind.Method) {
return DummyTypeParameter.GetMethodTypeParameter(type.Index);
} else {
return base.VisitTypeParameter(type);
}
}
}
sealed class NormalizeClassTypeParametersVisitor : TypeVisitor
{
public override IType VisitTypeParameter(ITypeParameter type)
{
if (type.OwnerType == SymbolKind.TypeDefinition) {
return DummyTypeParameter.GetClassTypeParameter(type.Index);
} else {
return base.VisitTypeParameter(type);
}
}
}
static readonly NormalizeMethodTypeParametersVisitor normalizeMethodTypeParameters = new NormalizeMethodTypeParametersVisitor();
static readonly NormalizeClassTypeParametersVisitor normalizeClassTypeParameters = new NormalizeClassTypeParametersVisitor();
/// <summary>
/// Replaces all occurrences of method type parameters in the given type
/// by normalized type parameters. This allows comparing parameter types from different
/// generic methods.
/// </summary>
public static IType NormalizeMethodTypeParameters(IType type)
{
return type.AcceptVisitor(normalizeMethodTypeParameters);
}
/// <summary>
/// Replaces all occurrences of class type parameters in the given type
/// by normalized type parameters. This allows comparing parameter types from different
/// generic methods.
/// </summary>
public static IType NormalizeClassTypeParameters(IType type)
{
return type.AcceptVisitor(normalizeClassTypeParameters);
}
/// <summary>
/// Replaces all occurrences of class and method type parameters in the given type
/// by normalized type parameters. This allows comparing parameter types from different
/// generic methods.
/// </summary>
public static IType NormalizeAllTypeParameters(IType type)
{
return type.AcceptVisitor(normalizeClassTypeParameters).AcceptVisitor(normalizeMethodTypeParameters);
}
readonly SymbolKind ownerType;
readonly int index;

15
ICSharpCode.Decompiler/TypeSystem/Implementation/SpecializedMember.cs

@ -258,6 +258,15 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation @@ -258,6 +258,15 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation
return baseMember.Specialize(TypeParameterSubstitution.Compose(newSubstitution, this.substitution));
}
public virtual bool Equals(IMember obj, TypeVisitor typeNormalization)
{
SpecializedMember other = obj as SpecializedMember;
if (other == null)
return false;
return this.baseMember.Equals(other.baseMember, typeNormalization)
&& this.substitution.Equals(other.substitution, typeNormalization);
}
public override bool Equals(object obj)
{
SpecializedMember other = obj as SpecializedMember;
@ -303,7 +312,7 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation @@ -303,7 +312,7 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation
if (result != null)
return result;
else
return LazyInit.GetOrSet(ref this.parameters, CreateParameters(this.Substitution));
return LazyInit.GetOrSet(ref this.parameters, CreateParameters(t => t.AcceptVisitor(this.Substitution)));
}
protected set {
// This setter is used for LiftedUserDefinedOperator, a special case of specialized member
@ -315,7 +324,7 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation @@ -315,7 +324,7 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation
}
}
protected IParameter[] CreateParameters(TypeVisitor substitution)
protected IParameter[] CreateParameters(Func<IType, IType> substitution)
{
var paramDefs = ((IParameterizedMember)this.baseMember).Parameters;
if (paramDefs.Count == 0) {
@ -324,7 +333,7 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation @@ -324,7 +333,7 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation
var parameters = new IParameter[paramDefs.Count];
for (int i = 0; i < parameters.Length; i++) {
var p = paramDefs[i];
IType newType = p.Type.AcceptVisitor(substitution);
IType newType = substitution(p.Type);
parameters[i] = new DefaultParameter(
newType, p.Name, this,
p.Attributes, p.IsRef, p.IsOut,

11
ICSharpCode.Decompiler/TypeSystem/Implementation/SpecializedMethod.cs

@ -147,7 +147,16 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation @@ -147,7 +147,16 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation
accessorOwner = value;
}
}
public override bool Equals(IMember obj, TypeVisitor typeNormalization)
{
SpecializedMethod other = obj as SpecializedMethod;
if (other == null)
return false;
return this.baseMember.Equals(other.baseMember, typeNormalization)
&& this.substitutionWithoutSpecializedTypeParameters.Equals(other.substitutionWithoutSpecializedTypeParameters, typeNormalization);
}
public override bool Equals(object obj)
{
SpecializedMethod other = obj as SpecializedMethod;

56
ICSharpCode.Decompiler/TypeSystem/NormalizeTypeVisitor.cs

@ -0,0 +1,56 @@ @@ -0,0 +1,56 @@
using System;
using System.Collections.Generic;
using System.Text;
using ICSharpCode.Decompiler.TypeSystem.Implementation;
namespace ICSharpCode.Decompiler.TypeSystem
{
sealed class NormalizeTypeVisitor : TypeVisitor
{
/// <summary>
/// NormalizeTypeVisitor that does not normalize type parameters,
/// but performs type erasure (object->dynamic; tuple->underlying type).
/// </summary>
internal static readonly NormalizeTypeVisitor TypeErasure = new NormalizeTypeVisitor {
ReplaceClassTypeParametersWithDummy = false,
ReplaceMethodTypeParametersWithDummy = false,
DynamicAndObject = true,
TupleToUnderlyingType = true
};
public bool ReplaceClassTypeParametersWithDummy = true;
public bool ReplaceMethodTypeParametersWithDummy = true;
public bool DynamicAndObject = true;
public bool TupleToUnderlyingType = true;
public override IType VisitTypeParameter(ITypeParameter type)
{
if (type.OwnerType == SymbolKind.Method && ReplaceMethodTypeParametersWithDummy) {
return DummyTypeParameter.GetMethodTypeParameter(type.Index);
} else if (type.OwnerType == SymbolKind.TypeDefinition && ReplaceClassTypeParametersWithDummy) {
return DummyTypeParameter.GetClassTypeParameter(type.Index);
} else {
return base.VisitTypeParameter(type);
}
}
public override IType VisitTypeDefinition(ITypeDefinition type)
{
if (DynamicAndObject && type.KnownTypeCode == KnownTypeCode.Object) {
// Instead of normalizing dynamic->object,
// we do this the opposite direction, so that we don't need a compilation to find the object type.
return SpecialType.Dynamic;
}
return base.VisitTypeDefinition(type);
}
public override IType VisitTupleType(TupleType type)
{
if (TupleToUnderlyingType) {
return type.UnderlyingType.AcceptVisitor(this);
} else {
return base.VisitTupleType(type);
}
}
}
}

28
ICSharpCode.Decompiler/TypeSystem/ParameterListComparer.cs

@ -34,27 +34,13 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -34,27 +34,13 @@ namespace ICSharpCode.Decompiler.TypeSystem
public sealed class ParameterListComparer : IEqualityComparer<IReadOnlyList<IParameter>>
{
public static readonly ParameterListComparer Instance = new ParameterListComparer();
sealed class NormalizeTypeVisitor : TypeVisitor
{
public override IType VisitTypeParameter(ITypeParameter type)
{
if (type.OwnerType == SymbolKind.Method) {
return DummyTypeParameter.GetMethodTypeParameter(type.Index);
} else {
return base.VisitTypeParameter(type);
}
}
public override IType VisitTypeDefinition(ITypeDefinition type)
{
if (type.KnownTypeCode == KnownTypeCode.Object)
return SpecialType.Dynamic;
return base.VisitTypeDefinition(type);
}
}
static readonly NormalizeTypeVisitor normalizationVisitor = new NormalizeTypeVisitor();
static readonly NormalizeTypeVisitor normalizationVisitor = new NormalizeTypeVisitor {
ReplaceClassTypeParametersWithDummy = false,
ReplaceMethodTypeParametersWithDummy = true,
DynamicAndObject = true,
TupleToUnderlyingType = true,
};
public bool Equals(IReadOnlyList<IParameter> x, IReadOnlyList<IParameter> y)
{

2
ICSharpCode.Decompiler/TypeSystem/ParameterizedType.cs

@ -271,6 +271,8 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -271,6 +271,8 @@ namespace ICSharpCode.Decompiler.TypeSystem
public bool Equals(IType other)
{
if (this == other)
return true;
ParameterizedType c = other as ParameterizedType;
if (c == null || !genericType.Equals(c.genericType) || typeArguments.Length != c.typeArguments.Length)
return false;

7
ICSharpCode.Decompiler/TypeSystem/SpecialType.cs

@ -36,7 +36,12 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -36,7 +36,12 @@ namespace ICSharpCode.Decompiler.TypeSystem
/// The null type is used as type of the null literal. It is a reference type without any members; and it is a subtype of all reference types.
/// </summary>
public readonly static SpecialType NullType = new SpecialType(TypeKind.Null, "null", isReferenceType: true);
/// <summary>
/// Used for expressions without type, e.g. method groups or lambdas.
/// </summary>
public readonly static SpecialType NoType = new SpecialType(TypeKind.None, "?", isReferenceType: null);
/// <summary>
/// Type representing the C# 'dynamic' type.
/// </summary>

369
ICSharpCode.Decompiler/TypeSystem/TupleType.cs

@ -1,17 +1,380 @@ @@ -1,17 +1,380 @@
using System;
// 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.Collections.Immutable;
using System.Diagnostics;
using System.Linq;
using System.Text;
using ICSharpCode.Decompiler.TypeSystem.Implementation;
using ICSharpCode.Decompiler.Util;
using Mono.Cecil;
namespace ICSharpCode.Decompiler.TypeSystem
{
public sealed class TupleType
public sealed class TupleType : AbstractType, ICompilationProvider
{
public const int RestPosition = 8;
const int RestIndex = RestPosition - 1;
public ICompilation Compilation { get; }
/// <summary>
/// Gets the underlying <c>System.ValueType</c> type.
/// </summary>
public ParameterizedType UnderlyingType { get; }
/// <summary>
/// Gets the tuple elements.
/// </summary>
public ImmutableArray<IType> ElementTypes { get; }
/// <summary>
/// Gets the names of the tuple elements.
/// </summary>
public ImmutableArray<string> ElementNames { get; }
public ImmutableArray<IField> TupleElements { get; }
public TupleType(ICompilation compilation, ImmutableArray<IType> elementTypes,
ImmutableArray<string> elementNames = default(ImmutableArray<string>),
IAssembly valueTupleAssembly = null)
{
this.Compilation = compilation;
this.UnderlyingType = CreateUnderlyingType(compilation, elementTypes, valueTupleAssembly);
this.ElementTypes = elementTypes;
if (elementNames.IsDefault) {
this.ElementNames = Enumerable.Repeat<string>(null, elementTypes.Length).ToImmutableArray();
} else {
Debug.Assert(elementNames.Length == elementTypes.Length);
this.ElementNames = elementNames;
}
}
static ParameterizedType CreateUnderlyingType(ICompilation compilation, ImmutableArray<IType> elementTypes, IAssembly valueTupleAssembly)
{
int remainder = (elementTypes.Length - 1) % (RestPosition - 1) + 1;
Debug.Assert(remainder >= 1 && remainder < RestPosition);
int pos = elementTypes.Length - remainder;
var type = new ParameterizedType(
FindValueTupleType(compilation, valueTupleAssembly, remainder),
elementTypes.Slice(pos));
while (pos > 0) {
pos -= (RestPosition - 1);
type = new ParameterizedType(
FindValueTupleType(compilation, valueTupleAssembly, RestPosition),
elementTypes.Slice(pos, RestPosition - 1).Concat(new[] { type }));
}
Debug.Assert(pos == 0);
return type;
}
private static IType FindValueTupleType(ICompilation compilation, IAssembly valueTupleAssembly, int tpc)
{
FullTypeName typeName = new TopLevelTypeName("System", "ValueTuple", tpc);
if (valueTupleAssembly != null) {
var typeDef = valueTupleAssembly.GetTypeDefinition(typeName);
if (typeDef != null)
return typeDef;
}
return compilation.FindType(typeName);
}
/// <summary>
/// Gets whether the specified type is a valid underlying type for a tuple.
/// Also returns true for tuple types themselves.
/// </summary>
public static bool IsTupleCompatible(IType type, out int tupleCardinality)
{
switch (type.Kind) {
case TypeKind.Tuple:
tupleCardinality = ((TupleType)type).ElementTypes.Length;
return true;
case TypeKind.Class:
case TypeKind.Struct:
if (type.Namespace == "System" && type.Name == "ValueTuple") {
int tpc = type.TypeParameterCount;
if (tpc > 0 && tpc < RestPosition) {
tupleCardinality = tpc;
return true;
} else if (tpc == RestPosition && type is ParameterizedType pt) {
if (IsTupleCompatible(pt.TypeArguments[RestIndex], out tupleCardinality)) {
tupleCardinality += RestPosition - 1;
return true;
}
}
}
break;
}
tupleCardinality = 0;
return false;
}
/// <summary>
/// Construct a tuple type (without element names) from the given underlying type.
/// Returns null if the input is not a valid underlying type.
/// </summary>
public static TupleType FromUnderlyingType(ICompilation compilation, IType type)
{
var elementTypes = GetTupleElementTypes(type);
if (elementTypes.Length > 0) {
return new TupleType(
compilation,
elementTypes,
valueTupleAssembly: type.GetDefinition()?.ParentAssembly
);
} else {
return null;
}
}
/// <summary>
/// Gets the tuple element types from a tuple type or tuple underlying type.
/// </summary>
public static ImmutableArray<IType> GetTupleElementTypes(IType tupleType)
{
List<IType> output = null;
if (Collect(tupleType)) {
return output.ToImmutableArray();
} else {
return default(ImmutableArray<IType>);
}
bool Collect(IType type)
{
switch (type.Kind) {
case TypeKind.Tuple:
if (output == null)
output = new List<IType>();
output.AddRange(((TupleType)type).ElementTypes);
return true;
case TypeKind.Class:
case TypeKind.Struct:
if (type.Namespace == "System" && type.Name == "ValueTuple") {
if (output == null)
output = new List<IType>();
int tpc = type.TypeParameterCount;
if (tpc > 0 && tpc < RestPosition) {
output.AddRange(type.TypeArguments);
return true;
} else if (tpc == RestPosition) {
output.AddRange(type.TypeArguments.Take(RestPosition - 1));
return Collect(type.TypeArguments[RestIndex]);
}
}
break;
}
return false;
}
}
public override TypeKind Kind => TypeKind.Tuple;
public override bool? IsReferenceType => UnderlyingType.IsReferenceType;
public override int TypeParameterCount => 0;
public override IReadOnlyList<ITypeParameter> TypeParameters => EmptyList<ITypeParameter>.Instance;
public override IReadOnlyList<IType> TypeArguments => EmptyList<IType>.Instance;
public override IEnumerable<IType> DirectBaseTypes => UnderlyingType.DirectBaseTypes;
public override string FullName => UnderlyingType.FullName;
public override string Name => UnderlyingType.Name;
public override string ReflectionName => UnderlyingType.ReflectionName;
public override string Namespace => UnderlyingType.Namespace;
public override bool Equals(IType other)
{
var o = other as TupleType;
if (o == null)
return false;
if (!UnderlyingType.Equals(o.UnderlyingType))
return false;
return UnderlyingType.Equals(o.UnderlyingType)
&& ElementNames.SequenceEqual(o.ElementNames);
}
public override int GetHashCode()
{
unchecked {
int hash = UnderlyingType.GetHashCode();
foreach (string name in ElementNames) {
hash *= 31;
hash += name != null ? name.GetHashCode() : 0;
}
return hash;
}
}
public override string ToString()
{
StringBuilder b = new StringBuilder();
b.Append('(');
for (int i = 0; i < ElementTypes.Length; i++) {
if (i > 0)
b.Append(", ");
b.Append(ElementTypes[i]);
if (ElementNames[i] != null) {
b.Append(' ');
b.Append(ElementNames[i]);
}
}
b.Append(')');
return b.ToString();
}
public override IType AcceptVisitor(TypeVisitor visitor)
{
return visitor.VisitTupleType(this);
}
public override IType VisitChildren(TypeVisitor visitor)
{
IType[] newElementTypes = null;
for (int i = 0; i < ElementTypes.Length; i++) {
IType type = ElementTypes[i];
var newType = type.AcceptVisitor(visitor);
if (newType != type) {
if (newElementTypes == null) {
newElementTypes = ElementTypes.ToArray();
}
newElementTypes[i] = newType;
}
}
if (newElementTypes != null) {
return new TupleType(this.Compilation, newElementTypes.ToImmutableArray(), this.ElementNames,
this.GetDefinition()?.ParentAssembly);
} else {
return this;
}
}
public override IEnumerable<IMethod> GetAccessors(Predicate<IUnresolvedMethod> filter = null, GetMemberOptions options = GetMemberOptions.None)
{
return UnderlyingType.GetAccessors(filter, options);
}
public override IEnumerable<IMethod> GetConstructors(Predicate<IUnresolvedMethod> filter = null, GetMemberOptions options = GetMemberOptions.IgnoreInheritedMembers)
{
// CS8181 'new' cannot be used with tuple type. Use a tuple literal expression instead.
return EmptyList<IMethod>.Instance;
}
public override ITypeDefinition GetDefinition()
{
return UnderlyingType.GetDefinition();
}
public override IEnumerable<IEvent> GetEvents(Predicate<IUnresolvedEvent> filter = null, GetMemberOptions options = GetMemberOptions.None)
{
return UnderlyingType.GetEvents(filter, options);
}
public override IEnumerable<IField> GetFields(Predicate<IUnresolvedField> filter = null, GetMemberOptions options = GetMemberOptions.None)
{
// The fields from the underlying type (Item1..Item7 and Rest)
foreach (var field in UnderlyingType.GetFields(filter, options)) {
yield return field;
}
/*for (int i = 0; i < ElementTypes.Length; i++) {
var type = ElementTypes[i];
var name = ElementNames[i];
int pos = i + 1;
string itemName = "Item" + pos;
if (name != itemName && name != null)
yield return MakeField(type, name);
if (pos >= RestPosition)
yield return MakeField(type, itemName);
}*/
}
/*private IField MakeField(IType type, string name)
{
var f = new DefaultUnresolvedField();
f.ReturnType = SpecialType.UnknownType;
f.Name = name;
return new TupleElementField(f, Compilation.TypeResolveContext);
}*/
public override IEnumerable<IMethod> GetMethods(Predicate<IUnresolvedMethod> filter = null, GetMemberOptions options = GetMemberOptions.None)
{
return UnderlyingType.GetMethods(filter, options);
}
public override IEnumerable<IMethod> GetMethods(IReadOnlyList<IType> typeArguments, Predicate<IUnresolvedMethod> filter = null, GetMemberOptions options = GetMemberOptions.None)
{
return UnderlyingType.GetMethods(typeArguments, filter, options);
}
public override IEnumerable<IType> GetNestedTypes(Predicate<ITypeDefinition> filter = null, GetMemberOptions options = GetMemberOptions.None)
{
return UnderlyingType.GetNestedTypes(filter, options);
}
public override IEnumerable<IType> GetNestedTypes(IReadOnlyList<IType> typeArguments, Predicate<ITypeDefinition> filter = null, GetMemberOptions options = GetMemberOptions.None)
{
return UnderlyingType.GetNestedTypes(typeArguments, filter, options);
}
public override IEnumerable<IProperty> GetProperties(Predicate<IUnresolvedProperty> filter = null, GetMemberOptions options = GetMemberOptions.None)
{
return UnderlyingType.GetProperties(filter, options);
}
}
public class TupleTypeReference : ITypeReference
{
/// <summary>
/// Gets the types of the tuple elements.
/// </summary>
public ImmutableArray<ITypeReference> ElementTypes { get; }
/// <summary>
/// Gets the names of the tuple elements.
/// </summary>
public ImmutableArray<string> ElementNames { get; }
public IAssemblyReference ValueTupleAssembly { get; }
public TupleTypeReference(ImmutableArray<ITypeReference> elementTypes)
{
this.ElementTypes = elementTypes;
}
public TupleTypeReference(ImmutableArray<ITypeReference> elementTypes,
ImmutableArray<string> elementNames = default(ImmutableArray<string>),
IAssemblyReference valueTupleAssembly = null)
{
this.ValueTupleAssembly = valueTupleAssembly;
this.ElementTypes = elementTypes;
this.ElementNames = elementNames;
}
public IType Resolve(ITypeResolveContext context)
{
return new TupleType(context.Compilation,
ElementTypes.Select(t => t.Resolve(context)).ToImmutableArray(),
ElementNames,
ValueTupleAssembly?.Resolve(context)
);
}
}
public static class TupleTypeExtensions
{
public static IType TupleUnderlyingTypeOrSelf(this IType type)
{
return (type as TupleType)?.UnderlyingType ?? type;
}
}
}

12
ICSharpCode.Decompiler/TypeSystem/TypeKind.cs

@ -45,12 +45,16 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -45,12 +45,16 @@ namespace ICSharpCode.Decompiler.TypeSystem
/// <summary>The <c>System.Void</c> type.</summary>
/// <see cref="KnownTypeReference.Void"/>
Void,
/// <summary>Type used for invalid expressions and for types whose definition could not be found.</summary>
/// <see cref="SpecialType.UnknownType"/>
Unknown,
/// <summary>The type of the null literal.</summary>
/// <see cref="SpecialType.NullType"/>
Null,
/// <summary>The type of expressions without type (except for null literals, which have <c>TypeKind.Null</c>).</summary>
/// <see cref="SpecialType.NoType"/>
None,
/// <summary>Type representing the C# 'dynamic' type.</summary>
/// <see cref="SpecialType.Dynamic"/>
Dynamic,
@ -81,5 +85,11 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -81,5 +85,11 @@ namespace ICSharpCode.Decompiler.TypeSystem
Intersection,
/// <see cref="SpecialType.ArgList"/>
ArgList,
/// <summary>A C# 7 tuple type.
/// E.g. <code>(string, int)</code>
/// Note: <code>System.ValueTuple&lt;string, int&gt;</code> is not considered a tuple type.
/// </summary>
/// <see cref="TupleType"/>
Tuple,
}
}

29
ICSharpCode.Decompiler/TypeSystem/TypeParameterSubstitution.cs

@ -96,8 +96,16 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -96,8 +96,16 @@ namespace ICSharpCode.Decompiler.TypeSystem
return result;
}
#endregion
#region Equals and GetHashCode implementation
public bool Equals(TypeParameterSubstitution other, TypeVisitor normalization)
{
if (other == null)
return false;
return TypeListEquals(classTypeArguments, other.classTypeArguments, normalization)
&& TypeListEquals(methodTypeArguments, other.methodTypeArguments, normalization);
}
public override bool Equals(object obj)
{
TypeParameterSubstitution other = obj as TypeParameterSubstitution;
@ -128,7 +136,24 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -128,7 +136,24 @@ namespace ICSharpCode.Decompiler.TypeSystem
}
return true;
}
static bool TypeListEquals(IReadOnlyList<IType> a, IReadOnlyList<IType> b, TypeVisitor normalization)
{
if (a == b)
return true;
if (a == null || b == null)
return false;
if (a.Count != b.Count)
return false;
for (int i = 0; i < a.Count; i++) {
var an = a[i].AcceptVisitor(normalization);
var bn = b[i].AcceptVisitor(normalization);
if (!an.Equals(bn))
return false;
}
return true;
}
static int TypeListHashCode(IReadOnlyList<IType> obj)
{
if (obj == null)

7
ICSharpCode.Decompiler/TypeSystem/TypeVisitor.cs

@ -52,7 +52,12 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -52,7 +52,12 @@ namespace ICSharpCode.Decompiler.TypeSystem
{
return type.VisitChildren(this);
}
public virtual IType VisitTupleType(TupleType type)
{
return type.VisitChildren(this);
}
public virtual IType VisitOtherType(IType type)
{
return type.VisitChildren(this);

8
ICSharpCode.Decompiler/TypeSystem/VarArgInstanceMethod.cs

@ -63,7 +63,13 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -63,7 +63,13 @@ namespace ICSharpCode.Decompiler.TypeSystem
{
return baseMethod.GetHashCode();
}
public bool Equals(IMember obj, TypeVisitor typeNormalization)
{
VarArgInstanceMethod other = obj as VarArgInstanceMethod;
return other != null && baseMethod.Equals(other.baseMethod, typeNormalization);
}
public override string ToString()
{
StringBuilder b = new StringBuilder("[");

20
ICSharpCode.Decompiler/Util/CollectionExtensions.cs

@ -12,6 +12,26 @@ namespace ICSharpCode.Decompiler.Util @@ -12,6 +12,26 @@ namespace ICSharpCode.Decompiler.Util
value = pair.Value;
}
public static IEnumerable<(A, B)> Zip<A, B>(this IEnumerable<A> input1, IEnumerable<B> input2)
{
return input1.Zip(input2, (a, b) => (a, b));
}
public static IEnumerable<T> Slice<T>(this IReadOnlyList<T> input, int offset, int length)
{
for (int i = offset; i < offset + length; i++) {
yield return input[i];
}
}
public static IEnumerable<T> Slice<T>(this IReadOnlyList<T> input, int offset)
{
int length = input.Count;
for (int i = offset; i < length; i++) {
yield return input[i];
}
}
public static HashSet<T> ToHashSet<T>(this IEnumerable<T> input)
{
return new HashSet<T>(input);

Loading…
Cancel
Save