diff --git a/eng/config/globalconfigs/Common.globalconfig b/eng/config/globalconfigs/Common.globalconfig
index b3339efbab8ce..1766acf873729 100644
--- a/eng/config/globalconfigs/Common.globalconfig
+++ b/eng/config/globalconfigs/Common.globalconfig
@@ -41,7 +41,7 @@ dotnet_diagnostic.RS0006.severity = error
dotnet_diagnostic.RS0012.severity = warning
dotnet_diagnostic.RS0014.severity = warning
dotnet_diagnostic.RS0015.severity = warning
-dotnet_diagnostic.RS0016.severity = error
+dotnet_diagnostic.RS0016.severity = none # PROTOTYPE(ft): re-enable before feature merge
dotnet_diagnostic.RS0017.severity = error
dotnet_diagnostic.RS0018.severity = warning
dotnet_diagnostic.RS0022.severity = error
diff --git a/src/Compilers/CSharp/Portable/CSharpResources.resx b/src/Compilers/CSharp/Portable/CSharpResources.resx
index d05760fe0229b..c779781950f88 100644
--- a/src/Compilers/CSharp/Portable/CSharpResources.resx
+++ b/src/Compilers/CSharp/Portable/CSharpResources.resx
@@ -7091,4 +7091,7 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ
unsigned right shift
+
+ file types
+
diff --git a/src/Compilers/CSharp/Portable/Declarations/DeclarationModifiers.cs b/src/Compilers/CSharp/Portable/Declarations/DeclarationModifiers.cs
index 7f4f224ad24b3..f42d991e744d6 100644
--- a/src/Compilers/CSharp/Portable/Declarations/DeclarationModifiers.cs
+++ b/src/Compilers/CSharp/Portable/Declarations/DeclarationModifiers.cs
@@ -36,8 +36,12 @@ internal enum DeclarationModifiers : uint
Async = 1 << 20,
Ref = 1 << 21, // used only for structs
- All = (1 << 23) - 1, // all modifiers
- Unset = 1 << 23, // used when a modifiers value hasn't yet been computed
+
+ // PROTOTYPE(ft): leaving 22 free since required is using it
+ File = 1 << 23, // used only for types
+
+ All = (1 << 24) - 1, // all modifiers
+ Unset = 1 << 24, // used when a modifiers value hasn't yet been computed
AccessibilityMask = PrivateProtected | Private | Protected | Internal | ProtectedInternal | Public,
}
diff --git a/src/Compilers/CSharp/Portable/Errors/MessageID.cs b/src/Compilers/CSharp/Portable/Errors/MessageID.cs
index e2266ed44bead..5070db6cb72d0 100644
--- a/src/Compilers/CSharp/Portable/Errors/MessageID.cs
+++ b/src/Compilers/CSharp/Portable/Errors/MessageID.cs
@@ -253,6 +253,8 @@ internal enum MessageID
IDS_FeatureUnsignedRightShift = MessageBase + 12823,
IDS_FeatureExtendedNameofScope = MessageBase + 12824,
+
+ IDS_FeatureFileTypes = MessageBase + 12850, // PROTOTYPE(ft): pack ID before merge
}
// Message IDs may refer to strings that need to be localized.
@@ -375,6 +377,7 @@ internal static LanguageVersion RequiredVersion(this MessageID feature)
case MessageID.IDS_FeatureUTF8StringLiterals: // semantic check
case MessageID.IDS_FeatureUnsignedRightShift: // semantic check for declarations and consumption, parsing check for doc comments
case MessageID.IDS_FeatureExtendedNameofScope: // semantic check
+ case MessageID.IDS_FeatureFileTypes: // semantic check
return LanguageVersion.Preview;
// C# 10.0 features.
diff --git a/src/Compilers/CSharp/Portable/Generated/CSharp.Generated.g4 b/src/Compilers/CSharp/Portable/Generated/CSharp.Generated.g4
index 2adb71f2ceb9d..da6c46a3367d2 100644
--- a/src/Compilers/CSharp/Portable/Generated/CSharp.Generated.g4
+++ b/src/Compilers/CSharp/Portable/Generated/CSharp.Generated.g4
@@ -99,6 +99,7 @@ modifier
| 'async'
| 'const'
| 'extern'
+ | 'file'
| 'fixed'
| 'internal'
| 'new'
diff --git a/src/Compilers/CSharp/Portable/Parser/LanguageParser.cs b/src/Compilers/CSharp/Portable/Parser/LanguageParser.cs
index 7504624b559aa..5450bd9459492 100644
--- a/src/Compilers/CSharp/Portable/Parser/LanguageParser.cs
+++ b/src/Compilers/CSharp/Portable/Parser/LanguageParser.cs
@@ -1163,6 +1163,8 @@ internal static DeclarationModifiers GetModifier(SyntaxKind kind, SyntaxKind con
return DeclarationModifiers.Partial;
case SyntaxKind.AsyncKeyword:
return DeclarationModifiers.Async;
+ case SyntaxKind.FileKeyword:
+ return DeclarationModifiers.File;
}
goto default;
@@ -1243,8 +1245,18 @@ private void ParseModifiers(SyntaxListBuilder tokens, bool forAccessors)
break;
}
+ case DeclarationModifiers.File:
+ if (!IsFeatureEnabled(MessageID.IDS_FeatureFileTypes) && !ShouldContextualKeywordBeTreatedAsModifier(parsingStatementNotDeclaration: false))
+ {
+ return;
+ }
+
+ // LangVersion errors for 'file' modifier are given during binding.
+ modTok = ConvertToKeyword(EatToken());
+ break;
+
case DeclarationModifiers.Async:
- if (!ShouldAsyncBeTreatedAsModifier(parsingStatementNotDeclaration: false))
+ if (!ShouldContextualKeywordBeTreatedAsModifier(parsingStatementNotDeclaration: false))
{
return;
}
@@ -1281,16 +1293,16 @@ bool isStructOrRecordKeyword(SyntaxToken token)
}
}
- private bool ShouldAsyncBeTreatedAsModifier(bool parsingStatementNotDeclaration)
+ private bool ShouldContextualKeywordBeTreatedAsModifier(bool parsingStatementNotDeclaration)
{
- Debug.Assert(this.CurrentToken.ContextualKind == SyntaxKind.AsyncKeyword);
+ Debug.Assert(this.CurrentToken.Kind == SyntaxKind.IdentifierToken && GetModifier(this.CurrentToken) != DeclarationModifiers.None);
// Adapted from CParser::IsAsyncMethod.
if (IsNonContextualModifier(PeekToken(1)))
{
// If the next token is a (non-contextual) modifier keyword, then this token is
- // definitely the async keyword
+ // definitely a modifier
return true;
}
@@ -1301,7 +1313,7 @@ private bool ShouldAsyncBeTreatedAsModifier(bool parsingStatementNotDeclaration)
try
{
- this.EatToken(); //move past contextual 'async'
+ this.EatToken(); //move past contextual token
if (!parsingStatementNotDeclaration &&
(this.CurrentToken.ContextualKind == SyntaxKind.PartialKeyword))
@@ -1309,13 +1321,12 @@ private bool ShouldAsyncBeTreatedAsModifier(bool parsingStatementNotDeclaration)
this.EatToken(); // "partial" doesn't affect our decision, so look past it.
}
- // Comment directly from CParser::IsAsyncMethod.
- // ... 'async' [partial] ...
- // ... 'async' [partial] ...
- // ... 'async' [partial] ...
- // ... 'async' [partial] ...
- // ... 'async' [partial] ...
- // ... 'async' [partial] ...
+ // ... 'TOKEN' [partial] ...
+ // ... 'TOKEN' [partial] ...
+ // ... 'TOKEN' [partial] ...
+ // ... 'TOKEN' [partial] ...
+ // ... 'TOKEN' [partial] ...
+ // ... 'TOKEN' [partial] ...
// DEVNOTE: Although we parse async user defined conversions, operators, etc. here,
// anything other than async methods are detected as erroneous later, during the define phase
@@ -1332,56 +1343,56 @@ private bool ShouldAsyncBeTreatedAsModifier(bool parsingStatementNotDeclaration)
if (ScanType() != ScanTypeFlags.NotType)
{
- // We've seen "async TypeName". Now we have to determine if we should we treat
- // 'async' as a modifier. Or is the user actually writing something like
- // "public async Goo" where 'async' is actually the return type.
+ // We've seen "TOKEN TypeName". Now we have to determine if we should we treat
+ // 'TOKEN' as a modifier. Or is the user actually writing something like
+ // "public TOKEN Goo" where 'TOKEN' is actually the return type.
if (IsPossibleMemberName())
{
- // we have: "async Type X" or "async Type this", 'async' is definitely a
+ // we have: "TOKEN Type X" or "TOKEN Type this", 'TOKEN' is definitely a
// modifier here.
return true;
}
var currentTokenKind = this.CurrentToken.Kind;
- // The file ends with "async TypeName", it's not legal code, and it's much
+ // The file ends with "TOKEN TypeName", it's not legal code, and it's much
// more likely that this is meant to be a modifier.
if (currentTokenKind == SyntaxKind.EndOfFileToken)
{
return true;
}
- // "async TypeName }". In this case, we just have an incomplete member, and
- // we should definitely default to 'async' being considered a return type here.
+ // "TOKEN TypeName }". In this case, we just have an incomplete member, and
+ // we should definitely default to 'TOKEN' being considered a return type here.
if (currentTokenKind == SyntaxKind.CloseBraceToken)
{
return true;
}
- // "async TypeName void". In this case, we just have an incomplete member before
- // an existing member. Treat this 'async' as a keyword.
+ // "TOKEN TypeName void". In this case, we just have an incomplete member before
+ // an existing member. Treat this 'TOKEN' as a keyword.
if (SyntaxFacts.IsPredefinedType(this.CurrentToken.Kind))
{
return true;
}
- // "async TypeName public". In this case, we just have an incomplete member before
- // an existing member. Treat this 'async' as a keyword.
+ // "TOKEN TypeName public". In this case, we just have an incomplete member before
+ // an existing member. Treat this 'TOKEN' as a keyword.
if (IsNonContextualModifier(this.CurrentToken))
{
return true;
}
- // "async TypeName class". In this case, we just have an incomplete member before
- // an existing type declaration. Treat this 'async' as a keyword.
+ // "TOKEN TypeName class". In this case, we just have an incomplete member before
+ // an existing type declaration. Treat this 'TOKEN' as a keyword.
if (IsTypeDeclarationStart())
{
return true;
}
- // "async TypeName namespace". In this case, we just have an incomplete member before
- // an existing namespace declaration. Treat this 'async' as a keyword.
+ // "TOKEN TypeName namespace". In this case, we just have an incomplete member before
+ // an existing namespace declaration. Treat this 'TOKEN' as a keyword.
if (currentTokenKind == SyntaxKind.NamespaceKeyword)
{
return true;
@@ -2661,8 +2672,7 @@ static bool isAcceptableNonDeclarationStatement(StatementSyntax statement, bool
private bool IsMisplacedModifier(SyntaxListBuilder modifiers, SyntaxList attributes, TypeSyntax type, out MemberDeclarationSyntax result)
{
if (GetModifier(this.CurrentToken) != DeclarationModifiers.None &&
- this.CurrentToken.ContextualKind != SyntaxKind.PartialKeyword &&
- this.CurrentToken.ContextualKind != SyntaxKind.AsyncKeyword &&
+ this.CurrentToken.ContextualKind is not (SyntaxKind.PartialKeyword or SyntaxKind.AsyncKeyword or SyntaxKind.FileKeyword) &&
IsComplete(type))
{
var misplacedModifier = this.CurrentToken;
@@ -7969,7 +7979,7 @@ private bool IsPossibleLocalDeclarationStatement(bool isGlobalScriptLevel)
tk = this.CurrentToken.ContextualKind;
var isPossibleAttributeOrModifier = (IsAdditionalLocalFunctionModifier(tk) || tk == SyntaxKind.OpenBracketToken)
- && (tk != SyntaxKind.AsyncKeyword || ShouldAsyncBeTreatedAsModifier(parsingStatementNotDeclaration: true));
+ && (tk != SyntaxKind.AsyncKeyword || ShouldContextualKeywordBeTreatedAsModifier(parsingStatementNotDeclaration: true));
if (isPossibleAttributeOrModifier)
{
return true;
diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/ModifierUtils.cs b/src/Compilers/CSharp/Portable/Symbols/Source/ModifierUtils.cs
index f28cdf1356928..433b7550cb820 100644
--- a/src/Compilers/CSharp/Portable/Symbols/Source/ModifierUtils.cs
+++ b/src/Compilers/CSharp/Portable/Symbols/Source/ModifierUtils.cs
@@ -86,6 +86,11 @@ internal static DeclarationModifiers CheckModifiers(
modifierErrors |= !Binder.CheckFeatureAvailability(errorLocation.SourceTree, MessageID.IDS_FeaturePrivateProtected, diagnostics, errorLocation);
}
+ if ((result & DeclarationModifiers.File) != 0)
+ {
+ modifierErrors |= !Binder.CheckFeatureAvailability(errorLocation.SourceTree, MessageID.IDS_FeatureFileTypes, diagnostics, errorLocation);
+ }
+
return result;
}
@@ -281,6 +286,8 @@ internal static string ConvertSingleModifierToSyntaxText(DeclarationModifiers mo
return SyntaxFacts.GetText(SyntaxKind.AsyncKeyword);
case DeclarationModifiers.Ref:
return SyntaxFacts.GetText(SyntaxKind.RefKeyword);
+ case DeclarationModifiers.File:
+ return SyntaxFacts.GetText(SyntaxKind.FileKeyword);
default:
throw ExceptionUtilities.UnexpectedValue(modifier);
}
@@ -328,6 +335,8 @@ private static DeclarationModifiers ToDeclarationModifier(SyntaxKind kind)
return DeclarationModifiers.Volatile;
case SyntaxKind.RefKeyword:
return DeclarationModifiers.Ref;
+ case SyntaxKind.FileKeyword:
+ return DeclarationModifiers.File;
default:
throw ExceptionUtilities.UnexpectedValue(kind);
}
diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberContainerSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberContainerSymbol.cs
index cd25021d1d4d5..062255f17974c 100644
--- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberContainerSymbol.cs
+++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberContainerSymbol.cs
@@ -249,7 +249,8 @@ private DeclarationModifiers MakeModifiers(TypeKind typeKind, BindingDiagnosticB
{
Symbol containingSymbol = this.ContainingSymbol;
DeclarationModifiers defaultAccess;
- var allowedModifiers = DeclarationModifiers.AccessibilityMask;
+ // PROTOTYPE(ft): confirm whether 'file' types can be nested
+ var allowedModifiers = DeclarationModifiers.AccessibilityMask | DeclarationModifiers.File;
if (containingSymbol.Kind == SymbolKind.Namespace)
{
diff --git a/src/Compilers/CSharp/Portable/Syntax/SyntaxKind.cs b/src/Compilers/CSharp/Portable/Syntax/SyntaxKind.cs
index 112f15b9b8343..4da3999520625 100644
--- a/src/Compilers/CSharp/Portable/Syntax/SyntaxKind.cs
+++ b/src/Compilers/CSharp/Portable/Syntax/SyntaxKind.cs
@@ -405,6 +405,9 @@ public enum SyntaxKind : ushort
/// Represents .
UnmanagedKeyword = 8446,
+ /// Represents .
+ FileKeyword = 8447,
+
// when adding a contextual keyword following functions must be adapted:
//
//
diff --git a/src/Compilers/CSharp/Portable/Syntax/SyntaxKindFacts.cs b/src/Compilers/CSharp/Portable/Syntax/SyntaxKindFacts.cs
index 1ffefc6557ffb..6577fed1a2090 100644
--- a/src/Compilers/CSharp/Portable/Syntax/SyntaxKindFacts.cs
+++ b/src/Compilers/CSharp/Portable/Syntax/SyntaxKindFacts.cs
@@ -1138,7 +1138,7 @@ public static SyntaxKind GetPreprocessorKeywordKind(string text)
public static IEnumerable GetContextualKeywordKinds()
{
- for (int i = (int)SyntaxKind.YieldKeyword; i <= (int)SyntaxKind.UnmanagedKeyword; i++)
+ for (int i = (int)SyntaxKind.YieldKeyword; i <= (int)SyntaxKind.FileKeyword; i++) // PROTOTYPE(ft): will conflict with required
{
yield return (SyntaxKind)i;
}
@@ -1191,6 +1191,7 @@ public static bool IsContextualKeyword(SyntaxKind kind)
case SyntaxKind.RecordKeyword:
case SyntaxKind.ManagedKeyword:
case SyntaxKind.UnmanagedKeyword:
+ case SyntaxKind.FileKeyword:
return true;
default:
return false;
@@ -1310,6 +1311,8 @@ public static SyntaxKind GetContextualKeywordKind(string text)
return SyntaxKind.ManagedKeyword;
case "unmanaged":
return SyntaxKind.UnmanagedKeyword;
+ case "file":
+ return SyntaxKind.FileKeyword;
default:
return SyntaxKind.None;
}
@@ -1751,6 +1754,8 @@ public static string GetText(SyntaxKind kind)
return "managed";
case SyntaxKind.UnmanagedKeyword:
return "unmanaged";
+ case SyntaxKind.FileKeyword:
+ return "file";
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 55dda0b93eacd..b92a529983355 100644
--- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf
+++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf
@@ -1477,6 +1477,11 @@
obor názvů pro celý soubor
+
+ file types
+ file types
+
+
generic attributes
obecné atributy
diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf
index 21a69156cbe6c..d810eb2b31e83 100644
--- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf
+++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf
@@ -1477,6 +1477,11 @@
Dateibereichsnamespace
+
+ file types
+ file types
+
+
generic attributes
Generische Attribute
diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf
index b47e9241de939..f0cbc782552ab 100644
--- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf
+++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf
@@ -1477,6 +1477,11 @@
espacio de nombres con ámbito de archivo
+
+ file types
+ file types
+
+
generic attributes
atributos genéricos
diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf
index 74ab389c8ae18..386b55de2416a 100644
--- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf
+++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf
@@ -1477,6 +1477,11 @@
espace de noms inclus dans l'étendue de fichier
+
+ file types
+ file types
+
+
generic attributes
attributs génériques
diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf
index c92c607c46ea6..30d4680434080 100644
--- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf
+++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf
@@ -1477,6 +1477,11 @@
spazio dei nomi con ambito file
+
+ file types
+ file types
+
+
generic attributes
attributi generici
diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf
index 70a9b6ea60df3..e5caa8f74442b 100644
--- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf
+++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf
@@ -1477,6 +1477,11 @@
ファイルスコープの名前空間
+
+ file types
+ file types
+
+
generic attributes
汎用属性
diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf
index 67692f912a123..3cae36e463245 100644
--- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf
+++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf
@@ -1477,6 +1477,11 @@
파일 범위 네임스페이스
+
+ file types
+ file types
+
+
generic attributes
제네릭 특성
diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf
index 76ce08171770f..2146a592c67a3 100644
--- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf
+++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf
@@ -1477,6 +1477,11 @@
przestrzeń nazw z określonym zakresem plików
+
+ file types
+ file types
+
+
generic attributes
atrybuty ogólne
diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf
index 9408d573e96f6..7f9ed175d0c85 100644
--- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf
+++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf
@@ -1477,6 +1477,11 @@
namespace de escopo de arquivo
+
+ file types
+ file types
+
+
generic attributes
atributos genéricos
diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf
index 3cafc50cb8524..0c6369f0f8bcc 100644
--- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf
+++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf
@@ -1477,6 +1477,11 @@
пространство имен с файловой областью
+
+ file types
+ file types
+
+
generic attributes
универсальные атрибуты
diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf
index f9690e228a1e1..b5dbed29ec3ee 100644
--- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf
+++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf
@@ -1477,6 +1477,11 @@
dosya kapsamlı ad alanı
+
+ file types
+ file types
+
+
generic attributes
genel öznitelikler
diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf
index cb476cfa1b2b7..d34e183163cea 100644
--- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf
+++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf
@@ -1477,6 +1477,11 @@
文件范围内的命名空间
+
+ file types
+ file types
+
+
generic attributes
通用属性
diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf
index 7544797983a45..c7eabe25da772 100644
--- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf
+++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf
@@ -1477,6 +1477,11 @@
以檔案為範圍的命名空間
+
+ file types
+ file types
+
+
generic attributes
一般屬性
diff --git a/src/Compilers/CSharp/Test/Symbol/Symbols/Source/FileModifierTests.cs b/src/Compilers/CSharp/Test/Symbol/Symbols/Source/FileModifierTests.cs
new file mode 100644
index 0000000000000..aeceafa616a16
--- /dev/null
+++ b/src/Compilers/CSharp/Test/Symbol/Symbols/Source/FileModifierTests.cs
@@ -0,0 +1,49 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using Microsoft.CodeAnalysis.CSharp.Test.Utilities;
+using Xunit;
+
+namespace Microsoft.CodeAnalysis.CSharp.UnitTests
+{
+ public class FileModifierTests : CSharpTestBase
+ {
+ [Fact]
+ public void LangVersion()
+ {
+ var source = """
+ file class C { }
+ """;
+
+ var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10);
+ comp.VerifyDiagnostics(
+ // (1,12): error CS8652: The feature 'file types' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.
+ // file class C { }
+ Diagnostic(ErrorCode.ERR_FeatureInPreview, "C").WithArguments("file types").WithLocation(1, 12));
+
+ comp = CreateCompilation(source);
+ comp.VerifyDiagnostics();
+ }
+
+ [Fact]
+ public void Nested()
+ {
+ var source = """
+ class Outer
+ {
+ file class C { }
+ }
+ """;
+
+ var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10);
+ comp.VerifyDiagnostics(
+ // (3,16): error CS8652: The feature 'file types' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.
+ // file class C { }
+ Diagnostic(ErrorCode.ERR_FeatureInPreview, "C").WithArguments("file types").WithLocation(3, 16));
+
+ comp = CreateCompilation(source);
+ comp.VerifyDiagnostics();
+ }
+ }
+}
diff --git a/src/Compilers/CSharp/Test/Syntax/Parsing/FileModifierParsingTests.cs b/src/Compilers/CSharp/Test/Syntax/Parsing/FileModifierParsingTests.cs
new file mode 100644
index 0000000000000..14c5f663d3e76
--- /dev/null
+++ b/src/Compilers/CSharp/Test/Syntax/Parsing/FileModifierParsingTests.cs
@@ -0,0 +1,2680 @@
+// 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 System;
+using System.Linq;
+using Microsoft.CodeAnalysis.CSharp.Test.Utilities;
+using Microsoft.CodeAnalysis.Test.Utilities;
+using Xunit;
+using Xunit.Abstractions;
+
+namespace Microsoft.CodeAnalysis.CSharp.UnitTests
+{
+ public class FileModifierParsingTests : ParsingTests
+ {
+ public FileModifierParsingTests(ITestOutputHelper output) : base(output) { }
+
+ protected override SyntaxTree ParseTree(string text, CSharpParseOptions? options)
+ {
+ return SyntaxFactory.ParseSyntaxTree(text, options ?? TestOptions.Regular);
+ }
+
+ private void UsingNode(string text, params DiagnosticDescription[] expectedDiagnostics)
+ {
+ UsingNode(text, options: null, expectedParsingDiagnostics: expectedDiagnostics);
+ }
+
+ private new void UsingNode(string text, CSharpParseOptions? options, params DiagnosticDescription[] expectedDiagnostics)
+ {
+ UsingNode(text, options, expectedParsingDiagnostics: expectedDiagnostics);
+ }
+
+ private void UsingNode(string text, CSharpParseOptions? options = null, DiagnosticDescription[]? expectedParsingDiagnostics = null, DiagnosticDescription[]? expectedBindingDiagnostics = null)
+ {
+ options ??= TestOptions.RegularPreview;
+ expectedParsingDiagnostics ??= Array.Empty();
+ expectedBindingDiagnostics ??= expectedParsingDiagnostics;
+
+ var tree = UsingTree(text, options);
+ Validate(text, (CSharpSyntaxNode)tree.GetRoot(), expectedParsingDiagnostics);
+
+ var comp = CreateCompilation(tree);
+ comp.VerifyDiagnostics(expectedBindingDiagnostics);
+ }
+
+ [Theory]
+ [InlineData(SyntaxKind.ClassKeyword)]
+ [InlineData(SyntaxKind.StructKeyword)]
+ [InlineData(SyntaxKind.InterfaceKeyword)]
+ [InlineData(SyntaxKind.RecordKeyword)]
+ [InlineData(SyntaxKind.EnumKeyword)]
+ public void FileModifier_01(SyntaxKind typeKeyword)
+ {
+ UsingNode($$"""
+ file {{SyntaxFacts.GetText(typeKeyword)}} C { }
+ """);
+ N(SyntaxKind.CompilationUnit);
+ {
+ N(SyntaxFacts.GetBaseTypeDeclarationKind(typeKeyword));
+ {
+ N(SyntaxKind.FileKeyword);
+ N(typeKeyword);
+ N(SyntaxKind.IdentifierToken, "C");
+ N(SyntaxKind.OpenBraceToken);
+ N(SyntaxKind.CloseBraceToken);
+ }
+ N(SyntaxKind.EndOfFileToken);
+ }
+ EOF();
+ }
+
+ [Theory]
+ [InlineData(SyntaxKind.ClassKeyword)]
+ [InlineData(SyntaxKind.StructKeyword)]
+ [InlineData(SyntaxKind.InterfaceKeyword)]
+ [InlineData(SyntaxKind.RecordKeyword)]
+ public void FileModifier_02(SyntaxKind typeKeyword)
+ {
+ UsingNode($$"""
+ file partial {{SyntaxFacts.GetText(typeKeyword)}} C { }
+ """);
+ N(SyntaxKind.CompilationUnit);
+ {
+ N(SyntaxFacts.GetBaseTypeDeclarationKind(typeKeyword));
+ {
+ N(SyntaxKind.FileKeyword);
+ N(SyntaxKind.PartialKeyword);
+ N(typeKeyword);
+ N(SyntaxKind.IdentifierToken, "C");
+ N(SyntaxKind.OpenBraceToken);
+ N(SyntaxKind.CloseBraceToken);
+ }
+ N(SyntaxKind.EndOfFileToken);
+ }
+ EOF();
+ }
+
+ [Fact]
+ public void FileModifier_02_Enum()
+ {
+ UsingNode($$"""
+ file partial enum C { }
+ """,
+ expectedParsingDiagnostics: new[]
+ {
+ // (1,6): error CS0267: The 'partial' modifier can only appear immediately before 'class', 'record', 'struct', 'interface', or a method return type.
+ // file partial enum C { }
+ Diagnostic(ErrorCode.ERR_PartialMisplaced, "partial").WithLocation(1, 6)
+ },
+ // note: we also get duplicate ERR_PartialMisplaced diagnostics on `partial enum C { }`.
+ expectedBindingDiagnostics: new[]
+ {
+ // (1,6): error CS0267: The 'partial' modifier can only appear immediately before 'class', 'record', 'struct', 'interface', or a method return type.
+ // file partial enum C { }
+ Diagnostic(ErrorCode.ERR_PartialMisplaced, "partial").WithLocation(1, 6),
+ // (1,19): error CS0267: The 'partial' modifier can only appear immediately before 'class', 'record', 'struct', 'interface', or a method return type.
+ // file partial enum C { }
+ Diagnostic(ErrorCode.ERR_PartialMisplaced, "C").WithLocation(1, 19)
+ });
+ N(SyntaxKind.CompilationUnit);
+ {
+ N(SyntaxKind.EnumDeclaration);
+ {
+ N(SyntaxKind.FileKeyword);
+ N(SyntaxKind.PartialKeyword);
+ N(SyntaxKind.EnumKeyword);
+ N(SyntaxKind.IdentifierToken, "C");
+ N(SyntaxKind.OpenBraceToken);
+ N(SyntaxKind.CloseBraceToken);
+ }
+ N(SyntaxKind.EndOfFileToken);
+ }
+ EOF();
+ }
+
+ [Theory]
+ [InlineData(SyntaxKind.ClassKeyword)]
+ [InlineData(SyntaxKind.StructKeyword)]
+ [InlineData(SyntaxKind.InterfaceKeyword)]
+ public void FileModifier_03(SyntaxKind typeKeyword)
+ {
+ UsingNode($$"""
+ partial file {{SyntaxFacts.GetText(typeKeyword)}} C { }
+ """,
+ expectedParsingDiagnostics: new[]
+ {
+ // (1,14): error CS1002: ; expected
+ // partial file {{SyntaxFacts.GetText(typeKeyword)}} C { }
+ Diagnostic(ErrorCode.ERR_SemicolonExpected, SyntaxFacts.GetText(typeKeyword)).WithLocation(1, 14)
+ },
+ expectedBindingDiagnostics: new[]
+ {
+ // (1,1): error CS0246: The type or namespace name 'partial' could not be found (are you missing a using directive or an assembly reference?)
+ // partial file interface C { }
+ Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "partial").WithArguments("partial").WithLocation(1, 1),
+ // (1,9): warning CS0168: The variable 'file' is declared but never used
+ // partial file interface C { }
+ Diagnostic(ErrorCode.WRN_UnreferencedVar, "file").WithArguments("file").WithLocation(1, 9),
+ // (1,14): error CS1002: ; expected
+ // partial file {{SyntaxFacts.GetText(typeKeyword)}} C { }
+ Diagnostic(ErrorCode.ERR_SemicolonExpected, SyntaxFacts.GetText(typeKeyword)).WithLocation(1, 14)
+ });
+ N(SyntaxKind.CompilationUnit);
+ {
+ N(SyntaxKind.GlobalStatement);
+ {
+ N(SyntaxKind.LocalDeclarationStatement);
+ {
+ N(SyntaxKind.VariableDeclaration);
+ {
+ N(SyntaxKind.IdentifierName);
+ {
+ N(SyntaxKind.IdentifierToken, "partial");
+ }
+ N(SyntaxKind.VariableDeclarator);
+ {
+ N(SyntaxKind.IdentifierToken, "file");
+ }
+ }
+ M(SyntaxKind.SemicolonToken);
+ }
+ }
+ N(SyntaxFacts.GetBaseTypeDeclarationKind(typeKeyword));
+ {
+ N(typeKeyword);
+ N(SyntaxKind.IdentifierToken, "C");
+ N(SyntaxKind.OpenBraceToken);
+ N(SyntaxKind.CloseBraceToken);
+ }
+ N(SyntaxKind.EndOfFileToken);
+ }
+ EOF();
+ }
+
+ // PROTOTYPE(ft): is it fine that records parse as a single declaration here, but not other type kinds?
+ [Theory]
+ [InlineData(SyntaxKind.RecordKeyword)]
+ public void FileModifier_04(SyntaxKind typeKeyword)
+ {
+ UsingNode($$"""
+ partial file {{SyntaxFacts.GetText(typeKeyword)}} C { }
+ """);
+ N(SyntaxKind.CompilationUnit);
+ {
+ N(SyntaxFacts.GetBaseTypeDeclarationKind(typeKeyword));
+ {
+ N(SyntaxKind.PartialKeyword);
+ N(SyntaxKind.FileKeyword);
+ N(typeKeyword);
+ N(SyntaxKind.IdentifierToken, "C");
+ N(SyntaxKind.OpenBraceToken);
+ N(SyntaxKind.CloseBraceToken);
+ }
+ N(SyntaxKind.EndOfFileToken);
+ }
+ EOF();
+ }
+
+ [Fact]
+ public void FileModifier_05()
+ {
+ UsingNode($$"""
+ file partial record struct C { }
+ """);
+ N(SyntaxKind.CompilationUnit);
+ {
+ N(SyntaxKind.RecordStructDeclaration);
+ {
+ N(SyntaxKind.FileKeyword);
+ N(SyntaxKind.PartialKeyword);
+ N(SyntaxKind.RecordKeyword);
+ N(SyntaxKind.StructKeyword);
+ N(SyntaxKind.IdentifierToken, "C");
+ N(SyntaxKind.OpenBraceToken);
+ N(SyntaxKind.CloseBraceToken);
+ }
+ N(SyntaxKind.EndOfFileToken);
+ }
+ EOF();
+ }
+
+ // PROTOTYPE(ft): is it fine that records parse here, but not other type kinds?
+ [Fact]
+ public void FileModifier_06()
+ {
+ UsingNode($$"""
+ partial file record struct C { }
+ """);
+ N(SyntaxKind.CompilationUnit);
+ {
+ N(SyntaxKind.RecordStructDeclaration);
+ {
+ N(SyntaxKind.PartialKeyword);
+ N(SyntaxKind.FileKeyword);
+ N(SyntaxKind.RecordKeyword);
+ N(SyntaxKind.StructKeyword);
+ N(SyntaxKind.IdentifierToken, "C");
+ N(SyntaxKind.OpenBraceToken);
+ N(SyntaxKind.CloseBraceToken);
+ }
+ N(SyntaxKind.EndOfFileToken);
+ }
+ EOF();
+ }
+
+ [Fact]
+ public void FileModifier_07_CSharp10()
+ {
+ UsingNode($$"""
+ file partial ref struct C { }
+ """,
+ options: TestOptions.Regular10,
+ expectedParsingDiagnostics: new[]
+ {
+ // (1,14): error CS1003: Syntax error, ',' expected
+ // file partial ref struct C { }
+ Diagnostic(ErrorCode.ERR_SyntaxError, "ref").WithArguments(",", "ref").WithLocation(1, 14),
+ // (1,18): error CS1002: ; expected
+ // file partial ref struct C { }
+ Diagnostic(ErrorCode.ERR_SemicolonExpected, "struct").WithLocation(1, 18)
+ },
+ expectedBindingDiagnostics: new[]
+ {
+ // (1,1): error CS0246: The type or namespace name 'file' could not be found (are you missing a using directive or an assembly reference?)
+ // file partial ref struct C { }
+ Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "file").WithArguments("file").WithLocation(1, 1),
+ // (1,6): warning CS0168: The variable 'partial' is declared but never used
+ // file partial ref struct C { }
+ Diagnostic(ErrorCode.WRN_UnreferencedVar, "partial").WithArguments("partial").WithLocation(1, 6),
+ // (1,14): error CS1003: Syntax error, ',' expected
+ // file partial ref struct C { }
+ Diagnostic(ErrorCode.ERR_SyntaxError, "ref").WithArguments(",", "ref").WithLocation(1, 14),
+ // (1,18): error CS1002: ; expected
+ // file partial ref struct C { }
+ Diagnostic(ErrorCode.ERR_SemicolonExpected, "struct").WithLocation(1, 18)
+ });
+ N(SyntaxKind.CompilationUnit);
+ {
+ N(SyntaxKind.GlobalStatement);
+ {
+ N(SyntaxKind.LocalDeclarationStatement);
+ {
+ N(SyntaxKind.VariableDeclaration);
+ {
+ N(SyntaxKind.IdentifierName);
+ {
+ N(SyntaxKind.IdentifierToken, "file");
+ }
+ N(SyntaxKind.VariableDeclarator);
+ {
+ N(SyntaxKind.IdentifierToken, "partial");
+ }
+ }
+ M(SyntaxKind.SemicolonToken);
+ }
+ }
+ N(SyntaxKind.StructDeclaration);
+ {
+ N(SyntaxKind.StructKeyword);
+ N(SyntaxKind.IdentifierToken, "C");
+ N(SyntaxKind.OpenBraceToken);
+ N(SyntaxKind.CloseBraceToken);
+ }
+ N(SyntaxKind.EndOfFileToken);
+ }
+ EOF();
+ }
+
+ [Fact]
+ public void FileModifier_07()
+ {
+ UsingNode($$"""
+ file partial ref struct C { }
+ """,
+ // (1,14): error CS1585: Member modifier 'ref' must precede the member type and name
+ // file partial ref struct C { }
+ Diagnostic(ErrorCode.ERR_BadModifierLocation, "ref").WithArguments("ref").WithLocation(1, 14));
+ N(SyntaxKind.CompilationUnit);
+ {
+ N(SyntaxKind.IncompleteMember);
+ {
+ N(SyntaxKind.FileKeyword);
+ N(SyntaxKind.IdentifierName);
+ {
+ N(SyntaxKind.IdentifierToken, "partial");
+ }
+ }
+ N(SyntaxKind.StructDeclaration);
+ {
+ N(SyntaxKind.RefKeyword);
+ N(SyntaxKind.StructKeyword);
+ N(SyntaxKind.IdentifierToken, "C");
+ N(SyntaxKind.OpenBraceToken);
+ N(SyntaxKind.CloseBraceToken);
+ }
+ N(SyntaxKind.EndOfFileToken);
+ }
+ EOF();
+ }
+
+ [Fact]
+ public void FileModifier_08()
+ {
+ UsingNode($$"""
+ partial file ref struct C { }
+ """,
+ expectedParsingDiagnostics: new[]
+ {
+ // (1,14): error CS1003: Syntax error, ',' expected
+ // partial file ref struct C { }
+ Diagnostic(ErrorCode.ERR_SyntaxError, "ref").WithArguments(",", "ref").WithLocation(1, 14),
+ // (1,18): error CS1002: ; expected
+ // partial file ref struct C { }
+ Diagnostic(ErrorCode.ERR_SemicolonExpected, "struct").WithLocation(1, 18)
+ },
+ expectedBindingDiagnostics: new[]
+ {
+ // (1,1): error CS0246: The type or namespace name 'partial' could not be found (are you missing a using directive or an assembly reference?)
+ // partial file ref struct C { }
+ Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "partial").WithArguments("partial").WithLocation(1, 1),
+ // (1,9): warning CS0168: The variable 'file' is declared but never used
+ // partial file ref struct C { }
+ Diagnostic(ErrorCode.WRN_UnreferencedVar, "file").WithArguments("file").WithLocation(1, 9),
+ // (1,14): error CS1003: Syntax error, ',' expected
+ // partial file ref struct C { }
+ Diagnostic(ErrorCode.ERR_SyntaxError, "ref").WithArguments(",", "ref").WithLocation(1, 14),
+ // (1,18): error CS1002: ; expected
+ // partial file ref struct C { }
+ Diagnostic(ErrorCode.ERR_SemicolonExpected, "struct").WithLocation(1, 18)
+ });
+
+ N(SyntaxKind.CompilationUnit);
+ {
+ N(SyntaxKind.GlobalStatement);
+ {
+ N(SyntaxKind.LocalDeclarationStatement);
+ {
+ N(SyntaxKind.VariableDeclaration);
+ {
+ N(SyntaxKind.IdentifierName);
+ {
+ N(SyntaxKind.IdentifierToken, "partial");
+ }
+ N(SyntaxKind.VariableDeclarator);
+ {
+ N(SyntaxKind.IdentifierToken, "file");
+ }
+ }
+ M(SyntaxKind.SemicolonToken);
+ }
+ }
+ N(SyntaxKind.StructDeclaration);
+ {
+ N(SyntaxKind.StructKeyword);
+ N(SyntaxKind.IdentifierToken, "C");
+ N(SyntaxKind.OpenBraceToken);
+ N(SyntaxKind.CloseBraceToken);
+ }
+ N(SyntaxKind.EndOfFileToken);
+ }
+ EOF();
+ }
+
+ [Fact]
+ public void FileModifier_09()
+ {
+ UsingNode($$"""
+ file abstract class C { }
+ """);
+ N(SyntaxKind.CompilationUnit);
+ {
+ N(SyntaxKind.ClassDeclaration);
+ {
+ N(SyntaxKind.FileKeyword);
+ N(SyntaxKind.AbstractKeyword);
+ N(SyntaxKind.ClassKeyword);
+ N(SyntaxKind.IdentifierToken, "C");
+ N(SyntaxKind.OpenBraceToken);
+ N(SyntaxKind.CloseBraceToken);
+ }
+ N(SyntaxKind.EndOfFileToken);
+ }
+ EOF();
+ }
+
+ [Fact]
+ public void FileModifier_10()
+ {
+ UsingNode($$"""
+ abstract file class C { }
+ """);
+ N(SyntaxKind.CompilationUnit);
+ {
+ N(SyntaxKind.ClassDeclaration);
+ {
+ N(SyntaxKind.AbstractKeyword);
+ N(SyntaxKind.FileKeyword);
+ N(SyntaxKind.ClassKeyword);
+ N(SyntaxKind.IdentifierToken, "C");
+ N(SyntaxKind.OpenBraceToken);
+ N(SyntaxKind.CloseBraceToken);
+ }
+ N(SyntaxKind.EndOfFileToken);
+ }
+ EOF();
+ }
+
+ [Theory]
+ [InlineData(SyntaxKind.ClassKeyword)]
+ [InlineData(SyntaxKind.StructKeyword)]
+ [InlineData(SyntaxKind.InterfaceKeyword)]
+ [InlineData(SyntaxKind.RecordKeyword)]
+ [InlineData(SyntaxKind.EnumKeyword)]
+ public void FileModifier_11(SyntaxKind typeKeyword)
+ {
+ UsingNode($$"""
+ public file {{SyntaxFacts.GetText(typeKeyword)}} C { }
+ """);
+ N(SyntaxKind.CompilationUnit);
+ {
+ N(SyntaxFacts.GetBaseTypeDeclarationKind(typeKeyword));
+ {
+ N(SyntaxKind.PublicKeyword);
+ N(SyntaxKind.FileKeyword);
+ N(typeKeyword);
+ N(SyntaxKind.IdentifierToken, "C");
+ N(SyntaxKind.OpenBraceToken);
+ N(SyntaxKind.CloseBraceToken);
+ }
+ N(SyntaxKind.EndOfFileToken);
+ }
+ EOF();
+ }
+
+ [Theory]
+ [InlineData(SyntaxKind.ClassKeyword)]
+ [InlineData(SyntaxKind.StructKeyword)]
+ [InlineData(SyntaxKind.InterfaceKeyword)]
+ [InlineData(SyntaxKind.RecordKeyword)]
+ [InlineData(SyntaxKind.EnumKeyword)]
+ public void FileModifier_12(SyntaxKind typeKeyword)
+ {
+ UsingNode($$"""
+ file public {{SyntaxFacts.GetText(typeKeyword)}} C { }
+ """);
+ N(SyntaxKind.CompilationUnit);
+ {
+ N(SyntaxFacts.GetBaseTypeDeclarationKind(typeKeyword));
+ {
+ N(SyntaxKind.FileKeyword);
+ N(SyntaxKind.PublicKeyword);
+ N(typeKeyword);
+ N(SyntaxKind.IdentifierToken, "C");
+ N(SyntaxKind.OpenBraceToken);
+ N(SyntaxKind.CloseBraceToken);
+ }
+ N(SyntaxKind.EndOfFileToken);
+ }
+ EOF();
+ }
+
+ [Fact]
+ public void FileModifier_13()
+ {
+ UsingNode("""
+ file class C { }
+ """,
+ options: TestOptions.Regular10,
+ expectedBindingDiagnostics: new[]
+ {
+ // (1,12): error CS8652: The feature 'file types' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.
+ // file class C { }
+ Diagnostic(ErrorCode.ERR_FeatureInPreview, "C").WithArguments("file types").WithLocation(1, 12)
+ });
+ N(SyntaxKind.CompilationUnit);
+ {
+ N(SyntaxKind.ClassDeclaration);
+ {
+ N(SyntaxKind.FileKeyword);
+ N(SyntaxKind.ClassKeyword);
+ N(SyntaxKind.IdentifierToken, "C");
+ N(SyntaxKind.OpenBraceToken);
+ N(SyntaxKind.CloseBraceToken);
+ }
+ N(SyntaxKind.EndOfFileToken);
+ }
+ EOF();
+ }
+
+ [Fact]
+ public void FileModifier_14()
+ {
+ UsingNode("""
+ file delegate void D();
+ """);
+
+ N(SyntaxKind.CompilationUnit);
+ {
+ N(SyntaxKind.DelegateDeclaration);
+ {
+ N(SyntaxKind.FileKeyword);
+ N(SyntaxKind.DelegateKeyword);
+ N(SyntaxKind.PredefinedType);
+ {
+ N(SyntaxKind.VoidKeyword);
+ }
+ N(SyntaxKind.IdentifierToken, "D");
+ N(SyntaxKind.ParameterList);
+ {
+ N(SyntaxKind.OpenParenToken);
+ N(SyntaxKind.CloseParenToken);
+ }
+ N(SyntaxKind.SemicolonToken);
+ }
+ N(SyntaxKind.EndOfFileToken);
+ }
+ EOF();
+ }
+
+ [Fact]
+ public void FileModifier_15()
+ {
+ UsingNode("""
+ namespace NS
+ {
+ file class C { }
+ }
+ """);
+
+ N(SyntaxKind.CompilationUnit);
+ {
+ N(SyntaxKind.NamespaceDeclaration);
+ {
+ N(SyntaxKind.NamespaceKeyword);
+ N(SyntaxKind.IdentifierName);
+ {
+ N(SyntaxKind.IdentifierToken, "NS");
+ }
+ N(SyntaxKind.OpenBraceToken);
+ N(SyntaxKind.ClassDeclaration);
+ {
+ N(SyntaxKind.FileKeyword);
+ N(SyntaxKind.ClassKeyword);
+ N(SyntaxKind.IdentifierToken, "C");
+ N(SyntaxKind.OpenBraceToken);
+ N(SyntaxKind.CloseBraceToken);
+ }
+ N(SyntaxKind.CloseBraceToken);
+ }
+ N(SyntaxKind.EndOfFileToken);
+ }
+ EOF();
+ }
+
+ [Fact]
+ public void FileModifier_16()
+ {
+ UsingNode("""
+ namespace NS;
+ file class C { }
+ """);
+
+ N(SyntaxKind.CompilationUnit);
+ {
+ N(SyntaxKind.FileScopedNamespaceDeclaration);
+ {
+ N(SyntaxKind.NamespaceKeyword);
+ N(SyntaxKind.IdentifierName);
+ {
+ N(SyntaxKind.IdentifierToken, "NS");
+ }
+ N(SyntaxKind.SemicolonToken);
+ N(SyntaxKind.ClassDeclaration);
+ {
+ N(SyntaxKind.FileKeyword);
+ N(SyntaxKind.ClassKeyword);
+ N(SyntaxKind.IdentifierToken, "C");
+ N(SyntaxKind.OpenBraceToken);
+ N(SyntaxKind.CloseBraceToken);
+ }
+ }
+ N(SyntaxKind.EndOfFileToken);
+ }
+ EOF();
+ }
+
+ [Fact]
+ public void FileModifier_17()
+ {
+ UsingNode("""
+ class Outer
+ {
+ file class C { }
+ }
+ """);
+
+ N(SyntaxKind.CompilationUnit);
+ {
+ N(SyntaxKind.ClassDeclaration);
+ {
+ N(SyntaxKind.ClassKeyword);
+ N(SyntaxKind.IdentifierToken, "Outer");
+ N(SyntaxKind.OpenBraceToken);
+ N(SyntaxKind.ClassDeclaration);
+ {
+ N(SyntaxKind.FileKeyword);
+ N(SyntaxKind.ClassKeyword);
+ N(SyntaxKind.IdentifierToken, "C");
+ N(SyntaxKind.OpenBraceToken);
+ N(SyntaxKind.CloseBraceToken);
+ }
+ N(SyntaxKind.CloseBraceToken);
+ }
+ N(SyntaxKind.EndOfFileToken);
+ }
+ EOF();
+ }
+
+ [Fact]
+ public void FileModifier_18()
+ {
+ UsingNode("""
+ class C
+ {
+ file delegate* M();
+ }
+ """,
+ expectedBindingDiagnostics: new[]
+ {
+ // (3,10): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context
+ // file delegate* M();
+ Diagnostic(ErrorCode.ERR_UnsafeNeeded, "delegate*").WithLocation(3, 10),
+ // (3,31): error CS0106: The modifier 'file' is not valid for this item
+ // file delegate* M();
+ Diagnostic(ErrorCode.ERR_BadMemberFlag, "M").WithArguments("file").WithLocation(3, 31),
+ // (3,31): error CS0501: 'C.M()' must declare a body because it is not marked abstract, extern, or partial
+ // file delegate* M();
+ Diagnostic(ErrorCode.ERR_ConcreteMissingBody, "M").WithArguments("C.M()").WithLocation(3, 31)
+ });
+
+ N(SyntaxKind.CompilationUnit);
+ {
+ N(SyntaxKind.ClassDeclaration);
+ {
+ N(SyntaxKind.ClassKeyword);
+ N(SyntaxKind.IdentifierToken, "C");
+ N(SyntaxKind.OpenBraceToken);
+ N(SyntaxKind.MethodDeclaration);
+ {
+ N(SyntaxKind.FileKeyword);
+ N(SyntaxKind.FunctionPointerType);
+ {
+ N(SyntaxKind.DelegateKeyword);
+ N(SyntaxKind.AsteriskToken);
+ N(SyntaxKind.FunctionPointerParameterList);
+ {
+ N(SyntaxKind.LessThanToken);
+ N(SyntaxKind.FunctionPointerParameter);
+ {
+ N(SyntaxKind.PredefinedType);
+ {
+ N(SyntaxKind.IntKeyword);
+ }
+ }
+ N(SyntaxKind.CommaToken);
+ N(SyntaxKind.FunctionPointerParameter);
+ {
+ N(SyntaxKind.PredefinedType);
+ {
+ N(SyntaxKind.VoidKeyword);
+ }
+ }
+ N(SyntaxKind.GreaterThanToken);
+ }
+ }
+ N(SyntaxKind.IdentifierToken, "M");
+ N(SyntaxKind.ParameterList);
+ {
+ N(SyntaxKind.OpenParenToken);
+ N(SyntaxKind.CloseParenToken);
+ }
+ N(SyntaxKind.SemicolonToken);
+ }
+ N(SyntaxKind.CloseBraceToken);
+ }
+ N(SyntaxKind.EndOfFileToken);
+ }
+ EOF();
+ }
+
+ [Fact]
+ public void FileMember_01()
+ {
+ UsingNode("""
+ class C
+ {
+ file void M() { }
+ }
+ """,
+ expectedBindingDiagnostics: new[]
+ {
+ // (3,15): error CS0106: The modifier 'file' is not valid for this item
+ // file void M() { }
+ Diagnostic(ErrorCode.ERR_BadMemberFlag, "M").WithArguments("file").WithLocation(3, 15)
+ });
+ N(SyntaxKind.CompilationUnit);
+ {
+ N(SyntaxKind.ClassDeclaration);
+ {
+ N(SyntaxKind.ClassKeyword);
+ N(SyntaxKind.IdentifierToken, "C");
+ N(SyntaxKind.OpenBraceToken);
+ N(SyntaxKind.MethodDeclaration);
+ {
+ N(SyntaxKind.FileKeyword);
+ 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);
+ }
+ N(SyntaxKind.EndOfFileToken);
+ }
+ EOF();
+ }
+
+ [Fact]
+ public void FileMember_02()
+ {
+ UsingNode("""
+ class C
+ {
+ file int x;
+ }
+ """,
+ expectedBindingDiagnostics: new[]
+ {
+ // (3,14): error CS0106: The modifier 'file' is not valid for this item
+ // file int x;
+ Diagnostic(ErrorCode.ERR_BadMemberFlag, "x").WithArguments("file").WithLocation(3, 14),
+ // (3,14): warning CS0169: The field 'C.x' is never used
+ // file int x;
+ Diagnostic(ErrorCode.WRN_UnreferencedField, "x").WithArguments("C.x").WithLocation(3, 14)
+ });
+ N(SyntaxKind.CompilationUnit);
+ {
+ N(SyntaxKind.ClassDeclaration);
+ {
+ N(SyntaxKind.ClassKeyword);
+ N(SyntaxKind.IdentifierToken, "C");
+ N(SyntaxKind.OpenBraceToken);
+ N(SyntaxKind.FieldDeclaration);
+ {
+ N(SyntaxKind.FileKeyword);
+ N(SyntaxKind.VariableDeclaration);
+ {
+ N(SyntaxKind.PredefinedType);
+ {
+ N(SyntaxKind.IntKeyword);
+ }
+ N(SyntaxKind.VariableDeclarator);
+ {
+ N(SyntaxKind.IdentifierToken, "x");
+ }
+ }
+ N(SyntaxKind.SemicolonToken);
+ }
+ N(SyntaxKind.CloseBraceToken);
+ }
+ N(SyntaxKind.EndOfFileToken);
+ }
+ EOF();
+ }
+
+ [Fact]
+ public void FileMember_03()
+ {
+ UsingNode($$"""
+ class C
+ {
+ file event Action x;
+ }
+ """,
+ expectedBindingDiagnostics: new[]
+ {
+ // (3,16): error CS0246: The type or namespace name 'Action' could not be found (are you missing a using directive or an assembly reference?)
+ // file event Action x;
+ Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "Action").WithArguments("Action").WithLocation(3, 16),
+ // (3,23): error CS0106: The modifier 'file' is not valid for this item
+ // file event Action x;
+ Diagnostic(ErrorCode.ERR_BadMemberFlag, "x").WithArguments("file").WithLocation(3, 23),
+ // (3,23): warning CS0067: The event 'C.x' is never used
+ // file event Action x;
+ Diagnostic(ErrorCode.WRN_UnreferencedEvent, "x").WithArguments("C.x").WithLocation(3, 23)
+ });
+ N(SyntaxKind.CompilationUnit);
+ {
+ N(SyntaxKind.ClassDeclaration);
+ {
+ N(SyntaxKind.ClassKeyword);
+ N(SyntaxKind.IdentifierToken, "C");
+ N(SyntaxKind.OpenBraceToken);
+ N(SyntaxKind.EventFieldDeclaration);
+ {
+ N(SyntaxKind.FileKeyword);
+ N(SyntaxKind.EventKeyword);
+ N(SyntaxKind.VariableDeclaration);
+ {
+ N(SyntaxKind.IdentifierName);
+ {
+ N(SyntaxKind.IdentifierToken, "Action");
+ }
+ N(SyntaxKind.VariableDeclarator);
+ {
+ N(SyntaxKind.IdentifierToken, "x");
+ }
+ }
+ N(SyntaxKind.SemicolonToken);
+ }
+ N(SyntaxKind.CloseBraceToken);
+ }
+ N(SyntaxKind.EndOfFileToken);
+ }
+ EOF();
+ }
+
+ [Fact]
+ public void FileMember_04()
+ {
+ var source = $$"""
+ class C
+ {
+ file int x { get; set; }
+ }
+ """;
+
+ UsingNode(source, expectedBindingDiagnostics: new[]
+ {
+ // (3,14): error CS0106: The modifier 'file' is not valid for this item
+ // file int x { get; set; }
+ Diagnostic(ErrorCode.ERR_BadMemberFlag, "x").WithArguments("file").WithLocation(3, 14)
+ });
+ N(SyntaxKind.CompilationUnit);
+ {
+ N(SyntaxKind.ClassDeclaration);
+ {
+ N(SyntaxKind.ClassKeyword);
+ N(SyntaxKind.IdentifierToken, "C");
+ N(SyntaxKind.OpenBraceToken);
+ N(SyntaxKind.PropertyDeclaration);
+ {
+ N(SyntaxKind.FileKeyword);
+ N(SyntaxKind.PredefinedType);
+ {
+ N(SyntaxKind.IntKeyword);
+ }
+ N(SyntaxKind.IdentifierToken, "x");
+ 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.EndOfFileToken);
+ }
+ EOF();
+ }
+
+ [Fact]
+ public void FileMember_05()
+ {
+ var source = $$"""
+ class C
+ {
+ async file void M() { }
+ }
+ """;
+
+ UsingNode(source, expectedBindingDiagnostics: new[]
+ {
+ // (3,21): error CS0106: The modifier 'file' is not valid for this item
+ // async file void M() { }
+ Diagnostic(ErrorCode.ERR_BadMemberFlag, "M").WithArguments("file").WithLocation(3, 21),
+ // (3,21): warning CS1998: This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread.
+ // async file void M() { }
+ Diagnostic(ErrorCode.WRN_AsyncLacksAwaits, "M").WithLocation(3, 21)
+ });
+ N(SyntaxKind.CompilationUnit);
+ {
+ N(SyntaxKind.ClassDeclaration);
+ {
+ N(SyntaxKind.ClassKeyword);
+ N(SyntaxKind.IdentifierToken, "C");
+ N(SyntaxKind.OpenBraceToken);
+ N(SyntaxKind.MethodDeclaration);
+ {
+ N(SyntaxKind.AsyncKeyword);
+ N(SyntaxKind.FileKeyword);
+ 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);
+ }
+ N(SyntaxKind.EndOfFileToken);
+ }
+ EOF();
+ }
+
+ [Fact]
+ public void MemberNamedFile_01()
+ {
+ UsingNode($$"""
+ class C
+ {
+ int file;
+ }
+ """, expectedBindingDiagnostics: new[]
+ {
+ // (3,9): warning CS0169: The field 'C.file' is never used
+ // int file;
+ Diagnostic(ErrorCode.WRN_UnreferencedField, "file").WithArguments("C.file").WithLocation(3, 9)
+ });
+
+ N(SyntaxKind.CompilationUnit);
+ {
+ N(SyntaxKind.ClassDeclaration);
+ {
+ N(SyntaxKind.ClassKeyword);
+ N(SyntaxKind.IdentifierToken, "C");
+ N(SyntaxKind.OpenBraceToken);
+ N(SyntaxKind.FieldDeclaration);
+ {
+ N(SyntaxKind.VariableDeclaration);
+ {
+ N(SyntaxKind.PredefinedType);
+ {
+ N(SyntaxKind.IntKeyword);
+ }
+ N(SyntaxKind.VariableDeclarator);
+ {
+ N(SyntaxKind.IdentifierToken, "file");
+ }
+ }
+ N(SyntaxKind.SemicolonToken);
+ }
+ N(SyntaxKind.CloseBraceToken);
+ }
+ N(SyntaxKind.EndOfFileToken);
+ }
+ EOF();
+ }
+
+ [Fact]
+ public void MemberNamedFile_02()
+ {
+ UsingNode($$"""
+ class C
+ {
+ int file { get; set; }
+ }
+ """);
+
+ N(SyntaxKind.CompilationUnit);
+ {
+ N(SyntaxKind.ClassDeclaration);
+ {
+ N(SyntaxKind.ClassKeyword);
+ N(SyntaxKind.IdentifierToken, "C");
+ N(SyntaxKind.OpenBraceToken);
+ N(SyntaxKind.PropertyDeclaration);
+ {
+ N(SyntaxKind.PredefinedType);
+ {
+ N(SyntaxKind.IntKeyword);
+ }
+ N(SyntaxKind.IdentifierToken, "file");
+ 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.EndOfFileToken);
+ }
+ EOF();
+ }
+
+ [Fact]
+ public void MemberNamedFile_03()
+ {
+ UsingNode($$"""
+ class C
+ {
+ event Action file;
+ }
+ """,
+ expectedBindingDiagnostics: new[]
+ {
+ // (3,11): error CS0246: The type or namespace name 'Action' could not be found (are you missing a using directive or an assembly reference?)
+ // event Action file;
+ Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "Action").WithArguments("Action").WithLocation(3, 11),
+ // (3,18): warning CS0067: The event 'C.file' is never used
+ // event Action file;
+ Diagnostic(ErrorCode.WRN_UnreferencedEvent, "file").WithArguments("C.file").WithLocation(3, 18)
+ });
+
+ N(SyntaxKind.CompilationUnit);
+ {
+ N(SyntaxKind.ClassDeclaration);
+ {
+ N(SyntaxKind.ClassKeyword);
+ N(SyntaxKind.IdentifierToken, "C");
+ N(SyntaxKind.OpenBraceToken);
+ N(SyntaxKind.EventFieldDeclaration);
+ {
+ N(SyntaxKind.EventKeyword);
+ N(SyntaxKind.VariableDeclaration);
+ {
+ N(SyntaxKind.IdentifierName);
+ {
+ N(SyntaxKind.IdentifierToken, "Action");
+ }
+ N(SyntaxKind.VariableDeclarator);
+ {
+ N(SyntaxKind.IdentifierToken, "file");
+ }
+ }
+ N(SyntaxKind.SemicolonToken);
+ }
+ N(SyntaxKind.CloseBraceToken);
+ }
+ N(SyntaxKind.EndOfFileToken);
+ }
+ EOF();
+ }
+
+ [Fact]
+ public void MemberNamedFile_04()
+ {
+ UsingNode($$"""
+ class C
+ {
+ void file() { }
+ }
+ """);
+
+ N(SyntaxKind.CompilationUnit);
+ {
+ N(SyntaxKind.ClassDeclaration);
+ {
+ N(SyntaxKind.ClassKeyword);
+ N(SyntaxKind.IdentifierToken, "C");
+ N(SyntaxKind.OpenBraceToken);
+ N(SyntaxKind.MethodDeclaration);
+ {
+ N(SyntaxKind.PredefinedType);
+ {
+ N(SyntaxKind.VoidKeyword);
+ }
+ N(SyntaxKind.IdentifierToken, "file");
+ 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();
+ }
+
+ [Fact]
+ public void MemberNamedFile_05()
+ {
+ UsingNode($$"""
+ file class file { }
+ """,
+ expectedBindingDiagnostics: new[]
+ {
+ // (1,12): warning CS8981: The type name 'file' only contains lower-cased ascii characters. Such names may become reserved for the language.
+ // file class file { }
+ Diagnostic(ErrorCode.WRN_LowerCaseTypeName, "file").WithArguments("file").WithLocation(1, 12)
+ });
+
+ N(SyntaxKind.CompilationUnit);
+ {
+ N(SyntaxKind.ClassDeclaration);
+ {
+ N(SyntaxKind.FileKeyword);
+ N(SyntaxKind.ClassKeyword);
+ N(SyntaxKind.IdentifierToken, "file");
+ N(SyntaxKind.OpenBraceToken);
+ N(SyntaxKind.CloseBraceToken);
+ }
+ N(SyntaxKind.EndOfFileToken);
+ }
+ EOF();
+ }
+
+ [Fact]
+ public void MemberNamedFile_06_CSharp10()
+ {
+ UsingNode($$"""
+ class C
+ {
+ file async;
+ }
+ """,
+ options: TestOptions.Regular10,
+ expectedBindingDiagnostics: new[]
+ {
+ // (3,5): error CS0246: The type or namespace name 'file' could not be found (are you missing a using directive or an assembly reference?)
+ // file async;
+ Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "file").WithArguments("file").WithLocation(3, 5),
+ // (3,10): warning CS0169: The field 'C.async' is never used
+ // file async;
+ Diagnostic(ErrorCode.WRN_UnreferencedField, "async").WithArguments("C.async").WithLocation(3, 10)
+ });
+ N(SyntaxKind.CompilationUnit);
+ {
+ N(SyntaxKind.ClassDeclaration);
+ {
+ N(SyntaxKind.ClassKeyword);
+ N(SyntaxKind.IdentifierToken, "C");
+ N(SyntaxKind.OpenBraceToken);
+ N(SyntaxKind.FieldDeclaration);
+ {
+ N(SyntaxKind.VariableDeclaration);
+ {
+ N(SyntaxKind.IdentifierName);
+ {
+ N(SyntaxKind.IdentifierToken, "file");
+ }
+ N(SyntaxKind.VariableDeclarator);
+ {
+ N(SyntaxKind.IdentifierToken, "async");
+ }
+ }
+ N(SyntaxKind.SemicolonToken);
+ }
+ N(SyntaxKind.CloseBraceToken);
+ }
+ N(SyntaxKind.EndOfFileToken);
+ }
+ EOF();
+ }
+
+ [Fact]
+ public void MemberNamedFile_06()
+ {
+ UsingNode($$"""
+ class C
+ {
+ file async;
+ }
+ """,
+ // (3,15): error CS1519: Invalid token ';' in class, record, struct, or interface member declaration
+ // file async;
+ Diagnostic(ErrorCode.ERR_InvalidMemberDecl, ";").WithArguments(";").WithLocation(3, 15),
+ // (3,15): error CS1519: Invalid token ';' in class, record, struct, or interface member declaration
+ // file async;
+ Diagnostic(ErrorCode.ERR_InvalidMemberDecl, ";").WithArguments(";").WithLocation(3, 15));
+
+ N(SyntaxKind.CompilationUnit);
+ {
+ N(SyntaxKind.ClassDeclaration);
+ {
+ N(SyntaxKind.ClassKeyword);
+ N(SyntaxKind.IdentifierToken, "C");
+ N(SyntaxKind.OpenBraceToken);
+ N(SyntaxKind.IncompleteMember);
+ {
+ N(SyntaxKind.FileKeyword);
+ N(SyntaxKind.IdentifierName);
+ {
+ N(SyntaxKind.IdentifierToken, "async");
+ }
+ }
+ N(SyntaxKind.CloseBraceToken);
+ }
+ N(SyntaxKind.EndOfFileToken);
+ }
+ EOF();
+ }
+
+ [Fact]
+ public void MemberNamedFile_07_CSharp10()
+ {
+ UsingNode($$"""
+ class C
+ {
+ file item;
+ }
+ """,
+ options: TestOptions.Regular10,
+ expectedBindingDiagnostics: new[]
+ {
+ // (3,5): error CS0246: The type or namespace name 'file' could not be found (are you missing a using directive or an assembly reference?)
+ // file item;
+ Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "file").WithArguments("file").WithLocation(3, 5),
+ // (3,10): warning CS0169: The field 'C.item' is never used
+ // file item;
+ Diagnostic(ErrorCode.WRN_UnreferencedField, "item").WithArguments("C.item").WithLocation(3, 10)
+ });
+
+ N(SyntaxKind.CompilationUnit);
+ {
+ N(SyntaxKind.ClassDeclaration);
+ {
+ N(SyntaxKind.ClassKeyword);
+ N(SyntaxKind.IdentifierToken, "C");
+ N(SyntaxKind.OpenBraceToken);
+ N(SyntaxKind.FieldDeclaration);
+ {
+ N(SyntaxKind.VariableDeclaration);
+ {
+ N(SyntaxKind.IdentifierName);
+ {
+ N(SyntaxKind.IdentifierToken, "file");
+ }
+ N(SyntaxKind.VariableDeclarator);
+ {
+ N(SyntaxKind.IdentifierToken, "item");
+ }
+ }
+ N(SyntaxKind.SemicolonToken);
+ }
+ N(SyntaxKind.CloseBraceToken);
+ }
+ N(SyntaxKind.EndOfFileToken);
+ }
+ EOF();
+ }
+
+ // PROTOTYPE(ft): confirm with LDM whether this breaking change is acceptable (compared to CSharp10 version above).
+ [Fact]
+ public void MemberNamedFile_07()
+ {
+ UsingNode($$"""
+ class C
+ {
+ file item;
+ }
+ """,
+ expectedParsingDiagnostics: new[]
+ {
+ // (3,14): error CS1519: Invalid token ';' in class, record, struct, or interface member declaration
+ // file item;
+ Diagnostic(ErrorCode.ERR_InvalidMemberDecl, ";").WithArguments(";").WithLocation(3, 14),
+ // (3,14): error CS1519: Invalid token ';' in class, record, struct, or interface member declaration
+ // file item;
+ Diagnostic(ErrorCode.ERR_InvalidMemberDecl, ";").WithArguments(";").WithLocation(3, 14)
+ });
+
+ N(SyntaxKind.CompilationUnit);
+ {
+ N(SyntaxKind.ClassDeclaration);
+ {
+ N(SyntaxKind.ClassKeyword);
+ N(SyntaxKind.IdentifierToken, "C");
+ N(SyntaxKind.OpenBraceToken);
+ N(SyntaxKind.IncompleteMember);
+ {
+ N(SyntaxKind.FileKeyword);
+ N(SyntaxKind.IdentifierName);
+ {
+ N(SyntaxKind.IdentifierToken, "item");
+ }
+ }
+ N(SyntaxKind.CloseBraceToken);
+ }
+ N(SyntaxKind.EndOfFileToken);
+ }
+ EOF();
+ }
+ [Fact]
+ public void MemberNamedFile_08()
+ {
+ UsingNode($$"""
+ record file { }
+ """,
+ expectedBindingDiagnostics: new[]
+ {
+ // (1,8): warning CS8981: The type name 'file' only contains lower-cased ascii characters. Such names may become reserved for the language.
+ // record file { }
+ Diagnostic(ErrorCode.WRN_LowerCaseTypeName, "file").WithArguments("file").WithLocation(1, 8)
+ });
+
+ N(SyntaxKind.CompilationUnit);
+ {
+ N(SyntaxKind.RecordDeclaration);
+ {
+ N(SyntaxKind.RecordKeyword);
+ N(SyntaxKind.IdentifierToken, "file");
+ N(SyntaxKind.OpenBraceToken);
+ N(SyntaxKind.CloseBraceToken);
+ }
+ N(SyntaxKind.EndOfFileToken);
+ }
+ EOF();
+ }
+
+ [Fact]
+ public void Errors_01_CSharp10()
+ {
+ UsingNode($$"""
+ file
+ """,
+ options: TestOptions.Regular10,
+ // (1,1): error CS0116: A namespace cannot directly contain members such as fields, methods or statements
+ // file
+ Diagnostic(ErrorCode.ERR_NamespaceUnexpected, "file").WithLocation(1, 1));
+
+ N(SyntaxKind.CompilationUnit);
+ {
+ N(SyntaxKind.IncompleteMember);
+ {
+ N(SyntaxKind.IdentifierName);
+ {
+ N(SyntaxKind.IdentifierToken, "file");
+ }
+ }
+ N(SyntaxKind.EndOfFileToken);
+ }
+ EOF();
+ }
+
+ [Fact]
+ public void Errors_01()
+ {
+ UsingNode($$"""
+ file
+ """,
+ // (1,1): error CS0116: A namespace cannot directly contain members such as fields, methods or statements
+ // file
+ Diagnostic(ErrorCode.ERR_NamespaceUnexpected, "file").WithLocation(1, 1));
+
+ N(SyntaxKind.CompilationUnit);
+ {
+ N(SyntaxKind.IncompleteMember);
+ {
+ N(SyntaxKind.FileKeyword);
+ }
+ N(SyntaxKind.EndOfFileToken);
+ }
+ EOF();
+ }
+
+ [Fact]
+ public void Errors_02_CSharp10()
+ {
+ UsingNode($$"""
+ file;
+ """,
+ options: TestOptions.Regular10,
+ expectedBindingDiagnostics: new[]
+ {
+ // (1,1): error CS0103: The name 'file' does not exist in the current context
+ // file;
+ Diagnostic(ErrorCode.ERR_NameNotInContext, "file").WithArguments("file").WithLocation(1, 1),
+ // (1,1): error CS0201: Only assignment, call, increment, decrement, await, and new object expressions can be used as a statement
+ // file;
+ Diagnostic(ErrorCode.ERR_IllegalStatement, "file").WithLocation(1, 1)
+ });
+
+ N(SyntaxKind.CompilationUnit);
+ {
+ N(SyntaxKind.GlobalStatement);
+ {
+ N(SyntaxKind.ExpressionStatement);
+ {
+ N(SyntaxKind.IdentifierName);
+ {
+ N(SyntaxKind.IdentifierToken, "file");
+ }
+ N(SyntaxKind.SemicolonToken);
+ }
+ }
+ N(SyntaxKind.EndOfFileToken);
+ }
+ EOF();
+ }
+
+ [Fact]
+ public void Errors_02()
+ {
+ UsingNode($$"""
+ file;
+ """,
+ expectedParsingDiagnostics: new[]
+ {
+ // (1,1): error CS0116: A namespace cannot directly contain members such as fields, methods or statements
+ // file;
+ Diagnostic(ErrorCode.ERR_NamespaceUnexpected, "file").WithLocation(1, 1)
+ },
+ expectedBindingDiagnostics: new[]
+ {
+ // (1,1): error CS0116: A namespace cannot directly contain members such as fields, methods or statements
+ // file;
+ Diagnostic(ErrorCode.ERR_NamespaceUnexpected, "file").WithLocation(1, 1),
+ // (1,5): error CS8937: At least one top-level statement must be non-empty.
+ // file;
+ Diagnostic(ErrorCode.ERR_SimpleProgramIsEmpty, ";").WithLocation(1, 5)
+ });
+
+ N(SyntaxKind.CompilationUnit);
+ {
+ N(SyntaxKind.IncompleteMember);
+ {
+ N(SyntaxKind.FileKeyword);
+ }
+ N(SyntaxKind.GlobalStatement);
+ {
+ N(SyntaxKind.EmptyStatement);
+ {
+ N(SyntaxKind.SemicolonToken);
+ }
+ }
+ N(SyntaxKind.EndOfFileToken);
+ }
+ EOF();
+ }
+
+ [Fact]
+ public void Errors_03_CSharp10()
+ {
+ UsingNode($$"""
+ file namespace NS;
+ """,
+ options: TestOptions.Regular10,
+ expectedParsingDiagnostics: new[]
+ {
+ // (1,1): error CS0116: A namespace cannot directly contain members such as fields, methods or statements
+ // file namespace NS;
+ Diagnostic(ErrorCode.ERR_NamespaceUnexpected, "file").WithLocation(1, 1)
+ },
+ expectedBindingDiagnostics: new[]
+ {
+ // (1,1): error CS0116: A namespace cannot directly contain members such as fields, methods or statements
+ // file namespace NS;
+ Diagnostic(ErrorCode.ERR_NamespaceUnexpected, "file").WithLocation(1, 1),
+ // (1,16): error CS8956: File-scoped namespace must precede all other members in a file.
+ // file namespace NS;
+ Diagnostic(ErrorCode.ERR_FileScopedNamespaceNotBeforeAllMembers, "NS").WithLocation(1, 16)
+ });
+
+ N(SyntaxKind.CompilationUnit);
+ {
+ N(SyntaxKind.IncompleteMember);
+ {
+ N(SyntaxKind.IdentifierName);
+ {
+ N(SyntaxKind.IdentifierToken, "file");
+ }
+ }
+ N(SyntaxKind.FileScopedNamespaceDeclaration);
+ {
+ N(SyntaxKind.NamespaceKeyword);
+ N(SyntaxKind.IdentifierName);
+ {
+ N(SyntaxKind.IdentifierToken, "NS");
+ }
+ N(SyntaxKind.SemicolonToken);
+ }
+ N(SyntaxKind.EndOfFileToken);
+ }
+ EOF();
+ }
+
+ [Fact]
+ public void Errors_03()
+ {
+ UsingNode($$"""
+ file namespace NS;
+ """,
+ expectedBindingDiagnostics: new[]
+ {
+ // (1,1): error CS1671: A namespace declaration cannot have modifiers or attributes
+ // file namespace NS;
+ Diagnostic(ErrorCode.ERR_BadModifiersOnNamespace, "file").WithLocation(1, 1)
+ });
+
+ N(SyntaxKind.CompilationUnit);
+ {
+ N(SyntaxKind.FileScopedNamespaceDeclaration);
+ {
+ N(SyntaxKind.FileKeyword);
+ N(SyntaxKind.NamespaceKeyword);
+ N(SyntaxKind.IdentifierName);
+ {
+ N(SyntaxKind.IdentifierToken, "NS");
+ }
+ N(SyntaxKind.SemicolonToken);
+ }
+ N(SyntaxKind.EndOfFileToken);
+ }
+ EOF();
+ }
+
+ [Fact]
+ public void Errors_04_CSharp10()
+ {
+ UsingNode($$"""
+ file namespace NS { }
+ """,
+ options: TestOptions.Regular10,
+ expectedParsingDiagnostics: new[]
+ {
+ // (1,1): error CS0116: A namespace cannot directly contain members such as fields, methods or statements
+ // file namespace NS { }
+ Diagnostic(ErrorCode.ERR_NamespaceUnexpected, "file").WithLocation(1, 1)
+ });
+
+ N(SyntaxKind.CompilationUnit);
+ {
+ N(SyntaxKind.IncompleteMember);
+ {
+ N(SyntaxKind.IdentifierName);
+ {
+ N(SyntaxKind.IdentifierToken, "file");
+ }
+ }
+ N(SyntaxKind.NamespaceDeclaration);
+ {
+ N(SyntaxKind.NamespaceKeyword);
+ N(SyntaxKind.IdentifierName);
+ {
+ N(SyntaxKind.IdentifierToken, "NS");
+ }
+ N(SyntaxKind.OpenBraceToken);
+ N(SyntaxKind.CloseBraceToken);
+ }
+ N(SyntaxKind.EndOfFileToken);
+ }
+ EOF();
+ }
+
+ [Fact]
+ public void Errors_04()
+ {
+ UsingNode($$"""
+ file namespace NS { }
+ """,
+ expectedBindingDiagnostics: new[]
+ {
+ // (1,1): error CS1671: A namespace declaration cannot have modifiers or attributes
+ // file namespace NS { }
+ Diagnostic(ErrorCode.ERR_BadModifiersOnNamespace, "file").WithLocation(1, 1)
+ });
+
+ N(SyntaxKind.CompilationUnit);
+ {
+ N(SyntaxKind.NamespaceDeclaration);
+ {
+ N(SyntaxKind.FileKeyword);
+ N(SyntaxKind.NamespaceKeyword);
+ N(SyntaxKind.IdentifierName);
+ {
+ N(SyntaxKind.IdentifierToken, "NS");
+ }
+ N(SyntaxKind.OpenBraceToken);
+ N(SyntaxKind.CloseBraceToken);
+ }
+ N(SyntaxKind.EndOfFileToken);
+ }
+ EOF();
+ }
+
+ [Fact]
+ public void File_Repeated()
+ {
+ const int FileModifiersCount = 100000;
+ var manyFileModifiers = string.Join(" ", Enumerable.Repeat("file", FileModifiersCount));
+ UsingNode(manyFileModifiers,
+ expectedParsingDiagnostics: new[]
+ {
+ Diagnostic(ErrorCode.ERR_NamespaceUnexpected, "file").WithLocation(1, 499996)
+ });
+
+ N(SyntaxKind.CompilationUnit);
+ {
+ N(SyntaxKind.IncompleteMember);
+ {
+ for (var i = 0; i < FileModifiersCount; i++)
+ {
+ N(SyntaxKind.FileKeyword);
+ }
+ N(SyntaxKind.EndOfFileToken);
+ }
+ }
+ EOF();
+
+ UsingNode(manyFileModifiers + " class { }",
+ expectedParsingDiagnostics: new[]
+ {
+ Diagnostic(ErrorCode.ERR_IdentifierExpected, "{").WithLocation(1, 500007)
+ },
+ expectedBindingDiagnostics: new[]
+ {
+ Diagnostic(ErrorCode.ERR_DuplicateModifier, "file").WithArguments("file").WithLocation(1, 6),
+ Diagnostic(ErrorCode.ERR_IdentifierExpected, "{").WithLocation(1, 500007)
+ });
+
+ N(SyntaxKind.CompilationUnit);
+ {
+ N(SyntaxKind.ClassDeclaration);
+ {
+ for (int i = 0; i < FileModifiersCount; i++)
+ {
+ N(SyntaxKind.FileKeyword);
+ }
+ N(SyntaxKind.ClassKeyword);
+ M(SyntaxKind.IdentifierToken);
+ N(SyntaxKind.OpenBraceToken);
+ N(SyntaxKind.CloseBraceToken);
+ }
+ N(SyntaxKind.EndOfFileToken);
+ }
+ EOF();
+ }
+
+ [Fact]
+ public void MethodNamedRecord_01_CSharp8()
+ {
+ UsingNode("""
+ class C
+ {
+ file record();
+ }
+ """,
+ options: TestOptions.Regular8,
+ expectedBindingDiagnostics: new[]
+ {
+ // (3,5): error CS0246: The type or namespace name 'file' could not be found (are you missing a using directive or an assembly reference?)
+ // file record();
+ Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "file").WithArguments("file").WithLocation(3, 5),
+ // (3,10): error CS0501: 'C.record()' must declare a body because it is not marked abstract, extern, or partial
+ // file record();
+ Diagnostic(ErrorCode.ERR_ConcreteMissingBody, "record").WithArguments("C.record()").WithLocation(3, 10)
+ });
+
+ 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, "file");
+ }
+ N(SyntaxKind.IdentifierToken, "record");
+ N(SyntaxKind.ParameterList);
+ {
+ N(SyntaxKind.OpenParenToken);
+ N(SyntaxKind.CloseParenToken);
+ }
+ N(SyntaxKind.SemicolonToken);
+ }
+ N(SyntaxKind.CloseBraceToken);
+ }
+ N(SyntaxKind.EndOfFileToken);
+ }
+ EOF();
+ }
+
+ [Fact]
+ public void MethodNamedRecord_01_CSharpNext()
+ {
+ UsingNode("""
+ class C
+ {
+ file record();
+ }
+ """,
+ expectedBindingDiagnostics: new[]
+ {
+ // (3,10): error CS0106: The modifier 'file' is not valid for this item
+ // file record();
+ Diagnostic(ErrorCode.ERR_BadMemberFlag, "record").WithArguments("file").WithLocation(3, 10),
+ // (3,10): error CS1520: Method must have a return type
+ // file record();
+ Diagnostic(ErrorCode.ERR_MemberNeedsType, "record").WithLocation(3, 10)
+ });
+
+ N(SyntaxKind.CompilationUnit);
+ {
+ N(SyntaxKind.ClassDeclaration);
+ {
+ N(SyntaxKind.ClassKeyword);
+ N(SyntaxKind.IdentifierToken, "C");
+ N(SyntaxKind.OpenBraceToken);
+ N(SyntaxKind.ConstructorDeclaration);
+ {
+ N(SyntaxKind.FileKeyword);
+ N(SyntaxKind.IdentifierToken, "record");
+ N(SyntaxKind.ParameterList);
+ {
+ N(SyntaxKind.OpenParenToken);
+ N(SyntaxKind.CloseParenToken);
+ }
+ N(SyntaxKind.SemicolonToken);
+ }
+ N(SyntaxKind.CloseBraceToken);
+ }
+ N(SyntaxKind.EndOfFileToken);
+ }
+ EOF();
+ }
+
+ [Fact]
+ public void MethodNamedRecord_02_CSharp8()
+ {
+ UsingNode("""
+ class C
+ {
+ file record() { }
+ }
+ """,
+ options: TestOptions.Regular8,
+ expectedBindingDiagnostics: new[]
+ {
+ // (3,5): error CS0246: The type or namespace name 'file' could not be found (are you missing a using directive or an assembly reference?)
+ // file record() { }
+ Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "file").WithArguments("file").WithLocation(3, 5),
+ // (3,10): error CS0161: 'C.record()': not all code paths return a value
+ // file record() { }
+ Diagnostic(ErrorCode.ERR_ReturnExpected, "record").WithArguments("C.record()").WithLocation(3, 10)
+ });
+
+ 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, "file");
+ }
+ N(SyntaxKind.IdentifierToken, "record");
+ 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();
+ }
+
+ [Fact]
+ public void MethodNamedRecord_02_CSharpNext()
+ {
+ UsingNode("""
+ class C
+ {
+ file record() { }
+ }
+ """, expectedBindingDiagnostics: new[]
+ {
+ // (3,10): error CS0106: The modifier 'file' is not valid for this item
+ // file record() { }
+ Diagnostic(ErrorCode.ERR_BadMemberFlag, "record").WithArguments("file").WithLocation(3, 10),
+ // (3,10): error CS1520: Method must have a return type
+ // file record() { }
+ Diagnostic(ErrorCode.ERR_MemberNeedsType, "record").WithLocation(3, 10)
+ });
+
+ N(SyntaxKind.CompilationUnit);
+ {
+ N(SyntaxKind.ClassDeclaration);
+ {
+ N(SyntaxKind.ClassKeyword);
+ N(SyntaxKind.IdentifierToken, "C");
+ N(SyntaxKind.OpenBraceToken);
+ N(SyntaxKind.ConstructorDeclaration);
+ {
+ N(SyntaxKind.FileKeyword);
+ N(SyntaxKind.IdentifierToken, "record");
+ 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();
+ }
+
+ [Fact]
+ public void FileRecord_01_CSharp8()
+ {
+ UsingNode("""
+ class C
+ {
+ file record X();
+ }
+ """,
+ options: TestOptions.Regular8,
+ expectedBindingDiagnostics: new[]
+ {
+ // (3,10): error CS0246: The type or namespace name 'record' could not be found (are you missing a using directive or an assembly reference?)
+ // file record X();
+ Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "record").WithArguments("record").WithLocation(3, 10),
+ // (3,17): error CS0106: The modifier 'file' is not valid for this item
+ // file record X();
+ Diagnostic(ErrorCode.ERR_BadMemberFlag, "X").WithArguments("file").WithLocation(3, 17),
+ // (3,17): error CS0501: 'C.X()' must declare a body because it is not marked abstract, extern, or partial
+ // file record X();
+ Diagnostic(ErrorCode.ERR_ConcreteMissingBody, "X").WithArguments("C.X()").WithLocation(3, 17)
+ });
+
+ N(SyntaxKind.CompilationUnit);
+ {
+ N(SyntaxKind.ClassDeclaration);
+ {
+ N(SyntaxKind.ClassKeyword);
+ N(SyntaxKind.IdentifierToken, "C");
+ N(SyntaxKind.OpenBraceToken);
+ N(SyntaxKind.MethodDeclaration);
+ {
+ N(SyntaxKind.FileKeyword);
+ N(SyntaxKind.IdentifierName);
+ {
+ N(SyntaxKind.IdentifierToken, "record");
+ }
+ N(SyntaxKind.IdentifierToken, "X");
+ N(SyntaxKind.ParameterList);
+ {
+ N(SyntaxKind.OpenParenToken);
+ N(SyntaxKind.CloseParenToken);
+ }
+ N(SyntaxKind.SemicolonToken);
+ }
+ N(SyntaxKind.CloseBraceToken);
+ }
+ N(SyntaxKind.EndOfFileToken);
+ }
+ EOF();
+ }
+
+ [Fact]
+ public void FileRecord_01_CSharpNext()
+ {
+ UsingNode("""
+ class C
+ {
+ file record X();
+ }
+ """);
+
+ N(SyntaxKind.CompilationUnit);
+ {
+ N(SyntaxKind.ClassDeclaration);
+ {
+ N(SyntaxKind.ClassKeyword);
+ N(SyntaxKind.IdentifierToken, "C");
+ N(SyntaxKind.OpenBraceToken);
+ N(SyntaxKind.RecordDeclaration);
+ {
+ N(SyntaxKind.FileKeyword);
+ N(SyntaxKind.RecordKeyword);
+ N(SyntaxKind.IdentifierToken, "X");
+ N(SyntaxKind.ParameterList);
+ {
+ N(SyntaxKind.OpenParenToken);
+ N(SyntaxKind.CloseParenToken);
+ }
+ N(SyntaxKind.SemicolonToken);
+ }
+ N(SyntaxKind.CloseBraceToken);
+ }
+ N(SyntaxKind.EndOfFileToken);
+ }
+ EOF();
+ }
+
+ [Fact]
+ public void FileRecord_02_CSharp8()
+ {
+ UsingNode("""
+ class C
+ {
+ file record X() { }
+ }
+ """,
+ options: TestOptions.Regular8,
+ expectedBindingDiagnostics: new[]
+ {
+ // (3,10): error CS0246: The type or namespace name 'record' could not be found (are you missing a using directive or an assembly reference?)
+ // file record X() { }
+ Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "record").WithArguments("record").WithLocation(3, 10),
+ // (3,17): error CS0106: The modifier 'file' is not valid for this item
+ // file record X() { }
+ Diagnostic(ErrorCode.ERR_BadMemberFlag, "X").WithArguments("file").WithLocation(3, 17),
+ // (3,17): error CS0161: 'C.X()': not all code paths return a value
+ // file record X() { }
+ Diagnostic(ErrorCode.ERR_ReturnExpected, "X").WithArguments("C.X()").WithLocation(3, 17)
+ });
+
+ N(SyntaxKind.CompilationUnit);
+ {
+ N(SyntaxKind.ClassDeclaration);
+ {
+ N(SyntaxKind.ClassKeyword);
+ N(SyntaxKind.IdentifierToken, "C");
+ N(SyntaxKind.OpenBraceToken);
+ N(SyntaxKind.MethodDeclaration);
+ {
+ N(SyntaxKind.FileKeyword);
+ N(SyntaxKind.IdentifierName);
+ {
+ N(SyntaxKind.IdentifierToken, "record");
+ }
+ N(SyntaxKind.IdentifierToken, "X");
+ 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();
+ }
+
+ [Fact]
+ public void FileRecord_02_CSharpNext()
+ {
+ UsingNode("""
+ class C
+ {
+ file record X() { }
+ }
+ """);
+
+ N(SyntaxKind.CompilationUnit);
+ {
+ N(SyntaxKind.ClassDeclaration);
+ {
+ N(SyntaxKind.ClassKeyword);
+ N(SyntaxKind.IdentifierToken, "C");
+ N(SyntaxKind.OpenBraceToken);
+ N(SyntaxKind.RecordDeclaration);
+ {
+ N(SyntaxKind.FileKeyword);
+ N(SyntaxKind.RecordKeyword);
+ N(SyntaxKind.IdentifierToken, "X");
+ N(SyntaxKind.ParameterList);
+ {
+ N(SyntaxKind.OpenParenToken);
+ N(SyntaxKind.CloseParenToken);
+ }
+ N(SyntaxKind.OpenBraceToken);
+ N(SyntaxKind.CloseBraceToken);
+ }
+ N(SyntaxKind.CloseBraceToken);
+ }
+ N(SyntaxKind.EndOfFileToken);
+ }
+ EOF();
+ }
+
+ [Fact]
+ public void FileRecord_03_CSharp8()
+ {
+ UsingNode("""
+ class C
+ {
+ file record X;
+ }
+ """,
+ options: TestOptions.Regular8, expectedBindingDiagnostics: new[]
+ {
+ // (3,10): error CS0246: The type or namespace name 'record' could not be found (are you missing a using directive or an assembly reference?)
+ // file record X;
+ Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "record").WithArguments("record").WithLocation(3, 10),
+ // (3,17): error CS0106: The modifier 'file' is not valid for this item
+ // file record X;
+ Diagnostic(ErrorCode.ERR_BadMemberFlag, "X").WithArguments("file").WithLocation(3, 17),
+ // (3,17): warning CS0169: The field 'C.X' is never used
+ // file record X;
+ Diagnostic(ErrorCode.WRN_UnreferencedField, "X").WithArguments("C.X").WithLocation(3, 17)
+ });
+
+ N(SyntaxKind.CompilationUnit);
+ {
+ N(SyntaxKind.ClassDeclaration);
+ {
+ N(SyntaxKind.ClassKeyword);
+ N(SyntaxKind.IdentifierToken, "C");
+ N(SyntaxKind.OpenBraceToken);
+ N(SyntaxKind.FieldDeclaration);
+ {
+ N(SyntaxKind.FileKeyword);
+ N(SyntaxKind.VariableDeclaration);
+ {
+ N(SyntaxKind.IdentifierName);
+ {
+ N(SyntaxKind.IdentifierToken, "record");
+ }
+ N(SyntaxKind.VariableDeclarator);
+ {
+ N(SyntaxKind.IdentifierToken, "X");
+ }
+ }
+ N(SyntaxKind.SemicolonToken);
+ }
+ N(SyntaxKind.CloseBraceToken);
+ }
+ N(SyntaxKind.EndOfFileToken);
+ }
+ EOF();
+ }
+
+ [Fact]
+ public void FileRecord_03_CSharpNext()
+ {
+ UsingNode("""
+ class C
+ {
+ file record X;
+ }
+ """);
+
+ N(SyntaxKind.CompilationUnit);
+ {
+ N(SyntaxKind.ClassDeclaration);
+ {
+ N(SyntaxKind.ClassKeyword);
+ N(SyntaxKind.IdentifierToken, "C");
+ N(SyntaxKind.OpenBraceToken);
+ N(SyntaxKind.RecordDeclaration);
+ {
+ N(SyntaxKind.FileKeyword);
+ N(SyntaxKind.RecordKeyword);
+ N(SyntaxKind.IdentifierToken, "X");
+ N(SyntaxKind.SemicolonToken);
+ }
+ N(SyntaxKind.CloseBraceToken);
+ }
+ N(SyntaxKind.EndOfFileToken);
+ }
+ EOF();
+ }
+
+ [Fact]
+ public void LocalVariable_01()
+ {
+ UsingNode("""
+ void M()
+ {
+ file file;
+ }
+ """,
+ expectedBindingDiagnostics: new[]
+ {
+ // (1,6): warning CS8321: The local function 'M' is declared but never used
+ // void M()
+ Diagnostic(ErrorCode.WRN_UnreferencedLocalFunction, "M").WithArguments("M").WithLocation(1, 6),
+ // (3,5): error CS0118: 'file' is a variable but is used like a type
+ // file file;
+ Diagnostic(ErrorCode.ERR_BadSKknown, "file").WithArguments("file", "variable", "type").WithLocation(3, 5),
+ // (3,10): warning CS0168: The variable 'file' is declared but never used
+ // file file;
+ Diagnostic(ErrorCode.WRN_UnreferencedVar, "file").WithArguments("file").WithLocation(3, 10)
+ });
+ N(SyntaxKind.CompilationUnit);
+ {
+ N(SyntaxKind.GlobalStatement);
+ {
+ N(SyntaxKind.LocalFunctionStatement);
+ {
+ 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.LocalDeclarationStatement);
+ {
+ N(SyntaxKind.VariableDeclaration);
+ {
+ N(SyntaxKind.IdentifierName);
+ {
+ N(SyntaxKind.IdentifierToken, "file");
+ }
+ N(SyntaxKind.VariableDeclarator);
+ {
+ N(SyntaxKind.IdentifierToken, "file");
+ }
+ }
+ N(SyntaxKind.SemicolonToken);
+ }
+ N(SyntaxKind.CloseBraceToken);
+ }
+ }
+ }
+ N(SyntaxKind.EndOfFileToken);
+ }
+ EOF();
+ }
+
+ [Fact]
+ public void LocalVariable_02()
+ {
+ UsingNode("""
+ void M()
+ {
+ int file;
+ }
+ """,
+ expectedBindingDiagnostics: new[]
+ {
+ // (1,6): warning CS8321: The local function 'M' is declared but never used
+ // void M()
+ Diagnostic(ErrorCode.WRN_UnreferencedLocalFunction, "M").WithArguments("M").WithLocation(1, 6),
+ // (3,9): warning CS0168: The variable 'file' is declared but never used
+ // int file;
+ Diagnostic(ErrorCode.WRN_UnreferencedVar, "file").WithArguments("file").WithLocation(3, 9)
+ });
+ N(SyntaxKind.CompilationUnit);
+ {
+ N(SyntaxKind.GlobalStatement);
+ {
+ N(SyntaxKind.LocalFunctionStatement);
+ {
+ 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.LocalDeclarationStatement);
+ {
+ N(SyntaxKind.VariableDeclaration);
+ {
+ N(SyntaxKind.PredefinedType);
+ {
+ N(SyntaxKind.IntKeyword);
+ }
+ N(SyntaxKind.VariableDeclarator);
+ {
+ N(SyntaxKind.IdentifierToken, "file");
+ }
+ }
+ N(SyntaxKind.SemicolonToken);
+ }
+ N(SyntaxKind.CloseBraceToken);
+ }
+ }
+ }
+ N(SyntaxKind.EndOfFileToken);
+ }
+ EOF();
+ }
+
+ // PROTOTYPE(ft): confirm whether this breaking change is acceptable
+ [Fact]
+ public void TopLevelVariable_01_CSharp10()
+ {
+ UsingNode("""
+ file file;
+ """,
+ options: TestOptions.Regular10,
+ expectedBindingDiagnostics: new[]
+ {
+ // (1,1): error CS0118: 'file' is a variable but is used like a type
+ // file file;
+ Diagnostic(ErrorCode.ERR_BadSKknown, "file").WithArguments("file", "variable", "type").WithLocation(1, 1),
+ // (1,6): warning CS0168: The variable 'file' is declared but never used
+ // file file;
+ Diagnostic(ErrorCode.WRN_UnreferencedVar, "file").WithArguments("file").WithLocation(1, 6)
+ });
+
+ N(SyntaxKind.CompilationUnit);
+ {
+ N(SyntaxKind.GlobalStatement);
+ {
+ N(SyntaxKind.LocalDeclarationStatement);
+ {
+ N(SyntaxKind.VariableDeclaration);
+ {
+ N(SyntaxKind.IdentifierName);
+ {
+ N(SyntaxKind.IdentifierToken, "file");
+ }
+ N(SyntaxKind.VariableDeclarator);
+ {
+ N(SyntaxKind.IdentifierToken, "file");
+ }
+ }
+ N(SyntaxKind.SemicolonToken);
+ }
+ }
+ N(SyntaxKind.EndOfFileToken);
+ }
+ EOF();
+ }
+
+ [Fact]
+ public void TopLevelVariable_01()
+ {
+ UsingNode("""
+ file file;
+ """,
+ expectedParsingDiagnostics: new[]
+ {
+ // (1,6): error CS0116: A namespace cannot directly contain members such as fields, methods or statements
+ // file file;
+ Diagnostic(ErrorCode.ERR_NamespaceUnexpected, "file").WithLocation(1, 6)
+ },
+ expectedBindingDiagnostics: new[]
+ {
+ // (1,6): error CS0116: A namespace cannot directly contain members such as fields, methods or statements
+ // file file;
+ Diagnostic(ErrorCode.ERR_NamespaceUnexpected, "file").WithLocation(1, 6),
+ // (1,10): error CS8937: At least one top-level statement must be non-empty.
+ // file file;
+ Diagnostic(ErrorCode.ERR_SimpleProgramIsEmpty, ";").WithLocation(1, 10)
+ });
+ N(SyntaxKind.CompilationUnit);
+ {
+ N(SyntaxKind.IncompleteMember);
+ {
+ N(SyntaxKind.FileKeyword);
+ N(SyntaxKind.FileKeyword);
+ }
+ N(SyntaxKind.GlobalStatement);
+ {
+ N(SyntaxKind.EmptyStatement);
+ {
+ N(SyntaxKind.SemicolonToken);
+ }
+ }
+ N(SyntaxKind.EndOfFileToken);
+ }
+ EOF();
+ }
+
+ [Fact]
+ public void TopLevelVariable_02()
+ {
+ UsingNode("""
+ int file;
+ """,
+ expectedBindingDiagnostics: new[]
+ {
+ // (1,5): warning CS0168: The variable 'file' is declared but never used
+ // int file;
+ Diagnostic(ErrorCode.WRN_UnreferencedVar, "file").WithArguments("file").WithLocation(1, 5)
+ });
+ N(SyntaxKind.CompilationUnit);
+ {
+ N(SyntaxKind.GlobalStatement);
+ {
+ N(SyntaxKind.LocalDeclarationStatement);
+ {
+ N(SyntaxKind.VariableDeclaration);
+ {
+ N(SyntaxKind.PredefinedType);
+ {
+ N(SyntaxKind.IntKeyword);
+ }
+ N(SyntaxKind.VariableDeclarator);
+ {
+ N(SyntaxKind.IdentifierToken, "file");
+ }
+ }
+ N(SyntaxKind.SemicolonToken);
+ }
+ }
+ N(SyntaxKind.EndOfFileToken);
+ }
+ EOF();
+ }
+
+ [Fact]
+ public void LambdaReturn()
+ {
+ UsingNode("""
+ _ = file () => { };
+ """,
+ expectedBindingDiagnostics: new[]
+ {
+ // (1,1): error CS8183: Cannot infer the type of implicitly-typed discard.
+ // _ = file () => { };
+ Diagnostic(ErrorCode.ERR_DiscardTypeInferenceFailed, "_").WithLocation(1, 1),
+ // (1,5): error CS0246: The type or namespace name 'file' could not be found (are you missing a using directive or an assembly reference?)
+ // _ = file () => { };
+ Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "file").WithArguments("file").WithLocation(1, 5)
+ });
+ N(SyntaxKind.CompilationUnit);
+ {
+ N(SyntaxKind.GlobalStatement);
+ {
+ N(SyntaxKind.ExpressionStatement);
+ {
+ N(SyntaxKind.SimpleAssignmentExpression);
+ {
+ N(SyntaxKind.IdentifierName);
+ {
+ N(SyntaxKind.IdentifierToken, "_");
+ }
+ N(SyntaxKind.EqualsToken);
+ N(SyntaxKind.ParenthesizedLambdaExpression);
+ {
+ N(SyntaxKind.IdentifierName);
+ {
+ N(SyntaxKind.IdentifierToken, "file");
+ }
+ N(SyntaxKind.ParameterList);
+ {
+ N(SyntaxKind.OpenParenToken);
+ N(SyntaxKind.CloseParenToken);
+ }
+ N(SyntaxKind.EqualsGreaterThanToken);
+ N(SyntaxKind.Block);
+ {
+ N(SyntaxKind.OpenBraceToken);
+ N(SyntaxKind.CloseBraceToken);
+ }
+ }
+ }
+ N(SyntaxKind.SemicolonToken);
+ }
+ }
+ N(SyntaxKind.EndOfFileToken);
+ }
+ EOF();
+ }
+
+ [Fact]
+ public void LocalFunctionReturn()
+ {
+ UsingNode("""
+ file local() { };
+ """,
+ expectedBindingDiagnostics: new[]
+ {
+ // (1,1): error CS0246: The type or namespace name 'file' could not be found (are you missing a using directive or an assembly reference?)
+ // file local() { };
+ Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "file").WithArguments("file").WithLocation(1, 1),
+ // (1,6): error CS0161: 'local()': not all code paths return a value
+ // file local() { };
+ Diagnostic(ErrorCode.ERR_ReturnExpected, "local").WithArguments("local()").WithLocation(1, 6),
+ // (1,6): warning CS8321: The local function 'local' is declared but never used
+ // file local() { };
+ Diagnostic(ErrorCode.WRN_UnreferencedLocalFunction, "local").WithArguments("local").WithLocation(1, 6)
+ });
+ N(SyntaxKind.CompilationUnit);
+ {
+ N(SyntaxKind.GlobalStatement);
+ {
+ N(SyntaxKind.LocalFunctionStatement);
+ {
+ N(SyntaxKind.IdentifierName);
+ {
+ N(SyntaxKind.IdentifierToken, "file");
+ }
+ N(SyntaxKind.IdentifierToken, "local");
+ N(SyntaxKind.ParameterList);
+ {
+ N(SyntaxKind.OpenParenToken);
+ N(SyntaxKind.CloseParenToken);
+ }
+ N(SyntaxKind.Block);
+ {
+ N(SyntaxKind.OpenBraceToken);
+ N(SyntaxKind.CloseBraceToken);
+ }
+ }
+ }
+ N(SyntaxKind.GlobalStatement);
+ {
+ N(SyntaxKind.EmptyStatement);
+ {
+ N(SyntaxKind.SemicolonToken);
+ }
+ }
+ N(SyntaxKind.EndOfFileToken);
+ }
+ EOF();
+ }
+
+ [Fact]
+ public void ParameterModifier()
+ {
+ UsingNode("""
+ class C
+ {
+ void M(file int x) { }
+ }
+ """,
+ expectedParsingDiagnostics: new[]
+ {
+ // (3,17): error CS1001: Identifier expected
+ // void M(file int x) { }
+ Diagnostic(ErrorCode.ERR_IdentifierExpected, "int").WithLocation(3, 17),
+ // (3,17): error CS1003: Syntax error, ',' expected
+ // void M(file int x) { }
+ Diagnostic(ErrorCode.ERR_SyntaxError, "int").WithArguments(",", "int").WithLocation(3, 17)
+ },
+ expectedBindingDiagnostics: new[]
+ {
+ // (3,12): error CS0246: The type or namespace name 'file' could not be found (are you missing a using directive or an assembly reference?)
+ // void M(file int x) { }
+ Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "file").WithArguments("file").WithLocation(3, 12),
+ // (3,17): error CS1001: Identifier expected
+ // void M(file int x) { }
+ Diagnostic(ErrorCode.ERR_IdentifierExpected, "int").WithLocation(3, 17),
+ // (3,17): error CS1003: Syntax error, ',' expected
+ // void M(file int x) { }
+ Diagnostic(ErrorCode.ERR_SyntaxError, "int").WithArguments(",", "int").WithLocation(3, 17)
+ });
+ N(SyntaxKind.CompilationUnit);
+ {
+ N(SyntaxKind.ClassDeclaration);
+ {
+ N(SyntaxKind.ClassKeyword);
+ N(SyntaxKind.IdentifierToken, "C");
+ N(SyntaxKind.OpenBraceToken);
+ N(SyntaxKind.MethodDeclaration);
+ {
+ N(SyntaxKind.PredefinedType);
+ {
+ N(SyntaxKind.VoidKeyword);
+ }
+ N(SyntaxKind.IdentifierToken, "M");
+ N(SyntaxKind.ParameterList);
+ {
+ N(SyntaxKind.OpenParenToken);
+ N(SyntaxKind.Parameter);
+ {
+ N(SyntaxKind.IdentifierName);
+ {
+ N(SyntaxKind.IdentifierToken, "file");
+ }
+ M(SyntaxKind.IdentifierToken);
+ }
+ M(SyntaxKind.CommaToken);
+ N(SyntaxKind.Parameter);
+ {
+ N(SyntaxKind.PredefinedType);
+ {
+ N(SyntaxKind.IntKeyword);
+ }
+ N(SyntaxKind.IdentifierToken, "x");
+ }
+ N(SyntaxKind.CloseParenToken);
+ }
+ N(SyntaxKind.Block);
+ {
+ N(SyntaxKind.OpenBraceToken);
+ N(SyntaxKind.CloseBraceToken);
+ }
+ }
+ N(SyntaxKind.CloseBraceToken);
+ }
+ N(SyntaxKind.EndOfFileToken);
+ }
+ EOF();
+ }
+
+ [Fact]
+ public void ParameterType()
+ {
+ UsingNode("""
+ class C
+ {
+ void M(file x) { }
+ }
+ """,
+ expectedBindingDiagnostics: new[]
+ {
+ // (3,12): error CS0246: The type or namespace name 'file' could not be found (are you missing a using directive or an assembly reference?)
+ // void M(file x) { }
+ Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "file").WithArguments("file").WithLocation(3, 12)
+ });
+ N(SyntaxKind.CompilationUnit);
+ {
+ N(SyntaxKind.ClassDeclaration);
+ {
+ N(SyntaxKind.ClassKeyword);
+ N(SyntaxKind.IdentifierToken, "C");
+ N(SyntaxKind.OpenBraceToken);
+ N(SyntaxKind.MethodDeclaration);
+ {
+ N(SyntaxKind.PredefinedType);
+ {
+ N(SyntaxKind.VoidKeyword);
+ }
+ N(SyntaxKind.IdentifierToken, "M");
+ N(SyntaxKind.ParameterList);
+ {
+ N(SyntaxKind.OpenParenToken);
+ N(SyntaxKind.Parameter);
+ {
+ N(SyntaxKind.IdentifierName);
+ {
+ N(SyntaxKind.IdentifierToken, "file");
+ }
+ N(SyntaxKind.IdentifierToken, "x");
+ }
+ N(SyntaxKind.CloseParenToken);
+ }
+ N(SyntaxKind.Block);
+ {
+ N(SyntaxKind.OpenBraceToken);
+ N(SyntaxKind.CloseBraceToken);
+ }
+ }
+ N(SyntaxKind.CloseBraceToken);
+ }
+ N(SyntaxKind.EndOfFileToken);
+ }
+ EOF();
+ }
+ }
+}