/
githubmirror
/
roslyn
Обзор
Документация
Войти
/
githubmirror
/
roslyn
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
src/Compilers/CSharp/Test/Symbol/Symbols/ExtendedPartialMethodsTests.cs
3 908 строк
160 KB
Rikki Gibson
Fix some missing attributes on partial async and iterator methods (#83790)
02 июн 2026, 18:47
Не верифицирован
02 июн 2026, 18:47
d6af2a8
Код
Авторство
О чём код?
// 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.Reflection; using System.Runtime.InteropServices; using Microsoft.CodeAnalysis.CSharp.Symbols; using Microsoft.CodeAnalysis.CSharp.Symbols.Metadata.PE; using Microsoft.CodeAnalysis.CSharp.Test.Utilities; using Microsoft.CodeAnalysis.Test.Utilities; using Roslyn.Test.Utilities; using Xunit; namespace Microsoft.CodeAnalysis.CSharp.UnitTests { public class ExtendedPartialMethodsTests : CSharpTestBase { [Fact] public void NonVoidReturnType_LangVersion() { const string text = @" partial class C { internal partial int M1(); internal partial int M1() => 1; }"; var comp = CreateCompilation(text, parseOptions: TestOptions.Regular8); comp.VerifyDiagnostics( // (4,26): error CS8400: Feature 'extended partial methods' is not available in C# 8.0. Please use language version 9.0 or greater. // internal partial int M1(); Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion8, "M1").WithArguments("extended partial methods", "9.0").WithLocation(4, 26), // (5,26): error CS8400: Feature 'extended partial methods' is not available in C# 8.0. Please use language version 9.0 or greater. // internal partial int M1() => 1; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion8, "M1").WithArguments("extended partial methods", "9.0").WithLocation(5, 26) ); comp = CreateCompilation(text, parseOptions: TestOptions.RegularWithExtendedPartialMethods); comp.VerifyDiagnostics(); } [Fact] public void NonVoidReturnType_NoAccessibility() { const string text = @" partial class C { partial int M1(); partial int M1() => 1; }"; var comp = CreateCompilation(text, parseOptions: TestOptions.RegularWithExtendedPartialMethods); comp.VerifyDiagnostics( // (4,17): error CS8794: Partial method 'C.M1()' must have accessibility modifiers because it has a non-void return type. // partial int M1(); Diagnostic(ErrorCode.ERR_PartialMethodWithNonVoidReturnMustHaveAccessMods, "M1").WithArguments("C.M1()").WithLocation(4, 17), // (5,17): error CS8794: Partial method 'C.M1()' must have accessibility modifiers because it has a non-void return type. // partial int M1() => 1; Diagnostic(ErrorCode.ERR_PartialMethodWithNonVoidReturnMustHaveAccessMods, "M1").WithArguments("C.M1()").WithLocation(5, 17) ); } [Fact] public void NonVoidReturnType_NoImpl() { const string text = @" partial class C { private partial int M1(); }"; var comp = CreateCompilation(text, parseOptions: TestOptions.RegularWithExtendedPartialMethods); comp.VerifyDiagnostics( // (4,25): error CS8793: Partial method 'C.M1()' must have an implementation part because it has accessibility modifiers. // private partial int M1(); Diagnostic(ErrorCode.ERR_PartialMethodWithAccessibilityModsMustHaveImplementation, "M1").WithArguments("C.M1()").WithLocation(4, 25) ); } [Fact] public void NonVoidReturnType_NoImpl_NoAccessibility() { const string text = @" partial class C { partial int M1(); }"; var comp = CreateCompilation(text, parseOptions: TestOptions.RegularWithExtendedPartialMethods); comp.VerifyDiagnostics( // (4,17): error CS8794: Partial method 'C.M1()' must have accessibility modifiers because it has a non-void return type. // partial int M1(); Diagnostic(ErrorCode.ERR_PartialMethodWithNonVoidReturnMustHaveAccessMods, "M1").WithArguments("C.M1()").WithLocation(4, 17) ); } [Fact] public void NonVoidReturnType_Semantics() { const string text1 = @" partial class C { private partial int M1(); public static void Main() { System.Console.WriteLine(new C().M1()); } }"; const string text2 = @" partial class C { private partial int M1() { return 42; } } "; var verifier = CompileAndVerify(new[] { text1, text2 }, parseOptions: TestOptions.RegularWithExtendedPartialMethods, expectedOutput: "42"); verifier.VerifyDiagnostics(); } [Fact] public void OutParam_LangVersion() { const string text = @" partial class C { private partial void M1(out int i); private partial void M1(out int i) { i = 0; } }"; var comp = CreateCompilation(text, parseOptions: TestOptions.Regular8); comp.VerifyDiagnostics( // (4,26): error CS8400: Feature 'extended partial methods' is not available in C# 8.0. Please use language version 9.0 or greater. // private partial void M1(out int i); Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion8, "M1").WithArguments("extended partial methods", "9.0").WithLocation(4, 26), // (5,26): error CS8400: Feature 'extended partial methods' is not available in C# 8.0. Please use language version 9.0 or greater. // private partial void M1(out int i) { i = 0; } Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion8, "M1").WithArguments("extended partial methods", "9.0").WithLocation(5, 26) ); comp = CreateCompilation(text, parseOptions: TestOptions.RegularWithExtendedPartialMethods); comp.VerifyDiagnostics(); } [Fact] public void OutParam_NoAccessibility() { const string text = @" partial class C { partial void M1(out int i); partial void M1(out int i) { i = 0; } }"; var comp = CreateCompilation(text, parseOptions: TestOptions.RegularWithExtendedPartialMethods); comp.VerifyDiagnostics( // (4,18): error CS8795: Partial method 'C.M1(out int)' must have accessibility modifiers because it has 'out' parameters. // partial void M1(out int i); Diagnostic(ErrorCode.ERR_PartialMethodWithOutParamMustHaveAccessMods, "M1").WithArguments("C.M1(out int)").WithLocation(4, 18), // (5,18): error CS8795: Partial method 'C.M1(out int)' must have accessibility modifiers because it has 'out' parameters. // partial void M1(out int i) { i = 0; } Diagnostic(ErrorCode.ERR_PartialMethodWithOutParamMustHaveAccessMods, "M1").WithArguments("C.M1(out int)").WithLocation(5, 18) ); } [Fact] public void OutParam_NoImpl() { const string text = @" partial class C { private partial void M1(out int i); }"; var comp = CreateCompilation(text, parseOptions: TestOptions.RegularWithExtendedPartialMethods); comp.VerifyDiagnostics( // (4,26): error CS8793: Partial method 'C.M1(out int)' must have an implementation part because it has accessibility modifiers. // private partial void M1(out int i); Diagnostic(ErrorCode.ERR_PartialMethodWithAccessibilityModsMustHaveImplementation, "M1").WithArguments("C.M1(out int)").WithLocation(4, 26) ); } [Fact] public void OutParam_NoImpl_NoAccessibility() { const string text = @" partial class C { partial void M1(out int i); }"; var comp = CreateCompilation(text, parseOptions: TestOptions.RegularWithExtendedPartialMethods); comp.VerifyDiagnostics( // (4,18): error CS8795: Partial method 'C.M1(out int)' must have accessibility modifiers because it has 'out' parameters. // partial void M1(out int i); Diagnostic(ErrorCode.ERR_PartialMethodWithOutParamMustHaveAccessMods, "M1").WithArguments("C.M1(out int)").WithLocation(4, 18) ); } [Fact] public void OutParam_Semantics() { const string text1 = @" partial class C { private partial void M1(out int value); public static void Main() { new C().M1(out var value); System.Console.WriteLine(value); } }"; const string text2 = @" partial class C { private partial void M1(out int value) { value = 42; } } "; var verifier = CompileAndVerify(new[] { text1, text2 }, parseOptions: TestOptions.RegularWithExtendedPartialMethods, expectedOutput: "42"); verifier.VerifyDiagnostics(); } [Fact] public void OutParam_DefiniteAssignment() { const string text1 = @" partial class C { private partial void M1(out int value); public static void Main() { int i; new C().M1(out i); System.Console.Write(i); } }"; const string text2 = @" partial class C { private partial void M1(out int value) { value = 42; } } "; var verifier = CompileAndVerify(new[] { text1, text2 }, parseOptions: TestOptions.RegularWithExtendedPartialMethods, expectedOutput: "42"); verifier.VerifyDiagnostics(); } public static readonly object[][] s_accessMods = new[] { new[] { "public" }, new[] { "internal" }, new[] { "protected" }, new[] { "private" }, new[] { "protected internal" }, new[] { "private protected" } }; [Theory] [MemberData(nameof(s_accessMods))] public void AccessMod_LangVersion(string mod) { var text = $@" partial class C {{ {mod} partial void M1(); {mod} partial void M1() {{ }} }}"; var comp = CreateCompilation(text, parseOptions: TestOptions.Regular8); comp.VerifyDiagnostics( // (4,27): error CS8400: Feature 'extended partial methods' is not available in C# 8.0. Please use language version 9.0 or greater. // internal partial void M1(); Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion8, "M1").WithArguments("extended partial methods", "9.0"), // (5,27): error CS8400: Feature 'extended partial methods' is not available in C# 8.0. Please use language version 9.0 or greater. // internal partial void M1() { } Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion8, "M1").WithArguments("extended partial methods", "9.0") ); comp = CreateCompilation(text, parseOptions: TestOptions.RegularWithExtendedPartialMethods); comp.VerifyDiagnostics(); } [Fact] public void AccessMod_Mismatch_01() { var text = @" partial class C { public partial void M1(); internal partial void M1() { } }"; var comp = CreateCompilation(text, parseOptions: TestOptions.RegularWithExtendedPartialMethods); comp.VerifyDiagnostics( // (5,28): error CS8797: Both partial method declarations must have equivalent accessibility modifiers. // internal partial void M1() { } Diagnostic(ErrorCode.ERR_PartialMemberAccessibilityDifference, "M1").WithLocation(5, 28) ); } [Fact] public void AccessMod_Mismatch_02() { var text = @" partial class C { private partial void M1(); partial void M1() { } }"; var comp = CreateCompilation(text, parseOptions: TestOptions.RegularWithExtendedPartialMethods); comp.VerifyDiagnostics( // (5,19): error CS8797: Both partial member declarations must have identical accessibility modifiers. // partial void M1() { } Diagnostic(ErrorCode.ERR_PartialMemberAccessibilityDifference, "M1").WithLocation(5, 19) ); } [Fact] public void AccessMod_Mismatch_03() { var text = @" partial class C { partial void M1(); private partial void M1() { } }"; var comp = CreateCompilation(text, parseOptions: TestOptions.RegularWithExtendedPartialMethods); comp.VerifyDiagnostics( // (5,27): error CS8797: Both partial member declarations must have identical accessibility modifiers. // private partial void M1() { } Diagnostic(ErrorCode.ERR_PartialMemberAccessibilityDifference, "M1").WithLocation(5, 27) ); } [Theory] [MemberData(nameof(s_accessMods))] public void AccessMod_NoImpl(string mod) { var text = $@" partial class C {{ {mod} partial void M1(); }}"; var comp = CreateCompilation(text, parseOptions: TestOptions.RegularWithExtendedPartialMethods); comp.VerifyDiagnostics( // (4,27): error CS8795: Partial method C.M1() must have an implementation part because it has accessibility modifiers. // {mod} partial void M1(); Diagnostic(ErrorCode.ERR_PartialMethodWithAccessibilityModsMustHaveImplementation, "M1").WithArguments("C.M1()") ); } [Fact] public void Static_NoImpl() { const string text1 = @" partial class C { static partial void M1(); }"; var comp = CreateCompilation(text1, parseOptions: TestOptions.RegularWithExtendedPartialMethods); comp.VerifyDiagnostics(); } [Fact] public void Simple_NoImpl() { const string text1 = @" partial class C { partial void M1(); }"; var comp = CreateCompilation(text1, parseOptions: TestOptions.RegularWithExtendedPartialMethods); comp.VerifyDiagnostics(); } [Fact] public void Virtual_LangVersion() { const string text1 = @" partial class C { internal virtual partial int M1(); internal virtual partial int M1() => 1; }"; var comp = CreateCompilation(text1, parseOptions: TestOptions.Regular8); comp.VerifyDiagnostics( // (4,34): error CS8400: Feature 'extended partial methods' is not available in C# 8.0. Please use language version 9.0 or greater. // internal virtual partial int M1(); Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion8, "M1").WithArguments("extended partial methods", "9.0").WithLocation(4, 34), // (5,34): error CS8400: Feature 'extended partial methods' is not available in C# 8.0. Please use language version 9.0 or greater. // internal virtual partial int M1() => 1; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion8, "M1").WithArguments("extended partial methods", "9.0").WithLocation(5, 34) ); comp = CreateCompilation(text1, parseOptions: TestOptions.RegularWithExtendedPartialMethods); comp.VerifyDiagnostics(); } [Fact] public void Virtual_NoAccessibility() { const string text1 = @" partial class C { virtual partial void M1(); virtual partial void M1() { } }"; var comp = CreateCompilation(text1, parseOptions: TestOptions.RegularWithExtendedPartialMethods); comp.VerifyDiagnostics( // (4,26): error CS8796: Partial method 'C.M1()' must have accessibility modifiers because it has a 'virtual', 'override', 'sealed', 'new', or 'extern' modifier. // virtual partial void M1(); Diagnostic(ErrorCode.ERR_PartialMethodWithExtendedModMustHaveAccessMods, "M1").WithArguments("C.M1()").WithLocation(4, 26), // (5,26): error CS8796: Partial method 'C.M1()' must have accessibility modifiers because it has a 'virtual', 'override', 'sealed', 'new', or 'extern' modifier. // virtual partial void M1() { } Diagnostic(ErrorCode.ERR_PartialMethodWithExtendedModMustHaveAccessMods, "M1").WithArguments("C.M1()").WithLocation(5, 26) ); } [Fact] public void Virtual_NoImpl() { const string text1 = @" partial class C { internal virtual partial void M1(); }"; var comp = CreateCompilation(text1, parseOptions: TestOptions.RegularWithExtendedPartialMethods); comp.VerifyDiagnostics( // (4,35): error CS8793: Partial method 'C.M1()' must have an implementation part because it has accessibility modifiers. // internal virtual partial void M1(); Diagnostic(ErrorCode.ERR_PartialMethodWithAccessibilityModsMustHaveImplementation, "M1").WithArguments("C.M1()").WithLocation(4, 35) ); } [Fact] public void Virtual_Mismatch_01() { const string text1 = @" partial class C { internal virtual partial void M1(); internal partial void M1() { } }"; var comp = CreateCompilation(text1, parseOptions: TestOptions.RegularWithExtendedPartialMethods); comp.VerifyDiagnostics( // (5,27): error CS8798: Both partial method declarations must have equal combinations of 'virtual', 'override', 'sealed', or 'new' modifiers. // internal partial void M1() { } Diagnostic(ErrorCode.ERR_PartialMemberExtendedModDifference, "M1").WithLocation(5, 27) ); } [Fact] public void Virtual_Mismatch_02() { const string text1 = @" partial class C { internal partial void M1(); internal virtual partial void M1() { } }"; var comp = CreateCompilation(text1, parseOptions: TestOptions.RegularWithExtendedPartialMethods); comp.VerifyDiagnostics( // (5,35): error CS8798: Both partial method declarations must have equal combinations of 'virtual', 'override', 'sealed', or 'new' modifiers. // internal virtual partial void M1() { } Diagnostic(ErrorCode.ERR_PartialMemberExtendedModDifference, "M1").WithLocation(5, 35) ); } [Fact] public void Virtual_Semantics() { const string text1 = @" using System; public partial class C { internal virtual partial int M1(); internal virtual partial int M1() => 1; } public class D : C { internal override int M1() => 2; static void UseC(C c) { Console.Write(c.M1()); } public static void Main() { UseC(new C()); UseC(new D()); } }"; CompileAndVerify(text1, parseOptions: TestOptions.RegularWithExtendedPartialMethods, expectedOutput: "12").VerifyDiagnostics(); } [Fact] public void Virtual_AllowNull_01() { const string text1 = @" #nullable enable using System.Diagnostics.CodeAnalysis; partial class C { internal virtual partial void M1([AllowNull] string s1); internal virtual partial void M1(string s1) { } } class D : C { internal override void M1(string s1) // 1 { } }"; var comp = CreateCompilation(new[] { text1, AllowNullAttributeDefinition }, parseOptions: TestOptions.RegularWithExtendedPartialMethods); comp.VerifyDiagnostics( // (12,28): warning CS8765: Nullability of type of parameter 's1' doesn't match overridden member (possibly because of nullability attributes). // internal override void M1(string s1) // 1 Diagnostic(ErrorCode.WRN_TopLevelNullabilityMismatchInParameterTypeOnOverride, "M1").WithArguments("s1").WithLocation(12, 28) ); } [Fact] public void Virtual_AllowNull_02() { const string text1 = @" #nullable enable using System.Diagnostics.CodeAnalysis; partial class C { internal virtual partial void M1(string s1); internal virtual partial void M1([AllowNull] string s1) { } } class D : C { internal override void M1(string s1) // 1 { } }"; var comp = CreateCompilation(new[] { text1, AllowNullAttributeDefinition }, parseOptions: TestOptions.RegularWithExtendedPartialMethods); comp.VerifyDiagnostics( // (12,28): warning CS8765: Nullability of type of parameter 's1' doesn't match overridden member (possibly because of nullability attributes). // internal override void M1(string s1) // 1 Diagnostic(ErrorCode.WRN_TopLevelNullabilityMismatchInParameterTypeOnOverride, "M1").WithArguments("s1").WithLocation(12, 28) ); } [Fact] public void Virtual_AllowNull_03() { const string text1 = @" #nullable enable using System.Diagnostics.CodeAnalysis; partial class C { internal virtual partial void M1(string s1); internal virtual partial void M1([AllowNull] string s1) { } } class D : C { internal override void M1([AllowNull] string s1) { } }"; var comp = CreateCompilation(new[] { text1, AllowNullAttributeDefinition }, parseOptions: TestOptions.RegularWithExtendedPartialMethods); comp.VerifyDiagnostics(); } [Fact] public void Virtual_AllowNull_04() { const string text1 = @" #nullable enable using System.Diagnostics.CodeAnalysis; partial class C { internal virtual partial void M1([AllowNull] string s1); internal virtual partial void M1(string s1) { } } class D : C { internal override void M1([AllowNull] string s1) { } }"; var comp = CreateCompilation(new[] { text1, AllowNullAttributeDefinition }, parseOptions: TestOptions.RegularWithExtendedPartialMethods); comp.VerifyDiagnostics(); } [Fact] public void Virtual_AllowNull_05() { const string text1 = @" #nullable enable using System.Diagnostics.CodeAnalysis; partial class C { internal virtual partial void M1([AllowNull] string s1, string s2); internal virtual partial void M1(string s1, [AllowNull] string s2) { } } class D : C { internal override void M1([AllowNull] string s1, [AllowNull] string s2) { } }"; var comp = CreateCompilation(new[] { text1, AllowNullAttributeDefinition }, parseOptions: TestOptions.RegularWithExtendedPartialMethods); comp.VerifyDiagnostics(); } [Fact] public void Virtual_AllowNull_06() { const string text1 = @" #nullable enable using System.Diagnostics.CodeAnalysis; partial class C { internal virtual partial void M1([AllowNull] string s1, string s2); internal virtual partial void M1(string s1, [AllowNull] string s2) { } } partial class D : C { internal override partial void M1(string s1, [AllowNull] string s2); internal override partial void M1([AllowNull] string s1, string s2) { } }"; var comp = CreateCompilation(new[] { text1, AllowNullAttributeDefinition }, parseOptions: TestOptions.RegularWithExtendedPartialMethods); comp.VerifyDiagnostics(); } [Fact] public void Override_LangVersion() { const string text1 = @" partial class D { public override partial string ToString(); public override partial string ToString() => ""hello""; }"; var comp = CreateCompilation(text1, parseOptions: TestOptions.Regular8); comp.VerifyDiagnostics( // (4,36): error CS8400: Feature 'extended partial methods' is not available in C# 8.0. Please use language version 9.0 or greater. // public override partial string ToString(); Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion8, "ToString").WithArguments("extended partial methods", "9.0").WithLocation(4, 36), // (5,36): error CS8400: Feature 'extended partial methods' is not available in C# 8.0. Please use language version 9.0 or greater. // public override partial string ToString() => "hello"; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion8, "ToString").WithArguments("extended partial methods", "9.0").WithLocation(5, 36) ); var method = comp.GetMember<MethodSymbol>("D.ToString"); Assert.Equal("System.String System.Object.ToString()", method.OverriddenMethod.ToTestDisplayString()); comp = CreateCompilation(text1, parseOptions: TestOptions.RegularWithExtendedPartialMethods); comp.VerifyDiagnostics(); method = comp.GetMember<MethodSymbol>("D.ToString"); Assert.Equal("System.String System.Object.ToString()", method.OverriddenMethod.ToTestDisplayString()); } [Fact] public void Override_WrongAccessibility() { const string text1 = @" partial class D { internal override partial string ToString(); internal override partial string ToString() => ""hello""; }"; var comp = CreateCompilation(text1, parseOptions: TestOptions.RegularWithExtendedPartialMethods); comp.VerifyDiagnostics( // (4,38): error CS0507: 'D.ToString()': cannot change access modifiers when overriding 'public' inherited member 'object.ToString()' // internal override partial string ToString(); Diagnostic(ErrorCode.ERR_CantChangeAccessOnOverride, "ToString").WithArguments("D.ToString()", "public", "object.ToString()").WithLocation(4, 38)); var method = comp.GetMember<MethodSymbol>("D.ToString"); Assert.Equal("System.String System.Object.ToString()", method.OverriddenMethod.ToTestDisplayString()); } [Fact] public void Override_AbstractBase() { const string text1 = @" abstract class C { internal abstract void M1(); } partial class D : C { internal override partial void M1(); internal override partial void M1() { } }"; var comp = CreateCompilation(text1, parseOptions: TestOptions.RegularWithExtendedPartialMethods); comp.VerifyDiagnostics(); var method = comp.GetMember<MethodSymbol>("D.M1"); Assert.Equal(comp.GetMember<MethodSymbol>("C.M1"), method.OverriddenMethod); } [Fact] public void Override_NoAccessibility() { const string text1 = @" class C { internal virtual void M1() { } } partial class D : C { override partial void M1(); override partial void M1() { } }"; var comp = CreateCompilation(text1, parseOptions: TestOptions.RegularWithExtendedPartialMethods); comp.VerifyDiagnostics( // (9,27): error CS8796: Partial method 'D.M1()' must have accessibility modifiers because it has a 'virtual', 'override', 'sealed', 'new', or 'extern' modifier. // override partial void M1(); Diagnostic(ErrorCode.ERR_PartialMethodWithExtendedModMustHaveAccessMods, "M1").WithArguments("D.M1()").WithLocation(9, 27), // (9,27): error CS0507: 'D.M1()': cannot change access modifiers when overriding 'internal' inherited member 'C.M1()' // override partial void M1(); Diagnostic(ErrorCode.ERR_CantChangeAccessOnOverride, "M1").WithArguments("D.M1()", "internal", "C.M1()").WithLocation(9, 27), // (10,27): error CS8796: Partial method 'D.M1()' must have accessibility modifiers because it has a 'virtual', 'override', 'sealed', 'new', or 'extern' modifier. // override partial void M1() { } Diagnostic(ErrorCode.ERR_PartialMethodWithExtendedModMustHaveAccessMods, "M1").WithArguments("D.M1()").WithLocation(10, 27) ); var method = comp.GetMember<MethodSymbol>("D.M1"); Assert.Equal(comp.GetMember<MethodSymbol>("C.M1"), method.OverriddenMethod); } [Fact] public void Override_NoImpl() { const string text1 = @" class C { internal virtual void M1() { } } partial class D : C { internal override partial void M1(); }"; var comp = CreateCompilation(text1, parseOptions: TestOptions.RegularWithExtendedPartialMethods); comp.VerifyDiagnostics( // (9,36): error CS8793: Partial method 'D.M1()' must have an implementation part because it has accessibility modifiers. // internal override partial void M1(); Diagnostic(ErrorCode.ERR_PartialMethodWithAccessibilityModsMustHaveImplementation, "M1").WithArguments("D.M1()").WithLocation(9, 36) ); var method = comp.GetMember<MethodSymbol>("D.M1"); Assert.Equal(comp.GetMember<MethodSymbol>("C.M1"), method.OverriddenMethod); } [Fact] public void Override_NoImpl_NoAccessibility() { const string text1 = @" class C { internal virtual void M1() { } } partial class D : C { override partial void M1(); }"; var comp = CreateCompilation(text1, parseOptions: TestOptions.RegularWithExtendedPartialMethods); comp.VerifyDiagnostics( // (9,27): error CS8796: Partial method 'D.M1()' must have accessibility modifiers because it has a 'virtual', 'override', 'sealed', 'new', or 'extern' modifier. // override partial void M1(); Diagnostic(ErrorCode.ERR_PartialMethodWithExtendedModMustHaveAccessMods, "M1").WithArguments("D.M1()").WithLocation(9, 27), // (9,27): error CS0507: 'D.M1()': cannot change access modifiers when overriding 'internal' inherited member 'C.M1()' // override partial void M1(); Diagnostic(ErrorCode.ERR_CantChangeAccessOnOverride, "M1").WithArguments("D.M1()", "internal", "C.M1()").WithLocation(9, 27) ); var method = comp.GetMember<MethodSymbol>("D.M1"); Assert.Equal(comp.GetMember<MethodSymbol>("C.M1"), method.OverriddenMethod); } [Fact] public void Override_Mismatch_01() { const string text1 = @" class C { internal virtual void M1() { } } partial class D : C { internal override partial void M1(); internal partial void M1() { } }"; var comp = CreateCompilation(text1, parseOptions: TestOptions.RegularWithExtendedPartialMethods); comp.VerifyDiagnostics( // (9,27): error CS8798: Both partial method declarations must have equal combinations of 'virtual', 'override', 'sealed', or 'new' modifiers. // internal partial void M1() { } Diagnostic(ErrorCode.ERR_PartialMemberExtendedModDifference, "M1").WithLocation(9, 27) ); } [Fact] public void Override_Mismatch_02() { const string text1 = @" class C { internal virtual void M1() { } } partial class D : C { internal partial void M1(); internal override partial void M1() { } }"; var comp = CreateCompilation(text1, parseOptions: TestOptions.RegularWithExtendedPartialMethods); comp.VerifyDiagnostics( // (8,27): warning CS0114: 'D.M1()' hides inherited member 'C.M1()'. To make the current member override that implementation, add the override keyword. Otherwise add the new keyword. // internal partial void M1(); Diagnostic(ErrorCode.WRN_NewOrOverrideExpected, "M1").WithArguments("D.M1()", "C.M1()").WithLocation(8, 27), // (9,36): error CS8798: Both partial method declarations must have equal combinations of 'virtual', 'override', 'sealed', or 'new' modifiers. // internal override partial void M1() { } Diagnostic(ErrorCode.ERR_PartialMemberExtendedModDifference, "M1").WithLocation(9, 36) ); } [Fact] public void Override_AllowNull_01() { const string text1 = @" #nullable enable using System.Diagnostics.CodeAnalysis; class C { internal virtual void M1([AllowNull] string s) { } } partial class D : C { internal override partial void M1(string s1); // 1 internal override partial void M1(string s1) { } }"; var comp = CreateCompilation(new[] { text1, AllowNullAttributeDefinition }, parseOptions: TestOptions.RegularWithExtendedPartialMethods); comp.VerifyDiagnostics( // (11,36): warning CS8765: Nullability of type of parameter 's1' doesn't match overridden member (possibly because of nullability attributes). // internal override partial void M1(string s1); // 1 Diagnostic(ErrorCode.WRN_TopLevelNullabilityMismatchInParameterTypeOnOverride, "M1").WithArguments("s1").WithLocation(11, 36) ); } [Fact] public void Override_AllowNull_02() { const string text1 = @" #nullable enable using System.Diagnostics.CodeAnalysis; class C { internal virtual void M1([AllowNull] string s1, [AllowNull] string s2) { } } partial class D : C { internal override partial void M1([AllowNull] string s1, string s2); internal override partial void M1(string s1, [AllowNull] string s2) { s1.ToString(); // 1 s2.ToString(); // 2 } }"; var comp = CreateCompilation(new[] { text1, AllowNullAttributeDefinition }, parseOptions: TestOptions.RegularWithExtendedPartialMethods); comp.VerifyDiagnostics( // (14,9): warning CS8602: Dereference of a possibly null reference. // s1.ToString(); // 1 Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "s1").WithLocation(14, 9), // (15,9): warning CS8602: Dereference of a possibly null reference. // s2.ToString(); // 2 Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "s2").WithLocation(15, 9)); } [Fact] public void Override_GenericBase() { const string text1 = @" #nullable enable class C<T> { internal virtual void M1(T t1) { } } partial class D : C<string> { internal override partial void M1(string t1); internal override partial void M1(string t1) { } }"; var comp = CreateCompilation(text1, parseOptions: TestOptions.RegularWithExtendedPartialMethods); comp.VerifyDiagnostics(); } [Fact] public void Sealed_LangVersion() { const string text1 = @" class C { internal virtual void M1() { } } partial class D : C { internal sealed override partial void M1(); internal sealed override partial void M1() { } }"; var comp = CreateCompilation(text1, parseOptions: TestOptions.Regular8); comp.VerifyDiagnostics( // (8,43): error CS8400: Feature 'extended partial methods' is not available in C# 8.0. Please use language version 9.0 or greater. // internal sealed override partial void M1(); Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion8, "M1").WithArguments("extended partial methods", "9.0").WithLocation(8, 43), // (9,43): error CS8400: Feature 'extended partial methods' is not available in C# 8.0. Please use language version 9.0 or greater. // internal sealed override partial void M1() { } Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion8, "M1").WithArguments("extended partial methods", "9.0").WithLocation(9, 43) ); comp = CreateCompilation(text1, parseOptions: TestOptions.RegularWithExtendedPartialMethods); comp.VerifyDiagnostics(); } [Fact] public void Sealed_NoAccessibility() { const string text1 = @" class C { internal virtual void M1() { } } partial class D : C { sealed override partial void M1(); sealed override partial void M1() { } }"; var comp = CreateCompilation(text1, parseOptions: TestOptions.RegularWithExtendedPartialMethods); comp.VerifyDiagnostics( // (8,34): error CS8796: Partial method 'D.M1()' must have accessibility modifiers because it has a 'virtual', 'override', 'sealed', 'new', or 'extern' modifier. // sealed override partial void M1(); Diagnostic(ErrorCode.ERR_PartialMethodWithExtendedModMustHaveAccessMods, "M1").WithArguments("D.M1()").WithLocation(8, 34), // (8,34): error CS0507: 'D.M1()': cannot change access modifiers when overriding 'internal' inherited member 'C.M1()' // sealed override partial void M1(); Diagnostic(ErrorCode.ERR_CantChangeAccessOnOverride, "M1").WithArguments("D.M1()", "internal", "C.M1()").WithLocation(8, 34), // (9,34): error CS8796: Partial method 'D.M1()' must have accessibility modifiers because it has a 'virtual', 'override', 'sealed', 'new', or 'extern' modifier. // sealed override partial void M1() { } Diagnostic(ErrorCode.ERR_PartialMethodWithExtendedModMustHaveAccessMods, "M1").WithArguments("D.M1()").WithLocation(9, 34) ); } [Fact] public void Sealed_Mismatch_01() { const string text1 = @" class C { internal virtual void M1() { } } partial class D : C { internal sealed override partial void M1(); internal override partial void M1() { } }"; var comp = CreateCompilation(text1, parseOptions: TestOptions.RegularWithExtendedPartialMethods); comp.VerifyDiagnostics( // (9,36): error CS8798: Both partial method declarations must have equal combinations of 'virtual', 'override', 'sealed', or 'new' modifiers. // internal override partial void M1() { } Diagnostic(ErrorCode.ERR_PartialMemberExtendedModDifference, "M1").WithLocation(9, 36) ); } [Fact] public void Sealed_Mismatch_02() { const string text1 = @" class C { internal virtual void M1() { } } partial class D : C { internal override partial void M1(); internal sealed override partial void M1() { } }"; var comp = CreateCompilation(text1, parseOptions: TestOptions.RegularWithExtendedPartialMethods); comp.VerifyDiagnostics( // (9,43): error CS8798: Both partial method declarations must have equal combinations of 'virtual', 'override', 'sealed', or 'new' modifiers. // internal sealed override partial void M1() { } Diagnostic(ErrorCode.ERR_PartialMemberExtendedModDifference, "M1").WithLocation(9, 43) ); } [Fact] public void SealedOverride_Reordered() { const string text1 = @" class C { internal virtual void M1() { } } partial class D : C { internal override sealed partial void M1(); internal sealed override partial void M1() { } }"; var comp = CreateCompilation(text1, parseOptions: TestOptions.RegularWithExtendedPartialMethods); comp.VerifyDiagnostics(); } [Fact] public void NewVirtual_Reordered() { const string text1 = @" class C { internal virtual void M1() { } } partial class D : C { internal new virtual partial void M1(); internal virtual new partial void M1() { } }"; var comp = CreateCompilation(text1, parseOptions: TestOptions.RegularWithExtendedPartialMethods); comp.VerifyDiagnostics(); } [Fact] public void Extern_LangVersion() { const string text1 = @" using System.Runtime.InteropServices; partial class C { internal static partial void M1(); [DllImport(""something.dll"")] internal static extern partial void M1(); }"; var comp = CreateCompilation(text1, parseOptions: TestOptions.Regular8); comp.VerifyDiagnostics( // (6,34): error CS8400: Feature 'extended partial methods' is not available in C# 8.0. Please use language version 9.0 or greater. // internal static partial void M1(); Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion8, "M1").WithArguments("extended partial methods", "9.0").WithLocation(6, 34), // (9,41): error CS8400: Feature 'extended partial methods' is not available in C# 8.0. Please use language version 9.0 or greater. // internal static extern partial void M1(); Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion8, "M1").WithArguments("extended partial methods", "9.0").WithLocation(9, 41)); comp = CreateCompilation(text1, parseOptions: TestOptions.RegularWithExtendedPartialMethods); comp.VerifyDiagnostics(); } [Fact] public void Extern_DuplicateMod() { const string text1 = @" using System.Runtime.InteropServices; partial class C { internal static extern partial void M1(); [DllImport(""something.dll"")] internal static extern partial void M1(); }"; var comp = CreateCompilation(text1, parseOptions: TestOptions.RegularWithExtendedPartialMethods); comp.VerifyDiagnostics( // (6,41): error CS0759: No defining declaration found for implementing declaration of partial method 'C.M1()' // internal static extern partial void M1(); Diagnostic(ErrorCode.ERR_PartialMethodMustHaveLatent, "M1").WithArguments("C.M1()").WithLocation(6, 41), // (9,41): error CS0757: A partial method may not have multiple implementing declarations // internal static extern partial void M1(); Diagnostic(ErrorCode.ERR_PartialMethodOnlyOneActual, "M1").WithLocation(9, 41), // (9,41): error CS0111: Type 'C' already defines a member called 'M1' with the same parameter types // internal static extern partial void M1(); Diagnostic(ErrorCode.ERR_MemberAlreadyExists, "M1").WithArguments("M1", "C").WithLocation(9, 41)); } [Fact] public void Extern_NoAccessibility() { const string text1 = @" using System.Runtime.InteropServices; partial class C { static partial void M1(); [DllImport(""something.dll"")] static extern partial void M1(); }"; var comp = CreateCompilation(text1, parseOptions: TestOptions.RegularWithExtendedPartialMethods); comp.VerifyDiagnostics( // (9,32): error CS8796: Partial method 'C.M1()' must have accessibility modifiers because it has a 'virtual', 'override', 'sealed', 'new', or 'extern' modifier. // static extern partial void M1(); Diagnostic(ErrorCode.ERR_PartialMethodWithExtendedModMustHaveAccessMods, "M1").WithArguments("C.M1()").WithLocation(9, 32) ); } [Fact] public void Extern_Symbols() { const string text1 = @" using System.Runtime.InteropServices; public partial class C { public static partial void M1(); [DllImport(""something.dll"")] public static extern partial void M1(); public static void M2() { M1(); } }"; const string text2 = @" using System.Runtime.InteropServices; public partial class C { [DllImport(""something.dll"")] public static partial void M1(); public static extern partial void M1(); public static void M2() { M1(); } }"; const string expectedIL = @" { // Code size 6 (0x6) .maxstack 0 IL_0000: call ""void C.M1()"" IL_0005: ret }"; var verifier = CompileAndVerify( text1, parseOptions: TestOptions.RegularWithExtendedPartialMethods, sourceSymbolValidator: validator, symbolValidator: validator); verifier.VerifyDiagnostics(); verifier.VerifyIL("C.M2", expectedIL); verifier = CompileAndVerify( text2, parseOptions: TestOptions.RegularWithExtendedPartialMethods, sourceSymbolValidator: validator, symbolValidator: validator); verifier.VerifyDiagnostics(); verifier.VerifyIL("C.M2", expectedIL); static void validator(ModuleSymbol module) { var type = module.ContainingAssembly.GetTypeByMetadataName("C"); var method = type.GetMember<MethodSymbol>("M1"); Assert.True(method.IsExtern); if (method.PartialImplementationPart is MethodSymbol implementation) { Assert.True(method.IsPartialDefinition()); Assert.True(implementation.IsExtern); } var importData = method.GetDllImportData(); Assert.NotNull(importData); Assert.Equal("something.dll", importData.ModuleName); Assert.Equal("M1", importData.EntryPointName); Assert.Equal(CharSet.None, importData.CharacterSet); Assert.False(importData.SetLastError); Assert.False(importData.ExactSpelling); Assert.Equal(MethodImplAttributes.PreserveSig, method.ImplementationAttributes); Assert.Equal(CallingConvention.Winapi, importData.CallingConvention); Assert.Null(importData.BestFitMapping); Assert.Null(importData.ThrowOnUnmappableCharacter); } } [Fact] public void Extern_Symbols_NoDllImport() { const string text1 = @" public partial class C { public static partial void M1(); public static extern partial void M1(); public static void M2() { M1(); } }"; const string text2 = @" public partial class C { public static partial void M1(); public static extern partial void M1(); public static void M2() { M1(); } }"; const string expectedIL = @" { // Code size 6 (0x6) .maxstack 0 IL_0000: call ""void C.M1()"" IL_0005: ret }"; var verifier = CompileAndVerify( text1, parseOptions: TestOptions.RegularWithExtendedPartialMethods, sourceSymbolValidator: module => validator(module, isSource: true), symbolValidator: module => validator(module, isSource: false), // PEVerify fails when extern methods lack an implementation verify: Verification.Skipped); verifier.VerifyDiagnostics(); verifier.VerifyIL("C.M2", expectedIL); verifier = CompileAndVerify( text2, parseOptions: TestOptions.RegularWithExtendedPartialMethods, sourceSymbolValidator: module => validator(module, isSource: true), symbolValidator: module => validator(module, isSource: false), // PEVerify fails when extern methods lack an implementation verify: Verification.Skipped); verifier.VerifyDiagnostics(); verifier.VerifyIL("C.M2", expectedIL); static void validator(ModuleSymbol module, bool isSource) { var type = module.ContainingAssembly.GetTypeByMetadataName("C"); var method = type.GetMember<MethodSymbol>("M1"); // 'IsExtern' is not round tripped when DllImport is missing Assert.Equal(isSource, method.IsExtern); if (method.PartialImplementationPart is MethodSymbol implementation) { Assert.True(method.IsPartialDefinition()); Assert.Equal(isSource, implementation.IsExtern); } var importData = method.GetDllImportData(); Assert.Null(importData); } } [Fact] public void Async_01() { const string text = @" partial class C { partial void M1(); async partial void M1() { } } "; var comp = CreateCompilation(text); comp.VerifyDiagnostics(); var method = (MethodSymbol)comp.GetMembers("C.M1")[0]; Assert.True(method.IsPartialDefinition()); Assert.True(method.IsAsync); Assert.True(method.PartialImplementationPart.IsAsync); } [Fact] public void Async_02() { const string text = @" using System.Threading.Tasks; partial class C { private partial Task M1(); private async partial Task M1() { } } "; var comp = CreateCompilation(text, parseOptions: TestOptions.RegularWithExtendedPartialMethods); comp.VerifyDiagnostics(); var method = (MethodSymbol)comp.GetMembers("C.M1")[0]; Assert.True(method.IsPartialDefinition()); Assert.True(method.IsAsync); Assert.True(method.PartialImplementationPart.IsAsync); } [Fact] public void Async_03() { const string text = @" using System.Threading.Tasks; using System; partial class C { private static async Task CompletedTask() { } private static partial Task<int> M1(); private static async partial Task<int> M1() { await CompletedTask(); return 1; } public static async Task Main() { Console.Write(await M1()); } } "; var verifier = CompileAndVerify(text, parseOptions: TestOptions.RegularWithExtendedPartialMethods, expectedOutput: "1"); verifier.VerifyDiagnostics(); var method = (MethodSymbol)verifier.Compilation.GetMembers("C.M1")[0]; Assert.True(method.IsPartialDefinition()); Assert.True(method.IsAsync); Assert.True(method.PartialImplementationPart.IsAsync); } [Fact] public void Async_04() { const string text = @" using System.Threading.Tasks; partial class C { internal async partial Task M(); } "; var comp = CreateCompilation(text, parseOptions: TestOptions.RegularWithExtendedPartialMethods); comp.VerifyDiagnostics( // (6,33): error CS8793: Partial method 'C.M()' must have an implementation part because it has accessibility modifiers. // internal async partial Task M(); Diagnostic(ErrorCode.ERR_PartialMethodWithAccessibilityModsMustHaveImplementation, "M").WithArguments("C.M()").WithLocation(6, 33), // (6,33): error CS1994: The 'async' modifier can only be used in methods that have a body. // internal async partial Task M(); Diagnostic(ErrorCode.ERR_BadAsyncLacksBody, "M").WithLocation(6, 33)); } [Fact] public void Async_05() { const string text = @" using System.Threading.Tasks; partial class C { internal async partial Task M(); internal async partial Task M() { await Task.Yield(); } } "; var comp = CreateCompilation(text, parseOptions: TestOptions.RegularWithExtendedPartialMethods); comp.VerifyDiagnostics( // (6,33): error CS1994: The 'async' modifier can only be used in methods that have a body. // internal async partial Task M(); Diagnostic(ErrorCode.ERR_BadAsyncLacksBody, "M").WithLocation(6, 33)); } [Fact] public void Async_06() { const string text = @" using System.Threading.Tasks; partial class C { internal async partial Task M(); internal partial Task M() { await Task.Yield(); } } "; var comp = CreateCompilation(text, parseOptions: TestOptions.RegularWithExtendedPartialMethods); comp.VerifyDiagnostics( // (6,33): error CS1994: The 'async' modifier can only be used in methods that have a body. // internal async partial Task M(); Diagnostic(ErrorCode.ERR_BadAsyncLacksBody, "M").WithLocation(6, 33), // (7,27): error CS0161: 'C.M()': not all code paths return a value // internal partial Task M() Diagnostic(ErrorCode.ERR_ReturnExpected, "M").WithArguments("C.M()").WithLocation(7, 27), // (9,9): error CS4032: The 'await' operator can only be used within an async method. Consider marking this method with the 'async' modifier and changing its return type to 'Task<Task>'. // await Task.Yield(); Diagnostic(ErrorCode.ERR_BadAwaitWithoutAsyncMethod, "await Task.Yield()").WithArguments("System.Threading.Tasks.Task").WithLocation(9, 9)); } [Fact] public void Async_07() { const string text = @" using System.Threading.Tasks; partial class C { partial Task M(); async partial Task M() { await Task.Yield(); } } "; var comp = CreateCompilation(text, parseOptions: TestOptions.RegularWithExtendedPartialMethods); comp.VerifyDiagnostics( // (6,18): error CS8794: Partial method 'C.M()' must have accessibility modifiers because it has a non-void return type. // partial Task M(); Diagnostic(ErrorCode.ERR_PartialMethodWithNonVoidReturnMustHaveAccessMods, "M").WithArguments("C.M()").WithLocation(6, 18), // (7,24): error CS8794: Partial method 'C.M()' must have accessibility modifiers because it has a non-void return type. // async partial Task M() Diagnostic(ErrorCode.ERR_PartialMethodWithNonVoidReturnMustHaveAccessMods, "M").WithArguments("C.M()").WithLocation(7, 24)); } [Fact] public void Iterator_01() { const string text = @" using System.Collections.Generic; partial class C { internal partial IEnumerable<int> M(); internal partial IEnumerable<int> M() { yield return 1; yield return 2; } } "; var comp = CreateCompilation(text, parseOptions: TestOptions.RegularWithExtendedPartialMethods); comp.VerifyDiagnostics(); var method = (MethodSymbol)comp.GetMembers("C.M")[0]; Assert.True(method.IsPartialDefinition()); Assert.True(method.IsIterator); Assert.True(method.PartialImplementationPart.IsIterator); } [Fact] public void Iterator_02() { const string text = @" using System.Collections.Generic; using System.Threading.Tasks; partial class C { internal partial IAsyncEnumerable<int> M(); internal partial async IAsyncEnumerable<int> M() { await Task.Yield(); yield return 1; } } "; var comp = CreateCompilationWithTasksExtensions(new[] { text, AsyncStreamsTypes }, parseOptions: TestOptions.RegularWithExtendedPartialMethods); comp.VerifyDiagnostics(); var method = (MethodSymbol)comp.GetMembers("C.M")[0]; Assert.True(method.IsPartialDefinition()); Assert.True(method.IsAsync); Assert.True(method.IsIterator); Assert.True(method.PartialImplementationPart.IsAsync); Assert.True(method.PartialImplementationPart.IsIterator); } [Fact] public void Iterator_03() { // Definition-only partial method is not an iterator const string text = @" using System.Collections.Generic; partial class C { internal partial IEnumerable<int> M(); } "; var comp = CreateCompilation(text, parseOptions: TestOptions.RegularWithExtendedPartialMethods); comp.VerifyDiagnostics( // (6,39): error CS8793: Partial method 'C.M()' must have an implementation part because it has accessibility modifiers. // internal partial IEnumerable<int> M(); Diagnostic(ErrorCode.ERR_PartialMethodWithAccessibilityModsMustHaveImplementation, "M").WithArguments("C.M()").WithLocation(6, 39)); var method = (MethodSymbol)comp.GetMembers("C.M")[0]; Assert.True(method.IsPartialDefinition()); Assert.False(method.IsIterator); } [Fact] public void New_LangVersion() { const string text1 = @" class C { internal void M1() { } } partial class D : C { internal new partial void M1(); internal new partial void M1() { } }"; var comp = CreateCompilation(text1, parseOptions: TestOptions.Regular8); comp.VerifyDiagnostics( // (9,31): error CS8400: Feature 'extended partial methods' is not available in C# 8.0. Please use language version 9.0 or greater. // internal new partial void M1(); Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion8, "M1").WithArguments("extended partial methods", "9.0").WithLocation(9, 31), // (10,31): error CS8400: Feature 'extended partial methods' is not available in C# 8.0. Please use language version 9.0 or greater. // internal new partial void M1() { } Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion8, "M1").WithArguments("extended partial methods", "9.0").WithLocation(10, 31)); comp = CreateCompilation(text1, parseOptions: TestOptions.RegularWithExtendedPartialMethods); comp.VerifyDiagnostics(); } [Fact] public void New_NoImpl() { const string text1 = @" class C { internal void M1() { } } partial class D : C { internal new partial void M1(); }"; var comp = CreateCompilation(text1, parseOptions: TestOptions.RegularWithExtendedPartialMethods); comp.VerifyDiagnostics( // (9,31): error CS8793: Partial method 'D.M1()' must have an implementation part because it has accessibility modifiers. // internal new partial void M1(); Diagnostic(ErrorCode.ERR_PartialMethodWithAccessibilityModsMustHaveImplementation, "M1").WithArguments("D.M1()").WithLocation(9, 31) ); } [Fact] public void New_NoAccessibility() { const string text1 = @" class C { internal void M1() { } } partial class D : C { new partial void M1(); new partial void M1() { } }"; var comp = CreateCompilation(text1, parseOptions: TestOptions.RegularWithExtendedPartialMethods); comp.VerifyDiagnostics( // (9,22): error CS8796: Partial method 'D.M1()' must have accessibility modifiers because it has a 'virtual', 'override', 'sealed', 'new', or 'extern' modifier. // new partial void M1(); Diagnostic(ErrorCode.ERR_PartialMethodWithExtendedModMustHaveAccessMods, "M1").WithArguments("D.M1()").WithLocation(9, 22), // (10,22): error CS8796: Partial method 'D.M1()' must have accessibility modifiers because it has a 'virtual', 'override', 'sealed', 'new', or 'extern' modifier. // new partial void M1() { } Diagnostic(ErrorCode.ERR_PartialMethodWithExtendedModMustHaveAccessMods, "M1").WithArguments("D.M1()").WithLocation(10, 22) ); } [Fact] public void New_Mismatch_01() { const string text1 = @" class C { internal void M1() { } } partial class D : C { internal new partial void M1(); internal partial void M1() { } }"; var comp = CreateCompilation(text1, parseOptions: TestOptions.RegularWithExtendedPartialMethods); comp.VerifyDiagnostics( // (10,27): error CS8798: Both partial method declarations must have equal combinations of 'virtual', 'override', 'sealed', or 'new' modifiers. // internal partial void M1() { } Diagnostic(ErrorCode.ERR_PartialMemberExtendedModDifference, "M1").WithLocation(10, 27) ); } [Fact] public void New_Mismatch_02() { const string text1 = @" class C { internal void M1() { } } partial class D : C { internal partial void M1(); internal new partial void M1() { } }"; var comp = CreateCompilation(text1, parseOptions: TestOptions.RegularWithExtendedPartialMethods); comp.VerifyDiagnostics( // (9,27): warning CS0108: 'D.M1()' hides inherited member 'C.M1()'. Use the new keyword if hiding was intended. // internal partial void M1(); Diagnostic(ErrorCode.WRN_NewRequired, "M1").WithArguments("D.M1()", "C.M1()").WithLocation(9, 27), // (10,31): error CS8798: Both partial method declarations must have equal combinations of 'virtual', 'override', 'sealed', or 'new' modifiers. // internal new partial void M1() { } Diagnostic(ErrorCode.ERR_PartialMemberExtendedModDifference, "M1").WithLocation(10, 31) ); } [Fact] public void InterfaceImpl_01() { const string text = @" interface I { void M(); } partial class C { public partial void M(); } partial class C : I { public partial void M() { System.Console.Write(1); } static void Main() { I i = new C(); i.M(); } } "; var verifier = CompileAndVerify( text, parseOptions: TestOptions.RegularWithExtendedPartialMethods, options: TestOptions.DebugExe, expectedOutput: "1"); verifier.VerifyDiagnostics(); } [Fact] public void InterfaceImpl_02() { const string text = @" interface I { void M(); } partial class C : I { public partial void M(); } partial class C { public partial void M() { System.Console.Write(1); } static void Main() { I i = new C(); i.M(); } } "; var verifier = CompileAndVerify( text, parseOptions: TestOptions.RegularWithExtendedPartialMethods, options: TestOptions.DebugExe, expectedOutput: "1"); verifier.VerifyDiagnostics(); } [Fact] public void InterfaceImpl_03() { const string text = @" #nullable enable using System.Diagnostics.CodeAnalysis; interface I { void M([AllowNull] string s1); } partial class C : I { public partial void M(string s1); // 1 } partial class C { public partial void M(string s1) { s1.ToString(); } } "; var comp = CreateCompilation(new[] { text, AllowNullAttributeDefinition }, parseOptions: TestOptions.RegularWithExtendedPartialMethods); comp.VerifyDiagnostics( // (13,25): warning CS8767: Nullability of reference types in type of parameter 's1' of 'void C.M(string s1)' doesn't match implicitly implemented member 'void I.M(string s1)' (possibly because of nullability attributes). // public partial void M(string s1); Diagnostic(ErrorCode.WRN_TopLevelNullabilityMismatchInParameterTypeOnImplicitImplementation, "M").WithArguments("s1", "void C.M(string s1)", "void I.M(string s1)").WithLocation(13, 25)); } [Fact] public void InterfaceImpl_04() { const string text = @" #nullable enable using System.Diagnostics.CodeAnalysis; interface I { void M([AllowNull] string s1, [AllowNull] string s2); } partial class C : I { public partial void M([AllowNull] string s1, string s2); } partial class C { public partial void M(string s1, [AllowNull] string s2) { s1.ToString(); // 1 s2.ToString(); // 2 } } "; var comp = CreateCompilation(new[] { text, AllowNullAttributeDefinition }, parseOptions: TestOptions.RegularWithExtendedPartialMethods); comp.VerifyDiagnostics( // (20,9): warning CS8602: Dereference of a possibly null reference. // s1.ToString(); // 1 Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "s1").WithLocation(20, 9), // (21,9): warning CS8602: Dereference of a possibly null reference. // s2.ToString(); // 2 Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "s2").WithLocation(21, 9)); } [Fact] public void InterfaceImpl_05() { const string text = @" #nullable enable using System.Diagnostics.CodeAnalysis; interface I { void M([AllowNull] string s1); } partial class C : I { public partial void M([AllowNull] string s1); } partial class C { public partial void M([AllowNull] string s1) // 1 { s1.ToString(); // 2 } } "; var comp = CreateCompilation(new[] { text, AllowNullAttributeDefinition }, parseOptions: TestOptions.RegularWithExtendedPartialMethods); comp.VerifyDiagnostics( // (13,28): error CS0579: Duplicate 'AllowNull' attribute // public partial void M([AllowNull] string s1); Diagnostic(ErrorCode.ERR_DuplicateAttribute, "AllowNull").WithArguments("AllowNull").WithLocation(13, 28), // (20,9): warning CS8602: Dereference of a possibly null reference. // s1.ToString(); // 2 Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "s1").WithLocation(20, 9)); } [Fact] public void DefaultInterfaceImpl_NoImpl() { const string text = @" #nullable enable partial interface I { internal partial void M(string s1); } "; var comp = CreateCompilation(text, parseOptions: TestOptions.RegularWithExtendedPartialMethods, targetFramework: TargetFramework.NetCoreApp); comp.VerifyDiagnostics( // (6,27): error CS8793: Partial method 'I.M(string)' must have an implementation part because it has accessibility modifiers. // internal partial void M(string s1); Diagnostic(ErrorCode.ERR_PartialMethodWithAccessibilityModsMustHaveImplementation, "M").WithArguments("I.M(string)").WithLocation(6, 27) ); } [Fact] public void DefaultInterfaceImpl_01() { const string text = @" #nullable enable partial interface I { internal partial void M(string s1); internal partial void M(string s1) { } } "; var comp = CreateCompilation(text, parseOptions: TestOptions.RegularWithExtendedPartialMethods, targetFramework: TargetFramework.NetCoreApp); comp.VerifyDiagnostics(); } [Fact] public void DefaultInterfaceImpl_AllowNull_01() { const string text = @" #nullable enable using System.Diagnostics.CodeAnalysis; partial interface I { public partial void M([AllowNull] string s1); public partial void M(string s1) { _ = s1.ToString(); // 1 } } class C : I { public void M(string s1) { } } "; // note that I.M is not virtual so C.M does not implement it var comp = CreateCompilation(text, parseOptions: TestOptions.RegularWithExtendedPartialMethods, targetFramework: TargetFramework.NetCoreApp); comp.VerifyDiagnostics( // (10,13): warning CS8602: Dereference of a possibly null reference. // _ = s1.ToString(); Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "s1").WithLocation(10, 13) ); } [Fact] public void DefaultInterfaceImpl_AllowNull_02() { const string text = @" #nullable enable using System.Diagnostics.CodeAnalysis; partial interface I { public virtual partial void M([AllowNull] string s1, string s2); public virtual partial void M(string s1, [AllowNull] string s2) { _ = s1.ToString(); // 1 _ = s2.ToString(); // 2 } } class C : I { void I.M(string s1, string s2) { } // 3, 4 } "; var comp = CreateCompilation(text, parseOptions: TestOptions.RegularWithExtendedPartialMethods, targetFramework: TargetFramework.NetCoreApp); comp.VerifyDiagnostics( // (10,13): warning CS8602: Dereference of a possibly null reference. // _ = s1.ToString(); // 1 Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "s1").WithLocation(10, 13), // (11,13): warning CS8602: Dereference of a possibly null reference. // _ = s2.ToString(); // 2 Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "s2").WithLocation(11, 13), // (17,12): warning CS8769: Nullability of reference types in type of parameter 's1' doesn't match implemented member 'void I.M(string s1, string s2)' (possibly because of nullability attributes). // void I.M(string s1, string s2) { } // 3, 4 Diagnostic(ErrorCode.WRN_TopLevelNullabilityMismatchInParameterTypeOnExplicitImplementation, "M").WithArguments("s1", "void I.M(string s1, string s2)").WithLocation(17, 12), // (17,12): warning CS8769: Nullability of reference types in type of parameter 's2' doesn't match implemented member 'void I.M(string s1, string s2)' (possibly because of nullability attributes). // void I.M(string s1, string s2) { } // 3, 4 Diagnostic(ErrorCode.WRN_TopLevelNullabilityMismatchInParameterTypeOnExplicitImplementation, "M").WithArguments("s2", "void I.M(string s1, string s2)").WithLocation(17, 12) ); } [Fact] public void DefaultInterfaceImpl_AllowNull_03() { const string text = @" #nullable enable using System.Diagnostics.CodeAnalysis; partial interface I { public virtual partial void M([AllowNull] string s1, string s2); public virtual partial void M(string s1, [AllowNull] string s2) { _ = s1.ToString(); // 1 _ = s2.ToString(); // 2 } } partial class C : I { public partial void M(string s1, [AllowNull] string s2); public partial void M([AllowNull] string s1, string s2) { _ = s1.ToString(); // 3 _ = s2.ToString(); // 4 } } "; var comp = CreateCompilation(text, parseOptions: TestOptions.RegularWithExtendedPartialMethods, targetFramework: TargetFramework.NetCoreApp); comp.VerifyDiagnostics( // (10,13): warning CS8602: Dereference of a possibly null reference. // _ = s1.ToString(); // 1 Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "s1").WithLocation(10, 13), // (11,13): warning CS8602: Dereference of a possibly null reference. // _ = s2.ToString(); // 2 Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "s2").WithLocation(11, 13), // (20,13): warning CS8602: Dereference of a possibly null reference. // _ = s1.ToString(); // 3 Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "s1").WithLocation(20, 13), // (21,13): warning CS8602: Dereference of a possibly null reference. // _ = s2.ToString(); // 4 Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "s2").WithLocation(21, 13) ); } [Fact] public void ExplicitInterfaceImpl_01() { const string text = @" interface I { void M(); } partial class C : I { partial void I.M(); // 1 partial void I.M() { } // 2 } "; var comp = CreateCompilation(text); comp.VerifyDiagnostics( // (9,20): error CS0754: A partial member may not explicitly implement an interface member // partial void I.M(); // 1 Diagnostic(ErrorCode.ERR_PartialMemberNotExplicit, "M").WithLocation(9, 20), // (10,20): error CS0754: A partial member may not explicitly implement an interface member // partial void I.M() { } // 2 Diagnostic(ErrorCode.ERR_PartialMemberNotExplicit, "M").WithLocation(10, 20)); } [Fact] public void ExplicitInterfaceImpl_02() { const string text = @" interface I { int M(); } partial class C : I { partial int I.M(); partial int I.M() => 42; } "; var comp = CreateCompilation(text, parseOptions: TestOptions.RegularWithExtendedPartialMethods); comp.VerifyDiagnostics( // (9,19): error CS0754: A partial member may not explicitly implement an interface member // partial int I.M(); Diagnostic(ErrorCode.ERR_PartialMemberNotExplicit, "M").WithLocation(9, 19), // (9,19): error CS8794: Partial method 'C.I.M()' must have accessibility modifiers because it has a non-void return type. // partial int I.M(); Diagnostic(ErrorCode.ERR_PartialMethodWithNonVoidReturnMustHaveAccessMods, "M").WithArguments("C.I.M()").WithLocation(9, 19), // (10,19): error CS0754: A partial member may not explicitly implement an interface member // partial int I.M() => 42; Diagnostic(ErrorCode.ERR_PartialMemberNotExplicit, "M").WithLocation(10, 19), // (10,19): error CS8794: Partial method 'C.I.M()' must have accessibility modifiers because it has a non-void return type. // partial int I.M() => 42; Diagnostic(ErrorCode.ERR_PartialMethodWithNonVoidReturnMustHaveAccessMods, "M").WithArguments("C.I.M()").WithLocation(10, 19)); } [Fact] public void InInterface() { var source = """ partial interface I { public partial int M(); public partial int M() => 0; } """; CreateCompilation(source).VerifyDiagnostics( // (4,24): error CS8701: Target runtime doesn't support default interface implementation. // public partial int M() => 0; Diagnostic(ErrorCode.ERR_RuntimeDoesNotSupportDefaultInterfaceImplementation, "M").WithLocation(4, 24)); CreateCompilation(source, targetFramework: TargetFramework.Net60).VerifyDiagnostics(); CreateCompilation(source, targetFramework: TargetFramework.Net60, parseOptions: TestOptions.Regular7).VerifyDiagnostics( // (3,24): error CS8703: The modifier 'public' is not valid for this item in C# 7.0. Please use language version '8.0' or greater. // public partial int M(); Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M").WithArguments("public", "7.0", "8.0").WithLocation(3, 24), // (3,24): error CS8703: The modifier 'partial' is not valid for this item in C# 7.0. Please use language version '8.0' or greater. // public partial int M(); Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "M").WithArguments("partial", "7.0", "8.0").WithLocation(3, 24), // (3,24): error CS8107: Feature 'extended partial methods' is not available in C# 7.0. Please use language version 9.0 or greater. // public partial int M(); Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7, "M").WithArguments("extended partial methods", "9.0").WithLocation(3, 24), // (4,24): error CS8107: Feature 'default interface implementation' is not available in C# 7.0. Please use language version 8.0 or greater. // public partial int M() => 0; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7, "M").WithArguments("default interface implementation", "8.0").WithLocation(4, 24), // (4,24): error CS8107: Feature 'extended partial methods' is not available in C# 7.0. Please use language version 9.0 or greater. // public partial int M() => 0; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7, "M").WithArguments("extended partial methods", "9.0").WithLocation(4, 24)); } [Fact] public void InInterface_DefinitionOnly() { var source = """ partial interface I { public partial int M(); } """; CreateCompilation(source).VerifyDiagnostics( // (3,24): error CS8795: Partial method 'I.M()' must have an implementation part because it has accessibility modifiers. // public partial int M(); Diagnostic(ErrorCode.ERR_PartialMethodWithAccessibilityModsMustHaveImplementation, "M").WithArguments("I.M()").WithLocation(3, 24)); } [Theory, CombinatorialData, WorkItem("https://github.com/dotnet/roslyn/issues/77346")] public void InInterface_Virtual( [CombinatorialValues("", "public", "private", "protected", "internal", "protected internal", "private protected")] string access, [CombinatorialValues("", "virtual", "sealed")] string virt, [CombinatorialValues(LanguageVersion.CSharp13, LanguageVersion.Preview, LanguageVersion.CSharp14)] LanguageVersion langVersion) { var source1 = $$""" using System; partial interface I { {{access}} {{virt}} partial void M(); {{access}} {{virt}} partial void M() { Console.Write(1); } } """; var source2 = """ using System; partial interface I { static void Main() { Helper(new C1()); Helper(new C2()); } static void Helper(I x) { x.M(); } } class C1 : I; class C2 : I { void I.M() { Console.Write(2); } } """; bool expectedPrivate = access is "" or "private"; var expectedAccessibility = access switch { _ when expectedPrivate => Accessibility.Private, "public" => Accessibility.Public, "protected" => Accessibility.Protected, "internal" => Accessibility.Internal, "protected internal" => Accessibility.ProtectedOrInternal, "private protected" => Accessibility.ProtectedAndFriend, _ => throw ExceptionUtilities.UnexpectedValue(access), }; bool expectedVirtual = virt == "virtual"; bool expectedSealed = virt == "sealed"; bool executable = !expectedPrivate && virt == "virtual"; DiagnosticDescription[] expectedDiagnostics = []; if (access == "" && virt != "") { expectedDiagnostics = [ // (6,18): error CS8798: Partial method 'I.M()' must have accessibility modifiers because it has a 'virtual', 'override', 'sealed', 'new', or 'extern' modifier. // partial void M(); Diagnostic(ErrorCode.ERR_PartialMethodWithExtendedModMustHaveAccessMods, "M").WithArguments("I.M()").WithLocation(6, 18), // (8,18): error CS8798: Partial method 'I.M()' must have accessibility modifiers because it has a 'virtual', 'override', 'sealed', 'new', or 'extern' modifier. // partial void M() { Console.Write(1); } Diagnostic(ErrorCode.ERR_PartialMethodWithExtendedModMustHaveAccessMods, "M").WithArguments("I.M()").WithLocation(8, 18) ]; } else if (virt == "sealed") { expectedDiagnostics = [ // (6,18): error CS0238: 'I.M()' cannot be sealed because it is not an override // partial void M(); Diagnostic(ErrorCode.ERR_SealedNonOverride, "M").WithArguments("I.M()").WithLocation(6, 18), // (8,18): error CS0238: 'I.M()' cannot be sealed because it is not an override // partial void M() { Console.Write(1); } Diagnostic(ErrorCode.ERR_SealedNonOverride, "M").WithArguments("I.M()").WithLocation(8, 18) ]; } else if (expectedPrivate && virt == "virtual") { expectedDiagnostics = [ // (6,18): error CS0621: 'I.M()': virtual or abstract members cannot be private // partial void M(); Diagnostic(ErrorCode.ERR_VirtualPrivate, "M").WithArguments("I.M()").WithLocation(6, 18), // (8,18): error CS0621: 'I.M()': virtual or abstract members cannot be private // partial void M() { Console.Write(1); } Diagnostic(ErrorCode.ERR_VirtualPrivate, "M").WithArguments("I.M()").WithLocation(8, 18) ]; } var comp = CreateCompilation(executable ? [source1, source2] : source1, options: TestOptions.DebugDll .WithOutputKind(executable ? OutputKind.ConsoleApplication : OutputKind.DynamicallyLinkedLibrary) .WithMetadataImportOptions(MetadataImportOptions.All), parseOptions: TestOptions.Regular.WithLanguageVersion(langVersion), targetFramework: TargetFramework.Net60).VerifyDiagnostics(expectedDiagnostics); if (expectedDiagnostics.Length == 0) { CompileAndVerify(comp, sourceSymbolValidator: validate, symbolValidator: validate, expectedOutput: executable && ExecutionConditionUtil.IsMonoOrCoreClr ? "12" : null, verify: Verification.FailsPEVerify).VerifyDiagnostics(); } else { validate(comp.SourceModule); } void validate(ModuleSymbol module) { var m = module.GlobalNamespace.GetMember<MethodSymbol>("I.M"); validateMethod(m); if (module is SourceModuleSymbol) { validateMethod((MethodSymbol)m.GetPartialImplementationPart()!); } } void validateMethod(MethodSymbol m) { Assert.False(m.IsAbstract); Assert.Equal(expectedVirtual, m.IsVirtual); Assert.Equal(expectedVirtual, m.IsMetadataVirtual()); Assert.Equal(expectedVirtual, m.IsMetadataNewSlot()); Assert.Equal(expectedSealed, m.IsSealed); Assert.False(m.IsStatic); Assert.False(m.IsExtern); Assert.False(m.IsOverride); Assert.Equal(expectedAccessibility, m.DeclaredAccessibility); Assert.True(m.ContainingModule is not SourceModuleSymbol || m.IsPartialMember()); } } [Theory, CombinatorialData, WorkItem("https://github.com/dotnet/roslyn/issues/77346")] public void InInterface_StaticVirtual( [CombinatorialValues("", "public", "private", "protected", "internal", "protected internal", "private protected")] string access, [CombinatorialValues("", "virtual", "sealed")] string virt, [CombinatorialValues(LanguageVersion.CSharp13, LanguageVersion.Preview, LanguageVersion.CSharp14)] LanguageVersion langVersion) { var source1 = $$""" partial interface I { {{access}} static {{virt}} partial void M(); {{access}} static {{virt}} partial void M() { System.Console.Write(1); } } """; var source2 = """ partial interface I { static void Main() { Helper<C1>(); Helper<C2>(); Helper<C3>(); } static void Helper<T>() where T : I { T.M(); } } class C1 : I { static void M() { System.Console.Write(2); } } class C2 : I { public static void M() { System.Console.Write(3); } } class C3 : I { static void I.M() { System.Console.Write(4); } } """; bool expectedPrivate = access is "" or "private"; var expectedAccessibility = access switch { _ when expectedPrivate => Accessibility.Private, "public" => Accessibility.Public, "protected" => Accessibility.Protected, "internal" => Accessibility.Internal, "protected internal" => Accessibility.ProtectedOrInternal, "private protected" => Accessibility.ProtectedAndFriend, _ => throw ExceptionUtilities.UnexpectedValue(access), }; bool expectedVirtual = virt == "virtual"; bool executable = virt == "virtual" && !expectedPrivate; DiagnosticDescription[] expectedDiagnostics = []; if (access == "" && virt == "virtual") { expectedDiagnostics = [ // (4,18): error CS8798: Partial method 'I.M()' must have accessibility modifiers because it has a 'virtual', 'override', 'sealed', 'new', or 'extern' modifier. // partial void M(); Diagnostic(ErrorCode.ERR_PartialMethodWithExtendedModMustHaveAccessMods, "M").WithArguments("I.M()").WithLocation(4, 18), // (6,18): error CS8798: Partial method 'I.M()' must have accessibility modifiers because it has a 'virtual', 'override', 'sealed', 'new', or 'extern' modifier. // partial void M() { System.Console.Write(1); } Diagnostic(ErrorCode.ERR_PartialMethodWithExtendedModMustHaveAccessMods, "M").WithArguments("I.M()").WithLocation(6, 18) ]; } else if (access == "private" && virt == "virtual") { expectedDiagnostics = [ // (4,18): error CS0621: 'I.M()': virtual or abstract members cannot be private // partial void M(); Diagnostic(ErrorCode.ERR_VirtualPrivate, "M").WithArguments("I.M()").WithLocation(4, 18), // (6,18): error CS0621: 'I.M()': virtual or abstract members cannot be private // partial void M() { System.Console.Write(1); } Diagnostic(ErrorCode.ERR_VirtualPrivate, "M").WithArguments("I.M()").WithLocation(6, 18) ]; } var comp = CreateCompilation(executable ? [source1, source2] : source1, parseOptions: TestOptions.Regular.WithLanguageVersion(langVersion), options: TestOptions.DebugDll .WithOutputKind(executable ? OutputKind.ConsoleApplication : OutputKind.DynamicallyLinkedLibrary) .WithMetadataImportOptions(MetadataImportOptions.All), targetFramework: TargetFramework.Net60).VerifyDiagnostics(expectedDiagnostics); if (expectedDiagnostics.Length == 0) { CompileAndVerify(comp, sourceSymbolValidator: validate, symbolValidator: validate, expectedOutput: executable && ExecutionConditionUtil.IsMonoOrCoreClr ? "134" : null, verify: virt != "virtual" ? Verification.FailsPEVerify : Verification.Fails with { ILVerifyMessage = """ [Helper]: Missing callvirt following constrained prefix. { Offset = 0x7 } """, }).VerifyDiagnostics(); } else { validate(comp.SourceModule); } void validate(ModuleSymbol module) { var m = module.GlobalNamespace.GetMember<MethodSymbol>("I.M"); validateMethod(m); if (module is SourceModuleSymbol) { validateMethod((MethodSymbol)m.GetPartialImplementationPart()!); } } void validateMethod(MethodSymbol m) { Assert.False(m.IsAbstract); Assert.Equal(expectedVirtual, m.IsVirtual); Assert.Equal(expectedVirtual, m.IsMetadataVirtual()); Assert.False(m.IsMetadataNewSlot()); Assert.False(m.IsSealed); Assert.True(m.IsStatic); Assert.False(m.IsExtern); Assert.False(m.IsOverride); Assert.Equal(expectedAccessibility, m.DeclaredAccessibility); Assert.True(m.ContainingModule is not SourceModuleSymbol || m.IsPartialMember()); } } [Fact] public void InsideStruct() { const string text = @" partial struct S { public partial int M(); public partial int M() => 42; } "; var comp = CreateCompilation(text, parseOptions: TestOptions.Regular8); comp.VerifyDiagnostics( // (4,24): error CS8400: Feature 'extended partial methods' is not available in C# 8.0. Please use language version 9.0 or greater. // public partial int M(); Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion8, "M").WithArguments("extended partial methods", "9.0").WithLocation(4, 24), // (5,24): error CS8400: Feature 'extended partial methods' is not available in C# 8.0. Please use language version 9.0 or greater. // public partial int M() => 42; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion8, "M").WithArguments("extended partial methods", "9.0").WithLocation(5, 24)); comp = CreateCompilation(text, parseOptions: TestOptions.RegularWithExtendedPartialMethods); comp.VerifyDiagnostics(); } [Fact] public void ReturnAttribute_01() { const string text = @" class Attr1 : System.Attribute { } class Attr2 : System.Attribute { } public partial class C { [return: Attr1] public partial string M(); [return: Attr2] public partial string M() => ""hello""; } "; var expectedAttributeNames = new[] { "Attr1", "Attr2" }; var comp = CreateCompilation(text, parseOptions: TestOptions.RegularWithExtendedPartialMethods); comp.VerifyDiagnostics(); CompileAndVerify(comp, symbolValidator: validator); var definitionPart = comp.GetMember<MethodSymbol>("C.M"); Assert.True(definitionPart.IsPartialDefinition()); Assert.Equal(expectedAttributeNames, GetAttributeNames(definitionPart.GetReturnTypeAttributes())); var implementationPart = definitionPart.PartialImplementationPart; Assert.NotNull(implementationPart); Assert.True(implementationPart.IsPartialImplementation()); Assert.Equal(expectedAttributeNames, GetAttributeNames(implementationPart.GetReturnTypeAttributes())); void validator(ModuleSymbol module) { var method = module.ContainingAssembly .GetTypeByMetadataName("C") .GetMember<MethodSymbol>("M"); Assert.Equal(expectedAttributeNames, GetAttributeNames(method.GetReturnTypeAttributes())); } } [Fact] public void ConflictingOverloads_RefOut_01() { const string text = @" partial class Program { internal static partial void M(ref object o); internal static partial void M(out object o); internal static partial void M(out object o) { o = null; } } "; var comp = CreateCompilation(text, parseOptions: TestOptions.RegularWithExtendedPartialMethods); comp.VerifyDiagnostics( // (4,34): error CS8793: Partial method 'Program.M(ref object)' must have an implementation part because it has accessibility modifiers. // internal static partial void M(ref object o); Diagnostic(ErrorCode.ERR_PartialMethodWithAccessibilityModsMustHaveImplementation, "M").WithArguments("Program.M(ref object)").WithLocation(4, 34), // (5,34): error CS0663: 'Program' cannot define an overloaded method that differs only on parameter modifiers 'out' and 'ref' // internal static partial void M(out object o); Diagnostic(ErrorCode.ERR_OverloadRefKind, "M").WithArguments("Program", "method", "out", "ref").WithLocation(5, 34)); } [Fact] public void ConflictingOverloads_RefOut_02() { const string text = @" partial class Program { internal static partial void M(ref object o); internal static partial void M(ref object o) { } internal static partial void M(out object o); internal static partial void M(out object o) { o = null; } } "; var comp = CreateCompilation(text, parseOptions: TestOptions.RegularWithExtendedPartialMethods); comp.VerifyDiagnostics( // (6,34): error CS0663: 'Program' cannot define an overloaded method that differs only on parameter modifiers 'out' and 'ref' // internal static partial void M(out object o); Diagnostic(ErrorCode.ERR_OverloadRefKind, "M").WithArguments("Program", "method", "out", "ref").WithLocation(6, 34)); } [Fact] public void RefReturn() { const string text = @" using System; partial class Program { static int i = 1; private static partial ref int M(); private static partial ref int M() => ref i; static void Main() { ref int local = ref M(); Console.Write(local); i++; Console.Write(local); } } "; var verifier = CompileAndVerify( text, parseOptions: TestOptions.RegularWithExtendedPartialMethods, expectedOutput: "12"); verifier.VerifyDiagnostics(); } [Fact] public void PrivateProtectedAccessibility_01() { const string text1 = @" using System; public partial class Base { private protected static partial void M1(); private protected static partial void M1() { Console.Write(1); } }"; const string text2 = @" class Derived : Base { static void Main() { M1(); } }"; var verifier = CompileAndVerify( new[] { text1, text2 }, parseOptions: TestOptions.RegularWithExtendedPartialMethods, expectedOutput: "1"); verifier.VerifyDiagnostics(); var comp1 = CreateCompilation(text1, parseOptions: TestOptions.RegularWithExtendedPartialMethods); verify(comp1.ToMetadataReference()); verify(comp1.EmitToImageReference()); void verify(MetadataReference reference) { var comp2 = CreateCompilation( text2, references: new[] { reference }, parseOptions: TestOptions.RegularWithExtendedPartialMethods); comp2.VerifyDiagnostics( // (6,9): error CS0122: 'Base.M1()' is inaccessible due to its protection level // M1(); Diagnostic(ErrorCode.ERR_BadAccess, "M1").WithArguments("Base.M1()").WithLocation(6, 9)); } } [Fact] public void PrivateProtectedAccessibility_02() { const string text1 = @" using System; partial class C { private protected static partial void M1(); private protected static partial void M1() { Console.Write(1); } }"; const string text2 = @" class Program { static void Main() { C.M1(); // 1 } }"; var comp = CreateCompilation(new[] { text1, text2 }, parseOptions: TestOptions.RegularWithExtendedPartialMethods); comp.VerifyDiagnostics( // (6,11): error CS0122: 'C.M1()' is inaccessible due to its protection level // C.M1(); // 1 Diagnostic(ErrorCode.ERR_BadAccess, "M1").WithArguments("C.M1()").WithLocation(6, 11)); } [Fact] public void ProtectedAccessibility_01() { const string text1 = @" using System; partial class Base { protected static partial void M1(); protected static partial void M1() { Console.Write(1); } }"; const string text2 = @" class Derived : Base { static void Main() { M1(); } }"; var verifier = CompileAndVerify( new[] { text1, text2 }, parseOptions: TestOptions.RegularWithExtendedPartialMethods, expectedOutput: "1"); verifier.VerifyDiagnostics(); } [Fact] public void ProtectedAccessibility_02() { const string text1 = @" using System; partial class C { protected static partial void M1(); protected static partial void M1() { Console.Write(1); } }"; const string text2 = @" class Program { static void Main() { C.M1(); // 1 } }"; var comp = CreateCompilation(new[] { text1, text2 }, parseOptions: TestOptions.RegularWithExtendedPartialMethods); comp.VerifyDiagnostics( // (6,11): error CS0122: 'C.M1()' is inaccessible due to its protection level // C.M1(); // 1 Diagnostic(ErrorCode.ERR_BadAccess, "M1").WithArguments("C.M1()").WithLocation(6, 11)); } [Fact] public void InternalAccessibility_01() { const string text1 = @" using System; internal partial class C { internal static partial void M1(); internal static partial void M1() { Console.Write(1); } }"; const string text2 = @" class Program { static void Main() { C.M1(); } }"; var verifier = CompileAndVerify( new[] { text1, text2 }, parseOptions: TestOptions.RegularWithExtendedPartialMethods, expectedOutput: "1"); verifier.VerifyDiagnostics(); } [Fact] public void InternalAccessibility_02() { const string text1 = @" using System; internal partial class C { internal static partial void M1(); internal static partial void M1() { Console.Write(1); } }"; const string text2 = @" class Program { static void Main() { C.M1(); // 1 } }"; var comp1 = CreateCompilation(text1, parseOptions: TestOptions.RegularWithExtendedPartialMethods); comp1.VerifyDiagnostics(); verify(comp1.ToMetadataReference()); verify(comp1.EmitToImageReference()); void verify(MetadataReference reference) { var comp2 = CreateCompilation( text2, references: new[] { comp1.ToMetadataReference() }, parseOptions: TestOptions.RegularWithExtendedPartialMethods); comp2.VerifyDiagnostics( // (6,9): error CS0122: 'C' is inaccessible due to its protection level // C.M1(); // 1 Diagnostic(ErrorCode.ERR_BadAccess, "C").WithArguments("C").WithLocation(6, 9)); } } [Fact] public void ProtectedInternalAccessibility_01() { const string text1 = @" using System; public partial class C { protected internal static partial void M1(); protected internal static partial void M1() { Console.Write(1); } }"; const string text2 = @" class Program { static void Main() { C.M1(); } }"; var verifier = CompileAndVerify( new[] { text1, text2 }, parseOptions: TestOptions.RegularWithExtendedPartialMethods, expectedOutput: "1"); verifier.VerifyDiagnostics(); var comp1 = CreateCompilation(text1, parseOptions: TestOptions.RegularWithExtendedPartialMethods); verify(comp1.ToMetadataReference()); verify(comp1.EmitToImageReference()); void verify(MetadataReference reference) { var comp2 = CreateCompilation( text2, references: new[] { reference }, parseOptions: TestOptions.RegularWithExtendedPartialMethods); comp2.VerifyDiagnostics( // (6,11): error CS0122: 'C.M1()' is inaccessible due to its protection level // C.M1(); Diagnostic(ErrorCode.ERR_BadAccess, "M1").WithArguments("C.M1()").WithLocation(6, 11)); } } [Fact] public void ProtectedInternalAccessibility_02() { const string text1 = @" using System; public partial class Base { protected internal static partial void M1(); protected internal static partial void M1() { Console.Write(1); } }"; const string text2 = @" class Derived : Base { static void Main() { M1(); } }"; var verifier = CompileAndVerify( new[] { text1, text2 }, parseOptions: TestOptions.RegularWithExtendedPartialMethods, expectedOutput: "1"); verifier.VerifyDiagnostics(); var comp1 = CreateCompilation(text1, parseOptions: TestOptions.RegularWithExtendedPartialMethods); verify(comp1.ToMetadataReference()); verify(comp1.EmitToImageReference()); void verify(MetadataReference reference) { var verifier = CompileAndVerify( text2, references: new[] { reference }, parseOptions: TestOptions.RegularWithExtendedPartialMethods, expectedOutput: "1"); verifier.VerifyDiagnostics(); } } [Fact] public void PublicAccessibility() { const string text1 = @" using System; public partial class C { public static partial void M1(); public static partial void M1() { Console.Write(1); } }"; const string text2 = @" class Program { static void Main() { C.M1(); } }"; var verifier = CompileAndVerify( new[] { text1, text2 }, parseOptions: TestOptions.RegularWithExtendedPartialMethods, expectedOutput: "1"); verifier.VerifyDiagnostics(); var comp1 = CreateCompilation(text1, parseOptions: TestOptions.RegularWithExtendedPartialMethods); verify(comp1.ToMetadataReference()); verify(comp1.EmitToImageReference()); void verify(MetadataReference reference) { var verifier = CompileAndVerify( text2, references: new[] { reference }, parseOptions: TestOptions.RegularWithExtendedPartialMethods, expectedOutput: "1"); verifier.VerifyDiagnostics(); } } [Fact] public void EntryPoint_01() { const string text1 = @" using System.Threading.Tasks; public partial class C { public static partial Task Main(); }"; var comp1 = CreateCompilation( text1, parseOptions: TestOptions.RegularWithExtendedPartialMethods, options: TestOptions.DebugExe); comp1.VerifyDiagnostics( // error CS5001: Program does not contain a static 'Main' method suitable for an entry point Diagnostic(ErrorCode.ERR_NoEntryPoint).WithLocation(1, 1), // (6,32): error CS8793: Partial method 'C.Main()' must have an implementation part because it has accessibility modifiers. // public static partial Task Main(); Diagnostic(ErrorCode.ERR_PartialMethodWithAccessibilityModsMustHaveImplementation, "Main").WithArguments("C.Main()").WithLocation(6, 32)); } [Fact] public void EntryPoint_02() { const string text1 = @" using System.Threading.Tasks; using System; public partial class C { public static partial Task Main(); public static partial async Task Main() { Console.Write(1); } }"; var verifier = CompileAndVerify( text1, parseOptions: TestOptions.RegularWithExtendedPartialMethods, options: TestOptions.DebugExe, expectedOutput: "1"); verifier.VerifyDiagnostics(); } [Fact] public void EntryPoint_03() { const string text1 = @" using System.Threading.Tasks; public partial class C { public static partial Task<int> Main(); }"; var comp1 = CreateCompilation( text1, parseOptions: TestOptions.RegularWithExtendedPartialMethods, options: TestOptions.DebugExe); comp1.VerifyDiagnostics( // error CS5001: Program does not contain a static 'Main' method suitable for an entry point Diagnostic(ErrorCode.ERR_NoEntryPoint).WithLocation(1, 1), // (6,37): error CS8793: Partial method 'C.Main()' must have an implementation part because it has accessibility modifiers. // public static partial Task<int> Main(); Diagnostic(ErrorCode.ERR_PartialMethodWithAccessibilityModsMustHaveImplementation, "Main").WithArguments("C.Main()").WithLocation(6, 37)); } [Fact] public void EntryPoint_04() { const string text1 = @" using System.Threading.Tasks; using System; public partial class C { public static partial Task<int> Main(); public static partial async Task<int> Main() { Console.Write(1); return 1; } }"; var verifier = CompileAndVerify( text1, parseOptions: TestOptions.RegularWithExtendedPartialMethods, options: TestOptions.DebugExe, expectedOutput: "1"); verifier.VerifyDiagnostics(); } [ConditionalFact(typeof(CoreClrOnly))] public void Override_CustomModifiers() { var source1 = @" public class C { public virtual void M(in object x) { } }"; var comp1 = CreateCompilation(source1, assemblyName: "C"); comp1.VerifyDiagnostics(); verify(comp1.ToMetadataReference()); verify(comp1.EmitToImageReference()); void verify(MetadataReference reference) { var source2 = @" public partial class D : C { public override partial void M(in object x); public override partial void M(in object x) { x.ToString(); } } "; var verifier = CompileAndVerify(source2, references: new[] { reference }, parseOptions: TestOptions.RegularWithExtendedPartialMethods); verifier.VerifyTypeIL("D", @" .class public auto ansi beforefieldinit D extends [C]C { // Methods .method public hidebysig virtual instance void M ( [in] object& modreq([netstandard]System.Runtime.InteropServices.InAttribute) x ) cil managed { .param [1] .custom instance void System.Runtime.CompilerServices.IsReadOnlyAttribute::.ctor() = ( 01 00 00 00 ) // Method begins at RVA 0x2067 // Code size 9 (0x9) .maxstack 8 IL_0000: ldarg.1 IL_0001: ldind.ref IL_0002: callvirt instance string [netstandard]System.Object::ToString() IL_0007: pop IL_0008: ret } // end of method D::M .method public hidebysig specialname rtspecialname instance void .ctor () cil managed { // Method begins at RVA 0x2071 // Code size 7 (0x7) .maxstack 8 IL_0000: ldarg.0 IL_0001: call instance void [C]C::.ctor() IL_0006: ret } // end of method D::.ctor } // end of class D "); } } [Fact] public void InterfaceImpl_InThunk() { var source = @" public interface I { void M(in object obj); } public partial class C : I { public partial void M(in object obj); public partial void M(in object obj) { } } "; var verifier = CompileAndVerify( source, options: TestOptions.DebugDll.WithMetadataImportOptions(MetadataImportOptions.All), parseOptions: TestOptions.RegularWithExtendedPartialMethods, symbolValidator: verify); verifier.VerifyDiagnostics(); void verify(ModuleSymbol module) { Assert.Equal(MetadataImportOptions.All, ((PEModuleSymbol)module).ImportOptions); var cType = module.ContainingAssembly.GetTypeByMetadataName("C"); Assert.NotNull(cType.GetMethod("M")); Assert.NotNull(cType.GetMethod("I.M")); } } [Fact] public void ConsumeExtendedPartialFromVB() { var csharp = @" public partial class C { public virtual partial int M1(); public virtual partial int M1() => 42; }"; var comp = CreateCompilation(csharp, parseOptions: TestOptions.RegularWithExtendedPartialMethods); comp.VerifyDiagnostics(); var vb = @" Public Class D Inherits C Public Overrides Function M1() As Integer Return 123 End Function End Class "; var vbComp = CreateVisualBasicCompilation(vb, referencedAssemblies: TargetFrameworkUtil.GetReferences(TargetFramework.Standard).Add(comp.EmitToImageReference())); vbComp.VerifyDiagnostics(); } [Fact] public void Override_SingleDimensionArraySizesInMetadata() { var il = @" .class public auto ansi abstract beforefieldinit Base extends [mscorlib]System.Object { // Methods .method public hidebysig newslot abstract virtual void M1 (int32[0...] param) cil managed { } .method public hidebysig newslot abstract virtual int32[0...] M2 () cil managed { } .method family hidebysig specialname rtspecialname instance void .ctor () cil managed { ldarg.0 call instance void [mscorlib]System.Object::.ctor() ret } }"; var source = @" public partial class Derived : Base { public override partial void M1(int[] param); public override partial void M1(int[] param) { } public override partial int[] M2(); public override partial int[] M2() => new int[0]; }"; var comp = CreateCompilationWithIL(source, il, parseOptions: TestOptions.RegularWithExtendedPartialMethods); comp.VerifyDiagnostics( // (2,22): error CS0534: 'Derived' does not implement inherited abstract member 'Base.M1(int[*])' // public partial class Derived : Base Diagnostic(ErrorCode.ERR_UnimplementedAbstractMethod, "Derived").WithArguments("Derived", "Base.M1(int[*])").WithLocation(2, 22), // (4,34): error CS0115: 'Derived.M1(int[])': no suitable method found to override // public override partial void M1(int[] param); Diagnostic(ErrorCode.ERR_OverrideNotExpected, "M1").WithArguments("Derived.M1(int[])").WithLocation(4, 34), // (7,35): error CS0508: 'Derived.M2()': return type must be 'int[*]' to match overridden member 'Base.M2()' // public override partial int[] M2(); Diagnostic(ErrorCode.ERR_CantChangeReturnTypeOnOverride, "M2").WithArguments("Derived.M2()", "Base.M2()", "int[*]").WithLocation(7, 35) ); } [Fact] public void Override_ArraySizesInMetadata() { var il = @" .class public auto ansi abstract beforefieldinit Base extends [mscorlib]System.Object { // Methods .method public hidebysig newslot abstract virtual void M1 (int32[5...5,2...4] param) cil managed { } .method public hidebysig newslot abstract virtual int32[5...5,2...4] M2 () cil managed { } .method family hidebysig specialname rtspecialname instance void .ctor () cil managed { ldarg.0 call instance void [mscorlib]System.Object::.ctor() ret } }"; var source = @" using System; partial class Derived : Base { public override partial void M1(int[,] param); public override partial int[,] M2(); public override partial void M1(int[,] param) { Console.Write(1); } public override partial int[,] M2() { Console.Write(2); return null; } public static void Main() { var d = new Derived(); d.M1(null); _ = d.M2(); } }"; var comp = CreateCompilationWithIL(source, il, options: TestOptions.DebugExe, parseOptions: TestOptions.RegularWithExtendedPartialMethods); CompileAndVerify(comp, expectedOutput: "12"); var m1 = comp.GetMember<MethodSymbol>("Derived.M1"); verifyArray(m1.Parameters[0].Type); var m2 = comp.GetMember<MethodSymbol>("Derived.M2"); verifyArray(m2.ReturnType); static void verifyArray(TypeSymbol type) { var array = (ArrayTypeSymbol)type; Assert.False(array.IsSZArray); Assert.Equal(2, array.Rank); Assert.Equal(5, array.LowerBounds[0]); Assert.Equal(1, array.Sizes[0]); Assert.Equal(2, array.LowerBounds[1]); Assert.Equal(3, array.Sizes[1]); } } [Fact, WorkItem(44930, "https://github.com/dotnet/roslyn/issues/44930")] public void DifferentReturnTypes_01() { var source = @" partial class C { public partial int M(); public partial long M() => 42; // 1 }"; var comp = CreateCompilation(source, options: TestOptions.ReleaseDll.WithWarningLevel(5), parseOptions: TestOptions.RegularWithExtendedPartialMethods); comp.VerifyDiagnostics( // (5,25): error CS8817: Both partial method declarations must have the same return type. // public partial long M() => 42; // 1 Diagnostic(ErrorCode.ERR_PartialMethodReturnTypeDifference, "M").WithLocation(5, 25)); comp = CreateCompilation(source, options: TestOptions.ReleaseDll.WithWarningLevel(6), parseOptions: TestOptions.RegularWithExtendedPartialMethods); comp.VerifyDiagnostics( // (5,25): error CS8817: Both partial method declarations must have the same return type. // public partial long M() => 42; // 1 Diagnostic(ErrorCode.ERR_PartialMethodReturnTypeDifference, "M").WithLocation(5, 25)); } [Fact, WorkItem(44930, "https://github.com/dotnet/roslyn/issues/44930")] public void DifferentReturnTypes_02() { var source = @" partial class C { public partial long M(); public partial int M() => 42; // 1 }"; var comp = CreateCompilation(source, parseOptions: TestOptions.RegularWithExtendedPartialMethods); comp.VerifyDiagnostics( // (5,24): error CS8817: Both partial method declarations must have the same return type. // public partial int M() => 42; // 1 Diagnostic(ErrorCode.ERR_PartialMethodReturnTypeDifference, "M").WithLocation(5, 24)); } [Fact, WorkItem(44930, "https://github.com/dotnet/roslyn/issues/44930")] public void DifferentReturnTypes_03() { var source = @" using System.Collections.Generic; #nullable enable partial class C { public partial string? M1(); public partial string M1() => ""hello""; public partial IEnumerable<string?> M2(); public partial IEnumerable<string> M2() => null!; }"; var comp = CreateCompilation(source, options: TestOptions.ReleaseDll.WithWarningLevel(5), parseOptions: TestOptions.RegularWithExtendedPartialMethods); comp.VerifyDiagnostics(); comp = CreateCompilation(source, options: TestOptions.ReleaseDll.WithWarningLevel(6), parseOptions: TestOptions.RegularWithExtendedPartialMethods); comp.VerifyDiagnostics( // (8,27): warning CS8825: Partial method declarations 'string? C.M1()' and 'string C.M1()' must have identical nullability for parameter types and return types. // public partial string M1() => "hello"; Diagnostic(ErrorCode.WRN_PartialMethodTypeDifference, "M1").WithArguments("string? C.M1()", "string C.M1()").WithLocation(8, 27), // (11,40): warning CS8825: Partial method declarations 'IEnumerable<string?> C.M2()' and 'IEnumerable<string> C.M2()' must have identical nullability for parameter types and return types. // public partial IEnumerable<string> M2() => null!; Diagnostic(ErrorCode.WRN_PartialMethodTypeDifference, "M2").WithArguments("IEnumerable<string?> C.M2()", "IEnumerable<string> C.M2()").WithLocation(11, 40)); } [Fact, WorkItem(44930, "https://github.com/dotnet/roslyn/issues/44930")] public void DifferentReturnTypes_04() { var source = @" using System.Collections.Generic; #nullable enable partial class C { public partial string M1(); public partial string? M1() => null; // 1 public partial IEnumerable<string> M2(); public partial IEnumerable<string?> M2() => null!; // 2 }"; var comp = CreateCompilation(source, options: TestOptions.ReleaseDll.WithWarningLevel(5), parseOptions: TestOptions.RegularWithExtendedPartialMethods); comp.VerifyDiagnostics( // (8,28): warning CS8819: Nullability of reference types in return type doesn't match partial method declaration. // public partial string? M1() => null; // 1 Diagnostic(ErrorCode.WRN_NullabilityMismatchInReturnTypeOnPartial, "M1").WithLocation(8, 28), // (11,41): warning CS8819: Nullability of reference types in return type doesn't match partial method declaration. // public partial IEnumerable<string?> M2() => null!; // 2 Diagnostic(ErrorCode.WRN_NullabilityMismatchInReturnTypeOnPartial, "M2").WithLocation(11, 41)); comp = CreateCompilation(source, options: TestOptions.ReleaseDll.WithWarningLevel(6), parseOptions: TestOptions.RegularWithExtendedPartialMethods); comp.VerifyDiagnostics( // (8,28): warning CS8819: Nullability of reference types in return type doesn't match partial method declaration. // public partial string? M1() => null; // 1 Diagnostic(ErrorCode.WRN_NullabilityMismatchInReturnTypeOnPartial, "M1").WithLocation(8, 28), // (11,41): warning CS8819: Nullability of reference types in return type doesn't match partial method declaration. // public partial IEnumerable<string?> M2() => null!; // 2 Diagnostic(ErrorCode.WRN_NullabilityMismatchInReturnTypeOnPartial, "M2").WithLocation(11, 41)); } [Fact, WorkItem(44930, "https://github.com/dotnet/roslyn/issues/44930")] public void DifferentReturnTypes_05() { var source = @" using System.Collections.Generic; class Base { } class Derived : Base { } partial class C { public partial Base M1(); public partial Derived M1() => new Derived(); // 1 public partial IEnumerable<Base> M2(); public partial IEnumerable<Derived> M2() => null!; // 2 }"; var comp = CreateCompilation(source, parseOptions: TestOptions.RegularWithExtendedPartialMethods); comp.VerifyDiagnostics( // (10,28): error CS8817: Both partial method declarations must have the same return type. // public partial Derived M1() => new Derived(); // 1 Diagnostic(ErrorCode.ERR_PartialMethodReturnTypeDifference, "M1").WithLocation(10, 28), // (13,41): error CS8817: Both partial method declarations must have the same return type. // public partial IEnumerable<Derived> M2() => null!; // 2 Diagnostic(ErrorCode.ERR_PartialMethodReturnTypeDifference, "M2").WithLocation(13, 41)); } [Fact, WorkItem(44930, "https://github.com/dotnet/roslyn/issues/44930")] public void DifferentReturnTypes_06() { var source = @" using System.Collections.Generic; class Base { } class Derived : Base { } partial class C { public partial Derived M1(); public partial Base M1() => new Base(); // 1 public partial IEnumerable<Derived> M2(); public partial IEnumerable<Base> M2() => null!; // 2 }"; var comp = CreateCompilation(source, parseOptions: TestOptions.RegularWithExtendedPartialMethods); comp.VerifyDiagnostics( // (10,25): error CS8817: Both partial method declarations must have the same return type. // public partial Base M1() => new Base(); // 1 Diagnostic(ErrorCode.ERR_PartialMethodReturnTypeDifference, "M1").WithLocation(10, 25), // (13,38): error CS8817: Both partial method declarations must have the same return type. // public partial IEnumerable<Base> M2() => null!; // 2 Diagnostic(ErrorCode.ERR_PartialMethodReturnTypeDifference, "M2").WithLocation(13, 38)); } [Fact, WorkItem(44930, "https://github.com/dotnet/roslyn/issues/44930")] public void DifferentReturnTypes_07() { var source = @" using System.Collections.Generic; partial class C { public partial U M1<U>(); public partial V M1<V>() => default; public partial IEnumerable<U> M2<U>(); public partial IEnumerable<U> M2<U>() => default; public partial U M3<U>(); public partial V M3<V>() => default; public partial IEnumerable<U> M4<U>(); public partial IEnumerable<V> M4<V>() => default; }"; var comp = CreateCompilation(source, parseOptions: TestOptions.RegularWithExtendedPartialMethods); comp.VerifyDiagnostics( // (7,22): warning CS8826: Partial method declarations 'U C.M1<U>()' and 'V C.M1<V>()' have signature differences. // public partial V M1<V>() => default; Diagnostic(ErrorCode.WRN_PartialMethodTypeDifference, "M1").WithArguments("U C.M1<U>()", "V C.M1<V>()").WithLocation(7, 22), // (13,22): warning CS8826: Partial method declarations 'U C.M3<U>()' and 'V C.M3<V>()' have signature differences. // public partial V M3<V>() => default; Diagnostic(ErrorCode.WRN_PartialMethodTypeDifference, "M3").WithArguments("U C.M3<U>()", "V C.M3<V>()").WithLocation(13, 22), // (16,35): warning CS8826: Partial method declarations 'IEnumerable<U> C.M4<U>()' and 'IEnumerable<V> C.M4<V>()' have signature differences. // public partial IEnumerable<V> M4<V>() => default; Diagnostic(ErrorCode.WRN_PartialMethodTypeDifference, "M4").WithArguments("IEnumerable<U> C.M4<U>()", "IEnumerable<V> C.M4<V>()").WithLocation(16, 35) ); } [Fact, WorkItem(44930, "https://github.com/dotnet/roslyn/issues/44930")] public void DifferentReturnTypes_08() { var source = @" using System.Collections.Generic; partial class C { public partial int M1(); public partial ERROR M1() => throw null!; // 1 public partial IEnumerable<int> M2(); public partial IEnumerable<ERROR> M2() => throw null!; // 2 public partial int M3(); public partial IEnumerable<ERROR> M3() => throw null!; // 3 public partial ERROR M4(); // 4 public partial int M4() => throw null!; public partial IEnumerable<ERROR> M5(); // 5 public partial IEnumerable<int> M5() => throw null!; public partial IEnumerable<ERROR> M6(); // 6 public partial int M6() => throw null!; public partial ERROR M7(); // 7 public partial ERROR M7() => throw null!; // 8 public partial IEnumerable<ERROR> M8(); // 9 public partial IEnumerable<ERROR> M8() => throw null!; // 10 }"; var comp = CreateCompilation(source, parseOptions: TestOptions.RegularWithExtendedPartialMethods); comp.VerifyDiagnostics( // (7,20): error CS0246: The type or namespace name 'ERROR' could not be found (are you missing a using directive or an assembly reference?) // public partial ERROR M1() => throw null!; // 1 Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "ERROR").WithArguments("ERROR").WithLocation(7, 20), // (7,26): error CS8817: Both partial method declarations must have the same return type. // public partial ERROR M1() => throw null!; // 1 Diagnostic(ErrorCode.ERR_PartialMethodReturnTypeDifference, "M1").WithLocation(7, 26), // (10,32): error CS0246: The type or namespace name 'ERROR' could not be found (are you missing a using directive or an assembly reference?) // public partial IEnumerable<ERROR> M2() => throw null!; // 2 Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "ERROR").WithArguments("ERROR").WithLocation(10, 32), // (10,39): error CS8817: Both partial method declarations must have the same return type. // public partial IEnumerable<ERROR> M2() => throw null!; // 2 Diagnostic(ErrorCode.ERR_PartialMethodReturnTypeDifference, "M2").WithLocation(10, 39), // (13,32): error CS0246: The type or namespace name 'ERROR' could not be found (are you missing a using directive or an assembly reference?) // public partial IEnumerable<ERROR> M3() => throw null!; // 3 Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "ERROR").WithArguments("ERROR").WithLocation(13, 32), // (13,39): error CS8817: Both partial method declarations must have the same return type. // public partial IEnumerable<ERROR> M3() => throw null!; // 3 Diagnostic(ErrorCode.ERR_PartialMethodReturnTypeDifference, "M3").WithLocation(13, 39), // (15,20): error CS0246: The type or namespace name 'ERROR' could not be found (are you missing a using directive or an assembly reference?) // public partial ERROR M4(); // 4 Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "ERROR").WithArguments("ERROR").WithLocation(15, 20), // (16,24): error CS8817: Both partial method declarations must have the same return type. // public partial int M4() => throw null!; Diagnostic(ErrorCode.ERR_PartialMethodReturnTypeDifference, "M4").WithLocation(16, 24), // (18,32): error CS0246: The type or namespace name 'ERROR' could not be found (are you missing a using directive or an assembly reference?) // public partial IEnumerable<ERROR> M5(); // 5 Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "ERROR").WithArguments("ERROR").WithLocation(18, 32), // (19,37): error CS8817: Both partial method declarations must have the same return type. // public partial IEnumerable<int> M5() => throw null!; Diagnostic(ErrorCode.ERR_PartialMethodReturnTypeDifference, "M5").WithLocation(19, 37), // (21,32): error CS0246: The type or namespace name 'ERROR' could not be found (are you missing a using directive or an assembly reference?) // public partial IEnumerable<ERROR> M6(); // 6 Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "ERROR").WithArguments("ERROR").WithLocation(21, 32), // (22,24): error CS8817: Both partial method declarations must have the same return type. // public partial int M6() => throw null!; Diagnostic(ErrorCode.ERR_PartialMethodReturnTypeDifference, "M6").WithLocation(22, 24), // (24,20): error CS0246: The type or namespace name 'ERROR' could not be found (are you missing a using directive or an assembly reference?) // public partial ERROR M7(); // 7 Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "ERROR").WithArguments("ERROR").WithLocation(24, 20), // (25,20): error CS0246: The type or namespace name 'ERROR' could not be found (are you missing a using directive or an assembly reference?) // public partial ERROR M7() => throw null!; // 8 Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "ERROR").WithArguments("ERROR").WithLocation(25, 20), // (27,32): error CS0246: The type or namespace name 'ERROR' could not be found (are you missing a using directive or an assembly reference?) // public partial IEnumerable<ERROR> M8(); // 9 Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "ERROR").WithArguments("ERROR").WithLocation(27, 32), // (28,32): error CS0246: The type or namespace name 'ERROR' could not be found (are you missing a using directive or an assembly reference?) // public partial IEnumerable<ERROR> M8() => throw null!; // 10 Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "ERROR").WithArguments("ERROR").WithLocation(28, 32)); } [Fact, WorkItem(44930, "https://github.com/dotnet/roslyn/issues/44930")] public void DifferentReturnTypes_09() { var source = @" partial class C { public partial ref int M1(); public partial int M1() => throw null!; // 1 public partial int M2(); public partial ref int M2() => throw null!; // 2 }"; var comp = CreateCompilation(source, parseOptions: TestOptions.RegularWithExtendedPartialMethods); comp.VerifyDiagnostics( // (5,24): error CS8818: Partial member declarations must have matching ref return values. // public partial int M1() => throw null!; // 1 Diagnostic(ErrorCode.ERR_PartialMemberRefReturnDifference, "M1").WithLocation(5, 24), // (5,24): warning CS8826: Partial method declarations 'ref int C.M1()' and 'int C.M1()' have signature differences. // public partial int M1() => throw null!; // 1 Diagnostic(ErrorCode.WRN_PartialMethodTypeDifference, "M1").WithArguments("ref int C.M1()", "int C.M1()").WithLocation(5, 24), // (8,28): error CS8818: Partial member declarations must have matching ref return values. // public partial ref int M2() => throw null!; // 2 Diagnostic(ErrorCode.ERR_PartialMemberRefReturnDifference, "M2").WithLocation(8, 28), // (8,28): warning CS8826: Partial method declarations 'int C.M2()' and 'ref int C.M2()' have signature differences. // public partial ref int M2() => throw null!; // 2 Diagnostic(ErrorCode.WRN_PartialMethodTypeDifference, "M2").WithArguments("int C.M2()", "ref int C.M2()").WithLocation(8, 28)); } [Fact, WorkItem(44930, "https://github.com/dotnet/roslyn/issues/44930")] public void DifferentReturnTypes_10() { var source = @" partial class C { public partial U M1<U>(); public partial U M1<U>() where U : struct => throw null!; // 1 public partial U M2<U>() where U : struct; public partial U M2<U>() => throw null!; // 2 }"; var comp = CreateCompilation(source, parseOptions: TestOptions.RegularWithExtendedPartialMethods); comp.VerifyDiagnostics( // (5,22): error CS0761: Partial method declarations of 'C.M1<U>()' have inconsistent constraints for type parameter 'U' // public partial U M1<U>() where U : struct => throw null!; // 1 Diagnostic(ErrorCode.ERR_PartialMethodInconsistentConstraints, "M1").WithArguments("C.M1<U>()", "U").WithLocation(5, 22), // (8,22): error CS0761: Partial method declarations of 'C.M2<U>()' have inconsistent constraints for type parameter 'U' // public partial U M2<U>() => throw null!; // 2 Diagnostic(ErrorCode.ERR_PartialMethodInconsistentConstraints, "M2").WithArguments("C.M2<U>()", "U").WithLocation(8, 22)); } [Fact, WorkItem(44930, "https://github.com/dotnet/roslyn/issues/44930")] public void DifferentReturnTypes_11() { var source = @" partial class C<T> { public partial T M1(); public partial T M2(); } partial class C<T> { public partial T M1() => throw null!; public partial T M2() => throw null!; }"; var comp = CreateCompilation(source, parseOptions: TestOptions.RegularWithExtendedPartialMethods); comp.VerifyDiagnostics(); } [Fact, WorkItem(44930, "https://github.com/dotnet/roslyn/issues/44930")] public void DifferentReturnTypes_12() { var source = @" partial class C { public partial (int x, int y) M1(); public partial (int x1, int y1) M1() => default; // 1 }"; var comp = CreateCompilation(source, parseOptions: TestOptions.RegularWithExtendedPartialMethods); comp.VerifyDiagnostics( // (5,37): error CS8142: Both partial member declarations, 'C.M1()' and 'C.M1()', must use the same tuple element names. // public partial (int x1, int y1) M1() => default; // 1 Diagnostic(ErrorCode.ERR_PartialMemberInconsistentTupleNames, "M1").WithArguments("C.M1()", "C.M1()").WithLocation(5, 37)); } [Fact, WorkItem(44930, "https://github.com/dotnet/roslyn/issues/44930")] public void DifferentReturnTypes_13() { var source = @" partial class C { public partial (int x, long y) M1(); public partial (long x, int y) M1() => default; // 1 }"; var comp = CreateCompilation(source, parseOptions: TestOptions.RegularWithExtendedPartialMethods); comp.VerifyDiagnostics( // (5,36): error CS8817: Both partial method declarations must have the same return type. // public partial (long x, int y) M1() => default; // 1 Diagnostic(ErrorCode.ERR_PartialMethodReturnTypeDifference, "M1").WithLocation(5, 36)); } [Fact, WorkItem(44930, "https://github.com/dotnet/roslyn/issues/44930")] public void DifferentReturnTypes_14() { var source = @" partial class C { public partial object M1(); public partial dynamic M1() => null; public partial dynamic M2(); public partial object M2() => null; }"; var comp = CreateCompilation(source, options: TestOptions.ReleaseDll.WithWarningLevel(5), parseOptions: TestOptions.RegularWithExtendedPartialMethods); comp.VerifyDiagnostics(); comp = CreateCompilation(source, options: TestOptions.ReleaseDll.WithWarningLevel(6), parseOptions: TestOptions.RegularWithExtendedPartialMethods); comp.VerifyDiagnostics( // (5,28): warning CS8826: Partial method declarations 'object C.M1()' and 'dynamic C.M1()' have signature differences. // public partial dynamic M1() => null; Diagnostic(ErrorCode.WRN_PartialMethodTypeDifference, "M1").WithArguments("object C.M1()", "dynamic C.M1()").WithLocation(5, 28), // (8,27): warning CS8826: Partial method declarations 'dynamic C.M2()' and 'object C.M2()' have signature differences. // public partial object M2() => null; Diagnostic(ErrorCode.WRN_PartialMethodTypeDifference, "M2").WithArguments("dynamic C.M2()", "object C.M2()").WithLocation(8, 27)); } [Fact, WorkItem(44930, "https://github.com/dotnet/roslyn/issues/44930")] public void DifferentReturnTypes_15() { var source = @" using System; partial class C { public partial IntPtr M1(); public partial nint M1() => 0; public partial nint M2(); public partial IntPtr M2() => default; }"; var comp = CreateCompilation(source, options: TestOptions.ReleaseDll.WithWarningLevel(5), parseOptions: TestOptions.RegularWithExtendedPartialMethods); comp.VerifyDiagnostics(); comp = CreateCompilation(source, options: TestOptions.ReleaseDll.WithWarningLevel(6), parseOptions: TestOptions.RegularWithExtendedPartialMethods); comp.VerifyDiagnostics( // (7,25): warning CS8826: Partial method declarations 'IntPtr C.M1()' and 'nint C.M1()' have signature differences. // public partial nint M1() => 0; Diagnostic(ErrorCode.WRN_PartialMethodTypeDifference, "M1").WithArguments("IntPtr C.M1()", "nint C.M1()").WithLocation(7, 25), // (10,27): warning CS8826: Partial method declarations 'nint C.M2()' and 'IntPtr C.M2()' have signature differences. // public partial IntPtr M2() => default; Diagnostic(ErrorCode.WRN_PartialMethodTypeDifference, "M2").WithArguments("nint C.M2()", "IntPtr C.M2()").WithLocation(10, 27)); } [Fact, WorkItem(44930, "https://github.com/dotnet/roslyn/issues/44930")] public void DifferentReturnTypes_16() { var source = @" partial class C { public partial ref int M1(); public partial ref readonly int M1() => throw null!; // 1 public partial ref readonly int M2(); public partial ref int M2() => throw null!; // 2 }"; var comp = CreateCompilation(source, parseOptions: TestOptions.RegularWithExtendedPartialMethods); comp.VerifyDiagnostics( // (5,37): error CS8818: Partial member declarations must have matching ref return values. // public partial ref readonly int M1() => throw null!; // 1 Diagnostic(ErrorCode.ERR_PartialMemberRefReturnDifference, "M1").WithLocation(5, 37), // (5,37): warning CS8826: Partial method declarations 'ref int C.M1()' and 'ref readonly int C.M1()' have signature differences. // public partial ref readonly int M1() => throw null!; // 1 Diagnostic(ErrorCode.WRN_PartialMethodTypeDifference, "M1").WithArguments("ref int C.M1()", "ref readonly int C.M1()").WithLocation(5, 37), // (8,28): error CS8818: Partial member declarations must have matching ref return values. // public partial ref int M2() => throw null!; // 2 Diagnostic(ErrorCode.ERR_PartialMemberRefReturnDifference, "M2").WithLocation(8, 28), // (8,28): warning CS8826: Partial method declarations 'ref readonly int C.M2()' and 'ref int C.M2()' have signature differences. // public partial ref int M2() => throw null!; // 2 Diagnostic(ErrorCode.WRN_PartialMethodTypeDifference, "M2").WithArguments("ref readonly int C.M2()", "ref int C.M2()").WithLocation(8, 28)); } [Fact, WorkItem(44930, "https://github.com/dotnet/roslyn/issues/44930")] public void DifferentReturnTypes_17() { var source = @" partial class C { #nullable enable public partial string M1(); public partial string? M1() => null; // 1 public partial string? M2(); public partial string M2() => ""hello""; // 2 #nullable disable public partial string M3(); public partial string? M3() => null; // 3 public partial string? M4(); // 4 public partial string M4() => ""hello""; #nullable enable public partial string M5(); public partial string M6() => null!; public partial string M7(); public partial string M8() => null!; // 5 public partial string? M9(); public partial string? M10() => null; public partial string? M11(); public partial string? M12() => null; #nullable disable public partial string M5() => null; public partial string M6(); public partial string? M7() => null; // 6 public partial string? M8(); // 7 public partial string M9() => null; public partial string M10(); public partial string? M11() => null; // 8 public partial string? M12(); // 9 }"; var comp = CreateCompilation(source, options: TestOptions.ReleaseDll.WithWarningLevel(5), parseOptions: TestOptions.RegularWithExtendedPartialMethods); comp.VerifyDiagnostics( // (6,28): warning CS8819: Nullability of reference types in return type doesn't match partial method declaration. // public partial string? M1() => null; // 1 Diagnostic(ErrorCode.WRN_NullabilityMismatchInReturnTypeOnPartial, "M1").WithLocation(6, 28), // (13,26): warning CS8632: The annotation for nullable reference types should only be used in code within a '#nullable' annotations context. // public partial string? M3() => null; // 3 Diagnostic(ErrorCode.WRN_MissingNonNullTypesContextForAnnotation, "?").WithLocation(13, 26), // (15,26): warning CS8632: The annotation for nullable reference types should only be used in code within a '#nullable' annotations context. // public partial string? M4(); // 4 Diagnostic(ErrorCode.WRN_MissingNonNullTypesContextForAnnotation, "?").WithLocation(15, 26), // (31,26): warning CS8632: The annotation for nullable reference types should only be used in code within a '#nullable' annotations context. // public partial string? M7() => null; // 6 Diagnostic(ErrorCode.WRN_MissingNonNullTypesContextForAnnotation, "?").WithLocation(31, 26), // (32,26): warning CS8632: The annotation for nullable reference types should only be used in code within a '#nullable' annotations context. // public partial string? M8(); // 7 Diagnostic(ErrorCode.WRN_MissingNonNullTypesContextForAnnotation, "?").WithLocation(32, 26), // (35,26): warning CS8632: The annotation for nullable reference types should only be used in code within a '#nullable' annotations context. // public partial string? M11() => null; // 8 Diagnostic(ErrorCode.WRN_MissingNonNullTypesContextForAnnotation, "?").WithLocation(35, 26), // (36,26): warning CS8632: The annotation for nullable reference types should only be used in code within a '#nullable' annotations context. // public partial string? M12(); // 9 Diagnostic(ErrorCode.WRN_MissingNonNullTypesContextForAnnotation, "?").WithLocation(36, 26)); comp = CreateCompilation(source, options: TestOptions.ReleaseDll.WithWarningLevel(6), parseOptions: TestOptions.RegularWithExtendedPartialMethods); comp.VerifyDiagnostics( // (6,28): warning CS8819: Nullability of reference types in return type doesn't match partial method declaration. // public partial string? M1() => null; // 1 Diagnostic(ErrorCode.WRN_NullabilityMismatchInReturnTypeOnPartial, "M1").WithLocation(6, 28), // (9,27): warning CS8826: Partial method declarations 'string? C.M2()' and 'string C.M2()' have signature differences. // public partial string M2() => "hello"; // 2 Diagnostic(ErrorCode.WRN_PartialMethodTypeDifference, "M2").WithArguments("string? C.M2()", "string C.M2()").WithLocation(9, 27), // (13,26): warning CS8632: The annotation for nullable reference types should only be used in code within a '#nullable' annotations context. // public partial string? M3() => null; // 3 Diagnostic(ErrorCode.WRN_MissingNonNullTypesContextForAnnotation, "?").WithLocation(13, 26), // (15,26): warning CS8632: The annotation for nullable reference types should only be used in code within a '#nullable' annotations context. // public partial string? M4(); // 4 Diagnostic(ErrorCode.WRN_MissingNonNullTypesContextForAnnotation, "?").WithLocation(15, 26), // (22,27): warning CS8826: Partial method declarations 'string? C.M8()' and 'string C.M8()' have signature differences. // public partial string M8() => null!; // 5 Diagnostic(ErrorCode.WRN_PartialMethodTypeDifference, "M8").WithArguments("string? C.M8()", "string C.M8()").WithLocation(22, 27), // (31,26): warning CS8632: The annotation for nullable reference types should only be used in code within a '#nullable' annotations context. // public partial string? M7() => null; // 6 Diagnostic(ErrorCode.WRN_MissingNonNullTypesContextForAnnotation, "?").WithLocation(31, 26), // (32,26): warning CS8632: The annotation for nullable reference types should only be used in code within a '#nullable' annotations context. // public partial string? M8(); // 7 Diagnostic(ErrorCode.WRN_MissingNonNullTypesContextForAnnotation, "?").WithLocation(32, 26), // (35,26): warning CS8632: The annotation for nullable reference types should only be used in code within a '#nullable' annotations context. // public partial string? M11() => null; // 8 Diagnostic(ErrorCode.WRN_MissingNonNullTypesContextForAnnotation, "?").WithLocation(35, 26), // (36,26): warning CS8632: The annotation for nullable reference types should only be used in code within a '#nullable' annotations context. // public partial string? M12(); // 9 Diagnostic(ErrorCode.WRN_MissingNonNullTypesContextForAnnotation, "?").WithLocation(36, 26)); } [Fact] public void DifferentReturnTypes_18() { var source = @"partial class C { public partial ref int F1(); public partial string F1() => null; }"; var comp = CreateCompilation(source, parseOptions: TestOptions.RegularWithExtendedPartialMethods); comp.VerifyDiagnostics( // (4,27): error CS8817: Both partial method declarations must have the same return type. // public partial string F1() => null; Diagnostic(ErrorCode.ERR_PartialMethodReturnTypeDifference, "F1").WithLocation(4, 27), // (4,27): error CS8818: Partial member declarations must have matching ref return values. // public partial string F1() => null; Diagnostic(ErrorCode.ERR_PartialMemberRefReturnDifference, "F1").WithLocation(4, 27)); } [Fact] public void DifferentReturnTypes_19() { var source = @"partial class C { public partial ref (int x, int y) F1(); public partial (int, int) F1() => default; }"; var comp = CreateCompilation(source, parseOptions: TestOptions.RegularWithExtendedPartialMethods); comp.VerifyDiagnostics( // (4,31): error CS8818: Partial member declarations must have matching ref return values. // public partial (int, int) F1() => default; Diagnostic(ErrorCode.ERR_PartialMemberRefReturnDifference, "F1").WithLocation(4, 31), // (4,31): warning CS8826: Partial method declarations 'ref (int x, int y) C.F1()' and '(int, int) C.F1()' have signature differences. // public partial (int, int) F1() => default; Diagnostic(ErrorCode.WRN_PartialMethodTypeDifference, "F1").WithArguments("ref (int x, int y) C.F1()", "(int, int) C.F1()").WithLocation(4, 31)); } [Fact] [WorkItem(45519, "https://github.com/dotnet/roslyn/issues/45519")] public void DifferentSignatures_Dynamic() { var source = @"partial class C { partial void F1(object o); partial void F1(dynamic o) { } // 1 internal partial void F2(object o); internal partial void F2(dynamic o) { } // 2 internal partial dynamic F3(); internal partial object F3() => null; // 3 }"; var comp = CreateCompilation(source, options: TestOptions.ReleaseDll.WithWarningLevel(5)); comp.VerifyDiagnostics(); comp = CreateCompilation(source, options: TestOptions.ReleaseDll.WithWarningLevel(6)); comp.VerifyDiagnostics( // (4,18): warning CS8826: Partial method declarations 'void C.F1(object o)' and 'void C.F1(dynamic o)' have signature differences. // partial void F1(dynamic o) { } // 1 Diagnostic(ErrorCode.WRN_PartialMethodTypeDifference, "F1", isSuppressed: false).WithArguments("void C.F1(object o)", "void C.F1(dynamic o)").WithLocation(4, 18), // (6,27): warning CS8826: Partial method declarations 'void C.F2(object o)' and 'void C.F2(dynamic o)' have signature differences. // internal partial void F2(dynamic o) { } // 2 Diagnostic(ErrorCode.WRN_PartialMethodTypeDifference, "F2", isSuppressed: false).WithArguments("void C.F2(object o)", "void C.F2(dynamic o)").WithLocation(6, 27), // (8,29): warning CS8826: Partial method declarations 'dynamic C.F3()' and 'object C.F3()' have signature differences. // internal partial object F3() => null; // 3 Diagnostic(ErrorCode.WRN_PartialMethodTypeDifference, "F3", isSuppressed: false).WithArguments("dynamic C.F3()", "object C.F3()").WithLocation(8, 29)); } [Fact] [WorkItem(45519, "https://github.com/dotnet/roslyn/issues/45519")] public void DifferentSignatures_Nullable() { var source = @"using System.Collections.Generic; #nullable enable partial class C { partial void F1(string? s); partial void F1(string s) { } // 1 partial void F2(IEnumerable<string?> s); partial void F2(IEnumerable<string> s) { } // 2 internal partial void F3(string? s); internal partial void F3(string s) { } // 3 internal partial void F4(IEnumerable<string?> s); internal partial void F4(IEnumerable<string> s) { } // 4 internal partial string? F5(); internal partial string F5() => null!; // 5 internal partial IEnumerable<string> F6(); internal partial IEnumerable<string?> F6() => null!; // 6 }"; var comp = CreateCompilation(source, options: TestOptions.ReleaseDll.WithWarningLevel(5)); comp.VerifyDiagnostics( // (6,18): warning CS8611: Nullability of reference types in type of parameter 's' doesn't match partial method declaration. // partial void F1(string s) { } // 1 Diagnostic(ErrorCode.WRN_NullabilityMismatchInParameterTypeOnPartial, "F1").WithArguments("s").WithLocation(6, 18), // (8,18): warning CS8611: Nullability of reference types in type of parameter 's' doesn't match partial method declaration. // partial void F2(IEnumerable<string> s) { } // 2 Diagnostic(ErrorCode.WRN_NullabilityMismatchInParameterTypeOnPartial, "F2").WithArguments("s").WithLocation(8, 18), // (10,27): warning CS8611: Nullability of reference types in type of parameter 's' doesn't match partial method declaration. // internal partial void F3(string s) { } // 3 Diagnostic(ErrorCode.WRN_NullabilityMismatchInParameterTypeOnPartial, "F3").WithArguments("s").WithLocation(10, 27), // (12,27): warning CS8611: Nullability of reference types in type of parameter 's' doesn't match partial method declaration. // internal partial void F4(IEnumerable<string> s) { } // 4 Diagnostic(ErrorCode.WRN_NullabilityMismatchInParameterTypeOnPartial, "F4").WithArguments("s").WithLocation(12, 27), // (16,43): warning CS8819: Nullability of reference types in return type doesn't match partial method declaration. // internal partial IEnumerable<string?> F6() => null!; // 6 Diagnostic(ErrorCode.WRN_NullabilityMismatchInReturnTypeOnPartial, "F6").WithLocation(16, 43)); comp = CreateCompilation(source, options: TestOptions.ReleaseDll.WithWarningLevel(6)); comp.VerifyDiagnostics( // (6,18): warning CS8611: Nullability of reference types in type of parameter 's' doesn't match partial method declaration. // partial void F1(string s) { } // 1 Diagnostic(ErrorCode.WRN_NullabilityMismatchInParameterTypeOnPartial, "F1").WithArguments("s").WithLocation(6, 18), // (8,18): warning CS8611: Nullability of reference types in type of parameter 's' doesn't match partial method declaration. // partial void F2(IEnumerable<string> s) { } // 2 Diagnostic(ErrorCode.WRN_NullabilityMismatchInParameterTypeOnPartial, "F2").WithArguments("s").WithLocation(8, 18), // (10,27): warning CS8611: Nullability of reference types in type of parameter 's' doesn't match partial method declaration. // internal partial void F3(string s) { } // 3 Diagnostic(ErrorCode.WRN_NullabilityMismatchInParameterTypeOnPartial, "F3").WithArguments("s").WithLocation(10, 27), // (12,27): warning CS8611: Nullability of reference types in type of parameter 's' doesn't match partial method declaration. // internal partial void F4(IEnumerable<string> s) { } // 4 Diagnostic(ErrorCode.WRN_NullabilityMismatchInParameterTypeOnPartial, "F4").WithArguments("s").WithLocation(12, 27), // (14,29): warning CS8826: Partial method declarations 'string? C.F5()' and 'string C.F5()' have signature differences. // internal partial string F5() => null!; // 5 Diagnostic(ErrorCode.WRN_PartialMethodTypeDifference, "F5").WithArguments("string? C.F5()", "string C.F5()").WithLocation(14, 29), // (16,43): warning CS8819: Nullability of reference types in return type doesn't match partial method declaration. // internal partial IEnumerable<string?> F6() => null!; // 6 Diagnostic(ErrorCode.WRN_NullabilityMismatchInReturnTypeOnPartial, "F6").WithLocation(16, 43)); } // Errors reported for all differences. [Fact] [WorkItem(45519, "https://github.com/dotnet/roslyn/issues/45519")] public void DifferentSignatures_Tuples() { var source = @"partial class C { partial void F1<T, U>((T x, U y) t) { } partial void F1<T, U>((T x, U y) t); partial void F2<T, U>((T x, U y) t) { } // 1 partial void F2<T, U>((T, U) t); partial void F3((dynamic, object) t); partial void F3((object x, dynamic y) t) { } // 2 internal partial void F4<T, U>((T x, U y) t); internal partial void F4<T, U>((T, U) t) { } // 3 internal partial (T, U) F5<T, U>() => default; internal partial (T, U) F5<T, U>(); internal partial (T, U) F6<T, U>() => default; // 4 internal partial (T x, U y) F6<T, U>(); }"; var comp = CreateCompilation(source, options: TestOptions.ReleaseDll.WithWarningLevel(5)); verifyDiagnostics(comp); comp = CreateCompilation(source, options: TestOptions.ReleaseDll.WithWarningLevel(6)); verifyDiagnostics(comp); static void verifyDiagnostics(CSharpCompilation comp) { comp.VerifyDiagnostics( // (5,18): error CS8142: Both partial member declarations, 'C.F2<T, U>((T, U))' and 'C.F2<T, U>((T x, U y))', must use the same tuple element names. // partial void F2<T, U>((T x, U y) t) { } // 1 Diagnostic(ErrorCode.ERR_PartialMemberInconsistentTupleNames, "F2").WithArguments("C.F2<T, U>((T, U))", "C.F2<T, U>((T x, U y))").WithLocation(5, 18), // (8,18): error CS8142: Both partial member declarations, 'C.F3((dynamic, object))' and 'C.F3((object x, dynamic y))', must use the same tuple element names. // partial void F3((object x, dynamic y) t) { } // 2 Diagnostic(ErrorCode.ERR_PartialMemberInconsistentTupleNames, "F3").WithArguments("C.F3((dynamic, object))", "C.F3((object x, dynamic y))").WithLocation(8, 18), // (10,27): error CS8142: Both partial member declarations, 'C.F4<T, U>((T x, U y))' and 'C.F4<T, U>((T, U))', must use the same tuple element names. // internal partial void F4<T, U>((T, U) t) { } // 3 Diagnostic(ErrorCode.ERR_PartialMemberInconsistentTupleNames, "F4").WithArguments("C.F4<T, U>((T x, U y))", "C.F4<T, U>((T, U))").WithLocation(10, 27), // (13,29): error CS8142: Both partial member declarations, 'C.F6<T, U>()' and 'C.F6<T, U>()', must use the same tuple element names. // internal partial (T, U) F6<T, U>() => default; // 4 Diagnostic(ErrorCode.ERR_PartialMemberInconsistentTupleNames, "F6").WithArguments("C.F6<T, U>()", "C.F6<T, U>()").WithLocation(13, 29)); } } [Fact] [WorkItem(45519, "https://github.com/dotnet/roslyn/issues/45519")] public void DifferentSignatures_NativeIntegers() { var source = @"using System.Collections.Generic; partial class C { partial void F1(nint i); partial void F1(System.IntPtr i) { } // 1 partial void F2(dynamic x, nint y); partial void F2(object x, System.IntPtr y) { } // 2 internal partial void F3(nint i); internal partial void F3(System.IntPtr i) { } // 3 internal partial IEnumerable<System.IntPtr> F4(); internal partial IEnumerable<nint> F4() => null; // 4 }"; var comp = CreateCompilation(source, options: TestOptions.ReleaseDll.WithWarningLevel(5)); comp.VerifyDiagnostics(); comp = CreateCompilation(source, options: TestOptions.ReleaseDll.WithWarningLevel(6)); comp.VerifyDiagnostics( // (5,18): warning CS8826: Partial method declarations 'void C.F1(nint i)' and 'void C.F1(IntPtr i)' have signature differences. // partial void F1(System.IntPtr i) { } // 1 Diagnostic(ErrorCode.WRN_PartialMethodTypeDifference, "F1").WithArguments("void C.F1(nint i)", "void C.F1(IntPtr i)").WithLocation(5, 18), // (7,18): warning CS8826: Partial method declarations 'void C.F2(dynamic x, nint y)' and 'void C.F2(object x, IntPtr y)' have signature differences. // partial void F2(object x, System.IntPtr y) { } // 2 Diagnostic(ErrorCode.WRN_PartialMethodTypeDifference, "F2").WithArguments("void C.F2(dynamic x, nint y)", "void C.F2(object x, IntPtr y)").WithLocation(7, 18), // (9,27): warning CS8826: Partial method declarations 'void C.F3(nint i)' and 'void C.F3(IntPtr i)' have signature differences. // internal partial void F3(System.IntPtr i) { } // 3 Diagnostic(ErrorCode.WRN_PartialMethodTypeDifference, "F3").WithArguments("void C.F3(nint i)", "void C.F3(IntPtr i)").WithLocation(9, 27), // (11,40): warning CS8826: Partial method declarations 'IEnumerable<IntPtr> C.F4()' and 'IEnumerable<nint> C.F4()' have signature differences. // internal partial IEnumerable<nint> F4() => null; // 4 Diagnostic(ErrorCode.WRN_PartialMethodTypeDifference, "F4").WithArguments("IEnumerable<IntPtr> C.F4()", "IEnumerable<nint> C.F4()").WithLocation(11, 40)); } [Fact] public void PublicAPI() { var source = @" #nullable enable partial class C { public partial string M1(); public partial string M1() => ""a""; partial void M2(); partial void M2() { } }"; var comp = CreateCompilation(source, parseOptions: TestOptions.RegularWithExtendedPartialMethods); comp.VerifyDiagnostics(); verifyPublicAPI(comp.GetMember<MethodSymbol>("C.M1").GetPublicSymbol()); verifyPublicAPI(comp.GetMember<MethodSymbol>("C.M2").GetPublicSymbol()); void verifyPublicAPI(IMethodSymbol defSymbol) { var implSymbol = defSymbol.PartialImplementationPart; Assert.NotNull(implSymbol); Assert.NotEqual(implSymbol, defSymbol); Assert.Null(defSymbol.PartialDefinitionPart); Assert.Null(implSymbol.PartialImplementationPart); Assert.Equal(implSymbol.PartialDefinitionPart, defSymbol); Assert.Equal(implSymbol.ToTestDisplayString(includeNonNullable: false), defSymbol.ToTestDisplayString(includeNonNullable: false)); } } } }