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)); }
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; } }
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)); }
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))); }
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))); }
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))); } }
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); }
/// <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(); }