private BoundForStatement BindForParts(ForStatementSyntax node, Binder originalBinder, DiagnosticBag diagnostics) { BoundStatement initializer; // Deconstruction, Declaration, and Initializers are mutually exclusive. if (_syntax.Deconstruction != null) { var assignment = originalBinder.BindDeconstructionDeclaration(node.Deconstruction, node.Deconstruction.VariableComponent, node.Deconstruction.Value, diagnostics); initializer = new BoundLocalDeconstructionDeclaration(node, assignment); } else if (_syntax.Declaration != null) { ImmutableArray <BoundLocalDeclaration> unused; initializer = originalBinder.BindForOrUsingOrFixedDeclarations(node.Declaration, LocalDeclarationKind.ForInitializerVariable, diagnostics, out unused); } else { initializer = originalBinder.BindStatementExpressionList(node.Initializers, diagnostics); } var condition = (node.Condition != null) ? originalBinder.BindBooleanExpression(node.Condition, diagnostics) : null; var increment = originalBinder.BindStatementExpressionList(node.Incrementors, diagnostics); var body = originalBinder.BindPossibleEmbeddedStatement(node.Statement, diagnostics); Debug.Assert(this.Locals == this.GetDeclaredLocalsForScope(node)); return(new BoundForStatement(node, this.Locals, initializer, condition, increment, body, this.BreakLabel, this.ContinueLabel)); }
private BoundForStatement BindForParts(ForStatementSyntax node, Binder originalBinder, DiagnosticBag diagnostics) { BoundStatement initializer; // Deconstruction, Declaration, and Initializers are mutually exclusive. if (_syntax.Deconstruction != null) { var assignment = originalBinder.BindDeconstructionDeclaration(node.Deconstruction, node.Deconstruction.VariableComponent, node.Deconstruction.Value, diagnostics); initializer = new BoundLocalDeconstructionDeclaration(node, assignment); } else if (_syntax.Declaration != null) { ImmutableArray<BoundLocalDeclaration> unused; initializer = originalBinder.BindForOrUsingOrFixedDeclarations(node.Declaration, LocalDeclarationKind.ForInitializerVariable, diagnostics, out unused); } else { initializer = originalBinder.BindStatementExpressionList(node.Initializers, diagnostics); } var condition = (node.Condition != null) ? originalBinder.BindBooleanExpression(node.Condition, diagnostics) : null; var increment = originalBinder.BindStatementExpressionList(node.Incrementors, diagnostics); var body = originalBinder.BindPossibleEmbeddedStatement(node.Statement, diagnostics); Debug.Assert(this.Locals == this.GetDeclaredLocalsForScope(node)); return new BoundForStatement(node, this.Locals, initializer, condition, increment, body, this.BreakLabel, this.ContinueLabel); }
private BoundForStatement BindForParts(ForStatementSyntax node, Binder originalBinder, DiagnosticBag diagnostics) { BoundStatement initializer; // Declaration and Initializers are mutually exclusive. if (_syntax.Declaration != null) { ImmutableArray <BoundLocalDeclaration> unused; initializer = originalBinder.BindForOrUsingOrFixedDeclarations(node.Declaration, LocalDeclarationKind.RegularVariable, diagnostics, out unused); } else { initializer = originalBinder.BindStatementExpressionList(node.Initializers, diagnostics); } BoundExpression condition = null; var innerLocals = ImmutableArray <LocalSymbol> .Empty; ExpressionSyntax conditionSyntax = node.Condition; if (conditionSyntax != null) { originalBinder = originalBinder.GetBinder(conditionSyntax); condition = originalBinder.BindBooleanExpression(conditionSyntax, diagnostics); innerLocals = originalBinder.GetDeclaredLocalsForScope(conditionSyntax); } BoundStatement increment = null; SeparatedSyntaxList <ExpressionSyntax> incrementors = node.Incrementors; if (incrementors.Count > 0) { var scopeDesignator = incrementors.First(); var incrementBinder = originalBinder.GetBinder(scopeDesignator); increment = incrementBinder.WrapWithVariablesIfAny(scopeDesignator, incrementBinder.BindStatementExpressionList(incrementors, diagnostics)); } var body = originalBinder.BindPossibleEmbeddedStatement(node.Statement, diagnostics); Debug.Assert(this.Locals == this.GetDeclaredLocalsForScope(node)); return(new BoundForStatement(node, this.Locals, initializer, innerLocals, condition, increment, body, this.BreakLabel, this.ContinueLabel)); }
private BoundForStatement BindForParts(ForStatementSyntax node, Binder originalBinder, DiagnosticBag diagnostics) { BoundStatement initializer; // Declaration and Initializers are mutually exclusive. if (_syntax.Declaration != null) { ImmutableArray<BoundLocalDeclaration> unused; initializer = originalBinder.BindForOrUsingOrFixedDeclarations(node.Declaration, LocalDeclarationKind.RegularVariable, diagnostics, out unused); } else { initializer = originalBinder.BindStatementExpressionList(node.Initializers, diagnostics); } BoundExpression condition = null; var innerLocals = ImmutableArray<LocalSymbol>.Empty; ExpressionSyntax conditionSyntax = node.Condition; if (conditionSyntax != null) { originalBinder = originalBinder.GetBinder(conditionSyntax); condition = originalBinder.BindBooleanExpression(conditionSyntax, diagnostics); innerLocals = originalBinder.GetDeclaredLocalsForScope(conditionSyntax); } BoundStatement increment = null; SeparatedSyntaxList<ExpressionSyntax> incrementors = node.Incrementors; if (incrementors.Count > 0) { var scopeDesignator = incrementors.First(); var incrementBinder = originalBinder.GetBinder(scopeDesignator); increment = incrementBinder.WrapWithVariablesIfAny(scopeDesignator, incrementBinder.BindStatementExpressionList(incrementors, diagnostics)); } var body = originalBinder.BindPossibleEmbeddedStatement(node.Statement, diagnostics); Debug.Assert(this.Locals == this.GetDeclaredLocalsForScope(node)); return new BoundForStatement(node, this.Locals, initializer, innerLocals, condition, increment, body, this.BreakLabel, this.ContinueLabel); }
internal static BoundStatement BindUsingStatementOrDeclarationFromParts(SyntaxNode syntax, SyntaxToken usingKeyword, SyntaxToken awaitKeyword, Binder originalBinder, UsingStatementBinder usingBinderOpt, DiagnosticBag diagnostics) { bool isUsingDeclaration = syntax.Kind() == SyntaxKind.LocalDeclarationStatement; bool isExpression = !isUsingDeclaration && syntax.Kind() != SyntaxKind.VariableDeclaration; bool hasAwait = awaitKeyword != default; Debug.Assert(isUsingDeclaration || usingBinderOpt != null); TypeSymbol disposableInterface = getDisposableInterface(hasAwait); Debug.Assert((object)disposableInterface != null); bool hasErrors = ReportUseSiteDiagnostics(disposableInterface, diagnostics, hasAwait ? awaitKeyword : usingKeyword); Conversion iDisposableConversion = Conversion.NoConversion; ImmutableArray <BoundLocalDeclaration> declarationsOpt = default; BoundMultipleLocalDeclarations multipleDeclarationsOpt = null; BoundExpression expressionOpt = null; AwaitableInfo awaitOpt = null; TypeSymbol declarationTypeOpt = null; MethodSymbol disposeMethodOpt = null; TypeSymbol awaitableTypeOpt = null; if (isExpression) { expressionOpt = usingBinderOpt.BindTargetExpression(diagnostics, originalBinder); hasErrors |= !populateDisposableConversionOrDisposeMethod(fromExpression: true); } else { VariableDeclarationSyntax declarationSyntax = isUsingDeclaration ? ((LocalDeclarationStatementSyntax)syntax).Declaration : (VariableDeclarationSyntax)syntax; originalBinder.BindForOrUsingOrFixedDeclarations(declarationSyntax, LocalDeclarationKind.UsingVariable, diagnostics, out declarationsOpt); Debug.Assert(!declarationsOpt.IsEmpty); multipleDeclarationsOpt = new BoundMultipleLocalDeclarations(declarationSyntax, declarationsOpt); declarationTypeOpt = declarationsOpt[0].DeclaredType.Type; if (declarationTypeOpt.IsDynamic()) { iDisposableConversion = Conversion.ImplicitDynamic; } else { hasErrors |= !populateDisposableConversionOrDisposeMethod(fromExpression: false); } } if (hasAwait) { BoundAwaitableValuePlaceholder placeholderOpt; if (awaitableTypeOpt is null) { placeholderOpt = null; } else { hasErrors |= ReportUseSiteDiagnostics(awaitableTypeOpt, diagnostics, awaitKeyword); placeholderOpt = new BoundAwaitableValuePlaceholder(syntax, awaitableTypeOpt).MakeCompilerGenerated(); } // even if we don't have a proper value to await, we'll still report bad usages of `await` awaitOpt = originalBinder.BindAwaitInfo(placeholderOpt, syntax, awaitKeyword.GetLocation(), diagnostics, ref hasErrors); } // This is not awesome, but its factored. // In the future it might be better to have a seperate shared type that we add the info to, and have the callers create the appropriate bound nodes from it if (isUsingDeclaration) { return(new BoundUsingLocalDeclarations(syntax, disposeMethodOpt, iDisposableConversion, awaitOpt, declarationsOpt, hasErrors)); } else { BoundStatement boundBody = originalBinder.BindPossibleEmbeddedStatement(usingBinderOpt._syntax.Statement, diagnostics); return(new BoundUsingStatement( usingBinderOpt._syntax, usingBinderOpt.Locals, multipleDeclarationsOpt, expressionOpt, iDisposableConversion, boundBody, awaitOpt, disposeMethodOpt, hasErrors)); } // initializes iDisposableConversion, awaitableTypeOpt and disposeMethodOpt bool populateDisposableConversionOrDisposeMethod(bool fromExpression) { HashSet <DiagnosticInfo> useSiteDiagnostics = null; iDisposableConversion = classifyConversion(fromExpression, disposableInterface, ref useSiteDiagnostics); diagnostics.Add(syntax, useSiteDiagnostics); if (iDisposableConversion.IsImplicit) { if (hasAwait) { awaitableTypeOpt = originalBinder.Compilation.GetWellKnownType(WellKnownType.System_Threading_Tasks_ValueTask); } return(true); } TypeSymbol type = fromExpression ? expressionOpt.Type : declarationTypeOpt; // If this is a ref struct, or we're in a valid asynchronous using, try binding via pattern. // We won't need to try and bind a second time if it fails, as async dispose can't be pattern based (ref structs are not allowed in async methods) if (!(type is null) && (type.IsRefLikeType || hasAwait)) { BoundExpression receiver = fromExpression ? expressionOpt : new BoundLocal(syntax, declarationsOpt[0].LocalSymbol, null, type) { WasCompilerGenerated = true }; disposeMethodOpt = originalBinder.TryFindDisposePatternMethod(receiver, syntax, hasAwait, diagnostics); if (!(disposeMethodOpt is null)) { if (hasAwait) { awaitableTypeOpt = disposeMethodOpt.ReturnType; } return(true); } } if (type is null || !type.IsErrorType()) { // Retry with a different assumption about whether the `using` is async TypeSymbol alternateInterface = getDisposableInterface(!hasAwait); HashSet <DiagnosticInfo> ignored = null; Conversion alternateConversion = classifyConversion(fromExpression, alternateInterface, ref ignored); bool wrongAsync = alternateConversion.IsImplicit; ErrorCode errorCode = wrongAsync ? (hasAwait ? ErrorCode.ERR_NoConvToIAsyncDispWrongAsync : ErrorCode.ERR_NoConvToIDispWrongAsync) : (hasAwait ? ErrorCode.ERR_NoConvToIAsyncDisp : ErrorCode.ERR_NoConvToIDisp); Error(diagnostics, errorCode, syntax, declarationTypeOpt ?? expressionOpt.Display); } return(false); } Conversion classifyConversion(bool fromExpression, TypeSymbol targetInterface, ref HashSet <DiagnosticInfo> diag) { return(fromExpression ? originalBinder.Conversions.ClassifyImplicitConversionFromExpression(expressionOpt, targetInterface, ref diag) : originalBinder.Conversions.ClassifyImplicitConversionFromType(declarationTypeOpt, targetInterface, ref diag)); } TypeSymbol getDisposableInterface(bool isAsync) { return(isAsync ? originalBinder.Compilation.GetWellKnownType(WellKnownType.System_IAsyncDisposable) : originalBinder.Compilation.GetSpecialType(SpecialType.System_IDisposable)); } }
internal override BoundStatement BindUsingStatementParts(DiagnosticBag diagnostics, Binder originalBinder) { ExpressionSyntax expressionSyntax = TargetExpressionSyntax; VariableDeclarationSyntax declarationSyntax = _syntax.Declaration; bool hasAwait = _syntax.AwaitKeyword.Kind() != default; Debug.Assert((expressionSyntax == null) ^ (declarationSyntax == null)); // Can't have both or neither. TypeSymbol iDisposable = hasAwait ? this.Compilation.GetWellKnownType(WellKnownType.System_IAsyncDisposable) : this.Compilation.GetSpecialType(SpecialType.System_IDisposable); Debug.Assert((object)iDisposable != null); bool hasErrors = ReportUseSiteDiagnostics(iDisposable, diagnostics, hasAwait ? _syntax.AwaitKeyword : _syntax.UsingKeyword); Conversion iDisposableConversion = Conversion.NoConversion; BoundMultipleLocalDeclarations declarationsOpt = null; BoundExpression expressionOpt = null; AwaitableInfo awaitOpt = null; if (expressionSyntax != null) { expressionOpt = this.BindTargetExpression(diagnostics, originalBinder); HashSet <DiagnosticInfo> useSiteDiagnostics = null; iDisposableConversion = originalBinder.Conversions.ClassifyImplicitConversionFromExpression(expressionOpt, iDisposable, ref useSiteDiagnostics); diagnostics.Add(expressionSyntax, useSiteDiagnostics); if (!iDisposableConversion.IsImplicit) { TypeSymbol expressionType = expressionOpt.Type; if ((object)expressionType == null || !expressionType.IsErrorType()) { Error(diagnostics, hasAwait ? ErrorCode.ERR_NoConvToIAsyncDisp : ErrorCode.ERR_NoConvToIDisp, expressionSyntax, expressionOpt.Display); } hasErrors = true; } } else { ImmutableArray <BoundLocalDeclaration> declarations; originalBinder.BindForOrUsingOrFixedDeclarations(declarationSyntax, LocalDeclarationKind.UsingVariable, diagnostics, out declarations); Debug.Assert(!declarations.IsEmpty); declarationsOpt = new BoundMultipleLocalDeclarations(declarationSyntax, declarations); TypeSymbol declType = declarations[0].DeclaredType.Type; if (declType.IsDynamic()) { iDisposableConversion = Conversion.ImplicitDynamic; } else { HashSet <DiagnosticInfo> useSiteDiagnostics = null; iDisposableConversion = originalBinder.Conversions.ClassifyImplicitConversionFromType(declType, iDisposable, ref useSiteDiagnostics); diagnostics.Add(declarationSyntax, useSiteDiagnostics); if (!iDisposableConversion.IsImplicit) { if (!declType.IsErrorType()) { Error(diagnostics, hasAwait ? ErrorCode.ERR_NoConvToIAsyncDisp : ErrorCode.ERR_NoConvToIDisp, declarationSyntax, declType); } hasErrors = true; } } } 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); } BoundStatement boundBody = originalBinder.BindPossibleEmbeddedStatement(_syntax.Statement, diagnostics); Debug.Assert(GetDeclaredLocalsForScope(_syntax) == this.Locals); return(new BoundUsingStatement( _syntax, this.Locals, declarationsOpt, expressionOpt, iDisposableConversion, boundBody, awaitOpt, hasErrors)); }
internal override BoundStatement BindUsingStatementParts(DiagnosticBag diagnostics, Binder originalBinder) { ExpressionSyntax expressionSyntax = TargetExpressionSyntax; VariableDeclarationSyntax declarationSyntax = _syntax.Declaration; Debug.Assert((expressionSyntax == null) ^ (declarationSyntax == null)); // Can't have both or neither. bool hasErrors = false; BoundMultipleLocalDeclarations declarationsOpt = null; BoundExpression expressionOpt = null; Conversion iDisposableConversion = Conversion.NoConversion; TypeSymbol iDisposable = this.Compilation.GetSpecialType(SpecialType.System_IDisposable); // no need for diagnostics, so use the Compilation version Debug.Assert((object)iDisposable != null); if (expressionSyntax != null) { expressionOpt = this.BindTargetExpression(diagnostics, originalBinder); HashSet <DiagnosticInfo> useSiteDiagnostics = null; iDisposableConversion = originalBinder.Conversions.ClassifyImplicitConversionFromExpression(expressionOpt, iDisposable, ref useSiteDiagnostics); diagnostics.Add(expressionSyntax, useSiteDiagnostics); if (!iDisposableConversion.IsImplicit) { TypeSymbol expressionType = expressionOpt.Type; if ((object)expressionType == null || !expressionType.IsErrorType()) { Error(diagnostics, ErrorCode.ERR_NoConvToIDisp, expressionSyntax, expressionOpt.Display); } hasErrors = true; } } else { ImmutableArray <BoundLocalDeclaration> declarations; originalBinder.BindForOrUsingOrFixedDeclarations(declarationSyntax, LocalDeclarationKind.UsingVariable, diagnostics, out declarations); Debug.Assert(!declarations.IsEmpty); declarationsOpt = new BoundMultipleLocalDeclarations(declarationSyntax, declarations); TypeSymbol declType = declarations[0].DeclaredType.Type; if (declType.IsDynamic()) { iDisposableConversion = Conversion.ImplicitDynamic; } else { HashSet <DiagnosticInfo> useSiteDiagnostics = null; iDisposableConversion = originalBinder.Conversions.ClassifyImplicitConversion(declType, iDisposable, ref useSiteDiagnostics); diagnostics.Add(declarationSyntax, useSiteDiagnostics); if (!iDisposableConversion.IsImplicit) { if (!declType.IsErrorType()) { Error(diagnostics, ErrorCode.ERR_NoConvToIDisp, declarationSyntax, declType); } hasErrors = true; } } } BoundStatement boundBody = originalBinder.BindPossibleEmbeddedStatement(_syntax.Statement, diagnostics); Debug.Assert(GetDeclaredLocalsForScope(_syntax) == this.Locals); return(new BoundUsingStatement( _syntax, this.Locals, declarationsOpt, expressionOpt, iDisposableConversion, boundBody, hasErrors)); }
internal override BoundStatement BindUsingStatementParts(DiagnosticBag diagnostics, Binder originalBinder) { ExpressionSyntax expressionSyntax = TargetExpressionSyntax; VariableDeclarationSyntax declarationSyntax = _syntax.Declaration; Debug.Assert((expressionSyntax == null) ^ (declarationSyntax == null)); // Can't have both or neither. bool hasErrors = false; BoundMultipleLocalDeclarations declarationsOpt = null; BoundExpression expressionOpt = null; Conversion iDisposableConversion = Conversion.NoConversion; TypeSymbol iDisposable = this.Compilation.GetSpecialType(SpecialType.System_IDisposable); // no need for diagnostics, so use the Compilation version Debug.Assert((object)iDisposable != null); if (expressionSyntax != null) { expressionOpt = this.BindTargetExpression(diagnostics, originalBinder); HashSet<DiagnosticInfo> useSiteDiagnostics = null; iDisposableConversion = originalBinder.Conversions.ClassifyImplicitConversionFromExpression(expressionOpt, iDisposable, ref useSiteDiagnostics); diagnostics.Add(expressionSyntax, useSiteDiagnostics); if (!iDisposableConversion.IsImplicit) { TypeSymbol expressionType = expressionOpt.Type; if ((object)expressionType == null || !expressionType.IsErrorType()) { Error(diagnostics, ErrorCode.ERR_NoConvToIDisp, expressionSyntax, expressionOpt.Display); } hasErrors = true; } } else { ImmutableArray<BoundLocalDeclaration> declarations; originalBinder.BindForOrUsingOrFixedDeclarations(declarationSyntax, LocalDeclarationKind.UsingVariable, diagnostics, out declarations); Debug.Assert(!declarations.IsEmpty); declarationsOpt = new BoundMultipleLocalDeclarations(declarationSyntax, declarations); TypeSymbol declType = declarations[0].DeclaredType.Type; if (declType.IsDynamic()) { iDisposableConversion = Conversion.ImplicitDynamic; } else { HashSet<DiagnosticInfo> useSiteDiagnostics = null; iDisposableConversion = originalBinder.Conversions.ClassifyImplicitConversion(declType, iDisposable, ref useSiteDiagnostics); diagnostics.Add(declarationSyntax, useSiteDiagnostics); if (!iDisposableConversion.IsImplicit) { if (!declType.IsErrorType()) { Error(diagnostics, ErrorCode.ERR_NoConvToIDisp, declarationSyntax, declType); } hasErrors = true; } } } BoundStatement boundBody = originalBinder.BindPossibleEmbeddedStatement(_syntax.Statement, diagnostics); Debug.Assert(GetDeclaredLocalsForScope(_syntax) == this.Locals); return new BoundUsingStatement( _syntax, this.Locals, declarationsOpt, expressionOpt, iDisposableConversion, boundBody, hasErrors); }
private BoundForStatement BindForParts(ForStatementSyntax node, Binder originalBinder, BindingDiagnosticBag diagnostics) { BoundStatement initializer; // Declaration and Initializers are mutually exclusive. if (_syntax.Declaration != null) { ImmutableArray <BoundLocalDeclaration> unused; initializer = originalBinder.BindForOrUsingOrFixedDeclarations(node.Declaration, LocalDeclarationKind.RegularVariable, diagnostics, out unused); } else { initializer = originalBinder.BindStatementExpressionList(node.Initializers, diagnostics); } BoundExpression condition = null; var innerLocals = ImmutableArray <LocalSymbol> .Empty; ExpressionSyntax conditionSyntax = node.Condition; if (conditionSyntax != null) { originalBinder = originalBinder.GetBinder(conditionSyntax); condition = originalBinder.BindBooleanExpression(conditionSyntax, diagnostics); innerLocals = originalBinder.GetDeclaredLocalsForScope(conditionSyntax); } BoundStatement increment = null; SeparatedSyntaxList <ExpressionSyntax> incrementors = node.Incrementors; if (incrementors.Count > 0) { var scopeDesignator = incrementors.First(); var incrementBinder = originalBinder.GetBinder(scopeDesignator); increment = incrementBinder.BindStatementExpressionList(incrementors, diagnostics); Debug.Assert(increment.Kind != BoundKind.StatementList || ((BoundStatementList)increment).Statements.Length > 1); var locals = incrementBinder.GetDeclaredLocalsForScope(scopeDesignator); if (!locals.IsEmpty) { if (increment.Kind == BoundKind.StatementList) { increment = new BoundBlock(scopeDesignator, locals, ((BoundStatementList)increment).Statements) { WasCompilerGenerated = true }; } else { increment = new BoundBlock(increment.Syntax, locals, ImmutableArray.Create(increment)) { WasCompilerGenerated = true }; } } } var body = originalBinder.BindPossibleEmbeddedStatement(node.Statement, diagnostics); Debug.Assert(this.Locals == this.GetDeclaredLocalsForScope(node)); return(new BoundForStatement(node, this.Locals, initializer, innerLocals, condition, increment, body, this.BreakLabel, this.ContinueLabel)); }
internal override BoundStatement BindUsingStatementParts(DiagnosticBag diagnostics, Binder originalBinder) { ExpressionSyntax expressionSyntax = TargetExpressionSyntax; VariableDeclarationSyntax declarationSyntax = _syntax.Declaration; bool hasAwait = _syntax.AwaitKeyword.Kind() != default; Debug.Assert((expressionSyntax == null) ^ (declarationSyntax == null)); // Can't have both or neither. TypeSymbol disposableInterface = getDisposableInterface(hasAwait); Debug.Assert((object)disposableInterface != null); bool hasErrors = ReportUseSiteDiagnostics(disposableInterface, diagnostics, hasAwait ? _syntax.AwaitKeyword : _syntax.UsingKeyword); Conversion iDisposableConversion = Conversion.NoConversion; BoundMultipleLocalDeclarations declarationsOpt = null; BoundExpression expressionOpt = null; AwaitableInfo awaitOpt = null; TypeSymbol declarationTypeOpt = null; if (expressionSyntax != null) { expressionOpt = this.BindTargetExpression(diagnostics, originalBinder); hasErrors |= !initConversion(fromExpression: true); } else { ImmutableArray <BoundLocalDeclaration> declarations; originalBinder.BindForOrUsingOrFixedDeclarations(declarationSyntax, LocalDeclarationKind.UsingVariable, diagnostics, out declarations); Debug.Assert(!declarations.IsEmpty); declarationsOpt = new BoundMultipleLocalDeclarations(declarationSyntax, declarations); declarationTypeOpt = declarations[0].DeclaredType.Type; if (declarationTypeOpt.IsDynamic()) { iDisposableConversion = Conversion.ImplicitDynamic; } else { hasErrors |= !initConversion(fromExpression: false); } } 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); } BoundStatement boundBody = originalBinder.BindPossibleEmbeddedStatement(_syntax.Statement, diagnostics); Debug.Assert(GetDeclaredLocalsForScope(_syntax) == this.Locals); return(new BoundUsingStatement( _syntax, this.Locals, declarationsOpt, expressionOpt, iDisposableConversion, boundBody, awaitOpt, hasErrors)); bool initConversion(bool fromExpression) { HashSet <DiagnosticInfo> useSiteDiagnostics = null; iDisposableConversion = classifyConversion(fromExpression, disposableInterface, ref useSiteDiagnostics); diagnostics.Add(fromExpression ? (CSharpSyntaxNode)expressionSyntax : declarationSyntax, useSiteDiagnostics); if (iDisposableConversion.IsImplicit) { return(true); } TypeSymbol type = fromExpression ? expressionOpt.Type : declarationTypeOpt; if (type is null || !type.IsErrorType()) { // Retry with a different assumption about whether the `using` is async TypeSymbol alternateInterface = getDisposableInterface(!hasAwait); HashSet <DiagnosticInfo> ignored = null; Conversion alternateConversion = classifyConversion(fromExpression, alternateInterface, ref ignored); bool wrongAsync = alternateConversion.IsImplicit; ErrorCode errorCode = wrongAsync ? (hasAwait ? ErrorCode.ERR_NoConvToIAsyncDispWrongAsync : ErrorCode.ERR_NoConvToIDispWrongAsync) : (hasAwait ? ErrorCode.ERR_NoConvToIAsyncDisp : ErrorCode.ERR_NoConvToIDisp); Error(diagnostics, errorCode, (CSharpSyntaxNode)declarationSyntax ?? expressionSyntax, declarationTypeOpt ?? expressionOpt.Display); } return(false); } Conversion classifyConversion(bool fromExpression, TypeSymbol targetInterface, ref HashSet <DiagnosticInfo> diag) { return(fromExpression ? originalBinder.Conversions.ClassifyImplicitConversionFromExpression(expressionOpt, targetInterface, ref diag) : originalBinder.Conversions.ClassifyImplicitConversionFromType(declarationTypeOpt, targetInterface, ref diag)); } TypeSymbol getDisposableInterface(bool isAsync) { return(isAsync ? this.Compilation.GetWellKnownType(WellKnownType.System_IAsyncDisposable) : this.Compilation.GetSpecialType(SpecialType.System_IDisposable)); } }