/// <summary>
        /// Rewrite an assignment operator.
        /// 
        /// Possible cases:
        ///   (1) Neither the lvalue nor rvalue contain an await expression.
        ///   (2) Only the lvalue contains an await expression.
        ///   (3) The rvalue contains an await expression, and the lvalue is one of:
        ///     (a) an await-containing expression,
        ///     (b) an array access,
        ///     (c) a field access, or
        ///     (d) a local
        ///
        /// </summary>
        public override BoundNode VisitAssignmentOperator(BoundAssignmentOperator node)
        {
            BoundExpression leftNode = (BoundExpression)this.Visit(node.Left);
            BoundExpression rightNode = (BoundExpression)this.Visit(node.Right);
            TypeSymbol type = this.VisitType(node.Type);

            if (!RequiresSpill(leftNode, rightNode))
            {
                // Case (1) - no await expression:
                return node.Update(leftNode, rightNode, node.RefKind, type);
            }

            if (!RequiresSpill(rightNode))
            {
                // Case (2) - only lvalue contains await
                //     Spill(l_sideEffects, lvalue) = rvalue
                //   is rewritten as:
                //     Spill(l_sideEffects, lvalue = rvalue)

                var spill = (BoundSpillSequence) leftNode;
                var newAssignment = node.Update(spill.Value, rightNode, node.RefKind, type);
                return RewriteSpillSequence(spill, newAssignment);
            }

            // Case (3) -
            return SpillAssignmentOperator(node, leftNode, (BoundSpillSequence) rightNode);
        }
 private BoundNode SpillAssignmentOperator(BoundAssignmentOperator node, BoundExpression left, BoundSpillSequence right)
 {
     var spillBuilder = new SpillBuilder();
     var spilledLeftNode = SpillLValue(left, spillBuilder);
     var innerSpill = node.Update(spilledLeftNode, right.Value, node.RefKind, node.Type);
     spillBuilder.AddSpill(right);
     return spillBuilder.BuildSequenceAndFree(F, innerSpill);
 }
        private BoundNode SpillAssignmentOperator(BoundAssignmentOperator node, BoundExpression left, BoundSpillSequence right)
        {
            var spillBuilder    = new SpillBuilder();
            var spilledLeftNode = SpillLValue(left, spillBuilder);
            var innerSpill      = node.Update(spilledLeftNode, right.Value, node.RefKind, node.Type);

            spillBuilder.AddSpill(right);
            return(spillBuilder.BuildSequenceAndFree(F, innerSpill));
        }
 private bool CheckForAssignmentToSelf(BoundAssignmentOperator node)
 {
     if (!node.HasAnyErrors && IsSameLocalOrField(node.Left, node.Right))
     {
         Error(ErrorCode.WRN_AssignmentToSelf, node);
         return(true);
     }
     return(false);
 }
        public override BoundNode VisitAssignmentOperator(BoundAssignmentOperator node)
        {
            if (!CheckForAssignmentToSelf(node) && _inExpressionLambda && node.Left.Kind != BoundKind.ObjectInitializerMember && node.Left.Kind != BoundKind.DynamicObjectInitializerMember)
            {
                Error(ErrorCode.ERR_ExpressionTreeContainsAssignment, node);
            }

            return(base.VisitAssignmentOperator(node));
        }
        public override BoundNode VisitAssignmentOperator(BoundAssignmentOperator node)
        {
            if (node.Left.Kind == BoundKind.Local && node.RefKind != RefKind.None)
            {
                var localSymbol = ((BoundLocal)node.Left).LocalSymbol;
                Debug.Assert(localSymbol.RefKind != RefKind.None);
                refLocalInitializers.Add(localSymbol, node.Right);
            }

            return(base.VisitAssignmentOperator(node));
        }
Exemple #7
0
        private BoundExpression HoistRefInitialization(SynthesizedLocal local, BoundAssignmentOperator node)
        {
            Debug.Assert(local.SynthesizedKind == SynthesizedLocalKind.Spill);
            Debug.Assert(local.SyntaxOpt != null);
            Debug.Assert(this.OriginalMethod.IsAsync);

            var right = (BoundExpression)Visit(node.Right);

            var sideEffects = ArrayBuilder <BoundExpression> .GetInstance();

            bool needsSacrificialEvaluation = false;
            var  hoistedFields = ArrayBuilder <StateMachineFieldSymbol> .GetInstance();

            SyntaxNode awaitSyntaxOpt;
            int        syntaxOffset;

            if (F.Compilation.Options.OptimizationLevel == OptimizationLevel.Debug)
            {
                awaitSyntaxOpt = local.GetDeclaratorSyntax();
                Debug.Assert(awaitSyntaxOpt.IsKind(SyntaxKind.AwaitExpression) || awaitSyntaxOpt.IsKind(SyntaxKind.SwitchExpression));
                syntaxOffset = OriginalMethod.CalculateLocalSyntaxOffset(LambdaUtilities.GetDeclaratorPosition(awaitSyntaxOpt), awaitSyntaxOpt.SyntaxTree);
            }
            else
            {
                // These are only used to calculate debug id for ref-spilled variables,
                // no need to do so in release build.
                awaitSyntaxOpt = null;
                syntaxOffset   = -1;
            }

            var replacement = HoistExpression(right, awaitSyntaxOpt, syntaxOffset, local.RefKind, sideEffects, hoistedFields, ref needsSacrificialEvaluation);

            proxies.Add(local, new CapturedToExpressionSymbolReplacement(replacement, hoistedFields.ToImmutableAndFree(), isReusable: true));

            if (needsSacrificialEvaluation)
            {
                var type            = TypeMap.SubstituteType(local.Type).Type;
                var sacrificialTemp = F.SynthesizedLocal(type, refKind: RefKind.Ref);
                Debug.Assert(TypeSymbol.Equals(type, replacement.Type, TypeCompareKind.ConsiderEverything2));
                return(F.Sequence(ImmutableArray.Create(sacrificialTemp), sideEffects.ToImmutableAndFree(), F.AssignmentExpression(F.Local(sacrificialTemp), replacement, isRef: true)));
            }

            if (sideEffects.Count == 0)
            {
                sideEffects.Free();
                return(null);
            }

            var last = sideEffects.Last();

            sideEffects.RemoveLast();
            return(F.Sequence(ImmutableArray <LocalSymbol> .Empty, sideEffects.ToImmutableAndFree(), last));
        }
Exemple #8
0
        /// <summary>
        /// Figures out how to assign from sourceType into receivingVariable and bundles the information (leaving holes for the actual source and receiver) into an AssignmentInfo.
        /// </summary>
        private BoundDeconstructionAssignmentStep MakeDeconstructionAssignmentStep(
            BoundExpression receivingVariable, TypeSymbol sourceType, BoundDeconstructValuePlaceholder inputPlaceholder,
            CSharpSyntaxNode node, DiagnosticBag diagnostics)
        {
            var outputPlaceholder = new BoundDeconstructValuePlaceholder(receivingVariable.Syntax, receivingVariable.Type)
            {
                WasCompilerGenerated = true
            };

            // each assignment has a placeholder for a receiver and another for the source
            BoundAssignmentOperator op = BindAssignment(receivingVariable.Syntax, outputPlaceholder, inputPlaceholder, diagnostics);

            return(new BoundDeconstructionAssignmentStep(node, op, inputPlaceholder, outputPlaceholder));
        }
Exemple #9
0
        private void InitVariableProxy(CSharpSyntaxNode syntax, Symbol symbol, LocalSymbol framePointer, ArrayBuilder <BoundExpression> prologue)
        {
            CapturedSymbolReplacement proxy;

            if (proxies.TryGetValue(symbol, out proxy))
            {
                BoundExpression value;
                switch (symbol.Kind)
                {
                case SymbolKind.Parameter:
                {
                    var             parameter = (ParameterSymbol)symbol;
                    ParameterSymbol parameterToUse;
                    if (!parameterMap.TryGetValue(parameter, out parameterToUse))
                    {
                        parameterToUse = parameter;
                    }
                    value = new BoundParameter(syntax, parameterToUse);
                }
                break;

                case SymbolKind.Local:
                    if (!this.assignLocals)
                    {
                        return;
                    }
                    else
                    {
                        var         local = (LocalSymbol)symbol;
                        LocalSymbol localToUse;
                        if (!localMap.TryGetValue(local, out localToUse))
                        {
                            localToUse = local;
                        }
                        value = new BoundLocal(syntax, localToUse, null, localToUse.Type);
                    }
                    break;

                default:
                    throw ExceptionUtilities.UnexpectedValue(symbol.Kind);
                }

                var left          = proxy.Replacement(syntax, frameType1 => new BoundLocal(syntax, framePointer, null, framePointer.Type));
                var assignToProxy = new BoundAssignmentOperator(syntax, left, value, value.Type);
                prologue.Add(assignToProxy);
            }
        }
Exemple #10
0
        public override BoundNode VisitAssignmentOperator(BoundAssignmentOperator node)
        {
            base.VisitAssignmentOperator(node);
            var rvalue = MakeValueHolder(node.Right);

            switch (node.Left.Kind)
            {
            case BoundKind.Local:
            {
                var left = (BoundLocal)node.Left;
                this.State.variables[left.LocalSymbol] = rvalue.value;
            }
            break;

            case BoundKind.DeclarationExpression:
            {
                var left = (BoundDeclarationExpression)node.Left;
                this.State.variables[left.LocalSymbol] = rvalue.value;
            }
            break;

            case BoundKind.Parameter:
            {
                var left = (BoundParameter)node.Left;
                this.State.variables[left.ParameterSymbol] = rvalue.value;
            }
            break;

            case BoundKind.FieldAccess:
            case BoundKind.PropertyAccess:
            {
                foreach (var e in rvalue.value.creations)
                {
                    this.State.possiblyUndisposedCreations.Remove(e);
                }
            }
            break;

            default:
                break;
            }

            return(rvalue);
        }
