Ejemplo n.º 1
0
 private bool CheckForAssignmentToSelf(BoundAssignmentOperator node)
 {
     if (!node.HasAnyErrors && IsSameLocalOrField(node.Left, node.Right))
     {
         Error(ErrorCode.WRN_AssignmentToSelf, node);
         return(true);
     }
     return(false);
 }
Ejemplo n.º 2
0
        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 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();

            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, local.RefKind, sideEffects, hoistedFields, ref needsSacrificialEvaluation);

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

            if (needsSacrificialEvaluation)
            {
                var type            = TypeMap.SubstituteType(local.Type.TypeSymbol).TypeSymbol;
                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));
        }
        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;

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

            return(MakeStaticAssignmentOperator(node.Syntax, loweredLeft, loweredRight, node.IsRef, node.Type, used));
        }
Ejemplo n.º 5
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 index = this.VisitExpression(ref builder, arrayAccess.Index);
                    left = arrayAccess.Update(expression, index, 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 MakePropertyAssignment(
            SyntaxNode 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,
                invokedAsExtensionMethod: false,
                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.TypeSymbol));
                }
            }
        }
 public override BoundNode VisitAssignmentOperator(BoundAssignmentOperator node)
 {
     // Assume value of expression is used.
     return(VisitAssignmentOperator(node, used: true));
 }
Ejemplo n.º 8
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);

            // 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,
                        memberInit.MemberSymbol?.GetParameterRefKinds() ?? default(ImmutableArray <RefKind>),
                        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);
                }

                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.ArrayAccess:
            {
                var arrayAccess = (BoundArrayAccess)rewrittenLeft;
                var indices     = EvaluateSideEffectingArgumentsToTemps(
                    ImmutableArray.Create(arrayAccess.Index),
                    paramRefKindsOpt: default,
                    result,
                    ref temps);
                rewrittenAccess = arrayAccess.Update(rewrittenReceiver, indices[0], 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;
            }
 public override BoundNode VisitAssignmentOperator(BoundAssignmentOperator node)
 {
     _mightAssignSomething = true;
     return(null);
 }
Ejemplo n.º 10
0
        /// <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.core_runtime_WindowsRuntime_EventRegistrationToken);
            NamedTypeSymbol marshalType = _factory.WellKnownType(WellKnownType.core_runtime_WindowsRuntime_WindowsRuntimeMarshal);

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

            TypeSymbol eventType = eventSymbol.Type.TypeSymbol;

            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.TypeSymbol);
                }
                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.core_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.TypeSymbol);
            }
            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));
        }
Ejemplo n.º 11
0
 public override BoundNode VisitAssignmentOperator(BoundAssignmentOperator node)
 {
     CheckForAssignmentToSelf(node);
     return(base.VisitAssignmentOperator(node));
 }