示例#1
0
 internal void Parse(BoundAsOperator boundAsOperator)
 {
     base.Parse(boundAsOperator);
     this.ConversionKind = boundAsOperator.Conversion.Kind;
     this.TargetType     = Deserialize(boundAsOperator.TargetType) as TypeExpression;
     this.Operand        = Deserialize(boundAsOperator.Operand) as Expression;
 }
示例#2
0
        public override BoundNode VisitAsOperator(BoundAsOperator node)
        {
            BoundSpillSequenceBuilder builder = null;
            var operand = VisitExpression(ref builder, node.Operand);

            return(UpdateExpression(builder, node.Update(operand, node.TargetType, node.Conversion, node.Type)));
        }
示例#3
0
        public override BoundNode VisitAsOperator(BoundAsOperator node)
        {
            BoundExpression rewrittenOperand    = VisitExpression(node.Operand);
            var             rewrittenTargetType = (BoundTypeExpression)VisitTypeExpression(node.TargetType);
            TypeSymbol      rewrittenType       = VisitType(node.Type);

            return(MakeAsOperator(node, node.Syntax, rewrittenOperand, rewrittenTargetType, node.Conversion, rewrittenType));
        }
        private BoundExpression VisitAsOperator(BoundAsOperator node)
        {
            if (node.Operand.IsLiteralNull() && (object)node.Operand.Type == null)
            {
                var operand = _bound.Null(_bound.SpecialType(SpecialType.System_Object));
                node = node.Update(operand, node.TargetType, node.Conversion, node.Type);
            }

            return(ExprFactory("TypeAs", Visit(node.Operand), _bound.Typeof(node.Type)));
        }
示例#5
0
        private BoundExpression MakeAsOperator(
            BoundAsOperator oldNode,
            SyntaxNode syntax,
            BoundExpression rewrittenOperand,
            BoundTypeExpression rewrittenTargetType,
            Conversion conversion,
            TypeSymbol rewrittenType)
        {
            // TODO: Handle dynamic operand type and target type
            Debug.Assert(rewrittenTargetType.Type.Equals(rewrittenType));

            // target type cannot be a non-nullable value type
            Debug.Assert(!rewrittenType.IsValueType || rewrittenType.IsNullableType());

            if (!_inExpressionLambda)
            {
                ConstantValue constantValue = Binder.GetAsOperatorConstantResult(rewrittenOperand.Type, rewrittenType, conversion.Kind, rewrittenOperand.ConstantValue);

                if (constantValue != null)
                {
                    Debug.Assert(constantValue.IsNull);
                    BoundExpression result = rewrittenType.IsNullableType() ? new BoundDefaultExpression(syntax, rewrittenType) : MakeLiteral(syntax, constantValue, rewrittenType);

                    if (rewrittenOperand.ConstantValue != null)
                    {
                        // No need to preserve any side-effects from the operand.
                        // We also can keep the "constant" notion of the result, which
                        // enables some optimizations down the road.
                        return(result);
                    }

                    return(new BoundSequence(
                               syntax: syntax,
                               locals: ImmutableArray <LocalSymbol> .Empty,
                               sideEffects: ImmutableArray.Create <BoundExpression>(rewrittenOperand),
                               value: result,
                               type: rewrittenType));
                }

                if (conversion.IsImplicit)
                {
                    // Operand with bound implicit conversion to target type.
                    // We don't need a runtime check, generate a conversion for the operand instead.
                    return(MakeConversionNode(syntax, rewrittenOperand, conversion, rewrittenType, @checked: false));
                }
            }

            return(oldNode.Update(rewrittenOperand, rewrittenTargetType, conversion, rewrittenType));
        }
        public override BoundNode VisitAsOperator(BoundAsOperator node)
        {
            BoundExpression     operand    = (BoundExpression)this.Visit(node.Operand);
            BoundTypeExpression targetType = (BoundTypeExpression)this.Visit(node.TargetType);
            TypeSymbol          type       = this.VisitType(node.Type);

            if (operand.Kind != BoundKind.SpillSequence)
            {
                return(node.Update(operand, targetType, node.Conversion, type));
            }

            var spill         = (BoundSpillSequence)operand;
            var newAsOperator = node.Update(spill.Value, targetType, node.Conversion, type);

            return(RewriteSpillSequence(spill, newAsOperator));
        }
