From ed3a094d46964088643d2eaa8f0826f0fbf6bcbe Mon Sep 17 00:00:00 2001 From: Chris Sienkiewicz Date: Mon, 10 Dec 2018 12:24:05 -0800 Subject: [PATCH 01/10] Add syntax for await using var x = ... - Update syntax nodes - Add parsing tests --- .../Syntax.xml.Internal.Generated.cs | 90 ++++++++++--- .../Generated/Syntax.xml.Main.Generated.cs | 19 ++- .../Generated/Syntax.xml.Syntax.Generated.cs | 45 +++++-- .../CSharp/Portable/Parser/LanguageParser.cs | 18 ++- .../CSharp/Portable/PublicAPI.Unshipped.txt | 6 +- ...StackAllocArrayCreationExpressionSyntax.cs | 4 +- .../CSharp/Portable/Syntax/Syntax.xml | 3 + .../Generated/Syntax.Test.xml.Generated.cs | 8 +- .../Syntax/Parsing/StatementParsingTests.cs | 126 ++++++++++++++++++ 9 files changed, 267 insertions(+), 52 deletions(-) diff --git a/src/Compilers/CSharp/Portable/Generated/Syntax.xml.Internal.Generated.cs b/src/Compilers/CSharp/Portable/Generated/Syntax.xml.Internal.Generated.cs index 4bdc74e1927d5..943a03db47332 100644 --- a/src/Compilers/CSharp/Portable/Generated/Syntax.xml.Internal.Generated.cs +++ b/src/Compilers/CSharp/Portable/Generated/Syntax.xml.Internal.Generated.cs @@ -12472,15 +12472,21 @@ static LocalFunctionStatementSyntax() internal sealed partial class LocalDeclarationStatementSyntax : StatementSyntax { + internal readonly SyntaxToken awaitKeyword; internal readonly SyntaxToken usingKeyword; internal readonly GreenNode modifiers; internal readonly VariableDeclarationSyntax declaration; internal readonly SyntaxToken semicolonToken; - internal LocalDeclarationStatementSyntax(SyntaxKind kind, SyntaxToken usingKeyword, GreenNode modifiers, VariableDeclarationSyntax declaration, SyntaxToken semicolonToken, DiagnosticInfo[] diagnostics, SyntaxAnnotation[] annotations) + internal LocalDeclarationStatementSyntax(SyntaxKind kind, SyntaxToken awaitKeyword, SyntaxToken usingKeyword, GreenNode modifiers, VariableDeclarationSyntax declaration, SyntaxToken semicolonToken, DiagnosticInfo[] diagnostics, SyntaxAnnotation[] annotations) : base(kind, diagnostics, annotations) { - this.SlotCount = 4; + this.SlotCount = 5; + if (awaitKeyword != null) + { + this.AdjustFlagsAndWidth(awaitKeyword); + this.awaitKeyword = awaitKeyword; + } if (usingKeyword != null) { this.AdjustFlagsAndWidth(usingKeyword); @@ -12498,11 +12504,16 @@ internal LocalDeclarationStatementSyntax(SyntaxKind kind, SyntaxToken usingKeywo } - internal LocalDeclarationStatementSyntax(SyntaxKind kind, SyntaxToken usingKeyword, GreenNode modifiers, VariableDeclarationSyntax declaration, SyntaxToken semicolonToken, SyntaxFactoryContext context) + internal LocalDeclarationStatementSyntax(SyntaxKind kind, SyntaxToken awaitKeyword, SyntaxToken usingKeyword, GreenNode modifiers, VariableDeclarationSyntax declaration, SyntaxToken semicolonToken, SyntaxFactoryContext context) : base(kind) { this.SetFactoryContext(context); - this.SlotCount = 4; + this.SlotCount = 5; + if (awaitKeyword != null) + { + this.AdjustFlagsAndWidth(awaitKeyword); + this.awaitKeyword = awaitKeyword; + } if (usingKeyword != null) { this.AdjustFlagsAndWidth(usingKeyword); @@ -12520,10 +12531,15 @@ internal LocalDeclarationStatementSyntax(SyntaxKind kind, SyntaxToken usingKeywo } - internal LocalDeclarationStatementSyntax(SyntaxKind kind, SyntaxToken usingKeyword, GreenNode modifiers, VariableDeclarationSyntax declaration, SyntaxToken semicolonToken) + internal LocalDeclarationStatementSyntax(SyntaxKind kind, SyntaxToken awaitKeyword, SyntaxToken usingKeyword, GreenNode modifiers, VariableDeclarationSyntax declaration, SyntaxToken semicolonToken) : base(kind) { - this.SlotCount = 4; + this.SlotCount = 5; + if (awaitKeyword != null) + { + this.AdjustFlagsAndWidth(awaitKeyword); + this.awaitKeyword = awaitKeyword; + } if (usingKeyword != null) { this.AdjustFlagsAndWidth(usingKeyword); @@ -12540,6 +12556,7 @@ internal LocalDeclarationStatementSyntax(SyntaxKind kind, SyntaxToken usingKeywo this.semicolonToken = semicolonToken; } + public SyntaxToken AwaitKeyword { get { return this.awaitKeyword; } } public SyntaxToken UsingKeyword { get { return this.usingKeyword; } } /// Gets the modifier list. public Microsoft.CodeAnalysis.Syntax.InternalSyntax.SyntaxList Modifiers { get { return new Microsoft.CodeAnalysis.Syntax.InternalSyntax.SyntaxList(this.modifiers); } } @@ -12550,10 +12567,11 @@ internal override GreenNode GetSlot(int index) { switch (index) { - case 0: return this.usingKeyword; - case 1: return this.modifiers; - case 2: return this.declaration; - case 3: return this.semicolonToken; + case 0: return this.awaitKeyword; + case 1: return this.usingKeyword; + case 2: return this.modifiers; + case 3: return this.declaration; + case 4: return this.semicolonToken; default: return null; } } @@ -12573,11 +12591,11 @@ public override void Accept(CSharpSyntaxVisitor visitor) visitor.VisitLocalDeclarationStatement(this); } - public LocalDeclarationStatementSyntax Update(SyntaxToken usingKeyword, Microsoft.CodeAnalysis.Syntax.InternalSyntax.SyntaxList modifiers, VariableDeclarationSyntax declaration, SyntaxToken semicolonToken) + public LocalDeclarationStatementSyntax Update(SyntaxToken awaitKeyword, SyntaxToken usingKeyword, Microsoft.CodeAnalysis.Syntax.InternalSyntax.SyntaxList modifiers, VariableDeclarationSyntax declaration, SyntaxToken semicolonToken) { - if (usingKeyword != this.UsingKeyword || modifiers != this.Modifiers || declaration != this.Declaration || semicolonToken != this.SemicolonToken) + if (awaitKeyword != this.AwaitKeyword || usingKeyword != this.UsingKeyword || modifiers != this.Modifiers || declaration != this.Declaration || semicolonToken != this.SemicolonToken) { - var newNode = SyntaxFactory.LocalDeclarationStatement(usingKeyword, modifiers, declaration, semicolonToken); + var newNode = SyntaxFactory.LocalDeclarationStatement(awaitKeyword, usingKeyword, modifiers, declaration, semicolonToken); var diags = this.GetDiagnostics(); if (diags != null && diags.Length > 0) newNode = newNode.WithDiagnosticsGreen(diags); @@ -12592,18 +12610,24 @@ public LocalDeclarationStatementSyntax Update(SyntaxToken usingKeyword, Microsof internal override GreenNode SetDiagnostics(DiagnosticInfo[] diagnostics) { - return new LocalDeclarationStatementSyntax(this.Kind, this.usingKeyword, this.modifiers, this.declaration, this.semicolonToken, diagnostics, GetAnnotations()); + return new LocalDeclarationStatementSyntax(this.Kind, this.awaitKeyword, this.usingKeyword, this.modifiers, this.declaration, this.semicolonToken, diagnostics, GetAnnotations()); } internal override GreenNode SetAnnotations(SyntaxAnnotation[] annotations) { - return new LocalDeclarationStatementSyntax(this.Kind, this.usingKeyword, this.modifiers, this.declaration, this.semicolonToken, GetDiagnostics(), annotations); + return new LocalDeclarationStatementSyntax(this.Kind, this.awaitKeyword, this.usingKeyword, this.modifiers, this.declaration, this.semicolonToken, GetDiagnostics(), annotations); } internal LocalDeclarationStatementSyntax(ObjectReader reader) : base(reader) { - this.SlotCount = 4; + this.SlotCount = 5; + var awaitKeyword = (SyntaxToken)reader.ReadValue(); + if (awaitKeyword != null) + { + AdjustFlagsAndWidth(awaitKeyword); + this.awaitKeyword = awaitKeyword; + } var usingKeyword = (SyntaxToken)reader.ReadValue(); if (usingKeyword != null) { @@ -12633,6 +12657,7 @@ internal LocalDeclarationStatementSyntax(ObjectReader reader) internal override void WriteTo(ObjectWriter writer) { base.WriteTo(writer); + writer.WriteValue(this.awaitKeyword); writer.WriteValue(this.usingKeyword); writer.WriteValue(this.modifiers); writer.WriteValue(this.declaration); @@ -37020,11 +37045,12 @@ public override CSharpSyntaxNode VisitLocalFunctionStatement(LocalFunctionStatem public override CSharpSyntaxNode VisitLocalDeclarationStatement(LocalDeclarationStatementSyntax node) { + var awaitKeyword = (SyntaxToken)this.Visit(node.AwaitKeyword); var usingKeyword = (SyntaxToken)this.Visit(node.UsingKeyword); var modifiers = this.VisitList(node.Modifiers); var declaration = (VariableDeclarationSyntax)this.Visit(node.Declaration); var semicolonToken = (SyntaxToken)this.Visit(node.SemicolonToken); - return node.Update(usingKeyword, modifiers, declaration, semicolonToken); + return node.Update(awaitKeyword, usingKeyword, modifiers, declaration, semicolonToken); } public override CSharpSyntaxNode VisitVariableDeclaration(VariableDeclarationSyntax node) @@ -40904,9 +40930,20 @@ public LocalFunctionStatementSyntax LocalFunctionStatement(Microsoft.CodeAnalysi return new LocalFunctionStatementSyntax(SyntaxKind.LocalFunctionStatement, modifiers.Node, returnType, identifier, typeParameterList, parameterList, constraintClauses.Node, body, expressionBody, semicolonToken, this.context); } - public LocalDeclarationStatementSyntax LocalDeclarationStatement(SyntaxToken usingKeyword, Microsoft.CodeAnalysis.Syntax.InternalSyntax.SyntaxList modifiers, VariableDeclarationSyntax declaration, SyntaxToken semicolonToken) + public LocalDeclarationStatementSyntax LocalDeclarationStatement(SyntaxToken awaitKeyword, SyntaxToken usingKeyword, Microsoft.CodeAnalysis.Syntax.InternalSyntax.SyntaxList modifiers, VariableDeclarationSyntax declaration, SyntaxToken semicolonToken) { #if DEBUG + if (awaitKeyword != null) + { + switch (awaitKeyword.Kind) + { + case SyntaxKind.AwaitKeyword: + case SyntaxKind.None: + break; + default: + throw new ArgumentException("awaitKeyword"); + } + } if (usingKeyword != null) { switch (usingKeyword.Kind) @@ -40931,7 +40968,7 @@ public LocalDeclarationStatementSyntax LocalDeclarationStatement(SyntaxToken usi } #endif - return new LocalDeclarationStatementSyntax(SyntaxKind.LocalDeclarationStatement, usingKeyword, modifiers.Node, declaration, semicolonToken, this.context); + return new LocalDeclarationStatementSyntax(SyntaxKind.LocalDeclarationStatement, awaitKeyword, usingKeyword, modifiers.Node, declaration, semicolonToken, this.context); } public VariableDeclarationSyntax VariableDeclaration(TypeSyntax type, Microsoft.CodeAnalysis.Syntax.InternalSyntax.SeparatedSyntaxList variables) @@ -47991,9 +48028,20 @@ public static LocalFunctionStatementSyntax LocalFunctionStatement(Microsoft.Code return new LocalFunctionStatementSyntax(SyntaxKind.LocalFunctionStatement, modifiers.Node, returnType, identifier, typeParameterList, parameterList, constraintClauses.Node, body, expressionBody, semicolonToken); } - public static LocalDeclarationStatementSyntax LocalDeclarationStatement(SyntaxToken usingKeyword, Microsoft.CodeAnalysis.Syntax.InternalSyntax.SyntaxList modifiers, VariableDeclarationSyntax declaration, SyntaxToken semicolonToken) + public static LocalDeclarationStatementSyntax LocalDeclarationStatement(SyntaxToken awaitKeyword, SyntaxToken usingKeyword, Microsoft.CodeAnalysis.Syntax.InternalSyntax.SyntaxList modifiers, VariableDeclarationSyntax declaration, SyntaxToken semicolonToken) { #if DEBUG + if (awaitKeyword != null) + { + switch (awaitKeyword.Kind) + { + case SyntaxKind.AwaitKeyword: + case SyntaxKind.None: + break; + default: + throw new ArgumentException("awaitKeyword"); + } + } if (usingKeyword != null) { switch (usingKeyword.Kind) @@ -48018,7 +48066,7 @@ public static LocalDeclarationStatementSyntax LocalDeclarationStatement(SyntaxTo } #endif - return new LocalDeclarationStatementSyntax(SyntaxKind.LocalDeclarationStatement, usingKeyword, modifiers.Node, declaration, semicolonToken); + return new LocalDeclarationStatementSyntax(SyntaxKind.LocalDeclarationStatement, awaitKeyword, usingKeyword, modifiers.Node, declaration, semicolonToken); } public static VariableDeclarationSyntax VariableDeclaration(TypeSyntax type, Microsoft.CodeAnalysis.Syntax.InternalSyntax.SeparatedSyntaxList variables) diff --git a/src/Compilers/CSharp/Portable/Generated/Syntax.xml.Main.Generated.cs b/src/Compilers/CSharp/Portable/Generated/Syntax.xml.Main.Generated.cs index 7c17b809ed20d..5075169558bc2 100644 --- a/src/Compilers/CSharp/Portable/Generated/Syntax.xml.Main.Generated.cs +++ b/src/Compilers/CSharp/Portable/Generated/Syntax.xml.Main.Generated.cs @@ -3170,11 +3170,12 @@ public override SyntaxNode VisitLocalFunctionStatement(LocalFunctionStatementSyn public override SyntaxNode VisitLocalDeclarationStatement(LocalDeclarationStatementSyntax node) { + var awaitKeyword = this.VisitToken(node.AwaitKeyword); var usingKeyword = this.VisitToken(node.UsingKeyword); var modifiers = this.VisitList(node.Modifiers); var declaration = (VariableDeclarationSyntax)this.Visit(node.Declaration); var semicolonToken = this.VisitToken(node.SemicolonToken); - return node.Update(usingKeyword, modifiers, declaration, semicolonToken); + return node.Update(awaitKeyword, usingKeyword, modifiers, declaration, semicolonToken); } public override SyntaxNode VisitVariableDeclaration(VariableDeclarationSyntax node) @@ -6869,8 +6870,16 @@ public static LocalFunctionStatementSyntax LocalFunctionStatement(TypeSyntax ret } /// Creates a new LocalDeclarationStatementSyntax instance. - public static LocalDeclarationStatementSyntax LocalDeclarationStatement(SyntaxToken usingKeyword, SyntaxTokenList modifiers, VariableDeclarationSyntax declaration, SyntaxToken semicolonToken) + public static LocalDeclarationStatementSyntax LocalDeclarationStatement(SyntaxToken awaitKeyword, SyntaxToken usingKeyword, SyntaxTokenList modifiers, VariableDeclarationSyntax declaration, SyntaxToken semicolonToken) { + switch (awaitKeyword.Kind()) + { + case SyntaxKind.AwaitKeyword: + case SyntaxKind.None: + break; + default: + throw new ArgumentException("awaitKeyword"); + } switch (usingKeyword.Kind()) { case SyntaxKind.UsingKeyword: @@ -6888,20 +6897,20 @@ public static LocalDeclarationStatementSyntax LocalDeclarationStatement(SyntaxTo default: throw new ArgumentException("semicolonToken"); } - return (LocalDeclarationStatementSyntax)Microsoft.CodeAnalysis.CSharp.Syntax.InternalSyntax.SyntaxFactory.LocalDeclarationStatement((Syntax.InternalSyntax.SyntaxToken)usingKeyword.Node, modifiers.Node.ToGreenList(), declaration == null ? null : (Microsoft.CodeAnalysis.CSharp.Syntax.InternalSyntax.VariableDeclarationSyntax)declaration.Green, (Syntax.InternalSyntax.SyntaxToken)semicolonToken.Node).CreateRed(); + return (LocalDeclarationStatementSyntax)Microsoft.CodeAnalysis.CSharp.Syntax.InternalSyntax.SyntaxFactory.LocalDeclarationStatement((Syntax.InternalSyntax.SyntaxToken)awaitKeyword.Node, (Syntax.InternalSyntax.SyntaxToken)usingKeyword.Node, modifiers.Node.ToGreenList(), declaration == null ? null : (Microsoft.CodeAnalysis.CSharp.Syntax.InternalSyntax.VariableDeclarationSyntax)declaration.Green, (Syntax.InternalSyntax.SyntaxToken)semicolonToken.Node).CreateRed(); } /// Creates a new LocalDeclarationStatementSyntax instance. public static LocalDeclarationStatementSyntax LocalDeclarationStatement(SyntaxTokenList modifiers, VariableDeclarationSyntax declaration) { - return SyntaxFactory.LocalDeclarationStatement(default(SyntaxToken), modifiers, declaration, SyntaxFactory.Token(SyntaxKind.SemicolonToken)); + return SyntaxFactory.LocalDeclarationStatement(default(SyntaxToken), default(SyntaxToken), modifiers, declaration, SyntaxFactory.Token(SyntaxKind.SemicolonToken)); } /// Creates a new LocalDeclarationStatementSyntax instance. public static LocalDeclarationStatementSyntax LocalDeclarationStatement(VariableDeclarationSyntax declaration) { - return SyntaxFactory.LocalDeclarationStatement(default(SyntaxToken), default(SyntaxTokenList), declaration, SyntaxFactory.Token(SyntaxKind.SemicolonToken)); + return SyntaxFactory.LocalDeclarationStatement(default(SyntaxToken), default(SyntaxToken), default(SyntaxTokenList), declaration, SyntaxFactory.Token(SyntaxKind.SemicolonToken)); } /// Creates a new VariableDeclarationSyntax instance. diff --git a/src/Compilers/CSharp/Portable/Generated/Syntax.xml.Syntax.Generated.cs b/src/Compilers/CSharp/Portable/Generated/Syntax.xml.Syntax.Generated.cs index 594c2aea429ec..a6cd8a1c5e71f 100644 --- a/src/Compilers/CSharp/Portable/Generated/Syntax.xml.Syntax.Generated.cs +++ b/src/Compilers/CSharp/Portable/Generated/Syntax.xml.Syntax.Generated.cs @@ -7831,13 +7831,25 @@ internal LocalDeclarationStatementSyntax(Microsoft.CodeAnalysis.CSharp.Syntax.In { } + public SyntaxToken AwaitKeyword + { + get + { + var slot = ((Microsoft.CodeAnalysis.CSharp.Syntax.InternalSyntax.LocalDeclarationStatementSyntax)this.Green).awaitKeyword; + if (slot != null) + return new SyntaxToken(this, slot, this.Position, 0); + + return default(SyntaxToken); + } + } + public SyntaxToken UsingKeyword { get { var slot = ((Microsoft.CodeAnalysis.CSharp.Syntax.InternalSyntax.LocalDeclarationStatementSyntax)this.Green).usingKeyword; if (slot != null) - return new SyntaxToken(this, slot, this.Position, 0); + return new SyntaxToken(this, slot, this.GetChildPosition(1), this.GetChildIndex(1)); return default(SyntaxToken); } @@ -7848,9 +7860,9 @@ public SyntaxTokenList Modifiers { get { - var slot = this.Green.GetSlot(1); + var slot = this.Green.GetSlot(2); if (slot != null) - return new SyntaxTokenList(this, slot, this.GetChildPosition(1), this.GetChildIndex(1)); + return new SyntaxTokenList(this, slot, this.GetChildPosition(2), this.GetChildIndex(2)); return default(SyntaxTokenList); } @@ -7860,20 +7872,20 @@ public VariableDeclarationSyntax Declaration { get { - return this.GetRed(ref this.declaration, 2); + return this.GetRed(ref this.declaration, 3); } } public SyntaxToken SemicolonToken { - get { return new SyntaxToken(this, ((Microsoft.CodeAnalysis.CSharp.Syntax.InternalSyntax.LocalDeclarationStatementSyntax)this.Green).semicolonToken, this.GetChildPosition(3), this.GetChildIndex(3)); } + get { return new SyntaxToken(this, ((Microsoft.CodeAnalysis.CSharp.Syntax.InternalSyntax.LocalDeclarationStatementSyntax)this.Green).semicolonToken, this.GetChildPosition(4), this.GetChildIndex(4)); } } internal override SyntaxNode GetNodeSlot(int index) { switch (index) { - case 2: return this.GetRed(ref this.declaration, 2); + case 3: return this.GetRed(ref this.declaration, 3); default: return null; } } @@ -7881,7 +7893,7 @@ internal override SyntaxNode GetCachedSlot(int index) { switch (index) { - case 2: return this.declaration; + case 3: return this.declaration; default: return null; } } @@ -7896,11 +7908,11 @@ public override void Accept(CSharpSyntaxVisitor visitor) visitor.VisitLocalDeclarationStatement(this); } - public LocalDeclarationStatementSyntax Update(SyntaxToken usingKeyword, SyntaxTokenList modifiers, VariableDeclarationSyntax declaration, SyntaxToken semicolonToken) + public LocalDeclarationStatementSyntax Update(SyntaxToken awaitKeyword, SyntaxToken usingKeyword, SyntaxTokenList modifiers, VariableDeclarationSyntax declaration, SyntaxToken semicolonToken) { - if (usingKeyword != this.UsingKeyword || modifiers != this.Modifiers || declaration != this.Declaration || semicolonToken != this.SemicolonToken) + if (awaitKeyword != this.AwaitKeyword || usingKeyword != this.UsingKeyword || modifiers != this.Modifiers || declaration != this.Declaration || semicolonToken != this.SemicolonToken) { - var newNode = SyntaxFactory.LocalDeclarationStatement(usingKeyword, modifiers, declaration, semicolonToken); + var newNode = SyntaxFactory.LocalDeclarationStatement(awaitKeyword, usingKeyword, modifiers, declaration, semicolonToken); var annotations = this.GetAnnotations(); if (annotations != null && annotations.Length > 0) return newNode.WithAnnotations(annotations); @@ -7910,24 +7922,29 @@ public LocalDeclarationStatementSyntax Update(SyntaxToken usingKeyword, SyntaxTo return this; } + public LocalDeclarationStatementSyntax WithAwaitKeyword(SyntaxToken awaitKeyword) + { + return this.Update(awaitKeyword, this.UsingKeyword, this.Modifiers, this.Declaration, this.SemicolonToken); + } + public LocalDeclarationStatementSyntax WithUsingKeyword(SyntaxToken usingKeyword) { - return this.Update(usingKeyword, this.Modifiers, this.Declaration, this.SemicolonToken); + return this.Update(this.AwaitKeyword, usingKeyword, this.Modifiers, this.Declaration, this.SemicolonToken); } public LocalDeclarationStatementSyntax WithModifiers(SyntaxTokenList modifiers) { - return this.Update(this.UsingKeyword, modifiers, this.Declaration, this.SemicolonToken); + return this.Update(this.AwaitKeyword, this.UsingKeyword, modifiers, this.Declaration, this.SemicolonToken); } public LocalDeclarationStatementSyntax WithDeclaration(VariableDeclarationSyntax declaration) { - return this.Update(this.UsingKeyword, this.Modifiers, declaration, this.SemicolonToken); + return this.Update(this.AwaitKeyword, this.UsingKeyword, this.Modifiers, declaration, this.SemicolonToken); } public LocalDeclarationStatementSyntax WithSemicolonToken(SyntaxToken semicolonToken) { - return this.Update(this.UsingKeyword, this.Modifiers, this.Declaration, semicolonToken); + return this.Update(this.AwaitKeyword, this.UsingKeyword, this.Modifiers, this.Declaration, semicolonToken); } public LocalDeclarationStatementSyntax AddModifiers(params SyntaxToken[] items) diff --git a/src/Compilers/CSharp/Portable/Parser/LanguageParser.cs b/src/Compilers/CSharp/Portable/Parser/LanguageParser.cs index c304c2679e2d1..a776ad38ab9ad 100644 --- a/src/Compilers/CSharp/Portable/Parser/LanguageParser.cs +++ b/src/Compilers/CSharp/Portable/Parser/LanguageParser.cs @@ -590,7 +590,7 @@ private void ParseNamespaceBody(ref SyntaxToken openBrace, ref NamespaceBodyBuil // incomplete members must be processed before we add any nodes to the body: AddIncompleteMembers(ref pendingIncompleteMembers, ref body); - body.Members.Add(_syntaxFactory.GlobalStatement(ParseUsingStatement(awaitTokenOpt: default))); + body.Members.Add(_syntaxFactory.GlobalStatement(ParseUsingStatement())); seen = NamespaceParts.MembersAndStatements; } else @@ -6695,7 +6695,7 @@ private StatementSyntax ParseStatementNoDeclaration(bool allowAnyExpression) } break; case SyntaxKind.UsingKeyword: - return PeekToken(1).Kind == SyntaxKind.OpenParenToken || (PeekToken(1).ContextualKind == SyntaxKind.AwaitKeyword && PeekToken(2).Kind == SyntaxKind.OpenParenToken) ? this.ParseUsingStatement(awaitTokenOpt: default) : this.ParseLocalDeclarationStatement(); + return PeekToken(1).Kind == SyntaxKind.OpenParenToken ? this.ParseUsingStatement() : this.ParseLocalDeclarationStatement(); case SyntaxKind.WhileKeyword: return this.ParseWhileStatement(); case SyntaxKind.OpenBraceToken: @@ -6709,7 +6709,14 @@ private StatementSyntax ParseStatementNoDeclaration(bool allowAnyExpression) } else if (isPossibleAwaitUsing()) { - return this.ParseUsingStatement(parseAwaitKeywordForAsyncStreams()); + if (PeekToken(2).Kind == SyntaxKind.OpenParenToken) + { + return this.ParseUsingStatement(parseAwaitKeywordForAsyncStreams()); + } + else + { + return this.ParseLocalDeclarationStatement(parseAwaitKeywordForAsyncStreams()); + } } else if (this.IsPossibleLabeledStatement()) { @@ -8148,7 +8155,7 @@ private UnsafeStatementSyntax ParseUnsafeStatement() return _syntaxFactory.UnsafeStatement(@unsafe, block); } - private UsingStatementSyntax ParseUsingStatement(SyntaxToken awaitTokenOpt) + private UsingStatementSyntax ParseUsingStatement(SyntaxToken awaitTokenOpt = default) { var @using = this.EatToken(SyntaxKind.UsingKeyword); var openParen = this.EatToken(SyntaxKind.OpenParenToken); @@ -8289,7 +8296,7 @@ private LabeledStatementSyntax ParseLabeledStatement() /// /// Parses any kind of local declaration statement: local variable or local function. /// - private StatementSyntax ParseLocalDeclarationStatement() + private StatementSyntax ParseLocalDeclarationStatement(SyntaxToken awaitKeywordOpt = default) { var usingKeyword = this.CurrentToken.Kind == SyntaxKind.UsingKeyword ? this.EatToken() : null; var mods = _pool.Allocate(); @@ -8332,6 +8339,7 @@ private StatementSyntax ParseLocalDeclarationStatement() // PROTOTYPE var semicolon = this.EatToken(SyntaxKind.SemicolonToken); return _syntaxFactory.LocalDeclarationStatement( + awaitKeywordOpt, usingKeyword, mods.ToList(), _syntaxFactory.VariableDeclaration(type, variables), diff --git a/src/Compilers/CSharp/Portable/PublicAPI.Unshipped.txt b/src/Compilers/CSharp/Portable/PublicAPI.Unshipped.txt index 47ff79eb6d592..344901989c264 100644 --- a/src/Compilers/CSharp/Portable/PublicAPI.Unshipped.txt +++ b/src/Compilers/CSharp/Portable/PublicAPI.Unshipped.txt @@ -1,6 +1,9 @@ *REMOVED*static Microsoft.CodeAnalysis.CSharp.LanguageVersionFacts.TryParse(this string version, out Microsoft.CodeAnalysis.CSharp.LanguageVersion result) -> bool Microsoft.CodeAnalysis.CSharp.Syntax.ForEachStatementSyntax.Update(Microsoft.CodeAnalysis.SyntaxToken awaitKeyword, Microsoft.CodeAnalysis.SyntaxToken forEachKeyword, Microsoft.CodeAnalysis.SyntaxToken openParenToken, Microsoft.CodeAnalysis.CSharp.Syntax.TypeSyntax type, Microsoft.CodeAnalysis.SyntaxToken identifier, Microsoft.CodeAnalysis.SyntaxToken inKeyword, Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionSyntax expression, Microsoft.CodeAnalysis.SyntaxToken closeParenToken, Microsoft.CodeAnalysis.CSharp.Syntax.StatementSyntax statement) -> Microsoft.CodeAnalysis.CSharp.Syntax.ForEachStatementSyntax Microsoft.CodeAnalysis.CSharp.Syntax.ForEachVariableStatementSyntax.Update(Microsoft.CodeAnalysis.SyntaxToken awaitKeyword, Microsoft.CodeAnalysis.SyntaxToken forEachKeyword, Microsoft.CodeAnalysis.SyntaxToken openParenToken, Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionSyntax variable, Microsoft.CodeAnalysis.SyntaxToken inKeyword, Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionSyntax expression, Microsoft.CodeAnalysis.SyntaxToken closeParenToken, Microsoft.CodeAnalysis.CSharp.Syntax.StatementSyntax statement) -> Microsoft.CodeAnalysis.CSharp.Syntax.ForEachVariableStatementSyntax +Microsoft.CodeAnalysis.CSharp.Syntax.LocalDeclarationStatementSyntax.Update(Microsoft.CodeAnalysis.SyntaxToken awaitKeyword, Microsoft.CodeAnalysis.SyntaxToken usingKeyword, Microsoft.CodeAnalysis.SyntaxTokenList modifiers, Microsoft.CodeAnalysis.CSharp.Syntax.VariableDeclarationSyntax declaration, Microsoft.CodeAnalysis.SyntaxToken semicolonToken) -> Microsoft.CodeAnalysis.CSharp.Syntax.LocalDeclarationStatementSyntax +Microsoft.CodeAnalysis.CSharp.Syntax.LocalDeclarationStatementSyntax.WithAwaitKeyword(Microsoft.CodeAnalysis.SyntaxToken awaitKeyword) -> Microsoft.CodeAnalysis.CSharp.Syntax.LocalDeclarationStatementSyntax +Microsoft.CodeAnalysis.CSharp.Syntax.LocalDeclarationStatementSyntax.AwaitKeyword.get -> Microsoft.CodeAnalysis.SyntaxToken Microsoft.CodeAnalysis.CSharp.Syntax.NullableDirectiveTriviaSyntax.NullableKeyword.get -> Microsoft.CodeAnalysis.SyntaxToken Microsoft.CodeAnalysis.CSharp.Syntax.NullableDirectiveTriviaSyntax.SettingToken.get -> Microsoft.CodeAnalysis.SyntaxToken Microsoft.CodeAnalysis.CSharp.Syntax.NullableDirectiveTriviaSyntax.Update(Microsoft.CodeAnalysis.SyntaxToken hashToken, Microsoft.CodeAnalysis.SyntaxToken nullableKeyword, Microsoft.CodeAnalysis.SyntaxToken settingToken, Microsoft.CodeAnalysis.SyntaxToken endOfDirectiveToken, bool isActive) -> Microsoft.CodeAnalysis.CSharp.Syntax.NullableDirectiveTriviaSyntax @@ -93,7 +96,6 @@ Microsoft.CodeAnalysis.CSharp.Syntax.RangeExpressionSyntax.Update(Microsoft.Code Microsoft.CodeAnalysis.CSharp.Syntax.RangeExpressionSyntax.WithLeftOperand(Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionSyntax leftOperand) -> Microsoft.CodeAnalysis.CSharp.Syntax.RangeExpressionSyntax Microsoft.CodeAnalysis.CSharp.Syntax.RangeExpressionSyntax.WithOperatorToken(Microsoft.CodeAnalysis.SyntaxToken operatorToken) -> Microsoft.CodeAnalysis.CSharp.Syntax.RangeExpressionSyntax Microsoft.CodeAnalysis.CSharp.Syntax.RangeExpressionSyntax.WithRightOperand(Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionSyntax rightOperand) -> Microsoft.CodeAnalysis.CSharp.Syntax.RangeExpressionSyntax -Microsoft.CodeAnalysis.CSharp.Syntax.LocalDeclarationStatementSyntax.Update(Microsoft.CodeAnalysis.SyntaxToken usingKeyword, Microsoft.CodeAnalysis.SyntaxTokenList modifiers, Microsoft.CodeAnalysis.CSharp.Syntax.VariableDeclarationSyntax declaration, Microsoft.CodeAnalysis.SyntaxToken semicolonToken) -> Microsoft.CodeAnalysis.CSharp.Syntax.LocalDeclarationStatementSyntax Microsoft.CodeAnalysis.CSharp.Syntax.LocalDeclarationStatementSyntax.UsingKeyword.get -> Microsoft.CodeAnalysis.SyntaxToken Microsoft.CodeAnalysis.CSharp.Syntax.LocalDeclarationStatementSyntax.WithUsingKeyword(Microsoft.CodeAnalysis.SyntaxToken usingKeyword) -> Microsoft.CodeAnalysis.CSharp.Syntax.LocalDeclarationStatementSyntax Microsoft.CodeAnalysis.CSharp.Syntax.SimpleNameSyntax.WithIdentifier(Microsoft.CodeAnalysis.SyntaxToken identifier) -> Microsoft.CodeAnalysis.CSharp.Syntax.SimpleNameSyntax @@ -149,6 +151,7 @@ static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.ArrayRankSpecifier(Microsoft. static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.ClassOrStructConstraint(Microsoft.CodeAnalysis.CSharp.SyntaxKind kind, Microsoft.CodeAnalysis.SyntaxToken classOrStructKeyword, Microsoft.CodeAnalysis.SyntaxToken questionToken) -> Microsoft.CodeAnalysis.CSharp.Syntax.ClassOrStructConstraintSyntax static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.ForEachStatement(Microsoft.CodeAnalysis.SyntaxToken awaitKeyword, Microsoft.CodeAnalysis.SyntaxToken forEachKeyword, Microsoft.CodeAnalysis.SyntaxToken openParenToken, Microsoft.CodeAnalysis.CSharp.Syntax.TypeSyntax type, Microsoft.CodeAnalysis.SyntaxToken identifier, Microsoft.CodeAnalysis.SyntaxToken inKeyword, Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionSyntax expression, Microsoft.CodeAnalysis.SyntaxToken closeParenToken, Microsoft.CodeAnalysis.CSharp.Syntax.StatementSyntax statement) -> Microsoft.CodeAnalysis.CSharp.Syntax.ForEachStatementSyntax static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.ForEachVariableStatement(Microsoft.CodeAnalysis.SyntaxToken awaitKeyword, Microsoft.CodeAnalysis.SyntaxToken forEachKeyword, Microsoft.CodeAnalysis.SyntaxToken openParenToken, Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionSyntax variable, Microsoft.CodeAnalysis.SyntaxToken inKeyword, Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionSyntax expression, Microsoft.CodeAnalysis.SyntaxToken closeParenToken, Microsoft.CodeAnalysis.CSharp.Syntax.StatementSyntax statement) -> Microsoft.CodeAnalysis.CSharp.Syntax.ForEachVariableStatementSyntax +static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.LocalDeclarationStatement(Microsoft.CodeAnalysis.SyntaxToken awaitKeyword, Microsoft.CodeAnalysis.SyntaxToken usingKeyword, Microsoft.CodeAnalysis.SyntaxTokenList modifiers, Microsoft.CodeAnalysis.CSharp.Syntax.VariableDeclarationSyntax declaration, Microsoft.CodeAnalysis.SyntaxToken semicolonToken) -> Microsoft.CodeAnalysis.CSharp.Syntax.LocalDeclarationStatementSyntax static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.NullableDirectiveTrivia(Microsoft.CodeAnalysis.SyntaxToken hashToken, Microsoft.CodeAnalysis.SyntaxToken nullableKeyword, Microsoft.CodeAnalysis.SyntaxToken settingToken, Microsoft.CodeAnalysis.SyntaxToken endOfDirectiveToken, bool isActive) -> Microsoft.CodeAnalysis.CSharp.Syntax.NullableDirectiveTriviaSyntax static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.NullableDirectiveTrivia(Microsoft.CodeAnalysis.SyntaxToken settingToken, bool isActive) -> Microsoft.CodeAnalysis.CSharp.Syntax.NullableDirectiveTriviaSyntax static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.ParseMemberDeclaration(string text, int offset = 0, Microsoft.CodeAnalysis.ParseOptions options = null, bool consumeFullText = true) -> Microsoft.CodeAnalysis.CSharp.Syntax.MemberDeclarationSyntax @@ -160,4 +163,3 @@ virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitNullableDirective virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitNullableDirectiveTrivia(Microsoft.CodeAnalysis.CSharp.Syntax.NullableDirectiveTriviaSyntax node) -> TResult virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitRangeExpression(Microsoft.CodeAnalysis.CSharp.Syntax.RangeExpressionSyntax node) -> void virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitRangeExpression(Microsoft.CodeAnalysis.CSharp.Syntax.RangeExpressionSyntax node) -> TResult -static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.LocalDeclarationStatement(Microsoft.CodeAnalysis.SyntaxToken usingKeyword, Microsoft.CodeAnalysis.SyntaxTokenList modifiers, Microsoft.CodeAnalysis.CSharp.Syntax.VariableDeclarationSyntax declaration, Microsoft.CodeAnalysis.SyntaxToken semicolonToken) -> Microsoft.CodeAnalysis.CSharp.Syntax.LocalDeclarationStatementSyntax diff --git a/src/Compilers/CSharp/Portable/Syntax/StackAllocArrayCreationExpressionSyntax.cs b/src/Compilers/CSharp/Portable/Syntax/StackAllocArrayCreationExpressionSyntax.cs index 2a7205d308395..1937e9ab266cb 100644 --- a/src/Compilers/CSharp/Portable/Syntax/StackAllocArrayCreationExpressionSyntax.cs +++ b/src/Compilers/CSharp/Portable/Syntax/StackAllocArrayCreationExpressionSyntax.cs @@ -13,7 +13,7 @@ public StackAllocArrayCreationExpressionSyntax Update(SyntaxToken stackAllocKeyw public partial class LocalDeclarationStatementSyntax { public LocalDeclarationStatementSyntax Update(SyntaxTokenList modifiers, VariableDeclarationSyntax declaration, SyntaxToken semicolonToken) - => Update(default(SyntaxToken), modifiers, declaration, semicolonToken); + => Update(default(SyntaxToken), default(SyntaxToken), modifiers, declaration, semicolonToken); } } @@ -25,6 +25,6 @@ public static StackAllocArrayCreationExpressionSyntax StackAllocArrayCreationExp => StackAllocArrayCreationExpression(stackAllocKeyword, type, default(InitializerExpressionSyntax)); public static LocalDeclarationStatementSyntax LocalDeclarationStatement(SyntaxTokenList modifiers, VariableDeclarationSyntax declaration, SyntaxToken semicolonToken) - => LocalDeclarationStatement(default(SyntaxToken), modifiers, declaration, semicolonToken); + => LocalDeclarationStatement(default(SyntaxToken), default(SyntaxToken), modifiers, declaration, semicolonToken); } } diff --git a/src/Compilers/CSharp/Portable/Syntax/Syntax.xml b/src/Compilers/CSharp/Portable/Syntax/Syntax.xml index f5feb251d365c..acfc8924efab9 100644 --- a/src/Compilers/CSharp/Portable/Syntax/Syntax.xml +++ b/src/Compilers/CSharp/Portable/Syntax/Syntax.xml @@ -1890,6 +1890,9 @@ + + + diff --git a/src/Compilers/CSharp/Test/Syntax/Generated/Syntax.Test.xml.Generated.cs b/src/Compilers/CSharp/Test/Syntax/Generated/Syntax.Test.xml.Generated.cs index d8467325e7dae..fda733023c02e 100644 --- a/src/Compilers/CSharp/Test/Syntax/Generated/Syntax.Test.xml.Generated.cs +++ b/src/Compilers/CSharp/Test/Syntax/Generated/Syntax.Test.xml.Generated.cs @@ -431,7 +431,7 @@ private static Microsoft.CodeAnalysis.CSharp.Syntax.InternalSyntax.LocalFunction private static Microsoft.CodeAnalysis.CSharp.Syntax.InternalSyntax.LocalDeclarationStatementSyntax GenerateLocalDeclarationStatement() { - return Microsoft.CodeAnalysis.CSharp.Syntax.InternalSyntax.SyntaxFactory.LocalDeclarationStatement(null, new Microsoft.CodeAnalysis.Syntax.InternalSyntax.SyntaxList(), GenerateVariableDeclaration(), Microsoft.CodeAnalysis.CSharp.Syntax.InternalSyntax.SyntaxFactory.Token(SyntaxKind.SemicolonToken)); + return Microsoft.CodeAnalysis.CSharp.Syntax.InternalSyntax.SyntaxFactory.LocalDeclarationStatement(null, null, new Microsoft.CodeAnalysis.Syntax.InternalSyntax.SyntaxList(), GenerateVariableDeclaration(), Microsoft.CodeAnalysis.CSharp.Syntax.InternalSyntax.SyntaxFactory.Token(SyntaxKind.SemicolonToken)); } private static Microsoft.CodeAnalysis.CSharp.Syntax.InternalSyntax.VariableDeclarationSyntax GenerateVariableDeclaration() @@ -2049,6 +2049,7 @@ public void TestLocalDeclarationStatementFactoryAndProperties() { var node = GenerateLocalDeclarationStatement(); + Assert.Null(node.AwaitKeyword); Assert.Null(node.UsingKeyword); Assert.NotNull(node.Modifiers); Assert.NotNull(node.Declaration); @@ -9489,7 +9490,7 @@ private static LocalFunctionStatementSyntax GenerateLocalFunctionStatement() private static LocalDeclarationStatementSyntax GenerateLocalDeclarationStatement() { - return SyntaxFactory.LocalDeclarationStatement(default(SyntaxToken), new SyntaxTokenList(), GenerateVariableDeclaration(), SyntaxFactory.Token(SyntaxKind.SemicolonToken)); + return SyntaxFactory.LocalDeclarationStatement(default(SyntaxToken), default(SyntaxToken), new SyntaxTokenList(), GenerateVariableDeclaration(), SyntaxFactory.Token(SyntaxKind.SemicolonToken)); } private static VariableDeclarationSyntax GenerateVariableDeclaration() @@ -11107,11 +11108,12 @@ public void TestLocalDeclarationStatementFactoryAndProperties() { var node = GenerateLocalDeclarationStatement(); + Assert.Equal(SyntaxKind.None, node.AwaitKeyword.Kind()); Assert.Equal(SyntaxKind.None, node.UsingKeyword.Kind()); Assert.NotNull(node.Modifiers); Assert.NotNull(node.Declaration); Assert.Equal(SyntaxKind.SemicolonToken, node.SemicolonToken.Kind()); - var newNode = node.WithUsingKeyword(node.UsingKeyword).WithModifiers(node.Modifiers).WithDeclaration(node.Declaration).WithSemicolonToken(node.SemicolonToken); + var newNode = node.WithAwaitKeyword(node.AwaitKeyword).WithUsingKeyword(node.UsingKeyword).WithModifiers(node.Modifiers).WithDeclaration(node.Declaration).WithSemicolonToken(node.SemicolonToken); Assert.Equal(node, newNode); } diff --git a/src/Compilers/CSharp/Test/Syntax/Parsing/StatementParsingTests.cs b/src/Compilers/CSharp/Test/Syntax/Parsing/StatementParsingTests.cs index fa62a5f4e41d5..92e16c36f34af 100644 --- a/src/Compilers/CSharp/Test/Syntax/Parsing/StatementParsingTests.cs +++ b/src/Compilers/CSharp/Test/Syntax/Parsing/StatementParsingTests.cs @@ -2505,6 +2505,132 @@ public void TestUsingVarWithVarDeclarationTree() } } + [Fact] + public void TestAwaitUsingVarWithDeclaration() + { + var text = "await using T a = b;"; + var statement = this.ParseStatement(text, 0, TestOptions.Regular8); + + Assert.NotNull(statement); + Assert.Equal(SyntaxKind.LocalDeclarationStatement, statement.Kind()); + Assert.Equal(text, statement.ToString()); + Assert.Equal(0, statement.Errors().Length); + + var us = (LocalDeclarationStatementSyntax)statement; + Assert.NotNull(us.AwaitKeyword); + Assert.Equal(SyntaxKind.AwaitKeyword, us.AwaitKeyword.ContextualKind()); + Assert.NotNull(us.UsingKeyword); + Assert.Equal(SyntaxKind.UsingKeyword, us.UsingKeyword.Kind()); + + Assert.NotNull(us.Declaration); + Assert.NotNull(us.Declaration.Type); + Assert.Equal("T", us.Declaration.Type.ToString()); + Assert.Equal(SyntaxKind.IdentifierName, us.Declaration.Type.Kind()); + Assert.Equal(SyntaxKind.IdentifierToken, ((IdentifierNameSyntax)us.Declaration.Type).Identifier.Kind()); + Assert.Equal(1, us.Declaration.Variables.Count); + Assert.NotNull(us.Declaration.Variables[0].Identifier); + Assert.Equal("a", us.Declaration.Variables[0].Identifier.ToString()); + Assert.Null(us.Declaration.Variables[0].ArgumentList); + Assert.NotNull(us.Declaration.Variables[0].Initializer); + Assert.NotNull(us.Declaration.Variables[0].Initializer.EqualsToken); + Assert.NotNull(us.Declaration.Variables[0].Initializer.Value); + Assert.Equal("b", us.Declaration.Variables[0].Initializer.Value.ToString()); + } + + [Fact] + public void TestAwaitUsingVarWithDeclarationTree() + { + UsingStatement(@"await using T a = b;", TestOptions.Regular8); + N(SyntaxKind.LocalDeclarationStatement); + { + N(SyntaxKind.AwaitKeyword); + N(SyntaxKind.UsingKeyword); + N(SyntaxKind.VariableDeclaration); + { + N(SyntaxKind.IdentifierName, "T"); + { + N(SyntaxKind.IdentifierToken); + } + N(SyntaxKind.VariableDeclarator); + { + N(SyntaxKind.IdentifierToken, "a"); + N(SyntaxKind.EqualsValueClause); + { + N(SyntaxKind.EqualsToken); + N(SyntaxKind.IdentifierName, "b"); + { + N(SyntaxKind.IdentifierToken); + } + } + } + } + N(SyntaxKind.SemicolonToken); + } + } + + [Fact] + public void TestAwaitUsingWithVarDeclaration() + { + var text = "await using var a = b;"; + var statement = this.ParseStatement(text, 0, TestOptions.Regular8); + + Assert.NotNull(statement); + Assert.Equal(SyntaxKind.LocalDeclarationStatement, statement.Kind()); + Assert.Equal(text, statement.ToString()); + Assert.Equal(0, statement.Errors().Length); + + var us = (LocalDeclarationStatementSyntax)statement; + Assert.NotNull(us.AwaitKeyword); + Assert.Equal(SyntaxKind.AwaitKeyword, us.AwaitKeyword.ContextualKind()); + Assert.NotNull(us.UsingKeyword); + Assert.Equal(SyntaxKind.UsingKeyword, us.UsingKeyword.Kind()); + + Assert.NotNull(us.Declaration); + Assert.NotNull(us.Declaration.Type); + Assert.Equal("var", us.Declaration.Type.ToString()); + Assert.Equal(SyntaxKind.IdentifierName, us.Declaration.Type.Kind()); + Assert.Equal(SyntaxKind.IdentifierToken, ((IdentifierNameSyntax)us.Declaration.Type).Identifier.Kind()); + Assert.Equal(1, us.Declaration.Variables.Count); + Assert.NotNull(us.Declaration.Variables[0].Identifier); + Assert.Equal("a", us.Declaration.Variables[0].Identifier.ToString()); + Assert.Null(us.Declaration.Variables[0].ArgumentList); + Assert.NotNull(us.Declaration.Variables[0].Initializer); + Assert.NotNull(us.Declaration.Variables[0].Initializer.EqualsToken); + Assert.NotNull(us.Declaration.Variables[0].Initializer.Value); + Assert.Equal("b", us.Declaration.Variables[0].Initializer.Value.ToString()); + } + + [Fact] + public void TestAwaitUsingVarWithVarDeclarationTree() + { + UsingStatement(@"await using var a = b;", TestOptions.Regular8); + N(SyntaxKind.LocalDeclarationStatement); + { + N(SyntaxKind.AwaitKeyword); + N(SyntaxKind.UsingKeyword); + N(SyntaxKind.VariableDeclaration); + { + N(SyntaxKind.IdentifierName, "var"); + { + N(SyntaxKind.IdentifierToken, "var"); + } + N(SyntaxKind.VariableDeclarator); + { + N(SyntaxKind.IdentifierToken, "a"); + N(SyntaxKind.EqualsValueClause); + { + N(SyntaxKind.EqualsToken); + N(SyntaxKind.IdentifierName, "b"); + { + N(SyntaxKind.IdentifierToken); + } + } + } + } + N(SyntaxKind.SemicolonToken); + } + } + [Fact] public void TestUsingWithDeclarationWithMultipleVariables() { From c26cfa32a097e310f26eaf34d994059f828e341f Mon Sep 17 00:00:00 2001 From: Chris Sienkiewicz Date: Tue, 11 Dec 2018 14:35:06 -0800 Subject: [PATCH 02/10] Support binding and lowering for await using var x =... - Add awaitable info to bound node - Find and store the awaiter if async - Lower the declaration node correctly - Add tests --- .../Portable/Binder/Binder_Statements.cs | 37 +++- .../Portable/Binder/UsingStatementBinder.cs | 6 +- .../CSharp/Portable/BoundTree/BoundNodes.xml | 1 + .../Portable/FlowAnalysis/DataFlowPass.cs | 3 + .../FlowAnalysis/PreciseAbstractFlowPass.cs | 4 + .../Generated/BoundNodes.xml.Generated.cs | 14 +- .../AsyncExceptionHandlerRewriter.cs | 8 +- .../LocalRewriter_UsingStatement.cs | 8 +- .../CodeGen/CodeGenUsingDeclarationTests.cs | 175 +++++++++++++++++- 9 files changed, 236 insertions(+), 20 deletions(-) diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Statements.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Statements.cs index e5aa839827019..df3391a27615e 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder_Statements.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder_Statements.cs @@ -635,18 +635,28 @@ private BoundStatement BindUsingDeclarationStatementParts(LocalDeclarationStatem { Conversion iDisposableConversion; MethodSymbol disposeMethod; + bool hasAwait = node.AwaitKeyword != default; var declarations = BindUsingVariableDeclaration( this, diagnostics, diagnostics.HasAnyErrors(), node, node.Declaration, - hasAwait: false, + hasAwait, out iDisposableConversion, out disposeMethod); - return new BoundUsingLocalDeclarations(node, disposeMethod, iDisposableConversion, declarations); + + AwaitableInfo awaitOpt = null; + bool hasErrors = false; + if (hasAwait) + { + awaitOpt = BindAsyncDisposeAwaiter(node, node.AwaitKeyword, disposeMethod, diagnostics, ref hasErrors); + } + + return new BoundUsingLocalDeclarations(node, disposeMethod, iDisposableConversion, awaitOpt, declarations, hasErrors); } + private BoundStatement BindDeclarationStatementParts(LocalDeclarationStatementSyntax node, DiagnosticBag diagnostics) { var typeSyntax = node.Declaration.Type.SkipRef(out _); @@ -762,6 +772,29 @@ internal MethodSymbol TryFindDisposePatternMethod(BoundExpression expr, SyntaxNo return disposeMethod; } + /// + /// Binds an awaiter for asynchronous dispose + /// + /// The synatx node to bind for + /// The await keyword of the syntax + /// The dispose method to call, or null to use IAsyncDisposable.DisposeAsync + /// Populated with any errors + /// True if errors occured during binding + /// An with the bound information + internal AwaitableInfo BindAsyncDisposeAwaiter(SyntaxNode node, SyntaxToken awaitKeyword, MethodSymbol disposeMethodOpt, DiagnosticBag diagnostics, ref bool hasErrors) + { + TypeSymbol taskType = disposeMethodOpt is null + ? this.Compilation.GetWellKnownType(WellKnownType.System_Threading_Tasks_ValueTask) + : disposeMethodOpt.ReturnType.TypeSymbol; + + hasErrors |= ReportUseSiteDiagnostics(taskType, diagnostics, awaitKeyword); + + BoundExpression placeholder = new BoundAwaitableValuePlaceholder(node, taskType).MakeCompilerGenerated(); + AwaitableInfo awaitOpt = BindAwaitInfo(placeholder, node, awaitKeyword.GetLocation(), diagnostics, ref hasErrors); + return awaitOpt; + } + + private TypeSymbolWithAnnotations BindVariableType(CSharpSyntaxNode declarationNode, DiagnosticBag diagnostics, TypeSyntax typeSyntax, ref bool isConst, out bool isVar, out AliasSymbol alias) { Debug.Assert( diff --git a/src/Compilers/CSharp/Portable/Binder/UsingStatementBinder.cs b/src/Compilers/CSharp/Portable/Binder/UsingStatementBinder.cs index 24a6800968cef..991e9dcec9eca 100644 --- a/src/Compilers/CSharp/Portable/Binder/UsingStatementBinder.cs +++ b/src/Compilers/CSharp/Portable/Binder/UsingStatementBinder.cs @@ -112,12 +112,8 @@ internal override BoundStatement BindUsingStatementParts(DiagnosticBag diagnosti if (hasAwait) { - TypeSymbol taskType = this.Compilation.GetWellKnownType(WellKnownType.System_Threading_Tasks_ValueTask); - hasErrors |= ReportUseSiteDiagnostics(taskType, diagnostics, _syntax.AwaitKeyword); - var resource = (SyntaxNode)expressionSyntax ?? declarationSyntax; - BoundExpression placeholder = new BoundAwaitableValuePlaceholder(resource, taskType).MakeCompilerGenerated(); - awaitOpt = BindAwaitInfo(placeholder, resource, _syntax.AwaitKeyword.GetLocation(), diagnostics, ref hasErrors); + awaitOpt = BindAsyncDisposeAwaiter(resource, _syntax.AwaitKeyword, disposeMethod, diagnostics, ref hasErrors); } BoundStatement boundBody = originalBinder.BindPossibleEmbeddedStatement(_syntax.Statement, diagnostics); diff --git a/src/Compilers/CSharp/Portable/BoundTree/BoundNodes.xml b/src/Compilers/CSharp/Portable/BoundTree/BoundNodes.xml index 50acf21978677..eae3fdc86172c 100644 --- a/src/Compilers/CSharp/Portable/BoundTree/BoundNodes.xml +++ b/src/Compilers/CSharp/Portable/BoundTree/BoundNodes.xml @@ -794,6 +794,7 @@ +