/// <summary>
        /// Rewrite a using statement into a try finally statement.  Two forms are possible:
        ///   1) using (expr) stmt
        ///   2) using (C c = expr) stmt
        ///   
        /// The former is handled by RewriteExpressionUsingStatement and the latter is handled by
        /// RewriteDeclarationUsingStatement (called in a loop, once for each local declared).
        /// </summary>
        /// <remarks>
        /// It would be more in line with our usual pattern to rewrite using to try-finally
        /// in the ControlFlowRewriter, but if we don't do it here the BoundMultipleLocalDeclarations
        /// will be rewritten into a form that makes them harder to separate.
        /// </remarks>
        public override BoundNode VisitUsingStatement(BoundUsingStatement node)
        {
            BoundStatement rewrittenBody = (BoundStatement)Visit(node.Body);

            BoundBlock tryBlock = rewrittenBody.Kind == BoundKind.Block
                ? (BoundBlock)rewrittenBody
                : BoundBlock.SynthesizedNoLocals(node.Syntax, rewrittenBody);

            if (node.ExpressionOpt != null)
            {
                return RewriteExpressionUsingStatement(node, tryBlock);
            }
            else
            {
                Debug.Assert(node.DeclarationsOpt != null);

                SyntaxNode usingSyntax = node.Syntax;
                Conversion idisposableConversion = node.IDisposableConversion;
                ImmutableArray<BoundLocalDeclaration> declarations = node.DeclarationsOpt.LocalDeclarations;

                BoundBlock result = tryBlock;

                int numDeclarations = declarations.Length;
                for (int i = numDeclarations - 1; i >= 0; i--) //NB: inner-to-outer = right-to-left
                {
                    result = RewriteDeclarationUsingStatement(usingSyntax, declarations[i], result, idisposableConversion);
                }

                // Declare all locals in a single, top-level block so that the scope is correct in the debugger
                // (Dev10 has them all come into scope at once, not per-declaration.)
                return new BoundBlock(
                    usingSyntax,
                    node.Locals,
                    ImmutableArray<LocalFunctionSymbol>.Empty,
                    ImmutableArray.Create<BoundStatement>(result));
            }
        }
        /// <summary>
        /// Lower "using (expression) statement" to a try-finally block.
        /// </summary>
        private BoundBlock RewriteExpressionUsingStatement(BoundUsingStatement node, BoundBlock tryBlock)
        {
            Debug.Assert(node.ExpressionOpt != null);
            Debug.Assert(node.DeclarationsOpt == null);

            // See comments in BuildUsingTryFinally for the details of the lowering to try-finally.
            //
            // SPEC: A using statement of the form "using (expression) statement; " has the 
            // SPEC: same three possible expansions [ as "using (ResourceType r = expression) statement; ]
            // SPEC: but in this case ResourceType is implicitly the compile-time type of the expression,
            // SPEC: and the resource variable is inaccessible to and invisible to the embedded statement.
            //
            // DELIBERATE SPEC VIOLATION: 
            //
            // The spec quote above implies that the expression must have a type; in fact we allow
            // the expression to be null.
            //
            // If expr is the constant null then we can elide the whole thing and simply generate the statement. 

            BoundExpression rewrittenExpression = (BoundExpression)Visit(node.ExpressionOpt);
            if (rewrittenExpression.ConstantValue == ConstantValue.Null)
            {
                Debug.Assert(node.Locals.IsEmpty); // TODO: This might not be a valid assumption in presence of semicolon operator.
                return tryBlock;
            }

            // Otherwise, we lower "using(expression) statement;" as follows:
            //
            // * If the expression is of type dynamic then we lower as though the user had written
            //
            //   using(IDisposable temp = (IDisposable)expression) statement;
            //
            //   Note that we have to do the conversion early, not in the finally block, because
            //   if the conversion fails at runtime with an exception then the exception must happen
            //   before the statement runs.
            //
            // * Otherwise we lower as though the user had written
            // 
            //   using(ResourceType temp = expression) statement;
            //

            TypeSymbol expressionType = rewrittenExpression.Type;
            CSharpSyntaxNode expressionSyntax = rewrittenExpression.Syntax;
            UsingStatementSyntax usingSyntax = (UsingStatementSyntax)node.Syntax;

            BoundAssignmentOperator tempAssignment;
            BoundLocal boundTemp;
            if ((object)expressionType == null || expressionType.IsDynamic())
            {
                // IDisposable temp = (IDisposable) expr;
                BoundExpression tempInit = MakeConversion(
                    expressionSyntax,
                    rewrittenExpression,
                    node.IDisposableConversion.Kind,
                    this.compilation.GetSpecialType(SpecialType.System_IDisposable),
                    @checked: false,
                    constantValueOpt: rewrittenExpression.ConstantValue);

                boundTemp = this.factory.StoreToTemp(tempInit, out tempAssignment);
            }
            else
            {
                // ResourceType temp = expr;
                boundTemp = this.factory.StoreToTemp(rewrittenExpression, out tempAssignment, kind: SynthesizedLocalKind.Using);
            }

            BoundStatement expressionStatement = new BoundExpressionStatement(expressionSyntax, tempAssignment);
            if (this.generateDebugInfo)
            {
                expressionStatement = AddSequencePoint(usingSyntax, expressionStatement);
            }

            BoundStatement tryFinally = RewriteUsingStatementTryFinally(usingSyntax, tryBlock, boundTemp);

            // { ResourceType temp = expr; try { ... } finally { ... } }
            return new BoundBlock(
                syntax: usingSyntax,
                locals: node.Locals.Add(boundTemp.LocalSymbol),
                statements: ImmutableArray.Create<BoundStatement>(expressionStatement, tryFinally));
        }
 public override BoundNode VisitUsingStatement(BoundUsingStatement node)
 {
     throw ExceptionUtilities.Unreachable; // using statements have been lowered away by now
 }
