diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Symbols.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Symbols.cs index c35c4512565cd..b3c42874d46a0 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder_Symbols.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder_Symbols.cs @@ -1373,14 +1373,32 @@ private NamedTypeSymbol ConstructNamedTypeUnlessTypeArgumentOmitted(SyntaxNode t { if (typeArgumentsSyntax.Any(SyntaxKind.OmittedTypeArgument)) { - // Note: lookup won't have reported this, since the arity was correct. - // CONSIDER: the text of this error message makes sense, but we might want to add a separate code. - Error(diagnostics, ErrorCode.ERR_BadArity, typeSyntax, type, MessageID.IDS_SK_TYPE.Localize(), typeArgumentsSyntax.Count); + if (this.IsInsideNameof) + { + // Inside a nameof an open-generic type is acceptable. Fall through and bind the remainder accordingly. + CheckFeatureAvailability(typeSyntax, MessageID.IDS_FeatureUnboundGenericTypesInNameof, diagnostics); + + // From the spec: + // + // Member lookup on an unbound type expression will be performed the same way as for a `this` + // expression within that type declaration. + // + // So we want to just return the originating type symbol as is (e.g. List in nameof(List<>)). + // This is distinctly different than how typeof(List<>) works, where it returns an unbound generic + // type. + } + else + { + // Note: lookup won't have reported this, since the arity was correct. + // CONSIDER: the text of this error message makes sense, but we might want to add a separate code. + + // If the syntax looks like an unbound generic type, then they probably wanted the definition. + // Give an error indicating that the syntax is incorrect and then use the definition. + // CONSIDER: we could construct an unbound generic type symbol, but that would probably be confusing + // outside a typeof. + Error(diagnostics, ErrorCode.ERR_BadArity, typeSyntax, type, MessageID.IDS_SK_TYPE.Localize(), typeArgumentsSyntax.Count); + } - // If the syntax looks like an unbound generic type, then they probably wanted the definition. - // Give an error indicating that the syntax is incorrect and then use the definition. - // CONSIDER: we could construct an unbound generic type symbol, but that would probably be confusing - // outside a typeof. return type; } else diff --git a/src/Compilers/CSharp/Portable/Binder/NameofBinder.cs b/src/Compilers/CSharp/Portable/Binder/NameofBinder.cs index 668cad30a97f3..acf4ba3dfcf59 100644 --- a/src/Compilers/CSharp/Portable/Binder/NameofBinder.cs +++ b/src/Compilers/CSharp/Portable/Binder/NameofBinder.cs @@ -2,7 +2,9 @@ // 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 Microsoft.CodeAnalysis.CSharp.Symbols; +using Microsoft.CodeAnalysis.CSharp.Syntax; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.CSharp @@ -19,19 +21,25 @@ namespace Microsoft.CodeAnalysis.CSharp /// internal sealed class NameofBinder : Binder { - private readonly SyntaxNode _nameofArgument; + private readonly ExpressionSyntax _nameofArgument; private readonly WithTypeParametersBinder? _withTypeParametersBinder; private readonly Binder? _withParametersBinder; private ThreeState _lazyIsNameofOperator; - internal NameofBinder(SyntaxNode nameofArgument, Binder next, WithTypeParametersBinder? withTypeParametersBinder, Binder? withParametersBinder) + private readonly Dictionary? _allowedMap; + + internal NameofBinder(ExpressionSyntax nameofArgument, Binder next, WithTypeParametersBinder? withTypeParametersBinder, Binder? withParametersBinder) : base(next) { _nameofArgument = nameofArgument; _withTypeParametersBinder = withTypeParametersBinder; _withParametersBinder = withParametersBinder; + OpenTypeVisitor.Visit(nameofArgument, out _allowedMap); } + protected override bool IsUnboundTypeAllowed(GenericNameSyntax syntax) + => _allowedMap != null && _allowedMap.TryGetValue(syntax, out bool allowed) && allowed; + private bool IsNameofOperator { get diff --git a/src/Compilers/CSharp/Portable/Binder/OpenTypeVisitor.cs b/src/Compilers/CSharp/Portable/Binder/OpenTypeVisitor.cs new file mode 100644 index 0000000000000..7654a5e40e9e1 --- /dev/null +++ b/src/Compilers/CSharp/Portable/Binder/OpenTypeVisitor.cs @@ -0,0 +1,99 @@ +// 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 Microsoft.CodeAnalysis.CSharp.Syntax; + +namespace Microsoft.CodeAnalysis.CSharp; + +internal partial class Binder +{ + /// + /// This visitor walks over a type expression looking for open types. + /// + /// Open types are allowed if an only if: + /// + /// There is no constructed generic type elsewhere in the visited syntax; and + /// The open type is not used as a type argument or array/pointer/nullable element type. + /// + /// + /// Open types can be used both in typeof(...) and nameof(...) expressions. + /// + protected sealed class OpenTypeVisitor : CSharpSyntaxVisitor + { + private Dictionary? _allowedMap; + private bool _seenConstructed; + + /// The argument to typeof. + /// + /// Keys are GenericNameSyntax nodes representing unbound generic types. + /// Values are false if the node should result in an error and true otherwise. + /// + public static void Visit(ExpressionSyntax typeSyntax, out Dictionary? allowedMap) + { + OpenTypeVisitor visitor = new OpenTypeVisitor(); + visitor.Visit(typeSyntax); + allowedMap = visitor._allowedMap; + } + + public override void VisitGenericName(GenericNameSyntax node) + { + SeparatedSyntaxList typeArguments = node.TypeArgumentList.Arguments; + if (node.IsUnboundGenericName) + { + _allowedMap ??= new Dictionary(); + _allowedMap[node] = !_seenConstructed; + } + else + { + _seenConstructed = true; + foreach (TypeSyntax arg in typeArguments) + { + Visit(arg); + } + } + } + + public override void VisitQualifiedName(QualifiedNameSyntax node) + { + bool seenConstructedBeforeRight = _seenConstructed; + + // Visit Right first because it's smaller (to make backtracking cheaper). + Visit(node.Right); + + bool seenConstructedBeforeLeft = _seenConstructed; + + Visit(node.Left); + + // If the first time we saw a constructed type was in Left, then we need to re-visit Right + if (!seenConstructedBeforeRight && !seenConstructedBeforeLeft && _seenConstructed) + { + Visit(node.Right); + } + } + + public override void VisitAliasQualifiedName(AliasQualifiedNameSyntax node) + { + Visit(node.Name); + } + + public override void VisitArrayType(ArrayTypeSyntax node) + { + _seenConstructed = true; + Visit(node.ElementType); + } + + public override void VisitPointerType(PointerTypeSyntax node) + { + _seenConstructed = true; + Visit(node.ElementType); + } + + public override void VisitNullableType(NullableTypeSyntax node) + { + _seenConstructed = true; + Visit(node.ElementType); + } + } +} diff --git a/src/Compilers/CSharp/Portable/Binder/TypeofBinder.cs b/src/Compilers/CSharp/Portable/Binder/TypeofBinder.cs index 279fbd58e052c..7f0c3d231363e 100644 --- a/src/Compilers/CSharp/Portable/Binder/TypeofBinder.cs +++ b/src/Compilers/CSharp/Portable/Binder/TypeofBinder.cs @@ -36,92 +36,5 @@ protected override bool IsUnboundTypeAllowed(GenericNameSyntax syntax) bool allowed; return _allowedMap != null && _allowedMap.TryGetValue(syntax, out allowed) && allowed; } - - /// - /// This visitor walks over a type expression looking for open types. - /// Open types are allowed if an only if: - /// 1) There is no constructed generic type elsewhere in the visited syntax; and - /// 2) The open type is not used as a type argument or array/pointer/nullable - /// element type. - /// - private class OpenTypeVisitor : CSharpSyntaxVisitor - { - private Dictionary _allowedMap; - private bool _seenConstructed; - - /// The argument to typeof. - /// - /// Keys are GenericNameSyntax nodes representing unbound generic types. - /// Values are false if the node should result in an error and true otherwise. - /// - public static void Visit(ExpressionSyntax typeSyntax, out Dictionary allowedMap) - { - OpenTypeVisitor visitor = new OpenTypeVisitor(); - visitor.Visit(typeSyntax); - allowedMap = visitor._allowedMap; - } - - public override void VisitGenericName(GenericNameSyntax node) - { - SeparatedSyntaxList typeArguments = node.TypeArgumentList.Arguments; - if (node.IsUnboundGenericName) - { - if (_allowedMap == null) - { - _allowedMap = new Dictionary(); - } - _allowedMap[node] = !_seenConstructed; - } - else - { - _seenConstructed = true; - foreach (TypeSyntax arg in typeArguments) - { - Visit(arg); - } - } - } - - public override void VisitQualifiedName(QualifiedNameSyntax node) - { - bool seenConstructedBeforeRight = _seenConstructed; - - // Visit Right first because it's smaller (to make backtracking cheaper). - Visit(node.Right); - - bool seenConstructedBeforeLeft = _seenConstructed; - - Visit(node.Left); - - // If the first time we saw a constructed type was in Left, then we need to re-visit Right - if (!seenConstructedBeforeRight && !seenConstructedBeforeLeft && _seenConstructed) - { - Visit(node.Right); - } - } - - public override void VisitAliasQualifiedName(AliasQualifiedNameSyntax node) - { - Visit(node.Name); - } - - public override void VisitArrayType(ArrayTypeSyntax node) - { - _seenConstructed = true; - Visit(node.ElementType); - } - - public override void VisitPointerType(PointerTypeSyntax node) - { - _seenConstructed = true; - Visit(node.ElementType); - } - - public override void VisitNullableType(NullableTypeSyntax node) - { - _seenConstructed = true; - Visit(node.ElementType); - } - } } } diff --git a/src/Compilers/CSharp/Portable/CSharpResources.resx b/src/Compilers/CSharp/Portable/CSharpResources.resx index 2a355f98b4b39..85dd758873c3f 100644 --- a/src/Compilers/CSharp/Portable/CSharpResources.resx +++ b/src/Compilers/CSharp/Portable/CSharpResources.resx @@ -4932,6 +4932,9 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ nameof operator + + unbound generic types in nameof operator + dictionary initializer diff --git a/src/Compilers/CSharp/Portable/Errors/MessageID.cs b/src/Compilers/CSharp/Portable/Errors/MessageID.cs index ddf0e8d382d5b..0783ddd7a7a0f 100644 --- a/src/Compilers/CSharp/Portable/Errors/MessageID.cs +++ b/src/Compilers/CSharp/Portable/Errors/MessageID.cs @@ -294,6 +294,7 @@ internal enum MessageID IDS_OverloadResolutionPriority = MessageBase + 12848, IDS_FeatureFirstClassSpan = MessageBase + 12849, + IDS_FeatureUnboundGenericTypesInNameof = MessageBase + 12850, } // Message IDs may refer to strings that need to be localized. @@ -476,6 +477,7 @@ internal static LanguageVersion RequiredVersion(this MessageID feature) // C# preview features. case MessageID.IDS_FeatureFieldKeyword: case MessageID.IDS_FeatureFirstClassSpan: + case MessageID.IDS_FeatureUnboundGenericTypesInNameof: return LanguageVersion.Preview; // C# 13.0 features. diff --git a/src/Compilers/CSharp/Portable/Parser/LanguageParser.cs b/src/Compilers/CSharp/Portable/Parser/LanguageParser.cs index 37d5e9817022e..8ed96d2f9c71a 100644 --- a/src/Compilers/CSharp/Portable/Parser/LanguageParser.cs +++ b/src/Compilers/CSharp/Portable/Parser/LanguageParser.cs @@ -6052,6 +6052,15 @@ private ScanTypeFlags ScanPossibleTypeArgumentList( return result; } + // Allow for any chain of errant commas in the generic name. like `Dictionary<,int>` or + // `Dictionary` We still want to think of these as generics, just with missing type-arguments, vs + // some invalid tree-expression that we would otherwise form. + if (this.CurrentToken.Kind == SyntaxKind.CommaToken) + { + lastScannedType = default; + continue; + } + lastScannedType = this.ScanType(out _); switch (lastScannedType) { diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf index 9280853e7d4e2..a5d4e7d459849 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf @@ -2577,6 +2577,11 @@ Inicializátory polí struktury + + unbound generic types in nameof operator + unbound generic types in nameof operator + + unsigned right shift nepodepsaný pravý posun diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf index f1ab55a44fbfe..49661004a2962 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf @@ -2577,6 +2577,11 @@ Strukturfeldinitialisierer + + unbound generic types in nameof operator + unbound generic types in nameof operator + + unsigned right shift Unsignierte Rechtsverschiebung diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf index 8fcc5196b9532..581451baade5e 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf @@ -2577,6 +2577,11 @@ inicializadores de campo de estructura + + unbound generic types in nameof operator + unbound generic types in nameof operator + + unsigned right shift cambio derecho sin firmar diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf index e0a6124ed6b93..246bddbdd5cc6 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf @@ -2577,6 +2577,11 @@ initialiseurs de champ de struct + + unbound generic types in nameof operator + unbound generic types in nameof operator + + unsigned right shift shift droit non signé diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf index 6e9edfb0ce2a4..438db326e9229 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf @@ -2577,6 +2577,11 @@ inizializzatori di campo struct + + unbound generic types in nameof operator + unbound generic types in nameof operator + + unsigned right shift spostamento a destra senza segno diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf index c631942fc593f..e6eb82d333c76 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf @@ -2577,6 +2577,11 @@ 構造体フィールド初期化子 + + unbound generic types in nameof operator + unbound generic types in nameof operator + + unsigned right shift 符号なし右シフト diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf index 4e72992be7e73..303ca7e9dc7a5 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf @@ -2577,6 +2577,11 @@ 구조체 필드 이니셜라이저 + + unbound generic types in nameof operator + unbound generic types in nameof operator + + unsigned right shift 부호 없는 오른쪽 시프트 diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf index 2377df8f9e139..a0d2f13e94d99 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf @@ -2577,6 +2577,11 @@ inicjatory pola struktury + + unbound generic types in nameof operator + unbound generic types in nameof operator + + unsigned right shift niepodpisane przesunięcie w prawo diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf index 5a9e8a14a525c..e6828357934e3 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf @@ -2577,6 +2577,11 @@ inicializadores de campo de struct + + unbound generic types in nameof operator + unbound generic types in nameof operator + + unsigned right shift deslocamento direito não atribuído diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf index afd7cc97f6b04..af40b0f4b46af 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf @@ -2577,6 +2577,11 @@ инициализаторы полей структуры + + unbound generic types in nameof operator + unbound generic types in nameof operator + + unsigned right shift сдвиг вправо без знака diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf index 5feae747be33d..62efb622ebeaf 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf @@ -2577,6 +2577,11 @@ struct alan başlatıcıları + + unbound generic types in nameof operator + unbound generic types in nameof operator + + unsigned right shift işaretsiz sağ kaydırma diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf index bfdbc17e43f04..6f8caf4fd86c1 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf @@ -2577,6 +2577,11 @@ 结构字段初始化表达式 + + unbound generic types in nameof operator + unbound generic types in nameof operator + + unsigned right shift 未签名的右移位 diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf index c510281698946..c8ffa8fac8617 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf @@ -2577,6 +2577,11 @@ 結構欄位初始設定式 + + unbound generic types in nameof operator + unbound generic types in nameof operator + + unsigned right shift 未簽署右移位 diff --git a/src/Compilers/CSharp/Test/Emit3/FlowAnalysis/FlowDiagnosticTests.cs b/src/Compilers/CSharp/Test/Emit3/FlowAnalysis/FlowDiagnosticTests.cs index a85ac73bb0e85..dd184de3140b9 100644 --- a/src/Compilers/CSharp/Test/Emit3/FlowAnalysis/FlowDiagnosticTests.cs +++ b/src/Compilers/CSharp/Test/Emit3/FlowAnalysis/FlowDiagnosticTests.cs @@ -858,10 +858,17 @@ public static int goo(int i) return 1; } }"; - var comp = CreateCompilation(program); - var parseErrors = comp.SyntaxTrees[0].GetDiagnostics(); - var errors = comp.GetDiagnostics(); - Assert.Equal(parseErrors.Count(), errors.Count()); + var comp = CreateCompilation(program).VerifyDiagnostics( + // (6,17): error CS0305: Using the generic method 'Program.goo(int)' requires 1 type arguments + // var s = goo<,int>(123); + Diagnostic(ErrorCode.ERR_BadArity, "goo<,int>").WithArguments("Program.goo(int)", "method", "1").WithLocation(6, 17), + // (6,21): error CS1031: Type expected + // var s = goo<,int>(123); + Diagnostic(ErrorCode.ERR_TypeExpected, ",").WithLocation(6, 21)); + comp.SyntaxTrees[0].GetDiagnostics().Verify( + // (6,21): error CS1031: Type expected + // var s = goo<,int>(123); + Diagnostic(ErrorCode.ERR_TypeExpected, ",").WithLocation(6, 21)); } [Fact] diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/NameOfTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/NameOfTests.cs index 572f5f8ddd22d..216a495096a2a 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/NameOfTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/NameOfTests.cs @@ -4,7 +4,6 @@ #nullable disable -using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; using System.Threading; @@ -16,7 +15,7 @@ namespace Microsoft.CodeAnalysis.CSharp.UnitTests { - public class NameofTests : CSharpTestBase + public sealed class NameofTests : CSharpTestBase { [Fact] public void TestGoodNameofInstances() @@ -249,9 +248,6 @@ class Test // (17,66): error CS1031: Type expected // s = nameof(System.Collections.Generic.Dictionary.KeyCollection); Diagnostic(ErrorCode.ERR_TypeExpected, ">").WithLocation(17, 66), - // (11,27): error CS0305: Using the generic type 'Action' requires 1 type arguments - // s = nameof(System.Action<>); - Diagnostic(ErrorCode.ERR_BadArity, "Action<>").WithArguments("System.Action", "type", "1").WithLocation(11, 27), // (16,20): error CS0103: The name 'List' does not exist in the current context // s = nameof(List.Enumerator); Diagnostic(ErrorCode.ERR_NameNotInContext, "List").WithArguments("List").WithLocation(16, 20), @@ -282,9 +278,6 @@ class Test // (31,20): error CS8083: An alias-qualified name is not an expression. // s = nameof(global::Program); // not an expression Diagnostic(ErrorCode.ERR_AliasQualifiedNameNotAnExpression, "global::Program").WithLocation(31, 20), - // (32,20): error CS0305: Using the generic type 'Test' requires 1 type arguments - // s = nameof(Test<>.s); // inaccessible - Diagnostic(ErrorCode.ERR_BadArity, "Test<>").WithArguments("Test", "type", "1").WithLocation(32, 20), // (32,27): error CS0122: 'Test.s' is inaccessible due to its protection level // s = nameof(Test<>.s); // inaccessible Diagnostic(ErrorCode.ERR_BadAccess, "s").WithArguments("Test.s").WithLocation(32, 27), @@ -2373,5 +2366,709 @@ class Attr : System.Attribute { public Attr(string s) {} }"; CreateCompilation(source, parseOptions: TestOptions.RegularPreview).VerifyDiagnostics(expectedDiagnostics); CreateCompilation(source, parseOptions: TestOptions.Regular11).VerifyDiagnostics(expectedDiagnostics); } + + [Fact] + public void OpenTypeInNameof_Preview() + { + CompileAndVerify(""" + using System; + using System.Collections.Generic; + + var v = nameof(List<>); + Console.WriteLine(v); + """, expectedOutput: "List").VerifyDiagnostics(); + } + + [Fact] + public void OpenTypeInNameof_CSharp13() + { + CreateCompilation(""" + using System; + using System.Collections.Generic; + + var v = nameof(List<>); + Console.WriteLine(v); + """, parseOptions: TestOptions.Regular13).VerifyDiagnostics( + // (4,16): error CS8652: The feature 'unbound generic types in nameof operator' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // var v = nameof(List<>); + Diagnostic(ErrorCode.ERR_FeatureInPreview, "List<>").WithArguments("unbound generic types in nameof operator").WithLocation(4, 16)); + } + + [Fact] + public void OpenTypeInNameof_Next() + { + CompileAndVerify(""" + using System; + using System.Collections.Generic; + + var v = nameof(List<>); + Console.WriteLine(v); + """, parseOptions: TestOptions.RegularNext, expectedOutput: "List").VerifyDiagnostics(); + } + + [Fact] + public void OpenTypeInNameof_CSharp13_Nested1() + { + CreateCompilation(""" + using System; + + var v = nameof(A<>.B); + Console.WriteLine(v); + + class A { public class B; } + """, parseOptions: TestOptions.Regular13).VerifyDiagnostics( + // (3,16): error CS8652: The feature 'unbound generic types in nameof operator' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // var v = nameof(A<>.B); + Diagnostic(ErrorCode.ERR_FeatureInPreview, "A<>").WithArguments("unbound generic types in nameof operator").WithLocation(3, 16)); + } + + [Fact] + public void OpenTypeInNameof_CSharp13_Nested2() + { + CreateCompilation(""" + using System; + + var v = nameof(A.B<>); + Console.WriteLine(v); + + class A { public class B; } + """, parseOptions: TestOptions.Regular13).VerifyDiagnostics( + // (3,23): error CS8652: The feature 'unbound generic types in nameof operator' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // var v = nameof(A.B<>); + Diagnostic(ErrorCode.ERR_FeatureInPreview, "B<>").WithArguments("unbound generic types in nameof operator").WithLocation(3, 23)); + } + + [Fact] + public void OpenTypeInNameof_CSharp13_Nested3() + { + CreateCompilation(""" + using System; + + var v = nameof(A<>.B<>); + Console.WriteLine(v); + + class A { public class B; } + """, parseOptions: TestOptions.Regular13).VerifyDiagnostics( + // (3,16): error CS8652: The feature 'unbound generic types in nameof operator' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // var v = nameof(A<>.B<>); + Diagnostic(ErrorCode.ERR_FeatureInPreview, "A<>").WithArguments("unbound generic types in nameof operator").WithLocation(3, 16), + // (3,20): error CS8652: The feature 'unbound generic types in nameof operator' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // var v = nameof(A<>.B<>); + Diagnostic(ErrorCode.ERR_FeatureInPreview, "B<>").WithArguments("unbound generic types in nameof operator").WithLocation(3, 20)); + } + + [Fact] + public void OpenTypeInNameof_BaseCase() + { + CompileAndVerify(""" + using System; + using System.Collections.Generic; + + var v = nameof(List<>); + Console.WriteLine(v); + """, expectedOutput: "List").VerifyDiagnostics(); + } + + [Fact] + public void OpenTypeInNameof_Nested1() + { + CompileAndVerify(""" + using System; + + var v = nameof(A<>.B); + Console.WriteLine(v); + + class A { public class B; } + """, expectedOutput: "B").VerifyDiagnostics(); + } + + [Fact] + public void OpenTypeInNameof_Nested2() + { + CompileAndVerify(""" + using System; + + var v = nameof(A.B<>); + Console.WriteLine(v); + + class A { public class B; } + """, expectedOutput: "B").VerifyDiagnostics(); + } + + [Fact] + public void OpenTypeInNameof_Nested3() + { + CompileAndVerify(""" + using System; + + var v = nameof(A<>.B<>); + Console.WriteLine(v); + + class A { public class B; } + """, expectedOutput: "B").VerifyDiagnostics(); + } + + [Fact] + public void OpenTypeInNameof_MultipleTypeArguments() + { + CompileAndVerify(""" + using System; + using System.Collections.Generic; + + var v = nameof(Dictionary<,>); + Console.WriteLine(v); + """, expectedOutput: "Dictionary").VerifyDiagnostics(); + } + + [Fact] + public void OpenTypeInNameof_IncorrectTypeArgumentCount1() + { + CreateCompilation(""" + using System; + using System.Collections.Generic; + + var v = nameof(Dictionary<>); + Console.WriteLine(v); + """).VerifyDiagnostics( + // (2,1): hidden CS8019: Unnecessary using directive. + // using System.Collections.Generic; + Diagnostic(ErrorCode.HDN_UnusedUsingDirective, "using System.Collections.Generic;").WithLocation(2, 1), + // (4,16): error CS0305: Using the generic type 'Dictionary' requires 2 type arguments + // var v = nameof(Dictionary<>); + Diagnostic(ErrorCode.ERR_BadArity, "Dictionary<>").WithArguments("System.Collections.Generic.Dictionary", "type", "2").WithLocation(4, 16)); + } + + [Fact] + public void OpenTypeInNameof_IncorrectTypeArgumentCount2() + { + CreateCompilation(""" + using System; + using System.Collections.Generic; + + var v = nameof(List<,>); + Console.WriteLine(v); + """).VerifyDiagnostics( + // (2,1): hidden CS8019: Unnecessary using directive. + // using System.Collections.Generic; + Diagnostic(ErrorCode.HDN_UnusedUsingDirective, "using System.Collections.Generic;").WithLocation(2, 1), + // (4,16): error CS0305: Using the generic type 'List' requires 1 type arguments + // var v = nameof(List<,>); + Diagnostic(ErrorCode.ERR_BadArity, "List<,>").WithArguments("System.Collections.Generic.List", "type", "1").WithLocation(4, 16)); + } + + [Fact] + public void OpenTypeInNameof_NoNestedOpenTypes1() + { + CreateCompilation(""" + using System; + using System.Collections.Generic; + + var v = nameof(List>); + Console.WriteLine(v); + """).VerifyDiagnostics( + // (4,21): error CS7003: Unexpected use of an unbound generic name + // var v = nameof(List>); + Diagnostic(ErrorCode.ERR_UnexpectedUnboundGenericName, "List<>").WithLocation(4, 21)); + } + + [Fact] + public void OpenTypeInNameof_NoNestedOpenTypes2() + { + CreateCompilation(""" + using System; + using System.Collections.Generic; + + var v = nameof(List[]>); + Console.WriteLine(v); + """).VerifyDiagnostics( + // (4,21): error CS7003: Unexpected use of an unbound generic name + // var v = nameof(List>); + Diagnostic(ErrorCode.ERR_UnexpectedUnboundGenericName, "List<>").WithLocation(4, 21)); + } + + [Fact] + public void OpenTypeInNameof_NoNestedOpenTypes3() + { + CreateCompilation(""" + using System; + using System.Collections.Generic; + + var v = nameof(List.Inner>); + Console.WriteLine(v); + + public class Outer { public class Inner { } } + """).VerifyDiagnostics( + // (4,21): error CS7003: Unexpected use of an unbound generic name + // var v = nameof(List.Inner>); + Diagnostic(ErrorCode.ERR_UnexpectedUnboundGenericName, "Outer<>").WithLocation(4, 21)); + } + + [Fact] + public void OpenTypeInNameof_NoNestedOpenTypes4() + { + CreateCompilation(""" + using System; + using System.Collections.Generic; + + var v = nameof(List>); + Console.WriteLine(v); + + public class Outer { public class Inner { } } + """).VerifyDiagnostics( + // (4,27): error CS7003: Unexpected use of an unbound generic name + // var v = nameof(List>); + Diagnostic(ErrorCode.ERR_UnexpectedUnboundGenericName, "Inner<>").WithLocation(4, 27)); + } + + [Fact] + public void Nameof_NestedClosedType1() + { + CompileAndVerify(""" + using System; + using System.Collections.Generic; + + var v = nameof(List>); + Console.WriteLine(v); + """, expectedOutput: "List").VerifyDiagnostics(); + } + + [Fact] + public void Nameof_NestedClosedType2() + { + CompileAndVerify(""" + using System; + using System.Collections.Generic; + + var v = nameof(List[]>); + Console.WriteLine(v); + """, expectedOutput: "List").VerifyDiagnostics(); + } + + [Fact] + public void OpenTypeInNameof_NoPartialOpenTypes_1() + { + CreateCompilation(""" + using System; + using System.Collections.Generic; + + var v = nameof(Dictionary<,int>); + Console.WriteLine(v); + """).VerifyDiagnostics( + // (4,27): error CS1031: Type expected + // var v = nameof(Dictionary<,int>); + Diagnostic(ErrorCode.ERR_TypeExpected, ",").WithLocation(4, 27)); + } + + [Fact] + public void OpenTypeInNameof_NoPartialOpenTypes_2() + { + CreateCompilation(""" + using System; + using System.Collections.Generic; + + var v = nameof(Dictionary); + Console.WriteLine(v); + """).VerifyDiagnostics( + // (4,31): error CS1031: Type expected + // var v = nameof(Dictionary); + Diagnostic(ErrorCode.ERR_TypeExpected, ">").WithLocation(4, 31)); + } + + [Fact] + public void OpenTypeInNameof_MemberAccessThatDoesNotUseTypeArgument() + { + CompileAndVerify(""" + using System; + using System.Collections.Generic; + + var v = nameof(List<>.Count); + Console.WriteLine(v); + """, expectedOutput: "Count").VerifyDiagnostics(); + } + + [Fact] + public void OpenTypeInNameof_MemberAccessThatDoesUseTypeArgument() + { + CompileAndVerify(""" + using System; + + var v = nameof(IGoo<>.Count); + Console.WriteLine(v); + + interface IGoo + { + T Count { get; } + } + """, expectedOutput: "Count").VerifyDiagnostics(); + } + + [Fact] + public void OpenTypeInNameof_MemberAccessThatDoesUseTypeArgument_ReferenceObjectMember() + { + CompileAndVerify(""" + using System; + + var v = nameof(IGoo<>.Count.ToString); + Console.WriteLine(v); + + interface IGoo + { + T Count { get; } + } + """, expectedOutput: "ToString").VerifyDiagnostics(); + } + + [Fact] + public void OpenTypeInNameof_MemberAccessThatDoesUseTypeArgument_ReferenceConstraintMember_Interface() + { + CompileAndVerify(""" + using System; + + var v = nameof(IGoo<>.X.CompareTo); + Console.WriteLine(v); + + interface IGoo where T : IComparable + { + T X { get; } + } + """, expectedOutput: "CompareTo").VerifyDiagnostics(); + } + + [Fact] + public void OpenTypeInNameof_MemberAccessThatDoesUseTypeArgument_ReferenceConstraintMember_ThroughTypeParameter() + { + CompileAndVerify(""" + using System; + + var v = nameof(IGoo<,>.X.CompareTo); + Console.WriteLine(v); + + interface IGoo where T : U where U : IComparable + { + T X { get; } + } + """, expectedOutput: "CompareTo").VerifyDiagnostics(); + } + + [Fact] + public void OpenTypeInNameof_MemberAccessThatDoesUseTypeArgument_ReferenceConstraintMember_Class() + { + CompileAndVerify(""" + using System; + + var v = nameof(IGoo<>.X.Z); + Console.WriteLine(v); + + class Base + { + public int Z { get; } + } + + interface IGoo where T : Base + { + T X { get; } + } + """, expectedOutput: "Z").VerifyDiagnostics(); + } + + [Fact] + public void OpenTypeInNameof_GenericMethod1() + { + CompileAndVerify(""" + using System; + + var v = nameof(IGoo.M); + Console.WriteLine(v); + + interface IGoo + { + void M(); + } + """, expectedOutput: "M").VerifyDiagnostics(); + } + + [Fact] + public void OpenTypeInNameof_GenericMethod2() + { + CreateCompilation(""" + using System; + + var v = nameof(IGoo.M<>); + Console.WriteLine(v); + + interface IGoo + { + void M(); + } + """).VerifyDiagnostics( + // (3,16): error CS0305: Using the generic method group 'M' requires 1 type arguments + // var v = nameof(IGoo.M<>); + Diagnostic(ErrorCode.ERR_BadArity, "IGoo.M<>").WithArguments("M", "method group", "1").WithLocation(3, 16)); + } + + [Fact] + public void OpenTypeInNameof_GenericMethod3() + { + CreateCompilation(""" + using System; + + var v = nameof(IGoo.M); + Console.WriteLine(v); + + interface IGoo + { + void M(); + } + """).VerifyDiagnostics( + // (3,16): error CS8084: Type parameters are not allowed on a method group as an argument to 'nameof'. + // var v = nameof(IGoo.M); + Diagnostic(ErrorCode.ERR_NameofMethodGroupWithTypeParameters, "IGoo.M").WithLocation(3, 16)); + } + + [Fact] + public void NameofFunctionPointer1() + { + CreateCompilation(""" + class C + { + unsafe void M() + { + var v = nameof(delegate*); + } + } + """, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics( + // (5,32): error CS1514: { expected + // var v = nameof(delegate*); + Diagnostic(ErrorCode.ERR_LbraceExpected, "*").WithLocation(5, 32), + // (5,32): warning CS8848: Operator '*' cannot be used here due to precedence. Use parentheses to disambiguate. + // var v = nameof(delegate*); + Diagnostic(ErrorCode.WRN_PrecedenceInversion, "*").WithArguments("*").WithLocation(5, 32), + // (5,33): error CS1525: Invalid expression term '<' + // var v = nameof(delegate*); + Diagnostic(ErrorCode.ERR_InvalidExprTerm, "<").WithArguments("<").WithLocation(5, 33), + // (5,34): error CS1525: Invalid expression term 'int' + // var v = nameof(delegate*); + Diagnostic(ErrorCode.ERR_InvalidExprTerm, "int").WithArguments("int").WithLocation(5, 34), + // (5,38): error CS1525: Invalid expression term ')' + // var v = nameof(delegate*); + Diagnostic(ErrorCode.ERR_InvalidExprTerm, ")").WithArguments(")").WithLocation(5, 38)); + } + + [Fact] + public void NameofFunctionPointer2() + { + CreateCompilation(""" + using System.Collections.Generic; + + class C + { + unsafe void M() + { + var v = nameof(delegate*>); + } + } + """, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics( + // (7,32): error CS1514: { expected + // var v = nameof(delegate*>); + Diagnostic(ErrorCode.ERR_LbraceExpected, "*").WithLocation(7, 32), + // (7,32): warning CS8848: Operator '*' cannot be used here due to precedence. Use parentheses to disambiguate. + // var v = nameof(delegate*>); + Diagnostic(ErrorCode.WRN_PrecedenceInversion, "*").WithArguments("*").WithLocation(7, 32), + // (7,33): error CS1525: Invalid expression term '<' + // var v = nameof(delegate*>); + Diagnostic(ErrorCode.ERR_InvalidExprTerm, "<").WithArguments("<").WithLocation(7, 33), + // (7,34): error CS0119: 'List' is a type, which is not valid in the given context + // var v = nameof(delegate*>); + Diagnostic(ErrorCode.ERR_BadSKunknown, "List<>").WithArguments("System.Collections.Generic.List", "type").WithLocation(7, 34), + // (7,41): error CS1525: Invalid expression term ')' + // var v = nameof(delegate*>); + Diagnostic(ErrorCode.ERR_InvalidExprTerm, ")").WithArguments(")").WithLocation(7, 41)); + } + + [Fact] + public void NameofFunctionPointer3() + { + CreateCompilation(""" + using System.Collections.Generic; + + class C + { + unsafe void M() + { + var v = nameof(List>); + } + } + """, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics( + // (7,13): warning CS0219: The variable 'v' is assigned but its value is never used + // var v = nameof(List>); + Diagnostic(ErrorCode.WRN_UnreferencedVarAssg, "v").WithArguments("v").WithLocation(7, 13), + // (7,29): error CS0306: The type 'delegate*' may not be used as a type argument + // var v = nameof(List>); + Diagnostic(ErrorCode.ERR_BadTypeArgument, "delegate*").WithArguments("delegate*").WithLocation(7, 29)); + } + + [Fact] + public void NameofFunctionPointer4() + { + CreateCompilation(""" + using System.Collections.Generic; + + class C + { + unsafe void M() + { + var v = nameof(List>>); + } + } + """, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics( + // (7,13): warning CS0219: The variable 'v' is assigned but its value is never used + // var v = nameof(List>>); + Diagnostic(ErrorCode.WRN_UnreferencedVarAssg, "v").WithArguments("v").WithLocation(7, 13), + // (7,29): error CS0306: The type 'delegate*>' may not be used as a type argument + // var v = nameof(List>>); + Diagnostic(ErrorCode.ERR_BadTypeArgument, "delegate*>").WithArguments("delegate*>").WithLocation(7, 29), + // (7,39): error CS7003: Unexpected use of an unbound generic name + // var v = nameof(List>>); + Diagnostic(ErrorCode.ERR_UnexpectedUnboundGenericName, "List<>").WithLocation(7, 39)); + } + + [Fact] + public void NameofFunctionPointer5() + { + CreateCompilation(""" + using System.Collections.Generic; + + class D + { + unsafe void M() + { + var v = nameof(D<, delegate*, List<>>); + } + } + """, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics( + // (7,26): error CS1031: Type expected + // var v = nameof(D<, delegate*, List<>>); + Diagnostic(ErrorCode.ERR_TypeExpected, ",").WithLocation(7, 26), + // (7,44): error CS7003: Unexpected use of an unbound generic name + // var v = nameof(D<, delegate*, List<>>); + Diagnostic(ErrorCode.ERR_UnexpectedUnboundGenericName, "List<>").WithLocation(7, 44)); + } + + [Fact] + public void Nameof_NestedOpenType1() + { + CompileAndVerify(""" + using System; + using System.Collections.Generic; + + var v = nameof(List[]>); + Console.WriteLine(v); + """, expectedOutput: "List").VerifyDiagnostics(); + } + + [Fact] + public void Nameof_NestedOpenType2() + { + CreateCompilation(""" + using System; + using System.Collections.Generic; + + var v = nameof(List[]>); + Console.WriteLine(v); + """).VerifyDiagnostics( + // (4,21): error CS7003: Unexpected use of an unbound generic name + // var v = nameof(List[]>); + Diagnostic(ErrorCode.ERR_UnexpectedUnboundGenericName, "List<>").WithLocation(4, 21)); + } + + [Fact] + public void Nameof_NestedOpenType3() + { + CompileAndVerify(""" + #nullable enable + using System; + using System.Collections.Generic; + + var v = nameof(List?>); + Console.WriteLine(v); + """, expectedOutput: "List").VerifyDiagnostics(); + } + + [Fact] + public void Nameof_NestedOpenType4() + { + CreateCompilation(""" + #nullable enable + using System; + using System.Collections.Generic; + + var v = nameof(List?>); + Console.WriteLine(v); + """).VerifyDiagnostics( + // (5,21): error CS7003: Unexpected use of an unbound generic name + // var v = nameof(List?>); + Diagnostic(ErrorCode.ERR_UnexpectedUnboundGenericName, "List<>").WithLocation(5, 21)); + } + + [Fact] + public void Nameof_AliasQualifiedName() + { + CompileAndVerify(""" + using System; + + var v = nameof(global::System.Collections.Generic.List<>); + Console.WriteLine(v); + """, expectedOutput: "List").VerifyDiagnostics(); + } + + [Theory] + [InlineData("IGoo<>")] + [InlineData("IGoo<>.Count")] + public void OpenTypeInNameof_SemanticModelTest1(string nameofTypeString) + { + var compilation = CreateCompilation($$""" + using System; + + var v1 = nameof({{nameofTypeString}}); + var v2 = typeof(IGoo<>); + Console.WriteLine(v1 + v2); + + interface IGoo { public T Count { get; } } + """).VerifyDiagnostics(); + var tree = compilation.SyntaxTrees.Single(); + var semanticModel = compilation.GetSemanticModel(tree); + + var root = tree.GetRoot(); + + var firstGeneric = root.DescendantNodes().OfType().First(); + var lastGeneric = root.DescendantNodes().OfType().Last(); + + Assert.NotSame(firstGeneric, lastGeneric); + + // Ensure the type inside the nameof is the same as the type inside the typeof. + var nameofType = semanticModel.GetTypeInfo(firstGeneric).Type; + var typeofType = semanticModel.GetTypeInfo(lastGeneric).Type; + + Assert.NotNull(nameofType); + Assert.NotNull(typeofType); + + // typeof will produce IGoo<>, while nameof will produce IGoo. These are distinctly different types (the + // latter has members for example). + Assert.NotEqual(nameofType, typeofType); + + Assert.True(nameofType.IsDefinition); + Assert.False(nameofType.IsUnboundGenericType()); + + Assert.False(typeofType.IsDefinition); + Assert.True(typeofType.IsUnboundGenericType()); + + Assert.Empty(typeofType.GetMembers("Count")); + Assert.Single(nameofType.GetMembers("Count")); + + var igooType = compilation.GetTypeByMetadataName("IGoo`1").GetPublicSymbol(); + Assert.NotNull(igooType); + + Assert.Equal(igooType, nameofType); + } } } diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/TypeOfTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/TypeOfTests.cs index 61ee254c26203..fbb75ecdb1d65 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/TypeOfTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/TypeOfTests.cs @@ -37,7 +37,91 @@ public C(int i) Assert.Equal("C..ctor(System.Int32 i)", symbolInfo.Symbol.ToTestDisplayString()); var typeInfo = model.GetTypeInfo(node); Assert.Equal("C", typeInfo.Type.ToTestDisplayString()); + } + + [Fact] + public void TypeofPointer() + { + CreateCompilation(""" + class C + { + unsafe void M() + { + var v = typeof(int*); + } + } + """, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(); + } + + [Fact] + public void TypeofFunctionPointer1() + { + CreateCompilation(""" + class C + { + unsafe void M() + { + var v = typeof(delegate*); + } + } + """, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(); + } + + [Fact] + public void TypeofFunctionPointer2() + { + CreateCompilation(""" + using System.Collections.Generic; + + class C + { + unsafe void M() + { + var v = typeof(delegate*,int>); + } + } + """, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(); + } + + [Fact] + public void TypeofFunctionPointer3() + { + CreateCompilation(""" + using System.Collections.Generic; + + class C + { + unsafe void M() + { + var v = typeof(delegate*,int>); + } + } + """, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics( + // (7,34): error CS7003: Unexpected use of an unbound generic name + // var v = typeof(delegate*,int>); + Diagnostic(ErrorCode.ERR_UnexpectedUnboundGenericName, "List<>").WithLocation(7, 34)); + } + + [Fact] + public void TypeofFunctionPointer4() + { + CreateCompilation(""" + using System.Collections.Generic; + class D + { + unsafe void M() + { + var v = typeof(D<, delegate*, List<>>); + } + } + """, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics( + // (7,26): error CS1031: Type expected + // var v = typeof(D<, delegate*, List<>>); + Diagnostic(ErrorCode.ERR_TypeExpected, ",").WithLocation(7, 26), + // (7,44): error CS7003: Unexpected use of an unbound generic name + // var v = typeof(D<, delegate*, List<>>); + Diagnostic(ErrorCode.ERR_UnexpectedUnboundGenericName, "List<>").WithLocation(7, 44)); } } } diff --git a/src/Compilers/CSharp/Test/Syntax/Parsing/TypeArgumentListParsingTests.cs b/src/Compilers/CSharp/Test/Syntax/Parsing/TypeArgumentListParsingTests.cs index 9a47468d3af2b..4a14eda2eeba3 100644 --- a/src/Compilers/CSharp/Test/Syntax/Parsing/TypeArgumentListParsingTests.cs +++ b/src/Compilers/CSharp/Test/Syntax/Parsing/TypeArgumentListParsingTests.cs @@ -2,19 +2,17 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using Roslyn.Test.Utilities; using Xunit; using Xunit.Abstractions; namespace Microsoft.CodeAnalysis.CSharp.UnitTests { - public class TypeArgumentListParsingTests : ParsingTests + public sealed class TypeArgumentListParsingTests : ParsingTests { public TypeArgumentListParsingTests(ITestOutputHelper output) : base(output) { } - protected override SyntaxTree ParseTree(string text, CSharpParseOptions options) + protected override SyntaxTree ParseTree(string text, CSharpParseOptions? options) { return SyntaxFactory.ParseSyntaxTree(text, options: options); } @@ -2826,5 +2824,877 @@ void M() } EOF(); } + + [Fact] + public void TestGenericWithExtraCommasAndMissingTypes1() + { + UsingTree(""" + class C + { + void M() + { + var added = Goo.Instance; + } + } + """, + // (5,32): error CS1031: Type expected + // var added = Goo.Instance; + Diagnostic(ErrorCode.ERR_TypeExpected, ",").WithLocation(5, 32), + // (5,33): error CS1031: Type expected + // var added = Goo.Instance; + Diagnostic(ErrorCode.ERR_TypeExpected, ">").WithLocation(5, 33)); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.MethodDeclaration); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.VoidKeyword); + } + N(SyntaxKind.IdentifierToken, "M"); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.Block); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.LocalDeclarationStatement); + { + N(SyntaxKind.VariableDeclaration); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "var"); + } + N(SyntaxKind.VariableDeclarator); + { + N(SyntaxKind.IdentifierToken, "added"); + N(SyntaxKind.EqualsValueClause); + { + N(SyntaxKind.EqualsToken); + N(SyntaxKind.SimpleMemberAccessExpression); + { + N(SyntaxKind.GenericName); + { + N(SyntaxKind.IdentifierToken, "Goo"); + N(SyntaxKind.TypeArgumentList); + { + N(SyntaxKind.LessThanToken); + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.StringKeyword); + } + N(SyntaxKind.CommaToken); + M(SyntaxKind.IdentifierName); + { + M(SyntaxKind.IdentifierToken); + } + N(SyntaxKind.CommaToken); + M(SyntaxKind.IdentifierName); + { + M(SyntaxKind.IdentifierToken); + } + N(SyntaxKind.GreaterThanToken); + } + } + N(SyntaxKind.DotToken); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Instance"); + } + } + } + } + } + N(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.CloseBraceToken); + } + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void TestGenericWithExtraCommasAndMissingTypes2() + { + UsingTree(""" + class C + { + void M() + { + var added = Goo.Instance; + } + } + """, + // (5,28): error CS1031: Type expected + // var added = Goo.Instance; + Diagnostic(ErrorCode.ERR_TypeExpected, ",").WithLocation(5, 28), + // (5,29): error CS1031: Type expected + // var added = Goo.Instance; + Diagnostic(ErrorCode.ERR_TypeExpected, ">").WithLocation(5, 29)); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.MethodDeclaration); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.VoidKeyword); + } + N(SyntaxKind.IdentifierToken, "M"); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.Block); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.LocalDeclarationStatement); + { + N(SyntaxKind.VariableDeclaration); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "var"); + } + N(SyntaxKind.VariableDeclarator); + { + N(SyntaxKind.IdentifierToken, "added"); + N(SyntaxKind.EqualsValueClause); + { + N(SyntaxKind.EqualsToken); + N(SyntaxKind.SimpleMemberAccessExpression); + { + N(SyntaxKind.GenericName); + { + N(SyntaxKind.IdentifierToken, "Goo"); + N(SyntaxKind.TypeArgumentList); + { + N(SyntaxKind.LessThanToken); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Id"); + } + N(SyntaxKind.CommaToken); + M(SyntaxKind.IdentifierName); + { + M(SyntaxKind.IdentifierToken); + } + N(SyntaxKind.CommaToken); + M(SyntaxKind.IdentifierName); + { + M(SyntaxKind.IdentifierToken); + } + N(SyntaxKind.GreaterThanToken); + } + } + N(SyntaxKind.DotToken); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Instance"); + } + } + } + } + } + N(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.CloseBraceToken); + } + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void TestGenericWithExtraCommasAndMissingTypes3() + { + UsingTree(""" + class C + { + void M() + { + var added = Goo<,Id,>.Instance; + } + } + """, + // (5,25): error CS1031: Type expected + // var added = Goo<,Id,>.Instance; + Diagnostic(ErrorCode.ERR_TypeExpected, ",").WithLocation(5, 25), + // (5,29): error CS1031: Type expected + // var added = Goo<,Id,>.Instance; + Diagnostic(ErrorCode.ERR_TypeExpected, ">").WithLocation(5, 29)); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.MethodDeclaration); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.VoidKeyword); + } + N(SyntaxKind.IdentifierToken, "M"); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.Block); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.LocalDeclarationStatement); + { + N(SyntaxKind.VariableDeclaration); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "var"); + } + N(SyntaxKind.VariableDeclarator); + { + N(SyntaxKind.IdentifierToken, "added"); + N(SyntaxKind.EqualsValueClause); + { + N(SyntaxKind.EqualsToken); + N(SyntaxKind.SimpleMemberAccessExpression); + { + N(SyntaxKind.GenericName); + { + N(SyntaxKind.IdentifierToken, "Goo"); + N(SyntaxKind.TypeArgumentList); + { + N(SyntaxKind.LessThanToken); + M(SyntaxKind.IdentifierName); + { + M(SyntaxKind.IdentifierToken); + } + N(SyntaxKind.CommaToken); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Id"); + } + N(SyntaxKind.CommaToken); + M(SyntaxKind.IdentifierName); + { + M(SyntaxKind.IdentifierToken); + } + N(SyntaxKind.GreaterThanToken); + } + } + N(SyntaxKind.DotToken); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Instance"); + } + } + } + } + } + N(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.CloseBraceToken); + } + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void TestGenericWithExtraCommasAndMissingTypes4() + { + UsingTree(""" + class C + { + void M() + { + var added = Goo<,,Id>.Instance; + } + } + """, + // (5,25): error CS1031: Type expected + // var added = Goo<,,Id>.Instance; + Diagnostic(ErrorCode.ERR_TypeExpected, ",").WithLocation(5, 25), + // (5,26): error CS1031: Type expected + // var added = Goo<,,Id>.Instance; + Diagnostic(ErrorCode.ERR_TypeExpected, ",").WithLocation(5, 26)); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.MethodDeclaration); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.VoidKeyword); + } + N(SyntaxKind.IdentifierToken, "M"); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.Block); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.LocalDeclarationStatement); + { + N(SyntaxKind.VariableDeclaration); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "var"); + } + N(SyntaxKind.VariableDeclarator); + { + N(SyntaxKind.IdentifierToken, "added"); + N(SyntaxKind.EqualsValueClause); + { + N(SyntaxKind.EqualsToken); + N(SyntaxKind.SimpleMemberAccessExpression); + { + N(SyntaxKind.GenericName); + { + N(SyntaxKind.IdentifierToken, "Goo"); + N(SyntaxKind.TypeArgumentList); + { + N(SyntaxKind.LessThanToken); + M(SyntaxKind.IdentifierName); + { + M(SyntaxKind.IdentifierToken); + } + N(SyntaxKind.CommaToken); + M(SyntaxKind.IdentifierName); + { + M(SyntaxKind.IdentifierToken); + } + N(SyntaxKind.CommaToken); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Id"); + } + N(SyntaxKind.GreaterThanToken); + } + } + N(SyntaxKind.DotToken); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Instance"); + } + } + } + } + } + N(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.CloseBraceToken); + } + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void TestGenericWithExtraCommasAndMissingTypes5() + { + UsingTree(""" + class C + { + void M() + { + var added = Goo.Instance; + } + } + """, + // (5,30): error CS1031: Type expected + // var added = Goo.Instance; + Diagnostic(ErrorCode.ERR_TypeExpected, ",").WithLocation(5, 30), + // (5,31): error CS1031: Type expected + // var added = Goo.Instance; + Diagnostic(ErrorCode.ERR_TypeExpected, ">").WithLocation(5, 31)); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.MethodDeclaration); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.VoidKeyword); + } + N(SyntaxKind.IdentifierToken, "M"); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.Block); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.LocalDeclarationStatement); + { + N(SyntaxKind.VariableDeclaration); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "var"); + } + N(SyntaxKind.VariableDeclarator); + { + N(SyntaxKind.IdentifierToken, "added"); + N(SyntaxKind.EqualsValueClause); + { + N(SyntaxKind.EqualsToken); + N(SyntaxKind.SimpleMemberAccessExpression); + { + N(SyntaxKind.GenericName); + { + N(SyntaxKind.IdentifierToken, "Goo"); + N(SyntaxKind.TypeArgumentList); + { + N(SyntaxKind.LessThanToken); + N(SyntaxKind.ArrayType); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Id"); + } + N(SyntaxKind.ArrayRankSpecifier); + { + N(SyntaxKind.OpenBracketToken); + N(SyntaxKind.OmittedArraySizeExpression); + { + N(SyntaxKind.OmittedArraySizeExpressionToken); + } + N(SyntaxKind.CloseBracketToken); + } + } + N(SyntaxKind.CommaToken); + M(SyntaxKind.IdentifierName); + { + M(SyntaxKind.IdentifierToken); + } + N(SyntaxKind.CommaToken); + M(SyntaxKind.IdentifierName); + { + M(SyntaxKind.IdentifierToken); + } + N(SyntaxKind.GreaterThanToken); + } + } + N(SyntaxKind.DotToken); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Instance"); + } + } + } + } + } + N(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.CloseBraceToken); + } + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void TestGenericWithExtraCommasAndMissingTypes6() + { + UsingTree(""" + class C + { + void M() + { + var added = Goo<(int i, int j),,>.Instance; + } + } + """, + // (5,40): error CS1031: Type expected + // var added = Goo<(int i, int j),,>.Instance; + Diagnostic(ErrorCode.ERR_TypeExpected, ",").WithLocation(5, 40), + // (5,41): error CS1031: Type expected + // var added = Goo<(int i, int j),,>.Instance; + Diagnostic(ErrorCode.ERR_TypeExpected, ">").WithLocation(5, 41)); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.MethodDeclaration); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.VoidKeyword); + } + N(SyntaxKind.IdentifierToken, "M"); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.Block); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.LocalDeclarationStatement); + { + N(SyntaxKind.VariableDeclaration); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "var"); + } + N(SyntaxKind.VariableDeclarator); + { + N(SyntaxKind.IdentifierToken, "added"); + N(SyntaxKind.EqualsValueClause); + { + N(SyntaxKind.EqualsToken); + N(SyntaxKind.SimpleMemberAccessExpression); + { + N(SyntaxKind.GenericName); + { + N(SyntaxKind.IdentifierToken, "Goo"); + N(SyntaxKind.TypeArgumentList); + { + N(SyntaxKind.LessThanToken); + N(SyntaxKind.TupleType); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.TupleElement); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.IntKeyword); + } + N(SyntaxKind.IdentifierToken, "i"); + } + N(SyntaxKind.CommaToken); + N(SyntaxKind.TupleElement); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.IntKeyword); + } + N(SyntaxKind.IdentifierToken, "j"); + } + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.CommaToken); + M(SyntaxKind.IdentifierName); + { + M(SyntaxKind.IdentifierToken); + } + N(SyntaxKind.CommaToken); + M(SyntaxKind.IdentifierName); + { + M(SyntaxKind.IdentifierToken); + } + N(SyntaxKind.GreaterThanToken); + } + } + N(SyntaxKind.DotToken); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Instance"); + } + } + } + } + } + N(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.CloseBraceToken); + } + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void TestGenericWithExtraCommasAndMissingTypes7() + { + UsingTree(""" + class C + { + void M() + { + var added = Goo,,>.Instance; + } + } + """, + // (5,32): error CS1031: Type expected + // var added = Goo,,>.Instance; + Diagnostic(ErrorCode.ERR_TypeExpected, ",").WithLocation(5, 32), + // (5,33): error CS1031: Type expected + // var added = Goo,,>.Instance; + Diagnostic(ErrorCode.ERR_TypeExpected, ">").WithLocation(5, 33)); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.MethodDeclaration); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.VoidKeyword); + } + N(SyntaxKind.IdentifierToken, "M"); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.Block); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.LocalDeclarationStatement); + { + N(SyntaxKind.VariableDeclaration); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "var"); + } + N(SyntaxKind.VariableDeclarator); + { + N(SyntaxKind.IdentifierToken, "added"); + N(SyntaxKind.EqualsValueClause); + { + N(SyntaxKind.EqualsToken); + N(SyntaxKind.SimpleMemberAccessExpression); + { + N(SyntaxKind.GenericName); + { + N(SyntaxKind.IdentifierToken, "Goo"); + N(SyntaxKind.TypeArgumentList); + { + N(SyntaxKind.LessThanToken); + N(SyntaxKind.GenericName); + { + N(SyntaxKind.IdentifierToken, "K"); + N(SyntaxKind.TypeArgumentList); + { + N(SyntaxKind.LessThanToken); + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.IntKeyword); + } + N(SyntaxKind.GreaterThanToken); + } + } + N(SyntaxKind.CommaToken); + M(SyntaxKind.IdentifierName); + { + M(SyntaxKind.IdentifierToken); + } + N(SyntaxKind.CommaToken); + M(SyntaxKind.IdentifierName); + { + M(SyntaxKind.IdentifierToken); + } + N(SyntaxKind.GreaterThanToken); + } + } + N(SyntaxKind.DotToken); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Instance"); + } + } + } + } + } + N(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.CloseBraceToken); + } + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void TestGenericWithExtraCommasAndMissingTypes8() + { + UsingTree(""" + class C + { + void M() + { + var added = Goo,,>.Instance; + } + } + """, + // (5,31): error CS1031: Type expected + // var added = Goo,,>.Instance; + Diagnostic(ErrorCode.ERR_TypeExpected, ",").WithLocation(5, 31), + // (5,32): error CS1031: Type expected + // var added = Goo,,>.Instance; + Diagnostic(ErrorCode.ERR_TypeExpected, ">").WithLocation(5, 32), + // (5,34): error CS1031: Type expected + // var added = Goo,,>.Instance; + Diagnostic(ErrorCode.ERR_TypeExpected, ",").WithLocation(5, 34), + // (5,35): error CS1031: Type expected + // var added = Goo,,>.Instance; + Diagnostic(ErrorCode.ERR_TypeExpected, ">").WithLocation(5, 35)); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.MethodDeclaration); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.VoidKeyword); + } + N(SyntaxKind.IdentifierToken, "M"); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.Block); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.LocalDeclarationStatement); + { + N(SyntaxKind.VariableDeclaration); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "var"); + } + N(SyntaxKind.VariableDeclarator); + { + N(SyntaxKind.IdentifierToken, "added"); + N(SyntaxKind.EqualsValueClause); + { + N(SyntaxKind.EqualsToken); + N(SyntaxKind.SimpleMemberAccessExpression); + { + N(SyntaxKind.GenericName); + { + N(SyntaxKind.IdentifierToken, "Goo"); + N(SyntaxKind.TypeArgumentList); + { + N(SyntaxKind.LessThanToken); + N(SyntaxKind.GenericName); + { + N(SyntaxKind.IdentifierToken, "K"); + N(SyntaxKind.TypeArgumentList); + { + N(SyntaxKind.LessThanToken); + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.IntKeyword); + } + N(SyntaxKind.CommaToken); + M(SyntaxKind.IdentifierName); + { + M(SyntaxKind.IdentifierToken); + } + N(SyntaxKind.CommaToken); + M(SyntaxKind.IdentifierName); + { + M(SyntaxKind.IdentifierToken); + } + N(SyntaxKind.GreaterThanToken); + } + } + N(SyntaxKind.CommaToken); + M(SyntaxKind.IdentifierName); + { + M(SyntaxKind.IdentifierToken); + } + N(SyntaxKind.CommaToken); + M(SyntaxKind.IdentifierName); + { + M(SyntaxKind.IdentifierToken); + } + N(SyntaxKind.GreaterThanToken); + } + } + N(SyntaxKind.DotToken); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Instance"); + } + } + } + } + } + N(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.CloseBraceToken); + } + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } } }