/
githubmirror
/
roslyn
Обзор
Документация
Войти
/
githubmirror
/
roslyn
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
src/Compilers/CSharp/Test/Semantic/Semantics/GenericConstraintsTests.cs
4 456 строк
199 KB
AlekseyTs
Detect struct cycles caused by erroneous field-like event declarations (#75668)
31 окт 2024, 01:35
Не верифицирован
31 окт 2024, 01:35
1fde068
Код
Авторство
О чём код?
// 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) ); } } }