1 /* ****************************************************************************
3 * Copyright (c) Microsoft Corporation.
5 * This source code is subject to terms and conditions of the Apache License, Version 2.0. A
6 * copy of the license can be found in the License.html file at the root of this distribution. If
7 * you cannot locate the Apache License, Version 2.0, please send an email to
8 * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound
9 * by the terms of the Apache License, Version 2.0.
11 * You must not remove this notice, or any other, from this software.
14 * ***************************************************************************/
17 using System.Collections.Generic;
18 using System.Collections.ObjectModel;
19 using System.Diagnostics;
20 using System.Dynamic.Utils;
21 using System.Runtime.CompilerServices;
24 namespace Microsoft.Scripting.Ast {
26 namespace System.Linq.Expressions {
30 /// Represents creating a new array and possibly initializing the elements of the new array.
32 [DebuggerTypeProxy(typeof(Expression.NewArrayExpressionProxy))]
33 public class NewArrayExpression : Expression {
34 private readonly ReadOnlyCollection<Expression> _expressions;
35 private readonly Type _type;
37 internal NewArrayExpression(Type type, ReadOnlyCollection<Expression> expressions) {
38 _expressions = expressions;
42 internal static NewArrayExpression Make(ExpressionType nodeType, Type type, ReadOnlyCollection<Expression> expressions) {
43 if (nodeType == ExpressionType.NewArrayInit) {
44 return new NewArrayInitExpression(type, expressions);
46 return new NewArrayBoundsExpression(type, expressions);
51 /// Gets the static type of the expression that this <see cref="Expression" /> represents. (Inherited from <see cref="Expression"/>.)
53 /// <returns>The <see cref="Type"/> that represents the static type of the expression.</returns>
54 public sealed override Type Type {
59 /// Gets the bounds of the array if the value of the <see cref="P:NodeType"/> property is NewArrayBounds, or the values to initialize the elements of the new array if the value of the <see cref="P:NodeType"/> property is NewArrayInit.
61 public ReadOnlyCollection<Expression> Expressions {
62 get { return _expressions; }
66 /// Dispatches to the specific visit method for this node type.
68 protected internal override Expression Accept(ExpressionVisitor visitor) {
69 return visitor.VisitNewArray(this);
73 /// Creates a new expression that is like this one, but using the
74 /// supplied children. If all of the children are the same, it will
75 /// return this expression.
77 /// <param name="expressions">The <see cref="Expressions" /> property of the result.</param>
78 /// <returns>This expression if no children changed, or an expression with the updated children.</returns>
79 public NewArrayExpression Update(IEnumerable<Expression> expressions) {
80 if (expressions == Expressions) {
83 if (NodeType == ExpressionType.NewArrayInit) {
84 return Expression.NewArrayInit(Type.GetElementType(), expressions);
86 return Expression.NewArrayBounds(Type.GetElementType(), expressions);
90 internal sealed class NewArrayInitExpression : NewArrayExpression {
91 internal NewArrayInitExpression(Type type, ReadOnlyCollection<Expression> expressions)
92 : base(type, expressions) {
97 /// Returns the node type of this <see cref="Expression" />. (Inherited from <see cref="Expression" />.)
99 /// <returns>The <see cref="ExpressionType"/> that represents this expression.</returns>
100 public sealed override ExpressionType NodeType {
101 get { return ExpressionType.NewArrayInit; }
105 internal sealed class NewArrayBoundsExpression : NewArrayExpression {
106 internal NewArrayBoundsExpression(Type type, ReadOnlyCollection<Expression> expressions)
107 : base(type, expressions) {
111 /// Returns the node type of this <see cref="Expression" />. (Inherited from <see cref="Expression" />.)
113 /// <returns>The <see cref="ExpressionType"/> that represents this expression.</returns>
114 public sealed override ExpressionType NodeType {
115 get { return ExpressionType.NewArrayBounds; }
119 public partial class Expression {
125 /// Creates a new array expression of the specified type from the provided initializers.
127 /// <param name="type">A Type that represents the element type of the array.</param>
128 /// <param name="initializers">The expressions used to create the array elements.</param>
129 /// <returns>An instance of the <see cref="NewArrayExpression"/>.</returns>
130 public static NewArrayExpression NewArrayInit(Type type, params Expression[] initializers) {
131 return NewArrayInit(type, (IEnumerable<Expression>)initializers);
135 /// Creates a new array expression of the specified type from the provided initializers.
137 /// <param name="type">A Type that represents the element type of the array.</param>
138 /// <param name="initializers">The expressions used to create the array elements.</param>
139 /// <returns>An instance of the <see cref="NewArrayExpression"/>.</returns>
140 public static NewArrayExpression NewArrayInit(Type type, IEnumerable<Expression> initializers) {
141 ContractUtils.RequiresNotNull(type, "type");
142 ContractUtils.RequiresNotNull(initializers, "initializers");
143 if (type.Equals(typeof(void))) {
144 throw Error.ArgumentCannotBeOfTypeVoid();
147 ReadOnlyCollection<Expression> initializerList = initializers.ToReadOnly();
149 Expression[] newList = null;
150 for (int i = 0, n = initializerList.Count; i < n; i++) {
151 Expression expr = initializerList[i];
152 RequiresCanRead(expr, "initializers");
154 if (!TypeUtils.AreReferenceAssignable(type, expr.Type)) {
155 if (!TryQuote(type, ref expr)){
156 throw Error.ExpressionTypeCannotInitializeArrayType(expr.Type, type);
158 if (newList == null) {
159 newList = new Expression[initializerList.Count];
160 for (int j = 0; j < i; j++) {
161 newList[j] = initializerList[j];
165 if (newList != null) {
169 if (newList != null) {
170 initializerList = new TrueReadOnlyCollection<Expression>(newList);
173 return NewArrayExpression.Make(ExpressionType.NewArrayInit, type.MakeArrayType(), initializerList);
178 #region NewArrayBounds
182 /// Creates a <see cref="NewArrayExpression"/> that represents creating an array that has a specified rank.
184 /// <param name="type">A <see cref="Type"/> that represents the element type of the array.</param>
185 /// <param name="bounds">An array that contains Expression objects to use to populate the Expressions collection.</param>
186 /// <returns>A <see cref="NewArrayExpression"/> that has the <see cref="P:NodeType"/> property equal to type and the <see cref="P:Expressions"/> property set to the specified value.</returns>
187 public static NewArrayExpression NewArrayBounds(Type type, params Expression[] bounds) {
188 return NewArrayBounds(type, (IEnumerable<Expression>)bounds);
193 /// Creates a <see cref="NewArrayExpression"/> that represents creating an array that has a specified rank.
195 /// <param name="type">A <see cref="Type"/> that represents the element type of the array.</param>
196 /// <param name="bounds">An IEnumerable{T} that contains Expression objects to use to populate the Expressions collection.</param>
197 /// <returns>A <see cref="NewArrayExpression"/> that has the <see cref="P:NodeType"/> property equal to type and the <see cref="P:Expressions"/> property set to the specified value.</returns>
198 public static NewArrayExpression NewArrayBounds(Type type, IEnumerable<Expression> bounds) {
199 ContractUtils.RequiresNotNull(type, "type");
200 ContractUtils.RequiresNotNull(bounds, "bounds");
202 if (type.Equals(typeof(void))) {
203 throw Error.ArgumentCannotBeOfTypeVoid();
206 ReadOnlyCollection<Expression> boundsList = bounds.ToReadOnly();
208 int dimensions = boundsList.Count;
209 if (dimensions <= 0) throw Error.BoundsCannotBeLessThanOne();
211 for (int i = 0; i < dimensions; i++) {
212 Expression expr = boundsList[i];
213 RequiresCanRead(expr, "bounds");
214 if (!TypeUtils.IsInteger(expr.Type)) {
215 throw Error.ArgumentMustBeInteger();
220 if (dimensions == 1) {
221 //To get a vector, need call Type.MakeArrayType().
222 //Type.MakeArrayType(1) gives a non-vector array, which will cause type check error.
223 arrayType = type.MakeArrayType();
225 arrayType = type.MakeArrayType(dimensions);
228 return NewArrayExpression.Make(ExpressionType.NewArrayBounds, arrayType, bounds.ToReadOnly());