Exemple #11
0
        /// <summary>
        /// Takes an expression and returns the bound local expression "temp"
        /// and the bound assignment expression "temp = expr".
        /// </summary>
        public BoundLocal StoreToTemp(BoundExpression argument, out BoundAssignmentOperator store, RefKind refKind = RefKind.None, TempKind tempKind = TempKind.None)
        {
            MethodSymbol containingMethod = this.CurrentMethod;
            var          syntax           = argument.Syntax;
            var          type             = argument.Type;
            var          local            = new BoundLocal(
                syntax,
                new SynthesizedLocal(containingMethod, type, syntax: (tempKind == TempKind.None) ? null : syntax, refKind: refKind, tempKind: tempKind),
                null,
                type);

            store = new BoundAssignmentOperator(
                syntax,
                local,
                argument,
                refKind,
                type);
            return(local);
        }
Exemple #12
0
        /// <summary>
        /// Takes an expression and returns the bound local expression "temp" 
        /// and the bound assignment expression "temp = expr".
        /// </summary>
        /// <param name="argument"></param>
        /// <param name="refKind"></param>
        /// <param name="containingMethod"></param>
        /// <returns></returns>
        public static Pair<BoundAssignmentOperator, BoundLocal> StoreToTemp(BoundExpression argument, RefKind refKind, MethodSymbol containingMethod)
        {
            var syntax = argument.Syntax;
            var type = argument.Type;
            var local = new BoundLocal(
                    syntax,
                    // TODO: the following temp local symbol should have its ContainingSymbol set.
                    new TempLocalSymbol(type, refKind, containingMethod),
                    null,
                    type);

            var store = new BoundAssignmentOperator(
                syntax,
                local,
                argument,
                refKind,
                type);

            return Pair.Make(store, local);
        }
Exemple #13
0
        /// <summary>
        /// Takes an expression and returns the bound local expression "temp"
        /// and the bound assignment expression "temp = expr".
        /// </summary>
        /// <param name="argument"></param>
        /// <param name="refKind"></param>
        /// <param name="containingMethod"></param>
        /// <returns></returns>
        public static Pair <BoundAssignmentOperator, BoundLocal> StoreToTemp(BoundExpression argument, RefKind refKind, MethodSymbol containingMethod)
        {
            var syntax = argument.Syntax;
            var type   = argument.Type;
            var local  = new BoundLocal(
                syntax,
                // TODO: the following temp local symbol should have its ContainingSymbol set.
                new TempLocalSymbol(type, refKind, containingMethod),
                null,
                type);

            var store = new BoundAssignmentOperator(
                syntax,
                local,
                argument,
                refKind,
                type);

            return(Pair.Make(store, local));
        }
        /// <summary>
        /// Takes an expression and returns the bound local expression "temp"
        /// and the bound assignment expression "temp = expr".
        /// </summary>
        public BoundLocal StoreToTemp(BoundExpression argument, out BoundAssignmentOperator store, RefKind refKind = RefKind.None, SynthesizedLocalKind kind = SynthesizedLocalKind.LoweringTemp)
        {
            MethodSymbol containingMethod = this.CurrentMethod;
            var          syntax           = argument.Syntax;
            var          type             = argument.Type;

            var local = new BoundLocal(
                syntax,
                new SynthesizedLocal(containingMethod, type, kind, syntax: kind.IsLongLived() ? syntax : null, refKind: refKind),
                null,
                type);

            store = new BoundAssignmentOperator(
                syntax,
                local,
                argument,
                refKind,
                type);

            return(local);
        }
        private static BoundExpressionStatement ClearGlobal(CSharpCompilation compilation, SyntaxNode node, FieldSymbol field)
        {
            var lhs = new BoundFieldAccess(node, null, field, null)
            {
                WasCompilerGenerated = true
            };
            var rhs = new BoundDefaultExpression(node, field.Type)
            {
                WasCompilerGenerated = true
            };
            var op = new BoundAssignmentOperator(node, lhs, rhs, field.Type)
            {
                WasCompilerGenerated = true
            };
            var stmt = new BoundExpressionStatement(node, op)
            {
                WasCompilerGenerated = true
            };

            return(stmt);
        }
        private static BoundExpressionStatement vulcanruntimeStateAssign(SyntaxNode syntax, FieldSymbol field, bool value)
        {
            var bfa = new BoundFieldAccess(syntax, null, field, ConstantValue.NotAvailable)
            {
                WasCompilerGenerated = true
            };
            var lit = new BoundLiteral(syntax, ConstantValue.Create(value), field.Type)
            {
                WasCompilerGenerated = true
            };
            var ass = new BoundAssignmentOperator(syntax, bfa, lit, isRef: false, lit.Type)
            {
                WasCompilerGenerated = true
            };
            var stmt = new BoundExpressionStatement(syntax, ass)
            {
                WasCompilerGenerated = true
            };

            return(stmt);
        }
Exemple #17
0
        private void InitParameterProxy(CSharpSyntaxNode syntax, Symbol p, LocalSymbol framePointer, ArrayBuilder <BoundExpression> prologue)
        {
            CapturedSymbolReplacement proxy;

            if (proxies.TryGetValue(p, out proxy))
            {
                BoundExpression assignToProxy;
                var             left = proxy.Replacement(syntax, frameType1 => new BoundLocal(syntax, framePointer, null, framePointer.Type));

                var parameter = p as ParameterSymbol;
                if ((object)parameter != null)
                {
                    ParameterSymbol parameterToUse;
                    if (!parameterMap.TryGetValue(parameter, out parameterToUse))
                    {
                        parameterToUse = parameter;
                    }
                    assignToProxy = new BoundAssignmentOperator(syntax,
                                                                left,
                                                                new BoundParameter(syntax, parameterToUse),
                                                                parameter.Type);
                }
                else
                {
                    var local = (LocalSymbol)p; // catch parameter
                    Debug.Assert(local.DeclarationKind == LocalDeclarationKind.Catch);
                    LocalSymbol localToUse;
                    if (!localMap.TryGetValue(local, out localToUse))
                    {
                        localToUse = local;
                    }
                    assignToProxy = new BoundAssignmentOperator(syntax,
                                                                left,
                                                                new BoundLocal(syntax, localToUse, null, localToUse.Type),
                                                                localToUse.Type);
                }

                prologue.Add(assignToProxy);
            }
        }
Exemple #18
0
        /// <summary>
        /// Returns true if the initializer is a field initializer which should be optimized out
        /// </summary>
        private static bool ShouldOptimizeOutInitializer(BoundStatement initializer)
        {
            BoundStatement statement = initializer;

            if (initializer.Kind == BoundKind.SequencePointWithSpan)
            {
                statement = ((BoundSequencePointWithSpan)initializer).StatementOpt;
            }
            else if (initializer.Kind == BoundKind.SequencePoint)
            {
                statement = ((BoundSequencePoint)initializer).StatementOpt;
            }

            if (statement == null || statement.Kind != BoundKind.ExpressionStatement)
            {
                return(false);
            }

            BoundAssignmentOperator assignment = ((BoundExpressionStatement)statement).Expression as BoundAssignmentOperator;

            if (assignment == null)
            {
                return(false);
            }

            Debug.Assert(assignment.Left.Kind == BoundKind.FieldAccess);

            var lhsField = ((BoundFieldAccess)assignment.Left).FieldSymbol;

            if (!lhsField.IsStatic && lhsField.ContainingType.IsStructType())
            {
                return(false);
            }

            BoundExpression rhs = assignment.Right;

            return(rhs.IsDefaultValue());
        }
 public override BoundNode VisitAssignmentOperator(BoundAssignmentOperator node)
 {
     // Assume value of expression is used.
     return(VisitAssignmentOperator(node, used: true));
 }
