/// <summary>
        /// <![CDATA[
        /// fixed(int* ptr = arr){ ... }    == becomes ===>
        ///
        /// pinned int[] pinnedTemp = arr;         // pinning managed ref
        /// int* ptr = pinnedTemp != null && pinnedTemp.Length != 0
        ///                (int*)&pinnedTemp[0]:   // unsafe cast to unmanaged ptr
        ///                0;
        ///   . . .
        ///   ]]>
        /// </summary>
        private BoundStatement InitializeFixedStatementArrayLocal(
            BoundLocalDeclaration localDecl,
            LocalSymbol localSymbol,
            BoundFixedLocalCollectionInitializer fixedInitializer,
            SyntheticBoundNodeFactory factory,
            out LocalSymbol pinnedTemp)
        {
            TypeSymbol      localType       = localSymbol.Type.TypeSymbol;
            BoundExpression initializerExpr = VisitExpression(fixedInitializer.Expression);
            TypeSymbol      initializerType = initializerExpr.Type;

            pinnedTemp = factory.SynthesizedLocal(initializerType, isPinned: true);
            ArrayTypeSymbol           arrayType        = (ArrayTypeSymbol)pinnedTemp.Type.TypeSymbol;
            TypeSymbolWithAnnotations arrayElementType = arrayType.ElementType;

            // NOTE: we pin the array, not the pointer.
            Debug.Assert(pinnedTemp.IsPinned);
            Debug.Assert(!localSymbol.IsPinned);

            //(pinnedTemp = array)
            BoundExpression arrayTempInit = factory.AssignmentExpression(factory.Local(pinnedTemp), initializerExpr);

            //(pinnedTemp = array) != null
            BoundExpression notNullCheck = MakeNullCheck(factory.Syntax, arrayTempInit, BinaryOperatorKind.NotEqual);

            BoundExpression lengthCall;

            if (arrayType.IsSZArray)
            {
                lengthCall = factory.ArrayLength(factory.Local(pinnedTemp));
            }
            else
            {
                MethodSymbol lengthMethod;
                if (TryGetWellKnownTypeMember(fixedInitializer.Syntax, WellKnownMember.System_Array__get_Length, out lengthMethod))
                {
                    lengthCall = factory.Call(factory.Local(pinnedTemp), lengthMethod);
                }
                else
                {
                    lengthCall = new BoundBadExpression(fixedInitializer.Syntax, LookupResultKind.NotInvocable, ImmutableArray <Symbol> .Empty, ImmutableArray.Create <BoundExpression>(factory.Local(pinnedTemp)), ErrorTypeSymbol.UnknownResultType);
                }
            }

            // NOTE: dev10 comment says ">", but code actually checks "!="
            //temp.Length != 0
            BoundExpression lengthCheck = factory.Binary(BinaryOperatorKind.Int32NotEqual, factory.SpecialType(SpecialType.System_Boolean), lengthCall, factory.Literal(0));

            //((temp = array) != null && temp.Length != 0)
            BoundExpression condition = factory.Binary(BinaryOperatorKind.LogicalBoolAnd, factory.SpecialType(SpecialType.System_Boolean), notNullCheck, lengthCheck);

            //temp[0]
            BoundExpression firstElement = factory.ArrayAccessFirstElement(factory.Local(pinnedTemp));

            // NOTE: this is a fixed statement address-of in that it's the initial value of the pointer.
            //&temp[0]
            BoundExpression firstElementAddress          = new BoundAddressOfOperator(factory.Syntax, firstElement, type: new PointerTypeSymbol(arrayElementType));
            BoundExpression convertedFirstElementAddress = factory.Convert(
                localType,
                firstElementAddress,
                fixedInitializer.ElementPointerTypeConversion);

            //loc = &temp[0]
            BoundExpression consequenceAssignment = factory.AssignmentExpression(factory.Local(localSymbol), convertedFirstElementAddress);

            //loc = null
            BoundExpression alternativeAssignment = factory.AssignmentExpression(factory.Local(localSymbol), factory.Null(localType));

            //(((temp = array) != null && temp.Length != 0) ? loc = &temp[0] : loc = null)
            BoundStatement localInit = factory.ExpressionStatement(
                new BoundConditionalOperator(factory.Syntax, false, condition, consequenceAssignment, alternativeAssignment, ConstantValue.NotAvailable, localType));

            return(InstrumentLocalDeclarationIfNecessary(localDecl, localSymbol, localInit));
        }
        /// <summary>
        /// <![CDATA[
        /// fixed(int* ptr = &v){ ... }    == becomes ===>
        ///
        /// pinned ref int pinnedTemp = ref v;    // pinning managed ref
        /// int* ptr = (int*)&pinnedTemp;         // unsafe cast to unmanaged ptr
        ///   . . .
        /// ]]>
        /// </summary>
        private BoundStatement InitializeFixedStatementGetPinnable(
            BoundLocalDeclaration localDecl,
            LocalSymbol localSymbol,
            BoundFixedLocalCollectionInitializer fixedInitializer,
            SyntheticBoundNodeFactory factory,
            out LocalSymbol pinnedTemp)
        {
            TypeSymbol      localType       = localSymbol.Type.TypeSymbol;
            BoundExpression initializerExpr = VisitExpression(fixedInitializer.Expression);

            var initializerType   = initializerExpr.Type;
            var initializerSyntax = initializerExpr.Syntax;
            var getPinnableMethod = fixedInitializer.GetPinnableOpt;

            // intervening parens may have been skipped by the binder; find the declarator
            VariableDeclarationSyntax declarator = fixedInitializer.Syntax.FirstAncestorOrSelf <VariableDeclarationSyntax>();

            Debug.Assert(declarator != null);

            // pinned ref int pinnedTemp
            pinnedTemp = factory.SynthesizedLocal(
                getPinnableMethod.ReturnType.TypeSymbol,
                syntax: declarator,
                isPinned: true,
                //NOTE: different from the array and string cases
                //      RefReadOnly to allow referring to readonly variables. (technically we only "read" through the temp anyways)
                refKind: RefKind.RefReadOnly,
                kind: SynthesizedLocalKind.FixedReference);

            BoundExpression callReceiver;
            int             currentConditionalAccessID = 0;

            bool needNullCheck = !initializerType.IsValueType;

            if (needNullCheck)
            {
                currentConditionalAccessID = _currentConditionalAccessID++;
                callReceiver = new BoundConditionalReceiver(
                    initializerSyntax,
                    currentConditionalAccessID,
                    initializerType);
            }
            else
            {
                callReceiver = initializerExpr;
            }

            // .GetPinnable()
            var getPinnableCall = getPinnableMethod.IsStatic ?
                                  factory.Call(null, getPinnableMethod, callReceiver) :
                                  factory.Call(callReceiver, getPinnableMethod);

            // temp =ref .GetPinnable()
            var tempAssignment = factory.AssignmentExpression(
                factory.Local(pinnedTemp),
                getPinnableCall,
                isRef: true);

            // &pinnedTemp
            var addr = new BoundAddressOfOperator(
                factory.Syntax,
                factory.Local(pinnedTemp),
                type: fixedInitializer.ElementPointerType);

            // (int*)&pinnedTemp
            var pointerValue = factory.Convert(
                localType,
                addr,
                fixedInitializer.ElementPointerTypeConversion);

            // {pinnedTemp =ref .GetPinnable(), (int*)&pinnedTemp}
            BoundExpression pinAndGetPtr = factory.Sequence(
                locals: ImmutableArray <LocalSymbol> .Empty,
                sideEffects: ImmutableArray.Create <BoundExpression>(tempAssignment),
                result: pointerValue);

            if (needNullCheck)
            {
                // initializer?.{temp =ref .GetPinnable(), (int*)&pinnedTemp} ?? default;
                pinAndGetPtr = new BoundLoweredConditionalAccess(
                    initializerSyntax,
                    initializerExpr,
                    hasValueMethodOpt: null,
                    whenNotNull: pinAndGetPtr,
                    whenNullOpt: null, // just return default(T*)
                    currentConditionalAccessID,
                    localType);
            }

            // ptr = initializer?.{temp =ref .GetPinnable(), (int*)&pinnedTemp} ?? default;
            BoundStatement localInit = InstrumentLocalDeclarationIfNecessary(localDecl, localSymbol, factory.Assignment(factory.Local(localSymbol), pinAndGetPtr));

            return(localInit);
        }
        /// <summary>
        /// fixed(char* ptr = stringVar){ ... }    == becomes ===>
        ///
        /// pinned string pinnedTemp = stringVar;    // pinning managed ref
        /// char* ptr = (char*)pinnedTemp;           // unsafe cast to unmanaged ptr
        /// if (pinnedTemp != null) ptr += OffsetToStringData();
        ///   . . .
        /// </summary>
        private BoundStatement InitializeFixedStatementStringLocal(
            BoundLocalDeclaration localDecl,
            LocalSymbol localSymbol,
            BoundFixedLocalCollectionInitializer fixedInitializer,
            SyntheticBoundNodeFactory factory,
            out LocalSymbol pinnedTemp)
        {
            TypeSymbol      localType       = localSymbol.Type.TypeSymbol;
            BoundExpression initializerExpr = VisitExpression(fixedInitializer.Expression);
            TypeSymbol      initializerType = initializerExpr.Type;

            // intervening parens may have been skipped by the binder; find the declarator
            VariableDeclarationSyntax declarator = fixedInitializer.Syntax.FirstAncestorOrSelf <VariableDeclarationSyntax>();

            Debug.Assert(declarator != null);

            pinnedTemp = factory.SynthesizedLocal(
                initializerType,
                syntax: declarator,
                isPinned: true,
                kind: SynthesizedLocalKind.FixedReference);

            // NOTE: we pin the string, not the pointer.
            Debug.Assert(pinnedTemp.IsPinned);
            Debug.Assert(!localSymbol.IsPinned);

            BoundStatement stringTempInit = factory.Assignment(factory.Local(pinnedTemp), initializerExpr);

            // (char*)pinnedTemp;
            var addr = factory.Convert(
                fixedInitializer.ElementPointerType,
                factory.Local(pinnedTemp),
                Conversion.PinnedObjectToPointer);

            var convertedStringTemp = factory.Convert(
                localType,
                addr,
                fixedInitializer.ElementPointerTypeConversion);

            BoundStatement localInit = InstrumentLocalDeclarationIfNecessary(localDecl, localSymbol,
                                                                             factory.Assignment(factory.Local(localSymbol), convertedStringTemp));

            BoundExpression notNullCheck = MakeNullCheck(factory.Syntax, factory.Local(localSymbol), BinaryOperatorKind.NotEqual);
            BoundExpression helperCall;

            MethodSymbol offsetMethod;

            if (TryGetWellKnownTypeMember(fixedInitializer.Syntax, WellKnownMember.System_Runtime_CompilerServices_RuntimeHelpers__get_OffsetToStringData, out offsetMethod))
            {
                helperCall = factory.Call(receiver: null, method: offsetMethod);
            }
            else
            {
                helperCall = new BoundBadExpression(fixedInitializer.Syntax, LookupResultKind.NotInvocable, ImmutableArray <Symbol> .Empty, ImmutableArray <BoundExpression> .Empty, ErrorTypeSymbol.UnknownResultType);
            }

            BoundExpression addition       = factory.Binary(BinaryOperatorKind.PointerAndInt32Addition, localType, factory.Local(localSymbol), helperCall);
            BoundStatement  conditionalAdd = factory.If(notNullCheck, factory.Assignment(factory.Local(localSymbol), addition));

            return(factory.Block(stringTempInit, localInit, conditionalAdd));
        }
 public override BoundNode VisitFixedLocalCollectionInitializer(BoundFixedLocalCollectionInitializer node)
 {
     throw ExceptionUtilities.Unreachable; //Should be handled by VisitFixedStatement
 }