From 4550ac37cdf09387ef09c32ed8d5fc924d2cf0ce Mon Sep 17 00:00:00 2001 From: Rikki Gibson Date: Mon, 9 May 2022 11:03:40 -0700 Subject: [PATCH 01/11] File modifier parsing (#60823) Co-authored-by: CyrusNajmabadi --- eng/config/globalconfigs/Common.globalconfig | 2 +- .../CSharp/Portable/CSharpResources.resx | 3 + .../Declarations/DeclarationModifiers.cs | 8 +- .../CSharp/Portable/Errors/MessageID.cs | 3 + .../Portable/Generated/CSharp.Generated.g4 | 1 + .../CSharp/Portable/Parser/LanguageParser.cs | 70 +- .../Portable/Symbols/Source/ModifierUtils.cs | 9 + .../Source/SourceMemberContainerSymbol.cs | 3 +- .../CSharp/Portable/Syntax/SyntaxKind.cs | 3 + .../CSharp/Portable/Syntax/SyntaxKindFacts.cs | 7 +- .../Portable/xlf/CSharpResources.cs.xlf | 5 + .../Portable/xlf/CSharpResources.de.xlf | 5 + .../Portable/xlf/CSharpResources.es.xlf | 5 + .../Portable/xlf/CSharpResources.fr.xlf | 5 + .../Portable/xlf/CSharpResources.it.xlf | 5 + .../Portable/xlf/CSharpResources.ja.xlf | 5 + .../Portable/xlf/CSharpResources.ko.xlf | 5 + .../Portable/xlf/CSharpResources.pl.xlf | 5 + .../Portable/xlf/CSharpResources.pt-BR.xlf | 5 + .../Portable/xlf/CSharpResources.ru.xlf | 5 + .../Portable/xlf/CSharpResources.tr.xlf | 5 + .../Portable/xlf/CSharpResources.zh-Hans.xlf | 5 + .../Portable/xlf/CSharpResources.zh-Hant.xlf | 5 + .../Symbols/Source/FileModifierTests.cs | 49 + .../Parsing/FileModifierParsingTests.cs | 2680 +++++++++++++++++ 25 files changed, 2868 insertions(+), 35 deletions(-) create mode 100644 src/Compilers/CSharp/Test/Symbol/Symbols/Source/FileModifierTests.cs create mode 100644 src/Compilers/CSharp/Test/Syntax/Parsing/FileModifierParsingTests.cs 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(); + } + } +} From 2226d1a5b27764a9181aa18b0cb0d91f73d51b46 Mon Sep 17 00:00:00 2001 From: Rikki Gibson Date: Sat, 28 May 2022 12:44:43 -0700 Subject: [PATCH 02/11] File types binding (#60977) --- .../CSharp/Portable/Binder/BinderFactory.cs | 2 +- .../Portable/Binder/Binder_Constraints.cs | 6 + .../CSharp/Portable/Binder/Binder_Lookup.cs | 42 +- .../CSharp/Portable/Binder/Binder_Symbols.cs | 23 + .../Portable/Binder/BuckStopsHereBinder.cs | 12 +- .../CSharp/Portable/CSharpResources.resx | 9 + ...ilation.UsingsFromOptionsAndDiagnostics.cs | 4 +- .../Portable/Compilation/CSharpCompilation.cs | 2 +- ...nCommentCompiler.IncludeElementExpander.cs | 6 +- .../Declarations/SingleTypeDeclaration.cs | 8 + .../CSharp/Portable/Errors/ErrorCode.cs | 5 + .../Lowering/SyntheticBoundNodeFactory.cs | 2 +- .../SymbolDisplayVisitor.Types.cs | 14 + .../Source/SourceConstructorSymbolBase.cs | 1 + .../Source/SourceDelegateMethodSymbol.cs | 10 + .../Source/SourceMemberContainerSymbol.cs | 13 +- .../Symbols/Source/SourceMemberFieldSymbol.cs | 6 +- .../Source/SourceMemberMethodSymbol.cs | 21 + .../Source/SourceNamedTypeSymbol_Bases.cs | 10 + .../Symbols/Source/SourceNamespaceSymbol.cs | 32 +- ...dinaryMethodOrUserDefinedOperatorSymbol.cs | 1 + .../Symbols/Source/SourcePropertySymbol.cs | 10 + .../CSharp/Portable/Symbols/Symbol.cs | 2 +- .../SynthesizedEntryPointSymbol.cs | 2 +- ...ynthesizedSimpleProgramEntryPointSymbol.cs | 4 +- .../Portable/Symbols/TypeSymbolExtensions.cs | 6 + .../Portable/xlf/CSharpResources.cs.xlf | 15 + .../Portable/xlf/CSharpResources.de.xlf | 15 + .../Portable/xlf/CSharpResources.es.xlf | 15 + .../Portable/xlf/CSharpResources.fr.xlf | 15 + .../Portable/xlf/CSharpResources.it.xlf | 15 + .../Portable/xlf/CSharpResources.ja.xlf | 15 + .../Portable/xlf/CSharpResources.ko.xlf | 15 + .../Portable/xlf/CSharpResources.pl.xlf | 15 + .../Portable/xlf/CSharpResources.pt-BR.xlf | 15 + .../Portable/xlf/CSharpResources.ru.xlf | 15 + .../Portable/xlf/CSharpResources.tr.xlf | 15 + .../Portable/xlf/CSharpResources.zh-Hans.xlf | 15 + .../Portable/xlf/CSharpResources.zh-Hant.xlf | 15 + .../Test/Symbol/Symbols/ConversionTests.cs | 4 +- .../Symbols/Source/FileModifierTests.cs | 2500 +++++++++- .../Parsing/FileModifierParsingTests.cs | 4275 +++++++++-------- .../SymbolDisplayCompilerInternalOptions.cs | 5 + .../Binders/EEMethodBinder.cs | 3 +- .../ExpressionCompiler/CompilationContext.cs | 3 +- 45 files changed, 5095 insertions(+), 2143 deletions(-) diff --git a/src/Compilers/CSharp/Portable/Binder/BinderFactory.cs b/src/Compilers/CSharp/Portable/Binder/BinderFactory.cs index 7c45b4cd1e836..b9ae6f4c7b29b 100644 --- a/src/Compilers/CSharp/Portable/Binder/BinderFactory.cs +++ b/src/Compilers/CSharp/Portable/Binder/BinderFactory.cs @@ -75,7 +75,7 @@ internal BinderFactory(CSharpCompilation compilation, SyntaxTree syntaxTree, boo // more than 50 items added before getting collected. _binderCache = new ConcurrentCache(50); - _buckStopsHereBinder = new BuckStopsHereBinder(compilation); + _buckStopsHereBinder = new BuckStopsHereBinder(compilation, syntaxTree); } internal SyntaxTree SyntaxTree diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Constraints.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Constraints.cs index 7f81b7826e5bb..a827850296103 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder_Constraints.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder_Constraints.cs @@ -410,6 +410,12 @@ private static void CheckConstraintTypeVisibility( // "Inconsistent accessibility: constraint type '{1}' is less accessible than '{0}'" diagnostics.Add(ErrorCode.ERR_BadVisBound, location, containingSymbol, constraintType.Type); } + + if (constraintType.Type.IsFileTypeOrUsesFileTypes() && !containingSymbol.ContainingType.IsFileTypeOrUsesFileTypes()) + { + diagnostics.Add(ErrorCode.ERR_FileTypeDisallowedInSignature, location, constraintType.Type, containingSymbol); + } + diagnostics.Add(location, useSiteInfo); } diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Lookup.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Lookup.cs index 53f907f187284..db6c114fa795f 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder_Lookup.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder_Lookup.cs @@ -1306,6 +1306,38 @@ internal static ImmutableArray GetCandidateMembers(NamespaceOrTypeSymbol } } + private bool IsInScopeOfAssociatedSyntaxTree(Symbol symbol) + { + while (symbol is not null and not SourceMemberContainerTypeSymbol { IsFile: true }) + { + symbol = symbol.ContainingType; + } + + if (symbol is null) + { + // the passed-in symbol was not contained in a file type. + return true; + } + + var tree = getSyntaxTreeForFileTypes(); + return symbol.IsDefinedInSourceTree(tree, definedWithinSpan: null); + + SyntaxTree getSyntaxTreeForFileTypes() + { + for (var binder = this; binder != null; binder = binder.Next) + { + if (binder is BuckStopsHereBinder lastBinder) + { + Debug.Assert(lastBinder.AssociatedSyntaxTree is not null); + return lastBinder.AssociatedSyntaxTree; + } + } + + Debug.Assert(false); + return null; + } + } + /// /// Distinguish from , which performs an analogous task for Add*LookupSymbolsInfo*. /// @@ -1322,8 +1354,12 @@ internal SingleLookupResult CheckViability(Symbol symbol, int arity, LookupOptio ? ((AliasSymbol)symbol).GetAliasTarget(basesBeingResolved) : symbol; + if (!IsInScopeOfAssociatedSyntaxTree(unwrappedSymbol)) + { + return LookupResult.Empty(); + } // Check for symbols marked with 'Microsoft.CodeAnalysis.Embedded' attribute - if (!this.Compilation.SourceModule.Equals(unwrappedSymbol.ContainingModule) && unwrappedSymbol.IsHiddenByCodeAnalysisEmbeddedAttribute()) + else if (!this.Compilation.SourceModule.Equals(unwrappedSymbol.ContainingModule) && unwrappedSymbol.IsHiddenByCodeAnalysisEmbeddedAttribute()) { return LookupResult.Empty(); } @@ -1522,6 +1558,10 @@ internal bool CanAddLookupSymbolInfo(Symbol symbol, LookupOptions options, Looku { return false; } + else if (!IsInScopeOfAssociatedSyntaxTree(symbol)) + { + return false; + } else if ((options & LookupOptions.MustBeInstance) != 0 && !IsInstance(symbol)) { return false; diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Symbols.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Symbols.cs index edca92213b32e..a4b93eebab50c 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder_Symbols.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder_Symbols.cs @@ -1816,6 +1816,15 @@ Symbol resultSymbol( Debug.Assert(!Symbol.Equals(first, second, TypeCompareKind.ConsiderEverything) || !Symbol.Equals(originalSymbols[best.Index], originalSymbols[secondBest.Index], TypeCompareKind.ConsiderEverything), "Why does the LookupResult contain the same symbol twice?"); + if (best.IsFromFile && !secondBest.IsFromFile) + { + // a lookup of a file type is "better" than a lookup of a non-file type; no need to further diagnose + // PROTOTYPE(ft): some "single symbol" diagnostics are missed here for similar reasons + // that make us miss diagnostics when reporting WRN_SameFullNameThisAggAgg. + // + return first; + } + CSDiagnosticInfo info; bool reportError; @@ -2133,6 +2142,7 @@ private static AssemblySymbol GetContainingAssembly(Symbol symbol) private enum BestSymbolLocation { None, + FromFile, FromSourceModule, FromAddedModule, FromReferencedAssembly, @@ -2180,6 +2190,14 @@ public bool IsFromCompilation } } + public bool IsFromFile + { + get + { + return _location == BestSymbolLocation.FromFile; + } + } + public bool IsNone { get @@ -2281,6 +2299,11 @@ private BestSymbolInfo GetBestSymbolInfo(ArrayBuilder symbols, out BestS private static BestSymbolLocation GetLocation(CSharpCompilation compilation, Symbol symbol) { + if (symbol is SourceMemberContainerTypeSymbol { IsFile: true }) + { + return BestSymbolLocation.FromFile; + } + var containingAssembly = symbol.ContainingAssembly; if (containingAssembly == compilation.SourceAssembly) { diff --git a/src/Compilers/CSharp/Portable/Binder/BuckStopsHereBinder.cs b/src/Compilers/CSharp/Portable/Binder/BuckStopsHereBinder.cs index 9c3a274d28542..90d184f2eed49 100644 --- a/src/Compilers/CSharp/Portable/Binder/BuckStopsHereBinder.cs +++ b/src/Compilers/CSharp/Portable/Binder/BuckStopsHereBinder.cs @@ -15,11 +15,21 @@ namespace Microsoft.CodeAnalysis.CSharp /// internal class BuckStopsHereBinder : Binder { - internal BuckStopsHereBinder(CSharpCompilation compilation) + internal BuckStopsHereBinder(CSharpCompilation compilation, SyntaxTree? associatedSyntaxTree) : base(compilation) { + this.AssociatedSyntaxTree = associatedSyntaxTree; } + /// + /// In non-speculative scenarios, the syntax tree being bound. + /// In speculative scenarios, the syntax tree from the original compilation used as the speculation context. + /// This is in some scenarios, such as the binder used for + /// or the binder used to bind usings in . + /// PROTOTYPE(ft): what about in EE scenarios? + /// + internal readonly SyntaxTree? AssociatedSyntaxTree; + internal override ImportChain? ImportChain { get diff --git a/src/Compilers/CSharp/Portable/CSharpResources.resx b/src/Compilers/CSharp/Portable/CSharpResources.resx index c779781950f88..649bc0e0876f6 100644 --- a/src/Compilers/CSharp/Portable/CSharpResources.resx +++ b/src/Compilers/CSharp/Portable/CSharpResources.resx @@ -7088,6 +7088,15 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ An expression tree may not contain UTF8 string conversion or literal. + + File type '{0}' cannot be used in a member signature in non-file type '{1}'. + + + File type '{0}' cannot use accessibility modifiers. + + + File type '{0}' cannot be used as a base type of non-file type '{1}'. + unsigned right shift diff --git a/src/Compilers/CSharp/Portable/Compilation/CSharpCompilation.UsingsFromOptionsAndDiagnostics.cs b/src/Compilers/CSharp/Portable/Compilation/CSharpCompilation.UsingsFromOptionsAndDiagnostics.cs index 2848b30694105..6068c3d3b99ca 100644 --- a/src/Compilers/CSharp/Portable/Compilation/CSharpCompilation.UsingsFromOptionsAndDiagnostics.cs +++ b/src/Compilers/CSharp/Portable/Compilation/CSharpCompilation.UsingsFromOptionsAndDiagnostics.cs @@ -34,7 +34,9 @@ public static UsingsFromOptionsAndDiagnostics FromOptions(CSharpCompilation comp } var diagnostics = new DiagnosticBag(); - var usingsBinder = new InContainerBinder(compilation.GlobalNamespace, new BuckStopsHereBinder(compilation)); + // PROTOTYPE(ft): should usings from compilation options be allowed to bring file types into scope? + // it doesn't seem to work for non-file types within the compilaton, so can probably do the same for file types. + var usingsBinder = new InContainerBinder(compilation.GlobalNamespace, new BuckStopsHereBinder(compilation, associatedSyntaxTree: null)); var boundUsings = ArrayBuilder.GetInstance(); var uniqueUsings = PooledHashSet.GetInstance(); diff --git a/src/Compilers/CSharp/Portable/Compilation/CSharpCompilation.cs b/src/Compilers/CSharp/Portable/Compilation/CSharpCompilation.cs index 295490a45d495..63292bd043ae3 100644 --- a/src/Compilers/CSharp/Portable/Compilation/CSharpCompilation.cs +++ b/src/Compilers/CSharp/Portable/Compilation/CSharpCompilation.cs @@ -82,7 +82,7 @@ internal Conversions Conversions { if (_conversions == null) { - Interlocked.CompareExchange(ref _conversions, new BuckStopsHereBinder(this).Conversions, null); + Interlocked.CompareExchange(ref _conversions, new BuckStopsHereBinder(this, associatedSyntaxTree: null).Conversions, null); } return _conversions; diff --git a/src/Compilers/CSharp/Portable/Compiler/DocumentationCommentCompiler.IncludeElementExpander.cs b/src/Compilers/CSharp/Portable/Compiler/DocumentationCommentCompiler.IncludeElementExpander.cs index ad5544fa88802..ca66c4ca60479 100644 --- a/src/Compilers/CSharp/Portable/Compiler/DocumentationCommentCompiler.IncludeElementExpander.cs +++ b/src/Compilers/CSharp/Portable/Compiler/DocumentationCommentCompiler.IncludeElementExpander.cs @@ -536,7 +536,7 @@ private void BindName(XAttribute attribute, CSharpSyntaxNode originatingSyntax, "Why are we processing a documentation comment that is not attached to a member declaration?"); var nameDiagnostics = BindingDiagnosticBag.GetInstance(_diagnostics); - Binder binder = MakeNameBinder(isParameter, isTypeParameterRef, _memberSymbol, _compilation); + Binder binder = MakeNameBinder(isParameter, isTypeParameterRef, _memberSymbol, _compilation, originatingSyntax.SyntaxTree); DocumentationCommentCompiler.BindName(attrSyntax, binder, _memberSymbol, ref _documentedParameters, ref _documentedTypeParameters, nameDiagnostics); RecordBindingDiagnostics(nameDiagnostics, sourceLocation); // Respects DocumentationMode. nameDiagnostics.Free(); @@ -545,9 +545,9 @@ private void BindName(XAttribute attribute, CSharpSyntaxNode originatingSyntax, // NOTE: We're not sharing code with the BinderFactory visitor, because we already have the // member symbol in hand, which makes things much easier. - private static Binder MakeNameBinder(bool isParameter, bool isTypeParameterRef, Symbol memberSymbol, CSharpCompilation compilation) + private static Binder MakeNameBinder(bool isParameter, bool isTypeParameterRef, Symbol memberSymbol, CSharpCompilation compilation, SyntaxTree syntaxTree) { - Binder binder = new BuckStopsHereBinder(compilation); + Binder binder = new BuckStopsHereBinder(compilation, syntaxTree); // All binders should have a containing symbol. Symbol containingSymbol = memberSymbol.ContainingSymbol; diff --git a/src/Compilers/CSharp/Portable/Declarations/SingleTypeDeclaration.cs b/src/Compilers/CSharp/Portable/Declarations/SingleTypeDeclaration.cs index 3c2a209adf7e8..10f6c25f29561 100644 --- a/src/Compilers/CSharp/Portable/Declarations/SingleTypeDeclaration.cs +++ b/src/Compilers/CSharp/Portable/Declarations/SingleTypeDeclaration.cs @@ -237,6 +237,14 @@ public bool Equals(TypeDeclarationIdentity other) return false; } + if ((object)thisDecl.Location.SourceTree != otherDecl.Location.SourceTree + && ((thisDecl.Modifiers & DeclarationModifiers.File) != 0 + || (otherDecl.Modifiers & DeclarationModifiers.File) != 0)) + { + // declarations of 'file' types are only the same type if they are in the same file + return false; + } + if (thisDecl._kind == DeclarationKind.Enum || thisDecl._kind == DeclarationKind.Delegate) { // oh, so close, but enums and delegates cannot be partial diff --git a/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs b/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs index d4971c7e8663e..a4603aa3a14db 100644 --- a/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs +++ b/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs @@ -2069,6 +2069,11 @@ internal enum ErrorCode ERR_CannotBeConvertedToUTF8 = 9026, ERR_ExpressionTreeContainsUTF8StringLiterals = 9027, + // PROTOTYPE(ft): compress these before feature merge + ERR_FileTypeDisallowedInSignature = 9300, + ERR_FileTypeNoExplicitAccessibility = 9301, + ERR_FileTypeBase = 9302, + #endregion // Note: you will need to re-generate compiler code after adding warnings (eng\generate-compiler-code.cmd) diff --git a/src/Compilers/CSharp/Portable/Lowering/SyntheticBoundNodeFactory.cs b/src/Compilers/CSharp/Portable/Lowering/SyntheticBoundNodeFactory.cs index 0bb67f8d7d8e7..285d4e3743a71 100644 --- a/src/Compilers/CSharp/Portable/Lowering/SyntheticBoundNodeFactory.cs +++ b/src/Compilers/CSharp/Portable/Lowering/SyntheticBoundNodeFactory.cs @@ -125,7 +125,7 @@ internal BoundExpression MakeInvocationExpression( private sealed class SyntheticBinderImpl : BuckStopsHereBinder { private readonly SyntheticBoundNodeFactory _factory; - internal SyntheticBinderImpl(SyntheticBoundNodeFactory factory) : base(factory.Compilation) + internal SyntheticBinderImpl(SyntheticBoundNodeFactory factory) : base(factory.Compilation, associatedSyntaxTree: null) { _factory = factory; } diff --git a/src/Compilers/CSharp/Portable/SymbolDisplay/SymbolDisplayVisitor.Types.cs b/src/Compilers/CSharp/Portable/SymbolDisplay/SymbolDisplayVisitor.Types.cs index a216deaffc65d..ede5009aff567 100644 --- a/src/Compilers/CSharp/Portable/SymbolDisplay/SymbolDisplayVisitor.Types.cs +++ b/src/Compilers/CSharp/Portable/SymbolDisplay/SymbolDisplayVisitor.Types.cs @@ -6,6 +6,7 @@ using System.Collections.Immutable; using System.Diagnostics; +using System.IO; using System.Linq; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp.Symbols; @@ -179,6 +180,19 @@ public override void VisitNamedType(INamedTypeSymbol symbol) { VisitNamedTypeWithoutNullability(symbol); AddNullableAnnotations(symbol); + + if ((format.CompilerInternalOptions & SymbolDisplayCompilerInternalOptions.IncludeContainingFileForFileTypes) != 0 + // PROTOTYPE(ft): public API? + && symbol.GetSymbol() is SourceMemberContainerTypeSymbol { IsFile: true } fileType) + { + var tree = symbol.DeclaringSyntaxReferences[0].SyntaxTree; + var fileDescription = tree.FilePath is { Length: not 0 } path + ? Path.GetFileNameWithoutExtension(path) + : $""; + + builder.Add(CreatePart(SymbolDisplayPartKind.Punctuation, symbol, "@")); + builder.Add(CreatePart(SymbolDisplayPartKind.ModuleName, symbol, fileDescription)); + } } private void VisitNamedTypeWithoutNullability(INamedTypeSymbol symbol) diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceConstructorSymbolBase.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceConstructorSymbolBase.cs index 1c35bb314b9a9..72f826be5c2a1 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceConstructorSymbolBase.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceConstructorSymbolBase.cs @@ -71,6 +71,7 @@ protected sealed override void MethodChecks(BindingDiagnosticBag diagnostics) } this.CheckEffectiveAccessibility(_lazyReturnType, _lazyParameters, diagnostics); + this.CheckFileTypeUsage(_lazyReturnType, _lazyParameters, diagnostics); if (_lazyIsVararg && (IsGenericMethod || ContainingType.IsGenericType || _lazyParameters.Length > 0 && _lazyParameters[_lazyParameters.Length - 1].IsParams)) { diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceDelegateMethodSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceDelegateMethodSymbol.cs index 242ee106c736b..38f1b1e635f74 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceDelegateMethodSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceDelegateMethodSymbol.cs @@ -98,6 +98,12 @@ internal static void AddDelegateMembers( diagnostics.Add(ErrorCode.ERR_BadVisDelegateReturn, delegateType.Locations[0], delegateType, invoke.ReturnType); } + var delegateTypeIsFile = delegateType.IsFileTypeOrUsesFileTypes(); + if (!delegateTypeIsFile && invoke.ReturnType.IsFileTypeOrUsesFileTypes()) + { + diagnostics.Add(ErrorCode.ERR_FileTypeDisallowedInSignature, delegateType.Locations[0], invoke.ReturnType, delegateType); + } + for (int i = 0; i < invoke.Parameters.Length; i++) { var parameterSymbol = invoke.Parameters[i]; @@ -106,6 +112,10 @@ internal static void AddDelegateMembers( // Inconsistent accessibility: parameter type '{1}' is less accessible than delegate '{0}' diagnostics.Add(ErrorCode.ERR_BadVisDelegateParam, delegateType.Locations[0], delegateType, parameterSymbol.Type); } + else if (!delegateTypeIsFile && parameterSymbol.Type.IsFileTypeOrUsesFileTypes()) + { + diagnostics.Add(ErrorCode.ERR_FileTypeDisallowedInSignature, delegateType.Locations[0], parameterSymbol.Type, delegateType); + } var parameterSyntax = syntax.ParameterList.Parameters[i]; if (parameterSyntax.ExclamationExclamationToken.Kind() == SyntaxKind.ExclamationExclamationToken) { diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberContainerSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberContainerSymbol.cs index 062255f17974c..a6f74381d0828 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberContainerSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberContainerSymbol.cs @@ -394,6 +394,10 @@ private DeclarationModifiers MakeAndCheckTypeModifiers( { result |= defaultAccess; } + else if ((result & DeclarationModifiers.File) != 0) + { + diagnostics.Add(ErrorCode.ERR_FileTypeNoExplicitAccessibility, Locations[0], this); + } if (missingPartial) { @@ -776,6 +780,11 @@ internal override ManagedKind GetManagedKind(ref CompoundUseSiteInfo HasFlag(DeclarationModifiers.New); + internal bool IsFile => HasFlag(DeclarationModifiers.File); + + /// If this symbol is only available within a single syntax tree, returns that syntax tree. Otherwise, returns null. + internal SyntaxTree? AssociatedSyntaxTree => IsFile ? declaration.Declarations[0].Location.SourceTree : null; + [MethodImpl(MethodImplOptions.AggressiveInlining)] private bool HasFlag(DeclarationModifiers flag) => (_declModifiers & flag) != 0; @@ -1219,7 +1228,7 @@ private Dictionary> GetTypeMembersDictio private Dictionary> MakeTypeMembers(BindingDiagnosticBag diagnostics) { var symbols = ArrayBuilder.GetInstance(); - var conflictDict = new Dictionary<(string, int), SourceNamedTypeSymbol>(); + var conflictDict = new Dictionary<(string name, int arity, SyntaxTree? syntaxTree), SourceNamedTypeSymbol>(); try { foreach (var childDeclaration in declaration.Children) @@ -1227,7 +1236,7 @@ private Dictionary> MakeTypeMembers(Bind var t = new SourceNamedTypeSymbol(this, childDeclaration, diagnostics); this.CheckMemberNameDistinctFromType(t, diagnostics); - var key = (t.Name, t.Arity); + var key = (t.Name, t.Arity, t.AssociatedSyntaxTree); SourceNamedTypeSymbol? other; if (conflictDict.TryGetValue(key, out other)) { diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberFieldSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberFieldSymbol.cs index b2b6cdf5584d1..2554ea27e2545 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberFieldSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberFieldSymbol.cs @@ -46,7 +46,11 @@ protected sealed override DeclarationModifiers Modifiers protected void TypeChecks(TypeSymbol type, BindingDiagnosticBag diagnostics) { - if (type.IsStatic) + if (type.IsFileTypeOrUsesFileTypes() && !ContainingType.IsFileTypeOrUsesFileTypes()) + { + diagnostics.Add(ErrorCode.ERR_FileTypeDisallowedInSignature, this.ErrorLocation, type, ContainingType); + } + else if (type.IsStatic) { // Cannot declare a variable of static type '{0}' diagnostics.Add(ErrorCode.ERR_VarDeclIsStaticClass, this.ErrorLocation, type); diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberMethodSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberMethodSymbol.cs index 4ad4c4430738b..c191ad81c931e 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberMethodSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberMethodSymbol.cs @@ -276,6 +276,27 @@ protected void CheckEffectiveAccessibility(TypeWithAnnotations returnType, Immut diagnostics.Add(Locations[0], useSiteInfo); } + protected void CheckFileTypeUsage(TypeWithAnnotations returnType, ImmutableArray parameters, BindingDiagnosticBag diagnostics) + { + if (ContainingType.IsFileTypeOrUsesFileTypes()) + { + return; + } + + if (returnType.Type.IsFileTypeOrUsesFileTypes()) + { + diagnostics.Add(ErrorCode.ERR_FileTypeDisallowedInSignature, Locations[0], returnType.Type, ContainingType); + } + + foreach (var param in parameters) + { + if (param.Type.IsFileTypeOrUsesFileTypes()) + { + diagnostics.Add(ErrorCode.ERR_FileTypeDisallowedInSignature, Locations[0], param.Type, ContainingType); + } + } + } + protected void MakeFlags( MethodKind methodKind, DeclarationModifiers declarationModifiers, diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceNamedTypeSymbol_Bases.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceNamedTypeSymbol_Bases.cs index 77a181093c2fc..eef38635a02d3 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceNamedTypeSymbol_Bases.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceNamedTypeSymbol_Bases.cs @@ -384,6 +384,11 @@ static bool containsOnlyOblivious(TypeSymbol type) // Inconsistent accessibility: base class '{1}' is less accessible than class '{0}' diagnostics.Add(ErrorCode.ERR_BadVisBaseClass, baseTypeLocation, this, baseType); } + + if (baseType.IsFileTypeOrUsesFileTypes() && !this.IsFileTypeOrUsesFileTypes()) + { + diagnostics.Add(ErrorCode.ERR_FileTypeBase, baseTypeLocation, baseType, this); + } } var baseInterfacesRO = baseInterfaces.ToImmutableAndFree(); @@ -396,6 +401,11 @@ static bool containsOnlyOblivious(TypeSymbol type) // Inconsistent accessibility: base interface '{1}' is less accessible than interface '{0}' diagnostics.Add(ErrorCode.ERR_BadVisBaseInterface, interfaceLocations[i], this, i); } + + if (i.IsFileTypeOrUsesFileTypes() && !this.IsFileTypeOrUsesFileTypes()) + { + diagnostics.Add(ErrorCode.ERR_FileTypeBase, interfaceLocations[i], i, this); + } } } diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceNamespaceSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceNamespaceSymbol.cs index a1b1c4e391b10..5bba097c91837 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceNamespaceSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceNamespaceSymbol.cs @@ -372,13 +372,17 @@ private static void CheckMembers(NamespaceSymbol @namespace, Dictionary (object)loc.SourceTree == leftTree, leftTree)) + { + return false; + } + + return true; + } } private NamespaceOrTypeSymbol BuildSymbol(MergedNamespaceOrTypeDeclaration declaration, BindingDiagnosticBag diagnostics) diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceOrdinaryMethodOrUserDefinedOperatorSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceOrdinaryMethodOrUserDefinedOperatorSymbol.cs index 1d3ba796909c0..b96816fa643c4 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceOrdinaryMethodOrUserDefinedOperatorSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceOrdinaryMethodOrUserDefinedOperatorSymbol.cs @@ -46,6 +46,7 @@ public sealed override bool ReturnsVoid this.SetReturnsVoid(_lazyReturnType.IsVoidType()); this.CheckEffectiveAccessibility(_lazyReturnType, _lazyParameters, diagnostics); + this.CheckFileTypeUsage(_lazyReturnType, _lazyParameters, diagnostics); var location = locations[0]; // Checks taken from MemberDefiner::defineMethod diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertySymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertySymbol.cs index f71c881683cec..0d26092df1ddd 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertySymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertySymbol.cs @@ -438,6 +438,12 @@ private TypeWithAnnotations ComputeType(Binder binder, SyntaxNode syntax, Bindin diagnostics.Add((this.IsIndexer ? ErrorCode.ERR_BadVisIndexerReturn : ErrorCode.ERR_BadVisPropertyType), Location, this, type.Type); } + if (type.Type.IsFileTypeOrUsesFileTypes() && !ContainingType.IsFileTypeOrUsesFileTypes()) + { + // PROTOTYPE(ft): should explicit interface implementations be allowed to use file types in signatures? + diagnostics.Add(ErrorCode.ERR_FileTypeDisallowedInSignature, Location, type.Type, ContainingType); + } + diagnostics.Add(Location, useSiteInfo); if (type.IsVoidType()) @@ -509,6 +515,10 @@ internal override void AfterAddingTypeMembersChecks(ConversionsBase conversions, { diagnostics.Add(ErrorCode.ERR_BadVisIndexerParam, Location, this, param.Type); } + else if (param.Type.IsFileTypeOrUsesFileTypes() && !this.ContainingType.IsFileTypeOrUsesFileTypes()) + { + diagnostics.Add(ErrorCode.ERR_FileTypeDisallowedInSignature, Location, param.Type, this.ContainingType); + } else if (SetMethod is object && param.Name == ParameterSymbol.ValueParameterName) { diagnostics.Add(ErrorCode.ERR_DuplicateGeneratedName, param.Locations.FirstOrDefault() ?? Location, param.Name); diff --git a/src/Compilers/CSharp/Portable/Symbols/Symbol.cs b/src/Compilers/CSharp/Portable/Symbols/Symbol.cs index 4e92167e21cfc..b39e4f73899f3 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Symbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Symbol.cs @@ -873,7 +873,7 @@ public virtual string GetDocumentationCommentXml( SymbolDisplayFormat.TestFormat .AddMiscellaneousOptions(SymbolDisplayMiscellaneousOptions.IncludeNullableReferenceTypeModifier | SymbolDisplayMiscellaneousOptions.IncludeNotNullableReferenceTypeModifier) - .WithCompilerInternalOptions(SymbolDisplayCompilerInternalOptions.None); + .WithCompilerInternalOptions(SymbolDisplayCompilerInternalOptions.IncludeContainingFileForFileTypes); internal virtual string GetDebuggerDisplay() { diff --git a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedEntryPointSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedEntryPointSymbol.cs index 4ec47baf02f08..953f0921d00b8 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedEntryPointSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedEntryPointSymbol.cs @@ -451,7 +451,7 @@ internal override BoundBlock CreateBody(BindingDiagnosticBag diagnostics) // Creates a new top-level binder that just contains the global imports for the compilation. // The imports are required if a consumer of the scripting API is using a Task implementation // that uses extension methods. - Binder binder = WithUsingNamespacesAndTypesBinder.Create(compilation.GlobalImports, next: new BuckStopsHereBinder(compilation), withImportChainEntry: true); + Binder binder = WithUsingNamespacesAndTypesBinder.Create(compilation.GlobalImports, next: new BuckStopsHereBinder(compilation, null), withImportChainEntry: true); binder = new InContainerBinder(compilation.GlobalNamespace, binder); var ctor = _containingType.GetScriptConstructor(); diff --git a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedSimpleProgramEntryPointSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedSimpleProgramEntryPointSymbol.cs index 1dda4db66ed28..50b6d3fc9634c 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedSimpleProgramEntryPointSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedSimpleProgramEntryPointSymbol.cs @@ -219,10 +219,10 @@ private ExecutableCodeBinder CreateBodyBinder(bool ignoreAccessibility) { CSharpCompilation compilation = DeclaringCompilation; - Binder result = new BuckStopsHereBinder(compilation); + var syntaxNode = SyntaxNode; + Binder result = new BuckStopsHereBinder(compilation, syntaxNode.SyntaxTree); var globalNamespace = compilation.GlobalNamespace; var declaringSymbol = (SourceNamespaceSymbol)compilation.SourceModule.GlobalNamespace; - var syntaxNode = SyntaxNode; result = WithExternAndUsingAliasesBinder.Create(declaringSymbol, syntaxNode, WithUsingNamespacesAndTypesBinder.Create(declaringSymbol, syntaxNode, result)); result = new InContainerBinder(globalNamespace, result); result = new InContainerBinder(ContainingType, result); diff --git a/src/Compilers/CSharp/Portable/Symbols/TypeSymbolExtensions.cs b/src/Compilers/CSharp/Portable/Symbols/TypeSymbolExtensions.cs index ccfe057817121..8da70c2692b45 100644 --- a/src/Compilers/CSharp/Portable/Symbols/TypeSymbolExtensions.cs +++ b/src/Compilers/CSharp/Portable/Symbols/TypeSymbolExtensions.cs @@ -1355,6 +1355,12 @@ public static bool IsPartial(this TypeSymbol type) return type is SourceNamedTypeSymbol { IsPartial: true }; } + public static bool IsFileTypeOrUsesFileTypes(this TypeSymbol type) + { + var foundType = type.VisitType(predicate: (type, _, _) => type is SourceMemberContainerTypeSymbol { IsFile: true }, arg: (object?)null); + return foundType is not null; + } + public static bool IsPointerType(this TypeSymbol type) { return type is PointerTypeSymbol; diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf index b92a529983355..977583d07ff89 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf @@ -562,6 +562,21 @@ Obor názvů pro celý soubor musí předcházet všem ostatním členům v souboru. + + File type '{0}' cannot be used as a base type of non-file type '{1}'. + File type '{0}' cannot be used as a base type of non-file type '{1}'. + + + + File type '{0}' cannot be used in a member signature in non-file type '{1}'. + File type '{0}' cannot be used in a member signature in non-file type '{1}'. + + + + File type '{0}' cannot use accessibility modifiers. + File type '{0}' cannot use accessibility modifiers. + + foreach statement cannot operate on variables of type '{0}' because '{0}' does not contain a public instance or extension definition for '{1}'. Did you mean 'await foreach' rather than 'foreach'? Příkaz foreach nejde použít pro proměnné typu {0}, protože {0} neobsahuje veřejnou definici instance nebo rozšíření pro {1}. Měli jste v úmyslu await foreach místo foreach? diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf index d810eb2b31e83..aca7c0c078ce6 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf @@ -562,6 +562,21 @@ Der Dateibereichsnamespace muss allen anderen Elementen in einer Datei vorangestellt sein. + + File type '{0}' cannot be used as a base type of non-file type '{1}'. + File type '{0}' cannot be used as a base type of non-file type '{1}'. + + + + File type '{0}' cannot be used in a member signature in non-file type '{1}'. + File type '{0}' cannot be used in a member signature in non-file type '{1}'. + + + + File type '{0}' cannot use accessibility modifiers. + File type '{0}' cannot use accessibility modifiers. + + foreach statement cannot operate on variables of type '{0}' because '{0}' does not contain a public instance or extension definition for '{1}'. Did you mean 'await foreach' rather than 'foreach'? Eine foreach-Anweisung kann nicht für Variablen vom Typ "{0}" verwendet werden, weil "{0}" keine öffentliche Instanz- oder Erweiterungsdefinition für "{1}" enthält. Meinten Sie "await foreach" statt "foreach"? diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf index f0cbc782552ab..f42d79adb2634 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf @@ -562,6 +562,21 @@ El espacio de nombres con ámbito de archivo debe preceder a todos los demás miembros de un archivo. + + File type '{0}' cannot be used as a base type of non-file type '{1}'. + File type '{0}' cannot be used as a base type of non-file type '{1}'. + + + + File type '{0}' cannot be used in a member signature in non-file type '{1}'. + File type '{0}' cannot be used in a member signature in non-file type '{1}'. + + + + File type '{0}' cannot use accessibility modifiers. + File type '{0}' cannot use accessibility modifiers. + + foreach statement cannot operate on variables of type '{0}' because '{0}' does not contain a public instance or extension definition for '{1}'. Did you mean 'await foreach' rather than 'foreach'? La instrucción foreach no puede funcionar en variables de tipo "{0}" porque "{0}" no contiene ninguna definición de extensión o instancia pública para "{1}". ¿Quiso decir “await foreach” en lugar de “foreach”? diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf index 386b55de2416a..8d4cf3223b65e 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf @@ -562,6 +562,21 @@ Un espace de noms de portée de fichier doit précéder tous les autres membres d’un fichier. + + File type '{0}' cannot be used as a base type of non-file type '{1}'. + File type '{0}' cannot be used as a base type of non-file type '{1}'. + + + + File type '{0}' cannot be used in a member signature in non-file type '{1}'. + File type '{0}' cannot be used in a member signature in non-file type '{1}'. + + + + File type '{0}' cannot use accessibility modifiers. + File type '{0}' cannot use accessibility modifiers. + + foreach statement cannot operate on variables of type '{0}' because '{0}' does not contain a public instance or extension definition for '{1}'. Did you mean 'await foreach' rather than 'foreach'? L'instruction foreach ne peut pas fonctionner sur des variables de type '{0}', car '{0}' ne contient pas de définition d'extension ou d'instance publique pour '{1}'. Vouliez-vous dire 'await foreach' plutôt que 'foreach' ? diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf index 30d4680434080..6816df3a581b0 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf @@ -562,6 +562,21 @@ Lo spazio dei nomi con ambito file deve precedere tutti gli altri membri di un file. + + File type '{0}' cannot be used as a base type of non-file type '{1}'. + File type '{0}' cannot be used as a base type of non-file type '{1}'. + + + + File type '{0}' cannot be used in a member signature in non-file type '{1}'. + File type '{0}' cannot be used in a member signature in non-file type '{1}'. + + + + File type '{0}' cannot use accessibility modifiers. + File type '{0}' cannot use accessibility modifiers. + + foreach statement cannot operate on variables of type '{0}' because '{0}' does not contain a public instance or extension definition for '{1}'. Did you mean 'await foreach' rather than 'foreach'? L'istruzione foreach non può funzionare con variabili di tipo '{0}' perché '{0}' non contiene una definizione di istanza o estensione pubblica per '{1}'. Si intendeva 'await foreach' invece di 'foreach'? diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf index e5caa8f74442b..d65a787d12822 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf @@ -562,6 +562,21 @@ ファイルスコープの名前空間は、ファイル内の他のすべてのメンバーの前に指定する必要があります。 + + File type '{0}' cannot be used as a base type of non-file type '{1}'. + File type '{0}' cannot be used as a base type of non-file type '{1}'. + + + + File type '{0}' cannot be used in a member signature in non-file type '{1}'. + File type '{0}' cannot be used in a member signature in non-file type '{1}'. + + + + File type '{0}' cannot use accessibility modifiers. + File type '{0}' cannot use accessibility modifiers. + + foreach statement cannot operate on variables of type '{0}' because '{0}' does not contain a public instance or extension definition for '{1}'. Did you mean 'await foreach' rather than 'foreach'? '{0}' は '{1}' のパブリック インスタンスまたは拡張機能の定義を含んでいないため、型 '{0}' の変数に対して foreach ステートメントを使用することはできません。'foreach' ではなく 'await foreach' ですか? diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf index 3cae36e463245..feedd419e9400 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf @@ -562,6 +562,21 @@ 파일 범위 네임스페이스는 파일의 다른 모든 멤버보다 앞에 와야 합니다. + + File type '{0}' cannot be used as a base type of non-file type '{1}'. + File type '{0}' cannot be used as a base type of non-file type '{1}'. + + + + File type '{0}' cannot be used in a member signature in non-file type '{1}'. + File type '{0}' cannot be used in a member signature in non-file type '{1}'. + + + + File type '{0}' cannot use accessibility modifiers. + File type '{0}' cannot use accessibility modifiers. + + foreach statement cannot operate on variables of type '{0}' because '{0}' does not contain a public instance or extension definition for '{1}'. Did you mean 'await foreach' rather than 'foreach'? '{0}' 형식 변수에서 foreach 문을 수행할 수 없습니다. '{0}'에는 '{1}'의 공개 인스턴스 또는 확장 정의가 없기 때문입니다. 'foreach' 대신 'await foreach'를 사용하시겠습니까? diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf index 2146a592c67a3..9c12edcac4154 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf @@ -562,6 +562,21 @@ Przestrzeń nazw z określonym zakresem plików musi poprzedzać wszystkie inne składowe w pliku. + + File type '{0}' cannot be used as a base type of non-file type '{1}'. + File type '{0}' cannot be used as a base type of non-file type '{1}'. + + + + File type '{0}' cannot be used in a member signature in non-file type '{1}'. + File type '{0}' cannot be used in a member signature in non-file type '{1}'. + + + + File type '{0}' cannot use accessibility modifiers. + File type '{0}' cannot use accessibility modifiers. + + foreach statement cannot operate on variables of type '{0}' because '{0}' does not contain a public instance or extension definition for '{1}'. Did you mean 'await foreach' rather than 'foreach'? Instrukcja foreach nie może operować na zmiennych typu „{0}”, ponieważ typ „{0}” nie zawiera publicznego wystąpienia lub definicji rozszerzenia dla elementu „{1}”. Czy planowano użyć instrukcji „await foreach”, a nie „foreach”? diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf index 7f9ed175d0c85..84b4c37b34ae6 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf @@ -562,6 +562,21 @@ O namespace de escopo de arquivo deve preceder todos os outros membros em um arquivo. + + File type '{0}' cannot be used as a base type of non-file type '{1}'. + File type '{0}' cannot be used as a base type of non-file type '{1}'. + + + + File type '{0}' cannot be used in a member signature in non-file type '{1}'. + File type '{0}' cannot be used in a member signature in non-file type '{1}'. + + + + File type '{0}' cannot use accessibility modifiers. + File type '{0}' cannot use accessibility modifiers. + + foreach statement cannot operate on variables of type '{0}' because '{0}' does not contain a public instance or extension definition for '{1}'. Did you mean 'await foreach' rather than 'foreach'? A instrução foreach não pode operar em variáveis do tipo '{0}' porque '{0}' não contém uma definição de extensão ou de instância pública para '{1}'. Você quis dizer 'await foreach' em vez de 'foreach'? diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf index 0c6369f0f8bcc..8fe5951ae352b 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf @@ -562,6 +562,21 @@ Пространство имен с файловой областью должно быть раньше всех остальных элементов в файле. + + File type '{0}' cannot be used as a base type of non-file type '{1}'. + File type '{0}' cannot be used as a base type of non-file type '{1}'. + + + + File type '{0}' cannot be used in a member signature in non-file type '{1}'. + File type '{0}' cannot be used in a member signature in non-file type '{1}'. + + + + File type '{0}' cannot use accessibility modifiers. + File type '{0}' cannot use accessibility modifiers. + + foreach statement cannot operate on variables of type '{0}' because '{0}' does not contain a public instance or extension definition for '{1}'. Did you mean 'await foreach' rather than 'foreach'? Оператор foreach не работает с переменными типа "{0}", так как "{0}" не содержит открытое определение экземпляра или расширения для "{1}" Возможно, вы имели в виду "await foreach", а не "foreach"? diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf index b5dbed29ec3ee..e3b0cc889f6d1 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf @@ -562,6 +562,21 @@ Dosya kapsamlı ad alanı bir dosyadaki diğer tüm üyelerin önünde olmalıdır. + + File type '{0}' cannot be used as a base type of non-file type '{1}'. + File type '{0}' cannot be used as a base type of non-file type '{1}'. + + + + File type '{0}' cannot be used in a member signature in non-file type '{1}'. + File type '{0}' cannot be used in a member signature in non-file type '{1}'. + + + + File type '{0}' cannot use accessibility modifiers. + File type '{0}' cannot use accessibility modifiers. + + foreach statement cannot operate on variables of type '{0}' because '{0}' does not contain a public instance or extension definition for '{1}'. Did you mean 'await foreach' rather than 'foreach'? '{0}', '{1}' için bir genel örnek veya uzantı tanımı içermediğinden foreach deyimi '{0}' türündeki değişkenler üzerinde çalışamaz. 'foreach' yerine 'await foreach' mi kullanmak istediniz? diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf index d34e183163cea..58e975855c659 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf @@ -562,6 +562,21 @@ 文件范围内的命名空间必须位于文件中所有其他成员之前。 + + File type '{0}' cannot be used as a base type of non-file type '{1}'. + File type '{0}' cannot be used as a base type of non-file type '{1}'. + + + + File type '{0}' cannot be used in a member signature in non-file type '{1}'. + File type '{0}' cannot be used in a member signature in non-file type '{1}'. + + + + File type '{0}' cannot use accessibility modifiers. + File type '{0}' cannot use accessibility modifiers. + + foreach statement cannot operate on variables of type '{0}' because '{0}' does not contain a public instance or extension definition for '{1}'. Did you mean 'await foreach' rather than 'foreach'? “{0}”不包含“{1}”的公共实例或扩展定义,因此 foreach 语句不能作用于“{0}”类型的变量。是否希望使用 "await foreach" 而非 "foreach"? diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf index c7eabe25da772..6a9aa2896054f 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf @@ -562,6 +562,21 @@ 以檔為範圍的命名空間必須在檔案中的所有其他成員之前。 + + File type '{0}' cannot be used as a base type of non-file type '{1}'. + File type '{0}' cannot be used as a base type of non-file type '{1}'. + + + + File type '{0}' cannot be used in a member signature in non-file type '{1}'. + File type '{0}' cannot be used in a member signature in non-file type '{1}'. + + + + File type '{0}' cannot use accessibility modifiers. + File type '{0}' cannot use accessibility modifiers. + + foreach statement cannot operate on variables of type '{0}' because '{0}' does not contain a public instance or extension definition for '{1}'. Did you mean 'await foreach' rather than 'foreach'? 因為 '{0}' 不包含 '{1}' 的公用執行個體或延伸模組定義,所以 foreach 陳述式無法在型別 '{0}' 的變數上運作。您指的是 'await foreach' 而不是 'foreach' 嗎? diff --git a/src/Compilers/CSharp/Test/Symbol/Symbols/ConversionTests.cs b/src/Compilers/CSharp/Test/Symbol/Symbols/ConversionTests.cs index 2fcaaecdc8f09..2ccef65358122 100644 --- a/src/Compilers/CSharp/Test/Symbol/Symbols/ConversionTests.cs +++ b/src/Compilers/CSharp/Test/Symbol/Symbols/ConversionTests.cs @@ -23,7 +23,7 @@ public void Test1() var mscorlibRef = TestMetadata.Net40.mscorlib; var compilation = CSharpCompilation.Create("Test", references: new MetadataReference[] { mscorlibRef }); var sys = compilation.GlobalNamespace.ChildNamespace("System"); - Conversions c = new BuckStopsHereBinder(compilation).Conversions; + Conversions c = new BuckStopsHereBinder(compilation, associatedSyntaxTree: null).Conversions; var types = new TypeSymbol[] { sys.ChildType("Object"), @@ -311,7 +311,7 @@ class C Assert.True(typeIntArrayWithCustomModifiers.HasCustomModifiers(flagNonDefaultArraySizesOrLowerBounds: false)); - var conv = new BuckStopsHereBinder(compilation).Conversions; + var conv = new BuckStopsHereBinder(compilation, associatedSyntaxTree: null).Conversions; HashSet useSiteDiagnostics = null; // no custom modifiers to custom modifiers diff --git a/src/Compilers/CSharp/Test/Symbol/Symbols/Source/FileModifierTests.cs b/src/Compilers/CSharp/Test/Symbol/Symbols/Source/FileModifierTests.cs index aeceafa616a16..b5e473aee9b02 100644 --- a/src/Compilers/CSharp/Test/Symbol/Symbols/Source/FileModifierTests.cs +++ b/src/Compilers/CSharp/Test/Symbol/Symbols/Source/FileModifierTests.cs @@ -2,48 +2,2500 @@ // 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.Linq; +using Microsoft.CodeAnalysis.CSharp.Symbols; +using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.CSharp.Test.Utilities; using Xunit; -namespace Microsoft.CodeAnalysis.CSharp.UnitTests +namespace Microsoft.CodeAnalysis.CSharp.UnitTests; + +public class FileModifierTests : CSharpTestBase { - 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_01() + { + 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(); + } + + [Fact] + public void Nested_02() { - [Fact] - public void LangVersion() + var source = """ + file class Outer + { + 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 Outer + Diagnostic(ErrorCode.ERR_FeatureInPreview, "Outer").WithArguments("file types").WithLocation(1, 12)); + verify(); + + comp = CreateCompilation(source); + comp.VerifyDiagnostics(); + verify(); + + void verify() { - var source = """ + var outer = comp.GetMember("Outer"); + Assert.Equal(Accessibility.Internal, outer.DeclaredAccessibility); + Assert.True(((SourceMemberContainerTypeSymbol)outer).IsFile); + + var classC = comp.GetMember("Outer.C"); + Assert.Equal(Accessibility.Private, classC.DeclaredAccessibility); + Assert.False(((SourceMemberContainerTypeSymbol)classC).IsFile); + } + } + + [Fact] + public void Nested_03() + { + var source = """ + file class Outer + { 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)); + // PROTOTYPE(ft): determine whether an inner file class within a file class is an error or if it's just fine. + 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 Outer + Diagnostic(ErrorCode.ERR_FeatureInPreview, "Outer").WithArguments("file types").WithLocation(1, 12), + // (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(); + } + + [Fact] + public void Nested_04() + { + var source = """ + file class Outer + { + public class C { } + } + + class D + { + void M(Outer.C c) { } // 1 + } + """; + + var comp = CreateCompilation(source); + comp.VerifyDiagnostics( + // (8,10): error CS9300: File type 'Outer.C' cannot be used in a member signature in non-file type 'D'. + // void M(Outer.C c) { } // 1 + Diagnostic(ErrorCode.ERR_FileTypeDisallowedInSignature, "M").WithArguments("Outer.C", "D").WithLocation(8, 10)); + } + + [Fact] + public void Nested_05() + { + var source = """ + file class Outer + { + public class C + { + void M1(Outer outer) { } // ok + void M2(C outer) { } // ok + } + } + """; + + var comp = CreateCompilation(source); + comp.VerifyDiagnostics(); + } + + [Fact] + public void Nested_06() + { + var source = """ + class A1 + { + internal class A2 { } + } + file class B : A1 + { + } + class C : B.A2 // ok: base type is bound as A1.A2 + { + } + """; + + var comp = CreateCompilation(source); + comp.VerifyDiagnostics(); + } + + [Fact] + public void SameFileUse() + { + var source = """ + using System; + + file class C + { + public static void M() + { + Console.Write(1); + } + } + + class Program + { + static void Main() + { + C.M(); + } + } + """; + + var verifier = CompileAndVerify(source, expectedOutput: "1"); + verifier.VerifyDiagnostics(); + // PROTOTYPE(ft): check metadata names + } + + [Fact] + public void OtherFileUse() + { + var source1 = """ + using System; + + file class C + { + public static void M() + { + Console.Write(1); + } + } + """; + + var source2 = """ + class Program + { + static void Main() + { + C.M(); // 1 + } + } + """; + + var comp = CreateCompilation(new[] { source1, source2 }); + comp.VerifyDiagnostics( + // (5,9): error CS0103: The name 'C' does not exist in the current context + // C.M(); // 1 + Diagnostic(ErrorCode.ERR_NameNotInContext, "C").WithArguments("C").WithLocation(5, 9)); + } + + [Theory] + [InlineData("file", "file")] + [InlineData("file", "")] + [InlineData("", "file")] + public void Duplication_01(string firstFileModifier, string secondFileModifier) + { + // A file type is allowed to have the same name as a non-file type from a different file. + // When both a file type and non-file type with the same name are in scope, the file type is preferred, since it's "more local". + var source1 = $$""" + using System; + + {{firstFileModifier}} class C + { + public static void M() + { + Console.Write(1); + } + } + """; + + var source2 = $$""" + using System; - comp = CreateCompilation(source); + {{secondFileModifier}} class C + { + public static void M() + { + Console.Write(2); + } + } + """; + + var main = """ + + class Program + { + static void Main() + { + C.M(); + } + } + """; + + // PROTOTYPE(ft): execute and check expectedOutput once name mangling is done + // expectedOutput: "1" + var comp = CreateCompilation(new[] { source1 + main, source2 }); + var cs = comp.GetMembers("C"); + var tree = comp.SyntaxTrees[0]; + var expectedSymbol = cs[0]; + verify(); + + // expectedOutput: "2" + comp = CreateCompilation(new[] { source1, source2 + main }); + cs = comp.GetMembers("C"); + tree = comp.SyntaxTrees[1]; + expectedSymbol = cs[1]; + verify(); + + void verify() + { comp.VerifyDiagnostics(); + Assert.Equal(2, cs.Length); + Assert.Equal(comp.SyntaxTrees[0], cs[0].DeclaringSyntaxReferences.Single().SyntaxTree); + Assert.Equal(comp.SyntaxTrees[1], cs[1].DeclaringSyntaxReferences.Single().SyntaxTree); + + var model = comp.GetSemanticModel(tree, ignoreAccessibility: true); + var cReference = tree.GetRoot().DescendantNodes().OfType().Last().Expression; + var info = model.GetTypeInfo(cReference); + Assert.Equal(expectedSymbol.GetPublicSymbol(), info.Type); } + } - [Fact] - public void Nested() - { - var source = """ - class Outer + [Fact] + public void Duplication_02() + { + // As a sanity check, demonstrate that non-file classes with the same name across different files are disallowed. + var source1 = """ + using System; + + class C + { + public static void M() + { + Console.Write(1); + } + } + """; + + var source2 = """ + using System; + + class C + { + public static void M() + { + Console.Write(2); + } + } + """; + + var main = """ + + class Program + { + static void Main() { - file class C { } + C.M(); } - """; + } + """; + + var comp = CreateCompilation(new[] { source1 + main, source2 }); + verify(); - var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10); + comp = CreateCompilation(new[] { source1, source2 + main }); + verify(); + + void verify() + { 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)); + // (3,7): error CS0101: The namespace '' already contains a definition for 'C' + // class C + Diagnostic(ErrorCode.ERR_DuplicateNameInNS, "C").WithArguments("C", "").WithLocation(3, 7), + // (5,24): error CS0111: Type 'C' already defines a member called 'M' with the same parameter types + // public static void M() + Diagnostic(ErrorCode.ERR_MemberAlreadyExists, "M").WithArguments("M", "C").WithLocation(5, 24), + // (14,11): error CS0121: The call is ambiguous between the following methods or properties: 'C.M()' and 'C.M()' + // C.M(); + Diagnostic(ErrorCode.ERR_AmbigCall, "M").WithArguments("C.M()", "C.M()").WithLocation(14, 11)); + + var cs = comp.GetMember("C"); + var syntaxReferences = cs.DeclaringSyntaxReferences; + Assert.Equal(2, syntaxReferences.Length); + Assert.Equal(comp.SyntaxTrees[0], syntaxReferences[0].SyntaxTree); + Assert.Equal(comp.SyntaxTrees[1], syntaxReferences[1].SyntaxTree); + } + } + + [Fact] + public void Duplication_03() + { + var source1 = """ + using System; + + partial class C + { + public static void M() + { + Console.Write(1); + } + } + """; + + var source2 = """ + partial class C + { + } + """; + + var main = """ + using System; + + file class C + { + public static void M() + { + Console.Write(2); + } + } + + class Program + { + static void Main() + { + C.M(); + } + } + """; + + var comp = CreateCompilation(new[] { source1, source2, main }); // expectedOutput: 2 + comp.VerifyDiagnostics(); + + var cs = comp.GetMembers("C"); + Assert.Equal(2, cs.Length); + + var c0 = cs[0]; + Assert.True(c0 is SourceMemberContainerTypeSymbol { IsFile: false }); + + var syntaxReferences = c0.DeclaringSyntaxReferences; + Assert.Equal(2, syntaxReferences.Length); + Assert.Equal(comp.SyntaxTrees[0], syntaxReferences[0].SyntaxTree); + Assert.Equal(comp.SyntaxTrees[1], syntaxReferences[1].SyntaxTree); + + var c1 = cs[1]; + Assert.True(c1 is SourceMemberContainerTypeSymbol { IsFile: true }); + Assert.Equal(comp.SyntaxTrees[2], c1.DeclaringSyntaxReferences.Single().SyntaxTree); + + var tree = comp.SyntaxTrees[2]; + var model = comp.GetSemanticModel(tree, ignoreAccessibility: true); + var cReference = tree.GetRoot().DescendantNodes().OfType().Last().Expression; + var info = model.GetTypeInfo(cReference); + Assert.Equal(c1.GetPublicSymbol(), info.Type); + } + + [Fact] + public void Duplication_04() + { + var source1 = """ + using System; + + class C + { + public static void M() + { + Console.Write(1); + } + } + """; + + var main = """ + using System; + + file partial class C + { + public static void M() + { + Console.Write(Number); + } + } + + file partial class C + { + private static int Number => 2; + } + + class Program + { + static void Main() + { + C.M(); + } + } + """; + + var comp = CreateCompilation(new[] { source1, main }); // expectedOutput: 2 + comp.VerifyDiagnostics(); + + var cs = comp.GetMembers("C"); + Assert.Equal(2, cs.Length); - comp = CreateCompilation(source); + var c0 = cs[0]; + Assert.True(c0 is SourceMemberContainerTypeSymbol { IsFile: false }); + Assert.Equal(comp.SyntaxTrees[0], c0.DeclaringSyntaxReferences.Single().SyntaxTree); + + var c1 = cs[1]; + Assert.True(c1 is SourceMemberContainerTypeSymbol { IsFile: true }); + + var syntaxReferences = c1.DeclaringSyntaxReferences; + Assert.Equal(2, syntaxReferences.Length); + Assert.Equal(comp.SyntaxTrees[1], syntaxReferences[0].SyntaxTree); + Assert.Equal(comp.SyntaxTrees[1], syntaxReferences[1].SyntaxTree); + + var tree = comp.SyntaxTrees[1]; + var model = comp.GetSemanticModel(tree, ignoreAccessibility: true); + var cReference = tree.GetRoot().DescendantNodes().OfType().Last().Expression; + var info = model.GetTypeInfo(cReference); + Assert.Equal(c1.GetPublicSymbol(), info.Type); + } + + [Theory] + [CombinatorialData] + public void Duplication_05(bool firstClassIsFile) + { + var source1 = $$""" + using System; + + {{(firstClassIsFile ? "file " : "")}}partial class C + { + public static void M() + { + Console.Write(1); + } + } + """; + + var main = """ + using System; + + file partial class C + { + public static void M() + { + Console.Write(2); + } + } + + class Program + { + static void Main() + { + C.M(); + } + } + """; + + var comp = CreateCompilation(new[] { source1, main }); // expectedOutput: 2 + comp.VerifyDiagnostics(); + + var cs = comp.GetMembers("C"); + Assert.Equal(2, cs.Length); + + var c0 = cs[0]; + Assert.Equal(firstClassIsFile, ((SourceMemberContainerTypeSymbol)c0).IsFile); + Assert.Equal(comp.SyntaxTrees[0], c0.DeclaringSyntaxReferences.Single().SyntaxTree); + + var c1 = cs[1]; + Assert.True(c1 is SourceMemberContainerTypeSymbol { IsFile: true }); + Assert.Equal(comp.SyntaxTrees[1], c1.DeclaringSyntaxReferences.Single().SyntaxTree); + + var tree = comp.SyntaxTrees[1]; + var model = comp.GetSemanticModel(tree, ignoreAccessibility: true); + var cReference = tree.GetRoot().DescendantNodes().OfType().Last().Expression; + var info = model.GetTypeInfo(cReference); + Assert.Equal(c1.GetPublicSymbol(), info.Type); + } + + [Fact] + public void Duplication_06() + { + var source1 = """ + using System; + + partial class C + { + public static void M() + { + Console.Write(Number); + } + } + """; + + var source2 = """ + using System; + + partial class C + { + private static int Number => 1; + } + + file class C + { + public static void M() + { + Console.Write(2); + } + } + """; + + var comp = CreateCompilation(new[] { source1, source2 }); + // PROTOTYPE(ft): should this diagnostic be more specific? + // the issue more precisely is that a definition for 'C' already exists in the current file--not that it's already in this namespace. + comp.VerifyDiagnostics( + // (8,12): error CS0101: The namespace '' already contains a definition for 'C' + // file class C + Diagnostic(ErrorCode.ERR_DuplicateNameInNS, "C").WithArguments("C", "").WithLocation(8, 12)); + + var cs = comp.GetMembers("C"); + Assert.Equal(2, cs.Length); + + var c0 = cs[0]; + Assert.True(c0 is SourceMemberContainerTypeSymbol { IsFile: false }); + var syntaxReferences = c0.DeclaringSyntaxReferences; + Assert.Equal(2, syntaxReferences.Length); + Assert.Equal(comp.SyntaxTrees[0], syntaxReferences[0].SyntaxTree); + Assert.Equal(comp.SyntaxTrees[1], syntaxReferences[1].SyntaxTree); + + var c1 = cs[1]; + Assert.True(c1 is SourceMemberContainerTypeSymbol { IsFile: true }); + Assert.Equal(comp.SyntaxTrees[1], c1.DeclaringSyntaxReferences.Single().SyntaxTree); + + + comp = CreateCompilation(new[] { source2, source1 }); + comp.VerifyDiagnostics( + // (5,24): error CS0111: Type 'C' already defines a member called 'M' with the same parameter types + // public static void M() + Diagnostic(ErrorCode.ERR_MemberAlreadyExists, "M").WithArguments("M", "C").WithLocation(5, 24), + // (8,12): error CS0260: Missing partial modifier on declaration of type 'C'; another partial declaration of this type exists + // file class C + Diagnostic(ErrorCode.ERR_MissingPartial, "C").WithArguments("C").WithLocation(8, 12)); + + var c = comp.GetMember("C"); + // PROTOTYPE(ft): is it a problem that we consider this symbol a file type in this scenario? + Assert.True(c is SourceMemberContainerTypeSymbol { IsFile: true }); + syntaxReferences = c.DeclaringSyntaxReferences; + Assert.Equal(3, syntaxReferences.Length); + Assert.Equal(comp.SyntaxTrees[0], syntaxReferences[0].SyntaxTree); + Assert.Equal(comp.SyntaxTrees[0], syntaxReferences[1].SyntaxTree); + Assert.Equal(comp.SyntaxTrees[1], syntaxReferences[2].SyntaxTree); + } + + [Fact] + public void Duplication_07() + { + var source1 = """ + using System; + + file partial class C + { + public static void M() + { + Console.Write(1); + } + } + """; + + var source2 = """ + using System; + + file partial class C + { + public static void M() + { + Console.Write(Number); + } + } + + file class C + { + private static int Number => 2; + } + """; + + var comp = CreateCompilation(new[] { source1, source2 }); + comp.VerifyDiagnostics( + // (11,12): error CS0260: Missing partial modifier on declaration of type 'C'; another partial declaration of this type exists + // file class C + Diagnostic(ErrorCode.ERR_MissingPartial, "C").WithArguments("C").WithLocation(11, 12)); + + var cs = comp.GetMembers("C"); + Assert.Equal(2, cs.Length); + + var c0 = cs[0]; + Assert.True(c0 is SourceMemberContainerTypeSymbol { IsFile: true }); + Assert.Equal(comp.SyntaxTrees[0], c0.DeclaringSyntaxReferences.Single().SyntaxTree); + + var c1 = cs[1]; + Assert.True(c1 is SourceMemberContainerTypeSymbol { IsFile: true }); + var syntaxReferences = c1.DeclaringSyntaxReferences; + Assert.Equal(2, syntaxReferences.Length); + Assert.Equal(comp.SyntaxTrees[1], syntaxReferences[0].SyntaxTree); + Assert.Equal(comp.SyntaxTrees[1], syntaxReferences[1].SyntaxTree); + + + comp = CreateCompilation(new[] { source2, source1 }); + comp.VerifyDiagnostics( + // (11,12): error CS0260: Missing partial modifier on declaration of type 'C'; another partial declaration of this type exists + // file class C + Diagnostic(ErrorCode.ERR_MissingPartial, "C").WithArguments("C").WithLocation(11, 12)); + + cs = comp.GetMembers("C"); + Assert.Equal(2, cs.Length); + + c0 = cs[0]; + Assert.True(c0 is SourceMemberContainerTypeSymbol { IsFile: true }); + syntaxReferences = c0.DeclaringSyntaxReferences; + Assert.Equal(2, syntaxReferences.Length); + Assert.Equal(comp.SyntaxTrees[0], syntaxReferences[0].SyntaxTree); + Assert.Equal(comp.SyntaxTrees[0], syntaxReferences[1].SyntaxTree); + + c1 = cs[1]; + Assert.True(c1 is SourceMemberContainerTypeSymbol { IsFile: true }); + Assert.Equal(comp.SyntaxTrees[1], c1.DeclaringSyntaxReferences.Single().SyntaxTree); + } + + [Fact] + public void Duplication_08() + { + var source1 = """ + partial class Outer + { + file class C + { + public static void M() { } + } + } + """; + + var source2 = """ + partial class Outer + { + file class C + { + public static void M() { } + } + } + """; + + var source3 = """ + partial class Outer + { + public class C + { + public static void M() { } + } + } + """; + + var compilation = CreateCompilation(new[] { source1, source2, source3 }); + compilation.VerifyDiagnostics(); + + var classOuter = compilation.GetMember("Outer"); + var cs = classOuter.GetMembers("C"); + Assert.Equal(3, cs.Length); + Assert.True(cs[0] is SourceMemberContainerTypeSymbol { IsFile: true }); + Assert.True(cs[1] is SourceMemberContainerTypeSymbol { IsFile: true }); + Assert.True(cs[2] is SourceMemberContainerTypeSymbol { IsFile: false }); + } + + [Fact] + public void Duplication_09() + { + var source1 = """ + namespace NS + { + file class C + { + public static void M() { } + } + } + """; + + var source2 = """ + namespace NS + { + file class C + { + public static void M() { } + } + } + """; + + var source3 = """ + namespace NS + { + public class C + { + public static void M() { } + } + } + """; + + var compilation = CreateCompilation(new[] { source1, source2, source3 }); + compilation.VerifyDiagnostics(); + + var namespaceNS = compilation.GetMember("NS"); + var cs = namespaceNS.GetMembers("C"); + Assert.Equal(3, cs.Length); + Assert.True(cs[0] is SourceMemberContainerTypeSymbol { IsFile: true }); + Assert.True(cs[1] is SourceMemberContainerTypeSymbol { IsFile: true }); + Assert.True(cs[2] is SourceMemberContainerTypeSymbol { IsFile: false }); + } + + [Theory] + [InlineData("file", "file")] + [InlineData("file", "")] + [InlineData("", "file")] + public void Duplication_10(string firstFileModifier, string secondFileModifier) + { + var source1 = $$""" + using System; + + partial class Program + { + {{firstFileModifier}} class C + { + public static void M() + { + Console.Write(1); + } + } + } + """; + + var source2 = $$""" + using System; + + partial class Program + { + {{secondFileModifier}} class C + { + public static void M() + { + Console.Write(2); + } + } + } + """; + + var main = """ + partial class Program + { + static void Main() + { + Program.C.M(); + } + } + """; + + // PROTOTYPE(ft): execute and check expectedOutput once name mangling is done + // expectedOutput: "1" + var comp = CreateCompilation(new[] { source1 + main, source2 }); + var cs = comp.GetMembers("Program.C"); + var tree = comp.SyntaxTrees[0]; + var expectedSymbol = cs[0]; + verify(); + + // expectedOutput: "2" + comp = CreateCompilation(new[] { source1, source2 + main }); + cs = comp.GetMembers("Program.C"); + tree = comp.SyntaxTrees[1]; + expectedSymbol = cs[1]; + verify(); + + void verify() + { + comp.VerifyDiagnostics(); + Assert.Equal(2, cs.Length); + Assert.Equal(comp.SyntaxTrees[0], cs[0].DeclaringSyntaxReferences.Single().SyntaxTree); + Assert.Equal(comp.SyntaxTrees[1], cs[1].DeclaringSyntaxReferences.Single().SyntaxTree); + + var model = comp.GetSemanticModel(tree, ignoreAccessibility: true); + var cReference = tree.GetRoot().DescendantNodes().OfType().Last(); + var info = model.GetTypeInfo(cReference); + Assert.Equal(expectedSymbol.GetPublicSymbol(), info.Type); + } + } + + [Theory] + [InlineData("file", "file")] + [InlineData("file", "")] + [InlineData("", "file")] + public void Duplication_11(string firstFileModifier, string secondFileModifier) + { + var source1 = $$""" + using System; + + {{firstFileModifier}} partial class Outer + { + internal class C + { + public static void M() + { + Console.Write(1); + } + } + } + """; + + var source2 = $$""" + using System; + + {{secondFileModifier}} partial class Outer + { + internal class C + { + public static void M() + { + Console.Write(2); + } + } + } + """; + + var main = """ + class Program + { + static void Main() + { + Outer.C.M(); + } + } + """; + + // PROTOTYPE(ft): execute and check expectedOutput once name mangling is done + // expectedOutput: "1" + var comp = CreateCompilation(new[] { source1 + main, source2 }); + var outers = comp.GetMembers("Outer"); + var cs = outers.Select(o => ((NamedTypeSymbol)o).GetMember("C")).ToArray(); + var tree = comp.SyntaxTrees[0]; + var expectedSymbol = cs[0]; + verify(); + + // expectedOutput: "2" + comp = CreateCompilation(new[] { source1, source2 + main }); + outers = comp.GetMembers("Outer"); + cs = outers.Select(o => ((NamedTypeSymbol)o).GetMember("C")).ToArray(); + tree = comp.SyntaxTrees[1]; + expectedSymbol = cs[1]; + verify(); + + void verify() + { comp.VerifyDiagnostics(); + Assert.Equal(2, cs.Length); + Assert.Equal(comp.SyntaxTrees[0], cs[0].DeclaringSyntaxReferences.Single().SyntaxTree); + Assert.Equal(comp.SyntaxTrees[1], cs[1].DeclaringSyntaxReferences.Single().SyntaxTree); + + var model = comp.GetSemanticModel(tree, ignoreAccessibility: true); + var cReference = tree.GetRoot().DescendantNodes().OfType().Last(); + var info = model.GetTypeInfo(cReference); + Assert.Equal(expectedSymbol.GetPublicSymbol(), info.Type); } } + + [Fact] + public void SignatureUsage_01() + { + var source = """ + file class C + { + } + + class D + { + public void M1(C c) { } // 1 + private void M2(C c) { } // 2 + } + """; + + var comp = CreateCompilation(source); + comp.VerifyDiagnostics( + // (7,17): error CS9300: File type 'C' cannot be used in a member signature in non-file type 'D'. + // public void M1(C c) { } // 1 + Diagnostic(ErrorCode.ERR_FileTypeDisallowedInSignature, "M1").WithArguments("C", "D").WithLocation(7, 17), + // (8,18): error CS9300: File type 'C' cannot be used in a member signature in non-file type 'D'. + // private void M2(C c) { } // 2 + Diagnostic(ErrorCode.ERR_FileTypeDisallowedInSignature, "M2").WithArguments("C", "D").WithLocation(8, 18)); + } + + [Fact] + public void SignatureUsage_02() + { + var source = """ + file class C + { + } + + class D + { + public C M1() => new C(); // 1 + private C M2() => new C(); // 2 + } + """; + + var comp = CreateCompilation(source); + comp.VerifyDiagnostics( + // (7,14): error CS9300: File type 'C' cannot be used in a member signature in non-file type 'D'. + // public C M1() => new C(); // 1 + Diagnostic(ErrorCode.ERR_FileTypeDisallowedInSignature, "M1").WithArguments("C", "D").WithLocation(7, 14), + // (8,15): error CS9300: File type 'C' cannot be used in a member signature in non-file type 'D'. + // private C M2() => new C(); // 2 + Diagnostic(ErrorCode.ERR_FileTypeDisallowedInSignature, "M2").WithArguments("C", "D").WithLocation(8, 15)); + } + + [Fact] + public void SignatureUsage_03() + { + var source = """ + file class C + { + } + file delegate void D(); + + public class E + { + C field; // 1 + C property { get; set; } // 2 + object this[C c] { get => c; set { } } // 3 + event D @event; // 4 + } + """; + + var comp = CreateCompilation(source); + comp.VerifyDiagnostics( + // (8,7): error CS9300: File type 'C' cannot be used in a member signature in non-file type 'E'. + // C field; // 1 + Diagnostic(ErrorCode.ERR_FileTypeDisallowedInSignature, "field").WithArguments("C", "E").WithLocation(8, 7), + // (8,7): warning CS0169: The field 'E.field' is never used + // C field; // 1 + Diagnostic(ErrorCode.WRN_UnreferencedField, "field").WithArguments("E.field").WithLocation(8, 7), + // (9,7): error CS9300: File type 'C' cannot be used in a member signature in non-file type 'E'. + // C property { get; set; } // 2 + Diagnostic(ErrorCode.ERR_FileTypeDisallowedInSignature, "property").WithArguments("C", "E").WithLocation(9, 7), + // (10,12): error CS9300: File type 'C' cannot be used in a member signature in non-file type 'E'. + // object this[C c] { get => c; set { } } // 3 + Diagnostic(ErrorCode.ERR_FileTypeDisallowedInSignature, "this").WithArguments("C", "E").WithLocation(10, 12), + // (11,13): error CS9300: File type 'D' cannot be used in a member signature in non-file type 'E'. + // event D @event; // 4 + Diagnostic(ErrorCode.ERR_FileTypeDisallowedInSignature, "@event").WithArguments("D", "E").WithLocation(11, 13), + // (11,13): warning CS0067: The event 'E.event' is never used + // event D @event; // 4 + Diagnostic(ErrorCode.WRN_UnreferencedEvent, "@event").WithArguments("E.event").WithLocation(11, 13)); + } + + [Fact] + public void SignatureUsage_04() + { + var source = """ + file class C + { + public class Inner { } + public delegate void InnerDelegate(); + } + + public class E + { + C.Inner field; // 1 + C.Inner property { get; set; } // 2 + object this[C.Inner inner] { get => inner; set { } } // 3 + event C.InnerDelegate @event; // 4 + } + """; + + var comp = CreateCompilation(source); + comp.VerifyDiagnostics( + // (9,13): error CS9300: File type 'C.Inner' cannot be used in a member signature in non-file type 'E'. + // C.Inner field; // 1 + Diagnostic(ErrorCode.ERR_FileTypeDisallowedInSignature, "field").WithArguments("C.Inner", "E").WithLocation(9, 13), + // (9,13): warning CS0169: The field 'E.field' is never used + // C.Inner field; // 1 + Diagnostic(ErrorCode.WRN_UnreferencedField, "field").WithArguments("E.field").WithLocation(9, 13), + // (10,13): error CS9300: File type 'C.Inner' cannot be used in a member signature in non-file type 'E'. + // C.Inner property { get; set; } // 2 + Diagnostic(ErrorCode.ERR_FileTypeDisallowedInSignature, "property").WithArguments("C.Inner", "E").WithLocation(10, 13), + // (11,12): error CS9300: File type 'C.Inner' cannot be used in a member signature in non-file type 'E'. + // object this[C.Inner inner] { get => inner; set { } } // 3 + Diagnostic(ErrorCode.ERR_FileTypeDisallowedInSignature, "this").WithArguments("C.Inner", "E").WithLocation(11, 12), + // (12,27): error CS9300: File type 'C.InnerDelegate' cannot be used in a member signature in non-file type 'E'. + // event C.InnerDelegate @event; // 4 + Diagnostic(ErrorCode.ERR_FileTypeDisallowedInSignature, "@event").WithArguments("C.InnerDelegate", "E").WithLocation(12, 27), + // (12,27): warning CS0067: The event 'E.event' is never used + // event C.InnerDelegate @event; // 4 + Diagnostic(ErrorCode.WRN_UnreferencedEvent, "@event").WithArguments("E.event").WithLocation(12, 27)); + } + + [Fact] + public void SignatureUsage_05() + { + var source = """ + #pragma warning disable 67, 169 // unused event, field + + file class C + { + public class Inner { } + public delegate void InnerDelegate(); + } + + file class D + { + public class Inner + { + C.Inner field; + C.Inner property { get; set; } + object this[C.Inner inner] { get => inner; set { } } + event C.InnerDelegate @event; + } + } + + class E + { + public class Inner + { + C.Inner field; // 1 + C.Inner property { get; set; } // 2 + object this[C.Inner inner] { get => inner; set { } } // 3 + event C.InnerDelegate @event; // 4 + } + } + """; + + var comp = CreateCompilation(source); + comp.VerifyDiagnostics( + // (24,17): error CS9300: File type 'C.Inner' cannot be used in a member signature in non-file type 'E.Inner'. + // C.Inner field; // 1 + Diagnostic(ErrorCode.ERR_FileTypeDisallowedInSignature, "field").WithArguments("C.Inner", "E.Inner").WithLocation(24, 17), + // (25,17): error CS9300: File type 'C.Inner' cannot be used in a member signature in non-file type 'E.Inner'. + // C.Inner property { get; set; } // 2 + Diagnostic(ErrorCode.ERR_FileTypeDisallowedInSignature, "property").WithArguments("C.Inner", "E.Inner").WithLocation(25, 17), + // (26,16): error CS9300: File type 'C.Inner' cannot be used in a member signature in non-file type 'E.Inner'. + // object this[C.Inner inner] { get => inner; set { } } // 3 + Diagnostic(ErrorCode.ERR_FileTypeDisallowedInSignature, "this").WithArguments("C.Inner", "E.Inner").WithLocation(26, 16), + // (27,31): error CS9300: File type 'C.InnerDelegate' cannot be used in a member signature in non-file type 'E.Inner'. + // event C.InnerDelegate @event; // 4 + Diagnostic(ErrorCode.ERR_FileTypeDisallowedInSignature, "@event").WithArguments("C.InnerDelegate", "E.Inner").WithLocation(27, 31)); + } + + [Fact] + public void SignatureUsage_06() + { + var source = """ + file class C + { + } + + delegate void Del1(C c); // 1 + delegate C Del2(); // 2 + """; + + var comp = CreateCompilation(source); + comp.VerifyDiagnostics( + // (5,15): error CS9300: File type 'C' cannot be used in a member signature in non-file type 'Del1'. + // delegate void Del1(C c); // 1 + Diagnostic(ErrorCode.ERR_FileTypeDisallowedInSignature, "Del1").WithArguments("C", "Del1").WithLocation(5, 15), + // (6,12): error CS9300: File type 'C' cannot be used in a member signature in non-file type 'Del2'. + // delegate C Del2(); // 2 + Diagnostic(ErrorCode.ERR_FileTypeDisallowedInSignature, "Del2").WithArguments("C", "Del2").WithLocation(6, 12)); + } + + [Fact] + public void SignatureUsage_07() + { + var source = """ + file class C + { + } + + class D + { + public static D operator +(D d, C c) => d; // 1 + public static C operator -(D d1, D d2) => new C(); // 2 + } + """; + + var comp = CreateCompilation(source); + comp.VerifyDiagnostics( + // (7,30): error CS9300: File type 'C' cannot be used in a member signature in non-file type 'D'. + // public static D operator +(D d, C c) => d; // 1 + Diagnostic(ErrorCode.ERR_FileTypeDisallowedInSignature, "+").WithArguments("C", "D").WithLocation(7, 30), + // (8,30): error CS9300: File type 'C' cannot be used in a member signature in non-file type 'D'. + // public static C operator -(D d1, D d2) => new C(); // 2 + Diagnostic(ErrorCode.ERR_FileTypeDisallowedInSignature, "-").WithArguments("C", "D").WithLocation(8, 30)); + } + + [Fact] + public void SignatureUsage_08() + { + var source = """ + file class C + { + } + + class D + { + public D(C c) { } // 1 + } + """; + + var comp = CreateCompilation(source); + comp.VerifyDiagnostics( + // (7,12): error CS9300: File type 'C' cannot be used in a member signature in non-file type 'D'. + // public D(C c) { } // 1 + Diagnostic(ErrorCode.ERR_FileTypeDisallowedInSignature, "D").WithArguments("C", "D").WithLocation(7, 12)); + } + + [Fact] + public void SignatureUsage_09() + { + var source = """ + file class C + { + } + + class D + { + public C M(C c1, C c2) => c1; // 1, 2, 3 + } + """; + + var comp = CreateCompilation(source); + comp.VerifyDiagnostics( + // (7,14): error CS9300: File type 'C' cannot be used in a member signature in non-file type 'D'. + // public C M(C c1, C c2) => c1; // 1, 2, 3 + Diagnostic(ErrorCode.ERR_FileTypeDisallowedInSignature, "M").WithArguments("C", "D").WithLocation(7, 14), + // (7,14): error CS9300: File type 'C' cannot be used in a member signature in non-file type 'D'. + // public C M(C c1, C c2) => c1; // 1, 2, 3 + Diagnostic(ErrorCode.ERR_FileTypeDisallowedInSignature, "M").WithArguments("C", "D").WithLocation(7, 14), + // (7,14): error CS9300: File type 'C' cannot be used in a member signature in non-file type 'D'. + // public C M(C c1, C c2) => c1; // 1, 2, 3 + Diagnostic(ErrorCode.ERR_FileTypeDisallowedInSignature, "M").WithArguments("C", "D").WithLocation(7, 14)); + } + + [Fact] + public void AccessModifiers_01() + { + var source = """ + public file class C { } // 1 + file internal class D { } // 2 + private file class E { } // 3, 4 + file class F { } // ok + """; + + var comp = CreateCompilation(source); + comp.VerifyDiagnostics( + // (1,19): error CS9301: File type 'C' cannot use accessibility modifiers. + // public file class C { } // 1 + Diagnostic(ErrorCode.ERR_FileTypeNoExplicitAccessibility, "C").WithArguments("C").WithLocation(1, 19), + // (2,21): error CS9301: File type 'D' cannot use accessibility modifiers. + // file internal class D { } // 2 + Diagnostic(ErrorCode.ERR_FileTypeNoExplicitAccessibility, "D").WithArguments("D").WithLocation(2, 21), + // (3,20): error CS9301: File type 'E' cannot use accessibility modifiers. + // private file class E { } // 3, 4 + Diagnostic(ErrorCode.ERR_FileTypeNoExplicitAccessibility, "E").WithArguments("E").WithLocation(3, 20), + // (3,20): error CS1527: Elements defined in a namespace cannot be explicitly declared as private, protected, protected internal, or private protected + // private file class E { } // 3, 4 + Diagnostic(ErrorCode.ERR_NoNamespacePrivate, "E").WithLocation(3, 20)); + } + + [Fact] + public void DuplicateModifiers_01() + { + var source = """ + file file class C { } // 1 + file readonly file struct D { } // 2 + """; + + var comp = CreateCompilation(source); + comp.VerifyDiagnostics( + // (1,6): error CS1004: Duplicate 'file' modifier + // file file class C { } // 1 + Diagnostic(ErrorCode.ERR_DuplicateModifier, "file").WithArguments("file").WithLocation(1, 6), + // (2,15): error CS1004: Duplicate 'file' modifier + // file readonly file struct D { } // 2 + Diagnostic(ErrorCode.ERR_DuplicateModifier, "file").WithArguments("file").WithLocation(2, 15)); + } + + [Fact] + public void BaseClause_01() + { + var source = """ + file class Base { } + class Derived1 : Base { } // 1 + public class Derived2 : Base { } // 2, 3 + file class Derived3 : Base { } // ok + """; + + var comp = CreateCompilation(source); + comp.VerifyDiagnostics( + // (2,7): error CS9301: File type 'Base' cannot be used as a base type of non-file type 'Derived1'. + // class Derived1 : Base { } // 1 + Diagnostic(ErrorCode.ERR_FileTypeBase, "Derived1").WithArguments("Base", "Derived1").WithLocation(2, 7), + // (3,14): error CS0060: Inconsistent accessibility: base class 'Base' is less accessible than class 'Derived2' + // public class Derived2 : Base { } // 2, 3 + Diagnostic(ErrorCode.ERR_BadVisBaseClass, "Derived2").WithArguments("Derived2", "Base").WithLocation(3, 14), + // (3,14): error CS9301: File type 'Base' cannot be used as a base type of non-file type 'Derived2'. + // public class Derived2 : Base { } // 2, 3 + Diagnostic(ErrorCode.ERR_FileTypeBase, "Derived2").WithArguments("Base", "Derived2").WithLocation(3, 14)); + } + + [Fact] + public void BaseClause_02() + { + var source = """ + file interface Interface { } + + class Derived1 : Interface { } // ok + file class Derived2 : Interface { } // ok + + interface Derived3 : Interface { } // 1 + file interface Derived4 : Interface { } // ok + """; + + var comp = CreateCompilation(source); + comp.VerifyDiagnostics( + // (6,11): error CS9301: File type 'Interface' cannot be used as a base type of non-file type 'Derived3'. + // interface Derived3 : Interface { } // 1 + Diagnostic(ErrorCode.ERR_FileTypeBase, "Derived3").WithArguments("Interface", "Derived3").WithLocation(6, 11)); + } + + [Fact] + public void BaseClause_03() + { + var source1 = """ + using System; + class Base + { + public static void M0() + { + Console.Write(1); + } + } + """; + var source2 = """ + using System; + + file class Base + { + public static void M0() + { + Console.Write(2); + } + } + file class Program : Base + { + static void Main() + { + M0(); + } + } + """; + + var comp = CreateCompilation(new[] { source1, source2 }); // PROTOTYPE(ft): expectedOutput: 2 + comp.VerifyDiagnostics(); + + var tree = comp.SyntaxTrees[1]; + var model = comp.GetSemanticModel(tree); + + var fileClassBase = (NamedTypeSymbol)comp.GetMembers("Base")[1]; + var expectedSymbol = fileClassBase.GetMember("M0"); + + var node = tree.GetRoot().DescendantNodes().OfType().Last(); + var symbolInfo = model.GetSymbolInfo(node.Expression); + Assert.Equal(expectedSymbol.GetPublicSymbol(), symbolInfo.Symbol); + Assert.Empty(symbolInfo.CandidateSymbols); + Assert.Equal(CandidateReason.None, symbolInfo.CandidateReason); + } + + [Fact] + public void BaseClause_04() + { + var source1 = """ + using System; + class Base + { + public static void M0() + { + Console.Write(1); + } + } + """; + var source2 = """ + file class Program : Base + { + static void Main() + { + M0(); + } + } + """; + + var comp = CreateCompilation(new[] { source1, source2 }); // PROTOTYPE(ft): expectedOutput: 1 + comp.VerifyDiagnostics(); + + var tree = comp.SyntaxTrees[1]; + var model = comp.GetSemanticModel(tree); + + var expectedSymbol = comp.GetMember("Base.M0"); + + var node = tree.GetRoot().DescendantNodes().OfType().Last(); + var symbolInfo = model.GetSymbolInfo(node.Expression); + Assert.Equal(expectedSymbol.GetPublicSymbol(), symbolInfo.Symbol); + Assert.Empty(symbolInfo.CandidateSymbols); + Assert.Equal(CandidateReason.None, symbolInfo.CandidateReason); + } + + [Fact] + public void BaseClause_05() + { + var source = """ + interface I2 { } + file interface I1 { } + partial interface Derived : I1 { } // 1 + partial interface Derived : I2 { } + """; + + var comp = CreateCompilation(source); + comp.VerifyDiagnostics( + // (3,19): error CS9302: File type 'I1' cannot be used as a base type of non-file type 'Derived'. + // partial interface Derived : I1 { } // 1 + Diagnostic(ErrorCode.ERR_FileTypeBase, "Derived").WithArguments("I1", "Derived").WithLocation(3, 19)); + } + + [Fact] + public void InterfaceImplementation_01() + { + var source = """ + file interface I + { + void F(); + } + class C : I + { + public void F() { } + } + """; + + var comp = CreateCompilation(source); + comp.VerifyDiagnostics(); + } + + [Fact] + public void InterfaceImplementation_02() + { + var source = """ + file interface I + { + void F(I i); + } + class C : I + { + public void F(I i) { } // 1 + } + """; + + var comp = CreateCompilation(source); + comp.VerifyDiagnostics( + // (7,17): error CS9300: File type 'I' cannot be used in a member signature in non-file type 'C'. + // public void F(I i) { } // 1 + Diagnostic(ErrorCode.ERR_FileTypeDisallowedInSignature, "F").WithArguments("I", "C").WithLocation(7, 17)); + } + + [Fact] + public void InterfaceImplementation_03() + { + var source = """ + file interface I + { + void F(I i); + } + class C : I + { + void I.F(I i) { } // PROTOTYPE(ft): is this acceptable, since it's only callable by casting to the referenced file type? + } + """; + + var comp = CreateCompilation(source); + comp.VerifyDiagnostics( + // (7,12): error CS9300: File type 'I' cannot be used in a member signature in non-file type 'C'. + // void I.F(I i) { } // PROTOTYPE(ft): is this acceptable, since it's only callable by casting to the referenced file type? + Diagnostic(ErrorCode.ERR_FileTypeDisallowedInSignature, "F").WithArguments("I", "C").WithLocation(7, 12)); + } + + [Fact] + public void InterfaceImplementation_04() + { + var source1 = """ + file interface I + { + void F(); + } + partial class C : I + { + } + """; + + var source2 = """ + partial class C + { + public void F() { } + } + """; + + // This is similar to how a base class may not have access to an interface (by being from another assembly, etc.), + // but a derived class might add that interface to its list, and a base member implicitly implements an interface member. + var comp = CreateCompilation(new[] { source1, source2 }); + comp.VerifyDiagnostics(); + } + + [Fact] + public void InterfaceImplementation_05() + { + var source1 = """ + file interface I + { + void F(); + } + partial class C : I // 1 + { + } + """; + + var source2 = """ + partial class C + { + void I.F() { } // 2, 3 + } + """; + + var comp = CreateCompilation(new[] { source1, source2 }); + comp.VerifyDiagnostics( + // (3,10): error CS0246: The type or namespace name 'I' could not be found (are you missing a using directive or an assembly reference?) + // void I.F() { } // 2, 3 + Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "I").WithArguments("I").WithLocation(3, 10), + // (3,10): error CS0538: 'I' in explicit interface declaration is not an interface + // void I.F() { } // 2, 3 + Diagnostic(ErrorCode.ERR_ExplicitInterfaceImplementationNotInterface, "I").WithArguments("I").WithLocation(3, 10), + // (5,19): error CS0535: 'C' does not implement interface member 'I.F()' + // partial class C : I // 1 + Diagnostic(ErrorCode.ERR_UnimplementedInterfaceMember, "I").WithArguments("C", "I.F()").WithLocation(5, 19)); + } + + [Fact] + public void TypeArguments_01() + { + var source = """ + file struct S { public int X; } + class Container { } + unsafe class Program + { + Container M1() => new Container(); // 1 + S[] M2() => new S[0]; // 2 + (S, S) M3() => (new S(), new S()); // 3 + S* M4() => null; // 4 + delegate* M5() => null; // 5 + } + """; + + var comp = CreateCompilation(source, options: TestOptions.UnsafeDebugDll); + comp.VerifyDiagnostics( + // (1,28): warning CS0649: Field 'S.X' is never assigned to, and will always have its default value 0 + // file struct S { public int X; } + Diagnostic(ErrorCode.WRN_UnassignedInternalField, "X").WithArguments("S.X", "0").WithLocation(1, 28), + // (5,18): error CS9300: File type 'Container' cannot be used in a member signature in non-file type 'Program'. + // Container M1() => new Container(); // 1 + Diagnostic(ErrorCode.ERR_FileTypeDisallowedInSignature, "M1").WithArguments("Container", "Program").WithLocation(5, 18), + // (6,9): error CS9300: File type 'S[]' cannot be used in a member signature in non-file type 'Program'. + // S[] M2() => new S[0]; // 2 + Diagnostic(ErrorCode.ERR_FileTypeDisallowedInSignature, "M2").WithArguments("S[]", "Program").WithLocation(6, 9), + // (7,12): error CS9300: File type '(S, S)' cannot be used in a member signature in non-file type 'Program'. + // (S, S) M3() => (new S(), new S()); // 3 + Diagnostic(ErrorCode.ERR_FileTypeDisallowedInSignature, "M3").WithArguments("(S, S)", "Program").WithLocation(7, 12), + // (8,8): error CS9300: File type 'S*' cannot be used in a member signature in non-file type 'Program'. + // S* M4() => null; // 4 + Diagnostic(ErrorCode.ERR_FileTypeDisallowedInSignature, "M4").WithArguments("S*", "Program").WithLocation(8, 8), + // (9,24): error CS9300: File type 'delegate*' cannot be used in a member signature in non-file type 'Program'. + // delegate* M5() => null; // 5 + Diagnostic(ErrorCode.ERR_FileTypeDisallowedInSignature, "M5").WithArguments("delegate*", "Program").WithLocation(9, 24)); + } + + [Fact] + public void Constraints_01() + { + var source = """ + file class C { } + + file class D + { + void M(T t) where T : C { } // ok + } + + class E + { + void M(T t) where T : C { } // 1 + } + """; + + var comp = CreateCompilation(source); + comp.VerifyDiagnostics( + // (10,30): error CS9300: File type 'C' cannot be used in a member signature in non-file type 'E.M(T)'. + // void M(T t) where T : C { } // 1 + Diagnostic(ErrorCode.ERR_FileTypeDisallowedInSignature, "C").WithArguments("C", "E.M(T)").WithLocation(10, 30)); + } + + [Fact] + public void PrimaryConstructor_01() + { + var source = """ + file class C { } + + record R1(C c); // 1 + record struct R2(C c); // 2 + + file record R3(C c); + file record struct R4(C c); + """; + + var comp = CreateCompilation(new[] { source, IsExternalInitTypeDefinition }); + comp.VerifyDiagnostics( + // (3,8): error CS9300: File type 'C' cannot be used in a member signature in non-file type 'R1'. + // record R1(C c); // 1 + Diagnostic(ErrorCode.ERR_FileTypeDisallowedInSignature, "R1").WithArguments("C", "R1").WithLocation(3, 8), + // (3,8): error CS9300: File type 'C' cannot be used in a member signature in non-file type 'R1'. + // record R1(C c); // 1 + Diagnostic(ErrorCode.ERR_FileTypeDisallowedInSignature, "R1").WithArguments("C", "R1").WithLocation(3, 8), + // (4,15): error CS9300: File type 'C' cannot be used in a member signature in non-file type 'R2'. + // record struct R2(C c); // 2 + Diagnostic(ErrorCode.ERR_FileTypeDisallowedInSignature, "R2").WithArguments("C", "R2").WithLocation(4, 15), + // (4,15): error CS9300: File type 'C' cannot be used in a member signature in non-file type 'R2'. + // record struct R2(C c); // 2 + Diagnostic(ErrorCode.ERR_FileTypeDisallowedInSignature, "R2").WithArguments("C", "R2").WithLocation(4, 15) + ); + } + + [Fact] + public void Lambda_01() + { + var source = """ + file class C { } + + class Program + { + void M() + { + var lambda = C (C c) => c; // ok + } + } + """; + + var comp = CreateCompilation(source); + comp.VerifyDiagnostics(); + } + + [Fact] + public void LocalFunction_01() + { + var source = """ + file class C { } + + class Program + { + void M() + { + local(null!); + C local(C c) => c; // ok + } + } + """; + + var comp = CreateCompilation(source); + comp.VerifyDiagnostics(); + } + + [Fact] + public void AccessThroughNamespace_01() + { + var source = """ + using System; + + namespace NS + { + file class C + { + public static void M() => Console.Write(1); + } + } + + class Program + { + public static void Main() + { + NS.C.M(); + } + } + """; + + var verifier = CompileAndVerify(source, expectedOutput: "1"); + verifier.VerifyDiagnostics(); + } + + [Fact] + public void AccessThroughNamespace_02() + { + var source1 = """ + using System; + + namespace NS + { + file class C + { + public static void M() + { + Console.Write(1); + } + } + } + """; + + var source2 = """ + class Program + { + static void Main() + { + NS.C.M(); // 1 + } + } + """; + + var comp = CreateCompilation(new[] { source1, source2 }); + comp.VerifyDiagnostics( + // (5,9): error CS0234: The type or namespace name 'C' does not exist in the namespace 'NS' (are you missing an assembly reference?) + // NS.C.M(); // 1 + Diagnostic(ErrorCode.ERR_DottedTypeNameNotFoundInNS, "NS.C").WithArguments("C", "NS").WithLocation(5, 9)); + } + + [Fact] + public void AccessThroughType_01() + { + var source = """ + using System; + + class Outer + { + file class C + { + public static void M() => Console.Write(1); + } + } + + class Program + { + public static void Main() + { + Outer.C.M(); // 1 + } + } + """; + + // note: there's no way to make 'file class C' internal here. it's forced to be private, at least for the initial release of the feature. + // we access it within the same containing type in test 'Duplication_10'. + var comp = CreateCompilation(source); + comp.VerifyDiagnostics( + // (15,15): error CS0122: 'Outer.C' is inaccessible due to its protection level + // Outer.C.M(); // 1 + Diagnostic(ErrorCode.ERR_BadAccess, "C").WithArguments("Outer.C").WithLocation(15, 15)); + } + + [Fact] + public void AccessThroughType_02() + { + var source1 = """ + using System; + + class Outer + { + file class C + { + public static void M() + { + Console.Write(1); + } + } + } + """; + + var source2 = """ + class Program + { + static void Main() + { + Outer.C.M(); // 1 + } + } + """; + + var comp = CreateCompilation(new[] { source1, source2 }); + comp.VerifyDiagnostics( + // (5,15): error CS0117: 'Outer' does not contain a definition for 'C' + // Outer.C.M(); // 1 + Diagnostic(ErrorCode.ERR_NoSuchMember, "C").WithArguments("Outer", "C").WithLocation(5, 15)); + } + + [Fact] + public void AccessThroughGlobalUsing_01() + { + var usings = """ + global using NS; + """; + + var source = """ + using System; + + namespace NS + { + file class C + { + public static void M() => Console.Write(1); + } + } + + class Program + { + public static void Main() + { + C.M(); + } + } + """; + + var verifier = CompileAndVerify(new[] { usings, source, IsExternalInitTypeDefinition }, expectedOutput: "1"); + verifier.VerifyDiagnostics(); + } + + [Theory] + [InlineData("file ")] + [InlineData("")] + public void AccessThroughGlobalUsing_02(string fileModifier) + { + var source = $$""" + using System; + + namespace NS + { + {{fileModifier}}class C + { + public static void M() => Console.Write(1); + } + } + + class Program + { + public static void Main() + { + C.M(); // 1 + } + } + """; + + // note: 'Usings' is a legacy setting which only works in scripts. + // https://github.com/dotnet/roslyn/issues/61502 + var compilation = CreateCompilation(new[] { source, IsExternalInitTypeDefinition }, options: TestOptions.DebugExe.WithUsings("NS")); + compilation.VerifyDiagnostics( + // (15,9): error CS0103: The name 'C' does not exist in the current context + // C.M(); // 1 + Diagnostic(ErrorCode.ERR_NameNotInContext, "C").WithArguments("C").WithLocation(15, 9)); + } + + [Fact] + public void GlobalUsingStatic_01() + { + var source = """ + global using static C; + + file class C + { + public static void M() { } + } + """; + + var main = """ + class Program + { + public static void Main() + { + M(); + } + } + """; + + // PROTOTYPE(ft): it should probably be an error to reference a file type in a global using static + var compilation = CreateCompilation(new[] { source, main }); + compilation.VerifyDiagnostics( + // (1,1): hidden CS8019: Unnecessary using directive. + // global using static C; + Diagnostic(ErrorCode.HDN_UnusedUsingDirective, "global using static C;").WithLocation(1, 1), + // (5,9): error CS0103: The name 'M' does not exist in the current context + // M(); + Diagnostic(ErrorCode.ERR_NameNotInContext, "M").WithArguments("M").WithLocation(5, 9)); + } + + [Fact] + public void UsingStatic_01() + { + var source = """ + using System; + using static C; + + file class C + { + public static void M() + { + Console.Write(1); + } + } + + class Program + { + public static void Main() + { + M(); + } + } + """; + + var verifier = CompileAndVerify(source, expectedOutput: "1"); + verifier.VerifyDiagnostics(); + } + + [Fact] + public void UsingStatic_02() + { + var source1 = """ + using System; + using static C.D; + + M(); + + file class C + { + public class D + { + public static void M() { Console.Write(1); } + } + } + """; + + var source2 = """ + using System; + + class C + { + public class D + { + public static void M() { Console.Write(2); } + } + } + """; + + // var verifier = CompileAndVerify(new[] { source1, source2 }, expectedOutput: "1"); + // verifier.VerifyDiagnostics(); + // var comp = (CSharpCompilation)verifier.Compilation; + + // PROTOTYPE(ft): replace the following with the above commented lines once name mangling is done + var comp = CreateCompilation(new[] { source1, source2 }); + comp.VerifyDiagnostics(); + + var tree = comp.SyntaxTrees[0]; + var model = comp.GetSemanticModel(tree); + + var members = comp.GetMembers("C"); + Assert.Equal(2, members.Length); + var expectedMember = ((NamedTypeSymbol)members[0]).GetMember("D.M"); + + var invocation = tree.GetRoot().DescendantNodes().OfType().First(); + var symbolInfo = model.GetSymbolInfo(invocation.Expression); + Assert.Equal(expectedMember.GetPublicSymbol(), symbolInfo.Symbol); + Assert.Equal(0, symbolInfo.CandidateSymbols.Length); + Assert.Equal(CandidateReason.None, symbolInfo.CandidateReason); + } + + [Theory] + [InlineData("file ")] + [InlineData("")] + public void UsingStatic_03(string fileModifier) + { + // note: the top-level `class D` "wins" the lookup in this scenario. + var source1 = $$""" + using System; + using static C; + + D.M(); + + {{fileModifier}}class C + { + public class D + { + public static void M() { Console.Write(1); } + } + } + """; + + var source2 = """ + using System; + + class D + { + public static void M() { Console.Write(2); } + } + """; + + // var verifier = CompileAndVerify(new[] { source1, source2 }, expectedOutput: "2"); + // verifier.VerifyDiagnostics(); + // var comp = (CSharpCompilation)verifier.Compilation; + + // PROTOTYPE(ft): replace the following with the above commented lines once name mangling is done + var comp = CreateCompilation(new[] { source1, source2 }); + comp.VerifyDiagnostics( + // (2,1): hidden CS8019: Unnecessary using directive. + // using static C; + Diagnostic(ErrorCode.HDN_UnusedUsingDirective, "using static C;").WithLocation(2, 1)); + + var tree = comp.SyntaxTrees[0]; + var model = comp.GetSemanticModel(tree); + + var expectedMember = comp.GetMember("D.M"); + + var invocation = tree.GetRoot().DescendantNodes().OfType().First(); + var symbolInfo = model.GetSymbolInfo(invocation.Expression); + Assert.Equal(expectedMember.GetPublicSymbol(), symbolInfo.Symbol); + Assert.Equal(0, symbolInfo.CandidateSymbols.Length); + Assert.Equal(CandidateReason.None, symbolInfo.CandidateReason); + } + + [Fact] + public void TypeShadowing() + { + var source = """ + using System; + + class Base + { + internal class C + { + public static void M() + { + Console.Write(1); + } + } + } + + class Derived : Base + { + new file class C + { + } + } + """; + + var main = """ + class Program + { + public static void Main() + { + Derived.C.M(); + } + } + """; + + // 'Derived.C' is not actually accessible from 'Program', so we just bind to 'Base.C' and things work. + var compilation = CompileAndVerify(new[] { source, main }, expectedOutput: "1"); + compilation.VerifyDiagnostics(); + } + + [Fact] + public void SemanticModel_01() + { + var source = """ + file class C + { + public static void M() { } + } + + class Program + { + public void M() + { + C.M(); + } + } + """; + + var compilation = CreateCompilation(source); + compilation.VerifyDiagnostics(); + + var tree = compilation.SyntaxTrees[0]; + var body = tree.GetRoot().DescendantNodes().OfType().Last().Body!; + + var model = compilation.GetSemanticModel(tree, ignoreAccessibility: false); + + var info = model.GetSymbolInfo(((ExpressionStatementSyntax)body.Statements.First()).Expression); + Assert.Equal(compilation.GetMember("C.M").GetPublicSymbol(), info.Symbol); + + var classC = compilation.GetMember("C").GetPublicSymbol(); + var symbols = model.LookupSymbols(body.OpenBraceToken.EndPosition, name: "C"); + Assert.Equal(new[] { classC }, symbols); + + symbols = model.LookupSymbols(body.OpenBraceToken.EndPosition); + Assert.Contains(classC, symbols); + } + + [Fact] + public void SemanticModel_02() + { + var source = """ + file class C + { + public static void M() { } + } + """; + + var main = """ + class Program + { + public void M() + { + C.M(); // 1 + } + } + """; + + var compilation = CreateCompilation(new[] { source, main }); + compilation.VerifyDiagnostics( + // (5,9): error CS0103: The name 'C' does not exist in the current context + // C.M(); + Diagnostic(ErrorCode.ERR_NameNotInContext, "C").WithArguments("C").WithLocation(5, 9) + ); + + var tree = compilation.SyntaxTrees[1]; + var body = tree.GetRoot().DescendantNodes().OfType().Last().Body!; + + var model = compilation.GetSemanticModel(tree, ignoreAccessibility: false); + + var info = model.GetSymbolInfo(((ExpressionStatementSyntax)body.Statements.First()).Expression); + Assert.Null(info.Symbol); + Assert.Empty(info.CandidateSymbols); + Assert.Equal(CandidateReason.None, info.CandidateReason); + + var symbols = model.LookupSymbols(body.OpenBraceToken.EndPosition, name: "C"); + Assert.Empty(symbols); + + symbols = model.LookupSymbols(body.OpenBraceToken.EndPosition); + Assert.DoesNotContain(compilation.GetMember("C").GetPublicSymbol(), symbols); + } + + [Fact] + public void Speculation_01() + { + var source = """ + file class C + { + public static void M() { } + } + + class Program + { + public void M() + { + + } + } + """; + + var compilation = CreateCompilation(source); + compilation.VerifyDiagnostics(); + + var tree = compilation.SyntaxTrees[0]; + var body = tree.GetRoot().DescendantNodes().OfType().Last().Body!; + + var model = compilation.GetSemanticModel(tree, ignoreAccessibility: false); + + var newBody = body.AddStatements(SyntaxFactory.ParseStatement("C.M();")); + Assert.True(model.TryGetSpeculativeSemanticModel(position: body.OpenBraceToken.EndPosition, newBody, out var speculativeModel)); + var info = speculativeModel!.GetSymbolInfo(((ExpressionStatementSyntax)newBody.Statements.First()).Expression); + Assert.Equal(compilation.GetMember("C.M").GetPublicSymbol(), info.Symbol); + + var classC = compilation.GetMember("C").GetPublicSymbol(); + var symbols = speculativeModel.LookupSymbols(newBody.OpenBraceToken.EndPosition, name: "C"); + Assert.Equal(new[] { classC }, symbols); + + symbols = speculativeModel.LookupSymbols(newBody.OpenBraceToken.EndPosition); + Assert.Contains(classC, symbols); + } + + [Fact] + public void Speculation_02() + { + var source = """ + file class C + { + public static void M() { } + } + """; + + var main = """ + class Program + { + public void M() + { + + } + } + """; + + var compilation = CreateCompilation(new[] { source, main }); + compilation.VerifyDiagnostics(); + + var tree = compilation.SyntaxTrees[1]; + var body = tree.GetRoot().DescendantNodes().OfType().Last().Body!; + + var model = compilation.GetSemanticModel(tree, ignoreAccessibility: false); + + var newBody = body.AddStatements(SyntaxFactory.ParseStatement("C.M();")); + Assert.True(model.TryGetSpeculativeSemanticModel(position: body.OpenBraceToken.EndPosition, newBody, out var speculativeModel)); + var info = speculativeModel!.GetSymbolInfo(((ExpressionStatementSyntax)newBody.Statements.First()).Expression); + Assert.Null(info.Symbol); + Assert.Empty(info.CandidateSymbols); + Assert.Equal(CandidateReason.None, info.CandidateReason); + + var symbols = speculativeModel.LookupSymbols(newBody.OpenBraceToken.EndPosition, name: "C"); + Assert.Empty(symbols); + + symbols = speculativeModel.LookupSymbols(newBody.OpenBraceToken.EndPosition); + Assert.DoesNotContain(compilation.GetMember("C").GetPublicSymbol(), symbols); + } + + [Fact] + public void Cref_01() + { + var source = """ + file class C + { + public static void M() { } + } + + class Program + { + /// + /// In the same file as . + /// + public static void M() + { + + } + } + """; + + var compilation = CreateCompilation(source, parseOptions: TestOptions.RegularPreview.WithDocumentationMode(DocumentationMode.Diagnose)); + compilation.VerifyDiagnostics(); + } + + [Fact] + public void Cref_02() + { + var source = """ + file class C + { + public static void M() { } + } + """; + + var main = """ + class Program + { + /// + /// In a different file than . + /// + public static void M() + { + + } + } + """; + + var compilation = CreateCompilation(new[] { source, main }, parseOptions: TestOptions.RegularPreview.WithDocumentationMode(DocumentationMode.Diagnose)); + compilation.VerifyDiagnostics( + // (4,45): warning CS1574: XML comment has cref attribute 'C' that could not be resolved + // /// In a different file than . + Diagnostic(ErrorCode.WRN_BadXMLRef, "C").WithArguments("C").WithLocation(4, 45) + ); + } + + [Fact] + public void TopLevelStatements() + { + var source = """ + using System; + + C.M(); + + file class C + { + public static void M() + { + Console.Write(1); + } + } + """; + + var verifier = CompileAndVerify(source, expectedOutput: "1"); + verifier.VerifyDiagnostics(); + } + + [Fact] + public void StaticFileClass() + { + var source = """ + using System; + + C.M(); + + static file class C + { + public static void M() + { + Console.Write(1); + } + } + """; + + var verifier = CompileAndVerify(source, expectedOutput: "1"); + verifier.VerifyDiagnostics(); + } + + [Fact] + public void ExtensionMethod_01() + { + var source = """ + using System; + + "a".M(); + + static file class C + { + public static void M(this string s) + { + Console.Write(1); + } + } + """; + + var verifier = CompileAndVerify(source, expectedOutput: "1"); + verifier.VerifyDiagnostics(); + } + + [Fact] + public void ExtensionMethod_02() + { + var source1 = """ + "a".M(); // 1 + """; + + var source2 = """ + using System; + + static file class C + { + public static void M(this string s) + { + Console.Write(1); + } + } + """; + + var comp = CreateCompilation(new[] { source1, source2 }); + comp.VerifyDiagnostics( + // (1,5): error CS1061: 'string' does not contain a definition for 'M' and no accessible extension method 'M' accepting a first argument of type 'string' could be found (are you missing a using directive or an assembly reference?) + // "a".M(); // 1 + Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "M").WithArguments("string", "M").WithLocation(1, 5)); + } + + [Fact] + public void ExtensionMethod_03() + { + var source1 = """ + "a".M(); // 1 + """; + + var source2 = """ + using System; + + file class C + { + static class D + { + public static void M(this string s) // 2 + { + Console.Write(1); + } + } + } + """; + + var comp = CreateCompilation(new[] { source1, source2 }); + comp.VerifyDiagnostics( + // (1,5): error CS1061: 'string' does not contain a definition for 'M' and no accessible extension method 'M' accepting a first argument of type 'string' could be found (are you missing a using directive or an assembly reference?) + // "a".M(); // 1 + Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "M").WithArguments("string", "M").WithLocation(1, 5), + // (7,28): error CS1109: Extension methods must be defined in a top level static class; D is a nested class + // public static void M(this string s) // 2 + Diagnostic(ErrorCode.ERR_ExtensionMethodsDecl, "M").WithArguments("D").WithLocation(7, 28)); + } + + [Fact] + public void Alias_01() + { + var source = """ + namespace NS; + using C1 = NS.C; + + file class C + { + } + + class D : C1 { } // 1 + """; + + var comp = CreateCompilation(source); + comp.VerifyDiagnostics( + // (8,7): error CS9302: File type 'C' cannot be used as a base type of non-file type 'D'. + // class D : C1 { } // 1 + Diagnostic(ErrorCode.ERR_FileTypeBase, "D").WithArguments("NS.C", "NS.D").WithLocation(8, 7)); + } + + [Fact] + public void SymbolDisplay() + { + var source1 = """ + file class C1 + { + public static void M() { } + } + """; + + var source2 = """ + file class C2 + { + public static void M() { } + } + """; + + var comp = CreateCompilation(new[] + { + SyntaxFactory.ParseSyntaxTree(source1, TestOptions.RegularPreview), + SyntaxFactory.ParseSyntaxTree(source2, TestOptions.RegularPreview, path: "path/to/FileB.cs") + }); + comp.VerifyDiagnostics(); + + var c1 = comp.GetMember("C1"); + var c2 = comp.GetMember("C2"); + var format = SymbolDisplayFormat.TestFormat.WithCompilerInternalOptions(SymbolDisplayCompilerInternalOptions.IncludeContainingFileForFileTypes); + Assert.Equal("C1@", c1.ToDisplayString(format)); + Assert.Equal("C2@FileB", c2.ToDisplayString(format)); + + Assert.Equal("void C1@.M()", c1.GetMember("M").ToDisplayString(format)); + Assert.Equal("void C2@FileB.M()", c2.GetMember("M").ToDisplayString(format)); + } + + [Fact] + public void Script_01() + { + var source1 = """ + using System; + + C1.M(); + + file class C1 + { + public static void M() { } + } + """; + + var comp = CreateSubmission(source1, parseOptions: TestOptions.Script.WithLanguageVersion(LanguageVersion.Preview)); + comp.VerifyDiagnostics(); + } + + [Fact] + public void SystemVoid_01() + { + var source1 = """ + using System; + + void M(Void v) { } // PROTOTYPE(ft): error here for explicit use of System.Void? + + namespace System + { + file class Void { } + } + """; + + var comp = CreateCompilation(source1); + comp.VerifyDiagnostics( + // (3,6): warning CS8321: The local function 'M' is declared but never used + // void M(Void v) { } // PROTOTYPE(ft): error here for explicit use of System.Void? + Diagnostic(ErrorCode.WRN_UnreferencedLocalFunction, "M").WithArguments("M").WithLocation(3, 6)); + + var tree = comp.SyntaxTrees[0]; + var model = comp.GetSemanticModel(tree); + + var voidTypeSyntax = tree.GetRoot().DescendantNodes().OfType().Single().Type!; + var typeInfo = model.GetTypeInfo(voidTypeSyntax); + Assert.Equal("System.Void@", typeInfo.Type!.ToDisplayString(SymbolDisplayFormat.TestFormat.WithCompilerInternalOptions(SymbolDisplayCompilerInternalOptions.IncludeContainingFileForFileTypes))); + } + + // PROTOTYPE(ft): public API (INamedTypeSymbol.IsFile?) } diff --git a/src/Compilers/CSharp/Test/Syntax/Parsing/FileModifierParsingTests.cs b/src/Compilers/CSharp/Test/Syntax/Parsing/FileModifierParsingTests.cs index 14c5f663d3e76..64fe0727e2f4d 100644 --- a/src/Compilers/CSharp/Test/Syntax/Parsing/FileModifierParsingTests.cs +++ b/src/Compilers/CSharp/Test/Syntax/Parsing/FileModifierParsingTests.cs @@ -9,2672 +9,2761 @@ using Xunit; using Xunit.Abstractions; -namespace Microsoft.CodeAnalysis.CSharp.UnitTests +namespace Microsoft.CodeAnalysis.CSharp.UnitTests; + +public class FileModifierParsingTests : ParsingTests { - 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) { - public FileModifierParsingTests(ITestOutputHelper output) : base(output) { } + 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); - protected override SyntaxTree ParseTree(string text, CSharpParseOptions? options) + 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); { - return SyntaxFactory.ParseSyntaxTree(text, options ?? TestOptions.Regular); + N(SyntaxFacts.GetBaseTypeDeclarationKind(typeKeyword)); + { + N(SyntaxKind.FileKeyword); + N(typeKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); } + EOF(); + } - private void UsingNode(string text, params DiagnosticDescription[] expectedDiagnostics) + [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); { - UsingNode(text, options: null, expectedParsingDiagnostics: expectedDiagnostics); + 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(); + } - private new void UsingNode(string text, CSharpParseOptions? options, params DiagnosticDescription[] expectedDiagnostics) + [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); { - UsingNode(text, options, expectedParsingDiagnostics: expectedDiagnostics); + 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(); + } - private void UsingNode(string text, CSharpParseOptions? options = null, DiagnosticDescription[]? expectedParsingDiagnostics = null, DiagnosticDescription[]? expectedBindingDiagnostics = null) + [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); { - options ??= TestOptions.RegularPreview; - expectedParsingDiagnostics ??= Array.Empty(); - expectedBindingDiagnostics ??= expectedParsingDiagnostics; + 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(); + } - var tree = UsingTree(text, options); - Validate(text, (CSharpSyntaxNode)tree.GetRoot(), expectedParsingDiagnostics); + // 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(); + } - var comp = CreateCompilation(tree); - comp.VerifyDiagnostics(expectedBindingDiagnostics); + [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(); + } - [Theory] - [InlineData(SyntaxKind.ClassKeyword)] - [InlineData(SyntaxKind.StructKeyword)] - [InlineData(SyntaxKind.InterfaceKeyword)] - [InlineData(SyntaxKind.RecordKeyword)] - [InlineData(SyntaxKind.EnumKeyword)] - public void FileModifier_01(SyntaxKind typeKeyword) + // 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); { - UsingNode($$""" - file {{SyntaxFacts.GetText(typeKeyword)}} C { } - """); - N(SyntaxKind.CompilationUnit); + N(SyntaxKind.RecordStructDeclaration); { - N(SyntaxFacts.GetBaseTypeDeclarationKind(typeKeyword)); - { - N(SyntaxKind.FileKeyword); - N(typeKeyword); - N(SyntaxKind.IdentifierToken, "C"); - N(SyntaxKind.OpenBraceToken); - N(SyntaxKind.CloseBraceToken); - } - N(SyntaxKind.EndOfFileToken); + N(SyntaxKind.PartialKeyword); + N(SyntaxKind.FileKeyword); + N(SyntaxKind.RecordKeyword); + N(SyntaxKind.StructKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); } - EOF(); + N(SyntaxKind.EndOfFileToken); } + EOF(); + } - [Theory] - [InlineData(SyntaxKind.ClassKeyword)] - [InlineData(SyntaxKind.StructKeyword)] - [InlineData(SyntaxKind.InterfaceKeyword)] - [InlineData(SyntaxKind.RecordKeyword)] - public void FileModifier_02(SyntaxKind typeKeyword) + [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); { - UsingNode($$""" - file partial {{SyntaxFacts.GetText(typeKeyword)}} C { } - """); - N(SyntaxKind.CompilationUnit); + N(SyntaxKind.GlobalStatement); { - N(SyntaxFacts.GetBaseTypeDeclarationKind(typeKeyword)); + N(SyntaxKind.LocalDeclarationStatement); { - N(SyntaxKind.FileKeyword); - N(SyntaxKind.PartialKeyword); - N(typeKeyword); - N(SyntaxKind.IdentifierToken, "C"); - N(SyntaxKind.OpenBraceToken); - N(SyntaxKind.CloseBraceToken); + N(SyntaxKind.VariableDeclaration); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "file"); + } + N(SyntaxKind.VariableDeclarator); + { + N(SyntaxKind.IdentifierToken, "partial"); + } + } + M(SyntaxKind.SemicolonToken); } - N(SyntaxKind.EndOfFileToken); } - EOF(); + N(SyntaxKind.StructDeclaration); + { + N(SyntaxKind.StructKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); } + EOF(); + } - [Fact] - public void FileModifier_02_Enum() + [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); { - 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.IncompleteMember); + { + N(SyntaxKind.FileKeyword); + N(SyntaxKind.IdentifierName); { - N(SyntaxKind.FileKeyword); - N(SyntaxKind.PartialKeyword); - N(SyntaxKind.EnumKeyword); - N(SyntaxKind.IdentifierToken, "C"); - N(SyntaxKind.OpenBraceToken); - N(SyntaxKind.CloseBraceToken); + N(SyntaxKind.IdentifierToken, "partial"); } - N(SyntaxKind.EndOfFileToken); } - EOF(); + 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) + }); - [Theory] - [InlineData(SyntaxKind.ClassKeyword)] - [InlineData(SyntaxKind.StructKeyword)] - [InlineData(SyntaxKind.InterfaceKeyword)] - public void FileModifier_03(SyntaxKind typeKeyword) + N(SyntaxKind.CompilationUnit); { - 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.GlobalStatement); + { + N(SyntaxKind.LocalDeclarationStatement); { - N(SyntaxKind.LocalDeclarationStatement); + N(SyntaxKind.VariableDeclaration); { - N(SyntaxKind.VariableDeclaration); + N(SyntaxKind.IdentifierName); { - N(SyntaxKind.IdentifierName); - { - N(SyntaxKind.IdentifierToken, "partial"); - } - N(SyntaxKind.VariableDeclarator); - { - N(SyntaxKind.IdentifierToken, "file"); - } + N(SyntaxKind.IdentifierToken, "partial"); + } + N(SyntaxKind.VariableDeclarator); + { + N(SyntaxKind.IdentifierToken, "file"); } - M(SyntaxKind.SemicolonToken); } + M(SyntaxKind.SemicolonToken); } - N(SyntaxFacts.GetBaseTypeDeclarationKind(typeKeyword)); - { - N(typeKeyword); - N(SyntaxKind.IdentifierToken, "C"); - N(SyntaxKind.OpenBraceToken); - N(SyntaxKind.CloseBraceToken); - } - N(SyntaxKind.EndOfFileToken); } - EOF(); + N(SyntaxKind.StructDeclaration); + { + 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 as a single declaration here, but not other type kinds? - [Theory] - [InlineData(SyntaxKind.RecordKeyword)] - public void FileModifier_04(SyntaxKind typeKeyword) + [Fact] + public void FileModifier_09() + { + UsingNode($$""" + file abstract class C { } + """); + N(SyntaxKind.CompilationUnit); { - UsingNode($$""" - partial file {{SyntaxFacts.GetText(typeKeyword)}} C { } - """); - N(SyntaxKind.CompilationUnit); + N(SyntaxKind.ClassDeclaration); { - 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); + N(SyntaxKind.FileKeyword); + N(SyntaxKind.AbstractKeyword); + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); } - EOF(); + N(SyntaxKind.EndOfFileToken); } + EOF(); + } - [Fact] - public void FileModifier_05() + [Fact] + public void FileModifier_10() + { + UsingNode($$""" + abstract file class C { } + """); + N(SyntaxKind.CompilationUnit); { - UsingNode($$""" - file partial record struct C { } - """); - N(SyntaxKind.CompilationUnit); + N(SyntaxKind.ClassDeclaration); { - 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); + N(SyntaxKind.AbstractKeyword); + N(SyntaxKind.FileKeyword); + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); } - EOF(); + N(SyntaxKind.EndOfFileToken); } + EOF(); + } - // PROTOTYPE(ft): is it fine that records parse here, but not other type kinds? - [Fact] - public void FileModifier_06() + [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 { } + """, + expectedBindingDiagnostics: new[] + { + // (1,20): error CS9301: File type 'C' cannot use accessibility modifiers. + // public file {{SyntaxFacts.GetText(typeKeyword)}} C { } + Diagnostic(ErrorCode.ERR_FileTypeNoExplicitAccessibility, "C").WithArguments("C") + }); + N(SyntaxKind.CompilationUnit); { - UsingNode($$""" - partial file record struct C { } - """); - N(SyntaxKind.CompilationUnit); + N(SyntaxFacts.GetBaseTypeDeclarationKind(typeKeyword)); { - 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); + N(SyntaxKind.PublicKeyword); + N(SyntaxKind.FileKeyword); + N(typeKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); } - EOF(); + N(SyntaxKind.EndOfFileToken); } + EOF(); + } - [Fact] - public void FileModifier_07_CSharp10() + [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 { } + """, + expectedBindingDiagnostics: new[] + { + // (1,19): error CS9301: File type 'C' cannot use accessibility modifiers. + // file public {{SyntaxFacts.GetText(typeKeyword)}} C { } + Diagnostic(ErrorCode.ERR_FileTypeNoExplicitAccessibility, "C").WithArguments("C") + }); + N(SyntaxKind.CompilationUnit); { - 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); + N(SyntaxFacts.GetBaseTypeDeclarationKind(typeKeyword)); + { + N(SyntaxKind.FileKeyword); + N(SyntaxKind.PublicKeyword); + N(typeKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); } - EOF(); + N(SyntaxKind.EndOfFileToken); } + EOF(); + } - [Fact] - public void FileModifier_07() + [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); { - 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.ClassDeclaration); { - 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); + N(SyntaxKind.FileKeyword); + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); } - EOF(); + N(SyntaxKind.EndOfFileToken); } + EOF(); + } + + [Fact] + public void FileModifier_14() + { + UsingNode(""" + file delegate void D(); + """); - [Fact] - public void FileModifier_08() + N(SyntaxKind.CompilationUnit); { - 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.DelegateDeclaration); + { + N(SyntaxKind.FileKeyword); + N(SyntaxKind.DelegateKeyword); + N(SyntaxKind.PredefinedType); { - 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.VoidKeyword); } - N(SyntaxKind.StructDeclaration); + N(SyntaxKind.IdentifierToken, "D"); + N(SyntaxKind.ParameterList); { - N(SyntaxKind.StructKeyword); - N(SyntaxKind.IdentifierToken, "C"); - N(SyntaxKind.OpenBraceToken); - N(SyntaxKind.CloseBraceToken); + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.CloseParenToken); } - N(SyntaxKind.EndOfFileToken); + N(SyntaxKind.SemicolonToken); } - EOF(); + N(SyntaxKind.EndOfFileToken); } + EOF(); + } + + [Fact] + public void FileModifier_15() + { + UsingNode(""" + namespace NS + { + file class C { } + } + """); - [Fact] - public void FileModifier_09() + N(SyntaxKind.CompilationUnit); { - UsingNode($$""" - file abstract 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.AbstractKeyword); N(SyntaxKind.ClassKeyword); N(SyntaxKind.IdentifierToken, "C"); N(SyntaxKind.OpenBraceToken); N(SyntaxKind.CloseBraceToken); } - N(SyntaxKind.EndOfFileToken); + N(SyntaxKind.CloseBraceToken); } - EOF(); + N(SyntaxKind.EndOfFileToken); } + EOF(); + } - [Fact] - public void FileModifier_10() + [Fact] + public void FileModifier_16() + { + UsingNode(""" + namespace NS; + file class C { } + """); + + N(SyntaxKind.CompilationUnit); { - UsingNode($$""" - abstract 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.AbstractKeyword); N(SyntaxKind.FileKeyword); N(SyntaxKind.ClassKeyword); N(SyntaxKind.IdentifierToken, "C"); N(SyntaxKind.OpenBraceToken); N(SyntaxKind.CloseBraceToken); } - N(SyntaxKind.EndOfFileToken); } - EOF(); + 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); + [Fact] + public void FileModifier_17() + { + UsingNode(""" + class Outer { - 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); + file class C { } } - EOF(); - } + """); - [Theory] - [InlineData(SyntaxKind.ClassKeyword)] - [InlineData(SyntaxKind.StructKeyword)] - [InlineData(SyntaxKind.InterfaceKeyword)] - [InlineData(SyntaxKind.RecordKeyword)] - [InlineData(SyntaxKind.EnumKeyword)] - public void FileModifier_12(SyntaxKind typeKeyword) + N(SyntaxKind.CompilationUnit); { - UsingNode($$""" - file public {{SyntaxFacts.GetText(typeKeyword)}} C { } - """); - N(SyntaxKind.CompilationUnit); + N(SyntaxKind.ClassDeclaration); { - N(SyntaxFacts.GetBaseTypeDeclarationKind(typeKeyword)); + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "Outer"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.ClassDeclaration); { N(SyntaxKind.FileKeyword); - N(SyntaxKind.PublicKeyword); - N(typeKeyword); + N(SyntaxKind.ClassKeyword); N(SyntaxKind.IdentifierToken, "C"); N(SyntaxKind.OpenBraceToken); N(SyntaxKind.CloseBraceToken); } - N(SyntaxKind.EndOfFileToken); + N(SyntaxKind.CloseBraceToken); } - EOF(); + 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) + }); - [Fact] - public void FileModifier_13() + N(SyntaxKind.CompilationUnit); { - 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.ClassDeclaration); + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.MethodDeclaration); { N(SyntaxKind.FileKeyword); - N(SyntaxKind.ClassKeyword); - N(SyntaxKind.IdentifierToken, "C"); - N(SyntaxKind.OpenBraceToken); - N(SyntaxKind.CloseBraceToken); + 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.EndOfFileToken); + N(SyntaxKind.CloseBraceToken); } - EOF(); + N(SyntaxKind.EndOfFileToken); } + EOF(); + } - [Fact] - public void FileModifier_14() + [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); { - UsingNode(""" - file delegate void D(); - """); - - N(SyntaxKind.CompilationUnit); + N(SyntaxKind.ClassDeclaration); { - N(SyntaxKind.DelegateDeclaration); + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.MethodDeclaration); { N(SyntaxKind.FileKeyword); - N(SyntaxKind.DelegateKeyword); N(SyntaxKind.PredefinedType); { N(SyntaxKind.VoidKeyword); } - N(SyntaxKind.IdentifierToken, "D"); + N(SyntaxKind.IdentifierToken, "M"); N(SyntaxKind.ParameterList); { N(SyntaxKind.OpenParenToken); N(SyntaxKind.CloseParenToken); } - N(SyntaxKind.SemicolonToken); + N(SyntaxKind.Block); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } } - N(SyntaxKind.EndOfFileToken); + N(SyntaxKind.CloseBraceToken); } - EOF(); + N(SyntaxKind.EndOfFileToken); } + EOF(); + } - [Fact] - public void FileModifier_15() + [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); { - UsingNode(""" - namespace NS + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.FieldDeclaration); { - file class C { } + 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(); + } - N(SyntaxKind.CompilationUnit); + [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.NamespaceDeclaration); + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.EventFieldDeclaration); { - N(SyntaxKind.NamespaceKeyword); - N(SyntaxKind.IdentifierName); - { - N(SyntaxKind.IdentifierToken, "NS"); - } - N(SyntaxKind.OpenBraceToken); - N(SyntaxKind.ClassDeclaration); + N(SyntaxKind.FileKeyword); + N(SyntaxKind.EventKeyword); + N(SyntaxKind.VariableDeclaration); { - N(SyntaxKind.FileKeyword); - N(SyntaxKind.ClassKeyword); - N(SyntaxKind.IdentifierToken, "C"); - N(SyntaxKind.OpenBraceToken); - N(SyntaxKind.CloseBraceToken); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Action"); + } + N(SyntaxKind.VariableDeclarator); + { + N(SyntaxKind.IdentifierToken, "x"); + } } - N(SyntaxKind.CloseBraceToken); + N(SyntaxKind.SemicolonToken); } - N(SyntaxKind.EndOfFileToken); + N(SyntaxKind.CloseBraceToken); } - EOF(); + N(SyntaxKind.EndOfFileToken); } + EOF(); + } - [Fact] - public void FileModifier_16() - { - UsingNode(""" - namespace NS; - file class C { } - """); + [Fact] + public void FileMember_04() + { + var source = $$""" + class C + { + file int x { get; set; } + } + """; - N(SyntaxKind.CompilationUnit); + 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.FileScopedNamespaceDeclaration); + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.PropertyDeclaration); { - N(SyntaxKind.NamespaceKeyword); - N(SyntaxKind.IdentifierName); + N(SyntaxKind.FileKeyword); + N(SyntaxKind.PredefinedType); { - N(SyntaxKind.IdentifierToken, "NS"); + N(SyntaxKind.IntKeyword); } - N(SyntaxKind.SemicolonToken); - N(SyntaxKind.ClassDeclaration); + N(SyntaxKind.IdentifierToken, "x"); + N(SyntaxKind.AccessorList); { - N(SyntaxKind.FileKeyword); - N(SyntaxKind.ClassKeyword); - N(SyntaxKind.IdentifierToken, "C"); 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.EndOfFileToken); + N(SyntaxKind.CloseBraceToken); } - EOF(); + N(SyntaxKind.EndOfFileToken); } + EOF(); + } - [Fact] - public void FileModifier_17() - { - UsingNode(""" - class Outer - { - file class C { } - } - """); + [Fact] + public void FileMember_05() + { + var source = $$""" + class C + { + async file void M() { } + } + """; - N(SyntaxKind.CompilationUnit); + 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.ClassDeclaration); + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.MethodDeclaration); { - N(SyntaxKind.ClassKeyword); - N(SyntaxKind.IdentifierToken, "Outer"); - N(SyntaxKind.OpenBraceToken); - N(SyntaxKind.ClassDeclaration); + 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.FileKeyword); - N(SyntaxKind.ClassKeyword); - N(SyntaxKind.IdentifierToken, "C"); N(SyntaxKind.OpenBraceToken); N(SyntaxKind.CloseBraceToken); } - N(SyntaxKind.CloseBraceToken); } - N(SyntaxKind.EndOfFileToken); + N(SyntaxKind.CloseBraceToken); } - EOF(); + 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) + }); - [Fact] - public void FileModifier_18() + N(SyntaxKind.CompilationUnit); { - 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.ClassDeclaration); + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.FieldDeclaration); { - N(SyntaxKind.ClassKeyword); - N(SyntaxKind.IdentifierToken, "C"); - N(SyntaxKind.OpenBraceToken); - N(SyntaxKind.MethodDeclaration); + N(SyntaxKind.VariableDeclaration); { - N(SyntaxKind.FileKeyword); - N(SyntaxKind.FunctionPointerType); + N(SyntaxKind.PredefinedType); { - 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.IntKeyword); } - N(SyntaxKind.IdentifierToken, "M"); - N(SyntaxKind.ParameterList); + N(SyntaxKind.VariableDeclarator); { - N(SyntaxKind.OpenParenToken); - N(SyntaxKind.CloseParenToken); + N(SyntaxKind.IdentifierToken, "file"); } - N(SyntaxKind.SemicolonToken); } - N(SyntaxKind.CloseBraceToken); + N(SyntaxKind.SemicolonToken); } - N(SyntaxKind.EndOfFileToken); + N(SyntaxKind.CloseBraceToken); } - EOF(); + N(SyntaxKind.EndOfFileToken); } + EOF(); + } + + [Fact] + public void MemberNamedFile_02() + { + UsingNode($$""" + class C + { + int file { get; set; } + } + """); - [Fact] - public void FileMember_01() + N(SyntaxKind.CompilationUnit); { - 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.ClassDeclaration); + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.PropertyDeclaration); { - N(SyntaxKind.ClassKeyword); - N(SyntaxKind.IdentifierToken, "C"); - N(SyntaxKind.OpenBraceToken); - N(SyntaxKind.MethodDeclaration); + N(SyntaxKind.PredefinedType); { - N(SyntaxKind.FileKeyword); - N(SyntaxKind.PredefinedType); - { - N(SyntaxKind.VoidKeyword); - } - N(SyntaxKind.IdentifierToken, "M"); - N(SyntaxKind.ParameterList); + N(SyntaxKind.IntKeyword); + } + N(SyntaxKind.IdentifierToken, "file"); + N(SyntaxKind.AccessorList); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.GetAccessorDeclaration); { - N(SyntaxKind.OpenParenToken); - N(SyntaxKind.CloseParenToken); + N(SyntaxKind.GetKeyword); + N(SyntaxKind.SemicolonToken); } - N(SyntaxKind.Block); + N(SyntaxKind.SetAccessorDeclaration); { - N(SyntaxKind.OpenBraceToken); - N(SyntaxKind.CloseBraceToken); + N(SyntaxKind.SetKeyword); + N(SyntaxKind.SemicolonToken); } + N(SyntaxKind.CloseBraceToken); } - N(SyntaxKind.CloseBraceToken); } - N(SyntaxKind.EndOfFileToken); + N(SyntaxKind.CloseBraceToken); } - EOF(); + 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) + }); - [Fact] - public void FileMember_02() + N(SyntaxKind.CompilationUnit); { - 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.ClassDeclaration); + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.EventFieldDeclaration); { - N(SyntaxKind.ClassKeyword); - N(SyntaxKind.IdentifierToken, "C"); - N(SyntaxKind.OpenBraceToken); - N(SyntaxKind.FieldDeclaration); + N(SyntaxKind.EventKeyword); + N(SyntaxKind.VariableDeclaration); { - N(SyntaxKind.FileKeyword); - N(SyntaxKind.VariableDeclaration); + N(SyntaxKind.IdentifierName); { - N(SyntaxKind.PredefinedType); - { - N(SyntaxKind.IntKeyword); - } - N(SyntaxKind.VariableDeclarator); - { - N(SyntaxKind.IdentifierToken, "x"); - } + N(SyntaxKind.IdentifierToken, "Action"); + } + N(SyntaxKind.VariableDeclarator); + { + N(SyntaxKind.IdentifierToken, "file"); } - N(SyntaxKind.SemicolonToken); } - N(SyntaxKind.CloseBraceToken); + N(SyntaxKind.SemicolonToken); } - N(SyntaxKind.EndOfFileToken); + N(SyntaxKind.CloseBraceToken); } - EOF(); + N(SyntaxKind.EndOfFileToken); } + EOF(); + } + + [Fact] + public void MemberNamedFile_04() + { + UsingNode($$""" + class C + { + void file() { } + } + """); - [Fact] - public void FileMember_03() + N(SyntaxKind.CompilationUnit); { - 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.ClassDeclaration); + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.MethodDeclaration); { - N(SyntaxKind.ClassKeyword); - N(SyntaxKind.IdentifierToken, "C"); - N(SyntaxKind.OpenBraceToken); - N(SyntaxKind.EventFieldDeclaration); + N(SyntaxKind.PredefinedType); { - 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.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); + N(SyntaxKind.CloseBraceToken); } - EOF(); + 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) + }); - [Fact] - public void FileMember_04() + N(SyntaxKind.CompilationUnit); { - var source = $$""" - class C - { - file int x { get; set; } - } - """; + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.FileKeyword); + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "file"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } - UsingNode(source, expectedBindingDiagnostics: new[] + [Fact] + public void MemberNamedFile_06_CSharp10() + { + UsingNode($$""" + class C { - // (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) + 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.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); { - N(SyntaxKind.ClassDeclaration); + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.FieldDeclaration); { - N(SyntaxKind.ClassKeyword); - N(SyntaxKind.IdentifierToken, "C"); - N(SyntaxKind.OpenBraceToken); - N(SyntaxKind.PropertyDeclaration); + N(SyntaxKind.VariableDeclaration); { - N(SyntaxKind.FileKeyword); - N(SyntaxKind.PredefinedType); + N(SyntaxKind.IdentifierName); { - N(SyntaxKind.IntKeyword); + N(SyntaxKind.IdentifierToken, "file"); } - N(SyntaxKind.IdentifierToken, "x"); - N(SyntaxKind.AccessorList); + N(SyntaxKind.VariableDeclarator); { - 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.IdentifierToken, "async"); } } - N(SyntaxKind.CloseBraceToken); + N(SyntaxKind.SemicolonToken); } - N(SyntaxKind.EndOfFileToken); + N(SyntaxKind.CloseBraceToken); } - EOF(); + 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)); - [Fact] - public void FileMember_05() + N(SyntaxKind.CompilationUnit); { - var source = $$""" - class C + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.IncompleteMember); { - async file void M() { } + N(SyntaxKind.FileKeyword); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "async"); + } } - """; + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } - UsingNode(source, expectedBindingDiagnostics: new[] + [Fact] + public void MemberNamedFile_07_CSharp10() + { + UsingNode($$""" + class C { - // (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) + 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.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); { - N(SyntaxKind.ClassDeclaration); + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.FieldDeclaration); { - N(SyntaxKind.ClassKeyword); - N(SyntaxKind.IdentifierToken, "C"); - N(SyntaxKind.OpenBraceToken); - N(SyntaxKind.MethodDeclaration); + N(SyntaxKind.VariableDeclaration); { - N(SyntaxKind.AsyncKeyword); - N(SyntaxKind.FileKeyword); - N(SyntaxKind.PredefinedType); - { - N(SyntaxKind.VoidKeyword); - } - N(SyntaxKind.IdentifierToken, "M"); - N(SyntaxKind.ParameterList); + N(SyntaxKind.IdentifierName); { - N(SyntaxKind.OpenParenToken); - N(SyntaxKind.CloseParenToken); + N(SyntaxKind.IdentifierToken, "file"); } - N(SyntaxKind.Block); + N(SyntaxKind.VariableDeclarator); { - N(SyntaxKind.OpenBraceToken); - N(SyntaxKind.CloseBraceToken); + N(SyntaxKind.IdentifierToken, "item"); } } - N(SyntaxKind.CloseBraceToken); + N(SyntaxKind.SemicolonToken); } - N(SyntaxKind.EndOfFileToken); + N(SyntaxKind.CloseBraceToken); } - EOF(); + 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) - }); + // 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.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); { - N(SyntaxKind.ClassDeclaration); + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.IncompleteMember); { - N(SyntaxKind.ClassKeyword); - N(SyntaxKind.IdentifierToken, "C"); - N(SyntaxKind.OpenBraceToken); - N(SyntaxKind.FieldDeclaration); + N(SyntaxKind.FileKeyword); + N(SyntaxKind.IdentifierName); { - N(SyntaxKind.VariableDeclaration); - { - N(SyntaxKind.PredefinedType); - { - N(SyntaxKind.IntKeyword); - } - N(SyntaxKind.VariableDeclarator); - { - N(SyntaxKind.IdentifierToken, "file"); - } - } - N(SyntaxKind.SemicolonToken); + N(SyntaxKind.IdentifierToken, "item"); } - N(SyntaxKind.CloseBraceToken); } - N(SyntaxKind.EndOfFileToken); + 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); } - EOF(); + 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)); - [Fact] - public void MemberNamedFile_02() + N(SyntaxKind.CompilationUnit); { - UsingNode($$""" - class C + N(SyntaxKind.IncompleteMember); + { + N(SyntaxKind.IdentifierName); { - int file { get; set; } + 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.CompilationUnit); + { + N(SyntaxKind.IncompleteMember); { - N(SyntaxKind.ClassDeclaration); + 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.ClassKeyword); - N(SyntaxKind.IdentifierToken, "C"); - N(SyntaxKind.OpenBraceToken); - N(SyntaxKind.PropertyDeclaration); + N(SyntaxKind.IdentifierName); { - 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.SemicolonToken); } - N(SyntaxKind.EndOfFileToken); } - EOF(); + 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) - }); + [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.CompilationUnit); + { + N(SyntaxKind.IncompleteMember); { - N(SyntaxKind.ClassDeclaration); + N(SyntaxKind.FileKeyword); + } + N(SyntaxKind.GlobalStatement); + { + N(SyntaxKind.EmptyStatement); { - 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.SemicolonToken); } - N(SyntaxKind.EndOfFileToken); } - EOF(); + N(SyntaxKind.EndOfFileToken); } + EOF(); + } - [Fact] - public void MemberNamedFile_04() + [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); { - UsingNode($$""" - class C + N(SyntaxKind.IncompleteMember); + { + N(SyntaxKind.IdentifierName); { - void file() { } + N(SyntaxKind.IdentifierToken, "file"); } - """); - - N(SyntaxKind.CompilationUnit); + } + N(SyntaxKind.FileScopedNamespaceDeclaration); { - N(SyntaxKind.ClassDeclaration); + N(SyntaxKind.NamespaceKeyword); + N(SyntaxKind.IdentifierName); { - 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.IdentifierToken, "NS"); } - N(SyntaxKind.EndOfFileToken); + N(SyntaxKind.SemicolonToken); } - EOF(); + 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) - }); + [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.CompilationUnit); + { + N(SyntaxKind.FileScopedNamespaceDeclaration); { - N(SyntaxKind.ClassDeclaration); + N(SyntaxKind.FileKeyword); + N(SyntaxKind.NamespaceKeyword); + N(SyntaxKind.IdentifierName); { - N(SyntaxKind.FileKeyword); - N(SyntaxKind.ClassKeyword); - N(SyntaxKind.IdentifierToken, "file"); - N(SyntaxKind.OpenBraceToken); - N(SyntaxKind.CloseBraceToken); + N(SyntaxKind.IdentifierToken, "NS"); } - N(SyntaxKind.EndOfFileToken); + N(SyntaxKind.SemicolonToken); } - EOF(); + 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) + }); - [Fact] - public void MemberNamedFile_06_CSharp10() + N(SyntaxKind.CompilationUnit); { - UsingNode($$""" - class C + N(SyntaxKind.IncompleteMember); + { + N(SyntaxKind.IdentifierName); { - file async; + N(SyntaxKind.IdentifierToken, "file"); } - """, - 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.NamespaceDeclaration); { - N(SyntaxKind.ClassDeclaration); + N(SyntaxKind.NamespaceKeyword); + N(SyntaxKind.IdentifierName); { - 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.IdentifierToken, "NS"); } - N(SyntaxKind.EndOfFileToken); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); } - EOF(); + 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) + }); - [Fact] - public void MemberNamedFile_06() + N(SyntaxKind.CompilationUnit); { - UsingNode($$""" - class C + N(SyntaxKind.NamespaceDeclaration); + { + N(SyntaxKind.FileKeyword); + N(SyntaxKind.NamespaceKeyword); + N(SyntaxKind.IdentifierName); { - file async; + N(SyntaxKind.IdentifierToken, "NS"); } - """, - // (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.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } - N(SyntaxKind.CompilationUnit); + [Fact] + public void File_Repeated() + { + const int FileModifiersCount = 100000; + var manyFileModifiers = string.Join(" ", Enumerable.Repeat("file", FileModifiersCount)); + UsingNode(manyFileModifiers, + expectedParsingDiagnostics: new[] { - N(SyntaxKind.ClassDeclaration); + Diagnostic(ErrorCode.ERR_NamespaceUnexpected, "file").WithLocation(1, 499996) + }); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.IncompleteMember); + { + for (var i = 0; i < FileModifiersCount; i++) { - 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.FileKeyword); } N(SyntaxKind.EndOfFileToken); } - EOF(); } + 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) + }); - [Fact] - public void MemberNamedFile_07_CSharp10() + N(SyntaxKind.CompilationUnit); { - UsingNode($$""" - class C + N(SyntaxKind.ClassDeclaration); + { + for (int i = 0; i < FileModifiersCount; i++) { - file item; + N(SyntaxKind.FileKeyword); } - """, - 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.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.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); { - N(SyntaxKind.ClassDeclaration); + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.MethodDeclaration); { - N(SyntaxKind.ClassKeyword); - N(SyntaxKind.IdentifierToken, "C"); - N(SyntaxKind.OpenBraceToken); - N(SyntaxKind.FieldDeclaration); + N(SyntaxKind.IdentifierName); { - N(SyntaxKind.VariableDeclaration); - { - N(SyntaxKind.IdentifierName); - { - N(SyntaxKind.IdentifierToken, "file"); - } - N(SyntaxKind.VariableDeclarator); - { - N(SyntaxKind.IdentifierToken, "item"); - } - } - N(SyntaxKind.SemicolonToken); + N(SyntaxKind.IdentifierToken, "file"); } - 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.IdentifierToken, "record"); + N(SyntaxKind.ParameterList); { - N(SyntaxKind.FileKeyword); - N(SyntaxKind.IdentifierName); - { - N(SyntaxKind.IdentifierToken, "item"); - } + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.CloseParenToken); } - N(SyntaxKind.CloseBraceToken); + N(SyntaxKind.SemicolonToken); } - N(SyntaxKind.EndOfFileToken); + N(SyntaxKind.CloseBraceToken); } - EOF(); + N(SyntaxKind.EndOfFileToken); } - [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) - }); + EOF(); + } - N(SyntaxKind.CompilationUnit); + [Fact] + public void MethodNamedRecord_01_CSharpNext() + { + UsingNode(""" + class C { - N(SyntaxKind.RecordDeclaration); - { - N(SyntaxKind.RecordKeyword); - N(SyntaxKind.IdentifierToken, "file"); - N(SyntaxKind.OpenBraceToken); - N(SyntaxKind.CloseBraceToken); - } - N(SyntaxKind.EndOfFileToken); + file record(); } - 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); + """, + expectedBindingDiagnostics: new[] { - N(SyntaxKind.IncompleteMember); - { - N(SyntaxKind.IdentifierName); - { - N(SyntaxKind.IdentifierToken, "file"); - } - } - N(SyntaxKind.EndOfFileToken); - } - EOF(); - } + // (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) + }); - [Fact] - public void Errors_01() + N(SyntaxKind.CompilationUnit); { - 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.ClassDeclaration); { - N(SyntaxKind.IncompleteMember); + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.ConstructorDeclaration); { 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.IdentifierToken, "record"); + N(SyntaxKind.ParameterList); { - N(SyntaxKind.IdentifierName); - { - N(SyntaxKind.IdentifierToken, "file"); - } - N(SyntaxKind.SemicolonToken); + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.CloseParenToken); } + N(SyntaxKind.SemicolonToken); } - N(SyntaxKind.EndOfFileToken); + N(SyntaxKind.CloseBraceToken); } - EOF(); + 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); + [Fact] + public void MethodNamedRecord_02_CSharp8() + { + UsingNode(""" + class C { - N(SyntaxKind.IncompleteMember); - { - N(SyntaxKind.FileKeyword); - } - N(SyntaxKind.GlobalStatement); - { - N(SyntaxKind.EmptyStatement); - { - N(SyntaxKind.SemicolonToken); - } - } - N(SyntaxKind.EndOfFileToken); + file record() { } } - EOF(); - } + """, + 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) + }); - [Fact] - public void Errors_03_CSharp10() + N(SyntaxKind.CompilationUnit); { - 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.ClassDeclaration); { - N(SyntaxKind.IncompleteMember); + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.MethodDeclaration); { N(SyntaxKind.IdentifierName); { N(SyntaxKind.IdentifierToken, "file"); } - } - N(SyntaxKind.FileScopedNamespaceDeclaration); - { - N(SyntaxKind.NamespaceKeyword); - N(SyntaxKind.IdentifierName); + N(SyntaxKind.IdentifierToken, "record"); + N(SyntaxKind.ParameterList); { - N(SyntaxKind.IdentifierToken, "NS"); + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.Block); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); } - N(SyntaxKind.SemicolonToken); } - N(SyntaxKind.EndOfFileToken); + N(SyntaxKind.CloseBraceToken); } - EOF(); + 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); + [Fact] + public void MethodNamedRecord_02_CSharpNext() + { + UsingNode(""" + class C { - N(SyntaxKind.FileScopedNamespaceDeclaration); - { - N(SyntaxKind.FileKeyword); - N(SyntaxKind.NamespaceKeyword); - N(SyntaxKind.IdentifierName); - { - N(SyntaxKind.IdentifierToken, "NS"); - } - N(SyntaxKind.SemicolonToken); - } - N(SyntaxKind.EndOfFileToken); + file record() { } } - EOF(); - } + """, 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) + }); - [Fact] - public void Errors_04_CSharp10() + N(SyntaxKind.CompilationUnit); { - 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.ClassDeclaration); { - N(SyntaxKind.IncompleteMember); + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.ConstructorDeclaration); { - N(SyntaxKind.IdentifierName); + N(SyntaxKind.FileKeyword); + N(SyntaxKind.IdentifierToken, "record"); + N(SyntaxKind.ParameterList); { - N(SyntaxKind.IdentifierToken, "file"); + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.CloseParenToken); } - } - N(SyntaxKind.NamespaceDeclaration); - { - N(SyntaxKind.NamespaceKeyword); - N(SyntaxKind.IdentifierName); + N(SyntaxKind.Block); { - N(SyntaxKind.IdentifierToken, "NS"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); } - N(SyntaxKind.OpenBraceToken); - N(SyntaxKind.CloseBraceToken); } - N(SyntaxKind.EndOfFileToken); + N(SyntaxKind.CloseBraceToken); } - EOF(); + 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) - }); + [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.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); { - N(SyntaxKind.NamespaceDeclaration); + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.MethodDeclaration); { N(SyntaxKind.FileKeyword); - N(SyntaxKind.NamespaceKeyword); N(SyntaxKind.IdentifierName); { - N(SyntaxKind.IdentifierToken, "NS"); + N(SyntaxKind.IdentifierToken, "record"); } - 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.IdentifierToken, "X"); + N(SyntaxKind.ParameterList); { - N(SyntaxKind.FileKeyword); + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.CloseParenToken); } - N(SyntaxKind.EndOfFileToken); + N(SyntaxKind.SemicolonToken); } + N(SyntaxKind.CloseBraceToken); } - 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.EndOfFileToken); + } + EOF(); + } - N(SyntaxKind.CompilationUnit); + [Fact] + public void FileRecord_01_CSharpNext() + { + UsingNode(""" + class C { - 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); + file record X(); } - EOF(); - } + """); - [Fact] - public void MethodNamedRecord_01_CSharp8() + N(SyntaxKind.CompilationUnit); { - 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.ClassDeclaration); + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.RecordDeclaration); { - N(SyntaxKind.ClassKeyword); - N(SyntaxKind.IdentifierToken, "C"); - N(SyntaxKind.OpenBraceToken); - N(SyntaxKind.MethodDeclaration); + N(SyntaxKind.FileKeyword); + N(SyntaxKind.RecordKeyword); + N(SyntaxKind.IdentifierToken, "X"); + N(SyntaxKind.ParameterList); { - 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.OpenParenToken); + N(SyntaxKind.CloseParenToken); } - N(SyntaxKind.CloseBraceToken); + N(SyntaxKind.SemicolonToken); } - N(SyntaxKind.EndOfFileToken); + N(SyntaxKind.CloseBraceToken); } - EOF(); + 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) - }); + [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.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); { - N(SyntaxKind.ClassDeclaration); + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.MethodDeclaration); { - N(SyntaxKind.ClassKeyword); - N(SyntaxKind.IdentifierToken, "C"); - N(SyntaxKind.OpenBraceToken); - N(SyntaxKind.ConstructorDeclaration); + N(SyntaxKind.FileKeyword); + N(SyntaxKind.IdentifierName); { - 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.IdentifierToken, "X"); + N(SyntaxKind.ParameterList); { - 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.OpenParenToken); + N(SyntaxKind.CloseParenToken); } - 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.Block); { - 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.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); } - N(SyntaxKind.CloseBraceToken); } - N(SyntaxKind.EndOfFileToken); + N(SyntaxKind.CloseBraceToken); } - EOF(); + 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); + [Fact] + public void FileRecord_02_CSharpNext() + { + UsingNode(""" + class C { - 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); + file record X() { } } - EOF(); - } + """); - [Fact] - public void FileRecord_01_CSharpNext() + N(SyntaxKind.CompilationUnit); { - UsingNode(""" - class C - { - file record X(); - } - """); - - N(SyntaxKind.CompilationUnit); + N(SyntaxKind.ClassDeclaration); { - N(SyntaxKind.ClassDeclaration); + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.RecordDeclaration); { - 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.FileKeyword); - N(SyntaxKind.RecordKeyword); - N(SyntaxKind.IdentifierToken, "X"); - N(SyntaxKind.ParameterList); - { - N(SyntaxKind.OpenParenToken); - N(SyntaxKind.CloseParenToken); - } - N(SyntaxKind.SemicolonToken); + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.CloseParenToken); } + N(SyntaxKind.OpenBraceToken); N(SyntaxKind.CloseBraceToken); } - N(SyntaxKind.EndOfFileToken); + N(SyntaxKind.CloseBraceToken); } - EOF(); + 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) + }); - [Fact] - public void FileRecord_02_CSharp8() + N(SyntaxKind.CompilationUnit); { - 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.ClassDeclaration); + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.FieldDeclaration); { - N(SyntaxKind.ClassKeyword); - N(SyntaxKind.IdentifierToken, "C"); - N(SyntaxKind.OpenBraceToken); - N(SyntaxKind.MethodDeclaration); + N(SyntaxKind.FileKeyword); + N(SyntaxKind.VariableDeclaration); { - N(SyntaxKind.FileKeyword); N(SyntaxKind.IdentifierName); { N(SyntaxKind.IdentifierToken, "record"); } - N(SyntaxKind.IdentifierToken, "X"); - N(SyntaxKind.ParameterList); + N(SyntaxKind.VariableDeclarator); { - N(SyntaxKind.OpenParenToken); - N(SyntaxKind.CloseParenToken); - } - N(SyntaxKind.Block); - { - N(SyntaxKind.OpenBraceToken); - N(SyntaxKind.CloseBraceToken); + N(SyntaxKind.IdentifierToken, "X"); } } - N(SyntaxKind.CloseBraceToken); + N(SyntaxKind.SemicolonToken); } - N(SyntaxKind.EndOfFileToken); + N(SyntaxKind.CloseBraceToken); } - EOF(); + N(SyntaxKind.EndOfFileToken); } + EOF(); + } - [Fact] - public void FileRecord_02_CSharpNext() - { - UsingNode(""" - class C - { - file record X() { } - } - """); - - N(SyntaxKind.CompilationUnit); + [Fact] + public void FileRecord_03_CSharpNext() + { + UsingNode(""" + class C { - 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); + file record X; } - EOF(); - } + """); - [Fact] - public void FileRecord_03_CSharp8() + N(SyntaxKind.CompilationUnit); { - 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.ClassDeclaration); + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.RecordDeclaration); { - 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.FileKeyword); + N(SyntaxKind.RecordKeyword); + N(SyntaxKind.IdentifierToken, "X"); + N(SyntaxKind.SemicolonToken); } - N(SyntaxKind.EndOfFileToken); + N(SyntaxKind.CloseBraceToken); } - EOF(); + N(SyntaxKind.EndOfFileToken); } + EOF(); + } - [Fact] - public void FileRecord_03_CSharpNext() + [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); { - UsingNode(""" - class C - { - file record X; - } - """); - - N(SyntaxKind.CompilationUnit); + N(SyntaxKind.GlobalStatement); { - N(SyntaxKind.ClassDeclaration); + N(SyntaxKind.LocalFunctionStatement); { - N(SyntaxKind.ClassKeyword); - N(SyntaxKind.IdentifierToken, "C"); - N(SyntaxKind.OpenBraceToken); - N(SyntaxKind.RecordDeclaration); + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.VoidKeyword); + } + N(SyntaxKind.IdentifierToken, "M"); + N(SyntaxKind.ParameterList); { - N(SyntaxKind.FileKeyword); - N(SyntaxKind.RecordKeyword); - N(SyntaxKind.IdentifierToken, "X"); - N(SyntaxKind.SemicolonToken); + 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.CloseBraceToken); } - N(SyntaxKind.EndOfFileToken); } - EOF(); + N(SyntaxKind.EndOfFileToken); } + EOF(); + } - [Fact] - public void LocalVariable_01() + [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); { - 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.GlobalStatement); + { + N(SyntaxKind.LocalFunctionStatement); { - N(SyntaxKind.LocalFunctionStatement); + N(SyntaxKind.PredefinedType); { - N(SyntaxKind.PredefinedType); - { - N(SyntaxKind.VoidKeyword); - } - N(SyntaxKind.IdentifierToken, "M"); - N(SyntaxKind.ParameterList); - { - N(SyntaxKind.OpenParenToken); - N(SyntaxKind.CloseParenToken); - } - N(SyntaxKind.Block); + 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.OpenBraceToken); - N(SyntaxKind.LocalDeclarationStatement); + N(SyntaxKind.VariableDeclaration); { - N(SyntaxKind.VariableDeclaration); + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.IntKeyword); + } + N(SyntaxKind.VariableDeclarator); { - N(SyntaxKind.IdentifierName); - { - N(SyntaxKind.IdentifierToken, "file"); - } - N(SyntaxKind.VariableDeclarator); - { - N(SyntaxKind.IdentifierToken, "file"); - } + N(SyntaxKind.IdentifierToken, "file"); } - N(SyntaxKind.SemicolonToken); } - N(SyntaxKind.CloseBraceToken); + N(SyntaxKind.SemicolonToken); } + N(SyntaxKind.CloseBraceToken); } } - N(SyntaxKind.EndOfFileToken); } - EOF(); + N(SyntaxKind.EndOfFileToken); } + EOF(); + } - [Fact] - public void LocalVariable_02() + // 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); { - 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.GlobalStatement); + { + N(SyntaxKind.LocalDeclarationStatement); { - N(SyntaxKind.LocalFunctionStatement); + N(SyntaxKind.VariableDeclaration); { - N(SyntaxKind.PredefinedType); - { - N(SyntaxKind.VoidKeyword); - } - N(SyntaxKind.IdentifierToken, "M"); - N(SyntaxKind.ParameterList); + N(SyntaxKind.IdentifierName); { - N(SyntaxKind.OpenParenToken); - N(SyntaxKind.CloseParenToken); + N(SyntaxKind.IdentifierToken, "file"); } - N(SyntaxKind.Block); + N(SyntaxKind.VariableDeclarator); { - 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.IdentifierToken, "file"); } } + N(SyntaxKind.SemicolonToken); } - N(SyntaxKind.EndOfFileToken); } - EOF(); + N(SyntaxKind.EndOfFileToken); } + EOF(); + } - // PROTOTYPE(ft): confirm whether this breaking change is acceptable - [Fact] - public void TopLevelVariable_01_CSharp10() + [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); { - UsingNode(""" - file file; - """, - options: TestOptions.Regular10, - expectedBindingDiagnostics: new[] + N(SyntaxKind.IncompleteMember); + { + N(SyntaxKind.FileKeyword); + N(SyntaxKind.FileKeyword); + } + N(SyntaxKind.GlobalStatement); + { + N(SyntaxKind.EmptyStatement); { - // (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.SemicolonToken); + } + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } - N(SyntaxKind.CompilationUnit); + [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.GlobalStatement); + N(SyntaxKind.LocalDeclarationStatement); { - N(SyntaxKind.LocalDeclarationStatement); + N(SyntaxKind.VariableDeclaration); { - N(SyntaxKind.VariableDeclaration); + N(SyntaxKind.PredefinedType); { - N(SyntaxKind.IdentifierName); - { - N(SyntaxKind.IdentifierToken, "file"); - } - N(SyntaxKind.VariableDeclarator); - { - N(SyntaxKind.IdentifierToken, "file"); - } + N(SyntaxKind.IntKeyword); + } + N(SyntaxKind.VariableDeclarator); + { + N(SyntaxKind.IdentifierToken, "file"); } - N(SyntaxKind.SemicolonToken); } + N(SyntaxKind.SemicolonToken); } - N(SyntaxKind.EndOfFileToken); } - EOF(); + N(SyntaxKind.EndOfFileToken); } + EOF(); + } - [Fact] - public void TopLevelVariable_01() + [Fact] + public void TopLevelVariable_04() + { + // PROTOTYPE(ft): this should parse and compile without errors + // we will share a common solution with 'required' and 'scoped' here. + UsingNode(""" + bool file; + file = true; + """, + expectedParsingDiagnostics: new[] + { + // (2,1): error CS0116: A namespace cannot directly contain members such as fields, methods or statements + // file = true; + Diagnostic(ErrorCode.ERR_NamespaceUnexpected, "file").WithLocation(2, 1), + // (2,6): error CS1525: Invalid expression term '=' + // file = true; + Diagnostic(ErrorCode.ERR_InvalidExprTerm, "=").WithArguments("=").WithLocation(2, 6) + }, + expectedBindingDiagnostics: new[] + { + // (1,6): warning CS0168: The variable 'file' is declared but never used + // bool file; + Diagnostic(ErrorCode.WRN_UnreferencedVar, "file").WithArguments("file").WithLocation(1, 6), + // (2,1): error CS0116: A namespace cannot directly contain members such as fields, methods or statements + // file = true; + Diagnostic(ErrorCode.ERR_NamespaceUnexpected, "file").WithLocation(2, 1), + // (2,6): error CS1525: Invalid expression term '=' + // file = true; + Diagnostic(ErrorCode.ERR_InvalidExprTerm, "=").WithArguments("=").WithLocation(2, 6) + }); + N(SyntaxKind.CompilationUnit); { - 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.GlobalStatement); { - N(SyntaxKind.IncompleteMember); - { - N(SyntaxKind.FileKeyword); - N(SyntaxKind.FileKeyword); - } - N(SyntaxKind.GlobalStatement); + N(SyntaxKind.LocalDeclarationStatement); { - N(SyntaxKind.EmptyStatement); + N(SyntaxKind.VariableDeclaration); { - N(SyntaxKind.SemicolonToken); + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.BoolKeyword); + } + N(SyntaxKind.VariableDeclarator); + { + N(SyntaxKind.IdentifierToken, "file"); + } } + 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.IncompleteMember); { - N(SyntaxKind.GlobalStatement); + N(SyntaxKind.FileKeyword); + } + N(SyntaxKind.GlobalStatement); + { + N(SyntaxKind.ExpressionStatement); { - N(SyntaxKind.LocalDeclarationStatement); + N(SyntaxKind.SimpleAssignmentExpression); { - N(SyntaxKind.VariableDeclaration); + M(SyntaxKind.IdentifierName); { - N(SyntaxKind.PredefinedType); - { - N(SyntaxKind.IntKeyword); - } - N(SyntaxKind.VariableDeclarator); - { - N(SyntaxKind.IdentifierToken, "file"); - } + M(SyntaxKind.IdentifierToken); + } + N(SyntaxKind.EqualsToken); + N(SyntaxKind.TrueLiteralExpression); + { + N(SyntaxKind.TrueKeyword); } - N(SyntaxKind.SemicolonToken); } + N(SyntaxKind.SemicolonToken); } - N(SyntaxKind.EndOfFileToken); } - EOF(); + N(SyntaxKind.EndOfFileToken); } + EOF(); + } - [Fact] - public void LambdaReturn() + [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); { - 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.GlobalStatement); + { + N(SyntaxKind.ExpressionStatement); { - N(SyntaxKind.ExpressionStatement); + N(SyntaxKind.SimpleAssignmentExpression); { - N(SyntaxKind.SimpleAssignmentExpression); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "_"); + } + N(SyntaxKind.EqualsToken); + N(SyntaxKind.ParenthesizedLambdaExpression); { N(SyntaxKind.IdentifierName); { - N(SyntaxKind.IdentifierToken, "_"); + N(SyntaxKind.IdentifierToken, "file"); } - N(SyntaxKind.EqualsToken); - N(SyntaxKind.ParenthesizedLambdaExpression); + N(SyntaxKind.ParameterList); { - 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.OpenParenToken); + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.EqualsGreaterThanToken); + N(SyntaxKind.Block); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); } } - N(SyntaxKind.SemicolonToken); } + N(SyntaxKind.SemicolonToken); } - N(SyntaxKind.EndOfFileToken); } - EOF(); + N(SyntaxKind.EndOfFileToken); } + EOF(); + } - [Fact] - public void LocalFunctionReturn() + [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); { - 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.GlobalStatement); + { + N(SyntaxKind.LocalFunctionStatement); { - N(SyntaxKind.LocalFunctionStatement); + N(SyntaxKind.IdentifierName); { - 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.IdentifierToken, "file"); } - } - N(SyntaxKind.GlobalStatement); - { - N(SyntaxKind.EmptyStatement); + N(SyntaxKind.IdentifierToken, "local"); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.Block); { - N(SyntaxKind.SemicolonToken); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); } } - N(SyntaxKind.EndOfFileToken); } - EOF(); + N(SyntaxKind.GlobalStatement); + { + N(SyntaxKind.EmptyStatement); + { + N(SyntaxKind.SemicolonToken); + } + } + N(SyntaxKind.EndOfFileToken); } + EOF(); + } - [Fact] - public void ParameterModifier() + [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); { - 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.ClassDeclaration); + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.MethodDeclaration); { - N(SyntaxKind.ClassKeyword); - N(SyntaxKind.IdentifierToken, "C"); - N(SyntaxKind.OpenBraceToken); - N(SyntaxKind.MethodDeclaration); + N(SyntaxKind.PredefinedType); { - N(SyntaxKind.PredefinedType); - { - N(SyntaxKind.VoidKeyword); - } - N(SyntaxKind.IdentifierToken, "M"); - N(SyntaxKind.ParameterList); + N(SyntaxKind.VoidKeyword); + } + N(SyntaxKind.IdentifierToken, "M"); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.Parameter); { - N(SyntaxKind.OpenParenToken); - N(SyntaxKind.Parameter); - { - N(SyntaxKind.IdentifierName); - { - N(SyntaxKind.IdentifierToken, "file"); - } - M(SyntaxKind.IdentifierToken); - } - M(SyntaxKind.CommaToken); - N(SyntaxKind.Parameter); + N(SyntaxKind.IdentifierName); { - N(SyntaxKind.PredefinedType); - { - N(SyntaxKind.IntKeyword); - } - N(SyntaxKind.IdentifierToken, "x"); + N(SyntaxKind.IdentifierToken, "file"); } - N(SyntaxKind.CloseParenToken); + M(SyntaxKind.IdentifierToken); } - N(SyntaxKind.Block); + M(SyntaxKind.CommaToken); + N(SyntaxKind.Parameter); { - N(SyntaxKind.OpenBraceToken); - N(SyntaxKind.CloseBraceToken); + 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); + N(SyntaxKind.CloseBraceToken); } - EOF(); + N(SyntaxKind.EndOfFileToken); } + EOF(); + } - [Fact] - public void ParameterType() + [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); { - 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.ClassDeclaration); + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.MethodDeclaration); { - N(SyntaxKind.ClassKeyword); - N(SyntaxKind.IdentifierToken, "C"); - N(SyntaxKind.OpenBraceToken); - N(SyntaxKind.MethodDeclaration); + N(SyntaxKind.PredefinedType); { - N(SyntaxKind.PredefinedType); - { - N(SyntaxKind.VoidKeyword); - } - N(SyntaxKind.IdentifierToken, "M"); - N(SyntaxKind.ParameterList); + N(SyntaxKind.VoidKeyword); + } + N(SyntaxKind.IdentifierToken, "M"); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.Parameter); { - N(SyntaxKind.OpenParenToken); - N(SyntaxKind.Parameter); + N(SyntaxKind.IdentifierName); { - N(SyntaxKind.IdentifierName); - { - N(SyntaxKind.IdentifierToken, "file"); - } - N(SyntaxKind.IdentifierToken, "x"); + N(SyntaxKind.IdentifierToken, "file"); } - N(SyntaxKind.CloseParenToken); - } - N(SyntaxKind.Block); - { - N(SyntaxKind.OpenBraceToken); - N(SyntaxKind.CloseBraceToken); + N(SyntaxKind.IdentifierToken, "x"); } + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.Block); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); } - N(SyntaxKind.CloseBraceToken); } - N(SyntaxKind.EndOfFileToken); + N(SyntaxKind.CloseBraceToken); } - EOF(); + N(SyntaxKind.EndOfFileToken); } + EOF(); } } diff --git a/src/Compilers/Core/Portable/SymbolDisplay/SymbolDisplayCompilerInternalOptions.cs b/src/Compilers/Core/Portable/SymbolDisplay/SymbolDisplayCompilerInternalOptions.cs index 15ac4fbde7c89..afde53e15eb99 100644 --- a/src/Compilers/Core/Portable/SymbolDisplay/SymbolDisplayCompilerInternalOptions.cs +++ b/src/Compilers/Core/Portable/SymbolDisplay/SymbolDisplayCompilerInternalOptions.cs @@ -62,5 +62,10 @@ internal enum SymbolDisplayCompilerInternalOptions /// Display `System.[U]IntPtr` instead of `n[u]int`. /// UseNativeIntegerUnderlyingType = 1 << 7, + + /// + /// Display `MyType@File.cs` instead of `MyType`. + /// + IncludeContainingFileForFileTypes = 1 << 8, } } diff --git a/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/Binders/EEMethodBinder.cs b/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/Binders/EEMethodBinder.cs index 5b197c99e8a73..1b075b464548e 100644 --- a/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/Binders/EEMethodBinder.cs +++ b/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/Binders/EEMethodBinder.cs @@ -44,7 +44,8 @@ internal EEMethodBinder(EEMethodSymbol method, MethodSymbol containingMethod, Bi var substitutedSourceMethod = method.SubstitutedSourceMethod; _parameterOffset = substitutedSourceMethod.IsStatic ? 0 : 1; _targetParameters = method.Parameters; - _sourceBinder = new InMethodBinder(substitutedSourceMethod, new BuckStopsHereBinder(next.Compilation)); + // PROTOTYPE(ft): add tests and adjust implementation to allow EE to access file types + _sourceBinder = new InMethodBinder(substitutedSourceMethod, new BuckStopsHereBinder(next.Compilation, associatedSyntaxTree: null)); } internal override void LookupSymbolsInSingleBinder(LookupResult result, string name, int arity, ConsList basesBeingResolved, LookupOptions options, Binder originalBinder, bool diagnose, ref CompoundUseSiteInfo useSiteInfo) diff --git a/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/CompilationContext.cs b/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/CompilationContext.cs index 7cd2b047799b1..94269b757bd9c 100644 --- a/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/CompilationContext.cs +++ b/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/CompilationContext.cs @@ -706,7 +706,8 @@ private static Binder CreateBinderChain( @namespace = @namespace.ContainingNamespace; } - Binder binder = new BuckStopsHereBinder(compilation); + // PROTOTYPE(ft): add tests and adjust implementation to allow EE to access file types + Binder binder = new BuckStopsHereBinder(compilation, associatedSyntaxTree: null); var hasImports = !importRecordGroups.IsDefaultOrEmpty; var numImportStringGroups = hasImports ? importRecordGroups.Length : 0; var currentStringGroup = numImportStringGroups - 1; From 95ed8edc3cb6a87cfe563601a855939b5a3211fd Mon Sep 17 00:00:00 2001 From: Rikki Gibson Date: Tue, 31 May 2022 15:01:46 -0700 Subject: [PATCH 03/11] Resolve merge conflicts --- .../CSharp/Portable/CSharpResources.resx | 8 ++-- .../Declarations/DeclarationModifiers.cs | 10 +---- .../CSharp/Portable/Errors/MessageID.cs | 10 +---- .../CSharp/Portable/Parser/LanguageParser.cs | 39 ++----------------- .../Portable/Symbols/Source/ModifierUtils.cs | 14 ++----- .../Source/SourceDelegateMethodSymbol.cs | 8 ---- .../CSharp/Portable/Syntax/SyntaxKind.cs | 2 +- .../CSharp/Portable/Syntax/SyntaxKindFacts.cs | 25 +++--------- 8 files changed, 21 insertions(+), 95 deletions(-) diff --git a/src/Compilers/CSharp/Portable/CSharpResources.resx b/src/Compilers/CSharp/Portable/CSharpResources.resx index c880907649d7e..20ac3f3e3b0bb 100644 --- a/src/Compilers/CSharp/Portable/CSharpResources.resx +++ b/src/Compilers/CSharp/Portable/CSharpResources.resx @@ -7115,10 +7115,6 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ unsigned right shift -<<<<<<< HEAD - - file types -======= relaxed shift operator @@ -7136,6 +7132,8 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ Unexpected keyword 'unchecked' ->>>>>>> upstream/main + + + file types diff --git a/src/Compilers/CSharp/Portable/Declarations/DeclarationModifiers.cs b/src/Compilers/CSharp/Portable/Declarations/DeclarationModifiers.cs index 260dee987be4c..172548d5dbb2c 100644 --- a/src/Compilers/CSharp/Portable/Declarations/DeclarationModifiers.cs +++ b/src/Compilers/CSharp/Portable/Declarations/DeclarationModifiers.cs @@ -36,19 +36,11 @@ internal enum DeclarationModifiers : uint Async = 1 << 20, Ref = 1 << 21, // used only for structs -<<<<<<< HEAD - - // PROTOTYPE(ft): leaving 22 free since required is using it + Required = 1 << 22, // Used only for properties and fields 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 -======= - Required = 1 << 22, // Used only for properties and fields - - All = (1 << 23) - 1, // all modifiers - Unset = 1 << 23, // used when a modifiers value hasn't yet been computed ->>>>>>> upstream/main 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 80a84caa205bf..8574f24c4178d 100644 --- a/src/Compilers/CSharp/Portable/Errors/MessageID.cs +++ b/src/Compilers/CSharp/Portable/Errors/MessageID.cs @@ -253,13 +253,10 @@ internal enum MessageID IDS_FeatureUnsignedRightShift = MessageBase + 12823, IDS_FeatureExtendedNameofScope = MessageBase + 12824, -<<<<<<< HEAD - IDS_FeatureFileTypes = MessageBase + 12850, // PROTOTYPE(ft): pack ID before merge -======= IDS_FeatureRelaxedShiftOperator = MessageBase + 12825, IDS_FeatureRequiredMembers = MessageBase + 12826, ->>>>>>> upstream/main + IDS_FeatureFileTypes = MessageBase + 12850, // PROTOTYPE(ft): pack ID before merge } // Message IDs may refer to strings that need to be localized. @@ -382,11 +379,8 @@ 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 -<<<<<<< HEAD - case MessageID.IDS_FeatureFileTypes: // semantic check -======= case MessageID.IDS_FeatureRelaxedShiftOperator: // semantic check ->>>>>>> upstream/main + case MessageID.IDS_FeatureFileTypes: // semantic check return LanguageVersion.Preview; // C# 10.0 features. diff --git a/src/Compilers/CSharp/Portable/Parser/LanguageParser.cs b/src/Compilers/CSharp/Portable/Parser/LanguageParser.cs index 7e646e55528ec..efdd02bbacda1 100644 --- a/src/Compilers/CSharp/Portable/Parser/LanguageParser.cs +++ b/src/Compilers/CSharp/Portable/Parser/LanguageParser.cs @@ -1163,13 +1163,10 @@ internal static DeclarationModifiers GetModifier(SyntaxKind kind, SyntaxKind con return DeclarationModifiers.Partial; case SyntaxKind.AsyncKeyword: return DeclarationModifiers.Async; -<<<<<<< HEAD - case SyntaxKind.FileKeyword: - return DeclarationModifiers.File; -======= case SyntaxKind.RequiredKeyword: return DeclarationModifiers.Required; ->>>>>>> upstream/main + case SyntaxKind.FileKeyword: + return DeclarationModifiers.File; } goto default; @@ -1262,11 +1259,7 @@ private void ParseModifiers(SyntaxListBuilder tokens, bool forAccessors, bool fo break; case DeclarationModifiers.Async: -<<<<<<< HEAD if (!ShouldContextualKeywordBeTreatedAsModifier(parsingStatementNotDeclaration: false)) -======= - if (!ShouldAsyncOrRequiredBeTreatedAsModifier(parsingStatementNotDeclaration: false)) ->>>>>>> upstream/main { return; } @@ -1280,7 +1273,7 @@ private void ParseModifiers(SyntaxListBuilder tokens, bool forAccessors, bool fo // machinery to make a conservative guess as to whether the user meant required to be a keyword, so that they get a good langver // diagnostic and all the machinery to upgrade their project kicks in. The only exception to this rule is top level statements, // where the user could conceivably have a local named required. For these locations, we need to disambiguate as well. - if ((!IsFeatureEnabled(MessageID.IDS_FeatureRequiredMembers) || forTopLevelStatements) && !ShouldAsyncOrRequiredBeTreatedAsModifier(parsingStatementNotDeclaration: false)) + if ((!IsFeatureEnabled(MessageID.IDS_FeatureRequiredMembers) || forTopLevelStatements) && !ShouldContextualKeywordBeTreatedAsModifier(parsingStatementNotDeclaration: false)) { return; } @@ -1317,26 +1310,16 @@ bool isStructOrRecordKeyword(SyntaxToken token) } } -<<<<<<< HEAD private bool ShouldContextualKeywordBeTreatedAsModifier(bool parsingStatementNotDeclaration) { Debug.Assert(this.CurrentToken.Kind == SyntaxKind.IdentifierToken && GetModifier(this.CurrentToken) != DeclarationModifiers.None); -======= - private bool ShouldAsyncOrRequiredBeTreatedAsModifier(bool parsingStatementNotDeclaration) - { - Debug.Assert(this.CurrentToken.ContextualKind is SyntaxKind.AsyncKeyword or SyntaxKind.RequiredKeyword); ->>>>>>> upstream/main // Adapted from CParser::IsAsyncMethod. if (IsNonContextualModifier(PeekToken(1))) { // If the next token is a (non-contextual) modifier keyword, then this token is -<<<<<<< HEAD // definitely a modifier -======= - // definitely the async or required keyword ->>>>>>> upstream/main return true; } @@ -1347,11 +1330,7 @@ private bool ShouldAsyncOrRequiredBeTreatedAsModifier(bool parsingStatementNotDe try { -<<<<<<< HEAD this.EatToken(); //move past contextual token -======= - this.EatToken(); //move past contextual 'async' or 'required' ->>>>>>> upstream/main if (!parsingStatementNotDeclaration && (this.CurrentToken.ContextualKind == SyntaxKind.PartialKeyword)) @@ -2712,13 +2691,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 && -<<<<<<< HEAD - this.CurrentToken.ContextualKind is not (SyntaxKind.PartialKeyword or SyntaxKind.AsyncKeyword or SyntaxKind.FileKeyword) && -======= - this.CurrentToken.ContextualKind != SyntaxKind.PartialKeyword && - this.CurrentToken.ContextualKind != SyntaxKind.AsyncKeyword && - this.CurrentToken.ContextualKind != SyntaxKind.RequiredKeyword && ->>>>>>> upstream/main + this.CurrentToken.ContextualKind is not (SyntaxKind.PartialKeyword or SyntaxKind.AsyncKeyword or SyntaxKind.RequiredKeyword or SyntaxKind.FileKeyword) && IsComplete(type)) { var misplacedModifier = this.CurrentToken; @@ -8023,11 +7996,7 @@ private bool IsPossibleLocalDeclarationStatement(bool isGlobalScriptLevel) tk = this.CurrentToken.ContextualKind; var isPossibleAttributeOrModifier = (IsAdditionalLocalFunctionModifier(tk) || tk == SyntaxKind.OpenBracketToken) -<<<<<<< HEAD && (tk != SyntaxKind.AsyncKeyword || ShouldContextualKeywordBeTreatedAsModifier(parsingStatementNotDeclaration: true)); -======= - && (tk != SyntaxKind.AsyncKeyword || ShouldAsyncOrRequiredBeTreatedAsModifier(parsingStatementNotDeclaration: true)); ->>>>>>> upstream/main 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 e1edfa6ca082d..ef25fe620078f 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/ModifierUtils.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/ModifierUtils.cs @@ -307,13 +307,10 @@ internal static string ConvertSingleModifierToSyntaxText(DeclarationModifiers mo return SyntaxFacts.GetText(SyntaxKind.AsyncKeyword); case DeclarationModifiers.Ref: return SyntaxFacts.GetText(SyntaxKind.RefKeyword); -<<<<<<< HEAD - case DeclarationModifiers.File: - return SyntaxFacts.GetText(SyntaxKind.FileKeyword); -======= case DeclarationModifiers.Required: return SyntaxFacts.GetText(SyntaxKind.RequiredKeyword); ->>>>>>> upstream/main + case DeclarationModifiers.File: + return SyntaxFacts.GetText(SyntaxKind.FileKeyword); default: throw ExceptionUtilities.UnexpectedValue(modifier); } @@ -361,13 +358,10 @@ private static DeclarationModifiers ToDeclarationModifier(SyntaxKind kind) return DeclarationModifiers.Volatile; case SyntaxKind.RefKeyword: return DeclarationModifiers.Ref; -<<<<<<< HEAD - case SyntaxKind.FileKeyword: - return DeclarationModifiers.File; -======= case SyntaxKind.RequiredKeyword: return DeclarationModifiers.Required; ->>>>>>> upstream/main + case SyntaxKind.FileKeyword: + return DeclarationModifiers.File; default: throw ExceptionUtilities.UnexpectedValue(kind); } diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceDelegateMethodSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceDelegateMethodSymbol.cs index a6bd0e05bc78d..8ee64559a3956 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceDelegateMethodSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceDelegateMethodSymbol.cs @@ -112,18 +112,10 @@ internal static void AddDelegateMembers( // Inconsistent accessibility: parameter type '{1}' is less accessible than delegate '{0}' diagnostics.Add(ErrorCode.ERR_BadVisDelegateParam, delegateType.Locations[0], delegateType, parameterSymbol.Type); } -<<<<<<< HEAD else if (!delegateTypeIsFile && parameterSymbol.Type.IsFileTypeOrUsesFileTypes()) { diagnostics.Add(ErrorCode.ERR_FileTypeDisallowedInSignature, delegateType.Locations[0], parameterSymbol.Type, delegateType); } - var parameterSyntax = syntax.ParameterList.Parameters[i]; - if (parameterSyntax.ExclamationExclamationToken.Kind() == SyntaxKind.ExclamationExclamationToken) - { - diagnostics.Add(ErrorCode.ERR_MustNullCheckInImplementation, parameterSyntax.Identifier.GetLocation(), parameterSyntax.Identifier.ValueText); - } -======= ->>>>>>> upstream/main } diagnostics.Add(delegateType.Locations[0], useSiteInfo); diff --git a/src/Compilers/CSharp/Portable/Syntax/SyntaxKind.cs b/src/Compilers/CSharp/Portable/Syntax/SyntaxKind.cs index 0cc1e70f19658..1ffd12dd5434c 100644 --- a/src/Compilers/CSharp/Portable/Syntax/SyntaxKind.cs +++ b/src/Compilers/CSharp/Portable/Syntax/SyntaxKind.cs @@ -408,7 +408,7 @@ public enum SyntaxKind : ushort RequiredKeyword = 8447, /// Represents . - FileKeyword = 8447, + FileKeyword = 8448, // 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 8ea2704ee6739..aa2b0663b9221 100644 --- a/src/Compilers/CSharp/Portable/Syntax/SyntaxKindFacts.cs +++ b/src/Compilers/CSharp/Portable/Syntax/SyntaxKindFacts.cs @@ -1138,11 +1138,7 @@ public static SyntaxKind GetPreprocessorKeywordKind(string text) public static IEnumerable GetContextualKeywordKinds() { -<<<<<<< HEAD - for (int i = (int)SyntaxKind.YieldKeyword; i <= (int)SyntaxKind.FileKeyword; i++) // PROTOTYPE(ft): will conflict with required -======= - for (int i = (int)SyntaxKind.YieldKeyword; i <= (int)SyntaxKind.RequiredKeyword; i++) ->>>>>>> upstream/main + for (int i = (int)SyntaxKind.YieldKeyword; i <= (int)SyntaxKind.FileKeyword; i++) { yield return (SyntaxKind)i; } @@ -1195,11 +1191,8 @@ public static bool IsContextualKeyword(SyntaxKind kind) case SyntaxKind.RecordKeyword: case SyntaxKind.ManagedKeyword: case SyntaxKind.UnmanagedKeyword: -<<<<<<< HEAD - case SyntaxKind.FileKeyword: -======= case SyntaxKind.RequiredKeyword: ->>>>>>> upstream/main + case SyntaxKind.FileKeyword: return true; default: return false; @@ -1319,13 +1312,10 @@ public static SyntaxKind GetContextualKeywordKind(string text) return SyntaxKind.ManagedKeyword; case "unmanaged": return SyntaxKind.UnmanagedKeyword; -<<<<<<< HEAD - case "file": - return SyntaxKind.FileKeyword; -======= case "required": return SyntaxKind.RequiredKeyword; ->>>>>>> upstream/main + case "file": + return SyntaxKind.FileKeyword; default: return SyntaxKind.None; } @@ -1765,13 +1755,10 @@ public static string GetText(SyntaxKind kind) return "managed"; case SyntaxKind.UnmanagedKeyword: return "unmanaged"; -<<<<<<< HEAD - case SyntaxKind.FileKeyword: - return "file"; -======= case SyntaxKind.RequiredKeyword: return "required"; ->>>>>>> upstream/main + case SyntaxKind.FileKeyword: + return "file"; default: return string.Empty; } From ba9ed17923e2b50648487e794d7f593d1bc91abc Mon Sep 17 00:00:00 2001 From: Rikki Gibson Date: Tue, 31 May 2022 15:36:29 -0700 Subject: [PATCH 04/11] fix tests --- .../Test/Syntax/Parsing/FileModifierParsingTests.cs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Compilers/CSharp/Test/Syntax/Parsing/FileModifierParsingTests.cs b/src/Compilers/CSharp/Test/Syntax/Parsing/FileModifierParsingTests.cs index 64fe0727e2f4d..95e79ed4401d2 100644 --- a/src/Compilers/CSharp/Test/Syntax/Parsing/FileModifierParsingTests.cs +++ b/src/Compilers/CSharp/Test/Syntax/Parsing/FileModifierParsingTests.cs @@ -274,7 +274,7 @@ file partial ref struct C { } { // (1,14): error CS1003: Syntax error, ',' expected // file partial ref struct C { } - Diagnostic(ErrorCode.ERR_SyntaxError, "ref").WithArguments(",", "ref").WithLocation(1, 14), + Diagnostic(ErrorCode.ERR_SyntaxError, "ref").WithArguments(",").WithLocation(1, 14), // (1,18): error CS1002: ; expected // file partial ref struct C { } Diagnostic(ErrorCode.ERR_SemicolonExpected, "struct").WithLocation(1, 18) @@ -289,7 +289,7 @@ 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), + Diagnostic(ErrorCode.ERR_SyntaxError, "ref").WithArguments(",").WithLocation(1, 14), // (1,18): error CS1002: ; expected // file partial ref struct C { } Diagnostic(ErrorCode.ERR_SemicolonExpected, "struct").WithLocation(1, 18) @@ -368,7 +368,7 @@ partial file ref struct C { } { // (1,14): error CS1003: Syntax error, ',' expected // partial file ref struct C { } - Diagnostic(ErrorCode.ERR_SyntaxError, "ref").WithArguments(",", "ref").WithLocation(1, 14), + Diagnostic(ErrorCode.ERR_SyntaxError, "ref").WithArguments(",").WithLocation(1, 14), // (1,18): error CS1002: ; expected // partial file ref struct C { } Diagnostic(ErrorCode.ERR_SemicolonExpected, "struct").WithLocation(1, 18) @@ -383,7 +383,7 @@ 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), + Diagnostic(ErrorCode.ERR_SyntaxError, "ref").WithArguments(",").WithLocation(1, 14), // (1,18): error CS1002: ; expected // partial file ref struct C { } Diagnostic(ErrorCode.ERR_SemicolonExpected, "struct").WithLocation(1, 18) @@ -2649,7 +2649,7 @@ 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) + Diagnostic(ErrorCode.ERR_SyntaxError, "int").WithArguments(",").WithLocation(3, 17) }, expectedBindingDiagnostics: new[] { @@ -2661,7 +2661,7 @@ 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) + Diagnostic(ErrorCode.ERR_SyntaxError, "int").WithArguments(",").WithLocation(3, 17) }); N(SyntaxKind.CompilationUnit); { From f95472fd9b0509ab45409589b9ede60e7320f779 Mon Sep 17 00:00:00 2001 From: Rikki Gibson Date: Wed, 29 Jun 2022 11:29:43 -0700 Subject: [PATCH 05/11] File types emit (#61646) --- .../CSharp/Portable/Binder/Binder_Symbols.cs | 3 +- .../CSharp/Portable/CSharpResources.resx | 3 + .../Emitter/Model/NamedTypeReference.cs | 10 + .../Emitter/Model/NamedTypeSymbolAdapter.cs | 10 + .../Portable/Emitter/Model/PEModuleBuilder.cs | 2 +- .../CSharp/Portable/Errors/ErrorCode.cs | 1 + .../SymbolDisplayVisitor.Types.cs | 24 +- ...ymousManager.TypeOrDelegatePublicSymbol.cs | 2 + ...nymousType.TypeOrDelegateTemplateSymbol.cs | 2 + .../Portable/Symbols/ErrorTypeSymbol.cs | 2 + .../Symbols/ExtendedErrorTypeSymbol.cs | 2 + .../Symbols/Metadata/PE/PENamedTypeSymbol.cs | 2 + .../Symbols/MissingMetadataTypeSymbol.cs | 3 + .../Portable/Symbols/NamedTypeSymbol.cs | 19 +- .../Portable/Symbols/NamespaceOrTypeSymbol.cs | 40 + .../NoPiaAmbiguousCanonicalTypeSymbol.cs | 2 + .../NoPiaIllegalGenericInstantiationSymbol.cs | 2 + .../NoPiaMissingCanonicalTypeSymbol.cs | 2 + .../Symbols/PlaceholderTypeArgumentSymbol.cs | 2 + .../Source/SourceMemberContainerSymbol.cs | 8 +- .../Symbols/Synthesized/GeneratedNameKind.cs | 1 + .../Synthesized/GeneratedNameParser.cs | 31 + .../Symbols/Synthesized/GeneratedNames.cs | 33 + .../Synthesized/SynthesizedContainer.cs | 4 + .../SynthesizedEmbeddedAttributeSymbol.cs | 2 + .../Portable/Symbols/TypeSymbolExtensions.cs | 11 + .../Portable/Symbols/UnboundGenericType.cs | 2 + .../Symbols/UnsupportedMetadataTypeSymbol.cs | 2 + .../Symbols/Wrapped/WrappedNamedTypeSymbol.cs | 2 + .../Portable/xlf/CSharpResources.cs.xlf | 5 + .../Portable/xlf/CSharpResources.de.xlf | 5 + .../Portable/xlf/CSharpResources.es.xlf | 5 + .../Portable/xlf/CSharpResources.fr.xlf | 5 + .../Portable/xlf/CSharpResources.it.xlf | 5 + .../Portable/xlf/CSharpResources.ja.xlf | 5 + .../Portable/xlf/CSharpResources.ko.xlf | 5 + .../Portable/xlf/CSharpResources.pl.xlf | 5 + .../Portable/xlf/CSharpResources.pt-BR.xlf | 5 + .../Portable/xlf/CSharpResources.ru.xlf | 5 + .../Portable/xlf/CSharpResources.tr.xlf | 5 + .../Portable/xlf/CSharpResources.zh-Hans.xlf | 5 + .../Portable/xlf/CSharpResources.zh-Hant.xlf | 5 + .../EditAndContinue/EditAndContinueTests.cs | 328 +++++++ .../Symbol/Symbols/MockNamedTypeSymbol.cs | 2 + .../Symbols/Source/FileModifierTests.cs | 892 ++++++++++++++++-- .../Parsing/FileModifierParsingTests.cs | 58 +- .../Portable/CodeGen/CompilationTestData.cs | 2 +- .../CodeGen/PrivateImplementationDetails.cs | 2 + .../Portable/Emit/CommonPEModuleBuilder.cs | 2 +- src/Compilers/Core/Portable/Emit/ErrorType.cs | 10 + .../Portable/Emit/NoPia/CommonEmbeddedType.cs | 10 + .../MetadataReader/MetadataHelpers.cs | 6 +- .../SymWriterMetadataProvider.cs | 2 +- .../Core/Portable/PEWriter/MetadataWriter.cs | 38 +- .../Core/Portable/PEWriter/RootModuleType.cs | 5 + .../Portable/PEWriter/TypeNameSerializer.cs | 13 +- src/Compilers/Core/Portable/PEWriter/Types.cs | 3 + .../SymbolDisplayCompilerInternalOptions.cs | 1 + .../SymbolDisplay/SymbolDisplayFormat.cs | 3 +- .../Portable/Binding/Binder_Symbols.vb | 2 +- .../Portable/Emit/NamedTypeReference.vb | 6 + .../Portable/Emit/NamedTypeSymbolAdapter.vb | 6 + .../Portable/Emit/PEModuleBuilder.vb | 2 +- .../Portable/Symbols/NamedTypeSymbol.vb | 2 +- .../Symbols/EENamedTypeSymbol.cs | 4 + .../NamespaceTypeDefinitionNoBase.cs | 4 + 66 files changed, 1582 insertions(+), 115 deletions(-) diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Symbols.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Symbols.cs index 1331731c757b1..9c977c755319c 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder_Symbols.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder_Symbols.cs @@ -2493,7 +2493,8 @@ protected AssemblySymbol GetForwardedToAssembly(string name, int arity, ref Name // NOTE: This won't work if the type isn't using CLS-style generic naming (i.e. `arity), but this code is // only intended to improve diagnostic messages, so false negatives in corner cases aren't a big deal. - var metadataName = MetadataHelpers.ComposeAritySuffixedMetadataName(name, arity); + // File types can't be forwarded, so we won't attempt to determine a file identifier to attach to the metadata name. + var metadataName = MetadataHelpers.ComposeAritySuffixedMetadataName(name, arity, associatedFileIdentifier: null); var fullMetadataName = MetadataHelpers.BuildQualifiedName(qualifierOpt?.ToDisplayString(SymbolDisplayFormat.QualifiedNameOnlyFormat), metadataName); var result = GetForwardedToAssembly(fullMetadataName, diagnostics, location); if ((object)result != null) diff --git a/src/Compilers/CSharp/Portable/CSharpResources.resx b/src/Compilers/CSharp/Portable/CSharpResources.resx index 3a545b4bd4048..139e9ce8ccbf4 100644 --- a/src/Compilers/CSharp/Portable/CSharpResources.resx +++ b/src/Compilers/CSharp/Portable/CSharpResources.resx @@ -7112,6 +7112,9 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ File type '{0}' cannot be used as a base type of non-file type '{1}'. + + File type '{0}' must be defined in a top level type; '{0}' is a nested type. + unsigned right shift diff --git a/src/Compilers/CSharp/Portable/Emitter/Model/NamedTypeReference.cs b/src/Compilers/CSharp/Portable/Emitter/Model/NamedTypeReference.cs index a4eeac4890e69..4d5b6f4b2c18b 100644 --- a/src/Compilers/CSharp/Portable/Emitter/Model/NamedTypeReference.cs +++ b/src/Compilers/CSharp/Portable/Emitter/Model/NamedTypeReference.cs @@ -40,6 +40,16 @@ bool Cci.INamedTypeReference.MangleName } } +#nullable enable + string? Cci.INamedTypeReference.AssociatedFileIdentifier + { + get + { + return UnderlyingNamedType.AssociatedFileIdentifier(); + } + } +#nullable disable + string Cci.INamedEntity.Name { get diff --git a/src/Compilers/CSharp/Portable/Emitter/Model/NamedTypeSymbolAdapter.cs b/src/Compilers/CSharp/Portable/Emitter/Model/NamedTypeSymbolAdapter.cs index 377645bb42318..ea7196e6596e2 100644 --- a/src/Compilers/CSharp/Portable/Emitter/Model/NamedTypeSymbolAdapter.cs +++ b/src/Compilers/CSharp/Portable/Emitter/Model/NamedTypeSymbolAdapter.cs @@ -756,6 +756,16 @@ bool Cci.INamedTypeReference.MangleName } } +#nullable enable + string? Cci.INamedTypeReference.AssociatedFileIdentifier + { + get + { + return AdaptedNamedTypeSymbol.AssociatedFileIdentifier(); + } + } +#nullable disable + string Cci.INamedEntity.Name { get diff --git a/src/Compilers/CSharp/Portable/Emitter/Model/PEModuleBuilder.cs b/src/Compilers/CSharp/Portable/Emitter/Model/PEModuleBuilder.cs index a16378eed574f..fc2b6fc942183 100644 --- a/src/Compilers/CSharp/Portable/Emitter/Model/PEModuleBuilder.cs +++ b/src/Compilers/CSharp/Portable/Emitter/Model/PEModuleBuilder.cs @@ -660,7 +660,7 @@ private void ReportExportedTypeNameCollisions(ImmutableArray e // exported types are not emitted in EnC deltas (hence generation 0): string fullEmittedName = MetadataHelpers.BuildQualifiedName( ((Cci.INamespaceTypeReference)type.GetCciAdapter()).NamespaceName, - Cci.MetadataWriter.GetMangledName(type.GetCciAdapter(), generation: 0)); + Cci.MetadataWriter.GetMetadataName(type.GetCciAdapter(), generation: 0)); // First check against types declared in the primary module if (ContainsTopLevelType(fullEmittedName)) diff --git a/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs b/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs index 4bf65a09750e1..255f4583dd594 100644 --- a/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs +++ b/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs @@ -2095,6 +2095,7 @@ internal enum ErrorCode ERR_FileTypeDisallowedInSignature = 9300, ERR_FileTypeNoExplicitAccessibility = 9301, ERR_FileTypeBase = 9302, + ERR_FileTypeNested = 9303, #endregion diff --git a/src/Compilers/CSharp/Portable/SymbolDisplay/SymbolDisplayVisitor.Types.cs b/src/Compilers/CSharp/Portable/SymbolDisplay/SymbolDisplayVisitor.Types.cs index c913f82010b5e..6bad689cf0e76 100644 --- a/src/Compilers/CSharp/Portable/SymbolDisplay/SymbolDisplayVisitor.Types.cs +++ b/src/Compilers/CSharp/Portable/SymbolDisplay/SymbolDisplayVisitor.Types.cs @@ -10,6 +10,7 @@ using System.Linq; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp.Symbols; +using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.SymbolDisplay; using Roslyn.Utilities; @@ -182,17 +183,28 @@ public override void VisitNamedType(INamedTypeSymbol symbol) AddNullableAnnotations(symbol); if ((format.CompilerInternalOptions & SymbolDisplayCompilerInternalOptions.IncludeContainingFileForFileTypes) != 0 - // PROTOTYPE(ft): public API? - && symbol.GetSymbol() is SourceMemberContainerTypeSymbol { IsFile: true } fileType) + && symbol is Symbols.PublicModel.Symbol { UnderlyingSymbol: NamedTypeSymbol { AssociatedSyntaxTree: SyntaxTree tree } internalSymbol }) { - var tree = symbol.DeclaringSyntaxReferences[0].SyntaxTree; - var fileDescription = tree.FilePath is { Length: not 0 } path - ? Path.GetFileNameWithoutExtension(path) - : $""; + var fileDescription = getDisplayFileName(tree) is { Length: not 0 } path + ? path + : $""; builder.Add(CreatePart(SymbolDisplayPartKind.Punctuation, symbol, "@")); builder.Add(CreatePart(SymbolDisplayPartKind.ModuleName, symbol, fileDescription)); } + + static string getDisplayFileName(SyntaxTree tree) + { + if (tree.FilePath.Length == 0) + { + return ""; + } + + var pooledBuilder = PooledStringBuilder.GetInstance(); + var sb = pooledBuilder.Builder; + GeneratedNames.AppendFileName(tree.FilePath, sb); + return pooledBuilder.ToStringAndFree(); + } } private void VisitNamedTypeWithoutNullability(INamedTypeSymbol symbol) diff --git a/src/Compilers/CSharp/Portable/Symbols/AnonymousTypes/PublicSymbols/AnonymousManager.TypeOrDelegatePublicSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/AnonymousTypes/PublicSymbols/AnonymousManager.TypeOrDelegatePublicSymbol.cs index 36e8bb11c2d01..ca8f87f34c1f7 100644 --- a/src/Compilers/CSharp/Portable/Symbols/AnonymousTypes/PublicSymbols/AnonymousManager.TypeOrDelegatePublicSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/AnonymousTypes/PublicSymbols/AnonymousManager.TypeOrDelegatePublicSymbol.cs @@ -73,6 +73,8 @@ internal sealed override bool MangleName get { return false; } } + internal sealed override SyntaxTree? AssociatedSyntaxTree => null; + public sealed override int Arity { get { return 0; } diff --git a/src/Compilers/CSharp/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousType.TypeOrDelegateTemplateSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousType.TypeOrDelegateTemplateSymbol.cs index 7f335aea333b8..db12a912c9cfa 100644 --- a/src/Compilers/CSharp/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousType.TypeOrDelegateTemplateSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousType.TypeOrDelegateTemplateSymbol.cs @@ -237,6 +237,8 @@ internal sealed override bool MangleName get { return this.Arity > 0; } } + internal sealed override SyntaxTree? AssociatedSyntaxTree => null; + internal sealed override ImmutableArray TypeArgumentsWithAnnotationsNoUseSiteDiagnostics { get { return GetTypeParametersAsTypeArguments(); } diff --git a/src/Compilers/CSharp/Portable/Symbols/ErrorTypeSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/ErrorTypeSymbol.cs index 286394b84209e..c786c186d65ce 100644 --- a/src/Compilers/CSharp/Portable/Symbols/ErrorTypeSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/ErrorTypeSymbol.cs @@ -578,6 +578,8 @@ internal override bool MangleName get { return _originalDefinition.MangleName; } } + internal override SyntaxTree? AssociatedSyntaxTree => _originalDefinition.AssociatedSyntaxTree; + internal override DiagnosticInfo? ErrorInfo { get { return _originalDefinition.ErrorInfo; } diff --git a/src/Compilers/CSharp/Portable/Symbols/ExtendedErrorTypeSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/ExtendedErrorTypeSymbol.cs index 08ce38645e2c7..1f141ab0f5a38 100644 --- a/src/Compilers/CSharp/Portable/Symbols/ExtendedErrorTypeSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/ExtendedErrorTypeSymbol.cs @@ -145,6 +145,8 @@ internal override bool MangleName } } + internal override SyntaxTree? AssociatedSyntaxTree => null; + public override Symbol? ContainingSymbol { get diff --git a/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PENamedTypeSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PENamedTypeSymbol.cs index 47d94ec32230c..9542e39a6f7d6 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PENamedTypeSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PENamedTypeSymbol.cs @@ -376,6 +376,8 @@ internal abstract override bool MangleName get; } + internal override SyntaxTree AssociatedSyntaxTree => null; + internal abstract int MetadataArity { get; diff --git a/src/Compilers/CSharp/Portable/Symbols/MissingMetadataTypeSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/MissingMetadataTypeSymbol.cs index 2dfb36efb2f81..f81ebf3f77af2 100644 --- a/src/Compilers/CSharp/Portable/Symbols/MissingMetadataTypeSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/MissingMetadataTypeSymbol.cs @@ -47,6 +47,9 @@ internal override bool MangleName return mangleName; } } + + internal override SyntaxTree? AssociatedSyntaxTree => null; + /// /// Get the arity of the missing type. /// diff --git a/src/Compilers/CSharp/Portable/Symbols/NamedTypeSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/NamedTypeSymbol.cs index b0177ecb18c00..e1f1c52db543e 100644 --- a/src/Compilers/CSharp/Portable/Symbols/NamedTypeSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/NamedTypeSymbol.cs @@ -479,6 +479,7 @@ public virtual bool IsImplicitClass /// public abstract override string Name { get; } +#nullable enable /// /// Return the name including the metadata arity suffix. /// @@ -486,14 +487,30 @@ public override string MetadataName { get { - return MangleName ? MetadataHelpers.ComposeAritySuffixedMetadataName(Name, Arity) : Name; + var fileIdentifier = this.AssociatedFileIdentifier(); + // If we have a fileIdentifier, the type will definitely use CLS arity encoding for nonzero arity. + Debug.Assert(!(fileIdentifier != null && !MangleName && Arity > 0)); + return fileIdentifier != null || MangleName + ? MetadataHelpers.ComposeAritySuffixedMetadataName(Name, Arity, fileIdentifier) + : Name; } } + /// + /// If this type is a file type, returns the syntax tree where this type is visible. Otherwise, returns null. + /// + internal abstract SyntaxTree? AssociatedSyntaxTree { get; } +#nullable disable + /// /// Should the name returned by Name property be mangled with [`arity] suffix in order to get metadata name. /// Must return False for a type with Arity == 0. /// + /// + /// Some types with Arity > 0 still have MangleName == false. For example, EENamedTypeSymbol. + /// Note that other differences between source names and metadata names exist and are not controlled by this property, + /// such as the 'AssociatedFileIdentifier' prefix for file types. + /// internal abstract bool MangleName { // Intentionally no default implementation to force consideration of appropriate implementation for each new subclass diff --git a/src/Compilers/CSharp/Portable/Symbols/NamespaceOrTypeSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/NamespaceOrTypeSymbol.cs index c6f9cfe5caaac..5271e6e4a4ec2 100644 --- a/src/Compilers/CSharp/Portable/Symbols/NamespaceOrTypeSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/NamespaceOrTypeSymbol.cs @@ -2,11 +2,14 @@ // 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.Collections.Generic; using System.Collections.Immutable; using System.Diagnostics; using System.Linq; +using Microsoft.CodeAnalysis.CSharp.Symbols.Metadata.PE; using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Symbols; using Roslyn.Utilities; @@ -243,6 +246,7 @@ internal virtual NamedTypeSymbol LookupMetadataType(ref MetadataTypeName emitted Debug.Assert(!emittedTypeName.IsNull); NamespaceOrTypeSymbol scope = this; + Debug.Assert(scope is not MergedNamespaceSymbol); if (scope.Kind == SymbolKind.ErrorType) { @@ -326,6 +330,35 @@ internal virtual NamedTypeSymbol LookupMetadataType(ref MetadataTypeName emitted } Done: + if (isTopLevel + && scope is not PENamespaceSymbol + && (emittedTypeName.ForcedArity == -1 || emittedTypeName.ForcedArity == emittedTypeName.InferredArity) + && GeneratedNameParser.TryParseFileTypeName( + emittedTypeName.UnmangledTypeName, + out string? displayFileName, + out int ordinal, + out string? sourceName)) + { + // also do a lookup for file types from source. + namespaceOrTypeMembers = scope.GetTypeMembers(sourceName); + foreach (var named in namespaceOrTypeMembers) + { + if (named.AssociatedSyntaxTree is SyntaxTree tree + && getDisplayName(tree) == displayFileName + && named.DeclaringCompilation.GetSyntaxTreeOrdinal(tree) == ordinal + && named.Arity == emittedTypeName.InferredArity) + { + if ((object?)namedType != null) + { + namedType = null; + break; + } + + namedType = named; + } + } + } + if ((object?)namedType == null) { if (isTopLevel) @@ -339,6 +372,13 @@ internal virtual NamedTypeSymbol LookupMetadataType(ref MetadataTypeName emitted } return namedType; + + static string getDisplayName(SyntaxTree tree) + { + var sb = PooledStringBuilder.GetInstance(); + GeneratedNames.AppendFileName(tree.FilePath, sb); + return sb.ToStringAndFree(); + } } /// diff --git a/src/Compilers/CSharp/Portable/Symbols/NoPiaAmbiguousCanonicalTypeSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/NoPiaAmbiguousCanonicalTypeSymbol.cs index 0b578b6715240..a1b600de31315 100644 --- a/src/Compilers/CSharp/Portable/Symbols/NoPiaAmbiguousCanonicalTypeSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/NoPiaAmbiguousCanonicalTypeSymbol.cs @@ -49,6 +49,8 @@ internal override bool MangleName } } + internal override SyntaxTree? AssociatedSyntaxTree => null; + public AssemblySymbol EmbeddingAssembly { get diff --git a/src/Compilers/CSharp/Portable/Symbols/NoPiaIllegalGenericInstantiationSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/NoPiaIllegalGenericInstantiationSymbol.cs index f8247bddef230..6161835bfa505 100644 --- a/src/Compilers/CSharp/Portable/Symbols/NoPiaIllegalGenericInstantiationSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/NoPiaIllegalGenericInstantiationSymbol.cs @@ -41,6 +41,8 @@ internal override bool MangleName } } + internal override SyntaxTree? AssociatedSyntaxTree => null; + public NamedTypeSymbol UnderlyingSymbol { get diff --git a/src/Compilers/CSharp/Portable/Symbols/NoPiaMissingCanonicalTypeSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/NoPiaMissingCanonicalTypeSymbol.cs index c50c29cbe0fad..2b31203cb7a28 100644 --- a/src/Compilers/CSharp/Portable/Symbols/NoPiaMissingCanonicalTypeSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/NoPiaMissingCanonicalTypeSymbol.cs @@ -73,6 +73,8 @@ internal override bool MangleName } } + internal override SyntaxTree? AssociatedSyntaxTree => null; + public string Guid { get diff --git a/src/Compilers/CSharp/Portable/Symbols/PlaceholderTypeArgumentSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/PlaceholderTypeArgumentSymbol.cs index 3c8eb1aa884d2..3178fe12f7762 100644 --- a/src/Compilers/CSharp/Portable/Symbols/PlaceholderTypeArgumentSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/PlaceholderTypeArgumentSymbol.cs @@ -48,6 +48,8 @@ internal override bool MangleName } } + internal override SyntaxTree? AssociatedSyntaxTree => null; + internal override DiagnosticInfo? ErrorInfo { get diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberContainerSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberContainerSymbol.cs index cc59b10392b0f..44a6c46bbb5db 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberContainerSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberContainerSymbol.cs @@ -826,8 +826,7 @@ internal override ManagedKind GetManagedKind(ref CompoundUseSiteInfo HasFlag(DeclarationModifiers.File); - /// If this symbol is only available within a single syntax tree, returns that syntax tree. Otherwise, returns null. - internal SyntaxTree? AssociatedSyntaxTree => IsFile ? declaration.Declarations[0].Location.SourceTree : null; + internal sealed override SyntaxTree? AssociatedSyntaxTree => IsFile ? declaration.Declarations[0].Location.SourceTree : null; [MethodImpl(MethodImplOptions.AggressiveInlining)] private bool HasFlag(DeclarationModifiers flag) => (_declModifiers & flag) != 0; @@ -1743,6 +1742,11 @@ protected void AfterMembersChecks(BindingDiagnosticBag diagnostics) } } + if (IsFile && (object?)ContainingType != null) + { + diagnostics.Add(ErrorCode.ERR_FileTypeNested, location, this); + } + return; bool hasBaseTypeOrInterface(Func predicate) diff --git a/src/Compilers/CSharp/Portable/Symbols/Synthesized/GeneratedNameKind.cs b/src/Compilers/CSharp/Portable/Symbols/Synthesized/GeneratedNameKind.cs index 66a294e654bad..1404bc8a80496 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Synthesized/GeneratedNameKind.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Synthesized/GeneratedNameKind.cs @@ -30,6 +30,7 @@ internal enum GeneratedNameKind ReusableHoistedLocalField = '7', LambdaCacheField = '9', FixedBufferField = 'e', + FileType = 'F', AnonymousType = 'f', TransparentIdentifier = 'h', AnonymousTypeField = 'i', diff --git a/src/Compilers/CSharp/Portable/Symbols/Synthesized/GeneratedNameParser.cs b/src/Compilers/CSharp/Portable/Symbols/Synthesized/GeneratedNameParser.cs index b9d6d4b44fa23..55f6d2b85c572 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Synthesized/GeneratedNameParser.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Synthesized/GeneratedNameParser.cs @@ -5,6 +5,7 @@ using System; using System.Diagnostics.CodeAnalysis; using System.Globalization; +using System.Text.RegularExpressions; namespace Microsoft.CodeAnalysis.CSharp.Symbols { @@ -170,5 +171,35 @@ internal static bool TryParseAnonymousTypeParameterName(string typeParameterName propertyName = null; return false; } + + // A full metadata name for a generic file type looks like: + // FN__ClassName`A + // where 'N' is the syntax tree ordinal, 'A' is the arity, + // and 'ClassName' is the source name of the type. + // + // The "unmangled" name of a generic file type looks like: + // FN__ClassName + private static readonly Regex s_fileTypeOrdinalPattern = new Regex(@"<([a-zA-Z_0-9]*)>F(\d)+__", RegexOptions.Compiled); + + /// + /// This method will work with either unmangled or mangled type names as input, but it does not remove any arity suffix if present. + /// + internal static bool TryParseFileTypeName(string generatedName, [NotNullWhen(true)] out string? displayFileName, out int ordinal, [NotNullWhen(true)] out string? originalTypeName) + { + if (s_fileTypeOrdinalPattern.Match(generatedName) is Match { Success: true, Groups: var groups, Index: var index, Length: var length } + && int.TryParse(groups[2].Value, out ordinal)) + { + displayFileName = groups[1].Value; + + var prefixEndsAt = index + length; + originalTypeName = generatedName.Substring(prefixEndsAt); + return true; + } + + ordinal = -1; + displayFileName = null; + originalTypeName = null; + return false; + } } } diff --git a/src/Compilers/CSharp/Portable/Symbols/Synthesized/GeneratedNames.cs b/src/Compilers/CSharp/Portable/Symbols/Synthesized/GeneratedNames.cs index cf9acb4bcd6e0..74b6ef0e57a8e 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Synthesized/GeneratedNames.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Synthesized/GeneratedNames.cs @@ -494,5 +494,38 @@ internal static string LambdaCopyParameterName(int ordinal) { return ""; } + + internal static string MakeFileIdentifier(string filePath, int ordinal) + { + var pooledBuilder = PooledStringBuilder.GetInstance(); + var sb = pooledBuilder.Builder; + sb.Append('<'); + AppendFileName(filePath, sb); + sb.Append('>'); + sb.Append((char)GeneratedNameKind.FileType); + sb.Append(ordinal); + sb.Append("__"); + return pooledBuilder.ToStringAndFree(); + } + + internal static void AppendFileName(string? filePath, StringBuilder sb) + { + var fileName = FileNameUtilities.GetFileName(filePath, includeExtension: false); + if (fileName is null) + { + return; + } + + foreach (var ch in fileName) + { + sb.Append(ch switch + { + >= 'a' and <= 'z' => ch, + >= 'A' and <= 'Z' => ch, + >= '0' and <= '9' => ch, + _ => '_' + }); + } + } } } diff --git a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedContainer.cs b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedContainer.cs index dd677239e1078..12ec75a9c91ca 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedContainer.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedContainer.cs @@ -165,6 +165,10 @@ internal override IEnumerable GetFieldsToEmit() internal override bool MangleName => Arity > 0; +#nullable enable + internal sealed override SyntaxTree? AssociatedSyntaxTree => null; +#nullable disable + public override bool IsImplicitlyDeclared => true; internal override bool ShouldAddWinRTMembers => false; diff --git a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedEmbeddedAttributeSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedEmbeddedAttributeSymbol.cs index a03039d83a6ca..6e36128fc5162 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedEmbeddedAttributeSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedEmbeddedAttributeSymbol.cs @@ -99,6 +99,8 @@ public SynthesizedEmbeddedAttributeSymbolBase( internal override bool MangleName => false; + internal override SyntaxTree AssociatedSyntaxTree => null; + internal override bool HasCodeAnalysisEmbeddedAttribute => true; internal override bool IsInterpolatedStringHandlerType => false; diff --git a/src/Compilers/CSharp/Portable/Symbols/TypeSymbolExtensions.cs b/src/Compilers/CSharp/Portable/Symbols/TypeSymbolExtensions.cs index 508a139a32598..2df49e75c19ab 100644 --- a/src/Compilers/CSharp/Portable/Symbols/TypeSymbolExtensions.cs +++ b/src/Compilers/CSharp/Portable/Symbols/TypeSymbolExtensions.cs @@ -7,6 +7,7 @@ using System.Collections.Immutable; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; +using System.Text; using Microsoft.CodeAnalysis.PooledObjects; using Roslyn.Utilities; @@ -1361,6 +1362,16 @@ public static bool IsFileTypeOrUsesFileTypes(this TypeSymbol type) return foundType is not null; } + internal static string? AssociatedFileIdentifier(this NamedTypeSymbol type) + { + if (type.AssociatedSyntaxTree is not SyntaxTree tree) + { + return null; + } + var ordinal = type.DeclaringCompilation.GetSyntaxTreeOrdinal(tree); + return GeneratedNames.MakeFileIdentifier(tree.FilePath, ordinal); + } + public static bool IsPointerType(this TypeSymbol type) { return type is PointerTypeSymbol; diff --git a/src/Compilers/CSharp/Portable/Symbols/UnboundGenericType.cs b/src/Compilers/CSharp/Portable/Symbols/UnboundGenericType.cs index 30e4a67d87744..1ee9dbccbb271 100644 --- a/src/Compilers/CSharp/Portable/Symbols/UnboundGenericType.cs +++ b/src/Compilers/CSharp/Portable/Symbols/UnboundGenericType.cs @@ -91,6 +91,8 @@ internal override bool MangleName } } + internal override SyntaxTree? AssociatedSyntaxTree => null; + internal override DiagnosticInfo ErrorInfo { get diff --git a/src/Compilers/CSharp/Portable/Symbols/UnsupportedMetadataTypeSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/UnsupportedMetadataTypeSymbol.cs index e4ca579dc1b86..80b81912ae070 100644 --- a/src/Compilers/CSharp/Portable/Symbols/UnsupportedMetadataTypeSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/UnsupportedMetadataTypeSymbol.cs @@ -37,5 +37,7 @@ internal override bool MangleName return false; } } + + internal override SyntaxTree? AssociatedSyntaxTree => null; } } diff --git a/src/Compilers/CSharp/Portable/Symbols/Wrapped/WrappedNamedTypeSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Wrapped/WrappedNamedTypeSymbol.cs index 48a0389a946be..aa26a0c66f5c8 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Wrapped/WrappedNamedTypeSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Wrapped/WrappedNamedTypeSymbol.cs @@ -95,6 +95,8 @@ internal override bool MangleName } } + internal override SyntaxTree AssociatedSyntaxTree => _underlyingType.AssociatedSyntaxTree; + public override string GetDocumentationCommentXml(CultureInfo preferredCulture = null, bool expandIncludes = false, CancellationToken cancellationToken = default(CancellationToken)) { return _underlyingType.GetDocumentationCommentXml(preferredCulture, expandIncludes, cancellationToken); diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf index 54d37aa08912e..4edff182eda01 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf @@ -577,6 +577,11 @@ File type '{0}' cannot be used in a member signature in non-file type '{1}'. + + File type '{0}' must be defined in a top level type; '{0}' is a nested type. + File type '{0}' must be defined in a top level type; '{0}' is a nested type. + + File type '{0}' cannot use accessibility modifiers. File type '{0}' cannot use accessibility modifiers. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf index 87b0902fd9c30..0d5dbb6ca6d5b 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf @@ -577,6 +577,11 @@ File type '{0}' cannot be used in a member signature in non-file type '{1}'. + + File type '{0}' must be defined in a top level type; '{0}' is a nested type. + File type '{0}' must be defined in a top level type; '{0}' is a nested type. + + File type '{0}' cannot use accessibility modifiers. File type '{0}' cannot use accessibility modifiers. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf index 83792b53903f8..c146398c4d563 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf @@ -577,6 +577,11 @@ File type '{0}' cannot be used in a member signature in non-file type '{1}'. + + File type '{0}' must be defined in a top level type; '{0}' is a nested type. + File type '{0}' must be defined in a top level type; '{0}' is a nested type. + + File type '{0}' cannot use accessibility modifiers. File type '{0}' cannot use accessibility modifiers. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf index 3a74a9c7bb492..52798620fbaf0 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf @@ -577,6 +577,11 @@ File type '{0}' cannot be used in a member signature in non-file type '{1}'. + + File type '{0}' must be defined in a top level type; '{0}' is a nested type. + File type '{0}' must be defined in a top level type; '{0}' is a nested type. + + File type '{0}' cannot use accessibility modifiers. File type '{0}' cannot use accessibility modifiers. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf index 3c47401ea0e07..177e269e704dc 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf @@ -577,6 +577,11 @@ File type '{0}' cannot be used in a member signature in non-file type '{1}'. + + File type '{0}' must be defined in a top level type; '{0}' is a nested type. + File type '{0}' must be defined in a top level type; '{0}' is a nested type. + + File type '{0}' cannot use accessibility modifiers. File type '{0}' cannot use accessibility modifiers. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf index 8c73c39d1d469..49343625d8876 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf @@ -577,6 +577,11 @@ File type '{0}' cannot be used in a member signature in non-file type '{1}'. + + File type '{0}' must be defined in a top level type; '{0}' is a nested type. + File type '{0}' must be defined in a top level type; '{0}' is a nested type. + + File type '{0}' cannot use accessibility modifiers. File type '{0}' cannot use accessibility modifiers. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf index f47b5109c0161..0199e0ab379a3 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf @@ -577,6 +577,11 @@ File type '{0}' cannot be used in a member signature in non-file type '{1}'. + + File type '{0}' must be defined in a top level type; '{0}' is a nested type. + File type '{0}' must be defined in a top level type; '{0}' is a nested type. + + File type '{0}' cannot use accessibility modifiers. File type '{0}' cannot use accessibility modifiers. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf index cd69d9f270d30..bfe3edd993e2e 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf @@ -577,6 +577,11 @@ File type '{0}' cannot be used in a member signature in non-file type '{1}'. + + File type '{0}' must be defined in a top level type; '{0}' is a nested type. + File type '{0}' must be defined in a top level type; '{0}' is a nested type. + + File type '{0}' cannot use accessibility modifiers. File type '{0}' cannot use accessibility modifiers. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf index 74a78e9c99d65..51ef2f7c6d194 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf @@ -577,6 +577,11 @@ File type '{0}' cannot be used in a member signature in non-file type '{1}'. + + File type '{0}' must be defined in a top level type; '{0}' is a nested type. + File type '{0}' must be defined in a top level type; '{0}' is a nested type. + + File type '{0}' cannot use accessibility modifiers. File type '{0}' cannot use accessibility modifiers. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf index 895aa4d900286..49fe2ce705ee8 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf @@ -577,6 +577,11 @@ File type '{0}' cannot be used in a member signature in non-file type '{1}'. + + File type '{0}' must be defined in a top level type; '{0}' is a nested type. + File type '{0}' must be defined in a top level type; '{0}' is a nested type. + + File type '{0}' cannot use accessibility modifiers. File type '{0}' cannot use accessibility modifiers. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf index 40c6a24e526ce..9daaaba095219 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf @@ -577,6 +577,11 @@ File type '{0}' cannot be used in a member signature in non-file type '{1}'. + + File type '{0}' must be defined in a top level type; '{0}' is a nested type. + File type '{0}' must be defined in a top level type; '{0}' is a nested type. + + File type '{0}' cannot use accessibility modifiers. File type '{0}' cannot use accessibility modifiers. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf index 7551f44f01217..211e53063cd85 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf @@ -577,6 +577,11 @@ File type '{0}' cannot be used in a member signature in non-file type '{1}'. + + File type '{0}' must be defined in a top level type; '{0}' is a nested type. + File type '{0}' must be defined in a top level type; '{0}' is a nested type. + + File type '{0}' cannot use accessibility modifiers. File type '{0}' cannot use accessibility modifiers. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf index 7c52b486b9619..9ac1bddbf4c14 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf @@ -577,6 +577,11 @@ File type '{0}' cannot be used in a member signature in non-file type '{1}'. + + File type '{0}' must be defined in a top level type; '{0}' is a nested type. + File type '{0}' must be defined in a top level type; '{0}' is a nested type. + + File type '{0}' cannot use accessibility modifiers. File type '{0}' cannot use accessibility modifiers. diff --git a/src/Compilers/CSharp/Test/Emit/Emit/EditAndContinue/EditAndContinueTests.cs b/src/Compilers/CSharp/Test/Emit/Emit/EditAndContinue/EditAndContinueTests.cs index 6b6ac34fcf5df..cb1148562ee86 100644 --- a/src/Compilers/CSharp/Test/Emit/Emit/EditAndContinue/EditAndContinueTests.cs +++ b/src/Compilers/CSharp/Test/Emit/Emit/EditAndContinue/EditAndContinueTests.cs @@ -13159,6 +13159,334 @@ .locals init ([unchanged] V_0, .maxstack 1 IL_0000: ldc.i4.s 10 IL_0002: ret +}"); + } + + [Fact] + public void FileTypes_01() + { + var source0 = MarkedSource(@" +using System; +file class C +{ + void M() + { + Console.Write(1); + } +}", "file1.cs"); + var source1 = MarkedSource(@" +using System; +file class C +{ + void M() + { + Console.Write(2); + } +}", "file1.cs"); + + var compilation0 = CreateCompilation(source0.Tree, options: ComSafeDebugDll); + var compilation1 = compilation0.WithSource(source1.Tree); + + var method0 = compilation0.GetMember("C.M"); + var method1 = compilation1.GetMember("C.M"); + + var v0 = CompileAndVerify(compilation0, verify: Verification.Skipped); + + v0.VerifyIL("C@file1.M", @" +{ + // Code size 9 (0x9) + .maxstack 1 + IL_0000: nop + IL_0001: ldc.i4.1 + IL_0002: call ""void System.Console.Write(int)"" + IL_0007: nop + IL_0008: ret +} +"); + + using var md0 = ModuleMetadata.CreateFromImage(v0.EmittedAssemblyData); + + var generation0 = EmitBaseline.CreateInitialBaseline(md0, v0.CreateSymReader().GetEncMethodDebugInfo); + + var diff = compilation1.EmitDifference( + generation0, + ImmutableArray.Create( + SemanticEdit.Create(SemanticEditKind.Update, method0, method1, GetSyntaxMapFromMarkers(source0, source1), preserveLocalVariables: true))); + + // There should be no diagnostics from rude edits + diff.EmitResult.Diagnostics.Verify(); + + diff.VerifyIL("C@file1.M", @" +{ + // Code size 9 (0x9) + .maxstack 1 + IL_0000: nop + IL_0001: ldc.i4.2 + IL_0002: call ""void System.Console.Write(int)"" + IL_0007: nop + IL_0008: ret +}"); + } + + [Fact] + public void FileTypes_02() + { + var source0 = MarkedSource(@" +using System; +file class C +{ + void M() + { + Console.Write(1); + } +}", "file1.cs"); + var source1 = MarkedSource(@" +using System; +file class C +{ + void M() + { + Console.Write(2); + } +}", "file1.cs"); + var source2 = MarkedSource(@" +using System; +file class C +{ + void M() + { + Console.Write(3); + } +}", "file2.cs"); + + var compilation0 = CreateCompilation(source0.Tree, options: ComSafeDebugDll); + var compilation1 = compilation0.WithSource(new[] { source1.Tree, source2.Tree }); + + var cm1_gen0 = compilation0.GetMember("C.M"); + var cm1_gen1 = ((NamedTypeSymbol)compilation1.GetMembers("C")[0]).GetMember("M"); + var c2_gen1 = ((NamedTypeSymbol)compilation1.GetMembers("C")[1]); + + var v0 = CompileAndVerify(compilation0, verify: Verification.Skipped); + + v0.VerifyIL("C@file1.M", @" +{ + // Code size 9 (0x9) + .maxstack 1 + IL_0000: nop + IL_0001: ldc.i4.1 + IL_0002: call ""void System.Console.Write(int)"" + IL_0007: nop + IL_0008: ret +} +"); + + using var md0 = ModuleMetadata.CreateFromImage(v0.EmittedAssemblyData); + + var generation0 = EmitBaseline.CreateInitialBaseline(md0, v0.CreateSymReader().GetEncMethodDebugInfo); + + var diff = compilation1.EmitDifference( + generation0, + ImmutableArray.Create( + SemanticEdit.Create(SemanticEditKind.Update, cm1_gen0, cm1_gen1, GetSyntaxMapFromMarkers(source0, source1), preserveLocalVariables: true), + SemanticEdit.Create(SemanticEditKind.Insert, null, c2_gen1, syntaxMap: null, preserveLocalVariables: true))); + + // There should be no diagnostics from rude edits + diff.EmitResult.Diagnostics.Verify(); + + diff.VerifyIL("C@file1.M", @" +{ + // Code size 9 (0x9) + .maxstack 1 + IL_0000: nop + IL_0001: ldc.i4.2 + IL_0002: call ""void System.Console.Write(int)"" + IL_0007: nop + IL_0008: ret +}"); + + diff.VerifyIL("C@file2.M", @" +{ + // Code size 9 (0x9) + .maxstack 1 + IL_0000: nop + IL_0001: ldc.i4.3 + IL_0002: call ""void System.Console.Write(int)"" + IL_0007: nop + IL_0008: ret +}"); + } + + [Fact] + public void FileTypes_03() + { + var source0_gen0 = MarkedSource(@" +using System; +file class C +{ + void M() + { + Console.Write(1); + } +}", "file1.cs"); + var source1_gen1 = MarkedSource(@" +using System; +file class C +{ + void M() + { + Console.Write(2); + } +}", "file2.cs"); + var source0_gen1 = MarkedSource(@" +using System; +file class C +{ + void M() + { + Console.Write(3); + } +}", "file1.cs"); + + var compilation0 = CreateCompilation(source0_gen0.Tree, options: ComSafeDebugDll); + // Because the order of syntax trees has changed here, the original type is considered deleted and the two new types are completely new, unrelated types. + + // https://github.com/dotnet/roslyn/issues/61999 + // we should handle this as a modification of an existing type rather than deletion and insertion of distinct types. + // most likely, we either need to identify file types based on something stable like the SyntaxTree.FilePath, or store a mapping of the ordinals from one generation to the next. + // although "real-world" compilations disallow duplicated file paths, duplicated or empty file paths are very common via direct use of the APIs, so there's not necessarily a single slam-dunk answer here. + var compilation1 = compilation0.WithSource(new[] { source1_gen1.Tree, source0_gen1.Tree }); + + var c1_gen0 = compilation0.GetMember("C"); + var c1_gen1 = ((NamedTypeSymbol)compilation1.GetMembers("C")[0]); + var c2_gen1 = ((NamedTypeSymbol)compilation1.GetMembers("C")[1]); + + var v0 = CompileAndVerify(compilation0, verify: Verification.Skipped); + + v0.VerifyIL("C@file1.M", @" +{ + // Code size 9 (0x9) + .maxstack 1 + IL_0000: nop + IL_0001: ldc.i4.1 + IL_0002: call ""void System.Console.Write(int)"" + IL_0007: nop + IL_0008: ret +} +"); + + using var md0 = ModuleMetadata.CreateFromImage(v0.EmittedAssemblyData); + + var generation0 = EmitBaseline.CreateInitialBaseline(md0, v0.CreateSymReader().GetEncMethodDebugInfo); + + var diff = compilation1.EmitDifference( + generation0, + ImmutableArray.Create( + SemanticEdit.Create(SemanticEditKind.Delete, c1_gen0, null, syntaxMap: null, preserveLocalVariables: true), + SemanticEdit.Create(SemanticEditKind.Insert, null, c1_gen1, syntaxMap: null, preserveLocalVariables: true), + SemanticEdit.Create(SemanticEditKind.Insert, null, c2_gen1, syntaxMap: null, preserveLocalVariables: true))); + + // There should be no diagnostics from rude edits + diff.EmitResult.Diagnostics.Verify(); + + diff.VerifyIL("C@file1.M", @" +{ + // Code size 9 (0x9) + .maxstack 1 + IL_0000: nop + IL_0001: ldc.i4.3 + IL_0002: call ""void System.Console.Write(int)"" + IL_0007: nop + IL_0008: ret +}"); + + diff.VerifyIL("C@file2.M", @" +{ + // Code size 9 (0x9) + .maxstack 1 + IL_0000: nop + IL_0001: ldc.i4.2 + IL_0002: call ""void System.Console.Write(int)"" + IL_0007: nop + IL_0008: ret +}"); + } + + [Fact] + public void FileTypes_04() + { + var source1_gen0 = MarkedSource(@" +using System; +file class C +{ + void M() + { + Console.Write(1); + } +}", "file1.cs"); + var source2_gen0 = MarkedSource(@" +using System; +file class C +{ + void M() + { + Console.Write(2); + } +}", "file2.cs"); + var source2_gen1 = MarkedSource(@" +using System; +file class C +{ + void M() + { + Console.Write(3); + } +}", "file2.cs"); + + var compilation0 = CreateCompilation(new[] { source1_gen0.Tree, source2_gen0.Tree }, options: ComSafeDebugDll); + + var compilation1 = compilation0.WithSource(new[] { source2_gen1.Tree }); + + var c1_gen0 = ((NamedTypeSymbol)compilation0.GetMembers("C")[0]); + var c2_gen0 = ((NamedTypeSymbol)compilation0.GetMembers("C")[1]); + var c2_gen1 = compilation1.GetMember("C"); + + var v0 = CompileAndVerify(compilation0, verify: Verification.Skipped); + + v0.VerifyIL("C@file2.M", @" +{ + // Code size 9 (0x9) + .maxstack 1 + IL_0000: nop + IL_0001: ldc.i4.2 + IL_0002: call ""void System.Console.Write(int)"" + IL_0007: nop + IL_0008: ret +} +"); + + using var md0 = ModuleMetadata.CreateFromImage(v0.EmittedAssemblyData); + + var generation0 = EmitBaseline.CreateInitialBaseline(md0, v0.CreateSymReader().GetEncMethodDebugInfo); + + var diff = compilation1.EmitDifference( + generation0, + ImmutableArray.Create( + SemanticEdit.Create(SemanticEditKind.Delete, c1_gen0, null, syntaxMap: null, preserveLocalVariables: true), + SemanticEdit.Create(SemanticEditKind.Delete, c2_gen0, null, syntaxMap: null, preserveLocalVariables: true), + SemanticEdit.Create(SemanticEditKind.Insert, null, c2_gen1, syntaxMap: null, preserveLocalVariables: true))); + + // There should be no diagnostics from rude edits + diff.EmitResult.Diagnostics.Verify(); + + diff.VerifyIL("C@file2.M", @" +{ + // Code size 9 (0x9) + .maxstack 1 + IL_0000: nop + IL_0001: ldc.i4.3 + IL_0002: call ""void System.Console.Write(int)"" + IL_0007: nop + IL_0008: ret }"); } } diff --git a/src/Compilers/CSharp/Test/Symbol/Symbols/MockNamedTypeSymbol.cs b/src/Compilers/CSharp/Test/Symbol/Symbols/MockNamedTypeSymbol.cs index d5e358d3b6939..db91e25e01b09 100644 --- a/src/Compilers/CSharp/Test/Symbol/Symbols/MockNamedTypeSymbol.cs +++ b/src/Compilers/CSharp/Test/Symbol/Symbols/MockNamedTypeSymbol.cs @@ -44,6 +44,8 @@ internal override bool MangleName } } + internal override SyntaxTree AssociatedSyntaxTree => null; + public override ImmutableArray TypeParameters { get diff --git a/src/Compilers/CSharp/Test/Symbol/Symbols/Source/FileModifierTests.cs b/src/Compilers/CSharp/Test/Symbol/Symbols/Source/FileModifierTests.cs index b5e473aee9b02..0fbb15b774fbb 100644 --- a/src/Compilers/CSharp/Test/Symbol/Symbols/Source/FileModifierTests.cs +++ b/src/Compilers/CSharp/Test/Symbol/Symbols/Source/FileModifierTests.cs @@ -3,9 +3,11 @@ // See the LICENSE file in the project root for more information. using System.Linq; +using System.Text; using Microsoft.CodeAnalysis.CSharp.Symbols; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.CSharp.Test.Utilities; +using Microsoft.CodeAnalysis.Test.Utilities; using Xunit; namespace Microsoft.CodeAnalysis.CSharp.UnitTests; @@ -43,10 +45,16 @@ file class C { } 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)); + Diagnostic(ErrorCode.ERR_FeatureInPreview, "C").WithArguments("file types").WithLocation(3, 16), + // (3,16): error CS9303: File type 'Outer.C' must be defined in a top level type; 'Outer.C' is a nested type. + // file class C { } + Diagnostic(ErrorCode.ERR_FileTypeNested, "C").WithArguments("Outer.C").WithLocation(3, 16)); comp = CreateCompilation(source); - comp.VerifyDiagnostics(); + comp.VerifyDiagnostics( + // (3,16): error CS9303: File type 'Outer.C' must be defined in a top level type; 'Outer.C' is a nested type. + // file class C { } + Diagnostic(ErrorCode.ERR_FileTypeNested, "C").WithArguments("Outer.C").WithLocation(3, 16)); } [Fact] @@ -92,7 +100,6 @@ file class C { } } """; - // PROTOTYPE(ft): determine whether an inner file class within a file class is an error or if it's just fine. 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. @@ -100,10 +107,16 @@ file class C { } Diagnostic(ErrorCode.ERR_FeatureInPreview, "Outer").WithArguments("file types").WithLocation(1, 12), // (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)); + Diagnostic(ErrorCode.ERR_FeatureInPreview, "C").WithArguments("file types").WithLocation(3, 16), + // (3,16): error CS9303: File type 'Outer.C' must be defined in a top level type; 'Outer.C' is a nested type. + // file class C { } + Diagnostic(ErrorCode.ERR_FileTypeNested, "C").WithArguments("Outer.C").WithLocation(3, 16)); comp = CreateCompilation(source); - comp.VerifyDiagnostics(); + comp.VerifyDiagnostics( + // (3,16): error CS9303: File type 'Outer.C' must be defined in a top level type; 'Outer.C' is a nested type. + // file class C { } + Diagnostic(ErrorCode.ERR_FileTypeNested, "C").WithArguments("Outer.C").WithLocation(3, 16)); } [Fact] @@ -167,7 +180,7 @@ class C : B.A2 // ok: base type is bound as A1.A2 } [Fact] - public void SameFileUse() + public void SameFileUse_01() { var source = """ using System; @@ -189,9 +202,244 @@ static void Main() } """; - var verifier = CompileAndVerify(source, expectedOutput: "1"); + var verifier = CompileAndVerify(source, expectedOutput: "1", symbolValidator: symbolValidator); + verifier.VerifyDiagnostics(); + + var comp = (CSharpCompilation)verifier.Compilation; + var symbol = comp.GetMember("C"); + Assert.Equal("<>F0__C", symbol.MetadataName); + + // The qualified name here is based on `SymbolDisplayCompilerInternalOptions.IncludeContainingFileForFileTypes`. + // We don't actually look up based on the file-encoded name of the type. + // This is similar to how generic types work (lookup based on 'C' instead of 'C`1'). + verifier.VerifyIL("C@.M", @" +{ + // Code size 7 (0x7) + .maxstack 1 + IL_0000: ldc.i4.1 + IL_0001: call ""void System.Console.Write(int)"" + IL_0006: ret +}"); + + void symbolValidator(ModuleSymbol symbol) + { + Assert.Equal(new[] { "", "<>F0__C", "Program" }, symbol.GlobalNamespace.GetMembers().Select(m => m.Name)); + var classC = symbol.GlobalNamespace.GetMember("<>F0__C"); + Assert.Equal(new[] { "M", ".ctor" }, classC.MemberNames); + } + } + + [Fact] + public void SameFileUse_02() + { + var source = """ + using System; + + file class C + { + public static void M() + { + Console.Write(1); + } + } + + class Program + { + static void Main() + { + C.M(); + } + } + """; + + var verifier = CompileAndVerify(new[] { "", source }, expectedOutput: "1", symbolValidator: symbolValidator); + verifier.VerifyDiagnostics(); + + var comp = (CSharpCompilation)verifier.Compilation; + var symbol = comp.GetMember("C"); + Assert.Equal("<>F1__C", symbol.MetadataName); + + // The qualified name here is based on `SymbolDisplayCompilerInternalOptions.IncludeContainingFileForFileTypes`. + // We don't actually look up based on the file-encoded name of the type. + // This is similar to how generic types work (lookup based on 'C' instead of 'C`1'). + verifier.VerifyIL("C@.M", @" +{ + // Code size 7 (0x7) + .maxstack 1 + IL_0000: ldc.i4.1 + IL_0001: call ""void System.Console.Write(int)"" + IL_0006: ret +}"); + + void symbolValidator(ModuleSymbol symbol) + { + Assert.Equal(new[] { "", "<>F1__C", "Program" }, symbol.GlobalNamespace.GetMembers().Select(m => m.Name)); + var classC = symbol.GlobalNamespace.GetMember("<>F1__C"); + Assert.Equal(new[] { "M", ".ctor" }, classC.MemberNames); + } + } + + [Fact] + public void FileEnum_01() + { + var source = """ + using System; + + file enum E + { + E1, E2 + } + + class Program + { + static void Main() + { + Console.Write(E.E2); + } + } + """; + + var verifier = CompileAndVerify(source, expectedOutput: "E2", symbolValidator: symbolValidator); + verifier.VerifyDiagnostics(); + + var comp = (CSharpCompilation)verifier.Compilation; + var symbol = comp.GetMember("E"); + Assert.Equal("<>F0__E", symbol.MetadataName); + + verifier.VerifyIL("Program.Main", @" +{ + // Code size 12 (0xc) + .maxstack 1 + IL_0000: ldc.i4.1 + IL_0001: box ""E"" + IL_0006: call ""void System.Console.Write(object)"" + IL_000b: ret +}"); + + void symbolValidator(ModuleSymbol symbol) + { + Assert.Equal(new[] { "", "<>F0__E", "Program" }, symbol.GlobalNamespace.GetMembers().Select(m => m.Name)); + var classC = symbol.GlobalNamespace.GetMember("<>F0__E"); + Assert.Equal(new[] { "value__", "E1", "E2", ".ctor" }, classC.MemberNames); + } + } + + [Fact] + public void FileEnum_02() + { + var source = """ + using System; + + file enum E + { + E1, E2 + } + + file class Attr : Attribute + { + public Attr(E e) { } + } + + [Attr(E.E2)] + class Program + { + static void Main() + { + var data = typeof(Program).GetCustomAttributesData(); + Console.Write(data[0].ConstructorArguments[0]); + } + } + """; + + var verifier = CompileAndVerify(source, expectedOutput: "(<>F0__E)1", symbolValidator: symbolValidator); + verifier.VerifyDiagnostics(); + + var comp = (CSharpCompilation)verifier.Compilation; + var symbol = comp.GetMember("E"); + Assert.Equal("<>F0__E", symbol.MetadataName); + + void symbolValidator(ModuleSymbol symbol) + { + Assert.Equal(new[] { "", "<>F0__E", "<>F0__Attr", "Program" }, symbol.GlobalNamespace.GetMembers().Select(m => m.Name)); + var classC = symbol.GlobalNamespace.GetMember("<>F0__E"); + Assert.Equal(new[] { "value__", "E1", "E2", ".ctor" }, classC.MemberNames); + } + } + + [Fact] + public void FileEnum_03() + { + var source = """ + using System; + + file enum E + { + E1, E2 + } + + class Attr : Attribute + { + public Attr(E e) { } // 1 + } + + [Attr(E.E2)] + class Program + { + static void Main() + { + var data = typeof(Program).GetCustomAttributesData(); + Console.Write(data[0].ConstructorArguments[0]); + } + } + """; + + var comp = CreateCompilation(source); + comp.VerifyDiagnostics( + // (10,12): error CS9300: File type 'E' cannot be used in a member signature in non-file type 'Attr'. + // public Attr(E e) { } // 1 + Diagnostic(ErrorCode.ERR_FileTypeDisallowedInSignature, "Attr").WithArguments("E", "Attr").WithLocation(10, 12)); + } + + [Fact] + public void FileEnum_04() + { + var source = """ + using System; + + file enum E + { + E1, E2 + } + + class Attr : Attribute + { + public Attr(object obj) { } + } + + [Attr(E.E2)] + class Program + { + static void Main() + { + var data = typeof(Program).GetCustomAttributesData(); + Console.Write(data[0].ConstructorArguments[0]); + } + } + """; + + var verifier = CompileAndVerify(source, expectedOutput: "(<>F0__E)1", symbolValidator: symbolValidator); verifier.VerifyDiagnostics(); - // PROTOTYPE(ft): check metadata names + + var comp = (CSharpCompilation)verifier.Compilation; + var symbol = comp.GetMember("E"); + Assert.Equal("<>F0__E", symbol.MetadataName); + + void symbolValidator(ModuleSymbol symbol) + { + Assert.Equal(new[] { "", "<>F0__E", "Attr", "Program" }, symbol.GlobalNamespace.GetMembers().Select(m => m.Name)); + var classC = symbol.GlobalNamespace.GetMember("<>F0__E"); + Assert.Equal(new[] { "value__", "E1", "E2", ".ctor" }, classC.MemberNames); + } } [Fact] @@ -226,11 +474,243 @@ static void Main() Diagnostic(ErrorCode.ERR_NameNotInContext, "C").WithArguments("C").WithLocation(5, 9)); } + [Fact] + public void Generic_01() + { + var source = """ + using System; + + C.M(1); + + file class C + { + public static void M(T t) { Console.Write(t); } + } + """; + + var verifier = CompileAndVerify(SyntaxFactory.ParseSyntaxTree(source, options: TestOptions.RegularPreview, path: "path/to/MyFile.cs", encoding: Encoding.Default), expectedOutput: "1", symbolValidator: symbolValidator); + verifier.VerifyDiagnostics(); + + verifier.VerifyIL("C@MyFile.M(T)", @" +{ + // Code size 12 (0xc) + .maxstack 1 + IL_0000: ldarg.0 + IL_0001: box ""T"" + IL_0006: call ""void System.Console.Write(object)"" + IL_000b: ret +} +"); + + var comp = (CSharpCompilation)verifier.Compilation; + var c = comp.GetMember("C"); + Assert.Equal("F0__C`1", c.MetadataName); + + void symbolValidator(ModuleSymbol module) + { + Assert.Equal(new[] { "", "Program", "F0__C" }, module.GlobalNamespace.GetMembers().Select(m => m.Name)); + + var classC = module.GlobalNamespace.GetMember("F0__C"); + Assert.Equal("F0__C`1", classC.MetadataName); + Assert.Equal(new[] { "M", ".ctor" }, classC.MemberNames); + } + } + + [Fact] + public void BadFileNames_01() + { + var source = """ + using System; + + C.M(); + + file class C + { + public static void M() { Console.Write(1); } + } + """; + + var verifier = CompileAndVerify(SyntaxFactory.ParseSyntaxTree(source, options: TestOptions.RegularPreview, path: "path/to/My<>File.cs", encoding: Encoding.Default), expectedOutput: "1", symbolValidator: symbolValidator); + verifier.VerifyDiagnostics(); + + var comp = (CSharpCompilation)verifier.Compilation; + var c = comp.GetMember("C"); + Assert.Equal("C@My__File", c.ToTestDisplayString()); + Assert.Equal("F0__C", c.MetadataName); + + void symbolValidator(ModuleSymbol module) + { + Assert.Equal(new[] { "", "Program", "F0__C" }, module.GlobalNamespace.GetMembers().Select(m => m.Name)); + var expectedSymbol = module.GlobalNamespace.GetMember("F0__C"); + Assert.Equal("F0__C", expectedSymbol.MetadataName); + Assert.Equal(new[] { "M", ".ctor" }, expectedSymbol.MemberNames); + } + } + + [Fact] + public void BadFileNames_02() + { + var source = """ + using System; + + C.M(); + + file class C + { + public static void M() { Console.Write(1); } + } + """; + + var verifier = CompileAndVerify(SyntaxFactory.ParseSyntaxTree(source, options: TestOptions.RegularPreview, path: "path/to/MyGeneratedFile.g.cs", encoding: Encoding.Default), expectedOutput: "1", symbolValidator: symbolValidator); + verifier.VerifyDiagnostics(); + + var comp = (CSharpCompilation)verifier.Compilation; + var c = comp.GetMember("C"); + Assert.Equal("C@MyGeneratedFile_g", c.ToTestDisplayString()); + Assert.Equal("F0__C", c.MetadataName); + + void symbolValidator(ModuleSymbol module) + { + Assert.Equal(new[] { "", "Program", "F0__C" }, module.GlobalNamespace.GetMembers().Select(m => m.Name)); + var expectedSymbol = module.GlobalNamespace.GetMember("F0__C"); + Assert.Equal("F0__C", expectedSymbol.MetadataName); + Assert.Equal(new[] { "M", ".ctor" }, expectedSymbol.MemberNames); + } + } + + [Fact] + public void DuplicateFileNames_01() + { + var path = "path/to/file.cs"; + var source1 = SyntaxFactory.ParseSyntaxTree(""" + using System; + + C.M(); + + file class C + { + public static void M() { Console.Write(1); } + } + """, options: TestOptions.RegularPreview, path: path, encoding: Encoding.Default); + var source2 = SyntaxFactory.ParseSyntaxTree(""" + using System; + + file class C + { + public static void M() { Console.Write(2); } + } + """, options: TestOptions.RegularPreview, path: path, encoding: Encoding.Default); + + var verifier = CompileAndVerify(new[] { source1, source2 }, expectedOutput: "1", symbolValidator: symbolValidator); + verifier.VerifyDiagnostics(); + + // note that VerifyIL doesn't work in this specific scenario because the files have the same name. + + void symbolValidator(ModuleSymbol module) + { + Assert.NotNull(module.GlobalNamespace.GetMember("F0__C")); + Assert.NotNull(module.GlobalNamespace.GetMember("F1__C")); + } + } + + // Data based on Lexer.ScanIdentifier_FastPath, excluding '/', '\', and ':' because those are path separators. [Theory] - [InlineData("file", "file")] - [InlineData("file", "")] - [InlineData("", "file")] - public void Duplication_01(string firstFileModifier, string secondFileModifier) + [InlineData('&')] + [InlineData('\0')] + [InlineData(' ')] + [InlineData('\r')] + [InlineData('\n')] + [InlineData('\t')] + [InlineData('!')] + [InlineData('%')] + [InlineData('(')] + [InlineData(')')] + [InlineData('*')] + [InlineData('+')] + [InlineData(',')] + [InlineData('-')] + [InlineData('.')] + [InlineData(';')] + [InlineData('<')] + [InlineData('=')] + [InlineData('>')] + [InlineData('?')] + [InlineData('[')] + [InlineData(']')] + [InlineData('^')] + [InlineData('{')] + [InlineData('|')] + [InlineData('}')] + [InlineData('~')] + [InlineData('"')] + [InlineData('\'')] + [InlineData('`')] + public void BadFileNames_03(char badChar) + { + var source = """ + using System; + + C.M(); + + file class C + { + public static void M() { Console.Write(1); } + } + """; + + var verifier = CompileAndVerify(SyntaxFactory.ParseSyntaxTree(source, options: TestOptions.RegularPreview, path: $"path/to/My{badChar}File.cs", encoding: Encoding.Default), expectedOutput: "1", symbolValidator: symbolValidator); + verifier.VerifyDiagnostics(); + + var comp = (CSharpCompilation)verifier.Compilation; + var c = comp.GetMember("C"); + Assert.Equal("C@My_File", c.ToTestDisplayString()); + Assert.Equal("F0__C", c.MetadataName); + + void symbolValidator(ModuleSymbol module) + { + Assert.Equal(new[] { "", "Program", "F0__C" }, module.GlobalNamespace.GetMembers().Select(m => m.Name)); + var expectedSymbol = module.GlobalNamespace.GetMember("F0__C"); + Assert.Equal("F0__C", expectedSymbol.MetadataName); + Assert.Equal(new[] { "M", ".ctor" }, expectedSymbol.MemberNames); + } + } + + [Fact] + public void Pdb_01() + { + var source = """ + using System; + + C.M(); + + file class C + { + public static void M() { Console.Write(1); } + } + """; + + var expectedMetadataName = "F0__C"; + var verifier = CompileAndVerify(SyntaxFactory.ParseSyntaxTree(source, options: TestOptions.RegularPreview, path: "path/to/My+File.cs", encoding: Encoding.Default), expectedOutput: "1", symbolValidator: validateSymbols); + verifier.VerifyDiagnostics(); + + var comp = (CSharpCompilation)verifier.Compilation; + var c = comp.GetMember("C"); + Assert.Equal("C@My_File", c.ToTestDisplayString()); + Assert.Equal(expectedMetadataName, c.MetadataName); + + void validateSymbols(ModuleSymbol module) + { + var type = module.GlobalNamespace.GetMember(expectedMetadataName); + Assert.NotNull(type); + Assert.Equal(new[] { "M", ".ctor" }, type.MemberNames); + } + } + + [Theory] + [InlineData("file", "file", "<>F0__C", "<>F1__C")] + [InlineData("file", "", "<>F0__C", "C")] + [InlineData("", "file", "C", "<>F1__C")] + public void Duplication_01(string firstFileModifier, string secondFileModifier, string firstMetadataName, string secondMetadataName) { // A file type is allowed to have the same name as a non-file type from a different file. // When both a file type and non-file type with the same name are in scope, the file type is preferred, since it's "more local". @@ -269,24 +749,25 @@ static void Main() } """; - // PROTOTYPE(ft): execute and check expectedOutput once name mangling is done - // expectedOutput: "1" - var comp = CreateCompilation(new[] { source1 + main, source2 }); + var verifier = CompileAndVerify(new[] { source1 + main, source2 }, expectedOutput: "1"); + var comp = (CSharpCompilation)verifier.Compilation; var cs = comp.GetMembers("C"); var tree = comp.SyntaxTrees[0]; var expectedSymbol = cs[0]; + Assert.Equal(firstMetadataName, expectedSymbol.MetadataName); verify(); - // expectedOutput: "2" - comp = CreateCompilation(new[] { source1, source2 + main }); + verifier = CompileAndVerify(new[] { source1, source2 + main }, expectedOutput: "2"); + comp = (CSharpCompilation)verifier.Compilation; cs = comp.GetMembers("C"); tree = comp.SyntaxTrees[1]; expectedSymbol = cs[1]; + Assert.Equal(secondMetadataName, expectedSymbol.MetadataName); verify(); void verify() { - comp.VerifyDiagnostics(); + verifier.VerifyDiagnostics(); Assert.Equal(2, cs.Length); Assert.Equal(comp.SyntaxTrees[0], cs[0].DeclaringSyntaxReferences.Single().SyntaxTree); Assert.Equal(comp.SyntaxTrees[1], cs[1].DeclaringSyntaxReferences.Single().SyntaxTree); @@ -405,7 +886,8 @@ static void Main() } """; - var comp = CreateCompilation(new[] { source1, source2, main }); // expectedOutput: 2 + var verifier = CompileAndVerify(new[] { source1, source2, main }, expectedOutput: "2"); + var comp = (CSharpCompilation)verifier.Compilation; comp.VerifyDiagnostics(); var cs = comp.GetMembers("C"); @@ -470,7 +952,8 @@ static void Main() } """; - var comp = CreateCompilation(new[] { source1, main }); // expectedOutput: 2 + var verifier = CompileAndVerify(new[] { source1, main }, expectedOutput: "2"); + var comp = (CSharpCompilation)verifier.Compilation; comp.VerifyDiagnostics(); var cs = comp.GetMembers("C"); @@ -531,7 +1014,8 @@ static void Main() } """; - var comp = CreateCompilation(new[] { source1, main }); // expectedOutput: 2 + var verifier = CompileAndVerify(new[] { source1, main }, expectedOutput: "2"); + var comp = (CSharpCompilation)verifier.Compilation; comp.VerifyDiagnostics(); var cs = comp.GetMembers("C"); @@ -734,7 +1218,13 @@ public static void M() { } """; var compilation = CreateCompilation(new[] { source1, source2, source3 }); - compilation.VerifyDiagnostics(); + compilation.VerifyDiagnostics( + // (3,16): error CS9303: File type 'Outer.C' must be defined in a top level type; 'Outer.C' is a nested type. + // file class C + Diagnostic(ErrorCode.ERR_FileTypeNested, "C").WithArguments("Outer.C").WithLocation(3, 16), + // (3,16): error CS9303: File type 'Outer.C' must be defined in a top level type; 'Outer.C' is a nested type. + // file class C + Diagnostic(ErrorCode.ERR_FileTypeNested, "C").WithArguments("Outer.C").WithLocation(3, 16)); var classOuter = compilation.GetMember("Outer"); var cs = classOuter.GetMembers("C"); @@ -834,15 +1324,12 @@ static void Main() } """; - // PROTOTYPE(ft): execute and check expectedOutput once name mangling is done - // expectedOutput: "1" var comp = CreateCompilation(new[] { source1 + main, source2 }); var cs = comp.GetMembers("Program.C"); var tree = comp.SyntaxTrees[0]; var expectedSymbol = cs[0]; verify(); - // expectedOutput: "2" comp = CreateCompilation(new[] { source1, source2 + main }); cs = comp.GetMembers("Program.C"); tree = comp.SyntaxTrees[1]; @@ -851,7 +1338,7 @@ static void Main() void verify() { - comp.VerifyDiagnostics(); + comp.GetDiagnostics().Where(d => d.Code is not (int)ErrorCode.ERR_FileTypeNested).Verify(); Assert.Equal(2, cs.Length); Assert.Equal(comp.SyntaxTrees[0], cs[0].DeclaringSyntaxReferences.Single().SyntaxTree); Assert.Equal(comp.SyntaxTrees[1], cs[1].DeclaringSyntaxReferences.Single().SyntaxTree); @@ -909,17 +1396,16 @@ static void Main() } """; - // PROTOTYPE(ft): execute and check expectedOutput once name mangling is done - // expectedOutput: "1" - var comp = CreateCompilation(new[] { source1 + main, source2 }); + var comp = CreateCompilation(new[] { source1 + main, source2 }, options: TestOptions.DebugExe); + comp.GetDiagnostics().Where(d => d.Code is not (int)ErrorCode.ERR_FileTypeNested).Verify(); var outers = comp.GetMembers("Outer"); var cs = outers.Select(o => ((NamedTypeSymbol)o).GetMember("C")).ToArray(); var tree = comp.SyntaxTrees[0]; var expectedSymbol = cs[0]; verify(); - // expectedOutput: "2" - comp = CreateCompilation(new[] { source1, source2 + main }); + comp = CreateCompilation(new[] { source1, source2 + main }, options: TestOptions.DebugExe); + comp.GetDiagnostics().Where(d => d.Code is not (int)ErrorCode.ERR_FileTypeNested).Verify(); outers = comp.GetMembers("Outer"); cs = outers.Select(o => ((NamedTypeSymbol)o).GetMember("C")).ToArray(); tree = comp.SyntaxTrees[1]; @@ -928,7 +1414,6 @@ static void Main() void verify() { - comp.VerifyDiagnostics(); Assert.Equal(2, cs.Length); Assert.Equal(comp.SyntaxTrees[0], cs[0].DeclaringSyntaxReferences.Single().SyntaxTree); Assert.Equal(comp.SyntaxTrees[1], cs[1].DeclaringSyntaxReferences.Single().SyntaxTree); @@ -1336,8 +1821,9 @@ static void Main() } """; - var comp = CreateCompilation(new[] { source1, source2 }); // PROTOTYPE(ft): expectedOutput: 2 - comp.VerifyDiagnostics(); + var verifier = CompileAndVerify(new[] { source1, source2 }, expectedOutput: "2"); + verifier.VerifyDiagnostics(); + var comp = (CSharpCompilation)verifier.Compilation; var tree = comp.SyntaxTrees[1]; var model = comp.GetSemanticModel(tree); @@ -1375,8 +1861,9 @@ static void Main() } """; - var comp = CreateCompilation(new[] { source1, source2 }); // PROTOTYPE(ft): expectedOutput: 1 - comp.VerifyDiagnostics(); + var verifier = CompileAndVerify(new[] { source1, source2 }, expectedOutput: "1"); + verifier.VerifyDiagnostics(); + var comp = (CSharpCompilation)verifier.Compilation; var tree = comp.SyntaxTrees[1]; var model = comp.GetSemanticModel(tree); @@ -1727,7 +2214,7 @@ public void AccessThroughType_01() class Outer { - file class C + file class C // 1 { public static void M() => Console.Write(1); } @@ -1737,17 +2224,18 @@ class Program { public static void Main() { - Outer.C.M(); // 1 + Outer.C.M(); // 2 } } """; - // note: there's no way to make 'file class C' internal here. it's forced to be private, at least for the initial release of the feature. - // we access it within the same containing type in test 'Duplication_10'. var comp = CreateCompilation(source); comp.VerifyDiagnostics( + // (5,16): error CS9303: File type 'Outer.C' must be defined in a top level type; 'Outer.C' is a nested type. + // file class C // 1 + Diagnostic(ErrorCode.ERR_FileTypeNested, "C").WithArguments("Outer.C").WithLocation(5, 16), // (15,15): error CS0122: 'Outer.C' is inaccessible due to its protection level - // Outer.C.M(); // 1 + // Outer.C.M(); // 2 Diagnostic(ErrorCode.ERR_BadAccess, "C").WithArguments("Outer.C").WithLocation(15, 15)); } @@ -1783,7 +2271,10 @@ static void Main() comp.VerifyDiagnostics( // (5,15): error CS0117: 'Outer' does not contain a definition for 'C' // Outer.C.M(); // 1 - Diagnostic(ErrorCode.ERR_NoSuchMember, "C").WithArguments("Outer", "C").WithLocation(5, 15)); + Diagnostic(ErrorCode.ERR_NoSuchMember, "C").WithArguments("Outer", "C").WithLocation(5, 15), + // (5,16): error CS9303: File type 'Outer.C' must be defined in a top level type; 'Outer.C' is a nested type. + // file class C + Diagnostic(ErrorCode.ERR_FileTypeNested, "C").WithArguments("Outer.C").WithLocation(5, 16)); } [Fact] @@ -1942,13 +2433,9 @@ public class D } """; - // var verifier = CompileAndVerify(new[] { source1, source2 }, expectedOutput: "1"); - // verifier.VerifyDiagnostics(); - // var comp = (CSharpCompilation)verifier.Compilation; - - // PROTOTYPE(ft): replace the following with the above commented lines once name mangling is done - var comp = CreateCompilation(new[] { source1, source2 }); - comp.VerifyDiagnostics(); + var verifier = CompileAndVerify(new[] { source1, source2 }, expectedOutput: "1"); + verifier.VerifyDiagnostics(); + var comp = (CSharpCompilation)verifier.Compilation; var tree = comp.SyntaxTrees[0]; var model = comp.GetSemanticModel(tree); @@ -1994,16 +2481,12 @@ class D } """; - // var verifier = CompileAndVerify(new[] { source1, source2 }, expectedOutput: "2"); - // verifier.VerifyDiagnostics(); - // var comp = (CSharpCompilation)verifier.Compilation; - - // PROTOTYPE(ft): replace the following with the above commented lines once name mangling is done - var comp = CreateCompilation(new[] { source1, source2 }); - comp.VerifyDiagnostics( + var verifier = CompileAndVerify(new[] { source1, source2 }, expectedOutput: "2"); + verifier.VerifyDiagnostics( // (2,1): hidden CS8019: Unnecessary using directive. // using static C; Diagnostic(ErrorCode.HDN_UnusedUsingDirective, "using static C;").WithLocation(2, 1)); + var comp = (CSharpCompilation)verifier.Compilation; var tree = comp.SyntaxTrees[0]; var model = comp.GetSemanticModel(tree); @@ -2052,9 +2535,20 @@ public static void Main() } """; - // 'Derived.C' is not actually accessible from 'Program', so we just bind to 'Base.C' and things work. - var compilation = CompileAndVerify(new[] { source, main }, expectedOutput: "1"); - compilation.VerifyDiagnostics(); + // 'Derived.C' is not actually accessible from 'Program', so we just bind to 'Base.C'. + var compilation = CreateCompilation(new[] { source, main }); + compilation.VerifyDiagnostics( + // (16,20): error CS9303: File type 'Derived.C' must be defined in a top level type; 'Derived.C' is a nested type. + // new file class C + Diagnostic(ErrorCode.ERR_FileTypeNested, "C").WithArguments("Derived.C").WithLocation(16, 20)); + + var expected = compilation.GetMember("Base.C.M"); + + var tree = compilation.SyntaxTrees[1]; + var model = compilation.GetSemanticModel(tree); + var invoked = tree.GetRoot().DescendantNodes().OfType().Single().Expression; + var symbolInfo = model.GetSymbolInfo(invoked); + Assert.Equal(expected, symbolInfo.Symbol.GetSymbol()); } [Fact] @@ -2443,12 +2937,11 @@ public static void M() { } var c1 = comp.GetMember("C1"); var c2 = comp.GetMember("C2"); - var format = SymbolDisplayFormat.TestFormat.WithCompilerInternalOptions(SymbolDisplayCompilerInternalOptions.IncludeContainingFileForFileTypes); - Assert.Equal("C1@", c1.ToDisplayString(format)); - Assert.Equal("C2@FileB", c2.ToDisplayString(format)); + Assert.Equal("C1@", c1.ToTestDisplayString()); + Assert.Equal("C2@FileB", c2.ToTestDisplayString()); - Assert.Equal("void C1@.M()", c1.GetMember("M").ToDisplayString(format)); - Assert.Equal("void C2@FileB.M()", c2.GetMember("M").ToDisplayString(format)); + Assert.Equal("void C1@.M()", c1.GetMember("M").ToTestDisplayString()); + Assert.Equal("void C2@FileB.M()", c2.GetMember("M").ToTestDisplayString()); } [Fact] @@ -2457,16 +2950,22 @@ public void Script_01() var source1 = """ using System; - C1.M(); + C1.M("a"); - file class C1 + static file class C1 { - public static void M() { } + public static void M(this string s) { } } """; var comp = CreateSubmission(source1, parseOptions: TestOptions.Script.WithLanguageVersion(LanguageVersion.Preview)); - comp.VerifyDiagnostics(); + comp.VerifyDiagnostics( + // (5,19): error CS9303: File type 'C1' must be defined in a top level type; 'C1' is a nested type. + // static file class C1 + Diagnostic(ErrorCode.ERR_FileTypeNested, "C1").WithArguments("C1").WithLocation(5, 19), + // (7,24): error CS1109: Extension methods must be defined in a top level static class; C1 is a nested class + // public static void M(this string s) { } + Diagnostic(ErrorCode.ERR_ExtensionMethodsDecl, "M").WithArguments("C1").WithLocation(7, 24)); } [Fact] @@ -2497,5 +2996,260 @@ file class Void { } Assert.Equal("System.Void@", typeInfo.Type!.ToDisplayString(SymbolDisplayFormat.TestFormat.WithCompilerInternalOptions(SymbolDisplayCompilerInternalOptions.IncludeContainingFileForFileTypes))); } - // PROTOTYPE(ft): public API (INamedTypeSymbol.IsFile?) + [Fact] + public void GetTypeByMetadataName_01() + { + var source1 = """ + file class C { } + """; + + // from source + var comp = CreateCompilation(source1); + comp.VerifyDiagnostics(); + var sourceMember = comp.GetMember("C"); + Assert.Equal("<>F0__C", sourceMember.MetadataName); + + var sourceType = comp.GetTypeByMetadataName("<>F0__C"); + Assert.Equal(sourceMember, sourceType); + + Assert.Null(comp.GetTypeByMetadataName("<>F0__D")); + Assert.Null(comp.GetTypeByMetadataName("<>F1__C")); + Assert.Null(comp.GetTypeByMetadataName("F0__C")); + Assert.Null(comp.GetTypeByMetadataName("F0__C")); + + // from metadata + var comp2 = CreateCompilation("", references: new[] { comp.EmitToImageReference() }); + comp2.VerifyDiagnostics(); + var metadataMember = comp2.GetMember("<>F0__C"); + Assert.Equal("<>F0__C", metadataMember.MetadataName); + + var metadataType = comp2.GetTypeByMetadataName("<>F0__C"); + Assert.Equal(metadataMember, metadataType); + } + + [Fact] + public void GetTypeByMetadataName_02() + { + var source1 = """ + file class C { } + """; + + // from source + var comp = CreateCompilation(source1); + comp.VerifyDiagnostics(); + var sourceMember = comp.GetMember("C"); + Assert.Equal("<>F0__C`1", sourceMember.MetadataName); + + var sourceType = comp.GetTypeByMetadataName("<>F0__C`1"); + Assert.Equal(sourceMember, sourceType); + Assert.Null(comp.GetTypeByMetadataName("<>F0__C")); + + // from metadata + var comp2 = CreateCompilation("", references: new[] { comp.EmitToImageReference() }); + comp2.VerifyDiagnostics(); + + var metadataMember = comp2.GetMember("<>F0__C"); + Assert.Equal("<>F0__C`1", metadataMember.MetadataName); + + var metadataType = comp2.GetTypeByMetadataName("<>F0__C`1"); + Assert.Equal(metadataMember, metadataType); + } + + [Fact] + public void GetTypeByMetadataName_03() + { + var source1 = """ + class Outer + { + file class C { } // 1 + } + """; + + // from source + var comp = CreateCompilation(source1); + comp.VerifyDiagnostics( + // (3,16): error CS9303: File type 'Outer.C' must be defined in a top level type; 'Outer.C' is a nested type. + // file class C { } // 1 + Diagnostic(ErrorCode.ERR_FileTypeNested, "C").WithArguments("Outer.C").WithLocation(3, 16)); + var sourceMember = comp.GetMember("Outer.C"); + Assert.Equal("<>F0__C", sourceMember.MetadataName); + + var sourceType = comp.GetTypeByMetadataName("Outer.<>F0__C"); + // Note: strictly speaking, it would be reasonable to return the (invalid) nested file type symbol here. + // However, since we don't actually support nested file types, we don't think we need the API to do the additional lookup + // when the requested type is nested, and so we end up giving a null here. + Assert.Null(sourceType); + } + + [Fact] + public void GetTypeByMetadataName_04() + { + var source1 = """ + file class C { } + """; + + var source2 = """ + class C { } + """; + + // from source + var comp = CreateCompilation(new[] { source1, source2 }); + comp.VerifyDiagnostics(); + var sourceMember = comp.GetMembers("C")[0]; + Assert.Equal("<>F0__C", sourceMember.MetadataName); + + var sourceType = comp.GetTypeByMetadataName("<>F0__C"); + Assert.Equal(sourceMember, sourceType); + + // from metadata + var comp2 = CreateCompilation("", references: new[] { comp.EmitToImageReference() }); + comp2.VerifyDiagnostics(); + + var metadataMember = comp2.GetMember("<>F0__C"); + Assert.Equal("<>F0__C", metadataMember.MetadataName); + + var metadataType = comp2.GetTypeByMetadataName("<>F0__C"); + Assert.Equal(metadataMember, metadataType); + } + + [CombinatorialData] + [Theory] + public void GetTypeByMetadataName_05(bool firstIsMetadataReference, bool secondIsMetadataReference) + { + var source1 = """ + file class C { } + """; + + // Create two references containing identically-named file types + var ref1 = CreateCompilation(source1, assemblyName: "ref1"); + var ref2 = CreateCompilation(source1, assemblyName: "ref2"); + + var comp = CreateCompilation("", references: new[] + { + firstIsMetadataReference ? ref1.ToMetadataReference() : ref1.EmitToImageReference(), + secondIsMetadataReference ? ref2.ToMetadataReference() : ref2.EmitToImageReference() + }); + comp.VerifyDiagnostics(); + + var sourceType = comp.GetTypeByMetadataName("<>F0__C"); + Assert.Null(sourceType); + + var types = comp.GetTypesByMetadataName("<>F0__C"); + Assert.Equal(2, types.Length); + Assert.Equal(firstIsMetadataReference ? "C@" : "<>F0__C", types[0].ToTestDisplayString()); + Assert.Equal(secondIsMetadataReference ? "C@" : "<>F0__C", types[1].ToTestDisplayString()); + Assert.NotEqual(types[0], types[1]); + } + + [Fact] + public void GetTypeByMetadataName_06() + { + var source1 = """ + file class C { } + file class C { } + """; + + var comp = CreateCompilation(source1); + comp.VerifyDiagnostics( + // (2,12): error CS0101: The namespace '' already contains a definition for 'C' + // file class C { } + Diagnostic(ErrorCode.ERR_DuplicateNameInNS, "C").WithArguments("C", "").WithLocation(2, 12)); + + var sourceType = ((Compilation)comp).GetTypeByMetadataName("<>F0__C"); + Assert.Equal("C@", sourceType.ToTestDisplayString()); + + var types = comp.GetTypesByMetadataName("<>F0__C"); + Assert.Equal(1, types.Length); + Assert.Same(sourceType, types[0]); + } + + [Fact] + public void GetTypeByMetadataName_07() + { + var source1 = """ + file class C { } + """; + + var comp = CreateCompilation(SyntaxFactory.ParseSyntaxTree(source1, options: TestOptions.RegularPreview, path: "path/to/SomeFile.cs")); + comp.VerifyDiagnostics(); + + Assert.Null(comp.GetTypeByMetadataName("<>F0__C")); + Assert.Empty(comp.GetTypesByMetadataName("<>F0__C")); + + Assert.Null(comp.GetTypeByMetadataName("F0__C")); + Assert.Empty(comp.GetTypesByMetadataName("F0__C")); + + var sourceType = ((Compilation)comp).GetTypeByMetadataName("F0__C"); + Assert.Equal("C@SomeFile", sourceType.ToTestDisplayString()); + + var types = comp.GetTypesByMetadataName("F0__C"); + Assert.Equal(1, types.Length); + Assert.Same(sourceType, types[0]); + } + + [Fact] + public void AssociatedSyntaxTree_01() + { + var source = """ + file class C + { + void M(C c) + { + } + } + """; + var comp = CreateCompilation(source); + comp.VerifyDiagnostics(); + + var tree = comp.SyntaxTrees[0]; + var model = comp.GetSemanticModel(tree); + var node = tree.GetRoot().DescendantNodes().OfType().Single(); + var type = model.GetTypeInfo(node.Type!).Type; + Assert.Equal("C@", type.ToTestDisplayString()); + Assert.Equal(tree, type.GetSymbol()!.AssociatedSyntaxTree); + } + + [Fact] + public void AssociatedSyntaxTree_02() + { + var source = """ + class C + { + void M(C c) + { + } + } + """; + var comp = CreateCompilation(source); + comp.VerifyDiagnostics(); + + var tree = comp.SyntaxTrees[0]; + var model = comp.GetSemanticModel(tree); + var node = tree.GetRoot().DescendantNodes().OfType().Single(); + var type = model.GetTypeInfo(node.Type!).Type; + Assert.Equal("C", type.ToTestDisplayString()); + Assert.Null(type.GetSymbol()!.AssociatedSyntaxTree); + } + + [Fact] + public void AssociatedSyntaxTree_03() + { + var source = """ + file class C + { + void M(C c) + { + } + } + """; + var comp = CreateCompilation(source); + comp.VerifyDiagnostics(); + + var tree = comp.SyntaxTrees[0]; + var model = comp.GetSemanticModel(tree); + var node = tree.GetRoot().DescendantNodes().OfType().Single(); + var type = model.GetTypeInfo(node.Type!).Type; + Assert.Equal("C@", type.ToTestDisplayString()); + Assert.Equal(tree, type.GetSymbol()!.AssociatedSyntaxTree); + } } diff --git a/src/Compilers/CSharp/Test/Syntax/Parsing/FileModifierParsingTests.cs b/src/Compilers/CSharp/Test/Syntax/Parsing/FileModifierParsingTests.cs index 95e79ed4401d2..0f7fbe85446b8 100644 --- a/src/Compilers/CSharp/Test/Syntax/Parsing/FileModifierParsingTests.cs +++ b/src/Compilers/CSharp/Test/Syntax/Parsing/FileModifierParsingTests.cs @@ -664,7 +664,13 @@ class Outer { file class C { } } - """); + """, + expectedBindingDiagnostics: new[] + { + // (3,16): error CS9303: File type 'Outer.C' must be defined in a top level type; 'Outer.C' is a nested type. + // file class C { } + Diagnostic(ErrorCode.ERR_FileTypeNested, "C").WithArguments("Outer.C").WithLocation(3, 16) + }); N(SyntaxKind.CompilationUnit); { @@ -1998,7 +2004,13 @@ class C { file record X(); } - """); + """, + expectedBindingDiagnostics: new[] + { + // (3,17): error CS9303: File type 'C.X' must be defined in a top level type; 'C.X' is a nested type. + // file record X(); + Diagnostic(ErrorCode.ERR_FileTypeNested, "X").WithArguments("C.X").WithLocation(3, 17) + }); N(SyntaxKind.CompilationUnit); { @@ -2090,7 +2102,13 @@ class C { file record X() { } } - """); + """, + expectedBindingDiagnostics: new[] + { + // (3,17): error CS9303: File type 'C.X' must be defined in a top level type; 'C.X' is a nested type. + // file record X() { } + Diagnostic(ErrorCode.ERR_FileTypeNested, "X").WithArguments("C.X").WithLocation(3, 17) + }); N(SyntaxKind.CompilationUnit); { @@ -2179,7 +2197,13 @@ class C { file record X; } - """); + """, + expectedBindingDiagnostics: new[] + { + // (3,17): error CS9303: File type 'C.X' must be defined in a top level type; 'C.X' is a nested type. + // file record X; + Diagnostic(ErrorCode.ERR_FileTypeNested, "X").WithArguments("C.X").WithLocation(3, 17) + }); N(SyntaxKind.CompilationUnit); { @@ -2202,6 +2226,32 @@ class C EOF(); } + [Fact] + public void FileRecord_04_CSharpNext() + { + UsingNode(""" + file record X(); + """); + + N(SyntaxKind.CompilationUnit); + { + 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.EndOfFileToken); + } + EOF(); + } + [Fact] public void LocalVariable_01() { diff --git a/src/Compilers/Core/Portable/CodeGen/CompilationTestData.cs b/src/Compilers/Core/Portable/CodeGen/CompilationTestData.cs index b0cb635e5360a..084f15f4153f2 100644 --- a/src/Compilers/Core/Portable/CodeGen/CompilationTestData.cs +++ b/src/Compilers/Core/Portable/CodeGen/CompilationTestData.cs @@ -68,7 +68,7 @@ public ImmutableDictionary GetMethodsByName() } private static readonly SymbolDisplayFormat _testDataKeyFormat = new SymbolDisplayFormat( - compilerInternalOptions: SymbolDisplayCompilerInternalOptions.UseMetadataMethodNames | SymbolDisplayCompilerInternalOptions.UseValueTuple, + compilerInternalOptions: SymbolDisplayCompilerInternalOptions.UseMetadataMethodNames | SymbolDisplayCompilerInternalOptions.UseValueTuple | SymbolDisplayCompilerInternalOptions.IncludeContainingFileForFileTypes, globalNamespaceStyle: SymbolDisplayGlobalNamespaceStyle.OmittedAsContaining, typeQualificationStyle: SymbolDisplayTypeQualificationStyle.NameAndContainingTypesAndNamespaces, genericsOptions: SymbolDisplayGenericsOptions.IncludeTypeParameters | SymbolDisplayGenericsOptions.IncludeVariance, diff --git a/src/Compilers/Core/Portable/CodeGen/PrivateImplementationDetails.cs b/src/Compilers/Core/Portable/CodeGen/PrivateImplementationDetails.cs index 123739a331653..d16b004e69fd8 100644 --- a/src/Compilers/Core/Portable/CodeGen/PrivateImplementationDetails.cs +++ b/src/Compilers/Core/Portable/CodeGen/PrivateImplementationDetails.cs @@ -592,6 +592,8 @@ public TypeDefinitionHandle TypeDef public bool MangleName => false; + public string? AssociatedFileIdentifier => null; + public virtual ushort Alignment => 0; public virtual Cci.ITypeReference GetBaseClass(EmitContext context) diff --git a/src/Compilers/Core/Portable/Emit/CommonPEModuleBuilder.cs b/src/Compilers/Core/Portable/Emit/CommonPEModuleBuilder.cs index e26ebb058b82b..bd9687d74c9a2 100644 --- a/src/Compilers/Core/Portable/Emit/CommonPEModuleBuilder.cs +++ b/src/Compilers/Core/Portable/Emit/CommonPEModuleBuilder.cs @@ -691,7 +691,7 @@ protected bool ContainsTopLevelType(string fullEmittedName) static void AddTopLevelType(HashSet names, Cci.INamespaceTypeDefinition type) // _namesOfTopLevelTypes are only used to generated exported types, which are not emitted in EnC deltas (hence generation 0): - => names?.Add(MetadataHelpers.BuildQualifiedName(type.NamespaceName, Cci.MetadataWriter.GetMangledName(type, generation: 0))); + => names?.Add(MetadataHelpers.BuildQualifiedName(type.NamespaceName, Cci.MetadataWriter.GetMetadataName(type, generation: 0))); } public virtual ImmutableArray GetAdditionalTopLevelTypes() diff --git a/src/Compilers/Core/Portable/Emit/ErrorType.cs b/src/Compilers/Core/Portable/Emit/ErrorType.cs index 79a43e38fc187..83d61eb70c3c3 100644 --- a/src/Compilers/Core/Portable/Emit/ErrorType.cs +++ b/src/Compilers/Core/Portable/Emit/ErrorType.cs @@ -55,6 +55,16 @@ bool Cci.INamedTypeReference.MangleName } } +#nullable enable + string? Cci.INamedTypeReference.AssociatedFileIdentifier + { + get + { + return null; + } + } +#nullable disable + bool Cci.ITypeReference.IsEnum { get diff --git a/src/Compilers/Core/Portable/Emit/NoPia/CommonEmbeddedType.cs b/src/Compilers/Core/Portable/Emit/NoPia/CommonEmbeddedType.cs index c5bf550d98e2a..2ab12dba66c50 100644 --- a/src/Compilers/Core/Portable/Emit/NoPia/CommonEmbeddedType.cs +++ b/src/Compilers/Core/Portable/Emit/NoPia/CommonEmbeddedType.cs @@ -675,6 +675,16 @@ bool Cci.INamedTypeReference.MangleName } } +#nullable enable + string? Cci.INamedTypeReference.AssociatedFileIdentifier + { + get + { + return UnderlyingNamedType.AssociatedFileIdentifier; + } + } +#nullable disable + string Cci.INamedEntity.Name { get diff --git a/src/Compilers/Core/Portable/MetadataReader/MetadataHelpers.cs b/src/Compilers/Core/Portable/MetadataReader/MetadataHelpers.cs index 440db10838871..e15e537b25a7d 100644 --- a/src/Compilers/Core/Portable/MetadataReader/MetadataHelpers.cs +++ b/src/Compilers/Core/Portable/MetadataReader/MetadataHelpers.cs @@ -470,10 +470,12 @@ internal static string GetAritySuffix(int arity) return (arity <= 9) ? s_aritySuffixesOneToNine[arity - 1] : string.Concat(GenericTypeNameManglingString, arity.ToString(CultureInfo.InvariantCulture)); } - internal static string ComposeAritySuffixedMetadataName(string name, int arity) +#nullable enable + internal static string ComposeAritySuffixedMetadataName(string name, int arity, string? associatedFileIdentifier) { - return arity == 0 ? name : name + GetAritySuffix(arity); + return associatedFileIdentifier + (arity == 0 ? name : name + GetAritySuffix(arity)); } +#nullable disable internal static int InferTypeArityFromMetadataName(string emittedTypeName) { diff --git a/src/Compilers/Core/Portable/NativePdbWriter/SymWriterMetadataProvider.cs b/src/Compilers/Core/Portable/NativePdbWriter/SymWriterMetadataProvider.cs index bcd9b1cc00509..e306f811888c4 100644 --- a/src/Compilers/Core/Portable/NativePdbWriter/SymWriterMetadataProvider.cs +++ b/src/Compilers/Core/Portable/NativePdbWriter/SymWriterMetadataProvider.cs @@ -45,7 +45,7 @@ public bool TryGetTypeDefinitionInfo(int typeDefinitionToken, out string namespa else { int generation = (t is INamedTypeDefinition namedType) ? _writer.Module.GetTypeDefinitionGeneration(namedType) : 0; - typeName = MetadataWriter.GetMangledName((INamedTypeReference)t, generation); + typeName = MetadataWriter.GetMetadataName((INamedTypeReference)t, generation); INamespaceTypeDefinition namespaceTypeDef; if ((namespaceTypeDef = t.AsNamespaceTypeDefinition(_writer.Context)) != null) diff --git a/src/Compilers/Core/Portable/PEWriter/MetadataWriter.cs b/src/Compilers/Core/Portable/PEWriter/MetadataWriter.cs index 24b0def4eb4c9..30bb8fa8e6d43 100644 --- a/src/Compilers/Core/Portable/PEWriter/MetadataWriter.cs +++ b/src/Compilers/Core/Portable/PEWriter/MetadataWriter.cs @@ -916,13 +916,13 @@ private static uint GetManagedResourceOffset(BlobBuilder resource, BlobBuilder r return (uint)result; } - public static string GetMangledName(INamedTypeReference namedType, int generation) + public static string GetMetadataName(INamedTypeReference namedType, int generation) { - string unmangledName = (generation == 0) ? namedType.Name : namedType.Name + "#" + generation; - - return namedType.MangleName - ? MetadataHelpers.ComposeAritySuffixedMetadataName(unmangledName, namedType.GenericParameterCount) - : unmangledName; + string nameWithGeneration = (generation == 0) ? namedType.Name : namedType.Name + "#" + generation; + string fileIdentifier = namedType.AssociatedFileIdentifier; + return namedType.MangleName || fileIdentifier != null + ? MetadataHelpers.ComposeAritySuffixedMetadataName(nameWithGeneration, namedType.GenericParameterCount, fileIdentifier) + : nameWithGeneration; } internal MemberReferenceHandle GetMemberReferenceHandle(ITypeMemberReference memberRef) @@ -2219,10 +2219,10 @@ private void PopulateExportedTypeTableRows() if ((namespaceTypeRef = exportedType.Type.AsNamespaceTypeReference) != null) { // exported types are not emitted in EnC deltas (hence generation 0): - string mangledTypeName = GetMangledName(namespaceTypeRef, generation: 0); + string metadataTypeName = GetMetadataName(namespaceTypeRef, generation: 0); - typeName = GetStringHandleForNameAndCheckLength(mangledTypeName, namespaceTypeRef); - typeNamespace = GetStringHandleForNamespaceAndCheckLength(namespaceTypeRef, mangledTypeName); + typeName = GetStringHandleForNameAndCheckLength(metadataTypeName, namespaceTypeRef); + typeNamespace = GetStringHandleForNamespaceAndCheckLength(namespaceTypeRef, metadataTypeName); implementation = GetExportedTypeImplementation(namespaceTypeRef); attributes = exportedType.IsForwarder ? TypeAttributes.NotPublic | Constants.TypeAttributes_TypeForwarder : TypeAttributes.Public; } @@ -2231,9 +2231,9 @@ private void PopulateExportedTypeTableRows() Debug.Assert(exportedType.ParentIndex != -1); // exported types are not emitted in EnC deltas (hence generation 0): - string mangledTypeName = GetMangledName(nestedRef, generation: 0); + string metadataTypeName = GetMetadataName(nestedRef, generation: 0); - typeName = GetStringHandleForNameAndCheckLength(mangledTypeName, nestedRef); + typeName = GetStringHandleForNameAndCheckLength(metadataTypeName, nestedRef); typeNamespace = default(StringHandle); implementation = MetadataTokens.ExportedTypeHandle(exportedType.ParentIndex + 1); attributes = exportedType.IsForwarder ? TypeAttributes.NotPublic : TypeAttributes.NestedPublic; @@ -2710,13 +2710,13 @@ private void PopulateTypeDefTableRows() var moduleBuilder = Context.Module; int generation = moduleBuilder.GetTypeDefinitionGeneration(typeDef); - string mangledTypeName = GetMangledName(typeDef, generation); + string metadataTypeName = GetMetadataName(typeDef, generation); ITypeReference baseType = typeDef.GetBaseClass(Context); metadata.AddTypeDefinition( attributes: GetTypeAttributes(typeDef), - @namespace: (namespaceType != null) ? GetStringHandleForNamespaceAndCheckLength(namespaceType, mangledTypeName) : default(StringHandle), - name: GetStringHandleForNameAndCheckLength(mangledTypeName, typeDef), + @namespace: (namespaceType != null) ? GetStringHandleForNamespaceAndCheckLength(namespaceType, metadataTypeName) : default(StringHandle), + name: GetStringHandleForNameAndCheckLength(metadataTypeName, typeDef), baseType: (baseType != null) ? GetTypeHandle(baseType) : default(EntityHandle), fieldList: GetFirstFieldDefinitionHandle(typeDef), methodList: GetFirstMethodDefinitionHandle(typeDef)); @@ -2785,9 +2785,9 @@ private void PopulateTypeRefTableRows() // It's not possible to reference newer versions of reloadable types from another assembly, hence generation 0: // TODO: https://github.com/dotnet/roslyn/issues/54981 - string mangledTypeName = GetMangledName(nestedTypeRef, generation: 0); + string metadataTypeName = GetMetadataName(nestedTypeRef, generation: 0); - name = this.GetStringHandleForNameAndCheckLength(mangledTypeName, nestedTypeRef); + name = this.GetStringHandleForNameAndCheckLength(metadataTypeName, nestedTypeRef); @namespace = default(StringHandle); } else @@ -2802,10 +2802,10 @@ private void PopulateTypeRefTableRows() // It's not possible to reference newer versions of reloadable types from another assembly, hence generation 0: // TODO: https://github.com/dotnet/roslyn/issues/54981 - string mangledTypeName = GetMangledName(namespaceTypeRef, generation: 0); + string metadataTypeName = GetMetadataName(namespaceTypeRef, generation: 0); - name = this.GetStringHandleForNameAndCheckLength(mangledTypeName, namespaceTypeRef); - @namespace = this.GetStringHandleForNamespaceAndCheckLength(namespaceTypeRef, mangledTypeName); + name = this.GetStringHandleForNameAndCheckLength(metadataTypeName, namespaceTypeRef); + @namespace = this.GetStringHandleForNamespaceAndCheckLength(namespaceTypeRef, metadataTypeName); } metadata.AddTypeReference( diff --git a/src/Compilers/Core/Portable/PEWriter/RootModuleType.cs b/src/Compilers/Core/Portable/PEWriter/RootModuleType.cs index f90f9f573c9e6..dd6391debef0f 100644 --- a/src/Compilers/Core/Portable/PEWriter/RootModuleType.cs +++ b/src/Compilers/Core/Portable/PEWriter/RootModuleType.cs @@ -58,6 +58,11 @@ public bool MangleName get { return false; } } + public string? AssociatedFileIdentifier + { + get { return null; } + } + public string Name { get { return ""; } diff --git a/src/Compilers/Core/Portable/PEWriter/TypeNameSerializer.cs b/src/Compilers/Core/Portable/PEWriter/TypeNameSerializer.cs index 29115ffdff6a5..8a1639677e959 100644 --- a/src/Compilers/Core/Portable/PEWriter/TypeNameSerializer.cs +++ b/src/Compilers/Core/Portable/PEWriter/TypeNameSerializer.cs @@ -10,6 +10,7 @@ using Microsoft.CodeAnalysis.PooledObjects; using System.Text; using System.Diagnostics; +using System.Linq; namespace Microsoft.Cci { @@ -71,7 +72,7 @@ internal static string GetSerializedTypeName(this ITypeReference typeReference, sb.Append('.'); } - sb.Append(GetMangledAndEscapedName(namespaceType)); + sb.Append(GetEscapedMetadataName(namespaceType)); goto done; } @@ -113,7 +114,7 @@ internal static string GetSerializedTypeName(this ITypeReference typeReference, bool nestedTypeIsAssemblyQualified = false; sb.Append(GetSerializedTypeName(nestedType.GetContainingType(context), context, ref nestedTypeIsAssemblyQualified)); sb.Append('+'); - sb.Append(GetMangledAndEscapedName(nestedType)); + sb.Append(GetEscapedMetadataName(nestedType)); goto done; } @@ -193,12 +194,18 @@ private static void AppendAssemblyQualifierIfNecessary(StringBuilder sb, ITypeRe } } - private static string GetMangledAndEscapedName(INamedTypeReference namedType) + private static string GetEscapedMetadataName(INamedTypeReference namedType) { var pooled = PooledStringBuilder.GetInstance(); StringBuilder mangledName = pooled.Builder; const string needsEscaping = "\\[]*.+,& "; + if (namedType.AssociatedFileIdentifier is string fileIdentifier) + { + Debug.Assert(needsEscaping.All(c => !fileIdentifier.Contains(c))); + mangledName.Append(fileIdentifier); + } + foreach (var ch in namedType.Name) { if (needsEscaping.IndexOf(ch) >= 0) diff --git a/src/Compilers/Core/Portable/PEWriter/Types.cs b/src/Compilers/Core/Portable/PEWriter/Types.cs index 97e957df38f1c..2a4e50b50ac52 100644 --- a/src/Compilers/Core/Portable/PEWriter/Types.cs +++ b/src/Compilers/Core/Portable/PEWriter/Types.cs @@ -253,6 +253,9 @@ internal interface INamedTypeReference : ITypeReference, INamedEntity /// If true, the persisted type name is mangled by appending "`n" where n is the number of type parameters, if the number of type parameters is greater than 0. /// bool MangleName { get; } + + /// Indicates that the type is scoped to the file it is declared in. Used as a prefix for the metadata name. + string? AssociatedFileIdentifier { get; } } /// diff --git a/src/Compilers/Core/Portable/SymbolDisplay/SymbolDisplayCompilerInternalOptions.cs b/src/Compilers/Core/Portable/SymbolDisplay/SymbolDisplayCompilerInternalOptions.cs index a0a688a22b402..2bf7dd3ca6047 100644 --- a/src/Compilers/Core/Portable/SymbolDisplay/SymbolDisplayCompilerInternalOptions.cs +++ b/src/Compilers/Core/Portable/SymbolDisplay/SymbolDisplayCompilerInternalOptions.cs @@ -62,6 +62,7 @@ internal enum SymbolDisplayCompilerInternalOptions /// Display `System.[U]IntPtr` instead of `n[u]int`. /// UseNativeIntegerUnderlyingType = 1 << 7, + /// /// Separate out nested types from containing types using + instead of . (dot). /// diff --git a/src/Compilers/Core/Portable/SymbolDisplay/SymbolDisplayFormat.cs b/src/Compilers/Core/Portable/SymbolDisplay/SymbolDisplayFormat.cs index d8a5dc6aba65e..20f8c6d92d74c 100644 --- a/src/Compilers/Core/Portable/SymbolDisplay/SymbolDisplayFormat.cs +++ b/src/Compilers/Core/Portable/SymbolDisplay/SymbolDisplayFormat.cs @@ -202,7 +202,8 @@ public class SymbolDisplayFormat SymbolDisplayCompilerInternalOptions.IncludeScriptType | SymbolDisplayCompilerInternalOptions.UseMetadataMethodNames | SymbolDisplayCompilerInternalOptions.FlagMissingMetadataTypes | - SymbolDisplayCompilerInternalOptions.IncludeCustomModifiers); + SymbolDisplayCompilerInternalOptions.IncludeCustomModifiers | + SymbolDisplayCompilerInternalOptions.IncludeContainingFileForFileTypes); /// /// A verbose format for displaying symbols (useful for testing). diff --git a/src/Compilers/VisualBasic/Portable/Binding/Binder_Symbols.vb b/src/Compilers/VisualBasic/Portable/Binding/Binder_Symbols.vb index 22f8d32a16009..0ea8e1ba9b275 100644 --- a/src/Compilers/VisualBasic/Portable/Binding/Binder_Symbols.vb +++ b/src/Compilers/VisualBasic/Portable/Binding/Binder_Symbols.vb @@ -375,7 +375,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic If rightPart.Kind = SyntaxKind.GenericName Then arity = DirectCast(rightPart, GenericNameSyntax).Arity - fullName = MetadataHelpers.ComposeAritySuffixedMetadataName(currDiagName, arity) + fullName = MetadataHelpers.ComposeAritySuffixedMetadataName(currDiagName, arity, associatedFileIdentifier:=Nothing) End If forwardedToAssembly = GetForwardedToAssembly(containingAssembly, fullName, arity, typeSyntax, diagBag) diff --git a/src/Compilers/VisualBasic/Portable/Emit/NamedTypeReference.vb b/src/Compilers/VisualBasic/Portable/Emit/NamedTypeReference.vb index bafab6592ced3..30f4422a89728 100644 --- a/src/Compilers/VisualBasic/Portable/Emit/NamedTypeReference.vb +++ b/src/Compilers/VisualBasic/Portable/Emit/NamedTypeReference.vb @@ -30,6 +30,12 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Emit End Get End Property + Private ReadOnly Property INamedTypeReferenceAssociatedFileIdentifier As String Implements Cci.INamedTypeReference.AssociatedFileIdentifier + Get + Return Nothing + End Get + End Property + Private ReadOnly Property INamedEntityName As String Implements Cci.INamedEntity.Name Get ' CCI automatically handles type suffix, so use Name instead of MetadataName diff --git a/src/Compilers/VisualBasic/Portable/Emit/NamedTypeSymbolAdapter.vb b/src/Compilers/VisualBasic/Portable/Emit/NamedTypeSymbolAdapter.vb index 7e5181c4d4a07..c857d34202f5a 100644 --- a/src/Compilers/VisualBasic/Portable/Emit/NamedTypeSymbolAdapter.vb +++ b/src/Compilers/VisualBasic/Portable/Emit/NamedTypeSymbolAdapter.vb @@ -758,6 +758,12 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols End Get End Property + Private ReadOnly Property INamedTypeReferenceAssociatedFileIdentifier As String Implements INamedTypeReference.AssociatedFileIdentifier + Get + Return Nothing + End Get + End Property + Private ReadOnly Property INamedEntityName As String Implements INamedEntity.Name Get ' CCI automatically adds the arity suffix, so we return Name, not MetadataName here. diff --git a/src/Compilers/VisualBasic/Portable/Emit/PEModuleBuilder.vb b/src/Compilers/VisualBasic/Portable/Emit/PEModuleBuilder.vb index 619f9b8c1f77f..22b2eeed16b1e 100644 --- a/src/Compilers/VisualBasic/Portable/Emit/PEModuleBuilder.vb +++ b/src/Compilers/VisualBasic/Portable/Emit/PEModuleBuilder.vb @@ -443,7 +443,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Emit ' exported types are not emitted in EnC deltas (hence generation 0): Dim fullEmittedName As String = MetadataHelpers.BuildQualifiedName( DirectCast(typeReference, Cci.INamespaceTypeReference).NamespaceName, - Cci.MetadataWriter.GetMangledName(DirectCast(typeReference, Cci.INamedTypeReference), generation:=0)) + Cci.MetadataWriter.GetMetadataName(DirectCast(typeReference, Cci.INamedTypeReference), generation:=0)) ' First check against types declared in the primary module If ContainsTopLevelType(fullEmittedName) Then diff --git a/src/Compilers/VisualBasic/Portable/Symbols/NamedTypeSymbol.vb b/src/Compilers/VisualBasic/Portable/Symbols/NamedTypeSymbol.vb index 77b23983ca0b2..c75ff30f818e3 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/NamedTypeSymbol.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/NamedTypeSymbol.vb @@ -159,7 +159,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols ' Therefore it is a good practice to avoid type names with dots. Debug.Assert(Me.IsErrorType OrElse Not (TypeOf Me Is SourceNamedTypeSymbol) OrElse Not Name.Contains("."), "type name contains dots: " + Name) - Return If(MangleName, MetadataHelpers.ComposeAritySuffixedMetadataName(Name, Arity), Name) + Return If(MangleName, MetadataHelpers.ComposeAritySuffixedMetadataName(Name, Arity, associatedFileIdentifier:=Nothing), Name) End Get End Property diff --git a/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/Symbols/EENamedTypeSymbol.cs b/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/Symbols/EENamedTypeSymbol.cs index b6856a5f05ff1..2ee0b8d7df52f 100644 --- a/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/Symbols/EENamedTypeSymbol.cs +++ b/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/Symbols/EENamedTypeSymbol.cs @@ -159,6 +159,10 @@ internal override bool MangleName get { return false; } } + // https://github.com/dotnet/roslyn/issues/61999 + // Determine if 'null' is the right return value here + internal override SyntaxTree AssociatedSyntaxTree => null; + public override IEnumerable MemberNames { get { throw ExceptionUtilities.Unreachable; } diff --git a/src/ExpressionEvaluator/Core/Test/ExpressionCompiler/NamespaceTypeDefinitionNoBase.cs b/src/ExpressionEvaluator/Core/Test/ExpressionCompiler/NamespaceTypeDefinitionNoBase.cs index d602dcf4c985e..b2cf692ad5453 100644 --- a/src/ExpressionEvaluator/Core/Test/ExpressionCompiler/NamespaceTypeDefinitionNoBase.cs +++ b/src/ExpressionEvaluator/Core/Test/ExpressionCompiler/NamespaceTypeDefinitionNoBase.cs @@ -77,6 +77,10 @@ internal NamespaceTypeDefinitionNoBase(INamespaceTypeDefinition underlyingType) bool INamedTypeReference.MangleName => UnderlyingType.MangleName; +#nullable enable + string? INamedTypeReference.AssociatedFileIdentifier => UnderlyingType.AssociatedFileIdentifier; +#nullable disable + string INamedEntity.Name => UnderlyingType.Name; string INamespaceTypeReference.NamespaceName => UnderlyingType.NamespaceName; From 332fa0afa4aecd4402bae99e1913629c1108899d Mon Sep 17 00:00:00 2001 From: Rikki Gibson Date: Wed, 29 Jun 2022 17:31:30 -0700 Subject: [PATCH 06/11] Give an error when a file type is used in a global using static (#62258) --- .../CSharp/Portable/CSharpResources.resx | 3 + .../CSharp/Portable/Errors/ErrorCode.cs | 1 + .../SourceNamespaceSymbol.AliasesAndUsings.cs | 5 ++ .../Portable/xlf/CSharpResources.cs.xlf | 5 ++ .../Portable/xlf/CSharpResources.de.xlf | 5 ++ .../Portable/xlf/CSharpResources.es.xlf | 5 ++ .../Portable/xlf/CSharpResources.fr.xlf | 5 ++ .../Portable/xlf/CSharpResources.it.xlf | 5 ++ .../Portable/xlf/CSharpResources.ja.xlf | 5 ++ .../Portable/xlf/CSharpResources.ko.xlf | 5 ++ .../Portable/xlf/CSharpResources.pl.xlf | 5 ++ .../Portable/xlf/CSharpResources.pt-BR.xlf | 5 ++ .../Portable/xlf/CSharpResources.ru.xlf | 5 ++ .../Portable/xlf/CSharpResources.tr.xlf | 5 ++ .../Portable/xlf/CSharpResources.zh-Hans.xlf | 5 ++ .../Portable/xlf/CSharpResources.zh-Hant.xlf | 5 ++ .../Symbols/Source/FileModifierTests.cs | 55 ++++++++++++++++--- 17 files changed, 122 insertions(+), 7 deletions(-) diff --git a/src/Compilers/CSharp/Portable/CSharpResources.resx b/src/Compilers/CSharp/Portable/CSharpResources.resx index 139e9ce8ccbf4..941de7567e043 100644 --- a/src/Compilers/CSharp/Portable/CSharpResources.resx +++ b/src/Compilers/CSharp/Portable/CSharpResources.resx @@ -7115,6 +7115,9 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ File type '{0}' must be defined in a top level type; '{0}' is a nested type. + + File type '{0}' cannot be used in a 'global using static' directive. + unsigned right shift diff --git a/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs b/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs index 255f4583dd594..f91117d77cb88 100644 --- a/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs +++ b/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs @@ -2096,6 +2096,7 @@ internal enum ErrorCode ERR_FileTypeNoExplicitAccessibility = 9301, ERR_FileTypeBase = 9302, ERR_FileTypeNested = 9303, + ERR_GlobalUsingStaticFileType = 9304 #endregion diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceNamespaceSymbol.AliasesAndUsings.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceNamespaceSymbol.AliasesAndUsings.cs index a3d202bebc10e..b1098e3ea273f 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceNamespaceSymbol.AliasesAndUsings.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceNamespaceSymbol.AliasesAndUsings.cs @@ -757,6 +757,11 @@ UsingsAndDiagnostics buildUsings( else { var importedType = (NamedTypeSymbol)imported; + if (usingDirective.GlobalKeyword != default(SyntaxToken) && importedType.IsFileTypeOrUsesFileTypes()) + { + diagnostics.Add(ErrorCode.ERR_GlobalUsingStaticFileType, usingDirective.Name.Location, imported); + } + if (!getOrCreateUniqueUsings(ref uniqueUsings, globalUsingNamespacesOrTypes).Add(importedType)) { diagnostics.Add(!globalUsingNamespacesOrTypes.IsEmpty && getOrCreateUniqueGlobalUsingsNotInTree(ref uniqueGlobalUsings, globalUsingNamespacesOrTypes, declarationSyntax.SyntaxTree).Contains(imported) ? diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf index 4edff182eda01..553ae7c029879 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf @@ -627,6 +627,11 @@ Globální direktiva using musí předcházet všem direktivám using, které nejsou globální. + + File type '{0}' cannot be used in a 'global using static' directive. + File type '{0}' cannot be used in a 'global using static' directive. + + A goto cannot jump to a location before a using declaration within the same block. Příkaz goto nemůže přejít na místo před deklarací using ve stejném bloku. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf index 0d5dbb6ca6d5b..541c2e0bd60d5 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf @@ -627,6 +627,11 @@ Eine globale using-Anweisung muss allen nicht globalen using-Anweisungen vorangehen. + + File type '{0}' cannot be used in a 'global using static' directive. + File type '{0}' cannot be used in a 'global using static' directive. + + A goto cannot jump to a location before a using declaration within the same block. Mit "goto" kann nicht an eine Position vor einer using-Deklaration im selben Block gesprungen werden. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf index c146398c4d563..371a0abd07553 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf @@ -627,6 +627,11 @@ Una directiva de uso global debe ser anterior a todas las directivas no globales que no son de uso. + + File type '{0}' cannot be used in a 'global using static' directive. + File type '{0}' cannot be used in a 'global using static' directive. + + A goto cannot jump to a location before a using declaration within the same block. Una instrucción goto no puede saltar a una ubicación antes que una declaración using dentro del mismo bloque. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf index 52798620fbaf0..f9c476fe63e8e 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf @@ -627,6 +627,11 @@ Une directive using globale doit précéder toutes les directives using non globales. + + File type '{0}' cannot be used in a 'global using static' directive. + File type '{0}' cannot be used in a 'global using static' directive. + + A goto cannot jump to a location before a using declaration within the same block. Un goto ne peut pas accéder à un emplacement avant une déclaration using dans le même bloc. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf index 177e269e704dc..9b21120e04b0f 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf @@ -627,6 +627,11 @@ Una direttiva sull'utilizzo globale deve precedere tutte le direttiva non sull'uso non globale. + + File type '{0}' cannot be used in a 'global using static' directive. + File type '{0}' cannot be used in a 'global using static' directive. + + A goto cannot jump to a location before a using declaration within the same block. Un'istruzione goto non può passare a una posizione che precede una dichiarazione using all'interno dello stesso blocco. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf index 49343625d8876..69f89a4cc4585 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf @@ -627,6 +627,11 @@ グローバル using ディレクティブは、すべての非グローバル using ディレクティブの前に指定する必要があります。 + + File type '{0}' cannot be used in a 'global using static' directive. + File type '{0}' cannot be used in a 'global using static' directive. + + A goto cannot jump to a location before a using declaration within the same block. goto は同じブロック内の using 宣言より前の位置にはジャンプできません。 diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf index 0199e0ab379a3..fe1ad3bc7b2cc 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf @@ -627,6 +627,11 @@ 전역 using 지시문은 전역이 아닌 모든 using 지시문 앞에 있어야 합니다. + + File type '{0}' cannot be used in a 'global using static' directive. + File type '{0}' cannot be used in a 'global using static' directive. + + A goto cannot jump to a location before a using declaration within the same block. goto는 동일한 블록 내의 using 선언 앞 위치로 이동할 수 없습니다. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf index bfe3edd993e2e..c8f32f240de6e 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf @@ -627,6 +627,11 @@ Globalne używające dyrektywy muszą poprzedzać wszystkie nieglobalne używające dyrektywy. + + File type '{0}' cannot be used in a 'global using static' directive. + File type '{0}' cannot be used in a 'global using static' directive. + + A goto cannot jump to a location before a using declaration within the same block. Instrukcja goto nie może przechodzić do lokalizacji występującej przed deklaracją using w tym samym bloku. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf index 51ef2f7c6d194..19a4209e27893 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf @@ -627,6 +627,11 @@ Uma diretiva de uso global deve preceder todas as diretivas de uso não global. + + File type '{0}' cannot be used in a 'global using static' directive. + File type '{0}' cannot be used in a 'global using static' directive. + + A goto cannot jump to a location before a using declaration within the same block. Um goto não pode saltar para um local antes de uma declaração using no mesmo bloco. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf index 49fe2ce705ee8..610c0398dd0f6 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf @@ -627,6 +627,11 @@ Глобальная директива using должна предшествовать всем неглобальным директивам using. + + File type '{0}' cannot be used in a 'global using static' directive. + File type '{0}' cannot be used in a 'global using static' directive. + + A goto cannot jump to a location before a using declaration within the same block. Оператор goto не может переходить к расположению раньше объявления using в том же блоке. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf index 9daaaba095219..f0dc2c30b3dfd 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf @@ -627,6 +627,11 @@ Genel bir using yönergesi genel olmayan tüm using yönergelerinden önce gelmelidir. + + File type '{0}' cannot be used in a 'global using static' directive. + File type '{0}' cannot be used in a 'global using static' directive. + + A goto cannot jump to a location before a using declaration within the same block. Bir goto, aynı blok içinde yer alan using bildiriminden önceki bir konuma atlayamaz. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf index 211e53063cd85..0252b3abb7b06 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf @@ -627,6 +627,11 @@ 全局 using 指令必须位于所有非全局 using 指令之前。 + + File type '{0}' cannot be used in a 'global using static' directive. + File type '{0}' cannot be used in a 'global using static' directive. + + A goto cannot jump to a location before a using declaration within the same block. goto 无法跳转到同一块中 using 声明之前的某个位置。 diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf index 9ac1bddbf4c14..d8d561655ec9e 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf @@ -627,6 +627,11 @@ 全域 using 指示詞必須在所有非全域 using 指示詞之前。 + + File type '{0}' cannot be used in a 'global using static' directive. + File type '{0}' cannot be used in a 'global using static' directive. + + A goto cannot jump to a location before a using declaration within the same block. 在相同區塊內,goto 不可跳到 using 宣告前的位置。 diff --git a/src/Compilers/CSharp/Test/Symbol/Symbols/Source/FileModifierTests.cs b/src/Compilers/CSharp/Test/Symbol/Symbols/Source/FileModifierTests.cs index 0fbb15b774fbb..dfc93da7eedfc 100644 --- a/src/Compilers/CSharp/Test/Symbol/Symbols/Source/FileModifierTests.cs +++ b/src/Compilers/CSharp/Test/Symbol/Symbols/Source/FileModifierTests.cs @@ -2364,15 +2364,56 @@ public static void Main() } """; - // PROTOTYPE(ft): it should probably be an error to reference a file type in a global using static var compilation = CreateCompilation(new[] { source, main }); compilation.VerifyDiagnostics( - // (1,1): hidden CS8019: Unnecessary using directive. - // global using static C; - Diagnostic(ErrorCode.HDN_UnusedUsingDirective, "global using static C;").WithLocation(1, 1), - // (5,9): error CS0103: The name 'M' does not exist in the current context - // M(); - Diagnostic(ErrorCode.ERR_NameNotInContext, "M").WithArguments("M").WithLocation(5, 9)); + // (1,1): hidden CS8019: Unnecessary using directive. + // global using static C; + Diagnostic(ErrorCode.HDN_UnusedUsingDirective, "global using static C;").WithLocation(1, 1), + // (1,21): error CS9304: File type 'C' cannot be used in a 'global using static' directive. + // global using static C; + Diagnostic(ErrorCode.ERR_GlobalUsingStaticFileType, "C").WithArguments("C").WithLocation(1, 21), + // (5,9): error CS0103: The name 'M' does not exist in the current context + // M(); + Diagnostic(ErrorCode.ERR_NameNotInContext, "M").WithArguments("M").WithLocation(5, 9)); + } + + [Fact] + public void GlobalUsingStatic_02() + { + var source = """ + global using static Container; + + public class Container + { + } + + file class C + { + public static void M() { } + } + """; + + var main = """ + class Program + { + public static void Main() + { + M(); + } + } + """; + + var compilation = CreateCompilation(new[] { source, main }); + compilation.VerifyDiagnostics( + // (1,1): hidden CS8019: Unnecessary using directive. + // global using static Container; + Diagnostic(ErrorCode.HDN_UnusedUsingDirective, "global using static Container;").WithLocation(1, 1), + // (1,21): error CS9304: File type 'Container' cannot be used in a 'global using static' directive. + // global using static Container; + Diagnostic(ErrorCode.ERR_GlobalUsingStaticFileType, "Container").WithArguments("Container").WithLocation(1, 21), + // (5,9): error CS0103: The name 'M' does not exist in the current context + // M(); + Diagnostic(ErrorCode.ERR_NameNotInContext, "M").WithArguments("M").WithLocation(5, 9)); } [Fact] From fa2182bc0d9b355c33b4f4be3b0bf8750cb47bb6 Mon Sep 17 00:00:00 2001 From: Youssef Victor Date: Thu, 30 Jun 2022 21:29:57 +0200 Subject: [PATCH 07/11] Fix add accessibility for file types (#62275) --- .../AddAccessibilityModifiersTests.cs | 66 +++++++++++++++++++ .../SyntaxFacts/CSharpAccessibilityFacts.cs | 2 + 2 files changed, 68 insertions(+) diff --git a/src/Analyzers/CSharp/Tests/AddAccessibilityModifiers/AddAccessibilityModifiersTests.cs b/src/Analyzers/CSharp/Tests/AddAccessibilityModifiers/AddAccessibilityModifiersTests.cs index 143b42bf932bb..75a4ca3e5a51c 100644 --- a/src/Analyzers/CSharp/Tests/AddAccessibilityModifiers/AddAccessibilityModifiersTests.cs +++ b/src/Analyzers/CSharp/Tests/AddAccessibilityModifiers/AddAccessibilityModifiersTests.cs @@ -611,5 +611,71 @@ internal class C : I await test.RunAsync(); } + + [Theory, Trait(Traits.Feature, Traits.Features.CodeActionsAddAccessibilityModifiers)] + [InlineData("class")] + [InlineData("struct")] + [InlineData("record")] + [InlineData("record struct")] + [InlineData("interface")] + [InlineData("enum")] + [WorkItem(62259, "https://github.com/dotnet/roslyn/issues/62259")] + public async Task TestFileDeclaration(string declarationKind) + { + var source = $"file {declarationKind} C {{ }}"; + + await new VerifyCS.Test + { + TestCode = source, + FixedCode = source, + LanguageVersion = LanguageVersion.Preview, + }.RunAsync(); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsAddAccessibilityModifiers)] + [WorkItem(62259, "https://github.com/dotnet/roslyn/issues/62259")] + public async Task TestFileDelegate() + { + var source = "file delegate void M();"; + + await new VerifyCS.Test + { + TestCode = source, + FixedCode = source, + LanguageVersion = LanguageVersion.Preview, + }.RunAsync(); + } + + [Theory, Trait(Traits.Feature, Traits.Features.CodeActionsAddAccessibilityModifiers)] + [InlineData("class")] + [InlineData("struct")] + [InlineData("record")] + [InlineData("record struct")] + [InlineData("interface")] + [InlineData("enum")] + [WorkItem(62259, "https://github.com/dotnet/roslyn/issues/62259")] + public async Task TestNestedFileDeclaration(string declarationKind) + { + var source = $$""" + file class C1 + { + {{declarationKind}} [|C2|] { } + } + """; + + var fixedSource = $$""" + file class C1 + { + private {{declarationKind}} C2 { } + } + """; + + await new VerifyCS.Test + { + TestCode = source, + FixedCode = fixedSource, + LanguageVersion = LanguageVersion.Preview, + }.RunAsync(); + } } } diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Services/SyntaxFacts/CSharpAccessibilityFacts.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Services/SyntaxFacts/CSharpAccessibilityFacts.cs index 86cfbb6cfaa17..0f19e230090f4 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Services/SyntaxFacts/CSharpAccessibilityFacts.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Services/SyntaxFacts/CSharpAccessibilityFacts.cs @@ -34,6 +34,8 @@ public bool CanHaveAccessibility(SyntaxNode declaration) case SyntaxKind.InterfaceDeclaration: case SyntaxKind.EnumDeclaration: case SyntaxKind.DelegateDeclaration: + return !((MemberDeclarationSyntax)declaration).Modifiers.Any(SyntaxKind.FileKeyword); + case SyntaxKind.FieldDeclaration: case SyntaxKind.EventFieldDeclaration: case SyntaxKind.GetAccessorDeclaration: From 80bdf2453604d088f294d4fc1963033446ff1f53 Mon Sep 17 00:00:00 2001 From: Rikki Gibson Date: Thu, 30 Jun 2022 17:15:52 -0700 Subject: [PATCH 08/11] Fix conflicts and build errors --- .../CSharp/Portable/CSharpResources.resx | 10 +- .../Declarations/DeclarationModifiers.cs | 10 +- .../CSharp/Portable/Errors/MessageID.cs | 12 +- .../CSharp/Portable/Parser/LanguageParser.cs | 52 +- .../Portable/Symbols/Source/ModifierUtils.cs | 16 +- .../CSharp/Portable/Syntax/SyntaxKind.cs | 3 +- .../CSharp/Portable/Syntax/SyntaxKindFacts.cs | 28 +- .../Portable/xlf/CSharpResources.cs.xlf | 16 +- .../Portable/xlf/CSharpResources.de.xlf | 14 +- .../Portable/xlf/CSharpResources.es.xlf | 18 +- .../Portable/xlf/CSharpResources.fr.xlf | 14 +- .../Portable/xlf/CSharpResources.it.xlf | 18 +- .../Portable/xlf/CSharpResources.ja.xlf | 14 +- .../Portable/xlf/CSharpResources.ko.xlf | 16 +- .../Portable/xlf/CSharpResources.pl.xlf | 78 +- .../Portable/xlf/CSharpResources.pt-BR.xlf | 20 +- .../Portable/xlf/CSharpResources.ru.xlf | 14 +- .../Portable/xlf/CSharpResources.tr.xlf | 12 +- .../Portable/xlf/CSharpResources.zh-Hans.xlf | 30 +- .../Portable/xlf/CSharpResources.zh-Hant.xlf | 132 ++- .../EditAndContinue/EditAndContinueTests.cs | 1008 ++++++++--------- .../SymbolDisplayCompilerInternalOptions.cs | 12 +- 22 files changed, 701 insertions(+), 846 deletions(-) diff --git a/src/Compilers/CSharp/Portable/CSharpResources.resx b/src/Compilers/CSharp/Portable/CSharpResources.resx index 5d00b599f77b2..58de8f3365ebf 100644 --- a/src/Compilers/CSharp/Portable/CSharpResources.resx +++ b/src/Compilers/CSharp/Portable/CSharpResources.resx @@ -7166,17 +7166,13 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ Required members are not allowed on the top level of a script or submission. -<<<<<<< HEAD - - file types - -||||||| 4518b4087d0 -======= One of the parameters of an equality, or inequality operator declared in interface '{0}' must be a type parameter on '{0}' constrained to '{0}' Operator '{0}' cannot be applied to operands of type '{1}' and '{2}' that are not UTF-8 byte representations ->>>>>>> upstream/main + + file types + diff --git a/src/Compilers/CSharp/Portable/Declarations/DeclarationModifiers.cs b/src/Compilers/CSharp/Portable/Declarations/DeclarationModifiers.cs index f37797c30872d..dc617f84502b4 100644 --- a/src/Compilers/CSharp/Portable/Declarations/DeclarationModifiers.cs +++ b/src/Compilers/CSharp/Portable/Declarations/DeclarationModifiers.cs @@ -36,15 +36,11 @@ internal enum DeclarationModifiers : uint Async = 1 << 20, Ref = 1 << 21, // used only for structs Required = 1 << 22, // Used only for properties and fields -<<<<<<< HEAD - File = 1 << 23, // used only for types -||||||| 4518b4087d0 -======= Scoped = 1 << 23, ->>>>>>> upstream/main + File = 1 << 24, // used only for types - All = (1 << 24) - 1, // all modifiers - Unset = 1 << 24, // used when a modifiers value hasn't yet been computed + All = (1 << 25) - 1, // all modifiers + Unset = 1 << 25, // 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 86d3f1a1eab0e..6e171c1298ea1 100644 --- a/src/Compilers/CSharp/Portable/Errors/MessageID.cs +++ b/src/Compilers/CSharp/Portable/Errors/MessageID.cs @@ -256,12 +256,8 @@ internal enum MessageID IDS_FeatureRelaxedShiftOperator = MessageBase + 12825, IDS_FeatureRequiredMembers = MessageBase + 12826, -<<<<<<< HEAD - IDS_FeatureFileTypes = MessageBase + 12850, // PROTOTYPE(ft): pack ID before merge -||||||| 4518b4087d0 -======= IDS_FeatureRefFields = MessageBase + 12827, ->>>>>>> upstream/main + IDS_FeatureFileTypes = MessageBase + 12850, // PROTOTYPE(ft): pack ID before merge } // Message IDs may refer to strings that need to be localized. @@ -385,12 +381,8 @@ internal static LanguageVersion RequiredVersion(this MessageID feature) case MessageID.IDS_FeatureUnsignedRightShift: // semantic check for declarations and consumption, parsing check for doc comments case MessageID.IDS_FeatureExtendedNameofScope: // semantic check case MessageID.IDS_FeatureRelaxedShiftOperator: // semantic check -<<<<<<< HEAD - case MessageID.IDS_FeatureFileTypes: // semantic check -||||||| 4518b4087d0 -======= case MessageID.IDS_FeatureRefFields: // semantic check ->>>>>>> upstream/main + case MessageID.IDS_FeatureFileTypes: // semantic check return LanguageVersion.Preview; // C# 10.0 features. diff --git a/src/Compilers/CSharp/Portable/Parser/LanguageParser.cs b/src/Compilers/CSharp/Portable/Parser/LanguageParser.cs index b8274eef34287..565b4ba4cbcfc 100644 --- a/src/Compilers/CSharp/Portable/Parser/LanguageParser.cs +++ b/src/Compilers/CSharp/Portable/Parser/LanguageParser.cs @@ -1165,14 +1165,10 @@ internal static DeclarationModifiers GetModifier(SyntaxKind kind, SyntaxKind con return DeclarationModifiers.Async; case SyntaxKind.RequiredKeyword: return DeclarationModifiers.Required; -<<<<<<< HEAD - case SyntaxKind.FileKeyword: - return DeclarationModifiers.File; -||||||| 4518b4087d0 -======= case SyntaxKind.ScopedKeyword: return DeclarationModifiers.Scoped; ->>>>>>> upstream/main + case SyntaxKind.FileKeyword: + return DeclarationModifiers.File; } goto default; @@ -1265,13 +1261,7 @@ private void ParseModifiers(SyntaxListBuilder tokens, bool forAccessors, bool fo break; case DeclarationModifiers.Async: -<<<<<<< HEAD if (!ShouldContextualKeywordBeTreatedAsModifier(parsingStatementNotDeclaration: false)) -||||||| 4518b4087d0 - if (!ShouldAsyncOrRequiredBeTreatedAsModifier(parsingStatementNotDeclaration: false)) -======= - if (!ShouldAsyncOrRequiredOrScopedBeTreatedAsModifier(parsingStatementNotDeclaration: false)) ->>>>>>> upstream/main { return; } @@ -1285,13 +1275,7 @@ private void ParseModifiers(SyntaxListBuilder tokens, bool forAccessors, bool fo // machinery to make a conservative guess as to whether the user meant required to be a keyword, so that they get a good langver // diagnostic and all the machinery to upgrade their project kicks in. The only exception to this rule is top level statements, // where the user could conceivably have a local named required. For these locations, we need to disambiguate as well. -<<<<<<< HEAD if ((!IsFeatureEnabled(MessageID.IDS_FeatureRequiredMembers) || forTopLevelStatements) && !ShouldContextualKeywordBeTreatedAsModifier(parsingStatementNotDeclaration: false)) -||||||| 4518b4087d0 - if ((!IsFeatureEnabled(MessageID.IDS_FeatureRequiredMembers) || forTopLevelStatements) && !ShouldAsyncOrRequiredBeTreatedAsModifier(parsingStatementNotDeclaration: false)) -======= - if ((!IsFeatureEnabled(MessageID.IDS_FeatureRequiredMembers) || forTopLevelStatements) && !ShouldAsyncOrRequiredOrScopedBeTreatedAsModifier(parsingStatementNotDeclaration: false)) ->>>>>>> upstream/main { return; } @@ -1301,7 +1285,7 @@ private void ParseModifiers(SyntaxListBuilder tokens, bool forAccessors, bool fo break; case DeclarationModifiers.Scoped: - if (!ShouldAsyncOrRequiredOrScopedBeTreatedAsModifier(parsingStatementNotDeclaration: false)) + if (!ShouldContextualKeywordBeTreatedAsModifier(parsingStatementNotDeclaration: false)) { return; } @@ -1336,21 +1320,9 @@ bool isStructOrRecordKeyword(SyntaxToken token) } } -<<<<<<< HEAD private bool ShouldContextualKeywordBeTreatedAsModifier(bool parsingStatementNotDeclaration) -||||||| 4518b4087d0 - private bool ShouldAsyncOrRequiredBeTreatedAsModifier(bool parsingStatementNotDeclaration) -======= - private bool ShouldAsyncOrRequiredOrScopedBeTreatedAsModifier(bool parsingStatementNotDeclaration) ->>>>>>> upstream/main { -<<<<<<< HEAD Debug.Assert(this.CurrentToken.Kind == SyntaxKind.IdentifierToken && GetModifier(this.CurrentToken) != DeclarationModifiers.None); -||||||| 4518b4087d0 - Debug.Assert(this.CurrentToken.ContextualKind is SyntaxKind.AsyncKeyword or SyntaxKind.RequiredKeyword); -======= - Debug.Assert(this.CurrentToken.ContextualKind is SyntaxKind.AsyncKeyword or SyntaxKind.RequiredKeyword or SyntaxKind.ScopedKeyword); ->>>>>>> upstream/main // Adapted from CParser::IsAsyncMethod. @@ -2727,15 +2699,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 && -<<<<<<< HEAD - this.CurrentToken.ContextualKind is not (SyntaxKind.PartialKeyword or SyntaxKind.AsyncKeyword or SyntaxKind.RequiredKeyword or SyntaxKind.FileKeyword) && -||||||| 4518b4087d0 - this.CurrentToken.ContextualKind != SyntaxKind.PartialKeyword && - this.CurrentToken.ContextualKind != SyntaxKind.AsyncKeyword && - this.CurrentToken.ContextualKind != SyntaxKind.RequiredKeyword && -======= - this.CurrentToken.ContextualKind is not (SyntaxKind.PartialKeyword or SyntaxKind.AsyncKeyword or SyntaxKind.RequiredKeyword or SyntaxKind.ScopedKeyword) && ->>>>>>> upstream/main + this.CurrentToken.ContextualKind is not (SyntaxKind.PartialKeyword or SyntaxKind.AsyncKeyword or SyntaxKind.RequiredKeyword or SyntaxKind.ScopedKeyword or SyntaxKind.FileKeyword) && IsComplete(type)) { var misplacedModifier = this.CurrentToken; @@ -8146,19 +8110,13 @@ private bool IsPossibleLocalDeclarationStatement(bool isGlobalScriptLevel) tk = this.CurrentToken.ContextualKind; if (tk == SyntaxKind.ScopedKeyword && - ShouldAsyncOrRequiredOrScopedBeTreatedAsModifier(parsingStatementNotDeclaration: true)) + ShouldContextualKeywordBeTreatedAsModifier(parsingStatementNotDeclaration: true)) { return true; } var isPossibleAttributeOrModifier = (IsAdditionalLocalFunctionModifier(tk) || tk == SyntaxKind.OpenBracketToken) -<<<<<<< HEAD && (tk != SyntaxKind.AsyncKeyword || ShouldContextualKeywordBeTreatedAsModifier(parsingStatementNotDeclaration: true)); -||||||| 4518b4087d0 - && (tk != SyntaxKind.AsyncKeyword || ShouldAsyncOrRequiredBeTreatedAsModifier(parsingStatementNotDeclaration: true)); -======= - && (tk != SyntaxKind.AsyncKeyword || ShouldAsyncOrRequiredOrScopedBeTreatedAsModifier(parsingStatementNotDeclaration: true)); ->>>>>>> upstream/main 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 cb5d0d7e3a2d1..86180610ecd95 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/ModifierUtils.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/ModifierUtils.cs @@ -319,14 +319,10 @@ internal static string ConvertSingleModifierToSyntaxText(DeclarationModifiers mo return SyntaxFacts.GetText(SyntaxKind.RefKeyword); case DeclarationModifiers.Required: return SyntaxFacts.GetText(SyntaxKind.RequiredKeyword); -<<<<<<< HEAD - case DeclarationModifiers.File: - return SyntaxFacts.GetText(SyntaxKind.FileKeyword); -||||||| 4518b4087d0 -======= case DeclarationModifiers.Scoped: return SyntaxFacts.GetText(SyntaxKind.ScopedKeyword); ->>>>>>> upstream/main + case DeclarationModifiers.File: + return SyntaxFacts.GetText(SyntaxKind.FileKeyword); default: throw ExceptionUtilities.UnexpectedValue(modifier); } @@ -376,14 +372,10 @@ private static DeclarationModifiers ToDeclarationModifier(SyntaxKind kind) return DeclarationModifiers.Ref; case SyntaxKind.RequiredKeyword: return DeclarationModifiers.Required; -<<<<<<< HEAD - case SyntaxKind.FileKeyword: - return DeclarationModifiers.File; -||||||| 4518b4087d0 -======= case SyntaxKind.ScopedKeyword: return DeclarationModifiers.Scoped; ->>>>>>> upstream/main + case SyntaxKind.FileKeyword: + return DeclarationModifiers.File; default: throw ExceptionUtilities.UnexpectedValue(kind); } diff --git a/src/Compilers/CSharp/Portable/Syntax/SyntaxKind.cs b/src/Compilers/CSharp/Portable/Syntax/SyntaxKind.cs index 367e63a55e471..8b7d6a6ffce69 100644 --- a/src/Compilers/CSharp/Portable/Syntax/SyntaxKind.cs +++ b/src/Compilers/CSharp/Portable/Syntax/SyntaxKind.cs @@ -408,9 +408,8 @@ public enum SyntaxKind : ushort RequiredKeyword = 8447, /// Represents . ScopedKeyword = 8448, - /// Represents . - FileKeyword = 8448, + FileKeyword = 8449, // 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 574d6cb8403ab..d6624d597b04b 100644 --- a/src/Compilers/CSharp/Portable/Syntax/SyntaxKindFacts.cs +++ b/src/Compilers/CSharp/Portable/Syntax/SyntaxKindFacts.cs @@ -1138,13 +1138,7 @@ public static SyntaxKind GetPreprocessorKeywordKind(string text) public static IEnumerable GetContextualKeywordKinds() { -<<<<<<< HEAD for (int i = (int)SyntaxKind.YieldKeyword; i <= (int)SyntaxKind.FileKeyword; i++) -||||||| 4518b4087d0 - for (int i = (int)SyntaxKind.YieldKeyword; i <= (int)SyntaxKind.RequiredKeyword; i++) -======= - for (int i = (int)SyntaxKind.YieldKeyword; i <= (int)SyntaxKind.ScopedKeyword; i++) ->>>>>>> upstream/main { yield return (SyntaxKind)i; } @@ -1198,12 +1192,8 @@ public static bool IsContextualKeyword(SyntaxKind kind) case SyntaxKind.ManagedKeyword: case SyntaxKind.UnmanagedKeyword: case SyntaxKind.RequiredKeyword: -<<<<<<< HEAD - case SyntaxKind.FileKeyword: -||||||| 4518b4087d0 -======= case SyntaxKind.ScopedKeyword: ->>>>>>> upstream/main + case SyntaxKind.FileKeyword: return true; default: return false; @@ -1325,14 +1315,10 @@ public static SyntaxKind GetContextualKeywordKind(string text) return SyntaxKind.UnmanagedKeyword; case "required": return SyntaxKind.RequiredKeyword; -<<<<<<< HEAD - case "file": - return SyntaxKind.FileKeyword; -||||||| 4518b4087d0 -======= case "scoped": return SyntaxKind.ScopedKeyword; ->>>>>>> upstream/main + case "file": + return SyntaxKind.FileKeyword; default: return SyntaxKind.None; } @@ -1774,14 +1760,10 @@ public static string GetText(SyntaxKind kind) return "unmanaged"; case SyntaxKind.RequiredKeyword: return "required"; -<<<<<<< HEAD - case SyntaxKind.FileKeyword: - return "file"; -||||||| 4518b4087d0 -======= case SyntaxKind.ScopedKeyword: return "scoped"; ->>>>>>> upstream/main + 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 01cbc9a4f7c17..1b1deec2d407e 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf @@ -582,7 +582,6 @@ Obor názvů pro celý soubor musí předcházet všem ostatním členům v souboru. -<<<<<<< HEAD File type '{0}' cannot be used as a base type of non-file type '{1}'. File type '{0}' cannot be used as a base type of non-file type '{1}'. @@ -603,14 +602,11 @@ File type '{0}' cannot use accessibility modifiers. -||||||| 4518b4087d0 -======= A fixed field must not be a ref field. A fixed field must not be a ref field. ->>>>>>> upstream/main foreach statement cannot operate on variables of type '{0}' because '{0}' does not contain a public instance or extension definition for '{1}'. Did you mean 'await foreach' rather than 'foreach'? Příkaz foreach nejde použít pro proměnné typu {0}, protože {0} neobsahuje veřejnou definici instance nebo rozšíření pro {1}. Měli jste v úmyslu await foreach místo foreach? @@ -1258,7 +1254,7 @@ The left-hand side of a ref assignment must be a ref variable. - The left-hand side of a ref assignment must be a ref variable. + Levá strana přiřazení odkazu musí být lokální proměnná nebo parametr odkazu. @@ -1753,7 +1749,7 @@ pattern matching ReadOnly/Span<char> on constant string - vzor odpovídající ReadOnly/Span<char> na konstantním řetězci + pattern matching ReadOnly/Span<char> on constant string @@ -2284,7 +2280,7 @@ -instrument:TestCoverage Vytvoří sestavení instrumentované ke shromažďování informací o pokrytí. -sourcelink:<file> Informace o zdrojovém odkazu vkládané do souboru PDB.. - + - CHYBY A UPOZORNĚNÍ - -warnaserror[+|-] Hlásí všechna upozornění jako chyby. -warnaserror[+|-]:<warn list> Hlásí zadaná upozornění jako chyby. @@ -6586,7 +6582,7 @@ Pokud se taková třída používá jako základní třída a pokud odvozující Cannot do non-virtual member lookup in '{0}' because it is a type parameter - Cannot do non-virtual member lookup in '{0}' because it is a type parameter + Nejde vyhledávat člena v {0}, protože se jedná o parametr typu. @@ -11133,7 +11129,7 @@ Pokud chcete odstranit toto varování, můžete místo toho použít /reference Cannot return a parameter by reference '{0}' because it is not a ref parameter - Cannot return a parameter by reference '{0}' because it is not a ref parameter + Parametr nejde vrátit pomocí odkazu {0}, protože nejde o parametr Ref nebo Out. @@ -11753,7 +11749,7 @@ Pokud chcete odstranit toto varování, můžete místo toho použít /reference Conversion, equality, or inequality operators declared in interfaces must be abstract or virtual - Conversion, equality, or inequality operators declared in interfaces must be abstract or virtual + Operátory převodu, rovnosti nebo nerovnosti deklarované v rozhraních musí být abstraktní. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf index fbfd078de08fc..11750c3594d54 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf @@ -582,7 +582,6 @@ Der Dateibereichsnamespace muss allen anderen Elementen in einer Datei vorangestellt sein. -<<<<<<< HEAD File type '{0}' cannot be used as a base type of non-file type '{1}'. File type '{0}' cannot be used as a base type of non-file type '{1}'. @@ -603,14 +602,11 @@ File type '{0}' cannot use accessibility modifiers. -||||||| 4518b4087d0 -======= A fixed field must not be a ref field. A fixed field must not be a ref field. ->>>>>>> upstream/main foreach statement cannot operate on variables of type '{0}' because '{0}' does not contain a public instance or extension definition for '{1}'. Did you mean 'await foreach' rather than 'foreach'? Eine foreach-Anweisung kann nicht für Variablen vom Typ "{0}" verwendet werden, weil "{0}" keine öffentliche Instanz- oder Erweiterungsdefinition für "{1}" enthält. Meinten Sie "await foreach" statt "foreach"? @@ -1258,7 +1254,7 @@ The left-hand side of a ref assignment must be a ref variable. - The left-hand side of a ref assignment must be a ref variable. + Die linke Seite einer ref-Zuweisung muss ein lokaler Verweis oder ein Parameter sein. @@ -2287,7 +2283,7 @@ – FEHLER UND WARNUNGEN – -warnaserror[+|-] Meldet alle Warnungen als Fehler. --warnaserror[+|-]:<Warnungsliste> Meldet bestimmte Warnungen als Fehler +-warnaserror[+|-]:<Warnungsliste> Meldet bestimmte Warnungen als Fehler (Verwendung von "nullable" für alle Warnungen zur NULL-Zulässigkeit). -warn:<n> Legt die Warnstufe fest (0 oder höher) (Kurzform: -w). -nowarn:<Warnungsliste> Deaktiviert bestimmte Warnmeldungen @@ -6586,7 +6582,7 @@ Wenn solch eine Klasse als Basisklasse verwendet wird und die ableitende Klasse Cannot do non-virtual member lookup in '{0}' because it is a type parameter - Cannot do non-virtual member lookup in '{0}' because it is a type parameter + In "{0}" kann kein Memberlookup ausgeführt werden, da es sich um einen Typparameter handelt. @@ -11133,7 +11129,7 @@ Um die Warnung zu beheben, können Sie stattdessen /reference verwenden (Einbett Cannot return a parameter by reference '{0}' because it is not a ref parameter - Cannot return a parameter by reference '{0}' because it is not a ref parameter + Ein Parameter kann nicht als Verweis "{0}" zurückgegeben werden, weil es sich nicht um einen ref- oder out-Parameter handelt. @@ -11753,7 +11749,7 @@ Um die Warnung zu beheben, können Sie stattdessen /reference verwenden (Einbett Conversion, equality, or inequality operators declared in interfaces must be abstract or virtual - Conversion, equality, or inequality operators declared in interfaces must be abstract or virtual + Konvertierungs-, Gleichheits- oder Ungleichheitsoperatoren, die in Schnittstellen deklariert sind, müssen abstrakt sein. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf index 4b0213e3c6151..1b2696dcd9286 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf @@ -582,7 +582,6 @@ El espacio de nombres con ámbito de archivo debe preceder a todos los demás miembros de un archivo. -<<<<<<< HEAD File type '{0}' cannot be used as a base type of non-file type '{1}'. File type '{0}' cannot be used as a base type of non-file type '{1}'. @@ -603,14 +602,11 @@ File type '{0}' cannot use accessibility modifiers. -||||||| 4518b4087d0 -======= A fixed field must not be a ref field. A fixed field must not be a ref field. ->>>>>>> upstream/main foreach statement cannot operate on variables of type '{0}' because '{0}' does not contain a public instance or extension definition for '{1}'. Did you mean 'await foreach' rather than 'foreach'? La instrucción foreach no puede funcionar en variables de tipo "{0}" porque "{0}" no contiene ninguna definición de extensión o instancia pública para "{1}". ¿Quiso decir “await foreach” en lugar de “foreach”? @@ -1258,7 +1254,7 @@ The left-hand side of a ref assignment must be a ref variable. - The left-hand side of a ref assignment must be a ref variable. + La parte izquierda de una asignación de referencias debe ser una referencia local o un parámetro. @@ -2222,7 +2218,7 @@ Opciones del compilador de Visual C# - ARCHIVOS DE SALIDA - --out:<archivo> Especifica el nombre del archivo de salida (el valor predeterminado: nombre base del +-out:<archivo> Especifica el nombre del archivo de salida (el valor predeterminado: nombre base del archivo con la clase principal o el primer archivo) -target:exe Compila un archivo ejecutable de consola (predeterminado) (forma corta: -t:exe) @@ -2284,7 +2280,7 @@ -instrument:TestCoverage Produce un ensamblado instrumentado para recopilar información de cobertura. -sourcelink:<archivo> Información del vínculo de origen para insertar en el PDB. - + - ERRORES Y ADVERTENCIAS - -warnaserror[+|-] Notifica todas las advertencias como errores. -warnaserror[+|-]:<lista de advertencias > Notifica advertencias específicas como errores @@ -2356,7 +2352,7 @@ -pdb:<archivo> Especifica el nombre de archivo de información de depuración (valor predeterminado: nombre de archivo de salida con la extensión .pdb). -errorendlocation Línea y columna de salida de la ubicación final de - cada error. + cada error. -preferreduilang Especifica el nombre del lenguaje de salida preferido. -nosdkpath Deshabilita la búsqueda de la ruta del SDK predeterminada para los ensamblados de biblioteca estándar. -nostdlib[+|-] No hace referencia a la biblioteca estándar (mscorlib.dll). @@ -6586,7 +6582,7 @@ Si se utiliza una clase de este tipo como clase base y si la clase derivada defi Cannot do non-virtual member lookup in '{0}' because it is a type parameter - Cannot do non-virtual member lookup in '{0}' because it is a type parameter + No se pueden buscar miembros en '{0}' porque es un parámetro de tipo @@ -11133,7 +11129,7 @@ Para eliminar la advertencia puede usar /reference (establezca la propiedad Embe Cannot return a parameter by reference '{0}' because it is not a ref parameter - Cannot return a parameter by reference '{0}' because it is not a ref parameter + No se pude devolver por referencia un parámetro '{0}' porque no es de tipo ref o out. @@ -11753,7 +11749,7 @@ Para eliminar la advertencia puede usar /reference (establezca la propiedad Embe Conversion, equality, or inequality operators declared in interfaces must be abstract or virtual - Conversion, equality, or inequality operators declared in interfaces must be abstract or virtual + Los operadores de conversión, igualdad o desigualdad declarados en interfaces deben ser abstractos diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf index b5a9b047b2f5a..934be541f7460 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf @@ -582,7 +582,6 @@ Un espace de noms de portée de fichier doit précéder tous les autres membres d’un fichier. -<<<<<<< HEAD File type '{0}' cannot be used as a base type of non-file type '{1}'. File type '{0}' cannot be used as a base type of non-file type '{1}'. @@ -603,14 +602,11 @@ File type '{0}' cannot use accessibility modifiers. -||||||| 4518b4087d0 -======= A fixed field must not be a ref field. A fixed field must not be a ref field. ->>>>>>> upstream/main foreach statement cannot operate on variables of type '{0}' because '{0}' does not contain a public instance or extension definition for '{1}'. Did you mean 'await foreach' rather than 'foreach'? L'instruction foreach ne peut pas fonctionner sur des variables de type '{0}', car '{0}' ne contient pas de définition d'extension ou d'instance publique pour '{1}'. Vouliez-vous dire 'await foreach' plutôt que 'foreach' ? @@ -1258,7 +1254,7 @@ The left-hand side of a ref assignment must be a ref variable. - The left-hand side of a ref assignment must be a ref variable. + La partie gauche d'une assignation par référence doit être une variable locale ou un paramètre ref. @@ -2284,7 +2280,7 @@ -instrument:TestCoverage Produire un assembly instrumenté pour collecter les informations de couverture -sourcelink:<fichier> Informations du lien source à incorporer dans le fichier PDB. - + - ERREURS ET AVERTISSEMENTS - -warnaserror[+|-] Signaler tous les avertissements comme des erreurs -warnaserror[+|-]:<avertiss.> Signaler des avertissements spécifiques comme des erreurs @@ -6586,7 +6582,7 @@ Si une telle classe est utilisée en tant que classe de base et si la classe dé Cannot do non-virtual member lookup in '{0}' because it is a type parameter - Cannot do non-virtual member lookup in '{0}' because it is a type parameter + Impossible de rechercher un membre dans '{0}', car il s'agit d'un paramètre de type @@ -11133,7 +11129,7 @@ Pour supprimer l'avertissement, vous pouvez utiliser la commande /reference (dé Cannot return a parameter by reference '{0}' because it is not a ref parameter - Cannot return a parameter by reference '{0}' because it is not a ref parameter + Impossible de retourner un paramètre '{0}' par référence, car il ne s'agit pas d'un paramètre ref ou out @@ -11753,7 +11749,7 @@ Pour supprimer l'avertissement, vous pouvez utiliser la commande /reference (dé Conversion, equality, or inequality operators declared in interfaces must be abstract or virtual - Conversion, equality, or inequality operators declared in interfaces must be abstract or virtual + Les opérateurs de conversion, d’égalité ou d’inégalité déclarés dans les interfaces doivent être abstract diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf index c0b2fd9cae480..aa5b8ade54759 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf @@ -582,7 +582,6 @@ Lo spazio dei nomi con ambito file deve precedere tutti gli altri membri di un file. -<<<<<<< HEAD File type '{0}' cannot be used as a base type of non-file type '{1}'. File type '{0}' cannot be used as a base type of non-file type '{1}'. @@ -603,14 +602,11 @@ File type '{0}' cannot use accessibility modifiers. -||||||| 4518b4087d0 -======= A fixed field must not be a ref field. A fixed field must not be a ref field. ->>>>>>> upstream/main foreach statement cannot operate on variables of type '{0}' because '{0}' does not contain a public instance or extension definition for '{1}'. Did you mean 'await foreach' rather than 'foreach'? L'istruzione foreach non può funzionare con variabili di tipo '{0}' perché '{0}' non contiene una definizione di istanza o estensione pubblica per '{1}'. Si intendeva 'await foreach' invece di 'foreach'? @@ -1258,7 +1254,7 @@ The left-hand side of a ref assignment must be a ref variable. - The left-hand side of a ref assignment must be a ref variable. + La parte sinistra di un'assegnazione ref deve essere un parametro o una variabile locale ref. @@ -2247,7 +2243,7 @@ ai caratteri jolly specificati -reference:<alias>=<file> Crea un riferimento ai metadati dal file di assembly specificato usando l'alias indicato. Forma breve: -r --reference:<elenco file> Crea un riferimento ai metadati dai file di assembly +-reference:<elenco file> Crea un riferimento ai metadati dai file di assembly specificati. Forma breve: -r -addmodule:<elenco file> Collega i moduli specificati in questo assembly -link:<elenco file> Incorpora metadati dai file di assembly di @@ -2284,7 +2280,7 @@ -instrument:TestCoverage Produce un assembly instrumentato per raccogliere informazioni sul code coverage -sourcelink:<file> Informazioni sul collegamento all'origine da incorporare nel file PDB. - + - ERRORI E AVVISI - -warnaserror[+|-] Segnala tutti gli avvisi come errori -warnaserror[+|-]:<elenco avvisi> Segnala determinati avvisi come errori @@ -2338,7 +2334,7 @@ - AVANZATE - -baseaddress:<indirizzo> Indirizzo di base della libreria da compilare --checksumalgorithm:<alg> Consente di specificare l'algoritmo per calcolare il checksum +-checksumalgorithm:<alg> Consente di specificare l'algoritmo per calcolare il checksum del file di origine archiviato nel file PDB. I valori supportati sono: SHA1 o SHA256 (impostazione predefinita). -codepage:<n> Consente di specificare la tabella codici da usare all'apertura dei file @@ -6586,7 +6582,7 @@ Se si usa tale classe come classe base e se la classe di derivazione definisce u Cannot do non-virtual member lookup in '{0}' because it is a type parameter - Cannot do non-virtual member lookup in '{0}' because it is a type parameter + Non è possibile eseguire la ricerca di membri in '{0}' perché è un parametro di tipo @@ -11133,7 +11129,7 @@ Per rimuovere l'avviso, è invece possibile usare /reference (impostare la propr Cannot return a parameter by reference '{0}' because it is not a ref parameter - Cannot return a parameter by reference '{0}' because it is not a ref parameter + Non è possibile restituire un parametro '{0}' per riferimento perché non è un parametro out o ref @@ -11753,7 +11749,7 @@ Per rimuovere l'avviso, è invece possibile usare /reference (impostare la propr Conversion, equality, or inequality operators declared in interfaces must be abstract or virtual - Conversion, equality, or inequality operators declared in interfaces must be abstract or virtual + Gli operatori di conversione, uguaglianza o disuguaglianza dichiarati nelle interfacce devono essere astratti diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf index 35bad44b4e344..437eefdfec647 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf @@ -582,7 +582,6 @@ ファイルスコープの名前空間は、ファイル内の他のすべてのメンバーの前に指定する必要があります。 -<<<<<<< HEAD File type '{0}' cannot be used as a base type of non-file type '{1}'. File type '{0}' cannot be used as a base type of non-file type '{1}'. @@ -603,14 +602,11 @@ File type '{0}' cannot use accessibility modifiers. -||||||| 4518b4087d0 -======= A fixed field must not be a ref field. A fixed field must not be a ref field. ->>>>>>> upstream/main foreach statement cannot operate on variables of type '{0}' because '{0}' does not contain a public instance or extension definition for '{1}'. Did you mean 'await foreach' rather than 'foreach'? '{0}' は '{1}' のパブリック インスタンスまたは拡張機能の定義を含んでいないため、型 '{0}' の変数に対して foreach ステートメントを使用することはできません。'foreach' ではなく 'await foreach' ですか? @@ -1258,7 +1254,7 @@ The left-hand side of a ref assignment must be a ref variable. - The left-hand side of a ref assignment must be a ref variable. + ref 代入の左辺は、ref ローカルまたはパラメーターにする必要があります。 @@ -2284,7 +2280,7 @@ -instrument:TestCoverage カバレッジ情報を収集するようにインストルメント化された アセンブリを生成します -sourcelink:<file> PDB に埋め込むソース リンク情報。 - + - エラーと警告 - -warnaserror[+|-] すべての警告をエラーとして報告します -warnaserror[+|-]:<warn list> 特定の警告をエラーとして報告します @@ -6586,7 +6582,7 @@ If such a class is used as a base class and if the deriving class defines a dest Cannot do non-virtual member lookup in '{0}' because it is a type parameter - Cannot do non-virtual member lookup in '{0}' because it is a type parameter + 型パラメーターであるため、'{0}' でメンバーの照合を行えません @@ -11133,7 +11129,7 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ Cannot return a parameter by reference '{0}' because it is not a ref parameter - Cannot return a parameter by reference '{0}' because it is not a ref parameter + ref パラメーターでも out パラメーターでもないため、パラメーターを参照 '{0}' 渡しで返すことはできません @@ -11753,7 +11749,7 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ Conversion, equality, or inequality operators declared in interfaces must be abstract or virtual - Conversion, equality, or inequality operators declared in interfaces must be abstract or virtual + インターフェイスで宣言された変換演算子、等値演算子、または非等値演算子は抽象的である必要があります diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf index b5833b8249ba2..54cc83d5cc26f 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf @@ -582,7 +582,6 @@ 파일 범위 네임스페이스는 파일의 다른 모든 멤버보다 앞에 와야 합니다. -<<<<<<< HEAD File type '{0}' cannot be used as a base type of non-file type '{1}'. File type '{0}' cannot be used as a base type of non-file type '{1}'. @@ -603,14 +602,11 @@ File type '{0}' cannot use accessibility modifiers. -||||||| 4518b4087d0 -======= A fixed field must not be a ref field. A fixed field must not be a ref field. ->>>>>>> upstream/main foreach statement cannot operate on variables of type '{0}' because '{0}' does not contain a public instance or extension definition for '{1}'. Did you mean 'await foreach' rather than 'foreach'? '{0}' 형식 변수에서 foreach 문을 수행할 수 없습니다. '{0}'에는 '{1}'의 공개 인스턴스 또는 확장 정의가 없기 때문입니다. 'foreach' 대신 'await foreach'를 사용하시겠습니까? @@ -1258,7 +1254,7 @@ The left-hand side of a ref assignment must be a ref variable. - The left-hand side of a ref assignment must be a ref variable. + 참조 할당의 왼쪽은 참조 로컬 또는 매개 변수여야 합니다. @@ -2230,7 +2226,7 @@ -target:library 라이브러리를 빌드합니다. (약식: -t:library) -target:module 다른 어셈블리에 추가할 수 있는 모듈을 빌드합니다. (약식: -t:module) --target:appcontainerexe Appcontainer 실행 파일을 빌드합니다. (약식: +-target:appcontainerexe Appcontainer 실행 파일을 빌드합니다. (약식: -t:appcontainerexe) -target:winmdobj WinMDExp에서 사용되는 Windows 런타임 중간 파일을 빌드합니다. (약식: -t:winmdobj) @@ -2344,7 +2340,7 @@ 지정합니다. -utf8output 컴파일러 메시지를 UTF-8 인코딩으로 출력합니다. -main:<type> 진입점이 포함된 형식을 지정합니다(다른 - 모든 가능한 진입점 무시). + 모든 가능한 진입점 무시). (약식: -m) -fullpaths 컴파일러가 정규화된 경로를 생성합니다. -filealign:<n> 출력 파일 섹션에 사용되는 맞춤을 @@ -6585,7 +6581,7 @@ If such a class is used as a base class and if the deriving class defines a dest Cannot do non-virtual member lookup in '{0}' because it is a type parameter - Cannot do non-virtual member lookup in '{0}' because it is a type parameter + '{0}'은(는) 형식 매개 변수이므로 멤버를 조회할 수 없습니다. @@ -11132,7 +11128,7 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ Cannot return a parameter by reference '{0}' because it is not a ref parameter - Cannot return a parameter by reference '{0}' because it is not a ref parameter + '{0}' 매개 변수는 ref 또는 out 매개 변수가 아니므로 참조로 반환할 수 없습니다. @@ -11752,7 +11748,7 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ Conversion, equality, or inequality operators declared in interfaces must be abstract or virtual - Conversion, equality, or inequality operators declared in interfaces must be abstract or virtual + 인터페이스에 선언된 변환, 같음 또는 부등식 연산자는 추상이어야 합니다. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf index 5d15bf522ec5a..09b88470e3dba 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf @@ -582,7 +582,6 @@ Przestrzeń nazw z określonym zakresem plików musi poprzedzać wszystkie inne składowe w pliku. -<<<<<<< HEAD File type '{0}' cannot be used as a base type of non-file type '{1}'. File type '{0}' cannot be used as a base type of non-file type '{1}'. @@ -603,14 +602,11 @@ File type '{0}' cannot use accessibility modifiers. -||||||| 4518b4087d0 -======= A fixed field must not be a ref field. A fixed field must not be a ref field. ->>>>>>> upstream/main foreach statement cannot operate on variables of type '{0}' because '{0}' does not contain a public instance or extension definition for '{1}'. Did you mean 'await foreach' rather than 'foreach'? Instrukcja foreach nie może operować na zmiennych typu „{0}”, ponieważ typ „{0}” nie zawiera publicznego wystąpienia lub definicji rozszerzenia dla elementu „{1}”. Czy planowano użyć instrukcji „await foreach”, a nie „foreach”? @@ -1258,7 +1254,7 @@ The left-hand side of a ref assignment must be a ref variable. - The left-hand side of a ref assignment must be a ref variable. + Lewa strona przypisania odwołania musi być odwołaniem lokalnym lub parametrem. @@ -1753,7 +1749,7 @@ pattern matching ReadOnly/Span<char> on constant string - dopasowanie wzorca ReadOnly/Span<char> w ciągu stałym + pattern matching ReadOnly/Span<char> on constant string @@ -2222,35 +2218,35 @@ Opcje kompilatora Visual C# - PLIKI WYJŚCIOWE - --out:<plik> Określ nazwę pliku wyjściowego (domyślnie: nazwa podstawowa +-out:<plik> Określ nazwę pliku wyjściowego (domyślnie: nazwa podstawowa pliku z klasą główną lub pierwszego pliku) --target:exe Kompiluj plik wykonywalny konsoli (domyślnie) (krótka +-target:exe Kompiluj plik wykonywalny konsoli (domyślnie) (krótka wersja: -t:exe) --target:winexe Kompiluj plik wykonywalny systemu Windows (krótka wersja: +-target:winexe Kompiluj plik wykonywalny systemu Windows (krótka wersja: -t:winexe) -target:library Kompiluj bibliotekę (krótka wersja: -t:library) --target:module Kompiluj moduł, który można dodać do innego +-target:module Kompiluj moduł, który można dodać do innego zestawu (krótka wersja: -t:module) --target:appcontainerexe Kompiluj plik wykonywalny kontenera aplikacji (krótka wersja: +-target:appcontainerexe Kompiluj plik wykonywalny kontenera aplikacji (krótka wersja: -t:appcontainerexe) --target:winmdobj Kompiluj plik pośredni środowiska uruchomieniowego systemu Windows +-target:winmdobj Kompiluj plik pośredni środowiska uruchomieniowego systemu Windows przeznaczony dla narzędzia WinMDExp (krótka wersja: -t:winmdobj) -doc:<plik> Plik dokumentacji XML do wygenerowania -refout:<plik> Dane wyjściowe zestawu odwołania do wygenerowania -platform:<ciąg> Ogranicz platformy, na których można uruchamiać ten kod: x86, - Itanium, x64, arm, arm64, anycpu32bitpreferred lub + Itanium, x64, arm, arm64, anycpu32bitpreferred lub anycpu. Wartość domyślna to anycpu. - PLIKI WEJŚCIOWE - --recurse:<symbol wieloznaczny> Uwzględnij wszystkie pliki zawarte w bieżącym katalogu i - podkatalogach zgodnie ze specyfikacją określoną przy użyciu +-recurse:<symbol wieloznaczny> Uwzględnij wszystkie pliki zawarte w bieżącym katalogu i + podkatalogach zgodnie ze specyfikacją określoną przy użyciu symboli wieloznacznych --reference:<alias>=<plik> Odwołuj się do metadanych z określonego pliku +-reference:<alias>=<plik> Odwołuj się do metadanych z określonego pliku zestawu przy użyciu podanego aliasu (krótka wersja: -r) --reference:<lista_plików> Odwołuj się do metadanych z określonych +-reference:<lista_plików> Odwołuj się do metadanych z określonych plików zestawów (krótka wersja: -r) -addmodule:<lista plików> Połącz określone moduły z tym zestawem --link:<lista_plików> Osadź metadane z określonych plików +-link:<lista_plików> Osadź metadane z określonych plików zestawów międzyoperacyjnych (krótka wersja: -l) -analyzer:<lista_plików> Uruchom analizatory z tego zestawu (krótka wersja: -a) @@ -2266,16 +2262,16 @@ -win32manifest:<plik> Określ plik manifestu środowiska Win32 (xml) -nowin32manifest Nie dołączaj domyślnego manifestu środowiska Win32 -resource:<informacje_o_zasobie> Osadź określony zasób (krótka wersja: -res) --linkresource:<informacje_o_zasobie> Połącz określony zasób z tym zestawem - (krótka wersja: -linkres), gdzie format informacji o zasobie +-linkresource:<informacje_o_zasobie> Połącz określony zasób z tym zestawem + (krótka wersja: -linkres), gdzie format informacji o zasobie to <plik>[,<nazwa ciągu>[,public|private]] - GENEROWANIE KODU - -debug[+|-] Emituj informacje o debugowaniu -debug:{full|pdbonly|portable|embedded} - Określ typ debugowania (wartość domyślna to „full”, + Określ typ debugowania (wartość domyślna to „full”, wartość „portable” to format międzyplatformowy, - a wartość „embedded” to format międzyplatformowy wbudowany w + a wartość „embedded” to format międzyplatformowy wbudowany w docelowym pliku dll lub exe) -optimize[+|-] Włącz optymalizacje (krótka wersja: -o) -deterministic Utwórz zestaw deterministyczny @@ -2302,11 +2298,11 @@ -reportanalyzer Zgłaszaj dodatkowe informacje analizatora, takie jak czas wykonywania. -skipanalyzers[+|-] Pomiń wykonywanie analizatorów diagnostycznych. - + -JĘZYK - -checked[+|-] Generuj operacje sprawdzenia przepełnienia -unsafe[+|-] Zezwalaj na niebezpieczny kod --define:<lista symboli> Zdefiniuj symbole kompilacji warunkowej (krótka +-define:<lista symboli> Zdefiniuj symbole kompilacji warunkowej (krótka wersja: -d) -langversion:? Wyświetl dozwolone wartości dla wersji języka -langversion:<ciąg> Określ wersję języka, na przykład @@ -2320,7 +2316,7 @@ Określ opcję kontekstu dopuszczającego wartość null: enable|disable|warnings|annotations. - ZABEZPIECZENIA - --delaysign[+|-] Podpisz z opóźnieniem zestaw, używając tylko +-delaysign[+|-] Podpisz z opóźnieniem zestaw, używając tylko części publicznej klucza o silnej nazwie -publicsign[+|-] Podpisz publicznie zestaw, używając tylko części publicznej klucza o silnej nazwie @@ -2341,34 +2337,34 @@ -checksumalgorithm:<algorytm> Określ algorytm do obliczania sumy kontrolnej pliku źródłowego przechowywanej w pliku PDB. Obsługiwane wartości: SHA1 lub SHA256 (domyślnie). --codepage:<n> Określ stronę kodową do użycia podczas otwierania +-codepage:<n> Określ stronę kodową do użycia podczas otwierania plików źródłowych -utf8output Wyprowadź komunikaty kompilatora przy użyciu kodowania UTF-8 --main:<typ> Określ typ zawierający punkt wejścia - (zignoruj wszystkie pozostałe możliwe punkty wejścia) (krótka +-main:<typ> Określ typ zawierający punkt wejścia + (zignoruj wszystkie pozostałe możliwe punkty wejścia) (krótka wersja: -m) -fullpaths Kompilator generuje w pełni kwalifikowane ścieżki --filealign:<n> Określ wyrównanie stosowane dla sekcji +-filealign:<n> Określ wyrównanie stosowane dla sekcji plików wyjściowych --pathmap:<K1>=<W1>,<K2>=<W2>,... - Określ mapowanie dla nazw ścieżek źródłowych wyprowadzanych przez +-pathmap:<K1>=<W1>,<K2>=<W2>,... + Określ mapowanie dla nazw ścieżek źródłowych wyprowadzanych przez kompilator. --pdb:<plik> Określ nazwę pliku z informacjami o debugowaniu (domyślnie: +-pdb:<plik> Określ nazwę pliku z informacjami o debugowaniu (domyślnie: nazwa pliku wyjściowego z rozszerzeniem pdb) --errorendlocation Wyprowadź wiersz i kolumnę lokalizacji końcowej dla +-errorendlocation Wyprowadź wiersz i kolumnę lokalizacji końcowej dla każdego błędu -preferreduilang Określ nazwę preferowanego języka wyjściowego. -nosdkpath Wyłącz przeszukiwanie domyślnej ścieżki zestawu SDK dla zestawów biblioteki standardowej. -nostdlib[+|-] Nie odwołuj się do biblioteki standardowej (mscorlib.dll) -subsystemversion:<ciąg> Określ wersję podsystemu tego zestawu --lib:<lista plików> Określ dodatkowe katalogi do przeszukania pod kątem +-lib:<lista plików> Określ dodatkowe katalogi do przeszukania pod kątem odwołań --errorreport:<ciąg> Określ, w jaki sposób obsługiwać wewnętrzne błędy kompilatora: - prompt, send, queue lub none. Wartość domyślna to +-errorreport:<ciąg> Określ, w jaki sposób obsługiwać wewnętrzne błędy kompilatora: + prompt, send, queue lub none. Wartość domyślna to queue. --appconfig:<plik> Określ plik konfiguracji aplikacji +-appconfig:<plik> Określ plik konfiguracji aplikacji zawierający ustawienia powiązania zestawu --moduleassemblyname:<ciąg> Nazwa zestawu, którego częścią +-moduleassemblyname:<ciąg> Nazwa zestawu, którego częścią ma być ten moduł -modulename:<ciąg> Określ nazwę modułu źródłowego -generatedfilesout:<katalog> Umieść pliki wygenerowane podczas kompilacji @@ -6586,7 +6582,7 @@ Jeśli taka klasa zostanie użyta jako klasa bazowa i klasa pochodna definiuje d Cannot do non-virtual member lookup in '{0}' because it is a type parameter - Cannot do non-virtual member lookup in '{0}' because it is a type parameter + Nie można wyszukać składowej w elemencie „{0}”, ponieważ to jest parametr typu @@ -11133,7 +11129,7 @@ Aby usunąć ostrzeżenie, możesz zamiast tego użyć opcji /reference (ustaw w Cannot return a parameter by reference '{0}' because it is not a ref parameter - Cannot return a parameter by reference '{0}' because it is not a ref parameter + Nie można zwrócić parametru „{0}” przez referencję, ponieważ to nie jest parametr ref ani out @@ -11753,7 +11749,7 @@ Aby usunąć ostrzeżenie, możesz zamiast tego użyć opcji /reference (ustaw w Conversion, equality, or inequality operators declared in interfaces must be abstract or virtual - Conversion, equality, or inequality operators declared in interfaces must be abstract or virtual + Operatory konwersji, równości lub nierówności zadeklarowane w interfejsach muszą być abstrakcyjne diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf index 96df474e65063..29ee38c96cd19 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf @@ -582,7 +582,6 @@ O namespace de escopo de arquivo deve preceder todos os outros membros em um arquivo. -<<<<<<< HEAD File type '{0}' cannot be used as a base type of non-file type '{1}'. File type '{0}' cannot be used as a base type of non-file type '{1}'. @@ -603,14 +602,11 @@ File type '{0}' cannot use accessibility modifiers. -||||||| 4518b4087d0 -======= A fixed field must not be a ref field. A fixed field must not be a ref field. ->>>>>>> upstream/main foreach statement cannot operate on variables of type '{0}' because '{0}' does not contain a public instance or extension definition for '{1}'. Did you mean 'await foreach' rather than 'foreach'? A instrução foreach não pode operar em variáveis do tipo '{0}' porque '{0}' não contém uma definição de extensão ou de instância pública para '{1}'. Você quis dizer 'await foreach' em vez de 'foreach'? @@ -1258,7 +1254,7 @@ The left-hand side of a ref assignment must be a ref variable. - The left-hand side of a ref assignment must be a ref variable. + O lado esquerdo da atribuição ref precisa ser um parâmetro ou local ref. @@ -2247,7 +2243,7 @@ curinga -reference:<alias>=<file> Metadados de referência do arquivo de assembly especificado usando o alias fornecido (Forma abreviada: -r) --reference:<file list> Metadados de referência dos arquivos de assembly +-reference:<file list> Metadados de referência dos arquivos de assembly especificados (Forma abreviada: -r) -addmodule:<file list> Vincular o módulo especificado a este assembly -link:<file list> Inserir os metadados dos arquivos de assembly de @@ -2275,7 +2271,7 @@ -debug:{full|pdbonly|portable|embedded} Especificar o tipo de depuração ('full' é o padrão, 'portable' é um formato multiplataforma, - 'embedded' é um formato multiplataforma inserido no + 'embedded' é um formato multiplataforma inserido no .dll ou no .exe de destino) -optimize[+|-] Habilitar as otimizações (Forma abreviada: -o) -deterministic Produzir um assembly determinístico @@ -2309,7 +2305,7 @@ -define:<symbol list> Definir os símbolos de compilação condicional (Forma abreviada: -d) -langversion:? Exibir os valores permitidos para a versão da linguagem --langversion:<string> Especificar a versão da linguagem, como +-langversion:<string> Especificar a versão da linguagem, como `latest` (última versão, incluindo as versões secundárias), `default` (igual a `latest`), `latestmajor` (última versão, excluindo as versões secundárias), @@ -2326,7 +2322,7 @@ da chave de nome forte -keyfile:<file> Especificar a arquivo de chave de nome forte -keycontainer:<string> Especificar o contêiner de chave de nome forte --highentropyva[+|-] Habilitar a ASLR de alta entropia +-highentropyva[+|-] Habilitar a ASLR de alta entropia – DIVERSOS – @<file> Ler o arquivo de resposta de mais opções @@ -6586,7 +6582,7 @@ Se tal classe for usada como uma classe base e se a classe derivada definir um d Cannot do non-virtual member lookup in '{0}' because it is a type parameter - Cannot do non-virtual member lookup in '{0}' because it is a type parameter + Não é possível fazer pesquisa de membro em "{0}" porque ele é um parâmetro de tipo @@ -11133,7 +11129,7 @@ Para incorporar informações de tipo de interoperabilidade para os dois assembl Cannot return a parameter by reference '{0}' because it is not a ref parameter - Cannot return a parameter by reference '{0}' because it is not a ref parameter + Não é possível retornar um parâmetro por referência '{0}', pois ele não é um parâmetro ref ou out @@ -11753,7 +11749,7 @@ Para incorporar informações de tipo de interoperabilidade para os dois assembl Conversion, equality, or inequality operators declared in interfaces must be abstract or virtual - Conversion, equality, or inequality operators declared in interfaces must be abstract or virtual + Operadores de conversão, igualdade ou desigualdade declarados em interfaces devem ser abstratos diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf index cdc7a12350911..cac0d81fe7c77 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf @@ -582,7 +582,6 @@ Пространство имен с файловой областью должно быть раньше всех остальных элементов в файле. -<<<<<<< HEAD File type '{0}' cannot be used as a base type of non-file type '{1}'. File type '{0}' cannot be used as a base type of non-file type '{1}'. @@ -603,14 +602,11 @@ File type '{0}' cannot use accessibility modifiers. -||||||| 4518b4087d0 -======= A fixed field must not be a ref field. A fixed field must not be a ref field. ->>>>>>> upstream/main foreach statement cannot operate on variables of type '{0}' because '{0}' does not contain a public instance or extension definition for '{1}'. Did you mean 'await foreach' rather than 'foreach'? Оператор foreach не работает с переменными типа "{0}", так как "{0}" не содержит открытое определение экземпляра или расширения для "{1}" Возможно, вы имели в виду "await foreach", а не "foreach"? @@ -1258,7 +1254,7 @@ The left-hand side of a ref assignment must be a ref variable. - The left-hand side of a ref assignment must be a ref variable. + Левая часть выражения назначения ссылки должна быть локальной ссылкой или параметром. @@ -2284,7 +2280,7 @@ -instrument:TestCoverage Создать сборку, инструментированную для сбора сведений об объеме протестированного кода -sourcelink:<file> Данные о ссылке на исходные файлы для внедрения в PDB. - + — Ошибки и предупреждения - -warnaserror[+|-] Регистрировать все предупреждения как ошибки -warnaserror[+|-]:<warn list> Регистрировать указанные предупреждения как ошибки @@ -6586,7 +6582,7 @@ If such a class is used as a base class and if the deriving class defines a dest Cannot do non-virtual member lookup in '{0}' because it is a type parameter - Cannot do non-virtual member lookup in '{0}' because it is a type parameter + Не удается выполнить поиск члена в "{0}", так как это параметр типа. @@ -11133,7 +11129,7 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ Cannot return a parameter by reference '{0}' because it is not a ref parameter - Cannot return a parameter by reference '{0}' because it is not a ref parameter + Невозможно вернуть параметр "{0}" по ссылке, так как это не параметр ref или out @@ -11753,7 +11749,7 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ Conversion, equality, or inequality operators declared in interfaces must be abstract or virtual - Conversion, equality, or inequality operators declared in interfaces must be abstract or virtual + Операторы преобразования, равенства или неравенства, объявленные в интерфейсах, должны быть абстрактными diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf index 2c63594e3cab3..a0208ccb1d4cc 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf @@ -582,7 +582,6 @@ Dosya kapsamlı ad alanı bir dosyadaki diğer tüm üyelerin önünde olmalıdır. -<<<<<<< HEAD File type '{0}' cannot be used as a base type of non-file type '{1}'. File type '{0}' cannot be used as a base type of non-file type '{1}'. @@ -603,14 +602,11 @@ File type '{0}' cannot use accessibility modifiers. -||||||| 4518b4087d0 -======= A fixed field must not be a ref field. A fixed field must not be a ref field. ->>>>>>> upstream/main foreach statement cannot operate on variables of type '{0}' because '{0}' does not contain a public instance or extension definition for '{1}'. Did you mean 'await foreach' rather than 'foreach'? '{0}', '{1}' için bir genel örnek veya uzantı tanımı içermediğinden foreach deyimi '{0}' türündeki değişkenler üzerinde çalışamaz. 'foreach' yerine 'await foreach' mi kullanmak istediniz? @@ -1258,7 +1254,7 @@ The left-hand side of a ref assignment must be a ref variable. - The left-hand side of a ref assignment must be a ref variable. + ref atamasının sol tarafı, yerel ref veya parametresi olmalıdır. @@ -6586,7 +6582,7 @@ Bu sınıf temel sınıf olarak kullanılırsa ve türetilen sınıf bir yıkıc Cannot do non-virtual member lookup in '{0}' because it is a type parameter - Cannot do non-virtual member lookup in '{0}' because it is a type parameter + '{0}' bir tür parametresi olduğundan burada üye araması yapılamıyor @@ -11133,7 +11129,7 @@ Uyarıyı kaldırmak için, /reference kullanabilirsiniz (Birlikte Çalışma T Cannot return a parameter by reference '{0}' because it is not a ref parameter - Cannot return a parameter by reference '{0}' because it is not a ref parameter + '{0}' parametresi bir ref veya out parametresi olmadığından başvuru ile döndürülemez @@ -11753,7 +11749,7 @@ Uyarıyı kaldırmak için, /reference kullanabilirsiniz (Birlikte Çalışma T Conversion, equality, or inequality operators declared in interfaces must be abstract or virtual - Conversion, equality, or inequality operators declared in interfaces must be abstract or virtual + Arabirimlerde bildirilen dönüştürme, eşitlik veya eşitsizlik işleçleri soyut olmalıdır diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf index 1db1f525645b2..0f9e9fae47e7c 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf @@ -582,7 +582,6 @@ 文件范围内的命名空间必须位于文件中所有其他成员之前。 -<<<<<<< HEAD File type '{0}' cannot be used as a base type of non-file type '{1}'. File type '{0}' cannot be used as a base type of non-file type '{1}'. @@ -603,14 +602,11 @@ File type '{0}' cannot use accessibility modifiers. -||||||| 4518b4087d0 -======= A fixed field must not be a ref field. A fixed field must not be a ref field. ->>>>>>> upstream/main foreach statement cannot operate on variables of type '{0}' because '{0}' does not contain a public instance or extension definition for '{1}'. Did you mean 'await foreach' rather than 'foreach'? “{0}”不包含“{1}”的公共实例或扩展定义,因此 foreach 语句不能作用于“{0}”类型的变量。是否希望使用 "await foreach" 而非 "foreach"? @@ -1258,7 +1254,7 @@ The left-hand side of a ref assignment must be a ref variable. - The left-hand side of a ref assignment must be a ref variable. + ref 赋值左侧必须为 ref 本地函数或参数。 @@ -2237,12 +2233,12 @@ (短格式: - t:winmdobj) -doc:<file> 要生成的 XML 文档文件 -refout:<file> 要生成的引用程序集输出 - + -platform:<string> 限制可以运行此代码的平台: x86、 Itanium、x64、arm、arm64、 anycpu32bitpreferred 或 anycpu。默认值是 anycpu。 - - 输入文件 - + - 输入文件 - -recurse:<wildcard> 根据通配符规范包括当前目录和 子目录中的 所有文件 @@ -2256,7 +2252,7 @@ -analyzer:<file list> 从此程序集运行分析器 (短格式: -a) -additionalfile:<file list> 不直接影响代码生成 - 但由分析器用于生成错误或警报 + 但由分析器用于生成错误或警报 的其他文件。 -embed 在 PDB 中嵌入所有源文件。 -embed:<file list> 在 PDB 中嵌入特定文件。 @@ -2269,7 +2265,7 @@ -resource:<resinfo> 嵌入指定的资源(短格式: -res) - linkresource:<resinfo> 将指定资源关联到此程序集 (短格式: -linkres),其中 resinfo 格式 - + 是 <file>[,<string name>[,public|private]] - 代码生成 - @@ -2286,16 +2282,16 @@ -instrument:TestCoverage 生成 已检测的程序集以收集 覆盖范围信息 -sourcelink:<file> 要嵌入 PDB 的源链接信息。 - + - 错误和警报 - -warnaserror[+|-] 将所有警报报告为错误 -warnaserror[+|-]:<warn list> 将特定警报报告为错误 (将 "nullable" 用于所有可为 null 的警报) -warn:<n> 设置警报级别(0 或更高) (短格式: -w) - + -nowarn:<warn list> 禁用特定警报消息 (将 "nullable" 用于所有可为 null 的警报) - + -ruleset:<file> 指定禁用特定诊断的规则集 文件。 -errorlog:<file> [,version=<sarif_version>] @@ -2304,7 +2300,7 @@ sarif_version:{1|2|2.1} 默认值是 1. 2 和 2.1 这两者 都是指 SARIF 版本 2.1.0。 -reportanalyzer 报告其他分析器信息,例如 - 执行时间。 + 执行时间。 -skipanalyzers[+|-] 跳过诊断分析器的执行。 - 语言 - @@ -2345,7 +2341,7 @@ -checksumalgorithm:<alg> 指定算法以计算存储在 PDB 中的源文件 校验和。支持的值是: SHA1 或 SHA256 (默认)。 - + -codepage:<n> 指定打开源文件时使用的 代码页 -utf8output 采用 UTF-8 编码的输出编译器消息 @@ -6591,7 +6587,7 @@ If such a class is used as a base class and if the deriving class defines a dest Cannot do non-virtual member lookup in '{0}' because it is a type parameter - Cannot do non-virtual member lookup in '{0}' because it is a type parameter + “{0}”是一个类型参数,无法在其中执行成员查找 @@ -11138,7 +11134,7 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ Cannot return a parameter by reference '{0}' because it is not a ref parameter - Cannot return a parameter by reference '{0}' because it is not a ref parameter + 无法通过引用“{0}”返回参数,因为它不是 ref 或 out 参数 @@ -11758,7 +11754,7 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ Conversion, equality, or inequality operators declared in interfaces must be abstract or virtual - Conversion, equality, or inequality operators declared in interfaces must be abstract or virtual + 在接口中声明的转换、等式或不等式运算符必须是抽象的 diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf index e1b7b81e5cf4a..720c77fec0f2d 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf @@ -139,12 +139,12 @@ The first operand of an overloaded shift operator must have the same type as the containing type or its type parameter constrained to it - 多載移位 (Shift) 運算子的第一個運算元的類型必須和包含的類型相同,或是其型別參數受限於該運算子 + The first operand of an overloaded shift operator must have the same type as the containing type or its type parameter constrained to it A static virtual or abstract interface member can be accessed only on a type parameter. - 只能在型別參數上存取靜態虛擬或抽象介面成員。 + A static virtual or abstract interface member can be accessed only on a type parameter. @@ -249,7 +249,7 @@ Cannot convert &method group '{0}' to delegate type '{1}'. - 無法將方法群組 '{0}' 轉換成委派類型 '{1}'(&M)。 + Cannot convert &method group '{0}' to delegate type '{1}'. @@ -304,12 +304,12 @@ This constructor must add 'SetsRequiredMembers' because it chains to a constructor that has that attribute. - 此建構函式必須新增 'SetsRequiredMembers',因為它鏈結至具有該屬性的建構函式。 + This constructor must add 'SetsRequiredMembers' because it chains to a constructor that has that attribute. The operator '{0}' requires a matching non-checked version of the operator to also be defined - 運算子 '{0}' 需要也同時定義運算子的相符未檢查版本 + The operator '{0}' requires a matching non-checked version of the operator to also be defined @@ -469,7 +469,7 @@ Do not use 'System.Runtime.CompilerServices.RequiredMemberAttribute'. Use the 'required' keyword on required fields and properties instead. - 請勿使用 'System.Runtime.CompilerServices.RequiredMemberAttribute'。請改為在必要的欄位和屬性上使用 'required' 關鍵字。 + Do not use 'System.Runtime.CompilerServices.RequiredMemberAttribute'. Use the 'required' keyword on required fields and properties instead. @@ -489,7 +489,7 @@ An expression tree may not contain an access of static virtual or abstract interface member - 運算式樹狀架構不可包含靜態虛擬或抽象介面成員的存取權 + An expression tree may not contain an access of static virtual or abstract interface member @@ -582,7 +582,6 @@ 以檔為範圍的命名空間必須在檔案中的所有其他成員之前。 -<<<<<<< HEAD File type '{0}' cannot be used as a base type of non-file type '{1}'. File type '{0}' cannot be used as a base type of non-file type '{1}'. @@ -603,14 +602,11 @@ File type '{0}' cannot use accessibility modifiers. -||||||| 4518b4087d0 -======= A fixed field must not be a ref field. A fixed field must not be a ref field. ->>>>>>> upstream/main foreach statement cannot operate on variables of type '{0}' because '{0}' does not contain a public instance or extension definition for '{1}'. Did you mean 'await foreach' rather than 'foreach'? 因為 '{0}' 不包含 '{1}' 的公用執行個體或延伸模組定義,所以 foreach 陳述式無法在型別 '{0}' 的變數上運作。您指的是 'await foreach' 而不是 'foreach' 嗎? @@ -683,7 +679,7 @@ An 'implicit' user-defined conversion operator cannot be declared checked - 無法將「隱式」使用者定義轉換運算子宣告為已檢查 + An 'implicit' user-defined conversion operator cannot be declared checked @@ -918,7 +914,7 @@ Unexpected keyword 'unchecked' - 未預期的關鍵字 'unchecked' + Unexpected keyword 'unchecked' @@ -983,7 +979,7 @@ '{2}' cannot satisfy the 'new()' constraint on parameter '{1}' in the generic type or or method '{0}' because '{2}' has required members. - '{2}' 無法滿足泛型型別或方法 '{0}' 中參數 '{1}' 的 'new()' 限制式,因為 '{2}' 具有必要的成員。 + '{2}' cannot satisfy the 'new()' constraint on parameter '{1}' in the generic type or or method '{0}' because '{2}' has required members. @@ -1103,7 +1099,7 @@ User-defined operator '{0}' cannot be declared checked - 使用者定義的運算子 '{0}' 無法宣告為已檢查 + User-defined operator '{0}' cannot be declared checked @@ -1118,7 +1114,7 @@ '{0}' must be required because it overrides required member '{1}' - '{0}' 必須為必要項目,因為它會覆蓋必要的成員 '{1}' + '{0}' must be required because it overrides required member '{1}' @@ -1133,7 +1129,7 @@ The 'parameter null-checking' feature is not supported. - 不支援 'parameter null-checking' 功能。 + The 'parameter null-checking' feature is not supported. @@ -1183,7 +1179,7 @@ A string 'null' constant is not supported as a pattern for '{0}'. Use an empty string instead. - 不支援字串 'null' 常數做為 '{0}' 的模式。請改為使用空字串。 + A string 'null' constant is not supported as a pattern for '{0}'. Use an empty string instead. @@ -1258,12 +1254,12 @@ The left-hand side of a ref assignment must be a ref variable. - The left-hand side of a ref assignment must be a ref variable. + 參考指派的左側必須為參考本機或參數。 Ref returning properties cannot be required. - 無法要求 Ref 傳回屬性。 + Ref returning properties cannot be required. @@ -1273,42 +1269,42 @@ Required member '{0}' cannot be hidden by '{1}'. - '{1}' 無法隱藏必要成員 '{0}'。 + Required member '{0}' cannot be hidden by '{1}'. Required member '{0}' cannot be less visible or have a setter less visible than the containing type '{1}'. - 必要成員 '{0}' 可見度不能較低,或 setter 的可見程度低於包含的類型 '{1}'。 + Required member '{0}' cannot be less visible or have a setter less visible than the containing type '{1}'. Required member '{0}' must be set in the object initializer or attribute constructor. - 必須在物件初始設定式或屬性建構函式中設定必要的成員 '{0}'。 + Required member '{0}' must be set in the object initializer or attribute constructor. Required member '{0}' must be settable. - 必要的成員 '{0}' 必須可設定。 + Required member '{0}' must be settable. The required members list for the base type '{0}' is malformed and cannot be interpreted. To use this constructor, apply the 'SetsRequiredMembers' attribute. - 基底類型 '{0}' 所需的成員清單格式錯誤,無法解譯。若要使用此建構函式,請套用 'SetsRequiredMembers' 屬性。 + The required members list for the base type '{0}' is malformed and cannot be interpreted. To use this constructor, apply the 'SetsRequiredMembers' attribute. The required members list for '{0}' is malformed and cannot be interpreted. - '{0}' 的必要成員清單格式錯誤,無法解譯。 + The required members list for '{0}' is malformed and cannot be interpreted. Required member '{0}' must be assigned a value, it cannot use a nested member or collection initializer. - 必要的成員 '{0}' 必須指派值,它無法使用巢狀成員或集合初始設定式。 + Required member '{0}' must be assigned a value, it cannot use a nested member or collection initializer. Types and aliases cannot be named 'required'. - 類型和別名不能命名為 'required'。 + Types and aliases cannot be named 'required'. @@ -1523,12 +1519,12 @@ Auto-implemented property '{0}' must be fully assigned before control is returned to the caller. Consider updating to language version '{1}' to auto-default the property. - 在控制項傳回呼叫者之前,必須先完全指派自動實作屬性 '{0}'。請考慮更新至語言版本 '{1}' 以自動預設屬性。 + Auto-implemented property '{0}' must be fully assigned before control is returned to the caller. Consider updating to language version '{1}' to auto-default the property. Field '{0}' must be fully assigned before control is returned to the caller. Consider updating to language version '{1}' to auto-default the field. - 在控制項傳回呼叫者之前,必須先完全指派欄位 '{0}'。請考慮更新至語言版本 '{1}' 以自動預設欄位。 + Field '{0}' must be fully assigned before control is returned to the caller. Consider updating to language version '{1}' to auto-default the field. @@ -1543,7 +1539,7 @@ '{0}' requires compiler feature '{1}', which is not supported by this version of the C# compiler. - '{0}' 需要編譯器功能 '{1}',此版本的 C# 編譯器不支援此功能。 + '{0}' requires compiler feature '{1}', which is not supported by this version of the C# compiler. @@ -1563,17 +1559,17 @@ Use of possibly unassigned field '{0}'. Consider updating to language version '{1}' to auto-default the field. - 使用可能未指派的欄位 '{0}'。請考慮更新語言版本 '{1}' 以自動預設欄位。 + Use of possibly unassigned field '{0}'. Consider updating to language version '{1}' to auto-default the field. Use of possibly unassigned auto-implemented property '{0}'. Consider updating to language version '{1}' to auto-default the property. - 使用可能未指派的自動實作屬性 '{0}'。請考慮更新語言版本 '{1}' 以自動預設屬性。 + Use of possibly unassigned auto-implemented property '{0}'. Consider updating to language version '{1}' to auto-default the property. The 'this' object cannot be used before all of its fields have been assigned. Consider updating to language version '{0}' to auto-default the unassigned fields. - 在指派 'this' 物件的所有欄位之前,無法使用該物件。請考慮更新語言版本 '{0}',以自動預設未指派的欄位。 + The 'this' object cannot be used before all of its fields have been assigned. Consider updating to language version '{0}' to auto-default the unassigned fields. @@ -1598,12 +1594,12 @@ auto default struct fields - 自動預設結構欄位 + auto default struct fields checked user-defined operators - 已檢查使用者定義的運算子 + checked user-defined operators @@ -1708,12 +1704,12 @@ relaxed shift operator - 寬鬆移位 (Shift) 運算子 + relaxed shift operator required members - 必要成員 + required members @@ -1728,7 +1724,7 @@ unsigned right shift - 未簽署右移位 + unsigned right shift @@ -1753,7 +1749,7 @@ pattern matching ReadOnly/Span<char> on constant string - 常數字串上的模式比對 ReadOnly/Span<char> + pattern matching ReadOnly/Span<char> on constant string @@ -1888,12 +1884,12 @@ Required member '{0}' should not be attributed with 'ObsoleteAttribute' unless the containing type is obsolete or all constructors are obsolete. - 除非包含的類型已過時或所有建構函式已過時,否則必要成員 '{0}' 的屬性不應為 'ObsoleteAttribute'。 + Required member '{0}' should not be attributed with 'ObsoleteAttribute' unless the containing type is obsolete or all constructors are obsolete. Members attributed with 'ObsoleteAttribute' should not be required unless the containing type is obsolete or all constructors are obsolete. - 除非包含的類型已過時或所有建構函式已過時,否則不應要求具有 'ObsoleteAttribute' 屬性的成員。 + Members attributed with 'ObsoleteAttribute' should not be required unless the containing type is obsolete or all constructors are obsolete. @@ -2008,7 +2004,7 @@ 'UnmanagedCallersOnly' can only be applied to ordinary static non-abstract, non-virtual methods or static local functions. - 'UnmanagedCallersOnly' 僅適用於一般靜態非抽象方法、非虛擬方法或靜態區域函式。 + 'UnmanagedCallersOnly' can only be applied to ordinary static non-abstract, non-virtual methods or static local functions. UnmanagedCallersOnly is not localizable. @@ -2284,7 +2280,7 @@ -instrument:TestCoverage 產生經檢測的組件,以收集 涵蓋範圍資訊 -sourcelink:<file> 要內嵌至 PDB 的來源連結資訊。 - + - 錯誤與警告 - -warnaserror[+|-] 將所有警告回報為錯誤 -warnaserror[+|-]:<warn list> 將特定警告回報為錯誤 @@ -3792,42 +3788,42 @@ Control is returned to caller before auto-implemented property '{0}' is explicitly assigned, causing a preceding implicit assignment of 'default'. - 在明確指派自動實作屬性 '{0}' 之前會先將控制項傳回呼叫者,導致先前隱含的指派為 'default'。 + Control is returned to caller before auto-implemented property '{0}' is explicitly assigned, causing a preceding implicit assignment of 'default'. Control is returned to caller before auto-implemented property is explicitly assigned, causing a preceding implicit assignment of 'default'. - 在明確指派自動實作屬性之前會先將控制項傳回呼叫者,導致先前隱含的指派為 'default'。 + Control is returned to caller before auto-implemented property is explicitly assigned, causing a preceding implicit assignment of 'default'. Auto-implemented property '{0}' must be fully assigned before control is returned to the caller. Consider updating to language version '{1}' to auto-default the property. - 在控制項傳回呼叫者之前,必須先完全指派自動實作屬性 '{0}'。請考慮更新至語言版本 '{1}' 以自動預設屬性。 + Auto-implemented property '{0}' must be fully assigned before control is returned to the caller. Consider updating to language version '{1}' to auto-default the property. An auto-implemented property must be fully assigned before control is returned to the caller. Consider updating the language version to auto-default the property. - 在控制項傳回呼叫者之前,必須先完全指派自動實作屬性。請考慮更新至語言版本以自動預設屬性。 + An auto-implemented property must be fully assigned before control is returned to the caller. Consider updating the language version to auto-default the property. Control is returned to caller before field '{0}' is explicitly assigned, causing a preceding implicit assignment of 'default'. - 在明確指派欄位 '{0}' 之前會先將控制項傳回呼叫者,導致先前隱含的指派為 'default'。 + Control is returned to caller before field '{0}' is explicitly assigned, causing a preceding implicit assignment of 'default'. Control is returned to caller before field is explicitly assigned, causing a preceding implicit assignment of 'default'. - 在明確指派欄位之前會先將控制項傳回呼叫者,導致先前隱含的指派為 'default'。 + Control is returned to caller before field is explicitly assigned, causing a preceding implicit assignment of 'default'. Field '{0}' must be fully assigned before control is returned to the caller. Consider updating to language version '{1}' to auto-default the field. - 在控制項傳回呼叫者之前,必須先完全指派欄位 '{0}'。請考慮更新至語言版本 '{1}' 以自動預設欄位。 + Field '{0}' must be fully assigned before control is returned to the caller. Consider updating to language version '{1}' to auto-default the field. Fields of a struct must be fully assigned in a constructor before control is returned to the caller. Consider updating the language version to auto-default the field. - 在控制項傳回呼叫者之前,必須先在建構函式中完全指派結構的欄位。請考慮更新至語言版本以自動預設欄位。 + Fields of a struct must be fully assigned in a constructor before control is returned to the caller. Consider updating the language version to auto-default the field. @@ -3892,22 +3888,22 @@ Field '{0}' is read before being explicitly assigned, causing a preceding implicit assignment of 'default'. - 在明確指派之前會先讀取欄位 '{0}',導致先前隱含的指派為 'default'。 + Field '{0}' is read before being explicitly assigned, causing a preceding implicit assignment of 'default'. Field is read before being explicitly assigned, causing a preceding implicit assignment of 'default'. - 在明確指派之前會先讀取欄位,導致先前隱含的指派為 'default'。 + Field is read before being explicitly assigned, causing a preceding implicit assignment of 'default'. Use of possibly unassigned field '{0}'. Consider updating to language version '{1}' to auto-default the field. - 使用可能未指派的欄位 '{0}'。請考慮更新語言版本 '{1}' 以自動預設欄位。 + Use of possibly unassigned field '{0}'. Consider updating to language version '{1}' to auto-default the field. Use of possibly unassigned field. Consider updating the language version to auto-default the field. - 使用可能未指派的欄位。請考慮更新語言版本以自動預設欄位。 + Use of possibly unassigned field. Consider updating the language version to auto-default the field. @@ -3932,22 +3928,22 @@ Auto-implemented property '{0}' is read before being explicitly assigned, causing a preceding implicit assignment of 'default'. - 在明確指派之前會先讀取自動實作屬性 '{0}',導致先前隱含的指派為 'default'。 + Auto-implemented property '{0}' is read before being explicitly assigned, causing a preceding implicit assignment of 'default'. Auto-implemented property is read before being explicitly assigned, causing a preceding implicit assignment of 'default'. - 在明確指派之前會先讀取自動實作屬性,導致先前隱含的指派為 'default'。 + Auto-implemented property is read before being explicitly assigned, causing a preceding implicit assignment of 'default'. Use of possibly unassigned auto-implemented property '{0}'. Consider updating to language version '{1}' to auto-default the property. - 使用可能未指派的自動實作屬性 '{0}'。請考慮更新語言版本 '{1}' 以自動預設屬性。 + Use of possibly unassigned auto-implemented property '{0}'. Consider updating to language version '{1}' to auto-default the property. Use of possibly unassigned auto-implemented property. Consider updating the language version to auto-default the property. - 使用可能未指派的自動實作屬性。請考慮更新語言版本以自動預設屬性。 + Use of possibly unassigned auto-implemented property. Consider updating the language version to auto-default the property. @@ -3957,22 +3953,22 @@ The 'this' object is read before all of its fields have been assigned, causing preceding implicit assignments of 'default' to non-explicitly assigned fields. - 在指派 'this' 物件的所有欄位之前,會先讀取該物件,導致先前對未明確指派的欄位進行隱含的 'default' 指派。 + The 'this' object is read before all of its fields have been assigned, causing preceding implicit assignments of 'default' to non-explicitly assigned fields. The 'this' object is read before all of its fields have been assigned, causing preceding implicit assignments of 'default' to non-explicitly assigned fields. - 在指派 'this' 物件的所有欄位之前,會先讀取該物件,導致先前對未明確指派的欄位進行隱含的 'default' 指派。 + The 'this' object is read before all of its fields have been assigned, causing preceding implicit assignments of 'default' to non-explicitly assigned fields. The 'this' object cannot be used before all of its fields have been assigned. Consider updating to language version '{0}' to auto-default the unassigned fields. - 在指派 'this' 物件的所有欄位之前,無法使用該物件。請考慮更新語言版本 '{0}',以自動預設未指派的欄位。 + The 'this' object cannot be used before all of its fields have been assigned. Consider updating to language version '{0}' to auto-default the unassigned fields. The 'this' object cannot be used in a constructor before all of its fields have been assigned. Consider updating the language version to auto-default the unassigned fields. - 在指派 'this' 物件的所有欄位之前,無法在建構函式中使用。請考慮更新語言版本,以自動預設未指派的欄位。 + The 'this' object cannot be used in a constructor before all of its fields have been assigned. Consider updating the language version to auto-default the unassigned fields. @@ -6011,7 +6007,7 @@ If such a class is used as a base class and if the deriving class defines a dest The first operand of an overloaded shift operator must have the same type as the containing type - 多載移位 (Shift) 運算子的第一個運算元的類型必須和包含類型相同 + The first operand of an overloaded shift operator must have the same type as the containing type @@ -6586,7 +6582,7 @@ If such a class is used as a base class and if the deriving class defines a dest Cannot do non-virtual member lookup in '{0}' because it is a type parameter - Cannot do non-virtual member lookup in '{0}' because it is a type parameter + 無法在 '{0}' 中進行成員查詢,因為其為類型參數 @@ -11133,7 +11129,7 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ Cannot return a parameter by reference '{0}' because it is not a ref parameter - Cannot return a parameter by reference '{0}' because it is not a ref parameter + 無法藉傳址方式 '{0}' 傳回參數,因為其非 ref 或 out 參數 @@ -11753,7 +11749,7 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ Conversion, equality, or inequality operators declared in interfaces must be abstract or virtual - Conversion, equality, or inequality operators declared in interfaces must be abstract or virtual + 在介面中宣告的轉換、等式或不等式運算子必須為抽象 diff --git a/src/Compilers/CSharp/Test/Emit/Emit/EditAndContinue/EditAndContinueTests.cs b/src/Compilers/CSharp/Test/Emit/Emit/EditAndContinue/EditAndContinueTests.cs index 8714e9fbc589f..9cdccab77612b 100644 --- a/src/Compilers/CSharp/Test/Emit/Emit/EditAndContinue/EditAndContinueTests.cs +++ b/src/Compilers/CSharp/Test/Emit/Emit/EditAndContinue/EditAndContinueTests.cs @@ -13161,337 +13161,6 @@ .maxstack 1 IL_0002: ret }"); } -<<<<<<< HEAD - - [Fact] - public void FileTypes_01() - { - var source0 = MarkedSource(@" -using System; -file class C -{ - void M() - { - Console.Write(1); - } -}", "file1.cs"); - var source1 = MarkedSource(@" -using System; -file class C -{ - void M() - { - Console.Write(2); - } -}", "file1.cs"); - - var compilation0 = CreateCompilation(source0.Tree, options: ComSafeDebugDll); - var compilation1 = compilation0.WithSource(source1.Tree); - - var method0 = compilation0.GetMember("C.M"); - var method1 = compilation1.GetMember("C.M"); - - var v0 = CompileAndVerify(compilation0, verify: Verification.Skipped); - - v0.VerifyIL("C@file1.M", @" -{ - // Code size 9 (0x9) - .maxstack 1 - IL_0000: nop - IL_0001: ldc.i4.1 - IL_0002: call ""void System.Console.Write(int)"" - IL_0007: nop - IL_0008: ret -} -"); - - using var md0 = ModuleMetadata.CreateFromImage(v0.EmittedAssemblyData); - - var generation0 = EmitBaseline.CreateInitialBaseline(md0, v0.CreateSymReader().GetEncMethodDebugInfo); - - var diff = compilation1.EmitDifference( - generation0, - ImmutableArray.Create( - SemanticEdit.Create(SemanticEditKind.Update, method0, method1, GetSyntaxMapFromMarkers(source0, source1), preserveLocalVariables: true))); - - // There should be no diagnostics from rude edits - diff.EmitResult.Diagnostics.Verify(); - - diff.VerifyIL("C@file1.M", @" -{ - // Code size 9 (0x9) - .maxstack 1 - IL_0000: nop - IL_0001: ldc.i4.2 - IL_0002: call ""void System.Console.Write(int)"" - IL_0007: nop - IL_0008: ret -}"); - } - - [Fact] - public void FileTypes_02() - { - var source0 = MarkedSource(@" -using System; -file class C -{ - void M() - { - Console.Write(1); - } -}", "file1.cs"); - var source1 = MarkedSource(@" -using System; -file class C -{ - void M() - { - Console.Write(2); - } -}", "file1.cs"); - var source2 = MarkedSource(@" -using System; -file class C -{ - void M() - { - Console.Write(3); - } -}", "file2.cs"); - - var compilation0 = CreateCompilation(source0.Tree, options: ComSafeDebugDll); - var compilation1 = compilation0.WithSource(new[] { source1.Tree, source2.Tree }); - - var cm1_gen0 = compilation0.GetMember("C.M"); - var cm1_gen1 = ((NamedTypeSymbol)compilation1.GetMembers("C")[0]).GetMember("M"); - var c2_gen1 = ((NamedTypeSymbol)compilation1.GetMembers("C")[1]); - - var v0 = CompileAndVerify(compilation0, verify: Verification.Skipped); - - v0.VerifyIL("C@file1.M", @" -{ - // Code size 9 (0x9) - .maxstack 1 - IL_0000: nop - IL_0001: ldc.i4.1 - IL_0002: call ""void System.Console.Write(int)"" - IL_0007: nop - IL_0008: ret -} -"); - - using var md0 = ModuleMetadata.CreateFromImage(v0.EmittedAssemblyData); - - var generation0 = EmitBaseline.CreateInitialBaseline(md0, v0.CreateSymReader().GetEncMethodDebugInfo); - - var diff = compilation1.EmitDifference( - generation0, - ImmutableArray.Create( - SemanticEdit.Create(SemanticEditKind.Update, cm1_gen0, cm1_gen1, GetSyntaxMapFromMarkers(source0, source1), preserveLocalVariables: true), - SemanticEdit.Create(SemanticEditKind.Insert, null, c2_gen1, syntaxMap: null, preserveLocalVariables: true))); - - // There should be no diagnostics from rude edits - diff.EmitResult.Diagnostics.Verify(); - - diff.VerifyIL("C@file1.M", @" -{ - // Code size 9 (0x9) - .maxstack 1 - IL_0000: nop - IL_0001: ldc.i4.2 - IL_0002: call ""void System.Console.Write(int)"" - IL_0007: nop - IL_0008: ret -}"); - - diff.VerifyIL("C@file2.M", @" -{ - // Code size 9 (0x9) - .maxstack 1 - IL_0000: nop - IL_0001: ldc.i4.3 - IL_0002: call ""void System.Console.Write(int)"" - IL_0007: nop - IL_0008: ret -}"); - } - - [Fact] - public void FileTypes_03() - { - var source0_gen0 = MarkedSource(@" -using System; -file class C -{ - void M() - { - Console.Write(1); - } -}", "file1.cs"); - var source1_gen1 = MarkedSource(@" -using System; -file class C -{ - void M() - { - Console.Write(2); - } -}", "file2.cs"); - var source0_gen1 = MarkedSource(@" -using System; -file class C -{ - void M() - { - Console.Write(3); - } -}", "file1.cs"); - - var compilation0 = CreateCompilation(source0_gen0.Tree, options: ComSafeDebugDll); - // Because the order of syntax trees has changed here, the original type is considered deleted and the two new types are completely new, unrelated types. - - // https://github.com/dotnet/roslyn/issues/61999 - // we should handle this as a modification of an existing type rather than deletion and insertion of distinct types. - // most likely, we either need to identify file types based on something stable like the SyntaxTree.FilePath, or store a mapping of the ordinals from one generation to the next. - // although "real-world" compilations disallow duplicated file paths, duplicated or empty file paths are very common via direct use of the APIs, so there's not necessarily a single slam-dunk answer here. - var compilation1 = compilation0.WithSource(new[] { source1_gen1.Tree, source0_gen1.Tree }); - - var c1_gen0 = compilation0.GetMember("C"); - var c1_gen1 = ((NamedTypeSymbol)compilation1.GetMembers("C")[0]); - var c2_gen1 = ((NamedTypeSymbol)compilation1.GetMembers("C")[1]); - - var v0 = CompileAndVerify(compilation0, verify: Verification.Skipped); - - v0.VerifyIL("C@file1.M", @" -{ - // Code size 9 (0x9) - .maxstack 1 - IL_0000: nop - IL_0001: ldc.i4.1 - IL_0002: call ""void System.Console.Write(int)"" - IL_0007: nop - IL_0008: ret -} -"); - - using var md0 = ModuleMetadata.CreateFromImage(v0.EmittedAssemblyData); - - var generation0 = EmitBaseline.CreateInitialBaseline(md0, v0.CreateSymReader().GetEncMethodDebugInfo); - - var diff = compilation1.EmitDifference( - generation0, - ImmutableArray.Create( - SemanticEdit.Create(SemanticEditKind.Delete, c1_gen0, null, syntaxMap: null, preserveLocalVariables: true), - SemanticEdit.Create(SemanticEditKind.Insert, null, c1_gen1, syntaxMap: null, preserveLocalVariables: true), - SemanticEdit.Create(SemanticEditKind.Insert, null, c2_gen1, syntaxMap: null, preserveLocalVariables: true))); - - // There should be no diagnostics from rude edits - diff.EmitResult.Diagnostics.Verify(); - - diff.VerifyIL("C@file1.M", @" -{ - // Code size 9 (0x9) - .maxstack 1 - IL_0000: nop - IL_0001: ldc.i4.3 - IL_0002: call ""void System.Console.Write(int)"" - IL_0007: nop - IL_0008: ret -}"); - - diff.VerifyIL("C@file2.M", @" -{ - // Code size 9 (0x9) - .maxstack 1 - IL_0000: nop - IL_0001: ldc.i4.2 - IL_0002: call ""void System.Console.Write(int)"" - IL_0007: nop - IL_0008: ret -}"); - } - - [Fact] - public void FileTypes_04() - { - var source1_gen0 = MarkedSource(@" -using System; -file class C -{ - void M() - { - Console.Write(1); - } -}", "file1.cs"); - var source2_gen0 = MarkedSource(@" -using System; -file class C -{ - void M() - { - Console.Write(2); - } -}", "file2.cs"); - var source2_gen1 = MarkedSource(@" -using System; -file class C -{ - void M() - { - Console.Write(3); - } -}", "file2.cs"); - - var compilation0 = CreateCompilation(new[] { source1_gen0.Tree, source2_gen0.Tree }, options: ComSafeDebugDll); - - var compilation1 = compilation0.WithSource(new[] { source2_gen1.Tree }); - - var c1_gen0 = ((NamedTypeSymbol)compilation0.GetMembers("C")[0]); - var c2_gen0 = ((NamedTypeSymbol)compilation0.GetMembers("C")[1]); - var c2_gen1 = compilation1.GetMember("C"); - - var v0 = CompileAndVerify(compilation0, verify: Verification.Skipped); - - v0.VerifyIL("C@file2.M", @" -{ - // Code size 9 (0x9) - .maxstack 1 - IL_0000: nop - IL_0001: ldc.i4.2 - IL_0002: call ""void System.Console.Write(int)"" - IL_0007: nop - IL_0008: ret -} -"); - - using var md0 = ModuleMetadata.CreateFromImage(v0.EmittedAssemblyData); - - var generation0 = EmitBaseline.CreateInitialBaseline(md0, v0.CreateSymReader().GetEncMethodDebugInfo); - - var diff = compilation1.EmitDifference( - generation0, - ImmutableArray.Create( - SemanticEdit.Create(SemanticEditKind.Delete, c1_gen0, null, syntaxMap: null, preserveLocalVariables: true), - SemanticEdit.Create(SemanticEditKind.Delete, c2_gen0, null, syntaxMap: null, preserveLocalVariables: true), - SemanticEdit.Create(SemanticEditKind.Insert, null, c2_gen1, syntaxMap: null, preserveLocalVariables: true))); - - // There should be no diagnostics from rude edits - diff.EmitResult.Diagnostics.Verify(); - - diff.VerifyIL("C@file2.M", @" -{ - // Code size 9 (0x9) - .maxstack 1 - IL_0000: nop - IL_0001: ldc.i4.3 - IL_0002: call ""void System.Console.Write(int)"" - IL_0007: nop - IL_0008: ret -}"); - } -||||||| 4518b4087d0 -======= [Theory] [InlineData("void M1() { }", 0)] @@ -13836,15 +13505,174 @@ .maxstack 8 .AddGeneration( source: """ - class A : System.Attribute { } - class B : System.Attribute { } - + class A : System.Attribute { } + class B : System.Attribute { } + + class C + { + [B] + [return: B] + void M1([B]int x) { } + + } + """, + edits: new[] { + Edit(SemanticEditKind.Insert, symbolProvider: c => c.GetMember("C.M1")), + }, + validator: g => + { + g.VerifyTypeDefNames(); + g.VerifyMethodDefNames("M1"); + g.VerifyEncLogDefinitions(new[] + { + Row(3, TableIndex.MethodDef, EditAndContinueOperation.Default), + Row(1, TableIndex.Param, EditAndContinueOperation.Default), + Row(2, TableIndex.Param, EditAndContinueOperation.Default), + Row(1, TableIndex.CustomAttribute, EditAndContinueOperation.Default), + Row(5, TableIndex.CustomAttribute, EditAndContinueOperation.Default), + Row(6, TableIndex.CustomAttribute, EditAndContinueOperation.Default) + }); + g.VerifyEncMapDefinitions(new[] + { + Handle(3, TableIndex.MethodDef), + Handle(1, TableIndex.Param), + Handle(2, TableIndex.Param), + Handle(1, TableIndex.CustomAttribute), + Handle(5, TableIndex.CustomAttribute), + Handle(6, TableIndex.CustomAttribute) + }); + g.VerifyCustomAttributes(new[] + { + new CustomAttributeRow(Handle(1, TableIndex.Param), Handle(2, TableIndex.MethodDef)), + new CustomAttributeRow(Handle(2, TableIndex.Param), Handle(2, TableIndex.MethodDef)), + new CustomAttributeRow(Handle(3, TableIndex.MethodDef), Handle(2, TableIndex.MethodDef)) + }); + + var expectedIL = """ + { + // Code size 2 (0x2) + .maxstack 8 + IL_0000: nop + IL_0001: ret + } + """; + + // Can't verify the IL of individual methods because that requires IMethodSymbolInternal implementations + g.VerifyIL(expectedIL); + }) + .Verify(); + } + + [Fact] + public void Method_AddThenDeleteThenAdd() + { + using var _ = new EditAndContinueTest(options: TestOptions.DebugDll, targetFramework: TargetFramework.NetStandard20) + .AddGeneration( + source: $$""" + class C + { + void Goo() { } + } + """, + validator: g => + { + g.VerifyTypeDefNames("", "C"); + g.VerifyMethodDefNames("Goo", ".ctor"); + g.VerifyMemberRefNames(/*CompilationRelaxationsAttribute.*/".ctor", /*RuntimeCompatibilityAttribute.*/".ctor", /*Object.*/".ctor", /*DebuggableAttribute*/".ctor"); + }) + + .AddGeneration( + source: """ + class C + { + void Goo() { } + C M1(C c) { return default; } + } + """, + edits: new[] { + Edit(SemanticEditKind.Insert, symbolProvider: c => c.GetMember("C.M1")), + }, + validator: g => + { + g.VerifyTypeDefNames(); + g.VerifyMethodDefNames("M1"); + g.VerifyEncLogDefinitions(new[] + { + Row(1, TableIndex.StandAloneSig, EditAndContinueOperation.Default), + Row(2, TableIndex.TypeDef, EditAndContinueOperation.AddMethod), + Row(3, TableIndex.MethodDef, EditAndContinueOperation.Default), + Row(3, TableIndex.MethodDef, EditAndContinueOperation.AddParameter), + Row(1, TableIndex.Param, EditAndContinueOperation.Default) + }); + g.VerifyEncMapDefinitions(new[] + { + Handle(3, TableIndex.MethodDef), + Handle(1, TableIndex.Param), + Handle(1, TableIndex.StandAloneSig) + }); + + var expectedIL = """ + { + // Code size 7 (0x7) + .maxstack 1 + IL_0000: nop + IL_0001: ldnull + IL_0002: stloc.0 + IL_0003: br.s IL_0005 + IL_0005: ldloc.0 + IL_0006: ret + } + """; + + // Can't verify the IL of individual methods because that requires IMethodSymbolInternal implementations + g.VerifyIL(expectedIL); + }) + + .AddGeneration( + source: """ + class C + { + void Goo() { } + } + """, + edits: new[] { + Edit(SemanticEditKind.Delete, symbolProvider: c => c.GetMember("C.M1"), newSymbolProvider: c=>c.GetMember("C")), + }, + validator: g => + { + g.VerifyTypeDefNames(); + g.VerifyMethodDefNames("M1"); + g.VerifyEncLogDefinitions(new[] + { + Row(3, TableIndex.MethodDef, EditAndContinueOperation.Default), + Row(1, TableIndex.Param, EditAndContinueOperation.Default) + }); + g.VerifyEncMapDefinitions(new[] + { + Handle(3, TableIndex.MethodDef), + Handle(1, TableIndex.Param), + }); + + var expectedIL = """ + { + // Code size 6 (0x6) + .maxstack 8 + IL_0000: newobj 0x0A000005 + IL_0005: throw + } + """; + + // Can't verify the IL of individual methods because that requires IMethodSymbolInternal implementations + g.VerifyIL(expectedIL); + + }) + + .AddGeneration( + source: """ class C { - [B] - [return: B] - void M1([B]int x) { } - + void Goo() { } + C M1(C b) { System.Console.Write(1); return default; } } """, edits: new[] { @@ -13856,197 +13684,365 @@ void M1([B]int x) { } g.VerifyMethodDefNames("M1"); g.VerifyEncLogDefinitions(new[] { + Row(2, TableIndex.StandAloneSig, EditAndContinueOperation.Default), Row(3, TableIndex.MethodDef, EditAndContinueOperation.Default), - Row(1, TableIndex.Param, EditAndContinueOperation.Default), - Row(2, TableIndex.Param, EditAndContinueOperation.Default), - Row(1, TableIndex.CustomAttribute, EditAndContinueOperation.Default), - Row(5, TableIndex.CustomAttribute, EditAndContinueOperation.Default), - Row(6, TableIndex.CustomAttribute, EditAndContinueOperation.Default) + Row(1, TableIndex.Param, EditAndContinueOperation.Default) }); g.VerifyEncMapDefinitions(new[] { Handle(3, TableIndex.MethodDef), Handle(1, TableIndex.Param), - Handle(2, TableIndex.Param), - Handle(1, TableIndex.CustomAttribute), - Handle(5, TableIndex.CustomAttribute), - Handle(6, TableIndex.CustomAttribute) - }); - g.VerifyCustomAttributes(new[] - { - new CustomAttributeRow(Handle(1, TableIndex.Param), Handle(2, TableIndex.MethodDef)), - new CustomAttributeRow(Handle(2, TableIndex.Param), Handle(2, TableIndex.MethodDef)), - new CustomAttributeRow(Handle(3, TableIndex.MethodDef), Handle(2, TableIndex.MethodDef)) + Handle(2, TableIndex.StandAloneSig) }); - var expectedIL = """ - { - // Code size 2 (0x2) - .maxstack 8 - IL_0000: nop - IL_0001: ret - } - """; + var expectedIL = """ + { + // Code size 14 (0xe) + .maxstack 1 + IL_0000: nop + IL_0001: ldc.i4.1 + IL_0002: call 0x0A000006 + IL_0007: nop + IL_0008: ldnull + IL_0009: stloc.0 + IL_000a: br.s IL_000c + IL_000c: ldloc.0 + IL_000d: ret + } + """; + + // Can't verify the IL of individual methods because that requires IMethodSymbolInternal implementations + g.VerifyIL(expectedIL); + }) + .Verify(); + } + + [Fact] + public void FileTypes_01() + { + var source0 = MarkedSource(@" +using System; +file class C +{ + void M() + { + Console.Write(1); + } +}", "file1.cs"); + var source1 = MarkedSource(@" +using System; +file class C +{ + void M() + { + Console.Write(2); + } +}", "file1.cs"); + + var compilation0 = CreateCompilation(source0.Tree, options: ComSafeDebugDll); + var compilation1 = compilation0.WithSource(source1.Tree); + + var method0 = compilation0.GetMember("C.M"); + var method1 = compilation1.GetMember("C.M"); + + var v0 = CompileAndVerify(compilation0, verify: Verification.Skipped); + + v0.VerifyIL("C@file1.M", @" +{ + // Code size 9 (0x9) + .maxstack 1 + IL_0000: nop + IL_0001: ldc.i4.1 + IL_0002: call ""void System.Console.Write(int)"" + IL_0007: nop + IL_0008: ret +} +"); + + using var md0 = ModuleMetadata.CreateFromImage(v0.EmittedAssemblyData); + + var generation0 = EmitBaseline.CreateInitialBaseline(md0, v0.CreateSymReader().GetEncMethodDebugInfo); + + var diff = compilation1.EmitDifference( + generation0, + ImmutableArray.Create( + SemanticEdit.Create(SemanticEditKind.Update, method0, method1, GetSyntaxMapFromMarkers(source0, source1), preserveLocalVariables: true))); + + // There should be no diagnostics from rude edits + diff.EmitResult.Diagnostics.Verify(); + + diff.VerifyIL("C@file1.M", @" +{ + // Code size 9 (0x9) + .maxstack 1 + IL_0000: nop + IL_0001: ldc.i4.2 + IL_0002: call ""void System.Console.Write(int)"" + IL_0007: nop + IL_0008: ret +}"); + } + + [Fact] + public void FileTypes_02() + { + var source0 = MarkedSource(@" +using System; +file class C +{ + void M() + { + Console.Write(1); + } +}", "file1.cs"); + var source1 = MarkedSource(@" +using System; +file class C +{ + void M() + { + Console.Write(2); + } +}", "file1.cs"); + var source2 = MarkedSource(@" +using System; +file class C +{ + void M() + { + Console.Write(3); + } +}", "file2.cs"); + + var compilation0 = CreateCompilation(source0.Tree, options: ComSafeDebugDll); + var compilation1 = compilation0.WithSource(new[] { source1.Tree, source2.Tree }); + + var cm1_gen0 = compilation0.GetMember("C.M"); + var cm1_gen1 = ((NamedTypeSymbol)compilation1.GetMembers("C")[0]).GetMember("M"); + var c2_gen1 = ((NamedTypeSymbol)compilation1.GetMembers("C")[1]); + + var v0 = CompileAndVerify(compilation0, verify: Verification.Skipped); + + v0.VerifyIL("C@file1.M", @" +{ + // Code size 9 (0x9) + .maxstack 1 + IL_0000: nop + IL_0001: ldc.i4.1 + IL_0002: call ""void System.Console.Write(int)"" + IL_0007: nop + IL_0008: ret +} +"); + + using var md0 = ModuleMetadata.CreateFromImage(v0.EmittedAssemblyData); + + var generation0 = EmitBaseline.CreateInitialBaseline(md0, v0.CreateSymReader().GetEncMethodDebugInfo); + + var diff = compilation1.EmitDifference( + generation0, + ImmutableArray.Create( + SemanticEdit.Create(SemanticEditKind.Update, cm1_gen0, cm1_gen1, GetSyntaxMapFromMarkers(source0, source1), preserveLocalVariables: true), + SemanticEdit.Create(SemanticEditKind.Insert, null, c2_gen1, syntaxMap: null, preserveLocalVariables: true))); + + // There should be no diagnostics from rude edits + diff.EmitResult.Diagnostics.Verify(); + + diff.VerifyIL("C@file1.M", @" +{ + // Code size 9 (0x9) + .maxstack 1 + IL_0000: nop + IL_0001: ldc.i4.2 + IL_0002: call ""void System.Console.Write(int)"" + IL_0007: nop + IL_0008: ret +}"); + + diff.VerifyIL("C@file2.M", @" +{ + // Code size 9 (0x9) + .maxstack 1 + IL_0000: nop + IL_0001: ldc.i4.3 + IL_0002: call ""void System.Console.Write(int)"" + IL_0007: nop + IL_0008: ret +}"); + } + + [Fact] + public void FileTypes_03() + { + var source0_gen0 = MarkedSource(@" +using System; +file class C +{ + void M() + { + Console.Write(1); + } +}", "file1.cs"); + var source1_gen1 = MarkedSource(@" +using System; +file class C +{ + void M() + { + Console.Write(2); + } +}", "file2.cs"); + var source0_gen1 = MarkedSource(@" +using System; +file class C +{ + void M() + { + Console.Write(3); + } +}", "file1.cs"); + + var compilation0 = CreateCompilation(source0_gen0.Tree, options: ComSafeDebugDll); + // Because the order of syntax trees has changed here, the original type is considered deleted and the two new types are completely new, unrelated types. + + // https://github.com/dotnet/roslyn/issues/61999 + // we should handle this as a modification of an existing type rather than deletion and insertion of distinct types. + // most likely, we either need to identify file types based on something stable like the SyntaxTree.FilePath, or store a mapping of the ordinals from one generation to the next. + // although "real-world" compilations disallow duplicated file paths, duplicated or empty file paths are very common via direct use of the APIs, so there's not necessarily a single slam-dunk answer here. + var compilation1 = compilation0.WithSource(new[] { source1_gen1.Tree, source0_gen1.Tree }); + + var c1_gen0 = compilation0.GetMember("C"); + var c1_gen1 = ((NamedTypeSymbol)compilation1.GetMembers("C")[0]); + var c2_gen1 = ((NamedTypeSymbol)compilation1.GetMembers("C")[1]); + + var v0 = CompileAndVerify(compilation0, verify: Verification.Skipped); + + v0.VerifyIL("C@file1.M", @" +{ + // Code size 9 (0x9) + .maxstack 1 + IL_0000: nop + IL_0001: ldc.i4.1 + IL_0002: call ""void System.Console.Write(int)"" + IL_0007: nop + IL_0008: ret +} +"); + + using var md0 = ModuleMetadata.CreateFromImage(v0.EmittedAssemblyData); - // Can't verify the IL of individual methods because that requires IMethodSymbolInternal implementations - g.VerifyIL(expectedIL); - }) - .Verify(); + var generation0 = EmitBaseline.CreateInitialBaseline(md0, v0.CreateSymReader().GetEncMethodDebugInfo); + + var diff = compilation1.EmitDifference( + generation0, + ImmutableArray.Create( + SemanticEdit.Create(SemanticEditKind.Delete, c1_gen0, null, syntaxMap: null, preserveLocalVariables: true), + SemanticEdit.Create(SemanticEditKind.Insert, null, c1_gen1, syntaxMap: null, preserveLocalVariables: true), + SemanticEdit.Create(SemanticEditKind.Insert, null, c2_gen1, syntaxMap: null, preserveLocalVariables: true))); + + // There should be no diagnostics from rude edits + diff.EmitResult.Diagnostics.Verify(); + + diff.VerifyIL("C@file1.M", @" +{ + // Code size 9 (0x9) + .maxstack 1 + IL_0000: nop + IL_0001: ldc.i4.3 + IL_0002: call ""void System.Console.Write(int)"" + IL_0007: nop + IL_0008: ret +}"); + + diff.VerifyIL("C@file2.M", @" +{ + // Code size 9 (0x9) + .maxstack 1 + IL_0000: nop + IL_0001: ldc.i4.2 + IL_0002: call ""void System.Console.Write(int)"" + IL_0007: nop + IL_0008: ret +}"); } [Fact] - public void Method_AddThenDeleteThenAdd() + public void FileTypes_04() { - using var _ = new EditAndContinueTest(options: TestOptions.DebugDll, targetFramework: TargetFramework.NetStandard20) - .AddGeneration( - source: $$""" - class C - { - void Goo() { } - } - """, - validator: g => - { - g.VerifyTypeDefNames("", "C"); - g.VerifyMethodDefNames("Goo", ".ctor"); - g.VerifyMemberRefNames(/*CompilationRelaxationsAttribute.*/".ctor", /*RuntimeCompatibilityAttribute.*/".ctor", /*Object.*/".ctor", /*DebuggableAttribute*/".ctor"); - }) + var source1_gen0 = MarkedSource(@" +using System; +file class C +{ + void M() + { + Console.Write(1); + } +}", "file1.cs"); + var source2_gen0 = MarkedSource(@" +using System; +file class C +{ + void M() + { + Console.Write(2); + } +}", "file2.cs"); + var source2_gen1 = MarkedSource(@" +using System; +file class C +{ + void M() + { + Console.Write(3); + } +}", "file2.cs"); - .AddGeneration( - source: """ - class C - { - void Goo() { } - C M1(C c) { return default; } - } - """, - edits: new[] { - Edit(SemanticEditKind.Insert, symbolProvider: c => c.GetMember("C.M1")), - }, - validator: g => - { - g.VerifyTypeDefNames(); - g.VerifyMethodDefNames("M1"); - g.VerifyEncLogDefinitions(new[] - { - Row(1, TableIndex.StandAloneSig, EditAndContinueOperation.Default), - Row(2, TableIndex.TypeDef, EditAndContinueOperation.AddMethod), - Row(3, TableIndex.MethodDef, EditAndContinueOperation.Default), - Row(3, TableIndex.MethodDef, EditAndContinueOperation.AddParameter), - Row(1, TableIndex.Param, EditAndContinueOperation.Default) - }); - g.VerifyEncMapDefinitions(new[] - { - Handle(3, TableIndex.MethodDef), - Handle(1, TableIndex.Param), - Handle(1, TableIndex.StandAloneSig) - }); + var compilation0 = CreateCompilation(new[] { source1_gen0.Tree, source2_gen0.Tree }, options: ComSafeDebugDll); - var expectedIL = """ - { - // Code size 7 (0x7) - .maxstack 1 - IL_0000: nop - IL_0001: ldnull - IL_0002: stloc.0 - IL_0003: br.s IL_0005 - IL_0005: ldloc.0 - IL_0006: ret - } - """; + var compilation1 = compilation0.WithSource(new[] { source2_gen1.Tree }); - // Can't verify the IL of individual methods because that requires IMethodSymbolInternal implementations - g.VerifyIL(expectedIL); - }) + var c1_gen0 = ((NamedTypeSymbol)compilation0.GetMembers("C")[0]); + var c2_gen0 = ((NamedTypeSymbol)compilation0.GetMembers("C")[1]); + var c2_gen1 = compilation1.GetMember("C"); - .AddGeneration( - source: """ - class C - { - void Goo() { } - } - """, - edits: new[] { - Edit(SemanticEditKind.Delete, symbolProvider: c => c.GetMember("C.M1"), newSymbolProvider: c=>c.GetMember("C")), - }, - validator: g => - { - g.VerifyTypeDefNames(); - g.VerifyMethodDefNames("M1"); - g.VerifyEncLogDefinitions(new[] - { - Row(3, TableIndex.MethodDef, EditAndContinueOperation.Default), - Row(1, TableIndex.Param, EditAndContinueOperation.Default) - }); - g.VerifyEncMapDefinitions(new[] - { - Handle(3, TableIndex.MethodDef), - Handle(1, TableIndex.Param), - }); + var v0 = CompileAndVerify(compilation0, verify: Verification.Skipped); - var expectedIL = """ - { - // Code size 6 (0x6) - .maxstack 8 - IL_0000: newobj 0x0A000005 - IL_0005: throw - } - """; + v0.VerifyIL("C@file2.M", @" +{ + // Code size 9 (0x9) + .maxstack 1 + IL_0000: nop + IL_0001: ldc.i4.2 + IL_0002: call ""void System.Console.Write(int)"" + IL_0007: nop + IL_0008: ret +} +"); - // Can't verify the IL of individual methods because that requires IMethodSymbolInternal implementations - g.VerifyIL(expectedIL); + using var md0 = ModuleMetadata.CreateFromImage(v0.EmittedAssemblyData); - }) + var generation0 = EmitBaseline.CreateInitialBaseline(md0, v0.CreateSymReader().GetEncMethodDebugInfo); - .AddGeneration( - source: """ - class C - { - void Goo() { } - C M1(C b) { System.Console.Write(1); return default; } - } - """, - edits: new[] { - Edit(SemanticEditKind.Insert, symbolProvider: c => c.GetMember("C.M1")), - }, - validator: g => - { - g.VerifyTypeDefNames(); - g.VerifyMethodDefNames("M1"); - g.VerifyEncLogDefinitions(new[] - { - Row(2, TableIndex.StandAloneSig, EditAndContinueOperation.Default), - Row(3, TableIndex.MethodDef, EditAndContinueOperation.Default), - Row(1, TableIndex.Param, EditAndContinueOperation.Default) - }); - g.VerifyEncMapDefinitions(new[] - { - Handle(3, TableIndex.MethodDef), - Handle(1, TableIndex.Param), - Handle(2, TableIndex.StandAloneSig) - }); + var diff = compilation1.EmitDifference( + generation0, + ImmutableArray.Create( + SemanticEdit.Create(SemanticEditKind.Delete, c1_gen0, null, syntaxMap: null, preserveLocalVariables: true), + SemanticEdit.Create(SemanticEditKind.Delete, c2_gen0, null, syntaxMap: null, preserveLocalVariables: true), + SemanticEdit.Create(SemanticEditKind.Insert, null, c2_gen1, syntaxMap: null, preserveLocalVariables: true))); - var expectedIL = """ - { - // Code size 14 (0xe) - .maxstack 1 - IL_0000: nop - IL_0001: ldc.i4.1 - IL_0002: call 0x0A000006 - IL_0007: nop - IL_0008: ldnull - IL_0009: stloc.0 - IL_000a: br.s IL_000c - IL_000c: ldloc.0 - IL_000d: ret - } - """; + // There should be no diagnostics from rude edits + diff.EmitResult.Diagnostics.Verify(); - // Can't verify the IL of individual methods because that requires IMethodSymbolInternal implementations - g.VerifyIL(expectedIL); - }) - .Verify(); + diff.VerifyIL("C@file2.M", @" +{ + // Code size 9 (0x9) + .maxstack 1 + IL_0000: nop + IL_0001: ldc.i4.3 + IL_0002: call ""void System.Console.Write(int)"" + IL_0007: nop + IL_0008: ret +}"); } ->>>>>>> upstream/main } } diff --git a/src/Compilers/Core/Portable/SymbolDisplay/SymbolDisplayCompilerInternalOptions.cs b/src/Compilers/Core/Portable/SymbolDisplay/SymbolDisplayCompilerInternalOptions.cs index 679db261772c4..d5b83d44d8fbc 100644 --- a/src/Compilers/Core/Portable/SymbolDisplay/SymbolDisplayCompilerInternalOptions.cs +++ b/src/Compilers/Core/Portable/SymbolDisplay/SymbolDisplayCompilerInternalOptions.cs @@ -67,19 +67,15 @@ internal enum SymbolDisplayCompilerInternalOptions /// Separate out nested types from containing types using + instead of . (dot). /// UsePlusForNestedTypes = 1 << 8, -<<<<<<< HEAD /// - /// Display `MyType@File.cs` instead of `MyType`. + /// Includes the scoped keyword. /// - IncludeContainingFileForFileTypes = 1 << 9, -||||||| 4518b4087d0 -======= + IncludeScoped = 1 << 9, /// - /// Includes the scoped keyword. + /// Display `MyType@File.cs` instead of `MyType`. /// - IncludeScoped = 1 << 9, ->>>>>>> upstream/main + IncludeContainingFileForFileTypes = 1 << 10, } } From 53b193b360c494f7c33db7cd9d7bec7f440cac8b Mon Sep 17 00:00:00 2001 From: Rikki Gibson Date: Tue, 5 Jul 2022 07:15:01 -0700 Subject: [PATCH 09/11] File types IDE changes (#62215) Co-authored-by: Cyrus Najmabadi Co-authored-by: Youssef Victor --- .../Symbols/PublicModel/NamedTypeSymbol.cs | 2 + .../Symbols/Source/FileModifierTests.cs | 27 +++- .../Core/Portable/Symbols/INamedTypeSymbol.cs | 5 + .../Portable/Symbols/NamedTypeSymbol.vb | 6 + .../KeywordCompletionProviderTests.cs | 146 ++++++++++++++++++ .../SymbolKey/SymbolKeyCompilationsTests.cs | 92 +++++++++++ .../CSharpTest/SymbolKey/SymbolKeyTests.cs | 105 +++++++++++++ .../CodeGenerationTests.CSharp.cs | 53 +++++++ .../KeywordCompletionProvider.cs | 1 + .../FileKeywordRecommender.cs | 30 ++++ ...aAsSourceService.WrappedNamedTypeSymbol.cs | 2 + .../CodeGeneration/CSharpSyntaxGenerator.cs | 15 +- .../CodeGeneration/NamedTypeGenerator.cs | 16 +- .../CodeGenerationAbstractNamedTypeSymbol.cs | 2 + .../Portable/Editing/DeclarationModifiers.cs | 16 +- .../SymbolKey/SymbolKey.NamedTypeSymbolKey.cs | 24 ++- .../Compiler/Core/SymbolKey/SymbolKey.cs | 2 +- .../CSharp/Utilities/SyntaxKindSet.cs | 1 + 18 files changed, 523 insertions(+), 22 deletions(-) create mode 100644 src/Features/CSharp/Portable/Completion/KeywordRecommenders/FileKeywordRecommender.cs diff --git a/src/Compilers/CSharp/Portable/Symbols/PublicModel/NamedTypeSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/PublicModel/NamedTypeSymbol.cs index f5173fe3d8665..6f09cef0e4714 100644 --- a/src/Compilers/CSharp/Portable/Symbols/PublicModel/NamedTypeSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/PublicModel/NamedTypeSymbol.cs @@ -194,6 +194,8 @@ INamedTypeSymbol INamedTypeSymbol.TupleUnderlyingType bool INamedTypeSymbol.IsSerializable => UnderlyingNamedTypeSymbol.IsSerializable; + bool INamedTypeSymbol.IsFile => UnderlyingNamedTypeSymbol.AssociatedSyntaxTree is not null; + INamedTypeSymbol INamedTypeSymbol.NativeIntegerUnderlyingType => UnderlyingNamedTypeSymbol.NativeIntegerUnderlyingType.GetPublicSymbol(); #region ISymbol Members diff --git a/src/Compilers/CSharp/Test/Symbol/Symbols/Source/FileModifierTests.cs b/src/Compilers/CSharp/Test/Symbol/Symbols/Source/FileModifierTests.cs index dfc93da7eedfc..be9266768eb8a 100644 --- a/src/Compilers/CSharp/Test/Symbol/Symbols/Source/FileModifierTests.cs +++ b/src/Compilers/CSharp/Test/Symbol/Symbols/Source/FileModifierTests.cs @@ -3245,9 +3245,22 @@ void M(C c) var tree = comp.SyntaxTrees[0]; var model = comp.GetSemanticModel(tree); var node = tree.GetRoot().DescendantNodes().OfType().Single(); - var type = model.GetTypeInfo(node.Type!).Type; + var type = (INamedTypeSymbol)model.GetTypeInfo(node.Type!).Type!; Assert.Equal("C@", type.ToTestDisplayString()); - Assert.Equal(tree, type.GetSymbol()!.AssociatedSyntaxTree); + Assert.Equal(tree, type.GetSymbol()!.AssociatedSyntaxTree); + Assert.True(type.IsFile); + + var referencingMetadataComp = CreateCompilation("", new[] { comp.ToMetadataReference() }); + type = ((Compilation)referencingMetadataComp).GetTypeByMetadataName("<>F0__C")!; + Assert.Equal("C@", type.ToTestDisplayString()); + Assert.Equal(tree, type.GetSymbol()!.AssociatedSyntaxTree); + Assert.True(type.IsFile); + + var referencingImageComp = CreateCompilation("", new[] { comp.EmitToImageReference() }); + type = ((Compilation)referencingImageComp).GetTypeByMetadataName("<>F0__C")!; + Assert.Equal("<>F0__C", type.ToTestDisplayString()); + Assert.Null(type.GetSymbol()!.AssociatedSyntaxTree); + Assert.False(type.IsFile); } [Fact] @@ -3267,9 +3280,10 @@ void M(C c) var tree = comp.SyntaxTrees[0]; var model = comp.GetSemanticModel(tree); var node = tree.GetRoot().DescendantNodes().OfType().Single(); - var type = model.GetTypeInfo(node.Type!).Type; + var type = (INamedTypeSymbol)model.GetTypeInfo(node.Type!).Type!; Assert.Equal("C", type.ToTestDisplayString()); - Assert.Null(type.GetSymbol()!.AssociatedSyntaxTree); + Assert.Null(type.GetSymbol()!.AssociatedSyntaxTree); + Assert.False(type.IsFile); } [Fact] @@ -3289,8 +3303,9 @@ void M(C c) var tree = comp.SyntaxTrees[0]; var model = comp.GetSemanticModel(tree); var node = tree.GetRoot().DescendantNodes().OfType().Single(); - var type = model.GetTypeInfo(node.Type!).Type; + var type = (INamedTypeSymbol)model.GetTypeInfo(node.Type!).Type!; Assert.Equal("C@", type.ToTestDisplayString()); - Assert.Equal(tree, type.GetSymbol()!.AssociatedSyntaxTree); + Assert.Equal(tree, type.GetSymbol()!.AssociatedSyntaxTree); + Assert.True(type.IsFile); } } diff --git a/src/Compilers/Core/Portable/Symbols/INamedTypeSymbol.cs b/src/Compilers/Core/Portable/Symbols/INamedTypeSymbol.cs index 3ba82acb88738..f8fab6b35decf 100644 --- a/src/Compilers/Core/Portable/Symbols/INamedTypeSymbol.cs +++ b/src/Compilers/Core/Portable/Symbols/INamedTypeSymbol.cs @@ -56,6 +56,11 @@ public interface INamedTypeSymbol : ITypeSymbol /// bool IsComImport { get; } + /// + /// Indicates the type is declared in source and is only visible in the file it is declared in. + /// + bool IsFile { get; } + /// /// Returns collection of names of members declared within this type. /// diff --git a/src/Compilers/VisualBasic/Portable/Symbols/NamedTypeSymbol.vb b/src/Compilers/VisualBasic/Portable/Symbols/NamedTypeSymbol.vb index c75ff30f818e3..7d30aafb6182c 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/NamedTypeSymbol.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/NamedTypeSymbol.vb @@ -1216,6 +1216,12 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols End Get End Property + Private ReadOnly Property INamedTypeSymbol_IsFile As Boolean Implements INamedTypeSymbol.IsFile + Get + Return False + End Get + End Property + Private ReadOnly Property INamedTypeSymbol_NativeIntegerUnderlyingType As INamedTypeSymbol Implements INamedTypeSymbol.NativeIntegerUnderlyingType Get Return Nothing diff --git a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/KeywordCompletionProviderTests.cs b/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/KeywordCompletionProviderTests.cs index 5c3d6722ef93b..cfbc1cf8ddd02 100644 --- a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/KeywordCompletionProviderTests.cs +++ b/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/KeywordCompletionProviderTests.cs @@ -684,5 +684,151 @@ class C await VerifyItemIsAbsentAsync(markup, "required"); } + + [Fact] + public async Task SuggestFileOnTypes() + { + var markup = $$""" + $$ class C { } + """; + + await VerifyItemExistsAsync(markup, "file"); + } + + [Fact] + public async Task DoNotSuggestFileAfterFile() + { + var markup = $$""" + file $$ + """; + + await VerifyItemIsAbsentAsync(markup, "file"); + } + + [Fact] + public async Task SuggestFileAfterReadonly() + { + // e.g. 'readonly file struct X { }' + var markup = $$""" + readonly $$ + """; + + await VerifyItemExistsAsync(markup, "file"); + } + + [Fact] + public async Task SuggestFileBeforeFileType() + { + var markup = $$""" + $$ + + file class C { } + """; + + // it might seem like we want to prevent 'file file class', + // but it's likely the user is declaring a file type above an existing file type here. + await VerifyItemExistsAsync(markup, "file"); + } + + [Fact] + public async Task SuggestFileBeforeDelegate() + { + var markup = $$""" + $$ delegate + """; + + await VerifyItemExistsAsync(markup, "file"); + } + + [Fact] + public async Task DoNotSuggestFileOnNestedTypes() + { + var markup = $$""" + class Outer + { + $$ class C { } + } + """; + + await VerifyItemIsAbsentAsync(markup, "file"); + } + + [Fact] + public async Task DoNotSuggestFileOnNonTypeMembers() + { + var markup = $$""" + class C + { + $$ + } + """; + + await VerifyItemIsAbsentAsync(markup, "file"); + } + + [Theory] + [InlineData("public")] + [InlineData("internal")] + [InlineData("protected")] + [InlineData("private")] + public async Task DoNotSuggestFileAfterFilteredKeywords(string keyword) + { + var markup = $$""" + {{keyword}} $$ + """; + + await VerifyItemIsAbsentAsync(markup, "file"); + } + + [Theory] + [InlineData("public")] + [InlineData("internal")] + [InlineData("protected")] + [InlineData("private")] + public async Task DoNotSuggestFilteredKeywordsAfterFile(string keyword) + { + var markup = $$""" + file $$ + """; + + await VerifyItemIsAbsentAsync(markup, keyword); + } + + [Fact] + public async Task SuggestFileInFileScopedNamespace() + { + var markup = $$""" + namespace NS; + + $$ + """; + + await VerifyItemExistsAsync(markup, "file"); + } + + [Fact] + public async Task SuggestFileInNamespace() + { + var markup = $$""" + namespace NS + { + $$ + } + """; + + await VerifyItemExistsAsync(markup, "file"); + } + + [Fact] + public async Task SuggestFileAfterClass() + { + var markup = $$""" + file class C { } + + $$ + """; + + await VerifyItemExistsAsync(markup, "file"); + } } } diff --git a/src/EditorFeatures/CSharpTest/SymbolKey/SymbolKeyCompilationsTests.cs b/src/EditorFeatures/CSharpTest/SymbolKey/SymbolKeyCompilationsTests.cs index 036aecc1b8656..11acb20fafeb1 100644 --- a/src/EditorFeatures/CSharpTest/SymbolKey/SymbolKeyCompilationsTests.cs +++ b/src/EditorFeatures/CSharpTest/SymbolKey/SymbolKeyCompilationsTests.cs @@ -239,6 +239,98 @@ public void M(List list) ResolveAndVerifySymbolList(members1, members2, comp1); } + [Fact] + public void FileType1() + { + var src1 = @"using System; + +namespace N1.N2 +{ + file class C { } +} +"; + var originalComp = CreateCompilation(src1, assemblyName: "Test"); + var newComp = CreateCompilation(src1, assemblyName: "Test"); + + var originalSymbols = GetSourceSymbols(originalComp, SymbolCategory.DeclaredType | SymbolCategory.DeclaredNamespace).OrderBy(s => s.Name).ToArray(); + var newSymbols = GetSourceSymbols(newComp, SymbolCategory.DeclaredType | SymbolCategory.DeclaredNamespace).OrderBy(s => s.Name).ToArray(); + + Assert.Equal(3, originalSymbols.Length); + ResolveAndVerifySymbolList(newSymbols, originalSymbols, originalComp); + } + + [Fact] + public void FileType2() + { + var src1 = @"using System; + +namespace N1.N2 +{ + file class C { } +} +"; + var originalComp = CreateCompilation(src1, assemblyName: "Test"); + var newComp = CreateCompilation(src1, assemblyName: "Test"); + + var originalSymbols = GetSourceSymbols(originalComp, SymbolCategory.DeclaredType | SymbolCategory.DeclaredNamespace).OrderBy(s => s.Name).ToArray(); + var newSymbols = GetSourceSymbols(newComp, SymbolCategory.DeclaredType | SymbolCategory.DeclaredNamespace).OrderBy(s => s.Name).ToArray(); + + Assert.Equal(3, originalSymbols.Length); + ResolveAndVerifySymbolList(newSymbols, originalSymbols, originalComp); + } + + [Fact] + public void FileType3() + { + var src1 = @"using System; + +namespace N1.N2 +{ + file class C { } +} +"; + // this should result in two entirely separate file symbols. + // note that the IDE can only distinguish file type symbols with the same name when they have distinct file paths. + // We are OK with this as we will require file types with identical names to have distinct file paths later in the preview. + // See https://github.com/dotnet/roslyn/issues/61999 + var originalComp = CreateCompilation(new[] { SyntaxFactory.ParseSyntaxTree(src1, path: "file1.cs"), SyntaxFactory.ParseSyntaxTree(src1, path: "file2.cs") }, assemblyName: "Test"); + var newComp = CreateCompilation(new[] { SyntaxFactory.ParseSyntaxTree(src1, path: "file1.cs"), SyntaxFactory.ParseSyntaxTree(src1, path: "file2.cs") }, assemblyName: "Test"); + + var originalSymbols = GetSourceSymbols(originalComp, SymbolCategory.DeclaredType | SymbolCategory.DeclaredNamespace).OrderBy(s => s.Name).ToArray(); + var newSymbols = GetSourceSymbols(newComp, SymbolCategory.DeclaredType | SymbolCategory.DeclaredNamespace).OrderBy(s => s.Name).ToArray(); + + Assert.Equal(4, originalSymbols.Length); + ResolveAndVerifySymbolList(newSymbols, originalSymbols, originalComp); + } + + [Fact] + public void FileType4() + { + // we should be able to distinguish a file type and non-file type when they have the same source name. + var src1 = SyntaxFactory.ParseSyntaxTree(@"using System; + +namespace N1.N2 +{ + file class C { } +} +", path: "File1.cs"); + + var src2 = SyntaxFactory.ParseSyntaxTree(@" +namespace N1.N2 +{ + class C { } +} +", path: "File2.cs"); + var originalComp = CreateCompilation(new[] { src1, src2 }, assemblyName: "Test"); + var newComp = CreateCompilation(new[] { src1, src2 }, assemblyName: "Test"); + + var originalSymbols = GetSourceSymbols(originalComp, SymbolCategory.DeclaredType | SymbolCategory.DeclaredNamespace).OrderBy(s => s.Name).ToArray(); + var newSymbols = GetSourceSymbols(newComp, SymbolCategory.DeclaredType | SymbolCategory.DeclaredNamespace).OrderBy(s => s.Name).ToArray(); + + Assert.Equal(4, originalSymbols.Length); + ResolveAndVerifySymbolList(newSymbols, originalSymbols, originalComp); + } + #endregion #region "Change to symbol" diff --git a/src/EditorFeatures/CSharpTest/SymbolKey/SymbolKeyTests.cs b/src/EditorFeatures/CSharpTest/SymbolKey/SymbolKeyTests.cs index c14e7076089f5..0acc20355cab7 100644 --- a/src/EditorFeatures/CSharpTest/SymbolKey/SymbolKeyTests.cs +++ b/src/EditorFeatures/CSharpTest/SymbolKey/SymbolKeyTests.cs @@ -19,6 +19,111 @@ namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.SymbolId [UseExportProvider] public class SymbolKeyTests { + [Fact] + public async Task FileType_01() + { + var typeSource = @" +file class C1 +{ + public static void M() { } +} +"; + + var workspaceXml = @$" + + + + +{typeSource} + + + +"; + using var workspace = TestWorkspace.Create(workspaceXml); + + var solution = workspace.CurrentSolution; + var project = solution.Projects.Single(); + + var compilation = await project.GetCompilationAsync(); + var type = compilation.GetTypeByMetadataName("F0__C1"); + Assert.NotNull(type); + var symbolKey = SymbolKey.Create(type); + var resolved = symbolKey.Resolve(compilation).Symbol; + Assert.Same(type, resolved); + } + + [Fact] + public async Task FileType_02() + { + var workspaceXml = $$""" + + + + +file class C +{ + public static void M() { } +} + + +file class C +{ + public static void M() { } +} + + + +"""; + using var workspace = TestWorkspace.Create(workspaceXml); + + var solution = workspace.CurrentSolution; + var project = solution.Projects.Single(); + + var compilation = await project.GetCompilationAsync(); + + var type = compilation.GetTypeByMetadataName("F1__C"); + Assert.NotNull(type); + var symbolKey = SymbolKey.Create(type); + var resolved = symbolKey.Resolve(compilation).Symbol; + Assert.Same(type, resolved); + + type = compilation.GetTypeByMetadataName("F0__C"); + Assert.NotNull(type); + symbolKey = SymbolKey.Create(type); + resolved = symbolKey.Resolve(compilation).Symbol; + Assert.Same(type, resolved); + } + + [Fact] + public async Task FileType_03() + { + var workspaceXml = $$""" + + + + +file class C +{ + public class Inner { } +} + + + +"""; + using var workspace = TestWorkspace.Create(workspaceXml); + + var solution = workspace.CurrentSolution; + var project = solution.Projects.Single(); + + var compilation = await project.GetCompilationAsync(); + + var type = compilation.GetTypeByMetadataName("F0__C+Inner"); + Assert.NotNull(type); + var symbolKey = SymbolKey.Create(type); + var resolved = symbolKey.Resolve(compilation).Symbol; + Assert.Same(type, resolved); + } + [Fact, WorkItem(45437, "https://github.com/dotnet/roslyn/issues/45437")] public async Task TestGenericsAndNullability() { diff --git a/src/EditorFeatures/Test/CodeGeneration/CodeGenerationTests.CSharp.cs b/src/EditorFeatures/Test/CodeGeneration/CodeGenerationTests.CSharp.cs index e7706f9195b6b..529e64816b069 100644 --- a/src/EditorFeatures/Test/CodeGeneration/CodeGenerationTests.CSharp.cs +++ b/src/EditorFeatures/Test/CodeGeneration/CodeGenerationTests.CSharp.cs @@ -220,6 +220,59 @@ await TestAddNamedTypeAsync(input, expected, modifiers: new Editing.DeclarationModifiers(isStatic: true)); } + [Fact, Trait(Traits.Feature, Traits.Features.CodeGeneration), WorkItem(544405, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/544405")] + public async Task AddStaticAbstractClass() + { + var input = "namespace [|N|] { }"; + var expected = @"namespace N +{ + public static class C + { + } +}"; + // note that 'abstract' is dropped here + await TestAddNamedTypeAsync(input, expected, + modifiers: new Editing.DeclarationModifiers(isStatic: true, isAbstract: true)); + } + + [Theory, Trait(Traits.Feature, Traits.Features.CodeGeneration), WorkItem(544405, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/544405")] + [InlineData(Accessibility.NotApplicable)] + [InlineData(Accessibility.Internal)] + [InlineData(Accessibility.Public)] + public async Task AddFileClass(Accessibility accessibility) + { + var input = "namespace [|N|] { }"; + var expected = @"namespace N +{ + file class C + { + } +}"; + // note: when invalid combinations of modifiers+accessibility are present here, + // we actually drop the accessibility. This is similar to what is done if someone declares a 'static abstract class C { }'. + await TestAddNamedTypeAsync(input, expected, + accessibility: accessibility, + modifiers: new Editing.DeclarationModifiers(isFile: true)); + } + + [Theory, Trait(Traits.Feature, Traits.Features.CodeGeneration), WorkItem(544405, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/544405")] + [InlineData("struct", TypeKind.Struct)] + [InlineData("interface", TypeKind.Interface)] + [InlineData("enum", TypeKind.Enum)] + public async Task AddFileType(string kindString, TypeKind typeKind) + { + var input = "namespace [|N|] { }"; + var expected = @"namespace N +{ + file " + kindString + @" C + { + } +}"; + await TestAddNamedTypeAsync(input, expected, + typeKind: typeKind, + modifiers: new Editing.DeclarationModifiers(isFile: true)); + } + [Fact, Trait(Traits.Feature, Traits.Features.CodeGeneration), WorkItem(544405, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/544405")] public async Task AddSealedClass() { diff --git a/src/Features/CSharp/Portable/Completion/CompletionProviders/KeywordCompletionProvider.cs b/src/Features/CSharp/Portable/Completion/CompletionProviders/KeywordCompletionProvider.cs index 2c74a4a4cc164..21c022e42f4eb 100644 --- a/src/Features/CSharp/Portable/Completion/CompletionProviders/KeywordCompletionProvider.cs +++ b/src/Features/CSharp/Portable/Completion/CompletionProviders/KeywordCompletionProvider.cs @@ -68,6 +68,7 @@ public KeywordCompletionProvider() new ExternKeywordRecommender(), new FalseKeywordRecommender(), new FieldKeywordRecommender(), + new FileKeywordRecommender(), new FinallyKeywordRecommender(), new FixedKeywordRecommender(), new FloatKeywordRecommender(), diff --git a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/FileKeywordRecommender.cs b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/FileKeywordRecommender.cs new file mode 100644 index 0000000000000..73510f4b46dd1 --- /dev/null +++ b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/FileKeywordRecommender.cs @@ -0,0 +1,30 @@ +// 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.Collections.Generic; +using System.Linq; +using System.Threading; +using Microsoft.CodeAnalysis.CSharp.Extensions.ContextQuery; +using Microsoft.CodeAnalysis.CSharp.Utilities; +using Roslyn.Utilities; + +namespace Microsoft.CodeAnalysis.CSharp.Completion.KeywordRecommenders; + +internal class FileKeywordRecommender : AbstractSyntacticSingleKeywordRecommender +{ + private static readonly ISet s_validModifiers = SyntaxKindSet.AllMemberModifiers + .Where(s => s != SyntaxKind.FileKeyword && !SyntaxFacts.IsAccessibilityModifier(s)) + .ToSet(); + + public FileKeywordRecommender() + : base(SyntaxKind.FileKeyword) + { + } + + protected override bool IsValidContext(int position, CSharpSyntaxContext context, CancellationToken cancellationToken) + { + return context.ContainingTypeDeclaration == null + && context.IsTypeDeclarationContext(s_validModifiers, SyntaxKindSet.AllTypeDeclarations, canBePartial: true, cancellationToken); + } +} diff --git a/src/Features/Core/Portable/MetadataAsSource/AbstractMetadataAsSourceService.WrappedNamedTypeSymbol.cs b/src/Features/Core/Portable/MetadataAsSource/AbstractMetadataAsSourceService.WrappedNamedTypeSymbol.cs index 8439fc7c3bd27..cb8972561e3ef 100644 --- a/src/Features/Core/Portable/MetadataAsSource/AbstractMetadataAsSourceService.WrappedNamedTypeSymbol.cs +++ b/src/Features/Core/Portable/MetadataAsSource/AbstractMetadataAsSourceService.WrappedNamedTypeSymbol.cs @@ -144,6 +144,8 @@ public ImmutableArray ToMinimalDisplayParts(SemanticModel sem public bool IsNativeIntegerType => _symbol.IsNativeIntegerType; + public bool IsFile => _symbol.IsFile; + public INamedTypeSymbol NativeIntegerUnderlyingType => _symbol.NativeIntegerUnderlyingType; NullableAnnotation ITypeSymbol.NullableAnnotation => throw new NotImplementedException(); diff --git a/src/Workspaces/CSharp/Portable/CodeGeneration/CSharpSyntaxGenerator.cs b/src/Workspaces/CSharp/Portable/CodeGeneration/CSharpSyntaxGenerator.cs index 7e32e605a28e3..3ba8fffee3e30 100644 --- a/src/Workspaces/CSharp/Portable/CodeGeneration/CSharpSyntaxGenerator.cs +++ b/src/Workspaces/CSharp/Portable/CodeGeneration/CSharpSyntaxGenerator.cs @@ -1447,23 +1447,26 @@ public override SyntaxNode WithAccessibility(SyntaxNode declaration, Accessibili DeclarationModifiers.Partial | DeclarationModifiers.Sealed | DeclarationModifiers.Static | - DeclarationModifiers.Unsafe; + DeclarationModifiers.Unsafe | + DeclarationModifiers.File; private static readonly DeclarationModifiers s_recordModifiers = DeclarationModifiers.Abstract | DeclarationModifiers.New | DeclarationModifiers.Partial | DeclarationModifiers.Sealed | - DeclarationModifiers.Unsafe; + DeclarationModifiers.Unsafe | + DeclarationModifiers.File; private static readonly DeclarationModifiers s_structModifiers = DeclarationModifiers.New | DeclarationModifiers.Partial | DeclarationModifiers.ReadOnly | DeclarationModifiers.Ref | - DeclarationModifiers.Unsafe; + DeclarationModifiers.Unsafe | + DeclarationModifiers.File; - private static readonly DeclarationModifiers s_interfaceModifiers = DeclarationModifiers.New | DeclarationModifiers.Partial | DeclarationModifiers.Unsafe; + private static readonly DeclarationModifiers s_interfaceModifiers = DeclarationModifiers.New | DeclarationModifiers.Partial | DeclarationModifiers.Unsafe | DeclarationModifiers.File; private static readonly DeclarationModifiers s_accessorModifiers = DeclarationModifiers.Abstract | DeclarationModifiers.New | DeclarationModifiers.Override | DeclarationModifiers.Virtual; private static readonly DeclarationModifiers s_localFunctionModifiers = @@ -1486,10 +1489,10 @@ private static DeclarationModifiers GetAllowedModifiers(SyntaxKind kind) return s_classModifiers; case SyntaxKind.EnumDeclaration: - return DeclarationModifiers.New; + return DeclarationModifiers.New | DeclarationModifiers.File; case SyntaxKind.DelegateDeclaration: - return DeclarationModifiers.New | DeclarationModifiers.Unsafe; + return DeclarationModifiers.New | DeclarationModifiers.Unsafe | DeclarationModifiers.File; case SyntaxKind.InterfaceDeclaration: return s_interfaceModifiers; diff --git a/src/Workspaces/CSharp/Portable/CodeGeneration/NamedTypeGenerator.cs b/src/Workspaces/CSharp/Portable/CodeGeneration/NamedTypeGenerator.cs index 41249624471d0..941fef327976a 100644 --- a/src/Workspaces/CSharp/Portable/CodeGeneration/NamedTypeGenerator.cs +++ b/src/Workspaces/CSharp/Portable/CodeGeneration/NamedTypeGenerator.cs @@ -267,11 +267,17 @@ private static SyntaxTokenList GenerateModifiers( { var tokens = ArrayBuilder.GetInstance(); - var defaultAccessibility = destination is CodeGenerationDestination.CompilationUnit or CodeGenerationDestination.Namespace - ? Accessibility.Internal - : Accessibility.Private; - - AddAccessibilityModifiers(namedType.DeclaredAccessibility, tokens, info, defaultAccessibility); + if (!namedType.IsFile) + { + var defaultAccessibility = destination is CodeGenerationDestination.CompilationUnit or CodeGenerationDestination.Namespace + ? Accessibility.Internal + : Accessibility.Private; + AddAccessibilityModifiers(namedType.DeclaredAccessibility, tokens, info, defaultAccessibility); + } + else + { + tokens.Add(SyntaxFactory.Token(SyntaxKind.FileKeyword)); + } if (namedType.IsStatic) { diff --git a/src/Workspaces/Core/Portable/CodeGeneration/Symbols/CodeGenerationAbstractNamedTypeSymbol.cs b/src/Workspaces/Core/Portable/CodeGeneration/Symbols/CodeGenerationAbstractNamedTypeSymbol.cs index ba6e428ebc76f..bc12ff16bfbe4 100644 --- a/src/Workspaces/Core/Portable/CodeGeneration/Symbols/CodeGenerationAbstractNamedTypeSymbol.cs +++ b/src/Workspaces/Core/Portable/CodeGeneration/Symbols/CodeGenerationAbstractNamedTypeSymbol.cs @@ -121,5 +121,7 @@ public override string MetadataName public INamedTypeSymbol TupleUnderlyingType => null; public bool IsSerializable => false; + + public bool IsFile => Modifiers.IsFile; } } diff --git a/src/Workspaces/Core/Portable/Editing/DeclarationModifiers.cs b/src/Workspaces/Core/Portable/Editing/DeclarationModifiers.cs index df4f81dd1d41e..b53d401c8b683 100644 --- a/src/Workspaces/Core/Portable/Editing/DeclarationModifiers.cs +++ b/src/Workspaces/Core/Portable/Editing/DeclarationModifiers.cs @@ -38,7 +38,8 @@ internal DeclarationModifiers( bool isRef = false, bool isVolatile = false, bool isExtern = false, - bool isRequired = false) + bool isRequired = false, + bool isFile = false) : this( (isStatic ? Modifiers.Static : Modifiers.None) | (isAbstract ? Modifiers.Abstract : Modifiers.None) | @@ -56,7 +57,8 @@ internal DeclarationModifiers( (isRef ? Modifiers.Ref : Modifiers.None) | (isVolatile ? Modifiers.Volatile : Modifiers.None) | (isExtern ? Modifiers.Extern : Modifiers.None) | - (isRequired ? Modifiers.Required : Modifiers.None)) + (isRequired ? Modifiers.Required : Modifiers.None) | + (isFile ? Modifiers.File : Modifiers.None)) { } @@ -84,7 +86,8 @@ IMethodSymbol or isVolatile: field?.IsVolatile == true, isExtern: symbol.IsExtern, isAsync: method?.IsAsync == true, - isRequired: symbol.IsRequired()); + isRequired: symbol.IsRequired(), + isFile: (symbol as INamedTypeSymbol)?.IsFile == true); } // Only named types, members of named types, and local functions have modifiers. @@ -126,6 +129,8 @@ IMethodSymbol or public bool IsRequired => (_modifiers & Modifiers.Required) != 0; + public bool IsFile => (_modifiers & Modifiers.File) != 0; + public DeclarationModifiers WithIsStatic(bool isStatic) => new(SetFlag(_modifiers, Modifiers.Static, isStatic)); @@ -178,6 +183,9 @@ public DeclarationModifiers WithIsExtern(bool isExtern) public DeclarationModifiers WithIsRequired(bool isRequired) => new(SetFlag(_modifiers, Modifiers.Required, isRequired)); + public DeclarationModifiers WithIsFile(bool isFile) + => new(SetFlag(_modifiers, Modifiers.File, isFile)); + private static Modifiers SetFlag(Modifiers existing, Modifiers modifier, bool isSet) => isSet ? (existing | modifier) : (existing & ~modifier); @@ -203,6 +211,7 @@ private enum Modifiers Volatile = 1 << 14, Extern = 1 << 15, Required = 1 << 16, + File = 1 << 17, #pragma warning restore format } @@ -225,6 +234,7 @@ private enum Modifiers public static DeclarationModifiers Volatile => new(Modifiers.Volatile); public static DeclarationModifiers Extern => new(Modifiers.Extern); public static DeclarationModifiers Required => new(Modifiers.Required); + public static DeclarationModifiers File => new(Modifiers.File); public static DeclarationModifiers operator |(DeclarationModifiers left, DeclarationModifiers right) => new(left._modifiers | right._modifiers); diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/SymbolKey/SymbolKey.NamedTypeSymbolKey.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/SymbolKey/SymbolKey.NamedTypeSymbolKey.cs index f45f66bdfe248..6b0fee736cd1e 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/SymbolKey/SymbolKey.NamedTypeSymbolKey.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/SymbolKey/SymbolKey.NamedTypeSymbolKey.cs @@ -16,6 +16,9 @@ public static void Create(INamedTypeSymbol symbol, SymbolKeyWriter visitor) visitor.WriteSymbolKey(symbol.ContainingSymbol); visitor.WriteString(symbol.Name); visitor.WriteInteger(symbol.Arity); + visitor.WriteString(symbol.IsFile + ? symbol.DeclaringSyntaxReferences[0].SyntaxTree.FilePath + : null); visitor.WriteBoolean(symbol.IsUnboundGenericType); if (!symbol.Equals(symbol.ConstructedFrom) && !symbol.IsUnboundGenericType) @@ -33,7 +36,9 @@ public static SymbolKeyResolution Resolve(SymbolKeyReader reader, out string? fa var containingSymbolResolution = reader.ReadSymbolKey(out var containingSymbolFailureReason); var name = reader.ReadRequiredString(); var arity = reader.ReadInteger(); + var filePath = reader.ReadString(); var isUnboundGenericType = reader.ReadBoolean(); + using var typeArguments = reader.ReadSymbolKeyArray(out var typeArgumentsFailureReason); if (containingSymbolFailureReason != null) @@ -61,7 +66,7 @@ public static SymbolKeyResolution Resolve(SymbolKeyReader reader, out string? fa foreach (var nsOrType in containingSymbolResolution.OfType()) { Resolve( - result, nsOrType, name, arity, + result, nsOrType, name, arity, filePath, isUnboundGenericType, typeArgumentArray); } @@ -73,11 +78,28 @@ private static void Resolve( INamespaceOrTypeSymbol container, string name, int arity, + string? filePath, bool isUnboundGenericType, ITypeSymbol[] typeArguments) { foreach (var type in container.GetTypeMembers(name, arity)) { + // if this is a 'file' type, then only resolve to a file-type from this same file + if (filePath != null) + { + if (!type.IsFile || + // note: if we found 'IsFile' returned true, we can assume DeclaringSyntaxReferences is non-empty. + type.DeclaringSyntaxReferences[0].SyntaxTree.FilePath != filePath) + { + continue; + } + } + else if (type.IsFile) + { + // since this key lacks a file path it can't match against a 'file' type + continue; + } + var currentType = typeArguments.Length > 0 ? type.Construct(typeArguments) : type; currentType = isUnboundGenericType ? currentType.ConstructUnboundGenericType() : currentType; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/SymbolKey/SymbolKey.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/SymbolKey/SymbolKey.cs index e30a325b2c17b..ad6fe979a4fa9 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/SymbolKey/SymbolKey.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/SymbolKey/SymbolKey.cs @@ -109,7 +109,7 @@ internal partial struct SymbolKey : IEquatable /// out a SymbolKey from a previous version of Roslyn and then attempt to use it in a /// newer version where the encoding has changed. /// - internal const int FormatVersion = 2; + internal const int FormatVersion = 3; [DataMember(Order = 0)] private readonly string _symbolKeyData; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/Utilities/SyntaxKindSet.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/Utilities/SyntaxKindSet.cs index 132a1de02a285..17444004886c8 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/Utilities/SyntaxKindSet.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/Utilities/SyntaxKindSet.cs @@ -14,6 +14,7 @@ internal class SyntaxKindSet public static readonly ISet AllTypeModifiers = new HashSet(SyntaxFacts.EqualityComparer) { SyntaxKind.AbstractKeyword, + SyntaxKind.FileKeyword, SyntaxKind.InternalKeyword, SyntaxKind.NewKeyword, SyntaxKind.PublicKeyword, From 730e0d64f35a8d5e36b56ef456c34405f71cf93e Mon Sep 17 00:00:00 2001 From: Rikki Gibson Date: Tue, 5 Jul 2022 11:24:21 -0700 Subject: [PATCH 10/11] Address prototype comments in file types branch (#62335) --- .../Compiler Breaking Changes - DotNet 7.md | 15 +- docs/contributing/Compiler Test Plan.md | 1 + eng/config/globalconfigs/Common.globalconfig | 2 +- .../Core/Analyzers/PublicAPI.Unshipped.txt | 3 + .../CSharp/Portable/Binder/Binder_Symbols.cs | 3 +- .../Portable/Binder/BuckStopsHereBinder.cs | 2 +- .../CSharp/Portable/CSharpResources.resx | 3 + ...ilation.UsingsFromOptionsAndDiagnostics.cs | 2 - .../CSharp/Portable/Errors/ErrorCode.cs | 12 +- .../CSharp/Portable/Errors/MessageID.cs | 2 +- .../CSharp/Portable/Parser/LanguageParser.cs | 2 +- .../CSharp/Portable/PublicAPI.Unshipped.txt | 1 + .../Source/SourceMemberContainerSymbol.cs | 6 +- .../Symbols/Source/SourcePropertySymbol.cs | 1 - .../Portable/xlf/CSharpResources.cs.xlf | 5 + .../Portable/xlf/CSharpResources.de.xlf | 5 + .../Portable/xlf/CSharpResources.es.xlf | 5 + .../Portable/xlf/CSharpResources.fr.xlf | 5 + .../Portable/xlf/CSharpResources.it.xlf | 5 + .../Portable/xlf/CSharpResources.ja.xlf | 5 + .../Portable/xlf/CSharpResources.ko.xlf | 5 + .../Portable/xlf/CSharpResources.pl.xlf | 5 + .../Portable/xlf/CSharpResources.pt-BR.xlf | 5 + .../Portable/xlf/CSharpResources.ru.xlf | 5 + .../Portable/xlf/CSharpResources.tr.xlf | 5 + .../Portable/xlf/CSharpResources.zh-Hans.xlf | 5 + .../Portable/xlf/CSharpResources.zh-Hant.xlf | 5 + .../Symbols/Source/FileModifierTests.cs | 131 +++--- .../Parsing/FileModifierParsingTests.cs | 394 ++++++++++++------ .../Core/Portable/PublicAPI.Unshipped.txt | 3 +- .../Binders/EEMethodBinder.cs | 2 +- .../ExpressionCompiler/CompilationContext.cs | 2 +- .../Core/Portable/PublicAPI.Unshipped.txt | 3 + 33 files changed, 451 insertions(+), 204 deletions(-) diff --git a/docs/compilers/CSharp/Compiler Breaking Changes - DotNet 7.md b/docs/compilers/CSharp/Compiler Breaking Changes - DotNet 7.md index 85417b7843492..4f99b63cec964 100644 --- a/docs/compilers/CSharp/Compiler Breaking Changes - DotNet 7.md +++ b/docs/compilers/CSharp/Compiler Breaking Changes - DotNet 7.md @@ -1,5 +1,18 @@ # This document lists known breaking changes in Roslyn after .NET 6 all the way to .NET 7. +## Types cannot be named `file` + +***Introduced in Visual Studio 2022 version 17.4.*** Starting in C# 11, types cannot be named `file`. The compiler will report an error on all such type names. To work around this, the type name and all usages must be escaped with an `@`: + +```csharp +class file {} // Error CS9056 +class @file {} // No error +``` + +This was done as `file` is now a modifier for type declarations. + +You can learn more about this change in the associated [csharplang issue](https://github.com/dotnet/csharplang/issues/6011). + ## Required spaces in #line span directives ***Introduced in .NET SDK 6.0.400, Visual Studio 2022 version 17.3.*** @@ -426,4 +439,4 @@ class @required {} // No error This was done as `required` is now a member modifier for properties and fields. -You can learn more about this change in the associated [csharplang issue](https://github.com/dotnet/csharplang/issues/3630). +You can learn more about this change in the associated [csharplang issue](https://github.com/dotnet/csharplang/issues/3630). \ No newline at end of file diff --git a/docs/contributing/Compiler Test Plan.md b/docs/contributing/Compiler Test Plan.md index f287fc02e3f49..a3d0b6b4f463a 100644 --- a/docs/contributing/Compiler Test Plan.md +++ b/docs/contributing/Compiler Test Plan.md @@ -38,6 +38,7 @@ This document provides guidance for thinking about language interactions and tes # Type and members - Access modifiers (public, protected, internal, protected internal, private protected, private), static, ref - type declarations (class, record class/struct with or without positional members, struct, interface, type parameter) +- file-local types - methods - fields (required and not) - properties (including get/set/init accessors, required and not) diff --git a/eng/config/globalconfigs/Common.globalconfig b/eng/config/globalconfigs/Common.globalconfig index 1766acf873729..b3339efbab8ce 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 = none # PROTOTYPE(ft): re-enable before feature merge +dotnet_diagnostic.RS0016.severity = error dotnet_diagnostic.RS0017.severity = error dotnet_diagnostic.RS0018.severity = warning dotnet_diagnostic.RS0022.severity = error diff --git a/src/CodeStyle/Core/Analyzers/PublicAPI.Unshipped.txt b/src/CodeStyle/Core/Analyzers/PublicAPI.Unshipped.txt index 691883be01a72..4c8f5c4788aaa 100644 --- a/src/CodeStyle/Core/Analyzers/PublicAPI.Unshipped.txt +++ b/src/CodeStyle/Core/Analyzers/PublicAPI.Unshipped.txt @@ -42,6 +42,7 @@ Microsoft.CodeAnalysis.Internal.Editing.DeclarationModifiers.IsPartial.get -> bo Microsoft.CodeAnalysis.Internal.Editing.DeclarationModifiers.IsReadOnly.get -> bool Microsoft.CodeAnalysis.Internal.Editing.DeclarationModifiers.IsRef.get -> bool Microsoft.CodeAnalysis.Internal.Editing.DeclarationModifiers.IsRequired.get -> bool +Microsoft.CodeAnalysis.Internal.Editing.DeclarationModifiers.IsFile.get -> bool Microsoft.CodeAnalysis.Internal.Editing.DeclarationModifiers.IsSealed.get -> bool Microsoft.CodeAnalysis.Internal.Editing.DeclarationModifiers.IsStatic.get -> bool Microsoft.CodeAnalysis.Internal.Editing.DeclarationModifiers.IsUnsafe.get -> bool @@ -58,6 +59,7 @@ Microsoft.CodeAnalysis.Internal.Editing.DeclarationModifiers.WithIsOverride(bool Microsoft.CodeAnalysis.Internal.Editing.DeclarationModifiers.WithIsReadOnly(bool isReadOnly) -> Microsoft.CodeAnalysis.Internal.Editing.DeclarationModifiers Microsoft.CodeAnalysis.Internal.Editing.DeclarationModifiers.WithIsRef(bool isRef) -> Microsoft.CodeAnalysis.Internal.Editing.DeclarationModifiers Microsoft.CodeAnalysis.Internal.Editing.DeclarationModifiers.WithIsRequired(bool isRequired) -> Microsoft.CodeAnalysis.Internal.Editing.DeclarationModifiers +Microsoft.CodeAnalysis.Internal.Editing.DeclarationModifiers.WithIsFile(bool isFile) -> Microsoft.CodeAnalysis.Internal.Editing.DeclarationModifiers Microsoft.CodeAnalysis.Internal.Editing.DeclarationModifiers.WithIsSealed(bool isSealed) -> Microsoft.CodeAnalysis.Internal.Editing.DeclarationModifiers Microsoft.CodeAnalysis.Internal.Editing.DeclarationModifiers.WithIsStatic(bool isStatic) -> Microsoft.CodeAnalysis.Internal.Editing.DeclarationModifiers Microsoft.CodeAnalysis.Internal.Editing.DeclarationModifiers.WithIsUnsafe(bool isUnsafe) -> Microsoft.CodeAnalysis.Internal.Editing.DeclarationModifiers @@ -87,6 +89,7 @@ static Microsoft.CodeAnalysis.Internal.Editing.DeclarationModifiers.Partial.get static Microsoft.CodeAnalysis.Internal.Editing.DeclarationModifiers.ReadOnly.get -> Microsoft.CodeAnalysis.Internal.Editing.DeclarationModifiers static Microsoft.CodeAnalysis.Internal.Editing.DeclarationModifiers.Ref.get -> Microsoft.CodeAnalysis.Internal.Editing.DeclarationModifiers static Microsoft.CodeAnalysis.Internal.Editing.DeclarationModifiers.Required.get -> Microsoft.CodeAnalysis.Internal.Editing.DeclarationModifiers +static Microsoft.CodeAnalysis.Internal.Editing.DeclarationModifiers.File.get -> Microsoft.CodeAnalysis.Internal.Editing.DeclarationModifiers static Microsoft.CodeAnalysis.Internal.Editing.DeclarationModifiers.Sealed.get -> Microsoft.CodeAnalysis.Internal.Editing.DeclarationModifiers static Microsoft.CodeAnalysis.Internal.Editing.DeclarationModifiers.Static.get -> Microsoft.CodeAnalysis.Internal.Editing.DeclarationModifiers static Microsoft.CodeAnalysis.Internal.Editing.DeclarationModifiers.TryParse(string value, out Microsoft.CodeAnalysis.Internal.Editing.DeclarationModifiers modifiers) -> bool diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Symbols.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Symbols.cs index 9c977c755319c..ee5c62da9ec38 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder_Symbols.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder_Symbols.cs @@ -1819,7 +1819,8 @@ Symbol resultSymbol( if (best.IsFromFile && !secondBest.IsFromFile) { // a lookup of a file type is "better" than a lookup of a non-file type; no need to further diagnose - // PROTOTYPE(ft): some "single symbol" diagnostics are missed here for similar reasons + // https://github.com/dotnet/roslyn/issues/62331 + // some "single symbol" diagnostics are missed here for similar reasons // that make us miss diagnostics when reporting WRN_SameFullNameThisAggAgg. // return first; diff --git a/src/Compilers/CSharp/Portable/Binder/BuckStopsHereBinder.cs b/src/Compilers/CSharp/Portable/Binder/BuckStopsHereBinder.cs index 90d184f2eed49..caa0df8490196 100644 --- a/src/Compilers/CSharp/Portable/Binder/BuckStopsHereBinder.cs +++ b/src/Compilers/CSharp/Portable/Binder/BuckStopsHereBinder.cs @@ -26,7 +26,7 @@ internal BuckStopsHereBinder(CSharpCompilation compilation, SyntaxTree? associat /// In speculative scenarios, the syntax tree from the original compilation used as the speculation context. /// This is in some scenarios, such as the binder used for /// or the binder used to bind usings in . - /// PROTOTYPE(ft): what about in EE scenarios? + /// https://github.com/dotnet/roslyn/issues/62332: what about in EE scenarios? /// internal readonly SyntaxTree? AssociatedSyntaxTree; diff --git a/src/Compilers/CSharp/Portable/CSharpResources.resx b/src/Compilers/CSharp/Portable/CSharpResources.resx index 58de8f3365ebf..e07d03a21ee8c 100644 --- a/src/Compilers/CSharp/Portable/CSharpResources.resx +++ b/src/Compilers/CSharp/Portable/CSharpResources.resx @@ -7139,6 +7139,9 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ File type '{0}' cannot be used in a 'global using static' directive. + + Types and aliases cannot be named 'file'. + unsigned right shift diff --git a/src/Compilers/CSharp/Portable/Compilation/CSharpCompilation.UsingsFromOptionsAndDiagnostics.cs b/src/Compilers/CSharp/Portable/Compilation/CSharpCompilation.UsingsFromOptionsAndDiagnostics.cs index 6068c3d3b99ca..09f02a1f032e3 100644 --- a/src/Compilers/CSharp/Portable/Compilation/CSharpCompilation.UsingsFromOptionsAndDiagnostics.cs +++ b/src/Compilers/CSharp/Portable/Compilation/CSharpCompilation.UsingsFromOptionsAndDiagnostics.cs @@ -34,8 +34,6 @@ public static UsingsFromOptionsAndDiagnostics FromOptions(CSharpCompilation comp } var diagnostics = new DiagnosticBag(); - // PROTOTYPE(ft): should usings from compilation options be allowed to bring file types into scope? - // it doesn't seem to work for non-file types within the compilaton, so can probably do the same for file types. var usingsBinder = new InContainerBinder(compilation.GlobalNamespace, new BuckStopsHereBinder(compilation, associatedSyntaxTree: null)); var boundUsings = ArrayBuilder.GetInstance(); var uniqueUsings = PooledHashSet.GetInstance(); diff --git a/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs b/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs index b33845e5d07ee..f5c0e9941c3d1 100644 --- a/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs +++ b/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs @@ -2099,12 +2099,12 @@ internal enum ErrorCode ERR_FixedFieldMustNotBeRef = 9049, ERR_RefFieldCannotReferToRefStruct = 9050, - // PROTOTYPE(ft): compress these before feature merge - ERR_FileTypeDisallowedInSignature = 9300, - ERR_FileTypeNoExplicitAccessibility = 9301, - ERR_FileTypeBase = 9302, - ERR_FileTypeNested = 9303, - ERR_GlobalUsingStaticFileType = 9304 + ERR_FileTypeDisallowedInSignature = 9051, + ERR_FileTypeNoExplicitAccessibility = 9052, + ERR_FileTypeBase = 9053, + ERR_FileTypeNested = 9054, + ERR_GlobalUsingStaticFileType = 9055, + ERR_FileTypeNameDisallowed = 9056, #endregion diff --git a/src/Compilers/CSharp/Portable/Errors/MessageID.cs b/src/Compilers/CSharp/Portable/Errors/MessageID.cs index 6e171c1298ea1..0cb52e6c2fea5 100644 --- a/src/Compilers/CSharp/Portable/Errors/MessageID.cs +++ b/src/Compilers/CSharp/Portable/Errors/MessageID.cs @@ -257,7 +257,7 @@ internal enum MessageID IDS_FeatureRelaxedShiftOperator = MessageBase + 12825, IDS_FeatureRequiredMembers = MessageBase + 12826, IDS_FeatureRefFields = MessageBase + 12827, - IDS_FeatureFileTypes = MessageBase + 12850, // PROTOTYPE(ft): pack ID before merge + IDS_FeatureFileTypes = MessageBase + 12828, } // Message IDs may refer to strings that need to be localized. diff --git a/src/Compilers/CSharp/Portable/Parser/LanguageParser.cs b/src/Compilers/CSharp/Portable/Parser/LanguageParser.cs index 565b4ba4cbcfc..b16fda396c9e7 100644 --- a/src/Compilers/CSharp/Portable/Parser/LanguageParser.cs +++ b/src/Compilers/CSharp/Portable/Parser/LanguageParser.cs @@ -1251,7 +1251,7 @@ private void ParseModifiers(SyntaxListBuilder tokens, bool forAccessors, bool fo } case DeclarationModifiers.File: - if (!IsFeatureEnabled(MessageID.IDS_FeatureFileTypes) && !ShouldContextualKeywordBeTreatedAsModifier(parsingStatementNotDeclaration: false)) + if ((!IsFeatureEnabled(MessageID.IDS_FeatureFileTypes) || forTopLevelStatements) && !ShouldContextualKeywordBeTreatedAsModifier(parsingStatementNotDeclaration: false)) { return; } diff --git a/src/Compilers/CSharp/Portable/PublicAPI.Unshipped.txt b/src/Compilers/CSharp/Portable/PublicAPI.Unshipped.txt index 623654949ba86..bfbee81018f48 100644 --- a/src/Compilers/CSharp/Portable/PublicAPI.Unshipped.txt +++ b/src/Compilers/CSharp/Portable/PublicAPI.Unshipped.txt @@ -5,6 +5,7 @@ Microsoft.CodeAnalysis.CSharp.SyntaxKind.InterpolatedSingleLineRawStringStartTok Microsoft.CodeAnalysis.CSharp.SyntaxKind.MultiLineRawStringLiteralToken = 8519 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind Microsoft.CodeAnalysis.CSharp.SyntaxKind.RequiredKeyword = 8447 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind Microsoft.CodeAnalysis.CSharp.SyntaxKind.ScopedKeyword = 8448 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind +Microsoft.CodeAnalysis.CSharp.SyntaxKind.FileKeyword = 8449 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind Microsoft.CodeAnalysis.CSharp.SyntaxKind.SingleLineRawStringLiteralToken = 8518 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.ConstructorDeclaration(Microsoft.CodeAnalysis.SyntaxList attributeLists, Microsoft.CodeAnalysis.SyntaxTokenList modifiers, Microsoft.CodeAnalysis.SyntaxToken identifier, Microsoft.CodeAnalysis.CSharp.Syntax.ParameterListSyntax! parameterList, Microsoft.CodeAnalysis.CSharp.Syntax.ConstructorInitializerSyntax? initializer, Microsoft.CodeAnalysis.CSharp.Syntax.BlockSyntax! body) -> Microsoft.CodeAnalysis.CSharp.Syntax.ConstructorDeclarationSyntax! *REMOVED*static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.ConstructorDeclaration(Microsoft.CodeAnalysis.SyntaxList attributeLists, Microsoft.CodeAnalysis.SyntaxTokenList modifiers, Microsoft.CodeAnalysis.SyntaxToken identifier, Microsoft.CodeAnalysis.CSharp.Syntax.ParameterListSyntax! parameterList, Microsoft.CodeAnalysis.CSharp.Syntax.ConstructorInitializerSyntax! initializer, Microsoft.CodeAnalysis.CSharp.Syntax.BlockSyntax! body) -> Microsoft.CodeAnalysis.CSharp.Syntax.ConstructorDeclarationSyntax! diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberContainerSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberContainerSymbol.cs index 2accc178cd4f6..eb9c4c3be96b4 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberContainerSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberContainerSymbol.cs @@ -274,7 +274,8 @@ private DeclarationModifiers MakeModifiers(TypeKind typeKind, BindingDiagnosticB { Symbol containingSymbol = this.ContainingSymbol; DeclarationModifiers defaultAccess; - // PROTOTYPE(ft): confirm whether 'file' types can be nested + + // note: we give a specific diagnostic when a file type is nested var allowedModifiers = DeclarationModifiers.AccessibilityMask | DeclarationModifiers.File; if (containingSymbol.Kind == SymbolKind.Namespace) @@ -476,7 +477,8 @@ internal static void ReportReservedTypeName(string? name, CSharpCompilation comp } if (reportIfContextual(SyntaxKind.RecordKeyword, MessageID.IDS_FeatureRecords, ErrorCode.WRN_RecordNamedDisallowed) - || reportIfContextual(SyntaxKind.RequiredKeyword, MessageID.IDS_FeatureRequiredMembers, ErrorCode.ERR_RequiredNameDisallowed)) + || reportIfContextual(SyntaxKind.RequiredKeyword, MessageID.IDS_FeatureRequiredMembers, ErrorCode.ERR_RequiredNameDisallowed) + || reportIfContextual(SyntaxKind.FileKeyword, MessageID.IDS_FeatureFileTypes, ErrorCode.ERR_FileTypeNameDisallowed)) { return; } diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertySymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertySymbol.cs index 0a020a570ea52..781b6bac6a5c7 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertySymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertySymbol.cs @@ -453,7 +453,6 @@ private TypeWithAnnotations ComputeType(Binder binder, SyntaxNode syntax, Bindin if (type.Type.IsFileTypeOrUsesFileTypes() && !ContainingType.IsFileTypeOrUsesFileTypes()) { - // PROTOTYPE(ft): should explicit interface implementations be allowed to use file types in signatures? diagnostics.Add(ErrorCode.ERR_FileTypeDisallowedInSignature, Location, type.Type, ContainingType); } diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf index 1b1deec2d407e..5e39ad0819175 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf @@ -592,6 +592,11 @@ File type '{0}' cannot be used in a member signature in non-file type '{1}'. + + Types and aliases cannot be named 'file'. + Types and aliases cannot be named 'file'. + + File type '{0}' must be defined in a top level type; '{0}' is a nested type. File type '{0}' must be defined in a top level type; '{0}' is a nested type. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf index 11750c3594d54..d85bca7010f4c 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf @@ -592,6 +592,11 @@ File type '{0}' cannot be used in a member signature in non-file type '{1}'. + + Types and aliases cannot be named 'file'. + Types and aliases cannot be named 'file'. + + File type '{0}' must be defined in a top level type; '{0}' is a nested type. File type '{0}' must be defined in a top level type; '{0}' is a nested type. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf index 1b2696dcd9286..5bda9f5c4481f 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf @@ -592,6 +592,11 @@ File type '{0}' cannot be used in a member signature in non-file type '{1}'. + + Types and aliases cannot be named 'file'. + Types and aliases cannot be named 'file'. + + File type '{0}' must be defined in a top level type; '{0}' is a nested type. File type '{0}' must be defined in a top level type; '{0}' is a nested type. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf index 934be541f7460..6d8f3c6681898 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf @@ -592,6 +592,11 @@ File type '{0}' cannot be used in a member signature in non-file type '{1}'. + + Types and aliases cannot be named 'file'. + Types and aliases cannot be named 'file'. + + File type '{0}' must be defined in a top level type; '{0}' is a nested type. File type '{0}' must be defined in a top level type; '{0}' is a nested type. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf index aa5b8ade54759..ca711e6b4ba31 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf @@ -592,6 +592,11 @@ File type '{0}' cannot be used in a member signature in non-file type '{1}'. + + Types and aliases cannot be named 'file'. + Types and aliases cannot be named 'file'. + + File type '{0}' must be defined in a top level type; '{0}' is a nested type. File type '{0}' must be defined in a top level type; '{0}' is a nested type. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf index 437eefdfec647..5b05461c673de 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf @@ -592,6 +592,11 @@ File type '{0}' cannot be used in a member signature in non-file type '{1}'. + + Types and aliases cannot be named 'file'. + Types and aliases cannot be named 'file'. + + File type '{0}' must be defined in a top level type; '{0}' is a nested type. File type '{0}' must be defined in a top level type; '{0}' is a nested type. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf index 54cc83d5cc26f..dfa5c51e9556a 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf @@ -592,6 +592,11 @@ File type '{0}' cannot be used in a member signature in non-file type '{1}'. + + Types and aliases cannot be named 'file'. + Types and aliases cannot be named 'file'. + + File type '{0}' must be defined in a top level type; '{0}' is a nested type. File type '{0}' must be defined in a top level type; '{0}' is a nested type. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf index 09b88470e3dba..0c0d0fefb9c9b 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf @@ -592,6 +592,11 @@ File type '{0}' cannot be used in a member signature in non-file type '{1}'. + + Types and aliases cannot be named 'file'. + Types and aliases cannot be named 'file'. + + File type '{0}' must be defined in a top level type; '{0}' is a nested type. File type '{0}' must be defined in a top level type; '{0}' is a nested type. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf index 29ee38c96cd19..9bd8242b1e766 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf @@ -592,6 +592,11 @@ File type '{0}' cannot be used in a member signature in non-file type '{1}'. + + Types and aliases cannot be named 'file'. + Types and aliases cannot be named 'file'. + + File type '{0}' must be defined in a top level type; '{0}' is a nested type. File type '{0}' must be defined in a top level type; '{0}' is a nested type. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf index cac0d81fe7c77..7d0ac87fca09c 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf @@ -592,6 +592,11 @@ File type '{0}' cannot be used in a member signature in non-file type '{1}'. + + Types and aliases cannot be named 'file'. + Types and aliases cannot be named 'file'. + + File type '{0}' must be defined in a top level type; '{0}' is a nested type. File type '{0}' must be defined in a top level type; '{0}' is a nested type. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf index a0208ccb1d4cc..3083e5bfd941f 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf @@ -592,6 +592,11 @@ File type '{0}' cannot be used in a member signature in non-file type '{1}'. + + Types and aliases cannot be named 'file'. + Types and aliases cannot be named 'file'. + + File type '{0}' must be defined in a top level type; '{0}' is a nested type. File type '{0}' must be defined in a top level type; '{0}' is a nested type. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf index 0f9e9fae47e7c..30de34a5fe134 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf @@ -592,6 +592,11 @@ File type '{0}' cannot be used in a member signature in non-file type '{1}'. + + Types and aliases cannot be named 'file'. + Types and aliases cannot be named 'file'. + + File type '{0}' must be defined in a top level type; '{0}' is a nested type. File type '{0}' must be defined in a top level type; '{0}' is a nested type. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf index 720c77fec0f2d..4d565648e74a0 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf @@ -592,6 +592,11 @@ File type '{0}' cannot be used in a member signature in non-file type '{1}'. + + Types and aliases cannot be named 'file'. + Types and aliases cannot be named 'file'. + + File type '{0}' must be defined in a top level type; '{0}' is a nested type. File type '{0}' must be defined in a top level type; '{0}' is a nested type. diff --git a/src/Compilers/CSharp/Test/Symbol/Symbols/Source/FileModifierTests.cs b/src/Compilers/CSharp/Test/Symbol/Symbols/Source/FileModifierTests.cs index be9266768eb8a..1316c04be7c7b 100644 --- a/src/Compilers/CSharp/Test/Symbol/Symbols/Source/FileModifierTests.cs +++ b/src/Compilers/CSharp/Test/Symbol/Symbols/Source/FileModifierTests.cs @@ -46,13 +46,13 @@ file class C { } // (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), - // (3,16): error CS9303: File type 'Outer.C' must be defined in a top level type; 'Outer.C' is a nested type. + // (3,16): error CS9054: File type 'Outer.C' must be defined in a top level type; 'Outer.C' is a nested type. // file class C { } Diagnostic(ErrorCode.ERR_FileTypeNested, "C").WithArguments("Outer.C").WithLocation(3, 16)); comp = CreateCompilation(source); comp.VerifyDiagnostics( - // (3,16): error CS9303: File type 'Outer.C' must be defined in a top level type; 'Outer.C' is a nested type. + // (3,16): error CS9054: File type 'Outer.C' must be defined in a top level type; 'Outer.C' is a nested type. // file class C { } Diagnostic(ErrorCode.ERR_FileTypeNested, "C").WithArguments("Outer.C").WithLocation(3, 16)); } @@ -108,13 +108,13 @@ file class C { } // (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), - // (3,16): error CS9303: File type 'Outer.C' must be defined in a top level type; 'Outer.C' is a nested type. + // (3,16): error CS9054: File type 'Outer.C' must be defined in a top level type; 'Outer.C' is a nested type. // file class C { } Diagnostic(ErrorCode.ERR_FileTypeNested, "C").WithArguments("Outer.C").WithLocation(3, 16)); comp = CreateCompilation(source); comp.VerifyDiagnostics( - // (3,16): error CS9303: File type 'Outer.C' must be defined in a top level type; 'Outer.C' is a nested type. + // (3,16): error CS9054: File type 'Outer.C' must be defined in a top level type; 'Outer.C' is a nested type. // file class C { } Diagnostic(ErrorCode.ERR_FileTypeNested, "C").WithArguments("Outer.C").WithLocation(3, 16)); } @@ -136,7 +136,7 @@ void M(Outer.C c) { } // 1 var comp = CreateCompilation(source); comp.VerifyDiagnostics( - // (8,10): error CS9300: File type 'Outer.C' cannot be used in a member signature in non-file type 'D'. + // (8,10): error CS9051: File type 'Outer.C' cannot be used in a member signature in non-file type 'D'. // void M(Outer.C c) { } // 1 Diagnostic(ErrorCode.ERR_FileTypeDisallowedInSignature, "M").WithArguments("Outer.C", "D").WithLocation(8, 10)); } @@ -395,7 +395,7 @@ static void Main() var comp = CreateCompilation(source); comp.VerifyDiagnostics( - // (10,12): error CS9300: File type 'E' cannot be used in a member signature in non-file type 'Attr'. + // (10,12): error CS9051: File type 'E' cannot be used in a member signature in non-file type 'Attr'. // public Attr(E e) { } // 1 Diagnostic(ErrorCode.ERR_FileTypeDisallowedInSignature, "Attr").WithArguments("E", "Attr").WithLocation(10, 12)); } @@ -1069,7 +1069,7 @@ public static void M() """; var comp = CreateCompilation(new[] { source1, source2 }); - // PROTOTYPE(ft): should this diagnostic be more specific? + // https://github.com/dotnet/roslyn/issues/62333: should this diagnostic be more specific? // the issue more precisely is that a definition for 'C' already exists in the current file--not that it's already in this namespace. comp.VerifyDiagnostics( // (8,12): error CS0101: The namespace '' already contains a definition for 'C' @@ -1101,7 +1101,6 @@ public static void M() Diagnostic(ErrorCode.ERR_MissingPartial, "C").WithArguments("C").WithLocation(8, 12)); var c = comp.GetMember("C"); - // PROTOTYPE(ft): is it a problem that we consider this symbol a file type in this scenario? Assert.True(c is SourceMemberContainerTypeSymbol { IsFile: true }); syntaxReferences = c.DeclaringSyntaxReferences; Assert.Equal(3, syntaxReferences.Length); @@ -1219,10 +1218,10 @@ public static void M() { } var compilation = CreateCompilation(new[] { source1, source2, source3 }); compilation.VerifyDiagnostics( - // (3,16): error CS9303: File type 'Outer.C' must be defined in a top level type; 'Outer.C' is a nested type. + // (3,16): error CS9054: File type 'Outer.C' must be defined in a top level type; 'Outer.C' is a nested type. // file class C Diagnostic(ErrorCode.ERR_FileTypeNested, "C").WithArguments("Outer.C").WithLocation(3, 16), - // (3,16): error CS9303: File type 'Outer.C' must be defined in a top level type; 'Outer.C' is a nested type. + // (3,16): error CS9054: File type 'Outer.C' must be defined in a top level type; 'Outer.C' is a nested type. // file class C Diagnostic(ErrorCode.ERR_FileTypeNested, "C").WithArguments("Outer.C").WithLocation(3, 16)); @@ -1442,10 +1441,10 @@ private void M2(C c) { } // 2 var comp = CreateCompilation(source); comp.VerifyDiagnostics( - // (7,17): error CS9300: File type 'C' cannot be used in a member signature in non-file type 'D'. + // (7,17): error CS9051: File type 'C' cannot be used in a member signature in non-file type 'D'. // public void M1(C c) { } // 1 Diagnostic(ErrorCode.ERR_FileTypeDisallowedInSignature, "M1").WithArguments("C", "D").WithLocation(7, 17), - // (8,18): error CS9300: File type 'C' cannot be used in a member signature in non-file type 'D'. + // (8,18): error CS9051: File type 'C' cannot be used in a member signature in non-file type 'D'. // private void M2(C c) { } // 2 Diagnostic(ErrorCode.ERR_FileTypeDisallowedInSignature, "M2").WithArguments("C", "D").WithLocation(8, 18)); } @@ -1467,10 +1466,10 @@ class D var comp = CreateCompilation(source); comp.VerifyDiagnostics( - // (7,14): error CS9300: File type 'C' cannot be used in a member signature in non-file type 'D'. + // (7,14): error CS9051: File type 'C' cannot be used in a member signature in non-file type 'D'. // public C M1() => new C(); // 1 Diagnostic(ErrorCode.ERR_FileTypeDisallowedInSignature, "M1").WithArguments("C", "D").WithLocation(7, 14), - // (8,15): error CS9300: File type 'C' cannot be used in a member signature in non-file type 'D'. + // (8,15): error CS9051: File type 'C' cannot be used in a member signature in non-file type 'D'. // private C M2() => new C(); // 2 Diagnostic(ErrorCode.ERR_FileTypeDisallowedInSignature, "M2").WithArguments("C", "D").WithLocation(8, 15)); } @@ -1495,19 +1494,19 @@ public class E var comp = CreateCompilation(source); comp.VerifyDiagnostics( - // (8,7): error CS9300: File type 'C' cannot be used in a member signature in non-file type 'E'. + // (8,7): error CS9051: File type 'C' cannot be used in a member signature in non-file type 'E'. // C field; // 1 Diagnostic(ErrorCode.ERR_FileTypeDisallowedInSignature, "field").WithArguments("C", "E").WithLocation(8, 7), // (8,7): warning CS0169: The field 'E.field' is never used // C field; // 1 Diagnostic(ErrorCode.WRN_UnreferencedField, "field").WithArguments("E.field").WithLocation(8, 7), - // (9,7): error CS9300: File type 'C' cannot be used in a member signature in non-file type 'E'. + // (9,7): error CS9051: File type 'C' cannot be used in a member signature in non-file type 'E'. // C property { get; set; } // 2 Diagnostic(ErrorCode.ERR_FileTypeDisallowedInSignature, "property").WithArguments("C", "E").WithLocation(9, 7), - // (10,12): error CS9300: File type 'C' cannot be used in a member signature in non-file type 'E'. + // (10,12): error CS9051: File type 'C' cannot be used in a member signature in non-file type 'E'. // object this[C c] { get => c; set { } } // 3 Diagnostic(ErrorCode.ERR_FileTypeDisallowedInSignature, "this").WithArguments("C", "E").WithLocation(10, 12), - // (11,13): error CS9300: File type 'D' cannot be used in a member signature in non-file type 'E'. + // (11,13): error CS9051: File type 'D' cannot be used in a member signature in non-file type 'E'. // event D @event; // 4 Diagnostic(ErrorCode.ERR_FileTypeDisallowedInSignature, "@event").WithArguments("D", "E").WithLocation(11, 13), // (11,13): warning CS0067: The event 'E.event' is never used @@ -1536,19 +1535,19 @@ public class E var comp = CreateCompilation(source); comp.VerifyDiagnostics( - // (9,13): error CS9300: File type 'C.Inner' cannot be used in a member signature in non-file type 'E'. + // (9,13): error CS9051: File type 'C.Inner' cannot be used in a member signature in non-file type 'E'. // C.Inner field; // 1 Diagnostic(ErrorCode.ERR_FileTypeDisallowedInSignature, "field").WithArguments("C.Inner", "E").WithLocation(9, 13), // (9,13): warning CS0169: The field 'E.field' is never used // C.Inner field; // 1 Diagnostic(ErrorCode.WRN_UnreferencedField, "field").WithArguments("E.field").WithLocation(9, 13), - // (10,13): error CS9300: File type 'C.Inner' cannot be used in a member signature in non-file type 'E'. + // (10,13): error CS9051: File type 'C.Inner' cannot be used in a member signature in non-file type 'E'. // C.Inner property { get; set; } // 2 Diagnostic(ErrorCode.ERR_FileTypeDisallowedInSignature, "property").WithArguments("C.Inner", "E").WithLocation(10, 13), - // (11,12): error CS9300: File type 'C.Inner' cannot be used in a member signature in non-file type 'E'. + // (11,12): error CS9051: File type 'C.Inner' cannot be used in a member signature in non-file type 'E'. // object this[C.Inner inner] { get => inner; set { } } // 3 Diagnostic(ErrorCode.ERR_FileTypeDisallowedInSignature, "this").WithArguments("C.Inner", "E").WithLocation(11, 12), - // (12,27): error CS9300: File type 'C.InnerDelegate' cannot be used in a member signature in non-file type 'E'. + // (12,27): error CS9051: File type 'C.InnerDelegate' cannot be used in a member signature in non-file type 'E'. // event C.InnerDelegate @event; // 4 Diagnostic(ErrorCode.ERR_FileTypeDisallowedInSignature, "@event").WithArguments("C.InnerDelegate", "E").WithLocation(12, 27), // (12,27): warning CS0067: The event 'E.event' is never used @@ -1593,16 +1592,16 @@ public class Inner var comp = CreateCompilation(source); comp.VerifyDiagnostics( - // (24,17): error CS9300: File type 'C.Inner' cannot be used in a member signature in non-file type 'E.Inner'. + // (24,17): error CS9051: File type 'C.Inner' cannot be used in a member signature in non-file type 'E.Inner'. // C.Inner field; // 1 Diagnostic(ErrorCode.ERR_FileTypeDisallowedInSignature, "field").WithArguments("C.Inner", "E.Inner").WithLocation(24, 17), - // (25,17): error CS9300: File type 'C.Inner' cannot be used in a member signature in non-file type 'E.Inner'. + // (25,17): error CS9051: File type 'C.Inner' cannot be used in a member signature in non-file type 'E.Inner'. // C.Inner property { get; set; } // 2 Diagnostic(ErrorCode.ERR_FileTypeDisallowedInSignature, "property").WithArguments("C.Inner", "E.Inner").WithLocation(25, 17), - // (26,16): error CS9300: File type 'C.Inner' cannot be used in a member signature in non-file type 'E.Inner'. + // (26,16): error CS9051: File type 'C.Inner' cannot be used in a member signature in non-file type 'E.Inner'. // object this[C.Inner inner] { get => inner; set { } } // 3 Diagnostic(ErrorCode.ERR_FileTypeDisallowedInSignature, "this").WithArguments("C.Inner", "E.Inner").WithLocation(26, 16), - // (27,31): error CS9300: File type 'C.InnerDelegate' cannot be used in a member signature in non-file type 'E.Inner'. + // (27,31): error CS9051: File type 'C.InnerDelegate' cannot be used in a member signature in non-file type 'E.Inner'. // event C.InnerDelegate @event; // 4 Diagnostic(ErrorCode.ERR_FileTypeDisallowedInSignature, "@event").WithArguments("C.InnerDelegate", "E.Inner").WithLocation(27, 31)); } @@ -1621,10 +1620,10 @@ file class C var comp = CreateCompilation(source); comp.VerifyDiagnostics( - // (5,15): error CS9300: File type 'C' cannot be used in a member signature in non-file type 'Del1'. + // (5,15): error CS9051: File type 'C' cannot be used in a member signature in non-file type 'Del1'. // delegate void Del1(C c); // 1 Diagnostic(ErrorCode.ERR_FileTypeDisallowedInSignature, "Del1").WithArguments("C", "Del1").WithLocation(5, 15), - // (6,12): error CS9300: File type 'C' cannot be used in a member signature in non-file type 'Del2'. + // (6,12): error CS9051: File type 'C' cannot be used in a member signature in non-file type 'Del2'. // delegate C Del2(); // 2 Diagnostic(ErrorCode.ERR_FileTypeDisallowedInSignature, "Del2").WithArguments("C", "Del2").WithLocation(6, 12)); } @@ -1646,10 +1645,10 @@ class D var comp = CreateCompilation(source); comp.VerifyDiagnostics( - // (7,30): error CS9300: File type 'C' cannot be used in a member signature in non-file type 'D'. + // (7,30): error CS9051: File type 'C' cannot be used in a member signature in non-file type 'D'. // public static D operator +(D d, C c) => d; // 1 Diagnostic(ErrorCode.ERR_FileTypeDisallowedInSignature, "+").WithArguments("C", "D").WithLocation(7, 30), - // (8,30): error CS9300: File type 'C' cannot be used in a member signature in non-file type 'D'. + // (8,30): error CS9051: File type 'C' cannot be used in a member signature in non-file type 'D'. // public static C operator -(D d1, D d2) => new C(); // 2 Diagnostic(ErrorCode.ERR_FileTypeDisallowedInSignature, "-").WithArguments("C", "D").WithLocation(8, 30)); } @@ -1670,7 +1669,7 @@ public D(C c) { } // 1 var comp = CreateCompilation(source); comp.VerifyDiagnostics( - // (7,12): error CS9300: File type 'C' cannot be used in a member signature in non-file type 'D'. + // (7,12): error CS9051: File type 'C' cannot be used in a member signature in non-file type 'D'. // public D(C c) { } // 1 Diagnostic(ErrorCode.ERR_FileTypeDisallowedInSignature, "D").WithArguments("C", "D").WithLocation(7, 12)); } @@ -1691,13 +1690,13 @@ class D var comp = CreateCompilation(source); comp.VerifyDiagnostics( - // (7,14): error CS9300: File type 'C' cannot be used in a member signature in non-file type 'D'. + // (7,14): error CS9051: File type 'C' cannot be used in a member signature in non-file type 'D'. // public C M(C c1, C c2) => c1; // 1, 2, 3 Diagnostic(ErrorCode.ERR_FileTypeDisallowedInSignature, "M").WithArguments("C", "D").WithLocation(7, 14), - // (7,14): error CS9300: File type 'C' cannot be used in a member signature in non-file type 'D'. + // (7,14): error CS9051: File type 'C' cannot be used in a member signature in non-file type 'D'. // public C M(C c1, C c2) => c1; // 1, 2, 3 Diagnostic(ErrorCode.ERR_FileTypeDisallowedInSignature, "M").WithArguments("C", "D").WithLocation(7, 14), - // (7,14): error CS9300: File type 'C' cannot be used in a member signature in non-file type 'D'. + // (7,14): error CS9051: File type 'C' cannot be used in a member signature in non-file type 'D'. // public C M(C c1, C c2) => c1; // 1, 2, 3 Diagnostic(ErrorCode.ERR_FileTypeDisallowedInSignature, "M").WithArguments("C", "D").WithLocation(7, 14)); } @@ -1714,13 +1713,13 @@ file class F { } // ok var comp = CreateCompilation(source); comp.VerifyDiagnostics( - // (1,19): error CS9301: File type 'C' cannot use accessibility modifiers. + // (1,19): error CS9052: File type 'C' cannot use accessibility modifiers. // public file class C { } // 1 Diagnostic(ErrorCode.ERR_FileTypeNoExplicitAccessibility, "C").WithArguments("C").WithLocation(1, 19), - // (2,21): error CS9301: File type 'D' cannot use accessibility modifiers. + // (2,21): error CS9052: File type 'D' cannot use accessibility modifiers. // file internal class D { } // 2 Diagnostic(ErrorCode.ERR_FileTypeNoExplicitAccessibility, "D").WithArguments("D").WithLocation(2, 21), - // (3,20): error CS9301: File type 'E' cannot use accessibility modifiers. + // (3,20): error CS9052: File type 'E' cannot use accessibility modifiers. // private file class E { } // 3, 4 Diagnostic(ErrorCode.ERR_FileTypeNoExplicitAccessibility, "E").WithArguments("E").WithLocation(3, 20), // (3,20): error CS1527: Elements defined in a namespace cannot be explicitly declared as private, protected, protected internal, or private protected @@ -1758,13 +1757,13 @@ public class Derived2 : Base { } // 2, 3 var comp = CreateCompilation(source); comp.VerifyDiagnostics( - // (2,7): error CS9301: File type 'Base' cannot be used as a base type of non-file type 'Derived1'. + // (2,7): error CS9053: File type 'Base' cannot be used as a base type of non-file type 'Derived1'. // class Derived1 : Base { } // 1 Diagnostic(ErrorCode.ERR_FileTypeBase, "Derived1").WithArguments("Base", "Derived1").WithLocation(2, 7), // (3,14): error CS0060: Inconsistent accessibility: base class 'Base' is less accessible than class 'Derived2' // public class Derived2 : Base { } // 2, 3 Diagnostic(ErrorCode.ERR_BadVisBaseClass, "Derived2").WithArguments("Derived2", "Base").WithLocation(3, 14), - // (3,14): error CS9301: File type 'Base' cannot be used as a base type of non-file type 'Derived2'. + // (3,14): error CS9053: File type 'Base' cannot be used as a base type of non-file type 'Derived2'. // public class Derived2 : Base { } // 2, 3 Diagnostic(ErrorCode.ERR_FileTypeBase, "Derived2").WithArguments("Base", "Derived2").WithLocation(3, 14)); } @@ -1784,7 +1783,7 @@ interface Derived3 : Interface { } // 1 var comp = CreateCompilation(source); comp.VerifyDiagnostics( - // (6,11): error CS9301: File type 'Interface' cannot be used as a base type of non-file type 'Derived3'. + // (6,11): error CS9053: File type 'Interface' cannot be used as a base type of non-file type 'Derived3'. // interface Derived3 : Interface { } // 1 Diagnostic(ErrorCode.ERR_FileTypeBase, "Derived3").WithArguments("Interface", "Derived3").WithLocation(6, 11)); } @@ -1889,7 +1888,7 @@ partial interface Derived : I2 { } var comp = CreateCompilation(source); comp.VerifyDiagnostics( - // (3,19): error CS9302: File type 'I1' cannot be used as a base type of non-file type 'Derived'. + // (3,19): error CS9053: File type 'I1' cannot be used as a base type of non-file type 'Derived'. // partial interface Derived : I1 { } // 1 Diagnostic(ErrorCode.ERR_FileTypeBase, "Derived").WithArguments("I1", "Derived").WithLocation(3, 19)); } @@ -1928,7 +1927,7 @@ public void F(I i) { } // 1 var comp = CreateCompilation(source); comp.VerifyDiagnostics( - // (7,17): error CS9300: File type 'I' cannot be used in a member signature in non-file type 'C'. + // (7,17): error CS9051: File type 'I' cannot be used in a member signature in non-file type 'C'. // public void F(I i) { } // 1 Diagnostic(ErrorCode.ERR_FileTypeDisallowedInSignature, "F").WithArguments("I", "C").WithLocation(7, 17)); } @@ -1943,14 +1942,14 @@ file interface I } class C : I { - void I.F(I i) { } // PROTOTYPE(ft): is this acceptable, since it's only callable by casting to the referenced file type? + void I.F(I i) { } } """; var comp = CreateCompilation(source); comp.VerifyDiagnostics( - // (7,12): error CS9300: File type 'I' cannot be used in a member signature in non-file type 'C'. - // void I.F(I i) { } // PROTOTYPE(ft): is this acceptable, since it's only callable by casting to the referenced file type? + // (7,12): error CS9051: File type 'I' cannot be used in a member signature in non-file type 'C'. + // void I.F(I i) { } Diagnostic(ErrorCode.ERR_FileTypeDisallowedInSignature, "F").WithArguments("I", "C").WithLocation(7, 12)); } @@ -2034,19 +2033,19 @@ unsafe class Program // (1,28): warning CS0649: Field 'S.X' is never assigned to, and will always have its default value 0 // file struct S { public int X; } Diagnostic(ErrorCode.WRN_UnassignedInternalField, "X").WithArguments("S.X", "0").WithLocation(1, 28), - // (5,18): error CS9300: File type 'Container' cannot be used in a member signature in non-file type 'Program'. + // (5,18): error CS9051: File type 'Container' cannot be used in a member signature in non-file type 'Program'. // Container M1() => new Container(); // 1 Diagnostic(ErrorCode.ERR_FileTypeDisallowedInSignature, "M1").WithArguments("Container", "Program").WithLocation(5, 18), - // (6,9): error CS9300: File type 'S[]' cannot be used in a member signature in non-file type 'Program'. + // (6,9): error CS9051: File type 'S[]' cannot be used in a member signature in non-file type 'Program'. // S[] M2() => new S[0]; // 2 Diagnostic(ErrorCode.ERR_FileTypeDisallowedInSignature, "M2").WithArguments("S[]", "Program").WithLocation(6, 9), - // (7,12): error CS9300: File type '(S, S)' cannot be used in a member signature in non-file type 'Program'. + // (7,12): error CS9051: File type '(S, S)' cannot be used in a member signature in non-file type 'Program'. // (S, S) M3() => (new S(), new S()); // 3 Diagnostic(ErrorCode.ERR_FileTypeDisallowedInSignature, "M3").WithArguments("(S, S)", "Program").WithLocation(7, 12), - // (8,8): error CS9300: File type 'S*' cannot be used in a member signature in non-file type 'Program'. + // (8,8): error CS9051: File type 'S*' cannot be used in a member signature in non-file type 'Program'. // S* M4() => null; // 4 Diagnostic(ErrorCode.ERR_FileTypeDisallowedInSignature, "M4").WithArguments("S*", "Program").WithLocation(8, 8), - // (9,24): error CS9300: File type 'delegate*' cannot be used in a member signature in non-file type 'Program'. + // (9,24): error CS9051: File type 'delegate*' cannot be used in a member signature in non-file type 'Program'. // delegate* M5() => null; // 5 Diagnostic(ErrorCode.ERR_FileTypeDisallowedInSignature, "M5").WithArguments("delegate*", "Program").WithLocation(9, 24)); } @@ -2070,7 +2069,7 @@ void M(T t) where T : C { } // 1 var comp = CreateCompilation(source); comp.VerifyDiagnostics( - // (10,30): error CS9300: File type 'C' cannot be used in a member signature in non-file type 'E.M(T)'. + // (10,30): error CS9051: File type 'C' cannot be used in a member signature in non-file type 'E.M(T)'. // void M(T t) where T : C { } // 1 Diagnostic(ErrorCode.ERR_FileTypeDisallowedInSignature, "C").WithArguments("C", "E.M(T)").WithLocation(10, 30)); } @@ -2090,16 +2089,16 @@ record struct R2(C c); // 2 var comp = CreateCompilation(new[] { source, IsExternalInitTypeDefinition }); comp.VerifyDiagnostics( - // (3,8): error CS9300: File type 'C' cannot be used in a member signature in non-file type 'R1'. + // (3,8): error CS9051: File type 'C' cannot be used in a member signature in non-file type 'R1'. // record R1(C c); // 1 Diagnostic(ErrorCode.ERR_FileTypeDisallowedInSignature, "R1").WithArguments("C", "R1").WithLocation(3, 8), - // (3,8): error CS9300: File type 'C' cannot be used in a member signature in non-file type 'R1'. + // (3,8): error CS9051: File type 'C' cannot be used in a member signature in non-file type 'R1'. // record R1(C c); // 1 Diagnostic(ErrorCode.ERR_FileTypeDisallowedInSignature, "R1").WithArguments("C", "R1").WithLocation(3, 8), - // (4,15): error CS9300: File type 'C' cannot be used in a member signature in non-file type 'R2'. + // (4,15): error CS9051: File type 'C' cannot be used in a member signature in non-file type 'R2'. // record struct R2(C c); // 2 Diagnostic(ErrorCode.ERR_FileTypeDisallowedInSignature, "R2").WithArguments("C", "R2").WithLocation(4, 15), - // (4,15): error CS9300: File type 'C' cannot be used in a member signature in non-file type 'R2'. + // (4,15): error CS9051: File type 'C' cannot be used in a member signature in non-file type 'R2'. // record struct R2(C c); // 2 Diagnostic(ErrorCode.ERR_FileTypeDisallowedInSignature, "R2").WithArguments("C", "R2").WithLocation(4, 15) ); @@ -2231,7 +2230,7 @@ public static void Main() var comp = CreateCompilation(source); comp.VerifyDiagnostics( - // (5,16): error CS9303: File type 'Outer.C' must be defined in a top level type; 'Outer.C' is a nested type. + // (5,16): error CS9054: File type 'Outer.C' must be defined in a top level type; 'Outer.C' is a nested type. // file class C // 1 Diagnostic(ErrorCode.ERR_FileTypeNested, "C").WithArguments("Outer.C").WithLocation(5, 16), // (15,15): error CS0122: 'Outer.C' is inaccessible due to its protection level @@ -2272,7 +2271,7 @@ static void Main() // (5,15): error CS0117: 'Outer' does not contain a definition for 'C' // Outer.C.M(); // 1 Diagnostic(ErrorCode.ERR_NoSuchMember, "C").WithArguments("Outer", "C").WithLocation(5, 15), - // (5,16): error CS9303: File type 'Outer.C' must be defined in a top level type; 'Outer.C' is a nested type. + // (5,16): error CS9054: File type 'Outer.C' must be defined in a top level type; 'Outer.C' is a nested type. // file class C Diagnostic(ErrorCode.ERR_FileTypeNested, "C").WithArguments("Outer.C").WithLocation(5, 16)); } @@ -2369,7 +2368,7 @@ public static void Main() // (1,1): hidden CS8019: Unnecessary using directive. // global using static C; Diagnostic(ErrorCode.HDN_UnusedUsingDirective, "global using static C;").WithLocation(1, 1), - // (1,21): error CS9304: File type 'C' cannot be used in a 'global using static' directive. + // (1,21): error CS9055: File type 'C' cannot be used in a 'global using static' directive. // global using static C; Diagnostic(ErrorCode.ERR_GlobalUsingStaticFileType, "C").WithArguments("C").WithLocation(1, 21), // (5,9): error CS0103: The name 'M' does not exist in the current context @@ -2408,7 +2407,7 @@ public static void Main() // (1,1): hidden CS8019: Unnecessary using directive. // global using static Container; Diagnostic(ErrorCode.HDN_UnusedUsingDirective, "global using static Container;").WithLocation(1, 1), - // (1,21): error CS9304: File type 'Container' cannot be used in a 'global using static' directive. + // (1,21): error CS9055: File type 'Container' cannot be used in a 'global using static' directive. // global using static Container; Diagnostic(ErrorCode.ERR_GlobalUsingStaticFileType, "Container").WithArguments("Container").WithLocation(1, 21), // (5,9): error CS0103: The name 'M' does not exist in the current context @@ -2579,7 +2578,7 @@ public static void Main() // 'Derived.C' is not actually accessible from 'Program', so we just bind to 'Base.C'. var compilation = CreateCompilation(new[] { source, main }); compilation.VerifyDiagnostics( - // (16,20): error CS9303: File type 'Derived.C' must be defined in a top level type; 'Derived.C' is a nested type. + // (16,20): error CS9054: File type 'Derived.C' must be defined in a top level type; 'Derived.C' is a nested type. // new file class C Diagnostic(ErrorCode.ERR_FileTypeNested, "C").WithArguments("Derived.C").WithLocation(16, 20)); @@ -2947,7 +2946,7 @@ class D : C1 { } // 1 var comp = CreateCompilation(source); comp.VerifyDiagnostics( - // (8,7): error CS9302: File type 'C' cannot be used as a base type of non-file type 'D'. + // (8,7): error CS9053: File type 'C' cannot be used as a base type of non-file type 'D'. // class D : C1 { } // 1 Diagnostic(ErrorCode.ERR_FileTypeBase, "D").WithArguments("NS.C", "NS.D").WithLocation(8, 7)); } @@ -3001,7 +3000,7 @@ public static void M(this string s) { } var comp = CreateSubmission(source1, parseOptions: TestOptions.Script.WithLanguageVersion(LanguageVersion.Preview)); comp.VerifyDiagnostics( - // (5,19): error CS9303: File type 'C1' must be defined in a top level type; 'C1' is a nested type. + // (5,19): error CS9054: File type 'C1' must be defined in a top level type; 'C1' is a nested type. // static file class C1 Diagnostic(ErrorCode.ERR_FileTypeNested, "C1").WithArguments("C1").WithLocation(5, 19), // (7,24): error CS1109: Extension methods must be defined in a top level static class; C1 is a nested class @@ -3015,7 +3014,7 @@ public void SystemVoid_01() var source1 = """ using System; - void M(Void v) { } // PROTOTYPE(ft): error here for explicit use of System.Void? + void M(Void v) { } namespace System { @@ -3023,10 +3022,12 @@ file class Void { } } """; + // https://github.com/dotnet/roslyn/issues/62331 + // Ideally we would give an error about use of System.Void here. var comp = CreateCompilation(source1); comp.VerifyDiagnostics( // (3,6): warning CS8321: The local function 'M' is declared but never used - // void M(Void v) { } // PROTOTYPE(ft): error here for explicit use of System.Void? + // void M(Void v) { } Diagnostic(ErrorCode.WRN_UnreferencedLocalFunction, "M").WithArguments("M").WithLocation(3, 6)); var tree = comp.SyntaxTrees[0]; @@ -3109,7 +3110,7 @@ file class C { } // 1 // from source var comp = CreateCompilation(source1); comp.VerifyDiagnostics( - // (3,16): error CS9303: File type 'Outer.C' must be defined in a top level type; 'Outer.C' is a nested type. + // (3,16): error CS9054: File type 'Outer.C' must be defined in a top level type; 'Outer.C' is a nested type. // file class C { } // 1 Diagnostic(ErrorCode.ERR_FileTypeNested, "C").WithArguments("Outer.C").WithLocation(3, 16)); var sourceMember = comp.GetMember("Outer.C"); diff --git a/src/Compilers/CSharp/Test/Syntax/Parsing/FileModifierParsingTests.cs b/src/Compilers/CSharp/Test/Syntax/Parsing/FileModifierParsingTests.cs index 0f7fbe85446b8..4526b59797ae9 100644 --- a/src/Compilers/CSharp/Test/Syntax/Parsing/FileModifierParsingTests.cs +++ b/src/Compilers/CSharp/Test/Syntax/Parsing/FileModifierParsingTests.cs @@ -192,7 +192,6 @@ public void FileModifier_03(SyntaxKind typeKeyword) 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) @@ -239,7 +238,6 @@ file partial record struct C { } EOF(); } - // PROTOTYPE(ft): is it fine that records parse here, but not other type kinds? [Fact] public void FileModifier_06() { @@ -332,22 +330,53 @@ 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)); + expectedParsingDiagnostics: new[] + { + // (1,14): error CS1003: Syntax error, ',' expected + // file partial ref struct C { } + Diagnostic(ErrorCode.ERR_SyntaxError, "ref").WithArguments(",").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(",").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.IncompleteMember); + N(SyntaxKind.GlobalStatement); { - N(SyntaxKind.FileKeyword); - N(SyntaxKind.IdentifierName); + N(SyntaxKind.LocalDeclarationStatement); { - N(SyntaxKind.IdentifierToken, "partial"); + 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.RefKeyword); N(SyntaxKind.StructKeyword); N(SyntaxKind.IdentifierToken, "C"); N(SyntaxKind.OpenBraceToken); @@ -478,7 +507,7 @@ public void FileModifier_11(SyntaxKind typeKeyword) """, expectedBindingDiagnostics: new[] { - // (1,20): error CS9301: File type 'C' cannot use accessibility modifiers. + // (1,20): error CS9052: File type 'C' cannot use accessibility modifiers. // public file {{SyntaxFacts.GetText(typeKeyword)}} C { } Diagnostic(ErrorCode.ERR_FileTypeNoExplicitAccessibility, "C").WithArguments("C") }); @@ -511,7 +540,7 @@ public void FileModifier_12(SyntaxKind typeKeyword) """, expectedBindingDiagnostics: new[] { - // (1,19): error CS9301: File type 'C' cannot use accessibility modifiers. + // (1,19): error CS9052: File type 'C' cannot use accessibility modifiers. // file public {{SyntaxFacts.GetText(typeKeyword)}} C { } Diagnostic(ErrorCode.ERR_FileTypeNoExplicitAccessibility, "C").WithArguments("C") }); @@ -667,7 +696,7 @@ file class C { } """, expectedBindingDiagnostics: new[] { - // (3,16): error CS9303: File type 'Outer.C' must be defined in a top level type; 'Outer.C' is a nested type. + // (3,16): error CS9054: File type 'Outer.C' must be defined in a top level type; 'Outer.C' is a nested type. // file class C { } Diagnostic(ErrorCode.ERR_FileTypeNested, "C").WithArguments("Outer.C").WithLocation(3, 16) }); @@ -1211,9 +1240,9 @@ 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. + // (1,12): error CS9056: Types and aliases cannot be named 'file'. // file class file { } - Diagnostic(ErrorCode.WRN_LowerCaseTypeName, "file").WithArguments("file").WithLocation(1, 12) + Diagnostic(ErrorCode.ERR_FileTypeNameDisallowed, "file").WithLocation(1, 12) }); N(SyntaxKind.CompilationUnit); @@ -1366,7 +1395,6 @@ class C EOF(); } - // PROTOTYPE(ft): confirm with LDM whether this breaking change is acceptable (compared to CSharp10 version above). [Fact] public void MemberNamedFile_07() { @@ -1407,6 +1435,7 @@ class C } EOF(); } + [Fact] public void MemberNamedFile_08() { @@ -1415,9 +1444,9 @@ 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. + // (1,8): error CS9056: Types and aliases cannot be named 'file'. // record file { } - Diagnostic(ErrorCode.WRN_LowerCaseTypeName, "file").WithArguments("file").WithLocation(1, 8) + Diagnostic(ErrorCode.ERR_FileTypeNameDisallowed, "file").WithLocation(1, 8) }); N(SyntaxKind.CompilationUnit); @@ -1434,6 +1463,85 @@ record file { } EOF(); } + [Fact] + public void TypeNamedFile_01() + { + UsingNode($$""" + class file { } + """, + expectedBindingDiagnostics: new[] + { + // (1,7): error CS9056: Types and aliases cannot be named 'file'. + // class file { } + Diagnostic(ErrorCode.ERR_FileTypeNameDisallowed, "file").WithLocation(1, 7) + }); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "file"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void TypeNamedFile_01_CSharp10() + { + UsingNode($$""" + class file { } + """, + options: TestOptions.Regular10, + expectedBindingDiagnostics: new[] + { + // (1,7): warning CS8981: The type name 'file' only contains lower-cased ascii characters. Such names may become reserved for the language. + // class file { } + Diagnostic(ErrorCode.WRN_LowerCaseTypeName, "file").WithArguments("file").WithLocation(1, 7) + }); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "file"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Theory] + [InlineData(LanguageVersion.CSharp10)] + [InlineData(LanguageVersionFacts.CSharpNext)] + public void TypeNamedFile_02(LanguageVersion languageVersion) + { + UsingNode($$""" + class @file { } + """, + options: TestOptions.Regular.WithLanguageVersion(languageVersion)); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "@file"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + [Fact] public void Errors_01_CSharp10() { @@ -1473,7 +1581,10 @@ public void Errors_01() { N(SyntaxKind.IncompleteMember); { - N(SyntaxKind.FileKeyword); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "file"); + } } N(SyntaxKind.EndOfFileToken); } @@ -1521,32 +1632,26 @@ 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 + // (1,1): error CS0103: The name 'file' does not exist in the current context // file; - Diagnostic(ErrorCode.ERR_NamespaceUnexpected, "file").WithLocation(1, 1), - // (1,5): error CS8937: At least one top-level statement must be non-empty. + 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_SimpleProgramIsEmpty, ";").WithLocation(1, 5) + Diagnostic(ErrorCode.ERR_IllegalStatement, "file").WithLocation(1, 1) }); N(SyntaxKind.CompilationUnit); { - N(SyntaxKind.IncompleteMember); - { - N(SyntaxKind.FileKeyword); - } N(SyntaxKind.GlobalStatement); { - N(SyntaxKind.EmptyStatement); + N(SyntaxKind.ExpressionStatement); { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "file"); + } N(SyntaxKind.SemicolonToken); } } @@ -1607,18 +1712,33 @@ public void Errors_03() UsingNode($$""" file namespace NS; """, + 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 CS1671: A namespace declaration cannot have modifiers or attributes + // (1,1): error CS0116: A namespace cannot directly contain members such as fields, methods or statements // file namespace NS; - Diagnostic(ErrorCode.ERR_BadModifiersOnNamespace, "file").WithLocation(1, 1) + 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.FileKeyword); N(SyntaxKind.NamespaceKeyword); N(SyntaxKind.IdentifierName); { @@ -1675,18 +1795,24 @@ public void Errors_04() UsingNode($$""" file namespace NS { } """, - expectedBindingDiagnostics: new[] + expectedParsingDiagnostics: new[] { - // (1,1): error CS1671: A namespace declaration cannot have modifiers or attributes + // (1,1): error CS0116: A namespace cannot directly contain members such as fields, methods or statements // file namespace NS { } - Diagnostic(ErrorCode.ERR_BadModifiersOnNamespace, "file").WithLocation(1, 1) + 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.FileKeyword); N(SyntaxKind.NamespaceKeyword); N(SyntaxKind.IdentifierName); { @@ -1704,7 +1830,7 @@ file namespace NS { } public void File_Repeated() { const int FileModifiersCount = 100000; - var manyFileModifiers = string.Join(" ", Enumerable.Repeat("file", FileModifiersCount)); + var manyFileModifiers = string.Join(" ", Enumerable.Repeat("file", FileModifiersCount)); UsingNode(manyFileModifiers, expectedParsingDiagnostics: new[] { @@ -1715,10 +1841,14 @@ public void File_Repeated() { N(SyntaxKind.IncompleteMember); { - for (var i = 0; i < FileModifiersCount; i++) + for (var i = 0; i < FileModifiersCount - 1; i++) { N(SyntaxKind.FileKeyword); } + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "file"); + } N(SyntaxKind.EndOfFileToken); } } @@ -2007,7 +2137,7 @@ class C """, expectedBindingDiagnostics: new[] { - // (3,17): error CS9303: File type 'C.X' must be defined in a top level type; 'C.X' is a nested type. + // (3,17): error CS9054: File type 'C.X' must be defined in a top level type; 'C.X' is a nested type. // file record X(); Diagnostic(ErrorCode.ERR_FileTypeNested, "X").WithArguments("C.X").WithLocation(3, 17) }); @@ -2105,7 +2235,7 @@ file record X() { } """, expectedBindingDiagnostics: new[] { - // (3,17): error CS9303: File type 'C.X' must be defined in a top level type; 'C.X' is a nested type. + // (3,17): error CS9054: File type 'C.X' must be defined in a top level type; 'C.X' is a nested type. // file record X() { } Diagnostic(ErrorCode.ERR_FileTypeNested, "X").WithArguments("C.X").WithLocation(3, 17) }); @@ -2200,7 +2330,7 @@ class C """, expectedBindingDiagnostics: new[] { - // (3,17): error CS9303: File type 'C.X' must be defined in a top level type; 'C.X' is a nested type. + // (3,17): error CS9054: File type 'C.X' must be defined in a top level type; 'C.X' is a nested type. // file record X; Diagnostic(ErrorCode.ERR_FileTypeNested, "X").WithArguments("C.X").WithLocation(3, 17) }); @@ -2377,14 +2507,15 @@ void M() EOF(); } - // PROTOTYPE(ft): confirm whether this breaking change is acceptable - [Fact] - public void TopLevelVariable_01_CSharp10() + [Theory] + [InlineData(LanguageVersion.CSharp10)] + [InlineData(LanguageVersionFacts.CSharpNext)] + public void TopLevelVariable_01(LanguageVersion languageVersion) { UsingNode(""" file file; """, - options: TestOptions.Regular10, + options: TestOptions.Regular.WithLanguageVersion(languageVersion), expectedBindingDiagnostics: new[] { // (1,1): error CS0118: 'file' is a variable but is used like a type @@ -2420,52 +2551,15 @@ public void TopLevelVariable_01_CSharp10() 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() + [Theory] + [InlineData(LanguageVersion.CSharp10)] + [InlineData(LanguageVersionFacts.CSharpNext)] + public void TopLevelVariable_02(LanguageVersion languageVersion) { UsingNode(""" int file; """, + options: TestOptions.Regular.WithLanguageVersion(languageVersion), expectedBindingDiagnostics: new[] { // (1,5): warning CS0168: The variable 'file' is declared but never used @@ -2497,36 +2591,23 @@ public void TopLevelVariable_02() EOF(); } - [Fact] - public void TopLevelVariable_04() + [Theory] + [InlineData(LanguageVersion.CSharp10)] + [InlineData(LanguageVersionFacts.CSharpNext)] + public void TopLevelVariable_03(LanguageVersion languageVersion) { - // PROTOTYPE(ft): this should parse and compile without errors - // we will share a common solution with 'required' and 'scoped' here. UsingNode(""" bool file; file = true; """, - expectedParsingDiagnostics: new[] - { - // (2,1): error CS0116: A namespace cannot directly contain members such as fields, methods or statements - // file = true; - Diagnostic(ErrorCode.ERR_NamespaceUnexpected, "file").WithLocation(2, 1), - // (2,6): error CS1525: Invalid expression term '=' - // file = true; - Diagnostic(ErrorCode.ERR_InvalidExprTerm, "=").WithArguments("=").WithLocation(2, 6) - }, + options: TestOptions.Regular.WithLanguageVersion(languageVersion), expectedBindingDiagnostics: new[] { - // (1,6): warning CS0168: The variable 'file' is declared but never used + // (1,6): warning CS0219: The variable 'file' is assigned but its value is never used // bool file; - Diagnostic(ErrorCode.WRN_UnreferencedVar, "file").WithArguments("file").WithLocation(1, 6), - // (2,1): error CS0116: A namespace cannot directly contain members such as fields, methods or statements - // file = true; - Diagnostic(ErrorCode.ERR_NamespaceUnexpected, "file").WithLocation(2, 1), - // (2,6): error CS1525: Invalid expression term '=' - // file = true; - Diagnostic(ErrorCode.ERR_InvalidExprTerm, "=").WithArguments("=").WithLocation(2, 6) + Diagnostic(ErrorCode.WRN_UnreferencedVarAssg, "file").WithArguments("file").WithLocation(1, 6) }); + N(SyntaxKind.CompilationUnit); { N(SyntaxKind.GlobalStatement); @@ -2547,19 +2628,15 @@ public void TopLevelVariable_04() N(SyntaxKind.SemicolonToken); } } - N(SyntaxKind.IncompleteMember); - { - N(SyntaxKind.FileKeyword); - } N(SyntaxKind.GlobalStatement); { N(SyntaxKind.ExpressionStatement); { N(SyntaxKind.SimpleAssignmentExpression); { - M(SyntaxKind.IdentifierName); + N(SyntaxKind.IdentifierName); { - M(SyntaxKind.IdentifierToken); + N(SyntaxKind.IdentifierToken, "file"); } N(SyntaxKind.EqualsToken); N(SyntaxKind.TrueLiteralExpression); @@ -2575,6 +2652,85 @@ public void TopLevelVariable_04() EOF(); } + [Fact] + public void Variable_01() + { + UsingNode(""" + void M() + { + bool file; + file = true; + } + """, + 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,10): warning CS0219: The variable 'file' is assigned but its value is never used + // bool file; + Diagnostic(ErrorCode.WRN_UnreferencedVarAssg, "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.PredefinedType); + { + N(SyntaxKind.BoolKeyword); + } + N(SyntaxKind.VariableDeclarator); + { + N(SyntaxKind.IdentifierToken, "file"); + } + } + N(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.ExpressionStatement); + { + N(SyntaxKind.SimpleAssignmentExpression); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "file"); + } + N(SyntaxKind.EqualsToken); + N(SyntaxKind.TrueLiteralExpression); + { + N(SyntaxKind.TrueKeyword); + } + } + N(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.CloseBraceToken); + } + } + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + [Fact] public void LambdaReturn() { diff --git a/src/Compilers/Core/Portable/PublicAPI.Unshipped.txt b/src/Compilers/Core/Portable/PublicAPI.Unshipped.txt index bf7b9db988916..7018e80cb367a 100644 --- a/src/Compilers/Core/Portable/PublicAPI.Unshipped.txt +++ b/src/Compilers/Core/Portable/PublicAPI.Unshipped.txt @@ -111,4 +111,5 @@ virtual Microsoft.CodeAnalysis.SymbolVisitor.VisitPointerTyp virtual Microsoft.CodeAnalysis.SymbolVisitor.VisitProperty(Microsoft.CodeAnalysis.IPropertySymbol! symbol, TArgument argument) -> TResult virtual Microsoft.CodeAnalysis.SymbolVisitor.VisitRangeVariable(Microsoft.CodeAnalysis.IRangeVariableSymbol! symbol, TArgument argument) -> TResult virtual Microsoft.CodeAnalysis.SymbolVisitor.VisitTypeParameter(Microsoft.CodeAnalysis.ITypeParameterSymbol! symbol, TArgument argument) -> TResult -Microsoft.CodeAnalysis.Operations.BinaryOperatorKind.UnsignedRightShift = 25 -> Microsoft.CodeAnalysis.Operations.BinaryOperatorKind \ No newline at end of file +Microsoft.CodeAnalysis.Operations.BinaryOperatorKind.UnsignedRightShift = 25 -> Microsoft.CodeAnalysis.Operations.BinaryOperatorKind +Microsoft.CodeAnalysis.INamedTypeSymbol.IsFile.get -> bool \ No newline at end of file diff --git a/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/Binders/EEMethodBinder.cs b/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/Binders/EEMethodBinder.cs index 1b075b464548e..c7b5cc398148e 100644 --- a/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/Binders/EEMethodBinder.cs +++ b/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/Binders/EEMethodBinder.cs @@ -44,7 +44,7 @@ internal EEMethodBinder(EEMethodSymbol method, MethodSymbol containingMethod, Bi var substitutedSourceMethod = method.SubstitutedSourceMethod; _parameterOffset = substitutedSourceMethod.IsStatic ? 0 : 1; _targetParameters = method.Parameters; - // PROTOTYPE(ft): add tests and adjust implementation to allow EE to access file types + // https://github.com/dotnet/roslyn/issues/62334: add tests and adjust implementation to allow EE to access file types _sourceBinder = new InMethodBinder(substitutedSourceMethod, new BuckStopsHereBinder(next.Compilation, associatedSyntaxTree: null)); } diff --git a/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/CompilationContext.cs b/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/CompilationContext.cs index 94269b757bd9c..c29de94be92eb 100644 --- a/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/CompilationContext.cs +++ b/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/CompilationContext.cs @@ -706,7 +706,7 @@ private static Binder CreateBinderChain( @namespace = @namespace.ContainingNamespace; } - // PROTOTYPE(ft): add tests and adjust implementation to allow EE to access file types + // https://github.com/dotnet/roslyn/issues/62334: add tests and adjust implementation to allow EE to access file types Binder binder = new BuckStopsHereBinder(compilation, associatedSyntaxTree: null); var hasImports = !importRecordGroups.IsDefaultOrEmpty; var numImportStringGroups = hasImports ? importRecordGroups.Length : 0; diff --git a/src/Workspaces/Core/Portable/PublicAPI.Unshipped.txt b/src/Workspaces/Core/Portable/PublicAPI.Unshipped.txt index 33861f0f5b2f4..107531883f1ae 100644 --- a/src/Workspaces/Core/Portable/PublicAPI.Unshipped.txt +++ b/src/Workspaces/Core/Portable/PublicAPI.Unshipped.txt @@ -4,6 +4,8 @@ Microsoft.CodeAnalysis.CodeFixes.FixAllScope.ContainingMember = 4 -> Microsoft.C Microsoft.CodeAnalysis.CodeFixes.FixAllScope.ContainingType = 5 -> Microsoft.CodeAnalysis.CodeFixes.FixAllScope Microsoft.CodeAnalysis.Editing.DeclarationModifiers.IsRequired.get -> bool Microsoft.CodeAnalysis.Editing.DeclarationModifiers.WithIsRequired(bool isRequired) -> Microsoft.CodeAnalysis.Editing.DeclarationModifiers +Microsoft.CodeAnalysis.Editing.DeclarationModifiers.IsFile.get -> bool +Microsoft.CodeAnalysis.Editing.DeclarationModifiers.WithIsFile(bool isFile) -> Microsoft.CodeAnalysis.Editing.DeclarationModifiers Microsoft.CodeAnalysis.Editing.SyntaxEditor.SyntaxEditor(Microsoft.CodeAnalysis.SyntaxNode root, Microsoft.CodeAnalysis.Host.HostWorkspaceServices services) -> void *REMOVED*static Microsoft.CodeAnalysis.Editing.SyntaxGenerator.DefaultRemoveOptions -> Microsoft.CodeAnalysis.SyntaxRemoveOptions Microsoft.CodeAnalysis.TextDocumentEventArgs @@ -16,6 +18,7 @@ Microsoft.CodeAnalysis.Workspace.TextDocumentOpened -> System.EventHandler System.Collections.Immutable.ImmutableArray static Microsoft.CodeAnalysis.CodeFixes.FixAllProvider.Create(System.Func, System.Threading.Tasks.Task> fixAllAsync, System.Collections.Immutable.ImmutableArray supportedFixAllScopes) -> Microsoft.CodeAnalysis.CodeFixes.FixAllProvider static Microsoft.CodeAnalysis.Editing.DeclarationModifiers.Required.get -> Microsoft.CodeAnalysis.Editing.DeclarationModifiers +static Microsoft.CodeAnalysis.Editing.DeclarationModifiers.File.get -> Microsoft.CodeAnalysis.Editing.DeclarationModifiers static Microsoft.CodeAnalysis.Recommendations.Recommender.GetRecommendedSymbolsAtPositionAsync(Microsoft.CodeAnalysis.Document document, int position, Microsoft.CodeAnalysis.Options.OptionSet options = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> System.Threading.Tasks.Task> static readonly Microsoft.CodeAnalysis.Editing.SyntaxGenerator.DefaultRemoveOptions -> Microsoft.CodeAnalysis.SyntaxRemoveOptions Microsoft.CodeAnalysis.Rename.SymbolRenameOptions From 34012bd3749b30373b26c8071ff05c26adcbf2e6 Mon Sep 17 00:00:00 2001 From: Rikki Gibson Date: Tue, 5 Jul 2022 15:05:58 -0700 Subject: [PATCH 11/11] Add suggested lookup tests (#62383) --- .../Symbols/Source/FileModifierTests.cs | 65 ++++++++- .../CSharpCompletionCommandHandlerTests.vb | 130 ++++++++++++++++++ 2 files changed, 189 insertions(+), 6 deletions(-) diff --git a/src/Compilers/CSharp/Test/Symbol/Symbols/Source/FileModifierTests.cs b/src/Compilers/CSharp/Test/Symbol/Symbols/Source/FileModifierTests.cs index 1316c04be7c7b..47029fb59b42d 100644 --- a/src/Compilers/CSharp/Test/Symbol/Symbols/Source/FileModifierTests.cs +++ b/src/Compilers/CSharp/Test/Symbol/Symbols/Source/FileModifierTests.cs @@ -2595,6 +2595,8 @@ public static void Main() public void SemanticModel_01() { var source = """ + namespace NS; + file class C { public static void M() { } @@ -2618,20 +2620,45 @@ public void M() var model = compilation.GetSemanticModel(tree, ignoreAccessibility: false); var info = model.GetSymbolInfo(((ExpressionStatementSyntax)body.Statements.First()).Expression); - Assert.Equal(compilation.GetMember("C.M").GetPublicSymbol(), info.Symbol); + Assert.Equal("void NS.C@.M()", info.Symbol.ToTestDisplayString()); - var classC = compilation.GetMember("C").GetPublicSymbol(); + var classC = compilation.GetMember("NS.C").GetPublicSymbol(); + Assert.Equal("NS.C@", classC.ToTestDisplayString()); + + // lookup with no container var symbols = model.LookupSymbols(body.OpenBraceToken.EndPosition, name: "C"); Assert.Equal(new[] { classC }, symbols); symbols = model.LookupSymbols(body.OpenBraceToken.EndPosition); Assert.Contains(classC, symbols); + + // lookup with a correct container + var nsSymbol = compilation.GetMember("NS").GetPublicSymbol(); + Assert.Equal("NS", nsSymbol.ToTestDisplayString()); + + symbols = model.LookupSymbols(body.OpenBraceToken.EndPosition, container: nsSymbol, name: "C"); + Assert.Equal(new[] { classC }, symbols); + + symbols = model.LookupSymbols(body.OpenBraceToken.EndPosition, container: nsSymbol); + Assert.Contains(classC, symbols); + + // lookup with an incorrect container + nsSymbol = compilation.GetMember("System").GetPublicSymbol(); + Assert.Equal("System", nsSymbol.ToTestDisplayString()); + + symbols = model.LookupSymbols(body.OpenBraceToken.EndPosition, container: nsSymbol, name: "C"); + Assert.Empty(symbols); + + symbols = model.LookupSymbols(body.OpenBraceToken.EndPosition, container: nsSymbol); + Assert.DoesNotContain(classC, symbols); } [Fact] public void SemanticModel_02() { var source = """ + namespace NS; + file class C { public static void M() { } @@ -2639,6 +2666,8 @@ public static void M() { } """; var main = """ + namespace NS; + class Program { public void M() @@ -2650,9 +2679,9 @@ public void M() var compilation = CreateCompilation(new[] { source, main }); compilation.VerifyDiagnostics( - // (5,9): error CS0103: The name 'C' does not exist in the current context - // C.M(); - Diagnostic(ErrorCode.ERR_NameNotInContext, "C").WithArguments("C").WithLocation(5, 9) + // (7,9): error CS0103: The name 'C' does not exist in the current context + // C.M(); // 1 + Diagnostic(ErrorCode.ERR_NameNotInContext, "C").WithArguments("C").WithLocation(7, 9) ); var tree = compilation.SyntaxTrees[1]; @@ -2665,11 +2694,35 @@ public void M() Assert.Empty(info.CandidateSymbols); Assert.Equal(CandidateReason.None, info.CandidateReason); + var classC = compilation.GetMember("NS.C").GetPublicSymbol(); + Assert.Equal("NS.C@", classC.ToTestDisplayString()); + + // lookup with no container var symbols = model.LookupSymbols(body.OpenBraceToken.EndPosition, name: "C"); Assert.Empty(symbols); symbols = model.LookupSymbols(body.OpenBraceToken.EndPosition); - Assert.DoesNotContain(compilation.GetMember("C").GetPublicSymbol(), symbols); + Assert.DoesNotContain(classC, symbols); + + // lookup with a correct container (still don't find the symbol due to lookup occurring in other file) + var nsSymbol = compilation.GetMember("NS").GetPublicSymbol(); + Assert.Equal("NS", nsSymbol.ToTestDisplayString()); + + symbols = model.LookupSymbols(body.OpenBraceToken.EndPosition, container: nsSymbol, name: "C"); + Assert.Empty(symbols); + + symbols = model.LookupSymbols(body.OpenBraceToken.EndPosition, container: nsSymbol); + Assert.DoesNotContain(classC, symbols); + + // lookup with an incorrect container + nsSymbol = compilation.GetMember("System").GetPublicSymbol(); + Assert.Equal("System", nsSymbol.ToTestDisplayString()); + + symbols = model.LookupSymbols(body.OpenBraceToken.EndPosition, container: nsSymbol, name: "C"); + Assert.Empty(symbols); + + symbols = model.LookupSymbols(body.OpenBraceToken.EndPosition, container: nsSymbol); + Assert.DoesNotContain(classC, symbols); } [Fact] diff --git a/src/EditorFeatures/Test2/IntelliSense/CSharpCompletionCommandHandlerTests.vb b/src/EditorFeatures/Test2/IntelliSense/CSharpCompletionCommandHandlerTests.vb index b3ca8a311e484..189654c326a60 100644 --- a/src/EditorFeatures/Test2/IntelliSense/CSharpCompletionCommandHandlerTests.vb +++ b/src/EditorFeatures/Test2/IntelliSense/CSharpCompletionCommandHandlerTests.vb @@ -29,6 +29,136 @@ Namespace Microsoft.CodeAnalysis.Editor.UnitTests.IntelliSense <[UseExportProvider]> Public Class CSharpCompletionCommandHandlerTests + + + Public Async Function CompletionOnFileType_SameFile_NonQualified(showCompletionInArgumentLists As Boolean) As Task + Using state = TestStateFactory.CreateCSharpTestState( + +namespace NS +{ + file class FC { } + + class C + { + public static void M() + { + var x = new $$ + } + } +} + , + showCompletionInArgumentLists:=showCompletionInArgumentLists, languageVersion:=LanguageVersion.Preview) + + state.SendTypeChars("F") + Await state.AssertSelectedCompletionItem(displayText:="FC", isHardSelected:=True) + + state.SendTab() + Await state.AssertNoCompletionSession() + Assert.Contains("var x = new FC", state.GetLineTextFromCaretPosition(), StringComparison.Ordinal) + End Using + End Function + + + + Public Async Function CompletionOnFileType_SameFile_NamespaceQualified(showCompletionInArgumentLists As Boolean) As Task + Using state = TestStateFactory.CreateCSharpTestState( + +namespace NS +{ + file class FC { } + + class C + { + public static void M() + { + var x = new NS.$$ + } + } +} + , + showCompletionInArgumentLists:=showCompletionInArgumentLists, languageVersion:=LanguageVersion.Preview) + + state.SendTypeChars("F") + Await state.AssertSelectedCompletionItem(displayText:="FC", isHardSelected:=True) + + state.SendTab() + Await state.AssertNoCompletionSession() + Assert.Contains("var x = new NS.FC", state.GetLineTextFromCaretPosition(), StringComparison.Ordinal) + End Using + End Function + + + + Public Async Function CompletionOnFileType_DifferentFile_NonQualified(showCompletionInArgumentLists As Boolean) As Task + Using State = New TestState( + > + +namespace NS +{ + file class FC { } +} + + +namespace NS +{ + class C + { + public static void M() + { + var x = new $$ + } + } +} + + + , + excludedTypes:=Nothing, extraExportedTypes:=Nothing, + includeFormatCommandHandler:=False, workspaceKind:=Nothing) + + State.Workspace.GlobalOptions.SetGlobalOption( + New OptionKey(CompletionOptionsStorage.TriggerInArgumentLists, LanguageNames.CSharp), showCompletionInArgumentLists) + + State.SendTypeChars("F") + Await State.AssertCompletionItemsDoNotContainAny("FC") + End Using + End Function + + + + Public Async Function CompletionOnFileType_DifferentFile_NamespaceQualified(showCompletionInArgumentLists As Boolean) As Task + Using State = New TestState( + > + +namespace NS +{ + file class FC { } +} + + +namespace NS +{ + class C + { + public static void M() + { + var x = new NS.$$ + } + } +} + + + , + excludedTypes:=Nothing, extraExportedTypes:=Nothing, + includeFormatCommandHandler:=False, workspaceKind:=Nothing) + + State.Workspace.GlobalOptions.SetGlobalOption( + New OptionKey(CompletionOptionsStorage.TriggerInArgumentLists, LanguageNames.CSharp), showCompletionInArgumentLists) + + State.SendTypeChars("F") + Await State.AssertCompletionItemsDoNotContainAny("FC") + End Using + End Function + Public Async Function CompletionOnExtendedPropertyPattern_FirstNested(showCompletionInArgumentLists As Boolean) As Task