File: Attributes\AttributeTests_Tuples.cs
Web Access
Project: src\src\Compilers\CSharp\Test\Emit3\Microsoft.CodeAnalysis.CSharp.Emit3.UnitTests.csproj (Microsoft.CodeAnalysis.CSharp.Emit3.UnitTests)
// 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.
 
#nullable disable
 
using System;
using System.Collections.Immutable;
using System.Linq;
using System.Reflection.Metadata;
using Microsoft.CodeAnalysis.CSharp.Symbols;
using Microsoft.CodeAnalysis.CSharp.Test.Utilities;
using Microsoft.CodeAnalysis.PooledObjects;
using Microsoft.CodeAnalysis.Test.Utilities;
using Roslyn.Test.Utilities;
using Xunit;
 
namespace Microsoft.CodeAnalysis.CSharp.UnitTests
{
    public class AttributeTests_Tuples : WellKnownAttributesTestBase
    {
        private static readonly string s_tuplesTestSource = @"
using System;
 
public class Base0 { }
public class Base1<T> { }
public class Base2<T, U> { }
 
public class Outer<T> : Base1<(int key, int val)>
{
    public class Inner<U, V> : Base2<(int key2, int val2), V>
    {
        public class InnerInner<W> : Base1<(int key3, int val3)> { }
    }
}
 
public class Derived<T> : Outer<(int e1, (int e2, int e3) e4)>.Inner<
    Outer<(int e5, int e6)>.Inner<(int e7, int e8)[], (int e9, int e10)>.InnerInner<int>[],
    ((int e11, int e12) e13, int e14)>
    .InnerInner<((int e15, int e16) e17, (int e18, Base1<(int e19, int e20)> e21) e22)>
{
    public static (int e1, int e2) Field1;
    public static (int e1, int e2) Field2;
    public static Base1<(int e1, (int e2, int e3) e4)> Field3;
 
    public static ValueTuple<Base1<(int e1, (int, (dynamic, dynamic)) e2)>, int> Field4;
 
    public static Outer<(object e1, dynamic e2)>
        .Inner<(dynamic e3, object e4),
                ValueTuple<dynamic, dynamic>> Field5;
 
    // No names
    public static Base1<(int, ValueTuple<int, ValueTuple>)> Field6;
    public static ValueTuple Field7;
 
    // Long tuples
    public static (int e1, int e2, int e3, int e4, int e5,
                   int e6, int e7, int e8, int e9) Field8;
    public static Base1<(int e1, int e2, int e3, int e4, int e5,
                         int e6, int e7, int e8, int e9)> Field9;
 
    public static (int e1, int e2) Method1() => (0, 0);
    public static void Method2((int e1, int e2) x) { }
    public static (int e1, int e2) Method3((int e3, int e4) x) => (0, 0);
    public static (int e1, int e2) Method4(ref (int e3, int e4) x) => x;
 
    public static ((int,
                    (object, (dynamic, object)),
                    object,
                    int),
                   ValueTuple) Method5(ref (object,dynamic) x) =>
        ((0, (null, (null, null)), null, 0), default(ValueTuple));
 
    public static (int e1, int e2, int e3, int e4, int e5,
                   int e6, int e7, int e8, int e9) Method6() => (0, 0, 0, 0,
                                                                 0, 0, 0, 0, 0);
 
    public static (int e1, int e2) Prop1 => (0, 0);
    public static (int e1, int e2) Prop2 { get; set; }
 
    public (int e1, int e2) this[(int e3, int e4) param]
    {
        get { return param; }
        set {}
    }
 
    public delegate void Delegate1<V>(object sender,
        ValueTuple<V,
            ((dynamic e1, dynamic e2, object e3) e4, dynamic e5),
            (dynamic, object)> args);
 
    public static event Delegate1<(dynamic e1,
                                   ValueTuple<(dynamic e2, dynamic e3)> e4)> Event1
    {
        add { }
        remove { }
    }
}";
 
        private static readonly MetadataReference[] s_attributeRefs =
        {
            ValueTupleRef, SystemRuntimeFacadeRef, SystemCoreRef, CSharpRef
        };
 
        [Fact]
        public void TestCompile()
        {
            CompileAndVerifyWithMscorlib40(s_tuplesTestSource,
                options: TestOptions.ReleaseDll,
                references: s_attributeRefs);
        }
 
        [Fact]
        public void TestTupleAttributes()
        {
            var comp = CreateCompilationWithMscorlib40(s_tuplesTestSource,
                options: TestOptions.UnsafeReleaseDll,
                references: s_attributeRefs);
 
            CompileAndVerify(comp, verify: Verification.Passes, symbolValidator: module =>
            {
                TupleAttributeValidator.ValidateTupleAttributes(module);
            });
        }
 
        [Fact]
        public void TupleAttributeWithOnlyOneConstructor()
        {
            var comp = CreateCompilationWithMscorlib40(
                s_tuplesTestSource + TestResources.NetFX.ValueTuple.tuplelib_cs + @"
namespace System.Runtime.CompilerServices
{
    /// <summary>
    /// Indicates that the use of <see cref=""System.ValueTuple""/> on a member is meant to be treated as a tuple with element names.
    /// </summary>
    [AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Property | AttributeTargets.ReturnValue | AttributeTargets.Class | AttributeTargets.Struct )]
    public sealed class TupleElementNamesAttribute : Attribute
    {
        public TupleElementNamesAttribute(string[] transformNames) { }
    }
}",
                references: new[] { SystemCoreRef },
                options: TestOptions.ReleaseDll);
            comp.VerifyDiagnostics();
 
            CompileAndVerify(comp, symbolValidator: module =>
            {
                TupleAttributeValidator.ValidateTupleAttributes(module);
            });
        }
 
        [Fact]
        public void TupleLambdaParametersMissingString()
        {
            var source0 =
@"namespace System
{
    public class Object { }
    public class ValueType { }
    public struct Void { }
    public struct IntPtr { }
    public struct Int32 { }
    public class MulticastDelegate { }
}";
            var source1 =
@"delegate void D<T>(T t);
class C
{
    static void Main()
    {
        D<(int x, int y)> d = o => { };
        d((0, 0));
    }
}";
            var parseOptions = TestOptions.Regular.WithNoRefSafetyRulesAttribute();
            var comp = CreateEmptyCompilation(source0, parseOptions: parseOptions);
            comp.VerifyDiagnostics();
            var ref0 = comp.EmitToImageReference();
            comp = CreateEmptyCompilation(source1,
                parseOptions: parseOptions,
                references: s_attributeRefs.Concat(new[] { ref0 }));
            comp.VerifyDiagnostics(
                // (6,11): error CS0518: Predefined type 'System.String' is not defined or imported
                //         D<(int x, int y)> d = o => { };
                Diagnostic(ErrorCode.ERR_PredefinedTypeNotFound, "(int x, int y)").WithArguments("System.String").WithLocation(6, 11),
                // (6,11): error CS0012: The type 'ValueType' is defined in an assembly that is not referenced. You must add a reference to assembly 'mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'.
                //         D<(int x, int y)> d = o => { };
                Diagnostic(ErrorCode.ERR_NoTypeDef, "(int x, int y)").WithArguments("System.ValueType", "mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089").WithLocation(6, 11),
                // (7,11): error CS0012: The type 'ValueType' is defined in an assembly that is not referenced. You must add a reference to assembly 'mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'.
                //         d((0, 0));
                Diagnostic(ErrorCode.ERR_NoTypeDef, "(0, 0)").WithArguments("System.ValueType", "mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089").WithLocation(7, 11)
                );
        }
 