示例#4
0
 public override BoundStatement InstrumentUsingTargetCapture(BoundUsingStatement original, BoundStatement usingTargetCapture)
 {
     return Previous.InstrumentUsingTargetCapture(original, usingTargetCapture);
 }
示例#5
0
 public override BoundStatement InstrumentUsingTargetCapture(BoundUsingStatement original, BoundStatement usingTargetCapture)
 {
     return AddSequencePoint((UsingStatementSyntax)original.Syntax, 
                             base.InstrumentUsingTargetCapture(original, usingTargetCapture));
 }
示例#6
0
 public override BoundStatement InstrumentUsingTargetCapture(BoundUsingStatement original, BoundStatement usingTargetCapture)
 {
     return AddDynamicAnalysis(original, base.InstrumentUsingTargetCapture(original, usingTargetCapture));
 }
示例#7
0
 public virtual BoundStatement InstrumentUsingTargetCapture(BoundUsingStatement original, BoundStatement usingTargetCapture)
 {
     Debug.Assert(!original.WasCompilerGenerated);
     Debug.Assert(original.Syntax.Kind() == SyntaxKind.UsingStatement);
     return usingTargetCapture;
 }
示例#8
0
 public override BoundStatement InstrumentUsingTargetCapture(BoundUsingStatement original, BoundStatement usingTargetCapture)
 {
     return(AddSequencePoint((UsingStatementSyntax)original.Syntax,
                             base.InstrumentUsingTargetCapture(original, usingTargetCapture)));
 }
示例#9
0
 public virtual BoundStatement InstrumentUsingTargetCapture(BoundUsingStatement original, BoundStatement usingTargetCapture)
 {
     Debug.Assert(!original.WasCompilerGenerated);
     Debug.Assert(original.Syntax.Kind() == SyntaxKind.UsingStatement);
     return(usingTargetCapture);
 }