Exemple #20
0
        public override BoundNode VisitAssignmentOperator(BoundAssignmentOperator node)
        {
            BoundSpillSequenceBuilder builder = null;
            var right = VisitExpression(ref builder, node.Right);

            BoundExpression left = node.Left;

            if (builder == null)
            {
                left = VisitExpression(ref builder, left);
            }
            else
            {
                // if the right-hand-side has await, spill the left
                var leftBuilder = new BoundSpillSequenceBuilder();

                switch (left.Kind)
                {
                case BoundKind.Local:
                case BoundKind.Parameter:
                    // locals and parameters are directly assignable, LHS is not on the stack so nothing to spill
                    break;

                case BoundKind.FieldAccess:
                    var field = (BoundFieldAccess)left;
                    // static fields are directly assignable, LHS is not on the stack, nothing to spill
                    if (field.FieldSymbol.IsStatic)
                    {
                        break;
                    }

                    // instance fields are directly assignable, but receiver is pushed, so need to spill that.
                    var receiver = VisitExpression(ref leftBuilder, field.ReceiverOpt);
                    receiver = Spill(builder, receiver, field.FieldSymbol.ContainingType.IsValueType ? RefKind.Ref : RefKind.None);
                    left     = field.Update(receiver, field.FieldSymbol, field.ConstantValueOpt, field.ResultKind, field.Type);
                    break;

                case BoundKind.ArrayAccess:
                    var arrayAccess = (BoundArrayAccess)left;
                    // array and indices are pushed on stack so need to spill that
                    var expression = VisitExpression(ref leftBuilder, arrayAccess.Expression);
                    expression = Spill(builder, expression, RefKind.None);
                    var indices = this.VisitExpressionList(ref builder, arrayAccess.Indices, forceSpill: true);
                    left = arrayAccess.Update(expression, indices, arrayAccess.Type);
                    break;

                default:
                    // must be something indirectly assignable, just visit and spill as an ordinary Ref  (not a RefReadOnly!!)
                    //
                    // NOTE: in some cases this will result in spiller producing an error.
                    //       For example if the LHS is a ref-returning method like
                    //
                    //       obj.RefReturning(a, b, c) = await Something();
                    //
                    //       the spiller would eventually have to spill the evaluation result of "refReturning" call as an ordinary Ref,
                    //       which it can't.
                    left = Spill(leftBuilder, VisitExpression(ref leftBuilder, left), RefKind.Ref);
                    break;
                }

                leftBuilder.Include(builder);
                builder = leftBuilder;
            }

            return(UpdateExpression(builder, node.Update(left, right, node.IsRef, node.Type)));
        }
 private BoundExpression HoistRefInitialization(LocalSymbol local, BoundAssignmentOperator node)
 {
     var right = (BoundExpression)Visit(node.Right);
     var sideEffects = ArrayBuilder<BoundExpression>.GetInstance();
     bool needsSacrificialEvaluation = false;
     var replacement = HoistExpression(local, right, true, sideEffects, ref needsSacrificialEvaluation);
     proxies.Add(local, new CapturedToExpressionSymbolReplacement(replacement));
     if (needsSacrificialEvaluation)
     {
         var type = TypeMap.SubstituteType(local.Type);
         var sacrificalTemp = F.SynthesizedLocal(type, refKind: RefKind.Ref);
         Debug.Assert(type == replacement.Type);
         return F.Sequence(ImmutableArray.Create(sacrificalTemp), sideEffects.ToImmutableAndFree(), F.AssignmentExpression(F.Local(sacrificalTemp), replacement, refKind: RefKind.Ref));
     }
     else if (sideEffects.Count == 0)
     {
         sideEffects.Free();
         return null;
     }
     else
     {
         var last = sideEffects.Last();
         sideEffects.RemoveLast();
         return F.Sequence(ImmutableArray<LocalSymbol>.Empty, sideEffects.ToImmutableAndFree(), last);
     }
 }
 public override BoundNode?VisitAssignmentOperator(BoundAssignmentOperator node)
 {
     _mightAssignSomething = true;
     return(null);
 }
        /// <summary>
        /// If we have a WinRT type event, we need to encapsulate the adder call
        /// (which returns an EventRegistrationToken) with a call to
        /// WindowsRuntimeMarshal.AddEventHandler or RemoveEventHandler, but these
        /// require us to create a new Func representing the adder and another
        /// Action representing the Remover.
        ///
        /// The rewritten call looks something like:
        ///
        /// WindowsRuntimeMarshal.AddEventHandler&lt;EventHandler&gt;
        ///     (new Func&lt;EventHandler, EventRegistrationToken&gt;(@object.add),
        ///      new Action&lt;EventRegistrationToken&gt;(@object.remove), handler);
        ///
        /// Where @object is a compiler-generated local temp if needed.
        /// </summary>
        /// <remarks>
        /// TODO: use or delete isDynamic.
        /// </remarks>
        private BoundExpression RewriteWindowsRuntimeEventAssignmentOperator(SyntaxNode syntax, EventSymbol eventSymbol, EventAssignmentKind kind, bool isDynamic, BoundExpression rewrittenReceiverOpt, BoundExpression rewrittenArgument)
        {
            BoundAssignmentOperator tempAssignment = null;
            BoundLocal boundTemp = null;

            if (!eventSymbol.IsStatic && CanChangeValueBetweenReads(rewrittenReceiverOpt))
            {
                boundTemp = _factory.StoreToTemp(rewrittenReceiverOpt, out tempAssignment);
            }

            NamedTypeSymbol tokenType   = _factory.WellKnownType(WellKnownType.System_Runtime_InteropServices_WindowsRuntime_EventRegistrationToken);
            NamedTypeSymbol marshalType = _factory.WellKnownType(WellKnownType.System_Runtime_InteropServices_WindowsRuntime_WindowsRuntimeMarshal);

            NamedTypeSymbol actionType = _factory.WellKnownType(WellKnownType.System_Action_T).Construct(tokenType);

            TypeSymbol eventType = eventSymbol.Type;

            BoundExpression delegateCreationArgument = boundTemp ?? rewrittenReceiverOpt ?? _factory.Type(eventType);

            BoundDelegateCreationExpression removeDelegate = new BoundDelegateCreationExpression(
                syntax: syntax,
                argument: delegateCreationArgument,
                methodOpt: eventSymbol.RemoveMethod,
                isExtensionMethod: false,
                type: actionType);

            BoundExpression clearCall = null;

            if (kind == EventAssignmentKind.Assignment)
            {
                MethodSymbol clearMethod;
                if (TryGetWellKnownTypeMember(syntax, WellKnownMember.System_Runtime_InteropServices_WindowsRuntime_WindowsRuntimeMarshal__RemoveAllEventHandlers, out clearMethod))
                {
                    clearCall = MakeCall(
                        syntax: syntax,
                        rewrittenReceiver: null,
                        method: clearMethod,
                        rewrittenArguments: ImmutableArray.Create <BoundExpression>(removeDelegate),
                        type: clearMethod.ReturnType);
                }
                else
                {
                    clearCall = new BoundBadExpression(syntax, LookupResultKind.NotInvocable, ImmutableArray <Symbol> .Empty, ImmutableArray.Create <BoundExpression>(removeDelegate), ErrorTypeSymbol.UnknownResultType);
                }
            }

            ImmutableArray <BoundExpression> marshalArguments;
            WellKnownMember helper;

            if (kind == EventAssignmentKind.Subtraction)
            {
                helper           = WellKnownMember.System_Runtime_InteropServices_WindowsRuntime_WindowsRuntimeMarshal__RemoveEventHandler_T;
                marshalArguments = ImmutableArray.Create <BoundExpression>(removeDelegate, rewrittenArgument);
            }
            else
            {
                NamedTypeSymbol func2Type = _factory.WellKnownType(WellKnownType.System_Func_T2).Construct(eventType, tokenType);

                BoundDelegateCreationExpression addDelegate = new BoundDelegateCreationExpression(
                    syntax: syntax,
                    argument: delegateCreationArgument,
                    methodOpt: eventSymbol.AddMethod,
                    isExtensionMethod: false,
                    type: func2Type);

                helper           = WellKnownMember.System_Runtime_InteropServices_WindowsRuntime_WindowsRuntimeMarshal__AddEventHandler_T;
                marshalArguments = ImmutableArray.Create <BoundExpression>(addDelegate, removeDelegate, rewrittenArgument);
            }

            BoundExpression marshalCall;

            MethodSymbol marshalMethod;

            if (TryGetWellKnownTypeMember(syntax, helper, out marshalMethod))
            {
                marshalMethod = marshalMethod.Construct(eventType);

                marshalCall = MakeCall(
                    syntax: syntax,
                    rewrittenReceiver: null,
                    method: marshalMethod,
                    rewrittenArguments: marshalArguments,
                    type: marshalMethod.ReturnType);
            }
            else
            {
                marshalCall = new BoundBadExpression(syntax, LookupResultKind.NotInvocable, ImmutableArray <Symbol> .Empty, marshalArguments, ErrorTypeSymbol.UnknownResultType);
            }

            // In this case, we don't need a sequence.
            if (boundTemp == null && clearCall == null)
            {
                return(marshalCall);
            }

            ImmutableArray <LocalSymbol> tempSymbols = boundTemp == null
                ? ImmutableArray <LocalSymbol> .Empty
                : ImmutableArray.Create <LocalSymbol>(boundTemp.LocalSymbol);

            ArrayBuilder <BoundExpression> sideEffects = ArrayBuilder <BoundExpression> .GetInstance(2); //max size

            if (clearCall != null)
            {
                sideEffects.Add(clearCall);
            }
            if (tempAssignment != null)
            {
                sideEffects.Add(tempAssignment);
            }
            Debug.Assert(sideEffects.Any(), "Otherwise, we shouldn't be building a sequence");

            return(new BoundSequence(syntax, tempSymbols, sideEffects.ToImmutableAndFree(), marshalCall, marshalCall.Type));
        }
 /// <summary>
 /// Takes an expression and returns the bound local expression "temp" 
 /// and the bound assignment expression "temp = expr".
 /// </summary>
 public BoundLocal StoreToTemp(BoundExpression argument, out BoundAssignmentOperator store, RefKind refKind = RefKind.None, TempKind tempKind = TempKind.None)
 {
     MethodSymbol containingMethod = this.CurrentMethod;
     var syntax = argument.Syntax;
     var type = argument.Type;
     var local = new BoundLocal(
         syntax,
         new SynthesizedLocal(containingMethod, type, syntax: (tempKind == TempKind.None) ? null : syntax, refKind: refKind, tempKind: tempKind),
         null,
         type);
     store = new BoundAssignmentOperator(
         syntax,
         local,
         argument,
         refKind,
         type);
     return local;
 }
        public override BoundNode VisitAssignmentOperator(BoundAssignmentOperator node)
        {
            if (node.Left.Kind != BoundKind.Local)
            {
                return base.VisitAssignmentOperator(node);
            }

            var leftLocal = ((BoundLocal)node.Left).LocalSymbol;
            if (!NeedsProxy(leftLocal))
            {
                return base.VisitAssignmentOperator(node);
            }

            if (proxies.ContainsKey(leftLocal))
            {
                Debug.Assert(node.RefKind == RefKind.None);
                return base.VisitAssignmentOperator(node);
            }

            // TODO (move to AsyncMethodToStateMachineRewriter, this is not applicable to iterators)

            // User-declared variables are preassigned their proxies, and by-value synthesized variables
            // are assigned proxies at the beginning of their scope by the enclosing construct.
            // Here we handle ref temps. Ref synthesized variables are the target of a ref assignment operator before
            // being used in any other way.

            Debug.Assert(leftLocal.SynthesizedKind == SynthesizedLocalKind.AwaitSpill);
            Debug.Assert(node.RefKind != RefKind.None);

            // We have an assignment to a variable that has not yet been assigned a proxy.
            // So we assign the proxy before translating the assignment.
            return HoistRefInitialization((SynthesizedLocal)leftLocal, node);
        }
        private BoundExpression HoistRefInitialization(SynthesizedLocal local, BoundAssignmentOperator node)
        {
            Debug.Assert(local.SynthesizedKind == SynthesizedLocalKind.AwaitSpill);
            Debug.Assert(local.SyntaxOpt != null);
            Debug.Assert(this.OriginalMethod.IsAsync);

            var right = (BoundExpression)Visit(node.Right);

            var sideEffects = ArrayBuilder<BoundExpression>.GetInstance();
            bool needsSacrificialEvaluation = false;
            var hoistedFields = ArrayBuilder<StateMachineFieldSymbol>.GetInstance();

            AwaitExpressionSyntax awaitSyntaxOpt;
            int syntaxOffset;
            if (F.Compilation.Options.OptimizationLevel == OptimizationLevel.Debug)
            {
                awaitSyntaxOpt = (AwaitExpressionSyntax)local.GetDeclaratorSyntax();
                syntaxOffset = this.OriginalMethod.CalculateLocalSyntaxOffset(awaitSyntaxOpt.SpanStart, awaitSyntaxOpt.SyntaxTree);
            }
            else
            {
                // These are only used to calculate debug id for ref-spilled variables, 
                // no need to do so in release build.
                awaitSyntaxOpt = null;
                syntaxOffset = -1;
            }

            var replacement = HoistExpression(right, awaitSyntaxOpt, syntaxOffset, true, sideEffects, hoistedFields, ref needsSacrificialEvaluation);

            proxies.Add(local, new CapturedToExpressionSymbolReplacement(replacement, hoistedFields.ToImmutableAndFree(), isReusable: true));

            if (needsSacrificialEvaluation)
            {
                var type = TypeMap.SubstituteType(local.Type).Type;
                var sacrificialTemp = F.SynthesizedLocal(type, refKind: RefKind.Ref);
                Debug.Assert(type == replacement.Type);
                return F.Sequence(ImmutableArray.Create(sacrificialTemp), sideEffects.ToImmutableAndFree(), F.AssignmentExpression(F.Local(sacrificialTemp), replacement, refKind: RefKind.Ref));
            }

            if (sideEffects.Count == 0)
            {
                sideEffects.Free();
                return null;
            }

            var last = sideEffects.Last();
            sideEffects.RemoveLast();
            return F.Sequence(ImmutableArray<LocalSymbol>.Empty, sideEffects.ToImmutableAndFree(), last);
        }
        public override BoundNode VisitAssignmentOperator(BoundAssignmentOperator node)
        {
            if (node.Left.Kind != BoundKind.Local)
            {
                return base.VisitAssignmentOperator(node);
            }

            var left = (BoundLocal)node.Left;
            var local = left.LocalSymbol;
            if (!IsCaptured(local))
            {
                return base.VisitAssignmentOperator(node);
            }

            if (proxies.ContainsKey(local))
            {
                Debug.Assert(node.RefKind == RefKind.None);
                return base.VisitAssignmentOperator(node);
            }

            // user-declared variables are preassigned their proxies, and value temps
            // are assigned proxies at the beginning of their scope by the enclosing construct.
            // Here we handle ref temps.  Ref temps are the target of a ref assignment operator before
            // being used in any other way.
            Debug.Assert(
                local.SynthesizedLocalKind == SynthesizedLocalKind.AwaitSpilledTemp ||
                local.SynthesizedLocalKind != SynthesizedLocalKind.LambdaDisplayClass);

            Debug.Assert(node.RefKind != RefKind.None);

            // we have an assignment to a variable that has not yet been assigned a proxy.
            // So we assign the proxy before translating the assignment.
            return HoistRefInitialization(local, node);
        }
        // Rewrite object initializer member assignment and add it to the result.
        //  new SomeType { Member = 0 };
        //                 ~~~~~~~~~~
        private void AddObjectInitializer(
            ref ArrayBuilder<BoundExpression> dynamicSiteInitializers,
            ref ArrayBuilder<LocalSymbol> temps,
            ArrayBuilder<BoundExpression> result,
            BoundExpression rewrittenReceiver,
            BoundAssignmentOperator assignment)
        {
            Debug.Assert(rewrittenReceiver != null);
            Debug.Assert(!_inExpressionLambda);

            // Update the receiver for the field/property access as we might have introduced a temp for the initializer rewrite.

            BoundExpression rewrittenLeft = null;

            // Do not lower pointer access yet, we'll do it later.
            if (assignment.Left.Kind != BoundKind.PointerElementAccess)
            {
                rewrittenLeft = VisitExpression(assignment.Left);
            }

            BoundKind rhsKind = assignment.Right.Kind;
            bool isRhsNestedInitializer = rhsKind == BoundKind.ObjectInitializerExpression || rhsKind == BoundKind.CollectionInitializerExpression;

            BoundExpression rewrittenAccess;
            switch ((rewrittenLeft ?? assignment.Left).Kind)
            {
                case BoundKind.ObjectInitializerMember:
                    {
                        var memberInit = (BoundObjectInitializerMember)rewrittenLeft;

                        if (!memberInit.Arguments.IsDefaultOrEmpty)
                        {
                            var args = EvaluateSideEffectingArgumentsToTemps(memberInit.Arguments, result, ref temps);
                            memberInit = memberInit.Update(
                                memberInit.MemberSymbol,
                                args,
                                memberInit.ArgumentNamesOpt,
                                memberInit.ArgumentRefKindsOpt,
                                memberInit.Expanded,
                                memberInit.ArgsToParamsOpt,
                                memberInit.ResultKind,
                                memberInit.Type);
                        }

                        if (memberInit.MemberSymbol == null && memberInit.Type.IsDynamic())
                        {
                            if (dynamicSiteInitializers == null)
                            {
                                dynamicSiteInitializers = ArrayBuilder<BoundExpression>.GetInstance();
                            }

                            if (!isRhsNestedInitializer)
                            {
                                var rewrittenRight = VisitExpression(assignment.Right);
                                var setMember = _dynamicFactory.MakeDynamicSetIndex(
                                    rewrittenReceiver,
                                    memberInit.Arguments,
                                    memberInit.ArgumentNamesOpt,
                                    memberInit.ArgumentRefKindsOpt,
                                    rewrittenRight);

                                dynamicSiteInitializers.Add(setMember.SiteInitialization);
                                result.Add(setMember.SiteInvocation);
                                return;
                            }

                            var getMember = _dynamicFactory.MakeDynamicGetIndex(
                                rewrittenReceiver,
                                memberInit.Arguments,
                                memberInit.ArgumentNamesOpt,
                                memberInit.ArgumentRefKindsOpt);

                            dynamicSiteInitializers.Add(getMember.SiteInitialization);
                            rewrittenAccess = getMember.SiteInvocation;
                        }
                        else
                        {
                            rewrittenAccess = MakeObjectInitializerMemberAccess(rewrittenReceiver, memberInit, isRhsNestedInitializer);
                            if (!isRhsNestedInitializer)
                            {
                                // Rewrite simple assignment to field/property.
                                var rewrittenRight = VisitExpression(assignment.Right);
                                result.Add(MakeStaticAssignmentOperator(assignment.Syntax, rewrittenAccess, rewrittenRight, RefKind.None, assignment.Type, used: false));
                                return;
                            }
                        }
                        break;
                    }

                case BoundKind.DynamicObjectInitializerMember:
                    {
                        if (dynamicSiteInitializers == null)
                        {
                            dynamicSiteInitializers = ArrayBuilder<BoundExpression>.GetInstance();
                        }

                        var initializerMember = (BoundDynamicObjectInitializerMember)rewrittenLeft;

                        if (!isRhsNestedInitializer)
                        {
                            var rewrittenRight = VisitExpression(assignment.Right);
                            var setMember = _dynamicFactory.MakeDynamicSetMember(rewrittenReceiver, initializerMember.MemberName, rewrittenRight);
                            dynamicSiteInitializers.Add(setMember.SiteInitialization);
                            result.Add(setMember.SiteInvocation);
                            return;
                        }

                        var getMember = _dynamicFactory.MakeDynamicGetMember(rewrittenReceiver, initializerMember.MemberName, resultIndexed: false);
                        dynamicSiteInitializers.Add(getMember.SiteInitialization);
                        rewrittenAccess = getMember.SiteInvocation;
                        break;
                    }

                case BoundKind.ArrayAccess:
                    {
                        var arrayAccess = (BoundArrayAccess)rewrittenLeft;
                        var indices = EvaluateSideEffectingArgumentsToTemps(arrayAccess.Indices, result, ref temps);
                        rewrittenAccess = arrayAccess.Update(rewrittenReceiver, indices, arrayAccess.Type);

                        if (!isRhsNestedInitializer)
                        {
                            // Rewrite simple assignment to field/property.
                            var rewrittenRight = VisitExpression(assignment.Right);
                            result.Add(MakeStaticAssignmentOperator(assignment.Syntax, rewrittenAccess, rewrittenRight, RefKind.None, assignment.Type, used: false));
                            return;
                        }

                        break;
                    }

                case BoundKind.PointerElementAccess:
                    {
                        // Remember we haven't lowered this node yet.
                        var pointerAccess = (BoundPointerElementAccess)assignment.Left;
                        var rewrittenIndex = VisitExpression(pointerAccess.Index);

                        if (CanChangeValueBetweenReads(rewrittenIndex))
                        {
                            BoundAssignmentOperator store;
                            var temp = _factory.StoreToTemp(rewrittenIndex, out store);
                            rewrittenIndex = temp;

                            if (temps == null)
                            {
                                temps = ArrayBuilder<LocalSymbol>.GetInstance();
                            }
                            temps.Add(temp.LocalSymbol);
                            result.Add(store);
                        }

                        rewrittenAccess = RewritePointerElementAccess(pointerAccess, rewrittenReceiver, rewrittenIndex);

                        if (!isRhsNestedInitializer)
                        {
                            // Rewrite as simple assignment.
                            var rewrittenRight = VisitExpression(assignment.Right);
                            result.Add(MakeStaticAssignmentOperator(assignment.Syntax, rewrittenAccess, rewrittenRight, RefKind.None, assignment.Type, used: false));
                            return;
                        }

                        break;
                    }

                default:
                    throw ExceptionUtilities.UnexpectedValue((rewrittenLeft ?? assignment.Left).Kind);
            }

            AddObjectOrCollectionInitializers(ref dynamicSiteInitializers, ref temps, result, rewrittenAccess, assignment.Right);
        }
        public override BoundNode VisitAssignmentOperator(BoundAssignmentOperator node)
        {
            CheckForAssignmentToSelf(node);
            if (_inExpressionLambda && node.Left.Kind != BoundKind.ObjectInitializerMember && node.Left.Kind != BoundKind.DynamicObjectInitializerMember)
            {
                Error(ErrorCode.ERR_ExpressionTreeContainsAssignment, node);
            }

            return base.VisitAssignmentOperator(node);
        }
 private bool CheckForAssignmentToSelf(BoundAssignmentOperator node)
 {
     if (!node.HasAnyErrors && IsSameLocalOrField(node.Left, node.Right))
     {
         Error(ErrorCode.WRN_AssignmentToSelf, node);
         return true;
     }
     return false;
 }