        [Fact]
        public void TupleInDeclarationFailureWithoutString()
        {
            var source0 =
@"namespace System
{
    public class Object { }
    public class ValueType { }
    public struct Void { }
    public struct IntPtr { }
    public struct Int32 { }
}";
            var source1 =
@"
class C
{
    static (int x, int y) M() => (0, 0);
}";
            var parseOptions = TestOptions.Regular.WithNoRefSafetyRulesAttribute();
            var comp = CreateEmptyCompilation(source0, parseOptions: parseOptions);
            comp.VerifyDiagnostics();
            var ref0 = comp.EmitToImageReference();
            comp = CreateEmptyCompilation(source1,
                parseOptions: parseOptions,
                references: new[] { ref0, ValueTupleRef });
            comp.VerifyDiagnostics(
                // (4,12): error CS0518: Predefined type 'System.String' is not defined or imported
                //     static (int x, int y) M() => (0, 0);
                Diagnostic(ErrorCode.ERR_PredefinedTypeNotFound, "(int x, int y)").WithArguments("System.String").WithLocation(4, 12),
                // (4,12): error CS0012: The type 'ValueType' is defined in an assembly that is not referenced. You must add a reference to assembly 'mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'.
                //     static (int x, int y) M() => (0, 0);
                Diagnostic(ErrorCode.ERR_NoTypeDef, "(int x, int y)").WithArguments("System.ValueType", "mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089").WithLocation(4, 12),
                // (4,34): error CS0012: The type 'ValueType' is defined in an assembly that is not referenced. You must add a reference to assembly 'mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'.
                //     static (int x, int y) M() => (0, 0);
                Diagnostic(ErrorCode.ERR_NoTypeDef, "(0, 0)").WithArguments("System.ValueType", "mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089").WithLocation(4, 34)
                );
        }
 
        [Fact]
        public void RoundTrip()
        {
            ModuleSymbol sourceModule = null;
            ModuleSymbol peModule = null;
            CompileAndVerifyWithMscorlib40(s_tuplesTestSource,
                options: TestOptions.UnsafeReleaseDll,
                references: s_attributeRefs,
                verify: Verification.Passes,
                sourceSymbolValidator: m => sourceModule = m,
                symbolValidator: m => peModule = m);
 
            var srcTypes = sourceModule.GlobalNamespace.GetTypeMembers();
            var peTypes = peModule.GlobalNamespace.GetTypeMembers()
                .WhereAsArray(t => t.Name != "<Module>");
 
            Assert.Equal(srcTypes.Length, peTypes.Length);
 
            for (int i = 0; i < srcTypes.Length; i++)
            {
                var srcType = srcTypes[i];
                var peType = peTypes[i];
 
                Assert.Equal(ToTestString(srcType.BaseType()), ToTestString(peType.BaseType()));
 
                var srcMembers = srcType.GetMembers()
                    .Where(m => !m.Name.Contains("k__BackingField"))
                    .Select(ToTestString)
                    .ToList();
                var peMembers = peType.GetMembers()
                    .Select(ToTestString)
                    .ToList();
 
                srcMembers.Sort();
                peMembers.Sort();
                AssertEx.Equal(srcMembers, peMembers);
            }
        }
 