示例#10
0
        /// <summary>
        /// Lower "using (expression) statement" to a try-finally block.
        /// </summary>
        private BoundBlock RewriteExpressionUsingStatement(BoundUsingStatement node, BoundBlock tryBlock)
        {
            Debug.Assert(node.ExpressionOpt != null);
            Debug.Assert(node.DeclarationsOpt == null);

            // See comments in BuildUsingTryFinally for the details of the lowering to try-finally.
            //
            // SPEC: A using statement of the form "using (expression) statement; " has the
            // SPEC: same three possible expansions [ as "using (ResourceType r = expression) statement; ]
            // SPEC: but in this case ResourceType is implicitly the compile-time type of the expression,
            // SPEC: and the resource variable is inaccessible to and invisible to the embedded statement.
            //
            // DELIBERATE SPEC VIOLATION:
            //
            // The spec quote above implies that the expression must have a type; in fact we allow
            // the expression to be null.
            //
            // If expr is the constant null then we can elide the whole thing and simply generate the statement.

            BoundExpression rewrittenExpression = (BoundExpression)Visit(node.ExpressionOpt);

            if (rewrittenExpression.ConstantValue == ConstantValue.Null)
            {
                Debug.Assert(node.Locals.IsEmpty); // TODO: This might not be a valid assumption in presence of semicolon operator.
                return(tryBlock);
            }

            // Otherwise, we lower "using(expression) statement;" as follows:
            //
            // * If the expression is of type dynamic then we lower as though the user had written
            //
            //   using(IDisposable temp = (IDisposable)expression) statement;
            //
            //   Note that we have to do the conversion early, not in the finally block, because
            //   if the conversion fails at runtime with an exception then the exception must happen
            //   before the statement runs.
            //
            // * Otherwise we lower as though the user had written
            //
            //   using(ResourceType temp = expression) statement;
            //

            TypeSymbol           expressionType   = rewrittenExpression.Type;
            SyntaxNode           expressionSyntax = rewrittenExpression.Syntax;
            UsingStatementSyntax usingSyntax      = (UsingStatementSyntax)node.Syntax;

            BoundAssignmentOperator tempAssignment;
            BoundLocal boundTemp;

            if ((object)expressionType == null || expressionType.IsDynamic())
            {
                // IDisposable temp = (IDisposable) expr;
                BoundExpression tempInit = MakeConversionNode(
                    expressionSyntax,
                    rewrittenExpression,
                    Conversion.GetTrivialConversion(node.IDisposableConversion.Kind),
                    _compilation.GetSpecialType(SpecialType.System_IDisposable),
                    @checked: false,
                    constantValueOpt: rewrittenExpression.ConstantValue);

                boundTemp = _factory.StoreToTemp(tempInit, out tempAssignment, kind: SynthesizedLocalKind.Using);
            }
            else
            {
                // ResourceType temp = expr;
                boundTemp = _factory.StoreToTemp(rewrittenExpression, out tempAssignment, syntaxOpt: usingSyntax, kind: SynthesizedLocalKind.Using);
            }

            BoundStatement expressionStatement = new BoundExpressionStatement(expressionSyntax, tempAssignment);

            if (this.Instrument)
            {
                expressionStatement = _instrumenter.InstrumentUsingTargetCapture(node, expressionStatement);
            }

            BoundStatement tryFinally = RewriteUsingStatementTryFinally(usingSyntax, tryBlock, boundTemp);

            // { ResourceType temp = expr; try { ... } finally { ... } }
            return(new BoundBlock(
                       syntax: usingSyntax,
                       locals: node.Locals.Add(boundTemp.LocalSymbol),
                       localFunctions: ImmutableArray <LocalFunctionSymbol> .Empty,
                       statements: ImmutableArray.Create <BoundStatement>(expressionStatement, tryFinally)));
        }
示例#11
0
 public override BoundNode VisitUsingStatement(BoundUsingStatement node)
 {
     throw ExceptionUtilities.Unreachable; // using statements have been lowered away by now
 }