Exemple #31
0
        /// <summary>
        /// Generates a submission initialization part of a Script type constructor that represents an interactive submission.
        /// </summary>
        /// <remarks>
        /// The constructor takes a parameter of type Roslyn.Scripting.Session - the session reference.
        /// It adds the object being constructed into the session by calling Microsoft.CSharp.RuntimeHelpers.SessionHelpers.SetSubmission,
        /// and retrieves strongly typed references on all previous submission script classes whose members are referenced by this submission.
        /// The references are stored to fields of the submission (<paramref name="synthesizedFields"/>).
        /// </remarks>
        private static ImmutableArray <BoundStatement> MakeSubmissionInitialization(CSharpSyntaxNode syntax, MethodSymbol submissionConstructor, SynthesizedSubmissionFields synthesizedFields, CSharpCompilation compilation)
        {
            Debug.Assert(submissionConstructor.ParameterCount == 2);

            BoundStatement[] result = new BoundStatement[1 + synthesizedFields.Count];

            var sessionReference = new BoundParameter(syntax, submissionConstructor.Parameters[0])
            {
                WasCompilerGenerated = true
            };
            var submissionGetter = (MethodSymbol)compilation.GetWellKnownTypeMember(
                WellKnownMember.Microsoft_CSharp_RuntimeHelpers_SessionHelpers__GetSubmission
                );
            var submissionAdder = (MethodSymbol)compilation.GetWellKnownTypeMember(
                WellKnownMember.Microsoft_CSharp_RuntimeHelpers_SessionHelpers__SetSubmission
                );

            // TODO: report missing adder/getter
            Debug.Assert((object)submissionAdder != null && (object)submissionGetter != null);

            var intType       = compilation.GetSpecialType(SpecialType.System_Int32);
            var thisReference = new BoundThisReference(syntax, submissionConstructor.ContainingType)
            {
                WasCompilerGenerated = true
            };

            int i = 0;

            // hostObject = (THostObject)SessionHelpers.SetSubmission(<session>, <slot index>, this);
            var slotIndex = compilation.GetSubmissionSlotIndex();

            Debug.Assert(slotIndex >= 0);

            BoundExpression setSubmission = BoundCall.Synthesized(syntax,
                                                                  null,
                                                                  submissionAdder,
                                                                  sessionReference,
                                                                  new BoundLiteral(syntax, ConstantValue.Create(slotIndex), intType)
            {
                WasCompilerGenerated = true
            },
                                                                  thisReference
                                                                  );

            var hostObjectField = synthesizedFields.GetHostObjectField();

            if ((object)hostObjectField != null)
            {
                setSubmission = new BoundAssignmentOperator(syntax,
                                                            new BoundFieldAccess(syntax, thisReference, hostObjectField, ConstantValue.NotAvailable)
                {
                    WasCompilerGenerated = true
                },
                                                            BoundConversion.Synthesized(syntax,
                                                                                        setSubmission,
                                                                                        Conversion.ExplicitReference,
                                                                                        false,
                                                                                        true,
                                                                                        ConstantValue.NotAvailable,
                                                                                        hostObjectField.Type
                                                                                        ),
                                                            hostObjectField.Type
                                                            )
                {
                    WasCompilerGenerated = true
                };
            }

            result[i++] = new BoundExpressionStatement(syntax, setSubmission)
            {
                WasCompilerGenerated = true
            };

            foreach (var field in synthesizedFields.FieldSymbols)
            {
                var targetScriptClass  = (ImplicitNamedTypeSymbol)field.Type;
                var targetSubmissionId = targetScriptClass.DeclaringCompilation.GetSubmissionSlotIndex();
                Debug.Assert(targetSubmissionId >= 0);

                // this.<field> = (<FieldType>)SessionHelpers.GetSubmission(<session>, <i>);
                result[i++] =
                    new BoundExpressionStatement(syntax,
                                                 new BoundAssignmentOperator(syntax,
                                                                             new BoundFieldAccess(syntax, thisReference, field, ConstantValue.NotAvailable)
                {
                    WasCompilerGenerated = true
                },
                                                                             BoundConversion.Synthesized(syntax,
                                                                                                         BoundCall.Synthesized(syntax,
                                                                                                                               null,
                                                                                                                               submissionGetter,
                                                                                                                               sessionReference,
                                                                                                                               new BoundLiteral(syntax, ConstantValue.Create(targetSubmissionId), intType)
                {
                    WasCompilerGenerated = true
                }),
                                                                                                         Conversion.ExplicitReference,
                                                                                                         false,
                                                                                                         true,
                                                                                                         ConstantValue.NotAvailable,
                                                                                                         targetScriptClass
                                                                                                         ),
                                                                             targetScriptClass
                                                                             )
                {
                    WasCompilerGenerated = true
                })
                {
                    WasCompilerGenerated = true
                };
            }

            Debug.Assert(i == result.Length);

            return(result.AsImmutableOrNull());
        }
        // Rewrite object initializer member assignment and add it to the result.
        //  new SomeType { Member = 0 };
        //                 ~~~~~~~~~~
        private void AddObjectInitializer(ref ArrayBuilder<BoundExpression> dynamicSiteInitializers, ArrayBuilder<BoundExpression> result, BoundExpression rewrittenReceiver, BoundAssignmentOperator assignment)
        {
            Debug.Assert(rewrittenReceiver != null);
            Debug.Assert(!inExpressionLambda);

            // Update the receiver for the field/property access as we might have introduced a temp for the initializer rewrite.

            BoundExpression rewrittenLeft = VisitExpression(assignment.Left);

            BoundKind rhsKind = assignment.Right.Kind;
            bool isRhsNestedInitializer = rhsKind == BoundKind.ObjectInitializerExpression || rhsKind == BoundKind.CollectionInitializerExpression;

            BoundExpression rewrittenAccess;
            if (rewrittenLeft.Kind == BoundKind.ObjectInitializerMember)
            {
                var memberInit = (BoundObjectInitializerMember)rewrittenLeft;
                if (memberInit.MemberSymbol == null && memberInit.Type.IsDynamic())
                {
                    if (dynamicSiteInitializers == null)
                    {
                        dynamicSiteInitializers = ArrayBuilder<BoundExpression>.GetInstance();
                    }

                    if (!isRhsNestedInitializer)
                    {
                        var rewrittenRight = VisitExpression(assignment.Right);
                        var setMember = dynamicFactory.MakeDynamicSetIndex(
                            rewrittenReceiver,
                            memberInit.Arguments,
                            default(ImmutableArray<string>),
                            default(ImmutableArray<RefKind>),
                            rewrittenRight);

                        dynamicSiteInitializers.Add(setMember.SiteInitialization);
                        result.Add(setMember.SiteInvocation);
                        return;
                    }

                    var getMember = dynamicFactory.MakeDynamicGetIndex(
                        rewrittenReceiver,
                        memberInit.Arguments,
                        default(ImmutableArray<string>),
                        default(ImmutableArray<RefKind>));

                    dynamicSiteInitializers.Add(getMember.SiteInitialization);
                    rewrittenAccess = getMember.SiteInvocation;
                }
                else
                {
                    rewrittenAccess = MakeObjectInitializerMemberAccess(rewrittenReceiver, memberInit, isRhsNestedInitializer);
                    if (!isRhsNestedInitializer)
                    {
                        // Rewrite simple assignment to field/property.
                        var rewrittenRight = VisitExpression(assignment.Right);
                        result.Add(MakeStaticAssignmentOperator(assignment.Syntax, rewrittenAccess, rewrittenRight, assignment.Type, used: false));
                        return;
                    }
                }
            }
            else
            {
                if (dynamicSiteInitializers == null)
                {
                    dynamicSiteInitializers = ArrayBuilder<BoundExpression>.GetInstance();
                }

                Debug.Assert(rewrittenLeft.Kind == BoundKind.DynamicObjectInitializerMember);
                var initializerMember = (BoundDynamicObjectInitializerMember)rewrittenLeft;

                if (!isRhsNestedInitializer)
                {
                    var rewrittenRight = VisitExpression(assignment.Right);
                    var setMember = dynamicFactory.MakeDynamicSetMember(rewrittenReceiver, initializerMember.MemberName, rewrittenRight);
                    dynamicSiteInitializers.Add(setMember.SiteInitialization);
                    result.Add(setMember.SiteInvocation);
                    return;
                }

                var getMember = dynamicFactory.MakeDynamicGetMember(rewrittenReceiver, initializerMember.MemberName, resultIndexed: false);
                dynamicSiteInitializers.Add(getMember.SiteInitialization);
                rewrittenAccess = getMember.SiteInvocation;
            }

            AddObjectOrCollectionInitializers(ref dynamicSiteInitializers, result, rewrittenAccess, assignment.Right);
        }
        private BoundExpression VisitAssignmentOperator(BoundAssignmentOperator node, bool used)
        {
            var loweredRight = VisitExpression(node.Right);

            BoundExpression left = node.Left;
            BoundExpression loweredLeft;

            switch (left.Kind)
            {
            case BoundKind.PropertyAccess:
                loweredLeft = VisitPropertyAccess((BoundPropertyAccess)left, isLeftOfAssignment: true);
                break;

            case BoundKind.IndexerAccess:
                loweredLeft = VisitIndexerAccess((BoundIndexerAccess)left, isLeftOfAssignment: true);
                break;

            case BoundKind.EventAccess:
            {
                BoundEventAccess eventAccess = (BoundEventAccess)left;
                if (eventAccess.EventSymbol.IsWindowsRuntimeEvent)
                {
                    Debug.Assert(!node.IsRef);
                    return(VisitWindowsRuntimeEventFieldAssignmentOperator(node.Syntax, eventAccess, loweredRight));
                }
                goto default;
            }

            case BoundKind.DynamicMemberAccess:
            {
                // dyn.m = expr
                var memberAccess    = (BoundDynamicMemberAccess)left;
                var loweredReceiver = VisitExpression(memberAccess.Receiver);
#if XSHARP
                if (_compilation.Options.LateBindingOrFox(node.Syntax) && !loweredReceiver.HasDynamicType())
                {
                    var expr = MakeVODynamicSetMember(loweredReceiver, memberAccess.Name, loweredRight);
                    if (expr != null)
                    {
                        return(expr);
                    }
                }
#endif
                return(_dynamicFactory.MakeDynamicSetMember(loweredReceiver, memberAccess.Name, loweredRight).ToExpression());
            }

            case BoundKind.DynamicIndexerAccess:
            {
                // dyn[args] = expr
                var indexerAccess = (BoundDynamicIndexerAccess)left;
                Debug.Assert(indexerAccess.ReceiverOpt != null);
                var loweredReceiver  = VisitExpression(indexerAccess.ReceiverOpt);
                var loweredArguments = VisitList(indexerAccess.Arguments);
                return(MakeDynamicSetIndex(
                           indexerAccess,
                           loweredReceiver,
                           loweredArguments,
                           indexerAccess.ArgumentNamesOpt,
                           indexerAccess.ArgumentRefKindsOpt,
                           loweredRight));
            }

            default:
                loweredLeft = VisitExpression(left);
                break;
            }

            return(MakeStaticAssignmentOperator(node.Syntax, loweredLeft, loweredRight, node.IsRef, node.Type, used));
        }