        private static string ToTestString(Symbol symbol)
        {
            var typeSymbols = ArrayBuilder<TypeSymbol>.GetInstance();
            switch (symbol.Kind)
            {
                case SymbolKind.Method:
                    var methodSymbol = (MethodSymbol)symbol;
                    typeSymbols.Add(methodSymbol.ReturnType);
                    foreach (var parameterType in methodSymbol.ParameterTypesWithAnnotations)
                    {
                        typeSymbols.Add(parameterType.Type);
                    }
                    break;
                case SymbolKind.NamedType:
                    var namedType = (NamedTypeSymbol)symbol;
                    typeSymbols.Add(namedType.BaseType() ?? namedType);
                    break;
                case SymbolKind.Field:
                    typeSymbols.Add(((FieldSymbol)symbol).Type);
                    break;
                case SymbolKind.Property:
                    typeSymbols.Add(((PropertySymbol)symbol).Type);
                    break;
                case SymbolKind.Event:
                    typeSymbols.Add(((EventSymbol)symbol).Type);
                    break;
            }
            var symbolString = string.Join(" | ", typeSymbols
                .Select(s => s.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat)));
            typeSymbols.Free();
            return $"{symbol.Name}: {symbolString}";
        }
 
        private readonly struct TupleAttributeValidator
        {
            private readonly NamedTypeSymbol
                _base0Class,
                _base1Class,
                _base2Class,
                _outerClass,
                _derivedClass;
 
            private TupleAttributeValidator(ModuleSymbol module)
            {
                var globalNs = module.GlobalNamespace;
 
                _base0Class = globalNs.GetTypeMember("Base0");
                _base1Class = globalNs.GetTypeMember("Base1");
                _base2Class = globalNs.GetTypeMember("Base2");
                _outerClass = globalNs.GetTypeMember("Outer");
                _derivedClass = globalNs.GetTypeMember("Derived");
            }
 
            internal static void ValidateTupleAttributes(ModuleSymbol module)
            {
                var validator = new TupleAttributeValidator(module);
 
                validator.ValidateAttributesOnNamedTypes();
                validator.ValidateAttributesOnFields();
                validator.ValidateAttributesOnMethods();
                validator.ValidateAttributesOnProperties();
                validator.ValidateAttributesOnEvents();
                validator.ValidateAttributesOnDelegates();
            }
 
            private void ValidateAttributesOnDelegates()
            {
                // public delegate void Delegate1<T>(object sender,
                //     ValueTuple<T,
                //         ((dynamic e1, dynamic e2, object e3) e4, dynamic e5),
                //         (dynamic, object)> args);
                var delegate1 = _derivedClass.GetMember<NamedTypeSymbol>("Delegate1");
                Assert.NotNull(delegate1);
                Assert.True(delegate1.IsDelegateType());
 
                var invokeMethod = delegate1.DelegateInvokeMethod;
                Assert.NotNull(invokeMethod);
                ValidateTupleNameAttribute(invokeMethod.GetAttributes(), expectedTupleNamesAttribute: false);
 
                Assert.Equal(2, invokeMethod.ParameterCount);
                var sender = invokeMethod.Parameters[0];
                Assert.Equal("sender", sender.Name);
                Assert.Equal(SpecialType.System_Object, sender.Type.SpecialType);
                ValidateTupleNameAttribute(sender.GetAttributes(), expectedTupleNamesAttribute: false);
 
                var args = invokeMethod.Parameters[1];
                Assert.Equal("args", args.Name);
 
                var expectedElementNames = new[]
                {
                    null, null, null, "e4", "e5", "e1", "e2", "e3", null, null
                };
                ValidateTupleNameAttribute(args.GetAttributes(),
                    expectedTupleNamesAttribute: true,
                    expectedElementNames: expectedElementNames);
 
                AttributeTests_Dynamic.DynamicAttributeValidator.ValidateDynamicAttribute(
                    args.GetAttributes(),
                    expectedDynamicAttribute: true,
                    expectedTransformFlags: new[]
                    {
                        false, false, false, false,
                        true, true, false, true,
                        false, true, false
                    });
            }
 
            private void ValidateAttributesOnEvents()
            {
                // public static event Delegate1<(dynamic e1,
                //                                ValueTuple<(dynamic e2, dynamic e3)> e4)> Event1;
                var event1 = _derivedClass.GetMember<EventSymbol>("Event1");
                Assert.NotNull(event1);
 
                ValidateTupleNameAttribute(event1.GetAttributes(),
                    expectedTupleNamesAttribute: true,
                    expectedElementNames: new[]
                    {
                        "e1", "e4", null, "e2", "e3"
                    });
                AttributeTests_Dynamic.DynamicAttributeValidator.ValidateDynamicAttribute(
                    event1.GetAttributes(),
                    expectedDynamicAttribute: true,
                    expectedTransformFlags: new[]
                    {
                        false, false, false, true,
                        false, false, true, true
                    });
            }
 
            private void ValidateAttributesOnNamedTypes()
            {
                // public class Base0 { }
                ValidateTupleNameAttribute(_base0Class.GetAttributes(), expectedTupleNamesAttribute: false);
 
                // public class Base1<T> { }
                ValidateTupleNameAttribute(_base1Class.GetAttributes(), expectedTupleNamesAttribute: false);
 
                // public class Base2<T, U> { }
                ValidateTupleNameAttribute(_base2Class.GetAttributes(), expectedTupleNamesAttribute: false);
 
                // public class Outer<T> : Base1<(int key, int val)>
                Assert.True(_outerClass.BaseType().ContainsTuple());
                var expectedElementNames = new[] { "key", "val" };
                ValidateTupleNameAttribute(_outerClass.GetAttributes(),
                    expectedTupleNamesAttribute: true,
                    expectedElementNames: expectedElementNames);
 
                // public class Derived<T> : Outer<(int e1, (int e2, int e3) e4)>.Inner<
                //     Outer<(int e5, int e6)>.Inner<(int e7, int e8)[], (int e9, int e10)>.InnerInner<int>[],
                //     ((int e11, int e12) e13, int e14)>
                //     .InnerInner<((int e15, int e16) e17, (int e18, Base1<(int e19, int e20)> e21) e22)>
                expectedElementNames = new[] {
                    "e1", "e4", "e2", "e3", "e5", "e6", "e7", "e8", "e9",
                    "e10", "e13", "e14", "e11", "e12", "e17", "e22", "e15",
                    "e16", "e18", "e21", "e19", "e20"
                };
                ValidateTupleNameAttribute(_derivedClass.GetAttributes(),
                    expectedTupleNamesAttribute: true,
                    expectedElementNames: expectedElementNames);
            }
 
            private void ValidateAttributesOnFields()
            {
                // public static (int e1, int e2) Field1;
                var field1 = _derivedClass.GetMember<FieldSymbol>("Field1");
                var expectedElementNames = new[] { "e1", "e2" };
                ValidateTupleNameAttribute(field1.GetAttributes(), expectedTupleNamesAttribute: true, expectedElementNames: expectedElementNames);
 
                // public static (int e1, int e2) Field2;
                var field2 = _derivedClass.GetMember<FieldSymbol>("Field2");
                expectedElementNames = new[] { "e1", "e2" };
                ValidateTupleNameAttribute(field2.GetAttributes(), expectedTupleNamesAttribute: true, expectedElementNames: expectedElementNames);
 
                // public static Base1<(int e1, (int e2, int e3) e4)> Field3;
                var field3 = _derivedClass.GetMember<FieldSymbol>("Field3");
                expectedElementNames = new[] { "e1", "e4", "e2", "e3" };
                ValidateTupleNameAttribute(field3.GetAttributes(), expectedTupleNamesAttribute: true, expectedElementNames: expectedElementNames);
 
                // public static ValueTuple<Base1<(int e1, (int, (dynamic, dynamic)) e2)>, int> Field4;
                var field4 = _derivedClass.GetMember<FieldSymbol>("Field4");
                expectedElementNames = new[] { null, null, "e1", "e2", null, null, null, null };
                ValidateTupleNameAttribute(field4.GetAttributes(), expectedTupleNamesAttribute: true, expectedElementNames: expectedElementNames);
                AttributeTests_Dynamic.DynamicAttributeValidator.ValidateDynamicAttribute(
                    field4.GetAttributes(),
                    expectedDynamicAttribute: true,
                    expectedTransformFlags: new[] {
                        false, false, false, false,
                        false, false, false, true,
                        true, false
                    });
 
                // public static Outer<(object e1, dynamic e2)>
                //     .Inner<(dynamic e3, object e4),
                //             ValueTuple<dynamic, dynamic>> Field5;
                var field5 = _derivedClass.GetMember<FieldSymbol>("Field5");
                expectedElementNames = new[] { "e1", "e2", "e3", "e4", null, null };
                ValidateTupleNameAttribute(field5.GetAttributes(),
                    expectedTupleNamesAttribute: true,
                    expectedElementNames: expectedElementNames);
                AttributeTests_Dynamic.DynamicAttributeValidator.ValidateDynamicAttribute(
                    field5.GetAttributes(),
                    expectedDynamicAttribute: true,
                    expectedTransformFlags: new[]
                    {
                        false, false, false, true,
                        false, true, false, false,
                        true, true
                    });
 
                // public static Base1<(int, ValueTuple<int, ValueTuple>)> Field6;
                var field6 = _derivedClass.GetMember<FieldSymbol>("Field6");
                ValidateTupleNameAttribute(field6.GetAttributes(), expectedTupleNamesAttribute: false);
                var field6Type = Assert.IsType<ConstructedNamedTypeSymbol>(field6.Type);
                Assert.Equal("Base1", field6Type.Name);
                Assert.Equal(1, field6Type.TypeParameters.Length);
                var firstTuple = field6Type.TypeArguments().Single();
                Assert.True(firstTuple.IsTupleType);
                Assert.True(firstTuple.TupleElementNames.IsDefault);
                Assert.Equal(2, firstTuple.TupleElementTypesWithAnnotations.Length);
                var secondTuple = firstTuple.TupleElementTypesWithAnnotations[1].Type;
                Assert.True(secondTuple.IsTupleType);
                Assert.True(secondTuple.TupleElementNames.IsDefault);
                Assert.Equal(2, secondTuple.TupleElementTypesWithAnnotations.Length);
 
                // public static ValueTuple Field7;
                var field7 = _derivedClass.GetMember<FieldSymbol>("Field7");
                ValidateTupleNameAttribute(field7.GetAttributes(), expectedTupleNamesAttribute: false);
                Assert.True(field7.Type.IsTupleType);
                Assert.Empty(field7.Type.TupleElementTypesWithAnnotations);
 
                // public static (int e1, int e2, int e3, int e4, int e5, int e6, int e7, int e8, int e9) Field8;
                var field8 = _derivedClass.GetMember<FieldSymbol>("Field8");
                expectedElementNames = new[]
                {
                    "e1", "e2", "e3", "e4", "e5",
                    "e6", "e7", "e8", "e9", null, null
                };
                ValidateTupleNameAttribute(field8.GetAttributes(), expectedTupleNamesAttribute: true,
                    expectedElementNames: expectedElementNames);
 
                // public static Base<(int e1, int e2, int e3, int e4, int e5, int e6, int e7, int e8, int e9)> Field9;
                var field9 = _derivedClass.GetMember<FieldSymbol>("Field9");
                expectedElementNames = new[]
                {
                    "e1", "e2", "e3", "e4", "e5",
                    "e6", "e7", "e8", "e9", null, null
                };
                ValidateTupleNameAttribute(field9.GetAttributes(), expectedTupleNamesAttribute: true,
                    expectedElementNames: expectedElementNames);
            }
 
            private void ValidateAttributesOnMethods()
            {
                // public static (int e1, int e2) Method1() => (0, 0);
                var method1 = _derivedClass.GetMember<MethodSymbol>("Method1");
                var expectedElementNames = new[] { "e1", "e2" };
                ValidateTupleNameAttribute(method1.GetReturnTypeAttributes(),
                    expectedTupleNamesAttribute: true,
                    expectedElementNames: expectedElementNames);
 
                // public static void Method2((int e1, int e2) x) { }
                var method2 = _derivedClass.GetMember<MethodSymbol>("Method2");
                expectedElementNames = new[] { "e1", "e2" };
                ValidateTupleNameAttribute(method2.Parameters.Single().GetAttributes(),
                    expectedTupleNamesAttribute: true,
                    expectedElementNames: expectedElementNames);
 
                // public static (int e1, int e2) Method3((int e3, int e4) x) => (0, 0);
                var method3 = _derivedClass.GetMember<MethodSymbol>("Method3");
                expectedElementNames = new[] { "e1", "e2" };
                ValidateTupleNameAttribute(method3.GetReturnTypeAttributes(),
                    expectedTupleNamesAttribute: true,
                    expectedElementNames: expectedElementNames);
                expectedElementNames = new[] { "e3", "e4" };
                ValidateTupleNameAttribute(method3.Parameters.Single().GetAttributes(),
                    expectedTupleNamesAttribute: true,
                    expectedElementNames: expectedElementNames);
 
                // public static (int e1, int e2) Method4(ref (int e3, int e4) x) => x;
                var method4 = _derivedClass.GetMember<MethodSymbol>("Method4");
                expectedElementNames = new[] { "e1", "e2" };
                ValidateTupleNameAttribute(method4.GetReturnTypeAttributes(),
                    expectedTupleNamesAttribute: true,
                    expectedElementNames: expectedElementNames);
                expectedElementNames = new[] { "e3", "e4" };
                ValidateTupleNameAttribute(method4.Parameters.Single().GetAttributes(),
                    expectedTupleNamesAttribute: true,
                    expectedElementNames: expectedElementNames);
 
                // public static ((int,
                //                 (object, (dynamic, object)),
                //                 object,
                //                 int),
                //                ValueTuple) Method5(ref (object,dynamic) x) =>
                //     ((0, (null, (null, null)), null, 0), default(ValueTuple));
                var method5 = _derivedClass.GetMember<MethodSymbol>("Method5");
                ValidateTupleNameAttribute(method5.GetReturnTypeAttributes(), expectedTupleNamesAttribute: false);
 
                ValidateTupleNameAttribute(method5.Parameters.Single().GetAttributes(), expectedTupleNamesAttribute: false);
 
                // public static (int e1, int e2, int e3, int e4, int e5,
                //                int e6, int e7, int e8, int e9) Method6() => (0, 0, 0, 0,
                //                                                              0, 0, 0, 0, 0);
                var method6 = _derivedClass.GetMember<MethodSymbol>("Method6");
                expectedElementNames = new[]
                {
                    "e1", "e2", "e3", "e4", "e5",
                    "e6", "e7", "e8", "e9", null, null
                };
                ValidateTupleNameAttribute(method6.GetReturnTypeAttributes(), expectedTupleNamesAttribute: true, expectedElementNames: expectedElementNames);
            }
 
            private void ValidateAttributesOnProperties()
            {
                // public static (int e1, int e2) Prop1 => (0, 0);
                var prop1 = _derivedClass.GetMember("Prop1");
                var expectedTupleNames = new[] { "e1", "e2" };
                ValidateTupleNameAttribute(prop1.GetAttributes(),
                    expectedTupleNamesAttribute: true,
                    expectedElementNames: expectedTupleNames);
 
                // public static (int e1, int e2) Prop2 { get; set; }
                var prop2 = _derivedClass.GetMember("Prop2");
                expectedTupleNames = new[] { "e1", "e2" };
                ValidateTupleNameAttribute(prop2.GetAttributes(),
                    expectedTupleNamesAttribute: true,
                    expectedElementNames: expectedTupleNames);
 
                // public (int e1, int e2) this[(int e3, int e4) param]
                var indexer = (PropertySymbol)_derivedClass.GetMember("this[]");
                expectedTupleNames = new[] { "e1", "e2" };
                ValidateTupleNameAttribute(indexer.GetAttributes(),
                    expectedTupleNamesAttribute: true,
                    expectedElementNames: expectedTupleNames);
                expectedTupleNames = new[] { "e3", "e4" };
                ValidateTupleNameAttribute(indexer.Parameters.Single().GetAttributes(),
                    expectedTupleNamesAttribute: true,
                    expectedElementNames: expectedTupleNames);
            }
 
            private void ValidateTupleNameAttribute(
                ImmutableArray<CSharpAttributeData> attributes,
                bool expectedTupleNamesAttribute,
                string[] expectedElementNames = null)
            {
                var synthesizedTupleElementNamesAttr = attributes.Where(attr => string.Equals(attr.AttributeClass.Name, "TupleElementNamesAttribute", StringComparison.Ordinal));
 
                if (!expectedTupleNamesAttribute)
                {
                    Assert.Empty(synthesizedTupleElementNamesAttr);
                    Assert.Null(expectedElementNames);
                }
                else
                {
                    var tupleAttr = synthesizedTupleElementNamesAttr.Single();
                    Assert.Equal("System.Runtime.CompilerServices.TupleElementNamesAttribute", tupleAttr.AttributeClass.ToTestDisplayString());
                    Assert.Equal("System.String[]", tupleAttr.AttributeConstructor.Parameters.Single().TypeWithAnnotations.ToTestDisplayString());
 
                    if (expectedElementNames == null)
                    {
                        Assert.True(tupleAttr.CommonConstructorArguments.IsEmpty);
                    }
                    else
                    {
                        var arg = tupleAttr.CommonConstructorArguments.Single();
                        Assert.Equal(TypedConstantKind.Array, arg.Kind);
                        var actualElementNames = arg.Values.SelectAsArray(TypedConstantString);
                        AssertEx.Equal(expectedElementNames, actualElementNames);
                    }
                }
            }
 
            private static string TypedConstantString(TypedConstant constant)
            {
                Assert.True(constant.Type.SpecialType == SpecialType.System_String);
                return (string)constant.Value;
            }
        }
 
        [Fact]
        public void TupleAttributeMissing()
        {
            var comp = CreateCompilationWithMscorlib40(
                s_tuplesTestSource + TestResources.NetFX.ValueTuple.tuplelib_cs,
                references: new[] { SystemCoreRef },
                options: TestOptions.ReleaseDll);
            comp.VerifyDiagnostics(
                // (8,31): 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?
                // public class Outer<T> : Base1<(int key, int val)>
                Diagnostic(ErrorCode.ERR_TupleElementNamesAttributeMissing, "(int key, int val)").WithArguments("System.Runtime.CompilerServices.TupleElementNamesAttribute").WithLocation(8, 31),
                // (16,42): 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?
                // public class Derived<T> : Outer<(int e1, (int e2, int e3) e4)>.Inner<
                Diagnostic(ErrorCode.ERR_TupleElementNamesAttributeMissing, "(int e2, int e3)").WithArguments("System.Runtime.CompilerServices.TupleElementNamesAttribute").WithLocation(16, 42),
                // (16,33): 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?
                // public class Derived<T> : Outer<(int e1, (int e2, int e3) e4)>.Inner<
                Diagnostic(ErrorCode.ERR_TupleElementNamesAttributeMissing, "(int e1, (int e2, int e3) e4)").WithArguments("System.Runtime.CompilerServices.TupleElementNamesAttribute").WithLocation(16, 33),
                // (17,11): 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?
                //     Outer<(int e5, int e6)>.Inner<(int e7, int e8)[], (int e9, int e10)>.InnerInner<int>[],
                Diagnostic(ErrorCode.ERR_TupleElementNamesAttributeMissing, "(int e5, int e6)").WithArguments("System.Runtime.CompilerServices.TupleElementNamesAttribute").WithLocation(17, 11),
                // (17,35): 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?
                //     Outer<(int e5, int e6)>.Inner<(int e7, int e8)[], (int e9, int e10)>.InnerInner<int>[],
                Diagnostic(ErrorCode.ERR_TupleElementNamesAttributeMissing, "(int e7, int e8)").WithArguments("System.Runtime.CompilerServices.TupleElementNamesAttribute").WithLocation(17, 35),
                // (17,55): 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?
                //     Outer<(int e5, int e6)>.Inner<(int e7, int e8)[], (int e9, int e10)>.InnerInner<int>[],
                Diagnostic(ErrorCode.ERR_TupleElementNamesAttributeMissing, "(int e9, int e10)").WithArguments("System.Runtime.CompilerServices.TupleElementNamesAttribute").WithLocation(17, 55),
                // (18,6): 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?
                //     ((int e11, int e12) e13, int e14)>
                Diagnostic(ErrorCode.ERR_TupleElementNamesAttributeMissing, "(int e11, int e12)").WithArguments("System.Runtime.CompilerServices.TupleElementNamesAttribute").WithLocation(18, 6),
                // (18,5): 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?
                //     ((int e11, int e12) e13, int e14)>
                Diagnostic(ErrorCode.ERR_TupleElementNamesAttributeMissing, "((int e11, int e12) e13, int e14)").WithArguments("System.Runtime.CompilerServices.TupleElementNamesAttribute").WithLocation(18, 5),
                // (19,18): 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?
                //     .InnerInner<((int e15, int e16) e17, (int e18, Base1<(int e19, int e20)> e21) e22)>
                Diagnostic(ErrorCode.ERR_TupleElementNamesAttributeMissing, "(int e15, int e16)").WithArguments("System.Runtime.CompilerServices.TupleElementNamesAttribute").WithLocation(19, 18),
                // (19,58): 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?
                //     .InnerInner<((int e15, int e16) e17, (int e18, Base1<(int e19, int e20)> e21) e22)>
                Diagnostic(ErrorCode.ERR_TupleElementNamesAttributeMissing, "(int e19, int e20)").WithArguments("System.Runtime.CompilerServices.TupleElementNamesAttribute").WithLocation(19, 58),
                // (19,42): 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?
                //     .InnerInner<((int e15, int e16) e17, (int e18, Base1<(int e19, int e20)> e21) e22)>
                Diagnostic(ErrorCode.ERR_TupleElementNamesAttributeMissing, "(int e18, Base1<(int e19, int e20)> e21)").WithArguments("System.Runtime.CompilerServices.TupleElementNamesAttribute").WithLocation(19, 42),
                // (19,17): 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?
                //     .InnerInner<((int e15, int e16) e17, (int e18, Base1<(int e19, int e20)> e21) e22)>
                Diagnostic(ErrorCode.ERR_TupleElementNamesAttributeMissing, "((int e15, int e16) e17, (int e18, Base1<(int e19, int e20)> e21) e22)").WithArguments("System.Runtime.CompilerServices.TupleElementNamesAttribute").WithLocation(19, 17),
                // (10,38): 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?
                //     public class Inner<U, V> : Base2<(int key2, int val2), V>
                Diagnostic(ErrorCode.ERR_TupleElementNamesAttributeMissing, "(int key2, int val2)").WithArguments("System.Runtime.CompilerServices.TupleElementNamesAttribute").WithLocation(10, 38),
                // (12,44): 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?
                //         public class InnerInner<W> : Base1<(int key3, int val3)> { }
                Diagnostic(ErrorCode.ERR_TupleElementNamesAttributeMissing, "(int key3, int val3)").WithArguments("System.Runtime.CompilerServices.TupleElementNamesAttribute").WithLocation(12, 44),
                // (72,47): 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?
                //                                    ValueTuple<(dynamic e2, dynamic e3)> e4)> Event1
                Diagnostic(ErrorCode.ERR_TupleElementNamesAttributeMissing, "(dynamic e2, dynamic e3)").WithArguments("System.Runtime.CompilerServices.TupleElementNamesAttribute").WithLocation(72, 47),
                // (71,35): 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?
                //     public static event Delegate1<(dynamic e1,
                Diagnostic(ErrorCode.ERR_TupleElementNamesAttributeMissing, @"(dynamic e1,
                                   ValueTuple<(dynamic e2, dynamic e3)> e4)").WithArguments("System.Runtime.CompilerServices.TupleElementNamesAttribute").WithLocation(71, 35),
                // (41,19): 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?
                //     public static (int e1, int e2) Method1() => (0, 0);
                Diagnostic(ErrorCode.ERR_TupleElementNamesAttributeMissing, "(int e1, int e2)").WithArguments("System.Runtime.CompilerServices.TupleElementNamesAttribute").WithLocation(41, 19),
                // (42,32): 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?
                //     public static void Method2((int e1, int e2) x) { }
                Diagnostic(ErrorCode.ERR_TupleElementNamesAttributeMissing, "(int e1, int e2)").WithArguments("System.Runtime.CompilerServices.TupleElementNamesAttribute").WithLocation(42, 32),
                // (43,44): 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?
                //     public static (int e1, int e2) Method3((int e3, int e4) x) => (0, 0);
                Diagnostic(ErrorCode.ERR_TupleElementNamesAttributeMissing, "(int e3, int e4)").WithArguments("System.Runtime.CompilerServices.TupleElementNamesAttribute").WithLocation(43, 44),
                // (43,19): 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?
                //     public static (int e1, int e2) Method3((int e3, int e4) x) => (0, 0);
                Diagnostic(ErrorCode.ERR_TupleElementNamesAttributeMissing, "(int e1, int e2)").WithArguments("System.Runtime.CompilerServices.TupleElementNamesAttribute").WithLocation(43, 19),
                // (44,48): 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?
                //     public static (int e1, int e2) Method4(ref (int e3, int e4) x) => x;
                Diagnostic(ErrorCode.ERR_TupleElementNamesAttributeMissing, "(int e3, int e4)").WithArguments("System.Runtime.CompilerServices.TupleElementNamesAttribute").WithLocation(44, 48),
                // (44,19): 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?
                //     public static (int e1, int e2) Method4(ref (int e3, int e4) x) => x;
                Diagnostic(ErrorCode.ERR_TupleElementNamesAttributeMissing, "(int e1, int e2)").WithArguments("System.Runtime.CompilerServices.TupleElementNamesAttribute").WithLocation(44, 19),
                // (53,19): 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?
                //     public static (int e1, int e2, int e3, int e4, int e5,
                Diagnostic(ErrorCode.ERR_TupleElementNamesAttributeMissing, @"(int e1, int e2, int e3, int e4, int e5,
                   int e6, int e7, int e8, int e9)").WithArguments("System.Runtime.CompilerServices.TupleElementNamesAttribute").WithLocation(53, 19),
                // (57,19): 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?
                //     public static (int e1, int e2) Prop1 => (0, 0);
                Diagnostic(ErrorCode.ERR_TupleElementNamesAttributeMissing, "(int e1, int e2)").WithArguments("System.Runtime.CompilerServices.TupleElementNamesAttribute").WithLocation(57, 19),
                // (58,19): 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?
                //     public static (int e1, int e2) Prop2 { get; set; }
                Diagnostic(ErrorCode.ERR_TupleElementNamesAttributeMissing, "(int e1, int e2)").WithArguments("System.Runtime.CompilerServices.TupleElementNamesAttribute").WithLocation(58, 19),
                // (60,34): 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?
                //     public (int e1, int e2) this[(int e3, int e4) param]
                Diagnostic(ErrorCode.ERR_TupleElementNamesAttributeMissing, "(int e3, int e4)").WithArguments("System.Runtime.CompilerServices.TupleElementNamesAttribute").WithLocation(60, 34),
                // (60,12): 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?
                //     public (int e1, int e2) this[(int e3, int e4) param]
                Diagnostic(ErrorCode.ERR_TupleElementNamesAttributeMissing, "(int e1, int e2)").WithArguments("System.Runtime.CompilerServices.TupleElementNamesAttribute").WithLocation(60, 12),
                // (68,14): 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?
                //             ((dynamic e1, dynamic e2, object e3) e4, dynamic e5),
                Diagnostic(ErrorCode.ERR_TupleElementNamesAttributeMissing, "(dynamic e1, dynamic e2, object e3)").WithArguments("System.Runtime.CompilerServices.TupleElementNamesAttribute").WithLocation(68, 14),
                // (68,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?
                //             ((dynamic e1, dynamic e2, object e3) e4, dynamic e5),
                Diagnostic(ErrorCode.ERR_TupleElementNamesAttributeMissing, "((dynamic e1, dynamic e2, object e3) e4, dynamic e5)").WithArguments("System.Runtime.CompilerServices.TupleElementNamesAttribute").WithLocation(68, 13),
                // (22,19): 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?
                //     public static (int e1, int e2) Field2;
                Diagnostic(ErrorCode.ERR_TupleElementNamesAttributeMissing, "(int e1, int e2)").WithArguments("System.Runtime.CompilerServices.TupleElementNamesAttribute").WithLocation(22, 19),
                // (23,34): 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?
                //     public static Base1<(int e1, (int e2, int e3) e4)> Field3;
                Diagnostic(ErrorCode.ERR_TupleElementNamesAttributeMissing, "(int e2, int e3)").WithArguments("System.Runtime.CompilerServices.TupleElementNamesAttribute").WithLocation(23, 34),
                // (23,25): 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?
                //     public static Base1<(int e1, (int e2, int e3) e4)> Field3;
                Diagnostic(ErrorCode.ERR_TupleElementNamesAttributeMissing, "(int e1, (int e2, int e3) e4)").WithArguments("System.Runtime.CompilerServices.TupleElementNamesAttribute").WithLocation(23, 25),
                // (25,36): 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?
                //     public static ValueTuple<Base1<(int e1, (int, (dynamic, dynamic)) e2)>, int> Field4;
                Diagnostic(ErrorCode.ERR_TupleElementNamesAttributeMissing, "(int e1, (int, (dynamic, dynamic)) e2)").WithArguments("System.Runtime.CompilerServices.TupleElementNamesAttribute").WithLocation(25, 36),
                // (27,25): 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?
                //     public static Outer<(object e1, dynamic e2)>
                Diagnostic(ErrorCode.ERR_TupleElementNamesAttributeMissing, "(object e1, dynamic e2)").WithArguments("System.Runtime.CompilerServices.TupleElementNamesAttribute").WithLocation(27, 25),
                // (28,16): 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?
                //         .Inner<(dynamic e3, object e4),
                Diagnostic(ErrorCode.ERR_TupleElementNamesAttributeMissing, "(dynamic e3, object e4)").WithArguments("System.Runtime.CompilerServices.TupleElementNamesAttribute").WithLocation(28, 16),
                // (36,19): 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?
                //     public static (int e1, int e2, int e3, int e4, int e5,
                Diagnostic(ErrorCode.ERR_TupleElementNamesAttributeMissing, @"(int e1, int e2, int e3, int e4, int e5,
                   int e6, int e7, int e8, int e9)").WithArguments("System.Runtime.CompilerServices.TupleElementNamesAttribute").WithLocation(36, 19),
                // (38,25): 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?
                //     public static Base1<(int e1, int e2, int e3, int e4, int e5,
                Diagnostic(ErrorCode.ERR_TupleElementNamesAttributeMissing, @"(int e1, int e2, int e3, int e4, int e5,
                         int e6, int e7, int e8, int e9)").WithArguments("System.Runtime.CompilerServices.TupleElementNamesAttribute").WithLocation(38, 25),
                // (21,19): 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?
                //     public static (int e1, int e2) Field1;
                Diagnostic(ErrorCode.ERR_TupleElementNamesAttributeMissing, "(int e1, int e2)").WithArguments("System.Runtime.CompilerServices.TupleElementNamesAttribute").WithLocation(21, 19));
        }
 
        [Fact]
        public void ExplicitTupleNamesAttribute()
        {
            var text = @"
using System;
using System.Runtime.CompilerServices;
 
[TupleElementNames(new[] { ""a"", ""b"" })]
public class C
{
    [TupleElementNames(new string[] { null, null })]
    public ValueTuple<int, int> Field1;
 
    [TupleElementNames(new[] { ""x"", ""y"" })]
    public ValueTuple<int, int> Prop1;
 
    [return: TupleElementNames(new string[] { null, null })]
    public ValueTuple<int, int> M([TupleElementNames(new string[] { null})] ValueTuple x) => (0, 0);
 
    public delegate void Delegate1<T>(object sender,
        [TupleElementNames(new[] { ""x"" })]ValueTuple<T> args);
 
    [TupleElementNames(new[] { ""y"" })]
    public event Delegate1<ValueTuple<int>> Event1
    {
        add { }
        remove { }
    }
 
    [TupleElementNames(new[] { ""a"", ""b"" })]
    public (int x, int y) this[[TupleElementNames](int a, int b) t] => t;
}
 
[TupleElementNames(new[] { ""a"", ""b"" })]
public struct S
{
}";
            var comp = CreateCompilationWithMscorlib40(text, references: s_attributeRefs);
            comp.VerifyDiagnostics(
                // (5,2): error CS8138: Cannot reference 'System.Runtime.CompilerServices.TupleElementNamesAttribute' explicitly. Use the tuple syntax to define tuple names.
                // [TupleElementNames(new[] { "a", "b" })]
                Diagnostic(ErrorCode.ERR_ExplicitTupleElementNamesAttribute, @"TupleElementNames(new[] { ""a"", ""b"" })").WithLocation(5, 2),
                // (31,2): error CS8138: Cannot reference 'System.Runtime.CompilerServices.TupleElementNamesAttribute' explicitly. Use the tuple syntax to define tuple names.
                // [TupleElementNames(new[] { "a", "b" })]
                Diagnostic(ErrorCode.ERR_ExplicitTupleElementNamesAttribute, @"TupleElementNames(new[] { ""a"", ""b"" })").WithLocation(31, 2),
                // (18,10): error CS8138: Cannot reference 'System.Runtime.CompilerServices.TupleElementNamesAttribute' explicitly. Use the tuple syntax to define tuple names.
                //         [TupleElementNames(new[] { "x" })]ValueTuple<T> args);
                Diagnostic(ErrorCode.ERR_ExplicitTupleElementNamesAttribute, @"TupleElementNames(new[] { ""x"" })").WithLocation(18, 10),
                // (11,6): error CS8138: Cannot reference 'System.Runtime.CompilerServices.TupleElementNamesAttribute' explicitly. Use the tuple syntax to define tuple names.
                //     [TupleElementNames(new[] { "x", "y" })]
                Diagnostic(ErrorCode.ERR_ExplicitTupleElementNamesAttribute, @"TupleElementNames(new[] { ""x"", ""y"" })").WithLocation(11, 6),
                // (14,14): error CS8138: Cannot reference 'System.Runtime.CompilerServices.TupleElementNamesAttribute' explicitly. Use the tuple syntax to define tuple names.
                //     [return: TupleElementNames(new string[] { null, null })]
                Diagnostic(ErrorCode.ERR_ExplicitTupleElementNamesAttribute, "TupleElementNames(new string[] { null, null })").WithLocation(14, 14),
                // (15,36): error CS8138: Cannot reference 'System.Runtime.CompilerServices.TupleElementNamesAttribute' explicitly. Use the tuple syntax to define tuple names.
                //     public ValueTuple<int, int> M([TupleElementNames(new string[] { null})] ValueTuple x) => (0, 0);
                Diagnostic(ErrorCode.ERR_ExplicitTupleElementNamesAttribute, "TupleElementNames(new string[] { null})").WithLocation(15, 36),
                // (20,6): error CS8138: Cannot reference 'System.Runtime.CompilerServices.TupleElementNamesAttribute' explicitly. Use the tuple syntax to define tuple names.
                //     [TupleElementNames(new[] { "y" })]
                Diagnostic(ErrorCode.ERR_ExplicitTupleElementNamesAttribute, @"TupleElementNames(new[] { ""y"" })").WithLocation(20, 6),
                // (27,6): error CS8138: Cannot reference 'System.Runtime.CompilerServices.TupleElementNamesAttribute' explicitly. Use the tuple syntax to define tuple names.
                //     [TupleElementNames(new[] { "a", "b" })]
                Diagnostic(ErrorCode.ERR_ExplicitTupleElementNamesAttribute, @"TupleElementNames(new[] { ""a"", ""b"" })").WithLocation(27, 6),
                // (28,33): error CS7036: There is no argument given that corresponds to the required parameter 'transformNames' of 'TupleElementNamesAttribute.TupleElementNamesAttribute(string[])'
                //     public (int x, int y) this[[TupleElementNames](int a, int b) t] => t;
                Diagnostic(ErrorCode.ERR_NoCorrespondingArgument, "TupleElementNames").WithArguments("transformNames", "System.Runtime.CompilerServices.TupleElementNamesAttribute.TupleElementNamesAttribute(string[])").WithLocation(28, 33),
                // (8,6): error CS8138: Cannot reference 'System.Runtime.CompilerServices.TupleElementNamesAttribute' explicitly. Use the tuple syntax to define tuple names.
                //     [TupleElementNames(new string[] { null, null })]
                Diagnostic(ErrorCode.ERR_ExplicitTupleElementNamesAttribute, "TupleElementNames(new string[] { null, null })").WithLocation(8, 6));
        }
 
        [Fact]
        [WorkItem(14844, "https://github.com/dotnet/roslyn/issues/14844")]
        public void AttributesOnTypeConstraints()
        {
            var src = @"
public interface I1<T> {}
 
public interface I2<T>
    where T : I1<(int a, int b)> {}
public interface I3<T>
    where T : I1<(int c, int d)> {}";
 
            Action<PEAssembly> validator = assembly =>
            {
                var reader = assembly.GetMetadataReader();
 
                Action<TypeDefinition, string[]> verifyTupleConstraint = (def, tupleNames) =>
                {
                    var typeParams = def.GetGenericParameters();
                    Assert.Equal(1, typeParams.Count);
                    var typeParam = reader.GetGenericParameter(typeParams[0]);
                    var constraintHandles = typeParam.GetConstraints();
                    Assert.Equal(1, constraintHandles.Count);
                    var constraint = reader.GetGenericParameterConstraint(constraintHandles[0]);
 
                    var attributes = constraint.GetCustomAttributes();
                    Assert.Equal(1, attributes.Count);
                    var attr = reader.GetCustomAttribute(attributes.Single());
 
                    // Verify that the attribute contains an array of matching tuple names
                    var argsReader = reader.GetBlobReader(attr.Value);
                    // Prolog
                    Assert.Equal(1, argsReader.ReadUInt16());
                    // Array size
                    Assert.Equal(tupleNames.Length, argsReader.ReadInt32());
 
                    foreach (var name in tupleNames)
                    {
                        Assert.Equal(name, argsReader.ReadSerializedString());
                    }
                };
 
                foreach (var typeHandle in reader.TypeDefinitions)
                {
                    var def = reader.GetTypeDefinition(typeHandle);
                    var name = reader.GetString(def.Name);
                    switch (name)
                    {
                        case "I1`1":
                        case "<Module>":
                            continue;
 
                        case "I2`1":
                            verifyTupleConstraint(def, new[] { "a", "b" });
                            break;
 
                        case "I3`1":
                            verifyTupleConstraint(def, new[] { "c", "d" });
                            break;
 
                        default:
                            throw TestExceptionUtilities.UnexpectedValue(name);
                    }
                }
            };
 
            void symbolValidator(ModuleSymbol m)
            {
                foreach (var t in m.GlobalNamespace.GetTypeMembers())
                {
                    switch (t.Name)
                    {
                        case "I1":
                        case "<Module>":
                            continue;
 
                        case "I2":
                            verifyTupleImpls(t, new[] { "a", "b" });
                            break;
 
                        case "I3":
                            verifyTupleImpls(t, new[] { "c", "d" });
                            break;
                    }
                }
                void verifyTupleImpls(NamedTypeSymbol t, string[] tupleNames)
                {
                    var typeParam = t.TypeParameters.Single();
                    var constraint = (NamedTypeSymbol)typeParam.ConstraintTypes().Single();
                    var typeArg = constraint.TypeArguments().Single();
                    Assert.True(typeArg.IsTupleType);
                    Assert.Equal(tupleNames, typeArg.TupleElementNames);
                }
            }
 
            CompileAndVerifyWithMscorlib40(src,
                references: new[] { ValueTupleRef, SystemRuntimeFacadeRef },
                parseOptions: TestOptions.Regular.WithNoRefSafetyRulesAttribute(),
                assemblyValidator: validator,
                symbolValidator: symbolValidator);
        }
 
        [Fact]
        [WorkItem(14844, "https://github.com/dotnet/roslyn/issues/14844")]
        public void AttributesOnInterfaceImplementations()
        {
            var src = @"
public interface I1<T> {}
 
public interface I2 : I1<(int a, int b)> {}
public interface I3 : I1<(int c, int d)> {}";
 
            Action<PEAssembly> validator = (assembly) =>
            {
                var reader = assembly.GetMetadataReader();
 
                Action<TypeDefinition, string[]> verifyTupleImpls = (def, tupleNames) =>
                {
                    var interfaceImpls = def.GetInterfaceImplementations();
                    Assert.Equal(1, interfaceImpls.Count);
                    var interfaceImpl = reader.GetInterfaceImplementation(interfaceImpls.Single());
 
                    var attributes = interfaceImpl.GetCustomAttributes();
                    Assert.Equal(1, attributes.Count);
                    var attr = reader.GetCustomAttribute(attributes.Single());
 
                    // Verify that the attribute contains an array of matching tuple names
                    var argsReader = reader.GetBlobReader(attr.Value);
                    // Prolog
                    Assert.Equal(1, argsReader.ReadUInt16());
                    // Array size
                    Assert.Equal(tupleNames.Length, argsReader.ReadInt32());
 
                    foreach (var name in tupleNames)
                    {
                        Assert.Equal(name, argsReader.ReadSerializedString());
                    }
                };
 
                foreach (var typeHandle in reader.TypeDefinitions)
                {
                    var def = reader.GetTypeDefinition(typeHandle);
                    var name = reader.GetString(def.Name);
                    switch (name)
                    {
                        case "I1`1":
                        case "<Module>":
                            continue;
 
                        case "I2":
                            verifyTupleImpls(def, new[] { "a", "b" });
                            break;
 
                        case "I3":
                            verifyTupleImpls(def, new[] { "c", "d" });
                            break;
 
                        default:
                            throw TestExceptionUtilities.UnexpectedValue(name);
                    }
                }
            };
 
            void symbolValidator(ModuleSymbol m)
            {
                foreach (var t in m.GlobalNamespace.GetTypeMembers())
                {
                    switch (t.Name)
                    {
                        case "I1":
                        case "<Module>":
                            continue;
 
                        case "I2":
                            VerifyTupleImpls(t, new[] { "a", "b" });
                            break;
 
                        case "I3":
                            VerifyTupleImpls(t, new[] { "c", "d" });
                            break;
 
                        default:
                            throw TestExceptionUtilities.UnexpectedValue(t.Name);
                    }
                }
 
                void VerifyTupleImpls(NamedTypeSymbol t, string[] tupleNames)
                {
                    var interfaceImpl = t.Interfaces().Single();
                    var typeArg = interfaceImpl.TypeArguments().Single();
                    Assert.True(typeArg.IsTupleType);
                    Assert.Equal(tupleNames, typeArg.TupleElementNames);
                }
            }
 
            CompileAndVerifyWithMscorlib40(src,
                references: new[] { ValueTupleRef, SystemRuntimeFacadeRef },
                parseOptions: TestOptions.Regular.WithNoRefSafetyRulesAttribute(),
                assemblyValidator: validator,
                symbolValidator: symbolValidator);
        }
    }
}