diff --git a/docs/compilers/CSharp/Compiler Breaking Changes - DotNet 10.md b/docs/compilers/CSharp/Compiler Breaking Changes - DotNet 10.md index 6075637771e03..b919a211cce5b 100644 --- a/docs/compilers/CSharp/Compiler Breaking Changes - DotNet 10.md +++ b/docs/compilers/CSharp/Compiler Breaking Changes - DotNet 10.md @@ -291,3 +291,20 @@ unsafe record struct R( public bool Equals(R other) => true; } ``` + +## `partial` cannot be a return type of methods + +***Introduced in Visual Studio 2022 version 17.14*** + +The [partial events and constructors](https://github.com/dotnet/csharplang/issues/9058) language feature +allows the `partial` modifier in more places and so it cannot be a return type unless escaped: + +```cs +class C +{ + partial F() => new partial(); // previously worked + @partial F() => new partial(); // workaround +} + +class partial { } +``` diff --git a/src/Compilers/CSharp/Portable/Errors/MessageID.cs b/src/Compilers/CSharp/Portable/Errors/MessageID.cs index 38c4399efd622..58a3aa1789e56 100644 --- a/src/Compilers/CSharp/Portable/Errors/MessageID.cs +++ b/src/Compilers/CSharp/Portable/Errors/MessageID.cs @@ -296,6 +296,8 @@ internal enum MessageID IDS_FeatureFirstClassSpan = MessageBase + 12849, IDS_FeatureUnboundGenericTypesInNameof = MessageBase + 12850, IDS_FeatureSimpleLambdaParameterModifiers = MessageBase + 12851, + + IDS_FeaturePartialEventsAndConstructors = MessageBase + 12852, } // Message IDs may refer to strings that need to be localized. @@ -480,6 +482,7 @@ internal static LanguageVersion RequiredVersion(this MessageID feature) case MessageID.IDS_FeatureFirstClassSpan: case MessageID.IDS_FeatureUnboundGenericTypesInNameof: case MessageID.IDS_FeatureSimpleLambdaParameterModifiers: + case MessageID.IDS_FeaturePartialEventsAndConstructors: return LanguageVersion.Preview; // C# 13.0 features. diff --git a/src/Compilers/CSharp/Portable/Parser/LanguageParser.cs b/src/Compilers/CSharp/Portable/Parser/LanguageParser.cs index 12f19f4de2626..05fa5bca1289f 100644 --- a/src/Compilers/CSharp/Portable/Parser/LanguageParser.cs +++ b/src/Compilers/CSharp/Portable/Parser/LanguageParser.cs @@ -1634,24 +1634,25 @@ private bool IsPartialType() private bool IsPartialMember() { - // note(cyrusn): this could have been written like so: - // - // return - // this.CurrentToken.ContextualKind == SyntaxKind.PartialKeyword && - // this.PeekToken(1).Kind == SyntaxKind.VoidKeyword; - // - // However, we want to be lenient and allow the user to write - // 'partial' in most modifier lists. We will then provide them with - // a more specific message later in binding that they are doing - // something wrong. - // - // Some might argue that the simple check would suffice. - // However, we'd like to maintain behavior with - // previously shipped versions, and so we're keeping this code. + Debug.Assert(this.CurrentToken.ContextualKind == SyntaxKind.PartialKeyword); + + // Check for: + // partial event + if (this.PeekToken(1).Kind == SyntaxKind.EventKeyword) + { + return true; + } + + // Check for constructor: + // partial Identifier( + if (this.PeekToken(1).Kind == SyntaxKind.IdentifierToken && + this.PeekToken(2).Kind == SyntaxKind.OpenParenToken) + { + return IsFeatureEnabled(MessageID.IDS_FeaturePartialEventsAndConstructors); + } - // Here we check for: + // Check for method/property: // partial ReturnType MemberName - Debug.Assert(this.CurrentToken.ContextualKind == SyntaxKind.PartialKeyword); using var _ = this.GetDisposableResetPoint(resetOnDispose: true); this.EatToken(); // partial @@ -5680,7 +5681,7 @@ private bool IsTrueIdentifier() { if (this.CurrentToken.Kind == SyntaxKind.IdentifierToken) { - if (!IsCurrentTokenPartialKeywordOfPartialMethodOrType() && + if (!IsCurrentTokenPartialKeywordOfPartialMemberOrType() && !IsCurrentTokenQueryKeywordInQuery() && !IsCurrentTokenWhereOfConstraintClause()) { @@ -5727,7 +5728,7 @@ private SyntaxToken ParseIdentifierToken(ErrorCode code = ErrorCode.ERR_Identifi // show the correct parameter help in this case. So, when we see "partial" we check if it's being used // as an identifier or as a contextual keyword. If it's the latter then we bail out. See // Bug: vswhidbey/542125 - if (IsCurrentTokenPartialKeywordOfPartialMethodOrType() || IsCurrentTokenQueryKeywordInQuery()) + if (IsCurrentTokenPartialKeywordOfPartialMemberOrType() || IsCurrentTokenQueryKeywordInQuery()) { var result = CreateMissingIdentifierToken(); result = this.AddError(result, ErrorCode.ERR_InvalidExprTerm, this.CurrentToken.Text); @@ -5754,7 +5755,7 @@ private bool IsCurrentTokenQueryKeywordInQuery() return this.IsInQuery && this.IsCurrentTokenQueryContextualKeyword; } - private bool IsCurrentTokenPartialKeywordOfPartialMethodOrType() + private bool IsCurrentTokenPartialKeywordOfPartialMemberOrType() { if (this.CurrentToken.ContextualKind == SyntaxKind.PartialKeyword) { diff --git a/src/Compilers/CSharp/Test/Emit3/PartialEventsAndConstructorsTests.cs b/src/Compilers/CSharp/Test/Emit3/PartialEventsAndConstructorsTests.cs new file mode 100644 index 0000000000000..a3a76c94790a7 --- /dev/null +++ b/src/Compilers/CSharp/Test/Emit3/PartialEventsAndConstructorsTests.cs @@ -0,0 +1,115 @@ +// 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. + +using Microsoft.CodeAnalysis.CSharp.Test.Utilities; +using Xunit; + +namespace Microsoft.CodeAnalysis.CSharp.UnitTests; + +public sealed class PartialEventsAndConstructorsTests : CSharpTestBase +{ + [Fact] + public void ReturningPartialType_LocalFunction_InMethod() + { + var source = """ + class @partial + { + static void Main() + { + System.Console.Write(F().GetType().Name); + partial F() => new(); + } + } + """; + CompileAndVerify(source, parseOptions: TestOptions.Regular13, expectedOutput: "partial").VerifyDiagnostics(); + + var expectedDiagnostics = new[] + { + // (5,30): error CS0103: The name 'F' does not exist in the current context + // System.Console.Write(F().GetType().Name); + Diagnostic(ErrorCode.ERR_NameNotInContext, "F").WithArguments("F").WithLocation(5, 30), + // (5,50): error CS1513: } expected + // System.Console.Write(F().GetType().Name); + Diagnostic(ErrorCode.ERR_RbraceExpected, "").WithLocation(5, 50), + // (6,9): error CS0267: The 'partial' modifier can only appear immediately before 'class', 'record', 'struct', 'interface', or a method or property return type. + // partial F() => new(); + Diagnostic(ErrorCode.ERR_PartialMisplaced, "partial").WithLocation(6, 9), + // (6,17): error CS1520: Method must have a return type + // partial F() => new(); + Diagnostic(ErrorCode.ERR_MemberNeedsType, "F").WithLocation(6, 17), + // (6,24): error CS0201: Only assignment, call, increment, decrement, await, and new object expressions can be used as a statement + // partial F() => new(); + Diagnostic(ErrorCode.ERR_IllegalStatement, "new()").WithLocation(6, 24), + // (8,1): error CS1022: Type or namespace definition, or end-of-file expected + // } + Diagnostic(ErrorCode.ERR_EOFExpected, "}").WithLocation(8, 1) + }; + + CreateCompilation(source, parseOptions: TestOptions.RegularNext).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(source).VerifyDiagnostics(expectedDiagnostics); + } + + [Fact] + public void ReturningPartialType_LocalFunction_TopLevel() + { + var source = """ + System.Console.Write(F().GetType().Name); + partial F() => new(); + class @partial; + """; + CompileAndVerify(source, parseOptions: TestOptions.Regular13, expectedOutput: "partial").VerifyDiagnostics(); + + var expectedDiagnostics = new[] + { + // (1,22): error CS0103: The name 'F' does not exist in the current context + // System.Console.Write(F().GetType().Name); + Diagnostic(ErrorCode.ERR_NameNotInContext, "F").WithArguments("F").WithLocation(1, 22), + // (2,9): error CS0116: A namespace cannot directly contain members such as fields, methods or statements + // partial F() => new(); + Diagnostic(ErrorCode.ERR_NamespaceUnexpected, "F").WithLocation(2, 9), + // (2,10): error CS0201: Only assignment, call, increment, decrement, await, and new object expressions can be used as a statement + // partial F() => new(); + Diagnostic(ErrorCode.ERR_IllegalStatement, "() => new()").WithLocation(2, 10) + }; + + CreateCompilation(source, parseOptions: TestOptions.RegularNext).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(source).VerifyDiagnostics(expectedDiagnostics); + } + + [Fact] + public void ReturningPartialType_Method() + { + var source = """ + class C + { + partial F() => new(); + static void Main() + { + System.Console.Write(new C().F().GetType().Name); + } + } + class @partial; + """; + CompileAndVerify(source, parseOptions: TestOptions.Regular13, expectedOutput: "partial").VerifyDiagnostics(); + + var expectedDiagnostics = new[] + { + // (3,5): error CS0267: The 'partial' modifier can only appear immediately before 'class', 'record', 'struct', 'interface', or a method or property return type. + // partial F() => new(); + Diagnostic(ErrorCode.ERR_PartialMisplaced, "partial").WithLocation(3, 5), + // (3,13): error CS1520: Method must have a return type + // partial F() => new(); + Diagnostic(ErrorCode.ERR_MemberNeedsType, "F").WithLocation(3, 13), + // (3,20): error CS0201: Only assignment, call, increment, decrement, await, and new object expressions can be used as a statement + // partial F() => new(); + Diagnostic(ErrorCode.ERR_IllegalStatement, "new()").WithLocation(3, 20), + // (6,38): error CS1061: 'C' does not contain a definition for 'F' and no accessible extension method 'F' accepting a first argument of type 'C' could be found (are you missing a using directive or an assembly reference?) + // System.Console.Write(new C().F().GetType().Name); + Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "F").WithArguments("C", "F").WithLocation(6, 38) + }; + + CreateCompilation(source, parseOptions: TestOptions.RegularNext).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(source).VerifyDiagnostics(expectedDiagnostics); + } +} diff --git a/src/Compilers/CSharp/Test/Symbol/Symbols/StaticAbstractMembersInInterfacesTests.cs b/src/Compilers/CSharp/Test/Symbol/Symbols/StaticAbstractMembersInInterfacesTests.cs index 9f2c305a4d345..3354802d99db8 100644 --- a/src/Compilers/CSharp/Test/Symbol/Symbols/StaticAbstractMembersInInterfacesTests.cs +++ b/src/Compilers/CSharp/Test/Symbol/Symbols/StaticAbstractMembersInInterfacesTests.cs @@ -901,48 +901,30 @@ sealed static partial I3() {} targetFramework: _supportingFramework); compilation1.VerifyDiagnostics( - // (4,19): error CS0246: The type or namespace name 'partial' could not be found (are you missing a using directive or an assembly reference?) + // (4,19): error CS0267: The 'partial' modifier can only appear immediately before 'class', 'record', 'struct', 'interface', or a method or property return type. // sealed static partial I2(); - Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "partial").WithArguments("partial").WithLocation(4, 19), - // (4,27): error CS0501: 'I2.I2()' must declare a body because it is not marked abstract, extern, or partial + Diagnostic(ErrorCode.ERR_PartialMisplaced, "partial").WithLocation(4, 19), + // (4,27): error CS0106: The modifier 'sealed' is not valid for this item // sealed static partial I2(); - Diagnostic(ErrorCode.ERR_ConcreteMissingBody, "I2").WithArguments("I2.I2()").WithLocation(4, 27), - // (4,27): error CS0542: 'I2': member names cannot be the same as their enclosing type - // sealed static partial I2(); - Diagnostic(ErrorCode.ERR_MemberNameSameAsType, "I2").WithArguments("I2").WithLocation(4, 27), - // (9,12): error CS0246: The type or namespace name 'partial' could not be found (are you missing a using directive or an assembly reference?) - // static partial I2() {} - Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "partial").WithArguments("partial").WithLocation(9, 12), - // (9,20): error CS0542: 'I2': member names cannot be the same as their enclosing type + Diagnostic(ErrorCode.ERR_BadMemberFlag, "I2").WithArguments("sealed").WithLocation(4, 27), + // (9,12): error CS0267: The 'partial' modifier can only appear immediately before 'class', 'record', 'struct', 'interface', or a method or property return type. // static partial I2() {} - Diagnostic(ErrorCode.ERR_MemberNameSameAsType, "I2").WithArguments("I2").WithLocation(9, 20), + Diagnostic(ErrorCode.ERR_PartialMisplaced, "partial").WithLocation(9, 12), // (9,20): error CS0111: Type 'I2' already defines a member called 'I2' with the same parameter types // static partial I2() {} Diagnostic(ErrorCode.ERR_MemberAlreadyExists, "I2").WithArguments("I2", "I2").WithLocation(9, 20), - // (9,20): error CS0161: 'I2.I2()': not all code paths return a value - // static partial I2() {} - Diagnostic(ErrorCode.ERR_ReturnExpected, "I2").WithArguments("I2.I2()").WithLocation(9, 20), - // (14,12): error CS0246: The type or namespace name 'partial' could not be found (are you missing a using directive or an assembly reference?) + // (14,12): error CS0267: The 'partial' modifier can only appear immediately before 'class', 'record', 'struct', 'interface', or a method or property return type. // static partial I3(); - Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "partial").WithArguments("partial").WithLocation(14, 12), - // (14,20): error CS0501: 'I3.I3()' must declare a body because it is not marked abstract, extern, or partial - // static partial I3(); - Diagnostic(ErrorCode.ERR_ConcreteMissingBody, "I3").WithArguments("I3.I3()").WithLocation(14, 20), - // (14,20): error CS0542: 'I3': member names cannot be the same as their enclosing type - // static partial I3(); - Diagnostic(ErrorCode.ERR_MemberNameSameAsType, "I3").WithArguments("I3").WithLocation(14, 20), - // (19,19): error CS0246: The type or namespace name 'partial' could not be found (are you missing a using directive or an assembly reference?) + Diagnostic(ErrorCode.ERR_PartialMisplaced, "partial").WithLocation(14, 12), + // (19,19): error CS0267: The 'partial' modifier can only appear immediately before 'class', 'record', 'struct', 'interface', or a method or property return type. // sealed static partial I3() {} - Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "partial").WithArguments("partial").WithLocation(19, 19), - // (19,27): error CS0542: 'I3': member names cannot be the same as their enclosing type + Diagnostic(ErrorCode.ERR_PartialMisplaced, "partial").WithLocation(19, 19), + // (19,27): error CS0106: The modifier 'sealed' is not valid for this item // sealed static partial I3() {} - Diagnostic(ErrorCode.ERR_MemberNameSameAsType, "I3").WithArguments("I3").WithLocation(19, 27), + Diagnostic(ErrorCode.ERR_BadMemberFlag, "I3").WithArguments("sealed").WithLocation(19, 27), // (19,27): error CS0111: Type 'I3' already defines a member called 'I3' with the same parameter types // sealed static partial I3() {} - Diagnostic(ErrorCode.ERR_MemberAlreadyExists, "I3").WithArguments("I3", "I3").WithLocation(19, 27), - // (19,27): error CS0161: 'I3.I3()': not all code paths return a value - // sealed static partial I3() {} - Diagnostic(ErrorCode.ERR_ReturnExpected, "I3").WithArguments("I3.I3()").WithLocation(19, 27) + Diagnostic(ErrorCode.ERR_MemberAlreadyExists, "I3").WithArguments("I3", "I3").WithLocation(19, 27) ); } diff --git a/src/Compilers/CSharp/Test/Symbol/Symbols/SymbolErrorTests.cs b/src/Compilers/CSharp/Test/Symbol/Symbols/SymbolErrorTests.cs index ba8f6bcd8ae5a..5be5485639018 100644 --- a/src/Compilers/CSharp/Test/Symbol/Symbols/SymbolErrorTests.cs +++ b/src/Compilers/CSharp/Test/Symbol/Symbols/SymbolErrorTests.cs @@ -22115,6 +22115,7 @@ string featureName [Fact] public void PartialConstructor() { + // PROTOTYPE: some of these should be allowed CreateCompilation(new[] { """ @@ -22136,30 +22137,18 @@ partial public PartialPublicCtor() { } } """ }).VerifyDiagnostics( - // (3,5): error CS0267: The 'partial' modifier can only appear immediately before 'class', 'record', 'struct', 'interface', or a method return type. + // 0.cs(3,5): error CS0267: The 'partial' modifier can only appear immediately before 'class', 'record', 'struct', 'interface', or a method or property return type. + // partial PartialCtor() { } + Diagnostic(ErrorCode.ERR_PartialMisplaced, "partial").WithLocation(3, 5), + // 2.cs(3,5): error CS0267: The 'partial' modifier can only appear immediately before 'class', 'record', 'struct', 'interface', or a method or property return type. // partial public PartialPublicCtor() { } Diagnostic(ErrorCode.ERR_PartialMisplaced, "partial").WithLocation(3, 5), - // (3,5): error CS0267: The 'partial' modifier can only appear immediately before 'class', 'record', 'struct', 'interface', or a method return type. + // 2.cs(3,5): error CS0267: The 'partial' modifier can only appear immediately before 'class', 'record', 'struct', 'interface', or a method or property return type. // partial public PartialPublicCtor() { } Diagnostic(ErrorCode.ERR_PartialMisplaced, "partial").WithLocation(3, 5), - // (3,5): error CS0246: The type or namespace name 'partial' could not be found (are you missing a using directive or an assembly reference?) - // partial PartialCtor() { } - Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "partial").WithArguments("partial").WithLocation(3, 5), - // (3,12): error CS0246: The type or namespace name 'partial' could not be found (are you missing a using directive or an assembly reference?) - // public partial PublicPartialCtor() { } - Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "partial").WithArguments("partial").WithLocation(3, 12), - // (3,13): error CS0542: 'PartialCtor': member names cannot be the same as their enclosing type - // partial PartialCtor() { } - Diagnostic(ErrorCode.ERR_MemberNameSameAsType, "PartialCtor").WithArguments("PartialCtor").WithLocation(3, 13), - // (3,13): error CS0161: 'PartialCtor.PartialCtor()': not all code paths return a value - // partial PartialCtor() { } - Diagnostic(ErrorCode.ERR_ReturnExpected, "PartialCtor").WithArguments("PartialCtor.PartialCtor()").WithLocation(3, 13), - // (3,20): error CS0542: 'PublicPartialCtor': member names cannot be the same as their enclosing type + // 1.cs(3,12): error CS0267: The 'partial' modifier can only appear immediately before 'class', 'record', 'struct', 'interface', or a method or property return type. // public partial PublicPartialCtor() { } - Diagnostic(ErrorCode.ERR_MemberNameSameAsType, "PublicPartialCtor").WithArguments("PublicPartialCtor").WithLocation(3, 20), - // (3,20): error CS0161: 'PublicPartialCtor.PublicPartialCtor()': not all code paths return a value - // public partial PublicPartialCtor() { } - Diagnostic(ErrorCode.ERR_ReturnExpected, "PublicPartialCtor").WithArguments("PublicPartialCtor.PublicPartialCtor()").WithLocation(3, 20)); + Diagnostic(ErrorCode.ERR_PartialMisplaced, "partial").WithLocation(3, 12)); } [Fact] @@ -22216,75 +22205,63 @@ partial public static PartialPublicStaticCtor() { } } """, }).VerifyDiagnostics( - // (3,5): error CS0267: The 'partial' modifier can only appear immediately before 'class', 'record', 'struct', 'interface', or a method return type. + // 0.cs(3,5): error CS0267: The 'partial' modifier can only appear immediately before 'class', 'record', 'struct', 'interface', or a method or property return type. // partial static PartialStaticCtor() { } Diagnostic(ErrorCode.ERR_PartialMisplaced, "partial").WithLocation(3, 5), - // (3,5): error CS0267: The 'partial' modifier can only appear immediately before 'class', 'record', 'struct', 'interface', or a method return type. + // 0.cs(3,5): error CS0267: The 'partial' modifier can only appear immediately before 'class', 'record', 'struct', 'interface', or a method or property return type. // partial static PartialStaticCtor() { } Diagnostic(ErrorCode.ERR_PartialMisplaced, "partial").WithLocation(3, 5), - // (3,5): error CS0267: The 'partial' modifier can only appear immediately before 'class', 'record', 'struct', 'interface', or a method return type. + // 7.cs(3,5): error CS0267: The 'partial' modifier can only appear immediately before 'class', 'record', 'struct', 'interface', or a method or property return type. // partial public static PartialPublicStaticCtor() { } Diagnostic(ErrorCode.ERR_PartialMisplaced, "partial").WithLocation(3, 5), - // (3,5): error CS0267: The 'partial' modifier can only appear immediately before 'class', 'record', 'struct', 'interface', or a method return type. + // 7.cs(3,5): error CS0267: The 'partial' modifier can only appear immediately before 'class', 'record', 'struct', 'interface', or a method or property return type. // partial public static PartialPublicStaticCtor() { } Diagnostic(ErrorCode.ERR_PartialMisplaced, "partial").WithLocation(3, 5), - // (3,5): error CS0267: The 'partial' modifier can only appear immediately before 'class', 'record', 'struct', 'interface', or a method return type. + // 6.cs(3,5): error CS0267: The 'partial' modifier can only appear immediately before 'class', 'record', 'struct', 'interface', or a method or property return type. // partial static public PartialStaticPublicCtor() { } Diagnostic(ErrorCode.ERR_PartialMisplaced, "partial").WithLocation(3, 5), - // (3,5): error CS0267: The 'partial' modifier can only appear immediately before 'class', 'record', 'struct', 'interface', or a method return type. + // 6.cs(3,5): error CS0267: The 'partial' modifier can only appear immediately before 'class', 'record', 'struct', 'interface', or a method or property return type. // partial static public PartialStaticPublicCtor() { } Diagnostic(ErrorCode.ERR_PartialMisplaced, "partial").WithLocation(3, 5), - // (3,12): error CS0267: The 'partial' modifier can only appear immediately before 'class', 'record', 'struct', 'interface', or a method return type. - // public partial static PublicPartialStaticCtor() { } - Diagnostic(ErrorCode.ERR_PartialMisplaced, "partial").WithLocation(3, 12), - // (3,12): error CS0267: The 'partial' modifier can only appear immediately before 'class', 'record', 'struct', 'interface', or a method return type. - // public partial static PublicPartialStaticCtor() { } + // 1.cs(3,12): error CS0267: The 'partial' modifier can only appear immediately before 'class', 'record', 'struct', 'interface', or a method or property return type. + // static partial StaticPartialCtor() { } Diagnostic(ErrorCode.ERR_PartialMisplaced, "partial").WithLocation(3, 12), - // (3,12): error CS0267: The 'partial' modifier can only appear immediately before 'class', 'record', 'struct', 'interface', or a method return type. + // 5.cs(3,12): error CS0267: The 'partial' modifier can only appear immediately before 'class', 'record', 'struct', 'interface', or a method or property return type. // static partial public StaticPartialPublicCtor() { } Diagnostic(ErrorCode.ERR_PartialMisplaced, "partial").WithLocation(3, 12), - // (3,12): error CS0267: The 'partial' modifier can only appear immediately before 'class', 'record', 'struct', 'interface', or a method return type. + // 5.cs(3,12): error CS0267: The 'partial' modifier can only appear immediately before 'class', 'record', 'struct', 'interface', or a method or property return type. // static partial public StaticPartialPublicCtor() { } Diagnostic(ErrorCode.ERR_PartialMisplaced, "partial").WithLocation(3, 12), - // (3,12): error CS0246: The type or namespace name 'partial' could not be found (are you missing a using directive or an assembly reference?) - // static partial StaticPartialCtor() { } - Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "partial").WithArguments("partial").WithLocation(3, 12), - // (3,19): error CS0246: The type or namespace name 'partial' could not be found (are you missing a using directive or an assembly reference?) + // 3.cs(3,12): error CS0267: The 'partial' modifier can only appear immediately before 'class', 'record', 'struct', 'interface', or a method or property return type. + // public partial static PublicPartialStaticCtor() { } + Diagnostic(ErrorCode.ERR_PartialMisplaced, "partial").WithLocation(3, 12), + // 3.cs(3,12): error CS0267: The 'partial' modifier can only appear immediately before 'class', 'record', 'struct', 'interface', or a method or property return type. + // public partial static PublicPartialStaticCtor() { } + Diagnostic(ErrorCode.ERR_PartialMisplaced, "partial").WithLocation(3, 12), + // 4.cs(3,19): error CS0267: The 'partial' modifier can only appear immediately before 'class', 'record', 'struct', 'interface', or a method or property return type. + // static public partial StaticPublicPartialCtor() { } + Diagnostic(ErrorCode.ERR_PartialMisplaced, "partial").WithLocation(3, 19), + // 2.cs(3,19): error CS0267: The 'partial' modifier can only appear immediately before 'class', 'record', 'struct', 'interface', or a method or property return type. // public static partial PublicStaticPartialCtor() { } - Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "partial").WithArguments("partial").WithLocation(3, 19), - // (3,19): error CS0246: The type or namespace name 'partial' could not be found (are you missing a using directive or an assembly reference?) + Diagnostic(ErrorCode.ERR_PartialMisplaced, "partial").WithLocation(3, 19), + // 4.cs(3,27): error CS0515: 'StaticPublicPartialCtor.StaticPublicPartialCtor()': access modifiers are not allowed on static constructors // static public partial StaticPublicPartialCtor() { } - Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "partial").WithArguments("partial").WithLocation(3, 19), - // (3,20): error CS0542: 'StaticPartialCtor': member names cannot be the same as their enclosing type - // static partial StaticPartialCtor() { } - Diagnostic(ErrorCode.ERR_MemberNameSameAsType, "StaticPartialCtor").WithArguments("StaticPartialCtor").WithLocation(3, 20), - // (3,20): error CS0161: 'StaticPartialCtor.StaticPartialCtor()': not all code paths return a value - // static partial StaticPartialCtor() { } - Diagnostic(ErrorCode.ERR_ReturnExpected, "StaticPartialCtor").WithArguments("StaticPartialCtor.StaticPartialCtor()").WithLocation(3, 20), - // (3,27): error CS0515: 'PartialPublicStaticCtor.PartialPublicStaticCtor()': access modifiers are not allowed on static constructors + Diagnostic(ErrorCode.ERR_StaticConstructorWithAccessModifiers, "StaticPublicPartialCtor").WithArguments("StaticPublicPartialCtor.StaticPublicPartialCtor()").WithLocation(3, 27), + // 7.cs(3,27): error CS0515: 'PartialPublicStaticCtor.PartialPublicStaticCtor()': access modifiers are not allowed on static constructors // partial public static PartialPublicStaticCtor() { } Diagnostic(ErrorCode.ERR_StaticConstructorWithAccessModifiers, "PartialPublicStaticCtor").WithArguments("PartialPublicStaticCtor.PartialPublicStaticCtor()").WithLocation(3, 27), - // (3,27): error CS0515: 'PublicPartialStaticCtor.PublicPartialStaticCtor()': access modifiers are not allowed on static constructors - // public partial static PublicPartialStaticCtor() { } - Diagnostic(ErrorCode.ERR_StaticConstructorWithAccessModifiers, "PublicPartialStaticCtor").WithArguments("PublicPartialStaticCtor.PublicPartialStaticCtor()").WithLocation(3, 27), - // (3,27): error CS0515: 'StaticPartialPublicCtor.StaticPartialPublicCtor()': access modifiers are not allowed on static constructors - // static partial public StaticPartialPublicCtor() { } - Diagnostic(ErrorCode.ERR_StaticConstructorWithAccessModifiers, "StaticPartialPublicCtor").WithArguments("StaticPartialPublicCtor.StaticPartialPublicCtor()").WithLocation(3, 27), - // (3,27): error CS0515: 'PartialStaticPublicCtor.PartialStaticPublicCtor()': access modifiers are not allowed on static constructors + // 6.cs(3,27): error CS0515: 'PartialStaticPublicCtor.PartialStaticPublicCtor()': access modifiers are not allowed on static constructors // partial static public PartialStaticPublicCtor() { } Diagnostic(ErrorCode.ERR_StaticConstructorWithAccessModifiers, "PartialStaticPublicCtor").WithArguments("PartialStaticPublicCtor.PartialStaticPublicCtor()").WithLocation(3, 27), - // (3,27): error CS0542: 'StaticPublicPartialCtor': member names cannot be the same as their enclosing type - // static public partial StaticPublicPartialCtor() { } - Diagnostic(ErrorCode.ERR_MemberNameSameAsType, "StaticPublicPartialCtor").WithArguments("StaticPublicPartialCtor").WithLocation(3, 27), - // (3,27): error CS0542: 'PublicStaticPartialCtor': member names cannot be the same as their enclosing type - // public static partial PublicStaticPartialCtor() { } - Diagnostic(ErrorCode.ERR_MemberNameSameAsType, "PublicStaticPartialCtor").WithArguments("PublicStaticPartialCtor").WithLocation(3, 27), - // (3,27): error CS0161: 'StaticPublicPartialCtor.StaticPublicPartialCtor()': not all code paths return a value - // static public partial StaticPublicPartialCtor() { } - Diagnostic(ErrorCode.ERR_ReturnExpected, "StaticPublicPartialCtor").WithArguments("StaticPublicPartialCtor.StaticPublicPartialCtor()").WithLocation(3, 27), - // (3,27): error CS0161: 'PublicStaticPartialCtor.PublicStaticPartialCtor()': not all code paths return a value + // 5.cs(3,27): error CS0515: 'StaticPartialPublicCtor.StaticPartialPublicCtor()': access modifiers are not allowed on static constructors + // static partial public StaticPartialPublicCtor() { } + Diagnostic(ErrorCode.ERR_StaticConstructorWithAccessModifiers, "StaticPartialPublicCtor").WithArguments("StaticPartialPublicCtor.StaticPartialPublicCtor()").WithLocation(3, 27), + // 3.cs(3,27): error CS0515: 'PublicPartialStaticCtor.PublicPartialStaticCtor()': access modifiers are not allowed on static constructors + // public partial static PublicPartialStaticCtor() { } + Diagnostic(ErrorCode.ERR_StaticConstructorWithAccessModifiers, "PublicPartialStaticCtor").WithArguments("PublicPartialStaticCtor.PublicPartialStaticCtor()").WithLocation(3, 27), + // 2.cs(3,27): error CS0515: 'PublicStaticPartialCtor.PublicStaticPartialCtor()': access modifiers are not allowed on static constructors // public static partial PublicStaticPartialCtor() { } - Diagnostic(ErrorCode.ERR_ReturnExpected, "PublicStaticPartialCtor").WithArguments("PublicStaticPartialCtor.PublicStaticPartialCtor()").WithLocation(3, 27)); + Diagnostic(ErrorCode.ERR_StaticConstructorWithAccessModifiers, "PublicStaticPartialCtor").WithArguments("PublicStaticPartialCtor.PublicStaticPartialCtor()").WithLocation(3, 27)); } } } diff --git a/src/Compilers/CSharp/Test/Syntax/Parsing/AsyncParsingTests.cs b/src/Compilers/CSharp/Test/Syntax/Parsing/AsyncParsingTests.cs index 563f7e270746e..b99cf257d1a95 100644 --- a/src/Compilers/CSharp/Test/Syntax/Parsing/AsyncParsingTests.cs +++ b/src/Compilers/CSharp/Test/Syntax/Parsing/AsyncParsingTests.cs @@ -1567,9 +1567,6 @@ class C { async partial event ", - // (4,19): error CS1519: Invalid token 'event' in class, record, struct, or interface member declaration - // async partial event - Diagnostic(ErrorCode.ERR_InvalidMemberDecl, "event").WithArguments("event").WithLocation(4, 19), // (4,24): error CS1031: Type expected // async partial event Diagnostic(ErrorCode.ERR_TypeExpected, "").WithLocation(4, 24), @@ -1589,16 +1586,10 @@ async partial event N(SyntaxKind.ClassKeyword); N(SyntaxKind.IdentifierToken, "C"); N(SyntaxKind.OpenBraceToken); - N(SyntaxKind.IncompleteMember); - { - N(SyntaxKind.AsyncKeyword); - N(SyntaxKind.IdentifierName); - { - N(SyntaxKind.IdentifierToken, "partial"); - } - } N(SyntaxKind.EventDeclaration); { + N(SyntaxKind.AsyncKeyword); + N(SyntaxKind.PartialKeyword); N(SyntaxKind.EventKeyword); M(SyntaxKind.IdentifierName); { diff --git a/src/Compilers/CSharp/Test/Syntax/Parsing/PartialEventsAndConstructorsParsingTests.cs b/src/Compilers/CSharp/Test/Syntax/Parsing/PartialEventsAndConstructorsParsingTests.cs new file mode 100644 index 0000000000000..62eb5c4c8a0cd --- /dev/null +++ b/src/Compilers/CSharp/Test/Syntax/Parsing/PartialEventsAndConstructorsParsingTests.cs @@ -0,0 +1,1528 @@ +// 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. + +using Microsoft.CodeAnalysis.CSharp.Test.Utilities; +using Xunit; +using Xunit.Abstractions; + +namespace Microsoft.CodeAnalysis.CSharp.UnitTests; + +public sealed class PartialEventsAndConstructorsParsingTests(ITestOutputHelper output) : ParsingTests(output) +{ + private sealed class CSharp14_Preview() + : CombinatorialValuesAttribute(LanguageVersionFacts.CSharpNext, LanguageVersion.Preview); + + private sealed class CSharp13_CSharp14_Preview() + : CombinatorialValuesAttribute(LanguageVersion.CSharp13, LanguageVersionFacts.CSharpNext, LanguageVersion.Preview); + + [Theory, CombinatorialData] + public void Event_Tree([CSharp14_Preview] LanguageVersion langVersion) + { + UsingTree(""" + partial class C + { + partial event Action E; + partial event Action E { add { } remove { } } + } + """, + TestOptions.Regular.WithLanguageVersion(langVersion)); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.PartialKeyword); + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.EventFieldDeclaration); + { + N(SyntaxKind.PartialKeyword); + N(SyntaxKind.EventKeyword); + N(SyntaxKind.VariableDeclaration); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Action"); + } + N(SyntaxKind.VariableDeclarator); + { + N(SyntaxKind.IdentifierToken, "E"); + } + } + N(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.EventDeclaration); + { + N(SyntaxKind.PartialKeyword); + N(SyntaxKind.EventKeyword); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Action"); + } + N(SyntaxKind.IdentifierToken, "E"); + N(SyntaxKind.AccessorList); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.AddAccessorDeclaration); + { + N(SyntaxKind.AddKeyword); + N(SyntaxKind.Block); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + } + N(SyntaxKind.RemoveAccessorDeclaration); + { + N(SyntaxKind.RemoveKeyword); + N(SyntaxKind.Block); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + } + N(SyntaxKind.CloseBraceToken); + } + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Theory, CombinatorialData] + public void Event_Definition([CSharp13_CSharp14_Preview] LanguageVersion langVersion) + { + UsingDeclaration(""" + partial event Action E; + """, + TestOptions.Regular.WithLanguageVersion(langVersion)); + + N(SyntaxKind.EventFieldDeclaration); + { + N(SyntaxKind.PartialKeyword); + N(SyntaxKind.EventKeyword); + N(SyntaxKind.VariableDeclaration); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Action"); + } + N(SyntaxKind.VariableDeclarator); + { + N(SyntaxKind.IdentifierToken, "E"); + } + } + N(SyntaxKind.SemicolonToken); + } + EOF(); + } + + [Theory, CombinatorialData] + public void Event_Definition_Multiple([CSharp14_Preview] LanguageVersion langVersion) + { + UsingDeclaration(""" + partial event Action E, F; + """, + TestOptions.Regular.WithLanguageVersion(langVersion)); + + N(SyntaxKind.EventFieldDeclaration); + { + N(SyntaxKind.PartialKeyword); + N(SyntaxKind.EventKeyword); + N(SyntaxKind.VariableDeclaration); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Action"); + } + N(SyntaxKind.VariableDeclarator); + { + N(SyntaxKind.IdentifierToken, "E"); + } + N(SyntaxKind.CommaToken); + N(SyntaxKind.VariableDeclarator); + { + N(SyntaxKind.IdentifierToken, "F"); + } + } + N(SyntaxKind.SemicolonToken); + } + EOF(); + } + + [Theory, CombinatorialData] + public void Event_Definition_Initializer([CSharp14_Preview] LanguageVersion langVersion) + { + UsingDeclaration(""" + partial event Action E = null; + """, + TestOptions.Regular.WithLanguageVersion(langVersion)); + + N(SyntaxKind.EventFieldDeclaration); + { + N(SyntaxKind.PartialKeyword); + N(SyntaxKind.EventKeyword); + N(SyntaxKind.VariableDeclaration); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Action"); + } + N(SyntaxKind.VariableDeclarator); + { + N(SyntaxKind.IdentifierToken, "E"); + N(SyntaxKind.EqualsValueClause); + { + N(SyntaxKind.EqualsToken); + N(SyntaxKind.NullLiteralExpression); + { + N(SyntaxKind.NullKeyword); + } + } + } + } + N(SyntaxKind.SemicolonToken); + } + EOF(); + } + + [Theory, CombinatorialData] + public void Event_Definition_Multiple_Initializer([CSharp14_Preview] LanguageVersion langVersion) + { + UsingDeclaration(""" + partial event Action E, F = null; + """, + TestOptions.Regular.WithLanguageVersion(langVersion)); + + N(SyntaxKind.EventFieldDeclaration); + { + N(SyntaxKind.PartialKeyword); + N(SyntaxKind.EventKeyword); + N(SyntaxKind.VariableDeclaration); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Action"); + } + N(SyntaxKind.VariableDeclarator); + { + N(SyntaxKind.IdentifierToken, "E"); + } + N(SyntaxKind.CommaToken); + N(SyntaxKind.VariableDeclarator); + { + N(SyntaxKind.IdentifierToken, "F"); + N(SyntaxKind.EqualsValueClause); + { + N(SyntaxKind.EqualsToken); + N(SyntaxKind.NullLiteralExpression); + { + N(SyntaxKind.NullKeyword); + } + } + } + } + N(SyntaxKind.SemicolonToken); + } + EOF(); + } + + [Theory, CombinatorialData] + public void Event_Definition_Multiple_Initializers([CSharp14_Preview] LanguageVersion langVersion) + { + UsingDeclaration(""" + partial event Action E = null, F = null; + """, + TestOptions.Regular.WithLanguageVersion(langVersion)); + + N(SyntaxKind.EventFieldDeclaration); + { + N(SyntaxKind.PartialKeyword); + N(SyntaxKind.EventKeyword); + N(SyntaxKind.VariableDeclaration); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Action"); + } + N(SyntaxKind.VariableDeclarator); + { + N(SyntaxKind.IdentifierToken, "E"); + N(SyntaxKind.EqualsValueClause); + { + N(SyntaxKind.EqualsToken); + N(SyntaxKind.NullLiteralExpression); + { + N(SyntaxKind.NullKeyword); + } + } + } + N(SyntaxKind.CommaToken); + N(SyntaxKind.VariableDeclarator); + { + N(SyntaxKind.IdentifierToken, "F"); + N(SyntaxKind.EqualsValueClause); + { + N(SyntaxKind.EqualsToken); + N(SyntaxKind.NullLiteralExpression); + { + N(SyntaxKind.NullKeyword); + } + } + } + } + N(SyntaxKind.SemicolonToken); + } + EOF(); + } + + [Theory, CombinatorialData] + public void Event_Definition_PartialAfterEvent([CSharp13_CSharp14_Preview] LanguageVersion langVersion) + { + UsingDeclaration(""" + event partial Action E; + """, + TestOptions.Regular.WithLanguageVersion(langVersion), + // (1,7): error CS1031: Type expected + // event partial Action E; + Diagnostic(ErrorCode.ERR_TypeExpected, "partial").WithLocation(1, 7), + // (1,7): error CS1525: Invalid expression term 'partial' + // event partial Action E; + Diagnostic(ErrorCode.ERR_InvalidExprTerm, "partial").WithArguments("partial").WithLocation(1, 7), + // (1,7): error CS1003: Syntax error, ',' expected + // event partial Action E; + Diagnostic(ErrorCode.ERR_SyntaxError, "partial").WithArguments(",").WithLocation(1, 7)); + + N(SyntaxKind.EventFieldDeclaration); + { + N(SyntaxKind.EventKeyword); + M(SyntaxKind.VariableDeclaration); + { + M(SyntaxKind.IdentifierName); + { + M(SyntaxKind.IdentifierToken); + } + M(SyntaxKind.VariableDeclarator); + { + M(SyntaxKind.IdentifierToken); + } + } + N(SyntaxKind.SemicolonToken); + } + EOF(); + } + + [Theory, CombinatorialData] + public void Event_Definition_PartialAfterType([CSharp13_CSharp14_Preview] LanguageVersion langVersion) + { + UsingDeclaration(""" + event Action partial E; + """, + TestOptions.Regular.WithLanguageVersion(langVersion), + // (1,22): error CS1003: Syntax error, ',' expected + // event Action partial E; + Diagnostic(ErrorCode.ERR_SyntaxError, "E").WithArguments(",").WithLocation(1, 22)); + + N(SyntaxKind.EventFieldDeclaration); + { + N(SyntaxKind.EventKeyword); + N(SyntaxKind.VariableDeclaration); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Action"); + } + N(SyntaxKind.VariableDeclarator); + { + N(SyntaxKind.IdentifierToken, "partial"); + } + } + N(SyntaxKind.SemicolonToken); + } + EOF(); + } + + [Theory, CombinatorialData] + public void Event_Definition_PartialAfterPublic([CSharp14_Preview] LanguageVersion langVersion) + { + UsingDeclaration(""" + public partial event Action E; + """, + TestOptions.Regular.WithLanguageVersion(langVersion)); + + N(SyntaxKind.EventFieldDeclaration); + { + N(SyntaxKind.PublicKeyword); + N(SyntaxKind.PartialKeyword); + N(SyntaxKind.EventKeyword); + N(SyntaxKind.VariableDeclaration); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Action"); + } + N(SyntaxKind.VariableDeclarator); + { + N(SyntaxKind.IdentifierToken, "E"); + } + } + N(SyntaxKind.SemicolonToken); + } + EOF(); + } + + [Theory, CombinatorialData] + public void Event_Definition_PartialBeforePublic([CSharp13_CSharp14_Preview] LanguageVersion langVersion) + { + UsingDeclaration(""" + partial public event Action E; + """, + TestOptions.Regular.WithLanguageVersion(langVersion)); + + N(SyntaxKind.EventFieldDeclaration); + { + N(SyntaxKind.PartialKeyword); + N(SyntaxKind.PublicKeyword); + N(SyntaxKind.EventKeyword); + N(SyntaxKind.VariableDeclaration); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Action"); + } + N(SyntaxKind.VariableDeclarator); + { + N(SyntaxKind.IdentifierToken, "E"); + } + } + N(SyntaxKind.SemicolonToken); + } + EOF(); + } + + [Theory, CombinatorialData] + public void Event_Definition_DoublePartial([CSharp14_Preview] LanguageVersion langVersion) + { + UsingDeclaration(""" + partial partial event Action E; + """, + TestOptions.Regular.WithLanguageVersion(langVersion), + // (1,9): error CS1525: Invalid expression term 'partial' + // partial partial event Action E; + Diagnostic(ErrorCode.ERR_InvalidExprTerm, "partial").WithArguments("partial").WithLocation(1, 9), + // (1,9): error CS1003: Syntax error, ',' expected + // partial partial event Action E; + Diagnostic(ErrorCode.ERR_SyntaxError, "partial").WithArguments(",").WithLocation(1, 9)); + + N(SyntaxKind.FieldDeclaration); + { + N(SyntaxKind.VariableDeclaration); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "partial"); + } + M(SyntaxKind.VariableDeclarator); + { + M(SyntaxKind.IdentifierToken); + } + } + N(SyntaxKind.SemicolonToken); + } + EOF(); + } + + [Theory, CombinatorialData] + public void Event_Definition_MissingRest([CSharp14_Preview] LanguageVersion langVersion) + { + UsingDeclaration(""" + partial event + """, + TestOptions.Regular.WithLanguageVersion(langVersion), + // (1,14): error CS1031: Type expected + // partial event + Diagnostic(ErrorCode.ERR_TypeExpected, "").WithLocation(1, 14), + // (1,14): error CS1514: { expected + // partial event + Diagnostic(ErrorCode.ERR_LbraceExpected, "").WithLocation(1, 14), + // (1,14): error CS1513: } expected + // partial event + Diagnostic(ErrorCode.ERR_RbraceExpected, "").WithLocation(1, 14)); + + N(SyntaxKind.EventDeclaration); + { + N(SyntaxKind.PartialKeyword); + N(SyntaxKind.EventKeyword); + M(SyntaxKind.IdentifierName); + { + M(SyntaxKind.IdentifierToken); + } + M(SyntaxKind.IdentifierToken); + M(SyntaxKind.AccessorList); + { + M(SyntaxKind.OpenBraceToken); + M(SyntaxKind.CloseBraceToken); + } + } + EOF(); + } + + [Theory, CombinatorialData] + public void Event_Implementation([CSharp14_Preview] LanguageVersion langVersion) + { + UsingDeclaration(""" + partial event Action E { add { } remove { } } + """, + TestOptions.Regular.WithLanguageVersion(langVersion)); + + N(SyntaxKind.EventDeclaration); + { + N(SyntaxKind.PartialKeyword); + N(SyntaxKind.EventKeyword); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Action"); + } + N(SyntaxKind.IdentifierToken, "E"); + N(SyntaxKind.AccessorList); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.AddAccessorDeclaration); + { + N(SyntaxKind.AddKeyword); + N(SyntaxKind.Block); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + } + N(SyntaxKind.RemoveAccessorDeclaration); + { + N(SyntaxKind.RemoveKeyword); + N(SyntaxKind.Block); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + } + N(SyntaxKind.CloseBraceToken); + } + } + EOF(); + } + + [Theory, CombinatorialData] + public void Event_Implementation_Multiple([CSharp14_Preview] LanguageVersion langVersion) + { + UsingDeclaration(""" + partial event Action E, F { add { } remove { } } + """, + TestOptions.Regular.WithLanguageVersion(langVersion), + // (1,27): error CS1003: Syntax error, ',' expected + // partial event Action E, F { add { } remove { } } + Diagnostic(ErrorCode.ERR_SyntaxError, "{").WithArguments(",").WithLocation(1, 27), + // (1,49): error CS1002: ; expected + // partial event Action E, F { add { } remove { } } + Diagnostic(ErrorCode.ERR_SemicolonExpected, "").WithLocation(1, 49)); + + N(SyntaxKind.EventFieldDeclaration); + { + N(SyntaxKind.PartialKeyword); + N(SyntaxKind.EventKeyword); + N(SyntaxKind.VariableDeclaration); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Action"); + } + N(SyntaxKind.VariableDeclarator); + { + N(SyntaxKind.IdentifierToken, "E"); + } + N(SyntaxKind.CommaToken); + N(SyntaxKind.VariableDeclarator); + { + N(SyntaxKind.IdentifierToken, "F"); + } + } + M(SyntaxKind.SemicolonToken); + } + EOF(); + } + + [Theory, CombinatorialData] + public void Event_Implementation_PartialAfterEvent([CSharp13_CSharp14_Preview] LanguageVersion langVersion) + { + UsingDeclaration(""" + event partial Action E { add { } remove { } } + """, + TestOptions.Regular.WithLanguageVersion(langVersion), + // (1,7): error CS1031: Type expected + // event partial Action E { add { } remove { } } + Diagnostic(ErrorCode.ERR_TypeExpected, "partial").WithLocation(1, 7), + // (1,7): error CS1525: Invalid expression term 'partial' + // event partial Action E { add { } remove { } } + Diagnostic(ErrorCode.ERR_InvalidExprTerm, "partial").WithArguments("partial").WithLocation(1, 7), + // (1,7): error CS1003: Syntax error, ',' expected + // event partial Action E { add { } remove { } } + Diagnostic(ErrorCode.ERR_SyntaxError, "partial").WithArguments(",").WithLocation(1, 7), + // (1,46): error CS1002: ; expected + // event partial Action E { add { } remove { } } + Diagnostic(ErrorCode.ERR_SemicolonExpected, "").WithLocation(1, 46)); + + N(SyntaxKind.EventFieldDeclaration); + { + N(SyntaxKind.EventKeyword); + M(SyntaxKind.VariableDeclaration); + { + M(SyntaxKind.IdentifierName); + { + M(SyntaxKind.IdentifierToken); + } + M(SyntaxKind.VariableDeclarator); + { + M(SyntaxKind.IdentifierToken); + } + } + M(SyntaxKind.SemicolonToken); + } + EOF(); + } + + [Theory, CombinatorialData] + public void Event_Implementation_SemicolonAccessors([CSharp14_Preview] LanguageVersion langVersion) + { + UsingDeclaration(""" + partial event Action E { add; remove; } + """, + TestOptions.Regular.WithLanguageVersion(langVersion)); + + N(SyntaxKind.EventDeclaration); + { + N(SyntaxKind.PartialKeyword); + N(SyntaxKind.EventKeyword); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Action"); + } + N(SyntaxKind.IdentifierToken, "E"); + N(SyntaxKind.AccessorList); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.AddAccessorDeclaration); + { + N(SyntaxKind.AddKeyword); + N(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.RemoveAccessorDeclaration); + { + N(SyntaxKind.RemoveKeyword); + N(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.CloseBraceToken); + } + } + EOF(); + } + + [Theory, CombinatorialData] + public void Event_Implementation_PartialAccessors([CSharp14_Preview] LanguageVersion langVersion) + { + UsingDeclaration(""" + partial event Action E { partial add; partial remove; } + """, + TestOptions.Regular.WithLanguageVersion(langVersion), + // (1,26): error CS1055: An add or remove accessor expected + // partial event Action E { partial add; partial remove; } + Diagnostic(ErrorCode.ERR_AddOrRemoveExpected, "partial").WithLocation(1, 26), + // (1,39): error CS1055: An add or remove accessor expected + // partial event Action E { partial add; partial remove; } + Diagnostic(ErrorCode.ERR_AddOrRemoveExpected, "partial").WithLocation(1, 39)); + + N(SyntaxKind.EventDeclaration); + { + N(SyntaxKind.PartialKeyword); + N(SyntaxKind.EventKeyword); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Action"); + } + N(SyntaxKind.IdentifierToken, "E"); + N(SyntaxKind.AccessorList); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.UnknownAccessorDeclaration); + { + N(SyntaxKind.IdentifierToken, "partial"); + } + N(SyntaxKind.AddAccessorDeclaration); + { + N(SyntaxKind.AddKeyword); + N(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.UnknownAccessorDeclaration); + { + N(SyntaxKind.IdentifierToken, "partial"); + } + N(SyntaxKind.RemoveAccessorDeclaration); + { + N(SyntaxKind.RemoveKeyword); + N(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.CloseBraceToken); + } + } + EOF(); + } + + [Theory, CombinatorialData] + public void Event_InPlaceOfIdentifier([CSharp14_Preview] LanguageVersion langVersion) + { + UsingTree(""" + partial class C + { + [Attr( + partial event Action E; + } + """, + TestOptions.Regular.WithLanguageVersion(langVersion), + // (3,11): error CS1026: ) expected + // [Attr( + Diagnostic(ErrorCode.ERR_CloseParenExpected, "").WithLocation(3, 11), + // (3,11): error CS1003: Syntax error, ']' expected + // [Attr( + Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments("]").WithLocation(3, 11)); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.PartialKeyword); + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.EventFieldDeclaration); + { + N(SyntaxKind.AttributeList); + { + N(SyntaxKind.OpenBracketToken); + N(SyntaxKind.Attribute); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Attr"); + } + N(SyntaxKind.AttributeArgumentList); + { + N(SyntaxKind.OpenParenToken); + M(SyntaxKind.CloseParenToken); + } + } + M(SyntaxKind.CloseBracketToken); + } + N(SyntaxKind.PartialKeyword); + N(SyntaxKind.EventKeyword); + N(SyntaxKind.VariableDeclaration); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Action"); + } + N(SyntaxKind.VariableDeclarator); + { + N(SyntaxKind.IdentifierToken, "E"); + } + } + N(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Theory, CombinatorialData] + public void Constructor_Tree([CSharp14_Preview] LanguageVersion langVersion) + { + UsingTree(""" + partial class C + { + partial C(); + partial C() { } + } + """, + TestOptions.Regular.WithLanguageVersion(langVersion)); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.PartialKeyword); + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.ConstructorDeclaration); + { + N(SyntaxKind.PartialKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.ConstructorDeclaration); + { + N(SyntaxKind.PartialKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.Block); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Theory, CombinatorialData] + public void Constructor_Declaration([CSharp14_Preview] LanguageVersion langVersion) + { + UsingDeclaration(""" + partial C() { } + """, + TestOptions.Regular.WithLanguageVersion(langVersion)); + + N(SyntaxKind.ConstructorDeclaration); + { + N(SyntaxKind.PartialKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.Block); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + } + EOF(); + } + + [Fact] + public void Constructor_Declaration_CSharp13() + { + UsingDeclaration(""" + partial C() { } + """, + TestOptions.Regular13); + + N(SyntaxKind.MethodDeclaration); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "partial"); + } + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.Block); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + } + EOF(); + } + + [Theory, CombinatorialData] + public void Constructor_ArrowBody([CSharp14_Preview] LanguageVersion langVersion) + { + UsingDeclaration(""" + partial C() => throw null; + """, + TestOptions.Regular.WithLanguageVersion(langVersion)); + + N(SyntaxKind.ConstructorDeclaration); + { + N(SyntaxKind.PartialKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.ArrowExpressionClause); + { + N(SyntaxKind.EqualsGreaterThanToken); + N(SyntaxKind.ThrowExpression); + { + N(SyntaxKind.ThrowKeyword); + N(SyntaxKind.NullLiteralExpression); + { + N(SyntaxKind.NullKeyword); + } + } + } + N(SyntaxKind.SemicolonToken); + } + EOF(); + } + + [Theory, CombinatorialData] + public void Constructor_NoParens([CSharp13_CSharp14_Preview] LanguageVersion langVersion) + { + UsingDeclaration(""" + partial C; + """, + TestOptions.Regular.WithLanguageVersion(langVersion)); + + N(SyntaxKind.FieldDeclaration); + { + N(SyntaxKind.VariableDeclaration); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "partial"); + } + N(SyntaxKind.VariableDeclarator); + { + N(SyntaxKind.IdentifierToken, "C"); + } + } + N(SyntaxKind.SemicolonToken); + } + EOF(); + } + + [Theory, CombinatorialData] + public void Constructor_NoName([CSharp13_CSharp14_Preview] LanguageVersion langVersion) + { + UsingDeclaration(""" + partial (); + """, + TestOptions.Regular.WithLanguageVersion(langVersion)); + + N(SyntaxKind.ConstructorDeclaration); + { + N(SyntaxKind.IdentifierToken, "partial"); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.SemicolonToken); + } + EOF(); + } + + [Theory, CombinatorialData] + public void Constructor_PartialAsName([CSharp14_Preview] LanguageVersion langVersion) + { + UsingDeclaration(""" + partial partial(); + """, + TestOptions.Regular.WithLanguageVersion(langVersion)); + + N(SyntaxKind.ConstructorDeclaration); + { + N(SyntaxKind.PartialKeyword); + N(SyntaxKind.IdentifierToken, "partial"); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.SemicolonToken); + } + EOF(); + } + + [Theory, CombinatorialData] + public void Constructor_PartialAfterName([CSharp13_CSharp14_Preview] LanguageVersion langVersion) + { + UsingDeclaration(""" + C partial(); + """, + TestOptions.Regular.WithLanguageVersion(langVersion)); + + N(SyntaxKind.MethodDeclaration); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "C"); + } + N(SyntaxKind.IdentifierToken, "partial"); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.SemicolonToken); + } + EOF(); + } + + [Theory, CombinatorialData] + public void Constructor_PartialAfterPublic([CSharp14_Preview] LanguageVersion langVersion) + { + UsingDeclaration(""" + public partial C(); + """, + TestOptions.Regular.WithLanguageVersion(langVersion)); + + N(SyntaxKind.ConstructorDeclaration); + { + N(SyntaxKind.PublicKeyword); + N(SyntaxKind.PartialKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.SemicolonToken); + } + EOF(); + } + + [Theory, CombinatorialData] + public void Constructor_PartialBeforePublic([CSharp13_CSharp14_Preview] LanguageVersion langVersion) + { + UsingDeclaration(""" + partial public C(); + """, + TestOptions.Regular.WithLanguageVersion(langVersion)); + + N(SyntaxKind.ConstructorDeclaration); + { + N(SyntaxKind.PartialKeyword); + N(SyntaxKind.PublicKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.SemicolonToken); + } + EOF(); + } + + [Theory, CombinatorialData] + public void Constructor_TypeTwice([CSharp13_CSharp14_Preview] LanguageVersion langVersion) + { + UsingDeclaration(""" + partial C C(); + """, + TestOptions.Regular.WithLanguageVersion(langVersion)); + + N(SyntaxKind.MethodDeclaration); + { + N(SyntaxKind.PartialKeyword); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "C"); + } + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.SemicolonToken); + } + EOF(); + } + + [Theory, CombinatorialData] + public void Constructor_PartialEscaped([CSharp13_CSharp14_Preview] LanguageVersion langVersion) + { + UsingDeclaration(""" + @partial C(); + """, + TestOptions.Regular.WithLanguageVersion(langVersion)); + + N(SyntaxKind.MethodDeclaration); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "@partial"); + } + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.SemicolonToken); + } + EOF(); + } + + [Theory, CombinatorialData] + public void Constructor_KeywordName([CSharp13_CSharp14_Preview] LanguageVersion langVersion) + { + UsingDeclaration(""" + partial const(); + """, + TestOptions.Regular.WithLanguageVersion(langVersion), + // (1,1): error CS1073: Unexpected token 'const' + // partial const(); + Diagnostic(ErrorCode.ERR_UnexpectedToken, "partial").WithArguments("const").WithLocation(1, 1), + // (1,9): error CS1519: Invalid token 'const' in class, record, struct, or interface member declaration + // partial const(); + Diagnostic(ErrorCode.ERR_InvalidMemberDecl, "const").WithArguments("const").WithLocation(1, 9)); + + N(SyntaxKind.IncompleteMember); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "partial"); + } + } + EOF(); + } + + [Theory, CombinatorialData] + public void Constructor_InPlaceOfIdentifier([CSharp14_Preview] LanguageVersion langVersion) + { + UsingTree(""" + partial class C + { + [Attr( + partial C(); + } + """, + TestOptions.Regular.WithLanguageVersion(langVersion), + // (3,11): error CS1026: ) expected + // [Attr( + Diagnostic(ErrorCode.ERR_CloseParenExpected, "").WithLocation(3, 11), + // (3,11): error CS1003: Syntax error, ']' expected + // [Attr( + Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments("]").WithLocation(3, 11)); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.PartialKeyword); + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.ConstructorDeclaration); + { + N(SyntaxKind.AttributeList); + { + N(SyntaxKind.OpenBracketToken); + N(SyntaxKind.Attribute); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Attr"); + } + N(SyntaxKind.AttributeArgumentList); + { + N(SyntaxKind.OpenParenToken); + M(SyntaxKind.CloseParenToken); + } + } + M(SyntaxKind.CloseBracketToken); + } + N(SyntaxKind.PartialKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Theory, CombinatorialData] + public void ReturningPartialType_LocalFunction_InMethod([CSharp14_Preview] LanguageVersion langVersion) + { + UsingTree(""" + class C + { + void M() + { + partial F() => null; + } + } + """, + TestOptions.Regular.WithLanguageVersion(langVersion), + // (4,6): error CS1513: } expected + // { + Diagnostic(ErrorCode.ERR_RbraceExpected, "").WithLocation(4, 6), + // (7,1): error CS1022: Type or namespace definition, or end-of-file expected + // } + Diagnostic(ErrorCode.ERR_EOFExpected, "}").WithLocation(7, 1)); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.MethodDeclaration); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.VoidKeyword); + } + N(SyntaxKind.IdentifierToken, "M"); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.Block); + { + N(SyntaxKind.OpenBraceToken); + M(SyntaxKind.CloseBraceToken); + } + } + N(SyntaxKind.ConstructorDeclaration); + { + N(SyntaxKind.PartialKeyword); + N(SyntaxKind.IdentifierToken, "F"); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.ArrowExpressionClause); + { + N(SyntaxKind.EqualsGreaterThanToken); + N(SyntaxKind.NullLiteralExpression); + { + N(SyntaxKind.NullKeyword); + } + } + N(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void ReturningPartialType_LocalFunction_InMethod_CSharp13() + { + UsingTree(""" + class C + { + void M() + { + partial F() => null; + } + } + """, + TestOptions.Regular13); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.MethodDeclaration); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.VoidKeyword); + } + N(SyntaxKind.IdentifierToken, "M"); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.Block); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.LocalFunctionStatement); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "partial"); + } + N(SyntaxKind.IdentifierToken, "F"); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.ArrowExpressionClause); + { + N(SyntaxKind.EqualsGreaterThanToken); + N(SyntaxKind.NullLiteralExpression); + { + N(SyntaxKind.NullKeyword); + } + } + N(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.CloseBraceToken); + } + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Theory, CombinatorialData] + public void ReturningPartialType_LocalFunction_TopLevel([CSharp14_Preview] LanguageVersion langVersion) + { + UsingTree(""" + partial F() => null; + """, + TestOptions.Regular.WithLanguageVersion(langVersion), + // (1,9): error CS0116: A namespace cannot directly contain members such as fields, methods or statements + // partial F() => null; + Diagnostic(ErrorCode.ERR_NamespaceUnexpected, "F").WithLocation(1, 9)); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.IncompleteMember); + { + N(SyntaxKind.PartialKeyword); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "F"); + } + } + N(SyntaxKind.GlobalStatement); + { + N(SyntaxKind.ExpressionStatement); + { + N(SyntaxKind.ParenthesizedLambdaExpression); + { + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.EqualsGreaterThanToken); + N(SyntaxKind.NullLiteralExpression); + { + N(SyntaxKind.NullKeyword); + } + } + N(SyntaxKind.SemicolonToken); + } + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void ReturningPartialType_LocalFunction_TopLevel_CSharp13() + { + UsingTree(""" + partial F() => null; + """, + TestOptions.Regular13); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.GlobalStatement); + { + N(SyntaxKind.LocalFunctionStatement); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "partial"); + } + N(SyntaxKind.IdentifierToken, "F"); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.ArrowExpressionClause); + { + N(SyntaxKind.EqualsGreaterThanToken); + N(SyntaxKind.NullLiteralExpression); + { + N(SyntaxKind.NullKeyword); + } + } + N(SyntaxKind.SemicolonToken); + } + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Theory, CombinatorialData] + public void ReturningPartialType_Method([CSharp14_Preview] LanguageVersion langVersion) + { + UsingTree(""" + class C + { + partial M() => null; + @partial M() => null; + } + """, + TestOptions.Regular.WithLanguageVersion(langVersion)); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.ConstructorDeclaration); + { + N(SyntaxKind.PartialKeyword); + N(SyntaxKind.IdentifierToken, "M"); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.ArrowExpressionClause); + { + N(SyntaxKind.EqualsGreaterThanToken); + N(SyntaxKind.NullLiteralExpression); + { + N(SyntaxKind.NullKeyword); + } + } + N(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.MethodDeclaration); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "@partial"); + } + N(SyntaxKind.IdentifierToken, "M"); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.ArrowExpressionClause); + { + N(SyntaxKind.EqualsGreaterThanToken); + N(SyntaxKind.NullLiteralExpression); + { + N(SyntaxKind.NullKeyword); + } + } + N(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void ReturningPartialType_Method_CSharp13() + { + UsingTree(""" + class C + { + partial M() => null; + @partial M() => null; + } + """, + TestOptions.Regular13); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.MethodDeclaration); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "partial"); + } + N(SyntaxKind.IdentifierToken, "M"); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.ArrowExpressionClause); + { + N(SyntaxKind.EqualsGreaterThanToken); + N(SyntaxKind.NullLiteralExpression); + { + N(SyntaxKind.NullKeyword); + } + } + N(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.MethodDeclaration); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "@partial"); + } + N(SyntaxKind.IdentifierToken, "M"); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.ArrowExpressionClause); + { + N(SyntaxKind.EqualsGreaterThanToken); + N(SyntaxKind.NullLiteralExpression); + { + N(SyntaxKind.NullKeyword); + } + } + N(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } +} diff --git a/src/Scripting/CSharpTest/ScriptTests.cs b/src/Scripting/CSharpTest/ScriptTests.cs index f78d4d5b7a29e..a04c40871cabc 100644 --- a/src/Scripting/CSharpTest/ScriptTests.cs +++ b/src/Scripting/CSharpTest/ScriptTests.cs @@ -1067,6 +1067,38 @@ public async Task SwitchPatternWithVar_WhenInvalidArm_ShouldReturnTheNameNotInCo Assert.True(exceptionThrown); } + [Fact] + public void Function_ReturningPartialType() + { + var script = CSharpScript.Create("class partial;", ScriptOptions.WithLanguageVersion(LanguageVersion.Preview)) + .ContinueWith("partial M() => new();"); + script.GetCompilation().VerifyDiagnostics( + // (1,9): error CS1520: Method must have a return type + // partial M() => new(); + Diagnostic(ErrorCode.ERR_MemberNeedsType, "M").WithLocation(1, 9), + // (1,9): error CS0759: No defining declaration found for implementing declaration of partial method 'M()' + // partial M() => new(); + Diagnostic(ErrorCode.ERR_PartialMethodMustHaveLatent, "M").WithArguments("M()").WithLocation(1, 9), + // (1,9): error CS0751: A partial member must be declared within a partial type + // partial M() => new(); + Diagnostic(ErrorCode.ERR_PartialMemberOnlyInPartialClass, "M").WithLocation(1, 9), + // (1,16): error CS0201: Only assignment, call, increment, decrement, await, and new object expressions can be used as a statement + // partial M() => new(); + Diagnostic(ErrorCode.ERR_IllegalStatement, "new()").WithLocation(1, 16)); + } + + [Fact] + public async Task Function_ReturningPartialType_CSharp13() + { + var script = CSharpScript.Create("class partial;", ScriptOptions.WithLanguageVersion(LanguageVersion.CSharp13)) + .ContinueWith("partial M() => new();") + .ContinueWith("M()"); + script.GetCompilation().VerifyDiagnostics(); + + var result = await script.EvaluateAsync(); + Assert.Equal("partial", result.GetType().Name); + } + private class StreamOffsetResolver : SourceReferenceResolver { public override bool Equals(object other) => ReferenceEquals(this, other);