Exemple #34
0
        // Rewrite object initializer member assignment and add it to the result.
        //  new SomeType { Member = 0 };
        //                 ~~~~~~~~~~
        private void AddObjectInitializer(
            ref ArrayBuilder <BoundExpression> dynamicSiteInitializers,
            ref ArrayBuilder <LocalSymbol> temps,
            ArrayBuilder <BoundExpression> result,
            BoundExpression rewrittenReceiver,
            BoundAssignmentOperator assignment)
        {
            Debug.Assert(rewrittenReceiver != null);
            Debug.Assert(!_inExpressionLambda);

            // Update the receiver for the field/property access as we might have introduced a temp for the initializer rewrite.

            BoundExpression rewrittenLeft = null;

            // Do not lower pointer access yet, we'll do it later.
            if (assignment.Left.Kind != BoundKind.PointerElementAccess)
            {
                rewrittenLeft = VisitExpression(assignment.Left);
            }

            BoundKind rhsKind = assignment.Right.Kind;
            bool      isRhsNestedInitializer = rhsKind == BoundKind.ObjectInitializerExpression || rhsKind == BoundKind.CollectionInitializerExpression;

            BoundExpression rewrittenAccess;

            switch ((rewrittenLeft ?? assignment.Left).Kind)
            {
            case BoundKind.ObjectInitializerMember:
            {
                var memberInit = (BoundObjectInitializerMember)rewrittenLeft;

                if (!memberInit.Arguments.IsDefaultOrEmpty)
                {
                    var args = EvaluateSideEffectingArgumentsToTemps(memberInit.Arguments, result, ref temps);
                    memberInit = memberInit.Update(
                        memberInit.MemberSymbol,
                        args,
                        memberInit.ArgumentNamesOpt,
                        memberInit.ArgumentRefKindsOpt,
                        memberInit.Expanded,
                        memberInit.ArgsToParamsOpt,
                        memberInit.ResultKind,
                        memberInit.ReceiverType,
                        memberInit.BinderOpt,
                        memberInit.Type);
                }

                if (memberInit.MemberSymbol == null && memberInit.Type.IsDynamic())
                {
                    if (dynamicSiteInitializers == null)
                    {
                        dynamicSiteInitializers = ArrayBuilder <BoundExpression> .GetInstance();
                    }

                    if (!isRhsNestedInitializer)
                    {
                        var rewrittenRight = VisitExpression(assignment.Right);
                        var setMember      = _dynamicFactory.MakeDynamicSetIndex(
                            rewrittenReceiver,
                            memberInit.Arguments,
                            memberInit.ArgumentNamesOpt,
                            memberInit.ArgumentRefKindsOpt,
                            rewrittenRight);

                        dynamicSiteInitializers.Add(setMember.SiteInitialization);
                        result.Add(setMember.SiteInvocation);
                        return;
                    }

                    var getMember = _dynamicFactory.MakeDynamicGetIndex(
                        rewrittenReceiver,
                        memberInit.Arguments,
                        memberInit.ArgumentNamesOpt,
                        memberInit.ArgumentRefKindsOpt);

                    dynamicSiteInitializers.Add(getMember.SiteInitialization);
                    rewrittenAccess = getMember.SiteInvocation;
                }
                else
                {
                    rewrittenAccess = MakeObjectInitializerMemberAccess(rewrittenReceiver, memberInit, isRhsNestedInitializer);
                    if (!isRhsNestedInitializer)
                    {
                        // Rewrite simple assignment to field/property.
                        var rewrittenRight = VisitExpression(assignment.Right);
                        result.Add(MakeStaticAssignmentOperator(assignment.Syntax, rewrittenAccess, rewrittenRight, false, assignment.Type, used: false));
                        return;
                    }
                }
                break;
            }

            case BoundKind.DynamicObjectInitializerMember:
            {
                if (dynamicSiteInitializers == null)
                {
                    dynamicSiteInitializers = ArrayBuilder <BoundExpression> .GetInstance();
                }

                var initializerMember = (BoundDynamicObjectInitializerMember)rewrittenLeft;

                if (!isRhsNestedInitializer)
                {
                    var rewrittenRight = VisitExpression(assignment.Right);
                    var setMember      = _dynamicFactory.MakeDynamicSetMember(rewrittenReceiver, initializerMember.MemberName, rewrittenRight);
                    dynamicSiteInitializers.Add(setMember.SiteInitialization);
                    result.Add(setMember.SiteInvocation);
                    return;
                }

                var getMember = _dynamicFactory.MakeDynamicGetMember(rewrittenReceiver, initializerMember.MemberName, resultIndexed: false);
                dynamicSiteInitializers.Add(getMember.SiteInitialization);
                rewrittenAccess = getMember.SiteInvocation;
                break;
            }

            case BoundKind.ArrayAccess:
            {
                var arrayAccess = (BoundArrayAccess)rewrittenLeft;
                var indices     = EvaluateSideEffectingArgumentsToTemps(arrayAccess.Indices, result, ref temps);
                rewrittenAccess = arrayAccess.Update(rewrittenReceiver, indices, arrayAccess.Type);

                if (!isRhsNestedInitializer)
                {
                    // Rewrite simple assignment to field/property.
                    var rewrittenRight = VisitExpression(assignment.Right);
                    result.Add(MakeStaticAssignmentOperator(assignment.Syntax, rewrittenAccess, rewrittenRight, false, assignment.Type, used: false));
                    return;
                }

                break;
            }

            case BoundKind.PointerElementAccess:
            {
                // Remember we haven't lowered this node yet.
                var pointerAccess  = (BoundPointerElementAccess)assignment.Left;
                var rewrittenIndex = VisitExpression(pointerAccess.Index);

                if (CanChangeValueBetweenReads(rewrittenIndex))
                {
                    BoundAssignmentOperator store;
                    var temp = _factory.StoreToTemp(rewrittenIndex, out store);
                    rewrittenIndex = temp;

                    if (temps == null)
                    {
                        temps = ArrayBuilder <LocalSymbol> .GetInstance();
                    }
                    temps.Add(temp.LocalSymbol);
                    result.Add(store);
                }

                rewrittenAccess = RewritePointerElementAccess(pointerAccess, rewrittenReceiver, rewrittenIndex);

                if (!isRhsNestedInitializer)
                {
                    // Rewrite as simple assignment.
                    var rewrittenRight = VisitExpression(assignment.Right);
                    result.Add(MakeStaticAssignmentOperator(assignment.Syntax, rewrittenAccess, rewrittenRight, false, assignment.Type, used: false));
                    return;
                }

                break;
            }

            default:
                throw ExceptionUtilities.UnexpectedValue((rewrittenLeft ?? assignment.Left).Kind);
            }

            AddObjectOrCollectionInitializers(ref dynamicSiteInitializers, ref temps, result, rewrittenAccess, assignment.Right);
        }
        /// <summary>
        /// Takes an expression and returns the bound local expression "temp" 
        /// and the bound assignment expression "temp = expr".
        /// </summary>
        public BoundLocal StoreToTemp(BoundExpression argument, out BoundAssignmentOperator store, RefKind refKind = RefKind.None, SynthesizedLocalKind kind = SynthesizedLocalKind.LoweringTemp)
        {
            MethodSymbol containingMethod = this.CurrentMethod;
            var syntax = argument.Syntax;
            var type = argument.Type;

            var local = new BoundLocal(
                syntax,
                new SynthesizedLocal(containingMethod, type, kind, syntax: kind.IsLongLived() ? syntax : null, refKind: refKind),
                null,
                type);

            store = new BoundAssignmentOperator(
                syntax,
                local,
                argument,
                refKind,
                type);

            return local;
        }
        /// <summary>
        /// Generates a submission initialization part of a Script type constructor that represents an interactive submission.
        /// </summary>
        /// <remarks>
        /// The constructor takes a parameter of type Roslyn.Scripting.Session - the session reference.
        /// It adds the object being constructed into the session by calling Microsoft.CSharp.RuntimeHelpers.SessionHelpers.SetSubmission,
        /// and retrieves strongly typed references on all previous submission script classes whose members are referenced by this submission.
        /// The references are stored to fields of the submission (<paramref name="synthesizedFields"/>).
        /// </remarks>
        private static ImmutableArray<BoundStatement> MakeSubmissionInitialization(CSharpSyntaxNode syntax, MethodSymbol submissionConstructor, SynthesizedSubmissionFields synthesizedFields, CSharpCompilation compilation)
        {
            Debug.Assert(submissionConstructor.ParameterCount == 2);

            BoundStatement[] result = new BoundStatement[1 + synthesizedFields.Count];

            var sessionReference = new BoundParameter(syntax, submissionConstructor.Parameters[0]) { WasCompilerGenerated = true };
            var submissionGetter = (MethodSymbol)compilation.GetWellKnownTypeMember(
                WellKnownMember.Microsoft_CSharp_RuntimeHelpers_SessionHelpers__GetSubmission
            );
            var submissionAdder = (MethodSymbol)compilation.GetWellKnownTypeMember(
                WellKnownMember.Microsoft_CSharp_RuntimeHelpers_SessionHelpers__SetSubmission
            );

            // TODO: report missing adder/getter
            Debug.Assert((object)submissionAdder != null && (object)submissionGetter != null);

            var intType = compilation.GetSpecialType(SpecialType.System_Int32);
            var thisReference = new BoundThisReference(syntax, submissionConstructor.ContainingType) { WasCompilerGenerated = true };

            int i = 0;

            // hostObject = (THostObject)SessionHelpers.SetSubmission(<session>, <slot index>, this);
            var slotIndex = compilation.GetSubmissionSlotIndex();
            Debug.Assert(slotIndex >= 0);

            BoundExpression setSubmission = BoundCall.Synthesized(syntax,
                null,
                submissionAdder,
                sessionReference,
                new BoundLiteral(syntax, ConstantValue.Create(slotIndex), intType) { WasCompilerGenerated = true },
                thisReference
            );

            var hostObjectField = synthesizedFields.GetHostObjectField();
            if ((object)hostObjectField != null)
            {
                setSubmission = new BoundAssignmentOperator(syntax,
                    new BoundFieldAccess(syntax, thisReference, hostObjectField, ConstantValue.NotAvailable) { WasCompilerGenerated = true },
                    BoundConversion.Synthesized(syntax,
                        setSubmission,
                        Conversion.ExplicitReference,
                        false,
                        true,
                        ConstantValue.NotAvailable,
                        hostObjectField.Type
                    ),
                    hostObjectField.Type
                )
                { WasCompilerGenerated = true };
            }

            result[i++] = new BoundExpressionStatement(syntax, setSubmission) { WasCompilerGenerated = true };

            foreach (var field in synthesizedFields.FieldSymbols)
            {
                var targetScriptClass = (ImplicitNamedTypeSymbol)field.Type;
                var targetSubmissionId = targetScriptClass.DeclaringCompilation.GetSubmissionSlotIndex();
                Debug.Assert(targetSubmissionId >= 0);

                // this.<field> = (<FieldType>)SessionHelpers.GetSubmission(<session>, <i>);
                result[i++] =
                    new BoundExpressionStatement(syntax,
                        new BoundAssignmentOperator(syntax,
                            new BoundFieldAccess(syntax, thisReference, field, ConstantValue.NotAvailable) { WasCompilerGenerated = true },
                            BoundConversion.Synthesized(syntax,
                                BoundCall.Synthesized(syntax,
                                    null,
                                    submissionGetter,
                                    sessionReference,
                                    new BoundLiteral(syntax, ConstantValue.Create(targetSubmissionId), intType) { WasCompilerGenerated = true }),
                                Conversion.ExplicitReference,
                                false,
                                true,
                                ConstantValue.NotAvailable,
                                targetScriptClass
                            ),
                            targetScriptClass
                        )
                { WasCompilerGenerated = true })
                { WasCompilerGenerated = true };
            }

            Debug.Assert(i == result.Length);

            return result.AsImmutableOrNull();
        }
        public override BoundNode VisitAssignmentOperator(BoundAssignmentOperator node)
        {
            if (node.Left.Kind != BoundKind.Local) return (BoundExpression)base.VisitAssignmentOperator(node);
            var left = (BoundLocal)node.Left;
            var local = left.LocalSymbol;
            if (!variablesCaptured.Contains(local)) return (BoundExpression)base.VisitAssignmentOperator(node);
            if (proxies.ContainsKey(local))
            {
                Debug.Assert(node.RefKind == RefKind.None);
                return (BoundExpression)base.VisitAssignmentOperator(node);
            }

            // user-declared variables are preassigned their proxies, and value temps
            // are assigned proxies at the beginning of their scope by the enclosing construct.
            // Here we handle ref temps.  Ref temps are the target of a ref assignment operator before
            // being used in any other way.
            Debug.Assert(local.DeclarationKind == LocalDeclarationKind.CompilerGenerated);
            Debug.Assert(node.RefKind != RefKind.None);

            // we have an assignment to a variable that has not yet been assigned a proxy.
            // So we assign the proxy before translating the assignment.
            return HoistRefInitialization(local, node);
        }
