diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Constraints.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Constraints.cs index 10d5b6ea9f9fe..4bbac7ae4e8c5 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder_Constraints.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder_Constraints.cs @@ -171,12 +171,17 @@ private TypeParameterConstraintClause BindTypeParameterConstraints( if ((constraints & (TypeParameterConstraintKind.ReferenceType | TypeParameterConstraintKind.ValueType)) != 0) { - // System.Enum is allowed to exist with class and struct constraints - if (type.SpecialType != SpecialType.System_Enum) + switch (type.SpecialType) { - // "'{0}': cannot specify both a constraint class and the 'class' or 'struct' constraint" - Error(diagnostics, ErrorCode.ERR_RefValBoundWithClass, syntax, type); - continue; + case SpecialType.System_Enum: + case SpecialType.System_Delegate: + case SpecialType.System_MulticastDelegate: + break; + + default: + // "'{0}': cannot specify both a constraint class and the 'class' or 'struct' constraint" + Error(diagnostics, ErrorCode.ERR_RefValBoundWithClass, syntax, type); + continue; } } } @@ -204,10 +209,13 @@ private static bool IsValidConstraintType(TypeConstraintSyntax syntax, TypeSymbo CheckFeatureAvailability(syntax, MessageID.IDS_FeatureEnumGenericTypeConstraint, diagnostics); break; - case SpecialType.System_Object: - case SpecialType.System_ValueType: case SpecialType.System_Delegate: case SpecialType.System_MulticastDelegate: + CheckFeatureAvailability(syntax, MessageID.IDS_FeatureDelegateGenericTypeConstraint, diagnostics); + break; + + case SpecialType.System_Object: + case SpecialType.System_ValueType: case SpecialType.System_Array: // "Constraint cannot be special class '{0}'" Error(diagnostics, ErrorCode.ERR_SpecialTypeAsBound, syntax, type); diff --git a/src/Compilers/CSharp/Portable/CSharpResources.Designer.cs b/src/Compilers/CSharp/Portable/CSharpResources.Designer.cs index 6f94d1648ae1b..4d86431e090cf 100644 --- a/src/Compilers/CSharp/Portable/CSharpResources.Designer.cs +++ b/src/Compilers/CSharp/Portable/CSharpResources.Designer.cs @@ -10349,6 +10349,15 @@ internal static string IDS_FeatureDefaultLiteral { } } + /// + /// Looks up a localized string similar to delegate generic type constraints. + /// + internal static string IDS_FeatureDelegateGenericTypeConstraint { + get { + return ResourceManager.GetString("IDS_FeatureDelegateGenericTypeConstraint", resourceCulture); + } + } + /// /// Looks up a localized string similar to dictionary initializer. /// diff --git a/src/Compilers/CSharp/Portable/CSharpResources.resx b/src/Compilers/CSharp/Portable/CSharpResources.resx index 5ee80ff140222..d1247c0c7e0f4 100644 --- a/src/Compilers/CSharp/Portable/CSharpResources.resx +++ b/src/Compilers/CSharp/Portable/CSharpResources.resx @@ -5249,4 +5249,7 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ enum generic type constraints + + delegate generic type constraints + \ No newline at end of file diff --git a/src/Compilers/CSharp/Portable/Errors/MessageID.cs b/src/Compilers/CSharp/Portable/Errors/MessageID.cs index 5bcb553d4dfb8..e1b371cf53552 100644 --- a/src/Compilers/CSharp/Portable/Errors/MessageID.cs +++ b/src/Compilers/CSharp/Portable/Errors/MessageID.cs @@ -148,6 +148,7 @@ internal enum MessageID IDS_FeatureAttributesOnBackingFields = MessageBase + 12731, IDS_FeatureEnumGenericTypeConstraint = MessageBase + 12732, + IDS_FeatureDelegateGenericTypeConstraint = MessageBase + 12733, } // Message IDs may refer to strings that need to be localized. @@ -190,6 +191,7 @@ internal static LanguageVersion RequiredVersion(this MessageID feature) // C# 7.3 features. case MessageID.IDS_FeatureAttributesOnBackingFields: // semantic check case MessageID.IDS_FeatureEnumGenericTypeConstraint: // semantic check + case MessageID.IDS_FeatureDelegateGenericTypeConstraint: // semantic check return LanguageVersion.CSharp7_3; // C# 7.2 features. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf index db4f65137ba32..bf4dc1302ae70 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf @@ -8605,6 +8605,11 @@ Pokud chcete odstranit toto varování, můžete místo toho použít /reference enum generic type constraints + + delegate generic type constraints + delegate generic type constraints + + \ No newline at end of file diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf index 19cbf57eae9c5..e06a6efdcaebd 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf @@ -8605,6 +8605,11 @@ Um die Warnung zu beheben, können Sie stattdessen /reference verwenden (Einbett enum generic type constraints + + delegate generic type constraints + delegate generic type constraints + + \ No newline at end of file diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf index abe58e72503f2..58094e72d25dd 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf @@ -8605,6 +8605,11 @@ Para eliminar la advertencia puede usar /reference (establezca la propiedad Embe enum generic type constraints + + delegate generic type constraints + delegate generic type constraints + + \ No newline at end of file diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf index 37ab3c12b9da8..e21f5f8eb7ee3 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf @@ -8605,6 +8605,11 @@ Pour supprimer l'avertissement, vous pouvez utiliser la commande /reference (dé enum generic type constraints + + delegate generic type constraints + delegate generic type constraints + + \ No newline at end of file diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf index ab77395165871..bce19c9126279 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf @@ -8605,6 +8605,11 @@ Per rimuovere l'avviso, è invece possibile usare /reference (impostare la propr enum generic type constraints + + delegate generic type constraints + delegate generic type constraints + + \ No newline at end of file diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf index 6d93f8c9ddffd..388fd1ecc3a17 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf @@ -8605,6 +8605,11 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ enum generic type constraints + + delegate generic type constraints + delegate generic type constraints + + \ No newline at end of file diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf index e7981d615704d..20e7535f4f4fb 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf @@ -8605,6 +8605,11 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ enum generic type constraints + + delegate generic type constraints + delegate generic type constraints + + \ No newline at end of file diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf index 8b0fc8b02f87f..33b8c8db8760a 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf @@ -8605,6 +8605,11 @@ Aby usunąć ostrzeżenie, możesz zamiast tego użyć opcji /reference (ustaw w enum generic type constraints + + delegate generic type constraints + delegate generic type constraints + + \ No newline at end of file diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf index cbbabefc475e7..d269eb541591c 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf @@ -8605,6 +8605,11 @@ Para incorporar informações de tipo de interoperabilidade para os dois assembl enum generic type constraints + + delegate generic type constraints + delegate generic type constraints + + \ No newline at end of file diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf index 3c2cdb770007b..0a8df165d98db 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf @@ -8605,6 +8605,11 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ enum generic type constraints + + delegate generic type constraints + delegate generic type constraints + + \ No newline at end of file diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf index 43691445961e2..89e2d76fde432 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf @@ -8605,6 +8605,11 @@ Uyarıyı kaldırmak için, /reference kullanabilirsiniz (Birlikte Çalışma T enum generic type constraints + + delegate generic type constraints + delegate generic type constraints + + \ No newline at end of file diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf index 855b945e44d74..4eb59040307b5 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf @@ -8605,6 +8605,11 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ enum generic type constraints + + delegate generic type constraints + delegate generic type constraints + + \ No newline at end of file diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf index 66200630464ae..f13ad18b061d7 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf @@ -8605,6 +8605,11 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ enum generic type constraints + + delegate generic type constraints + delegate generic type constraints + + \ No newline at end of file diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/GenericConstraintsTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/GenericConstraintsTests.cs index 96175927b3156..bd54debe3a1ee 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/GenericConstraintsTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/GenericConstraintsTests.cs @@ -579,5 +579,965 @@ public class Test where T : System.Enum // public class Test 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 obj) where T : System.Enum + { + System.Console.WriteLine(obj.GetTypeCode()); + } +}"; + + CompileAndVerify(code, expectedOutput: @" +Int16 +UInt32"); + } + + [Fact] + public void DelegateConstraint_Compilation_Alone() + { + CreateStandardCompilation(@" +public class Test where T : System.Delegate +{ +} +public delegate void D1(); +public class Test2 +{ + public void M() where U : System.Delegate + { + var a = new Test(); // delegate + var b = new Test(); // value type + var c = new Test(); // reference type + var d = new Test(); // delegate type + } +}").VerifyDiagnostics( + // (11,26): error CS0315: The type 'int' cannot be used as type parameter 'T' in the generic type or method 'Test'. There is no boxing conversion from 'int' to 'System.Delegate'. + // var b = new Test(); // value type + Diagnostic(ErrorCode.ERR_GenericConstraintNotSatisfiedValType, "int").WithArguments("Test", "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'. There is no implicit reference conversion from 'string' to 'System.Delegate'. + // var c = new Test(); // reference type + Diagnostic(ErrorCode.ERR_GenericConstraintNotSatisfiedRefType, "string").WithArguments("Test", "System.Delegate", "T", "string").WithLocation(12, 26)); + } + + [Fact] + public void DelegateConstraint_Compilation_ReferenceType() + { + CreateStandardCompilation(@" +public class Test where T : class, System.Delegate +{ +} +public delegate void D1(); +public class Test2 +{ + public void M() where U : class, System.Delegate + { + var a = new Test(); // delegate + var b = new Test(); // value type + var c = new Test(); // reference type + var d = new Test(); // 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' + // var b = new Test(); // value type + Diagnostic(ErrorCode.ERR_RefConstraintNotSatisfied, "int").WithArguments("Test", "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'. There is no implicit reference conversion from 'string' to 'System.Delegate'. + // var c = new Test(); // reference type + Diagnostic(ErrorCode.ERR_GenericConstraintNotSatisfiedRefType, "string").WithArguments("Test", "System.Delegate", "T", "string").WithLocation(12, 26)); + } + + [Fact] + public void DelegateConstraint_Compilation_ValueType() + { + CreateStandardCompilation(@" +public class Test where T : struct, System.Delegate +{ +}").VerifyDiagnostics( + // (2,19): error CS0455: Type parameter 'T' inherits conflicting constraints 'Delegate' and 'ValueType' + // public class Test where T : struct, System.Delegate + Diagnostic(ErrorCode.ERR_BaseConstraintConflict, "T").WithArguments("T", "System.Delegate", "System.ValueType").WithLocation(2, 19)); + } + + [Fact] + public void DelegateConstraint_Compilation_Constructor() + { + CreateStandardCompilation(@" +public class Test where T : System.Delegate, new() +{ +} +public delegate void D1(); +public class Test2 +{ + public void M() where U : System.Delegate, new() + { + var a = new Test(); // delegate + var b = new Test(); // value type + var c = new Test(); // reference type + var d = new Test(); // 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' + // var a = new Test(); // delegate + Diagnostic(ErrorCode.ERR_NewConstraintNotSatisfied, "D1").WithArguments("Test", "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'. There is no boxing conversion from 'int' to 'System.Delegate'. + // var b = new Test(); // value type + Diagnostic(ErrorCode.ERR_GenericConstraintNotSatisfiedValType, "int").WithArguments("Test", "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'. There is no implicit reference conversion from 'string' to 'System.Delegate'. + // var c = new Test(); // reference type + Diagnostic(ErrorCode.ERR_GenericConstraintNotSatisfiedRefType, "string").WithArguments("Test", "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' + // var c = new Test(); // reference type + Diagnostic(ErrorCode.ERR_NewConstraintNotSatisfied, "string").WithArguments("Test", "T", "string").WithLocation(12, 26)); + } + + [Fact] + public void DelegateConstraint_Reference_Alone() + { + var reference = CreateStandardCompilation(@" +public class Test where T : System.Delegate +{ +}").EmitToImageReference(); + + CreateStandardCompilation(@" +public delegate void D1(); +public class Test2 +{ + public void M() where U : System.Delegate + { + var a = new Test(); // delegate + var b = new Test(); // value type + var c = new Test(); // reference type + var d = new Test(); // 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'. There is no boxing conversion from 'int' to 'System.Delegate'. + // var b = new Test(); // value type + Diagnostic(ErrorCode.ERR_GenericConstraintNotSatisfiedValType, "int").WithArguments("Test", "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'. There is no implicit reference conversion from 'string' to 'System.Delegate'. + // var c = new Test(); // reference type + Diagnostic(ErrorCode.ERR_GenericConstraintNotSatisfiedRefType, "string").WithArguments("Test", "System.Delegate", "T", "string").WithLocation(9, 26)); + } + + [Fact] + public void DelegateConstraint_Reference_ReferenceType() + { + var reference = CreateStandardCompilation(@" +public class Test where T : class, System.Delegate +{ +}").EmitToImageReference(); + + CreateStandardCompilation(@" +public delegate void D1(); +public class Test2 +{ + public void M() where U : class, System.Delegate + { + var a = new Test(); // delegate + var b = new Test(); // value type + var c = new Test(); // reference type + var d = new Test(); // 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' + // var b = new Test(); // value type + Diagnostic(ErrorCode.ERR_RefConstraintNotSatisfied, "int").WithArguments("Test", "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'. There is no implicit reference conversion from 'string' to 'System.Delegate'. + // var c = new Test(); // reference type + Diagnostic(ErrorCode.ERR_GenericConstraintNotSatisfiedRefType, "string").WithArguments("Test", "System.Delegate", "T", "string").WithLocation(9, 26)); + } + + [Fact] + public void DelegateConstraint_Reference_Constructor() + { + var reference = CreateStandardCompilation(@" +public class Test where T : System.Delegate, new() +{ +}").EmitToImageReference(); + + CreateStandardCompilation(@" +public delegate void D1(); +public class Test2 +{ + public void M() where U : System.Delegate, new() + { + var a = new Test(); // delegate + var b = new Test(); // value type + var c = new Test(); // reference type + var d = new Test(); // 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' + // var a = new Test(); // delegate + Diagnostic(ErrorCode.ERR_NewConstraintNotSatisfied, "D1").WithArguments("Test", "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'. There is no boxing conversion from 'int' to 'System.Delegate'. + // var b = new Test(); // value type + Diagnostic(ErrorCode.ERR_GenericConstraintNotSatisfiedValType, "int").WithArguments("Test", "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'. There is no implicit reference conversion from 'string' to 'System.Delegate'. + // var c = new Test(); // reference type + Diagnostic(ErrorCode.ERR_GenericConstraintNotSatisfiedRefType, "string").WithArguments("Test", "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' + // var c = new Test(); // reference type + Diagnostic(ErrorCode.ERR_NewConstraintNotSatisfied, "string").WithArguments("Test", "T", "string").WithLocation(9, 26)); + } + + [Fact] + public void DelegateConstraint_Before_7_3() + { + var code = @" +public class Test where T : System.Delegate +{ +}"; + + CreateStandardCompilation(code, parseOptions: new CSharpParseOptions(LanguageVersion.CSharp7_2)).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 where T : System.Delegate + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7_2, "System.Delegate").WithArguments("delegate generic type constraints", "7.3").WithLocation(2, 32)); + } + + [Fact] + public void DelegateConstraint_InheritanceChain() + { + CreateStandardCompilation(@" +public delegate void D1(); +public class Test where U : System.Delegate, T +{ +} +public class Test2 +{ + public void M() + { + var a = new Test(); + + var b = new Test(); + var c = new Test(); + var d = new Test(); + var e = new Test(); + var f = new Test(); + + var g = new Test(); + var h = new Test(); + } +}").VerifyDiagnostics( + // (10,33): error CS0311: The type 'D1' cannot be used as type parameter 'U' in the generic type or method 'Test'. There is no implicit reference conversion from 'D1' to 'Test2'. + // var a = new Test(); + Diagnostic(ErrorCode.ERR_GenericConstraintNotSatisfiedRefType, "D1").WithArguments("Test", "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'. There is no implicit reference conversion from 'System.Delegate' to 'System.MulticastDelegate'. + // var d = new Test(); + Diagnostic(ErrorCode.ERR_GenericConstraintNotSatisfiedRefType, "System.Delegate").WithArguments("Test", "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'. There is no implicit reference conversion from 'System.Delegate' to 'D1'. + // var g = new Test(); + Diagnostic(ErrorCode.ERR_GenericConstraintNotSatisfiedRefType, "System.Delegate").WithArguments("Test", "D1", "U", "System.Delegate").WithLocation(18, 30)); + } + + [Fact] + public void DelegateConstraint_IsReflectedinSymbols_Alone() + { + var code = "public class Test where T : System.Delegate { }"; + + Action 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 = CreateStandardCompilation("public class Test where T : struct, System.Delegate { }") + .VerifyDiagnostics( + // (1,19): error CS0455: Type parameter 'T' inherits conflicting constraints 'Delegate' and 'ValueType' + // public class Test where T : struct, System.Delegate { } + Diagnostic(ErrorCode.ERR_BaseConstraintConflict, "T").WithArguments("T", "System.Delegate", "System.ValueType").WithLocation(1, 19)); + + var typeParameter = compilation.GlobalNamespace.GetTypeMember("Test").TypeParameters.Single(); + + Assert.True(typeParameter.HasValueTypeConstraint); + Assert.False(typeParameter.HasReferenceTypeConstraint); + Assert.False(typeParameter.HasConstructorConstraint); + Assert.Equal(SpecialType.System_Delegate, typeParameter.ConstraintTypes().Single().SpecialType); + } + + [Fact] + public void DelegateConstraint_IsReflectedinSymbols_ReferenceType() + { + var code = "public class Test where T : class, System.Delegate { }"; + + Action 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 where T : System.Delegate, new() { }"; + + Action 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() + { + CreateStandardCompilation(@" +public abstract class A +{ + public abstract void M() where T : System.Delegate; +} +public delegate void D1(); +public class B : A +{ + public override void M() { } + + public void Test() + { + this.M(); + this.M(); + } +}").VerifyDiagnostics( + // (13,9): error CS0315: The type 'int' cannot be used as type parameter 'T' in the generic type or method 'B.M()'. There is no boxing conversion from 'int' to 'System.Delegate'. + // this.M(); + Diagnostic(ErrorCode.ERR_GenericConstraintNotSatisfiedValType, "this.M").WithArguments("B.M()", "System.Delegate", "T", "int").WithLocation(13, 9)); + } + + [Fact] + public void DelegateConstraint_EnforcedInInheritanceChain_Downwards_Reference() + { + var reference = CreateStandardCompilation(@" +public abstract class A +{ + public abstract void M() where T : System.Delegate; +}").EmitToImageReference(); + + CreateStandardCompilation(@" +public delegate void D1(); +public class B : A +{ + public override void M() { } + + public void Test() + { + this.M(); + this.M(); + } +}", references: new[] { reference }).VerifyDiagnostics( + // (9,9): error CS0315: The type 'int' cannot be used as type parameter 'T' in the generic type or method 'B.M()'. There is no boxing conversion from 'int' to 'System.Delegate'. + // this.M(); + Diagnostic(ErrorCode.ERR_GenericConstraintNotSatisfiedValType, "this.M").WithArguments("B.M()", "System.Delegate", "T", "int").WithLocation(9, 9)); + } + + [Fact] + public void DelegateConstraint_EnforcedInInheritanceChain_Upwards_Source() + { + CreateStandardCompilation(@" +public abstract class A +{ + public abstract void M(); +} +public class B : A +{ + public override void M() where T : System.Delegate { } +}").VerifyDiagnostics( + // (8,33): error CS0460: Constraints for override and explicit interface implementation methods are inherited from the base method, so they cannot be specified directly + // public override void M() where T : System.Delegate { } + Diagnostic(ErrorCode.ERR_OverrideWithConstraints, "where").WithLocation(8, 33)); + } + + [Fact] + public void DelegateConstraint_EnforcedInInheritanceChain_Upwards_Reference() + { + var reference = CreateStandardCompilation(@" +public abstract class A +{ + public abstract void M(); +}").EmitToImageReference(); + + CreateStandardCompilation(@" +public class B : A +{ + public override void M() where T : System.Delegate { } +}", references: new[] { reference }).VerifyDiagnostics( + // (4,33): error CS0460: Constraints for override and explicit interface implementation methods are inherited from the base method, so they cannot be specified directly + // public override void M() where T : System.Delegate { } + Diagnostic(ErrorCode.ERR_OverrideWithConstraints, "where").WithLocation(4, 33)); + } + + [Fact] + public void DelegateConstraint_ResolveParentConstraints() + { + var comp = CreateStandardCompilation(@" +public delegate void D1(); +public abstract class A +{ + public abstract void F() where U : System.Delegate, T; +} +public class B : A +{ + public override void F() { } +}"); + + Action 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() + { + CreateCompilation(@" +namespace System +{ + public class Object {} + public class Void {} +} +public class Test 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 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(Impl); + } + public static void Test(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() + { + CreateStandardCompilation(@" +public class Test where T : System.MulticastDelegate +{ +} +public delegate void D1(); +public class Test2 +{ + public void M() where U : System.MulticastDelegate + { + var a = new Test(); // delegate + var b = new Test(); // value type + var c = new Test(); // reference type + var d = new Test(); // 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'. There is no boxing conversion from 'int' to 'System.MulticastDelegate'. + // var b = new Test(); // value type + Diagnostic(ErrorCode.ERR_GenericConstraintNotSatisfiedValType, "int").WithArguments("Test", "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'. There is no implicit reference conversion from 'string' to 'System.MulticastDelegate'. + // var c = new Test(); // reference type + Diagnostic(ErrorCode.ERR_GenericConstraintNotSatisfiedRefType, "string").WithArguments("Test", "System.MulticastDelegate", "T", "string").WithLocation(12, 26)); + } + + [Fact] + public void MulticastDelegateConstraint_Compilation_ReferenceType() + { + CreateStandardCompilation(@" +public class Test where T : class, System.MulticastDelegate +{ +} +public delegate void D1(); +public class Test2 +{ + public void M() where U : class, System.MulticastDelegate + { + var a = new Test(); // delegate + var b = new Test(); // value type + var c = new Test(); // reference type + var d = new Test(); // 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' + // var b = new Test(); // value type + Diagnostic(ErrorCode.ERR_RefConstraintNotSatisfied, "int").WithArguments("Test", "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'. There is no implicit reference conversion from 'string' to 'System.MulticastDelegate'. + // var c = new Test(); // reference type + Diagnostic(ErrorCode.ERR_GenericConstraintNotSatisfiedRefType, "string").WithArguments("Test", "System.MulticastDelegate", "T", "string").WithLocation(12, 26)); + } + + [Fact] + public void MulticastDelegateConstraint_Compilation_ValueType() + { + CreateStandardCompilation(@" +public class Test where T : struct, System.MulticastDelegate +{ +}").VerifyDiagnostics( + // (2,19): error CS0455: Type parameter 'T' inherits conflicting constraints 'MulticastDelegate' and 'ValueType' + // public class Test where T : struct, System.MulticastDelegate + Diagnostic(ErrorCode.ERR_BaseConstraintConflict, "T").WithArguments("T", "System.MulticastDelegate", "System.ValueType").WithLocation(2, 19)); + } + + [Fact] + public void MulticastDelegateConstraint_Compilation_Constructor() + { + CreateStandardCompilation(@" +public class Test where T : System.MulticastDelegate, new() +{ +} +public delegate void D1(); +public class Test2 +{ + public void M() where U : System.MulticastDelegate, new() + { + var a = new Test(); // delegate + var b = new Test(); // value type + var c = new Test(); // reference type + var d = new Test(); // 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' + // var a = new Test(); // delegate + Diagnostic(ErrorCode.ERR_NewConstraintNotSatisfied, "D1").WithArguments("Test", "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'. There is no boxing conversion from 'int' to 'System.MulticastDelegate'. + // var b = new Test(); // value type + Diagnostic(ErrorCode.ERR_GenericConstraintNotSatisfiedValType, "int").WithArguments("Test", "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'. There is no implicit reference conversion from 'string' to 'System.MulticastDelegate'. + // var c = new Test(); // reference type + Diagnostic(ErrorCode.ERR_GenericConstraintNotSatisfiedRefType, "string").WithArguments("Test", "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' + // var c = new Test(); // reference type + Diagnostic(ErrorCode.ERR_NewConstraintNotSatisfied, "string").WithArguments("Test", "T", "string").WithLocation(12, 26)); + } + + [Fact] + public void MulticastDelegateConstraint_Reference_Alone() + { + var reference = CreateStandardCompilation(@" +public class Test where T : System.MulticastDelegate +{ +}").EmitToImageReference(); + + CreateStandardCompilation(@" +public delegate void D1(); +public class Test2 +{ + public void M() where U : System.MulticastDelegate + { + var a = new Test(); // delegate + var b = new Test(); // value type + var c = new Test(); // reference type + var d = new Test(); // 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'. There is no boxing conversion from 'int' to 'System.MulticastDelegate'. + // var b = new Test(); // value type + Diagnostic(ErrorCode.ERR_GenericConstraintNotSatisfiedValType, "int").WithArguments("Test", "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'. There is no implicit reference conversion from 'string' to 'System.MulticastDelegate'. + // var c = new Test(); // reference type + Diagnostic(ErrorCode.ERR_GenericConstraintNotSatisfiedRefType, "string").WithArguments("Test", "System.MulticastDelegate", "T", "string").WithLocation(9, 26)); + } + + [Fact] + public void MulticastDelegateConstraint_Reference_ReferenceType() + { + var reference = CreateStandardCompilation(@" +public class Test where T : class, System.MulticastDelegate +{ +}").EmitToImageReference(); + + CreateStandardCompilation(@" +public delegate void D1(); +public class Test2 +{ + public void M() where U : class, System.MulticastDelegate + { + var a = new Test(); // delegate + var b = new Test(); // value type + var c = new Test(); // reference type + var d = new Test(); // 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' + // var b = new Test(); // value type + Diagnostic(ErrorCode.ERR_RefConstraintNotSatisfied, "int").WithArguments("Test", "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'. There is no implicit reference conversion from 'string' to 'System.MulticastDelegate'. + // var c = new Test(); // reference type + Diagnostic(ErrorCode.ERR_GenericConstraintNotSatisfiedRefType, "string").WithArguments("Test", "System.MulticastDelegate", "T", "string").WithLocation(9, 26)); + } + + [Fact] + public void MulticastDelegateConstraint_Reference_Constructor() + { + var reference = CreateStandardCompilation(@" +public class Test where T : System.MulticastDelegate, new() +{ +}").EmitToImageReference(); + + CreateStandardCompilation(@" +public delegate void D1(); +public class Test2 +{ + public void M() where U : System.MulticastDelegate, new() + { + var a = new Test(); // delegate + var b = new Test(); // value type + var c = new Test(); // reference type + var d = new Test(); // 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' + // var a = new Test(); // delegate + Diagnostic(ErrorCode.ERR_NewConstraintNotSatisfied, "D1").WithArguments("Test", "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'. There is no boxing conversion from 'int' to 'System.MulticastDelegate'. + // var b = new Test(); // value type + Diagnostic(ErrorCode.ERR_GenericConstraintNotSatisfiedValType, "int").WithArguments("Test", "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'. There is no implicit reference conversion from 'string' to 'System.MulticastDelegate'. + // var c = new Test(); // reference type + Diagnostic(ErrorCode.ERR_GenericConstraintNotSatisfiedRefType, "string").WithArguments("Test", "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' + // var c = new Test(); // reference type + Diagnostic(ErrorCode.ERR_NewConstraintNotSatisfied, "string").WithArguments("Test", "T", "string").WithLocation(9, 26)); + } + + [Fact] + public void MulticastDelegateConstraint_Before_7_3() + { + var code = @" +public class Test where T : System.MulticastDelegate +{ +}"; + + CreateStandardCompilation(code, parseOptions: new CSharpParseOptions(LanguageVersion.CSharp7_2)).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 where T : System.MulticastDelegate + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7_2, "System.MulticastDelegate").WithArguments("delegate generic type constraints", "7.3").WithLocation(2, 32)); + } + + [Fact] + public void MulticastDelegateConstraint_InheritanceChain() + { + CreateStandardCompilation(@" +public delegate void D1(); +public class Test where U : System.MulticastDelegate, T +{ +} +public class Test2 +{ + public void M() + { + var a = new Test(); + + var b = new Test(); + var c = new Test(); + var d = new Test(); + var e = new Test(); + var f = new Test(); + + var g = new Test(); + var h = new Test(); + } +}").VerifyDiagnostics( + // (10,33): error CS0311: The type 'D1' cannot be used as type parameter 'U' in the generic type or method 'Test'. There is no implicit reference conversion from 'D1' to 'Test2'. + // var a = new Test(); + Diagnostic(ErrorCode.ERR_GenericConstraintNotSatisfiedRefType, "D1").WithArguments("Test", "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'. There is no implicit reference conversion from 'System.Delegate' to 'System.MulticastDelegate'. + // var e = new Test(); + Diagnostic(ErrorCode.ERR_GenericConstraintNotSatisfiedRefType, "System.Delegate").WithArguments("Test", "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'. There is no implicit reference conversion from 'System.Delegate' to 'System.MulticastDelegate'. + // var f = new Test(); + Diagnostic(ErrorCode.ERR_GenericConstraintNotSatisfiedRefType, "System.Delegate").WithArguments("Test", "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'. There is no implicit reference conversion from 'System.MulticastDelegate' to 'D1'. + // var g = new Test(); + Diagnostic(ErrorCode.ERR_GenericConstraintNotSatisfiedRefType, "System.MulticastDelegate").WithArguments("Test", "D1", "U", "System.MulticastDelegate").WithLocation(18, 30)); + } + + [Fact] + public void MulticastDelegateConstraint_IsReflectedinSymbols_Alone() + { + var code = "public class Test where T : System.MulticastDelegate { }"; + + Action 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 = CreateStandardCompilation("public class Test where T : struct, System.MulticastDelegate { }") + .VerifyDiagnostics( + // (1,19): error CS0455: Type parameter 'T' inherits conflicting constraints 'MulticastDelegate' and 'ValueType' + // public class Test where T : struct, System.MulticastDelegate { } + Diagnostic(ErrorCode.ERR_BaseConstraintConflict, "T").WithArguments("T", "System.MulticastDelegate", "System.ValueType").WithLocation(1, 19)); + + var typeParameter = compilation.GlobalNamespace.GetTypeMember("Test").TypeParameters.Single(); + + Assert.True(typeParameter.HasValueTypeConstraint); + Assert.False(typeParameter.HasReferenceTypeConstraint); + Assert.False(typeParameter.HasConstructorConstraint); + Assert.Equal(SpecialType.System_MulticastDelegate, typeParameter.ConstraintTypes().Single().SpecialType); + } + + [Fact] + public void MulticastDelegateConstraint_IsReflectedinSymbols_ReferenceType() + { + var code = "public class Test where T : class, System.MulticastDelegate { }"; + + Action 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 where T : System.MulticastDelegate, new() { }"; + + Action 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() + { + CreateStandardCompilation(@" +public abstract class A +{ + public abstract void M() where T : System.MulticastDelegate; +} +public delegate void D1(); +public class B : A +{ + public override void M() { } + + public void Test() + { + this.M(); + this.M(); + } +}").VerifyDiagnostics( + // (13,9): error CS0315: The type 'int' cannot be used as type parameter 'T' in the generic type or method 'B.M()'. There is no boxing conversion from 'int' to 'System.MulticastDelegate'. + // this.M(); + Diagnostic(ErrorCode.ERR_GenericConstraintNotSatisfiedValType, "this.M").WithArguments("B.M()", "System.MulticastDelegate", "T", "int").WithLocation(13, 9)); + } + + [Fact] + public void MulticastDelegateConstraint_EnforcedInInheritanceChain_Downwards_Reference() + { + var reference = CreateStandardCompilation(@" +public abstract class A +{ + public abstract void M() where T : System.MulticastDelegate; +}").EmitToImageReference(); + + CreateStandardCompilation(@" +public delegate void D1(); +public class B : A +{ + public override void M() { } + + public void Test() + { + this.M(); + this.M(); + } +}", references: new[] { reference }).VerifyDiagnostics( + // (9,9): error CS0315: The type 'int' cannot be used as type parameter 'T' in the generic type or method 'B.M()'. There is no boxing conversion from 'int' to 'System.MulticastDelegate'. + // this.M(); + Diagnostic(ErrorCode.ERR_GenericConstraintNotSatisfiedValType, "this.M").WithArguments("B.M()", "System.MulticastDelegate", "T", "int").WithLocation(9, 9)); + } + + [Fact] + public void MulticastDelegateConstraint_EnforcedInInheritanceChain_Upwards_Source() + { + CreateStandardCompilation(@" +public abstract class A +{ + public abstract void M(); +} +public class B : A +{ + public override void M() where T : System.MulticastDelegate { } +}").VerifyDiagnostics( + // (8,33): error CS0460: Constraints for override and explicit interface implementation methods are inherited from the base method, so they cannot be specified directly + // public override void M() where T : System.MulticastDelegate { } + Diagnostic(ErrorCode.ERR_OverrideWithConstraints, "where").WithLocation(8, 33)); + } + + [Fact] + public void MulticastDelegateConstraint_EnforcedInInheritanceChain_Upwards_Reference() + { + var reference = CreateStandardCompilation(@" +public abstract class A +{ + public abstract void M(); +}").EmitToImageReference(); + + CreateStandardCompilation(@" +public class B : A +{ + public override void M() where T : System.MulticastDelegate { } +}", references: new[] { reference }).VerifyDiagnostics( + // (4,33): error CS0460: Constraints for override and explicit interface implementation methods are inherited from the base method, so they cannot be specified directly + // public override void M() where T : System.MulticastDelegate { } + Diagnostic(ErrorCode.ERR_OverrideWithConstraints, "where").WithLocation(4, 33)); + } + + [Fact] + public void MulticastDelegateConstraint_ResolveParentConstraints() + { + var comp = CreateStandardCompilation(@" +public delegate void D1(); +public abstract class A +{ + public abstract void F() where U : System.MulticastDelegate, T; +} +public class B : A +{ + public override void F() { } +}"); + + Action 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() + { + CreateCompilation(@" +namespace System +{ + public class Object {} + public class Void {} +} +public class Test 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 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(Impl); + } + public static void Test(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 where T : System.Delegate { } +class B : A where T : System.MulticastDelegate { }"; + + CreateStandardCompilation(code).VerifyDiagnostics(); + + code = @" +class A where T : System.MulticastDelegate { } +class B : A where T : System.Delegate { }"; + + CreateStandardCompilation(code).VerifyDiagnostics( + // (3,7): error CS0311: The type 'T' cannot be used as type parameter 'T' in the generic type or method 'A'. There is no implicit reference conversion from 'T' to 'System.MulticastDelegate'. + // class B : A where T : System.Delegate { } + Diagnostic(ErrorCode.ERR_GenericConstraintNotSatisfiedRefType, "B").WithArguments("A", "System.MulticastDelegate", "T", "T").WithLocation(3, 7)); + } } } diff --git a/src/Compilers/CSharp/Test/Symbol/SymbolDisplay/SymbolDisplayTests.cs b/src/Compilers/CSharp/Test/Symbol/SymbolDisplay/SymbolDisplayTests.cs index 32b99f410a880..1720aa1680e1e 100644 --- a/src/Compilers/CSharp/Test/Symbol/SymbolDisplay/SymbolDisplayTests.cs +++ b/src/Compilers/CSharp/Test/Symbol/SymbolDisplay/SymbolDisplayTests.cs @@ -6305,6 +6305,30 @@ Structure X SymbolDisplayPartKind.StructName); } + [Fact] + public void EnumConstraint_Type() + { + TestSymbolDescription( + "class X where T : System.Enum { }", + global => global.GetTypeMember("X"), + SymbolDisplayFormat.TestFormat.WithGenericsOptions(SymbolDisplayGenericsOptions.IncludeTypeParameters | SymbolDisplayGenericsOptions.IncludeTypeConstraints), + "X where T : System.Enum", + SymbolDisplayPartKind.ClassName, + SymbolDisplayPartKind.Punctuation, + SymbolDisplayPartKind.TypeParameterName, + SymbolDisplayPartKind.Punctuation, + SymbolDisplayPartKind.Space, + SymbolDisplayPartKind.Keyword, + SymbolDisplayPartKind.Space, + SymbolDisplayPartKind.TypeParameterName, + SymbolDisplayPartKind.Space, + SymbolDisplayPartKind.Punctuation, + SymbolDisplayPartKind.Space, + SymbolDisplayPartKind.NamespaceName, + SymbolDisplayPartKind.Punctuation, + SymbolDisplayPartKind.ClassName); + } + [Fact] public void EnumConstraint() { @@ -6317,5 +6341,79 @@ public void EnumConstraint() SymbolDisplayPartKind.Punctuation, SymbolDisplayPartKind.ClassName); } + + [Fact] + public void DelegateConstraint_Type() + { + TestSymbolDescription( + "class X where T : System.Delegate { }", + global => global.GetTypeMember("X"), + SymbolDisplayFormat.TestFormat.WithGenericsOptions(SymbolDisplayGenericsOptions.IncludeTypeParameters | SymbolDisplayGenericsOptions.IncludeTypeConstraints), + "X where T : System.Delegate", + SymbolDisplayPartKind.ClassName, + SymbolDisplayPartKind.Punctuation, + SymbolDisplayPartKind.TypeParameterName, + SymbolDisplayPartKind.Punctuation, + SymbolDisplayPartKind.Space, + SymbolDisplayPartKind.Keyword, + SymbolDisplayPartKind.Space, + SymbolDisplayPartKind.TypeParameterName, + SymbolDisplayPartKind.Space, + SymbolDisplayPartKind.Punctuation, + SymbolDisplayPartKind.Space, + SymbolDisplayPartKind.NamespaceName, + SymbolDisplayPartKind.Punctuation, + SymbolDisplayPartKind.ClassName); + } + + [Fact] + public void DelegateConstraint() + { + TestSymbolDescription( + "class X where T : System.Delegate { }", + global => global.GetTypeMember("X").TypeParameters.Single().ConstraintTypes().Single(), + SymbolDisplayFormat.TestFormat, + "System.Delegate", + SymbolDisplayPartKind.NamespaceName, + SymbolDisplayPartKind.Punctuation, + SymbolDisplayPartKind.ClassName); + } + + [Fact] + public void MulticastDelegateConstraint_Type() + { + TestSymbolDescription( + "class X where T : System.MulticastDelegate { }", + global => global.GetTypeMember("X"), + SymbolDisplayFormat.TestFormat.WithGenericsOptions(SymbolDisplayGenericsOptions.IncludeTypeParameters | SymbolDisplayGenericsOptions.IncludeTypeConstraints), + "X where T : System.MulticastDelegate", + SymbolDisplayPartKind.ClassName, + SymbolDisplayPartKind.Punctuation, + SymbolDisplayPartKind.TypeParameterName, + SymbolDisplayPartKind.Punctuation, + SymbolDisplayPartKind.Space, + SymbolDisplayPartKind.Keyword, + SymbolDisplayPartKind.Space, + SymbolDisplayPartKind.TypeParameterName, + SymbolDisplayPartKind.Space, + SymbolDisplayPartKind.Punctuation, + SymbolDisplayPartKind.Space, + SymbolDisplayPartKind.NamespaceName, + SymbolDisplayPartKind.Punctuation, + SymbolDisplayPartKind.ClassName); + } + + [Fact] + public void MulticastDelegateConstraint() + { + TestSymbolDescription( + "class X where T : System.MulticastDelegate { }", + global => global.GetTypeMember("X").TypeParameters.Single().ConstraintTypes().Single(), + SymbolDisplayFormat.TestFormat, + "System.MulticastDelegate", + SymbolDisplayPartKind.NamespaceName, + SymbolDisplayPartKind.Punctuation, + SymbolDisplayPartKind.ClassName); + } } } diff --git a/src/Compilers/CSharp/Test/Symbol/Symbols/SymbolErrorTests.cs b/src/Compilers/CSharp/Test/Symbol/Symbols/SymbolErrorTests.cs index 465f41475afe7..e53ac25dc7f66 100644 --- a/src/Compilers/CSharp/Test/Symbol/Symbols/SymbolErrorTests.cs +++ b/src/Compilers/CSharp/Test/Symbol/Symbols/SymbolErrorTests.cs @@ -12282,8 +12282,7 @@ public void CS0702ERR_SpecialTypeAsBound() interface IA where T : object { } interface IB where T : System.Object { } interface IC where T : ValueType { } -interface ID where T : Array { } -interface IE where T : Delegate where U : MulticastDelegate { }"; +interface ID where T : Array { }"; CreateStandardCompilation(source).VerifyDiagnostics( // (2,27): error CS0702: Constraint cannot be special class 'object' Diagnostic(ErrorCode.ERR_SpecialTypeAsBound, "object").WithArguments("object").WithLocation(2, 27), @@ -12292,11 +12291,7 @@ interface IE where T : Delegate where U : MulticastDelegate { }"; // (4,30): error CS0702: Constraint cannot be special class 'System.ValueType' Diagnostic(ErrorCode.ERR_SpecialTypeAsBound, "ValueType").WithArguments("System.ValueType").WithLocation(4, 30), // (5,27): error CS0702: Constraint cannot be special class 'System.Array' - Diagnostic(ErrorCode.ERR_SpecialTypeAsBound, "Array").WithArguments("System.Array").WithLocation(5, 27), - // (6,30): error CS0702: Constraint cannot be special class 'System.Delegate' - Diagnostic(ErrorCode.ERR_SpecialTypeAsBound, "Delegate").WithArguments("System.Delegate").WithLocation(6, 30), - // (6,49): error CS0702: Constraint cannot be special class 'System.MulticastDelegate' - Diagnostic(ErrorCode.ERR_SpecialTypeAsBound, "MulticastDelegate").WithArguments("System.MulticastDelegate").WithLocation(6, 49)); + Diagnostic(ErrorCode.ERR_SpecialTypeAsBound, "Array").WithArguments("System.Array").WithLocation(5, 27)); } [Fact] diff --git a/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/GenericConstraintTests.vb b/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/GenericConstraintTests.vb index 0bf9b2d85374e..9b6ea224b809a 100644 --- a/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/GenericConstraintTests.vb +++ b/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/GenericConstraintTests.vb @@ -5754,6 +5754,74 @@ BC32044: Type argument 'String' does not inherit from or implement the constrain ) End Sub + + Public Sub DelegateConstraint_FromCSharp() + Dim reference = CreateCSharpCompilation(" +public class Test where T : System.Delegate +{ +}", parseOptions:=New CSharp.CSharpParseOptions(CSharp.LanguageVersion.CSharp7_3)).EmitToImageReference() + + Dim compilation = CompilationUtils.CreateCompilationWithMscorlibAndVBRuntime( + + +Delegate Sub D1() + +Public Class Test2 + Public Sub M() + Dim a = new Test(Of D1)() ' delegate + Dim b = new Test(Of Integer)() ' value type + Dim c = new Test(Of string)() ' reference type + Dim d = new Test(Of System.Delegate)() ' Delegate type + End Sub +End Class + +, {reference}) + + AssertTheseDiagnostics(compilation, + +BC32044: Type argument 'Integer' does not inherit from or implement the constraint type '[Delegate]'. + Dim b = new Test(Of Integer)() ' value type + ~~~~~~~ +BC32044: Type argument 'String' does not inherit from or implement the constraint type '[Delegate]'. + Dim c = new Test(Of string)() ' reference type + ~~~~~~ +) + End Sub + + + Public Sub MulticastDelegateConstraint_FromCSharp() + Dim reference = CreateCSharpCompilation(" +public class Test where T : System.MulticastDelegate +{ +}", parseOptions:=New CSharp.CSharpParseOptions(CSharp.LanguageVersion.CSharp7_3)).EmitToImageReference() + + Dim compilation = CompilationUtils.CreateCompilationWithMscorlibAndVBRuntime( + + +Delegate Sub D1() + +Public Class Test2 + Public Sub M() + Dim a = new Test(Of D1)() ' delegate + Dim b = new Test(Of Integer)() ' value type + Dim c = new Test(Of string)() ' reference type + Dim d = new Test(Of System.MulticastDelegate)() ' MulticastDelegate type + End Sub +End Class + +, {reference}) + + AssertTheseDiagnostics(compilation, + +BC32044: Type argument 'Integer' does not inherit from or implement the constraint type 'MulticastDelegate'. + Dim b = new Test(Of Integer)() ' value type + ~~~~~~~ +BC32044: Type argument 'String' does not inherit from or implement the constraint type 'MulticastDelegate'. + Dim c = new Test(Of string)() ' reference type + ~~~~~~ +) + End Sub + End Class End Namespace diff --git a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/SymbolCompletionProviderTests.cs b/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/SymbolCompletionProviderTests.cs index e761651a64900..8c2eb32a5d7e9 100644 --- a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/SymbolCompletionProviderTests.cs +++ b/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/SymbolCompletionProviderTests.cs @@ -9210,5 +9210,23 @@ public async Task EnumConstraint() "; await VerifyItemExistsAsync(markup, "Enum"); } + + [Fact, Trait(Traits.Feature, Traits.Features.KeywordRecommending)] + public async Task DelegateConstraint() + { + var markup = +@"public class X where T : System.$$ +"; + await VerifyItemExistsAsync(markup, "Delegate"); + } + + [Fact, Trait(Traits.Feature, Traits.Features.KeywordRecommending)] + public async Task MulticastDelegateConstraint() + { + var markup = +@"public class X where T : System.$$ +"; + await VerifyItemExistsAsync(markup, "MulticastDelegate"); + } } } diff --git a/src/EditorFeatures/CSharpTest/Diagnostics/UpgradeProject/UpgradeProjectTests.cs b/src/EditorFeatures/CSharpTest/Diagnostics/UpgradeProject/UpgradeProjectTests.cs index 01a8abee2d407..4ad8054682884 100644 --- a/src/EditorFeatures/CSharpTest/Diagnostics/UpgradeProject/UpgradeProjectTests.cs +++ b/src/EditorFeatures/CSharpTest/Diagnostics/UpgradeProject/UpgradeProjectTests.cs @@ -265,6 +265,32 @@ await TestLanguageVersionUpgradedAsync( @"public class X where T : [|System.Enum|] { } +", + LanguageVersion.CSharp7_3, + new CSharpParseOptions(LanguageVersion.CSharp7_2), + index: 1); + } + + [Fact] + public async Task UpgradeProjectFromCSharp7_2ToLatest_DelegateConstraint() + { + await TestLanguageVersionUpgradedAsync( +@"public class X where T : [|System.Delegate|] +{ +} +", + LanguageVersion.CSharp7_3, + new CSharpParseOptions(LanguageVersion.CSharp7_2), + index: 1); + } + + [Fact] + public async Task UpgradeProjectFromCSharp7_2ToLatest_MulticastDelegateConstraint() + { + await TestLanguageVersionUpgradedAsync( +@"public class X where T : [|System.MulticastDelegate|] +{ +} ", LanguageVersion.CSharp7_3, new CSharpParseOptions(LanguageVersion.CSharp7_2), diff --git a/src/EditorFeatures/CSharpTest/QuickInfo/SemanticQuickInfoSourceTests.cs b/src/EditorFeatures/CSharpTest/QuickInfo/SemanticQuickInfoSourceTests.cs index bf91ab874e455..335cbc9b923a8 100644 --- a/src/EditorFeatures/CSharpTest/QuickInfo/SemanticQuickInfoSourceTests.cs +++ b/src/EditorFeatures/CSharpTest/QuickInfo/SemanticQuickInfoSourceTests.cs @@ -5164,5 +5164,29 @@ class X where T : System.Enum }", MainDescription($"T {FeaturesResources.in_} X where T : Enum")); } + + [Fact, Trait(Traits.Feature, Traits.Features.QuickInfo)] + public async Task DelegateConstraint() + { + await TestInMethodAsync( +@" +class X where T : System.Delegate +{ + private $$T x; +}", + MainDescription($"T {FeaturesResources.in_} X where T : Delegate")); + } + + [Fact, Trait(Traits.Feature, Traits.Features.QuickInfo)] + public async Task MulticastDelegateConstraint() + { + await TestInMethodAsync( +@" +class X where T : System.MulticastDelegate +{ + private $$T x; +}", + MainDescription($"T {FeaturesResources.in_} X where T : MulticastDelegate")); + } } }