diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Statements.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Statements.cs index e5aa839827019..5eb230f1c009e 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder_Statements.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder_Statements.cs @@ -635,16 +635,25 @@ 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) @@ -762,6 +771,29 @@ internal MethodSymbol TryFindDisposePatternMethod(BoundExpression expr, SyntaxNo return disposeMethod; } + /// + /// Binds an awaiter for asynchronous dispose + /// + /// The syntax 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 occurred during binding + /// An with the bound information + protected 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 @@ +