Exemple #38
0
        /// <summary>
        /// Takes an expression and returns the bound local expression "temp" 
        /// and the bound assignment expression "temp = expr".
        /// </summary>
        public BoundLocal StoreToTemp(
            BoundExpression argument,
            out BoundAssignmentOperator store,
            RefKind refKind = RefKind.None,
            SynthesizedLocalKind kind = SynthesizedLocalKind.LoweringTemp,
            CSharpSyntaxNode syntaxOpt = null
#if DEBUG
            , [CallerLineNumber]int callerLineNumber = 0
            , [CallerFilePath]string callerFilePath = null
#endif
            )
        {
            MethodSymbol containingMethod = this.CurrentMethod;
            var syntax = argument.Syntax;
            var type = argument.Type;

            var local = new BoundLocal(
                syntax,
                new SynthesizedLocal(
                    containingMethod,
                    type,
                    kind,
#if DEBUG
                    createdAtLineNumber: callerLineNumber,
                    createdAtFilePath: callerFilePath,
#endif
                    syntaxOpt: syntaxOpt ?? (kind.IsLongLived() ? syntax : null),
                    isPinned: false,
                    refKind: refKind),
                null,
                type);

            store = new BoundAssignmentOperator(
                syntax,
                local,
                argument,
                refKind,
                type);

            return local;
        }
        public override BoundNode VisitAssignmentOperator(BoundAssignmentOperator node)
        {
            BoundSpillSequence2 ss = null;
            var right = VisitExpression(ref ss, node.Right);
            BoundExpression left;
            if (ss == null || node.Left.Kind == BoundKind.Local)
            {
                left = VisitExpression(ref ss, node.Left);
            }
            else
            {
                // if the right-hand-side has await, spill the left
                var ss2 = new BoundSpillSequence2();
                left = VisitExpression(ref ss2, node.Left);
                if (left.Kind != BoundKind.Local) left = Spill(ss2, left, RefKind.Ref);
                ss2.IncludeSequence(ss);
                ss = ss2;
            }

            return UpdateExpression(ss, node.Update(left, right, node.RefKind, node.Type));
        }
        public override BoundNode VisitAssignmentOperator(BoundAssignmentOperator node)
        {
            if (node.Left.Kind == BoundKind.Local && node.RefKind != RefKind.None)
            {
                var localSymbol = ((BoundLocal)node.Left).LocalSymbol;
                Debug.Assert(localSymbol.RefKind != RefKind.None);
                refLocalInitializers.Add(localSymbol, node.Right);
            }

            return base.VisitAssignmentOperator(node);
        }
        private BoundExpression MakePropertyAssignment(
            CSharpSyntaxNode syntax,
            BoundExpression rewrittenReceiver,
            PropertySymbol property,
            ImmutableArray <BoundExpression> rewrittenArguments,
            ImmutableArray <RefKind> argumentRefKindsOpt,
            bool expanded,
            ImmutableArray <int> argsToParamsOpt,
            BoundExpression rewrittenRight,
            TypeSymbol type,
            bool used)
        {
            // Rewrite property assignment into call to setter.
            var setMethod = property.GetOwnOrInheritedSetMethod();

            if ((object)setMethod == null)
            {
                Debug.Assert((property as SourcePropertySymbol)?.IsAutoProperty == true,
                             "only autoproperties can be assignable without having setters");

                var backingField = (property as SourcePropertySymbol).BackingField;
                return(factory.AssignmentExpression(
                           factory.Field(rewrittenReceiver, backingField),
                           rewrittenRight));
            }

            // We have already lowered each argument, but we may need some additional rewriting for the arguments,
            // such as generating a params array, re-ordering arguments based on argsToParamsOpt map, inserting arguments for optional parameters, etc.
            ImmutableArray <LocalSymbol> argTemps;

            rewrittenArguments = MakeArguments(syntax, rewrittenArguments, property, setMethod, expanded, argsToParamsOpt, ref argumentRefKindsOpt, out argTemps, enableCallerInfo: ThreeState.True);

            if (used)
            {
                // Save expression value to a temporary before calling the
                // setter, and restore the temporary after the setter, so the
                // assignment can be used as an embedded expression.
                TypeSymbol exprType = rewrittenRight.Type;

                LocalSymbol rhsTemp = factory.SynthesizedLocal(exprType);

                BoundExpression boundRhs = new BoundLocal(syntax, rhsTemp, null, exprType);

                BoundExpression rhsAssignment = new BoundAssignmentOperator(
                    syntax,
                    boundRhs,
                    rewrittenRight,
                    exprType);

                BoundExpression setterCall = BoundCall.Synthesized(
                    syntax,
                    rewrittenReceiver,
                    setMethod,
                    AppendToPossibleNull(rewrittenArguments, rhsAssignment));

                return(new BoundSequence(
                           syntax,
                           AppendToPossibleNull(argTemps, rhsTemp),
                           ImmutableArray.Create(setterCall),
                           boundRhs,
                           type));
            }
            else
            {
                BoundCall setterCall = BoundCall.Synthesized(
                    syntax,
                    rewrittenReceiver,
                    setMethod,
                    AppendToPossibleNull(rewrittenArguments, rewrittenRight));

                if (argTemps.IsDefaultOrEmpty)
                {
                    return(setterCall);
                }
                else
                {
                    return(new BoundSequence(
                               syntax,
                               argTemps,
                               ImmutableArray <BoundExpression> .Empty,
                               setterCall,
                               setMethod.ReturnType));
                }
            }
        }
