diff --git a/docs/compilers/CSharp/Compiler Breaking Changes - DotNet 10.md b/docs/compilers/CSharp/Compiler Breaking Changes - DotNet 10.md
index 6075637771e03..3058c6165f03b 100644
--- a/docs/compilers/CSharp/Compiler Breaking Changes - DotNet 10.md
+++ b/docs/compilers/CSharp/Compiler Breaking Changes - DotNet 10.md
@@ -291,3 +291,29 @@ unsafe record struct R(
public bool Equals(R other) => true;
}
```
+
+## `extension` treated as a contextual keyword
+
+PROTOTYPE record which version this break is introduced in
+
+Starting with C# 14, the `extension` keyword serves a special purpose in denoting extension containers.
+This changes how the compiler interprets certain code constructs.
+
+If you need to use "extension" as an identifier rather than a keyword, escape it with the `@` prefix: `@extension`. This tells the compiler to treat it as a regular identifier instead of a keyword.
+
+The compiler will parse this as an extension container rather than a constructor.
+```csharp
+class extension
+{
+ extension(object o) { } // parsed as an extension container
+}
+```
+
+The compiler will fail to parse this as a method with return type `extension`.
+```csharp
+class extension
+{
+ extension M() { } // will not compile
+}
+```
+
diff --git a/src/Compilers/CSharp/Portable/CSharpResources.resx b/src/Compilers/CSharp/Portable/CSharpResources.resx
index 13c398af16501..424ae43759e4f 100644
--- a/src/Compilers/CSharp/Portable/CSharpResources.resx
+++ b/src/Compilers/CSharp/Portable/CSharpResources.resx
@@ -2600,7 +2600,7 @@ A catch() block after a catch (System.Exception e) block can catch non-CLS excep
Invalid preprocessor expression
- Invalid token '{0}' in class, record, struct, or interface member declaration
+ Invalid token '{0}' in a member declaration
Method must have a return type
@@ -8047,4 +8047,10 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ
'InterceptsLocationAttribute(string, int, int)' is not supported. Move to 'InterceptableLocation'-based generation of these attributes instead. (https://github.com/dotnet/roslyn/issues/72133)
+
+ extensions
+
+
+ Extension declarations may not have a name.
+
diff --git a/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs b/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs
index 83f128759bf41..dba82e9d33666 100644
--- a/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs
+++ b/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs
@@ -2360,6 +2360,9 @@ internal enum ErrorCode
ERR_ImplicitlyTypedParamsParameter = 9272,
ERR_VariableDeclarationNamedField = 9273,
+ // PROTOTYPE compact error codes
+ ERR_ExtensionDisallowsName = 9500,
+
// Note: you will need to do the following after adding errors:
// 1) Update ErrorFacts.IsBuildOnlyDiagnostic (src/Compilers/CSharp/Portable/Errors/ErrorFacts.cs)
diff --git a/src/Compilers/CSharp/Portable/Errors/ErrorFacts.cs b/src/Compilers/CSharp/Portable/Errors/ErrorFacts.cs
index f6e520514814b..ebabecd3dbf21 100644
--- a/src/Compilers/CSharp/Portable/Errors/ErrorFacts.cs
+++ b/src/Compilers/CSharp/Portable/Errors/ErrorFacts.cs
@@ -2479,6 +2479,7 @@ or ErrorCode.WRN_UnscopedRefAttributeOldRules
or ErrorCode.WRN_InterceptsLocationAttributeUnsupportedSignature
or ErrorCode.ERR_ImplicitlyTypedParamsParameter
or ErrorCode.ERR_VariableDeclarationNamedField
+ or ErrorCode.ERR_ExtensionDisallowsName
=> false,
};
#pragma warning restore CS8524 // The switch expression does not handle some values of its input type (it is not exhaustive) involving an unnamed enum value.
diff --git a/src/Compilers/CSharp/Portable/Errors/MessageID.cs b/src/Compilers/CSharp/Portable/Errors/MessageID.cs
index 38c4399efd622..30724c5576c1c 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_FeatureExtensions = 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_FeatureExtensions:
return LanguageVersion.Preview;
// C# 13.0 features.
diff --git a/src/Compilers/CSharp/Portable/Generated/CSharp.Generated.g4 b/src/Compilers/CSharp/Portable/Generated/CSharp.Generated.g4
index 6968dc30e0fb5..3c53475dbf132 100644
--- a/src/Compilers/CSharp/Portable/Generated/CSharp.Generated.g4
+++ b/src/Compilers/CSharp/Portable/Generated/CSharp.Generated.g4
@@ -160,7 +160,7 @@ parameter_list
;
parameter
- : attribute_list* modifier* type? (identifier_token | '__arglist') equals_value_clause?
+ : attribute_list* modifier* type? (identifier_token | '__arglist')? equals_value_clause?
;
constructor_initializer
@@ -323,6 +323,7 @@ enum_member_declaration
type_declaration
: class_declaration
+ | extension_declaration
| interface_declaration
| record_declaration
| struct_declaration
@@ -332,6 +333,10 @@ class_declaration
: attribute_list* modifier* 'class' identifier_token type_parameter_list? parameter_list? base_list? type_parameter_constraint_clause* '{'? member_declaration* '}'? ';'?
;
+extension_declaration
+ : attribute_list* modifier* 'extension' type_parameter_list? parameter_list? type_parameter_constraint_clause* '{'? member_declaration* '}'? ';'?
+ ;
+
interface_declaration
: attribute_list* modifier* 'interface' identifier_token type_parameter_list? parameter_list? base_list? type_parameter_constraint_clause* '{'? member_declaration* '}'? ';'?
;
diff --git a/src/Compilers/CSharp/Portable/Generated/CSharpSyntaxGenerator/CSharpSyntaxGenerator.SourceGenerator/Syntax.xml.Internal.Generated.cs b/src/Compilers/CSharp/Portable/Generated/CSharpSyntaxGenerator/CSharpSyntaxGenerator.SourceGenerator/Syntax.xml.Internal.Generated.cs
index 78d8aedb8b8f2..f268ad36627da 100644
--- a/src/Compilers/CSharp/Portable/Generated/CSharpSyntaxGenerator/CSharpSyntaxGenerator.SourceGenerator/Syntax.xml.Internal.Generated.cs
+++ b/src/Compilers/CSharp/Portable/Generated/CSharpSyntaxGenerator/CSharpSyntaxGenerator.SourceGenerator/Syntax.xml.Internal.Generated.cs
@@ -16509,7 +16509,7 @@ internal BaseTypeDeclarationSyntax(SyntaxKind kind)
}
/// Gets the identifier.
- public abstract SyntaxToken Identifier { get; }
+ public abstract SyntaxToken? Identifier { get; }
/// Gets the base type list.
public abstract BaseListSyntax? BaseList { get; }
@@ -16524,7 +16524,7 @@ internal BaseTypeDeclarationSyntax(SyntaxKind kind)
public abstract SyntaxToken? SemicolonToken { get; }
}
-/// Base class for type declaration syntax (class, struct, interface, record).
+/// Base class for type declaration syntax (class, struct, interface, record, extension).
internal abstract partial class TypeDeclarationSyntax : BaseTypeDeclarationSyntax
{
internal TypeDeclarationSyntax(SyntaxKind kind, DiagnosticInfo[]? diagnostics, SyntaxAnnotation[]? annotations)
@@ -16537,7 +16537,7 @@ internal TypeDeclarationSyntax(SyntaxKind kind)
{
}
- /// Gets the type keyword token ("class", "struct", "interface", "record").
+ /// Gets the type keyword token ("class", "struct", "interface", "record", "extension").
public abstract SyntaxToken Keyword { get; }
public abstract TypeParameterListSyntax? TypeParameterList { get; }
@@ -18109,6 +18109,236 @@ internal override GreenNode SetAnnotations(SyntaxAnnotation[]? annotations)
=> new EnumMemberDeclarationSyntax(this.Kind, this.attributeLists, this.modifiers, this.identifier, this.equalsValue, GetDiagnostics(), annotations);
}
+/// Extension container syntax.
+internal sealed partial class ExtensionDeclarationSyntax : TypeDeclarationSyntax
+{
+ internal readonly GreenNode? attributeLists;
+ internal readonly GreenNode? modifiers;
+ internal readonly SyntaxToken keyword;
+ internal readonly TypeParameterListSyntax? typeParameterList;
+ internal readonly ParameterListSyntax? parameterList;
+ internal readonly GreenNode? constraintClauses;
+ internal readonly SyntaxToken? openBraceToken;
+ internal readonly GreenNode? members;
+ internal readonly SyntaxToken? closeBraceToken;
+ internal readonly SyntaxToken? semicolonToken;
+
+ internal ExtensionDeclarationSyntax(SyntaxKind kind, GreenNode? attributeLists, GreenNode? modifiers, SyntaxToken keyword, TypeParameterListSyntax? typeParameterList, ParameterListSyntax? parameterList, GreenNode? constraintClauses, SyntaxToken? openBraceToken, GreenNode? members, SyntaxToken? closeBraceToken, SyntaxToken? semicolonToken, DiagnosticInfo[]? diagnostics, SyntaxAnnotation[]? annotations)
+ : base(kind, diagnostics, annotations)
+ {
+ this.SlotCount = 10;
+ if (attributeLists != null)
+ {
+ this.AdjustFlagsAndWidth(attributeLists);
+ this.attributeLists = attributeLists;
+ }
+ if (modifiers != null)
+ {
+ this.AdjustFlagsAndWidth(modifiers);
+ this.modifiers = modifiers;
+ }
+ this.AdjustFlagsAndWidth(keyword);
+ this.keyword = keyword;
+ if (typeParameterList != null)
+ {
+ this.AdjustFlagsAndWidth(typeParameterList);
+ this.typeParameterList = typeParameterList;
+ }
+ if (parameterList != null)
+ {
+ this.AdjustFlagsAndWidth(parameterList);
+ this.parameterList = parameterList;
+ }
+ if (constraintClauses != null)
+ {
+ this.AdjustFlagsAndWidth(constraintClauses);
+ this.constraintClauses = constraintClauses;
+ }
+ if (openBraceToken != null)
+ {
+ this.AdjustFlagsAndWidth(openBraceToken);
+ this.openBraceToken = openBraceToken;
+ }
+ if (members != null)
+ {
+ this.AdjustFlagsAndWidth(members);
+ this.members = members;
+ }
+ if (closeBraceToken != null)
+ {
+ this.AdjustFlagsAndWidth(closeBraceToken);
+ this.closeBraceToken = closeBraceToken;
+ }
+ if (semicolonToken != null)
+ {
+ this.AdjustFlagsAndWidth(semicolonToken);
+ this.semicolonToken = semicolonToken;
+ }
+ }
+
+ internal ExtensionDeclarationSyntax(SyntaxKind kind, GreenNode? attributeLists, GreenNode? modifiers, SyntaxToken keyword, TypeParameterListSyntax? typeParameterList, ParameterListSyntax? parameterList, GreenNode? constraintClauses, SyntaxToken? openBraceToken, GreenNode? members, SyntaxToken? closeBraceToken, SyntaxToken? semicolonToken, SyntaxFactoryContext context)
+ : base(kind)
+ {
+ this.SetFactoryContext(context);
+ this.SlotCount = 10;
+ if (attributeLists != null)
+ {
+ this.AdjustFlagsAndWidth(attributeLists);
+ this.attributeLists = attributeLists;
+ }
+ if (modifiers != null)
+ {
+ this.AdjustFlagsAndWidth(modifiers);
+ this.modifiers = modifiers;
+ }
+ this.AdjustFlagsAndWidth(keyword);
+ this.keyword = keyword;
+ if (typeParameterList != null)
+ {
+ this.AdjustFlagsAndWidth(typeParameterList);
+ this.typeParameterList = typeParameterList;
+ }
+ if (parameterList != null)
+ {
+ this.AdjustFlagsAndWidth(parameterList);
+ this.parameterList = parameterList;
+ }
+ if (constraintClauses != null)
+ {
+ this.AdjustFlagsAndWidth(constraintClauses);
+ this.constraintClauses = constraintClauses;
+ }
+ if (openBraceToken != null)
+ {
+ this.AdjustFlagsAndWidth(openBraceToken);
+ this.openBraceToken = openBraceToken;
+ }
+ if (members != null)
+ {
+ this.AdjustFlagsAndWidth(members);
+ this.members = members;
+ }
+ if (closeBraceToken != null)
+ {
+ this.AdjustFlagsAndWidth(closeBraceToken);
+ this.closeBraceToken = closeBraceToken;
+ }
+ if (semicolonToken != null)
+ {
+ this.AdjustFlagsAndWidth(semicolonToken);
+ this.semicolonToken = semicolonToken;
+ }
+ }
+
+ internal ExtensionDeclarationSyntax(SyntaxKind kind, GreenNode? attributeLists, GreenNode? modifiers, SyntaxToken keyword, TypeParameterListSyntax? typeParameterList, ParameterListSyntax? parameterList, GreenNode? constraintClauses, SyntaxToken? openBraceToken, GreenNode? members, SyntaxToken? closeBraceToken, SyntaxToken? semicolonToken)
+ : base(kind)
+ {
+ this.SlotCount = 10;
+ if (attributeLists != null)
+ {
+ this.AdjustFlagsAndWidth(attributeLists);
+ this.attributeLists = attributeLists;
+ }
+ if (modifiers != null)
+ {
+ this.AdjustFlagsAndWidth(modifiers);
+ this.modifiers = modifiers;
+ }
+ this.AdjustFlagsAndWidth(keyword);
+ this.keyword = keyword;
+ if (typeParameterList != null)
+ {
+ this.AdjustFlagsAndWidth(typeParameterList);
+ this.typeParameterList = typeParameterList;
+ }
+ if (parameterList != null)
+ {
+ this.AdjustFlagsAndWidth(parameterList);
+ this.parameterList = parameterList;
+ }
+ if (constraintClauses != null)
+ {
+ this.AdjustFlagsAndWidth(constraintClauses);
+ this.constraintClauses = constraintClauses;
+ }
+ if (openBraceToken != null)
+ {
+ this.AdjustFlagsAndWidth(openBraceToken);
+ this.openBraceToken = openBraceToken;
+ }
+ if (members != null)
+ {
+ this.AdjustFlagsAndWidth(members);
+ this.members = members;
+ }
+ if (closeBraceToken != null)
+ {
+ this.AdjustFlagsAndWidth(closeBraceToken);
+ this.closeBraceToken = closeBraceToken;
+ }
+ if (semicolonToken != null)
+ {
+ this.AdjustFlagsAndWidth(semicolonToken);
+ this.semicolonToken = semicolonToken;
+ }
+ }
+
+ public override CoreSyntax.SyntaxList AttributeLists => new CoreSyntax.SyntaxList(this.attributeLists);
+ public override CoreSyntax.SyntaxList Modifiers => new CoreSyntax.SyntaxList(this.modifiers);
+ public override SyntaxToken Keyword => this.keyword;
+ public override TypeParameterListSyntax? TypeParameterList => this.typeParameterList;
+ public override ParameterListSyntax? ParameterList => this.parameterList;
+ public override CoreSyntax.SyntaxList ConstraintClauses => new CoreSyntax.SyntaxList(this.constraintClauses);
+ public override SyntaxToken? OpenBraceToken => this.openBraceToken;
+ public override CoreSyntax.SyntaxList Members => new CoreSyntax.SyntaxList(this.members);
+ public override SyntaxToken? CloseBraceToken => this.closeBraceToken;
+ public override SyntaxToken? SemicolonToken => this.semicolonToken;
+
+ internal override GreenNode? GetSlot(int index)
+ => index switch
+ {
+ 0 => this.attributeLists,
+ 1 => this.modifiers,
+ 2 => this.keyword,
+ 3 => this.typeParameterList,
+ 4 => this.parameterList,
+ 5 => this.constraintClauses,
+ 6 => this.openBraceToken,
+ 7 => this.members,
+ 8 => this.closeBraceToken,
+ 9 => this.semicolonToken,
+ _ => null,
+ };
+
+ internal override SyntaxNode CreateRed(SyntaxNode? parent, int position) => new CSharp.Syntax.ExtensionDeclarationSyntax(this, parent, position);
+
+ public override void Accept(CSharpSyntaxVisitor visitor) => visitor.VisitExtensionDeclaration(this);
+ public override TResult Accept(CSharpSyntaxVisitor visitor) => visitor.VisitExtensionDeclaration(this);
+
+ public ExtensionDeclarationSyntax Update(CoreSyntax.SyntaxList attributeLists, CoreSyntax.SyntaxList modifiers, SyntaxToken keyword, TypeParameterListSyntax typeParameterList, ParameterListSyntax parameterList, CoreSyntax.SyntaxList constraintClauses, SyntaxToken openBraceToken, CoreSyntax.SyntaxList members, SyntaxToken closeBraceToken, SyntaxToken semicolonToken)
+ {
+ if (attributeLists != this.AttributeLists || modifiers != this.Modifiers || keyword != this.Keyword || typeParameterList != this.TypeParameterList || parameterList != this.ParameterList || constraintClauses != this.ConstraintClauses || openBraceToken != this.OpenBraceToken || members != this.Members || closeBraceToken != this.CloseBraceToken || semicolonToken != this.SemicolonToken)
+ {
+ var newNode = SyntaxFactory.ExtensionDeclaration(attributeLists, modifiers, keyword, typeParameterList, parameterList, constraintClauses, openBraceToken, members, closeBraceToken, semicolonToken);
+ var diags = GetDiagnostics();
+ if (diags?.Length > 0)
+ newNode = newNode.WithDiagnosticsGreen(diags);
+ var annotations = GetAnnotations();
+ if (annotations?.Length > 0)
+ newNode = newNode.WithAnnotationsGreen(annotations);
+ return newNode;
+ }
+
+ return this;
+ }
+
+ internal override GreenNode SetDiagnostics(DiagnosticInfo[]? diagnostics)
+ => new ExtensionDeclarationSyntax(this.Kind, this.attributeLists, this.modifiers, this.keyword, this.typeParameterList, this.parameterList, this.constraintClauses, this.openBraceToken, this.members, this.closeBraceToken, this.semicolonToken, diagnostics, GetAnnotations());
+
+ internal override GreenNode SetAnnotations(SyntaxAnnotation[]? annotations)
+ => new ExtensionDeclarationSyntax(this.Kind, this.attributeLists, this.modifiers, this.keyword, this.typeParameterList, this.parameterList, this.constraintClauses, this.openBraceToken, this.members, this.closeBraceToken, this.semicolonToken, GetDiagnostics(), annotations);
+}
+
/// Base list syntax.
internal sealed partial class BaseListSyntax : CSharpSyntaxNode
{
@@ -21618,10 +21848,10 @@ internal sealed partial class ParameterSyntax : BaseParameterSyntax
internal readonly GreenNode? attributeLists;
internal readonly GreenNode? modifiers;
internal readonly TypeSyntax? type;
- internal readonly SyntaxToken identifier;
+ internal readonly SyntaxToken? identifier;
internal readonly EqualsValueClauseSyntax? @default;
- internal ParameterSyntax(SyntaxKind kind, GreenNode? attributeLists, GreenNode? modifiers, TypeSyntax? type, SyntaxToken identifier, EqualsValueClauseSyntax? @default, DiagnosticInfo[]? diagnostics, SyntaxAnnotation[]? annotations)
+ internal ParameterSyntax(SyntaxKind kind, GreenNode? attributeLists, GreenNode? modifiers, TypeSyntax? type, SyntaxToken? identifier, EqualsValueClauseSyntax? @default, DiagnosticInfo[]? diagnostics, SyntaxAnnotation[]? annotations)
: base(kind, diagnostics, annotations)
{
this.SlotCount = 5;
@@ -21640,8 +21870,11 @@ internal ParameterSyntax(SyntaxKind kind, GreenNode? attributeLists, GreenNode?
this.AdjustFlagsAndWidth(type);
this.type = type;
}
- this.AdjustFlagsAndWidth(identifier);
- this.identifier = identifier;
+ if (identifier != null)
+ {
+ this.AdjustFlagsAndWidth(identifier);
+ this.identifier = identifier;
+ }
if (@default != null)
{
this.AdjustFlagsAndWidth(@default);
@@ -21649,7 +21882,7 @@ internal ParameterSyntax(SyntaxKind kind, GreenNode? attributeLists, GreenNode?
}
}
- internal ParameterSyntax(SyntaxKind kind, GreenNode? attributeLists, GreenNode? modifiers, TypeSyntax? type, SyntaxToken identifier, EqualsValueClauseSyntax? @default, SyntaxFactoryContext context)
+ internal ParameterSyntax(SyntaxKind kind, GreenNode? attributeLists, GreenNode? modifiers, TypeSyntax? type, SyntaxToken? identifier, EqualsValueClauseSyntax? @default, SyntaxFactoryContext context)
: base(kind)
{
this.SetFactoryContext(context);
@@ -21669,8 +21902,11 @@ internal ParameterSyntax(SyntaxKind kind, GreenNode? attributeLists, GreenNode?
this.AdjustFlagsAndWidth(type);
this.type = type;
}
- this.AdjustFlagsAndWidth(identifier);
- this.identifier = identifier;
+ if (identifier != null)
+ {
+ this.AdjustFlagsAndWidth(identifier);
+ this.identifier = identifier;
+ }
if (@default != null)
{
this.AdjustFlagsAndWidth(@default);
@@ -21678,7 +21914,7 @@ internal ParameterSyntax(SyntaxKind kind, GreenNode? attributeLists, GreenNode?
}
}
- internal ParameterSyntax(SyntaxKind kind, GreenNode? attributeLists, GreenNode? modifiers, TypeSyntax? type, SyntaxToken identifier, EqualsValueClauseSyntax? @default)
+ internal ParameterSyntax(SyntaxKind kind, GreenNode? attributeLists, GreenNode? modifiers, TypeSyntax? type, SyntaxToken? identifier, EqualsValueClauseSyntax? @default)
: base(kind)
{
this.SlotCount = 5;
@@ -21697,8 +21933,11 @@ internal ParameterSyntax(SyntaxKind kind, GreenNode? attributeLists, GreenNode?
this.AdjustFlagsAndWidth(type);
this.type = type;
}
- this.AdjustFlagsAndWidth(identifier);
- this.identifier = identifier;
+ if (identifier != null)
+ {
+ this.AdjustFlagsAndWidth(identifier);
+ this.identifier = identifier;
+ }
if (@default != null)
{
this.AdjustFlagsAndWidth(@default);
@@ -21712,7 +21951,7 @@ internal ParameterSyntax(SyntaxKind kind, GreenNode? attributeLists, GreenNode?
public override CoreSyntax.SyntaxList Modifiers => new CoreSyntax.SyntaxList(this.modifiers);
public override TypeSyntax? Type => this.type;
/// Gets the identifier.
- public SyntaxToken Identifier => this.identifier;
+ public SyntaxToken? Identifier => this.identifier;
public EqualsValueClauseSyntax? Default => this.@default;
internal override GreenNode? GetSlot(int index)
@@ -26654,6 +26893,7 @@ internal partial class CSharpSyntaxVisitor
public virtual TResult VisitEnumDeclaration(EnumDeclarationSyntax node) => this.DefaultVisit(node);
public virtual TResult VisitDelegateDeclaration(DelegateDeclarationSyntax node) => this.DefaultVisit(node);
public virtual TResult VisitEnumMemberDeclaration(EnumMemberDeclarationSyntax node) => this.DefaultVisit(node);
+ public virtual TResult VisitExtensionDeclaration(ExtensionDeclarationSyntax node) => this.DefaultVisit(node);
public virtual TResult VisitBaseList(BaseListSyntax node) => this.DefaultVisit(node);
public virtual TResult VisitSimpleBaseType(SimpleBaseTypeSyntax node) => this.DefaultVisit(node);
public virtual TResult VisitPrimaryConstructorBaseType(PrimaryConstructorBaseTypeSyntax node) => this.DefaultVisit(node);
@@ -26902,6 +27142,7 @@ internal partial class CSharpSyntaxVisitor
public virtual void VisitEnumDeclaration(EnumDeclarationSyntax node) => this.DefaultVisit(node);
public virtual void VisitDelegateDeclaration(DelegateDeclarationSyntax node) => this.DefaultVisit(node);
public virtual void VisitEnumMemberDeclaration(EnumMemberDeclarationSyntax node) => this.DefaultVisit(node);
+ public virtual void VisitExtensionDeclaration(ExtensionDeclarationSyntax node) => this.DefaultVisit(node);
public virtual void VisitBaseList(BaseListSyntax node) => this.DefaultVisit(node);
public virtual void VisitSimpleBaseType(SimpleBaseTypeSyntax node) => this.DefaultVisit(node);
public virtual void VisitPrimaryConstructorBaseType(PrimaryConstructorBaseTypeSyntax node) => this.DefaultVisit(node);
@@ -27490,6 +27731,9 @@ public override CSharpSyntaxNode VisitDelegateDeclaration(DelegateDeclarationSyn
public override CSharpSyntaxNode VisitEnumMemberDeclaration(EnumMemberDeclarationSyntax node)
=> node.Update(VisitList(node.AttributeLists), VisitList(node.Modifiers), (SyntaxToken)Visit(node.Identifier), (EqualsValueClauseSyntax)Visit(node.EqualsValue));
+ public override CSharpSyntaxNode VisitExtensionDeclaration(ExtensionDeclarationSyntax node)
+ => node.Update(VisitList(node.AttributeLists), VisitList(node.Modifiers), (SyntaxToken)Visit(node.Keyword), (TypeParameterListSyntax)Visit(node.TypeParameterList), (ParameterListSyntax)Visit(node.ParameterList), VisitList(node.ConstraintClauses), (SyntaxToken)Visit(node.OpenBraceToken), VisitList(node.Members), (SyntaxToken)Visit(node.CloseBraceToken), (SyntaxToken)Visit(node.SemicolonToken));
+
public override CSharpSyntaxNode VisitBaseList(BaseListSyntax node)
=> node.Update((SyntaxToken)Visit(node.ColonToken), VisitList(node.Types));
@@ -31416,6 +31660,43 @@ public EnumMemberDeclarationSyntax EnumMemberDeclaration(CoreSyntax.SyntaxList attributeLists, CoreSyntax.SyntaxList modifiers, SyntaxToken keyword, TypeParameterListSyntax? typeParameterList, ParameterListSyntax? parameterList, CoreSyntax.SyntaxList constraintClauses, SyntaxToken? openBraceToken, CoreSyntax.SyntaxList members, SyntaxToken? closeBraceToken, SyntaxToken? semicolonToken)
+ {
+#if DEBUG
+ if (keyword == null) throw new ArgumentNullException(nameof(keyword));
+ if (keyword.Kind != SyntaxKind.ExtensionKeyword) throw new ArgumentException(nameof(keyword));
+ if (openBraceToken != null)
+ {
+ switch (openBraceToken.Kind)
+ {
+ case SyntaxKind.OpenBraceToken:
+ case SyntaxKind.None: break;
+ default: throw new ArgumentException(nameof(openBraceToken));
+ }
+ }
+ if (closeBraceToken != null)
+ {
+ switch (closeBraceToken.Kind)
+ {
+ case SyntaxKind.CloseBraceToken:
+ case SyntaxKind.None: break;
+ default: throw new ArgumentException(nameof(closeBraceToken));
+ }
+ }
+ if (semicolonToken != null)
+ {
+ switch (semicolonToken.Kind)
+ {
+ case SyntaxKind.SemicolonToken:
+ case SyntaxKind.None: break;
+ default: throw new ArgumentException(nameof(semicolonToken));
+ }
+ }
+#endif
+
+ return new ExtensionDeclarationSyntax(SyntaxKind.ExtensionDeclaration, attributeLists.Node, modifiers.Node, keyword, typeParameterList, parameterList, constraintClauses.Node, openBraceToken, members.Node, closeBraceToken, semicolonToken, this.context);
+ }
+
public BaseListSyntax BaseList(SyntaxToken colonToken, CoreSyntax.SeparatedSyntaxList types)
{
#if DEBUG
@@ -32059,15 +32340,18 @@ public BracketedParameterListSyntax BracketedParameterList(SyntaxToken openBrack
return result;
}
- public ParameterSyntax Parameter(CoreSyntax.SyntaxList attributeLists, CoreSyntax.SyntaxList modifiers, TypeSyntax? type, SyntaxToken identifier, EqualsValueClauseSyntax? @default)
+ public ParameterSyntax Parameter(CoreSyntax.SyntaxList attributeLists, CoreSyntax.SyntaxList modifiers, TypeSyntax? type, SyntaxToken? identifier, EqualsValueClauseSyntax? @default)
{
#if DEBUG
- if (identifier == null) throw new ArgumentNullException(nameof(identifier));
- switch (identifier.Kind)
+ if (identifier != null)
{
- case SyntaxKind.IdentifierToken:
- case SyntaxKind.ArgListKeyword: break;
- default: throw new ArgumentException(nameof(identifier));
+ switch (identifier.Kind)
+ {
+ case SyntaxKind.IdentifierToken:
+ case SyntaxKind.ArgListKeyword:
+ case SyntaxKind.None: break;
+ default: throw new ArgumentException(nameof(identifier));
+ }
}
#endif
@@ -36684,6 +36968,43 @@ public static EnumMemberDeclarationSyntax EnumMemberDeclaration(CoreSyntax.Synta
return new EnumMemberDeclarationSyntax(SyntaxKind.EnumMemberDeclaration, attributeLists.Node, modifiers.Node, identifier, equalsValue);
}
+ public static ExtensionDeclarationSyntax ExtensionDeclaration(CoreSyntax.SyntaxList attributeLists, CoreSyntax.SyntaxList modifiers, SyntaxToken keyword, TypeParameterListSyntax? typeParameterList, ParameterListSyntax? parameterList, CoreSyntax.SyntaxList constraintClauses, SyntaxToken? openBraceToken, CoreSyntax.SyntaxList members, SyntaxToken? closeBraceToken, SyntaxToken? semicolonToken)
+ {
+#if DEBUG
+ if (keyword == null) throw new ArgumentNullException(nameof(keyword));
+ if (keyword.Kind != SyntaxKind.ExtensionKeyword) throw new ArgumentException(nameof(keyword));
+ if (openBraceToken != null)
+ {
+ switch (openBraceToken.Kind)
+ {
+ case SyntaxKind.OpenBraceToken:
+ case SyntaxKind.None: break;
+ default: throw new ArgumentException(nameof(openBraceToken));
+ }
+ }
+ if (closeBraceToken != null)
+ {
+ switch (closeBraceToken.Kind)
+ {
+ case SyntaxKind.CloseBraceToken:
+ case SyntaxKind.None: break;
+ default: throw new ArgumentException(nameof(closeBraceToken));
+ }
+ }
+ if (semicolonToken != null)
+ {
+ switch (semicolonToken.Kind)
+ {
+ case SyntaxKind.SemicolonToken:
+ case SyntaxKind.None: break;
+ default: throw new ArgumentException(nameof(semicolonToken));
+ }
+ }
+#endif
+
+ return new ExtensionDeclarationSyntax(SyntaxKind.ExtensionDeclaration, attributeLists.Node, modifiers.Node, keyword, typeParameterList, parameterList, constraintClauses.Node, openBraceToken, members.Node, closeBraceToken, semicolonToken);
+ }
+
public static BaseListSyntax BaseList(SyntaxToken colonToken, CoreSyntax.SeparatedSyntaxList types)
{
#if DEBUG
@@ -37327,15 +37648,18 @@ public static BracketedParameterListSyntax BracketedParameterList(SyntaxToken op
return result;
}
- public static ParameterSyntax Parameter(CoreSyntax.SyntaxList attributeLists, CoreSyntax.SyntaxList modifiers, TypeSyntax? type, SyntaxToken identifier, EqualsValueClauseSyntax? @default)
+ public static ParameterSyntax Parameter(CoreSyntax.SyntaxList attributeLists, CoreSyntax.SyntaxList modifiers, TypeSyntax? type, SyntaxToken? identifier, EqualsValueClauseSyntax? @default)
{
#if DEBUG
- if (identifier == null) throw new ArgumentNullException(nameof(identifier));
- switch (identifier.Kind)
+ if (identifier != null)
{
- case SyntaxKind.IdentifierToken:
- case SyntaxKind.ArgListKeyword: break;
- default: throw new ArgumentException(nameof(identifier));
+ switch (identifier.Kind)
+ {
+ case SyntaxKind.IdentifierToken:
+ case SyntaxKind.ArgListKeyword:
+ case SyntaxKind.None: break;
+ default: throw new ArgumentException(nameof(identifier));
+ }
}
#endif
diff --git a/src/Compilers/CSharp/Portable/Generated/CSharpSyntaxGenerator/CSharpSyntaxGenerator.SourceGenerator/Syntax.xml.Main.Generated.cs b/src/Compilers/CSharp/Portable/Generated/CSharpSyntaxGenerator/CSharpSyntaxGenerator.SourceGenerator/Syntax.xml.Main.Generated.cs
index 0b31bde257994..66df0106254e3 100644
--- a/src/Compilers/CSharp/Portable/Generated/CSharpSyntaxGenerator/CSharpSyntaxGenerator.SourceGenerator/Syntax.xml.Main.Generated.cs
+++ b/src/Compilers/CSharp/Portable/Generated/CSharpSyntaxGenerator/CSharpSyntaxGenerator.SourceGenerator/Syntax.xml.Main.Generated.cs
@@ -525,6 +525,9 @@ public partial class CSharpSyntaxVisitor
/// Called when the visitor visits a EnumMemberDeclarationSyntax node.
public virtual TResult? VisitEnumMemberDeclaration(EnumMemberDeclarationSyntax node) => this.DefaultVisit(node);
+ /// Called when the visitor visits a ExtensionDeclarationSyntax node.
+ public virtual TResult? VisitExtensionDeclaration(ExtensionDeclarationSyntax node) => this.DefaultVisit(node);
+
/// Called when the visitor visits a BaseListSyntax node.
public virtual TResult? VisitBaseList(BaseListSyntax node) => this.DefaultVisit(node);
@@ -1260,6 +1263,9 @@ public partial class CSharpSyntaxVisitor
/// Called when the visitor visits a EnumMemberDeclarationSyntax node.
public virtual void VisitEnumMemberDeclaration(EnumMemberDeclarationSyntax node) => this.DefaultVisit(node);
+ /// Called when the visitor visits a ExtensionDeclarationSyntax node.
+ public virtual void VisitExtensionDeclaration(ExtensionDeclarationSyntax node) => this.DefaultVisit(node);
+
/// Called when the visitor visits a BaseListSyntax node.
public virtual void VisitBaseList(BaseListSyntax node) => this.DefaultVisit(node);
@@ -1995,6 +2001,9 @@ public partial class CSharpSyntaxRewriter : CSharpSyntaxVisitor
public override SyntaxNode? VisitEnumMemberDeclaration(EnumMemberDeclarationSyntax node)
=> node.Update(VisitList(node.AttributeLists), VisitList(node.Modifiers), VisitToken(node.Identifier), (EqualsValueClauseSyntax?)Visit(node.EqualsValue));
+ public override SyntaxNode? VisitExtensionDeclaration(ExtensionDeclarationSyntax node)
+ => node.Update(VisitList(node.AttributeLists), VisitList(node.Modifiers), VisitToken(node.Keyword), (TypeParameterListSyntax?)Visit(node.TypeParameterList), (ParameterListSyntax?)Visit(node.ParameterList), VisitList(node.ConstraintClauses), VisitToken(node.OpenBraceToken), VisitList(node.Members), VisitToken(node.CloseBraceToken), VisitToken(node.SemicolonToken));
+
public override SyntaxNode? VisitBaseList(BaseListSyntax node)
=> node.Update(VisitToken(node.ColonToken), VisitList(node.Types));
@@ -3196,14 +3205,6 @@ public static SimpleLambdaExpressionSyntax SimpleLambdaExpression(SyntaxList(), modifiers.Node.ToGreenList(), (Syntax.InternalSyntax.ParameterSyntax)parameter.Green, (Syntax.InternalSyntax.SyntaxToken)arrowToken.Node!, block == null ? null : (Syntax.InternalSyntax.BlockSyntax)block.Green, expressionBody == null ? null : (Syntax.InternalSyntax.ExpressionSyntax)expressionBody.Green).CreateRed();
}
- /// Creates a new SimpleLambdaExpressionSyntax instance.
- public static SimpleLambdaExpressionSyntax SimpleLambdaExpression(SyntaxList attributeLists, SyntaxTokenList modifiers, ParameterSyntax parameter, BlockSyntax? block, ExpressionSyntax? expressionBody)
- => SyntaxFactory.SimpleLambdaExpression(attributeLists, modifiers, parameter, SyntaxFactory.Token(SyntaxKind.EqualsGreaterThanToken), block, expressionBody);
-
- /// Creates a new SimpleLambdaExpressionSyntax instance.
- public static SimpleLambdaExpressionSyntax SimpleLambdaExpression(ParameterSyntax parameter)
- => SyntaxFactory.SimpleLambdaExpression(default, default(SyntaxTokenList), parameter, SyntaxFactory.Token(SyntaxKind.EqualsGreaterThanToken), default, default);
-
/// Creates a new RefExpressionSyntax instance.
public static RefExpressionSyntax RefExpression(SyntaxToken refKeyword, ExpressionSyntax expression)
{
@@ -5146,6 +5147,39 @@ public static EnumMemberDeclarationSyntax EnumMemberDeclaration(SyntaxToken iden
public static EnumMemberDeclarationSyntax EnumMemberDeclaration(string identifier)
=> SyntaxFactory.EnumMemberDeclaration(default, default(SyntaxTokenList), SyntaxFactory.Identifier(identifier), default);
+ /// Creates a new ExtensionDeclarationSyntax instance.
+ public static ExtensionDeclarationSyntax ExtensionDeclaration(SyntaxList attributeLists, SyntaxTokenList modifiers, SyntaxToken keyword, TypeParameterListSyntax? typeParameterList, ParameterListSyntax? parameterList, SyntaxList constraintClauses, SyntaxToken openBraceToken, SyntaxList members, SyntaxToken closeBraceToken, SyntaxToken semicolonToken)
+ {
+ if (keyword.Kind() != SyntaxKind.ExtensionKeyword) throw new ArgumentException(nameof(keyword));
+ switch (openBraceToken.Kind())
+ {
+ case SyntaxKind.OpenBraceToken:
+ case SyntaxKind.None: break;
+ default: throw new ArgumentException(nameof(openBraceToken));
+ }
+ switch (closeBraceToken.Kind())
+ {
+ case SyntaxKind.CloseBraceToken:
+ case SyntaxKind.None: break;
+ default: throw new ArgumentException(nameof(closeBraceToken));
+ }
+ switch (semicolonToken.Kind())
+ {
+ case SyntaxKind.SemicolonToken:
+ case SyntaxKind.None: break;
+ default: throw new ArgumentException(nameof(semicolonToken));
+ }
+ return (ExtensionDeclarationSyntax)Syntax.InternalSyntax.SyntaxFactory.ExtensionDeclaration(attributeLists.Node.ToGreenList(), modifiers.Node.ToGreenList(), (Syntax.InternalSyntax.SyntaxToken)keyword.Node!, typeParameterList == null ? null : (Syntax.InternalSyntax.TypeParameterListSyntax)typeParameterList.Green, parameterList == null ? null : (Syntax.InternalSyntax.ParameterListSyntax)parameterList.Green, constraintClauses.Node.ToGreenList(), (Syntax.InternalSyntax.SyntaxToken?)openBraceToken.Node, members.Node.ToGreenList(), (Syntax.InternalSyntax.SyntaxToken?)closeBraceToken.Node, (Syntax.InternalSyntax.SyntaxToken?)semicolonToken.Node).CreateRed();
+ }
+
+ /// Creates a new ExtensionDeclarationSyntax instance.
+ public static ExtensionDeclarationSyntax ExtensionDeclaration(SyntaxList attributeLists, SyntaxTokenList modifiers, TypeParameterListSyntax? typeParameterList, ParameterListSyntax? parameterList, SyntaxList constraintClauses, SyntaxList members)
+ => SyntaxFactory.ExtensionDeclaration(attributeLists, modifiers, SyntaxFactory.Token(SyntaxKind.ExtensionKeyword), typeParameterList, parameterList, constraintClauses, default, members, default, default);
+
+ /// Creates a new ExtensionDeclarationSyntax instance.
+ public static ExtensionDeclarationSyntax ExtensionDeclaration()
+ => SyntaxFactory.ExtensionDeclaration(default, default(SyntaxTokenList), SyntaxFactory.Token(SyntaxKind.ExtensionKeyword), default, default, default, default, default, default, default);
+
/// Creates a new BaseListSyntax instance.
public static BaseListSyntax BaseList(SyntaxToken colonToken, SeparatedSyntaxList types)
{
@@ -5718,16 +5752,13 @@ public static ParameterSyntax Parameter(SyntaxList attribut
switch (identifier.Kind())
{
case SyntaxKind.IdentifierToken:
- case SyntaxKind.ArgListKeyword: break;
+ case SyntaxKind.ArgListKeyword:
+ case SyntaxKind.None: break;
default: throw new ArgumentException(nameof(identifier));
}
- return (ParameterSyntax)Syntax.InternalSyntax.SyntaxFactory.Parameter(attributeLists.Node.ToGreenList(), modifiers.Node.ToGreenList(), type == null ? null : (Syntax.InternalSyntax.TypeSyntax)type.Green, (Syntax.InternalSyntax.SyntaxToken)identifier.Node!, @default == null ? null : (Syntax.InternalSyntax.EqualsValueClauseSyntax)@default.Green).CreateRed();
+ return (ParameterSyntax)Syntax.InternalSyntax.SyntaxFactory.Parameter(attributeLists.Node.ToGreenList(), modifiers.Node.ToGreenList(), type == null ? null : (Syntax.InternalSyntax.TypeSyntax)type.Green, (Syntax.InternalSyntax.SyntaxToken?)identifier.Node, @default == null ? null : (Syntax.InternalSyntax.EqualsValueClauseSyntax)@default.Green).CreateRed();
}
- /// Creates a new ParameterSyntax instance.
- public static ParameterSyntax Parameter(SyntaxToken identifier)
- => SyntaxFactory.Parameter(default, default(SyntaxTokenList), default, identifier, default);
-
/// Creates a new FunctionPointerParameterSyntax instance.
public static FunctionPointerParameterSyntax FunctionPointerParameter(SyntaxList attributeLists, SyntaxTokenList modifiers, TypeSyntax type)
{
diff --git a/src/Compilers/CSharp/Portable/Generated/CSharpSyntaxGenerator/CSharpSyntaxGenerator.SourceGenerator/Syntax.xml.Syntax.Generated.cs b/src/Compilers/CSharp/Portable/Generated/CSharpSyntaxGenerator/CSharpSyntaxGenerator.SourceGenerator/Syntax.xml.Syntax.Generated.cs
index 0c97b7c25c0a7..aa66360fb08d8 100644
--- a/src/Compilers/CSharp/Portable/Generated/CSharpSyntaxGenerator/CSharpSyntaxGenerator.SourceGenerator/Syntax.xml.Syntax.Generated.cs
+++ b/src/Compilers/CSharp/Portable/Generated/CSharpSyntaxGenerator/CSharpSyntaxGenerator.SourceGenerator/Syntax.xml.Syntax.Generated.cs
@@ -10261,7 +10261,7 @@ internal BaseTypeDeclarationSyntax(InternalSyntax.CSharpSyntaxNode green, Syntax
public new BaseTypeDeclarationSyntax AddModifiers(params SyntaxToken[] items) => (BaseTypeDeclarationSyntax)AddModifiersCore(items);
}
-/// Base class for type declaration syntax (class, struct, interface, record).
+/// Base class for type declaration syntax (class, struct, interface, record, extension).
public abstract partial class TypeDeclarationSyntax : BaseTypeDeclarationSyntax
{
internal TypeDeclarationSyntax(InternalSyntax.CSharpSyntaxNode green, SyntaxNode? parent, int position)
@@ -10269,7 +10269,7 @@ internal TypeDeclarationSyntax(InternalSyntax.CSharpSyntaxNode green, SyntaxNode
{
}
- /// Gets the type keyword token ("class", "struct", "interface", "record").
+ /// Gets the type keyword token ("class", "struct", "interface", "record", "extension").
public abstract SyntaxToken Keyword { get; }
public TypeDeclarationSyntax WithKeyword(SyntaxToken keyword) => WithKeywordCore(keyword);
internal abstract TypeDeclarationSyntax WithKeywordCore(SyntaxToken keyword);
@@ -11312,6 +11312,154 @@ public EnumMemberDeclarationSyntax Update(SyntaxList attrib
public new EnumMemberDeclarationSyntax AddModifiers(params SyntaxToken[] items) => WithModifiers(this.Modifiers.AddRange(items));
}
+/// Extension container syntax.
+///
+/// This node is associated with the following syntax kinds:
+///
+///
+///
+///
+public sealed partial class ExtensionDeclarationSyntax : TypeDeclarationSyntax
+{
+ private SyntaxNode? attributeLists;
+ private TypeParameterListSyntax? typeParameterList;
+ private ParameterListSyntax? parameterList;
+ private SyntaxNode? constraintClauses;
+ private SyntaxNode? members;
+
+ internal ExtensionDeclarationSyntax(InternalSyntax.CSharpSyntaxNode green, SyntaxNode? parent, int position)
+ : base(green, parent, position)
+ {
+ }
+
+ public override SyntaxList AttributeLists => new SyntaxList(GetRed(ref this.attributeLists, 0));
+
+ public override SyntaxTokenList Modifiers
+ {
+ get
+ {
+ var slot = this.Green.GetSlot(1);
+ return slot != null ? new SyntaxTokenList(this, slot, GetChildPosition(1), GetChildIndex(1)) : default;
+ }
+ }
+
+ public override SyntaxToken Keyword => new SyntaxToken(this, ((InternalSyntax.ExtensionDeclarationSyntax)this.Green).keyword, GetChildPosition(2), GetChildIndex(2));
+
+ public override TypeParameterListSyntax? TypeParameterList => GetRed(ref this.typeParameterList, 3);
+
+ public override ParameterListSyntax? ParameterList => GetRed(ref this.parameterList, 4);
+
+ public override SyntaxList ConstraintClauses => new SyntaxList(GetRed(ref this.constraintClauses, 5));
+
+ public override SyntaxToken OpenBraceToken
+ {
+ get
+ {
+ var slot = ((Syntax.InternalSyntax.ExtensionDeclarationSyntax)this.Green).openBraceToken;
+ return slot != null ? new SyntaxToken(this, slot, GetChildPosition(6), GetChildIndex(6)) : default;
+ }
+ }
+
+ public override SyntaxList Members => new SyntaxList(GetRed(ref this.members, 7));
+
+ public override SyntaxToken CloseBraceToken
+ {
+ get
+ {
+ var slot = ((Syntax.InternalSyntax.ExtensionDeclarationSyntax)this.Green).closeBraceToken;
+ return slot != null ? new SyntaxToken(this, slot, GetChildPosition(8), GetChildIndex(8)) : default;
+ }
+ }
+
+ public override SyntaxToken SemicolonToken
+ {
+ get
+ {
+ var slot = ((Syntax.InternalSyntax.ExtensionDeclarationSyntax)this.Green).semicolonToken;
+ return slot != null ? new SyntaxToken(this, slot, GetChildPosition(9), GetChildIndex(9)) : default;
+ }
+ }
+
+ internal override SyntaxNode? GetNodeSlot(int index)
+ => index switch
+ {
+ 0 => GetRedAtZero(ref this.attributeLists)!,
+ 3 => GetRed(ref this.typeParameterList, 3),
+ 4 => GetRed(ref this.parameterList, 4),
+ 5 => GetRed(ref this.constraintClauses, 5)!,
+ 7 => GetRed(ref this.members, 7)!,
+ _ => null,
+ };
+
+ internal override SyntaxNode? GetCachedSlot(int index)
+ => index switch
+ {
+ 0 => this.attributeLists,
+ 3 => this.typeParameterList,
+ 4 => this.parameterList,
+ 5 => this.constraintClauses,
+ 7 => this.members,
+ _ => null,
+ };
+
+ public override void Accept(CSharpSyntaxVisitor visitor) => visitor.VisitExtensionDeclaration(this);
+ public override TResult? Accept(CSharpSyntaxVisitor visitor) where TResult : default => visitor.VisitExtensionDeclaration(this);
+
+ public ExtensionDeclarationSyntax Update(SyntaxList attributeLists, SyntaxTokenList modifiers, SyntaxToken keyword, TypeParameterListSyntax? typeParameterList, ParameterListSyntax? parameterList, SyntaxList constraintClauses, SyntaxToken openBraceToken, SyntaxList members, SyntaxToken closeBraceToken, SyntaxToken semicolonToken)
+ {
+ if (attributeLists != this.AttributeLists || modifiers != this.Modifiers || keyword != this.Keyword || typeParameterList != this.TypeParameterList || parameterList != this.ParameterList || constraintClauses != this.ConstraintClauses || openBraceToken != this.OpenBraceToken || members != this.Members || closeBraceToken != this.CloseBraceToken || semicolonToken != this.SemicolonToken)
+ {
+ var newNode = SyntaxFactory.ExtensionDeclaration(attributeLists, modifiers, keyword, typeParameterList, parameterList, constraintClauses, openBraceToken, members, closeBraceToken, semicolonToken);
+ var annotations = GetAnnotations();
+ return annotations?.Length > 0 ? newNode.WithAnnotations(annotations) : newNode;
+ }
+
+ return this;
+ }
+
+ internal override MemberDeclarationSyntax WithAttributeListsCore(SyntaxList attributeLists) => WithAttributeLists(attributeLists);
+ public new ExtensionDeclarationSyntax WithAttributeLists(SyntaxList attributeLists) => Update(attributeLists, this.Modifiers, this.Keyword, this.TypeParameterList, this.ParameterList, this.ConstraintClauses, this.OpenBraceToken, this.Members, this.CloseBraceToken, this.SemicolonToken);
+ internal override MemberDeclarationSyntax WithModifiersCore(SyntaxTokenList modifiers) => WithModifiers(modifiers);
+ public new ExtensionDeclarationSyntax WithModifiers(SyntaxTokenList modifiers) => Update(this.AttributeLists, modifiers, this.Keyword, this.TypeParameterList, this.ParameterList, this.ConstraintClauses, this.OpenBraceToken, this.Members, this.CloseBraceToken, this.SemicolonToken);
+ internal override TypeDeclarationSyntax WithKeywordCore(SyntaxToken keyword) => WithKeyword(keyword);
+ public new ExtensionDeclarationSyntax WithKeyword(SyntaxToken keyword) => Update(this.AttributeLists, this.Modifiers, keyword, this.TypeParameterList, this.ParameterList, this.ConstraintClauses, this.OpenBraceToken, this.Members, this.CloseBraceToken, this.SemicolonToken);
+ internal override TypeDeclarationSyntax WithTypeParameterListCore(TypeParameterListSyntax? typeParameterList) => WithTypeParameterList(typeParameterList);
+ public new ExtensionDeclarationSyntax WithTypeParameterList(TypeParameterListSyntax? typeParameterList) => Update(this.AttributeLists, this.Modifiers, this.Keyword, typeParameterList, this.ParameterList, this.ConstraintClauses, this.OpenBraceToken, this.Members, this.CloseBraceToken, this.SemicolonToken);
+ internal override TypeDeclarationSyntax WithParameterListCore(ParameterListSyntax? parameterList) => WithParameterList(parameterList);
+ public new ExtensionDeclarationSyntax WithParameterList(ParameterListSyntax? parameterList) => Update(this.AttributeLists, this.Modifiers, this.Keyword, this.TypeParameterList, parameterList, this.ConstraintClauses, this.OpenBraceToken, this.Members, this.CloseBraceToken, this.SemicolonToken);
+ internal override TypeDeclarationSyntax WithConstraintClausesCore(SyntaxList constraintClauses) => WithConstraintClauses(constraintClauses);
+ public new ExtensionDeclarationSyntax WithConstraintClauses(SyntaxList constraintClauses) => Update(this.AttributeLists, this.Modifiers, this.Keyword, this.TypeParameterList, this.ParameterList, constraintClauses, this.OpenBraceToken, this.Members, this.CloseBraceToken, this.SemicolonToken);
+ internal override BaseTypeDeclarationSyntax WithOpenBraceTokenCore(SyntaxToken openBraceToken) => WithOpenBraceToken(openBraceToken);
+ public new ExtensionDeclarationSyntax WithOpenBraceToken(SyntaxToken openBraceToken) => Update(this.AttributeLists, this.Modifiers, this.Keyword, this.TypeParameterList, this.ParameterList, this.ConstraintClauses, openBraceToken, this.Members, this.CloseBraceToken, this.SemicolonToken);
+ internal override TypeDeclarationSyntax WithMembersCore(SyntaxList members) => WithMembers(members);
+ public new ExtensionDeclarationSyntax WithMembers(SyntaxList members) => Update(this.AttributeLists, this.Modifiers, this.Keyword, this.TypeParameterList, this.ParameterList, this.ConstraintClauses, this.OpenBraceToken, members, this.CloseBraceToken, this.SemicolonToken);
+ internal override BaseTypeDeclarationSyntax WithCloseBraceTokenCore(SyntaxToken closeBraceToken) => WithCloseBraceToken(closeBraceToken);
+ public new ExtensionDeclarationSyntax WithCloseBraceToken(SyntaxToken closeBraceToken) => Update(this.AttributeLists, this.Modifiers, this.Keyword, this.TypeParameterList, this.ParameterList, this.ConstraintClauses, this.OpenBraceToken, this.Members, closeBraceToken, this.SemicolonToken);
+ internal override BaseTypeDeclarationSyntax WithSemicolonTokenCore(SyntaxToken semicolonToken) => WithSemicolonToken(semicolonToken);
+ public new ExtensionDeclarationSyntax WithSemicolonToken(SyntaxToken semicolonToken) => Update(this.AttributeLists, this.Modifiers, this.Keyword, this.TypeParameterList, this.ParameterList, this.ConstraintClauses, this.OpenBraceToken, this.Members, this.CloseBraceToken, semicolonToken);
+
+ internal override MemberDeclarationSyntax AddAttributeListsCore(params AttributeListSyntax[] items) => AddAttributeLists(items);
+ public new ExtensionDeclarationSyntax AddAttributeLists(params AttributeListSyntax[] items) => WithAttributeLists(this.AttributeLists.AddRange(items));
+ internal override MemberDeclarationSyntax AddModifiersCore(params SyntaxToken[] items) => AddModifiers(items);
+ public new ExtensionDeclarationSyntax AddModifiers(params SyntaxToken[] items) => WithModifiers(this.Modifiers.AddRange(items));
+ internal override TypeDeclarationSyntax AddTypeParameterListParametersCore(params TypeParameterSyntax[] items) => AddTypeParameterListParameters(items);
+ public new ExtensionDeclarationSyntax AddTypeParameterListParameters(params TypeParameterSyntax[] items)
+ {
+ var typeParameterList = this.TypeParameterList ?? SyntaxFactory.TypeParameterList();
+ return WithTypeParameterList(typeParameterList.WithParameters(typeParameterList.Parameters.AddRange(items)));
+ }
+ internal override TypeDeclarationSyntax AddParameterListParametersCore(params ParameterSyntax[] items) => AddParameterListParameters(items);
+ public new ExtensionDeclarationSyntax AddParameterListParameters(params ParameterSyntax[] items)
+ {
+ var parameterList = this.ParameterList ?? SyntaxFactory.ParameterList();
+ return WithParameterList(parameterList.WithParameters(parameterList.Parameters.AddRange(items)));
+ }
+ internal override TypeDeclarationSyntax AddConstraintClausesCore(params TypeParameterConstraintClauseSyntax[] items) => AddConstraintClauses(items);
+ public new ExtensionDeclarationSyntax AddConstraintClauses(params TypeParameterConstraintClauseSyntax[] items) => WithConstraintClauses(this.ConstraintClauses.AddRange(items));
+ internal override TypeDeclarationSyntax AddMembersCore(params MemberDeclarationSyntax[] items) => AddMembers(items);
+ public new ExtensionDeclarationSyntax AddMembers(params MemberDeclarationSyntax[] items) => WithMembers(this.Members.AddRange(items));
+}
+
/// Base list syntax.
///
/// This node is associated with the following syntax kinds:
@@ -13636,7 +13784,14 @@ public override SyntaxTokenList Modifiers
public override TypeSyntax? Type => GetRed(ref this.type, 2);
/// Gets the identifier.
- public SyntaxToken Identifier => new SyntaxToken(this, ((InternalSyntax.ParameterSyntax)this.Green).identifier, GetChildPosition(3), GetChildIndex(3));
+ public SyntaxToken Identifier
+ {
+ get
+ {
+ var slot = ((Syntax.InternalSyntax.ParameterSyntax)this.Green).identifier;
+ return slot != null ? new SyntaxToken(this, slot, GetChildPosition(3), GetChildIndex(3)) : default;
+ }
+ }
public EqualsValueClauseSyntax? Default => GetRed(ref this.@default, 4);
diff --git a/src/Compilers/CSharp/Portable/Parser/LanguageParser.cs b/src/Compilers/CSharp/Portable/Parser/LanguageParser.cs
index 12f19f4de2626..e1277d96a3152 100644
--- a/src/Compilers/CSharp/Portable/Parser/LanguageParser.cs
+++ b/src/Compilers/CSharp/Portable/Parser/LanguageParser.cs
@@ -84,7 +84,7 @@ internal enum TerminatorState
IsEndOfFunctionPointerParameterList = 1 << 23,
IsEndOfFunctionPointerParameterListErrored = 1 << 24,
IsEndOfFunctionPointerCallingConvention = 1 << 25,
- IsEndOfRecordOrClassOrStructOrInterfaceSignature = 1 << 26,
+ IsEndOfTypeSignature = 1 << 26,
IsExpressionOrPatternInCaseLabelOfSwitchStatement = 1 << 27,
IsPatternInSwitchExpressionArm = 1 << 28,
}
@@ -128,7 +128,7 @@ private bool IsTerminator()
case TerminatorState.IsEndOfFunctionPointerParameterList when this.IsEndOfFunctionPointerParameterList(errored: false):
case TerminatorState.IsEndOfFunctionPointerParameterListErrored when this.IsEndOfFunctionPointerParameterList(errored: true):
case TerminatorState.IsEndOfFunctionPointerCallingConvention when this.IsEndOfFunctionPointerCallingConvention():
- case TerminatorState.IsEndOfRecordOrClassOrStructOrInterfaceSignature when this.IsEndOfRecordOrClassOrStructOrInterfaceSignature():
+ case TerminatorState.IsEndOfTypeSignature when this.IsEndOfTypeSignature():
return true;
}
}
@@ -1692,13 +1692,13 @@ private MemberDeclarationSyntax ParseTypeDeclaration(SyntaxList attributes, SyntaxListBuilder modifiers)
+ private TypeDeclarationSyntax ParseMainTypeDeclaration(SyntaxList attributes, SyntaxListBuilder modifiers)
{
Debug.Assert(this.CurrentToken.Kind is SyntaxKind.ClassKeyword or SyntaxKind.StructKeyword or SyntaxKind.InterfaceKeyword ||
- this.CurrentToken.ContextualKind == SyntaxKind.RecordKeyword);
+ this.CurrentToken.ContextualKind is SyntaxKind.RecordKeyword or SyntaxKind.ExtensionKeyword);
// "top-level" expressions and statements should never occur inside an asynchronous context
Debug.Assert(!IsInAsync);
@@ -1728,19 +1728,34 @@ private TypeDeclarationSyntax ParseClassOrStructOrInterfaceDeclaration(SyntaxLis
keyword = ConvertToKeyword(this.EatToken());
}
+ bool isExtension = keyword.Kind == SyntaxKind.ExtensionKeyword;
var outerSaveTerm = _termState;
- _termState |= TerminatorState.IsEndOfRecordOrClassOrStructOrInterfaceSignature;
+ _termState |= TerminatorState.IsEndOfTypeSignature;
var saveTerm = _termState;
_termState |= TerminatorState.IsPossibleAggregateClauseStartOrStop;
- var name = this.ParseIdentifierToken();
+ SyntaxToken? name;
+ if (isExtension)
+ {
+ name = null;
+ if (this.CurrentToken.Kind == SyntaxKind.IdentifierToken)
+ {
+ keyword = AddTrailingSkippedSyntax(keyword, this.AddError(this.EatToken(), ErrorCode.ERR_ExtensionDisallowsName));
+ }
+ }
+ else
+ {
+ name = this.ParseIdentifierToken();
+ }
+
var typeParameters = this.ParseTypeParameterList();
- var paramList = CurrentToken.Kind == SyntaxKind.OpenParenToken
- ? ParseParenthesizedParameterList() : null;
+ // For extension declarations, there must be a parameter list
+ var paramList = CurrentToken.Kind == SyntaxKind.OpenParenToken || isExtension
+ ? ParseParenthesizedParameterList(forExtension: isExtension) : null;
- var baseList = this.ParseBaseList();
+ var baseList = isExtension ? null : this.ParseBaseList();
_termState = saveTerm;
// Parse class body
@@ -1882,7 +1897,7 @@ bool tryScanRecordStart([NotNullWhen(true)] out SyntaxToken? keyword, out Syntax
}
static TypeDeclarationSyntax constructTypeDeclaration(ContextAwareSyntax syntaxFactory, SyntaxList attributes, SyntaxListBuilder modifiers, SyntaxToken keyword, SyntaxToken? recordModifier,
- SyntaxToken name, TypeParameterListSyntax typeParameters, ParameterListSyntax? paramList, BaseListSyntax baseList, SyntaxListBuilder constraints,
+ SyntaxToken? name, TypeParameterListSyntax typeParameters, ParameterListSyntax? paramList, BaseListSyntax? baseList, SyntaxListBuilder constraints,
SyntaxToken? openBrace, SyntaxListBuilder members, SyntaxToken? closeBrace, SyntaxToken semicolon)
{
var modifiersList = (SyntaxList)modifiers.ToList();
@@ -1891,6 +1906,7 @@ static TypeDeclarationSyntax constructTypeDeclaration(ContextAwareSyntax syntaxF
switch (keyword.Kind)
{
case SyntaxKind.ClassKeyword:
+ Debug.Assert(name is not null);
return syntaxFactory.ClassDeclaration(
attributes,
modifiersList,
@@ -1906,6 +1922,7 @@ static TypeDeclarationSyntax constructTypeDeclaration(ContextAwareSyntax syntaxF
semicolon);
case SyntaxKind.StructKeyword:
+ Debug.Assert(name is not null);
return syntaxFactory.StructDeclaration(
attributes,
modifiersList,
@@ -1921,6 +1938,7 @@ static TypeDeclarationSyntax constructTypeDeclaration(ContextAwareSyntax syntaxF
semicolon);
case SyntaxKind.InterfaceKeyword:
+ Debug.Assert(name is not null);
return syntaxFactory.InterfaceDeclaration(
attributes,
modifiersList,
@@ -1939,6 +1957,7 @@ static TypeDeclarationSyntax constructTypeDeclaration(ContextAwareSyntax syntaxF
// record struct ...
// record ...
// record class ...
+ Debug.Assert(name is not null);
SyntaxKind declarationKind = recordModifier?.Kind == SyntaxKind.StructKeyword ? SyntaxKind.RecordStructDeclaration : SyntaxKind.RecordDeclaration;
return syntaxFactory.RecordDeclaration(
declarationKind,
@@ -1956,6 +1975,21 @@ static TypeDeclarationSyntax constructTypeDeclaration(ContextAwareSyntax syntaxF
closeBrace,
semicolon);
+ case SyntaxKind.ExtensionKeyword:
+ Debug.Assert(name is null);
+ Debug.Assert(baseList is null);
+ return syntaxFactory.ExtensionDeclaration(
+ attributes,
+ modifiers.ToList(),
+ keyword,
+ typeParameters,
+ paramList,
+ constraints,
+ openBrace,
+ members,
+ closeBrace,
+ semicolon);
+
default:
throw ExceptionUtilities.UnexpectedValue(keyword.Kind);
}
@@ -2053,8 +2087,8 @@ private bool IsPossibleAggregateClauseStartOrStop()
private BaseListSyntax ParseBaseList()
{
- // We are only called from ParseClassOrStructOrInterfaceDeclaration which unilaterally sets this.
- Debug.Assert((_termState & TerminatorState.IsEndOfRecordOrClassOrStructOrInterfaceSignature) != 0);
+ // We are only called from ParseMainTypeDeclaration which unilaterally sets this.
+ Debug.Assert((_termState & TerminatorState.IsEndOfTypeSignature) != 0);
var colon = this.TryEatToken(SyntaxKind.ColonToken);
if (colon == null)
@@ -2163,7 +2197,7 @@ private TypeParameterConstraintClauseSyntax ParseTypeParameterConstraintClause()
bool haveComma;
if (this.CurrentToken.Kind == SyntaxKind.OpenBraceToken
- || ((_termState & TerminatorState.IsEndOfRecordOrClassOrStructOrInterfaceSignature) != 0 && this.CurrentToken.Kind == SyntaxKind.SemicolonToken)
+ || ((_termState & TerminatorState.IsEndOfTypeSignature) != 0 && this.CurrentToken.Kind == SyntaxKind.SemicolonToken)
|| this.CurrentToken.Kind == SyntaxKind.EqualsGreaterThanToken
|| this.CurrentToken.ContextualKind == SyntaxKind.WhereKeyword)
{
@@ -2389,6 +2423,12 @@ private bool IsTypeDeclarationStart()
// older code that is not using C# 9 we conditionally parse based on langversion
return IsFeatureEnabled(MessageID.IDS_FeatureRecords);
}
+
+ if (IsExtensionContainerStart())
+ {
+ return true;
+ }
+
return false;
default:
@@ -3064,6 +3104,11 @@ private MemberDeclarationSyntax ParseMemberDeclarationCore(SyntaxKind parentKind
bool isPossibleTypeDeclaration;
this.ParseModifiers(modifiers, forAccessors: false, forTopLevelStatements: false, out isPossibleTypeDeclaration);
+ if (IsExtensionContainerStart())
+ {
+ return this.ParseMainTypeDeclaration(attributes, modifiers);
+ }
+
// Check for constructor form
if (this.CurrentToken.Kind == SyntaxKind.IdentifierToken && this.PeekToken(1).Kind == SyntaxKind.OpenParenToken)
{
@@ -3193,6 +3238,11 @@ private MemberDeclarationSyntax ParseMemberDeclarationCore(SyntaxKind parentKind
}
}
+ private bool IsExtensionContainerStart()
+ {
+ return this.CurrentToken.ContextualKind == SyntaxKind.ExtensionKeyword && IsFeatureEnabled(MessageID.IDS_FeatureExtensions);
+ }
+
// if the modifiers do not contain async or replace and the type is the identifier "async" or "replace", then
// add that identifier to the modifiers and assign a new type from the identifierOrThisOpt and the
// type parameter list
@@ -3307,7 +3357,7 @@ private ConstructorDeclarationSyntax ParseConstructorDeclaration(
_termState |= TerminatorState.IsEndOfMethodSignature;
try
{
- var paramList = this.ParseParenthesizedParameterList();
+ var paramList = this.ParseParenthesizedParameterList(forExtension: false);
var initializer = this.CurrentToken.Kind == SyntaxKind.ColonToken
? this.ParseConstructorInitializer()
: null;
@@ -3447,7 +3497,7 @@ private bool IsEndOfTypeParameterList()
private bool IsEndOfMethodSignature()
=> this.CurrentToken.Kind is SyntaxKind.SemicolonToken or SyntaxKind.OpenBraceToken;
- private bool IsEndOfRecordOrClassOrStructOrInterfaceSignature()
+ private bool IsEndOfTypeSignature()
{
return this.CurrentToken.Kind is SyntaxKind.SemicolonToken or SyntaxKind.OpenBraceToken;
}
@@ -3473,7 +3523,7 @@ private MethodDeclarationSyntax ParseMethodDeclaration(
var saveTerm = _termState;
_termState |= TerminatorState.IsEndOfMethodSignature;
- var paramList = this.ParseParenthesizedParameterList();
+ var paramList = this.ParseParenthesizedParameterList(forExtension: false);
var constraints = default(SyntaxListBuilder);
if (this.CurrentToken.ContextualKind == SyntaxKind.WhereKeyword)
@@ -3685,7 +3735,7 @@ private ConversionOperatorDeclarationSyntax TryParseConversionOperatorDeclaratio
type = ParseIdentifierName();
}
- var paramList = this.ParseParenthesizedParameterList();
+ var paramList = this.ParseParenthesizedParameterList(forExtension: false);
this.ParseBlockAndExpressionBodiesWithSemicolon(out var blockBody, out var expressionBody, out var semicolon);
@@ -3889,7 +3939,7 @@ private MemberDeclarationSyntax ParseOperatorDeclaration(
}
}
- var paramList = this.ParseParenthesizedParameterList();
+ var paramList = this.ParseParenthesizedParameterList(forExtension: false);
switch (paramList.Parameters.Count)
{
@@ -4502,14 +4552,14 @@ private static SyntaxKind GetAccessorKind(SyntaxToken accessorName)
};
}
- internal ParameterListSyntax ParseParenthesizedParameterList()
+ internal ParameterListSyntax ParseParenthesizedParameterList(bool forExtension)
{
- if (this.IsIncrementalAndFactoryContextMatches && CanReuseParameterList(this.CurrentNode as CSharp.Syntax.ParameterListSyntax))
+ if (this.IsIncrementalAndFactoryContextMatches && CanReuseParameterList(this.CurrentNode as CSharp.Syntax.ParameterListSyntax, allowOptionalIdentifier: forExtension))
{
return (ParameterListSyntax)this.EatNode();
}
- var parameters = this.ParseParameterList(out var open, out var close, SyntaxKind.OpenParenToken, SyntaxKind.CloseParenToken);
+ var parameters = this.ParseParameterList(out var open, out var close, SyntaxKind.OpenParenToken, SyntaxKind.CloseParenToken, forExtension);
return _syntaxFactory.ParameterList(open, parameters, close);
}
@@ -4520,11 +4570,11 @@ internal BracketedParameterListSyntax ParseBracketedParameterList()
return (BracketedParameterListSyntax)this.EatNode();
}
- var parameters = this.ParseParameterList(out var open, out var close, SyntaxKind.OpenBracketToken, SyntaxKind.CloseBracketToken);
+ var parameters = this.ParseParameterList(out var open, out var close, SyntaxKind.OpenBracketToken, SyntaxKind.CloseBracketToken, forExtension: false);
return _syntaxFactory.BracketedParameterList(open, parameters, close);
}
- private static bool CanReuseParameterList(CSharp.Syntax.ParameterListSyntax list)
+ private static bool CanReuseParameterList(Syntax.ParameterListSyntax list, bool allowOptionalIdentifier)
{
if (list == null)
{
@@ -4543,7 +4593,7 @@ private static bool CanReuseParameterList(CSharp.Syntax.ParameterListSyntax list
foreach (var parameter in list.Parameters)
{
- if (!CanReuseParameter(parameter))
+ if (!CanReuseParameter(parameter, allowOptionalIdentifier))
{
return false;
}
@@ -4552,7 +4602,7 @@ private static bool CanReuseParameterList(CSharp.Syntax.ParameterListSyntax list
return true;
}
- private static bool CanReuseBracketedParameterList(CSharp.Syntax.BracketedParameterListSyntax list)
+ private static bool CanReuseBracketedParameterList(Syntax.BracketedParameterListSyntax list)
{
if (list == null)
{
@@ -4571,7 +4621,7 @@ private static bool CanReuseBracketedParameterList(CSharp.Syntax.BracketedParame
foreach (var parameter in list.Parameters)
{
- if (!CanReuseParameter(parameter))
+ if (!CanReuseParameter(parameter, allowOptionalIdentifier: false))
{
return false;
}
@@ -4584,22 +4634,28 @@ private SeparatedSyntaxList ParseParameterList(
out SyntaxToken open,
out SyntaxToken close,
SyntaxKind openKind,
- SyntaxKind closeKind)
+ SyntaxKind closeKind,
+ bool forExtension)
{
open = this.EatToken(openKind);
var saveTerm = _termState;
_termState |= TerminatorState.IsEndOfParameterList;
+ Func parseElement = forExtension
+ ? static @this => @this.ParseParameter(allowOptionalIdentifier: true)
+ : static @this => @this.ParseParameter(allowOptionalIdentifier: false);
+
var parameters = ParseCommaSeparatedSyntaxList(
ref open,
closeKind,
static @this => @this.IsPossibleParameter(),
- static @this => @this.ParseParameter(),
+ parseElement,
skipBadParameterListTokens,
allowTrailingSeparator: false,
- requireOneElement: false,
+ requireOneElement: forExtension, // For extension declarations, we require at least one receiver parameter
allowSemicolonAsSeparator: false);
+ // PROTOTYPE consider suppressing parsing diagnostics on extension parameters beyond the first one
_termState = saveTerm;
close = this.EatToken(closeKind);
@@ -4639,7 +4695,7 @@ private bool IsPossibleParameter()
}
}
- private static bool CanReuseParameter(CSharp.Syntax.ParameterSyntax parameter)
+ private static bool CanReuseParameter(CSharp.Syntax.ParameterSyntax parameter, bool allowOptionalIdentifier)
{
if (parameter == null)
{
@@ -4670,14 +4726,22 @@ private static bool CanReuseParameter(CSharp.Syntax.ParameterSyntax parameter)
}
}
+ // We can only reuse parameters without identifiers (found in extension declarations) in context that allow optional identifiers.
+ // The reverse is fine though. Normal parameters (from non extensions) can be re-used into an extension declaration
+ // as all normal parameters are legal extension parameters.
+ if (!allowOptionalIdentifier && parameter.Identifier.Kind() == SyntaxKind.None)
+ {
+ return false;
+ }
+
return true;
}
#nullable enable
- private ParameterSyntax ParseParameter()
+ private ParameterSyntax ParseParameter(bool allowOptionalIdentifier)
{
- if (this.IsIncrementalAndFactoryContextMatches && CanReuseParameter(this.CurrentNode as CSharp.Syntax.ParameterSyntax))
+ if (this.IsIncrementalAndFactoryContextMatches && CanReuseParameter(this.CurrentNode as Syntax.ParameterSyntax, allowOptionalIdentifier))
{
return (ParameterSyntax)this.EatNode();
}
@@ -4696,19 +4760,22 @@ private ParameterSyntax ParseParameter()
}
var type = this.ParseType(mode: ParseTypeMode.Parameter);
- SyntaxToken identifier;
+ SyntaxToken? identifier;
if (this.CurrentToken.Kind == SyntaxKind.IdentifierToken && IsCurrentTokenWhereOfConstraintClause())
{
- identifier = this.AddError(CreateMissingIdentifierToken(), ErrorCode.ERR_IdentifierExpected);
+ identifier = allowOptionalIdentifier ? null : this.AddError(CreateMissingIdentifierToken(), ErrorCode.ERR_IdentifierExpected);
}
else
{
- identifier = this.ParseIdentifierToken();
+ // The receiver parameter on an extension declaration may have a name or not
+ identifier = allowOptionalIdentifier && this.CurrentToken.Kind != SyntaxKind.IdentifierToken
+ ? null
+ : this.ParseIdentifierToken();
}
// When the user type "int goo[]", give them a useful error
- if (this.CurrentToken.Kind is SyntaxKind.OpenBracketToken && this.PeekToken(1).Kind is SyntaxKind.CloseBracketToken)
+ if (identifier is not null && this.CurrentToken.Kind is SyntaxKind.OpenBracketToken && this.PeekToken(1).Kind is SyntaxKind.CloseBracketToken)
{
identifier = AddTrailingSkippedSyntax(identifier, SyntaxList.List(
this.AddError(this.EatToken(), ErrorCode.ERR_BadArraySyntax),
@@ -5442,7 +5509,7 @@ private bool IsLocalFunctionAfterIdentifier()
using var _ = this.GetDisposableResetPoint(resetOnDispose: true);
var typeParameterListOpt = this.ParseTypeParameterList();
- var paramList = ParseParenthesizedParameterList();
+ var paramList = ParseParenthesizedParameterList(forExtension: false);
if (!paramList.IsMissing &&
(this.CurrentToken.Kind is SyntaxKind.OpenBraceToken or SyntaxKind.EqualsGreaterThanToken ||
@@ -5502,7 +5569,7 @@ private DelegateDeclarationSyntax ParseDelegateDeclaration(SyntaxList);
if (this.CurrentToken.ContextualKind == SyntaxKind.WhereKeyword)
@@ -8429,7 +8496,7 @@ private bool IsPossibleMethodDeclarationFollowingNullableType()
var saveTerm = _termState;
_termState |= TerminatorState.IsEndOfMethodSignature;
- var paramList = this.ParseParenthesizedParameterList();
+ var paramList = this.ParseParenthesizedParameterList(forExtension: false);
_termState = saveTerm;
var separatedParameters = paramList.Parameters.GetWithSeparators();
@@ -10540,7 +10607,7 @@ private LocalFunctionStatementSyntax TryParseLocalFunctionStatementBody(
TypeParameterListSyntax typeParameterListOpt = this.ParseTypeParameterList();
// "await f()" still makes sense, so don't force accept a local function if there's a type parameter list.
- ParameterListSyntax paramList = this.ParseParenthesizedParameterList();
+ ParameterListSyntax paramList = this.ParseParenthesizedParameterList(forExtension: false);
// "await x()" is ambiguous (see note at start of this method), but we assume "await x(await y)" is meant to be a function if it's in a non-async context.
if (!forceLocalFunc)
{
@@ -13186,7 +13253,7 @@ AnonymousMethodExpressionSyntax parseAnonymousMethodExpressionWorker()
ParameterListSyntax parameterList = null;
if (this.CurrentToken.Kind == SyntaxKind.OpenParenToken)
{
- parameterList = this.ParseParenthesizedParameterList();
+ parameterList = this.ParseParenthesizedParameterList(forExtension: false);
}
// In mismatched braces cases (missing a }) it is possible for delegate declarations to be
@@ -13261,7 +13328,7 @@ private bool IsAnonymousFunctionAsyncModifier()
return true;
case var kind:
return IsPredefinedType(kind);
- };
+ }
}
///
diff --git a/src/Compilers/CSharp/Portable/PublicAPI.Unshipped.txt b/src/Compilers/CSharp/Portable/PublicAPI.Unshipped.txt
index 0ebff1a371642..5f122b7e67c97 100644
--- a/src/Compilers/CSharp/Portable/PublicAPI.Unshipped.txt
+++ b/src/Compilers/CSharp/Portable/PublicAPI.Unshipped.txt
@@ -1,5 +1,25 @@
Microsoft.CodeAnalysis.CSharp.Conversion.IsSpan.get -> bool
Microsoft.CodeAnalysis.CSharp.LanguageVersion.CSharp13 = 1300 -> Microsoft.CodeAnalysis.CSharp.LanguageVersion
+Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax
+Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax.AddAttributeLists(params Microsoft.CodeAnalysis.CSharp.Syntax.AttributeListSyntax![]! items) -> Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax!
+Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax.AddConstraintClauses(params Microsoft.CodeAnalysis.CSharp.Syntax.TypeParameterConstraintClauseSyntax![]! items) -> Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax!
+Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax.AddMembers(params Microsoft.CodeAnalysis.CSharp.Syntax.MemberDeclarationSyntax![]! items) -> Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax!
+Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax.AddModifiers(params Microsoft.CodeAnalysis.SyntaxToken[]! items) -> Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax!
+Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax.AddParameterListParameters(params Microsoft.CodeAnalysis.CSharp.Syntax.ParameterSyntax![]! items) -> Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax!
+Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax.AddTypeParameterListParameters(params Microsoft.CodeAnalysis.CSharp.Syntax.TypeParameterSyntax![]! items) -> Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax!
+Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax.Update(Microsoft.CodeAnalysis.SyntaxList attributeLists, Microsoft.CodeAnalysis.SyntaxTokenList modifiers, Microsoft.CodeAnalysis.SyntaxToken keyword, Microsoft.CodeAnalysis.CSharp.Syntax.TypeParameterListSyntax? typeParameterList, Microsoft.CodeAnalysis.CSharp.Syntax.ParameterListSyntax? parameterList, Microsoft.CodeAnalysis.SyntaxList constraintClauses, Microsoft.CodeAnalysis.SyntaxToken openBraceToken, Microsoft.CodeAnalysis.SyntaxList members, Microsoft.CodeAnalysis.SyntaxToken closeBraceToken, Microsoft.CodeAnalysis.SyntaxToken semicolonToken) -> Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax!
+Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax.WithAttributeLists(Microsoft.CodeAnalysis.SyntaxList attributeLists) -> Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax!
+Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax.WithCloseBraceToken(Microsoft.CodeAnalysis.SyntaxToken closeBraceToken) -> Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax!
+Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax.WithConstraintClauses(Microsoft.CodeAnalysis.SyntaxList constraintClauses) -> Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax!
+Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax.WithKeyword(Microsoft.CodeAnalysis.SyntaxToken keyword) -> Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax!
+Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax.WithMembers(Microsoft.CodeAnalysis.SyntaxList members) -> Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax!
+Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax.WithModifiers(Microsoft.CodeAnalysis.SyntaxTokenList modifiers) -> Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax!
+Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax.WithOpenBraceToken(Microsoft.CodeAnalysis.SyntaxToken openBraceToken) -> Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax!
+Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax.WithParameterList(Microsoft.CodeAnalysis.CSharp.Syntax.ParameterListSyntax? parameterList) -> Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax!
+Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax.WithSemicolonToken(Microsoft.CodeAnalysis.SyntaxToken semicolonToken) -> Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax!
+Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax.WithTypeParameterList(Microsoft.CodeAnalysis.CSharp.Syntax.TypeParameterListSyntax? typeParameterList) -> Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax!
+Microsoft.CodeAnalysis.CSharp.SyntaxKind.ExtensionDeclaration = 9079 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind
+Microsoft.CodeAnalysis.CSharp.SyntaxKind.ExtensionKeyword = 8451 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind
Microsoft.CodeAnalysis.CSharp.InterceptableLocation
abstract Microsoft.CodeAnalysis.CSharp.InterceptableLocation.Data.get -> string!
abstract Microsoft.CodeAnalysis.CSharp.InterceptableLocation.GetDisplayLocation() -> string!
@@ -7,8 +27,28 @@ abstract Microsoft.CodeAnalysis.CSharp.InterceptableLocation.Version.get -> int
Microsoft.CodeAnalysis.CSharp.SyntaxKind.RazorContentToken = 8523 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind
override abstract Microsoft.CodeAnalysis.CSharp.InterceptableLocation.Equals(object? obj) -> bool
override abstract Microsoft.CodeAnalysis.CSharp.InterceptableLocation.GetHashCode() -> int
+override Microsoft.CodeAnalysis.CSharp.CSharpSyntaxRewriter.VisitExtensionDeclaration(Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax! node) -> Microsoft.CodeAnalysis.SyntaxNode?
+override Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax.Accept(Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor! visitor) -> void
+override Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax.Accept(Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor! visitor) -> TResult?
+override Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax.AttributeLists.get -> Microsoft.CodeAnalysis.SyntaxList
+override Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax.BaseList.get -> Microsoft.CodeAnalysis.CSharp.Syntax.BaseListSyntax?
+override Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax.CloseBraceToken.get -> Microsoft.CodeAnalysis.SyntaxToken
+override Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax.ConstraintClauses.get -> Microsoft.CodeAnalysis.SyntaxList
+override Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax.Identifier.get -> Microsoft.CodeAnalysis.SyntaxToken
+override Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax.Keyword.get -> Microsoft.CodeAnalysis.SyntaxToken
+override Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax.Members.get -> Microsoft.CodeAnalysis.SyntaxList
+override Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax.Modifiers.get -> Microsoft.CodeAnalysis.SyntaxTokenList
+override Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax.OpenBraceToken.get -> Microsoft.CodeAnalysis.SyntaxToken
+override Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax.ParameterList.get -> Microsoft.CodeAnalysis.CSharp.Syntax.ParameterListSyntax?
+override Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax.SemicolonToken.get -> Microsoft.CodeAnalysis.SyntaxToken
+override Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax.TypeParameterList.get -> Microsoft.CodeAnalysis.CSharp.Syntax.TypeParameterListSyntax?
static Microsoft.CodeAnalysis.CSharp.CSharpExtensions.GetInterceptableLocation(this Microsoft.CodeAnalysis.SemanticModel? semanticModel, Microsoft.CodeAnalysis.CSharp.Syntax.InvocationExpressionSyntax! node, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> Microsoft.CodeAnalysis.CSharp.InterceptableLocation?
static Microsoft.CodeAnalysis.CSharp.CSharpExtensions.GetInterceptsLocationAttributeSyntax(this Microsoft.CodeAnalysis.CSharp.InterceptableLocation! location) -> string!
+static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.ExtensionDeclaration() -> Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax!
+static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.ExtensionDeclaration(Microsoft.CodeAnalysis.SyntaxList attributeLists, Microsoft.CodeAnalysis.SyntaxTokenList modifiers, Microsoft.CodeAnalysis.CSharp.Syntax.TypeParameterListSyntax? typeParameterList, Microsoft.CodeAnalysis.CSharp.Syntax.ParameterListSyntax? parameterList, Microsoft.CodeAnalysis.SyntaxList constraintClauses, Microsoft.CodeAnalysis.SyntaxList members) -> Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax!
+static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.ExtensionDeclaration(Microsoft.CodeAnalysis.SyntaxList attributeLists, Microsoft.CodeAnalysis.SyntaxTokenList modifiers, Microsoft.CodeAnalysis.SyntaxToken keyword, Microsoft.CodeAnalysis.CSharp.Syntax.TypeParameterListSyntax? typeParameterList, Microsoft.CodeAnalysis.CSharp.Syntax.ParameterListSyntax? parameterList, Microsoft.CodeAnalysis.SyntaxList constraintClauses, Microsoft.CodeAnalysis.SyntaxToken openBraceToken, Microsoft.CodeAnalysis.SyntaxList members, Microsoft.CodeAnalysis.SyntaxToken closeBraceToken, Microsoft.CodeAnalysis.SyntaxToken semicolonToken) -> Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax!
+virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitExtensionDeclaration(Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax! node) -> void
+virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitExtensionDeclaration(Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax! node) -> TResult?
[RSEXPERIMENTAL003]Microsoft.CodeAnalysis.CSharp.SyntaxTokenParser
[RSEXPERIMENTAL003]Microsoft.CodeAnalysis.CSharp.SyntaxTokenParser.Dispose() -> void
[RSEXPERIMENTAL003]Microsoft.CodeAnalysis.CSharp.SyntaxTokenParser.ParseLeadingTrivia() -> Microsoft.CodeAnalysis.CSharp.SyntaxTokenParser.Result
diff --git a/src/Compilers/CSharp/Portable/Syntax/ExtensionDeclarationSyntax.cs b/src/Compilers/CSharp/Portable/Syntax/ExtensionDeclarationSyntax.cs
new file mode 100644
index 0000000000000..b6b919098d81b
--- /dev/null
+++ b/src/Compilers/CSharp/Portable/Syntax/ExtensionDeclarationSyntax.cs
@@ -0,0 +1,22 @@
+// 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.
+
+namespace Microsoft.CodeAnalysis.CSharp.Syntax
+{
+ public partial class ExtensionDeclarationSyntax
+ {
+ public override SyntaxToken Identifier => default;
+
+ internal override BaseTypeDeclarationSyntax WithIdentifierCore(SyntaxToken identifier)
+ => throw new System.NotSupportedException();
+
+ public override BaseListSyntax? BaseList => null;
+
+ internal override BaseTypeDeclarationSyntax AddBaseListTypesCore(params BaseTypeSyntax[] items)
+ => throw new System.NotSupportedException();
+
+ internal override BaseTypeDeclarationSyntax WithBaseListCore(BaseListSyntax? baseList)
+ => throw new System.NotSupportedException();
+ }
+}
diff --git a/src/Compilers/CSharp/Portable/Syntax/InternalSyntax/TypeDeclarationSyntax.cs b/src/Compilers/CSharp/Portable/Syntax/InternalSyntax/TypeDeclarationSyntax.cs
index b41530c1f7a5d..6750b331260e9 100644
--- a/src/Compilers/CSharp/Portable/Syntax/InternalSyntax/TypeDeclarationSyntax.cs
+++ b/src/Compilers/CSharp/Portable/Syntax/InternalSyntax/TypeDeclarationSyntax.cs
@@ -4,6 +4,7 @@
#nullable disable
+using Roslyn.Utilities;
using CoreSyntax = Microsoft.CodeAnalysis.Syntax.InternalSyntax;
namespace Microsoft.CodeAnalysis.CSharp.Syntax.InternalSyntax
@@ -153,4 +154,47 @@ public override TypeDeclarationSyntax UpdateCore(
semicolonToken);
}
}
+
+ internal partial class ExtensionDeclarationSyntax
+ {
+ public override TypeDeclarationSyntax UpdateCore(
+ CoreSyntax.SyntaxList attributeLists,
+ CoreSyntax.SyntaxList modifiers,
+ SyntaxToken keyword,
+ SyntaxToken identifier,
+ TypeParameterListSyntax typeParameterList,
+ ParameterListSyntax parameterList,
+ BaseListSyntax baseList,
+ CoreSyntax.SyntaxList constraintClauses,
+ SyntaxToken openBraceToken,
+ CoreSyntax.SyntaxList members,
+ SyntaxToken closeBraceToken,
+ SyntaxToken semicolonToken)
+ {
+ if (identifier is not null)
+ {
+ throw ExceptionUtilities.Unreachable();
+ }
+
+ if (baseList is not null)
+ {
+ throw ExceptionUtilities.Unreachable();
+ }
+
+ return this.Update(
+ attributeLists,
+ modifiers,
+ keyword,
+ typeParameterList,
+ parameterList,
+ constraintClauses,
+ openBraceToken,
+ members,
+ closeBraceToken,
+ semicolonToken);
+ }
+
+ public override SyntaxToken Identifier => null;
+ public override BaseListSyntax BaseList => null;
+ }
}
diff --git a/src/Compilers/CSharp/Portable/Syntax/ParameterDeclarationSyntax.cs b/src/Compilers/CSharp/Portable/Syntax/ParameterDeclarationSyntax.cs
new file mode 100644
index 0000000000000..44e699e832c3f
--- /dev/null
+++ b/src/Compilers/CSharp/Portable/Syntax/ParameterDeclarationSyntax.cs
@@ -0,0 +1,16 @@
+// 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.Syntax;
+
+namespace Microsoft.CodeAnalysis.CSharp
+{
+ public partial class SyntaxFactory
+ {
+ /// Creates a new ParameterSyntax instance.
+ public static ParameterSyntax Parameter(SyntaxToken identifier)
+ => SyntaxFactory.Parameter(default, default(SyntaxTokenList), null, identifier, null);
+ }
+}
+
diff --git a/src/Compilers/CSharp/Portable/Syntax/SimpleLambdaExpressionSyntax.cs b/src/Compilers/CSharp/Portable/Syntax/SimpleLambdaExpressionSyntax.cs
index 7e070e3fe7c8b..dbd917f946cc9 100644
--- a/src/Compilers/CSharp/Portable/Syntax/SimpleLambdaExpressionSyntax.cs
+++ b/src/Compilers/CSharp/Portable/Syntax/SimpleLambdaExpressionSyntax.cs
@@ -39,6 +39,14 @@ namespace Microsoft.CodeAnalysis.CSharp
{
public partial class SyntaxFactory
{
+ /// Creates a new SimpleLambdaExpressionSyntax instance.
+ public static SimpleLambdaExpressionSyntax SimpleLambdaExpression(SyntaxList attributeLists, SyntaxTokenList modifiers, ParameterSyntax parameter, BlockSyntax? block, ExpressionSyntax? expressionBody)
+ => SyntaxFactory.SimpleLambdaExpression(attributeLists, modifiers, parameter, SyntaxFactory.Token(SyntaxKind.EqualsGreaterThanToken), block, expressionBody);
+
+ /// Creates a new SimpleLambdaExpressionSyntax instance.
+ public static SimpleLambdaExpressionSyntax SimpleLambdaExpression(ParameterSyntax parameter)
+ => SyntaxFactory.SimpleLambdaExpression(default, default(SyntaxTokenList), parameter, SyntaxFactory.Token(SyntaxKind.EqualsGreaterThanToken), null, null);
+
public static SimpleLambdaExpressionSyntax SimpleLambdaExpression(SyntaxToken asyncKeyword, ParameterSyntax parameter, SyntaxToken arrowToken, BlockSyntax? block, ExpressionSyntax? expressionBody)
=> SimpleLambdaExpression(attributeLists: default, TokenList(asyncKeyword), parameter, arrowToken, block, expressionBody);
diff --git a/src/Compilers/CSharp/Portable/Syntax/Syntax.xml b/src/Compilers/CSharp/Portable/Syntax/Syntax.xml
index 8e05ae9fee8b7..2d86da2a20261 100644
--- a/src/Compilers/CSharp/Portable/Syntax/Syntax.xml
+++ b/src/Compilers/CSharp/Portable/Syntax/Syntax.xml
@@ -1440,7 +1440,7 @@
-
+
@@ -3352,7 +3352,7 @@
Base class for type declaration syntax.
-
+
Gets the identifier.
@@ -3384,11 +3384,11 @@
- Base class for type declaration syntax (class, struct, interface, record).
+ Base class for type declaration syntax (class, struct, interface, record, extension).
- Gets the type keyword token ("class", "struct", "interface", "record").
+ Gets the type keyword token ("class", "struct", "interface", "record", "extension").
@@ -3617,6 +3617,30 @@
+
+
+ Extension container syntax.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Base list syntax.
@@ -4307,7 +4331,7 @@
-
+
Parameter syntax.
@@ -4323,7 +4347,8 @@
-
+
+
Gets the identifier.
diff --git a/src/Compilers/CSharp/Portable/Syntax/SyntaxFactory.cs b/src/Compilers/CSharp/Portable/Syntax/SyntaxFactory.cs
index 5c7b02cdd3254..a1cbe33a1b30f 100644
--- a/src/Compilers/CSharp/Portable/Syntax/SyntaxFactory.cs
+++ b/src/Compilers/CSharp/Portable/Syntax/SyntaxFactory.cs
@@ -1817,7 +1817,7 @@ public static ParameterListSyntax ParseParameterList(string text, int offset = 0
using (var lexer = MakeLexer(text, offset, (CSharpParseOptions?)options))
using (var parser = MakeParser(lexer))
{
- var node = parser.ParseParenthesizedParameterList();
+ var node = parser.ParseParenthesizedParameterList(forExtension: false);
if (consumeFullText) node = parser.ConsumeUnexpectedTokens(node);
return (ParameterListSyntax)node.CreateRed();
}
diff --git a/src/Compilers/CSharp/Portable/Syntax/SyntaxKind.cs b/src/Compilers/CSharp/Portable/Syntax/SyntaxKind.cs
index d697c4c2202be..d110fee28917e 100644
--- a/src/Compilers/CSharp/Portable/Syntax/SyntaxKind.cs
+++ b/src/Compilers/CSharp/Portable/Syntax/SyntaxKind.cs
@@ -421,6 +421,8 @@ public enum SyntaxKind : ushort
FileKeyword = 8449,
/// Represents .
AllowsKeyword = 8450,
+ /// Represents .
+ ExtensionKeyword = 8451,
// when adding a contextual keyword following functions must be adapted:
//
@@ -925,5 +927,7 @@ public enum SyntaxKind : ushort
CollectionExpression = 9076,
ExpressionElement = 9077,
SpreadElement = 9078,
+
+ ExtensionDeclaration = 9079,
}
}
diff --git a/src/Compilers/CSharp/Portable/Syntax/SyntaxKindFacts.cs b/src/Compilers/CSharp/Portable/Syntax/SyntaxKindFacts.cs
index 17382780cb90e..46cf10aa83278 100644
--- a/src/Compilers/CSharp/Portable/Syntax/SyntaxKindFacts.cs
+++ b/src/Compilers/CSharp/Portable/Syntax/SyntaxKindFacts.cs
@@ -1166,7 +1166,7 @@ public static SyntaxKind GetPreprocessorKeywordKind(string text)
public static IEnumerable GetContextualKeywordKinds()
{
- for (int i = (int)SyntaxKind.YieldKeyword; i <= (int)SyntaxKind.AllowsKeyword; i++)
+ for (int i = (int)SyntaxKind.YieldKeyword; i <= (int)SyntaxKind.ExtensionKeyword; i++)
{
// 8441 corresponds to a deleted kind (DataKeyword) that was previously shipped.
if (i != 8441)
@@ -1228,6 +1228,7 @@ public static bool IsContextualKeyword(SyntaxKind kind)
case SyntaxKind.ScopedKeyword:
case SyntaxKind.FileKeyword:
case SyntaxKind.AllowsKeyword:
+ case SyntaxKind.ExtensionKeyword:
return true;
default:
return false;
@@ -1355,6 +1356,8 @@ public static SyntaxKind GetContextualKeywordKind(string text)
return SyntaxKind.FileKeyword;
case "allows":
return SyntaxKind.AllowsKeyword;
+ case "extension":
+ return SyntaxKind.ExtensionKeyword;
default:
return SyntaxKind.None;
}
@@ -1802,6 +1805,8 @@ public static string GetText(SyntaxKind kind)
return "file";
case SyntaxKind.AllowsKeyword:
return "allows";
+ case SyntaxKind.ExtensionKeyword:
+ return "extension";
default:
return string.Empty;
}
diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf
index f9beb8f61f97b..d771b28ccc4ec 100644
--- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf
+++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf
@@ -757,6 +757,11 @@
Strom výrazů nesmí obsahovat výraz with.
+
+
+ Extension declarations may not have a name.
+
+
{0}: Externí událost nemůže mít inicializátor.
@@ -2422,6 +2427,11 @@
vzory rozšířených vlastností
+
+
+ extensions
+
+
klíčové slovo pole
@@ -8907,8 +8917,8 @@ Blok catch() po bloku catch (System.Exception e) může zachytit výjimky, kter
-
- Neplatný token {0} v deklaraci člena rozhraní, třídy, záznamu nebo struktury
+
+ Neplatný token {0} v deklaraci člena rozhraní, třídy, záznamu nebo struktury
diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf
index f67d28a8bb90d..2fc7e06de4d54 100644
--- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf
+++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf
@@ -757,6 +757,11 @@
Eine Ausdrucksbaumstruktur darf keinen with-Ausdruck enthalten.
+
+
+ Extension declarations may not have a name.
+
+
"{0}": Externes Ereignis darf keinen Initialisierer aufweisen.
@@ -2422,6 +2427,11 @@
Muster für erweiterte Eigenschaften
+
+
+ extensions
+
+
Feld Schlüsselwort
@@ -8907,8 +8917,8 @@ Ein catch()-Block nach einem catch (System.Exception e)-Block kann nicht-CLS-Aus
-
- Ungültiges Token "{0}" in Klassen-, Datensatz-, Struktur- oder Schnittstellenmemberdeklaration
+
+ Ungültiges Token "{0}" in Klassen-, Datensatz-, Struktur- oder Schnittstellenmemberdeklaration
diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf
index 97ad7e39a3a67..523b525596346 100644
--- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf
+++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf
@@ -757,6 +757,11 @@
Un árbol de expresión no puede contener una expresión with.
+
+
+ Extension declarations may not have a name.
+
+
"{0}": un evento externo no puede tener un inicializador
@@ -2422,6 +2427,11 @@
patrones de propiedad extendidos
+
+
+ extensions
+
+
palabra clave field
@@ -8907,8 +8917,8 @@ Un bloque catch() después de un bloque catch (System.Exception e) puede abarcar
-
- El token "{0}" no es válido en una clase, un registro, una estructura o una declaración de miembro de interfaz
+
+ El token "{0}" no es válido en una clase, un registro, una estructura o una declaración de miembro de interfaz
diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf
index 6c4bc747be0fc..7383e0cf667c8 100644
--- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf
+++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf
@@ -757,6 +757,11 @@
Une arborescence de l'expression ne peut pas contenir d'expression with.
+
+
+ Extension declarations may not have a name.
+
+
'{0}' : un événement extern ne peut pas avoir d'initialiseur
@@ -2422,6 +2427,11 @@
modèles de propriétés étendues
+
+
+ extensions
+
+
mot-clé du champ
@@ -8907,8 +8917,8 @@ Un bloc catch() après un bloc catch (System.Exception e) peut intercepter des e
-
- Jeton '{0}' non valide dans la déclaration de membre de classe, d'enregistrement, de struct ou d'interface
+
+ Jeton '{0}' non valide dans la déclaration de membre de classe, d'enregistrement, de struct ou d'interface
diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf
index 8ac91c37499e7..abed7030e83f3 100644
--- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf
+++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf
@@ -757,6 +757,11 @@
Un albero delle espressioni non può contenere un'espressione with.
+
+
+ Extension declarations may not have a name.
+
+
'{0}': l'evento extern non può avere inizializzatori
@@ -2422,6 +2427,11 @@
criteri di proprietà estesa
+
+
+ extensions
+
+
parola chiave campo
@@ -8907,8 +8917,8 @@ Un blocco catch() dopo un blocco catch (System.Exception e) può rilevare eccezi
-
- Il token '{0}' nella dichiarazione del membro di classe, record, struct o interfaccia non è valido
+
+ Il token '{0}' nella dichiarazione del membro di classe, record, struct o interfaccia non è valido
diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf
index 1435728a114fc..7f18696497376 100644
--- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf
+++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf
@@ -757,6 +757,11 @@
式ツリーは、with 式を含むことはできません
+
+
+ Extension declarations may not have a name.
+
+
'{0}': extern イベントは初期化子を持つことができません
@@ -2422,6 +2427,11 @@
拡張プロパティ パターン
+
+
+ extensions
+
+
field キーワード
@@ -8907,8 +8917,8 @@ AssemblyInfo.cs ファイルで RuntimeCompatibilityAttribute が false に設
-
- クラス、レコード、構造体、またはインターフェイス メンバーの宣言でトークン '{0}' が無効です
+
+ クラス、レコード、構造体、またはインターフェイス メンバーの宣言でトークン '{0}' が無効です
diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf
index d4c4a339c7929..e34d54bccda34 100644
--- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf
+++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf
@@ -757,6 +757,11 @@
식 트리에는 with 식이 포함될 수 없습니다.
+
+
+ Extension declarations may not have a name.
+
+
'{0}': extern 이벤트에는 이니셜라이저를 사용할 수 없습니다.
@@ -2422,6 +2427,11 @@
확장 속성 패턴
+
+
+ extensions
+
+
필드 키워드
@@ -8907,8 +8917,8 @@ catch (System.Exception e) 블록 뒤의 catch() 블록은 RuntimeCompatibilityA
-
- 클래스, 레코드, 구조체 또는 인터페이스 멤버 선언에 잘못된 토큰 '{0}'이(가) 있습니다.
+
+ 클래스, 레코드, 구조체 또는 인터페이스 멤버 선언에 잘못된 토큰 '{0}'이(가) 있습니다.
diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf
index 242fa39cf7703..0189c6cfdbb7a 100644
--- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf
+++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf
@@ -757,6 +757,11 @@
Drzewo wyrażeń nie może zawierać wyrażenia with.
+
+
+ Extension declarations may not have a name.
+
+
„{0}”: zdarzenie extern nie może mieć inicjatora
@@ -2422,6 +2427,11 @@
wzorce właściwości rozszerzonych
+
+
+ extensions
+
+
słowo kluczowe pola
@@ -8907,8 +8917,8 @@ Blok catch() po bloku catch (System.Exception e) może przechwytywać wyjątki n
-
- Nieprawidłowy token „{0}” w deklaracji składowej klasy, rekordu, struktury lub interfejsu
+
+ Nieprawidłowy token „{0}” w deklaracji składowej klasy, rekordu, struktury lub interfejsu
diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf
index aecc0953a73cf..0939296d30e53 100644
--- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf
+++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf
@@ -757,6 +757,11 @@
Uma árvore de expressão não pode conter uma expressão with.
+
+
+ Extension declarations may not have a name.
+
+
'{0}': o evento externo não pode ter inicializador
@@ -2422,6 +2427,11 @@
padrões de propriedade estendida
+
+
+ extensions
+
+
campo palavra-chave
@@ -8907,8 +8917,8 @@ Um bloco catch() depois de um bloco catch (System.Exception e) poderá capturar
-
- Token inválido '{0}' na declaração de membro de classe, de registro, de struct ou de interface
+
+ Token inválido '{0}' na declaração de membro de classe, de registro, de struct ou de interface
diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf
index f01a4b78a48da..702b2f26094ea 100644
--- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf
+++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf
@@ -757,6 +757,11 @@
Дерево выражения не может содержать выражение with.
+
+
+ Extension declarations may not have a name.
+
+
"{0}": внешнее событие не может иметь инициализатор
@@ -2422,6 +2427,11 @@
шаблоны расширенных свойств
+
+
+ extensions
+
+
ключевое слово поля
@@ -8908,8 +8918,8 @@ A catch() block after a catch (System.Exception e) block can catch non-CLS excep
-
- Недопустимый токен "{0}" в объявлении класса, записи, структуры или элемента интерфейса
+
+ Недопустимый токен "{0}" в объявлении класса, записи, структуры или элемента интерфейса
diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf
index 96e2fa7558ec1..bb9d1866d880e 100644
--- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf
+++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf
@@ -757,6 +757,11 @@
İfade ağacı, with ifadesi içeremez.
+
+
+ Extension declarations may not have a name.
+
+
'{0}': dış etkinliğin başlatıcısı olamaz
@@ -2422,6 +2427,11 @@
genişletilmiş özellik desenleri
+
+
+ extensions
+
+
alan anahtar sözcüğü
@@ -8907,8 +8917,8 @@ RuntimeCompatibilityAttribute AssemblyInfo.cs dosyasında false olarak ayarlanm
-
- Sınıf, kayıt, yapı veya arabirim üye bildiriminde '{0}' belirteci geçersiz
+
+ Sınıf, kayıt, yapı veya arabirim üye bildiriminde '{0}' belirteci geçersiz
diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf
index 2ff45997e4afb..7e487541e5f36 100644
--- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf
+++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf
@@ -757,6 +757,11 @@
表达式树不能包含 with 表达式。
+
+
+ Extension declarations may not have a name.
+
+
“{0}”: 外部事件不能有初始值设定项
@@ -2422,6 +2427,11 @@
扩展的属性模式
+
+
+ extensions
+
+
字段关键字
@@ -8907,8 +8917,8 @@ A catch() block after a catch (System.Exception e) block can catch non-CLS excep
-
- 类、记录、结构或接口成员声明中的标记“{0}”无效
+
+ 类、记录、结构或接口成员声明中的标记“{0}”无效
diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf
index ec8fad7250765..de89a093f15b7 100644
--- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf
+++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf
@@ -757,6 +757,11 @@
運算式樹狀架構不得包含 with 運算式。
+
+
+ Extension declarations may not have a name.
+
+
'{0}': 外部事件不可有初始設定式
@@ -2422,6 +2427,11 @@
擴充屬性模式
+
+
+ extensions
+
+
欄位關鍵字
@@ -8907,8 +8917,8 @@ A catch() block after a catch (System.Exception e) block can catch non-CLS excep
-
- 類別、記錄、結構或介面成員宣告中的語彙基元 '{0}' 無效
+
+ 類別、記錄、結構或介面成員宣告中的語彙基元 '{0}' 無效
diff --git a/src/Compilers/CSharp/Test/Emit3/Diagnostics/DiagnosticAnalyzerTests.AllInOne.cs b/src/Compilers/CSharp/Test/Emit3/Diagnostics/DiagnosticAnalyzerTests.AllInOne.cs
index 971a72c210829..b2901f9adeb50 100644
--- a/src/Compilers/CSharp/Test/Emit3/Diagnostics/DiagnosticAnalyzerTests.AllInOne.cs
+++ b/src/Compilers/CSharp/Test/Emit3/Diagnostics/DiagnosticAnalyzerTests.AllInOne.cs
@@ -36,6 +36,8 @@ public void DiagnosticAnalyzerAllInOne()
missingSyntaxKinds.Add(SyntaxKind.CollectionExpression);
missingSyntaxKinds.Add(SyntaxKind.ExpressionElement);
missingSyntaxKinds.Add(SyntaxKind.SpreadElement);
+ // PROTOTYPE Add to all-in-one
+ missingSyntaxKinds.Add(SyntaxKind.ExtensionDeclaration);
var analyzer = new CSharpTrackingDiagnosticAnalyzer();
var options = new AnalyzerOptions(new[] { new TestAdditionalText() }.ToImmutableArray());
diff --git a/src/Compilers/CSharp/Test/Syntax/Generated/Syntax.Test.xml.Generated.cs b/src/Compilers/CSharp/Test/Syntax/Generated/Syntax.Test.xml.Generated.cs
index 88f2342f45eec..604aa3566ef2d 100644
--- a/src/Compilers/CSharp/Test/Syntax/Generated/Syntax.Test.xml.Generated.cs
+++ b/src/Compilers/CSharp/Test/Syntax/Generated/Syntax.Test.xml.Generated.cs
@@ -520,6 +520,9 @@ private static Syntax.InternalSyntax.DelegateDeclarationSyntax GenerateDelegateD
private static Syntax.InternalSyntax.EnumMemberDeclarationSyntax GenerateEnumMemberDeclaration()
=> InternalSyntaxFactory.EnumMemberDeclaration(new Microsoft.CodeAnalysis.Syntax.InternalSyntax.SyntaxList(), new Microsoft.CodeAnalysis.Syntax.InternalSyntax.SyntaxList(), InternalSyntaxFactory.Identifier("Identifier"), null);
+ private static Syntax.InternalSyntax.ExtensionDeclarationSyntax GenerateExtensionDeclaration()
+ => InternalSyntaxFactory.ExtensionDeclaration(new Microsoft.CodeAnalysis.Syntax.InternalSyntax.SyntaxList(), new Microsoft.CodeAnalysis.Syntax.InternalSyntax.SyntaxList(), InternalSyntaxFactory.Token(SyntaxKind.ExtensionKeyword), null, null, new Microsoft.CodeAnalysis.Syntax.InternalSyntax.SyntaxList(), null, new Microsoft.CodeAnalysis.Syntax.InternalSyntax.SyntaxList(), null, null);
+
private static Syntax.InternalSyntax.BaseListSyntax GenerateBaseList()
=> InternalSyntaxFactory.BaseList(InternalSyntaxFactory.Token(SyntaxKind.ColonToken), new Microsoft.CodeAnalysis.Syntax.InternalSyntax.SeparatedSyntaxList());
@@ -602,7 +605,7 @@ private static Syntax.InternalSyntax.BracketedParameterListSyntax GenerateBracke
=> InternalSyntaxFactory.BracketedParameterList(InternalSyntaxFactory.Token(SyntaxKind.OpenBracketToken), new Microsoft.CodeAnalysis.Syntax.InternalSyntax.SeparatedSyntaxList(), InternalSyntaxFactory.Token(SyntaxKind.CloseBracketToken));
private static Syntax.InternalSyntax.ParameterSyntax GenerateParameter()
- => InternalSyntaxFactory.Parameter(new Microsoft.CodeAnalysis.Syntax.InternalSyntax.SyntaxList(), new Microsoft.CodeAnalysis.Syntax.InternalSyntax.SyntaxList(), null, InternalSyntaxFactory.Identifier("Identifier"), null);
+ => InternalSyntaxFactory.Parameter(new Microsoft.CodeAnalysis.Syntax.InternalSyntax.SyntaxList(), new Microsoft.CodeAnalysis.Syntax.InternalSyntax.SyntaxList(), null, null, null);
private static Syntax.InternalSyntax.FunctionPointerParameterSyntax GenerateFunctionPointerParameter()
=> InternalSyntaxFactory.FunctionPointerParameter(new Microsoft.CodeAnalysis.Syntax.InternalSyntax.SyntaxList(), new Microsoft.CodeAnalysis.Syntax.InternalSyntax.SyntaxList(), GenerateIdentifierName());
@@ -2891,6 +2894,25 @@ public void TestEnumMemberDeclarationFactoryAndProperties()
AttachAndCheckDiagnostics(node);
}
+ [Fact]
+ public void TestExtensionDeclarationFactoryAndProperties()
+ {
+ var node = GenerateExtensionDeclaration();
+
+ Assert.Equal(default, node.AttributeLists);
+ Assert.Equal(default, node.Modifiers);
+ Assert.Equal(SyntaxKind.ExtensionKeyword, node.Keyword.Kind);
+ Assert.Null(node.TypeParameterList);
+ Assert.Null(node.ParameterList);
+ Assert.Equal(default, node.ConstraintClauses);
+ Assert.Null(node.OpenBraceToken);
+ Assert.Equal(default, node.Members);
+ Assert.Null(node.CloseBraceToken);
+ Assert.Null(node.SemicolonToken);
+
+ AttachAndCheckDiagnostics(node);
+ }
+
[Fact]
public void TestBaseListFactoryAndProperties()
{
@@ -3268,7 +3290,7 @@ public void TestParameterFactoryAndProperties()
Assert.Equal(default, node.AttributeLists);
Assert.Equal(default, node.Modifiers);
Assert.Null(node.Type);
- Assert.Equal(SyntaxKind.IdentifierToken, node.Identifier.Kind);
+ Assert.Null(node.Identifier);
Assert.Null(node.Default);
AttachAndCheckDiagnostics(node);
@@ -8297,6 +8319,32 @@ public void TestEnumMemberDeclarationIdentityRewriter()
Assert.Same(oldNode, newNode);
}
+ [Fact]
+ public void TestExtensionDeclarationTokenDeleteRewriter()
+ {
+ var oldNode = GenerateExtensionDeclaration();
+ var rewriter = new TokenDeleteRewriter();
+ var newNode = rewriter.Visit(oldNode);
+
+ if(!oldNode.IsMissing)
+ {
+ Assert.NotEqual(oldNode, newNode);
+ }
+
+ Assert.NotNull(newNode);
+ Assert.True(newNode.IsMissing, "No tokens => missing");
+ }
+
+ [Fact]
+ public void TestExtensionDeclarationIdentityRewriter()
+ {
+ var oldNode = GenerateExtensionDeclaration();
+ var rewriter = new IdentityRewriter();
+ var newNode = rewriter.Visit(oldNode);
+
+ Assert.Same(oldNode, newNode);
+ }
+
[Fact]
public void TestBaseListTokenDeleteRewriter()
{
@@ -10736,6 +10784,9 @@ private static DelegateDeclarationSyntax GenerateDelegateDeclaration()
private static EnumMemberDeclarationSyntax GenerateEnumMemberDeclaration()
=> SyntaxFactory.EnumMemberDeclaration(new SyntaxList(), new SyntaxTokenList(), SyntaxFactory.Identifier("Identifier"), default(EqualsValueClauseSyntax));
+ private static ExtensionDeclarationSyntax GenerateExtensionDeclaration()
+ => SyntaxFactory.ExtensionDeclaration(new SyntaxList(), new SyntaxTokenList(), SyntaxFactory.Token(SyntaxKind.ExtensionKeyword), default(TypeParameterListSyntax), default(ParameterListSyntax), new SyntaxList(), default(SyntaxToken), new SyntaxList(), default(SyntaxToken), default(SyntaxToken));
+
private static BaseListSyntax GenerateBaseList()
=> SyntaxFactory.BaseList(SyntaxFactory.Token(SyntaxKind.ColonToken), new SeparatedSyntaxList());
@@ -10818,7 +10869,7 @@ private static BracketedParameterListSyntax GenerateBracketedParameterList()
=> SyntaxFactory.BracketedParameterList(SyntaxFactory.Token(SyntaxKind.OpenBracketToken), new SeparatedSyntaxList(), SyntaxFactory.Token(SyntaxKind.CloseBracketToken));
private static ParameterSyntax GenerateParameter()
- => SyntaxFactory.Parameter(new SyntaxList(), new SyntaxTokenList(), default(TypeSyntax), SyntaxFactory.Identifier("Identifier"), default(EqualsValueClauseSyntax));
+ => SyntaxFactory.Parameter(new SyntaxList(), new SyntaxTokenList(), default(TypeSyntax), default(SyntaxToken), default(EqualsValueClauseSyntax));
private static FunctionPointerParameterSyntax GenerateFunctionPointerParameter()
=> SyntaxFactory.FunctionPointerParameter(new SyntaxList(), new SyntaxTokenList(), GenerateIdentifierName());
@@ -13107,6 +13158,25 @@ public void TestEnumMemberDeclarationFactoryAndProperties()
Assert.Equal(node, newNode);
}
+ [Fact]
+ public void TestExtensionDeclarationFactoryAndProperties()
+ {
+ var node = GenerateExtensionDeclaration();
+
+ Assert.Equal(default, node.AttributeLists);
+ Assert.Equal(default, node.Modifiers);
+ Assert.Equal(SyntaxKind.ExtensionKeyword, node.Keyword.Kind());
+ Assert.Null(node.TypeParameterList);
+ Assert.Null(node.ParameterList);
+ Assert.Equal(default, node.ConstraintClauses);
+ Assert.Equal(SyntaxKind.None, node.OpenBraceToken.Kind());
+ Assert.Equal(default, node.Members);
+ Assert.Equal(SyntaxKind.None, node.CloseBraceToken.Kind());
+ Assert.Equal(SyntaxKind.None, node.SemicolonToken.Kind());
+ var newNode = node.WithAttributeLists(node.AttributeLists).WithModifiers(node.Modifiers).WithKeyword(node.Keyword).WithTypeParameterList(node.TypeParameterList).WithParameterList(node.ParameterList).WithConstraintClauses(node.ConstraintClauses).WithOpenBraceToken(node.OpenBraceToken).WithMembers(node.Members).WithCloseBraceToken(node.CloseBraceToken).WithSemicolonToken(node.SemicolonToken);
+ Assert.Equal(node, newNode);
+ }
+
[Fact]
public void TestBaseListFactoryAndProperties()
{
@@ -13484,7 +13554,7 @@ public void TestParameterFactoryAndProperties()
Assert.Equal(default, node.AttributeLists);
Assert.Equal(default, node.Modifiers);
Assert.Null(node.Type);
- Assert.Equal(SyntaxKind.IdentifierToken, node.Identifier.Kind());
+ Assert.Equal(SyntaxKind.None, node.Identifier.Kind());
Assert.Null(node.Default);
var newNode = node.WithAttributeLists(node.AttributeLists).WithModifiers(node.Modifiers).WithType(node.Type).WithIdentifier(node.Identifier).WithDefault(node.Default);
Assert.Equal(node, newNode);
@@ -18513,6 +18583,32 @@ public void TestEnumMemberDeclarationIdentityRewriter()
Assert.Same(oldNode, newNode);
}
+ [Fact]
+ public void TestExtensionDeclarationTokenDeleteRewriter()
+ {
+ var oldNode = GenerateExtensionDeclaration();
+ var rewriter = new TokenDeleteRewriter();
+ var newNode = rewriter.Visit(oldNode);
+
+ if(!oldNode.IsMissing)
+ {
+ Assert.NotEqual(oldNode, newNode);
+ }
+
+ Assert.NotNull(newNode);
+ Assert.True(newNode.IsMissing, "No tokens => missing");
+ }
+
+ [Fact]
+ public void TestExtensionDeclarationIdentityRewriter()
+ {
+ var oldNode = GenerateExtensionDeclaration();
+ var rewriter = new IdentityRewriter();
+ var newNode = rewriter.Visit(oldNode);
+
+ Assert.Same(oldNode, newNode);
+ }
+
[Fact]
public void TestBaseListTokenDeleteRewriter()
{
diff --git a/src/Compilers/CSharp/Test/Syntax/IncrementalParsing/IncrementalParsingTests.cs b/src/Compilers/CSharp/Test/Syntax/IncrementalParsing/IncrementalParsingTests.cs
index 9b02ce60e8227..b133bb0333a74 100644
--- a/src/Compilers/CSharp/Test/Syntax/IncrementalParsing/IncrementalParsingTests.cs
+++ b/src/Compilers/CSharp/Test/Syntax/IncrementalParsing/IncrementalParsingTests.cs
@@ -9,6 +9,8 @@
using System.Linq;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.CSharp.Test.Utilities;
+using Microsoft.CodeAnalysis.PooledObjects;
+using Microsoft.CodeAnalysis.Test.Utilities;
using Microsoft.CodeAnalysis.Text;
using Roslyn.Test.Utilities;
using Xunit;
@@ -104,27 +106,35 @@ public void TestChangeClassNameToNotMatchConstructor()
TestDiffsInOrder(diffs,
SyntaxKind.CompilationUnit,
SyntaxKind.ClassDeclaration,
- SyntaxKind.IdentifierToken,
- SyntaxKind.MethodDeclaration,
- SyntaxKind.PredefinedType,
- SyntaxKind.VoidKeyword);
+ SyntaxKind.IdentifierToken);
}
- private static void TestDiffsInOrder(ImmutableArray diffs, params SyntaxKind[] kinds)
+ private static void TestDiffsInOrder(ImmutableArray diffs, params SyntaxKind[] expectedKinds)
{
- Assert.InRange(diffs.Length, 0, kinds.Length);
+ if (diffs.Length != expectedKinds.Length)
+ {
+ Assert.Fail(getMessage());
+ }
- int diffI = 0;
- foreach (var kind in kinds)
+ for (int i = 0; i < diffs.Length; i++)
{
- if (diffI < diffs.Length && diffs[diffI].IsKind(kind))
+ if (!diffs[i].IsKind(expectedKinds[i]))
{
- diffI++;
+ Assert.Fail(getMessage());
}
}
- // all diffs must be consumed.
- Assert.Equal(diffI, diffs.Length);
+ string getMessage()
+ {
+ var builder = PooledStringBuilder.GetInstance();
+ builder.Builder.AppendLine("Actual:");
+ foreach (var diff in diffs)
+ {
+ builder.Builder.AppendLine($"SyntaxKind.{diff.Kind()},");
+ }
+
+ return builder.ToStringAndFree();
+ }
}
[Fact]
@@ -140,8 +150,7 @@ public void TestChangeClassNameToMatchConstructor()
TestDiffsInOrder(diffs,
SyntaxKind.CompilationUnit,
SyntaxKind.ClassDeclaration,
- SyntaxKind.IdentifierToken,
- SyntaxKind.ConstructorDeclaration);
+ SyntaxKind.IdentifierToken);
}
[Fact]
@@ -226,7 +235,6 @@ public void TestChangeMethodName()
SyntaxKind.CompilationUnit,
SyntaxKind.ClassDeclaration,
SyntaxKind.MethodDeclaration,
- SyntaxKind.PredefinedType,
SyntaxKind.IdentifierToken);
}
@@ -294,11 +302,8 @@ class C { void N() { } }
SyntaxKind.CompilationUnit,
SyntaxKind.ClassDeclaration,
SyntaxKind.ClassKeyword,
- SyntaxKind.IdentifierToken,
SyntaxKind.MethodDeclaration,
- SyntaxKind.PredefinedType,
SyntaxKind.IdentifierToken,
- SyntaxKind.ParameterList,
SyntaxKind.Block,
SyntaxKind.EndOfFileToken);
}
@@ -377,7 +382,6 @@ class C { void c() { } }
SyntaxKind.CompilationUnit,
SyntaxKind.ClassDeclaration, // class declaration on edge before change
SyntaxKind.MethodDeclaration,
- SyntaxKind.PredefinedType,
SyntaxKind.Block,
SyntaxKind.ClassDeclaration, // class declaration on edge after change
SyntaxKind.ClassKeyword, // edge of change and directives different
@@ -421,7 +425,6 @@ class C { void c() { } }
SyntaxKind.CompilationUnit,
SyntaxKind.ClassDeclaration, // class declaration on edge before change
SyntaxKind.MethodDeclaration,
- SyntaxKind.PredefinedType,
SyntaxKind.Block,
SyntaxKind.ClassDeclaration, // class declaration on edge after change
SyntaxKind.ClassKeyword, // edge of change and directives different
@@ -442,11 +445,9 @@ public void TestGlobalStatementToStatementChange()
SyntaxKind.GlobalStatement,
SyntaxKind.Block,
SyntaxKind.OpenBraceToken,
- SyntaxKind.EmptyStatement,
SyntaxKind.LocalDeclarationStatement,
SyntaxKind.VariableDeclaration,
SyntaxKind.PointerType,
- SyntaxKind.IdentifierName,
SyntaxKind.VariableDeclarator,
SyntaxKind.SemicolonToken, // missing
SyntaxKind.CloseBraceToken); // missing
@@ -464,12 +465,10 @@ public void TestStatementToGlobalStatementChange()
TestDiffsInOrder(diffs,
SyntaxKind.CompilationUnit,
SyntaxKind.GlobalStatement,
- SyntaxKind.EmptyStatement,
SyntaxKind.GlobalStatement,
SyntaxKind.ExpressionStatement,
SyntaxKind.MultiplyExpression,
SyntaxKind.IdentifierName,
- SyntaxKind.IdentifierName,
SyntaxKind.SemicolonToken);
}
@@ -846,6 +845,437 @@ public void M2()
WalkTreeAndVerify(withCloseBraceDeletedTree.GetCompilationUnitRoot(), fullTree.GetCompilationUnitRoot());
}
+ [Fact, CompilerTrait(CompilerFeature.Extensions)]
+ public void UpdateFromExtensionToClass()
+ {
+ var text = @"
+class C
+{
+ extension(object x) { }
+}
+";
+ var oldTree = this.Parse(text, LanguageVersionFacts.CSharpNext);
+ var newTree = oldTree.WithReplaceFirst("extension", "class D");
+ oldTree.GetDiagnostics().Verify();
+ newTree.GetDiagnostics().Verify();
+
+ var diffs = SyntaxDifferences.GetRebuiltNodes(oldTree, newTree);
+ TestDiffsInOrder(diffs,
+ SyntaxKind.CompilationUnit,
+ SyntaxKind.ClassDeclaration,
+ SyntaxKind.ClassDeclaration,
+ SyntaxKind.ClassKeyword,
+ SyntaxKind.IdentifierToken);
+
+ UsingTree(newTree);
+
+ N(SyntaxKind.CompilationUnit);
+ {
+ N(SyntaxKind.ClassDeclaration);
+ {
+ N(SyntaxKind.ClassKeyword);
+ N(SyntaxKind.IdentifierToken, "C");
+ N(SyntaxKind.OpenBraceToken);
+ N(SyntaxKind.ClassDeclaration);
+ {
+ N(SyntaxKind.ClassKeyword);
+ N(SyntaxKind.IdentifierToken, "D");
+ N(SyntaxKind.ParameterList);
+ {
+ N(SyntaxKind.OpenParenToken);
+ N(SyntaxKind.Parameter);
+ {
+ N(SyntaxKind.PredefinedType);
+ {
+ N(SyntaxKind.ObjectKeyword);
+ }
+ N(SyntaxKind.IdentifierToken, "x");
+ }
+ N(SyntaxKind.CloseParenToken);
+ }
+ N(SyntaxKind.OpenBraceToken);
+ N(SyntaxKind.CloseBraceToken);
+ }
+ N(SyntaxKind.CloseBraceToken);
+ }
+ N(SyntaxKind.EndOfFileToken);
+ }
+ EOF();
+ }
+
+ [Fact, CompilerTrait(CompilerFeature.Extensions)]
+ public void UpdateFromExtensionToClass_NoParameterIdentifier()
+ {
+ var text = @"
+class C
+{
+ extension(object) { }
+}
+";
+ var oldTree = this.Parse(text, LanguageVersionFacts.CSharpNext);
+ var newTree = oldTree.WithReplaceFirst("extension", "class D");
+ oldTree.GetDiagnostics().Verify();
+ newTree.GetDiagnostics().Verify(
+ // (4,19): error CS1001: Identifier expected
+ // class D(object) { }
+ Diagnostic(ErrorCode.ERR_IdentifierExpected, ")").WithLocation(4, 19));
+
+ var diffs = SyntaxDifferences.GetRebuiltNodes(oldTree, newTree);
+ TestDiffsInOrder(diffs,
+ SyntaxKind.CompilationUnit,
+ SyntaxKind.ClassDeclaration,
+ SyntaxKind.ClassDeclaration,
+ SyntaxKind.ClassKeyword,
+ SyntaxKind.IdentifierToken,
+ SyntaxKind.ParameterList,
+ SyntaxKind.Parameter,
+ SyntaxKind.IdentifierToken);
+
+ UsingTree(newTree,
+ // (4,19): error CS1001: Identifier expected
+ // class D(object) { }
+ Diagnostic(ErrorCode.ERR_IdentifierExpected, ")").WithLocation(4, 19));
+
+ N(SyntaxKind.CompilationUnit);
+ {
+ N(SyntaxKind.ClassDeclaration);
+ {
+ N(SyntaxKind.ClassKeyword);
+ N(SyntaxKind.IdentifierToken, "C");
+ N(SyntaxKind.OpenBraceToken);
+ N(SyntaxKind.ClassDeclaration);
+ {
+ N(SyntaxKind.ClassKeyword);
+ N(SyntaxKind.IdentifierToken, "D");
+ N(SyntaxKind.ParameterList);
+ {
+ N(SyntaxKind.OpenParenToken);
+ N(SyntaxKind.Parameter);
+ {
+ N(SyntaxKind.PredefinedType);
+ {
+ N(SyntaxKind.ObjectKeyword);
+ }
+ M(SyntaxKind.IdentifierToken);
+ }
+ N(SyntaxKind.CloseParenToken);
+ }
+ N(SyntaxKind.OpenBraceToken);
+ N(SyntaxKind.CloseBraceToken);
+ }
+ N(SyntaxKind.CloseBraceToken);
+ }
+ N(SyntaxKind.EndOfFileToken);
+ }
+ EOF();
+ }
+
+ [Fact, CompilerTrait(CompilerFeature.Extensions)]
+ public void UpdateFromExtensionToClass_WithName()
+ {
+ var text = @"
+class C
+{
+ extension E(object x) { }
+}
+";
+ var oldTree = this.Parse(text, LanguageVersionFacts.CSharpNext);
+ var newTree = oldTree.WithReplaceFirst("extension", "class");
+ oldTree.GetDiagnostics().Verify(
+ // (4,15): error CS9500: Extension declarations may not have a name.
+ // extension E(object x) { }
+ Diagnostic(ErrorCode.ERR_ExtensionDisallowsName, "E").WithLocation(4, 15));
+ newTree.GetDiagnostics().Verify();
+
+ var diffs = SyntaxDifferences.GetRebuiltNodes(oldTree, newTree);
+ TestDiffsInOrder(diffs,
+ SyntaxKind.CompilationUnit,
+ SyntaxKind.ClassDeclaration,
+ SyntaxKind.ClassDeclaration,
+ SyntaxKind.ClassKeyword,
+ SyntaxKind.IdentifierToken);
+
+ UsingTree(newTree);
+
+ N(SyntaxKind.CompilationUnit);
+ {
+ N(SyntaxKind.ClassDeclaration);
+ {
+ N(SyntaxKind.ClassKeyword);
+ N(SyntaxKind.IdentifierToken, "C");
+ N(SyntaxKind.OpenBraceToken);
+ N(SyntaxKind.ClassDeclaration);
+ {
+ N(SyntaxKind.ClassKeyword);
+ N(SyntaxKind.IdentifierToken, "E");
+ N(SyntaxKind.ParameterList);
+ {
+ N(SyntaxKind.OpenParenToken);
+ N(SyntaxKind.Parameter);
+ {
+ N(SyntaxKind.PredefinedType);
+ {
+ N(SyntaxKind.ObjectKeyword);
+ }
+ N(SyntaxKind.IdentifierToken, "x");
+ }
+ N(SyntaxKind.CloseParenToken);
+ }
+ N(SyntaxKind.OpenBraceToken);
+ N(SyntaxKind.CloseBraceToken);
+ }
+ N(SyntaxKind.CloseBraceToken);
+ }
+ N(SyntaxKind.EndOfFileToken);
+ }
+ EOF();
+ }
+
+ [Fact, CompilerTrait(CompilerFeature.Extensions)]
+ public void UpdateFromClassToExtension()
+ {
+ var text = @"
+class C
+{
+ class D(object x) { }
+}
+";
+ var oldTree = this.Parse(text, LanguageVersionFacts.CSharpNext);
+ var newTree = oldTree.WithReplaceFirst("class D", "extension");
+ oldTree.GetDiagnostics().Verify();
+ newTree.GetDiagnostics().Verify();
+
+ var diffs = SyntaxDifferences.GetRebuiltNodes(oldTree, newTree);
+ TestDiffsInOrder(diffs,
+ SyntaxKind.CompilationUnit,
+ SyntaxKind.ClassDeclaration,
+ SyntaxKind.ExtensionDeclaration,
+ SyntaxKind.ExtensionKeyword);
+
+ UsingTree(newTree);
+
+ N(SyntaxKind.CompilationUnit);
+ {
+ N(SyntaxKind.ClassDeclaration);
+ {
+ N(SyntaxKind.ClassKeyword);
+ N(SyntaxKind.IdentifierToken, "C");
+ N(SyntaxKind.OpenBraceToken);
+ N(SyntaxKind.ExtensionDeclaration);
+ {
+ N(SyntaxKind.ExtensionKeyword);
+ N(SyntaxKind.ParameterList);
+ {
+ N(SyntaxKind.OpenParenToken);
+ N(SyntaxKind.Parameter);
+ {
+ N(SyntaxKind.PredefinedType);
+ {
+ N(SyntaxKind.ObjectKeyword);
+ }
+ N(SyntaxKind.IdentifierToken, "x");
+ }
+ N(SyntaxKind.CloseParenToken);
+ }
+ N(SyntaxKind.OpenBraceToken);
+ N(SyntaxKind.CloseBraceToken);
+ }
+ N(SyntaxKind.CloseBraceToken);
+ }
+ N(SyntaxKind.EndOfFileToken);
+ }
+ EOF();
+ }
+
+ [Fact, CompilerTrait(CompilerFeature.Extensions)]
+ public void UpdateFromClassToExtension_NoParameterIdentifier()
+ {
+ var text = @"
+class C
+{
+ class D(object) { }
+}
+";
+ var oldTree = this.Parse(text, LanguageVersionFacts.CSharpNext);
+ var newTree = oldTree.WithReplaceFirst("class D", "extension");
+ oldTree.GetDiagnostics().Verify(
+ // (4,19): error CS1001: Identifier expected
+ // class D(object) { }
+ Diagnostic(ErrorCode.ERR_IdentifierExpected, ")").WithLocation(4, 19));
+ newTree.GetDiagnostics().Verify();
+
+ var diffs = SyntaxDifferences.GetRebuiltNodes(oldTree, newTree);
+ TestDiffsInOrder(diffs,
+ SyntaxKind.CompilationUnit,
+ SyntaxKind.ClassDeclaration,
+ SyntaxKind.ExtensionDeclaration,
+ SyntaxKind.ExtensionKeyword,
+ SyntaxKind.ParameterList,
+ SyntaxKind.Parameter);
+
+ UsingTree(newTree);
+
+ N(SyntaxKind.CompilationUnit);
+ {
+ N(SyntaxKind.ClassDeclaration);
+ {
+ N(SyntaxKind.ClassKeyword);
+ N(SyntaxKind.IdentifierToken, "C");
+ N(SyntaxKind.OpenBraceToken);
+ N(SyntaxKind.ExtensionDeclaration);
+ {
+ N(SyntaxKind.ExtensionKeyword);
+ N(SyntaxKind.ParameterList);
+ {
+ N(SyntaxKind.OpenParenToken);
+ N(SyntaxKind.Parameter);
+ {
+ N(SyntaxKind.PredefinedType);
+ {
+ N(SyntaxKind.ObjectKeyword);
+ }
+ }
+ N(SyntaxKind.CloseParenToken);
+ }
+ N(SyntaxKind.OpenBraceToken);
+ N(SyntaxKind.CloseBraceToken);
+ }
+ N(SyntaxKind.CloseBraceToken);
+ }
+ N(SyntaxKind.EndOfFileToken);
+ }
+ EOF();
+ }
+
+ [Fact, CompilerTrait(CompilerFeature.Extensions)]
+ public void UpdateFromClassToExtension_WithName()
+ {
+ var text = @"
+class C
+{
+ struct D(object x) { }
+}
+";
+ var oldTree = this.Parse(text, LanguageVersionFacts.CSharpNext);
+ var newTree = oldTree.WithReplaceFirst("struct", "extension");
+ oldTree.GetDiagnostics().Verify();
+ newTree.GetDiagnostics().Verify(
+ // (4,15): error CS9500: Extension declarations may not have a name.
+ // extension D(object x) { }
+ Diagnostic(ErrorCode.ERR_ExtensionDisallowsName, "D").WithLocation(4, 15));
+
+ var diffs = SyntaxDifferences.GetRebuiltNodes(oldTree, newTree);
+ TestDiffsInOrder(diffs,
+ SyntaxKind.CompilationUnit,
+ SyntaxKind.ClassDeclaration,
+ SyntaxKind.ExtensionDeclaration,
+ SyntaxKind.ExtensionKeyword);
+
+ UsingTree(newTree,
+ // (4,15): error CS9500: Extension declarations may not have a name.
+ // extension D(object x) { }
+ Diagnostic(ErrorCode.ERR_ExtensionDisallowsName, "D").WithLocation(4, 15));
+
+ N(SyntaxKind.CompilationUnit);
+ {
+ N(SyntaxKind.ClassDeclaration);
+ {
+ N(SyntaxKind.ClassKeyword);
+ N(SyntaxKind.IdentifierToken, "C");
+ N(SyntaxKind.OpenBraceToken);
+ N(SyntaxKind.ExtensionDeclaration);
+ {
+ N(SyntaxKind.ExtensionKeyword);
+ N(SyntaxKind.ParameterList);
+ {
+ N(SyntaxKind.OpenParenToken);
+ N(SyntaxKind.Parameter);
+ {
+ N(SyntaxKind.PredefinedType);
+ {
+ N(SyntaxKind.ObjectKeyword);
+ }
+ N(SyntaxKind.IdentifierToken, "x");
+ }
+ N(SyntaxKind.CloseParenToken);
+ }
+ N(SyntaxKind.OpenBraceToken);
+ N(SyntaxKind.CloseBraceToken);
+ }
+ N(SyntaxKind.CloseBraceToken);
+ }
+ N(SyntaxKind.EndOfFileToken);
+ }
+ EOF();
+ }
+
+ [Fact, CompilerTrait(CompilerFeature.Extensions)]
+ public void UpdateExtension_ChangeParameterList()
+ {
+ var text = """
+class C
+{
+ extension(object, Type z1) { }
+}
+""";
+ var oldTree = this.Parse(text, LanguageVersionFacts.CSharpNext);
+ var newTree = oldTree.WithReplaceFirst("z1", "z2");
+ oldTree.GetDiagnostics().Verify();
+ newTree.GetDiagnostics().Verify();
+
+ var diffs = SyntaxDifferences.GetRebuiltNodes(oldTree, newTree);
+ TestDiffsInOrder(diffs,
+ SyntaxKind.CompilationUnit,
+ SyntaxKind.ClassDeclaration,
+ SyntaxKind.ExtensionDeclaration,
+ SyntaxKind.ExtensionKeyword,
+ SyntaxKind.ParameterList,
+ SyntaxKind.Parameter,
+ SyntaxKind.IdentifierToken);
+
+ UsingTree(newTree);
+
+ N(SyntaxKind.CompilationUnit);
+ {
+ N(SyntaxKind.ClassDeclaration);
+ {
+ N(SyntaxKind.ClassKeyword);
+ N(SyntaxKind.IdentifierToken, "C");
+ N(SyntaxKind.OpenBraceToken);
+ N(SyntaxKind.ExtensionDeclaration);
+ {
+ N(SyntaxKind.ExtensionKeyword);
+ N(SyntaxKind.ParameterList);
+ {
+ N(SyntaxKind.OpenParenToken);
+ N(SyntaxKind.Parameter);
+ {
+ N(SyntaxKind.PredefinedType);
+ {
+ N(SyntaxKind.ObjectKeyword);
+ }
+ }
+ N(SyntaxKind.CommaToken);
+ N(SyntaxKind.Parameter);
+ {
+ N(SyntaxKind.IdentifierName);
+ {
+ N(SyntaxKind.IdentifierToken, "Type");
+ }
+ N(SyntaxKind.IdentifierToken, "z2");
+ }
+ N(SyntaxKind.CloseParenToken);
+ }
+ N(SyntaxKind.OpenBraceToken);
+ N(SyntaxKind.CloseBraceToken);
+ }
+ N(SyntaxKind.CloseBraceToken);
+ }
+ N(SyntaxKind.EndOfFileToken);
+ }
+ EOF();
+ }
+
#region "Regression"
#if false
diff --git a/src/Compilers/CSharp/Test/Syntax/Parsing/ExtensionsParsingTests.cs b/src/Compilers/CSharp/Test/Syntax/Parsing/ExtensionsParsingTests.cs
new file mode 100644
index 0000000000000..b17bde0719be2
--- /dev/null
+++ b/src/Compilers/CSharp/Test/Syntax/Parsing/ExtensionsParsingTests.cs
@@ -0,0 +1,4802 @@
+// 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 Microsoft.CodeAnalysis.CSharp.Test.Utilities;
+using Microsoft.CodeAnalysis.Test.Utilities;
+using Roslyn.Test.Utilities;
+using Xunit;
+using Xunit.Abstractions;
+
+namespace Microsoft.CodeAnalysis.CSharp.UnitTests;
+
+[CompilerTrait(CompilerFeature.Extensions)]
+public class ExtensionsParsingTests : ParsingTests
+{
+ public ExtensionsParsingTests(ITestOutputHelper output) : base(output) { }
+
+ [Fact]
+ public void LangVer13()
+ {
+ // PROTOTYPE consider giving a LangVer error to trigger UpgradeProject
+ UsingTree("""
+class C
+{
+ extension(object o) where T : struct { }
+}
+""",
+ TestOptions.Regular13,
+ // (3,17): error CS1519: Invalid token '(' in class, record, struct, or interface member declaration
+ // extension(object o) where T : struct { }
+ Diagnostic(ErrorCode.ERR_InvalidMemberDecl, "(").WithArguments("(").WithLocation(3, 17),
+ // (3,26): error CS8124: Tuple must contain at least two elements.
+ // extension(object o) where T : struct { }
+ Diagnostic(ErrorCode.ERR_TupleTooFewElements, ")").WithLocation(3, 26),
+ // (3,34): error CS1002: ; expected
+ // extension(object o) where T : struct { }
+ Diagnostic(ErrorCode.ERR_SemicolonExpected, "T").WithLocation(3, 34),
+ // (3,36): error CS1519: Invalid token ':' in class, record, struct, or interface member declaration
+ // extension(object o) where T : struct { }
+ Diagnostic(ErrorCode.ERR_InvalidMemberDecl, ":").WithArguments(":").WithLocation(3, 36),
+ // (3,36): error CS1519: Invalid token ':' in class, record, struct, or interface member declaration
+ // extension(object o) where T : struct { }
+ Diagnostic(ErrorCode.ERR_InvalidMemberDecl, ":").WithArguments(":").WithLocation(3, 36),
+ // (3,45): error CS1001: Identifier expected
+ // extension(object o) where T : struct { }
+ Diagnostic(ErrorCode.ERR_IdentifierExpected, "{").WithLocation(3, 45));
+
+ N(SyntaxKind.CompilationUnit);
+ {
+ N(SyntaxKind.ClassDeclaration);
+ {
+ N(SyntaxKind.ClassKeyword);
+ N(SyntaxKind.IdentifierToken, "C");
+ N(SyntaxKind.OpenBraceToken);
+ N(SyntaxKind.IncompleteMember);
+ {
+ N(SyntaxKind.GenericName);
+ {
+ N(SyntaxKind.IdentifierToken, "extension");
+ N(SyntaxKind.TypeArgumentList);
+ {
+ N(SyntaxKind.LessThanToken);
+ N(SyntaxKind.IdentifierName);
+ {
+ N(SyntaxKind.IdentifierToken, "T");
+ }
+ N(SyntaxKind.GreaterThanToken);
+ }
+ }
+ }
+ N(SyntaxKind.FieldDeclaration);
+ {
+ N(SyntaxKind.VariableDeclaration);
+ {
+ N(SyntaxKind.TupleType);
+ {
+ N(SyntaxKind.OpenParenToken);
+ N(SyntaxKind.TupleElement);
+ {
+ N(SyntaxKind.PredefinedType);
+ {
+ N(SyntaxKind.ObjectKeyword);
+ }
+ N(SyntaxKind.IdentifierToken, "o");
+ }
+ M(SyntaxKind.CommaToken);
+ M(SyntaxKind.TupleElement);
+ {
+ M(SyntaxKind.IdentifierName);
+ {
+ M(SyntaxKind.IdentifierToken);
+ }
+ }
+ N(SyntaxKind.CloseParenToken);
+ }
+ N(SyntaxKind.VariableDeclarator);
+ {
+ N(SyntaxKind.IdentifierToken, "where");
+ }
+ }
+ M(SyntaxKind.SemicolonToken);
+ }
+ N(SyntaxKind.IncompleteMember);
+ {
+ N(SyntaxKind.IdentifierName);
+ {
+ N(SyntaxKind.IdentifierToken, "T");
+ }
+ }
+ N(SyntaxKind.StructDeclaration);
+ {
+ N(SyntaxKind.StructKeyword);
+ M(SyntaxKind.IdentifierToken);
+ N(SyntaxKind.OpenBraceToken);
+ N(SyntaxKind.CloseBraceToken);
+ }
+ N(SyntaxKind.CloseBraceToken);
+ }
+ N(SyntaxKind.EndOfFileToken);
+ }
+ EOF();
+ }
+
+ [Theory, CombinatorialData]
+ public void LangVer14(bool useCSharp14)
+ {
+ UsingTree("""
+class C
+{
+ extension(object o) where T : struct { }
+}
+""",
+ useCSharp14 ? TestOptions.RegularNext : TestOptions.RegularPreview);
+
+ N(SyntaxKind.CompilationUnit);
+ {
+ N(SyntaxKind.ClassDeclaration);
+ {
+ N(SyntaxKind.ClassKeyword);
+ N(SyntaxKind.IdentifierToken, "C");
+ N(SyntaxKind.OpenBraceToken);
+ N(SyntaxKind.ExtensionDeclaration);
+ {
+ N(SyntaxKind.ExtensionKeyword);
+ N(SyntaxKind.TypeParameterList);
+ {
+ N(SyntaxKind.LessThanToken);
+ N(SyntaxKind.TypeParameter);
+ {
+ N(SyntaxKind.IdentifierToken, "T");
+ }
+ N(SyntaxKind.GreaterThanToken);
+ }
+ N(SyntaxKind.ParameterList);
+ {
+ N(SyntaxKind.OpenParenToken);
+ N(SyntaxKind.Parameter);
+ {
+ N(SyntaxKind.PredefinedType);
+ {
+ N(SyntaxKind.ObjectKeyword);
+ }
+ N(SyntaxKind.IdentifierToken, "o");
+ }
+ N(SyntaxKind.CloseParenToken);
+ }
+ N(SyntaxKind.TypeParameterConstraintClause);
+ {
+ N(SyntaxKind.WhereKeyword);
+ N(SyntaxKind.IdentifierName);
+ {
+ N(SyntaxKind.IdentifierToken, "T");
+ }
+ N(SyntaxKind.ColonToken);
+ N(SyntaxKind.StructConstraint);
+ {
+ N(SyntaxKind.StructKeyword);
+ }
+ }
+ N(SyntaxKind.OpenBraceToken);
+ N(SyntaxKind.CloseBraceToken);
+ }
+ N(SyntaxKind.CloseBraceToken);
+ }
+ N(SyntaxKind.EndOfFileToken);
+ }
+ EOF();
+ }
+
+ [Fact]
+ public void MultipleConstraints()
+ {
+ UsingTree("""
+class C
+{
+ extension(object o) where T1 : struct where T2 : class { }
+}
+""",
+ TestOptions.RegularPreview);
+
+ N(SyntaxKind.CompilationUnit);
+ {
+ N(SyntaxKind.ClassDeclaration);
+ {
+ N(SyntaxKind.ClassKeyword);
+ N(SyntaxKind.IdentifierToken, "C");
+ N(SyntaxKind.OpenBraceToken);
+ N(SyntaxKind.ExtensionDeclaration);
+ {
+ N(SyntaxKind.ExtensionKeyword);
+ N(SyntaxKind.TypeParameterList);
+ {
+ N(SyntaxKind.LessThanToken);
+ N(SyntaxKind.TypeParameter);
+ {
+ N(SyntaxKind.IdentifierToken, "T1");
+ }
+ N(SyntaxKind.CommaToken);
+ N(SyntaxKind.TypeParameter);
+ {
+ N(SyntaxKind.IdentifierToken, "T2");
+ }
+ N(SyntaxKind.GreaterThanToken);
+ }
+ N(SyntaxKind.ParameterList);
+ {
+ N(SyntaxKind.OpenParenToken);
+ N(SyntaxKind.Parameter);
+ {
+ N(SyntaxKind.PredefinedType);
+ {
+ N(SyntaxKind.ObjectKeyword);
+ }
+ N(SyntaxKind.IdentifierToken, "o");
+ }
+ N(SyntaxKind.CloseParenToken);
+ }
+ N(SyntaxKind.TypeParameterConstraintClause);
+ {
+ N(SyntaxKind.WhereKeyword);
+ N(SyntaxKind.IdentifierName);
+ {
+ N(SyntaxKind.IdentifierToken, "T1");
+ }
+ N(SyntaxKind.ColonToken);
+ N(SyntaxKind.StructConstraint);
+ {
+ N(SyntaxKind.StructKeyword);
+ }
+ }
+ N(SyntaxKind.TypeParameterConstraintClause);
+ {
+ N(SyntaxKind.WhereKeyword);
+ N(SyntaxKind.IdentifierName);
+ {
+ N(SyntaxKind.IdentifierToken, "T2");
+ }
+ N(SyntaxKind.ColonToken);
+ N(SyntaxKind.ClassConstraint);
+ {
+ N(SyntaxKind.ClassKeyword);
+ }
+ }
+ N(SyntaxKind.OpenBraceToken);
+ N(SyntaxKind.CloseBraceToken);
+ }
+ N(SyntaxKind.CloseBraceToken);
+ }
+ N(SyntaxKind.EndOfFileToken);
+ }
+ EOF();
+ }
+
+ [Fact]
+ public void MultipleConstraints_Incomplete()
+ {
+ UsingTree("""
+class C
+{
+ extension(object o) where T1 where T2 : class { }
+}
+""",
+ TestOptions.RegularPreview,
+ // (3,42): error CS1003: Syntax error, ':' expected
+ // extension(object o) where T1 where T2 : class { }
+ Diagnostic(ErrorCode.ERR_SyntaxError, "where").WithArguments(":").WithLocation(3, 42),
+ // (3,42): error CS1031: Type expected
+ // extension(object o) where T1 where T2 : class { }
+ Diagnostic(ErrorCode.ERR_TypeExpected, "where").WithLocation(3, 42));
+
+ N(SyntaxKind.CompilationUnit);
+ {
+ N(SyntaxKind.ClassDeclaration);
+ {
+ N(SyntaxKind.ClassKeyword);
+ N(SyntaxKind.IdentifierToken, "C");
+ N(SyntaxKind.OpenBraceToken);
+ N(SyntaxKind.ExtensionDeclaration);
+ {
+ N(SyntaxKind.ExtensionKeyword);
+ N(SyntaxKind.TypeParameterList);
+ {
+ N(SyntaxKind.LessThanToken);
+ N(SyntaxKind.TypeParameter);
+ {
+ N(SyntaxKind.IdentifierToken, "T1");
+ }
+ N(SyntaxKind.CommaToken);
+ N(SyntaxKind.TypeParameter);
+ {
+ N(SyntaxKind.IdentifierToken, "T2");
+ }
+ N(SyntaxKind.GreaterThanToken);
+ }
+ N(SyntaxKind.ParameterList);
+ {
+ N(SyntaxKind.OpenParenToken);
+ N(SyntaxKind.Parameter);
+ {
+ N(SyntaxKind.PredefinedType);
+ {
+ N(SyntaxKind.ObjectKeyword);
+ }
+ N(SyntaxKind.IdentifierToken, "o");
+ }
+ N(SyntaxKind.CloseParenToken);
+ }
+ N(SyntaxKind.TypeParameterConstraintClause);
+ {
+ N(SyntaxKind.WhereKeyword);
+ N(SyntaxKind.IdentifierName);
+ {
+ N(SyntaxKind.IdentifierToken, "T1");
+ }
+ M(SyntaxKind.ColonToken);
+ M(SyntaxKind.TypeConstraint);
+ {
+ M(SyntaxKind.IdentifierName);
+ {
+ M(SyntaxKind.IdentifierToken);
+ }
+ }
+ }
+ N(SyntaxKind.TypeParameterConstraintClause);
+ {
+ N(SyntaxKind.WhereKeyword);
+ N(SyntaxKind.IdentifierName);
+ {
+ N(SyntaxKind.IdentifierToken, "T2");
+ }
+ N(SyntaxKind.ColonToken);
+ N(SyntaxKind.ClassConstraint);
+ {
+ N(SyntaxKind.ClassKeyword);
+ }
+ }
+ N(SyntaxKind.OpenBraceToken);
+ N(SyntaxKind.CloseBraceToken);
+ }
+ N(SyntaxKind.CloseBraceToken);
+ }
+ N(SyntaxKind.EndOfFileToken);
+ }
+ EOF();
+ }
+
+ [Fact]
+ public void WithName()
+ {
+ UsingTree("""
+class C
+{
+ extension Name(Type) { }
+}
+""",
+ TestOptions.RegularPreview,
+ // (3,15): error CS9500: Extension declarations may not have a name.
+ // extension Name(Type) { }
+ Diagnostic(ErrorCode.ERR_ExtensionDisallowsName, "Name").WithLocation(3, 15));
+
+ N(SyntaxKind.CompilationUnit);
+ {
+ N(SyntaxKind.ClassDeclaration);
+ {
+ N(SyntaxKind.ClassKeyword);
+ N(SyntaxKind.IdentifierToken, "C");
+ N(SyntaxKind.OpenBraceToken);
+ N(SyntaxKind.ExtensionDeclaration);
+ {
+ N(SyntaxKind.ExtensionKeyword);
+ N(SyntaxKind.ParameterList);
+ {
+ N(SyntaxKind.OpenParenToken);
+ N(SyntaxKind.Parameter);
+ {
+ N(SyntaxKind.IdentifierName);
+ {
+ N(SyntaxKind.IdentifierToken, "Type");
+ }
+ }
+ N(SyntaxKind.CloseParenToken);
+ }
+ N(SyntaxKind.OpenBraceToken);
+ N(SyntaxKind.CloseBraceToken);
+ }
+ N(SyntaxKind.CloseBraceToken);
+ }
+ N(SyntaxKind.EndOfFileToken);
+ }
+ EOF();
+ }
+
+ [Fact]
+ public void WithName_02()
+ {
+ UsingTree("""
+class C
+{
+ extension Name(Type) { }
+}
+""",
+ TestOptions.RegularPreview,
+ // (3,15): error CS9500: Extension declarations may not have a name.
+ // extension Name(Type) { }
+ Diagnostic(ErrorCode.ERR_ExtensionDisallowsName, "Name").WithLocation(3, 15));
+
+ N(SyntaxKind.CompilationUnit);
+ {
+ N(SyntaxKind.ClassDeclaration);
+ {
+ N(SyntaxKind.ClassKeyword);
+ N(SyntaxKind.IdentifierToken, "C");
+ N(SyntaxKind.OpenBraceToken);
+ N(SyntaxKind.ExtensionDeclaration);
+ {
+ N(SyntaxKind.ExtensionKeyword);
+ N(SyntaxKind.TypeParameterList);
+ {
+ N(SyntaxKind.LessThanToken);
+ N(SyntaxKind.TypeParameter);
+ {
+ N(SyntaxKind.IdentifierToken, "T");
+ }
+ N(SyntaxKind.GreaterThanToken);
+ }
+ N(SyntaxKind.ParameterList);
+ {
+ N(SyntaxKind.OpenParenToken);
+ N(SyntaxKind.Parameter);
+ {
+ N(SyntaxKind.IdentifierName);
+ {
+ N(SyntaxKind.IdentifierToken, "Type");
+ }
+ }
+ N(SyntaxKind.CloseParenToken);
+ }
+ N(SyntaxKind.OpenBraceToken);
+ N(SyntaxKind.CloseBraceToken);
+ }
+ N(SyntaxKind.CloseBraceToken);
+ }
+ N(SyntaxKind.EndOfFileToken);
+ }
+ EOF();
+ }
+
+ [Fact]
+ public void WithDefaultParameterValue()
+ {
+ var src = """
+class C
+{
+ extension(Type x = null) { }
+}
+""";
+ // PROTOTYPE should be a semantic error
+ var comp = CreateCompilation(src);
+ comp.VerifyDiagnostics();
+
+ UsingTree(src, TestOptions.RegularPreview);
+
+ N(SyntaxKind.CompilationUnit);
+ {
+ N(SyntaxKind.ClassDeclaration);
+ {
+ N(SyntaxKind.ClassKeyword);
+ N(SyntaxKind.IdentifierToken, "C");
+ N(SyntaxKind.OpenBraceToken);
+ N(SyntaxKind.ExtensionDeclaration);
+ {
+ N(SyntaxKind.ExtensionKeyword);
+ N(SyntaxKind.ParameterList);
+ {
+ N(SyntaxKind.OpenParenToken);
+ N(SyntaxKind.Parameter);
+ {
+ N(SyntaxKind.IdentifierName);
+ {
+ N(SyntaxKind.IdentifierToken, "Type");
+ }
+ N(SyntaxKind.IdentifierToken, "x");
+ N(SyntaxKind.EqualsValueClause);
+ {
+ N(SyntaxKind.EqualsToken);
+ N(SyntaxKind.NullLiteralExpression);
+ {
+ N(SyntaxKind.NullKeyword);
+ }
+ }
+ }
+ N(SyntaxKind.CloseParenToken);
+ }
+ N(SyntaxKind.OpenBraceToken);
+ N(SyntaxKind.CloseBraceToken);
+ }
+ N(SyntaxKind.CloseBraceToken);
+ }
+ N(SyntaxKind.EndOfFileToken);
+ }
+ EOF();
+ }
+
+ [Fact]
+ public void WithDefaultParameterValue_02()
+ {
+ var src = """
+class C
+{
+ extension(Type = null) { }
+}
+""";
+ // PROTOTYPE should be a semantic error
+ var comp = CreateCompilation(src);
+ comp.VerifyDiagnostics();
+
+ UsingTree(src, TestOptions.RegularPreview);
+
+ N(SyntaxKind.CompilationUnit);
+ {
+ N(SyntaxKind.ClassDeclaration);
+ {
+ N(SyntaxKind.ClassKeyword);
+ N(SyntaxKind.IdentifierToken, "C");
+ N(SyntaxKind.OpenBraceToken);
+ N(SyntaxKind.ExtensionDeclaration);
+ {
+ N(SyntaxKind.ExtensionKeyword);
+ N(SyntaxKind.ParameterList);
+ {
+ N(SyntaxKind.OpenParenToken);
+ N(SyntaxKind.Parameter);
+ {
+ N(SyntaxKind.IdentifierName);
+ {
+ N(SyntaxKind.IdentifierToken, "Type");
+ }
+ N(SyntaxKind.EqualsValueClause);
+ {
+ N(SyntaxKind.EqualsToken);
+ N(SyntaxKind.NullLiteralExpression);
+ {
+ N(SyntaxKind.NullKeyword);
+ }
+ }
+ }
+ N(SyntaxKind.CloseParenToken);
+ }
+ N(SyntaxKind.OpenBraceToken);
+ N(SyntaxKind.CloseBraceToken);
+ }
+ N(SyntaxKind.CloseBraceToken);
+ }
+ N(SyntaxKind.EndOfFileToken);
+ }
+ EOF();
+ }
+
+ [Fact]
+ public void WithDefaultParameterValue_03()
+ {
+ var src = """
+class C
+{
+ extension(Type =) { }
+}
+""";
+ UsingTree(src, TestOptions.RegularPreview,
+ // (3,21): error CS1525: Invalid expression term ')'
+ // extension(Type =) { }
+ Diagnostic(ErrorCode.ERR_InvalidExprTerm, ")").WithArguments(")").WithLocation(3, 21));
+
+ N(SyntaxKind.CompilationUnit);
+ {
+ N(SyntaxKind.ClassDeclaration);
+ {
+ N(SyntaxKind.ClassKeyword);
+ N(SyntaxKind.IdentifierToken, "C");
+ N(SyntaxKind.OpenBraceToken);
+ N(SyntaxKind.ExtensionDeclaration);
+ {
+ N(SyntaxKind.ExtensionKeyword);
+ N(SyntaxKind.ParameterList);
+ {
+ N(SyntaxKind.OpenParenToken);
+ N(SyntaxKind.Parameter);
+ {
+ N(SyntaxKind.IdentifierName);
+ {
+ N(SyntaxKind.IdentifierToken, "Type");
+ }
+ N(SyntaxKind.EqualsValueClause);
+ {
+ N(SyntaxKind.EqualsToken);
+ M(SyntaxKind.IdentifierName);
+ {
+ M(SyntaxKind.IdentifierToken);
+ }
+ }
+ }
+ N(SyntaxKind.CloseParenToken);
+ }
+ N(SyntaxKind.OpenBraceToken);
+ N(SyntaxKind.CloseBraceToken);
+ }
+ N(SyntaxKind.CloseBraceToken);
+ }
+ N(SyntaxKind.EndOfFileToken);
+ }
+ EOF();
+ }
+
+ [Fact]
+ public void WithBaseList()
+ {
+ var src = """
+class C
+{
+ extension Name(Type) : Type2() { }
+}
+""";
+ UsingTree(src, TestOptions.RegularPreview,
+ // (3,15): error CS9500: Extension declarations may not have a name.
+ // extension Name(Type) : Type2() { }
+ Diagnostic(ErrorCode.ERR_ExtensionDisallowsName, "Name").WithLocation(3, 15),
+ // (3,26): error CS1514: { expected
+ // extension Name(Type) : Type2() { }
+ Diagnostic(ErrorCode.ERR_LbraceExpected, ":").WithLocation(3, 26),
+ // (3,26): error CS1513: } expected
+ // extension Name(Type) : Type2() { }
+ Diagnostic(ErrorCode.ERR_RbraceExpected, ":").WithLocation(3, 26),
+ // (3,26): error CS1519: Invalid token ':' in a member declaration
+ // extension Name(Type) : Type2() { }
+ Diagnostic(ErrorCode.ERR_InvalidMemberDecl, ":").WithArguments(":").WithLocation(3, 26));
+
+ N(SyntaxKind.CompilationUnit);
+ {
+ N(SyntaxKind.ClassDeclaration);
+ {
+ N(SyntaxKind.ClassKeyword);
+ N(SyntaxKind.IdentifierToken, "C");
+ N(SyntaxKind.OpenBraceToken);
+ N(SyntaxKind.ExtensionDeclaration);
+ {
+ N(SyntaxKind.ExtensionKeyword);
+ N(SyntaxKind.ParameterList);
+ {
+ N(SyntaxKind.OpenParenToken);
+ N(SyntaxKind.Parameter);
+ {
+ N(SyntaxKind.IdentifierName);
+ {
+ N(SyntaxKind.IdentifierToken, "Type");
+ }
+ }
+ N(SyntaxKind.CloseParenToken);
+ }
+ M(SyntaxKind.OpenBraceToken);
+ M(SyntaxKind.CloseBraceToken);
+ }
+ N(SyntaxKind.ConstructorDeclaration);
+ {
+ N(SyntaxKind.IdentifierToken, "Type2");
+ 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 TypeNamedExtension(bool useCSharp14)
+ {
+ UsingTree("""
+class extension
+{
+ extension(Type constructorParameter) { }
+}
+""",
+ TestOptions.Regular13);
+
+ N(SyntaxKind.CompilationUnit);
+ {
+ N(SyntaxKind.ClassDeclaration);
+ {
+ N(SyntaxKind.ClassKeyword);
+ N(SyntaxKind.IdentifierToken, "extension");
+ N(SyntaxKind.OpenBraceToken);
+ N(SyntaxKind.ConstructorDeclaration);
+ {
+ N(SyntaxKind.IdentifierToken, "extension");
+ N(SyntaxKind.ParameterList);
+ {
+ N(SyntaxKind.OpenParenToken);
+ N(SyntaxKind.Parameter);
+ {
+ N(SyntaxKind.IdentifierName);
+ {
+ N(SyntaxKind.IdentifierToken, "Type");
+ }
+ N(SyntaxKind.IdentifierToken, "constructorParameter");
+ }
+ N(SyntaxKind.CloseParenToken);
+ }
+ N(SyntaxKind.Block);
+ {
+ N(SyntaxKind.OpenBraceToken);
+ N(SyntaxKind.CloseBraceToken);
+ }
+ }
+ N(SyntaxKind.CloseBraceToken);
+ }
+ N(SyntaxKind.EndOfFileToken);
+ }
+ EOF();
+
+ // PROTOTYPE report error for declaring type named "extension"
+ // Note: break from C# 13
+ UsingTree("""
+class extension
+{
+ extension(Type constructorParameter) { }
+}
+""",
+ useCSharp14 ? TestOptions.RegularNext : TestOptions.RegularPreview);
+
+ N(SyntaxKind.CompilationUnit);
+ {
+ N(SyntaxKind.ClassDeclaration);
+ {
+ N(SyntaxKind.ClassKeyword);
+ N(SyntaxKind.IdentifierToken, "extension");
+ N(SyntaxKind.OpenBraceToken);
+ N(SyntaxKind.ExtensionDeclaration);
+ {
+ N(SyntaxKind.ExtensionKeyword);
+ N(SyntaxKind.ParameterList);
+ {
+ N(SyntaxKind.OpenParenToken);
+ N(SyntaxKind.Parameter);
+ {
+ N(SyntaxKind.IdentifierName);
+ {
+ N(SyntaxKind.IdentifierToken, "Type");
+ }
+ N(SyntaxKind.IdentifierToken, "constructorParameter");
+ }
+ N(SyntaxKind.CloseParenToken);
+ }
+ N(SyntaxKind.OpenBraceToken);
+ N(SyntaxKind.CloseBraceToken);
+ }
+ N(SyntaxKind.CloseBraceToken);
+ }
+ N(SyntaxKind.EndOfFileToken);
+ }
+ EOF();
+
+ UsingTree("""
+class extension
+{
+ @extension(Type constructorParameter) { }
+}
+""",
+ useCSharp14 ? TestOptions.RegularNext : TestOptions.RegularPreview);
+
+ N(SyntaxKind.CompilationUnit);
+ {
+ N(SyntaxKind.ClassDeclaration);
+ {
+ N(SyntaxKind.ClassKeyword);
+ N(SyntaxKind.IdentifierToken, "extension");
+ N(SyntaxKind.OpenBraceToken);
+ N(SyntaxKind.ConstructorDeclaration);
+ {
+ N(SyntaxKind.IdentifierToken, "@extension");
+ N(SyntaxKind.ParameterList);
+ {
+ N(SyntaxKind.OpenParenToken);
+ N(SyntaxKind.Parameter);
+ {
+ N(SyntaxKind.IdentifierName);
+ {
+ N(SyntaxKind.IdentifierToken, "Type");
+ }
+ N(SyntaxKind.IdentifierToken, "constructorParameter");
+ }
+ N(SyntaxKind.CloseParenToken);
+ }
+ N(SyntaxKind.Block);
+ {
+ N(SyntaxKind.OpenBraceToken);
+ N(SyntaxKind.CloseBraceToken);
+ }
+ }
+ N(SyntaxKind.CloseBraceToken);
+ }
+ N(SyntaxKind.EndOfFileToken);
+ }
+ EOF();
+ }
+
+ [Fact]
+ public void ReceiverParameter_NoName()
+ {
+ UsingTree("""
+class C
+{
+ extension(Type) { }
+}
+""",
+ TestOptions.RegularPreview);
+
+ N(SyntaxKind.CompilationUnit);
+ {
+ N(SyntaxKind.ClassDeclaration);
+ {
+ N(SyntaxKind.ClassKeyword);
+ N(SyntaxKind.IdentifierToken, "C");
+ N(SyntaxKind.OpenBraceToken);
+ N(SyntaxKind.ExtensionDeclaration);
+ {
+ N(SyntaxKind.ExtensionKeyword);
+ N(SyntaxKind.ParameterList);
+ {
+ N(SyntaxKind.OpenParenToken);
+ N(SyntaxKind.Parameter);
+ {
+ N(SyntaxKind.IdentifierName);
+ {
+ N(SyntaxKind.IdentifierToken, "Type");
+ }
+ }
+ N(SyntaxKind.CloseParenToken);
+ }
+ N(SyntaxKind.OpenBraceToken);
+ N(SyntaxKind.CloseBraceToken);
+ }
+ N(SyntaxKind.CloseBraceToken);
+ }
+ N(SyntaxKind.EndOfFileToken);
+ }
+ EOF();
+ }
+
+ [Fact]
+ public void ReceiverParameter_NoName_02()
+ {
+ UsingTree("""
+class C
+{
+ extension(object) { }
+}
+""",
+ TestOptions.RegularPreview);
+
+ N(SyntaxKind.CompilationUnit);
+ {
+ N(SyntaxKind.ClassDeclaration);
+ {
+ N(SyntaxKind.ClassKeyword);
+ N(SyntaxKind.IdentifierToken, "C");
+ N(SyntaxKind.OpenBraceToken);
+ N(SyntaxKind.ExtensionDeclaration);
+ {
+ N(SyntaxKind.ExtensionKeyword);
+ N(SyntaxKind.ParameterList);
+ {
+ N(SyntaxKind.OpenParenToken);
+ N(SyntaxKind.Parameter);
+ {
+ N(SyntaxKind.PredefinedType);
+ {
+ N(SyntaxKind.ObjectKeyword);
+ }
+ }
+ N(SyntaxKind.CloseParenToken);
+ }
+ N(SyntaxKind.OpenBraceToken);
+ N(SyntaxKind.CloseBraceToken);
+ }
+ N(SyntaxKind.CloseBraceToken);
+ }
+ N(SyntaxKind.EndOfFileToken);
+ }
+ EOF();
+ }
+
+ [Fact]
+ public void ReceiverParameter_Multiple()
+ {
+ var src = """
+class C
+{
+ extension(Type x1, Type x2) { }
+}
+""";
+ // PROTOTYPE should be a semantic error
+ var comp = CreateCompilation(src);
+ comp.VerifyDiagnostics();
+
+ UsingTree(src, TestOptions.RegularPreview);
+
+ N(SyntaxKind.CompilationUnit);
+ {
+ N(SyntaxKind.ClassDeclaration);
+ {
+ N(SyntaxKind.ClassKeyword);
+ N(SyntaxKind.IdentifierToken, "C");
+ N(SyntaxKind.OpenBraceToken);
+ N(SyntaxKind.ExtensionDeclaration);
+ {
+ N(SyntaxKind.ExtensionKeyword);
+ N(SyntaxKind.ParameterList);
+ {
+ N(SyntaxKind.OpenParenToken);
+ N(SyntaxKind.Parameter);
+ {
+ N(SyntaxKind.IdentifierName);
+ {
+ N(SyntaxKind.IdentifierToken, "Type");
+ }
+ N(SyntaxKind.IdentifierToken, "x1");
+ }
+ N(SyntaxKind.CommaToken);
+ N(SyntaxKind.Parameter);
+ {
+ N(SyntaxKind.IdentifierName);
+ {
+ N(SyntaxKind.IdentifierToken, "Type");
+ }
+ N(SyntaxKind.IdentifierToken, "x2");
+ }
+ N(SyntaxKind.CloseParenToken);
+ }
+ N(SyntaxKind.OpenBraceToken);
+ N(SyntaxKind.CloseBraceToken);
+ }
+ N(SyntaxKind.CloseBraceToken);
+ }
+ N(SyntaxKind.EndOfFileToken);
+ }
+ EOF();
+ }
+
+ [Fact]
+ public void ReceiverParameter_Multiple_02()
+ {
+ var src = """
+class C
+{
+ extension(Type, Type) { }
+}
+""";
+ // PROTOTYPE should be a semantic error
+ var comp = CreateCompilation(src);
+ comp.VerifyDiagnostics();
+
+ UsingTree(src, TestOptions.RegularPreview);
+
+ N(SyntaxKind.CompilationUnit);
+ {
+ N(SyntaxKind.ClassDeclaration);
+ {
+ N(SyntaxKind.ClassKeyword);
+ N(SyntaxKind.IdentifierToken, "C");
+ N(SyntaxKind.OpenBraceToken);
+ N(SyntaxKind.ExtensionDeclaration);
+ {
+ N(SyntaxKind.ExtensionKeyword);
+ N(SyntaxKind.ParameterList);
+ {
+ N(SyntaxKind.OpenParenToken);
+ N(SyntaxKind.Parameter);
+ {
+ N(SyntaxKind.IdentifierName);
+ {
+ N(SyntaxKind.IdentifierToken, "Type");
+ }
+ }
+ N(SyntaxKind.CommaToken);
+ N(SyntaxKind.Parameter);
+ {
+ N(SyntaxKind.IdentifierName);
+ {
+ N(SyntaxKind.IdentifierToken, "Type");
+ }
+ }
+ N(SyntaxKind.CloseParenToken);
+ }
+ N(SyntaxKind.OpenBraceToken);
+ N(SyntaxKind.CloseBraceToken);
+ }
+ N(SyntaxKind.CloseBraceToken);
+ }
+ N(SyntaxKind.EndOfFileToken);
+ }
+ EOF();
+ }
+
+ [Fact]
+ public void ReceiverParameter_Multiple_03()
+ {
+ var src = """
+class C
+{
+ extension(object object) { }
+}
+""";
+ UsingTree(src, TestOptions.RegularPreview,
+ // (3,22): error CS1003: Syntax error, ',' expected
+ // extension(object object) { }
+ Diagnostic(ErrorCode.ERR_SyntaxError, "object").WithArguments(",").WithLocation(3, 22));
+
+ N(SyntaxKind.CompilationUnit);
+ {
+ N(SyntaxKind.ClassDeclaration);
+ {
+ N(SyntaxKind.ClassKeyword);
+ N(SyntaxKind.IdentifierToken, "C");
+ N(SyntaxKind.OpenBraceToken);
+ N(SyntaxKind.ExtensionDeclaration);
+ {
+ N(SyntaxKind.ExtensionKeyword);
+ N(SyntaxKind.ParameterList);
+ {
+ N(SyntaxKind.OpenParenToken);
+ N(SyntaxKind.Parameter);
+ {
+ N(SyntaxKind.PredefinedType);
+ {
+ N(SyntaxKind.ObjectKeyword);
+ }
+ }
+ M(SyntaxKind.CommaToken);
+ N(SyntaxKind.Parameter);
+ {
+ N(SyntaxKind.PredefinedType);
+ {
+ N(SyntaxKind.ObjectKeyword);
+ }
+ }
+ N(SyntaxKind.CloseParenToken);
+ }
+ N(SyntaxKind.OpenBraceToken);
+ N(SyntaxKind.CloseBraceToken);
+ }
+ N(SyntaxKind.CloseBraceToken);
+ }
+ N(SyntaxKind.EndOfFileToken);
+ }
+ EOF();
+ }
+
+ [Fact]
+ public void ReceiverParameter_Multiple_04()
+ {
+ var src = """
+class C
+{
+ extension(Type, object object) { }
+}
+""";
+
+ UsingTree(src, TestOptions.RegularPreview,
+ // (3,28): error CS1003: Syntax error, ',' expected
+ // extension(Type, object object) { }
+ Diagnostic(ErrorCode.ERR_SyntaxError, "object").WithArguments(",").WithLocation(3, 28));
+
+ N(SyntaxKind.CompilationUnit);
+ {
+ N(SyntaxKind.ClassDeclaration);
+ {
+ N(SyntaxKind.ClassKeyword);
+ N(SyntaxKind.IdentifierToken, "C");
+ N(SyntaxKind.OpenBraceToken);
+ N(SyntaxKind.ExtensionDeclaration);
+ {
+ N(SyntaxKind.ExtensionKeyword);
+ N(SyntaxKind.ParameterList);
+ {
+ N(SyntaxKind.OpenParenToken);
+ N(SyntaxKind.Parameter);
+ {
+ N(SyntaxKind.IdentifierName);
+ {
+ N(SyntaxKind.IdentifierToken, "Type");
+ }
+ }
+ N(SyntaxKind.CommaToken);
+ N(SyntaxKind.Parameter);
+ {
+ N(SyntaxKind.PredefinedType);
+ {
+ N(SyntaxKind.ObjectKeyword);
+ }
+ }
+ M(SyntaxKind.CommaToken);
+ N(SyntaxKind.Parameter);
+ {
+ N(SyntaxKind.PredefinedType);
+ {
+ N(SyntaxKind.ObjectKeyword);
+ }
+ }
+ N(SyntaxKind.CloseParenToken);
+ }
+ N(SyntaxKind.OpenBraceToken);
+ N(SyntaxKind.CloseBraceToken);
+ }
+ N(SyntaxKind.CloseBraceToken);
+ }
+ N(SyntaxKind.EndOfFileToken);
+ }
+ EOF();
+ }
+
+ [Fact]
+ public void ReceiverParameter_Multiple_05()
+ {
+ var src = """
+class C
+{
+ extension(Type, object =) { }
+}
+""";
+ UsingTree(src, TestOptions.RegularPreview,
+ // (3,29): error CS1525: Invalid expression term ')'
+ // extension(Type, object =) { }
+ Diagnostic(ErrorCode.ERR_InvalidExprTerm, ")").WithArguments(")").WithLocation(3, 29));
+
+ N(SyntaxKind.CompilationUnit);
+ {
+ N(SyntaxKind.ClassDeclaration);
+ {
+ N(SyntaxKind.ClassKeyword);
+ N(SyntaxKind.IdentifierToken, "C");
+ N(SyntaxKind.OpenBraceToken);
+ N(SyntaxKind.ExtensionDeclaration);
+ {
+ N(SyntaxKind.ExtensionKeyword);
+ N(SyntaxKind.ParameterList);
+ {
+ N(SyntaxKind.OpenParenToken);
+ N(SyntaxKind.Parameter);
+ {
+ N(SyntaxKind.IdentifierName);
+ {
+ N(SyntaxKind.IdentifierToken, "Type");
+ }
+ }
+ N(SyntaxKind.CommaToken);
+ N(SyntaxKind.Parameter);
+ {
+ N(SyntaxKind.PredefinedType);
+ {
+ N(SyntaxKind.ObjectKeyword);
+ }
+ N(SyntaxKind.EqualsValueClause);
+ {
+ N(SyntaxKind.EqualsToken);
+ M(SyntaxKind.IdentifierName);
+ {
+ M(SyntaxKind.IdentifierToken);
+ }
+ }
+ }
+ N(SyntaxKind.CloseParenToken);
+ }
+ N(SyntaxKind.OpenBraceToken);
+ N(SyntaxKind.CloseBraceToken);
+ }
+ N(SyntaxKind.CloseBraceToken);
+ }
+ N(SyntaxKind.EndOfFileToken);
+ }
+ EOF();
+ }
+
+ [Fact]
+ public void ReceiverParameter_Multiple_06()
+ {
+ var src = """
+class C
+{
+ extension(Type, object { }
+}
+""";
+ UsingTree(src, TestOptions.RegularPreview,
+ // (3,28): error CS1026: ) expected
+ // extension(Type, object { }
+ Diagnostic(ErrorCode.ERR_CloseParenExpected, "{").WithLocation(3, 28));
+
+ N(SyntaxKind.CompilationUnit);
+ {
+ N(SyntaxKind.ClassDeclaration);
+ {
+ N(SyntaxKind.ClassKeyword);
+ N(SyntaxKind.IdentifierToken, "C");
+ N(SyntaxKind.OpenBraceToken);
+ N(SyntaxKind.ExtensionDeclaration);
+ {
+ N(SyntaxKind.ExtensionKeyword);
+ N(SyntaxKind.ParameterList);
+ {
+ N(SyntaxKind.OpenParenToken);
+ N(SyntaxKind.Parameter);
+ {
+ N(SyntaxKind.IdentifierName);
+ {
+ N(SyntaxKind.IdentifierToken, "Type");
+ }
+ }
+ N(SyntaxKind.CommaToken);
+ N(SyntaxKind.Parameter);
+ {
+ N(SyntaxKind.PredefinedType);
+ {
+ N(SyntaxKind.ObjectKeyword);
+ }
+ }
+ M(SyntaxKind.CloseParenToken);
+ }
+ N(SyntaxKind.OpenBraceToken);
+ N(SyntaxKind.CloseBraceToken);
+ }
+ N(SyntaxKind.CloseBraceToken);
+ }
+ N(SyntaxKind.EndOfFileToken);
+ }
+ EOF();
+ }
+
+ [Fact]
+ public void ReceiverParameter_Multiple_07()
+ {
+ var src = """
+class C
+{
+ extension(Type, params object[]) { }
+}
+""";
+ // PROTOTYPE should be a semantic error
+ var comp = CreateCompilation(src);
+ comp.VerifyDiagnostics();
+
+ UsingTree(src, TestOptions.RegularPreview);
+
+ N(SyntaxKind.CompilationUnit);
+ {
+ N(SyntaxKind.ClassDeclaration);
+ {
+ N(SyntaxKind.ClassKeyword);
+ N(SyntaxKind.IdentifierToken, "C");
+ N(SyntaxKind.OpenBraceToken);
+ N(SyntaxKind.ExtensionDeclaration);
+ {
+ N(SyntaxKind.ExtensionKeyword);
+ N(SyntaxKind.ParameterList);
+ {
+ N(SyntaxKind.OpenParenToken);
+ N(SyntaxKind.Parameter);
+ {
+ N(SyntaxKind.IdentifierName);
+ {
+ N(SyntaxKind.IdentifierToken, "Type");
+ }
+ }
+ N(SyntaxKind.CommaToken);
+ N(SyntaxKind.Parameter);
+ {
+ N(SyntaxKind.ParamsKeyword);
+ N(SyntaxKind.ArrayType);
+ {
+ N(SyntaxKind.PredefinedType);
+ {
+ N(SyntaxKind.ObjectKeyword);
+ }
+ N(SyntaxKind.ArrayRankSpecifier);
+ {
+ N(SyntaxKind.OpenBracketToken);
+ N(SyntaxKind.OmittedArraySizeExpression);
+ {
+ N(SyntaxKind.OmittedArraySizeExpressionToken);
+ }
+ N(SyntaxKind.CloseBracketToken);
+ }
+ }
+ }
+ N(SyntaxKind.CloseParenToken);
+ }
+ N(SyntaxKind.OpenBraceToken);
+ N(SyntaxKind.CloseBraceToken);
+ }
+ N(SyntaxKind.CloseBraceToken);
+ }
+ N(SyntaxKind.EndOfFileToken);
+ }
+ EOF();
+ }
+
+ [Fact]
+ public void ReceiverParameter_MissingClosingParen()
+ {
+ var src = """
+class C
+{
+ extension(object { }
+}
+""";
+
+ UsingTree(src, TestOptions.RegularPreview,
+ // (3,22): error CS1026: ) expected
+ // extension(object { }
+ Diagnostic(ErrorCode.ERR_CloseParenExpected, "{").WithLocation(3, 22));
+
+ N(SyntaxKind.CompilationUnit);
+ {
+ N(SyntaxKind.ClassDeclaration);
+ {
+ N(SyntaxKind.ClassKeyword);
+ N(SyntaxKind.IdentifierToken, "C");
+ N(SyntaxKind.OpenBraceToken);
+ N(SyntaxKind.ExtensionDeclaration);
+ {
+ N(SyntaxKind.ExtensionKeyword);
+ N(SyntaxKind.ParameterList);
+ {
+ N(SyntaxKind.OpenParenToken);
+ N(SyntaxKind.Parameter);
+ {
+ N(SyntaxKind.PredefinedType);
+ {
+ N(SyntaxKind.ObjectKeyword);
+ }
+ }
+ M(SyntaxKind.CloseParenToken);
+ }
+ N(SyntaxKind.OpenBraceToken);
+ N(SyntaxKind.CloseBraceToken);
+ }
+ N(SyntaxKind.CloseBraceToken);
+ }
+ N(SyntaxKind.EndOfFileToken);
+ }
+ EOF();
+ }
+
+ [Fact]
+ public void NoClosingBrace()
+ {
+ UsingTree("""
+class C
+{
+ extension(Type) { void M() { }
+}
+""",
+ TestOptions.RegularPreview,
+ // (4,2): error CS1513: } expected
+ // }
+ Diagnostic(ErrorCode.ERR_RbraceExpected, "").WithLocation(4, 2));
+
+ N(SyntaxKind.CompilationUnit);
+ {
+ N(SyntaxKind.ClassDeclaration);
+ {
+ N(SyntaxKind.ClassKeyword);
+ N(SyntaxKind.IdentifierToken, "C");
+ N(SyntaxKind.OpenBraceToken);
+ N(SyntaxKind.ExtensionDeclaration);
+ {
+ N(SyntaxKind.ExtensionKeyword);
+ N(SyntaxKind.ParameterList);
+ {
+ N(SyntaxKind.OpenParenToken);
+ N(SyntaxKind.Parameter);
+ {
+ N(SyntaxKind.IdentifierName);
+ {
+ N(SyntaxKind.IdentifierToken, "Type");
+ }
+ }
+ N(SyntaxKind.CloseParenToken);
+ }
+ 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.CloseBraceToken);
+ }
+ }
+ N(SyntaxKind.CloseBraceToken);
+ }
+ M(SyntaxKind.CloseBraceToken);
+ }
+ N(SyntaxKind.EndOfFileToken);
+ }
+ EOF();
+ }
+
+ [Fact]
+ public void TopLevel()
+ {
+ var src = """
+extension(Type) { }
+""";
+ // PROTOTYPE should be a semantic error
+ var comp = CreateCompilation(src);
+ comp.VerifyDiagnostics();
+
+ UsingTree(src, TestOptions.RegularPreview);
+
+ N(SyntaxKind.CompilationUnit);
+ {
+ N(SyntaxKind.ExtensionDeclaration);
+ {
+ N(SyntaxKind.ExtensionKeyword);
+ N(SyntaxKind.ParameterList);
+ {
+ N(SyntaxKind.OpenParenToken);
+ N(SyntaxKind.Parameter);
+ {
+ N(SyntaxKind.IdentifierName);
+ {
+ N(SyntaxKind.IdentifierToken, "Type");
+ }
+ }
+ N(SyntaxKind.CloseParenToken);
+ }
+ N(SyntaxKind.OpenBraceToken);
+ N(SyntaxKind.CloseBraceToken);
+ }
+ N(SyntaxKind.EndOfFileToken);
+ }
+ EOF();
+ }
+
+ [Fact]
+ public void InNestedType()
+ {
+ var src = """
+class C
+{
+ class Nested
+ {
+ extension(Type) { }
+ }
+}
+""";
+ // PROTOTYPE should be a semantic error
+ var comp = CreateCompilation(src);
+ comp.VerifyDiagnostics();
+ UsingTree(src, TestOptions.RegularPreview);
+
+ N(SyntaxKind.CompilationUnit);
+ {
+ N(SyntaxKind.ClassDeclaration);
+ {
+ N(SyntaxKind.ClassKeyword);
+ N(SyntaxKind.IdentifierToken, "C");
+ N(SyntaxKind.OpenBraceToken);
+ N(SyntaxKind.ClassDeclaration);
+ {
+ N(SyntaxKind.ClassKeyword);
+ N(SyntaxKind.IdentifierToken, "Nested");
+ N(SyntaxKind.OpenBraceToken);
+ N(SyntaxKind.ExtensionDeclaration);
+ {
+ N(SyntaxKind.ExtensionKeyword);
+ N(SyntaxKind.ParameterList);
+ {
+ N(SyntaxKind.OpenParenToken);
+ N(SyntaxKind.Parameter);
+ {
+ N(SyntaxKind.IdentifierName);
+ {
+ N(SyntaxKind.IdentifierToken, "Type");
+ }
+ }
+ N(SyntaxKind.CloseParenToken);
+ }
+ N(SyntaxKind.OpenBraceToken);
+ N(SyntaxKind.CloseBraceToken);
+ }
+ N(SyntaxKind.CloseBraceToken);
+ }
+ N(SyntaxKind.CloseBraceToken);
+ }
+ N(SyntaxKind.EndOfFileToken);
+ }
+ EOF();
+ }
+
+ [Fact]
+ public void InExtension()
+ {
+ var src = """
+class C
+{
+ extension(Type1)
+ {
+ extension(Type2) { }
+ }
+}
+""";
+ // PROTOTYPE should be a semantic error
+ var comp = CreateCompilation(src);
+ comp.VerifyDiagnostics();
+
+ UsingTree(src, TestOptions.RegularPreview);
+
+ N(SyntaxKind.CompilationUnit);
+ {
+ N(SyntaxKind.ClassDeclaration);
+ {
+ N(SyntaxKind.ClassKeyword);
+ N(SyntaxKind.IdentifierToken, "C");
+ N(SyntaxKind.OpenBraceToken);
+ N(SyntaxKind.ExtensionDeclaration);
+ {
+ N(SyntaxKind.ExtensionKeyword);
+ N(SyntaxKind.ParameterList);
+ {
+ N(SyntaxKind.OpenParenToken);
+ N(SyntaxKind.Parameter);
+ {
+ N(SyntaxKind.IdentifierName);
+ {
+ N(SyntaxKind.IdentifierToken, "Type1");
+ }
+ }
+ N(SyntaxKind.CloseParenToken);
+ }
+ N(SyntaxKind.OpenBraceToken);
+ N(SyntaxKind.ExtensionDeclaration);
+ {
+ N(SyntaxKind.ExtensionKeyword);
+ N(SyntaxKind.ParameterList);
+ {
+ N(SyntaxKind.OpenParenToken);
+ N(SyntaxKind.Parameter);
+ {
+ N(SyntaxKind.IdentifierName);
+ {
+ N(SyntaxKind.IdentifierToken, "Type2");
+ }
+ }
+ N(SyntaxKind.CloseParenToken);
+ }
+ N(SyntaxKind.OpenBraceToken);
+ N(SyntaxKind.CloseBraceToken);
+ }
+ N(SyntaxKind.CloseBraceToken);
+ }
+ N(SyntaxKind.CloseBraceToken);
+ }
+ N(SyntaxKind.EndOfFileToken);
+ }
+ EOF();
+ }
+
+ [Fact]
+ public void WithAttributes()
+ {
+ // PROTOTYPE should be a semantic error
+ UsingTree("""
+class C
+{
+ [MyAttribute]
+ extension(Type) { }
+}
+""",
+ TestOptions.RegularPreview);
+
+ N(SyntaxKind.CompilationUnit);
+ {
+ N(SyntaxKind.ClassDeclaration);
+ {
+ N(SyntaxKind.ClassKeyword);
+ N(SyntaxKind.IdentifierToken, "C");
+ N(SyntaxKind.OpenBraceToken);
+ N(SyntaxKind.ExtensionDeclaration);
+ {
+ N(SyntaxKind.AttributeList);
+ {
+ N(SyntaxKind.OpenBracketToken);
+ N(SyntaxKind.Attribute);
+ {
+ N(SyntaxKind.IdentifierName);
+ {
+ N(SyntaxKind.IdentifierToken, "MyAttribute");
+ }
+ }
+ N(SyntaxKind.CloseBracketToken);
+ }
+ N(SyntaxKind.ExtensionKeyword);
+ N(SyntaxKind.ParameterList);
+ {
+ N(SyntaxKind.OpenParenToken);
+ N(SyntaxKind.Parameter);
+ {
+ N(SyntaxKind.IdentifierName);
+ {
+ N(SyntaxKind.IdentifierToken, "Type");
+ }
+ }
+ N(SyntaxKind.CloseParenToken);
+ }
+ N(SyntaxKind.OpenBraceToken);
+ N(SyntaxKind.CloseBraceToken);
+ }
+ N(SyntaxKind.CloseBraceToken);
+ }
+ N(SyntaxKind.EndOfFileToken);
+ }
+ EOF();
+ }
+
+ [Fact]
+ public void WithModifiers_Partial()
+ {
+ UsingTree("""
+class C
+{
+ partial extension(Type) { }
+}
+""",
+ TestOptions.RegularPreview,
+ // (3,27): error CS1001: Identifier expected
+ // partial extension(Type) { }
+ Diagnostic(ErrorCode.ERR_IdentifierExpected, ")").WithLocation(3, 27));
+
+ 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, "extension");
+ N(SyntaxKind.ParameterList);
+ {
+ N(SyntaxKind.OpenParenToken);
+ N(SyntaxKind.Parameter);
+ {
+ N(SyntaxKind.IdentifierName);
+ {
+ N(SyntaxKind.IdentifierToken, "Type");
+ }
+ M(SyntaxKind.IdentifierToken);
+ }
+ N(SyntaxKind.CloseParenToken);
+ }
+ N(SyntaxKind.Block);
+ {
+ N(SyntaxKind.OpenBraceToken);
+ N(SyntaxKind.CloseBraceToken);
+ }
+ }
+ N(SyntaxKind.CloseBraceToken);
+ }
+ N(SyntaxKind.EndOfFileToken);
+ }
+ EOF();
+ }
+
+ [Fact]
+ public void WithModifiers_Scoped()
+ {
+ UsingTree("""
+class C
+{
+ scoped extension(Type) { }
+}
+""",
+ TestOptions.RegularPreview,
+ // (3,26): error CS1001: Identifier expected
+ // scoped extension(Type) { }
+ Diagnostic(ErrorCode.ERR_IdentifierExpected, ")").WithLocation(3, 26));
+
+ 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, "scoped");
+ }
+ N(SyntaxKind.IdentifierToken, "extension");
+ N(SyntaxKind.ParameterList);
+ {
+ N(SyntaxKind.OpenParenToken);
+ N(SyntaxKind.Parameter);
+ {
+ N(SyntaxKind.IdentifierName);
+ {
+ N(SyntaxKind.IdentifierToken, "Type");
+ }
+ M(SyntaxKind.IdentifierToken);
+ }
+ N(SyntaxKind.CloseParenToken);
+ }
+ N(SyntaxKind.Block);
+ {
+ N(SyntaxKind.OpenBraceToken);
+ N(SyntaxKind.CloseBraceToken);
+ }
+ }
+ N(SyntaxKind.CloseBraceToken);
+ }
+ N(SyntaxKind.EndOfFileToken);
+ }
+ EOF();
+ }
+
+ [Fact]
+ public void WithModifiers_Async()
+ {
+ UsingTree("""
+class C
+{
+ async extension(Type) { }
+}
+""",
+ TestOptions.RegularPreview,
+ // (3,25): error CS1001: Identifier expected
+ // async extension(Type) { }
+ Diagnostic(ErrorCode.ERR_IdentifierExpected, ")").WithLocation(3, 25));
+
+ 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, "async");
+ }
+ N(SyntaxKind.IdentifierToken, "extension");
+ N(SyntaxKind.ParameterList);
+ {
+ N(SyntaxKind.OpenParenToken);
+ N(SyntaxKind.Parameter);
+ {
+ N(SyntaxKind.IdentifierName);
+ {
+ N(SyntaxKind.IdentifierToken, "Type");
+ }
+ M(SyntaxKind.IdentifierToken);
+ }
+ N(SyntaxKind.CloseParenToken);
+ }
+ N(SyntaxKind.Block);
+ {
+ N(SyntaxKind.OpenBraceToken);
+ N(SyntaxKind.CloseBraceToken);
+ }
+ }
+ N(SyntaxKind.CloseBraceToken);
+ }
+ N(SyntaxKind.EndOfFileToken);
+ }
+ EOF();
+ }
+
+ [Fact]
+ public void WithModifiers_Const()
+ {
+ UsingTree("""
+class C
+{
+ const extension(Type) { }
+}
+""",
+ TestOptions.RegularPreview,
+ // (3,20): error CS1001: Identifier expected
+ // const extension(Type) { }
+ Diagnostic(ErrorCode.ERR_IdentifierExpected, "(").WithLocation(3, 20),
+ // (3,20): error CS1528: Expected ; or = (cannot specify constructor arguments in declaration)
+ // const extension(Type) { }
+ Diagnostic(ErrorCode.ERR_BadVarDecl, "(Type").WithLocation(3, 20),
+ // (3,20): error CS1003: Syntax error, '[' expected
+ // const extension(Type) { }
+ Diagnostic(ErrorCode.ERR_SyntaxError, "(").WithArguments("[").WithLocation(3, 20),
+ // (3,25): error CS1003: Syntax error, ']' expected
+ // const extension(Type) { }
+ Diagnostic(ErrorCode.ERR_SyntaxError, ")").WithArguments("]").WithLocation(3, 25),
+ // (3,27): error CS1003: Syntax error, ',' expected
+ // const extension(Type) { }
+ Diagnostic(ErrorCode.ERR_SyntaxError, "{").WithArguments(",").WithLocation(3, 27),
+ // (3,29): error CS1002: ; expected
+ // const extension(Type) { }
+ Diagnostic(ErrorCode.ERR_SemicolonExpected, "}").WithLocation(3, 29),
+ // (4,1): error CS1022: Type or namespace definition, or end-of-file expected
+ // }
+ Diagnostic(ErrorCode.ERR_EOFExpected, "}").WithLocation(4, 1));
+
+ N(SyntaxKind.CompilationUnit);
+ {
+ N(SyntaxKind.ClassDeclaration);
+ {
+ N(SyntaxKind.ClassKeyword);
+ N(SyntaxKind.IdentifierToken, "C");
+ N(SyntaxKind.OpenBraceToken);
+ N(SyntaxKind.FieldDeclaration);
+ {
+ N(SyntaxKind.ConstKeyword);
+ N(SyntaxKind.VariableDeclaration);
+ {
+ N(SyntaxKind.IdentifierName);
+ {
+ N(SyntaxKind.IdentifierToken, "extension");
+ }
+ N(SyntaxKind.VariableDeclarator);
+ {
+ M(SyntaxKind.IdentifierToken);
+ N(SyntaxKind.BracketedArgumentList);
+ {
+ M(SyntaxKind.OpenBracketToken);
+ N(SyntaxKind.Argument);
+ {
+ N(SyntaxKind.IdentifierName);
+ {
+ N(SyntaxKind.IdentifierToken, "Type");
+ }
+ }
+ M(SyntaxKind.CloseBracketToken);
+ }
+ }
+ }
+ M(SyntaxKind.SemicolonToken);
+ }
+ N(SyntaxKind.CloseBraceToken);
+ }
+ N(SyntaxKind.EndOfFileToken);
+ }
+ EOF();
+ }
+
+ [Fact]
+ public void WithModifiers_Fixed()
+ {
+ UsingTree("""
+class C
+{
+ fixed extension(Type) { }
+}
+""",
+ TestOptions.RegularPreview,
+ // (3,20): error CS1001: Identifier expected
+ // fixed extension(Type) { }
+ Diagnostic(ErrorCode.ERR_IdentifierExpected, "(").WithLocation(3, 20),
+ // (3,20): error CS1528: Expected ; or = (cannot specify constructor arguments in declaration)
+ // fixed extension(Type) { }
+ Diagnostic(ErrorCode.ERR_BadVarDecl, "(Type").WithLocation(3, 20),
+ // (3,20): error CS1003: Syntax error, '[' expected
+ // fixed extension(Type) { }
+ Diagnostic(ErrorCode.ERR_SyntaxError, "(").WithArguments("[").WithLocation(3, 20),
+ // (3,25): error CS1003: Syntax error, ']' expected
+ // fixed extension(Type) { }
+ Diagnostic(ErrorCode.ERR_SyntaxError, ")").WithArguments("]").WithLocation(3, 25),
+ // (3,27): error CS1003: Syntax error, ',' expected
+ // fixed extension(Type) { }
+ Diagnostic(ErrorCode.ERR_SyntaxError, "{").WithArguments(",").WithLocation(3, 27),
+ // (3,29): error CS1002: ; expected
+ // fixed extension(Type) { }
+ Diagnostic(ErrorCode.ERR_SemicolonExpected, "}").WithLocation(3, 29),
+ // (4,1): error CS1022: Type or namespace definition, or end-of-file expected
+ // }
+ Diagnostic(ErrorCode.ERR_EOFExpected, "}").WithLocation(4, 1));
+
+ N(SyntaxKind.CompilationUnit);
+ {
+ N(SyntaxKind.ClassDeclaration);
+ {
+ N(SyntaxKind.ClassKeyword);
+ N(SyntaxKind.IdentifierToken, "C");
+ N(SyntaxKind.OpenBraceToken);
+ N(SyntaxKind.FieldDeclaration);
+ {
+ N(SyntaxKind.FixedKeyword);
+ N(SyntaxKind.VariableDeclaration);
+ {
+ N(SyntaxKind.IdentifierName);
+ {
+ N(SyntaxKind.IdentifierToken, "extension");
+ }
+ N(SyntaxKind.VariableDeclarator);
+ {
+ M(SyntaxKind.IdentifierToken);
+ N(SyntaxKind.BracketedArgumentList);
+ {
+ M(SyntaxKind.OpenBracketToken);
+ N(SyntaxKind.Argument);
+ {
+ N(SyntaxKind.IdentifierName);
+ {
+ N(SyntaxKind.IdentifierToken, "Type");
+ }
+ }
+ M(SyntaxKind.CloseBracketToken);
+ }
+ }
+ }
+ M(SyntaxKind.SemicolonToken);
+ }
+ N(SyntaxKind.CloseBraceToken);
+ }
+ N(SyntaxKind.EndOfFileToken);
+ }
+ EOF();
+ }
+
+ [Fact]
+ public void WithModifiers_Ref()
+ {
+ UsingTree("""
+class C
+{
+ ref extension(Type) { }
+}
+""",
+ TestOptions.RegularPreview,
+ // (3,18): error CS1519: Invalid token '(' in a member declaration
+ // ref extension(Type) { }
+ Diagnostic(ErrorCode.ERR_InvalidMemberDecl, "(").WithArguments("(").WithLocation(3, 18),
+ // (3,23): error CS8124: Tuple must contain at least two elements.
+ // ref extension(Type) { }
+ Diagnostic(ErrorCode.ERR_TupleTooFewElements, ")").WithLocation(3, 23),
+ // (3,25): error CS1519: Invalid token '{' in a member declaration
+ // ref extension(Type) { }
+ Diagnostic(ErrorCode.ERR_InvalidMemberDecl, "{").WithArguments("{").WithLocation(3, 25),
+ // (4,1): error CS1022: Type or namespace definition, or end-of-file expected
+ // }
+ Diagnostic(ErrorCode.ERR_EOFExpected, "}").WithLocation(4, 1));
+
+ N(SyntaxKind.CompilationUnit);
+ {
+ N(SyntaxKind.ClassDeclaration);
+ {
+ N(SyntaxKind.ClassKeyword);
+ N(SyntaxKind.IdentifierToken, "C");
+ N(SyntaxKind.OpenBraceToken);
+ N(SyntaxKind.IncompleteMember);
+ {
+ N(SyntaxKind.RefType);
+ {
+ N(SyntaxKind.RefKeyword);
+ N(SyntaxKind.IdentifierName);
+ {
+ N(SyntaxKind.IdentifierToken, "extension");
+ }
+ }
+ }
+ N(SyntaxKind.IncompleteMember);
+ {
+ N(SyntaxKind.TupleType);
+ {
+ N(SyntaxKind.OpenParenToken);
+ N(SyntaxKind.TupleElement);
+ {
+ N(SyntaxKind.IdentifierName);
+ {
+ N(SyntaxKind.IdentifierToken, "Type");
+ }
+ }
+ M(SyntaxKind.CommaToken);
+ M(SyntaxKind.TupleElement);
+ {
+ M(SyntaxKind.IdentifierName);
+ {
+ M(SyntaxKind.IdentifierToken);
+ }
+ }
+ N(SyntaxKind.CloseParenToken);
+ }
+ }
+ N(SyntaxKind.CloseBraceToken);
+ }
+ N(SyntaxKind.EndOfFileToken);
+ }
+ EOF();
+ }
+
+ [Theory]
+ [InlineData("abstract", SyntaxKind.AbstractKeyword)]
+ [InlineData("sealed", SyntaxKind.SealedKeyword)]
+ [InlineData("static", SyntaxKind.StaticKeyword)]
+ [InlineData("new", SyntaxKind.NewKeyword)]
+ [InlineData("public", SyntaxKind.PublicKeyword)]
+ [InlineData("protected", SyntaxKind.ProtectedKeyword)]
+ [InlineData("private", SyntaxKind.PrivateKeyword)]
+ [InlineData("readonly", SyntaxKind.ReadOnlyKeyword)]
+ [InlineData("volatile", SyntaxKind.VolatileKeyword)]
+ [InlineData("extern", SyntaxKind.ExternKeyword)]
+ [InlineData("unsafe", SyntaxKind.UnsafeKeyword)]
+ [InlineData("virtual", SyntaxKind.VirtualKeyword)]
+ [InlineData("override", SyntaxKind.OverrideKeyword)]
+ [InlineData("required", SyntaxKind.RequiredKeyword)]
+ [InlineData("file", SyntaxKind.FileKeyword)]
+ public void WithModifiers_Misc(string modifier, SyntaxKind expected)
+ {
+ var src = $$"""
+class C
+{
+ {{modifier}} extension(Type) { }
+}
+""";
+ // PROTOTYPE should be a semantic error
+ var comp = CreateCompilation(src);
+ comp.VerifyDiagnostics();
+ UsingTree(src, TestOptions.RegularPreview);
+
+ N(SyntaxKind.CompilationUnit);
+ {
+ N(SyntaxKind.ClassDeclaration);
+ {
+ N(SyntaxKind.ClassKeyword);
+ N(SyntaxKind.IdentifierToken, "C");
+ N(SyntaxKind.OpenBraceToken);
+ N(SyntaxKind.ExtensionDeclaration);
+ {
+ N(expected);
+ N(SyntaxKind.ExtensionKeyword);
+ N(SyntaxKind.ParameterList);
+ {
+ N(SyntaxKind.OpenParenToken);
+ N(SyntaxKind.Parameter);
+ {
+ N(SyntaxKind.IdentifierName);
+ {
+ N(SyntaxKind.IdentifierToken, "Type");
+ }
+ }
+ N(SyntaxKind.CloseParenToken);
+ }
+ N(SyntaxKind.OpenBraceToken);
+ N(SyntaxKind.CloseBraceToken);
+ }
+ N(SyntaxKind.CloseBraceToken);
+ }
+ N(SyntaxKind.EndOfFileToken);
+ }
+ EOF();
+ }
+
+ [ConditionalFact(typeof(NoIOperationValidation))] // PROTOTYPE enable IOperation
+ public void Member_Const()
+ {
+ var src = """
+class C
+{
+ extension(Type)
+ {
+ const int i = 0;
+ }
+}
+""";
+ // PROTOTYPE should be a semantic error
+ var comp = CreateCompilation(src);
+ comp.VerifyDiagnostics();
+
+ UsingTree(src, TestOptions.RegularPreview);
+
+ N(SyntaxKind.CompilationUnit);
+ {
+ N(SyntaxKind.ClassDeclaration);
+ {
+ N(SyntaxKind.ClassKeyword);
+ N(SyntaxKind.IdentifierToken, "C");
+ N(SyntaxKind.OpenBraceToken);
+ N(SyntaxKind.ExtensionDeclaration);
+ {
+ N(SyntaxKind.ExtensionKeyword);
+ N(SyntaxKind.ParameterList);
+ {
+ N(SyntaxKind.OpenParenToken);
+ N(SyntaxKind.Parameter);
+ {
+ N(SyntaxKind.IdentifierName);
+ {
+ N(SyntaxKind.IdentifierToken, "Type");
+ }
+ }
+ N(SyntaxKind.CloseParenToken);
+ }
+ N(SyntaxKind.OpenBraceToken);
+ N(SyntaxKind.FieldDeclaration);
+ {
+ N(SyntaxKind.ConstKeyword);
+ N(SyntaxKind.VariableDeclaration);
+ {
+ N(SyntaxKind.PredefinedType);
+ {
+ N(SyntaxKind.IntKeyword);
+ }
+ N(SyntaxKind.VariableDeclarator);
+ {
+ N(SyntaxKind.IdentifierToken, "i");
+ N(SyntaxKind.EqualsValueClause);
+ {
+ N(SyntaxKind.EqualsToken);
+ N(SyntaxKind.NumericLiteralExpression);
+ {
+ N(SyntaxKind.NumericLiteralToken, "0");
+ }
+ }
+ }
+ }
+ N(SyntaxKind.SemicolonToken);
+ }
+ N(SyntaxKind.CloseBraceToken);
+ }
+ N(SyntaxKind.CloseBraceToken);
+ }
+ N(SyntaxKind.EndOfFileToken);
+ }
+ EOF();
+ }
+
+ [Fact]
+ public void Member_FixedField()
+ {
+ var src = """
+class C
+{
+ extension(Type)
+ {
+ fixed int field[10];
+ }
+}
+""";
+ // PROTOTYPE should be a semantic error
+ var comp = CreateCompilation(src);
+ comp.VerifyDiagnostics();
+
+ UsingTree(src, TestOptions.RegularPreview);
+
+ N(SyntaxKind.CompilationUnit);
+ {
+ N(SyntaxKind.ClassDeclaration);
+ {
+ N(SyntaxKind.ClassKeyword);
+ N(SyntaxKind.IdentifierToken, "C");
+ N(SyntaxKind.OpenBraceToken);
+ N(SyntaxKind.ExtensionDeclaration);
+ {
+ N(SyntaxKind.ExtensionKeyword);
+ N(SyntaxKind.ParameterList);
+ {
+ N(SyntaxKind.OpenParenToken);
+ N(SyntaxKind.Parameter);
+ {
+ N(SyntaxKind.IdentifierName);
+ {
+ N(SyntaxKind.IdentifierToken, "Type");
+ }
+ }
+ N(SyntaxKind.CloseParenToken);
+ }
+ N(SyntaxKind.OpenBraceToken);
+ N(SyntaxKind.FieldDeclaration);
+ {
+ N(SyntaxKind.FixedKeyword);
+ N(SyntaxKind.VariableDeclaration);
+ {
+ N(SyntaxKind.PredefinedType);
+ {
+ N(SyntaxKind.IntKeyword);
+ }
+ N(SyntaxKind.VariableDeclarator);
+ {
+ N(SyntaxKind.IdentifierToken, "field");
+ N(SyntaxKind.BracketedArgumentList);
+ {
+ N(SyntaxKind.OpenBracketToken);
+ N(SyntaxKind.Argument);
+ {
+ N(SyntaxKind.NumericLiteralExpression);
+ {
+ N(SyntaxKind.NumericLiteralToken, "10");
+ }
+ }
+ N(SyntaxKind.CloseBracketToken);
+ }
+ }
+ }
+ N(SyntaxKind.SemicolonToken);
+ }
+ N(SyntaxKind.CloseBraceToken);
+ }
+ N(SyntaxKind.CloseBraceToken);
+ }
+ N(SyntaxKind.EndOfFileToken);
+ }
+ EOF();
+ }
+
+ [Fact]
+ public void Member_EventField()
+ {
+ var src = """
+class C
+{
+ extension(Type)
+ {
+ event EventHandler eventField;
+ }
+}
+""";
+ // PROTOTYPE should be a semantic error
+ var comp = CreateCompilation(src);
+ comp.VerifyDiagnostics();
+
+ UsingTree(src, TestOptions.RegularPreview);
+
+ N(SyntaxKind.CompilationUnit);
+ {
+ N(SyntaxKind.ClassDeclaration);
+ {
+ N(SyntaxKind.ClassKeyword);
+ N(SyntaxKind.IdentifierToken, "C");
+ N(SyntaxKind.OpenBraceToken);
+ N(SyntaxKind.ExtensionDeclaration);
+ {
+ N(SyntaxKind.ExtensionKeyword);
+ N(SyntaxKind.ParameterList);
+ {
+ N(SyntaxKind.OpenParenToken);
+ N(SyntaxKind.Parameter);
+ {
+ N(SyntaxKind.IdentifierName);
+ {
+ N(SyntaxKind.IdentifierToken, "Type");
+ }
+ }
+ N(SyntaxKind.CloseParenToken);
+ }
+ N(SyntaxKind.OpenBraceToken);
+ N(SyntaxKind.EventFieldDeclaration);
+ {
+ N(SyntaxKind.EventKeyword);
+ N(SyntaxKind.VariableDeclaration);
+ {
+ N(SyntaxKind.IdentifierName);
+ {
+ N(SyntaxKind.IdentifierToken, "EventHandler");
+ }
+ N(SyntaxKind.VariableDeclarator);
+ {
+ N(SyntaxKind.IdentifierToken, "eventField");
+ }
+ }
+ N(SyntaxKind.SemicolonToken);
+ }
+ N(SyntaxKind.CloseBraceToken);
+ }
+ N(SyntaxKind.CloseBraceToken);
+ }
+ N(SyntaxKind.EndOfFileToken);
+ }
+ EOF();
+ }
+
+ [Fact]
+ public void Member_Event()
+ {
+ var src = """
+class C
+{
+ extension(Type)
+ {
+ event EventHandler Event { add; remove; }
+ }
+}
+""";
+ // PROTOTYPE should be a semantic error
+ var comp = CreateCompilation(src);
+ comp.VerifyDiagnostics();
+
+ UsingTree(src, TestOptions.RegularPreview);
+
+ N(SyntaxKind.CompilationUnit);
+ {
+ N(SyntaxKind.ClassDeclaration);
+ {
+ N(SyntaxKind.ClassKeyword);
+ N(SyntaxKind.IdentifierToken, "C");
+ N(SyntaxKind.OpenBraceToken);
+ N(SyntaxKind.ExtensionDeclaration);
+ {
+ N(SyntaxKind.ExtensionKeyword);
+ N(SyntaxKind.ParameterList);
+ {
+ N(SyntaxKind.OpenParenToken);
+ N(SyntaxKind.Parameter);
+ {
+ N(SyntaxKind.IdentifierName);
+ {
+ N(SyntaxKind.IdentifierToken, "Type");
+ }
+ }
+ N(SyntaxKind.CloseParenToken);
+ }
+ N(SyntaxKind.OpenBraceToken);
+ N(SyntaxKind.EventDeclaration);
+ {
+ N(SyntaxKind.EventKeyword);
+ N(SyntaxKind.IdentifierName);
+ {
+ N(SyntaxKind.IdentifierToken, "EventHandler");
+ }
+ N(SyntaxKind.IdentifierToken, "Event");
+ 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);
+ }
+ }
+ N(SyntaxKind.CloseBraceToken);
+ }
+ N(SyntaxKind.CloseBraceToken);
+ }
+ N(SyntaxKind.EndOfFileToken);
+ }
+ EOF();
+ }
+
+ [Fact]
+ public void Member_MethodAndProperty()
+ {
+ UsingTree("""
+class C
+{
+ extension(Type)
+ {
+ void M() { }
+ int Property { get; set; }
+ }
+}
+""",
+ TestOptions.RegularPreview);
+
+ N(SyntaxKind.CompilationUnit);
+ {
+ N(SyntaxKind.ClassDeclaration);
+ {
+ N(SyntaxKind.ClassKeyword);
+ N(SyntaxKind.IdentifierToken, "C");
+ N(SyntaxKind.OpenBraceToken);
+ N(SyntaxKind.ExtensionDeclaration);
+ {
+ N(SyntaxKind.ExtensionKeyword);
+ N(SyntaxKind.ParameterList);
+ {
+ N(SyntaxKind.OpenParenToken);
+ N(SyntaxKind.Parameter);
+ {
+ N(SyntaxKind.IdentifierName);
+ {
+ N(SyntaxKind.IdentifierToken, "Type");
+ }
+ }
+ N(SyntaxKind.CloseParenToken);
+ }
+ 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.CloseBraceToken);
+ }
+ }
+ N(SyntaxKind.PropertyDeclaration);
+ {
+ N(SyntaxKind.PredefinedType);
+ {
+ N(SyntaxKind.IntKeyword);
+ }
+ N(SyntaxKind.IdentifierToken, "Property");
+ N(SyntaxKind.AccessorList);
+ {
+ N(SyntaxKind.OpenBraceToken);
+ N(SyntaxKind.GetAccessorDeclaration);
+ {
+ N(SyntaxKind.GetKeyword);
+ N(SyntaxKind.SemicolonToken);
+ }
+ N(SyntaxKind.SetAccessorDeclaration);
+ {
+ N(SyntaxKind.SetKeyword);
+ N(SyntaxKind.SemicolonToken);
+ }
+ N(SyntaxKind.CloseBraceToken);
+ }
+ }
+ N(SyntaxKind.CloseBraceToken);
+ }
+ N(SyntaxKind.CloseBraceToken);
+ }
+ N(SyntaxKind.EndOfFileToken);
+ }
+ EOF();
+ }
+
+ [Fact]
+ public void Member_Nested()
+ {
+ var src = """
+class C
+{
+ extension(Type)
+ {
+ class Nested { }
+ }
+}
+""";
+ // PROTOTYPE should be a semantic error
+ var comp = CreateCompilation(src);
+ comp.VerifyDiagnostics();
+
+ UsingTree(src, TestOptions.RegularPreview);
+
+ N(SyntaxKind.CompilationUnit);
+ {
+ N(SyntaxKind.ClassDeclaration);
+ {
+ N(SyntaxKind.ClassKeyword);
+ N(SyntaxKind.IdentifierToken, "C");
+ N(SyntaxKind.OpenBraceToken);
+ N(SyntaxKind.ExtensionDeclaration);
+ {
+ N(SyntaxKind.ExtensionKeyword);
+ N(SyntaxKind.ParameterList);
+ {
+ N(SyntaxKind.OpenParenToken);
+ N(SyntaxKind.Parameter);
+ {
+ N(SyntaxKind.IdentifierName);
+ {
+ N(SyntaxKind.IdentifierToken, "Type");
+ }
+ }
+ N(SyntaxKind.CloseParenToken);
+ }
+ N(SyntaxKind.OpenBraceToken);
+ N(SyntaxKind.ClassDeclaration);
+ {
+ N(SyntaxKind.ClassKeyword);
+ N(SyntaxKind.IdentifierToken, "Nested");
+ N(SyntaxKind.OpenBraceToken);
+ N(SyntaxKind.CloseBraceToken);
+ }
+ N(SyntaxKind.CloseBraceToken);
+ }
+ N(SyntaxKind.CloseBraceToken);
+ }
+ N(SyntaxKind.EndOfFileToken);
+ }
+ EOF();
+ }
+
+ [ConditionalFact(typeof(NoIOperationValidation))] // PROTOTYPE enable IOperation
+ public void Member_Constructor()
+ {
+ var src = """
+class C
+{
+ extension(Type)
+ {
+ Constructor() { }
+ }
+}
+""";
+ // PROTOTYPE should be a semantic error
+ var comp = CreateCompilation(src);
+ comp.VerifyDiagnostics();
+
+ UsingTree(src, TestOptions.RegularPreview);
+
+ N(SyntaxKind.CompilationUnit);
+ {
+ N(SyntaxKind.ClassDeclaration);
+ {
+ N(SyntaxKind.ClassKeyword);
+ N(SyntaxKind.IdentifierToken, "C");
+ N(SyntaxKind.OpenBraceToken);
+ N(SyntaxKind.ExtensionDeclaration);
+ {
+ N(SyntaxKind.ExtensionKeyword);
+ N(SyntaxKind.ParameterList);
+ {
+ N(SyntaxKind.OpenParenToken);
+ N(SyntaxKind.Parameter);
+ {
+ N(SyntaxKind.IdentifierName);
+ {
+ N(SyntaxKind.IdentifierToken, "Type");
+ }
+ }
+ N(SyntaxKind.CloseParenToken);
+ }
+ N(SyntaxKind.OpenBraceToken);
+ N(SyntaxKind.ConstructorDeclaration);
+ {
+ N(SyntaxKind.IdentifierToken, "Constructor");
+ N(SyntaxKind.ParameterList);
+ {
+ N(SyntaxKind.OpenParenToken);
+ N(SyntaxKind.CloseParenToken);
+ }
+ N(SyntaxKind.Block);
+ {
+ N(SyntaxKind.OpenBraceToken);
+ N(SyntaxKind.CloseBraceToken);
+ }
+ }
+ N(SyntaxKind.CloseBraceToken);
+ }
+ N(SyntaxKind.CloseBraceToken);
+ }
+ N(SyntaxKind.EndOfFileToken);
+ }
+ EOF();
+ }
+
+ [ConditionalFact(typeof(NoIOperationValidation))] // PROTOTYPE enable IOperation
+ public void Member_StaticConstructor()
+ {
+ var src = """
+class C
+{
+ extension(Type)
+ {
+ static Constructor() { }
+ }
+}
+""";
+ // PROTOTYPE should be a semantic error
+ var comp = CreateCompilation(src);
+ comp.VerifyDiagnostics();
+
+ UsingTree(src, TestOptions.RegularPreview);
+
+ N(SyntaxKind.CompilationUnit);
+ {
+ N(SyntaxKind.ClassDeclaration);
+ {
+ N(SyntaxKind.ClassKeyword);
+ N(SyntaxKind.IdentifierToken, "C");
+ N(SyntaxKind.OpenBraceToken);
+ N(SyntaxKind.ExtensionDeclaration);
+ {
+ N(SyntaxKind.ExtensionKeyword);
+ N(SyntaxKind.ParameterList);
+ {
+ N(SyntaxKind.OpenParenToken);
+ N(SyntaxKind.Parameter);
+ {
+ N(SyntaxKind.IdentifierName);
+ {
+ N(SyntaxKind.IdentifierToken, "Type");
+ }
+ }
+ N(SyntaxKind.CloseParenToken);
+ }
+ N(SyntaxKind.OpenBraceToken);
+ N(SyntaxKind.ConstructorDeclaration);
+ {
+ N(SyntaxKind.StaticKeyword);
+ N(SyntaxKind.IdentifierToken, "Constructor");
+ N(SyntaxKind.ParameterList);
+ {
+ N(SyntaxKind.OpenParenToken);
+ N(SyntaxKind.CloseParenToken);
+ }
+ N(SyntaxKind.Block);
+ {
+ N(SyntaxKind.OpenBraceToken);
+ N(SyntaxKind.CloseBraceToken);
+ }
+ }
+ N(SyntaxKind.CloseBraceToken);
+ }
+ N(SyntaxKind.CloseBraceToken);
+ }
+ N(SyntaxKind.EndOfFileToken);
+ }
+ EOF();
+ }
+
+ [ConditionalFact(typeof(NoIOperationValidation))] // PROTOTYPE enable IOperation
+ public void Member_Finalizer()
+ {
+ var src = """
+class C
+{
+ extension(Type)
+ {
+ ~Finalizer() { }
+ }
+}
+""";
+ // PROTOTYPE should be a semantic error
+ var comp = CreateCompilation(src);
+ comp.VerifyDiagnostics();
+
+ UsingTree(src, TestOptions.RegularPreview);
+
+ N(SyntaxKind.CompilationUnit);
+ {
+ N(SyntaxKind.ClassDeclaration);
+ {
+ N(SyntaxKind.ClassKeyword);
+ N(SyntaxKind.IdentifierToken, "C");
+ N(SyntaxKind.OpenBraceToken);
+ N(SyntaxKind.ExtensionDeclaration);
+ {
+ N(SyntaxKind.ExtensionKeyword);
+ N(SyntaxKind.ParameterList);
+ {
+ N(SyntaxKind.OpenParenToken);
+ N(SyntaxKind.Parameter);
+ {
+ N(SyntaxKind.IdentifierName);
+ {
+ N(SyntaxKind.IdentifierToken, "Type");
+ }
+ }
+ N(SyntaxKind.CloseParenToken);
+ }
+ N(SyntaxKind.OpenBraceToken);
+ N(SyntaxKind.DestructorDeclaration);
+ {
+ N(SyntaxKind.TildeToken);
+ N(SyntaxKind.IdentifierToken, "Finalizer");
+ N(SyntaxKind.ParameterList);
+ {
+ N(SyntaxKind.OpenParenToken);
+ N(SyntaxKind.CloseParenToken);
+ }
+ N(SyntaxKind.Block);
+ {
+ N(SyntaxKind.OpenBraceToken);
+ N(SyntaxKind.CloseBraceToken);
+ }
+ }
+ N(SyntaxKind.CloseBraceToken);
+ }
+ N(SyntaxKind.CloseBraceToken);
+ }
+ N(SyntaxKind.EndOfFileToken);
+ }
+ EOF();
+ }
+
+ [Fact]
+ public void Member_Field()
+ {
+ var src = """
+class C
+{
+ extension(Type)
+ {
+ int field;
+ }
+}
+""";
+ // PROTOTYPE should be a semantic error
+ var comp = CreateCompilation(src);
+ comp.VerifyDiagnostics();
+
+ UsingTree(src, TestOptions.RegularPreview);
+
+ N(SyntaxKind.CompilationUnit);
+ {
+ N(SyntaxKind.ClassDeclaration);
+ {
+ N(SyntaxKind.ClassKeyword);
+ N(SyntaxKind.IdentifierToken, "C");
+ N(SyntaxKind.OpenBraceToken);
+ N(SyntaxKind.ExtensionDeclaration);
+ {
+ N(SyntaxKind.ExtensionKeyword);
+ N(SyntaxKind.ParameterList);
+ {
+ N(SyntaxKind.OpenParenToken);
+ N(SyntaxKind.Parameter);
+ {
+ N(SyntaxKind.IdentifierName);
+ {
+ N(SyntaxKind.IdentifierToken, "Type");
+ }
+ }
+ N(SyntaxKind.CloseParenToken);
+ }
+ N(SyntaxKind.OpenBraceToken);
+ N(SyntaxKind.FieldDeclaration);
+ {
+ N(SyntaxKind.VariableDeclaration);
+ {
+ N(SyntaxKind.PredefinedType);
+ {
+ N(SyntaxKind.IntKeyword);
+ }
+ N(SyntaxKind.VariableDeclarator);
+ {
+ N(SyntaxKind.IdentifierToken, "field");
+ }
+ }
+ N(SyntaxKind.SemicolonToken);
+ }
+ N(SyntaxKind.CloseBraceToken);
+ }
+ N(SyntaxKind.CloseBraceToken);
+ }
+ N(SyntaxKind.EndOfFileToken);
+ }
+ EOF();
+ }
+
+ [Fact]
+ public void Member_Indexer()
+ {
+ var src = """
+class C
+{
+ extension(Type)
+ {
+ int this[int i] { get => 0; set { } }
+ }
+}
+""";
+
+ UsingTree(src, TestOptions.RegularPreview);
+
+ N(SyntaxKind.CompilationUnit);
+ {
+ N(SyntaxKind.ClassDeclaration);
+ {
+ N(SyntaxKind.ClassKeyword);
+ N(SyntaxKind.IdentifierToken, "C");
+ N(SyntaxKind.OpenBraceToken);
+ N(SyntaxKind.ExtensionDeclaration);
+ {
+ N(SyntaxKind.ExtensionKeyword);
+ N(SyntaxKind.ParameterList);
+ {
+ N(SyntaxKind.OpenParenToken);
+ N(SyntaxKind.Parameter);
+ {
+ N(SyntaxKind.IdentifierName);
+ {
+ N(SyntaxKind.IdentifierToken, "Type");
+ }
+ }
+ N(SyntaxKind.CloseParenToken);
+ }
+ N(SyntaxKind.OpenBraceToken);
+ N(SyntaxKind.IndexerDeclaration);
+ {
+ N(SyntaxKind.PredefinedType);
+ {
+ N(SyntaxKind.IntKeyword);
+ }
+ N(SyntaxKind.ThisKeyword);
+ N(SyntaxKind.BracketedParameterList);
+ {
+ N(SyntaxKind.OpenBracketToken);
+ N(SyntaxKind.Parameter);
+ {
+ N(SyntaxKind.PredefinedType);
+ {
+ N(SyntaxKind.IntKeyword);
+ }
+ N(SyntaxKind.IdentifierToken, "i");
+ }
+ N(SyntaxKind.CloseBracketToken);
+ }
+ N(SyntaxKind.AccessorList);
+ {
+ N(SyntaxKind.OpenBraceToken);
+ N(SyntaxKind.GetAccessorDeclaration);
+ {
+ N(SyntaxKind.GetKeyword);
+ N(SyntaxKind.ArrowExpressionClause);
+ {
+ N(SyntaxKind.EqualsGreaterThanToken);
+ N(SyntaxKind.NumericLiteralExpression);
+ {
+ N(SyntaxKind.NumericLiteralToken, "0");
+ }
+ }
+ N(SyntaxKind.SemicolonToken);
+ }
+ N(SyntaxKind.SetAccessorDeclaration);
+ {
+ N(SyntaxKind.SetKeyword);
+ N(SyntaxKind.Block);
+ {
+ N(SyntaxKind.OpenBraceToken);
+ N(SyntaxKind.CloseBraceToken);
+ }
+ }
+ N(SyntaxKind.CloseBraceToken);
+ }
+ }
+ N(SyntaxKind.CloseBraceToken);
+ }
+ N(SyntaxKind.CloseBraceToken);
+ }
+ N(SyntaxKind.EndOfFileToken);
+ }
+ EOF();
+ }
+
+ [Fact]
+ public void Member_Operator()
+ {
+ var src = """
+class C
+{
+ extension(Type)
+ {
+ public static Type operator +(Type a, Type b) => a;
+ }
+}
+""";
+
+ UsingTree(src, TestOptions.RegularPreview);
+
+ N(SyntaxKind.CompilationUnit);
+ {
+ N(SyntaxKind.ClassDeclaration);
+ {
+ N(SyntaxKind.ClassKeyword);
+ N(SyntaxKind.IdentifierToken, "C");
+ N(SyntaxKind.OpenBraceToken);
+ N(SyntaxKind.ExtensionDeclaration);
+ {
+ N(SyntaxKind.ExtensionKeyword);
+ N(SyntaxKind.ParameterList);
+ {
+ N(SyntaxKind.OpenParenToken);
+ N(SyntaxKind.Parameter);
+ {
+ N(SyntaxKind.IdentifierName);
+ {
+ N(SyntaxKind.IdentifierToken, "Type");
+ }
+ }
+ N(SyntaxKind.CloseParenToken);
+ }
+ N(SyntaxKind.OpenBraceToken);
+ N(SyntaxKind.OperatorDeclaration);
+ {
+ N(SyntaxKind.PublicKeyword);
+ N(SyntaxKind.StaticKeyword);
+ N(SyntaxKind.IdentifierName);
+ {
+ N(SyntaxKind.IdentifierToken, "Type");
+ }
+ N(SyntaxKind.OperatorKeyword);
+ N(SyntaxKind.PlusToken);
+ N(SyntaxKind.ParameterList);
+ {
+ N(SyntaxKind.OpenParenToken);
+ N(SyntaxKind.Parameter);
+ {
+ N(SyntaxKind.IdentifierName);
+ {
+ N(SyntaxKind.IdentifierToken, "Type");
+ }
+ N(SyntaxKind.IdentifierToken, "a");
+ }
+ N(SyntaxKind.CommaToken);
+ N(SyntaxKind.Parameter);
+ {
+ N(SyntaxKind.IdentifierName);
+ {
+ N(SyntaxKind.IdentifierToken, "Type");
+ }
+ N(SyntaxKind.IdentifierToken, "b");
+ }
+ N(SyntaxKind.CloseParenToken);
+ }
+ N(SyntaxKind.ArrowExpressionClause);
+ {
+ N(SyntaxKind.EqualsGreaterThanToken);
+ N(SyntaxKind.IdentifierName);
+ {
+ N(SyntaxKind.IdentifierToken, "a");
+ }
+ }
+ N(SyntaxKind.SemicolonToken);
+ }
+ N(SyntaxKind.CloseBraceToken);
+ }
+ N(SyntaxKind.CloseBraceToken);
+ }
+ N(SyntaxKind.EndOfFileToken);
+ }
+ EOF();
+ }
+
+ [Fact]
+ public void Member_ConversionOperator()
+ {
+ var src = """
+class C
+{
+ extension(Type)
+ {
+ static implicit operator int(Type t) => 0;
+ }
+}
+""";
+
+ UsingTree(src, TestOptions.RegularPreview);
+
+ N(SyntaxKind.CompilationUnit);
+ {
+ N(SyntaxKind.ClassDeclaration);
+ {
+ N(SyntaxKind.ClassKeyword);
+ N(SyntaxKind.IdentifierToken, "C");
+ N(SyntaxKind.OpenBraceToken);
+ N(SyntaxKind.ExtensionDeclaration);
+ {
+ N(SyntaxKind.ExtensionKeyword);
+ N(SyntaxKind.ParameterList);
+ {
+ N(SyntaxKind.OpenParenToken);
+ N(SyntaxKind.Parameter);
+ {
+ N(SyntaxKind.IdentifierName);
+ {
+ N(SyntaxKind.IdentifierToken, "Type");
+ }
+ }
+ N(SyntaxKind.CloseParenToken);
+ }
+ N(SyntaxKind.OpenBraceToken);
+ N(SyntaxKind.ConversionOperatorDeclaration);
+ {
+ N(SyntaxKind.StaticKeyword);
+ N(SyntaxKind.ImplicitKeyword);
+ N(SyntaxKind.OperatorKeyword);
+ N(SyntaxKind.PredefinedType);
+ {
+ N(SyntaxKind.IntKeyword);
+ }
+ N(SyntaxKind.ParameterList);
+ {
+ N(SyntaxKind.OpenParenToken);
+ N(SyntaxKind.Parameter);
+ {
+ N(SyntaxKind.IdentifierName);
+ {
+ N(SyntaxKind.IdentifierToken, "Type");
+ }
+ N(SyntaxKind.IdentifierToken, "t");
+ }
+ N(SyntaxKind.CloseParenToken);
+ }
+ N(SyntaxKind.ArrowExpressionClause);
+ {
+ N(SyntaxKind.EqualsGreaterThanToken);
+ N(SyntaxKind.NumericLiteralExpression);
+ {
+ N(SyntaxKind.NumericLiteralToken, "0");
+ }
+ }
+ N(SyntaxKind.SemicolonToken);
+ }
+ N(SyntaxKind.CloseBraceToken);
+ }
+ N(SyntaxKind.CloseBraceToken);
+ }
+ N(SyntaxKind.EndOfFileToken);
+ }
+ EOF();
+ }
+
+ [Fact]
+ public void WithRef()
+ {
+ UsingTree("""
+class C
+{
+ ref extension(Type) { }
+}
+""",
+ TestOptions.RegularPreview,
+ // (3,18): error CS1519: Invalid token '(' in class, record, struct, or interface member declaration
+ // ref extension(Type) { }
+ Diagnostic(ErrorCode.ERR_InvalidMemberDecl, "(").WithArguments("(").WithLocation(3, 18),
+ // (3,23): error CS8124: Tuple must contain at least two elements.
+ // ref extension(Type) { }
+ Diagnostic(ErrorCode.ERR_TupleTooFewElements, ")").WithLocation(3, 23),
+ // (3,25): error CS1519: Invalid token '{' in class, record, struct, or interface member declaration
+ // ref extension(Type) { }
+ Diagnostic(ErrorCode.ERR_InvalidMemberDecl, "{").WithArguments("{").WithLocation(3, 25),
+ // (4,1): error CS1022: Type or namespace definition, or end-of-file expected
+ // }
+ Diagnostic(ErrorCode.ERR_EOFExpected, "}").WithLocation(4, 1));
+ N(SyntaxKind.CompilationUnit);
+ {
+ N(SyntaxKind.ClassDeclaration);
+ {
+ N(SyntaxKind.ClassKeyword);
+ N(SyntaxKind.IdentifierToken, "C");
+ N(SyntaxKind.OpenBraceToken);
+ N(SyntaxKind.IncompleteMember);
+ {
+ N(SyntaxKind.RefType);
+ {
+ N(SyntaxKind.RefKeyword);
+ N(SyntaxKind.IdentifierName);
+ {
+ N(SyntaxKind.IdentifierToken, "extension");
+ }
+ }
+ }
+ N(SyntaxKind.IncompleteMember);
+ {
+ N(SyntaxKind.TupleType);
+ {
+ N(SyntaxKind.OpenParenToken);
+ N(SyntaxKind.TupleElement);
+ {
+ N(SyntaxKind.IdentifierName);
+ {
+ N(SyntaxKind.IdentifierToken, "Type");
+ }
+ }
+ M(SyntaxKind.CommaToken);
+ M(SyntaxKind.TupleElement);
+ {
+ M(SyntaxKind.IdentifierName);
+ {
+ M(SyntaxKind.IdentifierToken);
+ }
+ }
+ N(SyntaxKind.CloseParenToken);
+ }
+ }
+ N(SyntaxKind.CloseBraceToken);
+ }
+ N(SyntaxKind.EndOfFileToken);
+ }
+ EOF();
+ }
+
+ [Fact]
+ public void WithAttributeOnParameter()
+ {
+ UsingTree("""
+class C
+{
+ extension([MyAttribute] Type) { }
+}
+""",
+ TestOptions.RegularPreview);
+
+ N(SyntaxKind.CompilationUnit);
+ {
+ N(SyntaxKind.ClassDeclaration);
+ {
+ N(SyntaxKind.ClassKeyword);
+ N(SyntaxKind.IdentifierToken, "C");
+ N(SyntaxKind.OpenBraceToken);
+ N(SyntaxKind.ExtensionDeclaration);
+ {
+ N(SyntaxKind.ExtensionKeyword);
+ N(SyntaxKind.ParameterList);
+ {
+ N(SyntaxKind.OpenParenToken);
+ N(SyntaxKind.Parameter);
+ {
+ N(SyntaxKind.AttributeList);
+ {
+ N(SyntaxKind.OpenBracketToken);
+ N(SyntaxKind.Attribute);
+ {
+ N(SyntaxKind.IdentifierName);
+ {
+ N(SyntaxKind.IdentifierToken, "MyAttribute");
+ }
+ }
+ N(SyntaxKind.CloseBracketToken);
+ }
+ N(SyntaxKind.IdentifierName);
+ {
+ N(SyntaxKind.IdentifierToken, "Type");
+ }
+ }
+ N(SyntaxKind.CloseParenToken);
+ }
+ N(SyntaxKind.OpenBraceToken);
+ N(SyntaxKind.CloseBraceToken);
+ }
+ N(SyntaxKind.CloseBraceToken);
+ }
+ N(SyntaxKind.EndOfFileToken);
+ }
+ EOF();
+ }
+
+ [Fact]
+ public void WithModifierOnParameter()
+ {
+ UsingTree("""
+class C
+{
+ extension(ref Type) { }
+}
+""",
+ TestOptions.RegularPreview);
+
+ N(SyntaxKind.CompilationUnit);
+ {
+ N(SyntaxKind.ClassDeclaration);
+ {
+ N(SyntaxKind.ClassKeyword);
+ N(SyntaxKind.IdentifierToken, "C");
+ N(SyntaxKind.OpenBraceToken);
+ N(SyntaxKind.ExtensionDeclaration);
+ {
+ N(SyntaxKind.ExtensionKeyword);
+ N(SyntaxKind.ParameterList);
+ {
+ N(SyntaxKind.OpenParenToken);
+ N(SyntaxKind.Parameter);
+ {
+ N(SyntaxKind.RefKeyword);
+ N(SyntaxKind.IdentifierName);
+ {
+ N(SyntaxKind.IdentifierToken, "Type");
+ }
+ }
+ N(SyntaxKind.CloseParenToken);
+ }
+ N(SyntaxKind.OpenBraceToken);
+ N(SyntaxKind.CloseBraceToken);
+ }
+ N(SyntaxKind.CloseBraceToken);
+ }
+ N(SyntaxKind.EndOfFileToken);
+ }
+ EOF();
+ }
+
+ [Fact]
+ public void WithModifierOnParameter_Scoped()
+ {
+ UsingTree("""
+class C
+{
+ extension(scoped Type x) { }
+}
+""",
+ TestOptions.RegularPreview);
+
+ N(SyntaxKind.CompilationUnit);
+ {
+ N(SyntaxKind.ClassDeclaration);
+ {
+ N(SyntaxKind.ClassKeyword);
+ N(SyntaxKind.IdentifierToken, "C");
+ N(SyntaxKind.OpenBraceToken);
+ N(SyntaxKind.ExtensionDeclaration);
+ {
+ N(SyntaxKind.ExtensionKeyword);
+ N(SyntaxKind.ParameterList);
+ {
+ N(SyntaxKind.OpenParenToken);
+ N(SyntaxKind.Parameter);
+ {
+ N(SyntaxKind.ScopedKeyword);
+ N(SyntaxKind.IdentifierName);
+ {
+ N(SyntaxKind.IdentifierToken, "Type");
+ }
+ N(SyntaxKind.IdentifierToken, "x");
+ }
+ N(SyntaxKind.CloseParenToken);
+ }
+ N(SyntaxKind.OpenBraceToken);
+ N(SyntaxKind.CloseBraceToken);
+ }
+ N(SyntaxKind.CloseBraceToken);
+ }
+ N(SyntaxKind.EndOfFileToken);
+ }
+ EOF();
+ }
+
+ [Fact]
+ public void WithModifierOnParameter_ScopedRef()
+ {
+ UsingTree("""
+class C
+{
+ extension(scoped ref Type x) { }
+}
+""",
+ TestOptions.RegularPreview);
+
+ N(SyntaxKind.CompilationUnit);
+ {
+ N(SyntaxKind.ClassDeclaration);
+ {
+ N(SyntaxKind.ClassKeyword);
+ N(SyntaxKind.IdentifierToken, "C");
+ N(SyntaxKind.OpenBraceToken);
+ N(SyntaxKind.ExtensionDeclaration);
+ {
+ N(SyntaxKind.ExtensionKeyword);
+ N(SyntaxKind.ParameterList);
+ {
+ N(SyntaxKind.OpenParenToken);
+ N(SyntaxKind.Parameter);
+ {
+ N(SyntaxKind.ScopedKeyword);
+ N(SyntaxKind.RefKeyword);
+ N(SyntaxKind.IdentifierName);
+ {
+ N(SyntaxKind.IdentifierToken, "Type");
+ }
+ N(SyntaxKind.IdentifierToken, "x");
+ }
+ N(SyntaxKind.CloseParenToken);
+ }
+ N(SyntaxKind.OpenBraceToken);
+ N(SyntaxKind.CloseBraceToken);
+ }
+ N(SyntaxKind.CloseBraceToken);
+ }
+ N(SyntaxKind.EndOfFileToken);
+ }
+ EOF();
+ }
+
+ [Theory]
+ [InlineData("partial")]
+ [InlineData("await")]
+ [InlineData("on")]
+ [InlineData("by")]
+ public void MiscIdentifier(string identifier)
+ {
+ UsingTree($$"""
+class C
+{
+ extension(Type {{identifier}}) { }
+}
+""",
+ TestOptions.RegularPreview);
+
+ N(SyntaxKind.CompilationUnit);
+ {
+ N(SyntaxKind.ClassDeclaration);
+ {
+ N(SyntaxKind.ClassKeyword);
+ N(SyntaxKind.IdentifierToken, "C");
+ N(SyntaxKind.OpenBraceToken);
+ N(SyntaxKind.ExtensionDeclaration);
+ {
+ N(SyntaxKind.ExtensionKeyword);
+ N(SyntaxKind.ParameterList);
+ {
+ N(SyntaxKind.OpenParenToken);
+ N(SyntaxKind.Parameter);
+ {
+ N(SyntaxKind.IdentifierName);
+ {
+ N(SyntaxKind.IdentifierToken, "Type");
+ }
+ N(SyntaxKind.IdentifierToken, identifier);
+ }
+ N(SyntaxKind.CloseParenToken);
+ }
+ N(SyntaxKind.OpenBraceToken);
+ N(SyntaxKind.CloseBraceToken);
+ }
+ N(SyntaxKind.CloseBraceToken);
+ }
+ N(SyntaxKind.EndOfFileToken);
+ }
+ EOF();
+ }
+
+ [Fact]
+ public void WithTerminator_SemiColon()
+ {
+ UsingTree("""
+class C
+{
+ extension(Type) { ;
+ class D { }
+}
+""",
+ TestOptions.RegularPreview,
+ // (3,23): error CS1519: Invalid token ';' in a member declaration
+ // extension(Type) { ;
+ Diagnostic(ErrorCode.ERR_InvalidMemberDecl, ";").WithArguments(";").WithLocation(3, 23),
+ // (5,2): error CS1513: } expected
+ // }
+ Diagnostic(ErrorCode.ERR_RbraceExpected, "").WithLocation(5, 2));
+
+ N(SyntaxKind.CompilationUnit);
+ {
+ N(SyntaxKind.ClassDeclaration);
+ {
+ N(SyntaxKind.ClassKeyword);
+ N(SyntaxKind.IdentifierToken, "C");
+ N(SyntaxKind.OpenBraceToken);
+ N(SyntaxKind.ExtensionDeclaration);
+ {
+ N(SyntaxKind.ExtensionKeyword);
+ N(SyntaxKind.ParameterList);
+ {
+ N(SyntaxKind.OpenParenToken);
+ N(SyntaxKind.Parameter);
+ {
+ N(SyntaxKind.IdentifierName);
+ {
+ N(SyntaxKind.IdentifierToken, "Type");
+ }
+ }
+ N(SyntaxKind.CloseParenToken);
+ }
+ N(SyntaxKind.OpenBraceToken);
+ N(SyntaxKind.ClassDeclaration);
+ {
+ N(SyntaxKind.ClassKeyword);
+ N(SyntaxKind.IdentifierToken, "D");
+ N(SyntaxKind.OpenBraceToken);
+ N(SyntaxKind.CloseBraceToken);
+ }
+ N(SyntaxKind.CloseBraceToken);
+ }
+ M(SyntaxKind.CloseBraceToken);
+ }
+ N(SyntaxKind.EndOfFileToken);
+ }
+ EOF();
+ }
+
+ [Fact]
+ public void WithTerminator_SemiColon_02()
+ {
+ UsingTree("""
+class C
+{
+ extension(Type) { ;
+}
+""",
+ TestOptions.RegularPreview,
+ // (3,23): error CS1519: Invalid token ';' in a member declaration
+ // extension(Type) { ;
+ Diagnostic(ErrorCode.ERR_InvalidMemberDecl, ";").WithArguments(";").WithLocation(3, 23),
+ // (4,2): error CS1513: } expected
+ // }
+ Diagnostic(ErrorCode.ERR_RbraceExpected, "").WithLocation(4, 2));
+
+ N(SyntaxKind.CompilationUnit);
+ {
+ N(SyntaxKind.ClassDeclaration);
+ {
+ N(SyntaxKind.ClassKeyword);
+ N(SyntaxKind.IdentifierToken, "C");
+ N(SyntaxKind.OpenBraceToken);
+ N(SyntaxKind.ExtensionDeclaration);
+ {
+ N(SyntaxKind.ExtensionKeyword);
+ N(SyntaxKind.ParameterList);
+ {
+ N(SyntaxKind.OpenParenToken);
+ N(SyntaxKind.Parameter);
+ {
+ N(SyntaxKind.IdentifierName);
+ {
+ N(SyntaxKind.IdentifierToken, "Type");
+ }
+ }
+ N(SyntaxKind.CloseParenToken);
+ }
+ N(SyntaxKind.OpenBraceToken);
+ N(SyntaxKind.CloseBraceToken);
+ }
+ M(SyntaxKind.CloseBraceToken);
+ }
+ N(SyntaxKind.EndOfFileToken);
+ }
+ EOF();
+ }
+
+ [Fact]
+ public void WithTerminator_SemiColon_03()
+ {
+ UsingTree("""
+class C
+{
+ extension' expected
+ // extension").WithLocation(3, 17),
+ // (3,17): error CS1003: Syntax error, '(' expected
+ // extension(Type) where T : struct;
+ class D { }
+}
+""",
+ TestOptions.RegularPreview);
+
+ N(SyntaxKind.CompilationUnit);
+ {
+ N(SyntaxKind.ClassDeclaration);
+ {
+ N(SyntaxKind.ClassKeyword);
+ N(SyntaxKind.IdentifierToken, "C");
+ N(SyntaxKind.OpenBraceToken);
+ N(SyntaxKind.ExtensionDeclaration);
+ {
+ N(SyntaxKind.ExtensionKeyword);
+ N(SyntaxKind.TypeParameterList);
+ {
+ N(SyntaxKind.LessThanToken);
+ N(SyntaxKind.TypeParameter);
+ {
+ N(SyntaxKind.IdentifierToken, "T");
+ }
+ N(SyntaxKind.GreaterThanToken);
+ }
+ N(SyntaxKind.ParameterList);
+ {
+ N(SyntaxKind.OpenParenToken);
+ N(SyntaxKind.Parameter);
+ {
+ N(SyntaxKind.IdentifierName);
+ {
+ N(SyntaxKind.IdentifierToken, "Type");
+ }
+ }
+ N(SyntaxKind.CloseParenToken);
+ }
+ N(SyntaxKind.TypeParameterConstraintClause);
+ {
+ N(SyntaxKind.WhereKeyword);
+ N(SyntaxKind.IdentifierName);
+ {
+ N(SyntaxKind.IdentifierToken, "T");
+ }
+ N(SyntaxKind.ColonToken);
+ N(SyntaxKind.StructConstraint);
+ {
+ N(SyntaxKind.StructKeyword);
+ }
+ }
+ N(SyntaxKind.SemicolonToken);
+ }
+ N(SyntaxKind.ClassDeclaration);
+ {
+ N(SyntaxKind.ClassKeyword);
+ N(SyntaxKind.IdentifierToken, "D");
+ N(SyntaxKind.OpenBraceToken);
+ N(SyntaxKind.CloseBraceToken);
+ }
+ N(SyntaxKind.CloseBraceToken);
+ }
+ N(SyntaxKind.EndOfFileToken);
+ }
+ EOF();
+ }
+
+ [Fact]
+ public void WithTerminator_OpenBrace()
+ {
+ UsingTree("""
+class C
+{
+ extension(Type) { {
+}
+""",
+ TestOptions.RegularPreview,
+ // (3,23): error CS1519: Invalid token '{' in a member declaration
+ // extension(Type) { {
+ Diagnostic(ErrorCode.ERR_InvalidMemberDecl, "{").WithArguments("{").WithLocation(3, 23),
+ // (4,2): error CS1513: } expected
+ // }
+ Diagnostic(ErrorCode.ERR_RbraceExpected, "").WithLocation(4, 2));
+
+ N(SyntaxKind.CompilationUnit);
+ {
+ N(SyntaxKind.ClassDeclaration);
+ {
+ N(SyntaxKind.ClassKeyword);
+ N(SyntaxKind.IdentifierToken, "C");
+ N(SyntaxKind.OpenBraceToken);
+ N(SyntaxKind.ExtensionDeclaration);
+ {
+ N(SyntaxKind.ExtensionKeyword);
+ N(SyntaxKind.ParameterList);
+ {
+ N(SyntaxKind.OpenParenToken);
+ N(SyntaxKind.Parameter);
+ {
+ N(SyntaxKind.IdentifierName);
+ {
+ N(SyntaxKind.IdentifierToken, "Type");
+ }
+ }
+ N(SyntaxKind.CloseParenToken);
+ }
+ N(SyntaxKind.OpenBraceToken);
+ N(SyntaxKind.CloseBraceToken);
+ }
+ M(SyntaxKind.CloseBraceToken);
+ }
+ N(SyntaxKind.EndOfFileToken);
+ }
+ EOF();
+ }
+
+ [Fact]
+ public void WithTerminator_OpenBrace_02()
+ {
+ UsingTree("""
+class C
+{
+ extension(Type) where { }
+}
+""",
+ TestOptions.RegularPreview,
+ // (3,30): error CS1001: Identifier expected
+ // extension(Type) where { }
+ Diagnostic(ErrorCode.ERR_IdentifierExpected, "{").WithLocation(3, 30),
+ // (3,30): error CS1003: Syntax error, ':' expected
+ // extension(Type) where { }
+ Diagnostic(ErrorCode.ERR_SyntaxError, "{").WithArguments(":").WithLocation(3, 30),
+ // (3,30): error CS1031: Type expected
+ // extension(Type) where { }
+ Diagnostic(ErrorCode.ERR_TypeExpected, "{").WithLocation(3, 30));
+
+ N(SyntaxKind.CompilationUnit);
+ {
+ N(SyntaxKind.ClassDeclaration);
+ {
+ N(SyntaxKind.ClassKeyword);
+ N(SyntaxKind.IdentifierToken, "C");
+ N(SyntaxKind.OpenBraceToken);
+ N(SyntaxKind.ExtensionDeclaration);
+ {
+ N(SyntaxKind.ExtensionKeyword);
+ N(SyntaxKind.TypeParameterList);
+ {
+ N(SyntaxKind.LessThanToken);
+ N(SyntaxKind.TypeParameter);
+ {
+ N(SyntaxKind.IdentifierToken, "T");
+ }
+ N(SyntaxKind.GreaterThanToken);
+ }
+ N(SyntaxKind.ParameterList);
+ {
+ N(SyntaxKind.OpenParenToken);
+ N(SyntaxKind.Parameter);
+ {
+ N(SyntaxKind.IdentifierName);
+ {
+ N(SyntaxKind.IdentifierToken, "Type");
+ }
+ }
+ N(SyntaxKind.CloseParenToken);
+ }
+ N(SyntaxKind.TypeParameterConstraintClause);
+ {
+ N(SyntaxKind.WhereKeyword);
+ M(SyntaxKind.IdentifierName);
+ {
+ M(SyntaxKind.IdentifierToken);
+ }
+ M(SyntaxKind.ColonToken);
+ M(SyntaxKind.TypeConstraint);
+ {
+ M(SyntaxKind.IdentifierName);
+ {
+ M(SyntaxKind.IdentifierToken);
+ }
+ }
+ }
+ N(SyntaxKind.OpenBraceToken);
+ N(SyntaxKind.CloseBraceToken);
+ }
+ N(SyntaxKind.CloseBraceToken);
+ }
+ N(SyntaxKind.EndOfFileToken);
+ }
+ EOF();
+ }
+
+ [Fact]
+ public void WithTerminator_OpenBrace_03()
+ {
+ UsingTree("""
+class C
+{
+ extension(Type) where T { }
+ class D { }
+}
+""",
+ TestOptions.RegularPreview,
+ // (3,32): error CS1003: Syntax error, ':' expected
+ // extension(Type) where T { }
+ Diagnostic(ErrorCode.ERR_SyntaxError, "{").WithArguments(":").WithLocation(3, 32),
+ // (3,32): error CS1031: Type expected
+ // extension(Type) where T { }
+ Diagnostic(ErrorCode.ERR_TypeExpected, "{").WithLocation(3, 32));
+
+ N(SyntaxKind.CompilationUnit);
+ {
+ N(SyntaxKind.ClassDeclaration);
+ {
+ N(SyntaxKind.ClassKeyword);
+ N(SyntaxKind.IdentifierToken, "C");
+ N(SyntaxKind.OpenBraceToken);
+ N(SyntaxKind.ExtensionDeclaration);
+ {
+ N(SyntaxKind.ExtensionKeyword);
+ N(SyntaxKind.TypeParameterList);
+ {
+ N(SyntaxKind.LessThanToken);
+ N(SyntaxKind.TypeParameter);
+ {
+ N(SyntaxKind.IdentifierToken, "T");
+ }
+ N(SyntaxKind.GreaterThanToken);
+ }
+ N(SyntaxKind.ParameterList);
+ {
+ N(SyntaxKind.OpenParenToken);
+ N(SyntaxKind.Parameter);
+ {
+ N(SyntaxKind.IdentifierName);
+ {
+ N(SyntaxKind.IdentifierToken, "Type");
+ }
+ }
+ N(SyntaxKind.CloseParenToken);
+ }
+ N(SyntaxKind.TypeParameterConstraintClause);
+ {
+ N(SyntaxKind.WhereKeyword);
+ N(SyntaxKind.IdentifierName);
+ {
+ N(SyntaxKind.IdentifierToken, "T");
+ }
+ M(SyntaxKind.ColonToken);
+ M(SyntaxKind.TypeConstraint);
+ {
+ M(SyntaxKind.IdentifierName);
+ {
+ M(SyntaxKind.IdentifierToken);
+ }
+ }
+ }
+ N(SyntaxKind.OpenBraceToken);
+ N(SyntaxKind.CloseBraceToken);
+ }
+ N(SyntaxKind.ClassDeclaration);
+ {
+ N(SyntaxKind.ClassKeyword);
+ N(SyntaxKind.IdentifierToken, "D");
+ N(SyntaxKind.OpenBraceToken);
+ N(SyntaxKind.CloseBraceToken);
+ }
+ N(SyntaxKind.CloseBraceToken);
+ }
+ N(SyntaxKind.EndOfFileToken);
+ }
+ EOF();
+ }
+
+ [Fact]
+ public void WithTerminator_OpenBrace_04()
+ {
+ UsingTree("""
+class C
+{
+ extension(Type) where T : { }
+}
+""",
+ TestOptions.RegularPreview,
+ // (3,34): error CS1031: Type expected
+ // extension(Type) where T : { }
+ Diagnostic(ErrorCode.ERR_TypeExpected, "{").WithLocation(3, 34));
+
+ N(SyntaxKind.CompilationUnit);
+ {
+ N(SyntaxKind.ClassDeclaration);
+ {
+ N(SyntaxKind.ClassKeyword);
+ N(SyntaxKind.IdentifierToken, "C");
+ N(SyntaxKind.OpenBraceToken);
+ N(SyntaxKind.ExtensionDeclaration);
+ {
+ N(SyntaxKind.ExtensionKeyword);
+ N(SyntaxKind.TypeParameterList);
+ {
+ N(SyntaxKind.LessThanToken);
+ N(SyntaxKind.TypeParameter);
+ {
+ N(SyntaxKind.IdentifierToken, "T");
+ }
+ N(SyntaxKind.GreaterThanToken);
+ }
+ N(SyntaxKind.ParameterList);
+ {
+ N(SyntaxKind.OpenParenToken);
+ N(SyntaxKind.Parameter);
+ {
+ N(SyntaxKind.IdentifierName);
+ {
+ N(SyntaxKind.IdentifierToken, "Type");
+ }
+ }
+ N(SyntaxKind.CloseParenToken);
+ }
+ N(SyntaxKind.TypeParameterConstraintClause);
+ {
+ N(SyntaxKind.WhereKeyword);
+ N(SyntaxKind.IdentifierName);
+ {
+ N(SyntaxKind.IdentifierToken, "T");
+ }
+ N(SyntaxKind.ColonToken);
+ M(SyntaxKind.TypeConstraint);
+ {
+ M(SyntaxKind.IdentifierName);
+ {
+ M(SyntaxKind.IdentifierToken);
+ }
+ }
+ }
+ N(SyntaxKind.OpenBraceToken);
+ N(SyntaxKind.CloseBraceToken);
+ }
+ N(SyntaxKind.CloseBraceToken);
+ }
+ N(SyntaxKind.EndOfFileToken);
+ }
+ EOF();
+ }
+
+ [Fact]
+ public void WithTerminator_OpenBrace_05()
+ {
+ UsingTree("""
+class C
+{
+ extension(Type) where T : struct, { }
+}
+""",
+ TestOptions.RegularPreview,
+ // (3,42): error CS1031: Type expected
+ // extension(Type) where T : struct, { }
+ Diagnostic(ErrorCode.ERR_TypeExpected, "{").WithLocation(3, 42));
+
+ N(SyntaxKind.CompilationUnit);
+ {
+ N(SyntaxKind.ClassDeclaration);
+ {
+ N(SyntaxKind.ClassKeyword);
+ N(SyntaxKind.IdentifierToken, "C");
+ N(SyntaxKind.OpenBraceToken);
+ N(SyntaxKind.ExtensionDeclaration);
+ {
+ N(SyntaxKind.ExtensionKeyword);
+ N(SyntaxKind.TypeParameterList);
+ {
+ N(SyntaxKind.LessThanToken);
+ N(SyntaxKind.TypeParameter);
+ {
+ N(SyntaxKind.IdentifierToken, "T");
+ }
+ N(SyntaxKind.GreaterThanToken);
+ }
+ N(SyntaxKind.ParameterList);
+ {
+ N(SyntaxKind.OpenParenToken);
+ N(SyntaxKind.Parameter);
+ {
+ N(SyntaxKind.IdentifierName);
+ {
+ N(SyntaxKind.IdentifierToken, "Type");
+ }
+ }
+ N(SyntaxKind.CloseParenToken);
+ }
+ N(SyntaxKind.TypeParameterConstraintClause);
+ {
+ N(SyntaxKind.WhereKeyword);
+ N(SyntaxKind.IdentifierName);
+ {
+ N(SyntaxKind.IdentifierToken, "T");
+ }
+ N(SyntaxKind.ColonToken);
+ N(SyntaxKind.StructConstraint);
+ {
+ N(SyntaxKind.StructKeyword);
+ }
+ N(SyntaxKind.CommaToken);
+ M(SyntaxKind.TypeConstraint);
+ {
+ M(SyntaxKind.IdentifierName);
+ {
+ M(SyntaxKind.IdentifierToken);
+ }
+ }
+ }
+ N(SyntaxKind.OpenBraceToken);
+ N(SyntaxKind.CloseBraceToken);
+ }
+ N(SyntaxKind.CloseBraceToken);
+ }
+ N(SyntaxKind.EndOfFileToken);
+ }
+ EOF();
+ }
+
+ [Fact]
+ public void WithTerminator_OpenBrace_06()
+ {
+ UsingTree("""
+class C
+{
+ extension' expected
+ // extension").WithLocation(3, 17),
+ // (3,17): error CS1003: Syntax error, '(' expected
+ // extension