Example #1
0
        private BoundNode RewriteMethodGroupConversion(BoundConversion conversion)
        {
            // in a method group conversion, we may need to rewrite the selected method
            BoundMethodGroup operand             = (BoundMethodGroup)conversion.Operand;
            BoundExpression  originalReceiverOpt = operand.ReceiverOpt;
            BoundExpression  receiverOpt;

            if (originalReceiverOpt == null)
            {
                receiverOpt = null;
            }
            else if (!conversion.IsExtensionMethod && conversion.SymbolOpt.IsStatic)
            {
                receiverOpt = new BoundTypeExpression(originalReceiverOpt.Syntax, null, VisitType(originalReceiverOpt.Type));
            }
            else
            {
                receiverOpt = (BoundExpression)Visit(originalReceiverOpt);
            }

            TypeSymbol type = this.VisitType(conversion.Type);

            MethodSymbol method = conversion.SymbolOpt;

            //  if the original receiver was a base access and is was rewritten,
            //  change the method to point to the wrapper method
            if (BaseReferenceInReceiverWasRewritten(originalReceiverOpt, receiverOpt) && method.IsMetadataVirtual())
            {
                method = GetMethodWrapperForBaseNonVirtualCall(method, conversion.Syntax);
            }

            method  = VisitMethodSymbol(method);
            operand = operand.Update(
                TypeMap.SubstituteTypesWithoutModifiers(operand.TypeArgumentsOpt),
                method.Name,
                operand.Methods,
                operand.LookupSymbolOpt,
                operand.LookupError,
                operand.Flags,
                receiverOpt,
                operand.ResultKind);

            var conversionInfo = conversion.Conversion;

            if (conversionInfo.Method != (object)method)
            {
                conversionInfo = conversionInfo.SetConversionMethod(method);
            }

            return(conversion.Update(
                       operand,
                       conversionInfo,
                       isBaseConversion: conversion.IsBaseConversion,
                       @checked: conversion.Checked,
                       explicitCastInCode: conversion.ExplicitCastInCode,
                       constantValueOpt: conversion.ConstantValueOpt,
                       type: type));
        }
        private BoundNode RewriteMethodGroupConversion(BoundConversion conversion)
        {
            // in a method group conversion, we may need to rewrite the selected method
            BoundMethodGroup operand = (BoundMethodGroup)conversion.Operand;
            BoundExpression originalReceiverOpt = operand.ReceiverOpt;
            BoundExpression receiverOpt;

            if (originalReceiverOpt == null)
            {
                receiverOpt = null;
            }
            else if (!conversion.IsExtensionMethod && conversion.SymbolOpt.IsStatic)
            {
                receiverOpt = new BoundTypeExpression(originalReceiverOpt.Syntax, null, VisitType(originalReceiverOpt.Type));
            }
            else
            {
                receiverOpt = (BoundExpression)Visit(originalReceiverOpt);
            }

            TypeSymbol type = this.VisitType(conversion.Type);

            MethodSymbol method = conversion.SymbolOpt;

            //  if the original receiver was a base access and is was rewritten, 
            //  change the method to point to the wrapper method
            if (BaseReferenceInReceiverWasRewritten(originalReceiverOpt, receiverOpt) && method.IsMetadataVirtual())
            {
                method = GetMethodWrapperForBaseNonVirtualCall(method, conversion.Syntax);
            }

            method = VisitMethodSymbol(method);
            operand = operand.Update(
                TypeMap.SubstituteTypesWithoutModifiers(operand.TypeArgumentsOpt),
                method.Name,
                operand.Methods,
                operand.LookupSymbolOpt,
                operand.LookupError,
                operand.Flags,
                receiverOpt,
                operand.ResultKind);

            var conversionInfo = conversion.Conversion;
            if (conversionInfo.Method != (object)method)
            {
                conversionInfo = conversionInfo.SetConversionMethod(method);
            }

            return conversion.Update(
                operand,
                conversionInfo,
                isBaseConversion: conversion.IsBaseConversion,
                @checked: conversion.Checked,
                explicitCastInCode: conversion.ExplicitCastInCode,
                constantValueOpt: conversion.ConstantValueOpt,
                type: type);
        }
Example #3
0
        /// <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);
        }
        /// <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;
        }
Example #5
0
 internal void Parse(BoundTypeExpression boundTypeExpression)
 {
     base.Parse(boundTypeExpression);
 }
Example #6
0
 public virtual void VisitTypeExpression(BoundTypeExpression node) => DefaultVisit(node);
Example #7
0
 public override object VisitTypeExpression(BoundTypeExpression node, object arg)
 {
     return(null);
 }