Exemplo n.º 1
0
        public override BoundNode VisitArrayCreation(BoundArrayCreation node)
        {
            var arrayType = (ArrayTypeSymbol)node.Type;

            if (_inExpressionLambda && node.InitializerOpt != null && !arrayType.IsSZArray)
            {
                Error(ErrorCode.ERR_ExpressionTreeContainsMultiDimensionalArrayInitializer, node);
            }

            return(base.VisitArrayCreation(node));
        }
Exemplo n.º 2
0
        internal void Parse(BoundArrayCreation boundArrayCreation)
        {
            base.Parse(boundArrayCreation);
            foreach (var boundExpression in boundArrayCreation.Bounds)
            {
                var item = Deserialize(boundExpression) as Expression;
                Debug.Assert(item != null);
                this.bounds.Add(item);
            }

            if (boundArrayCreation.InitializerOpt != null)
            {
                this.InitializerOpt = Deserialize(boundArrayCreation.InitializerOpt) as Expression;
            }
        }
Exemplo n.º 3
0
        public override object VisitArrayCreation(BoundArrayCreation node, object arg)
        {
            foreach (var e1 in node.Bounds)
            {
                VisitExpression(e1);
            }

            if (node.InitializerOpt != null && node.InitializerOpt.Initializers.IsNotNull)
            {
                foreach (var element in node.InitializerOpt.Initializers)
                {
                    VisitExpression(element);
                }
            }

            return(null);
        }
        public override BoundNode VisitArrayCreation(BoundArrayCreation node)
        {
            ReadOnlyArray <BoundExpression> bounds             = this.VisitList(node.Bounds);
            BoundArrayInitialization        visitedInitializer = (BoundArrayInitialization)this.Visit(node.InitializerOpt);
            TypeSymbol type = this.VisitType(node.Type);

            if (!RequiresSpill(bounds) && (visitedInitializer == null || !RequiresSpill(visitedInitializer.Initializers)))
            {
                return(node.Update(bounds, visitedInitializer, type));
            }

            var spillBuilder = new SpillBuilder();
            ReadOnlyArray <BoundExpression> newBounds         = SpillExpressionList(spillBuilder, bounds);
            BoundArrayInitialization        newInitializerOpt = (visitedInitializer == null) ? visitedInitializer :
                                                                visitedInitializer.Update(SpillExpressionList(spillBuilder, visitedInitializer.Initializers));
            BoundArrayCreation newArrayCreation = node.Update(newBounds, newInitializerOpt, type);

            return(spillBuilder.BuildSequenceAndFree(F, newArrayCreation));
        }
Exemplo n.º 5
0
        public override BoundNode VisitArrayCreation(BoundArrayCreation node)
        {
            BoundSpillSequenceBuilder builder = null;
            var             init = (BoundArrayInitialization)VisitExpression(ref builder, node.InitializerOpt);
            BoundExpression bound;

            if (builder == null)
            {
                bound = VisitExpression(ref builder, node.Size);
            }
            else
            {
                // spill bounds expressions if initializers contain await
                var boundsBuilder = new BoundSpillSequenceBuilder();
                bound = VisitExpression(ref boundsBuilder, node.Size);
                boundsBuilder.Include(builder);
                builder = boundsBuilder;
            }

            return(UpdateExpression(builder, node.Update(bound, init, node.Type)));
        }
Exemplo n.º 6
0
        public override BoundNode VisitArrayCreation(BoundArrayCreation node)
        {
            BoundSpillSequence2 ss = null;
            var init = (BoundArrayInitialization)VisitExpression(ref ss, node.InitializerOpt);
            ImmutableArray <BoundExpression> bounds;

            if (ss == null)
            {
                bounds = VisitExpressionList(ref ss, node.Bounds);
            }
            else
            {
                // spill bounds expressions if initializers contain await
                var ss2 = new BoundSpillSequence2();
                bounds = VisitExpressionList(ref ss2, node.Bounds, forceSpill: true);
                ss2.IncludeSequence(ss);
                ss = ss2;
            }

            return(UpdateExpression(ss, node.Update(bounds, init, node.Type)));
        }
Exemplo n.º 7
0
        private BoundExpression VisitArrayCreation(BoundArrayCreation node)
        {
            var arrayType = (ArrayTypeSymbol)node.Type;
            var boundType = _bound.Typeof(arrayType.ElementType.TypeSymbol);

            if (node.InitializerOpt != null)
            {
                if (arrayType.IsSZArray)
                {
                    return(ExprFactory("NewArrayInit", boundType, Expressions(node.InitializerOpt.Initializers)));
                }
                else
                {
                    // error should have been reported earlier
                    // Bound.Diagnostics.Add(ErrorCode.ERR_ExpressionTreeContainsMultiDimensionalArrayInitializer, node.Syntax.Location);
                    return(new BoundBadExpression(node.Syntax, default(LookupResultKind), ImmutableArray <Symbol> .Empty, ImmutableArray.Create <BoundExpression>(node), ExpressionType));
                }
            }
            else
            {
                return(ExprFactory("NewArrayBounds", boundType, Expressions(node.Bounds)));
            }
        }