示例#7
0
        public override BoundNode VisitAsOperator(BoundAsOperator node)
        {
            // rewrite is needed only for cases where there are no errors and
            // no warnings (i.e. non-constant result) generated during binding
            if (!node.HasErrors && node.ConstantValue == null)
            {
                BoundExpression operand     = node.Operand;
                var             targetType  = node.TargetType.Type;
                var             operandType = operand.Type;

                // target type cannot be a non-nullable value type
                Debug.Assert(!(targetType.IsValueType && !targetType.IsNullableType()));
                if (operandType != null && operandType.IsSameType(targetType))
                {
                    // operand with bound identity or implicit conversion
                    // we don't need a runtime check
                    return(Visit(operand));
                }
            }
            return(base.VisitAsOperator(node));
        }
        public override BoundNode VisitAsOperator(BoundAsOperator node)
        {
            // rewrite is needed only for cases where there are no errors and 
            // no warnings (i.e. non-constant result) generated during binding
            if (!node.HasErrors && node.ConstantValue == null)
            {
                BoundExpression operand = node.Operand;
                var targetType = node.TargetType.Type;
                var operandType = operand.Type;

                // target type cannot be a non-nullable value type
                Debug.Assert(!(targetType.IsValueType && !targetType.IsNullableType()));
                if (operandType != null && operandType.IsSameType(targetType))
                {
                    // operand with bound identity or implicit conversion
                    // we don't need a runtime check
                    return Visit(operand);
                }
            }
            return base.VisitAsOperator(node);
        }
        private BoundExpression MakeAsOperator(
            BoundAsOperator oldNode,
            CSharpSyntaxNode syntax,
            BoundExpression rewrittenOperand,
            BoundTypeExpression rewrittenTargetType,
            Conversion conversion,
            TypeSymbol rewrittenType)
        {
            // TODO: Handle dynamic operand type and target type
            Debug.Assert(rewrittenTargetType.Type.Equals(rewrittenType));

            // target type cannot be a non-nullable value type
            Debug.Assert(!rewrittenType.IsValueType || rewrittenType.IsNullableType());

            if (!inExpressionLambda)
            {
                ConstantValue constantValue = Binder.GetAsOperatorConstantResult(rewrittenOperand.Type, rewrittenType, conversion.Kind, rewrittenOperand.ConstantValue);
                Debug.Assert(constantValue == null || constantValue.IsNull);

                if (conversion.IsImplicit)
                {
                    // Operand with bound implicit conversion to target type.
                    // We don't need a runtime check, generate a conversion for the operand instead.
                    return(MakeConversion(syntax, rewrittenOperand, conversion, rewrittenType, @checked: false, constantValueOpt: constantValue));
                }
                else if (constantValue != null)
                {
                    return(new BoundSequence(
                               syntax: syntax,
                               locals: ImmutableArray <LocalSymbol> .Empty,
                               sideEffects: ImmutableArray.Create <BoundExpression>(rewrittenOperand),
                               value: MakeLiteral(syntax, constantValue, rewrittenType),
                               type: rewrittenType));
                }
            }

            return(oldNode.Update(rewrittenOperand, rewrittenTargetType, conversion, rewrittenType));
        }
