File: Emit\UnmanagedTypeModifierTests.cs
Web Access
Project: src\src\Compilers\CSharp\Test\Emit2\Microsoft.CodeAnalysis.CSharp.Emit2.UnitTests.csproj (Microsoft.CodeAnalysis.CSharp.Emit2.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.Linq;
using Microsoft.CodeAnalysis.CSharp.Test.Utilities;
using Microsoft.CodeAnalysis.Test.Utilities;
using Roslyn.Test.Utilities;
using Xunit;
 
namespace Microsoft.CodeAnalysis.CSharp.UnitTests.Emit
{
    public class UnmanagedTypeModifierTests : CSharpTestBase
    {
        [Fact]
        public void LoadingADifferentModifierTypeForUnmanagedConstraint()
        {
            var ilSource = IsUnmanagedAttributeIL + @"
.class public auto ansi beforefieldinit TestRef
       extends [mscorlib]System.Object
{
  .method public hidebysig instance void
          M1<valuetype .ctor (class [mscorlib]System.ValueType modreq([mscorlib]System.Runtime.InteropServices.UnmanagedType)) T>() cil managed
  {
    .param type T
    .custom instance void System.Runtime.CompilerServices.IsUnmanagedAttribute::.ctor() = ( 01 00 00 00 )
    // Code size       2 (0x2)
    .maxstack  8
    IL_0000:  nop
    IL_0001:  ret
  } // end of method TestRef::M1
 
  .method public hidebysig instance void
          M2<valuetype .ctor (class [mscorlib]System.ValueType modreq([mscorlib]System.Runtime.InteropServices.InAttribute)) T>() cil managed
  {
    .param type T
    .custom instance void System.Runtime.CompilerServices.IsUnmanagedAttribute::.ctor() = ( 01 00 00 00 )
    // Code size       2 (0x2)
    .maxstack  8
    IL_0000:  nop
    IL_0001:  ret
  } // end of method TestRef::M2
 
  .method public hidebysig specialname rtspecialname
          instance void  .ctor() cil managed
  {
    // Code size       8 (0x8)
    .maxstack  8
    IL_0000:  ldarg.0
    IL_0001:  call       instance void [mscorlib]System.Object::.ctor()
    IL_0006:  nop
    IL_0007:  ret
  } // end of method TestRef::.ctor
 
}";
 
            var reference = CompileIL(ilSource, prependDefaultHeader: false);
 
            var code = @"
public class Test
{
    public static void Main()
    {
        var obj = new TestRef();
 
        obj.M1<int>();      // valid
        obj.M2<int>();      // invalid
    }
}";
 
            CreateCompilation(code, references: new[] { reference }).VerifyDiagnostics(
                // (9,13): error CS0315: The type 'int' cannot be used as type parameter 'T' in the generic type or method 'TestRef.M2<T>()'. There is no boxing conversion from 'int' to '?'.
                //         obj.M2<int>();      // invalid
                Diagnostic(ErrorCode.ERR_GenericConstraintNotSatisfiedValType, "M2<int>").WithArguments("TestRef.M2<T>()", "?", "T", "int").WithLocation(9, 13),
                // (9,13): error CS0570: 'T' is not supported by the language
                //         obj.M2<int>();      // invalid
                Diagnostic(ErrorCode.ERR_BindToBogus, "M2<int>").WithArguments("T").WithLocation(9, 13),
                // (9,13): error CS0648: '' is a type not supported by the language
                //         obj.M2<int>();      // invalid
                Diagnostic(ErrorCode.ERR_BogusType, "M2<int>").WithArguments("").WithLocation(9, 13)
                );
        }
 
        [Fact]
        public void LoadingUnmanagedTypeModifier_OptionalIsError()
        {
            var ilSource = IsUnmanagedAttributeIL + @"
.class public auto ansi beforefieldinit TestRef
       extends [mscorlib]System.Object
{
  .method public hidebysig instance void
          M1<valuetype .ctor (class [mscorlib]System.ValueType modreq([mscorlib]System.Runtime.InteropServices.UnmanagedType)) T>() cil managed
  {
    .param type T
    .custom instance void System.Runtime.CompilerServices.IsUnmanagedAttribute::.ctor() = ( 01 00 00 00 )
    // Code size       2 (0x2)
    .maxstack  8
    IL_0000:  nop
    IL_0001:  ret
  } // end of method TestRef::M1
 
  .method public hidebysig instance void
          M2<valuetype .ctor (class [mscorlib]System.ValueType modopt([mscorlib]System.Runtime.InteropServices.UnmanagedType)) T>() cil managed
  {
    .param type T
    .custom instance void System.Runtime.CompilerServices.IsUnmanagedAttribute::.ctor() = ( 01 00 00 00 )
    // Code size       2 (0x2)
    .maxstack  8
    IL_0000:  nop
    IL_0001:  ret
  } // end of method TestRef::M2
 
  .method public hidebysig specialname rtspecialname
          instance void  .ctor() cil managed
  {
    // Code size       8 (0x8)
    .maxstack  8
    IL_0000:  ldarg.0
    IL_0001:  call       instance void [mscorlib]System.Object::.ctor()
    IL_0006:  nop
    IL_0007:  ret
  } // end of method TestRef::.ctor
 
}";
 
            var reference = CompileIL(ilSource, prependDefaultHeader: false);
 
            var code = @"
public class Test
{
    public static void Main()
    {
        var obj = new TestRef();
 
        obj.M1<int>();      // valid
        obj.M2<int>();      // invalid
    }
}";
 
            CreateCompilation(code, references: new[] { reference }).VerifyDiagnostics(
                // (9,13): error CS0315: The type 'int' cannot be used as type parameter 'T' in the generic type or method 'TestRef.M2<T>()'. There is no boxing conversion from 'int' to '?'.
                //         obj.M2<int>();      // invalid
                Diagnostic(ErrorCode.ERR_GenericConstraintNotSatisfiedValType, "M2<int>").WithArguments("TestRef.M2<T>()", "?", "T", "int").WithLocation(9, 13),
                // (9,13): error CS0570: 'T' is not supported by the language
                //         obj.M2<int>();      // invalid
                Diagnostic(ErrorCode.ERR_BindToBogus, "M2<int>").WithArguments("T").WithLocation(9, 13),
                // (9,13): error CS0648: '' is a type not supported by the language
                //         obj.M2<int>();      // invalid
                Diagnostic(ErrorCode.ERR_BogusType, "M2<int>").WithArguments("").WithLocation(9, 13)
                );
        }
 
        [Fact]
        public void LoadingUnmanagedTypeModifier_MoreThanOneModifier()
        {
            var ilSource = IsUnmanagedAttributeIL + @"
.class public auto ansi beforefieldinit TestRef
       extends [mscorlib]System.Object
{
  .method public hidebysig instance void
          M1<valuetype .ctor (class [mscorlib]System.ValueType modreq([mscorlib]System.Runtime.InteropServices.UnmanagedType)) T>() cil managed
  {
    .param type T
    .custom instance void System.Runtime.CompilerServices.IsUnmanagedAttribute::.ctor() = ( 01 00 00 00 )
    // Code size       2 (0x2)
    .maxstack  8
    IL_0000:  nop
    IL_0001:  ret
  } // end of method TestRef::M1
 
  .method public hidebysig instance void
          M2<valuetype .ctor (class [mscorlib]System.ValueType modopt([mscorlib]System.DateTime) modreq([mscorlib]System.Runtime.InteropServices.UnmanagedType)) T>() cil managed
  {
    .param type T
    .custom instance void System.Runtime.CompilerServices.IsUnmanagedAttribute::.ctor() = ( 01 00 00 00 )
    // Code size       2 (0x2)
    .maxstack  8
    IL_0000:  nop
    IL_0001:  ret
  } // end of method TestRef::M2
 
  .method public hidebysig specialname rtspecialname
          instance void  .ctor() cil managed
  {
    // Code size       8 (0x8)
    .maxstack  8
    IL_0000:  ldarg.0
    IL_0001:  call       instance void [mscorlib]System.Object::.ctor()
    IL_0006:  nop
    IL_0007:  ret
  } // end of method TestRef::.ctor
 
}";
 
            var reference = CompileIL(ilSource, prependDefaultHeader: false);
 
            var code = @"
public class Test
{
    public static void Main()
    {
        var obj = new TestRef();
 
        obj.M1<int>();      // valid
        obj.M2<int>();      // invalid
    }
}";
 
            CreateCompilation(code, references: new[] { reference }).VerifyDiagnostics(
                // (9,13): error CS0315: The type 'int' cannot be used as type parameter 'T' in the generic type or method 'TestRef.M2<T>()'. There is no boxing conversion from 'int' to '?'.
                //         obj.M2<int>();      // invalid
                Diagnostic(ErrorCode.ERR_GenericConstraintNotSatisfiedValType, "M2<int>").WithArguments("TestRef.M2<T>()", "?", "T", "int").WithLocation(9, 13),
                // (9,13): error CS0570: 'T' is not supported by the language
                //         obj.M2<int>();      // invalid
                Diagnostic(ErrorCode.ERR_BindToBogus, "M2<int>").WithArguments("T").WithLocation(9, 13),
                // (9,13): error CS0648: '' is a type not supported by the language
                //         obj.M2<int>();      // invalid
                Diagnostic(ErrorCode.ERR_BogusType, "M2<int>").WithArguments("").WithLocation(9, 13)
                );
        }
 
        [Fact]
        public void LoadingUnmanagedTypeModifier_ModreqWithoutAttribute()
        {
            var ilSource = IsUnmanagedAttributeIL + @"
.class public auto ansi beforefieldinit TestRef
       extends [mscorlib]System.Object
{
  .method public hidebysig instance void
          M1<valuetype .ctor (class [mscorlib]System.ValueType modreq([mscorlib]System.Runtime.InteropServices.UnmanagedType)) T>() cil managed
  {
    .param type T
    .custom instance void System.Runtime.CompilerServices.IsUnmanagedAttribute::.ctor() = ( 01 00 00 00 )
    // Code size       2 (0x2)
    .maxstack  8
    IL_0000:  nop
    IL_0001:  ret
  } // end of method TestRef::M1
 
  .method public hidebysig instance void
          M2<valuetype .ctor (class [mscorlib]System.ValueType modreq([mscorlib]System.Runtime.InteropServices.UnmanagedType)) T>() cil managed
  {
    // Code size       2 (0x2)
    .maxstack  8
    IL_0000:  nop
    IL_0001:  ret
  } // end of method TestRef::M2
 
  .method public hidebysig specialname rtspecialname
          instance void  .ctor() cil managed
  {
    // Code size       8 (0x8)
    .maxstack  8
    IL_0000:  ldarg.0
    IL_0001:  call       instance void [mscorlib]System.Object::.ctor()
    IL_0006:  nop
    IL_0007:  ret
  } // end of method TestRef::.ctor
 
}";
 
            var reference = CompileIL(ilSource, prependDefaultHeader: false);
 
            var code = @"
public class Test
{
    public static void Main()
    {
        var obj = new TestRef();
 
        obj.M1<int>();      // valid
        obj.M2<int>();      // invalid
    }
}";
 
            CreateCompilation(code, references: new[] { reference }).VerifyDiagnostics(
                // (9,13): error CS0570: 'T' is not supported by the language
                //         obj.M2<int>();      // invalid
                Diagnostic(ErrorCode.ERR_BindToBogus, "M2<int>").WithArguments("T").WithLocation(9, 13)
                );
        }
 
        [Fact]
        [WorkItem("https://github.com/dotnet/roslyn/issues/75681")]
        public void LoadingUnmanagedTypeModifier_ModreqGeneric()
        {
            var ilSource = IsUnmanagedAttributeIL + @"
.class public auto ansi beforefieldinit TestRef
       extends [mscorlib]System.Object
{
  .method public hidebysig instance void
          M1<valuetype .ctor (class [mscorlib]System.ValueType modreq(System.Runtime.InteropServices.UnmanagedType`1)) T>() cil managed
  {
    .param type T
    .custom instance void System.Runtime.CompilerServices.IsUnmanagedAttribute::.ctor() = ( 01 00 00 00 )
    // Code size       2 (0x2)
    .maxstack  8
    IL_0000:  nop
    IL_0001:  ret
  } // end of method TestRef::M1
 
  .method public hidebysig specialname rtspecialname
          instance void  .ctor() cil managed
  {
    // Code size       8 (0x8)
    .maxstack  8
    IL_0000:  ldarg.0
    IL_0001:  call       instance void [mscorlib]System.Object::.ctor()
    IL_0006:  nop
    IL_0007:  ret
  } // end of method TestRef::.ctor
}
 
.class public auto ansi beforefieldinit System.Runtime.InteropServices.UnmanagedType`1<T>
    extends [mscorlib]System.Object
{
    .method public hidebysig specialname rtspecialname 
        instance void .ctor () cil managed 
    {
        .maxstack 8
 
        IL_0000: ldarg.0
        IL_0001: call instance void [mscorlib]System.Object::.ctor()
        IL_0006: ret
    }
}
";
 
            var reference = CompileIL(ilSource, prependDefaultHeader: false);
 
            var code = @"
public class Test
{
    public static void Main()
    {
        var obj = new TestRef();
 
        obj.M1<int>();
    }
}";
 
            CreateCompilation(code, references: new[] { reference }).VerifyDiagnostics(
                // An error is expected here, see https://github.com/dotnet/roslyn/issues/75681
                );
        }
 
        [Fact]
        public void LoadingUnmanagedTypeModifier_AttributeWithoutModreq()
        {
            var ilSource = IsUnmanagedAttributeIL + @"
.class public auto ansi beforefieldinit TestRef
       extends [mscorlib]System.Object
{
  .method public hidebysig instance void
          M1<valuetype .ctor (class [mscorlib]System.ValueType modreq([mscorlib]System.Runtime.InteropServices.UnmanagedType)) T>() cil managed
  {
    .param type T
    .custom instance void System.Runtime.CompilerServices.IsUnmanagedAttribute::.ctor() = ( 01 00 00 00 )
    // Code size       2 (0x2)
    .maxstack  8
    IL_0000:  nop
    IL_0001:  ret
  } // end of method TestRef::M1
 
  .method public hidebysig instance void
          M2<valuetype .ctor (class [mscorlib]System.ValueType) T>() cil managed
  {
    .param type T
    .custom instance void System.Runtime.CompilerServices.IsUnmanagedAttribute::.ctor() = ( 01 00 00 00 )
    // Code size       2 (0x2)
    .maxstack  8
    IL_0000:  nop
    IL_0001:  ret
  } // end of method TestRef::M2
 
  .method public hidebysig specialname rtspecialname
          instance void  .ctor() cil managed
  {
    // Code size       8 (0x8)
    .maxstack  8
    IL_0000:  ldarg.0
    IL_0001:  call       instance void [mscorlib]System.Object::.ctor()
    IL_0006:  nop
    IL_0007:  ret
  } // end of method TestRef::.ctor
 
}";
 
            var reference = CompileIL(ilSource, prependDefaultHeader: false);
 
            var code = @"
public class Test
{
    public static void Main()
    {
        var obj = new TestRef();
 
        obj.M1<int>();      // valid
        obj.M2<int>();      // invalid
    }
}";
 
            CreateCompilation(code, references: new[] { reference }).VerifyDiagnostics(
                // (9,13): error CS0570: 'T' is not supported by the language
                //         obj.M2<int>();      // invalid
                Diagnostic(ErrorCode.ERR_BindToBogus, "M2<int>").WithArguments("T").WithLocation(9, 13)
                );
        }
 
        [Fact]
        public void ProperErrorsArePropagatedIfModreqTypeIsNotAvailable_Class()
        {
            var code = @"
namespace System
{
    public class Object {}
    public class Void {}
    public class ValueType {}
}
class Test<T> where T : unmanaged
{
}";
 
            CreateEmptyCompilation(code).VerifyDiagnostics(
                // (8,25): error CS0518: Predefined type 'System.Runtime.InteropServices.UnmanagedType' is not defined or imported
                // class Test<T> where T : unmanaged
                Diagnostic(ErrorCode.ERR_PredefinedTypeNotFound, "unmanaged").WithArguments("System.Runtime.InteropServices.UnmanagedType").WithLocation(8, 25));
        }
 
        [Fact]
        public void ProperErrorsArePropagatedIfModreqTypeIsNotAvailable_Method()
        {
            var code = @"
namespace System
{
    public class Object {}
    public class Void {}
    public class ValueType {}
}
class Test
{
    public void M<T>() where T : unmanaged {}
}";
 
            CreateEmptyCompilation(code).VerifyDiagnostics(
                // (10,34): error CS0518: Predefined type 'System.Runtime.InteropServices.UnmanagedType' is not defined or imported
                //     public void M<T>() where T : unmanaged {}
                Diagnostic(ErrorCode.ERR_PredefinedTypeNotFound, "unmanaged").WithArguments("System.Runtime.InteropServices.UnmanagedType").WithLocation(10, 34));
        }
 
        [Fact]
        public void ProperErrorsArePropagatedIfModreqTypeIsNotAvailable_Delegate()
        {
            var code = @"
namespace System
{
    public class Object {}
    public class Void {}
    public class ValueType {}
    public class IntPtr {}
    public class MulticastDelegate {}
}
public delegate void D<T>() where T : unmanaged;";
 
            CreateEmptyCompilation(code).VerifyDiagnostics(
                // (10,39): error CS0518: Predefined type 'System.Runtime.InteropServices.UnmanagedType' is not defined or imported
                // public delegate void D<T>() where T : unmanaged;
                Diagnostic(ErrorCode.ERR_PredefinedTypeNotFound, "unmanaged").WithArguments("System.Runtime.InteropServices.UnmanagedType").WithLocation(10, 39));
        }
 
        [Fact]
        public void ProperErrorsArePropagatedIfModreqTypeIsNotAvailable_LocalFunction()
        {
            var code = @"
namespace System
{
    public class Object {}
    public class Void {}
    public class ValueType {}
    public class IntPtr {}
    public class MulticastDelegate {}
}
public class Test
{
    public struct S {}
 
    public void M()
    {
        void N<T>() where T : unmanaged
        {
        }
 
        N<S>();
    }
}";
 
            CreateEmptyCompilation(code).VerifyDiagnostics(
                // (16,31): error CS0518: Predefined type 'System.Runtime.InteropServices.UnmanagedType' is not defined or imported
                //         void N<T>() where T : unmanaged
                Diagnostic(ErrorCode.ERR_PredefinedTypeNotFound, "unmanaged").WithArguments("System.Runtime.InteropServices.UnmanagedType").WithLocation(16, 31));
        }
 
        [Fact]
        public void ProperErrorsArePropagatedIfValueTypeIsNotAvailable_Class()
        {
            var code = @"
namespace System
{
    public class Object {}
    public class Void {}
 
    namespace Runtime
    {
        namespace InteropServices
        {
            public class UnmanagedType {}
        }
    }
}
class Test<T> where T : unmanaged
{
}";
 
            CreateEmptyCompilation(code).VerifyDiagnostics(
                // (15,25): error CS0518: Predefined type 'System.ValueType' is not defined or imported
                // class Test<T> where T : unmanaged
                Diagnostic(ErrorCode.ERR_PredefinedTypeNotFound, "unmanaged").WithArguments("System.ValueType").WithLocation(15, 25));
        }
 
        [Fact]
        public void ProperErrorsArePropagatedIfValueTypeIsNotAvailable_Method()
        {
            var code = @"
namespace System
{
    public class Object {}
    public class Void {}
 
    namespace Runtime
    {
        namespace InteropServices
        {
            public class UnmanagedType {}
        }
    }
}
class Test
{
    public void M<T>() where T : unmanaged {}
}";
 
            CreateEmptyCompilation(code).VerifyDiagnostics(
                // (17,34): error CS0518: Predefined type 'System.ValueType' is not defined or imported
                //     public void M<T>() where T : unmanaged {}
                Diagnostic(ErrorCode.ERR_PredefinedTypeNotFound, "unmanaged").WithArguments("System.ValueType").WithLocation(17, 34));
        }
 
        [Fact]
        public void ProperErrorsArePropagatedIfValueTypeIsNotAvailable_Delegate()
        {
            var code = @"
namespace System
{
    public class Object {}
    public class Void {}
    public class IntPtr {}
    public class MulticastDelegate {}
 
    namespace Runtime
    {
        namespace InteropServices
        {
            public class UnmanagedType {}
        }
    }
}
public delegate void M<T>() where T : unmanaged;";
 
            CreateEmptyCompilation(code).VerifyDiagnostics(
                // (17,39): error CS0518: Predefined type 'System.ValueType' is not defined or imported
                // public delegate void M<T>() where T : unmanaged;
                Diagnostic(ErrorCode.ERR_PredefinedTypeNotFound, "unmanaged").WithArguments("System.ValueType").WithLocation(17, 39));
        }
 
        [Fact]
        public void ProperErrorsArePropagatedIfValueTypeIsNotAvailable_LocalFunctions()
        {
            var code = @"
namespace System
{
    public class Object {}
    public class Void {}
    public struct Int32 {}
 
    namespace Runtime
    {
        namespace InteropServices
        {
            public class UnmanagedType {}
        }
    }
}
class Test
{
    public void M()
    {
        void N<T>() where T : unmanaged
        {
        }
 
        N<int>();
    }
}";
 
            CreateEmptyCompilation(code).VerifyDiagnostics(
                // (6,19): error CS0518: Predefined type 'System.ValueType' is not defined or imported
                //     public struct Int32 {}
                Diagnostic(ErrorCode.ERR_PredefinedTypeNotFound, "Int32").WithArguments("System.ValueType").WithLocation(6, 19),
                // (20,31): error CS0518: Predefined type 'System.ValueType' is not defined or imported
                //         void N<T>() where T : unmanaged
                Diagnostic(ErrorCode.ERR_PredefinedTypeNotFound, "unmanaged").WithArguments("System.ValueType").WithLocation(20, 31));
        }
 
        [Fact]
        public void UnmanagedTypeModreqIsCopiedToOverrides_Virtual_Compilation()
        {
            var reference = CompileAndVerify(@"
public class Parent
{
    public virtual string M<T>() where T : unmanaged => ""Parent"";
}
public class Child : Parent
{
    public override string M<T>() => ""Child"";
}", symbolValidator: module =>
            {
                var parentTypeParameter = module.ContainingAssembly.GetTypeByMetadataName("Parent").GetMethod("M").TypeParameters.Single();
                Assert.True(parentTypeParameter.HasValueTypeConstraint);
                Assert.True(parentTypeParameter.HasUnmanagedTypeConstraint);
 
                AttributeValidation.AssertReferencedIsUnmanagedAttribute(Accessibility.Internal, parentTypeParameter, module.ContainingAssembly.Name);
 
                var childTypeParameter = module.ContainingAssembly.GetTypeByMetadataName("Child").GetMethod("M").TypeParameters.Single();
                Assert.True(childTypeParameter.HasValueTypeConstraint);
                Assert.True(childTypeParameter.HasUnmanagedTypeConstraint);
 
                AttributeValidation.AssertReferencedIsUnmanagedAttribute(Accessibility.Internal, childTypeParameter, module.ContainingAssembly.Name);
            });
 
            CompileAndVerify(@"
class Program
{
    public static void Main()
    {
        System.Console.WriteLine(new Parent().M<int>());
        System.Console.WriteLine(new Child().M<int>());
    }
}", references: new[] { reference.Compilation.EmitToImageReference() }, expectedOutput: @"
Parent
Child");
        }
 
        [Fact]
        public void UnmanagedTypeModreqIsCopiedToOverrides_Virtual_Reference()
        {
            var parent = CompileAndVerify(@"
public class Parent
{
    public virtual string M<T>() where T : unmanaged => ""Parent"";
}", symbolValidator: module =>
            {
                var typeParameter = module.ContainingAssembly.GetTypeByMetadataName("Parent").GetMethod("M").TypeParameters.Single();
                Assert.True(typeParameter.HasValueTypeConstraint);
                Assert.True(typeParameter.HasUnmanagedTypeConstraint);
 
                AttributeValidation.AssertReferencedIsUnmanagedAttribute(Accessibility.Internal, typeParameter, module.ContainingAssembly.Name);
            });
 
            var child = CompileAndVerify(@"
public class Child : Parent
{
    public override string M<T>() => ""Child"";
}", references: new[] { parent.Compilation.EmitToImageReference() }, symbolValidator: module =>
            {
                var typeParameter = module.ContainingAssembly.GetTypeByMetadataName("Child").GetMethod("M").TypeParameters.Single();
                Assert.True(typeParameter.HasValueTypeConstraint);
                Assert.True(typeParameter.HasUnmanagedTypeConstraint);
 
                AttributeValidation.AssertReferencedIsUnmanagedAttribute(Accessibility.Internal, typeParameter, module.ContainingAssembly.Name);
            });
 
            CompileAndVerify(@"
class Program
{
    public static void Main()
    {
        System.Console.WriteLine(new Parent().M<int>());
        System.Console.WriteLine(new Child().M<int>());
    }
}", references: new[] { parent.Compilation.EmitToImageReference(), child.Compilation.EmitToImageReference() }, expectedOutput: @"
Parent
Child");
        }
 
        [Fact]
        public void UnmanagedTypeModreqIsCopiedToOverrides_Abstract_Compilation()
        {
            var reference = CompileAndVerify(@"
public abstract class Parent
{
    public abstract string M<T>() where T : unmanaged;
}
public class Child : Parent
{
    public override string M<T>() => ""Child"";
}", symbolValidator: module =>
            {
                var parentTypeParameter = module.ContainingAssembly.GetTypeByMetadataName("Parent").GetMethod("M").TypeParameters.Single();
                Assert.True(parentTypeParameter.HasValueTypeConstraint);
                Assert.True(parentTypeParameter.HasUnmanagedTypeConstraint);
 
                AttributeValidation.AssertReferencedIsUnmanagedAttribute(Accessibility.Internal, parentTypeParameter, module.ContainingAssembly.Name);
 
                var childTypeParameter = module.ContainingAssembly.GetTypeByMetadataName("Child").GetMethod("M").TypeParameters.Single();
                Assert.True(childTypeParameter.HasValueTypeConstraint);
                Assert.True(childTypeParameter.HasUnmanagedTypeConstraint);
 
                AttributeValidation.AssertReferencedIsUnmanagedAttribute(Accessibility.Internal, childTypeParameter, module.ContainingAssembly.Name);
            });
 
            CompileAndVerify(@"
class Program
{
    public static void Main()
    {
        System.Console.WriteLine(new Child().M<int>());
    }
}", references: new[] { reference.Compilation.EmitToImageReference() }, expectedOutput: "Child");
        }
 
        [Fact]
        public void UnmanagedTypeModreqIsCopiedToOverrides_Abstract_Reference()
        {
            var parent = CompileAndVerify(@"
public abstract class Parent
{
    public abstract string M<T>() where T : unmanaged;
}", symbolValidator: module =>
            {
                var typeParameter = module.ContainingAssembly.GetTypeByMetadataName("Parent").GetMethod("M").TypeParameters.Single();
                Assert.True(typeParameter.HasValueTypeConstraint);
                Assert.True(typeParameter.HasUnmanagedTypeConstraint);
 
                AttributeValidation.AssertReferencedIsUnmanagedAttribute(Accessibility.Internal, typeParameter, module.ContainingAssembly.Name);
            });
 
            var child = CompileAndVerify(@"
public class Child : Parent
{
    public override string M<T>() => ""Child"";
}", references: new[] { parent.Compilation.EmitToImageReference() }, symbolValidator: module =>
            {
                var typeParameter = module.ContainingAssembly.GetTypeByMetadataName("Child").GetMethod("M").TypeParameters.Single();
                Assert.True(typeParameter.HasValueTypeConstraint);
                Assert.True(typeParameter.HasUnmanagedTypeConstraint);
 
                AttributeValidation.AssertReferencedIsUnmanagedAttribute(Accessibility.Internal, typeParameter, module.ContainingAssembly.Name);
            });
 
            CompileAndVerify(@"
class Program
{
    public static void Main()
    {
        System.Console.WriteLine(new Child().M<int>());
    }
}", references: new[] { parent.Compilation.EmitToImageReference(), child.Compilation.EmitToImageReference() }, expectedOutput: "Child");
        }
 
        [Fact]
        public void UnmanagedTypeModreqIsCopiedToOverrides_Interface_Implicit_Nonvirtual_Compilation()
        {
            var reference = CompileAndVerify(@"
public interface Parent
{
    string M<T>() where T : unmanaged;
}
public class Child : Parent
{
    public string M<T>() where T : unmanaged => ""Child"";
}", symbolValidator: module =>
            {
                var parentTypeParameter = module.ContainingAssembly.GetTypeByMetadataName("Parent").GetMethod("M").TypeParameters.Single();
                Assert.True(parentTypeParameter.HasValueTypeConstraint);
                Assert.True(parentTypeParameter.HasUnmanagedTypeConstraint);
 
                AttributeValidation.AssertReferencedIsUnmanagedAttribute(Accessibility.Internal, parentTypeParameter, module.ContainingAssembly.Name);
 
                var childTypeParameter = module.ContainingAssembly.GetTypeByMetadataName("Child").GetMethod("M").TypeParameters.Single();
                Assert.True(childTypeParameter.HasValueTypeConstraint);
                Assert.True(childTypeParameter.HasUnmanagedTypeConstraint);
 
                AttributeValidation.AssertReferencedIsUnmanagedAttribute(Accessibility.Internal, childTypeParameter, module.ContainingAssembly.Name);
            });
 
            CompileAndVerify(@"
class Program
{
    public static void Main()
    {
        System.Console.WriteLine(new Child().M<int>());
    }
}", references: new[] { reference.Compilation.EmitToImageReference() }, expectedOutput: "Child");
        }
 
        [Fact]
        public void UnmanagedTypeModreqIsCopiedToOverrides_Interface_Implicit_Nonvirtual_Reference()
        {
            var parent = CompileAndVerify(@"
public interface Parent
{
    string M<T>() where T : unmanaged;
}", symbolValidator: module =>
            {
                var typeParameter = module.ContainingAssembly.GetTypeByMetadataName("Parent").GetMethod("M").TypeParameters.Single();
                Assert.True(typeParameter.HasValueTypeConstraint);
                Assert.True(typeParameter.HasUnmanagedTypeConstraint);
 
                AttributeValidation.AssertReferencedIsUnmanagedAttribute(Accessibility.Internal, typeParameter, module.ContainingAssembly.Name);
            });
 
            var child = CompileAndVerify(@"
public class Child : Parent
{
    public string M<T>() where T : unmanaged => ""Child"";
}", references: new[] { parent.Compilation.EmitToImageReference() }, symbolValidator: module =>
            {
                var typeParameter = module.ContainingAssembly.GetTypeByMetadataName("Child").GetMethod("M").TypeParameters.Single();
                Assert.True(typeParameter.HasValueTypeConstraint);
                Assert.True(typeParameter.HasUnmanagedTypeConstraint);
 
                AttributeValidation.AssertReferencedIsUnmanagedAttribute(Accessibility.Internal, typeParameter, module.ContainingAssembly.Name);
            });
 
            CompileAndVerify(@"
class Program
{
    public static void Main()
    {
        System.Console.WriteLine(new Child().M<int>());
    }
}", references: new[] { parent.Compilation.EmitToImageReference(), child.Compilation.EmitToImageReference() }, expectedOutput: "Child");
        }
 
        [Fact]
        public void UnmanagedTypeModreqIsCopiedToOverrides_Interface_Implicit_Virtual_Compilation()
        {
            var reference = CompileAndVerify(@"
public interface Parent
{
    string M<T>() where T : unmanaged;
}
public class Child : Parent
{
    public virtual string M<T>() where T : unmanaged => ""Child"";
}", symbolValidator: module =>
            {
                var parentTypeParameter = module.ContainingAssembly.GetTypeByMetadataName("Parent").GetMethod("M").TypeParameters.Single();
                Assert.True(parentTypeParameter.HasValueTypeConstraint);
                Assert.True(parentTypeParameter.HasUnmanagedTypeConstraint);
 
                AttributeValidation.AssertReferencedIsUnmanagedAttribute(Accessibility.Internal, parentTypeParameter, module.ContainingAssembly.Name);
 
                var childTypeParameter = module.ContainingAssembly.GetTypeByMetadataName("Child").GetMethod("M").TypeParameters.Single();
                Assert.True(childTypeParameter.HasValueTypeConstraint);
                Assert.True(childTypeParameter.HasUnmanagedTypeConstraint);
 
                AttributeValidation.AssertReferencedIsUnmanagedAttribute(Accessibility.Internal, childTypeParameter, module.ContainingAssembly.Name);
            });
 
            CompileAndVerify(@"
class Program
{
    public static void Main()
    {
        System.Console.WriteLine(new Child().M<int>());
    }
}", references: new[] { reference.Compilation.EmitToImageReference() }, expectedOutput: "Child");
        }
 
        [Fact]
        public void UnmanagedTypeModreqIsCopiedToOverrides_Interface_Implicit_Virtual_Reference()
        {
            var parent = CompileAndVerify(@"
public interface Parent
{
    string M<T>() where T : unmanaged;
}", symbolValidator: module =>
            {
                var typeParameter = module.ContainingAssembly.GetTypeByMetadataName("Parent").GetMethod("M").TypeParameters.Single();
                Assert.True(typeParameter.HasValueTypeConstraint);
                Assert.True(typeParameter.HasUnmanagedTypeConstraint);
 
                AttributeValidation.AssertReferencedIsUnmanagedAttribute(Accessibility.Internal, typeParameter, module.ContainingAssembly.Name);
            });
 
            var child = CompileAndVerify(@"
public class Child : Parent
{
    public virtual string M<T>() where T : unmanaged => ""Child"";
}", references: new[] { parent.Compilation.EmitToImageReference() }, symbolValidator: module =>
            {
                var typeParameter = module.ContainingAssembly.GetTypeByMetadataName("Child").GetMethod("M").TypeParameters.Single();
                Assert.True(typeParameter.HasValueTypeConstraint);
                Assert.True(typeParameter.HasUnmanagedTypeConstraint);
 
                AttributeValidation.AssertReferencedIsUnmanagedAttribute(Accessibility.Internal, typeParameter, module.ContainingAssembly.Name);
            });
 
            CompileAndVerify(@"
class Program
{
    public static void Main()
    {
        System.Console.WriteLine(new Child().M<int>());
    }
}", references: new[] { parent.Compilation.EmitToImageReference(), child.Compilation.EmitToImageReference() }, expectedOutput: "Child");
        }
 
        [Fact]
        public void UnmanagedTypeModreqIsCopiedToOverrides_Interface_Explicit_Compilation()
        {
            var reference = CompileAndVerify(@"
public interface Parent
{
    string M<T>() where T : unmanaged;
}
public class Child : Parent
{
    string Parent.M<T>() => ""Child"";
}", symbolValidator: module =>
            {
                var parentTypeParameter = module.ContainingAssembly.GetTypeByMetadataName("Parent").GetMethod("M").TypeParameters.Single();
                Assert.True(parentTypeParameter.HasValueTypeConstraint);
                Assert.True(parentTypeParameter.HasUnmanagedTypeConstraint);
 
                AttributeValidation.AssertReferencedIsUnmanagedAttribute(Accessibility.Internal, parentTypeParameter, module.ContainingAssembly.Name);
 
                var childTypeParameter = module.ContainingAssembly.GetTypeByMetadataName("Child").GetMethod("Parent.M").TypeParameters.Single();
                Assert.True(childTypeParameter.HasValueTypeConstraint);
                Assert.True(childTypeParameter.HasUnmanagedTypeConstraint);
 
                AttributeValidation.AssertReferencedIsUnmanagedAttribute(Accessibility.Internal, childTypeParameter, module.ContainingAssembly.Name);
            });
 
            CompileAndVerify(@"
class Program
{
    public static void Main()
    {
        Parent obj = new Child();
        System.Console.WriteLine(obj.M<int>());
    }
}", references: new[] { reference.Compilation.EmitToImageReference() }, expectedOutput: "Child");
        }
 
        [Fact]
        public void UnmanagedTypeModreqIsCopiedToOverrides_Interface_Explicit_Reference()
        {
            var parent = CompileAndVerify(@"
public interface Parent
{
    string M<T>() where T : unmanaged;
}", symbolValidator: module =>
            {
                var typeParameter = module.ContainingAssembly.GetTypeByMetadataName("Parent").GetMethod("M").TypeParameters.Single();
                Assert.True(typeParameter.HasValueTypeConstraint);
                Assert.True(typeParameter.HasUnmanagedTypeConstraint);
 
                AttributeValidation.AssertReferencedIsUnmanagedAttribute(Accessibility.Internal, typeParameter, module.ContainingAssembly.Name);
            });
 
            var child = CompileAndVerify(@"
public class Child : Parent
{
    string Parent.M<T>() => ""Child"";
}", references: new[] { parent.Compilation.EmitToImageReference() }, symbolValidator: module =>
            {
                var typeParameter = module.ContainingAssembly.GetTypeByMetadataName("Child").GetMethod("Parent.M").TypeParameters.Single();
                Assert.True(typeParameter.HasValueTypeConstraint);
                Assert.True(typeParameter.HasUnmanagedTypeConstraint);
 
                AttributeValidation.AssertReferencedIsUnmanagedAttribute(Accessibility.Internal, typeParameter, module.ContainingAssembly.Name);
            });
 
            CompileAndVerify(@"
class Program
{
    public static void Main()
    {
        Parent obj = new Child();
        System.Console.WriteLine(obj.M<int>());
    }
}", references: new[] { parent.Compilation.EmitToImageReference(), child.Compilation.EmitToImageReference() }, expectedOutput: "Child");
        }
 
        [Fact]
        public void UnmanagedTypeModreqIsCopiedToLambda_Compilation()
        {
            CompileAndVerify(@"
public delegate T D<T>() where T : unmanaged;
public class TestRef
{
    public static void Print<T>(D<T> lambda) where T : unmanaged
    {
        System.Console.WriteLine(lambda());
    }
}
public class Program
{
    static void Test<T>(T arg)  where T : unmanaged
    {
        TestRef.Print(() => arg);
    }
    
    public static void Main()
    {
        Test(5);
    }
}",
                expectedOutput: "5",
                options: TestOptions.ReleaseExe.WithMetadataImportOptions(MetadataImportOptions.All),
                symbolValidator: module =>
            {
                var delegateTypeParameter = module.ContainingAssembly.GetTypeByMetadataName("D`1").TypeParameters.Single();
                Assert.True(delegateTypeParameter.HasValueTypeConstraint);
                Assert.True(delegateTypeParameter.HasUnmanagedTypeConstraint);
 
                AttributeValidation.AssertReferencedIsUnmanagedAttribute(Accessibility.Internal, delegateTypeParameter, module.ContainingAssembly.Name);
 
                var lambdaTypeParameter = module.ContainingAssembly.GetTypeByMetadataName("Program").GetTypeMember("<>c__DisplayClass0_0").TypeParameters.Single();
                Assert.True(lambdaTypeParameter.HasValueTypeConstraint);
                Assert.True(lambdaTypeParameter.HasUnmanagedTypeConstraint);
 
                AttributeValidation.AssertReferencedIsUnmanagedAttribute(Accessibility.Internal, lambdaTypeParameter, module.ContainingAssembly.Name);
            });
        }
 
        [Fact]
        public void UnmanagedTypeModreqIsCopiedToLambda_Reference()
        {
            var reference = CompileAndVerify(@"
public delegate T D<T>() where T : unmanaged;
public class TestRef
{
    public static void Print<T>(D<T> lambda) where T : unmanaged
    {
        System.Console.WriteLine(lambda());
    }
}", symbolValidator: module =>
            {
                var typeParameter = module.ContainingAssembly.GetTypeByMetadataName("D`1").TypeParameters.Single();
                Assert.True(typeParameter.HasValueTypeConstraint);
                Assert.True(typeParameter.HasUnmanagedTypeConstraint);
                Assert.False(typeParameter.HasConstructorConstraint);   // .ctor  is an artifact of emit, we will ignore it on importing.
 
                AttributeValidation.AssertReferencedIsUnmanagedAttribute(Accessibility.Internal, typeParameter, module.ContainingAssembly.Name);
            });
 
            CompileAndVerify(@"
public class Program
{
    static void Test<T>(T arg)  where T : unmanaged
    {
        TestRef.Print(() => arg);
    }
    
    public static void Main()
    {
        Test(5);
    }
}",
                expectedOutput: "5",
                references: new[] { reference.Compilation.EmitToImageReference() },
                options: TestOptions.ReleaseExe.WithMetadataImportOptions(MetadataImportOptions.All),
                symbolValidator: module =>
                {
                    var typeParameter = module.ContainingAssembly.GetTypeByMetadataName("Program").GetTypeMember("<>c__DisplayClass0_0").TypeParameters.Single();
                    Assert.True(typeParameter.HasValueTypeConstraint);
                    Assert.True(typeParameter.HasUnmanagedTypeConstraint);
                    Assert.False(typeParameter.HasConstructorConstraint);  // .ctor  is an artifact of emit, we will ignore it on importing.
 
                    AttributeValidation.AssertReferencedIsUnmanagedAttribute(Accessibility.Internal, typeParameter, module.ContainingAssembly.Name);
                });
        }
 
        [Fact]
        public void DuplicateUnmanagedTypeInReferences()
        {
            var refCode = @"
namespace System.Runtime.InteropServices
{
    public class UnmanagedType {}
}";
 
            var ref1 = CreateCompilation(refCode).EmitToImageReference();
            var ref2 = CreateCompilation(refCode).EmitToImageReference();
 
            var user = @"
public class Test<T> where T : unmanaged
{
}";
 
            CreateCompilation(user, references: new[] { ref1, ref2 }).VerifyDiagnostics();
        }
 
        [Fact]
        public void DuplicateUnmanagedTypeInReferences_NoTypeInCorlib()
        {
            var corlib_cs = @"
namespace System
{
    public class Object { }
    public struct Int32 { }
    public struct Boolean { }
    public class String { }
    public class ValueType { }
    public struct Void { }
    public class Attribute { }
    public class AttributeUsageAttribute : Attribute
    {
        public AttributeUsageAttribute(AttributeTargets t) { }
        public bool AllowMultiple { get; set; }
        public bool Inherited { get; set; }
    }
    public struct Enum { }
    public enum AttributeTargets { }
}
";
 
            var corlibWithoutUnmanagedTypeRef = CreateEmptyCompilation(corlib_cs).EmitToImageReference();
 
            var refCode = @"
namespace System.Runtime.InteropServices
{
    public class UnmanagedType {}
}";
 
            var ref1 = CreateEmptyCompilation(refCode, references: new[] { corlibWithoutUnmanagedTypeRef }).EmitToImageReference();
            var ref2 = CreateEmptyCompilation(refCode, references: new[] { corlibWithoutUnmanagedTypeRef }).EmitToImageReference();
 
            var user = @"
public class Test<T> where T : unmanaged
{
}";
 
            CreateEmptyCompilation(user, references: new[] { ref1, ref2, corlibWithoutUnmanagedTypeRef })
                .VerifyDiagnostics(
                    // (2,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(2, 32));
        }
 
        [Fact]
        public void UnmanagedConstraintWithClassConstraint_IL()
        {
            var ilSource = IsUnmanagedAttributeIL + @"
.class public auto ansi beforefieldinit TestRef
       extends [mscorlib]System.Object
{
  .method public hidebysig instance void
          M<class (class [mscorlib]System.ValueType modreq([mscorlib]System.Runtime.InteropServices.UnmanagedType)) T>() cil managed
  {
    .param type T
    .custom instance void System.Runtime.CompilerServices.IsUnmanagedAttribute::.ctor() = ( 01 00 00 00 )
    // Code size       2 (0x2)
    .maxstack  8
    IL_0000:  nop
    IL_0001:  ret
  } // end of method TestRef::M
 
  .method public hidebysig specialname rtspecialname
          instance void  .ctor() cil managed
  {
    // Code size       8 (0x8)
    .maxstack  8
    IL_0000:  ldarg.0
    IL_0001:  call       instance void [mscorlib]System.Object::.ctor()
    IL_0006:  nop
    IL_0007:  ret
  } // end of method TestRef::.ctor
 
}";
 
            var reference = CompileIL(ilSource, prependDefaultHeader: false);
 
            var code = @"
public class Test
{
    public static void Main()
    {
        new TestRef().M<int>();
        new TestRef().M<string>();
    }
}";
 
            CreateCompilation(code, references: new[] { reference }).VerifyDiagnostics(
                // (6,23): error CS0452: The type 'int' must be a reference type in order to use it as parameter 'T' in the generic type or method 'TestRef.M<T>()'
                //         new TestRef().M<int>();
                Diagnostic(ErrorCode.ERR_RefConstraintNotSatisfied, "M<int>").WithArguments("TestRef.M<T>()", "T", "int").WithLocation(6, 23),
                // (7,23): error CS0311: The type 'string' cannot be used as type parameter 'T' in the generic type or method 'TestRef.M<T>()'. There is no implicit reference conversion from 'string' to 'System.ValueType'.
                //         new TestRef().M<string>();
                Diagnostic(ErrorCode.ERR_GenericConstraintNotSatisfiedRefType, "M<string>").WithArguments("TestRef.M<T>()", "System.ValueType", "T", "string").WithLocation(7, 23),
                // (7,23): error CS0570: 'T' is not supported by the language
                //         new TestRef().M<string>();
                Diagnostic(ErrorCode.ERR_BindToBogus, "M<string>").WithArguments("T").WithLocation(7, 23)
                );
        }
 
        [Fact]
        public void UnmanagedConstraintWithConstructorConstraint_IL()
        {
            var ilSource = IsUnmanagedAttributeIL + @"
.class public auto ansi beforefieldinit TestRef
       extends [mscorlib]System.Object
{
  .method public hidebysig instance void
          M<.ctor (class [mscorlib]System.ValueType modreq([mscorlib]System.Runtime.InteropServices.UnmanagedType)) T>() cil managed
  {
    .param type T
    .custom instance void System.Runtime.CompilerServices.IsUnmanagedAttribute::.ctor() = ( 01 00 00 00 )
    // Code size       2 (0x2)
    .maxstack  8
    IL_0000:  nop
    IL_0001:  ret
  } // end of method TestRef::M
 
  .method public hidebysig specialname rtspecialname
          instance void  .ctor() cil managed
  {
    // Code size       8 (0x8)
    .maxstack  8
    IL_0000:  ldarg.0
    IL_0001:  call       instance void [mscorlib]System.Object::.ctor()
    IL_0006:  nop
    IL_0007:  ret
  } // end of method TestRef::.ctor
 
}";
 
            var reference = CompileIL(ilSource, prependDefaultHeader: false);
 
            var code = @"
public class Test
{
    public static void Main()
    {
        new TestRef().M<int>();
        new TestRef().M<string>();
    }
}";
 
            CreateCompilation(code, references: new[] { reference }).VerifyDiagnostics(
                // (6,23): error CS0570: 'T' is not supported by the language
                //         new TestRef().M<int>();
                Diagnostic(ErrorCode.ERR_BindToBogus, "M<int>").WithArguments("T").WithLocation(6, 23),
                // (7,23): error CS0311: The type 'string' cannot be used as type parameter 'T' in the generic type or method 'TestRef.M<T>()'. There is no implicit reference conversion from 'string' to 'System.ValueType'.
                //         new TestRef().M<string>();
                Diagnostic(ErrorCode.ERR_GenericConstraintNotSatisfiedRefType, "M<string>").WithArguments("TestRef.M<T>()", "System.ValueType", "T", "string").WithLocation(7, 23),
                // (7,23): 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 'TestRef.M<T>()'
                //         new TestRef().M<string>();
                Diagnostic(ErrorCode.ERR_NewConstraintNotSatisfied, "M<string>").WithArguments("TestRef.M<T>()", "T", "string").WithLocation(7, 23),
                // (7,23): error CS0570: 'T' is not supported by the language
                //         new TestRef().M<string>();
                Diagnostic(ErrorCode.ERR_BindToBogus, "M<string>").WithArguments("T").WithLocation(7, 23));
        }
 
        [Fact]
        public void UnmanagedConstraintWithoutValueTypeConstraint_IL()
        {
            var ilSource = IsUnmanagedAttributeIL + @"
.class public auto ansi beforefieldinit TestRef
       extends [mscorlib]System.Object
{
  .method public hidebysig instance void
          M<(class [mscorlib]System.ValueType modreq([mscorlib]System.Runtime.InteropServices.UnmanagedType)) T>() cil managed
  {
    .param type T
    .custom instance void System.Runtime.CompilerServices.IsUnmanagedAttribute::.ctor() = ( 01 00 00 00 )
    // Code size       2 (0x2)
    .maxstack  8
    IL_0000:  nop
    IL_0001:  ret
  } // end of method TestRef::M
 
  .method public hidebysig specialname rtspecialname
          instance void  .ctor() cil managed
  {
    // Code size       8 (0x8)
    .maxstack  8
    IL_0000:  ldarg.0
    IL_0001:  call       instance void [mscorlib]System.Object::.ctor()
    IL_0006:  nop
    IL_0007:  ret
  } // end of method TestRef::.ctor
 
}";
 
            var reference = CompileIL(ilSource, prependDefaultHeader: false);
 
            var code = @"
public class Test
{
    public static void Main()
    {
        new TestRef().M<int>();
        new TestRef().M<string>();
    }
}";
 
            CreateCompilation(code, references: new[] { reference }).VerifyDiagnostics(
                // (6,23): error CS0570: 'T' is not supported by the language
                //         new TestRef().M<int>();
                Diagnostic(ErrorCode.ERR_BindToBogus, "M<int>").WithArguments("T").WithLocation(6, 23),
                // (7,23): error CS0311: The type 'string' cannot be used as type parameter 'T' in the generic type or method 'TestRef.M<T>()'. There is no implicit reference conversion from 'string' to 'System.ValueType'.
                //         new TestRef().M<string>();
                Diagnostic(ErrorCode.ERR_GenericConstraintNotSatisfiedRefType, "M<string>").WithArguments("TestRef.M<T>()", "System.ValueType", "T", "string").WithLocation(7, 23),
                // (7,23): error CS0570: 'T' is not supported by the language
                //         new TestRef().M<string>();
                Diagnostic(ErrorCode.ERR_BindToBogus, "M<string>").WithArguments("T").WithLocation(7, 23));
        }
 
        [Fact]
        public void UnmanagedConstraintWithTypeConstraint_IL()
        {
            var ilSource = IsUnmanagedAttributeIL + @"
.class public auto ansi beforefieldinit TestRef
       extends [mscorlib]System.Object
{
  .method public hidebysig instance void
          M<valuetype .ctor (class [mscorlib]System.IComparable, class [mscorlib]System.ValueType modreq([mscorlib]System.Runtime.InteropServices.UnmanagedType)) T>() cil managed
  {
    .param type T
    .custom instance void System.Runtime.CompilerServices.IsUnmanagedAttribute::.ctor() = ( 01 00 00 00 )
    // Code size       2 (0x2)
    .maxstack  8
    IL_0000:  nop
    IL_0001:  ret
  } // end of method TestRef::M
 
  .method public hidebysig specialname rtspecialname
          instance void  .ctor() cil managed
  {
    // Code size       8 (0x8)
    .maxstack  8
    IL_0000:  ldarg.0
    IL_0001:  call       instance void [mscorlib]System.Object::.ctor()
    IL_0006:  nop
    IL_0007:  ret
  } // end of method TestRef::.ctor
 
}";
 
            var reference = CompileIL(ilSource, prependDefaultHeader: false);
 
            var code = @"
public class Test
{
    public static void Main()
    {
        // OK
        new TestRef().M<int>();
 
        // Not IComparable
        new TestRef().M<S1>();
    }
 
    struct S1{}
}";
 
            CreateCompilation(code, references: new[] { reference }).VerifyDiagnostics(
                // (10,23): error CS0315: The type 'Test.S1' cannot be used as type parameter 'T' in the generic type or method 'TestRef.M<T>()'. There is no boxing conversion from 'Test.S1' to 'System.IComparable'.
                //         new TestRef().M<S1>();
                Diagnostic(ErrorCode.ERR_GenericConstraintNotSatisfiedValType, "M<S1>").WithArguments("TestRef.M<T>()", "System.IComparable", "T", "Test.S1").WithLocation(10, 23)
                );
        }
 
        [Fact]
        public void UnmanagedConstraintWithNoCtorConstraint_IL()
        {
            var ilSource = IsUnmanagedAttributeIL + @"
.class public auto ansi beforefieldinit TestRef
       extends [mscorlib]System.Object
{
  .method public hidebysig instance void
          M<valuetype (class [mscorlib]System.IComparable, class [mscorlib]System.ValueType modreq([mscorlib]System.Runtime.InteropServices.UnmanagedType)) T>() cil managed
  {
    .param type T
    .custom instance void System.Runtime.CompilerServices.IsUnmanagedAttribute::.ctor() = ( 01 00 00 00 )
    // Code size       2 (0x2)
    .maxstack  8
    IL_0000:  nop
    IL_0001:  ret
  } // end of method TestRef::M
 
  .method public hidebysig specialname rtspecialname
          instance void  .ctor() cil managed
  {
    // Code size       8 (0x8)
    .maxstack  8
    IL_0000:  ldarg.0
    IL_0001:  call       instance void [mscorlib]System.Object::.ctor()
    IL_0006:  nop
    IL_0007:  ret
  } // end of method TestRef::.ctor
 
}";
 
            var reference = CompileIL(ilSource, prependDefaultHeader: false);
 
            var code = @"
public class Test
{
    public static void Main()
    {
        // OK
        new TestRef().M<int>();
 
        // Not IComparable
        new TestRef().M<S1>();
    }
 
    struct S1{}
}";
 
            var c = CreateCompilation(code, references: new[] { reference });
 
            c.VerifyDiagnostics(
                // (10,23): error CS0315: The type 'Test.S1' cannot be used as type parameter 'T' in the generic type or method 'TestRef.M<T>()'. There is no boxing conversion from 'Test.S1' to 'System.IComparable'.
                //         new TestRef().M<S1>();
                Diagnostic(ErrorCode.ERR_GenericConstraintNotSatisfiedValType, "M<S1>").WithArguments("TestRef.M<T>()", "System.IComparable", "T", "Test.S1").WithLocation(10, 23)
                );
 
            var typeParameter = c.GlobalNamespace.GetTypeMember("TestRef").GetMethod("M").TypeParameters.Single();
            Assert.True(typeParameter.HasUnmanagedTypeConstraint);
            Assert.True(typeParameter.HasValueTypeConstraint);
            Assert.False(typeParameter.HasReferenceTypeConstraint);
            Assert.False(typeParameter.HasConstructorConstraint);
        }
 
        [Fact]
        [WorkItem(25654, "https://github.com/dotnet/roslyn/issues/25654")]
        public void UnmanagedConstraint_PointersTypeInference()
        {
            var code = @"
unsafe class Program
{
    static void M<T>(T* a) where T : unmanaged
    {
        System.Console.WriteLine(typeof(T).FullName);
    }
    static void Main()
    {
        int x = 5;
        M(&x);
 
        double y = 5.5;
        M(&y);
    }
}";
 
            CompileAndVerify(code, options: TestOptions.UnsafeReleaseExe, verify: Verification.Fails, expectedOutput: @"
System.Int32
System.Double
")
                .VerifyIL("Program.Main", @"
{
  // Code size       29 (0x1d)
  .maxstack  1
  .locals init (int V_0, //x
                double V_1) //y
  IL_0000:  ldc.i4.5
  IL_0001:  stloc.0
  IL_0002:  ldloca.s   V_0
  IL_0004:  conv.u
  IL_0005:  call       ""void Program.M<int>(int*)""
  IL_000a:  ldc.r8     5.5
  IL_0013:  stloc.1
  IL_0014:  ldloca.s   V_1
  IL_0016:  conv.u
  IL_0017:  call       ""void Program.M<double>(double*)""
  IL_001c:  ret
}");
        }
 
        private const string IsUnmanagedAttributeIL = @"
.assembly extern mscorlib
{
  .publickeytoken = (B7 7A 5C 56 19 34 E0 89 )
  .ver 4:0:0:0
}
.assembly Test
{
  .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilationRelaxationsAttribute::.ctor(int32) = ( 01 00 08 00 00 00 00 00 ) 
  .custom instance void [mscorlib]System.Runtime.CompilerServices.RuntimeCompatibilityAttribute::.ctor() = ( 01 00 01 00 54 02 16 57 72 61 70 4E 6F 6E 45 78 63 65 70 74 69 6F 6E 54 68 72 6F 77 73 01 )
  .hash algorithm 0x00008004
  .ver 0:0:0:0
}
.module Test.dll
.imagebase 0x10000000
.file alignment 0x00000200
.stackreserve 0x00100000
.subsystem 0x0003
.corflags 0x00000001
 
.class private auto ansi sealed beforefieldinit Microsoft.CodeAnalysis.EmbeddedAttribute
       extends [mscorlib]System.Attribute
{
  .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) 
  .custom instance void Microsoft.CodeAnalysis.EmbeddedAttribute::.ctor() = ( 01 00 00 00 ) 
  .method public hidebysig specialname rtspecialname 
          instance void  .ctor() cil managed
  {
    .maxstack  8
    IL_0000:  ldarg.0
    IL_0001:  call       instance void [mscorlib]System.Attribute::.ctor()
    IL_0006:  nop
    IL_0007:  ret
  }
}
 
.class private auto ansi sealed beforefieldinit System.Runtime.CompilerServices.IsUnmanagedAttribute
       extends [mscorlib]System.Attribute
{
  .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) 
  .custom instance void Microsoft.CodeAnalysis.EmbeddedAttribute::.ctor() = ( 01 00 00 00 ) 
  .method public hidebysig specialname rtspecialname 
          instance void  .ctor() cil managed
  {
    .maxstack  8
    IL_0000:  ldarg.0
    IL_0001:  call       instance void [mscorlib]System.Attribute::.ctor()
    IL_0006:  nop
    IL_0007:  ret
  }
}
";
    }
}