示例#12
0
        /// <summary>
        /// Rewrite a using statement into a try finally statement.  Four forms are possible:
        ///   1) using (expr) stmt
        ///   2) await using (expr) stmt
        ///   3) using (C c = expr) stmt
        ///   4) await using (C c = expr) stmt
        ///
        /// The first two are handled by RewriteExpressionUsingStatement and the latter two are handled by
        /// RewriteDeclarationUsingStatement (called in a loop, once for each local declared).
        ///
        /// For the async variants, `IAsyncDisposable` is used instead of `IDisposable` and we produce
        /// `... await expr.DisposeAsync() ...` instead of `... expr.Dispose() ...`.
        /// </summary>
        /// <remarks>
        /// It would be more in line with our usual pattern to rewrite using to try-finally
        /// in the ControlFlowRewriter, but if we don't do it here the BoundMultipleLocalDeclarations
        /// will be rewritten into a form that makes them harder to separate.
        /// </remarks>
        public override BoundNode VisitUsingStatement(BoundUsingStatement node)
        {
            BoundStatement?rewrittenBody = VisitStatement(node.Body);

            Debug.Assert(rewrittenBody is { });
示例#13
0
 public override BoundNode VisitUsingStatement(BoundUsingStatement node)
 {
     Fail(node);
     return(null);
 }
        /// <summary>
        /// Lower "using (expression) statement" to a try-finally block.
        /// </summary>
        private BoundBlock RewriteExpressionUsingStatement(BoundUsingStatement node, BoundBlock tryBlock)
        {
            Debug.Assert(node.ExpressionOpt != null);
            Debug.Assert(node.DeclarationsOpt == null);

            // See comments in BuildUsingTryFinally for the details of the lowering to try-finally.
            //
            // SPEC: A using statement of the form "using (expression) statement; " has the
            // SPEC: same three possible expansions [ as "using (ResourceType r = expression) statement; ]
            // SPEC: but in this case ResourceType is implicitly the compile-time type of the expression,
            // SPEC: and the resource variable is inaccessible to and invisible to the embedded statement.
            //
            // DELIBERATE SPEC VIOLATION:
            //
            // The spec quote above implies that the expression must have a type; in fact we allow
            // the expression to be null.
            //
            // If expr is the constant null then we can elide the whole thing and simply generate the statement.

            BoundExpression rewrittenExpression = (BoundExpression)Visit(node.ExpressionOpt);

            if (rewrittenExpression.ConstantValue == ConstantValue.Null)
            {
                return(tryBlock);
            }

            // Otherwise, we lower "using(expression) statement;" as follows:
            //
            // * If the expression is of type dynamic then we lower as though the user had written
            //
            //   using(IDisposable temp = (IDisposable)expression) statement;
            //
            //   Note that we have to do the conversion early, not in the finally block, because
            //   if the conversion fails at runtime with an exception then the exception must happen
            //   before the statement runs.
            //
            // * Otherwise we lower as though the user had written
            //
            //   using(ResourceType temp = expression) statement;
            //

            TypeSymbol           expressionType   = rewrittenExpression.Type;
            CSharpSyntaxNode     expressionSyntax = rewrittenExpression.Syntax;
            UsingStatementSyntax usingSyntax      = (UsingStatementSyntax)node.Syntax;

            BoundAssignmentOperator tempAssignment;
            BoundLocal boundTemp;

            if ((object)expressionType == null || expressionType.IsDynamic())
            {
                // IDisposable temp = (IDisposable) expr;
                BoundExpression tempInit = MakeConversion(
                    expressionSyntax,
                    rewrittenExpression,
                    node.IDisposableConversion.Kind,
                    this.compilation.GetSpecialType(SpecialType.System_IDisposable),
                    @checked: false,
                    constantValueOpt: rewrittenExpression.ConstantValue);

                boundTemp = this.factory.StoreToTemp(tempInit, out tempAssignment);
            }
            else
            {
                // ResourceType temp = expr;
                boundTemp = this.factory.StoreToTemp(rewrittenExpression, tempKind: TempKind.Using, store: out tempAssignment);
            }

            BoundStatement expressionStatement = new BoundExpressionStatement(expressionSyntax, tempAssignment);

            if (this.generateDebugInfo)
            {
                // NOTE: unlike in the assignment case, the sequence point is on the using keyword, not the expression.
                expressionStatement = new BoundSequencePointWithSpan(usingSyntax, expressionStatement, usingSyntax.UsingKeyword.Span);
            }

            BoundStatement tryFinally = RewriteUsingStatementTryFinally(usingSyntax, tryBlock, boundTemp);

            // { ResourceType temp = expr; try { ... } finally { ... } }
            return(new BoundBlock(
                       syntax: usingSyntax,
                       localsOpt: ImmutableArray.Create <LocalSymbol>(boundTemp.LocalSymbol),
                       statements: ImmutableArray.Create <BoundStatement>(expressionStatement, tryFinally)));
        }
示例#15
0
 public override BoundStatement InstrumentUsingTargetCapture(BoundUsingStatement original, BoundStatement usingTargetCapture)
 {
     return(AddDynamicAnalysis(original, base.InstrumentUsingTargetCapture(original, usingTargetCapture)));
 }
示例#16
0
 public override BoundStatement InstrumentUsingTargetCapture(BoundUsingStatement original, BoundStatement usingTargetCapture)
 {
     return(Previous.InstrumentUsingTargetCapture(original, usingTargetCapture));
 }