File: Semantics\GenericConstraintsTests.cs
Web Access
Project: src\src\Compilers\CSharp\Test\Semantic\Microsoft.CodeAnalysis.CSharp.Semantic.UnitTests.csproj (Microsoft.CodeAnalysis.CSharp.Semantic.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.Linq;
using Microsoft.CodeAnalysis.CSharp.Symbols;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.CSharp.Test.Utilities;
using Microsoft.CodeAnalysis.CSharp.UnitTests;
using Microsoft.CodeAnalysis.Test.Utilities;
using Roslyn.Test.Utilities;
using Xunit;
 
namespace Microsoft.CodeAnalysis.CSharp.UnitTests.Semantics
{
    public class GenericConstraintsTests : CompilingTestBase
    {
        [Fact]
        public void EnumConstraint_Compilation_Alone()
        {
            CreateCompilation(@"
public class Test<T> where T : System.Enum
{
}
public enum E1
{
    A
}
public class Test2
{
    public void M<U>() where U : System.Enum
    {
        var a = new Test<E1>();             // enum
        var b = new Test<int>();            // value type
        var c = new Test<string>();         // reference type
        var d = new Test<System.Enum>();    // Enum type
        var e = new Test<U>();              // Generic type constrained to enum
    }
}").VerifyDiagnostics(
                // (14,26): error CS0315: The type 'int' cannot be used as type parameter 'T' in the generic type or method 'Test<T>'. There is no boxing conversion from 'int' to 'System.Enum'.
                //         var b = new Test<int>();            // value type
                Diagnostic(ErrorCode.ERR_GenericConstraintNotSatisfiedValType, "int").WithArguments("Test<T>", "System.Enum", "T", "int").WithLocation(14, 26),
                // (15,26): error CS0311: The type 'string' cannot be used as type parameter 'T' in the generic type or method 'Test<T>'. There is no implicit reference conversion from 'string' to 'System.Enum'.
                //         var c = new Test<string>();         // reference type
                Diagnostic(ErrorCode.ERR_GenericConstraintNotSatisfiedRefType, "string").WithArguments("Test<T>", "System.Enum", "T", "string").WithLocation(15, 26));
        }
 
        [Fact]
        public void EnumConstraint_Compilation_ReferenceType()
        {
            CreateCompilation(@"
public class Test<T> where T : class, System.Enum
{
}
public enum E1
{
    A
}
public class Test2
{
    public void M<U>() where U : class, System.Enum
    {
        var a = new Test<E1>();             // enum
        var b = new Test<int>();            // value type
        var c = new Test<string>();         // reference type
        var d = new Test<System.Enum>();    // Enum type
        var e = new Test<U>();              // Generic type constrained to enum
    }
}").VerifyDiagnostics(
                // (13,26): error CS0452: The type 'E1' must be a reference type in order to use it as parameter 'T' in the generic type or method 'Test<T>'
                //         var a = new Test<E1>();             // enum
                Diagnostic(ErrorCode.ERR_RefConstraintNotSatisfied, "E1").WithArguments("Test<T>", "T", "E1").WithLocation(13, 26),
                // (14,26): error CS0452: The type 'int' must be a reference type in order to use it as parameter 'T' in the generic type or method 'Test<T>'
                //         var b = new Test<int>();            // value type
                Diagnostic(ErrorCode.ERR_RefConstraintNotSatisfied, "int").WithArguments("Test<T>", "T", "int").WithLocation(14, 26),
                // (15,26): error CS0311: The type 'string' cannot be used as type parameter 'T' in the generic type or method 'Test<T>'. There is no implicit reference conversion from 'string' to 'System.Enum'.
                //         var c = new Test<string>();         // reference type
                Diagnostic(ErrorCode.ERR_GenericConstraintNotSatisfiedRefType, "string").WithArguments("Test<T>", "System.Enum", "T", "string").WithLocation(15, 26));
        }
 
        [Fact]
        public void EnumConstraint_Compilation_Interface()
        {
            CreateCompilation(@"
public class Test<T> where T : System.Enum, System.IDisposable
{
}
public enum E1
{
    A
}
public class Test2
{
    public void M<U>() where U : System.IDisposable
    {
        var a = new Test<E1>();             // not disposable
        var b = new Test<U>();              // not enum
        var c = new Test<int>();            // neither disposable nor enum
    }
}").VerifyDiagnostics(
                // (13,26): error CS0315: The type 'E1' cannot be used as type parameter 'T' in the generic type or method 'Test<T>'. There is no boxing conversion from 'E1' to 'System.IDisposable'.
                //         var a = new Test<E1>();             // not disposable
                Diagnostic(ErrorCode.ERR_GenericConstraintNotSatisfiedValType, "E1").WithArguments("Test<T>", "System.IDisposable", "T", "E1").WithLocation(13, 26),
                // (14,26): error CS0314: The type 'U' cannot be used as type parameter 'T' in the generic type or method 'Test<T>'. There is no boxing conversion or type parameter conversion from 'U' to 'System.Enum'.
                //         var b = new Test<U>();              // not enum
                Diagnostic(ErrorCode.ERR_GenericConstraintNotSatisfiedTyVar, "U").WithArguments("Test<T>", "System.Enum", "T", "U").WithLocation(14, 26),
                // (15,26): error CS0315: The type 'int' cannot be used as type parameter 'T' in the generic type or method 'Test<T>'. There is no boxing conversion from 'int' to 'System.Enum'.
                //         var c = new Test<int>();            // neither disposable nor enum
                Diagnostic(ErrorCode.ERR_GenericConstraintNotSatisfiedValType, "int").WithArguments("Test<T>", "System.Enum", "T", "int").WithLocation(15, 26),
                // (15,26): error CS0315: The type 'int' cannot be used as type parameter 'T' in the generic type or method 'Test<T>'. There is no boxing conversion from 'int' to 'System.IDisposable'.
                //         var c = new Test<int>();            // neither disposable nor enum
                Diagnostic(ErrorCode.ERR_GenericConstraintNotSatisfiedValType, "int").WithArguments("Test<T>", "System.IDisposable", "T", "int").WithLocation(15, 26));
        }
 
        [Fact]
        public void EnumConstraint_Compilation_ValueType()
        {
            CreateCompilation(@"
public class Test<T> where T : struct, System.Enum
{
}
public enum E1
{
    A
}
public class Test2
{
    public void M<U>() where U : struct, System.Enum
    {
        var a = new Test<E1>();             // enum
        var b = new Test<int>();            // value type
        var c = new Test<string>();         // reference type
        var d = new Test<System.Enum>();    // Enum type
        var e = new Test<U>();              // Generic type constrained to enum
    }
}").VerifyDiagnostics(
                // (14,26): error CS0315: The type 'int' cannot be used as type parameter 'T' in the generic type or method 'Test<T>'. There is no boxing conversion from 'int' to 'System.Enum'.
                //         var b = new Test<int>();            // value type
                Diagnostic(ErrorCode.ERR_GenericConstraintNotSatisfiedValType, "int").WithArguments("Test<T>", "System.Enum", "T", "int").WithLocation(14, 26),
                // (15,26): error CS0453: The type 'string' must be a non-nullable value type in order to use it as parameter 'T' in the generic type or method 'Test<T>'
                //         var c = new Test<string>();         // reference type
                Diagnostic(ErrorCode.ERR_ValConstraintNotSatisfied, "string").WithArguments("Test<T>", "T", "string").WithLocation(15, 26),
                // (16,26): error CS0453: The type 'Enum' must be a non-nullable value type in order to use it as parameter 'T' in the generic type or method 'Test<T>'
                //         var d = new Test<System.Enum>();    // Enum type
                Diagnostic(ErrorCode.ERR_ValConstraintNotSatisfied, "System.Enum").WithArguments("Test<T>", "T", "System.Enum").WithLocation(16, 26));
        }
 
        [Fact]
        public void EnumConstraint_Compilation_Constructor()
        {
            CreateCompilation(@"
public class Test<T> where T : System.Enum, new()
{
}
public enum E1
{
    A
}
public class Test2
{
    public void M<U>() where U : System.Enum, new()
    {
        var a = new Test<E1>();             // enum
        var b = new Test<int>();            // value type
        var c = new Test<string>();         // reference type
        var d = new Test<System.Enum>();    // Enum type
        var e = new Test<U>();              // Generic type constrained to enum
    }
}").VerifyDiagnostics(
                // (14,26): error CS0315: The type 'int' cannot be used as type parameter 'T' in the generic type or method 'Test<T>'. There is no boxing conversion from 'int' to 'System.Enum'.
                //         var b = new Test<int>();            // value type
                Diagnostic(ErrorCode.ERR_GenericConstraintNotSatisfiedValType, "int").WithArguments("Test<T>", "System.Enum", "T", "int").WithLocation(14, 26),
                // (15,26): error CS0311: The type 'string' cannot be used as type parameter 'T' in the generic type or method 'Test<T>'. There is no implicit reference conversion from 'string' to 'System.Enum'.
                //         var c = new Test<string>();         // reference type
                Diagnostic(ErrorCode.ERR_GenericConstraintNotSatisfiedRefType, "string").WithArguments("Test<T>", "System.Enum", "T", "string").WithLocation(15, 26),
                // (15,26): error CS0310: 'string' must be a non-abstract type with a public parameterless constructor in order to use it as parameter 'T' in the generic type or method 'Test<T>'
                //         var c = new Test<string>();         // reference type
                Diagnostic(ErrorCode.ERR_NewConstraintNotSatisfied, "string").WithArguments("Test<T>", "T", "string").WithLocation(15, 26),
                // (16,26): error CS0310: 'Enum' must be a non-abstract type with a public parameterless constructor in order to use it as parameter 'T' in the generic type or method 'Test<T>'
                //         var d = new Test<System.Enum>();    // Enum type
                Diagnostic(ErrorCode.ERR_NewConstraintNotSatisfied, "System.Enum").WithArguments("Test<T>", "T", "System.Enum").WithLocation(16, 26));
        }
 
        [Fact]
        public void EnumConstraint_Reference_Alone()
        {
            var reference = CreateCompilation(@"
public class Test<T> where T : System.Enum
{
}"
                ).EmitToImageReference();
 
            var code = @"
public enum E1
{
    A
}
 
public class Test2
{
    public void M<U>() where U : System.Enum
    {
        var a = new Test<E1>();             // enum
        var b = new Test<int>();            // value type
        var c = new Test<string>();         // reference type
        var d = new Test<System.Enum>();    // Enum type
        var e = new Test<U>();              // Generic type constrained to enum
    }
}";
 
            CreateCompilation(code, references: new[] { reference }).VerifyDiagnostics(
                // (12,26): error CS0315: The type 'int' cannot be used as type parameter 'T' in the generic type or method 'Test<T>'. There is no boxing conversion from 'int' to 'System.Enum'.
                //         var b = new Test<int>();            // value type
                Diagnostic(ErrorCode.ERR_GenericConstraintNotSatisfiedValType, "int").WithArguments("Test<T>", "System.Enum", "T", "int").WithLocation(12, 26),
                // (13,26): error CS0311: The type 'string' cannot be used as type parameter 'T' in the generic type or method 'Test<T>'. There is no implicit reference conversion from 'string' to 'System.Enum'.
                //         var c = new Test<string>();         // reference type
                Diagnostic(ErrorCode.ERR_GenericConstraintNotSatisfiedRefType, "string").WithArguments("Test<T>", "System.Enum", "T", "string").WithLocation(13, 26));
        }
 
        [Fact]
        public void EnumConstraint_Reference_ReferenceType()
        {
            var reference = CreateCompilation(@"
public class Test<T> where T : class, System.Enum
{
}"
                ).EmitToImageReference();
 
            var code = @"
public enum E1
{
    A
}
 
public class Test2
{
    public void M<U>() where U : class, System.Enum
    {
        var a = new Test<E1>();             // enum
        var b = new Test<int>();            // value type
        var c = new Test<string>();         // reference type
        var d = new Test<System.Enum>();    // Enum type
        var e = new Test<U>();              // Generic type constrained to enum
    }
}";
 
            CreateCompilation(code, references: new[] { reference }).VerifyDiagnostics(
                // (11,26): error CS0452: The type 'E1' must be a reference type in order to use it as parameter 'T' in the generic type or method 'Test<T>'
                //         var a = new Test<E1>();             // enum
                Diagnostic(ErrorCode.ERR_RefConstraintNotSatisfied, "E1").WithArguments("Test<T>", "T", "E1").WithLocation(11, 26),
                // (12,26): error CS0452: The type 'int' must be a reference type in order to use it as parameter 'T' in the generic type or method 'Test<T>'
                //         var b = new Test<int>();            // value type
                Diagnostic(ErrorCode.ERR_RefConstraintNotSatisfied, "int").WithArguments("Test<T>", "T", "int").WithLocation(12, 26),
                // (13,26): error CS0311: The type 'string' cannot be used as type parameter 'T' in the generic type or method 'Test<T>'. There is no implicit reference conversion from 'string' to 'System.Enum'.
                //         var c = new Test<string>();         // reference type
                Diagnostic(ErrorCode.ERR_GenericConstraintNotSatisfiedRefType, "string").WithArguments("Test<T>", "System.Enum", "T", "string").WithLocation(13, 26));
        }
 
        [Fact]
        public void EnumConstraint_Reference_ValueType()
        {
            var reference = CreateCompilation(@"
public class Test<T> where T : struct, System.Enum
{
}"
                ).EmitToImageReference();
 
            var code = @"
public enum E1
{
    A
}
 
public class Test2
{
    public void M<U>() where U : struct, System.Enum
    {
        var a = new Test<E1>();             // enum
        var b = new Test<int>();            // value type
        var c = new Test<string>();         // reference type
        var d = new Test<System.Enum>();    // Enum type
        var e = new Test<U>();              // Generic type constrained to enum
    }
}";
 
            CreateCompilation(code, references: new[] { reference }).VerifyDiagnostics(
                // (12,26): error CS0315: The type 'int' cannot be used as type parameter 'T' in the generic type or method 'Test<T>'. There is no boxing conversion from 'int' to 'System.Enum'.
                //         var b = new Test<int>();            // value type
                Diagnostic(ErrorCode.ERR_GenericConstraintNotSatisfiedValType, "int").WithArguments("Test<T>", "System.Enum", "T", "int").WithLocation(12, 26),
                // (13,26): error CS0453: The type 'string' must be a non-nullable value type in order to use it as parameter 'T' in the generic type or method 'Test<T>'
                //         var c = new Test<string>();         // reference type
                Diagnostic(ErrorCode.ERR_ValConstraintNotSatisfied, "string").WithArguments("Test<T>", "T", "string").WithLocation(13, 26),
                // (14,26): error CS0453: The type 'Enum' must be a non-nullable value type in order to use it as parameter 'T' in the generic type or method 'Test<T>'
                //         var d = new Test<System.Enum>();    // Enum type
                Diagnostic(ErrorCode.ERR_ValConstraintNotSatisfied, "System.Enum").WithArguments("Test<T>", "T", "System.Enum").WithLocation(14, 26));
        }
 
        [Fact]
        public void EnumConstraint_Reference_Constructor()
        {
            var reference = CreateCompilation(@"
public class Test<T> where T : System.Enum, new()
{
}"
                ).EmitToImageReference();
 
            var code = @"
public enum E1
{
    A
}
 
public class Test2
{
    public void M<U>() where U : System.Enum, new()
    {
        var a = new Test<E1>();             // enum
        var b = new Test<int>();            // value type
        var c = new Test<string>();         // reference type
        var d = new Test<System.Enum>();    // Enum type
        var e = new Test<U>();              // Generic type constrained to enum
    }
}";
 
            CreateCompilation(code, references: new[] { reference }).VerifyDiagnostics(
                // (12,26): error CS0315: The type 'int' cannot be used as type parameter 'T' in the generic type or method 'Test<T>'. There is no boxing conversion from 'int' to 'System.Enum'.
                //         var b = new Test<int>();            // value type
                Diagnostic(ErrorCode.ERR_GenericConstraintNotSatisfiedValType, "int").WithArguments("Test<T>", "System.Enum", "T", "int").WithLocation(12, 26),
                // (13,26): error CS0311: The type 'string' cannot be used as type parameter 'T' in the generic type or method 'Test<T>'. There is no implicit reference conversion from 'string' to 'System.Enum'.
                //         var c = new Test<string>();         // reference type
                Diagnostic(ErrorCode.ERR_GenericConstraintNotSatisfiedRefType, "string").WithArguments("Test<T>", "System.Enum", "T", "string").WithLocation(13, 26),
                // (13,26): error CS0310: 'string' must be a non-abstract type with a public parameterless constructor in order to use it as parameter 'T' in the generic type or method 'Test<T>'
                //         var c = new Test<string>();         // reference type
                Diagnostic(ErrorCode.ERR_NewConstraintNotSatisfied, "string").WithArguments("Test<T>", "T", "string").WithLocation(13, 26),
                // (14,26): error CS0310: 'Enum' must be a non-abstract type with a public parameterless constructor in order to use it as parameter 'T' in the generic type or method 'Test<T>'
                //         var d = new Test<System.Enum>();    // Enum type
                Diagnostic(ErrorCode.ERR_NewConstraintNotSatisfied, "System.Enum").WithArguments("Test<T>", "T", "System.Enum").WithLocation(14, 26));
        }
 
        [Fact]
        public void EnumConstraint_Before_7_3()
        {
            var code = @"
public class Test<T> where T : System.Enum
{
}";
 
            var oldOptions = new CSharpParseOptions(LanguageVersion.CSharp7_2);
 
            CreateCompilation(code, parseOptions: oldOptions).VerifyDiagnostics(
                // (2,32): error CS8320: Feature 'enum generic type constraints' is not available in C# 7.2. Please use language version 7.3 or greater.
                // public class Test<T> where T : System.Enum
                Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7_2, "System.Enum").WithArguments("enum generic type constraints", "7.3").WithLocation(2, 32));
 
            var reference = CreateCompilation(code).EmitToImageReference();
 
            var legacyCode = @"
enum E
{
}
class Legacy
{
    void M()
    {
        var a = new Test<E>();          // valid
        var b = new Test<Legacy>();     // invalid
    }
}";
 
            CreateCompilation(legacyCode, parseOptions: oldOptions, references: new[] { reference }).VerifyDiagnostics(
                // (10,26): error CS0311: The type 'Legacy' cannot be used as type parameter 'T' in the generic type or method 'Test<T>'. There is no implicit reference conversion from 'Legacy' to 'System.Enum'.
                //         var b = new Test<Legacy>();     // invalid
                Diagnostic(ErrorCode.ERR_GenericConstraintNotSatisfiedRefType, "Legacy").WithArguments("Test<T>", "System.Enum", "T", "Legacy").WithLocation(10, 26));
        }
 
        [Theory]
        [InlineData("byte")]
        [InlineData("sbyte")]
        [InlineData("short")]
        [InlineData("ushort")]
        [InlineData("int")]
        [InlineData("uint")]
        [InlineData("long")]
        [InlineData("ulong")]
        public void EnumConstraint_DifferentBaseTypes(string type)
        {
            CreateCompilation($@"
public class Test<T> where T : System.Enum
{{
}}
public enum E1 : {type}
{{
    A
}}
public class Test2
{{
    public void M()
    {{
        var a = new Test<E1>();     // Valid
        var b = new Test<int>();    // Invalid
    }}
}}
").VerifyDiagnostics(
                // (14,26): error CS0315: The type 'int' cannot be used as type parameter 'T' in the generic type or method 'Test<T>'. There is no boxing conversion from 'int' to 'System.Enum'.
                //         var b = new Test<int>();    // Invalid
                Diagnostic(ErrorCode.ERR_GenericConstraintNotSatisfiedValType, "int").WithArguments("Test<T>", "System.Enum", "T", "int").WithLocation(14, 26));
        }
 
        [Fact]
        public void EnumConstraint_InheritanceChain()
        {
            CreateCompilation(@"
public enum E
{
    A
}
public class Test<T, U> where U : System.Enum, T
{
}
public class Test2
{
    public void M()
    {
        var a = new Test<Test2, E>();
 
        var b = new Test<E, E>();
        var c = new Test<System.Enum, System.Enum>();
 
        var d = new Test<E, System.Enum>();
        var e = new Test<System.Enum, E>();
    }
}").VerifyDiagnostics(
                // (13,33): error CS0315: The type 'E' cannot be used as type parameter 'U' in the generic type or method 'Test<T, U>'. There is no boxing conversion from 'E' to 'Test2'.
                //         var a = new Test<Test2, E>();
                Diagnostic(ErrorCode.ERR_GenericConstraintNotSatisfiedValType, "E").WithArguments("Test<T, U>", "Test2", "U", "E").WithLocation(13, 33),
                // (18,29): error CS0311: The type 'System.Enum' cannot be used as type parameter 'U' in the generic type or method 'Test<T, U>'. There is no implicit reference conversion from 'System.Enum' to 'E'.
                //         var d = new Test<E, System.Enum>();
                Diagnostic(ErrorCode.ERR_GenericConstraintNotSatisfiedRefType, "System.Enum").WithArguments("Test<T, U>", "E", "U", "System.Enum").WithLocation(18, 29));
        }
 
        [Fact]
        public void EnumConstraint_IsReflectedInSymbols_Alone()
        {
            var code = "public class Test<T> where T : System.Enum { }";
 
            Action<ModuleSymbol> validator = module =>
            {
                var typeParameter = module.GlobalNamespace.GetTypeMember("Test").TypeParameters.Single();
                Assert.False(typeParameter.IsValueType);
                Assert.False(typeParameter.IsReferenceType);
                Assert.False(typeParameter.HasValueTypeConstraint);
                Assert.False(typeParameter.HasReferenceTypeConstraint);
                Assert.Equal(SpecialType.System_Enum, typeParameter.ConstraintTypes().Single().SpecialType);
            };
 
            CompileAndVerify(code, sourceSymbolValidator: validator, symbolValidator: validator);
        }
 
        [Fact]
        public void EnumConstraint_IsReflectedInSymbols_ValueType()
        {
            var code = "public class Test<T> where T : struct, System.Enum { }";
 
            Action<ModuleSymbol> validator = module =>
            {
                var typeParameter = module.GlobalNamespace.GetTypeMember("Test").TypeParameters.Single();
                Assert.True(typeParameter.IsValueType);
                Assert.False(typeParameter.IsReferenceType);
                Assert.True(typeParameter.HasValueTypeConstraint);
                Assert.False(typeParameter.HasReferenceTypeConstraint);
                Assert.False(typeParameter.HasConstructorConstraint);
                Assert.Equal(SpecialType.System_Enum, typeParameter.ConstraintTypes().Single().SpecialType);
            };
 
            CompileAndVerify(code, sourceSymbolValidator: validator, symbolValidator: validator);
        }
 
        [Fact]
        public void EnumConstraint_IsReflectedInSymbols_ReferenceType()
        {
            var code = "public class Test<T> where T : class, System.Enum { }";
 
            Action<ModuleSymbol> validator = module =>
            {
                var typeParameter = module.GlobalNamespace.GetTypeMember("Test").TypeParameters.Single();
                Assert.False(typeParameter.IsValueType);
                Assert.True(typeParameter.IsReferenceType);
                Assert.False(typeParameter.HasValueTypeConstraint);
                Assert.True(typeParameter.HasReferenceTypeConstraint);
                Assert.False(typeParameter.HasConstructorConstraint);
                Assert.Equal(SpecialType.System_Enum, typeParameter.ConstraintTypes().Single().SpecialType);
            };
 
            CompileAndVerify(code, sourceSymbolValidator: validator, symbolValidator: validator);
        }
 
        [Fact]
        public void EnumConstraint_IsReflectedInSymbols_Constructor()
        {
            var code = "public class Test<T> where T : System.Enum, new() { }";
 
            Action<ModuleSymbol> validator = module =>
            {
                var typeParameter = module.GlobalNamespace.GetTypeMember("Test").TypeParameters.Single();
                Assert.False(typeParameter.IsValueType);
                Assert.False(typeParameter.IsReferenceType);
                Assert.False(typeParameter.HasValueTypeConstraint);
                Assert.False(typeParameter.HasReferenceTypeConstraint);
                Assert.True(typeParameter.HasConstructorConstraint);
                Assert.Equal(SpecialType.System_Enum, typeParameter.ConstraintTypes().Single().SpecialType);
            };
 
            CompileAndVerify(code, sourceSymbolValidator: validator, symbolValidator: validator);
        }
 
        [Fact]
        public void EnumConstraint_EnforcedInInheritanceChain_Downwards_Source()
        {
            CreateCompilation(@"
public abstract class A
{
    public abstract void M<T>() where T : System.Enum;
}
public class B : A
{
    public override void M<T>() { }
 
    public void Test()
    {
        this.M<int>();
        this.M<E>();
    }
}
public enum E
{
}").VerifyDiagnostics(
                // (12,14): error CS0315: The type 'int' cannot be used as type parameter 'T' in the generic type or method 'B.M<T>()'. There is no boxing conversion from 'int' to 'System.Enum'.
                //         this.M<int>();
                Diagnostic(ErrorCode.ERR_GenericConstraintNotSatisfiedValType, "M<int>").WithArguments("B.M<T>()", "System.Enum", "T", "int").WithLocation(12, 14)
                );
        }
 
        [Fact]
        public void EnumConstraint_EnforcedInInheritanceChain_Downwards_Reference()
        {
            var reference = CreateCompilation(@"
public abstract class A
{
    public abstract void M<T>() where T : System.Enum;
}").EmitToImageReference();
 
            CreateCompilation(@"
public class B : A
{
    public override void M<T>() { }
 
    public void Test()
    {
        this.M<int>();
        this.M<E>();
    }
}
public enum E
{
}", references: new[] { reference }).VerifyDiagnostics(
                // (8,14): error CS0315: The type 'int' cannot be used as type parameter 'T' in the generic type or method 'B.M<T>()'. There is no boxing conversion from 'int' to 'System.Enum'.
                //         this.M<int>();
                Diagnostic(ErrorCode.ERR_GenericConstraintNotSatisfiedValType, "M<int>").WithArguments("B.M<T>()", "System.Enum", "T", "int").WithLocation(8, 14)
                );
        }
 
        [Fact]
        public void EnumConstraint_EnforcedInInheritanceChain_Upwards_Source()
        {
            CreateCompilation(@"
public abstract class A
{
    public abstract void M<T>();
}
public class B : A
{
    public override void M<T>() where T : System.Enum { }
}").VerifyDiagnostics(
                // (8,43): error CS0460: Constraints for override and explicit interface implementation methods are inherited from the base method, so they cannot be specified directly, except for either a 'class', or a 'struct' constraint.
                //     public override void M<T>() where T : System.Enum { }
                Diagnostic(ErrorCode.ERR_OverrideWithConstraints, "System.Enum").WithLocation(8, 43));
        }
 
        [Fact]
        public void EnumConstraint_EnforcedInInheritanceChain_Upwards_Reference()
        {
            var reference = CreateCompilation(@"
public abstract class A
{
    public abstract void M<T>();
}").EmitToImageReference();
 
            CreateCompilation(@"
public class B : A
{
    public override void M<T>() where T : System.Enum { }
}", references: new[] { reference }).VerifyDiagnostics(
                // (4,43): error CS0460: Constraints for override and explicit interface implementation methods are inherited from the base method, so they cannot be specified directly, except for either a 'class', or a 'struct' constraint.
                //     public override void M<T>() where T : System.Enum { }
                Diagnostic(ErrorCode.ERR_OverrideWithConstraints, "System.Enum").WithLocation(4, 43));
        }
 
        [Fact]
        public void EnumConstraint_ResolveParentConstraints()
        {
            var comp = CreateCompilation(@"
public enum MyEnum
{
}
public abstract class A<T>
{
    public abstract void F<U>() where U : System.Enum, T;
}
public class B : A<MyEnum>
{
    public override void F<U>() { }
}");
 
            Action<ModuleSymbol> validator = module =>
            {
                var method = module.GlobalNamespace.GetTypeMember("B").GetMethod("F");
                var constraintTypeNames = method.TypeParameters.Single().ConstraintTypes().Select(type => type.ToTestDisplayString());
 
                AssertEx.SetEqual(new[] { "System.Enum", "MyEnum" }, constraintTypeNames);
            };
 
            CompileAndVerify(comp, sourceSymbolValidator: validator, symbolValidator: validator);
        }
 
        [Fact]
        public void EnumConstraint_TypeNotAvailable()
        {
            CreateEmptyCompilation(@"
namespace System
{
    public class Object {}
    public class Void {}
}
public class Test<T> where T : System.Enum
{
}").VerifyDiagnostics(
                // (7,39): error CS0234: The type or namespace name 'Enum' does not exist in the namespace 'System' (are you missing an assembly reference?)
                // public class Test<T> where T : System.Enum
                Diagnostic(ErrorCode.ERR_DottedTypeNameNotFoundInNS, "Enum").WithArguments("Enum", "System").WithLocation(7, 39));
        }
 
        [Fact]
        public void EnumConstraint_BindingToMethods()
        {
            var code = @"
enum A : short { a }
enum B : uint { b }
class Test
{
    public static void Main()
    {
        Print(A.a);
        Print(B.b);
    }
    static void Print<T>(T obj) where T : System.Enum
    {
        System.Console.WriteLine(obj.GetTypeCode());
    }
}";
 
            CompileAndVerify(code, expectedOutput: @"
Int16
UInt32");
        }
 
        [Fact]
        public void EnumConstraint_InheritingFromEnum()
        {
            var code = @"
public class Child : System.Enum
{
}
 
public enum E
{
    A
}
 
public class Test
{
    public void M<T>(T arg) where T : System.Enum
    {
    }
 
    public void N()
    {
        M(E.A);             // valid
        M(new Child());     // invalid
    }
}";
 
            CreateCompilation(code).VerifyDiagnostics(
                // (2,22): error CS0644: 'Child' cannot derive from special class 'Enum'
                // public class Child : System.Enum
                Diagnostic(ErrorCode.ERR_DeriveFromEnumOrValueType, "System.Enum").WithArguments("Child", "System.Enum").WithLocation(2, 22),
                // (20,9): error CS0311: The type 'Child' cannot be used as type parameter 'T' in the generic type or method 'Test.M<T>(T)'. There is no implicit reference conversion from 'Child' to 'System.Enum'.
                //         M(new Child());     // invalid
                Diagnostic(ErrorCode.ERR_GenericConstraintNotSatisfiedRefType, "M").WithArguments("Test.M<T>(T)", "System.Enum", "T", "Child").WithLocation(20, 9));
        }
 
        [Fact]
        public void DelegateConstraint_Compilation_Alone()
        {
            CreateCompilation(@"
public class Test<T> where T : System.Delegate
{
}
public delegate void D1();
public class Test2
{
    public void M<U>() where U : System.Delegate
    {
        var a = new Test<D1>();             // delegate
        var b = new Test<int>();            // value type
        var c = new Test<string>();         // reference type
        var d = new Test<U>();              // delegate type
    }
}").VerifyDiagnostics(
                // (11,26): error CS0315: The type 'int' cannot be used as type parameter 'T' in the generic type or method 'Test<T>'. There is no boxing conversion from 'int' to 'System.Delegate'.
                //         var b = new Test<int>();            // value type
                Diagnostic(ErrorCode.ERR_GenericConstraintNotSatisfiedValType, "int").WithArguments("Test<T>", "System.Delegate", "T", "int").WithLocation(11, 26),
                // (12,26): error CS0311: The type 'string' cannot be used as type parameter 'T' in the generic type or method 'Test<T>'. There is no implicit reference conversion from 'string' to 'System.Delegate'.
                //         var c = new Test<string>();         // reference type
                Diagnostic(ErrorCode.ERR_GenericConstraintNotSatisfiedRefType, "string").WithArguments("Test<T>", "System.Delegate", "T", "string").WithLocation(12, 26));
        }
 
        [Fact]
        public void DelegateConstraint_Compilation_ReferenceType()
        {
            CreateCompilation(@"
public class Test<T> where T : class, System.Delegate
{
}
public delegate void D1();
public class Test2
{
    public void M<U>() where U : class, System.Delegate
    {
        var a = new Test<D1>();             // delegate
        var b = new Test<int>();            // value type
        var c = new Test<string>();         // reference type
        var d = new Test<U>();              // delegate type
    }
}").VerifyDiagnostics(
                // (11,26): error CS0452: The type 'int' must be a reference type in order to use it as parameter 'T' in the generic type or method 'Test<T>'
                //         var b = new Test<int>();            // value type
                Diagnostic(ErrorCode.ERR_RefConstraintNotSatisfied, "int").WithArguments("Test<T>", "T", "int").WithLocation(11, 26),
                // (12,26): error CS0311: The type 'string' cannot be used as type parameter 'T' in the generic type or method 'Test<T>'. There is no implicit reference conversion from 'string' to 'System.Delegate'.
                //         var c = new Test<string>();         // reference type
                Diagnostic(ErrorCode.ERR_GenericConstraintNotSatisfiedRefType, "string").WithArguments("Test<T>", "System.Delegate", "T", "string").WithLocation(12, 26));
        }
 
        [Fact]
        public void DelegateConstraint_Compilation_ValueType()
        {
            CreateCompilation(@"
public class Test<T> where T : struct, System.Delegate
{
}").VerifyDiagnostics(
                // (2,40): error CS0450: 'Delegate': cannot specify both a constraint class and the 'class' or 'struct' constraint
                // public class Test<T> where T : struct, System.Delegate
                Diagnostic(ErrorCode.ERR_RefValBoundWithClass, "System.Delegate").WithArguments("System.Delegate").WithLocation(2, 40)
            );
        }
 
        [Fact]
        public void DelegateConstraint_Compilation_Constructor()
        {
            CreateCompilation(@"
public class Test<T> where T : System.Delegate, new()
{
}
public delegate void D1();
public class Test2
{
    public void M<U>() where U : System.Delegate, new()
    {
        var a = new Test<D1>();             // delegate
        var b = new Test<int>();            // value type
        var c = new Test<string>();         // reference type
        var d = new Test<U>();              // delegate type
    }
}").VerifyDiagnostics(
                // (10,26): error CS0310: 'D1' must be a non-abstract type with a public parameterless constructor in order to use it as parameter 'T' in the generic type or method 'Test<T>'
                //         var a = new Test<D1>();             // delegate
                Diagnostic(ErrorCode.ERR_NewConstraintNotSatisfied, "D1").WithArguments("Test<T>", "T", "D1").WithLocation(10, 26),
                // (11,26): error CS0315: The type 'int' cannot be used as type parameter 'T' in the generic type or method 'Test<T>'. There is no boxing conversion from 'int' to 'System.Delegate'.
                //         var b = new Test<int>();            // value type
                Diagnostic(ErrorCode.ERR_GenericConstraintNotSatisfiedValType, "int").WithArguments("Test<T>", "System.Delegate", "T", "int").WithLocation(11, 26),
                // (12,26): error CS0311: The type 'string' cannot be used as type parameter 'T' in the generic type or method 'Test<T>'. There is no implicit reference conversion from 'string' to 'System.Delegate'.
                //         var c = new Test<string>();         // reference type
                Diagnostic(ErrorCode.ERR_GenericConstraintNotSatisfiedRefType, "string").WithArguments("Test<T>", "System.Delegate", "T", "string").WithLocation(12, 26),
                // (12,26): error CS0310: 'string' must be a non-abstract type with a public parameterless constructor in order to use it as parameter 'T' in the generic type or method 'Test<T>'
                //         var c = new Test<string>();         // reference type
                Diagnostic(ErrorCode.ERR_NewConstraintNotSatisfied, "string").WithArguments("Test<T>", "T", "string").WithLocation(12, 26));
        }
 
        [Fact]
        public void DelegateConstraint_Reference_Alone()
        {
            var reference = CreateCompilation(@"
public class Test<T> where T : System.Delegate
{
}").EmitToImageReference();
 
            CreateCompilation(@"
public delegate void D1();
public class Test2
{
    public void M<U>() where U : System.Delegate
    {
        var a = new Test<D1>();             // delegate
        var b = new Test<int>();            // value type
        var c = new Test<string>();         // reference type
        var d = new Test<U>();              // delegate type
    }
}", references: new[] { reference }).VerifyDiagnostics(
                // (8,26): error CS0315: The type 'int' cannot be used as type parameter 'T' in the generic type or method 'Test<T>'. There is no boxing conversion from 'int' to 'System.Delegate'.
                //         var b = new Test<int>();            // value type
                Diagnostic(ErrorCode.ERR_GenericConstraintNotSatisfiedValType, "int").WithArguments("Test<T>", "System.Delegate", "T", "int").WithLocation(8, 26),
                // (9,26): error CS0311: The type 'string' cannot be used as type parameter 'T' in the generic type or method 'Test<T>'. There is no implicit reference conversion from 'string' to 'System.Delegate'.
                //         var c = new Test<string>();         // reference type
                Diagnostic(ErrorCode.ERR_GenericConstraintNotSatisfiedRefType, "string").WithArguments("Test<T>", "System.Delegate", "T", "string").WithLocation(9, 26));
        }
 
        [Fact]
        public void DelegateConstraint_Reference_ReferenceType()
        {
            var reference = CreateCompilation(@"
public class Test<T> where T : class, System.Delegate
{
}").EmitToImageReference();
 
            CreateCompilation(@"
public delegate void D1();
public class Test2
{
    public void M<U>() where U : class, System.Delegate
    {
        var a = new Test<D1>();             // delegate
        var b = new Test<int>();            // value type
        var c = new Test<string>();         // reference type
        var d = new Test<U>();              // delegate type
    }
}", references: new[] { reference }).VerifyDiagnostics(
                // (8,26): error CS0452: The type 'int' must be a reference type in order to use it as parameter 'T' in the generic type or method 'Test<T>'
                //         var b = new Test<int>();            // value type
                Diagnostic(ErrorCode.ERR_RefConstraintNotSatisfied, "int").WithArguments("Test<T>", "T", "int").WithLocation(8, 26),
                // (9,26): error CS0311: The type 'string' cannot be used as type parameter 'T' in the generic type or method 'Test<T>'. There is no implicit reference conversion from 'string' to 'System.Delegate'.
                //         var c = new Test<string>();         // reference type
                Diagnostic(ErrorCode.ERR_GenericConstraintNotSatisfiedRefType, "string").WithArguments("Test<T>", "System.Delegate", "T", "string").WithLocation(9, 26));
        }
 
        [Fact]
        public void DelegateConstraint_Reference_Constructor()
        {
            var reference = CreateCompilation(@"
public class Test<T> where T : System.Delegate, new()
{
}").EmitToImageReference();
 
            CreateCompilation(@"
public delegate void D1();
public class Test2
{
    public void M<U>() where U : System.Delegate, new()
    {
        var a = new Test<D1>();             // delegate
        var b = new Test<int>();            // value type
        var c = new Test<string>();         // reference type
        var d = new Test<U>();              // delegate type
    }
}", references: new[] { reference }).VerifyDiagnostics(
                // (7,26): error CS0310: 'D1' must be a non-abstract type with a public parameterless constructor in order to use it as parameter 'T' in the generic type or method 'Test<T>'
                //         var a = new Test<D1>();             // delegate
                Diagnostic(ErrorCode.ERR_NewConstraintNotSatisfied, "D1").WithArguments("Test<T>", "T", "D1").WithLocation(7, 26),
                // (8,26): error CS0315: The type 'int' cannot be used as type parameter 'T' in the generic type or method 'Test<T>'. There is no boxing conversion from 'int' to 'System.Delegate'.
                //         var b = new Test<int>();            // value type
                Diagnostic(ErrorCode.ERR_GenericConstraintNotSatisfiedValType, "int").WithArguments("Test<T>", "System.Delegate", "T", "int").WithLocation(8, 26),
                // (9,26): error CS0311: The type 'string' cannot be used as type parameter 'T' in the generic type or method 'Test<T>'. There is no implicit reference conversion from 'string' to 'System.Delegate'.
                //         var c = new Test<string>();         // reference type
                Diagnostic(ErrorCode.ERR_GenericConstraintNotSatisfiedRefType, "string").WithArguments("Test<T>", "System.Delegate", "T", "string").WithLocation(9, 26),
                // (9,26): error CS0310: 'string' must be a non-abstract type with a public parameterless constructor in order to use it as parameter 'T' in the generic type or method 'Test<T>'
                //         var c = new Test<string>();         // reference type
                Diagnostic(ErrorCode.ERR_NewConstraintNotSatisfied, "string").WithArguments("Test<T>", "T", "string").WithLocation(9, 26));
        }
 
        [Fact]
        public void DelegateConstraint_Before_7_3()
        {
            var code = @"
public class Test<T> where T : System.Delegate
{
}";
            var oldOptions = new CSharpParseOptions(LanguageVersion.CSharp7_2);
 
            CreateCompilation(code, parseOptions: oldOptions).VerifyDiagnostics(
                // (2,32): error CS8320: Feature 'delegate generic type constraints' is not available in C# 7.2. Please use language version 7.3 or greater.
                // public class Test<T> where T : System.Delegate
                Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7_2, "System.Delegate").WithArguments("delegate generic type constraints", "7.3").WithLocation(2, 32));
 
            var reference = CreateCompilation(code).EmitToImageReference();
 
            var legacyCode = @"
delegate void D();
 
class Legacy
{
    void M()
    {
        var a = new Test<D>();          // valid
        var b = new Test<Legacy>();     // invalid
    }
}";
 
            CreateCompilation(legacyCode, parseOptions: oldOptions, references: new[] { reference }).VerifyDiagnostics(
                // (9,26): error CS0311: The type 'Legacy' cannot be used as type parameter 'T' in the generic type or method 'Test<T>'. There is no implicit reference conversion from 'Legacy' to 'System.Delegate'.
                //         var b = new Test<Legacy>();     // invalid
                Diagnostic(ErrorCode.ERR_GenericConstraintNotSatisfiedRefType, "Legacy").WithArguments("Test<T>", "System.Delegate", "T", "Legacy").WithLocation(9, 26));
        }
 
        [Fact]
        public void DelegateConstraint_InheritanceChain()
        {
            CreateCompilation(@"
public delegate void D1();
public class Test<T, U> where U : System.Delegate, T
{
}
public class Test2
{
    public void M()
    {
        var a = new Test<Test2, D1>();
        
        var b = new Test<D1, D1>();
        var c = new Test<System.Delegate, System.Delegate>();
        var d = new Test<System.MulticastDelegate, System.Delegate>();
        var e = new Test<System.Delegate, System.MulticastDelegate>();
        var f = new Test<System.MulticastDelegate, System.MulticastDelegate>();
 
        var g = new Test<D1, System.Delegate>();
        var h = new Test<System.Delegate, D1>();
    }
}").VerifyDiagnostics(
                // (10,33): error CS0311: The type 'D1' cannot be used as type parameter 'U' in the generic type or method 'Test<T, U>'. There is no implicit reference conversion from 'D1' to 'Test2'.
                //         var a = new Test<Test2, D1>();
                Diagnostic(ErrorCode.ERR_GenericConstraintNotSatisfiedRefType, "D1").WithArguments("Test<T, U>", "Test2", "U", "D1").WithLocation(10, 33),
                // (14,52): error CS0311: The type 'System.Delegate' cannot be used as type parameter 'U' in the generic type or method 'Test<T, U>'. There is no implicit reference conversion from 'System.Delegate' to 'System.MulticastDelegate'.
                //         var d = new Test<System.MulticastDelegate, System.Delegate>();
                Diagnostic(ErrorCode.ERR_GenericConstraintNotSatisfiedRefType, "System.Delegate").WithArguments("Test<T, U>", "System.MulticastDelegate", "U", "System.Delegate").WithLocation(14, 52),
                // (18,30): error CS0311: The type 'System.Delegate' cannot be used as type parameter 'U' in the generic type or method 'Test<T, U>'. There is no implicit reference conversion from 'System.Delegate' to 'D1'.
                //         var g = new Test<D1, System.Delegate>();
                Diagnostic(ErrorCode.ERR_GenericConstraintNotSatisfiedRefType, "System.Delegate").WithArguments("Test<T, U>", "D1", "U", "System.Delegate").WithLocation(18, 30));
        }
 
        [Fact]
        public void DelegateConstraint_IsReflectedInSymbols_Alone()
        {
            var code = "public class Test<T> where T : System.Delegate { }";
 
            Action<ModuleSymbol> validator = module =>
            {
                var typeParameter = module.GlobalNamespace.GetTypeMember("Test").TypeParameters.Single();
                Assert.False(typeParameter.HasValueTypeConstraint);
                Assert.False(typeParameter.HasReferenceTypeConstraint);
                Assert.Equal(SpecialType.System_Delegate, typeParameter.ConstraintTypes().Single().SpecialType);
            };
 
            CompileAndVerify(code, sourceSymbolValidator: validator, symbolValidator: validator);
        }
 
        [Fact]
        public void DelegateConstraint_IsReflectedInSymbols_ValueType()
        {
            var compilation = CreateCompilation("public class Test<T> where T : struct, System.Delegate { }")
                    .VerifyDiagnostics(
                        // (1,40): error CS0450: 'Delegate': cannot specify both a constraint class and the 'class' or 'struct' constraint
                        // public class Test<T> where T : struct, System.Delegate { }
                        Diagnostic(ErrorCode.ERR_RefValBoundWithClass, "System.Delegate").WithArguments("System.Delegate").WithLocation(1, 40)
                    );
 
            var typeParameter = compilation.GlobalNamespace.GetTypeMember("Test").TypeParameters.Single();
 
            Assert.True(typeParameter.HasValueTypeConstraint);
            Assert.False(typeParameter.HasReferenceTypeConstraint);
            Assert.False(typeParameter.HasConstructorConstraint);
            Assert.Empty(typeParameter.ConstraintTypes());
        }
 
        [Fact]
        public void DelegateConstraint_IsReflectedInSymbols_ReferenceType()
        {
            var code = "public class Test<T> where T : class, System.Delegate { }";
 
            Action<ModuleSymbol> validator = module =>
            {
                var typeParameter = module.GlobalNamespace.GetTypeMember("Test").TypeParameters.Single();
                Assert.False(typeParameter.HasValueTypeConstraint);
                Assert.True(typeParameter.HasReferenceTypeConstraint);
                Assert.False(typeParameter.HasConstructorConstraint);
                Assert.Equal(SpecialType.System_Delegate, typeParameter.ConstraintTypes().Single().SpecialType);
            };
 
            CompileAndVerify(code, sourceSymbolValidator: validator, symbolValidator: validator);
        }
 
        [Fact]
        public void DelegateConstraint_IsReflectedInSymbols_Constructor()
        {
            var code = "public class Test<T> where T : System.Delegate, new() { }";
 
            Action<ModuleSymbol> validator = module =>
            {
                var typeParameter = module.GlobalNamespace.GetTypeMember("Test").TypeParameters.Single();
                Assert.False(typeParameter.HasValueTypeConstraint);
                Assert.False(typeParameter.HasReferenceTypeConstraint);
                Assert.True(typeParameter.HasConstructorConstraint);
                Assert.Equal(SpecialType.System_Delegate, typeParameter.ConstraintTypes().Single().SpecialType);
            };
 
            CompileAndVerify(code, sourceSymbolValidator: validator, symbolValidator: validator);
        }
 
        [Fact]
        public void DelegateConstraint_EnforcedInInheritanceChain_Downwards_Source()
        {
            CreateCompilation(@"
public abstract class A
{
    public abstract void M<T>() where T : System.Delegate;
}
public delegate void D1();
public class B : A
{
    public override void M<T>() { }
 
    public void Test()
    {
        this.M<int>();
        this.M<D1>();
    }
}").VerifyDiagnostics(
                // (13,14): error CS0315: The type 'int' cannot be used as type parameter 'T' in the generic type or method 'B.M<T>()'. There is no boxing conversion from 'int' to 'System.Delegate'.
                //         this.M<int>();
                Diagnostic(ErrorCode.ERR_GenericConstraintNotSatisfiedValType, "M<int>").WithArguments("B.M<T>()", "System.Delegate", "T", "int").WithLocation(13, 14)
                );
        }
 
        [Fact]
        public void DelegateConstraint_EnforcedInInheritanceChain_Downwards_Reference()
        {
            var reference = CreateCompilation(@"
public abstract class A
{
    public abstract void M<T>() where T : System.Delegate;
}").EmitToImageReference();
 
            CreateCompilation(@"
public delegate void D1();
public class B : A
{
    public override void M<T>() { }
 
    public void Test()
    {
        this.M<int>();
        this.M<D1>();
    }
}", references: new[] { reference }).VerifyDiagnostics(
                // (9,14): error CS0315: The type 'int' cannot be used as type parameter 'T' in the generic type or method 'B.M<T>()'. There is no boxing conversion from 'int' to 'System.Delegate'.
                //         this.M<int>();
                Diagnostic(ErrorCode.ERR_GenericConstraintNotSatisfiedValType, "M<int>").WithArguments("B.M<T>()", "System.Delegate", "T", "int").WithLocation(9, 14)
                );
        }
 
        [Fact]
        public void DelegateConstraint_EnforcedInInheritanceChain_Upwards_Source()
        {
            CreateCompilation(@"
public abstract class A
{
    public abstract void M<T>();
}
public class B : A
{
    public override void M<T>() where T : System.Delegate { }
}").VerifyDiagnostics(
                // (8,43): error CS0460: Constraints for override and explicit interface implementation methods are inherited from the base method, so they cannot be specified directly, except for either a 'class', or a 'struct' constraint.
                //     public override void M<T>() where T : System.Delegate { }
                Diagnostic(ErrorCode.ERR_OverrideWithConstraints, "System.Delegate").WithLocation(8, 43));
        }
 
        [Fact]
        public void DelegateConstraint_EnforcedInInheritanceChain_Upwards_Reference()
        {
            var reference = CreateCompilation(@"
public abstract class A
{
    public abstract void M<T>();
}").EmitToImageReference();
 
            CreateCompilation(@"
public class B : A
{
    public override void M<T>() where T : System.Delegate { }
}", references: new[] { reference }).VerifyDiagnostics(
                // (4,43): error CS0460: Constraints for override and explicit interface implementation methods are inherited from the base method, so they cannot be specified directly, except for either a 'class', or a 'struct' constraint.
                //     public override void M<T>() where T : System.Delegate { }
                Diagnostic(ErrorCode.ERR_OverrideWithConstraints, "System.Delegate").WithLocation(4, 43));
        }
 
        [Fact]
        public void DelegateConstraint_ResolveParentConstraints()
        {
            var comp = CreateCompilation(@"
public delegate void D1();
public abstract class A<T>
{
    public abstract void F<U>() where U : System.Delegate, T;
}
public class B : A<D1>
{
    public override void F<U>() { }
}");
 
            Action<ModuleSymbol> validator = module =>
            {
                var method = module.GlobalNamespace.GetTypeMember("B").GetMethod("F");
                var constraintTypeNames = method.TypeParameters.Single().ConstraintTypes().Select(type => type.ToTestDisplayString());
 
                AssertEx.SetEqual(new[] { "System.Delegate", "D1" }, constraintTypeNames);
            };
 
            CompileAndVerify(comp, sourceSymbolValidator: validator, symbolValidator: validator);
        }
 
        [Fact]
        public void DelegateConstraint_TypeNotAvailable()
        {
            CreateEmptyCompilation(@"
namespace System
{
    public class Object {}
    public class Void {}
}
public class Test<T> where T : System.Delegate
{
}").VerifyDiagnostics(
                // (7,39): error CS0234: The type or namespace name 'Delegate' does not exist in the namespace 'System' (are you missing an assembly reference?)
                // public class Test<T> where T : System.Delegate
                Diagnostic(ErrorCode.ERR_DottedTypeNameNotFoundInNS, "Delegate").WithArguments("Delegate", "System").WithLocation(7, 39));
        }
 
        [Fact]
        public void DelegateConstraint_BindingToMethods()
        {
            var code = @"
delegate void D1(int a, int b);
class TestClass
{
    public static void Impl(int a, int b)
    {
        System.Console.WriteLine($""Got {a} and {b}"");
    }
    public static void Main()
    {
        Test<D1>(Impl);
    }
    public static void Test<T>(T obj) where T : System.Delegate
    {
        obj.DynamicInvoke(2, 3);
        obj.DynamicInvoke(7, 9);
    }
}";
 
            CompileAndVerify(code, expectedOutput: @"
Got 2 and 3
Got 7 and 9");
        }
 
        [Fact]
        public void MulticastDelegateConstraint_Compilation_Alone()
        {
            CreateCompilation(@"
public class Test<T> where T : System.MulticastDelegate
{
}
public delegate void D1();
public class Test2
{
    public void M<U>() where U : System.MulticastDelegate
    {
        var a = new Test<D1>();             // delegate
        var b = new Test<int>();            // value type
        var c = new Test<string>();         // reference type
        var d = new Test<U>();              // multicast delegate type
    }
}").VerifyDiagnostics(
                // (11,26): error CS0315: The type 'int' cannot be used as type parameter 'T' in the generic type or method 'Test<T>'. There is no boxing conversion from 'int' to 'System.MulticastDelegate'.
                //         var b = new Test<int>();            // value type
                Diagnostic(ErrorCode.ERR_GenericConstraintNotSatisfiedValType, "int").WithArguments("Test<T>", "System.MulticastDelegate", "T", "int").WithLocation(11, 26),
                // (12,26): error CS0311: The type 'string' cannot be used as type parameter 'T' in the generic type or method 'Test<T>'. There is no implicit reference conversion from 'string' to 'System.MulticastDelegate'.
                //         var c = new Test<string>();         // reference type
                Diagnostic(ErrorCode.ERR_GenericConstraintNotSatisfiedRefType, "string").WithArguments("Test<T>", "System.MulticastDelegate", "T", "string").WithLocation(12, 26));
        }
 
        [Fact]
        public void MulticastDelegateConstraint_Compilation_ReferenceType()
        {
            CreateCompilation(@"
public class Test<T> where T : class, System.MulticastDelegate
{
}
public delegate void D1();
public class Test2
{
    public void M<U>() where U : class, System.MulticastDelegate
    {
        var a = new Test<D1>();             // delegate
        var b = new Test<int>();            // value type
        var c = new Test<string>();         // reference type
        var d = new Test<U>();              // multicast delegate type
    }
}").VerifyDiagnostics(
                // (11,26): error CS0452: The type 'int' must be a reference type in order to use it as parameter 'T' in the generic type or method 'Test<T>'
                //         var b = new Test<int>();            // value type
                Diagnostic(ErrorCode.ERR_RefConstraintNotSatisfied, "int").WithArguments("Test<T>", "T", "int").WithLocation(11, 26),
                // (12,26): error CS0311: The type 'string' cannot be used as type parameter 'T' in the generic type or method 'Test<T>'. There is no implicit reference conversion from 'string' to 'System.MulticastDelegate'.
                //         var c = new Test<string>();         // reference type
                Diagnostic(ErrorCode.ERR_GenericConstraintNotSatisfiedRefType, "string").WithArguments("Test<T>", "System.MulticastDelegate", "T", "string").WithLocation(12, 26));
        }
 
        [Fact]
        public void MulticastDelegateConstraint_Compilation_ValueType()
        {
            CreateCompilation(@"
public class Test<T> where T : struct, System.MulticastDelegate
{
}").VerifyDiagnostics(
                // (2,40): error CS0450: 'MulticastDelegate': cannot specify both a constraint class and the 'class' or 'struct' constraint
                // public class Test<T> where T : struct, System.MulticastDelegate
                Diagnostic(ErrorCode.ERR_RefValBoundWithClass, "System.MulticastDelegate").WithArguments("System.MulticastDelegate").WithLocation(2, 40)
            );
        }
 
        [Fact]
        public void MulticastDelegateConstraint_Compilation_Constructor()
        {
            CreateCompilation(@"
public class Test<T> where T : System.MulticastDelegate, new()
{
}
public delegate void D1();
public class Test2
{
    public void M<U>() where U : System.MulticastDelegate, new()
    {
        var a = new Test<D1>();             // delegate
        var b = new Test<int>();            // value type
        var c = new Test<string>();         // reference type
        var d = new Test<U>();              // multicast delegate type
    }
}").VerifyDiagnostics(
                // (10,26): error CS0310: 'D1' must be a non-abstract type with a public parameterless constructor in order to use it as parameter 'T' in the generic type or method 'Test<T>'
                //         var a = new Test<D1>();             // delegate
                Diagnostic(ErrorCode.ERR_NewConstraintNotSatisfied, "D1").WithArguments("Test<T>", "T", "D1").WithLocation(10, 26),
                // (11,26): error CS0315: The type 'int' cannot be used as type parameter 'T' in the generic type or method 'Test<T>'. There is no boxing conversion from 'int' to 'System.MulticastDelegate'.
                //         var b = new Test<int>();            // value type
                Diagnostic(ErrorCode.ERR_GenericConstraintNotSatisfiedValType, "int").WithArguments("Test<T>", "System.MulticastDelegate", "T", "int").WithLocation(11, 26),
                // (12,26): error CS0311: The type 'string' cannot be used as type parameter 'T' in the generic type or method 'Test<T>'. There is no implicit reference conversion from 'string' to 'System.MulticastDelegate'.
                //         var c = new Test<string>();         // reference type
                Diagnostic(ErrorCode.ERR_GenericConstraintNotSatisfiedRefType, "string").WithArguments("Test<T>", "System.MulticastDelegate", "T", "string").WithLocation(12, 26),
                // (12,26): error CS0310: 'string' must be a non-abstract type with a public parameterless constructor in order to use it as parameter 'T' in the generic type or method 'Test<T>'
                //         var c = new Test<string>();         // reference type
                Diagnostic(ErrorCode.ERR_NewConstraintNotSatisfied, "string").WithArguments("Test<T>", "T", "string").WithLocation(12, 26));
        }
 
        [Fact]
        public void MulticastDelegateConstraint_Reference_Alone()
        {
            var reference = CreateCompilation(@"
public class Test<T> where T : System.MulticastDelegate
{
}").EmitToImageReference();
 
            CreateCompilation(@"
public delegate void D1();
public class Test2
{
    public void M<U>() where U : System.MulticastDelegate
    {
        var a = new Test<D1>();             // delegate
        var b = new Test<int>();            // value type
        var c = new Test<string>();         // reference type
        var d = new Test<U>();              // multicast delegate type
    }
}", references: new[] { reference }).VerifyDiagnostics(
                // (8,26): error CS0315: The type 'int' cannot be used as type parameter 'T' in the generic type or method 'Test<T>'. There is no boxing conversion from 'int' to 'System.MulticastDelegate'.
                //         var b = new Test<int>();            // value type
                Diagnostic(ErrorCode.ERR_GenericConstraintNotSatisfiedValType, "int").WithArguments("Test<T>", "System.MulticastDelegate", "T", "int").WithLocation(8, 26),
                // (9,26): error CS0311: The type 'string' cannot be used as type parameter 'T' in the generic type or method 'Test<T>'. There is no implicit reference conversion from 'string' to 'System.MulticastDelegate'.
                //         var c = new Test<string>();         // reference type
                Diagnostic(ErrorCode.ERR_GenericConstraintNotSatisfiedRefType, "string").WithArguments("Test<T>", "System.MulticastDelegate", "T", "string").WithLocation(9, 26));
        }
 
        [Fact]
        public void MulticastDelegateConstraint_Reference_ReferenceType()
        {
            var reference = CreateCompilation(@"
public class Test<T> where T : class, System.MulticastDelegate
{
}").EmitToImageReference();
 
            CreateCompilation(@"
public delegate void D1();
public class Test2
{
    public void M<U>() where U : class, System.MulticastDelegate
    {
        var a = new Test<D1>();             // delegate
        var b = new Test<int>();            // value type
        var c = new Test<string>();         // reference type
        var d = new Test<U>();              // multicast delegate type
    }
}", references: new[] { reference }).VerifyDiagnostics(
                // (8,26): error CS0452: The type 'int' must be a reference type in order to use it as parameter 'T' in the generic type or method 'Test<T>'
                //         var b = new Test<int>();            // value type
                Diagnostic(ErrorCode.ERR_RefConstraintNotSatisfied, "int").WithArguments("Test<T>", "T", "int").WithLocation(8, 26),
                // (9,26): error CS0311: The type 'string' cannot be used as type parameter 'T' in the generic type or method 'Test<T>'. There is no implicit reference conversion from 'string' to 'System.MulticastDelegate'.
                //         var c = new Test<string>();         // reference type
                Diagnostic(ErrorCode.ERR_GenericConstraintNotSatisfiedRefType, "string").WithArguments("Test<T>", "System.MulticastDelegate", "T", "string").WithLocation(9, 26));
        }
 
        [Fact]
        public void MulticastDelegateConstraint_Reference_Constructor()
        {
            var reference = CreateCompilation(@"
public class Test<T> where T : System.MulticastDelegate, new()
{
}").EmitToImageReference();
 
            CreateCompilation(@"
public delegate void D1();
public class Test2
{
    public void M<U>() where U : System.MulticastDelegate, new()
    {
        var a = new Test<D1>();             // delegate
        var b = new Test<int>();            // value type
        var c = new Test<string>();         // reference type
        var d = new Test<U>();              // multicast delegate type
    }
}", references: new[] { reference }).VerifyDiagnostics(
                // (7,26): error CS0310: 'D1' must be a non-abstract type with a public parameterless constructor in order to use it as parameter 'T' in the generic type or method 'Test<T>'
                //         var a = new Test<D1>();             // delegate
                Diagnostic(ErrorCode.ERR_NewConstraintNotSatisfied, "D1").WithArguments("Test<T>", "T", "D1").WithLocation(7, 26),
                // (8,26): error CS0315: The type 'int' cannot be used as type parameter 'T' in the generic type or method 'Test<T>'. There is no boxing conversion from 'int' to 'System.MulticastDelegate'.
                //         var b = new Test<int>();            // value type
                Diagnostic(ErrorCode.ERR_GenericConstraintNotSatisfiedValType, "int").WithArguments("Test<T>", "System.MulticastDelegate", "T", "int").WithLocation(8, 26),
                // (9,26): error CS0311: The type 'string' cannot be used as type parameter 'T' in the generic type or method 'Test<T>'. There is no implicit reference conversion from 'string' to 'System.MulticastDelegate'.
                //         var c = new Test<string>();         // reference type
                Diagnostic(ErrorCode.ERR_GenericConstraintNotSatisfiedRefType, "string").WithArguments("Test<T>", "System.MulticastDelegate", "T", "string").WithLocation(9, 26),
                // (9,26): error CS0310: 'string' must be a non-abstract type with a public parameterless constructor in order to use it as parameter 'T' in the generic type or method 'Test<T>'
                //         var c = new Test<string>();         // reference type
                Diagnostic(ErrorCode.ERR_NewConstraintNotSatisfied, "string").WithArguments("Test<T>", "T", "string").WithLocation(9, 26));
        }
 
        [Fact]
        public void MulticastDelegateConstraint_Before_7_3()
        {
            var code = @"
public class Test<T> where T : System.MulticastDelegate
{
}";
 
            var oldOptions = new CSharpParseOptions(LanguageVersion.CSharp7_2);
 
            CreateCompilation(code, parseOptions: oldOptions).VerifyDiagnostics(
                // (2,32): error CS8320: Feature 'delegate generic type constraints' is not available in C# 7.2. Please use language version 7.3 or greater.
                // public class Test<T> where T : System.MulticastDelegate
                Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7_2, "System.MulticastDelegate").WithArguments("delegate generic type constraints", "7.3").WithLocation(2, 32));
 
            var reference = CreateCompilation(code).EmitToImageReference();
 
            var legacyCode = @"
delegate void D();
 
class Legacy
{
    void M()
    {
        var a = new Test<D>();          // valid
        var b = new Test<Legacy>();     // invalid
    }
}";
 
            CreateCompilation(legacyCode, parseOptions: oldOptions, references: new[] { reference }).VerifyDiagnostics(
                // (9,26): error CS0311: The type 'Legacy' cannot be used as type parameter 'T' in the generic type or method 'Test<T>'. There is no implicit reference conversion from 'Legacy' to 'System.MulticastDelegate'.
                //         var b = new Test<Legacy>();     // invalid
                Diagnostic(ErrorCode.ERR_GenericConstraintNotSatisfiedRefType, "Legacy").WithArguments("Test<T>", "System.MulticastDelegate", "T", "Legacy").WithLocation(9, 26));
        }
 
        [Fact]
        public void MulticastDelegateConstraint_InheritanceChain()
        {
            CreateCompilation(@"
public delegate void D1();
public class Test<T, U> where U : System.MulticastDelegate, T
{
}
public class Test2
{
    public void M()
    {
        var a = new Test<Test2, D1>();
        
        var b = new Test<D1, D1>();
        var c = new Test<System.MulticastDelegate, System.MulticastDelegate>();
        var d = new Test<System.Delegate, System.MulticastDelegate>();
        var e = new Test<System.MulticastDelegate, System.Delegate>();
        var f = new Test<System.Delegate, System.Delegate>();
 
        var g = new Test<D1, System.MulticastDelegate>();
        var h = new Test<System.MulticastDelegate, D1>();
    }
}").VerifyDiagnostics(
                // (10,33): error CS0311: The type 'D1' cannot be used as type parameter 'U' in the generic type or method 'Test<T, U>'. There is no implicit reference conversion from 'D1' to 'Test2'.
                //         var a = new Test<Test2, D1>();
                Diagnostic(ErrorCode.ERR_GenericConstraintNotSatisfiedRefType, "D1").WithArguments("Test<T, U>", "Test2", "U", "D1").WithLocation(10, 33),
                // (15,52): error CS0311: The type 'System.Delegate' cannot be used as type parameter 'U' in the generic type or method 'Test<T, U>'. There is no implicit reference conversion from 'System.Delegate' to 'System.MulticastDelegate'.
                //         var e = new Test<System.MulticastDelegate, System.Delegate>();
                Diagnostic(ErrorCode.ERR_GenericConstraintNotSatisfiedRefType, "System.Delegate").WithArguments("Test<T, U>", "System.MulticastDelegate", "U", "System.Delegate").WithLocation(15, 52),
                // (16,43): error CS0311: The type 'System.Delegate' cannot be used as type parameter 'U' in the generic type or method 'Test<T, U>'. There is no implicit reference conversion from 'System.Delegate' to 'System.MulticastDelegate'.
                //         var f = new Test<System.Delegate, System.Delegate>();
                Diagnostic(ErrorCode.ERR_GenericConstraintNotSatisfiedRefType, "System.Delegate").WithArguments("Test<T, U>", "System.MulticastDelegate", "U", "System.Delegate").WithLocation(16, 43),
                // (18,30): error CS0311: The type 'System.MulticastDelegate' cannot be used as type parameter 'U' in the generic type or method 'Test<T, U>'. There is no implicit reference conversion from 'System.MulticastDelegate' to 'D1'.
                //         var g = new Test<D1, System.MulticastDelegate>();
                Diagnostic(ErrorCode.ERR_GenericConstraintNotSatisfiedRefType, "System.MulticastDelegate").WithArguments("Test<T, U>", "D1", "U", "System.MulticastDelegate").WithLocation(18, 30));
        }
 
        [Fact]
        public void MulticastDelegateConstraint_IsReflectedInSymbols_Alone()
        {
            var code = "public class Test<T> where T : System.MulticastDelegate { }";
 
            Action<ModuleSymbol> validator = module =>
            {
                var typeParameter = module.GlobalNamespace.GetTypeMember("Test").TypeParameters.Single();
                Assert.False(typeParameter.HasValueTypeConstraint);
                Assert.False(typeParameter.HasReferenceTypeConstraint);
                Assert.Equal(SpecialType.System_MulticastDelegate, typeParameter.ConstraintTypes().Single().SpecialType);
            };
 
            CompileAndVerify(code, sourceSymbolValidator: validator, symbolValidator: validator);
        }
 
        [Fact]
        public void MulticastDelegateConstraint_IsReflectedInSymbols_ValueType()
        {
            var compilation = CreateCompilation("public class Test<T> where T : struct, System.MulticastDelegate { }")
                    .VerifyDiagnostics(
                        // (1,40): error CS0450: 'MulticastDelegate': cannot specify both a constraint class and the 'class' or 'struct' constraint
                        // public class Test<T> where T : struct, System.MulticastDelegate { }
                        Diagnostic(ErrorCode.ERR_RefValBoundWithClass, "System.MulticastDelegate").WithArguments("System.MulticastDelegate").WithLocation(1, 40)
                     );
 
            var typeParameter = compilation.GlobalNamespace.GetTypeMember("Test").TypeParameters.Single();
 
            Assert.True(typeParameter.HasValueTypeConstraint);
            Assert.False(typeParameter.HasReferenceTypeConstraint);
            Assert.False(typeParameter.HasConstructorConstraint);
            Assert.Empty(typeParameter.ConstraintTypes());
        }
 
        [Fact]
        public void MulticastDelegateConstraint_IsReflectedInSymbols_ReferenceType()
        {
            var code = "public class Test<T> where T : class, System.MulticastDelegate { }";
 
            Action<ModuleSymbol> validator = module =>
            {
                var typeParameter = module.GlobalNamespace.GetTypeMember("Test").TypeParameters.Single();
                Assert.False(typeParameter.HasValueTypeConstraint);
                Assert.True(typeParameter.HasReferenceTypeConstraint);
                Assert.False(typeParameter.HasConstructorConstraint);
                Assert.Equal(SpecialType.System_MulticastDelegate, typeParameter.ConstraintTypes().Single().SpecialType);
            };
 
            CompileAndVerify(code, sourceSymbolValidator: validator, symbolValidator: validator);
        }
 
        [Fact]
        public void MulticastDelegateConstraint_IsReflectedInSymbols_Constructor()
        {
            var code = "public class Test<T> where T : System.MulticastDelegate, new() { }";
 
            Action<ModuleSymbol> validator = module =>
            {
                var typeParameter = module.GlobalNamespace.GetTypeMember("Test").TypeParameters.Single();
                Assert.False(typeParameter.HasValueTypeConstraint);
                Assert.False(typeParameter.HasReferenceTypeConstraint);
                Assert.True(typeParameter.HasConstructorConstraint);
                Assert.Equal(SpecialType.System_MulticastDelegate, typeParameter.ConstraintTypes().Single().SpecialType);
            };
 
            CompileAndVerify(code, sourceSymbolValidator: validator, symbolValidator: validator);
        }
 
        [Fact]
        public void MulticastDelegateConstraint_EnforcedInInheritanceChain_Downwards_Source()
        {
            CreateCompilation(@"
public abstract class A
{
    public abstract void M<T>() where T : System.MulticastDelegate;
}
public delegate void D1();
public class B : A
{
    public override void M<T>() { }
 
    public void Test()
    {
        this.M<int>();
        this.M<D1>();
    }
}").VerifyDiagnostics(
                // (13,14): error CS0315: The type 'int' cannot be used as type parameter 'T' in the generic type or method 'B.M<T>()'. There is no boxing conversion from 'int' to 'System.MulticastDelegate'.
                //         this.M<int>();
                Diagnostic(ErrorCode.ERR_GenericConstraintNotSatisfiedValType, "M<int>").WithArguments("B.M<T>()", "System.MulticastDelegate", "T", "int").WithLocation(13, 14)
                );
        }
 
        [Fact]
        public void MulticastDelegateConstraint_EnforcedInInheritanceChain_Downwards_Reference()
        {
            var reference = CreateCompilation(@"
public abstract class A
{
    public abstract void M<T>() where T : System.MulticastDelegate;
}").EmitToImageReference();
 
            CreateCompilation(@"
public delegate void D1();
public class B : A
{
    public override void M<T>() { }
 
    public void Test()
    {
        this.M<int>();
        this.M<D1>();
    }
}", references: new[] { reference }).VerifyDiagnostics(
                // (9,14): error CS0315: The type 'int' cannot be used as type parameter 'T' in the generic type or method 'B.M<T>()'. There is no boxing conversion from 'int' to 'System.MulticastDelegate'.
                //         this.M<int>();
                Diagnostic(ErrorCode.ERR_GenericConstraintNotSatisfiedValType, "M<int>").WithArguments("B.M<T>()", "System.MulticastDelegate", "T", "int").WithLocation(9, 14)
                );
        }
 
        [Fact]
        public void MulticastDelegateConstraint_EnforcedInInheritanceChain_Upwards_Source()
        {
            CreateCompilation(@"
public abstract class A
{
    public abstract void M<T>();
}
public class B : A
{
    public override void M<T>() where T : System.MulticastDelegate { }
}").VerifyDiagnostics(
                // (8,43): error CS0460: Constraints for override and explicit interface implementation methods are inherited from the base method, so they cannot be specified directly, except for either a 'class', or a 'struct' constraint.
                //     public override void M<T>() where T : System.MulticastDelegate { }
                Diagnostic(ErrorCode.ERR_OverrideWithConstraints, "System.MulticastDelegate").WithLocation(8, 43));
        }
 
        [Fact]
        public void MulticastDelegateConstraint_EnforcedInInheritanceChain_Upwards_Reference()
        {
            var reference = CreateCompilation(@"
public abstract class A
{
    public abstract void M<T>();
}").EmitToImageReference();
 
            CreateCompilation(@"
public class B : A
{
    public override void M<T>() where T : System.MulticastDelegate { }
}", references: new[] { reference }).VerifyDiagnostics(
                // (4,43): error CS0460: Constraints for override and explicit interface implementation methods are inherited from the base method, so they cannot be specified directly, except for either a 'class', or a 'struct' constraint.
                //     public override void M<T>() where T : System.MulticastDelegate { }
                Diagnostic(ErrorCode.ERR_OverrideWithConstraints, "System.MulticastDelegate").WithLocation(4, 43));
        }
 
        [Fact]
        public void MulticastDelegateConstraint_ResolveParentConstraints()
        {
            var comp = CreateCompilation(@"
public delegate void D1();
public abstract class A<T>
{
    public abstract void F<U>() where U : System.MulticastDelegate, T;
}
public class B : A<D1>
{
    public override void F<U>() { }
}");
 
            Action<ModuleSymbol> validator = module =>
            {
                var method = module.GlobalNamespace.GetTypeMember("B").GetMethod("F");
                var constraintTypeNames = method.TypeParameters.Single().ConstraintTypes().Select(type => type.ToTestDisplayString());
 
                AssertEx.SetEqual(new[] { "System.MulticastDelegate", "D1" }, constraintTypeNames);
            };
 
            CompileAndVerify(comp, sourceSymbolValidator: validator, symbolValidator: validator);
        }
 
        [Fact]
        public void MulticastDelegateConstraint_TypeNotAvailable()
        {
            CreateEmptyCompilation(@"
namespace System
{
    public class Object {}
    public class Void {}
}
public class Test<T> where T : System.MulticastDelegate
{
}").VerifyDiagnostics(
                // (7,39): error CS0234: The type or namespace name 'MulticastDelegate' does not exist in the namespace 'System' (are you missing an assembly reference?)
                // public class Test<T> where T : System.MulticastDelegate
                Diagnostic(ErrorCode.ERR_DottedTypeNameNotFoundInNS, "MulticastDelegate").WithArguments("MulticastDelegate", "System").WithLocation(7, 39));
        }
 
        [Fact]
        public void MulticastDelegateConstraint_BindingToMethods()
        {
            var code = @"
delegate void D1(int a, int b);
class TestClass
{
    public static void Impl(int a, int b)
    {
        System.Console.WriteLine($""Got {a} and {b}"");
    }
    public static void Main()
    {
        Test<D1>(Impl);
    }
    public static void Test<T>(T obj) where T : System.MulticastDelegate
    {
        obj.DynamicInvoke(2, 3);
        obj.DynamicInvoke(7, 9);
    }
}";
 
            CompileAndVerify(code, expectedOutput: @"
Got 2 and 3
Got 7 and 9");
        }
 
        [Fact]
        public void ConversionInInheritanceChain_MulticastDelegate()
        {
            var code = @"
class A<T> where T : System.Delegate { }
class B<T> : A<T> where T : System.MulticastDelegate { }";
 
            CreateCompilation(code).VerifyDiagnostics();
 
            code = @"
class A<T> where T : System.MulticastDelegate { }
class B<T> : A<T> where T : System.Delegate { }";
 
            CreateCompilation(code).VerifyDiagnostics(
                // (3,7): error CS0311: The type 'T' cannot be used as type parameter 'T' in the generic type or method 'A<T>'. There is no implicit reference conversion from 'T' to 'System.MulticastDelegate'.
                // class B<T> : A<T> where T : System.Delegate { }
                Diagnostic(ErrorCode.ERR_GenericConstraintNotSatisfiedRefType, "B").WithArguments("A<T>", "System.MulticastDelegate", "T", "T").WithLocation(3, 7));
        }
 
        [ConditionalFact(typeof(ClrOnly), Reason = "https://github.com/mono/mono/issues/10782")]
        public void UnmanagedConstraint_Compilation_Alone_Type()
        {
            CreateCompilation(@"
public class Test<T> where T : unmanaged
{
}
public struct GoodType { public int I; }
public struct BadType { public string S; }
public class Test2
{
    public void M<U, W>() where U : unmanaged
    {
        var a = new Test<GoodType>();           // unmanaged struct
        var b = new Test<BadType>();            // managed struct
        var c = new Test<string>();             // reference type
        var d = new Test<int>();                // value type
        var e = new Test<U>();                  // generic type constrained to unmanaged
        var f = new Test<W>();                  // unconstrained generic type
    }
}").VerifyDiagnostics(
                // (12,26): error CS8379: The type 'BadType' must be a non-nullable value type, along with all fields at any level of nesting, in order to use it as parameter 'T' in the generic type or method 'Test<T>'
                //         var b = new Test<BadType>();            // managed struct
                Diagnostic(ErrorCode.ERR_UnmanagedConstraintNotSatisfied, "BadType").WithArguments("Test<T>", "T", "BadType").WithLocation(12, 26),
                // (13,26): error CS8379: The type 'string' must be a non-nullable value type, along with all fields at any level of nesting, in order to use it as parameter 'T' in the generic type or method 'Test<T>'
                //         var c = new Test<string>();             // reference type
                Diagnostic(ErrorCode.ERR_UnmanagedConstraintNotSatisfied, "string").WithArguments("Test<T>", "T", "string").WithLocation(13, 26),
                // (16,26): error CS8379: The type 'W' must be a non-nullable value type, along with all fields at any level of nesting, in order to use it as parameter 'T' in the generic type or method 'Test<T>'
                //         var f = new Test<W>();                  // unconstrained generic type
                Diagnostic(ErrorCode.ERR_UnmanagedConstraintNotSatisfied, "W").WithArguments("Test<T>", "T", "W").WithLocation(16, 26));
        }
 
        [ConditionalFact(typeof(ClrOnly), Reason = "https://github.com/mono/mono/issues/10782")]
        public void UnmanagedConstraint_Compilation_Alone_Method()
        {
            CreateCompilation(@"
public class Test
{
    public int M<T>() where T : unmanaged => 0;
}
public struct GoodType { public int I; }
public struct BadType { public string S; }
public class Test2
{
    public void M<U, W>() where U : unmanaged
    {
        var a = new Test().M<GoodType>();           // unmanaged struct
        var b = new Test().M<BadType>();            // managed struct
        var c = new Test().M<string>();             // reference type
        var d = new Test().M<int>();                // value type
        var e = new Test().M<U>();                  // generic type constrained to unmanaged
        var f = new Test().M<W>();                  // unconstrained generic type
    }
}").VerifyDiagnostics(
                // (13,28): error CS8379: The type 'BadType' must be a non-nullable value type, along with all fields at any level of nesting, in order to use it as parameter 'T' in the generic type or method 'Test.M<T>()'
                //         var b = new Test().M<BadType>();            // managed struct
                Diagnostic(ErrorCode.ERR_UnmanagedConstraintNotSatisfied, "M<BadType>").WithArguments("Test.M<T>()", "T", "BadType").WithLocation(13, 28),
                // (14,28): error CS8379: The type 'string' must be a non-nullable value type, along with all fields at any level of nesting, in order to use it as parameter 'T' in the generic type or method 'Test.M<T>()'
                //         var c = new Test().M<string>();             // reference type
                Diagnostic(ErrorCode.ERR_UnmanagedConstraintNotSatisfied, "M<string>").WithArguments("Test.M<T>()", "T", "string").WithLocation(14, 28),
                // (17,28): error CS8379: The type 'W' must be a non-nullable value type, along with all fields at any level of nesting, in order to use it as parameter 'T' in the generic type or method 'Test.M<T>()'
                //         var f = new Test().M<W>();                  // unconstrained generic type
                Diagnostic(ErrorCode.ERR_UnmanagedConstraintNotSatisfied, "M<W>").WithArguments("Test.M<T>()", "T", "W").WithLocation(17, 28)
                );
        }
 
        [ConditionalFact(typeof(ClrOnly), Reason = "https://github.com/mono/mono/issues/10782")]
        public void UnmanagedConstraint_Compilation_Alone_Delegate()
        {
            CreateCompilation(@"
public delegate void D<T>() where T : unmanaged;
public struct GoodType { public int I; }
public struct BadType { public string S; }
public abstract class Test2<U, W> where U : unmanaged
{
    public abstract D<GoodType> a();                // unmanaged struct
    public abstract D<BadType> b();                 // managed struct
    public abstract D<string> c();                  // reference type
    public abstract D<int> d();                     // value type
    public abstract D<U> e();                       // generic type constrained to unmanaged
    public abstract D<W> f();                       // unconstrained generic type
}").VerifyDiagnostics(
                // (8,32): error CS8379: The type 'BadType' must be a non-nullable value type, along with all fields at any level of nesting, in order to use it as parameter 'T' in the generic type or method 'D<T>'
                //     public abstract D<BadType> b();                 // managed struct
                Diagnostic(ErrorCode.ERR_UnmanagedConstraintNotSatisfied, "b").WithArguments("D<T>", "T", "BadType").WithLocation(8, 32),
                // (9,31): error CS8379: The type 'string' must be a non-nullable value type, along with all fields at any level of nesting, in order to use it as parameter 'T' in the generic type or method 'D<T>'
                //     public abstract D<string> c();                  // reference type
                Diagnostic(ErrorCode.ERR_UnmanagedConstraintNotSatisfied, "c").WithArguments("D<T>", "T", "string").WithLocation(9, 31),
                // (12,26): error CS8379: The type 'W' must be a non-nullable value type, along with all fields at any level of nesting, in order to use it as parameter 'T' in the generic type or method 'D<T>'
                //     public abstract D<W> f();                       // unconstrained generic type
                Diagnostic(ErrorCode.ERR_UnmanagedConstraintNotSatisfied, "f").WithArguments("D<T>", "T", "W").WithLocation(12, 26));
        }
 
        [ConditionalFact(typeof(ClrOnly), Reason = "https://github.com/mono/mono/issues/10782")]
        public void UnmanagedConstraint_Compilation_Alone_LocalFunction()
        {
            CreateCompilation(@"
public struct GoodType { public int I; }
public struct BadType { public string S; }
public class Test2
{
    public void M<U, W>() where U : unmanaged
    {
        void M<T>() where T : unmanaged
        {
        }
 
        M<GoodType>();                       // unmanaged struct
        M<BadType>();                        // managed struct
        M<string>();                         // reference type
        M<int>();                            // value type
        M<U>();                              // generic type constrained to unmanaged
        M<W>();                              // unconstrained generic type
    }
}").VerifyDiagnostics(
                // (13,9): error CS8377: The type 'BadType' must be a non-nullable value type, along with all fields at any level of nesting, in order to use it as parameter 'T' in the generic type or method 'M<T>()'
                //         M<BadType>();                        // managed struct
                Diagnostic(ErrorCode.ERR_UnmanagedConstraintNotSatisfied, "M<BadType>").WithArguments("M<T>()", "T", "BadType").WithLocation(13, 9),
                // (14,9): error CS8377: The type 'string' must be a non-nullable value type, along with all fields at any level of nesting, in order to use it as parameter 'T' in the generic type or method 'M<T>()'
                //         M<string>();                         // reference type
                Diagnostic(ErrorCode.ERR_UnmanagedConstraintNotSatisfied, "M<string>").WithArguments("M<T>()", "T", "string").WithLocation(14, 9),
                // (17,9): error CS8377: The type 'W' must be a non-nullable value type, along with all fields at any level of nesting, in order to use it as parameter 'T' in the generic type or method 'M<T>()'
                //         M<W>();                              // unconstrained generic type
                Diagnostic(ErrorCode.ERR_UnmanagedConstraintNotSatisfied, "M<W>").WithArguments("M<T>()", "T", "W").WithLocation(17, 9));
        }
 
        [Fact]
        public void UnmanagedConstraint_Compilation_ReferenceType()
        {
            var c = CreateCompilation("public class Test<T> where T : class, unmanaged {}");
 
            c.VerifyDiagnostics(
                // (1,39): error CS0449: The 'unmanaged' constraint cannot be combined with the 'class' constraint
                // public class Test<T> where T : class, unmanaged {}
                Diagnostic(ErrorCode.ERR_TypeConstraintsMustBeUniqueAndFirst, "unmanaged").WithLocation(1, 39));
 
            var typeParameter = c.GlobalNamespace.GetTypeMember("Test").TypeParameters.Single();
            Assert.False(typeParameter.HasUnmanagedTypeConstraint);
            Assert.False(typeParameter.HasValueTypeConstraint);
            Assert.True(typeParameter.HasReferenceTypeConstraint);
            Assert.False(typeParameter.HasConstructorConstraint);
            Assert.Empty(typeParameter.ConstraintTypes());
        }
 
        [Fact]
        public void UnmanagedConstraint_Compilation_ValueType()
        {
            var c = CreateCompilation("public class Test<T> where T : struct, unmanaged {}");
 
            c.VerifyDiagnostics(
                // (1,40): error CS0449: The 'unmanaged' constraint cannot be combined with the 'struct' constraint
                // public class Test<T> where T : struct, unmanaged {}
                Diagnostic(ErrorCode.ERR_TypeConstraintsMustBeUniqueAndFirst, "unmanaged").WithLocation(1, 40));
 
            var typeParameter = c.GlobalNamespace.GetTypeMember("Test").TypeParameters.Single();
            Assert.False(typeParameter.HasUnmanagedTypeConstraint);
            Assert.True(typeParameter.HasValueTypeConstraint);
            Assert.False(typeParameter.HasReferenceTypeConstraint);
            Assert.False(typeParameter.HasConstructorConstraint);
            Assert.Empty(typeParameter.ConstraintTypes());
        }
 
        [Fact]
        public void UnmanagedConstraint_Compilation_Constructor()
        {
            CreateCompilation("public class Test<T> where T : unmanaged, new() {}").VerifyDiagnostics(
                // (1,43): error CS8379: The 'new()' constraint cannot be used with the 'unmanaged' constraint
                // public class Test<T> where T : unmanaged, new() {}
                Diagnostic(ErrorCode.ERR_NewBoundWithUnmanaged, "new").WithLocation(1, 43));
        }
 
        [Fact]
        public void UnmanagedConstraint_Compilation_AnotherClass_Before()
        {
            CreateCompilation("public class Test<T> where T : unmanaged, System.Exception { }").VerifyDiagnostics(
                // (1,43): error CS8380: 'Exception': cannot specify both a constraint class and the 'unmanaged' constraint
                // public class Test<T> where T : unmanaged, System.Exception { }
                Diagnostic(ErrorCode.ERR_UnmanagedBoundWithClass, "System.Exception").WithArguments("System.Exception").WithLocation(1, 43)
            );
        }
 
        [Fact]
        public void UnmanagedConstraint_Compilation_AnotherClass_After()
        {
            CreateCompilation("public class Test<T> where T : System.Exception, unmanaged { }").VerifyDiagnostics(
                // (1,50): error CS8380: The 'unmanaged' constraint must come before any other constraints
                // public class Test<T> where T : System.Exception, unmanaged { }
                Diagnostic(ErrorCode.ERR_TypeConstraintsMustBeUniqueAndFirst, "unmanaged").WithLocation(1, 50));
        }
 
        [Fact]
        public void UnmanagedConstraint_Compilation_OtherValidTypes_After()
        {
            CreateCompilation("public class Test<T> where T : System.Enum, System.IDisposable, unmanaged { }").VerifyDiagnostics(
                // (1,65): error CS8376: The 'unmanaged' constraint must come before any other constraints
                // public class Test<T> where T : System.Enum, System.IDisposable, unmanaged { }
                Diagnostic(ErrorCode.ERR_TypeConstraintsMustBeUniqueAndFirst, "unmanaged").WithLocation(1, 65));
        }
 
        [Fact]
        public void UnmanagedConstraint_OtherValidTypes_Before()
        {
            Action<ModuleSymbol> validator = module =>
            {
                var typeParameter = module.GlobalNamespace.GetTypeMember("Test").TypeParameters.Single();
 
                Assert.True(typeParameter.HasUnmanagedTypeConstraint);
                AssertEx.Equal(new string[] { "Enum", "IDisposable" }, typeParameter.ConstraintTypes().Select(type => type.Name));
            };
 
            CompileAndVerify(
                "public class Test<T> where T : unmanaged, System.Enum, System.IDisposable { }",
                sourceSymbolValidator: validator,
                symbolValidator: validator);
        }
 
        [Fact]
        public void UnmanagedConstraint_Compilation_AnotherParameter_After()
        {
            CreateCompilation("public class Test<T, U> where T : U, unmanaged { }").VerifyDiagnostics(
                // (1,38): error CS8380: The 'unmanaged' constraint must come before any other constraints
                // public class Test<T, U> where T : U, unmanaged { }
                Diagnostic(ErrorCode.ERR_TypeConstraintsMustBeUniqueAndFirst, "unmanaged").WithLocation(1, 38));
        }
 
        [Fact]
        public void UnmanagedConstraint_Compilation_AnotherParameter_Before()
        {
            CreateCompilation("public class Test<T, U> where T : unmanaged, U { }").VerifyDiagnostics();
            CreateCompilation("public class Test<T, U> where U: class where T : unmanaged, U, System.IDisposable { }").VerifyDiagnostics();
        }
 
        [Fact]
        public void UnmanagedConstraint_UnmanagedEnumNotAvailable()
        {
            CreateEmptyCompilation(@"
namespace System
{
    public class Object {}
    public class Void {}
    public class ValueType {}
}
public class Test<T> where T : unmanaged
{
}").VerifyDiagnostics(
                // (8,32): error CS0518: Predefined type 'System.Runtime.InteropServices.UnmanagedType' is not defined or imported
                // public class Test<T> where T : unmanaged
                Diagnostic(ErrorCode.ERR_PredefinedTypeNotFound, "unmanaged").WithArguments("System.Runtime.InteropServices.UnmanagedType").WithLocation(8, 32));
        }
 
        [Fact]
        public void UnmanagedConstraint_ValueTypeNotAvailable()
        {
            CreateEmptyCompilation(@"
namespace System
{
    public class Object {}
    public class Void {}
    public class Enum {}
    public class Int32 {}
    namespace Runtime
    {
        namespace InteropServices
        {
            public enum UnmanagedType {}
        }
    }
}
public class Test<T> where T : unmanaged
{
}").VerifyDiagnostics(
                // (16,32): error CS0518: Predefined type 'System.ValueType' is not defined or imported
                // public class Test<T> where T : unmanaged
                Diagnostic(ErrorCode.ERR_PredefinedTypeNotFound, "unmanaged").WithArguments("System.ValueType").WithLocation(16, 32));
        }
 
        [Fact]
        public void UnmanagedConstraint_Reference_Alone_Type()
        {
            var reference = CreateCompilation(@"
public class Test<T> where T : unmanaged
{
}").EmitToImageReference();
 
            var code = @"
public struct GoodType { public int I; }
public struct BadType { public string S; }
public class Test2
{
    public void M<U, W>() where U : unmanaged
    {
        var a = new Test<GoodType>();           // unmanaged struct
        var b = new Test<BadType>();            // managed struct
        var c = new Test<string>();             // reference type
        var d = new Test<int>();                // value type
        var e = new Test<U>();                  // generic type constrained to unmanaged
        var f = new Test<W>();                  // unconstrained generic type
    }
}";
            CreateCompilation(code, references: new[] { reference }).VerifyDiagnostics(
                // (9,26): error CS8379: The type 'BadType' must be a non-nullable value type, along with all fields at any level of nesting, in order to use it as parameter 'T' in the generic type or method 'Test<T>'
                //         var b = new Test<BadType>();            // managed struct
                Diagnostic(ErrorCode.ERR_UnmanagedConstraintNotSatisfied, "BadType").WithArguments("Test<T>", "T", "BadType").WithLocation(9, 26),
                // (10,26): error CS8379: The type 'string' must be a non-nullable value type, along with all fields at any level of nesting, in order to use it as parameter 'T' in the generic type or method 'Test<T>'
                //         var c = new Test<string>();             // reference type
                Diagnostic(ErrorCode.ERR_UnmanagedConstraintNotSatisfied, "string").WithArguments("Test<T>", "T", "string").WithLocation(10, 26),
                // (13,26): error CS8379: The type 'W' must be a non-nullable value type, along with all fields at any level of nesting, in order to use it as parameter 'T' in the generic type or method 'Test<T>'
                //         var f = new Test<W>();                  // unconstrained generic type
                Diagnostic(ErrorCode.ERR_UnmanagedConstraintNotSatisfied, "W").WithArguments("Test<T>", "T", "W").WithLocation(13, 26));
        }
 
        [Fact]
        public void UnmanagedConstraint_Reference_Alone_Method()
        {
            var reference = CreateCompilation(@"
public class Test
{
    public int M<T>() where T : unmanaged => 0;
}").EmitToImageReference();
 
            var code = @"
public struct GoodType { public int I; }
public struct BadType { public string S; }
public class Test2
{
    public void M<U, W>() where U : unmanaged
    {
        var a = new Test().M<GoodType>();           // unmanaged struct
        var b = new Test().M<BadType>();            // managed struct
        var c = new Test().M<string>();             // reference type
        var d = new Test().M<int>();                // value type
        var e = new Test().M<U>();                  // generic type constrained to unmanaged
        var f = new Test().M<W>();                  // unconstrained generic type
    }
}";
            CreateCompilation(code, references: new[] { reference }).VerifyDiagnostics(
                // (9,28): error CS8379: The type 'BadType' must be a non-nullable value type, along with all fields at any level of nesting, in order to use it as parameter 'T' in the generic type or method 'Test.M<T>()'
                //         var b = new Test().M<BadType>();            // managed struct
                Diagnostic(ErrorCode.ERR_UnmanagedConstraintNotSatisfied, "M<BadType>").WithArguments("Test.M<T>()", "T", "BadType").WithLocation(9, 28),
                // (10,28): error CS8379: The type 'string' must be a non-nullable value type, along with all fields at any level of nesting, in order to use it as parameter 'T' in the generic type or method 'Test.M<T>()'
                //         var c = new Test().M<string>();             // reference type
                Diagnostic(ErrorCode.ERR_UnmanagedConstraintNotSatisfied, "M<string>").WithArguments("Test.M<T>()", "T", "string").WithLocation(10, 28),
                // (13,28): error CS8379: The type 'W' must be a non-nullable value type, along with all fields at any level of nesting, in order to use it as parameter 'T' in the generic type or method 'Test.M<T>()'
                //         var f = new Test().M<W>();                  // unconstrained generic type
                Diagnostic(ErrorCode.ERR_UnmanagedConstraintNotSatisfied, "M<W>").WithArguments("Test.M<T>()", "T", "W").WithLocation(13, 28)
                );
        }
 
        [Fact]
        public void UnmanagedConstraint_Reference_Alone_Delegate()
        {
            var reference = CreateCompilation(@"
public delegate void D<T>() where T : unmanaged;
").EmitToImageReference();
 
            var code = @"
public struct GoodType { public int I; }
public struct BadType { public string S; }
public abstract class Test2<U, W> where U : unmanaged
{
    public abstract D<GoodType> a();                // unmanaged struct
    public abstract D<BadType> b();                 // managed struct
    public abstract D<string> c();                  // reference type
    public abstract D<int> d();                     // value type
    public abstract D<U> e();                       // generic type constrained to unmanaged
    public abstract D<W> f();                       // unconstrained generic type
}";
            CreateCompilation(code, references: new[] { reference }).VerifyDiagnostics(
                // (7,32): error CS8379: The type 'BadType' must be a non-nullable value type, along with all fields at any level of nesting, in order to use it as parameter 'T' in the generic type or method 'D<T>'
                //     public abstract D<BadType> b();                 // managed struct
                Diagnostic(ErrorCode.ERR_UnmanagedConstraintNotSatisfied, "b").WithArguments("D<T>", "T", "BadType").WithLocation(7, 32),
                // (8,31): error CS8379: The type 'string' must be a non-nullable value type, along with all fields at any level of nesting, in order to use it as parameter 'T' in the generic type or method 'D<T>'
                //     public abstract D<string> c();                  // reference type
                Diagnostic(ErrorCode.ERR_UnmanagedConstraintNotSatisfied, "c").WithArguments("D<T>", "T", "string").WithLocation(8, 31),
                // (11,26): error CS8379: The type 'W' must be a non-nullable value type, along with all fields at any level of nesting, in order to use it as parameter 'T' in the generic type or method 'D<T>'
                //     public abstract D<W> f();                       // unconstrained generic type
                Diagnostic(ErrorCode.ERR_UnmanagedConstraintNotSatisfied, "f").WithArguments("D<T>", "T", "W").WithLocation(11, 26));
        }
 
        [Fact]
        public void UnmanagedConstraint_Before_7_3()
        {
            var code = @"
public class Test<T> where T : unmanaged
{
}";
 
            var oldOptions = new CSharpParseOptions(LanguageVersion.CSharp7_2);
 
            CreateCompilation(code, parseOptions: oldOptions).VerifyDiagnostics(
                // (2,32): error CS8320: Feature 'unmanaged generic type constraints' is not available in C# 7.2. Please use language version 7.3 or greater.
                // public class Test<T> where T : unmanaged
                Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7_2, "unmanaged").WithArguments("unmanaged generic type constraints", "7.3").WithLocation(2, 32));
 
            var reference = CreateCompilation(code).EmitToImageReference();
 
            var legacyCode = @"
class Legacy
{
    void M()
    {
        var a = new Test<int>();        // valid
        var b = new Test<Legacy>();     // invalid
    }
}";
 
            CreateCompilation(legacyCode, parseOptions: oldOptions, references: new[] { reference }).VerifyDiagnostics(
                // (7,26): error CS8377: The type 'Legacy' must be a non-nullable value type, along with all fields at any level of nesting, in order to use it as parameter 'T' in the generic type or method 'Test<T>'
                //         var b = new Test<Legacy>();     // invalid
                Diagnostic(ErrorCode.ERR_UnmanagedConstraintNotSatisfied, "Legacy").WithArguments("Test<T>", "T", "Legacy").WithLocation(7, 26));
        }
 
        [Fact]
        public void UnmanagedConstraint_IsReflectedInSymbols_Alone_Type()
        {
            var code = "public class Test<T> where T : unmanaged { }";
 
            Action<ModuleSymbol> validator = module =>
            {
                var typeParameter = module.GlobalNamespace.GetTypeMember("Test").TypeParameters.Single();
 
                Assert.True(typeParameter.IsValueType);
                Assert.False(typeParameter.IsReferenceType);
                Assert.True(typeParameter.HasUnmanagedTypeConstraint);
                Assert.True(typeParameter.HasValueTypeConstraint);
                Assert.False(typeParameter.HasReferenceTypeConstraint);
                Assert.False(typeParameter.HasConstructorConstraint);
                Assert.Empty(typeParameter.ConstraintTypes());
            };
 
            CompileAndVerify(code, sourceSymbolValidator: validator, symbolValidator: validator);
        }
 
        [Fact]
        public void UnmanagedConstraint_IsReflectedInSymbols_Alone_Method()
        {
            var code = @"
public class Test
{
    public void M<T>() where T : unmanaged {}
}";
 
            Action<ModuleSymbol> validator = module =>
            {
                var typeParameter = module.GlobalNamespace.GetTypeMember("Test").GetMethod("M").TypeParameters.Single();
 
                Assert.True(typeParameter.IsValueType);
                Assert.False(typeParameter.IsReferenceType);
                Assert.True(typeParameter.HasUnmanagedTypeConstraint);
                Assert.True(typeParameter.HasValueTypeConstraint);
                Assert.False(typeParameter.HasReferenceTypeConstraint);
                Assert.False(typeParameter.HasConstructorConstraint);
                Assert.Empty(typeParameter.ConstraintTypes());
            };
 
            CompileAndVerify(code, sourceSymbolValidator: validator, symbolValidator: validator);
        }
 
        [Fact]
        public void UnmanagedConstraint_IsReflectedInSymbols_Alone_Delegate()
        {
            var code = "public delegate void D<T>() where T : unmanaged;";
 
            Action<ModuleSymbol> validator = module =>
            {
                var typeParameter = module.GlobalNamespace.GetTypeMember("D").TypeParameters.Single();
 
                Assert.True(typeParameter.IsValueType);
                Assert.False(typeParameter.IsReferenceType);
                Assert.True(typeParameter.HasUnmanagedTypeConstraint);
                Assert.True(typeParameter.HasValueTypeConstraint);
                Assert.False(typeParameter.HasReferenceTypeConstraint);
                Assert.False(typeParameter.HasConstructorConstraint);
                Assert.Empty(typeParameter.ConstraintTypes());
            };
 
            CompileAndVerify(code, sourceSymbolValidator: validator, symbolValidator: validator);
        }
 
        [Fact]
        public void UnmanagedConstraint_IsReflectedInSymbols_Alone_LocalFunction()
        {
            var code = @"
public class Test
{
    public void M()
    {
        void N<T>() where T : unmanaged
        {
        }
    }
}";
 
            CompileAndVerify(code, options: TestOptions.ReleaseDll.WithMetadataImportOptions(MetadataImportOptions.All), symbolValidator: module =>
            {
                var typeParameter = module.ContainingAssembly.GetTypeByMetadataName("Test").GetMethod("<M>g__N|0_0").TypeParameters.Single();
 
                Assert.True(typeParameter.IsValueType);
                Assert.False(typeParameter.IsReferenceType);
                Assert.True(typeParameter.HasUnmanagedTypeConstraint);
                Assert.True(typeParameter.HasValueTypeConstraint);
                Assert.False(typeParameter.HasReferenceTypeConstraint);
                Assert.False(typeParameter.HasConstructorConstraint);
                Assert.Empty(typeParameter.ConstraintTypes());
            });
        }
 
        [Fact]
        public void UnmanagedConstraint_EnforcedInInheritanceChain_Downwards_Source()
        {
            CreateCompilation(@"
struct Test
{
    public string RefMember { get; set; }
}
public abstract class A
{
    public abstract void M<T>() where T : unmanaged;
}
public class B : A
{
    public override void M<T>() { }
 
    public void Test()
    {
        this.M<int>();
        this.M<string>();
        this.M<Test>();
    }
}").VerifyDiagnostics(
                // (17,14): error CS8379: The type 'string' must be a non-nullable value type, along with all fields at any level of nesting, in order to use it as parameter 'T' in the generic type or method 'B.M<T>()'
                //         this.M<string>();
                Diagnostic(ErrorCode.ERR_UnmanagedConstraintNotSatisfied, "M<string>").WithArguments("B.M<T>()", "T", "string").WithLocation(17, 14),
                // (18,14): error CS8379: The type 'Test' must be a non-nullable value type, along with all fields at any level of nesting, in order to use it as parameter 'T' in the generic type or method 'B.M<T>()'
                //         this.M<Test>();
                Diagnostic(ErrorCode.ERR_UnmanagedConstraintNotSatisfied, "M<Test>").WithArguments("B.M<T>()", "T", "Test").WithLocation(18, 14)
                );
        }
 
        [Fact]
        public void UnmanagedConstraint_EnforcedInInheritanceChain_Downwards_Reference()
        {
            var reference = CreateCompilation(@"
public abstract class A
{
    public abstract void M<T>() where T : unmanaged;
}").EmitToImageReference();
 
            CreateCompilation(@"
struct Test
{
    public string RefMember { get; set; }
}
public class B : A
{
    public override void M<T>() { }
 
    public void Test()
    {
        this.M<int>();
        this.M<string>();
        this.M<Test>();
    }
}", references: new[] { reference }).VerifyDiagnostics(
                // (13,14): error CS8379: The type 'string' must be a non-nullable value type, along with all fields at any level of nesting, in order to use it as parameter 'T' in the generic type or method 'B.M<T>()'
                //         this.M<string>();
                Diagnostic(ErrorCode.ERR_UnmanagedConstraintNotSatisfied, "M<string>").WithArguments("B.M<T>()", "T", "string").WithLocation(13, 14),
                // (14,14): error CS8379: The type 'Test' must be a non-nullable value type, along with all fields at any level of nesting, in order to use it as parameter 'T' in the generic type or method 'B.M<T>()'
                //         this.M<Test>();
                Diagnostic(ErrorCode.ERR_UnmanagedConstraintNotSatisfied, "M<Test>").WithArguments("B.M<T>()", "T", "Test").WithLocation(14, 14)
                );
        }
 
        [Fact]
        public void UnmanagedConstraint_EnforcedInInheritanceChain_Upwards_Source()
        {
            CreateCompilation(@"
public abstract class A
{
    public abstract void M<T>();
}
public class B : A
{
    public override void M<T>() where T : unmanaged { }
}").VerifyDiagnostics(
                // (8,43): error CS0460: Constraints for override and explicit interface implementation methods are inherited from the base method, so they cannot be specified directly, except for either a 'class', or a 'struct' constraint.
                //     public override void M<T>() where T : unmanaged { }
                Diagnostic(ErrorCode.ERR_OverrideWithConstraints, "unmanaged").WithLocation(8, 43));
        }
 
        [Fact]
        public void UnmanagedConstraint_StructMismatchInImplements()
        {
            CreateCompilation(@"
public struct Segment<T> {
    public T[] array;
}
 
public interface I1<in T> where T : unmanaged
{
    void Test<G>(G x) where G : unmanaged;
}
 
public class C2<T> : I1<T> where T : struct
{
    public void Test<G>(G x) where G : struct
    {
        I1<T> i = this;
        i.Test(default(Segment<int>));
    }
}
").VerifyDiagnostics(
                // (11,14): error CS8377: The type 'T' must be a non-nullable value type, along with all fields at any level of nesting, in order to use it as parameter 'T' in the generic type or method 'I1<T>'
                // public class C2<T> : I1<T> where T : struct
                Diagnostic(ErrorCode.ERR_UnmanagedConstraintNotSatisfied, "C2").WithArguments("I1<T>", "T", "T").WithLocation(11, 14),
                // (13,17): error CS0425: The constraints for type parameter 'G' of method 'C2<T>.Test<G>(G)' must match the constraints for type parameter 'G' of interface method 'I1<T>.Test<G>(G)'. Consider using an explicit interface implementation instead.
                //     public void Test<G>(G x) where G : struct
                Diagnostic(ErrorCode.ERR_ImplBadConstraints, "Test").WithArguments("G", "C2<T>.Test<G>(G)", "G", "I1<T>.Test<G>(G)").WithLocation(13, 17),
                // (15,12): error CS8377: The type 'T' must be a non-nullable value type, along with all fields at any level of nesting, in order to use it as parameter 'T' in the generic type or method 'I1<T>'
                //         I1<T> i = this;
                Diagnostic(ErrorCode.ERR_UnmanagedConstraintNotSatisfied, "T").WithArguments("I1<T>", "T", "T").WithLocation(15, 12),
                // (16,11): error CS8377: The type 'Segment<int>' must be a non-nullable value type, along with all fields at any level of nesting, in order to use it as parameter 'G' in the generic type or method 'I1<T>.Test<G>(G)'
                //         i.Test(default(Segment<int>));
                Diagnostic(ErrorCode.ERR_UnmanagedConstraintNotSatisfied, "Test").WithArguments("I1<T>.Test<G>(G)", "G", "Segment<int>").WithLocation(16, 11)
                );
        }
 
        [Fact]
        public void UnmanagedConstraint_TypeMismatchInImplements()
        {
            CreateCompilation(@"
public interface I1<in T> where T : unmanaged, System.IDisposable
{
    void Test<G>(G x) where G : unmanaged, System.Enum;
}
 
public class C2<T> : I1<T> where T : unmanaged
{
    public void Test<G>(G x) where G : unmanaged
    {
        I1<T> i = this;
        i.Test(default(System.AttributeTargets)); // <-- this one is OK
        i.Test(0);
    }
}
").VerifyDiagnostics(
                // (7,14): error CS0314: The type 'T' cannot be used as type parameter 'T' in the generic type or method 'I1<T>'. There is no boxing conversion or type parameter conversion from 'T' to 'System.IDisposable'.
                // public class C2<T> : I1<T> where T : unmanaged
                Diagnostic(ErrorCode.ERR_GenericConstraintNotSatisfiedTyVar, "C2").WithArguments("I1<T>", "System.IDisposable", "T", "T").WithLocation(7, 14),
                // (9,17): error CS0425: The constraints for type parameter 'G' of method 'C2<T>.Test<G>(G)' must match the constraints for type parameter 'G' of interface method 'I1<T>.Test<G>(G)'. Consider using an explicit interface implementation instead.
                //     public void Test<G>(G x) where G : unmanaged
                Diagnostic(ErrorCode.ERR_ImplBadConstraints, "Test").WithArguments("G", "C2<T>.Test<G>(G)", "G", "I1<T>.Test<G>(G)").WithLocation(9, 17),
                // (11,12): error CS0314: The type 'T' cannot be used as type parameter 'T' in the generic type or method 'I1<T>'. There is no boxing conversion or type parameter conversion from 'T' to 'System.IDisposable'.
                //         I1<T> i = this;
                Diagnostic(ErrorCode.ERR_GenericConstraintNotSatisfiedTyVar, "T").WithArguments("I1<T>", "System.IDisposable", "T", "T").WithLocation(11, 12),
                // (13,11): error CS0315: The type 'int' cannot be used as type parameter 'G' in the generic type or method 'I1<T>.Test<G>(G)'. There is no boxing conversion from 'int' to 'System.Enum'.
                //         i.Test(0);
                Diagnostic(ErrorCode.ERR_GenericConstraintNotSatisfiedValType, "Test").WithArguments("I1<T>.Test<G>(G)", "System.Enum", "G", "int").WithLocation(13, 11)
                );
        }
 
        [Fact]
        public void UnmanagedConstraint_TypeMismatchInImplementsMeta()
        {
            var reference = CreateCompilation(@"
public interface I1<in T> where T : unmanaged, System.IDisposable
{
    void Test<G>(G x) where G : unmanaged, System.Enum;
}
").EmitToImageReference();
 
            CreateCompilation(@"
public class C2<T> : I1<T> where T : unmanaged
{
    public void Test<G>(G x) where G : unmanaged
    {
        I1<T> i = this;
        i.Test(default(System.AttributeTargets)); // <-- this one is OK
        i.Test(0);
    }
}", references: new[] { reference }).VerifyDiagnostics(
                // (2,14): error CS0314: The type 'T' cannot be used as type parameter 'T' in the generic type or method 'I1<T>'. There is no boxing conversion or type parameter conversion from 'T' to 'System.IDisposable'.
                // public class C2<T> : I1<T> where T : unmanaged
                Diagnostic(ErrorCode.ERR_GenericConstraintNotSatisfiedTyVar, "C2").WithArguments("I1<T>", "System.IDisposable", "T", "T").WithLocation(2, 14),
                // (4,17): error CS0425: The constraints for type parameter 'G' of method 'C2<T>.Test<G>(G)' must match the constraints for type parameter 'G' of interface method 'I1<T>.Test<G>(G)'. Consider using an explicit interface implementation instead.
                //     public void Test<G>(G x) where G : unmanaged
                Diagnostic(ErrorCode.ERR_ImplBadConstraints, "Test").WithArguments("G", "C2<T>.Test<G>(G)", "G", "I1<T>.Test<G>(G)").WithLocation(4, 17),
                // (6,12): error CS0314: The type 'T' cannot be used as type parameter 'T' in the generic type or method 'I1<T>'. There is no boxing conversion or type parameter conversion from 'T' to 'System.IDisposable'.
                //         I1<T> i = this;
                Diagnostic(ErrorCode.ERR_GenericConstraintNotSatisfiedTyVar, "T").WithArguments("I1<T>", "System.IDisposable", "T", "T").WithLocation(6, 12),
                // (8,11): error CS0315: The type 'int' cannot be used as type parameter 'G' in the generic type or method 'I1<T>.Test<G>(G)'. There is no boxing conversion from 'int' to 'System.Enum'.
                //         i.Test(0);
                Diagnostic(ErrorCode.ERR_GenericConstraintNotSatisfiedValType, "Test").WithArguments("I1<T>.Test<G>(G)", "System.Enum", "G", "int").WithLocation(8, 11)
                );
        }
 
        [Fact]
        public void UnmanagedConstraint_TypeMismatchInImplementsMeta2()
        {
            var reference = CreateCompilation(@"
    public interface I1
    {
        void Test<G>(ref G x) where G : unmanaged, System.IDisposable;
    }
").EmitToImageReference();
 
            var reference1 = CreateCompilation(@"
public class C1 : I1
{
    void I1.Test<G>(ref G x)
    {
        x.Dispose();
    }
}", references: new[] { reference }).EmitToImageReference(); ;
 
            CompileAndVerify(@"
struct S : System.IDisposable
{
    public int a;
 
    public void Dispose()
    {
        a += 123;
    }
}
 
class Test
{
    static void Main()
    {
        S local = default;
        I1 i = new C1();
        i.Test(ref local);
        System.Console.WriteLine(local.a);
    }
}",
 
                // NOTE: must pass verification (IDisposable constraint is copied over to the implementing method) 
                options: TestOptions.UnsafeReleaseExe, references: new[] { reference, reference1 }, verify: Verification.Passes, expectedOutput: "123");
        }
 
        [Fact]
        public void UnmanagedConstraint_EnforcedInInheritanceChain_Upwards_Reference()
        {
            var reference = CreateCompilation(@"
public abstract class A
{
    public abstract void M<T>();
}").EmitToImageReference();
 
            CreateCompilation(@"
public class B : A
{
    public override void M<T>() where T : unmanaged { }
}", references: new[] { reference }).VerifyDiagnostics(
                // (4,43): error CS0460: Constraints for override and explicit interface implementation methods are inherited from the base method, so they cannot be specified directly, except for either a 'class', or a 'struct' constraint.
                //     public override void M<T>() where T : unmanaged { }
                Diagnostic(ErrorCode.ERR_OverrideWithConstraints, "unmanaged").WithLocation(4, 43));
        }
 
        [ConditionalFact(typeof(ClrOnly), Reason = "https://github.com/mono/mono/issues/10782")]
        public void UnmanagedConstraints_PointerOperations_Invalid()
        {
            CreateCompilation(@"
class Test
{
    void M<T>(T arg) where T : unmanaged
    {
    }
    void N()
    {
        M(""test"");
    }
}").VerifyDiagnostics(
                // (9,9): error CS8379: The type 'string' must be a non-nullable value type, along with all fields at any level of nesting, in order to use it as parameter 'T' in the generic type or method 'Test.M<T>(T)'
                //         M("test");
                Diagnostic(ErrorCode.ERR_UnmanagedConstraintNotSatisfied, "M").WithArguments("Test.M<T>(T)", "T", "string").WithLocation(9, 9));
        }
 
        [ConditionalTheory(typeof(ClrOnly), Reason = "https://github.com/mono/mono/issues/10782")]
        [InlineData("(sbyte)1", "System.SByte", 1)]
        [InlineData("(byte)1", "System.Byte", 1)]
        [InlineData("(short)1", "System.Int16", 2)]
        [InlineData("(ushort)1", "System.UInt16", 2)]
        [InlineData("(int)1", "System.Int32", 4)]
        [InlineData("(uint)1", "System.UInt32", 4)]
        [InlineData("(long)1", "System.Int64", 8)]
        [InlineData("(ulong)1", "System.UInt64", 8)]
        [InlineData("'a'", "System.Char", 2)]
        [InlineData("(float)1", "System.Single", 4)]
        [InlineData("(double)1", "System.Double", 8)]
        [InlineData("(decimal)1", "System.Decimal", 16)]
        [InlineData("false", "System.Boolean", 1)]
        [InlineData("E.A", "E", 4)]
        [InlineData("new S { a = 1, b = 2, c = 3 }", "S", 12)]
        public void UnmanagedConstraints_PointerOperations_SimpleTypes(string arg, string type, int size)
        {
            CompileAndVerify(@"
enum E
{
    A
}
struct S
{
    public int a;
    public int b;
    public int c;
}
unsafe class Test
{
    static T* M<T>(T arg) where T : unmanaged
    {
        T* ptr = &arg;
        System.Console.WriteLine(ptr->GetType());   // method access
        System.Console.WriteLine(sizeof(T));        // sizeof operator
    
        T* ar = stackalloc T [10];
        return ar;
    }
    static void Main()
    {
        M(" + arg + @");
    }
}",
    options: TestOptions.UnsafeReleaseExe, verify: Verification.Fails, expectedOutput: string.Join(Environment.NewLine, type, size)).VerifyIL("Test.M<T>", @"
{
  // Code size       43 (0x2b)
  .maxstack  2
  IL_0000:  ldarga.s   V_0
  IL_0002:  conv.u
  IL_0003:  constrained. ""T""
  IL_0009:  callvirt   ""System.Type object.GetType()""
  IL_000e:  call       ""void System.Console.WriteLine(object)""
  IL_0013:  sizeof     ""T""
  IL_0019:  call       ""void System.Console.WriteLine(int)""
  IL_001e:  ldc.i4.s   10
  IL_0020:  conv.u
  IL_0021:  sizeof     ""T""
  IL_0027:  mul.ovf.un
  IL_0028:  localloc
  IL_002a:  ret
}");
        }
 
        [ConditionalFact(typeof(ClrOnly), Reason = "https://github.com/mono/mono/issues/10782")]
        public void UnmanagedConstraints_InterfaceMethod()
        {
            CompileAndVerify(@"
struct S : System.IDisposable
{
    public int a;
 
    public void Dispose()
    {
        a += 123;
    }
}
unsafe class Test
{
    static void M<T>(ref T arg) where T : unmanaged, System.IDisposable
    {
        arg.Dispose();
 
        fixed(T* ptr = &arg)
        {
            ptr->Dispose();
        }
    }
 
    static void Main()
    {
        S local = default;
        M(ref local);
        System.Console.WriteLine(local.a);
    }
}",
    options: TestOptions.UnsafeReleaseExe, verify: Verification.Fails, expectedOutput: "246").VerifyIL("Test.M<T>", @"
{
  // Code size       31 (0x1f)
  .maxstack  1
  .locals init (pinned T& V_0)
  IL_0000:  ldarg.0
  IL_0001:  constrained. ""T""
  IL_0007:  callvirt   ""void System.IDisposable.Dispose()""
  IL_000c:  ldarg.0
  IL_000d:  stloc.0
  IL_000e:  ldloc.0
  IL_000f:  conv.u
  IL_0010:  constrained. ""T""
  IL_0016:  callvirt   ""void System.IDisposable.Dispose()""
  IL_001b:  ldc.i4.0
  IL_001c:  conv.u
  IL_001d:  stloc.0
  IL_001e:  ret
}");
        }
 
        [ConditionalFact(typeof(ClrOnly), Reason = "https://github.com/mono/mono/issues/10782")]
        public void UnmanagedConstraints_CtorAndValueTypeAreEmitted()
        {
            CompileAndVerify(@"
using System.Linq;
class Program
{
    public static void M<T>() where T: unmanaged
    {
    }
 
    static void Main(string[] args)
    {
        var typeParam = typeof(Program).GetMethod(""M"").GetGenericArguments().First();
        System.Console.WriteLine(typeParam.GenericParameterAttributes);
    }
}",
    options: TestOptions.UnsafeReleaseExe, verify: Verification.Passes, expectedOutput: "NotNullableValueTypeConstraint, DefaultConstructorConstraint");
        }
 
        [ConditionalFact(typeof(ClrOnly), Reason = "https://github.com/mono/mono/issues/10782")]
        public void UnmanagedConstraints_NestedStructs_Flat()
        {
            CompileAndVerify(@"
struct TestData
{
    public int A;
    public TestData(int a)
    {
        A = a;
    }
}
unsafe class Test
{
    public static void Main()
    {
        N<TestData>();
    }
    static void N<T>() where T : unmanaged
    {
        System.Console.WriteLine(sizeof(T));
    }
}", options: TestOptions.UnsafeReleaseExe, verify: Verification.Passes, expectedOutput: "4");
        }
 
        [ConditionalFact(typeof(ClrOnly), Reason = "https://github.com/mono/mono/issues/10782")]
        public void UnmanagedConstraints_NestedStructs_Nested()
        {
            CompileAndVerify(@"
struct InnerTestData
{
    public int B;
    public InnerTestData(int b)
    {
        B = b;
    }
}
struct TestData
{
    public int A;
    public InnerTestData B;
    public TestData(int a, int b)
    {
        A = a;
        B = new InnerTestData(b);
    }
}
unsafe class Test
{
    public static void Main()
    {
        N<TestData>();
    }
    static void N<T>() where T : unmanaged
    {
        System.Console.WriteLine(sizeof(T));
    }
}", options: TestOptions.UnsafeReleaseExe, verify: Verification.Passes, expectedOutput: "8");
        }
 
        [ConditionalFact(typeof(ClrOnly), Reason = "https://github.com/mono/mono/issues/10782")]
        public void UnmanagedConstraints_NestedStructs_Error()
        {
            CreateCompilation(@"
struct InnerTestData
{
    public string B;
    public InnerTestData(string b)
    {
        B = b;
    }
}
struct TestData
{
    public int A;
    public InnerTestData B;
    public TestData(int a, string b)
    {
        A = a;
        B = new InnerTestData(b);
    }
}
class Test
{
    public static void Main()
    {
        N<TestData>();
    }
    static void N<T>() where T : unmanaged
    {
    }
}").VerifyDiagnostics(
                // (24,9): error CS8379: The type 'TestData' must be a non-nullable value type, along with all fields at any level of nesting, in order to use it as parameter 'T' in the generic type or method 'Test.N<T>()'
                //         N<TestData>();
                Diagnostic(ErrorCode.ERR_UnmanagedConstraintNotSatisfied, "N<TestData>").WithArguments("Test.N<T>()", "T", "TestData").WithLocation(24, 9));
        }
 
        [ConditionalFact(typeof(ClrOnly), Reason = "https://github.com/mono/mono/issues/10782")]
        public void UnmanagedConstraints_ExistingUnmanagedKeywordType_InScope()
        {
            CompileAndVerify(@"
class unmanaged
{
    public void Print()
    {
        System.Console.WriteLine(""success"");
    }
}
class Test
{
    public static void Main()
    {
        M(new unmanaged());
    }
    static void M<T>(T arg) where T : unmanaged
    {
        arg.Print();
    }
}", expectedOutput: "success");
        }
 
        [ConditionalFact(typeof(ClrOnly), Reason = "https://github.com/mono/mono/issues/10782")]
        public void UnmanagedConstraints_ExistingUnmanagedKeywordType_OutOfScope()
        {
            CreateCompilation(@"
namespace hidden
{
    class @unmanaged
    {
        public void Print()
        {
            System.Console.WriteLine(""success"");
        }
    }
}
class Test
{
    public static void Main()
    {
        M(""test"");
    }
    static void M<T>(T arg) where T : unmanaged
    {
        arg.Print();
    }
}").VerifyDiagnostics(
                // (16,9): error CS8379: The type 'string' must be a non-nullable value type, along with all fields at any level of nesting, in order to use it as parameter 'T' in the generic type or method 'Test.M<T>(T)'
                //         M("test");
                Diagnostic(ErrorCode.ERR_UnmanagedConstraintNotSatisfied, "M").WithArguments("Test.M<T>(T)", "T", "string").WithLocation(16, 9),
                // (20,13): error CS1061: 'T' does not contain a definition for 'Print' and no extension method 'Print' accepting a first argument of type 'T' could be found (are you missing a using directive or an assembly reference?)
                //         arg.Print();
                Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "Print").WithArguments("T", "Print").WithLocation(20, 13));
        }
 
        [ConditionalFact(typeof(ClrOnly), Reason = "https://github.com/mono/mono/issues/10782")]
        public void UnmanagedConstraints_UnmanagedIsValidForStructConstraint_Methods()
        {
            CompileAndVerify(@"
class Program
{
    static void A<T>(T arg) where T : struct
    {
        System.Console.WriteLine(arg);
    }
    static void B<T>(T arg) where T : unmanaged
    {
        A(arg);
    }
    static void Main()
    {
        B(5);
    }
}", expectedOutput: "5");
        }
 
        [ConditionalFact(typeof(ClrOnly), Reason = "https://github.com/mono/mono/issues/10782")]
        public void UnmanagedConstraints_UnmanagedIsValidForStructConstraint_Types()
        {
            CompileAndVerify(@"
class A<T> where T : struct
{
    public void M(T arg)
    {
        System.Console.WriteLine(arg);
    }
}
class B<T> : A<T> where T : unmanaged
{
}
class Program
{
    static void Main()
    {
        new B<int>().M(5);
    }
}", expectedOutput: "5");
        }
 
        [ConditionalFact(typeof(ClrOnly), Reason = "https://github.com/mono/mono/issues/10782")]
        public void UnmanagedConstraints_UnmanagedIsValidForStructConstraint_Interfaces()
        {
            CompileAndVerify(@"
interface A<T> where T : struct
{
    void M(T arg);
}
class B<T> : A<T> where T : unmanaged
{
    public void M(T arg)
    {
        System.Console.WriteLine(arg);
    }
}
class Program
{
    static void Main()
    {
        new B<int>().M(5);
    }
}", expectedOutput: "5");
        }
 
        [ConditionalFact(typeof(ClrOnly), Reason = "https://github.com/mono/mono/issues/10782")]
        public void UnmanagedConstraints_UnmanagedIsValidForStructConstraint_LocalFunctions()
        {
            CompileAndVerify(@"
class Program
{
    static void Main()
    {
        void A<T>(T arg) where T : struct
        {
            System.Console.WriteLine(arg);
        }
 
        void B<T>(T arg) where T : unmanaged
        {
            A(arg);
        }
 
        B(5);
    }
}", expectedOutput: "5");
        }
 
        [ConditionalFact(typeof(ClrOnly), Reason = "https://github.com/mono/mono/issues/10782")]
        public void UnmanagedConstraints_PointerTypeSubstitution()
        {
            var compilation = CreateCompilation(@"
unsafe public class Test
{
    public T* M<T>() where T : unmanaged => throw null;
    
    public void N()
    {
        var result = M<int>();
    }
}", options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics();
 
            var tree = compilation.SyntaxTrees.Single();
            var model = compilation.GetSemanticModel(tree, ignoreAccessibility: true);
 
            var value = ((VariableDeclaratorSyntax)tree.FindNodeOrTokenByKind(SyntaxKind.VariableDeclarator)).Initializer.Value;
            Assert.Equal("M<int>()", value.ToFullString());
 
            var symbol = (IMethodSymbol)model.GetSymbolInfo(value).Symbol;
            Assert.Equal("System.Int32*", symbol.ReturnType.ToTestDisplayString());
        }
 
        [ConditionalFact(typeof(ClrOnly), Reason = "https://github.com/mono/mono/issues/10782")]
        public void UnmanagedConstraints_CannotConstraintToTypeParameterConstrainedByUnmanaged()
        {
            CreateCompilation(@"
class Test<U> where U : unmanaged
{
    void M<T>() where T : U
    {
    }
}").VerifyDiagnostics(
                // (4,12): error CS8379: Type parameter 'U' has the 'unmanaged' constraint so 'U' cannot be used as a constraint for 'T'
                //     void M<T>() where T : U
                Diagnostic(ErrorCode.ERR_ConWithUnmanagedCon, "T").WithArguments("T", "U").WithLocation(4, 12));
        }
 
        [ConditionalFact(typeof(ClrOnly), Reason = "https://github.com/mono/mono/issues/10782")]
        public void UnmanagedConstraints_UnmanagedAsTypeConstraintName()
        {
            CreateCompilation(@"
class Test<@unmanaged> where unmanaged : System.IDisposable
{
    void M<T>(T arg) where T : unmanaged
    {
        arg.Dispose();
        arg.NonExistentMethod();
    }
}").VerifyDiagnostics(
                // (7,13): error CS1061: 'T' does not contain a definition for 'NonExistentMethod' and no extension method 'NonExistentMethod' accepting a first argument of type 'T' could be found (are you missing a using directive or an assembly reference?)
                //         arg.NonExistentMethod();
                Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "NonExistentMethod").WithArguments("T", "NonExistentMethod").WithLocation(7, 13));
        }
 
        [ConditionalFact(typeof(ClrOnly), Reason = "https://github.com/mono/mono/issues/10782")]
        public void UnmanagedConstraints_CircularReferenceToUnmanagedTypeWillBindSuccessfully()
        {
            CreateCompilation(@"
public unsafe class C<U> where U : unmanaged
{
    public void M1<T>() where T : T* { }
    public void M2<T>() where T : U* { }
}", options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(
                // (5,35): error CS0706: Invalid constraint type. A type used as a constraint must be an interface, a non-sealed class or a type parameter.
                //     public void M2<T>() where T : U* { }
                Diagnostic(ErrorCode.ERR_BadConstraintType, "U*").WithLocation(5, 35),
                // (4,35): error CS0706: Invalid constraint type. A type used as a constraint must be an interface, a non-sealed class or a type parameter.
                //     public void M1<T>() where T : T* { }
                Diagnostic(ErrorCode.ERR_BadConstraintType, "T*").WithLocation(4, 35));
        }
 
        [ConditionalFact(typeof(ClrOnly), Reason = "https://github.com/mono/mono/issues/10782")]
        public void UnmanagedConstraints_EnumWithUnmanaged()
        {
            Action<ModuleSymbol> validator = module =>
            {
                var typeParameter = module.GlobalNamespace.GetTypeMember("Test").TypeParameters.Single();
 
                Assert.True(typeParameter.HasUnmanagedTypeConstraint);
                Assert.True(typeParameter.HasValueTypeConstraint);
                Assert.False(typeParameter.HasReferenceTypeConstraint);
                Assert.False(typeParameter.HasConstructorConstraint);
 
                Assert.Equal("Enum", typeParameter.ConstraintTypes().Single().Name);
 
                Assert.True(typeParameter.IsValueType);
                Assert.False(typeParameter.IsReferenceType);
            };
 
            CompileAndVerify(
                source: "public class Test<T> where T : unmanaged, System.Enum {}",
                sourceSymbolValidator: validator,
                symbolValidator: validator);
        }
 
        [ConditionalFact(typeof(ClrOnly), Reason = "https://github.com/mono/mono/issues/10782")]
        public void UnmanagedConstraints_NestedInGenericType()
        {
            var code = @"
public class Wrapper<T>
{
    public enum E
    {
    }
 
    public struct S
    {
    }
}
public class Test
{
    void IsUnmanaged<T>() where T : unmanaged { }
    void IsEnum<T>() where T : System.Enum { }
    void IsStruct<T>() where T : struct { }
    void IsNew<T>() where T : new() { }
    
 
    void User()
    {
        IsUnmanaged<Wrapper<int>.E>();
        IsEnum<Wrapper<int>.E>();
        IsStruct<Wrapper<int>.E>();
        IsNew<Wrapper<int>.E>();
 
        IsUnmanaged<Wrapper<int>.S>();
        IsEnum<Wrapper<int>.S>();               // Invalid
        IsStruct<Wrapper<int>.S>();
        IsNew<Wrapper<int>.S>();
 
        IsUnmanaged<Wrapper<string>.E>();
        IsEnum<Wrapper<string>.E>();
        IsStruct<Wrapper<string>.E>();
        IsNew<Wrapper<string>.E>();
 
        IsUnmanaged<Wrapper<string>.S>();
        IsEnum<Wrapper<string>.S>();               // Invalid
        IsStruct<Wrapper<string>.S>();
        IsNew<Wrapper<string>.S>();
    }
}";
 
            CreateCompilation(code).VerifyDiagnostics(
                // (28,9): error CS0315: The type 'Wrapper<int>.S' cannot be used as type parameter 'T' in the generic type or method 'Test.IsEnum<T>()'. There is no boxing conversion from 'Wrapper<int>.S' to 'System.Enum'.
                //         IsEnum<Wrapper<int>.S>();               // Invalid
                Diagnostic(ErrorCode.ERR_GenericConstraintNotSatisfiedValType, "IsEnum<Wrapper<int>.S>").WithArguments("Test.IsEnum<T>()", "System.Enum", "T", "Wrapper<int>.S").WithLocation(28, 9),
                // (38,9): error CS0315: The type 'Wrapper<string>.S' cannot be used as type parameter 'T' in the generic type or method 'Test.IsEnum<T>()'. There is no boxing conversion from 'Wrapper<string>.S' to 'System.Enum'.
                //         IsEnum<Wrapper<string>.S>();               // Invalid
                Diagnostic(ErrorCode.ERR_GenericConstraintNotSatisfiedValType, "IsEnum<Wrapper<string>.S>").WithArguments("Test.IsEnum<T>()", "System.Enum", "T", "Wrapper<string>.S").WithLocation(38, 9));
        }
 
        [ConditionalFact(typeof(ClrOnly), Reason = "https://github.com/mono/mono/issues/10782")]
        public void UnmanagedConstraints_PointerInsideStruct()
        {
            CompileAndVerify(@"
unsafe struct S
{
    public int a;
    public int* b;
 
    public S(int a, int* b)
    {
        this.a = a;
        this.b = b;
    }
}
unsafe class Test
{
    static T* M<T>() where T : unmanaged
    {
        System.Console.WriteLine(typeof(T).FullName);
 
        T* ar = null;
        return ar;
    }
    static void Main()
    {
        S* ar = M<S>();
    }
}",
                options: TestOptions.UnsafeReleaseExe,
                verify: Verification.Fails,
                expectedOutput: "S");
        }
 
        [ConditionalFact(typeof(ClrOnly), Reason = "https://github.com/mono/mono/issues/10782")]
        public void UnmanagedConstraint_LambdaTypeParameters()
        {
            CompileAndVerify(@"
public delegate T D<T>() where T : unmanaged;
public class Test<U1> where U1 : unmanaged
{
    public static void Print<T>(D<T> lambda) where T : unmanaged
    {
        System.Console.WriteLine(lambda());
    }
    public static void User1(U1 arg)
    {
        Print(() => arg);
    }
    public static void User2<U2>(U2 arg) where U2 : unmanaged
    {
        Print(() => arg);
    }
}
public class Program
{
    public static void Main()
    {
        // Testing the constraint when the lambda type parameter is both coming from an enclosing type, or copied to the generated lambda class
 
        Test<int>.User1(1);
        Test<int>.User2(2);
    }
}",
                expectedOutput: @"
1
2",
                options: TestOptions.ReleaseExe.WithMetadataImportOptions(MetadataImportOptions.All),
                symbolValidator: module =>
                {
                    Assert.True(module.ContainingAssembly.GetTypeByMetadataName("D`1").TypeParameters.Single().HasUnmanagedTypeConstraint);
                    Assert.True(module.ContainingAssembly.GetTypeByMetadataName("Test`1").TypeParameters.Single().HasUnmanagedTypeConstraint);
                    Assert.True(module.ContainingAssembly.GetTypeByMetadataName("Test`1").GetTypeMember("<>c__DisplayClass2_0").TypeParameters.Single().HasUnmanagedTypeConstraint);
                });
        }
 
        [ConditionalFact(typeof(ClrOnly), Reason = "https://github.com/mono/mono/issues/10782")]
        public void UnmanagedConstraint_IsConsideredDuringOverloadResolution()
        {
            CompileAndVerify(@"
public class Program
{
    static void Test<T>(T arg) where T : unmanaged
    {
        System.Console.WriteLine(""Unmanaged: "" + arg);
    }
    static void Test(object arg)
    {
        System.Console.WriteLine(""Object: "" + arg);
    }
 
    static void User<U>(U arg) where U : unmanaged
    {
        Test(1);                // should pick up the first, as it is better than the second one (which requires a conversion)
        Test(""2"");            // should pick up the second, as it is the only candidate
        Test(arg);              // should pick up the first, as it is the only candidate
    }
    static void Main()
    {
        User(3);
    }
}",
                expectedOutput: @"
Unmanaged: 1
Object: 2
Unmanaged: 3");
        }
 
        [ConditionalFact(typeof(ClrOnly), Reason = "https://github.com/mono/mono/issues/10782")]
        [WorkItem(25654, "https://github.com/dotnet/roslyn/issues/25654")]
        public void UnmanagedConstraint_PointersTypeInference()
        {
            var compilation = CreateCompilation(@"
class C
{
    unsafe void M<T>(T* a) where T : unmanaged
    {
        var p = stackalloc T[10];
        M(p);
    }
}", options: TestOptions.UnsafeReleaseDll);
 
            compilation.VerifyDiagnostics();
 
            var tree = compilation.SyntaxTrees.Single();
            var model = compilation.GetSemanticModel(tree);
 
            var call = tree.GetRoot().DescendantNodes().OfType<InvocationExpressionSyntax>().Single();
            var inferredMethod = (IMethodSymbol)model.GetSymbolInfo(call).Symbol;
            var declaredMethod = compilation.GlobalNamespace.GetTypeMember("C").GetMethod("M");
 
            Assert.Equal(declaredMethod.GetPublicSymbol(), inferredMethod);
            Assert.Equal(declaredMethod.TypeParameters.Single().GetPublicSymbol(), inferredMethod.TypeArguments.Single());
        }
 
        [ConditionalFact(typeof(ClrOnly), Reason = "https://github.com/mono/mono/issues/10782")]
        [WorkItem(25654, "https://github.com/dotnet/roslyn/issues/25654")]
        public void UnmanagedConstraint_PointersTypeInference_CallFromADifferentMethod()
        {
            var compilation = CreateCompilation(@"
class C
{
    unsafe void M<T>(T* a) where T : unmanaged
    {
    }
    unsafe void N()
    {
        var p = stackalloc int[10];
        M(p);
    }
}", options: TestOptions.UnsafeReleaseDll);
 
            compilation.VerifyDiagnostics();
 
            var tree = compilation.SyntaxTrees.Single();
            var model = compilation.GetSemanticModel(tree);
 
            var call = tree.GetRoot().DescendantNodes().OfType<InvocationExpressionSyntax>().Single();
            var inferredMethod = (IMethodSymbol)model.GetSymbolInfo(call).Symbol;
            var declaredMethod = compilation.GlobalNamespace.GetTypeMember("C").GetMethod("M");
 
            Assert.Equal(declaredMethod.GetPublicSymbol(), inferredMethod.ConstructedFrom());
            Assert.Equal(SpecialType.System_Int32, inferredMethod.TypeArguments.Single().SpecialType);
        }
 
        [ConditionalFact(typeof(ClrOnly), Reason = "https://github.com/mono/mono/issues/10782")]
        [WorkItem(25654, "https://github.com/dotnet/roslyn/issues/25654")]
        public void UnmanagedConstraint_PointersTypeInference_WithOtherArgs()
        {
            var compilation = CreateCompilation(@"
unsafe class C
{
    static void M<T>(T* a, T b) where T : unmanaged
    {
        M(null, b);
    }
}", options: TestOptions.UnsafeReleaseDll);
 
            compilation.VerifyDiagnostics();
 
            var tree = compilation.SyntaxTrees.Single();
            var model = compilation.GetSemanticModel(tree);
 
            var call = tree.GetRoot().DescendantNodes().OfType<InvocationExpressionSyntax>().Single();
            var inferredMethod = (IMethodSymbol)model.GetSymbolInfo(call).Symbol;
            var declaredMethod = compilation.GlobalNamespace.GetTypeMember("C").GetMethod("M");
 
            Assert.Equal(declaredMethod.GetPublicSymbol(), inferredMethod);
            Assert.Equal(declaredMethod.TypeParameters.Single().GetPublicSymbol(), inferredMethod.TypeArguments.Single());
        }
 
        [ConditionalFact(typeof(ClrOnly), Reason = "https://github.com/mono/mono/issues/10782")]
        [WorkItem(25654, "https://github.com/dotnet/roslyn/issues/25654")]
        public void UnmanagedConstraint_PointersTypeInference_WithOtherArgs_CallFromADifferentMethod()
        {
            var compilation = CreateCompilation(@"
unsafe class C
{
    static void M<T>(T* a, T b) where T : unmanaged
    {
    }
    static void N()
    {
        M(null, 5);
    }
}", options: TestOptions.UnsafeReleaseDll);
 
            compilation.VerifyDiagnostics();
 
            var tree = compilation.SyntaxTrees.Single();
            var model = compilation.GetSemanticModel(tree);
 
            var call = tree.GetRoot().DescendantNodes().OfType<InvocationExpressionSyntax>().Single();
            var inferredMethod = (IMethodSymbol)model.GetSymbolInfo(call).Symbol;
            var declaredMethod = compilation.GlobalNamespace.GetTypeMember("C").GetMethod("M");
 
            Assert.Equal(declaredMethod.GetPublicSymbol(), inferredMethod.ConstructedFrom());
            Assert.Equal(SpecialType.System_Int32, inferredMethod.TypeArguments.Single().SpecialType);
        }
 
        [ConditionalFact(typeof(ClrOnly), Reason = "https://github.com/mono/mono/issues/10782")]
        [WorkItem(25654, "https://github.com/dotnet/roslyn/issues/25654")]
        public void UnmanagedConstraint_PointersTypeInference_Errors()
        {
            CreateCompilation(@"
unsafe class C
{
    void Unmanaged<T>(T* a) where T : unmanaged
    {
    }
    void UnmanagedWithInterface<T>(T* a) where T : unmanaged, System.IDisposable
    {
    }
    void Test()
    {
        int a = 0;
 
        Unmanaged(0);                       // fail (type inference)
        Unmanaged(a);                       // fail (type inference)
        Unmanaged(&a);                      // succeed (unmanaged type pointer)
 
        UnmanagedWithInterface(0);          // fail (type inference)
        UnmanagedWithInterface(a);          // fail (type inference)
        UnmanagedWithInterface(&a);         // fail (does not match interface)
    }
}", options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(
                // (14,9): error CS0411: The type arguments for method 'C.Unmanaged<T>(T*)' cannot be inferred from the usage. Try specifying the type arguments explicitly.
                //         Unmanaged(0);                       // fail (type inference)
                Diagnostic(ErrorCode.ERR_CantInferMethTypeArgs, "Unmanaged").WithArguments("C.Unmanaged<T>(T*)").WithLocation(14, 9),
                // (15,9): error CS0411: The type arguments for method 'C.Unmanaged<T>(T*)' cannot be inferred from the usage. Try specifying the type arguments explicitly.
                //         Unmanaged(a);                       // fail (type inference)
                Diagnostic(ErrorCode.ERR_CantInferMethTypeArgs, "Unmanaged").WithArguments("C.Unmanaged<T>(T*)").WithLocation(15, 9),
                // (18,9): error CS0411: The type arguments for method 'C.UnmanagedWithInterface<T>(T*)' cannot be inferred from the usage. Try specifying the type arguments explicitly.
                //         UnmanagedWithInterface(0);          // fail (type inference)
                Diagnostic(ErrorCode.ERR_CantInferMethTypeArgs, "UnmanagedWithInterface").WithArguments("C.UnmanagedWithInterface<T>(T*)").WithLocation(18, 9),
                // (19,9): error CS0411: The type arguments for method 'C.UnmanagedWithInterface<T>(T*)' cannot be inferred from the usage. Try specifying the type arguments explicitly.
                //         UnmanagedWithInterface(a);          // fail (type inference)
                Diagnostic(ErrorCode.ERR_CantInferMethTypeArgs, "UnmanagedWithInterface").WithArguments("C.UnmanagedWithInterface<T>(T*)").WithLocation(19, 9),
                // (20,9): error CS0315: The type 'int' cannot be used as type parameter 'T' in the generic type or method 'C.UnmanagedWithInterface<T>(T*)'. There is no boxing conversion from 'int' to 'System.IDisposable'.
                //         UnmanagedWithInterface(&a);         // fail (does not match interface)
                Diagnostic(ErrorCode.ERR_GenericConstraintNotSatisfiedValType, "UnmanagedWithInterface").WithArguments("C.UnmanagedWithInterface<T>(T*)", "System.IDisposable", "T", "int").WithLocation(20, 9));
        }
 
        [Fact]
        public void UnmanagedGenericStructPointer()
        {
            var code = @"
public struct MyStruct<T>
{
    public T field;
}
 
public class C
{
    public unsafe void M()
    {
        MyStruct<int> myStruct;
        M2(&myStruct);
    }
 
    public unsafe void M2(MyStruct<int>* ms) { }
}
";
            CreateCompilation(code, options: TestOptions.UnsafeReleaseDll)
                .VerifyDiagnostics();
        }
 
        [Fact]
        public void ManagedGenericStructPointer()
        {
            var code = @"
public struct MyStruct<T>
{
    public T field;
}
 
public class C
{
    public unsafe void M()
    {
        MyStruct<string> myStruct;
        M2(&myStruct);
    }
 
    public unsafe void M2<T>(MyStruct<T>* ms) where T : unmanaged { }
}
";
            CreateCompilation(code, options: TestOptions.UnsafeReleaseDll)
                .VerifyDiagnostics(
                    // (12,9): error CS8377: The type 'string' must be a non-nullable value type, along with all fields at any level of nesting, in order to use it as parameter 'T' in the generic type or method 'C.M2<T>(MyStruct<T>*)'
                    //         M2(&myStruct);
                    Diagnostic(ErrorCode.ERR_UnmanagedConstraintNotSatisfied, "M2").WithArguments("C.M2<T>(MyStruct<T>*)", "T", "string").WithLocation(12, 9),
                    // (12,12): warning CS8500: This takes the address of, gets the size of, or declares a pointer to a managed type ('MyStruct<string>')
                    //         M2(&myStruct);
                    Diagnostic(ErrorCode.WRN_ManagedAddr, "&myStruct").WithArguments("MyStruct<string>").WithLocation(12, 12));
        }
 
        [Fact]
        public void UnmanagedGenericConstraintStructPointer()
        {
            var code = @"
public struct MyStruct<T> where T : unmanaged
{
    public T field;
}
 
public class C
{
    public unsafe void M()
    {
        MyStruct<int> myStruct;
        M2(&myStruct);
    }
 
    public unsafe void M2(MyStruct<int>* ms) { }
}
";
            CreateCompilation(code, options: TestOptions.UnsafeReleaseDll)
                .VerifyDiagnostics();
        }
 
        [Fact]
        public void UnmanagedGenericConstraintNestedStructPointer()
        {
            var code = @"
public struct MyStruct<T> where T : unmanaged
{
    public T field;
}
 
public struct OuterStruct
{
    public int x;
    public InnerStruct inner;
}
 
public struct InnerStruct
{
    public int y;
}
 
public class C
{
    public unsafe void M()
    {
        MyStruct<OuterStruct> myStruct;
        M2(&myStruct);
    }
 
    public unsafe void M2(MyStruct<OuterStruct>* ms) { }
}
";
            CreateCompilation(code, options: TestOptions.UnsafeReleaseDll)
                .VerifyDiagnostics();
        }
 
        [Fact]
        public void UnmanagedGenericConstraintNestedGenericStructPointer()
        {
            var code = @"
public struct MyStruct<T> where T : unmanaged
{
    public T field;
}
 
public struct InnerStruct<U>
{
    public U value;
}
 
public class C
{
    public unsafe void M()
    {
        MyStruct<InnerStruct<int>> myStruct;
        M2(&myStruct);
    }
 
    public unsafe void M2(MyStruct<InnerStruct<int>>* ms) { }
}
";
            CreateCompilation(code, options: TestOptions.UnsafeReleaseDll)
                .VerifyDiagnostics();
 
            CreateCompilation(code, options: TestOptions.UnsafeReleaseDll, parseOptions: TestOptions.Regular7_3)
                .VerifyDiagnostics(
                // (16,18): error CS8370: Feature 'unmanaged constructed types' is not available in C# 7.3. Please use language version 8.0 or greater.
                //         MyStruct<InnerStruct<int>> myStruct;
                Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7_3, "InnerStruct<int>").WithArguments("unmanaged constructed types", "8.0").WithLocation(16, 18),
                // (17,12): error CS8370: Feature 'unmanaged constructed types' is not available in C# 7.3. Please use language version 8.0 or greater.
                //         M2(&myStruct);
                Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7_3, "&myStruct").WithArguments("unmanaged constructed types", "8.0").WithLocation(17, 12),
                // (20,55): error CS8370: Feature 'unmanaged constructed types' is not available in C# 7.3. Please use language version 8.0 or greater.
                //     public unsafe void M2(MyStruct<InnerStruct<int>>* ms) { }
                Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7_3, "ms").WithArguments("unmanaged constructed types", "8.0").WithLocation(20, 55),
                // (20,55): error CS8370: Feature 'unmanaged constructed types' is not available in C# 7.3. Please use language version 8.0 or greater.
                //     public unsafe void M2(MyStruct<InnerStruct<int>>* ms) { }
                Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7_3, "ms").WithArguments("unmanaged constructed types", "8.0").WithLocation(20, 55));
        }
 
        [Fact]
        public void UnmanagedGenericStructMultipleConstraints()
        {
            // A diagnostic will only be produced for the first violated constraint.
            var code = @"
public struct MyStruct<T> where T : unmanaged, System.IDisposable
{
    public T field;
}
 
public struct InnerStruct<U>
{
    public U value;
}
 
public class C
{
    public unsafe void M()
    {
        MyStruct<InnerStruct<int>> myStruct = default;
        _ = myStruct;
    }
}
";
            CreateCompilation(code, options: TestOptions.UnsafeReleaseDll)
                .VerifyDiagnostics(
                    // (16,18): error CS0315: The type 'InnerStruct<int>' cannot be used as type parameter 'T' in the generic type or method 'MyStruct<T>'. There is no boxing conversion from 'InnerStruct<int>' to 'System.IDisposable'.
                    //         MyStruct<InnerStruct<int>> myStruct = default;
                    Diagnostic(ErrorCode.ERR_GenericConstraintNotSatisfiedValType, "InnerStruct<int>").WithArguments("MyStruct<T>", "System.IDisposable", "T", "InnerStruct<int>").WithLocation(16, 18)
                );
 
            CreateCompilation(code, options: TestOptions.UnsafeReleaseDll, parseOptions: TestOptions.Regular7_3)
                .VerifyDiagnostics(
                // (16,18): error CS8652: The feature 'unmanaged constructed types' is not available in C# 7.3. Please use language version 8.0 or greater.
                //         MyStruct<InnerStruct<int>> myStruct = default;
                Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7_3, "InnerStruct<int>").WithArguments("unmanaged constructed types", "8.0").WithLocation(16, 18)
                );
        }
 
        [Fact]
        public void UnmanagedGenericConstraintPartialConstructedStruct()
        {
            var code = @"
public struct MyStruct<T> where T : unmanaged
{
    public T field;
}
 
public class C
{
    public unsafe void M<U>()
    {
        MyStruct<U> myStruct;
        M2<U>(&myStruct);
    }
 
    public unsafe void M2<V>(MyStruct<V>* ms) { }
}
";
            CreateCompilation(code, options: TestOptions.UnsafeReleaseDll)
                .VerifyDiagnostics(
                    // (11,18): error CS8377: The type 'U' must be a non-nullable value type, along with all fields at any level of nesting, in order to use it as parameter 'T' in the generic type or method 'MyStruct<T>'
                    //         MyStruct<U> myStruct;
                    Diagnostic(ErrorCode.ERR_UnmanagedConstraintNotSatisfied, "U").WithArguments("MyStruct<T>", "T", "U").WithLocation(11, 18),
                    // (12,9): warning CS8500: This takes the address of, gets the size of, or declares a pointer to a managed type ('MyStruct<U>')
                    //         M2<U>(&myStruct);
                    Diagnostic(ErrorCode.WRN_ManagedAddr, "M2<U>").WithArguments("MyStruct<U>").WithLocation(12, 9),
                    // (12,9): error CS8377: The type 'U' must be a non-nullable value type, along with all fields at any level of nesting, in order to use it as parameter 'T' in the generic type or method 'MyStruct<T>'
                    //         M2<U>(&myStruct);
                    Diagnostic(ErrorCode.ERR_UnmanagedConstraintNotSatisfied, "M2<U>").WithArguments("MyStruct<T>", "T", "U").WithLocation(12, 9),
                    // (12,15): warning CS8500: This takes the address of, gets the size of, or declares a pointer to a managed type ('MyStruct<U>')
                    //         M2<U>(&myStruct);
                    Diagnostic(ErrorCode.WRN_ManagedAddr, "&myStruct").WithArguments("MyStruct<U>").WithLocation(12, 15),
                    // (15,43): warning CS8500: This takes the address of, gets the size of, or declares a pointer to a managed type ('MyStruct<V>')
                    //     public unsafe void M2<V>(MyStruct<V>* ms) { }
                    Diagnostic(ErrorCode.WRN_ManagedAddr, "ms").WithArguments("MyStruct<V>").WithLocation(15, 43),
                    // (15,43): error CS8377: The type 'V' must be a non-nullable value type, along with all fields at any level of nesting, in order to use it as parameter 'T' in the generic type or method 'MyStruct<T>'
                    //     public unsafe void M2<V>(MyStruct<V>* ms) { }
                    Diagnostic(ErrorCode.ERR_UnmanagedConstraintNotSatisfied, "ms").WithArguments("MyStruct<T>", "T", "V").WithLocation(15, 43));
        }
 
        [Fact]
        public void GenericStructManagedFieldPointer()
        {
            var code = @"
public struct MyStruct<T>
{
    public T field;
}
 
public class C
{
    public unsafe void M()
    {
        MyStruct<string> myStruct;
        M2(&myStruct);
    }
 
    public unsafe void M2(MyStruct<string>* ms) { }
}
";
            CreateCompilation(code, options: TestOptions.UnsafeReleaseDll)
                .VerifyDiagnostics(
                    // (12,12): warning CS8500: This takes the address of, gets the size of, or declares a pointer to a managed type ('MyStruct<string>')
                    //         M2(&myStruct);
                    Diagnostic(ErrorCode.WRN_ManagedAddr, "&myStruct").WithArguments("MyStruct<string>").WithLocation(12, 12),
                    // (15,45): warning CS8500: This takes the address of, gets the size of, or declares a pointer to a managed type ('MyStruct<string>')
                    //     public unsafe void M2(MyStruct<string>* ms) { }
                    Diagnostic(ErrorCode.WRN_ManagedAddr, "ms").WithArguments("MyStruct<string>").WithLocation(15, 45));
        }
 
        [Fact]
        public void UnmanagedRecursiveGenericStruct()
        {
            var code = @"
public unsafe struct MyStruct<T> where T : unmanaged
{
    public YourStruct<T>* field;
}
 
public unsafe struct YourStruct<T> where T : unmanaged
{
    public MyStruct<T>* field;
}
";
            var compilation = CreateCompilation(code, options: TestOptions.UnsafeReleaseDll);
            compilation.VerifyDiagnostics();
            Assert.False(compilation.GetMember<NamedTypeSymbol>("MyStruct").IsManagedTypeNoUseSiteDiagnostics);
            Assert.False(compilation.GetMember<NamedTypeSymbol>("YourStruct").IsManagedTypeNoUseSiteDiagnostics);
        }
 
        [Fact]
        public void UnmanagedRecursiveStruct()
        {
            var code = @"
public unsafe struct MyStruct
{
    public YourStruct* field;
}
 
public unsafe struct YourStruct
{
    public MyStruct* field;
}
";
            var compilation = CreateCompilation(code, options: TestOptions.UnsafeReleaseDll);
            compilation.VerifyDiagnostics();
            Assert.False(compilation.GetMember<NamedTypeSymbol>("MyStruct").IsManagedTypeNoUseSiteDiagnostics);
            Assert.False(compilation.GetMember<NamedTypeSymbol>("YourStruct").IsManagedTypeNoUseSiteDiagnostics);
 
        }
 
        [Fact]
        public void UnmanagedExpandingTypeArgument()
        {
            var code = @"
public struct MyStruct<T>
{
    public YourStruct<MyStruct<MyStruct<T>>> field;
}
 
public struct YourStruct<T> where T : unmanaged
{
    public T field;
}
";
            var compilation = CreateCompilation(code, options: TestOptions.UnsafeReleaseDll);
            compilation.VerifyDiagnostics(
                    // (4,46): error CS0523: Struct member 'MyStruct<T>.field' of type 'YourStruct<MyStruct<MyStruct<T>>>' causes a cycle in the struct layout
                    //     public YourStruct<MyStruct<MyStruct<T>>> field;
                    Diagnostic(ErrorCode.ERR_StructLayoutCycle, "field").WithArguments("MyStruct<T>.field", "YourStruct<MyStruct<MyStruct<T>>>").WithLocation(4, 46));
 
            Assert.False(compilation.GetMember<NamedTypeSymbol>("MyStruct").IsManagedTypeNoUseSiteDiagnostics);
            Assert.False(compilation.GetMember<NamedTypeSymbol>("YourStruct").IsManagedTypeNoUseSiteDiagnostics);
        }
 
        [Fact]
        public void UnmanagedCyclic()
        {
            var code = @"
public struct MyStruct<T>
{
    public YourStruct<T> field;
}
 
public struct YourStruct<T> where T : unmanaged
{
    public MyStruct<T> field;
}
";
            var compilation = CreateCompilation(code, options: TestOptions.UnsafeReleaseDll);
            compilation.VerifyDiagnostics(
                    // (4,26): error CS0523: Struct member 'MyStruct<T>.field' of type 'YourStruct<T>' causes a cycle in the struct layout
                    //     public YourStruct<T> field;
                    Diagnostic(ErrorCode.ERR_StructLayoutCycle, "field").WithArguments("MyStruct<T>.field", "YourStruct<T>").WithLocation(4, 26),
                    // (4,26): error CS8377: The type 'T' must be a non-nullable value type, along with all fields at any level of nesting, in order to use it as parameter 'T' in the generic type or method 'YourStruct<T>'
                    //     public YourStruct<T> field;
                    Diagnostic(ErrorCode.ERR_UnmanagedConstraintNotSatisfied, "field").WithArguments("YourStruct<T>", "T", "T").WithLocation(4, 26),
                    // (9,24): error CS0523: Struct member 'YourStruct<T>.field' of type 'MyStruct<T>' causes a cycle in the struct layout
                    //     public MyStruct<T> field;
                    Diagnostic(ErrorCode.ERR_StructLayoutCycle, "field").WithArguments("YourStruct<T>.field", "MyStruct<T>").WithLocation(9, 24));
 
            Assert.False(compilation.GetMember<NamedTypeSymbol>("MyStruct").IsManagedTypeNoUseSiteDiagnostics);
            Assert.False(compilation.GetMember<NamedTypeSymbol>("YourStruct").IsManagedTypeNoUseSiteDiagnostics);
        }
 
        [Fact]
        public void UnmanagedExpandingTypeArgumentManagedGenericField()
        {
            var code = @"
public struct MyStruct<T>
{
    public YourStruct<MyStruct<MyStruct<T>>> field;
    public T myField;
}
 
public struct YourStruct<T> where T : unmanaged
{
    public T field;
}
";
            var compilation = CreateCompilation(code, options: TestOptions.UnsafeReleaseDll);
            compilation.VerifyDiagnostics(
                    // (4,46): error CS0523: Struct member 'MyStruct<T>.field' of type 'YourStruct<MyStruct<MyStruct<T>>>' causes a cycle in the struct layout
                    //     public YourStruct<MyStruct<MyStruct<T>>> field;
                    Diagnostic(ErrorCode.ERR_StructLayoutCycle, "field").WithArguments("MyStruct<T>.field", "YourStruct<MyStruct<MyStruct<T>>>").WithLocation(4, 46));
 
            Assert.True(compilation.GetMember<NamedTypeSymbol>("MyStruct").IsManagedTypeNoUseSiteDiagnostics);
            Assert.False(compilation.GetMember<NamedTypeSymbol>("YourStruct").IsManagedTypeNoUseSiteDiagnostics);
        }
 
        [Fact]
        public void UnmanagedExpandingTypeArgumentConstraintViolation_01()
        {
            var code = @"
public struct MyStruct<T>
{
    public YourStruct<MyStruct<MyStruct<T>>> field;
    public string s;
}
 
public struct YourStruct<T> where T : unmanaged
{
    public T field;
}
";
            var compilation = CreateCompilation(code, options: TestOptions.UnsafeReleaseDll);
            compilation.VerifyDiagnostics(
                    // (4,46): error CS0523: Struct member 'MyStruct<T>.field' of type 'YourStruct<MyStruct<MyStruct<T>>>' causes a cycle in the struct layout
                    //     public YourStruct<MyStruct<MyStruct<T>>> field;
                    Diagnostic(ErrorCode.ERR_StructLayoutCycle, "field").WithArguments("MyStruct<T>.field", "YourStruct<MyStruct<MyStruct<T>>>").WithLocation(4, 46),
                    // (4,46): error CS8377: The type 'MyStruct<MyStruct<T>>' must be a non-nullable value type, along with all fields at any level of nesting, in order to use it as parameter 'T' in the generic type or method 'YourStruct<T>'
                    //     public YourStruct<MyStruct<MyStruct<T>>> field;
                    Diagnostic(ErrorCode.ERR_UnmanagedConstraintNotSatisfied, "field").WithArguments("YourStruct<T>", "T", "MyStruct<MyStruct<T>>").WithLocation(4, 46));
 
            Assert.True(compilation.GetMember<NamedTypeSymbol>("MyStruct").IsManagedTypeNoUseSiteDiagnostics);
            Assert.False(compilation.GetMember<NamedTypeSymbol>("YourStruct").IsManagedTypeNoUseSiteDiagnostics);
        }
 
        [Fact]
        public void UnmanagedExpandingTypeArgumentConstraintViolation_02()
        {
            var code = @"
public struct MyStruct<T>
{
    public string s;
    public YourStruct<MyStruct<MyStruct<T>>> field;
}
 
public struct YourStruct<T> where T : unmanaged
{
    public T field;
}
";
            var compilation = CreateCompilation(code, options: TestOptions.UnsafeReleaseDll);
            compilation.VerifyDiagnostics(
                    // (5,46): error CS0523: Struct member 'MyStruct<T>.field' of type 'YourStruct<MyStruct<MyStruct<T>>>' causes a cycle in the struct layout
                    //     public YourStruct<MyStruct<MyStruct<T>>> field;
                    Diagnostic(ErrorCode.ERR_StructLayoutCycle, "field").WithArguments("MyStruct<T>.field", "YourStruct<MyStruct<MyStruct<T>>>").WithLocation(5, 46),
                    // (5,46): error CS8377: The type 'MyStruct<MyStruct<T>>' must be a non-nullable value type, along with all fields at any level of nesting, in order to use it as parameter 'T' in the generic type or method 'YourStruct<T>'
                    //     public YourStruct<MyStruct<MyStruct<T>>> field;
                    Diagnostic(ErrorCode.ERR_UnmanagedConstraintNotSatisfied, "field").WithArguments("YourStruct<T>", "T", "MyStruct<MyStruct<T>>").WithLocation(5, 46));
 
            Assert.True(compilation.GetMember<NamedTypeSymbol>("MyStruct").IsManagedTypeNoUseSiteDiagnostics);
            Assert.False(compilation.GetMember<NamedTypeSymbol>("YourStruct").IsManagedTypeNoUseSiteDiagnostics);
        }
 
        [Fact]
        public void UnmanagedExpandingTypeArgumentConstraintViolation_03()
        {
            var code = @"
public struct MyStruct<T>
{
    public YourStruct<MyStruct<MyStruct<T>>> field {get;set;}
    public string s;
}
 
public struct YourStruct<T> where T : unmanaged
{
    public T field;
}
";
            var compilation = CreateCompilation(code, options: TestOptions.UnsafeReleaseDll);
            compilation.VerifyDiagnostics(
                    // (4,46): error CS0523: Struct member 'MyStruct<T>.field' of type 'YourStruct<MyStruct<MyStruct<T>>>' causes a cycle in the struct layout
                    //     public YourStruct<MyStruct<MyStruct<T>>> field;
                    Diagnostic(ErrorCode.ERR_StructLayoutCycle, "field").WithArguments("MyStruct<T>.field", "YourStruct<MyStruct<MyStruct<T>>>").WithLocation(4, 46),
                    // (4,46): error CS8377: The type 'MyStruct<MyStruct<T>>' must be a non-nullable value type, along with all fields at any level of nesting, in order to use it as parameter 'T' in the generic type or method 'YourStruct<T>'
                    //     public YourStruct<MyStruct<MyStruct<T>>> field;
                    Diagnostic(ErrorCode.ERR_UnmanagedConstraintNotSatisfied, "field").WithArguments("YourStruct<T>", "T", "MyStruct<MyStruct<T>>").WithLocation(4, 46));
 
            Assert.True(compilation.GetMember<NamedTypeSymbol>("MyStruct").IsManagedTypeNoUseSiteDiagnostics);
            Assert.False(compilation.GetMember<NamedTypeSymbol>("YourStruct").IsManagedTypeNoUseSiteDiagnostics);
        }
 
        [Fact]
        public void UnmanagedExpandingTypeArgumentConstraintViolation_04()
        {
            var code = @"
public struct MyStruct<T>
{
    public string s;
    public YourStruct<MyStruct<MyStruct<T>>> field {get;set;}
}
 
public struct YourStruct<T> where T : unmanaged
{
    public T field;
}
";
            var compilation = CreateCompilation(code, options: TestOptions.UnsafeReleaseDll);
            compilation.VerifyDiagnostics(
                    // (5,46): error CS0523: Struct member 'MyStruct<T>.field' of type 'YourStruct<MyStruct<MyStruct<T>>>' causes a cycle in the struct layout
                    //     public YourStruct<MyStruct<MyStruct<T>>> field;
                    Diagnostic(ErrorCode.ERR_StructLayoutCycle, "field").WithArguments("MyStruct<T>.field", "YourStruct<MyStruct<MyStruct<T>>>").WithLocation(5, 46),
                    // (5,46): error CS8377: The type 'MyStruct<MyStruct<T>>' must be a non-nullable value type, along with all fields at any level of nesting, in order to use it as parameter 'T' in the generic type or method 'YourStruct<T>'
                    //     public YourStruct<MyStruct<MyStruct<T>>> field;
                    Diagnostic(ErrorCode.ERR_UnmanagedConstraintNotSatisfied, "field").WithArguments("YourStruct<T>", "T", "MyStruct<MyStruct<T>>").WithLocation(5, 46));
 
            Assert.True(compilation.GetMember<NamedTypeSymbol>("MyStruct").IsManagedTypeNoUseSiteDiagnostics);
            Assert.False(compilation.GetMember<NamedTypeSymbol>("YourStruct").IsManagedTypeNoUseSiteDiagnostics);
        }
 
        [Fact]
        [WorkItem("https://github.com/dotnet/roslyn/issues/75620")]
        public void UnmanagedExpandingTypeArgumentConstraintViolation_05()
        {
            var code = @"
#pragma warning disable CS0067 // The event 'MyStruct<T>.field' is never used
 
public struct MyStruct<T>
{
    public event YourStruct<MyStruct<MyStruct<T>>> field;
    public string s;
}
 
public struct YourStruct<T> where T : unmanaged
{
    public T field;
}
";
            var compilation = CreateCompilation(code, options: TestOptions.UnsafeReleaseDll);
 
            compilation.VerifyDiagnostics(
                    // (6,52): error CS0523: Struct member 'MyStruct<T>.field' of type 'YourStruct<MyStruct<MyStruct<T>>>' causes a cycle in the struct layout
                    //     public event YourStruct<MyStruct<MyStruct<T>>> field;
                    Diagnostic(ErrorCode.ERR_StructLayoutCycle, "field").WithArguments("MyStruct<T>.field", "YourStruct<MyStruct<MyStruct<T>>>").WithLocation(6, 52),
                    // (6,52): error CS0066: 'MyStruct<T>.field': event must be of a delegate type
                    //     public event YourStruct<MyStruct<MyStruct<T>>> field;
                    Diagnostic(ErrorCode.ERR_EventNotDelegate, "field").WithArguments("MyStruct<T>.field").WithLocation(6, 52),
                    // (6,52): error CS8377: The type 'MyStruct<MyStruct<T>>' must be a non-nullable value type, along with all fields at any level of nesting, in order to use it as parameter 'T' in the generic type or method 'YourStruct<T>'
                    //     public event YourStruct<MyStruct<MyStruct<T>>> field;
                    Diagnostic(ErrorCode.ERR_UnmanagedConstraintNotSatisfied, "field").WithArguments("YourStruct<T>", "T", "MyStruct<MyStruct<T>>").WithLocation(6, 52)
                    );
 
            Assert.True(compilation.GetMember<NamedTypeSymbol>("MyStruct").IsManagedTypeNoUseSiteDiagnostics);
            Assert.False(compilation.GetMember<NamedTypeSymbol>("YourStruct").IsManagedTypeNoUseSiteDiagnostics);
        }
 
        [Fact]
        [WorkItem("https://github.com/dotnet/roslyn/issues/75620")]
        public void UnmanagedExpandingTypeArgumentConstraintViolation_06()
        {
            var code = @"
#pragma warning disable CS0067 // The event 'MyStruct<T>.field' is never used
 
public struct MyStruct<T>
{
    public string s;
    public event YourStruct<MyStruct<MyStruct<T>>> field;
}
 
public struct YourStruct<T> where T : unmanaged
{
    public T field;
}
";
            var compilation = CreateCompilation(code, options: TestOptions.UnsafeReleaseDll);
            compilation.VerifyDiagnostics(
                    // (7,52): error CS0523: Struct member 'MyStruct<T>.field' of type 'YourStruct<MyStruct<MyStruct<T>>>' causes a cycle in the struct layout
                    //     public event YourStruct<MyStruct<MyStruct<T>>> field;
                    Diagnostic(ErrorCode.ERR_StructLayoutCycle, "field").WithArguments("MyStruct<T>.field", "YourStruct<MyStruct<MyStruct<T>>>").WithLocation(7, 52),
                    // (7,52): error CS0066: 'MyStruct<T>.field': event must be of a delegate type
                    //     public event YourStruct<MyStruct<MyStruct<T>>> field;
                    Diagnostic(ErrorCode.ERR_EventNotDelegate, "field").WithArguments("MyStruct<T>.field").WithLocation(7, 52),
                    // (7,52): error CS8377: The type 'MyStruct<MyStruct<T>>' must be a non-nullable value type, along with all fields at any level of nesting, in order to use it as parameter 'T' in the generic type or method 'YourStruct<T>'
                    //     public event YourStruct<MyStruct<MyStruct<T>>> field;
                    Diagnostic(ErrorCode.ERR_UnmanagedConstraintNotSatisfied, "field").WithArguments("YourStruct<T>", "T", "MyStruct<MyStruct<T>>").WithLocation(7, 52)
                    );
 
            Assert.True(compilation.GetMember<NamedTypeSymbol>("MyStruct").IsManagedTypeNoUseSiteDiagnostics);
            Assert.False(compilation.GetMember<NamedTypeSymbol>("YourStruct").IsManagedTypeNoUseSiteDiagnostics);
        }
 
        [Fact]
        public void UnmanagedRecursiveTypeArgumentConstraintViolation_02()
        {
            var code = @"
public struct MyStruct<T>
{
    public YourStruct<MyStruct<MyStruct<T>>> field;
}
 
public struct YourStruct<T> where T : unmanaged
{
    public T field;
    public string s;
}
";
            var compilation = CreateCompilation(code, options: TestOptions.UnsafeReleaseDll);
            compilation.VerifyDiagnostics(
                    // (4,46): error CS0523: Struct member 'MyStruct<T>.field' of type 'YourStruct<MyStruct<MyStruct<T>>>' causes a cycle in the struct layout
                    //     public YourStruct<MyStruct<MyStruct<T>>> field;
                    Diagnostic(ErrorCode.ERR_StructLayoutCycle, "field").WithArguments("MyStruct<T>.field", "YourStruct<MyStruct<MyStruct<T>>>").WithLocation(4, 46),
                    // (4,46): error CS8377: The type 'MyStruct<MyStruct<T>>' must be a non-nullable value type, along with all fields at any level of nesting, in order to use it as parameter 'T' in the generic type or method 'YourStruct<T>'
                    //     public YourStruct<MyStruct<MyStruct<T>>> field;
                    Diagnostic(ErrorCode.ERR_UnmanagedConstraintNotSatisfied, "field").WithArguments("YourStruct<T>", "T", "MyStruct<MyStruct<T>>").WithLocation(4, 46));
 
            Assert.True(compilation.GetMember<NamedTypeSymbol>("MyStruct").IsManagedTypeNoUseSiteDiagnostics);
            Assert.True(compilation.GetMember<NamedTypeSymbol>("YourStruct").IsManagedTypeNoUseSiteDiagnostics);
        }
 
        [Fact]
        public void UnmanagedRecursiveTypeArgumentConstraintViolation_03()
        {
            var code = @"
public struct MyStruct<T>
{
    public YourStruct<MyStruct<MyStruct<T>>> field;
}
 
public struct YourStruct<T> where T : unmanaged
{
    public string s;
    public T field;
}
";
            var compilation = CreateCompilation(code, options: TestOptions.UnsafeReleaseDll);
            compilation.VerifyDiagnostics(
                    // (4,46): error CS0523: Struct member 'MyStruct<T>.field' of type 'YourStruct<MyStruct<MyStruct<T>>>' causes a cycle in the struct layout
                    //     public YourStruct<MyStruct<MyStruct<T>>> field;
                    Diagnostic(ErrorCode.ERR_StructLayoutCycle, "field").WithArguments("MyStruct<T>.field", "YourStruct<MyStruct<MyStruct<T>>>").WithLocation(4, 46),
                    // (4,46): error CS8377: The type 'MyStruct<MyStruct<T>>' must be a non-nullable value type, along with all fields at any level of nesting, in order to use it as parameter 'T' in the generic type or method 'YourStruct<T>'
                    //     public YourStruct<MyStruct<MyStruct<T>>> field;
                    Diagnostic(ErrorCode.ERR_UnmanagedConstraintNotSatisfied, "field").WithArguments("YourStruct<T>", "T", "MyStruct<MyStruct<T>>").WithLocation(4, 46));
 
            Assert.True(compilation.GetMember<NamedTypeSymbol>("MyStruct").IsManagedTypeNoUseSiteDiagnostics);
            Assert.True(compilation.GetMember<NamedTypeSymbol>("YourStruct").IsManagedTypeNoUseSiteDiagnostics);
        }
 
        [Fact]
        public void NestedGenericStructContainingPointer()
        {
            var code = @"
public unsafe struct MyStruct<T> where T : unmanaged
{
    public T* field;
 
    public T this[int index]
    {
        get { return field[index]; }
    }
}
 
public class C
{
    public static unsafe void Main()
    {
        float f = 42;
        var ms = new MyStruct<float> { field = &f };
        var test = new MyStruct<MyStruct<float>> { field = &ms };
        float value = test[0][0];
        System.Console.Write(value);
    }
}
";
            CompileAndVerify(code, options: TestOptions.UnsafeReleaseExe, expectedOutput: "42", verify: Verification.Skipped);
        }
 
        [Fact]
        public void SimpleGenericStructPointer_ILValidation()
        {
            var code = @"
public unsafe struct MyStruct<T> where T : unmanaged
{
    public T field;
 
    public static void Test()
    {
        var ms = new MyStruct<int>();
        MyStruct<int>* ptr = &ms;
        ptr->field = 42;
    }
}
";
            var il = @"
{
  // Code size       19 (0x13)
  .maxstack  2
  .locals init (MyStruct<int> V_0) //ms
  IL_0000:  ldloca.s   V_0
  IL_0002:  initobj    ""MyStruct<int>""
  IL_0008:  ldloca.s   V_0
  IL_000a:  conv.u
  IL_000b:  ldc.i4.s   42
  IL_000d:  stfld      ""int MyStruct<int>.field""
  IL_0012:  ret
}
";
            CompileAndVerify(code, options: TestOptions.UnsafeReleaseDll, verify: Verification.Skipped)
                .VerifyIL("MyStruct<T>.Test", il);
        }
 
        [Fact, WorkItem(31439, "https://github.com/dotnet/roslyn/issues/31439")]
        public void CircularTypeArgumentUnmanagedConstraint()
        {
            var code = @"
public struct X<T>
    where T : unmanaged
{
}
 
public struct Z
{
    public X<Z> field;
}";
            var compilation = CreateCompilation(code);
            compilation.VerifyDiagnostics();
 
            Assert.False(compilation.GetMember<NamedTypeSymbol>("X").IsManagedTypeNoUseSiteDiagnostics);
            Assert.False(compilation.GetMember<NamedTypeSymbol>("Z").IsManagedTypeNoUseSiteDiagnostics);
        }
 
        [Fact]
        public void GenericStructAddressOfRequiresCSharp8()
        {
            var code = @"
public struct MyStruct<T>
{
    public T field;
 
    public static unsafe void Test()
    {
        var ms = new MyStruct<int>();
        var ptr = &ms;
    }
}
";
            CreateCompilation(code, options: TestOptions.UnsafeReleaseDll, parseOptions: TestOptions.Regular7_3)
                .VerifyDiagnostics(
                // (9,19): error CS8652: The feature 'unmanaged constructed types' is not available in C# 7.3. Please use language version 8.0 or greater.
                //         var ptr = &ms;
                Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7_3, "&ms").WithArguments("unmanaged constructed types", "8.0").WithLocation(9, 19)
                );
 
            CreateCompilation(code, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics();
        }
 
        [Fact]
        public void GenericStructFixedRequiresCSharp8()
        {
            var code = @"
public struct MyStruct<T>
{
    public T field;
}
 
public class MyClass
{
    public MyStruct<int> ms;
    public static unsafe void Test(MyClass c)
    {
        fixed (MyStruct<int>* ptr = &c.ms)
        {
        }
    }
}
";
            CreateCompilation(code, options: TestOptions.UnsafeReleaseDll, parseOptions: TestOptions.Regular7_3)
                .VerifyDiagnostics(
                // (12,16): error CS8652: The feature 'unmanaged constructed types' is not available in C# 7.3. Please use language version 8.0 or greater.
                //         fixed (MyStruct<int>* ptr = &c.ms)
                Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7_3, "MyStruct<int>*").WithArguments("unmanaged constructed types", "8.0").WithLocation(12, 16),
                // (12,37): error CS8652: The feature 'unmanaged constructed types' is not available in C# 7.3. Please use language version 8.0 or greater.
                //         fixed (MyStruct<int>* ptr = &c.ms)
                Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7_3, "&c.ms").WithArguments("unmanaged constructed types", "8.0").WithLocation(12, 37));
 
            CreateCompilation(code, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics();
        }
 
        [Fact]
        public void GenericStructSizeofRequiresCSharp8()
        {
            var code = @"
public struct MyStruct<T>
{
    public T field;
 
    public static unsafe void Test()
    {
        var size = sizeof(MyStruct<int>);
    }
}
";
            CreateCompilation(code, options: TestOptions.UnsafeReleaseDll, parseOptions: TestOptions.Regular7_3)
                .VerifyDiagnostics(
                // (8,20): error CS8652: The feature 'unmanaged constructed types' is not available in C# 7.3. Please use language version 8.0 or greater.
                //         var size = sizeof(MyStruct<int>);
                Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7_3, "sizeof(MyStruct<int>)").WithArguments("unmanaged constructed types", "8.0").WithLocation(8, 20)
                );
 
            CreateCompilation(code, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics();
        }
 
        [Fact]
        public void GenericImplicitStackallocRequiresCSharp8()
        {
            var code = @"
public struct MyStruct<T>
{
    public T field;
 
    public static unsafe void Test()
    {
        var arr = stackalloc[] { new MyStruct<int>() };
    }
}
";
            CreateCompilation(code, options: TestOptions.UnsafeReleaseDll, parseOptions: TestOptions.Regular7_3)
                .VerifyDiagnostics(
                // (8,19): error CS8652: The feature 'unmanaged constructed types' is not available in C# 7.3. Please use language version 8.0 or greater.
                //         var arr = stackalloc[] { new MyStruct<int>() };
                Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7_3, "stackalloc[] { new MyStruct<int>() }").WithArguments("unmanaged constructed types", "8.0").WithLocation(8, 19));
 
            CreateCompilation(code, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics();
        }
 
        [Fact]
        public void GenericStackallocRequiresCSharp8()
        {
            var code = @"
public struct MyStruct<T>
{
    public T field;
 
    public static unsafe void Test()
    {
        var arr = stackalloc MyStruct<int>[4];
    }
}
";
            CreateCompilation(code, options: TestOptions.UnsafeReleaseDll, parseOptions: TestOptions.Regular7_3)
                .VerifyDiagnostics(
                // (8,30): error CS8652: The feature 'unmanaged constructed types' is not available in C# 7.3. Please use language version 8.0 or greater.
                //         var arr = stackalloc MyStruct<int>[4];
                Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7_3, "MyStruct<int>").WithArguments("unmanaged constructed types", "8.0").WithLocation(8, 30));
 
            CreateCompilation(code, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics();
        }
 
        [Fact]
        public void GenericStructPointerFieldRequiresCSharp8()
        {
            var code = @"
public struct MyStruct<T>
{
    public T field;
}
 
public unsafe struct OtherStruct
{
    public MyStruct<int>* ms;
}
";
            CreateCompilation(code, options: TestOptions.UnsafeReleaseDll, parseOptions: TestOptions.Regular7_3)
                .VerifyDiagnostics(
                // (9,27): error CS8370: Feature 'unmanaged constructed types' is not available in C# 7.3. Please use language version 8.0 or greater.
                //     public MyStruct<int>* ms;
                Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7_3, "ms").WithArguments("unmanaged constructed types", "8.0").WithLocation(9, 27)
                );
 
            CreateCompilation(code, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics();
        }
 
        [Fact]
        public void GenericNestedStructPointerFieldRequiresCSharp8()
        {
            var code = @"
public struct MyStruct<T>
{
    public struct InnerStruct
    {
        public T field;
    }
}
 
public unsafe struct OtherStruct
{
    public MyStruct<int>.InnerStruct* ms;
}
";
            CreateCompilation(code, options: TestOptions.UnsafeReleaseDll, parseOptions: TestOptions.Regular7_3)
                .VerifyDiagnostics(
                    // (12,39): error CS8370: Feature 'unmanaged constructed types' is not available in C# 7.3. Please use language version 8.0 or greater.
                    //     public MyStruct<int>.InnerStruct* ms;
                    Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7_3, "ms").WithArguments("unmanaged constructed types", "8.0").WithLocation(12, 39)
                );
 
            CreateCompilation(code, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics();
        }
 
        [Fact, WorkItem(32103, "https://github.com/dotnet/roslyn/issues/32103")]
        public void StructContainingTuple_Unmanaged_RequiresCSharp8()
        {
            var code = @"
public struct MyStruct
{
    public (int, int) field;
}
 
public class C
{
    public unsafe void M<T>() where T : unmanaged { }
 
    public void M2()
    {
        M<MyStruct>();
        M<(int, int)>();
    }
}
";
            CreateCompilation(code, options: TestOptions.UnsafeReleaseDll, parseOptions: TestOptions.Regular7_3)
                .VerifyDiagnostics(
                // (13,9): error CS8652: The feature 'unmanaged constructed types' is not available in C# 7.3. Please use language version 8.0 or greater.
                //         M<MyStruct>();
                Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7_3, "M<MyStruct>").WithArguments("unmanaged constructed types", "8.0").WithLocation(13, 9),
                // (14,9): error CS8652: The feature 'unmanaged constructed types' is not available in C# 7.3. Please use language version 8.0 or greater.
                //         M<(int, int)>();
                Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7_3, "M<(int, int)>").WithArguments("unmanaged constructed types", "8.0").WithLocation(14, 9)
                );
 
            CreateCompilation(code, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics();
        }
 
        [Fact, WorkItem(32103, "https://github.com/dotnet/roslyn/issues/32103")]
        public void StructContainingGenericTuple_Unmanaged()
        {
            var code = @"
public struct MyStruct<T>
{
    public (T, T) field;
}
 
public class C
{
    public unsafe void M<T>() where T : unmanaged { }
 
    public void M2<U>() where U : unmanaged
    {
        M<MyStruct<U>>();
    }
 
    public void M3<V>()
    {
        M<MyStruct<V>>();
    }
}
";
            CreateCompilation(code, options: TestOptions.UnsafeReleaseDll, parseOptions: TestOptions.Regular7_3)
                .VerifyDiagnostics(
                // (13,9): error CS8652: The feature 'unmanaged constructed types' is not available in C# 7.3. Please use language version 8.0 or greater.
                //         M<MyStruct<U>>();
                Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7_3, "M<MyStruct<U>>").WithArguments("unmanaged constructed types", "8.0").WithLocation(13, 9),
                // (18,9): error CS8377: The type 'MyStruct<V>' must be a non-nullable value type, along with all fields at any level of nesting, in order to use it as parameter 'T' in the generic type or method 'C.M<T>()'
                //         M<MyStruct<V>>();
                Diagnostic(ErrorCode.ERR_UnmanagedConstraintNotSatisfied, "M<MyStruct<V>>").WithArguments("C.M<T>()", "T", "MyStruct<V>").WithLocation(18, 9)
                );
 
            CreateCompilation(code, options: TestOptions.UnsafeReleaseDll)
                .VerifyDiagnostics(
                    // (18,9): error CS8377: The type 'MyStruct<V>' must be a non-nullable value type, along with all fields at any level of nesting, in order to use it as parameter 'T' in the generic type or method 'C.M<T>()'
                    //         M<MyStruct<V>>();
                    Diagnostic(ErrorCode.ERR_UnmanagedConstraintNotSatisfied, "M<MyStruct<V>>").WithArguments("C.M<T>()", "T", "MyStruct<V>").WithLocation(18, 9)
                );
        }
 
        [Fact]
        public void GenericRefStructAddressOf_01()
        {
            var code = @"
public ref struct MyStruct<T>
{
    public T field;
}
 
public class MyClass
{
    public static unsafe void Main()
    {
        var ms = new MyStruct<int>() { field = 42 };
        var ptr = &ms;
        System.Console.Write(ptr->field);
    }
}
";
 
            CompileAndVerify(code,
                options: TestOptions.UnsafeReleaseExe,
                verify: Verification.Skipped,
                expectedOutput: "42");
        }
 
        [Fact]
        public void GenericRefStructAddressOf_02()
        {
            var code = @"
public ref struct MyStruct<T>
{
    public T field;
}
 
public class MyClass
{
    public unsafe void M()
    {
        var ms = new MyStruct<object>();
        var ptr = &ms;
    }
}
";
 
            CreateCompilation(code, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(
                // (12,19): warning CS8500: This takes the address of, gets the size of, or declares a pointer to a managed type ('MyStruct<object>')
                //         var ptr = &ms;
                Diagnostic(ErrorCode.WRN_ManagedAddr, "&ms").WithArguments("MyStruct<object>").WithLocation(12, 19)
            );
        }
 
        [Fact]
        public void GenericStructFixedStatement()
        {
            var code = @"
public struct MyStruct<T>
{
    public T field;
}
 
public class MyClass
{
    public MyStruct<int> ms;
    public static unsafe void Main()
    {
        var c = new MyClass();
        c.ms.field = 42;
        fixed (MyStruct<int>* ptr = &c.ms)
        {
            System.Console.Write(ptr->field);
        }
    }
}
";
 
            CompileAndVerify(code,
                options: TestOptions.UnsafeReleaseExe,
                verify: Verification.Skipped,
                expectedOutput: "42");
        }
 
        [Fact]
        public void GenericStructLocalFixedStatement()
        {
            var code = @"
public struct MyStruct<T>
{
    public T field;
}
 
public class MyClass
{
    public static unsafe void Main()
    {
        var ms = new MyStruct<int>();
        fixed (int* ptr = &ms.field)
        {
        }
    }
}
";
            CreateCompilation(code, options: TestOptions.UnsafeReleaseDll)
                .VerifyDiagnostics(
                    // (12,27): error CS0213: You cannot use the fixed statement to take the address of an already fixed expression
                    //         fixed (int* ptr = &ms.field)
                    Diagnostic(ErrorCode.ERR_FixedNotNeeded, "&ms.field").WithLocation(12, 27)
                );
        }
 
        [Fact, WorkItem(45141, "https://github.com/dotnet/roslyn/issues/45141")]
        public void CannotCombineDiagnostics()
        {
            var comp = CreateCompilation(@"
class C1<T1> where T1 : class, struct, unmanaged, notnull
{
    void M1<T2>() where T2 : class, struct, unmanaged, notnull {}
}
class C2<T1> where T1 : struct, class, unmanaged, notnull
{
    void M2<T2>() where T2 : struct, class, unmanaged, notnull {}
}
class C3<T1> where T1 : class, class
{
    void M3<T2>() where T2 : class, class {}
}
");
 
            comp.VerifyDiagnostics(
                // (2,32): error CS0449: The 'class', 'struct', 'unmanaged', 'notnull', and 'default' constraints cannot be combined or duplicated, and must be specified first in the constraints list.
                // class C1<T1> where T1 : class, struct, unmanaged, notnull
                Diagnostic(ErrorCode.ERR_TypeConstraintsMustBeUniqueAndFirst, "struct").WithLocation(2, 32),
                // (2,40): error CS0449: The 'class', 'struct', 'unmanaged', 'notnull', and 'default' constraints cannot be combined or duplicated, and must be specified first in the constraints list.
                // class C1<T1> where T1 : class, struct, unmanaged, notnull
                Diagnostic(ErrorCode.ERR_TypeConstraintsMustBeUniqueAndFirst, "unmanaged").WithLocation(2, 40),
                // (2,51): error CS0449: The 'class', 'struct', 'unmanaged', 'notnull', and 'default' constraints cannot be combined or duplicated, and must be specified first in the constraints list.
                // class C1<T1> where T1 : class, struct, unmanaged, notnull
                Diagnostic(ErrorCode.ERR_TypeConstraintsMustBeUniqueAndFirst, "notnull").WithLocation(2, 51),
                // (4,37): error CS0449: The 'class', 'struct', 'unmanaged', 'notnull', and 'default' constraints cannot be combined or duplicated, and must be specified first in the constraints list.
                //     void M1<T2>() where T2 : class, struct, unmanaged, notnull {}
                Diagnostic(ErrorCode.ERR_TypeConstraintsMustBeUniqueAndFirst, "struct").WithLocation(4, 37),
                // (4,45): error CS0449: The 'class', 'struct', 'unmanaged', 'notnull', and 'default' constraints cannot be combined or duplicated, and must be specified first in the constraints list.
                //     void M1<T2>() where T2 : class, struct, unmanaged, notnull {}
                Diagnostic(ErrorCode.ERR_TypeConstraintsMustBeUniqueAndFirst, "unmanaged").WithLocation(4, 45),
                // (4,56): error CS0449: The 'class', 'struct', 'unmanaged', 'notnull', and 'default' constraints cannot be combined or duplicated, and must be specified first in the constraints list.
                //     void M1<T2>() where T2 : class, struct, unmanaged, notnull {}
                Diagnostic(ErrorCode.ERR_TypeConstraintsMustBeUniqueAndFirst, "notnull").WithLocation(4, 56),
                // (6,33): error CS0449: The 'class', 'struct', 'unmanaged', 'notnull', and 'default' constraints cannot be combined or duplicated, and must be specified first in the constraints list.
                // class C2<T1> where T1 : struct, class, unmanaged, notnull
                Diagnostic(ErrorCode.ERR_TypeConstraintsMustBeUniqueAndFirst, "class").WithLocation(6, 33),
                // (6,40): error CS0449: The 'class', 'struct', 'unmanaged', 'notnull', and 'default' constraints cannot be combined or duplicated, and must be specified first in the constraints list.
                // class C2<T1> where T1 : struct, class, unmanaged, notnull
                Diagnostic(ErrorCode.ERR_TypeConstraintsMustBeUniqueAndFirst, "unmanaged").WithLocation(6, 40),
                // (6,51): error CS0449: The 'class', 'struct', 'unmanaged', 'notnull', and 'default' constraints cannot be combined or duplicated, and must be specified first in the constraints list.
                // class C2<T1> where T1 : struct, class, unmanaged, notnull
                Diagnostic(ErrorCode.ERR_TypeConstraintsMustBeUniqueAndFirst, "notnull").WithLocation(6, 51),
                // (8,38): error CS0449: The 'class', 'struct', 'unmanaged', 'notnull', and 'default' constraints cannot be combined or duplicated, and must be specified first in the constraints list.
                //     void M2<T2>() where T2 : struct, class, unmanaged, notnull {}
                Diagnostic(ErrorCode.ERR_TypeConstraintsMustBeUniqueAndFirst, "class").WithLocation(8, 38),
                // (8,45): error CS0449: The 'class', 'struct', 'unmanaged', 'notnull', and 'default' constraints cannot be combined or duplicated, and must be specified first in the constraints list.
                //     void M2<T2>() where T2 : struct, class, unmanaged, notnull {}
                Diagnostic(ErrorCode.ERR_TypeConstraintsMustBeUniqueAndFirst, "unmanaged").WithLocation(8, 45),
                // (8,56): error CS0449: The 'class', 'struct', 'unmanaged', 'notnull', and 'default' constraints cannot be combined or duplicated, and must be specified first in the constraints list.
                //     void M2<T2>() where T2 : struct, class, unmanaged, notnull {}
                Diagnostic(ErrorCode.ERR_TypeConstraintsMustBeUniqueAndFirst, "notnull").WithLocation(8, 56),
                // (10,32): error CS0449: The 'class', 'struct', 'unmanaged', 'notnull', and 'default' constraints cannot be combined or duplicated, and must be specified first in the constraints list.
                // class C3<T1> where T1 : class, class
                Diagnostic(ErrorCode.ERR_TypeConstraintsMustBeUniqueAndFirst, "class").WithLocation(10, 32),
                // (12,37): error CS0449: The 'class', 'struct', 'unmanaged', 'notnull', and 'default' constraints cannot be combined or duplicated, and must be specified first in the constraints list.
                //     void M3<T2>() where T2 : class, class {}
                Diagnostic(ErrorCode.ERR_TypeConstraintsMustBeUniqueAndFirst, "class").WithLocation(12, 37)
            );
        }
 
        [Fact, WorkItem(45141, "https://github.com/dotnet/roslyn/issues/45141")]
        public void CannotCombineDiagnostics_InheritedClassStruct()
        {
            var comp = CreateCompilation(@"
class C
{
    public virtual void M<T1>() where T1 : class {}
}
class D : C
{
    public override void M<T1>() where T1 : C, class, struct {}
}
class E
{
    public virtual void M<T2>() where T2 : struct {}
}
class F : E
{
    public override void M<T2>() where T2 : E, struct, class {}
}
class G
{
    public virtual void M<T3>() where T3 : unmanaged {}
}
class H : G
{
    public override void M<T3>() where T3 : G, unmanaged, struct {}
}
");
 
            comp.VerifyDiagnostics(
                // (8,45): error CS0460: Constraints for override and explicit interface implementation methods are inherited from the base method, so they cannot be specified directly, except for either a 'class', or a 'struct' constraint.
                //     public override void M<T1>() where T1 : C, class, struct {}
                Diagnostic(ErrorCode.ERR_OverrideWithConstraints, "C").WithLocation(8, 45),
                // (16,45): error CS0460: Constraints for override and explicit interface implementation methods are inherited from the base method, so they cannot be specified directly, except for either a 'class', or a 'struct' constraint.
                //     public override void M<T2>() where T2 : E, struct, class {}
                Diagnostic(ErrorCode.ERR_OverrideWithConstraints, "E").WithLocation(16, 45),
                // (24,45): error CS0460: Constraints for override and explicit interface implementation methods are inherited from the base method, so they cannot be specified directly, except for either a 'class', or a 'struct' constraint.
                //     public override void M<T3>() where T3 : G, unmanaged, struct {}
                Diagnostic(ErrorCode.ERR_OverrideWithConstraints, "G").WithLocation(24, 45)
            );
        }
    }
}