Exemplo n.º 8
0
        private void EmitArrayCreationExpression(BoundArrayCreation expression, bool used)
        {
            var arrayType = (ArrayTypeSymbol)expression.Type;

            EmitArrayIndices(expression.Bounds);

            if (arrayType.IsSZArray)
            {
                _builder.EmitOpCode(ILOpCode.Newarr);
                EmitSymbolToken(arrayType.ElementType, expression.Syntax);
            }
            else
            {
                _builder.EmitArrayCreation(Emit.PEModuleBuilder.Translate(arrayType), expression.Syntax, _diagnostics);
            }

            if (expression.InitializerOpt != null)
            {
                EmitArrayInitializers(arrayType, expression.InitializerOpt);
            }

            // newarr has side-effects (negative bounds etc) so always emitted.
            EmitPopIfUnused(used);
        }
Exemplo n.º 9
0
        /// <summary>
        /// Rewrites arguments of an invocation according to the receiving method. It is assumed
        /// that arguments match parameters, but may need to be expanded/reordered.
        /// </summary>
        private void RewriteArguments(
            MethodSymbol method,
            bool expanded,
            ReadOnlyArray <int> argsToParamsOpt,
            ref ReadOnlyArray <RefKind> argumentRefKinds,
            ref ReadOnlyArray <BoundExpression> rewrittenArguments,
            out ReadOnlyArray <LocalSymbol> temporaries)
        {
            // We have:
            // * a list of arguments, already converted to their proper types,
            //   in source code order. Some optional arguments might be missing.
            // * a map showing which parameter each argument corresponds to. If
            //   this is null, then the argument to parameter mapping is one-to-one.
            // * the ref kind of each argument, in source code order. That is, whether
            //   the argument was marked as ref, out, or value (neither).
            // * a method symbol.
            // * whether the call is expanded or normal form.

            // We rewrite the call so that:
            // * if in its expanded form, we create the params array.
            // * if the call requires reordering of arguments because of named arguments, temporaries are generated as needed

            // Doing this transformation can move around refness in interesting ways. For example, consider
            //
            // A().M(y : ref B()[C()], x : out D());
            //
            // This will be created as a call with receiver A(), symbol M, argument list ( B()[C()], D() ),
            // name list ( y, x ) and ref list ( ref, out ).  We can rewrite this into temporaries:
            //
            // A().M(
            //    seq ( ref int temp_y = ref B()[C()], out D() ),
            //    temp_y );
            //
            // Now we have a call with receiver A(), symbol M, argument list as shown, no name list,
            // and ref list ( out, value ). We do not want to pass a *ref* to temp_y; the temporary
            // storage is not the thing being ref'd! We want to pass the *value* of temp_y, which
            // *contains* a reference.

            // We attempt to minimize the number of temporaries required. Arguments which neither
            // produce nor observe a side effect can be placed into their proper position without
            // recourse to a temporary. For example:
            //
            // Where(predicate: x=>x.Length!=0, sequence: S())
            //
            // can be rewritten without any temporaries because the conversion from lambda to
            // delegate does not produce any side effect that could be observed by S().
            //
            // By contrast:
            //
            // Foo(z: this.p, y: this.Q(), x: (object)10)
            //
            // The boxing of 10 can be reordered, but the fetch of this.p has to happen before the
            // call to this.Q() because the call could change the value of this.p.
            //
            // We start by binding everything that is not obviously reorderable as a temporary, and
            // then run an optimizer to remove unnecessary temporaries.

            ReadOnlyArray <ParameterSymbol> parameters = method.Parameters;
            var parameterCount = parameters.Count;
            var arguments      = new BoundExpression[parameterCount];

            temporaries = ReadOnlyArray <LocalSymbol> .Null;  // not using temps by default.

            List <RefKind> refKinds = null;

            if (argumentRefKinds.IsNotNull)
            {
                refKinds = new List <RefKind>(parameterCount);
                for (int p = 0; p < parameterCount; ++p)
                {
                    refKinds.Add(RefKind.None);
                }
            }

            ArrayBuilder <BoundAssignmentOperator> storesToTemps = null;
            ArrayBuilder <BoundExpression>         paramArray    = null;

            if (expanded)
            {
                paramArray = ArrayBuilder <BoundExpression> .GetInstance();
            }

            for (int a = 0; a < rewrittenArguments.Count; ++a)
            {
                var argument = rewrittenArguments[a];
                var p        = (argsToParamsOpt.IsNotNull) ? argsToParamsOpt[a] : a;
                var refKind  = argumentRefKinds.RefKinds(a);
                Debug.Assert(arguments[p] == null);
                if (expanded && p == parameterCount - 1)
                {
                    paramArray.Add(argument);
                    Debug.Assert(refKind == RefKind.None);
                }
                else if (IsSafeForReordering(argument, refKind))
                {
                    arguments[p] = argument;
                    if (refKinds != null)
                    {
                        refKinds[p] = refKind;
                    }
                }
                else
                {
                    if (storesToTemps == null)
                    {
                        storesToTemps = ArrayBuilder <BoundAssignmentOperator> .GetInstance(rewrittenArguments.Count);
                    }

                    var tempStore = TempHelpers.StoreToTemp(argument, refKind, containingSymbol);
                    storesToTemps.Add(tempStore.Item1);
                    arguments[p] = tempStore.Item2;
                }
            }

            if (expanded)
            {
                var paramArrayType = parameters[parameterCount - 1].Type;
                var arrayArgs      = paramArray.ToReadOnlyAndFree();

                var int32Type = method.ContainingAssembly.GetPrimitiveType(Microsoft.Cci.PrimitiveTypeCode.Int32);

                arguments[parameterCount - 1] = new BoundArrayCreation(
                    null,
                    null,
                    ReadOnlyArray.Singleton <BoundExpression>(
                        new BoundLiteral(null, null, ConstantValue.Create(arrayArgs.Count), int32Type)),
                    new BoundArrayInitialization(null, null, arrayArgs),
                    paramArrayType);
            }

            for (int p = 0; p < parameterCount; ++p)
            {
                if (arguments[p] == null)
                {
                    Debug.Assert(parameters[p].IsOptional);

                    // UNDONE: Add optional arguments.
                }
            }

            if (storesToTemps != null)
            {
                int tempsNeeded = MergeArgumentsAndSideEffects(storesToTemps, arguments);

                if (tempsNeeded > 0)
                {
                    var temps = new LocalSymbol[tempsNeeded];
                    for (int i = 0, j = 0; i < storesToTemps.Count; i++)
                    {
                        var s = storesToTemps[i];
                        if (s != null)
                        {
                            temps[j++] = ((BoundLocal)s.Left).LocalSymbol;
                        }
                    }

                    temporaries = temps.AsReadOnlyWrap();
                }

                storesToTemps.Free();
            }

            // * The rewritten list of names is now null because the arguments have been reordered.
            // * The args-to-params map is now null because every argument exactly matches its parameter.
            // * The call is no longer in its expanded form.

            argumentRefKinds   = refKinds == null ? ReadOnlyArray <RefKind> .Null : refKinds.AsReadOnly <RefKind>();
            rewrittenArguments = arguments.AsReadOnlyWrap();
        }
        /// <summary>
        /// Rewrites arguments of an invocation according to the receiving method. It is assumed
        /// that arguments match parameters, but may need to be expanded/reordered.
        /// </summary>
        private void RewriteArguments(
                MethodSymbol method,
                bool expanded,
                ReadOnlyArray<int> argsToParamsOpt,
                ref ReadOnlyArray<RefKind> argumentRefKinds,
                ref ReadOnlyArray<BoundExpression> rewrittenArguments,
                out ReadOnlyArray<LocalSymbol> temporaries)
        {

            // We have:
            // * a list of arguments, already converted to their proper types, 
            //   in source code order. Some optional arguments might be missing.
            // * a map showing which parameter each argument corresponds to. If
            //   this is null, then the argument to parameter mapping is one-to-one.
            // * the ref kind of each argument, in source code order. That is, whether
            //   the argument was marked as ref, out, or value (neither).
            // * a method symbol.
            // * whether the call is expanded or normal form.

            // We rewrite the call so that:
            // * if in its expanded form, we create the params array.
            // * if the call requires reordering of arguments because of named arguments, temporaries are generated as needed

            // Doing this transformation can move around refness in interesting ways. For example, consider
            //
            // A().M(y : ref B()[C()], x : out D());
            //
            // This will be created as a call with receiver A(), symbol M, argument list ( B()[C()], D() ),
            // name list ( y, x ) and ref list ( ref, out ).  We can rewrite this into temporaries:
            //
            // A().M( 
            //    seq ( ref int temp_y = ref B()[C()], out D() ),
            //    temp_y );
            // 
            // Now we have a call with receiver A(), symbol M, argument list as shown, no name list,
            // and ref list ( out, value ). We do not want to pass a *ref* to temp_y; the temporary
            // storage is not the thing being ref'd! We want to pass the *value* of temp_y, which
            // *contains* a reference.

            // We attempt to minimize the number of temporaries required. Arguments which neither
            // produce nor observe a side effect can be placed into their proper position without
            // recourse to a temporary. For example:
            //
            // Where(predicate: x=>x.Length!=0, sequence: S())
            //
            // can be rewritten without any temporaries because the conversion from lambda to
            // delegate does not produce any side effect that could be observed by S().
            //
            // By contrast:
            //
            // Foo(z: this.p, y: this.Q(), x: (object)10)
            //
            // The boxing of 10 can be reordered, but the fetch of this.p has to happen before the
            // call to this.Q() because the call could change the value of this.p. 
            //
            // We start by binding everything that is not obviously reorderable as a temporary, and
            // then run an optimizer to remove unnecessary temporaries.

            ReadOnlyArray<ParameterSymbol> parameters = method.Parameters;
            var parameterCount = parameters.Count;
            var arguments = new BoundExpression[parameterCount];
            temporaries = ReadOnlyArray<LocalSymbol>.Null;  // not using temps by default.

            List<RefKind> refKinds = null;
            if (argumentRefKinds.IsNotNull)
            {
                refKinds = new List<RefKind>(parameterCount);
                for (int p = 0; p < parameterCount; ++p)
                {
                    refKinds.Add(RefKind.None);
                }
            }

            ArrayBuilder<BoundAssignmentOperator> storesToTemps = null;
            ArrayBuilder<BoundExpression> paramArray = null;

            if (expanded)
            {
                paramArray = ArrayBuilder<BoundExpression>.GetInstance();
            }

            for (int a = 0; a < rewrittenArguments.Count; ++a)
            {
                var argument = rewrittenArguments[a];
                var p = (argsToParamsOpt.IsNotNull) ? argsToParamsOpt[a] : a;
                var refKind = argumentRefKinds.RefKinds(a);
                Debug.Assert(arguments[p] == null);
                if (expanded && p == parameterCount - 1)
                {
                    paramArray.Add(argument);
                    Debug.Assert(refKind == RefKind.None);
                }
                else if (IsSafeForReordering(argument, refKind))
                {
                    arguments[p] = argument;
                    if (refKinds != null)
                    {
                        refKinds[p] = refKind;
                    }
                }
                else
                {
                    if (storesToTemps == null)
                    {
                        storesToTemps = ArrayBuilder<BoundAssignmentOperator>.GetInstance(rewrittenArguments.Count);
                    }

                    var tempStore = TempHelpers.StoreToTemp(argument, refKind, containingSymbol);
                    storesToTemps.Add(tempStore.Item1);
                    arguments[p] = tempStore.Item2;
                }
            }

            if (expanded)
            {
                var paramArrayType = parameters[parameterCount - 1].Type;
                var arrayArgs = paramArray.ToReadOnlyAndFree();

                var int32Type = method.ContainingAssembly.GetPrimitiveType(Microsoft.Cci.PrimitiveTypeCode.Int32);

                arguments[parameterCount - 1] = new BoundArrayCreation(
                            null,
                            null,
                            ReadOnlyArray.Singleton<BoundExpression>(
                                new BoundLiteral(null, null, ConstantValue.Create(arrayArgs.Count), int32Type)),
                            new BoundArrayInitialization(null, null, arrayArgs),
                            paramArrayType);
            }

            for (int p = 0; p < parameterCount; ++p)
            {
                if (arguments[p] == null)
                {
                    Debug.Assert(parameters[p].IsOptional);

                    // UNDONE: Add optional arguments.
                }
            }

            if (storesToTemps != null)
            {
                int tempsNeeded = MergeArgumentsAndSideEffects(storesToTemps, arguments);

                if (tempsNeeded > 0)
                {
                    var temps = new LocalSymbol[tempsNeeded];
                    for (int i = 0, j = 0; i < storesToTemps.Count; i++)
                    {
                        var s = storesToTemps[i];
                        if (s != null)
                        {
                            temps[j++] = ((BoundLocal)s.Left).LocalSymbol;
                        }
                    }

                    temporaries = temps.AsReadOnlyWrap();
                }

                storesToTemps.Free();
            }

            // * The rewritten list of names is now null because the arguments have been reordered.
            // * The args-to-params map is now null because every argument exactly matches its parameter.
            // * The call is no longer in its expanded form.

            argumentRefKinds = refKinds == null ? ReadOnlyArray<RefKind>.Null : refKinds.AsReadOnly<RefKind>();
            rewrittenArguments = arguments.AsReadOnlyWrap();
        }