示例#10
0
        private void EmitAsExpression(BoundAsOperator asOp, bool used)
        {
            Debug.Assert(!asOp.Conversion.Kind.IsImplicitConversion());

            var operand = asOp.Operand;
            EmitExpression(operand, used);

            if (used)
            {
                var operandType = operand.Type;
                var targetType = asOp.Type;
                Debug.Assert((object)targetType != null);
                if ((object)operandType != null && !operandType.IsVerifierReference())
                {
                    // box the operand for isinst if it is not a verifier reference
                    EmitBox(operandType, operand.Syntax);
                }
                _builder.EmitOpCode(ILOpCode.Isinst);
                EmitSymbolToken(targetType, asOp.Syntax);
                if (!targetType.IsVerifierReference())
                {
                    // We need to unbox if the target type is not a reference type
                    _builder.EmitOpCode(ILOpCode.Unbox_any);
                    EmitSymbolToken(targetType, asOp.Syntax);
                }
            }
        }
        /// <summary>
        /// Lower a foreach loop that will enumerate a collection using an enumerator.
        ///
        /// E e = ((C)(x)).GetEnumerator()
        /// try {
        ///     while (e.MoveNext()) {
        ///         V v = (V)(T)e.Current;
        ///         // body
        ///     }
        /// }
        /// finally {
        ///     // clean up e
        /// }
        /// </summary>
        private BoundStatement RewriteEnumeratorForEachStatement(BoundForEachStatement node)
        {
            ForEachStatementSyntax forEachSyntax = (ForEachStatementSyntax)node.Syntax;

            ForEachEnumeratorInfo enumeratorInfo = node.EnumeratorInfoOpt;

            Debug.Assert(enumeratorInfo != null);

            BoundExpression collectionExpression = GetUnconvertedCollectionExpression(node);
            BoundExpression rewrittenExpression  = (BoundExpression)Visit(collectionExpression);
            BoundStatement  rewrittenBody        = (BoundStatement)Visit(node.Body);

            TypeSymbol enumeratorType = enumeratorInfo.GetEnumeratorMethod.ReturnType;
            TypeSymbol elementType    = enumeratorInfo.ElementType;

            // E e
            LocalSymbol enumeratorVar = _factory.SynthesizedLocal(enumeratorType, syntax: forEachSyntax, kind: SynthesizedLocalKind.ForEachEnumerator);

            // Reference to e.
            BoundLocal boundEnumeratorVar = MakeBoundLocal(forEachSyntax, enumeratorVar, enumeratorType);

            // ((C)(x)).GetEnumerator() or (x).GetEnumerator();
            BoundExpression enumeratorVarInitValue = SynthesizeCall(forEachSyntax, rewrittenExpression, enumeratorInfo.GetEnumeratorMethod, enumeratorInfo.CollectionConversion, enumeratorInfo.CollectionType);

            // E e = ((C)(x)).GetEnumerator();
            BoundStatement enumeratorVarDecl = MakeLocalDeclaration(forEachSyntax, enumeratorVar, enumeratorVarInitValue);

            AddForEachExpressionSequencePoint(forEachSyntax, ref enumeratorVarDecl);

            // V v
            LocalSymbol iterationVar = node.IterationVariable;

            //(V)(T)e.Current
            BoundExpression iterationVarAssignValue = MakeConversion(
                syntax: forEachSyntax,
                rewrittenOperand: MakeConversion(
                    syntax: forEachSyntax,
                    rewrittenOperand: BoundCall.Synthesized(
                        syntax: forEachSyntax,
                        receiverOpt: boundEnumeratorVar,
                        method: enumeratorInfo.CurrentPropertyGetter),
                    conversion: enumeratorInfo.CurrentConversion,
                    rewrittenType: elementType,
                    @checked: node.Checked),
                conversion: node.ElementConversion,
                rewrittenType: iterationVar.Type,
                @checked: node.Checked);

            // V v = (V)(T)e.Current;
            BoundStatement iterationVarDecl = MakeLocalDeclaration(forEachSyntax, iterationVar, iterationVarAssignValue);

            AddForEachIterationVariableSequencePoint(forEachSyntax, ref iterationVarDecl);

            // while (e.MoveNext()) {
            //     V v = (V)(T)e.Current;
            //     /* node.Body */
            // }

            var rewrittenBodyBlock = CreateBlockDeclaringIterationVariable(iterationVar, iterationVarDecl, rewrittenBody, forEachSyntax);

            BoundStatement whileLoop = RewriteWhileStatement(
                syntax: forEachSyntax,
                rewrittenCondition: BoundCall.Synthesized(
                    syntax: forEachSyntax,
                    receiverOpt: boundEnumeratorVar,
                    method: enumeratorInfo.MoveNextMethod),
                conditionSequencePointSpan: forEachSyntax.InKeyword.Span,
                rewrittenBody: rewrittenBodyBlock,
                breakLabel: node.BreakLabel,
                continueLabel: node.ContinueLabel,
                hasErrors: false);

            BoundStatement result;

            MethodSymbol disposeMethod;

            if (enumeratorInfo.NeedsDisposeMethod && Binder.TryGetSpecialTypeMember(_compilation, SpecialMember.System_IDisposable__Dispose, forEachSyntax, _diagnostics, out disposeMethod))
            {
                Binder.ReportDiagnosticsIfObsolete(_diagnostics, disposeMethod, forEachSyntax,
                                                   hasBaseReceiver: false,
                                                   containingMember: _factory.CurrentMethod,
                                                   containingType: _factory.CurrentType,
                                                   location: enumeratorInfo.Location);

                BoundBlock finallyBlockOpt;
                var        idisposableTypeSymbol = disposeMethod.ContainingType;
                var        conversions           = new TypeConversions(_factory.CurrentMethod.ContainingAssembly.CorLibrary);

                HashSet <DiagnosticInfo> useSiteDiagnostics = null;
                var isImplicit = conversions.ClassifyImplicitConversion(enumeratorType, idisposableTypeSymbol, ref useSiteDiagnostics).IsImplicit;
                _diagnostics.Add(forEachSyntax, useSiteDiagnostics);

                if (isImplicit)
                {
                    Debug.Assert(enumeratorInfo.NeedsDisposeMethod);

                    Conversion receiverConversion = enumeratorType.IsStructType() ?
                                                    Conversion.Boxing :
                                                    Conversion.ImplicitReference;

                    // ((IDisposable)e).Dispose(); or e.Dispose();
                    BoundStatement disposeCall = new BoundExpressionStatement(forEachSyntax,
                                                                              expression: SynthesizeCall(forEachSyntax, boundEnumeratorVar, disposeMethod, receiverConversion, idisposableTypeSymbol));

                    BoundStatement disposeStmt;
                    if (enumeratorType.IsValueType)
                    {
                        // No way for the struct to be nullable and disposable.
                        Debug.Assert(((TypeSymbol)enumeratorType.OriginalDefinition).SpecialType != SpecialType.System_Nullable_T);

                        // For non-nullable structs, no null check is required.
                        disposeStmt = disposeCall;
                    }
                    else
                    {
                        // NB: cast to object missing from spec.  Needed to ignore user-defined operators and box type parameters.
                        // if ((object)e != null) ((IDisposable)e).Dispose();
                        disposeStmt = RewriteIfStatement(
                            syntax: forEachSyntax,
                            rewrittenCondition: new BoundBinaryOperator(forEachSyntax,
                                                                        operatorKind: BinaryOperatorKind.NotEqual,
                                                                        left: MakeConversion(
                                                                            syntax: forEachSyntax,
                                                                            rewrittenOperand: boundEnumeratorVar,
                                                                            conversion: enumeratorInfo.EnumeratorConversion,
                                                                            rewrittenType: _compilation.GetSpecialType(SpecialType.System_Object),
                                                                            @checked: false),
                                                                        right: MakeLiteral(forEachSyntax,
                                                                                           constantValue: ConstantValue.Null,
                                                                                           type: null),
                                                                        constantValueOpt: null,
                                                                        methodOpt: null,
                                                                        resultKind: LookupResultKind.Viable,
                                                                        type: _compilation.GetSpecialType(SpecialType.System_Boolean)),
                            rewrittenConsequence: disposeCall,
                            rewrittenAlternativeOpt: null,
                            hasErrors: false);
                    }

                    finallyBlockOpt = new BoundBlock(forEachSyntax,
                                                     locals: ImmutableArray <LocalSymbol> .Empty,
                                                     localFunctions: ImmutableArray <LocalFunctionSymbol> .Empty,
                                                     statements: ImmutableArray.Create <BoundStatement>(disposeStmt));
                }
                else
                {
                    Debug.Assert(!enumeratorType.IsSealed);

                    // IDisposable d
                    LocalSymbol disposableVar = _factory.SynthesizedLocal(idisposableTypeSymbol);

                    // Reference to d.
                    BoundLocal boundDisposableVar = MakeBoundLocal(forEachSyntax, disposableVar, idisposableTypeSymbol);

                    BoundTypeExpression boundIDisposableTypeExpr = new BoundTypeExpression(forEachSyntax,
                                                                                           aliasOpt: null,
                                                                                           type: idisposableTypeSymbol);

                    // e as IDisposable
                    BoundExpression disposableVarInitValue = new BoundAsOperator(forEachSyntax,
                                                                                 operand: boundEnumeratorVar,
                                                                                 targetType: boundIDisposableTypeExpr,
                                                                                 conversion: Conversion.ExplicitReference, // Explicit so the emitter won't optimize it away.
                                                                                 type: idisposableTypeSymbol);

                    // IDisposable d = e as IDisposable;
                    BoundStatement disposableVarDecl = MakeLocalDeclaration(forEachSyntax, disposableVar, disposableVarInitValue);

                    // if (d != null) d.Dispose();
                    BoundStatement ifStmt = RewriteIfStatement(
                        syntax: forEachSyntax,
                        rewrittenCondition: new BoundBinaryOperator(forEachSyntax,
                                                                    operatorKind: BinaryOperatorKind.NotEqual, // reference equality
                                                                    left: boundDisposableVar,
                                                                    right: MakeLiteral(forEachSyntax,
                                                                                       constantValue: ConstantValue.Null,
                                                                                       type: null),
                                                                    constantValueOpt: null,
                                                                    methodOpt: null,
                                                                    resultKind: LookupResultKind.Viable,
                                                                    type: _compilation.GetSpecialType(SpecialType.System_Boolean)),
                        rewrittenConsequence: new BoundExpressionStatement(forEachSyntax,
                                                                           expression: BoundCall.Synthesized(
                                                                               syntax: forEachSyntax,
                                                                               receiverOpt: boundDisposableVar,
                                                                               method: disposeMethod)),
                        rewrittenAlternativeOpt: null,
                        hasErrors: false);

                    // IDisposable d = e as IDisposable;
                    // if (d != null) d.Dispose();
                    finallyBlockOpt = new BoundBlock(forEachSyntax,
                                                     locals: ImmutableArray.Create <LocalSymbol>(disposableVar),
                                                     localFunctions: ImmutableArray <LocalFunctionSymbol> .Empty,
                                                     statements: ImmutableArray.Create <BoundStatement>(disposableVarDecl, ifStmt));
                }

                // try {
                //     while (e.MoveNext()) {
                //         V v = (V)(T)e.Current;
                //         /* loop body */
                //     }
                // }
                // finally {
                //     /* dispose of e */
                // }
                BoundStatement tryFinally = new BoundTryStatement(forEachSyntax,
                                                                  tryBlock: new BoundBlock(forEachSyntax,
                                                                                           locals: ImmutableArray <LocalSymbol> .Empty,
                                                                                           localFunctions: ImmutableArray <LocalFunctionSymbol> .Empty,
                                                                                           statements: ImmutableArray.Create <BoundStatement>(whileLoop)),
                                                                  catchBlocks: ImmutableArray <BoundCatchBlock> .Empty,
                                                                  finallyBlockOpt: finallyBlockOpt);

                // E e = ((C)(x)).GetEnumerator();
                // try {
                //     /* as above */
                result = new BoundBlock(
                    syntax: forEachSyntax,
                    locals: ImmutableArray.Create(enumeratorVar),
                    localFunctions: ImmutableArray <LocalFunctionSymbol> .Empty,
                    statements: ImmutableArray.Create <BoundStatement>(enumeratorVarDecl, tryFinally));
            }
            else
            {
                // E e = ((C)(x)).GetEnumerator();
                // while (e.MoveNext()) {
                //     V v = (V)(T)e.Current;
                //     /* loop body */
                // }
                result = new BoundBlock(
                    syntax: forEachSyntax,
                    locals: ImmutableArray.Create(enumeratorVar),
                    localFunctions: ImmutableArray <LocalFunctionSymbol> .Empty,
                    statements: ImmutableArray.Create <BoundStatement>(enumeratorVarDecl, whileLoop));
            }

            AddForEachKeywordSequencePoint(forEachSyntax, ref result);

            return(result);
        }
        /// <summary>
        /// Lower a foreach loop that will enumerate a collection using an enumerator.
        /// 
        /// E e = ((C)(x)).GetEnumerator()
        /// try {
        ///     while (e.MoveNext()) {
        ///         V v = (V)(T)e.Current;
        ///         // body
        ///     }
        /// }
        /// finally {
        ///     // clean up e
        /// }
        /// </summary>
        private BoundStatement RewriteEnumeratorForEachStatement(BoundForEachStatement node)
        {
            ForEachStatementSyntax forEachSyntax = (ForEachStatementSyntax)node.Syntax;

            ForEachEnumeratorInfo enumeratorInfo = node.EnumeratorInfoOpt;
            Debug.Assert(enumeratorInfo != null);

            BoundExpression collectionExpression = GetUnconvertedCollectionExpression(node);
            BoundExpression rewrittenExpression = (BoundExpression)Visit(collectionExpression);
            BoundStatement rewrittenBody = (BoundStatement)Visit(node.Body);

            TypeSymbol enumeratorType = enumeratorInfo.GetEnumeratorMethod.ReturnType;
            TypeSymbol elementType = enumeratorInfo.ElementType;

            // E e
            LocalSymbol enumeratorVar = new TempLocalSymbol(enumeratorType, RefKind.None, this.containingMethod);

            // Reference to e.
            BoundLocal boundEnumeratorVar = MakeBoundLocal(forEachSyntax, enumeratorVar, enumeratorType);

            // ((C)(x)).GetEnumerator() or (x).GetEnumerator();
            BoundExpression enumeratorVarInitValue = SynthesizeCall(forEachSyntax, rewrittenExpression, enumeratorInfo.GetEnumeratorMethod, enumeratorInfo.CollectionConversion, enumeratorInfo.CollectionType);

            // E e = ((C)(x)).GetEnumerator();
            BoundStatement enumeratorVarDecl = MakeLocalDeclaration(forEachSyntax, enumeratorVar, enumeratorVarInitValue);

            AddForEachExpressionSequencePoint(forEachSyntax, ref enumeratorVarDecl);

            // V v
            LocalSymbol iterationVar = node.IterationVariable;

            //(V)(T)e.Current
            BoundExpression iterationVarAssignValue = SynthesizeConversion(
                syntax: forEachSyntax,
                operand: SynthesizeConversion(
                    syntax: forEachSyntax,
                    operand: BoundCall.Synthesized(
                        syntax: forEachSyntax,
                        receiverOpt: boundEnumeratorVar,
                        method: enumeratorInfo.CurrentPropertyGetter),
                    conversion: enumeratorInfo.CurrentConversion,
                    type: elementType),
                conversion: node.ElementConversion,
                type: iterationVar.Type);

            // V v = (V)(T)e.Current;
            BoundStatement iterationVarDecl = MakeLocalDeclaration(forEachSyntax, iterationVar, iterationVarAssignValue);

            AddForEachIterationVariableSequencePoint(forEachSyntax, ref iterationVarDecl);

            // while (e.MoveNext()) {
            //     V v = (V)(T)e.Current;
            //     /* node.Body */
            // }
            BoundStatement whileLoop = RewriteWhileStatement(
                syntax: forEachSyntax,
                rewrittenCondition: BoundCall.Synthesized(
                    syntax: forEachSyntax,
                    receiverOpt: boundEnumeratorVar,
                    method: enumeratorInfo.MoveNextMethod),
                conditionSequencePointSpan: forEachSyntax.InKeyword.Span,
                rewrittenBody: new BoundBlock(rewrittenBody.Syntax,
                    statements: ReadOnlyArray<BoundStatement>.CreateFrom(iterationVarDecl, rewrittenBody),
                    localsOpt: ReadOnlyArray<LocalSymbol>.CreateFrom(iterationVar)),
                breakLabel: node.BreakLabel,
                continueLabel: node.ContinueLabel,
                hasErrors: false);

            BoundStatement result;

            if (enumeratorInfo.DisposeMethodOpt != null)
            {
                BoundBlock finallyBlockOpt;
                var idisposableTypeSymbol = enumeratorInfo.DisposeMethodOpt.ContainingType;
                var conversions = new TypeConversions(this.containingMethod.ContainingAssembly.CorLibrary);

                if (conversions.ClassifyImplicitConversion(enumeratorType, idisposableTypeSymbol).IsImplicit)
                {
                    Debug.Assert(enumeratorInfo.DisposeMethodOpt != null);

                    Conversion receiverConversion = enumeratorType.IsStructType() ?
                        Conversion.Boxing :
                        Conversion.ImplicitReference;

                    // ((IDisposable)e).Dispose(); or e.Dispose();
                    BoundStatement disposeCall = new BoundExpressionStatement(forEachSyntax,
                        expression: SynthesizeCall(forEachSyntax, boundEnumeratorVar, enumeratorInfo.DisposeMethodOpt, receiverConversion, idisposableTypeSymbol));

                    BoundStatement disposeStmt;
                    if (enumeratorType.IsValueType)
                    {
                        // No way for the struct to be nullable and disposable.
                        Debug.Assert(((TypeSymbol)enumeratorType.OriginalDefinition).SpecialType != SpecialType.System_Nullable_T);

                        // For non-nullable structs, no null check is required.
                        disposeStmt = disposeCall;
                    }
                    else
                    {
                        // NB: cast to object missing from spec.  Needed to ignore user-defined operators and box type parameters.
                        // if ((object)e != null) ((IDisposable)e).Dispose(); 
                        disposeStmt = RewriteIfStatement(
                            syntax: forEachSyntax,
                            rewrittenCondition: new BoundBinaryOperator(forEachSyntax,
                                operatorKind: BinaryOperatorKind.NotEqual,
                                left: SynthesizeConversion(
                                    syntax: forEachSyntax,
                                    operand: boundEnumeratorVar,
                                    conversion: enumeratorInfo.EnumeratorConversion,
                                    type: this.compilation.GetSpecialType(SpecialType.System_Object)),
                                right: new BoundLiteral(forEachSyntax,
                                    constantValueOpt: ConstantValue.Null,
                                    type: null),
                                constantValueOpt: null,
                                methodOpt: null,
                                resultKind: LookupResultKind.Viable,
                                type: this.compilation.GetSpecialType(SpecialType.System_Boolean)),
                            rewrittenConsequence: disposeCall,
                            rewrittenAlternativeOpt: null,
                            hasErrors: false);
                    }

                    finallyBlockOpt = new BoundBlock(forEachSyntax,
                        localsOpt: ReadOnlyArray<LocalSymbol>.Null,
                        statements: ReadOnlyArray<BoundStatement>.CreateFrom(disposeStmt));
                }
                else
                {
                    Debug.Assert(!enumeratorType.IsSealed);

                    // IDisposable d
                    LocalSymbol disposableVar = new TempLocalSymbol(idisposableTypeSymbol, RefKind.None, this.containingMethod);

                    // Reference to d.
                    BoundLocal boundDisposableVar = MakeBoundLocal(forEachSyntax, disposableVar, idisposableTypeSymbol);

                    BoundTypeExpression boundIDisposableTypeExpr = new BoundTypeExpression(forEachSyntax,
                        type: idisposableTypeSymbol);

                    // e as IDisposable
                    BoundExpression disposableVarInitValue = new BoundAsOperator(forEachSyntax,
                        operand: boundEnumeratorVar,
                        targetType: boundIDisposableTypeExpr,
                        conversion: Conversion.ExplicitReference, // Explicit so the emitter won't optimize it away.
                        type: idisposableTypeSymbol);

                    // IDisposable d = e as IDisposable;
                    BoundStatement disposableVarDecl = MakeLocalDeclaration(forEachSyntax, disposableVar, disposableVarInitValue);

                    // if (d != null) d.Dispose();
                    BoundStatement ifStmt = RewriteIfStatement(
                        syntax: forEachSyntax,
                        rewrittenCondition: new BoundBinaryOperator(forEachSyntax,
                            operatorKind: BinaryOperatorKind.NotEqual, // reference equality
                            left: boundDisposableVar,
                            right: new BoundLiteral(forEachSyntax,
                                constantValueOpt: ConstantValue.Null,
                                type: null),
                            constantValueOpt: null,
                            methodOpt: null,
                            resultKind: LookupResultKind.Viable,
                            type: this.compilation.GetSpecialType(SpecialType.System_Boolean)),
                        rewrittenConsequence: new BoundExpressionStatement(forEachSyntax,
                            expression: BoundCall.Synthesized(
                                syntax: forEachSyntax,
                                receiverOpt: boundDisposableVar,
                                method: enumeratorInfo.DisposeMethodOpt)),
                        rewrittenAlternativeOpt: null,
                        hasErrors: false);

                    // IDisposable d = e as IDisposable;
                    // if (d != null) d.Dispose();
                    finallyBlockOpt = new BoundBlock(forEachSyntax,
                        localsOpt: ReadOnlyArray<LocalSymbol>.CreateFrom(disposableVar),
                        statements: ReadOnlyArray<BoundStatement>.CreateFrom(disposableVarDecl, ifStmt));
                }

                // try {
                //     while (e.MoveNext()) {
                //         V v = (V)(T)e.Current;
                //         /* loop body */
                //     }
                // }
                // finally {
                //     /* dispose of e */
                // }
                BoundStatement tryFinally = new BoundTryStatement(forEachSyntax,
                    tryBlock: new BoundBlock(forEachSyntax,
                        localsOpt: ReadOnlyArray<LocalSymbol>.Empty,
                        statements: ReadOnlyArray<BoundStatement>.CreateFrom(whileLoop)),
                    catchBlocks: ReadOnlyArray<BoundCatchBlock>.Empty,
                    finallyBlockOpt: finallyBlockOpt);

                // E e = ((C)(x)).GetEnumerator();
                // try {
                //     /* as above */
                result = new BoundBlock(
                    syntax: forEachSyntax,
                    localsOpt: ReadOnlyArray<LocalSymbol>.CreateFrom(enumeratorVar),
                    statements: ReadOnlyArray<BoundStatement>.CreateFrom(enumeratorVarDecl, tryFinally));
            }
            else
            {
                // E e = ((C)(x)).GetEnumerator();
                // while (e.MoveNext()) {
                //     V v = (V)(T)e.Current;
                //     /* loop body */
                // }
                result = new BoundBlock(
                    syntax: forEachSyntax,
                    localsOpt: ReadOnlyArray<LocalSymbol>.CreateFrom(enumeratorVar),
                    statements: ReadOnlyArray<BoundStatement>.CreateFrom(enumeratorVarDecl, whileLoop));
            }

            AddForEachKeywordSequencePoint(forEachSyntax, ref result);

            return result;
        }
示例#13
0
 public override object VisitAsOperator(BoundAsOperator node, object arg)
 {
     VisitExpression(node.Operand);
     return(null);
 }