// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. using System; using System.Collections.Generic; using System.Collections.Immutable; using System.Globalization; using System.Linq; using System.Reflection.Metadata; using System.Text; using Microsoft.CodeAnalysis.CSharp.Symbols; using Microsoft.CodeAnalysis.CSharp.Symbols.Metadata.PE; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.CSharp.Test.Utilities; using Microsoft.CodeAnalysis.Test.Extensions; using Microsoft.CodeAnalysis.Test.Utilities; using Microsoft.CodeAnalysis.Text; using Roslyn.Test.Utilities; using Roslyn.Utilities; using Xunit; using static TestResources.NetFX.ValueTuple; using static Roslyn.Test.Utilities.TestMetadata; namespace Microsoft.CodeAnalysis.CSharp.UnitTests.CodeGen { [CompilerTrait(CompilerFeature.Tuples)] public class CodeGenTupleTests : CSharpTestBase { private static readonly MetadataReference[] s_valueTupleRefs = new[] { SystemRuntimeFacadeRef, ValueTupleRef }; private static readonly string trivial2uple = @" namespace System { // struct with two values public struct ValueTuple { public T1 Item1; public T2 Item2; public ValueTuple(T1 item1, T2 item2) { this.Item1 = item1; this.Item2 = item2; } public override string ToString() { return '{' + Item1?.ToString() + "", "" + Item2?.ToString() + '}'; } } } "; private static readonly string trivial3uple = @" namespace System { // struct with two values public struct ValueTuple { public T1 Item1; public T2 Item2; public T3 Item3; public ValueTuple(T1 item1, T2 item2, T3 item3) { this.Item1 = item1; this.Item2 = item2; this.Item3 = item3; } public override string ToString() { return '{' + Item1?.ToString() + "", "" + Item2?.ToString() + "", "" + Item3?.ToString() + '}'; } } } "; private static readonly string trivialRemainingTuples = @" namespace System { public struct ValueTuple { public T1 Item1; public ValueTuple(T1 item1) { this.Item1 = item1; } public override string ToString() { return '{' + Item1?.ToString() + '}'; } } public struct ValueTuple { public T1 Item1; public T2 Item2; public T3 Item3; public T4 Item4; public ValueTuple(T1 item1, T2 item2, T3 item3, T4 item4) { Item1 = item1; Item2 = item2; Item3 = item3; Item4 = item4; } } public struct ValueTuple { public T1 Item1; public T2 Item2; public T3 Item3; public T4 Item4; public T5 Item5; public ValueTuple(T1 item1, T2 item2, T3 item3, T4 item4, T5 item5) { Item1 = item1; Item2 = item2; Item3 = item3; Item4 = item4; Item5 = item5; } } public struct ValueTuple { public T1 Item1; public T2 Item2; public T3 Item3; public T4 Item4; public T5 Item5; public T6 Item6; public ValueTuple(T1 item1, T2 item2, T3 item3, T4 item4, T5 item5, T6 item6) { Item1 = item1; Item2 = item2; Item3 = item3; Item4 = item4; Item5 = item5; Item6 = item6; } } public struct ValueTuple { public T1 Item1; public T2 Item2; public T3 Item3; public T4 Item4; public T5 Item5; public T6 Item6; public T7 Item7; public ValueTuple(T1 item1, T2 item2, T3 item3, T4 item4, T5 item5, T6 item6, T7 item7) { Item1 = item1; Item2 = item2; Item3 = item3; Item4 = item4; Item5 = item5; Item6 = item6; Item7 = item7; } } public struct ValueTuple { public T1 Item1; public T2 Item2; public T3 Item3; public T4 Item4; public T5 Item5; public T6 Item6; public T7 Item7; public TRest Rest; public ValueTuple(T1 item1, T2 item2, T3 item3, T4 item4, T5 item5, T6 item6, T7 item7, TRest rest) { Item1 = item1; Item2 = item2; Item3 = item3; Item4 = item4; Item5 = item5; Item6 = item6; Item7 = item7; Rest = rest; } public override string ToString() { return base.ToString(); } } } "; [Fact] public void BadValueTupleByItself() { var source = @" namespace System { struct ValueTuple { public T1 Item1; private T2 Item2; public ValueTuple(T1 item1, T2 item2) { this.Item1 = item1; this.Item2 = item2; } } }"; var comp = CreateCompilation(source, parseOptions: TestOptions.Regular7); comp.VerifyEmitDiagnostics( // (7,20): warning CS0169: The field '(T1, T2).Item2' is never used // private T2 Item2; Diagnostic(ErrorCode.WRN_UnreferencedField, "Item2").WithArguments("(T1, T2).Item2").WithLocation(7, 20), // (8,16): error CS0171: Field '(T1, T2).Item2' must be fully assigned before control is returned to the caller // public ValueTuple(T1 item1, T2 item2) Diagnostic(ErrorCode.ERR_UnassignedThis, "ValueTuple").WithArguments("(T1, T2).Item2").WithLocation(8, 16), // (8,16): error CS0171: Field '(T1, T2).Item2' must be fully assigned before control is returned to the caller // public ValueTuple(T1 item1, T2 item2) Diagnostic(ErrorCode.ERR_UnassignedThis, "ValueTuple").WithArguments("(T1, T2).Item2").WithLocation(8, 16), // (11,18): error CS0229: Ambiguity between '(T1, T2).Item2' and '(T1, T2).Item2' // this.Item2 = item2; Diagnostic(ErrorCode.ERR_AmbigMember, "Item2").WithArguments("(T1, T2).Item2", "(T1, T2).Item2").WithLocation(11, 18) ); } [Fact] public void ValueTupleWithDifferentNamesInOperator() { var source = @" namespace System { struct ValueTuple { public T1 Item1; public T2 Item2; public ValueTuple(T1 item1, T2 item2) { this.Item1 = item1; this.Item2 = item2; } public static bool operator +((T1 a, T2 b) t) => throw null; public static bool operator true((T1 a, T2 b) t) => throw null; public static bool operator false((T1 a, T2 b) t) => throw null; } }"; var comp = CreateCompilation(source, parseOptions: TestOptions.Regular7); comp.VerifyEmitDiagnostics(); } [Fact] public void MergeNamesFromTypelessTuple() { var src = @" class C { T M(T x, T y) => throw null; void M2() { var t = M((a: 1, b: ""hello""), (a: default, b: null)); t.a.ToString(); t.b.ToString(); var t2 = M((a: 1, b: ""hello""), (a: default, z: null)); // 1 t2.a.ToString(); t2.b.ToString(); var t3 = M((1, ""hello""), (a: default, b: null)); // 2, 3 t3.a.ToString(); // 4 t3.b.ToString(); // 5 } } "; var comp = CreateCompilation(src); comp.VerifyDiagnostics( // (11,53): warning CS8123: The tuple element name 'z' is ignored because a different name or no name is specified by the target type '(int a, string b)'. // var t2 = M((a: 1, b: "hello"), (a: default, z: null)); // 1 Diagnostic(ErrorCode.WRN_TupleLiteralNameMismatch, "z: null").WithArguments("z", "(int a, string b)").WithLocation(11, 53), // (15,35): warning CS8123: The tuple element name 'a' is ignored because a different name or no name is specified by the target type '(int, string)'. // var t3 = M((1, "hello"), (a: default, b: null)); // 2, 3 Diagnostic(ErrorCode.WRN_TupleLiteralNameMismatch, "a: default").WithArguments("a", "(int, string)").WithLocation(15, 35), // (15,47): warning CS8123: The tuple element name 'b' is ignored because a different name or no name is specified by the target type '(int, string)'. // var t3 = M((1, "hello"), (a: default, b: null)); // 2, 3 Diagnostic(ErrorCode.WRN_TupleLiteralNameMismatch, "b: null").WithArguments("b", "(int, string)").WithLocation(15, 47), // (16,12): error CS1061: '(int, string)' does not contain a definition for 'a' and no accessible extension method 'a' accepting a first argument of type '(int, string)' could be found (are you missing a using directive or an assembly reference?) // t3.a.ToString(); // 4 Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "a").WithArguments("(int, string)", "a").WithLocation(16, 12), // (17,12): error CS1061: '(int, string)' does not contain a definition for 'b' and no accessible extension method 'b' accepting a first argument of type '(int, string)' could be found (are you missing a using directive or an assembly reference?) // t3.b.ToString(); // 5 Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "b").WithArguments("(int, string)", "b").WithLocation(17, 12) ); } [Fact] public void InferenceWithTupleNamesInNullableContext() { var src = @" #nullable enable public class C { void M(C<(int a, string b)> list) { _ = list.Select(i => i.a); } } public static class Extensions { public static T2 Select(this C list, System.Func f) => throw null!; } "; var comp = CreateCompilation(src); comp.VerifyDiagnostics(); } [Fact] [WorkItem(14844, "https://github.com/dotnet/roslyn/issues/14844")] public void InterfaceImplAttributesAreNotSharedAcrossTypeRefs() { var src1 = @" public interface I1 {} public interface I2 : I1<(int a, int b)> {} public interface I3 : I1<(int c, int d)> {}"; var src2 = @" class C1 : I2, I1<(int a, int b)> {} class C2 : I3, I1<(int c, int d)> {}"; var comp1 = CreateCompilation(src1); comp1.VerifyDiagnostics(); var comp2 = CreateCompilation(src2, references: new[] { comp1.ToMetadataReference() }); comp2.VerifyDiagnostics(); var comp3 = CreateCompilation(src2, references: new[] { comp1.EmitToImageReference() }); comp3.VerifyDiagnostics(); } [Fact] [WorkItem(14844, "https://github.com/dotnet/roslyn/issues/14844")] public void ConstraintAttributesAreNotSharedAcrossTypeRefs() { var src1 = @" using System.Collections.Generic; public abstract class C1 { public abstract void M(T t) where T : IEnumerable<(int a, int b)>; } public abstract class C2 { public abstract void M(T t) where T : IEnumerable<(int c, int d)>; }"; var src2 = @" class C3 : C1 { public override void M(U u) { int x; foreach (var kvp in u) { x = kvp.a + kvp.b; } } } class C4 : C2 { public override void M(U u) { int x; foreach (var kvp in u) { x = kvp.c + kvp.d; } } }"; var comp1 = CreateCompilationWithMscorlib40(src1, references: s_valueTupleRefs); comp1.VerifyDiagnostics(); var comp2 = CreateCompilationWithMscorlib40(src2, references: new[] { SystemRuntimeFacadeRef, ValueTupleRef, comp1.ToMetadataReference() }); comp2.VerifyDiagnostics(); var comp3 = CreateCompilationWithMscorlib40(src2, references: new[] { SystemRuntimeFacadeRef, ValueTupleRef, comp1.EmitToImageReference() }); comp3.VerifyDiagnostics(); } [Fact] public void InterfaceAttributes() { var comp = CreateCompilation(@" using System; using System.Collections; using System.Collections.Generic; interface ITest { T Get(); } public class C : ITest<(int key, int val)> { public (int key, int val) Get() => (0, 0); } public class Base : ITest { public T Get() => default(T); } public class C2 : Base<(int x, int y)> { } public class C3 : IEnumerable<(int key, int val)> { private readonly (int, int)[] _backing; public C3((int, int)[] backing) { _backing = backing; } private class Inner : IEnumerator<(int key, int val)>, IEnumerator { private int index = -1; private readonly (int, int)[] _backing; public Inner((int, int)[] backing) { _backing = backing; } public (int key, int val) Current => _backing[index]; object IEnumerator.Current => Current; public void Dispose() { } public bool MoveNext() => ++index < _backing.Length; public void Reset() { throw new NotSupportedException(); } } IEnumerator<(int key, int val)> IEnumerable<(int key, int val)>.GetEnumerator() => new Inner(_backing); IEnumerator IEnumerable.GetEnumerator() => new Inner(_backing); } public class C4 : C3 { public C4((int, int)[] backing) : base(backing) { } } "); CompileAndVerify(comp, symbolValidator: m => { var c = m.GlobalNamespace.GetTypeMember("C"); Assert.Equal(1, c.Interfaces().Length); NamedTypeSymbol iface = c.Interfaces()[0]; Assert.True(iface.IsGenericType); Assert.Equal(1, iface.TypeArguments().Length); TypeSymbol typeArg = iface.TypeArguments()[0]; Assert.True(typeArg.IsTupleType); Assert.False(((NamedTypeSymbol)typeArg).IsSerializable); Assert.Equal(2, typeArg.TupleElementTypesWithAnnotations.Length); Assert.All(typeArg.TupleElementTypesWithAnnotations, t => Assert.Equal(SpecialType.System_Int32, t.SpecialType)); Assert.Equal(new[] { "key", "val" }, typeArg.TupleElementNames); var c2 = m.GlobalNamespace.GetTypeMember("C2"); var @base = c2.BaseType(); Assert.Equal("Base", @base.Name); Assert.Equal(1, @base.Interfaces().Length); iface = @base.Interfaces()[0]; Assert.True(iface.IsGenericType); Assert.Equal(1, iface.TypeArguments().Length); typeArg = iface.TypeArguments()[0]; Assert.True(typeArg.IsTupleType); Assert.Equal(2, typeArg.TupleElementTypesWithAnnotations.Length); Assert.All(typeArg.TupleElementTypesWithAnnotations, t => Assert.Equal(SpecialType.System_Int32, t.SpecialType)); Assert.Equal(new[] { "x", "y" }, typeArg.TupleElementNames); var c3 = m.GlobalNamespace.GetTypeMember("C3"); Assert.Equal(2, c3.Interfaces().Length); iface = c3.Interfaces()[0]; Assert.True(iface.IsGenericType); Assert.Equal(1, iface.TypeArguments().Length); typeArg = iface.TypeArguments()[0]; Assert.True(typeArg.IsTupleType); Assert.Equal(2, typeArg.TupleElementTypesWithAnnotations.Length); Assert.All(typeArg.TupleElementTypesWithAnnotations, t => Assert.Equal(SpecialType.System_Int32, t.SpecialType)); Assert.Equal(new[] { "key", "val" }, typeArg.TupleElementNames); var d = m.GlobalNamespace.GetTypeMember("C3"); Assert.Equal(2, d.Interfaces().Length); iface = d.Interfaces()[0]; Assert.True(iface.IsGenericType); Assert.Equal(1, iface.TypeArguments().Length); typeArg = iface.TypeArguments()[0]; Assert.True(typeArg.IsTupleType); Assert.Equal(2, typeArg.TupleElementTypesWithAnnotations.Length); Assert.All(typeArg.TupleElementTypesWithAnnotations, t => Assert.Equal(SpecialType.System_Int32, t.SpecialType)); Assert.Equal(new[] { "key", "val" }, typeArg.TupleElementNames); }); CompileAndVerify(@" using System; class D { public static void Main(string[] args) { var c = new C(); var temp = c.Get(); Console.WriteLine(temp); Console.WriteLine(""key: "" + temp.key); Console.WriteLine(""val: "" + temp.val); var c2 = new C2(); var temp2 = c2.Get(); Console.WriteLine(temp); Console.WriteLine(""x: "" + temp2.x); Console.WriteLine(""y: "" + temp2.y); var backing = new[] { (1, 1), (2, 2), (3, 3) }; var c3 = new C3(backing); foreach (var kvp in c3) { Console.WriteLine($""(key: {kvp.key}, val: {kvp.val})""); } var c4 = new C4(backing); foreach (var kvp in c4) { Console.WriteLine($""(key: {kvp.key}, val: {kvp.val})""); } } }", references: new[] { comp.EmitToImageReference() }, expectedOutput: @"(0, 0) key: 0 val: 0 (0, 0) x: 0 y: 0 (key: 1, val: 1) (key: 2, val: 2) (key: 3, val: 3) (key: 1, val: 1) (key: 2, val: 2) (key: 3, val: 3)"); } [Fact] public void GenericConstraintAttributes() { var comp = CreateCompilation(@" using System; using System.Collections; using System.Collections.Generic; public interface ITest { T Get { get; } } public class Test : ITest<(int key, int val)> { public (int key, int val) Get => (0, 0); } public class Base : ITest { public T Get { get; } protected Base(T t) { Get = t; } } public class C where T : ITest<(int key, int val)> { public T Get { get; } public C(T t) { Get = t; } } public class C2 where T : Base<(int key, int val)> { public T Get { get; } public C2(T t) { Get = t; } } public sealed class Test2 : Base<(int key, int val)> { public Test2() : base((-1, -2)) {} } public class C3 where T : IEnumerable<(int key, int val)> { public T Get { get; } public C3(T t) { Get = t; } } public struct TestEnumerable : IEnumerable<(int key, int val)> { private readonly (int, int)[] _backing; public TestEnumerable((int, int)[] backing) { _backing = backing; } private class Inner : IEnumerator<(int key, int val)>, IEnumerator { private int index = -1; private readonly (int, int)[] _backing; public Inner((int, int)[] backing) { _backing = backing; } public (int key, int val) Current => _backing[index]; object IEnumerator.Current => Current; public void Dispose() { } public bool MoveNext() => ++index < _backing.Length; public void Reset() { throw new NotSupportedException(); } } IEnumerator<(int key, int val)> IEnumerable<(int key, int val)>.GetEnumerator() => new Inner(_backing); IEnumerator IEnumerable.GetEnumerator() => new Inner(_backing); } "); CompileAndVerify(comp, symbolValidator: m => { var c = m.GlobalNamespace.GetTypeMember("C"); Assert.Equal(1, c.TypeParameters.Length); var param = c.TypeParameters[0]; Assert.Equal(1, param.ConstraintTypes().Length); var constraint = Assert.IsAssignableFrom(param.ConstraintTypes()[0]); Assert.True(constraint.IsGenericType); Assert.Equal(1, constraint.TypeArguments().Length); TypeSymbol typeArg = constraint.TypeArguments()[0]; Assert.True(typeArg.IsTupleType); Assert.Equal(2, typeArg.TupleElementTypesWithAnnotations.Length); Assert.All(typeArg.TupleElementTypesWithAnnotations, t => Assert.Equal(SpecialType.System_Int32, t.SpecialType)); Assert.False(typeArg.TupleElementNames.IsDefault); Assert.Equal(2, typeArg.TupleElementNames.Length); Assert.Equal(new[] { "key", "val" }, typeArg.TupleElementNames); var c2 = m.GlobalNamespace.GetTypeMember("C2"); Assert.Equal(1, c2.TypeParameters.Length); param = c2.TypeParameters[0]; Assert.Equal(1, param.ConstraintTypes().Length); constraint = Assert.IsAssignableFrom(param.ConstraintTypes()[0]); Assert.True(constraint.IsGenericType); Assert.Equal(1, constraint.TypeArguments().Length); typeArg = constraint.TypeArguments()[0]; Assert.True(typeArg.IsTupleType); Assert.Equal(2, typeArg.TupleElementTypesWithAnnotations.Length); Assert.All(typeArg.TupleElementTypesWithAnnotations, t => Assert.Equal(SpecialType.System_Int32, t.SpecialType)); Assert.False(typeArg.TupleElementNames.IsDefault); Assert.Equal(2, typeArg.TupleElementNames.Length); Assert.Equal(new[] { "key", "val" }, typeArg.TupleElementNames); }); CompileAndVerify(@" using System; class D { public static void Main(string[] args) { var c = new C(new Test()); var temp = c.Get.Get; Console.WriteLine(temp); Console.WriteLine(""key: "" + temp.key); Console.WriteLine(""val: "" + temp.val); var c2 = new C2(new Test2()); var temp2 = c2.Get.Get; Console.WriteLine(temp2); Console.WriteLine(""key: "" + temp2.key); Console.WriteLine(""val: "" + temp2.val); var backing = new[] { (1, 2), (3, 4), (5, 6) }; var c3 = new C3(new TestEnumerable(backing)); foreach (var kvp in c3.Get) { Console.WriteLine($""key: {kvp.key}, val: {kvp.val}""); } var c4 = new C(new Test2()); var temp4 = c4.Get.Get; Console.WriteLine(temp4); Console.WriteLine(""key: "" + temp4.key); Console.WriteLine(""val: "" + temp4.val); } }", references: new[] { comp.EmitToImageReference() }, expectedOutput: @"(0, 0) key: 0 val: 0 (-1, -2) key: -1 val: -2 key: 1, val: 2 key: 3, val: 4 key: 5, val: 6 (-1, -2) key: -1 val: -2 "); } [Fact] public void BadTupleNameMetadata() { var comp = CreateCompilationWithILAndMscorlib40("", @" .assembly extern mscorlib { } .assembly extern System.ValueTuple { .publickeytoken = (CC 7B 13 FF CD 2D DD 51 ) .ver 4:0:1:0 } .class public auto ansi C extends [mscorlib]System.Object { .field public class [System.ValueTuple]System.ValueTuple`2 ValidField .field public int32 ValidFieldWithAttribute .custom instance void [System.ValueTuple]System.Runtime.CompilerServices.TupleElementNamesAttribute::.ctor(string[]) // = {string[1](""name1"")} = ( 01 00 01 00 00 00 05 6E 61 6D 65 31 ) .field public class [System.ValueTuple]System.ValueTuple`2 TooFewNames .custom instance void [System.ValueTuple]System.Runtime.CompilerServices.TupleElementNamesAttribute::.ctor(string[]) // = {string[1](""name1"")} = ( 01 00 01 00 00 00 05 6E 61 6D 65 31 ) .field public class [System.ValueTuple]System.ValueTuple`2 TooManyNames .custom instance void [System.ValueTuple]System.Runtime.CompilerServices.TupleElementNamesAttribute::.ctor(string[]) // = {string[3](""e1"", ""e2"", ""e3"")} = ( 01 00 03 00 00 00 02 65 31 02 65 32 02 65 33 ) .method public hidebysig instance class [System.ValueTuple]System.ValueTuple`2 TooFewNamesMethod() cil managed { .param [0] .custom instance void [System.ValueTuple]System.Runtime.CompilerServices.TupleElementNamesAttribute::.ctor(string[]) // = {string[1](""name1"")} = ( 01 00 01 00 00 00 05 6E 61 6D 65 31 ) // Code size 8 (0x8) .maxstack 8 IL_0000: ldc.i4.0 IL_0001: ldc.i4.0 IL_0002: newobj instance void class [System.ValueTuple]System.ValueTuple`2::.ctor(!0, !1) IL_0007: ret } // end of method C::TooFewNamesMethod .method public hidebysig instance class [System.ValueTuple]System.ValueTuple`2 TooManyNamesMethod() cil managed { .param [0] .custom instance void [System.ValueTuple]System.Runtime.CompilerServices.TupleElementNamesAttribute::.ctor(string[]) // = {string[3](""e1"", ""e2"", ""e3"")} = ( 01 00 03 00 00 00 02 65 31 02 65 32 02 65 33 ) // Code size 8 (0x8) .maxstack 8 IL_0000: ldc.i4.0 IL_0001: ldc.i4.0 IL_0002: newobj instance void class [System.ValueTuple]System.ValueTuple`2::.ctor(!0, !1) IL_0007: ret } // end of method C::TooManyNamesMethod } // end of class C ", references: s_valueTupleRefs); var c = comp.GlobalNamespace.GetMember("C"); var validField = c.GetMember("ValidField"); Assert.False(validField.Type.IsErrorType()); Assert.True(validField.Type.IsTupleType); Assert.True(validField.Type.TupleElementNames.IsDefault); var validFieldWithAttribute = c.GetMember("ValidFieldWithAttribute"); Assert.True(validFieldWithAttribute.Type.IsErrorType()); Assert.False(validFieldWithAttribute.Type.IsTupleType); Assert.IsType(validFieldWithAttribute.Type); var tooFewNames = c.GetMember("TooFewNames"); Assert.True(tooFewNames.Type.IsErrorType()); Assert.IsType(tooFewNames.Type); Assert.False(((NamedTypeSymbol)tooFewNames.Type).IsSerializable); var tooManyNames = c.GetMember("TooManyNames"); Assert.True(tooManyNames.Type.IsErrorType()); Assert.IsType(tooManyNames.Type); var tooFewNamesMethod = c.GetMember("TooFewNamesMethod"); Assert.True(tooFewNamesMethod.ReturnType.IsErrorType()); Assert.IsType(tooFewNamesMethod.ReturnType); var tooManyNamesMethod = c.GetMember("TooManyNamesMethod"); Assert.True(tooManyNamesMethod.ReturnType.IsErrorType()); Assert.IsType(tooManyNamesMethod.ReturnType); } [Fact] public void MetadataForPartiallyNamedTuples() { var comp = CreateCompilationWithILAndMscorlib40("", @" .assembly extern mscorlib { } .assembly extern System.ValueTuple { .publickeytoken = (CC 7B 13 FF CD 2D DD 51 ) .ver 4:0:1:0 } .class public auto ansi C extends [mscorlib]System.Object { .field public class [System.ValueTuple]System.ValueTuple`2 ValidField .field public int32 ValidFieldWithAttribute .custom instance void [System.ValueTuple]System.Runtime.CompilerServices.TupleElementNamesAttribute::.ctor(string[]) // = {string[1](""name1"")} = ( 01 00 01 00 00 00 05 6E 61 6D 65 31 ) // In source, all or no names must be specified for a tuple .field public class [System.ValueTuple]System.ValueTuple`2 PartialNames .custom instance void [System.ValueTuple]System.Runtime.CompilerServices.TupleElementNamesAttribute::.ctor(string[]) // = {string[2](""e1"", null)} = ( 01 00 02 00 00 00 02 65 31 FF ) .field public class [System.ValueTuple]System.ValueTuple`2 AllNullNames .custom instance void [System.ValueTuple]System.Runtime.CompilerServices.TupleElementNamesAttribute::.ctor(string[]) // = {string[2](null, null)} = ( 01 00 02 00 00 00 ff ff 00 00 ) .method public hidebysig instance void PartialNamesMethod( class [System.ValueTuple]System.ValueTuple`1> c) cil managed { .param [1] .custom instance void [System.ValueTuple]System.Runtime.CompilerServices.TupleElementNamesAttribute::.ctor(string[]) // First null is fine (unnamed tuple) but the second is half-named // = {string[3](null, ""e1"", null)} = ( 01 00 03 00 00 00 FF 02 65 31 FF ) // Code size 2 (0x2) .maxstack 8 IL_0000: nop IL_0001: ret } // end of method C::PartialNamesMethod .method public hidebysig instance void AllNullNamesMethod( class [System.ValueTuple]System.ValueTuple`1> c) cil managed { .param [1] .custom instance void [System.ValueTuple]System.Runtime.CompilerServices.TupleElementNamesAttribute::.ctor(string[]) // First null is fine (unnamed tuple) but the second is half-named // = {string[3](null, null, null)} = ( 01 00 03 00 00 00 ff ff ff 00 00 ) // Code size 2 (0x2) .maxstack 8 IL_0000: nop IL_0001: ret } // end of method C::AllNullNamesMethod } // end of class C ", targetFramework: TargetFramework.Mscorlib40, references: s_valueTupleRefs); var c = comp.GlobalNamespace.GetMember("C"); var validField = c.GetMember("ValidField"); Assert.False(validField.Type.IsErrorType()); Assert.True(validField.Type.IsTupleType); Assert.True(validField.Type.TupleElementNames.IsDefault); var validFieldWithAttribute = c.GetMember("ValidFieldWithAttribute"); Assert.True(validFieldWithAttribute.Type.IsErrorType()); Assert.False(validFieldWithAttribute.Type.IsTupleType); Assert.IsType(validFieldWithAttribute.Type); var partialNames = c.GetMember("PartialNames"); Assert.False(partialNames.Type.IsErrorType()); Assert.True(partialNames.Type.IsTupleType); Assert.Equal("(System.Int32 e1, System.Int32)", partialNames.TypeWithAnnotations.ToTestDisplayString()); var allNullNames = c.GetMember("AllNullNames"); Assert.False(allNullNames.Type.IsErrorType()); Assert.True(allNullNames.Type.IsTupleType); Assert.Equal("(System.Int32, System.Int32)", allNullNames.TypeWithAnnotations.ToTestDisplayString()); var partialNamesMethod = c.GetMember("PartialNamesMethod"); var partialParamType = partialNamesMethod.Parameters.Single().TypeWithAnnotations; Assert.False(partialParamType.Type.IsErrorType()); Assert.True(partialParamType.Type.IsTupleType); Assert.Equal("System.ValueTuple<(System.Int32 e1, System.Int32)>", partialParamType.ToTestDisplayString()); var allNullNamesMethod = c.GetMember("AllNullNamesMethod"); var allNullParamType = allNullNamesMethod.Parameters.Single().TypeWithAnnotations; Assert.False(allNullParamType.Type.IsErrorType()); Assert.True(allNullParamType.Type.IsTupleType); Assert.Equal("System.ValueTuple<(System.Int32, System.Int32)>", allNullParamType.ToTestDisplayString()); } [Fact] public void NestedTuplesNoAttribute() { var comp = CreateCompilationWithILAndMscorlib40("", @" .assembly extern mscorlib { } .assembly extern System.ValueTuple { .publickeytoken = (CC 7B 13 FF CD 2D DD 51 ) .ver 4:0:1:0 } .class public auto ansi beforefieldinit Base`1 extends [mscorlib]System.Object { } .class public auto ansi C extends [mscorlib]System.Object { .field public class [System.ValueTuple]System.ValueTuple`2 Field1 .field public class Base`1>> Field2; } // end of class C ", references: s_valueTupleRefs); var c = comp.GlobalNamespace.GetMember("C"); var base1 = comp.GlobalNamespace.GetTypeMember("Base"); Assert.NotNull(base1); var field1 = c.GetMember("Field1"); Assert.False(field1.Type.IsErrorType()); Assert.True(field1.Type.IsTupleType); Assert.True(field1.Type.TupleElementNames.IsDefault); NamedTypeSymbol field2Type = (NamedTypeSymbol)c.GetMember("Field2").Type; Assert.Equal(base1, field2Type.OriginalDefinition); Assert.True(field2Type.IsGenericType); var first = field2Type.TypeArguments()[0]; Assert.True(first.IsTupleType); Assert.Equal(1, first.TupleElementTypesWithAnnotations.Length); Assert.True(first.TupleElementNames.IsDefault); var second = first.TupleElementTypesWithAnnotations[0].Type; Assert.True(second.IsTupleType); Assert.True(second.TupleElementNames.IsDefault); Assert.Equal(2, second.TupleElementTypesWithAnnotations.Length); Assert.All(second.TupleElementTypesWithAnnotations, t => Assert.Equal(SpecialType.System_Int32, t.SpecialType)); } [Fact] public void SimpleTuple() { var source = @" class C { static void Main() { var x = (1, 2); System.Console.WriteLine(x.ToString()); } } " + trivial2uple + tupleattributes_cs; var comp = CompileAndVerify(source, expectedOutput: "{1, 2}"); comp.VerifyDiagnostics(); comp.VerifyIL("C.Main", @" { // Code size 28 (0x1c) .maxstack 3 .locals init (System.ValueTuple V_0) //x IL_0000: ldloca.s V_0 IL_0002: ldc.i4.1 IL_0003: ldc.i4.2 IL_0004: call ""System.ValueTuple..ctor(int, int)"" IL_0009: ldloca.s V_0 IL_000b: constrained. ""System.ValueTuple"" IL_0011: callvirt ""string object.ToString()"" IL_0016: call ""void System.Console.WriteLine(string)"" IL_001b: ret }"); } [Fact] public void SimpleTupleNew() { var source = @" class C { static void Main() { var x = new (int, int)(1, 2); System.Console.WriteLine(x.ToString()); x = new (int, int)(); System.Console.WriteLine(x.ToString()); } } " + trivial2uple + tupleattributes_cs; var comp = CreateCompilation(source); comp.VerifyDiagnostics( // (6,21): error CS8181: 'new' cannot be used with tuple type. Use a tuple literal expression instead. // var x = new (int, int)(1, 2); Diagnostic(ErrorCode.ERR_NewWithTupleTypeSyntax, "(int, int)").WithLocation(6, 21), // (9,17): error CS8181: 'new' cannot be used with tuple type. Use a tuple literal expression instead. // x = new (int, int)(); Diagnostic(ErrorCode.ERR_NewWithTupleTypeSyntax, "(int, int)").WithLocation(9, 17) ); } [Fact] public void SimpleTupleNew1() { var source = @" class C { static void Main() { dynamic arg = 2; var x = new (int, int)(1, arg); System.Console.WriteLine(x.ToString()); } } " + trivial2uple + tupleattributes_cs; var comp = CreateCompilation(source); comp.VerifyDiagnostics( // (7,21): error CS8181: 'new' cannot be used with tuple type. Use a tuple literal expression instead. // var x = new (int, int)(1, arg); Diagnostic(ErrorCode.ERR_NewWithTupleTypeSyntax, "(int, int)").WithLocation(7, 21) ); } [Fact] public void SimpleTupleNew2() { var source = @" class C { static void Main() { var x = new (int a, int b)(1, 2); System.Console.WriteLine(x.a.ToString()); var x1 = new (int a, int b)(1, 2) { a = 3, Item2 = 4}; System.Console.WriteLine(x1.a.ToString()); var x2 = new (int a, (int b, int c) d)(1, new (int, int)(2, 3)) { a = 5, d = {b = 6, c = 7}}; System.Console.WriteLine(x2.a.ToString()); System.Console.WriteLine(x2.d.b.ToString()); System.Console.WriteLine(x2.d.c.ToString()); } } " + trivial2uple + tupleattributes_cs; var comp = CreateCompilation(source); comp.VerifyDiagnostics( // (6,21): error CS8181: 'new' cannot be used with tuple type. Use a tuple literal expression instead. // var x = new (int a, int b)(1, 2); Diagnostic(ErrorCode.ERR_NewWithTupleTypeSyntax, "(int a, int b)").WithLocation(6, 21), // (9,22): error CS8181: 'new' cannot be used with tuple type. Use a tuple literal expression instead. // var x1 = new (int a, int b)(1, 2) { a = 3, Item2 = 4}; Diagnostic(ErrorCode.ERR_NewWithTupleTypeSyntax, "(int a, int b)").WithLocation(9, 22), // (12,22): error CS8181: 'new' cannot be used with tuple type. Use a tuple literal expression instead. // var x2 = new (int a, (int b, int c) d)(1, new (int, int)(2, 3)) { a = 5, d = {b = 6, c = 7}}; Diagnostic(ErrorCode.ERR_NewWithTupleTypeSyntax, "(int a, (int b, int c) d)").WithLocation(12, 22), // (12,55): error CS8181: 'new' cannot be used with tuple type. Use a tuple literal expression instead. // var x2 = new (int a, (int b, int c) d)(1, new (int, int)(2, 3)) { a = 5, d = {b = 6, c = 7}}; Diagnostic(ErrorCode.ERR_NewWithTupleTypeSyntax, "(int, int)").WithLocation(12, 55) ); } [WorkItem(10874, "https://github.com/dotnet/roslyn/issues/10874")] [Fact] public void SimpleTupleNew3() { var source = @" class C { static void Main() { var x0 = new (int a, int b)(1, 2, 3); System.Console.WriteLine(x0.ToString()); var x1 = new (int, int)(1, 2, 3); System.Console.WriteLine(x1.ToString()); var x2 = new (int, int)(1, ""2""); System.Console.WriteLine(x2.ToString()); var x3 = new (int, int)(1); System.Console.WriteLine(x3.ToString()); var x4 = new (int, int)(1, 1) {a = 1, Item3 = 2} ; System.Console.WriteLine(x3.ToString()); } } " + trivial2uple + tupleattributes_cs; var comp = CreateCompilation(source); comp.VerifyDiagnostics( // (6,22): error CS8181: 'new' cannot be used with tuple type. Use a tuple literal expression instead. // var x0 = new (int a, int b)(1, 2, 3); Diagnostic(ErrorCode.ERR_NewWithTupleTypeSyntax, "(int a, int b)").WithLocation(6, 22), // (9,22): error CS8181: 'new' cannot be used with tuple type. Use a tuple literal expression instead. // var x1 = new (int, int)(1, 2, 3); Diagnostic(ErrorCode.ERR_NewWithTupleTypeSyntax, "(int, int)").WithLocation(9, 22), // (12,22): error CS8181: 'new' cannot be used with tuple type. Use a tuple literal expression instead. // var x2 = new (int, int)(1, "2"); Diagnostic(ErrorCode.ERR_NewWithTupleTypeSyntax, "(int, int)").WithLocation(12, 22), // (15,22): error CS8181: 'new' cannot be used with tuple type. Use a tuple literal expression instead. // var x3 = new (int, int)(1); Diagnostic(ErrorCode.ERR_NewWithTupleTypeSyntax, "(int, int)").WithLocation(15, 22), // (18,22): error CS8181: 'new' cannot be used with tuple type. Use a tuple literal expression instead. // var x4 = new (int, int)(1, 1) {a = 1, Item3 = 2} ; Diagnostic(ErrorCode.ERR_NewWithTupleTypeSyntax, "(int, int)").WithLocation(18, 22), // (18,40): error CS0117: '(int, int)' does not contain a definition for 'a' // var x4 = new (int, int)(1, 1) {a = 1, Item3 = 2} ; Diagnostic(ErrorCode.ERR_NoSuchMember, "a").WithArguments("(int, int)", "a").WithLocation(18, 40), // (18,47): error CS0117: '(int, int)' does not contain a definition for 'Item3' // var x4 = new (int, int)(1, 1) {a = 1, Item3 = 2} ; Diagnostic(ErrorCode.ERR_NoSuchMember, "Item3").WithArguments("(int, int)", "Item3").WithLocation(18, 47) ); } [Fact] public void SimpleTuple2() { var source = @" class C { static void Main() { var s = Single((a:1, b:2)); System.Console.WriteLine(s[0].b.ToString()); } static T[] Single(T x) { return new T[]{x}; } } " + trivial2uple + tupleattributes_cs; var comp = CompileAndVerify(source, expectedOutput: "2"); comp.VerifyDiagnostics(); comp.VerifyIL("C.Main", @" { // Code size 34 (0x22) .maxstack 2 IL_0000: ldc.i4.1 IL_0001: ldc.i4.2 IL_0002: newobj ""System.ValueTuple..ctor(int, int)"" IL_0007: call ""System.ValueTuple[] C.Single>(System.ValueTuple)"" IL_000c: ldc.i4.0 IL_000d: ldelema ""System.ValueTuple"" IL_0012: ldflda ""int System.ValueTuple.Item2"" IL_0017: call ""string int.ToString()"" IL_001c: call ""void System.Console.WriteLine(string)"" IL_0021: ret }"); } [Fact] public void SimpleTupleTargetTyped() { var source = @" class C { static void Main() { (object, object) x = (null, null); System.Console.WriteLine(x.ToString()); } } " + trivial2uple + tupleattributes_cs; var comp = CompileAndVerify(source, expectedOutput: "{, }"); comp.VerifyDiagnostics(); comp.VerifyIL("C.Main", @" { // Code size 28 (0x1c) .maxstack 3 .locals init (System.ValueTuple V_0) //x IL_0000: ldloca.s V_0 IL_0002: ldnull IL_0003: ldnull IL_0004: call ""System.ValueTuple..ctor(object, object)"" IL_0009: ldloca.s V_0 IL_000b: constrained. ""System.ValueTuple"" IL_0011: callvirt ""string object.ToString()"" IL_0016: call ""void System.Console.WriteLine(string)"" IL_001b: ret }"); } [Fact] public void SimpleTupleNested() { var source = @" class C { static void Main() { var x = (1, (2, (3, 4)).ToString()); System.Console.WriteLine(x.ToString()); } } " + trivial2uple + tupleattributes_cs; var comp = CompileAndVerify(source, expectedOutput: "{1, {2, {3, 4}}}"); comp.VerifyDiagnostics(); comp.VerifyIL("C.Main", @" { // Code size 54 (0x36) .maxstack 5 .locals init (System.ValueTuple V_0, //x System.ValueTuple> V_1) IL_0000: ldloca.s V_0 IL_0002: ldc.i4.1 IL_0003: ldc.i4.2 IL_0004: ldc.i4.3 IL_0005: ldc.i4.4 IL_0006: newobj ""System.ValueTuple..ctor(int, int)"" IL_000b: newobj ""System.ValueTuple>..ctor(int, System.ValueTuple)"" IL_0010: stloc.1 IL_0011: ldloca.s V_1 IL_0013: constrained. ""System.ValueTuple>"" IL_0019: callvirt ""string object.ToString()"" IL_001e: call ""System.ValueTuple..ctor(int, string)"" IL_0023: ldloca.s V_0 IL_0025: constrained. ""System.ValueTuple"" IL_002b: callvirt ""string object.ToString()"" IL_0030: call ""void System.Console.WriteLine(string)"" IL_0035: ret }"); } [Fact] public void TupleUnderlyingItemAccess() { var source = @" class C { static void Main() { var x = (1, 2); System.Console.WriteLine(x.Item2.ToString()); x.Item1 = 40; System.Console.WriteLine(x.Item1 + x.Item2); } } " + trivial2uple + tupleattributes_cs; var comp = CompileAndVerify(source, expectedOutput: @"2 42"); comp.VerifyDiagnostics(); comp.VerifyIL("C.Main", @" { // Code size 54 (0x36) .maxstack 3 .locals init (System.ValueTuple V_0) //x IL_0000: ldloca.s V_0 IL_0002: ldc.i4.1 IL_0003: ldc.i4.2 IL_0004: call ""System.ValueTuple..ctor(int, int)"" IL_0009: ldloca.s V_0 IL_000b: ldflda ""int System.ValueTuple.Item2"" IL_0010: call ""string int.ToString()"" IL_0015: call ""void System.Console.WriteLine(string)"" IL_001a: ldloca.s V_0 IL_001c: ldc.i4.s 40 IL_001e: stfld ""int System.ValueTuple.Item1"" IL_0023: ldloc.0 IL_0024: ldfld ""int System.ValueTuple.Item1"" IL_0029: ldloc.0 IL_002a: ldfld ""int System.ValueTuple.Item2"" IL_002f: add IL_0030: call ""void System.Console.WriteLine(int)"" IL_0035: ret } "); } [Fact] public void TupleUnderlyingItemAccess01() { var source = @" class C { static void Main() { var x = (a: 1, b: 2); System.Console.WriteLine(x.Item2.ToString()); x.Item1 = 40; System.Console.WriteLine(x.Item1 + x.Item2); } } " + trivial2uple + tupleattributes_cs; var comp = CompileAndVerify(source, expectedOutput: @"2 42"); comp.VerifyDiagnostics(); comp.VerifyIL("C.Main", @" { // Code size 54 (0x36) .maxstack 3 .locals init (System.ValueTuple V_0) //x IL_0000: ldloca.s V_0 IL_0002: ldc.i4.1 IL_0003: ldc.i4.2 IL_0004: call ""System.ValueTuple..ctor(int, int)"" IL_0009: ldloca.s V_0 IL_000b: ldflda ""int System.ValueTuple.Item2"" IL_0010: call ""string int.ToString()"" IL_0015: call ""void System.Console.WriteLine(string)"" IL_001a: ldloca.s V_0 IL_001c: ldc.i4.s 40 IL_001e: stfld ""int System.ValueTuple.Item1"" IL_0023: ldloc.0 IL_0024: ldfld ""int System.ValueTuple.Item1"" IL_0029: ldloc.0 IL_002a: ldfld ""int System.ValueTuple.Item2"" IL_002f: add IL_0030: call ""void System.Console.WriteLine(int)"" IL_0035: ret } "); } [Fact] public void TupleItemAccess() { var source = @" class C { static void Main() { var x = (a: 1, b: 2); System.Console.WriteLine(x.b.ToString()); x.a = 40; System.Console.WriteLine(x.a + x.b); } } " + trivial2uple + tupleattributes_cs; var comp = CompileAndVerify(source, expectedOutput: @"2 42"); comp.VerifyDiagnostics(); comp.VerifyIL("C.Main", @" { // Code size 54 (0x36) .maxstack 3 .locals init (System.ValueTuple V_0) //x IL_0000: ldloca.s V_0 IL_0002: ldc.i4.1 IL_0003: ldc.i4.2 IL_0004: call ""System.ValueTuple..ctor(int, int)"" IL_0009: ldloca.s V_0 IL_000b: ldflda ""int System.ValueTuple.Item2"" IL_0010: call ""string int.ToString()"" IL_0015: call ""void System.Console.WriteLine(string)"" IL_001a: ldloca.s V_0 IL_001c: ldc.i4.s 40 IL_001e: stfld ""int System.ValueTuple.Item1"" IL_0023: ldloc.0 IL_0024: ldfld ""int System.ValueTuple.Item1"" IL_0029: ldloc.0 IL_002a: ldfld ""int System.ValueTuple.Item2"" IL_002f: add IL_0030: call ""void System.Console.WriteLine(int)"" IL_0035: ret } "); } [Fact] public void TupleItemAccess01() { var source = @" class C { static void Main() { var x = (a: 1, b: (c: 2, d: 3)); System.Console.WriteLine(x.b.c.ToString()); x.b.d = 39; System.Console.WriteLine(x.a + x.b.c + x.b.d); } } " + trivial2uple + tupleattributes_cs; var comp = CompileAndVerify(source, expectedOutput: @"2 42"); comp.VerifyDiagnostics(); comp.VerifyIL("C.Main", @" { // Code size 87 (0x57) .maxstack 4 .locals init (System.ValueTuple> V_0) //x IL_0000: ldloca.s V_0 IL_0002: ldc.i4.1 IL_0003: ldc.i4.2 IL_0004: ldc.i4.3 IL_0005: newobj ""System.ValueTuple..ctor(int, int)"" IL_000a: call ""System.ValueTuple>..ctor(int, System.ValueTuple)"" IL_000f: ldloca.s V_0 IL_0011: ldflda ""System.ValueTuple System.ValueTuple>.Item2"" IL_0016: ldflda ""int System.ValueTuple.Item1"" IL_001b: call ""string int.ToString()"" IL_0020: call ""void System.Console.WriteLine(string)"" IL_0025: ldloca.s V_0 IL_0027: ldflda ""System.ValueTuple System.ValueTuple>.Item2"" IL_002c: ldc.i4.s 39 IL_002e: stfld ""int System.ValueTuple.Item2"" IL_0033: ldloc.0 IL_0034: ldfld ""int System.ValueTuple>.Item1"" IL_0039: ldloc.0 IL_003a: ldfld ""System.ValueTuple System.ValueTuple>.Item2"" IL_003f: ldfld ""int System.ValueTuple.Item1"" IL_0044: add IL_0045: ldloc.0 IL_0046: ldfld ""System.ValueTuple System.ValueTuple>.Item2"" IL_004b: ldfld ""int System.ValueTuple.Item2"" IL_0050: add IL_0051: call ""void System.Console.WriteLine(int)"" IL_0056: ret } "); } [Fact] public void TupleTypeDeclaration() { var source = @" class C { static void Main() { (int, string, int) x = (1, ""hello"", 2); System.Console.WriteLine(x.ToString()); } } " + trivial3uple; var comp = CompileAndVerify(source, expectedOutput: @"{1, hello, 2}"); } [Fact] [WorkItem(11281, "https://github.com/dotnet/roslyn/issues/11281")] public void TupleTypeMismatch_01() { var source = @" class C { static void Main() { (int, string) x = (1, ""hello"", 2); } } " + trivial2uple + trivial3uple + tupleattributes_cs; CreateCompilation(source).VerifyDiagnostics( // (6,27): error CS0029: Cannot implicitly convert type '(int, string, int)' to '(int, string)' // (int, string) x = (1, "hello", 2); Diagnostic(ErrorCode.ERR_NoImplicitConv, @"(1, ""hello"", 2)").WithArguments("(int, string, int)", "(int, string)").WithLocation(6, 27)); } [Fact] [WorkItem(11282, "https://github.com/dotnet/roslyn/issues/11282")] public void TupleTypeMismatch_02() { var source = @" class C { static void Main() { (int, string) x = (1, null, 2); } } " + trivial2uple + trivial3uple + tupleattributes_cs; CreateCompilation(source).VerifyDiagnostics( // (6,27): error CS8135: Tuple with 3 elements cannot be converted to type '(int, string)'. // (int, string) x = (1, null, 2); Diagnostic(ErrorCode.ERR_ConversionNotTupleCompatible, "(1, null, 2)").WithArguments("3", "(int, string)").WithLocation(6, 27) ); } [Fact] [WorkItem(11283, "https://github.com/dotnet/roslyn/issues/11283")] public void LongTupleTypeMismatch() { var source = @" class C { static void Main() { (int, int, int, int, int, int, int, int) x = (""Alice"", 2, 3, 4, 5, 6, 7, 8); (int, int, int, int, int, int, int, int) y = (1, 2, 3, 4, 5, 6, 7, 8, 9); } } "; CreateCompilationWithMscorlib40(source, references: new[] { ValueTupleRef, SystemRuntimeFacadeRef }).VerifyDiagnostics( // (6,55): error CS0029: Cannot implicitly convert type 'string' to 'int' // (int, int, int, int, int, int, int, int) x = ("Alice", 2, 3, 4, 5, 6, 7, 8); Diagnostic(ErrorCode.ERR_NoImplicitConv, @"""Alice""").WithArguments("string", "int").WithLocation(6, 55), // (7,54): error CS0029: Cannot implicitly convert type '(int, int, int, int, int, int, int, int, int)' to '(int, int, int, int, int, int, int, int)' // (int, int, int, int, int, int, int, int) y = (1, 2, 3, 4, 5, 6, 7, 8, 9); Diagnostic(ErrorCode.ERR_NoImplicitConv, "(1, 2, 3, 4, 5, 6, 7, 8, 9)").WithArguments("(int, int, int, int, int, int, int, int, int)", "(int, int, int, int, int, int, int, int)").WithLocation(7, 54) ); } [Fact] public void TupleTypeWithLateDiscoveredName() { var source = @" class C { static void Main() { (int, string a) x = (1, ""hello"", c: 2); } } " + trivial2uple + trivial3uple + tupleattributes_cs; var tree = Parse(source, options: TestOptions.Regular); var comp = CreateCompilation(tree); comp.VerifyDiagnostics( // (6,29): error CS0029: Cannot implicitly convert type '(int, string, int c)' to '(int, string a)' // (int, string a) x = (1, "hello", c: 2); Diagnostic(ErrorCode.ERR_NoImplicitConv, @"(1, ""hello"", c: 2)").WithArguments("(int, string, int c)", "(int, string a)").WithLocation(6, 29) ); var model = comp.GetSemanticModel(tree, ignoreAccessibility: false); var nodes = tree.GetCompilationUnitRoot().DescendantNodes(); var node = nodes.OfType().Single(); Assert.Equal(@"(1, ""hello"", c: 2)", node.ToString()); Assert.Equal("(System.Int32, System.String, System.Int32 c)", model.GetTypeInfo(node).Type.ToTestDisplayString()); var x = nodes.OfType().First(); var xSymbol = model.GetDeclaredSymbol(x).GetSymbol().Type; Assert.Equal("(System.Int32, System.String a)", xSymbol.ToTestDisplayString()); Assert.True(xSymbol.IsTupleType); Assert.Equal(new[] { "System.Int32", "System.String" }, xSymbol.TupleElementTypesWithAnnotations.SelectAsArray(t => t.ToTestDisplayString())); Assert.Equal(new[] { null, "a" }, xSymbol.TupleElementNames); } [Fact] public void TupleTypeDeclarationWithNames() { var source = @" class C { static void Main() { (int a, string b) x = (1, ""hello""); System.Console.WriteLine(x.a.ToString()); System.Console.WriteLine(x.b.ToString()); } } " + trivial2uple + tupleattributes_cs; var comp = CompileAndVerify(source, expectedOutput: @"1 hello"); } [Fact] public void TupleTypeWithOnlySomeNames() { var source = @" class C { static void Main() { (int, string a, int Item3) x = (1, ""hello"", 3); System.Console.WriteLine(x.Item1 + "" "" + x.Item2 + "" "" + x.a + "" "" + x.Item3); } } " + trivial2uple + trivial3uple + tupleattributes_cs; var comp = CompileAndVerify(source, expectedOutput: @"1 hello hello 3"); } [Fact] public void TupleTypeWithOnlySomeNamesInMetadata() { var source1 = @" public class C { public static (int, string b, int Item3) M() { return (1, ""hello"", 3); } } "; var source2 = @" class D { public static void Main() { var t = C.M(); System.Console.WriteLine(t.Item1 + "" "" + t.Item2 + "" "" + t.b + "" "" + t.Item3); } } "; var comp1 = CreateCompilationWithMscorlib40(source2 + source1, references: new[] { ValueTupleRef, SystemRuntimeFacadeRef }, options: TestOptions.ReleaseExe); comp1.VerifyDiagnostics(); CompileAndVerify(comp1, expectedOutput: "1 hello hello 3"); var compLib = CreateCompilationWithMscorlib40(source1, references: new[] { ValueTupleRef, SystemRuntimeFacadeRef }, options: TestOptions.ReleaseDll); compLib.VerifyDiagnostics(); var compLibCompilationRef = compLib.ToMetadataReference(); var comp2 = CreateCompilationWithMscorlib40(source2, references: new[] { ValueTupleRef, SystemRuntimeFacadeRef, compLibCompilationRef }, options: TestOptions.ReleaseExe); comp2.VerifyDiagnostics(); CompileAndVerify(comp2, expectedOutput: "1 hello hello 3"); var comp3 = CreateCompilationWithMscorlib40(source2, references: new[] { ValueTupleRef, SystemRuntimeFacadeRef, compLib.EmitToImageReference() }, options: TestOptions.ReleaseExe); comp3.VerifyDiagnostics(); CompileAndVerify(comp3, expectedOutput: "1 hello hello 3"); } [Fact] public void TupleLiteralWithOnlySomeNames() { var source = @" class C { static void Main() { (int, string, int) x = (1, b: ""hello"", Item3: 3); System.Console.WriteLine(x.Item1 + "" "" + x.Item2 + "" "" + x.Item3); } } " + trivial2uple + trivial3uple + tupleattributes_cs; var comp = CompileAndVerify(source, expectedOutput: @"1 hello 3"); } [Fact] public void TupleDictionary01() { var source = @" using System.Collections.Generic; class C { static void Main() { var k = (1, 2); var v = (a: 1, b: (c: 2, d: (e: 3, f: 4))); var d = Test(k, v); System.Console.WriteLine(d[(1, 2)].b.d.Item2); } static Dictionary Test(K key, V value) { var d = new Dictionary(); d[key] = value; return d; } } " + trivial2uple + tupleattributes_cs; var comp = CompileAndVerify(source, expectedOutput: @"4"); comp.VerifyDiagnostics(); comp.VerifyIL("C.Main", @" { // Code size 67 (0x43) .maxstack 6 .locals init (System.ValueTuple>> V_0) //v IL_0000: ldc.i4.1 IL_0001: ldc.i4.2 IL_0002: newobj ""System.ValueTuple..ctor(int, int)"" IL_0007: ldloca.s V_0 IL_0009: ldc.i4.1 IL_000a: ldc.i4.2 IL_000b: ldc.i4.3 IL_000c: ldc.i4.4 IL_000d: newobj ""System.ValueTuple..ctor(int, int)"" IL_0012: newobj ""System.ValueTuple>..ctor(int, System.ValueTuple)"" IL_0017: call ""System.ValueTuple>>..ctor(int, System.ValueTuple>)"" IL_001c: ldloc.0 IL_001d: call ""System.Collections.Generic.Dictionary, System.ValueTuple>>> C.Test, System.ValueTuple>>>(System.ValueTuple, System.ValueTuple>>)"" IL_0022: ldc.i4.1 IL_0023: ldc.i4.2 IL_0024: newobj ""System.ValueTuple..ctor(int, int)"" IL_0029: callvirt ""System.ValueTuple>> System.Collections.Generic.Dictionary, System.ValueTuple>>>.this[System.ValueTuple].get"" IL_002e: ldfld ""System.ValueTuple> System.ValueTuple>>.Item2"" IL_0033: ldfld ""System.ValueTuple System.ValueTuple>.Item2"" IL_0038: ldfld ""int System.ValueTuple.Item2"" IL_003d: call ""void System.Console.WriteLine(int)"" IL_0042: ret } "); } [Fact] public void TupleLambdaCapture01() { var source = @" using System; class C { static void Main() { Console.WriteLine(Test(42)); } public static T Test(T a) { var x = (f1: a, f2: a); Func f = () => x.f2; return f(); } } " + trivial2uple + tupleattributes_cs; var comp = CompileAndVerify(source, expectedOutput: @"42"); comp.VerifyDiagnostics(); comp.VerifyIL("C.<>c__DisplayClass1_0.b__0()", @" { // Code size 12 (0xc) .maxstack 1 IL_0000: ldarg.0 IL_0001: ldflda ""System.ValueTuple C.<>c__DisplayClass1_0.x"" IL_0006: ldfld ""T System.ValueTuple.Item2"" IL_000b: ret } "); } [Fact] public void TupleLambdaCapture02() { var source = @" using System; class C { static void Main() { Console.WriteLine(Test(42)); } public static string Test(T a) { var x = (f1: a, f2: a); Func f = () => x.ToString(); return f(); } } " + trivial2uple + tupleattributes_cs; var comp = CompileAndVerify(source, expectedOutput: @"{42, 42}"); comp.VerifyDiagnostics(); comp.VerifyIL("C.<>c__DisplayClass1_0.b__0()", @" { // Code size 18 (0x12) .maxstack 1 IL_0000: ldarg.0 IL_0001: ldflda ""System.ValueTuple C.<>c__DisplayClass1_0.x"" IL_0006: constrained. ""System.ValueTuple"" IL_000c: callvirt ""string object.ToString()"" IL_0011: ret } "); } [Fact(Skip = "https://github.com/dotnet/roslyn/issues/33615")] public void TupleLambdaCapture03() { var source = @" using System; class C { static void Main() { Console.WriteLine(Test(42)); } public static T Test(T a) { var x = (f1: a, f2: a); Func f = () => x.Test(a); return f(); } } namespace System { // struct with two values public struct ValueTuple { public T1 Item1; public T2 Item2; public ValueTuple(T1 item1, T2 item2) { this.Item1 = item1; this.Item2 = item2; } public override string ToString() { return '{' + Item1?.ToString() + "", "" + Item2?.ToString() + '}'; } public U Test(U val) { return val; } } } "; var comp = CompileAndVerify(source, targetFramework: TargetFramework.Mscorlib46Extended, expectedOutput: @"42"); comp.VerifyDiagnostics(); comp.VerifyIL("C.<>c__DisplayClass1_0.b__0()", @" { // Code size 18 (0x12) .maxstack 2 IL_0000: ldarg.0 IL_0001: ldflda ""(T f1, T f2) C.<>c__DisplayClass1_0.x"" IL_0006: ldarg.0 IL_0007: ldfld ""T C.<>c__DisplayClass1_0.a"" IL_000c: call ""T System.ValueTuple.Test(T)"" IL_0011: ret } "); } [Fact] public void TupleLambdaCapture04() { var source = @" using System; class C { static void Main() { Console.WriteLine(Test(42)); } public static T Test(T a) { var x = (f1: 1, f2: 2); Func f = () => x.Test(a); return f(); } } namespace System { // struct with two values public struct ValueTuple { public T1 Item1; public T2 Item2; public ValueTuple(T1 item1, T2 item2) { this.Item1 = item1; this.Item2 = item2; } public override string ToString() { return '{' + Item1?.ToString() + "", "" + Item2?.ToString() + '}'; } public U Test(U val) { return val; } } } "; var comp = CompileAndVerify(source, expectedOutput: @"42"); comp.VerifyDiagnostics(); comp.VerifyIL("C.<>c__DisplayClass1_0.b__0()", @" { // Code size 18 (0x12) .maxstack 2 IL_0000: ldarg.0 IL_0001: ldflda ""System.ValueTuple C.<>c__DisplayClass1_0.x"" IL_0006: ldarg.0 IL_0007: ldfld ""T C.<>c__DisplayClass1_0.a"" IL_000c: call ""T System.ValueTuple.Test(T)"" IL_0011: ret } "); } [Fact] public void TupleLambdaCapture05() { var source = @" using System; class C { static void Main() { Console.WriteLine(Test(42)); } public static T Test(T a) { var x = (f1: a, f2: a); Func f = () => x.P1; return f(); } } namespace System { public struct ValueTuple { public T1 Item1; public T2 Item2; public ValueTuple(T1 item1, T2 item2) { this.Item1 = item1; this.Item2 = item2; } public override string ToString() { return '{' + Item1?.ToString() + "", "" + Item2?.ToString() + '}'; } public T1 P1 { get { return Item1; } } } } "; var comp = CompileAndVerify(source, expectedOutput: @"42"); comp.VerifyDiagnostics(); comp.VerifyIL("C.<>c__DisplayClass1_0.b__0()", @" { // Code size 12 (0xc) .maxstack 1 IL_0000: ldarg.0 IL_0001: ldflda ""System.ValueTuple C.<>c__DisplayClass1_0.x"" IL_0006: call ""T System.ValueTuple.P1.get"" IL_000b: ret } "); } [Fact] public void TupleLambdaCapture06() { var source = @" using System; class C { static void Main() { var v1 = M1(); System.Action d1 = (int i1) => System.Console.WriteLine(i1); v1.Test(v1, d1); Test(v1); } static void Test((T1, T2) v1) { System.Action f = () => { System.Action d1 = (T1 i1) => System.Console.WriteLine(i1); System.Action d2 = (T2 i2) => System.Console.WriteLine(i2); v1.E1 += d1; v1.RaiseE1(); v1.E1 -= d1; v1.RaiseE1(); v1.E2 += d2; v1.RaiseE2(); v1.E2 -= d2; v1.RaiseE2(); }; f(); } static (int, long) M1() { return (1, 11); } } namespace System { public struct ValueTuple { public T1 Item1; public T2 Item2; public ValueTuple(T1 item1, T2 item2) { this.Item1 = item1; this.Item2 = item2; this.E1 = null; this._e2 = null; } public event System.Action E1; private System.Action _e2; public event System.Action E2 { add { _e2 += value; } remove { _e2 -= value; } } public void RaiseE1() { System.Console.WriteLine(""-""); if (E1 == null) { System.Console.WriteLine(""null""); } else { E1(Item1); } System.Console.WriteLine(""-""); } public void RaiseE2() { System.Console.WriteLine(""--""); if (_e2 == null) { System.Console.WriteLine(""null""); } else { _e2(Item2); } System.Console.WriteLine(""--""); } public void Test((S1, S2) val, System.Action d) { System.Action f= () => { val.E1 += d; System.Console.WriteLine(val.E1); val.E1(val.Item1); val.E1 -= d; System.Console.WriteLine(val.E1 == null); }; f(); } } } " + tupleattributes_cs; var comp = CompileAndVerify(source, expectedOutput: @"System.Action`1[System.Int32] 1 True - 1 - - null - -- 11 -- -- null --"); } [Fact] public void TupleAsyncCapture01() { var source = @" using System; using System.Threading.Tasks; class C { static void Main() { Console.WriteLine(Test(42).Result); } public static async Task Test(T a) { var x = (f1: a, f2: a); await Task.Yield(); return x.f1; } } " + trivial2uple + tupleattributes_cs; var verifier = CompileAndVerify(source, expectedOutput: @"42", options: TestOptions.ReleaseExe); verifier.VerifyDiagnostics(); verifier.VerifyIL("C.d__1.System.Runtime.CompilerServices.IAsyncStateMachine.MoveNext()", @" { // Code size 207 (0xcf) .maxstack 3 .locals init (int V_0, T V_1, System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter V_2, System.Runtime.CompilerServices.YieldAwaitable V_3, System.Exception V_4) IL_0000: ldarg.0 IL_0001: ldfld ""int C.d__1.<>1__state"" IL_0006: stloc.0 .try { IL_0007: ldloc.0 IL_0008: brfalse.s IL_0058 IL_000a: ldarg.0 IL_000b: ldarg.0 IL_000c: ldfld ""T C.d__1.a"" IL_0011: ldarg.0 IL_0012: ldfld ""T C.d__1.a"" IL_0017: newobj ""System.ValueTuple..ctor(T, T)"" IL_001c: stfld ""System.ValueTuple C.d__1.5__2"" IL_0021: call ""System.Runtime.CompilerServices.YieldAwaitable System.Threading.Tasks.Task.Yield()"" IL_0026: stloc.3 IL_0027: ldloca.s V_3 IL_0029: call ""System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter System.Runtime.CompilerServices.YieldAwaitable.GetAwaiter()"" IL_002e: stloc.2 IL_002f: ldloca.s V_2 IL_0031: call ""bool System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter.IsCompleted.get"" IL_0036: brtrue.s IL_0074 IL_0038: ldarg.0 IL_0039: ldc.i4.0 IL_003a: dup IL_003b: stloc.0 IL_003c: stfld ""int C.d__1.<>1__state"" IL_0041: ldarg.0 IL_0042: ldloc.2 IL_0043: stfld ""System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter C.d__1.<>u__1"" IL_0048: ldarg.0 IL_0049: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder C.d__1.<>t__builder"" IL_004e: ldloca.s V_2 IL_0050: ldarg.0 IL_0051: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.AwaitUnsafeOnCompletedd__1>(ref System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter, ref C.d__1)"" IL_0056: leave.s IL_00ce IL_0058: ldarg.0 IL_0059: ldfld ""System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter C.d__1.<>u__1"" IL_005e: stloc.2 IL_005f: ldarg.0 IL_0060: ldflda ""System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter C.d__1.<>u__1"" IL_0065: initobj ""System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter"" IL_006b: ldarg.0 IL_006c: ldc.i4.m1 IL_006d: dup IL_006e: stloc.0 IL_006f: stfld ""int C.d__1.<>1__state"" IL_0074: ldloca.s V_2 IL_0076: call ""void System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter.GetResult()"" IL_007b: ldarg.0 IL_007c: ldflda ""System.ValueTuple C.d__1.5__2"" IL_0081: ldfld ""T System.ValueTuple.Item1"" IL_0086: stloc.1 IL_0087: leave.s IL_00ae } catch System.Exception { IL_0089: stloc.s V_4 IL_008b: ldarg.0 IL_008c: ldc.i4.s -2 IL_008e: stfld ""int C.d__1.<>1__state"" IL_0093: ldarg.0 IL_0094: ldflda ""System.ValueTuple C.d__1.5__2"" IL_0099: initobj ""System.ValueTuple"" IL_009f: ldarg.0 IL_00a0: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder C.d__1.<>t__builder"" IL_00a5: ldloc.s V_4 IL_00a7: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetException(System.Exception)"" IL_00ac: leave.s IL_00ce } IL_00ae: ldarg.0 IL_00af: ldc.i4.s -2 IL_00b1: stfld ""int C.d__1.<>1__state"" IL_00b6: ldarg.0 IL_00b7: ldflda ""System.ValueTuple C.d__1.5__2"" IL_00bc: initobj ""System.ValueTuple"" IL_00c2: ldarg.0 IL_00c3: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder C.d__1.<>t__builder"" IL_00c8: ldloc.1 IL_00c9: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetResult(T)"" IL_00ce: ret } "); } [Fact] public void TupleAsyncCapture02() { var source = @" using System; using System.Threading.Tasks; class C { static void Main() { Console.WriteLine(Test(42).Result); } public static async Task Test(T a) { var x = (f1: a, f2: a); await Task.Yield(); return x.ToString(); } } " + trivial2uple + tupleattributes_cs; var verifier = CompileAndVerify(source, expectedOutput: @"{42, 42}", options: TestOptions.ReleaseExe); verifier.VerifyDiagnostics(); verifier.VerifyIL("C.d__1.System.Runtime.CompilerServices.IAsyncStateMachine.MoveNext()", @" { // Code size 213 (0xd5) .maxstack 3 .locals init (int V_0, string V_1, System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter V_2, System.Runtime.CompilerServices.YieldAwaitable V_3, System.Exception V_4) IL_0000: ldarg.0 IL_0001: ldfld ""int C.d__1.<>1__state"" IL_0006: stloc.0 .try { IL_0007: ldloc.0 IL_0008: brfalse.s IL_0058 IL_000a: ldarg.0 IL_000b: ldarg.0 IL_000c: ldfld ""T C.d__1.a"" IL_0011: ldarg.0 IL_0012: ldfld ""T C.d__1.a"" IL_0017: newobj ""System.ValueTuple..ctor(T, T)"" IL_001c: stfld ""System.ValueTuple C.d__1.5__2"" IL_0021: call ""System.Runtime.CompilerServices.YieldAwaitable System.Threading.Tasks.Task.Yield()"" IL_0026: stloc.3 IL_0027: ldloca.s V_3 IL_0029: call ""System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter System.Runtime.CompilerServices.YieldAwaitable.GetAwaiter()"" IL_002e: stloc.2 IL_002f: ldloca.s V_2 IL_0031: call ""bool System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter.IsCompleted.get"" IL_0036: brtrue.s IL_0074 IL_0038: ldarg.0 IL_0039: ldc.i4.0 IL_003a: dup IL_003b: stloc.0 IL_003c: stfld ""int C.d__1.<>1__state"" IL_0041: ldarg.0 IL_0042: ldloc.2 IL_0043: stfld ""System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter C.d__1.<>u__1"" IL_0048: ldarg.0 IL_0049: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder C.d__1.<>t__builder"" IL_004e: ldloca.s V_2 IL_0050: ldarg.0 IL_0051: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.AwaitUnsafeOnCompletedd__1>(ref System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter, ref C.d__1)"" IL_0056: leave.s IL_00d4 IL_0058: ldarg.0 IL_0059: ldfld ""System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter C.d__1.<>u__1"" IL_005e: stloc.2 IL_005f: ldarg.0 IL_0060: ldflda ""System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter C.d__1.<>u__1"" IL_0065: initobj ""System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter"" IL_006b: ldarg.0 IL_006c: ldc.i4.m1 IL_006d: dup IL_006e: stloc.0 IL_006f: stfld ""int C.d__1.<>1__state"" IL_0074: ldloca.s V_2 IL_0076: call ""void System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter.GetResult()"" IL_007b: ldarg.0 IL_007c: ldflda ""System.ValueTuple C.d__1.5__2"" IL_0081: constrained. ""System.ValueTuple"" IL_0087: callvirt ""string object.ToString()"" IL_008c: stloc.1 IL_008d: leave.s IL_00b4 } catch System.Exception { IL_008f: stloc.s V_4 IL_0091: ldarg.0 IL_0092: ldc.i4.s -2 IL_0094: stfld ""int C.d__1.<>1__state"" IL_0099: ldarg.0 IL_009a: ldflda ""System.ValueTuple C.d__1.5__2"" IL_009f: initobj ""System.ValueTuple"" IL_00a5: ldarg.0 IL_00a6: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder C.d__1.<>t__builder"" IL_00ab: ldloc.s V_4 IL_00ad: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetException(System.Exception)"" IL_00b2: leave.s IL_00d4 } IL_00b4: ldarg.0 IL_00b5: ldc.i4.s -2 IL_00b7: stfld ""int C.d__1.<>1__state"" IL_00bc: ldarg.0 IL_00bd: ldflda ""System.ValueTuple C.d__1.5__2"" IL_00c2: initobj ""System.ValueTuple"" IL_00c8: ldarg.0 IL_00c9: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder C.d__1.<>t__builder"" IL_00ce: ldloc.1 IL_00cf: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetResult(string)"" IL_00d4: ret } "); } [Fact(Skip = "https://github.com/dotnet/roslyn/issues/33615")] public void TupleAsyncCapture03() { var source = @" using System; using System.Threading.Tasks; class C { static void Main() { Console.WriteLine(Test(42).Result); } public static async Task Test(T a) { var x = (f1: a, f2: a); await Task.Yield(); return x.Test(a); } } namespace System { // struct with two values public struct ValueTuple { public T1 Item1; public T2 Item2; public ValueTuple(T1 item1, T2 item2) { this.Item1 = item1; this.Item2 = item2; } public override string ToString() { return '{' + Item1?.ToString() + "", "" + Item2?.ToString() + '}'; } public U Test(U val) { return val; } } } "; var verifier = CompileAndVerify(source, targetFramework: TargetFramework.Mscorlib46Extended, expectedOutput: @"42", options: TestOptions.ReleaseExe); verifier.VerifyDiagnostics(); verifier.VerifyIL("C.d__1.System.Runtime.CompilerServices.IAsyncStateMachine.MoveNext()", @" { // Code size 189 (0xbd) .maxstack 3 .locals init (int V_0, T V_1, System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter V_2, System.Runtime.CompilerServices.YieldAwaitable V_3, System.Exception V_4) IL_0000: ldarg.0 IL_0001: ldfld ""int C.d__1.<>1__state"" IL_0006: stloc.0 .try { IL_0007: ldloc.0 IL_0008: brfalse.s IL_0058 IL_000a: ldarg.0 IL_000b: ldarg.0 IL_000c: ldfld ""T C.d__1.a"" IL_0011: ldarg.0 IL_0012: ldfld ""T C.d__1.a"" IL_0017: newobj ""System.ValueTuple..ctor(T, T)"" IL_001c: stfld ""(T f1, T f2) C.d__1.5__2"" IL_0021: call ""System.Runtime.CompilerServices.YieldAwaitable System.Threading.Tasks.Task.Yield()"" IL_0026: stloc.3 IL_0027: ldloca.s V_3 IL_0029: call ""System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter System.Runtime.CompilerServices.YieldAwaitable.GetAwaiter()"" IL_002e: stloc.2 IL_002f: ldloca.s V_2 IL_0031: call ""bool System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter.IsCompleted.get"" IL_0036: brtrue.s IL_0074 IL_0038: ldarg.0 IL_0039: ldc.i4.0 IL_003a: dup IL_003b: stloc.0 IL_003c: stfld ""int C.d__1.<>1__state"" IL_0041: ldarg.0 IL_0042: ldloc.2 IL_0043: stfld ""System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter C.d__1.<>u__1"" IL_0048: ldarg.0 IL_0049: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder C.d__1.<>t__builder"" IL_004e: ldloca.s V_2 IL_0050: ldarg.0 IL_0051: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.AwaitUnsafeOnCompletedd__1>(ref System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter, ref C.d__1)"" IL_0056: leave.s IL_00bc IL_0058: ldarg.0 IL_0059: ldfld ""System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter C.d__1.<>u__1"" IL_005e: stloc.2 IL_005f: ldarg.0 IL_0060: ldflda ""System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter C.d__1.<>u__1"" IL_0065: initobj ""System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter"" IL_006b: ldarg.0 IL_006c: ldc.i4.m1 IL_006d: dup IL_006e: stloc.0 IL_006f: stfld ""int C.d__1.<>1__state"" IL_0074: ldloca.s V_2 IL_0076: call ""void System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter.GetResult()"" IL_007b: ldarg.0 IL_007c: ldflda ""(T f1, T f2) C.d__1.5__2"" IL_0081: ldarg.0 IL_0082: ldfld ""T C.d__1.a"" IL_0087: call ""T System.ValueTuple.Test(T)"" IL_008c: stloc.1 IL_008d: leave.s IL_00a8 } catch System.Exception { IL_008f: stloc.s V_4 IL_0091: ldarg.0 IL_0092: ldc.i4.s -2 IL_0094: stfld ""int C.d__1.<>1__state"" IL_0099: ldarg.0 IL_009a: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder C.d__1.<>t__builder"" IL_009f: ldloc.s V_4 IL_00a1: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetException(System.Exception)"" IL_00a6: leave.s IL_00bc } IL_00a8: ldarg.0 IL_00a9: ldc.i4.s -2 IL_00ab: stfld ""int C.d__1.<>1__state"" IL_00b0: ldarg.0 IL_00b1: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder C.d__1.<>t__builder"" IL_00b6: ldloc.1 IL_00b7: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetResult(T)"" IL_00bc: ret } "); } [Fact] public void TupleAsyncCapture04() { var source = @" using System; using System.Threading.Tasks; class C { static void Main() { Console.WriteLine(Test(42).Result); } public static async Task Test(T a) { var x = (f1: 1, f2: 2); await Task.Yield(); return x.Test(a); } } namespace System { // struct with two values public struct ValueTuple { public T1 Item1; public T2 Item2; public ValueTuple(T1 item1, T2 item2) { this.Item1 = item1; this.Item2 = item2; } public override string ToString() { return '{' + Item1?.ToString() + "", "" + Item2?.ToString() + '}'; } public U Test(U val) { return val; } } } "; var verifier = CompileAndVerify(source, expectedOutput: @"42", options: TestOptions.ReleaseExe); verifier.VerifyDiagnostics(); verifier.VerifyIL("C.d__1.System.Runtime.CompilerServices.IAsyncStateMachine.MoveNext()", @" { // Code size 179 (0xb3) .maxstack 3 .locals init (int V_0, T V_1, System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter V_2, System.Runtime.CompilerServices.YieldAwaitable V_3, System.Exception V_4) IL_0000: ldarg.0 IL_0001: ldfld ""int C.d__1.<>1__state"" IL_0006: stloc.0 .try { IL_0007: ldloc.0 IL_0008: brfalse.s IL_004e IL_000a: ldarg.0 IL_000b: ldc.i4.1 IL_000c: ldc.i4.2 IL_000d: newobj ""System.ValueTuple..ctor(int, int)"" IL_0012: stfld ""System.ValueTuple C.d__1.5__2"" IL_0017: call ""System.Runtime.CompilerServices.YieldAwaitable System.Threading.Tasks.Task.Yield()"" IL_001c: stloc.3 IL_001d: ldloca.s V_3 IL_001f: call ""System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter System.Runtime.CompilerServices.YieldAwaitable.GetAwaiter()"" IL_0024: stloc.2 IL_0025: ldloca.s V_2 IL_0027: call ""bool System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter.IsCompleted.get"" IL_002c: brtrue.s IL_006a IL_002e: ldarg.0 IL_002f: ldc.i4.0 IL_0030: dup IL_0031: stloc.0 IL_0032: stfld ""int C.d__1.<>1__state"" IL_0037: ldarg.0 IL_0038: ldloc.2 IL_0039: stfld ""System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter C.d__1.<>u__1"" IL_003e: ldarg.0 IL_003f: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder C.d__1.<>t__builder"" IL_0044: ldloca.s V_2 IL_0046: ldarg.0 IL_0047: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.AwaitUnsafeOnCompletedd__1>(ref System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter, ref C.d__1)"" IL_004c: leave.s IL_00b2 IL_004e: ldarg.0 IL_004f: ldfld ""System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter C.d__1.<>u__1"" IL_0054: stloc.2 IL_0055: ldarg.0 IL_0056: ldflda ""System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter C.d__1.<>u__1"" IL_005b: initobj ""System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter"" IL_0061: ldarg.0 IL_0062: ldc.i4.m1 IL_0063: dup IL_0064: stloc.0 IL_0065: stfld ""int C.d__1.<>1__state"" IL_006a: ldloca.s V_2 IL_006c: call ""void System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter.GetResult()"" IL_0071: ldarg.0 IL_0072: ldflda ""System.ValueTuple C.d__1.5__2"" IL_0077: ldarg.0 IL_0078: ldfld ""T C.d__1.a"" IL_007d: call ""T System.ValueTuple.Test(T)"" IL_0082: stloc.1 IL_0083: leave.s IL_009e } catch System.Exception { IL_0085: stloc.s V_4 IL_0087: ldarg.0 IL_0088: ldc.i4.s -2 IL_008a: stfld ""int C.d__1.<>1__state"" IL_008f: ldarg.0 IL_0090: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder C.d__1.<>t__builder"" IL_0095: ldloc.s V_4 IL_0097: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetException(System.Exception)"" IL_009c: leave.s IL_00b2 } IL_009e: ldarg.0 IL_009f: ldc.i4.s -2 IL_00a1: stfld ""int C.d__1.<>1__state"" IL_00a6: ldarg.0 IL_00a7: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder C.d__1.<>t__builder"" IL_00ac: ldloc.1 IL_00ad: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetResult(T)"" IL_00b2: ret } "); } [Fact] public void TupleAsyncCapture05() { var source = @" using System; using System.Threading.Tasks; class C { static void Main() { Console.WriteLine(Test(42).Result); } public static async Task Test(T a) { var x = (f1: a, f2: a); await Task.Yield(); return x.P1; } } namespace System { public struct ValueTuple { public T1 Item1; public T2 Item2; public ValueTuple(T1 item1, T2 item2) { this.Item1 = item1; this.Item2 = item2; } public override string ToString() { return '{' + Item1?.ToString() + "", "" + Item2?.ToString() + '}'; } public T1 P1 { get { return Item1; } } } } "; var verifier = CompileAndVerify(source, expectedOutput: @"42", options: TestOptions.ReleaseExe); verifier.VerifyDiagnostics(); } [Fact] public void TupleAsyncCapture06() { var source = @" using System; using System.Threading.Tasks; class C { static void Main() { var v1 = M1(); System.Action d1 = (int i1) => System.Console.WriteLine(i1); v1.Test(v1, d1).Wait(); Test(v1).Wait(); } static async Task Test((T1, T2) v1) { System.Action d1 = (T1 i1) => System.Console.WriteLine(i1); System.Action d2 = (T2 i2) => System.Console.WriteLine(i2); await Task.Yield(); v1.E1 += d1; v1.RaiseE1(); v1.E1 -= d1; v1.RaiseE1(); v1.E2 += d2; v1.RaiseE2(); v1.E2 -= d2; v1.RaiseE2(); } static (int, long) M1() { return (1, 11); } } namespace System { public struct ValueTuple { public T1 Item1; public T2 Item2; public ValueTuple(T1 item1, T2 item2) { this.Item1 = item1; this.Item2 = item2; this.E1 = null; this._e2 = null; } public event System.Action E1; private System.Action _e2; public event System.Action E2 { add { _e2 += value; } remove { _e2 -= value; } } public void RaiseE1() { System.Console.WriteLine(""-""); if (E1 == null) { System.Console.WriteLine(""null""); } else { E1(Item1); } System.Console.WriteLine(""-""); } public void RaiseE2() { System.Console.WriteLine(""--""); if (_e2 == null) { System.Console.WriteLine(""null""); } else { _e2(Item2); } System.Console.WriteLine(""--""); } public async Task Test((S1, S2) val, System.Action d) { d = d; await Task.Yield(); val.E1 += d; System.Console.WriteLine(val.E1); val.E1(val.Item1); val.E1 -= d; System.Console.WriteLine(val.E1 == null); } } } " + tupleattributes_cs; var comp = CompileAndVerify(source, expectedOutput: @"System.Action`1[System.Int32] 1 True - 1 - - null - -- 11 -- -- null --"); } [Fact] public void LongTupleWithSubstitution() { var source = @" using System; using System.Threading.Tasks; class C { static void Main() { Console.WriteLine(Test(42).Result); } public static async Task Test(T a) { var x = (f1: 1, f2: 2, f3: 3, f4: 4, f5: 5, f6: 6, f7: 7, f8: a); await Task.Yield(); return x.f8; } } " + trivial2uple + trivial3uple + trivialRemainingTuples + tupleattributes_cs; CompileAndVerify(source, expectedOutput: @"42", targetFramework: TargetFramework.Mscorlib46, options: TestOptions.ReleaseExe); } [Fact] public void TupleUsageWithoutTupleLibrary() { var source = @" class C { static void Main() { (int, string) x = (1, ""hello""); } } "; var comp = CreateCompilationWithMscorlib40(source); comp.VerifyDiagnostics( // (6,9): error CS8179: Predefined type 'System.ValueTuple`2' is not defined or imported // (int, string) x = (1, "hello"); Diagnostic(ErrorCode.ERR_PredefinedValueTupleTypeNotFound, "(int, string)").WithArguments("System.ValueTuple`2").WithLocation(6, 9), // (6,27): error CS8179: Predefined type 'System.ValueTuple`2' is not defined or imported // (int, string) x = (1, "hello"); Diagnostic(ErrorCode.ERR_PredefinedValueTupleTypeNotFound, @"(1, ""hello"")").WithArguments("System.ValueTuple`2").WithLocation(6, 27) ); } [Fact] public void TupleUsageWithMissingTupleMembers() { var source = @" namespace System { public struct ValueTuple { } } class C { static void Main() { (int, int) x = (1, 2); } } "; var comp = CreateCompilationWithMscorlib40(source, assemblyName: "comp"); comp.VerifyEmitDiagnostics( // (11,20): warning CS0219: The variable 'x' is assigned but its value is never used // (int, int) x = (1, 2); Diagnostic(ErrorCode.WRN_UnreferencedVarAssg, "x").WithArguments("x").WithLocation(11, 20), // (11,24): error CS8128: Member '.ctor' was not found on type '(T1, T2)' from assembly 'comp, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'. // (int, int) x = (1, 2); Diagnostic(ErrorCode.ERR_PredefinedTypeMemberNotFoundInAssembly, "(1, 2)").WithArguments(".ctor", "(T1, T2)", "comp, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null").WithLocation(11, 24) ); } [Fact] public void TupleWithDuplicateNames() { var source = @" class C { static void Main() { (int a, string a) x = (b: 1, b: ""hello"", b: 2); } } " + trivial2uple + trivial3uple + tupleattributes_cs; var comp = CreateCompilation(source); comp.VerifyDiagnostics( // (6,24): error CS8127: Tuple member names must be unique. // (int a, string a) x = (b: 1, b: "hello", b: 2); Diagnostic(ErrorCode.ERR_TupleDuplicateElementName, "a").WithLocation(6, 24), // (6,38): error CS8127: Tuple member names must be unique. // (int a, string a) x = (b: 1, b: "hello", b: 2); Diagnostic(ErrorCode.ERR_TupleDuplicateElementName, "b").WithLocation(6, 38), // (6,50): error CS8127: Tuple member names must be unique. // (int a, string a) x = (b: 1, b: "hello", b: 2); Diagnostic(ErrorCode.ERR_TupleDuplicateElementName, "b").WithLocation(6, 50) ); } [Fact] public void TupleWithDuplicateReservedNames() { var source = @" class C { static void Main() { (int Item1, string Item1) x = (Item1: 1, Item1: ""hello""); (int Item2, string Item2) y = (Item2: 1, Item2: ""hello""); } } " + trivial2uple + tupleattributes_cs; var comp = CreateCompilation(source); comp.VerifyDiagnostics( // (6,28): error CS8125: Tuple member name 'Item1' is only allowed at position 1. // (int Item1, string Item1) x = (Item1: 1, Item1: "hello"); Diagnostic(ErrorCode.ERR_TupleReservedElementName, "Item1").WithArguments("Item1", "1").WithLocation(6, 28), // (6,50): error CS8125: Tuple member name 'Item1' is only allowed at position 1. // (int Item1, string Item1) x = (Item1: 1, Item1: "hello"); Diagnostic(ErrorCode.ERR_TupleReservedElementName, "Item1").WithArguments("Item1", "1").WithLocation(6, 50), // (7,14): error CS8125: Tuple member name 'Item2' is only allowed at position 2. // (int Item2, string Item2) y = (Item2: 1, Item2: "hello"); Diagnostic(ErrorCode.ERR_TupleReservedElementName, "Item2").WithArguments("Item2", "2").WithLocation(7, 14), // (7,40): error CS8125: Tuple member name 'Item2' is only allowed at position 2. // (int Item2, string Item2) y = (Item2: 1, Item2: "hello"); Diagnostic(ErrorCode.ERR_TupleReservedElementName, "Item2").WithArguments("Item2", "2").WithLocation(7, 40) ); } [Fact] public void TupleWithNonReservedNames() { var source = @" class C { static void Main() { (int Item1, int Item01, int Item10) x = (Item01: 1, Item1: 2, Item10: 3); } } "; var comp = CreateCompilation(source); comp.VerifyDiagnostics( // (6,37): error CS8125: Tuple member name 'Item10' is only allowed at position 10. // (int Item1, int Item01, int Item10) x = (Item01: 1, Item1: 2, Item10: 3); Diagnostic(ErrorCode.ERR_TupleReservedElementName, "Item10").WithArguments("Item10", "10").WithLocation(6, 37), // (6,61): error CS8125: Tuple member name 'Item1' is only allowed at position 1. // (int Item1, int Item01, int Item10) x = (Item01: 1, Item1: 2, Item10: 3); Diagnostic(ErrorCode.ERR_TupleReservedElementName, "Item1").WithArguments("Item1", "1").WithLocation(6, 61), // (6,71): error CS8125: Tuple member name 'Item10' is only allowed at position 10. // (int Item1, int Item01, int Item10) x = (Item01: 1, Item1: 2, Item10: 3); Diagnostic(ErrorCode.ERR_TupleReservedElementName, "Item10").WithArguments("Item10", "10").WithLocation(6, 71) ); } [Fact] public void DefaultValueForTuple() { var source = @" class C { static void Main() { (int a, string b) x = (1, ""hello""); x = default((int, string)); System.Console.WriteLine(x.a); System.Console.WriteLine(x.b ?? ""null""); } } " + trivial2uple + tupleattributes_cs; var comp = CompileAndVerify(source, expectedOutput: @"0 null"); } [Fact] public void TupleWithDuplicateMemberNames() { var source = @" class C { static void Main() { (int a, string a) x = (b: 1, c: ""hello"", b: 2); } } " + trivial2uple + trivial3uple + tupleattributes_cs; var comp = CreateCompilation(source); comp.VerifyDiagnostics( // (6,24): error CS8127: Tuple member names must be unique. // (int a, string a) x = (b: 1, c: "hello", b: 2); Diagnostic(ErrorCode.ERR_TupleDuplicateElementName, "a").WithLocation(6, 24), // (6,50): error CS8127: Tuple member names must be unique. // (int a, string a) x = (b: 1, c: "hello", b: 2); Diagnostic(ErrorCode.ERR_TupleDuplicateElementName, "b").WithLocation(6, 50) ); } [Fact] public void TupleWithReservedMemberNames() { var source = @" class C { static void Main() { (int Item1, string Item3, string Item2, int Item4, int Item5, int Item6, int Item7, string Rest) x = (Item2: ""bad"", Item4: ""bad"", Item3: 3, Item4: 4, Item5: 5, Item6: 6, Item7: 7, Rest: ""bad""); } } "; var comp = CreateCompilation(source); comp.VerifyDiagnostics( // (6,28): error CS8125: Tuple member name 'Item3' is only allowed at position 3. // (int Item1, string Item3, string Item2, int Item4, int Item5, int Item6, int Item7, string Rest) x = (Item2: "bad", Item4: "bad", Item3: 3, Item4: 4, Item5: 5, Item6: 6, Item7: 7, Rest: "bad"); Diagnostic(ErrorCode.ERR_TupleReservedElementName, "Item3").WithArguments("Item3", "3").WithLocation(6, 28), // (6,42): error CS8125: Tuple member name 'Item2' is only allowed at position 2. // (int Item1, string Item3, string Item2, int Item4, int Item5, int Item6, int Item7, string Rest) x = (Item2: "bad", Item4: "bad", Item3: 3, Item4: 4, Item5: 5, Item6: 6, Item7: 7, Rest: "bad"); Diagnostic(ErrorCode.ERR_TupleReservedElementName, "Item2").WithArguments("Item2", "2").WithLocation(6, 42), // (6,100): error CS8126: Tuple member name 'Rest' is disallowed at any position. // (int Item1, string Item3, string Item2, int Item4, int Item5, int Item6, int Item7, string Rest) x = (Item2: "bad", Item4: "bad", Item3: 3, Item4: 4, Item5: 5, Item6: 6, Item7: 7, Rest: "bad"); Diagnostic(ErrorCode.ERR_TupleReservedElementNameAnyPosition, "Rest").WithArguments("Rest").WithLocation(6, 100), // (6,111): error CS8125: Tuple member name 'Item2' is only allowed at position 2. // (int Item1, string Item3, string Item2, int Item4, int Item5, int Item6, int Item7, string Rest) x = (Item2: "bad", Item4: "bad", Item3: 3, Item4: 4, Item5: 5, Item6: 6, Item7: 7, Rest: "bad"); Diagnostic(ErrorCode.ERR_TupleReservedElementName, "Item2").WithArguments("Item2", "2").WithLocation(6, 111), // (6,125): error CS8125: Tuple member name 'Item4' is only allowed at position 4. // (int Item1, string Item3, string Item2, int Item4, int Item5, int Item6, int Item7, string Rest) x = (Item2: "bad", Item4: "bad", Item3: 3, Item4: 4, Item5: 5, Item6: 6, Item7: 7, Rest: "bad"); Diagnostic(ErrorCode.ERR_TupleReservedElementName, "Item4").WithArguments("Item4", "4").WithLocation(6, 125), // (6,189): error CS8126: Tuple member name 'Rest' is disallowed at any position. // (int Item1, string Item3, string Item2, int Item4, int Item5, int Item6, int Item7, string Rest) x = (Item2: "bad", Item4: "bad", Item3: 3, Item4: 4, Item5: 5, Item6: 6, Item7: 7, Rest: "bad"); Diagnostic(ErrorCode.ERR_TupleReservedElementNameAnyPosition, "Rest").WithArguments("Rest").WithLocation(6, 189) ); } [Fact] public void TupleWithExistingUnderlyingMemberNames() { var source = @" class C { static void Main() { var x = (CompareTo: 2, Create: 3, Deconstruct: 4, Equals: 5, GetHashCode: 6, Rest: 8, ToString: 10); } } "; var comp = CreateCompilation(source); comp.VerifyDiagnostics( // (6,18): error CS8126: Tuple member name 'CompareTo' is disallowed at any position. // var x = (CompareTo: 2, Create: 3, Deconstruct: 4, Equals: 5, GetHashCode: 6, Rest: 8, ToString: 10); Diagnostic(ErrorCode.ERR_TupleReservedElementNameAnyPosition, "CompareTo").WithArguments("CompareTo").WithLocation(6, 18), // (6,43): error CS8126: Tuple member name 'Deconstruct' is disallowed at any position. // var x = (CompareTo: 2, Create: 3, Deconstruct: 4, Equals: 5, GetHashCode: 6, Rest: 8, ToString: 10); Diagnostic(ErrorCode.ERR_TupleReservedElementNameAnyPosition, "Deconstruct").WithArguments("Deconstruct").WithLocation(6, 43), // (6,59): error CS8126: Tuple member name 'Equals' is disallowed at any position. // var x = (CompareTo: 2, Create: 3, Deconstruct: 4, Equals: 5, GetHashCode: 6, Rest: 8, ToString: 10); Diagnostic(ErrorCode.ERR_TupleReservedElementNameAnyPosition, "Equals").WithArguments("Equals").WithLocation(6, 59), // (6,70): error CS8126: Tuple member name 'GetHashCode' is disallowed at any position. // var x = (CompareTo: 2, Create: 3, Deconstruct: 4, Equals: 5, GetHashCode: 6, Rest: 8, ToString: 10); Diagnostic(ErrorCode.ERR_TupleReservedElementNameAnyPosition, "GetHashCode").WithArguments("GetHashCode").WithLocation(6, 70), // (6,86): error CS8126: Tuple member name 'Rest' is disallowed at any position. // var x = (CompareTo: 2, Create: 3, Deconstruct: 4, Equals: 5, GetHashCode: 6, Rest: 8, ToString: 10); Diagnostic(ErrorCode.ERR_TupleReservedElementNameAnyPosition, "Rest").WithArguments("Rest").WithLocation(6, 86), // (6,95): error CS8126: Tuple member name 'ToString' is disallowed at any position. // var x = (CompareTo: 2, Create: 3, Deconstruct: 4, Equals: 5, GetHashCode: 6, Rest: 8, ToString: 10); Diagnostic(ErrorCode.ERR_TupleReservedElementNameAnyPosition, "ToString").WithArguments("ToString").WithLocation(6, 95) ); } [Fact] public void TupleWithExistingInaccessibleUnderlyingMemberNames() { var source = @" class C { static void Main() { var x = (CombineHashCodes: 1, Create: 2, GetHashCodeCore: 3, Size: 4, ToStringEnd: 5); System.Console.WriteLine(x.CombineHashCodes + "" "" + x.Create + "" "" + x.GetHashCodeCore + "" "" + x.Size + "" "" + x.ToStringEnd); } } "; var verifier = CompileAndVerify(source, expectedOutput: @"1 2 3 4 5"); verifier.VerifyDiagnostics(); } [ConditionalFact(typeof(DesktopOnly))] public void LongTupleDeclaration() { var source = @" class C { static void Main() { (int, int, int, int, int, int, int, string, int, int, int, int) x = (1, 2, 3, 4, 5, 6, 7, ""Alice"", 2, 3, 4, 5); System.Console.WriteLine($""{x.Item1} {x.Item2} {x.Item3} {x.Item4} {x.Item5} {x.Item6} {x.Item7} {x.Item8} {x.Item9} {x.Item10} {x.Item11} {x.Item12}""); } } " + trivial2uple + trivial3uple + trivialRemainingTuples + tupleattributes_cs; Action validator = module => { var sourceModule = (SourceModuleSymbol)module; var compilation = sourceModule.DeclaringCompilation; var tree = compilation.SyntaxTrees.First(); var model = compilation.GetSemanticModel(tree); var nodes = tree.GetCompilationUnitRoot().DescendantNodes(); var x = nodes.OfType().First(); Assert.Equal("(System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, " + "System.String, System.Int32, System.Int32, System.Int32, System.Int32) x", model.GetDeclaredSymbol(x).ToTestDisplayString()); }; var verifier = CompileAndVerify(source, expectedOutput: @"1 2 3 4 5 6 7 Alice 2 3 4 5", sourceSymbolValidator: validator); verifier.VerifyDiagnostics(); } [Fact] public void LongTupleDeclarationWithNames() { var source = @" class C { static void Main() { (int a, int b, int c, int d, int e, int f, int g, string h, int i, int j, int k, int l) x = (1, 2, 3, 4, 5, 6, 7, ""Alice"", 2, 3, 4, 5); System.Console.WriteLine($""{x.a} {x.b} {x.c} {x.d} {x.e} {x.f} {x.g} {x.h} {x.i} {x.j} {x.k} {x.l}""); } } "; Action validator = module => { var sourceModule = (SourceModuleSymbol)module; var compilation = sourceModule.DeclaringCompilation; var tree = compilation.SyntaxTrees.First(); var model = compilation.GetSemanticModel(tree); var nodes = tree.GetCompilationUnitRoot().DescendantNodes(); var x = nodes.OfType().First(); Assert.Equal("(System.Int32 a, System.Int32 b, System.Int32 c, System.Int32 d, System.Int32 e, System.Int32 f, System.Int32 g, " + "System.String h, System.Int32 i, System.Int32 j, System.Int32 k, System.Int32 l) x", model.GetDeclaredSymbol(x).ToTestDisplayString()); }; var verifier = CompileAndVerify(source, expectedOutput: @"1 2 3 4 5 6 7 Alice 2 3 4 5", sourceSymbolValidator: validator); verifier.VerifyDiagnostics(); } [ConditionalFact(typeof(NoIOperationValidation))] public void HugeTupleCreationParses() { StringBuilder b = new StringBuilder(); b.Append("("); for (int i = 0; i < 3000; i++) { b.Append("1, "); } b.Append("1)"); var source = @" class C { static void Main() { var x = " + b.ToString() + @"; } } "; CreateCompilation(source); } [ConditionalFact(typeof(NoIOperationValidation))] public void HugeTupleDeclarationParses() { StringBuilder b = new StringBuilder(); b.Append("("); for (int i = 0; i < 3000; i++) { b.Append("int, "); } b.Append("int)"); var source = @" class C { static void Main() { " + b.ToString() + @" x; } } "; CreateCompilation(source); } [Fact] public void GenericTupleWithoutTupleLibrary_01() { var source = @" class C { static void Main() { var x = M(); System.Console.WriteLine($""{x.first} {x.second}""); } static (T1 first, T2 second) M() { return (default(T1), default(T2)); } } " + tupleattributes_cs; var comp = CreateCompilationWithMscorlib40(source); comp.VerifyDiagnostics( // (10,12): error CS8179: Predefined type 'System.ValueTuple`2' is not defined or imported // static (T1 first, T2 second) M() Diagnostic(ErrorCode.ERR_PredefinedValueTupleTypeNotFound, "(T1 first, T2 second)").WithArguments("System.ValueTuple`2").WithLocation(10, 12), // (12,16): error CS8179: Predefined type 'System.ValueTuple`2' is not defined or imported // return (default(T1), default(T2)); Diagnostic(ErrorCode.ERR_PredefinedValueTupleTypeNotFound, "(default(T1), default(T2))").WithArguments("System.ValueTuple`2").WithLocation(12, 16) ); var c = comp.GetTypeByMetadataName("C"); var mTuple = (NamedTypeSymbol)c.GetMember("M").ReturnType; Assert.True(mTuple.IsTupleType); Assert.Equal(TypeKind.Error, mTuple.TupleUnderlyingType.TypeKind); Assert.Equal(SymbolKind.ErrorType, mTuple.TupleUnderlyingType.Kind); Assert.IsAssignableFrom(mTuple.TupleUnderlyingType); Assert.Equal(TypeKind.Error, mTuple.TypeKind); AssertTupleTypeEquality(mTuple); Assert.False(mTuple.IsImplicitlyDeclared); Assert.Equal("Predefined type 'System.ValueTuple`2' is not defined or imported", mTuple.GetUseSiteDiagnostic().GetMessage(CultureInfo.InvariantCulture)); Assert.Null(mTuple.BaseType()); Assert.False(mTuple.TupleData.UnderlyingDefinitionToMemberMap.Any()); var mFirst = (FieldSymbol)mTuple.GetMembers("first").Single(); Assert.IsType(mFirst); Assert.Equal("first", mFirst.Name); Assert.Same(mFirst, mFirst.OriginalDefinition); Assert.True(mFirst.Equals(mFirst)); Assert.Null(mFirst.TupleUnderlyingField); Assert.Null(mFirst.AssociatedSymbol); Assert.Same(mTuple, mFirst.ContainingSymbol); Assert.True(mFirst.TypeWithAnnotations.CustomModifiers.IsEmpty); Assert.True(mFirst.GetAttributes().IsEmpty); Assert.Null(mFirst.GetUseSiteDiagnostic()); Assert.False(mFirst.Locations.IsEmpty); Assert.Equal("T1 first", mFirst.DeclaringSyntaxReferences.Single().GetSyntax().ToString()); Assert.False(mFirst.IsImplicitlyDeclared); Assert.Null(mFirst.TypeLayoutOffset); var mItem1 = (FieldSymbol)mTuple.GetMembers("Item1").Single(); Assert.IsType(mItem1); Assert.Equal("Item1", mItem1.Name); Assert.Same(mItem1, mItem1.OriginalDefinition); Assert.True(mItem1.Equals(mItem1)); Assert.Null(mItem1.TupleUnderlyingField); Assert.Null(mItem1.AssociatedSymbol); Assert.Same(mTuple, mItem1.ContainingSymbol); Assert.True(mItem1.TypeWithAnnotations.CustomModifiers.IsEmpty); Assert.True(mItem1.GetAttributes().IsEmpty); Assert.Null(mItem1.GetUseSiteDiagnostic()); Assert.True(mItem1.Locations.IsEmpty); Assert.True(mItem1.IsImplicitlyDeclared); Assert.Null(mItem1.TypeLayoutOffset); } [Fact] [WorkItem(11287, "https://github.com/dotnet/roslyn/issues/11287")] public void GenericTupleWithoutTupleLibrary_02() { var source = @" class C { static void Main() { } static (T1, T2, T3, T4, T5, T6, T7, T8, T9) M() { throw new System.NotSupportedException(); } } " + trivial2uple + tupleattributes_cs; var comp = CreateCompilationWithMscorlib40(source); comp.VerifyDiagnostics( // (8,12): error CS8179: Predefined type 'System.ValueTuple`8' is not defined or imported // static (T1, T2, T3, T4, T5, T6, T7, T8, T9) M() Diagnostic(ErrorCode.ERR_PredefinedValueTupleTypeNotFound, "(T1, T2, T3, T4, T5, T6, T7, T8, T9)").WithArguments("System.ValueTuple`8").WithLocation(8, 12) ); } [Fact] public void GenericTuple() { var source = @" class C { static void Main() { var x = M(); System.Console.WriteLine($""{x.first} {x.second}""); } static (T1 first, T2 second) M() { return (default(T1), default(T2)); } } "; var comp = CompileAndVerify(source, expectedOutput: @"0 False"); } [Fact] public void LongTupleCreation() { var source = @" class C { static void Main() { var x = (1, 2, 3, 4, 5, 6, 7, ""Alice"", 2, 3, 4, 5, 6, 7, ""Bob"", 2, 3); System.Console.WriteLine($""{x.Item1} {x.Item2} {x.Item3} {x.Item4} {x.Item5} {x.Item6} {x.Item7} {x.Item8} {x.Item9} {x.Item10} {x.Item11} {x.Item12} {x.Item13} {x.Item14} {x.Item15} {x.Item16} {x.Item17}""); } } "; Action validator = module => { var sourceModule = (SourceModuleSymbol)module; var compilation = sourceModule.DeclaringCompilation; var tree = compilation.SyntaxTrees.First(); var model = compilation.GetSemanticModel(tree); var nodes = tree.GetCompilationUnitRoot().DescendantNodes(); var node = nodes.OfType().Single(); Assert.Equal("(System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, " + "System.String, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, " + "System.String, System.Int32, System.Int32)", model.GetTypeInfo(node).Type.ToTestDisplayString()); }; var verifier = CompileAndVerifyWithMscorlib40(source, expectedOutput: @"1 2 3 4 5 6 7 Alice 2 3 4 5 6 7 Bob 2 3", references: new[] { ValueTupleRef, SystemRuntimeFacadeRef }, sourceSymbolValidator: validator); verifier.VerifyDiagnostics(); } [Fact] public void TupleInLambda() { var source = @" class C { static void Main() { System.Action<(int, string)> f = ((int, string) x) => System.Console.WriteLine($""{x.Item1} {x.Item2}""); f((42, ""Alice"")); } } "; var comp = CompileAndVerify(source, expectedOutput: @"42 Alice"); } [Fact] public void TupleWithNamesInLambda() { var source = @" class C { static void Main() { int a, b = 0; System.Action<(int, string)> f = ((int a, string b) x) => System.Console.WriteLine($""{x.a} {x.b}""); f((c: 42, d: ""Alice"")); } } "; var comp = CompileAndVerify(source, expectedOutput: @"42 Alice"); } [Fact] public void TupleInProperty() { var source = @" class C { static (int a, string b) P { get; set; } static void Main() { P = (42, ""Alice""); System.Console.WriteLine($""{P.a} {P.b}""); } } "; var comp = CompileAndVerify(source, expectedOutput: @"42 Alice"); } [Fact] public void ExtensionMethodOnTuple() { var source = @" static class C { static void Extension(this (int a, string b) x) { System.Console.WriteLine($""{x.a} {x.b}""); } static void Main() { (42, ""Alice"").Extension(); } } "; CompileAndVerify(source, targetFramework: TargetFramework.Mscorlib45, references: new[] { Net451.System, Net451.SystemCore, Net451.SystemRuntime, ValueTupleRef }, expectedOutput: @"42 Alice"); } [Fact] public void TupleInOptionalParam() { var source = @" class C { void M(int x, (int a, string b) y = (42, ""Alice"")) { } } "; CreateCompilation(source).VerifyDiagnostics( // (4,41): error CS1736: Default parameter value for 'y' must be a compile-time constant // void M(int x, (int a, string b) y = (42, "Alice")) Diagnostic(ErrorCode.ERR_DefaultValueMustBeConstant, @"(42, ""Alice"")").WithArguments("y").WithLocation(4, 41)); } [Fact] public void TupleDefaultInOptionalParam() { var source = @" class C { public static void Main() { M(); } static void M((int a, string b) x = default((int, string))) { System.Console.WriteLine($""{x.a} {x.b}""); } } "; CompileAndVerify(source, expectedOutput: @"0 "); } [Fact] public void TupleAsNamedParam() { var source = @" class C { static void Main() { M(y : (42, ""Alice""), x : 1); } static void M(int x, (int a, string b) y) { System.Console.WriteLine($""{y.a} {y.Item2}""); } } "; var comp = CompileAndVerify(source, expectedOutput: @"42 Alice"); } [Fact] public void LongTupleCreationWithNames() { var source = @" class C { static void Main() { var x = (a: 1, b: 2, c: 3, d: 4, e: 5, f: 6, g: 7, h: ""Alice"", i: 2, j: 3, k: 4, l: 5, m: 6, n: 7, o: ""Bob"", p: 2, q: 3); System.Console.WriteLine($""{x.a} {x.b} {x.c} {x.d} {x.e} {x.f} {x.g} {x.h} {x.i} {x.j} {x.k} {x.l} {x.m} {x.n} {x.o} {x.p} {x.q}""); } } "; Action validator = module => { var sourceModule = (SourceModuleSymbol)module; var compilation = sourceModule.DeclaringCompilation; var tree = compilation.SyntaxTrees.First(); var model = compilation.GetSemanticModel(tree); var nodes = tree.GetCompilationUnitRoot().DescendantNodes(); var node = nodes.OfType().Single(); Assert.Equal("(System.Int32 a, System.Int32 b, System.Int32 c, System.Int32 d, System.Int32 e, System.Int32 f, System.Int32 g, " + "System.String h, System.Int32 i, System.Int32 j, System.Int32 k, System.Int32 l, System.Int32 m, System.Int32 n, " + "System.String o, System.Int32 p, System.Int32 q)", model.GetTypeInfo(node).Type.ToTestDisplayString()); }; var verifier = CompileAndVerify(source, expectedOutput: @"1 2 3 4 5 6 7 Alice 2 3 4 5 6 7 Bob 2 3", sourceSymbolValidator: validator); verifier.VerifyDiagnostics(); } [Fact] public void TupleCreationWithInferredNamesWithCSharp7() { var source = @" class C { int e = 5; int f = 6; C instance = null; void M() { int a = 1; int b = 3; int Item4 = 4; int g = 7; int Rest = 9; (int x, int, int b, int, int, int, int f, int, int, int) y = (a, (a), b: 2, b, Item4, instance.e, this.f, g, g, Rest); var z = (x: b, b); System.Console.Write(y); System.Console.Write(z); } } "; Action validator = module => { var sourceModule = (SourceModuleSymbol)module; var compilation = sourceModule.DeclaringCompilation; var tree = compilation.SyntaxTrees.First(); var model = compilation.GetSemanticModel(tree); var nodes = tree.GetCompilationUnitRoot().DescendantNodes(); var yTuple = nodes.OfType().ElementAt(0); Assert.Equal("(System.Int32 a, System.Int32, System.Int32 b, System.Int32, System.Int32, System.Int32 e, System.Int32 f, System.Int32, System.Int32, System.Int32)", model.GetTypeInfo(yTuple).Type.ToTestDisplayString()); var zTuple = nodes.OfType().ElementAt(1); Assert.Equal("(System.Int32 x, System.Int32 b)", model.GetTypeInfo(zTuple).Type.ToTestDisplayString()); }; var verifier = CompileAndVerify(source, sourceSymbolValidator: validator); verifier.VerifyDiagnostics(); } [Fact] public void MissingMemberAccessWithCSharp7() { var source = @" class C { void M() { int a = 1; var t = (a, 2); System.Console.Write(t.a); System.Console.Write(GetTuple().a); } (int, int) GetTuple() { return (1, 2); } } "; var comp = CreateCompilationWithMscorlib40(source, references: new[] { ValueTupleRef, SystemRuntimeFacadeRef }, parseOptions: TestOptions.Regular7); comp.VerifyDiagnostics( // (8,32): error CS8305: Tuple element name 'a' is inferred. Please use language version 7.1 or greater to access an element by its inferred name. // System.Console.Write(t.a); Diagnostic(ErrorCode.ERR_TupleInferredNamesNotAvailable, "a").WithArguments("a", "7.1").WithLocation(8, 32), // (9,41): error CS1061: '(int, int)' does not contain a definition for 'a' and no extension method 'a' accepting a first argument of type '(int, int)' could be found (are you missing a using directive or an assembly reference?) // System.Console.Write(GetTuple().a); Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "a").WithArguments("(int, int)", "a").WithLocation(9, 41) ); } [Fact] public void UseSiteDiagnosticOnTupleField() { var missing_cs = @"public class Missing { }"; var lib_cs = @" public class C { public static (Missing, int) GetTuple() { throw null; } } "; var source_cs = @" class D { void M() { System.Console.Write(C.GetTuple().Item1); } }"; var missingComp = CreateCompilation(missing_cs, assemblyName: "UseSiteDiagnosticOnTupleField_missingComp"); missingComp.VerifyDiagnostics(); var libComp = CreateCompilationWithMscorlib40(lib_cs, references: new[] { ValueTupleRef, SystemRuntimeFacadeRef, missingComp.ToMetadataReference() }); libComp.VerifyDiagnostics(); var comp7 = CreateCompilationWithMscorlib40(source_cs, references: new[] { ValueTupleRef, SystemRuntimeFacadeRef, libComp.ToMetadataReference() }, parseOptions: TestOptions.Regular); comp7.VerifyDiagnostics( // (6,30): error CS0012: The type 'Missing' is defined in an assembly that is not referenced. You must add a reference to assembly 'UseSiteDiagnosticOnTupleField_missingComp, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'. // System.Console.Write(C.GetTuple().Item1); Diagnostic(ErrorCode.ERR_NoTypeDef, "C.GetTuple").WithArguments("Missing", "UseSiteDiagnosticOnTupleField_missingComp, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null"), // (6,43): error CS0012: The type 'Missing' is defined in an assembly that is not referenced. You must add a reference to assembly 'UseSiteDiagnosticOnTupleField_missingComp, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'. // System.Console.Write(C.GetTuple().Item1); Diagnostic(ErrorCode.ERR_NoTypeDef, "Item1").WithArguments("Missing", "UseSiteDiagnosticOnTupleField_missingComp, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null") ); var comp7_1 = CreateCompilationWithMscorlib40(source_cs, assemblyName: "UseSiteDiagnosticOnTupleField_comp7_1", references: new[] { ValueTupleRef, SystemRuntimeFacadeRef, libComp.ToMetadataReference() }, parseOptions: TestOptions.Regular7_1); comp7_1.VerifyDiagnostics( // (6,30): error CS0012: The type 'Missing' is defined in an assembly that is not referenced. You must add a reference to assembly 'UseSiteDiagnosticOnTupleField_missingComp, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'. // System.Console.Write(C.GetTuple().Item1); Diagnostic(ErrorCode.ERR_NoTypeDef, "C.GetTuple").WithArguments("Missing", "UseSiteDiagnosticOnTupleField_missingComp, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null"), // (6,43): error CS0012: The type 'Missing' is defined in an assembly that is not referenced. You must add a reference to assembly 'UseSiteDiagnosticOnTupleField_missingComp, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'. // System.Console.Write(C.GetTuple().Item1); Diagnostic(ErrorCode.ERR_NoTypeDef, "Item1").WithArguments("Missing", "UseSiteDiagnosticOnTupleField_missingComp, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null") ); } [Fact] public void UseSiteDiagnosticOnTupleField2() { var source_cs = @" public class C { void M() { int a = 1; var t = (a, 2); System.Console.Write(t.a); } } namespace System { public struct ValueTuple { public ValueTuple(T1 item1, T2 item2) => throw null; } } "; var comp7 = CreateCompilation(source_cs, parseOptions: TestOptions.Regular, assemblyName: "UseSiteDiagnosticOnTupleField2_comp7"); comp7.VerifyDiagnostics( // (8,32): error CS8128: Member 'Item1' was not found on type '(T1, T2)' from assembly 'UseSiteDiagnosticOnTupleField2_comp7, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'. // System.Console.Write(t.a); Diagnostic(ErrorCode.ERR_PredefinedTypeMemberNotFoundInAssembly, "a").WithArguments("Item1", "(T1, T2)", "UseSiteDiagnosticOnTupleField2_comp7, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null").WithLocation(8, 32) ); var comp7_1 = CreateCompilation(source_cs, parseOptions: TestOptions.Regular7_1, assemblyName: "UseSiteDiagnosticOnTupleField2_comp7_1"); comp7_1.VerifyDiagnostics( // (8,32): error CS8128: Member 'Item1' was not found on type '(T1, T2)' from assembly 'UseSiteDiagnosticOnTupleField2_comp7_1, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'. // System.Console.Write(t.a); Diagnostic(ErrorCode.ERR_PredefinedTypeMemberNotFoundInAssembly, "a").WithArguments("Item1", "(T1, T2)", "UseSiteDiagnosticOnTupleField2_comp7_1, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null").WithLocation(8, 32) ); } [Fact] public void MissingMemberAccessWithExtensionWithCSharp7() { var source = @" class C { void M() { int a = 1; var t = (a, 2); System.Console.Write(t.a); System.Console.Write(t.a()); System.Console.Write(GetTuple().a); } (int, int) GetTuple() { return (1, 2); } } public static class Extensions { public static string a(this (int, int) self) { return ""hello""; } } "; var comp = CreateCompilationWithMscorlib45(source, references: new[] { Net451.System, Net451.SystemCore, Net451.SystemRuntime, ValueTupleRef }, parseOptions: TestOptions.Regular7); comp.VerifyDiagnostics( // (8,32): error CS8305: Tuple element name 'a' is inferred. Please use language version 7.1 or greater to access an element by its inferred name. // System.Console.Write(t.a); Diagnostic(ErrorCode.ERR_TupleInferredNamesNotAvailable, "a").WithArguments("a", "7.1").WithLocation(8, 32), // (10,30): error CS1503: Argument 1: cannot convert from 'method group' to 'string' // System.Console.Write(GetTuple().a); Diagnostic(ErrorCode.ERR_BadArgType, "GetTuple().a").WithArguments("1", "method group", "string") ); } [Fact] public void MissingMemberAccessWithCSharp7_1() { var source = @" class C { void M() { int a = 1; var t = (a, 2); System.Console.Write(t.a); System.Console.Write(t.b); } } "; var comp = CreateCompilationWithMscorlib40(source, references: new[] { ValueTupleRef, SystemRuntimeFacadeRef }, options: TestOptions.DebugDll, parseOptions: TestOptions.Regular7_1); comp.VerifyDiagnostics( // (9,32): error CS1061: '(int a, int)' does not contain a definition for 'b' and no extension method 'b' accepting a first argument of type '(int a, int)' could be found (are you missing a using directive or an assembly reference?) // System.Console.Write(t.b); Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "b").WithArguments("(int a, int)", "b").WithLocation(9, 32) ); } [Fact] public void TupleCreationWithInferredNames() { var source = @" class C { int e = 5; int f = 6; C instance = null; string M() { int a = 1; int b = 3; int Item4 = 4; int g = 7; int Rest = 9; (int x, int, int b, int, int, int, int f, int, int, int) y = (a, (a), b: 2, b, Item4, instance.e, this.f, g, g, Rest); var z = (x: b, b); System.Console.Write(y); System.Console.Write(z); return null; } int P { set { var t = (M(), value); System.Console.Write(t.value); } } } "; Action validator = module => { var sourceModule = (SourceModuleSymbol)module; var compilation = sourceModule.DeclaringCompilation; var tree = compilation.SyntaxTrees.First(); var model = compilation.GetSemanticModel(tree); var nodes = tree.GetCompilationUnitRoot().DescendantNodes(); var yTuple = nodes.OfType().ElementAt(0); Assert.Equal("(System.Int32 a, System.Int32, System.Int32 b, System.Int32, System.Int32, System.Int32 e, System.Int32 f, System.Int32, System.Int32, System.Int32)", model.GetTypeInfo(yTuple).Type.ToTestDisplayString()); var zTuple = nodes.OfType().ElementAt(1); Assert.Equal("(System.Int32 x, System.Int32 b)", model.GetTypeInfo(zTuple).Type.ToTestDisplayString()); var tTuple = nodes.OfType().ElementAt(2); Assert.Equal("(System.String, System.Int32 value)", model.GetTypeInfo(tTuple).Type.ToTestDisplayString()); }; var verifier = CompileAndVerify(source, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp7_1), sourceSymbolValidator: validator); verifier.VerifyDiagnostics(); } [Fact] public void TupleCreationWithInferredNames2() { var source = @" class C { private int e = 5; } class C2 { C instance = null; C2 instance2 = null; int M() { var y = (instance?.e, (instance.e, instance2.M(), checked(instance.e), default(int))); System.Console.Write(y); return 42; } } "; var compilation = CreateCompilation(source, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp7_1)); compilation.VerifyDiagnostics( // (12,27): error CS0122: 'C.e' is inaccessible due to its protection level // var y = (instance?.e, (instance.e, instance2.M(), checked(instance.e), default(int))); Diagnostic(ErrorCode.ERR_BadAccess, ".e").WithArguments("C.e").WithLocation(12, 27), // (12,41): error CS0122: 'C.e' is inaccessible due to its protection level // var y = (instance?.e, (instance.e, instance2.M(), checked(instance.e), default(int))); Diagnostic(ErrorCode.ERR_BadAccess, "e").WithArguments("C.e").WithLocation(12, 41), // (12,76): error CS0122: 'C.e' is inaccessible due to its protection level // var y = (instance?.e, (instance.e, instance2.M(), checked(instance.e), default(int))); Diagnostic(ErrorCode.ERR_BadAccess, "e").WithArguments("C.e").WithLocation(12, 76), // (4,17): warning CS0414: The field 'C.e' is assigned but its value is never used // private int e = 5; Diagnostic(ErrorCode.WRN_UnreferencedFieldAssg, "e").WithArguments("C.e") ); var tree = compilation.SyntaxTrees.First(); var model = compilation.GetSemanticModel(tree); var nodes = tree.GetCompilationUnitRoot().DescendantNodes(); // The type for int? was not picked up // Follow-up issue: https://github.com/dotnet/roslyn/issues/19144 var yTuple = nodes.OfType().ElementAt(0); Assert.Equal("(? e, (System.Int32 e, System.Int32, System.Int32, System.Int32))", model.GetTypeInfo(yTuple).Type.ToTestDisplayString()); } [Fact] public void InferredNamesInLinq() { var source = @" using System.Collections.Generic; using System.Linq; class C { int f1 = 0; int f2 = 1; static void M(IEnumerable list) { var result = list.Select(c => (c.f1, c.f2)).Where(t => t.f2 == 1); // t and result have names f1 and f2 System.Console.Write(result.Count()); } } "; Action validator = module => { var sourceModule = (SourceModuleSymbol)module; var compilation = sourceModule.DeclaringCompilation; var tree = compilation.SyntaxTrees.First(); var model = compilation.GetSemanticModel(tree); var nodes = tree.GetCompilationUnitRoot().DescendantNodes(); var result = tree.GetRoot().DescendantNodes().OfType().Where(d => d.Identifier.ValueText == "result").Single(); var resultSymbol = model.GetDeclaredSymbol(result); Assert.Equal("System.Collections.Generic.IEnumerable<(System.Int32 f1, System.Int32 f2)> result", resultSymbol.ToTestDisplayString()); }; var verifier = CompileAndVerify(source, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp7_1), sourceSymbolValidator: validator); verifier.VerifyDiagnostics(); } [Fact] public void InferredNamesInTernary() { var source = @" class C { static void Main() { var i = 1; var flag = false; var t = flag ? (i, 2) : (i, 3); System.Console.Write(t.i); } } "; var verifier = CompileAndVerify(source, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp7_1), targetFramework: TargetFramework.Mscorlib46Extended, expectedOutput: "1"); verifier.VerifyDiagnostics(); } [Fact] public void InferredNames_ExtensionNowFailsInCSharp7ButNotCSharp7_1() { var source = @" using System; class C { static void Main() { Action M = () => Console.Write(""lambda""); (1, M).M(); } } static class Extension { public static void M(this (int, Action) t) => Console.Write(""extension""); } "; // When C# 7.0 shipped, no tuple element would be found/inferred, so the extension method was called. // The C# 7.1 compiler disallows that, even when LanguageVersion is 7.0 var comp7 = CreateCompilation(source, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp7)); comp7.VerifyDiagnostics( // (8,16): error CS8305: Tuple element name 'M' is inferred. Please use language version 7.1 or greater to access an element by its inferred name. // (1, M).M(); Diagnostic(ErrorCode.ERR_TupleInferredNamesNotAvailable, "M").WithArguments("M", "7.1") ); var verifier7_1 = CompileAndVerify(source, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp7_1), expectedOutput: "lambda"); verifier7_1.VerifyDiagnostics(); } [WorkItem(21518, "https://github.com/dotnet/roslyn/issues/21518")] [Fact] public void InferredName_Conversion() { var source = @"class C { static void F((object, object) t) { } static void G(object o) { var t = (1, o); F(t); } }"; var comp = CreateEmptyCompilation(source, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp7), references: new[] { MscorlibRef, ValueTupleRef, SystemRuntimeFacadeRef, SystemCoreRef }); comp.VerifyEmitDiagnostics(); } [Fact] public void LongTupleWithArgumentEvaluation() { var source = @" class C { static void Main() { var x = (a: PrintAndReturn(1), b: 2, c: 3, d: PrintAndReturn(4), e: 5, f: 6, g: PrintAndReturn(7), h: PrintAndReturn(""Alice""), i: 2, j: 3, k: 4, l: 5, m: 6, n: PrintAndReturn(7), o: PrintAndReturn(""Bob""), p: 2, q: PrintAndReturn(3)); x.ToString(); } static T PrintAndReturn(T i) { System.Console.Write(i + "" ""); return i; } } "; var verifier = CompileAndVerify(source, expectedOutput: @"1 4 7 Alice 7 Bob 3"); verifier.VerifyDiagnostics(); } [Fact] public void LongTupleGettingRest() { var source = @" class C { static void Main() { var x = (a: 1, b: 2, c: 3, d: 4, e: 5, f: 6, g: 7, h: ""Alice"", i: 1); System.Console.WriteLine($""{x.Rest.Item1} {x.Rest.Item2}""); } } "; Action validator = module => { var sourceModule = (SourceModuleSymbol)module; var compilation = sourceModule.DeclaringCompilation; var tree = compilation.SyntaxTrees.First(); var model = compilation.GetSemanticModel(tree); var nodes = tree.GetCompilationUnitRoot().DescendantNodes(); var node = nodes.OfType().Where(n => n.ToString() == "x.Rest").First(); Assert.Equal("(System.String, System.Int32)", model.GetTypeInfo(node).Type.ToTestDisplayString()); }; var verifier = CompileAndVerify(source, expectedOutput: @"Alice 1", sourceSymbolValidator: validator); verifier.VerifyDiagnostics(); } [Fact] public void MethodReturnsValueTuple() { var source = @" class C { static void Main() { System.Console.WriteLine(M().ToString()); } static (int, string) M() { return (1, ""hello""); } } "; var comp = CompileAndVerify(source, expectedOutput: @"(1, hello)"); } [Fact] public void DistinctTupleTypesInCompilation() { var source1 = @" public class C1 { public static (int a, int b) M() { return (1, 2); } } "; var source2 = @" public class C2 { public static (int c, int d) M() { return (3, 4); } } "; var source = @" class C3 { public static void Main() { System.Console.Write(C1.M().Item1 + "" ""); System.Console.Write(C1.M().a + "" ""); System.Console.Write(C1.M().Item2 + "" ""); System.Console.Write(C1.M().b + "" ""); System.Console.Write(C2.M().Item1 + "" ""); System.Console.Write(C2.M().c + "" ""); System.Console.Write(C2.M().Item2 + "" ""); System.Console.Write(C2.M().d); } } "; var comp1 = CreateCompilation(source1); comp1.VerifyDiagnostics(); var comp2 = CreateCompilation(source2); comp2.VerifyDiagnostics(); var comp = CompileAndVerify(source, expectedOutput: @"1 1 2 2 3 3 4 4", references: new[] { new CSharpCompilationReference(comp1), new CSharpCompilationReference(comp2), }); } [Fact] public void DistinctTupleTypesInCompilationCanAssign() { var source1 = @" public class C1 { public static (int a, int b) M() { System.Console.WriteLine(""C1.M""); return (1, 2); } } " + trivial2uple + tupleattributes_cs; var source2 = @" public class C2 { public static (int c, int d) M() { System.Console.WriteLine(""C2.M""); return (3, 4); } } " + trivial2uple + tupleattributes_cs; var source = @" class C3 { public static void Main() { var x = C1.M(); x = C2.M(); } } "; var comp1 = CreateCompilation(source1); comp1.VerifyDiagnostics(); var comp2 = CreateCompilation(source2); comp2.VerifyDiagnostics(); var comp = CreateCompilation(source, references: new[] { new CSharpCompilationReference(comp1), new CSharpCompilationReference(comp2) }, options: TestOptions.ReleaseExe); var v = CompileAndVerify(comp, expectedOutput: @" C1.M C2.M "); v.VerifyIL("C3.Main()", @" { // Code size 31 (0x1f) .maxstack 2 .locals init (System.ValueTuple V_0) IL_0000: call ""System.ValueTuple C1.M()"" IL_0005: pop IL_0006: call ""System.ValueTuple C2.M()"" IL_000b: stloc.0 IL_000c: ldloc.0 IL_000d: ldfld ""int System.ValueTuple.Item1"" IL_0012: ldloc.0 IL_0013: ldfld ""int System.ValueTuple.Item2"" IL_0018: newobj ""System.ValueTuple..ctor(int, int)"" IL_001d: pop IL_001e: ret } "); } [Fact] public void AmbiguousTupleTypesForCreationWithVar() { var source = @" class C3 { public static void Main() { var x = (1, 1); } } "; var comp1 = CreateCompilationWithMscorlib40(trivial2uple, assemblyName: "comp1"); var comp2 = CreateCompilationWithMscorlib40(trivial2uple, assemblyName: "comp2"); var comp = CreateCompilationWithMscorlib40(source, references: new[] { new CSharpCompilationReference(comp1), new CSharpCompilationReference(comp2) }); comp.VerifyDiagnostics( // (6,17): error CS8356: Predefined type 'System.ValueTuple`2' is declared in multiple referenced assemblies: 'comp1, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' and 'comp2, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' // var x = (1, 1); Diagnostic(ErrorCode.ERR_PredefinedValueTupleTypeAmbiguous3, "(1, 1)").WithArguments("System.ValueTuple`2", "comp1, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null", "comp2, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null").WithLocation(6, 17) ); } [Fact] public void AmbiguousTupleTypesForCreation() { var source = @" class C3 { public static void Main() { (int, int) x = (1, 1); } } "; var comp1 = CreateCompilationWithMscorlib40(trivial2uple, assemblyName: "comp1"); var comp2 = CreateCompilationWithMscorlib40(trivial2uple, assemblyName: "comp2"); var comp = CreateCompilationWithMscorlib40(source, references: new[] { new CSharpCompilationReference(comp1), new CSharpCompilationReference(comp2) }); comp.VerifyDiagnostics( // (6,9): error CS8356: Predefined type 'System.ValueTuple`2' is declared in multiple referenced assemblies: 'comp1, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' and 'comp2, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' // (int, int) x = (1, 1); Diagnostic(ErrorCode.ERR_PredefinedValueTupleTypeAmbiguous3, "(int, int)").WithArguments("System.ValueTuple`2", "comp1, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null", "comp2, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null").WithLocation(6, 9), // (6,24): error CS8356: Predefined type 'System.ValueTuple`2' is declared in multiple referenced assemblies: 'comp1, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' and 'comp2, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' // (int, int) x = (1, 1); Diagnostic(ErrorCode.ERR_PredefinedValueTupleTypeAmbiguous3, "(1, 1)").WithArguments("System.ValueTuple`2", "comp1, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null", "comp2, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null").WithLocation(6, 24) ); } [Fact] public void AmbiguousTupleTypesForDeclaration() { var source = @" class C3 { public void M((int, int) x) { } } "; var comp1 = CreateCompilationWithMscorlib40(trivial2uple, assemblyName: "comp1"); var comp2 = CreateCompilationWithMscorlib40(trivial2uple, assemblyName: "comp2"); var comp = CreateCompilationWithMscorlib40(source, references: new[] { new CSharpCompilationReference(comp1), new CSharpCompilationReference(comp2) }); comp.VerifyDiagnostics( // (4,19): error CS8356: Predefined type 'System.ValueTuple`2' is declared in multiple referenced assemblies: 'comp1, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' and 'comp2, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' // public void M((int, int) x) { } Diagnostic(ErrorCode.ERR_PredefinedValueTupleTypeAmbiguous3, "(int, int)").WithArguments("System.ValueTuple`2", "comp1, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null", "comp2, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null").WithLocation(4, 19) ); } [Fact] public void LocalTupleTypeWinsWhenTupleTypesInCompilation() { var source1 = @" public class C1 { public static (int a, int b) M() { return (1, 2); } } " + trivial2uple + tupleattributes_cs; var source2 = @" public class C2 { public static (int c, int d) M() { return (3, 4); } } " + trivial2uple + tupleattributes_cs; var source = @" class C3 { public static void Main() { System.Console.Write(C1.M().Item1 + "" ""); System.Console.Write(C1.M().a + "" ""); System.Console.Write(C1.M().Item2 + "" ""); System.Console.Write(C1.M().b + "" ""); System.Console.Write(C2.M().Item1 + "" ""); System.Console.Write(C2.M().c + "" ""); System.Console.Write(C2.M().Item2 + "" ""); System.Console.Write(C2.M().d + "" ""); var x = (e: 5, f: 6); System.Console.Write(x.Item1 + "" ""); System.Console.Write(x.e + "" ""); System.Console.Write(x.Item2 + "" ""); System.Console.Write(x.f + "" ""); System.Console.Write(x.GetType().Assembly == typeof(C3).Assembly); } } " + trivial2uple + tupleattributes_cs; var comp1 = CreateCompilationWithMscorlib40(source1); comp1.VerifyDiagnostics(); var comp2 = CreateCompilationWithMscorlib40(source2); comp2.VerifyDiagnostics(); var comp = CompileAndVerifyWithMscorlib40(source, expectedOutput: @"1 1 2 2 3 3 4 4 5 5 6 6 True", references: new[] { new CSharpCompilationReference(comp1), new CSharpCompilationReference(comp2) }); } [Fact] public void UnderlyingTypeMemberWithWrongSignature_1() { string source = @" class C { static void M() { var x = (""Alice"", ""Bob""); System.Console.WriteLine($""{x.Item1}""); } } namespace System { public struct ValueTuple { public string Item1; // Not T1 public int Item2; public ValueTuple(T1 item1, T2 item2) { this.Item1 = ""1""; this.Item2 = 2; } (T1, T2) M1() => throw null; (T1 a, T2 b) M2() => throw null; } } "; var comp = CreateCompilation(source, assemblyName: "comp"); comp.VerifyDiagnostics( // (20,18): error CS0229: Ambiguity between '(T1, T2).Item1' and '(T1, T2).Item1' // this.Item1 = "1"; Diagnostic(ErrorCode.ERR_AmbigMember, "Item1").WithArguments("(T1, T2).Item1", "(T1, T2).Item1").WithLocation(20, 18), // (21,18): error CS0229: Ambiguity between '(T1, T2).Item2' and '(T1, T2).Item2' // this.Item2 = 2; Diagnostic(ErrorCode.ERR_AmbigMember, "Item2").WithArguments("(T1, T2).Item2", "(T1, T2).Item2").WithLocation(21, 18), // (18,16): error CS0171: Field '(T1, T2).Item2' must be fully assigned before control is returned to the caller // public ValueTuple(T1 item1, T2 item2) Diagnostic(ErrorCode.ERR_UnassignedThis, "ValueTuple").WithArguments("(T1, T2).Item2").WithLocation(18, 16), // (18,16): error CS0171: Field '(T1, T2).Item2' must be fully assigned before control is returned to the caller // public ValueTuple(T1 item1, T2 item2) Diagnostic(ErrorCode.ERR_UnassignedThis, "ValueTuple").WithArguments("(T1, T2).Item2").WithLocation(18, 16), // (18,16): error CS0171: Field '(T1, T2).Item1' must be fully assigned before control is returned to the caller // public ValueTuple(T1 item1, T2 item2) Diagnostic(ErrorCode.ERR_UnassignedThis, "ValueTuple").WithArguments("(T1, T2).Item1").WithLocation(18, 16), // (18,16): error CS0171: Field '(T1, T2).Item1' must be fully assigned before control is returned to the caller // public ValueTuple(T1 item1, T2 item2) Diagnostic(ErrorCode.ERR_UnassignedThis, "ValueTuple").WithArguments("(T1, T2).Item1").WithLocation(18, 16), // (7,39): error CS0229: Ambiguity between '(string, string).Item1' and '(string, string).Item1' // System.Console.WriteLine($"{x.Item1}"); Diagnostic(ErrorCode.ERR_AmbigMember, "Item1").WithArguments("(string, string).Item1", "(string, string).Item1").WithLocation(7, 39), // (6,13): warning CS0219: The variable 'x' is assigned but its value is never used // var x = ("Alice", "Bob"); Diagnostic(ErrorCode.WRN_UnreferencedVarAssg, "x").WithArguments("x").WithLocation(6, 13) ); var vt2 = comp.GetTypeByMetadataName("System.ValueTuple`2"); Assert.True(vt2.IsTupleType); Assert.True(vt2.IsDefinition); AssertEx.Equal(new[] { "T1 (T1, T2).Item1", "T2 (T1, T2).Item2" }, vt2.TupleElements.ToTestDisplayStrings()); vt2.TupleElements.All(e => verifyTupleErrorField(e)); AssertEx.Equal(new[] { "System.String (T1, T2).Item1", "System.Int32 (T1, T2).Item2", "(T1, T2)..ctor(T1 item1, T2 item2)", "(T1, T2) (T1, T2).M1()", "(T1 a, T2 b) (T1, T2).M2()", "(T1, T2)..ctor()", "T1 (T1, T2).Item1", "T2 (T1, T2).Item2" }, vt2.GetMembers().ToTestDisplayStrings()); var stringItem1 = vt2.GetMembers("Item1")[0]; Assert.Equal("System.String (T1, T2).Item1", stringItem1.ToTestDisplayString()); Assert.Equal(-1, ((FieldSymbol)stringItem1).TupleElementIndex); var intItem2 = vt2.GetMembers("Item2")[0]; Assert.Equal("System.Int32 (T1, T2).Item2", intItem2.ToTestDisplayString()); Assert.Equal(-1, ((FieldSymbol)intItem2).TupleElementIndex); var unnamedTuple = (NamedTypeSymbol)((MethodSymbol)vt2.GetMember("M1")).ReturnType; Assert.Equal("(T1, T2)", unnamedTuple.ToTestDisplayString()); Assert.Equal(SymbolKind.NamedType, unnamedTuple.Kind); Assert.True(unnamedTuple.IsDefinition); Assert.True(unnamedTuple.IsTupleType); Assert.Same(vt2, unnamedTuple); Assert.IsType(unnamedTuple); Assert.Same(vt2, unnamedTuple.ConstructedFrom); Assert.Same(unnamedTuple, unnamedTuple.OriginalDefinition); Assert.Same(unnamedTuple, unnamedTuple.TupleUnderlyingType); var namedTuple = (NamedTypeSymbol)((MethodSymbol)vt2.GetMember("M2")).ReturnType; Assert.Equal("(T1 a, T2 b)", namedTuple.ToTestDisplayString()); Assert.Equal(SymbolKind.NamedType, namedTuple.Kind); Assert.False(namedTuple.IsDefinition); Assert.True(namedTuple.IsTupleType); Assert.IsType(namedTuple); Assert.NotSame(vt2, namedTuple); Assert.Same(vt2, namedTuple.ConstructedFrom); Assert.Same(vt2, namedTuple.OriginalDefinition); Assert.False(namedTuple.Equals(namedTuple.TupleUnderlyingType, TypeCompareKind.ConsiderEverything)); Assert.True(namedTuple.Equals(namedTuple.TupleUnderlyingType, TypeCompareKind.IgnoreTupleNames)); bool verifyTupleErrorField(FieldSymbol field) { var errorField = field as TupleErrorFieldSymbol; Assert.NotNull(errorField); Assert.True(errorField.IsDefinition); Assert.True(errorField.TupleElementIndex != -1); return true; } } [Fact] public void UnderlyingTypeMemberWithWrongSignature_2() { string source = @" class C { (string, string) M() { var x = (""Alice"", ""Bob""); System.Console.WriteLine($""{x.Item1}""); return x; } void M2((int a, int b) y) { System.Console.WriteLine($""{y.Item1}""); System.Console.WriteLine($""{y.a}""); System.Console.WriteLine($""{y.Item2}""); System.Console.WriteLine($""{y.b}""); } } namespace System { public struct ValueTuple { public int Item2; public ValueTuple(T1 item1, T2 item2) { this.Item2 = 2; } } } "; var comp = CreateCompilationWithMscorlib40(source, assemblyName: "comp"); comp.VerifyDiagnostics( // (11,13): error CS8137: Cannot define a class or member that utilizes tuples because the compiler required type 'System.Runtime.CompilerServices.TupleElementNamesAttribute' cannot be found. Are you missing a reference? // void M2((int a, int b) y) Diagnostic(ErrorCode.ERR_TupleElementNamesAttributeMissing, "(int a, int b)").WithArguments("System.Runtime.CompilerServices.TupleElementNamesAttribute").WithLocation(11, 13), // (28,18): error CS0229: Ambiguity between '(T1, T2).Item2' and '(T1, T2).Item2' // this.Item2 = 2; Diagnostic(ErrorCode.ERR_AmbigMember, "Item2").WithArguments("(T1, T2).Item2", "(T1, T2).Item2").WithLocation(28, 18), // (26,16): error CS0171: Field '(T1, T2).Item2' must be fully assigned before control is returned to the caller // public ValueTuple(T1 item1, T2 item2) Diagnostic(ErrorCode.ERR_UnassignedThis, "ValueTuple").WithArguments("(T1, T2).Item2").WithLocation(26, 16), // (26,16): error CS0171: Field '(T1, T2).Item1' must be fully assigned before control is returned to the caller // public ValueTuple(T1 item1, T2 item2) Diagnostic(ErrorCode.ERR_UnassignedThis, "ValueTuple").WithArguments("(T1, T2).Item1").WithLocation(26, 16), // (26,16): error CS0171: Field '(T1, T2).Item2' must be fully assigned before control is returned to the caller // public ValueTuple(T1 item1, T2 item2) Diagnostic(ErrorCode.ERR_UnassignedThis, "ValueTuple").WithArguments("(T1, T2).Item2").WithLocation(26, 16), // (7,39): error CS8128: Member 'Item1' was not found on type '(T1, T2)' from assembly 'comp, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'. // System.Console.WriteLine($"{x.Item1}"); Diagnostic(ErrorCode.ERR_PredefinedTypeMemberNotFoundInAssembly, "Item1").WithArguments("Item1", "(T1, T2)", "comp, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null").WithLocation(7, 39), // (13,39): error CS8128: Member 'Item1' was not found on type '(T1, T2)' from assembly 'comp, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'. // System.Console.WriteLine($"{y.Item1}"); Diagnostic(ErrorCode.ERR_PredefinedTypeMemberNotFoundInAssembly, "Item1").WithArguments("Item1", "(T1, T2)", "comp, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null").WithLocation(13, 39), // (14,39): error CS8128: Member 'Item1' was not found on type '(T1, T2)' from assembly 'comp, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'. // System.Console.WriteLine($"{y.a}"); Diagnostic(ErrorCode.ERR_PredefinedTypeMemberNotFoundInAssembly, "a").WithArguments("Item1", "(T1, T2)", "comp, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null").WithLocation(14, 39), // (15,39): error CS0229: Ambiguity between '(int a, int b).Item2' and '(int a, int b).Item2' // System.Console.WriteLine($"{y.Item2}"); Diagnostic(ErrorCode.ERR_AmbigMember, "Item2").WithArguments("(int a, int b).Item2", "(int a, int b).Item2").WithLocation(15, 39), // (16,39): error CS8128: Member 'Item2' was not found on type '(T1, T2)' from assembly 'comp, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'. // System.Console.WriteLine($"{y.b}"); Diagnostic(ErrorCode.ERR_PredefinedTypeMemberNotFoundInAssembly, "b").WithArguments("Item2", "(T1, T2)", "comp, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null").WithLocation(16, 39) ); var mTuple = (NamedTypeSymbol)comp.SourceModule.GlobalNamespace.GetMember("C").GetMember("M").ReturnType; AssertTupleTypeEquality(mTuple); var mItem1 = (FieldSymbol)mTuple.GetMembers("Item1").Single(); Assert.IsType(mItem1); Assert.Same(mItem1, mItem1.OriginalDefinition); Assert.True(mItem1.Equals(mItem1)); Assert.Equal("Item1", mItem1.Name); Assert.Null(mItem1.TupleUnderlyingField); Assert.Null(mItem1.AssociatedSymbol); Assert.Same(mTuple, mItem1.ContainingSymbol); Assert.True(mItem1.TypeWithAnnotations.CustomModifiers.IsEmpty); Assert.True(mItem1.GetAttributes().IsEmpty); Assert.Equal("error CS8128: Member 'Item1' was not found on type '(T1, T2)' from assembly 'comp, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'.", mItem1.GetUseSiteDiagnostic().ToString(EnsureEnglishUICulture.PreferredOrNull)); Assert.True(mItem1.Locations.IsEmpty); Assert.True(mItem1.DeclaringSyntaxReferences.IsEmpty); Assert.True(mItem1.IsImplicitlyDeclared); Assert.Null(mItem1.TypeLayoutOffset); AssertTestDisplayString(mTuple.GetMembers(), "System.Int32 (System.String, System.String).Item2", "(System.String, System.String)..ctor(System.String item1, System.String item2)", "(System.String, System.String)..ctor()", "System.String (System.String, System.String).Item1", "System.String (System.String, System.String).Item2"); var m2Tuple = (NamedTypeSymbol)comp.SourceModule.GlobalNamespace.GetMember("C").GetMember("M2").Parameters[0].Type; AssertTupleTypeEquality(m2Tuple); AssertTestDisplayString(m2Tuple.GetMembers(), "System.Int32 (System.Int32 a, System.Int32 b).Item2", "(System.Int32 a, System.Int32 b)..ctor(System.Int32 item1, System.Int32 item2)", "(System.Int32 a, System.Int32 b)..ctor()", "System.Int32 (System.Int32 a, System.Int32 b).Item1", "System.Int32 (System.Int32 a, System.Int32 b).a", "System.Int32 (System.Int32 a, System.Int32 b).Item2", "System.Int32 (System.Int32 a, System.Int32 b).b" ); } [Fact] public void UnderlyingTypeMemberWithWrongSignature_3() { string source = @" class C { static void M() { var x = (a: ""Alice"", b: ""Bob""); System.Console.WriteLine($""{x.a}""); } } namespace System { public struct ValueTuple { public int Item2; public ValueTuple(T1 item1, T2 item2) { this.Item2 = 2; } } } "; var comp = CreateCompilation(source, assemblyName: "comp"); comp.VerifyDiagnostics( // (7,39): error CS8128: Member 'Item1' was not found on type '(T1, T2)' from assembly 'comp, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'. // System.Console.WriteLine($"{x.a}"); Diagnostic(ErrorCode.ERR_PredefinedTypeMemberNotFoundInAssembly, "a").WithArguments("Item1", "(T1, T2)", "comp, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null").WithLocation(7, 39), // (17,16): error CS0171: Field '(T1, T2).Item2' must be fully assigned before control is returned to the caller // public ValueTuple(T1 item1, T2 item2) Diagnostic(ErrorCode.ERR_UnassignedThis, "ValueTuple").WithArguments("(T1, T2).Item2").WithLocation(17, 16), // (17,16): error CS0171: Field '(T1, T2).Item1' must be fully assigned before control is returned to the caller // public ValueTuple(T1 item1, T2 item2) Diagnostic(ErrorCode.ERR_UnassignedThis, "ValueTuple").WithArguments("(T1, T2).Item1").WithLocation(17, 16), // (17,16): error CS0171: Field '(T1, T2).Item2' must be fully assigned before control is returned to the caller // public ValueTuple(T1 item1, T2 item2) Diagnostic(ErrorCode.ERR_UnassignedThis, "ValueTuple").WithArguments("(T1, T2).Item2").WithLocation(17, 16), // (19,18): error CS0229: Ambiguity between '(T1, T2).Item2' and '(T1, T2).Item2' // this.Item2 = 2; Diagnostic(ErrorCode.ERR_AmbigMember, "Item2").WithArguments("(T1, T2).Item2", "(T1, T2).Item2").WithLocation(19, 18) ); } [Fact] public void UnderlyingTypeMemberWithWrongSignature_4() { string source = @" class C { static void M() { var x = (a: 1, b: 2, c: 3, d: 4, e: 5, f: 6, g: 7, h: 8, i: 9); System.Console.WriteLine($""{x.a}""); System.Console.WriteLine($""{x.g}""); System.Console.WriteLine($""{x.h}""); System.Console.WriteLine($""{x.i}""); } } namespace System { public struct ValueTuple { } public struct ValueTuple { public TRest Rest; } } "; var comp = CreateCompilation(source, assemblyName: "comp"); comp.VerifyDiagnostics( // (7,39): error CS8128: Member 'Item1' was not found on type 'ValueTuple' from assembly 'comp, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'. // System.Console.WriteLine($"{x.a}"); Diagnostic(ErrorCode.ERR_PredefinedTypeMemberNotFoundInAssembly, "a").WithArguments("Item1", "System.ValueTuple", "comp, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null").WithLocation(7, 39), // (8,39): error CS8128: Member 'Item7' was not found on type 'ValueTuple' from assembly 'comp, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'. // System.Console.WriteLine($"{x.g}"); Diagnostic(ErrorCode.ERR_PredefinedTypeMemberNotFoundInAssembly, "g").WithArguments("Item7", "System.ValueTuple", "comp, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null").WithLocation(8, 39), // (9,39): error CS8128: Member 'Item1' was not found on type '(T1, T2)' from assembly 'comp, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'. // System.Console.WriteLine($"{x.h}"); Diagnostic(ErrorCode.ERR_PredefinedTypeMemberNotFoundInAssembly, "h").WithArguments("Item1", "(T1, T2)", "comp, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null").WithLocation(9, 39), // (10,39): error CS8128: Member 'Item2' was not found on type '(T1, T2)' from assembly 'comp, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'. // System.Console.WriteLine($"{x.i}"); Diagnostic(ErrorCode.ERR_PredefinedTypeMemberNotFoundInAssembly, "i").WithArguments("Item2", "(T1, T2)", "comp, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null").WithLocation(10, 39) ); } [Fact] public void ImplementTupleInterface() { string source = @" public interface I { (int, int) M((string, string) a); } class C : I { static void Main() { I i = new C(); var r = i.M((""Alice"", ""Bob"")); System.Console.WriteLine($""{r.Item1} {r.Item2}""); } public (int, int) M((string, string) a) { return (a.Item1.Length, a.Item2.Length); } } "; var comp = CompileAndVerify(source, expectedOutput: @"5 3"); comp.VerifyDiagnostics(); } [Fact] public void ImplementLongTupleInterface() { string source = @" public interface I { (int, int, int, int, int, int, int, int) M((int, int, int, int, int, int, int, int) a); } class C : I { static void Main() { I i = new C(); var r = i.M((1, 2, 3, 4, 5, 6, 7, 8)); System.Console.WriteLine($""{r.Item1} {r.Item7} {r.Item8}""); } public (int, int, int, int, int, int, int, int) M((int, int, int, int, int, int, int, int) a) { return a; } } "; var comp = CompileAndVerify(source, expectedOutput: @"1 7 8"); comp.VerifyDiagnostics(); } [Fact] public void ImplementTupleInterfaceWithValueTuple() { string source = @" public interface I { (int, int) M((string, string) a); } class C : I { static void Main() { I i = new C(); var r = i.M((""Alice"", ""Bob"")); System.Console.WriteLine($""{r.Item1} {r.Item2}""); } public System.ValueTuple M(System.ValueTuple a) { return (a.Item1.Length, a.Item2.Length); } } "; var comp = CompileAndVerify(source, expectedOutput: @"5 3"); comp.VerifyDiagnostics(); } [Fact] public void ImplementTupleInterfaceWithValueTuple2() { string source = @" public interface I { (int i1, int i2) M((string, string) a); } class C : I { public System.ValueTuple M(System.ValueTuple a) { return (1, 2); } void M(I i, C c) { var result1 = i.M((null, null)); System.Console.Write(result1.i1); var result2 = c.M((null, null)); System.Console.Write(result2.i1); } } "; var comp = CreateCompilation(source); comp.VerifyDiagnostics( // (19,38): error CS1061: '(int, int)' does not contain a definition for 'i1' and no extension method 'i1' accepting a first argument of type '(int, int)' could be found (are you missing a using directive or an assembly reference?) // System.Console.Write(result2.i1); Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "i1").WithArguments("(int, int)", "i1").WithLocation(19, 38) ); var tree = comp.SyntaxTrees.Single(); var model = comp.GetSemanticModel(tree); var invocation1 = tree.GetRoot().DescendantNodes().OfType().ElementAt(0); Assert.Equal("i.M((null, null))", invocation1.ToString()); Assert.Equal("(System.Int32 i1, System.Int32 i2) I.M((System.String, System.String) a)", model.GetSymbolInfo(invocation1.Expression).Symbol.ToTestDisplayString()); var invocation2 = tree.GetRoot().DescendantNodes().OfType().ElementAt(2); Assert.Equal("c.M((null, null))", invocation2.ToString()); Assert.Equal("(System.Int32, System.Int32) C.M((System.String, System.String) a)", model.GetSymbolInfo(invocation2.Expression).Symbol.ToTestDisplayString()); } [Fact] public void ImplementValueTupleInterfaceWithTuple() { string source = @" public interface I { System.ValueTuple M(System.ValueTuple a); } class C : I { static void Main() { I i = new C(); var r = i.M((""Alice"", ""Bob"")); System.Console.WriteLine($""{r.Item1} {r.Item2}""); } public (int, int) M((string, string) a) { return new System.ValueTuple(a.Item1.Length, a.Item2.Length); } } "; var comp = CompileAndVerify(source, expectedOutput: @"5 3"); comp.VerifyDiagnostics(); } [Fact] public void ImplementInterfaceWithGeneric() { string source = @" public interface I where TB : TA { (TB, TA, TC) M((TB, (TA, TC)) arg) where TC : TB; } public class CA { public override string ToString() { return ""CA""; } } public class CB : CA { public override string ToString() { return ""CB""; } } public class CC : CB { public override string ToString() { return ""CC""; } } class C : I { static void Main() { I i = new C(); var r = i.M((new CB(), (new CA(), new CC()))); System.Console.WriteLine($""{r.Item1} {r.Item2} {r.Item3}""); } public (CB, CA, TC) M((CB, (CA, TC)) arg) where TC : CB { return (arg.Item1, arg.Item2.Item1, arg.Item2.Item2); } } "; var comp = CompileAndVerify(source, expectedOutput: @"CB CA CC"); comp.VerifyDiagnostics(); } [Fact] public void ImplementInterfaceWithGenericError() { string source = @" public interface I where TB : TA { (TB, TA, TC) M((TB, (TA, TC)) arg) where TC : TB; } public class CA { } public class CB : CA { } public class CC : CB { } class C1 : I { public (CB, CA, TC) M((CB, (CA, TC)) arg) { return (arg.Item1, arg.Item2.Item1, arg.Item2.Item2); } } class C2 : I { public (CB, CA, TC) M((CB, (CA, TC)) arg) where TC : CB { return (arg.Item2.Item1, arg.Item1, arg.Item2.Item2); } } "; var comp = CreateCompilation(source); comp.VerifyDiagnostics( // (15,25): error CS0425: The constraints for type parameter 'TC' of method 'C1.M((CB, (CA, TC)))' must match the constraints for type parameter 'TC' of interface method 'I.M((CB, (CA, TC)))'. Consider using an explicit interface implementation instead. // public (CB, CA, TC) M((CB, (CA, TC)) arg) Diagnostic(ErrorCode.ERR_ImplBadConstraints, "M").WithArguments("TC", "C1.M((CB, (CA, TC)))", "TC", "I.M((CB, (CA, TC)))").WithLocation(15, 25), // (25,17): error CS0029: Cannot implicitly convert type 'CA' to 'CB' // return (arg.Item2.Item1, arg.Item1, arg.Item2.Item2); Diagnostic(ErrorCode.ERR_NoImplicitConv, "arg.Item2.Item1").WithArguments("CA", "CB").WithLocation(25, 17) ); } [Fact] public void OverrideTupleMethodWithDifferentNames() { string source = @" class C { public virtual (int a, int b) M((int c, int d) x) { throw new System.Exception(); } } class D : C { public override (int e, int f) M((int g, int h) y) { return y; } } "; var comp = CreateCompilation(source); comp.VerifyDiagnostics( // (11,36): error CS8139: 'D.M((int g, int h))': cannot change tuple element names when overriding inherited member 'C.M((int c, int d))' // public override (int e, int f) M((int g, int h) y) Diagnostic(ErrorCode.ERR_CantChangeTupleNamesOnOverride, "M").WithArguments("D.M((int g, int h))", "C.M((int c, int d))").WithLocation(11, 36) ); } [Fact] public void OverrideTupleMethodWithDifferentNamesInParameterType() { string source = @" class C { public virtual (int a, int b) M((int c, int d) x) { throw new System.Exception(); } } class D : C { public override (int, int) M((int g, int h) y) { return y; } } "; var comp = CreateCompilation(source); comp.VerifyDiagnostics( // (11,32): error CS8139: 'D.M((int g, int h))': cannot change tuple element names when overriding inherited member 'C.M((int c, int d))' // public override (int, int) M((int g, int h) y) Diagnostic(ErrorCode.ERR_CantChangeTupleNamesOnOverride, "M").WithArguments("D.M((int g, int h))", "C.M((int c, int d))").WithLocation(11, 32) ); } [Fact] public void OverrideTupleMethodWithDifferentNamesInReturnType() { string source = @" class C { public virtual (int a, int b) M((int c, int d) x) { throw new System.Exception(); } } class D : C { public override (int e, int f) M((int, int) y) { return y; } } "; var comp = CreateCompilation(source); comp.VerifyDiagnostics( // (11,36): error CS8139: 'D.M((int, int))': cannot change tuple element names when overriding inherited member 'C.M((int c, int d))' // public override (int e, int f) M((int, int) y) Diagnostic(ErrorCode.ERR_CantChangeTupleNamesOnOverride, "M").WithArguments("D.M((int, int))", "C.M((int c, int d))").WithLocation(11, 36) ); } [Fact] [WorkItem(20528, "https://github.com/dotnet/roslyn/issues/20528")] public void OverrideTupleMethodWithNoNames() { string source = @" class C { public virtual (int a, int b) M((int c, int d) x) { throw new System.Exception(); } } class D : C { public override (int, int) M((int, int) y) { return y; } } class E { void M(D d) { var result = d.M((1, 2)); System.Console.Write(result.a); } } "; var comp = CreateCompilation(source); comp.VerifyDiagnostics( // (21,37): error CS1061: '(int, int)' does not contain a definition for 'a' and no extension method 'a' accepting a first argument of type '(int, int)' could be found (are you missing a using directive or an assembly reference?) // System.Console.Write(result.a); Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "a").WithArguments("(int, int)", "a").WithLocation(21, 37) ); var tree = comp.SyntaxTrees.Single(); var model = comp.GetSemanticModel(tree); var invocation = tree.GetRoot().DescendantNodes().OfType().ElementAt(0); Assert.Equal("d.M((1, 2))", invocation.ToString()); Assert.Equal("(System.Int32, System.Int32) D.M((System.Int32, System.Int32) y)", model.GetSymbolInfo(invocation.Expression).Symbol.ToTestDisplayString()); } [Fact] [WorkItem(20528, "https://github.com/dotnet/roslyn/issues/20528")] public void OverrideTupleMethodWithNoNamesWithValueTuple() { string source = @" using System; class C { public virtual (int a, int b) M((int c, int d) x) { throw null; } } class D : C { public override ValueTuple M(ValueTuple y) { return y; } } class E { void M(D d) { var result = d.M((1, 2)); System.Console.Write(result.a); } } "; var comp = CreateCompilation(source); comp.VerifyDiagnostics( // (22,37): error CS1061: '(int, int)' does not contain a definition for 'a' and no extension method 'a' accepting a first argument of type '(int, int)' could be found (are you missing a using directive or an assembly reference?) // System.Console.Write(result.a); Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "a").WithArguments("(int, int)", "a").WithLocation(22, 37) ); var tree = comp.SyntaxTrees.Single(); var model = comp.GetSemanticModel(tree); var invocation = tree.GetRoot().DescendantNodes().OfType().ElementAt(0); Assert.Equal("d.M((1, 2))", invocation.ToString()); Assert.Equal("(System.Int32, System.Int32) D.M((System.Int32, System.Int32) y)", model.GetSymbolInfo(invocation.Expression).Symbol.ToTestDisplayString()); } [Fact] [WorkItem(20528, "https://github.com/dotnet/roslyn/issues/20528")] public void OverrideTuplePropertyWithNoNames() { string source = @" class C { public virtual (int a, int b) P { get; set; } } class D : C { public override (int, int) P { get; set; } void M(D d) { var result = d.P; var result2 = this.P; var result3 = base.P; System.Console.Write(result.a); System.Console.Write(result2.a); System.Console.Write(result3.a); } } "; var comp = CreateCompilation(source); comp.VerifyDiagnostics( // (14,37): error CS1061: '(int, int)' does not contain a definition for 'a' and no extension method 'a' accepting a first argument of type '(int, int)' could be found (are you missing a using directive or an assembly reference?) // System.Console.Write(result.a); Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "a").WithArguments("(int, int)", "a").WithLocation(14, 37), // (15,38): error CS1061: '(int, int)' does not contain a definition for 'a' and no extension method 'a' accepting a first argument of type '(int, int)' could be found (are you missing a using directive or an assembly reference?) // System.Console.Write(result2.a); Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "a").WithArguments("(int, int)", "a").WithLocation(15, 38) ); var tree = comp.SyntaxTrees.Single(); var model = comp.GetSemanticModel(tree); var memberAccess = tree.GetRoot().DescendantNodes().OfType().ElementAt(0); Assert.Equal("d.P", memberAccess.ToString()); Assert.Equal("(System.Int32, System.Int32) D.P { get; set; }", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); var memberAccess2 = tree.GetRoot().DescendantNodes().OfType().ElementAt(1); Assert.Equal("this.P", memberAccess2.ToString()); Assert.Equal("(System.Int32, System.Int32) D.P { get; set; }", model.GetSymbolInfo(memberAccess2).Symbol.ToTestDisplayString()); var memberAccess3 = tree.GetRoot().DescendantNodes().OfType().ElementAt(2); Assert.Equal("base.P", memberAccess3.ToString()); Assert.Equal("(System.Int32 a, System.Int32 b) C.P { get; set; }", model.GetSymbolInfo(memberAccess3).Symbol.ToTestDisplayString()); } [Fact] [WorkItem(20528, "https://github.com/dotnet/roslyn/issues/20528")] public void OverrideTupleEventWithNoNames() { string source = @" class C { public virtual event System.Func<((int a, int b) c, int d)> E; } class D : C { public override event System.Func<((int, int), int)> E; void M(D d) { var result = d.E(); System.Console.Write(result.c); } } "; var comp = CreateCompilation(source); comp.VerifyDiagnostics( // (12,37): error CS1061: '((int, int), int)' does not contain a definition for 'c' and no extension method 'c' accepting a first argument of type '((int, int), int)' could be found (are you missing a using directive or an assembly reference?) // System.Console.Write(result.c); Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "c").WithArguments("((int, int), int)", "c").WithLocation(12, 37), // (4,65): warning CS0067: The event 'C.E' is never used // public virtual event System.Func<((int a, int b) c, int d)> E; Diagnostic(ErrorCode.WRN_UnreferencedEvent, "E").WithArguments("C.E").WithLocation(4, 65) ); var tree = comp.SyntaxTrees.Single(); var model = comp.GetSemanticModel(tree); var invocation = tree.GetRoot().DescendantNodes().OfType().ElementAt(0); Assert.Equal("d.E()", invocation.ToString()); Assert.Equal("event System.Func<((System.Int32, System.Int32), System.Int32)> D.E", model.GetSymbolInfo(invocation.Expression).Symbol.ToTestDisplayString()); } [Fact] public void NewTupleMethodWithDifferentNames() { string source = @" class C { public virtual (int a, int b) M((int c, int d) x) { System.Console.WriteLine(""base""); return x; } } class D : C { static void Main() { D d = new D(); d.M((1, 2)); C c = d; c.M((1, 2)); } public new (int e, int f) M((int g, int h) y) { System.Console.Write(""new ""); return y; } } "; var comp = CompileAndVerify(source, expectedOutput: @"new base"); comp.VerifyDiagnostics(); } [Fact] public void DuplicateTupleMethodsNotAllowed() { string source = @" class C { public (int, int) M((string, string) a) { return new System.ValueTuple(a.Item1.Length, a.Item2.Length); } public System.ValueTuple M(System.ValueTuple a) { return (a.Item1.Length, a.Item2.Length); } } "; var comp = CreateCompilation(source); comp.VerifyDiagnostics( // (9,40): error CS0111: Type 'C' already defines a member called 'M' with the same parameter types // public System.ValueTuple M(System.ValueTuple a) Diagnostic(ErrorCode.ERR_MemberAlreadyExists, "M").WithArguments("M", "C").WithLocation(9, 40) ); } [Fact] public void TupleArrays() { string source = @" public interface I { System.ValueTuple[] M((int, int)[] a); } class C : I { static void Main() { I i = new C(); var r = i.M(new [] { new System.ValueTuple(1, 2) }); System.Console.WriteLine($""{r[0].Item1} {r[0].Item2}""); } public (int, int)[] M(System.ValueTuple[] a) { return new [] { (a[0].Item1, a[0].Item2) }; } } "; var comp = CompileAndVerify(source, expectedOutput: @"1 2"); comp.VerifyDiagnostics(); } [Fact] public void TupleRef() { string source = @" class C { static void Main() { var r = (1, 2); M(ref r); System.Console.WriteLine($""{r.Item1} {r.Item2}""); } static void M(ref (int, int) a) { System.Console.WriteLine($""{a.Item1} {a.Item2}""); a = (3, 4); } } "; var comp = CompileAndVerify(source, parseOptions: TestOptions.Regular, expectedOutput: @"1 2 3 4"); comp.VerifyDiagnostics(); } [Fact] public void TupleOut() { string source = @" class C { static void Main() { (int, int) r; M(out r); System.Console.WriteLine($""{r.Item1} {r.Item2}""); } static void M(out (int, int) a) { a = (1, 2); } } "; var comp = CompileAndVerify(source, expectedOutput: @"1 2"); comp.VerifyDiagnostics(); } [Fact] public void TupleTypeArgs() { string source = @" class C { static void Main() { var a = (1, ""Alice""); var r = M(a); System.Console.WriteLine($""{r.Item1} {r.Item2}""); } static (T1, T2) M((T1, T2) a) { return a; } } "; var comp = CompileAndVerify(source, expectedOutput: @"1 Alice"); comp.VerifyDiagnostics(); } [Fact] public void NullableTuple() { string source = @" class C { static void Main() { M((1, ""Alice"")); } static void M((int, string)? a) { System.Console.WriteLine($""{a.HasValue} {a.Value.Item1} {a.Value.Item2}""); } } "; var comp = CompileAndVerify(source, expectedOutput: @"True 1 Alice"); comp.VerifyDiagnostics(); } [Fact] public void TupleUnsupportedInUsingStatement() { var source = @" using VT2 = (int, int); "; var comp = CreateCompilation(source, options: TestOptions.DebugExe, parseOptions: TestOptions.RegularPreview); comp.VerifyDiagnostics( // (2,13): error CS1001: Identifier expected // using VT2 = (int, int); Diagnostic(ErrorCode.ERR_IdentifierExpected, "(").WithLocation(2, 13), // (2,13): error CS1002: ; expected // using VT2 = (int, int); Diagnostic(ErrorCode.ERR_SemicolonExpected, "(").WithLocation(2, 13), // (2,14): error CS1525: Invalid expression term 'int' // using VT2 = (int, int); Diagnostic(ErrorCode.ERR_InvalidExprTerm, "int").WithArguments("int").WithLocation(2, 14), // (2,19): error CS1525: Invalid expression term 'int' // using VT2 = (int, int); Diagnostic(ErrorCode.ERR_InvalidExprTerm, "int").WithArguments("int").WithLocation(2, 19), // (2,1): hidden CS8019: Unnecessary using directive. // using VT2 = (int, int); Diagnostic(ErrorCode.HDN_UnusedUsingDirective, "using VT2 = ").WithLocation(2, 1) ); } [Fact] public void TupleWithVar() { var source = @" class C { static void Main() { (int, var) x = (1, 2); } } " + trivial2uple + tupleattributes_cs; var comp = CreateCompilationWithMscorlib40(source); comp.VerifyDiagnostics( // (6,15): error CS0825: The contextual keyword 'var' may only appear within a local variable declaration or in script code // (int, var) x = (1, 2); Diagnostic(ErrorCode.ERR_TypeVarNotFound, "var").WithLocation(6, 15) ); } [Fact] [WorkItem(12032, "https://github.com/dotnet/roslyn/issues/12032")] public void MissingTypeInAlias() { var source = @" using System; using VT2 = System.ValueTuple; // ValueTuple is referenced but does not exist namespace System { public class Bogus { } } namespace TuplesCrash2 { class Program { static void Main(string[] args) { } } } "; var tree = Parse(source); var comp = CreateCompilation(new[] { tree }); var model = comp.GetSemanticModel(tree, ignoreAccessibility: false); var nodes = tree.GetCompilationUnitRoot().DescendantNodes(); model.LookupStaticMembers(201); // This position is inside Main method for (int pos = 0; pos < source.Length; pos++) { model.LookupStaticMembers(pos); } // didn't crash } [Fact] [WorkItem(11302, "https://github.com/dotnet/roslyn/issues/11302")] public void MultipleDefinitionsOfValueTuple() { var source1 = @" public static class C1 { public static void M1(this int x, (int, int) y) { System.Console.WriteLine(""C1.M1""); } } " + trivial2uple + tupleattributes_cs; var source2 = @" public static class C2 { public static void M1(this int x, (int, int) y) { System.Console.WriteLine(""C2.M1""); } } " + trivial2uple + tupleattributes_cs; var comp1 = CreateCompilationWithMscorlib40AndSystemCore(source1, assemblyName: "comp1"); comp1.VerifyDiagnostics(); var comp2 = CreateCompilationWithMscorlib40AndSystemCore(source2, assemblyName: "comp2"); comp2.VerifyDiagnostics(); var source = @" class C3 { public static void Main() { int x = 0; x.M1((1, 1)); } } "; var comp = CreateCompilationWithMscorlib40(source, references: new[] { comp1.ToMetadataReference(), comp2.ToMetadataReference() }); comp.VerifyDiagnostics( // (7,14): error CS8356: Predefined type 'System.ValueTuple`2' is declared in multiple referenced assemblies: 'comp1, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' and 'comp2, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' // x.M1((1, 1)); Diagnostic(ErrorCode.ERR_PredefinedValueTupleTypeAmbiguous3, "(1, 1)").WithArguments("System.ValueTuple`2", "comp1, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null", "comp2, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null").WithLocation(7, 14) ); comp = CreateCompilationWithMscorlib40(source, references: new[] { comp1.ToMetadataReference() }, options: TestOptions.DebugExe); comp.VerifyDiagnostics(); CompileAndVerify(comp, expectedOutput: "C1.M1"); } [Fact] [WorkItem(12082, "https://github.com/dotnet/roslyn/issues/12082")] public void TupleWithDynamic() { var source = @" class C { static void Main() { (dynamic, dynamic) d1 = (1, 1); // implicit to dynamic System.Console.WriteLine(d1); (dynamic, dynamic) d2 = M(); System.Console.WriteLine(d2); (int, int) t3 = (3, 3); (dynamic, dynamic) d3 = t3; System.Console.WriteLine(d3); (int, int) t4 = (4, 4); (dynamic, dynamic) d4 = ((dynamic, dynamic))t4; // explicit to dynamic System.Console.WriteLine(d4); dynamic d5 = 5; (int, int) t5 = (d5, d5); // implicit from dynamic System.Console.WriteLine(t5); (dynamic, dynamic) d6 = (6, 6); (int, int) t6 = ((int, int))d6; // explicit from dynamic System.Console.WriteLine(t6); (dynamic, dynamic) d7; (int, int) t7 = (7, 7); d7 = t7; System.Console.WriteLine(d7); } static (dynamic, dynamic) M() { return (2, 2); } } "; string expectedOutput = @"(1, 1) (2, 2) (3, 3) (4, 4) (5, 5) (6, 6) (7, 7) "; var comp = CompileAndVerify(source, references: new[] { CSharpRef }, expectedOutput: expectedOutput); comp.VerifyDiagnostics(); } [Fact] [WorkItem(12082, "https://github.com/dotnet/roslyn/issues/12082")] public void TupleWithDynamic2() { var source = @" class C { static void Main() { (dynamic, dynamic) d = (1, 1); (int, int) t = d; } } "; var comp = CreateCompilation(source, references: new[] { CSharpRef }); comp.VerifyDiagnostics( // (7,24): error CS0266: Cannot implicitly convert type '(dynamic, dynamic)' to '(int, int)'. An explicit conversion exists (are you missing a cast?) // (int, int) t = d; Diagnostic(ErrorCode.ERR_NoImplicitConvCast, "d").WithArguments("(dynamic, dynamic)", "(int, int)").WithLocation(7, 24) ); } [Fact] public void TupleWithDynamic3() { var source = @" class C { public static void Main() { dynamic longTuple = (a: 2, b: 2, c: 2, d: 2, e: 2, f: 2, g: 2, h: 2, i: 2); System.Console.Write($""Item1: {longTuple.Item1} Rest: {longTuple.Rest}""); try { System.Console.Write(longTuple.a); System.Console.Write(""unreachable""); } catch (Microsoft.CSharp.RuntimeBinder.RuntimeBinderException) {} try { System.Console.Write(longTuple.i); System.Console.Write(""unreachable""); } catch (Microsoft.CSharp.RuntimeBinder.RuntimeBinderException) {} try { System.Console.Write(longTuple.Item9); System.Console.Write(""unreachable""); } catch (Microsoft.CSharp.RuntimeBinder.RuntimeBinderException) {} } } "; var comp = CompileAndVerify(source, expectedOutput: "Item1: 2 Rest: (2, 2)", references: new[] { CSharpRef }); comp.VerifyDiagnostics(); } [Fact] public void TupleWithDynamic4() { var source = @" class C { public static void Main() { dynamic x = (1, 2, 3, 4, 5, 6, 7, 8, 9); M(x); } public static void M((int a, int, int, int, int, int, int, int h, int i) t) { System.Console.Write($""a:{t.a}, h:{t.h}, i:{t.i}, Item9:{t.Item9}, Rest:{t.Rest}""); } } "; var comp = CompileAndVerify(source, expectedOutput: "a:1, h:8, i:9, Item9:9, Rest:(8, 9)", references: new[] { CSharpRef }); comp.VerifyDiagnostics(); } [Fact] public void TupleWithDynamic5() { var source = @" class C { public static void Main() { dynamic d = (1, 2); try { (string, string) t = d; System.Console.Write(""unreachable""); } catch (Microsoft.CSharp.RuntimeBinder.RuntimeBinderException) {} System.Console.Write(""done""); } } "; var comp = CompileAndVerify(source, expectedOutput: "done", references: new[] { CSharpRef }); comp.VerifyDiagnostics(); } [Fact] public void TupleWithDynamic6() { var source = @" class C { public static void Main() { (int, int) t1 = (1, 1); M(t1, ""int""); (byte, byte) t2 = (2, 2); M(t2, ""byte""); (dynamic, dynamic) t3 = (3, 3); M(t3, ""dynamic""); (string, string) t4 = (""4"", ""4""); M(t4, ""string""); } public static void M((int, int) t, string type) { System.Console.WriteLine($""int overload with value {t} and type {type}""); } public static void M((dynamic, dynamic) t, string type) { System.Console.WriteLine($""dynamic overload with value {t} and type {type}""); } } "; string expectedOutput = @"int overload with value (1, 1) and type int int overload with value (2, 2) and type byte dynamic overload with value (3, 3) and type dynamic dynamic overload with value (4, 4) and type string"; var comp = CompileAndVerify(source, expectedOutput: expectedOutput, references: new[] { CSharpRef }); comp.VerifyDiagnostics(); } [Fact] public void Tuple2To8Members() { var source = @" class C { static void Main() { System.Console.Write((1, 2).Item1); System.Console.Write((1, 2).Item2); System.Console.Write((3, 4, 5).Item1); System.Console.Write((3, 4, 5).Item2); System.Console.Write((3, 4, 5).Item3); System.Console.Write((6, 7, 8, 9).Item1); System.Console.Write((6, 7, 8, 9).Item2); System.Console.Write((6, 7, 8, 9).Item3); System.Console.Write((6, 7, 8, 9).Item4); System.Console.Write((0, 1, 2, 3, 4).Item1); System.Console.Write((0, 1, 2, 3, 4).Item2); System.Console.Write((0, 1, 2, 3, 4).Item3); System.Console.Write((0, 1, 2, 3, 4).Item4); System.Console.Write((0, 1, 2, 3, 4).Item5); System.Console.Write((5, 6, 7, 8, 9, 0).Item1); System.Console.Write((5, 6, 7, 8, 9, 0).Item2); System.Console.Write((5, 6, 7, 8, 9, 0).Item3); System.Console.Write((5, 6, 7, 8, 9, 0).Item4); System.Console.Write((5, 6, 7, 8, 9, 0).Item5); System.Console.Write((5, 6, 7, 8, 9, 0).Item6); System.Console.Write((1, 2, 3, 4, 5, 6, 7).Item1); System.Console.Write((1, 2, 3, 4, 5, 6, 7).Item2); System.Console.Write((1, 2, 3, 4, 5, 6, 7).Item3); System.Console.Write((1, 2, 3, 4, 5, 6, 7).Item4); System.Console.Write((1, 2, 3, 4, 5, 6, 7).Item5); System.Console.Write((1, 2, 3, 4, 5, 6, 7).Item6); System.Console.Write((1, 2, 3, 4, 5, 6, 7).Item7); System.Console.Write((8, 9, 0, 1, 2, 3, 4, 5).Item1); System.Console.Write((8, 9, 0, 1, 2, 3, 4, 5).Item2); System.Console.Write((8, 9, 0, 1, 2, 3, 4, 5).Item3); System.Console.Write((8, 9, 0, 1, 2, 3, 4, 5).Item4); System.Console.Write((8, 9, 0, 1, 2, 3, 4, 5).Item5); System.Console.Write((8, 9, 0, 1, 2, 3, 4, 5).Item6); System.Console.Write((8, 9, 0, 1, 2, 3, 4, 5).Item7); System.Console.Write((8, 9, 0, 1, 2, 3, 4, 5).Item8); } } "; var comp = CompileAndVerify(source, expectedOutput: "12345678901234567890123456789012345"); } [Fact] public void CreateTupleTypeSymbol_BadArguments() { var comp = CSharpCompilation.Create("test", references: new[] { MscorlibRef }); // no ValueTuple TypeSymbol intType = comp.GetSpecialType(SpecialType.System_Int32); Assert.Throws(() => comp.CreateTupleTypeSymbol(null, default(ImmutableArray))); // if names are provided, you need one for each element var vt2 = comp.GetWellKnownType(WellKnownType.System_ValueTuple_T2).Construct(intType, intType); var e = Assert.Throws(() => comp.CreateTupleTypeSymbol(vt2, new[] { "Item1" }.AsImmutable())); Assert.Contains(CodeAnalysisResources.TupleElementNameCountMismatch, e.Message); var tree = CSharpSyntaxTree.ParseText("class C { }"); var loc1 = Location.Create(tree, new TextSpan(0, 1)); e = Assert.Throws(() => comp.CreateTupleTypeSymbol(vt2, elementLocations: new[] { loc1 }.AsImmutable())); Assert.Contains(CodeAnalysisResources.TupleElementLocationCountMismatch, e.Message); } [Fact, WorkItem(36676, "https://github.com/dotnet/roslyn/issues/36676")] public void CreateTupleTypeSymbol_WithValueTuple_TupleZero() { var tupleComp = CreateCompilationWithMscorlib40(@" namespace System { public struct ValueTuple { } }"); var comp = CSharpCompilation.Create("test", references: new[] { MscorlibRef, tupleComp.ToMetadataReference() }); var vt0 = comp.GetWellKnownType(WellKnownType.System_ValueTuple); var tupleWithoutNames = comp.CreateTupleTypeSymbol(vt0, ImmutableArray.Empty); Assert.True(tupleWithoutNames.IsTupleType); Assert.Equal(SymbolKind.NamedType, tupleWithoutNames.Kind); Assert.Null(tupleWithoutNames.TupleUnderlyingType); Assert.Equal("System.ValueTuple", tupleWithoutNames.ToTestDisplayString()); Assert.True(GetTupleElementNames(tupleWithoutNames).IsDefault); Assert.Empty(ElementTypeNames(tupleWithoutNames)); Assert.Equal(SymbolKind.NamedType, tupleWithoutNames.Kind); TypeSymbol intType = comp.GetSpecialType(SpecialType.System_Int32); TypeSymbol stringType = comp.GetSpecialType(SpecialType.System_String); var vt8 = comp.GetWellKnownType(WellKnownType.System_ValueTuple_TRest) .Construct(intType, stringType, intType, stringType, intType, stringType, intType, vt0); Assert.False(vt8.IsTupleType); Assert.Throws(() => comp.CreateTupleTypeSymbol(vt8, default)); } [Fact, WorkItem(36676, "https://github.com/dotnet/roslyn/issues/36676")] public void CreateTupleTypeSymbol_WithValueTuple_TupleOne() { var tupleComp = CreateCompilationWithMscorlib40(@" namespace System { public struct ValueTuple { public T1 Item1; public ValueTuple(T1 item1) { Item1 = item1; } } }"); var comp = CSharpCompilation.Create("test", references: new[] { MscorlibRef, tupleComp.ToMetadataReference() }); TypeSymbol intType = comp.GetSpecialType(SpecialType.System_Int32); var vt1 = comp.GetWellKnownType(WellKnownType.System_ValueTuple_T1).Construct(intType); var tupleWithoutNames = comp.CreateTupleTypeSymbol(vt1, ImmutableArray.Create(new[] { (string)null })); Assert.Same(vt1, ((Symbols.PublicModel.NonErrorNamedTypeSymbol)tupleWithoutNames).UnderlyingNamedTypeSymbol); Assert.True(tupleWithoutNames.IsTupleType); Assert.Equal("System.ValueTuple", tupleWithoutNames.ToTestDisplayString()); Assert.True(GetTupleElementNames(tupleWithoutNames).IsDefault); Assert.Equal(new[] { "System.Int32" }, ElementTypeNames(tupleWithoutNames)); } [Fact] public void CreateTupleTypeSymbol_WithValueTuple() { var tupleComp = CreateCompilationWithMscorlib40(trivial2uple); var comp = CSharpCompilation.Create("test", references: new[] { MscorlibRef, tupleComp.ToMetadataReference() }); TypeSymbol intType = comp.GetSpecialType(SpecialType.System_Int32); TypeSymbol stringType = comp.GetSpecialType(SpecialType.System_String); var vt2 = comp.GetWellKnownType(WellKnownType.System_ValueTuple_T2).Construct(intType, stringType); var tupleWithoutNames = comp.CreateTupleTypeSymbol(vt2, ImmutableArray.Create(null, null)); Assert.Same(vt2, ((Symbols.PublicModel.NamedTypeSymbol)tupleWithoutNames).UnderlyingNamedTypeSymbol); Assert.True(tupleWithoutNames.IsTupleType); Assert.Equal(SymbolKind.NamedType, tupleWithoutNames.Kind); Assert.Null(tupleWithoutNames.TupleUnderlyingType); Assert.Equal("(System.Int32, System.String)", tupleWithoutNames.ToTestDisplayString()); Assert.True(GetTupleElementNames(tupleWithoutNames).IsDefault); Assert.Equal(new[] { "System.Int32", "System.String" }, ElementTypeNames(tupleWithoutNames)); Assert.Equal(SymbolKind.NamedType, tupleWithoutNames.Kind); Assert.All(tupleWithoutNames.GetMembers().OfType().Select(f => f.Locations.FirstOrDefault()), loc => Assert.Null(loc)); } private static ImmutableArray GetTupleElementNames(INamedTypeSymbol tuple) { var elements = tuple.TupleElements; if (elements.All(e => e.IsImplicitlyDeclared)) { return default(ImmutableArray); } return elements.SelectAsArray(e => e.ProvidedTupleElementNameOrNull()); } [Fact] public void CreateTupleTypeSymbol_Locations() { var tupleComp = CreateCompilation(trivial2uple); var comp = CSharpCompilation.Create("test", references: new[] { MscorlibRef, tupleComp.ToMetadataReference() }); var intType = comp.GetSpecialType(SpecialType.System_Int32); var stringType = comp.GetSpecialType(SpecialType.System_String); var vt2 = comp.GetWellKnownType(WellKnownType.System_ValueTuple_T2).Construct(intType, stringType); var tree = CSharpSyntaxTree.ParseText("class C { }"); var loc1 = Location.Create(tree, new TextSpan(0, 1)); var loc2 = Location.Create(tree, new TextSpan(1, 1)); var tuple = comp.CreateTupleTypeSymbol( vt2, ImmutableArray.Create("i1", "i2"), ImmutableArray.Create(loc1, loc2)); Assert.True(tuple.IsTupleType); Assert.Equal(SymbolKind.NamedType, tuple.TupleUnderlyingType.Kind); Assert.Equal("(System.Int32 i1, System.String i2)", tuple.ToTestDisplayString()); Assert.Equal(new[] { "System.Int32", "System.String" }, ElementTypeNames(tuple)); Assert.Equal(SymbolKind.NamedType, tuple.Kind); Assert.Equal(loc1, tuple.GetMembers("i1").Single().Locations.Single()); Assert.Equal(loc2, tuple.GetMembers("i2").Single().Locations.Single()); } [Fact] public void MemberNamesOnValueTupleFromPEWithoutFields() { string trivial2uple_withoutFields = @" namespace System { public struct ValueTuple { public ValueTuple(T1 item1, T2 item2) => throw null; public override string ToString() => throw null; } }"; var tupleComp = CreateCompilation(trivial2uple_withoutFields); var comp = CSharpCompilation.Create("test", references: new[] { MscorlibRef, tupleComp.EmitToImageReference() }); var vt2 = comp.GetWellKnownType(WellKnownType.System_ValueTuple_T2); AssertEx.SetEqual(vt2.MemberNames.ToArray(), new[] { ".ctor", "ToString", "Item1", "Item2" }); // Note: we emitted the missing fields } [Fact] public void CreateTupleTypeSymbol_NoNames() { var comp = CSharpCompilation.Create("test", references: new[] { MscorlibRef }); // no ValueTuple TypeSymbol intType = comp.GetSpecialType(SpecialType.System_Int32); TypeSymbol stringType = comp.GetSpecialType(SpecialType.System_String); var vt2 = comp.GetWellKnownType(WellKnownType.System_ValueTuple_T2).Construct(intType, stringType); var tupleWithoutNames = comp.CreateTupleTypeSymbol(vt2, default(ImmutableArray)); Assert.True(tupleWithoutNames.IsTupleType); Assert.Equal(SymbolKind.ErrorType, tupleWithoutNames.Kind); Assert.Null(tupleWithoutNames.TupleUnderlyingType); Assert.Equal("(System.Int32, System.String)[missing]", tupleWithoutNames.ToTestDisplayString()); Assert.True(GetTupleElementNames(tupleWithoutNames).IsDefault); Assert.Equal(new[] { "System.Int32", "System.String" }, ElementTypeNames(tupleWithoutNames)); Assert.Equal(SymbolKind.ErrorType, tupleWithoutNames.Kind); Assert.All(tupleWithoutNames.GetMembers().OfType().Select(f => f.Locations.FirstOrDefault()), loc => Assert.Null(loc)); } [Fact] public void CreateTupleTypeSymbol_WithNames() { var comp = CSharpCompilation.Create("test", references: new[] { MscorlibRef }); // no ValueTuple TypeSymbol intType = comp.GetSpecialType(SpecialType.System_Int32); TypeSymbol stringType = comp.GetSpecialType(SpecialType.System_String); var vt2 = comp.GetWellKnownType(WellKnownType.System_ValueTuple_T2).Construct(intType, stringType); var tupleWithNames = comp.CreateTupleTypeSymbol(vt2, ImmutableArray.Create("Alice", "Bob")); Assert.True(tupleWithNames.IsTupleType); Assert.Equal("(System.Int32 Alice, System.String Bob)[missing]", tupleWithNames.ToTestDisplayString()); Assert.Equal(new[] { "Alice", "Bob" }, GetTupleElementNames(tupleWithNames)); Assert.Equal(new[] { "System.Int32", "System.String" }, ElementTypeNames(tupleWithNames)); Assert.Equal(SymbolKind.ErrorType, tupleWithNames.Kind); Assert.All(tupleWithNames.GetMembers().OfType().Select(f => f.Locations.FirstOrDefault()), loc => Assert.Null(loc)); } [Fact] public void CreateTupleTypeSymbol_WithSomeNames() { var comp = CSharpCompilation.Create("test", references: new[] { MscorlibRef }); // no ValueTuple TypeSymbol intType = comp.GetSpecialType(SpecialType.System_Int32); TypeSymbol stringType = comp.GetSpecialType(SpecialType.System_String); var vt3 = comp.GetWellKnownType(WellKnownType.System_ValueTuple_T3).Construct(intType, stringType, intType); var tupleWithSomeNames = comp.CreateTupleTypeSymbol(vt3, ImmutableArray.Create(null, "Item2", "Charlie")); Assert.True(tupleWithSomeNames.IsTupleType); Assert.Equal("(System.Int32, System.String Item2, System.Int32 Charlie)[missing]", tupleWithSomeNames.ToTestDisplayString()); Assert.Equal(new[] { null, "Item2", "Charlie" }, GetTupleElementNames(tupleWithSomeNames)); Assert.Equal(new[] { "System.Int32", "System.String", "System.Int32" }, ElementTypeNames(tupleWithSomeNames)); Assert.Equal(SymbolKind.ErrorType, tupleWithSomeNames.Kind); Assert.All(tupleWithSomeNames.GetMembers().OfType().Select(f => f.Locations.FirstOrDefault()), loc => Assert.Null(loc)); } [Fact] public void CreateTupleTypeSymbol_WithBadNames() { var comp = CSharpCompilation.Create("test", references: new[] { MscorlibRef }); // no ValueTuple TypeSymbol intType = comp.GetSpecialType(SpecialType.System_Int32); var vt2 = comp.GetWellKnownType(WellKnownType.System_ValueTuple_T2).Construct(intType, intType); var tupleWithNames = comp.CreateTupleTypeSymbol(vt2, ImmutableArray.Create("Item2", "Item1")); Assert.True(tupleWithNames.IsTupleType); Assert.Equal("(System.Int32 Item2, System.Int32 Item1)[missing]", tupleWithNames.ToTestDisplayString()); Assert.Equal(new[] { "Item2", "Item1" }, GetTupleElementNames(tupleWithNames)); Assert.Equal(new[] { "System.Int32", "System.Int32" }, ElementTypeNames(tupleWithNames)); Assert.Equal(SymbolKind.ErrorType, tupleWithNames.Kind); Assert.All(tupleWithNames.GetMembers().OfType().Select(f => f.Locations.FirstOrDefault()), loc => Assert.Null(loc)); } [Fact] public void CreateTupleTypeSymbol_Tuple8NoNames() { var comp = CSharpCompilation.Create("test", references: new[] { MscorlibRef }); // no ValueTuple TypeSymbol intType = comp.GetSpecialType(SpecialType.System_Int32); TypeSymbol stringType = comp.GetSpecialType(SpecialType.System_String); var vt8 = comp.GetWellKnownType(WellKnownType.System_ValueTuple_TRest) .Construct(intType, stringType, intType, stringType, intType, stringType, intType, comp.GetWellKnownType(WellKnownType.System_ValueTuple_T1).Construct(stringType)); var tuple8WithoutNames = comp.CreateTupleTypeSymbol(vt8, default(ImmutableArray)); Assert.True(tuple8WithoutNames.IsTupleType); Assert.Equal("System.ValueTuple[missing]>[missing]", tuple8WithoutNames.ToTestDisplayString()); Assert.False(vt8.OriginalDefinition.IsTupleType); Assert.True(GetTupleElementNames(tuple8WithoutNames).IsDefault); Assert.Equal(new[] { "System.Int32", "System.String", "System.Int32", "System.String", "System.Int32", "System.String", "System.Int32", "System.String" }, ElementTypeNames(tuple8WithoutNames)); Assert.All(tuple8WithoutNames.TupleElements.Select(f => f.Locations.FirstOrDefault()), loc => Assert.Null(loc)); } [Fact] public void CreateTupleTypeSymbol_Tuple8NoNames_WithValueTupleTypes() { var tupleComp = CreateCompilation(trivial2uple + trivial3uple + trivialRemainingTuples); var comp = CSharpCompilation.Create("test", references: new[] { MscorlibRef, tupleComp.ToMetadataReference() }); TypeSymbol intType = comp.GetSpecialType(SpecialType.System_Int32); TypeSymbol stringType = comp.GetSpecialType(SpecialType.System_String); var vt8 = comp.GetWellKnownType(WellKnownType.System_ValueTuple_TRest) .Construct(intType, stringType, intType, stringType, intType, stringType, intType, comp.GetWellKnownType(WellKnownType.System_ValueTuple_T1).Construct(stringType)); var tuple8WithoutNames = comp.CreateTupleTypeSymbol(vt8, elementNames: default); Assert.Same(vt8, ((Symbols.PublicModel.NamedTypeSymbol)tuple8WithoutNames).UnderlyingNamespaceOrTypeSymbol); Assert.True(tuple8WithoutNames.IsTupleType); Assert.Equal("(System.Int32, System.String, System.Int32, System.String, System.Int32, System.String, System.Int32, System.String)", tuple8WithoutNames.ToTestDisplayString()); Assert.True(GetTupleElementNames(tuple8WithoutNames).IsDefault); Assert.Equal(new[] { "System.Int32", "System.String", "System.Int32", "System.String", "System.Int32", "System.String", "System.Int32", "System.String" }, ElementTypeNames(tuple8WithoutNames)); Assert.All(tuple8WithoutNames.GetMembers().OfType().Where(f => f.Name != "Rest").Select(f => f.Locations.FirstOrDefault()), loc => Assert.Null(loc)); } [Fact] public void CreateTupleTypeSymbol_Tuple8WithNames() { var comp = CSharpCompilation.Create("test", references: new[] { MscorlibRef }); // no ValueTuple TypeSymbol intType = comp.GetSpecialType(SpecialType.System_Int32); TypeSymbol stringType = comp.GetSpecialType(SpecialType.System_String); var vt8 = comp.GetWellKnownType(WellKnownType.System_ValueTuple_TRest) .Construct(intType, stringType, intType, stringType, intType, stringType, intType, comp.GetWellKnownType(WellKnownType.System_ValueTuple_T1).Construct(stringType)); var tuple8WithNames = comp.CreateTupleTypeSymbol(vt8, ImmutableArray.Create("Alice1", "Alice2", "Alice3", "Alice4", "Alice5", "Alice6", "Alice7", "Alice8")); Assert.True(tuple8WithNames.IsTupleType); AssertEx.Equal("System.ValueTuple[missing]>[missing]", tuple8WithNames.ToTestDisplayString()); Assert.Equal(new[] { "Alice1", "Alice2", "Alice3", "Alice4", "Alice5", "Alice6", "Alice7", "Alice8" }, GetTupleElementNames(tuple8WithNames)); Assert.Equal(new[] { "System.Int32", "System.String", "System.Int32", "System.String", "System.Int32", "System.String", "System.Int32", "System.String" }, ElementTypeNames(tuple8WithNames)); Assert.All(tuple8WithNames.GetMembers().OfType().Select(f => f.Locations.FirstOrDefault()), loc => Assert.Null(loc)); } [Fact] public void CreateTupleTypeSymbol_Tuple9NoNames() { var comp = CSharpCompilation.Create("test", references: new[] { MscorlibRef }); // no ValueTuple TypeSymbol intType = comp.GetSpecialType(SpecialType.System_Int32); TypeSymbol stringType = comp.GetSpecialType(SpecialType.System_String); var vt9 = comp.GetWellKnownType(WellKnownType.System_ValueTuple_TRest) .Construct(intType, stringType, intType, stringType, intType, stringType, intType, comp.GetWellKnownType(WellKnownType.System_ValueTuple_T2).Construct(stringType, intType)); var tuple9WithoutNames = comp.CreateTupleTypeSymbol(vt9, default(ImmutableArray)); Assert.True(tuple9WithoutNames.IsTupleType); Assert.Equal("System.ValueTuple[missing]", tuple9WithoutNames.ToTestDisplayString()); Assert.True(GetTupleElementNames(tuple9WithoutNames).IsDefault); Assert.Equal(new[] { "System.Int32", "System.String", "System.Int32", "System.String", "System.Int32", "System.String", "System.Int32", "System.String", "System.Int32" }, ElementTypeNames(tuple9WithoutNames)); Assert.All(tuple9WithoutNames.GetMembers().OfType().Select(f => f.Locations.FirstOrDefault()), loc => Assert.Null(loc)); } [Fact] public void CreateTupleTypeSymbol_Tuple9WithNames() { var comp = CSharpCompilation.Create("test", references: new[] { MscorlibRef }); // no ValueTuple TypeSymbol intType = comp.GetSpecialType(SpecialType.System_Int32); TypeSymbol stringType = comp.GetSpecialType(SpecialType.System_String); var vt9 = comp.GetWellKnownType(WellKnownType.System_ValueTuple_TRest) .Construct(intType, stringType, intType, stringType, intType, stringType, intType, comp.GetWellKnownType(WellKnownType.System_ValueTuple_T2).Construct(stringType, intType)); var tuple9WithNames = comp.CreateTupleTypeSymbol(vt9, ImmutableArray.Create("Alice1", "Alice2", "Alice3", "Alice4", "Alice5", "Alice6", "Alice7", "Alice8", "Alice9")); Assert.True(tuple9WithNames.IsTupleType); AssertEx.Equal("System.ValueTuple[missing]", tuple9WithNames.ToTestDisplayString()); Assert.Equal(new[] { "Alice1", "Alice2", "Alice3", "Alice4", "Alice5", "Alice6", "Alice7", "Alice8", "Alice9" }, GetTupleElementNames(tuple9WithNames)); Assert.Equal(new[] { "System.Int32", "System.String", "System.Int32", "System.String", "System.Int32", "System.String", "System.Int32", "System.String", "System.Int32" }, ElementTypeNames(tuple9WithNames)); Assert.All(tuple9WithNames.GetMembers().OfType().Select(f => f.Locations.FirstOrDefault()), loc => Assert.Null(loc)); } [Fact] public void CreateTupleTypeSymbol_Tuple9WithDefaultNames() { var comp = CSharpCompilation.Create("test", references: new[] { MscorlibRef }); // no ValueTuple TypeSymbol intType = comp.GetSpecialType(SpecialType.System_Int32); TypeSymbol stringType = comp.GetSpecialType(SpecialType.System_String); var originalVT2 = comp.GetWellKnownType(WellKnownType.System_ValueTuple_T2); Assert.True(originalVT2.IsDefinition); var vt2 = originalVT2.Construct(intType, intType); Assert.False(vt2.IsDefinition); comp.CreateTupleTypeSymbol(vt2, new[] { "Item1", "Item2" }.AsImmutable()); var vt9 = comp.GetWellKnownType(WellKnownType.System_ValueTuple_TRest) .Construct(intType, stringType, intType, stringType, intType, stringType, intType, vt2); var tuple9WithNames = comp.CreateTupleTypeSymbol(vt9, ImmutableArray.Create("Item1", "Item2", "Item3", "Item4", "Item5", "Item6", "Item7", "Item8", "Item9")); Assert.True(tuple9WithNames.IsTupleType); Assert.Equal("System.ValueTuple[missing]", tuple9WithNames.ToTestDisplayString()); Assert.Equal(new[] { "Item1", "Item2", "Item3", "Item4", "Item5", "Item6", "Item7", "Item8", "Item9" }, GetTupleElementNames(tuple9WithNames)); Assert.Equal(new[] { "System.Int32", "System.String", "System.Int32", "System.String", "System.Int32", "System.String", "System.Int32", "System.Int32", "System.Int32" }, ElementTypeNames(tuple9WithNames)); Assert.All(tuple9WithNames.GetMembers().OfType().Select(f => f.Locations.FirstOrDefault()), loc => Assert.Null(loc)); } [Fact] public void CreateTupleTypeSymbol_ElementTypeIsError() { var tupleComp = CreateCompilation(trivial2uple + trivial3uple + trivialRemainingTuples); var comp = CSharpCompilation.Create("test", references: new[] { MscorlibRef, tupleComp.ToMetadataReference() }); TypeSymbol intType = comp.GetSpecialType(SpecialType.System_Int32); var vt2 = comp.GetWellKnownType(WellKnownType.System_ValueTuple_T2); var vt2WithErrorType = vt2.Construct(intType, ErrorTypeSymbol.UnknownResultType); var tupleWithoutNames = ((Symbols.PublicModel.NamedTypeSymbol)comp.CreateTupleTypeSymbol(vt2WithErrorType, elementNames: default)).UnderlyingNamedTypeSymbol; Assert.Same(vt2WithErrorType, tupleWithoutNames); Assert.Equal(SymbolKind.NamedType, tupleWithoutNames.Kind); var types = tupleWithoutNames.TupleElements.SelectAsArray(e => e.Type); Assert.Equal(2, types.Length); Assert.Equal(SymbolKind.NamedType, types[0].Kind); Assert.Equal(SymbolKind.ErrorType, types[1].Kind); Assert.All(tupleWithoutNames.GetMembers().OfType().Select(f => f.Locations.FirstOrDefault()), loc => Assert.Null(loc)); } [Fact, WorkItem(13277, "https://github.com/dotnet/roslyn/issues/13277")] [WorkItem(14365, "https://github.com/dotnet/roslyn/issues/14365")] public void CreateTupleTypeSymbol_UnderlyingTypeIsError() { var comp = (Compilation)CSharpCompilation.Create("test", references: new[] { MscorlibRef, TestReferences.SymbolsTests.netModule.netModule1 }); ITypeSymbol intType = comp.GetSpecialType(SpecialType.System_Int32); var vt2 = comp.CreateErrorTypeSymbol(null, "ValueTuple", 2).Construct(intType, intType); Assert.Throws(() => comp.CreateTupleTypeSymbol(underlyingType: vt2)); var vbComp = CreateVisualBasicCompilation(""); Assert.Throws(() => comp.CreateErrorTypeSymbol(null, null, 2)); Assert.Throws(() => comp.CreateErrorTypeSymbol(null, "a", -1)); Assert.Throws(() => comp.CreateErrorTypeSymbol(vbComp.GlobalNamespace, "a", 1)); Assert.Throws(() => comp.CreateErrorNamespaceSymbol(null, "a")); Assert.Throws(() => comp.CreateErrorNamespaceSymbol(vbComp.GlobalNamespace, null)); Assert.Throws(() => comp.CreateErrorNamespaceSymbol(vbComp.GlobalNamespace, "a")); var ns = comp.CreateErrorNamespaceSymbol(comp.GlobalNamespace, "a"); Assert.Equal("a", ns.ToTestDisplayString()); Assert.False(ns.IsGlobalNamespace); Assert.Equal(NamespaceKind.Compilation, ns.NamespaceKind); Assert.Same(comp.GlobalNamespace, ns.ContainingSymbol); Assert.Same(comp.GlobalNamespace.ContainingAssembly, ns.ContainingAssembly); Assert.Same(comp.GlobalNamespace.ContainingModule, ns.ContainingModule); ns = comp.CreateErrorNamespaceSymbol(comp.Assembly.GlobalNamespace, "a"); Assert.Equal("a", ns.ToTestDisplayString()); Assert.False(ns.IsGlobalNamespace); Assert.Equal(NamespaceKind.Assembly, ns.NamespaceKind); Assert.Same(comp.Assembly.GlobalNamespace, ns.ContainingSymbol); Assert.Same(comp.Assembly.GlobalNamespace.ContainingAssembly, ns.ContainingAssembly); Assert.Same(comp.Assembly.GlobalNamespace.ContainingModule, ns.ContainingModule); ns = comp.CreateErrorNamespaceSymbol(comp.SourceModule.GlobalNamespace, "a"); Assert.Equal("a", ns.ToTestDisplayString()); Assert.False(ns.IsGlobalNamespace); Assert.Equal(NamespaceKind.Module, ns.NamespaceKind); Assert.Same(comp.SourceModule.GlobalNamespace, ns.ContainingSymbol); Assert.Same(comp.SourceModule.GlobalNamespace.ContainingAssembly, ns.ContainingAssembly); Assert.Same(comp.SourceModule.GlobalNamespace.ContainingModule, ns.ContainingModule); ns = comp.CreateErrorNamespaceSymbol(comp.CreateErrorNamespaceSymbol(comp.GlobalNamespace, "a"), "b"); Assert.Equal("a.b", ns.ToTestDisplayString()); ns = comp.CreateErrorNamespaceSymbol(comp.GlobalNamespace, ""); Assert.Equal("", ns.ToTestDisplayString()); Assert.False(ns.IsGlobalNamespace); vt2 = comp.CreateErrorTypeSymbol(comp.CreateErrorNamespaceSymbol(comp.GlobalNamespace, "System"), "ValueTuple", 2).Construct(intType, intType); Assert.Equal("(System.Int32, System.Int32)[missing]", comp.CreateTupleTypeSymbol(underlyingType: vt2).ToTestDisplayString()); vt2 = comp.CreateErrorTypeSymbol(comp.CreateErrorNamespaceSymbol(comp.Assembly.GlobalNamespace, "System"), "ValueTuple", 2).Construct(intType, intType); Assert.Equal("(System.Int32, System.Int32)[missing]", comp.CreateTupleTypeSymbol(underlyingType: vt2).ToTestDisplayString()); vt2 = comp.CreateErrorTypeSymbol(comp.CreateErrorNamespaceSymbol(comp.SourceModule.GlobalNamespace, "System"), "ValueTuple", 2).Construct(intType, intType); Assert.Equal("(System.Int32, System.Int32)[missing]", comp.CreateTupleTypeSymbol(underlyingType: vt2).ToTestDisplayString()); } [Fact] public void CreateTupleTypeSymbol_BadNames() { var comp = CSharpCompilation.Create("test", references: new[] { MscorlibRef }); NamedTypeSymbol intType = comp.GetSpecialType(SpecialType.System_Int32); var vt2 = comp.GetWellKnownType(WellKnownType.System_ValueTuple_T2).Construct(intType, intType); var vt3 = comp.GetWellKnownType(WellKnownType.System_ValueTuple_T3).Construct(intType, intType, intType); // illegal C# identifiers, space and null var tuple2 = comp.CreateTupleTypeSymbol(vt3, ImmutableArray.Create("123", " ", null)); Assert.Equal(new[] { "123", " ", null }, GetTupleElementNames(tuple2)); // reserved identifiers var tuple3 = comp.CreateTupleTypeSymbol(vt2, ImmutableArray.Create("return", "class")); Assert.Equal(new[] { "return", "class" }, GetTupleElementNames(tuple3)); // not tuple-compatible underlying type var e = Assert.Throws(() => comp.CreateTupleTypeSymbol(intType)); Assert.Contains(CodeAnalysisResources.TupleUnderlyingTypeMustBeTupleCompatible, e.Message); } [Fact] public void CreateTupleTypeSymbol_EmptyNames() { var comp = CSharpCompilation.Create("test", references: new[] { MscorlibRef }); NamedTypeSymbol intType = comp.GetSpecialType(SpecialType.System_Int32); var vt2 = comp.GetWellKnownType(WellKnownType.System_ValueTuple_T2).Construct(intType, intType); // illegal C# identifiers and blank var e = Assert.Throws(() => comp.CreateTupleTypeSymbol(vt2, ImmutableArray.Create("123", ""))); Assert.Contains(CodeAnalysisResources.TupleElementNameEmpty, e.Message); Assert.Contains("elementNames[1]", e.Message); } [Fact] public void CreateTupleTypeSymbol_VisualBasicElements() { var vbSource = @"Public Class C End Class"; var vbComp = CreateVisualBasicCompilation("VB", vbSource, compilationOptions: new VisualBasic.VisualBasicCompilationOptions(OutputKind.DynamicallyLinkedLibrary)); vbComp.VerifyDiagnostics(); INamedTypeSymbol vbType = (INamedTypeSymbol)vbComp.GlobalNamespace.GetMembers("C").Single(); var comp = CSharpCompilation.Create("test", references: new[] { MscorlibRef }); var e = Assert.Throws(() => comp.CreateTupleTypeSymbol(vbType, default(ImmutableArray))); Assert.Contains(CSharpResources.NotACSharpSymbol, e.Message); } [Fact] public void CreateAnonymousTypeSymbol_VisualBasicElements() { var vbSource = @"Public Class C End Class"; var vbComp = CreateVisualBasicCompilation("VB", vbSource, compilationOptions: new VisualBasic.VisualBasicCompilationOptions(OutputKind.DynamicallyLinkedLibrary)); vbComp.VerifyDiagnostics(); var vbType = (ITypeSymbol)vbComp.GlobalNamespace.GetMembers("C").Single(); var comp = CSharpCompilation.Create("test", references: new[] { MscorlibRef }); var e = Assert.Throws(() => comp.CreateAnonymousTypeSymbol(ImmutableArray.Create(vbType), ImmutableArray.Create("m1"))); Assert.Contains(CSharpResources.NotACSharpSymbol, e.Message); } [Fact] public void CreateTupleTypeSymbol2_BadArguments() { var comp = CSharpCompilation.Create("test", references: new[] { MscorlibRef }); // no ValueTuple TypeSymbol intType = comp.GetSpecialType(SpecialType.System_Int32); Assert.Throws(() => comp.CreateTupleTypeSymbol(default(ImmutableArray), default(ImmutableArray))); // 0-tuple and 1-tuple are not supported at this point Assert.Throws(() => comp.CreateTupleTypeSymbol(ImmutableArray.Empty, default(ImmutableArray))); Assert.Throws(() => comp.CreateTupleTypeSymbol(new[] { intType }.AsImmutable(), default(ImmutableArray))); // if names are provided, you need one for each element Assert.Throws(() => comp.CreateTupleTypeSymbol(new[] { intType, intType }.AsImmutable(), new[] { "Item1" }.AsImmutable())); var syntaxTree = CSharpSyntaxTree.ParseText("class C { }"); var loc1 = Location.Create(syntaxTree, new TextSpan(0, 1)); Assert.Throws(() => comp.CreateTupleTypeSymbol(new[] { intType, intType }.AsImmutable(), elementLocations: ImmutableArray.Create(loc1))); // null types aren't allowed Assert.Throws(() => comp.CreateTupleTypeSymbol(new[] { intType, null }.AsImmutable(), default(ImmutableArray))); } [Fact] public void CreateTupleTypeSymbol2_WithValueTuple() { var tupleComp = CreateCompilation(trivial2uple + trivial3uple + trivialRemainingTuples); var comp = CSharpCompilation.Create("test", references: new[] { MscorlibRef, tupleComp.ToMetadataReference() }); TypeSymbol intType = comp.GetSpecialType(SpecialType.System_Int32); TypeSymbol stringType = comp.GetSpecialType(SpecialType.System_String); var tupleWithoutNames = comp.CreateTupleTypeSymbol(ImmutableArray.Create(intType, stringType), ImmutableArray.Create(null, null)); Assert.True(tupleWithoutNames.IsTupleType); Assert.Equal("(System.Int32, System.String)", tupleWithoutNames.ToTestDisplayString()); Assert.True(GetTupleElementNames(tupleWithoutNames).IsDefault); Assert.Equal(new[] { "System.Int32", "System.String" }, ElementTypeNames(tupleWithoutNames)); Assert.Equal(SymbolKind.NamedType, tupleWithoutNames.Kind); Assert.True(tupleWithoutNames.GetMembers("Item1").Single().Locations.IsEmpty); } [Fact] public void CreateTupleTypeSymbol_WithLocations() { var tupleComp = CreateCompilation(trivial2uple + trivial3uple + trivialRemainingTuples); var comp = CSharpCompilation.Create("test", references: new[] { MscorlibRef, tupleComp.ToMetadataReference() }); var intType = comp.GetSpecialType(SpecialType.System_Int32); var stringType = comp.GetSpecialType(SpecialType.System_String); var syntaxTree = CSharpSyntaxTree.ParseText("class C { }"); var loc1 = Location.Create(syntaxTree, new TextSpan(0, 1)); var loc2 = Location.Create(syntaxTree, new TextSpan(1, 1)); var tuple = comp.CreateTupleTypeSymbol( ImmutableArray.Create(intType, stringType), ImmutableArray.Create(null, null), ImmutableArray.Create(loc1, loc2)); Assert.True(tuple.IsTupleType); Assert.Equal("(System.Int32, System.String)", tuple.ToTestDisplayString()); Assert.True(GetTupleElementNames(tuple).IsDefault); Assert.Equal(new[] { "System.Int32", "System.String" }, ElementTypeNames(tuple)); Assert.Equal(SymbolKind.NamedType, tuple.Kind); Assert.Equal(loc1, tuple.GetMembers("Item1").Single().Locations.Single()); Assert.Equal(loc2, tuple.GetMembers("Item2").Single().Locations.Single()); } private static IEnumerable ElementTypeNames(INamedTypeSymbol tuple) { return tuple.TupleElements.Select(t => t.Type.ToTestDisplayString()); } [Fact] public void CreateTupleTypeSymbol2_NoNames() { var comp = CSharpCompilation.Create("test", references: new[] { MscorlibRef }); // no ValueTuple TypeSymbol intType = comp.GetSpecialType(SpecialType.System_Int32); TypeSymbol stringType = comp.GetSpecialType(SpecialType.System_String); var tupleWithoutNames = comp.CreateTupleTypeSymbol(ImmutableArray.Create(intType, stringType), default(ImmutableArray)); Assert.True(tupleWithoutNames.IsTupleType); Assert.Equal("(System.Int32, System.String)[missing]", tupleWithoutNames.ToTestDisplayString()); Assert.True(GetTupleElementNames(tupleWithoutNames).IsDefault); Assert.Equal(new[] { "System.Int32", "System.String" }, ElementTypeNames(tupleWithoutNames)); Assert.Equal(SymbolKind.ErrorType, tupleWithoutNames.Kind); } [Fact] public void CreateTupleTypeSymbol2_WithNames() { var comp = CSharpCompilation.Create("test", references: new[] { MscorlibRef }); // no ValueTuple TypeSymbol intType = comp.GetSpecialType(SpecialType.System_Int32); TypeSymbol stringType = comp.GetSpecialType(SpecialType.System_String); var tupleWithNames = comp.CreateTupleTypeSymbol(ImmutableArray.Create(intType, stringType), ImmutableArray.Create("Alice", "Bob")); Assert.True(tupleWithNames.IsTupleType); Assert.Equal("(System.Int32 Alice, System.String Bob)[missing]", tupleWithNames.ToTestDisplayString()); Assert.Equal(new[] { "Alice", "Bob" }, GetTupleElementNames(tupleWithNames)); Assert.Equal(new[] { "System.Int32", "System.String" }, ElementTypeNames(tupleWithNames)); Assert.Equal(SymbolKind.ErrorType, tupleWithNames.Kind); } [Fact] public void CreateTupleTypeSymbol2_WithBadNames() { var comp = CSharpCompilation.Create("test", references: new[] { MscorlibRef }); // no ValueTuple TypeSymbol intType = comp.GetSpecialType(SpecialType.System_Int32); var tupleWithNames = comp.CreateTupleTypeSymbol(ImmutableArray.Create(intType, intType), ImmutableArray.Create("Item2", "Item1")); Assert.True(tupleWithNames.IsTupleType); Assert.Equal("(System.Int32 Item2, System.Int32 Item1)[missing]", tupleWithNames.ToTestDisplayString()); Assert.Equal(new[] { "Item2", "Item1" }, GetTupleElementNames(tupleWithNames)); Assert.Equal(new[] { "System.Int32", "System.Int32" }, ElementTypeNames(tupleWithNames)); Assert.Equal(SymbolKind.ErrorType, tupleWithNames.Kind); } [Fact] public void CreateTupleTypeSymbol2_Tuple8NoNames() { var comp = CSharpCompilation.Create("test", references: new[] { MscorlibRef }); // no ValueTuple TypeSymbol intType = comp.GetSpecialType(SpecialType.System_Int32); TypeSymbol stringType = comp.GetSpecialType(SpecialType.System_String); var tuple8WithoutNames = comp.CreateTupleTypeSymbol(ImmutableArray.Create(intType, stringType, intType, stringType, intType, stringType, intType, stringType), default(ImmutableArray)); Assert.True(tuple8WithoutNames.IsTupleType); Assert.Equal("System.ValueTuple[missing]>[missing]", tuple8WithoutNames.ToTestDisplayString()); Assert.True(GetTupleElementNames(tuple8WithoutNames).IsDefault); Assert.Equal(new[] { "System.Int32", "System.String", "System.Int32", "System.String", "System.Int32", "System.String", "System.Int32", "System.String" }, ElementTypeNames(tuple8WithoutNames)); } [Fact] public void CreateTupleTypeSymbol2_Tuple8WithNames() { var comp = CSharpCompilation.Create("test", references: new[] { MscorlibRef }); // no ValueTuple TypeSymbol intType = comp.GetSpecialType(SpecialType.System_Int32); TypeSymbol stringType = comp.GetSpecialType(SpecialType.System_String); var tuple8WithNames = comp.CreateTupleTypeSymbol(ImmutableArray.Create(intType, stringType, intType, stringType, intType, stringType, intType, stringType), ImmutableArray.Create("Alice1", "Alice2", "Alice3", "Alice4", "Alice5", "Alice6", "Alice7", "Alice8")); Assert.True(tuple8WithNames.IsTupleType); AssertEx.Equal("System.ValueTuple[missing]>[missing]", tuple8WithNames.ToTestDisplayString()); Assert.Equal(new[] { "Alice1", "Alice2", "Alice3", "Alice4", "Alice5", "Alice6", "Alice7", "Alice8" }, GetTupleElementNames(tuple8WithNames)); Assert.Equal(new[] { "System.Int32", "System.String", "System.Int32", "System.String", "System.Int32", "System.String", "System.Int32", "System.String" }, ElementTypeNames(tuple8WithNames)); } [Fact] public void CreateTupleTypeSymbol2_Tuple9NoNames() { var comp = CSharpCompilation.Create("test", references: new[] { MscorlibRef }); // no ValueTuple TypeSymbol intType = comp.GetSpecialType(SpecialType.System_Int32); TypeSymbol stringType = comp.GetSpecialType(SpecialType.System_String); var tuple9WithoutNames = comp.CreateTupleTypeSymbol(ImmutableArray.Create(intType, stringType, intType, stringType, intType, stringType, intType, stringType, intType), default(ImmutableArray)); Assert.True(tuple9WithoutNames.IsTupleType); AssertEx.Equal("System.ValueTuple[missing]", tuple9WithoutNames.ToTestDisplayString()); Assert.False(tuple9WithoutNames.IsDefinition); Assert.True(GetTupleElementNames(tuple9WithoutNames).IsDefault); Assert.Equal(new[] { "System.Int32", "System.String", "System.Int32", "System.String", "System.Int32", "System.String", "System.Int32", "System.String", "System.Int32" }, ElementTypeNames(tuple9WithoutNames)); } [Fact] public void CreateTupleTypeSymbol2_Tuple9WithNames() { var comp = CSharpCompilation.Create("test", references: new[] { MscorlibRef }); // no ValueTuple TypeSymbol intType = comp.GetSpecialType(SpecialType.System_Int32); TypeSymbol stringType = comp.GetSpecialType(SpecialType.System_String); var tuple9WithNames = comp.CreateTupleTypeSymbol(ImmutableArray.Create(intType, stringType, intType, stringType, intType, stringType, intType, stringType, intType), ImmutableArray.Create("Alice1", "Alice2", "Alice3", "Alice4", "Alice5", "Alice6", "Alice7", "Alice8", "Alice9")); Assert.True(tuple9WithNames.IsTupleType); AssertEx.Equal("System.ValueTuple[missing]", tuple9WithNames.ToTestDisplayString()); Assert.False(tuple9WithNames.IsDefinition); Assert.Equal(new[] { "Alice1", "Alice2", "Alice3", "Alice4", "Alice5", "Alice6", "Alice7", "Alice8", "Alice9" }, GetTupleElementNames(tuple9WithNames)); Assert.Equal(new[] { "System.Int32", "System.String", "System.Int32", "System.String", "System.Int32", "System.String", "System.Int32", "System.String", "System.Int32" }, ElementTypeNames(tuple9WithNames)); } [Fact] public void CreateTupleTypeSymbol2_ElementTypeIsError() { var tupleComp = CreateCompilation(trivial2uple + trivial3uple + trivialRemainingTuples); var comp = CSharpCompilation.Create("test", references: new[] { MscorlibRef, tupleComp.ToMetadataReference() }); TypeSymbol intType = comp.GetSpecialType(SpecialType.System_Int32); var tupleWithoutNames = comp.CreateTupleTypeSymbol(ImmutableArray.Create(intType, ErrorTypeSymbol.UnknownResultType), default(ImmutableArray)); Assert.Equal(SymbolKind.NamedType, tupleWithoutNames.Kind); var types = tupleWithoutNames.TupleElements.SelectAsArray(e => e.Type); Assert.Equal(2, types.Length); Assert.Equal(SymbolKind.NamedType, types[0].Kind); Assert.Equal(SymbolKind.ErrorType, types[1].Kind); } [Fact] public void CreateTupleTypeSymbol2_BadNames() { var comp = CSharpCompilation.Create("test", references: new[] { MscorlibRef }); TypeSymbol intType = comp.GetSpecialType(SpecialType.System_Int32); // illegal C# identifiers and blank var tuple2 = comp.CreateTupleTypeSymbol(ImmutableArray.Create(intType, intType), ImmutableArray.Create("123", " ")); Assert.Equal(new[] { "123", " " }, GetTupleElementNames(tuple2)); // reserved identifiers var tuple3 = comp.CreateTupleTypeSymbol(ImmutableArray.Create(intType, intType), ImmutableArray.Create("return", "class")); Assert.Equal(new[] { "return", "class" }, GetTupleElementNames(tuple3)); } [Fact] public void CreateTupleTypeSymbol2_VisualBasicElements() { var vbSource = @"Public Class C End Class"; var vbComp = CreateVisualBasicCompilation("VB", vbSource, compilationOptions: new VisualBasic.VisualBasicCompilationOptions(OutputKind.DynamicallyLinkedLibrary)); vbComp.VerifyDiagnostics(); ITypeSymbol vbType = (ITypeSymbol)vbComp.GlobalNamespace.GetMembers("C").Single(); var comp = CSharpCompilation.Create("test", references: new[] { MscorlibRef }); INamedTypeSymbol intType = comp.GetSpecialType(SpecialType.System_String).GetPublicSymbol(); Assert.Throws(() => comp.CreateTupleTypeSymbol(ImmutableArray.Create(intType, vbType), default(ImmutableArray))); } [Fact] public void CreateTupleTypeSymbol_ComparingSymbols() { var source = @" class C { System.ValueTuple F; } "; var comp = (Compilation)CreateCompilation(source); var tuple1 = (INamedTypeSymbol)comp.SourceModule.GlobalNamespace.GetMember("C").GetMember("F").Type; var intType = comp.GetSpecialType(SpecialType.System_Int32); var stringType = comp.GetSpecialType(SpecialType.System_String); var twoStrings = comp.GetWellKnownType(WellKnownType.System_ValueTuple_T2).Construct(stringType, stringType); var twoStringsWithNames = comp.CreateTupleTypeSymbol(twoStrings, ImmutableArray.Create("a", "b")); var tuple2Underlying = comp.GetWellKnownType(WellKnownType.System_ValueTuple_TRest).Construct(intType, intType, intType, intType, intType, intType, intType, twoStringsWithNames); var tuple2 = comp.CreateTupleTypeSymbol(tuple2Underlying); var tuple3 = comp.CreateTupleTypeSymbol(ImmutableArray.Create(intType, intType, intType, intType, intType, intType, intType, stringType, stringType), ImmutableArray.Create("Item1", "Item2", "Item3", "Item4", "Item5", "Item6", "Item7", "a", "b")); var tuple4 = comp.CreateTupleTypeSymbol(tuple1, ImmutableArray.Create("Item1", "Item2", "Item3", "Item4", "Item5", "Item6", "Item7", "a", "b")); Assert.True(tuple1.Equals(tuple2)); Assert.True(tuple1.Equals(tuple2, TypeCompareKind.IgnoreDynamicAndTupleNames)); Assert.False(tuple1.Equals(tuple3)); Assert.True(tuple1.Equals(tuple3, TypeCompareKind.IgnoreDynamicAndTupleNames)); Assert.False(tuple1.Equals(tuple4)); Assert.True(tuple1.Equals(tuple4, TypeCompareKind.IgnoreDynamicAndTupleNames)); } [Fact] [WorkItem(36047, "https://github.com/dotnet/roslyn/issues/36047")] public void CreateTupleTypeSymbol_UnderlyingType_DefaultArgs_01() { var source = @"class Program { (int, string) F; }"; var comp = (Compilation)CreateCompilation(source); var tuple1 = (INamedTypeSymbol)((IFieldSymbol)comp.GetMember("Program.F")).Type; Assert.Null(tuple1.TupleUnderlyingType); var underlyingType = tuple1; var tuple2 = comp.CreateTupleTypeSymbol(underlyingType); Assert.True(tuple1.Equals(tuple2, TypeCompareKind.ConsiderEverything)); tuple2 = comp.CreateTupleTypeSymbol(underlyingType, default); Assert.True(tuple1.Equals(tuple2, TypeCompareKind.ConsiderEverything)); tuple2 = comp.CreateTupleTypeSymbol(underlyingType, default, default); Assert.True(tuple1.Equals(tuple2, TypeCompareKind.ConsiderEverything)); tuple2 = comp.CreateTupleTypeSymbol(underlyingType, default, default, default); Assert.True(tuple1.Equals(tuple2, TypeCompareKind.ConsiderEverything)); tuple2 = comp.CreateTupleTypeSymbol(underlyingType, default(ImmutableArray), default(ImmutableArray), default(ImmutableArray)); Assert.True(tuple1.Equals(tuple2, TypeCompareKind.ConsiderEverything)); tuple2 = comp.CreateTupleTypeSymbol(underlyingType, elementNames: default); Assert.True(tuple1.Equals(tuple2, TypeCompareKind.ConsiderEverything)); tuple2 = comp.CreateTupleTypeSymbol(underlyingType, elementLocations: default); Assert.True(tuple1.Equals(tuple2, TypeCompareKind.ConsiderEverything)); tuple2 = comp.CreateTupleTypeSymbol(underlyingType, elementNullableAnnotations: default); Assert.True(tuple1.Equals(tuple2, TypeCompareKind.ConsiderEverything)); } [Fact] [WorkItem(36047, "https://github.com/dotnet/roslyn/issues/36047")] [WorkItem(40105, "https://github.com/dotnet/roslyn/issues/40105")] public void CreateTupleTypeSymbol_UnderlyingType_DefaultArgs_02() { var source = @"class Program { (string, #nullable enable string, string?) F; }"; var comp = (Compilation)CreateCompilation(source); var tuple1 = (INamedTypeSymbol)((IFieldSymbol)comp.GetMember("Program.F")).Type; Assert.Null(tuple1.TupleUnderlyingType); var underlyingType = tuple1; var tuple2 = comp.CreateTupleTypeSymbol(underlyingType); Assert.True(tuple1.Equals(tuple2, TypeCompareKind.ConsiderEverything)); tuple2 = comp.CreateTupleTypeSymbol(underlyingType, default); Assert.True(tuple1.Equals(tuple2, TypeCompareKind.ConsiderEverything)); tuple2 = comp.CreateTupleTypeSymbol(underlyingType, default, default); Assert.True(tuple1.Equals(tuple2, TypeCompareKind.ConsiderEverything)); tuple2 = comp.CreateTupleTypeSymbol(underlyingType, default, default, default); Assert.True(tuple1.Equals(tuple2, TypeCompareKind.ConsiderEverything)); tuple2 = comp.CreateTupleTypeSymbol(underlyingType, default(ImmutableArray), default(ImmutableArray), default(ImmutableArray)); Assert.True(tuple1.Equals(tuple2, TypeCompareKind.ConsiderEverything)); tuple2 = comp.CreateTupleTypeSymbol(underlyingType, elementNames: default); Assert.True(tuple1.Equals(tuple2, TypeCompareKind.ConsiderEverything)); tuple2 = comp.CreateTupleTypeSymbol(underlyingType, elementLocations: default); Assert.True(tuple1.Equals(tuple2, TypeCompareKind.ConsiderEverything)); tuple2 = comp.CreateTupleTypeSymbol(underlyingType, elementNullableAnnotations: default); Assert.True(tuple1.Equals(tuple2, TypeCompareKind.ConsiderEverything)); } [Fact] [WorkItem(36047, "https://github.com/dotnet/roslyn/issues/36047")] public void CreateTupleTypeSymbol_ElementTypes_DefaultArgs_01() { var source = @"class Program { (int, string) F; }"; var comp = (Compilation)CreateCompilation(source); var tuple1 = (INamedTypeSymbol)((IFieldSymbol)comp.GetMember("Program.F")).Type; var elementTypes = tuple1.TupleElements.SelectAsArray(e => e.Type); var tuple2 = comp.CreateTupleTypeSymbol(elementTypes); Assert.True(tuple1.Equals(tuple2, TypeCompareKind.ConsiderEverything)); tuple2 = comp.CreateTupleTypeSymbol(elementTypes, default); Assert.True(tuple1.Equals(tuple2, TypeCompareKind.ConsiderEverything)); tuple2 = comp.CreateTupleTypeSymbol(elementTypes, default, default); Assert.True(tuple1.Equals(tuple2, TypeCompareKind.ConsiderEverything)); tuple2 = comp.CreateTupleTypeSymbol(elementTypes, default, default, default); Assert.True(tuple1.Equals(tuple2, TypeCompareKind.ConsiderEverything)); tuple2 = comp.CreateTupleTypeSymbol(elementTypes, default(ImmutableArray), default(ImmutableArray), default(ImmutableArray)); Assert.True(tuple1.Equals(tuple2, TypeCompareKind.ConsiderEverything)); tuple2 = comp.CreateTupleTypeSymbol(elementTypes, elementNames: default); Assert.True(tuple1.Equals(tuple2, TypeCompareKind.ConsiderEverything)); tuple2 = comp.CreateTupleTypeSymbol(elementTypes, elementLocations: default); Assert.True(tuple1.Equals(tuple2, TypeCompareKind.ConsiderEverything)); tuple2 = comp.CreateTupleTypeSymbol(elementTypes, elementNullableAnnotations: default); Assert.True(tuple1.Equals(tuple2, TypeCompareKind.ConsiderEverything)); } [Fact] [WorkItem(36047, "https://github.com/dotnet/roslyn/issues/36047")] [WorkItem(40105, "https://github.com/dotnet/roslyn/issues/40105")] public void CreateTupleTypeSymbol_ElementTypes_DefaultArgs_02() { var source = @"class Program { (string, #nullable enable string, string?) F; }"; var comp = (Compilation)CreateCompilation(source); var tuple1 = (INamedTypeSymbol)((IFieldSymbol)comp.GetMember("Program.F")).Type; var elementTypes = tuple1.TupleElements.SelectAsArray(e => e.Type); var tuple2 = comp.CreateTupleTypeSymbol(elementTypes); Assert.True(tuple1.Equals(tuple2, TypeCompareKind.ConsiderEverything)); tuple2 = comp.CreateTupleTypeSymbol(elementTypes, default); Assert.True(tuple1.Equals(tuple2, TypeCompareKind.ConsiderEverything)); tuple2 = comp.CreateTupleTypeSymbol(elementTypes, default, default); Assert.True(tuple1.Equals(tuple2, TypeCompareKind.ConsiderEverything)); tuple2 = comp.CreateTupleTypeSymbol(elementTypes, default, default, default); Assert.True(tuple1.Equals(tuple2, TypeCompareKind.ConsiderEverything)); tuple2 = comp.CreateTupleTypeSymbol(elementTypes, default(ImmutableArray), default(ImmutableArray), default(ImmutableArray)); Assert.True(tuple1.Equals(tuple2, TypeCompareKind.ConsiderEverything)); tuple2 = comp.CreateTupleTypeSymbol(elementTypes, elementNames: default); Assert.True(tuple1.Equals(tuple2, TypeCompareKind.ConsiderEverything)); tuple2 = comp.CreateTupleTypeSymbol(elementTypes, elementLocations: default); Assert.True(tuple1.Equals(tuple2, TypeCompareKind.ConsiderEverything)); tuple2 = comp.CreateTupleTypeSymbol(elementTypes, elementNullableAnnotations: default); Assert.True(tuple1.Equals(tuple2, TypeCompareKind.ConsiderEverything)); } [Fact] [WorkItem(36047, "https://github.com/dotnet/roslyn/issues/36047")] public void CreateTupleTypeSymbol_UnderlyingType_WithNullableAnnotations_01() { var source = @"class Program { (int, string) F; }"; var comp = CreateCompilation(source); var tuple1 = (INamedTypeSymbol)((FieldSymbol)comp.GetMember("Program.F")).GetPublicSymbol().Type; Assert.Null(tuple1.TupleUnderlyingType); var underlyingType = tuple1; var tuple2 = comp.CreateTupleTypeSymbol(underlyingType, elementNullableAnnotations: default); Assert.True(tuple1.Equals(tuple2, TypeCompareKind.ConsiderEverything)); var e = Assert.Throws(() => comp.CreateTupleTypeSymbol(underlyingType, elementNullableAnnotations: ImmutableArray.Empty)); Assert.Contains(CodeAnalysisResources.TupleElementNullableAnnotationCountMismatch, e.Message); tuple2 = comp.CreateTupleTypeSymbol( underlyingType, elementNullableAnnotations: ImmutableArray.Create(CodeAnalysis.NullableAnnotation.None, CodeAnalysis.NullableAnnotation.None)); Assert.True(tuple1.Equals(tuple2, TypeCompareKind.ConsiderEverything)); Assert.Equal("(System.Int32, System.String)", tuple2.ToTestDisplayString(includeNonNullable: true)); tuple2 = comp.CreateTupleTypeSymbol( underlyingType, elementNullableAnnotations: ImmutableArray.Create(CodeAnalysis.NullableAnnotation.NotAnnotated, CodeAnalysis.NullableAnnotation.Annotated)); Assert.True(tuple1.Equals(tuple2)); Assert.False(tuple1.Equals(tuple2, SymbolEqualityComparer.IncludeNullability)); Assert.Equal("(System.Int32, System.String?)", tuple2.ToTestDisplayString(includeNonNullable: true)); tuple2 = comp.CreateTupleTypeSymbol( underlyingType, elementNullableAnnotations: ImmutableArray.Create(CodeAnalysis.NullableAnnotation.Annotated, CodeAnalysis.NullableAnnotation.None)); Assert.True(tuple1.Equals(tuple2)); Assert.Equal("(System.Int32, System.String)", tuple2.ToTestDisplayString(includeNonNullable: true)); } [Fact] [WorkItem(36047, "https://github.com/dotnet/roslyn/issues/36047")] public void CreateTupleTypeSymbol_UnderlyingType_WithNullableAnnotations_02() { var source = @"class Program { (object _1, object _2, object _3, object _4, object _5, object _6, object _7, object _8, object _9) F; }"; var comp = (Compilation)CreateCompilation(source); var tuple1 = (INamedTypeSymbol)((IFieldSymbol)comp.GetMember("Program.F")).Type; var underlyingType = tuple1.TupleUnderlyingType; var tuple2 = comp.CreateTupleTypeSymbol(underlyingType, elementNullableAnnotations: default); Assert.True(TypeEquals(tuple1, tuple2, TypeCompareKind.IgnoreTupleNames)); Assert.Equal("(System.Object, System.Object, System.Object, System.Object, System.Object, System.Object, System.Object, System.Object, System.Object)", tuple2.ToTestDisplayString(includeNonNullable: true)); var e = Assert.Throws(() => comp.CreateTupleTypeSymbol(underlyingType, elementNullableAnnotations: CreateAnnotations(CodeAnalysis.NullableAnnotation.NotAnnotated, 8))); Assert.Contains(CodeAnalysisResources.TupleElementNullableAnnotationCountMismatch, e.Message); tuple2 = comp.CreateTupleTypeSymbol(underlyingType, elementNullableAnnotations: CreateAnnotations(CodeAnalysis.NullableAnnotation.None, 9)); Assert.True(TypeEquals(tuple1, tuple2, TypeCompareKind.IgnoreTupleNames)); Assert.Equal("(System.Object, System.Object, System.Object, System.Object, System.Object, System.Object, System.Object, System.Object, System.Object)", tuple2.ToTestDisplayString(includeNonNullable: true)); tuple2 = comp.CreateTupleTypeSymbol(underlyingType, elementNullableAnnotations: CreateAnnotations(CodeAnalysis.NullableAnnotation.Annotated, 9)); Assert.False(TypeEquals(tuple1, tuple2, TypeCompareKind.IgnoreTupleNames)); Assert.True(TypeEquals(tuple1, tuple2, TypeCompareKind.IgnoreTupleNames | TypeCompareKind.IgnoreNullableModifiersForReferenceTypes)); Assert.Equal("(System.Object?, System.Object?, System.Object?, System.Object?, System.Object?, System.Object?, System.Object?, System.Object?, System.Object?)", tuple2.ToTestDisplayString(includeNonNullable: true)); } [Fact] [WorkItem(36047, "https://github.com/dotnet/roslyn/issues/36047")] public void CreateTupleTypeSymbol_ElementTypes_WithNullableAnnotations_01() { var source = @"class Program { (int, string) F; }"; var comp = (Compilation)CreateCompilation(source); var tuple1 = (INamedTypeSymbol)((IFieldSymbol)comp.GetMember("Program.F")).Type; var elementTypes = tuple1.TupleElements.SelectAsArray(e => e.Type); var tuple2 = comp.CreateTupleTypeSymbol(elementTypes, elementNullableAnnotations: default); Assert.True(tuple1.Equals(tuple2)); var e = Assert.Throws(() => comp.CreateTupleTypeSymbol(elementTypes, elementNullableAnnotations: ImmutableArray.Empty)); Assert.Contains(CodeAnalysisResources.TupleElementNullableAnnotationCountMismatch, e.Message); tuple2 = comp.CreateTupleTypeSymbol( elementTypes, elementNullableAnnotations: ImmutableArray.Create(CodeAnalysis.NullableAnnotation.None, CodeAnalysis.NullableAnnotation.None)); Assert.True(tuple1.Equals(tuple2)); Assert.Equal("(System.Int32, System.String)", tuple2.ToTestDisplayString(includeNonNullable: true)); tuple2 = comp.CreateTupleTypeSymbol( elementTypes, elementNullableAnnotations: ImmutableArray.Create(CodeAnalysis.NullableAnnotation.NotAnnotated, CodeAnalysis.NullableAnnotation.Annotated)); Assert.True(tuple1.Equals(tuple2)); Assert.False(tuple1.Equals(tuple2, SymbolEqualityComparer.IncludeNullability)); Assert.Equal("(System.Int32, System.String?)", tuple2.ToTestDisplayString(includeNonNullable: true)); tuple2 = comp.CreateTupleTypeSymbol( elementTypes, elementNullableAnnotations: ImmutableArray.Create(CodeAnalysis.NullableAnnotation.Annotated, CodeAnalysis.NullableAnnotation.None)); Assert.True(tuple1.Equals(tuple2)); Assert.Equal("(System.Int32, System.String)", tuple2.ToTestDisplayString(includeNonNullable: true)); } [Fact] [WorkItem(36047, "https://github.com/dotnet/roslyn/issues/36047")] public void CreateTupleTypeSymbol_ElementTypes_WithNullableAnnotations_02() { var source = @"class Program { (object _1, object _2, object _3, object _4, object _5, object _6, object _7, object _8, object _9) F; }"; var comp = (Compilation)CreateCompilation(source); var tuple1 = (INamedTypeSymbol)((IFieldSymbol)comp.GetMember("Program.F")).Type; var elementTypes = tuple1.TupleElements.SelectAsArray(e => e.Type); var tuple2 = comp.CreateTupleTypeSymbol(elementTypes, elementNullableAnnotations: default); Assert.True(TypeEquals(tuple1, tuple2, TypeCompareKind.IgnoreTupleNames)); Assert.Equal("(System.Object, System.Object, System.Object, System.Object, System.Object, System.Object, System.Object, System.Object, System.Object)", tuple2.ToTestDisplayString(includeNonNullable: true)); var e = Assert.Throws(() => comp.CreateTupleTypeSymbol(elementTypes, elementNullableAnnotations: CreateAnnotations(CodeAnalysis.NullableAnnotation.NotAnnotated, 8))); Assert.Contains(CodeAnalysisResources.TupleElementNullableAnnotationCountMismatch, e.Message); tuple2 = comp.CreateTupleTypeSymbol(elementTypes, elementNullableAnnotations: CreateAnnotations(CodeAnalysis.NullableAnnotation.None, 9)); Assert.True(TypeEquals(tuple1, tuple2, TypeCompareKind.IgnoreTupleNames)); Assert.Equal("(System.Object, System.Object, System.Object, System.Object, System.Object, System.Object, System.Object, System.Object, System.Object)", tuple2.ToTestDisplayString(includeNonNullable: true)); tuple2 = comp.CreateTupleTypeSymbol(elementTypes, elementNullableAnnotations: CreateAnnotations(CodeAnalysis.NullableAnnotation.Annotated, 9)); Assert.False(TypeEquals(tuple1, tuple2, TypeCompareKind.IgnoreTupleNames)); Assert.True(TypeEquals(tuple1, tuple2, TypeCompareKind.IgnoreTupleNames | TypeCompareKind.IgnoreNullableModifiersForReferenceTypes)); Assert.Equal("(System.Object?, System.Object?, System.Object?, System.Object?, System.Object?, System.Object?, System.Object?, System.Object?, System.Object?)", tuple2.ToTestDisplayString(includeNonNullable: true)); } private static ImmutableArray CreateAnnotations(CodeAnalysis.NullableAnnotation annotation, int n) => ImmutableArray.CreateRange(Enumerable.Range(0, n).Select(_ => annotation)); private static bool TypeEquals(ITypeSymbol a, ITypeSymbol b, TypeCompareKind compareKind) => a.Equals(b, compareKind); [Fact] public void TupleMethodsOnNonTupleType() { var comp = CSharpCompilation.Create("test", references: new[] { MscorlibRef }); NamedTypeSymbol stringType = comp.GetSpecialType(SpecialType.System_String); Assert.False(stringType.IsTupleType); Assert.True(stringType.TupleElements.IsDefault); Assert.Null(stringType.TupleUnderlyingType); } [Fact] public void TupleTargetTypeAndConvert01() { var source = @" class C { static void Main() { // this works (short, string) x1 = (1, ""hello""); // this does not (short, string) x2 = ((long, string))(1, ""hello""); // this does not (short a, string b) x3 = ((long c, string d))(1, ""hello""); } } " + trivial2uple + tupleattributes_cs; var comp = CreateCompilation(source); comp.VerifyDiagnostics( // (10,30): error CS0266: Cannot implicitly convert type '(long, string)' to '(short, string)'. An explicit conversion exists (are you missing a cast?) // (short, string) x2 = ((long, string))(1, "hello"); Diagnostic(ErrorCode.ERR_NoImplicitConvCast, @"((long, string))(1, ""hello"")").WithArguments("(long, string)", "(short, string)").WithLocation(10, 30), // (13,34): error CS0266: Cannot implicitly convert type '(long c, string d)' to '(short a, string b)'. An explicit conversion exists (are you missing a cast?) // (short a, string b) x3 = ((long c, string d))(1, "hello"); Diagnostic(ErrorCode.ERR_NoImplicitConvCast, @"((long c, string d))(1, ""hello"")").WithArguments("(long c, string d)", "(short a, string b)").WithLocation(13, 34), // (7,25): warning CS0219: The variable 'x1' is assigned but its value is never used // (short, string) x1 = (1, "hello"); Diagnostic(ErrorCode.WRN_UnreferencedVarAssg, "x1").WithArguments("x1").WithLocation(7, 25), // (10,25): warning CS0219: The variable 'x2' is assigned but its value is never used // (short, string) x2 = ((long, string))(1, "hello"); Diagnostic(ErrorCode.WRN_UnreferencedVarAssg, "x2").WithArguments("x2").WithLocation(10, 25), // (13,29): warning CS0219: The variable 'x3' is assigned but its value is never used // (short a, string b) x3 = ((long c, string d))(1, "hello"); Diagnostic(ErrorCode.WRN_UnreferencedVarAssg, "x3").WithArguments("x3").WithLocation(13, 29) ); } [Fact] public void TupleTargetTypeAndConvert02() { var source = @" class C { static void Main() { (short, string) x2 = ((byte, string))(1, ""hello""); System.Console.WriteLine(x2); } } " + trivial2uple + tupleattributes_cs; var comp = CompileAndVerify(source, expectedOutput: @" {1, hello}"); comp.VerifyIL("C.Main()", @" { // Code size 41 (0x29) .maxstack 3 .locals init (System.ValueTuple V_0) IL_0000: ldloca.s V_0 IL_0002: ldc.i4.1 IL_0003: ldstr ""hello"" IL_0008: call ""System.ValueTuple..ctor(byte, string)"" IL_000d: ldloc.0 IL_000e: ldfld ""byte System.ValueTuple.Item1"" IL_0013: ldloc.0 IL_0014: ldfld ""string System.ValueTuple.Item2"" IL_0019: newobj ""System.ValueTuple..ctor(short, string)"" IL_001e: box ""System.ValueTuple"" IL_0023: call ""void System.Console.WriteLine(object)"" IL_0028: ret } "); ; } [Fact] [WorkItem(11875, "https://github.com/dotnet/roslyn/issues/11875")] public void TupleImplicitConversionFail01() { var source = @" class C { static void Main() { (int, int) x; x = (null, null, null); x = (1, 1, 1); x = (1, ""string""); x = (1, 1, garbage); x = (1, 1, ); x = (null, null); x = (1, null); x = (1, (t)=>t); x = null; } } " + trivial2uple + trivial3uple + tupleattributes_cs; CreateCompilation(source).VerifyDiagnostics( // (12,20): error CS1525: Invalid expression term ')' // x = (1, 1, ); Diagnostic(ErrorCode.ERR_InvalidExprTerm, ")").WithArguments(")").WithLocation(12, 20), // (8,13): error CS8129: Tuple with 3 elements cannot be converted to type '(int, int)'. // x = (null, null, null); Diagnostic(ErrorCode.ERR_ConversionNotTupleCompatible, "(null, null, null)").WithArguments("3", "(int, int)").WithLocation(8, 13), // (9,13): error CS0029: Cannot implicitly convert type '(int, int, int)' to '(int, int)' // x = (1, 1, 1); Diagnostic(ErrorCode.ERR_NoImplicitConv, "(1, 1, 1)").WithArguments("(int, int, int)", "(int, int)").WithLocation(9, 13), // (10,17): error CS0029: Cannot implicitly convert type 'string' to 'int' // x = (1, "string"); Diagnostic(ErrorCode.ERR_NoImplicitConv, @"""string""").WithArguments("string", "int").WithLocation(10, 17), // (11,20): error CS0103: The name 'garbage' does not exist in the current context // x = (1, 1, garbage); Diagnostic(ErrorCode.ERR_NameNotInContext, "garbage").WithArguments("garbage").WithLocation(11, 20), // (13,14): error CS0037: Cannot convert null to 'int' because it is a non-nullable value type // x = (null, null); Diagnostic(ErrorCode.ERR_ValueCantBeNull, "null").WithArguments("int").WithLocation(13, 14), // (13,20): error CS0037: Cannot convert null to 'int' because it is a non-nullable value type // x = (null, null); Diagnostic(ErrorCode.ERR_ValueCantBeNull, "null").WithArguments("int").WithLocation(13, 20), // (14,17): error CS0037: Cannot convert null to 'int' because it is a non-nullable value type // x = (1, null); Diagnostic(ErrorCode.ERR_ValueCantBeNull, "null").WithArguments("int").WithLocation(14, 17), // (15,17): error CS1660: Cannot convert lambda expression to type 'int' because it is not a delegate type // x = (1, (t)=>t); Diagnostic(ErrorCode.ERR_AnonMethToNonDel, "(t)=>t").WithArguments("lambda expression", "int").WithLocation(15, 17), // (16,13): error CS0037: Cannot convert null to '(int, int)' because it is a non-nullable value type // x = null; Diagnostic(ErrorCode.ERR_ValueCantBeNull, "null").WithArguments("(int, int)").WithLocation(16, 13) ); } [Fact] public void TupleExplicitConversionFail01() { var source = @" class C { static void Main() { (int, int) x; x = ((int, int))(null, null, null); x = ((int, int))(1, 1, 1); x = ((int, int))(1, ""string""); x = ((int, int))(1, 1, garbage); x = ((int, int))(1, 1, ); x = ((int, int))(null, null); x = ((int, int))(1, null); x = ((int, int))(1, (t)=>t); x = ((int, int))null; } } " + trivial2uple + trivial3uple + tupleattributes_cs; CreateCompilation(source, parseOptions: TestOptions.Regular).VerifyDiagnostics( // (12,32): error CS1525: Invalid expression term ')' // x = ((int, int))(1, 1, ); Diagnostic(ErrorCode.ERR_InvalidExprTerm, ")").WithArguments(")").WithLocation(12, 32), // (8,13): error CS8129: Tuple with 3 elements cannot be converted to type '(int, int)'. // x = ((int, int))(null, null, null); Diagnostic(ErrorCode.ERR_ConversionNotTupleCompatible, "((int, int))(null, null, null)").WithArguments("3", "(int, int)").WithLocation(8, 13), // (9,13): error CS0030: Cannot convert type '(int, int, int)' to '(int, int)' // x = ((int, int))(1, 1, 1); Diagnostic(ErrorCode.ERR_NoExplicitConv, "((int, int))(1, 1, 1)").WithArguments("(int, int, int)", "(int, int)").WithLocation(9, 13), // (10,29): error CS0030: Cannot convert type 'string' to 'int' // x = ((int, int))(1, "string"); Diagnostic(ErrorCode.ERR_NoExplicitConv, @"""string""").WithArguments("string", "int").WithLocation(10, 29), // (11,32): error CS0103: The name 'garbage' does not exist in the current context // x = ((int, int))(1, 1, garbage); Diagnostic(ErrorCode.ERR_NameNotInContext, "garbage").WithArguments("garbage").WithLocation(11, 32), // (13,26): error CS0037: Cannot convert null to 'int' because it is a non-nullable value type // x = ((int, int))(null, null); Diagnostic(ErrorCode.ERR_ValueCantBeNull, "null").WithArguments("int").WithLocation(13, 26), // (13,32): error CS0037: Cannot convert null to 'int' because it is a non-nullable value type // x = ((int, int))(null, null); Diagnostic(ErrorCode.ERR_ValueCantBeNull, "null").WithArguments("int").WithLocation(13, 32), // (14,29): error CS0037: Cannot convert null to 'int' because it is a non-nullable value type // x = ((int, int))(1, null); Diagnostic(ErrorCode.ERR_ValueCantBeNull, "null").WithArguments("int").WithLocation(14, 29), // (15,29): error CS1660: Cannot convert lambda expression to type 'int' because it is not a delegate type // x = ((int, int))(1, (t)=>t); Diagnostic(ErrorCode.ERR_AnonMethToNonDel, "(t)=>t").WithArguments("lambda expression", "int").WithLocation(15, 29), // (16,13): error CS0037: Cannot convert null to '(int, int)' because it is a non-nullable value type // x = ((int, int))null; Diagnostic(ErrorCode.ERR_ValueCantBeNull, "((int, int))null").WithArguments("(int, int)").WithLocation(16, 13) ); } [Fact] [WorkItem(11875, "https://github.com/dotnet/roslyn/issues/11875")] public void TupleImplicitConversionFail02() { var source = @" class C { static void Main() { System.ValueTuple x; x = (null, null, null); x = (1, 1, 1); x = (1, ""string""); x = (1, 1, garbage); x = (1, 1, ); x = (null, null); x = (1, null); x = (1, (t)=>t); x = null; } } " + trivial2uple + trivial3uple + tupleattributes_cs; CreateCompilationWithMscorlib40(source).VerifyDiagnostics( // (12,20): error CS1525: Invalid expression term ')' // x = (1, 1, ); Diagnostic(ErrorCode.ERR_InvalidExprTerm, ")").WithArguments(")").WithLocation(12, 20), // (8,13): error CS8129: Tuple with 3 elements cannot be converted to type '(int, int)'. // x = (null, null, null); Diagnostic(ErrorCode.ERR_ConversionNotTupleCompatible, "(null, null, null)").WithArguments("3", "(int, int)").WithLocation(8, 13), // (9,13): error CS0029: Cannot implicitly convert type '(int, int, int)' to '(int, int)' // x = (1, 1, 1); Diagnostic(ErrorCode.ERR_NoImplicitConv, "(1, 1, 1)").WithArguments("(int, int, int)", "(int, int)").WithLocation(9, 13), // (10,17): error CS0029: Cannot implicitly convert type 'string' to 'int' // x = (1, "string"); Diagnostic(ErrorCode.ERR_NoImplicitConv, @"""string""").WithArguments("string", "int").WithLocation(10, 17), // (11,20): error CS0103: The name 'garbage' does not exist in the current context // x = (1, 1, garbage); Diagnostic(ErrorCode.ERR_NameNotInContext, "garbage").WithArguments("garbage").WithLocation(11, 20), // (13,14): error CS0037: Cannot convert null to 'int' because it is a non-nullable value type // x = (null, null); Diagnostic(ErrorCode.ERR_ValueCantBeNull, "null").WithArguments("int").WithLocation(13, 14), // (13,20): error CS0037: Cannot convert null to 'int' because it is a non-nullable value type // x = (null, null); Diagnostic(ErrorCode.ERR_ValueCantBeNull, "null").WithArguments("int").WithLocation(13, 20), // (14,17): error CS0037: Cannot convert null to 'int' because it is a non-nullable value type // x = (1, null); Diagnostic(ErrorCode.ERR_ValueCantBeNull, "null").WithArguments("int").WithLocation(14, 17), // (15,17): error CS1660: Cannot convert lambda expression to type 'int' because it is not a delegate type // x = (1, (t)=>t); Diagnostic(ErrorCode.ERR_AnonMethToNonDel, "(t)=>t").WithArguments("lambda expression", "int").WithLocation(15, 17), // (16,13): error CS0037: Cannot convert null to '(int, int)' because it is a non-nullable value type // x = null; Diagnostic(ErrorCode.ERR_ValueCantBeNull, "null").WithArguments("(int, int)").WithLocation(16, 13) ); } [Fact] [WorkItem(11875, "https://github.com/dotnet/roslyn/issues/11875")] public void TupleImplicitConversionFail03() { var source = @" class C { static void Main() { (string, string) x; x = (null, null, null); x = (1, 1, 1); x = (1, ""string""); x = (1, 1, garbage); x = (1, 1, ); x = (null, null); x = (1, null); x = (1, (t)=>t); x = null; } } " + trivial2uple + trivial3uple + tupleattributes_cs; CreateCompilation(source).VerifyDiagnostics( // (12,20): error CS1525: Invalid expression term ')' // x = (1, 1, ); Diagnostic(ErrorCode.ERR_InvalidExprTerm, ")").WithArguments(")").WithLocation(12, 20), // (8,13): error CS8129: Tuple with 3 elements cannot be converted to type '(string, string)'. // x = (null, null, null); Diagnostic(ErrorCode.ERR_ConversionNotTupleCompatible, "(null, null, null)").WithArguments("3", "(string, string)").WithLocation(8, 13), // (9,13): error CS0029: Cannot implicitly convert type '(int, int, int)' to '(string, string)' // x = (1, 1, 1); Diagnostic(ErrorCode.ERR_NoImplicitConv, "(1, 1, 1)").WithArguments("(int, int, int)", "(string, string)").WithLocation(9, 13), // (10,14): error CS0029: Cannot implicitly convert type 'int' to 'string' // x = (1, "string"); Diagnostic(ErrorCode.ERR_NoImplicitConv, "1").WithArguments("int", "string").WithLocation(10, 14), // (11,20): error CS0103: The name 'garbage' does not exist in the current context // x = (1, 1, garbage); Diagnostic(ErrorCode.ERR_NameNotInContext, "garbage").WithArguments("garbage").WithLocation(11, 20), // (14,14): error CS0029: Cannot implicitly convert type 'int' to 'string' // x = (1, null); Diagnostic(ErrorCode.ERR_NoImplicitConv, "1").WithArguments("int", "string").WithLocation(14, 14), // (15,14): error CS0029: Cannot implicitly convert type 'int' to 'string' // x = (1, (t)=>t); Diagnostic(ErrorCode.ERR_NoImplicitConv, "1").WithArguments("int", "string").WithLocation(15, 14), // (15,17): error CS1660: Cannot convert lambda expression to type 'string' because it is not a delegate type // x = (1, (t)=>t); Diagnostic(ErrorCode.ERR_AnonMethToNonDel, "(t)=>t").WithArguments("lambda expression", "string").WithLocation(15, 17), // (16,13): error CS0037: Cannot convert null to '(string, string)' because it is a non-nullable value type // x = null; Diagnostic(ErrorCode.ERR_ValueCantBeNull, "null").WithArguments("(string, string)").WithLocation(16, 13) ); } [Fact] [WorkItem(11875, "https://github.com/dotnet/roslyn/issues/11875")] public void TupleImplicitConversionFail04() { var source = @" class C { static void Main() { ((int, int), int) x; x = ((null, null, null), 1); x = ((1, 1, 1), 1); x = ((1, ""string""), 1); x = ((1, 1, garbage), 1); x = ((1, 1, ), 1); x = ((null, null), 1); x = ((1, null), 1); x = ((1, (t)=>t), 1); x = (null, 1); } } " + trivial2uple + trivial3uple + tupleattributes_cs; CreateCompilation(source).VerifyDiagnostics( // (12,21): error CS1525: Invalid expression term ')' // x = ((1, 1, ), 1); Diagnostic(ErrorCode.ERR_InvalidExprTerm, ")").WithArguments(")").WithLocation(12, 21), // (8,14): error CS8129: Tuple with 3 elements cannot be converted to type '(int, int)'. // x = ((null, null, null), 1); Diagnostic(ErrorCode.ERR_ConversionNotTupleCompatible, "(null, null, null)").WithArguments("3", "(int, int)").WithLocation(8, 14), // (9,14): error CS0029: Cannot implicitly convert type '(int, int, int)' to '(int, int)' // x = ((1, 1, 1), 1); Diagnostic(ErrorCode.ERR_NoImplicitConv, "(1, 1, 1)").WithArguments("(int, int, int)", "(int, int)").WithLocation(9, 14), // (10,18): error CS0029: Cannot implicitly convert type 'string' to 'int' // x = ((1, "string"), 1); Diagnostic(ErrorCode.ERR_NoImplicitConv, @"""string""").WithArguments("string", "int").WithLocation(10, 18), // (11,21): error CS0103: The name 'garbage' does not exist in the current context // x = ((1, 1, garbage), 1); Diagnostic(ErrorCode.ERR_NameNotInContext, "garbage").WithArguments("garbage").WithLocation(11, 21), // (13,15): error CS0037: Cannot convert null to 'int' because it is a non-nullable value type // x = ((null, null), 1); Diagnostic(ErrorCode.ERR_ValueCantBeNull, "null").WithArguments("int").WithLocation(13, 15), // (13,21): error CS0037: Cannot convert null to 'int' because it is a non-nullable value type // x = ((null, null), 1); Diagnostic(ErrorCode.ERR_ValueCantBeNull, "null").WithArguments("int").WithLocation(13, 21), // (14,18): error CS0037: Cannot convert null to 'int' because it is a non-nullable value type // x = ((1, null), 1); Diagnostic(ErrorCode.ERR_ValueCantBeNull, "null").WithArguments("int").WithLocation(14, 18), // (15,18): error CS1660: Cannot convert lambda expression to type 'int' because it is not a delegate type // x = ((1, (t)=>t), 1); Diagnostic(ErrorCode.ERR_AnonMethToNonDel, "(t)=>t").WithArguments("lambda expression", "int").WithLocation(15, 18), // (16,14): error CS0037: Cannot convert null to '(int, int)' because it is a non-nullable value type // x = (null, 1); Diagnostic(ErrorCode.ERR_ValueCantBeNull, "null").WithArguments("(int, int)").WithLocation(16, 14) ); } [Fact] [WorkItem(11875, "https://github.com/dotnet/roslyn/issues/11875")] public void TupleImplicitConversionFail05() { var source = @" class C { static void Main() { (System.ValueTuple x0, int x1, int x2, int x3, int x4, int x5, int x6, int x7, int x8, int x9, int x10) x; x = (0,1,2,3,4,5,6,7,8,9,10); x = ((0, 0.0),1,2,3,4,5,6,7,8,9,10); x = ((0, 0),1,2,3,4,5,6,7,8,9,10,11); x = ((0, 0),1,2,3,4,5,6,7,8); x = ((0, 0),1,2,3,4,5,6,7,8,9.1,10); x = ((0, 0),1,2,3,4,5,6,7,8,; x = ((0, 0),1,2,3,4,5,6,7,8,9 x = ((0, 0),1,2,3,4,oops,6,7,oopsss,9,10); x = ((0, 0),1,2,3,4,5,6,7,8,9); x = ((0, 0),1,2,3,4,5,6,7,8,(1,1,1), 10); } } " + trivial2uple + trivialRemainingTuples + tupleattributes_cs; //intentionally not including 3-tuple for usesite errors CreateCompilationWithMscorlib46(source).VerifyDiagnostics( // (13,37): error CS1525: Invalid expression term ';' // x = ((0, 0),1,2,3,4,5,6,7,8,; Diagnostic(ErrorCode.ERR_InvalidExprTerm, ";").WithArguments(";").WithLocation(13, 37), // (13,37): error CS1026: ) expected // x = ((0, 0),1,2,3,4,5,6,7,8,; Diagnostic(ErrorCode.ERR_CloseParenExpected, ";").WithLocation(13, 37), // (14,38): error CS1026: ) expected // x = ((0, 0),1,2,3,4,5,6,7,8,9 Diagnostic(ErrorCode.ERR_CloseParenExpected, "").WithLocation(14, 38), // (14,38): error CS1002: ; expected // x = ((0, 0),1,2,3,4,5,6,7,8,9 Diagnostic(ErrorCode.ERR_SemicolonExpected, "").WithLocation(14, 38), // (8,14): error CS0029: Cannot implicitly convert type 'int' to '(int, int)' // x = (0,1,2,3,4,5,6,7,8,9,10); Diagnostic(ErrorCode.ERR_NoImplicitConv, "0").WithArguments("int", "(int, int)").WithLocation(8, 14), // (9,18): error CS0029: Cannot implicitly convert type 'double' to 'int' // x = ((0, 0.0),1,2,3,4,5,6,7,8,9,10); Diagnostic(ErrorCode.ERR_NoImplicitConv, "0.0").WithArguments("double", "int").WithLocation(9, 18), // (10,13): error CS0029: Cannot implicitly convert type '((int, int), int, int, int, int, int, int, int, int, int, int, int)' to '((int, int) x0, int x1, int x2, int x3, int x4, int x5, int x6, int x7, int x8, int x9, int x10)' // x = ((0, 0),1,2,3,4,5,6,7,8,9,10,11); Diagnostic(ErrorCode.ERR_NoImplicitConv, "((0, 0),1,2,3,4,5,6,7,8,9,10,11)").WithArguments("((int, int), int, int, int, int, int, int, int, int, int, int, int)", "((int, int) x0, int x1, int x2, int x3, int x4, int x5, int x6, int x7, int x8, int x9, int x10)").WithLocation(10, 13), // (11,13): error CS0029: Cannot implicitly convert type '((int, int), int, int, int, int, int, int, int, int)' to '((int, int) x0, int x1, int x2, int x3, int x4, int x5, int x6, int x7, int x8, int x9, int x10)' // x = ((0, 0),1,2,3,4,5,6,7,8); Diagnostic(ErrorCode.ERR_NoImplicitConv, "((0, 0),1,2,3,4,5,6,7,8)").WithArguments("((int, int), int, int, int, int, int, int, int, int)", "((int, int) x0, int x1, int x2, int x3, int x4, int x5, int x6, int x7, int x8, int x9, int x10)").WithLocation(11, 13), // (12,37): error CS0029: Cannot implicitly convert type 'double' to 'int' // x = ((0, 0),1,2,3,4,5,6,7,8,9.1,10); Diagnostic(ErrorCode.ERR_NoImplicitConv, "9.1").WithArguments("double", "int").WithLocation(12, 37), // (13,13): error CS8179: Predefined type 'System.ValueTuple`3' is not defined or imported // x = ((0, 0),1,2,3,4,5,6,7,8,; Diagnostic(ErrorCode.ERR_PredefinedValueTupleTypeNotFound, "((0, 0),1,2,3,4,5,6,7,8,").WithArguments("System.ValueTuple`3").WithLocation(13, 13), // (14,13): error CS8179: Predefined type 'System.ValueTuple`3' is not defined or imported // x = ((0, 0),1,2,3,4,5,6,7,8,9 Diagnostic(ErrorCode.ERR_PredefinedValueTupleTypeNotFound, @"((0, 0),1,2,3,4,5,6,7,8,9 ").WithArguments("System.ValueTuple`3").WithLocation(14, 13), // (15,29): error CS0103: The name 'oops' does not exist in the current context // x = ((0, 0),1,2,3,4,oops,6,7,oopsss,9,10); Diagnostic(ErrorCode.ERR_NameNotInContext, "oops").WithArguments("oops").WithLocation(15, 29), // (15,38): error CS0103: The name 'oopsss' does not exist in the current context // x = ((0, 0),1,2,3,4,oops,6,7,oopsss,9,10); Diagnostic(ErrorCode.ERR_NameNotInContext, "oopsss").WithArguments("oopsss").WithLocation(15, 38), // (17,13): error CS8179: Predefined type 'System.ValueTuple`3' is not defined or imported // x = ((0, 0),1,2,3,4,5,6,7,8,9); Diagnostic(ErrorCode.ERR_PredefinedValueTupleTypeNotFound, "((0, 0),1,2,3,4,5,6,7,8,9)").WithArguments("System.ValueTuple`3").WithLocation(17, 13), // (17,13): error CS0029: Cannot implicitly convert type 'System.ValueTuple<(int, int), int, int, int, int, int, int, (int, int, int)>' to '((int, int) x0, int x1, int x2, int x3, int x4, int x5, int x6, int x7, int x8, int x9, int x10)' // x = ((0, 0),1,2,3,4,5,6,7,8,9); Diagnostic(ErrorCode.ERR_NoImplicitConv, "((0, 0),1,2,3,4,5,6,7,8,9)").WithArguments("System.ValueTuple<(int, int), int, int, int, int, int, int, (int, int, int)>", "((int, int) x0, int x1, int x2, int x3, int x4, int x5, int x6, int x7, int x8, int x9, int x10)").WithLocation(17, 13), // (18,37): error CS8179: Predefined type 'System.ValueTuple`3' is not defined or imported // x = ((0, 0),1,2,3,4,5,6,7,8,(1,1,1), 10); Diagnostic(ErrorCode.ERR_PredefinedValueTupleTypeNotFound, "(1,1,1)").WithArguments("System.ValueTuple`3").WithLocation(18, 37)); } [Fact] [WorkItem(11875, "https://github.com/dotnet/roslyn/issues/11875")] public void TupleImplicitConversionFail06() { var source = @" using System; class C { static void Main() { Func l = ()=>1; // reference (string, Func) x = (null, ()=>1); // actual error, should be the same as above. Func<(string, string)> l1 = ()=>(null, 1.1); // reference (string, Func<(string, string)>) x1 = (null, ()=>(null, 1.1)); // actual error, should be the same as above. } } " + trivial2uple + trivial3uple + tupleattributes_cs; CreateCompilation(source).VerifyDiagnostics( // (8,30): error CS0029: Cannot implicitly convert type 'int' to 'string' // Func l = ()=>1; // reference Diagnostic(ErrorCode.ERR_NoImplicitConv, "1").WithArguments("int", "string").WithLocation(8, 30), // (8,30): error CS1662: Cannot convert lambda expression to intended delegate type because some of the return types in the block are not implicitly convertible to the delegate return type // Func l = ()=>1; // reference Diagnostic(ErrorCode.ERR_CantConvAnonMethReturns, "1").WithArguments("lambda expression").WithLocation(8, 30), // (10,47): error CS0029: Cannot implicitly convert type 'int' to 'string' // (string, Func) x = (null, ()=>1); // actual error, should be the same as above. Diagnostic(ErrorCode.ERR_NoImplicitConv, "1").WithArguments("int", "string").WithLocation(10, 47), // (10,47): error CS1662: Cannot convert lambda expression to intended delegate type because some of the return types in the block are not implicitly convertible to the delegate return type // (string, Func) x = (null, ()=>1); // actual error, should be the same as above. Diagnostic(ErrorCode.ERR_CantConvAnonMethReturns, "1").WithArguments("lambda expression").WithLocation(10, 47), // (12,48): error CS0029: Cannot implicitly convert type 'double' to 'string' // Func<(string, string)> l1 = ()=>(null, 1.1); // reference Diagnostic(ErrorCode.ERR_NoImplicitConv, "1.1").WithArguments("double", "string").WithLocation(12, 48), // (12,41): error CS1662: Cannot convert lambda expression to intended delegate type because some of the return types in the block are not implicitly convertible to the delegate return type // Func<(string, string)> l1 = ()=>(null, 1.1); // reference Diagnostic(ErrorCode.ERR_CantConvAnonMethReturns, "(null, 1.1)").WithArguments("lambda expression").WithLocation(12, 41), // (14,65): error CS0029: Cannot implicitly convert type 'double' to 'string' // (string, Func<(string, string)>) x1 = (null, ()=>(null, 1.1)); // actual error, should be the same as above. Diagnostic(ErrorCode.ERR_NoImplicitConv, "1.1").WithArguments("double", "string").WithLocation(14, 65), // (14,58): error CS1662: Cannot convert lambda expression to intended delegate type because some of the return types in the block are not implicitly convertible to the delegate return type // (string, Func<(string, string)>) x1 = (null, ()=>(null, 1.1)); // actual error, should be the same as above. Diagnostic(ErrorCode.ERR_CantConvAnonMethReturns, "(null, 1.1)").WithArguments("lambda expression").WithLocation(14, 58) ); } [Fact] public void TupleExplicitConversionFail06() { var source = @" using System; class C { static void Main() { Func l = (Func)(()=>1); // reference (string, Func) x = ((string, Func))(null, () => 1); // actual error, should be the same as above. Func<(string, string)> l1 = (Func<(string, string)>)(()=>(null, 1.1)); // reference (string, Func<(string, string)>) x1 = ((string, Func<(string, string)>))(null, () => (null, 1.1)); // actual error, should be the same as above. } } " + trivial2uple + trivial3uple + tupleattributes_cs; CreateCompilation(source, parseOptions: TestOptions.Regular).VerifyDiagnostics( // (8,45): error CS0029: Cannot implicitly convert type 'int' to 'string' // Func l = (Func)(()=>1); // reference Diagnostic(ErrorCode.ERR_NoImplicitConv, "1").WithArguments("int", "string").WithLocation(8, 45), // (8,45): error CS1662: Cannot convert lambda expression to intended delegate type because some of the return types in the block are not implicitly convertible to the delegate return type // Func l = (Func)(()=>1); // reference Diagnostic(ErrorCode.ERR_CantConvAnonMethReturns, "1").WithArguments("lambda expression").WithLocation(8, 45), // (10,73): error CS0029: Cannot implicitly convert type 'int' to 'string' // (string, Func) x = ((string, Func))(null, () => 1); // actual error, should be the same as above. Diagnostic(ErrorCode.ERR_NoImplicitConv, "1").WithArguments("int", "string").WithLocation(10, 73), // (10,73): error CS1662: Cannot convert lambda expression to intended delegate type because some of the return types in the block are not implicitly convertible to the delegate return type // (string, Func) x = ((string, Func))(null, () => 1); // actual error, should be the same as above. Diagnostic(ErrorCode.ERR_CantConvAnonMethReturns, "1").WithArguments("lambda expression").WithLocation(10, 73), // (12,73): error CS0029: Cannot implicitly convert type 'double' to 'string' // Func<(string, string)> l1 = (Func<(string, string)>)(()=>(null, 1.1)); // reference Diagnostic(ErrorCode.ERR_NoImplicitConv, "1.1").WithArguments("double", "string").WithLocation(12, 73), // (12,66): error CS1662: Cannot convert lambda expression to intended delegate type because some of the return types in the block are not implicitly convertible to the delegate return type // Func<(string, string)> l1 = (Func<(string, string)>)(()=>(null, 1.1)); // reference Diagnostic(ErrorCode.ERR_CantConvAnonMethReturns, "(null, 1.1)").WithArguments("lambda expression").WithLocation(12, 66), // (14,101): error CS0029: Cannot implicitly convert type 'double' to 'string' // (string, Func<(string, string)>) x1 = ((string, Func<(string, string)>))(null, () => (null, 1.1)); // actual error, should be the same as above. Diagnostic(ErrorCode.ERR_NoImplicitConv, "1.1").WithArguments("double", "string").WithLocation(14, 101), // (14,94): error CS1662: Cannot convert lambda expression to intended delegate type because some of the return types in the block are not implicitly convertible to the delegate return type // (string, Func<(string, string)>) x1 = ((string, Func<(string, string)>))(null, () => (null, 1.1)); // actual error, should be the same as above. Diagnostic(ErrorCode.ERR_CantConvAnonMethReturns, "(null, 1.1)").WithArguments("lambda expression").WithLocation(14, 94) ); } [Fact] public void TupleExplicitNullableConversionWithTypelessTuple() { var source = @" class C { static void Main() { var x = ((int, string)?) (1, null); System.Console.Write(x); } } "; var comp = CreateCompilation(source, options: TestOptions.DebugExe); comp.VerifyEmitDiagnostics(); CompileAndVerify(comp, expectedOutput: "(1, )"); var tree = comp.SyntaxTrees.Single(); var model = comp.GetSemanticModel(tree); var declaration = tree.GetRoot().DescendantNodes().OfType().First(); var value = declaration.Declaration.Variables.First().Initializer.Value; Assert.Equal("((int, string)?) (1, null)", value.ToString()); var castConversion = model.GetConversion(value); Assert.Equal(ConversionKind.Identity, castConversion.Kind); var tuple = ((CastExpressionSyntax)value).Expression; Assert.Equal("(1, null)", tuple.ToString()); var tupleConversion = model.GetConversion(tuple); Assert.Equal(ConversionKind.ExplicitNullable, tupleConversion.Kind); Assert.Equal(1, tupleConversion.UnderlyingConversions.Length); Assert.Equal(ConversionKind.ExplicitTupleLiteral, tupleConversion.UnderlyingConversions[0].Kind); } [Fact] public void TupleImplicitNullableConversionWithTypelessTuple() { var source = @" class C { static void Main() { (int, string)? x = (1, null); System.Console.Write(x); } } "; var comp = CreateCompilation(source, options: TestOptions.DebugExe); comp.VerifyEmitDiagnostics(); CompileAndVerify(comp, expectedOutput: "(1, )"); var tree = comp.SyntaxTrees.Single(); var model = comp.GetSemanticModel(tree); var declaration = tree.GetRoot().DescendantNodes().OfType().First(); var value = declaration.Declaration.Variables.First().Initializer.Value; Assert.Equal("(1, null)", value.ToString()); var tupleConversion = model.GetConversion(value); Assert.Equal(ConversionKind.ImplicitNullable, tupleConversion.Kind); Assert.Equal(1, tupleConversion.UnderlyingConversions.Length); Assert.Equal(ConversionKind.ImplicitTupleLiteral, tupleConversion.UnderlyingConversions[0].Kind); } [Fact] public void TupleImplicitNullableAndCustomConversionsWithTypelessTuple() { var source = @" struct C { static void Main() { C? x = (1, null); System.Console.Write(x); var x2 = (C)(2, null); System.Console.Write(x2); var x3 = (C?)(3, null); System.Console.Write(x3); } public static implicit operator C((int, string) x) { return new C(); } } "; var comp = CreateCompilation(source, options: TestOptions.DebugExe); comp.VerifyEmitDiagnostics(); CompileAndVerify(comp, expectedOutput: "CCC"); var tree = comp.SyntaxTrees.Single(); var model = comp.GetSemanticModel(tree); var tuples = tree.GetRoot().DescendantNodes().OfType(); var tuple1 = tuples.ElementAt(0); Assert.Equal("(1, null)", tuple1.ToString()); Assert.Null(model.GetTypeInfo(tuple1).Type); Assert.Equal("C?", model.GetTypeInfo(tuple1).ConvertedType.ToTestDisplayString()); var conversion1 = model.GetConversion(tuple1); Assert.Equal(ConversionKind.ImplicitUserDefined, conversion1.Kind); Assert.True(conversion1.UnderlyingConversions.IsDefault); var tuple2 = tuples.ElementAt(1); Assert.Equal("(2, null)", tuple2.ToString()); Assert.Null(model.GetTypeInfo(tuple2).Type); Assert.Equal("(System.Int32, System.String)", model.GetTypeInfo(tuple2).ConvertedType.ToTestDisplayString()); var conversion2 = model.GetConversion(tuple2); Assert.Equal(ConversionKind.ImplicitTupleLiteral, conversion2.Kind); Assert.False(conversion2.UnderlyingConversions.IsDefault); var tuple3 = tuples.ElementAt(2); Assert.Equal("(3, null)", tuple3.ToString()); Assert.Null(model.GetTypeInfo(tuple3).Type); Assert.Equal("(System.Int32, System.String)", model.GetTypeInfo(tuple3).ConvertedType.ToTestDisplayString()); var conversion3 = model.GetConversion(tuple3); Assert.Equal(ConversionKind.ImplicitTupleLiteral, conversion3.Kind); Assert.False(conversion3.UnderlyingConversions.IsDefault); } [Fact] public void TupleImplicitNullableAndCustomConversionsWithTypelessTupleInAsOperator() { var source = @" struct C { static void Main() { var x4 = (1, null) as C; System.Console.Write(x4); var x5 = (2, null) as C?; System.Console.Write(x5); } public static implicit operator C((int, string) x) { return new C(); } } "; var comp = CreateCompilation(source, options: TestOptions.DebugExe); comp.VerifyEmitDiagnostics( // (6,18): error CS8305: The first operand of an 'as' operator may not be a tuple literal without a natural type. // var x4 = (1, null) as C; Diagnostic(ErrorCode.ERR_TypelessTupleInAs, "(1, null) as C").WithLocation(6, 18), // (8,18): error CS8305: The first operand of an 'as' operator may not be a tuple literal without a natural type. // var x5 = (2, null) as C?; Diagnostic(ErrorCode.ERR_TypelessTupleInAs, "(2, null) as C?").WithLocation(8, 18) ); var tree = comp.SyntaxTrees.Single(); var model = comp.GetSemanticModel(tree); var tuples = tree.GetRoot().DescendantNodes().OfType(); verifyTuple("(1, null)", tuples.ElementAt(0)); verifyTuple("(2, null)", tuples.ElementAt(1)); void verifyTuple(string expected, TupleExpressionSyntax tuple) { Assert.Equal(expected, tuple.ToString()); Assert.Null(model.GetTypeInfo(tuple).Type); Assert.Null(model.GetTypeInfo(tuple).ConvertedType); var conversion = model.GetConversion(tuple); Assert.Equal(ConversionKind.Identity, conversion.Kind); Assert.True(conversion.UnderlyingConversions.IsDefault); } } [Fact] public void TupleTargetTypeLambda() { var source = @" using System; class C { static void Test(Func> d) { Console.WriteLine(""short""); } static void Test(Func> d) { Console.WriteLine(""byte""); } static void Main() { // this works because of identity conversion Test( ()=>()=>((byte, byte))(1,1)) ; // this works because of the betterness of the targets Test(()=>()=>(1,1)); } } "; var comp = CompileAndVerify(source, parseOptions: TestOptions.Regular, expectedOutput: @" byte byte "); } [Fact] public void TupleTargetTypeLambda1() { var source = @" using System; class C { static void Test(Func<(Func, int)> d) { Console.WriteLine(""short""); } static void Test(Func<(Func, int)> d) { Console.WriteLine(""byte""); } static void Main() { // this works Test(()=>(()=>(short)1, 1)); // this works Test(()=>(()=>(byte)1, 1)); // this does not Test(()=>(()=>1, 1)); } } "; CreateCompilation(source).VerifyDiagnostics( // (26,9): error CS0121: The call is ambiguous between the following methods or properties: 'C.Test(Func<(Func, int)>)' and 'C.Test(Func<(Func, int)>)' // Test(()=>(()=>1, 1)); Diagnostic(ErrorCode.ERR_AmbigCall, "Test").WithArguments("C.Test(System.Func<(System.Func, int)>)", "C.Test(System.Func<(System.Func, int)>)").WithLocation(26, 9) ); } [Fact] public void TargetTypingOverload01() { var source = @" using System; class C { static void Main() { Test((null, null)); Test((1, 1)); Test((()=>7, ()=>8), 2); } static void Test((T, T) x) { System.Console.WriteLine(""first""); } static void Test((object, object) x) { System.Console.WriteLine(""second""); } static void Test((Func, Func) x, T y) { System.Console.WriteLine(""third""); System.Console.WriteLine(x.Item1().ToString()); } } "; var comp = CompileAndVerify(source, parseOptions: TestOptions.Regular, expectedOutput: @" second first third 7 "); } [Fact] public void TargetTypingOverload02() { var source = @" using System; class C { static void Main() { Test((()=>7, ()=>8)); } static void Test((T, T) x) { System.Console.WriteLine(""first""); } static void Test((object, object) x) { System.Console.WriteLine(""second""); } static void Test((Func, Func) x) { System.Console.WriteLine(""third""); System.Console.WriteLine(x.Item1().ToString()); } } "; var comp = CompileAndVerify(source, parseOptions: TestOptions.Regular, expectedOutput: @" third 7 "); } [Fact] public void TargetTypingNullable01() { var source = @" using System; class C { static void Main() { var x = M1(); Test(x); } static (int a, double b)? M1() { return (1, 2); } static void Test(T arg) { System.Console.WriteLine(typeof(T)); System.Console.WriteLine(arg); } } "; var comp = CompileAndVerify(source, parseOptions: TestOptions.Regular, expectedOutput: @" System.Nullable`1[System.ValueTuple`2[System.Int32,System.Double]] (1, 2) "); } [Fact] public void TargetTypingOverload01Long() { var source = @" using System; class C { static void Main() { Test((null, null, null, null, null, null, null, null, null, null)); Test((1, 1, 1, 1, 1, 1, 1, 1, 1, 1)); Test((()=>7, ()=>8, ()=>8, ()=>8, ()=>8, ()=>8, ()=>8, ()=>8, ()=>8, ()=>8), 2); } static void Test((T, T, T, T, T, T, T, T, T, T) x) { System.Console.WriteLine(""first""); } static void Test((object, object, object, object, object, object, object, object, object, object) x) { System.Console.WriteLine(""second""); } static void Test((Func, Func, Func, Func, Func, Func, Func, Func, Func, Func) x, T y) { System.Console.WriteLine(""third""); System.Console.WriteLine(x.Item1().ToString()); } } "; var comp = CompileAndVerify(source, expectedOutput: @" second first third 7 "); } [Fact] public void TargetTypingNullable02() { var source = @" using System; class C { static void Main() { var x = M1(); Test(x); } static (int a, string b)? M1() { return (1, null); } static void Test(T arg) { System.Console.WriteLine(typeof(T)); System.Console.WriteLine(arg); } } "; var comp = CompileAndVerify(source, parseOptions: TestOptions.Regular, expectedOutput: @" System.Nullable`1[System.ValueTuple`2[System.Int32,System.String]] (1, ) "); } [Fact] public void TargetTypingNullable02Long() { var source = @" class C { static void Main() { var x = M1(); System.Console.WriteLine(x?.a); System.Console.WriteLine(x?.a8); Test(x); } static (int a, string b, int a1, int a2, int a3, int a4, int a5, int a6, int a7, int a8)? M1() { return (1, null, 1, 2, 3, 4, 5, 6, 7, 8); } static void Test(T arg) { System.Console.WriteLine(arg); } } "; var comp = CompileAndVerify(source, expectedOutput: @"1 8 (1, , 1, 2, 3, 4, 5, 6, 7, 8) "); } [Fact] public void TargetTypingNullableOverload() { var source = @" class C { static void Main() { Test((null, null, null, null, null, null, null, null, null, null)); Test((""a"", ""a"", ""a"", ""a"", ""a"", ""a"", ""a"", ""a"", ""a"", ""a"")); Test((1, 1, 1, 1, 1, 1, 1, 1, 1, 1)); } static void Test((string, string, string, string, string, string, string, string, string, string) x) { System.Console.WriteLine(""first""); } static void Test((string, string, string, string, string, string, string, string, string, string)? x) { System.Console.WriteLine(""second""); } static void Test((int, int, int, int, int, int, int, int, int, int)? x) { System.Console.WriteLine(""third""); } static void Test((int, int, int, int, int, int, int, int, int, int) x) { System.Console.WriteLine(""fourth""); } } "; var comp = CompileAndVerify(source, expectedOutput: @" first first fourth "); } [Fact] public void TupleConversion01() { var source = @" class C { static void Main() { // error must mention (long c, long d) (int a, int b) x1 = ((long c, long d))(e: 1, f:2); // error must mention (int c, long d) (short a, short b) x2 = ((int c, int d))(e: 1, f:2); // error must mention (int e, string f) (int a, int b) x3 = ((long c, long d))(e: 1, f:""qq""); } } " + trivial2uple + tupleattributes_cs; CreateCompilation(source).VerifyDiagnostics( // (7,48): warning CS8123: The tuple element name 'e' is ignored because a different name or no name is specified by the target type '(long c, long d)'. // (int a, int b) x1 = ((long c, long d))(e: 1, f:2); Diagnostic(ErrorCode.WRN_TupleLiteralNameMismatch, "e: 1").WithArguments("e", "(long c, long d)").WithLocation(7, 48), // (7,54): warning CS8123: The tuple element name 'f' is ignored because a different name or no name is specified by the target type '(long c, long d)'. // (int a, int b) x1 = ((long c, long d))(e: 1, f:2); Diagnostic(ErrorCode.WRN_TupleLiteralNameMismatch, "f:2").WithArguments("f", "(long c, long d)").WithLocation(7, 54), // (7,29): error CS0266: Cannot implicitly convert type '(long c, long d)' to '(int a, int b)'. An explicit conversion exists (are you missing a cast?) // (int a, int b) x1 = ((long c, long d))(e: 1, f:2); Diagnostic(ErrorCode.ERR_NoImplicitConvCast, "((long c, long d))(e: 1, f:2)").WithArguments("(long c, long d)", "(int a, int b)").WithLocation(7, 29), // (9,50): warning CS8123: The tuple element name 'e' is ignored because a different name or no name is specified by the target type '(int c, int d)'. // (short a, short b) x2 = ((int c, int d))(e: 1, f:2); Diagnostic(ErrorCode.WRN_TupleLiteralNameMismatch, "e: 1").WithArguments("e", "(int c, int d)").WithLocation(9, 50), // (9,56): warning CS8123: The tuple element name 'f' is ignored because a different name or no name is specified by the target type '(int c, int d)'. // (short a, short b) x2 = ((int c, int d))(e: 1, f:2); Diagnostic(ErrorCode.WRN_TupleLiteralNameMismatch, "f:2").WithArguments("f", "(int c, int d)").WithLocation(9, 56), // (9,33): error CS0266: Cannot implicitly convert type '(int c, int d)' to '(short a, short b)'. An explicit conversion exists (are you missing a cast?) // (short a, short b) x2 = ((int c, int d))(e: 1, f:2); Diagnostic(ErrorCode.ERR_NoImplicitConvCast, "((int c, int d))(e: 1, f:2)").WithArguments("(int c, int d)", "(short a, short b)").WithLocation(9, 33), // (12,56): error CS0030: Cannot convert type 'string' to 'long' // (int a, int b) x3 = ((long c, long d))(e: 1, f:"qq"); Diagnostic(ErrorCode.ERR_NoExplicitConv, @"""qq""").WithArguments("string", "long").WithLocation(12, 56), // (7,24): warning CS0219: The variable 'x1' is assigned but its value is never used // (int a, int b) x1 = ((long c, long d))(e: 1, f:2); Diagnostic(ErrorCode.WRN_UnreferencedVarAssg, "x1").WithArguments("x1").WithLocation(7, 24), // (9,28): warning CS0219: The variable 'x2' is assigned but its value is never used // (short a, short b) x2 = ((int c, int d))(e: 1, f:2); Diagnostic(ErrorCode.WRN_UnreferencedVarAssg, "x2").WithArguments("x2").WithLocation(9, 28) ); } [Fact] [WorkItem(11288, "https://github.com/dotnet/roslyn/issues/11288")] public void TupleConversion02() { var source = @" class C { static void Main() { (int a, int b) x4 = ((long c, long d))(1, null, 2); } } " + trivial2uple + trivial3uple + tupleattributes_cs; CreateCompilation(source).VerifyDiagnostics( // (6,29): error CS8135: Tuple with 3 elements cannot be converted to type '(long c, long d)'. // (int a, int b) x4 = ((long c, long d))(1, null, 2); Diagnostic(ErrorCode.ERR_ConversionNotTupleCompatible, "((long c, long d))(1, null, 2)").WithArguments("3", "(long c, long d)").WithLocation(6, 29) ); } [Fact] public void TupleConvertedType01() { var source = @" class C { static void Main() { (short a, string b)? x = (e: 1, f: ""hello""); } } " + trivial2uple + trivial3uple + tupleattributes_cs; var tree = Parse(source, options: TestOptions.Regular); var comp = CreateCompilation(tree); var model = comp.GetSemanticModel(tree, ignoreAccessibility: false); var nodes = tree.GetCompilationUnitRoot().DescendantNodes(); var node = nodes.OfType().Single(); Assert.Equal(@"(e: 1, f: ""hello"")", node.ToString()); Assert.Equal("(System.Int32 e, System.String f)", model.GetTypeInfo(node).Type.ToTestDisplayString()); Assert.Equal("(System.Int16 a, System.String b)?", model.GetTypeInfo(node).ConvertedType.ToTestDisplayString()); Assert.Equal(ConversionKind.ImplicitNullable, model.GetConversion(node).Kind); var x = nodes.OfType().First(); Assert.Equal("(System.Int16 a, System.String b)? x", model.GetDeclaredSymbol(x).ToTestDisplayString()); } [Fact] public void TupleConvertedType01insource() { var source = @" class C { static void Main() { // explicit conversion exists, cast in the code picks that. (short a, string b)? x = ((short c, string d)?)(e: 1, f: ""hello""); short? y = (short?)11; } } " + trivial2uple + trivial3uple + tupleattributes_cs; var tree = Parse(source, options: TestOptions.Regular); var comp = CreateCompilation(tree); var model = comp.GetSemanticModel(tree, ignoreAccessibility: false); var nodes = tree.GetCompilationUnitRoot().DescendantNodes(); var l11 = nodes.OfType().ElementAt(2); Assert.Equal(@"11", l11.ToString()); Assert.Equal("System.Int32", model.GetTypeInfo(l11).Type.ToTestDisplayString()); Assert.Equal("System.Int32", model.GetTypeInfo(l11).ConvertedType.ToTestDisplayString()); Assert.Equal(Conversion.Identity, model.GetConversion(l11)); var node = nodes.OfType().Single(); Assert.Equal(@"(e: 1, f: ""hello"")", node.ToString()); Assert.Equal("(System.Int32 e, System.String f)", model.GetTypeInfo(node).Type.ToTestDisplayString()); Assert.Equal("(System.Int16 c, System.String d)?", model.GetTypeInfo(node).ConvertedType.ToTestDisplayString()); Assert.Equal(ConversionKind.ExplicitNullable, model.GetConversion(node).Kind); ExpressionSyntax element; element = node.Arguments[0].Expression; Assert.Equal("System.Int32", model.GetTypeInfo(element).Type.ToTestDisplayString()); Assert.Equal("System.Int16", model.GetTypeInfo(element).ConvertedType.ToTestDisplayString()); Assert.Equal(ConversionKind.ImplicitConstant, model.GetConversion(element).Kind); element = node.Arguments[1].Expression; Assert.Equal("System.String", model.GetTypeInfo(element).Type.ToTestDisplayString()); Assert.Equal("System.String", model.GetTypeInfo(element).ConvertedType.ToTestDisplayString()); Assert.Equal(ConversionKind.Identity, model.GetConversion(element).Kind); // semantic model returns topmost conversion from the sequence of conversions for // ((short c, string d)?)(e: 1, f: ""hello"") Assert.Equal("(System.Int16 c, System.String d)?", model.GetTypeInfo(node.Parent).Type.ToTestDisplayString()); Assert.Equal("(System.Int16 a, System.String b)?", model.GetTypeInfo(node.Parent).ConvertedType.ToTestDisplayString()); Assert.Equal(Conversion.Identity, model.GetConversion(node.Parent)); var x = nodes.OfType().First(); Assert.Equal("(System.Int16 a, System.String b)? x", model.GetDeclaredSymbol(x).ToTestDisplayString()); } [Fact] public void TupleConvertedType01insourceImplicit() { var source = @" class C { static void Main() { (short a, string b)? x =(1, ""hello""); } } " + trivial2uple + trivial3uple + tupleattributes_cs; var tree = Parse(source, options: TestOptions.Regular); var comp = CreateCompilation(tree); var model = comp.GetSemanticModel(tree, ignoreAccessibility: false); var nodes = tree.GetCompilationUnitRoot().DescendantNodes(); var node = nodes.OfType().Single(); Assert.Equal(@"(1, ""hello"")", node.ToString()); var typeInfo = model.GetTypeInfo(node); Assert.Equal("(System.Int32, System.String)", typeInfo.Type.ToTestDisplayString()); Assert.Equal("(System.Int16 a, System.String b)?", typeInfo.ConvertedType.ToTestDisplayString()); Assert.Equal(ConversionKind.ImplicitNullable, model.GetConversion(node).Kind); CompileAndVerify(comp); } [Fact] public void TupleConvertedType02() { var source = @" class C { static void Main() { (short a, string b)? x = (e: 1, f: ""hello""); } } " + trivial2uple + trivial3uple + tupleattributes_cs; var tree = Parse(source, options: TestOptions.Regular); var comp = CreateCompilation(tree); var model = comp.GetSemanticModel(tree, ignoreAccessibility: false); var nodes = tree.GetCompilationUnitRoot().DescendantNodes(); var node = nodes.OfType().Single(); Assert.Equal(@"(e: 1, f: ""hello"")", node.ToString()); Assert.Equal("(System.Int32 e, System.String f)", model.GetTypeInfo(node).Type.ToTestDisplayString()); Assert.Equal("(System.Int16 a, System.String b)?", model.GetTypeInfo(node).ConvertedType.ToTestDisplayString()); Assert.Equal(ConversionKind.ImplicitNullable, model.GetConversion(node).Kind); var x = nodes.OfType().First(); Assert.Equal("(System.Int16 a, System.String b)? x", model.GetDeclaredSymbol(x).ToTestDisplayString()); } [Fact] public void TupleConvertedType02insource00() { var source = @" class C { static void Main() { (short a, string b)? x = ((short c, string d))(e: 1, f: ""hello""); } } " + trivial2uple + trivial3uple + tupleattributes_cs; var tree = Parse(source, options: TestOptions.Regular); var comp = CreateCompilation(tree); var model = comp.GetSemanticModel(tree, ignoreAccessibility: false); var nodes = tree.GetCompilationUnitRoot().DescendantNodes(); var node = nodes.OfType().Single(); Assert.Equal(@"(e: 1, f: ""hello"")", node.ToString()); Assert.Equal("(System.Int32 e, System.String f)", model.GetTypeInfo(node).Type.ToTestDisplayString()); Assert.Equal("(System.Int16 c, System.String d)", model.GetTypeInfo(node).ConvertedType.ToTestDisplayString()); Assert.Equal(ConversionKind.ExplicitTupleLiteral, model.GetConversion(node).Kind); ExpressionSyntax element; element = node.Arguments[0].Expression; Assert.Equal("System.Int32", model.GetTypeInfo(element).Type.ToTestDisplayString()); Assert.Equal("System.Int16", model.GetTypeInfo(element).ConvertedType.ToTestDisplayString()); Assert.Equal(ConversionKind.ImplicitConstant, model.GetConversion(element).Kind); element = node.Arguments[1].Expression; Assert.Equal("System.String", model.GetTypeInfo(element).Type.ToTestDisplayString()); Assert.Equal("System.String", model.GetTypeInfo(element).ConvertedType.ToTestDisplayString()); Assert.Equal(ConversionKind.Identity, model.GetConversion(element).Kind); // semantic model returns topmost conversion from the sequence of conversions for // ((short c, string d))(e: 1, f: ""hello"") Assert.Equal("(System.Int16 c, System.String d)", model.GetTypeInfo(node.Parent).Type.ToTestDisplayString()); Assert.Equal("(System.Int16 a, System.String b)?", model.GetTypeInfo(node.Parent).ConvertedType.ToTestDisplayString()); Assert.Equal(ConversionKind.ImplicitNullable, model.GetConversion(node.Parent).Kind); var x = nodes.OfType().First(); Assert.Equal("(System.Int16 a, System.String b)? x", model.GetDeclaredSymbol(x).ToTestDisplayString()); } [Fact] public void TupleConvertedType02insource01() { var source = @" class C { static void Main() { var x = (e: 1, f: ""hello""); (object a, string b) x1 = ((long c, string d))(x); } } " + trivial2uple + trivial3uple + tupleattributes_cs; var tree = Parse(source, options: TestOptions.Regular); var comp = CreateCompilation(tree); var model = comp.GetSemanticModel(tree, ignoreAccessibility: false); var nodes = tree.GetCompilationUnitRoot().DescendantNodes(); var node = nodes.OfType().Single().Parent; Assert.Equal(@"((long c, string d))(x)", node.ToString()); Assert.Equal("(System.Int64 c, System.String d)", model.GetTypeInfo(node).Type.ToTestDisplayString()); Assert.Equal("(System.Object a, System.String b)", model.GetTypeInfo(node).ConvertedType.ToTestDisplayString()); Assert.Equal(ConversionKind.ImplicitTuple, model.GetConversion(node).Kind); node = nodes.OfType().Single(); Assert.Equal(@"(x)", node.ToString()); Assert.Equal("(System.Int32 e, System.String f)", model.GetTypeInfo(node).Type.ToTestDisplayString()); Assert.Equal("(System.Int32 e, System.String f)", model.GetTypeInfo(node).ConvertedType.ToTestDisplayString()); Assert.Equal(Conversion.Identity, model.GetConversion(node)); } [Fact] public void TupleConvertedType02insource02() { var source = @" class C { static void Main() { var x = (e: 1, f: ""hello""); (object a, string b)? x1 = ((long c, string d))(x); } } " + trivial2uple + trivial3uple + tupleattributes_cs; var tree = Parse(source, options: TestOptions.Regular); var comp = CreateCompilation(tree); var model = comp.GetSemanticModel(tree, ignoreAccessibility: false); var nodes = tree.GetCompilationUnitRoot().DescendantNodes(); var node = nodes.OfType().Single().Parent; Assert.Equal(@"((long c, string d))(x)", node.ToString()); Assert.Equal("(System.Int64 c, System.String d)", model.GetTypeInfo(node).Type.ToTestDisplayString()); Assert.Equal("(System.Object a, System.String b)?", model.GetTypeInfo(node).ConvertedType.ToTestDisplayString()); Assert.Equal(ConversionKind.ImplicitNullable, model.GetConversion(node).Kind); node = nodes.OfType().Single(); Assert.Equal(@"(x)", node.ToString()); Assert.Equal("(System.Int32 e, System.String f)", model.GetTypeInfo(node).Type.ToTestDisplayString()); Assert.Equal("(System.Int32 e, System.String f)", model.GetTypeInfo(node).ConvertedType.ToTestDisplayString()); Assert.Equal(Conversion.Identity, model.GetConversion(node)); } [Fact] public void TupleConvertedType03() { var source = @" class C { static void Main() { (int a, string b)? x = (e: 1, f: ""hello""); } } " + trivial2uple + trivial3uple + tupleattributes_cs; var tree = Parse(source, options: TestOptions.Regular); var comp = CreateCompilation(tree); var model = comp.GetSemanticModel(tree, ignoreAccessibility: false); var nodes = tree.GetCompilationUnitRoot().DescendantNodes(); var node = nodes.OfType().Single(); Assert.Equal(@"(e: 1, f: ""hello"")", node.ToString()); Assert.Equal("(System.Int32 e, System.String f)", model.GetTypeInfo(node).Type.ToTestDisplayString()); Assert.Equal("(System.Int32 a, System.String b)?", model.GetTypeInfo(node).ConvertedType.ToTestDisplayString()); Assert.Equal(ConversionKind.ImplicitNullable, model.GetConversion(node).Kind); var x = nodes.OfType().First(); Assert.Equal("(System.Int32 a, System.String b)? x", model.GetDeclaredSymbol(x).ToTestDisplayString()); } [Fact] public void TupleConvertedType03insource() { var source = @" class C { static void Main() { (int a, string b)? x = ((int c, string d)?)(e: 1, f: ""hello""); } } " + trivial2uple + trivial3uple + tupleattributes_cs; var tree = Parse(source, options: TestOptions.Regular); var comp = CreateCompilation(tree); var model = comp.GetSemanticModel(tree, ignoreAccessibility: false); var nodes = tree.GetCompilationUnitRoot().DescendantNodes(); var node = nodes.OfType().Single(); Assert.Equal(@"(e: 1, f: ""hello"")", node.ToString()); Assert.Equal("(System.Int32 e, System.String f)", model.GetTypeInfo(node).Type.ToTestDisplayString()); Assert.Equal("(System.Int32 c, System.String d)?", model.GetTypeInfo(node).ConvertedType.ToTestDisplayString()); Assert.Equal(ConversionKind.ExplicitNullable, model.GetConversion(node).Kind); ExpressionSyntax element; element = node.Arguments[0].Expression; Assert.Equal("System.Int32", model.GetTypeInfo(element).Type.ToTestDisplayString()); Assert.Equal("System.Int32", model.GetTypeInfo(element).ConvertedType.ToTestDisplayString()); Assert.Equal(ConversionKind.Identity, model.GetConversion(element).Kind); element = node.Arguments[1].Expression; Assert.Equal("System.String", model.GetTypeInfo(element).Type.ToTestDisplayString()); Assert.Equal("System.String", model.GetTypeInfo(element).ConvertedType.ToTestDisplayString()); Assert.Equal(ConversionKind.Identity, model.GetConversion(element).Kind); // semantic model returns topmost conversion from the sequence of conversions for // ((int c, string d)?)(e: 1, f: ""hello"") Assert.Equal("(System.Int32 c, System.String d)?", model.GetTypeInfo(node.Parent).Type.ToTestDisplayString()); Assert.Equal("(System.Int32 a, System.String b)?", model.GetTypeInfo(node.Parent).ConvertedType.ToTestDisplayString()); Assert.Equal(Conversion.Identity, model.GetConversion(node.Parent)); var x = nodes.OfType().First(); Assert.Equal("(System.Int32 a, System.String b)? x", model.GetDeclaredSymbol(x).ToTestDisplayString()); } [Fact] public void TupleConvertedType04() { var source = @" class C { static void Main() { (int a, string b)? x = ((int c, string d))(e: 1, f: ""hello""); } } " + trivial2uple + trivial3uple + tupleattributes_cs; var tree = Parse(source, options: TestOptions.Regular); var comp = CreateCompilation(tree); var model = comp.GetSemanticModel(tree, ignoreAccessibility: false); var nodes = tree.GetCompilationUnitRoot().DescendantNodes(); var node = nodes.OfType().Single(); Assert.Equal(@"(e: 1, f: ""hello"")", node.ToString()); Assert.Equal("(System.Int32 e, System.String f)", model.GetTypeInfo(node).Type.ToTestDisplayString()); Assert.Equal("(System.Int32 e, System.String f)", model.GetTypeInfo(node).ConvertedType.ToTestDisplayString()); Assert.Equal(Conversion.Identity, model.GetConversion(node)); // semantic model returns topmost conversion from the sequence of conversions for // ((int c, string d))(e: 1, f: ""hello"") Assert.Equal("(System.Int32 c, System.String d)", model.GetTypeInfo(node.Parent).Type.ToTestDisplayString()); Assert.Equal("(System.Int32 a, System.String b)?", model.GetTypeInfo(node.Parent).ConvertedType.ToTestDisplayString()); Assert.Equal(ConversionKind.ImplicitNullable, model.GetConversion(node.Parent).Kind); var x = nodes.OfType().First(); Assert.Equal("(System.Int32 a, System.String b)? x", model.GetDeclaredSymbol(x).ToTestDisplayString()); } [Fact] public void TupleConvertedType05() { var source = @" class C { static void Main() { (int a, string b) x = (e: 1, f: ""hello""); } } " + trivial2uple + trivial3uple + tupleattributes_cs; var tree = Parse(source, options: TestOptions.Regular); var comp = CreateCompilation(tree); var model = comp.GetSemanticModel(tree, ignoreAccessibility: false); var nodes = tree.GetCompilationUnitRoot().DescendantNodes(); var node = nodes.OfType().Single(); Assert.Equal(@"(e: 1, f: ""hello"")", node.ToString()); Assert.Equal("(System.Int32 e, System.String f)", model.GetTypeInfo(node).Type.ToTestDisplayString()); Assert.Equal("(System.Int32 a, System.String b)", model.GetTypeInfo(node).ConvertedType.ToTestDisplayString()); Assert.Equal(Conversion.Identity, model.GetConversion(node)); var x = nodes.OfType().First(); Assert.Equal("(System.Int32 a, System.String b) x", model.GetDeclaredSymbol(x).ToTestDisplayString()); } [Fact] public void TupleConvertedType05insource() { var source = @" class C { static void Main() { (int a, string b) x = ((int c, string d))(e: 1, f: ""hello""); } } " + trivial2uple + trivial3uple + tupleattributes_cs; var tree = Parse(source, options: TestOptions.Regular); var comp = CreateCompilation(tree); var model = comp.GetSemanticModel(tree, ignoreAccessibility: false); var nodes = tree.GetCompilationUnitRoot().DescendantNodes(); var node = nodes.OfType().Single(); Assert.Equal(@"(e: 1, f: ""hello"")", node.ToString()); Assert.Equal("(System.Int32 e, System.String f)", model.GetTypeInfo(node).Type.ToTestDisplayString()); Assert.Equal("(System.Int32 e, System.String f)", model.GetTypeInfo(node).ConvertedType.ToTestDisplayString()); Assert.Equal(Conversion.Identity, model.GetConversion(node)); var x = nodes.OfType().First(); Assert.Equal("(System.Int32 a, System.String b) x", model.GetDeclaredSymbol(x).ToTestDisplayString()); } [Fact] public void TupleConvertedType06() { var source = @" class C { static void Main() { (short a, string b) x = (e: 1, f: ""hello""); } } " + trivial2uple + trivial3uple + tupleattributes_cs; var tree = Parse(source, options: TestOptions.Regular); var comp = CreateCompilation(tree); var model = comp.GetSemanticModel(tree, ignoreAccessibility: false); var nodes = tree.GetCompilationUnitRoot().DescendantNodes(); var node = nodes.OfType().Single(); Assert.Equal(@"(e: 1, f: ""hello"")", node.ToString()); Assert.Equal("(System.Int32 e, System.String f)", model.GetTypeInfo(node).Type.ToTestDisplayString()); Assert.Equal("(System.Int16 a, System.String b)", model.GetTypeInfo(node).ConvertedType.ToTestDisplayString()); Assert.Equal(ConversionKind.ImplicitTupleLiteral, model.GetConversion(node).Kind); var x = nodes.OfType().First(); Assert.Equal("(System.Int16 a, System.String b) x", model.GetDeclaredSymbol(x).ToTestDisplayString()); } [Fact] public void TupleConvertedType06insource() { var source = @" class C { static void Main() { (short a, string b) x = ((short c, string d))(e: 1, f: ""hello""); short y = (short)11; } } " + trivial2uple + trivial3uple + tupleattributes_cs; var tree = Parse(source, options: TestOptions.Regular); var comp = CreateCompilation(tree); var model = comp.GetSemanticModel(tree, ignoreAccessibility: false); var nodes = tree.GetCompilationUnitRoot().DescendantNodes(); var l11 = nodes.OfType().ElementAt(2); Assert.Equal(@"11", l11.ToString()); Assert.Equal("System.Int32", model.GetTypeInfo(l11).Type.ToTestDisplayString()); Assert.Equal("System.Int32", model.GetTypeInfo(l11).ConvertedType.ToTestDisplayString()); Assert.Equal(Conversion.Identity, model.GetConversion(l11)); var node = nodes.OfType().Single(); Assert.Equal(@"(e: 1, f: ""hello"")", node.ToString()); Assert.Equal("(System.Int32 e, System.String f)", model.GetTypeInfo(node).Type.ToTestDisplayString()); Assert.Equal("(System.Int16 c, System.String d)", model.GetTypeInfo(node).ConvertedType.ToTestDisplayString()); Assert.Equal(ConversionKind.ExplicitTupleLiteral, model.GetConversion(node).Kind); ExpressionSyntax element; element = node.Arguments[0].Expression; Assert.Equal("System.Int32", model.GetTypeInfo(element).Type.ToTestDisplayString()); Assert.Equal("System.Int16", model.GetTypeInfo(element).ConvertedType.ToTestDisplayString()); Assert.Equal(ConversionKind.ImplicitConstant, model.GetConversion(element).Kind); element = node.Arguments[1].Expression; Assert.Equal("System.String", model.GetTypeInfo(element).Type.ToTestDisplayString()); Assert.Equal("System.String", model.GetTypeInfo(element).ConvertedType.ToTestDisplayString()); Assert.Equal(ConversionKind.Identity, model.GetConversion(element).Kind); // semantic model returns topmost conversion from the sequence of conversions for // ((short c, string d))(e: 1, f: ""hello"") Assert.Equal("(System.Int16 c, System.String d)", model.GetTypeInfo(node.Parent).Type.ToTestDisplayString()); Assert.Equal("(System.Int16 a, System.String b)", model.GetTypeInfo(node.Parent).ConvertedType.ToTestDisplayString()); Assert.Equal(Conversion.Identity, model.GetConversion(node.Parent)); var x = nodes.OfType().First(); Assert.Equal("(System.Int16 a, System.String b) x", model.GetDeclaredSymbol(x).ToTestDisplayString()); } [Fact] public void TupleConvertedTypeNull01() { var source = @" class C { static void Main() { (short a, string b) x = (e: 1, f: null); } } " + trivial2uple + trivial3uple + tupleattributes_cs; var tree = Parse(source, options: TestOptions.Regular); var comp = CreateCompilation(tree); var model = comp.GetSemanticModel(tree, ignoreAccessibility: false); var nodes = tree.GetCompilationUnitRoot().DescendantNodes(); var node = nodes.OfType().Single(); Assert.Equal(@"(e: 1, f: null)", node.ToString()); Assert.Null(model.GetTypeInfo(node).Type); Assert.Equal("(System.Int16 a, System.String b)", model.GetTypeInfo(node).ConvertedType.ToTestDisplayString()); Assert.Equal(ConversionKind.ImplicitTupleLiteral, model.GetConversion(node).Kind); var x = nodes.OfType().First(); Assert.Equal("(System.Int16 a, System.String b) x", model.GetDeclaredSymbol(x).ToTestDisplayString()); } [Fact] public void TupleConvertedTypeNull01insource() { var source = @" class C { static void Main() { (short a, string b) x = ((short c, string d))(e: 1, f: null); string y = (string)null; } } " + trivial2uple + trivial3uple + tupleattributes_cs; var tree = Parse(source, options: TestOptions.Regular); var comp = CreateCompilation(tree); var model = comp.GetSemanticModel(tree, ignoreAccessibility: false); var nodes = tree.GetCompilationUnitRoot().DescendantNodes(); var lnull = nodes.OfType().ElementAt(2); Assert.Equal(@"null", lnull.ToString()); Assert.Null(model.GetTypeInfo(lnull).Type); Assert.Null(model.GetTypeInfo(lnull).ConvertedType); Assert.Equal(Conversion.Identity, model.GetConversion(lnull)); var node = nodes.OfType().Single(); Assert.Equal(@"(e: 1, f: null)", node.ToString()); Assert.Null(model.GetTypeInfo(node).Type); Assert.Equal("(System.Int16 c, System.String d)", model.GetTypeInfo(node).ConvertedType.ToTestDisplayString()); Assert.Equal(ConversionKind.ExplicitTupleLiteral, model.GetConversion(node).Kind); // semantic model returns topmost conversion from the sequence of conversions for // ((short c, string d))(e: 1, f: null) Assert.Equal("(System.Int16 c, System.String d)", model.GetTypeInfo(node.Parent).Type.ToTestDisplayString()); Assert.Equal("(System.Int16 a, System.String b)", model.GetTypeInfo(node.Parent).ConvertedType.ToTestDisplayString()); Assert.Equal(Conversion.Identity, model.GetConversion(node.Parent)); var x = nodes.OfType().First(); Assert.Equal("(System.Int16 a, System.String b) x", model.GetDeclaredSymbol(x).ToTestDisplayString()); } [Fact] public void TupleConvertedTypeUDC01() { var source = @" class C { static void Main() { (short a, string b) x = (e: 1, f: new C1(""qq"")); System.Console.WriteLine(x.ToString()); } class C1 { private string s; public C1(string arg) { s = arg + 1; } public static implicit operator string (C1 arg) { return arg.s; } } } " + trivial2uple + trivial3uple + tupleattributes_cs; var tree = Parse(source, options: TestOptions.Regular); var comp = CreateCompilation(tree, options: TestOptions.ReleaseExe); var model = comp.GetSemanticModel(tree, ignoreAccessibility: false); var nodes = tree.GetCompilationUnitRoot().DescendantNodes(); var node = nodes.OfType().Single(); Assert.Equal(@"(e: 1, f: new C1(""qq""))", node.ToString()); Assert.Equal("(System.Int32 e, C.C1 f)", model.GetTypeInfo(node).Type.ToTestDisplayString()); Assert.Equal("(System.Int16 a, System.String b)", model.GetTypeInfo(node).ConvertedType.ToTestDisplayString()); Assert.Equal(ConversionKind.ImplicitTupleLiteral, model.GetConversion(node).Kind); var x = nodes.OfType().First(); Assert.Equal("(System.Int16 a, System.String b) x", model.GetDeclaredSymbol(x).ToTestDisplayString()); CompileAndVerify(comp, expectedOutput: "{1, qq1}"); } [Fact] public void TupleConvertedTypeUDC01insource() { var source = @" class C { static void Main() { (short a, string b) x = ((short c, string d))(e: 1, f: new C1(""qq"")); System.Console.WriteLine(x.ToString()); } class C1 { private string s; public C1(string arg) { s = arg + 1; } public static implicit operator string (C1 arg) { return arg.s; } } } " + trivial2uple + trivial3uple + tupleattributes_cs; var tree = Parse(source, options: TestOptions.Regular); var comp = CreateCompilation(tree, options: TestOptions.ReleaseExe); var model = comp.GetSemanticModel(tree, ignoreAccessibility: false); var nodes = tree.GetCompilationUnitRoot().DescendantNodes(); var node = nodes.OfType().Single(); Assert.Equal(@"(e: 1, f: new C1(""qq""))", node.ToString()); Assert.Equal("(System.Int32 e, C.C1 f)", model.GetTypeInfo(node).Type.ToTestDisplayString()); Assert.Equal("(System.Int16 c, System.String d)", model.GetTypeInfo(node).ConvertedType.ToTestDisplayString()); Assert.Equal(ConversionKind.ExplicitTupleLiteral, model.GetConversion(node).Kind); ExpressionSyntax element; element = node.Arguments[0].Expression; Assert.Equal("System.Int32", model.GetTypeInfo(element).Type.ToTestDisplayString()); Assert.Equal("System.Int16", model.GetTypeInfo(element).ConvertedType.ToTestDisplayString()); Assert.Equal(ConversionKind.ImplicitConstant, model.GetConversion(element).Kind); element = node.Arguments[1].Expression; Assert.Equal("C.C1", model.GetTypeInfo(element).Type.ToTestDisplayString()); Assert.Equal("System.String", model.GetTypeInfo(element).ConvertedType.ToTestDisplayString()); Assert.Equal(ConversionKind.ExplicitUserDefined, model.GetConversion(element).Kind); // semantic model returns topmost conversion from the sequence of conversions for // ((short c, string d))(e: 1, f: null) Assert.Equal("(System.Int16 c, System.String d)", model.GetTypeInfo(node.Parent).Type.ToTestDisplayString()); Assert.Equal("(System.Int16 a, System.String b)", model.GetTypeInfo(node.Parent).ConvertedType.ToTestDisplayString()); Assert.Equal(Conversion.Identity, model.GetConversion(node.Parent)); var x = nodes.OfType().First(); Assert.Equal("(System.Int16 a, System.String b) x", model.GetDeclaredSymbol(x).ToTestDisplayString()); CompileAndVerify(comp, expectedOutput: "{1, qq1}"); } [Fact] [WorkItem(11289, "https://github.com/dotnet/roslyn/issues/11289")] public void TupleConvertedTypeUDC02() { var source = @" class C { static void Main() { C1 x = (1, ""qq""); System.Console.WriteLine(x.ToString()); } class C1 { private (byte, string) val; private C1((byte, string) arg) { val = arg; } public static implicit operator C1 ((byte, string) arg) { return new C1(arg); } public override string ToString() { return val.ToString(); } } } " + trivial2uple + tupleattributes_cs; var tree = Parse(source, options: TestOptions.Regular); var comp = CreateCompilation(tree, options: TestOptions.ReleaseExe); comp.VerifyDiagnostics(); var model = comp.GetSemanticModel(tree, ignoreAccessibility: false); var nodes = tree.GetCompilationUnitRoot().DescendantNodes(); var node = nodes.OfType().Single(); Assert.Equal(@"(1, ""qq"")", node.ToString()); var typeInfo = model.GetTypeInfo(node); Assert.Equal("(System.Int32, System.String)", typeInfo.Type.ToTestDisplayString()); Assert.Equal("C.C1", typeInfo.ConvertedType.ToTestDisplayString()); Assert.Equal(ConversionKind.ImplicitUserDefined, model.GetConversion(node).Kind); CompileAndVerify(comp, expectedOutput: "{1, qq}"); } [Fact] public void TupleConvertedTypeUDC03() { var source = @" class C { static void Main() { C1 x = (""1"", ""qq""); System.Console.WriteLine(x.ToString()); } class C1 { private (byte, string) val; private C1((byte, string) arg) { val = arg; } public static implicit operator C1 ((byte, string) arg) { return new C1(arg); } public override string ToString() { return val.ToString(); } } } "; var tree = Parse(source, options: TestOptions.Regular); var comp = CreateCompilation(tree, options: TestOptions.ReleaseExe); comp.VerifyDiagnostics( // (6,16): error CS0029: Cannot implicitly convert type '(string, string)' to 'C.C1' // C1 x = ("1", "qq"); Diagnostic(ErrorCode.ERR_NoImplicitConv, @"(""1"", ""qq"")").WithArguments("(string, string)", "C.C1").WithLocation(6, 16) ); var model = comp.GetSemanticModel(tree, ignoreAccessibility: false); var nodes = tree.GetCompilationUnitRoot().DescendantNodes(); var node = nodes.OfType().Single(); Assert.Equal(@"(""1"", ""qq"")", node.ToString()); var typeInfo = model.GetTypeInfo(node); Assert.Equal("(System.String, System.String)", typeInfo.Type.ToTestDisplayString()); Assert.Equal("C.C1", typeInfo.ConvertedType.ToTestDisplayString()); Assert.Equal(Conversion.NoConversion, model.GetConversion(node)); } [Fact] [WorkItem(11289, "https://github.com/dotnet/roslyn/issues/11289")] public void TupleConvertedTypeUDC04() { var source = @" public class C { static void Main() { C1 x = (1, ""qq""); System.Console.WriteLine(x.ToString()); } public class C1 { private (byte, string) val; public C1((byte, string) arg) { val = arg; } public override string ToString() { return val.ToString(); } } } namespace System { // struct with two values public struct ValueTuple { public T1 Item1; public T2 Item2; public ValueTuple(T1 item1, T2 item2) { this.Item1 = item1; this.Item2 = item2; } public override string ToString() { return '{' + Item1?.ToString() + "", "" + Item2?.ToString() + '}'; } public static implicit operator C.C1 ((T1, T2) arg) { return new C.C1(((byte)(int)(object)arg.Item1, (string)(object)arg.Item2)); } } } "; var tree = Parse(source, options: TestOptions.Regular); var comp = CreateCompilation(tree, options: TestOptions.ReleaseExe); comp.VerifyDiagnostics(); var model = comp.GetSemanticModel(tree, ignoreAccessibility: false); var nodes = tree.GetCompilationUnitRoot().DescendantNodes(); var node = nodes.OfType().First(); Assert.Equal(@"(1, ""qq"")", node.ToString()); var typeInfo = model.GetTypeInfo(node); Assert.Equal("(System.Int32, System.String)", typeInfo.Type.ToTestDisplayString()); Assert.Equal("C.C1", typeInfo.ConvertedType.ToTestDisplayString()); Assert.Equal(ConversionKind.ImplicitUserDefined, model.GetConversion(node).Kind); CompileAndVerify(comp, expectedOutput: "{1, qq}"); } [Fact] [WorkItem(11289, "https://github.com/dotnet/roslyn/issues/11289")] public void TupleConvertedTypeUDC05() { var source = @" public class C { static void Main() { C1 x = (1, ""qq""); System.Console.WriteLine(x.ToString()); } public class C1 { private (byte, string) val; public C1((byte, string) arg) { val = arg; } public static implicit operator C1 ((byte, string) arg) { System.Console.WriteLine(""C1""); return new C1(arg); } public override string ToString() { return val.ToString(); } } } namespace System { // struct with two values public struct ValueTuple { public T1 Item1; public T2 Item2; public ValueTuple(T1 item1, T2 item2) { this.Item1 = item1; this.Item2 = item2; } public override string ToString() { return '{' + Item1?.ToString() + "", "" + Item2?.ToString() + '}'; } public static implicit operator C.C1 ((T1, T2) arg) { System.Console.WriteLine(""VT""); return new C.C1(((byte)(int)(object)arg.Item1, (string)(object)arg.Item2)); } } } "; var tree = Parse(source, options: TestOptions.Regular); var comp = CreateCompilation(tree, options: TestOptions.ReleaseExe); comp.VerifyDiagnostics(); var model = comp.GetSemanticModel(tree, ignoreAccessibility: false); var nodes = tree.GetCompilationUnitRoot().DescendantNodes(); var node = nodes.OfType().First(); Assert.Equal(@"(1, ""qq"")", node.ToString()); var typeInfo = model.GetTypeInfo(node); Assert.Equal("(System.Int32, System.String)", typeInfo.Type.ToTestDisplayString()); Assert.Equal("C.C1", typeInfo.ConvertedType.ToTestDisplayString()); Assert.Equal(ConversionKind.ImplicitUserDefined, model.GetConversion(node).Kind); CompileAndVerify(comp, expectedOutput: @"VT {1, qq}"); } [Fact] [WorkItem(11289, "https://github.com/dotnet/roslyn/issues/11289")] public void TupleConvertedTypeUDC06() { var source = @" public class C { static void Main() { C1 x = (1, null); System.Console.WriteLine(x.ToString()); } public class C1 { private (byte, string) val; public C1((byte, string) arg) { val = arg; } public static implicit operator C1 ((byte, string) arg) { System.Console.WriteLine(""C1""); return new C1(arg); } public override string ToString() { return val.ToString(); } } } namespace System { // struct with two values public struct ValueTuple { public T1 Item1; public T2 Item2; public ValueTuple(T1 item1, T2 item2) { this.Item1 = item1; this.Item2 = item2; } public override string ToString() { return '{' + Item1?.ToString() + "", "" + Item2?.ToString() + '}'; } public static implicit operator C.C1 ((T1, T2) arg) { System.Console.WriteLine(""VT""); return new C.C1(((byte)(int)(object)arg.Item1, (string)(object)arg.Item2)); } } } "; var tree = Parse(source, options: TestOptions.Regular); var comp = CreateCompilation(tree, options: TestOptions.ReleaseExe); comp.VerifyDiagnostics(); var model = comp.GetSemanticModel(tree, ignoreAccessibility: false); var nodes = tree.GetCompilationUnitRoot().DescendantNodes(); var node = nodes.OfType().First(); Assert.Equal(@"(1, null)", node.ToString()); var typeInfo = model.GetTypeInfo(node); Assert.Null(typeInfo.Type); Assert.Equal("C.C1", typeInfo.ConvertedType.ToTestDisplayString()); Assert.Equal(ConversionKind.ImplicitUserDefined, model.GetConversion(node).Kind); CompileAndVerify(comp, expectedOutput: @"C1 {1, }"); } [Fact] public void TupleConvertedTypeUDC07() { var source = @" class C { static void Main() { C1 x = M1(); System.Console.WriteLine(x.ToString()); } static (int, string) M1() { return (1, ""qq""); } class C1 { private (byte, string) val; private C1((byte, string) arg) { val = arg; } public static implicit operator C1 ((byte, string) arg) { return new C1(arg); } } } "; var tree = Parse(source, options: TestOptions.Regular); var comp = CreateCompilation(tree, options: TestOptions.ReleaseExe); comp.VerifyDiagnostics( // (6,16): error CS0029: Cannot implicitly convert type '(int, string)' to 'C.C1' // C1 x = M1(); Diagnostic(ErrorCode.ERR_NoImplicitConv, "M1()").WithArguments("(int, string)", "C.C1").WithLocation(6, 16) ); } [Fact] public void Inference01() { var source = @" using System; class C { static void Main() { Test((null, null)); Test((1, 1)); Test((()=>7, ()=>8), 2); } static void Test((T, T) x) { System.Console.WriteLine(""first""); } static void Test((object, object) x) { System.Console.WriteLine(""second""); } static void Test((Func, Func) x, T y) { System.Console.WriteLine(""third""); System.Console.WriteLine(x.Item1().ToString()); } } "; var comp = CompileAndVerify(source, parseOptions: TestOptions.Regular, expectedOutput: @" second first third 7 "); } [Fact] public void Inference02() { var source = @" using System; class C { static void Main() { Test((()=>7, ()=>8)); } static void Test((T, T) x) { System.Console.WriteLine(""first""); } static void Test((object, object) x) { System.Console.WriteLine(""second""); } static void Test((Func, Func) x) { System.Console.WriteLine(""third""); System.Console.WriteLine(x.Item1().ToString()); } } "; var comp = CompileAndVerify(source, parseOptions: TestOptions.Regular, expectedOutput: @" third 7 "); } [Fact] public void Inference02_WithoutTuple() { var source = @" using System; class C { static void Main() { Test(()=>7, ()=>8); } static void Test(T x, T y) { System.Console.WriteLine(""first""); } static void Test(object x, object y) { System.Console.WriteLine(""second""); } static void Test(Func x, Func y) { System.Console.WriteLine(""third""); System.Console.WriteLine(x().ToString()); } } "; var comp = CompileAndVerify(source, parseOptions: TestOptions.Regular, expectedOutput: @" third 7 "); } [Fact] public void Inference03() { var source = @" using System; class C { static void Main() { Test(((x)=>x, (x)=>x)); } static void Test((T, T) x) { System.Console.WriteLine(""first""); } static void Test((object, object) x) { System.Console.WriteLine(""second""); } static void Test((Func, Func) x) { System.Console.WriteLine(""third""); System.Console.WriteLine(x.Item1(5).ToString()); } } "; var comp = CompileAndVerify(source, expectedOutput: @" third 5 "); } [Fact] public void Inference04() { var source = @" using System; class C { static void Main() { Test( (x)=>x.y ); Test( (x)=>x.bob ); } static void Test( Func<(byte x, byte y), T> x) { System.Console.WriteLine(""first""); System.Console.WriteLine(x((2,3)).ToString()); } static void Test( Func<(int alice, int bob), T> x) { System.Console.WriteLine(""second""); System.Console.WriteLine(x((4,5)).ToString()); } } "; var comp = CompileAndVerify(source, parseOptions: TestOptions.Regular, expectedOutput: @" first 3 second 5 "); } [Fact] public void Inference05() { var source = @" using System; class C { static void Main() { Test( ((x)=>x.x, (x)=>x.Item2) ); Test( ((x)=>x.bob, (x)=>x.Item1) ); } static void Test( (Func<(byte x, byte y), T> f1, Func<(int, int), T> f2) x) { System.Console.WriteLine(""first""); System.Console.WriteLine(x.f1((2,3)).ToString()); System.Console.WriteLine(x.f2((2,3)).ToString()); } static void Test( (Func<(int alice, int bob), T> f1, Func<(int, int), T> f2) x) { System.Console.WriteLine(""second""); System.Console.WriteLine(x.f1((4,5)).ToString()); System.Console.WriteLine(x.f2((4,5)).ToString()); } } "; var comp = CompileAndVerify(source, parseOptions: TestOptions.Regular, expectedOutput: @" first 2 3 second 5 4 "); } [WorkItem(10801, "https://github.com/dotnet/roslyn/issues/10801")] [Fact(Skip = "https://github.com/dotnet/roslyn/issues/10801")] public void Inference06() { var source = @" using System; class Program { static void Main(string[] args) { M1((() => ""qq"", null)); } static void M1((Func f, object o) a) { System.Console.WriteLine(1); } static void M1((Func f, object o) a) { System.Console.WriteLine(2); } } " + trivial2uple + tupleattributes_cs; var comp = CompileAndVerify(source, expectedOutput: @" 2 "); } [Fact] public void Inference07() { var source = @" using System; class C { static void Main() { Test((x) => (x, x), (t) => 1); Test1((x) => (x, x), (t) => 1); Test2((a: 1, b: 2), (t) => (t.a, t.b)); } static void Test(Func> f1, Func, int> f2) { System.Console.WriteLine(f2(f1(1))); } static void Test1(Func f1, Func<(U, U), int> f2) { System.Console.WriteLine(f2(f1(1))); } static void Test2(U f1, Func f2) { System.Console.WriteLine(f2(f1).y); } } "; var comp = CompileAndVerify(source, parseOptions: TestOptions.Regular, expectedOutput: @" 1 1 2 "); } [Fact] public void Inference08() { var source = @" using System; class C { static void Main() { Test1((a: 1, b: 2), (c: 3, d: 4)); Test2((a: 1, b: 2), (c: 3, d: 4), t => t.Item2); Test2((a: 1, b: 2), (a: 3, b: 4), t => t.a); Test2((a: 1, b: 2), (c: 3, d: 4), t => t.a); } static void Test1(T x, T y) { System.Console.WriteLine(""test1""); System.Console.WriteLine(x); } static void Test2(T x, T y, Func f) { System.Console.WriteLine(""test2_1""); System.Console.WriteLine(f(x)); } static void Test2(T x, object y, Func f) { System.Console.WriteLine(""test2_2""); System.Console.WriteLine(f(x)); } } " + trivial2uple + tupleattributes_cs; var comp = CompileAndVerify(source, expectedOutput: @" test1 {1, 2} test2_1 2 test2_1 1 test2_2 1 "); } [Fact] public void Inference08t() { var source = @" using System; class C { static void Main() { var ab = (a: 1, b: 2); var cd = (c: 3, d: 4); Test1(ab, cd); Test2(ab, cd, t => t.Item2); Test2(ab, ab, t => t.a); Test2(ab, cd, t => t.a); } static void Test1(T x, T y) { System.Console.WriteLine(""test1""); System.Console.WriteLine(x); } static void Test2(T x, T y, Func f) { System.Console.WriteLine(""test2_1""); System.Console.WriteLine(f(x)); } static void Test2(T x, object y, Func f) { System.Console.WriteLine(""test2_2""); System.Console.WriteLine(f(x)); } } " + trivial2uple + tupleattributes_cs; var comp = CompileAndVerify(source, expectedOutput: @" test1 {1, 2} test2_1 2 test2_1 1 test2_2 1 "); } [Fact] public void Inference09() { var source = @" using System; class C { static void Main() { // byval tuple, as a whole, sets a lower bound Test1((a: 1, b: 2), (ValueType)1); } static void Test1(T x, T y) { System.Console.WriteLine(typeof(T)); } } " + trivial2uple + tupleattributes_cs; var comp = CompileAndVerify(source, expectedOutput: @" System.ValueType "); } [Fact] public void Inference10() { var source = @" using System; class C { static void Main() { // byref tuple, as a whole, sets an exact bound var t = (a: 1, b: 2); Test1(ref t, (ValueType)1); } static void Test1(ref T x, T y) { System.Console.WriteLine(typeof(T)); } } " + trivial2uple + tupleattributes_cs; var comp = CreateCompilation(source); comp.VerifyDiagnostics( // (10,9): error CS0411: The type arguments for method 'C.Test1(ref T, T)' cannot be inferred from the usage. Try specifying the type arguments explicitly. // Test1(ref t, (ValueType)1); Diagnostic(ErrorCode.ERR_CantInferMethTypeArgs, "Test1").WithArguments("C.Test1(ref T, T)").WithLocation(10, 9) ); } [WorkItem(10800, "https://github.com/dotnet/roslyn/issues/10800")] [Fact] public void Inference11() { var source = @" class C { static void Main() { object o = null; dynamic d = null; var ab = (a: 1, b: o); var ad = (a: 1, d: d); var t1 = Test1(ref ab, ad); // exact bound and lower bound var t2 = Test2(ab, ref ad); // lower bound and exact bound var t3 = Test3(ref ab, ref ad); // two exact bounds var d1 = Test1(ref o, d); var d2 = Test2(o, ref d); var d3 = Test3(ref o, ref d); } static T Test1(ref T x, T y) => x; static T Test2(T x, ref T y) => x; static T Test3(ref T x, ref T y) => x; } " + trivial2uple + tupleattributes_cs; var comp = CreateCompilation(source, references: new[] { CSharpRef }); comp.VerifyDiagnostics( // (17,18): error CS0411: The type arguments for method 'C.Test3(ref T, ref T)' cannot be inferred from the usage. Try specifying the type arguments explicitly. // var d3 = Test3(ref o, ref d); Diagnostic(ErrorCode.ERR_CantInferMethTypeArgs, "Test3").WithArguments("C.Test3(ref T, ref T)").WithLocation(17, 18) ); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var names = tree.GetRoot().DescendantNodes().OfType(); var t1 = names.ElementAt(4); Assert.Equal("(System.Int32 a, dynamic) t1", model.GetDeclaredSymbol(t1).ToTestDisplayString()); var t2 = names.ElementAt(5); Assert.Equal("(System.Int32 a, dynamic) t2", model.GetDeclaredSymbol(t2).ToTestDisplayString()); var t3 = names.ElementAt(6); Assert.Equal("(System.Int32 a, dynamic) t3", model.GetDeclaredSymbol(t3).ToTestDisplayString()); var d1 = names.ElementAt(7); Assert.Equal("dynamic d1", model.GetDeclaredSymbol(d1).ToTestDisplayString()); var d2 = names.ElementAt(8); Assert.Equal("dynamic d2", model.GetDeclaredSymbol(d2).ToTestDisplayString()); var d3 = names.ElementAt(9); Assert.Equal("T d3", model.GetDeclaredSymbol(d3).ToTestDisplayString()); } [WorkItem(10800, "https://github.com/dotnet/roslyn/issues/10800")] [Fact] public void Inference11InNestedType() { var source = @" class C { static void Main() { object o = null; dynamic d = null; var ab = new [] { ((a: 1, b: o), c: 2) }; var ad = new [] { ((a: 1, d: d), c: 2) }; var t1 = Test1(ref ab, ad); // exact bound and lower bound var t2 = Test2(ab, ref ad); // lower bound and exact bound var t3 = Test3(ref ab, ref ad); // two exact bounds } static T Test1(ref T x, T y) => x; static T Test2(T x, ref T y) => x; static T Test3(ref T x, ref T y) => x; } " + trivial2uple + tupleattributes_cs; var comp = CreateCompilation(source, references: new[] { CSharpRef }); comp.VerifyDiagnostics(); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var names = tree.GetRoot().DescendantNodes().OfType(); var t1 = names.ElementAt(4); Assert.Equal("((System.Int32 a, dynamic), System.Int32 c)[] t1", model.GetDeclaredSymbol(t1).ToTestDisplayString()); var t2 = names.ElementAt(5); Assert.Equal("((System.Int32 a, dynamic), System.Int32 c)[] t2", model.GetDeclaredSymbol(t2).ToTestDisplayString()); var t3 = names.ElementAt(6); Assert.Equal("((System.Int32 a, dynamic), System.Int32 c)[] t3", model.GetDeclaredSymbol(t3).ToTestDisplayString()); } [WorkItem(10800, "https://github.com/dotnet/roslyn/issues/10800")] [Fact] public void Inference11WithLongTuple() { var source = @" class C { static void Main() { object o = null; dynamic d = null; var ay = (a: o, b: 2, c: 3, d: 4, e: 5, f: 6, g: 7, h: 8, y: 9); var az = (a: d, b: 2, c: 3, d: 4, e: 5, f: 6, g: 7, 8, z: 10); var t1 = Test1(ref ay, az); // exact bound and lower bound var t2 = Test2(ay, ref az); // lower bound and exact bound var t3 = Test3(ref ay, ref az); // two exact bounds } static T Test1(ref T x, T y) => x; static T Test2(T x, ref T y) => x; static T Test3(ref T x, ref T y) => x; } "; var comp = CreateCompilation(source); comp.VerifyDiagnostics(); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var names = tree.GetRoot().DescendantNodes().OfType(); var t1 = names.ElementAt(4); Assert.Equal("(dynamic a, System.Int32 b, System.Int32 c, System.Int32 d, System.Int32 e, System.Int32 f, System.Int32 g, System.Int32, System.Int32) t1", model.GetDeclaredSymbol(t1).ToTestDisplayString()); var t2 = names.ElementAt(5); Assert.Equal("(dynamic a, System.Int32 b, System.Int32 c, System.Int32 d, System.Int32 e, System.Int32 f, System.Int32 g, System.Int32, System.Int32) t2", model.GetDeclaredSymbol(t2).ToTestDisplayString()); var t3 = names.ElementAt(6); Assert.Equal("(dynamic a, System.Int32 b, System.Int32 c, System.Int32 d, System.Int32 e, System.Int32 f, System.Int32 g, System.Int32, System.Int32) t3", model.GetDeclaredSymbol(t3).ToTestDisplayString()); } [WorkItem(10800, "https://github.com/dotnet/roslyn/issues/10800")] [Fact] public void Inference11OnlyDynamicMismatch() { var source = @" using System.Linq; class C { static void Main() { object o = null; dynamic d = null; var doc = (new [] { ((a: d, b: o), c: 2) }).ToList(); var odc = (new [] { ((a: o, b: d), c: 2) }).ToList(); var t1 = Test1(ref doc, odc); // exact bound and lower bound var t2 = Test2(doc, ref odc); // lower bound and exact bound var t3 = Test3(ref doc, ref odc); // two exact bounds } static T Test1(ref T x, T y) => x; static T Test2(T x, ref T y) => x; static T Test3(ref T x, ref T y) => x; } "; var comp = CreateCompilation(source, references: new[] { CSharpRef }); comp.VerifyDiagnostics(); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var names = tree.GetRoot().DescendantNodes().OfType(); var t1 = names.ElementAt(4); Assert.Equal("System.Collections.Generic.List<((dynamic a, dynamic b), System.Int32 c)> t1", model.GetDeclaredSymbol(t1).ToTestDisplayString()); var t2 = names.ElementAt(5); Assert.Equal("System.Collections.Generic.List<((dynamic a, dynamic b), System.Int32 c)> t2", model.GetDeclaredSymbol(t2).ToTestDisplayString()); var t3 = names.ElementAt(6); Assert.Equal("System.Collections.Generic.List<((dynamic a, dynamic b), System.Int32 c)> t3", model.GetDeclaredSymbol(t3).ToTestDisplayString()); } [WorkItem(10800, "https://github.com/dotnet/roslyn/issues/10800")] [Fact] public void Inference11WithMoreThanTwoTypes() { var source = @" class C { static void Main() { var ab = (a: 1, b: 2); var cd = (c: 1, d: 2); var de = (d: 1, e: 2); var t1 = Test1(ref ab, cd, 1, de); } static T Test1(ref T x, T y, T z, T w) => x; } "; var comp = CreateCompilation(source, references: new[] { CSharpRef }); comp.VerifyDiagnostics( // (10,18): error CS0411: The type arguments for method 'C.Test1(ref T, T, T, T)' cannot be inferred from the usage. Try specifying the type arguments explicitly. // var t1 = Test1(ref ab, cd, 1, de); Diagnostic(ErrorCode.ERR_CantInferMethTypeArgs, "Test1").WithArguments("C.Test1(ref T, T, T, T)").WithLocation(10, 18) ); } [WorkItem(10800, "https://github.com/dotnet/roslyn/issues/10800")] [Fact] public void Inference11WithMoreThanTwoTypes2() { var source = @" class C { static void Main() { var abc = (a: 1, b: 2, c: 3); var abd = (a: 1, b: 2, d: 3); var byz = (b: 1, y: 2, c: 3); var t1 = Test1(ref abc, abd, byz); } static T Test1(ref T x, T y, T z) => x; } "; var comp = CreateCompilation(source, references: new[] { CSharpRef }); comp.VerifyDiagnostics(); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var t1 = tree.GetRoot().DescendantNodes().OfType().ElementAt(3); Assert.Equal("(System.Int32, System.Int32, System.Int32) t1", model.GetDeclaredSymbol(t1).ToTestDisplayString()); } [Fact] public void Inference11WithUpperBound() { var source = @" using System; using System.Collections.Generic; class Program { static void Main(string[] args) { Action> x1 = null; Action> x2 = null; var t1 = Test1(ref x1, x1, x2); // one exact bound and two upper bounds on T var t2 = Test2(x1, x2); // two upper bounds } public static T Test1(ref Action x, Action y, Action z) { return default(T); } public static T Test2(Action x, Action y) { return default(T); } } "; var comp = CreateCompilationWithMscorlib40(source, references: s_valueTupleRefs); comp.VerifyDiagnostics(); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var t1 = tree.GetRoot().DescendantNodes().OfType().ElementAt(2); Assert.Equal("System.Collections.Generic.IEnumerable<(System.Int32 a, dynamic)> t1", model.GetDeclaredSymbol(t1).ToTestDisplayString()); var t2 = tree.GetRoot().DescendantNodes().OfType().ElementAt(3); Assert.Equal("System.Collections.Generic.IEnumerable<(System.Int32 a, dynamic)> t2", model.GetDeclaredSymbol(t2).ToTestDisplayString()); } [WorkItem(10800, "https://github.com/dotnet/roslyn/issues/10800")] [Fact] public void Inference11WithImplicitConversion() { var source = @" class C { static void Main() { var ab = (a: 1, b: 2); var adL = (a: 1L, d: 2L); // `adL` is an exact bound, which `ab` can convert to, so the names on `ab` are ignored var t1 = Test1(ref adL, ab); var t2 = Test2(ab, ref adL); } static T Test1(ref T x, T y) => x; static T Test2(T x, ref T y) => x; } "; var comp = CreateCompilation(source); comp.VerifyDiagnostics(); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var names = tree.GetRoot().DescendantNodes().OfType(); var t1 = names.ElementAt(2); Assert.Equal("(System.Int64 a, System.Int64 d) t1", model.GetDeclaredSymbol(t1).ToTestDisplayString()); var t2 = names.ElementAt(3); Assert.Equal("(System.Int64 a, System.Int64 d) t2", model.GetDeclaredSymbol(t2).ToTestDisplayString()); } [Fact] public void Inference12() { var source = @" class C { static void Main() { // nested tuple literals set lower bounds Test1((a: 1, b: (a: 1, b: 2)), (a: 1, b: (object)1)); Test1((a: 1, b: (a: 1, b: 2)), (a: 1, b: (c: 1, d: 2))); Test1((a: 1, b: (a: 1, b: 2)), (a: 1, b: (1, 2))); Test1((a: 1, b: (a: 1, b: 2)), (a: 1, b: (a: 1, b: 2))); } static void Test1((T, U) x, (T, U) y) { System.Console.WriteLine(typeof(U)); } } "; var comp = CompileAndVerify(source, parseOptions: TestOptions.Regular, expectedOutput: @" System.Object System.ValueTuple`2[System.Int32,System.Int32] System.ValueTuple`2[System.Int32,System.Int32] System.ValueTuple`2[System.Int32,System.Int32] "); } [Fact] public void Inference13() { var source = @" class C { static void Main() { // nested tuple literals set lower bounds Test1((a: 1, b: (a: 1, b: 2)), (a: 1, b: (object)1)); Test1(Nullable((a: 1, b: (a: 1, b: 2))), (a: 1, b: (object)1)); Test1((a: 1, b: (a: 1, b: 2)), (a: 1, b: (c: 1, d: 2))); Test1((a: 1, b: (a: 1, b: 2)), (a: 1, b: (1, 2))); Test1((a: 1, b: (a: 1, b: 2)), (a: 1, b: (a: 1, b: 2))); } static T? Nullable(T x) where T : struct { return x; } static void Test1((T, U)? x, (T, U) y) { System.Console.WriteLine(typeof(U)); } } "; var comp = CompileAndVerify(source, parseOptions: TestOptions.Regular, expectedOutput: @" System.Object System.Object System.ValueTuple`2[System.Int32,System.Int32] System.ValueTuple`2[System.Int32,System.Int32] System.ValueTuple`2[System.Int32,System.Int32] "); } [Fact] public void Inference13_Err() { var source = @" class C { static void Main() { Test1(Nullable((a: 1, b: (a: 1, b: 2))), (a: 1, b: (object)1)); Test1((a: 1, b: (a: 1, b: 2)), Nullable((a: 1, b: (object)1))); } static T? Nullable(T x) where T : struct { return x; } static void Test1((T, U) x, (T, U) y) { System.Console.WriteLine(typeof(U)); } } "; var comp = CreateCompilation(source); comp.VerifyDiagnostics( // (6,15): error CS1503: Argument 1: cannot convert from '(int a, (int a, int b) b)?' to '(int, object)' // Test1(Nullable((a: 1, b: (a: 1, b: 2))), (a: 1, b: (object)1)); Diagnostic(ErrorCode.ERR_BadArgType, "Nullable((a: 1, b: (a: 1, b: 2)))").WithArguments("1", "(int a, (int a, int b) b)?", "(int, object)").WithLocation(6, 15), // (7,40): error CS1503: Argument 2: cannot convert from '(int a, object b)?' to '(int, (int a, int b))' // Test1((a: 1, b: (a: 1, b: 2)), Nullable((a: 1, b: (object)1))); Diagnostic(ErrorCode.ERR_BadArgType, "Nullable((a: 1, b: (object)1))").WithArguments("2", "(int a, object b)?", "(int, (int a, int b))").WithLocation(7, 40) ); } [Fact] public void Inference14() { var source = @" class C { static void Main() { // nested tuple literals set lower bounds Test1((a: 1, b: (a: 1, b: 2)), (a: 1, b: (c: 1, d: 2))); Test1((a: 1, b: (a: 1, b: 2)), (a: 1, b: (1, 2))); Test1((a: 1, b: (a: 1, b: 2)), (a: 1, b: (a: 1, b: 2))); } static void Test1((T, U)? x, (T, U?) y) where U: struct { System.Console.WriteLine(typeof(U)); } } "; var comp = CreateCompilation(source); comp.VerifyDiagnostics( // (7,9): error CS0411: The type arguments for method 'C.Test1((T, U)?, (T, U?))' cannot be inferred from the usage. Try specifying the type arguments explicitly. // Test1((a: 1, b: (a: 1, b: 2)), (a: 1, b: (c: 1, d: 2))); Diagnostic(ErrorCode.ERR_CantInferMethTypeArgs, "Test1").WithArguments("C.Test1((T, U)?, (T, U?))").WithLocation(7, 9), // (8,9): error CS0411: The type arguments for method 'C.Test1((T, U)?, (T, U?))' cannot be inferred from the usage. Try specifying the type arguments explicitly. // Test1((a: 1, b: (a: 1, b: 2)), (a: 1, b: (1, 2))); Diagnostic(ErrorCode.ERR_CantInferMethTypeArgs, "Test1").WithArguments("C.Test1((T, U)?, (T, U?))").WithLocation(8, 9), // (9,9): error CS0411: The type arguments for method 'C.Test1((T, U)?, (T, U?))' cannot be inferred from the usage. Try specifying the type arguments explicitly. // Test1((a: 1, b: (a: 1, b: 2)), (a: 1, b: (a: 1, b: 2))); Diagnostic(ErrorCode.ERR_CantInferMethTypeArgs, "Test1").WithArguments("C.Test1((T, U)?, (T, U?))").WithLocation(9, 9) ); } [Fact] public void Inference15() { var source = @" class C { static void Main() { Test1((a: ""q"", b: null), (a: null, b: ""w""), (x) => x.z); } static void Test1((T, U) x, (T, U) y, System.Func<(T x, U z), T> f) { System.Console.WriteLine(typeof(U)); System.Console.WriteLine(f(y)); } } "; var comp = CompileAndVerify(source, parseOptions: TestOptions.Regular, expectedOutput: @" System.String w "); } [Fact] public void Inference16() { var source = @" class C { static void Main() { // tuples set lower bounds var x = (1,2,3); Test(x); var x1 = (1,2,(long)3); Test(x1); var x2 = (1,(object)2,(long)3); Test(x2); } static void Test((T, T, T) x) { System.Console.WriteLine(typeof(T)); } } "; var comp = CompileAndVerify(source, parseOptions: TestOptions.Regular, expectedOutput: @" System.Int32 System.Int64 System.Object "); } [Fact] public void Constraints_01() { var source = @" namespace System { public struct ValueTuple where T2 : class { public ValueTuple(T1 _1, T2 _2) => throw null; } } class C { static void Main((int, int) p) { var t0 = (1, 2); (int, int) t1 = t0; } }"; var comp = CreateCompilationWithMscorlib45AndCSharp(source); comp.VerifyDiagnostics( // (14,33): error CS0452: The type 'int' must be a reference type in order to use it as parameter 'T2' in the generic type or method '(T1, T2)' // static void Main((int, int) p) Diagnostic(ErrorCode.ERR_RefConstraintNotSatisfied, "p").WithArguments("(T1, T2)", "T2", "int").WithLocation(14, 33), // (16,22): error CS0452: The type 'int' must be a reference type in order to use it as parameter 'T2' in the generic type or method '(T1, T2)' // var t0 = (1, 2); Diagnostic(ErrorCode.ERR_RefConstraintNotSatisfied, "2").WithArguments("(T1, T2)", "T2", "int").WithLocation(16, 22), // (17,15): error CS0452: The type 'int' must be a reference type in order to use it as parameter 'T2' in the generic type or method '(T1, T2)' // (int, int) t1 = t0; Diagnostic(ErrorCode.ERR_RefConstraintNotSatisfied, "int").WithArguments("(T1, T2)", "T2", "int").WithLocation(17, 15) ); } [Fact] [WorkItem(15399, "https://github.com/dotnet/roslyn/issues/15399")] public void Constraints_02() { var source = @" using System; class Program { unsafe void M((int, int*) p, ValueTuple q) { (int, int*) t0 = p; var t1 = (1, (int*)null); var t2 = new ValueTuple(1, null); ValueTuple t3 = t2; } }"; var comp = CreateCompilationWithMscorlib45AndCSharp(source, references: s_valueTupleRefs, options: TestOptions.UnsafeDebugDll); comp.VerifyDiagnostics( // (5,31): error CS0306: The type 'int*' may not be used as a type argument // unsafe void M((int, int*) p, ValueTuple q) Diagnostic(ErrorCode.ERR_BadTypeArgument, "p").WithArguments("int*").WithLocation(5, 31), // (5,56): error CS0306: The type 'int*' may not be used as a type argument // unsafe void M((int, int*) p, ValueTuple q) Diagnostic(ErrorCode.ERR_BadTypeArgument, "q").WithArguments("int*").WithLocation(5, 56), // (7,15): error CS0306: The type 'int*' may not be used as a type argument // (int, int*) t0 = p; Diagnostic(ErrorCode.ERR_BadTypeArgument, "int*").WithArguments("int*").WithLocation(7, 15), // (8,22): error CS0306: The type 'int*' may not be used as a type argument // var t1 = (1, (int*)null); Diagnostic(ErrorCode.ERR_BadTypeArgument, "(int*)null").WithArguments("int*").WithLocation(8, 22), // (9,38): error CS0306: The type 'int*' may not be used as a type argument // var t2 = new ValueTuple(1, null); Diagnostic(ErrorCode.ERR_BadTypeArgument, "int*").WithArguments("int*").WithLocation(9, 38), // (10,25): error CS0306: The type 'int*' may not be used as a type argument // ValueTuple t3 = t2; Diagnostic(ErrorCode.ERR_BadTypeArgument, "int*").WithArguments("int*").WithLocation(10, 25), // (8,13): warning CS0219: The variable 't1' is assigned but its value is never used // var t1 = (1, (int*)null); Diagnostic(ErrorCode.WRN_UnreferencedVarAssg, "t1").WithArguments("t1").WithLocation(8, 13) ); } [Fact] public void Constraints_03() { var source = @" using System.Collections.Generic; namespace System { public struct ValueTuple where T2 : class { public ValueTuple(T1 _1, T2 _2) => throw null; } } class C { List<(T, T)> field = null; (U, U) M(U x) { var t0 = new C(); var t1 = M(1); return default((U, U)); } }"; var comp = CreateCompilationWithMscorlib45AndCSharp(source); comp.VerifyDiagnostics( // (15,12): error CS0452: The type 'U' must be a reference type in order to use it as parameter 'T2' in the generic type or method '(T1, T2)' // (U, U) M(U x) Diagnostic(ErrorCode.ERR_RefConstraintNotSatisfied, "M").WithArguments("(T1, T2)", "T2", "U").WithLocation(15, 12), // (14,18): error CS0452: The type 'T' must be a reference type in order to use it as parameter 'T2' in the generic type or method '(T1, T2)' // List<(T, T)> field = null; Diagnostic(ErrorCode.ERR_RefConstraintNotSatisfied, "field").WithArguments("(T1, T2)", "T2", "T").WithLocation(14, 18), // (19,28): error CS0452: The type 'U' must be a reference type in order to use it as parameter 'T2' in the generic type or method '(T1, T2)' // return default((U, U)); Diagnostic(ErrorCode.ERR_RefConstraintNotSatisfied, "U").WithArguments("(T1, T2)", "T2", "U").WithLocation(19, 28), // (14,18): warning CS0414: The field 'C.field' is assigned but its value is never used // List<(T, T)> field = null; Diagnostic(ErrorCode.WRN_UnreferencedFieldAssg, "field").WithArguments("C.field").WithLocation(14, 18) ); } [Fact] public void Constraints_04() { var source = @" using System.Collections.Generic; namespace System { public struct ValueTuple where T2 : class { public ValueTuple(T1 _1, T2 _2) => throw null; } } class C where T : class { List<(T, T)> field = null; (U, U) M(U x) where U : class { var t0 = new C(); var t1 = M(1); return default((U, U)); } }"; var comp = CreateCompilationWithMscorlib45AndCSharp(source); comp.VerifyDiagnostics( // (17,24): error CS0452: The type 'int' must be a reference type in order to use it as parameter 'T' in the generic type or method 'C' // var t0 = new C(); Diagnostic(ErrorCode.ERR_RefConstraintNotSatisfied, "int").WithArguments("C", "T", "int").WithLocation(17, 24), // (18,18): error CS0452: The type 'int' must be a reference type in order to use it as parameter 'U' in the generic type or method 'C.M(U)' // var t1 = M(1); Diagnostic(ErrorCode.ERR_RefConstraintNotSatisfied, "M").WithArguments("C.M(U)", "U", "int").WithLocation(18, 18), // (14,18): warning CS0414: The field 'C.field' is assigned but its value is never used // List<(T, T)> field = null; Diagnostic(ErrorCode.WRN_UnreferencedFieldAssg, "field").WithArguments("C.field").WithLocation(14, 18) ); } [Fact] public void Constraints_05() { var source = @" using System.Collections.Generic; namespace System { public struct ValueTuple where T2 : struct { public ValueTuple(T1 _1, T2 _2) => throw null; } } class C where T : class { List<(T, T)> field = null; (U, U) M(U x) where U : class { var t0 = new C(); var t1 = M((1, 2)); return default((U, U)); } }"; var comp = CreateCompilationWithMscorlib45AndCSharp(source); comp.VerifyDiagnostics( // (15,12): error CS0453: The type 'U' must be a non-nullable value type in order to use it as parameter 'T2' in the generic type or method '(T1, T2)' // (U, U) M(U x) where U : class Diagnostic(ErrorCode.ERR_ValConstraintNotSatisfied, "M").WithArguments("(T1, T2)", "T2", "U").WithLocation(15, 12), // (14,18): error CS0453: The type 'T' must be a non-nullable value type in order to use it as parameter 'T2' in the generic type or method '(T1, T2)' // List<(T, T)> field = null; Diagnostic(ErrorCode.ERR_ValConstraintNotSatisfied, "field").WithArguments("(T1, T2)", "T2", "T").WithLocation(14, 18), // (17,24): error CS0452: The type 'int' must be a reference type in order to use it as parameter 'T' in the generic type or method 'C' // var t0 = new C(); Diagnostic(ErrorCode.ERR_RefConstraintNotSatisfied, "int").WithArguments("C", "T", "int").WithLocation(17, 24), // (18,18): error CS0452: The type '(int, int)' must be a reference type in order to use it as parameter 'U' in the generic type or method 'C.M(U)' // var t1 = M((1, 2)); Diagnostic(ErrorCode.ERR_RefConstraintNotSatisfied, "M").WithArguments("C.M(U)", "U", "(int, int)").WithLocation(18, 18), // (19,28): error CS0453: The type 'U' must be a non-nullable value type in order to use it as parameter 'T2' in the generic type or method '(T1, T2)' // return default((U, U)); Diagnostic(ErrorCode.ERR_ValConstraintNotSatisfied, "U").WithArguments("(T1, T2)", "T2", "U").WithLocation(19, 28), // (14,18): warning CS0414: The field 'C.field' is assigned but its value is never used // List<(T, T)> field = null; Diagnostic(ErrorCode.WRN_UnreferencedFieldAssg, "field").WithArguments("C.field").WithLocation(14, 18) ); } [Fact] public void Constraints_06() { var source = @" namespace System { public struct ValueTuple where T1 : class { public T1 Item1; public ValueTuple(T1 item1) { this.Item1 = item1; } } public struct ValueTuple where TRest : class { public T1 Item1; public T2 Item2; public T3 Item3; public T4 Item4; public T5 Item5; public T6 Item6; public T7 Item7; public TRest Rest; public ValueTuple(T1 item1, T2 item2, T3 item3, T4 item4, T5 item5, T6 item6, T7 item7, TRest rest) { Item1 = item1; Item2 = item2; Item3 = item3; Item4 = item4; Item5 = item5; Item6 = item6; Item7 = item7; Rest = rest; } } } class C { void M((int, int, int, int, int, int, int, int) p) { var t0 = (1, 2, 3, 4, 5, 6, 7, 8); (int, int, int, int, int, int, int, int) t1 = t0; } }"; var comp = CreateCompilationWithMscorlib45AndCSharp(source); comp.VerifyDiagnostics( // (42,53): error CS0452: The type 'ValueTuple' must be a reference type in order to use it as parameter 'TRest' in the generic type or method 'ValueTuple' // void M((int, int, int, int, int, int, int, int) p) Diagnostic(ErrorCode.ERR_RefConstraintNotSatisfied, "p").WithArguments("System.ValueTuple", "TRest", "System.ValueTuple").WithLocation(42, 53), // (42,53): error CS0452: The type 'int' must be a reference type in order to use it as parameter 'T1' in the generic type or method 'ValueTuple' // void M((int, int, int, int, int, int, int, int) p) Diagnostic(ErrorCode.ERR_RefConstraintNotSatisfied, "p").WithArguments("System.ValueTuple", "T1", "int").WithLocation(42, 53), // (44,18): error CS0452: The type 'ValueTuple' must be a reference type in order to use it as parameter 'TRest' in the generic type or method 'ValueTuple' // var t0 = (1, 2, 3, 4, 5, 6, 7, 8); Diagnostic(ErrorCode.ERR_RefConstraintNotSatisfied, "(1, 2, 3, 4, 5, 6, 7, 8)").WithArguments("System.ValueTuple", "TRest", "System.ValueTuple").WithLocation(44, 18), // (44,40): error CS0452: The type 'int' must be a reference type in order to use it as parameter 'T1' in the generic type or method 'ValueTuple' // var t0 = (1, 2, 3, 4, 5, 6, 7, 8); Diagnostic(ErrorCode.ERR_RefConstraintNotSatisfied, "8").WithArguments("System.ValueTuple", "T1", "int").WithLocation(44, 40), // (45,9): error CS0452: The type 'ValueTuple' must be a reference type in order to use it as parameter 'TRest' in the generic type or method 'ValueTuple' // (int, int, int, int, int, int, int, int) t1 = t0; Diagnostic(ErrorCode.ERR_RefConstraintNotSatisfied, "(int, int, int, int, int, int, int, int)").WithArguments("System.ValueTuple", "TRest", "System.ValueTuple").WithLocation(45, 9), // (45,45): error CS0452: The type 'int' must be a reference type in order to use it as parameter 'T1' in the generic type or method 'ValueTuple' // (int, int, int, int, int, int, int, int) t1 = t0; Diagnostic(ErrorCode.ERR_RefConstraintNotSatisfied, "int").WithArguments("System.ValueTuple", "T1", "int").WithLocation(45, 45) ); } [Fact] public void LongTupleConstraints() { var source = @" using System; class Program { unsafe void M0((int, int, int, int, int, int, int, int*) p) { (int, int, int, int, int, int, int, int*) t1 = p; var t2 = (1, 2, 3, 4, 5, 6, 7, (int*)null); var t3 = new ValueTuple> (); var t4 = new ValueTuple (); ValueTuple> t5 = t3; ValueTuple t6 = t4; } unsafe void M1((int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int*) q) { (int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int*) v1 = q; var v2 = (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, (int*)null); } }"; var comp = CreateCompilationWithMscorlib45AndCSharp(source, references: s_valueTupleRefs, options: TestOptions.UnsafeDebugDll); comp.VerifyDiagnostics( // (15,102): error CS0306: The type 'int*' may not be used as a type argument // unsafe void M1((int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int*) q) Diagnostic(ErrorCode.ERR_BadTypeArgument, "q").WithArguments("int*").WithLocation(15, 102), // (5,62): error CS0306: The type 'int*' may not be used as a type argument // unsafe void M0((int, int, int, int, int, int, int, int*) p) Diagnostic(ErrorCode.ERR_BadTypeArgument, "p").WithArguments("int*").WithLocation(5, 62), // (7,45): error CS0306: The type 'int*' may not be used as a type argument // (int, int, int, int, int, int, int, int*) t1 = p; Diagnostic(ErrorCode.ERR_BadTypeArgument, "int*").WithArguments("int*").WithLocation(7, 45), // (8,40): error CS0306: The type 'int*' may not be used as a type argument // var t2 = (1, 2, 3, 4, 5, 6, 7, (int*)null); Diagnostic(ErrorCode.ERR_BadTypeArgument, "(int*)null").WithArguments("int*").WithLocation(8, 40), // (9,84): error CS0306: The type 'int*' may not be used as a type argument // var t3 = new ValueTuple> (); Diagnostic(ErrorCode.ERR_BadTypeArgument, "int*").WithArguments("int*").WithLocation(9, 84), // (10,74): error CS0306: The type 'int*' may not be used as a type argument // var t4 = new ValueTuple (); Diagnostic(ErrorCode.ERR_BadTypeArgument, "int*").WithArguments("int*").WithLocation(10, 74), // (11,71): error CS0306: The type 'int*' may not be used as a type argument // ValueTuple> t5 = t3; Diagnostic(ErrorCode.ERR_BadTypeArgument, "int*").WithArguments("int*").WithLocation(11, 71), // (12,61): error CS0306: The type 'int*' may not be used as a type argument // ValueTuple t6 = t4; Diagnostic(ErrorCode.ERR_BadTypeArgument, "int*").WithArguments("int*").WithLocation(12, 61), // (8,13): warning CS0219: The variable 't2' is assigned but its value is never used // var t2 = (1, 2, 3, 4, 5, 6, 7, (int*)null); Diagnostic(ErrorCode.WRN_UnreferencedVarAssg, "t2").WithArguments("t2").WithLocation(8, 13), // (17,85): error CS0306: The type 'int*' may not be used as a type argument // (int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int*) v1 = q; Diagnostic(ErrorCode.ERR_BadTypeArgument, "int*").WithArguments("int*").WithLocation(17, 85), // (18,70): error CS0306: The type 'int*' may not be used as a type argument // var v2 = (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, (int*)null); Diagnostic(ErrorCode.ERR_BadTypeArgument, "(int*)null").WithArguments("int*").WithLocation(18, 70), // (18,13): warning CS0219: The variable 'v2' is assigned but its value is never used // var v2 = (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, (int*)null); Diagnostic(ErrorCode.WRN_UnreferencedVarAssg, "v2").WithArguments("v2").WithLocation(18, 13) ); } [Fact] public void RestrictedTypes1() { var source = @" class C { static void Main() { var x = (1, 2, new System.ArgIterator()); (int x, object y) y = (1, 2, new System.ArgIterator()); (int x, System.ArgIterator y) z = (1, 2, new System.ArgIterator()); } } " + trivial2uple + trivial3uple + tupleattributes_cs; var comp = CreateCompilationWithMscorlib40(source); comp.VerifyDiagnostics( // (6,24): error CS0306: The type 'ArgIterator' may not be used as a type argument // var x = (1, 2, new System.ArgIterator()); Diagnostic(ErrorCode.ERR_BadTypeArgument, "new System.ArgIterator()").WithArguments("System.ArgIterator").WithLocation(6, 24), // (7,38): error CS0306: The type 'ArgIterator' may not be used as a type argument // (int x, object y) y = (1, 2, new System.ArgIterator()); Diagnostic(ErrorCode.ERR_BadTypeArgument, "new System.ArgIterator()").WithArguments("System.ArgIterator").WithLocation(7, 38), // (7,31): error CS0029: Cannot implicitly convert type '(int, int, System.ArgIterator)' to '(int x, object y)' // (int x, object y) y = (1, 2, new System.ArgIterator()); Diagnostic(ErrorCode.ERR_NoImplicitConv, "(1, 2, new System.ArgIterator())").WithArguments("(int, int, System.ArgIterator)", "(int x, object y)").WithLocation(7, 31), // (8,36): error CS0306: The type 'ArgIterator' may not be used as a type argument // (int x, System.ArgIterator y) z = (1, 2, new System.ArgIterator()); Diagnostic(ErrorCode.ERR_BadTypeArgument, "y").WithArguments("System.ArgIterator").WithLocation(8, 36), // (8,50): error CS0306: The type 'ArgIterator' may not be used as a type argument // (int x, System.ArgIterator y) z = (1, 2, new System.ArgIterator()); Diagnostic(ErrorCode.ERR_BadTypeArgument, "new System.ArgIterator()").WithArguments("System.ArgIterator").WithLocation(8, 50), // (8,43): error CS0029: Cannot implicitly convert type '(int, int, System.ArgIterator)' to '(int x, System.ArgIterator y)' // (int x, System.ArgIterator y) z = (1, 2, new System.ArgIterator()); Diagnostic(ErrorCode.ERR_NoImplicitConv, "(1, 2, new System.ArgIterator())").WithArguments("(int, int, System.ArgIterator)", "(int x, System.ArgIterator y)").WithLocation(8, 43), // (6,13): warning CS0219: The variable 'x' is assigned but its value is never used // var x = (1, 2, new System.ArgIterator()); Diagnostic(ErrorCode.WRN_UnreferencedVarAssg, "x").WithArguments("x").WithLocation(6, 13) ); } [Fact] public void RestrictedTypes2() { var source = @" class C { static void Main() { (int x, System.ArgIterator y) y; } } " + trivial2uple + trivial3uple + tupleattributes_cs; var comp = CreateCompilationWithMscorlib40(source); comp.VerifyDiagnostics( // (6,36): error CS0306: The type 'ArgIterator' may not be used as a type argument // (int x, System.ArgIterator y) y; Diagnostic(ErrorCode.ERR_BadTypeArgument, "y").WithArguments("System.ArgIterator").WithLocation(6, 36), // (6,39): warning CS0168: The variable 'y' is declared but never used // (int x, System.ArgIterator y) y; Diagnostic(ErrorCode.WRN_UnreferencedVar, "y").WithArguments("y").WithLocation(6, 39) ); } [Fact, WorkItem(10569, "https://github.com/dotnet/roslyn/issues/10569")] public void IncompleteInterfaceMethod() { var source = @" public interface MyInterface { (int, int) Goo() } "; var comp = CreateCompilation(source); comp.VerifyDiagnostics( // (3,21): error CS1002: ; expected // (int, int) Goo() Diagnostic(ErrorCode.ERR_SemicolonExpected, "").WithLocation(3, 21) ); } [Fact] public void ImplementInterface() { var source = @" interface I { (int Alice, string Bob) M((int x, string y) value); (int Alice, string Bob) P1 { get; } } class C : I { static void Main() { var c = new C(); var x = c.M(c.P1); System.Console.WriteLine(x); } public (int Alice, string Bob) M((int x, string y) value) { return value; } public (int Alice, string Bob) P1 => (r: 1, s: ""hello""); } "; var comp = CompileAndVerify(source, parseOptions: TestOptions.Regular, expectedOutput: @"(1, hello) "); } [Fact] public void ImplementInterfaceExplicitly() { var source = @" interface I { (int Alice, string Bob) M((int x, string y) value); (int Alice, string Bob) P1 { get; } } class C : I { static void Main() { I c = new C(); var x = c.M(c.P1); System.Console.WriteLine(x); System.Console.WriteLine(x.Alice); } (int Alice, string Bob) I.M((int x, string y) value) { return value; } public (int Alice, string Bob) P1 => (r: 1, s: ""hello""); } "; var comp = CompileAndVerify(source, parseOptions: TestOptions.Regular, expectedOutput: @"(1, hello) 1"); } [Fact] public void TupleTypeArguments() { var source = @" interface I where TB : TA { (TA, TB) M(TA a, TB b); } class C : I<(int, string), (int Alice, string Bob)> { static void Main() { var c = new C(); var x = c.M((1, ""Australia""), (2, ""Brazil"")); System.Console.WriteLine(x); } public ((int, string), (int Alice, string Bob)) M((int, string) x, (int Alice, string Bob) y) { return (x, y); } } "; var comp = CompileAndVerify(source, parseOptions: TestOptions.Regular, expectedOutput: @"((1, Australia), (2, Brazil))"); } [Fact] public void LongTupleTypeArguments() { var source = @" interface I where TB : TA { (TA, TB) M(TA a, TB b); } class C : I<(int, string, int, string, int, string, int, string), (int A, string B, int C, string D, int E, string F, int G, string H)> { static void Main() { var c = new C(); var x = c.M((1, ""Australia"", 2, ""Brazil"", 3, ""Columbia"", 4, ""Ecuador""), (5, ""France"", 6, ""Germany"", 7, ""Honduras"", 8, ""India"")); System.Console.WriteLine(x); } public ((int, string, int, string, int, string, int, string), (int A, string B, int C, string D, int E, string F, int G, string H)) M((int, string, int, string, int, string, int, string) a, (int A, string B, int C, string D, int E, string F, int G, string H) b) { return (a, b); } } "; var comp = CompileAndVerify(source, expectedOutput: @"((1, Australia, 2, Brazil, 3, Columbia, 4, Ecuador), (5, France, 6, Germany, 7, Honduras, 8, India))"); } [Fact] public void OverrideGenericInterfaceWithDifferentNames() { string source = @" interface I where TB : TA { (TA returnA, TB returnB) M((TA paramA, TB paramB) x); } class C : I<(int b, int a), (int a, int b)> { public virtual ((int, int) x, (int, int) y) M(((int, int), (int, int)) x) { throw new System.Exception(); } } class D : C, I<(int a, int b), (int c, int d)> { public override ((int b, int a), (int b, int a)) M(((int a, int b), (int b, int a)) y) { return y; } } "; var comp = CreateCompilation(source); comp.VerifyDiagnostics( // (9,49): error CS8141: The tuple element names in the signature of method 'C.M(((int, int), (int, int)))' must match the tuple element names of interface method 'I<(int b, int a), (int a, int b)>.M(((int b, int a) paramA, (int a, int b) paramB))' (including on the return type). // public virtual ((int, int) x, (int, int) y) M(((int, int), (int, int)) x) Diagnostic(ErrorCode.ERR_ImplBadTupleNames, "M").WithArguments("C.M(((int, int), (int, int)))", "I<(int b, int a), (int a, int b)>.M(((int b, int a) paramA, (int a, int b) paramB))").WithLocation(9, 49), // (17,54): error CS8139: 'D.M(((int a, int b), (int b, int a)))': cannot change tuple element names when overriding inherited member 'C.M(((int, int), (int, int)))' // public override ((int b, int a), (int b, int a)) M(((int a, int b), (int b, int a)) y) Diagnostic(ErrorCode.ERR_CantChangeTupleNamesOnOverride, "M").WithArguments("D.M(((int a, int b), (int b, int a)))", "C.M(((int, int), (int, int)))").WithLocation(17, 54), // (17,54): error CS8141: The tuple element names in the signature of method 'D.M(((int a, int b), (int b, int a)))' must match the tuple element names of interface method 'I<(int a, int b), (int c, int d)>.M(((int a, int b) paramA, (int c, int d) paramB))' (including on the return type). // public override ((int b, int a), (int b, int a)) M(((int a, int b), (int b, int a)) y) Diagnostic(ErrorCode.ERR_ImplBadTupleNames, "M").WithArguments("D.M(((int a, int b), (int b, int a)))", "I<(int a, int b), (int c, int d)>.M(((int a, int b) paramA, (int c, int d) paramB))").WithLocation(17, 54) ); } [Fact] public void TupleWithoutFeatureFlag() { var source = @" class C { static void Main() { (int, int) x = (1, 1); } CS0151ERR_IntegralTypeValueExpected} " + trivial2uple + tupleattributes_cs; var comp = CreateCompilation(source, parseOptions: TestOptions.Regular6); comp.VerifyDiagnostics( // (6,9): error CS8059: Feature 'tuples' is not available in C# 6. Please use language version 7.0 or greater. // (int, int) x = (1, 1); Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion6, "(int, int)").WithArguments("tuples", "7.0").WithLocation(6, 9), // (6,24): error CS8059: Feature 'tuples' is not available in C# 6. Please use language version 7.0 or greater. // (int, int) x = (1, 1); Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion6, "(1, 1)").WithArguments("tuples", "7.0").WithLocation(6, 24), // (8,36): error CS1519: Invalid token '}' in class, struct, or interface member declaration // CS0151ERR_IntegralTypeValueExpected} Diagnostic(ErrorCode.ERR_InvalidMemberDecl, "}").WithArguments("}").WithLocation(8, 36) ); Assert.Equal("7.0", Compilation.GetRequiredLanguageVersion(comp.GetDiagnostics()[0])); Assert.Null(Compilation.GetRequiredLanguageVersion(comp.GetDiagnostics()[2])); Assert.Throws(() => Compilation.GetRequiredLanguageVersion(null)); } [ConditionalFact(typeof(WindowsDesktopOnly), Reason = "https://github.com/dotnet/roslyn/issues/28045")] public void DefaultAndFriendlyElementNames_01() { var source = @" using System; class C { static void Main() { var v1 = M1(); System.Console.WriteLine(v1.Item1); System.Console.WriteLine(v1.Item2); var v2 = M2(); System.Console.WriteLine(v2.Item1); System.Console.WriteLine(v2.Item2); System.Console.WriteLine(v2.a2); System.Console.WriteLine(v2.b2); var v6 = M6(); System.Console.WriteLine(v6.Item1); System.Console.WriteLine(v6.Item2); System.Console.WriteLine(v6.item1); System.Console.WriteLine(v6.item2); System.Console.WriteLine(v1.ToString()); System.Console.WriteLine(v2.ToString()); System.Console.WriteLine(v6.ToString()); } static (int, int) M1() { return (1, 11); } static (int a2, int b2) M2() { return (2, 22); } static (int item1, int item2) M6() { return (6, 66); } } "; var comp = CompileAndVerify(source, parseOptions: TestOptions.Regular, expectedOutput: @"1 11 2 22 2 22 6 66 6 66 (1, 11) (2, 22) (6, 66) "); var c = ((CSharpCompilation)comp.Compilation).GetTypeByMetadataName("C"); var m1Tuple = (NamedTypeSymbol)c.GetMember("M1").ReturnType; var m2Tuple = (NamedTypeSymbol)c.GetMember("M2").ReturnType; var m6Tuple = (NamedTypeSymbol)c.GetMember("M6").ReturnType; AssertTestDisplayString(m1Tuple.GetMembers(), "System.Int32 (System.Int32, System.Int32).Item1", "System.Int32 (System.Int32, System.Int32).Item2", "(System.Int32, System.Int32)..ctor()", "(System.Int32, System.Int32)..ctor(System.Int32 item1, System.Int32 item2)", "System.Boolean (System.Int32, System.Int32).Equals(System.Object obj)", "System.Boolean (System.Int32, System.Int32).Equals((System.Int32, System.Int32) other)", "System.Boolean (System.Int32, System.Int32).System.Collections.IStructuralEquatable.Equals(System.Object other, System.Collections.IEqualityComparer comparer)", "System.Int32 (System.Int32, System.Int32).System.IComparable.CompareTo(System.Object other)", "System.Int32 (System.Int32, System.Int32).CompareTo((System.Int32, System.Int32) other)", "System.Int32 (System.Int32, System.Int32).System.Collections.IStructuralComparable.CompareTo(System.Object other, System.Collections.IComparer comparer)", "System.Int32 (System.Int32, System.Int32).GetHashCode()", "System.Int32 (System.Int32, System.Int32).System.Collections.IStructuralEquatable.GetHashCode(System.Collections.IEqualityComparer comparer)", "System.Int32 (System.Int32, System.Int32).System.ITupleInternal.GetHashCode(System.Collections.IEqualityComparer comparer)", "System.String (System.Int32, System.Int32).ToString()", "System.String (System.Int32, System.Int32).System.ITupleInternal.ToStringEnd()", "System.Int32 (System.Int32, System.Int32).System.ITupleInternal.Size.get", "System.Int32 (System.Int32, System.Int32).System.ITupleInternal.Size { get; }"); Assert.Equal(new string[] { ".ctor", ".ctor", "CompareTo", "Equals", "Equals", "GetHashCode", "Item1", "Item2", "System.Collections.IStructuralComparable.CompareTo", "System.Collections.IStructuralEquatable.Equals", "System.Collections.IStructuralEquatable.GetHashCode", "System.IComparable.CompareTo", "System.ITupleInternal.get_Size", "System.ITupleInternal.GetHashCode", "System.ITupleInternal.Size", "System.ITupleInternal.ToStringEnd", "ToString" }, m1Tuple.TupleData.UnderlyingDefinitionToMemberMap.Values.Select(s => s.Name).OrderBy(n => n).ToArray()); AssertTestDisplayString(m2Tuple.GetMembers(), "System.Int32 (System.Int32 a2, System.Int32 b2).Item1", "System.Int32 (System.Int32 a2, System.Int32 b2).a2", "System.Int32 (System.Int32 a2, System.Int32 b2).Item2", "System.Int32 (System.Int32 a2, System.Int32 b2).b2", "(System.Int32 a2, System.Int32 b2)..ctor()", "(System.Int32 a2, System.Int32 b2)..ctor(System.Int32 item1, System.Int32 item2)", "System.Boolean (System.Int32 a2, System.Int32 b2).Equals(System.Object obj)", "System.Boolean (System.Int32 a2, System.Int32 b2).Equals((System.Int32, System.Int32) other)", "System.Boolean (System.Int32 a2, System.Int32 b2).System.Collections.IStructuralEquatable.Equals(System.Object other, System.Collections.IEqualityComparer comparer)", "System.Int32 (System.Int32 a2, System.Int32 b2).System.IComparable.CompareTo(System.Object other)", "System.Int32 (System.Int32 a2, System.Int32 b2).CompareTo((System.Int32, System.Int32) other)", "System.Int32 (System.Int32 a2, System.Int32 b2).System.Collections.IStructuralComparable.CompareTo(System.Object other, System.Collections.IComparer comparer)", "System.Int32 (System.Int32 a2, System.Int32 b2).GetHashCode()", "System.Int32 (System.Int32 a2, System.Int32 b2).System.Collections.IStructuralEquatable.GetHashCode(System.Collections.IEqualityComparer comparer)", "System.Int32 (System.Int32 a2, System.Int32 b2).System.ITupleInternal.GetHashCode(System.Collections.IEqualityComparer comparer)", "System.String (System.Int32 a2, System.Int32 b2).ToString()", "System.String (System.Int32 a2, System.Int32 b2).System.ITupleInternal.ToStringEnd()", "System.Int32 (System.Int32 a2, System.Int32 b2).System.ITupleInternal.Size.get", "System.Int32 (System.Int32 a2, System.Int32 b2).System.ITupleInternal.Size { get; }"); Assert.Equal(new string[] { ".ctor", ".ctor", "CompareTo", "Equals", "Equals", "GetHashCode", "Item1", "Item2", "System.Collections.IStructuralComparable.CompareTo", "System.Collections.IStructuralEquatable.Equals", "System.Collections.IStructuralEquatable.GetHashCode", "System.IComparable.CompareTo", "System.ITupleInternal.get_Size", "System.ITupleInternal.GetHashCode", "System.ITupleInternal.Size", "System.ITupleInternal.ToStringEnd", "ToString" }, m2Tuple.TupleData.UnderlyingDefinitionToMemberMap.Values.Select(s => s.Name).OrderBy(n => n).ToArray()); AssertTestDisplayString(m6Tuple.GetMembers(), "System.Int32 (System.Int32 item1, System.Int32 item2).Item1", "System.Int32 (System.Int32 item1, System.Int32 item2).item1", "System.Int32 (System.Int32 item1, System.Int32 item2).Item2", "System.Int32 (System.Int32 item1, System.Int32 item2).item2", "(System.Int32 item1, System.Int32 item2)..ctor()", "(System.Int32 item1, System.Int32 item2)..ctor(System.Int32 item1, System.Int32 item2)", "System.Boolean (System.Int32 item1, System.Int32 item2).Equals(System.Object obj)", "System.Boolean (System.Int32 item1, System.Int32 item2).Equals((System.Int32, System.Int32) other)", "System.Boolean (System.Int32 item1, System.Int32 item2).System.Collections.IStructuralEquatable.Equals(System.Object other, System.Collections.IEqualityComparer comparer)", "System.Int32 (System.Int32 item1, System.Int32 item2).System.IComparable.CompareTo(System.Object other)", "System.Int32 (System.Int32 item1, System.Int32 item2).CompareTo((System.Int32, System.Int32) other)", "System.Int32 (System.Int32 item1, System.Int32 item2).System.Collections.IStructuralComparable.CompareTo(System.Object other, System.Collections.IComparer comparer)", "System.Int32 (System.Int32 item1, System.Int32 item2).GetHashCode()", "System.Int32 (System.Int32 item1, System.Int32 item2).System.Collections.IStructuralEquatable.GetHashCode(System.Collections.IEqualityComparer comparer)", "System.Int32 (System.Int32 item1, System.Int32 item2).System.ITupleInternal.GetHashCode(System.Collections.IEqualityComparer comparer)", "System.String (System.Int32 item1, System.Int32 item2).ToString()", "System.String (System.Int32 item1, System.Int32 item2).System.ITupleInternal.ToStringEnd()", "System.Int32 (System.Int32 item1, System.Int32 item2).System.ITupleInternal.Size.get", "System.Int32 (System.Int32 item1, System.Int32 item2).System.ITupleInternal.Size { get; }"); Assert.Equal(new string[] { ".ctor", ".ctor", "CompareTo", "Equals", "Equals", "GetHashCode", "Item1", "Item2", "System.Collections.IStructuralComparable.CompareTo", "System.Collections.IStructuralEquatable.Equals", "System.Collections.IStructuralEquatable.GetHashCode", "System.IComparable.CompareTo", "System.ITupleInternal.get_Size", "System.ITupleInternal.GetHashCode", "System.ITupleInternal.Size", "System.ITupleInternal.ToStringEnd", "ToString" }, m6Tuple.TupleData.UnderlyingDefinitionToMemberMap.Values.Select(s => s.Name).OrderBy(n => n).ToArray()); Assert.Equal("(System.Int32, System.Int32)", m1Tuple.ToTestDisplayString()); Assert.Equal("ValueTuple", m1Tuple.Name); Assert.Equal(SymbolKind.NamedType, m1Tuple.Kind); Assert.Equal(TypeKind.Struct, m1Tuple.TypeKind); Assert.False(m1Tuple.IsImplicitlyDeclared); Assert.True(m1Tuple.IsTupleType); Assert.True(m1Tuple.Equals(m1Tuple.TupleUnderlyingType, TypeCompareKind.ConsiderEverything)); var tupleType = comp.Compilation.CommonGetWellKnownType(WellKnownType.System_ValueTuple_T2); Assert.Same(tupleType, m1Tuple.ConstructedFrom); Assert.False(m1Tuple.IsDefinition); Assert.Same(tupleType, m1Tuple.OriginalDefinition); AssertTupleTypeEquality(m1Tuple); Assert.Same(m1Tuple.TupleUnderlyingType.ContainingSymbol, m1Tuple.ContainingSymbol); Assert.Same(m1Tuple.ContainingSymbol, m1Tuple.ContainingSymbol); Assert.Null(m1Tuple.GetUseSiteDiagnostic()); Assert.Null(m1Tuple.EnumUnderlyingType); AssertEx.SetEqual(new[] { "Item1", "Item2", ".ctor", "Equals", "System.Collections.IStructuralEquatable.Equals", "System.IComparable.CompareTo", "CompareTo", "System.Collections.IStructuralComparable.CompareTo", "GetHashCode", "System.Collections.IStructuralEquatable.GetHashCode", "System.ITupleInternal.GetHashCode", "ToString", "System.ITupleInternal.ToStringEnd", "System.ITupleInternal.get_Size", "System.ITupleInternal.Size" }, m1Tuple.MemberNames.ToArray()); Assert.Equal("(System.Int32 a2, System.Int32 b2)", m2Tuple.ToTestDisplayString()); AssertEx.SetEqual(new[] { "Item1", "a2", "Item2", "b2", ".ctor", "Equals", "System.Collections.IStructuralEquatable.Equals", "System.IComparable.CompareTo", "CompareTo", "System.Collections.IStructuralComparable.CompareTo", "GetHashCode", "System.Collections.IStructuralEquatable.GetHashCode", "System.ITupleInternal.GetHashCode", "ToString", "System.ITupleInternal.ToStringEnd", "System.ITupleInternal.get_Size", "System.ITupleInternal.Size" }, m2Tuple.MemberNames.ToArray()); Assert.Equal(2, m1Tuple.Arity); Assert.Equal(new[] { "T1", "T2" }, m1Tuple.TypeParameters.Select(tp => tp.ToTestDisplayString())); Assert.Equal("System.ValueType", m1Tuple.BaseType().ToTestDisplayString()); Assert.Null(m1Tuple.ComImportCoClass); Assert.True(m1Tuple.TypeArgumentsWithAnnotationsNoUseSiteDiagnostics.All(t => t.CustomModifiers.IsEmpty)); Assert.False(m1Tuple.IsComImport); Assert.Equal(new[] { "System.Int32", "System.Int32" }, m1Tuple.TypeArgumentsWithAnnotationsNoUseSiteDiagnostics.Select(t => t.ToTestDisplayString())); Assert.True(m1Tuple.GetAttributes().IsEmpty); Assert.Equal("System.Int32 (System.Int32 a2, System.Int32 b2).Item1", m2Tuple.GetMembers("Item1").Single().ToTestDisplayString()); Assert.Equal("System.Int32 (System.Int32 a2, System.Int32 b2).a2", m2Tuple.GetMembers("a2").Single().ToTestDisplayString()); Assert.True(m1Tuple.GetTypeMembers().IsEmpty); Assert.True(m1Tuple.GetTypeMembers("C9").IsEmpty); Assert.True(m1Tuple.GetTypeMembers("C9", 0).IsEmpty); Assert.Equal(6, m1Tuple.Interfaces().Length); Assert.Equal("System.Int32 (System.Int32, System.Int32).Item1", m1Tuple.GetEarlyAttributeDecodingMembers("Item1").Single().ToTestDisplayString()); Assert.True(m1Tuple.GetTypeMembersUnordered().IsEmpty); Assert.Equal(1, m1Tuple.Locations.Length); Assert.Equal("(int, int)", m1Tuple.DeclaringSyntaxReferences.Single().GetSyntax().ToString()); Assert.Equal("(int a2, int b2)", m2Tuple.DeclaringSyntaxReferences.Single().GetSyntax().ToString()); AssertTupleTypeEquality(m2Tuple); AssertTupleTypeEquality(m6Tuple); Assert.False(m1Tuple.Equals(m2Tuple)); Assert.False(m1Tuple.Equals(m6Tuple)); Assert.False(m6Tuple.Equals(m2Tuple)); AssertTupleTypeMembersEquality(m1Tuple, m2Tuple); AssertTupleTypeMembersEquality(m1Tuple, m6Tuple); AssertTupleTypeMembersEquality(m2Tuple, m6Tuple); var m1Item1 = (FieldSymbol)m1Tuple.GetMembers()[0]; var m2Item1 = (FieldSymbol)m2Tuple.GetMembers()[0]; var m2a2 = (FieldSymbol)m2Tuple.GetMembers()[1]; AssertNonvirtualTupleElementField(m1Item1); AssertNonvirtualTupleElementField(m2Item1); AssertVirtualTupleElementField(m2a2); Assert.NotSame(m1Item1, m1Item1.OriginalDefinition); Assert.Equal("System.Int32 (System.Int32, System.Int32).Item1", m1Item1.ToTestDisplayString()); Assert.Equal("T1 (T1, T2).Item1", m1Item1.OriginalDefinition.ToTestDisplayString()); Assert.True(m1Item1.ContainingType.OriginalDefinition.TupleElements[0].Equals(m1Item1.OriginalDefinition, TypeCompareKind.ConsiderEverything)); Assert.True(m1Item1.Equals(m1Item1)); Assert.Equal("System.Int32 (System.Int32, System.Int32).Item1", m1Item1.TupleUnderlyingField.ToTestDisplayString()); Assert.Null(m1Item1.AssociatedSymbol); Assert.Same(m1Tuple, m1Item1.ContainingSymbol); Assert.Same(m1Tuple, m1Item1.TupleUnderlyingField.ContainingSymbol); Assert.True(m1Item1.TypeWithAnnotations.CustomModifiers.IsEmpty); Assert.True(m1Item1.GetAttributes().IsEmpty); Assert.Null(m1Item1.GetUseSiteDiagnostic()); Assert.False(m1Item1.Locations.IsEmpty); Assert.True(m1Item1.DeclaringSyntaxReferences.IsEmpty); Assert.Equal("Item1", m1Item1.TupleUnderlyingField.Name); Assert.True(m1Item1.IsImplicitlyDeclared); Assert.Null(m1Item1.TypeLayoutOffset); Assert.False(m2Item1.IsDefinition); Assert.NotSame(m2Item1, m2Item1.OriginalDefinition); Assert.Equal("System.Int32 (System.Int32 a2, System.Int32 b2).Item1", m2Item1.ToTestDisplayString()); Assert.Equal("T1 (T1, T2).Item1", m2Item1.OriginalDefinition.ToTestDisplayString()); Assert.True(m2Item1.ContainingType.OriginalDefinition.TupleElements[0].Equals(m2Item1.OriginalDefinition, TypeCompareKind.ConsiderEverything)); Assert.True(m2Item1.Equals(m2Item1)); Assert.Equal("System.Int32 (System.Int32 a2, System.Int32 b2).Item1", m2Item1.TupleUnderlyingField.ToTestDisplayString()); Assert.Null(m2Item1.AssociatedSymbol); Assert.False(m2Tuple.IsDefinition); Assert.Same(m2Tuple, m2Item1.ContainingSymbol); Assert.Same(m2Tuple, m2Item1.TupleUnderlyingField.ContainingSymbol); Assert.True(m2Item1.TypeWithAnnotations.CustomModifiers.IsEmpty); Assert.True(m2Item1.GetAttributes().IsEmpty); Assert.Null(m2Item1.GetUseSiteDiagnostic()); Assert.False(m2Item1.Locations.IsEmpty); Assert.Equal("Item1", m2Item1.Name); Assert.Equal("Item1", m2Item1.TupleUnderlyingField.Name); Assert.NotEqual(m2Item1.Locations.Single(), m2Item1.TupleUnderlyingField.Locations.Single()); Assert.Equal("MetadataFile(System.ValueTuple.dll)", m2Item1.TupleUnderlyingField.Locations.Single().ToString()); Assert.Equal("SourceFile([826..828))", m2Item1.Locations.Single().ToString()); Assert.True(m2Item1.IsImplicitlyDeclared); Assert.Null(m2Item1.TypeLayoutOffset); Assert.True(m2a2.IsDefinition); Assert.True(m2a2.Equals(m2a2)); Assert.Equal("System.Int32 (System.Int32 a2, System.Int32 b2).a2", m2a2.ToTestDisplayString()); Assert.True(m2a2.ContainingType.OriginalDefinition.TupleElements[0].Equals(m1Item1.OriginalDefinition, TypeCompareKind.ConsiderEverything)); Assert.Equal("System.Int32 (System.Int32 a2, System.Int32 b2).Item1", m2a2.TupleUnderlyingField.ToTestDisplayString()); Assert.Null(m2a2.AssociatedSymbol); Assert.Same(m2Tuple, m2a2.ContainingSymbol); Assert.Same(m2Tuple, m2a2.TupleUnderlyingField.ContainingSymbol); Assert.True(m2a2.TypeWithAnnotations.CustomModifiers.IsEmpty); Assert.True(m2a2.GetAttributes().IsEmpty); Assert.Null(m2a2.GetUseSiteDiagnostic()); Assert.False(m2a2.Locations.IsEmpty); Assert.Equal("int a2", m2a2.DeclaringSyntaxReferences.Single().GetSyntax().ToString()); Assert.Equal("Item1", m2a2.TupleUnderlyingField.Name); Assert.False(m2a2.IsImplicitlyDeclared); Assert.Null(m2a2.TypeLayoutOffset); Assert.False(m6Tuple.IsDefinition); } [ConditionalFact(typeof(WindowsDesktopOnly), Reason = "https://github.com/dotnet/roslyn/issues/28045")] public void DefaultAndFriendlyElementNames_LongTuple() { var source = @" using System; class C { static void Main() { var v1 = M1(); System.Console.Write(v1.Item9 + "" ""); var v1b = M1b(); System.Console.Write(v1b.Item9 + "" ""); var v2 = M2(); System.Console.Write(v2.Item9 + "" ""); System.Console.Write(v2.i2 + "" ""); var v6 = M6(); System.Console.Write(v6.item8 + "" ""); } static (int, int, int, int, int, int, int, int, int) M1() => (1, 1, 1, 11, 11, 11, 111, 111, 111); static ValueTuple> M1b() => (1, 1, 1, 11, 11, 11, 111, 111, 111); static (int a2, int b2, int c2, int d2, int e2, int f2, int g2, int h2, int i2) M2() => (2, 2, 2, 22, 22, 22, 222, 222, 222); static (int item1, int item2, int item3, int item4, int item5, int item6, int item7, int item8) M6() => (6, 6, 6, 66, 66, 66, 666, 666); } "; var comp = CompileAndVerify(source, parseOptions: TestOptions.Regular, expectedOutput: @"111 111 222 222 666"); var c = ((CSharpCompilation)comp.Compilation).GetTypeByMetadataName("C"); var m1Tuple = (NamedTypeSymbol)c.GetMember("M1").ReturnType; var m1bTuple = (NamedTypeSymbol)c.GetMember("M1b").ReturnType; var m2Tuple = (NamedTypeSymbol)c.GetMember("M2").ReturnType; var m6Tuple = (NamedTypeSymbol)c.GetMember("M6").ReturnType; AssertTestDisplayString(m1Tuple.GetMembers(), "System.Int32 (System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32).Item1", "System.Int32 (System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32).Item2", "System.Int32 (System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32).Item3", "System.Int32 (System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32).Item4", "System.Int32 (System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32).Item5", "System.Int32 (System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32).Item6", "System.Int32 (System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32).Item7", "(System.Int32, System.Int32) (System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32).Rest", "(System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32)..ctor()", "(System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32)..ctor(System.Int32 item1, System.Int32 item2, System.Int32 item3, System.Int32 item4, System.Int32 item5, System.Int32 item6, System.Int32 item7, (System.Int32, System.Int32) rest)", "System.Boolean (System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32).Equals(System.Object obj)", "System.Boolean (System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32).Equals((System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32) other)", "System.Boolean (System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32).System.Collections.IStructuralEquatable.Equals(System.Object other, System.Collections.IEqualityComparer comparer)", "System.Int32 (System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32).System.IComparable.CompareTo(System.Object other)", "System.Int32 (System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32).CompareTo((System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32) other)", "System.Int32 (System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32).System.Collections.IStructuralComparable.CompareTo(System.Object other, System.Collections.IComparer comparer)", "System.Int32 (System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32).GetHashCode()", "System.Int32 (System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32).System.Collections.IStructuralEquatable.GetHashCode(System.Collections.IEqualityComparer comparer)", "System.Int32 (System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32).System.ITupleInternal.GetHashCode(System.Collections.IEqualityComparer comparer)", "System.String (System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32).ToString()", "System.String (System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32).System.ITupleInternal.ToStringEnd()", "System.Int32 (System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32).System.ITupleInternal.Size.get", "System.Int32 (System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32).System.ITupleInternal.Size { get; }", "System.Int32 (System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32).Item8", "System.Int32 (System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32).Item9"); AssertTestDisplayString(m2Tuple.GetMembers(), "System.Int32 (System.Int32 a2, System.Int32 b2, System.Int32 c2, System.Int32 d2, System.Int32 e2, System.Int32 f2, System.Int32 g2, System.Int32 h2, System.Int32 i2).Item1", "System.Int32 (System.Int32 a2, System.Int32 b2, System.Int32 c2, System.Int32 d2, System.Int32 e2, System.Int32 f2, System.Int32 g2, System.Int32 h2, System.Int32 i2).a2", "System.Int32 (System.Int32 a2, System.Int32 b2, System.Int32 c2, System.Int32 d2, System.Int32 e2, System.Int32 f2, System.Int32 g2, System.Int32 h2, System.Int32 i2).Item2", "System.Int32 (System.Int32 a2, System.Int32 b2, System.Int32 c2, System.Int32 d2, System.Int32 e2, System.Int32 f2, System.Int32 g2, System.Int32 h2, System.Int32 i2).b2", "System.Int32 (System.Int32 a2, System.Int32 b2, System.Int32 c2, System.Int32 d2, System.Int32 e2, System.Int32 f2, System.Int32 g2, System.Int32 h2, System.Int32 i2).Item3", "System.Int32 (System.Int32 a2, System.Int32 b2, System.Int32 c2, System.Int32 d2, System.Int32 e2, System.Int32 f2, System.Int32 g2, System.Int32 h2, System.Int32 i2).c2", "System.Int32 (System.Int32 a2, System.Int32 b2, System.Int32 c2, System.Int32 d2, System.Int32 e2, System.Int32 f2, System.Int32 g2, System.Int32 h2, System.Int32 i2).Item4", "System.Int32 (System.Int32 a2, System.Int32 b2, System.Int32 c2, System.Int32 d2, System.Int32 e2, System.Int32 f2, System.Int32 g2, System.Int32 h2, System.Int32 i2).d2", "System.Int32 (System.Int32 a2, System.Int32 b2, System.Int32 c2, System.Int32 d2, System.Int32 e2, System.Int32 f2, System.Int32 g2, System.Int32 h2, System.Int32 i2).Item5", "System.Int32 (System.Int32 a2, System.Int32 b2, System.Int32 c2, System.Int32 d2, System.Int32 e2, System.Int32 f2, System.Int32 g2, System.Int32 h2, System.Int32 i2).e2", "System.Int32 (System.Int32 a2, System.Int32 b2, System.Int32 c2, System.Int32 d2, System.Int32 e2, System.Int32 f2, System.Int32 g2, System.Int32 h2, System.Int32 i2).Item6", "System.Int32 (System.Int32 a2, System.Int32 b2, System.Int32 c2, System.Int32 d2, System.Int32 e2, System.Int32 f2, System.Int32 g2, System.Int32 h2, System.Int32 i2).f2", "System.Int32 (System.Int32 a2, System.Int32 b2, System.Int32 c2, System.Int32 d2, System.Int32 e2, System.Int32 f2, System.Int32 g2, System.Int32 h2, System.Int32 i2).Item7", "System.Int32 (System.Int32 a2, System.Int32 b2, System.Int32 c2, System.Int32 d2, System.Int32 e2, System.Int32 f2, System.Int32 g2, System.Int32 h2, System.Int32 i2).g2", "(System.Int32, System.Int32) (System.Int32 a2, System.Int32 b2, System.Int32 c2, System.Int32 d2, System.Int32 e2, System.Int32 f2, System.Int32 g2, System.Int32 h2, System.Int32 i2).Rest", "(System.Int32 a2, System.Int32 b2, System.Int32 c2, System.Int32 d2, System.Int32 e2, System.Int32 f2, System.Int32 g2, System.Int32 h2, System.Int32 i2)..ctor()", "(System.Int32 a2, System.Int32 b2, System.Int32 c2, System.Int32 d2, System.Int32 e2, System.Int32 f2, System.Int32 g2, System.Int32 h2, System.Int32 i2)..ctor(System.Int32 item1, System.Int32 item2, System.Int32 item3, System.Int32 item4, System.Int32 item5, System.Int32 item6, System.Int32 item7, (System.Int32, System.Int32) rest)", "System.Boolean (System.Int32 a2, System.Int32 b2, System.Int32 c2, System.Int32 d2, System.Int32 e2, System.Int32 f2, System.Int32 g2, System.Int32 h2, System.Int32 i2).Equals(System.Object obj)", "System.Boolean (System.Int32 a2, System.Int32 b2, System.Int32 c2, System.Int32 d2, System.Int32 e2, System.Int32 f2, System.Int32 g2, System.Int32 h2, System.Int32 i2).Equals((System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32) other)", "System.Boolean (System.Int32 a2, System.Int32 b2, System.Int32 c2, System.Int32 d2, System.Int32 e2, System.Int32 f2, System.Int32 g2, System.Int32 h2, System.Int32 i2).System.Collections.IStructuralEquatable.Equals(System.Object other, System.Collections.IEqualityComparer comparer)", "System.Int32 (System.Int32 a2, System.Int32 b2, System.Int32 c2, System.Int32 d2, System.Int32 e2, System.Int32 f2, System.Int32 g2, System.Int32 h2, System.Int32 i2).System.IComparable.CompareTo(System.Object other)", "System.Int32 (System.Int32 a2, System.Int32 b2, System.Int32 c2, System.Int32 d2, System.Int32 e2, System.Int32 f2, System.Int32 g2, System.Int32 h2, System.Int32 i2).CompareTo((System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32) other)", "System.Int32 (System.Int32 a2, System.Int32 b2, System.Int32 c2, System.Int32 d2, System.Int32 e2, System.Int32 f2, System.Int32 g2, System.Int32 h2, System.Int32 i2).System.Collections.IStructuralComparable.CompareTo(System.Object other, System.Collections.IComparer comparer)", "System.Int32 (System.Int32 a2, System.Int32 b2, System.Int32 c2, System.Int32 d2, System.Int32 e2, System.Int32 f2, System.Int32 g2, System.Int32 h2, System.Int32 i2).GetHashCode()", "System.Int32 (System.Int32 a2, System.Int32 b2, System.Int32 c2, System.Int32 d2, System.Int32 e2, System.Int32 f2, System.Int32 g2, System.Int32 h2, System.Int32 i2).System.Collections.IStructuralEquatable.GetHashCode(System.Collections.IEqualityComparer comparer)", "System.Int32 (System.Int32 a2, System.Int32 b2, System.Int32 c2, System.Int32 d2, System.Int32 e2, System.Int32 f2, System.Int32 g2, System.Int32 h2, System.Int32 i2).System.ITupleInternal.GetHashCode(System.Collections.IEqualityComparer comparer)", "System.String (System.Int32 a2, System.Int32 b2, System.Int32 c2, System.Int32 d2, System.Int32 e2, System.Int32 f2, System.Int32 g2, System.Int32 h2, System.Int32 i2).ToString()", "System.String (System.Int32 a2, System.Int32 b2, System.Int32 c2, System.Int32 d2, System.Int32 e2, System.Int32 f2, System.Int32 g2, System.Int32 h2, System.Int32 i2).System.ITupleInternal.ToStringEnd()", "System.Int32 (System.Int32 a2, System.Int32 b2, System.Int32 c2, System.Int32 d2, System.Int32 e2, System.Int32 f2, System.Int32 g2, System.Int32 h2, System.Int32 i2).System.ITupleInternal.Size.get", "System.Int32 (System.Int32 a2, System.Int32 b2, System.Int32 c2, System.Int32 d2, System.Int32 e2, System.Int32 f2, System.Int32 g2, System.Int32 h2, System.Int32 i2).System.ITupleInternal.Size { get; }", "System.Int32 (System.Int32 a2, System.Int32 b2, System.Int32 c2, System.Int32 d2, System.Int32 e2, System.Int32 f2, System.Int32 g2, System.Int32 h2, System.Int32 i2).Item8", "System.Int32 (System.Int32 a2, System.Int32 b2, System.Int32 c2, System.Int32 d2, System.Int32 e2, System.Int32 f2, System.Int32 g2, System.Int32 h2, System.Int32 i2).h2", "System.Int32 (System.Int32 a2, System.Int32 b2, System.Int32 c2, System.Int32 d2, System.Int32 e2, System.Int32 f2, System.Int32 g2, System.Int32 h2, System.Int32 i2).Item9", "System.Int32 (System.Int32 a2, System.Int32 b2, System.Int32 c2, System.Int32 d2, System.Int32 e2, System.Int32 f2, System.Int32 g2, System.Int32 h2, System.Int32 i2).i2"); Assert.Equal("ValueTuple", m1Tuple.Name); Assert.Equal(SymbolKind.NamedType, m1Tuple.Kind); Assert.Equal(TypeKind.Struct, m1Tuple.TypeKind); Assert.False(m1Tuple.IsImplicitlyDeclared); Assert.True(m1Tuple.IsTupleType); Assert.Equal("(System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32)", m1Tuple.TupleUnderlyingType.ToTestDisplayString()); Assert.Equal("System.ValueTuple", m1Tuple.OriginalDefinition.ToTestDisplayString()); Assert.Same(m1Tuple.OriginalDefinition, m1Tuple.ConstructedFrom); AssertTupleTypeEquality(m1Tuple); Assert.Same(m1Tuple.TupleUnderlyingType.ContainingSymbol, m1Tuple.ContainingSymbol); Assert.True(m1Tuple.TupleUnderlyingType.Equals(m1Tuple, TypeCompareKind.ConsiderEverything)); Assert.Null(m1Tuple.GetUseSiteDiagnostic()); Assert.Null(m1Tuple.EnumUnderlyingType); AssertEx.Equal(new[] { "Item1", "Item2", "Item3", "Item4", "Item5", "Item6", "Item7", "Rest", ".ctor", "Equals", "System.Collections.IStructuralEquatable.Equals", "System.IComparable.CompareTo", "CompareTo", "System.Collections.IStructuralComparable.CompareTo", "GetHashCode", "System.Collections.IStructuralEquatable.GetHashCode", "System.ITupleInternal.GetHashCode", "ToString", "System.ITupleInternal.ToStringEnd", "System.ITupleInternal.get_Size", "System.ITupleInternal.Size", "Item8", "Item9" }, m1Tuple.MemberNames.ToArray()); AssertEx.Equal(new[] { "Item1", "a2", "Item2", "b2", "Item3", "c2", "Item4", "d2", "Item5", "e2", "Item6", "f2", "Item7", "g2", "Rest", ".ctor", "Equals", "System.Collections.IStructuralEquatable.Equals", "System.IComparable.CompareTo", "CompareTo", "System.Collections.IStructuralComparable.CompareTo", "GetHashCode", "System.Collections.IStructuralEquatable.GetHashCode", "System.ITupleInternal.GetHashCode", "ToString", "System.ITupleInternal.ToStringEnd", "System.ITupleInternal.get_Size", "System.ITupleInternal.Size", "Item8", "h2", "Item9", "i2" }, m2Tuple.MemberNames.ToArray()); Assert.Equal(8, m1Tuple.Arity); AssertEx.Equal(new[] { "T1", "T2", "T3", "T4", "T5", "T6", "T7", "TRest" }, m1Tuple.TypeParameters.ToTestDisplayStrings()); Assert.Equal("System.ValueType", m1Tuple.BaseType().ToTestDisplayString()); Assert.Null(m1Tuple.ComImportCoClass); Assert.True(m1Tuple.TypeArgumentsWithAnnotationsNoUseSiteDiagnostics.All(t => t.CustomModifiers.IsEmpty)); Assert.False(m1Tuple.IsComImport); AssertEx.Equal(new[] { "System.Int32", "System.Int32", "System.Int32", "System.Int32", "System.Int32", "System.Int32", "System.Int32", "(System.Int32, System.Int32)" }, m1Tuple.TypeArgumentsWithAnnotationsNoUseSiteDiagnostics.ToTestDisplayStrings()); Assert.True(m1Tuple.GetAttributes().IsEmpty); Assert.Equal("System.Int32 (System.Int32 a2, System.Int32 b2, System.Int32 c2, System.Int32 d2, System.Int32 e2, System.Int32 f2, System.Int32 g2, System.Int32 h2, System.Int32 i2).Item9", m2Tuple.GetMembers("Item9").Single().ToTestDisplayString()); Assert.Equal("System.Int32 (System.Int32 a2, System.Int32 b2, System.Int32 c2, System.Int32 d2, System.Int32 e2, System.Int32 f2, System.Int32 g2, System.Int32 h2, System.Int32 i2).i2", m2Tuple.GetMembers("i2").Single().ToTestDisplayString()); Assert.True(m1Tuple.GetTypeMembers().IsEmpty); Assert.True(m1Tuple.GetTypeMembers("C9").IsEmpty); Assert.True(m1Tuple.GetTypeMembers("C9", 0).IsEmpty); Assert.Equal(6, m1Tuple.Interfaces().Length); Assert.Equal("System.Int32 (System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32).Item1", m1Tuple.GetEarlyAttributeDecodingMembers("Item1").Single().ToTestDisplayString()); Assert.True(m1Tuple.GetTypeMembersUnordered().IsEmpty); Assert.Equal(1, m1Tuple.Locations.Length); Assert.Equal("(int, int, int, int, int, int, int, int, int)", m1Tuple.DeclaringSyntaxReferences.Single().GetSyntax().ToString()); Assert.Equal("(int a2, int b2, int c2, int d2, int e2, int f2, int g2, int h2, int i2)", m2Tuple.DeclaringSyntaxReferences.Single().GetSyntax().ToString()); AssertTupleTypeEquality(m2Tuple); AssertTupleTypeEquality(m6Tuple); Assert.False(m1Tuple.Equals(m2Tuple)); Assert.False(m1Tuple.Equals(m6Tuple)); Assert.False(m6Tuple.Equals(m2Tuple)); AssertTupleTypeMembersEquality(m1Tuple, m2Tuple); AssertTupleTypeMembersEquality(m1Tuple, m6Tuple); AssertTupleTypeMembersEquality(m2Tuple, m6Tuple); var m1Item7 = (FieldSymbol)m1Tuple.GetMembers().Where(m => m.Name == "Item7").Single(); var m1Item9 = (FieldSymbol)m1Tuple.GetMembers().Where(m => m.Name == "Item9").Single(); AssertNonvirtualTupleElementField(m1Item7); AssertVirtualTupleElementField(m1Item9); var m2g2 = (FieldSymbol)m2Tuple.GetMembers().Where(m => m.Name == "g2").Single(); var m2Item9 = (FieldSymbol)m2Tuple.GetMembers().Where(m => m.Name == "Item9").Single(); var m2i2 = (FieldSymbol)m2Tuple.GetMembers().Where(m => m.Name == "i2").Single(); AssertVirtualTupleElementField(m2g2); AssertVirtualTupleElementField(m2Item9); AssertVirtualTupleElementField(m2i2); Assert.Same(m1Item9, m1Item9.OriginalDefinition); Assert.True(m1Item9.Equals(m1Item9)); Assert.Equal("System.Int32 (System.Int32, System.Int32).Item2", m1Item9.TupleUnderlyingField.ToTestDisplayString()); Assert.Null(m1Item9.AssociatedSymbol); Assert.Same(m1Tuple, m1Item9.ContainingSymbol); Assert.Same(m1Tuple.TypeArgumentsWithAnnotationsNoUseSiteDiagnostics.Last().Type, m1Item9.TupleUnderlyingField.ContainingSymbol); Assert.True(m1Item9.TypeWithAnnotations.CustomModifiers.IsEmpty); Assert.True(m1Item9.GetAttributes().IsEmpty); Assert.Null(m1Item9.GetUseSiteDiagnostic()); Assert.False(m1Item9.Locations.IsEmpty); Assert.True(m1Item9.DeclaringSyntaxReferences.IsEmpty); Assert.Equal("Item2", m1Item9.TupleUnderlyingField.Name); Assert.True(m1Item9.IsImplicitlyDeclared); Assert.Null(m1Item9.TypeLayoutOffset); Assert.Same(m2Item9, m2Item9.OriginalDefinition); Assert.True(m2Item9.Equals(m2Item9)); Assert.Equal("System.Int32 (System.Int32, System.Int32).Item2", m2Item9.TupleUnderlyingField.ToTestDisplayString()); Assert.Null(m2Item9.AssociatedSymbol); Assert.Same(m2Tuple, m2Item9.ContainingSymbol); Assert.Same(m2Tuple.TypeArgumentsWithAnnotationsNoUseSiteDiagnostics.Last().Type, m2Item9.TupleUnderlyingField.ContainingSymbol); Assert.True(m2Item9.TypeWithAnnotations.CustomModifiers.IsEmpty); Assert.True(m2Item9.GetAttributes().IsEmpty); Assert.Null(m2Item9.GetUseSiteDiagnostic()); Assert.False(m2Item9.Locations.IsEmpty); Assert.Equal("Item9", m2Item9.Name); Assert.Equal("Item2", m2Item9.TupleUnderlyingField.Name); Assert.Equal("SourceFile([739..741))", m2Item9.Locations.Single().ToString()); Assert.Equal("MetadataFile(System.ValueTuple.dll)", m2Item9.TupleUnderlyingField.Locations.Single().ToString()); Assert.True(m2Item9.IsImplicitlyDeclared); Assert.Null(m2Item9.TypeLayoutOffset); Assert.Same(m2i2, m2i2.OriginalDefinition); Assert.True(m2i2.Equals(m2i2)); Assert.Equal("System.Int32 (System.Int32, System.Int32).Item2", m2i2.TupleUnderlyingField.ToTestDisplayString()); Assert.Null(m2i2.AssociatedSymbol); Assert.Same(m2Tuple, m2i2.ContainingSymbol); Assert.Same(m2Tuple.TypeArgumentsWithAnnotationsNoUseSiteDiagnostics.Last().Type, m2i2.TupleUnderlyingField.ContainingSymbol); Assert.True(m2i2.TypeWithAnnotations.CustomModifiers.IsEmpty); Assert.True(m2i2.GetAttributes().IsEmpty); Assert.Null(m2i2.GetUseSiteDiagnostic()); Assert.False(m2i2.Locations.IsEmpty); Assert.Equal("int i2", m2i2.DeclaringSyntaxReferences.Single().GetSyntax().ToString()); Assert.Equal("Item2", m2i2.TupleUnderlyingField.Name); Assert.False(m2i2.IsImplicitlyDeclared); Assert.Null(m2i2.TypeLayoutOffset); } private static void AssertTupleTypeEquality(TypeSymbol tuple) { Assert.True(tuple.Equals(tuple)); Assert.True(tuple.Equals(tuple, TypeCompareKind.ConsiderEverything)); Assert.True(tuple.Equals(tuple, TypeCompareKind.IgnoreDynamicAndTupleNames)); var members = tuple.GetMembers(); for (int i = 0; i < members.Length; i++) { for (int j = 0; j < members.Length; j++) { if (i != j) { Assert.NotSame(members[i], members[j]); Assert.False(members[i].Equals(members[j])); Assert.False(members[j].Equals(members[i])); } } } } private static void AssertTupleTypeMembersEquality(TypeSymbol tuple1, TypeSymbol tuple2) { Assert.NotSame(tuple1, tuple2); if (tuple1.Equals(tuple2)) { Assert.True(tuple2.Equals(tuple1)); var members1 = tuple1.GetMembers(); var members2 = tuple2.GetMembers(); Assert.Equal(members1.Length, members2.Length); for (int i = 0; i < members1.Length; i++) { Assert.NotSame(members1[i], members2[i]); Assert.True(members1[i].Equals(members2[i])); Assert.True(members2[i].Equals(members1[i])); Assert.Equal(members2[i].GetHashCode(), members1[i].GetHashCode()); if (members1[i].Kind == SymbolKind.Method) { var parameters1 = ((MethodSymbol)members1[i]).Parameters; var parameters2 = ((MethodSymbol)members2[i]).Parameters; AssertTupleMembersParametersEquality(parameters1, parameters2); var typeParameters1 = ((MethodSymbol)members1[i]).TypeParameters; var typeParameters2 = ((MethodSymbol)members2[i]).TypeParameters; Assert.Equal(typeParameters1.Length, typeParameters2.Length); for (int j = 0; j < typeParameters1.Length; j++) { Assert.NotSame(typeParameters1[j], typeParameters2[j]); Assert.True(typeParameters1[j].Equals(typeParameters2[j])); Assert.True(typeParameters2[j].Equals(typeParameters1[j])); Assert.Equal(typeParameters2[j].GetHashCode(), typeParameters1[j].GetHashCode()); } } else if (members1[i].Kind == SymbolKind.Property) { var parameters1 = ((PropertySymbol)members1[i]).Parameters; var parameters2 = ((PropertySymbol)members2[i]).Parameters; AssertTupleMembersParametersEquality(parameters1, parameters2); } } for (int i = 0; i < members1.Length; i++) { for (int j = 0; j < members2.Length; j++) { if (i != j) { Assert.NotSame(members1[i], members2[j]); Assert.False(members1[i].Equals(members2[j])); } } } } else { Assert.False(tuple2.Equals(tuple1)); var members1 = tuple1.GetMembers(); var members2 = tuple2.GetMembers(); foreach (var m in members1) { Assert.False(members2.Any(u => u.Equals(m))); Assert.False(members2.Any(u => m.Equals(u))); } } } private static void AssertTupleMembersParametersEquality(ImmutableArray parameters1, ImmutableArray parameters2) { Assert.Equal(parameters1.Length, parameters2.Length); for (int j = 0; j < parameters1.Length; j++) { Assert.NotSame(parameters1[j], parameters2[j]); Assert.True(parameters1[j].Equals(parameters2[j])); Assert.True(parameters2[j].Equals(parameters1[j])); Assert.Equal(parameters2[j].GetHashCode(), parameters1[j].GetHashCode()); } } [ConditionalFact(typeof(DesktopOnly))] public void DefaultAndFriendlyElementNames_02() { var source = @" using System; class C { static void Main() { var v3 = M3(); System.Console.WriteLine(v3.Item1); System.Console.WriteLine(v3.Item2); System.Console.WriteLine(v3.Item3); System.Console.WriteLine(v3.Item4); System.Console.WriteLine(v3.Item5); System.Console.WriteLine(v3.Item6); System.Console.WriteLine(v3.Item7); System.Console.WriteLine(v3.Item8); System.Console.WriteLine(v3.Item9); System.Console.WriteLine(v3.Rest.Item1); System.Console.WriteLine(v3.Rest.Item2); System.Console.WriteLine(v3.ToString()); } static (int, int, int, int, int, int, int, int, int) M3() { return (31, 32, 33, 34, 35, 36, 37, 38, 39); } } "; var comp = CompileAndVerify(source, parseOptions: TestOptions.Regular, expectedOutput: @"31 32 33 34 35 36 37 38 39 38 39 (31, 32, 33, 34, 35, 36, 37, 38, 39) "); var c = ((CSharpCompilation)comp.Compilation).GetTypeByMetadataName("C"); var m3Tuple = (NamedTypeSymbol)c.GetMember("M3").ReturnType; AssertTupleTypeEquality(m3Tuple); AssertTestDisplayString(m3Tuple.GetMembers(), "System.Int32 (System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32).Item1", "System.Int32 (System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32).Item2", "System.Int32 (System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32).Item3", "System.Int32 (System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32).Item4", "System.Int32 (System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32).Item5", "System.Int32 (System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32).Item6", "System.Int32 (System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32).Item7", "(System.Int32, System.Int32) (System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32).Rest", "(System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32)..ctor()", "(System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32)..ctor(System.Int32 item1, System.Int32 item2, System.Int32 item3, System.Int32 item4, System.Int32 item5, System.Int32 item6, System.Int32 item7, (System.Int32, System.Int32) rest)", "System.Boolean (System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32).Equals(System.Object obj)", "System.Boolean (System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32).Equals((System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32) other)", "System.Boolean (System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32).System.Collections.IStructuralEquatable.Equals(System.Object other, System.Collections.IEqualityComparer comparer)", "System.Int32 (System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32).System.IComparable.CompareTo(System.Object other)", "System.Int32 (System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32).CompareTo((System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32) other)", "System.Int32 (System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32).System.Collections.IStructuralComparable.CompareTo(System.Object other, System.Collections.IComparer comparer)", "System.Int32 (System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32).GetHashCode()", "System.Int32 (System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32).System.Collections.IStructuralEquatable.GetHashCode(System.Collections.IEqualityComparer comparer)", "System.Int32 (System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32).System.ITupleInternal.GetHashCode(System.Collections.IEqualityComparer comparer)", "System.String (System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32).ToString()", "System.String (System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32).System.ITupleInternal.ToStringEnd()", "System.Int32 (System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32).System.ITupleInternal.Size.get", "System.Int32 (System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32).System.ITupleInternal.Size { get; }", "System.Int32 (System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32).Item8", "System.Int32 (System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32).Item9"); var m3Item8 = (FieldSymbol)m3Tuple.GetMembers("Item8").Single(); AssertVirtualTupleElementField(m3Item8); Assert.Same(m3Item8, m3Item8.OriginalDefinition); Assert.True(m3Item8.Equals(m3Item8)); Assert.Equal("System.Int32 (System.Int32, System.Int32).Item1", m3Item8.TupleUnderlyingField.ToTestDisplayString()); Assert.Null(m3Item8.AssociatedSymbol); Assert.Same(m3Tuple, m3Item8.ContainingSymbol); Assert.NotEqual(m3Tuple.TupleUnderlyingType, m3Item8.TupleUnderlyingField.ContainingSymbol); Assert.NotEqual(m3Tuple, m3Item8.TupleUnderlyingField.ContainingSymbol); Assert.True(m3Item8.TypeWithAnnotations.CustomModifiers.IsEmpty); Assert.True(m3Item8.GetAttributes().IsEmpty); Assert.Null(m3Item8.GetUseSiteDiagnostic()); Assert.False(m3Item8.Locations.IsEmpty); Assert.True(m3Item8.DeclaringSyntaxReferences.IsEmpty); Assert.Equal("Item1", m3Item8.TupleUnderlyingField.Name); Assert.True(m3Item8.IsImplicitlyDeclared); Assert.Null(m3Item8.TypeLayoutOffset); var m3TupleRestTuple = (NamedTypeSymbol)((FieldSymbol)m3Tuple.GetMembers("Rest").Single()).Type; AssertTestDisplayString(m3TupleRestTuple.GetMembers(), "System.Int32 (System.Int32, System.Int32).Item1", "System.Int32 (System.Int32, System.Int32).Item2", "(System.Int32, System.Int32)..ctor()", "(System.Int32, System.Int32)..ctor(System.Int32 item1, System.Int32 item2)", "System.Boolean (System.Int32, System.Int32).Equals(System.Object obj)", "System.Boolean (System.Int32, System.Int32).Equals((System.Int32, System.Int32) other)", "System.Boolean (System.Int32, System.Int32).System.Collections.IStructuralEquatable.Equals(System.Object other, System.Collections.IEqualityComparer comparer)", "System.Int32 (System.Int32, System.Int32).System.IComparable.CompareTo(System.Object other)", "System.Int32 (System.Int32, System.Int32).CompareTo((System.Int32, System.Int32) other)", "System.Int32 (System.Int32, System.Int32).System.Collections.IStructuralComparable.CompareTo(System.Object other, System.Collections.IComparer comparer)", "System.Int32 (System.Int32, System.Int32).GetHashCode()", "System.Int32 (System.Int32, System.Int32).System.Collections.IStructuralEquatable.GetHashCode(System.Collections.IEqualityComparer comparer)", "System.Int32 (System.Int32, System.Int32).System.ITupleInternal.GetHashCode(System.Collections.IEqualityComparer comparer)", "System.String (System.Int32, System.Int32).ToString()", "System.String (System.Int32, System.Int32).System.ITupleInternal.ToStringEnd()", "System.Int32 (System.Int32, System.Int32).System.ITupleInternal.Size.get", "System.Int32 (System.Int32, System.Int32).System.ITupleInternal.Size { get; }"); Assert.True(m3TupleRestTuple.IsTupleType); AssertTupleTypeEquality(m3TupleRestTuple); Assert.True(m3TupleRestTuple.Locations.IsEmpty); Assert.True(m3TupleRestTuple.DeclaringSyntaxReferences.IsEmpty); foreach (var m in m3TupleRestTuple.GetMembers().OfType()) { Assert.True(m.Locations.IsEmpty); } } [ConditionalFact(typeof(DesktopOnly))] public void DefaultAndFriendlyElementNames_03() { var source = @" using System; class C { static void Main() { var v4 = M4 (); System.Console.WriteLine(v4.Item1); System.Console.WriteLine(v4.Item2); System.Console.WriteLine(v4.Item3); System.Console.WriteLine(v4.Item4); System.Console.WriteLine(v4.Item5); System.Console.WriteLine(v4.Item6); System.Console.WriteLine(v4.Item7); System.Console.WriteLine(v4.Item8); System.Console.WriteLine(v4.Item9); System.Console.WriteLine(v4.Rest.Item1); System.Console.WriteLine(v4.Rest.Item2); System.Console.WriteLine(v4.a4); System.Console.WriteLine(v4.b4); System.Console.WriteLine(v4.c4); System.Console.WriteLine(v4.d4); System.Console.WriteLine(v4.e4); System.Console.WriteLine(v4.f4); System.Console.WriteLine(v4.g4); System.Console.WriteLine(v4.h4); System.Console.WriteLine(v4.i4); System.Console.WriteLine(v4.ToString()); } static (int a4, int b4, int c4, int d4, int e4, int f4, int g4, int h4, int i4) M4() { return (41, 42, 43, 44, 45, 46, 47, 48, 49); } } "; var comp = CompileAndVerify(source, parseOptions: TestOptions.Regular, expectedOutput: @"41 42 43 44 45 46 47 48 49 48 49 41 42 43 44 45 46 47 48 49 (41, 42, 43, 44, 45, 46, 47, 48, 49) "); var c = ((CSharpCompilation)comp.Compilation).GetTypeByMetadataName("C"); var m4Tuple = (NamedTypeSymbol)c.GetMember("M4").ReturnType; AssertTupleTypeEquality(m4Tuple); AssertTestDisplayString(m4Tuple.GetMembers(), "System.Int32 (System.Int32 a4, System.Int32 b4, System.Int32 c4, System.Int32 d4, System.Int32 e4, System.Int32 f4, System.Int32 g4, System.Int32 h4, System.Int32 i4)" + ".Item1", "System.Int32 (System.Int32 a4, System.Int32 b4, System.Int32 c4, System.Int32 d4, System.Int32 e4, System.Int32 f4, System.Int32 g4, System.Int32 h4, System.Int32 i4)" + ".a4", "System.Int32 (System.Int32 a4, System.Int32 b4, System.Int32 c4, System.Int32 d4, System.Int32 e4, System.Int32 f4, System.Int32 g4, System.Int32 h4, System.Int32 i4)" + ".Item2", "System.Int32 (System.Int32 a4, System.Int32 b4, System.Int32 c4, System.Int32 d4, System.Int32 e4, System.Int32 f4, System.Int32 g4, System.Int32 h4, System.Int32 i4)" + ".b4", "System.Int32 (System.Int32 a4, System.Int32 b4, System.Int32 c4, System.Int32 d4, System.Int32 e4, System.Int32 f4, System.Int32 g4, System.Int32 h4, System.Int32 i4)" + ".Item3", "System.Int32 (System.Int32 a4, System.Int32 b4, System.Int32 c4, System.Int32 d4, System.Int32 e4, System.Int32 f4, System.Int32 g4, System.Int32 h4, System.Int32 i4)" + ".c4", "System.Int32 (System.Int32 a4, System.Int32 b4, System.Int32 c4, System.Int32 d4, System.Int32 e4, System.Int32 f4, System.Int32 g4, System.Int32 h4, System.Int32 i4)" + ".Item4", "System.Int32 (System.Int32 a4, System.Int32 b4, System.Int32 c4, System.Int32 d4, System.Int32 e4, System.Int32 f4, System.Int32 g4, System.Int32 h4, System.Int32 i4)" + ".d4", "System.Int32 (System.Int32 a4, System.Int32 b4, System.Int32 c4, System.Int32 d4, System.Int32 e4, System.Int32 f4, System.Int32 g4, System.Int32 h4, System.Int32 i4)" + ".Item5", "System.Int32 (System.Int32 a4, System.Int32 b4, System.Int32 c4, System.Int32 d4, System.Int32 e4, System.Int32 f4, System.Int32 g4, System.Int32 h4, System.Int32 i4)" + ".e4", "System.Int32 (System.Int32 a4, System.Int32 b4, System.Int32 c4, System.Int32 d4, System.Int32 e4, System.Int32 f4, System.Int32 g4, System.Int32 h4, System.Int32 i4)" + ".Item6", "System.Int32 (System.Int32 a4, System.Int32 b4, System.Int32 c4, System.Int32 d4, System.Int32 e4, System.Int32 f4, System.Int32 g4, System.Int32 h4, System.Int32 i4)" + ".f4", "System.Int32 (System.Int32 a4, System.Int32 b4, System.Int32 c4, System.Int32 d4, System.Int32 e4, System.Int32 f4, System.Int32 g4, System.Int32 h4, System.Int32 i4)" + ".Item7", "System.Int32 (System.Int32 a4, System.Int32 b4, System.Int32 c4, System.Int32 d4, System.Int32 e4, System.Int32 f4, System.Int32 g4, System.Int32 h4, System.Int32 i4)" + ".g4", "(System.Int32, System.Int32) (System.Int32 a4, System.Int32 b4, System.Int32 c4, System.Int32 d4, System.Int32 e4, System.Int32 f4, System.Int32 g4, System.Int32 h4, System.Int32 i4)" + ".Rest", "(System.Int32 a4, System.Int32 b4, System.Int32 c4, System.Int32 d4, System.Int32 e4, System.Int32 f4, System.Int32 g4, System.Int32 h4, System.Int32 i4)" + "..ctor()", "(System.Int32 a4, System.Int32 b4, System.Int32 c4, System.Int32 d4, System.Int32 e4, System.Int32 f4, System.Int32 g4, System.Int32 h4, System.Int32 i4)" + "..ctor" + "(System.Int32 item1, System.Int32 item2, System.Int32 item3, System.Int32 item4, System.Int32 item5, System.Int32 item6, System.Int32 item7, (System.Int32, System.Int32) rest)", "System.Boolean (System.Int32 a4, System.Int32 b4, System.Int32 c4, System.Int32 d4, System.Int32 e4, System.Int32 f4, System.Int32 g4, System.Int32 h4, System.Int32 i4)" + ".Equals(System.Object obj)", "System.Boolean (System.Int32 a4, System.Int32 b4, System.Int32 c4, System.Int32 d4, System.Int32 e4, System.Int32 f4, System.Int32 g4, System.Int32 h4, System.Int32 i4)" + ".Equals((System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32) other)", "System.Boolean (System.Int32 a4, System.Int32 b4, System.Int32 c4, System.Int32 d4, System.Int32 e4, System.Int32 f4, System.Int32 g4, System.Int32 h4, System.Int32 i4)" + ".System.Collections.IStructuralEquatable.Equals(System.Object other, System.Collections.IEqualityComparer comparer)", "System.Int32 (System.Int32 a4, System.Int32 b4, System.Int32 c4, System.Int32 d4, System.Int32 e4, System.Int32 f4, System.Int32 g4, System.Int32 h4, System.Int32 i4)" + ".System.IComparable.CompareTo(System.Object other)", "System.Int32 (System.Int32 a4, System.Int32 b4, System.Int32 c4, System.Int32 d4, System.Int32 e4, System.Int32 f4, System.Int32 g4, System.Int32 h4, System.Int32 i4)" + ".CompareTo((System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32) other)", "System.Int32 (System.Int32 a4, System.Int32 b4, System.Int32 c4, System.Int32 d4, System.Int32 e4, System.Int32 f4, System.Int32 g4, System.Int32 h4, System.Int32 i4)" + ".System.Collections.IStructuralComparable.CompareTo(System.Object other, System.Collections.IComparer comparer)", "System.Int32 (System.Int32 a4, System.Int32 b4, System.Int32 c4, System.Int32 d4, System.Int32 e4, System.Int32 f4, System.Int32 g4, System.Int32 h4, System.Int32 i4)" + ".GetHashCode()", "System.Int32 (System.Int32 a4, System.Int32 b4, System.Int32 c4, System.Int32 d4, System.Int32 e4, System.Int32 f4, System.Int32 g4, System.Int32 h4, System.Int32 i4)" + ".System.Collections.IStructuralEquatable.GetHashCode(System.Collections.IEqualityComparer comparer)", "System.Int32 (System.Int32 a4, System.Int32 b4, System.Int32 c4, System.Int32 d4, System.Int32 e4, System.Int32 f4, System.Int32 g4, System.Int32 h4, System.Int32 i4)" + ".System.ITupleInternal.GetHashCode(System.Collections.IEqualityComparer comparer)", "System.String (System.Int32 a4, System.Int32 b4, System.Int32 c4, System.Int32 d4, System.Int32 e4, System.Int32 f4, System.Int32 g4, System.Int32 h4, System.Int32 i4)" + ".ToString()", "System.String (System.Int32 a4, System.Int32 b4, System.Int32 c4, System.Int32 d4, System.Int32 e4, System.Int32 f4, System.Int32 g4, System.Int32 h4, System.Int32 i4)" + ".System.ITupleInternal.ToStringEnd()", "System.Int32 (System.Int32 a4, System.Int32 b4, System.Int32 c4, System.Int32 d4, System.Int32 e4, System.Int32 f4, System.Int32 g4, System.Int32 h4, System.Int32 i4)" + ".System.ITupleInternal.Size.get", "System.Int32 (System.Int32 a4, System.Int32 b4, System.Int32 c4, System.Int32 d4, System.Int32 e4, System.Int32 f4, System.Int32 g4, System.Int32 h4, System.Int32 i4)" + ".System.ITupleInternal.Size { get; }", "System.Int32 (System.Int32 a4, System.Int32 b4, System.Int32 c4, System.Int32 d4, System.Int32 e4, System.Int32 f4, System.Int32 g4, System.Int32 h4, System.Int32 i4)" + ".Item8", "System.Int32 (System.Int32 a4, System.Int32 b4, System.Int32 c4, System.Int32 d4, System.Int32 e4, System.Int32 f4, System.Int32 g4, System.Int32 h4, System.Int32 i4)" + ".h4", "System.Int32 (System.Int32 a4, System.Int32 b4, System.Int32 c4, System.Int32 d4, System.Int32 e4, System.Int32 f4, System.Int32 g4, System.Int32 h4, System.Int32 i4)" + ".Item9", "System.Int32 (System.Int32 a4, System.Int32 b4, System.Int32 c4, System.Int32 d4, System.Int32 e4, System.Int32 f4, System.Int32 g4, System.Int32 h4, System.Int32 i4)" + ".i4" ); var m4Item8 = (FieldSymbol)m4Tuple.GetMembers("Item8").Single(); AssertVirtualTupleElementField(m4Item8); Assert.Same(m4Item8, m4Item8.OriginalDefinition); Assert.True(m4Item8.Equals(m4Item8)); Assert.Equal("System.Int32 (System.Int32, System.Int32).Item1", m4Item8.TupleUnderlyingField.ToTestDisplayString()); Assert.Null(m4Item8.AssociatedSymbol); Assert.Same(m4Tuple, m4Item8.ContainingSymbol); Assert.NotEqual(m4Tuple.TupleUnderlyingType, m4Item8.TupleUnderlyingField.ContainingSymbol); Assert.NotEqual(m4Tuple, m4Item8.TupleUnderlyingField.ContainingSymbol); Assert.True(m4Item8.TypeWithAnnotations.CustomModifiers.IsEmpty); Assert.True(m4Item8.GetAttributes().IsEmpty); Assert.Null(m4Item8.GetUseSiteDiagnostic()); Assert.False(m4Item8.Locations.IsEmpty); Assert.Equal("Item1", m4Item8.TupleUnderlyingField.Name); Assert.True(m4Item8.IsImplicitlyDeclared); Assert.Null(m4Item8.TypeLayoutOffset); var m4h4 = (FieldSymbol)m4Tuple.GetMembers("h4").Single(); AssertVirtualTupleElementField(m4h4); Assert.Same(m4h4, m4h4.OriginalDefinition); Assert.True(m4h4.Equals(m4h4)); Assert.Equal("System.Int32 (System.Int32, System.Int32).Item1", m4h4.TupleUnderlyingField.ToTestDisplayString()); Assert.Null(m4h4.AssociatedSymbol); Assert.Same(m4Tuple, m4h4.ContainingSymbol); Assert.NotEqual(m4Tuple.TupleUnderlyingType, m4h4.TupleUnderlyingField.ContainingSymbol); Assert.NotEqual(m4Tuple, m4h4.TupleUnderlyingField.ContainingSymbol); Assert.True(m4h4.TypeWithAnnotations.CustomModifiers.IsEmpty); Assert.True(m4h4.GetAttributes().IsEmpty); Assert.Null(m4h4.GetUseSiteDiagnostic()); Assert.False(m4h4.Locations.IsEmpty); Assert.Equal("int h4", m4h4.DeclaringSyntaxReferences.Single().GetSyntax().ToString()); Assert.Equal("Item1", m4h4.TupleUnderlyingField.Name); Assert.False(m4h4.IsImplicitlyDeclared); Assert.Null(m4h4.TypeLayoutOffset); var m4TupleRestTuple = ((FieldSymbol)m4Tuple.GetMembers("Rest").Single()).Type; AssertTupleTypeEquality(m4TupleRestTuple); AssertTestDisplayString(m4TupleRestTuple.GetMembers(), "System.Int32 (System.Int32, System.Int32).Item1", "System.Int32 (System.Int32, System.Int32).Item2", "(System.Int32, System.Int32)..ctor()", "(System.Int32, System.Int32)..ctor(System.Int32 item1, System.Int32 item2)", "System.Boolean (System.Int32, System.Int32).Equals(System.Object obj)", "System.Boolean (System.Int32, System.Int32).Equals((System.Int32, System.Int32) other)", "System.Boolean (System.Int32, System.Int32).System.Collections.IStructuralEquatable.Equals(System.Object other, System.Collections.IEqualityComparer comparer)", "System.Int32 (System.Int32, System.Int32).System.IComparable.CompareTo(System.Object other)", "System.Int32 (System.Int32, System.Int32).CompareTo((System.Int32, System.Int32) other)", "System.Int32 (System.Int32, System.Int32).System.Collections.IStructuralComparable.CompareTo(System.Object other, System.Collections.IComparer comparer)", "System.Int32 (System.Int32, System.Int32).GetHashCode()", "System.Int32 (System.Int32, System.Int32).System.Collections.IStructuralEquatable.GetHashCode(System.Collections.IEqualityComparer comparer)", "System.Int32 (System.Int32, System.Int32).System.ITupleInternal.GetHashCode(System.Collections.IEqualityComparer comparer)", "System.String (System.Int32, System.Int32).ToString()", "System.String (System.Int32, System.Int32).System.ITupleInternal.ToStringEnd()", "System.Int32 (System.Int32, System.Int32).System.ITupleInternal.Size.get", "System.Int32 (System.Int32, System.Int32).System.ITupleInternal.Size { get; }"); foreach (var m in m4TupleRestTuple.GetMembers().OfType()) { Assert.True(m.Locations.IsEmpty); } } [Fact] public void DefaultAndFriendlyElementNames_04() { var source = @" class C { static void Main() { var v4 = M4 (); System.Console.WriteLine(v4.Rest.a4); System.Console.WriteLine(v4.Rest.b4); System.Console.WriteLine(v4.Rest.c4); System.Console.WriteLine(v4.Rest.d4); System.Console.WriteLine(v4.Rest.e4); System.Console.WriteLine(v4.Rest.f4); System.Console.WriteLine(v4.Rest.g4); System.Console.WriteLine(v4.Rest.h4); System.Console.WriteLine(v4.Rest.i4); } static (int a4, int b4, int c4, int d4, int e4, int f4, int g4, int h4, int i4) M4() { return (41, 42, 43, 44, 45, 46, 47, 48, 49); } } "; var comp = CreateCompilation(source); comp.VerifyDiagnostics( // (8,42): error CS1061: '(int, int)' does not contain a definition for 'a4' and no extension method 'a4' accepting a first argument of type '(int, int)' could be found (are you missing a using directive or an assembly reference?) // System.Console.WriteLine(v4.Rest.a4); Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "a4").WithArguments("(int, int)", "a4").WithLocation(8, 42), // (9,42): error CS1061: '(int, int)' does not contain a definition for 'b4' and no extension method 'b4' accepting a first argument of type '(int, int)' could be found (are you missing a using directive or an assembly reference?) // System.Console.WriteLine(v4.Rest.b4); Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "b4").WithArguments("(int, int)", "b4").WithLocation(9, 42), // (10,42): error CS1061: '(int, int)' does not contain a definition for 'c4' and no extension method 'c4' accepting a first argument of type '(int, int)' could be found (are you missing a using directive or an assembly reference?) // System.Console.WriteLine(v4.Rest.c4); Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "c4").WithArguments("(int, int)", "c4").WithLocation(10, 42), // (11,42): error CS1061: '(int, int)' does not contain a definition for 'd4' and no extension method 'd4' accepting a first argument of type '(int, int)' could be found (are you missing a using directive or an assembly reference?) // System.Console.WriteLine(v4.Rest.d4); Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "d4").WithArguments("(int, int)", "d4").WithLocation(11, 42), // (12,42): error CS1061: '(int, int)' does not contain a definition for 'e4' and no extension method 'e4' accepting a first argument of type '(int, int)' could be found (are you missing a using directive or an assembly reference?) // System.Console.WriteLine(v4.Rest.e4); Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "e4").WithArguments("(int, int)", "e4").WithLocation(12, 42), // (13,42): error CS1061: '(int, int)' does not contain a definition for 'f4' and no extension method 'f4' accepting a first argument of type '(int, int)' could be found (are you missing a using directive or an assembly reference?) // System.Console.WriteLine(v4.Rest.f4); Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "f4").WithArguments("(int, int)", "f4").WithLocation(13, 42), // (14,42): error CS1061: '(int, int)' does not contain a definition for 'g4' and no extension method 'g4' accepting a first argument of type '(int, int)' could be found (are you missing a using directive or an assembly reference?) // System.Console.WriteLine(v4.Rest.g4); Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "g4").WithArguments("(int, int)", "g4").WithLocation(14, 42), // (15,42): error CS1061: '(int, int)' does not contain a definition for 'h4' and no extension method 'h4' accepting a first argument of type '(int, int)' could be found (are you missing a using directive or an assembly reference?) // System.Console.WriteLine(v4.Rest.h4); Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "h4").WithArguments("(int, int)", "h4").WithLocation(15, 42), // (16,42): error CS1061: '(int, int)' does not contain a definition for 'i4' and no extension method 'i4' accepting a first argument of type '(int, int)' could be found (are you missing a using directive or an assembly reference?) // System.Console.WriteLine(v4.Rest.i4); Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "i4").WithArguments("(int, int)", "i4").WithLocation(16, 42) ); } [ConditionalFact(typeof(DesktopOnly))] public void DefaultAndFriendlyElementNames_05() { var source = @" using System; class C { static void Main() { var v5 = M5(); System.Console.WriteLine(v5.Item1); System.Console.WriteLine(v5.Item2); System.Console.WriteLine(v5.Item3); System.Console.WriteLine(v5.Item4); System.Console.WriteLine(v5.Item5); System.Console.WriteLine(v5.Item6); System.Console.WriteLine(v5.Item7); System.Console.WriteLine(v5.Item8); System.Console.WriteLine(v5.Item9); System.Console.WriteLine(v5.Item10); System.Console.WriteLine(v5.Item11); System.Console.WriteLine(v5.Item12); System.Console.WriteLine(v5.Item13); System.Console.WriteLine(v5.Item14); System.Console.WriteLine(v5.Item15); System.Console.WriteLine(v5.Item16); System.Console.WriteLine(v5.Rest.Item1); System.Console.WriteLine(v5.Rest.Item2); System.Console.WriteLine(v5.Rest.Item3); System.Console.WriteLine(v5.Rest.Item4); System.Console.WriteLine(v5.Rest.Item5); System.Console.WriteLine(v5.Rest.Item6); System.Console.WriteLine(v5.Rest.Item7); System.Console.WriteLine(v5.Rest.Item8); System.Console.WriteLine(v5.Rest.Item9); System.Console.WriteLine(v5.Rest.Rest.Item1); System.Console.WriteLine(v5.Rest.Rest.Item2); System.Console.WriteLine(v5.ToString()); } static (int Item1, int Item2, int Item3, int Item4, int Item5, int Item6, int Item7, int Item8, int Item9, int Item10, int Item11, int Item12, int Item13, int Item14, int Item15, int Item16) M5() { return (501, 502, 503, 504, 505, 506, 507, 508, 509, 510, 511, 512, 513, 514, 515, 516); } } "; var comp = CompileAndVerify(source, parseOptions: TestOptions.Regular, expectedOutput: @"501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 508 509 510 511 512 513 514 515 516 515 516 (501, 502, 503, 504, 505, 506, 507, 508, 509, 510, 511, 512, 513, 514, 515, 516) "); var c = ((CSharpCompilation)comp.Compilation).GetTypeByMetadataName("C"); var m5Tuple = (NamedTypeSymbol)c.GetMember("M5").ReturnType; AssertTupleTypeEquality(m5Tuple); AssertTestDisplayString(m5Tuple.GetMembers(), "System.Int32 (System.Int32 Item1, System.Int32 Item2, System.Int32 Item3, System.Int32 Item4, System.Int32 Item5, System.Int32 Item6, System.Int32 Item7, System.Int32 Item8, System.Int32 Item9, System.Int32 Item10, System.Int32 Item11, System.Int32 Item12, System.Int32 Item13, System.Int32 Item14, System.Int32 Item15, System.Int32 Item16).Item1", "System.Int32 (System.Int32 Item1, System.Int32 Item2, System.Int32 Item3, System.Int32 Item4, System.Int32 Item5, System.Int32 Item6, System.Int32 Item7, System.Int32 Item8, System.Int32 Item9, System.Int32 Item10, System.Int32 Item11, System.Int32 Item12, System.Int32 Item13, System.Int32 Item14, System.Int32 Item15, System.Int32 Item16).Item2", "System.Int32 (System.Int32 Item1, System.Int32 Item2, System.Int32 Item3, System.Int32 Item4, System.Int32 Item5, System.Int32 Item6, System.Int32 Item7, System.Int32 Item8, System.Int32 Item9, System.Int32 Item10, System.Int32 Item11, System.Int32 Item12, System.Int32 Item13, System.Int32 Item14, System.Int32 Item15, System.Int32 Item16).Item3", "System.Int32 (System.Int32 Item1, System.Int32 Item2, System.Int32 Item3, System.Int32 Item4, System.Int32 Item5, System.Int32 Item6, System.Int32 Item7, System.Int32 Item8, System.Int32 Item9, System.Int32 Item10, System.Int32 Item11, System.Int32 Item12, System.Int32 Item13, System.Int32 Item14, System.Int32 Item15, System.Int32 Item16).Item4", "System.Int32 (System.Int32 Item1, System.Int32 Item2, System.Int32 Item3, System.Int32 Item4, System.Int32 Item5, System.Int32 Item6, System.Int32 Item7, System.Int32 Item8, System.Int32 Item9, System.Int32 Item10, System.Int32 Item11, System.Int32 Item12, System.Int32 Item13, System.Int32 Item14, System.Int32 Item15, System.Int32 Item16).Item5", "System.Int32 (System.Int32 Item1, System.Int32 Item2, System.Int32 Item3, System.Int32 Item4, System.Int32 Item5, System.Int32 Item6, System.Int32 Item7, System.Int32 Item8, System.Int32 Item9, System.Int32 Item10, System.Int32 Item11, System.Int32 Item12, System.Int32 Item13, System.Int32 Item14, System.Int32 Item15, System.Int32 Item16).Item6", "System.Int32 (System.Int32 Item1, System.Int32 Item2, System.Int32 Item3, System.Int32 Item4, System.Int32 Item5, System.Int32 Item6, System.Int32 Item7, System.Int32 Item8, System.Int32 Item9, System.Int32 Item10, System.Int32 Item11, System.Int32 Item12, System.Int32 Item13, System.Int32 Item14, System.Int32 Item15, System.Int32 Item16).Item7", "(System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32) (System.Int32 Item1, System.Int32 Item2, System.Int32 Item3, System.Int32 Item4, System.Int32 Item5, System.Int32 Item6, System.Int32 Item7, System.Int32 Item8, System.Int32 Item9, System.Int32 Item10, System.Int32 Item11, System.Int32 Item12, System.Int32 Item13, System.Int32 Item14, System.Int32 Item15, System.Int32 Item16).Rest", "(System.Int32 Item1, System.Int32 Item2, System.Int32 Item3, System.Int32 Item4, System.Int32 Item5, System.Int32 Item6, System.Int32 Item7, System.Int32 Item8, System.Int32 Item9, System.Int32 Item10, System.Int32 Item11, System.Int32 Item12, System.Int32 Item13, System.Int32 Item14, System.Int32 Item15, System.Int32 Item16)..ctor()", "(System.Int32 Item1, System.Int32 Item2, System.Int32 Item3, System.Int32 Item4, System.Int32 Item5, System.Int32 Item6, System.Int32 Item7, System.Int32 Item8, System.Int32 Item9, System.Int32 Item10, System.Int32 Item11, System.Int32 Item12, System.Int32 Item13, System.Int32 Item14, System.Int32 Item15, System.Int32 Item16)..ctor(System.Int32 item1, System.Int32 item2, System.Int32 item3, System.Int32 item4, System.Int32 item5, System.Int32 item6, System.Int32 item7, (System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32) rest)", "System.Boolean (System.Int32 Item1, System.Int32 Item2, System.Int32 Item3, System.Int32 Item4, System.Int32 Item5, System.Int32 Item6, System.Int32 Item7, System.Int32 Item8, System.Int32 Item9, System.Int32 Item10, System.Int32 Item11, System.Int32 Item12, System.Int32 Item13, System.Int32 Item14, System.Int32 Item15, System.Int32 Item16).Equals(System.Object obj)", "System.Boolean (System.Int32 Item1, System.Int32 Item2, System.Int32 Item3, System.Int32 Item4, System.Int32 Item5, System.Int32 Item6, System.Int32 Item7, System.Int32 Item8, System.Int32 Item9, System.Int32 Item10, System.Int32 Item11, System.Int32 Item12, System.Int32 Item13, System.Int32 Item14, System.Int32 Item15, System.Int32 Item16).Equals((System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32) other)", "System.Boolean (System.Int32 Item1, System.Int32 Item2, System.Int32 Item3, System.Int32 Item4, System.Int32 Item5, System.Int32 Item6, System.Int32 Item7, System.Int32 Item8, System.Int32 Item9, System.Int32 Item10, System.Int32 Item11, System.Int32 Item12, System.Int32 Item13, System.Int32 Item14, System.Int32 Item15, System.Int32 Item16).System.Collections.IStructuralEquatable.Equals(System.Object other, System.Collections.IEqualityComparer comparer)", "System.Int32 (System.Int32 Item1, System.Int32 Item2, System.Int32 Item3, System.Int32 Item4, System.Int32 Item5, System.Int32 Item6, System.Int32 Item7, System.Int32 Item8, System.Int32 Item9, System.Int32 Item10, System.Int32 Item11, System.Int32 Item12, System.Int32 Item13, System.Int32 Item14, System.Int32 Item15, System.Int32 Item16).System.IComparable.CompareTo(System.Object other)", "System.Int32 (System.Int32 Item1, System.Int32 Item2, System.Int32 Item3, System.Int32 Item4, System.Int32 Item5, System.Int32 Item6, System.Int32 Item7, System.Int32 Item8, System.Int32 Item9, System.Int32 Item10, System.Int32 Item11, System.Int32 Item12, System.Int32 Item13, System.Int32 Item14, System.Int32 Item15, System.Int32 Item16).CompareTo((System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32) other)", "System.Int32 (System.Int32 Item1, System.Int32 Item2, System.Int32 Item3, System.Int32 Item4, System.Int32 Item5, System.Int32 Item6, System.Int32 Item7, System.Int32 Item8, System.Int32 Item9, System.Int32 Item10, System.Int32 Item11, System.Int32 Item12, System.Int32 Item13, System.Int32 Item14, System.Int32 Item15, System.Int32 Item16).System.Collections.IStructuralComparable.CompareTo(System.Object other, System.Collections.IComparer comparer)", "System.Int32 (System.Int32 Item1, System.Int32 Item2, System.Int32 Item3, System.Int32 Item4, System.Int32 Item5, System.Int32 Item6, System.Int32 Item7, System.Int32 Item8, System.Int32 Item9, System.Int32 Item10, System.Int32 Item11, System.Int32 Item12, System.Int32 Item13, System.Int32 Item14, System.Int32 Item15, System.Int32 Item16).GetHashCode()", "System.Int32 (System.Int32 Item1, System.Int32 Item2, System.Int32 Item3, System.Int32 Item4, System.Int32 Item5, System.Int32 Item6, System.Int32 Item7, System.Int32 Item8, System.Int32 Item9, System.Int32 Item10, System.Int32 Item11, System.Int32 Item12, System.Int32 Item13, System.Int32 Item14, System.Int32 Item15, System.Int32 Item16).System.Collections.IStructuralEquatable.GetHashCode(System.Collections.IEqualityComparer comparer)", "System.Int32 (System.Int32 Item1, System.Int32 Item2, System.Int32 Item3, System.Int32 Item4, System.Int32 Item5, System.Int32 Item6, System.Int32 Item7, System.Int32 Item8, System.Int32 Item9, System.Int32 Item10, System.Int32 Item11, System.Int32 Item12, System.Int32 Item13, System.Int32 Item14, System.Int32 Item15, System.Int32 Item16).System.ITupleInternal.GetHashCode(System.Collections.IEqualityComparer comparer)", "System.String (System.Int32 Item1, System.Int32 Item2, System.Int32 Item3, System.Int32 Item4, System.Int32 Item5, System.Int32 Item6, System.Int32 Item7, System.Int32 Item8, System.Int32 Item9, System.Int32 Item10, System.Int32 Item11, System.Int32 Item12, System.Int32 Item13, System.Int32 Item14, System.Int32 Item15, System.Int32 Item16).ToString()", "System.String (System.Int32 Item1, System.Int32 Item2, System.Int32 Item3, System.Int32 Item4, System.Int32 Item5, System.Int32 Item6, System.Int32 Item7, System.Int32 Item8, System.Int32 Item9, System.Int32 Item10, System.Int32 Item11, System.Int32 Item12, System.Int32 Item13, System.Int32 Item14, System.Int32 Item15, System.Int32 Item16).System.ITupleInternal.ToStringEnd()", "System.Int32 (System.Int32 Item1, System.Int32 Item2, System.Int32 Item3, System.Int32 Item4, System.Int32 Item5, System.Int32 Item6, System.Int32 Item7, System.Int32 Item8, System.Int32 Item9, System.Int32 Item10, System.Int32 Item11, System.Int32 Item12, System.Int32 Item13, System.Int32 Item14, System.Int32 Item15, System.Int32 Item16).System.ITupleInternal.Size.get", "System.Int32 (System.Int32 Item1, System.Int32 Item2, System.Int32 Item3, System.Int32 Item4, System.Int32 Item5, System.Int32 Item6, System.Int32 Item7, System.Int32 Item8, System.Int32 Item9, System.Int32 Item10, System.Int32 Item11, System.Int32 Item12, System.Int32 Item13, System.Int32 Item14, System.Int32 Item15, System.Int32 Item16).System.ITupleInternal.Size { get; }", "System.Int32 (System.Int32 Item1, System.Int32 Item2, System.Int32 Item3, System.Int32 Item4, System.Int32 Item5, System.Int32 Item6, System.Int32 Item7, System.Int32 Item8, System.Int32 Item9, System.Int32 Item10, System.Int32 Item11, System.Int32 Item12, System.Int32 Item13, System.Int32 Item14, System.Int32 Item15, System.Int32 Item16).Item8", "System.Int32 (System.Int32 Item1, System.Int32 Item2, System.Int32 Item3, System.Int32 Item4, System.Int32 Item5, System.Int32 Item6, System.Int32 Item7, System.Int32 Item8, System.Int32 Item9, System.Int32 Item10, System.Int32 Item11, System.Int32 Item12, System.Int32 Item13, System.Int32 Item14, System.Int32 Item15, System.Int32 Item16).Item9", "System.Int32 (System.Int32 Item1, System.Int32 Item2, System.Int32 Item3, System.Int32 Item4, System.Int32 Item5, System.Int32 Item6, System.Int32 Item7, System.Int32 Item8, System.Int32 Item9, System.Int32 Item10, System.Int32 Item11, System.Int32 Item12, System.Int32 Item13, System.Int32 Item14, System.Int32 Item15, System.Int32 Item16).Item10", "System.Int32 (System.Int32 Item1, System.Int32 Item2, System.Int32 Item3, System.Int32 Item4, System.Int32 Item5, System.Int32 Item6, System.Int32 Item7, System.Int32 Item8, System.Int32 Item9, System.Int32 Item10, System.Int32 Item11, System.Int32 Item12, System.Int32 Item13, System.Int32 Item14, System.Int32 Item15, System.Int32 Item16).Item11", "System.Int32 (System.Int32 Item1, System.Int32 Item2, System.Int32 Item3, System.Int32 Item4, System.Int32 Item5, System.Int32 Item6, System.Int32 Item7, System.Int32 Item8, System.Int32 Item9, System.Int32 Item10, System.Int32 Item11, System.Int32 Item12, System.Int32 Item13, System.Int32 Item14, System.Int32 Item15, System.Int32 Item16).Item12", "System.Int32 (System.Int32 Item1, System.Int32 Item2, System.Int32 Item3, System.Int32 Item4, System.Int32 Item5, System.Int32 Item6, System.Int32 Item7, System.Int32 Item8, System.Int32 Item9, System.Int32 Item10, System.Int32 Item11, System.Int32 Item12, System.Int32 Item13, System.Int32 Item14, System.Int32 Item15, System.Int32 Item16).Item13", "System.Int32 (System.Int32 Item1, System.Int32 Item2, System.Int32 Item3, System.Int32 Item4, System.Int32 Item5, System.Int32 Item6, System.Int32 Item7, System.Int32 Item8, System.Int32 Item9, System.Int32 Item10, System.Int32 Item11, System.Int32 Item12, System.Int32 Item13, System.Int32 Item14, System.Int32 Item15, System.Int32 Item16).Item14", "System.Int32 (System.Int32 Item1, System.Int32 Item2, System.Int32 Item3, System.Int32 Item4, System.Int32 Item5, System.Int32 Item6, System.Int32 Item7, System.Int32 Item8, System.Int32 Item9, System.Int32 Item10, System.Int32 Item11, System.Int32 Item12, System.Int32 Item13, System.Int32 Item14, System.Int32 Item15, System.Int32 Item16).Item15", "System.Int32 (System.Int32 Item1, System.Int32 Item2, System.Int32 Item3, System.Int32 Item4, System.Int32 Item5, System.Int32 Item6, System.Int32 Item7, System.Int32 Item8, System.Int32 Item9, System.Int32 Item10, System.Int32 Item11, System.Int32 Item12, System.Int32 Item13, System.Int32 Item14, System.Int32 Item15, System.Int32 Item16).Item16"); var m5Item8 = (FieldSymbol)m5Tuple.GetMembers("Item8").Single(); AssertVirtualTupleElementField(m5Item8); Assert.Same(m5Item8, m5Item8.OriginalDefinition); Assert.True(m5Item8.Equals(m5Item8)); Assert.Equal("System.Int32 (System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32).Item1", m5Item8.TupleUnderlyingField.ToTestDisplayString()); Assert.Null(m5Item8.AssociatedSymbol); Assert.Same(m5Tuple, m5Item8.ContainingSymbol); Assert.NotEqual(m5Tuple.TupleUnderlyingType, m5Item8.TupleUnderlyingField.ContainingSymbol); Assert.NotEqual(m5Tuple, m5Item8.TupleUnderlyingField.ContainingSymbol); Assert.True(m5Item8.TypeWithAnnotations.CustomModifiers.IsEmpty); Assert.True(m5Item8.GetAttributes().IsEmpty); Assert.Null(m5Item8.GetUseSiteDiagnostic()); Assert.False(m5Item8.Locations.IsEmpty); Assert.Equal("int Item8", m5Item8.DeclaringSyntaxReferences.Single().GetSyntax().ToString()); Assert.Equal("Item1", m5Item8.TupleUnderlyingField.Name); Assert.False(m5Item8.IsImplicitlyDeclared); Assert.Null(m5Item8.TypeLayoutOffset); var m5TupleRestTuple = ((FieldSymbol)m5Tuple.GetMembers("Rest").Single()).Type; AssertTupleTypeEquality(m5TupleRestTuple); AssertTestDisplayString(m5TupleRestTuple.GetMembers(), "System.Int32 (System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32).Item1", "System.Int32 (System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32).Item2", "System.Int32 (System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32).Item3", "System.Int32 (System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32).Item4", "System.Int32 (System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32).Item5", "System.Int32 (System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32).Item6", "System.Int32 (System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32).Item7", "(System.Int32, System.Int32) (System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32).Rest", "(System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32)..ctor()", "(System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32)..ctor(System.Int32 item1, System.Int32 item2, System.Int32 item3, System.Int32 item4, System.Int32 item5, System.Int32 item6, System.Int32 item7, (System.Int32, System.Int32) rest)", "System.Boolean (System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32).Equals(System.Object obj)", "System.Boolean (System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32).Equals((System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32) other)", "System.Boolean (System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32).System.Collections.IStructuralEquatable.Equals(System.Object other, System.Collections.IEqualityComparer comparer)", "System.Int32 (System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32).System.IComparable.CompareTo(System.Object other)", "System.Int32 (System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32).CompareTo((System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32) other)", "System.Int32 (System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32).System.Collections.IStructuralComparable.CompareTo(System.Object other, System.Collections.IComparer comparer)", "System.Int32 (System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32).GetHashCode()", "System.Int32 (System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32).System.Collections.IStructuralEquatable.GetHashCode(System.Collections.IEqualityComparer comparer)", "System.Int32 (System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32).System.ITupleInternal.GetHashCode(System.Collections.IEqualityComparer comparer)", "System.String (System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32).ToString()", "System.String (System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32).System.ITupleInternal.ToStringEnd()", "System.Int32 (System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32).System.ITupleInternal.Size.get", "System.Int32 (System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32).System.ITupleInternal.Size { get; }", "System.Int32 (System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32).Item8", "System.Int32 (System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32).Item9"); foreach (var m in m5TupleRestTuple.GetMembers().OfType()) { if (m.Name != "Rest") { Assert.True(m.Locations.IsEmpty); } else { Assert.Equal("Rest", m.Name); } } var m5TupleRestTupleRestTuple = ((FieldSymbol)m5TupleRestTuple.GetMembers("Rest").Single()).Type; AssertTupleTypeEquality(m5TupleRestTupleRestTuple); AssertTestDisplayString(m5TupleRestTupleRestTuple.GetMembers(), "System.Int32 (System.Int32, System.Int32).Item1", "System.Int32 (System.Int32, System.Int32).Item2", "(System.Int32, System.Int32)..ctor()", "(System.Int32, System.Int32)..ctor(System.Int32 item1, System.Int32 item2)", "System.Boolean (System.Int32, System.Int32).Equals(System.Object obj)", "System.Boolean (System.Int32, System.Int32).Equals((System.Int32, System.Int32) other)", "System.Boolean (System.Int32, System.Int32).System.Collections.IStructuralEquatable.Equals(System.Object other, System.Collections.IEqualityComparer comparer)", "System.Int32 (System.Int32, System.Int32).System.IComparable.CompareTo(System.Object other)", "System.Int32 (System.Int32, System.Int32).CompareTo((System.Int32, System.Int32) other)", "System.Int32 (System.Int32, System.Int32).System.Collections.IStructuralComparable.CompareTo(System.Object other, System.Collections.IComparer comparer)", "System.Int32 (System.Int32, System.Int32).GetHashCode()", "System.Int32 (System.Int32, System.Int32).System.Collections.IStructuralEquatable.GetHashCode(System.Collections.IEqualityComparer comparer)", "System.Int32 (System.Int32, System.Int32).System.ITupleInternal.GetHashCode(System.Collections.IEqualityComparer comparer)", "System.String (System.Int32, System.Int32).ToString()", "System.String (System.Int32, System.Int32).System.ITupleInternal.ToStringEnd()", "System.Int32 (System.Int32, System.Int32).System.ITupleInternal.Size.get", "System.Int32 (System.Int32, System.Int32).System.ITupleInternal.Size { get; }"); foreach (var m in m5TupleRestTupleRestTuple.GetMembers().OfType()) { Assert.True(m.Locations.IsEmpty); } } [Fact] public void DefaultAndFriendlyElementNames_06() { var source = @" class C { static void Main() { var v5 = M5(); System.Console.WriteLine(v5.Rest.Item10); System.Console.WriteLine(v5.Rest.Item11); System.Console.WriteLine(v5.Rest.Item12); System.Console.WriteLine(v5.Rest.Item13); System.Console.WriteLine(v5.Rest.Item14); System.Console.WriteLine(v5.Rest.Item15); System.Console.WriteLine(v5.Rest.Item16); System.Console.WriteLine(v5.Rest.Rest.Item3); System.Console.WriteLine(v5.Rest.Rest.Item4); System.Console.WriteLine(v5.Rest.Rest.Item5); System.Console.WriteLine(v5.Rest.Rest.Item6); System.Console.WriteLine(v5.Rest.Rest.Item7); System.Console.WriteLine(v5.Rest.Rest.Item8); System.Console.WriteLine(v5.Rest.Rest.Item9); System.Console.WriteLine(v5.Rest.Rest.Item10); System.Console.WriteLine(v5.Rest.Rest.Item11); System.Console.WriteLine(v5.Rest.Rest.Item12); System.Console.WriteLine(v5.Rest.Rest.Item13); System.Console.WriteLine(v5.Rest.Rest.Item14); System.Console.WriteLine(v5.Rest.Rest.Item15); System.Console.WriteLine(v5.Rest.Rest.Item16); } static (int Item1, int Item2, int Item3, int Item4, int Item5, int Item6, int Item7, int Item8, int Item9, int Item10, int Item11, int Item12, int Item13, int Item14, int Item15, int Item16) M5() { return (501, 502, 503, 504, 505, 506, 507, 508, 509, 510, 511, 512, 513, 514, 515, 516); } } "; var comp = CreateCompilation(source); comp.VerifyDiagnostics( // (8,42): error CS1061: '(int, int, int, int, int, int, int, int, int)' does not contain a definition for 'Item10' and no extension method 'Item10' accepting a first argument of type '(int, int, int, int, int, int, int, int, int)' could be found (are you missing a using directive or an assembly reference?) // System.Console.WriteLine(v5.Rest.Item10); Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "Item10").WithArguments("(int, int, int, int, int, int, int, int, int)", "Item10").WithLocation(8, 42), // (9,42): error CS1061: '(int, int, int, int, int, int, int, int, int)' does not contain a definition for 'Item11' and no extension method 'Item11' accepting a first argument of type '(int, int, int, int, int, int, int, int, int)' could be found (are you missing a using directive or an assembly reference?) // System.Console.WriteLine(v5.Rest.Item11); Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "Item11").WithArguments("(int, int, int, int, int, int, int, int, int)", "Item11").WithLocation(9, 42), // (10,42): error CS1061: '(int, int, int, int, int, int, int, int, int)' does not contain a definition for 'Item12' and no extension method 'Item12' accepting a first argument of type '(int, int, int, int, int, int, int, int, int)' could be found (are you missing a using directive or an assembly reference?) // System.Console.WriteLine(v5.Rest.Item12); Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "Item12").WithArguments("(int, int, int, int, int, int, int, int, int)", "Item12").WithLocation(10, 42), // (11,42): error CS1061: '(int, int, int, int, int, int, int, int, int)' does not contain a definition for 'Item13' and no extension method 'Item13' accepting a first argument of type '(int, int, int, int, int, int, int, int, int)' could be found (are you missing a using directive or an assembly reference?) // System.Console.WriteLine(v5.Rest.Item13); Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "Item13").WithArguments("(int, int, int, int, int, int, int, int, int)", "Item13").WithLocation(11, 42), // (12,42): error CS1061: '(int, int, int, int, int, int, int, int, int)' does not contain a definition for 'Item14' and no extension method 'Item14' accepting a first argument of type '(int, int, int, int, int, int, int, int, int)' could be found (are you missing a using directive or an assembly reference?) // System.Console.WriteLine(v5.Rest.Item14); Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "Item14").WithArguments("(int, int, int, int, int, int, int, int, int)", "Item14").WithLocation(12, 42), // (13,42): error CS1061: '(int, int, int, int, int, int, int, int, int)' does not contain a definition for 'Item15' and no extension method 'Item15' accepting a first argument of type '(int, int, int, int, int, int, int, int, int)' could be found (are you missing a using directive or an assembly reference?) // System.Console.WriteLine(v5.Rest.Item15); Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "Item15").WithArguments("(int, int, int, int, int, int, int, int, int)", "Item15").WithLocation(13, 42), // (14,42): error CS1061: '(int, int, int, int, int, int, int, int, int)' does not contain a definition for 'Item16' and no extension method 'Item16' accepting a first argument of type '(int, int, int, int, int, int, int, int, int)' could be found (are you missing a using directive or an assembly reference?) // System.Console.WriteLine(v5.Rest.Item16); Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "Item16").WithArguments("(int, int, int, int, int, int, int, int, int)", "Item16").WithLocation(14, 42), // (16,47): error CS1061: '(int, int)' does not contain a definition for 'Item3' and no extension method 'Item3' accepting a first argument of type '(int, int)' could be found (are you missing a using directive or an assembly reference?) // System.Console.WriteLine(v5.Rest.Rest.Item3); Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "Item3").WithArguments("(int, int)", "Item3").WithLocation(16, 47), // (17,47): error CS1061: '(int, int)' does not contain a definition for 'Item4' and no extension method 'Item4' accepting a first argument of type '(int, int)' could be found (are you missing a using directive or an assembly reference?) // System.Console.WriteLine(v5.Rest.Rest.Item4); Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "Item4").WithArguments("(int, int)", "Item4").WithLocation(17, 47), // (18,47): error CS1061: '(int, int)' does not contain a definition for 'Item5' and no extension method 'Item5' accepting a first argument of type '(int, int)' could be found (are you missing a using directive or an assembly reference?) // System.Console.WriteLine(v5.Rest.Rest.Item5); Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "Item5").WithArguments("(int, int)", "Item5").WithLocation(18, 47), // (19,47): error CS1061: '(int, int)' does not contain a definition for 'Item6' and no extension method 'Item6' accepting a first argument of type '(int, int)' could be found (are you missing a using directive or an assembly reference?) // System.Console.WriteLine(v5.Rest.Rest.Item6); Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "Item6").WithArguments("(int, int)", "Item6").WithLocation(19, 47), // (20,47): error CS1061: '(int, int)' does not contain a definition for 'Item7' and no extension method 'Item7' accepting a first argument of type '(int, int)' could be found (are you missing a using directive or an assembly reference?) // System.Console.WriteLine(v5.Rest.Rest.Item7); Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "Item7").WithArguments("(int, int)", "Item7").WithLocation(20, 47), // (21,47): error CS1061: '(int, int)' does not contain a definition for 'Item8' and no extension method 'Item8' accepting a first argument of type '(int, int)' could be found (are you missing a using directive or an assembly reference?) // System.Console.WriteLine(v5.Rest.Rest.Item8); Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "Item8").WithArguments("(int, int)", "Item8").WithLocation(21, 47), // (22,47): error CS1061: '(int, int)' does not contain a definition for 'Item9' and no extension method 'Item9' accepting a first argument of type '(int, int)' could be found (are you missing a using directive or an assembly reference?) // System.Console.WriteLine(v5.Rest.Rest.Item9); Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "Item9").WithArguments("(int, int)", "Item9").WithLocation(22, 47), // (23,47): error CS1061: '(int, int)' does not contain a definition for 'Item10' and no extension method 'Item10' accepting a first argument of type '(int, int)' could be found (are you missing a using directive or an assembly reference?) // System.Console.WriteLine(v5.Rest.Rest.Item10); Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "Item10").WithArguments("(int, int)", "Item10").WithLocation(23, 47), // (24,47): error CS1061: '(int, int)' does not contain a definition for 'Item11' and no extension method 'Item11' accepting a first argument of type '(int, int)' could be found (are you missing a using directive or an assembly reference?) // System.Console.WriteLine(v5.Rest.Rest.Item11); Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "Item11").WithArguments("(int, int)", "Item11").WithLocation(24, 47), // (25,47): error CS1061: '(int, int)' does not contain a definition for 'Item12' and no extension method 'Item12' accepting a first argument of type '(int, int)' could be found (are you missing a using directive or an assembly reference?) // System.Console.WriteLine(v5.Rest.Rest.Item12); Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "Item12").WithArguments("(int, int)", "Item12").WithLocation(25, 47), // (26,47): error CS1061: '(int, int)' does not contain a definition for 'Item13' and no extension method 'Item13' accepting a first argument of type '(int, int)' could be found (are you missing a using directive or an assembly reference?) // System.Console.WriteLine(v5.Rest.Rest.Item13); Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "Item13").WithArguments("(int, int)", "Item13").WithLocation(26, 47), // (27,47): error CS1061: '(int, int)' does not contain a definition for 'Item14' and no extension method 'Item14' accepting a first argument of type '(int, int)' could be found (are you missing a using directive or an assembly reference?) // System.Console.WriteLine(v5.Rest.Rest.Item14); Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "Item14").WithArguments("(int, int)", "Item14").WithLocation(27, 47), // (28,47): error CS1061: '(int, int)' does not contain a definition for 'Item15' and no extension method 'Item15' accepting a first argument of type '(int, int)' could be found (are you missing a using directive or an assembly reference?) // System.Console.WriteLine(v5.Rest.Rest.Item15); Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "Item15").WithArguments("(int, int)", "Item15").WithLocation(28, 47), // (29,47): error CS1061: '(int, int)' does not contain a definition for 'Item16' and no extension method 'Item16' accepting a first argument of type '(int, int)' could be found (are you missing a using directive or an assembly reference?) // System.Console.WriteLine(v5.Rest.Rest.Item16); Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "Item16").WithArguments("(int, int)", "Item16").WithLocation(29, 47) ); } [Fact] public void DefaultAndFriendlyElementNames_07() { var source = @" class C { static void Main() { } static (int Item9, int Item1, int Item2, int Item3, int Item4, int Item5, int Item6, int Item7, int Item8) M7() { return (701, 702, 703, 704, 705, 706, 707, 708, 709); } } " + trivial2uple + trivial3uple + trivialRemainingTuples + tupleattributes_cs; var comp = CreateCompilation(source); comp.VerifyDiagnostics( // (9,17): error CS8125: Tuple member name 'Item9' is only allowed at position 9. // static (int Item9, int Item1, int Item2, int Item3, int Item4, int Item5, int Item6, int Item7, int Item8) M7() Diagnostic(ErrorCode.ERR_TupleReservedElementName, "Item9").WithArguments("Item9", "9").WithLocation(9, 17), // (9,28): error CS8125: Tuple member name 'Item1' is only allowed at position 1. // static (int Item9, int Item1, int Item2, int Item3, int Item4, int Item5, int Item6, int Item7, int Item8) M7() Diagnostic(ErrorCode.ERR_TupleReservedElementName, "Item1").WithArguments("Item1", "1").WithLocation(9, 28), // (9,39): error CS8125: Tuple member name 'Item2' is only allowed at position 2. // static (int Item9, int Item1, int Item2, int Item3, int Item4, int Item5, int Item6, int Item7, int Item8) M7() Diagnostic(ErrorCode.ERR_TupleReservedElementName, "Item2").WithArguments("Item2", "2").WithLocation(9, 39), // (9,50): error CS8125: Tuple member name 'Item3' is only allowed at position 3. // static (int Item9, int Item1, int Item2, int Item3, int Item4, int Item5, int Item6, int Item7, int Item8) M7() Diagnostic(ErrorCode.ERR_TupleReservedElementName, "Item3").WithArguments("Item3", "3").WithLocation(9, 50), // (9,61): error CS8125: Tuple member name 'Item4' is only allowed at position 4. // static (int Item9, int Item1, int Item2, int Item3, int Item4, int Item5, int Item6, int Item7, int Item8) M7() Diagnostic(ErrorCode.ERR_TupleReservedElementName, "Item4").WithArguments("Item4", "4").WithLocation(9, 61), // (9,72): error CS8125: Tuple member name 'Item5' is only allowed at position 5. // static (int Item9, int Item1, int Item2, int Item3, int Item4, int Item5, int Item6, int Item7, int Item8) M7() Diagnostic(ErrorCode.ERR_TupleReservedElementName, "Item5").WithArguments("Item5", "5").WithLocation(9, 72), // (9,83): error CS8125: Tuple member name 'Item6' is only allowed at position 6. // static (int Item9, int Item1, int Item2, int Item3, int Item4, int Item5, int Item6, int Item7, int Item8) M7() Diagnostic(ErrorCode.ERR_TupleReservedElementName, "Item6").WithArguments("Item6", "6").WithLocation(9, 83), // (9,94): error CS8125: Tuple member name 'Item7' is only allowed at position 7. // static (int Item9, int Item1, int Item2, int Item3, int Item4, int Item5, int Item6, int Item7, int Item8) M7() Diagnostic(ErrorCode.ERR_TupleReservedElementName, "Item7").WithArguments("Item7", "7").WithLocation(9, 94), // (9,105): error CS8125: Tuple member name 'Item8' is only allowed at position 8. // static (int Item9, int Item1, int Item2, int Item3, int Item4, int Item5, int Item6, int Item7, int Item8) M7() Diagnostic(ErrorCode.ERR_TupleReservedElementName, "Item8").WithArguments("Item8", "8").WithLocation(9, 105) ); var c = comp.GetTypeByMetadataName("C"); var m7Tuple = c.GetMember("M7").ReturnType; AssertTupleTypeEquality(m7Tuple); AssertTestDisplayString(m7Tuple.GetMembers(), "System.Int32 (System.Int32 Item9, System.Int32 Item1, System.Int32 Item2, System.Int32 Item3, System.Int32 Item4, System.Int32 Item5, System.Int32 Item6, System.Int32 Item7, System.Int32 Item8)" + ".Item1", "System.Int32 (System.Int32 Item9, System.Int32 Item1, System.Int32 Item2, System.Int32 Item3, System.Int32 Item4, System.Int32 Item5, System.Int32 Item6, System.Int32 Item7, System.Int32 Item8)" + ".Item9", "System.Int32 (System.Int32 Item9, System.Int32 Item1, System.Int32 Item2, System.Int32 Item3, System.Int32 Item4, System.Int32 Item5, System.Int32 Item6, System.Int32 Item7, System.Int32 Item8)" + ".Item2", "System.Int32 (System.Int32 Item9, System.Int32 Item1, System.Int32 Item2, System.Int32 Item3, System.Int32 Item4, System.Int32 Item5, System.Int32 Item6, System.Int32 Item7, System.Int32 Item8)" + ".Item1", "System.Int32 (System.Int32 Item9, System.Int32 Item1, System.Int32 Item2, System.Int32 Item3, System.Int32 Item4, System.Int32 Item5, System.Int32 Item6, System.Int32 Item7, System.Int32 Item8)" + ".Item3", "System.Int32 (System.Int32 Item9, System.Int32 Item1, System.Int32 Item2, System.Int32 Item3, System.Int32 Item4, System.Int32 Item5, System.Int32 Item6, System.Int32 Item7, System.Int32 Item8)" + ".Item2", "System.Int32 (System.Int32 Item9, System.Int32 Item1, System.Int32 Item2, System.Int32 Item3, System.Int32 Item4, System.Int32 Item5, System.Int32 Item6, System.Int32 Item7, System.Int32 Item8)" + ".Item4", "System.Int32 (System.Int32 Item9, System.Int32 Item1, System.Int32 Item2, System.Int32 Item3, System.Int32 Item4, System.Int32 Item5, System.Int32 Item6, System.Int32 Item7, System.Int32 Item8)" + ".Item3", "System.Int32 (System.Int32 Item9, System.Int32 Item1, System.Int32 Item2, System.Int32 Item3, System.Int32 Item4, System.Int32 Item5, System.Int32 Item6, System.Int32 Item7, System.Int32 Item8)" + ".Item5", "System.Int32 (System.Int32 Item9, System.Int32 Item1, System.Int32 Item2, System.Int32 Item3, System.Int32 Item4, System.Int32 Item5, System.Int32 Item6, System.Int32 Item7, System.Int32 Item8)" + ".Item4", "System.Int32 (System.Int32 Item9, System.Int32 Item1, System.Int32 Item2, System.Int32 Item3, System.Int32 Item4, System.Int32 Item5, System.Int32 Item6, System.Int32 Item7, System.Int32 Item8)" + ".Item6", "System.Int32 (System.Int32 Item9, System.Int32 Item1, System.Int32 Item2, System.Int32 Item3, System.Int32 Item4, System.Int32 Item5, System.Int32 Item6, System.Int32 Item7, System.Int32 Item8)" + ".Item5", "System.Int32 (System.Int32 Item9, System.Int32 Item1, System.Int32 Item2, System.Int32 Item3, System.Int32 Item4, System.Int32 Item5, System.Int32 Item6, System.Int32 Item7, System.Int32 Item8)" + ".Item7", "System.Int32 (System.Int32 Item9, System.Int32 Item1, System.Int32 Item2, System.Int32 Item3, System.Int32 Item4, System.Int32 Item5, System.Int32 Item6, System.Int32 Item7, System.Int32 Item8)" + ".Item6", "(System.Int32, System.Int32) (System.Int32 Item9, System.Int32 Item1, System.Int32 Item2, System.Int32 Item3, System.Int32 Item4, System.Int32 Item5, System.Int32 Item6, System.Int32 Item7, System.Int32 Item8)" + ".Rest", "(System.Int32 Item9, System.Int32 Item1, System.Int32 Item2, System.Int32 Item3, System.Int32 Item4, System.Int32 Item5, System.Int32 Item6, System.Int32 Item7, System.Int32 Item8)" + "..ctor" + "(System.Int32 item1, System.Int32 item2, System.Int32 item3, System.Int32 item4, System.Int32 item5, System.Int32 item6, System.Int32 item7, (System.Int32, System.Int32) rest)", "System.String (System.Int32 Item9, System.Int32 Item1, System.Int32 Item2, System.Int32 Item3, System.Int32 Item4, System.Int32 Item5, System.Int32 Item6, System.Int32 Item7, System.Int32 Item8)" + ".ToString()", "(System.Int32 Item9, System.Int32 Item1, System.Int32 Item2, System.Int32 Item3, System.Int32 Item4, System.Int32 Item5, System.Int32 Item6, System.Int32 Item7, System.Int32 Item8)" + "..ctor()", "System.Int32 (System.Int32 Item9, System.Int32 Item1, System.Int32 Item2, System.Int32 Item3, System.Int32 Item4, System.Int32 Item5, System.Int32 Item6, System.Int32 Item7, System.Int32 Item8)" + ".Item8", "System.Int32 (System.Int32 Item9, System.Int32 Item1, System.Int32 Item2, System.Int32 Item3, System.Int32 Item4, System.Int32 Item5, System.Int32 Item6, System.Int32 Item7, System.Int32 Item8)" + ".Item7", "System.Int32 (System.Int32 Item9, System.Int32 Item1, System.Int32 Item2, System.Int32 Item3, System.Int32 Item4, System.Int32 Item5, System.Int32 Item6, System.Int32 Item7, System.Int32 Item8)" + ".Item9", "System.Int32 (System.Int32 Item9, System.Int32 Item1, System.Int32 Item2, System.Int32 Item3, System.Int32 Item4, System.Int32 Item5, System.Int32 Item6, System.Int32 Item7, System.Int32 Item8)" + ".Item8" ); } [ConditionalFact(typeof(DesktopOnly))] public void DefaultAndFriendlyElementNames_08() { var source = @" class C { static void Main() { } static (int a1, int a2, int a3, int a4, int a5, int a6, int a7, int Item1) M8() { return (801, 802, 803, 804, 805, 806, 807, 808); } } "; var comp = CreateCompilation(source); comp.VerifyDiagnostics( // (9,73): error CS8125: Tuple member name 'Item1' is only allowed at position 1. // static (int a1, int a2, int a3, int a4, int a5, int a6, int a7, int Item1) M8() Diagnostic(ErrorCode.ERR_TupleReservedElementName, "Item1").WithArguments("Item1", "1").WithLocation(9, 73) ); var c = comp.GetTypeByMetadataName("C"); var m8Tuple = (NamedTypeSymbol)c.GetMember("M8").ReturnType; AssertTupleTypeEquality(m8Tuple); AssertTestDisplayString(m8Tuple.GetMembers(), "System.Int32 (System.Int32 a1, System.Int32 a2, System.Int32 a3, System.Int32 a4, System.Int32 a5, System.Int32 a6, System.Int32 a7, System.Int32 Item1).Item1", "System.Int32 (System.Int32 a1, System.Int32 a2, System.Int32 a3, System.Int32 a4, System.Int32 a5, System.Int32 a6, System.Int32 a7, System.Int32 Item1).a1", "System.Int32 (System.Int32 a1, System.Int32 a2, System.Int32 a3, System.Int32 a4, System.Int32 a5, System.Int32 a6, System.Int32 a7, System.Int32 Item1).Item2", "System.Int32 (System.Int32 a1, System.Int32 a2, System.Int32 a3, System.Int32 a4, System.Int32 a5, System.Int32 a6, System.Int32 a7, System.Int32 Item1).a2", "System.Int32 (System.Int32 a1, System.Int32 a2, System.Int32 a3, System.Int32 a4, System.Int32 a5, System.Int32 a6, System.Int32 a7, System.Int32 Item1).Item3", "System.Int32 (System.Int32 a1, System.Int32 a2, System.Int32 a3, System.Int32 a4, System.Int32 a5, System.Int32 a6, System.Int32 a7, System.Int32 Item1).a3", "System.Int32 (System.Int32 a1, System.Int32 a2, System.Int32 a3, System.Int32 a4, System.Int32 a5, System.Int32 a6, System.Int32 a7, System.Int32 Item1).Item4", "System.Int32 (System.Int32 a1, System.Int32 a2, System.Int32 a3, System.Int32 a4, System.Int32 a5, System.Int32 a6, System.Int32 a7, System.Int32 Item1).a4", "System.Int32 (System.Int32 a1, System.Int32 a2, System.Int32 a3, System.Int32 a4, System.Int32 a5, System.Int32 a6, System.Int32 a7, System.Int32 Item1).Item5", "System.Int32 (System.Int32 a1, System.Int32 a2, System.Int32 a3, System.Int32 a4, System.Int32 a5, System.Int32 a6, System.Int32 a7, System.Int32 Item1).a5", "System.Int32 (System.Int32 a1, System.Int32 a2, System.Int32 a3, System.Int32 a4, System.Int32 a5, System.Int32 a6, System.Int32 a7, System.Int32 Item1).Item6", "System.Int32 (System.Int32 a1, System.Int32 a2, System.Int32 a3, System.Int32 a4, System.Int32 a5, System.Int32 a6, System.Int32 a7, System.Int32 Item1).a6", "System.Int32 (System.Int32 a1, System.Int32 a2, System.Int32 a3, System.Int32 a4, System.Int32 a5, System.Int32 a6, System.Int32 a7, System.Int32 Item1).Item7", "System.Int32 (System.Int32 a1, System.Int32 a2, System.Int32 a3, System.Int32 a4, System.Int32 a5, System.Int32 a6, System.Int32 a7, System.Int32 Item1).a7", "System.ValueTuple (System.Int32 a1, System.Int32 a2, System.Int32 a3, System.Int32 a4, System.Int32 a5, System.Int32 a6, System.Int32 a7, System.Int32 Item1).Rest", "(System.Int32 a1, System.Int32 a2, System.Int32 a3, System.Int32 a4, System.Int32 a5, System.Int32 a6, System.Int32 a7, System.Int32 Item1)..ctor()", "(System.Int32 a1, System.Int32 a2, System.Int32 a3, System.Int32 a4, System.Int32 a5, System.Int32 a6, System.Int32 a7, System.Int32 Item1)..ctor(System.Int32 item1, System.Int32 item2, System.Int32 item3, System.Int32 item4, System.Int32 item5, System.Int32 item6, System.Int32 item7, System.ValueTuple rest)", "System.Boolean (System.Int32 a1, System.Int32 a2, System.Int32 a3, System.Int32 a4, System.Int32 a5, System.Int32 a6, System.Int32 a7, System.Int32 Item1).Equals(System.Object obj)", "System.Boolean (System.Int32 a1, System.Int32 a2, System.Int32 a3, System.Int32 a4, System.Int32 a5, System.Int32 a6, System.Int32 a7, System.Int32 Item1).Equals((System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32) other)", "System.Boolean (System.Int32 a1, System.Int32 a2, System.Int32 a3, System.Int32 a4, System.Int32 a5, System.Int32 a6, System.Int32 a7, System.Int32 Item1).System.Collections.IStructuralEquatable.Equals(System.Object other, System.Collections.IEqualityComparer comparer)", "System.Int32 (System.Int32 a1, System.Int32 a2, System.Int32 a3, System.Int32 a4, System.Int32 a5, System.Int32 a6, System.Int32 a7, System.Int32 Item1).System.IComparable.CompareTo(System.Object other)", "System.Int32 (System.Int32 a1, System.Int32 a2, System.Int32 a3, System.Int32 a4, System.Int32 a5, System.Int32 a6, System.Int32 a7, System.Int32 Item1).CompareTo((System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32) other)", "System.Int32 (System.Int32 a1, System.Int32 a2, System.Int32 a3, System.Int32 a4, System.Int32 a5, System.Int32 a6, System.Int32 a7, System.Int32 Item1).System.Collections.IStructuralComparable.CompareTo(System.Object other, System.Collections.IComparer comparer)", "System.Int32 (System.Int32 a1, System.Int32 a2, System.Int32 a3, System.Int32 a4, System.Int32 a5, System.Int32 a6, System.Int32 a7, System.Int32 Item1).GetHashCode()", "System.Int32 (System.Int32 a1, System.Int32 a2, System.Int32 a3, System.Int32 a4, System.Int32 a5, System.Int32 a6, System.Int32 a7, System.Int32 Item1).System.Collections.IStructuralEquatable.GetHashCode(System.Collections.IEqualityComparer comparer)", "System.Int32 (System.Int32 a1, System.Int32 a2, System.Int32 a3, System.Int32 a4, System.Int32 a5, System.Int32 a6, System.Int32 a7, System.Int32 Item1).System.ITupleInternal.GetHashCode(System.Collections.IEqualityComparer comparer)", "System.String (System.Int32 a1, System.Int32 a2, System.Int32 a3, System.Int32 a4, System.Int32 a5, System.Int32 a6, System.Int32 a7, System.Int32 Item1).ToString()", "System.String (System.Int32 a1, System.Int32 a2, System.Int32 a3, System.Int32 a4, System.Int32 a5, System.Int32 a6, System.Int32 a7, System.Int32 Item1).System.ITupleInternal.ToStringEnd()", "System.Int32 (System.Int32 a1, System.Int32 a2, System.Int32 a3, System.Int32 a4, System.Int32 a5, System.Int32 a6, System.Int32 a7, System.Int32 Item1).System.ITupleInternal.Size.get", "System.Int32 (System.Int32 a1, System.Int32 a2, System.Int32 a3, System.Int32 a4, System.Int32 a5, System.Int32 a6, System.Int32 a7, System.Int32 Item1).System.ITupleInternal.Size { get; }", "System.Int32 (System.Int32 a1, System.Int32 a2, System.Int32 a3, System.Int32 a4, System.Int32 a5, System.Int32 a6, System.Int32 a7, System.Int32 Item1).Item8", "System.Int32 (System.Int32 a1, System.Int32 a2, System.Int32 a3, System.Int32 a4, System.Int32 a5, System.Int32 a6, System.Int32 a7, System.Int32 Item1).Item1"); var m8Item8 = (FieldSymbol)m8Tuple.GetMembers("Item8").Single(); AssertVirtualTupleElementField(m8Item8); Assert.Same(m8Item8, m8Item8.OriginalDefinition); Assert.True(m8Item8.Equals(m8Item8)); Assert.Equal("System.Int32 System.ValueTuple.Item1", m8Item8.TupleUnderlyingField.ToTestDisplayString()); Assert.Null(m8Item8.AssociatedSymbol); Assert.Same(m8Tuple, m8Item8.ContainingSymbol); Assert.NotEqual(m8Tuple.TupleUnderlyingType, m8Item8.TupleUnderlyingField.ContainingSymbol); Assert.NotEqual(m8Tuple, m8Item8.TupleUnderlyingField.ContainingSymbol); Assert.True(m8Item8.TypeWithAnnotations.CustomModifiers.IsEmpty); Assert.True(m8Item8.GetAttributes().IsEmpty); Assert.Null(m8Item8.GetUseSiteDiagnostic()); Assert.False(m8Item8.Locations.IsEmpty); Assert.Equal("Item1", m8Item8.TupleUnderlyingField.Name); Assert.True(m8Item8.IsImplicitlyDeclared); Assert.Null(m8Item8.TypeLayoutOffset); var m8Item1 = (FieldSymbol)m8Tuple.GetMembers("Item1").Last(); AssertVirtualTupleElementField(m8Item1); Assert.Same(m8Item1, m8Item1.OriginalDefinition); Assert.True(m8Item1.Equals(m8Item1)); Assert.Equal("System.Int32 System.ValueTuple.Item1", m8Item1.TupleUnderlyingField.ToTestDisplayString()); Assert.Null(m8Item1.AssociatedSymbol); Assert.Same(m8Tuple, m8Item1.ContainingSymbol); Assert.NotEqual(m8Tuple.TupleUnderlyingType, m8Item1.TupleUnderlyingField.ContainingSymbol); Assert.NotEqual(m8Tuple, m8Item1.TupleUnderlyingField.ContainingSymbol); Assert.True(m8Item1.TypeWithAnnotations.CustomModifiers.IsEmpty); Assert.True(m8Item1.GetAttributes().IsEmpty); Assert.Null(m8Item1.GetUseSiteDiagnostic()); Assert.False(m8Item1.Locations.IsEmpty); Assert.Equal("Item1", m8Item1.Name); Assert.Equal("Item1", m8Item1.TupleUnderlyingField.Name); Assert.NotEqual(m8Item1.Locations.Single(), m8Item1.TupleUnderlyingField.Locations.Single()); Assert.False(m8Item1.IsImplicitlyDeclared); Assert.Null(m8Item1.TypeLayoutOffset); var m8TupleRestTuple = ((FieldSymbol)m8Tuple.GetMembers("Rest").Single()).Type; AssertTupleTypeEquality(m8TupleRestTuple); AssertTestDisplayString(m8TupleRestTuple.GetMembers(), "System.Int32 System.ValueTuple.Item1", "System.ValueTuple..ctor()", "System.ValueTuple..ctor(System.Int32 item1)", "System.Boolean System.ValueTuple.Equals(System.Object obj)", "System.Boolean System.ValueTuple.Equals(System.ValueTuple other)", "System.Boolean System.ValueTuple.System.Collections.IStructuralEquatable.Equals(System.Object other, System.Collections.IEqualityComparer comparer)", "System.Int32 System.ValueTuple.System.IComparable.CompareTo(System.Object other)", "System.Int32 System.ValueTuple.CompareTo(System.ValueTuple other)", "System.Int32 System.ValueTuple.System.Collections.IStructuralComparable.CompareTo(System.Object other, System.Collections.IComparer comparer)", "System.Int32 System.ValueTuple.GetHashCode()", "System.Int32 System.ValueTuple.System.Collections.IStructuralEquatable.GetHashCode(System.Collections.IEqualityComparer comparer)", "System.Int32 System.ValueTuple.System.ITupleInternal.GetHashCode(System.Collections.IEqualityComparer comparer)", "System.String System.ValueTuple.ToString()", "System.String System.ValueTuple.System.ITupleInternal.ToStringEnd()", "System.Int32 System.ValueTuple.System.ITupleInternal.Size.get", "System.Int32 System.ValueTuple.System.ITupleInternal.Size { get; }"); } [ConditionalFact(typeof(WindowsOnly), Reason = ConditionalSkipReason.TestExecutionHasNewLineDependency)] public void DefaultAndFriendlyElementNames_09() { var source = @" using System; class C { static void Main() { var v1 = (1, 11); System.Console.WriteLine(v1.Item1); System.Console.WriteLine(v1.Item2); var v2 =(a2: 2, b2: 22); System.Console.WriteLine(v2.Item1); System.Console.WriteLine(v2.Item2); System.Console.WriteLine(v2.a2); System.Console.WriteLine(v2.b2); var v6 = (item1: 6, item2: 66); System.Console.WriteLine(v6.Item1); System.Console.WriteLine(v6.Item2); System.Console.WriteLine(v6.item1); System.Console.WriteLine(v6.item2); System.Console.WriteLine(v1.ToString()); System.Console.WriteLine(v2.ToString()); System.Console.WriteLine(v6.ToString()); } } " + trivial2uple + tupleattributes_cs; var comp = CompileAndVerify(source, expectedOutput: @"1 11 2 22 2 22 6 66 6 66 {1, 11} {2, 22} {6, 66} "); var c = (CSharpCompilation)comp.Compilation; var tree = c.SyntaxTrees.Single(); var model = c.GetSemanticModel(tree); var node = tree.GetRoot().DescendantNodes().OfType().First(); var m1Tuple = model.LookupSymbols(node.SpanStart, name: "v1").OfType().Single().Type.GetSymbol(); var m2Tuple = model.LookupSymbols(node.SpanStart, name: "v2").OfType().Single().Type.GetSymbol(); var m6Tuple = model.LookupSymbols(node.SpanStart, name: "v6").OfType().Single().Type.GetSymbol(); AssertEx.Equal(new[] { "(System.Int32, System.Int32)..ctor()", "(System.Int32, System.Int32)..ctor(System.Int32 item1, System.Int32 item2)", "System.Int32 (System.Int32, System.Int32).Item1", "System.Int32 (System.Int32, System.Int32).Item2", "System.String (System.Int32, System.Int32).ToString()" }, m1Tuple.GetMembersUnordered().ToTestDisplayStrings().ToImmutableArray().Sort()); AssertTestDisplayString(m1Tuple.GetMembers(), "System.Int32 (System.Int32, System.Int32).Item1", "System.Int32 (System.Int32, System.Int32).Item2", "(System.Int32, System.Int32)..ctor(System.Int32 item1, System.Int32 item2)", "System.String (System.Int32, System.Int32).ToString()", "(System.Int32, System.Int32)..ctor()"); AssertTestDisplayString(m2Tuple.GetMembers(), "System.Int32 (System.Int32 a2, System.Int32 b2).Item1", "System.Int32 (System.Int32 a2, System.Int32 b2).a2", "System.Int32 (System.Int32 a2, System.Int32 b2).Item2", "System.Int32 (System.Int32 a2, System.Int32 b2).b2", "(System.Int32 a2, System.Int32 b2)..ctor(System.Int32 item1, System.Int32 item2)", "System.String (System.Int32 a2, System.Int32 b2).ToString()", "(System.Int32 a2, System.Int32 b2)..ctor()"); AssertTestDisplayString(m6Tuple.GetMembers(), "System.Int32 (System.Int32 item1, System.Int32 item2).Item1", "System.Int32 (System.Int32 item1, System.Int32 item2).item1", "System.Int32 (System.Int32 item1, System.Int32 item2).Item2", "System.Int32 (System.Int32 item1, System.Int32 item2).item2", "(System.Int32 item1, System.Int32 item2)..ctor(System.Int32 item1, System.Int32 item2)", "System.String (System.Int32 item1, System.Int32 item2).ToString()", "(System.Int32 item1, System.Int32 item2)..ctor()"); Assert.Equal("(System.Int32, System.Int32)", m1Tuple.ToTestDisplayString()); Assert.Equal("ValueTuple", m1Tuple.Name); Assert.Equal("System", m1Tuple.ContainingNamespace.ToTestDisplayString()); Assert.Equal(SymbolKind.NamedType, m1Tuple.Kind); Assert.Equal(TypeKind.Struct, m1Tuple.TypeKind); Assert.False(m1Tuple.IsImplicitlyDeclared); Assert.True(m1Tuple.IsTupleType); Assert.Same(m1Tuple, m1Tuple); Assert.Equal("(T1, T2)", m1Tuple.ConstructedFrom.ToTestDisplayString()); Assert.Equal("(T1, T2)", m1Tuple.OriginalDefinition.ToTestDisplayString()); Assert.NotSame(m1Tuple, m1Tuple.ConstructedFrom); Assert.NotSame(m1Tuple, m1Tuple.OriginalDefinition); AssertTupleTypeEquality(m1Tuple); Assert.Null(m1Tuple.GetUseSiteDiagnostic()); Assert.Null(m1Tuple.EnumUnderlyingType); Assert.Equal(new string[] { "Item1", "Item2", ".ctor", "ToString" }, m1Tuple.MemberNames.ToArray()); Assert.Equal(new string[] { "Item1", "a2", "Item2", "b2", ".ctor", "ToString" }, m2Tuple.MemberNames.ToArray()); Assert.Equal(2, m1Tuple.Arity); Assert.Equal(new[] { "T1", "T2" }, m1Tuple.TypeParameters.ToTestDisplayStrings()); Assert.Equal("System.ValueType", m1Tuple.BaseType().ToTestDisplayString()); Assert.Null(m1Tuple.ComImportCoClass); Assert.True(m1Tuple.TypeArgumentsWithAnnotationsNoUseSiteDiagnostics.All(t => t.CustomModifiers.IsEmpty)); Assert.False(m1Tuple.IsComImport); Assert.Equal(new[] { "System.Int32", "System.Int32" }, m1Tuple.TypeArgumentsWithAnnotationsNoUseSiteDiagnostics.ToTestDisplayStrings()); Assert.True(m1Tuple.GetAttributes().IsEmpty); Assert.Equal("System.Int32 (System.Int32 a2, System.Int32 b2).Item1", m2Tuple.GetMembers("Item1").Single().ToTestDisplayString()); Assert.Equal("System.Int32 (System.Int32 a2, System.Int32 b2).a2", m2Tuple.GetMembers("a2").Single().ToTestDisplayString()); Assert.True(m1Tuple.GetTypeMembers().IsEmpty); Assert.True(m1Tuple.GetTypeMembers("C9").IsEmpty); Assert.True(m1Tuple.GetTypeMembers("C9", 0).IsEmpty); Assert.True(m1Tuple.Interfaces().IsEmpty); Assert.Equal(m1Tuple.GetEarlyAttributeDecodingMembers().Select(m => m.Name).ToArray(), m1Tuple.GetEarlyAttributeDecodingMembers().Select(m => m.Name).ToArray()); Assert.Equal("System.Int32 (System.Int32, System.Int32).Item1", m1Tuple.GetEarlyAttributeDecodingMembers("Item1").Single().ToTestDisplayString()); Assert.True(m1Tuple.GetTypeMembersUnordered().IsEmpty); Assert.Equal(1, m1Tuple.Locations.Length); Assert.Equal("(1, 11)", m1Tuple.DeclaringSyntaxReferences.Single().GetSyntax().ToString()); Assert.Equal("(a2: 2, b2: 22)", m2Tuple.DeclaringSyntaxReferences.Single().GetSyntax().ToString()); Assert.True(m1Tuple.TupleUnderlyingType.DeclaringSyntaxReferences.IsEmpty); Assert.Equal("public struct ValueTuple", m1Tuple.OriginalDefinition.DeclaringSyntaxReferences.Single().GetSyntax().ToString().Substring(0, 32)); AssertTupleTypeEquality(m2Tuple); AssertTupleTypeEquality(m6Tuple); Assert.False(m1Tuple.Equals(m2Tuple)); Assert.False(m1Tuple.Equals(m6Tuple)); Assert.False(m6Tuple.Equals(m2Tuple)); AssertTupleTypeMembersEquality(m1Tuple, m2Tuple); AssertTupleTypeMembersEquality(m1Tuple, m6Tuple); AssertTupleTypeMembersEquality(m2Tuple, m6Tuple); var m1Item1 = (FieldSymbol)m1Tuple.GetMembers()[0]; var m2Item1 = (FieldSymbol)m2Tuple.GetMembers()[0]; var m2a2 = (FieldSymbol)m2Tuple.GetMembers()[1]; AssertNonvirtualTupleElementField(m1Item1); AssertNonvirtualTupleElementField(m2Item1); AssertVirtualTupleElementField(m2a2); Assert.NotSame(m1Item1, m1Item1.OriginalDefinition); Assert.True(m1Item1.ContainingType.OriginalDefinition.TupleElements[0].Equals(m1Item1.OriginalDefinition, TypeCompareKind.ConsiderEverything)); Assert.True(m1Item1.Equals(m1Item1)); Assert.Equal("System.Int32 (System.Int32, System.Int32).Item1", m1Item1.TupleUnderlyingField.ToTestDisplayString()); Assert.Null(m1Item1.AssociatedSymbol); Assert.Same(m1Tuple, m1Item1.ContainingSymbol); Assert.Same(m1Tuple, m1Item1.TupleUnderlyingField.ContainingSymbol); Assert.True(m1Item1.TypeWithAnnotations.CustomModifiers.IsEmpty); Assert.True(m1Item1.GetAttributes().IsEmpty); Assert.Null(m1Item1.GetUseSiteDiagnostic()); Assert.False(m1Item1.Locations.IsEmpty); Assert.True(m1Item1.DeclaringSyntaxReferences.IsEmpty); Assert.Equal("Item1", m1Item1.TupleUnderlyingField.DeclaringSyntaxReferences.Single().GetSyntax().ToString()); Assert.True(m1Item1.IsImplicitlyDeclared); Assert.Null(m1Item1.TypeLayoutOffset); Assert.NotSame(m2Item1, m2Item1.OriginalDefinition); Assert.True(m2Item1.ContainingType.OriginalDefinition.TupleElements[0].Equals(m2Item1.OriginalDefinition, TypeCompareKind.ConsiderEverything)); Assert.True(m2Item1.Equals(m2Item1)); Assert.Equal("System.Int32 (System.Int32 a2, System.Int32 b2).Item1", m2Item1.TupleUnderlyingField.ToTestDisplayString()); Assert.Null(m2Item1.AssociatedSymbol); Assert.Same(m2Tuple, m2Item1.ContainingSymbol); Assert.Same(m2Tuple, m2Item1.TupleUnderlyingField.ContainingSymbol); Assert.True(m2Item1.TypeWithAnnotations.CustomModifiers.IsEmpty); Assert.True(m2Item1.GetAttributes().IsEmpty); Assert.Null(m2Item1.GetUseSiteDiagnostic()); Assert.False(m2Item1.Locations.IsEmpty); Assert.True(m2Item1.DeclaringSyntaxReferences.IsEmpty); Assert.Equal("Item1", m2Item1.TupleUnderlyingField.DeclaringSyntaxReferences.Single().GetSyntax().ToString()); Assert.NotEqual(m2Item1.Locations.Single(), m2Item1.TupleUnderlyingField.Locations.Single()); Assert.Equal("SourceFile([891..896))", m2Item1.TupleUnderlyingField.Locations.Single().ToString()); Assert.Equal("SourceFile([196..198))", m2Item1.Locations.Single().ToString()); Assert.True(m2Item1.IsImplicitlyDeclared); Assert.Null(m2Item1.TypeLayoutOffset); Assert.Same(m2a2, m2a2.OriginalDefinition); Assert.True(m2a2.Equals(m2a2)); Assert.Equal("System.Int32 (System.Int32 a2, System.Int32 b2).Item1", m2a2.TupleUnderlyingField.ToTestDisplayString()); Assert.Null(m2a2.AssociatedSymbol); Assert.Same(m2Tuple, m2a2.ContainingSymbol); Assert.Same(m2Tuple, m2a2.TupleUnderlyingField.ContainingSymbol); Assert.True(m2a2.TypeWithAnnotations.CustomModifiers.IsEmpty); Assert.True(m2a2.GetAttributes().IsEmpty); Assert.Null(m2a2.GetUseSiteDiagnostic()); Assert.False(m2a2.Locations.IsEmpty); Assert.Equal("a2", m2a2.DeclaringSyntaxReferences.Single().GetSyntax().ToString()); Assert.Equal("Item1", m2a2.TupleUnderlyingField.DeclaringSyntaxReferences.Single().GetSyntax().ToString()); Assert.False(m2a2.IsImplicitlyDeclared); Assert.Null(m2a2.TypeLayoutOffset); var m1ToString = m1Tuple.GetMember("ToString"); Assert.NotSame(m1ToString, m1ToString.OriginalDefinition); Assert.Same(m1ToString, m1ToString.ConstructedFrom); Assert.Equal("System.String (T1, T2).ToString()", m1ToString.OriginalDefinition.ToTestDisplayString()); Assert.Equal("System.String (System.Int32, System.Int32).ToString()", m1ToString.ConstructedFrom.ToTestDisplayString()); Assert.Same(m1Tuple, m1ToString.ContainingSymbol); Assert.Null(m1ToString.AssociatedSymbol); Assert.False(m1ToString.IsExplicitInterfaceImplementation); Assert.True(m1ToString.ExplicitInterfaceImplementations.IsEmpty); Assert.False(m1ToString.ReturnsVoid); Assert.True(m1ToString.TypeArgumentsWithAnnotations.IsEmpty); Assert.True(m1ToString.TypeParameters.IsEmpty); Assert.True(m1ToString.GetAttributes().IsEmpty); Assert.Null(m1ToString.GetUseSiteDiagnostic()); Assert.Equal("System.String System.ValueType.ToString()", m1ToString.OverriddenMethod.ToTestDisplayString()); Assert.False(m1ToString.Locations.IsEmpty); Assert.Equal("public override string ToString()", m1ToString.DeclaringSyntaxReferences.Single().GetSyntax().ToString().Substring(0, 33)); } [Fact] public void CustomValueTupleWithStrangeThings_01() { var source = @" class C { static void Main() { var x1 = M9().Item1; var x2 = M9().Item2; var y = (int, int).C9; System.ValueTuple.C9 z = null; System.Console.WriteLine(z); } static (int, int) M9() { return (901, 902); } } namespace System { public struct ValueTuple { public T1 Item1; public T2 Item2; public ValueTuple(T1 item1, T2 item2) { this.Item1 = item1; this.Item2 = item2; } public override string ToString() { return '{' + Item1?.ToString() + "", "" + Item2?.ToString() + '}'; } public class C9{} } } " + tupleattributes_cs; var comp = CreateCompilationWithMscorlib40(source); comp.VerifyDiagnostics( // (10,18): error CS1525: Invalid expression term 'int' // var y = (int, int).C9; Diagnostic(ErrorCode.ERR_InvalidExprTerm, "int").WithArguments("int").WithLocation(10, 18), // (10,23): error CS1525: Invalid expression term 'int' // var y = (int, int).C9; Diagnostic(ErrorCode.ERR_InvalidExprTerm, "int").WithArguments("int").WithLocation(10, 23) ); var c = comp.GetTypeByMetadataName("C"); var m9Tuple = (NamedTypeSymbol)c.GetMember("M9").ReturnType; AssertTupleTypeEquality(m9Tuple); AssertTestDisplayString(m9Tuple.GetMembers(), "System.Int32 (System.Int32, System.Int32).Item1", "System.Int32 (System.Int32, System.Int32).Item2", "(System.Int32, System.Int32)..ctor(System.Int32 item1, System.Int32 item2)", "System.String (System.Int32, System.Int32).ToString()", "(System.Int32, System.Int32)..ctor()"); Assert.True(m9Tuple.Equals(m9Tuple.TupleUnderlyingType, TypeCompareKind.ConsiderEverything)); Assert.Equal("(System.Int32, System.Int32).C9", m9Tuple.GetTypeMembers().Single().ToTestDisplayString()); Assert.Equal("(System.Int32, System.Int32).C9", m9Tuple.GetTypeMembers("C9").Single().ToTestDisplayString()); Assert.Equal("(System.Int32, System.Int32).C9", m9Tuple.GetTypeMembers("C9", 0).Single().ToTestDisplayString()); Assert.Equal("(System.Int32, System.Int32).C9", m9Tuple.GetTypeMembersUnordered().Single().ToTestDisplayString()); } [Fact] public void CustomValueTupleWithStrangeThings_02() { var source = @" partial class C { static void Main() { } public static (int, int) M10() { return (101, 102); } static (int, int, int, int, int, int, int, int, int) M101() { return (1, 1, 1, 1, 1, 1, 1, 1, 1); } I1 Test01() { return M10(); } static (int a, int b) M102() { return (1, 1); } void Test02() { System.Console.WriteLine(M10().Item1); System.Console.WriteLine(M10().Item20); System.Console.WriteLine(M102().a); } static (int a, int b, int c, int d, int e, int f, int g, int h, int Item2) M103() { return (1, 1, 1, 1, 1, 1, 1, 1, 1); } } interface I1 { void M1(); int P1 { get; set; } event System.Action E1; } namespace System { [Obsolete] public struct ValueTuple : I1 { [Obsolete] public T1 Item1; [System.Runtime.InteropServices.FieldOffsetAttribute(20)] public T2 Item2; public ValueTuple(T1 item1, T2 item2) { this.Item1 = item1; this.Item2 = item2; this.Item20 = 0; this.Item21 = 0; } public override string ToString() { return '{' + Item1?.ToString() + "", "" + Item2?.ToString() + '}'; } public class C9{} void I1.M1(){} [Obsolete] public byte Item20; [System.Runtime.InteropServices.FieldOffsetAttribute(21)] public byte Item21; [Obsolete] public void M2() {} int I1.P1 { get; set; } [Obsolete] public int P2 { get; set; } event System.Action I1.E1 {add{} remove{}} [Obsolete] public event System.Action E2; } } partial class C { static void Test03() { M10().M2(); var x = M10().P2; M10().E2 += null; } } " + trivialRemainingTuples + tupleattributes_cs; var comp = CreateCompilation(source); var c = comp.GetTypeByMetadataName("C"); // Note: we don't report on Item2 because it is considered implicitly declared (see `ClsComplianceChecker.DoNotVisit`) comp.VerifyDiagnostics( // (8,19): warning CS0612: '(T1, T2)' is obsolete // public static (int, int) M10() Diagnostic(ErrorCode.WRN_DeprecatedSymbol, "(int, int)").WithArguments("(T1, T2)").WithLocation(8, 19), // (8,19): warning CS0612: '(int, int)' is obsolete // public static (int, int) M10() Diagnostic(ErrorCode.WRN_DeprecatedSymbol, "(int, int)").WithArguments("(int, int)").WithLocation(8, 19), // (13,12): warning CS0612: '(T1, T2)' is obsolete // static (int, int, int, int, int, int, int, int, int) M101() Diagnostic(ErrorCode.WRN_DeprecatedSymbol, "(int, int, int, int, int, int, int, int, int)").WithArguments("(T1, T2)").WithLocation(13, 12), // (23,12): warning CS0612: '(T1, T2)' is obsolete // static (int a, int b) M102() Diagnostic(ErrorCode.WRN_DeprecatedSymbol, "(int a, int b)").WithArguments("(T1, T2)").WithLocation(23, 12), // (23,12): warning CS0612: '(int a, int b)' is obsolete // static (int a, int b) M102() Diagnostic(ErrorCode.WRN_DeprecatedSymbol, "(int a, int b)").WithArguments("(int a, int b)").WithLocation(23, 12), // (35,73): error CS8125: Tuple element name 'Item2' is only allowed at position 2. // static (int a, int b, int c, int d, int e, int f, int g, int h, int Item2) M103() Diagnostic(ErrorCode.ERR_TupleReservedElementName, "Item2").WithArguments("Item2", "2").WithLocation(35, 73), // (35,12): warning CS0612: '(T1, T2)' is obsolete // static (int a, int b, int c, int d, int e, int f, int g, int h, int Item2) M103() Diagnostic(ErrorCode.WRN_DeprecatedSymbol, "(int a, int b, int c, int d, int e, int f, int g, int h, int Item2)").WithArguments("(T1, T2)").WithLocation(35, 12), // (55,10): error CS0636: The FieldOffset attribute can only be placed on members of types marked with the StructLayout(LayoutKind.Explicit) // [System.Runtime.InteropServices.FieldOffsetAttribute(20)] Diagnostic(ErrorCode.ERR_StructOffsetOnBadStruct, "System.Runtime.InteropServices.FieldOffsetAttribute").WithLocation(55, 10), // (78,10): error CS0636: The FieldOffset attribute can only be placed on members of types marked with the StructLayout(LayoutKind.Explicit) // [System.Runtime.InteropServices.FieldOffsetAttribute(21)] Diagnostic(ErrorCode.ERR_StructOffsetOnBadStruct, "System.Runtime.InteropServices.FieldOffsetAttribute").WithLocation(78, 10), // (10,16): warning CS0612: '(T1, T2)' is obsolete // return (101, 102); Diagnostic(ErrorCode.WRN_DeprecatedSymbol, "(101, 102)").WithArguments("(T1, T2)").WithLocation(10, 16), // (15,16): warning CS0612: '(T1, T2)' is obsolete // return (1, 1, 1, 1, 1, 1, 1, 1, 1); Diagnostic(ErrorCode.WRN_DeprecatedSymbol, "(1, 1, 1, 1, 1, 1, 1, 1, 1)").WithArguments("(T1, T2)").WithLocation(15, 16), // (25,16): warning CS0612: '(T1, T2)' is obsolete // return (1, 1); Diagnostic(ErrorCode.WRN_DeprecatedSymbol, "(1, 1)").WithArguments("(T1, T2)").WithLocation(25, 16), // (58,16): error CS0843: Auto-implemented property '(T1, T2).I1.P1' must be fully assigned before control is returned to the caller. // public ValueTuple(T1 item1, T2 item2) Diagnostic(ErrorCode.ERR_UnassignedThisAutoProperty, "ValueTuple").WithArguments("(T1, T2).I1.P1").WithLocation(58, 16), // (58,16): error CS0843: Auto-implemented property '(T1, T2).P2' must be fully assigned before control is returned to the caller. // public ValueTuple(T1 item1, T2 item2) Diagnostic(ErrorCode.ERR_UnassignedThisAutoProperty, "ValueTuple").WithArguments("(T1, T2).P2").WithLocation(58, 16), // (58,16): error CS0171: Field '(T1, T2).E2' must be fully assigned before control is returned to the caller // public ValueTuple(T1 item1, T2 item2) Diagnostic(ErrorCode.ERR_UnassignedThis, "ValueTuple").WithArguments("(T1, T2).E2").WithLocation(58, 16), // (30,34): warning CS0612: '(int, int).Item1' is obsolete // System.Console.WriteLine(M10().Item1); Diagnostic(ErrorCode.WRN_DeprecatedSymbol, "M10().Item1").WithArguments("(int, int).Item1").WithLocation(30, 34), // (31,34): warning CS0612: '(int, int).Item20' is obsolete // System.Console.WriteLine(M10().Item20); Diagnostic(ErrorCode.WRN_DeprecatedSymbol, "M10().Item20").WithArguments("(int, int).Item20").WithLocation(31, 34), // (32,34): warning CS0612: '(int a, int b).a' is obsolete // System.Console.WriteLine(M102().a); Diagnostic(ErrorCode.WRN_DeprecatedSymbol, "M102().a").WithArguments("(int a, int b).a").WithLocation(32, 34), // (37,16): warning CS0612: '(T1, T2)' is obsolete // return (1, 1, 1, 1, 1, 1, 1, 1, 1); Diagnostic(ErrorCode.WRN_DeprecatedSymbol, "(1, 1, 1, 1, 1, 1, 1, 1, 1)").WithArguments("(T1, T2)").WithLocation(37, 16), // (98,9): warning CS0612: '(int, int).M2()' is obsolete // M10().M2(); Diagnostic(ErrorCode.WRN_DeprecatedSymbol, "M10().M2()").WithArguments("(int, int).M2()").WithLocation(98, 9), // (99,17): warning CS0612: '(int, int).P2' is obsolete // var x = M10().P2; Diagnostic(ErrorCode.WRN_DeprecatedSymbol, "M10().P2").WithArguments("(int, int).P2").WithLocation(99, 17), // (100,9): warning CS0612: '(int, int).E2' is obsolete // M10().E2 += null; Diagnostic(ErrorCode.WRN_DeprecatedSymbol, "M10().E2").WithArguments("(int, int).E2").WithLocation(100, 9), // (90,36): warning CS0067: The event '(T1, T2).E2' is never used // public event System.Action E2; Diagnostic(ErrorCode.WRN_UnreferencedEvent, "E2").WithArguments("(T1, T2).E2").WithLocation(90, 36) ); var m10Tuple = (NamedTypeSymbol)c.GetMember("M10").ReturnType; AssertTupleTypeEquality(m10Tuple); Assert.Equal("System.ObsoleteAttribute", m10Tuple.GetAttributes().Single().ToString()); Assert.Equal("I1", m10Tuple.Interfaces().Single().ToTestDisplayString()); var m102Tuple = (NamedTypeSymbol)c.GetMember("M102").ReturnType; AssertTupleTypeEquality(m102Tuple); var m10Item1 = (FieldSymbol)m10Tuple.GetMembers("Item1").Single(); var m102Item20 = (FieldSymbol)m102Tuple.GetMembers("Item20").Single(); var m102a = (FieldSymbol)m102Tuple.GetMembers("a").Single(); AssertNonvirtualTupleElementField(m10Item1); AssertTupleNonElementField(m102Item20); AssertVirtualTupleElementField(m102a); Assert.Equal("System.ObsoleteAttribute", m10Item1.GetAttributes().Single().ToString()); Assert.Equal("System.ObsoleteAttribute", m102Item20.GetAttributes().Single().ToString()); Assert.Equal("System.ObsoleteAttribute", m102a.GetAttributes().Single().ToString()); var m10Item2 = (FieldSymbol)m10Tuple.GetMembers("Item2").Single(); var m102Item21 = (FieldSymbol)m102Tuple.GetMembers("Item21").Single(); var m102Item2 = (FieldSymbol)m102Tuple.GetMembers("Item2").Single(); var m102b = (FieldSymbol)m102Tuple.GetMembers("b").Single(); AssertNonvirtualTupleElementField(m10Item2); AssertNonvirtualTupleElementField(m102Item2); AssertTupleNonElementField(m102Item21); AssertVirtualTupleElementField(m102b); Assert.Equal(20, m10Item2.TypeLayoutOffset); Assert.Equal(20, m102Item2.TypeLayoutOffset); Assert.Equal(21, m102Item21.TypeLayoutOffset); Assert.Null(m102b.TypeLayoutOffset); Assert.Equal(20, m102b.TupleUnderlyingField.TypeLayoutOffset); var m103Tuple = (NamedTypeSymbol)c.GetMember("M103").ReturnType; AssertTupleTypeEquality(m103Tuple); var m103Item2 = (FieldSymbol)m103Tuple.GetMembers("Item2").Last(); var m103Item9 = (FieldSymbol)m103Tuple.GetMembers("Item9").Single(); AssertVirtualTupleElementField(m103Item2); AssertVirtualTupleElementField(m103Item9); Assert.Null(m103Item2.TypeLayoutOffset); Assert.Equal(20, m103Item2.TupleUnderlyingField.TypeLayoutOffset); Assert.Null(m103Item9.TypeLayoutOffset); Assert.Equal(20, m103Item9.TupleUnderlyingField.TypeLayoutOffset); var m10I1M1 = m10Tuple.GetMember("I1.M1"); Assert.True(m10I1M1.IsExplicitInterfaceImplementation); Assert.Equal("void I1.M1()", m10I1M1.ExplicitInterfaceImplementations.Single().ToTestDisplayString()); var m10M2 = m10Tuple.GetMember("M2"); Assert.Equal("System.ObsoleteAttribute", m10M2.GetAttributes().Single().ToString()); var m10I1P1 = m10Tuple.GetMember("I1.P1"); Assert.True(m10I1P1.IsExplicitInterfaceImplementation); Assert.Equal("System.Int32 I1.P1 { get; set; }", m10I1P1.ExplicitInterfaceImplementations.Single().ToTestDisplayString()); Assert.True(m10I1P1.GetMethod.IsExplicitInterfaceImplementation); Assert.Equal("System.Int32 I1.P1.get", m10I1P1.GetMethod.ExplicitInterfaceImplementations.Single().ToTestDisplayString()); Assert.True(m10I1P1.SetMethod.IsExplicitInterfaceImplementation); Assert.Equal("void I1.P1.set", m10I1P1.SetMethod.ExplicitInterfaceImplementations.Single().ToTestDisplayString()); var m10P2 = m10Tuple.GetMember("P2"); Assert.Equal("System.ObsoleteAttribute", m10P2.GetAttributes().Single().ToString()); var m10I1E1 = m10Tuple.GetMember("I1.E1"); Assert.True(m10I1E1.IsExplicitInterfaceImplementation); Assert.Equal("event System.Action I1.E1", m10I1E1.ExplicitInterfaceImplementations.Single().ToTestDisplayString()); Assert.True(m10I1E1.AddMethod.IsExplicitInterfaceImplementation); Assert.Equal("void I1.E1.add", m10I1E1.AddMethod.ExplicitInterfaceImplementations.Single().ToTestDisplayString()); Assert.True(m10I1E1.RemoveMethod.IsExplicitInterfaceImplementation); Assert.Equal("void I1.E1.remove", m10I1E1.RemoveMethod.ExplicitInterfaceImplementations.Single().ToTestDisplayString()); var m10E2 = m10Tuple.GetMember("E2"); Assert.Equal("System.ObsoleteAttribute", m10E2.GetAttributes().Single().ToString()); } private void AssertTupleNonElementField(FieldSymbol sym) { Assert.True(sym.ContainingType.IsTupleType); Assert.False(sym.IsVirtualTupleField); //it is not an element so index must be negative Assert.True(sym.TupleElementIndex < 0); } private void AssertVirtualTupleElementField(FieldSymbol sym) { Assert.True(sym.ContainingType.IsTupleType); Assert.True(sym.IsVirtualTupleField); //it is an element so must have nonnegative index Assert.True(sym.TupleElementIndex >= 0); } private void AssertNonvirtualTupleElementField(FieldSymbol sym) { Assert.True(sym.ContainingType.IsTupleType); Assert.False(sym.IsVirtualTupleField); //it is an element so must have nonnegative index Assert.True(sym.TupleElementIndex >= 0); //if it was 8th or after, it would be virtual Assert.True(sym.TupleElementIndex < NamedTypeSymbol.ValueTupleRestPosition - 1); } [Fact] public void CustomValueTupleWithGenericMethod() { var source = @" class C { static void Main() { M9().Test(""Yes""); } static (int, int) M9() { return (901, 902); } } namespace System { public struct ValueTuple { public T1 Item1; public T2 Item2; public ValueTuple(T1 item1, T2 item2) { this.Item1 = item1; this.Item2 = item2; } public void Test(U val) { System.Console.WriteLine(typeof(U)); System.Console.WriteLine(val); } } } " + tupleattributes_cs; var comp = CreateCompilation(source, options: TestOptions.ReleaseExe); comp.VerifyDiagnostics(); CompileAndVerify(comp, expectedOutput: @"System.String Yes"); var c = comp.GetTypeByMetadataName("C"); var m9Tuple = c.GetMember("M9").ReturnType; AssertTupleTypeEquality(m9Tuple); var m9Test = m9Tuple.GetMember("Test"); Assert.NotSame(m9Test, m9Test.OriginalDefinition); Assert.Same(m9Test, m9Test.ConstructedFrom); Assert.Equal("void (T1, T2).Test(U val)", m9Test.OriginalDefinition.ToTestDisplayString()); Assert.Equal("void (System.Int32, System.Int32).Test(U val)", m9Test.ConstructedFrom.ToTestDisplayString()); Assert.NotSame(m9Test.TypeParameters.Single(), m9Test.TypeParameters.Single().OriginalDefinition); Assert.Same(m9Test, m9Test.TypeParameters.Single().ContainingSymbol); Assert.Same(m9Test, m9Test.Parameters.Single().ContainingSymbol); Assert.Equal(0, m9Test.TypeParameters.Single().Ordinal); Assert.Equal(1, m9Test.Arity); } [ConditionalFact(typeof(DesktopOnly))] public void CreationOfTupleSymbols_01() { var source = @" class C { static void Main() { } static (int, int) M1() { return (101, 102); } static (int, int, int, int, int, int, int, int, int) M2() { return (1, 1, 1, 1, 1, 1, 1, 1, 1); } static (int, int, int) M3() { return (101, 102, 103); } } namespace System { public struct ValueTuple { public T1 Item1; public T2 Item2; public ValueTuple(T1 item1, T2 item2, T3 item3) => throw null; } } "; var comp = CreateCompilation(source); var c = comp.GetTypeByMetadataName("C"); comp.VerifyDiagnostics(); var m1Tuple = (NamedTypeSymbol)c.GetMember("M1").ReturnType; { var t1 = NamedTypeSymbol.CreateTuple(m1Tuple); var t2 = NamedTypeSymbol.CreateTuple(m1Tuple); Assert.True(t1.Equals(t2)); AssertTupleTypeMembersEquality(t1, t2); var t3 = NamedTypeSymbol.CreateTuple(m1Tuple, ImmutableArray.Create("a", "b")); var t4 = NamedTypeSymbol.CreateTuple(m1Tuple, ImmutableArray.Create("a", "b")); var t5 = NamedTypeSymbol.CreateTuple(m1Tuple, ImmutableArray.Create("b", "a")); Assert.False(t1.Equals(t3)); Assert.True(t1.Equals(t3, TypeCompareKind.IgnoreDynamicAndTupleNames)); Assert.True(t3.Equals(t1, TypeCompareKind.IgnoreDynamicAndTupleNames)); AssertTupleTypeMembersEquality(t1, t3); Assert.True(t3.Equals(t4)); AssertTupleTypeMembersEquality(t3, t4); Assert.False(t5.Equals(t3)); Assert.True(t5.Equals(t3, TypeCompareKind.IgnoreDynamicAndTupleNames)); Assert.True(t3.Equals(t5, TypeCompareKind.IgnoreDynamicAndTupleNames)); AssertTupleTypeMembersEquality(t5, t3); var t6 = NamedTypeSymbol.CreateTuple(m1Tuple, ImmutableArray.Create("Item1", "Item2")); var t7 = NamedTypeSymbol.CreateTuple(m1Tuple, ImmutableArray.Create("Item1", "Item2")); Assert.True(t6.Equals(t7)); AssertTupleTypeMembersEquality(t6, t7); Assert.False(t1.Equals(t6)); Assert.True(t1.Equals(t6, TypeCompareKind.IgnoreDynamicAndTupleNames)); Assert.True(t6.Equals(t1, TypeCompareKind.IgnoreDynamicAndTupleNames)); AssertTupleTypeMembersEquality(t1, t6); var t8 = NamedTypeSymbol.CreateTuple(m1Tuple, ImmutableArray.Create("Item2", "Item1")); Assert.False(t1.Equals(t8)); Assert.True(t1.Equals(t8, TypeCompareKind.IgnoreDynamicAndTupleNames)); Assert.True(t8.Equals(t1, TypeCompareKind.IgnoreDynamicAndTupleNames)); AssertTupleTypeMembersEquality(t1, t8); Assert.False(t6.Equals(t8)); Assert.True(t6.Equals(t8, TypeCompareKind.IgnoreDynamicAndTupleNames)); Assert.True(t8.Equals(t6, TypeCompareKind.IgnoreDynamicAndTupleNames)); AssertTupleTypeMembersEquality(t6, t8); } var m2Tuple = (NamedTypeSymbol)c.GetMember("M2").ReturnType; { var t1 = NamedTypeSymbol.CreateTuple(m2Tuple, default(ImmutableArray)); var t2 = NamedTypeSymbol.CreateTuple(m2Tuple, default(ImmutableArray)); Assert.True(t1.Equals(t2)); AssertTupleTypeMembersEquality(t1, t2); var t3 = NamedTypeSymbol.CreateTuple(m2Tuple, ImmutableArray.Create("a", "b", "c", "d", "e", "f", "g", "h", "i")); var t4 = NamedTypeSymbol.CreateTuple(m2Tuple, ImmutableArray.Create("a", "b", "c", "d", "e", "f", "g", "h", "i")); var t5 = NamedTypeSymbol.CreateTuple(m2Tuple, ImmutableArray.Create("a", "b", "c", "d", "e", "f", "g", "i", "h")); Assert.False(t1.Equals(t3)); Assert.True(t1.Equals(t3, TypeCompareKind.IgnoreDynamicAndTupleNames)); Assert.True(t3.Equals(t1, TypeCompareKind.IgnoreDynamicAndTupleNames)); AssertTupleTypeMembersEquality(t1, t3); Assert.True(t3.Equals(t4)); AssertTupleTypeMembersEquality(t3, t4); Assert.False(t5.Equals(t3)); Assert.True(t5.Equals(t3, TypeCompareKind.IgnoreDynamicAndTupleNames)); Assert.True(t3.Equals(t5, TypeCompareKind.IgnoreDynamicAndTupleNames)); AssertTupleTypeMembersEquality(t5, t3); var t6 = NamedTypeSymbol.CreateTuple(m2Tuple, ImmutableArray.Create("Item1", "Item2", "Item3", "Item4", "Item5", "Item6", "Item7", "Item8", "Item9")); var t7 = NamedTypeSymbol.CreateTuple(m2Tuple, ImmutableArray.Create("Item1", "Item2", "Item3", "Item4", "Item5", "Item6", "Item7", "Item8", "Item9")); Assert.True(t6.Equals(t7)); AssertTupleTypeMembersEquality(t6, t7); Assert.False(t1.Equals(t6)); Assert.True(t1.Equals(t6, TypeCompareKind.IgnoreDynamicAndTupleNames)); Assert.True(t6.Equals(t1, TypeCompareKind.IgnoreDynamicAndTupleNames)); AssertTupleTypeMembersEquality(t1, t6); var t8 = NamedTypeSymbol.CreateTuple(m2Tuple, ImmutableArray.Create("Item1", "Item2", "Item3", "Item4", "Item5", "Item6", "Item7", "Item9", "Item8")); Assert.False(t1.Equals(t8)); Assert.True(t1.Equals(t8, TypeCompareKind.IgnoreDynamicAndTupleNames)); Assert.True(t8.Equals(t1, TypeCompareKind.IgnoreDynamicAndTupleNames)); AssertTupleTypeMembersEquality(t1, t8); Assert.False(t6.Equals(t8)); Assert.True(t6.Equals(t8, TypeCompareKind.IgnoreDynamicAndTupleNames)); Assert.True(t8.Equals(t6, TypeCompareKind.IgnoreDynamicAndTupleNames)); AssertTupleTypeMembersEquality(t6, t8); var t9 = NamedTypeSymbol.CreateTuple(m2Tuple, ImmutableArray.Create("a", "b", "c", "d", "e", "f", "g", "Item1", "Item2")); var t10 = NamedTypeSymbol.CreateTuple(m2Tuple, ImmutableArray.Create("a", "b", "c", "d", "e", "f", "g", "Item1", "Item2")); Assert.True(t9.Equals(t10)); AssertTupleTypeMembersEquality(t9, t10); var t11 = NamedTypeSymbol.CreateTuple(m2Tuple.OriginalDefinition.Construct( m2Tuple.TypeArgumentsWithAnnotationsNoUseSiteDiagnostics.RemoveAt(7). Add(TypeWithAnnotations.Create(NamedTypeSymbol.CreateTuple(m1Tuple, ImmutableArray.Create("a", "b")))) )); Assert.False(t1.Equals(t11)); AssertTupleTypeMembersEquality(t1, t11); Assert.True(t1.Equals(t11, TypeCompareKind.IgnoreDynamicAndTupleNames)); Assert.True(t11.Equals(t1, TypeCompareKind.IgnoreDynamicAndTupleNames)); Assert.False(t1.Equals(t11)); Assert.True(t1.Equals(t11, TypeCompareKind.IgnoreDynamicAndTupleNames)); Assert.False(t11.Equals(t1)); Assert.True(t11.Equals(t1, TypeCompareKind.IgnoreDynamicAndTupleNames)); AssertTestDisplayString(t11.GetMembers(), "System.Int32 System.ValueTuple.Item1", "System.Int32 System.ValueTuple.Item2", "System.Int32 System.ValueTuple.Item3", "System.Int32 System.ValueTuple.Item4", "System.Int32 System.ValueTuple.Item5", "System.Int32 System.ValueTuple.Item6", "System.Int32 System.ValueTuple.Item7", "(System.Int32 a, System.Int32 b) System.ValueTuple.Rest", "System.ValueTuple..ctor()", "System.ValueTuple..ctor" + "(System.Int32 item1, System.Int32 item2, System.Int32 item3, System.Int32 item4, System.Int32 item5, System.Int32 item6, System.Int32 item7, " + "(System.Int32 a, System.Int32 b) rest)", "System.Boolean System.ValueTuple.Equals(System.Object obj)", "System.Boolean System.ValueTuple" + ".Equals(System.ValueTuple other)", "System.Boolean System.ValueTuple" + ".System.Collections.IStructuralEquatable.Equals(System.Object other, System.Collections.IEqualityComparer comparer)", "System.Int32 System.ValueTuple" + ".System.IComparable.CompareTo(System.Object other)", "System.Int32 System.ValueTuple" + ".CompareTo(System.ValueTuple other)", "System.Int32 System.ValueTuple" + ".System.Collections.IStructuralComparable.CompareTo(System.Object other, System.Collections.IComparer comparer)", "System.Int32 System.ValueTuple" + ".GetHashCode()", "System.Int32 System.ValueTuple" + ".System.Collections.IStructuralEquatable.GetHashCode(System.Collections.IEqualityComparer comparer)", "System.Int32 System.ValueTuple" + ".System.ITupleInternal.GetHashCode(System.Collections.IEqualityComparer comparer)", "System.String System.ValueTuple.ToString()", "System.String System.ValueTuple" + ".System.ITupleInternal.ToStringEnd()", "System.Int32 System.ValueTuple" + ".System.ITupleInternal.Size.get", "System.Int32 System.ValueTuple" + ".System.ITupleInternal.Size { get; }", "System.Int32 System.ValueTuple.Item8", "System.Int32 System.ValueTuple.Item9" ); var t12 = NamedTypeSymbol.CreateTuple(m2Tuple.OriginalDefinition.Construct( m2Tuple.TypeArgumentsWithAnnotationsNoUseSiteDiagnostics.RemoveAt(7). Add(TypeWithAnnotations.Create(NamedTypeSymbol.CreateTuple(m1Tuple, ImmutableArray.Create("Item1", "Item2")))) ), ImmutableArray.Create("Item1", "Item2", "Item3", "Item4", "Item5", "Item6", "Item7", "Item8", "Item9")); Assert.False(t1.Equals(t12)); AssertTupleTypeMembersEquality(t1, t12); Assert.True(t1.Equals(t12, TypeCompareKind.IgnoreDynamicAndTupleNames)); Assert.True(t12.Equals(t1, TypeCompareKind.IgnoreDynamicAndTupleNames)); Assert.False(t1.TupleUnderlyingType.Equals(t12.TupleUnderlyingType)); Assert.True(t1.TupleUnderlyingType.Equals(t12.TupleUnderlyingType, TypeCompareKind.IgnoreDynamicAndTupleNames)); Assert.False(t12.TupleUnderlyingType.Equals(t1.TupleUnderlyingType)); Assert.True(t12.TupleUnderlyingType.Equals(t1.TupleUnderlyingType, TypeCompareKind.IgnoreDynamicAndTupleNames)); Assert.False(t1.Equals(t12)); Assert.True(t1.Equals(t12, TypeCompareKind.IgnoreDynamicAndTupleNames)); Assert.False(t12.Equals(t1)); Assert.True(t12.Equals(t1, TypeCompareKind.IgnoreDynamicAndTupleNames)); AssertTestDisplayString(t12.GetMembers(), "System.Int32 (System.Int32 Item1, System.Int32 Item2, System.Int32 Item3, System.Int32 Item4, System.Int32 Item5, System.Int32 Item6, System.Int32 Item7, System.Int32 Item8, System.Int32 Item9).Item1", "System.Int32 (System.Int32 Item1, System.Int32 Item2, System.Int32 Item3, System.Int32 Item4, System.Int32 Item5, System.Int32 Item6, System.Int32 Item7, System.Int32 Item8, System.Int32 Item9).Item2", "System.Int32 (System.Int32 Item1, System.Int32 Item2, System.Int32 Item3, System.Int32 Item4, System.Int32 Item5, System.Int32 Item6, System.Int32 Item7, System.Int32 Item8, System.Int32 Item9).Item3", "System.Int32 (System.Int32 Item1, System.Int32 Item2, System.Int32 Item3, System.Int32 Item4, System.Int32 Item5, System.Int32 Item6, System.Int32 Item7, System.Int32 Item8, System.Int32 Item9).Item4", "System.Int32 (System.Int32 Item1, System.Int32 Item2, System.Int32 Item3, System.Int32 Item4, System.Int32 Item5, System.Int32 Item6, System.Int32 Item7, System.Int32 Item8, System.Int32 Item9).Item5", "System.Int32 (System.Int32 Item1, System.Int32 Item2, System.Int32 Item3, System.Int32 Item4, System.Int32 Item5, System.Int32 Item6, System.Int32 Item7, System.Int32 Item8, System.Int32 Item9).Item6", "System.Int32 (System.Int32 Item1, System.Int32 Item2, System.Int32 Item3, System.Int32 Item4, System.Int32 Item5, System.Int32 Item6, System.Int32 Item7, System.Int32 Item8, System.Int32 Item9).Item7", "(System.Int32 Item1, System.Int32 Item2) (System.Int32 Item1, System.Int32 Item2, System.Int32 Item3, System.Int32 Item4, System.Int32 Item5, System.Int32 Item6, System.Int32 Item7, System.Int32 Item8, System.Int32 Item9).Rest", "(System.Int32 Item1, System.Int32 Item2, System.Int32 Item3, System.Int32 Item4, System.Int32 Item5, System.Int32 Item6, System.Int32 Item7, System.Int32 Item8, System.Int32 Item9)..ctor()", "(System.Int32 Item1, System.Int32 Item2, System.Int32 Item3, System.Int32 Item4, System.Int32 Item5, System.Int32 Item6, System.Int32 Item7, System.Int32 Item8, System.Int32 Item9)" + "..ctor(System.Int32 item1, System.Int32 item2, System.Int32 item3, System.Int32 item4, System.Int32 item5, System.Int32 item6, System.Int32 item7, (System.Int32 Item1, System.Int32 Item2) rest)", "System.Boolean (System.Int32 Item1, System.Int32 Item2, System.Int32 Item3, System.Int32 Item4, System.Int32 Item5, System.Int32 Item6, System.Int32 Item7, System.Int32 Item8, System.Int32 Item9).Equals(System.Object obj)", "System.Boolean (System.Int32 Item1, System.Int32 Item2, System.Int32 Item3, System.Int32 Item4, System.Int32 Item5, System.Int32 Item6, System.Int32 Item7, System.Int32 Item8, System.Int32 Item9)" + ".Equals((System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32) other)", "System.Boolean (System.Int32 Item1, System.Int32 Item2, System.Int32 Item3, System.Int32 Item4, System.Int32 Item5, System.Int32 Item6, System.Int32 Item7, System.Int32 Item8, System.Int32 Item9)" + ".System.Collections.IStructuralEquatable.Equals(System.Object other, System.Collections.IEqualityComparer comparer)", "System.Int32 (System.Int32 Item1, System.Int32 Item2, System.Int32 Item3, System.Int32 Item4, System.Int32 Item5, System.Int32 Item6, System.Int32 Item7, System.Int32 Item8, System.Int32 Item9)" + ".System.IComparable.CompareTo(System.Object other)", "System.Int32 (System.Int32 Item1, System.Int32 Item2, System.Int32 Item3, System.Int32 Item4, System.Int32 Item5, System.Int32 Item6, System.Int32 Item7, System.Int32 Item8, System.Int32 Item9)" + ".CompareTo((System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32) other)", "System.Int32 (System.Int32 Item1, System.Int32 Item2, System.Int32 Item3, System.Int32 Item4, System.Int32 Item5, System.Int32 Item6, System.Int32 Item7, System.Int32 Item8, System.Int32 Item9)" + ".System.Collections.IStructuralComparable.CompareTo(System.Object other, System.Collections.IComparer comparer)", "System.Int32 (System.Int32 Item1, System.Int32 Item2, System.Int32 Item3, System.Int32 Item4, System.Int32 Item5, System.Int32 Item6, System.Int32 Item7, System.Int32 Item8, System.Int32 Item9)" + ".GetHashCode()", "System.Int32 (System.Int32 Item1, System.Int32 Item2, System.Int32 Item3, System.Int32 Item4, System.Int32 Item5, System.Int32 Item6, System.Int32 Item7, System.Int32 Item8, System.Int32 Item9)" + ".System.Collections.IStructuralEquatable.GetHashCode(System.Collections.IEqualityComparer comparer)", "System.Int32 (System.Int32 Item1, System.Int32 Item2, System.Int32 Item3, System.Int32 Item4, System.Int32 Item5, System.Int32 Item6, System.Int32 Item7, System.Int32 Item8, System.Int32 Item9)" + ".System.ITupleInternal.GetHashCode(System.Collections.IEqualityComparer comparer)", "System.String (System.Int32 Item1, System.Int32 Item2, System.Int32 Item3, System.Int32 Item4, System.Int32 Item5, System.Int32 Item6, System.Int32 Item7, System.Int32 Item8, System.Int32 Item9).ToString()", "System.String (System.Int32 Item1, System.Int32 Item2, System.Int32 Item3, System.Int32 Item4, System.Int32 Item5, System.Int32 Item6, System.Int32 Item7, System.Int32 Item8, System.Int32 Item9)" + ".System.ITupleInternal.ToStringEnd()", "System.Int32 (System.Int32 Item1, System.Int32 Item2, System.Int32 Item3, System.Int32 Item4, System.Int32 Item5, System.Int32 Item6, System.Int32 Item7, System.Int32 Item8, System.Int32 Item9)" + ".System.ITupleInternal.Size.get", "System.Int32 (System.Int32 Item1, System.Int32 Item2, System.Int32 Item3, System.Int32 Item4, System.Int32 Item5, System.Int32 Item6, System.Int32 Item7, System.Int32 Item8, System.Int32 Item9)" + ".System.ITupleInternal.Size { get; }", "System.Int32 (System.Int32 Item1, System.Int32 Item2, System.Int32 Item3, System.Int32 Item4, System.Int32 Item5, System.Int32 Item6, System.Int32 Item7, System.Int32 Item8, System.Int32 Item9).Item8", "System.Int32 (System.Int32 Item1, System.Int32 Item2, System.Int32 Item3, System.Int32 Item4, System.Int32 Item5, System.Int32 Item6, System.Int32 Item7, System.Int32 Item8, System.Int32 Item9).Item9" ); var t13 = NamedTypeSymbol.CreateTuple(m2Tuple.OriginalDefinition.Construct( m2Tuple.TypeArgumentsWithAnnotationsNoUseSiteDiagnostics.RemoveAt(7). Add(TypeWithAnnotations.Create(NamedTypeSymbol.CreateTuple(m1Tuple, ImmutableArray.Create("a", "b")))) ), ImmutableArray.Create("Item1", "Item2", "Item3", "Item4", "Item5", "Item6", "Item7", "Item8", "item9")); Assert.Equal("System.ValueTuple", t13.ToTestDisplayString()); } var m3Tuple = (NamedTypeSymbol)c.GetMember("M3").ReturnType; { var t1 = NamedTypeSymbol.CreateTuple(m3Tuple); var t2 = NamedTypeSymbol.CreateTuple(m3Tuple); Assert.True(t1.Equals(t2)); AssertTupleTypeMembersEquality(t1, t2); var t3 = NamedTypeSymbol.CreateTuple(m3Tuple, ImmutableArray.Create("a", "b", "c")); var t4 = NamedTypeSymbol.CreateTuple(m3Tuple, ImmutableArray.Create("a", "b", "c")); var t5 = NamedTypeSymbol.CreateTuple(m3Tuple, ImmutableArray.Create("c", "b", "a")); Assert.False(t1.Equals(t3)); Assert.True(t1.Equals(t3, TypeCompareKind.IgnoreDynamicAndTupleNames)); Assert.True(t3.Equals(t1, TypeCompareKind.IgnoreDynamicAndTupleNames)); AssertTupleTypeMembersEquality(t1, t3); Assert.True(t3.Equals(t4)); AssertTupleTypeMembersEquality(t3, t4); Assert.False(t5.Equals(t3)); Assert.True(t5.Equals(t3, TypeCompareKind.IgnoreDynamicAndTupleNames)); Assert.True(t3.Equals(t5, TypeCompareKind.IgnoreDynamicAndTupleNames)); AssertTupleTypeMembersEquality(t5, t3); var t6 = NamedTypeSymbol.CreateTuple(m3Tuple, ImmutableArray.Create("Item1", "Item2", "Item3")); var t7 = NamedTypeSymbol.CreateTuple(m3Tuple, ImmutableArray.Create("Item1", "Item2", "Item3")); Assert.True(t6.Equals(t7)); AssertTupleTypeMembersEquality(t6, t7); Assert.False(t1.Equals(t6)); Assert.True(t1.Equals(t6, TypeCompareKind.IgnoreDynamicAndTupleNames)); Assert.True(t6.Equals(t1, TypeCompareKind.IgnoreDynamicAndTupleNames)); AssertTupleTypeMembersEquality(t1, t6); var t8 = NamedTypeSymbol.CreateTuple(m3Tuple, ImmutableArray.Create("Item2", "Item3", "Item1")); Assert.False(t1.Equals(t8)); Assert.True(t1.Equals(t8, TypeCompareKind.IgnoreDynamicAndTupleNames)); Assert.True(t8.Equals(t1, TypeCompareKind.IgnoreDynamicAndTupleNames)); AssertTupleTypeMembersEquality(t1, t8); Assert.False(t6.Equals(t8)); Assert.True(t6.Equals(t8, TypeCompareKind.IgnoreDynamicAndTupleNames)); Assert.True(t8.Equals(t6, TypeCompareKind.IgnoreDynamicAndTupleNames)); AssertTupleTypeMembersEquality(t6, t8); } } private static void AssertTestDisplayString(ImmutableArray symbols, params string[] baseLine) { AssertEx.Equal(baseLine, symbols.Select(s => s.ToTestDisplayString())); } [Fact] public void UnifyUnderlyingWithTuple_01() { var source1 = @" class C { static void Main() { var v1 = Test.M1(); System.Console.WriteLine(v1.Item8); System.Console.WriteLine(v1.Item9); } } "; var source2 = @" using System; public class Test { public static ValueTuple> M1() { return (1, 2, 3, 4, 5, 6, 7, 8, 9); } } "; var comp1 = CreateCompilationWithMscorlib40(source2 + source1, references: new[] { ValueTupleRef, SystemRuntimeFacadeRef }, options: TestOptions.ReleaseExe); UnifyUnderlyingWithTuple_01_AssertCompilation(comp1); var comp2 = CreateCompilationWithMscorlib40(source2, references: new[] { ValueTupleRef, SystemRuntimeFacadeRef }, options: TestOptions.ReleaseDll); var comp2CompilationRef = comp2.ToMetadataReference(); var comp3 = CreateCompilationWithMscorlib45(source1, references: new[] { ValueTupleRef, SystemRuntimeFacadeRef, comp2CompilationRef }, options: TestOptions.ReleaseExe); Assert.NotSame(comp2.Assembly, (AssemblySymbol)comp3.GetAssemblyOrModuleSymbol(comp2CompilationRef)); // We are interested in retargeting scenario UnifyUnderlyingWithTuple_01_AssertCompilation(comp3); var comp4 = CreateCompilationWithMscorlib40(source1, references: new[] { ValueTupleRef, SystemRuntimeFacadeRef, comp2.EmitToImageReference() }, options: TestOptions.ReleaseExe); UnifyUnderlyingWithTuple_01_AssertCompilation(comp4); } private void UnifyUnderlyingWithTuple_01_AssertCompilation(CSharpCompilation comp) { CompileAndVerify(comp, expectedOutput: @"8 9 "); var test = comp.GetTypeByMetadataName("Test"); var m1Tuple = (NamedTypeSymbol)test.GetMember("M1").ReturnType; Assert.True(m1Tuple.IsTupleType); Assert.Equal("(System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32)", m1Tuple.ToTestDisplayString()); } [Fact] public void UnifyUnderlyingWithTuple_02() { var source = @" using System; class C { static void Main() { System.Console.WriteLine(nameof(ValueTuple>)); System.Console.WriteLine(typeof(ValueTuple>)); System.Console.WriteLine(typeof((int, int, int, int, int, int, int, int, int))); System.Console.WriteLine(typeof((int a, int b, int c, int d, int e, int f, int g, int h, int i))); System.Console.WriteLine(typeof(ValueTuple<,>)); System.Console.WriteLine(typeof(ValueTuple<,,,,,,,>)); } } "; var comp = CompileAndVerify(source, expectedOutput: @"ValueTuple System.ValueTuple`8[System.Int32,System.Int32,System.Int32,System.Int32,System.Int32,System.Int32,System.Int32,System.ValueTuple`2[System.Int32,System.Int32]] System.ValueTuple`8[System.Int32,System.Int32,System.Int32,System.Int32,System.Int32,System.Int32,System.Int32,System.ValueTuple`2[System.Int32,System.Int32]] System.ValueTuple`8[System.Int32,System.Int32,System.Int32,System.Int32,System.Int32,System.Int32,System.Int32,System.ValueTuple`2[System.Int32,System.Int32]] System.ValueTuple`2[T1,T2] System.ValueTuple`8[T1,T2,T3,T4,T5,T6,T7,TRest] "); var c = (CSharpCompilation)comp.Compilation; var tree = c.SyntaxTrees.Single(); var model = c.GetSemanticModel(tree); var nameofNode = tree.GetRoot().DescendantNodes().OfType().Where(id => id.Identifier.ValueText == "nameof").Single(); var nameofArg = ((InvocationExpressionSyntax)nameofNode.Parent).ArgumentList.Arguments.Single().Expression; var nameofArgSymbolInfo = model.GetSymbolInfo(nameofArg); Assert.True(((ITypeSymbol)nameofArgSymbolInfo.Symbol).IsTupleType); Assert.Equal("(System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32)", nameofArgSymbolInfo.Symbol.ToTestDisplayString()); var typeofNodes = tree.GetRoot().DescendantNodes().OfType().ToArray(); Assert.Equal(5, typeofNodes.Length); for (int i = 0; i < typeofNodes.Length; i++) { var t = typeofNodes[i]; var typeInfo = model.GetTypeInfo(t.Type); var symbolInfo = model.GetSymbolInfo(t.Type); Assert.Equal(typeInfo.Type, symbolInfo.Symbol); switch (i) { case 0: case 1: Assert.True(typeInfo.Type.IsTupleType); Assert.Equal("(System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32)", typeInfo.Type.ToTestDisplayString()); break; case 2: Assert.True(typeInfo.Type.IsTupleType); Assert.Equal("(System.Int32 a, System.Int32 b, System.Int32 c, System.Int32 d, System.Int32 e, System.Int32 f, System.Int32 g, System.Int32 h, System.Int32 i)", typeInfo.Type.ToTestDisplayString()); break; default: Assert.False(typeInfo.Type.IsTupleType); Assert.True(((INamedTypeSymbol)typeInfo.Type).IsUnboundGenericType); break; } } } [Fact] public void UnifyUnderlyingWithTuple_03() { var source = @" class C { static void Main() { System.Console.WriteLine(nameof((int, int))); System.Console.WriteLine(nameof((int a, int b))); } } "; var comp = CreateCompilation(source); comp.VerifyDiagnostics( // (6,42): error CS1525: Invalid expression term 'int' // System.Console.WriteLine(nameof((int, int))); Diagnostic(ErrorCode.ERR_InvalidExprTerm, "int").WithArguments("int").WithLocation(6, 42), // (6,47): error CS1525: Invalid expression term 'int' // System.Console.WriteLine(nameof((int, int))); Diagnostic(ErrorCode.ERR_InvalidExprTerm, "int").WithArguments("int").WithLocation(6, 47), // (7,42): error CS8185: A declaration is not allowed in this context. // System.Console.WriteLine(nameof((int a, int b))); Diagnostic(ErrorCode.ERR_DeclarationExpressionNotPermitted, "int a").WithLocation(7, 42), // (7,49): error CS8185: A declaration is not allowed in this context. // System.Console.WriteLine(nameof((int a, int b))); Diagnostic(ErrorCode.ERR_DeclarationExpressionNotPermitted, "int b").WithLocation(7, 49), // (7,41): error CS8081: Expression does not have a name. // System.Console.WriteLine(nameof((int a, int b))); Diagnostic(ErrorCode.ERR_ExpressionHasNoName, "(int a, int b)").WithLocation(7, 41) ); } [Fact] public void UnifyUnderlyingWithTuple_04() { var source1 = @" class C { static void Main() { var v1 = Test.M1(); System.Console.WriteLine(v1.Rest.a); System.Console.WriteLine(v1.Rest.b); } } "; var source2 = @" using System; public class Test { public static ValueTuple M1() { return (1, 2, 3, 4, 5, 6, 7, 8, 9); } } "; var comp1 = CreateCompilationWithMscorlib40(source2 + source1, references: s_valueTupleRefs, options: TestOptions.ReleaseExe); unifyUnderlyingWithTuple_04_AssertCompilation(comp1); var comp2 = CreateCompilationWithMscorlib40(source2, references: s_valueTupleRefs, options: TestOptions.ReleaseDll); var comp2CompilationRef = comp2.ToMetadataReference(); var comp3 = CreateCompilationWithMscorlib45(source1, references: (new[] { comp2CompilationRef }).Concat(s_valueTupleRefs), options: TestOptions.ReleaseExe); Assert.NotSame(comp2.Assembly, (AssemblySymbol)comp3.GetAssemblyOrModuleSymbol(comp2CompilationRef)); // We are interested in retargeting scenario unifyUnderlyingWithTuple_04_AssertCompilation(comp3); var comp4 = CreateCompilationWithMscorlib40(source1, references: (new[] { comp2.EmitToImageReference() }).Concat(s_valueTupleRefs), options: TestOptions.ReleaseExe); unifyUnderlyingWithTuple_04_AssertCompilation(comp4); void unifyUnderlyingWithTuple_04_AssertCompilation(CSharpCompilation comp) { CompileAndVerify(comp, expectedOutput: @"8 9 "); var test = comp.GetTypeByMetadataName("Test"); var m1Tuple = (NamedTypeSymbol)test.GetMember("M1").ReturnType; Assert.True(m1Tuple.IsTupleType); AssertEx.Equal("System.ValueTuple", m1Tuple.ToTestDisplayString()); } } [ConditionalFact(typeof(DesktopOnly))] public void UnifyUnderlyingWithTuple_05() { var source = @" using System; using System.Collections.Generic; class C { static void Main() { var v1 = Test>.M1((1, 2, 3, 4, 5, 6, 7, 8, 9)); System.Console.WriteLine(v1.Item8); System.Console.WriteLine(v1.Item9); var v2 = Test<(int a, int b)>.M2((1, 2, 3, 4, 5, 6, 7, 10, 11)); System.Console.WriteLine(v2.Item8); System.Console.WriteLine(v2.Item9); System.Console.WriteLine(v2.Rest.a); System.Console.WriteLine(v2.Rest.b); Test>.F1 = (1, 2, 3, 4, 5, 6, 7, 12, 13); var v3 = Test>.F1; System.Console.WriteLine(v3.Item8); System.Console.WriteLine(v3.Item9); Test>.P1 = (1, 2, 3, 4, 5, 6, 7, 14, 15); var v4 = Test>.P1; System.Console.WriteLine(v4.Item8); System.Console.WriteLine(v4.Item9); var v5 = Test>.M3((1, 2, 3, 4, 5, 6, 7, 16, 17)); System.Console.WriteLine(v5[0].Item8); System.Console.WriteLine(v5[0].Item9); var v6 = Test>.M4((1, 2, 3, 4, 5, 6, 7, 18, 19)); System.Console.WriteLine(v6[0].Item8); System.Console.WriteLine(v6[0].Item9); var v7 = (new Test33()).M5((1, 2, 3, 4, 5, 6, 7, 20, 21)); System.Console.WriteLine(v7.Item8); System.Console.WriteLine(v7.Item9); var v8 = (1, 2).M6((1, 2, 3, 4, 5, 6, 7, 22, 23)); System.Console.WriteLine(v8.Item8); System.Console.WriteLine(v8.Item9); } } class Test where T : struct { public static ValueTuple M1(ValueTuple val) { return val; } public static ValueTuple M2(ValueTuple val) { return val; } public static ValueTuple F1; public static ValueTuple P1 {get; set;} public static ValueTuple[] M3(ValueTuple val) { return new [] {val}; } public static List> M4(ValueTuple val) { return new List>() {val}; } } abstract class Test31 { public abstract U M5(U val) where U : T; } abstract class Test32 : Test31> where T : struct { } class Test33 : Test32> { public override U M5(U val) { return val; } } static class Test4 { public static ValueTuple M6(this T target, ValueTuple val) where T : struct { return val; } } "; var comp = CompileAndVerify(source, options: TestOptions.ReleaseExe.WithAllowUnsafe(true), expectedOutput: @"8 9 10 11 10 11 12 13 14 15 16 17 18 19 20 21 22 23 "); var test = comp.Compilation.GetTypeByMetadataName("Test`1"); var m1Tuple = (INamedTypeSymbol)test.GetMember("M1").ReturnType; Assert.False(m1Tuple.IsTupleType); Assert.Equal("System.ValueTuple", m1Tuple.ToTestDisplayString()); m1Tuple = (INamedTypeSymbol)test.GetMember("M1").Parameters[0].Type; Assert.False(m1Tuple.IsTupleType); Assert.Equal("System.ValueTuple", m1Tuple.ToTestDisplayString()); var c = (CSharpCompilation)comp.Compilation; var tree = c.SyntaxTrees.Single(); var model = c.GetSemanticModel(tree); var m1 = tree.GetRoot().DescendantNodes().OfType().Where(id => id.Identifier.ValueText == "M1").Single(); var symbolInfo = model.GetSymbolInfo(m1); m1Tuple = (INamedTypeSymbol)((IMethodSymbol)symbolInfo.Symbol).ReturnType; Assert.True(m1Tuple.IsTupleType); Assert.Equal("(System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32)", m1Tuple.ToTestDisplayString()); Assert.Equal("(System.Int32, System.Int32)", m1Tuple.GetMember("Rest").Type.ToTestDisplayString()); m1Tuple = (INamedTypeSymbol)((IMethodSymbol)symbolInfo.Symbol).Parameters[0].Type; Assert.True(m1Tuple.IsTupleType); Assert.Equal("(System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32)", m1Tuple.ToTestDisplayString()); Assert.Equal("(System.Int32, System.Int32)", m1Tuple.GetMember("Rest").Type.ToTestDisplayString()); var m2 = tree.GetRoot().DescendantNodes().OfType().Where(id => id.Identifier.ValueText == "M2").Single(); symbolInfo = model.GetSymbolInfo(m2); var m2Tuple = (INamedTypeSymbol)((IMethodSymbol)symbolInfo.Symbol).ReturnType; Assert.True(m2Tuple.IsTupleType); Assert.Equal("System.ValueTuple", m2Tuple.ToTestDisplayString()); Assert.Equal("(System.Int32 a, System.Int32 b)", m2Tuple.GetMember("Rest").Type.ToTestDisplayString()); var f1Tuple = (INamedTypeSymbol)test.GetMember("F1").Type; Assert.False(f1Tuple.IsTupleType); Assert.Equal("System.ValueTuple", f1Tuple.ToTestDisplayString()); var f1 = tree.GetRoot().DescendantNodes().OfType().Where(id => id.Identifier.ValueText == "F1").First(); symbolInfo = model.GetSymbolInfo(f1); f1Tuple = (INamedTypeSymbol)((IFieldSymbol)symbolInfo.Symbol).Type; Assert.True(f1Tuple.IsTupleType); Assert.Equal("(System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32)", f1Tuple.ToTestDisplayString()); Assert.Equal("(System.Int32, System.Int32)", f1Tuple.GetMember("Rest").Type.ToTestDisplayString()); var p1Tuple = (INamedTypeSymbol)test.GetMember("P1").Type; Assert.False(p1Tuple.IsTupleType); Assert.Equal("System.ValueTuple", p1Tuple.ToTestDisplayString()); var p1 = tree.GetRoot().DescendantNodes().OfType().Where(id => id.Identifier.ValueText == "P1").First(); symbolInfo = model.GetSymbolInfo(p1); p1Tuple = (INamedTypeSymbol)((IPropertySymbol)symbolInfo.Symbol).Type; Assert.True(p1Tuple.IsTupleType); Assert.Equal("(System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32)", p1Tuple.ToTestDisplayString()); Assert.Equal("(System.Int32, System.Int32)", p1Tuple.GetMember("Rest").Type.ToTestDisplayString()); var m3TupleArray = (IArrayTypeSymbol)test.GetMember("M3").ReturnType; Assert.False(m3TupleArray.ElementType.IsTupleType); Assert.Equal("System.ValueTuple[]", m3TupleArray.ToTestDisplayString()); Assert.Equal("System.Collections.Generic.IList>", m3TupleArray.Interfaces[0].ToTestDisplayString()); var m3 = tree.GetRoot().DescendantNodes().OfType().Where(id => id.Identifier.ValueText == "M3").Single(); symbolInfo = model.GetSymbolInfo(m3); m3TupleArray = (IArrayTypeSymbol)((IMethodSymbol)symbolInfo.Symbol).ReturnType; Assert.True(m3TupleArray.ElementType.IsTupleType); Assert.Equal("(System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32)[]", m3TupleArray.ToTestDisplayString()); Assert.Equal("System.Collections.Generic.IList<(System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32)>", m3TupleArray.Interfaces[0].ToTestDisplayString()); var m4TupleList = (INamedTypeSymbol)test.GetMember("M4").ReturnType; Assert.False(m4TupleList.TypeArguments[0].IsTupleType); Assert.Equal("System.Collections.Generic.List>", m4TupleList.ToTestDisplayString()); Assert.Equal("System.Collections.Generic.IList>", m4TupleList.Interfaces[0].ToTestDisplayString()); var m4 = tree.GetRoot().DescendantNodes().OfType().Where(id => id.Identifier.ValueText == "M4").Single(); symbolInfo = model.GetSymbolInfo(m4); m4TupleList = (INamedTypeSymbol)((IMethodSymbol)symbolInfo.Symbol).ReturnType; Assert.True(m4TupleList.TypeArguments[0].IsTupleType); Assert.Equal("System.Collections.Generic.List<(System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32)>", m4TupleList.ToTestDisplayString()); var m5 = tree.GetRoot().DescendantNodes().OfType().Where(id => id.Identifier.ValueText == "M5").Single(); symbolInfo = model.GetSymbolInfo(m5); var m5Tuple = ((IMethodSymbol)symbolInfo.Symbol).TypeParameters[0].ConstraintTypes.Single(); Assert.True(m5Tuple.IsTupleType); Assert.Equal("(System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32)", m5Tuple.ToTestDisplayString()); var m6 = tree.GetRoot().DescendantNodes().OfType().Where(id => id.Identifier.ValueText == "M6").Single(); symbolInfo = model.GetSymbolInfo(m6); var m6Method = (IMethodSymbol)symbolInfo.Symbol; Assert.Equal(MethodKind.ReducedExtension, m6Method.MethodKind); var m6Tuple = m6Method.ReturnType; Assert.True(m6Tuple.IsTupleType); Assert.Equal("(System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32)", m6Tuple.ToTestDisplayString()); m6Tuple = m6Method.Parameters.Last().Type; Assert.True(m6Tuple.IsTupleType); Assert.Equal("(System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32)", m6Tuple.ToTestDisplayString()); } [Fact] public void UnifyUnderlyingWithTuple_06() { var source = @" using System; unsafe class C { static void Main() { var x = Test>.E1; var v7 = Test>.M5(); System.Console.WriteLine(v7->Item8); System.Console.WriteLine(v7->Item9); Test1> v1 = null; System.Console.WriteLine(v1.Item8); ITest2> v2 = null; System.Console.WriteLine(v2.Item8); } } unsafe class Test where T : struct { public static event ValueTuple E1; public static ValueTuple* M5() { return null; } } class Test1 : ValueTuple where T : struct { } interface ITest2 : ValueTuple where T : struct { } "; var comp = (Compilation)CreateCompilation(source, options: TestOptions.ReleaseExe.WithAllowUnsafe(true)); comp.VerifyDiagnostics( // (31,18): error CS0509: 'Test1': cannot derive from sealed type 'ValueTuple' // class Test1 : ValueTuple where T : struct Diagnostic(ErrorCode.ERR_CantDeriveFromSealedType, "ValueTuple").WithArguments("Test1", "System.ValueTuple").WithLocation(31, 18), // (35,23): error CS0527: Type 'ValueTuple' in interface list is not an interface // interface ITest2 : ValueTuple where T : struct Diagnostic(ErrorCode.ERR_NonInterfaceInInterfaceList, "ValueTuple").WithArguments("System.ValueTuple").WithLocation(35, 23), // (25,69): error CS0208: Cannot take the address of, get the size of, or declare a pointer to a managed type ('ValueTuple') // public static ValueTuple* M5() Diagnostic(ErrorCode.ERR_ManagedAddr, "M5").WithArguments("System.ValueTuple").WithLocation(25, 69), // (23,74): error CS0066: 'Test.E1': event must be of a delegate type // public static event ValueTuple E1; Diagnostic(ErrorCode.ERR_EventNotDelegate, "E1").WithArguments("Test.E1").WithLocation(23, 74), // (7,44): error CS0070: The event 'Test<(int, int)>.E1' can only appear on the left hand side of += or -= (except when used from within the type 'Test<(int, int)>') // var x = Test>.E1; Diagnostic(ErrorCode.ERR_BadEventUsage, "E1").WithArguments("Test<(int, int)>.E1", "Test<(int, int)>").WithLocation(7, 44), // (14,37): error CS1061: 'Test1<(int, int)>' does not contain a definition for 'Item8' and no accessible extension method 'Item8' accepting a first argument of type 'Test1<(int, int)>' could be found (are you missing a using directive or an assembly reference?) // System.Console.WriteLine(v1.Item8); Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "Item8").WithArguments("Test1<(int, int)>", "Item8").WithLocation(14, 37), // (17,37): error CS1061: 'ITest2<(int, int)>' does not contain a definition for 'Item8' and no accessible extension method 'Item8' accepting a first argument of type 'ITest2<(int, int)>' could be found (are you missing a using directive or an assembly reference?) // System.Console.WriteLine(v2.Item8); Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "Item8").WithArguments("ITest2<(int, int)>", "Item8").WithLocation(17, 37) ); var test = comp.GetTypeByMetadataName("Test`1"); var e1Tuple = (INamedTypeSymbol)test.GetMember("E1").Type; Assert.False(e1Tuple.IsTupleType); Assert.Equal("System.ValueTuple", e1Tuple.ToTestDisplayString()); var tree = comp.SyntaxTrees.Single(); var model = comp.GetSemanticModel(tree); var e1 = tree.GetRoot().DescendantNodes().OfType().Where(id => id.Identifier.ValueText == "E1").Single(); var symbolInfo = model.GetSymbolInfo(e1); e1Tuple = (INamedTypeSymbol)((IEventSymbol)symbolInfo.CandidateSymbols.Single()).Type; Assert.True(e1Tuple.IsTupleType); Assert.Equal("(System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32)", e1Tuple.ToTestDisplayString()); Assert.Equal("(System.Int32, System.Int32)", e1Tuple.GetMember("Rest").Type.ToTestDisplayString()); var m5TuplePointer = (IPointerTypeSymbol)test.GetMember("M5").ReturnType; Assert.False(m5TuplePointer.PointedAtType.IsTupleType); Assert.Equal("System.ValueTuple*", m5TuplePointer.ToTestDisplayString()); var m5 = tree.GetRoot().DescendantNodes().OfType().Where(id => id.Identifier.ValueText == "M5").Single(); symbolInfo = model.GetSymbolInfo(m5); m5TuplePointer = (IPointerTypeSymbol)((IMethodSymbol)symbolInfo.Symbol).ReturnType; Assert.True(m5TuplePointer.PointedAtType.IsTupleType); Assert.Equal("(System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32, System.Int32)*", m5TuplePointer.ToTestDisplayString()); var v1 = tree.GetRoot().DescendantNodes().OfType().Where(id => id.Identifier.ValueText == "v1").Single(); symbolInfo = model.GetSymbolInfo(v1); var v1Type = ((ILocalSymbol)symbolInfo.Symbol).Type; Assert.Equal("Test1<(System.Int32, System.Int32)>", v1Type.ToTestDisplayString()); var v1Tuple = v1Type.BaseType; Assert.False(v1Tuple.IsTupleType); Assert.Equal("System.Object", v1Tuple.ToTestDisplayString()); var v2 = tree.GetRoot().DescendantNodes().OfType().Where(id => id.Identifier.ValueText == "v2").Single(); symbolInfo = model.GetSymbolInfo(v2); var v2Type = ((ILocalSymbol)symbolInfo.Symbol).Type; Assert.Equal("ITest2<(System.Int32, System.Int32)>", v2Type.ToTestDisplayString()); Assert.True(v2Type.Interfaces.IsEmpty); } [Fact] public void UnifyUnderlyingWithTuple_07() { var source1 = @" using System; public class Test { public static ValueTuple M1() { throw new NotImplementedException(); } } " + trivialRemainingTuples + tupleattributes_cs; var source2 = @" class C { static void Main() { var v1 = Test<(int, int, int, int, int, int, int, int, int)>.M1(); System.Console.WriteLine(v1.Item8); System.Console.WriteLine(v1.Item9); System.Console.WriteLine(v1.Rest.Item8); System.Console.WriteLine(v1.Rest.Item9); } } " + trivial2uple + trivialRemainingTuples + tupleattributes_cs; var comp1 = CreateCompilationWithMscorlib40(source1, options: TestOptions.ReleaseDll); comp1.VerifyDiagnostics(); var comp2 = CreateCompilationWithMscorlib40(source2, references: new[] { comp1.ToMetadataReference() }, options: TestOptions.ReleaseExe); comp2.VerifyDiagnostics( // (7,37): error CS1061: 'ValueTuple' does not contain a definition for 'Item8' and no extension method 'Item8' accepting a first argument of type 'ValueTuple' could be found (are you missing a using directive or an assembly reference?) // System.Console.WriteLine(v1.Item8); Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "Item8").WithArguments("System.ValueTuple", "Item8").WithLocation(7, 37), // (8,37): error CS1061: 'ValueTuple' does not contain a definition for 'Item9' and no extension method 'Item9' accepting a first argument of type 'ValueTuple' could be found (are you missing a using directive or an assembly reference?) // System.Console.WriteLine(v1.Item9); Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "Item9").WithArguments("System.ValueTuple", "Item9").WithLocation(8, 37) ); } [Fact] public void UnifyUnderlyingWithTuple_08() { var source = @" using System; using System.Collections.Generic; class C { static void Main() { var x = (1, 3); string s = x; System.Console.WriteLine(s); System.Console.WriteLine((long)x); (int, string) y = new KeyValuePair(2, ""4""); System.Console.WriteLine(y); System.Console.WriteLine((ValueTuple)""5""); System.Console.WriteLine(+x); System.Console.WriteLine(-x); System.Console.WriteLine(!x); System.Console.WriteLine(~x); System.Console.WriteLine(++x); System.Console.WriteLine(--x); System.Console.WriteLine(x ? true : false); System.Console.WriteLine(!x ? true : false); System.Console.WriteLine(x + 1); System.Console.WriteLine(x - 1); System.Console.WriteLine(x * 3); System.Console.WriteLine(x / 2); System.Console.WriteLine(x % 3); System.Console.WriteLine(x & 3); System.Console.WriteLine(x | 15); System.Console.WriteLine(x ^ 4); System.Console.WriteLine(x << 1); System.Console.WriteLine(x >> 1); System.Console.WriteLine(x == 1); System.Console.WriteLine(x != 1); System.Console.WriteLine(x > 1); System.Console.WriteLine(x < 1); System.Console.WriteLine(x >= 1); System.Console.WriteLine(x <= 1); } } "; var tuple = @" namespace System { // struct with two values public struct ValueTuple { public T1 Item1; public T2 Item2; public ValueTuple(T1 item1, T2 item2) { this.Item1 = item1; this.Item2 = item2; } public override string ToString() { return '{' + Item1?.ToString() + "", "" + Item2?.ToString() + '}'; } public static implicit operator string(ValueTuple arg) { return arg.ToString(); } public static explicit operator long(ValueTuple arg) { return ((long)(int)(object)arg.Item1 + (long)(int)(object)arg.Item2); } public static implicit operator ValueTuple(System.Collections.Generic.KeyValuePair arg) { return new ValueTuple(arg.Key, arg.Value); } public static explicit operator ValueTuple(string arg) { return new ValueTuple((T1)(object)arg, (T2)(object)arg); } public static ValueTuple operator +(ValueTuple arg) { return arg; } public static long operator -(ValueTuple arg) { return -(long)arg; } public static bool operator !(ValueTuple arg) { return (long)arg == 0; } public static long operator ~(ValueTuple arg) { return -(long)arg; } public static ValueTuple operator ++(ValueTuple arg) { return new ValueTuple((T1)(object)((int)(object)arg.Item1+1), (T2)(object)((int)(object)arg.Item2+1)); } public static ValueTuple operator --(ValueTuple arg) { return new ValueTuple((T1)(object)((int)(object)arg.Item1 - 1), (T2)(object)((int)(object)arg.Item2 - 1)); } public static bool operator true(ValueTuple arg) { return (long)arg != 0; } public static bool operator false(ValueTuple arg) { return (long)arg == 0; } public static long operator + (ValueTuple arg1, int arg2) { return (long)arg1 + arg2; } public static long operator -(ValueTuple arg1, int arg2) { return (long)arg1 - arg2; } public static long operator *(ValueTuple arg1, int arg2) { return (long)arg1 * arg2; } public static long operator /(ValueTuple arg1, int arg2) { return (long)arg1 / arg2; } public static long operator %(ValueTuple arg1, int arg2) { return (long)arg1 % arg2; } public static long operator &(ValueTuple arg1, int arg2) { return (long)arg1 & arg2; } public static long operator |(ValueTuple arg1, long arg2) { return (long)arg1 | arg2; } public static long operator ^(ValueTuple arg1, int arg2) { return (long)arg1 ^ arg2; } public static long operator <<(ValueTuple arg1, int arg2) { return (long)arg1 << arg2; } public static long operator >>(ValueTuple arg1, int arg2) { return (long)arg1 >> arg2; } public static bool operator ==(ValueTuple arg1, int arg2) { return (long)arg1 == arg2; } public static bool operator !=(ValueTuple arg1, int arg2) { return (long)arg1 != arg2; } public static bool operator >(ValueTuple arg1, int arg2) { return (long)arg1 > arg2; } public static bool operator <(ValueTuple arg1, int arg2) { return (long)arg1 < arg2; } public static bool operator >=(ValueTuple arg1, int arg2) { return (long)arg1 >= arg2; } public static bool operator <=(ValueTuple arg1, int arg2) { return (long)arg1 <= arg2; } public override bool Equals(object obj) { return base.Equals(obj); } public override int GetHashCode() { return base.GetHashCode(); } } } "; var expectedOutput = @"{1, 3} 4 {2, 4} {5, 5} {1, 3} -4 False -4 {2, 4} {1, 3} True False 5 3 12 2 1 0 15 0 8 2 False True True False True False "; var lib = CreateCompilationWithMscorlib40(tuple, options: TestOptions.ReleaseDll); lib.VerifyDiagnostics(); var consumer1 = CreateCompilationWithMscorlib40(source, options: TestOptions.ReleaseExe, references: new[] { lib.ToMetadataReference() }); CompileAndVerify(consumer1, expectedOutput: expectedOutput).VerifyDiagnostics(); var consumer2 = CreateCompilationWithMscorlib40(source, options: TestOptions.ReleaseExe, references: new[] { lib.EmitToImageReference() }); CompileAndVerify(consumer2, expectedOutput: expectedOutput).VerifyDiagnostics(); } [Fact] public void UnifyUnderlyingWithTuple_09() { var source = @" using System; using System.Collections.Generic; class C { static void Main() { var x = (1, 3); string s = x; System.Console.WriteLine(s); System.Console.WriteLine((long)x); (int, string) y = new KeyValuePair(2, ""4""); System.Console.WriteLine(y); System.Console.WriteLine((ValueTuple)""5""); System.Console.WriteLine(+x); System.Console.WriteLine(-x); System.Console.WriteLine(!x); System.Console.WriteLine(~x); System.Console.WriteLine(++x); System.Console.WriteLine(--x); System.Console.WriteLine(x ? true : false); System.Console.WriteLine(!x ? true : false); System.Console.WriteLine(x + 1); System.Console.WriteLine(x - 1); System.Console.WriteLine(x * 3); System.Console.WriteLine(x / 2); System.Console.WriteLine(x % 3); System.Console.WriteLine(x & 3); System.Console.WriteLine(x | 15); System.Console.WriteLine(x ^ 4); System.Console.WriteLine(x << 1); System.Console.WriteLine(x >> 1); System.Console.WriteLine(x == 1); System.Console.WriteLine(x != 1); System.Console.WriteLine(x > 1); System.Console.WriteLine(x < 1); System.Console.WriteLine(x >= 1); System.Console.WriteLine(x <= 1); } } "; var tuple = @" namespace System { // struct with two values public struct ValueTuple { public T1 Item1; public T2 Item2; public ValueTuple(T1 item1, T2 item2) { this.Item1 = item1; this.Item2 = item2; } public override string ToString() { return '{' + Item1?.ToString() + "", "" + Item2?.ToString() + '}'; } public static implicit operator string((T1, T2) arg) { return arg.ToString(); } public static explicit operator long((T1, T2) arg) { return ((long)(int)(object)arg.Item1 + (long)(int)(object)arg.Item2); } public static implicit operator (T1, T2)(System.Collections.Generic.KeyValuePair arg) { return (arg.Key, arg.Value); } public static explicit operator (T1, T2)(string arg) { return ((T1)(object)arg, (T2)(object)arg); } public static (T1, T2) operator +((T1, T2) arg) { return arg; } public static long operator -((T1, T2) arg) { return -(long)arg; } public static bool operator !((T1, T2) arg) { return (long)arg == 0; } public static long operator ~((T1, T2) arg) { return -(long)arg; } public static (T1, T2) operator ++((T1, T2) arg) { return new ValueTuple((T1)(object)((int)(object)arg.Item1+1), (T2)(object)((int)(object)arg.Item2+1)); } public static (T1, T2) operator --((T1, T2) arg) { return new ValueTuple((T1)(object)((int)(object)arg.Item1 - 1), (T2)(object)((int)(object)arg.Item2 - 1)); } public static bool operator true((T1, T2) arg) { return (long)arg != 0; } public static bool operator false((T1, T2) arg) { return (long)arg == 0; } public static long operator + ((T1, T2) arg1, int arg2) { return (long)arg1 + arg2; } public static long operator -((T1, T2) arg1, int arg2) { return (long)arg1 - arg2; } public static long operator *((T1, T2) arg1, int arg2) { return (long)arg1 * arg2; } public static long operator /((T1, T2) arg1, int arg2) { return (long)arg1 / arg2; } public static long operator %((T1, T2) arg1, int arg2) { return (long)arg1 % arg2; } public static long operator &((T1, T2) arg1, int arg2) { return (long)arg1 & arg2; } public static long operator |((T1, T2) arg1, long arg2) { return (long)arg1 | arg2; } public static long operator ^((T1, T2) arg1, int arg2) { return (long)arg1 ^ arg2; } public static long operator <<((T1, T2) arg1, int arg2) { return (long)arg1 << arg2; } public static long operator >>((T1, T2) arg1, int arg2) { return (long)arg1 >> arg2; } public static bool operator ==((T1, T2) arg1, int arg2) { return (long)arg1 == arg2; } public static bool operator !=((T1, T2) arg1, int arg2) { return (long)arg1 != arg2; } public static bool operator >((T1, T2) arg1, int arg2) { return (long)arg1 > arg2; } public static bool operator <((T1, T2) arg1, int arg2) { return (long)arg1 < arg2; } public static bool operator >=((T1, T2) arg1, int arg2) { return (long)arg1 >= arg2; } public static bool operator <=((T1, T2) arg1, int arg2) { return (long)arg1 <= arg2; } public override bool Equals(object obj) { return base.Equals(obj); } public override int GetHashCode() { return base.GetHashCode(); } } } "; var expectedOutput = @"{1, 3} 4 {2, 4} {5, 5} {1, 3} -4 False -4 {2, 4} {1, 3} True False 5 3 12 2 1 0 15 0 8 2 False True True False True False "; var lib = CreateCompilationWithMscorlib40(tuple, options: TestOptions.ReleaseDll); lib.VerifyDiagnostics(); var consumer1 = CreateCompilationWithMscorlib40(source, options: TestOptions.ReleaseExe, references: new[] { lib.ToMetadataReference() }); CompileAndVerify(consumer1, expectedOutput: expectedOutput).VerifyDiagnostics(); var consumer2 = CreateCompilationWithMscorlib40(source, options: TestOptions.ReleaseExe, references: new[] { lib.EmitToImageReference() }); CompileAndVerify(consumer2, expectedOutput: expectedOutput).VerifyDiagnostics(); } [Fact] [WorkItem(11530, "https://github.com/dotnet/roslyn/issues/11530")] public void UnifyUnderlyingWithTuple_10() { var source = @" using System.Collections.Generic; class Test { static void Main() { var a = new KeyValuePair(1, 2); (int, long) b = a; System.Console.WriteLine(b.Item1); System.Console.WriteLine(b.Item2); b.Item1++; b.Item2++; a = b; System.Console.WriteLine(a.Key); System.Console.WriteLine(a.Value); } } namespace System { public struct ValueTuple { public T1 Item1; public T2 Item2; public ValueTuple(T1 item1, T2 item2) { this.Item1 = item1; this.Item2 = item2; } public static implicit operator KeyValuePair(ValueTuple tuple) { T1 k; T2 v; (k, v) = tuple; return new KeyValuePair(k, v); } public static implicit operator ValueTuple(KeyValuePair kvp) { return (kvp.Key, kvp.Value); } } } "; var comp = CompileAndVerify(source, parseOptions: TestOptions.Regular, options: TestOptions.ReleaseExe, expectedOutput: @"1 2 2 3"); } [Fact] [WorkItem(11986, "https://github.com/dotnet/roslyn/issues/11986")] public void UnifyUnderlyingWithTuple_11() { var source = @" using System.Collections.Generic; class Test { static void Main() { var a = (1, 2); System.Console.WriteLine((int)a); System.Console.WriteLine((long)a); System.Console.WriteLine((string)a); System.Console.WriteLine((double)a); } } namespace System { public struct ValueTuple { public T1 Item1; public T2 Item2; public ValueTuple(T1 item1, T2 item2) { this.Item1 = item1; this.Item2 = item2; } public static explicit operator int((T1, T2)? source) { return 1; } public static explicit operator long(Nullable<(T1, T2)> source) { return 2; } public static explicit operator string(Nullable> source) { return ""3""; } public static explicit operator double(ValueTuple? source) { return 4; } } } "; var comp = CompileAndVerify(source, parseOptions: TestOptions.Regular, options: TestOptions.ReleaseExe, expectedOutput: @"1 2 3 4"); } [Fact] public void UnifyUnderlyingWithTuple_12() { var source = @" using System; using System.Collections.Generic; class C { static void Main() { (int, int)? x = (1, 3); string s = x; System.Console.WriteLine(s); System.Console.WriteLine((long)x); (int, string)? y = new KeyValuePair(2, ""4""); System.Console.WriteLine(y); System.Console.WriteLine((ValueTuple)""5""); System.Console.WriteLine(+x); System.Console.WriteLine(-x); System.Console.WriteLine(!x); System.Console.WriteLine(~x); System.Console.WriteLine(++x); System.Console.WriteLine(--x); System.Console.WriteLine(x ? true : false); System.Console.WriteLine(!x ? true : false); System.Console.WriteLine(x + 1); System.Console.WriteLine(x - 1); System.Console.WriteLine(x * 3); System.Console.WriteLine(x / 2); System.Console.WriteLine(x % 3); System.Console.WriteLine(x & 3); System.Console.WriteLine(x | 15); System.Console.WriteLine(x ^ 4); System.Console.WriteLine(x << 1); System.Console.WriteLine(x >> 1); System.Console.WriteLine(x == 1); System.Console.WriteLine(x != 1); System.Console.WriteLine(x > 1); System.Console.WriteLine(x < 1); System.Console.WriteLine(x >= 1); System.Console.WriteLine(x <= 1); } } "; var tuple = @" namespace System { // struct with two values public struct ValueTuple { public T1 Item1; public T2 Item2; public ValueTuple(T1 item1, T2 item2) { this.Item1 = item1; this.Item2 = item2; } public override string ToString() { return '{' + Item1?.ToString() + "", "" + Item2?.ToString() + '}'; } public static implicit operator string(ValueTuple? arg) { return arg.ToString(); } public static explicit operator long(ValueTuple? arg) { return ((long)(int)(object)arg.Value.Item1 + (long)(int)(object)arg.Value.Item2); } public static implicit operator ValueTuple?(System.Collections.Generic.KeyValuePair arg) { return new ValueTuple(arg.Key, arg.Value); } public static explicit operator ValueTuple?(string arg) { return new ValueTuple((T1)(object)arg, (T2)(object)arg); } public static ValueTuple? operator +(ValueTuple? arg) { return arg; } public static long operator -(ValueTuple? arg) { return -(long)arg; } public static bool operator !(ValueTuple? arg) { return (long)arg == 0; } public static long operator ~(ValueTuple? arg) { return -(long)arg; } public static ValueTuple? operator ++(ValueTuple? arg) { return new ValueTuple((T1)(object)((int)(object)arg.Value.Item1+1), (T2)(object)((int)(object)arg.Value.Item2+1)); } public static ValueTuple? operator --(ValueTuple? arg) { return new ValueTuple((T1)(object)((int)(object)arg.Value.Item1 - 1), (T2)(object)((int)(object)arg.Value.Item2 - 1)); } public static bool operator true(ValueTuple? arg) { return (long)arg != 0; } public static bool operator false(ValueTuple? arg) { return (long)arg == 0; } public static long operator + (ValueTuple? arg1, int arg2) { return (long)arg1 + arg2; } public static long operator -(ValueTuple? arg1, int arg2) { return (long)arg1 - arg2; } public static long operator *(ValueTuple? arg1, int arg2) { return (long)arg1 * arg2; } public static long operator /(ValueTuple? arg1, int arg2) { return (long)arg1 / arg2; } public static long operator %(ValueTuple? arg1, int arg2) { return (long)arg1 % arg2; } public static long operator &(ValueTuple? arg1, int arg2) { return (long)arg1 & arg2; } public static long operator |(ValueTuple? arg1, long arg2) { return (long)arg1 | arg2; } public static long operator ^(ValueTuple? arg1, int arg2) { return (long)arg1 ^ arg2; } public static long operator <<(ValueTuple? arg1, int arg2) { return (long)arg1 << arg2; } public static long operator >>(ValueTuple? arg1, int arg2) { return (long)arg1 >> arg2; } public static bool operator ==(ValueTuple? arg1, int arg2) { return (long)arg1 == arg2; } public static bool operator !=(ValueTuple? arg1, int arg2) { return (long)arg1 != arg2; } public static bool operator >(ValueTuple? arg1, int arg2) { return (long)arg1 > arg2; } public static bool operator <(ValueTuple? arg1, int arg2) { return (long)arg1 < arg2; } public static bool operator >=(ValueTuple? arg1, int arg2) { return (long)arg1 >= arg2; } public static bool operator <=(ValueTuple? arg1, int arg2) { return (long)arg1 <= arg2; } public override bool Equals(object obj) { return base.Equals(obj); } public override int GetHashCode() { return base.GetHashCode(); } } } "; var expectedOutput = @"{1, 3} 4 {2, 4} {5, 5} {1, 3} -4 False -4 {2, 4} {1, 3} True False 5 3 12 2 1 0 15 0 8 2 False True True False True False "; var lib = CreateCompilationWithMscorlib46(tuple, options: TestOptions.ReleaseDll); lib.VerifyDiagnostics(); var consumer1 = CreateCompilationWithMscorlib46(source, options: TestOptions.ReleaseExe, references: new[] { lib.ToMetadataReference() }); CompileAndVerify(consumer1, expectedOutput: expectedOutput).VerifyDiagnostics(); var consumer2 = CreateCompilationWithMscorlib46(source, options: TestOptions.ReleaseExe, references: new[] { lib.EmitToImageReference() }); CompileAndVerify(consumer2, expectedOutput: expectedOutput).VerifyDiagnostics(); } [Fact] public void UnifyUnderlyingWithTuple_13() { var source = @" using System; using System.Collections.Generic; class C { static void Main() { (int, int)? x = (1, 3); string s = x; System.Console.WriteLine(s); System.Console.WriteLine((long)x); (int, string)? y = new KeyValuePair(2, ""4""); System.Console.WriteLine(y); System.Console.WriteLine((ValueTuple)""5""); System.Console.WriteLine(+x); System.Console.WriteLine(-x); System.Console.WriteLine(!x); System.Console.WriteLine(~x); System.Console.WriteLine(++x); System.Console.WriteLine(--x); System.Console.WriteLine(x ? true : false); System.Console.WriteLine(!x ? true : false); System.Console.WriteLine(x + 1); System.Console.WriteLine(x - 1); System.Console.WriteLine(x * 3); System.Console.WriteLine(x / 2); System.Console.WriteLine(x % 3); System.Console.WriteLine(x & 3); System.Console.WriteLine(x | 15); System.Console.WriteLine(x ^ 4); System.Console.WriteLine(x << 1); System.Console.WriteLine(x >> 1); System.Console.WriteLine(x == 1); System.Console.WriteLine(x != 1); System.Console.WriteLine(x > 1); System.Console.WriteLine(x < 1); System.Console.WriteLine(x >= 1); System.Console.WriteLine(x <= 1); } } "; var tuple = @" namespace System { // struct with two values public struct ValueTuple { public T1 Item1; public T2 Item2; public ValueTuple(T1 item1, T2 item2) { this.Item1 = item1; this.Item2 = item2; } public override string ToString() { return '{' + Item1?.ToString() + "", "" + Item2?.ToString() + '}'; } public static implicit operator string((T1, T2)? arg) { return arg.ToString(); } public static explicit operator long((T1, T2)? arg) { return ((long)(int)(object)arg.Value.Item1 + (long)(int)(object)arg.Value.Item2); } public static implicit operator (T1, T2)?(System.Collections.Generic.KeyValuePair arg) { return (arg.Key, arg.Value); } public static explicit operator (T1, T2)?(string arg) { return ((T1)(object)arg, (T2)(object)arg); } public static (T1, T2)? operator +((T1, T2)? arg) { return arg; } public static long operator -((T1, T2)? arg) { return -(long)arg; } public static bool operator !((T1, T2)? arg) { return (long)arg == 0; } public static long operator ~((T1, T2)? arg) { return -(long)arg; } public static (T1, T2)? operator ++((T1, T2)? arg) { return new ValueTuple((T1)(object)((int)(object)arg.Value.Item1+1), (T2)(object)((int)(object)arg.Value.Item2+1)); } public static (T1, T2)? operator --((T1, T2)? arg) { return new ValueTuple((T1)(object)((int)(object)arg.Value.Item1 - 1), (T2)(object)((int)(object)arg.Value.Item2 - 1)); } public static bool operator true((T1, T2)? arg) { return (long)arg != 0; } public static bool operator false((T1, T2)? arg) { return (long)arg == 0; } public static long operator + ((T1, T2)? arg1, int arg2) { return (long)arg1 + arg2; } public static long operator -((T1, T2)? arg1, int arg2) { return (long)arg1 - arg2; } public static long operator *((T1, T2)? arg1, int arg2) { return (long)arg1 * arg2; } public static long operator /((T1, T2)? arg1, int arg2) { return (long)arg1 / arg2; } public static long operator %((T1, T2)? arg1, int arg2) { return (long)arg1 % arg2; } public static long operator &((T1, T2)? arg1, int arg2) { return (long)arg1 & arg2; } public static long operator |((T1, T2)? arg1, long arg2) { return (long)arg1 | arg2; } public static long operator ^((T1, T2)? arg1, int arg2) { return (long)arg1 ^ arg2; } public static long operator <<((T1, T2)? arg1, int arg2) { return (long)arg1 << arg2; } public static long operator >>((T1, T2)? arg1, int arg2) { return (long)arg1 >> arg2; } public static bool operator ==((T1, T2)? arg1, int arg2) { return (long)arg1 == arg2; } public static bool operator !=((T1, T2)? arg1, int arg2) { return (long)arg1 != arg2; } public static bool operator >((T1, T2)? arg1, int arg2) { return (long)arg1 > arg2; } public static bool operator <((T1, T2)? arg1, int arg2) { return (long)arg1 < arg2; } public static bool operator >=((T1, T2)? arg1, int arg2) { return (long)arg1 >= arg2; } public static bool operator <=((T1, T2)? arg1, int arg2) { return (long)arg1 <= arg2; } public override bool Equals(object obj) { return base.Equals(obj); } public override int GetHashCode() { return base.GetHashCode(); } } } "; var expectedOutput = @"{1, 3} 4 {2, 4} {5, 5} {1, 3} -4 False -4 {2, 4} {1, 3} True False 5 3 12 2 1 0 15 0 8 2 False True True False True False "; var lib = CreateCompilationWithMscorlib46(tuple, options: TestOptions.ReleaseDll); lib.VerifyDiagnostics(); var consumer1 = CreateCompilationWithMscorlib46(source, options: TestOptions.ReleaseExe, references: new[] { lib.ToMetadataReference() }); CompileAndVerify(consumer1, expectedOutput: expectedOutput).VerifyDiagnostics(); var consumer2 = CreateCompilationWithMscorlib46(source, options: TestOptions.ReleaseExe, references: new[] { lib.EmitToImageReference() }); CompileAndVerify(consumer2, expectedOutput: expectedOutput).VerifyDiagnostics(); } [Fact] public void ConstructorInvocation_01() { var source = @" using System; using System.Collections.Generic; class C { static void Main() { var v1 = new ValueTuple(1, 2); System.Console.WriteLine(v1.ToString()); var v2 = new ValueTuple> (10, 20, 30, 40, 50, 60, 70, new ValueTuple(80, 90)); System.Console.WriteLine(v2.ToString()); var v3 = new ValueTuple (100, 200, 300, 400, 500, 600, 700, (800, 900)); System.Console.WriteLine(v3.ToString()); } } "; var comp = CompileAndVerify(source, options: TestOptions.ReleaseExe, expectedOutput: @"(1, 2) (10, 20, 30, 40, 50, 60, 70, 80, 90) (100, 200, 300, 400, 500, 600, 700, 800, 900) "); } [Fact] public void PropertiesAsMembers_01() { var source = @" using System; class C { static void Main() { var v1 = M1(); v1.P1 = 33; System.Console.WriteLine(v1.P1); System.Console.WriteLine(v1[-1, -2]); } static (int, int) M1() { return (1, 11); } static (int a2, int b2) M2() { return (2, 22); } static (int, int) M3() { return (6, 66); } } namespace System { public struct ValueTuple { public T1 Item1; public T2 Item2; public ValueTuple(T1 item1, T2 item2) { this.Item1 = item1; this.Item2 = item2; this.P1 = 0; } public override string ToString() { return '{' + Item1?.ToString() + "", "" + Item2?.ToString() + '}'; } public int P1 {get; set;} public int this[int a, int b] { get { return 44; } } } } "; var comp = CompileAndVerify(source, expectedOutput: @"33 44"); var c = ((CSharpCompilation)comp.Compilation).GetTypeByMetadataName("C"); var m1Tuple = (NamedTypeSymbol)c.GetMember("M1").ReturnType; AssertTestDisplayString(m1Tuple.GetMembers(), "System.Int32 (System.Int32, System.Int32).Item1", "System.Int32 (System.Int32, System.Int32).Item2", "(System.Int32, System.Int32)..ctor(System.Int32 item1, System.Int32 item2)", "System.String (System.Int32, System.Int32).ToString()", "System.Int32 (System.Int32, System.Int32).k__BackingField", "System.Int32 (System.Int32, System.Int32).P1 { readonly get; set; }", "readonly System.Int32 (System.Int32, System.Int32).P1.get", "void (System.Int32, System.Int32).P1.set", "System.Int32 (System.Int32, System.Int32).this[System.Int32 a, System.Int32 b] { get; }", "System.Int32 (System.Int32, System.Int32).this[System.Int32 a, System.Int32 b].get", "(System.Int32, System.Int32)..ctor()"); AssertTupleTypeEquality(m1Tuple); Assert.Equal(new string[] { "Item1", "Item2", ".ctor", "ToString", "k__BackingField", "P1", "get_P1", "set_P1", "this[]", "get_Item"}, m1Tuple.MemberNames.ToArray()); Assert.Equal("System.Int32 (System.Int32, System.Int32).P1 { readonly get; set; }", m1Tuple.GetEarlyAttributeDecodingMembers("P1").Single().ToTestDisplayString()); var m2Tuple = (NamedTypeSymbol)c.GetMember("M2").ReturnType; var m3Tuple = (NamedTypeSymbol)c.GetMember("M3").ReturnType; AssertTupleTypeMembersEquality(m1Tuple, m2Tuple); AssertTupleTypeMembersEquality(m1Tuple, m3Tuple); var m1P1 = m1Tuple.GetMember("P1"); var m1P1Get = m1Tuple.GetMember("get_P1"); var m1P1Set = m1Tuple.GetMember("set_P1"); Assert.Equal(SymbolKind.Property, m1P1.Kind); Assert.NotSame(m1P1, m1P1.OriginalDefinition); Assert.True(m1P1.Equals(m1P1)); Assert.Equal("System.Int32 (System.Int32, System.Int32).P1 { readonly get; set; }", m1P1.ToTestDisplayString()); Assert.Same(m1Tuple, m1P1.ContainingSymbol); Assert.True(m1P1.TypeWithAnnotations.CustomModifiers.IsEmpty); Assert.True(m1P1.GetAttributes().IsEmpty); Assert.Null(m1P1.GetUseSiteDiagnostic()); Assert.False(m1P1.IsImplicitlyDeclared); Assert.True(m1P1.Parameters.IsEmpty); Assert.True(m1P1Get.Equals(m1P1.GetMethod, TypeCompareKind.ConsiderEverything)); Assert.True(m1P1Set.Equals(m1P1.SetMethod, TypeCompareKind.ConsiderEverything)); Assert.False(m1P1.IsExplicitInterfaceImplementation); Assert.True(m1P1.ExplicitInterfaceImplementations.IsEmpty); Assert.False(m1P1.IsIndexer); Assert.Null(m1P1.OverriddenProperty); Assert.True(m1P1.Equals(m1P1Get.AssociatedSymbol, TypeCompareKind.ConsiderEverything)); Assert.False(m1P1Get.IsImplicitlyDeclared); Assert.True(m1P1.Equals(m1P1Set.AssociatedSymbol, TypeCompareKind.ConsiderEverything)); Assert.False(m1P1Set.IsImplicitlyDeclared); var m1P1BackingField = m1Tuple.GetMember("k__BackingField"); Assert.True(m1P1.Equals(m1P1BackingField.AssociatedSymbol, TypeCompareKind.ConsiderEverything)); Assert.True(m1P1BackingField.IsImplicitlyDeclared); Assert.True(m1P1BackingField.TupleUnderlyingField.IsImplicitlyDeclared); var m1this = m1Tuple.GetMember("this[]"); var m1thisGet = m1Tuple.GetMember("get_Item"); Assert.Equal(SymbolKind.Property, m1this.Kind); Assert.NotSame(m1this, m1this.OriginalDefinition); Assert.True(m1this.Equals(m1this)); Assert.Same(m1Tuple, m1this.ContainingSymbol); Assert.True(m1this.TypeWithAnnotations.CustomModifiers.IsEmpty); Assert.True(m1this.GetAttributes().IsEmpty); Assert.Null(m1this.GetUseSiteDiagnostic()); Assert.False(m1this.IsImplicitlyDeclared); Assert.Equal(2, m1this.Parameters.Length); Assert.True(m1thisGet.Equals(m1this.GetMethod, TypeCompareKind.ConsiderEverything)); Assert.Null(m1this.SetMethod); Assert.False(m1this.IsExplicitInterfaceImplementation); Assert.True(m1this.ExplicitInterfaceImplementations.IsEmpty); Assert.True(m1this.IsIndexer); Assert.Null(m1this.OverriddenProperty); Assert.False(m1this.IsDefinition); Assert.False(m1thisGet.IsImplicitlyDeclared); } private class SyntaxReferenceEqualityComparer : IEqualityComparer { public static readonly SyntaxReferenceEqualityComparer Instance = new SyntaxReferenceEqualityComparer(); private SyntaxReferenceEqualityComparer() { } public bool Equals(SyntaxReference x, SyntaxReference y) { return x.GetSyntax().Equals(y.GetSyntax()); } public int GetHashCode(SyntaxReference obj) { return obj.GetHashCode(); } } [Fact] public void EventsAsMembers_01() { var source = @" using System; class C { static void Main() { var v1 = M1(); System.Action d1 = (int i1) => System.Console.WriteLine(i1); v1.Test(v1, d1); System.Action d2 = (long i2) => System.Console.WriteLine(i2); v1.E1 += d1; v1.RaiseE1(); v1.E1 -= d1; v1.RaiseE1(); v1.E2 += d2; v1.RaiseE2(); v1.E2 -= d2; v1.RaiseE2(); } static (int, long) M1() { return (1, 11); } static (int a2, long b2) M2() { return (2, 22); } static (int, long) M3() { return (6, 66); } } namespace System { public struct ValueTuple { public T1 Item1; public T2 Item2; public ValueTuple(T1 item1, T2 item2) { this.Item1 = item1; this.Item2 = item2; this.E1 = null; this._e2 = null; } public event System.Action E1; private System.Action _e2; public event System.Action E2 { add { _e2 += value; } remove { _e2 -= value; } } public void RaiseE1() { System.Console.WriteLine(""-""); if (E1 == null) { System.Console.WriteLine(""null""); } else { E1(Item1); } System.Console.WriteLine(""-""); } public void RaiseE2() { System.Console.WriteLine(""--""); if (_e2 == null) { System.Console.WriteLine(""null""); } else { _e2(Item2); } System.Console.WriteLine(""--""); } public void Test((T1, T2) val, System.Action d) { val.E1 += d; System.Console.WriteLine(val.E1); val.E1(val.Item1); val.E1 -= d; System.Console.WriteLine(val.E1 == null); } } } " + tupleattributes_cs; var comp = CompileAndVerify(source, expectedOutput: @"System.Action`1[System.Int32] 1 True - 1 - - null - -- 11 -- -- null --"); var c = ((CSharpCompilation)comp.Compilation).GetTypeByMetadataName("C"); var m1Tuple = (NamedTypeSymbol)c.GetMember("M1").ReturnType; AssertTestDisplayString(m1Tuple.GetMembers(), "System.Int32 (System.Int32, System.Int64).Item1", "System.Int64 (System.Int32, System.Int64).Item2", "(System.Int32, System.Int64)..ctor(System.Int32 item1, System.Int64 item2)", "void (System.Int32, System.Int64).E1.add", "void (System.Int32, System.Int64).E1.remove", "event System.Action (System.Int32, System.Int64).E1", "System.Action (System.Int32, System.Int64)._e2", "event System.Action (System.Int32, System.Int64).E2", "void (System.Int32, System.Int64).E2.add", "void (System.Int32, System.Int64).E2.remove", "void (System.Int32, System.Int64).RaiseE1()", "void (System.Int32, System.Int64).RaiseE2()", "void (System.Int32, System.Int64).Test((System.Int32, System.Int64) val, System.Action d)", "(System.Int32, System.Int64)..ctor()"); AssertTupleTypeEquality(m1Tuple); Assert.Equal(new string[] { "Item1", "Item2", ".ctor", "add_E1", "remove_E1", "E1", "_e2", "E2", "add_E2", "remove_E2", "RaiseE1", "RaiseE2", "Test" }, m1Tuple.MemberNames.ToArray()); Assert.Equal("event System.Action (System.Int32, System.Int64).E1", m1Tuple.GetEarlyAttributeDecodingMembers("E1").Single().ToTestDisplayString()); Assert.Equal("event System.Action (System.Int32, System.Int64).E2", m1Tuple.GetEarlyAttributeDecodingMembers("E2").Single().ToTestDisplayString()); var m2Tuple = (NamedTypeSymbol)c.GetMember("M2").ReturnType; var m3Tuple = (NamedTypeSymbol)c.GetMember("M3").ReturnType; AssertTupleTypeMembersEquality(m1Tuple, m2Tuple); AssertTupleTypeMembersEquality(m1Tuple, m3Tuple); var m1E1 = m1Tuple.GetMember("E1"); var m1E1Add = m1Tuple.GetMember("add_E1"); var m1E1Remove = m1Tuple.GetMember("remove_E1"); Assert.Equal(SymbolKind.Event, m1E1.Kind); Assert.NotSame(m1E1, m1E1.OriginalDefinition); Assert.Equal("event System.Action (System.Int32, System.Int64).E1", m1E1.ToTestDisplayString()); Assert.Equal("event System.Action (T1, T2).E1", m1E1.OriginalDefinition.ToTestDisplayString()); Assert.True(m1E1.Equals(m1E1)); Assert.Equal("event System.Action (System.Int32, System.Int64).E1", m1E1.ToTestDisplayString()); Assert.Same(m1Tuple, m1E1.ContainingSymbol); Assert.True(m1E1.GetAttributes().IsEmpty); Assert.Null(m1E1.GetUseSiteDiagnostic()); Assert.True(m1E1.DeclaringSyntaxReferences.SequenceEqual(m1E1.DeclaringSyntaxReferences, SyntaxReferenceEqualityComparer.Instance)); Assert.False(m1E1.IsImplicitlyDeclared); Assert.True(m1E1Add.Equals(m1E1.AddMethod, TypeCompareKind.ConsiderEverything)); Assert.True(m1E1Remove.Equals(m1E1.RemoveMethod, TypeCompareKind.ConsiderEverything)); Assert.False(m1E1.IsExplicitInterfaceImplementation); Assert.True(m1E1.ExplicitInterfaceImplementations.IsEmpty); Assert.Null(m1E1.OverriddenEvent); Assert.True(m1E1.Equals(m1E1Add.AssociatedSymbol, TypeCompareKind.ConsiderEverything)); Assert.True(m1E1Add.IsImplicitlyDeclared); Assert.True(m1E1.Equals(m1E1Remove.AssociatedSymbol, TypeCompareKind.ConsiderEverything)); Assert.True(m1E1Remove.IsImplicitlyDeclared); var m1E1BackingField = m1E1.AssociatedField; Assert.Equal("System.Action (System.Int32, System.Int64).E1", m1E1BackingField.ToTestDisplayString()); Assert.Same(m1Tuple, m1E1BackingField.ContainingSymbol); Assert.True(m1E1.Equals(m1E1BackingField.AssociatedSymbol, TypeCompareKind.ConsiderEverything)); Assert.True(m1E1BackingField.IsImplicitlyDeclared); Assert.True(m1E1BackingField.TupleUnderlyingField.IsImplicitlyDeclared); var m1E2 = m1Tuple.GetMember("E2"); var m1E2Add = m1Tuple.GetMember("add_E2"); var m1E2Remove = m1Tuple.GetMember("remove_E2"); Assert.Equal(SymbolKind.Event, m1E2.Kind); Assert.Equal("event System.Action (System.Int32, System.Int64).E2", m1E2.ToTestDisplayString()); Assert.Equal("event System.Action (T1, T2).E2", m1E2.OriginalDefinition.ToTestDisplayString()); Assert.Same(m1Tuple, m1E2.ContainingSymbol); Assert.True(m1E2.GetAttributes().IsEmpty); Assert.Null(m1E2.GetUseSiteDiagnostic()); Assert.True(m1E2.DeclaringSyntaxReferences.SequenceEqual(m1E2.DeclaringSyntaxReferences, SyntaxReferenceEqualityComparer.Instance)); Assert.False(m1E2.IsImplicitlyDeclared); Assert.NotSame(m1E2Add, m1E2.AddMethod); Assert.True(m1E2Add.Equals(m1E2.AddMethod, TypeCompareKind.ConsiderEverything)); Assert.NotSame(m1E2Remove, m1E2.RemoveMethod); Assert.True(m1E2Remove.Equals(m1E2.RemoveMethod, TypeCompareKind.ConsiderEverything)); Assert.False(m1E2.IsExplicitInterfaceImplementation); Assert.True(m1E2.ExplicitInterfaceImplementations.IsEmpty); Assert.Null(m1E2.OverriddenEvent); Assert.Null(m1E2.AssociatedField); Assert.NotSame(m1E2, m1E2Add.AssociatedSymbol); Assert.True(m1E2.Equals(m1E2Add.AssociatedSymbol, TypeCompareKind.ConsiderEverything)); Assert.False(m1E2Add.IsImplicitlyDeclared); Assert.NotSame(m1E2, m1E2Remove.AssociatedSymbol); Assert.True(m1E2.Equals(m1E2Remove.AssociatedSymbol, TypeCompareKind.ConsiderEverything)); Assert.False(m1E2Remove.IsImplicitlyDeclared); } [Fact] public void EventsAsMembers_02() { var source = @" class C { static void Main() { var v1 = M1(); v1.E1(); } static (int, long) M1() { return (1, 11); } } namespace System { public struct ValueTuple { public T1 Item1; public T2 Item2; public ValueTuple(T1 item1, T2 item2) { this.Item1 = item1; this.Item2 = item2; this.E1 = null; this.E1(); } public event System.Action E1; } } "; var comp = CreateCompilation(source); comp.VerifyDiagnostics( // (7,12): error CS0070: The event '(int, long).E1' can only appear on the left hand side of += or -= (except when used from within the type '(int, long)') // v1.E1(); Diagnostic(ErrorCode.ERR_BadEventUsage, "E1").WithArguments("(int, long).E1", "(int, long)").WithLocation(7, 12) ); } [Fact] public void TupleTypeWithPatternIs() { var source = @" class C { void Match(object o) { if (o is (int, int) t) { } } } " + trivial2uple + tupleattributes_cs; var comp = CreateCompilation(source); comp.VerifyDiagnostics( // (6,19): error CS8652: The feature 'type pattern' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. // if (o is (int, int) t) { } Diagnostic(ErrorCode.ERR_FeatureInPreview, "int").WithArguments("type pattern").WithLocation(6, 19), // (6,24): error CS8652: The feature 'type pattern' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. // if (o is (int, int) t) { } Diagnostic(ErrorCode.ERR_FeatureInPreview, "int").WithArguments("type pattern").WithLocation(6, 24), // (6,18): error CS8129: No suitable 'Deconstruct' instance or extension method was found for type 'object', with 2 out parameters and a void return type. // if (o is (int, int) t) { } Diagnostic(ErrorCode.ERR_MissingDeconstruct, "(int, int)").WithArguments("object", "2").WithLocation(6, 18) ); } [Fact] public void TupleAsStatement() { var source = @" class C { void M(int x) { (x, x); } } " + trivial2uple + tupleattributes_cs; var comp = CreateCompilation(source); comp.VerifyDiagnostics( // (6,9): error CS0201: Only assignment, call, increment, decrement, await, and new object expressions can be used as a statement // (x, x); Diagnostic(ErrorCode.ERR_IllegalStatement, "(x, x)").WithLocation(6, 9) ); } [Fact] public void TupleTypeWithPatternIs2() { var source = @" class C { void Match(object o) { if (o is (int a, int b)) { } } } " + trivial2uple + tupleattributes_cs; var comp = CreateCompilation(source); comp.VerifyDiagnostics( // (6,18): error CS1061: 'object' does not contain a definition for 'Deconstruct' and no extension method 'Deconstruct' accepting a first argument of type 'object' could be found (are you missing a using directive or an assembly reference?) // if (o is (int a, int b)) { } Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "(int a, int b)").WithArguments("object", "Deconstruct").WithLocation(6, 18), // (6,18): error CS8129: No suitable Deconstruct instance or extension method was found for type 'object', with 2 out parameters and a void return type. // if (o is (int a, int b)) { } Diagnostic(ErrorCode.ERR_MissingDeconstruct, "(int a, int b)").WithArguments("object", "2").WithLocation(6, 18) ); } [Fact] public void TupleDeclarationWithPatternIs() { var source = @" class C { void Match(object o) { if (o is (1, 2)) { } } } " + trivial2uple + tupleattributes_cs; var comp = CreateCompilation(source); comp.VerifyDiagnostics( // (6,18): error CS1061: 'object' does not contain a definition for 'Deconstruct' and no extension method 'Deconstruct' accepting a first argument of type 'object' could be found (are you missing a using directive or an assembly reference?) // if (o is (1, 2)) { } Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "(1, 2)").WithArguments("object", "Deconstruct").WithLocation(6, 18), // (6,18): error CS8129: No suitable Deconstruct instance or extension method was found for type 'object', with 2 out parameters and a void return type. // if (o is (1, 2)) { } Diagnostic(ErrorCode.ERR_MissingDeconstruct, "(1, 2)").WithArguments("object", "2").WithLocation(6, 18) ); } [Fact] public void TupleTypeWithPatternSwitch() { var source = @" class C { void Match(object o) { switch(o) { case (int, int) tuple: return; } } } " + trivial2uple + tupleattributes_cs; var comp = CreateCompilation(source); comp.VerifyDiagnostics( // (7,19): error CS8652: The feature 'type pattern' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. // case (int, int) tuple: return; Diagnostic(ErrorCode.ERR_FeatureInPreview, "int").WithArguments("type pattern").WithLocation(7, 19), // (7,24): error CS8652: The feature 'type pattern' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. // case (int, int) tuple: return; Diagnostic(ErrorCode.ERR_FeatureInPreview, "int").WithArguments("type pattern").WithLocation(7, 24), // (7,18): error CS8129: No suitable 'Deconstruct' instance or extension method was found for type 'object', with 2 out parameters and a void return type. // case (int, int) tuple: return; Diagnostic(ErrorCode.ERR_MissingDeconstruct, "(int, int)").WithArguments("object", "2").WithLocation(7, 18) ); } [Fact] public void TupleLiteralWithPatternSwitch() { var source = @" class C { void Match(object o) { switch(o) { case (1, 1): return; } } } " + trivial2uple + tupleattributes_cs; var comp = CreateCompilation(source); comp.VerifyDiagnostics( // (7,18): error CS1061: 'object' does not contain a definition for 'Deconstruct' and no extension method 'Deconstruct' accepting a first argument of type 'object' could be found (are you missing a using directive or an assembly reference?) // case (1, 1): return; Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "(1, 1)").WithArguments("object", "Deconstruct").WithLocation(7, 18), // (7,18): error CS8129: No suitable Deconstruct instance or extension method was found for type 'object', with 2 out parameters and a void return type. // case (1, 1): return; Diagnostic(ErrorCode.ERR_MissingDeconstruct, "(1, 1)").WithArguments("object", "2").WithLocation(7, 18) ); } [Fact] public void TupleLiteralWithPatternSwitch2() { var source = @" class C { void Match(object o) { switch(o) { case (1, 1) t: return; } } } " + trivial2uple + tupleattributes_cs; var comp = CreateCompilation(source); comp.VerifyDiagnostics( // (7,18): error CS1061: 'object' does not contain a definition for 'Deconstruct' and no extension method 'Deconstruct' accepting a first argument of type 'object' could be found (are you missing a using directive or an assembly reference?) // case (1, 1) t: return; Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "(1, 1)").WithArguments("object", "Deconstruct").WithLocation(7, 18), // (7,18): error CS8129: No suitable Deconstruct instance or extension method was found for type 'object', with 2 out parameters and a void return type. // case (1, 1) t: return; Diagnostic(ErrorCode.ERR_MissingDeconstruct, "(1, 1)").WithArguments("object", "2").WithLocation(7, 18) ); } [Fact] public void TupleAsStatement2() { var source = @" class C { void M() { (1, 1); } } " + trivial2uple + tupleattributes_cs; var comp = CreateCompilation(source); comp.VerifyDiagnostics( // (6,9): error CS0201: Only assignment, call, increment, decrement, await, and new object expressions can be used as a statement // (1, 1); Diagnostic(ErrorCode.ERR_IllegalStatement, "(1, 1)").WithLocation(6, 9) ); } [Fact(Skip = "https://github.com/dotnet/roslyn/issues/11282 + https://github.com/dotnet/roslyn/issues/11291")] [WorkItem(11282, "https://github.com/dotnet/roslyn/issues/11282")] [WorkItem(11291, "https://github.com/dotnet/roslyn/issues/11291")] public void TargetTyping_01() { var source = @" class C { static void Main() { var x0 = new {tuple = (null, null)}; System.Console.WriteLine(x0.ToString()); System.ValueType x1 = (null, ""1""); } [TestAttribute((null, ""2""))] [TestAttribute((3, ""3""))] [TestAttribute(Val = (null, ""4""))] [TestAttribute(Val = (5, ""5""))] static void AttributeTarget1(){} async System.Threading.Tasks.Task AsyncTest() { await (null, ""6""); await (7, ""7""); } static void Default((int, string) val1 = (8, null), (int, string) val2 = (9, ""9""), (int, string) val3 = (""10"", ""10"")) {} [TestAttribute((""11"", ""11""))] [TestAttribute(Val = (""12"", ""12""))] static void AttributeTarget2(){} enum TestEnum { V1 = (13, null), V2 = (14, ""14""), V3 = (""15"", ""15""), } static void Test2() { var x = (16, (16 , null)); System.Console.WriteLine(x); var u = __refvalue((17, null), (int, string)); var v = __refvalue((18, ""18""), (int, string)); var w = __refvalue((""19"", ""19""), (int, string)); } } class TestAttribute : System.Attribute { public TestAttribute() {} public TestAttribute((int, string) val) {} public (int, string) Val {get; set;} } " + trivial2uple + tupleattributes_cs; var comp = CreateCompilation(source, references: new[] { SystemRef }); comp.VerifyDiagnostics( // (6,32): error CS8129: Type of the tuple element cannot be inferred from ''. // var x0 = new {tuple = (null, null)}; Diagnostic(ErrorCode.Unknown, "null").WithArguments("").WithLocation(6, 32), // (6,38): error CS8129: Type of the tuple element cannot be inferred from ''. // var x0 = new {tuple = (null, null)}; Diagnostic(ErrorCode.Unknown, "null").WithArguments("").WithLocation(6, 38), // (8,31): error CS8330: Cannot implicitly convert tuple expression to 'ValueType' // System.ValueType x1 = (null, "1"); Diagnostic(ErrorCode.Unknown, @"(null, ""1"")").WithArguments("System.ValueType").WithLocation(8, 31), // (11,20): error CS1503: Argument 1: cannot convert from '' to '(int, string)' // [TestAttribute((null, "2"))] Diagnostic(ErrorCode.ERR_BadArgType, @"(null, ""2"")").WithArguments("1", "", "(int, string)").WithLocation(11, 20), // (12,6): error CS0181: Attribute constructor parameter 'val' has type '(int, string)', which is not a valid attribute parameter type // [TestAttribute((3, "3"))] Diagnostic(ErrorCode.ERR_BadAttributeParamType, "TestAttribute").WithArguments("val", "(int, string)").WithLocation(12, 6), // (13,20): error CS0655: 'Val' is not a valid named attribute argument because it is not a valid attribute parameter type // [TestAttribute(Val = (null, "4"))] Diagnostic(ErrorCode.ERR_BadNamedAttributeArgumentType, "Val").WithArguments("Val").WithLocation(13, 20), // (14,20): error CS0655: 'Val' is not a valid named attribute argument because it is not a valid attribute parameter type // [TestAttribute(Val = (5, "5"))] Diagnostic(ErrorCode.ERR_BadNamedAttributeArgumentType, "Val").WithArguments("Val").WithLocation(14, 20), // (19,16): error CS8129: Type of the tuple element cannot be inferred from ''. // await (null, "6"); Diagnostic(ErrorCode.Unknown, "null").WithArguments("").WithLocation(19, 16), // (20,9): error CS1061: '(int, string)' does not contain a definition for 'GetAwaiter' and no extension method 'GetAwaiter' accepting a first argument of type '(int, string)' could be found (are you missing a using directive or an assembly reference?) // await (7, "7"); Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, @"await (7, ""7"")").WithArguments("(int, string)", "GetAwaiter").WithLocation(20, 9), // (23,46): error CS1736: Default parameter value for 'val1' must be a compile-time constant // static void Default((int, string) val1 = (8, null), Diagnostic(ErrorCode.ERR_DefaultValueMustBeConstant, "(8, null)").WithArguments("val1").WithLocation(23, 46), // (24,46): error CS1736: Default parameter value for 'val2' must be a compile-time constant // (int, string) val2 = (9, "9")) Diagnostic(ErrorCode.ERR_DefaultValueMustBeConstant, @"(9, ""9"")").WithArguments("val2").WithLocation(24, 46), // (25,46): error CS1736: Default parameter value for 'val3' must be a compile-time constant // (int, string) val3 = ("10", "10")) Diagnostic(ErrorCode.ERR_DefaultValueMustBeConstant, @"(""10"", ""10"")").WithArguments("val3").WithLocation(25, 46), // (28,20): error CS1503: Argument 1: cannot convert from '' to '(int, string)' // [TestAttribute(("11", "11"))] Diagnostic(ErrorCode.ERR_BadArgType, @"(""11"", ""11"")").WithArguments("1", "", "(int, string)").WithLocation(28, 20), // (29,20): error CS0655: 'Val' is not a valid named attribute argument because it is not a valid attribute parameter type // [TestAttribute(Val = ("12", "12"))] Diagnostic(ErrorCode.ERR_BadNamedAttributeArgumentType, "Val").WithArguments("Val").WithLocation(29, 20), // (34,14): error CS8330: Cannot implicitly convert tuple expression to 'int' // V1 = (13, null), Diagnostic(ErrorCode.Unknown, "(13, null)").WithArguments("int").WithLocation(34, 14), // (35,14): error CS8330: Cannot implicitly convert tuple expression to 'int' // V2 = (14, "14"), Diagnostic(ErrorCode.Unknown, @"(14, ""14"")").WithArguments("int").WithLocation(35, 14), // (36,14): error CS8330: Cannot implicitly convert tuple expression to 'int' // V3 = ("15", "15"), Diagnostic(ErrorCode.Unknown, @"(""15"", ""15"")").WithArguments("int").WithLocation(36, 14), // (41,28): error CS8129: Type of the tuple element cannot be inferred from ''. // var x = (16, (16 , null)); Diagnostic(ErrorCode.Unknown, "null").WithArguments("").WithLocation(41, 28), // (44,17): error CS8330: Cannot implicitly convert tuple expression to 'TypedReference' // var u = __refvalue((17, null), (int, string)); Diagnostic(ErrorCode.Unknown, "__refvalue((17, null), (int, string))").WithArguments("System.TypedReference").WithLocation(44, 17), // (45,17): error CS8330: Cannot implicitly convert tuple expression to 'TypedReference' // var v = __refvalue((18, "18"), (int, string)); Diagnostic(ErrorCode.Unknown, @"__refvalue((18, ""18""), (int, string))").WithArguments("System.TypedReference").WithLocation(45, 17), // (46,17): error CS8330: Cannot implicitly convert tuple expression to 'TypedReference' // var w = __refvalue(("19", "19"), (int, string)); Diagnostic(ErrorCode.Unknown, @"__refvalue((""19"", ""19""), (int, string))").WithArguments("System.TypedReference").WithLocation(46, 17) ); } [Fact] public void TargetTyping_02() { var source = @" class C { static void Print(T val) { System.Console.WriteLine($""{typeof(T)} - {val.ToString()}""); } static void Main() { var x0 = new {tuple = (1, ""s"")}; Print(x0.tuple); System.ValueType x1 = (2, ""s""); Print(x1); (int, (int, string)) x2 = (3, (3 , null)); Print(x2); } } " + trivial2uple + tupleattributes_cs; var comp = CreateCompilation(source, options: TestOptions.ReleaseExe); CompileAndVerify(comp, expectedOutput: @"System.ValueTuple`2[System.Int32,System.String] - {1, s} System.ValueType - {2, s} System.ValueTuple`2[System.Int32,System.ValueTuple`2[System.Int32,System.String]] - {3, {3, }} "); } [Fact] public void TargetTyping_03() { var source = @" class Class { void Method() { tuple = (1, ""hello""); } } " + trivial2uple + tupleattributes_cs; var comp = CreateCompilation(source); comp.VerifyDiagnostics( // (2,31): error CS0103: The name 'tuple' does not exist in the current context // class Class { void Method() { tuple = (1, "hello"); } } Diagnostic(ErrorCode.ERR_NameNotInContext, "tuple").WithArguments("tuple").WithLocation(2, 31) ); var tree = comp.SyntaxTrees.Single(); var model = comp.GetSemanticModel(tree, ignoreAccessibility: false); var nodes = tree.GetCompilationUnitRoot().DescendantNodes(); var node = nodes.OfType().Single(); Assert.Equal(@"(1, ""hello"")", node.ToString()); var typeInfo = model.GetTypeInfo(node); Assert.Equal("(System.Int32, System.String)", typeInfo.Type.ToTestDisplayString()); Assert.Equal("(System.Int32, System.String)", typeInfo.ConvertedType.ToTestDisplayString()); Assert.Equal(ConversionKind.Identity, model.GetConversion(node).Kind); } [Fact] public void MissingUnderlyingType() { string source = @" class C { void M() { (int, int) x = (1, 1); } } "; var tree = Parse(source, options: TestOptions.Regular); var comp = CreateCompilationWithMscorlib40(new[] { tree }); var model = comp.GetSemanticModel(tree, ignoreAccessibility: false); var nodes = tree.GetCompilationUnitRoot().DescendantNodes(); var x = nodes.OfType().First(); var xSymbol = (INamedTypeSymbol)((ILocalSymbol)model.GetDeclaredSymbol(x)).Type; Assert.True(xSymbol.IsTupleType); Assert.Equal("(System.Int32, System.Int32)[missing]", xSymbol.ToTestDisplayString()); Assert.Null(xSymbol.TupleUnderlyingType); Assert.True(xSymbol.IsErrorType()); Assert.True(xSymbol.IsReferenceType); AssertEx.Equal(new[] { "System.Int32 (System.Int32, System.Int32)[missing].Item1", "System.Int32 (System.Int32, System.Int32)[missing].Item2" }, ((ErrorTypeSymbol)((Symbols.PublicModel.ErrorTypeSymbol)xSymbol).UnderlyingSymbol).GetMembersUnordered().ToTestDisplayStrings().ToImmutableArray().Sort()); AssertEx.Equal("System.Int32 (System.Int32, System.Int32)[missing].Item1", ((NamedTypeSymbol)((Symbols.PublicModel.ErrorTypeSymbol)xSymbol).UnderlyingSymbol).GetMembers("Item1").Single().ToTestDisplayString()); } [Fact] public void MissingUnderlyingType_WithNames() { string source = @" class C { void M() { (int a, int b) x = (1, 1); } } "; var tree = Parse(source, options: TestOptions.Regular); var comp = CreateCompilationWithMscorlib40(new[] { tree }); var model = comp.GetSemanticModel(tree, ignoreAccessibility: false); var nodes = tree.GetCompilationUnitRoot().DescendantNodes(); var x = nodes.OfType().First(); var xSymbol = (INamedTypeSymbol)((ILocalSymbol)model.GetDeclaredSymbol(x)).Type; Assert.True(xSymbol.IsTupleType); Assert.Equal("(System.Int32 a, System.Int32 b)[missing]", xSymbol.ToTestDisplayString()); Assert.True(xSymbol.TupleUnderlyingType.IsErrorType()); Assert.True(xSymbol.IsErrorType()); Assert.True(xSymbol.IsReferenceType); AssertEx.Equal(new[] { "System.Int32 (System.Int32 a, System.Int32 b)[missing].a", "System.Int32 (System.Int32 a, System.Int32 b)[missing].b", "System.Int32 (System.Int32 a, System.Int32 b)[missing].Item1", "System.Int32 (System.Int32 a, System.Int32 b)[missing].Item2" }, ((ErrorTypeSymbol)((Symbols.PublicModel.ErrorTypeSymbol)xSymbol).UnderlyingSymbol).GetMembersUnordered().ToTestDisplayStrings().ToImmutableArray().Sort()); AssertEx.Equal("System.Int32 (System.Int32 a, System.Int32 b)[missing].Item1", ((NamedTypeSymbol)((Symbols.PublicModel.ErrorTypeSymbol)xSymbol).UnderlyingSymbol).GetMembers("Item1").Single().ToTestDisplayString()); AssertEx.Equal("System.Int32 (System.Int32 a, System.Int32 b)[missing].a", ((NamedTypeSymbol)((Symbols.PublicModel.ErrorTypeSymbol)xSymbol).UnderlyingSymbol).GetMembers("a").Single().ToTestDisplayString()); } [Fact, CompilerTrait(CompilerFeature.LocalFunctions)] public void LocalFunction() { var source = @" class C { static void Main() { (int, int) Local((int, int) x) { return x; } System.Console.WriteLine(Local((1, 2))); } } "; var comp = CompileAndVerify(source, expectedOutput: "(1, 2)"); comp.VerifyDiagnostics(); } [Fact] public void LocalFunctionWithNamedTuple() { var source = @" class C { static void Main() { (int a, int b) Local((int c, int d) x) { return x; } System.Console.WriteLine(Local((d: 1, c: 2)).b); } } "; var comp = CompileAndVerify(source, expectedOutput: "2"); comp.VerifyDiagnostics( // (7,41): warning CS8123: The tuple element name 'd' is ignored because a different name is specified by the target type '(int c, int d)'. // System.Console.WriteLine(Local((d: 1, c: 2)).b); Diagnostic(ErrorCode.WRN_TupleLiteralNameMismatch, "d: 1").WithArguments("d", "(int c, int d)").WithLocation(7, 41), // (7,47): warning CS8123: The tuple element name 'c' is ignored because a different name is specified by the target type '(int c, int d)'. // System.Console.WriteLine(Local((d: 1, c: 2)).b); Diagnostic(ErrorCode.WRN_TupleLiteralNameMismatch, "c: 2").WithArguments("c", "(int c, int d)").WithLocation(7, 47) ); } [Fact, CompilerTrait(CompilerFeature.LocalFunctions)] public void LocalFunctionWithLongTuple() { var source = @" class C { static void Main() { (int, string, int, string, int, string, int, string) Local((int, string, int, string, int, string, int, string) x) { return x; } System.Console.WriteLine(Local((1, ""Alice"", 2, ""Brenda"", 3, ""Chloe"", 4, ""Dylan""))); } } "; var comp = CompileAndVerify(source, expectedOutput: "(1, Alice, 2, Brenda, 3, Chloe, 4, Dylan)"); comp.VerifyDiagnostics(); } [Fact] public void TupleMembersInLambda() { var source = @" using System; class C { static Action action; static void Main() { var tuple = (a: 1, b: 2, c: 3, d: 4, e: 5, f: 6, g: 7, h: 8); action += () => { Console.Write(tuple.Item1 + "" "" + tuple.a + "" "" + tuple.Rest + "" "" + tuple.Item8 + "" "" + tuple.h); }; action(); } } "; var comp = CompileAndVerify(source, expectedOutput: "1 1 (8) 8 8"); comp.VerifyDiagnostics(); } [Fact] public void LongTupleConstructor() { var source = @" class C { void M() { var x = new (int, int, int, int, int, int, int, int)(1, 2, 3, 4, 5, 6, 7, 8); var y = new (int, int, int, int, int, int, int, int, int)(1, 2, 3, 4, 5, 6, 7, 8, 9); } } "; var comp = CreateCompilation(source); comp.VerifyDiagnostics( // (6,21): error CS8181: 'new' cannot be used with tuple type. Use a tuple literal expression instead. // var x = new (int, int, int, int, int, int, int, int)(1, 2, 3, 4, 5, 6, 7, 8); Diagnostic(ErrorCode.ERR_NewWithTupleTypeSyntax, "(int, int, int, int, int, int, int, int)").WithLocation(6, 21), // (7,21): error CS8181: 'new' cannot be used with tuple type. Use a tuple literal expression instead. // var y = new (int, int, int, int, int, int, int, int, int)(1, 2, 3, 4, 5, 6, 7, 8, 9); Diagnostic(ErrorCode.ERR_NewWithTupleTypeSyntax, "(int, int, int, int, int, int, int, int, int)").WithLocation(7, 21) ); } [Fact] public void TupleWithDynamicInSeparateCompilations() { var lib_cs = @" public class C { public static (dynamic, dynamic) M((dynamic, dynamic) x) { return x; } } "; var source = @" class D { static void Main() { var x = C.M((1, ""hello"")); x.Item1.DynamicMethod1(); x.Item2.DynamicMethod2(); } } "; var libComp = CreateCompilation(lib_cs, assemblyName: "lib"); libComp.VerifyDiagnostics(); var comp1 = CreateCompilation(source, references: new[] { libComp.ToMetadataReference() }); comp1.VerifyDiagnostics(); var comp2 = CreateCompilation(source, references: new[] { libComp.EmitToImageReference() }); comp2.VerifyDiagnostics(); } [Fact] [WorkItem(11322, "https://github.com/dotnet/roslyn/issues/11322")] public void LiteralsAndAmbiguousVT_01() { var source = @" class C3 { public static void Main() { var x = (1, 1); System.Console.WriteLine(x.GetType().Assembly); } } "; var comp1 = CreateCompilationWithMscorlib40(trivial2uple, assemblyName: "comp1"); var comp2 = CreateCompilationWithMscorlib40(trivial2uple, assemblyName: "comp2"); var comp = CreateCompilationWithMscorlib40(source, references: new[] { comp1.ToMetadataReference(), comp2.ToMetadataReference() }, parseOptions: TestOptions.Regular, options: TestOptions.DebugExe); comp.VerifyDiagnostics( // (6,17): error CS8356: Predefined type 'System.ValueTuple`2' is declared in multiple referenced assemblies: 'comp1, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' and 'comp2, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' // var x = (1, 1); Diagnostic(ErrorCode.ERR_PredefinedValueTupleTypeAmbiguous3, "(1, 1)").WithArguments("System.ValueTuple`2", "comp1, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null", "comp2, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null").WithLocation(6, 17) ); comp = CreateCompilationWithMscorlib40(source, references: new[] { comp2.ToMetadataReference(), comp1.ToMetadataReference() }, parseOptions: TestOptions.Regular, options: TestOptions.DebugExe); comp.VerifyDiagnostics( // (6,17): error CS8356: Predefined type 'System.ValueTuple`2' is declared in multiple referenced assemblies: 'comp2, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' and 'comp1, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' // var x = (1, 1); Diagnostic(ErrorCode.ERR_PredefinedValueTupleTypeAmbiguous3, "(1, 1)").WithArguments("System.ValueTuple`2", "comp2, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null", "comp1, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null").WithLocation(6, 17) ); comp = CreateCompilationWithMscorlib40(source, references: new[] { comp2.ToMetadataReference(ImmutableArray.Create("alias")), comp1.ToMetadataReference() }, parseOptions: TestOptions.Regular, options: TestOptions.DebugExe); comp.VerifyDiagnostics(); CompileAndVerify(comp, expectedOutput: "comp1, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null"); } [Fact] [WorkItem(11322, "https://github.com/dotnet/roslyn/issues/11322")] public void LiteralsAndAmbiguousVT_02() { var source1 = trivial2uple; var source2 = @" public static class C2 { public static void M1(this string x, (int, string) y) { System.Console.WriteLine(""C2.M1""); } } " + trivial2uple + tupleattributes_cs; var comp1 = CreateCompilationWithMscorlib40AndSystemCore(source1, assemblyName: "comp1"); comp1.VerifyDiagnostics(); var comp2 = CreateCompilationWithMscorlib40AndSystemCore(source2, assemblyName: "comp2"); comp2.VerifyDiagnostics(); var source3 = @" class C3 { public static void Main() { ""x"".M1((1, null)); } } "; var comp = CreateCompilationWithMscorlib40(source3, references: new[] { comp1.ToMetadataReference(), comp2.ToMetadataReference() }, parseOptions: TestOptions.Regular, options: TestOptions.DebugExe); comp.VerifyDiagnostics( // (6,16): error CS8356: Predefined type 'System.ValueTuple`2' is declared in multiple referenced assemblies: 'comp1, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' and 'comp2, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' // "x".M1((1, null)); Diagnostic(ErrorCode.ERR_PredefinedValueTupleTypeAmbiguous3, "(1, null)").WithArguments("System.ValueTuple`2", "comp1, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null", "comp2, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null").WithLocation(6, 16) ); comp = CreateCompilationWithMscorlib40(source3, references: new[] { comp1.ToMetadataReference().WithAliases(ImmutableArray.Create("alias")), comp2.ToMetadataReference() }, parseOptions: TestOptions.Regular, options: TestOptions.DebugExe); comp.VerifyDiagnostics(); CompileAndVerify(comp, expectedOutput: "C2.M1"); var source4 = @" extern alias alias1; using alias1; class C3 { public static void Main() { ""x"".M1((1, null)); } } "; comp = CreateCompilationWithMscorlib40(source4, references: new[] { comp1.ToMetadataReference(), comp2.ToMetadataReference().WithAliases(ImmutableArray.Create("alias1")) }, parseOptions: TestOptions.Regular, options: TestOptions.DebugExe); comp.VerifyDiagnostics(); CompileAndVerify(comp, expectedOutput: "C2.M1"); } [Fact] [WorkItem(11322, "https://github.com/dotnet/roslyn/issues/11322")] public void LongLiteralsAndAmbiguousVT_02() { var source1 = trivial2uple + trivial3uple + trivialRemainingTuples + tupleattributes_cs; var source2 = @" public static class C2 { public static void M1(this string x, (int, string, int, string, int, string, int, string, int, string) y) { System.Console.WriteLine(""C2.M1""); } } " + trivial2uple + trivial3uple + trivialRemainingTuples + tupleattributes_cs; var comp1 = CreateCompilationWithMscorlib40AndSystemCore(source1, assemblyName: "comp1"); comp1.VerifyDiagnostics(); var comp2 = CreateCompilationWithMscorlib40AndSystemCore(source2, assemblyName: "comp2"); comp2.VerifyDiagnostics(); var source3 = @" class C3 { public static void Main() { ""x"".M1((1, null, 1, null, 1, null, 1, null, 1, null)); } } "; var comp = CreateCompilationWithMscorlib40(source3, references: new[] { comp1.ToMetadataReference(), comp2.ToMetadataReference() }, parseOptions: TestOptions.Regular, options: TestOptions.DebugExe); comp.VerifyDiagnostics( // (6,16): error CS8356: Predefined type 'System.ValueTuple`3' is declared in multiple referenced assemblies: 'comp1, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' and 'comp2, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' // "x".M1((1, null, 1, null, 1, null, 1, null, 1, null)); Diagnostic(ErrorCode.ERR_PredefinedValueTupleTypeAmbiguous3, "(1, null, 1, null, 1, null, 1, null, 1, null)").WithArguments("System.ValueTuple`3", "comp1, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null", "comp2, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null").WithLocation(6, 16), // (6,16): error CS8356: Predefined type 'System.ValueTuple`8' is declared in multiple referenced assemblies: 'comp1, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' and 'comp2, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' // "x".M1((1, null, 1, null, 1, null, 1, null, 1, null)); Diagnostic(ErrorCode.ERR_PredefinedValueTupleTypeAmbiguous3, "(1, null, 1, null, 1, null, 1, null, 1, null)").WithArguments("System.ValueTuple`8", "comp1, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null", "comp2, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null").WithLocation(6, 16) ); comp = CreateCompilationWithMscorlib40(source3, references: new[] { comp1.ToMetadataReference().WithAliases(ImmutableArray.Create("alias")), comp2.ToMetadataReference() }, parseOptions: TestOptions.Regular, options: TestOptions.DebugExe); comp.VerifyDiagnostics(); CompileAndVerify(comp, expectedOutput: "C2.M1"); var source4 = @" extern alias alias1; using alias1; class C3 { public static void Main() { ""x"".M1((1, null, 1, null, 1, null, 1, null, 1, null)); } } "; comp = CreateCompilationWithMscorlib40(source4, references: new[] { comp1.ToMetadataReference(), comp2.ToMetadataReference().WithAliases(ImmutableArray.Create("alias1")) }, parseOptions: TestOptions.Regular, options: TestOptions.DebugExe); comp.VerifyDiagnostics(); CompileAndVerify(comp, expectedOutput: "C2.M1"); } [Fact] [WorkItem(11323, "https://github.com/dotnet/roslyn/issues/11323")] public void ExactlyMatchingExpression() { var source1 = @" namespace NS1 { public static class C1 { public static void M1(this string x, (int, int) y) { System.Console.WriteLine(""C1.M1""); } } } "; var source2 = @" namespace NS2 { public static class C2 { public static void M1(this string x, (int, int) y) { System.Console.WriteLine(""C2.M1""); } } } "; var comp1 = CreateCompilationWithMscorlib40AndSystemCore(source1, references: s_valueTupleRefs, assemblyName: "comp1"); comp1.VerifyDiagnostics(); var comp2 = CreateCompilationWithMscorlib40AndSystemCore(source2, references: s_valueTupleRefs, assemblyName: "comp2"); comp2.VerifyDiagnostics(); var source3 = @" extern alias alias1; using alias1::NS2; using NS1; class C3 { public static void Main() { ""x"".M1((1, 1)); } } "; var comp = CreateCompilationWithMscorlib40(source3, references: s_valueTupleRefs.Concat(new[] { comp1.ToMetadataReference(), comp2.ToMetadataReference().WithAliases(ImmutableArray.Create("alias1")) }), parseOptions: TestOptions.Regular, options: TestOptions.DebugExe); comp.VerifyDiagnostics( // (10,13): error CS0121: The call is ambiguous between the following methods or properties: 'NS2.C2.M1(string, (int, int))' and 'NS1.C1.M1(string, (int, int))' // "x".M1((1, 1)); Diagnostic(ErrorCode.ERR_AmbigCall, "M1").WithArguments("NS2.C2.M1(string, (int, int))", "NS1.C1.M1(string, (int, int))").WithLocation(10, 13) ); var source4 = @" using NS1; class C3 { public static void Main() { ""x"".M1((1, 1)); } } "; comp = CreateCompilationWithMscorlib40(source4, references: s_valueTupleRefs.Concat(new[] { comp1.ToMetadataReference(), comp2.ToMetadataReference().WithAliases(ImmutableArray.Create("alias1")) }), parseOptions: TestOptions.Regular, options: TestOptions.DebugExe); comp.VerifyDiagnostics(); CompileAndVerify(comp, expectedOutput: "C1.M1"); var source5 = @" extern alias alias1; using alias1::NS2; class C3 { public static void Main() { ""x"".M1((1, 1)); } } "; comp = CreateCompilationWithMscorlib40(source5, references: new[] { comp1.ToMetadataReference(), comp2.ToMetadataReference().WithAliases(ImmutableArray.Create("alias1")), ValueTupleRef, SystemRuntimeFacadeRef }, parseOptions: TestOptions.Regular, options: TestOptions.DebugExe); comp.VerifyDiagnostics(); CompileAndVerify(comp, expectedOutput: "C2.M1"); } [Fact] public void MultipleVT_01() { var source1 = @" public class C1 { public void M1((int, int) y) { System.Console.WriteLine(""C1.M1""); } } " + trivial2uple + tupleattributes_cs; var source2 = @" public class C2 { public void M1((int, int) y) { System.Console.WriteLine(""C2.M1""); } } " + trivial2uple + tupleattributes_cs; var comp1 = CreateCompilationWithMscorlib40AndSystemCore(source1, assemblyName: "comp1"); comp1.VerifyDiagnostics(); var comp2 = CreateCompilationWithMscorlib40AndSystemCore(source2, assemblyName: "comp2"); comp2.VerifyDiagnostics(); var source = @" extern alias alias1; class C3 { public static void Main() { new C1().M1((1, 1)); new alias1::C2().M1((1, 1)); } } "; var comp = CreateCompilationWithMscorlib46(source, references: new[] { comp1.ToMetadataReference(), comp2.ToMetadataReference().WithAliases(ImmutableArray.Create("alias1")) }, parseOptions: TestOptions.Regular, options: TestOptions.DebugExe); comp.VerifyDiagnostics(); CompileAndVerify(comp, expectedOutput: @"C1.M1 C2.M1"); } [Fact] [WorkItem(11325, "https://github.com/dotnet/roslyn/issues/11325")] public void MultipleVT_02() { var source1 = @" public class C1 { public (int, int) M2() { System.Console.WriteLine(""C1.M2""); return (1, 1); } } " + trivial2uple + tupleattributes_cs; var source2 = @" public class C2 { public void M3((int, int) y) { System.Console.WriteLine(""C2.M3""); } } " + trivial2uple + tupleattributes_cs; var comp1 = CreateCompilationWithMscorlib40AndSystemCore(source1, assemblyName: "comp1"); comp1.VerifyDiagnostics(); var comp2 = CreateCompilationWithMscorlib40AndSystemCore(source2, assemblyName: "comp2"); comp2.VerifyDiagnostics(); var source = @" extern alias alias1; class C3 { public static void Main() { new alias1::C2().M3(new C1().M2()); } } "; var comp = CreateCompilation(source, references: new[] { comp1.ToMetadataReference(), comp2.ToMetadataReference().WithAliases(ImmutableArray.Create("alias1")) }, parseOptions: TestOptions.Regular, options: TestOptions.DebugExe); CompileAndVerify(comp, expectedOutput: @"C1.M2 C2.M3"); } [Fact(Skip = "https://github.com/dotnet/roslyn/issues/11326")] [WorkItem(11326, "https://github.com/dotnet/roslyn/issues/11326")] public void GetTypeInfo_01() { var source = @" class C { static void Main() { var x1 = ((short, string))(1, ""hello""); var x2 = ((short, string))(2, null); var x3 = (short)11; var x4 = (string)null; var x5 = (System.Func)(() => 12); } } " + trivial2uple + trivial3uple + tupleattributes_cs; var tree = Parse(source, options: TestOptions.Regular); var comp = CreateCompilation(tree); //comp.VerifyDiagnostics(); var model = comp.GetSemanticModel(tree, ignoreAccessibility: false); var nodes = tree.GetCompilationUnitRoot().DescendantNodes(); var n1 = nodes.OfType().ElementAt(0); Assert.Equal(@"(1, ""hello"")", n1.ToString()); Assert.Equal("(System.Int32, System.String)", model.GetTypeInfo(n1).Type.ToTestDisplayString()); Assert.Equal("(System.Int32, System.String)", model.GetTypeInfo(n1).ConvertedType.ToTestDisplayString()); Assert.Equal(Conversion.Identity, model.GetConversion(n1)); var n2 = nodes.OfType().ElementAt(1); Assert.Equal(@"(2, null)", n2.ToString()); Assert.Null(model.GetTypeInfo(n2).Type); Assert.Null(model.GetTypeInfo(n2).ConvertedType); Assert.Equal(Conversion.Identity, model.GetConversion(n2)); var n3 = nodes.OfType().ElementAt(4); Assert.Equal(@"11", n3.ToString()); Assert.Equal("System.Int32", model.GetTypeInfo(n3).Type.ToTestDisplayString()); Assert.Equal("System.Int32", model.GetTypeInfo(n3).ConvertedType.ToTestDisplayString()); Assert.Equal(Conversion.Identity, model.GetConversion(n3)); var n4 = nodes.OfType().ElementAt(5); Assert.Equal(@"null", n4.ToString()); Assert.Null(model.GetTypeInfo(n4).Type); Assert.Null(model.GetTypeInfo(n4).ConvertedType); Assert.Equal(Conversion.Identity, model.GetConversion(n4)); var n5 = nodes.OfType().Single(); Assert.Equal(@"() => 12", n5.ToString()); Assert.Null(model.GetTypeInfo(n5).Type); Assert.Equal("System.Func", model.GetTypeInfo(n5).ConvertedType.ToTestDisplayString()); Assert.Equal(ConversionKind.AnonymousFunction, model.GetConversion(n5).Kind); } [Fact] [WorkItem(11326, "https://github.com/dotnet/roslyn/issues/11326")] public void GetTypeInfo_02() { var source = @" class C { static void Main() { (short, string) x1 = (1, ""hello""); (short, string) x2 = (2, null); short x3 = 11; string x4 = null; System.Func x5 = () => 12; } } " + trivial2uple + trivial3uple + tupleattributes_cs; var tree = Parse(source, options: TestOptions.Regular); var comp = CreateCompilation(tree); //comp.VerifyDiagnostics(); var model = comp.GetSemanticModel(tree, ignoreAccessibility: false); var nodes = tree.GetCompilationUnitRoot().DescendantNodes(); var n1 = nodes.OfType().ElementAt(0); Assert.Equal(@"(1, ""hello"")", n1.ToString()); Assert.Equal("(System.Int32, System.String)", model.GetTypeInfo(n1).Type.ToTestDisplayString()); Assert.Equal("(System.Int16, System.String)", model.GetTypeInfo(n1).ConvertedType.ToTestDisplayString()); Assert.Equal(ConversionKind.ImplicitTupleLiteral, model.GetConversion(n1).Kind); var n2 = nodes.OfType().ElementAt(1); Assert.Equal(@"(2, null)", n2.ToString()); Assert.Null(model.GetTypeInfo(n2).Type); Assert.Equal("(System.Int16, System.String)", model.GetTypeInfo(n2).ConvertedType.ToTestDisplayString()); Assert.Equal(ConversionKind.ImplicitTupleLiteral, model.GetConversion(n2).Kind); var n3 = nodes.OfType().ElementAt(4); Assert.Equal(@"11", n3.ToString()); Assert.Equal("System.Int32", model.GetTypeInfo(n3).Type.ToTestDisplayString()); Assert.Equal("System.Int16", model.GetTypeInfo(n3).ConvertedType.ToTestDisplayString()); Assert.Equal(ConversionKind.ImplicitConstant, model.GetConversion(n3).Kind); var n4 = nodes.OfType().ElementAt(5); Assert.Equal(@"null", n4.ToString()); Assert.Null(model.GetTypeInfo(n4).Type); Assert.Equal("System.String", model.GetTypeInfo(n4).ConvertedType.ToTestDisplayString()); Assert.Equal(Conversion.ImplicitReference, model.GetConversion(n4)); var n5 = nodes.OfType().Single(); Assert.Equal(@"() => 12", n5.ToString()); Assert.Null(model.GetTypeInfo(n5).Type); Assert.Equal("System.Func", model.GetTypeInfo(n5).ConvertedType.ToTestDisplayString()); Assert.Equal(ConversionKind.AnonymousFunction, model.GetConversion(n5).Kind); } [Fact] [WorkItem(36185, "https://github.com/dotnet/roslyn/issues/36185")] public void GetTypeInfo_03() { var source = @" class C { static void Main() { M((1, ""hello"")); M((2, null)); } public static void M((short, string) x) { } } " + trivial2uple + tupleattributes_cs; var tree = Parse(source, options: TestOptions.Regular); var comp = CreateCompilation(tree); comp.VerifyDiagnostics(); var model = comp.GetSemanticModel(tree, ignoreAccessibility: false); var nodes = tree.GetCompilationUnitRoot().DescendantNodes(); var n1 = nodes.OfType().ElementAt(0); Assert.Equal(@"(1, ""hello"")", n1.ToString()); Assert.Equal("(System.Int32, System.String)", model.GetTypeInfo(n1).Type.ToTestDisplayString()); Assert.Equal("(System.Int16, System.String)", model.GetTypeInfo(n1).ConvertedType.ToTestDisplayString()); Assert.Equal(ConversionKind.ImplicitTupleLiteral, model.GetConversion(n1).Kind); var n2 = nodes.OfType().ElementAt(1); Assert.Equal(@"(2, null)", n2.ToString()); Assert.Null(model.GetTypeInfo(n2).Type); Assert.Equal("(System.Int16, System.String)", model.GetTypeInfo(n2).ConvertedType.ToTestDisplayString()); Assert.Equal(ConversionKind.ImplicitTupleLiteral, model.GetConversion(n2).Kind); } [Fact] [WorkItem(14600, "https://github.com/dotnet/roslyn/issues/14600")] public void GetSymbolInfo_01() { var source = @" class C { static void Main() { // error is intentional. GetSymbolInfo should still work DummyType x1 = (Alice: 1, ""hello""); var Alice = x1.Alice; } } " + trivial2uple + trivial3uple + tupleattributes_cs; var tree = Parse(source, options: TestOptions.Regular); var comp = CreateCompilation(tree); var model = comp.GetSemanticModel(tree, ignoreAccessibility: false); var nodes = tree.GetCompilationUnitRoot().DescendantNodes(); var nc = nodes.OfType().ElementAt(0); var sym = model.GetSymbolInfo(nc.Name); Assert.Equal(SymbolKind.Field, sym.Symbol.Kind); Assert.Equal("Alice", sym.Symbol.Name); Assert.Equal(nc.Name.GetLocation(), sym.Symbol.Locations[0]); } [Fact] public void GetSymbolInfo_WithInferredName() { var source = @" class C { static void Main() { string Bob = ""hello""; var x1 = (Alice: 1, Bob); var Alice = x1.Alice; var BobCopy = x1.Bob; } } "; var tree = Parse(source, options: TestOptions.Regular7_1); var comp = CreateCompilation(tree); comp.VerifyDiagnostics(); var model = comp.GetSemanticModel(tree, ignoreAccessibility: false); var nodes = tree.GetCompilationUnitRoot().DescendantNodes(); var x1Bob = nodes.OfType().ElementAt(1); Assert.Equal("x1.Bob", x1Bob.ToString()); var x1Symbol = model.GetSymbolInfo(x1Bob.Expression).Symbol as ILocalSymbol; Assert.Equal("(System.Int32 Alice, System.String Bob)", x1Symbol.Type.ToTestDisplayString()); var bobField = x1Symbol.Type.GetMember("Bob"); Assert.Equal(SymbolKind.Field, bobField.Kind); var secondElement = nodes.OfType().First().Arguments[1]; Assert.Equal(secondElement.GetLocation(), bobField.Locations[0]); } [Fact] [WorkItem(23651, "https://github.com/dotnet/roslyn/issues/23651")] public void GetSymbolInfo_WithDuplicateInferredName() { var source = @" class C { static object M(string Bob) { var x1 = (Bob, Bob); return x1; } } "; var tree = Parse(source, options: TestOptions.Regular7_1); var comp = CreateCompilation(tree); comp.VerifyDiagnostics(); var model = comp.GetSemanticModel(tree, ignoreAccessibility: false); var nodes = tree.GetCompilationUnitRoot().DescendantNodes(); var x1 = nodes.OfType().Single(); Assert.Equal("x1 = (Bob, Bob)", x1.ToString()); var x1Symbol = (ILocalSymbol)model.GetDeclaredSymbol(x1); Assert.Equal("(System.String, System.String) x1", x1Symbol.ToTestDisplayString()); Assert.True(x1Symbol.Type.GetSymbol().TupleElementNames.IsDefault); } [Fact] public void CompileTupleLib() { string additionalSource = @" namespace System { public class SR { public static string ArgumentException_ValueTupleIncorrectType { get { return """"; } } public static string ArgumentException_ValueTupleLastArgumentNotAValueTuple { get { return """"; } } } } namespace System.Diagnostics { public static class Debug { public static void Assert(bool condition) { } public static void Assert(bool condition, string message) { } } } "; var tupleComp = CreateCompilationWithMscorlib40( tuplelib_cs + tupleattributes_cs + additionalSource); tupleComp.VerifyDiagnostics(); var source = @" class C { static void Main() { var x = (1, 2); System.Console.WriteLine(x.ToString()); } } "; var comp = CompileAndVerifyWithMscorlib40(source, expectedOutput: "(1, 2)", references: new[] { tupleComp.ToMetadataReference() }); comp.VerifyDiagnostics(); } [Fact] public void ImplicitConversions01() { var source = @" using System; class C { static void Main() { // long tuple var x1 = (1,2,3,4,5,6,7,8,9,10,11,12); (long, long, long, long, long, long, long, long,long, long, long, long) y1 = x1; System.Console.WriteLine(y1); // long nested tuple var x2 = (1,2,3,4,5,6,7,8,9,10,11,(1,2,3,4,5,6,7,8,9,10,11,12)); (long, long, long, long, long, long, long, long,long, long, long, (long, long, long, long, long, long, long, long,long, long, long, long)) y2 = x2; System.Console.WriteLine(y2); // user defined conversion var x3 = (1,1); C1 y3 = x3; x3 = y3; System.Console.WriteLine(x3); } class C1 { static public implicit operator C1((long, long) arg) { return new C1(); } static public implicit operator (byte, byte)(C1 arg) { return (2, 2); } } } "; var comp = CompileAndVerify(source, expectedOutput: @" (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12) (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12)) (2, 2) "); } [Fact] public void ExplicitConversions01() { var source = @" using System; class C { static void Main() { // long tuple var x1 = (1,2,3,4,5,6,7,8,9,10,11,12); (byte, byte, byte, byte, byte, byte, byte, byte,byte, byte, byte, byte) y1 = ((byte, byte, byte, byte, byte, byte, byte, byte,byte, byte, byte, byte))x1; System.Console.WriteLine(y1); // long nested tuple var x2 = (1,2,3,4,5,6,7,8,9,10,11,(1,2,3,4,5,6,7,8,9,10,11,12)); (byte, byte, byte, byte, byte, byte, byte, byte,byte, byte, byte, (byte, byte, byte, byte, byte, byte, byte, byte,byte, byte, byte, byte)) y2 = ((byte, byte, byte, byte, byte, byte, byte, byte,byte, byte, byte, (byte, byte, byte, byte, byte, byte, byte, byte,byte, byte, byte, byte)))x2; System.Console.WriteLine(y2); // user defined conversion var x3 = (1,1); C1 y3 = (C1)x3; x3 = ((int, int))y3; System.Console.WriteLine(x3); } class C1 { static public explicit operator C1((long, long) arg) { return new C1(); } static public explicit operator (byte, byte)(C1 arg) { return (2, 2); } } } "; var comp = CompileAndVerify(source, expectedOutput: @" (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12) (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12)) (2, 2) "); } [Fact] public void ImplicitConversions02() { var source = @" using System; class C { static void Main() { var x = (a:1, b:1); C1 y = x; x = y; System.Console.WriteLine(x); x = ((int, int))(C1)x; System.Console.WriteLine(x); } class C1 { static public implicit operator C1((long, long) arg) { return new C1(); } static public implicit operator (byte c, byte d)(C1 arg) { return (2, 2); } } } "; var comp = CompileAndVerify(source, parseOptions: TestOptions.Regular, expectedOutput: @" (2, 2) (2, 2)"); comp.VerifyIL("C.Main", @" { // Code size 125 (0x7d) .maxstack 2 .locals init (System.ValueTuple V_0, System.ValueTuple V_1) IL_0000: ldc.i4.1 IL_0001: ldc.i4.1 IL_0002: newobj ""System.ValueTuple..ctor(int, int)"" IL_0007: stloc.0 IL_0008: ldloc.0 IL_0009: ldfld ""int System.ValueTuple.Item1"" IL_000e: conv.i8 IL_000f: ldloc.0 IL_0010: ldfld ""int System.ValueTuple.Item2"" IL_0015: conv.i8 IL_0016: newobj ""System.ValueTuple..ctor(long, long)"" IL_001b: call ""C.C1 C.C1.op_Implicit(System.ValueTuple)"" IL_0020: call ""System.ValueTuple C.C1.op_Implicit(C.C1)"" IL_0025: stloc.1 IL_0026: ldloc.1 IL_0027: ldfld ""byte System.ValueTuple.Item1"" IL_002c: ldloc.1 IL_002d: ldfld ""byte System.ValueTuple.Item2"" IL_0032: newobj ""System.ValueTuple..ctor(int, int)"" IL_0037: dup IL_0038: box ""System.ValueTuple"" IL_003d: call ""void System.Console.WriteLine(object)"" IL_0042: stloc.0 IL_0043: ldloc.0 IL_0044: ldfld ""int System.ValueTuple.Item1"" IL_0049: conv.i8 IL_004a: ldloc.0 IL_004b: ldfld ""int System.ValueTuple.Item2"" IL_0050: conv.i8 IL_0051: newobj ""System.ValueTuple..ctor(long, long)"" IL_0056: call ""C.C1 C.C1.op_Implicit(System.ValueTuple)"" IL_005b: call ""System.ValueTuple C.C1.op_Implicit(C.C1)"" IL_0060: stloc.1 IL_0061: ldloc.1 IL_0062: ldfld ""byte System.ValueTuple.Item1"" IL_0067: ldloc.1 IL_0068: ldfld ""byte System.ValueTuple.Item2"" IL_006d: newobj ""System.ValueTuple..ctor(int, int)"" IL_0072: box ""System.ValueTuple"" IL_0077: call ""void System.Console.WriteLine(object)"" IL_007c: ret } "); ; } [Fact] public void ExplicitConversions02() { var source = @" using System; class C { static void Main() { var x = (a:1, b:1); C1 y = (C1)x; x = ((int a, int b))y; System.Console.WriteLine(x); x = ((int, int))(C1)x; System.Console.WriteLine(x); } class C1 { static public explicit operator C1((long, long) arg) { return new C1(); } static public explicit operator (byte c, byte d)(C1 arg) { return (2, 2); } } } "; var comp = CompileAndVerify(source, parseOptions: TestOptions.Regular, expectedOutput: @" (2, 2) (2, 2)"); comp.VerifyIL("C.Main", @" { // Code size 125 (0x7d) .maxstack 2 .locals init (System.ValueTuple V_0, System.ValueTuple V_1) IL_0000: ldc.i4.1 IL_0001: ldc.i4.1 IL_0002: newobj ""System.ValueTuple..ctor(int, int)"" IL_0007: stloc.0 IL_0008: ldloc.0 IL_0009: ldfld ""int System.ValueTuple.Item1"" IL_000e: conv.i8 IL_000f: ldloc.0 IL_0010: ldfld ""int System.ValueTuple.Item2"" IL_0015: conv.i8 IL_0016: newobj ""System.ValueTuple..ctor(long, long)"" IL_001b: call ""C.C1 C.C1.op_Explicit(System.ValueTuple)"" IL_0020: call ""System.ValueTuple C.C1.op_Explicit(C.C1)"" IL_0025: stloc.1 IL_0026: ldloc.1 IL_0027: ldfld ""byte System.ValueTuple.Item1"" IL_002c: ldloc.1 IL_002d: ldfld ""byte System.ValueTuple.Item2"" IL_0032: newobj ""System.ValueTuple..ctor(int, int)"" IL_0037: dup IL_0038: box ""System.ValueTuple"" IL_003d: call ""void System.Console.WriteLine(object)"" IL_0042: stloc.0 IL_0043: ldloc.0 IL_0044: ldfld ""int System.ValueTuple.Item1"" IL_0049: conv.i8 IL_004a: ldloc.0 IL_004b: ldfld ""int System.ValueTuple.Item2"" IL_0050: conv.i8 IL_0051: newobj ""System.ValueTuple..ctor(long, long)"" IL_0056: call ""C.C1 C.C1.op_Explicit(System.ValueTuple)"" IL_005b: call ""System.ValueTuple C.C1.op_Explicit(C.C1)"" IL_0060: stloc.1 IL_0061: ldloc.1 IL_0062: ldfld ""byte System.ValueTuple.Item1"" IL_0067: ldloc.1 IL_0068: ldfld ""byte System.ValueTuple.Item2"" IL_006d: newobj ""System.ValueTuple..ctor(int, int)"" IL_0072: box ""System.ValueTuple"" IL_0077: call ""void System.Console.WriteLine(object)"" IL_007c: ret } "); } [Fact] public void ImplicitConversions03() { var source = @" using System; class C { static void Main() { var x = (a:1, b:1); C1 y = x; (int, int)? x1 = y; System.Console.WriteLine(x1); x1 = ((int, int)?)(C1)x; System.Console.WriteLine(x1); } class C1 { static public implicit operator C1((long, long)? arg) { return new C1(); } static public implicit operator (byte c, byte d)(C1 arg) { return (2, 2); } } } "; var comp = CompileAndVerify(source, parseOptions: TestOptions.Regular, expectedOutput: @" (2, 2) (2, 2) "); } [Fact] public void ExplicitConversions03() { var source = @" using System; class C { static void Main() { var x = (a:1, b:1); C1 y = (C1)x; (int, int)? x1 = ((int, int)?)y; System.Console.WriteLine(x1); x1 = ((int, int)?)(C1)x; System.Console.WriteLine(x1); } class C1 { static public explicit operator C1((long, long)? arg) { return new C1(); } static public explicit operator (byte c, byte d)(C1 arg) { return (2, 2); } } } "; var comp = CompileAndVerify(source, parseOptions: TestOptions.Regular, expectedOutput: @" (2, 2) (2, 2) "); } [Fact] public void ImplicitConversions04() { var source = @" using System; class C { static void Main() { var x = (1, (1, (1, (1, (1, (1, 1)))))); C1 y = x; (int, int) x2 = y; System.Console.WriteLine(x2); (int, (int, int)) x3 = y; System.Console.WriteLine(x3); (int, (int, (int, (int, (int, (int, (int, (int, (int, (int, (int, int))))))))))) x12 = y; System.Console.WriteLine(x12); } class C1 { private byte x; static public implicit operator C1((long, C1) arg) { var result = new C1(); result.x = arg.Item2.x; return result; } static public implicit operator C1((long, long) arg) { var result = new C1(); result.x = (byte)(arg.Item2); return result; } static public implicit operator (byte, C1)(C1 arg) { return ((byte)(arg.x++), arg); } static public implicit operator (byte c, byte d)(C1 arg) { return ((byte)(arg.x++), (byte)(arg.x++)); } } } "; var comp = CompileAndVerify(source, parseOptions: TestOptions.Regular, expectedOutput: @" (1, 2) (3, (4, 5)) (6, (7, (8, (9, (10, (11, (12, (13, (14, (15, (16, 17)))))))))))"); } [Fact] public void ExplicitConversions04Err() { // explicit conversion case similar to ImplicitConversions04 // is a compiler error since explicit tuple conversions do not stack up like // implicit tuple conversions which are in standard implicit set. var source = @" using System; class C { static void Main() { var x = (1, (1, (1, (1, (1, (1, 1)))))); C1 y = (C1)x; (int, int) x2 = ((int, int))y; System.Console.WriteLine(x2); (int, (int, int)) x3 = ((int, (int, int)))y; System.Console.WriteLine(x3); (int, (int, (int, (int, (int, (int, (int, (int, (int, (int, (int, int))))))))))) x12 = ((int, (int, (int, (int, (int, (int, (int, (int, (int, (int, (int, int))))))))))))y; System.Console.WriteLine(x12); } class C1 { private byte x; static public explicit operator C1((long, C1) arg) { var result = new C1(); result.x = arg.Item2.x; return result; } static public explicit operator C1((long, long) arg) { var result = new C1(); result.x = (byte)(arg.Item2); return result; } static public explicit operator (byte, C1)(C1 arg) { return ((byte)(arg.x++), arg); } static public explicit operator (byte c, byte d)(C1 arg) { return ((byte)(arg.x++), (byte)(arg.x++)); } } } "; var comp = CreateCompilation(source, parseOptions: TestOptions.Regular, assemblyName: "ImplicitConversions06Err"); comp.VerifyEmitDiagnostics( // (8,16): error CS0030: Cannot convert type '(int, (int, (int, (int, (int, (int, int))))))' to 'C.C1' // C1 y = (C1)x; Diagnostic(ErrorCode.ERR_NoExplicitConv, "(C1)x").WithArguments("(int, (int, (int, (int, (int, (int, int))))))", "C.C1").WithLocation(8, 16), // (13,32): error CS0030: Cannot convert type 'C.C1' to '(int, (int, int))' // (int, (int, int)) x3 = ((int, (int, int)))y; Diagnostic(ErrorCode.ERR_NoExplicitConv, "((int, (int, int)))y").WithArguments("C.C1", "(int, (int, int))").WithLocation(13, 32), // (16,96): error CS0030: Cannot convert type 'C.C1' to '(int, (int, (int, (int, (int, (int, (int, (int, (int, (int, (int, int)))))))))))' // (int, (int, (int, (int, (int, (int, (int, (int, (int, (int, (int, int))))))))))) x12 = ((int, (int, (int, (int, (int, (int, (int, (int, (int, (int, (int, int))))))))))))y; Diagnostic(ErrorCode.ERR_NoExplicitConv, "((int, (int, (int, (int, (int, (int, (int, (int, (int, (int, (int, int))))))))))))y").WithArguments("C.C1", "(int, (int, (int, (int, (int, (int, (int, (int, (int, (int, (int, int)))))))))))").WithLocation(16, 96) ); } [Fact] public void ImplicitConversions05() { var source = @" using System; class C { static void Main() { var x = (1, (1, (1, (1, (1, 1))))); C1 y = x; (int, (object, (byte, (int?, (long, IComparable)?))?))? x1 = y; System.Console.WriteLine(x1); } class C1 { private byte x; static public implicit operator C1((long, C1) arg) { var result = new C1(); result.x = arg.Item2.x; return result; } static public implicit operator C1((long, long) arg) { var result = new C1(); result.x = (byte)(arg.Item2); return result; } static public implicit operator (byte, C1)(C1 arg) { return ((byte)(arg.x++), arg); } static public implicit operator (byte c, byte d)(C1 arg) { return ((byte)(arg.x++), (byte)(arg.x++)); } } } "; var comp = CompileAndVerify(source, parseOptions: TestOptions.Regular, expectedOutput: @" (1, (2, (3, (4, (5, 6))))) "); } [Fact] public void ExplicitConversions05() { var source = @" using System; class C { static void Main() { var x = (1, (1, (1, (1, (1, 1))))); C1 y = (C1)((int, C1))((int, (int, C1)))((int, (int, (int, C1))))((int, (int, (int, (int, C1)))))x; (int, (object, (byte, (int?, (long, IComparable)?))?))? x1 = ((int, (object, (byte, (int?, (long, IComparable)?))?))?) ((int, (object, (byte, (int?, C1))?))?) ((int, (object, (byte, C1)?))?) ((int, (object, C1))?) ((int, C1)?) (C1)y; System.Console.WriteLine(x1); } class C1 { private byte x; static public explicit operator C1((long, C1) arg) { var result = new C1(); result.x = arg.Item2.x; return result; } static public explicit operator C1((long, long) arg) { var result = new C1(); result.x = (byte)(arg.Item2); return result; } static public explicit operator (byte, C1)(C1 arg) { return ((byte)(arg.x++), arg); } static public explicit operator (byte c, byte d)(C1 arg) { return ((byte)(arg.x++), (byte)(arg.x++)); } } } "; var comp = CompileAndVerify(source, parseOptions: TestOptions.Regular, expectedOutput: @" (1, (2, (3, (4, (5, 6))))) "); } [Fact] public void ImplicitConversions05Err() { var source = @" using System; class C { static void Main() { var x = (1, (1, (1, (1, (1, 1))))); C1 y = x; (int, (object, (byte, (int?, (long, IComparable)?))?))? x1 = y; System.Console.WriteLine(x1); } class C1 { private byte x; static public implicit operator C1((long, C1) arg) { var result = new C1(); result.x = arg.Item2.x; return result; } static public implicit operator C1((long, long) arg) { var result = new C1(); result.x = (byte)(arg.Item2); return result; } } } "; var comp = CreateCompilation(source); comp.VerifyDiagnostics( // (10,70): error CS0029: Cannot implicitly convert type 'C.C1' to '(int, (object, (byte, (int?, (long, System.IComparable)?))?))?' // (int, (object, (byte, (int?, (long, IComparable)?))?))? x1 = y; Diagnostic(ErrorCode.ERR_NoImplicitConv, "y").WithArguments("C.C1", "(int, (object, (byte, (int?, (long, System.IComparable)?))?))?").WithLocation(10, 70) ); } [Fact] public void ExplicitConversions05Err() { var source = @" using System; class C { static void Main() { var x = (1, (1, (1, (1, (1, 1))))); C1 y = (C1)((int, C1))((int, (int, C1)))((int, (int, (int, C1))))((int, (int, (int, (int, C1)))))x; (int, (object, (byte, (int?, (long, IComparable)?))?))? x1 = ((int, (object, (byte, (int?, (long, IComparable)?))?))?) ((int, (object, (byte, (int?, C1))?))?) ((int, (object, (byte, C1)?))?) ((int, (object, C1))?) ((int, C1)?) (C1)y; System.Console.WriteLine(x1); } class C1 { private byte x; static public explicit operator C1((long, C1) arg) { var result = new C1(); result.x = arg.Item2.x; return result; } static public explicit operator C1((long, long) arg) { var result = new C1(); result.x = (byte)(arg.Item2); return result; } } } "; var comp = CreateCompilation(source); comp.VerifyDiagnostics( // (14,70): error CS0030: Cannot convert type 'C.C1' to '(int, C.C1)?' // ((int, C1)?) Diagnostic(ErrorCode.ERR_NoExplicitConv, @"((int, C1)?) (C1)y").WithArguments("C.C1", "(int, C.C1)?").WithLocation(14, 70) ); } [Fact] public void ImplicitConversions06Err() { var source = @" class C { static void Main() { var x = (1, 1); (long, long) y = x; System.Console.WriteLine(y); } } namespace System { // struct with two values (missing a field) public struct ValueTuple { public T1 Item1; public ValueTuple(T1 item1, T2 item2) => throw null; } } "; var comp = CreateCompilation(source, assemblyName: "ImplicitConversions06Err"); comp.VerifyEmitDiagnostics( // (7,26): error CS8128: Member 'Item2' was not found on type '(T1, T2)' from assembly 'ImplicitConversions06Err, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'. // (long, long) y = x; Diagnostic(ErrorCode.ERR_PredefinedTypeMemberNotFoundInAssembly, "x").WithArguments("Item2", "(T1, T2)", "ImplicitConversions06Err, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null").WithLocation(7, 26) ); } [Fact] public void ExplicitConversions06Err() { var source = @" class C { static void Main() { var x = (1, 1); (byte, byte) y = ((byte, byte))x; System.Console.WriteLine(y); } } namespace System { // struct with two values (missing a field) public struct ValueTuple { public T1 Item1; public ValueTuple(T1 item1, T2 item2) { this.Item1 = item1; } } } "; var comp = CreateCompilation(source, assemblyName: "ImplicitConversions06Err"); comp.VerifyEmitDiagnostics( // (7,26): error CS8128: Member 'Item2' was not found on type '(T1, T2)' from assembly 'ImplicitConversions06Err, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'. // (byte, byte) y = ((byte, byte))x; Diagnostic(ErrorCode.ERR_PredefinedTypeMemberNotFoundInAssembly, "((byte, byte))x").WithArguments("Item2", "(T1, T2)", "ImplicitConversions06Err, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null").WithLocation(7, 26) ); } [Fact] public void ImplicitConversions07() { var source = @" using System; internal class Program { static void Main(string[] args) { var t = (1, 1); (C2, C2) aa = t; System.Console.WriteLine(aa); } // accessibility of operators. Notice Private private class C2 { public static implicit operator C2(int arg) { return new C2(); } } } " + trivial2uple + tupleattributes_cs; var comp = CompileAndVerify(source, expectedOutput: @" {Program+C2, Program+C2} "); } [Fact] public void ExplicitConversions07() { var source = @" using System; internal class Program { static void Main(string[] args) { var t = (1, 1); (C2, C2) aa = ((C2, C2))t; System.Console.WriteLine(aa); } // accessibility of operators. Notice Private private class C2 { public static explicit operator C2(int arg) { return new C2(); } } } " + trivial2uple + tupleattributes_cs; var comp = CompileAndVerify(source, expectedOutput: @" {Program+C2, Program+C2} "); } [Fact] public void ExplicitConversionsSimple01() { var source = @" using System; class C { static void Main() { var x = (a:1, b:2); var y = ((byte, byte))x; System.Console.WriteLine(y); var z = ((int, int))((long)3, (object)4); System.Console.WriteLine(z); } } " + trivial2uple + tupleattributes_cs; var comp = CompileAndVerify(source, expectedOutput: @" {1, 2} {3, 4}"); comp.VerifyIL("C.Main", @" { // Code size 65 (0x41) .maxstack 2 .locals init (System.ValueTuple V_0) IL_0000: ldc.i4.1 IL_0001: ldc.i4.2 IL_0002: newobj ""System.ValueTuple..ctor(int, int)"" IL_0007: stloc.0 IL_0008: ldloc.0 IL_0009: ldfld ""int System.ValueTuple.Item1"" IL_000e: conv.u1 IL_000f: ldloc.0 IL_0010: ldfld ""int System.ValueTuple.Item2"" IL_0015: conv.u1 IL_0016: newobj ""System.ValueTuple..ctor(byte, byte)"" IL_001b: box ""System.ValueTuple"" IL_0020: call ""void System.Console.WriteLine(object)"" IL_0025: ldc.i4.3 IL_0026: ldc.i4.4 IL_0027: box ""int"" IL_002c: unbox.any ""int"" IL_0031: newobj ""System.ValueTuple..ctor(int, int)"" IL_0036: box ""System.ValueTuple"" IL_003b: call ""void System.Console.WriteLine(object)"" IL_0040: ret } "); ; } [Fact] public void ExplicitConversionsSimple02() { var source = @" using System; class C { static void Main() { var x = (a:1, b:2); var y = ((C2, C2))x; System.Console.WriteLine(y); var z = ((C2, C2))((object)null, 4); System.Console.WriteLine(z); } private class C2 { private int x; public static explicit operator C2(int arg) { var result = new C2(); result.x = arg + 1; return result; } public override string ToString() { return x.ToString(); } } } " + trivial2uple + tupleattributes_cs; var comp = CompileAndVerify(source, expectedOutput: @" {2, 3} {, 5}"); comp.VerifyIL("C.Main", @" { // Code size 68 (0x44) .maxstack 2 .locals init (System.ValueTuple V_0) IL_0000: ldc.i4.1 IL_0001: ldc.i4.2 IL_0002: newobj ""System.ValueTuple..ctor(int, int)"" IL_0007: stloc.0 IL_0008: ldloc.0 IL_0009: ldfld ""int System.ValueTuple.Item1"" IL_000e: call ""C.C2 C.C2.op_Explicit(int)"" IL_0013: ldloc.0 IL_0014: ldfld ""int System.ValueTuple.Item2"" IL_0019: call ""C.C2 C.C2.op_Explicit(int)"" IL_001e: newobj ""System.ValueTuple..ctor(C.C2, C.C2)"" IL_0023: box ""System.ValueTuple"" IL_0028: call ""void System.Console.WriteLine(object)"" IL_002d: ldnull IL_002e: ldc.i4.4 IL_002f: call ""C.C2 C.C2.op_Explicit(int)"" IL_0034: newobj ""System.ValueTuple..ctor(C.C2, C.C2)"" IL_0039: box ""System.ValueTuple"" IL_003e: call ""void System.Console.WriteLine(object)"" IL_0043: ret } "); ; } [Fact] [WorkItem(11804, "https://github.com/dotnet/roslyn/issues/11804")] public void ExplicitConversionsSimple02Expr() { var source = @" class C { static void Main() { var x = (a:1, b:2); var y = ((C2, C2))x; System.Console.WriteLine(y); var z = ((C2, C2))(null, 4); System.Console.WriteLine(z); } private class C2 { private int x; public static explicit operator C2(int arg) { var result = new C2(); result.x = arg + 1; return result; } public override string ToString() { return x.ToString(); } } } " + trivial2uple + tupleattributes_cs; var comp = CompileAndVerify(source, parseOptions: TestOptions.Regular, expectedOutput: @" {2, 3} {, 5}"); comp.VerifyIL("C.Main", @" { // Code size 68 (0x44) .maxstack 2 .locals init (System.ValueTuple V_0) IL_0000: ldc.i4.1 IL_0001: ldc.i4.2 IL_0002: newobj ""System.ValueTuple..ctor(int, int)"" IL_0007: stloc.0 IL_0008: ldloc.0 IL_0009: ldfld ""int System.ValueTuple.Item1"" IL_000e: call ""C.C2 C.C2.op_Explicit(int)"" IL_0013: ldloc.0 IL_0014: ldfld ""int System.ValueTuple.Item2"" IL_0019: call ""C.C2 C.C2.op_Explicit(int)"" IL_001e: newobj ""System.ValueTuple..ctor(C.C2, C.C2)"" IL_0023: box ""System.ValueTuple"" IL_0028: call ""void System.Console.WriteLine(object)"" IL_002d: ldnull IL_002e: ldc.i4.4 IL_002f: call ""C.C2 C.C2.op_Explicit(int)"" IL_0034: newobj ""System.ValueTuple..ctor(C.C2, C.C2)"" IL_0039: box ""System.ValueTuple"" IL_003e: call ""void System.Console.WriteLine(object)"" IL_0043: ret } "); } [WorkItem(12064, "https://github.com/dotnet/roslyn/issues/12064")] [Fact] public void ExplicitConversionsPreference01() { var source = @" using System; class B { static void Main() { C x = new D(""original""); D y = (D)x; // explicit builtin downcast is preferred Console.WriteLine(""explicit""); Console.WriteLine(y); Console.WriteLine(); y = x; // implicit user defined implicit conversion Console.WriteLine(""implicit""); Console.WriteLine(y); Console.WriteLine(); Console.WriteLine(); (C, C) xt = (new D(""original1""), new D(""original2"")); var xtxt = (xt, xt); Console.WriteLine(""explicit""); (D, D) yt = ((D, D))xt; // explicit builtin downcast is preferred Console.WriteLine(yt); ((D, D),(D, D)) ytyt = (((D, D),(D, D)))(xt, xt); // explicit builtin downcast is preferred Console.WriteLine(ytyt); ytyt = (((D, D),(D, D)))xtxt; // explicit builtin downcast is preferred Console.WriteLine(ytyt); (D, D)? ytn = ((D, D)?)xt; // explicit builtin downcast is preferred (nullable) Console.WriteLine(ytn); Console.WriteLine(); Console.WriteLine(""implicit""); yt = xt; // implicit user defined implicit conversion Console.WriteLine(yt); ytyt = xtxt; // implicit user defined implicit conversion Console.WriteLine(ytyt); ytyt = (xt, xt); // implicit user defined implicit conversion Console.WriteLine(ytyt); ytn = xt; // implicit user defined implicit conversion Console.WriteLine(ytn); } } class C { } class D : C { private readonly string val; public D(string val) { this.val = val; } public override string ToString() { return val; } public static implicit operator D(C x) { return new D(""converted""); } } " + trivial2uple + tupleattributes_cs; var comp = CompileAndVerify(source, expectedOutput: @" explicit original implicit converted explicit {original1, original2} {{original1, original2}, {original1, original2}} {{original1, original2}, {original1, original2}} {original1, original2} implicit {converted, converted} {{converted, converted}, {converted, converted}} {{converted, converted}, {converted, converted}} {converted, converted} "); } [Fact] public void ExplicitConversionsPreference02() { var source = @" using System; class A { public static implicit operator A(int d) { return null; } } class B : A { public static implicit operator B(long d) { return null; } } class C { static void Main() { var x = 1; var xt = (x, x); // implicit conversions are unambiguous B b = x; (B, B) bt = xt; // the following is an error for compat reasons // explicit conversion is ambiguous and implicit conversion exists, but ignored b = (B)x; // SHOULD THIS BE AN ERROR TOO? bt = ((B, B))xt; // SHOULD THIS BE AN ERROR TOO? bt = ((B, B)?)xt; } } " + trivial2uple + tupleattributes_cs; var comp = CreateCompilation(source, assemblyName: "ImplicitConversions06Err"); comp.VerifyEmitDiagnostics( // (28,13): error CS0457: Ambiguous user defined conversions 'B.implicit operator B(long)' and 'A.implicit operator A(int)' when converting from 'int' to 'B' // b = (B)x; Diagnostic(ErrorCode.ERR_AmbigUDConv, "(B)x").WithArguments("B.implicit operator B(long)", "A.implicit operator A(int)", "int", "B").WithLocation(28, 13), // (31,14): error CS0030: Cannot convert type '(int, int)' to '(B, B)' // bt = ((B, B))xt; Diagnostic(ErrorCode.ERR_NoExplicitConv, "((B, B))xt").WithArguments("(int, int)", "(B, B)").WithLocation(31, 14), // (34,14): error CS0030: Cannot convert type '(int, int)' to '(B, B)?' // bt = ((B, B)?)xt; Diagnostic(ErrorCode.ERR_NoExplicitConv, "((B, B)?)xt").WithArguments("(int, int)", "(B, B)?").WithLocation(34, 14) ); } [Fact] public void ConversionsOverload02() { var source = @" using System; class C { static void Main() { (long, long) x = (1,1); Test(x); (int, int) y = (1,1); Test(y); Test((1, 1)); } static void Test((long, long) x) { System.Console.WriteLine(""first""); } static void Test((long?, long?) x) { System.Console.WriteLine(""second""); } } "; var comp = CompileAndVerify(source, parseOptions: TestOptions.Regular, expectedOutput: @" first first first "); } [Fact] public void ConversionsOverload03() { var source = @" using System; class C { static void Main() { Test((1, 1)); (int, int)? y = (1,1); Test(y); (long, long)? x = (1,1); Test(x); } static void Test((long?, long?)? x) { System.Console.WriteLine(""second""); } } "; var comp = CompileAndVerify(source, parseOptions: TestOptions.Regular, expectedOutput: @" second second second "); } [Fact] public void ConversionsOverload04() { var source = @" using System; class C { static void Main() { Test((1, 1)); (int, int)? y = (1,1); Test(y); (long, long)? x = (1,1); Test(x); } static void Test((long, long) x) { System.Console.WriteLine(""first""); } static void Test((long?, long?)? x) { System.Console.WriteLine(""second""); } } "; var comp = CompileAndVerify(source, parseOptions: TestOptions.Regular, expectedOutput: @" first second second "); } [Fact] public void ConversionsOverload05() { var source = @" using System; using System.Collections; using System.Collections.Generic; class Program { static void Main(string[] args) { Action x = null; Action> x1 = null; // valid and T is IEnumerable // Action is introducing upper bound on T Test(x, x1); (Action x, Action y) z = (null, null); (Action> x, Action> y) z1 = (null, null); // inference fails // (T, T) is introducing exact bound on T even in an 'in' param position Test(z, z1); // evidently, this is an error. Test<(IEnumerable, IEnumerable )> (z, z1); } public static void Test(Action x, Action y) { System.Console.WriteLine(typeof(T)); } } " + trivial2uple + tupleattributes_cs; var comp = CreateCompilation(source); comp.VerifyDiagnostics( // (22,9): error CS0411: The type arguments for method 'Program.Test(Action, Action)' cannot be inferred from the usage. Try specifying the type arguments explicitly. // Test(z, z1); Diagnostic(ErrorCode.ERR_CantInferMethTypeArgs, "Test").WithArguments("Program.Test(System.Action, System.Action)").WithLocation(22, 9), // (25,54): error CS1503: Argument 1: cannot convert from '(System.Action x, System.Action y)' to 'System.Action<(System.Collections.Generic.IEnumerable, System.Collections.Generic.IEnumerable)>' // Test<(IEnumerable, IEnumerable )> (z, z1); Diagnostic(ErrorCode.ERR_BadArgType, "z").WithArguments("1", "(System.Action x, System.Action y)", "System.Action<(System.Collections.Generic.IEnumerable, System.Collections.Generic.IEnumerable)>").WithLocation(25, 54), // (25,57): error CS1503: Argument 2: cannot convert from '(System.Action> x, System.Action> y)' to 'System.Action<(System.Collections.Generic.IEnumerable, System.Collections.Generic.IEnumerable)>' // Test<(IEnumerable, IEnumerable )> (z, z1); Diagnostic(ErrorCode.ERR_BadArgType, "z1").WithArguments("2", "(System.Action> x, System.Action> y)", "System.Action<(System.Collections.Generic.IEnumerable, System.Collections.Generic.IEnumerable)>").WithLocation(25, 57) ); } [Fact] public void ClassifyConversionIdentity01() { var tupleComp = CreateCompilation(trivial2uple + trivial3uple + trivialRemainingTuples); var comp = CSharpCompilation.Create("test", references: new[] { MscorlibRef, tupleComp.ToMetadataReference() }); TypeSymbol intType = comp.GetSpecialType(SpecialType.System_Int32); TypeSymbol stringType = comp.GetSpecialType(SpecialType.System_String); var int_string1 = comp.CreateTupleTypeSymbol(ImmutableArray.Create(intType, stringType)); var int_string2 = comp.CreateTupleTypeSymbol(ImmutableArray.Create(intType, stringType)); var int_stringNamed = comp.CreateTupleTypeSymbol(ImmutableArray.Create(intType, stringType), ImmutableArray.Create("a", "b")); Assert.Equal(ConversionKind.Identity, comp.ClassifyConversion(int_string1, int_string1).Kind); Assert.Equal(ConversionKind.Identity, comp.ClassifyConversion(int_string1, int_string2).Kind); Assert.Equal(ConversionKind.Identity, comp.ClassifyConversion(int_string1, int_stringNamed).Kind); } [Fact] public void ClassifyConversionIdentity02() { var tupleComp = CreateCompilation(trivial2uple + trivial3uple + trivialRemainingTuples); var comp = (Compilation)CSharpCompilation.Create("test", references: new[] { MscorlibRef, tupleComp.ToMetadataReference() }); ITypeSymbol intType = comp.GetSpecialType(SpecialType.System_Int32); ITypeSymbol stringType = comp.GetSpecialType(SpecialType.System_String); var int_string1 = comp.GetWellKnownType(WellKnownType.System_ValueTuple_T2).Construct(intType, stringType); var int_string2 = comp.CreateTupleTypeSymbol(ImmutableArray.Create(intType, stringType)); var int_stringNamed = comp.CreateTupleTypeSymbol(ImmutableArray.Create(intType, stringType), ImmutableArray.Create("a", "b")); Assert.Equal(ConversionKind.Identity, comp.ClassifyConversion(int_string1, int_string1).Kind); Assert.Equal(ConversionKind.Identity, comp.ClassifyConversion(int_string1, int_string2).Kind); Assert.Equal(ConversionKind.Identity, comp.ClassifyConversion(int_string1, int_stringNamed).Kind); Assert.Equal(ConversionKind.Identity, comp.ClassifyConversion(int_string2, int_string1).Kind); Assert.Equal(ConversionKind.Identity, comp.ClassifyConversion(int_stringNamed, int_string1).Kind); } [Fact] public void ClassifyConversionNone01() { var tupleComp = CreateCompilation(trivial2uple + trivial3uple + trivialRemainingTuples); var comp = (Compilation)CSharpCompilation.Create("test", references: new[] { MscorlibRef, tupleComp.ToMetadataReference() }); ITypeSymbol intType = comp.GetSpecialType(SpecialType.System_Int32); ITypeSymbol stringType = comp.GetSpecialType(SpecialType.System_String); var int_int = comp.CreateTupleTypeSymbol(ImmutableArray.Create(intType, intType)); var int_int_int = comp.CreateTupleTypeSymbol(ImmutableArray.Create(intType, intType, intType)); var string_string = comp.CreateTupleTypeSymbol(ImmutableArray.Create(stringType, stringType)); var int_int1 = comp.GetWellKnownType(WellKnownType.System_ValueTuple_T2).Construct(intType, intType); Assert.Equal(ConversionKind.NoConversion, comp.ClassifyConversion(int_int, int_int_int).Kind); Assert.Equal(ConversionKind.NoConversion, comp.ClassifyConversion(int_int, string_string).Kind); Assert.Equal(ConversionKind.NoConversion, comp.ClassifyConversion(int_int1, string_string).Kind); Assert.Equal(ConversionKind.NoConversion, comp.ClassifyConversion(int_int1, int_int_int).Kind); Assert.Equal(ConversionKind.NoConversion, comp.ClassifyConversion(string_string, int_int1).Kind); Assert.Equal(ConversionKind.NoConversion, comp.ClassifyConversion(int_int_int, int_int1).Kind); } [Fact] public void ClassifyConversionImplicit01() { var tupleComp = CreateCompilation(trivial2uple + trivial3uple + trivialRemainingTuples); var comp = CSharpCompilation.Create("test", references: new[] { MscorlibRef, tupleComp.ToMetadataReference() }); TypeSymbol intType = comp.GetSpecialType(SpecialType.System_Int32); TypeSymbol stringType = comp.GetSpecialType(SpecialType.System_String); TypeSymbol objectType = comp.GetSpecialType(SpecialType.System_Object); var int_string = comp.CreateTupleTypeSymbol(ImmutableArray.Create(intType, stringType)); var int_object = comp.CreateTupleTypeSymbol(ImmutableArray.Create(intType, objectType)); Assert.Equal(ConversionKind.ImplicitTuple, comp.ClassifyConversion(int_string, int_object).Kind); Assert.Equal(ConversionKind.ExplicitTuple, comp.ClassifyConversion(int_object, int_string).Kind); } [Fact] public void ClassifyConversionImplicit02() { var tupleComp = CreateCompilation(trivial2uple + trivial3uple + trivialRemainingTuples); var comp = (Compilation)CSharpCompilation.Create("test", references: new[] { MscorlibRef, tupleComp.ToMetadataReference() }); ITypeSymbol intType = comp.GetSpecialType(SpecialType.System_Int32); ITypeSymbol stringType = comp.GetSpecialType(SpecialType.System_String); ITypeSymbol objectType = comp.GetSpecialType(SpecialType.System_Object); var int_string1 = comp.CreateTupleTypeSymbol(ImmutableArray.Create(intType, stringType)); var int_object1 = comp.CreateTupleTypeSymbol(ImmutableArray.Create(intType, objectType)); var int_string2 = comp.GetWellKnownType(WellKnownType.System_ValueTuple_T2).Construct(intType, stringType); var int_object2 = comp.GetWellKnownType(WellKnownType.System_ValueTuple_T2).Construct(intType, objectType); Assert.Equal(ConversionKind.ImplicitTuple, comp.ClassifyConversion(int_string1, int_object2).Kind); Assert.Equal(ConversionKind.ImplicitTuple, comp.ClassifyConversion(int_string2, int_object1).Kind); Assert.Equal(ConversionKind.ImplicitTuple, comp.ClassifyConversion(int_string2, int_object2).Kind); Assert.Equal(ConversionKind.ExplicitTuple, comp.ClassifyConversion(int_object2, int_string1).Kind); Assert.Equal(ConversionKind.ExplicitTuple, comp.ClassifyConversion(int_object1, int_string2).Kind); Assert.Equal(ConversionKind.ExplicitTuple, comp.ClassifyConversion(int_object2, int_string2).Kind); } [Fact] public void ClassifyConversionImplicit03() { var tupleComp1 = CreateCompilation(trivial2uple + trivial3uple + trivialRemainingTuples); var tupleComp2 = CreateCompilation(trivial2uple + trivial3uple + trivialRemainingTuples); var comp = (Compilation)CSharpCompilation.Create("test", references: new[] { MscorlibRef, tupleComp1.ToMetadataReference(), tupleComp2.ToMetadataReference() }); ITypeSymbol intType = comp.GetSpecialType(SpecialType.System_Int32); ITypeSymbol stringType = comp.GetSpecialType(SpecialType.System_String); ITypeSymbol objectType = comp.GetSpecialType(SpecialType.System_Object); var int_string1 = tupleComp1.CreateTupleTypeSymbol(ImmutableArray.Create(intType, stringType)); var int_string2 = tupleComp2.CreateTupleTypeSymbol(ImmutableArray.Create(intType, stringType)); var int_object = tupleComp1.CreateTupleTypeSymbol(ImmutableArray.Create(intType, objectType)); Assert.Equal(ConversionKind.ImplicitTuple, comp.ClassifyConversion(int_string1, int_string2).Kind); Assert.Equal(ConversionKind.ImplicitTuple, comp.ClassifyConversion(int_string2, int_string1).Kind); Assert.Equal(ConversionKind.ImplicitTuple, comp.ClassifyConversion(int_string1, int_object).Kind); Assert.Equal(ConversionKind.ImplicitTuple, comp.ClassifyConversion(int_string2, int_object).Kind); Assert.Equal(ConversionKind.ExplicitTuple, comp.ClassifyConversion(int_object, int_string1).Kind); Assert.Equal(ConversionKind.ExplicitTuple, comp.ClassifyConversion(int_object, int_string2).Kind); } [Fact] public void ClassifyConversionImplicit03u() { var tupleComp1 = CreateCompilation(trivial2uple + trivial3uple + trivialRemainingTuples); var tupleComp2 = CreateCompilation(trivial2uple + trivial3uple + trivialRemainingTuples); var comp = (Compilation)CSharpCompilation.Create("test", references: new[] { MscorlibRef, tupleComp1.ToMetadataReference(), tupleComp2.ToMetadataReference() }); ITypeSymbol intType = comp.GetSpecialType(SpecialType.System_Int32); ITypeSymbol stringType = comp.GetSpecialType(SpecialType.System_String); ITypeSymbol objectType = comp.GetSpecialType(SpecialType.System_Object); var int_string1 = tupleComp1.CreateTupleTypeSymbol(ImmutableArray.Create(intType, stringType)); var int_string2 = tupleComp2.CreateTupleTypeSymbol(ImmutableArray.Create(intType, stringType)); var int_object = tupleComp1.CreateTupleTypeSymbol(ImmutableArray.Create(intType, objectType)); Assert.Null(int_string1.TupleUnderlyingType); Assert.Equal(ConversionKind.ImplicitTuple, comp.ClassifyConversion(int_string1, int_string2).Kind); Assert.Equal(ConversionKind.ImplicitTuple, comp.ClassifyConversion(int_string2, int_string1).Kind); Assert.Equal(ConversionKind.ImplicitTuple, comp.ClassifyConversion(int_string1, int_object).Kind); Assert.Equal(ConversionKind.ImplicitTuple, comp.ClassifyConversion(int_string2, int_object).Kind); Assert.Equal(ConversionKind.ExplicitTuple, comp.ClassifyConversion(int_object, int_string1).Kind); Assert.Equal(ConversionKind.ExplicitTuple, comp.ClassifyConversion(int_object, int_string2).Kind); } [Fact] public void ClassifyConversionImplicit03uu() { var tupleComp1 = CreateCompilation(trivial2uple + trivial3uple + trivialRemainingTuples); var tupleComp2 = CreateCompilation(trivial2uple + trivial3uple + trivialRemainingTuples); var comp = (Compilation)CSharpCompilation.Create("test", references: new[] { MscorlibRef, tupleComp1.ToMetadataReference(), tupleComp2.ToMetadataReference() }); ITypeSymbol intType = comp.GetSpecialType(SpecialType.System_Int32); ITypeSymbol stringType = comp.GetSpecialType(SpecialType.System_String); ITypeSymbol objectType = comp.GetSpecialType(SpecialType.System_Object); var int_string1 = tupleComp1.CreateTupleTypeSymbol(ImmutableArray.Create(intType, stringType)); var int_string2 = tupleComp2.CreateTupleTypeSymbol(ImmutableArray.Create(intType, stringType)); var int_object = tupleComp1.CreateTupleTypeSymbol(ImmutableArray.Create(intType, objectType)); Assert.Null(int_string1.TupleUnderlyingType); Assert.Null(int_string2.TupleUnderlyingType); Assert.Equal(ConversionKind.ImplicitTuple, comp.ClassifyConversion(int_string1, int_string2).Kind); Assert.Equal(ConversionKind.ImplicitTuple, comp.ClassifyConversion(int_string2, int_string1).Kind); Assert.Equal(ConversionKind.ImplicitTuple, comp.ClassifyConversion(int_string1, int_object).Kind); Assert.Equal(ConversionKind.ImplicitTuple, comp.ClassifyConversion(int_string2, int_object).Kind); Assert.Equal(ConversionKind.ExplicitTuple, comp.ClassifyConversion(int_object, int_string1).Kind); Assert.Equal(ConversionKind.ExplicitTuple, comp.ClassifyConversion(int_object, int_string2).Kind); } [Fact] public void ClassifyConversionImplicit03uuu() { var tupleComp1 = CreateCompilation(trivial2uple + trivial3uple + trivialRemainingTuples); var tupleComp2 = CreateCompilation(trivial2uple + trivial3uple + trivialRemainingTuples); var comp = (Compilation)CSharpCompilation.Create("test", references: new[] { MscorlibRef, tupleComp1.ToMetadataReference(), tupleComp2.ToMetadataReference() }); ITypeSymbol intType = comp.GetSpecialType(SpecialType.System_Int32); ITypeSymbol stringType = comp.GetSpecialType(SpecialType.System_String); ITypeSymbol objectType = comp.GetSpecialType(SpecialType.System_Object); var int_string1 = tupleComp1.CreateTupleTypeSymbol(ImmutableArray.Create(intType, stringType)); var int_string2 = tupleComp2.CreateTupleTypeSymbol(ImmutableArray.Create(intType, stringType)); var int_object = tupleComp1.CreateTupleTypeSymbol(ImmutableArray.Create(intType, objectType)); Assert.Null(int_string1.TupleUnderlyingType); Assert.Null(int_string2.TupleUnderlyingType); Assert.Null(int_object.TupleUnderlyingType); Assert.Equal(ConversionKind.ImplicitTuple, comp.ClassifyConversion(int_string1, int_string2).Kind); Assert.Equal(ConversionKind.ImplicitTuple, comp.ClassifyConversion(int_string2, int_string1).Kind); Assert.Equal(ConversionKind.ImplicitTuple, comp.ClassifyConversion(int_string1, int_object).Kind); Assert.Equal(ConversionKind.ImplicitTuple, comp.ClassifyConversion(int_string2, int_object).Kind); Assert.Equal(ConversionKind.ExplicitTuple, comp.ClassifyConversion(int_object, int_string1).Kind); Assert.Equal(ConversionKind.ExplicitTuple, comp.ClassifyConversion(int_object, int_string2).Kind); } [Fact] public void ClassifyConversionImplicit04() { var text = @" class C { public static implicit operator int(C c) { return 0; } public C() { var x = (1, ""qq""); var i = /**/x/**/; } }"; var tupleComp1 = CreateCompilationWithMscorlib40(trivial2uple + trivial3uple + trivialRemainingTuples); var tree = Parse(text); var comp = (Compilation)CSharpCompilation.Create("test", syntaxTrees: new[] { tree }, references: new[] { (MetadataReference)Net40.mscorlib, tupleComp1.ToMetadataReference() }); var model = comp.GetSemanticModel(tree); var exprs = GetBindingNodes(comp); var expr1 = exprs.First(); ITypeSymbol intType = comp.GetSpecialType(SpecialType.System_Int32); ITypeSymbol stringType = comp.GetSpecialType(SpecialType.System_String); ITypeSymbol objectType = comp.GetSpecialType(SpecialType.System_Object); var int_string1 = tupleComp1.CreateTupleTypeSymbol(ImmutableArray.Create(intType, stringType)); var int_object = tupleComp1.CreateTupleTypeSymbol(ImmutableArray.Create(intType, objectType)); var int_object_object = tupleComp1.CreateTupleTypeSymbol(ImmutableArray.Create(intType, objectType, objectType)); Assert.Equal(ConversionKind.Identity, model.ClassifyConversion(expr1, int_string1).Kind); Assert.Equal(ConversionKind.Identity, model.ClassifyConversion(expr1, int_string1, isExplicitInSource: true).Kind); Assert.Equal(ConversionKind.ImplicitTuple, model.ClassifyConversion(expr1, int_object).Kind); Assert.Equal(ConversionKind.ExplicitTuple, model.ClassifyConversion(expr1, int_object, isExplicitInSource: true).Kind); Assert.Equal(ConversionKind.NoConversion, model.ClassifyConversion(expr1, int_object_object).Kind); Assert.Equal(ConversionKind.NoConversion, model.ClassifyConversion(expr1, int_object_object, isExplicitInSource: true).Kind); } [Fact] public void ClassifyConversionImplicit05() { var text = @" class C { public static implicit operator int(C c) { return 0; } public C() { var x = (1, (object)""qq""); var i = /**/x/**/; } }"; var tupleComp1 = CreateCompilationWithMscorlib40(trivial2uple + trivial3uple + trivialRemainingTuples); var tree = Parse(text); var comp = (Compilation)CSharpCompilation.Create("test", syntaxTrees: new[] { tree }, references: new[] { (MetadataReference)Net40.mscorlib, tupleComp1.ToMetadataReference() }); var model = comp.GetSemanticModel(tree); var exprs = GetBindingNodes(comp); var expr1 = exprs.First(); ITypeSymbol intType = comp.GetSpecialType(SpecialType.System_Int32); ITypeSymbol stringType = comp.GetSpecialType(SpecialType.System_String); ITypeSymbol objectType = comp.GetSpecialType(SpecialType.System_Object); var int_string1 = tupleComp1.CreateTupleTypeSymbol(ImmutableArray.Create(intType, stringType)); var int_object = tupleComp1.CreateTupleTypeSymbol(ImmutableArray.Create(intType, objectType)); var int_object_object = tupleComp1.CreateTupleTypeSymbol(ImmutableArray.Create(intType, objectType, objectType)); Assert.Equal(ConversionKind.ExplicitTuple, model.ClassifyConversion(expr1, int_string1).Kind); Assert.Equal(ConversionKind.Identity, model.ClassifyConversion(expr1, int_object).Kind); Assert.Equal(ConversionKind.ExplicitTuple, model.ClassifyConversion(expr1, int_string1, isExplicitInSource: true).Kind); Assert.Equal(ConversionKind.Identity, model.ClassifyConversion(expr1, int_object, isExplicitInSource: true).Kind); Assert.Equal(ConversionKind.NoConversion, model.ClassifyConversion(expr1, int_object_object).Kind); Assert.Equal(ConversionKind.NoConversion, model.ClassifyConversion(expr1, int_object_object, isExplicitInSource: true).Kind); } [Fact] public void ClassifyConversionImplicit06() { var text = @" class C { public static implicit operator int(C c) { return 0; } public C() { var x = (1, ""qq""); var i = /**/x/**/; } }"; var tupleComp1 = CreateCompilation(trivial2uple + trivial3uple + trivialRemainingTuples); var tree = Parse(text); var comp = (Compilation)CSharpCompilation.Create("test", syntaxTrees: new[] { tree }, references: new[] { MscorlibRef, tupleComp1.ToMetadataReference() }); var model = comp.GetSemanticModel(tree); var exprs = GetBindingNodes(comp); var expr1 = exprs.First(); ITypeSymbol intType = comp.GetSpecialType(SpecialType.System_Int32); ITypeSymbol stringType = comp.GetSpecialType(SpecialType.System_String); ITypeSymbol objectType = comp.GetSpecialType(SpecialType.System_Object); var int_string1 = comp.GetWellKnownType(WellKnownType.System_ValueTuple_T2).Construct(intType, stringType); var int_object = comp.GetWellKnownType(WellKnownType.System_ValueTuple_T2).Construct(intType, objectType); var int_object_object = comp.GetWellKnownType(WellKnownType.System_ValueTuple_T3).Construct(intType, objectType, objectType); Assert.Equal(ConversionKind.Identity, model.ClassifyConversion(expr1, int_string1).Kind); Assert.Equal(ConversionKind.Identity, model.ClassifyConversion(expr1, int_string1, isExplicitInSource: true).Kind); Assert.Equal(ConversionKind.ImplicitTuple, model.ClassifyConversion(expr1, int_object).Kind); Assert.Equal(ConversionKind.ExplicitTuple, model.ClassifyConversion(expr1, int_object, isExplicitInSource: true).Kind); Assert.Equal(ConversionKind.NoConversion, model.ClassifyConversion(expr1, int_object_object).Kind); Assert.Equal(ConversionKind.NoConversion, model.ClassifyConversion(expr1, int_object_object, isExplicitInSource: true).Kind); } [Fact] public void ClassifyConversionImplicit07() { var text = @" class C { public static implicit operator int(C c) { return 0; } public C() { var x = (1, (object)""qq""); var i = /**/x/**/; } }"; var tupleComp1 = CreateCompilation(trivial2uple + trivial3uple + trivialRemainingTuples); var tree = Parse(text); var comp = (Compilation)CSharpCompilation.Create("test", syntaxTrees: new[] { tree }, references: new[] { MscorlibRef, tupleComp1.ToMetadataReference() }); var model = comp.GetSemanticModel(tree); var exprs = GetBindingNodes(comp); var expr1 = exprs.First(); ITypeSymbol intType = comp.GetSpecialType(SpecialType.System_Int32); ITypeSymbol stringType = comp.GetSpecialType(SpecialType.System_String); ITypeSymbol objectType = comp.GetSpecialType(SpecialType.System_Object); var int_string1 = comp.GetWellKnownType(WellKnownType.System_ValueTuple_T2).Construct(intType, stringType); var int_object = comp.GetWellKnownType(WellKnownType.System_ValueTuple_T2).Construct(intType, objectType); var int_object_object = comp.GetWellKnownType(WellKnownType.System_ValueTuple_T3).Construct(intType, objectType, objectType); Assert.Equal(ConversionKind.ExplicitTuple, model.ClassifyConversion(expr1, int_string1).Kind); Assert.Equal(ConversionKind.Identity, model.ClassifyConversion(expr1, int_object).Kind); Assert.Equal(ConversionKind.ExplicitTuple, model.ClassifyConversion(expr1, int_string1, isExplicitInSource: true).Kind); Assert.Equal(ConversionKind.Identity, model.ClassifyConversion(expr1, int_object, isExplicitInSource: true).Kind); Assert.Equal(ConversionKind.NoConversion, model.ClassifyConversion(expr1, int_object_object).Kind); Assert.Equal(ConversionKind.NoConversion, model.ClassifyConversion(expr1, int_object_object, isExplicitInSource: true).Kind); } [Fact] public void TernaryTypeInferenceWithDynamicAndTupleNames() { var source = @" public class C { public void M() { bool flag = true; var x1 = flag ? (a: 1, b: 2) : (a: 1, c: 2); dynamic d = null; var t1 = (a: 1, b: 2); var t2 = (a: 1, c: d); var x2 = flag ? t1 : t2; } } "; var comp = CreateCompilation(source); comp.VerifyDiagnostics( // (7,32): warning CS8123: The tuple element name 'b' is ignored because a different name is specified by the target type '(int a, int)'. // var x1 = flag ? (a: 1, b: 2) : (a: 1, c: 2); Diagnostic(ErrorCode.WRN_TupleLiteralNameMismatch, "b: 2").WithArguments("b", "(int a, int)").WithLocation(7, 32), // (7,47): warning CS8123: The tuple element name 'c' is ignored because a different name is specified by the target type '(int a, int)'. // var x1 = flag ? (a: 1, b: 2) : (a: 1, c: 2); Diagnostic(ErrorCode.WRN_TupleLiteralNameMismatch, "c: 2").WithArguments("c", "(int a, int)").WithLocation(7, 47) ); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var nodes = tree.GetCompilationUnitRoot().DescendantNodes(); var x1 = model.GetDeclaredSymbol(nodes.OfType().Skip(1).First()); Assert.Equal("(System.Int32 a, System.Int32) x1", x1.ToTestDisplayString()); var x2 = model.GetDeclaredSymbol(nodes.OfType().Skip(5).First()); Assert.Equal("(System.Int32 a, dynamic c) x2", x2.ToTestDisplayString()); } [Fact] [WorkItem(16825, "https://github.com/dotnet/roslyn/issues/16825")] public void NullCoalescingOperatorWithTupleNames() { // See section 7.13 of the spec, regarding the null-coalescing operator var source = @" public class C { public void M() { (int a, int b)? nab = (1, 2); (int a, int c)? nac = (1, 3); var x1 = nab ?? nac; // (a, b)? var x2 = nab ?? nac.Value; // (a, b) var x3 = new C() ?? nac; // C var x4 = new D() ?? nac; // (a, c)? var x5 = nab != null ? nab : nac; // (a, )? var x6 = nab ?? (a: 1, c: 3); // (a, b) var x7 = nab ?? (a: 1, c: 3); // (a, b) var x8 = new C() ?? (a: 1, c: 3); // C var x9 = new D() ?? (a: 1, c: 3); // (a, c) var x6double = nab ?? (d: 1.1, c: 3); // (a, c) } public static implicit operator C((int, int) x) { throw null; } } public class D { public static implicit operator (int d1, int d2) (D x) { throw null; } } "; var comp = CreateCompilation(source); comp.VerifyDiagnostics( // (16,32): warning CS8123: The tuple element name 'c' is ignored because a different name is specified by the target type '(int a, int b)'. // var x6 = nab ?? (a: 1, c: 3); // (a, b)? Diagnostic(ErrorCode.WRN_TupleLiteralNameMismatch, "c: 3").WithArguments("c", "(int a, int b)").WithLocation(16, 32), // (17,32): warning CS8123: The tuple element name 'c' is ignored because a different name is specified by the target type '(int a, int b)'. // var x7 = nab ?? (a: 1, c: 3); // (a, b) Diagnostic(ErrorCode.WRN_TupleLiteralNameMismatch, "c: 3").WithArguments("c", "(int a, int b)").WithLocation(17, 32), // (18,30): warning CS8123: The tuple element name 'a' is ignored because a different name is specified by the target type '(int, int)'. // var x8 = new C() ?? (a: 1, c: 3); // C Diagnostic(ErrorCode.WRN_TupleLiteralNameMismatch, "a: 1").WithArguments("a", "(int, int)").WithLocation(18, 30), // (18,36): warning CS8123: The tuple element name 'c' is ignored because a different name is specified by the target type '(int, int)'. // var x8 = new C() ?? (a: 1, c: 3); // C Diagnostic(ErrorCode.WRN_TupleLiteralNameMismatch, "c: 3").WithArguments("c", "(int, int)").WithLocation(18, 36) ); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var nodes = tree.GetCompilationUnitRoot().DescendantNodes(); var x1 = model.GetDeclaredSymbol(nodes.OfType().ElementAt(2)); Assert.Equal("(System.Int32 a, System.Int32 b)? x1", x1.ToTestDisplayString()); var x2 = model.GetDeclaredSymbol(nodes.OfType().ElementAt(3)); Assert.Equal("(System.Int32 a, System.Int32 b) x2", x2.ToTestDisplayString()); var x3 = model.GetDeclaredSymbol(nodes.OfType().ElementAt(4)); Assert.Equal("C x3", x3.ToTestDisplayString()); var x4 = model.GetDeclaredSymbol(nodes.OfType().ElementAt(5)); Assert.Equal("(System.Int32 a, System.Int32 c)? x4", x4.ToTestDisplayString()); var x5 = model.GetDeclaredSymbol(nodes.OfType().ElementAt(6)); Assert.Equal("(System.Int32 a, System.Int32)? x5", x5.ToTestDisplayString()); var x6 = model.GetDeclaredSymbol(nodes.OfType().ElementAt(7)); Assert.Equal("(System.Int32 a, System.Int32 b) x6", x6.ToTestDisplayString()); var x7 = model.GetDeclaredSymbol(nodes.OfType().ElementAt(8)); Assert.Equal("(System.Int32 a, System.Int32 b) x7", x7.ToTestDisplayString()); var x8 = model.GetDeclaredSymbol(nodes.OfType().ElementAt(9)); Assert.Equal("C x8", x8.ToTestDisplayString()); var x9 = model.GetDeclaredSymbol(nodes.OfType().ElementAt(10)); Assert.Equal("(System.Int32 a, System.Int32 c) x9", x9.ToTestDisplayString()); var x6double = model.GetDeclaredSymbol(nodes.OfType().ElementAt(11)); Assert.Equal("(System.Double d, System.Int32 c) x6double", x6double.ToTestDisplayString()); } [Fact] public void TernaryTypeInferenceWithNoNames() { var source = @" public class C { public void M() { bool flag = true; var x1 = flag ? (a: 1, b: 2) : (1, 2); var x2 = flag ? (1, 2) : (a: 1, b: 2); } } "; var comp = CreateCompilation(source); comp.VerifyDiagnostics( // (7,26): warning CS8123: The tuple element name 'a' is ignored because a different name is specified by the target type '(int, int)'. // var x1 = flag ? (a: 1, b: 2) : (1, 2); Diagnostic(ErrorCode.WRN_TupleLiteralNameMismatch, "a: 1").WithArguments("a", "(int, int)").WithLocation(7, 26), // (7,32): warning CS8123: The tuple element name 'b' is ignored because a different name is specified by the target type '(int, int)'. // var x1 = flag ? (a: 1, b: 2) : (1, 2); Diagnostic(ErrorCode.WRN_TupleLiteralNameMismatch, "b: 2").WithArguments("b", "(int, int)").WithLocation(7, 32), // (8,35): warning CS8123: The tuple element name 'a' is ignored because a different name is specified by the target type '(int, int)'. // var x2 = flag ? (1, 2) : (a: 1, b: 2); Diagnostic(ErrorCode.WRN_TupleLiteralNameMismatch, "a: 1").WithArguments("a", "(int, int)").WithLocation(8, 35), // (8,41): warning CS8123: The tuple element name 'b' is ignored because a different name is specified by the target type '(int, int)'. // var x2 = flag ? (1, 2) : (a: 1, b: 2); Diagnostic(ErrorCode.WRN_TupleLiteralNameMismatch, "b: 2").WithArguments("b", "(int, int)").WithLocation(8, 41) ); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var nodes = tree.GetCompilationUnitRoot().DescendantNodes(); var x1 = model.GetDeclaredSymbol(nodes.OfType().Skip(1).First()); Assert.Equal("(System.Int32, System.Int32) x1", x1.ToTestDisplayString()); var x2 = model.GetDeclaredSymbol(nodes.OfType().Skip(2).First()); Assert.Equal("(System.Int32, System.Int32) x2", x2.ToTestDisplayString()); } [Fact] public void TernaryTypeInferenceDropsCandidates() { var source = @" public class C { public void M() { bool flag = true; var x1 = flag ? (a: 1, b: (long)2) : (a: (byte)1, c: 2); } } "; var comp = CreateCompilation(source); comp.VerifyDiagnostics( // (7,59): warning CS8123: The tuple element name 'c' is ignored because a different name is specified by the target type '(int a, long b)'. // var x1 = flag ? (a: 1, b: (long)2) : (a: (byte)1, c: 2); Diagnostic(ErrorCode.WRN_TupleLiteralNameMismatch, "c: 2").WithArguments("c", "(int a, long b)").WithLocation(7, 59) ); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var nodes = tree.GetCompilationUnitRoot().DescendantNodes(); var x1 = model.GetDeclaredSymbol(nodes.OfType().Skip(1).First()); Assert.Equal("(System.Int32 a, System.Int64 b) x1", x1.ToTestDisplayString()); } [Fact] public void LambdaTypeInferenceWithTupleNames() { var source = @" public class C { public void M() { var x1 = M2(() => { bool flag = true; if (flag) { return (a: 1, b: 2); } else { if (flag) { return (a: 1, c: 3); } else { return (a: 1, d: 4); } } }); } public T M2(System.Func f) { return f(); } } "; var comp = CreateCompilation(source); comp.VerifyDiagnostics( // (11,43): warning CS8123: The tuple element name 'b' is ignored because a different name is specified by the target type '(int a, int)'. // return (a: 1, b: 2); Diagnostic(ErrorCode.WRN_TupleLiteralNameMismatch, "b: 2").WithArguments("b", "(int a, int)").WithLocation(11, 43), // (17,47): warning CS8123: The tuple element name 'c' is ignored because a different name is specified by the target type '(int a, int)'. // return (a: 1, c: 3); Diagnostic(ErrorCode.WRN_TupleLiteralNameMismatch, "c: 3").WithArguments("c", "(int a, int)").WithLocation(17, 47), // (21,47): warning CS8123: The tuple element name 'd' is ignored because a different name is specified by the target type '(int a, int)'. // return (a: 1, d: 4); Diagnostic(ErrorCode.WRN_TupleLiteralNameMismatch, "d: 4").WithArguments("d", "(int a, int)").WithLocation(21, 47) ); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var nodes = tree.GetCompilationUnitRoot().DescendantNodes(); var x1 = model.GetDeclaredSymbol(nodes.OfType().First()); Assert.Equal("(System.Int32 a, System.Int32) x1", x1.ToTestDisplayString()); } [Fact(Skip = "https://github.com/dotnet/roslyn/issues/32006")] public void LambdaTypeInferenceWithDynamic() { // See https://github.com/dotnet/roslyn/issues/32006 // need to relax assertion in GetImplicitTupleLiteralConversion var source = @" public class C { public void M() { var x1 = M2(() => { bool flag = true; dynamic d = null; if (flag) { return (a: 1, b: 2); } else { if (flag) { return (a: d, c: 3); } else { return (a: d, d: 4); } } }); } public T M2(System.Func f) { return f(); } } "; var comp = CreateCompilation(source); comp.VerifyDiagnostics( // (12,43): warning CS8123: The tuple element name 'b' is ignored because a different name is specified by the target type '(dynamic a, int)'. // return (a: 1, b: 2); Diagnostic(ErrorCode.WRN_TupleLiteralNameMismatch, "b: 2").WithArguments("b", "(dynamic a, int)").WithLocation(12, 43), // (18,47): warning CS8123: The tuple element name 'c' is ignored because a different name is specified by the target type '(dynamic a, int)'. // return (a: d, c: 3); Diagnostic(ErrorCode.WRN_TupleLiteralNameMismatch, "c: 3").WithArguments("c", "(dynamic a, int)").WithLocation(18, 47), // (22,47): warning CS8123: The tuple element name 'd' is ignored because a different name is specified by the target type '(dynamic a, int)'. // return (a: d, d: 4); Diagnostic(ErrorCode.WRN_TupleLiteralNameMismatch, "d: 4").WithArguments("d", "(dynamic a, int)").WithLocation(22, 47) ); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var nodes = tree.GetCompilationUnitRoot().DescendantNodes(); var x1 = model.GetDeclaredSymbol(nodes.OfType().First()); Assert.Equal("(dynamic a, System.Int32) x1", x1.ToTestDisplayString()); } [Fact] public void LambdaTypeInferenceFails() { var source = @" public class C { public void M() { var x1 = M2(() => { bool flag = true; dynamic d = null; if (flag) { return (a: 1, b: d); } else { if (flag) { return (a: d, c: 3); } else { return (a: d, d: 4); } } }); } public T M2(System.Func f) { return f(); } } "; var comp = CreateCompilation(source); comp.VerifyDiagnostics( // (6,18): error CS0411: The type arguments for method 'C.M2(Func)' cannot be inferred from the usage. Try specifying the type arguments explicitly. // var x1 = M2(() => Diagnostic(ErrorCode.ERR_CantInferMethTypeArgs, "M2").WithArguments("C.M2(System.Func)").WithLocation(6, 18) ); } [Fact] public void WarnForDroppingNamesInConversion() { var source = @" public class C { public void M() { (int a, int) x1 = (1, b: 2); (int a, string) x2 = (1, b: null); } } "; var comp = CreateCompilation(source); comp.VerifyDiagnostics( // (6,31): warning CS8123: The tuple element name 'b' is ignored because a different name or no name is specified by the target type '(int a, int)'. // (int a, int) x1 = (1, b: 2); Diagnostic(ErrorCode.WRN_TupleLiteralNameMismatch, "b: 2").WithArguments("b", "(int a, int)").WithLocation(6, 31), // (7,34): warning CS8123: The tuple element name 'b' is ignored because a different name or no name is specified by the target type '(int a, string)'. // (int a, string) x2 = (1, b: null); Diagnostic(ErrorCode.WRN_TupleLiteralNameMismatch, "b: null").WithArguments("b", "(int a, string)").WithLocation(7, 34), // (6,22): warning CS0219: The variable 'x1' is assigned but its value is never used // (int a, int) x1 = (1, b: 2); Diagnostic(ErrorCode.WRN_UnreferencedVarAssg, "x1").WithArguments("x1").WithLocation(6, 22), // (7,25): warning CS0219: The variable 'x2' is assigned but its value is never used // (int a, string) x2 = (1, b: null); Diagnostic(ErrorCode.WRN_UnreferencedVarAssg, "x2").WithArguments("x2").WithLocation(7, 25) ); } [Fact] public void MethodTypeInferenceMergesTupleNames() { var source = @" public class C { public void M() { var t = M2((a: 1, b: 2), (a: 1, c: 3)); System.Console.Write(t.a); System.Console.Write(t.b); System.Console.Write(t.c); M2((1, 2), (c: 1, d: 3)); M2(new[] { (a: 1, b: 2) }, new[] { (1, 3) }); } public T M2(T x1, T x2) { return x1; } } "; var comp = CreateCompilation(source); comp.VerifyDiagnostics( // (6,27): warning CS8123: The tuple element name 'b' is ignored because a different name is specified by the target type '(int a, int)'. // var t = M2((a: 1, b: 2), (a: 1, c: 3)); Diagnostic(ErrorCode.WRN_TupleLiteralNameMismatch, "b: 2").WithArguments("b", "(int a, int)").WithLocation(6, 27), // (6,41): warning CS8123: The tuple element name 'c' is ignored because a different name is specified by the target type '(int a, int)'. // var t = M2((a: 1, b: 2), (a: 1, c: 3)); Diagnostic(ErrorCode.WRN_TupleLiteralNameMismatch, "c: 3").WithArguments("c", "(int a, int)").WithLocation(6, 41), // (8,32): error CS1061: '(int a, int)' does not contain a definition for 'b' and no extension method 'b' accepting a first argument of type '(int a, int)' could be found (are you missing a using directive or an assembly reference?) // System.Console.Write(t.b); Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "b").WithArguments("(int a, int)", "b").WithLocation(8, 32), // (9,32): error CS1061: '(int a, int)' does not contain a definition for 'c' and no extension method 'c' accepting a first argument of type '(int a, int)' could be found (are you missing a using directive or an assembly reference?) // System.Console.Write(t.c); Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "c").WithArguments("(int a, int)", "c").WithLocation(9, 32), // (10,21): warning CS8123: The tuple element name 'c' is ignored because a different name is specified by the target type '(int, int)'. // M2((1, 2), (c: 1, d: 3)); Diagnostic(ErrorCode.WRN_TupleLiteralNameMismatch, "c: 1").WithArguments("c", "(int, int)").WithLocation(10, 21), // (10,27): warning CS8123: The tuple element name 'd' is ignored because a different name is specified by the target type '(int, int)'. // M2((1, 2), (c: 1, d: 3)); Diagnostic(ErrorCode.WRN_TupleLiteralNameMismatch, "d: 3").WithArguments("d", "(int, int)").WithLocation(10, 27) ); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var nodes = tree.GetCompilationUnitRoot().DescendantNodes(); var invocation1 = model.GetSymbolInfo(nodes.OfType().First()); Assert.Equal("(System.Int32 a, System.Int32)", ((IMethodSymbol)invocation1.Symbol).ReturnType.ToTestDisplayString()); var invocation2 = model.GetSymbolInfo(nodes.OfType().Skip(4).First()); Assert.Equal("(System.Int32, System.Int32)", ((IMethodSymbol)invocation2.Symbol).ReturnType.ToTestDisplayString()); var invocation3 = model.GetSymbolInfo(nodes.OfType().Skip(5).First()); Assert.Equal("(System.Int32, System.Int32)[]", ((IMethodSymbol)invocation3.Symbol).ReturnType.ToTestDisplayString()); } [Fact] public void MethodTypeInferenceDropsCandidates() { var source = @" public class C { public void M() { M2((a: 1, b: 2), (a: (byte)1, c: (byte)3)); M2(((long)1, b: 2), (c: 1, d: (byte)3)); M2((a: (long)1, b: 2), ((byte)1, 3)); } public T M2(T x1, T x2) { return x1; } } "; var comp = CreateCompilation(source); comp.VerifyDiagnostics( // (6,39): warning CS8123: The tuple element name 'c' is ignored because a different name is specified by the target type '(int a, int b)'. // M2((a: 1, b: 2), (a: (byte)1, c: (byte)3)); Diagnostic(ErrorCode.WRN_TupleLiteralNameMismatch, "c: (byte)3").WithArguments("c", "(int a, int b)").WithLocation(6, 39), // (7,30): warning CS8123: The tuple element name 'c' is ignored because a different name is specified by the target type '(long, int b)'. // M2(((long)1, b: 2), (c: 1, d: (byte)3)); Diagnostic(ErrorCode.WRN_TupleLiteralNameMismatch, "c: 1").WithArguments("c", "(long, int b)").WithLocation(7, 30), // (7,36): warning CS8123: The tuple element name 'd' is ignored because a different name is specified by the target type '(long, int b)'. // M2(((long)1, b: 2), (c: 1, d: (byte)3)); Diagnostic(ErrorCode.WRN_TupleLiteralNameMismatch, "d: (byte)3").WithArguments("d", "(long, int b)").WithLocation(7, 36) ); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var nodes = tree.GetCompilationUnitRoot().DescendantNodes(); var invocation1 = model.GetSymbolInfo(nodes.OfType().First()); Assert.Equal("(System.Int32 a, System.Int32 b) C.M2<(System.Int32 a, System.Int32 b)>((System.Int32 a, System.Int32 b) x1, (System.Int32 a, System.Int32 b) x2)", invocation1.Symbol.ToTestDisplayString()); var invocation2 = model.GetSymbolInfo(nodes.OfType().Skip(1).First()); Assert.Equal("(System.Int64, System.Int32 b) C.M2<(System.Int64, System.Int32 b)>((System.Int64, System.Int32 b) x1, (System.Int64, System.Int32 b) x2)", invocation2.Symbol.ToTestDisplayString()); var invocation3 = model.GetSymbolInfo(nodes.OfType().Skip(2).First()); Assert.Equal("(System.Int64 a, System.Int32 b) C.M2<(System.Int64 a, System.Int32 b)>((System.Int64 a, System.Int32 b) x1, (System.Int64 a, System.Int32 b) x2)", invocation3.Symbol.ToTestDisplayString()); } [Fact] public void MethodTypeInferenceMergesDynamic() { var source = @" public class C { public void M() { (dynamic[] a, object[] b) x1 = (null, null); (object[] a, dynamic[] c) x2 = (null, null); M2(x1, x2); } public void M2(T x1, T x2) { } } "; var comp = CreateCompilation(source); comp.VerifyDiagnostics(); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var nodes = tree.GetCompilationUnitRoot().DescendantNodes(); var invocation1 = model.GetSymbolInfo(nodes.OfType().First()); Assert.Equal("void C.M2<(dynamic[] a, dynamic[])>((dynamic[] a, dynamic[]) x1, (dynamic[] a, dynamic[]) x2)", invocation1.Symbol.ToTestDisplayString()); } [Fact(Skip = "https://github.com/dotnet/roslyn/issues/12267")] [WorkItem(12267, "https://github.com/dotnet/roslyn/issues/12267")] public void ConstraintsAndNames() { var source1 = @" using System.Collections.Generic; public abstract class Base { public abstract void M(T x) where T : IEnumerable<(int a, int b)>; } "; var source2 = @" class Derived : Base { public override void M(T x) { foreach (var y in x) { System.Console.WriteLine(y.a); } } }"; var comp1 = CreateCompilation(source1 + trivial2uple + source2); comp1.VerifyDiagnostics(); var comp2 = CreateCompilationWithMscorlib45(source1 + trivial2uple); comp2.VerifyDiagnostics(); // Retargeting (different version of mscorlib) var comp3 = CreateCompilationWithMscorlib46(source2, references: new[] { new CSharpCompilationReference(comp2) }); comp3.VerifyDiagnostics(); // Metadata var comp4 = CreateCompilationWithMscorlib45(source2, references: new[] { comp2.EmitToImageReference() }); comp4.VerifyDiagnostics(); } [Fact] public void OverriddenMethodWithDifferentTupleNamesInReturn() { var source = @" public class Base { public virtual (int a, int b) M1() { return (1, 2); } public virtual (int a, int b) M2() { return (1, 2); } public virtual (int a, int b)[] M3() { return new[] { (1, 2) }; } public virtual System.Nullable<(int a, int b)> M4() { return (1, 2); } public virtual ((int a, int b) c, int d) M5() { return ((1, 2), 3); } public virtual (dynamic a, dynamic b) M6() { return (1, 2); } } public class Derived : Base { public override (int a, int b) M1() { return (1, 2); } public override (int notA, int notB) M2() { return (1, 2); } public override (int notA, int notB)[] M3() { return new[] { (1, 2) }; } public override System.Nullable<(int notA, int notB)> M4() { return (1, 2); } public override ((int notA, int notB) c, int d) M5() { return ((1, 2), 3); } public override (dynamic notA, dynamic) M6() { return (1, 2); } } "; var comp = CreateCompilationWithMscorlib40(source, references: new[] { ValueTupleRef, SystemRuntimeFacadeRef, CSharpRef, SystemCoreRef }); comp.VerifyDiagnostics( // (14,42): error CS8139: 'Derived.M2()': cannot change tuple element names when overriding inherited member 'Base.M2()' // public override (int notA, int notB) M2() { return (1, 2); } Diagnostic(ErrorCode.ERR_CantChangeTupleNamesOnOverride, "M2").WithArguments("Derived.M2()", "Base.M2()").WithLocation(14, 42), // (15,44): error CS8139: 'Derived.M3()': cannot change tuple element names when overriding inherited member 'Base.M3()' // public override (int notA, int notB)[] M3() { return new[] { (1, 2) }; } Diagnostic(ErrorCode.ERR_CantChangeTupleNamesOnOverride, "M3").WithArguments("Derived.M3()", "Base.M3()").WithLocation(15, 44), // (16,59): error CS8139: 'Derived.M4()': cannot change tuple element names when overriding inherited member 'Base.M4()' // public override System.Nullable<(int notA, int notB)> M4() { return (1, 2); } Diagnostic(ErrorCode.ERR_CantChangeTupleNamesOnOverride, "M4").WithArguments("Derived.M4()", "Base.M4()").WithLocation(16, 59), // (17,53): error CS8139: 'Derived.M5()': cannot change tuple element names when overriding inherited member 'Base.M5()' // public override ((int notA, int notB) c, int d) M5() { return ((1, 2), 3); } Diagnostic(ErrorCode.ERR_CantChangeTupleNamesOnOverride, "M5").WithArguments("Derived.M5()", "Base.M5()").WithLocation(17, 53), // (18,45): error CS8139: 'Derived.M6()': cannot change tuple element names when overriding inherited member 'Base.M6()' // public override (dynamic notA, dynamic) M6() { return (1, 2); } Diagnostic(ErrorCode.ERR_CantChangeTupleNamesOnOverride, "M6").WithArguments("Derived.M6()", "Base.M6()").WithLocation(18, 45) ); var m3 = comp.GetMember("Derived.M3").ReturnType; Assert.Equal("(System.Int32 notA, System.Int32 notB)[]", m3.ToTestDisplayString()); Assert.Equal(new[] { "System.Collections.Generic.IList<(System.Int32 notA, System.Int32 notB)>" }, m3.Interfaces().SelectAsArray(t => t.ToTestDisplayString())); } [Fact] public void OverriddenMethodWithDifferentTupleNamesInReturnUsingTypeArg() { var source = @" public class Base { public virtual (T a, T b) M1() { return (default(T), default(T)); } public virtual (T a, T b) M2() { return (default(T), default(T)); } public virtual (T a, T b)[] M3() { return new[] { (default(T), default(T)) }; } public virtual System.Nullable<(T a, T b)> M4() { return (default(T), default(T)); } public virtual ((T a, T b) c, T d) M5() { return ((default(T), default(T)), default(T)); } public virtual (dynamic a, dynamic b) M6() { return (default(T), default(T)); } } public class Derived : Base { public override (T a, T b) M1() { return (default(T), default(T)); } public override (T notA, T notB) M2() { return (default(T), default(T)); } public override (T notA, T notB)[] M3() { return new[] { (default(T), default(T)) }; } public override System.Nullable<(T notA, T notB)> M4() { return (default(T), default(T)); } public override ((T notA, T notB) c, T d) M5() { return ((default(T), default(T)), default(T)); } public override (dynamic notA, dynamic) M6() { return (default(T), default(T)); } } "; var comp = CreateCompilation(source, references: new[] { CSharpRef }); comp.VerifyDiagnostics( // (14,38): error CS8139: 'Derived.M2()': cannot change tuple element names when overriding inherited member 'Base.M2()' // public override (T notA, T notB) M2() { return (default(T), default(T)); } Diagnostic(ErrorCode.ERR_CantChangeTupleNamesOnOverride, "M2").WithArguments("Derived.M2()", "Base.M2()").WithLocation(14, 38), // (15,40): error CS8139: 'Derived.M3()': cannot change tuple element names when overriding inherited member 'Base.M3()' // public override (T notA, T notB)[] M3() { return new[] { (default(T), default(T)) }; } Diagnostic(ErrorCode.ERR_CantChangeTupleNamesOnOverride, "M3").WithArguments("Derived.M3()", "Base.M3()").WithLocation(15, 40), // (16,55): error CS8139: 'Derived.M4()': cannot change tuple element names when overriding inherited member 'Base.M4()' // public override System.Nullable<(T notA, T notB)> M4() { return (default(T), default(T)); } Diagnostic(ErrorCode.ERR_CantChangeTupleNamesOnOverride, "M4").WithArguments("Derived.M4()", "Base.M4()").WithLocation(16, 55), // (17,47): error CS8139: 'Derived.M5()': cannot change tuple element names when overriding inherited member 'Base.M5()' // public override ((T notA, T notB) c, T d) M5() { return ((default(T), default(T)), default(T)); } Diagnostic(ErrorCode.ERR_CantChangeTupleNamesOnOverride, "M5").WithArguments("Derived.M5()", "Base.M5()").WithLocation(17, 47), // (18,45): error CS8139: 'Derived.M6()': cannot change tuple element names when overriding inherited member 'Base.M6()' // public override (dynamic notA, dynamic) M6() { return (default(T), default(T)); } Diagnostic(ErrorCode.ERR_CantChangeTupleNamesOnOverride, "M6").WithArguments("Derived.M6()", "Base.M6()").WithLocation(18, 45) ); } [Fact] public void OverriddenMethodWithDifferentTupleNamesInParameters() { var source = @" public class Base { public virtual void M1((int a, int b) x) { } public virtual void M2((int a, int b)[] x) { } public virtual void M3(System.Nullable<(int a, int b)> x) { } public virtual void M4(((int a, int b) c, int d) x) { } } public class Derived : Base { public override void M1((int notA, int notB) y) { } public override void M2((int notA, int notB)[] x) { } public override void M3(System.Nullable<(int notA, int notB)> x) { } public override void M4(((int notA, int notB) c, int d) x) { } } "; var comp = CreateCompilation(source); comp.VerifyDiagnostics( // (12,26): error CS8139: 'Derived.M2((int notA, int notB)[])': cannot change tuple element names when overriding inherited member 'Base.M2((int a, int b)[])' // public override void M2((int notA, int notB)[] x) { } Diagnostic(ErrorCode.ERR_CantChangeTupleNamesOnOverride, "M2").WithArguments("Derived.M2((int notA, int notB)[])", "Base.M2((int a, int b)[])").WithLocation(12, 26), // (13,26): error CS8139: 'Derived.M3((int notA, int notB)?)': cannot change tuple element names when overriding inherited member 'Base.M3((int a, int b)?)' // public override void M3(System.Nullable<(int notA, int notB)> x) { } Diagnostic(ErrorCode.ERR_CantChangeTupleNamesOnOverride, "M3").WithArguments("Derived.M3((int notA, int notB)?)", "Base.M3((int a, int b)?)").WithLocation(13, 26), // (14,26): error CS8139: 'Derived.M4(((int notA, int notB) c, int d))': cannot change tuple element names when overriding inherited member 'Base.M4(((int a, int b) c, int d))' // public override void M4(((int notA, int notB) c, int d) x) { } Diagnostic(ErrorCode.ERR_CantChangeTupleNamesOnOverride, "M4").WithArguments("Derived.M4(((int notA, int notB) c, int d))", "Base.M4(((int a, int b) c, int d))").WithLocation(14, 26), // (11,26): error CS8139: 'Derived.M1((int notA, int notB))': cannot change tuple element names when overriding inherited member 'Base.M1((int a, int b))' // public override void M1((int notA, int notB) y) { } Diagnostic(ErrorCode.ERR_CantChangeTupleNamesOnOverride, "M1").WithArguments("Derived.M1((int notA, int notB))", "Base.M1((int a, int b))").WithLocation(11, 26) ); } [Fact] public void OverriddenMethodWithDifferentTupleNamesInParametersUsingTypeArg() { var source = @" public class Base { public virtual void M1((T a, T b) x) { } public virtual void M2((T a, T b)[] x) { } public virtual void M3(System.Nullable<(T a, T b)> x) { } public virtual void M4(((T a, T b) c, T d) x) { } } public class Derived : Base { public override void M1((T notA, T notB) y) { } public override void M2((T notA, T notB)[] x) { } public override void M3(System.Nullable<(T notA, T notB)> x) { } public override void M4(((T notA, T notB) c, T d) x) { } } "; var comp = CreateCompilation(source); comp.VerifyDiagnostics( // (12,26): error CS8139: 'Derived.M2((T notA, T notB)[])': cannot change tuple element names when overriding inherited member 'Base.M2((T a, T b)[])' // public override void M2((T notA, T notB)[] x) { } Diagnostic(ErrorCode.ERR_CantChangeTupleNamesOnOverride, "M2").WithArguments("Derived.M2((T notA, T notB)[])", "Base.M2((T a, T b)[])").WithLocation(12, 26), // (13,26): error CS8139: 'Derived.M3((T notA, T notB)?)': cannot change tuple element names when overriding inherited member 'Base.M3((T a, T b)?)' // public override void M3(System.Nullable<(T notA, T notB)> x) { } Diagnostic(ErrorCode.ERR_CantChangeTupleNamesOnOverride, "M3").WithArguments("Derived.M3((T notA, T notB)?)", "Base.M3((T a, T b)?)").WithLocation(13, 26), // (14,26): error CS8139: 'Derived.M4(((T notA, T notB) c, T d))': cannot change tuple element names when overriding inherited member 'Base.M4(((T a, T b) c, T d))' // public override void M4(((T notA, T notB) c, T d) x) { } Diagnostic(ErrorCode.ERR_CantChangeTupleNamesOnOverride, "M4").WithArguments("Derived.M4(((T notA, T notB) c, T d))", "Base.M4(((T a, T b) c, T d))").WithLocation(14, 26), // (11,26): error CS8139: 'Derived.M1((T notA, T notB))': cannot change tuple element names when overriding inherited member 'Base.M1((T a, T b))' // public override void M1((T notA, T notB) y) { } Diagnostic(ErrorCode.ERR_CantChangeTupleNamesOnOverride, "M1").WithArguments("Derived.M1((T notA, T notB))", "Base.M1((T a, T b))").WithLocation(11, 26) ); } [Fact] public void OverriddenPropertiesWithDifferentTupleNames() { var source = @" public class Base { public virtual (int a, int b) P1 { get { return (1, 2); } set { } } public virtual (int a, int b)[] P2 { get; set; } public virtual (int a, int b)? P3 { get { return (1, 2); } set { } } public virtual ((int a, int b) c, int d) P4 { get; set; } } public class Derived : Base { public override (int notA, int notB) P1 { get { return (1, 2); } set { } } public override (int notA, int notB)[] P2 { get; set; } public override (int notA, int notB)? P3 { get { return (1, 2); } set { } } public override ((int notA, int notB) c, int d) P4 { get; set; } } "; var comp = CreateCompilation(source); comp.VerifyDiagnostics( // (12,44): error CS8139: 'Derived.P2': cannot change tuple element names when overriding inherited member 'Base.P2' // public override (int notA, int notB)[] P2 { get; set; } Diagnostic(ErrorCode.ERR_CantChangeTupleNamesOnOverride, "P2").WithArguments("Derived.P2", "Base.P2").WithLocation(12, 44), // (12,49): error CS8139: 'Derived.P2.get': cannot change tuple element names when overriding inherited member 'Base.P2.get' // public override (int notA, int notB)[] P2 { get; set; } Diagnostic(ErrorCode.ERR_CantChangeTupleNamesOnOverride, "get").WithArguments("Derived.P2.get", "Base.P2.get").WithLocation(12, 49), // (12,54): error CS8139: 'Derived.P2.set': cannot change tuple element names when overriding inherited member 'Base.P2.set' // public override (int notA, int notB)[] P2 { get; set; } Diagnostic(ErrorCode.ERR_CantChangeTupleNamesOnOverride, "set").WithArguments("Derived.P2.set", "Base.P2.set").WithLocation(12, 54), // (13,43): error CS8139: 'Derived.P3': cannot change tuple element names when overriding inherited member 'Base.P3' // public override (int notA, int notB)? P3 { get { return (1, 2); } set { } } Diagnostic(ErrorCode.ERR_CantChangeTupleNamesOnOverride, "P3").WithArguments("Derived.P3", "Base.P3").WithLocation(13, 43), // (13,48): error CS8139: 'Derived.P3.get': cannot change tuple element names when overriding inherited member 'Base.P3.get' // public override (int notA, int notB)? P3 { get { return (1, 2); } set { } } Diagnostic(ErrorCode.ERR_CantChangeTupleNamesOnOverride, "get").WithArguments("Derived.P3.get", "Base.P3.get").WithLocation(13, 48), // (13,71): error CS8139: 'Derived.P3.set': cannot change tuple element names when overriding inherited member 'Base.P3.set' // public override (int notA, int notB)? P3 { get { return (1, 2); } set { } } Diagnostic(ErrorCode.ERR_CantChangeTupleNamesOnOverride, "set").WithArguments("Derived.P3.set", "Base.P3.set").WithLocation(13, 71), // (14,53): error CS8139: 'Derived.P4': cannot change tuple element names when overriding inherited member 'Base.P4' // public override ((int notA, int notB) c, int d) P4 { get; set; } Diagnostic(ErrorCode.ERR_CantChangeTupleNamesOnOverride, "P4").WithArguments("Derived.P4", "Base.P4").WithLocation(14, 53), // (14,58): error CS8139: 'Derived.P4.get': cannot change tuple element names when overriding inherited member 'Base.P4.get' // public override ((int notA, int notB) c, int d) P4 { get; set; } Diagnostic(ErrorCode.ERR_CantChangeTupleNamesOnOverride, "get").WithArguments("Derived.P4.get", "Base.P4.get").WithLocation(14, 58), // (14,63): error CS8139: 'Derived.P4.set': cannot change tuple element names when overriding inherited member 'Base.P4.set' // public override ((int notA, int notB) c, int d) P4 { get; set; } Diagnostic(ErrorCode.ERR_CantChangeTupleNamesOnOverride, "set").WithArguments("Derived.P4.set", "Base.P4.set").WithLocation(14, 63), // (11,42): error CS8139: 'Derived.P1': cannot change tuple element names when overriding inherited member 'Base.P1' // public override (int notA, int notB) P1 { get { return (1, 2); } set { } } Diagnostic(ErrorCode.ERR_CantChangeTupleNamesOnOverride, "P1").WithArguments("Derived.P1", "Base.P1").WithLocation(11, 42), // (11,47): error CS8139: 'Derived.P1.get': cannot change tuple element names when overriding inherited member 'Base.P1.get' // public override (int notA, int notB) P1 { get { return (1, 2); } set { } } Diagnostic(ErrorCode.ERR_CantChangeTupleNamesOnOverride, "get").WithArguments("Derived.P1.get", "Base.P1.get").WithLocation(11, 47), // (11,70): error CS8139: 'Derived.P1.set': cannot change tuple element names when overriding inherited member 'Base.P1.set' // public override (int notA, int notB) P1 { get { return (1, 2); } set { } } Diagnostic(ErrorCode.ERR_CantChangeTupleNamesOnOverride, "set").WithArguments("Derived.P1.set", "Base.P1.set").WithLocation(11, 70) ); } [Fact] public void OverriddenEventsWithDifferentTupleNames() { var source = @" using System; public class Base { public virtual event Func<(int a, int b)> E1; public virtual event Func<(int a, int b)> E2; public virtual event Func<(int a, int b)[]> E3; public virtual event Func<((int a, int b) c, int d)> E4; void M() { E1(); E2(); E3(); E4(); } } public class Derived : Base { public override event Func<(int a, int b)> E1; public override event Func<(int notA, int notB)> E2; public override event Func<(int notA, int notB)[]> E3; public override event Func<((int notA, int) c, int d)> E4; void M() { E1(); E2(); E3(); E4(); } } "; var comp = CreateCompilation(source); comp.VerifyDiagnostics( // (15,54): error CS8139: 'Derived.E2': cannot change tuple element names when overriding inherited member 'Base.E2' // public override event Func<(int notA, int notB)> E2; Diagnostic(ErrorCode.ERR_CantChangeTupleNamesOnOverride, "E2").WithArguments("Derived.E2", "Base.E2").WithLocation(15, 54), // (15,54): error CS8139: 'Derived.E2.add': cannot change tuple element names when overriding inherited member 'Base.E2.add' // public override event Func<(int notA, int notB)> E2; Diagnostic(ErrorCode.ERR_CantChangeTupleNamesOnOverride, "E2").WithArguments("Derived.E2.add", "Base.E2.add").WithLocation(15, 54), // (15,54): error CS8139: 'Derived.E2.remove': cannot change tuple element names when overriding inherited member 'Base.E2.remove' // public override event Func<(int notA, int notB)> E2; Diagnostic(ErrorCode.ERR_CantChangeTupleNamesOnOverride, "E2").WithArguments("Derived.E2.remove", "Base.E2.remove").WithLocation(15, 54), // (16,56): error CS8139: 'Derived.E3': cannot change tuple element names when overriding inherited member 'Base.E3' // public override event Func<(int notA, int notB)[]> E3; Diagnostic(ErrorCode.ERR_CantChangeTupleNamesOnOverride, "E3").WithArguments("Derived.E3", "Base.E3").WithLocation(16, 56), // (16,56): error CS8139: 'Derived.E3.add': cannot change tuple element names when overriding inherited member 'Base.E3.add' // public override event Func<(int notA, int notB)[]> E3; Diagnostic(ErrorCode.ERR_CantChangeTupleNamesOnOverride, "E3").WithArguments("Derived.E3.add", "Base.E3.add").WithLocation(16, 56), // (16,56): error CS8139: 'Derived.E3.remove': cannot change tuple element names when overriding inherited member 'Base.E3.remove' // public override event Func<(int notA, int notB)[]> E3; Diagnostic(ErrorCode.ERR_CantChangeTupleNamesOnOverride, "E3").WithArguments("Derived.E3.remove", "Base.E3.remove").WithLocation(16, 56), // (17,60): error CS8139: 'Derived.E4': cannot change tuple element names when overriding inherited member 'Base.E4' // public override event Func<((int notA, int) c, int d)> E4; Diagnostic(ErrorCode.ERR_CantChangeTupleNamesOnOverride, "E4").WithArguments("Derived.E4", "Base.E4").WithLocation(17, 60), // (17,60): error CS8139: 'Derived.E4.add': cannot change tuple element names when overriding inherited member 'Base.E4.add' // public override event Func<((int notA, int) c, int d)> E4; Diagnostic(ErrorCode.ERR_CantChangeTupleNamesOnOverride, "E4").WithArguments("Derived.E4.add", "Base.E4.add").WithLocation(17, 60), // (17,60): error CS8139: 'Derived.E4.remove': cannot change tuple element names when overriding inherited member 'Base.E4.remove' // public override event Func<((int notA, int) c, int d)> E4; Diagnostic(ErrorCode.ERR_CantChangeTupleNamesOnOverride, "E4").WithArguments("Derived.E4.remove", "Base.E4.remove").WithLocation(17, 60) ); } [Fact] public void HiddenMethodsWithDifferentTupleNames() { var source = @" public class Base { public virtual int M0() { return 0; } public virtual (int a, int b) M1() { return (1, 2); } public virtual (int a, int b)[] M2() { return new[] { (1, 2) }; } public virtual System.Nullable<(int a, int b)> M3() { return null; } public virtual ((int a, int b) c, int d) M4() { return ((1, 2), 3); } } public class Derived : Base { public string M0() { return null; } public (int a, int b) M1() { return (1, 2); } public (int notA, int notB)[] M2() { return new[] { (1, 2) }; } public System.Nullable<(int notA, int notB)> M3() { return null; } public ((int notA, int notB) c, int d) M4() { return ((1, 2), 3); } } "; var comp = CreateCompilation(source); comp.VerifyDiagnostics( // (13,27): warning CS0114: 'Derived.M1()' hides inherited member 'Base.M1()'. To make the current member override that implementation, add the override keyword. Otherwise add the new keyword. // public (int a, int b) M1() { return (1, 2); } Diagnostic(ErrorCode.WRN_NewOrOverrideExpected, "M1").WithArguments("Derived.M1()", "Base.M1()").WithLocation(13, 27), // (14,35): warning CS0114: 'Derived.M2()' hides inherited member 'Base.M2()'. To make the current member override that implementation, add the override keyword. Otherwise add the new keyword. // public (int notA, int notB)[] M2() { return new[] { (1, 2) }; } Diagnostic(ErrorCode.WRN_NewOrOverrideExpected, "M2").WithArguments("Derived.M2()", "Base.M2()").WithLocation(14, 35), // (15,50): warning CS0114: 'Derived.M3()' hides inherited member 'Base.M3()'. To make the current member override that implementation, add the override keyword. Otherwise add the new keyword. // public System.Nullable<(int notA, int notB)> M3() { return null; } Diagnostic(ErrorCode.WRN_NewOrOverrideExpected, "M3").WithArguments("Derived.M3()", "Base.M3()").WithLocation(15, 50), // (16,44): warning CS0114: 'Derived.M4()' hides inherited member 'Base.M4()'. To make the current member override that implementation, add the override keyword. Otherwise add the new keyword. // public ((int notA, int notB) c, int d) M4() { return ((1, 2), 3); } Diagnostic(ErrorCode.WRN_NewOrOverrideExpected, "M4").WithArguments("Derived.M4()", "Base.M4()").WithLocation(16, 44), // (12,19): warning CS0114: 'Derived.M0()' hides inherited member 'Base.M0()'. To make the current member override that implementation, add the override keyword. Otherwise add the new keyword. // public string M0() { return null; } Diagnostic(ErrorCode.WRN_NewOrOverrideExpected, "M0").WithArguments("Derived.M0()", "Base.M0()").WithLocation(12, 19) ); } [Fact] [WorkItem(20528, "https://github.com/dotnet/roslyn/issues/20528")] public void HiddenMethodsWithNoNames() { var source = @" public class Base { public virtual (int a, int b) M1() { return (1, 2); } } public class Derived : Base { public (int, int) M1() { return (1, 2); } } "; var comp = CreateCompilation(source); comp.VerifyDiagnostics( // (8,23): warning CS0114: 'Derived.M1()' hides inherited member 'Base.M1()'. To make the current member override that implementation, add the override keyword. Otherwise add the new keyword. // public (int, int) M1() { return (1, 2); } Diagnostic(ErrorCode.WRN_NewOrOverrideExpected, "M1").WithArguments("Derived.M1()", "Base.M1()").WithLocation(8, 23) ); } [Fact] public void DuplicateMethodDetectionWithDifferentTupleNames() { var source = @" public class C { public void M1((int a, int b) x) { } public void M1((int notA, int notB) x) { } public void M2((int a, int b)[] x) { } public void M2((int notA, int notB)[] x) { } public void M3(System.Nullable<(int a, int b)> x) { } public void M3(System.Nullable<(int notA, int notB)> x) { } public void M4(((int a, int b) c, int d) x) { } public void M4(((int notA, int notB) c, int d) x) { } } "; var comp = CreateCompilation(source); comp.VerifyDiagnostics( // (5,17): error CS0111: Type 'C' already defines a member called 'M1' with the same parameter types // public void M1((int notA, int notB) x) { } Diagnostic(ErrorCode.ERR_MemberAlreadyExists, "M1").WithArguments("M1", "C").WithLocation(5, 17), // (8,17): error CS0111: Type 'C' already defines a member called 'M2' with the same parameter types // public void M2((int notA, int notB)[] x) { } Diagnostic(ErrorCode.ERR_MemberAlreadyExists, "M2").WithArguments("M2", "C").WithLocation(8, 17), // (11,17): error CS0111: Type 'C' already defines a member called 'M3' with the same parameter types // public void M3(System.Nullable<(int notA, int notB)> x) { } Diagnostic(ErrorCode.ERR_MemberAlreadyExists, "M3").WithArguments("M3", "C").WithLocation(11, 17), // (14,17): error CS0111: Type 'C' already defines a member called 'M4' with the same parameter types // public void M4(((int notA, int notB) c, int d) x) { } Diagnostic(ErrorCode.ERR_MemberAlreadyExists, "M4").WithArguments("M4", "C").WithLocation(14, 17) ); } [Fact] public void HiddenMethodParametersWithDifferentTupleNames() { var source = @" public class Base { public virtual void M1((int a, int b) x) { } public virtual void M2((int a, int b)[] x) { } public virtual void M3(System.Nullable<(int a, int b)> x) { } public virtual void M4(((int a, int b) c, int d) x) { } } public class Derived : Base { public void M1((int notA, int notB) y) { } public void M2((int notA, int notB)[] x) { } public void M3(System.Nullable<(int notA, int notB)> x) { } public void M4(((int notA, int notB) c, int d) x) { } } "; var comp = CreateCompilation(source); comp.VerifyDiagnostics( // (12,17): warning CS0114: 'Derived.M2((int notA, int notB)[])' hides inherited member 'Base.M2((int a, int b)[])'. To make the current member override that implementation, add the override keyword. Otherwise add the new keyword. // public void M2((int notA, int notB)[] x) { } Diagnostic(ErrorCode.WRN_NewOrOverrideExpected, "M2").WithArguments("Derived.M2((int notA, int notB)[])", "Base.M2((int a, int b)[])").WithLocation(12, 17), // (13,17): warning CS0114: 'Derived.M3((int notA, int notB)?)' hides inherited member 'Base.M3((int a, int b)?)'. To make the current member override that implementation, add the override keyword. Otherwise add the new keyword. // public void M3(System.Nullable<(int notA, int notB)> x) { } Diagnostic(ErrorCode.WRN_NewOrOverrideExpected, "M3").WithArguments("Derived.M3((int notA, int notB)?)", "Base.M3((int a, int b)?)").WithLocation(13, 17), // (14,17): warning CS0114: 'Derived.M4(((int notA, int notB) c, int d))' hides inherited member 'Base.M4(((int a, int b) c, int d))'. To make the current member override that implementation, add the override keyword. Otherwise add the new keyword. // public void M4(((int notA, int notB) c, int d) x) { } Diagnostic(ErrorCode.WRN_NewOrOverrideExpected, "M4").WithArguments("Derived.M4(((int notA, int notB) c, int d))", "Base.M4(((int a, int b) c, int d))").WithLocation(14, 17), // (11,17): warning CS0114: 'Derived.M1((int notA, int notB))' hides inherited member 'Base.M1((int a, int b))'. To make the current member override that implementation, add the override keyword. Otherwise add the new keyword. // public void M1((int notA, int notB) y) { } Diagnostic(ErrorCode.WRN_NewOrOverrideExpected, "M1").WithArguments("Derived.M1((int notA, int notB))", "Base.M1((int a, int b))").WithLocation(11, 17) ); } [Fact] public void ExplicitInterfaceImplementationWithDifferentTupleNames() { var source = @" public interface I0 { void M1((int, int b) x); void M2((int a, int b) x); (int, int b) MR1(); (int a, int b) MR2(); } public class C : I0 { void I0.M1((int notMissing, int b) z) { } void I0.M2((int notA, int notB) z) { } (int notMissing, int b) I0.MR1() { return (1, 2); } (int notA, int notB) I0.MR2() { return (1, 2); } } "; var comp = CreateCompilation(source); comp.VerifyDiagnostics( // (12,13): error CS8141: The tuple element names in the signature of method 'C.I0.M2((int notA, int notB))' must match the tuple element names of interface method 'I0.M2((int a, int b))' (including on the return type). // void I0.M2((int notA, int notB) z) { } Diagnostic(ErrorCode.ERR_ImplBadTupleNames, "M2").WithArguments("C.I0.M2((int notA, int notB))", "I0.M2((int a, int b))").WithLocation(12, 13), // (13,32): error CS8141: The tuple element names in the signature of method 'C.I0.MR1()' must match the tuple element names of interface method 'I0.MR1()' (including on the return type). // (int notMissing, int b) I0.MR1() { return (1, 2); } Diagnostic(ErrorCode.ERR_ImplBadTupleNames, "MR1").WithArguments("C.I0.MR1()", "I0.MR1()").WithLocation(13, 32), // (14,29): error CS8141: The tuple element names in the signature of method 'C.I0.MR2()' must match the tuple element names of interface method 'I0.MR2()' (including on the return type). // (int notA, int notB) I0.MR2() { return (1, 2); } Diagnostic(ErrorCode.ERR_ImplBadTupleNames, "MR2").WithArguments("C.I0.MR2()", "I0.MR2()").WithLocation(14, 29), // (11,13): error CS8141: The tuple element names in the signature of method 'C.I0.M1((int notMissing, int b))' must match the tuple element names of interface method 'I0.M1((int, int b))' (including on the return type). // void I0.M1((int notMissing, int b) z) { } Diagnostic(ErrorCode.ERR_ImplBadTupleNames, "M1").WithArguments("C.I0.M1((int notMissing, int b))", "I0.M1((int, int b))").WithLocation(11, 13) ); } [Fact] [WorkItem(20528, "https://github.com/dotnet/roslyn/issues/20528")] public void ExplicitInterfaceImplementationWithNoNames() { var source = @" public interface I0 { void M1((int, int b) x); void M2((int a, int b) x); (int, int b) MR1(); (int a, int b) MR2(); (int a, int b) P { get; set; } } public class C : I0 { void I0.M1((int, int) z) { } void I0.M2((int, int) z) { } (int, int) I0.MR1() { return (1, 2); } (int, int) I0.MR2() { return (1, 2); } (int, int) I0.P { get; set; } } "; var comp = CreateCompilation(source); comp.VerifyDiagnostics(); } [Fact] public void InterfaceHidingAnotherInterfaceWithDifferentTupleNames() { var source = @" public interface I0 { void M2((int a, int b) x); (int a, int b) MR2(); } public interface I1 : I0 { void M2((int notA, int notB) z); (int notA, int notB) MR2(); } "; var comp = CreateCompilation(source); comp.VerifyDiagnostics( // (10,26): warning CS0108: 'I1.MR2()' hides inherited member 'I0.MR2()'. Use the new keyword if hiding was intended. // (int notA, int notB) MR2(); Diagnostic(ErrorCode.WRN_NewRequired, "MR2").WithArguments("I1.MR2()", "I0.MR2()").WithLocation(10, 26), // (9,10): warning CS0108: 'I1.M2((int notA, int notB))' hides inherited member 'I0.M2((int a, int b))'. Use the new keyword if hiding was intended. // void M2((int notA, int notB) z); Diagnostic(ErrorCode.WRN_NewRequired, "M2").WithArguments("I1.M2((int notA, int notB))", "I0.M2((int a, int b))").WithLocation(9, 10) ); } [Fact] public void HidingInterfaceMethodsWithDifferentTupleNames() { var source = @" public interface I0 { void M1((int a, int b) x); void M2((int a, int b) x); void M3((int a, int b) x); void M4((int a, int b) x); (int a, int b) M5(); (int a, int b) M6(); } public interface I1 : I0 { void M1((int notA, int notB) x); void M2((int a, int b) x); new void M3((int a, int b) x); new void M4((int notA, int notB) x); (int notA, int notB) M5(); (int a, int b) M6(); } "; var comp = CreateCompilation(source); comp.VerifyDiagnostics( // (18,20): warning CS0108: 'I1.M6()' hides inherited member 'I0.M6()'. Use the new keyword if hiding was intended. // (int a, int b) M6(); Diagnostic(ErrorCode.WRN_NewRequired, "M6").WithArguments("I1.M6()", "I0.M6()").WithLocation(18, 20), // (14,10): warning CS0108: 'I1.M2((int a, int b))' hides inherited member 'I0.M2((int a, int b))'. Use the new keyword if hiding was intended. // void M2((int a, int b) x); Diagnostic(ErrorCode.WRN_NewRequired, "M2").WithArguments("I1.M2((int a, int b))", "I0.M2((int a, int b))").WithLocation(14, 10), // (17,26): warning CS0108: 'I1.M5()' hides inherited member 'I0.M5()'. Use the new keyword if hiding was intended. // (int notA, int notB) M5(); Diagnostic(ErrorCode.WRN_NewRequired, "M5").WithArguments("I1.M5()", "I0.M5()").WithLocation(17, 26), // (13,10): warning CS0108: 'I1.M1((int notA, int notB))' hides inherited member 'I0.M1((int a, int b))'. Use the new keyword if hiding was intended. // void M1((int notA, int notB) x); Diagnostic(ErrorCode.WRN_NewRequired, "M1").WithArguments("I1.M1((int notA, int notB))", "I0.M1((int a, int b))").WithLocation(13, 10) ); } [Fact] public void DuplicateInterfaceDetectionWithDifferentTupleNames_01() { var source = @" public interface I0 { } public class C1 : I0<(int a, int b)>, I0<(int notA, int notB)> { } public class C2 : I0<(int a, int b)>, I0<(int a, int b)> { } public class C3 : I0, I0 { } public class C4 : I0<(int a, int b)>, I0<(T a, U b)> { } public class C5 : I0<(int a, int b)>, I0<(T notA, U notB)> { } "; var comp = CreateCompilation(source); comp.VerifyDiagnostics( // (5,28): error CS0528: 'I0' is already listed in interface list // public class C3 : I0, I0 { } Diagnostic(ErrorCode.ERR_DuplicateInterfaceInBaseList, "I0").WithArguments("I0").WithLocation(5, 28), // (4,39): error CS0528: 'I0<(int a, int b)>' is already listed in interface list // public class C2 : I0<(int a, int b)>, I0<(int a, int b)> { } Diagnostic(ErrorCode.ERR_DuplicateInterfaceInBaseList, "I0<(int a, int b)>").WithArguments("I0<(int a, int b)>").WithLocation(4, 39), // (3,14): error CS8140: 'I0<(int notA, int notB)>' is already listed in the interface list on type 'C1' with different tuple element names, as 'I0<(int a, int b)>'. // public class C1 : I0<(int a, int b)>, I0<(int notA, int notB)> { } Diagnostic(ErrorCode.ERR_DuplicateInterfaceWithTupleNamesInBaseList, "C1").WithArguments("I0<(int notA, int notB)>", "I0<(int a, int b)>", "C1").WithLocation(3, 14), // (6,14): error CS0695: 'C4' cannot implement both 'I0<(int a, int b)>' and 'I0<(T a, U b)>' because they may unify for some type parameter substitutions // public class C4 : I0<(int a, int b)>, I0<(T a, U b)> { } Diagnostic(ErrorCode.ERR_UnifyingInterfaceInstantiations, "C4").WithArguments("C4", "I0<(int a, int b)>", "I0<(T a, U b)>").WithLocation(6, 14), // (7,14): error CS0695: 'C5' cannot implement both 'I0<(int a, int b)>' and 'I0<(T notA, U notB)>' because they may unify for some type parameter substitutions // public class C5 : I0<(int a, int b)>, I0<(T notA, U notB)> { } Diagnostic(ErrorCode.ERR_UnifyingInterfaceInstantiations, "C5").WithArguments("C5", "I0<(int a, int b)>", "I0<(T notA, U notB)>").WithLocation(7, 14) ); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var nodes = tree.GetCompilationUnitRoot().DescendantNodes(); var c1 = nodes.OfType().First(); Assert.Equal(2, model.GetDeclaredSymbol(c1).AllInterfaces.Count()); Assert.Equal("I0<(System.Int32 a, System.Int32 b)>", model.GetDeclaredSymbol(c1).AllInterfaces[0].ToTestDisplayString()); Assert.Equal("I0<(System.Int32 notA, System.Int32 notB)>", model.GetDeclaredSymbol(c1).AllInterfaces[1].ToTestDisplayString()); var c2 = nodes.OfType().Skip(1).First(); Assert.Equal(1, model.GetDeclaredSymbol(c2).AllInterfaces.Count()); Assert.Equal("I0<(System.Int32 a, System.Int32 b)>", model.GetDeclaredSymbol(c2).AllInterfaces[0].ToTestDisplayString()); var c3 = nodes.OfType().Skip(2).First(); Assert.Equal(1, model.GetDeclaredSymbol(c3).AllInterfaces.Count()); Assert.Equal("I0", model.GetDeclaredSymbol(c3).AllInterfaces[0].ToTestDisplayString()); } [Fact] [WorkItem(31977, "https://github.com/dotnet/roslyn/issues/31977")] public void DuplicateInterfaceDetectionWithDifferentTupleNames_02() { var source = @" public interface I1 { void M(); } public interface I2 : I1<(int a, int b)> { } public interface I3 : I1<(int c, int d)> { } public class C1 : I2, I1<(int c, int d)> { void I1<(int a, int b)>.M(){} void I1<(int c, int d)>.M(){} } public class C2 : I1<(int c, int d)>, I2 { void I1<(int a, int b)>.M(){} void I1<(int c, int d)>.M(){} } public class C3 : I1<(int a, int b)>, I1<(int c, int d)> { void I1<(int a, int b)>.M(){} void I1<(int c, int d)>.M(){} } public class C4 : I2, I3 { void I1<(int a, int b)>.M(){} void I1<(int c, int d)>.M(){} } "; var comp = (Compilation)CreateCompilation(source); comp.VerifyDiagnostics( // (10,14): error CS8140: 'I1<(int c, int d)>' is already listed in the interface list on type 'C1' with different tuple element names, as 'I1<(int a, int b)>'. // public class C1 : I2, I1<(int c, int d)> Diagnostic(ErrorCode.ERR_DuplicateInterfaceWithTupleNamesInBaseList, "C1").WithArguments("I1<(int c, int d)>", "I1<(int a, int b)>", "C1").WithLocation(10, 14), // (10,14): error CS8646: 'I1<(int a, int b)>.M()' is explicitly implemented more than once. // public class C1 : I2, I1<(int c, int d)> Diagnostic(ErrorCode.ERR_DuplicateExplicitImpl, "C1").WithArguments("I1<(int a, int b)>.M()").WithLocation(10, 14), // (10,14): error CS8646: 'I1<(int c, int d)>.M()' is explicitly implemented more than once. // public class C1 : I2, I1<(int c, int d)> Diagnostic(ErrorCode.ERR_DuplicateExplicitImpl, "C1").WithArguments("I1<(int c, int d)>.M()").WithLocation(10, 14), // (16,14): error CS8140: 'I1<(int a, int b)>' is already listed in the interface list on type 'C2' with different tuple element names, as 'I1<(int c, int d)>'. // public class C2 : I1<(int c, int d)>, I2 Diagnostic(ErrorCode.ERR_DuplicateInterfaceWithTupleNamesInBaseList, "C2").WithArguments("I1<(int a, int b)>", "I1<(int c, int d)>", "C2").WithLocation(16, 14), // (16,14): error CS8646: 'I1<(int c, int d)>.M()' is explicitly implemented more than once. // public class C2 : I1<(int c, int d)>, I2 Diagnostic(ErrorCode.ERR_DuplicateExplicitImpl, "C2").WithArguments("I1<(int c, int d)>.M()").WithLocation(16, 14), // (16,14): error CS8646: 'I1<(int a, int b)>.M()' is explicitly implemented more than once. // public class C2 : I1<(int c, int d)>, I2 Diagnostic(ErrorCode.ERR_DuplicateExplicitImpl, "C2").WithArguments("I1<(int a, int b)>.M()").WithLocation(16, 14), // (22,14): error CS8140: 'I1<(int c, int d)>' is already listed in the interface list on type 'C3' with different tuple element names, as 'I1<(int a, int b)>'. // public class C3 : I1<(int a, int b)>, I1<(int c, int d)> Diagnostic(ErrorCode.ERR_DuplicateInterfaceWithTupleNamesInBaseList, "C3").WithArguments("I1<(int c, int d)>", "I1<(int a, int b)>", "C3").WithLocation(22, 14), // (22,14): error CS8646: 'I1<(int a, int b)>.M()' is explicitly implemented more than once. // public class C3 : I1<(int a, int b)>, I1<(int c, int d)> Diagnostic(ErrorCode.ERR_DuplicateExplicitImpl, "C3").WithArguments("I1<(int a, int b)>.M()").WithLocation(22, 14), // (22,14): error CS8646: 'I1<(int c, int d)>.M()' is explicitly implemented more than once. // public class C3 : I1<(int a, int b)>, I1<(int c, int d)> Diagnostic(ErrorCode.ERR_DuplicateExplicitImpl, "C3").WithArguments("I1<(int c, int d)>.M()").WithLocation(22, 14), // (28,14): error CS8140: 'I1<(int c, int d)>' is already listed in the interface list on type 'C4' with different tuple element names, as 'I1<(int a, int b)>'. // public class C4 : I2, I3 Diagnostic(ErrorCode.ERR_DuplicateInterfaceWithTupleNamesInBaseList, "C4").WithArguments("I1<(int c, int d)>", "I1<(int a, int b)>", "C4").WithLocation(28, 14), // (28,14): error CS8646: 'I1<(int a, int b)>.M()' is explicitly implemented more than once. // public class C4 : I2, I3 Diagnostic(ErrorCode.ERR_DuplicateExplicitImpl, "C4").WithArguments("I1<(int a, int b)>.M()").WithLocation(28, 14), // (28,14): error CS8646: 'I1<(int c, int d)>.M()' is explicitly implemented more than once. // public class C4 : I2, I3 Diagnostic(ErrorCode.ERR_DuplicateExplicitImpl, "C4").WithArguments("I1<(int c, int d)>.M()").WithLocation(28, 14) ); var c1 = (INamedTypeSymbol)comp.GetTypeByMetadataName("C1"); var c1Interfaces = c1.Interfaces; var c1AllInterfaces = c1.AllInterfaces; Assert.Equal(2, c1Interfaces.Length); Assert.Equal(3, c1AllInterfaces.Length); Assert.Equal("I2", c1Interfaces[0].ToTestDisplayString()); Assert.Equal("I1<(System.Int32 c, System.Int32 d)>", c1Interfaces[1].ToTestDisplayString()); Assert.Equal("I2", c1AllInterfaces[0].ToTestDisplayString()); Assert.Equal("I1<(System.Int32 a, System.Int32 b)>", c1AllInterfaces[1].ToTestDisplayString()); Assert.Equal("I1<(System.Int32 c, System.Int32 d)>", c1AllInterfaces[2].ToTestDisplayString()); assertExplicitInterfaceImplementations(c1); var c2 = (INamedTypeSymbol)comp.GetTypeByMetadataName("C2"); var c2Interfaces = c2.Interfaces; var c2AllInterfaces = c2.AllInterfaces; Assert.Equal(2, c2Interfaces.Length); Assert.Equal(3, c2AllInterfaces.Length); Assert.Equal("I1<(System.Int32 c, System.Int32 d)>", c2Interfaces[0].ToTestDisplayString()); Assert.Equal("I2", c2Interfaces[1].ToTestDisplayString()); Assert.Equal("I1<(System.Int32 c, System.Int32 d)>", c2AllInterfaces[0].ToTestDisplayString()); Assert.Equal("I2", c2AllInterfaces[1].ToTestDisplayString()); Assert.Equal("I1<(System.Int32 a, System.Int32 b)>", c2AllInterfaces[2].ToTestDisplayString()); assertExplicitInterfaceImplementations(c2); var c3 = (INamedTypeSymbol)comp.GetTypeByMetadataName("C3"); var c3Interfaces = c3.Interfaces; var c3AllInterfaces = c3.AllInterfaces; Assert.Equal(2, c3Interfaces.Length); Assert.Equal(2, c3AllInterfaces.Length); Assert.Equal("I1<(System.Int32 a, System.Int32 b)>", c3Interfaces[0].ToTestDisplayString()); Assert.Equal("I1<(System.Int32 c, System.Int32 d)>", c3Interfaces[1].ToTestDisplayString()); Assert.Equal("I1<(System.Int32 a, System.Int32 b)>", c3AllInterfaces[0].ToTestDisplayString()); Assert.Equal("I1<(System.Int32 c, System.Int32 d)>", c3AllInterfaces[1].ToTestDisplayString()); assertExplicitInterfaceImplementations(c3); var c4 = (INamedTypeSymbol)comp.GetTypeByMetadataName("C4"); var c4Interfaces = c4.Interfaces; var c4AllInterfaces = c4.AllInterfaces; Assert.Equal(2, c4Interfaces.Length); Assert.Equal(4, c4AllInterfaces.Length); Assert.Equal("I2", c4Interfaces[0].ToTestDisplayString()); Assert.Equal("I3", c4Interfaces[1].ToTestDisplayString()); Assert.Equal("I2", c4AllInterfaces[0].ToTestDisplayString()); Assert.Equal("I1<(System.Int32 a, System.Int32 b)>", c4AllInterfaces[1].ToTestDisplayString()); Assert.Equal("I3", c4AllInterfaces[2].ToTestDisplayString()); Assert.Equal("I1<(System.Int32 c, System.Int32 d)>", c4AllInterfaces[3].ToTestDisplayString()); assertExplicitInterfaceImplementations(c4); void assertExplicitInterfaceImplementations(INamedTypeSymbol c) { var cMabImplementations = ((IMethodSymbol)c.GetMember("I1<(System.Int32a,System.Int32b)>.M")).ExplicitInterfaceImplementations; Assert.Equal(1, cMabImplementations.Length); Assert.Equal("void I1<(System.Int32 a, System.Int32 b)>.M()", cMabImplementations[0].ToTestDisplayString()); var cMcdImplementations = ((IMethodSymbol)c.GetMember("I1<(System.Int32c,System.Int32d)>.M")).ExplicitInterfaceImplementations; Assert.Equal(1, cMcdImplementations.Length); Assert.Equal("void I1<(System.Int32 c, System.Int32 d)>.M()", cMcdImplementations[0].ToTestDisplayString()); } } [Fact] [WorkItem(31977, "https://github.com/dotnet/roslyn/issues/31977")] public void DuplicateInterfaceDetectionWithDifferentTupleNames_03() { var source = @" public interface I1 { void M1(); void M2(); } public class C1 : I1<(int a, int b)> { public void M1() => System.Console.WriteLine(""C1.M1""); void I1<(int a, int b)>.M2() => System.Console.WriteLine(""C1.M2""); } public class C2 : C1, I1<(int c, int d)> { new public void M1() => System.Console.WriteLine(""C2.M1""); void I1<(int c, int d)>.M2() => System.Console.WriteLine(""C2.M2""); static void Main() { var x = (C1)new C2(); var y = (I1<(int a, int b)>)x; y.M1(); y.M2(); } } "; var comp = CreateCompilation(source, options: TestOptions.DebugExe); comp.VerifyDiagnostics(); Action validate = (m) => { bool isMetadata = m is PEModuleSymbol; var c1 = (NamedTypeSymbol)m.GlobalNamespace.GetTypeMember("C1"); var c1Interfaces = c1.Interfaces(); var c1AllInterfaces = c1.AllInterfaces(); Assert.Equal(1, c1Interfaces.Length); Assert.Equal(1, c1AllInterfaces.Length); Assert.Equal("I1<(System.Int32 a, System.Int32 b)>", c1Interfaces[0].ToTestDisplayString()); Assert.Equal("I1<(System.Int32 a, System.Int32 b)>", c1AllInterfaces[0].ToTestDisplayString()); var c2 = (NamedTypeSymbol)m.GlobalNamespace.GetTypeMember("C2"); var c2Interfaces = c2.Interfaces(); var c2AllInterfaces = c2.AllInterfaces(); Assert.Equal(1, c2Interfaces.Length); Assert.Equal(2, c2AllInterfaces.Length); Assert.Equal("I1<(System.Int32 c, System.Int32 d)>", c2Interfaces[0].ToTestDisplayString()); Assert.Equal("I1<(System.Int32 a, System.Int32 b)>", c2AllInterfaces[0].ToTestDisplayString()); Assert.Equal("I1<(System.Int32 c, System.Int32 d)>", c2AllInterfaces[1].ToTestDisplayString()); Assert.Equal("void C2.M1()", c2.FindImplementationForInterfaceMember(((TypeSymbol)c2Interfaces[0]).GetMember("M1")).ToTestDisplayString()); Assert.Equal("void C2.M1()", c2.FindImplementationForInterfaceMember(((TypeSymbol)c1Interfaces[0]).GetMember("M1")).ToTestDisplayString()); var m2 = (MethodSymbol)((TypeSymbol)c2).GetMember("I1<(System.Int32c,System.Int32d)>.M2"); var m2Implementations = m2.ExplicitInterfaceImplementations; Assert.Equal(1, m2Implementations.Length); Assert.Equal(isMetadata ? "void I1<(System.Int32, System.Int32)>.M2()" : "void I1<(System.Int32 c, System.Int32 d)>.M2()", m2Implementations[0].ToTestDisplayString()); Assert.Same(m2, c2.FindImplementationForInterfaceMember(((TypeSymbol)c2Interfaces[0]).GetMember("M2"))); Assert.Same(m2, c2.FindImplementationForInterfaceMember(((TypeSymbol)c1Interfaces[0]).GetMember("M2"))); }; CompileAndVerify(comp, sourceSymbolValidator: validate, symbolValidator: validate, expectedOutput: @"C2.M1 C2.M2 "); } [Fact] [WorkItem(31977, "https://github.com/dotnet/roslyn/issues/31977")] public void DuplicateInterfaceDetectionWithDifferentTupleNames_04() { var source = @" public interface I1 { void M(); } public interface I2 : I1<(I2T a, I2T b)> { } public interface I3 : I1<(I3T c, I3T d)> { } public class C1 : I2, I1<(T c, T d)> { void I1<(T a, T b)>.M(){} void I1<(T c, T d)>.M(){} } public class C2 : I1<(T c, T d)>, I2 { void I1<(T a, T b)>.M(){} void I1<(T c, T d)>.M(){} } public class C3 : I1<(T a, T b)>, I1<(T c, T d)> { void I1<(T a, T b)>.M(){} void I1<(T c, T d)>.M(){} } public class C4 : I2, I3 { void I1<(T a, T b)>.M(){} void I1<(T c, T d)>.M(){} } "; var comp = (Compilation)CreateCompilation(source); comp.VerifyDiagnostics( // (10,14): error CS8140: 'I1<(T c, T d)>' is already listed in the interface list on type 'C1' with different tuple element names, as 'I1<(T a, T b)>'. // public class C1 : I2, I1<(T c, T d)> Diagnostic(ErrorCode.ERR_DuplicateInterfaceWithTupleNamesInBaseList, "C1").WithArguments("I1<(T c, T d)>", "I1<(T a, T b)>", "C1").WithLocation(10, 14), // (10,14): error CS8646: 'I1<(T a, T b)>.M()' is explicitly implemented more than once. // public class C1 : I2, I1<(T c, T d)> Diagnostic(ErrorCode.ERR_DuplicateExplicitImpl, "C1").WithArguments("I1<(T a, T b)>.M()").WithLocation(10, 14), // (10,14): error CS8646: 'I1<(T c, T d)>.M()' is explicitly implemented more than once. // public class C1 : I2, I1<(T c, T d)> Diagnostic(ErrorCode.ERR_DuplicateExplicitImpl, "C1").WithArguments("I1<(T c, T d)>.M()").WithLocation(10, 14), // (16,14): error CS8140: 'I1<(T a, T b)>' is already listed in the interface list on type 'C2' with different tuple element names, as 'I1<(T c, T d)>'. // public class C2 : I1<(T c, T d)>, I2 Diagnostic(ErrorCode.ERR_DuplicateInterfaceWithTupleNamesInBaseList, "C2").WithArguments("I1<(T a, T b)>", "I1<(T c, T d)>", "C2").WithLocation(16, 14), // (16,14): error CS8646: 'I1<(T c, T d)>.M()' is explicitly implemented more than once. // public class C2 : I1<(T c, T d)>, I2 Diagnostic(ErrorCode.ERR_DuplicateExplicitImpl, "C2").WithArguments("I1<(T c, T d)>.M()").WithLocation(16, 14), // (16,14): error CS8646: 'I1<(T a, T b)>.M()' is explicitly implemented more than once. // public class C2 : I1<(T c, T d)>, I2 Diagnostic(ErrorCode.ERR_DuplicateExplicitImpl, "C2").WithArguments("I1<(T a, T b)>.M()").WithLocation(16, 14), // (22,14): error CS8140: 'I1<(T c, T d)>' is already listed in the interface list on type 'C3' with different tuple element names, as 'I1<(T a, T b)>'. // public class C3 : I1<(T a, T b)>, I1<(T c, T d)> Diagnostic(ErrorCode.ERR_DuplicateInterfaceWithTupleNamesInBaseList, "C3").WithArguments("I1<(T c, T d)>", "I1<(T a, T b)>", "C3").WithLocation(22, 14), // (22,14): error CS8646: 'I1<(T a, T b)>.M()' is explicitly implemented more than once. // public class C3 : I1<(T a, T b)>, I1<(T c, T d)> Diagnostic(ErrorCode.ERR_DuplicateExplicitImpl, "C3").WithArguments("I1<(T a, T b)>.M()").WithLocation(22, 14), // (22,14): error CS8646: 'I1<(T c, T d)>.M()' is explicitly implemented more than once. // public class C3 : I1<(T a, T b)>, I1<(T c, T d)> Diagnostic(ErrorCode.ERR_DuplicateExplicitImpl, "C3").WithArguments("I1<(T c, T d)>.M()").WithLocation(22, 14), // (28,14): error CS8140: 'I1<(T c, T d)>' is already listed in the interface list on type 'C4' with different tuple element names, as 'I1<(T a, T b)>'. // public class C4 : I2, I3 Diagnostic(ErrorCode.ERR_DuplicateInterfaceWithTupleNamesInBaseList, "C4").WithArguments("I1<(T c, T d)>", "I1<(T a, T b)>", "C4").WithLocation(28, 14), // (28,14): error CS8646: 'I1<(T a, T b)>.M()' is explicitly implemented more than once. // public class C4 : I2, I3 Diagnostic(ErrorCode.ERR_DuplicateExplicitImpl, "C4").WithArguments("I1<(T a, T b)>.M()").WithLocation(28, 14), // (28,14): error CS8646: 'I1<(T c, T d)>.M()' is explicitly implemented more than once. // public class C4 : I2, I3 Diagnostic(ErrorCode.ERR_DuplicateExplicitImpl, "C4").WithArguments("I1<(T c, T d)>.M()").WithLocation(28, 14) ); var c1 = (INamedTypeSymbol)comp.GetTypeByMetadataName("C1`1"); var c1Interfaces = c1.Interfaces; var c1AllInterfaces = c1.AllInterfaces; Assert.Equal(2, c1Interfaces.Length); Assert.Equal(3, c1AllInterfaces.Length); Assert.Equal("I2", c1Interfaces[0].ToTestDisplayString()); Assert.Equal("I1<(T c, T d)>", c1Interfaces[1].ToTestDisplayString()); Assert.Equal("I2", c1AllInterfaces[0].ToTestDisplayString()); Assert.Equal("I1<(T a, T b)>", c1AllInterfaces[1].ToTestDisplayString()); Assert.Equal("I1<(T c, T d)>", c1AllInterfaces[2].ToTestDisplayString()); assertExplicitInterfaceImplementations(c1); var c2 = (INamedTypeSymbol)comp.GetTypeByMetadataName("C2`1"); var c2Interfaces = c2.Interfaces; var c2AllInterfaces = c2.AllInterfaces; Assert.Equal(2, c2Interfaces.Length); Assert.Equal(3, c2AllInterfaces.Length); Assert.Equal("I1<(T c, T d)>", c2Interfaces[0].ToTestDisplayString()); Assert.Equal("I2", c2Interfaces[1].ToTestDisplayString()); Assert.Equal("I1<(T c, T d)>", c2AllInterfaces[0].ToTestDisplayString()); Assert.Equal("I2", c2AllInterfaces[1].ToTestDisplayString()); Assert.Equal("I1<(T a, T b)>", c2AllInterfaces[2].ToTestDisplayString()); assertExplicitInterfaceImplementations(c2); var c3 = (INamedTypeSymbol)comp.GetTypeByMetadataName("C3`1"); var c3Interfaces = c3.Interfaces; var c3AllInterfaces = c3.AllInterfaces; Assert.Equal(2, c3Interfaces.Length); Assert.Equal(2, c3AllInterfaces.Length); Assert.Equal("I1<(T a, T b)>", c3Interfaces[0].ToTestDisplayString()); Assert.Equal("I1<(T c, T d)>", c3Interfaces[1].ToTestDisplayString()); Assert.Equal("I1<(T a, T b)>", c3AllInterfaces[0].ToTestDisplayString()); Assert.Equal("I1<(T c, T d)>", c3AllInterfaces[1].ToTestDisplayString()); assertExplicitInterfaceImplementations(c3); var c4 = (INamedTypeSymbol)comp.GetTypeByMetadataName("C4`1"); var c4Interfaces = c4.Interfaces; var c4AllInterfaces = c4.AllInterfaces; Assert.Equal(2, c4Interfaces.Length); Assert.Equal(4, c4AllInterfaces.Length); Assert.Equal("I2", c4Interfaces[0].ToTestDisplayString()); Assert.Equal("I3", c4Interfaces[1].ToTestDisplayString()); Assert.Equal("I2", c4AllInterfaces[0].ToTestDisplayString()); Assert.Equal("I1<(T a, T b)>", c4AllInterfaces[1].ToTestDisplayString()); Assert.Equal("I3", c4AllInterfaces[2].ToTestDisplayString()); Assert.Equal("I1<(T c, T d)>", c4AllInterfaces[3].ToTestDisplayString()); assertExplicitInterfaceImplementations(c4); void assertExplicitInterfaceImplementations(INamedTypeSymbol c) { var cMabImplementations = ((IMethodSymbol)c.GetMember("I1<(Ta,Tb)>.M")).ExplicitInterfaceImplementations; Assert.Equal(1, cMabImplementations.Length); Assert.Equal("void I1<(T a, T b)>.M()", cMabImplementations[0].ToTestDisplayString()); var cMcdImplementations = ((IMethodSymbol)c.GetMember("I1<(Tc,Td)>.M")).ExplicitInterfaceImplementations; Assert.Equal(1, cMcdImplementations.Length); Assert.Equal("void I1<(T c, T d)>.M()", cMcdImplementations[0].ToTestDisplayString()); } } [Fact] [WorkItem(31977, "https://github.com/dotnet/roslyn/issues/31977")] public void DuplicateInterfaceDetectionWithDifferentTupleNames_05() { var source = @" public interface I1 { void M(); } public class C3 : I1<(T a, T b)>, I1<(U c, U d)> { void I1<(T a, T b)>.M(){} void I1<(U c, U d)>.M(){} } "; var comp = (Compilation)CreateCompilation(source); comp.VerifyDiagnostics( // (7,14): error CS0695: 'C3' cannot implement both 'I1<(T a, T b)>' and 'I1<(U c, U d)>' because they may unify for some type parameter substitutions // public class C3 : I1<(T a, T b)>, I1<(U c, U d)> Diagnostic(ErrorCode.ERR_UnifyingInterfaceInstantiations, "C3").WithArguments("C3", "I1<(T a, T b)>", "I1<(U c, U d)>").WithLocation(7, 14) ); var c3 = (INamedTypeSymbol)comp.GetTypeByMetadataName("C3`2"); var c3Interfaces = c3.Interfaces; var c3AllInterfaces = c3.AllInterfaces; Assert.Equal(2, c3Interfaces.Length); Assert.Equal(2, c3AllInterfaces.Length); Assert.Equal("I1<(T a, T b)>", c3Interfaces[0].ToTestDisplayString()); Assert.Equal("I1<(U c, U d)>", c3Interfaces[1].ToTestDisplayString()); Assert.Equal("I1<(T a, T b)>", c3AllInterfaces[0].ToTestDisplayString()); Assert.Equal("I1<(U c, U d)>", c3AllInterfaces[1].ToTestDisplayString()); assertExplicitInterfaceImplementations(c3); void assertExplicitInterfaceImplementations(INamedTypeSymbol c) { var cMabImplementations = ((IMethodSymbol)c.GetMember("I1<(Ta,Tb)>.M")).ExplicitInterfaceImplementations; Assert.Equal(1, cMabImplementations.Length); Assert.Equal("void I1<(T a, T b)>.M()", cMabImplementations[0].ToTestDisplayString()); var cMcdImplementations = ((IMethodSymbol)c.GetMember("I1<(Uc,Ud)>.M")).ExplicitInterfaceImplementations; Assert.Equal(1, cMcdImplementations.Length); Assert.Equal("void I1<(U c, U d)>.M()", cMcdImplementations[0].ToTestDisplayString()); } } [Fact] [WorkItem(31977, "https://github.com/dotnet/roslyn/issues/31977")] public void DuplicateInterfaceDetectionWithDifferentTupleNames_06() { var source = @" public interface I1 { void M(); } public class C3 : I1<(int a, int b)> { void I1<(int c, int d)>.M(){} } public class C4 : I1<(int c, int d)> { void I1<(int c, int d)>.M(){} } "; var comp = CreateCompilation(source); comp.VerifyDiagnostics( // (9,10): error CS0540: 'C3.I1<(int c, int d)>.M()': containing type does not implement interface 'I1<(int c, int d)>' // void I1<(int c, int d)>.M(){} Diagnostic(ErrorCode.ERR_ClassDoesntImplementInterface, "I1<(int c, int d)>").WithArguments("C3.I1<(int c, int d)>.M()", "I1<(int c, int d)>").WithLocation(9, 10) ); var c3 = comp.GetTypeByMetadataName("C3"); var c3Interfaces = c3.Interfaces(); var c3AllInterfaces = c3.AllInterfaces(); Assert.Equal(1, c3Interfaces.Length); Assert.Equal(1, c3AllInterfaces.Length); Assert.Equal("I1<(System.Int32 a, System.Int32 b)>", c3Interfaces[0].ToTestDisplayString()); Assert.Equal("I1<(System.Int32 a, System.Int32 b)>", c3AllInterfaces[0].ToTestDisplayString()); var mImplementations = ((MethodSymbol)c3.GetMember("I1<(System.Int32c,System.Int32d)>.M")).GetPublicSymbol().ExplicitInterfaceImplementations; Assert.Equal(1, mImplementations.Length); Assert.Equal("void I1<(System.Int32 c, System.Int32 d)>.M()", mImplementations[0].ToTestDisplayString()); Assert.Equal("void C3.I1<(System.Int32 c, System.Int32 d)>.M()", c3.FindImplementationForInterfaceMember(((TypeSymbol)c3Interfaces[0]).GetMember("M")).ToTestDisplayString()); Assert.Equal("void C3.I1<(System.Int32 c, System.Int32 d)>.M()", c3.FindImplementationForInterfaceMember(comp.GetTypeByMetadataName("C4").InterfacesNoUseSiteDiagnostics()[0].GetMember("M")).ToTestDisplayString()); } [Fact] public void AccessCheckLooksInsideTuples() { var source = @" namespace System { public struct ValueTuple { public ValueTuple(T1 item1, T2 item2) => throw null; } } public class C { (C2.C3, int) M() { throw new System.Exception(); } } public class C2 { private class C3 { } } "; var comp = CreateCompilation(source); comp.VerifyDiagnostics( // (11,9): error CS0122: 'C2.C3' is inaccessible due to its protection level // (C2.C3, int) M() { throw new System.Exception(); } Diagnostic(ErrorCode.ERR_BadAccess, "C3").WithArguments("C2.C3").WithLocation(11, 9) ); } [Fact] public void AccessCheckLooksInsideTuples2() { var source = @" namespace System { public struct ValueTuple { public ValueTuple(T1 item1, T2 item2) => throw null; } } public class C { public (C2, int) M() { throw new System.Exception(); } private class C2 { } } "; var comp = CreateCompilation(source); comp.VerifyDiagnostics( // (11,22): error CS0050: Inconsistent accessibility: return type '(C.C2, int)' is less accessible than method 'C.M()' // public (C2, int) M() { throw new System.Exception(); } Diagnostic(ErrorCode.ERR_BadVisReturnType, "M").WithArguments("C.M()", "(C.C2, int)").WithLocation(11, 22) ); } [Fact] public void ImplicitInterfaceImplementationWithDifferentTupleNames() { var source = @" public interface I0 { T get(); void set(T x); } public class C : I0<(int a, int b)> { public (int notA, int notB) get() { return (1, 2); } public void set((int notA, int notB) y) { } } public class D : I0<(int a, int b)> { public (int a, int b) get() { return (1, 2); } public void set((int a, int b) y) { } } "; var comp = CreateCompilation(source); comp.VerifyDiagnostics( // (10,17): error CS8141: The tuple element names in the signature of method 'C.set((int notA, int notB))' must match the tuple element names of interface method 'I0<(int a, int b)>.set((int a, int b))'. // public void set((int notA, int notB) y) { } Diagnostic(ErrorCode.ERR_ImplBadTupleNames, "set").WithArguments("C.set((int notA, int notB))", "I0<(int a, int b)>.set((int a, int b))").WithLocation(10, 17), // (9,33): error CS8141: The tuple element names in the signature of method 'C.get()' must match the tuple element names of interface method 'I0<(int a, int b)>.get()'. // public (int notA, int notB) get() { return (1, 2); } Diagnostic(ErrorCode.ERR_ImplBadTupleNames, "get").WithArguments("C.get()", "I0<(int a, int b)>.get()").WithLocation(9, 33) ); } [Fact] public void ImplicitAndExplicitInterfaceImplementationWithDifferentTupleNames() { var source = @" public interface I0 { T get(); void set(T x); } public class C1 : I0<(int a, int b)> { public (int a, int b) get() { return (1, 2); } public void set((int a, int b) y) { } } public class C2 : C1, I0<(int a, int b)> { (int a, int b) I0<(int a, int b)>.get() { return (1, 2); } void I0<(int a, int b)>.set((int a, int b) y) { } } public class D1 : I0<(int a, int b)> { public (int notA, int notB) get() { return (1, 2); } public void set((int notA, int notB) y) { } } public class D2 : D1, I0<(int notA, int notB)> { (int a, int b) I0<(int a, int b)>.get() { return (1, 2); } void I0<(int a, int b)>.set((int a, int b) y) { } } "; var comp = CreateCompilation(source); comp.VerifyDiagnostics( // (20,17): error CS8141: The tuple element names in the signature of method 'D1.set((int notA, int notB))' must match the tuple element names of interface method 'I0<(int a, int b)>.set((int a, int b))' (including on the return type). // public void set((int notA, int notB) y) { } Diagnostic(ErrorCode.ERR_ImplBadTupleNames, "set").WithArguments("D1.set((int notA, int notB))", "I0<(int a, int b)>.set((int a, int b))").WithLocation(20, 17), // (19,33): error CS8141: The tuple element names in the signature of method 'D1.get()' must match the tuple element names of interface method 'I0<(int a, int b)>.get()' (including on the return type). // public (int notA, int notB) get() { return (1, 2); } Diagnostic(ErrorCode.ERR_ImplBadTupleNames, "get").WithArguments("D1.get()", "I0<(int a, int b)>.get()").WithLocation(19, 33), // (25,10): error CS0540: 'D2.I0<(int a, int b)>.set((int a, int b))': containing type does not implement interface 'I0<(int a, int b)>' // void I0<(int a, int b)>.set((int a, int b) y) { } Diagnostic(ErrorCode.ERR_ClassDoesntImplementInterface, "I0<(int a, int b)>").WithArguments("D2.I0<(int a, int b)>.set((int a, int b))", "I0<(int a, int b)>").WithLocation(25, 10), // (24,20): error CS0540: 'D2.I0<(int a, int b)>.get()': containing type does not implement interface 'I0<(int a, int b)>' // (int a, int b) I0<(int a, int b)>.get() { return (1, 2); } Diagnostic(ErrorCode.ERR_ClassDoesntImplementInterface, "I0<(int a, int b)>").WithArguments("D2.I0<(int a, int b)>.get()", "I0<(int a, int b)>").WithLocation(24, 20) ); } [Fact] [WorkItem(20528, "https://github.com/dotnet/roslyn/issues/20528")] public void ImplicitAndExplicitInterfaceImplementationWithNoNames() { var source = @" public interface I0 { T get(); void set(T x); } public class C1 : I0<(int a, int b)> { public (int a, int b) get() { return (1, 2); } public void set((int a, int b) y) { } } public class C2 : C1, I0<(int a, int b)> { (int, int) I0<(int, int)>.get() { return (1, 2); } void I0<(int, int)>.set((int, int) y) { } } public class D1 : I0<(int, int)> { public (int, int) get() { return (1, 2); } public void set((int, int) y) { } } public class D2 : D1, I0<(int, int)> { (int, int) I0<(int, int)>.get() { return (1, 2); } void I0<(int, int)>.set((int, int) y) { } } "; var comp = CreateCompilation(source); comp.VerifyDiagnostics( // (15,10): error CS0540: 'C2.I0<(int, int)>.set((int, int))': containing type does not implement interface 'I0<(int, int)>' // void I0<(int, int)>.set((int, int) y) { } Diagnostic(ErrorCode.ERR_ClassDoesntImplementInterface, "I0<(int, int)>").WithArguments("C2.I0<(int, int)>.set((int, int))", "I0<(int, int)>").WithLocation(15, 10), // (14,16): error CS0540: 'C2.I0<(int, int)>.get()': containing type does not implement interface 'I0<(int, int)>' // (int, int) I0<(int, int)>.get() { return (1, 2); } Diagnostic(ErrorCode.ERR_ClassDoesntImplementInterface, "I0<(int, int)>").WithArguments("C2.I0<(int, int)>.get()", "I0<(int, int)>").WithLocation(14, 16) ); } [Fact] public void PartialMethodsWithDifferentTupleNames() { var source = @" public partial class C { partial void M1((int a, int b) x); partial void M2((int a, int b) x); partial void M3((int a, int b) x); } public partial class C { partial void M1((int notA, int notB) y) { } partial void M2((int, int) y) { } partial void M3((int a, int b) y) { } } "; var comp = CreateCompilation(source); comp.VerifyDiagnostics( // (4,18): error CS8142: Both partial method declarations, 'C.M1((int a, int b))' and 'C.M1((int notA, int notB))', must use the same tuple element names. // partial void M1((int a, int b) x); Diagnostic(ErrorCode.ERR_PartialMethodInconsistentTupleNames, "M1").WithArguments("C.M1((int a, int b))", "C.M1((int notA, int notB))").WithLocation(4, 18), // (5,18): error CS8142: Both partial method declarations, 'C.M2((int a, int b))' and 'C.M2((int, int))', must use the same tuple element names. // partial void M2((int a, int b) x); Diagnostic(ErrorCode.ERR_PartialMethodInconsistentTupleNames, "M2").WithArguments("C.M2((int a, int b))", "C.M2((int, int))").WithLocation(5, 18) ); } [Fact] public void PartialClassWithDifferentTupleNamesInBaseInterfaces() { var source = @" public interface I0 { } public partial class C : I0<(int a, int b)> { } public partial class C : I0<(int notA, int notB)> { } public partial class C : I0<(int, int)> { } public partial class D : I0<(int a, int b)> { } public partial class D : I0<(int a, int b)> { } "; var comp = CreateCompilation(source); comp.VerifyDiagnostics( // (3,22): error CS8140: 'I0<(int notA, int notB)>' is already listed in the interface list on type 'C' with different tuple element names, as 'I0<(int a, int b)>'. // public partial class C : I0<(int a, int b)> { } Diagnostic(ErrorCode.ERR_DuplicateInterfaceWithTupleNamesInBaseList, "C").WithArguments("I0<(int notA, int notB)>", "I0<(int a, int b)>", "C").WithLocation(3, 22), // (3,22): error CS8140: 'I0<(int, int)>' is already listed in the interface list on type 'C' with different tuple element names, as 'I0<(int a, int b)>'. // public partial class C : I0<(int a, int b)> { } Diagnostic(ErrorCode.ERR_DuplicateInterfaceWithTupleNamesInBaseList, "C").WithArguments("I0<(int, int)>", "I0<(int a, int b)>", "C").WithLocation(3, 22) ); } [Fact] public void PartialClassWithDifferentTupleNamesInBaseTypes() { var source = @" public class Base { } public partial class C1 : Base<(int a, int b)> { } public partial class C1 : Base<(int notA, int notB)> { } public partial class C2 : Base<(int a, int b)> { } public partial class C2 : Base<(int, int)> { } public partial class C3 : Base<(int a, int b)> { } public partial class C3 : Base<(int a, int b)> { } "; var comp = CreateCompilation(source); comp.VerifyDiagnostics( // (5,22): error CS0263: Partial declarations of 'C2' must not specify different base classes // public partial class C2 : Base<(int a, int b)> { } Diagnostic(ErrorCode.ERR_PartialMultipleBases, "C2").WithArguments("C2").WithLocation(5, 22), // (3,22): error CS0263: Partial declarations of 'C1' must not specify different base classes // public partial class C1 : Base<(int a, int b)> { } Diagnostic(ErrorCode.ERR_PartialMultipleBases, "C1").WithArguments("C1").WithLocation(3, 22) ); } [Fact] public void IndirectInterfaceBasesWithDifferentTupleNames() { var source = @" public interface I0 { } public interface I1 : I0<(int a, int b)> { } public interface I2 : I0<(int notA, int notB)> { } public interface I3 : I0<(int a, int b)> { } public class C : I1, I2 { } public class D : I1, I3 { } "; var comp = CreateCompilation(source); comp.VerifyDiagnostics( // (7,14): error CS8140: 'I0<(int notA, int notB)>' is already listed in the interface list on type 'C' with different tuple element names, as 'I0<(int a, int b)>'. // public class C : I1, I2 { } Diagnostic(ErrorCode.ERR_DuplicateInterfaceWithTupleNamesInBaseList, "C").WithArguments("I0<(int notA, int notB)>", "I0<(int a, int b)>", "C").WithLocation(7, 14) ); } [Fact] public void InterfaceUnification() { var source = @" public interface I0 { } public class C1 : I0<(int, int)>, I0<(T2, T2)> { } public class C2 : I0<(int, int)>, I0> { } public class C3 : I0<(int a, int b)>, I0<(T2, T2)> { } public class C4 : I0<(int a, int b)>, I0<(T2 a, T2 b)> { } "; var comp = CreateCompilation(source); comp.VerifyDiagnostics( // (6,14): error CS0695: 'C4' cannot implement both 'I0<(int a, int b)>' and 'I0<(T2 a, T2 b)>' because they may unify for some type parameter substitutions // public class C4 : I0<(int a, int b)>, I0<(T2 a, T2 b)> { } Diagnostic(ErrorCode.ERR_UnifyingInterfaceInstantiations, "C4").WithArguments("C4", "I0<(int a, int b)>", "I0<(T2 a, T2 b)>").WithLocation(6, 14), // (3,14): error CS0695: 'C1' cannot implement both 'I0<(int, int)>' and 'I0<(T2, T2)>' because they may unify for some type parameter substitutions // public class C1 : I0<(int, int)>, I0<(T2, T2)> { } Diagnostic(ErrorCode.ERR_UnifyingInterfaceInstantiations, "C1").WithArguments("C1", "I0<(int, int)>", "I0<(T2, T2)>").WithLocation(3, 14), // (5,14): error CS0695: 'C3' cannot implement both 'I0<(int a, int b)>' and 'I0<(T2, T2)>' because they may unify for some type parameter substitutions // public class C3 : I0<(int a, int b)>, I0<(T2, T2)> { } Diagnostic(ErrorCode.ERR_UnifyingInterfaceInstantiations, "C3").WithArguments("C3", "I0<(int a, int b)>", "I0<(T2, T2)>").WithLocation(5, 14), // (4,14): error CS0695: 'C2' cannot implement both 'I0<(int, int)>' and 'I0<(T2, T2)>' because they may unify for some type parameter substitutions // public class C2 : I0<(int, int)>, I0> { } Diagnostic(ErrorCode.ERR_UnifyingInterfaceInstantiations, "C2").WithArguments("C2", "I0<(int, int)>", "I0<(T2, T2)>").WithLocation(4, 14) ); } [Fact] public void ConversionToBase() { var source = @" public class Base { } public class Derived : Base<(int a, int b)> { public static explicit operator Base<(int, int)>(Derived x) { return null; } public static explicit operator Derived(Base<(int, int)> x) { return null; } } "; var comp = CreateCompilation(source); comp.VerifyDiagnostics( // (9,37): error CS0553: 'Derived.explicit operator Derived(Base<(int, int)>)': user-defined conversions to or from a base class are not allowed // public static explicit operator Derived(Base<(int, int)> x) Diagnostic(ErrorCode.ERR_ConversionWithBase, "Derived").WithArguments("Derived.explicit operator Derived(Base<(int, int)>)").WithLocation(9, 37), // (5,37): error CS0553: 'Derived.explicit operator Base<(int, int)>(Derived)': user-defined conversions to or from a base class are not allowed // public static explicit operator Base<(int, int)>(Derived x) Diagnostic(ErrorCode.ERR_ConversionWithBase, "Base<(int, int)>").WithArguments("Derived.explicit operator Base<(int, int)>(Derived)").WithLocation(5, 37) ); } [Fact] public void InterfaceUnification2() { var source = @" public interface I0 { } public class Derived : I0>, I0 { } "; var comp = CreateCompilation(source); comp.VerifyDiagnostics(); // Didn't run out of memory in trying to substitute T with Derived<(T, T)> in a loop } [Fact] public void AmbiguousExtensionMethodWithDifferentTupleNames() { var source = @" public static class C1 { public static void M(this string self, (int, int) x) { System.Console.Write($""C1.M({x}) ""); } } public static class C2 { public static void M(this string self, (int a, int b) x) { System.Console.Write($""C2.M({x}) ""); } } public static class C3 { public static void M(this string self, (int c, int d) x) { System.Console.Write($""C3.M({x}) ""); } } public class D { public static void Main() { ""string"".M((1, 1)); ""string"".M((a: 1, b: 1)); ""string"".M((c: 1, d: 1)); } } "; var comp = CreateCompilation(source); comp.VerifyDiagnostics( // (18,18): error CS0121: The call is ambiguous between the following methods or properties: 'C1.M(string, (int, int))' and 'C2.M(string, (int a, int b))' // "string".M((1, 1)); Diagnostic(ErrorCode.ERR_AmbigCall, "M").WithArguments("C1.M(string, (int, int))", "C2.M(string, (int a, int b))").WithLocation(18, 18), // (19,18): error CS0121: The call is ambiguous between the following methods or properties: 'C1.M(string, (int, int))' and 'C2.M(string, (int a, int b))' // "string".M((a: 1, b: 1)); Diagnostic(ErrorCode.ERR_AmbigCall, "M").WithArguments("C1.M(string, (int, int))", "C2.M(string, (int a, int b))").WithLocation(19, 18), // (20,18): error CS0121: The call is ambiguous between the following methods or properties: 'C1.M(string, (int, int))' and 'C2.M(string, (int a, int b))' // "string".M((c: 1, d: 1)); Diagnostic(ErrorCode.ERR_AmbigCall, "M").WithArguments("C1.M(string, (int, int))", "C2.M(string, (int a, int b))").WithLocation(20, 18) ); } [Fact] public void InheritFromMetadataWithDifferentNames() { const string ilSource = @" .assembly extern mscorlib { } .assembly extern System.ValueTuple { .publickeytoken = (CC 7B 13 FF CD 2D DD 51 ) .ver 4:0:1:0 } .class public auto ansi beforefieldinit Base extends [mscorlib]System.Object { .method public hidebysig newslot virtual instance class [System.ValueTuple]System.ValueTuple`2 M() cil managed { .param [0] // = (int a, int b) .custom instance void [System.ValueTuple]System.Runtime.CompilerServices.TupleElementNamesAttribute::.ctor(string[]) = ( 01 00 02 00 00 00 01 61 01 62 00 00 ) // Code size 13 (0xd) .maxstack 2 .locals init (class [System.ValueTuple]System.ValueTuple`2 V_0) IL_0000: nop IL_0001: ldc.i4.1 IL_0002: ldc.i4.2 IL_0003: newobj instance void class [System.ValueTuple]System.ValueTuple`2::.ctor(!0, !1) IL_0008: stloc.0 IL_0009: br.s IL_000b IL_000b: ldloc.0 IL_000c: ret } // end of method Base::M .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 Base::.ctor } // end of class Base .class public auto ansi beforefieldinit Base2 extends Base { .method public hidebysig virtual instance class [System.ValueTuple]System.ValueTuple`2 M() cil managed { .param [0] // = (int notA, int notB) .custom instance void [System.ValueTuple]System.Runtime.CompilerServices.TupleElementNamesAttribute::.ctor(string[]) = ( 01 00 02 00 00 00 04 6e 6f 74 41 04 6e 6f 74 42 00 00 ) // Code size 13 (0xd) .maxstack 2 .locals init (class [System.ValueTuple]System.ValueTuple`2 V_0) IL_0000: nop IL_0001: ldc.i4.1 IL_0002: ldc.i4.2 IL_0003: newobj instance void class [System.ValueTuple]System.ValueTuple`2::.ctor(!0, !1) IL_0008: stloc.0 IL_0009: br.s IL_000b IL_000b: ldloc.0 IL_000c: ret } // end of method Base2::M .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 Base::.ctor() IL_0006: nop IL_0007: ret } // end of method Base2::.ctor } // end of class Base2 "; string sourceWithMatchingNames = @" public class C : Base2 { public override (int notA, int notB) M() { return (1, 2); } }"; var compMatching = CreateCompilationWithILAndMscorlib40(sourceWithMatchingNames, ilSource, targetFramework: TargetFramework.Mscorlib46Extended, options: TestOptions.DebugDll); compMatching.VerifyEmitDiagnostics(); string sourceWithDifferentNames1 = @" public class C : Base2 { public override (int a, int b) M() { return (1, 2); } }"; var compDifferent1 = CreateCompilationWithILAndMscorlib40(sourceWithDifferentNames1, ilSource, targetFramework: TargetFramework.Mscorlib46Extended, options: TestOptions.DebugDll); compDifferent1.VerifyDiagnostics( // (4,36): error CS8139: 'C.M()': cannot change tuple element names when overriding inherited member 'Base2.M()' // public override (int a, int b) M() { return (1, 2); } Diagnostic(ErrorCode.ERR_CantChangeTupleNamesOnOverride, "M").WithArguments("C.M()", "Base2.M()").WithLocation(4, 36) ); string sourceWithDifferentNames2 = @" public class C : Base2 { public override (int, int) M() { return (1, 2); } }"; var compDifferent2 = CreateCompilationWithILAndMscorlib40(sourceWithDifferentNames2, ilSource, targetFramework: TargetFramework.Mscorlib46Extended, options: TestOptions.DebugDll); compDifferent2.VerifyDiagnostics(); } [Fact] public void TupleNamesInAnonymousTypes() { var source = @" public class C { public static void Main() { var x1 = new { Tuple = (a: 1, b: 2) }; var x2 = new { Tuple = (c: 1, 2) }; x2 = x1; System.Console.Write(x1.Tuple.a); } } "; var comp = CreateCompilation(source, options: TestOptions.DebugExe); comp.VerifyDiagnostics(); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var nodes = tree.GetCompilationUnitRoot().DescendantNodes(); var x1 = nodes.OfType().First(); Assert.Equal(" x1", model.GetDeclaredSymbol(x1).ToTestDisplayString()); var x2 = nodes.OfType().Skip(1).First(); Assert.Equal(" x2", model.GetDeclaredSymbol(x2).ToTestDisplayString()); } [Fact] public void OverriddenPropertyWithDifferentTupleNamesInReturn() { var source = @" public class Base { public virtual (int a, int b) P1 { get; set; } public virtual (int a, int b) P2 { get; set; } public virtual (int a, int b)[] P3 { get; set; } public virtual System.Nullable<(int a, int b)> P4 { get; set; } public virtual ((int a, int b) c, int d) P5 { get; set; } public virtual (dynamic a, dynamic b) P6 { get; set; } } public class Derived : Base { public override (int a, int b) P1 { get; set; } public override (int notA, int notB) P2 { get; set; } public override (int notA, int notB)[] P3 { get; set; } public override System.Nullable<(int notA, int notB)> P4 { get; set; } public override ((int notA, int notB) c, int d) P5 { get; set; } public override (dynamic notA, dynamic) P6 { get; set; } } "; var comp = CreateCompilation(source, references: new[] { CSharpRef }); comp.VerifyDiagnostics( // (14,42): error CS8139: 'Derived.P2': cannot change tuple element names when overriding inherited member 'Base.P2' // public override (int notA, int notB) P2 { get; set; } Diagnostic(ErrorCode.ERR_CantChangeTupleNamesOnOverride, "P2").WithArguments("Derived.P2", "Base.P2").WithLocation(14, 42), // (14,47): error CS8139: 'Derived.P2.get': cannot change tuple element names when overriding inherited member 'Base.P2.get' // public override (int notA, int notB) P2 { get; set; } Diagnostic(ErrorCode.ERR_CantChangeTupleNamesOnOverride, "get").WithArguments("Derived.P2.get", "Base.P2.get").WithLocation(14, 47), // (14,52): error CS8139: 'Derived.P2.set': cannot change tuple element names when overriding inherited member 'Base.P2.set' // public override (int notA, int notB) P2 { get; set; } Diagnostic(ErrorCode.ERR_CantChangeTupleNamesOnOverride, "set").WithArguments("Derived.P2.set", "Base.P2.set").WithLocation(14, 52), // (15,44): error CS8139: 'Derived.P3': cannot change tuple element names when overriding inherited member 'Base.P3' // public override (int notA, int notB)[] P3 { get; set; } Diagnostic(ErrorCode.ERR_CantChangeTupleNamesOnOverride, "P3").WithArguments("Derived.P3", "Base.P3").WithLocation(15, 44), // (15,49): error CS8139: 'Derived.P3.get': cannot change tuple element names when overriding inherited member 'Base.P3.get' // public override (int notA, int notB)[] P3 { get; set; } Diagnostic(ErrorCode.ERR_CantChangeTupleNamesOnOverride, "get").WithArguments("Derived.P3.get", "Base.P3.get").WithLocation(15, 49), // (15,54): error CS8139: 'Derived.P3.set': cannot change tuple element names when overriding inherited member 'Base.P3.set' // public override (int notA, int notB)[] P3 { get; set; } Diagnostic(ErrorCode.ERR_CantChangeTupleNamesOnOverride, "set").WithArguments("Derived.P3.set", "Base.P3.set").WithLocation(15, 54), // (16,59): error CS8139: 'Derived.P4': cannot change tuple element names when overriding inherited member 'Base.P4' // public override System.Nullable<(int notA, int notB)> P4 { get; set; } Diagnostic(ErrorCode.ERR_CantChangeTupleNamesOnOverride, "P4").WithArguments("Derived.P4", "Base.P4").WithLocation(16, 59), // (16,64): error CS8139: 'Derived.P4.get': cannot change tuple element names when overriding inherited member 'Base.P4.get' // public override System.Nullable<(int notA, int notB)> P4 { get; set; } Diagnostic(ErrorCode.ERR_CantChangeTupleNamesOnOverride, "get").WithArguments("Derived.P4.get", "Base.P4.get").WithLocation(16, 64), // (16,69): error CS8139: 'Derived.P4.set': cannot change tuple element names when overriding inherited member 'Base.P4.set' // public override System.Nullable<(int notA, int notB)> P4 { get; set; } Diagnostic(ErrorCode.ERR_CantChangeTupleNamesOnOverride, "set").WithArguments("Derived.P4.set", "Base.P4.set").WithLocation(16, 69), // (17,53): error CS8139: 'Derived.P5': cannot change tuple element names when overriding inherited member 'Base.P5' // public override ((int notA, int notB) c, int d) P5 { get; set; } Diagnostic(ErrorCode.ERR_CantChangeTupleNamesOnOverride, "P5").WithArguments("Derived.P5", "Base.P5").WithLocation(17, 53), // (17,58): error CS8139: 'Derived.P5.get': cannot change tuple element names when overriding inherited member 'Base.P5.get' // public override ((int notA, int notB) c, int d) P5 { get; set; } Diagnostic(ErrorCode.ERR_CantChangeTupleNamesOnOverride, "get").WithArguments("Derived.P5.get", "Base.P5.get").WithLocation(17, 58), // (17,63): error CS8139: 'Derived.P5.set': cannot change tuple element names when overriding inherited member 'Base.P5.set' // public override ((int notA, int notB) c, int d) P5 { get; set; } Diagnostic(ErrorCode.ERR_CantChangeTupleNamesOnOverride, "set").WithArguments("Derived.P5.set", "Base.P5.set").WithLocation(17, 63), // (18,45): error CS8139: 'Derived.P6': cannot change tuple element names when overriding inherited member 'Base.P6' // public override (dynamic notA, dynamic) P6 { get; set; } Diagnostic(ErrorCode.ERR_CantChangeTupleNamesOnOverride, "P6").WithArguments("Derived.P6", "Base.P6").WithLocation(18, 45), // (18,50): error CS8139: 'Derived.P6.get': cannot change tuple element names when overriding inherited member 'Base.P6.get' // public override (dynamic notA, dynamic) P6 { get; set; } Diagnostic(ErrorCode.ERR_CantChangeTupleNamesOnOverride, "get").WithArguments("Derived.P6.get", "Base.P6.get").WithLocation(18, 50), // (18,55): error CS8139: 'Derived.P6.set': cannot change tuple element names when overriding inherited member 'Base.P6.set' // public override (dynamic notA, dynamic) P6 { get; set; } Diagnostic(ErrorCode.ERR_CantChangeTupleNamesOnOverride, "set").WithArguments("Derived.P6.set", "Base.P6.set").WithLocation(18, 55) ); } [Fact] public void DefiniteAssignment001() { var source = @" using System; class C { static void Main(string[] args) { (string A, string B) ss; ss.A = ""q""; ss.Item2 = ""w""; System.Console.WriteLine(ss); } } "; var comp = CompileAndVerify(source, parseOptions: TestOptions.Regular, expectedOutput: @" (q, w) "); } [Fact] public void DefiniteAssignment002() { var source = @" using System; class C { static void Main(string[] args) { (string A, string B) ss; ss.A = ""q""; ss.B = ""q""; ss.Item1 = ""w""; ss.Item2 = ""w""; System.Console.WriteLine(ss); } } "; var comp = CompileAndVerify(source, parseOptions: TestOptions.Regular, expectedOutput: @"(w, w)"); } [Fact] public void DefiniteAssignment003() { var source = @" using System; class C { static void Main(string[] args) { (string A, (string B, string C) D) ss; ss.A = ""q""; ss.D.B = ""w""; ss.D.C = ""e""; System.Console.WriteLine(ss); } } "; var comp = CompileAndVerify(source, parseOptions: TestOptions.Regular, expectedOutput: @" (q, (w, e)) "); } [Fact] public void DefiniteAssignment004() { var source = @" using System; class C { static void Main(string[] args) { (string I1, string I2, string I3, string I4, string I5, string I6, string I7, string I8, string I9, string I10) ss; ss.I1 = ""q""; ss.I2 = ""q""; ss.I3 = ""q""; ss.I4 = ""q""; ss.I5 = ""q""; ss.I6 = ""q""; ss.I7 = ""q""; ss.I8 = ""q""; ss.I9 = ""q""; ss.I10 = ""q""; System.Console.WriteLine(ss); } } "; var comp = CompileAndVerify(source, parseOptions: TestOptions.Regular, expectedOutput: @" (q, q, q, q, q, q, q, q, q, q) "); } [Fact] public void DefiniteAssignment005() { var source = @" using System; class C { static void Main(string[] args) { (string I1, string I2, string I3, string I4, string I5, string I6, string I7, string I8, string I9, string I10) ss; ss.Item1 = ""q""; ss.Item2 = ""q""; ss.Item3 = ""q""; ss.Item4 = ""q""; ss.Item5 = ""q""; ss.Item6 = ""q""; ss.Item7 = ""q""; ss.Item8 = ""q""; ss.Item9 = ""q""; ss.Item10 = ""q""; System.Console.WriteLine(ss); } } "; var comp = CompileAndVerify(source, parseOptions: TestOptions.Regular, expectedOutput: @" (q, q, q, q, q, q, q, q, q, q) "); } [Fact] public void DefiniteAssignment006() { var source = @" using System; class C { static void Main(string[] args) { (string I1, string I2, string I3, string I4, string I5, string I6, string I7, string I8, string I9, string I10) ss; ss.Item1 = ""q""; ss.I2 = ""q""; ss.Item3 = ""q""; ss.I4 = ""q""; ss.Item5 = ""q""; ss.I6 = ""q""; ss.Item7 = ""q""; ss.I8 = ""q""; ss.Item9 = ""q""; ss.I10 = ""q""; System.Console.WriteLine(ss); } } "; var comp = CompileAndVerify(source, parseOptions: TestOptions.Regular, expectedOutput: @" (q, q, q, q, q, q, q, q, q, q) "); } [Fact] public void DefiniteAssignment007() { var source = @" using System; class C { static void Main(string[] args) { (string I1, string I2, string I3, string I4, string I5, string I6, string I7, string I8, string I9, string I10) ss; ss.Item1 = ""q""; ss.I2 = ""q""; ss.Item3 = ""q""; ss.I4 = ""q""; ss.Item5 = ""q""; ss.I6 = ""q""; ss.Item7 = ""q""; ss.I8 = ""q""; ss.Item9 = ""q""; ss.I10 = ""q""; System.Console.WriteLine(ss.Rest); } } "; var comp = CompileAndVerify(source, parseOptions: TestOptions.Regular, expectedOutput: @" (q, q, q) "); } [Fact] public void DefiniteAssignment008() { var source = @" using System; class C { static void Main(string[] args) { (string I1, string I2, string I3, string I4, string I5, string I6, string I7, string I8, string I9, string I10) ss; ss.I8 = ""q""; ss.Item9 = ""q""; ss.I10 = ""q""; System.Console.WriteLine(ss.Rest); } } "; var comp = CompileAndVerify(source, parseOptions: TestOptions.Regular, expectedOutput: @" (q, q, q) "); } [Fact] public void DefiniteAssignment009() { var source = @" using System; class C { static void Main(string[] args) { (string I1, string I2, string I3, string I4, string I5, string I6, string I7, string I8, string I9, string I10) ss; ss.I1 = ""q""; ss.I2 = ""q""; ss.I3 = ""q""; ss.I4 = ""q""; ss.I5 = ""q""; ss.I6 = ""q""; ss.I7 = ""q""; Assign(out ss.Rest); System.Console.WriteLine(ss); } static void Assign(out T v) { v = default(T); } } "; var comp = CompileAndVerify(source, parseOptions: TestOptions.Regular, expectedOutput: @" (q, q, q, q, q, q, q, , , ) "); } [Fact] public void DefiniteAssignment010() { var source = @" using System; class C { static void Main(string[] args) { (string I1, string I2, string I3, string I4, string I5, string I6, string I7, string I8, string I9, string I10) ss; Assign(out ss.Rest, (""q"", ""w"", ""e"")); System.Console.WriteLine(ss.I9); } static void Assign(out T r, T v) { r = v; } } "; var comp = CompileAndVerify(source, parseOptions: TestOptions.Regular, expectedOutput: @"w"); } [Fact] public void DefiniteAssignment011() { var source = @" class C { static void Main(string[] args) { if (1.ToString() == 2.ToString()) { (string I1, string I2, string I3, string I4, string I5, string I6, string I7, string I8) ss; ss.I1 = ""q""; ss.I2 = ""q""; ss.I3 = ""q""; ss.I4 = ""q""; ss.I5 = ""q""; ss.I6 = ""q""; ss.I7 = ""q""; ss.I8 = ""q""; System.Console.WriteLine(ss); } else if (1.ToString() == 3.ToString()) { (string I1, string I2, string I3, string I4, string I5, string I6, string I7, string I8) ss; ss.I1 = ""q""; ss.I2 = ""q""; ss.I3 = ""q""; ss.I4 = ""q""; ss.I5 = ""q""; ss.I6 = ""q""; ss.I7 = ""q""; // ss.I8 = ""q""; System.Console.WriteLine(ss); } else { (string I1, string I2, string I3, string I4, string I5, string I6, string I7, string I8) ss; ss.I1 = ""q""; ss.I2 = ""q""; ss.I3 = ""q""; ss.I4 = ""q""; ss.I5 = ""q""; ss.I6 = ""q""; // ss.I7 = ""q""; ss.I8 = ""q""; System.Console.WriteLine(ss); // should fail } } } namespace System { public struct ValueTuple { public T1 Item1; public ValueTuple(T1 item1) { this.Item1 = item1; } } public struct ValueTuple { public T1 Item1; public T2 Item2; public ValueTuple(T1 item1, T2 item2) { this.Item1 = item1; this.Item2 = item2; } } public struct ValueTuple { public T1 Item1; public T2 Item2; public T3 Item3; public T4 Item4; public T5 Item5; public T6 Item6; public T7 Item7; // public TRest Rest; oops, Rest is missing public ValueTuple(T1 item1, T2 item2, T3 item3, T4 item4, T5 item5, T6 item6, T7 item7, TRest rest) { Item1 = item1; Item2 = item2; Item3 = item3; Item4 = item4; Item5 = item5; Item6 = item6; Item7 = item7; // Rest = rest; } } } " + TestResources.NetFX.ValueTuple.tupleattributes_cs; var comp = CreateCompilation(source, assemblyName: "comp", parseOptions: TestOptions.Regular); comp.VerifyDiagnostics( // (8,13): error CS8128: Member 'Rest' was not found on type 'ValueTuple' from assembly 'comp, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'. // (string I1, Diagnostic(ErrorCode.ERR_PredefinedTypeMemberNotFoundInAssembly, @"(string I1, string I2, string I3, string I4, string I5, string I6, string I7, string I8)").WithArguments("Rest", "System.ValueTuple", "comp, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null").WithLocation(8, 13), // (30,13): error CS8128: Member 'Rest' was not found on type 'ValueTuple' from assembly 'comp, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'. // (string I1, Diagnostic(ErrorCode.ERR_PredefinedTypeMemberNotFoundInAssembly, @"(string I1, string I2, string I3, string I4, string I5, string I6, string I7, string I8)").WithArguments("Rest", "System.ValueTuple", "comp, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null").WithLocation(30, 13), // (52,13): error CS8128: Member 'Rest' was not found on type 'ValueTuple' from assembly 'comp, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'. // (string I1, Diagnostic(ErrorCode.ERR_PredefinedTypeMemberNotFoundInAssembly, @"(string I1, string I2, string I3, string I4, string I5, string I6, string I7, string I8)").WithArguments("Rest", "System.ValueTuple", "comp, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null").WithLocation(52, 13), // (70,38): error CS0165: Use of unassigned local variable 'ss' // System.Console.WriteLine(ss); // should fail Diagnostic(ErrorCode.ERR_UseDefViolation, "ss").WithArguments("ss").WithLocation(70, 38) ); } [Fact] public void DefiniteAssignment012() { var source = @" class C { static void Main(string[] args) { if (1.ToString() == 2.ToString()) { (string I1, string I2, string I3, string I4, string I5, string I6, string I7, string I8) ss; ss.I1 = ""q""; ss.I2 = ""q""; ss.I3 = ""q""; ss.I4 = ""q""; ss.I5 = ""q""; ss.I6 = ""q""; ss.I7 = ""q""; ss.I8 = ""q""; System.Console.WriteLine(ss); } else if (1.ToString() == 3.ToString()) { (string I1, string I2, string I3, string I4, string I5, string I6, string I7, string I8) ss; ss.I1 = ""q""; ss.I2 = ""q""; ss.I3 = ""q""; ss.I4 = ""q""; ss.I5 = ""q""; ss.I6 = ""q""; ss.I7 = ""q""; // ss.I8 = ""q""; System.Console.WriteLine(ss); // should fail1 } else { (string I1, string I2, string I3, string I4, string I5, string I6, string I7, string I8) ss; ss.I1 = ""q""; ss.I2 = ""q""; ss.I3 = ""q""; ss.I4 = ""q""; ss.I5 = ""q""; ss.I6 = ""q""; // ss.I7 = ""q""; ss.I8 = ""q""; System.Console.WriteLine(ss); // should fail2 } } } "; var comp = CreateCompilation(source, parseOptions: TestOptions.Regular); comp.VerifyDiagnostics( // (48,38): error CS0165: Use of unassigned local variable 'ss' // System.Console.WriteLine(ss); // should fail1 Diagnostic(ErrorCode.ERR_UseDefViolation, "ss").WithArguments("ss").WithLocation(48, 38), // (70,38): error CS0165: Use of unassigned local variable 'ss' // System.Console.WriteLine(ss); // should fail2 Diagnostic(ErrorCode.ERR_UseDefViolation, "ss").WithArguments("ss").WithLocation(70, 38) ); } [Fact] public void DefiniteAssignment013() { var source = @" class C { static void Main(string[] args) { (string I1, string I2, string I3, string I4, string I5, string I6, string I7, string I8) ss; ss.I1 = ""q""; ss.I2 = ""q""; ss.I3 = ""q""; ss.I4 = ""q""; ss.I5 = ""q""; ss.I6 = ""q""; ss.I7 = ""q""; ss.Item1 = ""q""; ss.Item2 = ""q""; ss.Item3 = ""q""; ss.Item4 = ""q""; ss.Item5 = ""q""; ss.Item6 = ""q""; ss.Item7 = ""q""; System.Console.WriteLine(ss.Rest); } } "; var comp = CreateCompilation(source, parseOptions: TestOptions.Regular); comp.VerifyDiagnostics( // (31,34): error CS0170: Use of possibly unassigned field 'Rest' // System.Console.WriteLine(ss.Rest); Diagnostic(ErrorCode.ERR_UseDefViolationField, "ss.Rest").WithArguments("Rest").WithLocation(31, 34) ); } [Fact] public void DefiniteAssignment014() { var source = @" class C { static void Main(string[] args) { (string I1, string I2, string I3, string I4, string I5, string I6, string I7, string I8) ss; ss.I1 = ""q""; ss.Item2 = ""aa""; System.Console.WriteLine(ss.Item1); System.Console.WriteLine(ss.I2); System.Console.WriteLine(ss.I3); } } "; var comp = CreateCompilation(source, parseOptions: TestOptions.Regular); comp.VerifyDiagnostics( // (21,34): error CS0170: Use of possibly unassigned field 'I3' // System.Console.WriteLine(ss.I3); Diagnostic(ErrorCode.ERR_UseDefViolationField, "ss.I3").WithArguments("I3").WithLocation(21, 34) ); } [Fact] public void DefiniteAssignment015() { var source = @" using System; using System.Threading.Tasks; class C { static void Main(string[] args) { var v = Test().Result; } static async Task Test() { (long a, int b) v1; (byte x, int y) v2; v1.a = 5; v2.x = 5; // no need to persist across await since it is unused after it. System.Console.WriteLine(v2.Item1); await Task.Yield(); // this is assigned and persisted across await return v1.Item1; } } " + trivial2uple + tupleattributes_cs; var verifier = CompileAndVerify(source, targetFramework: TargetFramework.Mscorlib46, expectedOutput: @"5", options: TestOptions.ReleaseExe); // NOTE: !!! There should be NO IL local for " (long a, int b) v1 " , it should be captured instead // NOTE: !!! There should be an IL local for " (byte x, int y) v2 " , it should not be captured verifier.VerifyIL("C.d__1.System.Runtime.CompilerServices.IAsyncStateMachine.MoveNext()", @" { // Code size 193 (0xc1) .maxstack 3 .locals init (int V_0, long V_1, System.ValueTuple V_2, //v2 System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter V_3, System.Runtime.CompilerServices.YieldAwaitable V_4, System.Exception V_5) IL_0000: ldarg.0 IL_0001: ldfld ""int C.d__1.<>1__state"" IL_0006: stloc.0 .try { IL_0007: ldloc.0 IL_0008: brfalse.s IL_0062 IL_000a: ldarg.0 IL_000b: ldflda ""System.ValueTuple C.d__1.5__2"" IL_0010: ldc.i4.5 IL_0011: conv.i8 IL_0012: stfld ""long System.ValueTuple.Item1"" IL_0017: ldloca.s V_2 IL_0019: ldc.i4.5 IL_001a: stfld ""byte System.ValueTuple.Item1"" IL_001f: ldloc.2 IL_0020: ldfld ""byte System.ValueTuple.Item1"" IL_0025: call ""void System.Console.WriteLine(int)"" IL_002a: call ""System.Runtime.CompilerServices.YieldAwaitable System.Threading.Tasks.Task.Yield()"" IL_002f: stloc.s V_4 IL_0031: ldloca.s V_4 IL_0033: call ""System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter System.Runtime.CompilerServices.YieldAwaitable.GetAwaiter()"" IL_0038: stloc.3 IL_0039: ldloca.s V_3 IL_003b: call ""bool System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter.IsCompleted.get"" IL_0040: brtrue.s IL_007e IL_0042: ldarg.0 IL_0043: ldc.i4.0 IL_0044: dup IL_0045: stloc.0 IL_0046: stfld ""int C.d__1.<>1__state"" IL_004b: ldarg.0 IL_004c: ldloc.3 IL_004d: stfld ""System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter C.d__1.<>u__1"" IL_0052: ldarg.0 IL_0053: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder C.d__1.<>t__builder"" IL_0058: ldloca.s V_3 IL_005a: ldarg.0 IL_005b: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.AwaitUnsafeOnCompletedd__1>(ref System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter, ref C.d__1)"" IL_0060: leave.s IL_00c0 IL_0062: ldarg.0 IL_0063: ldfld ""System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter C.d__1.<>u__1"" IL_0068: stloc.3 IL_0069: ldarg.0 IL_006a: ldflda ""System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter C.d__1.<>u__1"" IL_006f: initobj ""System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter"" IL_0075: ldarg.0 IL_0076: ldc.i4.m1 IL_0077: dup IL_0078: stloc.0 IL_0079: stfld ""int C.d__1.<>1__state"" IL_007e: ldloca.s V_3 IL_0080: call ""void System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter.GetResult()"" IL_0085: ldarg.0 IL_0086: ldflda ""System.ValueTuple C.d__1.5__2"" IL_008b: ldfld ""long System.ValueTuple.Item1"" IL_0090: stloc.1 IL_0091: leave.s IL_00ac } catch System.Exception { IL_0093: stloc.s V_5 IL_0095: ldarg.0 IL_0096: ldc.i4.s -2 IL_0098: stfld ""int C.d__1.<>1__state"" IL_009d: ldarg.0 IL_009e: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder C.d__1.<>t__builder"" IL_00a3: ldloc.s V_5 IL_00a5: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetException(System.Exception)"" IL_00aa: leave.s IL_00c0 } IL_00ac: ldarg.0 IL_00ad: ldc.i4.s -2 IL_00af: stfld ""int C.d__1.<>1__state"" IL_00b4: ldarg.0 IL_00b5: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder C.d__1.<>t__builder"" IL_00ba: ldloc.1 IL_00bb: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetResult(long)"" IL_00c0: ret } "); } [Fact] public void StructInStruct() { var source = @" public struct S { public (S, S) field; } "; var comp = CreateCompilation(source); comp.VerifyDiagnostics( // (4,19): error CS0523: Struct member 'S.field' of type '(S, S)' causes a cycle in the struct layout // public (S, S) field; Diagnostic(ErrorCode.ERR_StructLayoutCycle, "field").WithArguments("S.field", "(S, S)").WithLocation(4, 19) ); } [Fact] public void RetargetTupleErrorType() { var lib_cs = @" public class A { public static (int, int) M() { return (1, 2); } } "; var source = @" public class B { void M2() { return A.M(); } } "; var lib = CreateCompilationWithMscorlib40(lib_cs, references: s_valueTupleRefs); lib.VerifyDiagnostics(); var comp = CreateCompilationWithMscorlib40(source, references: new[] { lib.ToMetadataReference() }); comp.VerifyDiagnostics( // (4,24): error CS0012: The type '(, )' is defined in an assembly that is not referenced. You must add a reference to assembly 'System.ValueTuple, Version=4.0.1.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51'. // void M2() { return A.M(); } Diagnostic(ErrorCode.ERR_NoTypeDef, "A.M").WithArguments("(, )", "System.ValueTuple, Version=4.0.1.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51").WithLocation(4, 24) ); var methodM = comp.GetMember("A.M"); Assert.Equal("(System.Int32, System.Int32)[missing]", methodM.ReturnTypeWithAnnotations.ToTestDisplayString()); Assert.True(methodM.ReturnType.IsTupleType); Assert.True(methodM.ReturnType.IsErrorType()); } [Fact, WorkItem(13088, "https://github.com/dotnet/roslyn/issues/13088")] public void AssignNullWithMissingValueTuple() { var source = @" public class S { (int, int) t = null; } "; var comp = CreateCompilationWithMscorlib40(source); comp.VerifyDiagnostics( // (4,5): error CS8179: Predefined type 'System.ValueTuple`2' is not defined or imported // (int, int) t = null; Diagnostic(ErrorCode.ERR_PredefinedValueTupleTypeNotFound, "(int, int)").WithArguments("System.ValueTuple`2").WithLocation(4, 5) ); } [Fact, WorkItem(11302, "https://github.com/dotnet/roslyn/issues/11302")] public void CrashInVisitCallReceiverOnBadTupleSyntax() { var source1 = @" public static class C1 { public void M1(this int x, (int, int))) { System.Console.WriteLine(""M1""); } } " + trivial2uple + tupleattributes_cs; var source2 = @" public static class C2 { public void M1(this int x, (int, int))) { System.Console.WriteLine(""M1""); } } " + trivial2uple + tupleattributes_cs; var comp1 = CreateCompilationWithMscorlib40AndSystemCore(source1, assemblyName: "comp1", parseOptions: TestOptions.Regular.WithTuplesFeature()); var comp2 = CreateCompilationWithMscorlib40AndSystemCore(source2, assemblyName: "comp2", parseOptions: TestOptions.Regular.WithTuplesFeature()); var source = @" class C3 { public static void Main() { int x = 0; x.M1((1, 1)); } } "; var comp = CreateCompilationWithMscorlib40(source, references: new[] { comp1.ToMetadataReference(), comp2.ToMetadataReference() }, parseOptions: TestOptions.Regular.WithTuplesFeature(), options: TestOptions.DebugExe); comp.VerifyDiagnostics( // (7,14): error CS8356: Predefined type 'System.ValueTuple`2' is declared in multiple referenced assemblies: 'comp1, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' and 'comp2, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' // x.M1((1, 1)); Diagnostic(ErrorCode.ERR_PredefinedValueTupleTypeAmbiguous3, "(1, 1)").WithArguments("System.ValueTuple`2", "comp1, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null", "comp2, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null").WithLocation(7, 14) ); } [Fact, WorkItem(12952, "https://github.com/dotnet/roslyn/issues/12952")] public void DropTupleNamesFromArray() { var source = @" public class C { public (int c, int d)[] M() { return new[] { (d: 1, 2) }; } public (int c, int d)[] M2() { return new[] { (d: 1, 2), (d: 1, e: 3), TupleDE() }; } public (int d, int e) TupleDE() { return (1, 3); } } "; var comp = CreateCompilation(source); comp.VerifyDiagnostics( // (10,42): warning CS8123: The tuple element name 'e' is ignored because a different name is specified by the target type '(int d, int)'. // return new[] { (d: 1, 2), (d: 1, e: 3), TupleDE() }; Diagnostic(ErrorCode.WRN_TupleLiteralNameMismatch, "e: 3").WithArguments("e", "(int d, int)").WithLocation(10, 42) ); } [Fact, WorkItem(10951, "https://github.com/dotnet/roslyn/issues/10951")] public void ObsoleteValueTuple() { var lib_cs = @" namespace System { [Obsolete] public struct ValueTuple { public ValueTuple(T1 item1, T2 item2) { } } public struct ValueTuple { public ValueTuple(T1 item1, T2 item2, T3 item3) { } } [Obsolete] public struct ValueTuple { public ValueTuple(T1 item1, T2 item2, T3 item3, T4 item4, T5 item5, T6 item6, T7 item7, TRest rest) { } public TRest Rest; } } public class D { public static void M2((int, int) x) { } public static void M3((int, string) x) { } } "; var source = @" public class C { void M() { (int, int) x1 = (1, 2); var x2 = (1, 2); var x9 = (1, 2, 3, 4, 5, 6, 7, 8, 9); var x10 = (1, 2, 3, 4, 5, 6, 7, 8, 9, 10); D.M2((1, 2)); D.M3((1, null)); System.Console.Write($""{x1} {x2} {x9} {x10}""); } } "; var compLib = CreateCompilationWithMscorlib40(lib_cs, options: TestOptions.ReleaseDll); var comp = CreateCompilationWithMscorlib40(source, references: new[] { compLib.ToMetadataReference() }); comp.VerifyDiagnostics( // (6,9): warning CS0612: '(T1, T2)' is obsolete // (int, int) x1 = (1, 2); Diagnostic(ErrorCode.WRN_DeprecatedSymbol, "(int, int)").WithArguments("(T1, T2)").WithLocation(6, 9), // (6,9): warning CS0612: '(int, int)' is obsolete // (int, int) x1 = (1, 2); Diagnostic(ErrorCode.WRN_DeprecatedSymbol, "(int, int)").WithArguments("(int, int)").WithLocation(6, 9), // (6,25): warning CS0612: '(T1, T2)' is obsolete // (int, int) x1 = (1, 2); Diagnostic(ErrorCode.WRN_DeprecatedSymbol, "(1, 2)").WithArguments("(T1, T2)").WithLocation(6, 25), // (7,18): warning CS0612: '(T1, T2)' is obsolete // var x2 = (1, 2); Diagnostic(ErrorCode.WRN_DeprecatedSymbol, "(1, 2)").WithArguments("(T1, T2)").WithLocation(7, 18), // (8,18): warning CS0612: '(T1, T2)' is obsolete // var x9 = (1, 2, 3, 4, 5, 6, 7, 8, 9); Diagnostic(ErrorCode.WRN_DeprecatedSymbol, "(1, 2, 3, 4, 5, 6, 7, 8, 9)").WithArguments("(T1, T2)").WithLocation(8, 18), // (8,18): warning CS0612: 'ValueTuple' is obsolete // var x9 = (1, 2, 3, 4, 5, 6, 7, 8, 9); Diagnostic(ErrorCode.WRN_DeprecatedSymbol, "(1, 2, 3, 4, 5, 6, 7, 8, 9)").WithArguments("System.ValueTuple").WithLocation(8, 18), // (9,19): warning CS0612: 'ValueTuple' is obsolete // var x10 = (1, 2, 3, 4, 5, 6, 7, 8, 9, 10); Diagnostic(ErrorCode.WRN_DeprecatedSymbol, "(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)").WithArguments("System.ValueTuple").WithLocation(9, 19), // (10,14): warning CS0612: '(T1, T2)' is obsolete // D.M2((1, 2)); Diagnostic(ErrorCode.WRN_DeprecatedSymbol, "(1, 2)").WithArguments("(T1, T2)").WithLocation(10, 14), // (11,14): warning CS0612: '(T1, T2)' is obsolete // D.M3((1, null)); Diagnostic(ErrorCode.WRN_DeprecatedSymbol, "(1, null)").WithArguments("(T1, T2)").WithLocation(11, 14) ); } [Fact, WorkItem(10951, "https://github.com/dotnet/roslyn/issues/10951")] public void ObsoleteValueTuple2() { var source = @" public class C { void M() { var x9 = (1, 2, 3, 4, 5, 6, 7, 8, 9); System.Console.Write(x9); } } namespace System { [Obsolete] public struct ValueTuple { public ValueTuple(T1 item1, T2 item2) => throw null; } public struct ValueTuple { public ValueTuple(T1 item1, T2 item2, T3 item3, T4 item4, T5 item5, T6 item6, T7 item7, TRest rest) { Rest = rest; } public TRest Rest; } } "; var comp = CreateCompilation(source); comp.VerifyDiagnostics( // (6,18): warning CS0612: '(T1, T2)' is obsolete // var x9 = (1, 2, 3, 4, 5, 6, 7, 8, 9); Diagnostic(ErrorCode.WRN_DeprecatedSymbol, "(1, 2, 3, 4, 5, 6, 7, 8, 9)").WithArguments("(T1, T2)").WithLocation(6, 18) ); } [Fact, WorkItem(13365, "https://github.com/dotnet/roslyn/issues/13365")] public void Bug13365() { var source = @" namespace System { public struct ValueTuple { public ValueTuple(T1 item1, T2 item2) => throw null; } } namespace System.Runtime.CompilerServices { public class TupleElementNamesAttribute : Attribute { public TupleElementNamesAttribute(string[] transformNames) { } } } public class C { public (int, int) GetCoordinates() => (0, 0); public (int x, int y) GetCoordinates2() => (0, 0); public void PrintCoordinates() { (int x1, int y1) = GetCoordinates(); (int x2, int y2) = GetCoordinates2(); } } "; var comp = CreateCompilation(source, assemblyName: "comp"); comp.VerifyEmitDiagnostics( // (25,28): error CS8128: Member 'Item1' was not found on type '(T1, T2)' from assembly 'comp, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'. // (int x1, int y1) = GetCoordinates(); Diagnostic(ErrorCode.ERR_PredefinedTypeMemberNotFoundInAssembly, "GetCoordinates()").WithArguments("Item1", "(T1, T2)", "comp, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null").WithLocation(25, 28), // (25,28): error CS8128: Member 'Item2' was not found on type '(T1, T2)' from assembly 'comp, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'. // (int x1, int y1) = GetCoordinates(); Diagnostic(ErrorCode.ERR_PredefinedTypeMemberNotFoundInAssembly, "GetCoordinates()").WithArguments("Item2", "(T1, T2)", "comp, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null").WithLocation(25, 28), // (26,28): error CS8128: Member 'Item1' was not found on type '(T1, T2)' from assembly 'comp, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'. // (int x2, int y2) = GetCoordinates2(); Diagnostic(ErrorCode.ERR_PredefinedTypeMemberNotFoundInAssembly, "GetCoordinates2()").WithArguments("Item1", "(T1, T2)", "comp, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null").WithLocation(26, 28), // (26,28): error CS8128: Member 'Item2' was not found on type '(T1, T2)' from assembly 'comp, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'. // (int x2, int y2) = GetCoordinates2(); Diagnostic(ErrorCode.ERR_PredefinedTypeMemberNotFoundInAssembly, "GetCoordinates2()").WithArguments("Item2", "(T1, T2)", "comp, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null").WithLocation(26, 28) ); } [Fact, WorkItem(13494, "https://github.com/dotnet/roslyn/issues/13494")] public static void Bug13494() { var source1 = @" class Program { static void Main(string[] args) { var(a, ) } } "; var text = SourceText.From(source1); var startTree = SyntaxFactory.ParseSyntaxTree(text); var finalString = startTree.GetCompilationUnitRoot().ToFullString(); var pos = source1.IndexOf("var(a, )") + 8; var newText = text.WithChanges(new TextChange(new TextSpan(pos, 0), " ")); // add space before closing-paren var newTree = startTree.WithChangedText(newText); var finalText = newTree.GetCompilationUnitRoot().ToFullString(); Assert.Equal(newText.ToString(), finalText); // no crash } [Fact] [WorkItem(258853, "https://devdiv.visualstudio.com/DevDiv/_workitems/edit/258853")] public void BadOverloadWithTupleLiteralWithNaturalType() { var source = @" class Program { static void M(int i) { } static void M(string i) { } static void Main() { M((1, 2)); } }"; var comp = CreateCompilation(source); comp.VerifyDiagnostics( // (9,11): error CS1503: Argument 1: cannot convert from '(int, int)' to 'int' // M((1, 2)); Diagnostic(ErrorCode.ERR_BadArgType, "(1, 2)").WithArguments("1", "(int, int)", "int").WithLocation(9, 11)); } [Fact] [WorkItem(258853, "https://devdiv.visualstudio.com/DevDiv/_workitems/edit/258853")] public void BadOverloadWithTupleLiteralWithNoNaturalType() { var source = @" class Program { static void M(int i) { } static void M(string i) { } static void Main() { M((1, null)); } }"; var comp = CreateCompilation(source); comp.VerifyDiagnostics( // (9,11): error CS1503: Argument 1: cannot convert from '(int, )' to 'int' // M((1, null)); Diagnostic(ErrorCode.ERR_BadArgType, "(1, null)").WithArguments("1", "(int, )", "int").WithLocation(9, 11)); } [Fact] [WorkItem(261049, "https://devdiv.visualstudio.com/DevDiv/_workitems/edit/261049")] public void DevDiv261049RegressionTest() { var source = @" class Program { static void Main(string[] args) { var (a,b) = Get(out int x, out int y); Console.WriteLine($""({a.first}, {a.second})""); } static (string first,string second) Get(out int a, out int b) { a = 0; b = 1; return (""a"",""b""); } } "; var comp = CreateCompilation(source); comp.VerifyDiagnostics( // (7,37): error CS1061: 'string' does not contain a definition for 'first' and no extension method 'first' accepting a first argument of type 'string' could be found (are you missing a using directive or an assembly reference?) // Console.WriteLine($"({a.first}, {a.second})"); Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "first").WithArguments("string", "first").WithLocation(7, 37), // (7,48): error CS1061: 'string' does not contain a definition for 'second' and no extension method 'second' accepting a first argument of type 'string' could be found (are you missing a using directive or an assembly reference?) // Console.WriteLine($"({a.first}, {a.second})"); Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "second").WithArguments("string", "second").WithLocation(7, 48), // (7,13): error CS0103: The name 'Console' does not exist in the current context // Console.WriteLine($"({a.first}, {a.second})"); Diagnostic(ErrorCode.ERR_NameNotInContext, "Console").WithArguments("Console").WithLocation(7, 13) ); } [Fact, WorkItem(13705, "https://github.com/dotnet/roslyn/issues/13705")] public static void TupleCoVariance() { var source = @" public interface I { System.ValueTuple M(); } "; var comp1 = CreateCompilation(source); comp1.VerifyDiagnostics( // (4,5): error CS1961: Invalid variance: The type parameter 'T' must be invariantly valid on 'I.M()'. 'T' is covariant. // System.ValueTuple M(); Diagnostic(ErrorCode.ERR_UnexpectedVariance, "System.ValueTuple").WithArguments("I.M()", "T", "covariant", "invariantly").WithLocation(4, 5) ); } [Fact, WorkItem(13705, "https://github.com/dotnet/roslyn/issues/13705")] public static void TupleCoVariance2() { var source = @" public interface I { (bool, T)[] M(); } "; var comp1 = CreateCompilation(source); comp1.VerifyDiagnostics( // (4,5): error CS1961: Invalid variance: The type parameter 'T' must be invariantly valid on 'I.M()'. 'T' is covariant. // (bool, T)[] M(); Diagnostic(ErrorCode.ERR_UnexpectedVariance, "(bool, T)[]").WithArguments("I.M()", "T", "covariant", "invariantly").WithLocation(4, 5) ); } [Fact, WorkItem(13705, "https://github.com/dotnet/roslyn/issues/13705")] public static void TupleContraVariance() { var source = @" public interface I { void M((bool, T)[] x); } "; var comp1 = CreateCompilation(source); comp1.VerifyDiagnostics( // (4,12): error CS1961: Invalid variance: The type parameter 'T' must be invariantly valid on 'I.M((bool, T)[])'. 'T' is contravariant. // void M((bool, T)[] x); Diagnostic(ErrorCode.ERR_UnexpectedVariance, "(bool, T)[]").WithArguments("I.M((bool, T)[])", "T", "contravariant", "invariantly").WithLocation(4, 12) ); } [ConditionalFact(typeof(DesktopOnly))] [WorkItem(13767, "https://github.com/dotnet/roslyn/issues/13767")] public void TupleInConstant() { var source = @" class C { } class C { static void Main() { const C<(int, int)> c = null; System.Console.Write(c); } }"; var comp = CreateCompilation(source, assemblyName: "comp", options: TestOptions.DebugExe); // emit without pdb using (ModuleMetadata block = ModuleMetadata.CreateFromStream(comp.EmitToStream())) { var reader = block.MetadataReader; AssertEx.SetEqual(new[] { "mscorlib 4.0", "System.ValueTuple 4.0" }, reader.DumpAssemblyReferences()); Assert.Contains("ValueTuple`2, System, AssemblyReference:System.ValueTuple", reader.DumpTypeReferences()); } // emit with pdb comp.VerifyEmitDiagnostics(); CompileAndVerify(comp, expectedOutput: "", validator: (assembly) => { var reader = assembly.GetMetadataReader(); AssertEx.SetEqual(new[] { "mscorlib 4.0", "System.ValueTuple 4.0" }, reader.DumpAssemblyReferences()); Assert.Contains("ValueTuple`2, System, AssemblyReference:System.ValueTuple", reader.DumpTypeReferences()); }); // no assertion in MetadataWriter } [ConditionalFact(typeof(DesktopOnly))] [WorkItem(13767, "https://github.com/dotnet/roslyn/issues/13767")] public void ConstantTypeFromReferencedAssembly() { var libSource = @" public class ReferencedType { } "; var source = @" class C { static void Main() { const ReferencedType c = null; System.Console.Write(c); } }"; var libComp = CreateCompilationWithMscorlib40(libSource, assemblyName: "lib"); libComp.VerifyDiagnostics(); var comp = CreateCompilationWithMscorlib40(source, assemblyName: "comp", references: new[] { libComp.EmitToImageReference() }, options: TestOptions.DebugExe); // emit without pdb using (ModuleMetadata block = ModuleMetadata.CreateFromStream(comp.EmitToStream())) { var reader = block.MetadataReader; AssertEx.SetEqual(new[] { "mscorlib 4.0", "lib 0.0" }, reader.DumpAssemblyReferences()); Assert.Contains("ReferencedType, , AssemblyReference:lib", reader.DumpTypeReferences()); } // emit with pdb comp.VerifyEmitDiagnostics(); CompileAndVerify(comp, expectedOutput: "", validator: (assembly) => { var reader = assembly.GetMetadataReader(); AssertEx.SetEqual(new[] { "mscorlib 4.0", "lib 0.0" }, reader.DumpAssemblyReferences()); Assert.Contains("ReferencedType, , AssemblyReference:lib", reader.DumpTypeReferences()); }); // no assertion in MetadataWriter } [Fact] [WorkItem(13661, "https://github.com/dotnet/roslyn/issues/13661")] public void LongTupleWithPartialNames_Bug13661() { var source = @" using System; class C { static void Main() { var o = (A: 1, 2, C: 3, D: 4, E: 5, F: 6, G: 7, 8, I: 9); Console.Write(o.I); } } "; CompileAndVerify(source, options: TestOptions.DebugExe, expectedOutput: @"9", sourceSymbolValidator: (module) => { var sourceModule = (SourceModuleSymbol)module; var compilation = sourceModule.DeclaringCompilation; var tree = compilation.SyntaxTrees.First(); var model = compilation.GetSemanticModel(tree); var nodes = tree.GetCompilationUnitRoot().DescendantNodes(); var x = nodes.OfType().First(); var xSymbol = ((ILocalSymbol)model.GetDeclaredSymbol(x)).Type; AssertEx.SetEqual(xSymbol.GetMembers().OfType().Select(f => f.Name), "A", "C", "D", "E", "F", "G", "I", "Item1", "Item2", "Item3", "Item4", "Item5", "Item6", "Item7", "Item8", "Item9", "Rest"); }); // no assert hit } [Fact] [WorkItem(11689, "https://github.com/dotnet/roslyn/issues/11689")] public void ValueTupleNotStruct0() { var source = @" class C { static void Main() { (int a, int b) x; x.Item1 = 1; x.b = 2; // by the language rules tuple x is definitely assigned // since all its elements are definitely assigned System.Console.WriteLine(x); } } namespace System { public class ValueTuple { public T1 Item1; public T2 Item2; public ValueTuple(T1 item1, T2 item2) { this.Item1 = item1; this.Item2 = item2; } } } " + tupleattributes_cs; var comp = CreateCompilation(source, assemblyName: "ValueTupleNotStruct", options: TestOptions.DebugExe); comp.VerifyEmitDiagnostics( // (7,9): error CS0165: Use of unassigned local variable 'x' // x.Item1 = 1; Diagnostic(ErrorCode.ERR_UseDefViolation, "x").WithArguments("x").WithLocation(7, 9), // (23,9): error CS8182: Predefined type 'ValueTuple`2' must be a struct. // public ValueTuple(T1 item1, T2 item2) { this.Item1 = item1; this.Item2 = item2; } Diagnostic(ErrorCode.ERR_PredefinedValueTupleTypeMustBeStruct, "public ValueTuple(T1 item1, T2 item2) { this.Item1 = item1; this.Item2 = item2; }").WithArguments("ValueTuple`2").WithLocation(23, 9) ); } [Fact] [WorkItem(11689, "https://github.com/dotnet/roslyn/issues/11689")] public void ValueTupleNotStruct1() { var source = @" class C { static void Main() { var x = (1,2,3,4,5,6,7,8,9); System.Console.WriteLine(x); } } namespace System { public class ValueTuple { public T1 Item1; public T2 Item2; public ValueTuple(T1 item1, T2 item2) { this.Item1 = item1; this.Item2 = item2; } } public class ValueTuple { public T1 Item1; public T2 Item2; public T3 Item3; public T4 Item4; public T5 Item5; public T6 Item6; public T7 Item7; public TRest Rest; public ValueTuple(T1 item1, T2 item2, T3 item3, T4 item4, T5 item5, T6 item6, T7 item7, TRest rest) { Item1 = item1; Item2 = item2; Item3 = item3; Item4 = item4; Item5 = item5; Item6 = item6; Item7 = item7; Rest = rest; } public override string ToString() { return base.ToString(); } } } " + tupleattributes_cs; var comp = CreateCompilation(source, assemblyName: "ValueTupleNotStruct", options: TestOptions.DebugExe); comp.VerifyEmitDiagnostics( // (6,13): error CS8182: Predefined type 'ValueTuple`8' must be a struct. // var x = (1,2,3,4,5,6,7,8,9); Diagnostic(ErrorCode.ERR_PredefinedValueTupleTypeMustBeStruct, "x = (1,2,3,4,5,6,7,8,9)").WithArguments("ValueTuple`8").WithLocation(6, 13), // (6,13): error CS8182: Predefined type 'ValueTuple`2' must be a struct. // var x = (1,2,3,4,5,6,7,8,9); Diagnostic(ErrorCode.ERR_PredefinedValueTupleTypeMustBeStruct, "x = (1,2,3,4,5,6,7,8,9)").WithArguments("ValueTuple`2").WithLocation(6, 13), // (19,9): error CS8182: Predefined type 'ValueTuple`2' must be a struct. // public ValueTuple(T1 item1, T2 item2) Diagnostic(ErrorCode.ERR_PredefinedValueTupleTypeMustBeStruct, @"public ValueTuple(T1 item1, T2 item2) { this.Item1 = item1; this.Item2 = item2; }").WithArguments("ValueTuple`2").WithLocation(19, 9) ); } [Fact] [WorkItem(11689, "https://github.com/dotnet/roslyn/issues/11689")] public void ValueTupleNotStruct2() { var source = @" class C { static void Main() { } static void Test2((int a, int b) arg) { } } namespace System { public class ValueTuple { public T1 Item1; public T2 Item2; public ValueTuple(T1 item1, T2 item2) { this.Item1 = item1; this.Item2 = item2; } } } " + tupleattributes_cs; var comp = CreateCompilation(source, assemblyName: "ValueTupleNotStruct", options: TestOptions.DebugExe); comp.VerifyEmitDiagnostics( // (20,9): error CS8182: Predefined type 'ValueTuple`2' must be a struct. // public ValueTuple(T1 item1, T2 item2) { this.Item1 = item1; this.Item2 = item2; } Diagnostic(ErrorCode.ERR_PredefinedValueTupleTypeMustBeStruct, "public ValueTuple(T1 item1, T2 item2) { this.Item1 = item1; this.Item2 = item2; }").WithArguments("ValueTuple`2").WithLocation(20, 9) ); } [Fact] [WorkItem(11689, "https://github.com/dotnet/roslyn/issues/11689")] public void ValueTupleNotStruct2i() { var source = @" class C { static void Main() { } static void Test2((int a, int b) arg) { } } namespace System { public interface ValueTuple { } } " + tupleattributes_cs; var comp = CreateCompilation(source, assemblyName: "ValueTupleNotStruct", options: TestOptions.DebugExe); comp.VerifyEmitDiagnostics( // error CS8182: Predefined type 'ValueTuple`2' must be a struct. Diagnostic(ErrorCode.ERR_PredefinedValueTupleTypeMustBeStruct).WithArguments("ValueTuple`2").WithLocation(1, 1), // error CS8182: Predefined type 'ValueTuple`2' must be a struct. Diagnostic(ErrorCode.ERR_PredefinedValueTupleTypeMustBeStruct).WithArguments("ValueTuple`2").WithLocation(1, 1) ); } [Fact] [WorkItem(11689, "https://github.com/dotnet/roslyn/issues/11689")] public void ValueTupleNotStruct3() { var source = @" class C { static void Main() { } static void Test1() { (int, int)[] x = null; System.Console.WriteLine(x); } } namespace System { public class ValueTuple { public T1 Item1; public T2 Item2; public ValueTuple(T1 item1, T2 item2) { this.Item1 = item1; this.Item2 = item2; } } } " + tupleattributes_cs; var comp = CreateCompilation(source, assemblyName: "ValueTupleNotStruct", options: TestOptions.DebugExe); comp.VerifyEmitDiagnostics( // (10,22): error CS8182: Predefined type 'ValueTuple`2' must be a struct. // (int, int)[] x = null; Diagnostic(ErrorCode.ERR_PredefinedValueTupleTypeMustBeStruct, "x = null").WithArguments("ValueTuple`2").WithLocation(10, 22), // (23,9): error CS8182: Predefined type 'ValueTuple`2' must be a struct. // public ValueTuple(T1 item1, T2 item2) { this.Item1 = item1; this.Item2 = item2; } Diagnostic(ErrorCode.ERR_PredefinedValueTupleTypeMustBeStruct, "public ValueTuple(T1 item1, T2 item2) { this.Item1 = item1; this.Item2 = item2; }").WithArguments("ValueTuple`2").WithLocation(23, 9) ); } [Fact] [WorkItem(11689, "https://github.com/dotnet/roslyn/issues/11689")] public void ValueTupleNotStruct4() { var source = @" class C { static void Main() { } static (int a, int b) Test2() { return (1, 1); } } namespace System { public class ValueTuple { public T1 Item1; public T2 Item2; public ValueTuple(T1 item1, T2 item2) { this.Item1 = item1; this.Item2 = item2; } } } " + tupleattributes_cs; var comp = CreateCompilation(source, assemblyName: "ValueTupleNotStruct", options: TestOptions.DebugExe); comp.VerifyEmitDiagnostics( // (8,35): error CS8182: Predefined type 'ValueTuple`2' must be a struct. // static (int a, int b) Test2() { return (1, 1); } Diagnostic(ErrorCode.ERR_PredefinedValueTupleTypeMustBeStruct, "{ return (1, 1); }").WithArguments("ValueTuple`2").WithLocation(8, 35), // (8,44): error CS8182: Predefined type 'ValueTuple`2' must be a struct. // static (int a, int b) Test2() { return (1, 1); } Diagnostic(ErrorCode.ERR_PredefinedValueTupleTypeMustBeStruct, "(1, 1)").WithArguments("ValueTuple`2").WithLocation(8, 44), // (18,9): error CS8182: Predefined type 'ValueTuple`2' must be a struct. // public ValueTuple(T1 item1, T2 item2) { this.Item1 = item1; this.Item2 = item2; } Diagnostic(ErrorCode.ERR_PredefinedValueTupleTypeMustBeStruct, "public ValueTuple(T1 item1, T2 item2) { this.Item1 = item1; this.Item2 = item2; }").WithArguments("ValueTuple`2").WithLocation(18, 9) ); } [Fact] public void ValueTupleBaseError_NoSystemRuntime() { var source = @"interface I { ((int, int), (int, int)) F(); }"; var comp = CreateCompilationWithMscorlib40(source, references: new[] { ValueTupleRef }); comp.VerifyEmitDiagnostics( // (3,6): error CS0012: The type 'ValueType' is defined in an assembly that is not referenced. You must add a reference to assembly 'System.Runtime, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'. // ((int, int), (int, int)) F(); Diagnostic(ErrorCode.ERR_NoTypeDef, "(int, int)").WithArguments("System.ValueType", "System.Runtime, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a").WithLocation(3, 6), // (3,18): error CS0012: The type 'ValueType' is defined in an assembly that is not referenced. You must add a reference to assembly 'System.Runtime, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'. // ((int, int), (int, int)) F(); Diagnostic(ErrorCode.ERR_NoTypeDef, "(int, int)").WithArguments("System.ValueType", "System.Runtime, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a").WithLocation(3, 18), // (3,5): error CS0012: The type 'ValueType' is defined in an assembly that is not referenced. You must add a reference to assembly 'System.Runtime, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'. // ((int, int), (int, int)) F(); Diagnostic(ErrorCode.ERR_NoTypeDef, "((int, int), (int, int))").WithArguments("System.ValueType", "System.Runtime, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a").WithLocation(3, 5)); } [WorkItem(16879, "https://github.com/dotnet/roslyn/issues/16879")] [Fact] public void ValueTupleBaseError_MissingReference() { var source0 = @"public class A { } public class B { }"; var comp0 = CreateCompilationWithMscorlib40(source0, assemblyName: "92872377-08d1-4723-8906-a43b03e56ed3"); comp0.VerifyDiagnostics(); var ref0 = comp0.EmitToImageReference(); var source1 = @"public class C { } namespace System { public class ValueTuple : A { public ValueTuple(T1 _1, T2 _2) { } } public class ValueTuple : C { public ValueTuple(T1 _1, T2 _2, T3 _3) { } } }"; var comp1 = CreateCompilationWithMscorlib40(source1, references: new[] { ref0 }); comp1.VerifyDiagnostics(); var ref1 = comp1.EmitToImageReference(); var source = @"interface I { (int, (int, int), (int, int)) F(); }"; var comp = CreateCompilationWithMscorlib40(source, references: new[] { ref1 }); comp.VerifyEmitDiagnostics( // error CS0012: The type 'B' is defined in an assembly that is not referenced. You must add a reference to assembly '92872377-08d1-4723-8906-a43b03e56ed3, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'. Diagnostic(ErrorCode.ERR_NoTypeDef).WithArguments("B", "92872377-08d1-4723-8906-a43b03e56ed3, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null").WithLocation(1, 1), // error CS0012: The type 'B' is defined in an assembly that is not referenced. You must add a reference to assembly '92872377-08d1-4723-8906-a43b03e56ed3, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'. Diagnostic(ErrorCode.ERR_NoTypeDef).WithArguments("B", "92872377-08d1-4723-8906-a43b03e56ed3, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null").WithLocation(1, 1), // error CS0012: The type 'A' is defined in an assembly that is not referenced. You must add a reference to assembly '92872377-08d1-4723-8906-a43b03e56ed3, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'. Diagnostic(ErrorCode.ERR_NoTypeDef).WithArguments("A", "92872377-08d1-4723-8906-a43b03e56ed3, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null").WithLocation(1, 1), // error CS0012: The type 'A' is defined in an assembly that is not referenced. You must add a reference to assembly '92872377-08d1-4723-8906-a43b03e56ed3, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'. Diagnostic(ErrorCode.ERR_NoTypeDef).WithArguments("A", "92872377-08d1-4723-8906-a43b03e56ed3, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null").WithLocation(1, 1)); } [Fact] public void ValueTupleBase_AssemblyUnification() { var source0v1 = @"[assembly: System.Reflection.AssemblyVersion(""1.0.0.0"")] public class A { }"; var signedDllOptions = TestOptions.SigningReleaseDll. WithCryptoKeyFile(SigningTestHelpers.KeyPairFile); var comp0v1 = CreateCompilationWithMscorlib40(source0v1, assemblyName: "A", options: signedDllOptions); comp0v1.VerifyDiagnostics(); var ref0v1 = comp0v1.EmitToImageReference(); var source0v2 = @"[assembly: System.Reflection.AssemblyVersion(""2.0.0.0"")] public class A { }"; var comp0v2 = CreateCompilationWithMscorlib40(source0v2, assemblyName: "A", options: signedDllOptions); comp0v2.VerifyDiagnostics(); var ref0v2 = comp0v2.EmitToImageReference(); var source1 = @"public class B : A { }"; var comp1 = CreateCompilationWithMscorlib40(source1, references: new[] { ref0v1 }); comp1.VerifyDiagnostics(); var ref1 = comp1.EmitToImageReference(); var source2 = @"namespace System { public class ValueTuple : B { public ValueTuple(T1 _1, T2 _2) { } } }"; var comp2 = CreateCompilationWithMscorlib40(source2, references: new[] { ref1, ref0v1 }); comp2.VerifyDiagnostics(); var ref2 = comp2.EmitToImageReference(); var source = @"interface I { (int, int) F(); }"; var comp = CreateCompilationWithMscorlib40(source, references: new[] { ref0v2, ref1, ref2 }); comp.VerifyEmitDiagnostics( // error CS8182: Predefined type 'ValueTuple`2' must be a struct. Diagnostic(ErrorCode.ERR_PredefinedValueTupleTypeMustBeStruct).WithArguments("ValueTuple`2").WithLocation(1, 1), // error CS8182: Predefined type 'ValueTuple`2' must be a struct. Diagnostic(ErrorCode.ERR_PredefinedValueTupleTypeMustBeStruct).WithArguments("ValueTuple`2").WithLocation(1, 1)); } [ConditionalFact(typeof(DesktopOnly))] [WorkItem(13472, "https://github.com/dotnet/roslyn/issues/13472")] public void InvalidCastRef() { var source = @" namespace System { public struct ValueTuple { public T1 Item1; public T2 Item2; public ValueTuple(T1 _1, T2 _2) { Item1 = _1; Item2 = _2; } } } namespace System.Runtime.CompilerServices { public class TupleElementNamesAttribute : Attribute { public TupleElementNamesAttribute(string[] names) { } } } class C { static void Main() { (int A, int B) x = (1, 2); ref (int, int) y = ref x; } }"; var comp = CompileAndVerify(source); comp.EmitAndVerify(); } [Fact] [WorkItem(14166, "https://github.com/dotnet/roslyn/issues/14166")] public void RefTuple001() { var source = @" class Program { static (int Alice, int Bob)[] arr = new(int Alice, int Bob)[1]; static void Main(string[] args) { RefParam(ref arr[0]); System.Console.WriteLine(arr[0]); RefReturn().Item2 = 42; System.Console.WriteLine(arr[0]); ref (int, int) x = ref arr[0]; x.Item1 = 33; System.Console.WriteLine(arr[0]); } static void RefParam(ref (int, int) p) { p.Item1 = 42; } static ref (int, int) RefReturn() { return ref arr[0]; } }"; var comp = CompileAndVerify(source, parseOptions: TestOptions.Regular, expectedOutput: @"(42, 0) (42, 42) (33, 42)"); comp.VerifyIL("Program.Main", @" { // Code size 110 (0x6e) .maxstack 2 IL_0000: ldsfld ""System.ValueTuple[] Program.arr"" IL_0005: ldc.i4.0 IL_0006: ldelema ""System.ValueTuple"" IL_000b: call ""void Program.RefParam(ref System.ValueTuple)"" IL_0010: ldsfld ""System.ValueTuple[] Program.arr"" IL_0015: ldc.i4.0 IL_0016: ldelem ""System.ValueTuple"" IL_001b: box ""System.ValueTuple"" IL_0020: call ""void System.Console.WriteLine(object)"" IL_0025: call ""ref System.ValueTuple Program.RefReturn()"" IL_002a: ldc.i4.s 42 IL_002c: stfld ""int System.ValueTuple.Item2"" IL_0031: ldsfld ""System.ValueTuple[] Program.arr"" IL_0036: ldc.i4.0 IL_0037: ldelem ""System.ValueTuple"" IL_003c: box ""System.ValueTuple"" IL_0041: call ""void System.Console.WriteLine(object)"" IL_0046: ldsfld ""System.ValueTuple[] Program.arr"" IL_004b: ldc.i4.0 IL_004c: ldelema ""System.ValueTuple"" IL_0051: ldc.i4.s 33 IL_0053: stfld ""int System.ValueTuple.Item1"" IL_0058: ldsfld ""System.ValueTuple[] Program.arr"" IL_005d: ldc.i4.0 IL_005e: ldelem ""System.ValueTuple"" IL_0063: box ""System.ValueTuple"" IL_0068: call ""void System.Console.WriteLine(object)"" IL_006d: ret } "); comp.VerifyIL("Program.RefReturn", @" { // Code size 12 (0xc) .maxstack 2 IL_0000: ldsfld ""System.ValueTuple[] Program.arr"" IL_0005: ldc.i4.0 IL_0006: ldelema ""System.ValueTuple"" IL_000b: ret } "); } [Fact] public static void OperatorOverloadingWithDifferentTupleNames() { var source = @" public class B1 { public static bool operator >=((B1 a, B1 b) x1, B1 x2) { return true; } public static bool operator <=((B1 notA, B1 notB) x1, B1 x2) { return true; } } "; var comp1 = CreateCompilation(source); comp1.VerifyDiagnostics(); } [WorkItem(14708, "https://github.com/dotnet/roslyn/issues/14708")] [WorkItem(14709, "https://github.com/dotnet/roslyn/issues/14709")] [ConditionalFact(typeof(DesktopOnly))] public void RefTupleDynamicDecode001() { string lib = @" namespace ClassLibrary1 { public class C1 { public virtual ref (int, dynamic) Goo(int arg) { return ref new (int, dynamic)[]{(1, arg)}[0]; } } } "; var libComp = CreateCompilationWithMscorlib45AndCSharp(lib, references: s_valueTupleRefs, options: TestOptions.DebugDll); libComp.VerifyDiagnostics(); var source = @" namespace ConsoleApplication5 { class Program { static void Main(string[] args) { ref var x = ref new C2().Goo(42); System.Console.Write(x.Item2); x.Item2 = ""qq""; System.Console.WriteLine(x.Item2); } } class C2: ClassLibrary1.C1 { public override ref (int, object) Goo(int arg) { return ref base.Goo(arg); } } } "; var comp = CompileAndVerify(source, expectedOutput: "42qq", references: new[] { libComp.ToMetadataReference() }, options: TestOptions.DebugExe, verify: Verification.Fails); var m = (MethodSymbol)(((CSharpCompilation)comp.Compilation).GetTypeByMetadataName("ConsoleApplication5.C2").GetMembers("Goo").First()); Assert.Equal("ref (System.Int32, System.Object) ConsoleApplication5.C2.Goo(System.Int32 arg)", m.ToTestDisplayString()); var b = m.OverriddenMethod; Assert.Equal("ref (System.Int32, dynamic) ClassLibrary1.C1.Goo(System.Int32 arg)", b.ToTestDisplayString()); } [WorkItem(14708, "https://github.com/dotnet/roslyn/issues/14708")] [WorkItem(14709, "https://github.com/dotnet/roslyn/issues/14709")] [Fact] public void RefTupleDynamicDecode002() { string lib = @" namespace ClassLibrary1 { public class C1 { public virtual ref (int, dynamic) Goo(int arg) { return ref new (int, dynamic)[]{(1, arg)}[0]; } } } "; var libComp = CreateCompilationWithMscorlib45AndCSharp(lib, options: TestOptions.DebugDll, references: s_valueTupleRefs); libComp.VerifyDiagnostics(); var source = @" namespace ConsoleApplication5 { class Program { static void Main(string[] args) { ref var x = ref new C2().Goo(42); System.Console.Write(x.Item2); x.Item2 = ""qq""; System.Console.WriteLine(x.Item2); } } class C2: ClassLibrary1.C1 { public override ref (int, object) Goo(int arg) { return ref base.Goo(arg); } } } "; var libCompRef = AssemblyMetadata.CreateFromImage(libComp.EmitToArray()).GetReference(); var comp = CompileAndVerifyWithMscorlib40(source, expectedOutput: "42qq", references: s_valueTupleRefs.Concat(new[] { libCompRef }).ToArray(), options: TestOptions.DebugExe, verify: Verification.Fails); var m = (IMethodSymbol)(comp.Compilation.GetTypeByMetadataName("ConsoleApplication5.C2").GetMembers("Goo").First()); Assert.Equal("ref (System.Int32, System.Object) ConsoleApplication5.C2.Goo(System.Int32 arg)", m.ToTestDisplayString()); var b = m.OverriddenMethod; Assert.Equal("ref (System.Int32, dynamic) ClassLibrary1.C1.Goo(System.Int32 arg)", b.ToTestDisplayString()); } [Fact] [WorkItem(269808, "https://devdiv.visualstudio.com/DevDiv/_workitems?id=269808")] public void UserDefinedConversionsAndNameMismatch_01() { var source = @" partial class C { public static void Main() { Test((X1:1, Y1:2)); var t1 = (X1:3, Y1:4); Test(t1); Test((5, 6)); var t2 = (7, 8); Test(t2); } public static void Test(AA val) { } } class AA { public static implicit operator AA ((int X1, int Y1) x) { System.Console.WriteLine(x); return new AA(); } }"; var comp = CompileAndVerify(source, parseOptions: TestOptions.Regular, expectedOutput: @"(1, 2) (3, 4) (5, 6) (7, 8)"); } [Fact] [WorkItem(269808, "https://devdiv.visualstudio.com/DevDiv/_workitems?id=269808")] public void UserDefinedConversionsAndNameMismatch_02() { var source = @" partial class C { public static void Main() { Test((X1:1, Y1:2)); var t1 = (X1:3, Y1:4); Test(t1); Test((5, 6)); var t2 = (7, 8); Test(t2); } public static void Test(AA? val) { } } struct AA { public static implicit operator AA ((int X1, int Y1) x) { System.Console.WriteLine(x); return new AA(); } }"; var comp = CompileAndVerify(source, parseOptions: TestOptions.Regular, expectedOutput: @"(1, 2) (3, 4) (5, 6) (7, 8)"); } [Fact] [WorkItem(269808, "https://devdiv.visualstudio.com/DevDiv/_workitems?id=269808")] public void UserDefinedConversionsAndNameMismatch_03() { var source = @" partial class C { public static void Main() { (int X1, int Y1)? t1 = (X1:3, Y1:4); Test(t1); (int, int)? t2 = (7, 8); Test(t2); System.Console.WriteLine(""--""); t1 = null; Test(t1); t2 = null; Test(t2); System.Console.WriteLine(""--""); } public static void Test(AA? val) { } } struct AA { public static implicit operator AA ((int X1, int Y1) x) { System.Console.WriteLine(x); return new AA(); } }"; var comp = CompileAndVerify(source, parseOptions: TestOptions.Regular, expectedOutput: @"(3, 4) (7, 8) -- --"); } [Fact] [WorkItem(269808, "https://devdiv.visualstudio.com/DevDiv/_workitems?id=269808")] public void UserDefinedConversionsAndNameMismatch_04() { var source = @" partial class C { public static void Main() { Test(new AA()); } public static void Test((int X1, int Y1) val) { System.Console.WriteLine(val); } } class AA { public static implicit operator (int, int) (AA x) { return (1, 2); } }"; var comp = CompileAndVerify(source, parseOptions: TestOptions.Regular, expectedOutput: @"(1, 2)"); } [Fact] [WorkItem(269808, "https://devdiv.visualstudio.com/DevDiv/_workitems?id=269808")] public void UserDefinedConversionsAndNameMismatch_05() { var source = @" partial class C { public static void Main() { Test(new AA()); } public static void Test((int X1, int Y1) val) { System.Console.WriteLine(val); } } class AA { public static implicit operator (int X1, int Y1) (AA x) { return (1, 2); } }"; var comp = CompileAndVerify(source, parseOptions: TestOptions.Regular, expectedOutput: @"(1, 2)"); } [Fact] [WorkItem(269808, "https://devdiv.visualstudio.com/DevDiv/_workitems?id=269808")] public void UserDefinedConversionsAndNameMismatch_06() { var source = @" partial class C { public static void Main() { BB<(int X1, int Y1)>? t1 = new BB<(int X1, int Y1)>(); Test(t1); BB<(int, int)>? t2 = new BB<(int, int)>(); Test(t2); System.Console.WriteLine(""--""); t1 = null; Test(t1); t2 = null; Test(t2); System.Console.WriteLine(""--""); } public static void Test(AA? val) { } } struct AA { public static implicit operator AA (BB<(int X1, int Y1)> x) { System.Console.WriteLine(""implicit operator AA""); return new AA(); } } struct BB { } "; var comp = CompileAndVerify(source, parseOptions: TestOptions.Regular, expectedOutput: @"implicit operator AA implicit operator AA -- --"); } [WorkItem(14708, "https://github.com/dotnet/roslyn/issues/14708")] [WorkItem(14709, "https://github.com/dotnet/roslyn/issues/14709")] [Fact] public void RefTupleDynamicDecode003() { string lib = @" // 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 extern System.ValueTuple { .publickeytoken = (CC 7B 13 FF CD 2D DD 51 ) // .{...-.Q .ver 4:0:1:0 } // =============== CLASS MEMBERS DECLARATION =================== .class public auto ansi beforefieldinit ClassLibrary1.C1 extends [mscorlib]System.Object { .method public hidebysig newslot virtual instance valuetype [System.ValueTuple]System.ValueTuple`2& Goo(int32 arg) cil managed { .param [0] // the dynamic flags array is too short - decoder expects a flag matching ""ref"", but it is missing here. .custom instance void [System.Core]System.Runtime.CompilerServices.DynamicAttribute::.ctor(bool[]) = ( 01 00 03 00 00 00 00 00 01 00 00 ) // Code size 37 (0x25) .maxstack 5 .locals init (valuetype [System.ValueTuple]System.ValueTuple`2& V_0) IL_0000: nop IL_0001: ldc.i4.1 IL_0002: newarr valuetype [System.ValueTuple]System.ValueTuple`2 IL_0007: dup IL_0008: ldc.i4.0 IL_0009: ldc.i4.1 IL_000a: ldarg.1 IL_000b: box [mscorlib]System.Int32 IL_0010: newobj instance void valuetype [System.ValueTuple]System.ValueTuple`2::.ctor(!0, !1) IL_0015: stelem valuetype [System.ValueTuple]System.ValueTuple`2 IL_001a: ldc.i4.0 IL_001b: ldelema valuetype [System.ValueTuple]System.ValueTuple`2 IL_0020: stloc.0 IL_0021: br.s IL_0023 IL_0023: ldloc.0 IL_0024: ret } // end of method C1::Goo .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 C1::.ctor } // end of class ClassLibrary1.C1 "; var libCompRef = CompileIL(lib); var source = @" namespace ConsoleApplication5 { class Program { static void Main(string[] args) { ref var x = ref new C2().Goo(42); System.Console.Write(x.Item2); x.Item2 = ""qq""; System.Console.WriteLine(x.Item2); } } class C2: ClassLibrary1.C1 { public override ref (int, dynamic) Goo(int arg) { return ref base.Goo(arg); } } } "; var comp = CreateCompilationWithMscorlib45AndCSharp(source, references: (new[] { libCompRef }).Concat(s_valueTupleRefs).ToArray(), options: TestOptions.DebugExe); CompileAndVerify(comp, expectedOutput: "42qq", verify: Verification.Fails); var m = (MethodSymbol)(comp.GetTypeByMetadataName("ConsoleApplication5.C2").GetMembers("Goo").First()); Assert.Equal("ref (System.Int32, dynamic) ConsoleApplication5.C2.Goo(System.Int32 arg)", m.ToTestDisplayString()); var b = m.OverriddenMethod; // not (int, dynamic), // since dynamic flags were not aligned, we have ignored the flags Assert.Equal("ref (System.Int32, System.Object) ClassLibrary1.C1.Goo(System.Int32 arg)", b.ToTestDisplayString()); } [WorkItem(14708, "https://github.com/dotnet/roslyn/issues/14708")] [WorkItem(14709, "https://github.com/dotnet/roslyn/issues/14709")] [ConditionalFact(typeof(DesktopOnly))] public void RefTupleDynamicDecode004() { string lib = @" namespace ClassLibrary1 { public class C1 { public virtual ref (int, dynamic) Goo => ref new (int, dynamic)[]{(1, 42)}[0]; } } "; var libComp = CreateCompilationWithMscorlib45AndCSharp(lib, references: s_valueTupleRefs, options: TestOptions.DebugDll); libComp.VerifyDiagnostics(); var source = @" namespace ConsoleApplication5 { class Program { static void Main(string[] args) { ref var x = ref new C2().Goo; System.Console.Write(x.Item2); x.Item2 = ""qq""; System.Console.WriteLine(x.Item2); } } class C2: ClassLibrary1.C1 { public override ref (int, object) Goo => ref base.Goo; } } "; var libCompRef = AssemblyMetadata.CreateFromImage(libComp.EmitToArray()).GetReference(); var comp = CompileAndVerify(source, expectedOutput: "42qq", references: new[] { libCompRef }, options: TestOptions.DebugExe, verify: Verification.Passes); var m = (PropertySymbol)(((CSharpCompilation)comp.Compilation).GetTypeByMetadataName("ConsoleApplication5.C2").GetMembers("Goo").First()); Assert.Equal("ref (System.Int32, System.Object) ConsoleApplication5.C2.Goo { get; }", m.ToTestDisplayString()); Assert.Equal("ref (System.Int32, System.Object) ConsoleApplication5.C2.Goo.get", m.GetMethod.ToTestDisplayString()); var b = m.OverriddenProperty; Assert.Equal("ref (System.Int32, dynamic) ClassLibrary1.C1.Goo { get; }", b.ToTestDisplayString()); Assert.Equal("ref (System.Int32, dynamic) ClassLibrary1.C1.Goo.get", b.GetMethod.ToTestDisplayString()); } [Fact] [WorkItem(14267, "https://github.com/dotnet/roslyn/issues/14267")] public void NoSystemRuntimeFacade() { var source = @" class C { static void M() { var o = (1, 2); } } "; var compilation = CreateCompilationWithMscorlib40(source, references: new[] { ValueTupleRef }); Assert.Equal(TypeKind.Class, compilation.GetWellKnownType(WellKnownType.System_ValueTuple_T2).TypeKind); compilation.VerifyDiagnostics( // (6,17): error CS0012: The type 'ValueType' is defined in an assembly that is not referenced. You must add a reference to assembly 'System.Runtime, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'. // var o = (1, 2); Diagnostic(ErrorCode.ERR_NoTypeDef, "(1, 2)").WithArguments("System.ValueType", "System.Runtime, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a").WithLocation(6, 17) ); } [Fact] [WorkItem(14888, "https://github.com/dotnet/roslyn/issues/14888")] public void Iterator_01() { var source = @" using System; using System.Collections.Generic; public class C { static void Main(string[] args) { foreach (var x in entries()) { Console.WriteLine(x); } } static public IEnumerable<(int, int)> entries() { yield return (1, 2); } } "; var comp = CompileAndVerify(source, parseOptions: TestOptions.Regular, expectedOutput: @"(1, 2)"); } [Fact] [WorkItem(14888, "https://github.com/dotnet/roslyn/issues/14888")] public void Iterator_02() { var source = @" using System; using System.Collections.Generic; public class C { public IEnumerable<(int, int)> entries() { yield return (1, 2); } } "; var compilation = CreateCompilationWithMscorlib40(source, references: new[] { ValueTupleRef }); compilation.VerifyEmitDiagnostics( // (7,24): error CS0012: The type 'ValueType' is defined in an assembly that is not referenced. You must add a reference to assembly 'System.Runtime, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'. // public IEnumerable<(int, int)> entries() Diagnostic(ErrorCode.ERR_NoTypeDef, "(int, int)").WithArguments("System.ValueType", "System.Runtime, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a").WithLocation(7, 24), // (9,22): error CS0012: The type 'ValueType' is defined in an assembly that is not referenced. You must add a reference to assembly 'System.Runtime, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'. // yield return (1, 2); Diagnostic(ErrorCode.ERR_NoTypeDef, "(1, 2)").WithArguments("System.ValueType", "System.Runtime, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a").WithLocation(9, 22) ); } [Fact] [WorkItem(14649, "https://github.com/dotnet/roslyn/issues/14649")] public void ParseLongLambda() { string filler = string.Join("\r\n", Enumerable.Range(1, 1000).Select(i => $"int y{i};")); string parameters = string.Join(", ", Enumerable.Range(1, 2000).Select(i => $"int x{i}")); string text = @" class C { " + filler + @" public void M() { N((" + parameters + @") => 1); } } "; // This is designed to trigger a shift of the array of lexed tokens (see AddLexedTokenSlot) while // parsing lambda parameters var tree = SyntaxFactory.ParseSyntaxTree(text, CSharpParseOptions.Default); // no assertion } [Fact] public void UnusedTuple() { string source = @" public class C { void M(int x) { // Warnings int[] array = new int[] { 42 }; unsafe { fixed (int* p = &array[0]) { (int*, int*) t1 = (p, p); // converted tuple literal with a pointer type (string, int*) t2 = (null, p); // implicit tuple literal conversion on a converted tuple literal with a pointer type (string, (int*, int*)) t3 = (null, (p, p)); } } (int, int) t4 = default((int, int)); (int, int) t5 = (1, 2); (string, string) t6 = (null, null); (string, string) t7 = (""hello"", ""world""); (S, (S, S)) t8 = (new S(), (new S(), new S())); (int, int) t9 = ((C, int))(new C(), 2); // implicit tuple conversion with a user conversion on an element (int, int) t10 = (new C(), 2); // implicit tuple literal conversion with a user conversion on an element (int, int) t11 = ((int, int))(((C, int))(new C(), 2)); // explicit tuple conversion with a user conversion on an element (C, C) t12 = (new C(), new C()); (C, (C, C)) t13 = (new C(), (new C(), new C())); (S, (S, S)) t14 = (new S(), (new S() { /* object initializer */ }, new S())); // No warnings (C, int) tuple = (new C(), 2); (int, int) t20 = ((C, int))tuple; (int, int) t21 = tuple; (int, int) t22 = ((int, int))tuple; C c1 = (1, 2); (int, int) intTuple = (1, 2); C c2 = intTuple; int i1 = 1; int i2 = i1; } public static implicit operator int(C c) { return 0; } public static implicit operator C((int, int) t) { return new C(); } } public struct S { } "; var comp = CreateCompilationWithMscorlib45AndCSharp(source, references: s_valueTupleRefs, options: TestOptions.UnsafeDebugDll); comp.VerifyDiagnostics( // (13,18): error CS0306: The type 'int*' may not be used as a type argument // (int*, int*) t1 = (p, p); // converted tuple literal with a pointer type Diagnostic(ErrorCode.ERR_BadTypeArgument, "int*").WithArguments("int*").WithLocation(13, 18), // (13,24): error CS0306: The type 'int*' may not be used as a type argument // (int*, int*) t1 = (p, p); // converted tuple literal with a pointer type Diagnostic(ErrorCode.ERR_BadTypeArgument, "int*").WithArguments("int*").WithLocation(13, 24), // (13,36): error CS0306: The type 'int*' may not be used as a type argument // (int*, int*) t1 = (p, p); // converted tuple literal with a pointer type Diagnostic(ErrorCode.ERR_BadTypeArgument, "p").WithArguments("int*").WithLocation(13, 36), // (13,39): error CS0306: The type 'int*' may not be used as a type argument // (int*, int*) t1 = (p, p); // converted tuple literal with a pointer type Diagnostic(ErrorCode.ERR_BadTypeArgument, "p").WithArguments("int*").WithLocation(13, 39), // (14,26): error CS0306: The type 'int*' may not be used as a type argument // (string, int*) t2 = (null, p); // implicit tuple literal conversion on a converted tuple literal with a pointer type Diagnostic(ErrorCode.ERR_BadTypeArgument, "int*").WithArguments("int*").WithLocation(14, 26), // (15,27): error CS0306: The type 'int*' may not be used as a type argument // (string, (int*, int*)) t3 = (null, (p, p)); Diagnostic(ErrorCode.ERR_BadTypeArgument, "int*").WithArguments("int*").WithLocation(15, 27), // (15,33): error CS0306: The type 'int*' may not be used as a type argument // (string, (int*, int*)) t3 = (null, (p, p)); Diagnostic(ErrorCode.ERR_BadTypeArgument, "int*").WithArguments("int*").WithLocation(15, 33), // (15,53): error CS0306: The type 'int*' may not be used as a type argument // (string, (int*, int*)) t3 = (null, (p, p)); Diagnostic(ErrorCode.ERR_BadTypeArgument, "p").WithArguments("int*").WithLocation(15, 53), // (15,56): error CS0306: The type 'int*' may not be used as a type argument // (string, (int*, int*)) t3 = (null, (p, p)); Diagnostic(ErrorCode.ERR_BadTypeArgument, "p").WithArguments("int*").WithLocation(15, 56), // (13,30): warning CS0219: The variable 't1' is assigned but its value is never used // (int*, int*) t1 = (p, p); // converted tuple literal with a pointer type Diagnostic(ErrorCode.WRN_UnreferencedVarAssg, "t1").WithArguments("t1").WithLocation(13, 30), // (14,32): warning CS0219: The variable 't2' is assigned but its value is never used // (string, int*) t2 = (null, p); // implicit tuple literal conversion on a converted tuple literal with a pointer type Diagnostic(ErrorCode.WRN_UnreferencedVarAssg, "t2").WithArguments("t2").WithLocation(14, 32), // (15,40): warning CS0219: The variable 't3' is assigned but its value is never used // (string, (int*, int*)) t3 = (null, (p, p)); Diagnostic(ErrorCode.WRN_UnreferencedVarAssg, "t3").WithArguments("t3").WithLocation(15, 40), // (19,20): warning CS0219: The variable 't4' is assigned but its value is never used // (int, int) t4 = default((int, int)); Diagnostic(ErrorCode.WRN_UnreferencedVarAssg, "t4").WithArguments("t4").WithLocation(19, 20), // (20,20): warning CS0219: The variable 't5' is assigned but its value is never used // (int, int) t5 = (1, 2); Diagnostic(ErrorCode.WRN_UnreferencedVarAssg, "t5").WithArguments("t5").WithLocation(20, 20), // (22,26): warning CS0219: The variable 't6' is assigned but its value is never used // (string, string) t6 = (null, null); Diagnostic(ErrorCode.WRN_UnreferencedVarAssg, "t6").WithArguments("t6").WithLocation(22, 26), // (23,26): warning CS0219: The variable 't7' is assigned but its value is never used // (string, string) t7 = ("hello", "world"); Diagnostic(ErrorCode.WRN_UnreferencedVarAssg, "t7").WithArguments("t7").WithLocation(23, 26), // (24,21): warning CS0219: The variable 't8' is assigned but its value is never used // (S, (S, S)) t8 = (new S(), (new S(), new S())); Diagnostic(ErrorCode.WRN_UnreferencedVarAssg, "t8").WithArguments("t8").WithLocation(24, 21), // (26,20): warning CS0219: The variable 't9' is assigned but its value is never used // (int, int) t9 = ((C, int))(new C(), 2); // implicit tuple conversion with a user conversion on an element Diagnostic(ErrorCode.WRN_UnreferencedVarAssg, "t9").WithArguments("t9").WithLocation(26, 20), // (27,20): warning CS0219: The variable 't10' is assigned but its value is never used // (int, int) t10 = (new C(), 2); // implicit tuple literal conversion with a user conversion on an element Diagnostic(ErrorCode.WRN_UnreferencedVarAssg, "t10").WithArguments("t10").WithLocation(27, 20), // (28,20): warning CS0219: The variable 't11' is assigned but its value is never used // (int, int) t11 = ((int, int))(((C, int))(new C(), 2)); // explicit tuple conversion with a user conversion on an element Diagnostic(ErrorCode.WRN_UnreferencedVarAssg, "t11").WithArguments("t11").WithLocation(28, 20), // (30,16): warning CS0219: The variable 't12' is assigned but its value is never used // (C, C) t12 = (new C(), new C()); Diagnostic(ErrorCode.WRN_UnreferencedVarAssg, "t12").WithArguments("t12").WithLocation(30, 16), // (31,21): warning CS0219: The variable 't13' is assigned but its value is never used // (C, (C, C)) t13 = (new C(), (new C(), new C())); Diagnostic(ErrorCode.WRN_UnreferencedVarAssg, "t13").WithArguments("t13").WithLocation(31, 21), // (32,21): warning CS0219: The variable 't14' is assigned but its value is never used // (S, (S, S)) t14 = (new S(), (new S() { /* object initializer */ }, new S())); Diagnostic(ErrorCode.WRN_UnreferencedVarAssg, "t14").WithArguments("t14").WithLocation(32, 21) ); } [Fact] [WorkItem(14881, "https://github.com/dotnet/roslyn/issues/14881")] [WorkItem(15476, "https://github.com/dotnet/roslyn/issues/15476")] public void TupleElementVsLocal() { var source = @" using System; static class Program { static void Main() { (int elem1, int elem2) tuple; int elem2; tuple = (5, 6); tuple.elem2 = 23; elem2 = 10; Console.WriteLine(tuple.elem2); Console.WriteLine(elem2); } } "; var compilation = CreateCompilationWithMscorlib40(source, references: new[] { ValueTupleRef, SystemRuntimeFacadeRef }); compilation.VerifyDiagnostics(); var tree = compilation.SyntaxTrees.First(); var model = compilation.GetSemanticModel(tree); var nodes = tree.GetRoot().DescendantNodes().OfType().Where(id => id.Identifier.ValueText == "elem2").ToArray(); Assert.Equal(4, nodes.Length); Assert.Equal("tuple.elem2 = 23", nodes[0].Parent.Parent.ToString()); Assert.Equal("System.Int32 (System.Int32 elem1, System.Int32 elem2).elem2", model.GetSymbolInfo(nodes[0]).Symbol.ToTestDisplayString()); Assert.Equal("elem2 = 10", nodes[1].Parent.ToString()); Assert.Equal("System.Int32 elem2", model.GetSymbolInfo(nodes[1]).Symbol.ToTestDisplayString()); Assert.Equal("(tuple.elem2)", nodes[2].Parent.Parent.Parent.ToString()); Assert.Equal("System.Int32 (System.Int32 elem1, System.Int32 elem2).elem2", model.GetSymbolInfo(nodes[2]).Symbol.ToTestDisplayString()); Assert.Equal("(elem2)", nodes[3].Parent.Parent.ToString()); Assert.Equal("System.Int32 elem2", model.GetSymbolInfo(nodes[3]).Symbol.ToTestDisplayString()); var type = tree.GetRoot().DescendantNodes().OfType().Single(); var symbolInfo = model.GetSymbolInfo(type); Assert.Equal("(System.Int32 elem1, System.Int32 elem2)", symbolInfo.Symbol.ToTestDisplayString()); var typeInfo = model.GetTypeInfo(type); Assert.Equal("(System.Int32 elem1, System.Int32 elem2)", typeInfo.Type.ToTestDisplayString()); Assert.Equal(symbolInfo.Symbol, typeInfo.Type); Assert.Equal("System.Int32 (System.Int32 elem1, System.Int32 elem2).elem1", model.GetDeclaredSymbol(type.Elements.First()).ToTestDisplayString()); Assert.Equal("System.Int32 (System.Int32 elem1, System.Int32 elem2).elem2", model.GetDeclaredSymbol(type.Elements.Last()).ToTestDisplayString()); Assert.Equal("System.Int32 (System.Int32 elem1, System.Int32 elem2).elem1", model.GetDeclaredSymbol((SyntaxNode)type.Elements.First()).ToTestDisplayString()); Assert.Equal("System.Int32 (System.Int32 elem1, System.Int32 elem2).elem2", model.GetDeclaredSymbol((SyntaxNode)type.Elements.Last()).ToTestDisplayString()); } [Fact] [WorkItem(14841, "https://github.com/dotnet/roslyn/issues/14841")] public void ImplicitIEnumerableImplementationWithDifferentTupleNames() { var source = @" using System; using System.Collections; using System.Collections.Generic; class Base : IEnumerable<(int a, int b)> { public IEnumerator<(int a, int b)> GetEnumerator() { throw new Exception(); } IEnumerator IEnumerable.GetEnumerator() { throw new Exception(); } } class Derived : Base, IEnumerable<(int notA, int notB)> { public new IEnumerator<(int notA, int notB)> GetEnumerator() { return new DerivedEnumerator(); } IEnumerator IEnumerable.GetEnumerator() { throw new Exception(); } public class DerivedEnumerator : IEnumerator<(int notA, int notB)> { bool done = false; public (int notA, int notB) Current { get { return (2, 2); } } public bool MoveNext() { if (done) { return false; } else { done = true; return true; } } public void Reset() { } public void Dispose() { } object IEnumerator.Current { get { throw new Exception(); } } } } class C { static void Main() { foreach (var x in new Derived()) { Console.WriteLine(x.notA); } } } "; var comp = CreateCompilation(source, options: TestOptions.DebugExe); comp.VerifyDiagnostics(); var tree = comp.SyntaxTrees.Single(); var model = comp.GetSemanticModel(tree); var derived = tree.GetRoot().DescendantNodes().OfType().ElementAt(1); var derivedSymbol = model.GetDeclaredSymbol(derived); Assert.Equal("Derived", derivedSymbol.ToTestDisplayString()); Assert.Equal(new[] { "System.Collections.Generic.IEnumerable<(System.Int32 a, System.Int32 b)>", "System.Collections.Generic.IEnumerable<(System.Int32 notA, System.Int32 notB)>", "System.Collections.IEnumerable" }, derivedSymbol.AllInterfaces.Select(i => i.ToTestDisplayString())); var xSymbol = model.GetDeclaredSymbol(tree.GetRoot().DescendantNodes().OfType().Single()); Assert.Equal("(System.Int32 notA, System.Int32 notB)", xSymbol.Type.ToTestDisplayString()); CompileAndVerify(comp, expectedOutput: "2"); } [Fact] [WorkItem(14841, "https://github.com/dotnet/roslyn/issues/14841")] public void ExplicitIEnumerableImplementationWithDifferentTupleNames() { var source = @" using System; using System.Collections; using System.Collections.Generic; class Base : IEnumerable<(int a, int b)> { IEnumerator<(int a, int b)> IEnumerable<(int a, int b)>.GetEnumerator() { throw new Exception(); } IEnumerator IEnumerable.GetEnumerator() { throw new Exception(); } } class Derived : Base, IEnumerable<(int notA, int notB)> { IEnumerator<(int notA, int notB)> IEnumerable<(int notA, int notB)>.GetEnumerator() { return new DerivedEnumerator(); } IEnumerator IEnumerable.GetEnumerator() { throw new Exception(); } public class DerivedEnumerator : IEnumerator<(int notA, int notB)> { bool done = false; public (int notA, int notB) Current { get { return (2, 2); } } public bool MoveNext() { if (done) { return false; } else { done = true; return true; } } public void Reset() { } public void Dispose() { } object IEnumerator.Current { get { throw new Exception(); } } } } class C { static void Main() { foreach (var x in new Derived()) { System.Console.WriteLine(x.notA); } } } "; var comp = CreateCompilation(source, options: TestOptions.DebugExe); comp.VerifyDiagnostics(); var tree = comp.SyntaxTrees.Single(); var model = comp.GetSemanticModel(tree); var derived = tree.GetRoot().DescendantNodes().OfType().ElementAt(1); var derivedSymbol = model.GetDeclaredSymbol(derived); Assert.Equal("Derived", derivedSymbol.ToTestDisplayString()); Assert.Equal(new[] { "System.Collections.Generic.IEnumerable<(System.Int32 a, System.Int32 b)>", "System.Collections.Generic.IEnumerable<(System.Int32 notA, System.Int32 notB)>", "System.Collections.IEnumerable" }, derivedSymbol.AllInterfaces.Select(i => i.ToTestDisplayString())); var xSymbol = model.GetDeclaredSymbol(tree.GetRoot().DescendantNodes().OfType().Single()); Assert.Equal("(System.Int32 notA, System.Int32 notB)", xSymbol.Type.ToTestDisplayString()); CompileAndVerify(comp, expectedOutput: "2"); } [Fact] [WorkItem(14841, "https://github.com/dotnet/roslyn/issues/14841")] public void GenericImplicitIEnumerableImplementationUsedWithDifferentTypesAndTupleNames() { var source = @" using System.Collections; using System.Collections.Generic; class Base : IEnumerable<(int, int)> { public IEnumerator<(int, int)> GetEnumerator() { return null; } IEnumerator IEnumerable.GetEnumerator() { return null; } } class Derived : Base, IEnumerable { public T state; public new IEnumerator GetEnumerator() { return new DerivedEnumerator() { state = state }; } IEnumerator IEnumerable.GetEnumerator() { return null; } public class DerivedEnumerator : IEnumerator { public T state; bool done = false; public T Current { get { return state; } } public bool MoveNext() { if (done) { return false; } else { done = true; return true; } } public void Reset() { } public void Dispose() { } object IEnumerator.Current { get { return null; } } } } class C { static void Main() { var collection = new Derived<(string a, string b)>() { state = (""hello"", ""world"") }; foreach (var x in collection) { System.Console.WriteLine(x.a); } } } "; var comp = CreateCompilation(source, options: TestOptions.DebugExe); comp.VerifyDiagnostics(); var tree = comp.SyntaxTrees.Single(); var model = comp.GetSemanticModel(tree); var derived = tree.GetRoot().DescendantNodes().OfType().ElementAt(1); var derivedSymbol = model.GetDeclaredSymbol(derived); Assert.Equal("Derived", derivedSymbol.ToTestDisplayString()); Assert.Equal(new[] { "System.Collections.Generic.IEnumerable<(System.Int32, System.Int32)>", "System.Collections.Generic.IEnumerable", "System.Collections.IEnumerable" }, derivedSymbol.AllInterfaces.Select(i => i.ToTestDisplayString())); var collection = tree.GetRoot().DescendantNodes().OfType().ElementAt(3); var collectionSymbol = (model.GetDeclaredSymbol(collection) as ILocalSymbol)?.Type; Assert.Equal("Derived<(System.String a, System.String b)>", collectionSymbol.ToTestDisplayString()); Assert.Equal(new[] { "System.Collections.Generic.IEnumerable<(System.Int32, System.Int32)>", "System.Collections.Generic.IEnumerable<(System.String a, System.String b)>", "System.Collections.IEnumerable" }, collectionSymbol.AllInterfaces.Select(i => i.ToTestDisplayString())); CompileAndVerify(comp, expectedOutput: "hello"); } [Fact] [WorkItem(14841, "https://github.com/dotnet/roslyn/issues/14841")] public void GenericExplicitIEnumerableImplementationUsedWithDifferentTupleNames() { var source = @" using System; using System.Collections; using System.Collections.Generic; class Base : IEnumerable<(int a, int b)> { IEnumerator<(int a, int b)> IEnumerable<(int a, int b)>.GetEnumerator() { throw new Exception(); } IEnumerator IEnumerable.GetEnumerator() { throw new Exception(); } } class Derived : Base, IEnumerable { public T state; IEnumerator IEnumerable.GetEnumerator() { return new DerivedEnumerator() { state = state }; } IEnumerator IEnumerable.GetEnumerator() { throw new Exception(); } public class DerivedEnumerator : IEnumerator { public T state; bool done = false; public T Current { get { return state; } } public bool MoveNext() { if (done) { return false; } else { done = true; return true; } } public void Reset() { } public void Dispose() { } object IEnumerator.Current { get { throw new Exception(); } } } } class C { static void Main() { var collection = new Derived<(int notA, int notB)>() { state = (42, 43) }; foreach (var x in collection) { System.Console.WriteLine(x.notA); } } } "; var comp = CreateCompilation(source, options: TestOptions.DebugExe); comp.VerifyDiagnostics(); var tree = comp.SyntaxTrees.Single(); var model = comp.GetSemanticModel(tree); var derived = tree.GetRoot().DescendantNodes().OfType().ElementAt(1); var derivedSymbol = model.GetDeclaredSymbol(derived) as INamedTypeSymbol; Assert.Equal("Derived", derivedSymbol.ToTestDisplayString()); Assert.Equal(new[] { "System.Collections.Generic.IEnumerable<(System.Int32 a, System.Int32 b)>", "System.Collections.Generic.IEnumerable", "System.Collections.IEnumerable" }, derivedSymbol.AllInterfaces.Select(i => i.ToTestDisplayString())); var collection = tree.GetRoot().DescendantNodes().OfType().ElementAt(3); var collectionSymbol = (model.GetDeclaredSymbol(collection) as ILocalSymbol)?.Type; Assert.Equal("Derived<(System.Int32 notA, System.Int32 notB)>", collectionSymbol.ToTestDisplayString()); Assert.Equal(new[] { "System.Collections.Generic.IEnumerable<(System.Int32 a, System.Int32 b)>", "System.Collections.Generic.IEnumerable<(System.Int32 notA, System.Int32 notB)>", "System.Collections.IEnumerable" }, collectionSymbol.AllInterfaces.Select(i => i.ToTestDisplayString())); Assert.Empty(derivedSymbol.GetSymbol().AsUnboundGenericType().AllInterfaces()); } [Fact] [WorkItem(14841, "https://github.com/dotnet/roslyn/issues/14841")] public void GenericExplicitIEnumerableImplementationUsedWithoutTuples() { var source = @" using System; using System.Collections; using System.Collections.Generic; class Base : IEnumerable { IEnumerator IEnumerable.GetEnumerator() { throw new Exception(); } IEnumerator IEnumerable.GetEnumerator() { throw new Exception(); } } class Derived : Base, IEnumerable { public T state; IEnumerator IEnumerable.GetEnumerator() { return new DerivedEnumerator() { state = state }; } IEnumerator IEnumerable.GetEnumerator() { throw new Exception(); } public class DerivedEnumerator : IEnumerator { public T state; bool done = false; public T Current { get { return state; } } public bool MoveNext() { if (done) { return false; } else { done = true; return true; } } public void Reset() { } public void Dispose() { } object IEnumerator.Current { get { throw new Exception(); } } } } class C { static void Main() { var collection = new Derived() { state = 42 }; foreach (var x in collection) { System.Console.WriteLine(x); } } } "; var comp = CreateCompilation(source, options: TestOptions.DebugExe); comp.VerifyDiagnostics(); var tree = comp.SyntaxTrees.Single(); var model = comp.GetSemanticModel(tree); var derived = tree.GetRoot().DescendantNodes().OfType().ElementAt(1); var derivedSymbol = model.GetDeclaredSymbol(derived); Assert.Equal("Derived", derivedSymbol.ToTestDisplayString()); Assert.Equal(new[] { "System.Collections.Generic.IEnumerable", "System.Collections.Generic.IEnumerable", "System.Collections.IEnumerable" }, derivedSymbol.AllInterfaces.Select(i => i.ToTestDisplayString())); var collection = tree.GetRoot().DescendantNodes().OfType().ElementAt(3); var collectionSymbol = (model.GetDeclaredSymbol(collection) as ILocalSymbol)?.Type; Assert.Equal("Derived", collectionSymbol.ToTestDisplayString()); Assert.Equal(new[] { "System.Collections.Generic.IEnumerable", "System.Collections.IEnumerable" }, collectionSymbol.AllInterfaces.Select(i => i.ToTestDisplayString())); } [Fact] [WorkItem(14841, "https://github.com/dotnet/roslyn/issues/14841")] public void GenericExplicitIEnumerableImplementationUsedWithDifferentTypesAndTupleNames() { var source = @" using System; using System.Collections; using System.Collections.Generic; class Base : IEnumerable<(int a, int b)> { IEnumerator<(int a, int b)> IEnumerable<(int a, int b)>.GetEnumerator() { throw new Exception(); } IEnumerator IEnumerable.GetEnumerator() { throw new Exception(); } } class Derived : Base, IEnumerable { public T state; IEnumerator IEnumerable.GetEnumerator() { return new DerivedEnumerator() { state = state }; } IEnumerator IEnumerable.GetEnumerator() { throw new Exception(); } public class DerivedEnumerator : IEnumerator { public T state; bool done = false; public T Current { get { return state; } } public bool MoveNext() { if (done) { return false; } else { done = true; return true; } } public void Reset() { } public void Dispose() { } object IEnumerator.Current { get { throw new Exception(); } } } } class C { static void Main() { var collection = new Derived<(string notA, string notB)>() { state = (""hello"", ""world"") }; foreach (var x in collection) { System.Console.WriteLine(x.notA); } } } "; var comp = CreateCompilation(source, options: TestOptions.DebugExe); comp.VerifyDiagnostics( // (35,27): error CS1640: foreach statement cannot operate on variables of type 'Derived<(string notA, string notB)>' because it implements multiple instantiations of 'IEnumerable'; try casting to a specific interface instantiation // foreach (var x in collection) Diagnostic(ErrorCode.ERR_MultipleIEnumOfT, "collection").WithArguments("Derived<(string notA, string notB)>", "System.Collections.Generic.IEnumerable").WithLocation(35, 27) ); var tree = comp.SyntaxTrees.Single(); var model = comp.GetSemanticModel(tree); var derived = tree.GetRoot().DescendantNodes().OfType().ElementAt(1); var derivedSymbol = model.GetDeclaredSymbol(derived); Assert.Equal("Derived", derivedSymbol.ToTestDisplayString()); Assert.Equal(new[] { "System.Collections.Generic.IEnumerable<(System.Int32 a, System.Int32 b)>", "System.Collections.Generic.IEnumerable", "System.Collections.IEnumerable" }, derivedSymbol.AllInterfaces.Select(i => i.ToTestDisplayString())); var collection = tree.GetRoot().DescendantNodes().OfType().ElementAt(3); var collectionSymbol = (model.GetDeclaredSymbol(collection) as ILocalSymbol)?.Type; Assert.Equal("Derived<(System.String notA, System.String notB)>", collectionSymbol.ToTestDisplayString()); Assert.Equal(new[] { "System.Collections.Generic.IEnumerable<(System.Int32 a, System.Int32 b)>", "System.Collections.Generic.IEnumerable<(System.String notA, System.String notB)>", "System.Collections.IEnumerable" }, collectionSymbol.AllInterfaces.Select(i => i.ToTestDisplayString())); } [Fact] [WorkItem(14843, "https://github.com/dotnet/roslyn/issues/14843")] public void TupleNameDifferencesIgnoredInConstraintWhenNotIdentityConversion() { var source = @" interface I1 {} class Base where U : I1<(int a, int b)> {} class Derived : Base> {} "; var comp = CreateCompilation(source); comp.VerifyDiagnostics(); } [Fact] [WorkItem(14843, "https://github.com/dotnet/roslyn/issues/14843")] public void TupleNameDifferencesIgnoredInConstraintWhenNotIdentityConversion2() { var source = @" interface I1 {} interface I2 : I1 {} class Base where U : I1<(int a, int b)> {} class Derived : Base> {} "; var comp = CreateCompilation(source); comp.VerifyDiagnostics(); } [Fact] [WorkItem(14841, "https://github.com/dotnet/roslyn/issues/14841")] public void CanReImplementInterfaceWithDifferentTupleNames() { var source = @" interface I { T M(); } class Base : I<(int a, int b)> { (int a, int b) I<(int a, int b)>.M() { return (1, 2); } // explicit implementation } class Derived : Base, I<(int notA, int notB)> { public (int notA, int notB) M() { return (3, 4); } } "; var comp = CreateCompilation(source); comp.VerifyDiagnostics(); } [Fact] [WorkItem(14841, "https://github.com/dotnet/roslyn/issues/14841")] public void CannotOverrideWithDifferentTupleNames() { var source = @" interface I { T M(); } class Base : I<(int a, int b)> { public virtual (int a, int b) M() { return (1, 2); } } class Derived : Base, I<(int notA, int notB)> { public override (int notA, int notB) M() { return (3, 4); } } "; var comp = CreateCompilation(source); comp.VerifyDiagnostics( // (12,42): error CS8139: 'Derived.M()': cannot change tuple element names when overriding inherited member 'Base.M()' // public override (int notA, int notB) M() { return (3, 4); } Diagnostic(ErrorCode.ERR_CantChangeTupleNamesOnOverride, "M").WithArguments("Derived.M()", "Base.M()").WithLocation(12, 42) ); } [Fact] [WorkItem(14841, "https://github.com/dotnet/roslyn/issues/14841")] public void CanShadowWithDifferentTupleNames() { var source = @" interface I { T M(); } class Base : I<(int a, int b)> { public (int a, int b) M() { return (1, 2); } } class Derived : Base, I<(int notA, int notB)> { public new (int notA, int notB) M() { return (3, 4); } } "; var comp = CreateCompilation(source); comp.VerifyDiagnostics(); } [Fact] [WorkItem(14841, "https://github.com/dotnet/roslyn/issues/14841")] public void ExplicitBaseImplementationNotConsideredImplementationForInterfaceWithDifferentTupleNames_01() { var source = @" interface I { T M(); } class Base : I<(int a, int b)> { (int a, int b) I<(int a, int b)>.M() { return (1, 2); } // explicit implementation } class Derived1 : Base, I<(int notA, int notB)> { // error } class Derived2 : Base, I<(int a, int b)> { // ok } "; var comp = CreateCompilation(source); comp.VerifyDiagnostics( // (10,24): error CS0535: 'Derived1' does not implement interface member 'I<(int notA, int notB)>.M()' // class Derived1 : Base, I<(int notA, int notB)> { } Diagnostic(ErrorCode.ERR_UnimplementedInterfaceMember, "I<(int notA, int notB)>").WithArguments("Derived1", "I<(int notA, int notB)>.M()").WithLocation(10, 24) ); } [Fact] [WorkItem(14841, "https://github.com/dotnet/roslyn/issues/14841")] public void ExplicitBaseImplementationNotConsideredImplementationForInterfaceWithDifferentTupleNames_02() { var source = @" interface I { T M(); } class Base : I<(int a, int b)> { (int a, int b) I<(int a, int b)>.M() { return (1, 2); } // explicit implementation public (int notA, int notB) M() { return (1, 2); } } class Derived1 : Base, I<(int notA, int notB)> { // error } class Derived2 : Base, I<(int a, int b)> { // ok } "; var comp = CreateCompilation(source); comp.VerifyDiagnostics( // (11,24): error CS0535: 'Derived1' does not implement interface member 'I<(int notA, int notB)>.M()' // class Derived1 : Base, I<(int notA, int notB)> { } Diagnostic(ErrorCode.ERR_UnimplementedInterfaceMember, "I<(int notA, int notB)>").WithArguments("Derived1", "I<(int notA, int notB)>.M()").WithLocation(11, 24) ); } [Fact] public void ExplicitBaseImplementationNotConsideredImplementationForInterfaceWithDifferentTupleNames_03() { var source = @" interface I { T M(); } class Base : I<(int a, int b)> { } class Derived1 : Base, I<(int notA, int notB)> { // error } class Derived2 : Base, I<(int a, int b)> { // ok } "; var comp = CreateCompilation(source); comp.VerifyDiagnostics( // (6,14): error CS0535: 'Base' does not implement interface member 'I<(int a, int b)>.M()' // class Base : I<(int a, int b)> Diagnostic(ErrorCode.ERR_UnimplementedInterfaceMember, "I<(int a, int b)>").WithArguments("Base", "I<(int a, int b)>.M()").WithLocation(6, 14), // (9,24): error CS0535: 'Derived1' does not implement interface member 'I<(int notA, int notB)>.M()' // class Derived1 : Base, I<(int notA, int notB)> Diagnostic(ErrorCode.ERR_UnimplementedInterfaceMember, "I<(int notA, int notB)>").WithArguments("Derived1", "I<(int notA, int notB)>.M()").WithLocation(9, 24) ); } [Fact] public void ExplicitBaseImplementationNotConsideredImplementationForInterfaceWithDifferentTupleNames_04() { var source1 = @" public interface I { T M(); } public class Base : I<(int a, int b)> { } "; var comp1 = CreateCompilation(source1); comp1.VerifyDiagnostics( // (6,21): error CS0535: 'Base' does not implement interface member 'I<(int a, int b)>.M()' // public class Base : I<(int a, int b)> Diagnostic(ErrorCode.ERR_UnimplementedInterfaceMember, "I<(int a, int b)>").WithArguments("Base", "I<(int a, int b)>.M()").WithLocation(6, 21) ); var source2 = @" class Derived1 : Base, I<(int notA, int notB)> { } class Derived2 : Base, I<(int a, int b)> { } "; var comp2 = CreateCompilation(source2, references: new[] { comp1.ToMetadataReference() }); comp2.VerifyDiagnostics( // (2,24): error CS0535: 'Derived1' does not implement interface member 'I<(int notA, int notB)>.M()' // class Derived1 : Base, I<(int notA, int notB)> Diagnostic(ErrorCode.ERR_UnimplementedInterfaceMember, "I<(int notA, int notB)>").WithArguments("Derived1", "I<(int notA, int notB)>.M()").WithLocation(2, 24) ); } [Fact] [WorkItem(14841, "https://github.com/dotnet/roslyn/issues/14841")] public void ExplicitBaseImplementationNotConsideredImplementationForInterfaceWithDifferentTupleNames_05() { var source = @" interface I { T M(); } class Base : I<(int a, int b)> { public (int a, int b) M() { return (1, 2); } } class Derived1 : Base, I<(int notA, int notB)> { // error } class Derived2 : Base, I<(int a, int b)> { // ok } "; var comp = CreateCompilation(source); comp.VerifyDiagnostics( // (10,24): error CS8141: The tuple element names in the signature of method 'Base.M()' must match the tuple element names of interface method 'I<(int notA, int notB)>.M()' (including on the return type). // class Derived1 : Base, I<(int notA, int notB)> Diagnostic(ErrorCode.ERR_ImplBadTupleNames, "I<(int notA, int notB)>").WithArguments("Base.M()", "I<(int notA, int notB)>.M()").WithLocation(10, 24) ); } [Fact] [WorkItem(14841, "https://github.com/dotnet/roslyn/issues/14841")] public void ImplicitBaseImplementationNotConsideredImplementationForInterfaceWithDifferentTupleNames() { var source = @" interface I { T M(); } class Base : I<(int a, int b)> { public (int a, int b) M() { return (1, 2); } } class Derived : Base, I<(int notA, int notB)> { // error } "; var comp = CreateCompilation(source); comp.VerifyDiagnostics( // (10,23): error CS8141: The tuple element names in the signature of method 'Base.M()' must match the tuple element names of interface method 'I<(int notA, int notB)>.M()' (including on the return type). // class Derived : Base, I<(int notA, int notB)> Diagnostic(ErrorCode.ERR_ImplBadTupleNames, "I<(int notA, int notB)>").WithArguments("Base.M()", "I<(int notA, int notB)>.M()").WithLocation(10, 23) ); } [Fact] [WorkItem(14841, "https://github.com/dotnet/roslyn/issues/14841")] public void ImplicitBaseImplementationNotConsideredImplementationForInterfaceWithDifferentTupleNames2() { var source = @" interface I { T M(); } class Base { public (int a, int b) M() { return (1, 2); } } class Derived : Base, I<(int notA, int notB)> { // error } "; var comp = CreateCompilation(source); comp.VerifyDiagnostics( // (10,23): error CS8141: The tuple element names in the signature of method 'Base.M()' must match the tuple element names of interface method 'I<(int notA, int notB)>.M()' (including on the return type). // class Derived : Base, I<(int notA, int notB)> Diagnostic(ErrorCode.ERR_ImplBadTupleNames, "I<(int notA, int notB)>").WithArguments("Base.M()", "I<(int notA, int notB)>.M()").WithLocation(10, 23) ); } [Fact] [WorkItem(20528, "https://github.com/dotnet/roslyn/issues/20528")] public void ImplicitBaseImplementationNotConsideredImplementationForInterfaceWithNoNames() { var source = @" interface I { T M(); } class Base : I<(int a, int b)> { public (int a, int b) M() { return (1, 2); } } class Derived : Base, I<(int, int)> { // error } "; var comp = CreateCompilation(source); comp.VerifyDiagnostics( // (10,23): error CS8141: The tuple element names in the signature of method 'Base.M()' must match the tuple element names of interface method 'I<(int, int)>.M()' (including on the return type). // class Derived : Base, I<(int, int)> Diagnostic(ErrorCode.ERR_ImplBadTupleNames, "I<(int, int)>").WithArguments("Base.M()", "I<(int, int)>.M()").WithLocation(10, 23) ); } [Fact] [WorkItem(20528, "https://github.com/dotnet/roslyn/issues/20528")] public void ImplicitBaseImplementationWithNoNamesConsideredImplementationForInterface() { var source = @" interface I { T M(); } class Base : I<(int, int)> { public (int, int) M() { return (1, 2); } } class Derived : Base, I<(int a, int b)> { // ok } "; var comp = CreateCompilation(source); comp.VerifyDiagnostics(); } [Fact] [WorkItem(14841, "https://github.com/dotnet/roslyn/issues/14841")] public void ReImplementationAndInference() { var source = @" interface I { T M(); } class Base : I<(int a, int b)> { (int a, int b) I<(int a, int b)>.M() { return (1, 2); } } class Derived : Base, I<(int notA, int notB)> { public (int notA, int notB) M() { return (3, 4); } } class C { static void Main() { Base b = new Derived(); var x = Test(b); // tuple names from Base, implementation from Derived System.Console.Write(x.a); } static T Test(I t) { return t.M(); } } "; var comp = CreateCompilation(source, options: TestOptions.DebugExe); comp.VerifyDiagnostics(); CompileAndVerify(comp, expectedOutput: "3"); var tree = comp.SyntaxTrees.Single(); var model = comp.GetSemanticModel(tree); var x = tree.GetRoot().DescendantNodes().OfType().ElementAt(1); Assert.Equal("x", x.Identifier.ToString()); var xSymbol = ((ILocalSymbol)model.GetDeclaredSymbol(x)).Type; Assert.Equal("(System.Int32 a, System.Int32 b)", xSymbol.ToTestDisplayString()); } [Fact] [WorkItem(14091, "https://github.com/dotnet/roslyn/issues/14091")] public void TupleTypeWithTooFewElements() { var source = @" class C { void M(int x, () y, (int a) z) { } } "; var comp = CreateCompilation(source); comp.VerifyDiagnostics( // (4,20): error CS8124: Tuple must contain at least two elements. // void M(int x, () y, (int a) z) { } Diagnostic(ErrorCode.ERR_TupleTooFewElements, ")").WithLocation(4, 20), // (4,31): error CS8124: Tuple must contain at least two elements. // void M(int x, () y, (int a) z) { } Diagnostic(ErrorCode.ERR_TupleTooFewElements, ")").WithLocation(4, 31) ); var tree = comp.SyntaxTrees.Single(); var model = comp.GetSemanticModel(tree); var y = tree.GetRoot().DescendantNodes().OfType().ElementAt(0); Assert.Equal("()", y.ToString()); var yType = model.GetTypeInfo(y); Assert.Equal("(?, ?)", yType.Type.ToTestDisplayString()); var z = tree.GetRoot().DescendantNodes().OfType().ElementAt(1); Assert.Equal("(int a)", z.ToString()); var zType = model.GetTypeInfo(z); Assert.Equal("(System.Int32 a, ?)", zType.Type.ToTestDisplayString()); } [Fact] [WorkItem(14091, "https://github.com/dotnet/roslyn/issues/14091")] public void TupleExpressionWithTooFewElements() { var source = @" class C { object x = (Alice: 1); } "; var comp = CreateCompilation(source); comp.VerifyDiagnostics( // (4,25): error CS8124: Tuple must contain at least two elements. // object x = (Alice: 1); Diagnostic(ErrorCode.ERR_TupleTooFewElements, ")").WithLocation(4, 25) ); var tree = comp.SyntaxTrees.Single(); var model = comp.GetSemanticModel(tree); var tuple = tree.GetRoot().DescendantNodes().OfType().ElementAt(0); Assert.Equal("(Alice: 1)", tuple.ToString()); var tupleType = model.GetTypeInfo(tuple); Assert.Equal("(System.Int32 Alice, ?)", tupleType.Type.ToTestDisplayString()); } [Fact] [WorkItem(16159, "https://github.com/dotnet/roslyn/issues/16159")] public void ExtensionMethodOnConvertedTuple001() { var source = @" using System; using System.Linq; using System.Collections.Generic; static class C { static IEnumerable<(T, U)> Zip(this(IEnumerable xs, IEnumerable ys) source) => source.xs.Zip(source.ys, (x, y) => (x, y)); static void Main() { foreach (var t in Zip((new int[] { 1, 2 }, new byte[] { 3, 4 }))) { System.Console.WriteLine(t); } foreach (var t in (new int[] { 1, 2 }, new byte[] { 3, 4 }).Zip()) { System.Console.WriteLine(t); } var notALiteral = (new int[] { 1, 2 }, new byte[] { 3, 4 }); foreach (var (x, y) in notALiteral.Zip()) { System.Console.WriteLine((x, y)); } } } "; var comp = CompileAndVerify(source, parseOptions: TestOptions.Regular, expectedOutput: @" (1, 3) (2, 4) (1, 3) (2, 4) (1, 3) (2, 4) "); } [Fact] public void ExtensionMethodOnConvertedTuple002() { var source = @" using System; using System.Collections; static class C { static string M(this(object x, (ValueType, IStructuralComparable) y) self) => self.ToString(); static string M1(this (dynamic x, System.Exception y) self) => self.ToString(); static void Main() { System.Console.WriteLine((""qq"", (Alice: 1, (2, 3))).M()); (dynamic Alice, NullReferenceException Bob) arg = (123, null); System.Console.WriteLine(arg.M1()); } } "; var comp = CompileAndVerify(source, parseOptions: TestOptions.Regular, expectedOutput: @" (qq, (1, (2, 3))) (123, ) "); } [Fact] public void ExtensionMethodOnConvertedTuple002Err() { var source = @" using System; using System.Collections; static class C { static string M(this(object x, (ValueType, IStructuralComparable) y) self) => self.ToString(); static string GetAwaiter(this (object x, Func y) self) => self.ToString(); static void Main() { System.Console.WriteLine((""qq"", (Alice: 1, (null, 3))).M()); System.Console.WriteLine((""qq"", ()=>1 ).GetAwaiter()); } } "; var comp = CreateCompilation(source); comp.VerifyDiagnostics( // (13,64): error CS0117: '(string, (int, (, int)))' does not contain a definition for 'M' // System.Console.WriteLine(("qq", (Alice: 1, (null, 3))).M()); Diagnostic(ErrorCode.ERR_NoSuchMember, "M").WithArguments("(string, (int, (, int)))", "M").WithLocation(13, 64), // (15,49): error CS0117: '(string, lambda expression)' does not contain a definition for 'GetAwaiter' // System.Console.WriteLine(("qq", ()=>1 ).GetAwaiter()); Diagnostic(ErrorCode.ERR_NoSuchMember, "GetAwaiter").WithArguments("(string, lambda expression)", "GetAwaiter").WithLocation(15, 49) ); } [Fact] public void ExtensionMethodOnConvertedTuple003() { var source = @" static class C { static string M(this (int x, long y) self) => self.ToString(); static string M1(this (int x, long? y) self) => self.ToString(); static void Main() { // implicit constant conversion System.Console.WriteLine((1, 2).M()); // identity conversion (this one is OK) System.Console.WriteLine((1, 2L).M()); // implicit nullable conversion System.Console.WriteLine((First: 1, Second: 2L).M1()); // null literal conversion System.Console.WriteLine((1, null).M1()); // implicit numeric conversion var notAliteral = (A: 1, B: 2); System.Console.WriteLine(notAliteral.M()); } } "; var comp = CreateCompilation(source); comp.VerifyDiagnostics( // (10,34): error CS1929: '(int, int)' does not contain a definition for 'M' and the best extension method overload 'C.M((int x, long y))' requires a receiver of type '(int x, long y)' // System.Console.WriteLine((1, 2).M()); Diagnostic(ErrorCode.ERR_BadInstanceArgType, "(1, 2)").WithArguments("(int, int)", "M", "C.M((int x, long y))", "(int x, long y)").WithLocation(10, 34), // (16,34): error CS1929: '(int, long)' does not contain a definition for 'M1' and the best extension method overload 'C.M1((int x, long? y))' requires a receiver of type '(int x, long? y)' // System.Console.WriteLine((First: 1, Second: 2L).M1()); Diagnostic(ErrorCode.ERR_BadInstanceArgType, "(First: 1, Second: 2L)").WithArguments("(int, long)", "M1", "C.M1((int x, long? y))", "(int x, long? y)").WithLocation(16, 34), // (19,44): error CS0117: '(int, )' does not contain a definition for 'M1' // System.Console.WriteLine((1, null).M1()); Diagnostic(ErrorCode.ERR_NoSuchMember, "M1").WithArguments("(int, )", "M1"), // (23,34): error CS1929: '(int A, int B)' does not contain a definition for 'M' and the best extension method overload 'C.M((int x, long y))' requires a receiver of type '(int x, long y)' // System.Console.WriteLine(notAliteral.M()); Diagnostic(ErrorCode.ERR_BadInstanceArgType, "notAliteral").WithArguments("(int A, int B)", "M", "C.M((int x, long y))", "(int x, long y)").WithLocation(23, 34) ); } [ConditionalFact(typeof(DesktopOnly))] public void Serialization() { var source = @" using System; class C { public static void Main() { VerifySerialization(new ValueTuple()); VerifySerialization(ValueTuple.Create(1)); VerifySerialization((1, 2, 3, 4, 5, 6, 7, 8)); Console.WriteLine(""DONE""); } public static void VerifySerialization(T tuple) { var serializer = new System.Xml.Serialization.XmlSerializer(typeof(T)); var writer = new System.IO.StringWriter(); serializer.Serialize(writer, tuple); string xml = writer.ToString(); object output = serializer.Deserialize(new System.IO.StringReader(xml)); if (!tuple.Equals(output)) { throw new Exception(""Deserialization output didn't match""); } } }"; var comp = CreateCompilationWithMscorlib40(new[] { source, tuplelib_cs }, references: new[] { SystemXmlRef }, options: TestOptions.DebugExe); comp.VerifyDiagnostics(); CompileAndVerify(comp, expectedOutput: "DONE"); } [Fact] public void GetWellKnownTypeWithAmbiguities() { var versionTemplate = @"[assembly: System.Reflection.AssemblyVersion(""{0}.0.0.0"")]"; var corlib_cs = @" namespace System { public class Object { } public struct Int32 { } public struct Boolean { } public class String { } public class ValueType { } public struct Void { } public class Attribute { } } namespace System.Reflection { public class AssemblyVersionAttribute : Attribute { public AssemblyVersionAttribute(String version) { } } }"; string valuetuple_cs = @" namespace System { public struct ValueTuple { public T1 Item1; public T2 Item2; public ValueTuple(T1 item1, T2 item2) => (Item1, Item2) = (item1, item2); } }"; var corlibWithoutVT = CreateEmptyCompilation(new[] { Parse(String.Format(versionTemplate, "1") + corlib_cs) }, assemblyName: "corlib"); corlibWithoutVT.VerifyDiagnostics(); var corlibWithoutVTRef = corlibWithoutVT.EmitToImageReference(); var corlibWithVT = CreateEmptyCompilation(new[] { Parse(String.Format(versionTemplate, "2") + corlib_cs + valuetuple_cs) }, assemblyName: "corlib"); corlibWithVT.VerifyDiagnostics(); var corlibWithVTRef = corlibWithVT.EmitToImageReference(); var libWithVT = CreateEmptyCompilation(valuetuple_cs, references: new[] { corlibWithoutVTRef }, options: TestOptions.DebugDll); libWithVT.VerifyDiagnostics(); var libWithVTRef = libWithVT.EmitToImageReference(); var comp = CSharpCompilation.Create("test", references: new[] { libWithVTRef, corlibWithVTRef }); Assert.True(comp.GetWellKnownType(WellKnownType.System_ValueTuple_T2).IsErrorType()); var comp2 = comp.WithOptions(comp.Options.WithTopLevelBinderFlags(BinderFlags.IgnoreCorLibraryDuplicatedTypes)); var tuple2 = comp2.GetWellKnownType(WellKnownType.System_ValueTuple_T2); Assert.False(tuple2.IsErrorType()); Assert.Equal(libWithVTRef.Display, tuple2.ContainingAssembly.MetadataName.ToString()); var comp3 = CSharpCompilation.Create("test", references: new[] { corlibWithVTRef, libWithVTRef }) // order reversed .WithOptions(comp.Options.WithTopLevelBinderFlags(BinderFlags.IgnoreCorLibraryDuplicatedTypes)); var tuple3 = comp3.GetWellKnownType(WellKnownType.System_ValueTuple_T2); Assert.False(tuple3.IsErrorType()); Assert.Equal(libWithVTRef.Display, tuple3.ContainingAssembly.MetadataName.ToString()); } [Fact] [WorkItem(17962, "https://github.com/dotnet/roslyn/issues/17962")] public void TupleWithAsOperator() { var source = @" class C { void M() { var x = (0, null) as (int, T)?; System.Console.WriteLine(x == null); } }"; var comp = CreateCompilationWithMscorlib40(source, references: new[] { ValueTupleRef, SystemRuntimeFacadeRef }); comp.VerifyDiagnostics( // (6,17): error CS8304: The first operand of an 'as' operator may not be a tuple literal without a natural type. // var x = (0, null) as (int, T)?; Diagnostic(ErrorCode.ERR_TypelessTupleInAs, "(0, null) as (int, T)?").WithLocation(6, 17) ); } [Fact] public void CheckedConstantConversions() { var source = @"#pragma warning disable 219 class C { static void Main() { unchecked { var u = ((byte, byte))(0, -1); var (a, b) = ((byte, byte))(0, -2); } checked { var c = ((byte, byte))(0, -1); var (a, b) = ((byte, byte))(0, -2); } } }"; var comp = CreateCompilationWithMscorlib40( source, references: new[] { ValueTupleRef, SystemRuntimeFacadeRef }, options: TestOptions.ReleaseExe); comp.VerifyDiagnostics( // (13,39): error CS0221: Constant value '-1' cannot be converted to a 'byte' (use 'unchecked' syntax to override) // var c = ((byte, byte))(0, -1); Diagnostic(ErrorCode.ERR_ConstOutOfRangeChecked, "-1").WithArguments("-1", "byte").WithLocation(13, 39), // (14,44): error CS0221: Constant value '-2' cannot be converted to a 'byte' (use 'unchecked' syntax to override) // var (a, b) = ((byte, byte))(0, -2); Diagnostic(ErrorCode.ERR_ConstOutOfRangeChecked, "-2").WithArguments("-2", "byte").WithLocation(14, 44)); } [Fact] [WorkItem(17963, "https://github.com/dotnet/roslyn/issues/17963")] public void NullableTupleInAsOperator() { var source = @" using System; class P { static void Main() { var x1 = (1, 1) as (int, int a)?; var x2 = (1, 1) as (int, int)?; var x3 = (1, new object()) as (int, dynamic)?; Console.Write($""{x1} {x2} {x3}""); } }"; var comp = CreateCompilationWithMscorlib40(source, references: new[] { ValueTupleRef, SystemRuntimeFacadeRef }, options: TestOptions.DebugExe); comp.VerifyDiagnostics(); CompileAndVerify(comp, expectedOutput: "(1, 1) (1, 1) (1, System.Object)"); } [Fact] [WorkItem(17963, "https://github.com/dotnet/roslyn/issues/17963")] public void NullableTupleInAsOperator2() { var source = @" class P { static void M() { var x = (a: 1, b: 1) as (int c, int d)?; var y = (1, 1) as (int, long)?; } }"; var comp = CreateCompilationWithMscorlib40(source, references: new[] { ValueTupleRef, SystemRuntimeFacadeRef }); comp.VerifyDiagnostics( // (7,17): warning CS0458: The result of the expression is always 'null' of type '(int, long)?' // var y = (1, 1) as (int, long)?; Diagnostic(ErrorCode.WRN_AlwaysNull, "(1, 1) as (int, long)?").WithArguments("(int, long)?").WithLocation(7, 17) ); } [Fact] [WorkItem(17963, "https://github.com/dotnet/roslyn/issues/17963")] public void NullableTupleInIsOperator() { var source = @" class P { static void M() { var x1 = (1, 1) is (int, int a)?; } }"; var comp = CreateCompilationWithMscorlib40(source, references: new[] { ValueTupleRef, SystemRuntimeFacadeRef }); comp.VerifyDiagnostics( // (6,29): error CS8652: The feature 'type pattern' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. // var x1 = (1, 1) is (int, int a)?; Diagnostic(ErrorCode.ERR_FeatureInPreview, "int").WithArguments("type pattern").WithLocation(6, 29), // (6,41): error CS1525: Invalid expression term ';' // var x1 = (1, 1) is (int, int a)?; Diagnostic(ErrorCode.ERR_InvalidExprTerm, ";").WithArguments(";").WithLocation(6, 41), // (6,41): error CS1003: Syntax error, ':' expected // var x1 = (1, 1) is (int, int a)?; Diagnostic(ErrorCode.ERR_SyntaxError, ";").WithArguments(":", ";").WithLocation(6, 41), // (6,41): error CS1525: Invalid expression term ';' // var x1 = (1, 1) is (int, int a)?; Diagnostic(ErrorCode.ERR_InvalidExprTerm, ";").WithArguments(";").WithLocation(6, 41) ); } [Fact] [WorkItem(17963, "https://github.com/dotnet/roslyn/issues/17963")] public void NullableTupleInIsOperator2() { var source = @" class P { static void M() { var x1 = (1, 1) is System.Nullable<(int, int a)>; } }"; var comp = CreateCompilationWithMscorlib40(source, references: new[] { ValueTupleRef, SystemRuntimeFacadeRef }); comp.VerifyDiagnostics( // (6,18): warning CS0183: The given expression is always of the provided ('(int, int a)?') type // var x1 = (1, 1) is System.Nullable<(int, int a)>; Diagnostic(ErrorCode.WRN_IsAlwaysTrue, "(1, 1) is System.Nullable<(int, int a)>").WithArguments("(int, int a)?").WithLocation(6, 18) ); } [Fact] [WorkItem(18459, "https://github.com/dotnet/roslyn/issues/18459")] public void CheckedConversions() { var source = @"using System; class C { static (long, byte) Default((int, int) t) { return ((long, byte))t; } static (long, byte) Unchecked((int, int) t) { unchecked { return ((long, byte))t; } } static (long, byte) Checked((int, int) t) { checked { return ((long, byte))t; } } static void Main() { var d = Default((-1, -1)); Console.Write(d); var u = Unchecked((-1, -1)); Console.Write(u); try { var c = Checked((-1, -1)); Console.Write(c); } catch (OverflowException) { Console.Write(""overflow""); } } }"; var comp = CreateCompilationWithMscorlib40( source, references: new[] { ValueTupleRef, SystemRuntimeFacadeRef }, options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: @"(-1, 255)(-1, 255)overflow"); verifier.VerifyIL("C.Default", @"{ // Code size 22 (0x16) .maxstack 2 .locals init (System.ValueTuple V_0) IL_0000: ldarg.0 IL_0001: stloc.0 IL_0002: ldloc.0 IL_0003: ldfld ""int System.ValueTuple.Item1"" IL_0008: conv.i8 IL_0009: ldloc.0 IL_000a: ldfld ""int System.ValueTuple.Item2"" IL_000f: conv.u1 IL_0010: newobj ""System.ValueTuple..ctor(long, byte)"" IL_0015: ret }"); verifier.VerifyIL("C.Unchecked", @"{ // Code size 22 (0x16) .maxstack 2 .locals init (System.ValueTuple V_0) IL_0000: ldarg.0 IL_0001: stloc.0 IL_0002: ldloc.0 IL_0003: ldfld ""int System.ValueTuple.Item1"" IL_0008: conv.i8 IL_0009: ldloc.0 IL_000a: ldfld ""int System.ValueTuple.Item2"" IL_000f: conv.u1 IL_0010: newobj ""System.ValueTuple..ctor(long, byte)"" IL_0015: ret }"); verifier.VerifyIL("C.Checked", @"{ // Code size 22 (0x16) .maxstack 2 .locals init (System.ValueTuple V_0) IL_0000: ldarg.0 IL_0001: stloc.0 IL_0002: ldloc.0 IL_0003: ldfld ""int System.ValueTuple.Item1"" IL_0008: conv.i8 IL_0009: ldloc.0 IL_000a: ldfld ""int System.ValueTuple.Item2"" IL_000f: conv.ovf.u1 IL_0010: newobj ""System.ValueTuple..ctor(long, byte)"" IL_0015: ret }"); } [Fact] [WorkItem(19434, "https://github.com/dotnet/roslyn/issues/19434")] public void ExplicitTupleLiteralConversionWithNullable01() { var source = @" class C { static void Main() { int x = 1; var y = ((byte, byte)?)(x, x); System.Console.WriteLine(y.Value); } } "; var comp = CompileAndVerify(source, options: TestOptions.DebugExe, expectedOutput: @"(1, 1)"); comp.VerifyIL("C.Main()", @" { // Code size 38 (0x26) .maxstack 3 .locals init (int V_0, //x System.ValueTuple? V_1) //y IL_0000: nop IL_0001: ldc.i4.1 IL_0002: stloc.0 IL_0003: ldloca.s V_1 IL_0005: ldloc.0 IL_0006: conv.u1 IL_0007: ldloc.0 IL_0008: conv.u1 IL_0009: newobj ""System.ValueTuple..ctor(byte, byte)"" IL_000e: call ""System.ValueTuple?..ctor(System.ValueTuple)"" IL_0013: ldloca.s V_1 IL_0015: call ""System.ValueTuple System.ValueTuple?.Value.get"" IL_001a: box ""System.ValueTuple"" IL_001f: call ""void System.Console.WriteLine(object)"" IL_0024: nop IL_0025: ret } "); comp = CompileAndVerify(source, options: TestOptions.ReleaseExe, expectedOutput: @"(1, 1)"); comp.VerifyIL("C.Main()", @" { // Code size 36 (0x24) .maxstack 3 .locals init (int V_0, //x System.ValueTuple? V_1) //y IL_0000: ldc.i4.1 IL_0001: stloc.0 IL_0002: ldloca.s V_1 IL_0004: ldloc.0 IL_0005: conv.u1 IL_0006: ldloc.0 IL_0007: conv.u1 IL_0008: newobj ""System.ValueTuple..ctor(byte, byte)"" IL_000d: call ""System.ValueTuple?..ctor(System.ValueTuple)"" IL_0012: ldloca.s V_1 IL_0014: call ""System.ValueTuple System.ValueTuple?.Value.get"" IL_0019: box ""System.ValueTuple"" IL_001e: call ""void System.Console.WriteLine(object)"" IL_0023: ret } "); } [Fact] [WorkItem(18738, "https://github.com/dotnet/roslyn/issues/18738")] public void TypelessTupleWithNoImplicitConversion_01() { var source = @" class C { void M() { int? e = 5; (int, string) y = (e, null); // the only conversion we find is an explicit conversion System.Console.Write(y); } } "; var comp = CreateEmptyCompilation(source, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp7_1), references: new[] { MscorlibRef, ValueTupleRef, SystemRuntimeFacadeRef }); comp.VerifyDiagnostics( // (7,28): error CS0029: Cannot implicitly convert type 'int?' to 'int' // (int, string) y = (e, null); Diagnostic(ErrorCode.ERR_NoImplicitConv, "e").WithArguments("int?", "int").WithLocation(7, 28) ); VerifySemanticModelTypelessTupleWithNoImplicitConversion(comp); } private static void VerifySemanticModelTypelessTupleWithNoImplicitConversion(CSharpCompilation comp) { var tree = comp.SyntaxTrees.Single(); var model = comp.GetSemanticModel(tree); var tuple = tree.GetRoot().DescendantNodes().OfType().Single(); Assert.Null(model.GetTypeInfo(tuple).Type); Assert.Equal("(System.Int32, System.String)", model.GetTypeInfo(tuple).ConvertedType.ToTestDisplayString()); Assert.Equal(ConversionKind.ExplicitTupleLiteral, model.GetConversion(tuple).Kind); var first = tuple.Arguments[0].Expression; Assert.Equal("System.Int32?", model.GetTypeInfo(first).Type.ToTestDisplayString()); Assert.Equal("System.Int32", model.GetTypeInfo(first).ConvertedType.ToTestDisplayString()); Assert.Equal(ConversionKind.ExplicitNullable, model.GetConversion(first).Kind); var second = tuple.Arguments[1].Expression; Assert.Null(model.GetTypeInfo(second).Type); Assert.Equal("System.String", model.GetTypeInfo(second).ConvertedType.ToTestDisplayString()); Assert.Equal(ConversionKind.ImplicitReference, model.GetConversion(second).Kind); } [Fact] [WorkItem(18738, "https://github.com/dotnet/roslyn/issues/18738")] public void TypelessTupleWithNoImplicitConversion_02() { var source = @" class C { (int, string) M() { int? e = 5; return (e, null); // the only conversion we find is an explicit conversion } } "; var comp = CreateEmptyCompilation(source, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp7_1), references: new[] { MscorlibRef, ValueTupleRef, SystemRuntimeFacadeRef }); comp.VerifyDiagnostics( // (7,17): error CS0029: Cannot implicitly convert type 'int?' to 'int' // return (e, null); // the only conversion we find is an explicit conversion Diagnostic(ErrorCode.ERR_NoImplicitConv, "e").WithArguments("int?", "int").WithLocation(7, 17) ); VerifySemanticModelTypelessTupleWithNoImplicitConversion(comp); } [Fact] [WorkItem(18738, "https://github.com/dotnet/roslyn/issues/18738")] public void TypelessTupleWithNoImplicitConversion2_01() { var source = @" class C { void M() { int? e = 5; (int, string)? y = (e, null); // the only conversion we find is an explicit conversion System.Console.Write(y); } } "; var comp = CreateEmptyCompilation(source, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp7_1), references: new[] { MscorlibRef, ValueTupleRef, SystemRuntimeFacadeRef }); comp.VerifyDiagnostics( // (7,28): error CS8135: Tuple with 2 elements cannot be converted to type '(int, string)?'. // (int, string)? y = (e, null); // the only conversion we find is an explicit conversion Diagnostic(ErrorCode.ERR_ConversionNotTupleCompatible, "(e, null)").WithArguments("2", "(int, string)?").WithLocation(7, 28) ); VerifySemanticModelTypelessTupleWithNoImplicitConversion2(comp); } private static void VerifySemanticModelTypelessTupleWithNoImplicitConversion2(CSharpCompilation comp) { var tree = comp.SyntaxTrees.Single(); var model = comp.GetSemanticModel(tree); var tuple = tree.GetRoot().DescendantNodes().OfType().Single(); Assert.Null(model.GetTypeInfo(tuple).Type); Assert.Equal("(System.Int32, System.String)?", model.GetTypeInfo(tuple).ConvertedType.ToTestDisplayString()); Assert.Equal(ConversionKind.ExplicitNullable, model.GetConversion(tuple).Kind); var first = tuple.Arguments[0].Expression; Assert.Equal("System.Int32?", model.GetTypeInfo(first).Type.ToTestDisplayString()); Assert.Equal("System.Int32", model.GetTypeInfo(first).ConvertedType.ToTestDisplayString()); Assert.Equal(ConversionKind.ExplicitNullable, model.GetConversion(first).Kind); var second = tuple.Arguments[1].Expression; Assert.Null(model.GetTypeInfo(second).Type); Assert.Equal("System.String", model.GetTypeInfo(second).ConvertedType.ToTestDisplayString()); Assert.Equal(ConversionKind.ImplicitReference, model.GetConversion(second).Kind); } [Fact] [WorkItem(18738, "https://github.com/dotnet/roslyn/issues/18738")] public void TypelessTupleWithNoImplicitConversion2_02() { var source = @" class C { (int, string)? M() { int? e = 5; return (e, null); // the only conversion we find is an explicit conversion } } "; var comp = CreateEmptyCompilation(source, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp7_1), references: new[] { MscorlibRef, ValueTupleRef, SystemRuntimeFacadeRef }); comp.VerifyDiagnostics( // (7,16): error CS8135: Tuple with 2 elements cannot be converted to type '(int, string)?'. // return (e, null); // the only conversion we find is an explicit conversion Diagnostic(ErrorCode.ERR_ConversionNotTupleCompatible, "(e, null)").WithArguments("2", "(int, string)?").WithLocation(7, 16) ); VerifySemanticModelTypelessTupleWithNoImplicitConversion2(comp); } [Fact] [WorkItem(18738, "https://github.com/dotnet/roslyn/issues/18738")] public void TypelessTupleWithNoImplicitConversion3() { var source = @" class C { void M() { int? e = 5; (int, string, int) y = (e, null); // no conversion found System.Console.Write(y); } } "; var comp = CreateEmptyCompilation(source, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp7_1), references: new[] { MscorlibRef, ValueTupleRef, SystemRuntimeFacadeRef }); comp.VerifyDiagnostics( // (7,32): error CS8135: Tuple with 2 elements cannot be converted to type '(int, string, int)'. // (int, string, int) y = (e, null); // no conversion found Diagnostic(ErrorCode.ERR_ConversionNotTupleCompatible, "(e, null)").WithArguments("2", "(int, string, int)").WithLocation(7, 32) ); var tree = comp.SyntaxTrees.Single(); var model = comp.GetSemanticModel(tree); var tuple = tree.GetRoot().DescendantNodes().OfType().Single(); Assert.Null(model.GetTypeInfo(tuple).Type); Assert.Equal("(System.Int32, System.String, System.Int32)", model.GetTypeInfo(tuple).ConvertedType.ToTestDisplayString()); Assert.Equal(ConversionKind.NoConversion, model.GetConversion(tuple).Kind); var first = tuple.Arguments[0].Expression; Assert.Equal("System.Int32?", model.GetTypeInfo(first).Type.ToTestDisplayString()); Assert.Equal("System.Int32?", model.GetTypeInfo(first).ConvertedType.ToTestDisplayString()); Assert.Equal(ConversionKind.Identity, model.GetConversion(first).Kind); var second = tuple.Arguments[1].Expression; Assert.Null(model.GetTypeInfo(second).Type); Assert.Null(model.GetTypeInfo(second).ConvertedType); Assert.Equal(ConversionKind.Identity, model.GetConversion(second).Kind); } [Fact] [WorkItem(20208, "https://github.com/dotnet/roslyn/issues/20208")] public void UnusedTupleAssignedToVar() { var source = @" class C { public static void Main () { (int, int) t1 = (1, 2); var t2 = (3, 4); } } "; var comp = CreateEmptyCompilation(source, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp7_1), references: new[] { MscorlibRef, ValueTupleRef, SystemRuntimeFacadeRef }); comp.VerifyDiagnostics( // (6,20): warning CS0219: The variable 't1' is assigned but its value is never used // (int, int) t1 = (1, 2); Diagnostic(ErrorCode.WRN_UnreferencedVarAssg, "t1").WithArguments("t1").WithLocation(6, 20), // (7,13): warning CS0219: The variable 't2' is assigned but its value is never used // var t2 = (3, 4); Diagnostic(ErrorCode.WRN_UnreferencedVarAssg, "t2").WithArguments("t2").WithLocation(7, 13) ); var tree = comp.SyntaxTrees.Single(); var model = comp.GetSemanticModel(tree); var tuple = tree.GetRoot().DescendantNodes().OfType().ElementAt(1); Assert.Equal("(System.Int32, System.Int32)", model.GetTypeInfo(tuple).Type.ToTestDisplayString()); Assert.Equal("(System.Int32, System.Int32)", model.GetTypeInfo(tuple).ConvertedType.ToTestDisplayString()); Assert.Equal(ConversionKind.Identity, model.GetConversion(tuple).Kind); } [Fact] [WorkItem(18738, "https://github.com/dotnet/roslyn/issues/18738")] public void TypedTupleWithNoConversion() { var source = @" class C { void M() { int? e = 5; (int, string, int) y = (e, """"); // no conversion found System.Console.Write(y); } } "; var comp = CreateEmptyCompilation(source, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp7_1), references: new[] { MscorlibRef, ValueTupleRef, SystemRuntimeFacadeRef }); comp.VerifyDiagnostics( // (7,32): error CS0029: Cannot implicitly convert type '(int? e, string)' to '(int, string, int)' // (int, string, int) y = (e, ""); // no conversion found Diagnostic(ErrorCode.ERR_NoImplicitConv, @"(e, """")").WithArguments("(int? e, string)", "(int, string, int)").WithLocation(7, 32) ); var tree = comp.SyntaxTrees.Single(); var model = comp.GetSemanticModel(tree); var tuple = tree.GetRoot().DescendantNodes().OfType().Single(); Assert.Equal("(System.Int32? e, System.String)", model.GetTypeInfo(tuple).Type.ToTestDisplayString()); Assert.Equal("(System.Int32, System.String, System.Int32)", model.GetTypeInfo(tuple).ConvertedType.ToTestDisplayString()); Assert.Equal(ConversionKind.NoConversion, model.GetConversion(tuple).Kind); } [Fact] [WorkItem(20494, "https://github.com/dotnet/roslyn/issues/20494")] public void MoreGenericTieBreaker_01() { var source = @"using System; public class C { public static void Main() { A> a = null; M1(a); // ok, selects M1(A> a) var b = default(ValueTuple, int>); M2(b); // ok, should select M2(ValueTuple, int> a) } public static void M1(A a) { Console.Write(1); } public static void M1(A> a) { Console.Write(2); } public static void M2(ValueTuple a) { Console.Write(3); } public static void M2(ValueTuple, int> a) { Console.Write(4); } } public class A {}"; var comp = CompileAndVerify(source, expectedOutput: "24"); } [Fact] [WorkItem(20494, "https://github.com/dotnet/roslyn/issues/20494")] public void MoreGenericTieBreaker_01b() { var source = @"using System; public class C { public static void Main() { var b = ((0, 0), 0); M2(b); // ok, should select M2(((T, int), int) a) } public static void M2((T, int) a) { Console.Write(3); } public static void M2(((T, int), int) a) { Console.Write(4); } }"; var comp = CompileAndVerify(source, expectedOutput: "4"); } [Fact] [WorkItem(20494, "https://github.com/dotnet/roslyn/issues/20494")] [WorkItem(20583, "https://github.com/dotnet/roslyn/issues/20583")] public void MoreGenericTieBreaker_02a1() { var source = @"using System; public class C { public static void Main() { // var b = (1, 2, 3, 4, 5, 6, 7, 8); var b = new ValueTuple>(1, 2, 3, 4, 5, 6, 7, new ValueTuple(8)); M1(b); M2(b); // ok, should select M2(ValueTuple> a) } public static void M1(ValueTuple a) where TRest : struct { Console.Write(1); } public static void M2(ValueTuple> a) { Console.Write(2); } public static void M2(ValueTuple a) where TRest : struct { Console.Write(3); } } "; var comp = CompileAndVerify(source, expectedOutput: @"12"); } [Fact] [WorkItem(20494, "https://github.com/dotnet/roslyn/issues/20494")] [WorkItem(20583, "https://github.com/dotnet/roslyn/issues/20583")] public void MoreGenericTieBreaker_02a2() { var source = @"using System; public class C { public static void Main() { // var b = (1, 2, 3, 4, 5, 6, 7, 8); var b = new ValueTuple>(1, 2, 3, 4, 5, 6, 7, new ValueTuple(8)); M1(ref b); M2(ref b); // ok, should select M2(ValueTuple> a) } public static void M1(ref ValueTuple a) where TRest : struct { Console.Write(1); } public static void M2(ref ValueTuple> a) { Console.Write(2); } public static void M2(ref ValueTuple a) where TRest : struct { Console.Write(3); } } "; var comp = CompileAndVerify(source, expectedOutput: @"12"); } [Fact] [WorkItem(20494, "https://github.com/dotnet/roslyn/issues/20494")] [WorkItem(20583, "https://github.com/dotnet/roslyn/issues/20583")] public void MoreGenericTieBreaker_02a3() { var source = @"using System; public class C { public static void Main() { I>> b = null; M1(b); M2(b); } public static void M1(I> a) where TRest : struct { Console.Write(1); } public static void M2(I>> a) { Console.Write(2); } public static void M2(I> a) where TRest : struct { Console.Write(3); } } public interface I{} "; var comp = CompileAndVerify(source, expectedOutput: @"12"); } [Fact] [WorkItem(20494, "https://github.com/dotnet/roslyn/issues/20494")] [WorkItem(20583, "https://github.com/dotnet/roslyn/issues/20583")] public void MoreGenericTieBreaker_02a4() { var source = @"using System; public class C { public static void Main() { I>> b = null; M1(b); M2(b); } public static void M1(I> a) where TRest : struct { Console.Write(1); } public static void M2(I>> a) { Console.Write(2); } public static void M2(I> a) where TRest : struct { Console.Write(3); } } public interface I{} "; var comp = CompileAndVerify(source, expectedOutput: @"12"); } [Fact] [WorkItem(20494, "https://github.com/dotnet/roslyn/issues/20494")] [WorkItem(20583, "https://github.com/dotnet/roslyn/issues/20583")] public void MoreGenericTieBreaker_02a5() { var source = @"using System; public class C { public static void Main() { M1((1, 2, 3, 4, 5, 6, 7, 8)); M2((1, 2, 3, 4, 5, 6, 7, 8)); } public static void M1(ValueTuple a) where TRest : struct { Console.Write(1); } public static void M2(ValueTuple> a) { Console.Write(2); } public static void M2(ValueTuple a) where TRest : struct { Console.Write(3); } } "; var comp = CompileAndVerify(source, expectedOutput: @"12"); } [Fact] [WorkItem(20494, "https://github.com/dotnet/roslyn/issues/20494")] [WorkItem(20583, "https://github.com/dotnet/roslyn/issues/20583")] public void MoreGenericTieBreaker_02a6() { var source = @"using System; public class C { public static void Main() { M2((()=>1, ()=>2, ()=>3, ()=>4, ()=>5, ()=>6, ()=>7, ()=>8)); } public static void M2(ValueTuple, Func, Func, Func, Func, Func, Func, ValueTuple>> a) { Console.Write(2); } public static void M2(ValueTuple, Func, Func, Func, Func, Func, Func, TRest> a) where TRest : struct { Console.Write(3); } } "; var comp = CompileAndVerify(source, expectedOutput: @"2"); } [Fact] [WorkItem(20494, "https://github.com/dotnet/roslyn/issues/20494")] [WorkItem(20583, "https://github.com/dotnet/roslyn/issues/20583")] public void MoreGenericTieBreaker_02a7() { var source = @"using System; public class C { public static void Main() { M1((()=>1, ()=>2, ()=>3, ()=>4, ()=>5, ()=>6, ()=>7, ()=>8)); } public static void M1(ValueTuple, Func, Func, Func, Func, Func, Func, TRest> a) where TRest : struct { Console.Write(1); } } "; CreateCompilation(source).VerifyDiagnostics( // (6,9): error CS0411: The type arguments for method 'C.M1(ValueTuple, Func, Func, Func, Func, Func, Func, TRest>)' cannot be inferred from the usage. Try specifying the type arguments explicitly. // M1((()=>1, ()=>2, ()=>3, ()=>4, ()=>5, ()=>6, ()=>7, ()=>8)); Diagnostic(ErrorCode.ERR_CantInferMethTypeArgs, "M1").WithArguments("C.M1(System.ValueTuple, System.Func, System.Func, System.Func, System.Func, System.Func, System.Func, TRest>)").WithLocation(6, 9) ); } [Fact] [WorkItem(20494, "https://github.com/dotnet/roslyn/issues/20494")] [WorkItem(20583, "https://github.com/dotnet/roslyn/issues/20583")] public void MoreGenericTieBreaker_02b() { var source = @"using System; public class C { public static void Main() { var b = (1, 2, 3, 4, 5, 6, 7, 8); M1(b); M2(b); // ok, should select M2((T1, T2, T3, T4, T5, T6, T7, T8) a) } public static void M1(ValueTuple a) where TRest : struct { Console.Write(1); } public static void M2((T1, T2, T3, T4, T5, T6, T7, T8) a) { Console.Write(2); } public static void M2(ValueTuple a) where TRest : struct { Console.Write(3); } } "; var comp = CompileAndVerify(source, expectedOutput: @"12"); } [Fact] [WorkItem(20494, "https://github.com/dotnet/roslyn/issues/20494")] public void MoreGenericTieBreaker_03() { var source = @"using System; public class C { public static void Main() { var b = ((1, 1), 2, 3, 4, 5, 6, 7, 8, 9, (10, 10), (11, 11)); M1(b); // ok, should select M2(((T, int), int, int, int, int, int, int, int, int, (U, int), V) a) } public static void M1(((T, int), int, int, int, int, int, int, int, int, (U, int), V) a) { Console.Write(3); } public static void M1((T, int, int, int, int, int, int, int, int, U, (V, int)) a) { Console.Write(4); } }"; var comp = CompileAndVerify(source, expectedOutput: "3"); } [Fact] [WorkItem(20494, "https://github.com/dotnet/roslyn/issues/20494")] public void MoreGenericTieBreaker_04() { var source = @"using System; public class C { public static void Main() { var b = ((1, 1), 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, (20, 20)); M1(b); // error: ambiguous } public static void M1((T, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, (U, int)) a) { Console.Write(3); } public static void M1(((T, int), int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, U) a) { Console.Write(4); } }"; CreateCompilation(source).VerifyDiagnostics( // (7,9): error CS0121: The call is ambiguous between the following methods or properties: 'C.M1((T, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, (U, int)))' and 'C.M1(((T, int), int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, U))' // M1(b); // error: ambiguous Diagnostic(ErrorCode.ERR_AmbigCall, "M1").WithArguments("C.M1((T, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, (U, int)))", "C.M1(((T, int), int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, U))").WithLocation(7, 9) ); } [Fact] [WorkItem(21785, "https://github.com/dotnet/roslyn/issues/21785")] void TypelessTupleInArrayInitializer() { string source = @" class C { static (int A, object B)[] mTupleArray = { (A: 0, B: null) }; private static void Main() { System.Console.Write(mTupleArray[0].B == null); } }"; var comp = CreateCompilation(source, options: TestOptions.DebugExe); comp.VerifyDiagnostics(); CompileAndVerify(comp, expectedOutput: "True"); var tree = comp.SyntaxTrees[0]; var model = comp.GetSemanticModel(tree); var nodes = tree.GetCompilationUnitRoot().DescendantNodes(); var node = nodes.OfType().Single(); Assert.Equal("(A: 0, B: null)", node.ToString()); var tupleSymbol = model.GetTypeInfo(node); Assert.Null(tupleSymbol.Type); Assert.Equal("(System.Int32 A, System.Object B)", tupleSymbol.ConvertedType.ToTestDisplayString()); } [Fact] public void SettingMembersOfReadOnlyTuple() { var text = @" public class C { public static void Main() { var tuple = (1, 2); tuple.Item1 = 3; } } namespace System { public readonly struct ValueTuple { public readonly T1 Item1; public readonly T2 Item2; public ValueTuple(T1 item1, T2 item2) { this.Item1 = item1; this.Item2 = item2; } } } "; CreateCompilation(text).VerifyDiagnostics( // (10,9): error CS0191: A readonly field cannot be assigned to (except in the constructor of the class in which the field is defined or a variable initializer)) // tuple.Item1 = 3; Diagnostic(ErrorCode.ERR_AssgReadonly, "tuple.Item1").WithLocation(8, 9)); } [Fact, WorkItem(24781, "https://github.com/dotnet/roslyn/issues/24781")] public void InferenceWithTuple_AddingNames() { string source = @" using System; public interface IDo { IResult Do(Func fn); } public interface IResult { } public class Class1 { public void Test1(IDo<(int, int)> impl) { var case3 = impl.Do(((int x, int y) a) => a.x * a.y); } }"; var comp = CreateCompilation(source); comp.VerifyDiagnostics(); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var doSyntax = tree.GetCompilationUnitRoot().DescendantNodes().OfType().Single(); Assert.Equal("impl.Do(((int x, int y) a) => a.x * a.y)", doSyntax.ToString()); var doSymbol = (IMethodSymbol)model.GetSymbolInfo(doSyntax).Symbol; Assert.Equal("IResult", doSymbol.ReturnType.ToTestDisplayString()); } [Fact, WorkItem(24781, "https://github.com/dotnet/roslyn/issues/24781")] public void InferenceWithTuple_DifferentNames() { string source = @" using System; public interface IDo { IResult Do(Func fn); } public interface IResult { } public class Class1 { public void Test1(IDo<(int a, int b)> impl) { var case3 = impl.Do(((int x, int y) a) => a.x * a.y); } }"; var comp = CreateCompilation(source); comp.VerifyDiagnostics(); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var doSyntax = tree.GetCompilationUnitRoot().DescendantNodes().OfType().Single(); Assert.Equal("impl.Do(((int x, int y) a) => a.x * a.y)", doSyntax.ToString()); var doSymbol = (IMethodSymbol)model.GetSymbolInfo(doSyntax).Symbol; Assert.Equal("IResult", doSymbol.ReturnType.ToTestDisplayString()); } [Fact, WorkItem(24781, "https://github.com/dotnet/roslyn/issues/24781")] public void InferenceWithTuple_DroppingNames() { string source = @" using System; public interface IDo { IResult Do(Func fn); } public interface IResult { } public class Class1 { public void Test1(IDo<(int a, int b)> impl) { var case3 = impl.Do(((int, int) a) => a.Item1 * a.Item2); } }"; var comp = CreateCompilation(source); comp.VerifyDiagnostics(); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var doSyntax = tree.GetCompilationUnitRoot().DescendantNodes().OfType().Single(); Assert.Equal("impl.Do(((int, int) a) => a.Item1 * a.Item2)", doSyntax.ToString()); var doSymbol = (IMethodSymbol)model.GetSymbolInfo(doSyntax).Symbol; Assert.Equal("IResult", doSymbol.ReturnType.ToTestDisplayString()); } [Fact, WorkItem(24781, "https://github.com/dotnet/roslyn/issues/24781")] public void InferenceWithDynamic() { string source = @" using System; public interface IDo { IResult Do(Func fn); } public interface IResult { } public class Class1 { public void Test1(IDo impl) { var case3 = impl.Do((dynamic a) => 1); } }"; var comp = CreateCompilation(source); comp.VerifyDiagnostics(); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var doSyntax = tree.GetCompilationUnitRoot().DescendantNodes().OfType().Single(); Assert.Equal("impl.Do((dynamic a) => 1)", doSyntax.ToString()); var doSymbol = (IMethodSymbol)model.GetSymbolInfo(doSyntax).Symbol; Assert.Equal("IResult", doSymbol.ReturnType.ToTestDisplayString()); } [Theory] [InlineData(true)] [InlineData(false)] [WorkItem(40430, "https://github.com/dotnet/roslyn/issues/40430")] public void MissingTypeArgumentInBase_ValueTuple(bool useImageReference) { var lib_cs = @" public class C2 { } public class SelfReferencing : C2 { public SelfReferencing() { System.Console.Write(""ran""); } } "; var lib = CreateCompilationWithMscorlib40(lib_cs, references: s_valueTupleRefs); lib.VerifyDiagnostics(); var libRef = useImageReference ? lib.EmitToImageReference() : lib.ToMetadataReference(); var source_cs = @" public class Program { public static void M() { _ = new SelfReferencing(); } } "; var comp = CreateCompilationWithMscorlib40(source_cs, references: new[] { libRef }); comp.VerifyEmitDiagnostics(); var executable_cs = @" public class C { public static void Main() { Program.M(); } }"; var executeComp = CreateCompilationWithMscorlib40(executable_cs, references: new[] { comp.EmitToImageReference(), libRef, SystemRuntimeFacadeRef, ValueTupleRef }, options: TestOptions.DebugExe); CompileAndVerify(executeComp, expectedOutput: "ran"); } [Theory] [InlineData(true, true)] [InlineData(true, false)] [InlineData(false, true)] [InlineData(false, false)] [WorkItem(40430, "https://github.com/dotnet/roslyn/issues/40430")] public void MissingTypeArgumentInBase_ValueTupleInContainer(bool useImageReference, bool missingValueTuple) { var missingContainer_cs = @" public class MissingContainer { } "; var missingContainer = CreateCompilationWithMscorlib40(missingContainer_cs, references: s_valueTupleRefs); missingContainer.VerifyDiagnostics(); var missingContainerRef = useImageReference ? missingContainer.EmitToImageReference() : missingContainer.ToMetadataReference(); var lib_cs = @" public class C2 { } public class SelfReferencing : C2> { public SelfReferencing() { System.Console.Write(""ran""); } } "; var lib = CreateCompilationWithMscorlib40(lib_cs, references: new[] { missingContainerRef, SystemRuntimeFacadeRef, ValueTupleRef }); lib.VerifyDiagnostics(); var libRef = useImageReference ? lib.EmitToImageReference() : lib.ToMetadataReference(); var source_cs = @" public class Program { public static void M() { _ = new SelfReferencing(); } } "; // Compile without System.ValueTuple and/or MissingContainer var references = missingValueTuple ? new[] { libRef } : new[] { libRef, SystemRuntimeFacadeRef, ValueTupleRef }; var comp = CreateCompilationWithMscorlib40(source_cs, references: references); comp.VerifyEmitDiagnostics(); // Execute with all the references present var executable_cs = @" public class C { public static void Main() { Program.M(); } }"; var executeComp = CreateCompilationWithMscorlib40(executable_cs, references: new[] { comp.EmitToImageReference(), libRef, SystemRuntimeFacadeRef, ValueTupleRef, missingContainerRef }, options: TestOptions.DebugExe); CompileAndVerify(executeComp, expectedOutput: "ran"); } [Theory] [InlineData(true)] [InlineData(false)] [WorkItem(40430, "https://github.com/dotnet/roslyn/issues/40430")] public void MissingTypeArgumentInBase_ValueTupleAndContainer(bool useImageReference) { var missingContainer_cs = @" public class MissingContainer { } "; var missingContainer = CreateCompilationWithMscorlib40(missingContainer_cs, references: s_valueTupleRefs); missingContainer.VerifyDiagnostics(); var missingContainerRef = useImageReference ? missingContainer.EmitToImageReference() : missingContainer.ToMetadataReference(); var lib_cs = @" public class C : MissingContainer<(string A, int B)> { public C() { System.Console.Write(""ran""); } } "; var lib = CreateCompilationWithMscorlib40(lib_cs, references: new[] { SystemRuntimeFacadeRef, ValueTupleRef, missingContainerRef }); lib.VerifyDiagnostics(); var libRef = useImageReference ? lib.EmitToImageReference() : lib.ToMetadataReference(); var source_cs = @" public class C2 { public static void M() { _ = new C(); } } "; var executable_cs = @" public class C3 { public static void Main() { C2.M(); } }"; var comp = CreateCompilationWithMscorlib40(source_cs, references: new[] { libRef }); // missing System.ValueTuple and MissingContainer comp.VerifyEmitDiagnostics(); var executeComp = CreateCompilationWithMscorlib40(executable_cs, references: new[] { comp.EmitToImageReference(), libRef, missingContainerRef, SystemRuntimeFacadeRef, ValueTupleRef }, options: TestOptions.DebugExe); CompileAndVerify(executeComp, expectedOutput: "ran"); var comp2 = CreateCompilationWithMscorlib40(source_cs, references: new[] { libRef, missingContainerRef }); // missing System.ValueTuple comp2.VerifyEmitDiagnostics(); var executeComp2 = CreateCompilationWithMscorlib40(executable_cs, references: new[] { comp.EmitToImageReference(), libRef, missingContainerRef, SystemRuntimeFacadeRef, ValueTupleRef }, options: TestOptions.DebugExe); CompileAndVerify(executeComp2, expectedOutput: "ran"); } [Theory] [InlineData(true)] [InlineData(false)] [WorkItem(40430, "https://github.com/dotnet/roslyn/issues/40430")] public void MissingTypeArgumentInBase(bool useImageReference) { var missing_cs = @"public class Missing { }"; var missing = CreateCompilation(missing_cs); missing.VerifyDiagnostics(); var missingRef = useImageReference ? missing.EmitToImageReference() : missing.ToMetadataReference(); var lib_cs = @" public class C2 { } public class SelfReferencingClassWithMissing : C2 { public SelfReferencingClassWithMissing() { System.Console.Write(""ran""); } } "; var lib = CreateCompilation(lib_cs, references: new[] { missingRef }); lib.VerifyDiagnostics(); var libRef = useImageReference ? lib.EmitToImageReference() : lib.ToMetadataReference(); var source_cs = @" public class C { public static void M() { _ = new SelfReferencingClassWithMissing(); } } "; var comp = CreateCompilation(source_cs, references: new[] { libRef }); comp.VerifyEmitDiagnostics(); var executable_cs = @" public class C2 { public static void Main() { C.M(); } }"; var executeComp = CreateCompilation(executable_cs, references: new[] { comp.EmitToImageReference(), libRef, missingRef }, options: TestOptions.DebugExe); CompileAndVerify(executeComp, expectedOutput: "ran"); } [Fact] [WorkItem(41699, "https://github.com/dotnet/roslyn/issues/41699")] public void MissingBaseType_TupleTypeArgumentWithNames() { var sourceA = @"public class A { }"; var comp = CreateCompilation(sourceA, assemblyName: "A"); var refA = comp.EmitToImageReference(); var sourceB = @"public class B : A<(object X, B Y)> { }"; comp = CreateCompilation(sourceB, references: new[] { refA }); var refB = comp.EmitToImageReference(); var sourceC = @"class Program { static void Main() { var b = new B(); b.ToString(); } }"; comp = CreateCompilation(sourceC, references: new[] { refB }); comp.VerifyDiagnostics( // (6,11): error CS0012: The type 'A<>' is defined in an assembly that is not referenced. You must add a reference to assembly 'A, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'. // b.ToString(); Diagnostic(ErrorCode.ERR_NoTypeDef, "ToString").WithArguments("A<>", "A, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null").WithLocation(6, 11)); } [Fact] [WorkItem(21727, "https://github.com/dotnet/roslyn/issues/21727")] public void FailedDecodingOfTupleNamesWhenMissingValueTupleType() { var vtLib = CreateEmptyCompilation(trivial2uple + tupleattributes_cs, references: new[] { MscorlibRef }, assemblyName: "vt"); var lib_cs = @" using System.Collections; using System.Collections.Generic; public class ClassA : IEnumerable<(int alice, int bob)> { public void Add(int alice, int bob) => throw null; public IEnumerator<(int alice, int bob)> GetEnumerator() => throw null; IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); }"; var lib = CreateEmptyCompilation(lib_cs, references: new[] { MscorlibRef, vtLib.EmitToImageReference() }); lib.VerifyDiagnostics(); var client_cs = @" public class ClassB { public ClassB() { new ClassA { { 42, 10 } }; } }"; var comp = CreateEmptyCompilation(client_cs, references: new[] { MscorlibRef, lib.EmitToImageReference() }); // missing reference to vt comp.VerifyDiagnostics(); verifyTupleTypeWithErrorUnderlyingType(comp, decodingSuccessful: false); var compWithMetadataReference = CreateEmptyCompilation(client_cs, references: new[] { MscorlibRef, lib.ToMetadataReference() }); // missing reference to vt compWithMetadataReference.VerifyDiagnostics(); verifyTupleTypeWithErrorUnderlyingType(compWithMetadataReference, decodingSuccessful: true); var fakeVtLib = CreateEmptyCompilation("", references: new[] { MscorlibRef }, assemblyName: "vt"); var compWithFakeVt = CreateEmptyCompilation(client_cs, references: new[] { MscorlibRef, lib.EmitToImageReference(), fakeVtLib.EmitToImageReference() }); // reference to fake vt compWithFakeVt.VerifyDiagnostics(); verifyTupleTypeWithErrorUnderlyingType(compWithFakeVt, decodingSuccessful: false); var client2_cs = @" public class ClassB { public ClassB() { var collectionA = new ClassA { { 42, 10 } }; foreach (var i in collectionA) { } } }"; var comp2 = CreateEmptyCompilation(client2_cs, references: new[] { MscorlibRef, lib.EmitToImageReference() }); // missing reference to vt comp2.VerifyDiagnostics( // (7,27): error CS0012: The type '(, )' is defined in an assembly that is not referenced. You must add a reference to assembly 'vt, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'. // foreach (var i in collectionA) Diagnostic(ErrorCode.ERR_NoTypeDef, "collectionA").WithArguments("(, )", "vt, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null").WithLocation(7, 27), // (7,27): error CS0012: The type '(, )' is defined in an assembly that is not referenced. You must add a reference to assembly 'vt, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'. // foreach (var i in collectionA) Diagnostic(ErrorCode.ERR_NoTypeDef, "collectionA").WithArguments("(, )", "vt, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null").WithLocation(7, 27) ); verifyTupleTypeWithErrorUnderlyingType(comp2, decodingSuccessful: false); var comp2WithFakeVt = CreateEmptyCompilation(client2_cs, references: new[] { MscorlibRef, lib.EmitToImageReference(), fakeVtLib.EmitToImageReference() }); // reference to fake vt comp2WithFakeVt.VerifyDiagnostics( // (7,27): error CS7069: Reference to type '(, )' claims it is defined in 'vt', but it could not be found // foreach (var i in collectionA) Diagnostic(ErrorCode.ERR_MissingTypeInAssembly, "collectionA").WithArguments("(, )", "vt").WithLocation(7, 27), // (7,27): error CS7069: Reference to type '(, )' claims it is defined in 'vt', but it could not be found // foreach (var i in collectionA) Diagnostic(ErrorCode.ERR_MissingTypeInAssembly, "collectionA").WithArguments("(, )", "vt").WithLocation(7, 27) ); verifyTupleTypeWithErrorUnderlyingType(comp2WithFakeVt, decodingSuccessful: false); void verifyTupleTypeWithErrorUnderlyingType(CSharpCompilation compilation, bool decodingSuccessful) { var classA = (NamedTypeSymbol)compilation.GetMember("ClassA"); var iEnumerable = (ConstructedNamedTypeSymbol)classA.Interfaces()[0]; if (decodingSuccessful) { Assert.Equal("System.Collections.Generic.IEnumerable<(System.Int32 alice, System.Int32 bob)[missing]>", iEnumerable.ToTestDisplayString()); } else { Assert.Equal("System.Collections.Generic.IEnumerable<(System.Int32, System.Int32)[missing]>", iEnumerable.ToTestDisplayString()); } var tuple = iEnumerable.TypeArguments()[0]; if (decodingSuccessful) { Assert.Equal("(System.Int32 alice, System.Int32 bob)[missing]", tuple.ToTestDisplayString()); Assert.True(tuple.IsTupleType); Assert.True(tuple.IsErrorType()); } else { Assert.Equal("(System.Int32, System.Int32)[missing]", tuple.ToTestDisplayString()); Assert.True(tuple.IsTupleType); Assert.True(tuple.IsErrorType()); } } } [Fact] [WorkItem(21727, "https://github.com/dotnet/roslyn/issues/21727")] public void FailedDecodingOfLongTupleNamesWhenMissingValueTupleType() { var vtLib = CreateEmptyCompilation(tuplelib_cs + tupleattributes_cs, references: new[] { MscorlibRef }, assemblyName: "vt"); var lib_cs = @" using System.Collections; using System.Collections.Generic; public class ClassA : IEnumerable<(int i1, int i2, int i3, int i4, int i5, int i6, int i7, int i8)> { public void Add(int i1, int i2, int i3, int i4, int i5, int i6, int i7, int i8) => throw null; public IEnumerator<(int i1, int i2, int i3, int i4, int i5, int i6, int i7, int i8)> GetEnumerator() => throw null; IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); }"; var lib = CreateEmptyCompilation(lib_cs, references: new[] { MscorlibRef, vtLib.EmitToImageReference() }); lib.VerifyDiagnostics(); var client2_cs = @" public class ClassB { public ClassB() { var collectionA = new ClassA { { 1, 2, 3, 4, 5, 6, 7, 8 } }; foreach (var i in collectionA) { } } }"; var fakeVtLib = CreateEmptyCompilation("", references: new[] { MscorlibRef }, assemblyName: "vt"); var comp = CreateEmptyCompilation(client2_cs, references: new[] { MscorlibRef, lib.EmitToImageReference() }); // missing reference to vt comp.VerifyDiagnostics( // (7,27): error CS0012: The type 'ValueTuple<,,,,,,,>' is defined in an assembly that is not referenced. You must add a reference to assembly 'vt, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'. // foreach (var i in collectionA) Diagnostic(ErrorCode.ERR_NoTypeDef, "collectionA").WithArguments("System.ValueTuple<,,,,,,,>", "vt, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null").WithLocation(7, 27), // (7,27): error CS0012: The type 'ValueTuple<,,,,,,,>' is defined in an assembly that is not referenced. You must add a reference to assembly 'vt, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'. // foreach (var i in collectionA) Diagnostic(ErrorCode.ERR_NoTypeDef, "collectionA").WithArguments("System.ValueTuple<,,,,,,,>", "vt, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null").WithLocation(7, 27) ); verifyTupleTypeWithErrorUnderlyingType(comp); var compWithFakeVt = CreateEmptyCompilation(client2_cs, references: new[] { MscorlibRef, lib.EmitToImageReference(), fakeVtLib.EmitToImageReference() }); // reference to fake vt compWithFakeVt.VerifyDiagnostics( // (7,27): error CS7069: Reference to type 'ValueTuple<,,,,,,,>' claims it is defined in 'vt', but it could not be found // foreach (var i in collectionA) Diagnostic(ErrorCode.ERR_MissingTypeInAssembly, "collectionA").WithArguments("System.ValueTuple<,,,,,,,>", "vt").WithLocation(7, 27), // (7,27): error CS7069: Reference to type 'ValueTuple<,,,,,,,>' claims it is defined in 'vt', but it could not be found // foreach (var i in collectionA) Diagnostic(ErrorCode.ERR_MissingTypeInAssembly, "collectionA").WithArguments("System.ValueTuple<,,,,,,,>", "vt").WithLocation(7, 27) ); verifyTupleTypeWithErrorUnderlyingType(compWithFakeVt); void verifyTupleTypeWithErrorUnderlyingType(CSharpCompilation compilation) { var classA = (NamedTypeSymbol)compilation.GetMember("ClassA"); var iEnumerable = (ConstructedNamedTypeSymbol)classA.Interfaces()[0]; var tuple = iEnumerable.TypeArguments()[0]; AssertEx.Equal("System.ValueTuple[missing]>[missing]", tuple.ToTestDisplayString()); Assert.True(tuple.IsErrorType()); Assert.True(tuple.IsTupleType); } } [Fact] [WorkItem(21727, "https://github.com/dotnet/roslyn/issues/21727")] public void FailedDecodingOfTupleNamesWhenMissingNonTupleType() { var containerLib = CreateEmptyCompilation("public class Container { }", references: new[] { MscorlibRef }, assemblyName: "container"); var lib_cs = @" using System.Collections; using System.Collections.Generic; public class ClassA : IEnumerable> { public void Add(int alice, int bob) => throw null; public IEnumerator> GetEnumerator() => throw null; IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); }"; var lib = CreateEmptyCompilation(lib_cs + tuplelib_cs + tupleattributes_cs, references: new[] { MscorlibRef, containerLib.EmitToImageReference() }); lib.VerifyDiagnostics(); var client_cs = @" public class ClassB { public ClassB() { new ClassA { { 42, 10 } }; } }"; var comp = CreateEmptyCompilation(client_cs, references: new[] { MscorlibRef, lib.EmitToImageReference() }); // missing reference to container comp.VerifyDiagnostics(); verifyTupleTypeWithErrorUnderlyingType(comp, decodingSuccessful: false); var compWithMetadataReference = CreateEmptyCompilation(client_cs, references: new[] { MscorlibRef, lib.ToMetadataReference() }); // missing reference to container compWithMetadataReference.VerifyDiagnostics(); verifyTupleTypeWithErrorUnderlyingType(compWithMetadataReference, decodingSuccessful: true); var fakeContainerLib = CreateEmptyCompilation("", references: new[] { MscorlibRef }, assemblyName: "container"); var compWithFakeContainer = CreateEmptyCompilation(client_cs, references: new[] { MscorlibRef, lib.EmitToImageReference(), fakeContainerLib.EmitToImageReference() }); // reference to fake container compWithFakeContainer.VerifyDiagnostics(); verifyTupleTypeWithErrorUnderlyingType(compWithFakeContainer, decodingSuccessful: false); void verifyTupleTypeWithErrorUnderlyingType(CSharpCompilation compilation, bool decodingSuccessful) { var classA = (NamedTypeSymbol)compilation.GetMember("ClassA"); var iEnumerable = (ConstructedNamedTypeSymbol)classA.Interfaces()[0]; if (decodingSuccessful) { AssertEx.Equal("System.Collections.Generic.IEnumerable[missing]>", iEnumerable.ToTestDisplayString()); } else { Assert.Equal("System.Collections.Generic.IEnumerable[missing]>", iEnumerable.ToTestDisplayString()); } var container = (NamedTypeSymbol)iEnumerable.TypeArguments()[0]; Assert.True(container.IsErrorType()); var tuple = (NamedTypeSymbol)container.TypeArguments()[0]; if (decodingSuccessful) { Assert.Equal("(System.Int32 alice, System.Int32 bob)", tuple.ToTestDisplayString()); } else { Assert.Equal("(System.Int32, System.Int32)", tuple.ToTestDisplayString()); } Assert.True(tuple.IsTupleType); Assert.False(tuple.TupleUnderlyingType.IsErrorType()); Assert.False(tuple.IsErrorType()); } } [Fact] [WorkItem(21727, "https://github.com/dotnet/roslyn/issues/21727")] public void FailedDecodingOfTupleNamesWhenMissingContainerType() { var containerLib = CreateEmptyCompilation("public class Container { public class Contained { } }", references: new[] { MscorlibRef }, assemblyName: "container"); var lib_cs = @" using System.Collections; using System.Collections.Generic; public class ClassA : IEnumerable.Contained<(int charlie, int dylan)>> { public void Add(int alice, int bob) => throw null; public IEnumerator.Contained<(int charlie, int dylan)>> GetEnumerator() => throw null; IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); }"; var lib = CreateEmptyCompilation(lib_cs + tuplelib_cs + tupleattributes_cs, references: new[] { MscorlibRef, containerLib.EmitToImageReference() }); lib.VerifyDiagnostics(); var client_cs = @" public class ClassB { public ClassB() { new ClassA { { 42, 10 } }; } }"; var comp = CreateEmptyCompilation(client_cs, references: new[] { MscorlibRef, lib.EmitToImageReference() }); // missing reference to container comp.VerifyDiagnostics(); verifyTupleTypeWithErrorUnderlyingType(comp, decodingSuccessful: false); var compWithMetadataReference = CreateEmptyCompilation(client_cs, references: new[] { MscorlibRef, lib.ToMetadataReference() }); // missing reference to container compWithMetadataReference.VerifyDiagnostics(); verifyTupleTypeWithErrorUnderlyingType(compWithMetadataReference, decodingSuccessful: true); var fakeContainerLib = CreateEmptyCompilation("", references: new[] { MscorlibRef }, assemblyName: "container"); var compWithFakeContainer = CreateEmptyCompilation(client_cs, references: new[] { MscorlibRef, lib.EmitToImageReference(), fakeContainerLib.EmitToImageReference() }); // reference to fake container compWithFakeContainer.VerifyDiagnostics(); verifyTupleTypeWithErrorUnderlyingType(compWithFakeContainer, decodingSuccessful: false); void verifyTupleTypeWithErrorUnderlyingType(CSharpCompilation compilation, bool decodingSuccessful) { var classA = (NamedTypeSymbol)compilation.GetMember("ClassA"); var iEnumerable = (ConstructedNamedTypeSymbol)classA.Interfaces()[0]; AssertEx.Equal(decodingSuccessful ? "System.Collections.Generic.IEnumerable[missing].Contained<(System.Int32 charlie, System.Int32 dylan)>[missing]>" : "System.Collections.Generic.IEnumerable[missing].Contained<(System.Int32, System.Int32)>[missing]>", iEnumerable.ToTestDisplayString()); var contained = (NamedTypeSymbol)iEnumerable.TypeArguments()[0]; Assert.Equal(decodingSuccessful ? "Container<(System.Int32 alice, System.Int32 bob)>[missing].Contained<(System.Int32 charlie, System.Int32 dylan)>[missing]" : "Container<(System.Int32, System.Int32)>[missing].Contained<(System.Int32, System.Int32)>[missing]", contained.ToTestDisplayString()); Assert.True(contained.IsErrorType()); var tuple1 = (NamedTypeSymbol)contained.TypeArguments()[0]; Assert.Equal(decodingSuccessful ? "(System.Int32 charlie, System.Int32 dylan)" : "(System.Int32, System.Int32)", tuple1.ToTestDisplayString()); Assert.True(tuple1.IsTupleType); Assert.False(tuple1.TupleUnderlyingType.IsErrorType()); Assert.False(tuple1.IsErrorType()); var container = contained.ContainingType; Assert.Equal(decodingSuccessful ? "Container<(System.Int32 alice, System.Int32 bob)>[missing]" : "Container<(System.Int32, System.Int32)>[missing]", container.ToTestDisplayString()); Assert.True(container.IsErrorType()); var tuple2 = (NamedTypeSymbol)container.TypeArguments()[0]; Assert.Equal(decodingSuccessful ? "(System.Int32 alice, System.Int32 bob)" : "(System.Int32, System.Int32)", tuple2.ToTestDisplayString()); Assert.True(tuple2.IsTupleType); Assert.False(tuple2.TupleUnderlyingType.IsErrorType()); Assert.False(tuple2.IsErrorType()); } } [Fact] [WorkItem(41207, "https://github.com/dotnet/roslyn/issues/41207")] [WorkItem(1056281, "https://dev.azure.com/devdiv/DevDiv/_workitems/edit/1056281")] [WorkItem(43549, "https://github.com/dotnet/roslyn/issues/43549")] public void CustomFields_01() { var source0 = @" namespace System { // struct with two values public struct ValueTuple { public static int F1 = 123; public T1 Item1; public T2 Item2; public ValueTuple(T1 item1, T2 item2) { this.Item1 = item1; this.Item2 = item2; } public override string ToString() { return F1.ToString(); } } } "; var source1 = @" class Program { public static void Main() { System.Console.WriteLine((1,2).ToString()); } } "; var source2 = @" class Program { public static void Main() { System.Console.WriteLine(System.ValueTuple.F1); } } "; var comp1 = CreateCompilation(source0 + source1, targetFramework: TargetFramework.Mscorlib40, options: TestOptions.DebugExe); CompileAndVerify(comp1, expectedOutput: "123"); verifyField(comp1); var comp1Ref = new[] { comp1.ToMetadataReference() }; var comp1ImageRef = new[] { comp1.EmitToImageReference() }; var comp4 = CreateCompilation(source0 + source2, targetFramework: TargetFramework.Mscorlib40, options: TestOptions.DebugExe); CompileAndVerify(comp4, expectedOutput: "123"); var comp5 = CreateCompilation(source2, targetFramework: TargetFramework.Mscorlib40, options: TestOptions.DebugExe, references: comp1Ref); CompileAndVerify(comp5, expectedOutput: "123"); verifyField(comp5); var comp6 = CreateCompilation(source2, targetFramework: TargetFramework.Mscorlib40, options: TestOptions.DebugExe, references: comp1ImageRef); CompileAndVerify(comp6, expectedOutput: "123"); verifyField(comp6); // Uncomment after https://github.com/dotnet/roslyn/issues/43549 is fixed. //var comp7 = CreateCompilation(source2, targetFramework: TargetFramework.Mscorlib46, options: TestOptions.DebugExe, references: comp1Ref); //CompileAndVerify(comp7, expectedOutput: "123"); //verifyField(comp7); void verifyField(CSharpCompilation comp) { var field = comp.GetMember("System.ValueTuple.F1"); Assert.NotNull(field.TupleUnderlyingField); Assert.NotSame(field, field.TupleUnderlyingField); var toEmit = field.ContainingType.GetFieldsToEmit().Where(f => f.Name == "F1").Single(); Assert.Same(toEmit, toEmit.TupleUnderlyingField); Assert.Same(field.TupleUnderlyingField, toEmit); } } [Fact] [WorkItem(41207, "https://github.com/dotnet/roslyn/issues/41207")] [WorkItem(1056281, "https://dev.azure.com/devdiv/DevDiv/_workitems/edit/1056281")] [WorkItem(43549, "https://github.com/dotnet/roslyn/issues/43549")] public void CustomFields_02() { var source0 = @" namespace System { // struct with two values public struct ValueTuple { public int F1; public T1 Item1; public T2 Item2; public ValueTuple(T1 item1, T2 item2) { this.Item1 = item1; this.Item2 = item2; F1 = 123; } public override string ToString() { return F1.ToString(); } } } "; var source1 = @" class Program { public static void Main() { System.Console.WriteLine((1,2).ToString()); } } "; var source2 = @" class Program { public static void Main() { System.Console.WriteLine((1,2).F1); } } "; var comp1 = CreateCompilation(source0 + source1, targetFramework: TargetFramework.Mscorlib40, options: TestOptions.DebugExe); CompileAndVerify(comp1, expectedOutput: "123"); verifyField(comp1); var comp1Ref = new[] { comp1.ToMetadataReference() }; var comp1ImageRef = new[] { comp1.EmitToImageReference() }; var comp4 = CreateCompilation(source0 + source2, targetFramework: TargetFramework.Mscorlib40, options: TestOptions.DebugExe); CompileAndVerify(comp4, expectedOutput: "123"); var comp5 = CreateCompilation(source2, targetFramework: TargetFramework.Mscorlib40, options: TestOptions.DebugExe, references: comp1Ref); CompileAndVerify(comp5, expectedOutput: "123"); verifyField(comp5); var comp6 = CreateCompilation(source2, targetFramework: TargetFramework.Mscorlib40, options: TestOptions.DebugExe, references: comp1ImageRef); CompileAndVerify(comp6, expectedOutput: "123"); verifyField(comp6); // Uncomment after https://github.com/dotnet/roslyn/issues/43549 is fixed. //var comp7 = CreateCompilation(source2, targetFramework: TargetFramework.Mscorlib46, options: TestOptions.DebugExe, references: comp1Ref); //CompileAndVerify(comp7, expectedOutput: "123"); //verifyField(comp7); void verifyField(CSharpCompilation comp) { var field = comp.GetMember("System.ValueTuple.F1"); Assert.NotNull(field.TupleUnderlyingField); Assert.NotSame(field, field.TupleUnderlyingField); var toEmit = field.ContainingType.GetFieldsToEmit().Where(f => f.Name == "F1").Single(); Assert.Same(toEmit, toEmit.TupleUnderlyingField); Assert.Same(field.TupleUnderlyingField, toEmit); } } [Fact] [WorkItem(43524, "https://github.com/dotnet/roslyn/issues/43524")] [WorkItem(1095184, "https://devdiv.visualstudio.com/DevDiv/_workitems/edit/1095184")] [WorkItem(43549, "https://github.com/dotnet/roslyn/issues/43549")] public void CustomFields_03() { var source0 = @" namespace System { public struct ValueTuple { public static readonly int F1 = 4; public static int CombineHashCodes(int h1, int h2) { return F1 + h1 + h2; } } } "; var source1 = @" class Program { static void Main() { System.Console.WriteLine(System.ValueTuple.CombineHashCodes(2, 3)); } } "; var source2 = @" class Program { public static void Main() { System.Console.WriteLine(System.ValueTuple.F1 + 2 + 3); } } "; var comp1 = CreateCompilation(source0 + source1, targetFramework: TargetFramework.Mscorlib40, options: TestOptions.DebugExe); CompileAndVerify(comp1, expectedOutput: "9"); verifyField(comp1); var comp1Ref = new[] { comp1.ToMetadataReference() }; var comp1ImageRef = new[] { comp1.EmitToImageReference() }; var comp4 = CreateCompilation(source0 + source2, targetFramework: TargetFramework.Mscorlib40, options: TestOptions.DebugExe); CompileAndVerify(comp4, expectedOutput: "9"); var comp5 = CreateCompilation(source2, targetFramework: TargetFramework.Mscorlib40, options: TestOptions.DebugExe, references: comp1Ref); CompileAndVerify(comp5, expectedOutput: "9"); verifyField(comp5); var comp6 = CreateCompilation(source2, targetFramework: TargetFramework.Mscorlib40, options: TestOptions.DebugExe, references: comp1ImageRef); CompileAndVerify(comp6, expectedOutput: "9"); verifyField(comp6); // Uncomment after https://github.com/dotnet/roslyn/issues/43549 is fixed. //var comp7 = CreateCompilation(source2, targetFramework: TargetFramework.Mscorlib46, options: TestOptions.DebugExe, references: comp1Ref); //CompileAndVerify(comp7, expectedOutput: "9"); //verifyField(comp7); void verifyField(CSharpCompilation comp) { var field = comp.GetMember("System.ValueTuple.F1"); Assert.NotNull(field.TupleUnderlyingField); Assert.NotSame(field, field.TupleUnderlyingField); var toEmit = field.ContainingType.GetFieldsToEmit().Single(); Assert.Same(toEmit, toEmit.TupleUnderlyingField); Assert.Same(field.TupleUnderlyingField, toEmit); } } [Fact] [WorkItem(43524, "https://github.com/dotnet/roslyn/issues/43524")] [WorkItem(1095184, "https://devdiv.visualstudio.com/DevDiv/_workitems/edit/1095184")] [WorkItem(43549, "https://github.com/dotnet/roslyn/issues/43549")] public void CustomFields_04() { var source0 = @" namespace System { public struct ValueTuple { public int F1; public int CombineHashCodes(int h1, int h2) { return F1 + h1 + h2; } } } "; var source1 = @" class Program { static void Main() { System.ValueTuple tuple = default; tuple.F1 = 4; System.Console.WriteLine(tuple.CombineHashCodes(2, 3)); } } "; var source2 = @" class Program { public static void Main() { System.ValueTuple tuple = default; tuple.F1 = 4; System.Console.WriteLine(tuple.F1 + 2 + 3); } } "; var comp1 = CreateCompilation(source0 + source1, targetFramework: TargetFramework.Mscorlib40, options: TestOptions.DebugExe); CompileAndVerify(comp1, expectedOutput: "9"); verifyField(comp1); var comp1Ref = new[] { comp1.ToMetadataReference() }; var comp1ImageRef = new[] { comp1.EmitToImageReference() }; var comp4 = CreateCompilation(source0 + source2, targetFramework: TargetFramework.Mscorlib40, options: TestOptions.DebugExe); CompileAndVerify(comp4, expectedOutput: "9"); var comp5 = CreateCompilation(source2, targetFramework: TargetFramework.Mscorlib40, options: TestOptions.DebugExe, references: comp1Ref); CompileAndVerify(comp5, expectedOutput: "9"); verifyField(comp5); var comp6 = CreateCompilation(source2, targetFramework: TargetFramework.Mscorlib40, options: TestOptions.DebugExe, references: comp1ImageRef); CompileAndVerify(comp6, expectedOutput: "9"); verifyField(comp6); // Uncomment after https://github.com/dotnet/roslyn/issues/43549 is fixed. //var comp7 = CreateCompilation(source2, targetFramework: TargetFramework.Mscorlib46, options: TestOptions.DebugExe, references: comp1Ref); //CompileAndVerify(comp7, expectedOutput: "9"); //verifyField(comp7); void verifyField(CSharpCompilation comp) { var field = comp.GetMember("System.ValueTuple.F1"); Assert.NotNull(field.TupleUnderlyingField); Assert.NotSame(field, field.TupleUnderlyingField); var toEmit = field.ContainingType.GetFieldsToEmit().Single(); Assert.Same(toEmit, toEmit.TupleUnderlyingField); Assert.Same(field.TupleUnderlyingField, toEmit); } } [Fact(Skip = "https://github.com/dotnet/roslyn/issues/43621")] [WorkItem(43621, "https://github.com/dotnet/roslyn/issues/43621")] public void CustomFields_05() { var source0 = @" using System; namespace System { public class C { public unsafe static void Main() { var s = new ValueTuple(); int* p = s.MessageType; s.MessageType[0] = 12; p[1] = p[0]; Console.WriteLine(s.MessageType[1]); } } public unsafe struct ValueTuple { public fixed int MessageType[50]; } } "; var comp1 = CreateCompilation(source0, options: TestOptions.DebugExe.WithAllowUnsafe(true)); CompileAndVerify(comp1, expectedOutput: "12"); } [Fact] [WorkItem(41702, "https://github.com/dotnet/roslyn/issues/41702")] public void TupleUnderlyingType_FromCSharp() { var source = @"#pragma warning disable 169 class Program { static System.ValueTuple F0; static (int, int) F1; static (int A, int B) F2; static (object, object, object, object, object, object, object, object) F3; static (object, object B, object, object D, object, object F, object, object H) F4; }"; var comp = CreateCompilation(source); comp.VerifyDiagnostics(); var containingType = comp.GlobalNamespace.GetTypeMembers("Program").Single(); VerifyTypeFromCSharp((NamedTypeSymbol)((FieldSymbol)containingType.GetMembers("F0").Single()).Type, TupleUnderlyingTypeValue.Same, TupleUnderlyingTypeValue.Null, TupleUnderlyingTypeValue.Same, TupleUnderlyingTypeValue.Null, "System.ValueTuple", "()"); VerifyTypeFromCSharp((NamedTypeSymbol)((FieldSymbol)containingType.GetMembers("F1").Single()).Type, TupleUnderlyingTypeValue.Same, TupleUnderlyingTypeValue.Null, TupleUnderlyingTypeValue.Same, TupleUnderlyingTypeValue.Null, "(System.Int32, System.Int32)", "(System.Int32, System.Int32)"); VerifyTypeFromCSharp((NamedTypeSymbol)((FieldSymbol)containingType.GetMembers("F2").Single()).Type, TupleUnderlyingTypeValue.Distinct, TupleUnderlyingTypeValue.Distinct, TupleUnderlyingTypeValue.Same, TupleUnderlyingTypeValue.Null, "(System.Int32 A, System.Int32 B)", "(A As System.Int32, B As System.Int32)"); VerifyTypeFromCSharp((NamedTypeSymbol)((FieldSymbol)containingType.GetMembers("F3").Single()).Type, TupleUnderlyingTypeValue.Same, TupleUnderlyingTypeValue.Null, TupleUnderlyingTypeValue.Null, TupleUnderlyingTypeValue.Null, "(System.Object, System.Object, System.Object, System.Object, System.Object, System.Object, System.Object, System.Object)", "(System.Object, System.Object, System.Object, System.Object, System.Object, System.Object, System.Object, System.Object)"); VerifyTypeFromCSharp((NamedTypeSymbol)((FieldSymbol)containingType.GetMembers("F4").Single()).Type, TupleUnderlyingTypeValue.Distinct, TupleUnderlyingTypeValue.Distinct, TupleUnderlyingTypeValue.Null, TupleUnderlyingTypeValue.Null, "(System.Object, System.Object B, System.Object, System.Object D, System.Object, System.Object F, System.Object, System.Object H)", "(System.Object, B As System.Object, System.Object, D As System.Object, System.Object, F As System.Object, System.Object, H As System.Object)"); } [Fact] [WorkItem(41702, "https://github.com/dotnet/roslyn/issues/41702")] public void TupleUnderlyingType_FromVisualBasic() { var source = @"Class Program Private F0 As System.ValueTuple Private F1 As (Integer, Integer) Private F2 As (A As Integer, B As Integer) Private F3 As (Object, Object, Object, Object, Object, Object, Object, Object) Private F4 As (Object, B As Object, Object, D As Object, Object, F As Object, Object, H As Object) End Class"; var comp = CreateVisualBasicCompilation(source, referencedAssemblies: TargetFrameworkUtil.GetReferences(TargetFramework.Standard)); comp.VerifyDiagnostics(); var containingType = comp.GlobalNamespace.GetTypeMembers("Program").Single(); VerifyTypeFromVisualBasic((INamedTypeSymbol)((IFieldSymbol)containingType.GetMembers("F0").Single()).Type, TupleUnderlyingTypeValue.Null, "System.ValueTuple", "System.ValueTuple"); VerifyTypeFromVisualBasic((INamedTypeSymbol)((IFieldSymbol)containingType.GetMembers("F1").Single()).Type, TupleUnderlyingTypeValue.Distinct, "(System.Int32, System.Int32)", "(System.Int32, System.Int32)"); VerifyTypeFromVisualBasic((INamedTypeSymbol)((IFieldSymbol)containingType.GetMembers("F2").Single()).Type, TupleUnderlyingTypeValue.Distinct, "(System.Int32 A, System.Int32 B)", "(A As System.Int32, B As System.Int32)"); VerifyTypeFromVisualBasic((INamedTypeSymbol)((IFieldSymbol)containingType.GetMembers("F3").Single()).Type, TupleUnderlyingTypeValue.Distinct, "(System.Object, System.Object, System.Object, System.Object, System.Object, System.Object, System.Object, System.Object)", "(System.Object, System.Object, System.Object, System.Object, System.Object, System.Object, System.Object, System.Object)"); VerifyTypeFromVisualBasic((INamedTypeSymbol)((IFieldSymbol)containingType.GetMembers("F4").Single()).Type, TupleUnderlyingTypeValue.Distinct, "(System.Object, System.Object B, System.Object, System.Object D, System.Object, System.Object F, System.Object, System.Object H)", "(System.Object, B As System.Object, System.Object, D As System.Object, System.Object, F As System.Object, System.Object, H As System.Object)"); } private enum TupleUnderlyingTypeValue { Null, Distinct, Same } private static void VerifyTypeFromCSharp( NamedTypeSymbol type, TupleUnderlyingTypeValue expectedInternalValue, TupleUnderlyingTypeValue expectedPublicValue, TupleUnderlyingTypeValue definitionInternalValue, TupleUnderlyingTypeValue definitionPublicValue, string expectedCSharp, string expectedVisualBasic) { VerifyDisplay(type.GetPublicSymbol(), expectedCSharp, expectedVisualBasic); VerifyInternalType(type, expectedInternalValue); VerifyPublicType(type.GetPublicSymbol(), expectedPublicValue); type = type.OriginalDefinition; VerifyInternalType(type, definitionInternalValue); VerifyPublicType(type.GetPublicSymbol(), definitionPublicValue); } private static void VerifyTypeFromVisualBasic( INamedTypeSymbol type, TupleUnderlyingTypeValue expectedValue, string expectedCSharp, string expectedVisualBasic) { VerifyDisplay(type, expectedCSharp, expectedVisualBasic); VerifyPublicType(type, expectedValue); VerifyPublicType(type.OriginalDefinition, expectedValue); } private static void VerifyDisplay(INamedTypeSymbol type, string expectedCSharp, string expectedVisualBasic) { Assert.Equal(expectedCSharp, CSharp.SymbolDisplay.ToDisplayString(type, SymbolDisplayFormat.TestFormat)); Assert.Equal(expectedVisualBasic, VisualBasic.SymbolDisplay.ToDisplayString(type, SymbolDisplayFormat.TestFormat)); } private static void VerifyInternalType(NamedTypeSymbol type, TupleUnderlyingTypeValue expectedValue) { var underlyingType = type.TupleUnderlyingType; switch (expectedValue) { case TupleUnderlyingTypeValue.Null: Assert.Null(underlyingType); break; case TupleUnderlyingTypeValue.Distinct: Assert.NotEqual(type, underlyingType); Assert.True(type.Equals(underlyingType, TypeCompareKind.AllIgnoreOptions)); Assert.False(type.Equals(underlyingType, TypeCompareKind.ConsiderEverything)); VerifyInternalType(underlyingType, TupleUnderlyingTypeValue.Same); break; case TupleUnderlyingTypeValue.Same: Assert.Equal(type, underlyingType); Assert.True(type.Equals(underlyingType, TypeCompareKind.ConsiderEverything)); break; default: throw ExceptionUtilities.UnexpectedValue(expectedValue); } } private static void VerifyPublicType(INamedTypeSymbol type, TupleUnderlyingTypeValue expectedValue) { var underlyingType = type.TupleUnderlyingType; switch (expectedValue) { case TupleUnderlyingTypeValue.Null: Assert.Null(underlyingType); break; case TupleUnderlyingTypeValue.Distinct: Assert.NotEqual(type, underlyingType); Assert.False(type.Equals(underlyingType, SymbolEqualityComparer.Default)); Assert.False(type.Equals(underlyingType, SymbolEqualityComparer.ConsiderEverything)); VerifyPublicType(underlyingType, TupleUnderlyingTypeValue.Null); break; default: throw ExceptionUtilities.UnexpectedValue(expectedValue); } } [Fact] [WorkItem(40981, "https://github.com/dotnet/roslyn/issues/40981")] public void TupleFromMetadata_TypeInference() { var source0 = @" using System; public interface IInterface { (Type, Type)[] GetTypeTuples(); } "; var source1 = @" using System; using System.Linq; public class Class { private void Method(IInterface inter, Func<(Type, Type), string> keySelector) { var tuples = inter.GetTypeTuples(); IOrderedEnumerable<(Type, Type)> ordered = tuples.OrderBy(keySelector); } } "; var comp0 = CreateCompilation(new[] { source0, source1 }, options: TestOptions.DebugDll); CompileAndVerify(comp0); var comp1 = CreateCompilation(source0, options: TestOptions.DebugDll); CompileAndVerify(comp1); var comp2 = CreateCompilation(source1, references: new[] { comp1.EmitToImageReference() }, options: TestOptions.DebugDll); CompileAndVerify(comp2); } [Fact] [WorkItem(1090920, "https://devdiv.visualstudio.com/DefaultCollection/DevDiv/_workitems/edit/1090920")] public void GetSymbolInfoOnInitializerOfValueTupleField() { var source = @" namespace System { public struct ValueTuple { public T1 Item1 = default; public ValueTuple(T1 item1) { } } } "; var comp = CreateCompilation(new[] { source }, options: TestOptions.DebugDll); var tree = comp.SyntaxTrees.Single(); var model = comp.GetSemanticModel(tree, ignoreAccessibility: false); var literal = tree.GetRoot().DescendantNodes().OfType().Single(); Assert.True(model.GetSymbolInfo(literal).IsEmpty); } [Fact, WorkItem(1090920, "https://devdiv.visualstudio.com/DefaultCollection/DevDiv/_workitems/edit/1090920")] public void NameofFixedBuffer() { var source = @" namespace System { public class C { public static void Main() { ValueTuple myStruct = default; Console.Write(myStruct.ToString()); char[] o; myStruct.DoSomething(out o); Console.Write(Other.GetFromExternal()); } } public unsafe struct ValueTuple { public fixed char MessageType[50]; public override string ToString() { return nameof(MessageType); } public void DoSomething(out char[] x) { x = new char[] { }; Action a = () => { System.Console.Write($"" {nameof(x)} ""); }; a(); } } class Other { public static string GetFromExternal() { ValueTuple myStruct = default; return nameof(myStruct.MessageType); } } } "; var compilation = CreateCompilationWithMscorlib45(source, null, new CSharpCompilationOptions(OutputKind.ConsoleApplication).WithAllowUnsafe(true)); CompileAndVerify(compilation, expectedOutput: "MessageType x MessageType").VerifyDiagnostics(); } [Fact] [WorkItem(27322, "https://github.com/dotnet/roslyn/issues/27322")] public void ExpressionTreeWithTuple() { var source = @" using System; using System.Collections.Generic; using System.Linq.Expressions; class C { static void Main() { var tupleA = (1, 3); var tupleB = (1, ""123"".Length); Expression> ok1 = () => tupleA.Item1; Expression> ok2 = () => tupleA.GetHashCode(); Expression>> ok3 = () => tupleA.ToTuple(); Expression> ok4 = () => Equals(tupleA, tupleB); Expression> ok5 = () => Comparer<(int, int)>.Default.Compare(tupleA, tupleB); ok1.Compile()(); ok2.Compile()(); ok3.Compile()(); ok4.Compile()(); ok5.Compile()(); Expression> issue1 = () => tupleA.Equals(tupleB); Expression> issue2 = () => tupleA.CompareTo(tupleB); Console.WriteLine(""Done.""); } }"; var comp = CreateCompilation( source, options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: @"Done."); verifier.VerifyIL("C.Main", @" { // Code size 799 (0x31f) .maxstack 7 .locals init (C.<>c__DisplayClass0_0 V_0, //CS$<>8__locals0 System.Linq.Expressions.Expression> V_1, //ok1 System.Linq.Expressions.Expression> V_2, //ok2 System.Linq.Expressions.Expression>> V_3, //ok3 System.Linq.Expressions.Expression> V_4) //ok4 IL_0000: newobj ""C.<>c__DisplayClass0_0..ctor()"" IL_0005: stloc.0 IL_0006: ldloc.0 IL_0007: ldc.i4.1 IL_0008: ldc.i4.3 IL_0009: newobj ""System.ValueTuple..ctor(int, int)"" IL_000e: stfld ""System.ValueTuple C.<>c__DisplayClass0_0.tupleA"" IL_0013: ldloc.0 IL_0014: ldc.i4.1 IL_0015: ldstr ""123"" IL_001a: call ""int string.Length.get"" IL_001f: newobj ""System.ValueTuple..ctor(int, int)"" IL_0024: stfld ""System.ValueTuple C.<>c__DisplayClass0_0.tupleB"" IL_0029: ldloc.0 IL_002a: ldtoken ""C.<>c__DisplayClass0_0"" IL_002f: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" IL_0034: call ""System.Linq.Expressions.ConstantExpression System.Linq.Expressions.Expression.Constant(object, System.Type)"" IL_0039: ldtoken ""System.ValueTuple C.<>c__DisplayClass0_0.tupleA"" IL_003e: call ""System.Reflection.FieldInfo System.Reflection.FieldInfo.GetFieldFromHandle(System.RuntimeFieldHandle)"" IL_0043: call ""System.Linq.Expressions.MemberExpression System.Linq.Expressions.Expression.Field(System.Linq.Expressions.Expression, System.Reflection.FieldInfo)"" IL_0048: ldtoken ""int System.ValueTuple.Item1"" IL_004d: ldtoken ""System.ValueTuple"" IL_0052: call ""System.Reflection.FieldInfo System.Reflection.FieldInfo.GetFieldFromHandle(System.RuntimeFieldHandle, System.RuntimeTypeHandle)"" IL_0057: call ""System.Linq.Expressions.MemberExpression System.Linq.Expressions.Expression.Field(System.Linq.Expressions.Expression, System.Reflection.FieldInfo)"" IL_005c: call ""System.Linq.Expressions.ParameterExpression[] System.Array.Empty()"" IL_0061: call ""System.Linq.Expressions.Expression> System.Linq.Expressions.Expression.Lambda>(System.Linq.Expressions.Expression, params System.Linq.Expressions.ParameterExpression[])"" IL_0066: stloc.1 IL_0067: ldloc.0 IL_0068: ldtoken ""C.<>c__DisplayClass0_0"" IL_006d: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" IL_0072: call ""System.Linq.Expressions.ConstantExpression System.Linq.Expressions.Expression.Constant(object, System.Type)"" IL_0077: ldtoken ""System.ValueTuple C.<>c__DisplayClass0_0.tupleA"" IL_007c: call ""System.Reflection.FieldInfo System.Reflection.FieldInfo.GetFieldFromHandle(System.RuntimeFieldHandle)"" IL_0081: call ""System.Linq.Expressions.MemberExpression System.Linq.Expressions.Expression.Field(System.Linq.Expressions.Expression, System.Reflection.FieldInfo)"" IL_0086: ldtoken ""int object.GetHashCode()"" IL_008b: call ""System.Reflection.MethodBase System.Reflection.MethodBase.GetMethodFromHandle(System.RuntimeMethodHandle)"" IL_0090: castclass ""System.Reflection.MethodInfo"" IL_0095: call ""System.Linq.Expressions.Expression[] System.Array.Empty()"" IL_009a: call ""System.Linq.Expressions.MethodCallExpression System.Linq.Expressions.Expression.Call(System.Linq.Expressions.Expression, System.Reflection.MethodInfo, params System.Linq.Expressions.Expression[])"" IL_009f: call ""System.Linq.Expressions.ParameterExpression[] System.Array.Empty()"" IL_00a4: call ""System.Linq.Expressions.Expression> System.Linq.Expressions.Expression.Lambda>(System.Linq.Expressions.Expression, params System.Linq.Expressions.ParameterExpression[])"" IL_00a9: stloc.2 IL_00aa: ldnull IL_00ab: ldtoken ""System.Tuple System.TupleExtensions.ToTuple(System.ValueTuple)"" IL_00b0: call ""System.Reflection.MethodBase System.Reflection.MethodBase.GetMethodFromHandle(System.RuntimeMethodHandle)"" IL_00b5: castclass ""System.Reflection.MethodInfo"" IL_00ba: ldc.i4.1 IL_00bb: newarr ""System.Linq.Expressions.Expression"" IL_00c0: dup IL_00c1: ldc.i4.0 IL_00c2: ldloc.0 IL_00c3: ldtoken ""C.<>c__DisplayClass0_0"" IL_00c8: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" IL_00cd: call ""System.Linq.Expressions.ConstantExpression System.Linq.Expressions.Expression.Constant(object, System.Type)"" IL_00d2: ldtoken ""System.ValueTuple C.<>c__DisplayClass0_0.tupleA"" IL_00d7: call ""System.Reflection.FieldInfo System.Reflection.FieldInfo.GetFieldFromHandle(System.RuntimeFieldHandle)"" IL_00dc: call ""System.Linq.Expressions.MemberExpression System.Linq.Expressions.Expression.Field(System.Linq.Expressions.Expression, System.Reflection.FieldInfo)"" IL_00e1: stelem.ref IL_00e2: call ""System.Linq.Expressions.MethodCallExpression System.Linq.Expressions.Expression.Call(System.Linq.Expressions.Expression, System.Reflection.MethodInfo, params System.Linq.Expressions.Expression[])"" IL_00e7: call ""System.Linq.Expressions.ParameterExpression[] System.Array.Empty()"" IL_00ec: call ""System.Linq.Expressions.Expression>> System.Linq.Expressions.Expression.Lambda>>(System.Linq.Expressions.Expression, params System.Linq.Expressions.ParameterExpression[])"" IL_00f1: stloc.3 IL_00f2: ldnull IL_00f3: ldtoken ""bool object.Equals(object, object)"" IL_00f8: call ""System.Reflection.MethodBase System.Reflection.MethodBase.GetMethodFromHandle(System.RuntimeMethodHandle)"" IL_00fd: castclass ""System.Reflection.MethodInfo"" IL_0102: ldc.i4.2 IL_0103: newarr ""System.Linq.Expressions.Expression"" IL_0108: dup IL_0109: ldc.i4.0 IL_010a: ldloc.0 IL_010b: ldtoken ""C.<>c__DisplayClass0_0"" IL_0110: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" IL_0115: call ""System.Linq.Expressions.ConstantExpression System.Linq.Expressions.Expression.Constant(object, System.Type)"" IL_011a: ldtoken ""System.ValueTuple C.<>c__DisplayClass0_0.tupleA"" IL_011f: call ""System.Reflection.FieldInfo System.Reflection.FieldInfo.GetFieldFromHandle(System.RuntimeFieldHandle)"" IL_0124: call ""System.Linq.Expressions.MemberExpression System.Linq.Expressions.Expression.Field(System.Linq.Expressions.Expression, System.Reflection.FieldInfo)"" IL_0129: ldtoken ""object"" IL_012e: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" IL_0133: call ""System.Linq.Expressions.UnaryExpression System.Linq.Expressions.Expression.Convert(System.Linq.Expressions.Expression, System.Type)"" IL_0138: stelem.ref IL_0139: dup IL_013a: ldc.i4.1 IL_013b: ldloc.0 IL_013c: ldtoken ""C.<>c__DisplayClass0_0"" IL_0141: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" IL_0146: call ""System.Linq.Expressions.ConstantExpression System.Linq.Expressions.Expression.Constant(object, System.Type)"" IL_014b: ldtoken ""System.ValueTuple C.<>c__DisplayClass0_0.tupleB"" IL_0150: call ""System.Reflection.FieldInfo System.Reflection.FieldInfo.GetFieldFromHandle(System.RuntimeFieldHandle)"" IL_0155: call ""System.Linq.Expressions.MemberExpression System.Linq.Expressions.Expression.Field(System.Linq.Expressions.Expression, System.Reflection.FieldInfo)"" IL_015a: ldtoken ""object"" IL_015f: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" IL_0164: call ""System.Linq.Expressions.UnaryExpression System.Linq.Expressions.Expression.Convert(System.Linq.Expressions.Expression, System.Type)"" IL_0169: stelem.ref IL_016a: call ""System.Linq.Expressions.MethodCallExpression System.Linq.Expressions.Expression.Call(System.Linq.Expressions.Expression, System.Reflection.MethodInfo, params System.Linq.Expressions.Expression[])"" IL_016f: call ""System.Linq.Expressions.ParameterExpression[] System.Array.Empty()"" IL_0174: call ""System.Linq.Expressions.Expression> System.Linq.Expressions.Expression.Lambda>(System.Linq.Expressions.Expression, params System.Linq.Expressions.ParameterExpression[])"" IL_0179: stloc.s V_4 IL_017b: ldnull IL_017c: ldtoken ""System.Collections.Generic.Comparer> System.Collections.Generic.Comparer>.Default.get"" IL_0181: ldtoken ""System.Collections.Generic.Comparer>"" IL_0186: call ""System.Reflection.MethodBase System.Reflection.MethodBase.GetMethodFromHandle(System.RuntimeMethodHandle, System.RuntimeTypeHandle)"" IL_018b: castclass ""System.Reflection.MethodInfo"" IL_0190: call ""System.Linq.Expressions.MemberExpression System.Linq.Expressions.Expression.Property(System.Linq.Expressions.Expression, System.Reflection.MethodInfo)"" IL_0195: ldtoken ""int System.Collections.Generic.Comparer>.Compare(System.ValueTuple, System.ValueTuple)"" IL_019a: ldtoken ""System.Collections.Generic.Comparer>"" IL_019f: call ""System.Reflection.MethodBase System.Reflection.MethodBase.GetMethodFromHandle(System.RuntimeMethodHandle, System.RuntimeTypeHandle)"" IL_01a4: castclass ""System.Reflection.MethodInfo"" IL_01a9: ldc.i4.2 IL_01aa: newarr ""System.Linq.Expressions.Expression"" IL_01af: dup IL_01b0: ldc.i4.0 IL_01b1: ldloc.0 IL_01b2: ldtoken ""C.<>c__DisplayClass0_0"" IL_01b7: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" IL_01bc: call ""System.Linq.Expressions.ConstantExpression System.Linq.Expressions.Expression.Constant(object, System.Type)"" IL_01c1: ldtoken ""System.ValueTuple C.<>c__DisplayClass0_0.tupleA"" IL_01c6: call ""System.Reflection.FieldInfo System.Reflection.FieldInfo.GetFieldFromHandle(System.RuntimeFieldHandle)"" IL_01cb: call ""System.Linq.Expressions.MemberExpression System.Linq.Expressions.Expression.Field(System.Linq.Expressions.Expression, System.Reflection.FieldInfo)"" IL_01d0: stelem.ref IL_01d1: dup IL_01d2: ldc.i4.1 IL_01d3: ldloc.0 IL_01d4: ldtoken ""C.<>c__DisplayClass0_0"" IL_01d9: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" IL_01de: call ""System.Linq.Expressions.ConstantExpression System.Linq.Expressions.Expression.Constant(object, System.Type)"" IL_01e3: ldtoken ""System.ValueTuple C.<>c__DisplayClass0_0.tupleB"" IL_01e8: call ""System.Reflection.FieldInfo System.Reflection.FieldInfo.GetFieldFromHandle(System.RuntimeFieldHandle)"" IL_01ed: call ""System.Linq.Expressions.MemberExpression System.Linq.Expressions.Expression.Field(System.Linq.Expressions.Expression, System.Reflection.FieldInfo)"" IL_01f2: stelem.ref IL_01f3: call ""System.Linq.Expressions.MethodCallExpression System.Linq.Expressions.Expression.Call(System.Linq.Expressions.Expression, System.Reflection.MethodInfo, params System.Linq.Expressions.Expression[])"" IL_01f8: call ""System.Linq.Expressions.ParameterExpression[] System.Array.Empty()"" IL_01fd: call ""System.Linq.Expressions.Expression> System.Linq.Expressions.Expression.Lambda>(System.Linq.Expressions.Expression, params System.Linq.Expressions.ParameterExpression[])"" IL_0202: ldloc.1 IL_0203: callvirt ""System.Func System.Linq.Expressions.Expression>.Compile()"" IL_0208: callvirt ""int System.Func.Invoke()"" IL_020d: pop IL_020e: ldloc.2 IL_020f: callvirt ""System.Func System.Linq.Expressions.Expression>.Compile()"" IL_0214: callvirt ""int System.Func.Invoke()"" IL_0219: pop IL_021a: ldloc.3 IL_021b: callvirt ""System.Func> System.Linq.Expressions.Expression>>.Compile()"" IL_0220: callvirt ""System.Tuple System.Func>.Invoke()"" IL_0225: pop IL_0226: ldloc.s V_4 IL_0228: callvirt ""System.Func System.Linq.Expressions.Expression>.Compile()"" IL_022d: callvirt ""bool System.Func.Invoke()"" IL_0232: pop IL_0233: callvirt ""System.Func System.Linq.Expressions.Expression>.Compile()"" IL_0238: callvirt ""int System.Func.Invoke()"" IL_023d: pop IL_023e: ldloc.0 IL_023f: ldtoken ""C.<>c__DisplayClass0_0"" IL_0244: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" IL_0249: call ""System.Linq.Expressions.ConstantExpression System.Linq.Expressions.Expression.Constant(object, System.Type)"" IL_024e: ldtoken ""System.ValueTuple C.<>c__DisplayClass0_0.tupleA"" IL_0253: call ""System.Reflection.FieldInfo System.Reflection.FieldInfo.GetFieldFromHandle(System.RuntimeFieldHandle)"" IL_0258: call ""System.Linq.Expressions.MemberExpression System.Linq.Expressions.Expression.Field(System.Linq.Expressions.Expression, System.Reflection.FieldInfo)"" IL_025d: ldtoken ""bool System.ValueTuple.Equals(System.ValueTuple)"" IL_0262: ldtoken ""System.ValueTuple"" IL_0267: call ""System.Reflection.MethodBase System.Reflection.MethodBase.GetMethodFromHandle(System.RuntimeMethodHandle, System.RuntimeTypeHandle)"" IL_026c: castclass ""System.Reflection.MethodInfo"" IL_0271: ldc.i4.1 IL_0272: newarr ""System.Linq.Expressions.Expression"" IL_0277: dup IL_0278: ldc.i4.0 IL_0279: ldloc.0 IL_027a: ldtoken ""C.<>c__DisplayClass0_0"" IL_027f: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" IL_0284: call ""System.Linq.Expressions.ConstantExpression System.Linq.Expressions.Expression.Constant(object, System.Type)"" IL_0289: ldtoken ""System.ValueTuple C.<>c__DisplayClass0_0.tupleB"" IL_028e: call ""System.Reflection.FieldInfo System.Reflection.FieldInfo.GetFieldFromHandle(System.RuntimeFieldHandle)"" IL_0293: call ""System.Linq.Expressions.MemberExpression System.Linq.Expressions.Expression.Field(System.Linq.Expressions.Expression, System.Reflection.FieldInfo)"" IL_0298: stelem.ref IL_0299: call ""System.Linq.Expressions.MethodCallExpression System.Linq.Expressions.Expression.Call(System.Linq.Expressions.Expression, System.Reflection.MethodInfo, params System.Linq.Expressions.Expression[])"" IL_029e: call ""System.Linq.Expressions.ParameterExpression[] System.Array.Empty()"" IL_02a3: call ""System.Linq.Expressions.Expression> System.Linq.Expressions.Expression.Lambda>(System.Linq.Expressions.Expression, params System.Linq.Expressions.ParameterExpression[])"" IL_02a8: pop IL_02a9: ldloc.0 IL_02aa: ldtoken ""C.<>c__DisplayClass0_0"" IL_02af: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" IL_02b4: call ""System.Linq.Expressions.ConstantExpression System.Linq.Expressions.Expression.Constant(object, System.Type)"" IL_02b9: ldtoken ""System.ValueTuple C.<>c__DisplayClass0_0.tupleA"" IL_02be: call ""System.Reflection.FieldInfo System.Reflection.FieldInfo.GetFieldFromHandle(System.RuntimeFieldHandle)"" IL_02c3: call ""System.Linq.Expressions.MemberExpression System.Linq.Expressions.Expression.Field(System.Linq.Expressions.Expression, System.Reflection.FieldInfo)"" IL_02c8: ldtoken ""int System.ValueTuple.CompareTo(System.ValueTuple)"" IL_02cd: ldtoken ""System.ValueTuple"" IL_02d2: call ""System.Reflection.MethodBase System.Reflection.MethodBase.GetMethodFromHandle(System.RuntimeMethodHandle, System.RuntimeTypeHandle)"" IL_02d7: castclass ""System.Reflection.MethodInfo"" IL_02dc: ldc.i4.1 IL_02dd: newarr ""System.Linq.Expressions.Expression"" IL_02e2: dup IL_02e3: ldc.i4.0 IL_02e4: ldloc.0 IL_02e5: ldtoken ""C.<>c__DisplayClass0_0"" IL_02ea: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" IL_02ef: call ""System.Linq.Expressions.ConstantExpression System.Linq.Expressions.Expression.Constant(object, System.Type)"" IL_02f4: ldtoken ""System.ValueTuple C.<>c__DisplayClass0_0.tupleB"" IL_02f9: call ""System.Reflection.FieldInfo System.Reflection.FieldInfo.GetFieldFromHandle(System.RuntimeFieldHandle)"" IL_02fe: call ""System.Linq.Expressions.MemberExpression System.Linq.Expressions.Expression.Field(System.Linq.Expressions.Expression, System.Reflection.FieldInfo)"" IL_0303: stelem.ref IL_0304: call ""System.Linq.Expressions.MethodCallExpression System.Linq.Expressions.Expression.Call(System.Linq.Expressions.Expression, System.Reflection.MethodInfo, params System.Linq.Expressions.Expression[])"" IL_0309: call ""System.Linq.Expressions.ParameterExpression[] System.Array.Empty()"" IL_030e: call ""System.Linq.Expressions.Expression> System.Linq.Expressions.Expression.Lambda>(System.Linq.Expressions.Expression, params System.Linq.Expressions.ParameterExpression[])"" IL_0313: pop IL_0314: ldstr ""Done."" IL_0319: call ""void System.Console.WriteLine(string)"" IL_031e: ret } "); } [Fact] [WorkItem(24517, "https://github.com/dotnet/roslyn/issues/24517")] public void Issue24517() { var source = @" using System; using System.Collections.Generic; using System.Linq.Expressions; class C { static void Main() { Expression>> e1 = () => new ValueTuple(1, 2); Expression>> e2 = () => new KeyValuePair(1, 2); e1.Compile()(); e2.Compile()(); Console.WriteLine(""Done.""); } }"; var comp = CreateCompilation( source, options: TestOptions.ReleaseExe); CompileAndVerify(comp, expectedOutput: @"Done."); } [Fact] [WorkItem(44000, "https://github.com/dotnet/roslyn/issues/44000")] public void TupleField_ForceComplete() { var source = @"namespace System { public struct ValueTuple { public T1 Item1; public ValueTuple(T1 item1) { Item1 = item1; } } }"; var comp = CreateCompilation(source, targetFramework: TargetFramework.Mscorlib45); var type = (SourceNamedTypeSymbol)comp.GetMember("System.ValueTuple"); var field = (TupleFieldSymbol)type.GetMember("Item1"); var underlyingField = field.TupleUnderlyingField; Assert.True(field.RequiresCompletion); Assert.True(underlyingField.RequiresCompletion); Assert.False(field.HasComplete(CompletionPart.All)); Assert.False(underlyingField.HasComplete(CompletionPart.All)); field.ForceComplete(null, default); Assert.True(field.RequiresCompletion); Assert.True(underlyingField.RequiresCompletion); Assert.True(field.HasComplete(CompletionPart.All)); Assert.True(underlyingField.HasComplete(CompletionPart.All)); } [Theory, WorkItem(43857, "https://github.com/dotnet/roslyn/issues/43857")] [InlineData("(Z a, Z b)*", @"System.Runtime.CompilerServices.TupleElementNamesAttribute({""a"", ""b""})")] [InlineData("(Z, Z b)*", @"System.Runtime.CompilerServices.TupleElementNamesAttribute({null, ""b""})")] [InlineData("(Z a, Z)*", @"System.Runtime.CompilerServices.TupleElementNamesAttribute({""a"", null})")] [InlineData("(Z, Z)*", null)] [InlineData("((Z a, Z b), Z c)*", @"System.Runtime.CompilerServices.TupleElementNamesAttribute({null, ""c"", ""a"", ""b""})")] public void PointerTypeDecoding(string type, string expectedAttribute) { var comp = CompileAndVerify($@" unsafe struct Z {{ public {type} F; }} ", options: TestOptions.UnsafeReleaseDll, symbolValidator: symbolValidator); void symbolValidator(ModuleSymbol module) { var c = module.GlobalNamespace.GetTypeMember("Z"); var field = c.GetField("F"); if (expectedAttribute == null) { Assert.Empty(field.GetAttributes()); } else { Assert.Equal(expectedAttribute, field.GetAttributes().Single().ToString()); } Assert.Equal(type, field.Type.ToTestDisplayString()); } } } }