Exemple #42
0
        // Rewrite object initializer member assignment and add it to the result.
        //  new SomeType { Member = 0 };
        //                 ~~~~~~~~~~
        private void AddObjectInitializer(ref ArrayBuilder <BoundExpression> dynamicSiteInitializers, ArrayBuilder <BoundExpression> result, BoundExpression rewrittenReceiver, BoundAssignmentOperator assignment)
        {
            Debug.Assert(rewrittenReceiver != null);
            Debug.Assert(!inExpressionLambda);

            // Update the receiver for the field/property access as we might have introduced a temp for the initializer rewrite.

            BoundExpression rewrittenLeft = VisitExpression(assignment.Left);

            BoundKind rhsKind = assignment.Right.Kind;
            bool      isRhsNestedInitializer = rhsKind == BoundKind.ObjectInitializerExpression || rhsKind == BoundKind.CollectionInitializerExpression;

            BoundExpression rewrittenAccess;

            if (rewrittenLeft.Kind == BoundKind.ObjectInitializerMember)
            {
                rewrittenAccess = MakeObjectInitializerMemberAccess(rewrittenReceiver, (BoundObjectInitializerMember)rewrittenLeft, isRhsNestedInitializer);
                if (!isRhsNestedInitializer)
                {
                    // Rewrite simple assignment to field/property.
                    var rewrittenRight = VisitExpression(assignment.Right);
                    result.Add(MakeStaticAssignmentOperator(assignment.Syntax, rewrittenAccess, rewrittenRight, assignment.Type, used: false));
                    return;
                }
            }
            else
            {
                if (dynamicSiteInitializers == null)
                {
                    dynamicSiteInitializers = ArrayBuilder <BoundExpression> .GetInstance();
                }

                Debug.Assert(rewrittenLeft.Kind == BoundKind.DynamicObjectInitializerMember);
                var initializerMember = (BoundDynamicObjectInitializerMember)rewrittenLeft;

                if (!isRhsNestedInitializer)
                {
                    var rewrittenRight = VisitExpression(assignment.Right);
                    var setMember      = dynamicFactory.MakeDynamicSetMember(rewrittenReceiver, initializerMember.MemberName, rewrittenRight);
                    dynamicSiteInitializers.Add(setMember.SiteInitialization);
                    result.Add(setMember.SiteInvocation);
                    return;
                }

                var getMember = dynamicFactory.MakeDynamicGetMember(rewrittenReceiver, initializerMember.MemberName, resultIndexed: false);
                dynamicSiteInitializers.Add(getMember.SiteInitialization);
                rewrittenAccess = getMember.SiteInvocation;
            }

            AddObjectOrCollectionInitializers(ref dynamicSiteInitializers, result, rewrittenAccess, assignment.Right);
        }
Exemple #43
0
        private BoundExpression VisitAssignmentOperator(BoundAssignmentOperator node, bool used)
        {
            var loweredRight = VisitExpression(node.Right);

            BoundExpression left = node.Left;
            BoundExpression loweredLeft;

            switch (left.Kind)
            {
            case BoundKind.PropertyAccess:
                loweredLeft = VisitPropertyAccess((BoundPropertyAccess)left, isLeftOfAssignment: true);
                break;

            case BoundKind.IndexerAccess:
                loweredLeft = VisitIndexerAccess((BoundIndexerAccess)left, isLeftOfAssignment: true);
                break;

            case BoundKind.ImplicitIndexerAccess:
                loweredLeft = VisitImplicitIndexerAccess(
                    (BoundImplicitIndexerAccess)left,
                    isLeftOfAssignment: true);
                break;

            case BoundKind.EventAccess:
            {
                BoundEventAccess eventAccess = (BoundEventAccess)left;
                if (eventAccess.EventSymbol.IsWindowsRuntimeEvent)
                {
                    Debug.Assert(!node.IsRef);
                    return(VisitWindowsRuntimeEventFieldAssignmentOperator(node.Syntax, eventAccess, loweredRight));
                }
                goto default;
            }

            case BoundKind.DynamicMemberAccess:
            {
                // dyn.m = expr
                var memberAccess    = (BoundDynamicMemberAccess)left;
                var loweredReceiver = VisitExpression(memberAccess.Receiver);
                return(_dynamicFactory.MakeDynamicSetMember(loweredReceiver, memberAccess.Name, loweredRight).ToExpression());
            }

            case BoundKind.DynamicIndexerAccess:
            {
                // dyn[args] = expr
                var indexerAccess   = (BoundDynamicIndexerAccess)left;
                var loweredReceiver = VisitExpression(indexerAccess.Receiver);
                // Dynamic can't have created handler conversions because we don't know target types.
                AssertNoImplicitInterpolatedStringHandlerConversions(indexerAccess.Arguments);
                var loweredArguments = VisitList(indexerAccess.Arguments);
                return(MakeDynamicSetIndex(
                           indexerAccess,
                           loweredReceiver,
                           loweredArguments,
                           indexerAccess.ArgumentNamesOpt,
                           indexerAccess.ArgumentRefKindsOpt,
                           loweredRight));
            }

            default:
                loweredLeft = VisitExpression(left);
                break;
            }

            return(MakeStaticAssignmentOperator(node.Syntax, loweredLeft, loweredRight, node.IsRef, node.Type, used));
        }
Exemple #44
0
        /// <summary>
        /// Introduce a frame around the translation of the given node.
        /// </summary>
        /// <param name="node">The node whose translation should be translated to contain a frame</param>
        /// <param name="frame">The frame for the translated node</param>
        /// <param name="F">A function that computes the translation of the node.  It receives lists of added statements and added symbols</param>
        /// <returns>The translated statement, as returned from F</returns>
        private T IntroduceFrame <T>(BoundNode node, LambdaFrame frame, Func <ArrayBuilder <BoundExpression>, ArrayBuilder <LocalSymbol>, T> F)
        {
            NamedTypeSymbol frameType    = frame.ConstructIfGeneric(StaticCast <TypeSymbol> .From(currentTypeParameters));
            LocalSymbol     framePointer = new LambdaFrameLocalSymbol(this.topLevelMethod, frameType, CompilationState);

            CSharpSyntaxNode syntax = node.Syntax;

            // assign new frame to the frame variable
            CompilationState.AddSynthesizedMethod(frame.Constructor, FlowAnalysisPass.AppendImplicitReturn(MethodCompiler.BindMethodBody(frame.Constructor, CompilationState, null), frame.Constructor));

            var prologue = ArrayBuilder <BoundExpression> .GetInstance();

            MethodSymbol constructor = frame.Constructor.AsMember(frameType);

            Debug.Assert(frameType == constructor.ContainingType);
            var newFrame = new BoundObjectCreationExpression(
                syntax: syntax,
                constructor: constructor);

            prologue.Add(new BoundAssignmentOperator(syntax,
                                                     new BoundLocal(syntax, framePointer, null, frameType),
                                                     newFrame,
                                                     frameType));

            CapturedSymbolReplacement oldInnermostFrameProxy = null;

            if ((object)innermostFramePointer != null)
            {
                proxies.TryGetValue(innermostFramePointer, out oldInnermostFrameProxy);
                if (analysis.needsParentFrame.Contains(node))
                {
                    var             capturedFrame = new LambdaCapturedVariable(frame, innermostFramePointer);
                    FieldSymbol     frameParent   = capturedFrame.AsMember(frameType);
                    BoundExpression left          = new BoundFieldAccess(syntax, new BoundLocal(syntax, framePointer, null, frameType), frameParent, null);
                    BoundExpression right         = FrameOfType(syntax, frameParent.Type as NamedTypeSymbol);
                    BoundExpression assignment    = new BoundAssignmentOperator(syntax, left, right, left.Type);

                    if (this.currentMethod.MethodKind == MethodKind.Constructor && capturedFrame.Type == this.currentMethod.ContainingType && !this.seenBaseCall)
                    {
                        // Containing method is a constructor
                        // Initialization statement for the "this" proxy must be inserted
                        // after the constructor initializer statement block
                        // This insertion will be done by the delegate F
                        Debug.Assert(thisProxyInitDeferred == null);
                        thisProxyInitDeferred = assignment;
                    }
                    else
                    {
                        prologue.Add(assignment);
                    }

                    if (CompilationState.Emitting)
                    {
                        CompilationState.ModuleBuilderOpt.AddSynthesizedDefinition(frame, capturedFrame);
                    }

                    proxies[innermostFramePointer] = new CapturedToFrameSymbolReplacement(capturedFrame);
                }
            }

            // Capture any parameters of this block.  This would typically occur
            // at the top level of a method or lambda with captured parameters.
            // TODO: speed up the following by computing it in analysis.
            foreach (var v in analysis.variablesCaptured)
            {
                BoundNode varNode;
                if (!analysis.variableBlock.TryGetValue(v, out varNode) ||
                    varNode != node ||
                    analysis.declaredInsideExpressionLambda.Contains(v))
                {
                    continue;
                }

                InitVariableProxy(syntax, v, framePointer, prologue);
            }

            Symbol oldInnermostFramePointer = innermostFramePointer;

            innermostFramePointer = framePointer;
            var addedLocals = ArrayBuilder <LocalSymbol> .GetInstance();

            addedLocals.Add(framePointer);
            framePointers.Add(frame, framePointer);

            var result = F(prologue, addedLocals);

            framePointers.Remove(frame);
            innermostFramePointer = oldInnermostFramePointer;

            if ((object)innermostFramePointer != null)
            {
                if (oldInnermostFrameProxy != null)
                {
                    proxies[innermostFramePointer] = oldInnermostFrameProxy;
                }
                else
                {
                    proxies.Remove(innermostFramePointer);
                }
            }

            return(result);
        }